beam-alpha 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/probe.js ADDED
@@ -0,0 +1,3084 @@
1
+ "use strict";
2
+ (() => {
3
+ // ../../node_modules/torph/dist/index.mjs
4
+ var _t = { locale: "en", duration: 400, ease: "cubic-bezier(0.19, 1, 0.22, 1)", disabled: false, respectReducedMotion: true };
5
+ function Dt(e, t, n) {
6
+ if (n < 1) {
7
+ let u = t * Math.sqrt(1 - n * n);
8
+ return 1 - Math.exp(-n * t * e) * (Math.cos(u * e) + n * t / u * Math.sin(u * e));
9
+ }
10
+ let i = Math.sqrt(n * n - 1), r = -t * (n + i), s = -t * (n - i), o = -r / (s - r);
11
+ return 1 - (1 - o) * Math.exp(r * e) - o * Math.exp(s * e);
12
+ }
13
+ function Ie(e, t, n) {
14
+ let s = 0;
15
+ for (let o = 0; o < 10; o += 1e-3) if (Math.abs(Dt(o, e, t) - 1) > n) s = 0;
16
+ else if (s += 1e-3, s > 0.1) return Math.ceil((o - s + 1e-3) * 1e3);
17
+ return Math.ceil(10 * 1e3);
18
+ }
19
+ function Ft(e, t) {
20
+ if (typeof e == "object") {
21
+ let n = Le(e);
22
+ return { ease: n.easing, duration: n.duration };
23
+ }
24
+ return { ease: e, duration: t };
25
+ }
26
+ var $t = /* @__PURE__ */ new Map();
27
+ function Le(e) {
28
+ let { stiffness: t = 100, damping: n = 10, mass: i = 1, precision: r = 1e-3 } = e ?? {}, s = `${t}:${n}:${i}:${r}`, o = $t.get(s);
29
+ if (o) return o;
30
+ let a = Math.sqrt(t / i), u = n / (2 * Math.sqrt(t * i)), c = Ie(a, u, r), f = Math.min(100, Math.max(32, Math.round(c / 15))), l = [];
31
+ for (let d = 0; d < f; d++) {
32
+ let h = d / (f - 1) * (c / 1e3), M = d === f - 1 ? 1 : Dt(h, a, u);
33
+ l.push(Math.round(M * 1e4) / 1e4 + "");
34
+ }
35
+ for (; l.length > 2 && l[l.length - 2] === "1"; ) l.splice(l.length - 2, 1);
36
+ let m = { easing: `linear(${l.join(", ")})`, duration: c };
37
+ return $t.set(s, m), m;
38
+ }
39
+ function G(e, t) {
40
+ let n = e.length, i = t.length, r = Array.from({ length: n + 1 }, () => Array(i + 1).fill(0));
41
+ for (let c = n - 1; c >= 0; c--) for (let f = i - 1; f >= 0; f--) r[c][f] = e[c] === t[f] ? r[c + 1][f + 1] + 1 : Math.max(r[c + 1][f], r[c][f + 1]);
42
+ let s = [], o = [], a = 0, u = 0;
43
+ for (; a < n && u < i; ) e[a] === t[u] ? (s.push(a), o.push(u), a++, u++) : r[a + 1][u] >= r[a][u + 1] ? a++ : u++;
44
+ return [s, o];
45
+ }
46
+ var Ne = "\0n";
47
+ var ke = 0;
48
+ function ht() {
49
+ return `${Ne}${ke++}`;
50
+ }
51
+ function k(e) {
52
+ return e >= "0" && e <= "9";
53
+ }
54
+ function q(e) {
55
+ for (let t of e) if (k(t)) return true;
56
+ return false;
57
+ }
58
+ function gt(e) {
59
+ let t = "";
60
+ for (let n of e) !k(n) && !bt.includes(n) && (t += n);
61
+ return t;
62
+ }
63
+ var bt = ".,'\xA0\u202F\u2009\u2007";
64
+ var He = "+-\u2212(#";
65
+ var Oe = `%.,!?:;)"'\u201D\u2019`;
66
+ var _e = new RegExp("\\p{Sc}", "u");
67
+ function Pt(e, t) {
68
+ return t.includes(e) || _e.test(e);
69
+ }
70
+ function J(e) {
71
+ let t = 0, n = e.length;
72
+ for (; t < n && Pt(e[t], He); ) t++;
73
+ for (; n > t && Pt(e[n - 1], Oe); ) n--;
74
+ if (t >= n || !k(e[t]) || !k(e[n - 1])) return false;
75
+ for (let i = t; i < n; i++) {
76
+ let r = e[i];
77
+ if (!k(r) && !bt.includes(r)) return false;
78
+ }
79
+ return true;
80
+ }
81
+ function at(e) {
82
+ return k(e) ? "digit" : "symbol";
83
+ }
84
+ var Ct = /* @__PURE__ */ new Map();
85
+ function xt(e) {
86
+ let t = String(e), n = Ct.get(t);
87
+ if (n) return n;
88
+ let i = ".";
89
+ try {
90
+ i = new Intl.NumberFormat(e).formatToParts(1.1).find((r) => r.type === "decimal")?.value ?? ".";
91
+ } catch {
92
+ }
93
+ return Ct.set(t, i), i;
94
+ }
95
+ function U(e, t, n, i = ".") {
96
+ let r = e.split("");
97
+ if (!t || t.length === 0) return $e(r);
98
+ let s = t.map((c) => c.string === "\xA0" ? " " : c.string), o = n != null ? De(s, r, n, i) : Fe(s, r, i), a = /* @__PURE__ */ new Set();
99
+ for (let [, c] of o) a.add(t[c].id);
100
+ let u = [];
101
+ for (let c = 0; c < r.length; c++) {
102
+ let f = r[c], l = at(f), m = f === " " ? "\xA0" : f;
103
+ if (o.has(c)) {
104
+ let d = o.get(c);
105
+ u.push({ id: t[d].id, string: m, kind: l });
106
+ } else {
107
+ let d = ht();
108
+ for (; a.has(d); ) d = ht();
109
+ a.add(d), u.push({ id: d, string: m, kind: l });
110
+ }
111
+ }
112
+ return u;
113
+ }
114
+ function $e(e) {
115
+ return e.map((t) => ({ id: ht(), string: t === " " ? "\xA0" : t, kind: at(t) }));
116
+ }
117
+ function De(e, t, n, i) {
118
+ let r = /* @__PURE__ */ new Map(), s = Xt(e, i), o = Xt(t, i), a = (m, d) => r.set(o[m], s[d]), u = 0;
119
+ for (; u < o.length && o[u] < n; ) u++;
120
+ let c = o.length - s.length;
121
+ if (c > 0) {
122
+ let m = u - c;
123
+ for (let d = 0; d < m && d < s.length; d++) a(d, d);
124
+ for (let d = u; d < o.length; d++) {
125
+ let h = d - c;
126
+ h >= 0 && h < s.length && a(d, h);
127
+ }
128
+ } else if (c < 0) {
129
+ for (let m = 0; m < u && m < o.length; m++) a(m, m);
130
+ for (let m = u; m < o.length; m++) {
131
+ let d = m - c;
132
+ d >= 0 && d < s.length && a(m, d);
133
+ }
134
+ } else for (let m = 0; m < o.length; m++) t[o[m]] === e[s[m]] && a(m, m);
135
+ let f = Bt(e, i), l = Bt(t, i);
136
+ for (let m = 1; m <= f.length && m <= l.length; m++) {
137
+ let d = f[f.length - m], h = l[l.length - m];
138
+ e[d] === t[h] && r.set(h, d);
139
+ }
140
+ return r;
141
+ }
142
+ function Kt(e, t) {
143
+ return e !== t && bt.includes(e);
144
+ }
145
+ function Xt(e, t) {
146
+ let n = [];
147
+ for (let i = 0; i < e.length; i++) Kt(e[i], t) || n.push(i);
148
+ return n;
149
+ }
150
+ function Bt(e, t) {
151
+ let n = [];
152
+ for (let i = 0; i < e.length; i++) Kt(e[i], t) && n.push(i);
153
+ return n;
154
+ }
155
+ function Fe(e, t, n) {
156
+ let i = /* @__PURE__ */ new Map(), r = 0;
157
+ for (; r < e.length && r < t.length && e[r] === t[r] && !k(e[r]); ) i.set(r, r), r++;
158
+ let s = e.length, o = t.length;
159
+ for (; s > r && o > r && e[s - 1] === t[o - 1] && !k(e[s - 1]); ) i.set(o - 1, s - 1), s--, o--;
160
+ let a = Ut(e, r, s, n), u = Ut(t, r, o, n), c = Gt(e, r, a), f = Gt(t, r, u);
161
+ if (c > 0 && f > 0 && Math.abs(c - f) >= Pe) return i;
162
+ if (!d(r, a, r, u, true)) for (let h = 1; a - h >= r && u - h >= r; h++) m(a - h, u - h);
163
+ if (a < s && u < o) {
164
+ i.set(u, a);
165
+ for (let h = 1; a + h < s && u + h < o; h++) m(a + h, u + h);
166
+ d(a + 1, s, u + 1, o, false);
167
+ }
168
+ function m(h, M) {
169
+ let x = e[h];
170
+ k(x) || x === t[M] && i.set(M, h);
171
+ }
172
+ function d(h, M, x, T, L) {
173
+ let E = Wt(e, h, M), N = Wt(t, x, T);
174
+ if (E.length === N.length || !L) {
175
+ let A = Math.min(E.length, N.length);
176
+ for (let _ = 0; _ < A; _++) {
177
+ let B = E[_], rt = N[_];
178
+ e[B] === t[rt] && i.set(rt, B);
179
+ }
180
+ return false;
181
+ }
182
+ let g = E.map((A) => e[A]).reverse(), v = N.map((A) => t[A]).reverse(), [R, O] = G(g, v);
183
+ for (let A = 0; A < R.length; A++) {
184
+ let _ = E[E.length - 1 - R[A]], B = N[N.length - 1 - O[A]];
185
+ i.set(B, _);
186
+ }
187
+ return R.length > 0;
188
+ }
189
+ return i;
190
+ }
191
+ function Wt(e, t, n) {
192
+ let i = [];
193
+ for (let r = t; r < n; r++) k(e[r]) && i.push(r);
194
+ return i;
195
+ }
196
+ var Pe = 3;
197
+ function Gt(e, t, n) {
198
+ let i = 0;
199
+ for (let r = t; r < n; r++) k(e[r]) && i++;
200
+ return i;
201
+ }
202
+ function Ut(e, t, n, i) {
203
+ for (let r = n - 1; r >= t; r--) if (e[r] === i) return r;
204
+ return n;
205
+ }
206
+ function yt() {
207
+ let e = /* @__PURE__ */ new Set();
208
+ return { reserve(t) {
209
+ e.add(t);
210
+ }, has(t) {
211
+ return e.has(t);
212
+ }, take(t) {
213
+ if (!e.has(t)) return e.add(t), t;
214
+ let n = 1;
215
+ for (; e.has(`${t}~${n}`); ) n++;
216
+ let i = `${t}~${n}`;
217
+ return e.add(i), i;
218
+ } };
219
+ }
220
+ function zt(e) {
221
+ let t = [], n = [], i = () => {
222
+ n.length !== 0 && (t.push({ word: n.map((r) => r.string).join(""), segments: n }), n = []);
223
+ };
224
+ for (let r of e) r.string === "\xA0" || r.string === `
225
+ ` ? i() : n.push(r);
226
+ return i(), t;
227
+ }
228
+ function Yt(e) {
229
+ let t = [], n = [], i = () => {
230
+ if (n.length === 0) return;
231
+ let r = n.map((s) => s.string).join("");
232
+ J(r) ? t.push(...U(r)) : t.push(...n), n = [];
233
+ };
234
+ for (let r of e) r.string === "\xA0" || r.string === `
235
+ ` ? (i(), t.push(r)) : n.push(r);
236
+ return i(), t;
237
+ }
238
+ function K(e, t, n = true) {
239
+ let i = e.includes(`
240
+ `), r = e.includes(" ") || i, s = yt();
241
+ if (i) {
242
+ let a = e.split(`
243
+ `), u = [], c = 0;
244
+ return a.forEach((f, l) => {
245
+ l > 0 && (u.push({ id: s.take(`newline-${c}`), string: `
246
+ ` }), c += 1), f.length > 0 && u.push(...jt(f, t, true, c, s)), c += f.length;
247
+ }), n ? Yt(u) : u;
248
+ }
249
+ let o = jt(e, t, r, 0, s);
250
+ return n ? Yt(o) : o;
251
+ }
252
+ function jt(e, t, n, i, r) {
253
+ if (typeof Intl.Segmenter < "u") {
254
+ let s = new Intl.Segmenter(t, { granularity: n ? "word" : "grapheme" });
255
+ return Ce(s.segment(e)[Symbol.iterator](), i, r);
256
+ }
257
+ return Xe(e, n, i, r);
258
+ }
259
+ function Ce(e, t, n) {
260
+ let i = [];
261
+ for (let r of Array.from(e)) {
262
+ let s = t + r.index;
263
+ r.segment === " " ? i.push({ id: n.take(`space-${s}`), string: "\xA0" }) : i.push({ id: qt(r.segment, s, n), string: r.segment });
264
+ }
265
+ return i;
266
+ }
267
+ function qt(e, t, n) {
268
+ return n.has(e) ? n.take(`${e}-${t}`) : n.take(e);
269
+ }
270
+ function Xe(e, t, n, i) {
271
+ let r = t ? e.split(" ") : e.split(""), s = [], o = n;
272
+ return r.forEach((a, u) => {
273
+ t && u > 0 && (s.push({ id: i.take(`space-${o}`), string: "\xA0" }), o += 1), s.push({ id: qt(a, o, i), string: a }), o += a.length;
274
+ }), s;
275
+ }
276
+ var Y = "torph-root";
277
+ var Q = "torph-item";
278
+ var w = "torph-id";
279
+ var V = "torph-kind";
280
+ var F = "torph-slot";
281
+ var H = "torph-exiting";
282
+ var P = "torph-sr";
283
+ var Z = "torph-debug";
284
+ var tt = "empty";
285
+ var Be = { linear: [0, 0, 1, 1], ease: [0.25, 0.1, 0.25, 1], "ease-in": [0.42, 0, 1, 1], "ease-out": [0, 0, 0.58, 1], "ease-in-out": [0.42, 0, 0.58, 1] };
286
+ var Jt = (e, t, n) => {
287
+ let i = 1 - n;
288
+ return 3 * i * i * n * e + 3 * i * n * n * t + n * n * n;
289
+ };
290
+ function Qt(e, t, n, i) {
291
+ return (r) => {
292
+ if (r <= 0) return 0;
293
+ if (r >= 1) return 1;
294
+ let s = 0, o = 1;
295
+ for (let a = 0; a < 24; a += 1) {
296
+ let u = (s + o) / 2;
297
+ Jt(e, n, u) < r ? s = u : o = u;
298
+ }
299
+ return Jt(t, i, (s + o) / 2);
300
+ };
301
+ }
302
+ function We(e) {
303
+ let t = [...e];
304
+ (t[0] === null || t[0] === void 0) && (t[0] = 0), t[t.length - 1] === null && (t[t.length - 1] = 1);
305
+ for (let n = 1; n < t.length; n += 1) {
306
+ if (t[n] !== null) continue;
307
+ let i = n;
308
+ for (; t[i] === null; ) i += 1;
309
+ let r = t[n - 1], s = (t[i] - r) / (i - n + 1);
310
+ for (let o = n; o < i; o += 1) t[o] = r + s * (o - n + 1);
311
+ }
312
+ return t.map((n, i, r) => i === 0 ? n : Math.max(n, r[i - 1]));
313
+ }
314
+ function Ge(e) {
315
+ let t = [], n = [];
316
+ for (let r of e.split(",")) {
317
+ let s = r.trim().split(/\s+/).filter(Boolean), o = Number(s[0]);
318
+ if (!Number.isFinite(o)) return null;
319
+ let a = s.slice(1);
320
+ if (a.length > 2) return null;
321
+ if (a.length === 0) {
322
+ t.push(o), n.push(null);
323
+ continue;
324
+ }
325
+ for (let u of a) {
326
+ if (!u.endsWith("%")) return null;
327
+ let c = Number(u.slice(0, -1));
328
+ if (!Number.isFinite(c)) return null;
329
+ t.push(o), n.push(c / 100);
330
+ }
331
+ }
332
+ if (t.length < 2) return null;
333
+ let i = We(n);
334
+ return (r) => {
335
+ if (r <= i[0]) return t[0];
336
+ let s = i.length - 1;
337
+ if (r >= i[s]) return t[s];
338
+ let o = 0;
339
+ for (; o < s && i[o + 1] < r; ) o += 1;
340
+ let a = i[o + 1] - i[o];
341
+ return a === 0 ? t[o + 1] : t[o] + (t[o + 1] - t[o]) * (r - i[o]) / a;
342
+ };
343
+ }
344
+ function Vt(e) {
345
+ let t = e.trim().toLowerCase(), n = Be[t];
346
+ if (n) return Qt(...n);
347
+ let i = /^cubic-bezier\(([^)]*)\)$/.exec(t);
348
+ if (i) {
349
+ let s = i[1].split(",").map((o) => Number(o.trim()));
350
+ return s.length !== 4 || s.some((o) => !Number.isFinite(o)) ? null : Qt(s[0], s[1], s[2], s[3]);
351
+ }
352
+ let r = /^linear\(([^)]*)\)$/.exec(t);
353
+ return r ? Ge(r[1]) : null;
354
+ }
355
+ var St = 1e-4;
356
+ function Mt(e, t) {
357
+ let n = Math.min(Math.max(t, 0), 1 - St);
358
+ return (e(n + St) - e(n)) / St;
359
+ }
360
+ function lt(e, t) {
361
+ return e * t;
362
+ }
363
+ function X(e) {
364
+ let t = getComputedStyle(e).transform;
365
+ if (!t || t === "none") return { tx: 0, ty: 0 };
366
+ let n = t.match(/matrix\(([^)]+)\)/);
367
+ if (!n) return { tx: 0, ty: 0 };
368
+ let i = n[1].split(",").map(Number);
369
+ return { tx: i[4] || 0, ty: i[5] || 0 };
370
+ }
371
+ function et(e) {
372
+ let t = getComputedStyle(e), n = parseFloat(t.width), i = parseFloat(t.height);
373
+ if (Number.isNaN(n) || Number.isNaN(i)) {
374
+ let r = e.getBoundingClientRect();
375
+ return { width: r.width, height: r.height };
376
+ }
377
+ return { width: n, height: i };
378
+ }
379
+ function j(e) {
380
+ let { tx: t, ty: n } = X(e), i = Number(getComputedStyle(e).opacity) || 1;
381
+ return e.getAnimations().forEach((r) => r.cancel()), { tx: t, ty: n, opacity: i };
382
+ }
383
+ var Ue = 8;
384
+ var Ke = 0.1;
385
+ var Ye = 0.5;
386
+ var je = 0.5;
387
+ var ee = () => performance.now();
388
+ function ze(e, t) {
389
+ let n = Math.max(0, Math.min(Ue, t) - Mt(e, 0));
390
+ if (!(n > 0)) return { curve: e, k: 0 };
391
+ let i = Math.max(3, Math.ceil(n / (Math.E * Ke)) - 1);
392
+ return { curve: (r) => r >= 1 ? 1 : e(r) + n * r * Math.pow(1 - r, i), k: n };
393
+ }
394
+ function qe(e, t) {
395
+ let n = Math.min(120, Math.max(32, Math.round(t / 8))), i = [];
396
+ for (let r = 0; r < n; r += 1) {
397
+ let s = r / (n - 1), o = r === n - 1 ? 1 : e(s);
398
+ i.push(`${Math.round(o * 1e4) / 1e4}`);
399
+ }
400
+ return `linear(${i.join(", ")})`;
401
+ }
402
+ function Zt(e, t, n, i, r, s, o, a) {
403
+ let u = (m, d, h, M, x) => {
404
+ let T = e.animate([{ [t]: `${m}px` }, { [t]: `${d}px` }], { duration: s, easing: h, fill: "both" });
405
+ return x !== void 0 && (T.currentTime = x), { anim: T, from: m, to: d, easing: h, curve: M, startedAt: ee() - (x ?? 0) };
406
+ };
407
+ if (r && r.elapsed !== null && Math.abs(r.to - i) < je) return u(r.from, r.to, r.easing, r.curve, r.elapsed);
408
+ let c = i - n, f = o, l = a;
409
+ if (a && Math.abs(c) > Ye) {
410
+ let m = ze(a, (r?.velocity ?? 0) * s / c);
411
+ m.k > 0 && (l = m.curve, f = qe(m.curve, s));
412
+ }
413
+ return u(n, i, f, l);
414
+ }
415
+ function te(e, t) {
416
+ let n = e.anim.currentTime === null, i = ee() - e.startedAt, s = n || !Number.isFinite(i) || i >= t || i < 0 ? null : i;
417
+ return { from: e.from, to: e.to, easing: e.easing, curve: e.curve, elapsed: s, velocity: s === null || !e.curve ? 0 : (e.to - e.from) * Mt(e.curve, s / t) / t };
418
+ }
419
+ var D = /* @__PURE__ */ new WeakMap();
420
+ function Je(e) {
421
+ return D.get(e)?.snapshot();
422
+ }
423
+ function ut(e) {
424
+ e.style.width = "", e.style.height = "", e.style.transitionProperty = "";
425
+ }
426
+ function ne(e) {
427
+ let t = D.get(e);
428
+ t && (D.delete(e), t.stop(), t.onCancel?.());
429
+ }
430
+ function re(e) {
431
+ let t = D.get(e);
432
+ t && (D.delete(e), t.stop()), ut(e);
433
+ }
434
+ function ie(e, t, n, i, r, s, o) {
435
+ let a = Je(e);
436
+ if (ne(e), t === 0 || n === 0) {
437
+ ut(e), o?.();
438
+ return;
439
+ }
440
+ e.style.transitionProperty = "none", e.style.width = "", e.style.height = "", e.offsetWidth;
441
+ let { width: u, height: c } = et(e), f = Vt(r), l = Zt(e, "width", t, u, a?.width, i, r, f), m = Zt(e, "height", n, c, a?.height, i, r, f), d = () => {
442
+ l.anim.cancel(), m.anim.cancel();
443
+ };
444
+ l.anim.onfinish = () => {
445
+ D.delete(e), d(), ut(e), s?.();
446
+ }, D.set(e, { stop: d, onCancel: o, snapshot: () => ({ width: te(l, i), height: te(m, i) }) });
447
+ }
448
+ function se(e, t, n, i, r, s) {
449
+ ne(e), e.style.transitionProperty = "none", e.style.width = `${t}px`, e.style.height = `${n}px`;
450
+ let o = setTimeout(() => {
451
+ D.delete(e), ut(e), r?.();
452
+ }, i), a = (u) => ({ from: u, to: u, easing: "linear", curve: null, elapsed: null, velocity: 0 });
453
+ D.set(e, { stop: () => clearTimeout(o), onCancel: s, snapshot: () => ({ width: a(t), height: a(n) }) });
454
+ }
455
+ function ct(e) {
456
+ let t = Array.from(e.children), n = {}, i = e.getBoundingClientRect();
457
+ return t.forEach((r, s) => {
458
+ if (r.hasAttribute(H) || r.hasAttribute(P) || r.tagName === "BR") return;
459
+ let o = r.getAttribute(w) || `child-${s}`, a = r.getBoundingClientRect(), { tx: u, ty: c } = X(r);
460
+ n[o] = { x: a.left - i.left - u, y: a.top - i.top - c };
461
+ }), n;
462
+ }
463
+ function Tt(e, t, n) {
464
+ let i = e[n], r = t[n];
465
+ return !i || !r ? { dx: 0, dy: 0 } : { dx: i.x - r.x, dy: i.y - r.y };
466
+ }
467
+ function Et(e, t, n, i = "backward-first") {
468
+ let [r, s] = i === "backward-first" ? ["backward", "forward"] : ["forward", "backward"], o = (a) => {
469
+ if (a === "backward") {
470
+ for (let u = e - 1; u >= 0; u--) if (n.has(t[u])) return t[u];
471
+ } else for (let u = e + 1; u < t.length; u++) if (n.has(t[u])) return t[u];
472
+ return null;
473
+ };
474
+ return o(r) ?? o(s);
475
+ }
476
+ function oe(e, t, n, i) {
477
+ let r = new Set(n.filter((o, a) => i.has(o) && !t.has(e[a]))), s = /* @__PURE__ */ new Map();
478
+ for (let o = 0; o < e.length; o++) {
479
+ let a = e[o];
480
+ t.has(a) && s.set(a, Et(o, n, r, "forward-first"));
481
+ }
482
+ return s;
483
+ }
484
+ function ae(e, t) {
485
+ let { dx: n, dy: i, duration: r, ease: s, scale: o } = t;
486
+ e.animate({ transform: o ? `translate(${n}px, ${i}px) scale(0.95)` : `translate(${n}px, ${i}px)`, offset: 1 }, { duration: r, easing: s, fill: "both" });
487
+ let a = e.animate({ opacity: 0, offset: 1 }, { duration: lt(r, 0.25), easing: "linear", fill: "both" });
488
+ a.onfinish = () => e.remove();
489
+ }
490
+ function ue(e, t) {
491
+ let { deltaX: n, deltaY: i, isNew: r, duration: s, ease: o } = t, a = j(e), u = n + a.tx, c = i + a.ty, f = r && a.opacity >= 1 ? 0 : a.opacity;
492
+ e.animate([{ transform: `translate(${u}px, ${c}px) scale(${r ? 0.95 : 1})` }, { transform: "none" }], { duration: s, easing: o, fill: "both" }), f < 1 && e.animate([{ opacity: f }, { opacity: 1 }], { duration: lt(s, r ? 0.5 : 0.25), delay: r ? lt(s, 0.25) : 0, easing: "linear", fill: "both" });
493
+ }
494
+ function Qe(e, t) {
495
+ let n = 0, i = 0;
496
+ for (let r = e; r && r !== t; r = r.offsetParent) n += r.offsetLeft, i += r.offsetTop;
497
+ return { x: n, y: i };
498
+ }
499
+ function At(e, t) {
500
+ let n = document.createElement(e);
501
+ return n.setAttribute(Q, ""), n.setAttribute(w, t), n.setAttribute("aria-hidden", "true"), n;
502
+ }
503
+ function le(e, t) {
504
+ let n = /* @__PURE__ */ new Map();
505
+ for (let i of t) {
506
+ if (i.tagName === "BR") continue;
507
+ let { x: r, y: s } = Qe(i, e), { tx: o, ty: a } = X(i), { width: u, height: c } = et(i), f = Number(getComputedStyle(i).opacity) || 1;
508
+ i.getAnimations().forEach((l) => l.cancel()), n.set(i, { left: r + o, top: s + a, width: u, height: c, opacity: f });
509
+ }
510
+ for (let i = t.length - 1; i >= 0; i--) t[i].tagName === "BR" && (t[i].remove(), t.splice(i, 1));
511
+ t.forEach((i) => {
512
+ let r = n.get(i);
513
+ i.setAttribute(H, ""), i.style.position = "absolute", i.style.pointerEvents = "none", i.style.left = `${r.left}px`, i.style.top = `${r.top}px`, i.style.width = `${r.width}px`, i.style.height = `${r.height}px`, i.style.opacity = String(r.opacity);
514
+ });
515
+ }
516
+ function ce(e, t) {
517
+ if (t.size === 0) return;
518
+ let n = Array.from(e.children), i = /* @__PURE__ */ new Set();
519
+ for (let r of n) {
520
+ if (r.hasAttribute(H)) continue;
521
+ let s = r.getAttribute(w);
522
+ if (!s || i.has(s)) continue;
523
+ let o = t.get(s);
524
+ if (o) {
525
+ i.add(s);
526
+ for (let a of o) {
527
+ let u = At("span", a.id);
528
+ wt(u, a), r.before(u);
529
+ }
530
+ r.remove();
531
+ }
532
+ }
533
+ }
534
+ function wt(e, t) {
535
+ if (!t.kind) {
536
+ e.removeAttribute(V), e.removeAttribute(F), e.textContent = t.string;
537
+ return;
538
+ }
539
+ e.setAttribute(V, t.kind), e.setAttribute(F, "");
540
+ let n = e.firstElementChild;
541
+ n || (e.textContent = "", n = document.createElement("span"), e.appendChild(n)), n.textContent = t.string;
542
+ }
543
+ function vt(e) {
544
+ return e.hasAttribute(F) ? e.firstElementChild ?? e : e;
545
+ }
546
+ function me(e, t, n, i) {
547
+ let r = /* @__PURE__ */ new Map();
548
+ t.forEach((s) => {
549
+ let o = s.getAttribute(w);
550
+ n.has(o) && !s.hasAttribute(H) && (r.set(o, s), s.remove());
551
+ }), Array.from(e.childNodes).forEach((s) => {
552
+ s.nodeType === Node.TEXT_NODE && s.remove();
553
+ }), i.forEach((s) => {
554
+ let o = r.get(s.id);
555
+ if (o && r.delete(s.id), s.string === `
556
+ `) {
557
+ o && o.tagName === "BR" ? e.appendChild(o) : e.appendChild(At("br", s.id));
558
+ return;
559
+ }
560
+ if (o && o.tagName !== "BR") o.style.transformOrigin = "", wt(o, s), e.appendChild(o);
561
+ else {
562
+ let a = At("span", s.id);
563
+ wt(a, s), e.appendChild(a);
564
+ }
565
+ });
566
+ }
567
+ var Ve = 0.45;
568
+ var Ze = 0.25;
569
+ function pe(e, t) {
570
+ let { dx: n, dy: i, slideDistance: r, duration: s, ease: o } = t, a = vt(e);
571
+ e.animate({ transform: `translate(${n}px, ${i}px)`, offset: 1 }, { duration: s, easing: o, fill: "both" }), a.animate({ transform: `translate(0px, ${r}px)`, offset: 1 }, { duration: s, easing: o, fill: "both" });
572
+ let u = a.animate({ opacity: 0, offset: 1 }, { duration: s * Ve, easing: "linear", fill: "both" });
573
+ u.onfinish = () => e.remove();
574
+ }
575
+ function fe(e, t) {
576
+ let { deltaX: n, deltaY: i, slideDistance: r, kind: s, duration: o, ease: a } = t;
577
+ Rt(e, { deltaX: n, deltaY: i, duration: o, ease: a });
578
+ let u = vt(e), c = j(u), f = s === "digit" ? -r : r;
579
+ u.animate({ transform: `translate(0px, ${c.ty + f}px)`, offset: 0 }, { duration: o, easing: a, fill: "both" });
580
+ let l = c.opacity >= 1 ? 0 : c.opacity;
581
+ l < 1 && u.animate([{ opacity: l }, { opacity: 1 }], { duration: o * Ze, easing: "linear", fill: "both" });
582
+ }
583
+ function Rt(e, t) {
584
+ let { deltaX: n, deltaY: i, duration: r, ease: s } = t, { tx: o, ty: a } = X(e);
585
+ e.getAnimations().forEach((f) => f.cancel());
586
+ let u = n + o, c = i + a;
587
+ u === 0 && c === 0 || e.animate({ transform: `translate(${u}px, ${c}px)`, offset: 0 }, { duration: r, easing: s, fill: "both" });
588
+ }
589
+ var tn = 6;
590
+ var de = 0.8;
591
+ var en = 0.45;
592
+ var nn = 0.35;
593
+ function he(e) {
594
+ let t = e.map((u) => u.getBoundingClientRect()), n = Math.min(...t.map((u) => u.left)), i = Math.max(...t.map((u) => u.right)), r = Math.min(...t.map((u) => u.top)), s = Math.max(...t.map((u) => u.bottom)), o = (n + i) / 2, a = (r + s) / 2;
595
+ return t.map((u) => `${o - u.left}px ${a - u.top}px`);
596
+ }
597
+ function ge(e, t) {
598
+ let { duration: n, ease: i } = t, r = he(e);
599
+ e.forEach((s, o) => {
600
+ s.getAnimations().forEach((u) => u.cancel()), s.style.transformOrigin = r[o], s.animate({ transform: `scale(${de})`, offset: 1 }, { duration: n, easing: i, fill: "both" });
601
+ let a = s.animate({ opacity: 0, offset: 1 }, { duration: n * en, easing: "linear", fill: "both" });
602
+ a.onfinish = () => s.remove();
603
+ });
604
+ }
605
+ function be(e, t) {
606
+ let { duration: n, ease: i } = t, r = he(e);
607
+ e.forEach((s, o) => {
608
+ let a = j(s);
609
+ s.style.transformOrigin = r[o], s.animate({ transform: `scale(${de})`, offset: 0 }, { duration: n, easing: i, fill: "both" });
610
+ let u = a.opacity >= 1 ? 0 : a.opacity;
611
+ s.animate([{ opacity: u }, { opacity: 1 }], { duration: n * nn, easing: "linear", fill: "both" });
612
+ });
613
+ }
614
+ function It(e, t) {
615
+ let n = [], i = [], r = () => {
616
+ i.length >= tn && n.push(i), i = [];
617
+ };
618
+ for (let s of e) t.has(s) ? i.push(s) : r();
619
+ return r(), n;
620
+ }
621
+ var rn = "\0#";
622
+ function xe(e, t) {
623
+ if (e.segments.length !== 1 || e.word.length <= 1) return e.segments;
624
+ let n = e.segments[0], i = e.word.split("").map((r, s) => ({ id: `${n.id}:${s}`, string: r }));
625
+ return t.set(n.id, i), i;
626
+ }
627
+ function sn(e) {
628
+ return e.map((t) => ({ ...t, kind: t.kind ?? at(t.string) }));
629
+ }
630
+ function on(e, t) {
631
+ if (e.length === 0 || t.length === 0) return 0;
632
+ let [n] = G(e.split(""), t.split(""));
633
+ return n.length / Math.max(e.length, t.length);
634
+ }
635
+ function ye(e, t) {
636
+ let n = [], i = 0;
637
+ for (let r = 0; r < e; r++) n.push(i), t.has(r) && i++;
638
+ return n;
639
+ }
640
+ var an = 0.4;
641
+ function un(e, t) {
642
+ return (q(e) || q(t)) && gt(e) === gt(t) ? 1 : on(e, t);
643
+ }
644
+ var ln = 2500;
645
+ var cn = 1e6;
646
+ function Lt(e, t, n, i = {}) {
647
+ let r = t.includes(" "), s = t.includes(`
648
+ `), o = zt(e), a = i.numbers !== false, u = (p) => a && J(p), c = (p) => u(p) ? rn : p, f = a && (q(t) || o.some((p) => q(p.word)));
649
+ if (o.length <= 1 && !r && !s && !f) return { segments: K(t, n, a), splits: /* @__PURE__ */ new Map() };
650
+ let l = [], m = [], d = t.split(/( |\n)/), h = [];
651
+ for (let p of d) p === " " || p === `
652
+ ` ? h.push(p) : p.length > 0 && (m.push(h), l.push(p), h = []);
653
+ let M = h, x = o.map((p) => p.word);
654
+ if (x.length * l.length > cn) return { segments: K(t, n, a), splits: /* @__PURE__ */ new Map() };
655
+ let [T, L] = G(x.map(c), l.map(c)), E = new Set(T), N = new Set(L), g = /* @__PURE__ */ new Map();
656
+ for (let p = 0; p < L.length; p++) g.set(L[p], T[p]);
657
+ let v = x.map((p, b) => b).filter((p) => !E.has(p)), R = l.map((p, b) => b).filter((p) => !N.has(p)), O = /* @__PURE__ */ new Set();
658
+ for (let p of R) for (let b of v) if (!O.has(b) && c(l[p]) === c(x[b])) {
659
+ g.set(p, b), O.add(b);
660
+ break;
661
+ }
662
+ O.size > 0 && (v = v.filter((p) => !O.has(p)), R = R.filter((p) => !g.has(p)));
663
+ let A = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Set(), B = ye(x.length, E), rt = ye(l.length, N);
664
+ if (v.length * R.length <= ln) for (let p of R) {
665
+ let b = -1, S = an;
666
+ for (let y of v) {
667
+ if (_.has(y) || B[y] !== rt[p]) continue;
668
+ let it = un(x[y], l[p]);
669
+ it > S && (S = it, b = y);
670
+ }
671
+ b >= 0 && (A.set(p, b), _.add(b));
672
+ }
673
+ let pt = l.map((p, b) => {
674
+ let S = g.get(b), y = S ?? A.get(b);
675
+ return y === void 0 ? { mode: "fresh" } : u(p) ? { mode: "number", oi: y } : S !== void 0 ? { mode: "reuse", oi: y } : { mode: "morph", oi: y };
676
+ }), kt = pt.filter((p) => p.mode === "number").length === 1 ? i.cursorIndex : void 0, Ae = xt(n), W = yt();
677
+ for (let p of pt) {
678
+ if (p.mode === "fresh") continue;
679
+ let b = o[p.oi];
680
+ if (p.mode !== "reuse" && b.segments.length === 1) {
681
+ let S = b.segments[0];
682
+ for (let y = 0; y < b.word.length; y++) W.reserve(`${S.id}:${y}`);
683
+ } else for (let S of b.segments) W.reserve(S.id);
684
+ }
685
+ let $ = [], ft = /* @__PURE__ */ new Map(), z = 0;
686
+ function Ht(p) {
687
+ for (let b of p) b === `
688
+ ` ? $.push({ id: W.take(`newline-${z}`), string: `
689
+ ` }) : $.push({ id: W.take(`space-${z}`), string: "\xA0" }), z++;
690
+ }
691
+ for (let p = 0; p < l.length; p++) {
692
+ Ht(m[p] ?? (p > 0 ? [" "] : []));
693
+ let b = pt[p], S = l[p];
694
+ if (b.mode === "reuse") for (let y of o[b.oi].segments) $.push(y);
695
+ else if (b.mode === "number") {
696
+ let y = o[b.oi];
697
+ $.push(...U(S, sn(xe(y, ft)), kt === void 0 ? void 0 : kt - z, Ae));
698
+ } else if (b.mode === "morph") {
699
+ let y = o[b.oi], it = y.word, we = xe(y, ft), ve = it.split(""), st = S.split(""), [Re, Ot] = G(ve, st), dt = /* @__PURE__ */ new Map();
700
+ for (let I = 0; I < Ot.length; I++) {
701
+ let ot = we[Re[I]];
702
+ ot && dt.set(Ot[I], ot);
703
+ }
704
+ for (let I = 0; I < st.length; I++) if (dt.has(I)) {
705
+ let ot = dt.get(I);
706
+ $.push({ id: ot.id, string: st[I] });
707
+ } else $.push({ id: W.take(`${S}~${I}`), string: st[I] });
708
+ } else u(S) ? $.push(...U(S)) : $.push({ id: W.take(S), string: S });
709
+ z += S.length;
710
+ }
711
+ return Ht(M), { segments: $, splits: ft };
712
+ }
713
+ var mn = `
714
+ [${Y}] {
715
+ display: inline-block;
716
+ position: relative;
717
+ vertical-align: top;
718
+ will-change: width, height;
719
+ white-space: nowrap;
720
+ text-align: inherit;
721
+ }
722
+
723
+ [${Q}]:not(br) {
724
+ display: inline-block;
725
+ position: relative;
726
+ will-change: opacity, transform;
727
+ transform: none;
728
+ opacity: 1;
729
+ }
730
+
731
+ /*
732
+ * The value once as plain text \u2014 every other child is an aria-hidden fragment.
733
+ * Out of flow, because the engine measures every child of the root. Clipped
734
+ * rather than display: none, which would take it out of the a11y tree as well.
735
+ * user-select: none, or a copied selection pastes the value twice.
736
+ */
737
+ [${P}] {
738
+ position: absolute;
739
+ width: 1px;
740
+ height: 1px;
741
+ margin: -1px;
742
+ padding: 0;
743
+ border: 0;
744
+ overflow: hidden;
745
+ clip-path: inset(50%);
746
+ white-space: pre;
747
+ -webkit-user-select: none;
748
+ user-select: none;
749
+ }
750
+
751
+ /*
752
+ * A digit slides a whole line box to arrive, so it needs its own box to hide
753
+ * behind. Not the root: that spans every line, so clipping there leaves a digit
754
+ * on a middle line sliding over its neighbour in view. The transform sits on the
755
+ * child, so the slide never touches the slot's rect and the FLIP pass stays
756
+ * oblivious. clip-path, not overflow \u2014 an inline-block whose overflow is
757
+ * anything but visible has its baseline synthesized to the bottom margin edge
758
+ * (CSS 2.1 \xA710.8.1), and engines disagree on whether overflow: clip counts.
759
+ * The inline axis stays open so glyph overhang is not shaved.
760
+ */
761
+ [${F}] {
762
+ clip-path: inset(0 -100vw);
763
+ }
764
+
765
+ [${F}] > span {
766
+ display: inline-block;
767
+ will-change: opacity, transform;
768
+ }
769
+
770
+ /*
771
+ * Softens the clip above into a gradient, positionally rather than on a timer, so
772
+ * it stays in step with the slide at any duration. The band (--torph-fade, 0 for a
773
+ * hard edge) must eat into the box: the clip trims at the border box, so a ramp
774
+ * reaching past it sits in territory already removed and is never seen. no-clip
775
+ * plus repeat-x is what carries the profile across glyph overhang.
776
+ */
777
+ @supports (mask-clip: no-clip) or (-webkit-mask-clip: no-clip) {
778
+ [${F}] {
779
+ --torph-mask: linear-gradient(
780
+ to bottom,
781
+ transparent,
782
+ #000 var(--torph-fade, 0.15em),
783
+ #000 calc(100% - var(--torph-fade, 0.15em)),
784
+ transparent
785
+ );
786
+ -webkit-mask-image: var(--torph-mask);
787
+ mask-image: var(--torph-mask);
788
+ -webkit-mask-repeat: repeat-x;
789
+ mask-repeat: repeat-x;
790
+ -webkit-mask-clip: no-clip;
791
+ mask-clip: no-clip;
792
+ }
793
+ }
794
+
795
+ [${Y}][${Z}] {
796
+ outline: 2px solid magenta;
797
+ [${Q}] {
798
+ outline: 2px solid cyan;
799
+ outline-offset: -4px;
800
+ }
801
+ }`;
802
+ var C = null;
803
+ var Nt = 0;
804
+ function Se() {
805
+ Nt++, !C && (C = document.createElement("style"), C.dataset.torph = "true", C.textContent = mn, document.head.appendChild(C));
806
+ }
807
+ function Me() {
808
+ Nt--, !(Nt > 0 || !C) && (C.remove(), C = null);
809
+ }
810
+ function Te() {
811
+ if (typeof window > "u") return { prefersReducedMotion: false, destroy: () => {
812
+ } };
813
+ let e = window.matchMedia("(prefers-reduced-motion: reduce)"), t = { prefersReducedMotion: e.matches, destroy: i };
814
+ function n(r) {
815
+ t.prefersReducedMotion = r.matches;
816
+ }
817
+ function i() {
818
+ e.removeEventListener("change", n);
819
+ }
820
+ return e.addEventListener("change", n), t;
821
+ }
822
+ var Ee = { ..._t, debug: false, scale: true, numbers: true };
823
+ var nt = class {
824
+ element;
825
+ options = {};
826
+ data;
827
+ currentMeasures = {};
828
+ prevMeasures = {};
829
+ previousSegments = [];
830
+ isInitialRender = true;
831
+ reducedMotion = null;
832
+ srNode = null;
833
+ hasSetup = false;
834
+ constructor(t) {
835
+ let n = Object.fromEntries(Object.entries(t).filter(([, a]) => a !== void 0)), { ease: i, ...r } = { ...Ee, ...n }, { ease: s, duration: o } = Ft(i, r.duration);
836
+ this.options = { ...r, ease: s, duration: o }, this.element = t.element, this.options.respectReducedMotion && (this.reducedMotion = Te()), this.data = "", this.isDisabled() || this.setup();
837
+ }
838
+ setup() {
839
+ this.hasSetup || (this.hasSetup = true, this.element.setAttribute(Y, ""), this.options.debug && this.element.setAttribute(Z, ""), Se());
840
+ }
841
+ destroy() {
842
+ this.reducedMotion?.destroy(), re(this.element), this.element.getAnimations().forEach((t) => t.cancel()), this.srNode?.remove(), this.srNode = null, this.element.removeAttribute(Y), this.element.removeAttribute(Z), this.hasSetup && (this.hasSetup = false, Me());
843
+ }
844
+ isDisabled() {
845
+ return !!(this.options.disabled || this.reducedMotion?.prefersReducedMotion);
846
+ }
847
+ update(t, n) {
848
+ let i = typeof t == "number" ? t.toLocaleString(this.options.locale, { minimumFractionDigits: this.options.decimals, maximumFractionDigits: this.options.decimals }) : t;
849
+ if (i !== this.data) {
850
+ if (this.data = i, this.isDisabled()) {
851
+ typeof i == "string" && (this.srNode = null, this.element.textContent = i, this.previousSegments = [], this.isInitialRender = true);
852
+ return;
853
+ }
854
+ if (this.setup(), this.data instanceof HTMLElement) throw new Error("HTMLElement not yet supported");
855
+ this.options.onAnimationStart && !this.isInitialRender && this.options.onAnimationStart(), this.createTextGroup(this.data, this.element, n);
856
+ }
857
+ }
858
+ createTextGroup(t, n, i) {
859
+ let { width: r, height: s } = et(n), o = this.options.numbers !== false;
860
+ this.syncAccessibleText(t);
861
+ let a, u;
862
+ if (this.previousSegments.length > 0) {
863
+ let g = Lt(this.previousSegments, t, this.options.locale, { numbers: o, cursorIndex: i });
864
+ a = g.segments, u = g.splits;
865
+ } else a = K(t, this.options.locale, o), u = /* @__PURE__ */ new Map();
866
+ let c = a.length === 0;
867
+ c && (a = [{ id: tt, string: "\u200B" }]), ce(n, u), this.prevMeasures = ct(this.element);
868
+ let f = Array.from(n.children).filter((g) => !g.hasAttribute(P)), l = new Set(a.map((g) => g.id)), m = f.filter((g) => !l.has(g.getAttribute(w)) && !g.hasAttribute(H)), d = new Set(m), h = f.map((g) => g.getAttribute(w)), M = oe(f, d, h, l);
869
+ le(n, m), me(n, f, l, a), this.currentMeasures = ct(this.element);
870
+ let x = a.reduce((g, v) => v.string === `
871
+ ` ? g + 1 : g, 1), T = (n.offsetHeight || 20 * x) / x;
872
+ n.style.width = `${r}px`, n.offsetWidth;
873
+ let L = ct(this.element);
874
+ n.style.width = "", this.updateStyles(a, L, T);
875
+ let E = this.isInitialRender ? [] : It(f, new Set(m)), N = new Set(E.flat());
876
+ for (let g of E) ge(g, { duration: this.options.duration, ease: this.options.ease });
877
+ if (m.forEach((g) => {
878
+ if (this.isInitialRender || g.getAttribute(w) === tt) {
879
+ g.remove();
880
+ return;
881
+ }
882
+ if (N.has(g)) return;
883
+ let v = M.get(g), { dx: R, dy: O } = v ? Tt(this.currentMeasures, this.prevMeasures, v) : { dx: 0, dy: 0 };
884
+ g.hasAttribute(V) ? pe(g, { dx: R, dy: O, slideDistance: T, duration: this.options.duration, ease: this.options.ease }) : ae(g, { dx: R, dy: O, duration: this.options.duration, ease: this.options.ease, scale: this.options.scale });
885
+ }), this.previousSegments = a, this.isInitialRender) {
886
+ this.isInitialRender = false, n.style.width = "", n.style.height = "";
887
+ return;
888
+ }
889
+ c ? se(n, r, s, this.options.duration, this.options.onAnimationComplete, this.options.onAnimationCancel) : ie(n, r, s, this.options.duration, this.options.ease, this.options.onAnimationComplete, this.options.onAnimationCancel);
890
+ }
891
+ updateStyles(t, n, i) {
892
+ if (this.isInitialRender) return;
893
+ let r = Array.from(this.element.children).filter((l) => !l.hasAttribute(P)), s = t.map((l) => l.id), o = new Map(t.map((l) => [l.id, l.kind])), a = r.filter((l) => !l.hasAttribute(H) && l.tagName !== "BR" && l.getAttribute(w) !== tt), u = new Set(a.filter((l) => !this.prevMeasures[l.getAttribute(w)])), c = /* @__PURE__ */ new Set();
894
+ for (let l of It(a, u)) l.forEach((m) => c.add(m)), be(l, { duration: this.options.duration, ease: this.options.ease });
895
+ let f = new Set(s.filter((l) => this.prevMeasures[l]));
896
+ r.forEach((l, m) => {
897
+ if (l.hasAttribute(H) || l.tagName === "BR" || c.has(l)) return;
898
+ let d = l.getAttribute(w) || `child-${m}`;
899
+ if (d === tt) return;
900
+ let h = !this.prevMeasures[d], M = h ? Et(t.findIndex((E) => E.id === d), s, f) : d, { dx: x, dy: T } = M ? Tt(this.prevMeasures, n, M) : { dx: 0, dy: 0 }, L = o.get(d);
901
+ L && h ? fe(l, { deltaX: x, deltaY: T, slideDistance: i, kind: L, duration: this.options.duration, ease: this.options.ease }) : L ? Rt(l, { deltaX: x, deltaY: T, duration: this.options.duration, ease: this.options.ease }) : ue(l, { deltaX: x, deltaY: T, isNew: h, duration: this.options.duration, ease: this.options.ease });
902
+ });
903
+ }
904
+ syncAccessibleText(t) {
905
+ if (!this.srNode || this.srNode.parentNode !== this.element) {
906
+ let n = document.createElement("span");
907
+ n.setAttribute(P, ""), this.element.prepend(n), this.srNode = n;
908
+ }
909
+ this.srNode.textContent = t;
910
+ }
911
+ };
912
+
913
+ // ../probe/src/index.ts
914
+ var MAX_CANDIDATES = 4;
915
+ var SEL_ATTR = "data-bp-sel";
916
+ var OVERLAY_ID = "__bp_overlay__";
917
+ var SPOT_ATTR = "data-bp-spot";
918
+ var SPOT_STYLE_ID = "__bp_spotlight__";
919
+ var NON_VISUAL = /* @__PURE__ */ new Set(["head", "script", "style", "link", "meta", "title", "template", "noscript", "base"]);
920
+ var MAX_FIBER_WALK = 500;
921
+ var PORTAL_SCAN = 200;
922
+ var MAX_SCAN = 6e3;
923
+ var MAX_TREE = 800;
924
+ function emit(type, payload) {
925
+ try {
926
+ window.__bpEmit?.(JSON.stringify({ type, payload, t: performance.now() }));
927
+ } catch {
928
+ }
929
+ }
930
+ function mountRoot() {
931
+ return document.body ?? document.documentElement;
932
+ }
933
+ function pathOf(el) {
934
+ const mount = mountRoot();
935
+ const segments = [];
936
+ let node = el;
937
+ while (node && node !== mount) {
938
+ const parent = node.parentElement;
939
+ if (!parent) return null;
940
+ segments.unshift(Array.prototype.indexOf.call(parent.children, node));
941
+ node = parent;
942
+ }
943
+ return node === mount ? segments.join("/") : null;
944
+ }
945
+ function hasOwnText(el) {
946
+ for (const node of Array.from(el.childNodes)) {
947
+ if (node.nodeType === 3 && (node.nodeValue ?? "").trim() !== "") return true;
948
+ }
949
+ return false;
950
+ }
951
+ function elementAt(path) {
952
+ const mount = mountRoot();
953
+ if (path === "") return mount;
954
+ let node = mount;
955
+ for (const seg of path.split("/")) {
956
+ const next = node.children[Number(seg)];
957
+ if (!next) return null;
958
+ node = next;
959
+ }
960
+ return node;
961
+ }
962
+ function rectOf(el) {
963
+ const b = el.getBoundingClientRect();
964
+ return { x: b.left, y: b.top, w: b.width, h: b.height };
965
+ }
966
+ var RADIUS_PROPS = [
967
+ "borderTopLeftRadius",
968
+ "borderTopRightRadius",
969
+ "borderBottomRightRadius",
970
+ "borderBottomLeftRadius"
971
+ ];
972
+ function radiiOf(el, rect) {
973
+ if (!(el instanceof HTMLElement) || !el.isConnected) return [0, 0, 0, 0];
974
+ const cs = getComputedStyle(el);
975
+ const w2 = el.offsetWidth;
976
+ const h = el.offsetHeight;
977
+ if (w2 <= 0 || h <= 0) return [0, 0, 0, 0];
978
+ const r = RADIUS_PROPS.map((prop) => {
979
+ const v = cs[prop].split(" ")[0];
980
+ const n = parseFloat(v);
981
+ if (!(n > 0)) return 0;
982
+ return v.endsWith("%") ? n / 100 * w2 : n;
983
+ });
984
+ const [tl, tr, br, bl] = r;
985
+ const f = Math.min(1, w2 / (tl + tr || 1), w2 / (bl + br || 1), h / (tl + bl || 1), h / (tr + br || 1));
986
+ const k2 = rect.w / w2;
987
+ return r.map((v) => v * f * k2);
988
+ }
989
+ function targetOf(el) {
990
+ const rect = rectOf(el);
991
+ return { rect, radii: radiiOf(el, rect) };
992
+ }
993
+ var fiberKey = null;
994
+ function fiberOf(el) {
995
+ if (fiberKey !== null) {
996
+ const hit = el[fiberKey];
997
+ if (hit) return hit;
998
+ }
999
+ for (const key of Object.keys(el)) {
1000
+ if (key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")) {
1001
+ fiberKey = key;
1002
+ return el[key];
1003
+ }
1004
+ }
1005
+ return null;
1006
+ }
1007
+ function fiberName(type) {
1008
+ if (typeof type === "function") {
1009
+ const fn = type;
1010
+ const name = fn.displayName || fn.name;
1011
+ if (!name || name === "_c" || name.includes(".")) return null;
1012
+ return name;
1013
+ }
1014
+ if (type && typeof type === "object") {
1015
+ const o = type;
1016
+ if (o.displayName && !o.displayName.includes(".")) return o.displayName;
1017
+ if (o.render) return fiberName(o.render);
1018
+ if (o.type) return fiberName(o.type);
1019
+ if (o.displayName) return null;
1020
+ }
1021
+ return null;
1022
+ }
1023
+ function nearestComponent(el) {
1024
+ let f = fiberOf(el);
1025
+ while (f) {
1026
+ const name = fiberName(f.type);
1027
+ if (name) return { fiber: f, name };
1028
+ f = f.return;
1029
+ }
1030
+ return null;
1031
+ }
1032
+ function componentFiber(el) {
1033
+ let f = fiberOf(el);
1034
+ while (f) {
1035
+ if (fiberName(f.type)) return f;
1036
+ f = f.return;
1037
+ }
1038
+ return null;
1039
+ }
1040
+ function componentRoot(el) {
1041
+ const f = componentFiber(el);
1042
+ if (!f) return null;
1043
+ const mount = mountRoot();
1044
+ let root = el;
1045
+ while (root.parentElement && root.parentElement !== mount && componentFiber(root.parentElement) === f) {
1046
+ root = root.parentElement;
1047
+ }
1048
+ return root;
1049
+ }
1050
+ function componentNameOf(el) {
1051
+ return nearestComponent(el)?.name ?? void 0;
1052
+ }
1053
+ function identityOf(el) {
1054
+ const near = nearestComponent(el);
1055
+ if (!near) return void 0;
1056
+ const root = componentRoot(el);
1057
+ if (!root) return void 0;
1058
+ const rootPath = pathOf(root);
1059
+ if (rootPath === null) return void 0;
1060
+ const owner = root.parentElement && mountRoot().contains(root.parentElement) ? root.parentElement : mountRoot();
1061
+ const peers = [];
1062
+ let ambiguous = false;
1063
+ const firstType = componentFiber(root)?.type;
1064
+ let scanned = 0;
1065
+ const all = owner.querySelectorAll("*");
1066
+ for (const node of Array.from(all)) {
1067
+ if (++scanned > MAX_SCAN) break;
1068
+ const nc = nearestComponent(node);
1069
+ if (!nc || nc.name !== near.name) continue;
1070
+ if (componentRoot(node) !== node) continue;
1071
+ if (componentFiber(node)?.type !== firstType) ambiguous = true;
1072
+ peers.push(node);
1073
+ }
1074
+ if (!peers.includes(root)) peers.push(root);
1075
+ peers.sort((a, b) => comparePaths(pathOf(a) ?? "", pathOf(b) ?? ""));
1076
+ const discriminant = discriminantOf(peers, root);
1077
+ return {
1078
+ key: `${near.name}@${pathOf(owner) ?? ""}`,
1079
+ name: near.name,
1080
+ kind: "component",
1081
+ index: peers.indexOf(root),
1082
+ count: peers.length,
1083
+ rootPath,
1084
+ ...ambiguous ? { ambiguous: true } : {},
1085
+ ...discriminant ? { variant: discriminant.variant, variantCount: discriminant.count } : {}
1086
+ };
1087
+ }
1088
+ var VARIANT_SKIP = ["children", "className", "class", "style", "key", "ref", "id"];
1089
+ var VARIANT_PREFERRED = ["variant", "kind", "type", "mode", "appearance", "intent", "tone", "status", "state", "size", "color"];
1090
+ function variantValue(v) {
1091
+ if (typeof v === "string") return v.length > 0 && v.length <= 32 ? v : null;
1092
+ if (typeof v === "number" || typeof v === "boolean") return String(v);
1093
+ return null;
1094
+ }
1095
+ function propsOf(el) {
1096
+ const props = componentFiber(el)?.memoizedProps;
1097
+ return props && typeof props === "object" ? props : {};
1098
+ }
1099
+ function matchesVariant(root, variant) {
1100
+ return variantValue(propsOf(root)[variant.prop]) === variant.value;
1101
+ }
1102
+ function discriminantOf(peers, root) {
1103
+ if (peers.length < 2) return void 0;
1104
+ const props = peers.map(propsOf);
1105
+ const mine = props[peers.indexOf(root)];
1106
+ if (!mine) return void 0;
1107
+ const candidates = [];
1108
+ for (const prop of Object.keys(mine)) {
1109
+ if (VARIANT_SKIP.indexOf(prop) !== -1 || prop.slice(0, 2) === "on") continue;
1110
+ const own = variantValue(mine[prop]);
1111
+ if (own === null) continue;
1112
+ const values = props.map((p) => variantValue(p[prop]));
1113
+ if (values.some((v) => v === null)) continue;
1114
+ const distinct = [];
1115
+ for (const v of values) if (v !== null && distinct.indexOf(v) === -1) distinct.push(v);
1116
+ if (distinct.length < 2) continue;
1117
+ candidates.push({ prop, value: own });
1118
+ }
1119
+ if (candidates.length === 0) return void 0;
1120
+ const rank = (prop) => {
1121
+ const at2 = VARIANT_PREFERRED.indexOf(prop);
1122
+ return at2 === -1 ? VARIANT_PREFERRED.length : at2;
1123
+ };
1124
+ candidates.sort((a, b) => rank(a.prop) - rank(b.prop) || (a.prop < b.prop ? -1 : 1));
1125
+ const best = candidates[0];
1126
+ let count = 0;
1127
+ for (const p of props) if (variantValue(p[best.prop]) === best.value) count++;
1128
+ return { variant: { prop: best.prop, value: best.value }, count };
1129
+ }
1130
+ function comparePaths(a, b) {
1131
+ const l = a === "" ? [] : a.split("/").map(Number);
1132
+ const r = b === "" ? [] : b.split("/").map(Number);
1133
+ for (let i = 0; i < Math.max(l.length, r.length); i++) {
1134
+ const x = l[i] ?? -1;
1135
+ const y = r[i] ?? -1;
1136
+ if (x !== y) return x - y;
1137
+ }
1138
+ return 0;
1139
+ }
1140
+ function describeValue(v) {
1141
+ if (v === null) return "null";
1142
+ if (Array.isArray(v)) return `[${v.length} items]`;
1143
+ switch (typeof v) {
1144
+ case "string":
1145
+ return JSON.stringify(v.length > 60 ? `${v.slice(0, 60)}\u2026` : v);
1146
+ case "number":
1147
+ case "boolean":
1148
+ case "undefined":
1149
+ return String(v);
1150
+ case "function":
1151
+ return "fn";
1152
+ case "object": {
1153
+ const o = v;
1154
+ if (o["$$typeof"]) return "<element>";
1155
+ try {
1156
+ const json = JSON.stringify(v);
1157
+ return json && json.length <= 80 ? json : "{\u2026}";
1158
+ } catch {
1159
+ return "{\u2026}";
1160
+ }
1161
+ }
1162
+ default:
1163
+ return typeof v;
1164
+ }
1165
+ }
1166
+ function summariseProps(props) {
1167
+ const out = {};
1168
+ if (!props || typeof props !== "object") return out;
1169
+ let taken = 0;
1170
+ for (const [key, value] of Object.entries(props)) {
1171
+ if (taken >= 16) break;
1172
+ if (key === "children" && typeof value !== "string") continue;
1173
+ out[key] = describeValue(value);
1174
+ taken++;
1175
+ }
1176
+ return out;
1177
+ }
1178
+ function labelParts(el) {
1179
+ const comp = componentNameOf(el);
1180
+ if (comp && componentRoot(el) === el) return { label: comp, componentName: comp };
1181
+ const aria = el.getAttribute("aria-label");
1182
+ if (aria) return { label: aria, componentName: comp };
1183
+ const text = el.children.length === 0 ? (el.textContent ?? "").trim() : "";
1184
+ if (text && text.length <= 24) return { label: text, componentName: comp };
1185
+ if (comp) return { label: comp, componentName: comp };
1186
+ const role = el.getAttribute("role");
1187
+ return { label: role || el.tagName.toLowerCase(), componentName: comp };
1188
+ }
1189
+ function labelOf(el) {
1190
+ return labelParts(el).label;
1191
+ }
1192
+ function crumbLite(el) {
1193
+ const elementPath = pathOf(el);
1194
+ if (elementPath === null) return null;
1195
+ const source = el.getAttribute("data-bp-source");
1196
+ const { label, componentName } = labelParts(el);
1197
+ return {
1198
+ elementPath,
1199
+ tag: el.tagName.toLowerCase(),
1200
+ classes: Array.from(el.classList),
1201
+ label,
1202
+ componentName,
1203
+ ...source ? { source } : {},
1204
+ rect: rectOf(el)
1205
+ };
1206
+ }
1207
+ function crumbOf(el) {
1208
+ const lite = crumbLite(el);
1209
+ if (!lite) return null;
1210
+ return { ...lite, identity: identityOf(el) };
1211
+ }
1212
+ function refOf(el) {
1213
+ const self = crumbOf(el);
1214
+ if (!self) return null;
1215
+ const mount = mountRoot();
1216
+ const ancestors = [];
1217
+ let node = el.parentElement;
1218
+ while (node && node !== mount) {
1219
+ const crumb = crumbOf(node);
1220
+ if (crumb) ancestors.unshift(crumb);
1221
+ node = node.parentElement;
1222
+ }
1223
+ const rootCrumb = crumbOf(mount);
1224
+ if (rootCrumb) ancestors.unshift(rootCrumb);
1225
+ return { ...self, ancestors };
1226
+ }
1227
+ function elementAtPoint(x, y) {
1228
+ const mount = mountRoot();
1229
+ const stack = document.elementsFromPoint(x, y);
1230
+ for (const el of stack) {
1231
+ if (el.id === OVERLAY_ID || el.closest(`#${OVERLAY_ID}`)) continue;
1232
+ if (el === mount || mount.contains(el)) return el;
1233
+ }
1234
+ return null;
1235
+ }
1236
+ var SELECTOR_MAX_DEPTH = 12;
1237
+ var STABLE_ATTRS = ["data-testid", "data-test-id", "data-test", "data-cy", "data-qa", "data-component", "name"];
1238
+ var OUR_ATTRS = /* @__PURE__ */ new Set([SEL_ATTR, SPOT_ATTR, "data-bp-source"]);
1239
+ var PLAIN_NAME = /^[A-Za-z_-][-A-Za-z0-9_]*$/;
1240
+ function quoteValue(value) {
1241
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
1242
+ }
1243
+ function resolvesTo(selector, el) {
1244
+ try {
1245
+ const found = mountRoot().querySelectorAll(selector);
1246
+ return found.length === 1 && found[0] === el;
1247
+ } catch {
1248
+ return false;
1249
+ }
1250
+ }
1251
+ function anchorFor(el) {
1252
+ const id = el.getAttribute("id");
1253
+ if (id && PLAIN_NAME.test(id) && resolvesTo(`#${id}`, el)) return `#${id}`;
1254
+ const tried = [];
1255
+ for (const attr of STABLE_ATTRS) {
1256
+ const value = el.getAttribute(attr);
1257
+ if (value !== null && value.length <= 80) tried.push(`[${attr}=${quoteValue(value)}]`);
1258
+ }
1259
+ for (const attr of Array.from(el.attributes)) {
1260
+ if (!attr.name.startsWith("data-") || OUR_ATTRS.has(attr.name)) continue;
1261
+ if (STABLE_ATTRS.indexOf(attr.name) !== -1) continue;
1262
+ if (attr.value.length > 80) continue;
1263
+ tried.push(attr.value === "" ? `[${attr.name}]` : `[${attr.name}=${quoteValue(attr.value)}]`);
1264
+ }
1265
+ for (const selector of tried) if (resolvesTo(selector, el)) return selector;
1266
+ return null;
1267
+ }
1268
+ function compoundFor(el) {
1269
+ const tag = el.tagName.toLowerCase();
1270
+ const classes = Array.from(el.classList).filter((c) => PLAIN_NAME.test(c)).slice(0, 3);
1271
+ const base = tag + classes.map((c) => `.${c}`).join("");
1272
+ const parent = el.parentElement;
1273
+ if (!parent) return base;
1274
+ const siblings = Array.from(parent.children);
1275
+ let matches = 0;
1276
+ for (const sibling of siblings) {
1277
+ try {
1278
+ if (sibling.matches(base)) matches++;
1279
+ } catch {
1280
+ matches = 2;
1281
+ break;
1282
+ }
1283
+ }
1284
+ if (matches === 1) return base;
1285
+ return `${base}:nth-child(${siblings.indexOf(el) + 1})`;
1286
+ }
1287
+ function printSelector(el) {
1288
+ const mount = mountRoot();
1289
+ if (el === mount || !mount.contains(el) && el !== mount) return null;
1290
+ const own = anchorFor(el);
1291
+ if (own) return own;
1292
+ const parts = [];
1293
+ let node = el;
1294
+ for (let depth = 0; node && node !== mount && depth < SELECTOR_MAX_DEPTH; depth++) {
1295
+ const anchor = depth === 0 ? null : anchorFor(node);
1296
+ parts.unshift(anchor ?? compoundFor(node));
1297
+ const candidate = parts.join(" > ");
1298
+ if (resolvesTo(candidate, el)) return candidate;
1299
+ if (anchor) break;
1300
+ node = node.parentElement;
1301
+ }
1302
+ return null;
1303
+ }
1304
+ var RING_STROKE = 2;
1305
+ var TAB_RADIUS = 6;
1306
+ var JOIN_RADIUS = 4;
1307
+ var INNER_RADIUS = 4;
1308
+ var BADGE_RADIUS = 6;
1309
+ var MARKER_SIZE = 18;
1310
+ var TAB_HEIGHT = 17;
1311
+ var CHROME_FONT = "-apple-system,BlinkMacSystemFont,system-ui,sans-serif";
1312
+ var POP_EASE = "cubic-bezier(0.34,1.45,0.64,1)";
1313
+ var MARKER_MORPH_MS = 180;
1314
+ var CURSOR_DX = 6;
1315
+ var CURSOR_DY = 23;
1316
+ var CURSOR_FLIP_DY = 6;
1317
+ var CURSOR_FADE_MS = 140;
1318
+ var POINTING_CSS = "*{cursor:crosshair!important}[data-bp-marker]{cursor:pointer!important}";
1319
+ var POINTING_STYLE_ID = "__bp_cursor__";
1320
+ var TAB_INTRO_MS = 240;
1321
+ var TAB_INTRO_DELAY_MS = 60;
1322
+ var TAB_BLEED = 6;
1323
+ var DETACH_SETTLE_MS = 1200;
1324
+ var MORPH_SPRING = { stiffness: 345, damping: 32, mass: 1.2, precision: 7e-3 };
1325
+ var RING_COLOR_VAR = "--bp-ring-c";
1326
+ var RING_JOIN_VAR = "--bp-ring-j";
1327
+ var RECOLOR_MS = 320;
1328
+ var RECOLOR_EASE = "cubic-bezier(0.23, 1, 0.32, 1)";
1329
+ var colorPropsRegistered = false;
1330
+ function registerRingColors() {
1331
+ if (colorPropsRegistered) return;
1332
+ colorPropsRegistered = true;
1333
+ for (const name of [RING_COLOR_VAR, RING_JOIN_VAR]) {
1334
+ try {
1335
+ CSS.registerProperty({ name, syntax: "<color>", inherits: true, initialValue: "transparent" });
1336
+ } catch {
1337
+ }
1338
+ }
1339
+ }
1340
+ var GLYPH_SIZE = 8;
1341
+ var SPIN_MS = 900;
1342
+ var GLYPH_TURN_MS = 200;
1343
+ var SPIN_GLYPH = `<svg width="${GLYPH_SIZE}" height="${GLYPH_SIZE}" viewBox="0 0 8 8" fill="none" style="display:block"><path d="M8 4C8 6.20914 6.20914 8 4 8C1.79086 8 0 6.20914 0 4C0 1.79086 1.79086 0 4 0C6.20914 0 8 1.79086 8 4ZM1.69306 4C1.69306 5.27409 2.72591 6.30694 4 6.30694C5.27409 6.30694 6.30694 5.27409 6.30694 4C6.30694 2.72591 5.27409 1.69306 4 1.69306C2.72591 1.69306 1.69306 2.72591 1.69306 4Z" fill="currentColor" fill-opacity="0.4"/><path d="M7.15347 4C7.621 4 8.00896 3.61686 7.91076 3.15977C7.82445 2.75808 7.67642 2.37042 7.47045 2.01104C7.12346 1.40559 6.62412 0.901459 6.02202 0.548704C5.41991 0.195949 4.736 0.00684783 4.03821 0.000182513C3.624 -0.00377393 3.21346 0.0566317 2.82087 0.177743C2.37412 0.31556 2.22958 0.841322 2.45817 1.24915C2.68676 1.65699 3.20646 1.78396 3.66915 1.7169C3.78559 1.70003 3.90355 1.69203 4.02203 1.69316C4.42448 1.69701 4.81892 1.80607 5.16617 2.00951C5.51342 2.21296 5.80141 2.50371 6.00153 2.8529C6.06045 2.9557 6.11115 3.06251 6.15336 3.17233C6.32109 3.60873 6.68595 4 7.15347 4Z" fill="currentColor"/></svg>`;
1344
+ var STROKE_GLYPH = (d) => `<svg width="${GLYPH_SIZE}" height="${GLYPH_SIZE}" viewBox="0 0 8 8" fill="none" style="display:block">${d}</svg>`;
1345
+ var PAUSE_GLYPH = STROKE_GLYPH(
1346
+ '<path d="M2 1.5V6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 1.5V6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
1347
+ );
1348
+ var ALERT_GLYPH = STROKE_GLYPH(
1349
+ '<path d="M4 1.25V3.75" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 6.75V6.7501" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
1350
+ );
1351
+ var AGENT_TAB = {
1352
+ working: { text: "Working...", glyph: SPIN_GLYPH, spin: true },
1353
+ approval: { text: "Needs Approval", glyph: PAUSE_GLYPH, spin: false },
1354
+ failed: { text: "Failed", glyph: ALERT_GLYPH, spin: false }
1355
+ };
1356
+ var AGENT_FALLBACK = {
1357
+ working: "#f87bdf",
1358
+ approval: "#fd8a44",
1359
+ failed: "#e5484d"
1360
+ };
1361
+ var RESOLVED_FALLBACK = "#1d9c00";
1362
+ var CHECK_GLYPH = '<svg width="10" height="10" viewBox="0 0 10 10" fill="none" style="display:block"><path d="M2.1 5.25L4.05 7.2L7.9 3" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/></svg>';
1363
+ function turnOver(el, html) {
1364
+ if (typeof el.animate !== "function") {
1365
+ el.innerHTML = html;
1366
+ return;
1367
+ }
1368
+ for (const a of el.getAnimations?.() ?? []) {
1369
+ if (a.id === "turn") a.cancel();
1370
+ }
1371
+ const half = GLYPH_TURN_MS / 2;
1372
+ const out = el.animate([{ opacity: 1, scale: "1" }, { opacity: 0, scale: "0.4" }], {
1373
+ duration: half,
1374
+ easing: "ease-in",
1375
+ id: "turn"
1376
+ });
1377
+ out.onfinish = () => {
1378
+ el.innerHTML = html;
1379
+ el.animate([{ opacity: 0, scale: "0.4" }, { opacity: 1, scale: "1" }], {
1380
+ duration: half,
1381
+ easing: POP_EASE,
1382
+ fill: "backwards",
1383
+ id: "turn"
1384
+ });
1385
+ };
1386
+ out.oncancel = () => {
1387
+ el.innerHTML = html;
1388
+ };
1389
+ }
1390
+ var FRAME_PATH = "";
1391
+ function frameBox() {
1392
+ const s = RING_STROKE;
1393
+ return { x: s, y: s, w: Math.max(0, window.innerWidth - 2 * s), h: Math.max(0, window.innerHeight - 2 * s) };
1394
+ }
1395
+ function markRect(path, el) {
1396
+ return path === FRAME_PATH ? frameBox() : rectOf(el);
1397
+ }
1398
+ function markTarget(path, el) {
1399
+ return path === FRAME_PATH ? { rect: frameBox(), radii: [0, 0, 0, 0] } : targetOf(el);
1400
+ }
1401
+ function filletBox(r) {
1402
+ return `width:${r}px;height:${r}px;overflow:hidden;`;
1403
+ }
1404
+ function filletArc(r, hole, color) {
1405
+ const left = hole === "tr" || hole === "br" ? 0 : -r;
1406
+ const top = hole === "bl" || hole === "br" ? 0 : -r;
1407
+ return `position:absolute;left:${left}px;top:${top}px;width:${2 * r}px;height:${2 * r}px;border-radius:50%;box-shadow:0 0 0 ${r}px ${color};`;
1408
+ }
1409
+ function dressFillet(f, position, r, hole, color) {
1410
+ f.square.style.cssText = position + filletBox(r);
1411
+ f.arc.style.cssText = filletArc(r, hole, color);
1412
+ }
1413
+ var Ring = class {
1414
+ constructor(parent, fill, morphing = false) {
1415
+ /** Styling caches — rewritten on change, never per frame. */
1416
+ this.color = "";
1417
+ this.textColor = "#ffffff";
1418
+ this.joinColor = "";
1419
+ this.label = "";
1420
+ this.morph = null;
1421
+ this.glyph = null;
1422
+ this.spinning = false;
1423
+ this.tabW = 0;
1424
+ this.radius = "";
1425
+ this.tucked = false;
1426
+ this.tabShift = 0;
1427
+ this.tabDress = "";
1428
+ this.dropR = -1;
1429
+ this.tabHidden = false;
1430
+ this.hasTab = true;
1431
+ this.geom = "";
1432
+ this.fused = false;
1433
+ this.shown = false;
1434
+ this.rect = null;
1435
+ this.fill = fill;
1436
+ this.morphing = morphing;
1437
+ const div = (css, into) => {
1438
+ const d = document.createElement("div");
1439
+ d.style.cssText = css;
1440
+ into.appendChild(d);
1441
+ return d;
1442
+ };
1443
+ registerRingColors();
1444
+ this.rootEl = div(
1445
+ "position:fixed;left:0;top:0;pointer-events:none;display:none;will-change:transform,width,height;",
1446
+ parent
1447
+ );
1448
+ const fillet = (css, into) => {
1449
+ const square = div(css, into);
1450
+ return { square, arc: div("", square) };
1451
+ };
1452
+ this.box = div("position:absolute;inset:0;box-sizing:border-box;", this.rootEl);
1453
+ this.inTL = fillet("position:absolute;left:0;top:0;", this.box);
1454
+ this.inTR = fillet("position:absolute;right:0;top:0;display:none;", this.box);
1455
+ this.inBR = fillet("position:absolute;right:0;bottom:0;display:none;", this.box);
1456
+ this.tabRow = div("position:absolute;bottom:100%;left:0;overflow:hidden;white-space:nowrap;", this.rootEl);
1457
+ this.tabSlide = div("position:relative;display:flex;align-items:flex-end;", this.tabRow);
1458
+ this.tab = div(
1459
+ `display:flex;align-items:center;gap:4px;padding:2px 6px 1px;font:600 11px/14px ${CHROME_FONT};letter-spacing:-0.08px;border-radius:${TAB_RADIUS}px ${TAB_RADIUS}px 0 0;`,
1460
+ this.tabSlide
1461
+ );
1462
+ this.tabGlyph = div(`display:none;flex:none;width:${GLYPH_SIZE}px;height:${GLYPH_SIZE}px;`, this.tab);
1463
+ this.tabText = div("", this.tab);
1464
+ this.tabJoin = fillet("", this.tabSlide);
1465
+ this.tabBleed = div(`position:absolute;left:0;right:0;top:100%;height:${TAB_BLEED}px;`, this.tabSlide);
1466
+ this.tabDrop = fillet("position:absolute;left:100%;top:0;display:none;", this.rootEl);
1467
+ this.markJoin = fillet(`position:absolute;top:100%;right:${MARKER_SIZE}px;display:none;`, this.rootEl);
1468
+ }
1469
+ /**
1470
+ * Everything that only changes with color or fusion.
1471
+ *
1472
+ * The pieces are written once, against `var(--bp-ring-c)` (and the join's
1473
+ * own variable), and the container holds the values. So a ring that
1474
+ * *changes* color — an agent ring going from working to needs-approval —
1475
+ * writes one property and the stroke, the tab, the bleed and every join
1476
+ * fillet travel together, interpolated in oklab by the registered
1477
+ * property. The very first color is written without the transition: a new
1478
+ * ring appears in its color, it does not fade up out of transparent.
1479
+ */
1480
+ style(color, textColor, joinColor) {
1481
+ if (color === this.color && textColor === this.textColor && joinColor === this.joinColor) return;
1482
+ const first = this.color === "";
1483
+ this.color = color;
1484
+ this.textColor = textColor;
1485
+ this.joinColor = joinColor;
1486
+ if (first) {
1487
+ const c2 = `var(${RING_COLOR_VAR})`;
1488
+ this.box.style.border = `${RING_STROKE}px solid ${c2}`;
1489
+ this.box.style.background = this.fill ? colorMix(c2, 0.08) : "transparent";
1490
+ this.tab.style.background = c2;
1491
+ this.tabBleed.style.background = c2;
1492
+ dressFillet(this.tabJoin, "position:relative;", JOIN_RADIUS, "tr", c2);
1493
+ }
1494
+ this.tab.style.color = textColor;
1495
+ this.rootEl.style.setProperty(RING_COLOR_VAR, color);
1496
+ this.rootEl.style.setProperty(RING_JOIN_VAR, joinColor);
1497
+ if (first) {
1498
+ requestAnimationFrame(() => {
1499
+ this.rootEl.style.transition = `${RING_COLOR_VAR} ${RECOLOR_MS}ms ${RECOLOR_EASE},${RING_JOIN_VAR} ${RECOLOR_MS}ms ${RECOLOR_EASE}`;
1500
+ });
1501
+ }
1502
+ const c = `var(${RING_COLOR_VAR})`;
1503
+ dressFillet(this.inTL, `position:absolute;left:0;top:0;display:${this.hasTab ? "block" : "none"};`, INNER_RADIUS, "br", c);
1504
+ dressFillet(this.inBR, `position:absolute;right:0;bottom:0;display:${this.fused ? "block" : "none"};`, INNER_RADIUS, "tl", c);
1505
+ dressFillet(
1506
+ this.markJoin,
1507
+ `position:absolute;top:100%;right:${MARKER_SIZE}px;display:${this.fused ? "block" : "none"};`,
1508
+ JOIN_RADIUS,
1509
+ "bl",
1510
+ `var(${RING_JOIN_VAR})`
1511
+ );
1512
+ this.dropFillets(this.dropR, true);
1513
+ this.radius = "";
1514
+ }
1515
+ /**
1516
+ * The overhang's two fillets, sized to the room the tab actually leaves.
1517
+ *
1518
+ * `r` is the drop's radius — zero when the tab clears the box's right edge
1519
+ * by less than the corner it is already rounding, in which case the tab's
1520
+ * own curve lands on that edge and there is nothing left to round. The
1521
+ * inner one is the box's, so it keeps the inner radius whenever the
1522
+ * corner is squared at all.
1523
+ */
1524
+ dropFillets(r, force = false) {
1525
+ if (r === this.dropR && !force) return;
1526
+ this.dropR = r;
1527
+ const c = `var(${RING_COLOR_VAR})`;
1528
+ const drop = Math.max(r, 0);
1529
+ dressFillet(this.tabDrop, `position:absolute;left:100%;top:0;display:${drop > 0 ? "block" : "none"};`, drop, "br", c);
1530
+ dressFillet(this.inTR, `position:absolute;right:0;top:0;display:${r >= 0 ? "block" : "none"};`, INNER_RADIUS, "bl", c);
1531
+ }
1532
+ /** The tab's text — measured only when it changes (the old chip's trick). */
1533
+ setLabel(label) {
1534
+ if (label === this.label) return;
1535
+ this.label = label;
1536
+ if (this.morphing) {
1537
+ if (!this.morph) {
1538
+ this.morph = new nt({
1539
+ element: this.tabText,
1540
+ ease: MORPH_SPRING,
1541
+ onAnimationComplete: () => {
1542
+ if (this.hasTab) this.tabW = this.tab.offsetWidth;
1543
+ }
1544
+ });
1545
+ }
1546
+ this.morph.update(label);
1547
+ if (this.hasTab) this.tabW = this.tab.offsetWidth;
1548
+ } else {
1549
+ this.tabText.textContent = label;
1550
+ }
1551
+ if (this.hasTab && !this.morphing) this.tabW = this.tab.offsetWidth;
1552
+ }
1553
+ /**
1554
+ * The tab's leading glyph — the agent rings' spinner, pause and alert
1555
+ * (`AGENT_TAB`); `null` for every other ring, which is the default. Only a
1556
+ * change in *presence* re-measures the tab: the three glyphs are one size,
1557
+ * so swapping one for another moves nothing.
1558
+ *
1559
+ * `spin` turns the glyph, which is the whole of what "Working…" claims —
1560
+ * a partial ring standing still reads as broken, not busy. WAAPI so it
1561
+ * survives the page's own stylesheets, and reduced motion leaves it still:
1562
+ * the word beside it already says the fact.
1563
+ */
1564
+ setGlyph(svg, spin = false) {
1565
+ if (svg !== this.glyph) {
1566
+ const swap = svg !== null && this.glyph !== null;
1567
+ const appeared = svg !== null !== (this.glyph !== null);
1568
+ this.glyph = svg;
1569
+ if (swap && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
1570
+ this.turnOver(svg);
1571
+ } else {
1572
+ this.tabGlyph.innerHTML = svg ?? "";
1573
+ }
1574
+ this.tabGlyph.style.display = svg === null ? "none" : "block";
1575
+ if (appeared && this.hasTab) this.tabW = this.tab.offsetWidth;
1576
+ }
1577
+ if (spin === this.spinning) return;
1578
+ this.spinning = spin;
1579
+ for (const a of this.tabGlyph.getAnimations?.() ?? []) if (a.id === "spin") a.cancel();
1580
+ if (!spin || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1581
+ this.tabGlyph.animate?.([{ rotate: "0deg" }, { rotate: "360deg" }], {
1582
+ duration: SPIN_MS,
1583
+ iterations: Infinity,
1584
+ easing: "linear",
1585
+ id: "spin"
1586
+ });
1587
+ }
1588
+ /** Half out, swap, half back — the glyph's own state change. */
1589
+ turnOver(svg) {
1590
+ turnOver(this.tabGlyph, svg);
1591
+ }
1592
+ /**
1593
+ * Take the whole construction out of the page — a status ring whose turn
1594
+ * ended. The pooled rings (hover, selection) never call it.
1595
+ *
1596
+ * It leaves rather than vanishing: the fused chip under it is already
1597
+ * traveling back to annotate purple on the recolor clock, and a ring that
1598
+ * cut out from around a chip mid-transition would read as two events. The
1599
+ * caller has already dropped this ring, so a fading one is never redrawn.
1600
+ */
1601
+ destroy() {
1602
+ for (const a of this.tabGlyph.getAnimations?.() ?? []) a.cancel();
1603
+ this.morph?.destroy();
1604
+ this.morph = null;
1605
+ if (!this.shown || typeof this.rootEl.animate !== "function") {
1606
+ this.rootEl.remove();
1607
+ return;
1608
+ }
1609
+ const out = this.rootEl.animate([{ opacity: 1 }, { opacity: 0 }], {
1610
+ duration: RECOLOR_MS,
1611
+ easing: RECOLOR_EASE
1612
+ });
1613
+ out.onfinish = () => this.rootEl.remove();
1614
+ out.oncancel = () => this.rootEl.remove();
1615
+ }
1616
+ /** Whether the construction carries its label tab at all. Pointer hover
1617
+ * hands the name to the cursor label, so its ring drops the tab and gets
1618
+ * all four corners back; path-driven hovers (the layers preview, a
1619
+ * hovered marker) keep it — there is no cursor there to follow. */
1620
+ setTab(show) {
1621
+ if (show === this.hasTab) return;
1622
+ this.hasTab = show;
1623
+ this.tabRow.style.display = show ? "block" : "none";
1624
+ this.inTL.square.style.display = show ? "block" : "none";
1625
+ if (show && this.label) this.tabW = this.tab.offsetWidth;
1626
+ this.radius = "";
1627
+ }
1628
+ /** The select hand-off's second half: the tab pushes out of the box's
1629
+ * top-left edge (down out of it when tucked), clipped by `tabRow` so it
1630
+ * emerges from behind the ring rather than sliding over it. WAAPI so a
1631
+ * quick re-select restarts cleanly; the caller gates reduced motion. */
1632
+ intro() {
1633
+ if (!this.hasTab || typeof this.tabSlide.animate !== "function") return;
1634
+ for (const a of this.tabSlide.getAnimations?.() ?? []) a.cancel();
1635
+ this.tabSlide.animate(
1636
+ [{ transform: this.tucked ? "translateY(-100%)" : "translateY(100%)" }, { transform: "translateY(0)" }],
1637
+ { duration: TAB_INTRO_MS, delay: TAB_INTRO_DELAY_MS, easing: POP_EASE, fill: "backwards" }
1638
+ );
1639
+ }
1640
+ /** During a parameter drag the label gets out of the way — the old chip's
1641
+ * suppression, inherited by the tab. The box stays, so the drag keeps its
1642
+ * bearings. */
1643
+ setTabHidden(hidden) {
1644
+ if (hidden === this.tabHidden) return;
1645
+ this.tabHidden = hidden;
1646
+ this.tabRow.style.visibility = hidden ? "hidden" : "visible";
1647
+ }
1648
+ /** A marker is fused at the box's bottom-right: that corner squares off,
1649
+ * the inner fillet rounds it from inside, and the join appears. */
1650
+ setFused(fused) {
1651
+ if (fused === this.fused) return;
1652
+ this.fused = fused;
1653
+ this.inBR.square.style.display = fused ? "block" : "none";
1654
+ this.markJoin.square.style.display = fused ? "block" : "none";
1655
+ this.radius = "";
1656
+ }
1657
+ /** Returns whether the ring's geometry actually changed this call — the
1658
+ * draw loop's own motion signal, free because the cache is already here. */
1659
+ draw(target) {
1660
+ if (!target) {
1661
+ const moved2 = this.shown;
1662
+ if (this.shown) this.rootEl.style.display = "none";
1663
+ this.shown = false;
1664
+ this.rect = null;
1665
+ this.geom = "";
1666
+ return moved2;
1667
+ }
1668
+ const { rect, radii } = target;
1669
+ const s = RING_STROKE;
1670
+ const geom = `${rect.x}|${rect.y}|${rect.w}|${rect.h}`;
1671
+ const moved = geom !== this.geom;
1672
+ if (moved) {
1673
+ this.geom = geom;
1674
+ this.rootEl.style.display = "block";
1675
+ this.rootEl.style.transform = `translate(${rect.x - s}px,${rect.y - s}px)`;
1676
+ this.rootEl.style.width = `${rect.w + 2 * s}px`;
1677
+ this.rootEl.style.height = `${rect.h + 2 * s}px`;
1678
+ }
1679
+ this.shown = true;
1680
+ this.rect = rect;
1681
+ const tucked = rect.y - s < TAB_HEIGHT;
1682
+ if (tucked !== this.tucked) {
1683
+ this.tucked = tucked;
1684
+ this.tabRow.style.bottom = tucked ? "auto" : "100%";
1685
+ this.tabRow.style.top = tucked ? `${RING_STROKE}px` : "auto";
1686
+ this.tabBleed.style.top = tucked ? "auto" : "100%";
1687
+ this.tabBleed.style.bottom = tucked ? "100%" : "auto";
1688
+ }
1689
+ const past = rect.x - s + this.tabW + JOIN_RADIUS - window.innerWidth;
1690
+ const shift = past > 0 ? -Math.min(past, Math.max(0, rect.x - s)) : 0;
1691
+ if (shift !== this.tabShift) {
1692
+ this.tabShift = shift;
1693
+ this.tabRow.style.transform = shift === 0 ? "" : `translateX(${shift}px)`;
1694
+ }
1695
+ const width = rect.w + 2 * s;
1696
+ const clear = this.hasTab && !tucked ? this.tabW + shift - width : -1;
1697
+ const overhang = clear >= 0;
1698
+ const tabR = overhang ? Math.min(TAB_RADIUS, clear) : 0;
1699
+ this.dropFillets(overhang ? Math.min(JOIN_RADIUS, clear - tabR) : -1);
1700
+ const joinFits = !tucked && clear + JOIN_RADIUS <= 0;
1701
+ const dress = `${tucked ? "tucked" : tabR}|${joinFits}`;
1702
+ if (dress !== this.tabDress) {
1703
+ this.tabDress = dress;
1704
+ this.tab.style.borderRadius = tucked ? `0 0 ${TAB_RADIUS}px ${TAB_RADIUS}px` : `${TAB_RADIUS}px ${TAB_RADIUS}px ${tabR}px 0`;
1705
+ this.tabJoin.square.style.visibility = joinFits ? "visible" : "hidden";
1706
+ }
1707
+ const [tl, tr, br, bl] = radii;
1708
+ const outer = (r) => `${Math.round((r + s) * 100) / 100}px`;
1709
+ const radius = `${this.hasTab ? "0px" : outer(tl)} ${overhang ? "0px" : outer(tr)} ${this.fused ? "0px" : outer(br)} ${outer(bl)}`;
1710
+ if (radius !== this.radius) {
1711
+ this.radius = radius;
1712
+ this.box.style.borderRadius = radius;
1713
+ }
1714
+ return moved;
1715
+ }
1716
+ tabState() {
1717
+ if (!this.shown || this.tabHidden || !this.hasTab) return null;
1718
+ const b = this.tab.getBoundingClientRect();
1719
+ return { rect: { x: b.left, y: b.top, w: b.width, h: b.height }, text: this.label };
1720
+ }
1721
+ };
1722
+ var Overlay = class {
1723
+ constructor() {
1724
+ this.root = null;
1725
+ /** The cursor label: pointer hover's name, riding the pointer. */
1726
+ this.cursorEl = null;
1727
+ this.cursorLabel = "";
1728
+ this.cursorW = 0;
1729
+ this.cursorShown = false;
1730
+ /** Standing ordinal markers, keyed by element path. */
1731
+ this.markerEls = /* @__PURE__ */ new Map();
1732
+ this.markerStyle = /* @__PURE__ */ new Map();
1733
+ this.markerPos = /* @__PURE__ */ new Map();
1734
+ /** Drawn marker geometry, for synthetic pointing — a wire host forwards
1735
+ * coordinates instead of real events, so the probe answers "was that a
1736
+ * marker?" itself and every host gets Beam's native behavior. */
1737
+ this.markerXY = /* @__PURE__ */ new Map();
1738
+ this.markersHidden = false;
1739
+ this.lastMarkers = [];
1740
+ /** The standing agent rings, one construction per decorated element path —
1741
+ * the markers' lifecycle, applied to a ring. */
1742
+ this.statusRings = /* @__PURE__ */ new Map();
1743
+ this.statusDress = /* @__PURE__ */ new Map();
1744
+ this.lastStatus = [];
1745
+ /** Hovering a marker points at its annotation: the hover construction
1746
+ * draws on its element in annotate's color, fused to the chip. */
1747
+ this.hoverAnnotate = false;
1748
+ /** Whether the annotation each ring is fused to is resolved — the one fact
1749
+ * that recolors the whole construction green, chip and ring together. */
1750
+ this.hoverResolved = false;
1751
+ this.selResolved = false;
1752
+ this.markerHandler = null;
1753
+ this.markerHover = null;
1754
+ this.colors = { hover: "#32b2ed", selection: "#32b2ed", chipText: "#ffffff", annotate: "#bc5cf3" };
1755
+ this.visible = false;
1756
+ /** A pointing mode is up: the page wears the crosshair. Separate from
1757
+ * `visible` because interact keeps the rings while giving the page its
1758
+ * cursor back. */
1759
+ this.pointing = false;
1760
+ this.pointingStyle = null;
1761
+ /** A parameter drag is in flight: the selection ring gets out of the way
1762
+ * so the change is readable. Hover stays live — this is not `visible`. */
1763
+ this.suppressSelection = false;
1764
+ }
1765
+ ensure() {
1766
+ if (this.root && this.root.isConnected) return true;
1767
+ const host = document.documentElement;
1768
+ if (!host) return false;
1769
+ const root = document.createElement("div");
1770
+ root.id = OVERLAY_ID;
1771
+ root.setAttribute("aria-hidden", "true");
1772
+ root.style.cssText = "position:fixed;inset:0;z-index:2147483646;pointer-events:none;contain:strict;";
1773
+ this.hoverRing = new Ring(root, true);
1774
+ this.selRing = new Ring(root, false);
1775
+ const cursor = document.createElement("div");
1776
+ cursor.style.cssText = `position:fixed;left:0;top:0;pointer-events:none;display:none;will-change:transform;padding:2px 6px 1px;font:600 11px/14px ${CHROME_FONT};letter-spacing:-0.08px;white-space:nowrap;border-radius:${BADGE_RADIUS}px;box-shadow:0 3px 8px rgba(0,0,0,0.18);opacity:0;transition:opacity ${CURSOR_FADE_MS}ms ease;`;
1777
+ root.appendChild(cursor);
1778
+ this.cursorEl = cursor;
1779
+ host.appendChild(root);
1780
+ this.root = root;
1781
+ this.restyle();
1782
+ return true;
1783
+ }
1784
+ setColors(c) {
1785
+ this.colors = { ...this.colors, ...c };
1786
+ if (!this.root) return;
1787
+ this.restyle();
1788
+ this.markerStyle.clear();
1789
+ this.statusDress.clear();
1790
+ }
1791
+ /** The color one agent state paints with — the host's, else the token's
1792
+ * literal (`AGENT_FALLBACK`). */
1793
+ statusColor(state) {
1794
+ return this.colors[state] ?? AGENT_FALLBACK[state];
1795
+ }
1796
+ annotateColor() {
1797
+ return this.colors.annotate ?? this.colors.selection;
1798
+ }
1799
+ resolvedColor() {
1800
+ return this.colors.resolved ?? RESOLVED_FALLBACK;
1801
+ }
1802
+ /** What an annotation's construction paints with: purple while it is still
1803
+ * asking, green once it has been answered. One function, because the chip
1804
+ * and every ring that fuses to it must never disagree. */
1805
+ annColor(resolved) {
1806
+ return resolved ? this.resolvedColor() : this.annotateColor();
1807
+ }
1808
+ restyle() {
1809
+ const hoverAnn = this.annColor(this.hoverResolved);
1810
+ this.hoverRing.style(this.hoverAnnotate ? hoverAnn : this.colors.hover, this.colors.chipText, hoverAnn);
1811
+ const selAnn = this.annColor(this.selResolved);
1812
+ this.selRing.style(this.selRing.fused ? selAnn : this.colors.selection, this.colors.chipText, selAnn);
1813
+ if (this.cursorEl) {
1814
+ this.cursorEl.style.background = this.colors.hover;
1815
+ this.cursorEl.style.color = this.colors.chipText;
1816
+ }
1817
+ }
1818
+ /** Marker hover recolors the hover construction to the annotation's own
1819
+ * color — purple while it is still asking, the resolved green once it has
1820
+ * been answered. */
1821
+ setHoverAccent(annotate, resolved = false) {
1822
+ if (!this.ensure()) return;
1823
+ if (annotate === this.hoverAnnotate && resolved === this.hoverResolved) return;
1824
+ this.hoverAnnotate = annotate;
1825
+ this.hoverResolved = resolved;
1826
+ this.restyle();
1827
+ }
1828
+ setHoverFused(fused) {
1829
+ if (this.ensure()) this.hoverRing.setFused(fused);
1830
+ }
1831
+ setSelectionLabel(label) {
1832
+ if (this.ensure()) this.selRing.setLabel(label);
1833
+ }
1834
+ /** `resolved` is the fused mark's own state, not the selection's: a request
1835
+ * answered while its ring is standing recolors in place, on the same
1836
+ * clock the chip below it recolors on. */
1837
+ setSelectionFused(fused, resolved = false) {
1838
+ if (!this.ensure()) return;
1839
+ const next = fused && !this.suppressSelection;
1840
+ const done = next && resolved;
1841
+ if (next === this.selRing.fused && done === this.selResolved) return;
1842
+ this.selResolved = done;
1843
+ this.selRing.setFused(next);
1844
+ this.restyle();
1845
+ }
1846
+ drawHover(target, label) {
1847
+ if (!this.ensure()) return false;
1848
+ if (target && label !== null) this.hoverRing.setLabel(label);
1849
+ this.hoverRing.setTabHidden(this.suppressSelection);
1850
+ return this.hoverRing.draw(this.visible ? target : null);
1851
+ }
1852
+ /** Whether the hover construction carries its tab — off for pointer hover
1853
+ * (the cursor label owns the name), on for path-driven hovers. */
1854
+ setHoverTab(show) {
1855
+ if (this.ensure()) this.hoverRing.setTab(show);
1856
+ }
1857
+ /**
1858
+ * The cursor label follows the pointer at its top-right — flipped below
1859
+ * near the viewport top, pulled left of the pointer at the right edge, so
1860
+ * the name is always beside the cursor and never clipped. Text is measured
1861
+ * only when it changes; a move writes one transform.
1862
+ */
1863
+ drawCursor(x, y, label) {
1864
+ if (!this.ensure() || !this.visible) return;
1865
+ const el = this.cursorEl;
1866
+ const showing = this.cursorShown;
1867
+ if (!showing) {
1868
+ this.cursorShown = true;
1869
+ el.style.display = "block";
1870
+ }
1871
+ if (label !== this.cursorLabel) {
1872
+ this.cursorLabel = label;
1873
+ el.textContent = label;
1874
+ this.cursorW = el.offsetWidth;
1875
+ } else if (!showing) {
1876
+ void el.offsetWidth;
1877
+ }
1878
+ let cx = x + CURSOR_DX;
1879
+ if (cx + this.cursorW + 4 > window.innerWidth) cx = Math.max(4, x - CURSOR_DX - this.cursorW);
1880
+ let cy = y - CURSOR_DY;
1881
+ if (cy < 4) cy = y + CURSOR_FLIP_DY;
1882
+ el.style.transform = `translate(${cx}px,${cy}px)`;
1883
+ if (!showing) el.style.opacity = "1";
1884
+ }
1885
+ /** Take the cursor label down — fading in place (a click, the pointer
1886
+ * leaving) or instantly (scroll, teardown: a stale position must not
1887
+ * linger where the content used to be). */
1888
+ hideCursor(fade) {
1889
+ const el = this.cursorEl;
1890
+ if (!el || !this.cursorShown) return;
1891
+ this.cursorShown = false;
1892
+ el.style.opacity = "0";
1893
+ if (!fade) el.style.display = "none";
1894
+ }
1895
+ /** The crosshair sheet follows `pointing && visible` — installed under the
1896
+ * document root (the spotlight's pattern, page CSS can't outrank it),
1897
+ * removed the moment pointing ends so the page's own cursors return. */
1898
+ syncCursorStyle() {
1899
+ const want = this.pointing && this.visible;
1900
+ if (want) {
1901
+ if (this.pointingStyle && this.pointingStyle.isConnected) return;
1902
+ const host = document.documentElement;
1903
+ if (!host) return;
1904
+ const style = document.createElement("style");
1905
+ style.id = POINTING_STYLE_ID;
1906
+ style.textContent = POINTING_CSS;
1907
+ host.appendChild(style);
1908
+ this.pointingStyle = style;
1909
+ } else if (this.pointingStyle) {
1910
+ this.pointingStyle.remove();
1911
+ this.pointingStyle = null;
1912
+ }
1913
+ }
1914
+ /** The click hand-off: the cursor label freezes and fades while the new
1915
+ * selection's tab pushes out of the ring — one name changing owners.
1916
+ * Reduced motion keeps the fade (it is one) and skips the push. */
1917
+ handOff() {
1918
+ if (!this.ensure()) return;
1919
+ this.hideCursor(true);
1920
+ if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1921
+ this.selRing.intro();
1922
+ }
1923
+ drawSelection(target) {
1924
+ if (!this.ensure()) return false;
1925
+ return this.selRing.draw(this.visible && !this.suppressSelection ? target : null);
1926
+ }
1927
+ /**
1928
+ * The standing agent rings — the full construction on every element a
1929
+ * managed turn is live on, redrawn every frame like the markers so they
1930
+ * can't lag a scroll. Standing chrome: this draws with no selection, and
1931
+ * only the host clears it.
1932
+ *
1933
+ * One ring per element and no more: the caller stands the selection and
1934
+ * hover constructions down on these elements, because two rings on one
1935
+ * element read as a bug rather than as two facts.
1936
+ */
1937
+ drawStatus(draws) {
1938
+ if (!this.ensure()) return false;
1939
+ this.lastStatus = draws;
1940
+ let moved = false;
1941
+ const keep = new Set(draws.map((d) => d.key));
1942
+ for (const [key, ring] of this.statusRings) {
1943
+ if (keep.has(key)) continue;
1944
+ ring.destroy();
1945
+ this.statusRings.delete(key);
1946
+ this.statusDress.delete(key);
1947
+ moved = true;
1948
+ }
1949
+ for (const d of draws) {
1950
+ let ring = this.statusRings.get(d.key);
1951
+ if (!ring) {
1952
+ ring = new Ring(this.root, false, true);
1953
+ this.statusRings.set(d.key, ring);
1954
+ moved = true;
1955
+ }
1956
+ const dress = `${d.state}|${this.colors.chipText}|${this.statusColor(d.state)}`;
1957
+ if (this.statusDress.get(d.key) !== dress) {
1958
+ this.statusDress.set(d.key, dress);
1959
+ const color = this.statusColor(d.state);
1960
+ const tab = AGENT_TAB[d.state];
1961
+ ring.style(color, this.colors.chipText, color);
1962
+ ring.setLabel(tab.text);
1963
+ ring.setGlyph(tab.glyph, tab.spin);
1964
+ }
1965
+ ring.setFused(d.fused);
1966
+ if (ring.draw(d.target)) moved = true;
1967
+ }
1968
+ return moved;
1969
+ }
1970
+ /**
1971
+ * The standing ordinal markers — annotation numbers at their elements'
1972
+ * bottom-right, redrawn every frame like the rings so they can't lag a
1973
+ * scroll. A marker on the selected element draws fused (square top, the
1974
+ * ring's join beside it); the CSS transition is what makes ring dismissal
1975
+ * a morph instead of a jump. Markers are the one pointer-active chrome:
1976
+ * a click answers the host, never the page.
1977
+ */
1978
+ drawMarkers(draws) {
1979
+ if (!this.ensure()) return false;
1980
+ this.lastMarkers = draws;
1981
+ let moved = false;
1982
+ const born = [];
1983
+ const keep = new Set(draws.map((d) => d.key));
1984
+ for (const [key, el] of this.markerEls) {
1985
+ if (!keep.has(key)) {
1986
+ el.remove();
1987
+ this.markerEls.delete(key);
1988
+ this.markerStyle.delete(key);
1989
+ this.markerPos.delete(key);
1990
+ this.markerXY.delete(key);
1991
+ moved = true;
1992
+ }
1993
+ }
1994
+ for (const d of draws) {
1995
+ let el = this.markerEls.get(d.key);
1996
+ if (!el) {
1997
+ el = document.createElement("div");
1998
+ el.setAttribute("data-bp-marker", "");
1999
+ el.style.cssText = `position:fixed;left:0;top:0;display:flex;align-items:center;justify-content:center;pointer-events:auto;cursor:pointer;z-index:1;width:${MARKER_SIZE}px;height:${MARKER_SIZE}px;box-sizing:border-box;font:600 11px/1 ${CHROME_FONT};letter-spacing:-0.4px;font-variant-numeric:tabular-nums;will-change:translate;border-radius:${BADGE_RADIUS}px;transition:border-radius ${MARKER_MORPH_MS}ms ${POP_EASE},box-shadow ${MARKER_MORPH_MS}ms ease,opacity 200ms ease,background-color ${RECOLOR_MS}ms ${RECOLOR_EASE};`;
2000
+ const key = d.key;
2001
+ const marker = el;
2002
+ el.addEventListener("pointerdown", (e) => e.stopPropagation());
2003
+ el.addEventListener("click", (e) => {
2004
+ e.preventDefault();
2005
+ e.stopPropagation();
2006
+ const ordinal = Number(marker.dataset.ordinal ?? "0");
2007
+ this.markerHandler?.(key, ordinal);
2008
+ emit("markerClick", { path: key, ordinal });
2009
+ });
2010
+ el.addEventListener("pointerenter", () => this.markerHover?.(key));
2011
+ el.addEventListener("pointerleave", () => this.markerHover?.(null));
2012
+ this.root.appendChild(el);
2013
+ this.markerEls.set(d.key, el);
2014
+ born.push({ el, ordinal: d.ordinal });
2015
+ moved = true;
2016
+ }
2017
+ if (this.markersHidden) el.style.display = "flex";
2018
+ const s = RING_STROKE;
2019
+ let x = d.rect.x + d.rect.w + s - MARKER_SIZE;
2020
+ let y = d.rect.y + d.rect.h + s;
2021
+ if (y + MARKER_SIZE > window.innerHeight) y = d.rect.y + d.rect.h - s - MARKER_SIZE;
2022
+ x = Math.max(0, Math.min(x, window.innerWidth - MARKER_SIZE));
2023
+ this.markerXY.set(d.key, { x, y, ordinal: d.ordinal });
2024
+ const pos = `${x}px ${y}px`;
2025
+ if (this.markerPos.get(d.key) !== pos) {
2026
+ this.markerPos.set(d.key, pos);
2027
+ el.style.translate = pos;
2028
+ moved = true;
2029
+ }
2030
+ const style = `${d.ordinal}|${d.fused}|${d.status}|${d.detached}|${d.agent ?? ""}`;
2031
+ const was = this.markerStyle.get(d.key);
2032
+ if (was !== style) {
2033
+ this.markerStyle.set(d.key, style);
2034
+ const done = d.status === "resolved";
2035
+ const mark = done ? CHECK_GLYPH : String(d.ordinal);
2036
+ const turning = was !== void 0 && was.split("|")[2] !== d.status && !matchMedia("(prefers-reduced-motion: reduce)").matches;
2037
+ if (turning) turnOver(el, mark);
2038
+ else if (done) el.innerHTML = mark;
2039
+ else el.textContent = mark;
2040
+ el.dataset.ordinal = String(d.ordinal);
2041
+ el.style.background = d.detached ? "#a9adb1" : d.agent ? this.statusColor(d.agent) : done ? this.resolvedColor() : this.annotateColor();
2042
+ el.style.color = this.colors.chipText;
2043
+ el.style.border = "none";
2044
+ el.style.opacity = "1";
2045
+ el.style.borderRadius = d.fused ? `0 0 ${BADGE_RADIUS}px ${BADGE_RADIUS}px` : `${BADGE_RADIUS}px`;
2046
+ el.style.boxShadow = d.fused ? "0 1px 3px rgba(0,0,0,0.06)" : "0 3px 8px rgba(0,0,0,0.15)";
2047
+ }
2048
+ }
2049
+ if (born.length > 0 && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
2050
+ born.sort((a, b) => a.ordinal - b.ordinal);
2051
+ born.forEach(
2052
+ (b, i) => b.el.animate([{ opacity: 0, scale: "0.25", offset: 0 }], {
2053
+ duration: 280,
2054
+ delay: Math.min(i * 45, 400),
2055
+ easing: POP_EASE,
2056
+ fill: "backwards"
2057
+ })
2058
+ );
2059
+ }
2060
+ this.markersHidden = false;
2061
+ return moved;
2062
+ }
2063
+ /** The marker under a viewport point, for synthetic pointing. Only markers
2064
+ * actually drawn this session answer — hidden overlays have none. */
2065
+ markerAtPoint(x, y) {
2066
+ if (!this.visible || this.markersHidden) return null;
2067
+ for (const [path, m] of this.markerXY) {
2068
+ if (x >= m.x && x <= m.x + MARKER_SIZE && y >= m.y && y <= m.y + MARKER_SIZE)
2069
+ return { path, ordinal: m.ordinal };
2070
+ }
2071
+ return null;
2072
+ }
2073
+ hideAll() {
2074
+ if (!this.root) return;
2075
+ this.hoverRing.draw(null);
2076
+ this.selRing.draw(null);
2077
+ for (const ring of this.statusRings.values()) ring.draw(null);
2078
+ this.hideCursor(false);
2079
+ for (const el of this.markerEls.values()) el.style.display = "none";
2080
+ this.markersHidden = true;
2081
+ }
2082
+ /** What is actually painted right now — the conformance suite's read.
2083
+ * `hover` and `selection` stay the element rects (the construction paints
2084
+ * the stroke outside them); `hoverTab`, `cursorChip`, `tab`, `badge` and
2085
+ * `markers` are the chrome. Pointer hover names through `cursorChip`;
2086
+ * `hoverTab` stands only for path-driven hovers (layers preview, a
2087
+ * hovered marker). */
2088
+ state() {
2089
+ if (!this.root)
2090
+ return {
2091
+ hover: null,
2092
+ hoverTab: null,
2093
+ cursorChip: null,
2094
+ selection: null,
2095
+ tab: null,
2096
+ badge: null,
2097
+ markers: [],
2098
+ status: []
2099
+ };
2100
+ const rect = (el) => {
2101
+ const b = el.getBoundingClientRect();
2102
+ return { x: b.left, y: b.top, w: b.width, h: b.height };
2103
+ };
2104
+ const markers = this.markersHidden ? [] : this.lastMarkers.map((d) => {
2105
+ const el = this.markerEls.get(d.key);
2106
+ return el ? { rect: rect(el), text: String(d.ordinal), fused: d.fused } : null;
2107
+ }).filter((m) => m !== null);
2108
+ const fused = markers.find((m) => m.fused);
2109
+ return {
2110
+ hover: this.hoverRing.shown ? this.hoverRing.rect : null,
2111
+ hoverTab: this.hoverRing.tabState(),
2112
+ cursorChip: this.cursorShown && this.cursorEl ? { rect: rect(this.cursorEl), text: this.cursorLabel } : null,
2113
+ selection: this.selRing.shown ? this.selRing.rect : null,
2114
+ tab: this.selRing.tabState(),
2115
+ badge: fused ? { rect: fused.rect, text: fused.text } : null,
2116
+ markers: markers.map((m) => ({ rect: m.rect, text: m.text })),
2117
+ // Element rects, like `hover` and `selection`: the construction paints
2118
+ // its stroke outside them. `text` is what the tab says.
2119
+ status: this.lastStatus.map((d) => {
2120
+ const ring = this.statusRings.get(d.key);
2121
+ if (!ring?.shown || !ring.rect) return null;
2122
+ return { rect: ring.rect, text: AGENT_TAB[d.state].text, state: d.state };
2123
+ }).filter((r) => r !== null)
2124
+ };
2125
+ }
2126
+ };
2127
+ function colorMix(color, alpha) {
2128
+ return `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`;
2129
+ }
2130
+ var SPOT_CSS = `[${SPOT_ATTR}="0"]{visibility:hidden!important}[${SPOT_ATTR}="1"]{visibility:visible!important}`;
2131
+ var ARMED_CSS = `body{visibility:hidden!important}${SPOT_CSS}`;
2132
+ var Spotlight = class {
2133
+ constructor() {
2134
+ this.style = null;
2135
+ this.text = "";
2136
+ this.path = null;
2137
+ this.applied = false;
2138
+ this.marked = /* @__PURE__ */ new Set();
2139
+ /** `<body>`'s children the first time the element resolved. Without React
2140
+ * this is the only clue a node is a portal: it wasn't there before. */
2141
+ this.baseline = null;
2142
+ this.rootWatch = null;
2143
+ }
2144
+ /** Spotlight the element at `path`; `null` turns it off. */
2145
+ set(path) {
2146
+ if (path === this.path) return;
2147
+ this.path = path;
2148
+ this.applied = false;
2149
+ this.baseline = null;
2150
+ this.clearMarks();
2151
+ if (path === null) {
2152
+ this.write("");
2153
+ this.emitState();
2154
+ return;
2155
+ }
2156
+ this.write(ARMED_CSS);
2157
+ this.emitState();
2158
+ this.refresh();
2159
+ }
2160
+ /** Re-measure the kept set. Called on every coalesced content change. */
2161
+ refresh() {
2162
+ if (this.path === null) return;
2163
+ if (!document.body) return;
2164
+ const el = elementAt(this.path);
2165
+ if (!el || !el.isConnected) {
2166
+ if (!this.applied) return;
2167
+ this.applied = false;
2168
+ this.clearMarks();
2169
+ this.write(ARMED_CSS);
2170
+ this.emitState();
2171
+ return;
2172
+ }
2173
+ const { hide, show } = this.compute(el);
2174
+ this.mark(hide, show);
2175
+ this.write(SPOT_CSS);
2176
+ if (!this.applied) {
2177
+ this.applied = true;
2178
+ this.emitState();
2179
+ }
2180
+ }
2181
+ state() {
2182
+ let kept = 0;
2183
+ for (const el of this.marked) if (el.getAttribute(SPOT_ATTR) === "1") kept++;
2184
+ return { path: this.path, applied: this.applied, hidden: this.marked.size - kept, kept };
2185
+ }
2186
+ /** Is `el` marked hidden right now? Used by the tag/selection paths so the
2187
+ * spotlight and the overlay can't argue about one element. */
2188
+ hidden(el) {
2189
+ return el.getAttribute(SPOT_ATTR) === "0";
2190
+ }
2191
+ compute(el) {
2192
+ const hide = [];
2193
+ const show = [];
2194
+ const body = document.body;
2195
+ if (body && this.baseline === null) this.baseline = new Set(Array.from(body.children));
2196
+ const chain = [];
2197
+ for (let node = el; node; node = node.parentElement) chain.unshift(node);
2198
+ const fiber = fiberOf(el);
2199
+ const rect = el.getBoundingClientRect();
2200
+ for (let i = 0; i < chain.length - 1; i++) {
2201
+ for (const child of Array.from(chain[i].children)) {
2202
+ if (child === chain[i + 1] || child.id === OVERLAY_ID) continue;
2203
+ if (NON_VISUAL.has(child.tagName.toLowerCase())) continue;
2204
+ if (this.owned(child, fiber, rect)) show.push(child);
2205
+ else hide.push(child);
2206
+ }
2207
+ }
2208
+ return { hide, show };
2209
+ }
2210
+ /** Did the focused element put this node on screen? */
2211
+ owned(child, focus, rect) {
2212
+ if (focus) {
2213
+ if (this.ownedFiber(child, focus)) return true;
2214
+ if (fiberOf(child) === null) {
2215
+ let scanned = 0;
2216
+ for (const node of Array.from(child.querySelectorAll("*"))) {
2217
+ if (++scanned > PORTAL_SCAN) break;
2218
+ if (this.ownedFiber(node, focus)) return true;
2219
+ }
2220
+ }
2221
+ return false;
2222
+ }
2223
+ if (!this.baseline || child.parentElement !== document.body || this.baseline.has(child)) return false;
2224
+ const b = child.getBoundingClientRect();
2225
+ return b.width > 0 && b.height > 0 && b.left < rect.right && b.right > rect.left && b.top < rect.bottom && b.bottom > rect.top;
2226
+ }
2227
+ /** Does `node`'s fiber ancestry pass through the focused element's fiber? */
2228
+ ownedFiber(node, focus) {
2229
+ let f = fiberOf(node);
2230
+ const alt = focus.alternate ?? null;
2231
+ for (let steps = 0; f && steps < MAX_FIBER_WALK; steps++, f = f.return) {
2232
+ if (f === focus || f === alt || (f.alternate ?? null) === focus) return true;
2233
+ }
2234
+ return false;
2235
+ }
2236
+ mark(hide, show) {
2237
+ const next = new Set(hide);
2238
+ for (const el of show) next.add(el);
2239
+ for (const el of this.marked) if (!next.has(el)) el.removeAttribute(SPOT_ATTR);
2240
+ for (const el of hide) if (el.getAttribute(SPOT_ATTR) !== "0") el.setAttribute(SPOT_ATTR, "0");
2241
+ for (const el of show) if (el.getAttribute(SPOT_ATTR) !== "1") el.setAttribute(SPOT_ATTR, "1");
2242
+ this.marked = next;
2243
+ }
2244
+ clearMarks() {
2245
+ for (const el of this.marked) el.removeAttribute(SPOT_ATTR);
2246
+ this.marked = /* @__PURE__ */ new Set();
2247
+ }
2248
+ write(text) {
2249
+ this.text = text;
2250
+ if (!this.ensureStyle()) return;
2251
+ if (this.style.textContent !== text) this.style.textContent = text;
2252
+ }
2253
+ /**
2254
+ * The sheet lives on `<html>`, not in the override stylesheet, so the two
2255
+ * can never fight — and it has to exist before the document has a `<body>`,
2256
+ * which is the whole point of arming.
2257
+ */
2258
+ ensureStyle() {
2259
+ if (this.style && this.style.isConnected) return true;
2260
+ const host = document.documentElement;
2261
+ if (!host) {
2262
+ this.waitForRoot();
2263
+ return false;
2264
+ }
2265
+ const style = document.createElement("style");
2266
+ style.id = SPOT_STYLE_ID;
2267
+ style.textContent = this.text;
2268
+ host.appendChild(style);
2269
+ this.style = style;
2270
+ return true;
2271
+ }
2272
+ waitForRoot() {
2273
+ if (this.rootWatch || typeof MutationObserver === "undefined") return;
2274
+ this.rootWatch = new MutationObserver(() => {
2275
+ if (!document.documentElement) return;
2276
+ this.rootWatch?.disconnect();
2277
+ this.rootWatch = null;
2278
+ this.write(this.text);
2279
+ this.refresh();
2280
+ });
2281
+ this.rootWatch.observe(document, { childList: true, subtree: true });
2282
+ }
2283
+ emitState() {
2284
+ emit("spotlight", this.state());
2285
+ }
2286
+ };
2287
+ var RuntimeParams = class {
2288
+ constructor() {
2289
+ this.values = {};
2290
+ this.subs = /* @__PURE__ */ new Set();
2291
+ /** Channels the page has read at least once, this document. */
2292
+ this.claimed = /* @__PURE__ */ new Set();
2293
+ /** Before/after: suspended, every read falls through to the page's own value. */
2294
+ this.enabled = true;
2295
+ }
2296
+ api() {
2297
+ return {
2298
+ get: (name, fallback) => {
2299
+ if (!this.claimed.has(name)) {
2300
+ this.claimed.add(name);
2301
+ emit("claims", { channels: Array.from(this.claimed) });
2302
+ }
2303
+ if (!this.enabled) return fallback;
2304
+ const v = this.values[name];
2305
+ return v === void 0 ? fallback : v;
2306
+ },
2307
+ all: () => ({ ...this.values }),
2308
+ subscribe: (fn) => {
2309
+ this.subs.add(fn);
2310
+ return () => this.subs.delete(fn);
2311
+ }
2312
+ };
2313
+ }
2314
+ set(values, enabled) {
2315
+ this.values = values;
2316
+ this.enabled = enabled;
2317
+ this.notify();
2318
+ }
2319
+ claims() {
2320
+ return Array.from(this.claimed);
2321
+ }
2322
+ // A page that reads parameters in render needs a nudge to render again, and
2323
+ // there is no general way to ask a framework for one. So: tell subscribers,
2324
+ // and dispatch a DOM event for anything that would rather listen than
2325
+ // subscribe. Both carry the values, so neither has to read back.
2326
+ notify() {
2327
+ const snapshot = { ...this.values };
2328
+ for (const fn of this.subs) {
2329
+ try {
2330
+ fn(snapshot);
2331
+ } catch {
2332
+ }
2333
+ }
2334
+ try {
2335
+ window.dispatchEvent(new CustomEvent("bp:params", { detail: snapshot }));
2336
+ } catch {
2337
+ }
2338
+ }
2339
+ };
2340
+ var SCROLL_SETTLE_MS = 150;
2341
+ var LOOP_ACTIVE_MS = 500;
2342
+ var LOOP_IDLE_MS = 250;
2343
+ var Probe = class {
2344
+ constructor() {
2345
+ this.overlay = new Overlay();
2346
+ this.params = new RuntimeParams();
2347
+ this.spot = new Spotlight();
2348
+ this.tagSeq = 0;
2349
+ this.hoverEl = null;
2350
+ this.hoverLabel = null;
2351
+ /** How the hover landed: the pointer carries the cursor label, a path
2352
+ * (layers preview) keeps the ring's own tab — no cursor to follow. */
2353
+ this.hoverVia = "pointer";
2354
+ this.selEl = null;
2355
+ this.rafId = null;
2356
+ /** Standing annotation markers the host asked for — see `decorate`. */
2357
+ this.decorations = [];
2358
+ /** When each mark's path first failed to resolve — a mark only falls back
2359
+ * to its stored snapshot after a settle, so a booting document (elements
2360
+ * three renders away) never flashes gray markers at stale positions. */
2361
+ this.unresolvedSince = /* @__PURE__ */ new Map();
2362
+ /** The marker under the pointer, owning the hover construction. */
2363
+ this.markerHoverPath = null;
2364
+ this.mutationRaf = null;
2365
+ this.declRaf = null;
2366
+ /** When the last activity signal landed — the loop's full-rate window. */
2367
+ this.lastActivityAt = 0;
2368
+ /** Hover suppression window while the page scrolls. */
2369
+ this.scrollingUntil = 0;
2370
+ this.idleTimer = null;
2371
+ this.activityAttached = false;
2372
+ /**
2373
+ * Tags someone *else* owns — an override stylesheet, a pin.
2374
+ *
2375
+ * The selection hands its tag back when it moves on; a held one never does,
2376
+ * because the rule addressing it outlives the pick that wrote it. Without
2377
+ * this, the tweak you just tuned came undone the moment you inspected the
2378
+ * next element: `[data-bp-sel="7"]` stopped matching anything.
2379
+ *
2380
+ * Tag values, not elements: a page that re-renders the node away leaves a
2381
+ * short dead string here rather than a detached `Element` this set would
2382
+ * otherwise keep alive for the session.
2383
+ */
2384
+ this.heldTags = /* @__PURE__ */ new Set();
2385
+ this.onScroll = () => {
2386
+ this.scrollingUntil = performance.now() + SCROLL_SETTLE_MS;
2387
+ if (this.hoverEl) {
2388
+ this.hoverEl = null;
2389
+ this.hoverLabel = null;
2390
+ this.overlay.hideCursor(false);
2391
+ this.overlay.drawHover(null, null);
2392
+ }
2393
+ this.wake();
2394
+ };
2395
+ this.onResize = () => this.wake();
2396
+ this.onMotion = () => this.wake();
2397
+ this.watch();
2398
+ this.tick = this.tick.bind(this);
2399
+ this.overlay.markerHover = (path) => {
2400
+ this.markerHoverPath = path;
2401
+ this.wake();
2402
+ };
2403
+ window.__bpParams = this.params.api();
2404
+ if (typeof window.__bpSpot === "string") this.spot.set(window.__bpSpot);
2405
+ window.addEventListener("bp:declare", () => this.emitDeclarations());
2406
+ if (window.__bpDecl && window.__bpDecl.rev > 0) this.emitDeclarations();
2407
+ emit("ready", { url: location.href });
2408
+ const painted = () => {
2409
+ requestAnimationFrame(
2410
+ () => requestAnimationFrame(() => emit("painted", { url: location.href }))
2411
+ );
2412
+ };
2413
+ if (document.readyState === "complete") painted();
2414
+ else window.addEventListener("load", painted, { once: true });
2415
+ }
2416
+ /** The page's declared parameters, in registration order. */
2417
+ declared() {
2418
+ const reg = window.__bpDecl;
2419
+ return reg ? Object.values(reg.params) : [];
2420
+ }
2421
+ // Coalesced to a frame: HMR replaces a module and every `useParam` in it
2422
+ // re-registers in one burst, which must land as one event, not a storm.
2423
+ emitDeclarations() {
2424
+ if (this.declRaf !== null) return;
2425
+ this.declRaf = requestAnimationFrame(() => {
2426
+ this.declRaf = null;
2427
+ emit("declarations", { params: this.declared() });
2428
+ });
2429
+ }
2430
+ /** Push the card's runtime parameters. `enabled` is the before/after gate. */
2431
+ setParams(values, enabled) {
2432
+ this.params.set(values, enabled);
2433
+ }
2434
+ /** Which channels the page has read, this document. */
2435
+ claimedChannels() {
2436
+ return this.params.claims();
2437
+ }
2438
+ setOverlay(config) {
2439
+ if (config.colors) this.overlay.setColors(config.colors);
2440
+ if (config.suppressSelection !== void 0) {
2441
+ this.overlay.suppressSelection = config.suppressSelection;
2442
+ if (config.suppressSelection) this.overlay.drawSelection(null);
2443
+ }
2444
+ if (config.pointing !== void 0) this.overlay.pointing = config.pointing;
2445
+ if (config.visible !== void 0) {
2446
+ this.overlay.visible = config.visible;
2447
+ if (!config.visible) {
2448
+ this.hoverEl = null;
2449
+ this.hoverLabel = null;
2450
+ this.overlay.hideAll();
2451
+ this.stopLoop();
2452
+ this.detachActivity();
2453
+ } else {
2454
+ this.attachActivity();
2455
+ this.wake();
2456
+ }
2457
+ }
2458
+ if (config.pointing !== void 0 || config.visible !== void 0) this.overlay.syncCursorStyle();
2459
+ }
2460
+ /**
2461
+ * Standing annotation markers: the ordinals the host says stand on these
2462
+ * elements. Standing chrome — redrawn every frame with the rings, cleared
2463
+ * only by the host (never by `clearSelection`), and the one pointer-active
2464
+ * piece of the overlay: a marker click answers the host, not the page
2465
+ * (`markerClick` emit for wire hosts, `onMarkerClick` for in-page ones).
2466
+ */
2467
+ decorate(marks) {
2468
+ this.decorations = marks;
2469
+ this.wake();
2470
+ }
2471
+ onMarkerClick(handler) {
2472
+ this.overlay.markerHandler = handler;
2473
+ }
2474
+ hover(x, y) {
2475
+ const mark = this.overlay.markerAtPoint(x, y);
2476
+ if (mark) {
2477
+ if (this.markerHoverPath !== mark.path) {
2478
+ this.markerHoverPath = mark.path;
2479
+ this.wake();
2480
+ }
2481
+ this.hoverEl = null;
2482
+ this.hoverLabel = null;
2483
+ this.overlay.hideCursor(false);
2484
+ this.overlay.drawHover(null, null);
2485
+ emit("hover", null);
2486
+ return null;
2487
+ }
2488
+ if (this.markerHoverPath !== null) {
2489
+ this.markerHoverPath = null;
2490
+ this.wake();
2491
+ }
2492
+ const el = elementAtPoint(x, y);
2493
+ this.hoverEl = el;
2494
+ this.hoverVia = "pointer";
2495
+ const crumb = el ? crumbLite(el) : null;
2496
+ this.hoverLabel = crumb?.label ?? null;
2497
+ const suppressed = performance.now() < this.scrollingUntil;
2498
+ const shown = !suppressed && el !== null && el !== this.selEl;
2499
+ this.overlay.setHoverTab(false);
2500
+ this.overlay.drawHover(shown && el ? targetOf(el) : null, this.hoverLabel);
2501
+ if (shown && this.hoverLabel) this.overlay.drawCursor(x, y, this.hoverLabel);
2502
+ else this.overlay.hideCursor(!suppressed);
2503
+ this.wake();
2504
+ emit("hover", crumb);
2505
+ return crumb;
2506
+ }
2507
+ hoverOff() {
2508
+ this.hoverEl = null;
2509
+ this.hoverLabel = null;
2510
+ this.overlay.hideCursor(true);
2511
+ this.overlay.drawHover(null, null);
2512
+ emit("hover", null);
2513
+ }
2514
+ /** Draw the hover construction on the element at `path` — the layers
2515
+ * list's row preview. Draw-only: no `hover` emission, so the last pointer
2516
+ * crumb (what an annotate click places a pin from) is untouched. */
2517
+ hoverPath(path) {
2518
+ const el = elementAt(path);
2519
+ this.hoverEl = el;
2520
+ this.hoverVia = "path";
2521
+ this.hoverLabel = el ? labelOf(el) : null;
2522
+ this.overlay.hideCursor(false);
2523
+ this.overlay.setHoverTab(true);
2524
+ this.overlay.drawHover(el && el !== this.selEl ? targetOf(el) : null, this.hoverLabel);
2525
+ this.wake();
2526
+ }
2527
+ select(x, y) {
2528
+ const mark = this.overlay.markerAtPoint(x, y);
2529
+ if (mark) {
2530
+ this.overlay.markerHandler?.(mark.path, mark.ordinal);
2531
+ emit("markerClick", { path: mark.path, ordinal: mark.ordinal });
2532
+ return null;
2533
+ }
2534
+ const el = elementAtPoint(x, y);
2535
+ if (!el) return null;
2536
+ return this.commitSelection(el, true);
2537
+ }
2538
+ selectPath(path) {
2539
+ const el = elementAt(path);
2540
+ return el ? this.commitSelection(el) : null;
2541
+ }
2542
+ /** A stable, unique tag for an element, so `[data-bp-sel="v"]` matches
2543
+ * exactly one node — pins and the selection can coexist without collision. */
2544
+ tag(el) {
2545
+ const existing = el.getAttribute(SEL_ATTR);
2546
+ if (existing) return existing;
2547
+ const v = String(++this.tagSeq);
2548
+ el.setAttribute(SEL_ATTR, v);
2549
+ return v;
2550
+ }
2551
+ /** Whether the selection may reclaim this element's tag. */
2552
+ tagHeld(el) {
2553
+ const tag = el.getAttribute(SEL_ATTR);
2554
+ return tag !== null && this.heldTags.has(tag);
2555
+ }
2556
+ commitSelection(el, viaPointer = false) {
2557
+ const fresh = el !== this.selEl;
2558
+ if (this.selEl && this.selEl !== el && this.selEl.getAttribute(SEL_ATTR) && !this.tagHeld(this.selEl)) {
2559
+ this.selEl.removeAttribute(SEL_ATTR);
2560
+ }
2561
+ this.selEl = el;
2562
+ this.tag(el);
2563
+ const ref = refOf(el);
2564
+ this.overlay.setSelectionLabel(labelOf(el));
2565
+ this.overlay.drawSelection(targetOf(el));
2566
+ this.overlay.drawHover(null, null);
2567
+ if (viaPointer && fresh) this.overlay.handOff();
2568
+ else this.overlay.hideCursor(viaPointer);
2569
+ this.wake();
2570
+ return ref;
2571
+ }
2572
+ clearSelection() {
2573
+ if (this.selEl && !this.tagHeld(this.selEl)) this.selEl.removeAttribute(SEL_ATTR);
2574
+ this.selEl = null;
2575
+ this.overlay.drawSelection(null);
2576
+ this.wake();
2577
+ }
2578
+ describe(path) {
2579
+ const el = elementAt(path);
2580
+ return el ? refOf(el) : null;
2581
+ }
2582
+ rects(paths) {
2583
+ return paths.map((p) => {
2584
+ const el = elementAt(p);
2585
+ return el ? markRect(p, el) : null;
2586
+ });
2587
+ }
2588
+ scope(scope) {
2589
+ if (!scope.componentKey) return elementAt(scope.elementPath) ? [scope.elementPath] : [];
2590
+ const [name, ownerPath = ""] = scope.componentKey.split("@");
2591
+ const variant = scope.variant;
2592
+ const find = (owner2) => {
2593
+ const found = [];
2594
+ let scanned = 0;
2595
+ for (const node of Array.from(owner2.querySelectorAll("*"))) {
2596
+ if (++scanned > MAX_SCAN) break;
2597
+ const nc = nearestComponent(node);
2598
+ if (nc?.name !== name || componentRoot(node) !== node) continue;
2599
+ if (variant && !matchesVariant(node, variant)) continue;
2600
+ found.push(node);
2601
+ }
2602
+ return found;
2603
+ };
2604
+ const mount = mountRoot();
2605
+ const owner = elementAt(ownerPath) ?? mount;
2606
+ let roots = find(owner);
2607
+ if (roots.length === 0 && owner !== mount) roots = find(mount);
2608
+ roots.sort((a, b) => comparePaths(pathOf(a) ?? "", pathOf(b) ?? ""));
2609
+ const chosen = scope.instanceIndex === void 0 ? roots : roots.filter((_, i) => i === scope.instanceIndex);
2610
+ const inner = scope.innerPath ?? "";
2611
+ return chosen.map((root) => {
2612
+ const rp = pathOf(root);
2613
+ if (rp === null) return null;
2614
+ const full = inner === "" ? rp : rp === "" ? inner : `${rp}/${inner}`;
2615
+ return elementAt(full) ? full : null;
2616
+ }).filter((p) => p !== null);
2617
+ }
2618
+ /** Ensure the element at `path` carries `data-bp-sel` so main can find its
2619
+ * CDP nodeId for pinning. Returns the selector value, or null. */
2620
+ ensureTag(path) {
2621
+ const el = elementAt(path);
2622
+ if (!el) return null;
2623
+ const tag = this.tag(el);
2624
+ this.heldTags.add(tag);
2625
+ return tag;
2626
+ }
2627
+ /**
2628
+ * Hand held tags back — `null` releases every one (Reset, a host dropping
2629
+ * its whole override sheet). The element the selection is still on keeps its
2630
+ * attribute; every other loses it, so the page is left carrying nothing
2631
+ * Blueprint put there.
2632
+ */
2633
+ releaseTags(paths) {
2634
+ const tags = paths === null ? [...this.heldTags] : paths.map((p) => elementAt(p)?.getAttribute(SEL_ATTR) ?? null).filter((tag) => tag !== null);
2635
+ for (const tag of tags) {
2636
+ this.heldTags.delete(tag);
2637
+ const el = document.querySelector(`[${SEL_ATTR}="${CSS.escape(tag)}"]`);
2638
+ if (el && el !== this.selEl) el.removeAttribute(SEL_ATTR);
2639
+ }
2640
+ if (paths === null) this.heldTags.clear();
2641
+ }
2642
+ /** Computed style values for the element at `path` — the pin test reads the
2643
+ * forced :hover background here, and phase 3 derives parameters from it. */
2644
+ /**
2645
+ * A durable CSS selector for the element at `path` — the beam's own address.
2646
+ *
2647
+ * The inverse of `query`, and the reason a capture can cross a process
2648
+ * boundary at all: a path is measured against one render, a selector is
2649
+ * re-resolved against every later one. See `printSelector`.
2650
+ */
2651
+ selectorFor(path) {
2652
+ const el = elementAt(path);
2653
+ return el ? printSelector(el) : null;
2654
+ }
2655
+ /** Child-index path of the first element matching a CSS selector, or null.
2656
+ * Provenance (phase 3) and the conformance suite both address by selector. */
2657
+ query(selector) {
2658
+ let el = null;
2659
+ try {
2660
+ el = mountRoot().querySelector(selector);
2661
+ } catch {
2662
+ return null;
2663
+ }
2664
+ return el ? pathOf(el) : null;
2665
+ }
2666
+ computed(path, props) {
2667
+ const el = elementAt(path);
2668
+ if (!el) return null;
2669
+ const cs = getComputedStyle(el);
2670
+ const out = {};
2671
+ for (const prop of props) out[prop] = cs.getPropertyValue(prop);
2672
+ return out;
2673
+ }
2674
+ /** `computed`, for a whole subtree at once — see `PageProbe.sample`. */
2675
+ sample(paths, props) {
2676
+ return paths.map((path) => this.computed(path, props));
2677
+ }
2678
+ /**
2679
+ * The page's color variables (mirrors `PageColorVariable`): every custom
2680
+ * property declared on the root by the page's own stylesheets — Tailwind
2681
+ * v4's `@theme` lands as `:root, :host { --color-…}` inside `@layer
2682
+ * theme`, so grouping rules are walked — resolved off the root and kept
2683
+ * where the value is a color. Cross-origin sheets can't be read and are
2684
+ * skipped; a sheet Blueprint injected is the page's too, and harmless.
2685
+ */
2686
+ colorVariables() {
2687
+ const names = /* @__PURE__ */ new Set();
2688
+ const rootish = /(^|[\s,])(:root|html|:host)(\b|[\s,:])/;
2689
+ const walk = (rules) => {
2690
+ for (const rule of Array.from(rules)) {
2691
+ if (rule instanceof CSSStyleRule) {
2692
+ if (!rootish.test(rule.selectorText)) continue;
2693
+ for (let i = 0; i < rule.style.length; i++) {
2694
+ const prop = rule.style[i];
2695
+ if (prop && prop.startsWith("--")) names.add(prop);
2696
+ }
2697
+ } else if ("cssRules" in rule) {
2698
+ walk(rule.cssRules);
2699
+ }
2700
+ if (names.size > 600) return;
2701
+ }
2702
+ };
2703
+ for (const sheet of Array.from(document.styleSheets)) {
2704
+ try {
2705
+ walk(sheet.cssRules);
2706
+ } catch {
2707
+ }
2708
+ }
2709
+ const cs = getComputedStyle(document.documentElement);
2710
+ const out = [];
2711
+ for (const name of [...names].sort()) {
2712
+ const value = cs.getPropertyValue(name).trim();
2713
+ if (value && CSS.supports("color", value)) out.push({ name, value });
2714
+ }
2715
+ return out;
2716
+ }
2717
+ /** What the overlay is drawing right now — a test/debug read, so the suite
2718
+ * can assert against the painted chrome rather than the element rects. */
2719
+ overlayState() {
2720
+ return this.overlay.state();
2721
+ }
2722
+ /**
2723
+ * The component behind an element, described for a sandbox request: what
2724
+ * it was rendered *with*, and what it was rendered *inside*.
2725
+ *
2726
+ * `wrappedBy` is every named component up the fiber tree, outermost first —
2727
+ * the provider chain as Blueprint can see it. Blueprint doesn't try to guess
2728
+ * which of them are providers; the agent knows the codebase and can.
2729
+ */
2730
+ describeComponent(path) {
2731
+ const el = elementAt(path);
2732
+ if (!el) return null;
2733
+ const near = nearestComponent(el);
2734
+ if (!near) return null;
2735
+ const wrappedBy = [];
2736
+ let f = near.fiber.return;
2737
+ for (let i = 0; f && i < MAX_FIBER_WALK && wrappedBy.length < 12; i++, f = f.return) {
2738
+ const name = fiberName(f.type);
2739
+ if (name && wrappedBy[0] !== name) wrappedBy.unshift(name);
2740
+ }
2741
+ return { name: near.name, props: summariseProps(near.fiber.memoizedProps), wrappedBy };
2742
+ }
2743
+ /** What a sandbox page says about itself, or null on any other page.
2744
+ * The entry owns the fact; Blueprint owns the state drawn over the card. */
2745
+ sandbox() {
2746
+ return window.__bpSandbox ?? null;
2747
+ }
2748
+ /** Show only the element at `path`, its ancestors and what it opened;
2749
+ * `null` lifts it. See `Spotlight`. */
2750
+ spotlight(path) {
2751
+ this.spot.set(path);
2752
+ }
2753
+ /** Whether the spotlight is armed or applied, and how much it is hiding. */
2754
+ spotlightState() {
2755
+ return this.spot.state();
2756
+ }
2757
+ /**
2758
+ * The element tree in document order, for the layers list. Depth-first from
2759
+ * the mount root, capped at `maxNodes` with the cut declared — never silent.
2760
+ * `name` is the component where the element is a component root (the unit a
2761
+ * person thinks in), the DOM tag otherwise.
2762
+ */
2763
+ tree(maxNodes = MAX_TREE) {
2764
+ const nodes = [];
2765
+ let truncated = false;
2766
+ const walk = (el, depth) => {
2767
+ for (const child of Array.from(el.children)) {
2768
+ if (child.id === OVERLAY_ID) continue;
2769
+ if (nodes.length >= maxNodes) {
2770
+ truncated = true;
2771
+ return false;
2772
+ }
2773
+ const path = pathOf(child);
2774
+ if (path === null) continue;
2775
+ const comp = componentRoot(child) === child ? componentNameOf(child) : void 0;
2776
+ nodes.push({
2777
+ path,
2778
+ tag: child.tagName.toLowerCase(),
2779
+ name: comp ?? child.tagName.toLowerCase(),
2780
+ component: comp !== void 0,
2781
+ depth,
2782
+ text: hasOwnText(child)
2783
+ });
2784
+ if (!walk(child, depth + 1)) return false;
2785
+ }
2786
+ return true;
2787
+ };
2788
+ walk(mountRoot(), 0);
2789
+ return { nodes, truncated };
2790
+ }
2791
+ /**
2792
+ * The element at `path`, as a live handle.
2793
+ *
2794
+ * Only ever useful to an **in-page** host: over CDP a DOM node cannot cross
2795
+ * the wire, which is why every other method here answers in paths and rects.
2796
+ * Beam's driver runs in the same document as the probe, so it can ask
2797
+ * directly rather than re-implementing the walk — one addressing scheme, not
2798
+ * two (`packages/probe/src/beam.ts`).
2799
+ */
2800
+ nodeAt(path) {
2801
+ return elementAt(path);
2802
+ }
2803
+ /** Path for a live element handle — main resolves an animation's target
2804
+ * (`DOM.resolveNode` → `Runtime.callFunctionOn`) through this, so the
2805
+ * Live motion strip can scope itself with the same addressing scheme
2806
+ * selection uses. */
2807
+ pathForElement(el) {
2808
+ return el instanceof Element ? pathOf(el) : null;
2809
+ }
2810
+ /**
2811
+ * The pseudo-states that are *live* around the element at `path` right now
2812
+ * — candidates, not conclusions.
2813
+ *
2814
+ * A capture leaving this page (Beam's crossing, the beam driver) carries
2815
+ * them so the card can try them once resolving the selector bare has
2816
+ * failed; the cost of over-guessing is one retry rather than a static
2817
+ * element arriving pinned. What earns a place is a signal that something is
2818
+ * *held open*: an expanded trigger, a focused control, or the immediate
2819
+ * ancestors the pointer is on (which is how `.parent:hover .child` and
2820
+ * `group-hover` work). Deliberately short — a card wearing four pins that
2821
+ * changed nothing is a lie about why it looks the way it does.
2822
+ */
2823
+ candidatePins(path) {
2824
+ const el = elementAt(path);
2825
+ const out = [];
2826
+ const seen = /* @__PURE__ */ new Set();
2827
+ const add = (node, states) => {
2828
+ if (!node || out.length >= MAX_CANDIDATES || node === document.body || node === document.documentElement) return;
2829
+ const selector = printSelector(node);
2830
+ if (!selector || seen.has(selector)) return;
2831
+ seen.add(selector);
2832
+ out.push({ selector, states });
2833
+ };
2834
+ let expanded = 0;
2835
+ for (const node of Array.from(document.querySelectorAll('[aria-expanded="true"]'))) {
2836
+ if (++expanded > 2) break;
2837
+ add(node, ["hover", "focus"]);
2838
+ }
2839
+ if (el) {
2840
+ let node = el.parentElement;
2841
+ for (let i = 0; node && i < 2; i++, node = node.parentElement) {
2842
+ if (node.matches(":hover")) add(node, ["hover"]);
2843
+ }
2844
+ }
2845
+ const active = document.activeElement;
2846
+ if (active && active !== document.body && !(el && el.contains(active))) add(active, ["focus"]);
2847
+ return out;
2848
+ }
2849
+ pauseAnimations() {
2850
+ for (const anim of document.getAnimations?.() ?? []) anim.pause();
2851
+ }
2852
+ resumeAnimations() {
2853
+ for (const anim of document.getAnimations?.() ?? []) anim.play();
2854
+ }
2855
+ // Re-measure while visible: the whole reason the rings live in the page.
2856
+ // Frame rate while anything moves; `LOOP_IDLE_MS` sampling once everything
2857
+ // drawn has held still past `LOOP_ACTIVE_MS`; parked outright with nothing
2858
+ // drawn. Any activity signal (`wake`) restores frame rate.
2859
+ startLoop() {
2860
+ if (this.idleTimer !== null) {
2861
+ clearTimeout(this.idleTimer);
2862
+ this.idleTimer = null;
2863
+ }
2864
+ if (this.rafId === null) this.rafId = requestAnimationFrame(this.tick);
2865
+ }
2866
+ stopLoop() {
2867
+ if (this.rafId !== null) cancelAnimationFrame(this.rafId);
2868
+ this.rafId = null;
2869
+ if (this.idleTimer !== null) clearTimeout(this.idleTimer);
2870
+ this.idleTimer = null;
2871
+ }
2872
+ wake() {
2873
+ this.lastActivityAt = performance.now();
2874
+ if (this.overlay.visible) this.startLoop();
2875
+ }
2876
+ /** Scroll and resize can move what the rings track without a single DOM
2877
+ * mutation — listened only while the overlay is up. Capture, because
2878
+ * `scroll` doesn't bubble but does capture through the light tree. */
2879
+ attachActivity() {
2880
+ if (this.activityAttached) return;
2881
+ this.activityAttached = true;
2882
+ window.addEventListener("scroll", this.onScroll, { capture: true, passive: true });
2883
+ window.addEventListener("resize", this.onResize, { passive: true });
2884
+ window.addEventListener("animationstart", this.onMotion, { capture: true, passive: true });
2885
+ window.addEventListener("transitionrun", this.onMotion, { capture: true, passive: true });
2886
+ }
2887
+ detachActivity() {
2888
+ if (!this.activityAttached) return;
2889
+ this.activityAttached = false;
2890
+ window.removeEventListener("scroll", this.onScroll, true);
2891
+ window.removeEventListener("resize", this.onResize);
2892
+ window.removeEventListener("animationstart", this.onMotion, true);
2893
+ window.removeEventListener("transitionrun", this.onMotion, true);
2894
+ }
2895
+ tick() {
2896
+ this.rafId = null;
2897
+ if (!this.overlay.visible) return;
2898
+ const now = performance.now();
2899
+ const scrolling = now < this.scrollingUntil;
2900
+ const hoverMark = this.markerHoverPath;
2901
+ const draws = [];
2902
+ const status = [];
2903
+ const ringed = /* @__PURE__ */ new Set();
2904
+ let fused = false;
2905
+ let fusedResolved = false;
2906
+ let settling = false;
2907
+ for (const d of this.decorations) {
2908
+ const el = elementAt(d.path);
2909
+ const alive = el !== null && el.isConnected;
2910
+ if (alive) this.unresolvedSince.delete(d.path);
2911
+ else {
2912
+ const since = this.unresolvedSince.get(d.path) ?? now;
2913
+ if (this.unresolvedSince.get(d.path) === void 0) this.unresolvedSince.set(d.path, now);
2914
+ if (now - since < DETACH_SETTLE_MS) {
2915
+ settling = true;
2916
+ continue;
2917
+ }
2918
+ if (!d.fallbackRect) continue;
2919
+ }
2920
+ const onSelection = alive && el === this.selEl;
2921
+ if (onSelection) {
2922
+ fused = true;
2923
+ fusedResolved = d.status === "resolved";
2924
+ }
2925
+ const agent = alive ? d.agent : void 0;
2926
+ if (agent && el) {
2927
+ ringed.add(el);
2928
+ status.push({ key: d.path, state: agent, target: markTarget(d.path, el), fused: true });
2929
+ }
2930
+ draws.push({
2931
+ key: d.path,
2932
+ ordinal: d.ordinal,
2933
+ rect: alive ? markRect(d.path, el) : d.fallbackRect,
2934
+ fused: onSelection || agent !== void 0 || alive && d.path === hoverMark,
2935
+ status: d.status ?? "sent",
2936
+ detached: !alive,
2937
+ ...agent ? { agent } : {}
2938
+ });
2939
+ }
2940
+ const selTarget = this.selEl && this.selEl.isConnected ? targetOf(this.selEl) : null;
2941
+ let hoverLost = false;
2942
+ if (this.hoverEl && !this.hoverEl.isConnected) {
2943
+ this.hoverEl = null;
2944
+ this.hoverLabel = null;
2945
+ hoverLost = true;
2946
+ }
2947
+ const hoverMarkEl = hoverMark ? elementAt(hoverMark) : null;
2948
+ const markHover = hoverMark !== null && hoverMarkEl && hoverMarkEl.isConnected && !ringed.has(hoverMarkEl) ? {
2949
+ target: hoverMarkEl !== this.selEl ? markTarget(hoverMark, hoverMarkEl) : null,
2950
+ label: labelOf(hoverMarkEl),
2951
+ resolved: draws.some((d) => d.key === hoverMark && d.status === "resolved")
2952
+ } : null;
2953
+ const hoverTarget = !markHover && this.hoverEl && this.hoverEl !== this.selEl && !ringed.has(this.hoverEl) ? targetOf(this.hoverEl) : null;
2954
+ let movedAny = false;
2955
+ if (this.overlay.drawStatus(status)) movedAny = true;
2956
+ this.overlay.setSelectionFused(fused, fusedResolved);
2957
+ if (this.selEl) {
2958
+ if (selTarget) {
2959
+ const standDown = ringed.has(this.selEl);
2960
+ if (this.overlay.drawSelection(standDown ? null : selTarget)) movedAny = true;
2961
+ } else {
2962
+ this.clearSelection();
2963
+ movedAny = true;
2964
+ }
2965
+ }
2966
+ if (markHover) {
2967
+ this.overlay.setHoverTab(true);
2968
+ this.overlay.hideCursor(true);
2969
+ this.overlay.setHoverAccent(true, markHover.resolved);
2970
+ this.overlay.setHoverFused(true);
2971
+ if (this.overlay.drawHover(scrolling ? null : markHover.target, markHover.label)) movedAny = true;
2972
+ } else {
2973
+ this.overlay.setHoverAccent(false);
2974
+ this.overlay.setHoverFused(false);
2975
+ this.overlay.setHoverTab(this.hoverVia === "path");
2976
+ if (this.hoverEl) {
2977
+ if (this.overlay.drawHover(scrolling ? null : hoverTarget, this.hoverLabel)) movedAny = true;
2978
+ } else if (hoverMark || hoverLost) {
2979
+ if (hoverLost) this.overlay.hideCursor(false);
2980
+ if (this.overlay.drawHover(null, null)) movedAny = true;
2981
+ }
2982
+ }
2983
+ if (this.overlay.drawMarkers(draws)) movedAny = true;
2984
+ if (movedAny) this.lastActivityAt = now;
2985
+ const nothingShown = draws.length === 0 && status.length === 0 && !settling && !this.selEl && !this.hoverEl && !hoverMark;
2986
+ if (nothingShown) return;
2987
+ if (scrolling || now - this.lastActivityAt < LOOP_ACTIVE_MS) {
2988
+ this.startLoop();
2989
+ } else {
2990
+ this.idleTimer = setTimeout(() => {
2991
+ this.idleTimer = null;
2992
+ this.startLoop();
2993
+ }, LOOP_IDLE_MS);
2994
+ }
2995
+ }
2996
+ // Content shape changes re-anchor scoped params and pins on the host side.
2997
+ watch() {
2998
+ const ping = () => {
2999
+ this.wake();
3000
+ if (this.mutationRaf !== null) return;
3001
+ this.mutationRaf = requestAnimationFrame(() => {
3002
+ this.mutationRaf = null;
3003
+ this.spot.refresh();
3004
+ emit("contentChanged");
3005
+ });
3006
+ };
3007
+ const ours = (r) => r.type === "attributes" && (r.attributeName === SPOT_ATTR || r.attributeName === SEL_ATTR);
3008
+ const start = () => {
3009
+ const mount = mountRoot();
3010
+ const mo = new MutationObserver((records) => {
3011
+ if (records.every(ours)) return;
3012
+ ping();
3013
+ });
3014
+ mo.observe(mount, { childList: true, subtree: true, attributes: true, characterData: true });
3015
+ if (typeof ResizeObserver !== "undefined") {
3016
+ const ro = new ResizeObserver(ping);
3017
+ ro.observe(mount);
3018
+ }
3019
+ };
3020
+ if (document.body) start();
3021
+ else document.addEventListener("DOMContentLoaded", start, { once: true });
3022
+ }
3023
+ };
3024
+ var HOLD_KEYS = /* @__PURE__ */ new Set(["Meta", "Alt", "Shift", "Control"]);
3025
+ var PRINTABLE_HOLDS = /* @__PURE__ */ new Set(["c", "`"]);
3026
+ function typingHere(e) {
3027
+ const target = e.composedPath()[0];
3028
+ if (!(target instanceof HTMLElement)) return false;
3029
+ return target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable;
3030
+ }
3031
+ function forwardHolds() {
3032
+ const send = (kind, e, key) => {
3033
+ emit("keyHold", { kind, key, meta: e.metaKey, alt: e.altKey, ctrl: e.ctrlKey });
3034
+ };
3035
+ window.addEventListener(
3036
+ "keydown",
3037
+ (e) => {
3038
+ if (!window.__bpEmit || e.repeat) return;
3039
+ if (HOLD_KEYS.has(e.key)) {
3040
+ send("down", e, e.key);
3041
+ return;
3042
+ }
3043
+ if (e.metaKey || e.altKey) {
3044
+ send("chord", e);
3045
+ return;
3046
+ }
3047
+ const key = e.key.toLowerCase();
3048
+ if (PRINTABLE_HOLDS.has(key) && !e.ctrlKey && !typingHere(e)) send("down", e, key);
3049
+ },
3050
+ true
3051
+ );
3052
+ window.addEventListener(
3053
+ "keyup",
3054
+ (e) => {
3055
+ if (!window.__bpEmit) return;
3056
+ const key = HOLD_KEYS.has(e.key) ? e.key : e.key.toLowerCase();
3057
+ if (HOLD_KEYS.has(key) || PRINTABLE_HOLDS.has(key)) send("up", e, key);
3058
+ },
3059
+ true
3060
+ );
3061
+ }
3062
+ function forwardZoom() {
3063
+ window.addEventListener(
3064
+ "wheel",
3065
+ (e) => {
3066
+ if (!window.__bpEmit || !window.__bpZoomToHost) return;
3067
+ if (!e.ctrlKey && !e.metaKey) return;
3068
+ e.preventDefault();
3069
+ emit("wheelZoom", { deltaY: e.deltaY, deltaMode: e.deltaMode, x: e.clientX, y: e.clientY });
3070
+ },
3071
+ // Non-passive, or `preventDefault` is a no-op and the browser zooms
3072
+ // anyway — the same lesson the canvas root's listener carries.
3073
+ { passive: false, capture: true }
3074
+ );
3075
+ }
3076
+ function install() {
3077
+ if (window.__bp) return;
3078
+ window.__bp = new Probe();
3079
+ forwardHolds();
3080
+ forwardZoom();
3081
+ }
3082
+ if (window.__bpDeferInstall) window.__bpInstall = install;
3083
+ else install();
3084
+ })();