@leonidstern/census 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.
package/dist/census.js ADDED
@@ -0,0 +1,1990 @@
1
+ "use strict";
2
+ (() => {
3
+ // src/color.ts
4
+ function parseColor(css) {
5
+ let m = css.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/);
6
+ if (m) return [+m[1], +m[2], +m[3], m[4] === void 0 ? 1 : m[4].endsWith("%") ? parseFloat(m[4]) / 100 : +m[4]];
7
+ m = css.match(/^color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+%?))?\s*\)$/);
8
+ if (m) return [+m[1] * 255, +m[2] * 255, +m[3] * 255, m[4] === void 0 ? 1 : m[4].endsWith("%") ? parseFloat(m[4]) / 100 : +m[4]];
9
+ m = css.match(/^#([0-9a-f]{3,8})$/i);
10
+ if (m && [3, 4, 6, 8].includes(m[1].length)) {
11
+ const h = m[1].length <= 4 ? [...m[1]].map((x) => x + x).join("") : m[1];
12
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16), h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1];
13
+ }
14
+ return painted(css);
15
+ }
16
+ var paints = /* @__PURE__ */ new Map();
17
+ var probeHost = null;
18
+ var kept = null;
19
+ function colorProbe(host) {
20
+ probeHost = host;
21
+ kept = null;
22
+ }
23
+ var paintCtx;
24
+ function painted(css) {
25
+ if (!/^[a-z(]/i.test(css) || css.length > 240) return null;
26
+ const had = paints.get(css);
27
+ if (had !== void 0) return had;
28
+ if (paintCtx === void 0) {
29
+ try {
30
+ const c = typeof document === "undefined" ? null : document.createElement("canvas");
31
+ if (c) {
32
+ c.width = c.height = 1;
33
+ }
34
+ paintCtx = c?.getContext("2d", { willReadFrequently: true }) ?? null;
35
+ } catch {
36
+ paintCtx = null;
37
+ }
38
+ }
39
+ let out = null;
40
+ try {
41
+ if (typeof document !== "undefined" && document.body) {
42
+ const probe = kept ?? document.createElement("i");
43
+ probe.style.color = "";
44
+ probe.style.color = `color-mix(in srgb, ${css} 100%, transparent)`;
45
+ if (probe.style.color) {
46
+ if (!probeHost) {
47
+ probe.style.display = "none";
48
+ document.body.append(probe);
49
+ } else if (!kept) {
50
+ probeHost.append(probe);
51
+ kept = probe;
52
+ }
53
+ const said = getComputedStyle(probe).color;
54
+ if (!probeHost) probe.remove();
55
+ const m = said.match(/^color\(srgb\s+([-\d.e]+)\s+([-\d.e]+)\s+([-\d.e]+)(?:\s*\/\s*([\d.e]+))?\s*\)$/);
56
+ if (m) out = [Math.min(255, Math.max(0, +m[1] * 255)), Math.min(255, Math.max(0, +m[2] * 255)), Math.min(255, Math.max(0, +m[3] * 255)), m[4] === void 0 ? 1 : +m[4]];
57
+ }
58
+ }
59
+ } catch {
60
+ out = null;
61
+ }
62
+ try {
63
+ if (!out && paintCtx) {
64
+ paintCtx.clearRect(0, 0, 1, 1);
65
+ paintCtx.fillStyle = "#000";
66
+ paintCtx.fillStyle = css;
67
+ if (paintCtx.fillStyle !== "#000000" || /^(#0{3,8}|black|rgba?\(0[,\s]+0[,\s]+0\)?)/i.test(css)) {
68
+ paintCtx.fillRect(0, 0, 1, 1);
69
+ const d = paintCtx.getImageData(0, 0, 1, 1).data;
70
+ out = [d[0], d[1], d[2], d[3] / 255];
71
+ }
72
+ }
73
+ } catch {
74
+ out = null;
75
+ }
76
+ if (paints.size < 200) paints.set(css, out);
77
+ return out;
78
+ }
79
+ function over(top, under) {
80
+ const a = top[3];
81
+ return [top[0] * a + under[0] * (1 - a), top[1] * a + under[1] * (1 - a), top[2] * a + under[2] * (1 - a), 1];
82
+ }
83
+ var lum = (c) => {
84
+ const ch = (v) => {
85
+ const x = v / 255;
86
+ return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
87
+ };
88
+ return 0.2126 * ch(c[0]) + 0.7152 * ch(c[1]) + 0.0722 * ch(c[2]);
89
+ };
90
+ function contrast(a, b) {
91
+ const x = lum(a), y = lum(b);
92
+ return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
93
+ }
94
+
95
+ // src/findings.ts
96
+ var CHECKS = {
97
+ off: { level: "rule", what: "a value off rules.json (colors, type, radii, shadows)" },
98
+ "no-part": { level: "rule", what: "a control none of rules.parts drew" },
99
+ contrast: { level: "accessibility", preset: "recommended@1", what: "text contrast, WCAG 1.4.3" },
100
+ focus: { level: "accessibility", preset: "recommended@1", what: "focus visible, WCAG 2.4.7" },
101
+ target: { level: "accessibility", preset: "recommended@1", what: "target size, WCAG 2.5.8" },
102
+ max: { level: "max", preset: "best-practice@1", what: "more distinct values in a group than best practice" }
103
+ };
104
+ var PRESETS = ["recommended@1", "best-practice@1"];
105
+ var MAX_DEFAULTS = {
106
+ font: 2,
107
+ type: 8,
108
+ text: 6,
109
+ fill: 12,
110
+ line: 4,
111
+ radius: 4,
112
+ shadow: 5,
113
+ height: 6,
114
+ layer: 3
115
+ };
116
+ var COLOR_GROUPS = ["fill", "text", "line"];
117
+ var presetsOf = (rules) => (typeof rules.extends === "string" ? [rules.extends] : rules.extends ?? []).filter((e) => PRESETS.includes(e));
118
+ var hasValues = (rules) => !!(rules.colors || rules.type || rules.radii || rules.shadows || rules.parts);
119
+ function checkSetting(rules, check) {
120
+ const c = CHECKS[check];
121
+ if (!c) return { level: null };
122
+ const s = rules.checks?.[check];
123
+ const byPreset = !!c.preset && presetsOf(rules).includes(c.preset);
124
+ const byDefault = check === "max" && (!!rules.max || !hasValues(rules));
125
+ const base = c.level === "rule" || byPreset || byDefault ? c.level : null;
126
+ if (s === void 0) return { level: base };
127
+ if (s === "off") return { level: null };
128
+ if (s === "rule") return { level: "rule" };
129
+ if (typeof s === "number") return { level: base ?? c.level, n: s };
130
+ if (Array.isArray(s)) return { level: "rule", n: s[1] };
131
+ return { level: base };
132
+ }
133
+ var asksChecks = (rules) => !!(rules.extends || rules.checks && Object.values(rules.checks).some((v) => v !== "off") || checkSetting(rules, "max").level);
134
+ function maxFindings(groups, rules, name = 3) {
135
+ const want = checkSetting(rules, "max");
136
+ if (!want.level) return [];
137
+ const level = want.level;
138
+ const capOf = (group) => rules.max?.[group] ?? MAX_DEFAULTS[group];
139
+ const out = [];
140
+ for (const g of groups) {
141
+ const cap = capOf(g.name);
142
+ if (cap === void 0 || cap === "off") continue;
143
+ const n = g.rows.length + (g.more ?? 0);
144
+ if (n <= cap) continue;
145
+ const over2 = n - cap;
146
+ const tail = [...g.rows].sort((a, b) => a.n - b.n).slice(0, Math.min(name, over2)).map((r) => `${r.key}${(r.note ?? "").replace(/ \((from|via) .*$/, "")}${r.n ? ` \xD7${r.n}` : ""}${r.at[0] ? `: ${r.at[0]}` : ""}`);
147
+ out.push({ id: `max|${g.name}`, check: "max", level, key: `${g.name} ${n} values, ${cap} the max: drop ${over2}, rarest first`, n, at: [...tail, ...over2 > tail.length ? [`... ${over2 - tail.length} more`] : []] });
148
+ }
149
+ const palette = Object.keys(rules.colors ?? {}).length;
150
+ const paletteCap = COLOR_GROUPS.reduce((sum, g) => {
151
+ const c = capOf(g);
152
+ return typeof c === "number" ? sum + c : sum;
153
+ }, 0);
154
+ if (palette && paletteCap && palette > paletteCap) out.push({ id: "max|rules.json|colors", check: "max", level, key: `rules.json lists ${palette} colors, ${paletteCap} the max`, n: palette, at: [] });
155
+ return out;
156
+ }
157
+ function findingLines(c, max = 12) {
158
+ const out = [];
159
+ const fs = (c.findings ?? []).filter((f) => f.level === "accessibility");
160
+ if (fs.length) {
161
+ const lines = [...fs].sort((a, b) => Number(!!a.unsure) - Number(!!b.unsure) || b.n - a.n).slice(0, max).map((f) => ` ${f.key}${f.n > 1 ? ` \xD7${f.n}` : ""}${f.unsure ? " (unsure)" : ""}${f.note ?? ""}${f.at.length ? `: ${f.at.join("; ")}` : ""}`);
162
+ out.push(`accessibility (${fs.length}, WCAG 2.2 AA; unsure: computed styles can't decide)`, ...lines, ...fs.length > max ? [` ... ${fs.length - max} more`] : []);
163
+ }
164
+ const ms = (c.findings ?? []).filter((f) => f.level === "max");
165
+ if (ms.length) {
166
+ out.push(`max (${ms.length} over, best practice)`);
167
+ for (const f of ms) {
168
+ out.push(` ${f.key}${f.note ?? ""}`);
169
+ for (const a of f.at) out.push(` ${a}`);
170
+ }
171
+ }
172
+ return out;
173
+ }
174
+ function mergeFindings(pages) {
175
+ const names = Object.keys(pages);
176
+ if (!names.some((p) => pages[p].findings)) return void 0;
177
+ const by = /* @__PURE__ */ new Map();
178
+ for (const p of names) for (const f of pages[p].findings ?? []) {
179
+ if (f.level === "max") continue;
180
+ const had = by.get(f.id), at2 = f.at.slice(0, 1).map((x) => `[${p}] ${x}`);
181
+ if (!had) {
182
+ by.set(f.id, { f: { ...f, at: at2, values: f.values ? [...f.values] : void 0 }, pages: [p] });
183
+ continue;
184
+ }
185
+ had.f.n += f.n;
186
+ had.pages.push(p);
187
+ if (had.f.at.length < 3) had.f.at.push(...at2);
188
+ if (f.values) had.f.values = [.../* @__PURE__ */ new Set([...had.f.values ?? [], ...f.values])];
189
+ had.f.unsure = had.f.unsure && f.unsure;
190
+ }
191
+ return [...by.values()].map(({ f, pages: ps }) => ({ ...f, note: `${f.note ?? ""} (${ps.length === names.length && names.length > 1 ? "all" : ps.join("+")})` }));
192
+ }
193
+
194
+ // src/census.ts
195
+ var POPUP = "[role=menu],[role=listbox],[role=dialog],[role=alertdialog]";
196
+ var PRESSABLE = "button,a[href],[role=button],[role=tab],[role=option],[role=menuitem],[role=switch],[role=checkbox],[role=radio],[role=treeitem],[role=row],[data-item],[data-section]";
197
+ var MADE = /^(react-aria|_r_|:r|«r|radix-|base-ui-|headlessui-|mui-)/;
198
+ var ownId = (el) => el.id && !MADE.test(el.id) ? el.id : "";
199
+ var PROBLEM = /^(outside|cut-text|overlap|wrapped|no-edge|faint|faded|squeezed|covered|faint-drawn|hidden-drawn) /;
200
+ var REGION = "[role=dialog],[role=alertdialog],[role=menu],[role=listbox],[role=toolbar],[role=tablist],[role=region],header,nav,aside,main";
201
+ var box = (r) => `${Math.round(r.left)},${Math.round(r.top)} ${Math.round(r.width)}x${Math.round(r.height)}`;
202
+ var shown = (el, r) => r.width > 0 && r.height > 0 && r.bottom > 0 && r.right > 0 && r.top < innerHeight && r.left < innerWidth && (typeof el.checkVisibility !== "function" || el.checkVisibility({ opacityProperty: true, visibilityProperty: true }));
203
+ var ownText = (el) => [...el.childNodes].filter((n) => n.nodeType === 3).map((n) => n.textContent ?? "").join("").trim().replace(/\s+/g, " ");
204
+ var WORDY = "button,a,label,h1,h2,h3,h4,h5,h6,[role=button],[role=menuitem],[role=menuitemcheckbox],[role=menuitemradio],[role=option],[role=tab],[role=heading],[role=switch],[role=checkbox],[role=radio]";
205
+ function nameOf(el) {
206
+ if (ownId(el)) return `#${el.id}`;
207
+ const role = el.getAttribute("role"), label = el.getAttribute("aria-label");
208
+ const own = el.closest(WORDY) && !el.closest("[data-census-private]") ? ownText(el) : null;
209
+ const words = (label ?? own ?? "").slice(0, 40);
210
+ return `${role ?? el.tagName.toLowerCase()}${words ? ` ${JSON.stringify(words)}` : ""}`;
211
+ }
212
+ var inside = (el) => {
213
+ for (let p = el.parentElement; p; p = p.parentElement) if (ownId(p)) return ` in #${p.id}`;
214
+ return "";
215
+ };
216
+ function layoutLines(root = document.body, cap = 160, skip, faint = FAINT_TEXT) {
217
+ const regions = [], wrong = [];
218
+ const texts = [];
219
+ const controls = [];
220
+ const seeing = looking();
221
+ const clipOf = /* @__PURE__ */ new Map();
222
+ const room = (el) => {
223
+ if (!el || el === document.documentElement) return new DOMRect(0, 0, innerWidth, innerHeight);
224
+ if (clipOf.has(el)) return clipOf.get(el);
225
+ const up = room(el.parentElement);
226
+ let out = up;
227
+ if (up && el instanceof HTMLElement && !/visible/.test(getComputedStyle(el).overflow)) out = cross(up, el.getBoundingClientRect());
228
+ clipOf.set(el, out);
229
+ return out;
230
+ };
231
+ const all = root.querySelectorAll("*");
232
+ for (let i = 0; i < all.length && i < 8e3; i++) {
233
+ const el = all[i];
234
+ if (el.closest("svg") && el.tagName.toLowerCase() !== "svg") continue;
235
+ if (skip?.(el)) continue;
236
+ const full = el.getBoundingClientRect();
237
+ if (el instanceof HTMLElement && full.width > 0 && full.height < 24 && el.scrollHeight > 40 && el.children.length && wrong.length < 60 && /auto|scroll/.test(getComputedStyle(el).overflowY) && (typeof el.checkVisibility !== "function" || el.checkVisibility({ visibilityProperty: true }))) {
238
+ wrong.push(`squeezed ${nameOf(el)}${inside(el)} ${box(full)}: shows ${Math.round(full.height)}px of ${el.scrollHeight}px`);
239
+ }
240
+ if (!shown(el, full)) continue;
241
+ const space = room(el.parentElement);
242
+ const r = space && cross(space, full);
243
+ if (!r) continue;
244
+ if (el instanceof HTMLElement && wrong.length < 60) {
245
+ const cs = getComputedStyle(el);
246
+ if (/flex/.test(cs.display) && cs.flexWrap === "wrap") {
247
+ const kids = [...el.children].map((c) => ({ c, r: c.getBoundingClientRect() })).filter((k) => k.r.width > 0 && k.r.height > 0);
248
+ const top = Math.min(...kids.map((k) => k.r.top));
249
+ const down = kids.filter((k) => k.r.top >= top + Math.max(4, kids[0]?.r.height ?? 0) * 0.75 && k.c.matches(`${WORDY},[id],[aria-label]`));
250
+ if (kids.length > 1 && down.length) wrong.push(`wrapped ${nameOf(el)}${inside(el)} ${box(full)}: ${down.slice(0, 3).map((k) => nameOf(k.c)).join(", ")} dropped to the next line`);
251
+ }
252
+ if (el.matches(PRESSABLE) && !el.closest(OFF)) {
253
+ const op = seeing.opacity(el);
254
+ if (op < 0.35) wrong.push(`faded ${nameOf(el)}${inside(el)} ${box(full)}: opacity ${op.toFixed(2)} but not disabled`);
255
+ else if (r.width >= 4 && r.height >= 4 && (ownId(el) || el.getAttribute("aria-label") || ownText(el))) controls.push({ el, r });
256
+ const svg = !el.textContent?.trim() ? el.querySelector("svg") : null;
257
+ if (svg && op >= 0.35) {
258
+ const ratio = seeing.ratio(el, getComputedStyle(svg).color, op);
259
+ if (ratio !== null && ratio < FAINT_ICON) wrong.push(`faint ${nameOf(el)}${inside(el)} ${box(full)}: icon contrast ${ratio.toFixed(1)}:1 ${seeing.say(el, getComputedStyle(svg).color)}`);
260
+ }
261
+ }
262
+ if (el.matches("button,[role=button]")) {
263
+ const bg = cs.backgroundColor;
264
+ if (!/^(transparent|rgba\([^)]*, 0\))$/.test(bg) && !(parseFloat(cs.borderTopWidth) > 0 && cs.borderTopColor !== bg)) {
265
+ let up = el.parentElement, under = "";
266
+ while (up && !under) {
267
+ const b = getComputedStyle(up).backgroundColor;
268
+ if (!/^(transparent|rgba\([^)]*, 0\))$/.test(b)) under = b;
269
+ else up = up.parentElement;
270
+ }
271
+ if (under === bg && !(cs.outlineStyle !== "none" && parseFloat(cs.outlineWidth) > 0) && !shadowLayers(cs.boxShadow).rings.length) wrong.push(`no-edge ${nameOf(el)}${inside(el)} ${box(full)}: same color as ${up ? nameOf(up) : "the page"} behind it (${((c) => c ? `rgb(${c.slice(0, 3).map(Math.round).join(",")})` : bg)(parseColor(bg))})`);
272
+ }
273
+ }
274
+ }
275
+ if ((el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) && el.placeholder && !el.value && wrong.length < 60 && full.width >= 24) {
276
+ const cs = getComputedStyle(el), ps = getComputedStyle(el, "::placeholder");
277
+ const ctx = measure ??= document.createElement("canvas").getContext("2d");
278
+ if (ctx) {
279
+ ctx.font = `${ps.fontStyle} ${ps.fontWeight} ${ps.fontSize} ${ps.fontFamily}`;
280
+ const said = ps.textTransform === "uppercase" ? el.placeholder.toUpperCase() : ps.textTransform === "lowercase" ? el.placeholder.toLowerCase() : el.placeholder;
281
+ const need = ctx.measureText(said).width + (parseFloat(ps.letterSpacing) || 0) * said.length;
282
+ const lines = el instanceof HTMLTextAreaElement ? Math.max(1, Math.floor((el.clientHeight - parseFloat(cs.paddingTop) - parseFloat(cs.paddingBottom)) / (parseFloat(ps.lineHeight) || parseFloat(ps.fontSize) * 1.2 || 1))) : 1;
283
+ const has = (el.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight) - (parseFloat(cs.textIndent) || 0)) * lines;
284
+ if (need > has + 1) wrong.push(`cut-text placeholder of ${nameOf(el)}${inside(el)} ${box(full)} needs ${Math.ceil(need)}px, has ${Math.floor(has)}px${cs.textOverflow === "ellipsis" ? " (ends in \u2026)" : ""}`);
285
+ }
286
+ }
287
+ if ((ownId(el) || el.matches(REGION)) && full.width >= 24 && full.height >= 12) {
288
+ regions.push(`${nameOf(el)} ${box(full)}`);
289
+ const W = innerWidth, H = innerHeight;
290
+ const scrolls = (axis) => {
291
+ for (let p = el.parentElement; p; p = p.parentElement) if (/auto|scroll/.test(getComputedStyle(p)[axis])) return true;
292
+ return false;
293
+ };
294
+ if ((full.top < -1 && space.top <= 1 || full.bottom > H + 1 && space.bottom >= H - 1) && !scrolls("overflowY") || (full.left < -1 && space.left <= 1 || full.right > W + 1 && space.right >= W - 1) && !scrolls("overflowX")) wrong.push(`outside ${nameOf(el)} ${box(full)} window ${W}x${H}`);
295
+ }
296
+ if (!ownText(el)) continue;
297
+ const range = document.createRange();
298
+ const nodes = [...el.childNodes].filter((n2) => n2.nodeType === 3 && n2.textContent?.trim());
299
+ range.setStartBefore(nodes[0]);
300
+ range.setEndAfter(nodes[nodes.length - 1]);
301
+ const words = cross(r, range.getBoundingClientRect());
302
+ if (words) texts.push({ el, r: words, layer: el.closest(POPUP) });
303
+ if (el instanceof HTMLElement) {
304
+ const cs = getComputedStyle(el);
305
+ if (words && wrong.length < 60 && !el.closest(OFF)) {
306
+ const ratio = seeing.ratio(el, cs.color, seeing.opacity(el));
307
+ if (ratio !== null && ratio < faint) wrong.push(`faint ${nameOf(el)}${inside(el)} ${box(full)}: contrast ${ratio.toFixed(1)}:1 ${seeing.say(el, cs.color)}`);
308
+ }
309
+ const clips = cs.textOverflow === "ellipsis" || /hidden|clip/.test(cs.overflowX + cs.overflowY);
310
+ if (clips && full.width > 2 && full.height > 2 && (el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1)) {
311
+ wrong.push(`cut-text ${nameOf(el)}${inside(el)} ${box(full)} needs ${el.scrollWidth}x${el.scrollHeight}`);
312
+ }
313
+ }
314
+ }
315
+ const showing = (el, r) => {
316
+ for (const c of document.elementsFromPoint(r.left + r.width / 2, r.top + r.height / 2)) {
317
+ if (c === el || el.contains(c) || c.contains(el)) return true;
318
+ if (!/^(transparent|rgba\([^)]*, 0\))$/.test(getComputedStyle(c).backgroundColor)) return false;
319
+ }
320
+ return true;
321
+ };
322
+ const peek = new CSSStyleSheet();
323
+ peek.replaceSync("* { pointer-events: auto !important; }");
324
+ const sheets = [...document.adoptedStyleSheets];
325
+ document.adoptedStyleSheets = [...sheets, peek];
326
+ const inert = [...document.querySelectorAll("[inert]")];
327
+ for (const e of inert) e.inert = false;
328
+ const n = Math.min(texts.length, 700);
329
+ try {
330
+ for (let a = 0; a < n && wrong.length < cap; a++) {
331
+ for (let b = a + 1; b < n; b++) {
332
+ const A = texts[a], B = texts[b];
333
+ const x = cross(A.r, B.r);
334
+ if (x && x.width > 3 && x.height > 3 && A.layer === B.layer && !A.el.contains(B.el) && !B.el.contains(A.el) && showing(A.el, A.r) && showing(B.el, B.r)) wrong.push(`overlap ${nameOf(A.el)} ${box(A.r)} / ${nameOf(B.el)} ${box(B.r)}`);
335
+ }
336
+ }
337
+ for (const c of controls.slice(0, 300)) {
338
+ if (wrong.length >= cap) break;
339
+ if (c.el.closest(POPUP)) continue;
340
+ const by = coverOf(c.el, c.r);
341
+ if (by) wrong.push(`covered ${nameOf(c.el)}${inside(c.el)} ${box(c.r)}: under ${nameOf(by)}${inside(by)}`);
342
+ }
343
+ } finally {
344
+ document.adoptedStyleSheets = sheets;
345
+ for (const e of inert) e.inert = true;
346
+ }
347
+ const head = [`window ${innerWidth}x${innerHeight}`];
348
+ const rest = cap - head.length - Math.min(wrong.length, 60);
349
+ return [...head, ...wrong.slice(0, 60), ...regions.slice(0, Math.max(0, rest))];
350
+ }
351
+ var OFF = "[disabled],[aria-disabled=true],[inert],[data-census-dim]";
352
+ var measure;
353
+ var FAINT_TEXT = 2;
354
+ var FAINT_ICON = 1.5;
355
+ var clear = (c) => !c || c[3] < 0.02;
356
+ function looking() {
357
+ const bg = /* @__PURE__ */ new Map(), op = /* @__PURE__ */ new Map();
358
+ const base = () => {
359
+ for (const e of [document.body, document.documentElement]) {
360
+ const c = e && parseColor(getComputedStyle(e).backgroundColor);
361
+ if (c && !clear(c)) return over(c, [255, 255, 255, 1]);
362
+ }
363
+ return [255, 255, 255, 1];
364
+ };
365
+ const back = (el) => {
366
+ if (!el) return base();
367
+ const had = bg.get(el);
368
+ if (had) return had;
369
+ const c = parseColor(getComputedStyle(el).backgroundColor);
370
+ const out = clear(c) ? back(el.parentElement) : c[3] >= 0.995 ? c : over(c, back(el.parentElement));
371
+ bg.set(el, out);
372
+ return out;
373
+ };
374
+ const opacity = (el) => {
375
+ if (!el) return 1;
376
+ const had = op.get(el);
377
+ if (had !== void 0) return had;
378
+ const out = (parseFloat(getComputedStyle(el).opacity) || 0) * opacity(el.parentElement);
379
+ op.set(el, out);
380
+ return out;
381
+ };
382
+ return {
383
+ opacity,
384
+ back,
385
+ /** The contrast of `color` drawn at `alpha` in el, against what's behind el. */
386
+ ratio(el, color, alpha) {
387
+ const fg = parseColor(color);
388
+ if (!fg) return null;
389
+ const under = back(el);
390
+ return contrast(over([fg[0], fg[1], fg[2], fg[3] * alpha], under), under);
391
+ },
392
+ say: (el, color) => {
393
+ const rgb = (c) => `rgb(${c.slice(0, 3).map(Math.round).join(",")})`, fg = parseColor(color);
394
+ return `(${fg ? rgb(fg) : color.replace(/\s+/g, "")} on ${rgb(back(el))})`;
395
+ }
396
+ };
397
+ }
398
+ function behind(el) {
399
+ if (!el) return [255, 255, 255, 1];
400
+ const c = parseColor(getComputedStyle(el).backgroundColor);
401
+ return clear(c) ? behind(el.parentElement) : c[3] >= 0.995 ? c : over(c, behind(el.parentElement));
402
+ }
403
+ function coverOf(el, r) {
404
+ for (const c of document.elementsFromPoint(r.left + r.width / 2, r.top + r.height / 2)) {
405
+ if (c === el || el.contains(c) || c.contains(el)) return null;
406
+ if (c.closest(POPUP)) return null;
407
+ const cr = c.getBoundingClientRect();
408
+ if (cr.width * cr.height > innerWidth * innerHeight * 0.8) continue;
409
+ const bg = parseColor(getComputedStyle(c).backgroundColor);
410
+ if (bg && bg[3] > 0.5 || c.tagName === "CANVAS" || c.tagName === "IMG" || c.tagName === "VIDEO") return c;
411
+ }
412
+ return null;
413
+ }
414
+ function sayAlign(a, dir) {
415
+ if (a === "center" || a === "-webkit-center") return "center";
416
+ if (a === "justify") return "justify";
417
+ const rtl = dir === "rtl";
418
+ return a === "end" || a === "right" && !rtl || a === "left" && rtl ? "end" : "start";
419
+ }
420
+ var SAY_JUSTIFY = { center: "center", "flex-end": "end", end: "end", right: "end", "space-between": "between", "space-around": "around", "space-evenly": "evenly" };
421
+ var SAY_ITEMS = { center: "center", "flex-start": "start", start: "start", "flex-end": "end", end: "end", baseline: "baseline" };
422
+ var sayGaps = (g) => {
423
+ const lo = Math.min(...g), hi = Math.max(...g);
424
+ return lo === hi ? `${lo}` : g.length <= 6 ? g.join(" ") : `${lo}-${hi}`;
425
+ };
426
+ function layoutOf(el, cs, r, filled) {
427
+ if (r.width < 4 || r.height < 4) return null;
428
+ const flex = /flex/.test(cs.display), grid = /grid/.test(cs.display);
429
+ const pad = [cs.paddingTop, cs.paddingRight, cs.paddingBottom, cs.paddingLeft].map((v) => Math.round(parseFloat(v) || 0));
430
+ const padded = pad.some(Boolean);
431
+ if (!flex && !grid && !(filled && padded)) return null;
432
+ const kids = [...el.children].map((c) => ({ c, b: c.getBoundingClientRect() })).filter(({ c, b }) => b.width > 0 && b.height > 0 && !/^(absolute|fixed)$/.test(getComputedStyle(c).position));
433
+ if (!kids.length || (flex || grid) && kids.length < 2 && !(filled && padded)) return null;
434
+ const parts = [];
435
+ if (grid) {
436
+ const cols = cs.gridTemplateColumns.split(/\s+(?![^(]*\))/).filter(Boolean).length;
437
+ const rg = Math.round(parseFloat(cs.rowGap) || 0), cg = Math.round(parseFloat(cs.columnGap) || 0);
438
+ parts.push(`grid ${cols} col${cols > 1 ? "s" : ""}`);
439
+ if (rg || cg) parts.push(rg === cg ? `gap ${rg}` : `gap ${rg}/${cg}`);
440
+ } else if (flex) {
441
+ const col = /column/.test(cs.flexDirection);
442
+ parts.push(`${col ? "column" : "row"}${cs.flexWrap === "wrap" ? " wrap" : ""}`);
443
+ const sorted = [...kids].sort((a, b) => col ? a.b.top - b.b.top : a.b.left - b.b.left);
444
+ const set = Math.round(parseFloat(col ? cs.rowGap : cs.columnGap) || 0), gaps = [], from = /* @__PURE__ */ new Set();
445
+ const m = (e, side) => parseFloat(getComputedStyle(e).getPropertyValue(`margin-${side}`)) || 0;
446
+ for (let i = 1; i < sorted.length; i++) {
447
+ const a = sorted[i - 1], b = sorted[i];
448
+ if (!col && Math.min(a.b.bottom, b.b.bottom) - Math.max(a.b.top, b.b.top) <= 0) continue;
449
+ const g = Math.round(col ? b.b.top - a.b.bottom : b.b.left - a.b.right), mg = Math.round(col ? m(a.c, "bottom") + m(b.c, "top") : m(a.c, "right") + m(b.c, "left"));
450
+ gaps.push(g);
451
+ if (set) from.add("gap");
452
+ if (mg > 0) from.add("margins");
453
+ if (g - set - mg > 1) from.add("free space");
454
+ }
455
+ if (gaps.length) {
456
+ if (Math.min(...gaps) < 0) parts.push("overlapping");
457
+ else if (Math.max(...gaps) > 0) parts.push(`${new Set(gaps).size > 1 ? "gaps" : "gap"} ${sayGaps(gaps)}${from.size && !(from.size === 1 && from.has("gap")) ? ` (${[...from].map((f) => f === "gap" ? `gap ${set}` : f).join(" and ")})` : ""}`);
458
+ }
459
+ } else parts.push("box");
460
+ if (padded) parts.push(`pad ${pad.every((p) => p === pad[0]) ? pad[0] : pad[0] === pad[2] && pad[1] === pad[3] ? `${pad[0]} ${pad[1]}` : pad.join(" ")}`);
461
+ if (flex) {
462
+ const j = SAY_JUSTIFY[cs.justifyContent], it = SAY_ITEMS[cs.alignItems];
463
+ if (j) parts.push(`justify ${j}`);
464
+ if (it) parts.push(`items ${it}`);
465
+ const grow = kids.filter((k) => parseFloat(getComputedStyle(k.c).flexGrow) > 0).length;
466
+ if (grow) parts.push(grow === kids.length ? "children grow" : `${grow} of ${kids.length} grow`);
467
+ }
468
+ return { key: parts.join(" "), kids: `${kids.length}: ${kids.slice(0, 3).map((k) => nameOf(k.c)).join(", ")}${kids.length > 3 ? ", \u2026" : ""}` };
469
+ }
470
+ function cross(a, b) {
471
+ const l = Math.max(a.left, b.left), t = Math.max(a.top, b.top), r = Math.min(a.right, b.right), btm = Math.min(a.bottom, b.bottom);
472
+ return r > l && btm > t ? new DOMRect(l, t, r - l, btm - t) : null;
473
+ }
474
+ var hex = (c) => `#${c.slice(0, 3).map((v) => Math.round(v).toString(16).padStart(2, "0")).join("")}${c[3] < 0.995 ? Math.round(c[3] * 255).toString(16).padStart(2, "0") : ""}`;
475
+ var num = (v) => String(Math.round(v * 10) / 10);
476
+ var splitTop = (s) => {
477
+ const parts = [];
478
+ let depth = 0, from = 0;
479
+ for (let i = 0; i < s.length; i++) {
480
+ const c = s[i];
481
+ if (c === "(" || c === "[") depth++;
482
+ else if (c === ")" || c === "]") depth--;
483
+ else if (c === "," && !depth) {
484
+ parts.push(s.slice(from, i));
485
+ from = i + 1;
486
+ }
487
+ }
488
+ parts.push(s.slice(from));
489
+ return parts.map((x) => x.trim());
490
+ };
491
+ function shadowLayers(css) {
492
+ const out = { rings: [], rest: [] };
493
+ if (!css || css === "none") return out;
494
+ for (const layer of splitTop(css)) {
495
+ let color = "", inset = false;
496
+ const len = [];
497
+ const words = layer.replace(/[a-z-]+\((?:[^()]|\((?:[^()]|\([^()]*\))*\))*\)|#[0-9a-f]{3,8}\b/i, (m) => {
498
+ color = m;
499
+ return " ";
500
+ });
501
+ for (const w of words.trim().split(/\s+/)) {
502
+ if (w === "inset") inset = true;
503
+ else if (/^-?[\d.]+(e[+-]?\d+)?(px)?$/.test(w)) len.push(parseFloat(w));
504
+ else if (w) color ||= w;
505
+ }
506
+ const [x = 0, y = 0, blur = 0, spread = 0] = len;
507
+ const c = color ? parseColor(color) : null;
508
+ if (c && c[3] < 0.02 || !x && !y && !blur && !spread) continue;
509
+ const say = c ? hex(c) : color || "currentcolor";
510
+ if (!x && !y && !blur) out.rings.push(`${say} ${num(Math.abs(spread))}px (ring${inset ? " inset" : ""})`);
511
+ else out.rest.push(`${[x, y, blur, spread].map((v) => v ? `${num(v)}px` : "0").join(" ")} ${say}${inset ? " inset" : ""}`);
512
+ }
513
+ return out;
514
+ }
515
+ function stateOf(el) {
516
+ const a = (k) => el.getAttribute(k);
517
+ const out = [];
518
+ if (el.disabled === true || a("aria-disabled") === "true" || a("data-disabled") !== null) out.push("disabled");
519
+ if (a("aria-selected") === "true" || a("aria-checked") === "true" || a("aria-pressed") === "true" || (a("aria-current") ?? "false") !== "false" || /^(on|active|checked|selected)$/.test(a("data-state") ?? "") || a("data-selected") !== null) out.push("selected");
520
+ if (a("aria-expanded") === "true" || a("data-state") === "open") out.push("open");
521
+ return out.join(" ");
522
+ }
523
+ function fontDiff(stack, first) {
524
+ const fam = (s) => s.split(",").map((x) => x.trim()).filter(Boolean);
525
+ const a = fam(stack), b = fam(first);
526
+ const plus = a.filter((x) => !b.includes(x)), minus = b.filter((x) => !a.includes(x));
527
+ if (!plus.length && !minus.length) return `the first stack in another order: ${a.join(", ")}`;
528
+ if (plus.length + minus.length > a.length + b.length - plus.length - minus.length) return a.join(", ");
529
+ return `the first stack${plus.length ? ` plus ${plus.map((x) => `${x}${a[0] === x ? " (in front)" : ""}`).join(", ")}` : ""}${minus.length ? ` minus ${minus.join(", ")}` : ""}`;
530
+ }
531
+ var PART_PROPS = ["variant", "size", "tone", "intent", "kind", "appearance", "shape", "density"];
532
+ var MORE_PROPS = ["color", "colorScheme", "colorPalette", "status", "severity", "level"];
533
+ var compName = (t, depth = 0) => {
534
+ if (depth > 3) return "";
535
+ if (typeof t === "function") return t.displayName ?? t.name ?? "";
536
+ if (t && typeof t === "object") {
537
+ const o = t;
538
+ return o.displayName ?? compName(o.render ?? o.type, depth + 1);
539
+ }
540
+ return "";
541
+ };
542
+ var PLAIN = /^[A-Z][A-Za-z0-9]{2,}$/;
543
+ var PLUMBING = /(Provider|Context|Consumer|Boundary|Slot|Portal|Fragment|FocusManager|FocusScope|FocusTrap|Presence)$/;
544
+ var fiberKey = "";
545
+ var fiberOf = (el) => {
546
+ const bag = el;
547
+ if (!fiberKey || !(fiberKey in bag)) {
548
+ const k = Object.keys(el).find((x) => x.startsWith("__reactFiber$"));
549
+ if (!k) return null;
550
+ fiberKey = k;
551
+ }
552
+ return bag[fiberKey] ?? null;
553
+ };
554
+ var propsOf = (f, keys = PART_PROPS) => keys.flatMap((k) => {
555
+ const v = f.memoizedProps?.[k];
556
+ return (typeof v === "string" || typeof v === "number") && /^[\w.-]{1,20}$/.test(String(v)) ? [`${k}=${v}`] : [];
557
+ }).join(" ");
558
+ var named = (f) => {
559
+ const n = compName(f.type);
560
+ return PLAIN.test(n) && !PLUMBING.test(n) ? n : "";
561
+ };
562
+ var family = (name) => name.match(/^[A-Za-z][a-z0-9]*/)?.[0] ?? name;
563
+ var obj = (v) => v && typeof v === "object" ? v : null;
564
+ var propsIn = (o, keys = PART_PROPS) => o ? keys.flatMap((k) => {
565
+ let v = o[k];
566
+ if (typeof v === "function") {
567
+ try {
568
+ v = /^\[(?:Input )?Signal: (.*)\]$/.exec(String(v))?.[1];
569
+ } catch {
570
+ v = void 0;
571
+ }
572
+ }
573
+ return (typeof v === "string" || typeof v === "number") && /^[\w.-]{1,20}$/.test(String(v)) ? [`${k}=${v}`] : [];
574
+ }).join(" ") : "";
575
+ var baseName = (file) => typeof file === "string" ? file.replace(/^.*[\\/]/, "").replace(/\.(vue|svelte|[jt]sx?)$/, "") : "";
576
+ function otherChain(el) {
577
+ const e = el, out = [];
578
+ const add = (name, props, src) => {
579
+ if (PLAIN.test(name) && !PLUMBING.test(name)) out.push({ name, props, fiber: null, gap: false, src });
580
+ };
581
+ for (let inst = obj(e.__vueParentComponent), i = 0; inst && i < 12; inst = obj(inst.parent), i++) {
582
+ if (obj(inst.subTree)?.el !== el && obj(inst.vnode)?.el !== el) break;
583
+ const type = obj(inst.type) ?? {};
584
+ add(String(type.name ?? type.__name ?? "") || baseName(type.__file), propsIn(obj(inst.props)), String(obj(obj(inst.parent)?.type)?.__file ?? "") || void 0);
585
+ }
586
+ if (out.length) return out;
587
+ for (let vm = obj(e.__vue__), i = 0; vm && vm.$el === el && i < 12; vm = obj(vm.$parent), i++) {
588
+ const o = obj(vm.$options) ?? {};
589
+ add(String(o.name ?? o._componentTag ?? "") || baseName(o.__file), propsIn(obj(vm.$props)), String(obj(obj(vm.$parent)?.$options)?.__file ?? "") || void 0);
590
+ }
591
+ if (out.length) return out;
592
+ const meta = obj(e.__svelte_meta), file = obj(meta?.loc)?.file;
593
+ if (typeof file === "string") {
594
+ const up = obj(el.parentElement?.__svelte_meta);
595
+ if (obj(up?.loc)?.file !== file) {
596
+ const name = baseName(file);
597
+ let src;
598
+ for (let p = obj(meta.parent), i = 0; p && i < 20; p = obj(p.parent), i++) if (p.type === "component" && (!p.componentTag || p.componentTag === name) && typeof p.file === "string") {
599
+ src = `${p.file}:${p.line ?? 0}`;
600
+ break;
601
+ }
602
+ add(name, "", src);
603
+ }
604
+ return out;
605
+ }
606
+ const ng = obj(globalThis.ng);
607
+ if (ng && typeof ng.getComponent === "function") {
608
+ const get = ng.getComponent;
609
+ for (const host of [el, el.parentElement && el.parentElement.children.length === 1 ? el.parentElement : null]) {
610
+ if (!host) continue;
611
+ let c = null;
612
+ try {
613
+ c = obj(get(host));
614
+ } catch {
615
+ c = null;
616
+ }
617
+ if (c) {
618
+ add(String(c.constructor?.name ?? "").replace(/Component$/, ""), propsIn(c));
619
+ break;
620
+ }
621
+ }
622
+ }
623
+ return out;
624
+ }
625
+ var NOT_APP = /node_modules|react-dom|react-jsx|jsx-dev-runtime|react-server|scheduler|\(native\)|<anonymous>/;
626
+ function fiberSrc(f) {
627
+ const b = obj(f);
628
+ if (!b) return "";
629
+ const ds = obj(b._debugSource);
630
+ if (ds && typeof ds.fileName === "string") return `${ds.fileName}:${ds.lineNumber ?? 0}`;
631
+ const st = obj(b._debugStack)?.stack;
632
+ if (typeof st !== "string") return "";
633
+ const frames = [];
634
+ for (const line of st.split("\n").slice(1)) {
635
+ const m = /((?:https?|file|webpack|turbopack|webpack-internal):\/\/[^\s()]+?):(\d+):(\d+)\)?\s*$/.exec(line);
636
+ if (m && !NOT_APP.test(m[1])) frames.push(`${m[1]}:${m[2]}:${m[3]}`);
637
+ if (frames.length === 3) break;
638
+ }
639
+ return frames.length ? `{${frames.join(" ")}}` : "";
640
+ }
641
+ function partInfo(el, parts) {
642
+ const tag = el.getAttribute("data-part");
643
+ if (tag) {
644
+ const props = (e) => ["variant", "size", "tone"].flatMap((k) => {
645
+ const v = e.getAttribute(`data-${k}`);
646
+ return v ? [`${k}=${v.slice(0, 20)}`] : [];
647
+ }).join(" ");
648
+ let say2 = [tag, props(el)].filter(Boolean).join(" ");
649
+ if (!props(el)) for (let p = el.parentElement, i = 0; p && i < 6; p = p.parentElement, i++) {
650
+ const t = p.getAttribute("data-part");
651
+ if (t && family(t) === family(tag) && props(p)) {
652
+ say2 = `${tag} of ${t} ${props(p)}`;
653
+ break;
654
+ }
655
+ }
656
+ return { say: say2, key: say2, fiber: null, listed: !parts?.length || parts.includes(tag), cand: true, own: false };
657
+ }
658
+ const start = fiberOf(el);
659
+ let chain = [];
660
+ let gap = false;
661
+ if (!start) chain = otherChain(el);
662
+ else for (let f = start.return, i = 0; f && typeof f.type !== "string" && chain.length < 16 && i < 80; f = f.return, i++) {
663
+ const raw = compName(f.type);
664
+ if (/(Provider|Context|Consumer|Boundary)$/.test(raw)) gap = chain.length > 0;
665
+ else if (PLAIN.test(raw) && !PLUMBING.test(raw)) {
666
+ chain.push({ name: raw, props: propsOf(f), fiber: f, gap });
667
+ gap = false;
668
+ }
669
+ }
670
+ if (!chain.length) return null;
671
+ const text = (c) => c.props ? `${c.name} ${c.props}` : c.name;
672
+ const inner = chain.find((c) => c.props);
673
+ let main = chain.find((c) => parts?.includes(c.name));
674
+ const listed = !!main;
675
+ const reach = (from, ok) => {
676
+ let to = from;
677
+ for (const c of chain.slice(chain.indexOf(from) + 1)) {
678
+ if (c.gap) break;
679
+ if (ok(c)) to = c;
680
+ }
681
+ return to;
682
+ };
683
+ if (main) main = reach(main, (c) => !!parts?.includes(c.name) && family(c.name) === family(main.name));
684
+ else if (inner) main = reach(inner, (c) => !!c.props);
685
+ else main = chain[0];
686
+ let key = text(main);
687
+ if (!main.props && start) {
688
+ let hosts = 0;
689
+ for (let f = start.return, i = 0; f && i < 60 && hosts < 6; f = f.return, i++) {
690
+ if (typeof f.type === "string") {
691
+ hosts++;
692
+ continue;
693
+ }
694
+ const name = hosts ? named(f) : "";
695
+ if (name && family(name) === family(main.name) && propsOf(f)) {
696
+ key = `${main.name} of ${name} ${propsOf(f)}`;
697
+ break;
698
+ }
699
+ }
700
+ }
701
+ const say = inner && inner !== main && inner.name !== main.name && chain.indexOf(inner) < chain.indexOf(main) ? `${key} < ${text(inner)}` : key;
702
+ return { say, key, fiber: main.fiber, listed, cand: listed || key.includes("="), own: listed || !!main.props, src: start ? void 0 : main.src };
703
+ }
704
+ var identEnd = (s, i) => {
705
+ while (i < s.length) {
706
+ if (s[i] === "\\") i += 2;
707
+ else if (/[\w-]/.test(s[i]) || s.charCodeAt(i) > 127) i++;
708
+ else break;
709
+ }
710
+ return i;
711
+ };
712
+ var closeOf = (s, i) => {
713
+ let d = 0;
714
+ for (; i < s.length; i++) {
715
+ if (s[i] === "\\") i++;
716
+ else if (s[i] === "(" || s[i] === "[") d++;
717
+ else if ((s[i] === ")" || s[i] === "]") && !--d) return i + 1;
718
+ }
719
+ return s.length;
720
+ };
721
+ function specificity(sel) {
722
+ let n = 0;
723
+ for (let i = 0; i < sel.length; ) {
724
+ const c = sel[i];
725
+ if (c === "\\") i += 2;
726
+ else if (c === "#") {
727
+ n += 1e6;
728
+ i = identEnd(sel, i + 1);
729
+ } else if (c === ".") {
730
+ n += 1e3;
731
+ i = identEnd(sel, i + 1);
732
+ } else if (c === "[") {
733
+ n += 1e3;
734
+ i = closeOf(sel, i);
735
+ } else if (c === ":") {
736
+ const el = sel[i + 1] === ":", from = i + (el ? 2 : 1), to = identEnd(sel, from), name = sel.slice(from, to).toLowerCase();
737
+ const end = sel[to] === "(" ? closeOf(sel, to) : to, arg = end > to ? sel.slice(to + 1, end - 1) : "";
738
+ if (el || /^(before|after|first-line|first-letter)$/.test(name)) n += 1;
739
+ else if (/^(is|not|has|matches|-webkit-any|-moz-any)$/.test(name)) n += Math.max(0, ...splitTop(arg).map(specificity));
740
+ else if (name !== "where") n += 1e3 + (/^nth-(last-)?child$/.test(name) && / of /.test(arg) ? Math.max(0, ...splitTop(arg.slice(arg.indexOf(" of ") + 4)).map(specificity)) : 0);
741
+ i = end;
742
+ } else if (/[a-zA-Z_]/.test(c) || sel.charCodeAt(i) > 127) {
743
+ n += 1;
744
+ i = identEnd(sel, i);
745
+ } else i++;
746
+ }
747
+ return n;
748
+ }
749
+ var ON_STATE = /\[(?:data-state=["']?(?:on|active|checked|selected)["']?|aria-(?:pressed|checked|selected)=["']?true["']?|data-(?:selected|checked|on)(?:=[^\]]*)?)\]/;
750
+ var PRESSED_ATTR = /\[data-pressed(?:=[^\]]*)?\]/;
751
+ var pressedIsOnIn = (sel, list) => {
752
+ const alt = (arms) => arms.some((x) => PRESSED_ATTR.test(x)) && arms.some((x) => ON_STATE.test(x) && !PRESSED_ATTR.test(x));
753
+ if (alt(list)) return true;
754
+ for (const m of sel.matchAll(/:(?:is|where|matches|-webkit-any)\(/g)) {
755
+ const open = m.index + m[0].length - 1;
756
+ if (alt(splitTop(sel.slice(open + 1, closeOf(sel, open) - 1)))) return true;
757
+ }
758
+ return false;
759
+ };
760
+ function readSheets() {
761
+ const layers = /* @__PURE__ */ new Map();
762
+ const layerCmp = (a, b) => {
763
+ if (a === b) return 0;
764
+ if (!a || !b) return a ? -1 : 1;
765
+ const x = a.split("."), y = b.split(".");
766
+ for (let i = 0; ; i++) {
767
+ if (i >= x.length || i >= y.length) return i >= x.length ? 1 : -1;
768
+ if (x[i] !== y[i]) return (layers.get(x.slice(0, i + 1).join(".")) ?? 0) - (layers.get(y.slice(0, i + 1).join(".")) ?? 0);
769
+ }
770
+ };
771
+ const spec = (r) => r.spec ??= specificity(r.sel);
772
+ const out = { states: [], plain: [], unreadable: 0, beats: (a, aImp, b, bImp) => {
773
+ if (aImp !== bImp) return aImp;
774
+ const l = layerCmp(a.layer, b.layer) * (aImp ? -1 : 1);
775
+ return l ? l > 0 : spec(a) !== spec(b) ? spec(a) > spec(b) : a.order > b.order;
776
+ } };
777
+ let order = 0, anon = 0;
778
+ const enter = (parent, name) => {
779
+ let full = parent;
780
+ for (const seg of name.split(".")) {
781
+ full = full ? `${full}.${seg}` : seg;
782
+ if (!layers.has(full)) layers.set(full, layers.size);
783
+ }
784
+ return full;
785
+ };
786
+ const re = (pseudo, attrs) => new RegExp([`(?<!\\\\)${pseudo}(?![\\w-])`, ...attrs.map((n) => `\\[${n}(?:=[^\\]]*)?\\]`)].join("|"), "g");
787
+ const STATE = [["hover", re(":hover", ["data-hovered", "data-highlighted"])], ["pressed", re(":active", ["data-pressed"])], ["focus", re(":focus-visible", ["data-focus-visible"])]];
788
+ const walk = (list, parent, layer) => {
789
+ for (const rule of list) {
790
+ if (out.plain.length > 4e4) return;
791
+ const kind = rule.constructor.name;
792
+ if (rule instanceof CSSImportRule) {
793
+ const ln = rule.layerName;
794
+ try {
795
+ if (rule.styleSheet && (!rule.media.mediaText || matchMedia(rule.media.mediaText).matches)) walk(rule.styleSheet.cssRules, "", ln == null ? layer : enter(layer, ln || `(${anon++})`));
796
+ } catch {
797
+ out.unreadable++;
798
+ }
799
+ continue;
800
+ }
801
+ if (kind === "CSSLayerStatementRule") {
802
+ for (const n of rule.nameList ?? []) enter(layer, n);
803
+ continue;
804
+ }
805
+ if (rule instanceof CSSMediaRule && !matchMedia(rule.conditionText).matches) continue;
806
+ if (rule instanceof CSSSupportsRule && !CSS.supports(rule.conditionText)) continue;
807
+ if (kind === "CSSStartingStyleRule") continue;
808
+ const within = kind === "CSSLayerBlockRule" ? enter(layer, rule.name || `(${anon++})`) : layer;
809
+ let sels = null;
810
+ if (rule instanceof CSSStyleRule) sels = splitTop(rule.selectorText).map((x) => parent ? x.includes("&") ? x.replaceAll("&", parent) : `${parent} ${x}` : x);
811
+ else if (parent && kind === "CSSNestedDeclarations") sels = [parent];
812
+ const style = sels ? rule.style : null;
813
+ if (sels && style?.length) {
814
+ order++;
815
+ for (const sel of sels) {
816
+ const plain = { sel, style, layer: within, order, has: [] };
817
+ out.plain.push(plain);
818
+ for (const [state, r] of STATE) {
819
+ r.lastIndex = 0;
820
+ if (!r.test(sel)) continue;
821
+ plain.has.push(state);
822
+ r.lastIndex = 0;
823
+ let base = sel.replace(r, ":where(*)");
824
+ const pm = /::?(before|after)$/.exec(base);
825
+ if (pm) base = base.slice(0, pm.index) || "*";
826
+ const on = state === "pressed" && !/(?<!\\):active(?![\w-])/.test(sel);
827
+ if (!base.includes("::")) out.states.push({ state, base, pseudo: pm ? pm[1] : "", style, sel, layer: within, order, on, toggle: on && pressedIsOnIn(sel, sels) });
828
+ }
829
+ }
830
+ }
831
+ const kids = rule.cssRules;
832
+ if (kids?.length) walk(kids, rule instanceof CSSStyleRule ? sels.length > 1 ? `:is(${sels.join(",")})` : sels[0] : parent, within);
833
+ }
834
+ };
835
+ for (const sheet of [...document.styleSheets, ...document.adoptedStyleSheets ?? []]) {
836
+ if (sheet.disabled) continue;
837
+ try {
838
+ if (!sheet.media.mediaText || matchMedia(sheet.media.mediaText).matches) walk(sheet.cssRules, "", "");
839
+ } catch {
840
+ out.unreadable++;
841
+ }
842
+ }
843
+ return out;
844
+ }
845
+ var pseudoOf = (x) => {
846
+ if (x.pseudo === void 0) {
847
+ const m = /::?(before|after)$/.exec(x.sel);
848
+ x.base = m ? x.sel.slice(0, m.index) || "*" : x.sel;
849
+ x.pseudo = m ? m[1] : x.sel.includes("::") ? "other" : "";
850
+ }
851
+ return x.pseudo;
852
+ };
853
+ function resolveVars(v, el, first = []) {
854
+ const cs = getComputedStyle(el);
855
+ const get = (name) => {
856
+ for (const s of first) {
857
+ const x = s.getPropertyValue(name).trim();
858
+ if (x) return x;
859
+ }
860
+ return cs.getPropertyValue(name).trim();
861
+ };
862
+ for (let i = 0; i < 6 && v.includes("var("); i++) v = v.replace(/var\((--[\w-]+)(?:,\s*([^()]*(?:\([^()]*\))?[^()]*))?\)/g, (_, name, fb) => get(name) || (fb ?? "").trim());
863
+ return v.trim();
864
+ }
865
+ function censusLines(c) {
866
+ const out = [c.head];
867
+ for (const g of c.groups) {
868
+ if (!g.rows.length) continue;
869
+ const n = g.rows.length + (g.more ?? 0);
870
+ out.push(`${g.name} (${n}${g.what === void 0 ? " values" : g.what ? `, ${g.what}` : ""})`);
871
+ for (const r of g.rows) out.push(` ${rowText(r)}`);
872
+ if (g.more) out.push(` ... ${g.more} more`);
873
+ }
874
+ if (c.report) out.push(...findingLines(c));
875
+ return out;
876
+ }
877
+ var looksOf = (r) => {
878
+ if (!r.flag || !r.looks) return 1;
879
+ const skins = /* @__PURE__ */ new Map();
880
+ for (const l of r.looks) skins.set(l.state, (skins.get(l.state) ?? /* @__PURE__ */ new Set()).add(l.skin));
881
+ return Math.max(new Set(r.looks.map((l) => l.shape)).size, ...[...skins.values()].map((s) => s.size));
882
+ };
883
+ function rowText(r) {
884
+ if (!r.looks) return `${r.key}${r.n ? ` \xD7${r.n}` : ""}${r.note ?? ""}${r.at.length ? `: ${r.at.join("; ")}` : ""}`;
885
+ const multi = r.looks.length > 1, n = looksOf(r);
886
+ const by = /* @__PURE__ */ new Map();
887
+ for (const l of [...r.looks].sort((a, b) => b.n - a.n)) {
888
+ const say = l.say.replace("h=content", l.lo === l.hi ? `h${l.lo} (its content's)` : `h${l.lo}-${l.hi} (its content's)`);
889
+ by.set(l.state, [...by.get(l.state) ?? [], `${say} \xD7${l.n}${multi && l.at.length ? ` (${l.at.join("; ")})` : ""}`]);
890
+ }
891
+ return `${r.key}${n > 1 ? ` IN ${n} LOOKS` : ""}${r.note ?? ""}: ${[...by].sort((a, b) => a[0].localeCompare(b[0])).map(([st, v]) => `${st ? `${st}: ` : ""}${v.join(" | ")}`).join(" ; ")}`;
892
+ }
893
+ function mergeCensus(pages, rules = {}) {
894
+ const names = Object.keys(pages);
895
+ const groups = [];
896
+ const accs = /* @__PURE__ */ new Map();
897
+ for (const page of names) for (const g of pages[page].groups) {
898
+ let to = groups.find((x) => x.name === g.name);
899
+ if (!to) {
900
+ to = { name: g.name, what: g.what, rows: [], more: 0 };
901
+ groups.push(to);
902
+ accs.set(to, /* @__PURE__ */ new Map());
903
+ }
904
+ to.more = Math.max(to.more ?? 0, g.more ?? 0);
905
+ const rows = accs.get(to);
906
+ for (const r of g.rows) {
907
+ const k = `${r.key}
908
+ ${r.note ?? ""}`;
909
+ let a = rows.get(k);
910
+ if (!a) {
911
+ a = { row: { key: r.key, n: 0, note: r.note, at: [], looks: r.looks ? [] : void 0 }, pages: [], at: /* @__PURE__ */ new Map() };
912
+ rows.set(k, a);
913
+ to.rows.push(a.row);
914
+ }
915
+ a.row.n += r.n;
916
+ a.pages.push(page);
917
+ a.at.set(page, r.at);
918
+ if (r.flag) a.row.flag = true;
919
+ for (const l of r.looks ?? []) {
920
+ const had = a.row.looks.find((x) => x.state === l.state && x.say === l.say), at2 = l.at.slice(0, 1).map((p) => `[${page}] ${p}`);
921
+ if (!had) a.row.looks.push({ ...l, at: at2 });
922
+ else {
923
+ had.n += l.n;
924
+ had.lo = Math.min(had.lo ?? 1e9, l.lo ?? 1e9);
925
+ had.hi = Math.max(had.hi ?? 0, l.hi ?? 0);
926
+ if (had.at.length < 2) had.at.push(...at2);
927
+ }
928
+ }
929
+ }
930
+ }
931
+ for (const rows of accs.values()) for (const a of rows.values()) {
932
+ a.row.note = `${a.row.note ?? ""} (${a.pages.length === names.length && names.length > 1 ? "all" : a.pages.join("+")})`;
933
+ const said = /* @__PURE__ */ new Set();
934
+ for (let i = 0; i < 3; i++) for (const p of a.pages) {
935
+ const x = a.at.get(p)?.[i];
936
+ if (x && a.row.at.length < 3 && !said.has(x)) {
937
+ said.add(x);
938
+ a.row.at.push(`[${p}] ${x}`);
939
+ }
940
+ }
941
+ }
942
+ for (const g of groups) if (g.name !== "layout problems") g.rows.sort((a, b) => looksOf(b) - looksOf(a) || b.n - a.n);
943
+ const merged = mergeFindings(pages), overs = maxFindings(groups, rules), findings = merged || overs.length ? [...merged ?? [], ...overs] : void 0;
944
+ const report = names.some((p) => pages[p].report);
945
+ return { head: `${pages[names[0]]?.head ?? "styles on screen"}; pages: ${names.join(", ")}`, groups: groups.map((g) => ({ ...g, more: g.more || void 0 })), ...findings ? { findings } : {}, ...report ? { report } : {} };
946
+ }
947
+ var shares = (sizes, budget) => {
948
+ const out = sizes.map(() => 0);
949
+ let left = budget, n = sizes.length;
950
+ for (const i of sizes.map((_, j) => j).sort((a, b) => sizes[a] - sizes[b])) {
951
+ out[i] = Math.min(sizes[i], Math.floor(left / n));
952
+ left -= out[i];
953
+ n--;
954
+ }
955
+ return out;
956
+ };
957
+ function styleData(rules = {}, root = document.body, cap = 220) {
958
+ const host = document.createElement("div");
959
+ host.setAttribute("data-census-private", "");
960
+ host.style.display = "none";
961
+ document.body.append(host);
962
+ colorProbe(host);
963
+ try {
964
+ return census(rules, root, cap, host);
965
+ } finally {
966
+ colorProbe(null);
967
+ host.remove();
968
+ forced = /* @__PURE__ */ new WeakMap();
969
+ rings = /* @__PURE__ */ new WeakMap();
970
+ }
971
+ }
972
+ var textLines = (el) => {
973
+ const tops = [], walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT), range = document.createRange();
974
+ for (let n = walk.nextNode(), i = 0; n && i < 200; n = walk.nextNode(), i++) {
975
+ if (!n.nodeValue?.trim()) continue;
976
+ range.selectNodeContents(n);
977
+ for (const b of range.getClientRects()) if (b.width > 0 && !tops.some((t) => Math.abs(t - b.top) < b.height / 2)) tops.push(b.top);
978
+ }
979
+ return tops.length;
980
+ };
981
+ var CONTROL = "button,[role=button],[role=tab],[role=radio],[role=checkbox],[role=switch],[role=option],[role=menuitem],input,select,textarea,a[href]";
982
+ var NATIVE = "a[href],button,input,select,textarea";
983
+ var forced = /* @__PURE__ */ new WeakMap();
984
+ var FORCE_ATTR = { hover: "data-hovered", "pressed-attr": "data-pressed", focus: "data-focus-visible" };
985
+ var lookNow = (el) => {
986
+ const cs = getComputedStyle(el), o = { fill: cs.backgroundColor, text: cs.color, line: parseFloat(cs.borderTopWidth) > 0 ? cs.borderTopColor : "" };
987
+ for (const p of ["before", "after"]) {
988
+ const ps = getComputedStyle(el, `::${p}`);
989
+ if (!/^(none|normal)$/.test(ps.content)) o[`overlay ${p}`] = ps.backgroundColor;
990
+ }
991
+ return o;
992
+ };
993
+ var rings = /* @__PURE__ */ new WeakMap();
994
+ var ringNow = (el) => {
995
+ const cs = getComputedStyle(el);
996
+ return [cs.outlineStyle !== "none" && parseFloat(cs.outlineWidth) > 0 ? `outline ${cs.outlineStyle} ${cs.outlineWidth} ${cs.outlineColor} ${cs.outlineOffset}` : "", cs.boxShadow !== "none" ? `shadow ${cs.boxShadow}` : "", `decoration ${cs.textDecorationLine}`, `border ${cs.borderTopWidth} ${cs.borderTopStyle} ${cs.borderTopColor}`].join("|");
997
+ };
998
+ var SKIP_ATTR = /^(id|href|src|alt|title|value|name|placeholder|for|tabindex|aria-(label|labelledby|describedby|controls|owns|activedescendant|posinset|setsize|valuenow|valuetext)|data-census-.*|data-(key|id|index|testid|test-id|value|row-index|item-index))$/;
999
+ function stateKey(el, rest) {
1000
+ const own = [...el.attributes].filter((a) => !SKIP_ATTR.test(a.name)).map((a) => `${a.name}=${a.value}`).sort().join(" ");
1001
+ const up = [];
1002
+ for (let a = el.parentElement; a && a !== document.body; a = a.parentElement) up.push(`${a.tagName} ${a.getAttribute("class") ?? ""} ${a.getAttribute("style") ?? ""}`);
1003
+ const at2 = `${el.previousElementSibling ? "" : "first"} ${el.nextElementSibling ? "" : "last"}`;
1004
+ return [el.tagName, own, at2, JSON.stringify(rest), up.join(" < ")].join("|");
1005
+ }
1006
+ function forceMark() {
1007
+ let i = 0;
1008
+ const seen = /* @__PURE__ */ new Map();
1009
+ for (const el of document.querySelectorAll(CONTROL)) {
1010
+ const r = el.getBoundingClientRect();
1011
+ if (r.width < 4 || r.height < 4 || r.bottom < 0 || r.top > innerHeight || r.right < 0 || r.left > innerWidth || !el.checkVisibility()) continue;
1012
+ const rest = lookNow(el), key = stateKey(el, rest), like = seen.get(key);
1013
+ if (like) {
1014
+ forced.set(el, like);
1015
+ continue;
1016
+ }
1017
+ const readings = /* @__PURE__ */ new Map([["rest", rest]]);
1018
+ rings.set(readings, { rest: ringNow(el) });
1019
+ seen.set(key, readings);
1020
+ forced.set(el, readings);
1021
+ el.setAttribute("data-census-f", String(i));
1022
+ for (let a = el.parentElement; a && a !== document.documentElement; a = a.parentElement) a.setAttribute("data-census-up", `${a.getAttribute("data-census-up") ?? ""} ${i}`.trim());
1023
+ if (++i >= 400) break;
1024
+ }
1025
+ return i;
1026
+ }
1027
+ function forceRead(i, read, next) {
1028
+ const el = document.querySelector(`[data-census-f="${i}"]`);
1029
+ if (!el) return;
1030
+ const map = forced.get(el), set = (state) => {
1031
+ const a = FORCE_ATTR[state];
1032
+ if (a && !el.hasAttribute(a)) {
1033
+ el.setAttribute(a, "true");
1034
+ el.setAttribute("data-census-set", a);
1035
+ }
1036
+ };
1037
+ const clear2 = () => {
1038
+ const a = el.getAttribute("data-census-set");
1039
+ if (a) {
1040
+ el.removeAttribute(a);
1041
+ el.removeAttribute("data-census-set");
1042
+ }
1043
+ };
1044
+ if (read) {
1045
+ map?.set(read, lookNow(el));
1046
+ if (read === "focus" && map) {
1047
+ const r = rings.get(map);
1048
+ if (r) r.focus = ringNow(el);
1049
+ }
1050
+ clear2();
1051
+ if (read === "pressed") {
1052
+ set("pressed-attr");
1053
+ map?.set("pressed-attr", lookNow(el));
1054
+ clear2();
1055
+ }
1056
+ }
1057
+ if (next) set(next);
1058
+ }
1059
+ function forceDone() {
1060
+ for (const el of document.querySelectorAll("[data-census-f],[data-census-up]")) {
1061
+ el.removeAttribute("data-census-f");
1062
+ el.removeAttribute("data-census-up");
1063
+ }
1064
+ }
1065
+ var LAYER = /^(dialog|alertdialog|menu|listbox|tooltip)$/;
1066
+ var LOOK = ["height", "min-height", "border-top-left-radius", "background-color", "color", "font-size", "font-weight", "line-height", "letter-spacing", "font-family", "box-shadow", "border-top-color"];
1067
+ var STYLE_KEYS = { height: "height", minHeight: "min-height", borderRadius: "border-top-left-radius", background: "background-color", backgroundColor: "background-color", color: "color", fontSize: "font-size", fontWeight: "font-weight", lineHeight: "line-height", letterSpacing: "letter-spacing", fontFamily: "font-family", boxShadow: "box-shadow", borderColor: "border-top-color" };
1068
+ function census(rules, root, cap, host) {
1069
+ const G = () => /* @__PURE__ */ new Map();
1070
+ const groups = { font: G(), type: G(), text: G(), fill: G(), line: G(), radius: G(), shadow: G(), field: G(), height: G(), layout: G(), align: G(), states: G(), used: G(), layer: G(), rules: G() };
1071
+ const infos = /* @__PURE__ */ new Map();
1072
+ const part = (el) => {
1073
+ let p = infos.get(el);
1074
+ if (p === void 0) {
1075
+ p = partInfo(el, rules.parts);
1076
+ infos.set(el, p);
1077
+ }
1078
+ return p;
1079
+ };
1080
+ const srcs = /* @__PURE__ */ new Map();
1081
+ const srcOf = (p) => {
1082
+ if (!rules.sources || !p) return "";
1083
+ let s = p.src ?? "";
1084
+ if (!s && p.fiber) {
1085
+ s = srcs.get(p.fiber) ?? fiberSrc(p.fiber);
1086
+ srcs.set(p.fiber, s);
1087
+ }
1088
+ return s ? ` @ ${s}` : "";
1089
+ };
1090
+ const hostSrc = (el) => {
1091
+ if (!rules.sources) return "";
1092
+ const loc = obj(obj(el.__svelte_meta)?.loc);
1093
+ const s = fiberSrc(fiberOf(el)) || (loc && typeof loc.file === "string" ? `${loc.file}:${loc.line ?? 0}` : "");
1094
+ return s ? ` @ ${s}` : "";
1095
+ };
1096
+ const owners = /* @__PURE__ */ new Map();
1097
+ const ownerOf = (el) => {
1098
+ let o = owners.get(el);
1099
+ if (o !== void 0) return o;
1100
+ o = null;
1101
+ const makers = /* @__PURE__ */ new Set(), f = fiberOf(el);
1102
+ let told = false;
1103
+ if (f && "_debugOwner" in f) {
1104
+ told = true;
1105
+ for (let m = f._debugOwner, i = 0; m && i < 12; m = m._debugOwner ?? m.owner ?? null, i++) makers.add(compName(m.type) || m.name || "");
1106
+ }
1107
+ for (let a = el.parentElement, i = 0; a && a !== document.body && i < 4; a = a.parentElement, i++) {
1108
+ if (a.matches(CONTROL)) break;
1109
+ const lone = told || a.querySelectorAll(CONTROL).length === 1, ap = part(a);
1110
+ if (ap?.listed && lone && (!told || !ap.fiber || makers.has(compName(ap.fiber.type)))) {
1111
+ o = ap;
1112
+ break;
1113
+ }
1114
+ if (!lone) break;
1115
+ }
1116
+ owners.set(el, o);
1117
+ return o;
1118
+ };
1119
+ const inPart = (el, p) => rules.parts?.length && !p?.listed && el.matches(NATIVE) ? ownerOf(el) : null;
1120
+ const stray = (el, p) => !!rules.parts?.length && !p?.listed && el.matches(NATIVE) && !ownerOf(el);
1121
+ const where = (el) => {
1122
+ for (let p = el.parentElement; p; p = p.parentElement) {
1123
+ const t = p.tagName.toLowerCase(), role = p.getAttribute("role");
1124
+ if (/^(header|footer|nav|aside)$/.test(t)) return ` in ${t}`;
1125
+ if (role && /^(dialog|alertdialog|menu|listbox|tooltip|toolbar)$/.test(role)) return ` in ${role}`;
1126
+ }
1127
+ return inside(el);
1128
+ };
1129
+ const place = (el, r, name = el) => {
1130
+ const p = part(name), st = stateOf(name), no = stray(name, p), own = no ? null : inPart(name, p), tail = no ? "no DS part" : own ? `inside ${own.say}` : "";
1131
+ return `${nameOf(name)}${st ? ` (${st})` : ""}${p ? ` [${p.say}${tail ? `, ${tail}` : ""}]` : tail ? ` [${tail}]` : ""}${where(el)} ${box(r)}`;
1132
+ };
1133
+ const snap = rules.items ? /* @__PURE__ */ new Map() : null;
1134
+ const groupName = new Map(Object.entries(groups).map(([k, v]) => [v, k]));
1135
+ const add = (g, k, el, r, name = el) => {
1136
+ if (snap && snap.size < 4e3) {
1137
+ let it = snap.get(name);
1138
+ if (!it) snap.set(name, it = { el, r, look: /* @__PURE__ */ new Map() });
1139
+ const gn = groupName.get(g), had = it.look.get(gn) ?? [];
1140
+ if (!had.includes(k)) it.look.set(gn, [...had, k]);
1141
+ }
1142
+ let s = g.get(k);
1143
+ if (!s) g.set(k, s = { n: 0, at: [], el: name, els: [] });
1144
+ s.n++;
1145
+ if (s.at.length < 3) {
1146
+ s.at.push(place(el, r, name));
1147
+ s.els?.push(name);
1148
+ }
1149
+ return s;
1150
+ };
1151
+ const looks = /* @__PURE__ */ new Map();
1152
+ const seenLooks = [];
1153
+ const colorOf = (css) => {
1154
+ const c = parseColor(css);
1155
+ return c && c[3] >= 0.02 ? hex(c) : null;
1156
+ };
1157
+ const px = (v) => Math.round(parseFloat(v) * 10) / 10;
1158
+ const lineOf = (cs) => {
1159
+ for (const side of ["top", "right", "bottom", "left"]) {
1160
+ const w = parseFloat(cs.getPropertyValue(`border-${side}-width`));
1161
+ const c = w > 0 && cs.getPropertyValue(`border-${side}-style`) !== "none" ? colorOf(cs.getPropertyValue(`border-${side}-color`)) : null;
1162
+ if (c) return `${c} ${num(w)}px`;
1163
+ }
1164
+ return "";
1165
+ };
1166
+ const cornerOf = (cs) => {
1167
+ const one = (v) => {
1168
+ const n = parseFloat(v) || 0;
1169
+ return (v.includes("%") ? n >= 50 : n >= 999) ? "full" : num(n);
1170
+ };
1171
+ const c = [cs.borderTopLeftRadius, cs.borderTopRightRadius, cs.borderBottomRightRadius, cs.borderBottomLeftRadius].map(one);
1172
+ return c.every((x) => x === c[0]) ? c[0] : c.join(" ");
1173
+ };
1174
+ const sayCorner = (c) => c.split(" ").map((x) => x === "full" || x === "0" ? x : `${x}px`).join(" ");
1175
+ const seeing = looking();
1176
+ const ruleColors = Object.entries(rules.colors ?? {}).map(([k, v]) => [k, parseColor(v)]).filter((x) => !!x[1]);
1177
+ const dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2], (a[3] - b[3]) * 255);
1178
+ const tokens = /* @__PURE__ */ new Map();
1179
+ const tokenOf = (h) => {
1180
+ let t = tokens.get(h);
1181
+ if (t) return t;
1182
+ t = {};
1183
+ const c = ruleColors.length ? parseColor(h) : null;
1184
+ if (c) {
1185
+ let best = ruleColors[0], d = Infinity;
1186
+ for (const x of ruleColors) {
1187
+ const e = dist(c, x[1]);
1188
+ if (e < d) {
1189
+ d = e;
1190
+ best = x;
1191
+ }
1192
+ }
1193
+ const solid = d <= 2 || c[3] >= 0.995 ? void 0 : ruleColors.find((x) => x[1][3] >= 0.995 && Math.hypot(c[0] - x[1][0], c[1] - x[1][1], c[2] - x[1][2]) <= 3);
1194
+ t = d <= 2 ? { name: best[0] } : solid ? { name: `${solid[0]}/${Math.round(c[3] * 100)}` } : { off: ` OFF (nearest ${best[0]}, ${Math.round(d)} away)` };
1195
+ }
1196
+ tokens.set(h, t);
1197
+ return t;
1198
+ };
1199
+ const sayColors = (s) => s.replace(/(?<![\dx] )#[0-9a-f]{6,8}\b/g, (h) => {
1200
+ const t = tokenOf(h);
1201
+ return t.name ?? `${h}${t.off ?? ""}`;
1202
+ });
1203
+ const shadowNames = Object.entries(rules.shadows ?? {}).map(([k, v]) => [k, shadowLayers(v).rest.join(", ")]);
1204
+ const sayShadow = (k) => !shadowNames.length || k === "none" ? k : shadowNames.find((x) => x[1] === k)?.[0] ?? `${k} OFF`;
1205
+ const nameOf$ = (h) => h ? tokenOf(h).name ?? null : null;
1206
+ const base$ = (n) => n.replace(/\/\d+$/, "");
1207
+ const legacyRe = rules.legacy?.length ? new RegExp(`(?:^|[ <])(${rules.legacy.map((x) => x.replace(/[^\w-]/g, "")).join("|")})(?= |$)`) : null;
1208
+ const roleCheck = (who, fill, shadow, corner, el, r) => {
1209
+ const want2 = rules.roles?.[who];
1210
+ if (!want2) return;
1211
+ if (want2.fill && base$(nameOf$(fill) ?? "none") !== want2.fill) add(groups.rules, `${who} fill ${fill ?? "none"}: its role takes ${want2.fill}`, el, r);
1212
+ if (want2.shadow && shadow !== want2.shadow) add(groups.rules, `${who} shadow ${shadow}: its role takes ${want2.shadow}`, el, r);
1213
+ if (want2.radius !== void 0 && corner !== String(want2.radius)) add(groups.rules, `${who} corner ${sayCorner(corner)}: its role takes ${want2.radius}px`, el, r);
1214
+ };
1215
+ let skipped = [];
1216
+ try {
1217
+ if (rules.ignore) skipped = [rules.ignore];
1218
+ root.querySelector(rules.ignore || "*");
1219
+ } catch {
1220
+ skipped = [];
1221
+ }
1222
+ const out = new Set(root.querySelectorAll(["[data-census-private]", ...skipped].join(",")));
1223
+ let react = rules.foreign !== false && [...document.body.children].some((c) => fiberOf(c) || [...c.children].some(fiberOf));
1224
+ if (react) {
1225
+ const cs = [...document.querySelectorAll("button,[role=button],input,a[href]")].filter((c) => !c.closest("[data-census-private]"));
1226
+ if (cs.filter((c) => !fiberOf(c)).length * 3 > cs.length) react = false;
1227
+ }
1228
+ const foreign = /* @__PURE__ */ new Map(), embedded = /* @__PURE__ */ new Map(), roots = /* @__PURE__ */ new Map();
1229
+ const isRoot = (el) => {
1230
+ let r = roots.get(el);
1231
+ if (r === void 0) {
1232
+ r = Object.keys(el).some((k) => k.startsWith("__reactContainer$"));
1233
+ roots.set(el, r);
1234
+ }
1235
+ return r;
1236
+ };
1237
+ const foreignTop = (el) => {
1238
+ let top = el;
1239
+ while (top.parentElement && top.parentElement !== document.body && !fiberOf(top.parentElement) && !isRoot(top.parentElement)) top = top.parentElement;
1240
+ let f = foreign.get(top);
1241
+ if (f === void 0) {
1242
+ const par = top.parentElement, pf = par ? fiberOf(par) : null;
1243
+ f = false;
1244
+ if (!pf?.memoizedProps?.dangerouslySetInnerHTML && !isRoot(top) && ![...top.querySelectorAll("*")].some((c) => fiberOf(c) || isRoot(c))) {
1245
+ const tr = top.getBoundingClientRect(), flow = par === document.body && /^(static|relative)$/.test(getComputedStyle(top).position) && tr.width > 0 && tr.height > 0;
1246
+ f = !flow && (top.matches("button,[role=button],input,a[href]") ? [top] : [...top.querySelectorAll("button,[role=button],input,a[href]")]).some((c) => !fiberOf(c));
1247
+ }
1248
+ foreign.set(top, f);
1249
+ }
1250
+ return f ? top : null;
1251
+ };
1252
+ const sheets = readSheets();
1253
+ const pressedIsOn = !!document.querySelector("[data-pressed]:not(:active)");
1254
+ const saysOn = (el) => el.hasAttribute("aria-pressed") || el.hasAttribute("aria-checked") || el.hasAttribute("aria-selected");
1255
+ const lit = /* @__PURE__ */ new Set(), litText = /* @__PURE__ */ new Set(), litBy = /* @__PURE__ */ new Map();
1256
+ for (const st of sheets.states) {
1257
+ if (st.pseudo || st.on && (st.toggle || pressedIsOn)) continue;
1258
+ const tint = !!st.style.getPropertyValue("color");
1259
+ if (!tint && !["background-color", "background", "border-color", "box-shadow", "opacity"].some((k) => st.style.getPropertyValue(k))) continue;
1260
+ let els = litBy.get(st.sel);
1261
+ if (!els) {
1262
+ try {
1263
+ els = [...document.querySelectorAll(st.sel)];
1264
+ } catch {
1265
+ els = [];
1266
+ }
1267
+ litBy.set(st.sel, els);
1268
+ }
1269
+ for (const e of els) {
1270
+ if (st.on && saysOn(e)) continue;
1271
+ lit.add(e);
1272
+ if (tint) litText.add(e);
1273
+ }
1274
+ }
1275
+ const sizing = /* @__PURE__ */ new Map(), sizers = /* @__PURE__ */ new Map();
1276
+ const sized = (el) => {
1277
+ let v = sizing.get(el);
1278
+ if (v !== void 0) return v;
1279
+ const real = (x) => !!x && !/^(auto|0(px)?|fit-content|min-content|max-content|inherit|initial|unset|revert|revert-layer)$/.test(x.trim());
1280
+ v = ["height", "min-height", "block-size", "min-block-size", "aspect-ratio"].some((k) => {
1281
+ const own = el.style?.getPropertyValue(k) ?? "";
1282
+ if (own) return real(own);
1283
+ let list = sizers.get(k), top = null;
1284
+ if (!list) sizers.set(k, list = sheets.plain.filter((x) => x.style.getPropertyValue(k)));
1285
+ const imp = (x) => x.style.getPropertyPriority(k) === "important";
1286
+ for (const x of list) {
1287
+ try {
1288
+ if ((!top || sheets.beats(x, imp(x), top, imp(top))) && el.matches(x.sel)) top = x;
1289
+ } catch {
1290
+ }
1291
+ }
1292
+ return !!top && real(top.style.getPropertyValue(k));
1293
+ });
1294
+ sizing.set(el, v);
1295
+ return v;
1296
+ };
1297
+ const want = (check) => checkSetting(rules, check);
1298
+ const W = { contrast: want("contrast") };
1299
+ const hits = /* @__PURE__ */ new Map();
1300
+ const hit = (id, el, r, more = {}) => {
1301
+ let h = hits.get(id);
1302
+ if (!h) hits.set(id, h = { n: 0, at: [], el, r, ...more });
1303
+ h.n++;
1304
+ if (h.at.length < 3) h.at.push(place(el, r));
1305
+ const nm = nameOf(el);
1306
+ if ((h.names ??= []).length < 20 && !h.names.includes(nm)) h.names.push(nm);
1307
+ if (more.min !== void 0) h.min = Math.min(h.min ?? 99, more.min);
1308
+ if (more.unsure === false) h.unsure = false;
1309
+ return h;
1310
+ };
1311
+ const unsureText = (el, cs, r) => {
1312
+ if (cs.backgroundClip === "text" || cs.getPropertyValue("-webkit-background-clip") === "text" || cs.getPropertyValue("-webkit-text-fill-color") && colorOf(cs.getPropertyValue("-webkit-text-fill-color")) !== colorOf(cs.color) || cs.mixBlendMode !== "normal" || cs.filter !== "none" || cs.textShadow !== "none") return true;
1313
+ for (let e = el; e; e = e.parentElement) {
1314
+ const s = getComputedStyle(e);
1315
+ if (s.backgroundImage !== "none" || s.backdropFilter && s.backdropFilter !== "none") return true;
1316
+ const c = parseColor(s.backgroundColor);
1317
+ if (c && c[3] >= 0.995) break;
1318
+ }
1319
+ for (const c of document.elementsFromPoint(r.left + r.width / 2, r.top + r.height / 2)) {
1320
+ if (c === el || c.contains(el) || el.contains(c)) return false;
1321
+ const s = getComputedStyle(c), bgc = parseColor(s.backgroundColor);
1322
+ if (bgc && bgc[3] > 0.02 || s.backgroundImage !== "none" || /^(IMG|VIDEO|CANVAS)$/.test(c.tagName)) return true;
1323
+ }
1324
+ return false;
1325
+ };
1326
+ const turnedOff = (el) => !!el.closest(`${OFF},fieldset[disabled],[data-disabled]`) || el.disabled === true;
1327
+ const contrastOf = (el, color, cs, r, what) => {
1328
+ const ratio = seeing.ratio(el, color, seeing.opacity(el));
1329
+ if (ratio === null) return;
1330
+ const size = parseFloat(cs.fontSize), weight = parseFloat(cs.fontWeight) || 400;
1331
+ const large = size >= 24 || size >= 18.66 && weight >= 700, team = W.contrast.n;
1332
+ const floor = team !== void 0 ? large ? Math.min(3, team) : team : large ? 3 : 4.5;
1333
+ if (ratio >= floor) return;
1334
+ const fg = colorOf(color) ?? color, bg = hex(seeing.back(el)), id = `contrast|${what}${fg} on ${bg}|${large ? "large" : ""}`;
1335
+ const had = hits.get(id);
1336
+ hit(id, el, r, { min: ratio, big: large, fg, bg, what, ...had && (had.n >= 3 || !had.unsure) ? {} : { unsure: unsureText(el, cs, r) } });
1337
+ };
1338
+ const placeholders = /* @__PURE__ */ new Map(), icons = /* @__PURE__ */ new Map(), tracking = /* @__PURE__ */ new Map();
1339
+ let moving = 0, hot = 0, warm = null;
1340
+ const controls = [];
1341
+ const uses = [];
1342
+ const all = [root, ...root.querySelectorAll("*")];
1343
+ let skip = root.closest("[data-census-private]") ? root : null;
1344
+ for (const el of all) {
1345
+ if (skip) {
1346
+ if (skip.contains(el)) continue;
1347
+ skip = null;
1348
+ }
1349
+ if (out.has(el)) {
1350
+ skip = el;
1351
+ continue;
1352
+ }
1353
+ if (!(el instanceof HTMLElement || el instanceof SVGElement)) continue;
1354
+ if (react && !fiberOf(el)) {
1355
+ const top = foreignTop(el);
1356
+ if (top) {
1357
+ embedded.set(top, (embedded.get(top) ?? 0) + 1);
1358
+ continue;
1359
+ }
1360
+ }
1361
+ const r = el.getBoundingClientRect();
1362
+ if (!shown(el, r)) continue;
1363
+ const cs = getComputedStyle(el);
1364
+ if (el instanceof SVGElement) {
1365
+ if (/^(path|rect|circle|ellipse|line|polyline|polygon|use)$/.test(el.tagName)) {
1366
+ const svg = el.closest("svg") ?? el;
1367
+ const had = icons.get(svg) ?? /* @__PURE__ */ new Set();
1368
+ icons.set(svg, had);
1369
+ for (const v of [cs.fill, cs.stroke]) {
1370
+ const c = v && v !== "none" ? colorOf(v) : null;
1371
+ if (c && !had.has(c)) {
1372
+ had.add(c);
1373
+ add(groups.text, `${c} (icon)`, svg, svg.getBoundingClientRect());
1374
+ }
1375
+ }
1376
+ }
1377
+ continue;
1378
+ }
1379
+ if (warm && !warm.contains(el)) warm = null;
1380
+ if (!warm && litText.has(el)) warm = el;
1381
+ const own = ownText(el);
1382
+ if (!own && !el.children.length && cs.animationName !== "none" && /infinite/.test(cs.animationIterationCount)) {
1383
+ const f = colorOf(cs.backgroundColor) ?? "none";
1384
+ placeholders.set(f, (placeholders.get(f) ?? 0) + 1);
1385
+ continue;
1386
+ }
1387
+ if (own && r.width > 2 && r.height > 2) {
1388
+ const lh = cs.lineHeight === "normal" ? "normal" : String(px(cs.lineHeight)), ls = parseFloat(cs.letterSpacing) ? px(cs.letterSpacing) : 0;
1389
+ add(groups.type, `${px(cs.fontSize)}/${cs.fontWeight}/${lh}${ls ? ` ${ls}ls` : ""}`, el, r);
1390
+ add(groups.font, cs.fontFamily.replace(/["']/g, "").replace(/\s*,\s*/g, ", "), el, r);
1391
+ const t = colorOf(cs.color);
1392
+ if (t && !warm) {
1393
+ add(groups.text, t, el, r);
1394
+ const tn = nameOf$(t);
1395
+ if (rules.text?.length && tn && !rules.text.includes(tn) && !rules.text.includes(base$(tn))) add(groups.rules, `text ${t} is not a text color (text takes ${rules.text.join(", ")})`, el, r);
1396
+ if (rules.pairs && tn) {
1397
+ const under = hex(behind(el)), un = nameOf$(under), takes = un ? rules.pairs[un] ?? rules.pairs[base$(un)] : void 0;
1398
+ if (takes && !takes.includes(tn) && !takes.includes(base$(tn))) add(groups.rules, `text ${t} on ${under}: that fill takes text ${takes.join(", ")}`, el, r);
1399
+ }
1400
+ }
1401
+ const ta = sayAlign(cs.textAlign, cs.direction);
1402
+ if (ta && ta !== "start" && !(ta === "center" && el.closest(CONTROL))) add(groups.align, `text ${ta}`, el, r);
1403
+ const per = tracking.get(px(cs.fontSize)) ?? /* @__PURE__ */ new Map();
1404
+ tracking.set(px(cs.fontSize), per);
1405
+ const had = per.get(ls);
1406
+ if (had) had.n++;
1407
+ else per.set(ls, { n: 1, at: [place(el, r)], el });
1408
+ if (W.contrast.level && !warm && !turnedOff(el) && !el.closest("svg,[role=img]")) contrastOf(el, cs.color, cs, r, "");
1409
+ }
1410
+ if (W.contrast.level && (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) && el.placeholder && !el.value && !turnedOff(el)) {
1411
+ const ps = getComputedStyle(el, "::placeholder");
1412
+ contrastOf(el, ps.color, ps, r, "placeholder ");
1413
+ }
1414
+ const big = r.width >= 4 && r.height >= 4;
1415
+ let bg = colorOf(cs.backgroundColor), line = lineOf(cs), corner = cornerOf(cs);
1416
+ const ctl = big && el.matches(CONTROL);
1417
+ const still = !(bg || ctl) || !el.getAnimations?.().some((a) => a.playState === "running");
1418
+ if (!still) {
1419
+ moving++;
1420
+ bg = null;
1421
+ }
1422
+ const live = lit.has(el);
1423
+ if (live) {
1424
+ if (bg || line || ctl) hot++;
1425
+ bg = null;
1426
+ line = "";
1427
+ }
1428
+ if (bg && big) add(groups.fill, bg, el, r);
1429
+ if (line) add(groups.line, line, el, r);
1430
+ const sh = !live && cs.boxShadow && cs.boxShadow !== "none" ? shadowLayers(cs.boxShadow) : null;
1431
+ for (const ring of sh?.rings ?? []) add(groups.line, ring, el, r);
1432
+ if (corner !== "0" && (bg || line)) add(groups.radius, sayCorner(corner), el, r);
1433
+ if (sh?.rest.length) add(groups.shadow, sh.rest.join(", "), el, r);
1434
+ const lay = layoutOf(el, cs, r, !!(bg || line));
1435
+ if (lay) {
1436
+ const s = add(groups.layout, lay.key, el, r);
1437
+ if (s.at.length && !s.at[s.at.length - 1].includes(" holding ")) s.at[s.at.length - 1] += ` holding ${lay.kids}`;
1438
+ }
1439
+ const role = el.getAttribute("role");
1440
+ if (role && LAYER.test(role) || el === root && root !== document.body) {
1441
+ let lb = bg, ll = line, lc = corner, ls = sh;
1442
+ const inner = !lb && !ls?.rest.length && !!el.parentElement?.closest("[role=dialog],[role=alertdialog],[role=menu],[role=listbox],[role=tooltip]");
1443
+ for (let p2 = el.parentElement, i = 0; !inner && !lb && !ls?.rest.length && p2 && i < 4; p2 = p2.parentElement, i++) {
1444
+ const pcs = getComputedStyle(p2), pb = colorOf(pcs.backgroundColor), ps = shadowLayers(pcs.boxShadow);
1445
+ if (pb || ps.rest.length) {
1446
+ lb = pb;
1447
+ ll = lineOf(pcs);
1448
+ lc = cornerOf(pcs);
1449
+ ls = ps;
1450
+ }
1451
+ }
1452
+ if (!inner) {
1453
+ add(groups.layer, `${role ?? "layer"} corner ${sayCorner(lc)} fill ${lb ?? "none"}${ll ? ` line ${ll}` : ""} shadow ${ls?.rest.length ? ls.rest.join(", ") : "none"}`, el, r);
1454
+ if (role) roleCheck(role, lb, ls?.rest.length ? sayShadow(ls.rest.join(", ")) : "none", lc, el, r);
1455
+ }
1456
+ }
1457
+ const p = part(el);
1458
+ if (p && big) {
1459
+ const old = legacyRe?.exec(p.say)?.[1];
1460
+ if (old) add(groups.rules, `legacy part ${old} on screen`, el, r);
1461
+ const pn = p.key.split(" ")[0];
1462
+ if (rules.roles?.[pn] && !live && still && !stateOf(el)) roleCheck(pn, bg, sh?.rest.length ? sayShadow(sh.rest.join(", ")) : "none", corner, el, r);
1463
+ }
1464
+ let boxR = r, hug = false;
1465
+ if (ctl) {
1466
+ if (!live && (el instanceof HTMLInputElement && /^(text|search|email|number|password|tel|url)$/.test(el.type) || el instanceof HTMLTextAreaElement)) {
1467
+ for (let w = el.parentElement, i = 0; !bg && !line && w && i < 6; w = w.parentElement, i++) {
1468
+ const wr = w.getBoundingClientRect();
1469
+ if (wr.height > r.height * 3 + 8) break;
1470
+ const wcs = getComputedStyle(w), wb = colorOf(wcs.backgroundColor), wl = lineOf(wcs);
1471
+ if (wb || wl) {
1472
+ bg = wb;
1473
+ line = wl;
1474
+ corner = cornerOf(wcs);
1475
+ boxR = wr;
1476
+ }
1477
+ }
1478
+ add(groups.field, `${Math.round(boxR.height)}px corner ${sayCorner(corner)} fill ${bg ?? "none"}${line ? ` line ${line}` : ""}`, el, boxR);
1479
+ }
1480
+ const inner = Math.max(0, ...[...el.children].map((c) => c.getBoundingClientRect().height), own && cs.lineHeight !== "normal" ? parseFloat(cs.lineHeight) : 0);
1481
+ hug = !bg && !line && !parseFloat(cs.paddingTop) && !parseFloat(cs.paddingBottom) && inner >= r.height - 1;
1482
+ const kind = role ?? (el.tagName === "INPUT" ? `input ${el.type}` : el.tagName.toLowerCase());
1483
+ if (!hug) {
1484
+ const s = add(groups.height, `${kind} ${Math.round(boxR.height)}px${boxR === r ? "" : " (field box)"}`, el, boxR);
1485
+ if (p) (s.parts ??= /* @__PURE__ */ new Set()).add(p.key);
1486
+ }
1487
+ controls.push({ el, r: boxR });
1488
+ }
1489
+ const no = stray(el, p), within = no ? null : inPart(el, p);
1490
+ if (big && (p || no || within) && (bg || ctl)) {
1491
+ if (still && !live) {
1492
+ const st = stateOf(el), tc = ctl ? colorOf(cs.color) : null, op = seeing.opacity(el);
1493
+ let h = Math.round(boxR.height);
1494
+ if (ctl && !hug && boxR === r) {
1495
+ const lh = parseFloat(cs.lineHeight), inner = r.height - parseFloat(cs.paddingTop) - parseFloat(cs.paddingBottom) - parseFloat(cs.borderTopWidth) - parseFloat(cs.borderBottomWidth), n = lh > 0 ? Math.round(inner / lh) : 0;
1496
+ if (n >= 2 && Math.abs(inner - n * lh) <= 1 && (el instanceof HTMLTextAreaElement || textLines(el) === n) && !sized(el)) h = Math.round(r.height - (n - 1) * lh);
1497
+ }
1498
+ const shape = `${ctl ? hug ? "h=content " : `h${h} ` : ""}r${corner.replaceAll(" ", "/")}`;
1499
+ const skin = `${shape} fill ${bg ?? "none"}${op < 0.995 ? ` at ${Math.round(op * 100)}%` : ""}`, say = `${skin}${tc ? ` text ${tc}` : ""}`;
1500
+ const key = no ? `${p?.key ?? el.tagName.toLowerCase()} (no DS part)` : within ? `${within.key} ${el.tagName.toLowerCase()}` : p.key;
1501
+ seenLooks.push({ key, flag: no ? false : within ? within.cand : p.cand, st, shape, skin, say, h, hug, at: `${nameOf(el)}${where(el)} ${box(boxR)}${srcOf(within ?? p)}`, fiber: (within ?? p)?.fiber ?? null });
1502
+ }
1503
+ }
1504
+ const props = p?.own && big ? p.fiber?.memoizedProps : null;
1505
+ if (props && uses.length < 600) {
1506
+ const cls = typeof props.className === "string" ? props.className.split(/\s+/).filter(Boolean).slice(0, 40) : [];
1507
+ const style = props.style && typeof props.style === "object" ? Object.keys(props.style).flatMap((k) => STYLE_KEYS[k] ? [STYLE_KEYS[k]] : []) : [];
1508
+ if (cls.length || style.length) uses.push({ el, r, key: p.key, cls, style, ctl });
1509
+ }
1510
+ }
1511
+ const perKey = /* @__PURE__ */ new Map();
1512
+ for (const x of seenLooks) perKey.set(x.key, [...perKey.get(x.key) ?? [], x]);
1513
+ for (const [key, list] of perKey) {
1514
+ if (!list[0].flag || new Set(list.map((x) => x.shape)).size < 2 && new Set(list.map((x) => `${x.st}|${x.skin}`)).size === new Set(list.map((x) => x.st)).size) continue;
1515
+ const more = list.map((x) => x.fiber ? propsOf(x.fiber, MORE_PROPS) : "");
1516
+ if (new Set(more).size > 1) list.forEach((x, i) => {
1517
+ if (more[i]) x.key = `${key} ${more[i]}`;
1518
+ });
1519
+ }
1520
+ for (const x of seenLooks) {
1521
+ const of = looks.get(x.key) ?? { flag: x.flag, m: /* @__PURE__ */ new Map() };
1522
+ looks.set(x.key, of);
1523
+ let l = of.m.get(`${x.st}|${x.say}`);
1524
+ if (!l) of.m.set(`${x.st}|${x.say}`, l = { state: x.st, shape: x.shape, skin: x.skin, say: x.say, n: 0, at: [] });
1525
+ l.n++;
1526
+ if (x.hug) {
1527
+ l.lo = Math.min(l.lo ?? 1e9, x.h);
1528
+ l.hi = Math.max(l.hi ?? 0, x.h);
1529
+ }
1530
+ if (l.at.length < 2) l.at.push(x.at);
1531
+ }
1532
+ const shut = /* @__PURE__ */ new Map();
1533
+ let cut = false;
1534
+ if (rules.closed) {
1535
+ let top = all.map(fiberOf).find(Boolean) ?? null;
1536
+ while (top?.return) top = top.return;
1537
+ const mounted = /* @__PURE__ */ new Set(), fibers = [], stack = top ? [top] : [];
1538
+ const worn = /* @__PURE__ */ new Map();
1539
+ while (stack.length && fibers.length < 6e4) {
1540
+ const f = stack.pop();
1541
+ fibers.push(f);
1542
+ mounted.add(f.memoizedProps);
1543
+ if (f.alternate?.memoizedProps) mounted.add(f.alternate.memoizedProps);
1544
+ const cn = typeof f.type === "string" ? null : f.memoizedProps?.className;
1545
+ if (typeof cn === "string" && cn) for (const t of /* @__PURE__ */ new Set([f.type, f.elementType ?? f.type])) {
1546
+ const l = worn.get(t) ?? [];
1547
+ if (l.length < 400) l.push({ props: propsOf(f), cls: new Set(cn.split(/\s+/)) });
1548
+ worn.set(t, l);
1549
+ }
1550
+ if (f.sibling) stack.push(f.sibling);
1551
+ if (f.child) stack.push(f.child);
1552
+ }
1553
+ if (stack.length) cut = true;
1554
+ const seen = /* @__PURE__ */ new Set();
1555
+ let budget = 3e4;
1556
+ const scan = (v, depth) => {
1557
+ if (!v || typeof v !== "object" || depth > 12) return;
1558
+ if (Array.isArray(v)) {
1559
+ if (seen.has(v)) return;
1560
+ seen.add(v);
1561
+ for (let i = 0; i < v.length && i < 200; i++) {
1562
+ const x = v[i];
1563
+ if (x && typeof x === "object" && !Array.isArray(x) && !x.$$typeof) return;
1564
+ scan(x, depth + 1);
1565
+ }
1566
+ return;
1567
+ }
1568
+ const e = v;
1569
+ if (!e.$$typeof || !e.props || typeof e.props !== "object" || seen.has(v)) return;
1570
+ if (budget-- < 0) {
1571
+ cut = true;
1572
+ return;
1573
+ }
1574
+ seen.add(v);
1575
+ const name = compName(e.type);
1576
+ if (!mounted.has(e.props) && typeof e.props.className === "string" && e.props.className && PLAIN.test(name) && !PLUMBING.test(name)) {
1577
+ const props = propsOf({ type: e.type, return: null, memoizedProps: e.props }), k = `${name} ${props}
1578
+ ${e.props.className}`, had = shut.get(k), cls = e.props.className.split(/\s+/).filter(Boolean);
1579
+ if (had) had.n++;
1580
+ else if (worn.get(e.type)?.some((w) => w.props === props && cls.every((t) => w.cls.has(t)))) {
1581
+ } else if (shut.size < 300) shut.set(k, { name, props, cls: e.props.className, n: 1 });
1582
+ else cut = true;
1583
+ }
1584
+ for (const k of Object.keys(e.props)) scan(e.props[k], depth + 1);
1585
+ };
1586
+ for (const f of fibers) {
1587
+ const p = f.memoizedProps;
1588
+ if (p && typeof p === "object") for (const k of Object.keys(p)) scan(p[k], 0);
1589
+ }
1590
+ for (const x of shut.values()) {
1591
+ x.el = document.createElement("div");
1592
+ x.el.className = x.cls;
1593
+ host.append(x.el);
1594
+ }
1595
+ }
1596
+ const ghosts = /* @__PURE__ */ new Map();
1597
+ for (const cls of [...uses.map((u) => u.cls), ...[...shut.values()].filter((x) => x.props).map((x) => x.cls.split(/\s+/).filter(Boolean))]) for (const t of cls) if (!ghosts.has(t) && ghosts.size < 500) {
1598
+ const g = document.createElement("div");
1599
+ g.className = t;
1600
+ host.append(g);
1601
+ ghosts.set(t, { el: g, sets: /* @__PURE__ */ new Map() });
1602
+ }
1603
+ const targets = /* @__PURE__ */ new Set([...controls.map((c) => c.el), ...uses.map((u) => u.el), ...[...ghosts.values()].map((g) => g.el)]);
1604
+ const matched = /* @__PURE__ */ new Map(), found = /* @__PURE__ */ new Map();
1605
+ for (const st of sheets.states) {
1606
+ if (st.on && (st.toggle || pressedIsOn)) continue;
1607
+ let els = found.get(st.base);
1608
+ if (!els) {
1609
+ try {
1610
+ els = [...document.querySelectorAll(st.base)].filter((e) => targets.has(e));
1611
+ } catch {
1612
+ els = [];
1613
+ }
1614
+ found.set(st.base, els);
1615
+ }
1616
+ for (const el of els) {
1617
+ const l = matched.get(el);
1618
+ if (l) l.push(st);
1619
+ else matched.set(el, [st]);
1620
+ }
1621
+ }
1622
+ const stateSaid = /* @__PURE__ */ new Map();
1623
+ const setters = /* @__PURE__ */ new Map();
1624
+ const settersOf = (prop) => {
1625
+ let l = setters.get(prop);
1626
+ if (!l) setters.set(prop, l = sheets.plain.filter((x) => x.style.getPropertyValue(prop)));
1627
+ return l;
1628
+ };
1629
+ const statesOf = (el) => {
1630
+ let said = stateSaid.get(el);
1631
+ if (said) return said;
1632
+ said = [];
1633
+ const real = forced.get(el), toggles = saysOn(el);
1634
+ if (real && real.size > 1) {
1635
+ const rest = real.get("rest"), cs = getComputedStyle(el), off2 = el.matches(":disabled");
1636
+ const attrPress = (matched.get(el) ?? []).some((st) => st.state === "pressed" && st.on) && !toggles;
1637
+ for (const [name, look] of real) {
1638
+ if (name === (attrPress ? "pressed" : "pressed-attr")) continue;
1639
+ const state = name === "pressed-attr" ? "pressed" : name;
1640
+ if (state === "rest" || state !== "focus" && cs.pointerEvents === "none" || state !== "hover" && off2) continue;
1641
+ for (const [k, v] of Object.entries(look)) {
1642
+ const c = v ? colorOf(v) : null;
1643
+ const was = (x) => x ? colorOf(x) : null;
1644
+ if (c && c !== was(rest[k]) && !(state === "pressed" && c === was(real.get("hover")?.[k]))) said.push(`${state} ${k.startsWith("overlay") ? "overlay fill" : k} ${c}`);
1645
+ }
1646
+ }
1647
+ stateSaid.set(el, said);
1648
+ return said;
1649
+ }
1650
+ const win = /* @__PURE__ */ new Map();
1651
+ const mine = matched.get(el) ?? [];
1652
+ for (const st of mine) for (const [prop, word] of [["background-color", "fill"], ["color", "text"], ["border-color", "line"]]) {
1653
+ const raw = st.on && toggles ? "" : st.style.getPropertyValue(prop);
1654
+ if (!raw) continue;
1655
+ const k = `${st.state}${st.pseudo ? " overlay" : ""} ${word}`, imp = st.style.getPropertyPriority(prop) === "important", had = win.get(k);
1656
+ if (!had || sheets.beats(st, imp, had.st, had.imp)) win.set(k, { raw, imp, st, prop });
1657
+ }
1658
+ const ecs = win.size ? getComputedStyle(el) : null, off = el.matches(":disabled");
1659
+ for (const [k, w] of win) {
1660
+ const state = w.st.state, long = w.prop === "border-color" ? "border-top-color" : w.prop;
1661
+ if (state !== "focus" && ecs.pointerEvents === "none" || state !== "hover" && off) continue;
1662
+ const inline = w.st.pseudo ? "" : el.style?.getPropertyValue(long) ?? "";
1663
+ if (inline && !(w.imp && el.style.getPropertyPriority(long) !== "important")) continue;
1664
+ if (settersOf(long).some((x) => {
1665
+ if (x === w.st || x.has.includes(state) || pseudoOf(x) !== w.st.pseudo || !sheets.beats(x, x.style.getPropertyPriority(long) === "important", w.st, w.imp)) return false;
1666
+ try {
1667
+ return el.matches(x.base);
1668
+ } catch {
1669
+ return false;
1670
+ }
1671
+ })) continue;
1672
+ const rest = getComputedStyle(el, w.st.pseudo ? `::${w.st.pseudo}` : void 0);
1673
+ if (w.st.pseudo && /^(none|normal)$/.test(rest.content) && !w.st.style.getPropertyValue("content")) continue;
1674
+ if (w.prop === "border-color" && !(parseFloat(rest.borderTopWidth) > 0)) continue;
1675
+ const same = [w.st.style, ...mine.filter((x) => x !== w.st && x.state === state && x.pseudo === w.st.pseudo).reverse().map((x) => x.style)];
1676
+ let value = resolveVars(w.raw, el, same);
1677
+ if (w.prop !== "color" && /currentcolor/i.test(value)) {
1678
+ const tw = win.get(`${state}${w.st.pseudo ? " overlay" : ""} text`) ?? win.get(`${state} text`);
1679
+ const text = tw ? resolveVars(tw.raw, el, [tw.st.style]) : "";
1680
+ value = value.replace(/currentcolor/gi, text && !/currentcolor|inherit/i.test(text) ? text : rest.color);
1681
+ }
1682
+ const c = colorOf(value);
1683
+ if (c && c !== colorOf(rest.getPropertyValue(long))) said.push(`${k} ${c}`);
1684
+ }
1685
+ stateSaid.set(el, said);
1686
+ return said;
1687
+ };
1688
+ const stateRule = (st) => {
1689
+ const w = rules.states?.[st];
1690
+ if (!w) return null;
1691
+ const m = /^wash\s+(\S+)$/.exec(w.trim()), name = m ? m[1] : w.trim(), c = m && rules.colors?.[name] ? parseColor(rules.colors[name]) : null;
1692
+ return m ? c ? { wash: c, name } : null : { name };
1693
+ };
1694
+ for (const c of controls) for (const s of statesOf(c.el)) {
1695
+ add(groups.states, s, c.el, c.r);
1696
+ const m = /^(\w+)( overlay)? fill (#[0-9a-f]{6,8})$/.exec(s), want2 = m ? stateRule(m[1]) : null;
1697
+ if (!m || !want2) continue;
1698
+ const got = parseColor(m[3]);
1699
+ if (want2.wash) {
1700
+ const rest = parseColor(getComputedStyle(c.el).backgroundColor), back = behind(c.el.parentElement), under = rest && rest[3] >= 0.02 ? rest[3] >= 0.995 ? rest : over(rest, back) : back;
1701
+ if (Math.max(under[0], under[1], under[2]) - Math.min(under[0], under[1], under[2]) > 16) continue;
1702
+ const ok = m[2] ? dist(got, want2.wash) <= 2 : dist(got[3] >= 0.995 ? got : over(got, back), over(want2.wash, under)) <= 3;
1703
+ if (!ok) add(groups.rules, `${m[1]} fill ${m[3]} is not a ${want2.name} wash${m[2] ? "" : ` over ${hex(under)}`}`, c.el, c.r);
1704
+ } else if (base$(nameOf$(m[3]) ?? "") !== want2.name) add(groups.rules, `${m[1]} fill ${m[3]}: ${m[1]} takes ${want2.name}`, c.el, c.r);
1705
+ }
1706
+ const focusW = want("focus");
1707
+ if (focusW.level) {
1708
+ const within = sheets.plain.filter((x) => /:focus-within/.test(x.sel)).map((x) => x.sel.replace(/:focus-within/g, ""));
1709
+ for (const c of controls) {
1710
+ const real = forced.get(c.el), ring = real && rings.get(real);
1711
+ if (!real?.has("focus") || !ring?.focus || turnedOff(c.el) || c.el.closest("[inert]") || c.el.getAttribute("tabindex") === "-1") continue;
1712
+ if (JSON.stringify(real.get("focus")) !== JSON.stringify(real.get("rest")) || ring.focus !== ring.rest) continue;
1713
+ let unsure = false;
1714
+ for (let a = c.el.parentElement; a && !unsure; a = a.parentElement) unsure = within.some((s) => {
1715
+ try {
1716
+ return a.matches(s);
1717
+ } catch {
1718
+ return false;
1719
+ }
1720
+ });
1721
+ hit(`focus|${part(c.el)?.key ?? c.el.tagName.toLowerCase()}`, c.el, c.r, { unsure });
1722
+ }
1723
+ }
1724
+ const targetW = want("target");
1725
+ if (targetW.level) {
1726
+ const min = targetW.n ?? 24;
1727
+ const boxes = controls.filter((c) => !c.el.closest("[inert]")).map((c) => ({ el: c.el, r: c.el.getBoundingClientRect() }));
1728
+ const exempt = (el) => {
1729
+ if (turnedOff(el)) return true;
1730
+ const cs = getComputedStyle(el);
1731
+ if (el.matches("a[href]") && cs.display === "inline" && [...el.parentElement?.childNodes ?? []].some((n) => n !== el && n.nodeType === 3 && n.textContent?.trim())) return true;
1732
+ return el instanceof HTMLInputElement && /^(checkbox|radio|range|color|file|date|time)$/.test(el.type) && cs.appearance !== "none";
1733
+ };
1734
+ const small = boxes.filter((b) => (b.r.width < min - 0.5 || b.r.height < min - 0.5) && !exempt(b.el)).map((b) => {
1735
+ let r = b.r;
1736
+ for (const l of b.el.labels ?? []) {
1737
+ const lr = l.getBoundingClientRect();
1738
+ const L = Math.min(r.left, lr.left), T = Math.min(r.top, lr.top);
1739
+ r = new DOMRect(L, T, Math.max(r.right, lr.right) - L, Math.max(r.bottom, lr.bottom) - T);
1740
+ }
1741
+ return { ...b, hit: r };
1742
+ }).filter((b) => b.hit.width < min - 0.5 || b.hit.height < min - 0.5);
1743
+ const mid = (r) => [r.left + r.width / 2, r.top + r.height / 2];
1744
+ const reaches = (x, y, r) => Math.hypot(x - Math.max(r.left, Math.min(x, r.right)), y - Math.max(r.top, Math.min(y, r.bottom))) < min / 2;
1745
+ for (const s of small) {
1746
+ const [x, y] = mid(s.hit);
1747
+ const near = boxes.some((o) => o.el !== s.el && !o.el.contains(s.el) && !s.el.contains(o.el) && reaches(x, y, o.r)) || small.some((o) => o !== s && !o.el.contains(s.el) && !s.el.contains(o.el) && Math.hypot(x - mid(o.hit)[0], y - mid(o.hit)[1]) < min);
1748
+ if (near) hit(`target|${part(s.el)?.key ?? s.el.getAttribute("role") ?? s.el.tagName.toLowerCase()}|${Math.round(s.hit.width)}x${Math.round(s.hit.height)}`, s.el, s.r);
1749
+ }
1750
+ }
1751
+ const closed = [];
1752
+ if (uses.length || shut.size) {
1753
+ const bare = host.appendChild(document.createElement("div")), bcs = getComputedStyle(bare);
1754
+ const base = new Map(LOOK.map((k) => [k, bcs.getPropertyValue(k)]));
1755
+ for (const g of ghosts.values()) {
1756
+ const gcs = getComputedStyle(g.el);
1757
+ for (const k of LOOK) {
1758
+ const v = gcs.getPropertyValue(k);
1759
+ if (v !== base.get(k)) g.sets.set(k, v);
1760
+ }
1761
+ }
1762
+ for (const u of uses) {
1763
+ const cs = getComputedStyle(u.el), set = new Set(u.style), hover = /* @__PURE__ */ new Set();
1764
+ for (const t of u.cls) {
1765
+ const g = ghosts.get(t);
1766
+ if (!g) continue;
1767
+ for (const [k, v] of g.sets) if (cs.getPropertyValue(k) === v) set.add(k);
1768
+ for (const s of statesOf(g.el)) hover.add(s);
1769
+ }
1770
+ const items2 = [];
1771
+ for (const k of LOOK) {
1772
+ if (!set.has(k)) continue;
1773
+ const v = cs.getPropertyValue(k), c = /color$/.test(k) ? colorOf(v) : null;
1774
+ if (k === "height" || k === "min-height") {
1775
+ if (u.ctl) items2.push(`${k === "height" ? "height" : "min height"} ${num(parseFloat(v))}px`);
1776
+ } else if (k === "border-top-left-radius") items2.push(`corner ${sayCorner(cornerOf(cs))}`);
1777
+ else if (k === "background-color") items2.push(`fill ${c ?? "none"}`);
1778
+ else if (k === "color") {
1779
+ if (c) items2.push(`text ${c}`);
1780
+ } else if (k === "border-top-color") {
1781
+ if (c && parseFloat(cs.borderTopWidth) > 0 && c !== colorOf(cs.color)) items2.push(`line ${c}`);
1782
+ } else if (k === "font-size" || k === "line-height") items2.push(`${k === "font-size" ? "size" : "line height"} ${num(parseFloat(v))}px`);
1783
+ else if (k === "font-weight") items2.push(`weight ${v}`);
1784
+ else if (k === "letter-spacing") items2.push(`tracking ${num(parseFloat(v) || 0)}px`);
1785
+ else if (k === "font-family") items2.push(`font ${v.replace(/["']/g, "").split(",")[0]}\u2026`);
1786
+ else if (k === "box-shadow") {
1787
+ const s = shadowLayers(v);
1788
+ items2.push(`shadow ${s.rest.length ? sayShadow(s.rest.join(", ")) : s.rings.length ? s.rings.join(", ") : "none"}`);
1789
+ }
1790
+ }
1791
+ const mine = statesOf(u.el);
1792
+ items2.push(...[...hover].filter((s) => mine.includes(s)));
1793
+ if (!items2.length || items2.every((i) => i.startsWith("text "))) continue;
1794
+ add(groups.used, `${u.key}: ${items2.join("; ")}`, u.el, u.r);
1795
+ }
1796
+ const rows = /* @__PURE__ */ new Map();
1797
+ for (const x of shut.values()) {
1798
+ const cs = getComputedStyle(x.el), fill = colorOf(cs.backgroundColor), sh = shadowLayers(cs.boxShadow), line = lineOf(cs), say = x.props ? `${x.name} ${x.props}` : x.name;
1799
+ let row = "";
1800
+ if (fill && (sh.rest.length || cornerOf(cs) !== "0" || line)) row = `${say}: corner ${sayCorner(cornerOf(cs))} fill ${fill}${line ? ` line ${line}` : ""} shadow ${sh.rest.length ? sayShadow(sh.rest.join(", ")) : "none"}`;
1801
+ else if (x.props && (!rules.parts?.length || rules.parts.includes(x.name))) {
1802
+ const set = /* @__PURE__ */ new Map(), hover = /* @__PURE__ */ new Set();
1803
+ for (const t of x.cls.split(/\s+/)) {
1804
+ const g = ghosts.get(t);
1805
+ if (!g) continue;
1806
+ for (const [k, v] of g.sets) set.set(k, v);
1807
+ for (const st of statesOf(g.el)) hover.add(st);
1808
+ }
1809
+ const items2 = [set.has("height") ? `height ${num(parseFloat(set.get("height")))}px` : "", set.has("border-top-left-radius") ? `corner ${sayCorner(cornerOf(cs))}` : "", fill ? `fill ${fill}` : "", ...hover].filter((i) => i && !/NaN/.test(i));
1810
+ if (items2.length) row = `${say}: set where used: ${items2.join("; ")}`;
1811
+ }
1812
+ if (row) rows.set(row, (rows.get(row) ?? 0) + x.n);
1813
+ }
1814
+ for (const [k, n] of [...rows].slice(0, 30)) closed.push({ key: sayColors(k), n, at: [] });
1815
+ }
1816
+ const SHORT = { "border-top-left-radius": ["border-radius"], "background-color": ["background"], "font-family": ["font"], "line-height": ["font"] };
1817
+ const PASS = /^(inherit|unset|revert|revert-layer)$/;
1818
+ const declared = (style, prop) => style.getPropertyValue(prop).trim() || (SHORT[prop] ?? []).map((k) => style.getPropertyValue(k).trim()).find((v) => v.includes("var(")) || "";
1819
+ const declaring = /* @__PURE__ */ new Map();
1820
+ const whence = (el, prop, inherited) => {
1821
+ let list = declaring.get(prop);
1822
+ if (!list) declaring.set(prop, list = sheets.plain.filter((x) => declared(x.style, prop)));
1823
+ for (let e = el, i = 0; e && i < (inherited ? 16 : 1); e = e.parentElement, i++) {
1824
+ const own = e.style ? declared(e.style, prop) : "";
1825
+ if (own && !PASS.test(own)) return " (from its style attribute)";
1826
+ const hits2 = /* @__PURE__ */ new Map(), pass = [];
1827
+ for (const x of list) {
1828
+ try {
1829
+ if (e.matches(x.sel)) {
1830
+ if (PASS.test(declared(x.style, prop))) pass.push(x);
1831
+ else hits2.set(x.style, x);
1832
+ }
1833
+ } catch {
1834
+ }
1835
+ }
1836
+ if (hits2.size > 1) return "";
1837
+ for (const [style, x] of hits2) {
1838
+ const imp = (r) => r.style.getPropertyPriority(prop) === "important";
1839
+ if (own || pass.some((y) => sheets.beats(y, imp(y), x, imp(x)))) break;
1840
+ const text = declared(style, prop), whole = text.match(/^var\((--[\w-]+)\)$/), vars = style.getPropertyValue(prop) ? [] : [...text.matchAll(/var\((--[\w-]+)/g)];
1841
+ const v = whole?.[1] ?? (vars.length === 1 ? vars[0][1] : "");
1842
+ return ` (from ${x.sel.length > 40 ? `${x.sel.slice(0, 39)}\u2026` : x.sel}, ${v ? `via var(${v})` : "written out"})`;
1843
+ }
1844
+ if (!inherited || !e.parentElement || getComputedStyle(e).getPropertyValue(prop) !== getComputedStyle(e.parentElement).getPropertyValue(prop)) return "";
1845
+ }
1846
+ return "";
1847
+ };
1848
+ const typeNote = (k) => !rules.type?.length || rules.type.includes(k.split(" ")[0]) ? "" : " OFF";
1849
+ const radiusNote = (k) => {
1850
+ if (!rules.radii?.length) return "";
1851
+ const off = k.split(" ").map(parseFloat).filter((v) => v > 0 && !rules.radii.includes(v));
1852
+ return off.length ? ` OFF (nearest ${rules.radii.reduce((a, b) => Math.abs(b - off[0]) < Math.abs(a - off[0]) ? b : a)}px)` : "";
1853
+ };
1854
+ const nearOf = (g, k, list) => {
1855
+ const me = list.find((x) => x[0] === k);
1856
+ for (const [o, s] of list) {
1857
+ if (o === k || s.n < me[1].n) continue;
1858
+ if (g === "text" || g === "fill" || g === "line") {
1859
+ const a = parseColor(k.split(" ")[0]), b = parseColor(o.split(" ")[0]);
1860
+ if (a && b && dist(a, b) > 0 && dist(a, b) <= 12 && k.split(" ").slice(1).join(" ") === o.split(" ").slice(1).join(" ")) return ` near ${sayColors(o.split(" ")[0])}`;
1861
+ } else if (g === "radius" && !/full| /.test(k + o) && Math.abs(parseFloat(k) - parseFloat(o)) <= 1.5) return ` near ${o}`;
1862
+ else if (g === "type") {
1863
+ const [a, b] = [k.split(/[/ ]/), o.split(/[/ ]/)];
1864
+ if (a[0] !== b[0] && Math.abs(parseFloat(a[0]) - parseFloat(b[0])) <= 1 && a[1] === b[1]) return ` near ${o.split(" ")[0]}`;
1865
+ if (a[0] === b[0] && a[1] === b[1] && a[2] !== b[2]) return ` near ${o.split(" ")[0]} (line height)`;
1866
+ } else if (g === "height") {
1867
+ const [ka, kh] = [k.replace(/ \d+px.*$/, ""), parseFloat(k.match(/(\d+)px/)[1])], [oa, oh] = [o.replace(/ \d+px.*$/, ""), parseFloat(o.match(/(\d+)px/)[1])];
1868
+ if (ka === oa && kh !== oh && Math.abs(kh - oh) <= 4 && [...me[1].parts ?? []].some((x) => s.parts?.has(x))) return ` near ${oh}px (same part)`;
1869
+ }
1870
+ }
1871
+ return "";
1872
+ };
1873
+ const WHENCE = { text: ["color", true], fill: ["background-color", false], radius: ["border-top-left-radius", false] };
1874
+ const made = [];
1875
+ for (const [g, map] of Object.entries(groups)) {
1876
+ const list = [...map].sort((a, b) => b[1].n - a[1].n);
1877
+ if (!list.length && !(g === "align" && groups.type.size)) continue;
1878
+ const rows = list.map(([k, s]) => {
1879
+ let key = k, note = "";
1880
+ if (g === "font") {
1881
+ key = k === list[0][0] ? k : fontDiff(k, list[0][0]);
1882
+ note = whence(s.el, "font-family", true);
1883
+ } else if (g === "type") note = typeNote(k);
1884
+ else if (g === "radius") note = radiusNote(k);
1885
+ else if (g === "shadow") key = sayShadow(k);
1886
+ else if (g === "layer") key = `${sayColors(k.slice(0, k.indexOf(" shadow ")))} shadow ${sayShadow(k.slice(k.indexOf(" shadow ") + 8))}`;
1887
+ else if (g === "text" || g === "fill" || g === "line") {
1888
+ const [h, ...rest] = k.split(" "), t = tokenOf(h), near = nearOf(g, k, list);
1889
+ key = [t.name && near !== ` near ${t.name}` ? t.name : h, ...rest].join(" ");
1890
+ note = t.off ?? "";
1891
+ } else key = sayColors(k);
1892
+ note += nearOf(g, k, list);
1893
+ if (note && WHENCE[g] && !/\(icon\)/.test(k)) note += whence(s.el, ...WHENCE[g]);
1894
+ else if (g === "type" && / \(line height\)$/.test(note)) note += whence(s.el, "line-height", true);
1895
+ const at2 = rules.sources && (g === "used" || g === "rules" || / OFF| near /.test(`${key}${note}`)) ? s.at.map((a, i) => {
1896
+ const e = s.els?.[i];
1897
+ return e ? `${a}${srcOf(part(e) ?? ownerOf(e)) || hostSrc(e)}` : a;
1898
+ }) : s.at;
1899
+ return { key, n: s.n, note: note || void 0, at: at2 };
1900
+ });
1901
+ if (g === "align") rows.push({ key: "every other text at the start of its box", n: 0, at: [] });
1902
+ if (g === "type") {
1903
+ for (const [size, per] of tracking) {
1904
+ const signs = [...per].sort((a, b) => b[1].n - a[1].n);
1905
+ const odd = signs.find(([ls]) => ls * signs[0][0] < 0);
1906
+ if (odd) rows.push({ key: `tracking at ${size}px: ${signs.map(([ls, s]) => `${ls > 0 ? "+" : ""}${ls} \xD7${s.n}`).join(", ")}`, n: 0, note: whence(odd[1].el, "letter-spacing", true) || void 0, at: odd[1].at });
1907
+ }
1908
+ }
1909
+ const WHAT = { used: "what a part's use site changed about its look with a class or style of its own", layer: "pop-ups and their boxes", layout: "rows, columns, grids and filled boxes: the gaps between their children as drawn, their padding, how the children sit", align: "words set other than to the start of their box", rules: "the rules file's roles, text, states, pairs and legacy, each line one rule broken" };
1910
+ made.push({ name: g === "used" ? "set where used" : g === "rules" ? "rules broken" : g, what: WHAT[g], rows });
1911
+ }
1912
+ const partRows = [...looks].map(([key, l]) => ({ key, n: [...l.m.values()].reduce((n, x) => n + x.n, 0), at: [], flag: l.flag, looks: [...l.m.values()].map((x) => ({ ...x, skin: sayColors(x.skin), say: sayColors(x.say) })) }));
1913
+ partRows.sort((a, b) => looksOf(b) - looksOf(a) || b.n - a.n);
1914
+ if (closed.length) made.push({ name: "closed", what: "would look; not on screen: pop-ups and their contents the page holds but hasn't opened", rows: closed });
1915
+ if (partRows.length) made.push({ name: "parts", what: "by the component that drew them; looks are height (controls), corner, fill and text color, by state", rows: partRows });
1916
+ const findings = [];
1917
+ const push = (f, level) => {
1918
+ if (level) findings.push({ ...f, level });
1919
+ };
1920
+ const plain = (note) => (note ?? "").replace(/ \((from|via) .*$/, "");
1921
+ const offW = want("off");
1922
+ for (const g of made) {
1923
+ if (/^(parts|closed|left out|layout problems)$/.test(g.name)) continue;
1924
+ for (const r of g.rows) {
1925
+ const said = `${r.key}${r.note ?? ""}`;
1926
+ if (/ OFF/.test(said)) push({ id: `off|${g.name}|${r.key}`, check: "off", key: `${g.name} ${r.key}${plain(r.note)}`, n: r.n, at: r.at.slice(0, 1) }, offW.level);
1927
+ }
1928
+ }
1929
+ for (const r of partRows) if (/\(no DS part\)/.test(r.key)) push({ id: `no-part|${r.key}`, check: "no-part", key: r.key, n: r.n, at: (r.looks ?? []).flatMap((l) => l.at).slice(0, 2) }, want("no-part").level);
1930
+ for (const [id, h] of hits) {
1931
+ const [check, a, b] = id.split("|");
1932
+ if (check === "contrast") {
1933
+ const team = W.contrast.n, floor = team !== void 0 ? h.big ? Math.min(3, team) : team : h.big ? 3 : 4.5, wcag = h.big ? 3 : 4.5;
1934
+ const crit = team !== void 0 && team < wcag ? ` (team floor; WCAG 1.4.3 asks ${wcag})` : " (WCAG 1.4.3)";
1935
+ const nm = (x) => tokenOf(x).name ?? x;
1936
+ push({ id, check, key: `contrast ${h.min.toFixed(2)}:1 ${h.what}${nm(h.fg)} on ${nm(h.bg)}${h.big ? " (large text)" : ""} below ${floor}${crit}`, n: h.n, at: h.at, unsure: h.unsure, values: h.names }, W.contrast.level);
1937
+ } else if (check === "focus") push({ id, check, key: `focus not visible (2.4.7): ${a} changes nothing focused`, n: h.n, at: h.at, unsure: h.unsure, values: h.names }, focusW.level);
1938
+ else if (check === "target") push({ id, check, key: `target ${b} under ${targetW.n ?? 24}px, too close to another (2.5.8): ${a}`, n: h.n, at: h.at, values: h.names }, targetW.level);
1939
+ }
1940
+ findings.push(...maxFindings(made, rules));
1941
+ const give = shares(made.map((g) => g.rows.length), cap);
1942
+ made.forEach((g, i) => {
1943
+ if (g.rows.length > give[i]) {
1944
+ g.more = g.rows.length - give[i];
1945
+ g.rows = g.rows.slice(0, give[i]);
1946
+ }
1947
+ });
1948
+ const left = [];
1949
+ if (placeholders.size) left.push({ key: "loading placeholders (empty boxes that animate forever)", n: [...placeholders.values()].reduce((a, b) => a + b, 0), at: [[...placeholders].map(([f, n]) => `fill ${sayColors(f)} \xD7${n}`).join(", ")] });
1950
+ if (moving) left.push({ key: "mid-animation when read (a flash or a fade: its fill and look aren't counted)", n: moving, at: [] });
1951
+ if (hot) left.push({ key: "under the pointer, pressed or focused when read (it wears that state's colors: its fill, line and look aren't counted)", n: hot, at: [] });
1952
+ if (cut) left.push({ key: "closed pop-ups: the scan stopped early, the closed list is incomplete", n: 0, at: [] });
1953
+ if (embedded.size) left.push({ key: "not the app's components (drawn by another script: a dev tool, an embedded widget)", n: [...embedded.values()].reduce((a, b) => a + b, 0), at: [...embedded.keys()].slice(0, 4).map((e) => {
1954
+ const b = e.matches("button,a[href]") ? e : e.querySelector("button,[role=button],a[href]") ?? e;
1955
+ return `${nameOf(b)} ${box(b.getBoundingClientRect())}`;
1956
+ }) });
1957
+ if (sheets.unreadable) left.push({ key: `${sheets.unreadable} sheets unreadable (another site's: their hover and pressed colors aren't in states)`, n: 0, at: [] });
1958
+ if (left.length) made.push({ name: "left out", what: "", rows: left });
1959
+ const gone = [...embedded.keys(), ...out];
1960
+ const problems = layoutLines(root, 160, gone.length ? (el) => gone.some((x) => x.contains(el)) : void 0, rules.contrast ?? FAINT_TEXT).filter((l) => PROBLEM.test(l));
1961
+ if (problems.length) made.push({ name: "layout problems", what: "", rows: problems.slice(0, 30).map((l) => ({ key: l, n: 0, at: [] })), more: Math.max(0, problems.length - 30) || void 0 });
1962
+ let items;
1963
+ if (snap) {
1964
+ items = [];
1965
+ for (const [name, it] of snap) {
1966
+ const p = part(name), st = stateOf(name), look = {};
1967
+ for (const [g, ks] of it.look) look[g === "used" ? "set where used" : g === "rules" ? "rules broken" : g] = ks.map((k) => g === "shadow" ? sayShadow(k) : sayColors(k)).join("; ");
1968
+ if (st) look.state = st;
1969
+ const tag = name.getAttribute("role") ?? name.tagName.toLowerCase();
1970
+ items.push({ id: `${nameOf(name)}${p ? ` [${p.say}]` : ""}${where(it.el)}`, loose: `${tag}${p ? ` [${p.key}]` : ""}${where(it.el)}`, at: place(it.el, it.r, name), box: [it.r.left, it.r.top, it.r.width, it.r.height].map(Math.round), look });
1971
+ }
1972
+ }
1973
+ const report = asksChecks(rules);
1974
+ const against = rules.colors || rules.type || rules.radii ? ", checked against the design system's values" : checkSetting(rules, "max").level ? ", against best practice" : "";
1975
+ return { head: `styles on screen, window ${innerWidth}x${innerHeight}${against}`, groups: made, items, findings, ...report ? { report } : {} };
1976
+ }
1977
+
1978
+ // src/browser.ts
1979
+ var at = (sel) => sel ? document.querySelector(sel) ?? document.body : document.body;
1980
+ window.census = {
1981
+ data: (rules, sel) => styleData(rules, at(sel)),
1982
+ lines: (c) => censusLines(c),
1983
+ merge: (pages) => mergeCensus(pages),
1984
+ layout: () => layoutLines(),
1985
+ // for a capture that forces states through the DevTools Protocol
1986
+ forceMark,
1987
+ forceRead,
1988
+ forceDone
1989
+ };
1990
+ })();