twiddle-panel 0.8.2 → 0.9.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.js CHANGED
@@ -1,8 +1,8 @@
1
- var TwiddleBundle=(function(Ke){"use strict";const We=new Set;let M=Xn(),K=[],ue=[],Ee=null,Lt=0;function Xn(){const e=new URLSearchParams(location.search).get("twd");if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function Zn(){const e=new URL(location.href);Object.keys(M).length?e.searchParams.set("twd",JSON.stringify(M)):e.searchParams.delete("twd"),history.replaceState(history.state,"",e)}function Ge(){Zn(),We.forEach(e=>e(M))}function ee(e,t){if(JSON.stringify(e)===JSON.stringify(M))return;const n=Date.now();t&&t===Ee&&n-Lt<400||(K.push(M),K.length>100&&K.shift()),ue=[],Ee=t,Lt=n,M=e,Ge()}function Ce(e,t){const n={...e,...t};return Object.keys(n).forEach(a=>{n[a]==null&&delete n[a]}),Object.keys(n).length?n:null}function U(e,t,n){const a={...e};return n==null?delete a[t]:a[t]=n,a}function Ye(){return JSON.parse(JSON.stringify(M))}function Jn(e,t){ee(U(M,e,Ce(M[e],t)),`${e}:${Object.keys(t)}`)}function Qn(e,t=`multi:${Object.keys(e)}`){const n=Object.entries(e).reduce((a,[o,s])=>U(a,o,Ce(a[o],s)),M);ee(n,t)}function Pt(e,t,n){const a=U(M.scopes?.[e],t,Ce(M.scopes?.[e]?.[t],n)),o=U(M.scopes,e,Object.keys(a).length?a:null);ee(U(M,"scopes",Object.keys(o).length?o:null),`${e}|${t}:${Object.keys(n)}`)}function ea(e,t){if(t)return Pt(e,t,Object.fromEntries(Object.keys(M.scopes?.[e]?.[t]||{}).map(a=>[a,null])));const n=U(M.scopes,e,null);ee(U(M,"scopes",Object.keys(n).length?n:null))}function ta(e,t){const n=M.scopes?.[e];if(!n||e===t)return;let a={...M.scopes[t]};Object.entries(n).forEach(([s,r])=>{a=U(a,s,Ce(a[s],r))});const o=U(U(M.scopes,e,null),t,a);ee(U(M,"scopes",o))}function Ot(){ee({})}function Ft(){K.length&&(ue.push(M),M=K.pop(),Ee=null,Ge())}function Nt(){ue.length&&(K.push(M),M=ue.pop(),Ee=null,Ge())}const na=()=>K.length>0,aa=()=>ue.length>0;function jt(e){return We.add(e),()=>We.delete(e)}const oa=Object.freeze(Object.defineProperty({__proto__:null,canRedo:aa,canUndo:na,getState:Ye,moveScope:ta,onChange:jt,redo:Nt,removeScope:ea,resetState:Ot,setScope:Pt,setSection:Jn,setSections:Qn,undo:Ft},Symbol.toStringTag,{value:"Module"})),Rt=[];let Xe=[],Ze={},R=null,te=!1,zt={};function ra(e){typeof e=="function"&&Rt.push(e)}const It=e=>Object.assign({},...Rt.map(t=>t(e)||{})),Je=e=>/^(\.[\w-]+|\[data-twd="[^"]+"\])$/.test(e),sa=e=>{try{return document.querySelector(e),!0}catch{return!1}};function ia(){return(!R||!R.isConnected)&&(R=document.createElement("style"),R.id="twiddle-scoped",document.head.appendChild(R)),R}function Dt(){const e=document.documentElement;Xe.forEach(t=>e.style.removeProperty(t)),Xe=[],Ze={}}function Qe(e){if(zt=e,te)return;const t=document.documentElement;Dt();const n=It(e),a=Object.entries(e.scopes||{}).filter(([s])=>sa(s)).sort(([s],[r])=>Je(r)-Je(s)).map(([s,r])=>[s,It(r)]);Object.entries(n).forEach(([s,r])=>t.style.setProperty(s,r)),Xe=Object.keys(n),Ze=n;const o=a.filter(([,s])=>Object.keys(s).length).map(([s,r])=>`${s} {
2
- ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
1
+ var TwiddleBundle=(function(et){"use strict";const tt=new Set;let M=ca(),Z=[],me=[],Le=null,Vt=0;function ca(){const e=new URLSearchParams(location.search).get("twd");if(!e)return{};try{return JSON.parse(e)}catch{return{}}}function pa(){const e=new URL(location.href);Object.keys(M).length?e.searchParams.set("twd",JSON.stringify(M)):e.searchParams.delete("twd"),history.replaceState(history.state,"",e)}function nt(){pa(),tt.forEach(e=>e(M))}function J(e,t){if(JSON.stringify(e)===JSON.stringify(M))return;const n=Date.now();t&&t===Le&&n-Vt<400||(Z.push(M),Z.length>100&&Z.shift()),me=[],Le=t,Vt=n,M=e,nt()}function be(e,t){const n={...e,...t};return Object.keys(n).forEach(a=>{n[a]==null&&delete n[a]}),Object.keys(n).length?n:null}function z(e,t,n){const a={...e};return n==null?delete a[t]:a[t]=n,a}function at(){return JSON.parse(JSON.stringify(M))}function ua(e,t){J(z(M,e,be(M[e],t)),`${e}:${Object.keys(t)}`)}function ha(e,t=`multi:${Object.keys(e)}`){const n=Object.entries(e).reduce((a,[o,r])=>z(a,o,be(a[o],r)),M);J(n,t)}function qt(e,t,n){const a=z(M.scopes?.[e],t,be(M.scopes?.[e]?.[t],n)),o=z(M.scopes,e,Object.keys(a).length?a:null);J(z(M,"scopes",Object.keys(o).length?o:null),`${e}|${t}:${Object.keys(n)}`)}function fa(e,t,n=`multi:${Object.keys(t)}`){const a=Object.entries(t).reduce((r,[s,i])=>z(r,s,be(r?.[s],i)),M.scopes?.[e]),o=z(M.scopes,e,Object.keys(a).length?a:null);J(z(M,"scopes",Object.keys(o).length?o:null),`${e}|${n}`)}function ga(e,t){if(t)return qt(e,t,Object.fromEntries(Object.keys(M.scopes?.[e]?.[t]||{}).map(a=>[a,null])));const n=z(M.scopes,e,null);J(z(M,"scopes",Object.keys(n).length?n:null))}function ma(e,t){const n=M.scopes?.[e];if(!n||e===t)return;let a={...M.scopes[t]};Object.entries(n).forEach(([r,s])=>{a=z(a,r,be(a[r],s))});const o=z(z(M.scopes,e,null),t,a);J(z(M,"scopes",o))}function Ht(){J({})}function _t(){Z.length&&(me.push(M),M=Z.pop(),Le=null,nt())}function Kt(){me.length&&(Z.push(M),M=me.pop(),Le=null,nt())}const ba=()=>Z.length>0,xa=()=>me.length>0;function Wt(e){return tt.add(e),()=>tt.delete(e)}const wa=Object.freeze(Object.defineProperty({__proto__:null,canRedo:xa,canUndo:ba,getState:at,moveScope:ma,onChange:Wt,redo:Kt,removeScope:ga,resetState:Ht,setScope:qt,setScopeSections:fa,setSection:ua,setSections:ha,undo:_t},Symbol.toStringTag,{value:"Module"})),Gt=':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)}',va=[...Gt.matchAll(/(--twd-[\w-]+):\s*([^;]*var\(--twd-[^;]*);/g)].map(e=>[e[1],e[2].trim()]);function ya(e){const t=document.documentElement,n=document.createElement("div");n.hidden=!0,t.appendChild(n);const a=getComputedStyle(t),o=getComputedStyle(n),r=[];return va.forEach(([s,i])=>{const l=e[s];if(l!=null){String(l).includes("var(")&&r.push([s,l]);return}n.style.setProperty("--twd-probe",i),o.getPropertyValue("--twd-probe").trim()===a.getPropertyValue(s).trim()&&r.push([s,i])}),n.remove(),r}const Yt=[];let ot=[],rt={},R=null,se=!1,Xt={};function ka(e){typeof e=="function"&&Yt.push(e)}const Zt=e=>Object.assign({},...Yt.map(t=>t(e)||{})),st=e=>/^(\.[\w-]+|\[data-twd="[^"]+"\])$/.test(e),Sa=e=>{try{return document.querySelector(e),!0}catch{return!1}};function $a(){return(!R||!R.isConnected)&&(R=document.createElement("style"),R.id="twiddle-scoped",document.head.appendChild(R)),R}function Jt(){const e=document.documentElement;ot.forEach(t=>e.style.removeProperty(t)),ot=[],rt={}}function it(e){if(Xt=e,se)return;const t=document.documentElement;Jt();const n=Zt(e),a=e.scopes?ya(n):[],o=Object.entries(e.scopes||{}).filter(([s])=>Sa(s)).sort(([s],[i])=>st(i)-st(s)).map(([s,i])=>[s,Zt(i)]);Object.entries(n).forEach(([s,i])=>t.style.setProperty(s,i)),ot=Object.keys(n),rt=n;const r=o.filter(([,s])=>Object.keys(s).length).map(([s,i])=>`${s} {
2
+ ${[...a.filter(([l])=>!(l in i)).map(([l,d])=>` ${l}: ${d};`),...Object.entries(i).map(([l,d])=>` ${l}: ${d} !important;`)].join(`
3
3
  `)}
4
4
  }`).join(`
5
- `);(o||R)&&(ia().textContent=o)}function Bt(e){const t=document.documentElement,n=te,a={...Ze};Object.keys(a).forEach(o=>t.style.removeProperty(o)),R&&(R.disabled=!0);try{return e()}finally{n||(Object.entries(a).forEach(([o,s])=>t.style.setProperty(o,s)),R&&(R.disabled=!1))}}function la(e,t=document.documentElement){return Bt(()=>{const n=getComputedStyle(t);return Object.fromEntries(e.map(a=>[a,n.getPropertyValue(a).trim()]))})}function da(){te||(Dt(),R&&(R.disabled=!0),te=!0)}function ca(){te&&(te=!1,R&&(R.disabled=!1),Qe(zt))}const pa=`
5
+ `);(r||R)&&($a().textContent=r)}function Qt(e){const t=document.documentElement,n=se,a={...rt};Object.keys(a).forEach(o=>t.style.removeProperty(o)),R&&(R.disabled=!0);try{return e()}finally{n||(Object.entries(a).forEach(([o,r])=>t.style.setProperty(o,r)),R&&(R.disabled=!1))}}function Ea(e,t=document.documentElement){return Qt(()=>{const n=getComputedStyle(t);return Object.fromEntries(e.map(a=>[a,n.getPropertyValue(a).trim()]))})}function Ca(){se||(Jt(),R&&(R.disabled=!0),se=!0)}function Ma(){se&&(se=!1,R&&(R.disabled=!1),it(Xt))}const Ta=`
6
6
  :host { all: initial; } /* block fonts/colours inherited from the page */
7
7
  * { box-sizing: border-box; }
8
8
 
@@ -14,6 +14,9 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
14
14
  --p-hover: #f4f4f5;
15
15
  --p-track: #f4f4f5;
16
16
  --p-selected: #ffffff;
17
+ --p-line-strong: #d4d4d8; /* tile and segmented outlines */
18
+ --p-brand: #4f46e5; /* selected borders (Twiddle accent) */
19
+ --p-brand-fg: #4f46e5; /* selected icons and labels */
17
20
  --p-accent: #18181b;
18
21
  --p-on-accent: #ffffff;
19
22
  --p-shadow: 0 12px 40px rgb(0 0 0 / 0.14), 0 2px 6px rgb(0 0 0 / 0.06);
@@ -44,6 +47,11 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
44
47
  --p-hover: #27272a;
45
48
  --p-track: #27272a;
46
49
  --p-selected: #3f3f46;
50
+ --p-line-strong: #3f3f46;
51
+ /* Brand on dark (Ravi, 2026-10-16): the accent #4f46e5 is too dark to read on
52
+ #1c1c1f, so borders use #6366f1 and icons/labels the lighter #818cf8. */
53
+ --p-brand: #6366f1;
54
+ --p-brand-fg: #818cf8;
47
55
  --p-accent: #f4f4f5;
48
56
  --p-on-accent: #18181b;
49
57
  --p-shadow: 0 12px 40px rgb(0 0 0 / 0.5), 0 2px 6px rgb(0 0 0 / 0.3);
@@ -62,14 +70,14 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
62
70
  cursor: pointer;
63
71
  padding: 0;
64
72
  }
65
- /* Open or minimised: centred on the tabs. 10px = panel border 1 + tab bar
73
+ /* Minimised: centred on the tab bar. 10px = panel border 1 + tab bar
66
74
  padding 6 + half a tab (~49px) − half the launcher (22). */
67
75
  .launcher { transition: margin-bottom .2s cubic-bezier(0.2, 0.8, 0.2, 1); }
68
- .wrap.is-open .launcher { margin-bottom: 10px; }
76
+ .wrap.is-min .launcher { margin-bottom: 10px; } /* open: the actions row is at the bottom, already centred (~40px tall) */
69
77
  /* Left corners: the panel opens to the right of the launcher. Top corners: tops aligned. */
70
78
  .wrap.at-left { flex-direction: row-reverse; }
71
79
  .wrap.at-top { align-items: flex-start; }
72
- .wrap.at-top.is-open .launcher { margin-bottom: 0; }
80
+ .wrap.at-top.is-min .launcher { margin-bottom: 0; }
73
81
  .launcher { touch-action: none; }
74
82
  .wrap.dragging .launcher { cursor: grabbing; }
75
83
  .wrap.dragging .panel { pointer-events: none; }
@@ -105,15 +113,10 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
105
113
  }
106
114
  .panel[hidden] { display: none; }
107
115
 
108
- .head {
109
- display: flex; align-items: center; gap: 4px;
110
- padding: 10px 10px 6px 14px; /* the actions row below carries the divider */
111
- }
112
- .brand { font-weight: 600; font-size: 14px; letter-spacing: -0.01em; flex: 1; }
113
116
  .icon-btn {
114
117
  width: 28px; height: 28px; padding: 0;
115
118
  border: 0; border-radius: 6px;
116
- background: transparent; color: var(--p-muted);
119
+ background: transparent; color: var(--p-fg);
117
120
  display: grid; place-items: center;
118
121
  cursor: pointer;
119
122
  }
@@ -157,6 +160,7 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
157
160
  display: flex; gap: 2px; padding: 2px;
158
161
  border-radius: 6px;
159
162
  background: var(--p-track);
163
+ border: 1px solid var(--p-line-strong); /* clearer group edge (Ravi, 2026-10-16) */
160
164
  }
161
165
  .seg [role="radio"] {
162
166
  flex: 1 1 0; min-width: 0;
@@ -173,7 +177,7 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
173
177
  .seg [role="radio"]:hover { background: var(--p-hover); color: var(--p-fg); }
174
178
  .seg [aria-checked="true"] {
175
179
  background: var(--p-bg); color: var(--p-fg);
176
- box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
180
+ box-shadow: inset 0 0 0 1px var(--p-brand);
177
181
  }
178
182
  .seg [aria-checked="true"]:hover { background: var(--p-hover); }
179
183
  .seg [role="radio"]:focus-visible { outline: 2px solid var(--p-accent); outline-offset: 0; position: relative; }
@@ -298,7 +302,7 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
298
302
  box-shadow: inset 0 0 0 2px transparent;
299
303
  }
300
304
  .swatch:hover .swatch-ring { box-shadow: inset 0 0 0 2px var(--p-line); }
301
- .swatch[aria-checked="true"] .swatch-ring { box-shadow: inset 0 0 0 2px var(--p-accent); }
305
+ .swatch[aria-checked="true"] .swatch-ring { box-shadow: inset 0 0 0 2px var(--p-brand); }
302
306
  .swatch:focus-visible .swatch-ring { box-shadow: none; outline: 2px dashed var(--p-accent); outline-offset: -2px; }
303
307
  .swatch-dot { width: 22px; height: 22px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08); }
304
308
  .swatch-label { font-size: 12px; color: var(--p-muted); }
@@ -306,16 +310,60 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
306
310
 
307
311
  /* Second header row: the global actions that used to be the footer */
308
312
  .actions {
309
- border-bottom: 1px solid var(--p-line);
310
- padding: 2px 10px 10px;
313
+ padding: 8px 8px 8px 8px;
314
+ border-top: 1px solid var(--p-line);
311
315
  display: flex; align-items: center; gap: 2px;
312
316
  color: var(--p-muted); font-size: 12px;
313
317
  }
314
318
  .spacer { flex: 1; }
319
+ .sep { width: 1px; height: 16px; margin: 0 3px; background: var(--p-line-strong); flex: none; }
320
+ /* Changes: an icon with the count badge on its corner */
321
+ /* Changes: just the count in a circle (Ravi, 2026-10-16); opens the side panel */
322
+ .changes-btn {
323
+ flex: none; height: 28px; padding: 0 3px; border: 0; border-radius: 6px;
324
+ background: transparent; display: grid; place-items: center; cursor: pointer;
325
+ }
326
+ .changes-btn .badge { min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px; font-size: 11px; background: var(--p-hover); color: var(--p-muted); }
327
+ .changes-btn.has-changes .badge { background: var(--p-brand); color: #fff; }
328
+ .changes-btn:hover .badge { box-shadow: 0 0 0 2px var(--p-line-strong); }
329
+ .changes-btn[aria-pressed="true"] .badge { box-shadow: 0 0 0 2px var(--p-brand-fg); }
330
+ .changes-btn:focus-visible { outline: 2px solid var(--p-accent); outline-offset: 0; }
331
+
332
+ /* Changes side panel: beside the main panel, on the side away from the edge */
333
+ .side {
334
+ width: 300px; max-width: calc(100vw - var(--off-x) - 440px);
335
+ max-height: calc(100vh - var(--off-y) - 16px);
336
+ max-height: calc(100dvh - var(--off-y) - 16px);
337
+ background: var(--p-bg); border: 1px solid var(--p-line); border-radius: 14px;
338
+ box-shadow: var(--p-shadow);
339
+ display: flex; flex-direction: column; overflow: hidden;
340
+ }
341
+ .side[hidden] { display: none; }
342
+ .side-head {
343
+ display: flex; align-items: center; justify-content: space-between;
344
+ padding: 10px 8px 8px 14px; border-bottom: 1px solid var(--p-line);
345
+ font-size: 13px; font-weight: 600;
346
+ }
347
+ .side .body { flex: 0 1 auto; min-height: 0; } /* as tall as the list; scrolls when the window is shorter */
348
+ .wrap.at-top .side { align-self: flex-start; }
349
+ /* Phones: the one footer row gets compact (no dividers, "Copy", 26px icons) */
350
+ @media (max-width: 440px) {
351
+ .actions .sep, .apply-btn .wide { display: none; }
352
+ .actions .icon-btn { width: 26px; }
353
+ /* icons only; the names stay as tooltips and for screen readers */
354
+ .tab span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
355
+ .tab { padding: 9px 0; }
356
+ }
357
+ /* Not enough room beside it (phones): over the main panel instead */
358
+ @media (max-width: 780px) {
359
+ .side { position: absolute; bottom: 0; right: 54px; width: min(360px, calc(100vw - var(--off-x) - 70px)); max-width: none; z-index: 4; }
360
+ .wrap.at-left .side { right: auto; left: 54px; }
361
+ .wrap.at-top .side { bottom: auto; top: 0; }
362
+ }
315
363
  .icon-btn:disabled { opacity: .35; cursor: default; background: transparent; }
316
364
  .actions .icon-btn, .actions .apply { flex: none; } /* Undo / Redo / Copy prompt keep their size; Changes gives way if space runs out */
317
365
  .actions .text-btn { min-width: 0; overflow: hidden; }
318
- .icon-btn[aria-pressed="true"] { background: var(--p-accent); color: var(--p-on-accent); }
366
+ .icon-btn[aria-pressed="true"], .icon-btn[aria-pressed="true"]:hover { background: var(--p-hover); color: var(--p-brand-fg); }
319
367
  kbd {
320
368
  font: 11px ui-monospace, "SF Mono", Menlo, monospace;
321
369
  border: 1px solid var(--p-line); border-radius: 4px;
@@ -349,9 +397,9 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
349
397
  color: var(--p-muted); font: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
350
398
  }
351
399
  .text-btn:hover { background: var(--p-hover); color: var(--p-fg); }
352
- .text-btn[aria-pressed="true"] { background: var(--p-hover); color: var(--p-fg); }
400
+ .text-btn[aria-pressed="true"] { background: var(--p-hover); color: var(--p-brand-fg); }
353
401
  .badge {
354
- min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
402
+ min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; line-height: 1;
355
403
  display: inline-grid; place-items: center;
356
404
  background: var(--p-accent); color: var(--p-on-accent);
357
405
  font-size: 11px; font-weight: 600;
@@ -363,20 +411,22 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
363
411
  .apply-btn {
364
412
  height: 28px; padding: 0 12px;
365
413
  border: 0; border-radius: 6px;
366
- background: var(--p-accent); color: var(--p-on-accent);
367
- font: inherit; font-size: 12px; font-weight: 400; cursor: pointer;
414
+ /* Soft brand button (Ravi, 2026-10-16): was solid white */
415
+ background: color-mix(in srgb, var(--p-brand) 22%, transparent); color: var(--p-brand-fg);
416
+ font: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
368
417
  }
369
418
  .apply { flex: none; }
419
+ .apply-btn:hover, .apply-menu-btn:hover { background: color-mix(in srgb, var(--p-brand) 32%, transparent); }
370
420
  .apply .apply-btn { border-radius: 6px 0 0 6px; display: inline-flex; align-items: center; gap: 6px; padding: 0 10px; white-space: nowrap; }
371
421
  .apply-menu-btn {
372
422
  width: 22px; height: 28px; padding: 0;
373
423
  display: grid; place-items: center;
374
- border: 0; border-left: 1px solid color-mix(in srgb, var(--p-on-accent) 25%, transparent);
424
+ border: 0; border-left: 1px solid color-mix(in srgb, var(--p-brand) 45%, transparent);
375
425
  border-radius: 0 6px 6px 0;
376
- background: var(--p-accent); color: var(--p-on-accent); cursor: pointer;
426
+ background: color-mix(in srgb, var(--p-brand) 22%, transparent); color: var(--p-brand-fg); cursor: pointer;
377
427
  }
378
428
  .menu {
379
- position: absolute; right: 0; top: calc(100% + 6px); z-index: 2; /* opens downwards from the header */
429
+ position: absolute; right: 0; bottom: calc(100% + 6px); z-index: 2; /* opens upwards from the bottom actions */
380
430
  min-width: 180px; padding: 4px; display: grid; gap: 2px;
381
431
  background: var(--p-bg); border: 1px solid var(--p-line); border-radius: 8px;
382
432
  box-shadow: var(--p-shadow);
@@ -431,6 +481,7 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
431
481
  }
432
482
  .scope-name .muted { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
433
483
  .scope-target:empty, .warnings:empty { display: none; }
484
+ .scope-note { font-size: 12px; line-height: 1.45; color: var(--p-muted); }
434
485
  .muted { color: var(--p-muted); }
435
486
  .empty { padding: 14px; color: var(--p-muted); font-size: 12px; line-height: 1.5; }
436
487
 
@@ -636,23 +687,26 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
636
687
  /* ---------- Tabbed layout (Figma: Panel — tabbed layout (proposal), 254:323) ---------- */
637
688
  .tabbar {
638
689
  display: flex; gap: 2px; padding: 6px;
639
- border-top: 1px solid var(--p-line);
690
+ border-bottom: 1px solid var(--p-line); /* tabs on top (Ravi, 2026-10-16) */
640
691
  }
641
692
  .tab {
642
693
  flex: 1 1 0; min-width: 0;
643
694
  display: grid; justify-items: center; gap: 3px;
644
- padding: 7px 2px 6px; border: 0; border-radius: 8px;
645
- background: transparent; color: var(--p-muted);
695
+ padding: 7px 0 6px; border: 0; border-radius: 8px; /* no side padding: six labels + the Minimise chevron fit 360px */
696
+ background: transparent; color: var(--p-fg);
646
697
  font: inherit; font-size: 11px; cursor: pointer;
647
698
  }
648
699
  .tab:hover { background: var(--p-hover); color: var(--p-fg); }
649
- .tab[aria-pressed="true"] { background: var(--p-hover); color: var(--p-fg); font-weight: 600; }
700
+ .tab[aria-pressed="true"] { background: var(--p-hover); color: var(--p-brand-fg); font-weight: 600; }
650
701
  .tab span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
651
702
 
652
703
  /* Minimised (proposal, not yet in Figma): only the tab bar (and the Compare
653
704
  strip while it shows); clicking a tab opens the panel on that tab. */
654
705
  .panel.minimised > :not(.tabbar):not(.original-pill) { display: none; }
655
- .panel.minimised .tabbar { border-top: 0; }
706
+ .panel.minimised .tabbar { border-bottom: 0; }
707
+ .tab-min { flex: none; align-self: center; width: 24px; }
708
+ .tab-min svg { transition: transform .2s cubic-bezier(0.2, 0.8, 0.2, 1); }
709
+ .panel.minimised .tab-min svg { transform: rotate(180deg); }
656
710
  .page-fields { gap: 16px; }
657
711
  .page-heading { display: flex; align-items: baseline; justify-content: space-between; font-size: 13px; font-weight: 500; color: var(--p-fg); margin-bottom: -6px; }
658
712
  .page-heading .muted { font-size: 12px; font-weight: 400; }
@@ -661,12 +715,13 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
661
715
  .tiles { display: grid; grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr)); gap: 8px; }
662
716
  .tile {
663
717
  display: grid; justify-items: center; align-content: start; gap: 6px; min-width: 0;
664
- padding: 8px; border: 1px solid var(--p-line); border-radius: 10px;
718
+ padding: 8px; border: 1px solid var(--p-line-strong); border-radius: 10px;
665
719
  background: var(--p-bg); color: var(--p-muted);
666
720
  font: inherit; font-size: 11px; text-align: center; cursor: pointer;
667
721
  }
668
722
  .tile:hover { border-color: var(--p-muted); }
669
- .tile[aria-checked="true"] { border-color: var(--p-accent); box-shadow: inset 0 0 0 1px var(--p-accent); color: var(--p-fg); font-weight: 600; }
723
+ .tile[aria-checked="true"] { border-color: var(--p-brand); box-shadow: inset 0 0 0 1px var(--p-brand); color: var(--p-fg); font-weight: 600; }
724
+ .tile.near:not([aria-checked="true"]) { border-style: dashed; border-color: var(--p-brand); } /* between two presets (Figma 275:921) */
670
725
  .tile:focus-visible { outline: 2px solid var(--p-accent); outline-offset: 2px; }
671
726
  .tile.wide { grid-column: 1 / -1; }
672
727
  .tile-text { display: grid; gap: 1px; min-width: 0; max-width: 100%; }
@@ -691,26 +746,35 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
691
746
  .sketch i { height: 9px; border-radius: 2px; background: var(--p-line); }
692
747
  .sketch i:first-child { background: var(--p-muted); }
693
748
  .shape { display: block; }
694
- .shape-button { width: 52px; height: 24px; background: #4f46e5; }
695
- .shape-button.size-small { width: 38px; height: 16px; border-radius: 4px; }
696
- .shape-button.size-medium { width: 52px; height: 22px; border-radius: 5px; }
697
- .shape-button.size-large { width: 66px; height: 28px; border-radius: 6px; }
749
+ /* Live previews: --pv-* come from the page (panel.js syncPreviews); fallbacks = defaults. */
750
+ .shape-button { width: 52px; height: 24px; background: var(--pv-primary, #4f46e5); }
751
+ .shape-button.size-small { width: 38px; height: 16px; border-radius: min(var(--pv-radius-control, 8px), 8px); }
752
+ .shape-button.size-medium { width: 52px; height: 22px; border-radius: min(var(--pv-radius-control, 8px), 11px); }
753
+ .shape-button.size-large { width: 66px; height: 28px; border-radius: min(var(--pv-radius-control, 8px), 14px); }
698
754
  .shape-card { width: 52px; height: 38px; background: var(--p-bg); border: 1px solid var(--p-muted); }
699
- .shape-card.border-none { border-color: transparent; background: var(--p-hover); border-radius: 6px; }
700
- .shape-card.border-thin { border-radius: 6px; }
701
- .shape-card.border-thick { border-width: 2px; border-radius: 6px; }
702
- /* Style tiles (v0.4): Figma "Shape — with styles" 257:711 */
703
- .shape-button[class*="style-"] { width: 52px; height: 22px; border-radius: 5px; display: grid; place-items: center; border: 1.5px solid transparent; }
704
- .shape-button[class*="style-"]::after { content: ""; width: 22px; height: 3px; border-radius: 2px; background: #a5b4fc; }
705
- .shape-button.style-solid::after { background: #fff; }
706
- .shape-button.style-soft { background: rgb(79 70 229 / 0.32); }
707
- .shape-button.style-outline { background: transparent; border-color: #818cf8; }
755
+ .shape-card[class*="border-"] { border-radius: min(calc(var(--pv-radius-container, 12px) / 2), 10px); }
756
+ .shape-card.border-none { border-color: transparent; background: var(--p-hover); }
757
+ .shape-card.border-thick { border-width: 2px; }
758
+ /* Button style tiles (Figma 281:1158) */
759
+ .shape-button[class*="style-"] { width: 52px; height: 22px; border-radius: min(var(--pv-radius-control, 8px), 11px); display: grid; place-items: center; border: 1.5px solid transparent; }
760
+ .shape-button[class*="style-"]::after { content: ""; width: 22px; height: 3px; border-radius: 2px; background: color-mix(in srgb, var(--pv-primary, #4f46e5) 55%, white); }
761
+ .shape-button.style-solid::after { background: var(--pv-on-primary, #fff); }
762
+ .shape-button.style-soft { background: color-mix(in srgb, var(--pv-primary, #4f46e5) 32%, transparent); }
763
+ .shape-button.style-outline { background: transparent; border-color: color-mix(in srgb, var(--pv-primary, #4f46e5) 70%, white); }
708
764
  .shape-button.style-ghost { background: transparent; }
709
- .shape-card[class*="style-"] { border-radius: 6px; }
710
- .shape-card.style-filled { background: var(--p-hover); border-color: var(--p-line); }
711
- .shape-card.style-outlined { background: transparent; border-color: var(--p-muted); }
712
- .shape-card.style-elevated { background: color-mix(in oklch, var(--p-hover) 88%, white); border-color: transparent; box-shadow: 0 5px 12px rgb(0 0 0 / 0.55); }
713
- .shape-card.style-tinted { background: rgb(79 70 229 / 0.2); border-color: rgb(129 140 248 / 0.5); }
765
+ /* Card style tiles: a mini card with content lines on a page backdrop (Figma 281:1421) */
766
+ .mini { display: grid; place-items: center; width: 60px; height: 42px; border-radius: 6px; background: var(--p-hover); }
767
+ .mini-card {
768
+ width: 44px; height: 28px; padding: 0 7px; box-sizing: border-box;
769
+ display: grid; align-content: center; gap: 4px;
770
+ border: 1px solid transparent; border-radius: min(calc(var(--pv-radius-container, 12px) / 2), 10px);
771
+ }
772
+ .mini-card i { display: block; width: 22px; height: 3px; border-radius: 2px; background: #a1a1aa; }
773
+ .mini-card i + i { width: 30px; background: #71717a; }
774
+ .mini-card.style-filled { background: #3f3f46; border-color: #52525b; }
775
+ .mini-card.style-outlined { background: transparent; border-color: #a1a1aa; }
776
+ .mini-card.style-elevated { background: #52525b; box-shadow: 0 4px 8px rgb(0 0 0 / 0.7); }
777
+ .mini-card.style-tinted { background: color-mix(in srgb, var(--pv-primary, #6366f1) 30%, transparent); border-color: color-mix(in srgb, var(--pv-primary, #6366f1) 70%, white); }
714
778
  .shape-card[class*="shadow-"] { width: 44px; height: 32px; border-radius: 6px; border-color: var(--p-line); margin: 4px 0 6px; }
715
779
  .shape-card.shadow-bold { border-color: var(--p-fg); }
716
780
 
@@ -761,8 +825,8 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
761
825
  .summary-swatch { width: 14px; height: 14px; border-radius: 4px; flex: none; }
762
826
  .summary-swatch[hidden] { display: none; }
763
827
  .summary-row .chev { display: grid; color: var(--p-muted); }
764
- `,L=(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={dial:L(20,1.8,'<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),link:L(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"/>'),reset:L(15,2,'<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/>'),close:L(15,2,'<path d="M18 6L6 18M6 6l12 12"/>'),chevron:L(12,2.4,'<path d="M9 6l6 6-6 6"/>'),pick:L(15,2,'<circle cx="12" cy="12" r="7"/><path d="M12 2v4M12 18v4M2 12h4M18 12h4"/>'),compare:L(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"/>'),undo:L(15,2,'<path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/>'),redo:L(15,2,'<path d="M15 14l5-5-5-5"/><path d="M20 9H9a5 5 0 0 0 0 10h3"/>'),back:L(15,2,'<path d="M15 18l-6-6 6-6"/>'),down:L(12,2.4,'<path d="M6 9l6 6 6-6"/>'),minimise:L(15,2,'<path d="M5 12h14"/>'),copy:L(13,2,'<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/>'),warn:L(13,2,'<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>'),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>',tabOverview:L(18,1.8,'<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),tabColour:L(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"/>'),tabType:L(18,2,'<path d="M5 7V5h14v2"/><path d="M12 5v14"/><path d="M9 19h6"/>'),tabSpacing:L(18,2,'<path d="M4 5v14M20 5v14"/><path d="M8 12h8"/><path d="M10 9l-3 3 3 3M14 9l3 3-3 3"/>'),tabShape:L(18,2,'<path d="M20 4h-9a7 7 0 0 0-7 7v9"/><path d="M20 10h-5a5 5 0 0 0-5 5v5"/>'),tabShadows:L(18,2,'<rect x="4" y="4" width="12" height="12" rx="2"/><path d="M20 8v10a2 2 0 0 1-2 2H8"/>'),sliders:L(15,2,'<path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/>')},Ut="twiddle:";function W(e){try{return localStorage.getItem(Ut+e)}catch{return null}}function ne(e,t){try{localStorage.setItem(Ut+e,t)}catch{}}const ae=44,oe=8,ua=4,qt={corner:"br",x:16,y:16};function ha(){try{const e=JSON.parse(W("position"));if(e&&/^[tb][lr]$/.test(e.corner)&&isFinite(e.x)&&isFinite(e.y))return e}catch{}return{...qt}}function Ht(e){const t=Math.max(oe,innerWidth-ae-oe),n=Math.max(oe,innerHeight-ae-oe);return{corner:e.corner,x:Math.round(Math.min(Math.max(e.x,oe),t)),y:Math.round(Math.min(Math.max(e.y,oe),n))}}function fa({wrapEl:e,launcherEl:t}){let n=ha();function a(){const d=Ht(n),p=d.corner[1]==="l",u=d.corner[0]==="t";Object.assign(e.style,{left:p?`${d.x}px`:"auto",right:p?"auto":`${d.x}px`,top:u?`${d.y}px`:"auto",bottom:u?"auto":`${d.y}px`}),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)}function o(d,p=!0){n=Ht(d),a(),p&&ne("position",JSON.stringify(n))}function s(d,p){const u=d+ae/2<innerWidth/2,v=p+ae/2<innerHeight/2,f=!v&&e.classList.contains("is-open")?10:0;return{corner:(v?"t":"b")+(u?"l":"r"),x:u?d:innerWidth-d-ae,y:v?p:innerHeight-p-ae-f}}let r=null,i=!1;t.addEventListener("pointerdown",d=>{if(d.button!==0)return;const p=t.getBoundingClientRect();r={id:d.pointerId,sx:d.clientX,sy:d.clientY,dx:d.clientX-p.left,dy:d.clientY-p.top,moving:!1}}),t.addEventListener("pointermove",d=>{if(!(!r||d.pointerId!==r.id)){if(!r.moving){if(Math.hypot(d.clientX-r.sx,d.clientY-r.sy)<ua)return;r.moving=!0,t.setPointerCapture(d.pointerId),e.classList.add("dragging")}o(s(d.clientX-r.dx,d.clientY-r.dy),!1)}});const l=d=>{!r||d.pointerId!==r.id||(r.moving&&(i=!0,e.classList.remove("dragging"),o(n)),r=null)};return t.addEventListener("pointerup",l),t.addEventListener("pointercancel",l),t.addEventListener("keydown",d=>{const p={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[d.key];if(!p||d.altKey||d.metaKey||d.ctrlKey)return;d.preventDefault();const u=d.shiftKey?10:1,v=n.corner[1]==="l"?1:-1,f=n.corner[0]==="t"?1:-1;o({corner:n.corner,x:n.x+p[0]*u*v,y:n.y+p[1]*u*f})}),window.addEventListener("resize",a),a(),{consumeClick(){const d=i;return i=!1,d},reset(){o({...qt})}}}function re({label:e,options:t,onSelect:n}){const a=document.createElement("div");a.className="seg",a.setAttribute("role","radiogroup"),a.setAttribute("aria-label",e);const o=t.map(l=>{const d=document.createElement("button");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});a.append(...o);let s=null;function r(l){s=l,o.forEach(p=>p.setAttribute("aria-checked",String(p.dataset.value===l)));const d=Math.max(0,o.findIndex(p=>p.dataset.value===l));o.forEach((p,u)=>{p.tabIndex=u===d?0:-1})}function i(l,d){l!==s&&(r(l),n(l)),d&&o.find(p=>p.dataset.value===l).focus()}return a.addEventListener("keydown",l=>{const d=o.indexOf(l.target);if(d<0)return;const p={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let u;if(p)u=(d+p+o.length)%o.length;else if(l.key==="Home")u=0;else if(l.key==="End")u=o.length-1;else return;l.preventDefault(),i(o[u].dataset.value,!0)}),r(null),{el:a,setValue:r}}const Vt=/var\(\s*(--twd-[\w-]+)/g,ga=/::?[\w-]+(\([^)]*\))?/g;function*Me(e){for(const t of e)t.selectorText!=null&&(yield t),t.cssRules&&(yield*Me(t.cssRules))}function ma(){const e=[];for(const t of document.styleSheets){if(t.ownerNode?.id==="twiddle-scoped")continue;let n;try{n=t.cssRules}catch{continue}for(const a of Me(n)){const o=[...a.style.cssText.matchAll(Vt)].map(s=>s[1]);o.length&&e.push({selectors:a.selectorText.split(","),vars:o})}}return e}function ba(e,t){const n=t.replace(ga,"").trim()||"*";try{return e.matches(n)}catch{return!1}}function _t(e){const t=new Set,n=[];return ma().forEach(({selectors:a,vars:o})=>{const s=a.find(r=>ba(e,r));s&&(o.forEach(r=>t.add(r)),n.push(s.trim()))}),[...(e.getAttribute("style")||"").matchAll(Vt)].forEach(a=>t.add(a[1])),{names:t,selectors:n}}const et=e=>window.CSS&&CSS.escape?CSS.escape(e):e;function xa(e){const t=[];let n=e;for(;n&&n.nodeType===1&&n!==document.body&&n!==document.documentElement;){if(n.id&&document.querySelectorAll(`#${et(n.id)}`).length===1)return t.unshift(`#${et(n.id)}`),t.join(" > ");const a=n.localName,o=[...n.parentElement.children].filter(s=>s.localName===a);t.unshift(o.length>1?`${a}:nth-of-type(${o.indexOf(n)+1})`:a),n=n.parentElement}return["body",...t].join(" > ")}function wa(e,t=_t(e).selectors){const n=e.getAttribute("data-twd");if(n)return`[data-twd="${n.replace(/"/g,"")}"]`;const a=[...e.classList],s=a.find(r=>t.some(i=>new RegExp(`\\.${r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(?![\\w-])`).test(i)))||a[0];return s?`.${et(s)}`:null}function ya(e){const t=_t(e),n=wa(e,t.selectors),a=(e.getAttribute("aria-label")||e.placeholder||e.textContent||"").trim().replace(/\s+/g," ");return{el:e,tag:e.localName,classes:[...e.classList],text:a.length>40?`${a.slice(0,40)}…`:a,tokens:t.names,elementSelector:xa(e),classSelector:n,classCount:n?document.querySelectorAll(n).length:0}}const tt=e=>e.localName+[...e.classList].map(t=>`.${t}`).join(""),va={radius:"px",intensity:"%",base:"px"},Kt=e=>e.charAt(0).toUpperCase()+e.slice(1),ka=(e,t)=>typeof t=="number"||/^\d+$/.test(t)?`${t}${va[e]||""}`:Kt(String(t));function Wt(e,t,n){const a=Bt(()=>e.tokens({[e.id]:t})||{}),o=Object.keys(a);let s={};if(o.length){const r=n.selector?document.querySelector(n.selector):void 0;s=la(o,r||void 0)}return{...n,sectionId:e.id,title:e.title,settings:Object.entries(t).map(([r,i])=>({key:r,label:Kt(r),value:ka(r,i),...e.describe?.(r,i)||{}})),tokens:o.map(r=>({name:r,from:s[r]||"",to:a[r]}))}}function Gt(e,t){const n=[];return t.forEach(a=>{e[a.id]&&n.push(Wt(a,e[a.id],{kind:"global",selector:null}))}),Object.entries(e.scopes||{}).forEach(([a,o])=>{const s=Je(a)?"class":"element";t.forEach(r=>{o[r.id]&&n.push(Wt(r,o[r.id],{kind:s,selector:a}))})}),n}function Sa(e){const t=o=>Object.values(o||{}).reduce((s,r)=>s+Object.keys(r||{}).length,0),{scopes:n,...a}=e;return t(a)+Object.values(n||{}).reduce((o,s)=>o+t(s),0)}const se=e=>`\`${e}\``,nt=e=>e.map(t=>` - ${se(t.name)}: ${t.from?`${se(t.from)} → `:""}${se(t.to)}`),at=e=>`${e.title} › ${e.settings.map(t=>`${t.label}: ${t.value}`).join(", ")}`;function $a(e){let t=null;try{t=document.querySelector(e)}catch{}if(!t)return"not found on the current page";const n=(t.getAttribute("aria-label")||t.placeholder||t.textContent||"").trim().replace(/\s+/g," ").slice(0,60);return`${se(tt(t))}${n?` with text “${n}”`:""}`}function Yt(e,t){const n=new Map;return e.forEach(a=>{const o=a[t];n.has(o)||n.set(o,[]),n.get(o).push(a)}),[...n]}function Ea(e,{link:t=location.href,warnings:n=[]}={}){if(!e.length)return"";const a=e.filter(i=>i.kind==="global"),o=e.filter(i=>i.kind==="class"),s=e.filter(i=>i.kind==="element"),r=[];if(r.push("# Apply design tweaks from Panel","","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.","",`Preview of the tweaked version: ${t}`),a.length&&(r.push("","## 1. Global token changes","","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.",""),a.forEach(i=>r.push(`- **${at(i)}**`,...nt(i.tokens)))),o.length&&(r.push("",`## ${a.length?2:1}. Component-wide changes`,"","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.",""),Yt(o,"selector").forEach(([i,l])=>{r.push(`- ${se(i)} (${document.querySelectorAll(i).length} on this page)`),l.forEach(d=>r.push(` - **${at(d)}**`,...nt(d.tokens).map(p=>` ${p}`)))})),s.length){const i=1+(a.length?1:0)+(o.length?1:0);r.push("",`## ${i}. Single-element changes`,"","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.",""),Yt(s,"selector").forEach(([l,d])=>{r.push(`- ${$a(l)}, found at ${se(l)}`),d.forEach(p=>r.push(` - **${at(p)}**`,...nt(p.tokens).map(u=>` ${u}`)))})}return n.length&&r.push("","## Contrast to check","","Panel flagged these colour pairs as below WCAG AA with the new values:","",...n.map(i=>`- ${i.text}`)),r.push("","## Constraints","","- Keep styling through the `--twd-*` tokens; don't hard-code the new values in component rules.","- Change only what is listed above.","- If a value uses `color-mix()` and the project targets older browsers, ask before converting it.","- When done, list the files you changed."),r.join(`
765
- `)}const Te=4.5,Ca=3,Ma=[["--twd-text","--twd-bg","Text on background"],["--twd-text","--twd-surface","Text on surface"],["--twd-text-muted","--twd-surface","Muted text on surface"],["--twd-on-primary","--twd-primary","Text on brand"]];let G;function ot(e){if(!e||(G||=Object.assign(document.createElement("canvas"),{width:1,height:1}).getContext("2d",{willReadFrequently:!0}),!G))return null;G.clearRect(0,0,1,1),G.fillStyle="#000",G.fillStyle=e,G.fillRect(0,0,1,1);const[t,n,a,o]=G.getImageData(0,0,1,1).data;return[t,n,a,o/255]}function Xt(e){const t=document.createElement("i");t.style.cssText=`position:absolute;visibility:hidden;color:var(${e})`,document.documentElement.appendChild(t);const n=getComputedStyle(t).color;return t.remove(),ot(n)}const Zt=([e,t,n])=>{const a=o=>(o/=255,o<=.03928?o/12.92:((o+.055)/1.055)**2.4);return .2126*a(e)+.7152*a(t)+.0722*a(n)},Jt=(e,t)=>e.slice(0,3).map((n,a)=>n*e[3]+t[a]*(1-e[3])).concat(1);function Qt(e,t){const n=Zt(e[3]<1?Jt(e,t):e),a=Zt(t);return(Math.max(n,a)+.05)/(Math.min(n,a)+.05)}const en=e=>`${e.toFixed(1)}:1`;function rt(){const e=[];return Ma.forEach(([t,n,a])=>{const o=Xt(t),s=Xt(n);if(!o||!s||s[3]===0)return;const r=Qt(o,s);r<Te&&e.push({label:a,ratio:r,needed:Te,text:`${a}: ${en(r)} · AA needs ${Te}`})}),e}function Ta(e){const t=[];for(let n=e;n&&n.nodeType===1;n=n.parentElement){const a=ot(getComputedStyle(n).backgroundColor);if(a&&a[3]>0&&(t.push(a),a[3]>=1))break}return t.reduceRight((n,a)=>Jt(a,n),[255,255,255,1])}function Aa(e){if(!e.textContent.trim()&&!e.placeholder)return null;const t=getComputedStyle(e),n=ot(t.color);if(!n)return null;const a=parseFloat(t.fontSize),s=a>=24||a>=18.66&&parseInt(t.fontWeight,10)>=700?Ca:Te,r=Qt(n,Ta(e));return r<s?{label:"This element",ratio:r,needed:s,text:`This element’s text: ${en(r)} · AA needs ${s}`}:null}const tn="twiddle-panel",La="0.8.2",nn="https://panel.twiddle.in",Pa="--twd-radius-control",Oa=/var\(\s*--twd-/;function Fa(e){return e.style.cssText.split(";").some(t=>{const n=t.slice(0,t.indexOf(":")).trim();return n&&!n.startsWith("--")&&Oa.test(t)})}function Na(){if(!getComputedStyle(document.documentElement).getPropertyValue(Pa).trim())return"no-tokens";let e=!1;for(const t of document.styleSheets){if(t.ownerNode?.id==="twiddle-scoped")continue;let n;try{n=t.cssRules}catch{e=!0;continue}for(const a of Me(n))if(Fa(a))return"ok"}return document.querySelector('[style*="var(--twd-"]')?"ok":e?"unknown":"unused"}function ja(){const e=new Set,t=n=>{for(const a of n.matchAll(/var\(\s*(--twd-[\w-]+)/g))e.add(a[1])};for(const n of document.styleSheets){if(n.ownerNode?.id==="twiddle-scoped")continue;let a;try{a=n.cssRules}catch{continue}for(const o of Me(a))o.style.cssText.split(";").forEach(s=>{const r=s.slice(0,s.indexOf(":")).trim();r&&!r.startsWith("--")&&t(s)})}return document.querySelectorAll('[style*="var(--twd-"]').forEach(n=>t(n.getAttribute("style"))),e}const an=[{label:"With a build tool, in your entry file",code:`import '${tn}/tokens.css';`},{label:"Plain HTML, in <head>",code:`<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/${tn}@${La}/dist/twiddle-tokens.css">`}],Ra=`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.
828
+ `,A=(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>`,P={dial:A(20,1.8,'<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),link:A(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"/>'),reset:A(15,2,'<path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/>'),close:A(15,2,'<path d="M18 6L6 18M6 6l12 12"/>'),chevron:A(12,2.4,'<path d="M9 6l6 6-6 6"/>'),pick:A(15,2,'<path d="M17.202 10.5576C17.6738 10.3035 17.9098 10.1765 17.9694 10.0236C18.0212 9.89097 18.0066 9.74158 17.9301 9.6215C17.8419 9.48312 17.5858 9.40424 17.0737 9.24647L7.05204 6.15943C6.63366 6.03055 6.42447 5.96611 6.28318 6.01796C6.16011 6.06312 6.06312 6.16011 6.01796 6.28317C5.96611 6.42446 6.03055 6.63365 6.15943 7.05204L9.24645 17.0737C9.40422 17.5858 9.4831 17.8419 9.62147 17.9301C9.74156 18.0066 9.89095 18.0212 10.0236 17.9694C10.1764 17.9098 10.3035 17.6738 10.5576 17.202L12.7816 13.0717C12.8193 13.0016 12.8382 12.9666 12.8625 12.9359C12.884 12.9086 12.9086 12.884 12.9359 12.8624C12.9666 12.8382 13.0016 12.8193 13.0717 12.7816L17.202 10.5576Z"/>'),compare:A(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"/>'),undo:A(15,2,'<path d="M9 14L4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 0 10h-3"/>'),redo:A(15,2,'<path d="M15 14l5-5-5-5"/><path d="M20 9H9a5 5 0 0 0 0 10h3"/>'),back:A(15,2,'<path d="M15 18l-6-6 6-6"/>'),down:A(12,2.4,'<path d="M6 9l6 6 6-6"/>'),minimise:A(15,2,'<path d="M6 9l6 6 6-6"/>'),changes:A(15,2,'<path d="M9 6h11M9 12h11M9 18h11"/><path d="M4.5 6h.01M4.5 12h.01M4.5 18h.01"/>'),copy:A(13,2,'<rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/>'),warn:A(13,2,'<path d="M12 3l9.5 17h-19z"/><path d="M12 10v4M12 17.5v.01"/>'),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>',tabOverview:A(18,1.8,'<circle cx="12" cy="12" r="8"/><path d="M12 12l4-4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2"/>'),tabColour:A(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"/>'),tabType:A(18,2,'<path d="M5 7V5h14v2"/><path d="M12 5v14"/><path d="M9 19h6"/>'),tabSpacing:A(18,2,'<path d="M4 5v14M20 5v14"/><path d="M8 12h8"/><path d="M10 9l-3 3 3 3M14 9l3 3-3 3"/>'),tabShape:A(18,2,'<path d="M20 4h-9a7 7 0 0 0-7 7v9"/><path d="M20 10h-5a5 5 0 0 0-5 5v5"/>'),tabShadows:A(18,2,'<rect x="4" y="4" width="12" height="12" rx="2"/><path d="M20 8v10a2 2 0 0 1-2 2H8"/>'),sliders:A(15,2,'<path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/>')},en="twiddle:";function Q(e){try{return localStorage.getItem(en+e)}catch{return null}}function ie(e,t){try{localStorage.setItem(en+e,t)}catch{}}const le=44,de=8,La=4,tn={corner:"br",x:16,y:16};function Aa(){try{const e=JSON.parse(Q("position"));if(e&&/^[tb][lr]$/.test(e.corner)&&isFinite(e.x)&&isFinite(e.y))return e}catch{}return{...tn}}function nn(e){const t=Math.max(de,innerWidth-le-de),n=Math.max(de,innerHeight-le-de);return{corner:e.corner,x:Math.round(Math.min(Math.max(e.x,de),t)),y:Math.round(Math.min(Math.max(e.y,de),n))}}function Pa({wrapEl:e,launcherEl:t}){let n=Aa();function a(){const d=nn(n),p=d.corner[1]==="l",f=d.corner[0]==="t";Object.assign(e.style,{left:p?`${d.x}px`:"auto",right:p?"auto":`${d.x}px`,top:f?`${d.y}px`:"auto",bottom:f?"auto":`${d.y}px`}),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",f)}function o(d,p=!0){n=nn(d),a(),p&&ie("position",JSON.stringify(n))}function r(d,p){const f=d+le/2<innerWidth/2,v=p+le/2<innerHeight/2,u=!v&&e.classList.contains("is-open")?10:0;return{corner:(v?"t":"b")+(f?"l":"r"),x:f?d:innerWidth-d-le,y:v?p:innerHeight-p-le-u}}let s=null,i=!1;t.addEventListener("pointerdown",d=>{if(d.button!==0)return;const p=t.getBoundingClientRect();s={id:d.pointerId,sx:d.clientX,sy:d.clientY,dx:d.clientX-p.left,dy:d.clientY-p.top,moving:!1}}),t.addEventListener("pointermove",d=>{if(!(!s||d.pointerId!==s.id)){if(!s.moving){if(Math.hypot(d.clientX-s.sx,d.clientY-s.sy)<La)return;s.moving=!0,t.setPointerCapture(d.pointerId),e.classList.add("dragging")}o(r(d.clientX-s.dx,d.clientY-s.dy),!1)}});const l=d=>{!s||d.pointerId!==s.id||(s.moving&&(i=!0,e.classList.remove("dragging"),o(n)),s=null)};return t.addEventListener("pointerup",l),t.addEventListener("pointercancel",l),t.addEventListener("keydown",d=>{const p={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[d.key];if(!p||d.altKey||d.metaKey||d.ctrlKey)return;d.preventDefault();const f=d.shiftKey?10:1,v=n.corner[1]==="l"?1:-1,u=n.corner[0]==="t"?1:-1;o({corner:n.corner,x:n.x+p[0]*f*v,y:n.y+p[1]*f*u})}),window.addEventListener("resize",a),a(),{consumeClick(){const d=i;return i=!1,d},reset(){o({...tn})}}}function ce({label:e,options:t,onSelect:n}){const a=document.createElement("div");a.className="seg",a.setAttribute("role","radiogroup"),a.setAttribute("aria-label",e);const o=t.map(l=>{const d=document.createElement("button");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});a.append(...o);let r=null;function s(l){r=l,o.forEach(p=>p.setAttribute("aria-checked",String(p.dataset.value===l)));const d=Math.max(0,o.findIndex(p=>p.dataset.value===l));o.forEach((p,f)=>{p.tabIndex=f===d?0:-1})}function i(l,d){l!==r&&(s(l),n(l)),d&&o.find(p=>p.dataset.value===l).focus()}return a.addEventListener("keydown",l=>{const d=o.indexOf(l.target);if(d<0)return;const p={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let f;if(p)f=(d+p+o.length)%o.length;else if(l.key==="Home")f=0;else if(l.key==="End")f=o.length-1;else return;l.preventDefault(),i(o[f].dataset.value,!0)}),s(null),{el:a,setValue:s}}const an=/var\(\s*(--twd-[\w-]+)/g,Oa=/::?[\w-]+(\([^)]*\))?/g;function*Ae(e){for(const t of e)t.selectorText!=null&&(yield t),t.cssRules&&(yield*Ae(t.cssRules))}function ja(){const e=[];for(const t of document.styleSheets){if(t.ownerNode?.id==="twiddle-scoped")continue;let n;try{n=t.cssRules}catch{continue}for(const a of Ae(n)){const o=[...a.style.cssText.matchAll(an)].map(r=>r[1]);o.length&&e.push({selectors:a.selectorText.split(","),vars:o})}}return e}function Fa(e,t){const n=t.replace(Oa,"").trim()||"*";try{return e.matches(n)}catch{return!1}}function on(e){const t=new Set,n=[];return ja().forEach(({selectors:a,vars:o})=>{const r=a.find(s=>Fa(e,s));r&&(o.forEach(s=>t.add(s)),n.push(r.trim()))}),[...(e.getAttribute("style")||"").matchAll(an)].forEach(a=>t.add(a[1])),{names:t,selectors:n}}const lt=e=>window.CSS&&CSS.escape?CSS.escape(e):e;function Na(e){const t=[];let n=e;for(;n&&n.nodeType===1&&n!==document.body&&n!==document.documentElement;){if(n.id&&document.querySelectorAll(`#${lt(n.id)}`).length===1)return t.unshift(`#${lt(n.id)}`),t.join(" > ");const a=n.localName,o=[...n.parentElement.children].filter(r=>r.localName===a);t.unshift(o.length>1?`${a}:nth-of-type(${o.indexOf(n)+1})`:a),n=n.parentElement}return["body",...t].join(" > ")}function Ra(e,t=on(e).selectors){const n=e.getAttribute("data-twd");if(n)return`[data-twd="${n.replace(/"/g,"")}"]`;const a=[...e.classList],r=a.find(s=>t.some(i=>new RegExp(`\\.${s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(?![\\w-])`).test(i)))||a[0];return r?`.${lt(r)}`:null}function za(e){const t=on(e),n=Ra(e,t.selectors),a=(e.getAttribute("aria-label")||e.placeholder||e.textContent||"").trim().replace(/\s+/g," ");return{el:e,tag:e.localName,classes:[...e.classList],text:a.length>40?`${a.slice(0,40)}…`:a,tokens:t.names,elementSelector:Na(e),classSelector:n,classCount:n?document.querySelectorAll(n).length:0}}const dt=e=>e.localName+[...e.classList].map(t=>`.${t}`).join(""),Ia={radius:"px",intensity:"%",base:"px"},rn=e=>e.charAt(0).toUpperCase()+e.slice(1),Da=(e,t)=>typeof t=="number"||/^\d+$/.test(t)?`${t}${Ia[e]||""}`:rn(String(t));function sn(e,t,n){const a=Qt(()=>e.tokens({[e.id]:t})||{}),o=Object.keys(a);let r={};if(o.length){const s=n.selector?document.querySelector(n.selector):void 0;r=Ea(o,s||void 0)}return{...n,sectionId:e.id,title:e.title,settings:Object.entries(t).map(([s,i])=>({key:s,label:rn(s),value:Da(s,i),...e.describe?.(s,i)||{}})),tokens:o.map(s=>({name:s,from:r[s]||"",to:a[s]}))}}function ln(e,t){const n=[];return t.forEach(a=>{e[a.id]&&n.push(sn(a,e[a.id],{kind:"global",selector:null}))}),Object.entries(e.scopes||{}).forEach(([a,o])=>{const r=st(a)?"class":"element";t.forEach(s=>{o[s.id]&&n.push(sn(s,o[s.id],{kind:r,selector:a}))})}),n}function Ba(e){const t=o=>Object.values(o||{}).reduce((r,s)=>r+Object.keys(s||{}).length,0),{scopes:n,...a}=e;return t(a)+Object.values(n||{}).reduce((o,r)=>o+t(r),0)}const pe=e=>`\`${e}\``,ct=e=>e.map(t=>` - ${pe(t.name)}: ${t.from?`${pe(t.from)} → `:""}${pe(t.to)}`),pt=e=>`${e.title} › ${e.settings.map(t=>`${t.label}: ${t.value}`).join(", ")}`;function Ua(e){let t=null;try{t=document.querySelector(e)}catch{}if(!t)return"not found on the current page";const n=(t.getAttribute("aria-label")||t.placeholder||t.textContent||"").trim().replace(/\s+/g," ").slice(0,60);return`${pe(dt(t))}${n?` with text “${n}”`:""}`}function dn(e,t){const n=new Map;return e.forEach(a=>{const o=a[t];n.has(o)||n.set(o,[]),n.get(o).push(a)}),[...n]}function Va(e,{link:t=location.href,warnings:n=[]}={}){if(!e.length)return"";const a=e.filter(i=>i.kind==="global"),o=e.filter(i=>i.kind==="class"),r=e.filter(i=>i.kind==="element"),s=[];if(s.push("# Apply design tweaks from Panel","","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.","",`Preview of the tweaked version: ${t}`),a.length&&(s.push("","## 1. Global token changes","","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.",""),a.forEach(i=>s.push(`- **${pt(i)}**`,...ct(i.tokens)))),o.length&&(s.push("",`## ${a.length?2:1}. Component-wide changes`,"","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.",""),dn(o,"selector").forEach(([i,l])=>{s.push(`- ${pe(i)} (${document.querySelectorAll(i).length} on this page)`),l.forEach(d=>s.push(` - **${pt(d)}**`,...ct(d.tokens).map(p=>` ${p}`)))})),r.length){const i=1+(a.length?1:0)+(o.length?1:0);s.push("",`## ${i}. Single-element changes`,"","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.",""),dn(r,"selector").forEach(([l,d])=>{s.push(`- ${Ua(l)}, found at ${pe(l)}`),d.forEach(p=>s.push(` - **${pt(p)}**`,...ct(p.tokens).map(f=>` ${f}`)))})}return n.length&&s.push("","## Contrast to check","","Panel flagged these colour pairs as below WCAG AA with the new values:","",...n.map(i=>`- ${i.text}`)),s.push("","## Constraints","","- Keep styling through the `--twd-*` tokens; don't hard-code the new values in component rules.","- Change only what is listed above.","- If a value uses `color-mix()` and the project targets older browsers, ask before converting it.","- When done, list the files you changed."),s.join(`
829
+ `)}const Pe=4.5,qa=3,Ha=[["--twd-text","--twd-bg","Text on background"],["--twd-text","--twd-surface","Text on surface"],["--twd-text-muted","--twd-surface","Muted text on surface"],["--twd-on-primary","--twd-primary","Text on brand"]];let ee;function ut(e){if(!e||(ee||=Object.assign(document.createElement("canvas"),{width:1,height:1}).getContext("2d",{willReadFrequently:!0}),!ee))return null;ee.clearRect(0,0,1,1),ee.fillStyle="#000",ee.fillStyle=e,ee.fillRect(0,0,1,1);const[t,n,a,o]=ee.getImageData(0,0,1,1).data;return[t,n,a,o/255]}function cn(e){const t=document.createElement("i");t.style.cssText=`position:absolute;visibility:hidden;color:var(${e})`,document.documentElement.appendChild(t);const n=getComputedStyle(t).color;return t.remove(),ut(n)}const pn=([e,t,n])=>{const a=o=>(o/=255,o<=.03928?o/12.92:((o+.055)/1.055)**2.4);return .2126*a(e)+.7152*a(t)+.0722*a(n)},un=(e,t)=>e.slice(0,3).map((n,a)=>n*e[3]+t[a]*(1-e[3])).concat(1);function hn(e,t){const n=pn(e[3]<1?un(e,t):e),a=pn(t);return(Math.max(n,a)+.05)/(Math.min(n,a)+.05)}const fn=e=>`${e.toFixed(1)}:1`;function ht(){const e=[];return Ha.forEach(([t,n,a])=>{const o=cn(t),r=cn(n);if(!o||!r||r[3]===0)return;const s=hn(o,r);s<Pe&&e.push({label:a,ratio:s,needed:Pe,text:`${a}: ${fn(s)} · AA needs ${Pe}`})}),e}function _a(e){const t=[];for(let n=e;n&&n.nodeType===1;n=n.parentElement){const a=ut(getComputedStyle(n).backgroundColor);if(a&&a[3]>0&&(t.push(a),a[3]>=1))break}return t.reduceRight((n,a)=>un(a,n),[255,255,255,1])}function Ka(e){if(!e.textContent.trim()&&!e.placeholder)return null;const t=getComputedStyle(e),n=ut(t.color);if(!n)return null;const a=parseFloat(t.fontSize),r=a>=24||a>=18.66&&parseInt(t.fontWeight,10)>=700?qa:Pe,s=hn(n,_a(e));return s<r?{label:"This element",ratio:s,needed:r,text:`This element’s text: ${fn(s)} · AA needs ${r}`}:null}const gn="twiddle-panel",Wa="0.9.1",mn="https://panel.twiddle.in",Ga="--twd-radius-control",Ya=/var\(\s*--twd-/;function Xa(e){return e.style.cssText.split(";").some(t=>{const n=t.slice(0,t.indexOf(":")).trim();return n&&!n.startsWith("--")&&Ya.test(t)})}function Za(){if(!getComputedStyle(document.documentElement).getPropertyValue(Ga).trim())return"no-tokens";let e=!1;for(const t of document.styleSheets){if(t.ownerNode?.id==="twiddle-scoped")continue;let n;try{n=t.cssRules}catch{e=!0;continue}for(const a of Ae(n))if(Xa(a))return"ok"}return document.querySelector('[style*="var(--twd-"]')?"ok":e?"unknown":"unused"}function Ja(){const e=new Set,t=n=>{for(const a of n.matchAll(/var\(\s*(--twd-[\w-]+)/g))e.add(a[1])};for(const n of document.styleSheets){if(n.ownerNode?.id==="twiddle-scoped")continue;let a;try{a=n.cssRules}catch{continue}for(const o of Ae(a))o.style.cssText.split(";").forEach(r=>{const s=r.slice(0,r.indexOf(":")).trim();s&&!s.startsWith("--")&&t(r)})}return document.querySelectorAll('[style*="var(--twd-"]').forEach(n=>t(n.getAttribute("style"))),e}const bn=[{label:"With a build tool, in your entry file",code:`import '${gn}/tokens.css';`},{label:"Plain HTML, in <head>",code:`<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/${gn}@${Wa}/dist/twiddle-tokens.css">`}],Qa=`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.
766
830
 
767
831
  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.
768
832
  2. Replace fixed values in component styles with var(--twd-…). Map each value to the closest token by role:
@@ -779,82 +843,79 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
779
843
  - Shadows: --twd-shadow-sm, --twd-shadow-md, --twd-shadow-lg
780
844
  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.
781
845
  4. Don't change the layout or how the page looks; after the change it should look the same until someone uses the panel.
782
- 5. When done, list the files you changed and any values you left fixed, with the reason.`;function D(e){const t=document.createElement("div");t.className="field";const n=document.createElement("div");n.className="field-head";const a=document.createElement("span");a.className="field-label",a.textContent=e;const o=document.createElement("span");return o.className="field-value",o.hidden=!0,n.append(a,o),t.append(n),{el:t,setValue(s){o.textContent=s||"",o.hidden=!s},append(...s){t.append(...s)}}}function za({label:e,ends:t,cols:n=9,rows:a=5,onInput:o}){const s=document.createElement("div");s.className="pad",s.tabIndex=0,s.setAttribute("role","group"),s.setAttribute("aria-roledescription","2D slider");const r=(b,h)=>{const y=document.createElement("span");return y.className=`pad-edge ${b}`,y.textContent=h,y.setAttribute("aria-hidden","true"),y};s.append(r("top",t.top),r("bottom",t.bottom),r("left",t.left),r("right",t.right));const i=document.createElement("div");i.className="pad-area";for(let b=0;b<a;b++)for(let h=0;h<n;h++){const y=document.createElement("i");y.className="pad-dot",y.style.left=`${h/(n-1)*100}%`,y.style.top=`${b/(a-1)*100}%`,i.append(y)}const l=document.createElement("span");l.className="pad-knob",i.append(l),s.append(i);let d=.5,p=.5;const u=(b,h)=>Math.round(Math.min(1,Math.max(0,b))*(h-1))/(h-1);function v(){l.style.left=`${d*100}%`,l.style.top=`${p*100}%`}function f(b,h,y){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))}const m=b=>{const h=i.getBoundingClientRect();f((b.clientX-h.left)/h.width,(b.clientY-h.top)/h.height)};s.addEventListener("pointerdown",b=>{s.setPointerCapture(b.pointerId),s.classList.add("dragging"),m(b)}),s.addEventListener("pointermove",b=>{s.hasPointerCapture(b.pointerId)&&m(b)});const x=b=>{s.hasPointerCapture(b.pointerId)&&s.releasePointerCapture(b.pointerId),s.classList.remove("dragging")};return s.addEventListener("pointerup",x),s.addEventListener("pointercancel",x),s.addEventListener("keydown",b=>{const h={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[b.key];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"))}),{el:s,setValue(b,h,y){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)}}}function on({label:e,min:t,max:n,step:a=1,format:o=String,onInput:s}){const r=document.createElement("div");r.className="slider";const i=document.createElement("input");i.type="range",i.min=String(t),i.max=String(n),i.step=String(a),i.setAttribute("aria-label",e);const l=document.createElement("span");l.className="slider-value",l.setAttribute("aria-hidden","true"),r.append(i,l);const d=p=>{const u=(Number(i.value)-t)/(n-t)*100;i.style.setProperty("--fill",`${u}%`),l.textContent=p??o(Number(i.value)),i.setAttribute("aria-valuetext",l.textContent)};return i.addEventListener("input",()=>{d(),s(Number(i.value))}),{el:r,setValue(p,u){i.value=String(p),d(u)}}}function Ia({label:e,options:t,columns:n=3,className:a="",onSelect:o}){const s=document.createElement("div");s.className=`tiles ${a}`.trim(),s.style.setProperty("--cols",n),s.setAttribute("role","radiogroup"),s.setAttribute("aria-label",e);const r=t.map(p=>{const u=document.createElement("button");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});s.append(...r);let i=null;function l(p){i=p,r.forEach(v=>v.setAttribute("aria-checked",String(v.dataset.value===p)));const u=Math.max(0,r.findIndex(v=>v.dataset.value===p));r.forEach((v,f)=>{v.tabIndex=f===u?0:-1})}function d(p,u){p!==i&&(l(p),o(p)),u&&r.find(v=>v.dataset.value===p).focus()}return s.addEventListener("keydown",p=>{const u=r.indexOf(p.target.closest(".tile"));if(u<0)return;const v={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[p.key];let f;if(v)f=(u+v+r.length)%r.length;else if(p.key==="Home")f=0;else if(p.key==="End")f=r.length-1;else return;p.preventDefault(),d(r[f].dataset.value,!0)}),l(null),{el:s,setValue:l}}const F=e=>getComputedStyle(document.documentElement).getPropertyValue(e).trim();function he(e,t){const n=/^(-?\d*\.?\d+)([a-z%]*)$/i.exec(String(e).trim());if(!n)return null;const a=parseFloat(n[1])*t,o=n[2]||"px";return o==="px"?`${Math.round(a)}px`:`${+a.toFixed(3)}${o}`}const Da=999;function rn({id:e,title:t,hint:n,token:a,uses:o=[],presets:s,max:r,extra:i=[],extraTokens:l=()=>({}),shape:d="card"}){const p=f=>s.find(m=>m.value===f),u=f=>f>=Da?"full":`${f}px`,v=f=>{if(typeof f.radius=="number"&&isFinite(f.radius))return{[a]:`${Math.min(Math.max(f.radius,0),r)}px`};const m=p(f.corners);return m?{[a]:`${m.radius}px`}:{}};return{id:e,title:t,hint:n,presets:s,uses:[a,...o],tokens(f){const m=f[e]||{};return{...v(m),...l(m)}},parts:{corners(f,m,{label:x="Corners"}={}){const b=D(x),h=re({label:`${t} corners`,options:s.map(E=>({value:E.value,label:E.label,title:u(E.radius)})),onSelect:E=>m.setSection(e,{corners:E,radius:null})}),y=on({label:`${t} corner radius`,min:0,max:r,format:u,onInput:E=>m.setSection(e,{radius:E,corners:null})});b.append(h.el,y.el),f.append(b.el);const P=()=>{const E=parseFloat((m.readToken||F)(a)),de=m.getState()[e]||{},Z=p(de.corners)||s.find(J=>J.radius===E);if(h.setValue(Z?Z.value:null),isNaN(E)){y.setValue(0,"—"),b.setValue("");return}y.setValue(Math.min(E,r),u(E)),b.setValue(u(E))};P(),m.onChange(P)},...Object.fromEntries(i.map(f=>[f.key,(m,x,{label:b}={})=>m.append(fe(x,{section:e,...f,label:b||f.label}))])),cornerTiles(f,m,{label:x="Corners"}={}){const b=h=>`<span class="shape shape-${d}" style="border-radius:${Math.min(h,d==="button"?12:16)}px"></span>`;f.append(H(m,{section:e,key:"corners",label:x,columns:s.length,options:s.map(h=>({value:h.value,label:h.label,title:u(h.radius),preview:b(h.radius)})),current:h=>{const y=h[e]||{};if(y.radius!=null)return null;const P=parseFloat((m.readToken||F)(a));return(p(y.corners)||s.find(E=>E.radius===P))?.value||null},select:h=>m.setSection(e,{corners:h,radius:null}),valueText:()=>{const h=parseFloat((m.readToken||F)(a));return isNaN(h)?"":u(h)}}))},...Object.fromEntries(i.filter(f=>f.preview).map(f=>[`${f.key}Tiles`,(m,x,{label:b}={})=>m.append(H(x,{section:e,key:f.key,label:b||f.label,fallback:f.fallback,columns:f.columns||f.options.length,options:f.options.map(h=>({...h,preview:f.preview(h.value)}))}))]))},render(f,m){Object.entries(this.parts).filter(([x])=>!x.endsWith("Tiles")).forEach(([,x])=>x(f,m))}}}function fe(e,{section:t,key:n,label:a,options:o,fallback:s,valueText:r}){const i=D(a),l=re({label:a,options:o,onSelect:p=>e.setSection(t,{[n]:p})});i.append(l.el);const d=()=>{const p=(e.getState()[t]||{})[n]||s;l.setValue(p),i.setValue(r?r(p):"")};return d(),e.onChange(d),i.el}function Ba(e,{section:t,key:n,label:a,min:o,max:s,fallback:r,format:i}){const l=D(a),d=on({label:a,min:o,max:s,format:i,onInput:u=>e.setSection(t,{[n]:u})});l.append(d.el);const p=()=>{const u=(e.getState()[t]||{})[n];d.setValue(typeof u=="number"?u:r)};return p(),e.onChange(p),l.el}function H(e,{section:t,key:n,label:a,options:o,columns:s=3,className:r="",fallback:i,valueText:l,current:d,select:p}){const u=D(a),v=Ia({label:a,options:o,columns:s,className:r,onSelect:m=>p?p(m):e.setSection(t,{[n]:m})});u.append(v.el);const f=()=>{const m=e.getState(),x=d?d(m):(m[t]||{})[n]||i||null;v.setValue(x),u.setValue(l?l(x,m):"")};return f(),e.onChange(f),u.el}const sn=(e,t)=>t.map(n=>`${e}${n}`),ln={fonts:{label:"Tokens",tokens:["font-heading","font-body"],kind:"text"},type:{label:"Tokens",tokens:sn("text-",["xs","sm","base","lg","xl","2xl","3xl"]),kind:"length"},leading:{label:"Line height",tokens:["leading-tight","leading-normal"],kind:"number"},weights:{label:"Weights",tokens:["weight-heading","weight-strong"],kind:"number"},colours:{label:"Tokens",tokens:["bg","surface","surface-raised","text","text-muted","border","primary","primary-hover","on-primary","focus","success","warning","danger"],kind:"colour"},spacing:{label:"Steps",tokens:sn("space-",[1,2,3,4,5,6,7,8]),kind:"length",bar:64},controls:{label:"Controls",tokens:["control-height","control-pad-x"],kind:"length"},corners:{label:"Tokens",tokens:["radius-control","radius-container"],kind:"length"},borders:{label:"Tokens",tokens:["border-width","border-width-container"],kind:"length"},shadows:{label:"Tokens",tokens:["shadow-sm","shadow-md","shadow-lg"],kind:"text"},buttonStyle:{label:"Button",tokens:["button-bg","button-fg","button-border","button-hover"],kind:"colour"},cardStyle:{label:"Card",tokens:["card-bg","card-border"],kind:"colour"},cardShadow:{label:"Card shadow",tokens:["card-shadow"],kind:"text"}},_=e=>`--twd-${e}`,st=(e,t)=>Object.prototype.hasOwnProperty.call(e.getState().custom||{},t),dn=(e,t)=>ln[t].tokens.some(n=>(e.custom||{})[n]!=null);function Ua(e,t){const n=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());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":"")}}function qa(e,t){const n=e.trim();return n?t==="length"&&/^-?\d*\.?\d+$/.test(n)?`${n}px`:n:null}function Ha(e,t,n,a){const o=document.createElement("div");o.className=`token-row kind-${n}`,o.innerHTML=`
783
- <code class="token-name" title="${_(t)}">${t}</code>
846
+ 5. When done, list the files you changed and any values you left fixed, with the reason.`;function I(e){const t=document.createElement("div");t.className="field";const n=document.createElement("div");n.className="field-head";const a=document.createElement("span");a.className="field-label",a.textContent=e;const o=document.createElement("span");return o.className="field-value",o.hidden=!0,n.append(a,o),t.append(n),{el:t,setValue(r){o.textContent=r||"",o.hidden=!r},append(...r){t.append(...r)}}}function eo({label:e,ends:t,cols:n=9,rows:a=5,onInput:o}){const r=document.createElement("div");r.className="pad",r.tabIndex=0,r.setAttribute("role","group"),r.setAttribute("aria-roledescription","2D slider");const s=(b,h)=>{const w=document.createElement("span");return w.className=`pad-edge ${b}`,w.textContent=h,w.setAttribute("aria-hidden","true"),w};r.append(s("top",t.top),s("bottom",t.bottom),s("left",t.left),s("right",t.right));const i=document.createElement("div");i.className="pad-area";for(let b=0;b<a;b++)for(let h=0;h<n;h++){const w=document.createElement("i");w.className="pad-dot",w.style.left=`${h/(n-1)*100}%`,w.style.top=`${b/(a-1)*100}%`,i.append(w)}const l=document.createElement("span");l.className="pad-knob",i.append(l),r.append(i);let d=.5,p=.5;const f=(b,h)=>Math.round(Math.min(1,Math.max(0,b))*(h-1))/(h-1);function v(){l.style.left=`${d*100}%`,l.style.top=`${p*100}%`}function u(b,h,w){b=w==="x"?d:f(b,n),h=w==="y"?p:f(h,a),!(b===d&&h===p)&&(d=b,p=h,v(),o(d,p))}const m=b=>{const h=i.getBoundingClientRect();u((b.clientX-h.left)/h.width,(b.clientY-h.top)/h.height)};r.addEventListener("pointerdown",b=>{r.setPointerCapture(b.pointerId),r.classList.add("dragging"),m(b)}),r.addEventListener("pointermove",b=>{r.hasPointerCapture(b.pointerId)&&m(b)});const x=b=>{r.hasPointerCapture(b.pointerId)&&r.releasePointerCapture(b.pointerId),r.classList.remove("dragging")};return r.addEventListener("pointerup",x),r.addEventListener("pointercancel",x),r.addEventListener("keydown",b=>{const h={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[b.key];h&&(b.preventDefault(),h[0]?u(f(d,n)+h[0]/(n-1),p,"y"):u(d,f(p,a)+h[1]/(a-1),"x"))}),{el:r,setValue(b,h,w){d=Math.min(1,Math.max(0,b)),p=Math.min(1,Math.max(0,h)),v(),r.setAttribute("aria-label",w?`${e}: ${w}`:e)}}}function xn({label:e,min:t,max:n,step:a=1,format:o=String,onInput:r}){const s=document.createElement("div");s.className="slider";const i=document.createElement("input");i.type="range",i.min=String(t),i.max=String(n),i.step=String(a),i.setAttribute("aria-label",e);const l=document.createElement("span");l.className="slider-value",l.setAttribute("aria-hidden","true"),s.append(i,l);const d=p=>{const f=(Number(i.value)-t)/(n-t)*100;i.style.setProperty("--fill",`${f}%`),l.textContent=p??o(Number(i.value)),i.setAttribute("aria-valuetext",l.textContent)};return i.addEventListener("input",()=>{d(),r(Number(i.value))}),{el:s,setValue(p,f){i.value=String(p),d(f)}}}function to({label:e,options:t,columns:n=3,className:a="",onSelect:o}){const r=document.createElement("div");r.className=`tiles ${a}`.trim(),r.style.setProperty("--cols",n),r.setAttribute("role","radiogroup"),r.setAttribute("aria-label",e);const s=t.map(p=>{const f=document.createElement("button");return f.type="button",f.className="tile",p.wide&&f.classList.add("wide"),f.setAttribute("role","radio"),f.dataset.value=p.value,p.title&&(f.title=p.title),f.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>`,f.querySelector(".tile-label").textContent=p.label,p.sub&&(f.querySelector(".tile-sub").textContent=p.sub),f.addEventListener("click",()=>l(p.value)),f});r.append(...s);function i(p){s.forEach(v=>v.setAttribute("aria-checked",String(v.dataset.value===p)));const f=Math.max(0,s.findIndex(v=>v.dataset.value===p));s.forEach((v,u)=>{v.tabIndex=u===f?0:-1})}function l(p,f){i(p),o(p),f&&s.find(v=>v.dataset.value===p).focus()}function d(p=[]){s.forEach(f=>f.classList.toggle("near",p.includes(f.dataset.value)))}return r.addEventListener("keydown",p=>{const f=s.indexOf(p.target.closest(".tile"));if(f<0)return;const v={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[p.key];let u;if(v)u=(f+v+s.length)%s.length;else if(p.key==="Home")u=0;else if(p.key==="End")u=s.length-1;else return;p.preventDefault(),l(s[u].dataset.value,!0)}),i(null),{el:r,setValue:i,setNear:d}}const L=e=>getComputedStyle(document.documentElement).getPropertyValue(e).trim();function xe(e,t){const n=/^(-?\d*\.?\d+)([a-z%]*)$/i.exec(String(e).trim());if(!n)return null;const a=parseFloat(n[1])*t,o=n[2]||"px";return o==="px"?`${Math.round(a)}px`:`${+a.toFixed(3)}${o}`}const no=999;function wn({id:e,title:t,hint:n,token:a,uses:o=[],presets:r,max:s,extra:i=[],extraTokens:l=()=>({}),shape:d="card"}){const p=u=>r.find(m=>m.value===u),f=u=>u>=no?"full":`${u}px`,v=u=>{if(typeof u.radius=="number"&&isFinite(u.radius))return{[a]:`${Math.min(Math.max(u.radius,0),s)}px`};const m=p(u.corners);return m?{[a]:`${m.radius}px`}:{}};return{id:e,title:t,hint:n,presets:r,uses:[a,...o],tokens(u){const m=u[e]||{};return{...v(m),...l(m)}},parts:{corners(u,m,{label:x="Corners"}={}){const b=I(x),h=ce({label:`${t} corners`,options:r.map($=>({value:$.value,label:$.label,title:f($.radius)})),onSelect:$=>m.setSection(e,{corners:$,radius:null})}),w=xn({label:`${t} corner radius`,min:0,max:s,format:f,onInput:$=>m.setSection(e,{radius:$,corners:null})});b.append(h.el,w.el),u.append(b.el);const S=()=>{const $=parseFloat((m.readToken||L)(a)),Y=m.getState()[e]||{},oe=p(Y.corners)||r.find(Ue=>Ue.radius===$);if(h.setValue(oe?oe.value:null),isNaN($)){w.setValue(0,"—"),b.setValue("");return}w.setValue(Math.min($,s),f($)),b.setValue(f($))};S(),m.onChange(S)},...Object.fromEntries(i.map(u=>[u.key,(m,x,{label:b}={})=>m.append(we(x,{section:e,...u,label:b||u.label}))])),cornerTiles(u,m,{label:x="Corners"}={}){const b=h=>`<span class="shape shape-${d}" style="border-radius:${Math.min(h,d==="button"?12:16)}px"></span>`;u.append(V(m,{section:e,key:"corners",label:x,columns:r.length,options:r.map(h=>({value:h.value,label:h.label,title:f(h.radius),preview:b(h.radius)})),current:h=>{const w=h[e]||{};if(w.radius!=null)return null;if(p(w.corners))return w.corners;if(ue(h,a))return null;const S=parseFloat((m.readToken||L)(a));return r.find($=>$.radius===S)?.value||null},select:h=>m.setSection(e,{corners:h,radius:null}),valueText:(h,w)=>{const S=parseFloat((m.readToken||L)(a));if(isNaN(S))return"";const $=w[e]||{};return f(S)+yn(w,a,$.radius!=null?"custom":p($.corners)?.label)}}))},...Object.fromEntries(i.filter(u=>u.preview).map(u=>[`${u.key}Tiles`,(m,x,{label:b}={})=>m.append(V(x,{section:e,key:u.key,label:b||u.label,fallback:u.fallback,columns:u.columns||u.options.length,options:u.options.map(h=>({...h,preview:u.preview(h.value)})),...u.token&&{current:h=>(h[e]||{})[u.key]||(ue(h,u.token)?null:u.fallback||null),valueText:(h,w)=>{if(!ue(w,u.token))return"";const S=u.options.find($=>$.value===(w[e]||{})[u.key]);return`${(x.readToken||L)(u.token)}${yn(w,u.token,S&&S.label)}`}},...u.current&&{current:h=>u.current(h[e]||{})},...u.valueText&&{valueText:(h,w)=>u.valueText(w[e]||{},x.readToken||L)},...u.select&&{select:h=>x.setSection(e,u.select(h))}}))]))},render(u,m){Object.entries(this.parts).filter(([x])=>!x.endsWith("Tiles")).forEach(([,x])=>x(u,m))}}}function we(e,{section:t,key:n,label:a,options:o,fallback:r,valueText:s}){const i=I(a),l=ce({label:a,options:o,onSelect:p=>e.setSection(t,{[n]:p})});i.append(l.el);const d=()=>{const p=(e.getState()[t]||{})[n]||r;l.setValue(p),i.setValue(s?s(p):"")};return d(),e.onChange(d),i.el}function ao(e,{section:t,key:n,label:a,min:o,max:r,fallback:s,format:i,note:l,value:d}){const p=I(a),f=xn({label:a,min:o,max:r,format:i,onInput:u=>e.setSection(t,{[n]:u})});p.append(f.el);const v=()=>{const u=e.getState(),m=d?d(u):(u[t]||{})[n];f.setValue(typeof m=="number"?m:s),l&&(p.el.querySelector(".field-label").textContent=`${a}${l(u)?` · ${l(u)}`:""}`)};return v(),e.onChange(v),p.el}let vn=()=>({});const oo=e=>{vn=e},ue=(e,t)=>Object.prototype.hasOwnProperty.call(vn(e),t),yn=(e,t,n)=>ue(e,t)?n?` · ${n}, adjusted by Character`:" · from Character":"";function V(e,{section:t,key:n,label:a,options:o,columns:r=3,className:s="",fallback:i,valueText:l,current:d,select:p,near:f}){const v=I(a),u=to({label:a,options:o,columns:r,className:s,onSelect:x=>p?p(x):e.setSection(t,{[n]:x})});v.append(u.el);const m=()=>{const x=e.getState(),b=d?d(x):(x[t]||{})[n]||i||null;u.setValue(b),u.setNear(f?f(x):[]),v.setValue(l?l(b,x):"")};return m(),e.onChange(m),v.el}const kn=(e,t)=>t.map(n=>`${e}${n}`),Sn={fonts:{label:"Tokens",tokens:["font-heading","font-body"],kind:"text"},type:{label:"Tokens",tokens:kn("text-",["xs","sm","base","lg","xl","2xl","3xl"]),kind:"length"},leading:{label:"Line height",tokens:["leading-tight","leading-normal"],kind:"number"},weights:{label:"Weights",tokens:["weight-heading","weight-strong"],kind:"number"},colours:{label:"Tokens",tokens:["bg","surface","surface-raised","text","text-muted","border","primary","primary-hover","on-primary","focus","success","warning","danger"],kind:"colour"},spacing:{label:"Steps",tokens:kn("space-",[1,2,3,4,5,6,7,8]),kind:"length",bar:64},controls:{label:"Controls",tokens:["control-height","control-pad-x"],kind:"length"},corners:{label:"Tokens",tokens:["radius-control","radius-container"],kind:"length"},borders:{label:"Tokens",tokens:["border-width","border-width-container"],kind:"length"},shadows:{label:"Tokens",tokens:["shadow-sm","shadow-md","shadow-lg"],kind:"text"},buttonStyle:{label:"Button",tokens:["button-bg","button-fg","button-border","button-hover"],kind:"colour"},cardStyle:{label:"Card",tokens:["card-bg","card-border"],kind:"colour"},cardShadow:{label:"Card shadow",tokens:["card-shadow"],kind:"text"}},K=e=>`--twd-${e}`,ft=(e,t)=>Object.prototype.hasOwnProperty.call(e.getState().custom||{},t),ve=(e,t)=>Sn[t].tokens.some(n=>(e.custom||{})[n]!=null);function ro(e,t){const n=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());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":"")}}function so(e,t){const n=e.trim();return n?t==="length"&&/^-?\d*\.?\d+$/.test(n)?`${n}px`:n:null}function io(e,t,n,a){const o=document.createElement("div");o.className=`token-row kind-${n}`,o.innerHTML=`
847
+ <code class="token-name" title="${K(t)}">${t}</code>
784
848
  ${a?'<span class="token-bar"><span></span></span>':'<span class="token-gap"></span>'}
785
849
  <span class="custom-tag" hidden>Custom</span>
786
850
  <label class="token-value">
787
851
  ${n==="colour"?'<span class="token-swatch"></span>':""}
788
- <input type="text" spellcheck="false" aria-label="${_(t)}" ${n==="length"||n==="number"?'inputmode="decimal"':""}>
852
+ <input type="text" spellcheck="false" aria-label="${K(t)}" ${n==="length"||n==="number"?'inputmode="decimal"':""}>
789
853
  <span class="token-unit"></span>
790
854
  </label>
791
- <button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${_(t)}" hidden>${A.reset}</button>
792
- `;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");let u="";const v=()=>{let m=s.value;u&&/^-?\d*\.?\d+$/.test(m.trim())&&(m=`${m.trim()}${u}`);const x=qa(m,n),b=F(_(t));if(x===null){st(e,t)?e.setSection("custom",{[t]:null}):f();return}if(x===b&&!st(e,t))return f();e.setSection("custom",{[t]:x})};s.addEventListener("change",v),s.addEventListener("blur",()=>f()),s.addEventListener("keydown",m=>{m.key==="Enter"&&(m.preventDefault(),s.blur()),m.key==="Escape"&&(m.stopPropagation(),f(),s.blur())}),p.addEventListener("click",()=>e.setSection("custom",{[t]:null}));function f(){const m=F(_(t)),x=st(e,t),b=Ua(m,n);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}return f(),e.onChange(f),o}const Va={id:"custom",title:"Custom tokens",hint:"Any token, set to a fixed value",uses:[],tokens(e){return Object.fromEntries(Object.entries(e.custom||{}).map(([t,n])=>[_(t),n]))},describe:(e,t)=>({label:_(e),value:String(t)}),parts:Object.fromEntries(Object.entries(ln).map(([e,t])=>[e,(n,a,{label:o=t.label}={})=>{const s=D(o);s.el.classList.add("token-field");const r=t.tokens[0],i=t.tokens[t.tokens.length-1];s.setValue(t.tokens.length>2&&/-\w+$/.test(r)?`${_(r)} … ${i.split("-").pop()}`:"");const l=document.createElement("div");l.className="token-rows",t.tokens.forEach(d=>l.append(Ha(a,d,t.kind,t.bar))),s.append(l),n.append(s.el)}]))},ge={compact:.75,regular:1,comfy:1.25},it=[.75,1.25],cn=[1,2,3,4,5,6,7,8].map(e=>`--twd-space-${e}`);function ie(e={}){return typeof e.factor=="number"&&isFinite(e.factor)?Math.min(it[1],Math.max(it[0],e.factor)):ge[e.spacing]||1}const lt=e=>`${Math.round(e*100)}%`,_a={id:"density",title:"Density",hint:"Compact · regular · comfortable",uses:cn,tokens(e){const t=ie(e.density);if(t===1)return{};const n={};return cn.forEach(a=>{const o=he(F(a),t);o&&(n[a]=o)}),n},describe:(e,t)=>e==="factor"?{label:"Spacing",value:lt(t)}:null,parts:{spacingTiles(e,t,{label:n="Density"}={}){const a=(o,s)=>`<span class="sketch" style="padding:${s}px;gap:${o}px"><i></i><i></i><i></i></span>`;e.append(H(t,{section:"density",key:"spacing",label:n,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)}],current:o=>{const s=ie(o.density);return Object.keys(ge).find(r=>ge[r]===s)||null},select:o=>t.setSection("density",{spacing:o,factor:null}),valueText:(o,s)=>dn(s,"spacing")?"Custom":o?"":lt(ie(s.density))}))},spacing(e,t,{label:n="Spacing"}={}){const a=D(n),o=re({label:n,options:[{value:"compact",label:"Compact"},{value:"regular",label:"Regular"},{value:"comfy",label:"Comfy"}],onSelect:r=>t.setSection("density",{spacing:r,factor:null})});a.append(o.el);const s=()=>{const r=t.getState().density||{},i=ie(r),l=Object.keys(ge).find(d=>ge[d]===i);o.setValue(l||null),a.setValue(dn(t.getState(),"spacing")?"Custom":l?"":lt(i))};s(),t.onChange(s),e.append(a.el)}},render(e,t){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(e,t))}},Ka='<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>',Wa=[[50,"white",10],[100,"white",20],[200,"white",36],[300,"white",56],[400,"white",78],[500,null,100],[600,"black",86],[700,"black",72],[800,"black",58],[900,"black",45],[950,"black",30]],dt=e=>{let t=String(e).trim().replace(/^#/,"");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};function Ga({label:e,onInput:t}){const n=document.createElement("div");n.className="colour";const a=document.createElement("div");a.className="colour-field";const o=document.createElement("input");o.type="color",o.className="colour-picker",o.tabIndex=-1,o.setAttribute("aria-hidden","true");const s=document.createElement("button");s.type="button",s.className="colour-swatch",s.setAttribute("aria-label",`${e}: open colour picker`);const r=document.createElement("input");r.type="text",r.className="colour-hex",r.spellcheck=!1,r.maxLength=7,r.setAttribute("aria-label",`${e} hex value`);const i=document.createElement("button");i.type="button",i.className="colour-pipette",i.innerHTML=Ka,i.title="Pick a colour from the screen",i.setAttribute("aria-label","Pick a colour from the screen"),a.append(o,s,r,i);const l=document.createElement("div");l.className="ramp",l.setAttribute("aria-hidden","true"),l.innerHTML=Wa.map(([f,m,x])=>{const b=m?`color-mix(in oklch, var(--brand) ${x}%, ${m})`:"var(--brand)";return`<span title="${f}" style="background:${b}"></span>`}).join(""),n.append(a,l);let d="#000000";const p=f=>{d=f,o.value=f.toLowerCase(),s.style.background=f,n.getRootNode().activeElement!==r&&(r.value=f),n.style.setProperty("--brand",f)},u=f=>{f!==d&&(p(f),t(f))};s.addEventListener("click",()=>{if(o.showPicker)try{o.showPicker();return}catch{}o.click()}),o.addEventListener("input",()=>u(o.value.toUpperCase())),r.addEventListener("input",()=>{const f=dt(r.value);f&&u(f)});const v=()=>{r.value=d};return r.addEventListener("blur",v),r.addEventListener("keydown",f=>{f.key==="Enter"&&(v(),r.select())}),i.addEventListener("click",async()=>{if("EyeDropper"in window)try{const{sRGBHex:f}=await new window.EyeDropper().open(),m=dt(f);m&&u(m)}catch{}else s.click()}),{el:n,setValue:f=>p(dt(f)||d)}}function Ya({label:e,options:t,onSelect:n}){const a=document.createElement("div");a.className="swatches",a.setAttribute("role","radiogroup"),a.setAttribute("aria-label",e);const o=t.map(l=>{const d=document.createElement("button");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});a.append(...o);let s=null;function r(l){s=l,o.forEach(p=>p.setAttribute("aria-checked",String(p.dataset.value===l)));const d=Math.max(0,o.findIndex(p=>p.dataset.value===l));o.forEach((p,u)=>{p.tabIndex=u===d?0:-1})}function i(l,d){l!==s&&(r(l),n(l)),d&&o.find(p=>p.dataset.value===l).focus()}return a.addEventListener("keydown",l=>{const d=o.indexOf(l.target.closest(".swatch"));if(d<0)return;const p={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let u;if(p)u=(d+p+o.length)%o.length;else if(l.key==="Home")u=0;else if(l.key==="End")u=o.length-1;else return;l.preventDefault(),i(o[u].dataset.value,!0)}),r(null),{el:a,setValue:r}}const Xa=[50,100,200,300,400,500,600,700,800,900,950],me=e=>Object.fromEntries(e.split(" ").map((t,n)=>[Xa[n],`#${t}`])),ct={slate:me("f8fafc f1f5f9 e2e8f0 cbd5e1 94a3b8 64748b 475569 334155 1e293b 0f172a 020617"),gray:me("f9fafb f3f4f6 e5e7eb d1d5db 9ca3af 6b7280 4b5563 374151 1f2937 111827 030712"),zinc:me("fafafa f4f4f5 e4e4e7 d4d4d8 a1a1aa 71717a 52525b 3f3f46 27272a 18181b 09090b"),neutral:me("fafafa f5f5f5 e5e5e5 d4d4d4 a3a3a3 737373 525252 404040 262626 171717 0a0a0a"),stone:me("fafaf9 f5f5f4 e7e5e4 d6d3d1 a8a29e 78716c 57534e 44403c 292524 1c1917 0c0a09")},N=e=>Object.fromEntries(e.split(" ").map((t,n)=>[400+100*n,`#${t}`])),pt={red:N("f87171 ef4444 dc2626 b91c1c 991b1b"),orange:N("fb923c f97316 ea580c c2410c 9a3412"),amber:N("fbbf24 f59e0b d97706 b45309 92400e"),yellow:N("facc15 eab308 ca8a04 a16207 854d0e"),lime:N("a3e635 84cc16 65a30d 4d7c0f 3f6212"),green:N("4ade80 22c55e 16a34a 15803d 166534"),emerald:N("34d399 10b981 059669 047857 065f46"),teal:N("2dd4bf 14b8a6 0d9488 0f766e 115e59"),cyan:N("22d3ee 06b6d4 0891b2 0e7490 155e75"),sky:N("38bdf8 0ea5e9 0284c7 0369a1 075985"),blue:N("60a5fa 3b82f6 2563eb 1d4ed8 1e40af"),indigo:N("818cf8 6366f1 4f46e5 4338ca 3730a3"),violet:N("a78bfa 8b5cf6 7c3aed 6d28d9 5b21b6"),purple:N("c084fc a855f7 9333ea 7e22ce 6b21a8"),fuchsia:N("e879f9 d946ef c026d3 a21caf 86198f"),pink:N("f472b6 ec4899 db2777 be185d 9d174d"),rose:N("fb7185 f43f5e e11d48 be123c 9f1239")},Ae=[{value:"indigo-zinc",label:"Indigo · Zinc",primary:"indigo",neutral:"zinc"},{value:"emerald-stone",label:"Emerald · Stone",primary:"emerald",neutral:"stone"},{value:"rose-slate",label:"Rose · Slate",primary:"rose",neutral:"slate"},{value:"amber-neutral",label:"Amber · Neutral",primary:"amber",neutral:"neutral"}],pn="#4F46E5",Za="#A0743C",Ja=[{value:"pure",label:"Pure",colour:"#8E8E93"},{value:"subtle",label:"Subtle",colour:"#8A89A6"},{value:"warm",label:"Warm",colour:"#9C9389"}],un=["bg","surface","surface-raised","text","text-muted","border"],Qa={bg:"#0F0F11",surface:"#18181B","surface-raised":"#1F1F23",text:"#F4F4F5","text-muted":"#A1A1AA",border:"#2E2E33"},eo={bg:4,surface:2,"surface-raised":2,text:5,"text-muted":12,border:10},Y=e=>/^#[0-9a-f]{6}$/i.test(e||""),ut=e=>[500,600,700].includes(Number(e.shade))?Number(e.shade):600,ht=e=>e[0].toUpperCase()+e.slice(1);function hn(e){const t=l=>(l/=255,l<=.03928?l/12.92:((l+.055)/1.055)**2.4),[n,a,o]=[1,3,5].map(l=>t(parseInt(e.slice(l,l+2),16))),s=.2126*n+.7152*a+.0722*o,r=1.05/(s+.05),i=(s+.05)/(.0098+.05);return r>=i?"#FFFFFF":"#18181B"}const Le={id:"colour",title:"Colour",hint:"Brand colour · neutral tint · mode",uses:["--twd-primary","--twd-primary-hover","--twd-on-primary","--twd-focus",...un.map(e=>`--twd-${e}`)],tokens(e){const t=e.colour||{},n={},a=t.mode==="dark",o=pt[t.primary];if(!Y(t.brand)&&o){const i=ut(t);n["--twd-primary"]=o[i],n["--twd-primary-hover"]=o[a?i-100:i+100],n["--twd-on-primary"]=hn(o[i]),n["--twd-focus"]=o[500]}Y(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"]=hn(t.brand),n["--twd-focus"]=t.brand);const s=t.tint==="subtle"?Y(t.brand)?t.brand:F("--twd-primary")||pn:t.tint==="warm"?Za:null,r=ct[t.neutral];if(r){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]};Object.entries(i).forEach(([l,d])=>{n[`--twd-${l}`]=d})}else(a||s)&&un.forEach(i=>{const l=a?Qa[i]:F(`--twd-${i}`);l&&(n[`--twd-${i}`]=s?`color-mix(in oklch, ${l} ${100-eo[i]}%, ${s})`:l)});return n},parts:{themeTiles(e,t,{label:n="Theme"}={}){const a=o=>{const s=ct[o.neutral],r=pt[o.primary];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>`};e.append(H(t,{section:"colour",key:"theme",label:n,columns:2,className:"tiles-themes",options:Ae.map(o=>({value:o.value,label:o.label,preview:a(o)})),current:o=>{const s=o.colour||{};return Y(s.brand)?null:Ae.find(r=>r.primary===s.primary&&r.neutral===s.neutral)?.value||null},select:o=>{const s=Ae.find(r=>r.value===o);t.setSection("colour",{primary:s.primary,neutral:s.neutral,shade:null,brand:null,tint:null})},valueText:(o,s)=>{const r=s.colour||{};return o?"":r.primary||r.neutral||r.brand?"Custom":"Prototype colours"}}))},primary(e,t,{label:n="Primary"}={}){const a=D(n),o=H(t,{section:"colour",key:"primary",label:`${n} colour family`,columns:9,className:"tiles-swatches",options:Object.entries(pt).map(([i,l])=>({value:i,label:ht(i),title:ht(i),preview:`<span class="dot" style="background:${l[500]}"></span>`})),current:i=>{const l=i.colour||{};return Y(l.brand)?null:l.primary||null},select:i=>t.setSection("colour",{primary:i,brand:null})});o.querySelector(".field-head").remove();const s=re({label:"Shade",options:[500,600,700].map(i=>({value:String(i),label:String(i)})),onSelect:i=>t.setSection("colour",{shade:Number(i)})});a.append(o,s.el);const r=()=>{const i=t.getState().colour||{};s.setValue(String(ut(i))),a.setValue(Y(i.brand)?i.brand.toLowerCase():i.primary?`${i.primary}-${ut(i)}`:"")};r(),t.onChange(r),e.append(a.el)},neutralTiles(e,t,{label:n="Neutral"}={}){e.append(H(t,{section:"colour",key:"neutral",label:n,columns:5,className:"tiles-greys",options:Object.entries(ct).map(([a,o])=>({value:a,label:ht(a),preview:`<span class="greys">${[o[50],o[200],o[500],o[900]].map(s=>`<i style="background:${s}"></i>`).join("")}</span>`})),select:a=>t.setSection("colour",{neutral:a,tint:null}),valueText:a=>a||""}))},custom(e,t){const n=document.createElement("details");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>';const a=document.createElement("div");a.className="more-body",n.append(a),Le.parts.brand(a,t,{label:"Brand"}),Y((t.getState().colour||{}).brand)&&(n.open=!0),e.append(n)},brand(e,t,{label:n="Brand"}={}){const a=D(n),o=Ga({label:"Brand colour",onInput:r=>t.setSection("colour",{brand:r})});a.append(o.el);const s=()=>o.setValue((t.getState().colour||{}).brand||(t.readToken||F)("--twd-primary")||pn);s(),t.onChange(s),e.append(a.el)},neutral(e,t,{label:n="Neutral"}={}){const a=D(n),o=Ya({label:"Neutral tint",options:Ja,onSelect:r=>t.setSection("colour",{tint:r})});a.append(o.el);const s=()=>o.setValue((t.getState().colour||{}).tint||"pure");s(),t.onChange(s),e.append(a.el)},mode(e,t,{label:n="Mode"}={}){e.append(fe(t,{section:"colour",key:"mode",label:n,fallback:"light",options:[{value:"light",label:"Light"},{value:"dark",label:"Dark"}]}))}},render(e,t){["brand","neutral","mode"].forEach(n=>this.parts[n](e,t))}},Pe=(e,t="var(--twd-surface)")=>`color-mix(in oklch, var(--twd-primary) ${e}%, ${t})`,to={soft:{bg:Pe(14),fg:"var(--twd-primary)",border:"transparent",hover:Pe(22)},outline:{bg:"transparent",fg:"var(--twd-primary)",border:"var(--twd-primary)",hover:Pe(8,"transparent")},ghost:{bg:"transparent",fg:"var(--twd-primary)",border:"transparent",hover:Pe(10,"transparent")}},no={small:{height:.8,pad:.75},large:{height:1.2,pad:1.25}},fn=rn({id:"buttons",title:"Buttons",hint:"Style · corners · size",token:"--twd-radius-control",shape:"button",uses:["--twd-control-height","--twd-control-pad-x","--twd-button-bg","--twd-button-fg","--twd-button-border","--twd-button-hover"],max:24,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:4},{value:"rounded",label:"Rounded",radius:8},{value:"pill",label:"Pill",radius:999}],extraTokens(e){const t={},n=to[e.style];n&&Object.entries(n).forEach(([r,i])=>{t[`--twd-button-${r}`]=i});const a=no[e.size];if(!a)return t;const o=he(F("--twd-control-height"),a.height),s=he(F("--twd-control-pad-x"),a.pad);return o&&(t["--twd-control-height"]=o),s&&(t["--twd-control-pad-x"]=s),t},extra:[{key:"style",label:"Style",fallback:"solid",columns:4,preview:e=>`<span class="shape shape-button style-${e}"></span>`,options:[{value:"solid",label:"Solid"},{value:"soft",label:"Soft"},{value:"outline",label:"Outline"},{value:"ghost",label:"Ghost"}]},{key:"size",label:"Size",fallback:"medium",preview:e=>`<span class="shape shape-button size-${e}"></span>`,options:[{value:"small",label:"Small"},{value:"medium",label:"Medium"},{value:"large",label:"Large"}]}]}),ao={outlined:{bg:"transparent",border:"color-mix(in oklch, var(--twd-border) 60%, var(--twd-text))",shadow:"none"},elevated:{bg:"var(--twd-surface-raised)",border:"transparent",shadow:"var(--twd-shadow-md)"},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"}},ft=rn({id:"cards",title:"Cards",hint:"Style · corners · border",token:"--twd-radius-container",shape:"card",uses:["--twd-border-width-container","--twd-card-bg","--twd-card-border","--twd-card-shadow"],max:32,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:6},{value:"rounded",label:"Rounded",radius:12},{value:"large",label:"Large",radius:20}],extraTokens(e){const t={},n=ao[e.style];if(n&&Object.entries(n).forEach(([a,o])=>{t[`--twd-card-${a}`]=o}),e.border==="none"&&(t["--twd-border-width-container"]="0px"),e.border==="thick"){const a=he(F("--twd-border-width-container"),2);a&&(t["--twd-border-width-container"]=a)}return t},extra:[{key:"style",label:"Style",fallback:"filled",columns:4,preview:e=>`<span class="shape shape-card style-${e}"></span>`,options:[{value:"filled",label:"Filled"},{value:"outlined",label:"Outlined"},{value:"elevated",label:"Elevated"},{value:"tinted",label:"Tinted"}]},{key:"border",label:"Border",fallback:"thin",preview:e=>`<span class="shape shape-card border-${e}"></span>`,options:[{value:"none",label:"None"},{value:"thin",label:"Thin"},{value:"thick",label:"Thick"}]}]}),le=60,gt={soft:{sm:[0,1,2,0,.06],md:[0,4,12,0,.08],lg:[0,12,32,0,.12]},crisp:{sm:[0,1,1,0,.12],md:[0,2,4,0,.14],lg:[0,4,8,0,.16]},bold:{sm:[2,2,0,0,.85],md:[3,3,0,0,.85],lg:[5,5,0,0,.85]}},Oe=([e,t,n,a,o],s)=>{const r=Math.min(1,+(o*s).toFixed(3));return r<=0?"none":`${e}px ${t}px ${n}px ${a}px rgb(0 0 0 / ${r})`},mt={id:"depth",title:"Depth",hint:"Flat · soft · crisp · bold",uses:["--twd-shadow-sm","--twd-shadow-md","--twd-shadow-lg"],tokens(e){const t=e.depth||{},n=t.style||"soft",a=typeof t.intensity=="number"?Math.min(100,Math.max(0,t.intensity)):le;if(n==="flat")return{"--twd-shadow-sm":"none","--twd-shadow-md":"none","--twd-shadow-lg":"none"};const o=gt[n];if(!o)return{};if(n==="soft"&&a===le)return{};const s=a/le;return{"--twd-shadow-sm":Oe(o.sm,s),"--twd-shadow-md":Oe(o.md,s),"--twd-shadow-lg":Oe(o.lg,s)}},parts:{styleTiles(e,t,{label:n="Style"}={}){const a=o=>`<span class="shape shape-card shadow-${o}" style="box-shadow:${gt[o]?Oe(gt[o].md,1):"none"}"></span>`;e.append(H(t,{section:"depth",key:"style",label:n,fallback:"soft",columns:4,options:["flat","soft","crisp","bold"].map(o=>({value:o,label:o[0].toUpperCase()+o.slice(1),preview:a(o)}))}))},style(e,t,{label:n="Style"}={}){e.append(fe(t,{section:"depth",key:"style",label:n,fallback:"soft",options:[{value:"flat",label:"Flat"},{value:"soft",label:"Soft"},{value:"crisp",label:"Crisp"},{value:"bold",label:"Bold"}]}))},intensity(e,t,{label:n="Intensity"}={}){e.append(Ba(t,{section:"depth",key:"intensity",label:n,min:0,max:100,fallback:le,format:a=>`${a}%`}))}},render(e,t){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(e,t))}},oo=e=>Math.min(1,Math.max(0,e)),gn=e=>Math.round(e/50)*50,bt=e=>`${+e.toFixed(1)}%`;function xt(e={}){return typeof e.bold=="number"&&isFinite(e.bold)&&e.bold!==.5?oo(e.bold):null}const Fe=(e,t,n)=>(e.tokens(t)||{})[n]||F(n),ro={id:"character",title:"Character",hint:"Subtle ↔ Bold",uses:[],tokens(e){const t=xt(e.character);if(t===null)return{};const n={},a=2*t-1,o=Math.max(0,a),s=Math.max(0,-a);n["--twd-weight-heading"]=String(gn(600+200*a)),n["--twd-weight-strong"]=String(gn(600+100*a));const r=Fe(Le,e,"--twd-border");if(s&&(n["--twd-border"]=`color-mix(in oklch, ${r} ${bt(100-50*s)}, var(--twd-bg))`),o){n["--twd-border"]=`color-mix(in oklch, ${r} ${bt(100-90*o)}, var(--twd-text))`;const l=Fe(Le,e,"--twd-text-muted");n["--twd-text-muted"]=`color-mix(in oklch, ${l} ${bt(100-35*o)}, var(--twd-text))`,["--twd-border-width","--twd-border-width-container"].forEach(d=>{const p=d==="--twd-border-width-container"?Fe(ft,e,d):F(d),u=parseFloat(p);isNaN(u)||(n[d]=`${Math.round(u*(1+o))}px`)}),[[fn,"--twd-radius-control"],[ft,"--twd-radius-container"]].forEach(([d,p])=>{const u=parseFloat(Fe(d,e,p));!isNaN(u)&&u<999&&(n[p]=he(`${u}px`,1-.5*o))})}const i=e.depth||{};if(!i.style){const l=typeof i.intensity=="number"?i.intensity:le,d=s?mt.tokens({depth:{style:"soft",intensity:l*(1-s)}}):mt.tokens({depth:{style:"bold",intensity:le*o}});Object.assign(n,d)}return n},describe:(e,t)=>e==="bold"?{label:"Subtle ↔ Bold",value:`${Math.round(t*100)}%`}:null},so='<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>',io='<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>';let lo=0;function co({label:e,options:t,onSelect:n,placeholder:a,onOpen:o}){const s=`twd-fonts-${++lo}`,r=document.createElement("div");r.className="font-select";const i=document.createElement("button");i.type="button",i.className="font-trigger",i.setAttribute("aria-haspopup","listbox"),i.setAttribute("aria-expanded","false"),i.setAttribute("aria-controls",s),i.innerHTML=`
855
+ <button class="icon-btn token-reset" title="Back to the page’s value" aria-label="Reset ${K(t)}" hidden>${P.reset}</button>
856
+ `;const r=o.querySelector("input"),s=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");let f="";const v=()=>{let m=r.value;f&&/^-?\d*\.?\d+$/.test(m.trim())&&(m=`${m.trim()}${f}`);const x=so(m,n),b=L(K(t));if(x===null){ft(e,t)?e.setSection("custom",{[t]:null}):u();return}if(x===b&&!ft(e,t))return u();e.setSection("custom",{[t]:x})};r.addEventListener("change",v),r.addEventListener("blur",()=>u()),r.addEventListener("keydown",m=>{m.key==="Enter"&&(m.preventDefault(),r.blur()),m.key==="Escape"&&(m.stopPropagation(),u(),r.blur())}),p.addEventListener("click",()=>e.setSection("custom",{[t]:null}));function u(){const m=L(K(t)),x=ft(e,t),b=ro(m,n);f=b?b.unit:"",document.activeElement!==r&&o.getRootNode().activeElement!==r&&(r.value=b?String(b.n):m),r.title=m,s.textContent=f,s.hidden=!f,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}return u(),e.onChange(u),o}const lo={id:"custom",title:"Custom tokens",hint:"Any token, set to a fixed value",uses:[],tokens(e){return Object.fromEntries(Object.entries(e.custom||{}).map(([t,n])=>[K(t),n]))},describe:(e,t)=>({label:K(e),value:String(t)}),parts:Object.fromEntries(Object.entries(Sn).map(([e,t])=>[e,(n,a,{label:o=t.label}={})=>{const r=I(o);r.el.classList.add("token-field");const s=t.tokens[0],i=t.tokens[t.tokens.length-1];r.setValue(t.tokens.length>2&&/-\w+$/.test(s)?`${K(s)} … ${i.split("-").pop()}`:"");const l=document.createElement("div");l.className="token-rows",t.tokens.forEach(d=>l.append(io(a,d,t.kind,t.bar))),r.append(l),n.append(r.el)}]))},W={compact:.75,regular:1,comfy:1.25},gt=[.75,1.25],$n=[1,2,3,4,5,6,7,8].map(e=>`--twd-space-${e}`);function En(e){const t=Object.entries(W).sort((a,o)=>a[1]-o[1]);if(t.some(([,a])=>a===e))return[];const n=t.findIndex(([,a])=>a>e);return n>0?[t[n-1][0],t[n][0]]:[]}const mt=e=>e[0].toUpperCase()+e.slice(1);function bt(e){const t=Object.keys(W).find(a=>W[a]===e);if(t)return mt(t);const n=En(e);return n.length?`Between ${mt(n[0])} and ${mt(n[1])}`:e>1?"Comfy":"Compact"}function q(e={}){return typeof e.factor=="number"&&isFinite(e.factor)?Math.min(gt[1],Math.max(gt[0],e.factor)):W[e.spacing]||1}const xt=e=>`${Math.round(e*100)}%`,co={id:"density",title:"Density",hint:"Compact · regular · comfortable",uses:$n,tokens(e){const t=q(e.density);if(t===1)return{};const n={};return $n.forEach(a=>{const o=xe(L(a),t);o&&(n[a]=o)}),n},describe:(e,t)=>e==="factor"?{label:"Spacing",value:xt(t)}:null,parts:{spacingTiles(e,t,{label:n="Density"}={}){const a=(o,r)=>`<span class="sketch" style="padding:${r}px;gap:${o}px"><i></i><i></i><i></i></span>`;e.append(V(t,{section:"density",key:"spacing",label:n,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)}],current:o=>{const r=q(o.density);return Object.keys(W).find(s=>W[s]===r)||null},select:o=>t.setSection("density",{spacing:o,factor:null}),near:o=>ve(o,"spacing")?[]:En(q(o.density)),valueText:(o,r)=>ve(r,"spacing")?"Custom":o?"":`${bt(q(r.density))} · ${xt(q(r.density))}`}))},spacing(e,t,{label:n="Spacing"}={}){const a=I(n),o=ce({label:n,options:[{value:"compact",label:"Compact"},{value:"regular",label:"Regular"},{value:"comfy",label:"Comfy"}],onSelect:s=>t.setSection("density",{spacing:s,factor:null})});a.append(o.el);const r=()=>{const s=t.getState().density||{},i=q(s),l=Object.keys(W).find(d=>W[d]===i);o.setValue(l||null),a.setValue(ve(t.getState(),"spacing")?"Custom":l?"":xt(i))};r(),t.onChange(r),e.append(a.el)}},render(e,t){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(e,t))}},po='<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>',uo=[[50,"white",10],[100,"white",20],[200,"white",36],[300,"white",56],[400,"white",78],[500,null,100],[600,"black",86],[700,"black",72],[800,"black",58],[900,"black",45],[950,"black",30]],wt=e=>{let t=String(e).trim().replace(/^#/,"");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};function ho({label:e,onInput:t}){const n=document.createElement("div");n.className="colour";const a=document.createElement("div");a.className="colour-field";const o=document.createElement("input");o.type="color",o.className="colour-picker",o.tabIndex=-1,o.setAttribute("aria-hidden","true");const r=document.createElement("button");r.type="button",r.className="colour-swatch",r.setAttribute("aria-label",`${e}: open colour picker`);const s=document.createElement("input");s.type="text",s.className="colour-hex",s.spellcheck=!1,s.maxLength=7,s.setAttribute("aria-label",`${e} hex value`);const i=document.createElement("button");i.type="button",i.className="colour-pipette",i.innerHTML=po,i.title="Pick a colour from the screen",i.setAttribute("aria-label","Pick a colour from the screen"),a.append(o,r,s,i);const l=document.createElement("div");l.className="ramp",l.setAttribute("aria-hidden","true"),l.innerHTML=uo.map(([u,m,x])=>{const b=m?`color-mix(in oklch, var(--brand) ${x}%, ${m})`:"var(--brand)";return`<span title="${u}" style="background:${b}"></span>`}).join(""),n.append(a,l);let d="#000000";const p=u=>{d=u,o.value=u.toLowerCase(),r.style.background=u,n.getRootNode().activeElement!==s&&(s.value=u),n.style.setProperty("--brand",u)},f=u=>{u!==d&&(p(u),t(u))};r.addEventListener("click",()=>{if(o.showPicker)try{o.showPicker();return}catch{}o.click()}),o.addEventListener("input",()=>f(o.value.toUpperCase())),s.addEventListener("input",()=>{const u=wt(s.value);u&&f(u)});const v=()=>{s.value=d};return s.addEventListener("blur",v),s.addEventListener("keydown",u=>{u.key==="Enter"&&(v(),s.select())}),i.addEventListener("click",async()=>{if("EyeDropper"in window)try{const{sRGBHex:u}=await new window.EyeDropper().open(),m=wt(u);m&&f(m)}catch{}else r.click()}),{el:n,setValue:u=>p(wt(u)||d)}}function fo({label:e,options:t,onSelect:n}){const a=document.createElement("div");a.className="swatches",a.setAttribute("role","radiogroup"),a.setAttribute("aria-label",e);const o=t.map(l=>{const d=document.createElement("button");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});a.append(...o);let r=null;function s(l){r=l,o.forEach(p=>p.setAttribute("aria-checked",String(p.dataset.value===l)));const d=Math.max(0,o.findIndex(p=>p.dataset.value===l));o.forEach((p,f)=>{p.tabIndex=f===d?0:-1})}function i(l,d){l!==r&&(s(l),n(l)),d&&o.find(p=>p.dataset.value===l).focus()}return a.addEventListener("keydown",l=>{const d=o.indexOf(l.target.closest(".swatch"));if(d<0)return;const p={ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}[l.key];let f;if(p)f=(d+p+o.length)%o.length;else if(l.key==="Home")f=0;else if(l.key==="End")f=o.length-1;else return;l.preventDefault(),i(o[f].dataset.value,!0)}),s(null),{el:a,setValue:s}}const go=[50,100,200,300,400,500,600,700,800,900,950],ye=e=>Object.fromEntries(e.split(" ").map((t,n)=>[go[n],`#${t}`])),vt={slate:ye("f8fafc f1f5f9 e2e8f0 cbd5e1 94a3b8 64748b 475569 334155 1e293b 0f172a 020617"),gray:ye("f9fafb f3f4f6 e5e7eb d1d5db 9ca3af 6b7280 4b5563 374151 1f2937 111827 030712"),zinc:ye("fafafa f4f4f5 e4e4e7 d4d4d8 a1a1aa 71717a 52525b 3f3f46 27272a 18181b 09090b"),neutral:ye("fafafa f5f5f5 e5e5e5 d4d4d4 a3a3a3 737373 525252 404040 262626 171717 0a0a0a"),stone:ye("fafaf9 f5f5f4 e7e5e4 d6d3d1 a8a29e 78716c 57534e 44403c 292524 1c1917 0c0a09")},N=e=>Object.fromEntries(e.split(" ").map((t,n)=>[400+100*n,`#${t}`])),yt={red:N("f87171 ef4444 dc2626 b91c1c 991b1b"),orange:N("fb923c f97316 ea580c c2410c 9a3412"),amber:N("fbbf24 f59e0b d97706 b45309 92400e"),yellow:N("facc15 eab308 ca8a04 a16207 854d0e"),lime:N("a3e635 84cc16 65a30d 4d7c0f 3f6212"),green:N("4ade80 22c55e 16a34a 15803d 166534"),emerald:N("34d399 10b981 059669 047857 065f46"),teal:N("2dd4bf 14b8a6 0d9488 0f766e 115e59"),cyan:N("22d3ee 06b6d4 0891b2 0e7490 155e75"),sky:N("38bdf8 0ea5e9 0284c7 0369a1 075985"),blue:N("60a5fa 3b82f6 2563eb 1d4ed8 1e40af"),indigo:N("818cf8 6366f1 4f46e5 4338ca 3730a3"),violet:N("a78bfa 8b5cf6 7c3aed 6d28d9 5b21b6"),purple:N("c084fc a855f7 9333ea 7e22ce 6b21a8"),fuchsia:N("e879f9 d946ef c026d3 a21caf 86198f"),pink:N("f472b6 ec4899 db2777 be185d 9d174d"),rose:N("fb7185 f43f5e e11d48 be123c 9f1239")},Oe=[{value:"indigo-zinc",label:"Indigo · Zinc",primary:"indigo",neutral:"zinc"},{value:"emerald-stone",label:"Emerald · Stone",primary:"emerald",neutral:"stone"},{value:"rose-slate",label:"Rose · Slate",primary:"rose",neutral:"slate"},{value:"amber-neutral",label:"Amber · Neutral",primary:"amber",neutral:"neutral"}],Cn="#4F46E5",mo="#A0743C",bo=[{value:"pure",label:"Pure",colour:"#8E8E93"},{value:"subtle",label:"Subtle",colour:"#8A89A6"},{value:"warm",label:"Warm",colour:"#9C9389"}],Mn=["bg","surface","surface-raised","text","text-muted","border"],xo={bg:"#0F0F11",surface:"#18181B","surface-raised":"#1F1F23",text:"#F4F4F5","text-muted":"#A1A1AA",border:"#2E2E33"},wo={bg:4,surface:2,"surface-raised":2,text:5,"text-muted":12,border:10},te=e=>/^#[0-9a-f]{6}$/i.test(e||""),kt=e=>[500,600,700].includes(Number(e.shade))?Number(e.shade):600,St=e=>e[0].toUpperCase()+e.slice(1);function Tn(e){const t=l=>(l/=255,l<=.03928?l/12.92:((l+.055)/1.055)**2.4),[n,a,o]=[1,3,5].map(l=>t(parseInt(e.slice(l,l+2),16))),r=.2126*n+.7152*a+.0722*o,s=1.05/(r+.05),i=(r+.05)/(.0098+.05);return s>=i?"#FFFFFF":"#18181B"}const je={id:"colour",title:"Colour",hint:"Brand colour · neutral tint · mode",uses:["--twd-primary","--twd-primary-hover","--twd-on-primary","--twd-focus",...Mn.map(e=>`--twd-${e}`)],tokens(e){const t=e.colour||{},n={},a=t.mode==="dark",o=yt[t.primary];if(!te(t.brand)&&o){const i=kt(t);n["--twd-primary"]=o[i],n["--twd-primary-hover"]=o[a?i-100:i+100],n["--twd-on-primary"]=Tn(o[i]),n["--twd-focus"]=o[500]}te(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"]=Tn(t.brand),n["--twd-focus"]=t.brand);const r=t.tint==="subtle"?te(t.brand)?t.brand:L("--twd-primary")||Cn:t.tint==="warm"?mo:null,s=vt[t.neutral];if(s){const i=a?{bg:s[950],surface:s[900],"surface-raised":s[800],text:s[100],"text-muted":s[400],border:s[800]}:{bg:s[50],surface:"#ffffff","surface-raised":"#ffffff",text:s[900],"text-muted":s[500],border:s[200]};Object.entries(i).forEach(([l,d])=>{n[`--twd-${l}`]=d})}else(a||r)&&Mn.forEach(i=>{const l=a?xo[i]:L(`--twd-${i}`);l&&(n[`--twd-${i}`]=r?`color-mix(in oklch, ${l} ${100-wo[i]}%, ${r})`:l)});return n},parts:{themeTiles(e,t,{label:n="Theme"}={}){const a=o=>{const r=vt[o.neutral],s=yt[o.primary];return`<span class="theme" style="--bg:${r[50]};--line:${r[200]};--ink:${r[900]};--soft:${r[500]};--pri:${s[600]}"><i><b></b><s></s><u></u></i></span><span class="palette">${[s[400],s[500],s[600],s[700],s[800],r[200],r[500],r[900]].map(i=>`<i style="background:${i}"></i>`).join("")}</span>`};e.append(V(t,{section:"colour",key:"theme",label:n,columns:2,className:"tiles-themes",options:Oe.map(o=>({value:o.value,label:o.label,preview:a(o)})),current:o=>{const r=o.colour||{};return te(r.brand)?null:Oe.find(s=>s.primary===r.primary&&s.neutral===r.neutral)?.value||null},select:o=>{const r=Oe.find(s=>s.value===o);t.setSection("colour",{primary:r.primary,neutral:r.neutral,shade:null,brand:null,tint:null})},valueText:(o,r)=>{const s=r.colour||{};return o?"":s.primary||s.neutral||s.brand?"Custom":"Prototype colours"}}))},primary(e,t,{label:n="Primary"}={}){const a=I(n),o=V(t,{section:"colour",key:"primary",label:`${n} colour family`,columns:9,className:"tiles-swatches",options:Object.entries(yt).map(([i,l])=>({value:i,label:St(i),title:St(i),preview:`<span class="dot" style="background:${l[500]}"></span>`})),current:i=>{const l=i.colour||{};return te(l.brand)?null:l.primary||null},select:i=>t.setSection("colour",{primary:i,brand:null})});o.querySelector(".field-head").remove();const r=ce({label:"Shade",options:[500,600,700].map(i=>({value:String(i),label:String(i)})),onSelect:i=>t.setSection("colour",{shade:Number(i)})});a.append(o,r.el);const s=()=>{const i=t.getState().colour||{};r.setValue(String(kt(i))),a.setValue(te(i.brand)?i.brand.toLowerCase():i.primary?`${i.primary}-${kt(i)}`:"")};s(),t.onChange(s),e.append(a.el)},neutralTiles(e,t,{label:n="Neutral"}={}){e.append(V(t,{section:"colour",key:"neutral",label:n,columns:5,className:"tiles-greys",options:Object.entries(vt).map(([a,o])=>({value:a,label:St(a),preview:`<span class="greys">${[o[50],o[200],o[500],o[900]].map(r=>`<i style="background:${r}"></i>`).join("")}</span>`})),select:a=>t.setSection("colour",{neutral:a,tint:null}),valueText:a=>a||""}))},custom(e,t){const n=document.createElement("details");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>';const a=document.createElement("div");a.className="more-body",n.append(a),je.parts.brand(a,t,{label:"Brand"}),te((t.getState().colour||{}).brand)&&(n.open=!0),e.append(n)},brand(e,t,{label:n="Brand"}={}){const a=I(n),o=ho({label:"Brand colour",onInput:s=>t.setSection("colour",{brand:s})});a.append(o.el);const r=()=>o.setValue((t.getState().colour||{}).brand||(t.readToken||L)("--twd-primary")||Cn);r(),t.onChange(r),e.append(a.el)},neutral(e,t,{label:n="Neutral"}={}){const a=I(n),o=fo({label:"Neutral tint",options:bo,onSelect:s=>t.setSection("colour",{tint:s})});a.append(o.el);const r=()=>o.setValue((t.getState().colour||{}).tint||"pure");r(),t.onChange(r),e.append(a.el)},mode(e,t,{label:n="Mode"}={}){e.append(we(t,{section:"colour",key:"mode",label:n,fallback:"light",options:[{value:"light",label:"Light"},{value:"dark",label:"Dark"}]}))}},render(e,t){["brand","neutral","mode"].forEach(n=>this.parts[n](e,t))}},Fe=(e,t="var(--twd-surface)")=>`color-mix(in oklch, var(--twd-primary) ${e}%, ${t})`,vo={soft:{bg:Fe(14),fg:"var(--twd-primary)",border:"transparent",hover:Fe(22)},outline:{bg:"transparent",fg:"var(--twd-primary)",border:"var(--twd-primary)",hover:Fe(8,"transparent")},ghost:{bg:"transparent",fg:"var(--twd-primary)",border:"transparent",hover:Fe(10,"transparent")}},yo={small:{height:.8,pad:.75},large:{height:1.2,pad:1.25}},Ln=wn({id:"buttons",title:"Buttons",hint:"Style · corners · size",token:"--twd-radius-control",shape:"button",uses:["--twd-control-height","--twd-control-pad-x","--twd-button-bg","--twd-button-fg","--twd-button-border","--twd-button-hover"],max:24,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:4},{value:"rounded",label:"Rounded",radius:8},{value:"pill",label:"Pill",radius:999}],extraTokens(e){const t={},n=vo[e.style];n&&Object.entries(n).forEach(([s,i])=>{t[`--twd-button-${s}`]=i});const a=yo[e.size];if(!a)return t;const o=xe(L("--twd-control-height"),a.height),r=xe(L("--twd-control-pad-x"),a.pad);return o&&(t["--twd-control-height"]=o),r&&(t["--twd-control-pad-x"]=r),t},extra:[{key:"style",label:"Style",fallback:"solid",columns:4,preview:e=>`<span class="shape shape-button style-${e}"></span>`,options:[{value:"solid",label:"Solid"},{value:"soft",label:"Soft"},{value:"outline",label:"Outline"},{value:"ghost",label:"Ghost"}]},{key:"size",label:"Size",fallback:"medium",valueText:(e,t)=>t("--twd-control-height"),preview:e=>`<span class="shape shape-button size-${e}"></span>`,options:[{value:"small",label:"Small"},{value:"medium",label:"Medium"},{value:"large",label:"Large"}]}]}),ko={outlined:{bg:"transparent",border:"color-mix(in oklch, var(--twd-border) 60%, var(--twd-text))",shadow:"none"},elevated:{bg:"var(--twd-surface-raised)",border:"transparent",shadow:"var(--twd-shadow-md)"},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"}},$t=wn({id:"cards",title:"Cards",hint:"Style · corners · border",token:"--twd-radius-container",shape:"card",uses:["--twd-border-width-container","--twd-card-bg","--twd-card-border","--twd-card-shadow"],max:32,presets:[{value:"square",label:"Square",radius:0},{value:"soft",label:"Soft",radius:6},{value:"rounded",label:"Rounded",radius:12},{value:"large",label:"Large",radius:20}],extraTokens(e){const t={},n=ko[e.style];if(n&&Object.entries(n).forEach(([a,o])=>{t[`--twd-card-${a}`]=o}),e.border==="none"&&(t["--twd-border-width-container"]="0px"),e.border==="thick"){const a=xe(L("--twd-border-width-container"),2);a&&(t["--twd-border-width-container"]=a)}return t},extra:[{key:"style",label:"Style",fallback:"filled",columns:4,preview:e=>`<span class="mini"><span class="mini-card style-${e}"><i></i><i></i></span></span>`,options:[{value:"filled",label:"Filled"},{value:"outlined",label:"Outlined"},{value:"elevated",label:"Elevated"},{value:"tinted",label:"Tinted"}]},{key:"border",label:"Border",fallback:"thin",token:"--twd-border-width-container",preview:e=>`<span class="shape shape-card border-${e}"></span>`,options:[{value:"none",label:"None"},{value:"thin",label:"Thin"},{value:"thick",label:"Thick"}]}]}),Ne=e=>!(e.depth||{}).style&&ue(e,"--twd-shadow-md"),So=e=>((e.character||{}).bold||.5)>.5,G=60,Et={soft:{sm:[0,1,2,0,.06],md:[0,4,12,0,.08],lg:[0,12,32,0,.12]},crisp:{sm:[0,1,1,0,.12],md:[0,2,4,0,.14],lg:[0,4,8,0,.16]},bold:{sm:[2,2,0,0,.85],md:[3,3,0,0,.85],lg:[5,5,0,0,.85]}},Re=([e,t,n,a,o],r)=>{const s=Math.min(1,+(o*r).toFixed(3));return s<=0?"none":`${e}px ${t}px ${n}px ${a}px rgb(0 0 0 / ${s})`},Ct={id:"depth",title:"Depth",hint:"Flat · soft · crisp · bold",uses:["--twd-shadow-sm","--twd-shadow-md","--twd-shadow-lg"],tokens(e){const t=e.depth||{},n=t.style||"soft",a=typeof t.intensity=="number"?Math.min(100,Math.max(0,t.intensity)):G;if(n==="flat")return{"--twd-shadow-sm":"none","--twd-shadow-md":"none","--twd-shadow-lg":"none"};const o=Et[n];if(!o)return{};if(n==="soft"&&a===G)return{};const r=a/G;return{"--twd-shadow-sm":Re(o.sm,r),"--twd-shadow-md":Re(o.md,r),"--twd-shadow-lg":Re(o.lg,r)}},parts:{styleTiles(e,t,{label:n="Style"}={}){const a=o=>`<span class="shape shape-card shadow-${o}" style="box-shadow:${Et[o]?Re(Et[o].md,1):"none"}"></span>`;e.append(V(t,{section:"depth",key:"style",label:n,fallback:"soft",columns:4,options:["flat","soft","crisp","bold"].map(o=>({value:o,label:o[0].toUpperCase()+o.slice(1),preview:a(o)})),current:o=>(o.depth||{}).style||(Ne(o)?null:"soft"),valueText:(o,r)=>Ne(r)?`${So(r)?"Bold recipe":"Soft, faded"} · from Character`:""}))},style(e,t,{label:n="Style"}={}){e.append(we(t,{section:"depth",key:"style",label:n,fallback:"soft",options:[{value:"flat",label:"Flat"},{value:"soft",label:"Soft"},{value:"crisp",label:"Crisp"},{value:"bold",label:"Bold"}]}))},intensity(e,t,{label:n="Intensity"}={}){e.append(ao(t,{section:"depth",key:"intensity",label:n,min:0,max:100,fallback:G,format:a=>`${a}%`,note:a=>Ne(a)?"from Character":"",value:a=>{if(!Ne(a))return(a.depth||{}).intensity;const o=a.character.bold,r=typeof(a.depth||{}).intensity=="number"?a.depth.intensity:G;return Math.round(o>.5?G*(2*o-1):r*(1-(1-2*o)))}}))}},render(e,t){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(e,t))}},$o=e=>Math.min(1,Math.max(0,e)),An=e=>Math.round(e/50)*50,Mt=e=>`${+e.toFixed(1)}%`;function Tt(e={}){return typeof e.bold=="number"&&isFinite(e.bold)&&e.bold!==.5?$o(e.bold):null}const ze=(e,t,n)=>(e.tokens(t)||{})[n]||L(n),Pn={id:"character",title:"Character",hint:"Subtle ↔ Bold",uses:[],tokens(e){const t=Tt(e.character);if(t===null)return{};const n={},a=2*t-1,o=Math.max(0,a),r=Math.max(0,-a);n["--twd-weight-heading"]=String(An(600+200*a)),n["--twd-weight-strong"]=String(An(600+100*a));const s=ze(je,e,"--twd-border");if(r&&(n["--twd-border"]=`color-mix(in oklch, ${s} ${Mt(100-50*r)}, var(--twd-bg))`),o){n["--twd-border"]=`color-mix(in oklch, ${s} ${Mt(100-90*o)}, var(--twd-text))`;const l=ze(je,e,"--twd-text-muted");n["--twd-text-muted"]=`color-mix(in oklch, ${l} ${Mt(100-35*o)}, var(--twd-text))`,["--twd-border-width","--twd-border-width-container"].forEach(d=>{const p=d==="--twd-border-width-container"?ze($t,e,d):L(d),f=parseFloat(p);f>0&&(n[d]=`${Math.round(f*(1+o))}px`)}),[[Ln,"--twd-radius-control"],[$t,"--twd-radius-container"]].forEach(([d,p])=>{const f=parseFloat(ze(d,e,p));f>0&&f<999&&(n[p]=xe(`${f}px`,1-.5*o))})}const i=e.depth||{};if(!i.style){const l=typeof i.intensity=="number"?i.intensity:G,d=r?Ct.tokens({depth:{style:"soft",intensity:l*(1-r)}}):Ct.tokens({depth:{style:"bold",intensity:G*o}});Object.assign(n,d)}return n},describe:(e,t)=>e==="bold"?{label:"Subtle ↔ Bold",value:`${Math.round(t*100)}%`}:null};oo(e=>Pn.tokens(e));const Eo='<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>';let Mo=0;function To({label:e,options:t,onSelect:n,placeholder:a,onOpen:o}){const r=`twd-fonts-${++Mo}`,s=document.createElement("div");s.className="font-select";const i=document.createElement("button");i.type="button",i.className="font-trigger",i.setAttribute("aria-haspopup","listbox"),i.setAttribute("aria-expanded","false"),i.setAttribute("aria-controls",r),i.innerHTML=`
793
857
  <span class="font-aa" aria-hidden="true">Aa</span>
794
858
  <span class="font-name"></span>
795
859
  <span class="font-fonts"></span>
796
- <span class="font-chevron">${so}</span>`;const l=document.createElement("div");l.className="font-menu",l.id=s,l.setAttribute("role","listbox"),l.setAttribute("aria-label",e),l.hidden=!0;const d=t.map(h=>{const y=document.createElement("div");return y.className="font-option",y.setAttribute("role","option"),y.tabIndex=-1,y.dataset.value=h.value,y.innerHTML=`
860
+ <span class="font-chevron">${Eo}</span>`;const l=document.createElement("div");l.className="font-menu",l.id=r,l.setAttribute("role","listbox"),l.setAttribute("aria-label",e),l.hidden=!0;const d=t.map(h=>{const w=document.createElement("div");return w.className="font-option",w.setAttribute("role","option"),w.tabIndex=-1,w.dataset.value=h.value,w.innerHTML=`
797
861
  <span class="font-aa" style="font-family:${h.preview}" aria-hidden="true">Aa</span>
798
862
  <span class="font-text"><span class="font-name">${h.name}</span><span class="font-fonts">${h.fonts}</span></span>
799
- <span class="font-check">${io}</span>`,y.addEventListener("click",()=>b(h.value)),y});l.append(...d),r.append(i,l);let p=null;function u(h){const y=t.find(E=>E.value===h),P=y||a||t[0];p=y?y.value:a?null:t[0].value,i.querySelector(".font-name").textContent=P.name,i.querySelector(".font-fonts").textContent=P.fonts,i.querySelector(".font-aa").style.fontFamily=P.preview,i.setAttribute("aria-label",`${e}: ${P.name}, ${P.fonts}`),d.forEach(E=>E.setAttribute("aria-selected",String(E.dataset.value===p)))}function v(){const h=i.getBoundingClientRect(),y=l.offsetHeight,E=window.innerHeight-h.bottom-8>=y?h.bottom+4:Math.max(8,h.top-4-y);l.style.top=`${E}px`,l.style.left=`${h.left}px`,l.style.width=`${h.width}px`}function f(){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}))}function m(h){l.hidden||(l.hidden=!0,i.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",x,!0),window.removeEventListener("resize",m),h===!0&&i.focus())}function x(h){h.composedPath().includes(r)||m()}function b(h){h!==p&&(u(h),n(h)),m(!0)}return i.addEventListener("click",()=>l.hidden?f():m(!0)),i.addEventListener("keydown",h=>{(h.key==="ArrowDown"||h.key==="ArrowUp")&&(h.preventDefault(),f())}),l.addEventListener("keydown",h=>{const y=d.indexOf(h.target);let P=null;if(h.key==="ArrowDown")P=Math.min(d.length-1,y+1);else if(h.key==="ArrowUp")P=Math.max(0,y-1);else if(h.key==="Home")P=0;else if(h.key==="End")P=d.length-1;else if(h.key==="Enter"||h.key===" "){h.preventDefault(),b(h.target.dataset.value);return}else if(h.key==="Escape"){h.preventDefault(),h.stopPropagation(),m(!0);return}else if(h.key==="Tab"){m();return}P!==null&&(h.preventDefault(),d[P].focus())}),u(a?null:t[0].value),{el:r,setValue:u}}const z='ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',Ne='Georgia, "Times New Roman", serif',X=[{value:"neutral",name:"Neutral",fonts:"Inter · Inter",heading:`"Inter", ${z}`,body:`"Inter", ${z}`,load:["Inter:wght@400;500;600;700"]},{value:"modern",name:"Modern",fonts:"Geist · Geist",heading:`"Geist", ${z}`,body:`"Geist", ${z}`,load:["Geist:wght@400;500;600;700"]},{value:"editorial",name:"Editorial",fonts:"Fraunces · Inter",heading:`"Fraunces", ${Ne}`,body:`"Inter", ${z}`,load:["Fraunces:wght@400;600;700","Inter:wght@400;500;600;700"]},{value:"technical",name:"Technical",fonts:"Space Grotesk · DM Sans",heading:`"Space Grotesk", ${z}`,body:`"DM Sans", ${z}`,load:["Space+Grotesk:wght@500;600;700","DM+Sans:wght@400;500;600;700"]},{value:"classic",name:"Classic",fonts:"Playfair · DM Sans",heading:`"Playfair Display", ${Ne}`,body:`"DM Sans", ${z}`,load:["Playfair+Display:wght@600;700","DM+Sans:wght@400;500;600;700"]},{value:"plex",name:"Plex",fonts:"Plex Serif · Plex Sans",heading:`"IBM Plex Serif", ${Ne}`,body:`"IBM Plex Sans", ${z}`,load:["IBM+Plex+Serif:wght@500;600;700","IBM+Plex+Sans:wght@400;500;600"]},{value:"elegant",name:"Elegant",fonts:"Instrument Serif · Inter",heading:`"Instrument Serif", ${Ne}`,body:`"Inter", ${z}`,load:["Instrument+Serif","Inter:wght@400;500;600;700"]},{value:"friendly",name:"Friendly",fonts:"Manrope · Manrope",heading:`"Manrope", ${z}`,body:`"Manrope", ${z}`,load:["Manrope:wght@400;500;600;700"]}],be={compact:1.125,balanced:1.2,expressive:1.333},mn={xs:-2,sm:-1,base:0,lg:1,xl:2,"2xl":3,"3xl":4},bn=new Set;function wt(e){const t=e.filter(a=>!bn.has(a));if(!t.length)return;t.forEach(a=>bn.add(a));const n=document.createElement("link");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)}const po={id:"typography",title:"Typography",hint:"Font pairing · base size · scale",uses:["--twd-font-heading","--twd-font-body",...Object.keys(mn).map(e=>`--twd-text-${e}`)],tokens(e){const t=e.typography||{},n={},a=X.find(o=>o.value===t.font);if(a&&(wt(a.load),n["--twd-font-heading"]=a.heading,n["--twd-font-body"]=a.body),t.base||t.scale){const o=Number(t.base)||16,s=be[t.scale]||be.balanced;Object.entries(mn).forEach(([r,i])=>{n[`--twd-text-${r}`]=`${+(o*s**i/16).toFixed(3)}rem`})}return n},parts:{fonts(e,t,{label:n="Fonts"}={}){const a=D(n),o=co({label:"Font pairing",options:X.map(r=>({value:r.value,name:r.name,fonts:r.fonts,preview:r.heading})),placeholder:{name:"Default",fonts:"Prototype fonts",preview:z},onOpen:()=>wt([...new Set(X.flatMap(r=>r.load))]),onSelect:r=>t.setSection("typography",{font:r})});a.append(o.el);const s=()=>o.setValue((t.getState().typography||{}).font||null);s(),t.onChange(s),e.append(a.el)},base(e,t,{label:n="Base size"}={}){e.append(fe(t,{section:"typography",key:"base",label:n,fallback:"16",options:["14","15","16"].map(a=>({value:a,label:a})),valueText:a=>`${a}px`}))},fontTiles(e,t,{label:n="Fonts"}={}){const a=i=>i.replace(/"/g,"&quot;"),o=i=>`<span class="tile-aa" style="font-family:${a(i)}">Aa</span>`,s=H(t,{section:"typography",key:"font",label:n,columns:2,className:"tiles-fonts",options:[{value:"default",label:"Prototype fonts",sub:"Default",preview:o(z),wide:!0},...X.map(i=>({value:i.value,label:i.name,sub:i.fonts,preview:o(i.heading)}))],current:i=>(i.typography||{}).font||"default",select:i=>t.setSection("typography",{font:i==="default"?null:i}),valueText:i=>i==="default"?"Default":X.find(l=>l.value===i)?.name||""}),r=new IntersectionObserver(i=>{i.some(l=>l.isIntersecting)&&(wt([...new Set(X.flatMap(l=>l.load))]),r.disconnect())});r.observe(s),e.append(s)},scaleTiles(e,t,{label:n="Scale"}={}){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>`;e.append(H(t,{section:"typography",key:"scale",label:n,fallback:"balanced",options:Object.entries(be).map(([o,s])=>({value:o,label:o[0].toUpperCase()+o.slice(1),preview:a(s)})),valueText:o=>String(be[o])}))},scale(e,t,{label:n="Scale"}={}){e.append(fe(t,{section:"typography",key:"scale",label:n,fallback:"balanced",options:[{value:"compact",label:"Compact"},{value:"balanced",label:"Balanced"},{value:"expressive",label:"Expressive"}],valueText:a=>String(be[a])}))}},render(e,t){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(e,t))}},[xn,je]=it;function uo(e){return e>.56?"Bold":e<.44?"Subtle":"Balanced"}function wn(e){return e>1.06?"Comfy":e<.94?"Compact":"Regular"}const Re=e=>e&&e[0].toUpperCase()+e.slice(1),yn=[["colour","Colour",e=>{const t=e.colour||{},n=Ae.find(o=>o.primary===t.primary&&o.neutral===t.neutral);return{text:`${t.brand?t.brand.toUpperCase():n&&!t.shade?n.label:t.primary?`${Re(t.primary)}${t.neutral?` · ${Re(t.neutral)}`:""}`:"Prototype colours"}${t.mode==="dark"?" · Dark":""}`,swatch:F("--twd-primary")}}],["type","Type",e=>{const t=e.typography||{};return{text:`${X.find(n=>n.value===t.font)?.name||"Prototype fonts"} · ${t.base||16}px`}}],["spacing","Spacing",e=>({text:wn(ie(e.density))})],["shape","Shape",e=>({text:`${Re((e.buttons||{}).corners)||"Default"} corners`})],["shadows","Shadows",e=>({text:Re((e.depth||{}).style)||(xt(e.character)!==null?"From the pad":"Default")})]],ho={summary(e,t,{label:n="Current look",goTab:a}={}){const o=D(n),s=document.createElement("div");s.className="summary",yn.forEach(([i,l])=>{const d=document.createElement("button");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)}),o.append(s);const r=()=>{const i=t.getState();yn.forEach(([l,,d])=>{const p=s.querySelector(`[data-summary="${l}"]`),u=d(i);p.querySelector(".summary-value").textContent=u.text;const v=p.querySelector(".summary-swatch");v.hidden=!u.swatch,u.swatch&&(v.style.background=u.swatch)})};r(),t.onChange(r),e.append(o.el)},character(e,t,{label:n="Character"}={}){const a=D(n),o=za({label:n,ends:{top:"Spacious",bottom:"Compact",left:"Subtle",right:"Bold"},onInput:(r,i)=>{const l=+(je-i*(je-xn)).toFixed(3),d=+r.toFixed(3);t.setSections({density:{factor:l===1?null:l,spacing:null},character:{bold:d===.5?null:d}},"character")}});a.append(o.el);const s=()=>{const r=t.getState(),i=ie(r.density),l=xt(r.character),d=l===null?.5:l,p=`${wn(i)} · ${uo(d)}`;o.setValue(d,(je-i)/(je-xn),p),a.setValue(p)};s(),t.onChange(s),e.append(a.el)}},yt=[{key:"page-pad",label:"Page padding",step:5},{key:"section-gap",label:"Section gap",step:6},{key:"card-pad",label:"Card padding",step:5},{key:"card-gap",label:"Card gap",step:2},{key:"control-gap",label:"Control gap",step:3},{key:"control-pad-x",label:"Control padding",step:null}],fo=[1,2,3,4,5,6,7,8],go=/^var\(\s*--twd-space-(\d)\s*\)$/,vt=e=>{const t=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());return t?+(parseFloat(t[1])*(t[2]==="rem"?16:1)).toFixed(1):null};function mo(e,t,n){const a=`--twd-${t.key}`,o=document.createElement("div");o.className="role-row",n||o.classList.add("unused"),o.innerHTML=`
863
+ <span class="font-check">${Co}</span>`,w.addEventListener("click",()=>b(h.value)),w});l.append(...d),s.append(i,l);let p=null;function f(h){const w=t.find($=>$.value===h),S=w||a||t[0];p=w?w.value:a?null:t[0].value,i.querySelector(".font-name").textContent=S.name,i.querySelector(".font-fonts").textContent=S.fonts,i.querySelector(".font-aa").style.fontFamily=S.preview,i.setAttribute("aria-label",`${e}: ${S.name}, ${S.fonts}`),d.forEach($=>$.setAttribute("aria-selected",String($.dataset.value===p)))}function v(){const h=i.getBoundingClientRect(),w=l.offsetHeight,$=window.innerHeight-h.bottom-8>=w?h.bottom+4:Math.max(8,h.top-4-w);l.style.top=`${$}px`,l.style.left=`${h.left}px`,l.style.width=`${h.width}px`}function u(){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),s.closest(".body")?.addEventListener("scroll",m,{once:!0}))}function m(h){l.hidden||(l.hidden=!0,i.setAttribute("aria-expanded","false"),document.removeEventListener("pointerdown",x,!0),window.removeEventListener("resize",m),h===!0&&i.focus())}function x(h){h.composedPath().includes(s)||m()}function b(h){h!==p&&(f(h),n(h)),m(!0)}return i.addEventListener("click",()=>l.hidden?u():m(!0)),i.addEventListener("keydown",h=>{(h.key==="ArrowDown"||h.key==="ArrowUp")&&(h.preventDefault(),u())}),l.addEventListener("keydown",h=>{const w=d.indexOf(h.target);let S=null;if(h.key==="ArrowDown")S=Math.min(d.length-1,w+1);else if(h.key==="ArrowUp")S=Math.max(0,w-1);else if(h.key==="Home")S=0;else if(h.key==="End")S=d.length-1;else if(h.key==="Enter"||h.key===" "){h.preventDefault(),b(h.target.dataset.value);return}else if(h.key==="Escape"){h.preventDefault(),h.stopPropagation(),m(!0);return}else if(h.key==="Tab"){m();return}S!==null&&(h.preventDefault(),d[S].focus())}),f(a?null:t[0].value),{el:s,setValue:f}}const D='ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',Ie='Georgia, "Times New Roman", serif',ne=[{value:"neutral",name:"Neutral",fonts:"Inter · Inter",heading:`"Inter", ${D}`,body:`"Inter", ${D}`,load:["Inter:wght@400;500;600;700"]},{value:"modern",name:"Modern",fonts:"Geist · Geist",heading:`"Geist", ${D}`,body:`"Geist", ${D}`,load:["Geist:wght@400;500;600;700"]},{value:"editorial",name:"Editorial",fonts:"Fraunces · Inter",heading:`"Fraunces", ${Ie}`,body:`"Inter", ${D}`,load:["Fraunces:wght@400;600;700","Inter:wght@400;500;600;700"]},{value:"technical",name:"Technical",fonts:"Space Grotesk · DM Sans",heading:`"Space Grotesk", ${D}`,body:`"DM Sans", ${D}`,load:["Space+Grotesk:wght@500;600;700","DM+Sans:wght@400;500;600;700"]},{value:"classic",name:"Classic",fonts:"Playfair · DM Sans",heading:`"Playfair Display", ${Ie}`,body:`"DM Sans", ${D}`,load:["Playfair+Display:wght@600;700","DM+Sans:wght@400;500;600;700"]},{value:"plex",name:"Plex",fonts:"Plex Serif · Plex Sans",heading:`"IBM Plex Serif", ${Ie}`,body:`"IBM Plex Sans", ${D}`,load:["IBM+Plex+Serif:wght@500;600;700","IBM+Plex+Sans:wght@400;500;600"]},{value:"elegant",name:"Elegant",fonts:"Instrument Serif · Inter",heading:`"Instrument Serif", ${Ie}`,body:`"Inter", ${D}`,load:["Instrument+Serif","Inter:wght@400;500;600;700"]},{value:"friendly",name:"Friendly",fonts:"Manrope · Manrope",heading:`"Manrope", ${D}`,body:`"Manrope", ${D}`,load:["Manrope:wght@400;500;600;700"]}],ke={compact:1.125,balanced:1.2,expressive:1.333},On={xs:-2,sm:-1,base:0,lg:1,xl:2,"2xl":3,"3xl":4},jn=new Set;function Lt(e){const t=e.filter(a=>!jn.has(a));if(!t.length)return;t.forEach(a=>jn.add(a));const n=document.createElement("link");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)}const Lo={id:"typography",title:"Typography",hint:"Font pairing · base size · scale",uses:["--twd-font-heading","--twd-font-body",...Object.keys(On).map(e=>`--twd-text-${e}`)],tokens(e){const t=e.typography||{},n={},a=ne.find(o=>o.value===t.font);if(a&&(Lt(a.load),n["--twd-font-heading"]=a.heading,n["--twd-font-body"]=a.body),t.base||t.scale){const o=Number(t.base)||16,r=ke[t.scale]||ke.balanced;Object.entries(On).forEach(([s,i])=>{n[`--twd-text-${s}`]=`${+(o*r**i/16).toFixed(3)}rem`})}return n},parts:{fonts(e,t,{label:n="Fonts"}={}){const a=I(n),o=To({label:"Font pairing",options:ne.map(s=>({value:s.value,name:s.name,fonts:s.fonts,preview:s.heading})),placeholder:{name:"Default",fonts:"Prototype fonts",preview:D},onOpen:()=>Lt([...new Set(ne.flatMap(s=>s.load))]),onSelect:s=>t.setSection("typography",{font:s})});a.append(o.el);const r=()=>o.setValue((t.getState().typography||{}).font||null);r(),t.onChange(r),e.append(a.el)},base(e,t,{label:n="Base size"}={}){e.append(we(t,{section:"typography",key:"base",label:n,fallback:"16",options:["14","15","16"].map(a=>({value:a,label:a})),valueText:a=>`${a}px`}))},fontTiles(e,t,{label:n="Fonts"}={}){const a=i=>i.replace(/"/g,"&quot;"),o=i=>`<span class="tile-aa" style="font-family:${a(i)}">Aa</span>`,r=V(t,{section:"typography",key:"font",label:n,columns:2,className:"tiles-fonts",options:[{value:"default",label:"Prototype fonts",sub:"Default",preview:o(D),wide:!0},...ne.map(i=>({value:i.value,label:i.name,sub:i.fonts,preview:o(i.heading)}))],current:i=>(i.typography||{}).font||"default",select:i=>t.setSection("typography",{font:i==="default"?null:i}),valueText:i=>i==="default"?"Default":ne.find(l=>l.value===i)?.name||""}),s=new IntersectionObserver(i=>{i.some(l=>l.isIntersecting)&&(Lt([...new Set(ne.flatMap(l=>l.load))]),s.disconnect())});s.observe(r),e.append(r)},weights(e,t,{label:n="Weights"}={}){const a=I(n),o=()=>{const r=t.getState(),s=L("--twd-weight-heading"),i=L("--twd-weight-strong");a.setValue(s||i?`Headings ${s||"—"} · strong ${i||"—"}${ue(r,"--twd-weight-heading")?" · from Character":""}`:"")};o(),t.onChange(o),e.append(a.el)},scaleTiles(e,t,{label:n="Scale"}={}){const a=o=>`<span class="ladder">${[-1,0,1,2].map(r=>`<b style="font-size:${Math.round(13*o**r)}px">A</b>`).join("")}</span>`;e.append(V(t,{section:"typography",key:"scale",label:n,fallback:"balanced",options:Object.entries(ke).map(([o,r])=>({value:o,label:o[0].toUpperCase()+o.slice(1),preview:a(r)})),valueText:o=>String(ke[o])}))},scale(e,t,{label:n="Scale"}={}){e.append(we(t,{section:"typography",key:"scale",label:n,fallback:"balanced",options:[{value:"compact",label:"Compact"},{value:"balanced",label:"Balanced"},{value:"expressive",label:"Expressive"}],valueText:a=>String(ke[a])}))}},render(e,t){Object.entries(this.parts).filter(([n])=>!n.endsWith("Tiles")).forEach(([,n])=>n(e,t))}},[Fn,De]=gt;function Ao(e){return e>.56?"Bold":e<.44?"Subtle":"Balanced"}function Po(e){return ve(e,"spacing")?"Custom spacing":bt(q(e.density))}const Be=e=>e&&e[0].toUpperCase()+e.slice(1),Nn=[["colour","Colour",e=>{const t=e.colour||{},n=Oe.find(o=>o.primary===t.primary&&o.neutral===t.neutral);return{text:`${t.brand?t.brand.toUpperCase():n&&!t.shade?n.label:t.primary?`${Be(t.primary)}${t.neutral?` · ${Be(t.neutral)}`:""}`:"Prototype colours"}${t.mode==="dark"?" · Dark":""}`,swatch:L("--twd-primary")}}],["type","Type",e=>{const t=e.typography||{};return{text:`${ne.find(n=>n.value===t.font)?.name||"Prototype fonts"} · ${t.base||16}px`}}],["spacing","Spacing",e=>({text:ve(e,"spacing")?"Custom":bt(q(e.density))})],["shape","Shape",e=>({text:`${Be((e.buttons||{}).corners)||"Default"} corners`})],["shadows","Shadows",e=>({text:Be((e.depth||{}).style)||(Tt(e.character)!==null?"From the pad":"Default")})]],Oo={summary(e,t,{label:n="Current look",goTab:a}={}){const o=I(n),r=document.createElement("div");r.className="summary",Nn.forEach(([i,l])=>{const d=document.createElement("button");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">${P.chevron}</span>`,d.querySelector(".summary-name").textContent=l,d.addEventListener("click",()=>a&&a(i)),r.append(d)}),o.append(r);const s=()=>{const i=t.getState();Nn.forEach(([l,,d])=>{const p=r.querySelector(`[data-summary="${l}"]`),f=d(i);p.querySelector(".summary-value").textContent=f.text;const v=p.querySelector(".summary-swatch");v.hidden=!f.swatch,f.swatch&&(v.style.background=f.swatch)})};s(),t.onChange(s),e.append(o.el)},character(e,t,{label:n="Character"}={}){const a=I(n),o=eo({label:n,ends:{top:"Spacious",bottom:"Compact",left:"Subtle",right:"Bold"},onInput:(s,i)=>{const l=+(De-i*(De-Fn)).toFixed(3),d=+s.toFixed(3);t.setSections({density:{factor:l===1?null:l,spacing:null},character:{bold:d===.5?null:d}},"character")}});a.append(o.el);const r=()=>{const s=t.getState(),i=q(s.density),l=Tt(s.character),d=l===null?.5:l,p=`${Po(s)} · ${Ao(d)}`;o.setValue(d,(De-i)/(De-Fn),p),a.setValue(p)};r(),t.onChange(r),e.append(a.el)}},At=[{key:"page-pad",label:"Page padding",step:5},{key:"section-gap",label:"Section gap",step:6},{key:"card-pad",label:"Card padding",step:5},{key:"card-gap",label:"Card gap",step:2},{key:"control-gap",label:"Control gap",step:3},{key:"control-pad-x",label:"Control padding",step:null}],jo=[1,2,3,4,5,6,7,8],Fo=/^var\(\s*--twd-space-(\d)\s*\)$/,Pt=e=>{const t=/^(-?\d*\.?\d+)(px|rem)?$/.exec(String(e).trim());return t?+(parseFloat(t[1])*(t[2]==="rem"?16:1)).toFixed(1):null};function No(e,t,n){const a=`--twd-${t.key}`,o=document.createElement("div");o.className="role-row",n||o.classList.add("unused"),o.innerHTML=`
800
864
  <span class="role-label" title="${a}${n?"":" (not used on this page)"}">${t.label}</span>
801
865
  <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>
802
866
  <span class="step-select">
803
867
  <select aria-label="${t.label}"></select>
804
- <span class="step-chevron" aria-hidden="true">${A.down}</span>
868
+ <span class="step-chevron" aria-hidden="true">${P.down}</span>
805
869
  </span>
806
- <button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${t.label}" hidden>${A.reset}</button>
807
- `;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=()=>{const x=d();if(x==null)return t.step?{step:t.step}:{fixed:F(a)};const b=go.exec(x);return b?{step:+b[1]}:{fixed:x}},u=x=>e.setSection("custom",{[t.key]:x}),v=x=>t.step?x===`var(--twd-space-${t.step})`:!1;s.addEventListener("change",()=>{if(s.value==="fixed"){const b=vt(F(a));u(b!=null?`${b}px`:F(a)),i.focus(),i.select();return}const x=`var(--twd-space-${s.value})`;u(v(x)?null:x)});const f=()=>{const x=i.value.trim();if(!x)return u(null);u(/^-?\d*\.?\d+$/.test(x)?`${x}px`:x)};i.addEventListener("change",f),i.addEventListener("blur",()=>m()),i.addEventListener("keydown",x=>{x.key==="Enter"&&(x.preventDefault(),i.blur()),x.key==="Escape"&&(x.stopPropagation(),m(),i.blur())}),l.addEventListener("click",()=>u(null));function m(){const x=p();if(s.innerHTML=fo.map(h=>`<option value="${h}">space-${h} · ${vt(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){const h=vt(x.fixed);i.value=h!=null?String(h):x.fixed}const b=d()!=null;o.classList.toggle("edited",b),l.hidden=!b}return m(),e.onChange(m),o}const bo={spacing(e,t,{label:n="Roles"}={}){const a=ja(),o=D(n);o.el.classList.add("token-field");const s=yt.filter(l=>!a.has(`--twd-${l.key}`));o.setValue(s.length===yt.length?"not used on this page":"");const r=document.createElement("div");r.className="token-rows",yt.forEach(l=>r.append(mo(t,l,a.has(`--twd-${l.key}`)))),o.append(r),e.append(o.el);const i=document.createElement("p");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)}},xe=[{id:"overview",title:"Overview",icon:"tabOverview",parts:[["simple","character"],["simple","summary"]]},{id:"colour",title:"Colour",icon:"tabColour",parts:[["colour","themeTiles"],{heading:"Fine-tune",note:"Tailwind palette"},["colour","primary"],["colour","neutralTiles"],["colour","custom"],["colour","mode"],"warnings",{more:"Colour tokens",parts:[["custom","colours"]]}]},{id:"type",title:"Type",icon:"tabType",parts:[["typography","fontTiles"],["typography","base"],["typography","scaleTiles"],{more:"Type tokens",parts:[["custom","fonts"],["custom","type"],["custom","leading"],["custom","weights"]]}]},{id:"spacing",title:"Spacing",icon:"tabSpacing",parts:[["density","spacingTiles"],{more:"Layout roles",parts:[["roles","spacing"]]},{more:"Spacing tokens",parts:[["custom","spacing"]]}]},{id:"shape",title:"Shape",icon:"tabShape",parts:[{heading:"Buttons"},["buttons","styleTiles",{label:"Style"}],["buttons","cornerTiles",{label:"Corners"}],["buttons","sizeTiles",{label:"Size"}],{heading:"Cards"},["cards","styleTiles",{label:"Style"}],["cards","cornerTiles",{label:"Corners"}],["cards","borderTiles",{label:"Borders"}],{more:"Shape tokens",parts:[["custom","buttonStyle"],["custom","cardStyle"],["custom","cardShadow"],["custom","corners"],["custom","controls"],["custom","borders"]]}]},{id:"shadows",title:"Shadows",icon:"tabShadows",parts:[["depth","styleTiles"],["depth","intensity"],{more:"Shadow tokens",parts:[["custom","shadows"]]}]}],O=e=>String(e).replace(/[&<>"]/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[t]);function xo({sections:e,store:t,view:n}){const a=document.createElement("div");a.id="twiddle-root",document.body.appendChild(a);const o=a.attachShadow({mode:"open"}),s=c=>c.map(g=>`
808
- <details data-section="${g.id}">
809
- <summary>${g.title}<span class="chev">${A.chevron}</span></summary>
810
- <div class="section-body"><div class="placeholder">${g.hint}</div></div>
811
- </details>
812
- `).join("");o.innerHTML=`
813
- <style>${pa}</style>
870
+ <button class="icon-btn token-reset" title="Back to the default" aria-label="Reset ${t.label}" hidden>${P.reset}</button>
871
+ `;const r=o.querySelector("select"),s=o.querySelector(".role-fixed"),i=s.querySelector("input"),l=o.querySelector(".token-reset"),d=()=>(e.getState().custom||{})[t.key],p=()=>{const x=d();if(x==null)return t.step?{step:t.step}:{fixed:L(a)};const b=Fo.exec(x);return b?{step:+b[1]}:{fixed:x}},f=x=>e.setSection("custom",{[t.key]:x}),v=x=>t.step?x===`var(--twd-space-${t.step})`:!1;r.addEventListener("change",()=>{if(r.value==="fixed"){const b=Pt(L(a));f(b!=null?`${b}px`:L(a)),i.focus(),i.select();return}const x=`var(--twd-space-${r.value})`;f(v(x)?null:x)});const u=()=>{const x=i.value.trim();if(!x)return f(null);f(/^-?\d*\.?\d+$/.test(x)?`${x}px`:x)};i.addEventListener("change",u),i.addEventListener("blur",()=>m()),i.addEventListener("keydown",x=>{x.key==="Enter"&&(x.preventDefault(),i.blur()),x.key==="Escape"&&(x.stopPropagation(),m(),i.blur())}),l.addEventListener("click",()=>f(null));function m(){const x=p();if(r.innerHTML=jo.map(h=>`<option value="${h}">space-${h} · ${Pt(L(`--twd-space-${h}`))??"?"}</option>`).join("")+'<option value="fixed">Fixed</option>',r.value=x.step?String(x.step):"fixed",s.hidden=!x.fixed,o.classList.toggle("is-fixed",!!x.fixed),x.fixed&&o.getRootNode().activeElement!==i){const h=Pt(x.fixed);i.value=h!=null?String(h):x.fixed}const b=d()!=null;o.classList.toggle("edited",b),l.hidden=!b}return m(),e.onChange(m),o}const Ro={spacing(e,t,{label:n="Roles"}={}){const a=Ja(),o=I(n);o.el.classList.add("token-field");const r=At.filter(l=>!a.has(`--twd-${l.key}`));o.setValue(r.length===At.length?"not used on this page":"");const s=document.createElement("div");s.className="token-rows",At.forEach(l=>s.append(No(t,l,a.has(`--twd-${l.key}`)))),o.append(s),e.append(o.el);const i=document.createElement("p");i.className="role-note",i.textContent=r.length?`Only elements styled with these tokens change. Not used on this page: ${r.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)}},ae=[{id:"overview",title:"Overview",icon:"tabOverview",parts:[["simple","character"],["simple","summary"]]},{id:"colour",title:"Colour",icon:"tabColour",parts:[["colour","themeTiles"],{heading:"Fine-tune",note:"Tailwind palette"},["colour","primary"],["colour","neutralTiles"],["colour","custom"],["colour","mode"],"warnings",{more:"Colour tokens",parts:[["custom","colours"]]}]},{id:"type",title:"Type",icon:"tabType",parts:[["typography","fontTiles"],["typography","base"],["typography","scaleTiles"],["typography","weights"],{more:"Type tokens",parts:[["custom","fonts"],["custom","type"],["custom","leading"],["custom","weights"]]}]},{id:"spacing",title:"Spacing",icon:"tabSpacing",parts:[["density","spacingTiles"],{more:"Layout roles",parts:[["roles","spacing"]]},{more:"Spacing tokens",parts:[["custom","spacing"]]}]},{id:"shape",title:"Shape",icon:"tabShape",parts:[{tabs:[{label:"Buttons & Inputs",parts:[["buttons","styleTiles",{label:"Style"}],["buttons","cornerTiles",{label:"Corners"}],["buttons","sizeTiles",{label:"Size"}]]},{label:"Cards",parts:[["cards","styleTiles",{label:"Style"}],["cards","cornerTiles",{label:"Corners"}],["cards","borderTiles",{label:"Borders"}]]}]},{more:"Shape tokens",parts:[["custom","buttonStyle"],["custom","cardStyle"],["custom","cardShadow"],["custom","corners"],["custom","controls"],["custom","borders"]]}]},{id:"shadows",title:"Shadows",icon:"tabShadows",parts:[["depth","styleTiles"],["depth","intensity"],{more:"Shadow tokens",parts:[["custom","shadows"]]}]}],j=e=>String(e).replace(/[&<>"]/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[t]);function zo({sections:e,store:t,view:n}){const a=document.createElement("div");a.id="twiddle-root",document.body.appendChild(a);const o=a.attachShadow({mode:"open"});o.innerHTML=`
872
+ <style>${Ta}</style>
814
873
  <div class="pick-box" hidden><span class="pick-tag"></span></div>
815
874
  <div class="wrap">
816
875
  <div class="toast" role="status"></div>
876
+ <section class="side" aria-label="Changes" hidden>
877
+ <div class="side-head"><span>Changes</span><button class="icon-btn" data-action="changes-close" title="Close Changes" aria-label="Close Changes">${P.close}</button></div>
878
+ <div class="body" data-view="changes"></div>
879
+ </section>
817
880
  <div class="panel" role="dialog" aria-label="Panel" hidden>
818
- <div class="head">
819
- <span class="brand">Panel</span>
820
- <button class="icon-btn" data-action="pick" title="Pick an element to tweak on its own" aria-label="Pick an element" aria-pressed="false">${A.pick}</button>
821
- <button class="icon-btn" data-action="compare" title="Hold to see the original (Alt+C toggles)" aria-label="Compare with original" aria-pressed="false">${A.compare}</button>
822
- <button class="icon-btn" data-action="copy" title="Copy link to this version" aria-label="Copy link">${A.link}</button>
823
- <button class="icon-btn" data-action="reset" title="Reset to defaults" aria-label="Reset">${A.reset}</button>
824
- <button class="icon-btn" data-action="minimise" title="Minimise to the tabs" aria-label="Minimise to the tabs">${A.minimise}</button>
825
- <button class="icon-btn" data-action="close" title="Close (Alt+T)" aria-label="Close">${A.close}</button>
881
+ <nav class="tabbar" aria-label="Areas">
882
+ ${ae.map(c=>`<button class="tab" data-tab="${c.id}" title="${c.title}" aria-pressed="false">${P[c.icon]}<span>${c.title}</span></button>`).join("")}
883
+ <button class="icon-btn tab-min" data-action="minimise" title="Minimise to the tabs" aria-label="Minimise to the tabs">${P.minimise}</button>
884
+ </nav>
885
+ <div class="original-pill" hidden>Showing original</div>
886
+ <div class="body" data-view="global"><div class="setup-hint" role="status" hidden></div>
887
+ ${ae.map(c=>`<div class="page page-fields" data-page="${c.id}" hidden></div>`).join("")}
826
888
  </div>
889
+ <div class="body" data-view="local" hidden></div>
890
+ <!-- One footer row with every action (Ravi, 2026-10-16); the launcher closes the panel. -->
827
891
  <div class="actions">
828
- <button class="icon-btn" data-action="undo" title="Undo (⌘Z)" aria-label="Undo">${A.undo}</button>
829
- <button class="icon-btn" data-action="redo" title="Redo (⇧⌘Z)" aria-label="Redo">${A.redo}</button>
830
- <button class="text-btn" data-action="changes" aria-pressed="false">Changes <span class="badge" hidden></span></button>
892
+ <button class="icon-btn" data-action="undo" title="Undo (⌘Z)" aria-label="Undo">${P.undo}</button>
893
+ <button class="icon-btn" data-action="redo" title="Redo (⇧⌘Z)" aria-label="Redo">${P.redo}</button>
894
+ <span class="sep" aria-hidden="true"></span>
895
+ <button class="icon-btn" data-action="pick" title="Pick an element to tweak on its own" aria-label="Pick an element" aria-pressed="false">${P.pick}</button>
896
+ <button class="icon-btn" data-action="compare" title="Hold to see the original (Alt+C toggles)" aria-label="Compare with original" aria-pressed="false">${P.compare}</button>
897
+ <button class="icon-btn" data-action="copy" title="Copy link to this version" aria-label="Copy link">${P.link}</button>
898
+ <button class="icon-btn" data-action="reset" title="Reset to defaults" aria-label="Reset">${P.reset}</button>
899
+ <span class="sep" aria-hidden="true"></span>
900
+ <button class="changes-btn" data-action="changes" title="Changes" aria-label="Changes" aria-pressed="false"><span class="badge">0</span></button>
831
901
  <span class="spacer"></span>
832
902
  <div class="apply">
833
- <button class="apply-btn" data-action="apply" title="Copy these tweaks as a prompt for your coding agent">Copy prompt</button>
834
- <button class="apply-menu-btn" data-action="apply-menu" aria-label="Copy prompt options" aria-haspopup="true" aria-expanded="false">${A.down}</button>
903
+ <button class="apply-btn" data-action="apply" title="Copy these tweaks as a prompt for your coding agent">Copy<span class="wide"> prompt</span></button>
904
+ <button class="apply-menu-btn" data-action="apply-menu" aria-label="Copy prompt options" aria-haspopup="true" aria-expanded="false">${P.down}</button>
835
905
  <div class="menu apply-menu" role="menu" hidden>
836
906
  <button role="menuitemradio" data-apply-mode="preview">Preview before copying</button>
837
907
  <button role="menuitemradio" data-apply-mode="copy">Copy without preview</button>
838
908
  </div>
839
909
  </div>
840
910
  </div>
841
- <div class="original-pill" hidden>Showing original</div>
842
- <div class="body" data-view="global"><div class="setup-hint" role="status" hidden></div>
843
- ${xe.map(c=>`<div class="page page-fields" data-page="${c.id}" hidden></div>`).join("")}
844
- </div>
845
- <div class="body" data-view="local" hidden></div>
846
- <div class="body" data-view="changes" hidden></div>
847
- <nav class="tabbar" aria-label="Areas">
848
- ${xe.map(c=>`<button class="tab" data-tab="${c.id}" aria-pressed="false">${A[c.icon]}<span>${c.title}</span></button>`).join("")}
849
- </nav>
850
911
  </div>
851
- <button class="launcher" aria-label="Open Panel" aria-expanded="false" title="Panel · drag to move, double-click to reset">${A.panelMark}</button>
912
+ <button class="launcher" aria-label="Open Panel" aria-expanded="false" title="Panel · drag to move, double-click to reset">${P.panelMark}</button>
852
913
  </div>
853
914
  <div class="dialog-backdrop" hidden>
854
915
  <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="twd-dialog-title">
855
916
  <div class="dialog-head">
856
917
  <span id="twd-dialog-title">Prompt for your agent</span>
857
- <button class="icon-btn" data-action="dialog-close" aria-label="Close">${A.close}</button>
918
+ <button class="icon-btn" data-action="dialog-close" aria-label="Close">${P.close}</button>
858
919
  </div>
859
920
  <textarea class="prompt-text" readonly spellcheck="false" aria-label="Generated prompt"></textarea>
860
921
  <div class="dialog-foot">
@@ -863,43 +924,44 @@ ${Object.entries(r).map(([i,l])=>` ${i}: ${l} !important;`).join(`
863
924
  </div>
864
925
  </div>
865
926
  </div>
866
- `;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};function m(c,g,w){g.forEach(k=>{if(typeof k.render!="function")return;const C=c.querySelector(`[data-section="${k.id}"] .section-body`);C.innerHTML="",k.render(C,w)});const $=[...c.querySelectorAll("details")];return $.forEach(k=>k.addEventListener("toggle",()=>{k.open&&$.forEach(C=>{C!==k&&(C.open=!1)})})),$}const x=Object.fromEntries(e.map(c=>[c.id,c]));function b(c,g){g.forEach(w=>{if(w==="warnings"){const S=document.createElement("div");S.className="warnings page-warnings",c.append(S);return}if(w.heading){const S=document.createElement("div");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);return}if(w.more){const S=document.createElement("details");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);return}if(w.tabs){const S=w.tabs.map(j=>{const I=document.createElement("div");return I.className="tab-pane",b(I,j.parts),I}),$e=re({label:"View",options:w.tabs.map((j,I)=>({value:String(I),label:j.label})),onSelect:j=>{$e.setValue(j),S.forEach((I,Oo)=>{I.hidden=String(Oo)!==j})}});$e.setValue("0"),S.forEach((j,I)=>{j.hidden=I!==0}),c.append($e.el,...S);return}const[$,k,C={}]=w,q=$==="simple"?ho[k]:$==="roles"?bo[k]:x[$]?.parts?.[k];q&&q(c,f,{...C,buttons:x.buttons,cards:x.cards,goTab:S=>{J("global"),E(S)}})})}xe.forEach(c=>b(p.global.querySelector(`[data-page="${c.id}"]`),c.parts));const h=[...o.querySelectorAll(".tab")];let y=xe.some(c=>c.id===W("tab"))?W("tab"):xe[0].id;function P(){h.forEach(c=>c.setAttribute("aria-pressed",String(Z==="global"&&c.dataset.tab===y)))}function E(c){y=c,ne("tab",c),p.global.querySelectorAll(".page").forEach(g=>{g.hidden=g.dataset.page!==c}),p.global.scrollTop=0,P()}const de=c=>c.map(g=>`<div class="warning">${A.warn}<span>${O(g.text)}</span></div>`).join("");let Z="global";function J(c){Z=c,Object.entries(p).forEach(([g,w])=>{w.hidden=g!==c}),r('[data-action="changes"]').setAttribute("aria-pressed",String(c==="changes")),c!=="local"&&Co(),c==="changes"&&Bn(),P()}E(y);const kt="cubic-bezier(0.3, 0.7, 0.2, 1)",St="cubic-bezier(0.2, 0.8, 0.2, 1)",ze=640,we=100,$t=50,ko=()=>l.querySelector(".mark-knob"),So=()=>[l.querySelector(".mark-t1"),l.querySelector(".mark-t2")];function kn(c){if(matchMedia("(prefers-reduced-motion: reduce)").matches||!l.animate)return;const g=ko(),[w,$]=So(),k=C=>`translateY(${C}px)`;if(c){g.animate([{transform:k(32)},{transform:k(-6),offset:.78},{transform:k(0)}],{duration:ze,easing:kt});const C=[{transform:"scale(0.4)",opacity:0},{transform:"scale(1)",opacity:1}];$.animate(C,{duration:we*2,delay:ze*.12,easing:kt,fill:"backwards"}),w.animate(C,{duration:we*2,delay:ze*.32+$t,easing:kt,fill:"backwards"})}else{const C=[{opacity:1},{opacity:0}];w.animate(C,{duration:we,easing:St}),$.animate(C,{duration:we,delay:$t/2,easing:St,fill:"backwards"}),g.animate([{transform:k(0)},{transform:k(34),offset:.8},{transform:k(32)}],{duration:ze*.7,delay:we+$t/2,easing:St,fill:"backwards"})}}const Et=r(".wrap"),Sn=fa({wrapEl:Et,launcherEl:l});let $n=!1;function Ie(c){$n=c,i.classList.toggle("minimised",c),i.hidden||ne("panel",c?"tabs":"open")}function Q({animate:c=!0}={}){i.hidden&&c&&kn(!0),i.hidden=!1,Et.classList.add("is-open"),l.setAttribute("aria-expanded","true"),l.setAttribute("aria-label","Close Panel"),Ie(!1)}function $o(){i.hidden&&Q(),Ie(!0)}function Ct(){i.hidden||kn(!1),i.hidden=!0,Et.classList.remove("is-open"),l.setAttribute("aria-expanded","false"),l.setAttribute("aria-label","Open Panel"),ne("panel","closed"),Be()}function De(){i.hidden?Q():Ct()}let En;function V(c){d.textContent=c,d.classList.add("show"),clearTimeout(En),En=setTimeout(()=>d.classList.remove("show"),1600)}function ye(c,g){navigator.clipboard.writeText(c).then(()=>V(g)).catch(()=>V("Couldn’t copy — select the text and copy it instead"))}let Mt=null;function ce(c,g){if(Mt=c,!c){u.hidden=!0;return}const w=c.getBoundingClientRect();Object.assign(u.style,{top:`${w.top}px`,left:`${w.left}px`,width:`${w.width}px`,height:`${w.height}px`}),v.textContent=g||tt(c),u.hidden=!1}const Cn=()=>{Mt&&!u.hidden&&ce(Mt,v.textContent)};window.addEventListener("scroll",Cn,!0),window.addEventListener("resize",Cn);let ve=!1;const Mn=r('[data-action="pick"]'),Tn=c=>c.composedPath().includes(a);function An(c){if(Tn(c))return;const g=c.target;g&&g.nodeType===1&&g!==document.documentElement&&g!==document.body&&ce(g)}function Ln(c){if(Tn(c)||(c.preventDefault(),c.stopPropagation(),c.type!=="click"))return;const g=c.target;!g||g===document.documentElement||g===document.body||(Be(),Nn(g))}function Pn(c){c.key==="Escape"&&(c.preventDefault(),Be(),T&&ce(T.el))}const On=["pointerdown","mousedown","mouseup","click"];function Fn(){if(!ve){if(ve=!0,!document.getElementById("twiddle-picking")){const c=document.createElement("style");c.id="twiddle-picking",c.textContent="html.twd-picking, html.twd-picking * { cursor: crosshair !important; }",document.head.appendChild(c)}Q(),Mn.setAttribute("aria-pressed","true"),document.documentElement.classList.add("twd-picking"),document.addEventListener("pointermove",An,!0),On.forEach(c=>document.addEventListener(c,Ln,!0)),document.addEventListener("keydown",Pn,!0),V("Click an element · Esc to cancel")}}function Be(){ve&&(ve=!1,Mn.setAttribute("aria-pressed","false"),document.documentElement.classList.remove("twd-picking"),document.removeEventListener("pointermove",An,!0),On.forEach(c=>document.removeEventListener(c,Ln,!0)),document.removeEventListener("keydown",Pn,!0),ce(T?T.el:null))}let T=null;function Eo(c,g){const w=[];return{ctx:{getState:()=>(t.getState().scopes||{})[c]||{},setSection:($,k)=>t.setScope(c,$,k),onChange:$=>{const k=t.onChange($);return w.push(k),k},readToken:$=>getComputedStyle(g).getPropertyValue($).trim()},dispose:()=>w.forEach($=>$())}}function Nn(c,g){const w=ya(c),$=t.getState().scopes||{};g||(g=!$[w.elementSelector]&&w.classSelector&&$[w.classSelector]?"class":"element"),T&&T.dispose(),T={el:c,info:w,target:g,dispose:()=>{}},Tt(),J("local"),Q(),ce(c)}const jn=()=>T.target==="class"?T.info.classSelector:T.info.elementSelector;function Tt(){T.dispose();const{info:c}=T,g=e.filter(j=>(j.uses||[]).some(I=>c.tokens.has(I))),w=p.local;if(w.innerHTML=`
927
+ `;const r=c=>o.querySelector(c),s=r(".panel"),i=r(".launcher"),l=r(".toast"),d={global:r('[data-view="global"]'),local:r('[data-view="local"]'),changes:r('[data-view="changes"]')},p=r(".pick-box"),f=r(".pick-tag"),v={getState:t.getState,setSection:t.setSection,setSections:t.setSections,onChange:t.onChange},u=Object.fromEntries(e.map(c=>[c.id,c]));function m(c,g,y=v){const C=y!==v;g.forEach(k=>{if(k==="warnings"){if(C)return;const F=document.createElement("div");F.className="warnings page-warnings",c.append(F);return}if(k.heading){const F=document.createElement("div");F.className="page-heading",F.innerHTML=`<span></span>${k.note?'<span class="muted"></span>':""}`,F.firstChild.textContent=k.heading,k.note&&(F.lastChild.textContent=k.note),c.append(F);return}if(k.more){const F=document.createElement("details");F.className="more",F.innerHTML=`<summary><span class="chev" aria-hidden="true">${P.chevron}</span><span></span></summary><div class="more-body"></div>`,F.querySelector("summary span:last-child").textContent=k.more,m(F.querySelector(".more-body"),k.parts,y),c.append(F);return}if(k.tabs){const F=k.tabs.map(X=>{const _=document.createElement("div");return _.className="tab-pane",m(_,X.parts,y),_}),Ut=ce({label:"View",options:k.tabs.map((X,_)=>({value:String(_),label:X.label})),onSelect:X=>{Ut.setValue(X),F.forEach((_,Zo)=>{_.hidden=String(Zo)!==X})}});Ut.setValue("0"),F.forEach((X,_)=>{X.hidden=_!==0}),c.append(Ut.el,...F);return}const[T,U,O={}]=k,Te=T==="simple"?Oo[U]:T==="roles"?Ro[U]:u[T]?.parts?.[U];Te&&Te(c,y,{...O,buttons:u.buttons,cards:u.cards,goTab:F=>{Ve(zn()),w(F)}})})}ae.forEach(c=>m(d.global.querySelector(`[data-page="${c.id}"]`),c.parts));const x=[...o.querySelectorAll(".tab")];let b=ae.some(c=>c.id===Q("tab"))?Q("tab"):ae[0].id;function h(){x.forEach(c=>c.setAttribute("aria-pressed",String(c.dataset.tab===b)))}function w(c){b=c,ie("tab",c),[d.global,d.local].forEach(g=>{g.querySelectorAll(".page").forEach(y=>{y.hidden=y.dataset.page!==c}),g.scrollTop=0}),h()}const S=c=>c.map(g=>`<div class="warning">${P.warn}<span>${j(g.text)}</span></div>`).join(""),$=r(".side");let Y=!1;function oe(c){Y=c&&!s.hidden,$.hidden=!Y,r('[data-action="changes"]').setAttribute("aria-pressed",String(Y)),Y&&ta()}let Ue="global";const zn=()=>E?"local":"global";function Ve(c){Ue=c,Object.entries(d).forEach(([g,y])=>{y.hidden=g!==c}),h()}w(b);const Ot="cubic-bezier(0.3, 0.7, 0.2, 1)",jt="cubic-bezier(0.2, 0.8, 0.2, 1)",qe=640,Se=100,Ft=50,Bo=()=>i.querySelector(".mark-knob"),Uo=()=>[i.querySelector(".mark-t1"),i.querySelector(".mark-t2")];function In(c){if(matchMedia("(prefers-reduced-motion: reduce)").matches||!i.animate)return;const g=Bo(),[y,C]=Uo(),k=T=>`translateY(${T}px)`;if(c){g.animate([{transform:k(32)},{transform:k(-6),offset:.78},{transform:k(0)}],{duration:qe,easing:Ot});const T=[{transform:"scale(0.4)",opacity:0},{transform:"scale(1)",opacity:1}];C.animate(T,{duration:Se*2,delay:qe*.12,easing:Ot,fill:"backwards"}),y.animate(T,{duration:Se*2,delay:qe*.32+Ft,easing:Ot,fill:"backwards"})}else{const T=[{opacity:1},{opacity:0}];y.animate(T,{duration:Se,easing:jt}),C.animate(T,{duration:Se,delay:Ft/2,easing:jt,fill:"backwards"}),g.animate([{transform:k(0)},{transform:k(34),offset:.8},{transform:k(32)}],{duration:qe*.7,delay:Se+Ft/2,easing:jt,fill:"backwards"})}}const He=r(".wrap"),Dn=Pa({wrapEl:He,launcherEl:i});let Nt=!1;function $e(c){Nt=c,s.classList.toggle("minimised",c),c&&oe(!1),He.classList.toggle("is-min",c);const g=r('[data-action="minimise"]');g.title=c?"Expand the panel":"Minimise to the tabs",g.setAttribute("aria-label",g.title),s.hidden||ie("panel",c?"tabs":"open")}function re({animate:c=!0}={}){s.hidden&&c&&In(!0),s.hidden=!1,He.classList.add("is-open"),i.setAttribute("aria-expanded","true"),i.setAttribute("aria-label","Close Panel"),$e(!1)}function Vo(){s.hidden&&re(),$e(!0)}function Rt(){s.hidden||In(!1),s.hidden=!0,He.classList.remove("is-open","is-min"),oe(!1),i.setAttribute("aria-expanded","false"),i.setAttribute("aria-label","Open Panel"),ie("panel","closed"),Ge()}function _e(){s.hidden?re():Rt()}let Bn;function H(c){l.textContent=c,l.classList.add("show"),clearTimeout(Bn),Bn=setTimeout(()=>l.classList.remove("show"),1600)}function Ee(c,g){navigator.clipboard.writeText(c).then(()=>H(g)).catch(()=>H("Couldn’t copy — select the text and copy it instead"))}let zt=null;function he(c,g){if(zt=c,!c){p.hidden=!0;return}const y=c.getBoundingClientRect();Object.assign(p.style,{top:`${y.top}px`,left:`${y.left}px`,width:`${y.width}px`,height:`${y.height}px`}),f.textContent=g||dt(c),p.hidden=!1}const Un=()=>{zt&&!p.hidden&&he(zt,f.textContent)};window.addEventListener("scroll",Un,!0),window.addEventListener("resize",Un);let fe=!1;const Ke=r('[data-action="pick"]'),Vn=c=>c.composedPath().includes(a);function qn(c){if(Vn(c))return;const g=c.target;g&&g.nodeType===1&&g!==document.documentElement&&g!==document.body&&he(g)}function Hn(c){if(Vn(c)||(c.preventDefault(),c.stopPropagation(),c.type!=="click"))return;const g=c.target;!g||g===document.documentElement||g===document.body||(Ge(),Gn(g))}function _n(c){c.key==="Escape"&&(c.preventDefault(),Ge(),E&&he(E.el),We())}const Kn=["pointerdown","mousedown","mouseup","click"];function Wn(){if(!fe){if(fe=!0,!document.getElementById("twiddle-picking")){const c=document.createElement("style");c.id="twiddle-picking",c.textContent="html.twd-picking, html.twd-picking * { cursor: crosshair !important; }",document.head.appendChild(c)}re(),Ke.setAttribute("aria-pressed","true"),document.documentElement.classList.add("twd-picking"),document.addEventListener("pointermove",qn,!0),Kn.forEach(c=>document.addEventListener(c,Hn,!0)),document.addEventListener("keydown",_n,!0),H("Click an element · Esc to cancel")}}function We(){const c=fe||!!E;Ke.setAttribute("aria-pressed",String(c));const g=c?"Leave selection mode":"Pick an element to tweak on its own";Ke.title=g,Ke.setAttribute("aria-label",c?"Leave selection mode":"Pick an element")}function Ge(){fe&&(fe=!1,We(),document.documentElement.classList.remove("twd-picking"),document.removeEventListener("pointermove",qn,!0),Kn.forEach(c=>document.removeEventListener(c,Hn,!0)),document.removeEventListener("keydown",_n,!0),he(E?E.el:null))}let E=null;function qo(c,g){const y=[];return{ctx:{getState:()=>(t.getState().scopes||{})[c]||{},setSection:(C,k)=>t.setScope(c,C,k),setSections:(C,k)=>t.setScopeSections(c,C,k),onChange:C=>{const k=t.onChange(C);return y.push(k),k},readToken:C=>getComputedStyle(g).getPropertyValue(C).trim()},dispose:()=>y.forEach(C=>C())}}function Gn(c,g){const y=za(c),C=t.getState().scopes||{};g||(g=!C[y.elementSelector]&&y.classSelector&&C[y.classSelector]?"class":"element"),E&&E.dispose(),E={el:c,info:y,target:g,dispose:()=>{}},It(),Ve("local"),re(),he(c),We(),Bt()}const Yn=()=>E.target==="class"?E.info.classSelector:E.info.elementSelector;function It(){E.dispose();const{info:c}=E,g=d.local;if(g.innerHTML=`
867
928
  <div class="scope-bar">
868
929
  <div class="scope-head">
869
- <button class="icon-btn" data-action="back" title="Back to the whole page" aria-label="Back to the whole page">${A.back}</button>
930
+ <button class="icon-btn" data-action="back" title="Leave selection mode" aria-label="Leave selection mode">${P.back}</button>
870
931
  <div class="scope-name">
871
- <code>${O(tt(c.el))}</code>
872
- ${c.text?`<span class="muted">“${O(c.text)}”</span>`:""}
932
+ <code>${j(dt(c.el))}</code>
933
+ ${c.text?`<span class="muted">“${j(c.text)}”</span>`:""}
873
934
  </div>
874
935
  </div>
875
936
  <div class="scope-target"></div>
937
+ ${c.tokens.size?"":'<div class="scope-note">This element doesn’t use Panel tokens yet, so changes here won’t show. Style it with <code>var(--twd-…)</code> to make it tweakable.</div>'}
876
938
  <div class="warnings"></div>
877
939
  </div>
878
- ${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>'}
879
- `,c.classSelector){const j=re({label:"Apply to",options:[{value:"element",label:"This element"},{value:"class",label:`All ${c.classSelector} (${c.classCount})`,title:`Every element matching ${c.classSelector}`}],onSelect:I=>{I==="class"&&t.moveScope(c.elementSelector,c.classSelector),T.target=I,Tt()}});j.setValue(T.target),w.querySelector(".scope-target").append(j.el)}const{ctx:$,dispose:k}=Eo(jn(),c.el),C=m(w,g,$);C[0]&&(C[0].open=!0);const q=w.querySelector(".warnings"),S=()=>{const j=c.tokens.size?Aa(c.el):null;q.innerHTML=j?de([j]):""};S();const $e=t.onChange(S);T.dispose=()=>{k(),$e()}}function Rn(){if(!T||!T.info.classSelector)return;const c=t.getState().scopes||{},g=T.target==="class"?"element":"class",w=g==="class"?T.info.classSelector:T.info.elementSelector;!c[jn()]&&c[w]&&(T.target=g,Tt())}const zn=()=>{t.undo(),Rn()},In=()=>{t.redo(),Rn()};function Co(){T&&(T.dispose(),T=null,p.local.innerHTML="",ce(null))}const Dn=c=>c.kind==="global"?"Whole page":c.kind==="class"?`All ${c.selector}`:"One element";function Bn(){const c=Gt(t.getState(),e),g=rt(),w=p.changes;if(!c.length){w.innerHTML=`<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${de(g)}`;return}const $=new Map;c.forEach(k=>{const C=k.selector||"";$.has(C)||$.set(C,[]),$.get(C).push(k)}),w.innerHTML=(g.length?`<div class="warnings">${de(g)}</div>`:"")+[...$].map(([k,C])=>`
940
+ ${ae.map(O=>`<div class="page page-fields" data-page="${O.id}"${O.id===b?"":" hidden"}></div>`).join("")}
941
+ `,c.classSelector){const O=ce({label:"Apply to",options:[{value:"element",label:"This element"},{value:"class",label:`All ${c.classSelector} (${c.classCount})`,title:`Every element matching ${c.classSelector}`}],onSelect:Te=>{Te==="class"&&t.moveScope(c.elementSelector,c.classSelector),E.target=Te,It()}});O.setValue(E.target),g.querySelector(".scope-target").append(O.el)}const{ctx:y,dispose:C}=qo(Yn(),c.el);ae.forEach(O=>m(g.querySelector(`[data-page="${O.id}"]`),O.parts,y));const k=g.querySelector(".warnings"),T=()=>{const O=c.tokens.size?Ka(c.el):null;k.innerHTML=O?S([O]):""};T();const U=t.onChange(T);E.dispose=()=>{C(),U()}}function Xn(){if(!E||!E.info.classSelector)return;const c=t.getState().scopes||{},g=E.target==="class"?"element":"class",y=g==="class"?E.info.classSelector:E.info.elementSelector;!c[Yn()]&&c[y]&&(E.target=g,It())}const Zn=()=>{t.undo(),Xn()},Jn=()=>{t.redo(),Xn()};function Qn(){E&&(E.dispose(),E=null,d.local.innerHTML="",he(null),We(),Ue==="local"&&Ve("global"))}const ea=c=>c.kind==="global"?"Whole page":c.kind==="class"?`All ${c.selector}`:"One element";function ta(){const c=ln(t.getState(),e),g=ht(),y=d.changes;if(!c.length){y.innerHTML=`<div class="empty">No changes yet. Tweak a section, or pick an element to change it on its own.</div>${S(g)}`;return}const C=new Map;c.forEach(k=>{const T=k.selector||"";C.has(T)||C.set(T,[]),C.get(T).push(k)}),y.innerHTML=(g.length?`<div class="warnings">${S(g)}</div>`:"")+[...C].map(([k,T])=>`
880
942
  <div class="change-group">
881
943
  <div class="change-scope">
882
- ${k?`<button class="link-btn" data-select="${O(k)}" title="Select it on the page">${O(Dn(C[0]))}</button><code>${O(k)}</code>`:`<span>${Dn(C[0])}</span>`}
944
+ ${k?`<button class="link-btn" data-select="${j(k)}" title="Select it on the page">${j(ea(T[0]))}</button><code>${j(k)}</code>`:`<span>${ea(T[0])}</span>`}
883
945
  </div>
884
- ${C.map(q=>`
946
+ ${T.map(U=>`
885
947
  <div class="change-row">
886
948
  <div class="change-main">
887
- <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>
888
- ${q.tokens.map(S=>`<div class="change-token"><code>${O(S.name)}</code> ${S.from?`${O(S.from)} → `:""}${O(S.to)}</div>`).join("")}
949
+ <div class="change-title">${j(U.title)} <span class="muted">›</span> ${U.settings.map(O=>`${j(O.label)}: <b>${j(O.value)}</b>`).join(", ")}</div>
950
+ ${U.tokens.map(O=>`<div class="change-token"><code>${j(O.name)}</code> ${O.from?`${j(O.from)} → `:""}${j(O.to)}</div>`).join("")}
889
951
  </div>
890
- <button class="icon-btn" data-remove="${O(q.sectionId)}" data-remove-scope="${O(k)}" aria-label="Remove ${O(q.title)} change">${A.close}</button>
952
+ <button class="icon-btn" data-remove="${j(U.sectionId)}" data-remove-scope="${j(k)}" aria-label="Remove ${j(U.title)} change">${P.close}</button>
891
953
  </div>`).join("")}
892
- </div>`).join("")}function Mo(c,g){if(g)return t.removeScope(g,c);const w=t.getState()[c]||{};t.setSection(c,Object.fromEntries(Object.keys(w).map($=>[$,null])))}const ke=r(".apply-menu"),Un=r('[data-action="apply-menu"]'),qn=()=>W("apply-mode")==="copy"?"copy":"preview";function To(){ke.querySelectorAll("[data-apply-mode]").forEach(c=>c.setAttribute("aria-checked",String(c.dataset.applyMode===qn())))}function Ue(c){ke.hidden=!c,Un.setAttribute("aria-expanded",String(c)),c&&To()}function Hn(){return Ea(Gt(t.getState(),e),{warnings:rt()})}const qe=r(".dialog-backdrop"),Vn=r(".prompt-text");function Ao(){const c=Hn();if(!c)return V("No changes to copy yet");if(qn()==="copy")return ye(c,"Prompt copied · paste it into your agent");Vn.value=c,qe.hidden=!1,r('[data-action="dialog-copy"]').focus()}function At(){qe.hidden=!0,r('[data-action="apply"]').focus()}const pe=r('[data-action="compare"]'),Lo=r(".original-pill");function He(c){c?n.suspend():n.resume(),pe.setAttribute("aria-pressed",String(c)),Lo.hidden=!c}let _n=null,Se=!1;pe.addEventListener("pointerdown",()=>{Se=!1,_n=setTimeout(()=>{Se=!0,He(!0)},180)});const Kn=()=>{clearTimeout(_n),Se&&(He(!1),Se=!1)};pe.addEventListener("pointerup",Kn),pe.addEventListener("pointerleave",Kn);const Ve=r(".setup-hint"),Wn=`setup-hint-dismissed:${location.pathname}`,Po={"no-tokens":{title:"The Panel tokens aren’t loaded",text:"The knobs change the --twd-* variables, but this page doesn’t load them. Add the token stylesheet before your own CSS:",snippets:an,link:`${nn}/#install`},unused:{title:"Nothing here uses the Panel tokens yet",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:",copy:"Copy prompt for your agent",copied:"Prompt copied",text2copy:Ra,link:`${nn}/#tokens`}};let B=null;function _e(){const c=Na();B=W(Wn)===c?null:Po[c]||null,l.toggleAttribute("data-hint",!!B),Ve.hidden=!B,B&&(Ve.innerHTML=`
893
- <div class="setup-head">${A.warn}<b>${O(B.title)}</b>
894
- <button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${A.close}</button>
954
+ </div>`).join("")}function Ho(c,g){if(g)return t.removeScope(g,c);const y=t.getState()[c]||{};t.setSection(c,Object.fromEntries(Object.keys(y).map(C=>[C,null])))}const Ce=r(".apply-menu"),na=r('[data-action="apply-menu"]'),aa=()=>Q("apply-mode")==="copy"?"copy":"preview";function _o(){Ce.querySelectorAll("[data-apply-mode]").forEach(c=>c.setAttribute("aria-checked",String(c.dataset.applyMode===aa())))}function Ye(c){Ce.hidden=!c,na.setAttribute("aria-expanded",String(c)),c&&_o()}function oa(){return Va(ln(t.getState(),e),{warnings:ht()})}const Xe=r(".dialog-backdrop"),ra=r(".prompt-text");function Ko(){const c=oa();if(!c)return H("No changes to copy yet");if(aa()==="copy")return Ee(c,"Prompt copied · paste it into your agent");ra.value=c,Xe.hidden=!1,r('[data-action="dialog-copy"]').focus()}function Dt(){Xe.hidden=!0,r('[data-action="apply"]').focus()}const ge=r('[data-action="compare"]'),Wo=r(".original-pill");function Ze(c){c?n.suspend():n.resume(),ge.setAttribute("aria-pressed",String(c)),Wo.hidden=!c}let sa=null,Me=!1;ge.addEventListener("pointerdown",()=>{Me=!1,sa=setTimeout(()=>{Me=!0,Ze(!0)},180)});const ia=()=>{clearTimeout(sa),Me&&(Ze(!1),Me=!1)};ge.addEventListener("pointerup",ia),ge.addEventListener("pointerleave",ia);const Je=r(".setup-hint"),la=`setup-hint-dismissed:${location.pathname}`,Go={"no-tokens":{title:"The Panel tokens aren’t loaded",text:"The knobs change the --twd-* variables, but this page doesn’t load them. Add the token stylesheet before your own CSS:",snippets:bn,link:`${mn}/#install`},unused:{title:"Nothing here uses the Panel tokens yet",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:",copy:"Copy prompt for your agent",copied:"Prompt copied",text2copy:Qa,link:`${mn}/#tokens`}};let B=null;function Qe(){const c=Za();B=Q(la)===c?null:Go[c]||null,i.toggleAttribute("data-hint",!!B),Je.hidden=!B,B&&(Je.innerHTML=`
955
+ <div class="setup-head">${P.warn}<b>${j(B.title)}</b>
956
+ <button class="icon-btn" data-action="setup-dismiss" title="Hide this message" aria-label="Hide this message">${P.close}</button>
895
957
  </div>
896
- <p>${O(B.text)}</p>
897
- ${(B.snippets||[]).map((g,w)=>`
958
+ <p>${j(B.text)}</p>
959
+ ${(B.snippets||[]).map((g,y)=>`
898
960
  <div class="setup-snippet">
899
- <span>${O(g.label)}</span>
900
- <div class="setup-code"><code>${O(g.code)}</code><button class="text-btn" data-setup-snippet="${w}">Copy</button></div>
961
+ <span>${j(g.label)}</span>
962
+ <div class="setup-code"><code>${j(g.code)}</code><button class="text-btn" data-setup-snippet="${y}">Copy</button></div>
901
963
  </div>`).join("")}
902
964
  <div class="setup-actions">
903
- ${B.copy?`<button class="apply-btn" data-action="setup-copy">${O(B.copy)}</button>`:""}
965
+ ${B.copy?`<button class="apply-btn" data-action="setup-copy">${j(B.copy)}</button>`:""}
904
966
  <a href="${B.link}" target="_blank" rel="noopener">Setup guide</a>
905
- </div>`,Ve.dataset.status=c)}_e(),document.readyState!=="complete"&&window.addEventListener("load",_e,{once:!0}),setTimeout(_e,1500);const Gn=r(".badge");function Yn(){r('[data-action="undo"]').disabled=!t.canUndo(),r('[data-action="redo"]').disabled=!t.canRedo();const c=Sa(t.getState());Gn.textContent=c,Gn.hidden=!c;const g=de(rt());p.global.querySelectorAll(".page-warnings").forEach(w=>{w.innerHTML=g}),Z==="changes"&&Bn()}return t.onChange(Yn),Yn(),o.addEventListener("click",c=>{if(c.target===qe)return At();const g=c.target.closest("button");if(g){if(g!==Un&&!ke.contains(g)&&Ue(!1),g===l)return Sn.consumeClick()?void 0:c.detail===2?(De(),Sn.reset(),V("Panel moved back to the corner")):De();if(g.dataset.select){const w=document.querySelector(g.dataset.select);return w?Nn(w):V("That element isn’t on this page")}if(g.dataset.setupSnippet)return ye(an[g.dataset.setupSnippet].code,"Copied");if(g.dataset.tab)return J("global"),$n&&Ie(!1),E(g.dataset.tab);if(g.dataset.remove)return Mo(g.dataset.remove,g.dataset.removeScope);if(g.dataset.applyMode)return ne("apply-mode",g.dataset.applyMode),Ue(!1),V(g.dataset.applyMode==="copy"?"Copy prompt copies straight away":"Copy prompt shows a preview first");switch(g.dataset.action){case"close":return Ct();case"minimise":return $o(),(o.querySelector('.tab[aria-pressed="true"]')||h[0]).focus();case"reset":return t.resetState(),V("Reset to defaults · ⌘Z to undo");case"copy":return ye(location.href,"Link copied");case"pick":return ve?Be():Fn();case"compare":Se||He(pe.getAttribute("aria-pressed")!=="true");return;case"undo":return zn();case"redo":return In();case"back":return J("global");case"changes":return J(Z==="changes"?"global":"changes");case"apply":return Ao();case"apply-menu":return Ue(ke.hidden);case"dialog-close":return At();case"dialog-copy":return ye(Vn.value,"Prompt copied · paste it into your agent");case"setup-copy":return B&&ye(B.text2copy,B.copied);case"setup-dismiss":return ne(Wn,Ve.dataset.status),_e()}}}),o.addEventListener("keydown",c=>{if(c.key==="Escape"){if(!qe.hidden)return At();if(!ke.hidden)return Ue(!1)}!(c.metaKey||c.ctrlKey)||c.key.toLowerCase()!=="z"||c.target.matches?.('input[type="text"], textarea')||(c.preventDefault(),c.shiftKey?In():zn())}),document.addEventListener("keydown",c=>{c.altKey&&(c.code==="KeyT"&&(c.preventDefault(),De()),c.code==="KeyC"&&(c.preventDefault(),He(pe.getAttribute("aria-pressed")!=="true")))}),W("panel")==="open"?Q({animate:!1}):W("panel")==="tabs"&&(Q({animate:!1}),Ie(!0)),{open:Q,close:Ct,toggle:De,toast:V,pick:Fn,prompt:Hn}}const vn=[po,Le,fn,ft,_a,mt,ro,Va],wo=':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)}';function yo(){if(getComputedStyle(document.documentElement).getPropertyValue("--twd-radius-control").trim()||document.getElementById("twiddle-tokens"))return;const t=document.createElement("style");t.id="twiddle-tokens",t.textContent=wo,document.head.prepend(t)}if(!window.Twiddle){yo(),vn.forEach(n=>ra(n.tokens)),jt(Qe);let e;const t=()=>{Qe(Ye()),e=xo({sections:vn,store:oa,view:{suspend:da,resume:ca}})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t):t(),window.Twiddle={open:()=>e&&e.open(),close:()=>e&&e.close(),toggle:()=>e&&e.toggle(),reset:()=>Ot(),undo:()=>Ft(),redo:()=>Nt(),pick:()=>e&&e.pick(),prompt:()=>e?e.prompt():"",getState:Ye}}const vo=window.Twiddle;return Ke.Twiddle=vo,Object.defineProperty(Ke,Symbol.toStringTag,{value:"Module"}),Ke})({});
967
+ </div>`,Je.dataset.status=c)}Qe(),document.readyState!=="complete"&&window.addEventListener("load",Qe,{once:!0}),setTimeout(Qe,1500);const Yo={"--pv-primary":"--twd-primary","--pv-on-primary":"--twd-on-primary","--pv-radius-control":"--twd-radius-control","--pv-radius-container":"--twd-radius-container"};function Bt(){[[d.global,document.documentElement],[d.local,E&&E.info.el]].forEach(([c,g])=>{if(!g)return;const y=getComputedStyle(g);Object.entries(Yo).forEach(([C,k])=>{const T=y.getPropertyValue(k).trim();T?c.style.setProperty(C,T):c.style.removeProperty(C)})})}t.onChange(()=>requestAnimationFrame(Bt)),Bt();const Xo=r(".badge");function da(){r('[data-action="undo"]').disabled=!t.canUndo(),r('[data-action="redo"]').disabled=!t.canRedo();const c=Ba(t.getState());Xo.textContent=c,r('[data-action="changes"]').classList.toggle("has-changes",c>0),r('[data-action="changes"]').setAttribute("aria-label",`Changes (${c})`);const g=S(ht());d.global.querySelectorAll(".page-warnings").forEach(y=>{y.innerHTML=g}),Y&&ta()}return t.onChange(da),da(),o.addEventListener("click",c=>{if(c.target===Xe)return Dt();const g=c.target.closest("button");if(g){if(g!==na&&!Ce.contains(g)&&Ye(!1),g===i)return Dn.consumeClick()?void 0:c.detail===2?(_e(),Dn.reset(),H("Panel moved back to the corner")):_e();if(g.dataset.select){const y=document.querySelector(g.dataset.select);return y?Gn(y):H("That element isn’t on this page")}if(g.dataset.setupSnippet)return Ee(bn[g.dataset.setupSnippet].code,"Copied");if(g.dataset.tab)return Ve(zn()),Nt&&$e(!1),w(g.dataset.tab);if(g.dataset.remove)return Ho(g.dataset.remove,g.dataset.removeScope);if(g.dataset.applyMode)return ie("apply-mode",g.dataset.applyMode),Ye(!1),H(g.dataset.applyMode==="copy"?"Copy prompt copies straight away":"Copy prompt shows a preview first");switch(g.dataset.action){case"close":return Rt();case"minimise":return Nt?$e(!1):(Vo(),(o.querySelector('.tab[aria-pressed="true"]')||x[0]).focus());case"reset":return t.resetState(),H("Reset to defaults · ⌘Z to undo");case"copy":return Ee(location.href,"Link copied");case"pick":return fe||E?(Ge(),Qn()):Wn();case"compare":Me||Ze(ge.getAttribute("aria-pressed")!=="true");return;case"undo":return Zn();case"redo":return Jn();case"back":return Qn();case"changes":return oe(!Y);case"changes-close":return oe(!1);case"apply":return Ko();case"apply-menu":return Ye(Ce.hidden);case"dialog-close":return Dt();case"dialog-copy":return Ee(ra.value,"Prompt copied · paste it into your agent");case"setup-copy":return B&&Ee(B.text2copy,B.copied);case"setup-dismiss":return ie(la,Je.dataset.status),Qe()}}}),o.addEventListener("keydown",c=>{if(c.key==="Escape"){if(!Xe.hidden)return Dt();if(!Ce.hidden)return Ye(!1)}!(c.metaKey||c.ctrlKey)||c.key.toLowerCase()!=="z"||c.target.matches?.('input[type="text"], textarea')||(c.preventDefault(),c.shiftKey?Jn():Zn())}),document.addEventListener("keydown",c=>{c.altKey&&(c.code==="KeyT"&&(c.preventDefault(),_e()),c.code==="KeyC"&&(c.preventDefault(),Ze(ge.getAttribute("aria-pressed")!=="true")))}),Q("panel")==="open"?re({animate:!1}):Q("panel")==="tabs"&&(re({animate:!1}),$e(!0)),{open:re,close:Rt,toggle:_e,toast:H,pick:Wn,prompt:oa}}const Rn=[Lo,je,Ln,$t,co,Ct,Pn,lo];function Io(){if(getComputedStyle(document.documentElement).getPropertyValue("--twd-radius-control").trim()||document.getElementById("twiddle-tokens"))return;const t=document.createElement("style");t.id="twiddle-tokens",t.textContent=Gt,document.head.prepend(t)}if(!window.Twiddle){Io(),Rn.forEach(n=>ka(n.tokens)),Wt(it);let e;const t=()=>{it(at()),e=zo({sections:Rn,store:wa,view:{suspend:Ca,resume:Ma}})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t):t(),window.Twiddle={open:()=>e&&e.open(),close:()=>e&&e.close(),toggle:()=>e&&e.toggle(),reset:()=>Ht(),undo:()=>_t(),redo:()=>Kt(),pick:()=>e&&e.pick(),prompt:()=>e?e.prompt():"",getState:at}}const Do=window.Twiddle;return et.Twiddle=Do,Object.defineProperty(et,Symbol.toStringTag,{value:"Module"}),et})({});