twiddle-panel 0.7.1 → 0.8.1

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/twiddle.mjs CHANGED
@@ -1,148 +1,148 @@
1
- const ut = /* @__PURE__ */ new Set();
2
- let M = ta(), J = [], ve = [], De = null, en = 0;
3
- function ta() {
4
- const t = new URLSearchParams(location.search).get("twd");
5
- if (!t) return {};
1
+ const gt = /* @__PURE__ */ new Set();
2
+ let M = sa(), Q = [], ke = [], qe = null, an = 0;
3
+ function sa() {
4
+ const e = new URLSearchParams(location.search).get("twd");
5
+ if (!e) return {};
6
6
  try {
7
- return JSON.parse(t);
7
+ return JSON.parse(e);
8
8
  } catch {
9
9
  return {};
10
10
  }
11
11
  }
12
- function na() {
13
- const t = new URL(location.href);
14
- Object.keys(M).length ? t.searchParams.set("twd", JSON.stringify(M)) : t.searchParams.delete("twd"), history.replaceState(history.state, "", t);
12
+ function ia() {
13
+ const e = new URL(location.href);
14
+ Object.keys(M).length ? e.searchParams.set("twd", JSON.stringify(M)) : e.searchParams.delete("twd"), history.replaceState(history.state, "", e);
15
15
  }
16
- function kt() {
17
- na(), ut.forEach((t) => t(M));
16
+ function Et() {
17
+ ia(), gt.forEach((e) => e(M));
18
18
  }
19
- function le(t, e) {
20
- if (JSON.stringify(t) === JSON.stringify(M)) return;
19
+ function pe(e, t) {
20
+ if (JSON.stringify(e) === JSON.stringify(M)) return;
21
21
  const n = Date.now();
22
- e && e === De && n - en < 400 || (J.push(M), J.length > 100 && J.shift()), ve = [], De = e, en = n, M = t, kt();
22
+ t && t === qe && n - an < 400 || (Q.push(M), Q.length > 100 && Q.shift()), ke = [], qe = t, an = n, M = e, Et();
23
23
  }
24
- function Ue(t, e) {
25
- const n = { ...t, ...e };
24
+ function Ve(e, t) {
25
+ const n = { ...e, ...t };
26
26
  return Object.keys(n).forEach((a) => {
27
27
  n[a] == null && delete n[a];
28
28
  }), Object.keys(n).length ? n : null;
29
29
  }
30
- function U(t, e, n) {
31
- const a = { ...t };
32
- return n == null ? delete a[e] : a[e] = n, a;
30
+ function B(e, t, n) {
31
+ const a = { ...e };
32
+ return n == null ? delete a[t] : a[t] = n, a;
33
33
  }
34
- function ht() {
34
+ function mt() {
35
35
  return JSON.parse(JSON.stringify(M));
36
36
  }
37
- function aa(t, e) {
38
- le(U(M, t, Ue(M[t], e)), `${t}:${Object.keys(e)}`);
37
+ function la(e, t) {
38
+ pe(B(M, e, Ve(M[e], t)), `${e}:${Object.keys(t)}`);
39
39
  }
40
- function oa(t, e = `multi:${Object.keys(t)}`) {
41
- const n = Object.entries(t).reduce((a, [o, s]) => U(a, o, Ue(a[o], s)), M);
42
- le(n, e);
40
+ function da(e, t = `multi:${Object.keys(e)}`) {
41
+ const n = Object.entries(e).reduce((a, [o, s]) => B(a, o, Ve(a[o], s)), M);
42
+ pe(n, t);
43
43
  }
44
- function Sn(t, e, n) {
45
- const a = U(M.scopes?.[t], e, Ue(M.scopes?.[t]?.[e], n)), o = U(M.scopes, t, Object.keys(a).length ? a : null);
46
- le(U(M, "scopes", Object.keys(o).length ? o : null), `${t}|${e}:${Object.keys(n)}`);
44
+ function Mn(e, t, n) {
45
+ const a = B(M.scopes?.[e], t, Ve(M.scopes?.[e]?.[t], n)), o = B(M.scopes, e, Object.keys(a).length ? a : null);
46
+ pe(B(M, "scopes", Object.keys(o).length ? o : null), `${e}|${t}:${Object.keys(n)}`);
47
47
  }
48
- function ra(t, e) {
49
- if (e) return Sn(t, e, Object.fromEntries(
50
- Object.keys(M.scopes?.[t]?.[e] || {}).map((a) => [a, null])
48
+ function ca(e, t) {
49
+ if (t) return Mn(e, t, Object.fromEntries(
50
+ Object.keys(M.scopes?.[e]?.[t] || {}).map((a) => [a, null])
51
51
  ));
52
- const n = U(M.scopes, t, null);
53
- le(U(M, "scopes", Object.keys(n).length ? n : null));
52
+ const n = B(M.scopes, e, null);
53
+ pe(B(M, "scopes", Object.keys(n).length ? n : null));
54
54
  }
55
- function sa(t, e) {
56
- const n = M.scopes?.[t];
57
- if (!n || t === e) return;
58
- let a = { ...M.scopes[e] };
55
+ function pa(e, t) {
56
+ const n = M.scopes?.[e];
57
+ if (!n || e === t) return;
58
+ let a = { ...M.scopes[t] };
59
59
  Object.entries(n).forEach(([s, r]) => {
60
- a = U(a, s, Ue(a[s], r));
60
+ a = B(a, s, Ve(a[s], r));
61
61
  });
62
- const o = U(U(M.scopes, t, null), e, a);
63
- le(U(M, "scopes", o));
62
+ const o = B(B(M.scopes, e, null), t, a);
63
+ pe(B(M, "scopes", o));
64
64
  }
65
- function $n() {
66
- le({});
65
+ function Tn() {
66
+ pe({});
67
67
  }
68
- function En() {
69
- J.length && (ve.push(M), M = J.pop(), De = null, kt());
68
+ function An() {
69
+ Q.length && (ke.push(M), M = Q.pop(), qe = null, Et());
70
70
  }
71
- function Cn() {
72
- ve.length && (J.push(M), M = ve.pop(), De = null, kt());
71
+ function Ln() {
72
+ ke.length && (Q.push(M), M = ke.pop(), qe = null, Et());
73
73
  }
74
- const ia = () => J.length > 0, la = () => ve.length > 0;
75
- function Mn(t) {
76
- return ut.add(t), () => ut.delete(t);
74
+ const ua = () => Q.length > 0, ha = () => ke.length > 0;
75
+ function Pn(e) {
76
+ return gt.add(e), () => gt.delete(e);
77
77
  }
78
- const da = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
78
+ const fa = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
79
79
  __proto__: null,
80
- canRedo: la,
81
- canUndo: ia,
82
- getState: ht,
83
- moveScope: sa,
84
- onChange: Mn,
85
- redo: Cn,
86
- removeScope: ra,
87
- resetState: $n,
88
- setScope: Sn,
89
- setSection: aa,
90
- setSections: oa,
91
- undo: En
92
- }, Symbol.toStringTag, { value: "Module" })), Tn = [];
93
- let ft = [], St = {}, R = null, se = !1, An = {};
94
- function ca(t) {
95
- typeof t == "function" && Tn.push(t);
96
- }
97
- const tn = (t) => Object.assign({}, ...Tn.map((e) => e(t) || {})), gt = (t) => /^(\.[\w-]+|\[data-twd="[^"]+"\])$/.test(t), pa = (t) => {
80
+ canRedo: ha,
81
+ canUndo: ua,
82
+ getState: mt,
83
+ moveScope: pa,
84
+ onChange: Pn,
85
+ redo: Ln,
86
+ removeScope: ca,
87
+ resetState: Tn,
88
+ setScope: Mn,
89
+ setSection: la,
90
+ setSections: da,
91
+ undo: An
92
+ }, Symbol.toStringTag, { value: "Module" })), On = [];
93
+ let bt = [], Ct = {}, R = null, de = !1, Fn = {};
94
+ function ga(e) {
95
+ typeof e == "function" && On.push(e);
96
+ }
97
+ const on = (e) => Object.assign({}, ...On.map((t) => t(e) || {})), xt = (e) => /^(\.[\w-]+|\[data-twd="[^"]+"\])$/.test(e), ma = (e) => {
98
98
  try {
99
- return document.querySelector(t), !0;
99
+ return document.querySelector(e), !0;
100
100
  } catch {
101
101
  return !1;
102
102
  }
103
103
  };
104
- function ua() {
104
+ function ba() {
105
105
  return (!R || !R.isConnected) && (R = document.createElement("style"), R.id = "twiddle-scoped", document.head.appendChild(R)), R;
106
106
  }
107
- function Ln() {
108
- const t = document.documentElement;
109
- ft.forEach((e) => t.style.removeProperty(e)), ft = [], St = {};
110
- }
111
- function mt(t) {
112
- if (An = t, se) return;
107
+ function Nn() {
113
108
  const e = document.documentElement;
114
- Ln();
115
- const n = tn(t), a = Object.entries(t.scopes || {}).filter(([s]) => pa(s)).sort(([s], [r]) => gt(r) - gt(s)).map(([s, r]) => [s, tn(r)]);
116
- Object.entries(n).forEach(([s, r]) => e.style.setProperty(s, r)), ft = Object.keys(n), St = n;
109
+ bt.forEach((t) => e.style.removeProperty(t)), bt = [], Ct = {};
110
+ }
111
+ function wt(e) {
112
+ if (Fn = e, de) return;
113
+ const t = document.documentElement;
114
+ Nn();
115
+ const n = on(e), a = Object.entries(e.scopes || {}).filter(([s]) => ma(s)).sort(([s], [r]) => xt(r) - xt(s)).map(([s, r]) => [s, on(r)]);
116
+ Object.entries(n).forEach(([s, r]) => t.style.setProperty(s, r)), bt = Object.keys(n), Ct = n;
117
117
  const o = a.filter(([, s]) => Object.keys(s).length).map(([s, r]) => `${s} {
118
118
  ${Object.entries(r).map(([i, l]) => ` ${i}: ${l} !important;`).join(`
119
119
  `)}
120
120
  }`).join(`
121
121
  `);
122
- (o || R) && (ua().textContent = o);
122
+ (o || R) && (ba().textContent = o);
123
123
  }
124
- function On(t) {
125
- const e = document.documentElement, n = se, a = { ...St };
126
- Object.keys(a).forEach((o) => e.style.removeProperty(o)), R && (R.disabled = !0);
124
+ function jn(e) {
125
+ const t = document.documentElement, n = de, a = { ...Ct };
126
+ Object.keys(a).forEach((o) => t.style.removeProperty(o)), R && (R.disabled = !0);
127
127
  try {
128
- return t();
128
+ return e();
129
129
  } finally {
130
- n || (Object.entries(a).forEach(([o, s]) => e.style.setProperty(o, s)), R && (R.disabled = !1));
130
+ n || (Object.entries(a).forEach(([o, s]) => t.style.setProperty(o, s)), R && (R.disabled = !1));
131
131
  }
132
132
  }
133
- function ha(t, e = document.documentElement) {
134
- return On(() => {
135
- const n = getComputedStyle(e);
136
- return Object.fromEntries(t.map((a) => [a, n.getPropertyValue(a).trim()]));
133
+ function xa(e, t = document.documentElement) {
134
+ return jn(() => {
135
+ const n = getComputedStyle(t);
136
+ return Object.fromEntries(e.map((a) => [a, n.getPropertyValue(a).trim()]));
137
137
  });
138
138
  }
139
- function fa() {
140
- se || (Ln(), R && (R.disabled = !0), se = !0);
139
+ function wa() {
140
+ de || (Nn(), R && (R.disabled = !0), de = !0);
141
141
  }
142
- function ga() {
143
- se && (se = !1, R && (R.disabled = !1), mt(An));
142
+ function ya() {
143
+ de && (de = !1, R && (R.disabled = !1), wt(Fn));
144
144
  }
145
- const ma = `
145
+ const va = `
146
146
  :host { all: initial; } /* block fonts/colours inherited from the page */
147
147
  * { box-sizing: border-box; }
148
148
 
@@ -160,6 +160,10 @@ const ma = `
160
160
  position: fixed;
161
161
  right: 16px;
162
162
  bottom: 16px;
163
+ /* Where it sits is set inline by position.js (drag / nudge, per site);
164
+ --off-x / --off-y = distance from the two nearest edges. */
165
+ --off-x: 16px;
166
+ --off-y: 16px;
163
167
  z-index: 2147483647;
164
168
  font: 13px/1.4 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
165
169
  color: var(--p-fg);
@@ -202,6 +206,13 @@ const ma = `
202
206
  padding 6 + half a tab (~49px) − half the launcher (22). */
203
207
  .launcher { transition: margin-bottom .2s cubic-bezier(0.2, 0.8, 0.2, 1); }
204
208
  .wrap.is-open .launcher { margin-bottom: 10px; }
209
+ /* Left corners: the panel opens to the right of the launcher. Top corners: tops aligned. */
210
+ .wrap.at-left { flex-direction: row-reverse; }
211
+ .wrap.at-top { align-items: flex-start; }
212
+ .wrap.at-top.is-open .launcher { margin-bottom: 0; }
213
+ .launcher { touch-action: none; }
214
+ .wrap.dragging .launcher { cursor: grabbing; }
215
+ .wrap.dragging .panel { pointer-events: none; }
205
216
  @media (prefers-reduced-motion: reduce) { .launcher { transition: none; } }
206
217
  .mark { display: block; overflow: visible; }
207
218
  .mark-disc { fill: #16161a; }
@@ -219,12 +230,12 @@ const ma = `
219
230
  /* Panel */
220
231
  .panel {
221
232
  width: 360px; /* tabbed layout (Figma 254:323); was 300 */
222
- /* 86px = 16 + 16 margins + 44 launcher + 10 gap */
223
- max-width: calc(100vw - 86px);
233
+ /* 70px = 16 room on the far side + 44 launcher + 10 gap */
234
+ max-width: calc(100vw - var(--off-x) - 70px);
224
235
  /* As tall as its content; scrolls only when the window is shorter.
225
236
  32px = 16 margin below + 16 room at the top. */
226
- max-height: calc(100vh - 32px);
227
- max-height: calc(100dvh - 32px);
237
+ max-height: calc(100vh - var(--off-y) - 16px);
238
+ max-height: calc(100dvh - var(--off-y) - 16px);
228
239
  background: var(--p-bg);
229
240
  border: 1px solid var(--p-line);
230
241
  border-radius: 14px;
@@ -451,9 +462,7 @@ const ma = `
451
462
  padding: 1px 4px;
452
463
  }
453
464
 
454
- /* Closed: beside the launcher (left of it, centred on it). Open or minimised:
455
- the panel takes that spot, so the toast floats just above the tab bar
456
- (63px tall), inside the panel's right edge. */
465
+ /* Closed: beside the launcher (on the panel's side of it, centred on it). */
457
466
  .toast {
458
467
  position: absolute; bottom: 22px; right: 54px; transform: translateY(50%);
459
468
  background: var(--p-accent); color: var(--p-on-accent);
@@ -462,7 +471,13 @@ const ma = `
462
471
  opacity: 0; transition: opacity .15s ease; pointer-events: none;
463
472
  }
464
473
  .toast.show { opacity: 1; }
465
- .wrap.is-open .toast { bottom: 72px; right: 62px; transform: none; z-index: 3; }
474
+ .wrap.at-left .toast { right: auto; left: 54px; }
475
+ .wrap.at-top .toast { bottom: auto; top: 22px; transform: translateY(-50%); }
476
+ /* Open or minimised: just above the panel, right-aligned with it, so it
477
+ never covers a row (Ravi, 2026-10-16; Figma 269:1037). Top corners: below it. */
478
+ .wrap.is-open .toast { bottom: calc(100% + 8px); right: 54px; left: auto; top: auto; transform: none; z-index: 3; }
479
+ .wrap.is-open.at-left .toast { right: auto; left: 54px; }
480
+ .wrap.is-open.at-top .toast { bottom: auto; top: calc(100% + 8px); }
466
481
 
467
482
  /* ---------- Proposals below: not yet designed in Figma ---------- */
468
483
 
@@ -886,219 +901,288 @@ const ma = `
886
901
  .summary-swatch { width: 14px; height: 14px; border-radius: 4px; flex: none; }
887
902
  .summary-swatch[hidden] { display: none; }
888
903
  .summary-row .chev { display: grid; color: var(--p-muted); }
889
- `, O = (t, e, n) => `<svg width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${e}" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${n}</svg>`, A = {
890
- dial: O(20, 1.8, '<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),
891
- link: O(15, 2, '<path d="M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1 1"/><path d="M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1-1"/>'),
892
- reset: O(15, 2, '<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/>'),
893
- close: O(15, 2, '<path d="M18 6L6 18M6 6l12 12"/>'),
894
- chevron: O(12, 2.4, '<path d="M9 6l6 6-6 6"/>'),
904
+ `, P = (e, t, n) => `<svg width="${e}" height="${e}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${t}" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${n}</svg>`, A = {
905
+ dial: P(20, 1.8, '<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),
906
+ link: P(15, 2, '<path d="M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1 1"/><path d="M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1-1"/>'),
907
+ reset: P(15, 2, '<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/>'),
908
+ close: P(15, 2, '<path d="M18 6L6 18M6 6l12 12"/>'),
909
+ chevron: P(12, 2.4, '<path d="M9 6l6 6-6 6"/>'),
895
910
  // Proposals: not yet in the Figma Icon/* set.
896
- pick: O(15, 2, '<circle cx="12" cy="12" r="7"/><path d="M12 2v4M12 18v4M2 12h4M18 12h4"/>'),
897
- compare: O(15, 2, '<circle cx="12" cy="12" r="9"/><path d="M12 3v18" /><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/>'),
898
- undo: O(15, 2, '<path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/>'),
899
- redo: O(15, 2, '<path d="M15 14l5-5-5-5"/><path d="M20 9H9a5 5 0 0 0 0 10h3"/>'),
900
- back: O(15, 2, '<path d="M15 18l-6-6 6-6"/>'),
901
- down: O(12, 2.4, '<path d="M6 9l6 6 6-6"/>'),
902
- minimise: O(15, 2, '<path d="M5 12h14"/>'),
903
- copy: O(13, 2, '<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/>'),
904
- warn: O(13, 2, '<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>'),
911
+ pick: P(15, 2, '<circle cx="12" cy="12" r="7"/><path d="M12 2v4M12 18v4M2 12h4M18 12h4"/>'),
912
+ compare: P(15, 2, '<circle cx="12" cy="12" r="9"/><path d="M12 3v18" /><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/>'),
913
+ undo: P(15, 2, '<path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/>'),
914
+ redo: P(15, 2, '<path d="M15 14l5-5-5-5"/><path d="M20 9H9a5 5 0 0 0 0 10h3"/>'),
915
+ back: P(15, 2, '<path d="M15 18l-6-6 6-6"/>'),
916
+ down: P(12, 2.4, '<path d="M6 9l6 6 6-6"/>'),
917
+ minimise: P(15, 2, '<path d="M5 12h14"/>'),
918
+ copy: P(13, 2, '<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/>'),
919
+ warn: P(13, 2, '<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>'),
905
920
  // Launcher: the Panel product mark (Twiddle brand; Figma Logo page › Panel mark; also site/favicon.svg).
906
921
  // A switch knocked out of a disc; knob + two-dot trail. Classes let the Toggle animation move them.
907
922
  panelMark: '<svg class="mark" width="44" height="44" viewBox="0 0 120 120" aria-hidden="true"><path class="mark-disc" fill-rule="evenodd" clip-rule="evenodd" d="M60 120C93.1371 120 120 93.1371 120 60C120 26.8629 93.1371 0 60 0C26.8629 0 0 26.8629 0 60C0 93.1371 26.8629 120 60 120ZM86 76C86 90.3594 74.3594 102 60 102C45.6406 102 34 90.3594 34 76V44C34 29.6406 45.6406 18 60 18C74.3594 18 86 29.6406 86 44V76ZM60 22C72.1503 22 82 31.8497 82 44V76C82 88.1503 72.1503 98 60 98C47.8497 98 38 88.1503 38 76V44C38 31.8497 47.8497 22 60 22Z"/><circle class="mark-t2" cx="60" cy="80.46" r="4.28"/><circle class="mark-t1" cx="60" cy="66.04" r="7.14"/><circle class="mark-knob" cx="60" cy="44" r="11.9"/></svg>',
908
923
  // Tab bar (Figma: Panel — tabbed layout (proposal), Icon/Tab * components)
909
- tabOverview: O(18, 1.8, '<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),
910
- tabColour: O(18, 2, '<path d="M12 3c-3.5 4.5-6 7.8-6 11a6 6 0 0 0 12 0c0-3.2-2.5-6.5-6-11z"/>'),
911
- tabType: O(18, 2, '<path d="M5 7V5h14v2"/><path d="M12 5v14"/><path d="M9 19h6"/>'),
912
- tabSpacing: O(18, 2, '<path d="M4 5v14M20 5v14"/><path d="M8 12h8"/><path d="M10 9l-3 3 3 3M14 9l3 3-3 3"/>'),
913
- tabShape: O(18, 2, '<path d="M20 4h-9a7 7 0 0 0-7 7v9"/><path d="M20 10h-5a5 5 0 0 0-5 5v5"/>'),
914
- tabShadows: O(18, 2, '<rect x="4" y="4" width="12" height="12" rx="2"/><path d="M20 8v10a2 2 0 0 1-2 2H8"/>'),
915
- sliders: O(15, 2, '<path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/>')
924
+ tabOverview: P(18, 1.8, '<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),
925
+ tabColour: P(18, 2, '<path d="M12 3c-3.5 4.5-6 7.8-6 11a6 6 0 0 0 12 0c0-3.2-2.5-6.5-6-11z"/>'),
926
+ tabType: P(18, 2, '<path d="M5 7V5h14v2"/><path d="M12 5v14"/><path d="M9 19h6"/>'),
927
+ tabSpacing: P(18, 2, '<path d="M4 5v14M20 5v14"/><path d="M8 12h8"/><path d="M10 9l-3 3 3 3M14 9l3 3-3 3"/>'),
928
+ tabShape: P(18, 2, '<path d="M20 4h-9a7 7 0 0 0-7 7v9"/><path d="M20 10h-5a5 5 0 0 0-5 5v5"/>'),
929
+ tabShadows: P(18, 2, '<rect x="4" y="4" width="12" height="12" rx="2"/><path d="M20 8v10a2 2 0 0 1-2 2H8"/>'),
930
+ sliders: P(15, 2, '<path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/>')
916
931
  // Figma: Icon/Sliders (proposal)
917
- }, Pn = "twiddle:";
918
- function ne(t) {
932
+ }, Rn = "twiddle:";
933
+ function Z(e) {
919
934
  try {
920
- return localStorage.getItem(Pn + t);
935
+ return localStorage.getItem(Rn + e);
921
936
  } catch {
922
937
  return null;
923
938
  }
924
939
  }
925
- function ge(t, e) {
940
+ function oe(e, t) {
926
941
  try {
927
- localStorage.setItem(Pn + t, e);
942
+ localStorage.setItem(Rn + e, t);
928
943
  } catch {
929
944
  }
930
945
  }
931
- function ie({ label: t, options: e, onSelect: n }) {
946
+ const re = 44, ae = 8, ka = 4, zn = { corner: "br", x: 16, y: 16 };
947
+ function Sa() {
948
+ try {
949
+ const e = JSON.parse(Z("position"));
950
+ if (e && /^[tb][lr]$/.test(e.corner) && isFinite(e.x) && isFinite(e.y)) return e;
951
+ } catch {
952
+ }
953
+ return { ...zn };
954
+ }
955
+ function rn(e) {
956
+ const t = Math.max(ae, innerWidth - re - ae), n = Math.max(ae, innerHeight - re - ae);
957
+ return { corner: e.corner, x: Math.round(Math.min(Math.max(e.x, ae), t)), y: Math.round(Math.min(Math.max(e.y, ae), n)) };
958
+ }
959
+ function $a({ wrapEl: e, launcherEl: t }) {
960
+ let n = Sa();
961
+ function a() {
962
+ const d = rn(n), p = d.corner[1] === "l", u = d.corner[0] === "t";
963
+ Object.assign(e.style, {
964
+ left: p ? `${d.x}px` : "auto",
965
+ right: p ? "auto" : `${d.x}px`,
966
+ top: u ? `${d.y}px` : "auto",
967
+ bottom: u ? "auto" : `${d.y}px`
968
+ }), e.style.setProperty("--off-x", `${d.x}px`), e.style.setProperty("--off-y", `${d.y}px`), e.classList.toggle("at-left", p), e.classList.toggle("at-top", u);
969
+ }
970
+ function o(d, p = !0) {
971
+ n = rn(d), a(), p && oe("position", JSON.stringify(n));
972
+ }
973
+ function s(d, p) {
974
+ const u = d + re / 2 < innerWidth / 2, v = p + re / 2 < innerHeight / 2, f = !v && e.classList.contains("is-open") ? 10 : 0;
975
+ return {
976
+ corner: (v ? "t" : "b") + (u ? "l" : "r"),
977
+ x: u ? d : innerWidth - d - re,
978
+ y: v ? p : innerHeight - p - re - f
979
+ };
980
+ }
981
+ let r = null, i = !1;
982
+ t.addEventListener("pointerdown", (d) => {
983
+ if (d.button !== 0) return;
984
+ const p = t.getBoundingClientRect();
985
+ r = { id: d.pointerId, sx: d.clientX, sy: d.clientY, dx: d.clientX - p.left, dy: d.clientY - p.top, moving: !1 };
986
+ }), t.addEventListener("pointermove", (d) => {
987
+ if (!(!r || d.pointerId !== r.id)) {
988
+ if (!r.moving) {
989
+ if (Math.hypot(d.clientX - r.sx, d.clientY - r.sy) < ka) return;
990
+ r.moving = !0, t.setPointerCapture(d.pointerId), e.classList.add("dragging");
991
+ }
992
+ o(s(d.clientX - r.dx, d.clientY - r.dy), !1);
993
+ }
994
+ });
995
+ const l = (d) => {
996
+ !r || d.pointerId !== r.id || (r.moving && (i = !0, e.classList.remove("dragging"), o(n)), r = null);
997
+ };
998
+ return t.addEventListener("pointerup", l), t.addEventListener("pointercancel", l), t.addEventListener("keydown", (d) => {
999
+ const p = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] }[d.key];
1000
+ if (!p || d.altKey || d.metaKey || d.ctrlKey) return;
1001
+ d.preventDefault();
1002
+ const u = d.shiftKey ? 10 : 1, v = n.corner[1] === "l" ? 1 : -1, f = n.corner[0] === "t" ? 1 : -1;
1003
+ o({ corner: n.corner, x: n.x + p[0] * u * v, y: n.y + p[1] * u * f });
1004
+ }), window.addEventListener("resize", a), a(), {
1005
+ /** Call from the launcher's click handler: true = ignore this click (it ended a drag). */
1006
+ consumeClick() {
1007
+ const d = i;
1008
+ return i = !1, d;
1009
+ },
1010
+ reset() {
1011
+ o({ ...zn });
1012
+ }
1013
+ };
1014
+ }
1015
+ function ce({ label: e, options: t, onSelect: n }) {
932
1016
  const a = document.createElement("div");
933
- a.className = "seg", a.setAttribute("role", "radiogroup"), a.setAttribute("aria-label", t);
934
- const o = e.map((l) => {
935
- const p = document.createElement("button");
936
- return p.type = "button", p.setAttribute("role", "radio"), p.dataset.value = l.value, p.textContent = l.label, l.title && (p.title = l.title), p.addEventListener("click", () => i(l.value)), p;
1017
+ a.className = "seg", a.setAttribute("role", "radiogroup"), a.setAttribute("aria-label", e);
1018
+ const o = t.map((l) => {
1019
+ const d = document.createElement("button");
1020
+ return d.type = "button", d.setAttribute("role", "radio"), d.dataset.value = l.value, d.textContent = l.label, l.title && (d.title = l.title), d.addEventListener("click", () => i(l.value)), d;
937
1021
  });
938
1022
  a.append(...o);
939
1023
  let s = null;
940
1024
  function r(l) {
941
- s = l, o.forEach((c) => c.setAttribute("aria-checked", String(c.dataset.value === l)));
942
- const p = Math.max(0, o.findIndex((c) => c.dataset.value === l));
943
- o.forEach((c, h) => {
944
- c.tabIndex = h === p ? 0 : -1;
1025
+ s = l, o.forEach((p) => p.setAttribute("aria-checked", String(p.dataset.value === l)));
1026
+ const d = Math.max(0, o.findIndex((p) => p.dataset.value === l));
1027
+ o.forEach((p, u) => {
1028
+ p.tabIndex = u === d ? 0 : -1;
945
1029
  });
946
1030
  }
947
- function i(l, p) {
948
- l !== s && (r(l), n(l)), p && o.find((c) => c.dataset.value === l).focus();
1031
+ function i(l, d) {
1032
+ l !== s && (r(l), n(l)), d && o.find((p) => p.dataset.value === l).focus();
949
1033
  }
950
1034
  return a.addEventListener("keydown", (l) => {
951
- const p = o.indexOf(l.target);
952
- if (p < 0) return;
953
- const c = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[l.key];
954
- let h;
955
- if (c) h = (p + c + o.length) % o.length;
956
- else if (l.key === "Home") h = 0;
957
- else if (l.key === "End") h = o.length - 1;
1035
+ const d = o.indexOf(l.target);
1036
+ if (d < 0) return;
1037
+ const p = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[l.key];
1038
+ let u;
1039
+ if (p) u = (d + p + o.length) % o.length;
1040
+ else if (l.key === "Home") u = 0;
1041
+ else if (l.key === "End") u = o.length - 1;
958
1042
  else return;
959
- l.preventDefault(), i(o[h].dataset.value, !0);
1043
+ l.preventDefault(), i(o[u].dataset.value, !0);
960
1044
  }), r(null), { el: a, setValue: r };
961
1045
  }
962
- const Fn = /var\(\s*(--twd-[\w-]+)/g, ba = /::?[\w-]+(\([^)]*\))?/g;
963
- function* qe(t) {
964
- for (const e of t)
965
- e.selectorText != null && (yield e), e.cssRules && (yield* qe(e.cssRules));
1046
+ const In = /var\(\s*(--twd-[\w-]+)/g, Ea = /::?[\w-]+(\([^)]*\))?/g;
1047
+ function* _e(e) {
1048
+ for (const t of e)
1049
+ t.selectorText != null && (yield t), t.cssRules && (yield* _e(t.cssRules));
966
1050
  }
967
- function xa() {
968
- const t = [];
969
- for (const e of document.styleSheets) {
970
- if (e.ownerNode?.id === "twiddle-scoped") continue;
1051
+ function Ca() {
1052
+ const e = [];
1053
+ for (const t of document.styleSheets) {
1054
+ if (t.ownerNode?.id === "twiddle-scoped") continue;
971
1055
  let n;
972
1056
  try {
973
- n = e.cssRules;
1057
+ n = t.cssRules;
974
1058
  } catch {
975
1059
  continue;
976
1060
  }
977
- for (const a of qe(n)) {
978
- const o = [...a.style.cssText.matchAll(Fn)].map((s) => s[1]);
979
- o.length && t.push({ selectors: a.selectorText.split(","), vars: o });
1061
+ for (const a of _e(n)) {
1062
+ const o = [...a.style.cssText.matchAll(In)].map((s) => s[1]);
1063
+ o.length && e.push({ selectors: a.selectorText.split(","), vars: o });
980
1064
  }
981
1065
  }
982
- return t;
1066
+ return e;
983
1067
  }
984
- function wa(t, e) {
985
- const n = e.replace(ba, "").trim() || "*";
1068
+ function Ma(e, t) {
1069
+ const n = t.replace(Ea, "").trim() || "*";
986
1070
  try {
987
- return t.matches(n);
1071
+ return e.matches(n);
988
1072
  } catch {
989
1073
  return !1;
990
1074
  }
991
1075
  }
992
- function Nn(t) {
993
- const e = /* @__PURE__ */ new Set(), n = [];
994
- return xa().forEach(({ selectors: a, vars: o }) => {
995
- const s = a.find((r) => wa(t, r));
996
- s && (o.forEach((r) => e.add(r)), n.push(s.trim()));
997
- }), [...(t.getAttribute("style") || "").matchAll(Fn)].forEach((a) => e.add(a[1])), { names: e, selectors: n };
1076
+ function Dn(e) {
1077
+ const t = /* @__PURE__ */ new Set(), n = [];
1078
+ return Ca().forEach(({ selectors: a, vars: o }) => {
1079
+ const s = a.find((r) => Ma(e, r));
1080
+ s && (o.forEach((r) => t.add(r)), n.push(s.trim()));
1081
+ }), [...(e.getAttribute("style") || "").matchAll(In)].forEach((a) => t.add(a[1])), { names: t, selectors: n };
998
1082
  }
999
- const bt = (t) => window.CSS && CSS.escape ? CSS.escape(t) : t;
1000
- function va(t) {
1001
- const e = [];
1002
- let n = t;
1083
+ const yt = (e) => window.CSS && CSS.escape ? CSS.escape(e) : e;
1084
+ function Ta(e) {
1085
+ const t = [];
1086
+ let n = e;
1003
1087
  for (; n && n.nodeType === 1 && n !== document.body && n !== document.documentElement; ) {
1004
- if (n.id && document.querySelectorAll(`#${bt(n.id)}`).length === 1)
1005
- return e.unshift(`#${bt(n.id)}`), e.join(" > ");
1088
+ if (n.id && document.querySelectorAll(`#${yt(n.id)}`).length === 1)
1089
+ return t.unshift(`#${yt(n.id)}`), t.join(" > ");
1006
1090
  const a = n.localName, o = [...n.parentElement.children].filter((s) => s.localName === a);
1007
- e.unshift(o.length > 1 ? `${a}:nth-of-type(${o.indexOf(n) + 1})` : a), n = n.parentElement;
1091
+ t.unshift(o.length > 1 ? `${a}:nth-of-type(${o.indexOf(n) + 1})` : a), n = n.parentElement;
1008
1092
  }
1009
- return ["body", ...e].join(" > ");
1093
+ return ["body", ...t].join(" > ");
1010
1094
  }
1011
- function ya(t, e = Nn(t).selectors) {
1012
- const n = t.getAttribute("data-twd");
1095
+ function Aa(e, t = Dn(e).selectors) {
1096
+ const n = e.getAttribute("data-twd");
1013
1097
  if (n) return `[data-twd="${n.replace(/"/g, "")}"]`;
1014
- const a = [...t.classList], s = a.find((r) => e.some((i) => new RegExp(`\\.${r.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(i))) || a[0];
1015
- return s ? `.${bt(s)}` : null;
1098
+ const a = [...e.classList], s = a.find((r) => t.some((i) => new RegExp(`\\.${r.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(i))) || a[0];
1099
+ return s ? `.${yt(s)}` : null;
1016
1100
  }
1017
- function ka(t) {
1018
- const e = Nn(t), n = ya(t, e.selectors), a = (t.getAttribute("aria-label") || t.placeholder || t.textContent || "").trim().replace(/\s+/g, " ");
1101
+ function La(e) {
1102
+ const t = Dn(e), n = Aa(e, t.selectors), a = (e.getAttribute("aria-label") || e.placeholder || e.textContent || "").trim().replace(/\s+/g, " ");
1019
1103
  return {
1020
- el: t,
1021
- tag: t.localName,
1022
- classes: [...t.classList],
1104
+ el: e,
1105
+ tag: e.localName,
1106
+ classes: [...e.classList],
1023
1107
  text: a.length > 40 ? `${a.slice(0, 40)}…` : a,
1024
- tokens: e.names,
1025
- elementSelector: va(t),
1108
+ tokens: t.names,
1109
+ elementSelector: Ta(e),
1026
1110
  classSelector: n,
1027
1111
  classCount: n ? document.querySelectorAll(n).length : 0
1028
1112
  };
1029
1113
  }
1030
- const xt = (t) => t.localName + [...t.classList].map((e) => `.${e}`).join(""), Sa = { radius: "px", intensity: "%", base: "px" }, jn = (t) => t.charAt(0).toUpperCase() + t.slice(1), $a = (t, e) => typeof e == "number" || /^\d+$/.test(e) ? `${e}${Sa[t] || ""}` : jn(String(e));
1031
- function nn(t, e, n) {
1032
- const a = On(() => t.tokens({ [t.id]: e }) || {}), o = Object.keys(a);
1114
+ const vt = (e) => e.localName + [...e.classList].map((t) => `.${t}`).join(""), Pa = { radius: "px", intensity: "%", base: "px" }, Un = (e) => e.charAt(0).toUpperCase() + e.slice(1), Oa = (e, t) => typeof t == "number" || /^\d+$/.test(t) ? `${t}${Pa[e] || ""}` : Un(String(t));
1115
+ function sn(e, t, n) {
1116
+ const a = jn(() => e.tokens({ [e.id]: t }) || {}), o = Object.keys(a);
1033
1117
  let s = {};
1034
1118
  if (o.length) {
1035
1119
  const r = n.selector ? document.querySelector(n.selector) : void 0;
1036
- s = ha(o, r || void 0);
1120
+ s = xa(o, r || void 0);
1037
1121
  }
1038
1122
  return {
1039
1123
  ...n,
1040
- sectionId: t.id,
1041
- title: t.title,
1042
- settings: Object.entries(e).map(([r, i]) => ({ key: r, label: jn(r), value: $a(r, i), ...t.describe?.(r, i) || {} })),
1124
+ sectionId: e.id,
1125
+ title: e.title,
1126
+ settings: Object.entries(t).map(([r, i]) => ({ key: r, label: Un(r), value: Oa(r, i), ...e.describe?.(r, i) || {} })),
1043
1127
  tokens: o.map((r) => ({ name: r, from: s[r] || "", to: a[r] }))
1044
1128
  };
1045
1129
  }
1046
- function an(t, e) {
1130
+ function ln(e, t) {
1047
1131
  const n = [];
1048
- return e.forEach((a) => {
1049
- t[a.id] && n.push(nn(a, t[a.id], { kind: "global", selector: null }));
1050
- }), Object.entries(t.scopes || {}).forEach(([a, o]) => {
1051
- const s = gt(a) ? "class" : "element";
1052
- e.forEach((r) => {
1053
- o[r.id] && n.push(nn(r, o[r.id], { kind: s, selector: a }));
1132
+ return t.forEach((a) => {
1133
+ e[a.id] && n.push(sn(a, e[a.id], { kind: "global", selector: null }));
1134
+ }), Object.entries(e.scopes || {}).forEach(([a, o]) => {
1135
+ const s = xt(a) ? "class" : "element";
1136
+ t.forEach((r) => {
1137
+ o[r.id] && n.push(sn(r, o[r.id], { kind: s, selector: a }));
1054
1138
  });
1055
1139
  }), n;
1056
1140
  }
1057
- function Ea(t) {
1058
- const e = (o) => Object.values(o || {}).reduce((s, r) => s + Object.keys(r || {}).length, 0), { scopes: n, ...a } = t;
1059
- return e(a) + Object.values(n || {}).reduce((o, s) => o + e(s), 0);
1141
+ function Fa(e) {
1142
+ const t = (o) => Object.values(o || {}).reduce((s, r) => s + Object.keys(r || {}).length, 0), { scopes: n, ...a } = e;
1143
+ return t(a) + Object.values(n || {}).reduce((o, s) => o + t(s), 0);
1060
1144
  }
1061
- const re = (t) => `\`${t}\``, Xe = (t) => t.map((e) => ` - ${re(e.name)}: ${e.from ? `${re(e.from)} → ` : ""}${re(e.to)}`), Je = (t) => `${t.title} › ${t.settings.map((e) => `${e.label}: ${e.value}`).join(", ")}`;
1062
- function Ca(t) {
1063
- let e = null;
1145
+ const le = (e) => `\`${e}\``, et = (e) => e.map((t) => ` - ${le(t.name)}: ${t.from ? `${le(t.from)} → ` : ""}${le(t.to)}`), tt = (e) => `${e.title} › ${e.settings.map((t) => `${t.label}: ${t.value}`).join(", ")}`;
1146
+ function Na(e) {
1147
+ let t = null;
1064
1148
  try {
1065
- e = document.querySelector(t);
1149
+ t = document.querySelector(e);
1066
1150
  } catch {
1067
1151
  }
1068
- if (!e) return "not found on the current page";
1069
- const n = (e.getAttribute("aria-label") || e.placeholder || e.textContent || "").trim().replace(/\s+/g, " ").slice(0, 60);
1070
- return `${re(xt(e))}${n ? ` with text “${n}”` : ""}`;
1152
+ if (!t) return "not found on the current page";
1153
+ const n = (t.getAttribute("aria-label") || t.placeholder || t.textContent || "").trim().replace(/\s+/g, " ").slice(0, 60);
1154
+ return `${le(vt(t))}${n ? ` with text “${n}”` : ""}`;
1071
1155
  }
1072
- function on(t, e) {
1156
+ function dn(e, t) {
1073
1157
  const n = /* @__PURE__ */ new Map();
1074
- return t.forEach((a) => {
1075
- const o = a[e];
1158
+ return e.forEach((a) => {
1159
+ const o = a[t];
1076
1160
  n.has(o) || n.set(o, []), n.get(o).push(a);
1077
1161
  }), [...n];
1078
1162
  }
1079
- function Ma(t, { link: e = location.href, warnings: n = [] } = {}) {
1080
- if (!t.length) return "";
1081
- const a = t.filter((i) => i.kind === "global"), o = t.filter((i) => i.kind === "class"), s = t.filter((i) => i.kind === "element"), r = [];
1163
+ function ja(e, { link: t = location.href, warnings: n = [] } = {}) {
1164
+ if (!e.length) return "";
1165
+ const a = e.filter((i) => i.kind === "global"), o = e.filter((i) => i.kind === "class"), s = e.filter((i) => i.kind === "element"), r = [];
1082
1166
  if (r.push(
1083
1167
  "# Apply design tweaks from Panel",
1084
1168
  "",
1085
1169
  "I explored design changes to this prototype with Panel (by Twiddle), a tweak panel that overrides the prototype's `--twd-*` CSS custom properties (design tokens) at runtime. Make these changes permanent in the source code.",
1086
1170
  "",
1087
- `Preview of the tweaked version: ${e}`
1171
+ `Preview of the tweaked version: ${t}`
1088
1172
  ), a.length && (r.push(
1089
1173
  "",
1090
1174
  "## 1. Global token changes",
1091
1175
  "",
1092
1176
  "Update the default value of each token where it is defined (usually a `:root` rule or a `tokens.css` / `twiddle-tokens.css` file). Change the definition, not the places that use it.",
1093
1177
  ""
1094
- ), a.forEach((i) => r.push(`- **${Je(i)}**`, ...Xe(i.tokens)))), o.length && (r.push(
1178
+ ), a.forEach((i) => r.push(`- **${tt(i)}**`, ...et(i.tokens)))), o.length && (r.push(
1095
1179
  "",
1096
1180
  `## ${a.length ? 2 : 1}. Component-wide changes`,
1097
1181
  "",
1098
1182
  "These apply to every element matching the selector. In the CSS rule for that component, redeclare the token, e.g. `.input { --twd-radius-control: 999px; }`. Don't replace the `var(--twd-…)` usages with fixed values.",
1099
1183
  ""
1100
- ), on(o, "selector").forEach(([i, l]) => {
1101
- r.push(`- ${re(i)} (${document.querySelectorAll(i).length} on this page)`), l.forEach((p) => r.push(` - **${Je(p)}**`, ...Xe(p.tokens).map((c) => ` ${c}`)));
1184
+ ), dn(o, "selector").forEach(([i, l]) => {
1185
+ r.push(`- ${le(i)} (${document.querySelectorAll(i).length} on this page)`), l.forEach((d) => r.push(` - **${tt(d)}**`, ...et(d.tokens).map((p) => ` ${p}`)));
1102
1186
  })), s.length) {
1103
1187
  const i = 1 + (a.length ? 1 : 0) + (o.length ? 1 : 0);
1104
1188
  r.push(
@@ -1107,8 +1191,8 @@ function Ma(t, { link: e = location.href, warnings: n = [] } = {}) {
1107
1191
  "",
1108
1192
  "These apply to one element only. Add a modifier class to that element (e.g. `input--pill`) and redeclare the token in a rule for that class. The selectors below are runtime paths to help you find the element; don't copy them into the stylesheet.",
1109
1193
  ""
1110
- ), on(s, "selector").forEach(([l, p]) => {
1111
- r.push(`- ${Ca(l)}, found at ${re(l)}`), p.forEach((c) => r.push(` - **${Je(c)}**`, ...Xe(c.tokens).map((h) => ` ${h}`)));
1194
+ ), dn(s, "selector").forEach(([l, d]) => {
1195
+ r.push(`- ${Na(l)}, found at ${le(l)}`), d.forEach((p) => r.push(` - **${tt(p)}**`, ...et(p.tokens).map((u) => ` ${u}`)));
1112
1196
  });
1113
1197
  }
1114
1198
  return n.length && r.push(
@@ -1129,85 +1213,85 @@ function Ma(t, { link: e = location.href, warnings: n = [] } = {}) {
1129
1213
  ), r.join(`
1130
1214
  `);
1131
1215
  }
1132
- const ze = 4.5, Ta = 3, Aa = [
1216
+ const Ue = 4.5, Ra = 3, za = [
1133
1217
  ["--twd-text", "--twd-bg", "Text on background"],
1134
1218
  ["--twd-text", "--twd-surface", "Text on surface"],
1135
1219
  ["--twd-text-muted", "--twd-surface", "Muted text on surface"],
1136
1220
  ["--twd-on-primary", "--twd-primary", "Text on brand"]
1137
1221
  ];
1138
1222
  let Y;
1139
- function $t(t) {
1140
- if (!t || (Y ||= Object.assign(document.createElement("canvas"), { width: 1, height: 1 }).getContext("2d", { willReadFrequently: !0 }), !Y)) return null;
1141
- Y.clearRect(0, 0, 1, 1), Y.fillStyle = "#000", Y.fillStyle = t, Y.fillRect(0, 0, 1, 1);
1142
- const [e, n, a, o] = Y.getImageData(0, 0, 1, 1).data;
1143
- return [e, n, a, o / 255];
1144
- }
1145
- function rn(t) {
1146
- const e = document.createElement("i");
1147
- e.style.cssText = `position:absolute;visibility:hidden;color:var(${t})`, document.documentElement.appendChild(e);
1148
- const n = getComputedStyle(e).color;
1149
- return e.remove(), $t(n);
1150
- }
1151
- const sn = ([t, e, n]) => {
1223
+ function Mt(e) {
1224
+ if (!e || (Y ||= Object.assign(document.createElement("canvas"), { width: 1, height: 1 }).getContext("2d", { willReadFrequently: !0 }), !Y)) return null;
1225
+ Y.clearRect(0, 0, 1, 1), Y.fillStyle = "#000", Y.fillStyle = e, Y.fillRect(0, 0, 1, 1);
1226
+ const [t, n, a, o] = Y.getImageData(0, 0, 1, 1).data;
1227
+ return [t, n, a, o / 255];
1228
+ }
1229
+ function cn(e) {
1230
+ const t = document.createElement("i");
1231
+ t.style.cssText = `position:absolute;visibility:hidden;color:var(${e})`, document.documentElement.appendChild(t);
1232
+ const n = getComputedStyle(t).color;
1233
+ return t.remove(), Mt(n);
1234
+ }
1235
+ const pn = ([e, t, n]) => {
1152
1236
  const a = (o) => (o /= 255, o <= 0.03928 ? o / 12.92 : ((o + 0.055) / 1.055) ** 2.4);
1153
- return 0.2126 * a(t) + 0.7152 * a(e) + 0.0722 * a(n);
1154
- }, Rn = (t, e) => t.slice(0, 3).map((n, a) => n * t[3] + e[a] * (1 - t[3])).concat(1);
1155
- function zn(t, e) {
1156
- const n = sn(t[3] < 1 ? Rn(t, e) : t), a = sn(e);
1237
+ return 0.2126 * a(e) + 0.7152 * a(t) + 0.0722 * a(n);
1238
+ }, Bn = (e, t) => e.slice(0, 3).map((n, a) => n * e[3] + t[a] * (1 - e[3])).concat(1);
1239
+ function qn(e, t) {
1240
+ const n = pn(e[3] < 1 ? Bn(e, t) : e), a = pn(t);
1157
1241
  return (Math.max(n, a) + 0.05) / (Math.min(n, a) + 0.05);
1158
1242
  }
1159
- const In = (t) => `${t.toFixed(1)}:1`;
1160
- function Qe() {
1161
- const t = [];
1162
- return Aa.forEach(([e, n, a]) => {
1163
- const o = rn(e), s = rn(n);
1243
+ const Hn = (e) => `${e.toFixed(1)}:1`;
1244
+ function nt() {
1245
+ const e = [];
1246
+ return za.forEach(([t, n, a]) => {
1247
+ const o = cn(t), s = cn(n);
1164
1248
  if (!o || !s || s[3] === 0) return;
1165
- const r = zn(o, s);
1166
- r < ze && t.push({ label: a, ratio: r, needed: ze, text: `${a}: ${In(r)} · AA needs ${ze}` });
1167
- }), t;
1249
+ const r = qn(o, s);
1250
+ r < Ue && e.push({ label: a, ratio: r, needed: Ue, text: `${a}: ${Hn(r)} · AA needs ${Ue}` });
1251
+ }), e;
1168
1252
  }
1169
- function La(t) {
1170
- const e = [];
1171
- for (let n = t; n && n.nodeType === 1; n = n.parentElement) {
1172
- const a = $t(getComputedStyle(n).backgroundColor);
1173
- if (a && a[3] > 0 && (e.push(a), a[3] >= 1))
1253
+ function Ia(e) {
1254
+ const t = [];
1255
+ for (let n = e; n && n.nodeType === 1; n = n.parentElement) {
1256
+ const a = Mt(getComputedStyle(n).backgroundColor);
1257
+ if (a && a[3] > 0 && (t.push(a), a[3] >= 1))
1174
1258
  break;
1175
1259
  }
1176
- return e.reduceRight((n, a) => Rn(a, n), [255, 255, 255, 1]);
1260
+ return t.reduceRight((n, a) => Bn(a, n), [255, 255, 255, 1]);
1177
1261
  }
1178
- function Oa(t) {
1179
- if (!t.textContent.trim() && !t.placeholder) return null;
1180
- const e = getComputedStyle(t), n = $t(e.color);
1262
+ function Da(e) {
1263
+ if (!e.textContent.trim() && !e.placeholder) return null;
1264
+ const t = getComputedStyle(e), n = Mt(t.color);
1181
1265
  if (!n) return null;
1182
- const a = parseFloat(e.fontSize), s = a >= 24 || a >= 18.66 && parseInt(e.fontWeight, 10) >= 700 ? Ta : ze, r = zn(n, La(t));
1183
- return r < s ? { label: "This element", ratio: r, needed: s, text: `This element’s text: ${In(r)} · AA needs ${s}` } : null;
1184
- }
1185
- const ln = "twiddle-panel", Pa = "0.7.1", dn = "https://panel.twiddle.in", Fa = "--twd-radius-control", Na = /var\(\s*--twd-/;
1186
- function ja(t) {
1187
- return t.style.cssText.split(";").some((e) => {
1188
- const n = e.slice(0, e.indexOf(":")).trim();
1189
- return n && !n.startsWith("--") && Na.test(e);
1266
+ const a = parseFloat(t.fontSize), s = a >= 24 || a >= 18.66 && parseInt(t.fontWeight, 10) >= 700 ? Ra : Ue, r = qn(n, Ia(e));
1267
+ return r < s ? { label: "This element", ratio: r, needed: s, text: `This element’s text: ${Hn(r)} · AA needs ${s}` } : null;
1268
+ }
1269
+ const un = "twiddle-panel", Ua = "0.8.1", hn = "https://panel.twiddle.in", Ba = "--twd-radius-control", qa = /var\(\s*--twd-/;
1270
+ function Ha(e) {
1271
+ return e.style.cssText.split(";").some((t) => {
1272
+ const n = t.slice(0, t.indexOf(":")).trim();
1273
+ return n && !n.startsWith("--") && qa.test(t);
1190
1274
  });
1191
1275
  }
1192
- function Ra() {
1193
- if (!getComputedStyle(document.documentElement).getPropertyValue(Fa).trim()) return "no-tokens";
1194
- let t = !1;
1195
- for (const e of document.styleSheets) {
1196
- if (e.ownerNode?.id === "twiddle-scoped") continue;
1276
+ function Va() {
1277
+ if (!getComputedStyle(document.documentElement).getPropertyValue(Ba).trim()) return "no-tokens";
1278
+ let e = !1;
1279
+ for (const t of document.styleSheets) {
1280
+ if (t.ownerNode?.id === "twiddle-scoped") continue;
1197
1281
  let n;
1198
1282
  try {
1199
- n = e.cssRules;
1283
+ n = t.cssRules;
1200
1284
  } catch {
1201
- t = !0;
1285
+ e = !0;
1202
1286
  continue;
1203
1287
  }
1204
- for (const a of qe(n)) if (ja(a)) return "ok";
1288
+ for (const a of _e(n)) if (Ha(a)) return "ok";
1205
1289
  }
1206
- return document.querySelector('[style*="var(--twd-"]') ? "ok" : t ? "unknown" : "unused";
1290
+ return document.querySelector('[style*="var(--twd-"]') ? "ok" : e ? "unknown" : "unused";
1207
1291
  }
1208
- function za() {
1209
- const t = /* @__PURE__ */ new Set(), e = (n) => {
1210
- for (const a of n.matchAll(/var\(\s*(--twd-[\w-]+)/g)) t.add(a[1]);
1292
+ function _a() {
1293
+ const e = /* @__PURE__ */ new Set(), t = (n) => {
1294
+ for (const a of n.matchAll(/var\(\s*(--twd-[\w-]+)/g)) e.add(a[1]);
1211
1295
  };
1212
1296
  for (const n of document.styleSheets) {
1213
1297
  if (n.ownerNode?.id === "twiddle-scoped") continue;
@@ -1217,19 +1301,19 @@ function za() {
1217
1301
  } catch {
1218
1302
  continue;
1219
1303
  }
1220
- for (const o of qe(a))
1304
+ for (const o of _e(a))
1221
1305
  o.style.cssText.split(";").forEach((s) => {
1222
1306
  const r = s.slice(0, s.indexOf(":")).trim();
1223
- r && !r.startsWith("--") && e(s);
1307
+ r && !r.startsWith("--") && t(s);
1224
1308
  });
1225
1309
  }
1226
- return document.querySelectorAll('[style*="var(--twd-"]').forEach((n) => e(n.getAttribute("style"))), t;
1310
+ return document.querySelectorAll('[style*="var(--twd-"]').forEach((n) => t(n.getAttribute("style"))), e;
1227
1311
  }
1228
- const cn = [
1229
- { label: "With a build tool, in your entry file", code: `import '${ln}/tokens.css';` },
1312
+ const fn = [
1313
+ { label: "With a build tool, in your entry file", code: `import '${un}/tokens.css';` },
1230
1314
  // Pinned to this build's version: unversioned jsDelivr links can lag a release by days, and unpkg once failed for a fresh one.
1231
- { label: "Plain HTML, in <head>", code: `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/${ln}@${Pa}/dist/twiddle-tokens.css">` }
1232
- ], Ia = `Convert this prototype's styles to use the Panel design tokens (the --twd-* CSS custom properties from twiddle-panel), so the panel can tweak them live.
1315
+ { label: "Plain HTML, in <head>", code: `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/${un}@${Ua}/dist/twiddle-tokens.css">` }
1316
+ ], Ka = `Convert this prototype's styles to use the Panel design tokens (the --twd-* CSS custom properties from twiddle-panel), so the panel can tweak them live.
1233
1317
 
1234
1318
  1. Keep the current look. In a :root rule loaded after twiddle-tokens.css, set each token below to the value this project already uses (for example, if buttons use #0f766e, set --twd-primary: #0f766e). Only set the tokens the project actually needs.
1235
1319
  2. Replace fixed values in component styles with var(--twd-…). Map each value to the closest token by role:
@@ -1247,52 +1331,52 @@ const cn = [
1247
1331
  3. Leave values that don't match a role as they are (layout widths, one-off illustrations, icon sizes). Don't invent new --twd-* tokens.
1248
1332
  4. Don't change the layout or how the page looks; after the change it should look the same until someone uses the panel.
1249
1333
  5. When done, list the files you changed and any values you left fixed, with the reason.`;
1250
- function B(t) {
1251
- const e = document.createElement("div");
1252
- e.className = "field";
1334
+ function U(e) {
1335
+ const t = document.createElement("div");
1336
+ t.className = "field";
1253
1337
  const n = document.createElement("div");
1254
1338
  n.className = "field-head";
1255
1339
  const a = document.createElement("span");
1256
- a.className = "field-label", a.textContent = t;
1340
+ a.className = "field-label", a.textContent = e;
1257
1341
  const o = document.createElement("span");
1258
- return o.className = "field-value", o.hidden = !0, n.append(a, o), e.append(n), {
1259
- el: e,
1342
+ return o.className = "field-value", o.hidden = !0, n.append(a, o), t.append(n), {
1343
+ el: t,
1260
1344
  setValue(s) {
1261
1345
  o.textContent = s || "", o.hidden = !s;
1262
1346
  },
1263
1347
  append(...s) {
1264
- e.append(...s);
1348
+ t.append(...s);
1265
1349
  }
1266
1350
  };
1267
1351
  }
1268
- function Da({ label: t, ends: e, cols: n = 9, rows: a = 5, onInput: o }) {
1352
+ function Wa({ label: e, ends: t, cols: n = 9, rows: a = 5, onInput: o }) {
1269
1353
  const s = document.createElement("div");
1270
1354
  s.className = "pad", s.tabIndex = 0, s.setAttribute("role", "group"), s.setAttribute("aria-roledescription", "2D slider");
1271
- const r = (b, u) => {
1272
- const v = document.createElement("span");
1273
- return v.className = `pad-edge ${b}`, v.textContent = u, v.setAttribute("aria-hidden", "true"), v;
1355
+ const r = (b, h) => {
1356
+ const y = document.createElement("span");
1357
+ return y.className = `pad-edge ${b}`, y.textContent = h, y.setAttribute("aria-hidden", "true"), y;
1274
1358
  };
1275
- s.append(r("top", e.top), r("bottom", e.bottom), r("left", e.left), r("right", e.right));
1359
+ s.append(r("top", t.top), r("bottom", t.bottom), r("left", t.left), r("right", t.right));
1276
1360
  const i = document.createElement("div");
1277
1361
  i.className = "pad-area";
1278
1362
  for (let b = 0; b < a; b++)
1279
- for (let u = 0; u < n; u++) {
1280
- const v = document.createElement("i");
1281
- v.className = "pad-dot", v.style.left = `${u / (n - 1) * 100}%`, v.style.top = `${b / (a - 1) * 100}%`, i.append(v);
1363
+ for (let h = 0; h < n; h++) {
1364
+ const y = document.createElement("i");
1365
+ y.className = "pad-dot", y.style.left = `${h / (n - 1) * 100}%`, y.style.top = `${b / (a - 1) * 100}%`, i.append(y);
1282
1366
  }
1283
1367
  const l = document.createElement("span");
1284
1368
  l.className = "pad-knob", i.append(l), s.append(i);
1285
- let p = 0.5, c = 0.5;
1286
- const h = (b, u) => Math.round(Math.min(1, Math.max(0, b)) * (u - 1)) / (u - 1);
1287
- function y() {
1288
- l.style.left = `${p * 100}%`, l.style.top = `${c * 100}%`;
1369
+ let d = 0.5, p = 0.5;
1370
+ const u = (b, h) => Math.round(Math.min(1, Math.max(0, b)) * (h - 1)) / (h - 1);
1371
+ function v() {
1372
+ l.style.left = `${d * 100}%`, l.style.top = `${p * 100}%`;
1289
1373
  }
1290
- function f(b, u, v) {
1291
- b = v === "x" ? p : h(b, n), u = v === "y" ? c : h(u, a), !(b === p && u === c) && (p = b, c = u, y(), o(p, c));
1374
+ function f(b, h, y) {
1375
+ b = y === "x" ? d : u(b, n), h = y === "y" ? p : u(h, a), !(b === d && h === p) && (d = b, p = h, v(), o(d, p));
1292
1376
  }
1293
1377
  const m = (b) => {
1294
- const u = i.getBoundingClientRect();
1295
- f((b.clientX - u.left) / u.width, (b.clientY - u.top) / u.height);
1378
+ const h = i.getBoundingClientRect();
1379
+ f((b.clientX - h.left) / h.width, (b.clientY - h.top) / h.height);
1296
1380
  };
1297
1381
  s.addEventListener("pointerdown", (b) => {
1298
1382
  s.setPointerCapture(b.pointerId), s.classList.add("dragging"), m(b);
@@ -1303,149 +1387,149 @@ function Da({ label: t, ends: e, cols: n = 9, rows: a = 5, onInput: o }) {
1303
1387
  s.hasPointerCapture(b.pointerId) && s.releasePointerCapture(b.pointerId), s.classList.remove("dragging");
1304
1388
  };
1305
1389
  return s.addEventListener("pointerup", x), s.addEventListener("pointercancel", x), s.addEventListener("keydown", (b) => {
1306
- const u = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] }[b.key];
1307
- u && (b.preventDefault(), u[0] ? f(h(p, n) + u[0] / (n - 1), c, "y") : f(p, h(c, a) + u[1] / (a - 1), "x"));
1390
+ const h = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] }[b.key];
1391
+ h && (b.preventDefault(), h[0] ? f(u(d, n) + h[0] / (n - 1), p, "y") : f(d, u(p, a) + h[1] / (a - 1), "x"));
1308
1392
  }), {
1309
1393
  el: s,
1310
1394
  /** Show a position without telling anyone (used to sync). Off-grid values are shown as they are. */
1311
- setValue(b, u, v) {
1312
- p = Math.min(1, Math.max(0, b)), c = Math.min(1, Math.max(0, u)), y(), s.setAttribute("aria-label", v ? `${t}: ${v}` : t);
1395
+ setValue(b, h, y) {
1396
+ d = Math.min(1, Math.max(0, b)), p = Math.min(1, Math.max(0, h)), v(), s.setAttribute("aria-label", y ? `${e}: ${y}` : e);
1313
1397
  }
1314
1398
  };
1315
1399
  }
1316
- function Dn({ label: t, min: e, max: n, step: a = 1, format: o = String, onInput: s }) {
1400
+ function Vn({ label: e, min: t, max: n, step: a = 1, format: o = String, onInput: s }) {
1317
1401
  const r = document.createElement("div");
1318
1402
  r.className = "slider";
1319
1403
  const i = document.createElement("input");
1320
- i.type = "range", i.min = String(e), i.max = String(n), i.step = String(a), i.setAttribute("aria-label", t);
1404
+ i.type = "range", i.min = String(t), i.max = String(n), i.step = String(a), i.setAttribute("aria-label", e);
1321
1405
  const l = document.createElement("span");
1322
1406
  l.className = "slider-value", l.setAttribute("aria-hidden", "true"), r.append(i, l);
1323
- const p = (c) => {
1324
- const h = (Number(i.value) - e) / (n - e) * 100;
1325
- i.style.setProperty("--fill", `${h}%`), l.textContent = c ?? o(Number(i.value)), i.setAttribute("aria-valuetext", l.textContent);
1407
+ const d = (p) => {
1408
+ const u = (Number(i.value) - t) / (n - t) * 100;
1409
+ i.style.setProperty("--fill", `${u}%`), l.textContent = p ?? o(Number(i.value)), i.setAttribute("aria-valuetext", l.textContent);
1326
1410
  };
1327
1411
  return i.addEventListener("input", () => {
1328
- p(), s(Number(i.value));
1412
+ d(), s(Number(i.value));
1329
1413
  }), {
1330
1414
  el: r,
1331
1415
  /** Show a value without reporting it (sync after reset / URL load). */
1332
- setValue(c, h) {
1333
- i.value = String(c), p(h);
1416
+ setValue(p, u) {
1417
+ i.value = String(p), d(u);
1334
1418
  }
1335
1419
  };
1336
1420
  }
1337
- function Ba({ label: t, options: e, columns: n = 3, className: a = "", onSelect: o }) {
1421
+ function Ga({ label: e, options: t, columns: n = 3, className: a = "", onSelect: o }) {
1338
1422
  const s = document.createElement("div");
1339
- s.className = `tiles ${a}`.trim(), s.style.setProperty("--cols", n), s.setAttribute("role", "radiogroup"), s.setAttribute("aria-label", t);
1340
- const r = e.map((c) => {
1341
- const h = document.createElement("button");
1342
- return h.type = "button", h.className = "tile", c.wide && h.classList.add("wide"), h.setAttribute("role", "radio"), h.dataset.value = c.value, c.title && (h.title = c.title), h.innerHTML = `${c.preview ? `<span class="tile-preview" aria-hidden="true">${c.preview}</span>` : ""}<span class="tile-text"><span class="tile-label"></span>${c.sub ? '<span class="tile-sub"></span>' : ""}</span>`, h.querySelector(".tile-label").textContent = c.label, c.sub && (h.querySelector(".tile-sub").textContent = c.sub), h.addEventListener("click", () => p(c.value)), h;
1423
+ s.className = `tiles ${a}`.trim(), s.style.setProperty("--cols", n), s.setAttribute("role", "radiogroup"), s.setAttribute("aria-label", e);
1424
+ const r = t.map((p) => {
1425
+ const u = document.createElement("button");
1426
+ return u.type = "button", u.className = "tile", p.wide && u.classList.add("wide"), u.setAttribute("role", "radio"), u.dataset.value = p.value, p.title && (u.title = p.title), u.innerHTML = `${p.preview ? `<span class="tile-preview" aria-hidden="true">${p.preview}</span>` : ""}<span class="tile-text"><span class="tile-label"></span>${p.sub ? '<span class="tile-sub"></span>' : ""}</span>`, u.querySelector(".tile-label").textContent = p.label, p.sub && (u.querySelector(".tile-sub").textContent = p.sub), u.addEventListener("click", () => d(p.value)), u;
1343
1427
  });
1344
1428
  s.append(...r);
1345
1429
  let i = null;
1346
- function l(c) {
1347
- i = c, r.forEach((y) => y.setAttribute("aria-checked", String(y.dataset.value === c)));
1348
- const h = Math.max(0, r.findIndex((y) => y.dataset.value === c));
1349
- r.forEach((y, f) => {
1350
- y.tabIndex = f === h ? 0 : -1;
1430
+ function l(p) {
1431
+ i = p, r.forEach((v) => v.setAttribute("aria-checked", String(v.dataset.value === p)));
1432
+ const u = Math.max(0, r.findIndex((v) => v.dataset.value === p));
1433
+ r.forEach((v, f) => {
1434
+ v.tabIndex = f === u ? 0 : -1;
1351
1435
  });
1352
1436
  }
1353
- function p(c, h) {
1354
- c !== i && (l(c), o(c)), h && r.find((y) => y.dataset.value === c).focus();
1437
+ function d(p, u) {
1438
+ p !== i && (l(p), o(p)), u && r.find((v) => v.dataset.value === p).focus();
1355
1439
  }
1356
- return s.addEventListener("keydown", (c) => {
1357
- const h = r.indexOf(c.target.closest(".tile"));
1358
- if (h < 0) return;
1359
- const y = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[c.key];
1440
+ return s.addEventListener("keydown", (p) => {
1441
+ const u = r.indexOf(p.target.closest(".tile"));
1442
+ if (u < 0) return;
1443
+ const v = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[p.key];
1360
1444
  let f;
1361
- if (y) f = (h + y + r.length) % r.length;
1362
- else if (c.key === "Home") f = 0;
1363
- else if (c.key === "End") f = r.length - 1;
1445
+ if (v) f = (u + v + r.length) % r.length;
1446
+ else if (p.key === "Home") f = 0;
1447
+ else if (p.key === "End") f = r.length - 1;
1364
1448
  else return;
1365
- c.preventDefault(), p(r[f].dataset.value, !0);
1449
+ p.preventDefault(), d(r[f].dataset.value, !0);
1366
1450
  }), l(null), { el: s, setValue: l };
1367
1451
  }
1368
- const F = (t) => getComputedStyle(document.documentElement).getPropertyValue(t).trim();
1369
- function ye(t, e) {
1370
- const n = /^(-?\d*\.?\d+)([a-z%]*)$/i.exec(String(t).trim());
1452
+ const F = (e) => getComputedStyle(document.documentElement).getPropertyValue(e).trim();
1453
+ function Se(e, t) {
1454
+ const n = /^(-?\d*\.?\d+)([a-z%]*)$/i.exec(String(e).trim());
1371
1455
  if (!n) return null;
1372
- const a = parseFloat(n[1]) * e, o = n[2] || "px";
1456
+ const a = parseFloat(n[1]) * t, o = n[2] || "px";
1373
1457
  return o === "px" ? `${Math.round(a)}px` : `${+a.toFixed(3)}${o}`;
1374
1458
  }
1375
- const Ua = 999;
1376
- function Bn({ id: t, title: e, hint: n, token: a, uses: o = [], presets: s, max: r, extra: i = [], extraTokens: l = () => ({}), shape: p = "card" }) {
1377
- const c = (f) => s.find((m) => m.value === f), h = (f) => f >= Ua ? "full" : `${f}px`, y = (f) => {
1459
+ const Ya = 999;
1460
+ function _n({ id: e, title: t, hint: n, token: a, uses: o = [], presets: s, max: r, extra: i = [], extraTokens: l = () => ({}), shape: d = "card" }) {
1461
+ const p = (f) => s.find((m) => m.value === f), u = (f) => f >= Ya ? "full" : `${f}px`, v = (f) => {
1378
1462
  if (typeof f.radius == "number" && isFinite(f.radius))
1379
1463
  return { [a]: `${Math.min(Math.max(f.radius, 0), r)}px` };
1380
- const m = c(f.corners);
1464
+ const m = p(f.corners);
1381
1465
  return m ? { [a]: `${m.radius}px` } : {};
1382
1466
  };
1383
1467
  return {
1384
- id: t,
1385
- title: e,
1468
+ id: e,
1469
+ title: t,
1386
1470
  hint: n,
1387
1471
  presets: s,
1388
1472
  uses: [a, ...o],
1389
1473
  tokens(f) {
1390
- const m = f[t] || {};
1391
- return { ...y(m), ...l(m) };
1474
+ const m = f[e] || {};
1475
+ return { ...v(m), ...l(m) };
1392
1476
  },
1393
1477
  // One render function per knob, so a layout can place them separately.
1394
1478
  // Each takes an optional label (e.g. "Buttons" on the Corners page).
1395
1479
  parts: {
1396
1480
  corners(f, m, { label: x = "Corners" } = {}) {
1397
- const b = B(x), u = ie({
1398
- label: `${e} corners`,
1399
- options: s.map((E) => ({ value: E.value, label: E.label, title: h(E.radius) })),
1400
- onSelect: (E) => m.setSection(t, { corners: E, radius: null })
1401
- }), v = Dn({
1402
- label: `${e} corner radius`,
1481
+ const b = U(x), h = ce({
1482
+ label: `${t} corners`,
1483
+ options: s.map((E) => ({ value: E.value, label: E.label, title: u(E.radius) })),
1484
+ onSelect: (E) => m.setSection(e, { corners: E, radius: null })
1485
+ }), y = Vn({
1486
+ label: `${t} corner radius`,
1403
1487
  min: 0,
1404
1488
  max: r,
1405
- format: h,
1406
- onInput: (E) => m.setSection(t, { radius: E, corners: null })
1489
+ format: u,
1490
+ onInput: (E) => m.setSection(e, { radius: E, corners: null })
1407
1491
  });
1408
- b.append(u.el, v.el), f.append(b.el);
1492
+ b.append(h.el, y.el), f.append(b.el);
1409
1493
  const L = () => {
1410
- const E = parseFloat((m.readToken || F)(a)), Q = m.getState()[t] || {}, K = c(Q.corners) || s.find((G) => G.radius === E);
1411
- if (u.setValue(K ? K.value : null), isNaN(E)) {
1412
- v.setValue(0, "—"), b.setValue("");
1494
+ const E = parseFloat((m.readToken || F)(a)), ee = m.getState()[e] || {}, K = p(ee.corners) || s.find((W) => W.radius === E);
1495
+ if (h.setValue(K ? K.value : null), isNaN(E)) {
1496
+ y.setValue(0, "—"), b.setValue("");
1413
1497
  return;
1414
1498
  }
1415
- v.setValue(Math.min(E, r), h(E)), b.setValue(h(E));
1499
+ y.setValue(Math.min(E, r), u(E)), b.setValue(u(E));
1416
1500
  };
1417
1501
  L(), m.onChange(L);
1418
1502
  },
1419
- ...Object.fromEntries(i.map((f) => [f.key, (m, x, { label: b } = {}) => m.append(ke(x, { section: t, ...f, label: b || f.label }))])),
1503
+ ...Object.fromEntries(i.map((f) => [f.key, (m, x, { label: b } = {}) => m.append($e(x, { section: e, ...f, label: b || f.label }))])),
1420
1504
  // Tabbed layout: presets as tiles showing the real rounding.
1421
1505
  cornerTiles(f, m, { label: x = "Corners" } = {}) {
1422
- const b = (u) => `<span class="shape shape-${p}" style="border-radius:${Math.min(u, p === "button" ? 12 : 16)}px"></span>`;
1506
+ const b = (h) => `<span class="shape shape-${d}" style="border-radius:${Math.min(h, d === "button" ? 12 : 16)}px"></span>`;
1423
1507
  f.append(V(m, {
1424
- section: t,
1508
+ section: e,
1425
1509
  key: "corners",
1426
1510
  label: x,
1427
1511
  columns: s.length,
1428
- options: s.map((u) => ({ value: u.value, label: u.label, title: h(u.radius), preview: b(u.radius) })),
1429
- current: (u) => {
1430
- const v = u[t] || {};
1431
- if (v.radius != null) return null;
1512
+ options: s.map((h) => ({ value: h.value, label: h.label, title: u(h.radius), preview: b(h.radius) })),
1513
+ current: (h) => {
1514
+ const y = h[e] || {};
1515
+ if (y.radius != null) return null;
1432
1516
  const L = parseFloat((m.readToken || F)(a));
1433
- return (c(v.corners) || s.find((E) => E.radius === L))?.value || null;
1517
+ return (p(y.corners) || s.find((E) => E.radius === L))?.value || null;
1434
1518
  },
1435
- select: (u) => m.setSection(t, { corners: u, radius: null }),
1519
+ select: (h) => m.setSection(e, { corners: h, radius: null }),
1436
1520
  valueText: () => {
1437
- const u = parseFloat((m.readToken || F)(a));
1438
- return isNaN(u) ? "" : h(u);
1521
+ const h = parseFloat((m.readToken || F)(a));
1522
+ return isNaN(h) ? "" : u(h);
1439
1523
  }
1440
1524
  }));
1441
1525
  },
1442
1526
  ...Object.fromEntries(i.filter((f) => f.preview).map((f) => [`${f.key}Tiles`, (m, x, { label: b } = {}) => m.append(V(x, {
1443
- section: t,
1527
+ section: e,
1444
1528
  key: f.key,
1445
1529
  label: b || f.label,
1446
1530
  fallback: f.fallback,
1447
1531
  columns: f.columns || f.options.length,
1448
- options: f.options.map((u) => ({ ...u, preview: f.preview(u.value) }))
1532
+ options: f.options.map((h) => ({ ...h, preview: f.preview(h.value) }))
1449
1533
  }))]))
1450
1534
  },
1451
1535
  render(f, m) {
@@ -1453,50 +1537,50 @@ function Bn({ id: t, title: e, hint: n, token: a, uses: o = [], presets: s, max:
1453
1537
  }
1454
1538
  };
1455
1539
  }
1456
- function ke(t, { section: e, key: n, label: a, options: o, fallback: s, valueText: r }) {
1457
- const i = B(a), l = ie({
1540
+ function $e(e, { section: t, key: n, label: a, options: o, fallback: s, valueText: r }) {
1541
+ const i = U(a), l = ce({
1458
1542
  label: a,
1459
1543
  options: o,
1460
- onSelect: (c) => t.setSection(e, { [n]: c })
1544
+ onSelect: (p) => e.setSection(t, { [n]: p })
1461
1545
  });
1462
1546
  i.append(l.el);
1463
- const p = () => {
1464
- const c = (t.getState()[e] || {})[n] || s;
1465
- l.setValue(c), i.setValue(r ? r(c) : "");
1547
+ const d = () => {
1548
+ const p = (e.getState()[t] || {})[n] || s;
1549
+ l.setValue(p), i.setValue(r ? r(p) : "");
1466
1550
  };
1467
- return p(), t.onChange(p), i.el;
1468
- }
1469
- function qa(t, { section: e, key: n, label: a, min: o, max: s, fallback: r, format: i }) {
1470
- const l = B(a), p = Dn({ label: a, min: o, max: s, format: i, onInput: (h) => t.setSection(e, { [n]: h }) });
1471
- l.append(p.el);
1472
- const c = () => {
1473
- const h = (t.getState()[e] || {})[n];
1474
- p.setValue(typeof h == "number" ? h : r);
1551
+ return d(), e.onChange(d), i.el;
1552
+ }
1553
+ function Xa(e, { section: t, key: n, label: a, min: o, max: s, fallback: r, format: i }) {
1554
+ const l = U(a), d = Vn({ label: a, min: o, max: s, format: i, onInput: (u) => e.setSection(t, { [n]: u }) });
1555
+ l.append(d.el);
1556
+ const p = () => {
1557
+ const u = (e.getState()[t] || {})[n];
1558
+ d.setValue(typeof u == "number" ? u : r);
1475
1559
  };
1476
- return c(), t.onChange(c), l.el;
1560
+ return p(), e.onChange(p), l.el;
1477
1561
  }
1478
- function V(t, { section: e, key: n, label: a, options: o, columns: s = 3, className: r = "", fallback: i, valueText: l, current: p, select: c }) {
1479
- const h = B(a), y = Ba({
1562
+ function V(e, { section: t, key: n, label: a, options: o, columns: s = 3, className: r = "", fallback: i, valueText: l, current: d, select: p }) {
1563
+ const u = U(a), v = Ga({
1480
1564
  label: a,
1481
1565
  options: o,
1482
1566
  columns: s,
1483
1567
  className: r,
1484
- onSelect: (m) => c ? c(m) : t.setSection(e, { [n]: m })
1568
+ onSelect: (m) => p ? p(m) : e.setSection(t, { [n]: m })
1485
1569
  });
1486
- h.append(y.el);
1570
+ u.append(v.el);
1487
1571
  const f = () => {
1488
- const m = t.getState(), x = p ? p(m) : (m[e] || {})[n] || i || null;
1489
- y.setValue(x), h.setValue(l ? l(x, m) : "");
1572
+ const m = e.getState(), x = d ? d(m) : (m[t] || {})[n] || i || null;
1573
+ v.setValue(x), u.setValue(l ? l(x, m) : "");
1490
1574
  };
1491
- return f(), t.onChange(f), h.el;
1575
+ return f(), e.onChange(f), u.el;
1492
1576
  }
1493
- const pn = (t, e) => e.map((n) => `${t}${n}`), Un = {
1577
+ const gn = (e, t) => t.map((n) => `${e}${n}`), Kn = {
1494
1578
  fonts: { label: "Tokens", tokens: ["font-heading", "font-body"], kind: "text" },
1495
- type: { label: "Tokens", tokens: pn("text-", ["xs", "sm", "base", "lg", "xl", "2xl", "3xl"]), kind: "length" },
1579
+ type: { label: "Tokens", tokens: gn("text-", ["xs", "sm", "base", "lg", "xl", "2xl", "3xl"]), kind: "length" },
1496
1580
  leading: { label: "Line height", tokens: ["leading-tight", "leading-normal"], kind: "number" },
1497
1581
  weights: { label: "Weights", tokens: ["weight-heading", "weight-strong"], kind: "number" },
1498
1582
  colours: { label: "Tokens", tokens: ["bg", "surface", "surface-raised", "text", "text-muted", "border", "primary", "primary-hover", "on-primary", "focus", "success", "warning", "danger"], kind: "colour" },
1499
- spacing: { label: "Steps", tokens: pn("space-", [1, 2, 3, 4, 5, 6, 7, 8]), kind: "length", bar: 64 },
1583
+ spacing: { label: "Steps", tokens: gn("space-", [1, 2, 3, 4, 5, 6, 7, 8]), kind: "length", bar: 64 },
1500
1584
  controls: { label: "Controls", tokens: ["control-height", "control-pad-x"], kind: "length" },
1501
1585
  corners: { label: "Tokens", tokens: ["radius-control", "radius-container"], kind: "length" },
1502
1586
  borders: { label: "Tokens", tokens: ["border-width", "border-width-container"], kind: "length" },
@@ -1504,124 +1588,124 @@ const pn = (t, e) => e.map((n) => `${t}${n}`), Un = {
1504
1588
  buttonStyle: { label: "Button", tokens: ["button-bg", "button-fg", "button-border", "button-hover"], kind: "colour" },
1505
1589
  cardStyle: { label: "Card", tokens: ["card-bg", "card-border"], kind: "colour" },
1506
1590
  cardShadow: { label: "Card shadow", tokens: ["card-shadow"], kind: "text" }
1507
- }, _ = (t) => `--twd-${t}`, et = (t, e) => Object.prototype.hasOwnProperty.call(t.getState().custom || {}, e), un = (t, e) => Un[e].tokens.some((n) => (t.custom || {})[n] != null);
1508
- function Va(t, e) {
1509
- const n = /^(-?\d*\.?\d+)(px|rem)?$/.exec(String(t).trim());
1510
- return !n || e === "text" || e === "colour" ? null : n[2] === "rem" ? { n: +(parseFloat(n[1]) * 16).toFixed(1), unit: "px" } : { n: +parseFloat(n[1]).toFixed(3), unit: n[2] || (e === "length" ? "px" : "") };
1591
+ }, _ = (e) => `--twd-${e}`, at = (e, t) => Object.prototype.hasOwnProperty.call(e.getState().custom || {}, t), mn = (e, t) => Kn[t].tokens.some((n) => (e.custom || {})[n] != null);
1592
+ function Za(e, t) {
1593
+ const n = /^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());
1594
+ return !n || t === "text" || t === "colour" ? null : n[2] === "rem" ? { n: +(parseFloat(n[1]) * 16).toFixed(1), unit: "px" } : { n: +parseFloat(n[1]).toFixed(3), unit: n[2] || (t === "length" ? "px" : "") };
1511
1595
  }
1512
- function Ha(t, e) {
1513
- const n = t.trim();
1514
- return n ? e === "length" && /^-?\d*\.?\d+$/.test(n) ? `${n}px` : n : null;
1596
+ function Ja(e, t) {
1597
+ const n = e.trim();
1598
+ return n ? t === "length" && /^-?\d*\.?\d+$/.test(n) ? `${n}px` : n : null;
1515
1599
  }
1516
- function _a(t, e, n, a) {
1600
+ function Qa(e, t, n, a) {
1517
1601
  const o = document.createElement("div");
1518
1602
  o.className = `token-row kind-${n}`, o.innerHTML = `
1519
- <code class="token-name" title="${_(e)}">${e}</code>
1603
+ <code class="token-name" title="${_(t)}">${t}</code>
1520
1604
  ${a ? '<span class="token-bar"><span></span></span>' : '<span class="token-gap"></span>'}
1521
1605
  <span class="custom-tag" hidden>Custom</span>
1522
1606
  <label class="token-value">
1523
1607
  ${n === "colour" ? '<span class="token-swatch"></span>' : ""}
1524
- <input type="text" spellcheck="false" aria-label="${_(e)}" ${n === "length" || n === "number" ? 'inputmode="decimal"' : ""}>
1608
+ <input type="text" spellcheck="false" aria-label="${_(t)}" ${n === "length" || n === "number" ? 'inputmode="decimal"' : ""}>
1525
1609
  <span class="token-unit"></span>
1526
1610
  </label>
1527
- <button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${_(e)}" hidden>${A.reset}</button>
1611
+ <button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${_(t)}" hidden>${A.reset}</button>
1528
1612
  `;
1529
- const s = o.querySelector("input"), r = o.querySelector(".token-unit"), i = o.querySelector(".token-bar span"), l = o.querySelector(".token-swatch"), p = o.querySelector(".custom-tag"), c = o.querySelector(".token-reset");
1530
- let h = "";
1531
- const y = () => {
1613
+ const s = o.querySelector("input"), r = o.querySelector(".token-unit"), i = o.querySelector(".token-bar span"), l = o.querySelector(".token-swatch"), d = o.querySelector(".custom-tag"), p = o.querySelector(".token-reset");
1614
+ let u = "";
1615
+ const v = () => {
1532
1616
  let m = s.value;
1533
- h && /^-?\d*\.?\d+$/.test(m.trim()) && (m = `${m.trim()}${h}`);
1534
- const x = Ha(m, n), b = F(_(e));
1617
+ u && /^-?\d*\.?\d+$/.test(m.trim()) && (m = `${m.trim()}${u}`);
1618
+ const x = Ja(m, n), b = F(_(t));
1535
1619
  if (x === null) {
1536
- et(t, e) ? t.setSection("custom", { [e]: null }) : f();
1620
+ at(e, t) ? e.setSection("custom", { [t]: null }) : f();
1537
1621
  return;
1538
1622
  }
1539
- if (x === b && !et(t, e)) return f();
1540
- t.setSection("custom", { [e]: x });
1623
+ if (x === b && !at(e, t)) return f();
1624
+ e.setSection("custom", { [t]: x });
1541
1625
  };
1542
- s.addEventListener("change", y), s.addEventListener("blur", () => f()), s.addEventListener("keydown", (m) => {
1626
+ s.addEventListener("change", v), s.addEventListener("blur", () => f()), s.addEventListener("keydown", (m) => {
1543
1627
  m.key === "Enter" && (m.preventDefault(), s.blur()), m.key === "Escape" && (m.stopPropagation(), f(), s.blur());
1544
- }), c.addEventListener("click", () => t.setSection("custom", { [e]: null }));
1628
+ }), p.addEventListener("click", () => e.setSection("custom", { [t]: null }));
1545
1629
  function f() {
1546
- const m = F(_(e)), x = et(t, e), b = Va(m, n);
1547
- h = b ? b.unit : "", document.activeElement !== s && o.getRootNode().activeElement !== s && (s.value = b ? String(b.n) : m), s.title = m, r.textContent = h, r.hidden = !h, i && (i.style.width = `${Math.max(2, Math.min(100, (b ? b.n : 0) / a * 100))}%`), l && (l.style.background = m), o.classList.toggle("edited", x), p.hidden = !x, c.hidden = !x;
1630
+ const m = F(_(t)), x = at(e, t), b = Za(m, n);
1631
+ u = b ? b.unit : "", document.activeElement !== s && o.getRootNode().activeElement !== s && (s.value = b ? String(b.n) : m), s.title = m, r.textContent = u, r.hidden = !u, i && (i.style.width = `${Math.max(2, Math.min(100, (b ? b.n : 0) / a * 100))}%`), l && (l.style.background = m), o.classList.toggle("edited", x), d.hidden = !x, p.hidden = !x;
1548
1632
  }
1549
- return f(), t.onChange(f), o;
1633
+ return f(), e.onChange(f), o;
1550
1634
  }
1551
- const Ka = {
1635
+ const eo = {
1552
1636
  id: "custom",
1553
1637
  title: "Custom tokens",
1554
1638
  hint: "Any token, set to a fixed value",
1555
1639
  uses: [],
1556
1640
  // not offered for a single picked element (yet)
1557
- tokens(t) {
1558
- return Object.fromEntries(Object.entries(t.custom || {}).map(([e, n]) => [_(e), n]));
1641
+ tokens(e) {
1642
+ return Object.fromEntries(Object.entries(e.custom || {}).map(([t, n]) => [_(t), n]));
1559
1643
  },
1560
- describe: (t, e) => ({ label: _(t), value: String(e) }),
1644
+ describe: (e, t) => ({ label: _(e), value: String(t) }),
1561
1645
  // One part per Edit page group, e.g. parts.spacing → rows for --twd-space-1 … 8.
1562
- parts: Object.fromEntries(Object.entries(Un).map(([t, e]) => [t, (n, a, { label: o = e.label } = {}) => {
1563
- const s = B(o);
1646
+ parts: Object.fromEntries(Object.entries(Kn).map(([e, t]) => [e, (n, a, { label: o = t.label } = {}) => {
1647
+ const s = U(o);
1564
1648
  s.el.classList.add("token-field");
1565
- const r = e.tokens[0], i = e.tokens[e.tokens.length - 1];
1566
- s.setValue(e.tokens.length > 2 && /-\w+$/.test(r) ? `${_(r)} … ${i.split("-").pop()}` : "");
1649
+ const r = t.tokens[0], i = t.tokens[t.tokens.length - 1];
1650
+ s.setValue(t.tokens.length > 2 && /-\w+$/.test(r) ? `${_(r)} … ${i.split("-").pop()}` : "");
1567
1651
  const l = document.createElement("div");
1568
- l.className = "token-rows", e.tokens.forEach((p) => l.append(_a(a, p, e.kind, e.bar))), s.append(l), n.append(s.el);
1652
+ l.className = "token-rows", t.tokens.forEach((d) => l.append(Qa(a, d, t.kind, t.bar))), s.append(l), n.append(s.el);
1569
1653
  }]))
1570
- }, we = { compact: 0.75, regular: 1, comfy: 1.25 }, wt = [0.75, 1.25], hn = [1, 2, 3, 4, 5, 6, 7, 8].map((t) => `--twd-space-${t}`);
1571
- function ae(t = {}) {
1572
- return typeof t.factor == "number" && isFinite(t.factor) ? Math.min(wt[1], Math.max(wt[0], t.factor)) : we[t.spacing] || 1;
1654
+ }, ve = { compact: 0.75, regular: 1, comfy: 1.25 }, kt = [0.75, 1.25], bn = [1, 2, 3, 4, 5, 6, 7, 8].map((e) => `--twd-space-${e}`);
1655
+ function se(e = {}) {
1656
+ return typeof e.factor == "number" && isFinite(e.factor) ? Math.min(kt[1], Math.max(kt[0], e.factor)) : ve[e.spacing] || 1;
1573
1657
  }
1574
- const tt = (t) => `${Math.round(t * 100)}%`, Ga = {
1658
+ const ot = (e) => `${Math.round(e * 100)}%`, to = {
1575
1659
  id: "density",
1576
1660
  title: "Density",
1577
1661
  hint: "Compact · regular · comfortable",
1578
- uses: hn,
1579
- tokens(t) {
1580
- const e = ae(t.density);
1581
- if (e === 1) return {};
1662
+ uses: bn,
1663
+ tokens(e) {
1664
+ const t = se(e.density);
1665
+ if (t === 1) return {};
1582
1666
  const n = {};
1583
- return hn.forEach((a) => {
1584
- const o = ye(F(a), e);
1667
+ return bn.forEach((a) => {
1668
+ const o = Se(F(a), t);
1585
1669
  o && (n[a] = o);
1586
1670
  }), n;
1587
1671
  },
1588
1672
  /** How the Changes list and prompt describe a setting. */
1589
- describe: (t, e) => t === "factor" ? { label: "Spacing", value: tt(e) } : null,
1673
+ describe: (e, t) => e === "factor" ? { label: "Spacing", value: ot(t) } : null,
1590
1674
  parts: {
1591
1675
  // Tabbed layout: presets as tiles with a tiny layout sketch.
1592
- spacingTiles(t, e, { label: n = "Density" } = {}) {
1676
+ spacingTiles(e, t, { label: n = "Density" } = {}) {
1593
1677
  const a = (o, s) => `<span class="sketch" style="padding:${s}px;gap:${o}px"><i></i><i></i><i></i></span>`;
1594
- t.append(V(e, {
1678
+ e.append(V(t, {
1595
1679
  section: "density",
1596
1680
  key: "spacing",
1597
1681
  label: n,
1598
1682
  options: [{ value: "compact", label: "Compact", preview: a(2, 5) }, { value: "regular", label: "Regular", preview: a(4, 8) }, { value: "comfy", label: "Comfy", preview: a(6, 11) }],
1599
1683
  current: (o) => {
1600
- const s = ae(o.density);
1601
- return Object.keys(we).find((r) => we[r] === s) || null;
1684
+ const s = se(o.density);
1685
+ return Object.keys(ve).find((r) => ve[r] === s) || null;
1602
1686
  },
1603
- select: (o) => e.setSection("density", { spacing: o, factor: null }),
1604
- valueText: (o, s) => un(s, "spacing") ? "Custom" : o ? "" : tt(ae(s.density))
1687
+ select: (o) => t.setSection("density", { spacing: o, factor: null }),
1688
+ valueText: (o, s) => mn(s, "spacing") ? "Custom" : o ? "" : ot(se(s.density))
1605
1689
  }));
1606
1690
  },
1607
- spacing(t, e, { label: n = "Spacing" } = {}) {
1608
- const a = B(n), o = ie({
1691
+ spacing(e, t, { label: n = "Spacing" } = {}) {
1692
+ const a = U(n), o = ce({
1609
1693
  label: n,
1610
1694
  options: [{ value: "compact", label: "Compact" }, { value: "regular", label: "Regular" }, { value: "comfy", label: "Comfy" }],
1611
- onSelect: (r) => e.setSection("density", { spacing: r, factor: null })
1695
+ onSelect: (r) => t.setSection("density", { spacing: r, factor: null })
1612
1696
  });
1613
1697
  a.append(o.el);
1614
1698
  const s = () => {
1615
- const r = e.getState().density || {}, i = ae(r), l = Object.keys(we).find((p) => we[p] === i);
1616
- o.setValue(l || null), a.setValue(un(e.getState(), "spacing") ? "Custom" : l ? "" : tt(i));
1699
+ const r = t.getState().density || {}, i = se(r), l = Object.keys(ve).find((d) => ve[d] === i);
1700
+ o.setValue(l || null), a.setValue(mn(t.getState(), "spacing") ? "Custom" : l ? "" : ot(i));
1617
1701
  };
1618
- s(), e.onChange(s), t.append(a.el);
1702
+ s(), t.onChange(s), e.append(a.el);
1619
1703
  }
1620
1704
  },
1621
- render(t, e) {
1622
- Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(t, e));
1705
+ render(e, t) {
1706
+ Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(e, t));
1623
1707
  }
1624
- }, Wa = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 6l4 4M4 20l1-4 9.5-9.5a2.1 2.1 0 013 3L8 19l-4 1z"/></svg>', Ya = [
1708
+ }, no = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 6l4 4M4 20l1-4 9.5-9.5a2.1 2.1 0 013 3L8 19l-4 1z"/></svg>', ao = [
1625
1709
  [50, "white", 10],
1626
1710
  [100, "white", 20],
1627
1711
  [200, "white", 36],
@@ -1633,11 +1717,11 @@ const tt = (t) => `${Math.round(t * 100)}%`, Ga = {
1633
1717
  [800, "black", 58],
1634
1718
  [900, "black", 45],
1635
1719
  [950, "black", 30]
1636
- ], nt = (t) => {
1637
- let e = String(t).trim().replace(/^#/, "");
1638
- return /^[0-9a-f]{3}$/i.test(e) && (e = e.split("").map((n) => n + n).join("")), /^[0-9a-f]{6}$/i.test(e) ? `#${e.toUpperCase()}` : null;
1720
+ ], rt = (e) => {
1721
+ let t = String(e).trim().replace(/^#/, "");
1722
+ return /^[0-9a-f]{3}$/i.test(t) && (t = t.split("").map((n) => n + n).join("")), /^[0-9a-f]{6}$/i.test(t) ? `#${t.toUpperCase()}` : null;
1639
1723
  };
1640
- function Za({ label: t, onInput: e }) {
1724
+ function oo({ label: e, onInput: t }) {
1641
1725
  const n = document.createElement("div");
1642
1726
  n.className = "colour";
1643
1727
  const a = document.createElement("div");
@@ -1645,21 +1729,21 @@ function Za({ label: t, onInput: e }) {
1645
1729
  const o = document.createElement("input");
1646
1730
  o.type = "color", o.className = "colour-picker", o.tabIndex = -1, o.setAttribute("aria-hidden", "true");
1647
1731
  const s = document.createElement("button");
1648
- s.type = "button", s.className = "colour-swatch", s.setAttribute("aria-label", `${t}: open colour picker`);
1732
+ s.type = "button", s.className = "colour-swatch", s.setAttribute("aria-label", `${e}: open colour picker`);
1649
1733
  const r = document.createElement("input");
1650
- r.type = "text", r.className = "colour-hex", r.spellcheck = !1, r.maxLength = 7, r.setAttribute("aria-label", `${t} hex value`);
1734
+ r.type = "text", r.className = "colour-hex", r.spellcheck = !1, r.maxLength = 7, r.setAttribute("aria-label", `${e} hex value`);
1651
1735
  const i = document.createElement("button");
1652
- i.type = "button", i.className = "colour-pipette", i.innerHTML = Wa, i.title = "Pick a colour from the screen", i.setAttribute("aria-label", "Pick a colour from the screen"), a.append(o, s, r, i);
1736
+ i.type = "button", i.className = "colour-pipette", i.innerHTML = no, i.title = "Pick a colour from the screen", i.setAttribute("aria-label", "Pick a colour from the screen"), a.append(o, s, r, i);
1653
1737
  const l = document.createElement("div");
1654
- l.className = "ramp", l.setAttribute("aria-hidden", "true"), l.innerHTML = Ya.map(([f, m, x]) => {
1738
+ l.className = "ramp", l.setAttribute("aria-hidden", "true"), l.innerHTML = ao.map(([f, m, x]) => {
1655
1739
  const b = m ? `color-mix(in oklch, var(--brand) ${x}%, ${m})` : "var(--brand)";
1656
1740
  return `<span title="${f}" style="background:${b}"></span>`;
1657
1741
  }).join(""), n.append(a, l);
1658
- let p = "#000000";
1659
- const c = (f) => {
1660
- p = f, o.value = f.toLowerCase(), s.style.background = f, n.getRootNode().activeElement !== r && (r.value = f), n.style.setProperty("--brand", f);
1661
- }, h = (f) => {
1662
- f !== p && (c(f), e(f));
1742
+ let d = "#000000";
1743
+ const p = (f) => {
1744
+ d = f, o.value = f.toLowerCase(), s.style.background = f, n.getRootNode().activeElement !== r && (r.value = f), n.style.setProperty("--brand", f);
1745
+ }, u = (f) => {
1746
+ f !== d && (p(f), t(f));
1663
1747
  };
1664
1748
  s.addEventListener("click", () => {
1665
1749
  if (o.showPicker)
@@ -1669,64 +1753,64 @@ function Za({ label: t, onInput: e }) {
1669
1753
  } catch {
1670
1754
  }
1671
1755
  o.click();
1672
- }), o.addEventListener("input", () => h(o.value.toUpperCase())), r.addEventListener("input", () => {
1673
- const f = nt(r.value);
1674
- f && h(f);
1756
+ }), o.addEventListener("input", () => u(o.value.toUpperCase())), r.addEventListener("input", () => {
1757
+ const f = rt(r.value);
1758
+ f && u(f);
1675
1759
  });
1676
- const y = () => {
1677
- r.value = p;
1760
+ const v = () => {
1761
+ r.value = d;
1678
1762
  };
1679
- return r.addEventListener("blur", y), r.addEventListener("keydown", (f) => {
1680
- f.key === "Enter" && (y(), r.select());
1763
+ return r.addEventListener("blur", v), r.addEventListener("keydown", (f) => {
1764
+ f.key === "Enter" && (v(), r.select());
1681
1765
  }), i.addEventListener("click", async () => {
1682
1766
  if ("EyeDropper" in window)
1683
1767
  try {
1684
- const { sRGBHex: f } = await new window.EyeDropper().open(), m = nt(f);
1685
- m && h(m);
1768
+ const { sRGBHex: f } = await new window.EyeDropper().open(), m = rt(f);
1769
+ m && u(m);
1686
1770
  } catch {
1687
1771
  }
1688
1772
  else
1689
1773
  s.click();
1690
- }), { el: n, setValue: (f) => c(nt(f) || p) };
1774
+ }), { el: n, setValue: (f) => p(rt(f) || d) };
1691
1775
  }
1692
- function Xa({ label: t, options: e, onSelect: n }) {
1776
+ function ro({ label: e, options: t, onSelect: n }) {
1693
1777
  const a = document.createElement("div");
1694
- a.className = "swatches", a.setAttribute("role", "radiogroup"), a.setAttribute("aria-label", t);
1695
- const o = e.map((l) => {
1696
- const p = document.createElement("button");
1697
- return p.type = "button", p.className = "swatch", p.setAttribute("role", "radio"), p.dataset.value = l.value, p.innerHTML = `<span class="swatch-ring"><span class="swatch-dot" style="background:${l.colour}"></span></span><span class="swatch-label">${l.label}</span>`, p.addEventListener("click", () => i(l.value)), p;
1778
+ a.className = "swatches", a.setAttribute("role", "radiogroup"), a.setAttribute("aria-label", e);
1779
+ const o = t.map((l) => {
1780
+ const d = document.createElement("button");
1781
+ return d.type = "button", d.className = "swatch", d.setAttribute("role", "radio"), d.dataset.value = l.value, d.innerHTML = `<span class="swatch-ring"><span class="swatch-dot" style="background:${l.colour}"></span></span><span class="swatch-label">${l.label}</span>`, d.addEventListener("click", () => i(l.value)), d;
1698
1782
  });
1699
1783
  a.append(...o);
1700
1784
  let s = null;
1701
1785
  function r(l) {
1702
- s = l, o.forEach((c) => c.setAttribute("aria-checked", String(c.dataset.value === l)));
1703
- const p = Math.max(0, o.findIndex((c) => c.dataset.value === l));
1704
- o.forEach((c, h) => {
1705
- c.tabIndex = h === p ? 0 : -1;
1786
+ s = l, o.forEach((p) => p.setAttribute("aria-checked", String(p.dataset.value === l)));
1787
+ const d = Math.max(0, o.findIndex((p) => p.dataset.value === l));
1788
+ o.forEach((p, u) => {
1789
+ p.tabIndex = u === d ? 0 : -1;
1706
1790
  });
1707
1791
  }
1708
- function i(l, p) {
1709
- l !== s && (r(l), n(l)), p && o.find((c) => c.dataset.value === l).focus();
1792
+ function i(l, d) {
1793
+ l !== s && (r(l), n(l)), d && o.find((p) => p.dataset.value === l).focus();
1710
1794
  }
1711
1795
  return a.addEventListener("keydown", (l) => {
1712
- const p = o.indexOf(l.target.closest(".swatch"));
1713
- if (p < 0) return;
1714
- const c = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[l.key];
1715
- let h;
1716
- if (c) h = (p + c + o.length) % o.length;
1717
- else if (l.key === "Home") h = 0;
1718
- else if (l.key === "End") h = o.length - 1;
1796
+ const d = o.indexOf(l.target.closest(".swatch"));
1797
+ if (d < 0) return;
1798
+ const p = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[l.key];
1799
+ let u;
1800
+ if (p) u = (d + p + o.length) % o.length;
1801
+ else if (l.key === "Home") u = 0;
1802
+ else if (l.key === "End") u = o.length - 1;
1719
1803
  else return;
1720
- l.preventDefault(), i(o[h].dataset.value, !0);
1804
+ l.preventDefault(), i(o[u].dataset.value, !0);
1721
1805
  }), r(null), { el: a, setValue: r };
1722
1806
  }
1723
- const Ja = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], me = (t) => Object.fromEntries(t.split(" ").map((e, n) => [Ja[n], `#${e}`])), at = {
1724
- slate: me("f8fafc f1f5f9 e2e8f0 cbd5e1 94a3b8 64748b 475569 334155 1e293b 0f172a 020617"),
1725
- gray: me("f9fafb f3f4f6 e5e7eb d1d5db 9ca3af 6b7280 4b5563 374151 1f2937 111827 030712"),
1726
- zinc: me("fafafa f4f4f5 e4e4e7 d4d4d8 a1a1aa 71717a 52525b 3f3f46 27272a 18181b 09090b"),
1727
- neutral: me("fafafa f5f5f5 e5e5e5 d4d4d4 a3a3a3 737373 525252 404040 262626 171717 0a0a0a"),
1728
- stone: me("fafaf9 f5f5f4 e7e5e4 d6d3d1 a8a29e 78716c 57534e 44403c 292524 1c1917 0c0a09")
1729
- }, N = (t) => Object.fromEntries(t.split(" ").map((e, n) => [400 + 100 * n, `#${e}`])), ot = {
1807
+ const so = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], xe = (e) => Object.fromEntries(e.split(" ").map((t, n) => [so[n], `#${t}`])), st = {
1808
+ slate: xe("f8fafc f1f5f9 e2e8f0 cbd5e1 94a3b8 64748b 475569 334155 1e293b 0f172a 020617"),
1809
+ gray: xe("f9fafb f3f4f6 e5e7eb d1d5db 9ca3af 6b7280 4b5563 374151 1f2937 111827 030712"),
1810
+ zinc: xe("fafafa f4f4f5 e4e4e7 d4d4d8 a1a1aa 71717a 52525b 3f3f46 27272a 18181b 09090b"),
1811
+ neutral: xe("fafafa f5f5f5 e5e5e5 d4d4d4 a3a3a3 737373 525252 404040 262626 171717 0a0a0a"),
1812
+ stone: xe("fafaf9 f5f5f4 e7e5e4 d6d3d1 a8a29e 78716c 57534e 44403c 292524 1c1917 0c0a09")
1813
+ }, N = (e) => Object.fromEntries(e.split(" ").map((t, n) => [400 + 100 * n, `#${t}`])), it = {
1730
1814
  red: N("f87171 ef4444 dc2626 b91c1c 991b1b"),
1731
1815
  orange: N("fb923c f97316 ea580c c2410c 9a3412"),
1732
1816
  amber: N("fbbf24 f59e0b d97706 b45309 92400e"),
@@ -1744,17 +1828,17 @@ const Ja = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], me = (t) => O
1744
1828
  fuchsia: N("e879f9 d946ef c026d3 a21caf 86198f"),
1745
1829
  pink: N("f472b6 ec4899 db2777 be185d 9d174d"),
1746
1830
  rose: N("fb7185 f43f5e e11d48 be123c 9f1239")
1747
- }, Ie = [
1831
+ }, Be = [
1748
1832
  { value: "indigo-zinc", label: "Indigo · Zinc", primary: "indigo", neutral: "zinc" },
1749
1833
  { value: "emerald-stone", label: "Emerald · Stone", primary: "emerald", neutral: "stone" },
1750
1834
  { value: "rose-slate", label: "Rose · Slate", primary: "rose", neutral: "slate" },
1751
1835
  { value: "amber-neutral", label: "Amber · Neutral", primary: "amber", neutral: "neutral" }
1752
- ], fn = "#4F46E5", Qa = "#A0743C", eo = [
1836
+ ], xn = "#4F46E5", io = "#A0743C", lo = [
1753
1837
  // Figma Swatch row sample colours
1754
1838
  { value: "pure", label: "Pure", colour: "#8E8E93" },
1755
1839
  { value: "subtle", label: "Subtle", colour: "#8A89A6" },
1756
1840
  { value: "warm", label: "Warm", colour: "#9C9389" }
1757
- ], gn = ["bg", "surface", "surface-raised", "text", "text-muted", "border"], to = {
1841
+ ], wn = ["bg", "surface", "surface-raised", "text", "text-muted", "border"], co = {
1758
1842
  // proposal
1759
1843
  bg: "#0F0F11",
1760
1844
  surface: "#18181B",
@@ -1762,56 +1846,56 @@ const Ja = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950], me = (t) => O
1762
1846
  text: "#F4F4F5",
1763
1847
  "text-muted": "#A1A1AA",
1764
1848
  border: "#2E2E33"
1765
- }, no = { bg: 4, surface: 2, "surface-raised": 2, text: 5, "text-muted": 12, border: 10 }, Z = (t) => /^#[0-9a-f]{6}$/i.test(t || ""), rt = (t) => [500, 600, 700].includes(Number(t.shade)) ? Number(t.shade) : 600, st = (t) => t[0].toUpperCase() + t.slice(1);
1766
- function mn(t) {
1767
- const e = (l) => (l /= 255, l <= 0.03928 ? l / 12.92 : ((l + 0.055) / 1.055) ** 2.4), [n, a, o] = [1, 3, 5].map((l) => e(parseInt(t.slice(l, l + 2), 16))), s = 0.2126 * n + 0.7152 * a + 0.0722 * o, r = 1.05 / (s + 0.05), i = (s + 0.05) / (98e-4 + 0.05);
1849
+ }, po = { bg: 4, surface: 2, "surface-raised": 2, text: 5, "text-muted": 12, border: 10 }, X = (e) => /^#[0-9a-f]{6}$/i.test(e || ""), lt = (e) => [500, 600, 700].includes(Number(e.shade)) ? Number(e.shade) : 600, dt = (e) => e[0].toUpperCase() + e.slice(1);
1850
+ function yn(e) {
1851
+ const t = (l) => (l /= 255, l <= 0.03928 ? l / 12.92 : ((l + 0.055) / 1.055) ** 2.4), [n, a, o] = [1, 3, 5].map((l) => t(parseInt(e.slice(l, l + 2), 16))), s = 0.2126 * n + 0.7152 * a + 0.0722 * o, r = 1.05 / (s + 0.05), i = (s + 0.05) / (98e-4 + 0.05);
1768
1852
  return r >= i ? "#FFFFFF" : "#18181B";
1769
1853
  }
1770
- const Be = {
1854
+ const He = {
1771
1855
  id: "colour",
1772
1856
  title: "Colour",
1773
1857
  hint: "Brand colour · neutral tint · mode",
1774
- uses: ["--twd-primary", "--twd-primary-hover", "--twd-on-primary", "--twd-focus", ...gn.map((t) => `--twd-${t}`)],
1775
- tokens(t) {
1776
- const e = t.colour || {}, n = {}, a = e.mode === "dark", o = ot[e.primary];
1777
- if (!Z(e.brand) && o) {
1778
- const i = rt(e);
1779
- n["--twd-primary"] = o[i], n["--twd-primary-hover"] = o[a ? i - 100 : i + 100], n["--twd-on-primary"] = mn(o[i]), n["--twd-focus"] = o[500];
1858
+ uses: ["--twd-primary", "--twd-primary-hover", "--twd-on-primary", "--twd-focus", ...wn.map((e) => `--twd-${e}`)],
1859
+ tokens(e) {
1860
+ const t = e.colour || {}, n = {}, a = t.mode === "dark", o = it[t.primary];
1861
+ if (!X(t.brand) && o) {
1862
+ const i = lt(t);
1863
+ n["--twd-primary"] = o[i], n["--twd-primary-hover"] = o[a ? i - 100 : i + 100], n["--twd-on-primary"] = yn(o[i]), n["--twd-focus"] = o[500];
1780
1864
  }
1781
- Z(e.brand) && (n["--twd-primary"] = e.brand, n["--twd-primary-hover"] = a ? `color-mix(in oklch, ${e.brand} 85%, white)` : `color-mix(in oklch, ${e.brand} 86%, black)`, n["--twd-on-primary"] = mn(e.brand), n["--twd-focus"] = e.brand);
1782
- const s = e.tint === "subtle" ? Z(e.brand) ? e.brand : F("--twd-primary") || fn : e.tint === "warm" ? Qa : null, r = at[e.neutral];
1865
+ X(t.brand) && (n["--twd-primary"] = t.brand, n["--twd-primary-hover"] = a ? `color-mix(in oklch, ${t.brand} 85%, white)` : `color-mix(in oklch, ${t.brand} 86%, black)`, n["--twd-on-primary"] = yn(t.brand), n["--twd-focus"] = t.brand);
1866
+ const s = t.tint === "subtle" ? X(t.brand) ? t.brand : F("--twd-primary") || xn : t.tint === "warm" ? io : null, r = st[t.neutral];
1783
1867
  if (r) {
1784
1868
  const i = a ? { bg: r[950], surface: r[900], "surface-raised": r[800], text: r[100], "text-muted": r[400], border: r[800] } : { bg: r[50], surface: "#ffffff", "surface-raised": "#ffffff", text: r[900], "text-muted": r[500], border: r[200] };
1785
- Object.entries(i).forEach(([l, p]) => {
1786
- n[`--twd-${l}`] = p;
1869
+ Object.entries(i).forEach(([l, d]) => {
1870
+ n[`--twd-${l}`] = d;
1787
1871
  });
1788
- } else (a || s) && gn.forEach((i) => {
1789
- const l = a ? to[i] : F(`--twd-${i}`);
1790
- l && (n[`--twd-${i}`] = s ? `color-mix(in oklch, ${l} ${100 - no[i]}%, ${s})` : l);
1872
+ } else (a || s) && wn.forEach((i) => {
1873
+ const l = a ? co[i] : F(`--twd-${i}`);
1874
+ l && (n[`--twd-${i}`] = s ? `color-mix(in oklch, ${l} ${100 - po[i]}%, ${s})` : l);
1791
1875
  });
1792
1876
  return n;
1793
1877
  },
1794
1878
  parts: {
1795
1879
  // ---- Tabbed layout (Colour tab): themes, then Tailwind fine-tuning ----
1796
- themeTiles(t, e, { label: n = "Theme" } = {}) {
1880
+ themeTiles(e, t, { label: n = "Theme" } = {}) {
1797
1881
  const a = (o) => {
1798
- const s = at[o.neutral], r = ot[o.primary];
1882
+ const s = st[o.neutral], r = it[o.primary];
1799
1883
  return `<span class="theme" style="--bg:${s[50]};--line:${s[200]};--ink:${s[900]};--soft:${s[500]};--pri:${r[600]}"><i><b></b><s></s><u></u></i></span><span class="palette">${[r[400], r[500], r[600], r[700], r[800], s[200], s[500], s[900]].map((i) => `<i style="background:${i}"></i>`).join("")}</span>`;
1800
1884
  };
1801
- t.append(V(e, {
1885
+ e.append(V(t, {
1802
1886
  section: "colour",
1803
1887
  key: "theme",
1804
1888
  label: n,
1805
1889
  columns: 2,
1806
1890
  className: "tiles-themes",
1807
- options: Ie.map((o) => ({ value: o.value, label: o.label, preview: a(o) })),
1891
+ options: Be.map((o) => ({ value: o.value, label: o.label, preview: a(o) })),
1808
1892
  current: (o) => {
1809
1893
  const s = o.colour || {};
1810
- return Z(s.brand) ? null : Ie.find((r) => r.primary === s.primary && r.neutral === s.neutral)?.value || null;
1894
+ return X(s.brand) ? null : Be.find((r) => r.primary === s.primary && r.neutral === s.neutral)?.value || null;
1811
1895
  },
1812
1896
  select: (o) => {
1813
- const s = Ie.find((r) => r.value === o);
1814
- e.setSection("colour", { primary: s.primary, neutral: s.neutral, shade: null, brand: null, tint: null });
1897
+ const s = Be.find((r) => r.value === o);
1898
+ t.setSection("colour", { primary: s.primary, neutral: s.neutral, shade: null, brand: null, tint: null });
1815
1899
  },
1816
1900
  valueText: (o, s) => {
1817
1901
  const r = s.colour || {};
@@ -1819,61 +1903,61 @@ const Be = {
1819
1903
  }
1820
1904
  }));
1821
1905
  },
1822
- primary(t, e, { label: n = "Primary" } = {}) {
1823
- const a = B(n), o = V(e, {
1906
+ primary(e, t, { label: n = "Primary" } = {}) {
1907
+ const a = U(n), o = V(t, {
1824
1908
  section: "colour",
1825
1909
  key: "primary",
1826
1910
  label: `${n} colour family`,
1827
1911
  columns: 9,
1828
1912
  className: "tiles-swatches",
1829
- options: Object.entries(ot).map(([i, l]) => ({ value: i, label: st(i), title: st(i), preview: `<span class="dot" style="background:${l[500]}"></span>` })),
1913
+ options: Object.entries(it).map(([i, l]) => ({ value: i, label: dt(i), title: dt(i), preview: `<span class="dot" style="background:${l[500]}"></span>` })),
1830
1914
  current: (i) => {
1831
1915
  const l = i.colour || {};
1832
- return Z(l.brand) ? null : l.primary || null;
1916
+ return X(l.brand) ? null : l.primary || null;
1833
1917
  },
1834
- select: (i) => e.setSection("colour", { primary: i, brand: null })
1918
+ select: (i) => t.setSection("colour", { primary: i, brand: null })
1835
1919
  });
1836
1920
  o.querySelector(".field-head").remove();
1837
- const s = ie({ label: "Shade", options: [500, 600, 700].map((i) => ({ value: String(i), label: String(i) })), onSelect: (i) => e.setSection("colour", { shade: Number(i) }) });
1921
+ const s = ce({ label: "Shade", options: [500, 600, 700].map((i) => ({ value: String(i), label: String(i) })), onSelect: (i) => t.setSection("colour", { shade: Number(i) }) });
1838
1922
  a.append(o, s.el);
1839
1923
  const r = () => {
1840
- const i = e.getState().colour || {};
1841
- s.setValue(String(rt(i))), a.setValue(Z(i.brand) ? i.brand.toLowerCase() : i.primary ? `${i.primary}-${rt(i)}` : "");
1924
+ const i = t.getState().colour || {};
1925
+ s.setValue(String(lt(i))), a.setValue(X(i.brand) ? i.brand.toLowerCase() : i.primary ? `${i.primary}-${lt(i)}` : "");
1842
1926
  };
1843
- r(), e.onChange(r), t.append(a.el);
1927
+ r(), t.onChange(r), e.append(a.el);
1844
1928
  },
1845
- neutralTiles(t, e, { label: n = "Neutral" } = {}) {
1846
- t.append(V(e, {
1929
+ neutralTiles(e, t, { label: n = "Neutral" } = {}) {
1930
+ e.append(V(t, {
1847
1931
  section: "colour",
1848
1932
  key: "neutral",
1849
1933
  label: n,
1850
1934
  columns: 5,
1851
1935
  className: "tiles-greys",
1852
- options: Object.entries(at).map(([a, o]) => ({ value: a, label: st(a), preview: `<span class="greys">${[o[50], o[200], o[500], o[900]].map((s) => `<i style="background:${s}"></i>`).join("")}</span>` })),
1853
- select: (a) => e.setSection("colour", { neutral: a, tint: null }),
1936
+ options: Object.entries(st).map(([a, o]) => ({ value: a, label: dt(a), preview: `<span class="greys">${[o[50], o[200], o[500], o[900]].map((s) => `<i style="background:${s}"></i>`).join("")}</span>` })),
1937
+ select: (a) => t.setSection("colour", { neutral: a, tint: null }),
1854
1938
  valueText: (a) => a || ""
1855
1939
  }));
1856
1940
  },
1857
- custom(t, e) {
1941
+ custom(e, t) {
1858
1942
  const n = document.createElement("details");
1859
1943
  n.className = "more more-custom", n.innerHTML = '<summary><span class="rainbow" aria-hidden="true"></span><span>Custom colour…</span><span class="muted">any hex</span></summary>';
1860
1944
  const a = document.createElement("div");
1861
- a.className = "more-body", n.append(a), Be.parts.brand(a, e, { label: "Brand" }), Z((e.getState().colour || {}).brand) && (n.open = !0), t.append(n);
1945
+ a.className = "more-body", n.append(a), He.parts.brand(a, t, { label: "Brand" }), X((t.getState().colour || {}).brand) && (n.open = !0), e.append(n);
1862
1946
  },
1863
- brand(t, e, { label: n = "Brand" } = {}) {
1864
- const a = B(n), o = Za({ label: "Brand colour", onInput: (r) => e.setSection("colour", { brand: r }) });
1947
+ brand(e, t, { label: n = "Brand" } = {}) {
1948
+ const a = U(n), o = oo({ label: "Brand colour", onInput: (r) => t.setSection("colour", { brand: r }) });
1865
1949
  a.append(o.el);
1866
- const s = () => o.setValue((e.getState().colour || {}).brand || (e.readToken || F)("--twd-primary") || fn);
1867
- s(), e.onChange(s), t.append(a.el);
1950
+ const s = () => o.setValue((t.getState().colour || {}).brand || (t.readToken || F)("--twd-primary") || xn);
1951
+ s(), t.onChange(s), e.append(a.el);
1868
1952
  },
1869
- neutral(t, e, { label: n = "Neutral" } = {}) {
1870
- const a = B(n), o = Xa({ label: "Neutral tint", options: eo, onSelect: (r) => e.setSection("colour", { tint: r }) });
1953
+ neutral(e, t, { label: n = "Neutral" } = {}) {
1954
+ const a = U(n), o = ro({ label: "Neutral tint", options: lo, onSelect: (r) => t.setSection("colour", { tint: r }) });
1871
1955
  a.append(o.el);
1872
- const s = () => o.setValue((e.getState().colour || {}).tint || "pure");
1873
- s(), e.onChange(s), t.append(a.el);
1956
+ const s = () => o.setValue((t.getState().colour || {}).tint || "pure");
1957
+ s(), t.onChange(s), e.append(a.el);
1874
1958
  },
1875
- mode(t, e, { label: n = "Mode" } = {}) {
1876
- t.append(ke(e, {
1959
+ mode(e, t, { label: n = "Mode" } = {}) {
1960
+ e.append($e(t, {
1877
1961
  section: "colour",
1878
1962
  key: "mode",
1879
1963
  label: n,
@@ -1882,15 +1966,15 @@ const Be = {
1882
1966
  }));
1883
1967
  }
1884
1968
  },
1885
- render(t, e) {
1886
- ["brand", "neutral", "mode"].forEach((n) => this.parts[n](t, e));
1969
+ render(e, t) {
1970
+ ["brand", "neutral", "mode"].forEach((n) => this.parts[n](e, t));
1887
1971
  }
1888
- }, Oe = (t, e = "var(--twd-surface)") => `color-mix(in oklch, var(--twd-primary) ${t}%, ${e})`, ao = {
1972
+ }, Ne = (e, t = "var(--twd-surface)") => `color-mix(in oklch, var(--twd-primary) ${e}%, ${t})`, uo = {
1889
1973
  // proposal recipes; Solid leaves tokens.css defaults
1890
- soft: { bg: Oe(14), fg: "var(--twd-primary)", border: "transparent", hover: Oe(22) },
1891
- outline: { bg: "transparent", fg: "var(--twd-primary)", border: "var(--twd-primary)", hover: Oe(8, "transparent") },
1892
- ghost: { bg: "transparent", fg: "var(--twd-primary)", border: "transparent", hover: Oe(10, "transparent") }
1893
- }, oo = { small: { height: 0.8, pad: 0.75 }, large: { height: 1.2, pad: 1.25 } }, qn = Bn({
1974
+ soft: { bg: Ne(14), fg: "var(--twd-primary)", border: "transparent", hover: Ne(22) },
1975
+ outline: { bg: "transparent", fg: "var(--twd-primary)", border: "var(--twd-primary)", hover: Ne(8, "transparent") },
1976
+ ghost: { bg: "transparent", fg: "var(--twd-primary)", border: "transparent", hover: Ne(10, "transparent") }
1977
+ }, ho = { small: { height: 0.8, pad: 0.75 }, large: { height: 1.2, pad: 1.25 } }, Wn = _n({
1894
1978
  id: "buttons",
1895
1979
  title: "Buttons",
1896
1980
  hint: "Style · corners · size",
@@ -1909,15 +1993,15 @@ const Be = {
1909
1993
  // Figma: "8px"
1910
1994
  { value: "pill", label: "Pill", radius: 999 }
1911
1995
  ],
1912
- extraTokens(t) {
1913
- const e = {}, n = ao[t.style];
1996
+ extraTokens(e) {
1997
+ const t = {}, n = uo[e.style];
1914
1998
  n && Object.entries(n).forEach(([r, i]) => {
1915
- e[`--twd-button-${r}`] = i;
1999
+ t[`--twd-button-${r}`] = i;
1916
2000
  });
1917
- const a = oo[t.size];
1918
- if (!a) return e;
1919
- const o = ye(F("--twd-control-height"), a.height), s = ye(F("--twd-control-pad-x"), a.pad);
1920
- return o && (e["--twd-control-height"] = o), s && (e["--twd-control-pad-x"] = s), e;
2001
+ const a = ho[e.size];
2002
+ if (!a) return t;
2003
+ const o = Se(F("--twd-control-height"), a.height), s = Se(F("--twd-control-pad-x"), a.pad);
2004
+ return o && (t["--twd-control-height"] = o), s && (t["--twd-control-pad-x"] = s), t;
1921
2005
  },
1922
2006
  extra: [
1923
2007
  {
@@ -1925,23 +2009,23 @@ const Be = {
1925
2009
  label: "Style",
1926
2010
  fallback: "solid",
1927
2011
  columns: 4,
1928
- preview: (t) => `<span class="shape shape-button style-${t}"></span>`,
2012
+ preview: (e) => `<span class="shape shape-button style-${e}"></span>`,
1929
2013
  options: [{ value: "solid", label: "Solid" }, { value: "soft", label: "Soft" }, { value: "outline", label: "Outline" }, { value: "ghost", label: "Ghost" }]
1930
2014
  },
1931
2015
  {
1932
2016
  key: "size",
1933
2017
  label: "Size",
1934
2018
  fallback: "medium",
1935
- preview: (t) => `<span class="shape shape-button size-${t}"></span>`,
2019
+ preview: (e) => `<span class="shape shape-button size-${e}"></span>`,
1936
2020
  options: [{ value: "small", label: "Small" }, { value: "medium", label: "Medium" }, { value: "large", label: "Large" }]
1937
2021
  }
1938
2022
  ]
1939
- }), ro = {
2023
+ }), fo = {
1940
2024
  // proposal recipes; Filled leaves tokens.css defaults
1941
2025
  outlined: { bg: "transparent", border: "color-mix(in oklch, var(--twd-border) 60%, var(--twd-text))", shadow: "none" },
1942
2026
  elevated: { bg: "var(--twd-surface-raised)", border: "transparent", shadow: "var(--twd-shadow-md)" },
1943
2027
  tinted: { bg: "color-mix(in oklch, var(--twd-primary) 8%, var(--twd-surface))", border: "color-mix(in oklch, var(--twd-primary) 25%, var(--twd-surface))", shadow: "none" }
1944
- }, vt = Bn({
2028
+ }, St = _n({
1945
2029
  id: "cards",
1946
2030
  title: "Cards",
1947
2031
  hint: "Style · corners · border",
@@ -1960,15 +2044,15 @@ const Be = {
1960
2044
  { value: "large", label: "Large", radius: 20 }
1961
2045
  // proposal (cards don't go fully pill)
1962
2046
  ],
1963
- extraTokens(t) {
1964
- const e = {}, n = ro[t.style];
2047
+ extraTokens(e) {
2048
+ const t = {}, n = fo[e.style];
1965
2049
  if (n && Object.entries(n).forEach(([a, o]) => {
1966
- e[`--twd-card-${a}`] = o;
1967
- }), t.border === "none" && (e["--twd-border-width-container"] = "0px"), t.border === "thick") {
1968
- const a = ye(F("--twd-border-width-container"), 2);
1969
- a && (e["--twd-border-width-container"] = a);
2050
+ t[`--twd-card-${a}`] = o;
2051
+ }), e.border === "none" && (t["--twd-border-width-container"] = "0px"), e.border === "thick") {
2052
+ const a = Se(F("--twd-border-width-container"), 2);
2053
+ a && (t["--twd-border-width-container"] = a);
1970
2054
  }
1971
- return e;
2055
+ return t;
1972
2056
  },
1973
2057
  extra: [
1974
2058
  {
@@ -1976,49 +2060,49 @@ const Be = {
1976
2060
  label: "Style",
1977
2061
  fallback: "filled",
1978
2062
  columns: 4,
1979
- preview: (t) => `<span class="shape shape-card style-${t}"></span>`,
2063
+ preview: (e) => `<span class="shape shape-card style-${e}"></span>`,
1980
2064
  options: [{ value: "filled", label: "Filled" }, { value: "outlined", label: "Outlined" }, { value: "elevated", label: "Elevated" }, { value: "tinted", label: "Tinted" }]
1981
2065
  },
1982
2066
  {
1983
2067
  key: "border",
1984
2068
  label: "Border",
1985
2069
  fallback: "thin",
1986
- preview: (t) => `<span class="shape shape-card border-${t}"></span>`,
2070
+ preview: (e) => `<span class="shape shape-card border-${e}"></span>`,
1987
2071
  options: [{ value: "none", label: "None" }, { value: "thin", label: "Thin" }, { value: "thick", label: "Thick" }]
1988
2072
  }
1989
2073
  ]
1990
- }), oe = 60, it = {
2074
+ }), ie = 60, ct = {
1991
2075
  soft: { sm: [0, 1, 2, 0, 0.06], md: [0, 4, 12, 0, 0.08], lg: [0, 12, 32, 0, 0.12] },
1992
2076
  // = tokens.css
1993
2077
  crisp: { sm: [0, 1, 1, 0, 0.12], md: [0, 2, 4, 0, 0.14], lg: [0, 4, 8, 0, 0.16] },
1994
2078
  bold: { sm: [2, 2, 0, 0, 0.85], md: [3, 3, 0, 0, 0.85], lg: [5, 5, 0, 0, 0.85] }
1995
- }, Pe = ([t, e, n, a, o], s) => {
2079
+ }, je = ([e, t, n, a, o], s) => {
1996
2080
  const r = Math.min(1, +(o * s).toFixed(3));
1997
- return r <= 0 ? "none" : `${t}px ${e}px ${n}px ${a}px rgb(0 0 0 / ${r})`;
1998
- }, yt = {
2081
+ return r <= 0 ? "none" : `${e}px ${t}px ${n}px ${a}px rgb(0 0 0 / ${r})`;
2082
+ }, $t = {
1999
2083
  id: "depth",
2000
2084
  title: "Depth",
2001
2085
  hint: "Flat · soft · crisp · bold",
2002
2086
  uses: ["--twd-shadow-sm", "--twd-shadow-md", "--twd-shadow-lg"],
2003
- tokens(t) {
2004
- const e = t.depth || {}, n = e.style || "soft", a = typeof e.intensity == "number" ? Math.min(100, Math.max(0, e.intensity)) : oe;
2087
+ tokens(e) {
2088
+ const t = e.depth || {}, n = t.style || "soft", a = typeof t.intensity == "number" ? Math.min(100, Math.max(0, t.intensity)) : ie;
2005
2089
  if (n === "flat")
2006
2090
  return { "--twd-shadow-sm": "none", "--twd-shadow-md": "none", "--twd-shadow-lg": "none" };
2007
- const o = it[n];
2091
+ const o = ct[n];
2008
2092
  if (!o) return {};
2009
- if (n === "soft" && a === oe) return {};
2010
- const s = a / oe;
2093
+ if (n === "soft" && a === ie) return {};
2094
+ const s = a / ie;
2011
2095
  return {
2012
- "--twd-shadow-sm": Pe(o.sm, s),
2013
- "--twd-shadow-md": Pe(o.md, s),
2014
- "--twd-shadow-lg": Pe(o.lg, s)
2096
+ "--twd-shadow-sm": je(o.sm, s),
2097
+ "--twd-shadow-md": je(o.md, s),
2098
+ "--twd-shadow-lg": je(o.lg, s)
2015
2099
  };
2016
2100
  },
2017
2101
  parts: {
2018
2102
  // Tabbed layout: each style as a small card wearing that shadow.
2019
- styleTiles(t, e, { label: n = "Style" } = {}) {
2020
- const a = (o) => `<span class="shape shape-card shadow-${o}" style="box-shadow:${it[o] ? Pe(it[o].md, 1) : "none"}"></span>`;
2021
- t.append(V(e, {
2103
+ styleTiles(e, t, { label: n = "Style" } = {}) {
2104
+ const a = (o) => `<span class="shape shape-card shadow-${o}" style="box-shadow:${ct[o] ? je(ct[o].md, 1) : "none"}"></span>`;
2105
+ e.append(V(t, {
2022
2106
  section: "depth",
2023
2107
  key: "style",
2024
2108
  label: n,
@@ -2027,8 +2111,8 @@ const Be = {
2027
2111
  options: ["flat", "soft", "crisp", "bold"].map((o) => ({ value: o, label: o[0].toUpperCase() + o.slice(1), preview: a(o) }))
2028
2112
  }));
2029
2113
  },
2030
- style(t, e, { label: n = "Style" } = {}) {
2031
- t.append(ke(e, {
2114
+ style(e, t, { label: n = "Style" } = {}) {
2115
+ e.append($e(t, {
2032
2116
  section: "depth",
2033
2117
  key: "style",
2034
2118
  label: n,
@@ -2036,160 +2120,160 @@ const Be = {
2036
2120
  options: [{ value: "flat", label: "Flat" }, { value: "soft", label: "Soft" }, { value: "crisp", label: "Crisp" }, { value: "bold", label: "Bold" }]
2037
2121
  }));
2038
2122
  },
2039
- intensity(t, e, { label: n = "Intensity" } = {}) {
2040
- t.append(qa(e, { section: "depth", key: "intensity", label: n, min: 0, max: 100, fallback: oe, format: (a) => `${a}%` }));
2123
+ intensity(e, t, { label: n = "Intensity" } = {}) {
2124
+ e.append(Xa(t, { section: "depth", key: "intensity", label: n, min: 0, max: 100, fallback: ie, format: (a) => `${a}%` }));
2041
2125
  }
2042
2126
  },
2043
- render(t, e) {
2044
- Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(t, e));
2127
+ render(e, t) {
2128
+ Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(e, t));
2045
2129
  }
2046
- }, so = (t) => Math.min(1, Math.max(0, t)), bn = (t) => Math.round(t / 50) * 50, lt = (t) => `${+t.toFixed(1)}%`;
2047
- function Et(t = {}) {
2048
- return typeof t.bold == "number" && isFinite(t.bold) && t.bold !== 0.5 ? so(t.bold) : null;
2130
+ }, go = (e) => Math.min(1, Math.max(0, e)), vn = (e) => Math.round(e / 50) * 50, pt = (e) => `${+e.toFixed(1)}%`;
2131
+ function Tt(e = {}) {
2132
+ return typeof e.bold == "number" && isFinite(e.bold) && e.bold !== 0.5 ? go(e.bold) : null;
2049
2133
  }
2050
- const Fe = (t, e, n) => (t.tokens(e) || {})[n] || F(n), io = {
2134
+ const Re = (e, t, n) => (e.tokens(t) || {})[n] || F(n), mo = {
2051
2135
  id: "character",
2052
2136
  title: "Character",
2053
2137
  hint: "Subtle ↔ Bold",
2054
2138
  uses: [],
2055
2139
  // set from the Simple page only
2056
- tokens(t) {
2057
- const e = Et(t.character);
2058
- if (e === null) return {};
2059
- const n = {}, a = 2 * e - 1, o = Math.max(0, a), s = Math.max(0, -a);
2060
- n["--twd-weight-heading"] = String(bn(600 + 200 * a)), n["--twd-weight-strong"] = String(bn(600 + 100 * a));
2061
- const r = Fe(Be, t, "--twd-border");
2062
- if (s && (n["--twd-border"] = `color-mix(in oklch, ${r} ${lt(100 - 50 * s)}, var(--twd-bg))`), o) {
2063
- n["--twd-border"] = `color-mix(in oklch, ${r} ${lt(100 - 90 * o)}, var(--twd-text))`;
2064
- const l = Fe(Be, t, "--twd-text-muted");
2065
- n["--twd-text-muted"] = `color-mix(in oklch, ${l} ${lt(100 - 35 * o)}, var(--twd-text))`, ["--twd-border-width", "--twd-border-width-container"].forEach((p) => {
2066
- const c = p === "--twd-border-width-container" ? Fe(vt, t, p) : F(p), h = parseFloat(c);
2067
- isNaN(h) || (n[p] = `${Math.round(h * (1 + o))}px`);
2068
- }), [[qn, "--twd-radius-control"], [vt, "--twd-radius-container"]].forEach(([p, c]) => {
2069
- const h = parseFloat(Fe(p, t, c));
2070
- !isNaN(h) && h < 999 && (n[c] = ye(`${h}px`, 1 - 0.5 * o));
2140
+ tokens(e) {
2141
+ const t = Tt(e.character);
2142
+ if (t === null) return {};
2143
+ const n = {}, a = 2 * t - 1, o = Math.max(0, a), s = Math.max(0, -a);
2144
+ n["--twd-weight-heading"] = String(vn(600 + 200 * a)), n["--twd-weight-strong"] = String(vn(600 + 100 * a));
2145
+ const r = Re(He, e, "--twd-border");
2146
+ if (s && (n["--twd-border"] = `color-mix(in oklch, ${r} ${pt(100 - 50 * s)}, var(--twd-bg))`), o) {
2147
+ n["--twd-border"] = `color-mix(in oklch, ${r} ${pt(100 - 90 * o)}, var(--twd-text))`;
2148
+ const l = Re(He, e, "--twd-text-muted");
2149
+ n["--twd-text-muted"] = `color-mix(in oklch, ${l} ${pt(100 - 35 * o)}, var(--twd-text))`, ["--twd-border-width", "--twd-border-width-container"].forEach((d) => {
2150
+ const p = d === "--twd-border-width-container" ? Re(St, e, d) : F(d), u = parseFloat(p);
2151
+ isNaN(u) || (n[d] = `${Math.round(u * (1 + o))}px`);
2152
+ }), [[Wn, "--twd-radius-control"], [St, "--twd-radius-container"]].forEach(([d, p]) => {
2153
+ const u = parseFloat(Re(d, e, p));
2154
+ !isNaN(u) && u < 999 && (n[p] = Se(`${u}px`, 1 - 0.5 * o));
2071
2155
  });
2072
2156
  }
2073
- const i = t.depth || {};
2157
+ const i = e.depth || {};
2074
2158
  if (!i.style) {
2075
- const l = typeof i.intensity == "number" ? i.intensity : oe, p = s ? yt.tokens({ depth: { style: "soft", intensity: l * (1 - s) } }) : yt.tokens({ depth: { style: "bold", intensity: oe * o } });
2076
- Object.assign(n, p);
2159
+ const l = typeof i.intensity == "number" ? i.intensity : ie, d = s ? $t.tokens({ depth: { style: "soft", intensity: l * (1 - s) } }) : $t.tokens({ depth: { style: "bold", intensity: ie * o } });
2160
+ Object.assign(n, d);
2077
2161
  }
2078
2162
  return n;
2079
2163
  },
2080
- describe: (t, e) => t === "bold" ? { label: "Subtle ↔ Bold", value: `${Math.round(e * 100)}%` } : null
2081
- }, lo = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>', co = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>';
2082
- let po = 0;
2083
- function uo({ label: t, options: e, onSelect: n, placeholder: a, onOpen: o }) {
2084
- const s = `twd-fonts-${++po}`, r = document.createElement("div");
2164
+ describe: (e, t) => e === "bold" ? { label: "Subtle ↔ Bold", value: `${Math.round(t * 100)}%` } : null
2165
+ }, bo = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>', xo = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>';
2166
+ let wo = 0;
2167
+ function yo({ label: e, options: t, onSelect: n, placeholder: a, onOpen: o }) {
2168
+ const s = `twd-fonts-${++wo}`, r = document.createElement("div");
2085
2169
  r.className = "font-select";
2086
2170
  const i = document.createElement("button");
2087
2171
  i.type = "button", i.className = "font-trigger", i.setAttribute("aria-haspopup", "listbox"), i.setAttribute("aria-expanded", "false"), i.setAttribute("aria-controls", s), i.innerHTML = `
2088
2172
  <span class="font-aa" aria-hidden="true">Aa</span>
2089
2173
  <span class="font-name"></span>
2090
2174
  <span class="font-fonts"></span>
2091
- <span class="font-chevron">${lo}</span>`;
2175
+ <span class="font-chevron">${bo}</span>`;
2092
2176
  const l = document.createElement("div");
2093
- l.className = "font-menu", l.id = s, l.setAttribute("role", "listbox"), l.setAttribute("aria-label", t), l.hidden = !0;
2094
- const p = e.map((u) => {
2095
- const v = document.createElement("div");
2096
- return v.className = "font-option", v.setAttribute("role", "option"), v.tabIndex = -1, v.dataset.value = u.value, v.innerHTML = `
2097
- <span class="font-aa" style="font-family:${u.preview}" aria-hidden="true">Aa</span>
2098
- <span class="font-text"><span class="font-name">${u.name}</span><span class="font-fonts">${u.fonts}</span></span>
2099
- <span class="font-check">${co}</span>`, v.addEventListener("click", () => b(u.value)), v;
2177
+ l.className = "font-menu", l.id = s, l.setAttribute("role", "listbox"), l.setAttribute("aria-label", e), l.hidden = !0;
2178
+ const d = t.map((h) => {
2179
+ const y = document.createElement("div");
2180
+ return y.className = "font-option", y.setAttribute("role", "option"), y.tabIndex = -1, y.dataset.value = h.value, y.innerHTML = `
2181
+ <span class="font-aa" style="font-family:${h.preview}" aria-hidden="true">Aa</span>
2182
+ <span class="font-text"><span class="font-name">${h.name}</span><span class="font-fonts">${h.fonts}</span></span>
2183
+ <span class="font-check">${xo}</span>`, y.addEventListener("click", () => b(h.value)), y;
2100
2184
  });
2101
- l.append(...p), r.append(i, l);
2102
- let c = null;
2103
- function h(u) {
2104
- const v = e.find((E) => E.value === u), L = v || a || e[0];
2105
- c = v ? v.value : a ? null : e[0].value, i.querySelector(".font-name").textContent = L.name, i.querySelector(".font-fonts").textContent = L.fonts, i.querySelector(".font-aa").style.fontFamily = L.preview, i.setAttribute("aria-label", `${t}: ${L.name}, ${L.fonts}`), p.forEach((E) => E.setAttribute("aria-selected", String(E.dataset.value === c)));
2185
+ l.append(...d), r.append(i, l);
2186
+ let p = null;
2187
+ function u(h) {
2188
+ const y = t.find((E) => E.value === h), L = y || a || t[0];
2189
+ p = y ? y.value : a ? null : t[0].value, i.querySelector(".font-name").textContent = L.name, i.querySelector(".font-fonts").textContent = L.fonts, i.querySelector(".font-aa").style.fontFamily = L.preview, i.setAttribute("aria-label", `${e}: ${L.name}, ${L.fonts}`), d.forEach((E) => E.setAttribute("aria-selected", String(E.dataset.value === p)));
2106
2190
  }
2107
- function y() {
2108
- const u = i.getBoundingClientRect(), v = l.offsetHeight, E = window.innerHeight - u.bottom - 8 >= v ? u.bottom + 4 : Math.max(8, u.top - 4 - v);
2109
- l.style.top = `${E}px`, l.style.left = `${u.left}px`, l.style.width = `${u.width}px`;
2191
+ function v() {
2192
+ const h = i.getBoundingClientRect(), y = l.offsetHeight, E = window.innerHeight - h.bottom - 8 >= y ? h.bottom + 4 : Math.max(8, h.top - 4 - y);
2193
+ l.style.top = `${E}px`, l.style.left = `${h.left}px`, l.style.width = `${h.width}px`;
2110
2194
  }
2111
2195
  function f() {
2112
- l.hidden && (l.hidden = !1, i.setAttribute("aria-expanded", "true"), o && o(), y(), (p.find((u) => u.dataset.value === c) || p[0]).focus(), setTimeout(() => document.addEventListener("pointerdown", x, !0)), window.addEventListener("resize", m), r.closest(".body")?.addEventListener("scroll", m, { once: !0 }));
2196
+ l.hidden && (l.hidden = !1, i.setAttribute("aria-expanded", "true"), o && o(), v(), (d.find((h) => h.dataset.value === p) || d[0]).focus(), setTimeout(() => document.addEventListener("pointerdown", x, !0)), window.addEventListener("resize", m), r.closest(".body")?.addEventListener("scroll", m, { once: !0 }));
2113
2197
  }
2114
- function m(u) {
2115
- l.hidden || (l.hidden = !0, i.setAttribute("aria-expanded", "false"), document.removeEventListener("pointerdown", x, !0), window.removeEventListener("resize", m), u === !0 && i.focus());
2198
+ function m(h) {
2199
+ l.hidden || (l.hidden = !0, i.setAttribute("aria-expanded", "false"), document.removeEventListener("pointerdown", x, !0), window.removeEventListener("resize", m), h === !0 && i.focus());
2116
2200
  }
2117
- function x(u) {
2118
- u.composedPath().includes(r) || m();
2201
+ function x(h) {
2202
+ h.composedPath().includes(r) || m();
2119
2203
  }
2120
- function b(u) {
2121
- u !== c && (h(u), n(u)), m(!0);
2204
+ function b(h) {
2205
+ h !== p && (u(h), n(h)), m(!0);
2122
2206
  }
2123
- return i.addEventListener("click", () => l.hidden ? f() : m(!0)), i.addEventListener("keydown", (u) => {
2124
- (u.key === "ArrowDown" || u.key === "ArrowUp") && (u.preventDefault(), f());
2125
- }), l.addEventListener("keydown", (u) => {
2126
- const v = p.indexOf(u.target);
2207
+ return i.addEventListener("click", () => l.hidden ? f() : m(!0)), i.addEventListener("keydown", (h) => {
2208
+ (h.key === "ArrowDown" || h.key === "ArrowUp") && (h.preventDefault(), f());
2209
+ }), l.addEventListener("keydown", (h) => {
2210
+ const y = d.indexOf(h.target);
2127
2211
  let L = null;
2128
- if (u.key === "ArrowDown") L = Math.min(p.length - 1, v + 1);
2129
- else if (u.key === "ArrowUp") L = Math.max(0, v - 1);
2130
- else if (u.key === "Home") L = 0;
2131
- else if (u.key === "End") L = p.length - 1;
2132
- else if (u.key === "Enter" || u.key === " ") {
2133
- u.preventDefault(), b(u.target.dataset.value);
2212
+ if (h.key === "ArrowDown") L = Math.min(d.length - 1, y + 1);
2213
+ else if (h.key === "ArrowUp") L = Math.max(0, y - 1);
2214
+ else if (h.key === "Home") L = 0;
2215
+ else if (h.key === "End") L = d.length - 1;
2216
+ else if (h.key === "Enter" || h.key === " ") {
2217
+ h.preventDefault(), b(h.target.dataset.value);
2134
2218
  return;
2135
- } else if (u.key === "Escape") {
2136
- u.preventDefault(), u.stopPropagation(), m(!0);
2219
+ } else if (h.key === "Escape") {
2220
+ h.preventDefault(), h.stopPropagation(), m(!0);
2137
2221
  return;
2138
- } else if (u.key === "Tab") {
2222
+ } else if (h.key === "Tab") {
2139
2223
  m();
2140
2224
  return;
2141
2225
  }
2142
- L !== null && (u.preventDefault(), p[L].focus());
2143
- }), h(a ? null : e[0].value), { el: r, setValue: h };
2226
+ L !== null && (h.preventDefault(), d[L].focus());
2227
+ }), u(a ? null : t[0].value), { el: r, setValue: u };
2144
2228
  }
2145
- const I = 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif', Ne = 'Georgia, "Times New Roman", serif', X = [
2229
+ const I = 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif', ze = 'Georgia, "Times New Roman", serif', J = [
2146
2230
  { value: "neutral", name: "Neutral", fonts: "Inter · Inter", heading: `"Inter", ${I}`, body: `"Inter", ${I}`, load: ["Inter:wght@400;500;600;700"] },
2147
2231
  { value: "modern", name: "Modern", fonts: "Geist · Geist", heading: `"Geist", ${I}`, body: `"Geist", ${I}`, load: ["Geist:wght@400;500;600;700"] },
2148
- { value: "editorial", name: "Editorial", fonts: "Fraunces · Inter", heading: `"Fraunces", ${Ne}`, body: `"Inter", ${I}`, load: ["Fraunces:wght@400;600;700", "Inter:wght@400;500;600;700"] },
2232
+ { value: "editorial", name: "Editorial", fonts: "Fraunces · Inter", heading: `"Fraunces", ${ze}`, body: `"Inter", ${I}`, load: ["Fraunces:wght@400;600;700", "Inter:wght@400;500;600;700"] },
2149
2233
  { value: "technical", name: "Technical", fonts: "Space Grotesk · DM Sans", heading: `"Space Grotesk", ${I}`, body: `"DM Sans", ${I}`, load: ["Space+Grotesk:wght@500;600;700", "DM+Sans:wght@400;500;600;700"] },
2150
- { value: "classic", name: "Classic", fonts: "Playfair · DM Sans", heading: `"Playfair Display", ${Ne}`, body: `"DM Sans", ${I}`, load: ["Playfair+Display:wght@600;700", "DM+Sans:wght@400;500;600;700"] },
2151
- { value: "plex", name: "Plex", fonts: "Plex Serif · Plex Sans", heading: `"IBM Plex Serif", ${Ne}`, body: `"IBM Plex Sans", ${I}`, load: ["IBM+Plex+Serif:wght@500;600;700", "IBM+Plex+Sans:wght@400;500;600"] },
2152
- { value: "elegant", name: "Elegant", fonts: "Instrument Serif · Inter", heading: `"Instrument Serif", ${Ne}`, body: `"Inter", ${I}`, load: ["Instrument+Serif", "Inter:wght@400;500;600;700"] },
2234
+ { value: "classic", name: "Classic", fonts: "Playfair · DM Sans", heading: `"Playfair Display", ${ze}`, body: `"DM Sans", ${I}`, load: ["Playfair+Display:wght@600;700", "DM+Sans:wght@400;500;600;700"] },
2235
+ { value: "plex", name: "Plex", fonts: "Plex Serif · Plex Sans", heading: `"IBM Plex Serif", ${ze}`, body: `"IBM Plex Sans", ${I}`, load: ["IBM+Plex+Serif:wght@500;600;700", "IBM+Plex+Sans:wght@400;500;600"] },
2236
+ { value: "elegant", name: "Elegant", fonts: "Instrument Serif · Inter", heading: `"Instrument Serif", ${ze}`, body: `"Inter", ${I}`, load: ["Instrument+Serif", "Inter:wght@400;500;600;700"] },
2153
2237
  { value: "friendly", name: "Friendly", fonts: "Manrope · Manrope", heading: `"Manrope", ${I}`, body: `"Manrope", ${I}`, load: ["Manrope:wght@400;500;600;700"] }
2154
- ], be = { compact: 1.125, balanced: 1.2, expressive: 1.333 }, xn = { xs: -2, sm: -1, base: 0, lg: 1, xl: 2, "2xl": 3, "3xl": 4 }, wn = /* @__PURE__ */ new Set();
2155
- function dt(t) {
2156
- const e = t.filter((a) => !wn.has(a));
2157
- if (!e.length) return;
2158
- e.forEach((a) => wn.add(a));
2238
+ ], we = { compact: 1.125, balanced: 1.2, expressive: 1.333 }, kn = { xs: -2, sm: -1, base: 0, lg: 1, xl: 2, "2xl": 3, "3xl": 4 }, Sn = /* @__PURE__ */ new Set();
2239
+ function ut(e) {
2240
+ const t = e.filter((a) => !Sn.has(a));
2241
+ if (!t.length) return;
2242
+ t.forEach((a) => Sn.add(a));
2159
2243
  const n = document.createElement("link");
2160
- n.rel = "stylesheet", n.href = `https://fonts.googleapis.com/css2?${e.map((a) => `family=${a}`).join("&")}&display=swap`, n.dataset.twiddle = "fonts", document.head.appendChild(n);
2244
+ n.rel = "stylesheet", n.href = `https://fonts.googleapis.com/css2?${t.map((a) => `family=${a}`).join("&")}&display=swap`, n.dataset.twiddle = "fonts", document.head.appendChild(n);
2161
2245
  }
2162
- const ho = {
2246
+ const vo = {
2163
2247
  id: "typography",
2164
2248
  title: "Typography",
2165
2249
  hint: "Font pairing · base size · scale",
2166
- uses: ["--twd-font-heading", "--twd-font-body", ...Object.keys(xn).map((t) => `--twd-text-${t}`)],
2167
- tokens(t) {
2168
- const e = t.typography || {}, n = {}, a = X.find((o) => o.value === e.font);
2169
- if (a && (dt(a.load), n["--twd-font-heading"] = a.heading, n["--twd-font-body"] = a.body), e.base || e.scale) {
2170
- const o = Number(e.base) || 16, s = be[e.scale] || be.balanced;
2171
- Object.entries(xn).forEach(([r, i]) => {
2250
+ uses: ["--twd-font-heading", "--twd-font-body", ...Object.keys(kn).map((e) => `--twd-text-${e}`)],
2251
+ tokens(e) {
2252
+ const t = e.typography || {}, n = {}, a = J.find((o) => o.value === t.font);
2253
+ if (a && (ut(a.load), n["--twd-font-heading"] = a.heading, n["--twd-font-body"] = a.body), t.base || t.scale) {
2254
+ const o = Number(t.base) || 16, s = we[t.scale] || we.balanced;
2255
+ Object.entries(kn).forEach(([r, i]) => {
2172
2256
  n[`--twd-text-${r}`] = `${+(o * s ** i / 16).toFixed(3)}rem`;
2173
2257
  });
2174
2258
  }
2175
2259
  return n;
2176
2260
  },
2177
2261
  parts: {
2178
- fonts(t, e, { label: n = "Fonts" } = {}) {
2179
- const a = B(n), o = uo({
2262
+ fonts(e, t, { label: n = "Fonts" } = {}) {
2263
+ const a = U(n), o = yo({
2180
2264
  label: "Font pairing",
2181
- options: X.map((r) => ({ value: r.value, name: r.name, fonts: r.fonts, preview: r.heading })),
2265
+ options: J.map((r) => ({ value: r.value, name: r.name, fonts: r.fonts, preview: r.heading })),
2182
2266
  placeholder: { name: "Default", fonts: "Prototype fonts", preview: I },
2183
2267
  // Load every pairing's fonts when the list opens, so the "Aa" previews are real.
2184
- onOpen: () => dt([...new Set(X.flatMap((r) => r.load))]),
2185
- onSelect: (r) => e.setSection("typography", { font: r })
2268
+ onOpen: () => ut([...new Set(J.flatMap((r) => r.load))]),
2269
+ onSelect: (r) => t.setSection("typography", { font: r })
2186
2270
  });
2187
2271
  a.append(o.el);
2188
- const s = () => o.setValue((e.getState().typography || {}).font || null);
2189
- s(), e.onChange(s), t.append(a.el);
2272
+ const s = () => o.setValue((t.getState().typography || {}).font || null);
2273
+ s(), t.onChange(s), e.append(a.el);
2190
2274
  },
2191
- base(t, e, { label: n = "Base size" } = {}) {
2192
- t.append(ke(e, {
2275
+ base(e, t, { label: n = "Base size" } = {}) {
2276
+ e.append($e(t, {
2193
2277
  section: "typography",
2194
2278
  key: "base",
2195
2279
  label: n,
@@ -2200,8 +2284,8 @@ const ho = {
2200
2284
  },
2201
2285
  // Tabbed layout: pairings as tiles, each "Aa" in its own heading font.
2202
2286
  // The fonts load (from Google Fonts) only once the tiles are on screen.
2203
- fontTiles(t, e, { label: n = "Fonts" } = {}) {
2204
- const a = (i) => i.replace(/"/g, "&quot;"), o = (i) => `<span class="tile-aa" style="font-family:${a(i)}">Aa</span>`, s = V(e, {
2287
+ fontTiles(e, t, { label: n = "Fonts" } = {}) {
2288
+ const a = (i) => i.replace(/"/g, "&quot;"), o = (i) => `<span class="tile-aa" style="font-family:${a(i)}">Aa</span>`, s = V(t, {
2205
2289
  section: "typography",
2206
2290
  key: "font",
2207
2291
  label: n,
@@ -2209,165 +2293,165 @@ const ho = {
2209
2293
  className: "tiles-fonts",
2210
2294
  options: [
2211
2295
  { value: "default", label: "Prototype fonts", sub: "Default", preview: o(I), wide: !0 },
2212
- ...X.map((i) => ({ value: i.value, label: i.name, sub: i.fonts, preview: o(i.heading) }))
2296
+ ...J.map((i) => ({ value: i.value, label: i.name, sub: i.fonts, preview: o(i.heading) }))
2213
2297
  ],
2214
2298
  current: (i) => (i.typography || {}).font || "default",
2215
- select: (i) => e.setSection("typography", { font: i === "default" ? null : i }),
2216
- valueText: (i) => i === "default" ? "Default" : X.find((l) => l.value === i)?.name || ""
2299
+ select: (i) => t.setSection("typography", { font: i === "default" ? null : i }),
2300
+ valueText: (i) => i === "default" ? "Default" : J.find((l) => l.value === i)?.name || ""
2217
2301
  }), r = new IntersectionObserver((i) => {
2218
- i.some((l) => l.isIntersecting) && (dt([...new Set(X.flatMap((l) => l.load))]), r.disconnect());
2302
+ i.some((l) => l.isIntersecting) && (ut([...new Set(J.flatMap((l) => l.load))]), r.disconnect());
2219
2303
  });
2220
- r.observe(s), t.append(s);
2304
+ r.observe(s), e.append(s);
2221
2305
  },
2222
- scaleTiles(t, e, { label: n = "Scale" } = {}) {
2306
+ scaleTiles(e, t, { label: n = "Scale" } = {}) {
2223
2307
  const a = (o) => `<span class="ladder">${[-1, 0, 1, 2].map((s) => `<b style="font-size:${Math.round(13 * o ** s)}px">A</b>`).join("")}</span>`;
2224
- t.append(V(e, {
2308
+ e.append(V(t, {
2225
2309
  section: "typography",
2226
2310
  key: "scale",
2227
2311
  label: n,
2228
2312
  fallback: "balanced",
2229
- options: Object.entries(be).map(([o, s]) => ({ value: o, label: o[0].toUpperCase() + o.slice(1), preview: a(s) })),
2230
- valueText: (o) => String(be[o])
2313
+ options: Object.entries(we).map(([o, s]) => ({ value: o, label: o[0].toUpperCase() + o.slice(1), preview: a(s) })),
2314
+ valueText: (o) => String(we[o])
2231
2315
  }));
2232
2316
  },
2233
- scale(t, e, { label: n = "Scale" } = {}) {
2234
- t.append(ke(e, {
2317
+ scale(e, t, { label: n = "Scale" } = {}) {
2318
+ e.append($e(t, {
2235
2319
  section: "typography",
2236
2320
  key: "scale",
2237
2321
  label: n,
2238
2322
  fallback: "balanced",
2239
2323
  options: [{ value: "compact", label: "Compact" }, { value: "balanced", label: "Balanced" }, { value: "expressive", label: "Expressive" }],
2240
- valueText: (a) => String(be[a])
2324
+ valueText: (a) => String(we[a])
2241
2325
  }));
2242
2326
  }
2243
2327
  },
2244
- render(t, e) {
2245
- Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(t, e));
2328
+ render(e, t) {
2329
+ Object.entries(this.parts).filter(([n]) => !n.endsWith("Tiles")).forEach(([, n]) => n(e, t));
2246
2330
  }
2247
- }, [vn, je] = wt;
2248
- function fo(t) {
2249
- return t > 0.56 ? "Bold" : t < 0.44 ? "Subtle" : "Balanced";
2331
+ }, [$n, Ie] = kt;
2332
+ function ko(e) {
2333
+ return e > 0.56 ? "Bold" : e < 0.44 ? "Subtle" : "Balanced";
2250
2334
  }
2251
- function Vn(t) {
2252
- return t > 1.06 ? "Comfy" : t < 0.94 ? "Compact" : "Regular";
2335
+ function Gn(e) {
2336
+ return e > 1.06 ? "Comfy" : e < 0.94 ? "Compact" : "Regular";
2253
2337
  }
2254
- const Re = (t) => t && t[0].toUpperCase() + t.slice(1), yn = [
2255
- ["colour", "Colour", (t) => {
2256
- const e = t.colour || {}, n = Ie.find((o) => o.primary === e.primary && o.neutral === e.neutral);
2257
- return { text: `${e.brand ? e.brand.toUpperCase() : n && !e.shade ? n.label : e.primary ? `${Re(e.primary)}${e.neutral ? ` · ${Re(e.neutral)}` : ""}` : "Prototype colours"}${e.mode === "dark" ? " · Dark" : ""}`, swatch: F("--twd-primary") };
2338
+ const De = (e) => e && e[0].toUpperCase() + e.slice(1), En = [
2339
+ ["colour", "Colour", (e) => {
2340
+ const t = e.colour || {}, n = Be.find((o) => o.primary === t.primary && o.neutral === t.neutral);
2341
+ return { text: `${t.brand ? t.brand.toUpperCase() : n && !t.shade ? n.label : t.primary ? `${De(t.primary)}${t.neutral ? ` · ${De(t.neutral)}` : ""}` : "Prototype colours"}${t.mode === "dark" ? " · Dark" : ""}`, swatch: F("--twd-primary") };
2258
2342
  }],
2259
- ["type", "Type", (t) => {
2260
- const e = t.typography || {};
2261
- return { text: `${X.find((n) => n.value === e.font)?.name || "Prototype fonts"} · ${e.base || 16}px` };
2343
+ ["type", "Type", (e) => {
2344
+ const t = e.typography || {};
2345
+ return { text: `${J.find((n) => n.value === t.font)?.name || "Prototype fonts"} · ${t.base || 16}px` };
2262
2346
  }],
2263
- ["spacing", "Spacing", (t) => ({ text: Vn(ae(t.density)) })],
2264
- ["shape", "Shape", (t) => ({ text: `${Re((t.buttons || {}).corners) || "Default"} corners` })],
2265
- ["shadows", "Shadows", (t) => ({ text: Re((t.depth || {}).style) || (Et(t.character) !== null ? "From the pad" : "Default") })]
2266
- ], go = {
2267
- summary(t, e, { label: n = "Current look", goTab: a } = {}) {
2268
- const o = B(n), s = document.createElement("div");
2269
- s.className = "summary", yn.forEach(([i, l]) => {
2270
- const p = document.createElement("button");
2271
- p.type = "button", p.className = "summary-row", p.dataset.summary = i, p.innerHTML = `<span class="summary-name"></span><span class="summary-swatch" hidden></span><span class="summary-value"></span><span class="chev" aria-hidden="true">${A.chevron}</span>`, p.querySelector(".summary-name").textContent = l, p.addEventListener("click", () => a && a(i)), s.append(p);
2347
+ ["spacing", "Spacing", (e) => ({ text: Gn(se(e.density)) })],
2348
+ ["shape", "Shape", (e) => ({ text: `${De((e.buttons || {}).corners) || "Default"} corners` })],
2349
+ ["shadows", "Shadows", (e) => ({ text: De((e.depth || {}).style) || (Tt(e.character) !== null ? "From the pad" : "Default") })]
2350
+ ], So = {
2351
+ summary(e, t, { label: n = "Current look", goTab: a } = {}) {
2352
+ const o = U(n), s = document.createElement("div");
2353
+ s.className = "summary", En.forEach(([i, l]) => {
2354
+ const d = document.createElement("button");
2355
+ d.type = "button", d.className = "summary-row", d.dataset.summary = i, d.innerHTML = `<span class="summary-name"></span><span class="summary-swatch" hidden></span><span class="summary-value"></span><span class="chev" aria-hidden="true">${A.chevron}</span>`, d.querySelector(".summary-name").textContent = l, d.addEventListener("click", () => a && a(i)), s.append(d);
2272
2356
  }), o.append(s);
2273
2357
  const r = () => {
2274
- const i = e.getState();
2275
- yn.forEach(([l, , p]) => {
2276
- const c = s.querySelector(`[data-summary="${l}"]`), h = p(i);
2277
- c.querySelector(".summary-value").textContent = h.text;
2278
- const y = c.querySelector(".summary-swatch");
2279
- y.hidden = !h.swatch, h.swatch && (y.style.background = h.swatch);
2358
+ const i = t.getState();
2359
+ En.forEach(([l, , d]) => {
2360
+ const p = s.querySelector(`[data-summary="${l}"]`), u = d(i);
2361
+ p.querySelector(".summary-value").textContent = u.text;
2362
+ const v = p.querySelector(".summary-swatch");
2363
+ v.hidden = !u.swatch, u.swatch && (v.style.background = u.swatch);
2280
2364
  });
2281
2365
  };
2282
- r(), e.onChange(r), t.append(o.el);
2366
+ r(), t.onChange(r), e.append(o.el);
2283
2367
  },
2284
- character(t, e, { label: n = "Character" } = {}) {
2285
- const a = B(n), o = Da({
2368
+ character(e, t, { label: n = "Character" } = {}) {
2369
+ const a = U(n), o = Wa({
2286
2370
  label: n,
2287
2371
  ends: { top: "Spacious", bottom: "Compact", left: "Subtle", right: "Bold" },
2288
2372
  onInput: (r, i) => {
2289
- const l = +(je - i * (je - vn)).toFixed(3), p = +r.toFixed(3);
2290
- e.setSections({
2373
+ const l = +(Ie - i * (Ie - $n)).toFixed(3), d = +r.toFixed(3);
2374
+ t.setSections({
2291
2375
  density: { factor: l === 1 ? null : l, spacing: null },
2292
- character: { bold: p === 0.5 ? null : p }
2376
+ character: { bold: d === 0.5 ? null : d }
2293
2377
  }, "character");
2294
2378
  }
2295
2379
  });
2296
2380
  a.append(o.el);
2297
2381
  const s = () => {
2298
- const r = e.getState(), i = ae(r.density), l = Et(r.character), p = l === null ? 0.5 : l, c = `${Vn(i)} · ${fo(p)}`;
2299
- o.setValue(p, (je - i) / (je - vn), c), a.setValue(c);
2382
+ const r = t.getState(), i = se(r.density), l = Tt(r.character), d = l === null ? 0.5 : l, p = `${Gn(i)} · ${ko(d)}`;
2383
+ o.setValue(d, (Ie - i) / (Ie - $n), p), a.setValue(p);
2300
2384
  };
2301
- s(), e.onChange(s), t.append(a.el);
2385
+ s(), t.onChange(s), e.append(a.el);
2302
2386
  }
2303
- }, ct = [
2387
+ }, ht = [
2304
2388
  { key: "page-pad", label: "Page padding", step: 5 },
2305
2389
  { key: "section-gap", label: "Section gap", step: 6 },
2306
2390
  { key: "card-pad", label: "Card padding", step: 5 },
2307
2391
  { key: "card-gap", label: "Card gap", step: 2 },
2308
2392
  { key: "control-gap", label: "Control gap", step: 3 },
2309
2393
  { key: "control-pad-x", label: "Control padding", step: null }
2310
- ], mo = [1, 2, 3, 4, 5, 6, 7, 8], bo = /^var\(\s*--twd-space-(\d)\s*\)$/, pt = (t) => {
2311
- const e = /^(-?\d*\.?\d+)(px|rem)?$/.exec(String(t).trim());
2312
- return e ? +(parseFloat(e[1]) * (e[2] === "rem" ? 16 : 1)).toFixed(1) : null;
2394
+ ], $o = [1, 2, 3, 4, 5, 6, 7, 8], Eo = /^var\(\s*--twd-space-(\d)\s*\)$/, ft = (e) => {
2395
+ const t = /^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());
2396
+ return t ? +(parseFloat(t[1]) * (t[2] === "rem" ? 16 : 1)).toFixed(1) : null;
2313
2397
  };
2314
- function xo(t, e, n) {
2315
- const a = `--twd-${e.key}`, o = document.createElement("div");
2398
+ function Co(e, t, n) {
2399
+ const a = `--twd-${t.key}`, o = document.createElement("div");
2316
2400
  o.className = "role-row", n || o.classList.add("unused"), o.innerHTML = `
2317
- <span class="role-label" title="${a}${n ? "" : " (not used on this page)"}">${e.label}</span>
2318
- <label class="token-value role-fixed" hidden><input type="text" inputmode="decimal" spellcheck="false" aria-label="${e.label}, fixed value"><span class="token-unit">px</span></label>
2401
+ <span class="role-label" title="${a}${n ? "" : " (not used on this page)"}">${t.label}</span>
2402
+ <label class="token-value role-fixed" hidden><input type="text" inputmode="decimal" spellcheck="false" aria-label="${t.label}, fixed value"><span class="token-unit">px</span></label>
2319
2403
  <span class="step-select">
2320
- <select aria-label="${e.label}"></select>
2404
+ <select aria-label="${t.label}"></select>
2321
2405
  <span class="step-chevron" aria-hidden="true">${A.down}</span>
2322
2406
  </span>
2323
- <button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${e.label}" hidden>${A.reset}</button>
2407
+ <button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${t.label}" hidden>${A.reset}</button>
2324
2408
  `;
2325
- const s = o.querySelector("select"), r = o.querySelector(".role-fixed"), i = r.querySelector("input"), l = o.querySelector(".token-reset"), p = () => (t.getState().custom || {})[e.key], c = () => {
2326
- const x = p();
2327
- if (x == null) return e.step ? { step: e.step } : { fixed: F(a) };
2328
- const b = bo.exec(x);
2409
+ const s = o.querySelector("select"), r = o.querySelector(".role-fixed"), i = r.querySelector("input"), l = o.querySelector(".token-reset"), d = () => (e.getState().custom || {})[t.key], p = () => {
2410
+ const x = d();
2411
+ if (x == null) return t.step ? { step: t.step } : { fixed: F(a) };
2412
+ const b = Eo.exec(x);
2329
2413
  return b ? { step: +b[1] } : { fixed: x };
2330
- }, h = (x) => t.setSection("custom", { [e.key]: x }), y = (x) => e.step ? x === `var(--twd-space-${e.step})` : !1;
2414
+ }, u = (x) => e.setSection("custom", { [t.key]: x }), v = (x) => t.step ? x === `var(--twd-space-${t.step})` : !1;
2331
2415
  s.addEventListener("change", () => {
2332
2416
  if (s.value === "fixed") {
2333
- const b = pt(F(a));
2334
- h(b != null ? `${b}px` : F(a)), i.focus(), i.select();
2417
+ const b = ft(F(a));
2418
+ u(b != null ? `${b}px` : F(a)), i.focus(), i.select();
2335
2419
  return;
2336
2420
  }
2337
2421
  const x = `var(--twd-space-${s.value})`;
2338
- h(y(x) ? null : x);
2422
+ u(v(x) ? null : x);
2339
2423
  });
2340
2424
  const f = () => {
2341
2425
  const x = i.value.trim();
2342
- if (!x) return h(null);
2343
- h(/^-?\d*\.?\d+$/.test(x) ? `${x}px` : x);
2426
+ if (!x) return u(null);
2427
+ u(/^-?\d*\.?\d+$/.test(x) ? `${x}px` : x);
2344
2428
  };
2345
2429
  i.addEventListener("change", f), i.addEventListener("blur", () => m()), i.addEventListener("keydown", (x) => {
2346
2430
  x.key === "Enter" && (x.preventDefault(), i.blur()), x.key === "Escape" && (x.stopPropagation(), m(), i.blur());
2347
- }), l.addEventListener("click", () => h(null));
2431
+ }), l.addEventListener("click", () => u(null));
2348
2432
  function m() {
2349
- const x = c();
2350
- if (s.innerHTML = mo.map((u) => `<option value="${u}">space-${u} · ${pt(F(`--twd-space-${u}`)) ?? "?"}</option>`).join("") + '<option value="fixed">Fixed</option>', s.value = x.step ? String(x.step) : "fixed", r.hidden = !x.fixed, o.classList.toggle("is-fixed", !!x.fixed), x.fixed && o.getRootNode().activeElement !== i) {
2351
- const u = pt(x.fixed);
2352
- i.value = u != null ? String(u) : x.fixed;
2433
+ const x = p();
2434
+ if (s.innerHTML = $o.map((h) => `<option value="${h}">space-${h} · ${ft(F(`--twd-space-${h}`)) ?? "?"}</option>`).join("") + '<option value="fixed">Fixed</option>', s.value = x.step ? String(x.step) : "fixed", r.hidden = !x.fixed, o.classList.toggle("is-fixed", !!x.fixed), x.fixed && o.getRootNode().activeElement !== i) {
2435
+ const h = ft(x.fixed);
2436
+ i.value = h != null ? String(h) : x.fixed;
2353
2437
  }
2354
- const b = p() != null;
2438
+ const b = d() != null;
2355
2439
  o.classList.toggle("edited", b), l.hidden = !b;
2356
2440
  }
2357
- return m(), t.onChange(m), o;
2441
+ return m(), e.onChange(m), o;
2358
2442
  }
2359
- const wo = {
2360
- spacing(t, e, { label: n = "Roles" } = {}) {
2361
- const a = za(), o = B(n);
2443
+ const Mo = {
2444
+ spacing(e, t, { label: n = "Roles" } = {}) {
2445
+ const a = _a(), o = U(n);
2362
2446
  o.el.classList.add("token-field");
2363
- const s = ct.filter((l) => !a.has(`--twd-${l.key}`));
2364
- o.setValue(s.length === ct.length ? "not used on this page" : "");
2447
+ const s = ht.filter((l) => !a.has(`--twd-${l.key}`));
2448
+ o.setValue(s.length === ht.length ? "not used on this page" : "");
2365
2449
  const r = document.createElement("div");
2366
- r.className = "token-rows", ct.forEach((l) => r.append(xo(e, l, a.has(`--twd-${l.key}`)))), o.append(r), t.append(o.el);
2450
+ r.className = "token-rows", ht.forEach((l) => r.append(Co(t, l, a.has(`--twd-${l.key}`)))), o.append(r), e.append(o.el);
2367
2451
  const i = document.createElement("p");
2368
- i.className = "role-note", i.textContent = s.length ? `Only elements styled with these tokens change. Not used on this page: ${s.map((l) => l.label).join(", ")}.` : "Each role points at a spacing step, so Density still scales it. Pick another step, or a fixed value.", t.append(i);
2452
+ i.className = "role-note", i.textContent = s.length ? `Only elements styled with these tokens change. Not used on this page: ${s.map((l) => l.label).join(", ")}.` : "Each role points at a spacing step, so Density still scales it. Pick another step, or a fixed value.", e.append(i);
2369
2453
  }
2370
- }, xe = [
2454
+ }, ye = [
2371
2455
  { id: "overview", title: "Overview", icon: "tabOverview", parts: [["simple", "character"], ["simple", "summary"]] },
2372
2456
  { id: "colour", title: "Colour", icon: "tabColour", parts: [
2373
2457
  ["colour", "themeTiles"],
@@ -2407,18 +2491,18 @@ const wo = {
2407
2491
  ["depth", "intensity"],
2408
2492
  { more: "Shadow tokens", parts: [["custom", "shadows"]] }
2409
2493
  ] }
2410
- ], P = (t) => String(t).replace(/[&<>"]/g, (e) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[e]);
2411
- function vo({ sections: t, store: e, view: n }) {
2494
+ ], O = (e) => String(e).replace(/[&<>"]/g, (t) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[t]);
2495
+ function To({ sections: e, store: t, view: n }) {
2412
2496
  const a = document.createElement("div");
2413
2497
  a.id = "twiddle-root", document.body.appendChild(a);
2414
- const o = a.attachShadow({ mode: "open" }), s = (d) => d.map((g) => `
2498
+ const o = a.attachShadow({ mode: "open" }), s = (c) => c.map((g) => `
2415
2499
  <details data-section="${g.id}">
2416
2500
  <summary>${g.title}<span class="chev">${A.chevron}</span></summary>
2417
2501
  <div class="section-body"><div class="placeholder">${g.hint}</div></div>
2418
2502
  </details>
2419
2503
  `).join("");
2420
2504
  o.innerHTML = `
2421
- <style>${ma}</style>
2505
+ <style>${va}</style>
2422
2506
  <div class="pick-box" hidden><span class="pick-tag"></span></div>
2423
2507
  <div class="wrap">
2424
2508
  <div class="toast" role="status"></div>
@@ -2448,15 +2532,15 @@ function vo({ sections: t, store: e, view: n }) {
2448
2532
  </div>
2449
2533
  <div class="original-pill" hidden>Showing original</div>
2450
2534
  <div class="body" data-view="global"><div class="setup-hint" role="status" hidden></div>
2451
- ${xe.map((d) => `<div class="page page-fields" data-page="${d.id}" hidden></div>`).join("")}
2535
+ ${ye.map((c) => `<div class="page page-fields" data-page="${c.id}" hidden></div>`).join("")}
2452
2536
  </div>
2453
2537
  <div class="body" data-view="local" hidden></div>
2454
2538
  <div class="body" data-view="changes" hidden></div>
2455
2539
  <nav class="tabbar" aria-label="Areas">
2456
- ${xe.map((d) => `<button class="tab" data-tab="${d.id}" aria-pressed="false">${A[d.icon]}<span>${d.title}</span></button>`).join("")}
2540
+ ${ye.map((c) => `<button class="tab" data-tab="${c.id}" aria-pressed="false">${A[c.icon]}<span>${c.title}</span></button>`).join("")}
2457
2541
  </nav>
2458
2542
  </div>
2459
- <button class="launcher" aria-label="Open Panel" aria-expanded="false">${A.panelMark}</button>
2543
+ <button class="launcher" aria-label="Open Panel" aria-expanded="false" title="Panel · drag to move, double-click to reset">${A.panelMark}</button>
2460
2544
  </div>
2461
2545
  <div class="dialog-backdrop" hidden>
2462
2546
  <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="twd-dialog-title">
@@ -2472,168 +2556,168 @@ function vo({ sections: t, store: e, view: n }) {
2472
2556
  </div>
2473
2557
  </div>
2474
2558
  `;
2475
- const r = (d) => o.querySelector(d), i = r(".panel"), l = r(".launcher"), p = r(".toast"), c = { global: r('[data-view="global"]'), local: r('[data-view="local"]'), changes: r('[data-view="changes"]') }, h = r(".pick-box"), y = r(".pick-tag"), f = { getState: e.getState, setSection: e.setSection, setSections: e.setSections, onChange: e.onChange };
2476
- function m(d, g, w) {
2559
+ const r = (c) => o.querySelector(c), i = r(".panel"), l = r(".launcher"), d = r(".toast"), p = { global: r('[data-view="global"]'), local: r('[data-view="local"]'), changes: r('[data-view="changes"]') }, u = r(".pick-box"), v = r(".pick-tag"), f = { getState: t.getState, setSection: t.setSection, setSections: t.setSections, onChange: t.onChange };
2560
+ function m(c, g, w) {
2477
2561
  g.forEach((k) => {
2478
2562
  if (typeof k.render != "function") return;
2479
- const C = d.querySelector(`[data-section="${k.id}"] .section-body`);
2563
+ const C = c.querySelector(`[data-section="${k.id}"] .section-body`);
2480
2564
  C.innerHTML = "", k.render(C, w);
2481
2565
  });
2482
- const $ = [...d.querySelectorAll("details")];
2566
+ const $ = [...c.querySelectorAll("details")];
2483
2567
  return $.forEach((k) => k.addEventListener("toggle", () => {
2484
2568
  k.open && $.forEach((C) => {
2485
2569
  C !== k && (C.open = !1);
2486
2570
  });
2487
2571
  })), $;
2488
2572
  }
2489
- const x = Object.fromEntries(t.map((d) => [d.id, d]));
2490
- function b(d, g) {
2573
+ const x = Object.fromEntries(e.map((c) => [c.id, c]));
2574
+ function b(c, g) {
2491
2575
  g.forEach((w) => {
2492
2576
  if (w === "warnings") {
2493
2577
  const S = document.createElement("div");
2494
- S.className = "warnings page-warnings", d.append(S);
2578
+ S.className = "warnings page-warnings", c.append(S);
2495
2579
  return;
2496
2580
  }
2497
2581
  if (w.heading) {
2498
2582
  const S = document.createElement("div");
2499
- S.className = "page-heading", S.innerHTML = `<span></span>${w.note ? '<span class="muted"></span>' : ""}`, S.firstChild.textContent = w.heading, w.note && (S.lastChild.textContent = w.note), d.append(S);
2583
+ S.className = "page-heading", S.innerHTML = `<span></span>${w.note ? '<span class="muted"></span>' : ""}`, S.firstChild.textContent = w.heading, w.note && (S.lastChild.textContent = w.note), c.append(S);
2500
2584
  return;
2501
2585
  }
2502
2586
  if (w.more) {
2503
2587
  const S = document.createElement("details");
2504
- S.className = "more", S.innerHTML = `<summary><span class="chev" aria-hidden="true">${A.chevron}</span><span></span></summary><div class="more-body"></div>`, S.querySelector("summary span:last-child").textContent = w.more, b(S.querySelector(".more-body"), w.parts), d.append(S);
2588
+ S.className = "more", S.innerHTML = `<summary><span class="chev" aria-hidden="true">${A.chevron}</span><span></span></summary><div class="more-body"></div>`, S.querySelector("summary span:last-child").textContent = w.more, b(S.querySelector(".more-body"), w.parts), c.append(S);
2505
2589
  return;
2506
2590
  }
2507
2591
  if (w.tabs) {
2508
2592
  const S = w.tabs.map((j) => {
2509
2593
  const z = document.createElement("div");
2510
2594
  return z.className = "tab-pane", b(z, j.parts), z;
2511
- }), fe = ie({
2595
+ }), be = ce({
2512
2596
  label: "View",
2513
2597
  options: w.tabs.map((j, z) => ({ value: String(z), label: j.label })),
2514
2598
  onSelect: (j) => {
2515
- fe.setValue(j), S.forEach((z, ea) => {
2516
- z.hidden = String(ea) !== j;
2599
+ be.setValue(j), S.forEach((z, ra) => {
2600
+ z.hidden = String(ra) !== j;
2517
2601
  });
2518
2602
  }
2519
2603
  });
2520
- fe.setValue("0"), S.forEach((j, z) => {
2604
+ be.setValue("0"), S.forEach((j, z) => {
2521
2605
  j.hidden = z !== 0;
2522
- }), d.append(fe.el, ...S);
2606
+ }), c.append(be.el, ...S);
2523
2607
  return;
2524
2608
  }
2525
- const [$, k, C = {}] = w, q = $ === "simple" ? go[k] : $ === "roles" ? wo[k] : x[$]?.parts?.[k];
2526
- q && q(d, f, { ...C, buttons: x.buttons, cards: x.cards, goTab: (S) => {
2527
- G("global"), E(S);
2609
+ const [$, k, C = {}] = w, q = $ === "simple" ? So[k] : $ === "roles" ? Mo[k] : x[$]?.parts?.[k];
2610
+ q && q(c, f, { ...C, buttons: x.buttons, cards: x.cards, goTab: (S) => {
2611
+ W("global"), E(S);
2528
2612
  } });
2529
2613
  });
2530
2614
  }
2531
- xe.forEach((d) => b(c.global.querySelector(`[data-page="${d.id}"]`), d.parts));
2532
- const u = [...o.querySelectorAll(".tab")];
2533
- let v = xe.some((d) => d.id === ne("tab")) ? ne("tab") : xe[0].id;
2615
+ ye.forEach((c) => b(p.global.querySelector(`[data-page="${c.id}"]`), c.parts));
2616
+ const h = [...o.querySelectorAll(".tab")];
2617
+ let y = ye.some((c) => c.id === Z("tab")) ? Z("tab") : ye[0].id;
2534
2618
  function L() {
2535
- u.forEach((d) => d.setAttribute("aria-pressed", String(K === "global" && d.dataset.tab === v)));
2619
+ h.forEach((c) => c.setAttribute("aria-pressed", String(K === "global" && c.dataset.tab === y)));
2536
2620
  }
2537
- function E(d) {
2538
- v = d, ge("tab", d), c.global.querySelectorAll(".page").forEach((g) => {
2539
- g.hidden = g.dataset.page !== d;
2540
- }), c.global.scrollTop = 0, L();
2621
+ function E(c) {
2622
+ y = c, oe("tab", c), p.global.querySelectorAll(".page").forEach((g) => {
2623
+ g.hidden = g.dataset.page !== c;
2624
+ }), p.global.scrollTop = 0, L();
2541
2625
  }
2542
- const Q = (d) => d.map((g) => `<div class="warning">${A.warn}<span>${P(g.text)}</span></div>`).join("");
2626
+ const ee = (c) => c.map((g) => `<div class="warning">${A.warn}<span>${O(g.text)}</span></div>`).join("");
2543
2627
  let K = "global";
2544
- function G(d) {
2545
- K = d, Object.entries(c).forEach(([g, w]) => {
2546
- w.hidden = g !== d;
2547
- }), r('[data-action="changes"]').setAttribute("aria-pressed", String(d === "changes")), d !== "local" && Wn(), d === "changes" && Ht(), L();
2548
- }
2549
- E(v);
2550
- const Ve = "cubic-bezier(0.3, 0.7, 0.2, 1)", He = "cubic-bezier(0.2, 0.8, 0.2, 1)", Se = 640, de = 100, _e = 50, Hn = () => l.querySelector(".mark-knob"), _n = () => [l.querySelector(".mark-t1"), l.querySelector(".mark-t2")];
2551
- function Ct(d) {
2628
+ function W(c) {
2629
+ K = c, Object.entries(p).forEach(([g, w]) => {
2630
+ w.hidden = g !== c;
2631
+ }), r('[data-action="changes"]').setAttribute("aria-pressed", String(c === "changes")), c !== "local" && Qn(), c === "changes" && Wt(), L();
2632
+ }
2633
+ E(y);
2634
+ const Ke = "cubic-bezier(0.3, 0.7, 0.2, 1)", We = "cubic-bezier(0.2, 0.8, 0.2, 1)", Ee = 640, ue = 100, Ge = 50, Yn = () => l.querySelector(".mark-knob"), Xn = () => [l.querySelector(".mark-t1"), l.querySelector(".mark-t2")];
2635
+ function At(c) {
2552
2636
  if (matchMedia("(prefers-reduced-motion: reduce)").matches || !l.animate) return;
2553
- const g = Hn(), [w, $] = _n(), k = (C) => `translateY(${C}px)`;
2554
- if (d) {
2555
- g.animate([{ transform: k(32) }, { transform: k(-6), offset: 0.78 }, { transform: k(0) }], { duration: Se, easing: Ve });
2637
+ const g = Yn(), [w, $] = Xn(), k = (C) => `translateY(${C}px)`;
2638
+ if (c) {
2639
+ g.animate([{ transform: k(32) }, { transform: k(-6), offset: 0.78 }, { transform: k(0) }], { duration: Ee, easing: Ke });
2556
2640
  const C = [{ transform: "scale(0.4)", opacity: 0 }, { transform: "scale(1)", opacity: 1 }];
2557
- $.animate(C, { duration: de * 2, delay: Se * 0.12, easing: Ve, fill: "backwards" }), w.animate(C, { duration: de * 2, delay: Se * 0.32 + _e, easing: Ve, fill: "backwards" });
2641
+ $.animate(C, { duration: ue * 2, delay: Ee * 0.12, easing: Ke, fill: "backwards" }), w.animate(C, { duration: ue * 2, delay: Ee * 0.32 + Ge, easing: Ke, fill: "backwards" });
2558
2642
  } else {
2559
2643
  const C = [{ opacity: 1 }, { opacity: 0 }];
2560
- w.animate(C, { duration: de, easing: He }), $.animate(C, { duration: de, delay: _e / 2, easing: He, fill: "backwards" }), g.animate([{ transform: k(0) }, { transform: k(34), offset: 0.8 }, { transform: k(32) }], { duration: Se * 0.7, delay: de + _e / 2, easing: He, fill: "backwards" });
2644
+ w.animate(C, { duration: ue, easing: We }), $.animate(C, { duration: ue, delay: Ge / 2, easing: We, fill: "backwards" }), g.animate([{ transform: k(0) }, { transform: k(34), offset: 0.8 }, { transform: k(32) }], { duration: Ee * 0.7, delay: ue + Ge / 2, easing: We, fill: "backwards" });
2561
2645
  }
2562
2646
  }
2563
- const Mt = r(".wrap");
2564
- let Tt = !1;
2565
- function $e(d) {
2566
- Tt = d, i.classList.toggle("minimised", d), i.hidden || ge("panel", d ? "tabs" : "open");
2647
+ const Ye = r(".wrap"), Lt = $a({ wrapEl: Ye, launcherEl: l });
2648
+ let Pt = !1;
2649
+ function Ce(c) {
2650
+ Pt = c, i.classList.toggle("minimised", c), i.hidden || oe("panel", c ? "tabs" : "open");
2567
2651
  }
2568
- function W({ animate: d = !0 } = {}) {
2569
- i.hidden && d && Ct(!0), i.hidden = !1, Mt.classList.add("is-open"), l.setAttribute("aria-expanded", "true"), l.setAttribute("aria-label", "Close Panel"), $e(!1);
2652
+ function G({ animate: c = !0 } = {}) {
2653
+ i.hidden && c && At(!0), i.hidden = !1, Ye.classList.add("is-open"), l.setAttribute("aria-expanded", "true"), l.setAttribute("aria-label", "Close Panel"), Ce(!1);
2570
2654
  }
2571
- function Kn() {
2572
- i.hidden && W(), $e(!0);
2655
+ function Zn() {
2656
+ i.hidden && G(), Ce(!0);
2573
2657
  }
2574
- function Ke() {
2575
- i.hidden || Ct(!1), i.hidden = !0, Mt.classList.remove("is-open"), l.setAttribute("aria-expanded", "false"), l.setAttribute("aria-label", "Open Panel"), ge("panel", "closed"), Ee();
2658
+ function Xe() {
2659
+ i.hidden || At(!1), i.hidden = !0, Ye.classList.remove("is-open"), l.setAttribute("aria-expanded", "false"), l.setAttribute("aria-label", "Open Panel"), oe("panel", "closed"), Te();
2576
2660
  }
2577
- function Ge() {
2578
- i.hidden ? W() : Ke();
2661
+ function Me() {
2662
+ i.hidden ? G() : Xe();
2579
2663
  }
2580
- let At;
2581
- function H(d) {
2582
- p.textContent = d, p.classList.add("show"), clearTimeout(At), At = setTimeout(() => p.classList.remove("show"), 1600);
2664
+ let Ot;
2665
+ function H(c) {
2666
+ d.textContent = c, d.classList.add("show"), clearTimeout(Ot), Ot = setTimeout(() => d.classList.remove("show"), 1600);
2583
2667
  }
2584
- function ce(d, g) {
2585
- navigator.clipboard.writeText(d).then(() => H(g)).catch(() => H("Couldn’t copy — select the text and copy it instead"));
2668
+ function he(c, g) {
2669
+ navigator.clipboard.writeText(c).then(() => H(g)).catch(() => H("Couldn’t copy — select the text and copy it instead"));
2586
2670
  }
2587
- let We = null;
2588
- function ee(d, g) {
2589
- if (We = d, !d) {
2590
- h.hidden = !0;
2671
+ let Ze = null;
2672
+ function te(c, g) {
2673
+ if (Ze = c, !c) {
2674
+ u.hidden = !0;
2591
2675
  return;
2592
2676
  }
2593
- const w = d.getBoundingClientRect();
2594
- Object.assign(h.style, { top: `${w.top}px`, left: `${w.left}px`, width: `${w.width}px`, height: `${w.height}px` }), y.textContent = g || xt(d), h.hidden = !1;
2677
+ const w = c.getBoundingClientRect();
2678
+ Object.assign(u.style, { top: `${w.top}px`, left: `${w.left}px`, width: `${w.width}px`, height: `${w.height}px` }), v.textContent = g || vt(c), u.hidden = !1;
2595
2679
  }
2596
- const Lt = () => {
2597
- We && !h.hidden && ee(We, y.textContent);
2680
+ const Ft = () => {
2681
+ Ze && !u.hidden && te(Ze, v.textContent);
2598
2682
  };
2599
- window.addEventListener("scroll", Lt, !0), window.addEventListener("resize", Lt);
2600
- let pe = !1;
2601
- const Ot = r('[data-action="pick"]'), Pt = (d) => d.composedPath().includes(a);
2602
- function Ft(d) {
2603
- if (Pt(d)) return;
2604
- const g = d.target;
2605
- g && g.nodeType === 1 && g !== document.documentElement && g !== document.body && ee(g);
2606
- }
2607
- function Nt(d) {
2608
- if (Pt(d) || (d.preventDefault(), d.stopPropagation(), d.type !== "click")) return;
2609
- const g = d.target;
2610
- !g || g === document.documentElement || g === document.body || (Ee(), It(g));
2611
- }
2612
- function jt(d) {
2613
- d.key === "Escape" && (d.preventDefault(), Ee(), T && ee(T.el));
2614
- }
2615
- const Rt = ["pointerdown", "mousedown", "mouseup", "click"];
2616
- function zt() {
2617
- if (!pe) {
2618
- if (pe = !0, !document.getElementById("twiddle-picking")) {
2619
- const d = document.createElement("style");
2620
- d.id = "twiddle-picking", d.textContent = "html.twd-picking, html.twd-picking * { cursor: crosshair !important; }", document.head.appendChild(d);
2683
+ window.addEventListener("scroll", Ft, !0), window.addEventListener("resize", Ft);
2684
+ let fe = !1;
2685
+ const Nt = r('[data-action="pick"]'), jt = (c) => c.composedPath().includes(a);
2686
+ function Rt(c) {
2687
+ if (jt(c)) return;
2688
+ const g = c.target;
2689
+ g && g.nodeType === 1 && g !== document.documentElement && g !== document.body && te(g);
2690
+ }
2691
+ function zt(c) {
2692
+ if (jt(c) || (c.preventDefault(), c.stopPropagation(), c.type !== "click")) return;
2693
+ const g = c.target;
2694
+ !g || g === document.documentElement || g === document.body || (Te(), Bt(g));
2695
+ }
2696
+ function It(c) {
2697
+ c.key === "Escape" && (c.preventDefault(), Te(), T && te(T.el));
2698
+ }
2699
+ const Dt = ["pointerdown", "mousedown", "mouseup", "click"];
2700
+ function Ut() {
2701
+ if (!fe) {
2702
+ if (fe = !0, !document.getElementById("twiddle-picking")) {
2703
+ const c = document.createElement("style");
2704
+ c.id = "twiddle-picking", c.textContent = "html.twd-picking, html.twd-picking * { cursor: crosshair !important; }", document.head.appendChild(c);
2621
2705
  }
2622
- W(), Ot.setAttribute("aria-pressed", "true"), document.documentElement.classList.add("twd-picking"), document.addEventListener("pointermove", Ft, !0), Rt.forEach((d) => document.addEventListener(d, Nt, !0)), document.addEventListener("keydown", jt, !0), H("Click an element · Esc to cancel");
2706
+ G(), Nt.setAttribute("aria-pressed", "true"), document.documentElement.classList.add("twd-picking"), document.addEventListener("pointermove", Rt, !0), Dt.forEach((c) => document.addEventListener(c, zt, !0)), document.addEventListener("keydown", It, !0), H("Click an element · Esc to cancel");
2623
2707
  }
2624
2708
  }
2625
- function Ee() {
2626
- pe && (pe = !1, Ot.setAttribute("aria-pressed", "false"), document.documentElement.classList.remove("twd-picking"), document.removeEventListener("pointermove", Ft, !0), Rt.forEach((d) => document.removeEventListener(d, Nt, !0)), document.removeEventListener("keydown", jt, !0), ee(T ? T.el : null));
2709
+ function Te() {
2710
+ fe && (fe = !1, Nt.setAttribute("aria-pressed", "false"), document.documentElement.classList.remove("twd-picking"), document.removeEventListener("pointermove", Rt, !0), Dt.forEach((c) => document.removeEventListener(c, zt, !0)), document.removeEventListener("keydown", It, !0), te(T ? T.el : null));
2627
2711
  }
2628
2712
  let T = null;
2629
- function Gn(d, g) {
2713
+ function Jn(c, g) {
2630
2714
  const w = [];
2631
2715
  return {
2632
2716
  ctx: {
2633
- getState: () => (e.getState().scopes || {})[d] || {},
2634
- setSection: ($, k) => e.setScope(d, $, k),
2717
+ getState: () => (t.getState().scopes || {})[c] || {},
2718
+ setSection: ($, k) => t.setScope(c, $, k),
2635
2719
  onChange: ($) => {
2636
- const k = e.onChange($);
2720
+ const k = t.onChange($);
2637
2721
  return w.push(k), k;
2638
2722
  },
2639
2723
  readToken: ($) => getComputedStyle(g).getPropertyValue($).trim()
@@ -2641,262 +2725,263 @@ function vo({ sections: t, store: e, view: n }) {
2641
2725
  dispose: () => w.forEach(($) => $())
2642
2726
  };
2643
2727
  }
2644
- function It(d, g) {
2645
- const w = ka(d), $ = e.getState().scopes || {};
2646
- g || (g = !$[w.elementSelector] && w.classSelector && $[w.classSelector] ? "class" : "element"), T && T.dispose(), T = { el: d, info: w, target: g, dispose: () => {
2647
- } }, Ye(), G("local"), W(), ee(d);
2728
+ function Bt(c, g) {
2729
+ const w = La(c), $ = t.getState().scopes || {};
2730
+ g || (g = !$[w.elementSelector] && w.classSelector && $[w.classSelector] ? "class" : "element"), T && T.dispose(), T = { el: c, info: w, target: g, dispose: () => {
2731
+ } }, Je(), W("local"), G(), te(c);
2648
2732
  }
2649
- const Dt = () => T.target === "class" ? T.info.classSelector : T.info.elementSelector;
2650
- function Ye() {
2733
+ const qt = () => T.target === "class" ? T.info.classSelector : T.info.elementSelector;
2734
+ function Je() {
2651
2735
  T.dispose();
2652
- const { info: d } = T, g = t.filter((j) => (j.uses || []).some((z) => d.tokens.has(z))), w = c.local;
2736
+ const { info: c } = T, g = e.filter((j) => (j.uses || []).some((z) => c.tokens.has(z))), w = p.local;
2653
2737
  if (w.innerHTML = `
2654
2738
  <div class="scope-bar">
2655
2739
  <div class="scope-head">
2656
2740
  <button class="icon-btn" data-action="back" title="Back to the whole page" aria-label="Back to the whole page">${A.back}</button>
2657
2741
  <div class="scope-name">
2658
- <code>${P(xt(d.el))}</code>
2659
- ${d.text ? `<span class="muted">“${P(d.text)}”</span>` : ""}
2742
+ <code>${O(vt(c.el))}</code>
2743
+ ${c.text ? `<span class="muted">“${O(c.text)}”</span>` : ""}
2660
2744
  </div>
2661
2745
  </div>
2662
2746
  <div class="scope-target"></div>
2663
2747
  <div class="warnings"></div>
2664
2748
  </div>
2665
2749
  ${g.length ? s(g) : '<div class="empty">This element doesn’t use Panel tokens yet, so there’s nothing to tweak here. Style it with <code>var(--twd-…)</code> to make it tweakable.</div>'}
2666
- `, d.classSelector) {
2667
- const j = ie({
2750
+ `, c.classSelector) {
2751
+ const j = ce({
2668
2752
  label: "Apply to",
2669
2753
  options: [
2670
2754
  { value: "element", label: "This element" },
2671
- { value: "class", label: `All ${d.classSelector} (${d.classCount})`, title: `Every element matching ${d.classSelector}` }
2755
+ { value: "class", label: `All ${c.classSelector} (${c.classCount})`, title: `Every element matching ${c.classSelector}` }
2672
2756
  ],
2673
2757
  onSelect: (z) => {
2674
- z === "class" && e.moveScope(d.elementSelector, d.classSelector), T.target = z, Ye();
2758
+ z === "class" && t.moveScope(c.elementSelector, c.classSelector), T.target = z, Je();
2675
2759
  }
2676
2760
  });
2677
2761
  j.setValue(T.target), w.querySelector(".scope-target").append(j.el);
2678
2762
  }
2679
- const { ctx: $, dispose: k } = Gn(Dt(), d.el), C = m(w, g, $);
2763
+ const { ctx: $, dispose: k } = Jn(qt(), c.el), C = m(w, g, $);
2680
2764
  C[0] && (C[0].open = !0);
2681
2765
  const q = w.querySelector(".warnings"), S = () => {
2682
- const j = d.tokens.size ? Oa(d.el) : null;
2683
- q.innerHTML = j ? Q([j]) : "";
2766
+ const j = c.tokens.size ? Da(c.el) : null;
2767
+ q.innerHTML = j ? ee([j]) : "";
2684
2768
  };
2685
2769
  S();
2686
- const fe = e.onChange(S);
2770
+ const be = t.onChange(S);
2687
2771
  T.dispose = () => {
2688
- k(), fe();
2772
+ k(), be();
2689
2773
  };
2690
2774
  }
2691
- function Bt() {
2775
+ function Ht() {
2692
2776
  if (!T || !T.info.classSelector) return;
2693
- const d = e.getState().scopes || {}, g = T.target === "class" ? "element" : "class", w = g === "class" ? T.info.classSelector : T.info.elementSelector;
2694
- !d[Dt()] && d[w] && (T.target = g, Ye());
2777
+ const c = t.getState().scopes || {}, g = T.target === "class" ? "element" : "class", w = g === "class" ? T.info.classSelector : T.info.elementSelector;
2778
+ !c[qt()] && c[w] && (T.target = g, Je());
2695
2779
  }
2696
- const Ut = () => {
2697
- e.undo(), Bt();
2698
- }, qt = () => {
2699
- e.redo(), Bt();
2780
+ const Vt = () => {
2781
+ t.undo(), Ht();
2782
+ }, _t = () => {
2783
+ t.redo(), Ht();
2700
2784
  };
2701
- function Wn() {
2702
- T && (T.dispose(), T = null, c.local.innerHTML = "", ee(null));
2703
- }
2704
- const Vt = (d) => d.kind === "global" ? "Whole page" : d.kind === "class" ? `All ${d.selector}` : "One element";
2705
- function Ht() {
2706
- const d = an(e.getState(), t), g = Qe(), w = c.changes;
2707
- if (!d.length) {
2708
- w.innerHTML = `<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${Q(g)}`;
2785
+ function Qn() {
2786
+ T && (T.dispose(), T = null, p.local.innerHTML = "", te(null));
2787
+ }
2788
+ const Kt = (c) => c.kind === "global" ? "Whole page" : c.kind === "class" ? `All ${c.selector}` : "One element";
2789
+ function Wt() {
2790
+ const c = ln(t.getState(), e), g = nt(), w = p.changes;
2791
+ if (!c.length) {
2792
+ w.innerHTML = `<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${ee(g)}`;
2709
2793
  return;
2710
2794
  }
2711
2795
  const $ = /* @__PURE__ */ new Map();
2712
- d.forEach((k) => {
2796
+ c.forEach((k) => {
2713
2797
  const C = k.selector || "";
2714
2798
  $.has(C) || $.set(C, []), $.get(C).push(k);
2715
- }), w.innerHTML = (g.length ? `<div class="warnings">${Q(g)}</div>` : "") + [...$].map(([k, C]) => `
2799
+ }), w.innerHTML = (g.length ? `<div class="warnings">${ee(g)}</div>` : "") + [...$].map(([k, C]) => `
2716
2800
  <div class="change-group">
2717
2801
  <div class="change-scope">
2718
- ${k ? `<button class="link-btn" data-select="${P(k)}" title="Select it on the page">${P(Vt(C[0]))}</button><code>${P(k)}</code>` : `<span>${Vt(C[0])}</span>`}
2802
+ ${k ? `<button class="link-btn" data-select="${O(k)}" title="Select it on the page">${O(Kt(C[0]))}</button><code>${O(k)}</code>` : `<span>${Kt(C[0])}</span>`}
2719
2803
  </div>
2720
2804
  ${C.map((q) => `
2721
2805
  <div class="change-row">
2722
2806
  <div class="change-main">
2723
- <div class="change-title">${P(q.title)} <span class="muted">›</span> ${q.settings.map((S) => `${P(S.label)}: <b>${P(S.value)}</b>`).join(", ")}</div>
2724
- ${q.tokens.map((S) => `<div class="change-token"><code>${P(S.name)}</code> ${S.from ? `${P(S.from)} → ` : ""}${P(S.to)}</div>`).join("")}
2807
+ <div class="change-title">${O(q.title)} <span class="muted">›</span> ${q.settings.map((S) => `${O(S.label)}: <b>${O(S.value)}</b>`).join(", ")}</div>
2808
+ ${q.tokens.map((S) => `<div class="change-token"><code>${O(S.name)}</code> ${S.from ? `${O(S.from)} → ` : ""}${O(S.to)}</div>`).join("")}
2725
2809
  </div>
2726
- <button class="icon-btn" data-remove="${P(q.sectionId)}" data-remove-scope="${P(k)}" aria-label="Remove ${P(q.title)} change">${A.close}</button>
2810
+ <button class="icon-btn" data-remove="${O(q.sectionId)}" data-remove-scope="${O(k)}" aria-label="Remove ${O(q.title)} change">${A.close}</button>
2727
2811
  </div>`).join("")}
2728
2812
  </div>`).join("");
2729
2813
  }
2730
- function Yn(d, g) {
2731
- if (g) return e.removeScope(g, d);
2732
- const w = e.getState()[d] || {};
2733
- e.setSection(d, Object.fromEntries(Object.keys(w).map(($) => [$, null])));
2814
+ function ea(c, g) {
2815
+ if (g) return t.removeScope(g, c);
2816
+ const w = t.getState()[c] || {};
2817
+ t.setSection(c, Object.fromEntries(Object.keys(w).map(($) => [$, null])));
2734
2818
  }
2735
- const ue = r(".apply-menu"), _t = r('[data-action="apply-menu"]'), Kt = () => ne("apply-mode") === "copy" ? "copy" : "preview";
2736
- function Zn() {
2737
- ue.querySelectorAll("[data-apply-mode]").forEach((d) => d.setAttribute("aria-checked", String(d.dataset.applyMode === Kt())));
2819
+ const ge = r(".apply-menu"), Gt = r('[data-action="apply-menu"]'), Yt = () => Z("apply-mode") === "copy" ? "copy" : "preview";
2820
+ function ta() {
2821
+ ge.querySelectorAll("[data-apply-mode]").forEach((c) => c.setAttribute("aria-checked", String(c.dataset.applyMode === Yt())));
2738
2822
  }
2739
- function Ce(d) {
2740
- ue.hidden = !d, _t.setAttribute("aria-expanded", String(d)), d && Zn();
2823
+ function Ae(c) {
2824
+ ge.hidden = !c, Gt.setAttribute("aria-expanded", String(c)), c && ta();
2741
2825
  }
2742
- function Gt() {
2743
- return Ma(an(e.getState(), t), { warnings: Qe() });
2826
+ function Xt() {
2827
+ return ja(ln(t.getState(), e), { warnings: nt() });
2744
2828
  }
2745
- const Me = r(".dialog-backdrop"), Wt = r(".prompt-text");
2746
- function Xn() {
2747
- const d = Gt();
2748
- if (!d) return H("No changes to copy yet");
2749
- if (Kt() === "copy") return ce(d, "Prompt copied · paste it into your agent");
2750
- Wt.value = d, Me.hidden = !1, r('[data-action="dialog-copy"]').focus();
2829
+ const Le = r(".dialog-backdrop"), Zt = r(".prompt-text");
2830
+ function na() {
2831
+ const c = Xt();
2832
+ if (!c) return H("No changes to copy yet");
2833
+ if (Yt() === "copy") return he(c, "Prompt copied · paste it into your agent");
2834
+ Zt.value = c, Le.hidden = !1, r('[data-action="dialog-copy"]').focus();
2751
2835
  }
2752
- function Ze() {
2753
- Me.hidden = !0, r('[data-action="apply"]').focus();
2836
+ function Qe() {
2837
+ Le.hidden = !0, r('[data-action="apply"]').focus();
2754
2838
  }
2755
- const te = r('[data-action="compare"]'), Jn = r(".original-pill");
2756
- function Te(d) {
2757
- d ? n.suspend() : n.resume(), te.setAttribute("aria-pressed", String(d)), Jn.hidden = !d;
2839
+ const ne = r('[data-action="compare"]'), aa = r(".original-pill");
2840
+ function Pe(c) {
2841
+ c ? n.suspend() : n.resume(), ne.setAttribute("aria-pressed", String(c)), aa.hidden = !c;
2758
2842
  }
2759
- let Yt = null, he = !1;
2760
- te.addEventListener("pointerdown", () => {
2761
- he = !1, Yt = setTimeout(() => {
2762
- he = !0, Te(!0);
2843
+ let Jt = null, me = !1;
2844
+ ne.addEventListener("pointerdown", () => {
2845
+ me = !1, Jt = setTimeout(() => {
2846
+ me = !0, Pe(!0);
2763
2847
  }, 180);
2764
2848
  });
2765
- const Zt = () => {
2766
- clearTimeout(Yt), he && (Te(!1), he = !1);
2849
+ const Qt = () => {
2850
+ clearTimeout(Jt), me && (Pe(!1), me = !1);
2767
2851
  };
2768
- te.addEventListener("pointerup", Zt), te.addEventListener("pointerleave", Zt);
2769
- const Ae = r(".setup-hint"), Xt = `setup-hint-dismissed:${location.pathname}`, Qn = {
2852
+ ne.addEventListener("pointerup", Qt), ne.addEventListener("pointerleave", Qt);
2853
+ const Oe = r(".setup-hint"), en = `setup-hint-dismissed:${location.pathname}`, oa = {
2770
2854
  "no-tokens": {
2771
2855
  title: "The Panel tokens aren’t loaded",
2772
2856
  text: "The knobs change the --twd-* variables, but this page doesn’t load them. Add the token stylesheet before your own CSS:",
2773
- snippets: cn,
2774
- link: `${dn}/#install`
2857
+ snippets: fn,
2858
+ link: `${hn}/#install`
2775
2859
  },
2776
2860
  unused: {
2777
2861
  title: "Nothing here uses the Panel tokens yet",
2778
2862
  text: "The tokens are loaded, but no style on this page uses var(--twd-…), so the knobs won’t change anything. Ask your coding agent to convert the styles:",
2779
2863
  copy: "Copy prompt for your agent",
2780
2864
  copied: "Prompt copied",
2781
- text2copy: Ia,
2782
- link: `${dn}/#tokens`
2865
+ text2copy: Ka,
2866
+ link: `${hn}/#tokens`
2783
2867
  }
2784
2868
  };
2785
2869
  let D = null;
2786
- function Le() {
2787
- const d = Ra();
2788
- D = ne(Xt) === d ? null : Qn[d] || null, l.toggleAttribute("data-hint", !!D), Ae.hidden = !D, D && (Ae.innerHTML = `
2789
- <div class="setup-head">${A.warn}<b>${P(D.title)}</b>
2870
+ function Fe() {
2871
+ const c = Va();
2872
+ D = Z(en) === c ? null : oa[c] || null, l.toggleAttribute("data-hint", !!D), Oe.hidden = !D, D && (Oe.innerHTML = `
2873
+ <div class="setup-head">${A.warn}<b>${O(D.title)}</b>
2790
2874
  <button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${A.close}</button>
2791
2875
  </div>
2792
- <p>${P(D.text)}</p>
2876
+ <p>${O(D.text)}</p>
2793
2877
  ${(D.snippets || []).map((g, w) => `
2794
2878
  <div class="setup-snippet">
2795
- <span>${P(g.label)}</span>
2796
- <div class="setup-code"><code>${P(g.code)}</code><button class="text-btn" data-setup-snippet="${w}">Copy</button></div>
2879
+ <span>${O(g.label)}</span>
2880
+ <div class="setup-code"><code>${O(g.code)}</code><button class="text-btn" data-setup-snippet="${w}">Copy</button></div>
2797
2881
  </div>`).join("")}
2798
2882
  <div class="setup-actions">
2799
- ${D.copy ? `<button class="apply-btn" data-action="setup-copy">${P(D.copy)}</button>` : ""}
2883
+ ${D.copy ? `<button class="apply-btn" data-action="setup-copy">${O(D.copy)}</button>` : ""}
2800
2884
  <a href="${D.link}" target="_blank" rel="noopener">Setup guide</a>
2801
- </div>`, Ae.dataset.status = d);
2802
- }
2803
- Le(), document.readyState !== "complete" && window.addEventListener("load", Le, { once: !0 }), setTimeout(Le, 1500);
2804
- const Jt = r(".badge");
2805
- function Qt() {
2806
- r('[data-action="undo"]').disabled = !e.canUndo(), r('[data-action="redo"]').disabled = !e.canRedo();
2807
- const d = Ea(e.getState());
2808
- Jt.textContent = d, Jt.hidden = !d;
2809
- const g = Q(Qe());
2810
- c.global.querySelectorAll(".page-warnings").forEach((w) => {
2885
+ </div>`, Oe.dataset.status = c);
2886
+ }
2887
+ Fe(), document.readyState !== "complete" && window.addEventListener("load", Fe, { once: !0 }), setTimeout(Fe, 1500);
2888
+ const tn = r(".badge");
2889
+ function nn() {
2890
+ r('[data-action="undo"]').disabled = !t.canUndo(), r('[data-action="redo"]').disabled = !t.canRedo();
2891
+ const c = Fa(t.getState());
2892
+ tn.textContent = c, tn.hidden = !c;
2893
+ const g = ee(nt());
2894
+ p.global.querySelectorAll(".page-warnings").forEach((w) => {
2811
2895
  w.innerHTML = g;
2812
- }), K === "changes" && Ht();
2896
+ }), K === "changes" && Wt();
2813
2897
  }
2814
- return e.onChange(Qt), Qt(), o.addEventListener("click", (d) => {
2815
- if (d.target === Me) return Ze();
2816
- const g = d.target.closest("button");
2898
+ return t.onChange(nn), nn(), o.addEventListener("click", (c) => {
2899
+ if (c.target === Le) return Qe();
2900
+ const g = c.target.closest("button");
2817
2901
  if (g) {
2818
- if (g !== _t && !ue.contains(g) && Ce(!1), g === l) return Ge();
2902
+ if (g !== Gt && !ge.contains(g) && Ae(!1), g === l)
2903
+ return Lt.consumeClick() ? void 0 : c.detail === 2 ? (Me(), Lt.reset(), H("Panel moved back to the corner")) : Me();
2819
2904
  if (g.dataset.select) {
2820
2905
  const w = document.querySelector(g.dataset.select);
2821
- return w ? It(w) : H("That element isn’t on this page");
2906
+ return w ? Bt(w) : H("That element isn’t on this page");
2822
2907
  }
2823
- if (g.dataset.setupSnippet) return ce(cn[g.dataset.setupSnippet].code, "Copied");
2908
+ if (g.dataset.setupSnippet) return he(fn[g.dataset.setupSnippet].code, "Copied");
2824
2909
  if (g.dataset.tab)
2825
- return G("global"), Tt && $e(!1), E(g.dataset.tab);
2826
- if (g.dataset.remove) return Yn(g.dataset.remove, g.dataset.removeScope);
2910
+ return W("global"), Pt && Ce(!1), E(g.dataset.tab);
2911
+ if (g.dataset.remove) return ea(g.dataset.remove, g.dataset.removeScope);
2827
2912
  if (g.dataset.applyMode)
2828
- return ge("apply-mode", g.dataset.applyMode), Ce(!1), H(g.dataset.applyMode === "copy" ? "Copy prompt copies straight away" : "Copy prompt shows a preview first");
2913
+ return oe("apply-mode", g.dataset.applyMode), Ae(!1), H(g.dataset.applyMode === "copy" ? "Copy prompt copies straight away" : "Copy prompt shows a preview first");
2829
2914
  switch (g.dataset.action) {
2830
2915
  case "close":
2831
- return Ke();
2916
+ return Xe();
2832
2917
  case "minimise":
2833
- return Kn(), (o.querySelector('.tab[aria-pressed="true"]') || u[0]).focus();
2918
+ return Zn(), (o.querySelector('.tab[aria-pressed="true"]') || h[0]).focus();
2834
2919
  case "reset":
2835
- return e.resetState(), H("Reset to defaults · ⌘Z to undo");
2920
+ return t.resetState(), H("Reset to defaults · ⌘Z to undo");
2836
2921
  case "copy":
2837
- return ce(location.href, "Link copied");
2922
+ return he(location.href, "Link copied");
2838
2923
  case "pick":
2839
- return pe ? Ee() : zt();
2924
+ return fe ? Te() : Ut();
2840
2925
  case "compare":
2841
- he || Te(te.getAttribute("aria-pressed") !== "true");
2926
+ me || Pe(ne.getAttribute("aria-pressed") !== "true");
2842
2927
  return;
2843
2928
  case "undo":
2844
- return Ut();
2929
+ return Vt();
2845
2930
  case "redo":
2846
- return qt();
2931
+ return _t();
2847
2932
  case "back":
2848
- return G("global");
2933
+ return W("global");
2849
2934
  case "changes":
2850
- return G(K === "changes" ? "global" : "changes");
2935
+ return W(K === "changes" ? "global" : "changes");
2851
2936
  case "apply":
2852
- return Xn();
2937
+ return na();
2853
2938
  case "apply-menu":
2854
- return Ce(ue.hidden);
2939
+ return Ae(ge.hidden);
2855
2940
  case "dialog-close":
2856
- return Ze();
2941
+ return Qe();
2857
2942
  case "dialog-copy":
2858
- return ce(Wt.value, "Prompt copied · paste it into your agent");
2943
+ return he(Zt.value, "Prompt copied · paste it into your agent");
2859
2944
  case "setup-copy":
2860
- return D && ce(D.text2copy, D.copied);
2945
+ return D && he(D.text2copy, D.copied);
2861
2946
  case "setup-dismiss":
2862
- return ge(Xt, Ae.dataset.status), Le();
2947
+ return oe(en, Oe.dataset.status), Fe();
2863
2948
  }
2864
2949
  }
2865
- }), o.addEventListener("keydown", (d) => {
2866
- if (d.key === "Escape") {
2867
- if (!Me.hidden) return Ze();
2868
- if (!ue.hidden) return Ce(!1);
2950
+ }), o.addEventListener("keydown", (c) => {
2951
+ if (c.key === "Escape") {
2952
+ if (!Le.hidden) return Qe();
2953
+ if (!ge.hidden) return Ae(!1);
2869
2954
  }
2870
- !(d.metaKey || d.ctrlKey) || d.key.toLowerCase() !== "z" || d.target.matches?.('input[type="text"], textarea') || (d.preventDefault(), d.shiftKey ? qt() : Ut());
2871
- }), document.addEventListener("keydown", (d) => {
2872
- d.altKey && (d.code === "KeyT" && (d.preventDefault(), Ge()), d.code === "KeyC" && (d.preventDefault(), Te(te.getAttribute("aria-pressed") !== "true")));
2873
- }), ne("panel") === "open" ? W({ animate: !1 }) : ne("panel") === "tabs" && (W({ animate: !1 }), $e(!0)), { open: W, close: Ke, toggle: Ge, toast: H, pick: zt, prompt: Gt };
2955
+ !(c.metaKey || c.ctrlKey) || c.key.toLowerCase() !== "z" || c.target.matches?.('input[type="text"], textarea') || (c.preventDefault(), c.shiftKey ? _t() : Vt());
2956
+ }), document.addEventListener("keydown", (c) => {
2957
+ c.altKey && (c.code === "KeyT" && (c.preventDefault(), Me()), c.code === "KeyC" && (c.preventDefault(), Pe(ne.getAttribute("aria-pressed") !== "true")));
2958
+ }), Z("panel") === "open" ? G({ animate: !1 }) : Z("panel") === "tabs" && (G({ animate: !1 }), Ce(!0)), { open: G, close: Xe, toggle: Me, toast: H, pick: Ut, prompt: Xt };
2874
2959
  }
2875
- const kn = [ho, Be, qn, vt, Ga, yt, io, Ka], yo = ':root{--twd-font-heading: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--twd-font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--twd-text-xs: .694rem;--twd-text-sm: .833rem;--twd-text-base: 1rem;--twd-text-lg: 1.2rem;--twd-text-xl: 1.44rem;--twd-text-2xl: 1.728rem;--twd-text-3xl: 2.074rem;--twd-leading-tight: 1.2;--twd-leading-normal: 1.5;--twd-weight-heading: 600;--twd-weight-strong: 600;--twd-bg: #fafafa;--twd-surface: #ffffff;--twd-surface-raised: #ffffff;--twd-text: #18181b;--twd-text-muted: #71717a;--twd-border: #e4e4e7;--twd-primary: #4f46e5;--twd-primary-hover: #4338ca;--twd-on-primary: #ffffff;--twd-focus: #6366f1;--twd-success: #16a34a;--twd-warning: #d97706;--twd-danger: #dc2626;--twd-radius-control: 8px;--twd-radius-container: 12px;--twd-space-1: 4px;--twd-space-2: 8px;--twd-space-3: 12px;--twd-space-4: 16px;--twd-space-5: 24px;--twd-space-6: 32px;--twd-space-7: 48px;--twd-space-8: 64px;--twd-control-height: 40px;--twd-control-pad-x: 16px;--twd-page-pad: var(--twd-space-5);--twd-section-gap: var(--twd-space-6);--twd-card-pad: var(--twd-space-5);--twd-card-gap: var(--twd-space-2);--twd-control-gap: var(--twd-space-3);--twd-border-width: 1px;--twd-border-width-container: var(--twd-border-width);--twd-shadow-sm: 0 1px 2px rgb(0 0 0 / .06);--twd-shadow-md: 0 4px 12px rgb(0 0 0 / .08);--twd-shadow-lg: 0 12px 32px rgb(0 0 0 / .12);--twd-button-bg: var(--twd-primary);--twd-button-fg: var(--twd-on-primary);--twd-button-border: transparent;--twd-button-hover: var(--twd-primary-hover);--twd-card-bg: var(--twd-surface);--twd-card-border: var(--twd-border);--twd-card-shadow: var(--twd-shadow-sm)}';
2876
- function ko() {
2960
+ const Cn = [vo, He, Wn, St, to, $t, mo, eo], Ao = ':root{--twd-font-heading: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--twd-font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--twd-text-xs: .694rem;--twd-text-sm: .833rem;--twd-text-base: 1rem;--twd-text-lg: 1.2rem;--twd-text-xl: 1.44rem;--twd-text-2xl: 1.728rem;--twd-text-3xl: 2.074rem;--twd-leading-tight: 1.2;--twd-leading-normal: 1.5;--twd-weight-heading: 600;--twd-weight-strong: 600;--twd-bg: #fafafa;--twd-surface: #ffffff;--twd-surface-raised: #ffffff;--twd-text: #18181b;--twd-text-muted: #71717a;--twd-border: #e4e4e7;--twd-primary: #4f46e5;--twd-primary-hover: #4338ca;--twd-on-primary: #ffffff;--twd-focus: #6366f1;--twd-success: #16a34a;--twd-warning: #d97706;--twd-danger: #dc2626;--twd-radius-control: 8px;--twd-radius-container: 12px;--twd-space-1: 4px;--twd-space-2: 8px;--twd-space-3: 12px;--twd-space-4: 16px;--twd-space-5: 24px;--twd-space-6: 32px;--twd-space-7: 48px;--twd-space-8: 64px;--twd-control-height: 40px;--twd-control-pad-x: 16px;--twd-page-pad: var(--twd-space-5);--twd-section-gap: var(--twd-space-6);--twd-card-pad: var(--twd-space-5);--twd-card-gap: var(--twd-space-2);--twd-control-gap: var(--twd-space-3);--twd-border-width: 1px;--twd-border-width-container: var(--twd-border-width);--twd-shadow-sm: 0 1px 2px rgb(0 0 0 / .06);--twd-shadow-md: 0 4px 12px rgb(0 0 0 / .08);--twd-shadow-lg: 0 12px 32px rgb(0 0 0 / .12);--twd-button-bg: var(--twd-primary);--twd-button-fg: var(--twd-on-primary);--twd-button-border: transparent;--twd-button-hover: var(--twd-primary-hover);--twd-card-bg: var(--twd-surface);--twd-card-border: var(--twd-border);--twd-card-shadow: var(--twd-shadow-sm)}';
2961
+ function Lo() {
2877
2962
  if (getComputedStyle(document.documentElement).getPropertyValue("--twd-radius-control").trim() || document.getElementById("twiddle-tokens")) return;
2878
- const e = document.createElement("style");
2879
- e.id = "twiddle-tokens", e.textContent = yo, document.head.prepend(e);
2963
+ const t = document.createElement("style");
2964
+ t.id = "twiddle-tokens", t.textContent = Ao, document.head.prepend(t);
2880
2965
  }
2881
2966
  if (!window.Twiddle) {
2882
- ko(), kn.forEach((n) => ca(n.tokens)), Mn(mt);
2883
- let t;
2884
- const e = () => {
2885
- mt(ht()), t = vo({ sections: kn, store: da, view: { suspend: fa, resume: ga } });
2967
+ Lo(), Cn.forEach((n) => ga(n.tokens)), Pn(wt);
2968
+ let e;
2969
+ const t = () => {
2970
+ wt(mt()), e = To({ sections: Cn, store: fa, view: { suspend: wa, resume: ya } });
2886
2971
  };
2887
- document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", e) : e(), window.Twiddle = {
2888
- open: () => t && t.open(),
2889
- close: () => t && t.close(),
2890
- toggle: () => t && t.toggle(),
2891
- reset: () => $n(),
2892
- undo: () => En(),
2893
- redo: () => Cn(),
2894
- pick: () => t && t.pick(),
2895
- prompt: () => t ? t.prompt() : "",
2896
- getState: ht
2972
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", t) : t(), window.Twiddle = {
2973
+ open: () => e && e.open(),
2974
+ close: () => e && e.close(),
2975
+ toggle: () => e && e.toggle(),
2976
+ reset: () => Tn(),
2977
+ undo: () => An(),
2978
+ redo: () => Ln(),
2979
+ pick: () => e && e.pick(),
2980
+ prompt: () => e ? e.prompt() : "",
2981
+ getState: mt
2897
2982
  };
2898
2983
  }
2899
- const So = window.Twiddle;
2984
+ const Po = window.Twiddle;
2900
2985
  export {
2901
- So as Twiddle
2986
+ Po as Twiddle
2902
2987
  };