dsh-motion-ui 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -36,7 +36,7 @@ __export(client_exports, {
36
36
  inject: () => inject
37
37
  });
38
38
  module.exports = __toCommonJS(client_exports);
39
- var import_react24 = __toESM(require("react"), 1);
39
+ var import_react26 = __toESM(require("react"), 1);
40
40
 
41
41
  // src/expressive-controls.js
42
42
  var import_react2 = __toESM(require("react"), 1);
@@ -45,6 +45,13 @@ var import_react2 = __toESM(require("react"), 1);
45
45
  var import_react = __toESM(require("react"), 1);
46
46
  var h = import_react.default.createElement;
47
47
  var paths = {
48
+ play: ["m8 4 12 8-12 8V4Z"],
49
+ pause: ["M7 4h3v16H7zM14 4h3v16h-3z"],
50
+ volume: ["M11 4 5 9H2v6h3l6 5V4Z", "M15 8a6 6 0 0 1 0 8M18 4a11 11 0 0 1 0 16"],
51
+ volumeOff: ["M11 4 5 9H2v6h3l6 5V4Z", "m16 9 6 6m0-6-6 6"],
52
+ fullscreen: ["M8 3H3v5m13-5h5v5M3 16v5h5m13-5v5h-5"],
53
+ minimize: ["M3 8h5V3m8 0v5h5M8 21v-5H3m13 5v-5h5"],
54
+ download: ["M12 3v12m-5-5 5 5 5-5M4 17v4h16v-4"],
48
55
  copy: ["M9 8h11v13H9z", "M15 8V3H4v13h5"],
49
56
  external: ["M14 4h6v6M20 4l-9 9", "M10 4H4v16h16v-6"],
50
57
  file: ["M14 3H5v18h14V8l-5-5Z", "M14 3v5h5M8 13h8M8 17h5"],
@@ -359,6 +366,78 @@ svg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);s
359
366
  @media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}
360
367
  @media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;
361
368
 
369
+ // lib/timeline.js
370
+ function createTimelineAPI(animate, capture = false, notify = () => {
371
+ }) {
372
+ const timelines = /* @__PURE__ */ new Map();
373
+ function timeline(options) {
374
+ const { id: id2 = "main", duration, draw, loop = false, autoplay = true, chapters = [] } = options ?? {};
375
+ if (typeof id2 !== "string" || !/^[A-Za-z_][\w-]{0,63}$/.test(id2) || timelines.has(id2)) throw Error("Timeline id must be unique");
376
+ if (!Number.isFinite(duration) || duration <= 0 || duration > 86400 || typeof draw !== "function") throw Error("Timeline requires positive duration and draw(time, info)");
377
+ if (!Array.isArray(chapters) || chapters.length > 100 || chapters.some((c) => !c || typeof c.label !== "string" || !Number.isFinite(c.time) || c.time < 0 || c.time >= duration)) throw Error("Invalid timeline chapters");
378
+ let time = 0, playing = !!autoplay && !capture, disposed = false, reduced = false, visible = true;
379
+ const listeners4 = /* @__PURE__ */ new Set();
380
+ const state2 = () => ({ id: id2, time, duration, playing, loop: !!loop, reducedMotion: reduced, visible, chapters: chapters.map((c) => ({ time: c.time, label: c.label })) });
381
+ const render = () => {
382
+ draw(time, state2());
383
+ notify(state2());
384
+ for (const fn2 of listeners4) fn2(state2());
385
+ };
386
+ const seek = (value) => {
387
+ if (disposed) throw Error("Timeline disposed");
388
+ if (!Number.isFinite(value)) throw Error("Timeline seek requires finite seconds");
389
+ time = Math.max(0, Math.min(duration, value));
390
+ render();
391
+ return state2();
392
+ };
393
+ const api = Object.freeze({ state: state2, seek, play() {
394
+ if (disposed) throw Error("Timeline disposed");
395
+ playing = true;
396
+ render();
397
+ }, pause() {
398
+ playing = false;
399
+ render();
400
+ }, replay() {
401
+ playing = !capture;
402
+ seek(0);
403
+ }, chapter(index) {
404
+ if (!Number.isInteger(index) || !chapters[index]) throw Error("Invalid chapter");
405
+ playing = false;
406
+ return seek(chapters[index].time);
407
+ }, subscribe(fn2) {
408
+ if (typeof fn2 !== "function") throw Error("Timeline listener required");
409
+ listeners4.add(fn2);
410
+ fn2(state2());
411
+ return () => listeners4.delete(fn2);
412
+ }, dispose() {
413
+ if (disposed) return;
414
+ disposed = true;
415
+ stop();
416
+ listeners4.clear();
417
+ timelines.delete(id2);
418
+ } });
419
+ timelines.set(id2, api);
420
+ const stop = animate((info) => {
421
+ reduced = !!info.reducedMotion;
422
+ visible = info.visible !== false;
423
+ if (!capture && playing && !reduced && visible) {
424
+ const next = time + info.delta;
425
+ time = loop ? next % duration : Math.min(duration, next);
426
+ if (!loop && time === duration) playing = false;
427
+ }
428
+ render();
429
+ });
430
+ return api;
431
+ }
432
+ return { timeline, capture: Object.freeze({ list: () => [...timelines.values()].map((t) => t.state()), seek: (id2, time) => {
433
+ const t = timelines.get(id2);
434
+ if (!t) throw Error("Timeline not found: " + id2);
435
+ t.seek(time);
436
+ t.pause();
437
+ return t.state();
438
+ } }) };
439
+ }
440
+
362
441
  // lib/sandbox.js
363
442
  var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });
364
443
  function canvasSnapshot(node, state2, data, derived, disabled, theme) {
@@ -385,13 +464,15 @@ function sandboxDocument(node, channel, nonce) {
385
464
  const animations=new Set(), motion=matchMedia('(prefers-reduced-motion: reduce)');
386
465
  let raf=0,last=0,time=0;
387
466
  const visible=()=>snapshot.visible!==false&&!document.hidden;
388
- const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;
467
+ const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches&&!window.__DSHMotionRender;
389
468
  const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};
390
469
  const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};
391
470
  const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};
392
471
  motion.addEventListener('change',refresh);document.addEventListener('visibilitychange',refresh);
393
472
  const formatNumber=${formatNumber.toString()};
394
473
  const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!=='function')throw Error('Listener required');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send('patch',patch)},animate(fn){if(typeof fn!=='function')throw Error('Animation callback required');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};
474
+ let soundTick=0,soundPlaying,soundTime,soundVisible;const timelineAPI=(${createTimelineAPI.toString()})(api.animate,!!window.__DSHMotionRender,s=>{if(snapshot.motionSound){const now=performance.now();if(now-soundTick>=100||s.playing!==soundPlaying||s.visible!==soundVisible||(!s.playing&&s.time!==soundTime)){soundTick=now;soundPlaying=s.playing;soundTime=s.time;soundVisible=s.visible;send('timeline',s)}}});api.timeline=timelineAPI.timeline;
475
+ Object.defineProperty(window,'__DSHMotionCapture',{value:timelineAPI.capture,writable:false});
395
476
  ${node.libraries?.includes("mechanism") ? MECHANISM_RUNTIME.replace(/<\/script/gi, "<\\/script") + ";api.mechanism=__MotionMechanism.createMechanismAPI(api);" : ""}
396
477
  Object.defineProperty(window,'DSHUI',{value:Object.freeze(api),writable:false});
397
478
  for(const type of ['click','input','change','keydown','pointerdown'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);
@@ -3569,15 +3650,15 @@ function CanvasPreview({ node }) {
3569
3650
  var import_react8 = __toESM(require("react"), 1);
3570
3651
 
3571
3652
  // lib/export-runtime-bundle.js
3572
- var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target", "external", "file", "globe"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/mechanism-runtime-bundle.js\n var MECHANISM_RUNTIME = \'var __MotionMechanism=(()=>{var it=Object.defineProperty;var Ot=Object.getOwnPropertyDescriptor;var Et=Object.getOwnPropertyNames;var It=Object.prototype.hasOwnProperty;var zt=(t,a)=>{for(var n in a)it(t,n,{get:a[n],enumerable:!0})},Pt=(t,a,n,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let e of Et(a))!It.call(t,e)&&e!==n&&it(t,e,{get:()=>a[e],enumerable:!(o=Ot(a,e))||o.enumerable});return t};var _t=t=>Pt(it({},"__esModule",{value:!0}),t);var Tt={};zt(Tt,{createMechanismAPI:()=>Ft});var st=Math.PI/180,Ct=Math.sqrt(1.6);function yt({scale:t,azimuth:a=45,elevation:n=30}){let o=a*st,e=n*st;return{sinA:Math.sin(o),cosA:Math.cos(o),sinE:Math.sin(e),cosE:Math.cos(e),k:t*Ct}}function q([t,a,n],o){let{origin:e}=o,{sinA:i,cosA:r,sinE:p,cosE:d,k:m}=yt(o);return[e[0]+(t*i-a*r)*m,e[1]+((t*r+a*i)*p-n*d)*m]}function tt([t,a,n],o){let{sinA:e,cosA:i,sinE:r,cosE:p}=yt(o);return(t*i+a*e)*p+n*r}function vt({x:t,y:a,w:n,d:o,r:e},i=8){let r=Math.max(0,Math.min(e,n/2,o/2)),p=[[t+n-r,a+r,-90],[t+n-r,a+o-r,0],[t+r,a+o-r,90],[t+r,a+r,180]],d=[];for(let[m,s,c]of p){let u=r>0?i:0;for(let f=0;f<=u;f++){let g=(c+(u?90*f/u:45))*st;d.push([m+r*Math.cos(g),s+r*Math.sin(g)])}}return d}function lt(t,a,n,o=40){return Array.from({length:o},(e,i)=>{let r=i/o*Math.PI*2;return[t+n*Math.cos(r),a+n*Math.sin(r)]})}function ct(t,a,n,{pad:o=24,headroom:e=0,azimuth:i=45,elevation:r=30}={}){let p={origin:[0,0],scale:1,azimuth:i,elevation:r},d=t.map(M=>q(M,p)),m=d.map(([M])=>M),s=d.map(([,M])=>M),c=Math.min(...m),u=Math.max(...m),f=Math.min(...s),g=Math.max(...s),h=Math.min((a-o*2)/(u-c),(n-o*2-e)/(g-f));return{origin:[a/2-(c+u)/2*h,e+(n-e)/2-(f+g)/2*h],scale:h,azimuth:i,elevation:r}}var Nt=Object.freeze({parts:96,teeth:64,faces:8192}),Ht=t=>typeof t=="number"&&Number.isFinite(t),y=t=>{throw Error("Motion mechanism: "+t)},v=(t,a,n=-1e4,o=1e4)=>((!Ht(t)||t<n||t>o)&&y(a+" must be a finite number in "+n+".."+o),t),U=(t,a)=>((!Array.isArray(t)||t.length!==3)&&y(a+" must be [x,y,z]"),t.map((n,o)=>v(n,a+"["+o+"]"))),et=t=>typeof t=="string"&&/^[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}$/u.test(t)&&!["constructor","prototype","__proto__"].includes(t),kt=["box","cylinder","gear","rod","spring"],I=(t,a)=>t.map((n,o)=>n+a[o]),B=(t,a)=>t.map((n,o)=>n-a[o]),_=(t,a)=>t.map(n=>n*a),dt=(t,a)=>t.reduce((n,o,e)=>n+o*a[e],0),V=(t,a)=>[t[1]*a[2]-t[2]*a[1],t[2]*a[0]-t[0]*a[2],t[0]*a[1]-t[1]*a[0]],J=t=>{let a=Math.hypot(...t);return a<1e-6&&y("zero-length axis"),_(t,1/a)};function Y(t){(!t||typeof t!="object"||Array.isArray(t))&&y("scene must be an object"),(!Array.isArray(t.parts)||!t.parts.length||t.parts.length>Nt.parts)&&y("parts requires 1..96 objects");let a=new Set,n=new Set;for(let[o,e]of t.parts.entries()){let i="parts["+o+"]";(!e||typeof e!="object"||!et(e.id)||a.has(e.id))&&y(i+".id must be a unique identifier"),a.add(e.id),kt.includes(e.type)||y(i+".type must be "+kt.join("/")),e.group!==void 0&&(et(e.group)||y(i+".group must be an identifier"),n.add(e.group));for(let r of["label","description"])e[r]!==void 0&&(typeof e[r]!="string"||e[r].length>1024)&&y(i+"."+r+" must be short text");if(e.cover!==void 0&&typeof e.cover!="boolean"&&y(i+".cover must be boolean"),e.material!==void 0&&!["metal","dark","accent","warm","cool"].includes(e.material)&&y(i+".material must be metal/dark/accent/warm/cool"),e.at!==void 0&&U(e.at,i+".at"),e.explode!==void 0&&U(e.explode,i+".explode"),e.rotation!==void 0&&v(e.rotation,i+".rotation",-1e9,1e9),e.axis!==void 0&&!["x","y","z"].includes(e.axis)&&y(i+".axis must be x/y/z"),e.type==="box"){let r=U(e.size,i+".size");r.some(p=>p<=0||p>2e3)&&y(i+".size must be positive and <=2000"),e.round!==void 0&&v(e.round,i+".round",0,Math.min(r[0],r[1])/2)}if(["cylinder","gear"].includes(e.type)&&(v(e.radius,i+".radius",.1,1e3),v(e.height??8,i+".height",.1,1e3),e.inner!==void 0&&v(e.inner,i+".inner",0,e.radius-.01)),e.type==="gear"){let r=v(e.teeth,i+".teeth",6,64);Number.isInteger(r)||y(i+".teeth must be an integer"),e.module!==void 0&&v(e.module,i+".module",.1,e.radius/3)}if(["rod","spring"].includes(e.type)&&(U(e.from,i+".from"),U(e.to,i+".to"),Math.hypot(...B(e.to,e.from))<.1&&y(i+" endpoints must differ"),v(e.radius??2,i+".radius",.1,200)),e.type==="spring"){let r=v(e.turns??8,i+".turns",2,24);Number.isInteger(r)||y(i+".turns must be integer")}}if(t.groups!==void 0){(!Array.isArray(t.groups)||t.groups.length>12)&&y("groups must be an array of <=12 labels");let o=new Set;for(let e of t.groups)(!e||!et(e.id)||o.has(e.id)||!n.has(e.id)||typeof e.label!="string"||e.label.length>128)&&y("groups must name unique existing part groups"),o.add(e.id)}if(t.bounds!==void 0){(!Array.isArray(t.bounds)||t.bounds.length!==2)&&y("bounds must be [minXYZ,maxXYZ]");let[o,e]=t.bounds.map((i,r)=>U(i,"bounds["+r+"]"));o.some((i,r)=>i>=e[r])&&y("bounds min must be below max on every axis")}if(t.azimuth!==void 0&&v(t.azimuth,"azimuth",10,80),t.elevation!==void 0&&v(t.elevation,"elevation",15,70),t.title!==void 0&&(typeof t.title!="string"||t.title.length>256)&&y("title must be short text"),t.bind!==void 0){(!t.bind||typeof t.bind!="object"||Array.isArray(t.bind))&&y("bind must be an object");for(let[o,e]of Object.entries(t.bind))(!["explode","selected","cutaway"].includes(o)||!et(e))&&y("bind only accepts declared state keys for explode/selected/cutaway")}return t}function Lt(t){return t==="x"?[[0,1,0],[0,0,1],[1,0,0]]:t==="y"?[[0,0,1],[1,0,0],[0,1,0]]:[[1,0,0],[0,1,0],[0,0,1]]}var at=(t,a,n,o)=>I(I(_(t[0],a),_(t[1],n)),_(t[2],o));function Rt(t,a,n,o){let e=t.map(([m,s])=>at(n,m,s,-a/2)),i=t.map(([m,s])=>at(n,m,s,a/2)),r=[],p=o?.map(([m,s])=>at(n,m,s,a/2)),d=o?.map(([m,s])=>at(n,m,s,-a/2));r.push({points:i,holes:p?[p.slice().reverse()]:[],normal:n[2]},{points:e.slice().reverse(),holes:d?[d]:[],normal:_(n[2],-1)});for(let m=0;m<t.length;m++){let s=(m+1)%t.length;Math.hypot(...B(e[s],e[m]))<1e-6||(r.push({points:[e[m],e[s],i[s],i[m]],normal:J(V(B(e[s],e[m]),n[2]))}),o&&r.push({points:[d[s],d[m],p[m],p[s]],normal:J(V(B(d[m],d[s]),n[2]))}))}return r}function ot(t){let a=Lt(t.axis),n,o,e;if(t.type==="box"&&(n=vt({x:-t.size[0]/2,y:-t.size[1]/2,w:t.size[0],d:t.size[1],r:t.round??Math.min(2,t.size[0]/2,t.size[1]/2)},3),o=t.size[2]),t.type==="cylinder"&&(n=lt(0,0,t.radius,24),o=t.height??8),t.type==="gear"){let s=Math.PI*2/t.teeth,c=t.module??t.radius*2/t.teeth;n=[];for(let u=0;u<t.teeth;u++)for(let[f,g]of[[-.5,t.radius-c*.85],[-.32,t.radius-c*.85],[-.17,t.radius+c*.7],[.17,t.radius+c*.7],[.32,t.radius-c*.85]]){let h=(u+f)*s;n.push([Math.cos(h)*g,Math.sin(h)*g])}o=t.height??8}if(t.type==="rod"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0]));a=[c,V(s,c),s],n=lt(0,0,t.radius??2,16),o=Math.hypot(...B(t.to,t.from))}if(t.type==="spring"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0])),u=V(s,c),f=[];for(let g=0;g<=128;g++){let h=g/128,M=h*(t.turns??8)*Math.PI*2,O=Math.min(1,h*12,(1-h)*12);f.push(I(I(t.from,_(B(t.to,t.from),h)),I(_(c,Math.cos(M)*(t.radius??6)*O),_(u,Math.sin(M)*(t.radius??6)*O))))}return{line:f,points:f}}let i=t.rotation??0,r=Math.cos(i),p=Math.sin(i);n=n.map(([s,c])=>[s*r-c*p,s*p+c*r]);let d=t.inner?n.map(([s,c])=>{let u=Math.atan2(c,s);return[Math.cos(u)*t.inner,Math.sin(u)*t.inner]}):void 0;e=Rt(n,o,a,d);let m=t.type==="rod"?_(I(t.from,t.to),.5):t.at??[0,0,0];return e=e.map(s=>({...s,points:s.points.map(c=>I(c,m)),holes:s.holes?.map(c=>c.map(u=>I(u,m)))})),{faces:e,points:e.flatMap(s=>s.points)}}function wt(t){if(t.bounds){let[a,n]=t.bounds;return Array.from({length:8},(o,e)=>[e&1?n[0]:a[0],e&2?n[1]:a[1],e&4?n[2]:a[2]])}return t.parts.flatMap(a=>ot(a).points.flatMap(o=>[o,I(o,a.explode??[0,0,0])]))}function W({driverTeeth:t=16,drivenTeeth:a=32,rpm:n=30,angle:o=0,module:e=2}={}){for(let[i,r]of Object.entries({driverTeeth:t,drivenTeeth:a}))(!Number.isInteger(r)||r<6||r>64)&&y(i+" must be integer 6..64");return v(n,"rpm",-600,600),v(o,"angle",-1e9,1e9),v(e,"module",.1,10),{driverRadius:t*e/2,drivenRadius:a*e/2,centerDistance:(t+a)*e/2,driverAngle:o,drivenAngle:-o*t/a+Math.PI-Math.PI/a,driverRpm:n,drivenRpm:-n*t/a,ratio:a/t}}function X({angle:t=0,radius:a=20,rod:n=70,z:o=20}={}){v(t,"angle",-1e9,1e9),v(a,"radius",.1,200),v(n,"rod",.1,1e3),v(o,"z"),n<=a&&y("connecting rod length must exceed crank radius");let e=[a*Math.cos(t),a*Math.sin(t),o],i=e[0]+Math.sqrt(n*n-e[1]*e[1]);return{crank:e,piston:[i,0,o],position:i,stroke:a*2,angle:t}}function Mt(t,a,n,o=.16){return v(t,"value",-1e9,1e9),v(a,"target",-1e9,1e9),v(n,"delta",0,.1),v(o,"tau",.01,10),t+(a-t)*(1-Math.exp(-n/o))}var $t=Math.PI*2;function nt(t,a){Y(t);let n=a&&!t.bounds?t.parts.filter(o=>!a.cutaway||!o.cover).flatMap(o=>ot(o).points.map(e=>I(e,_(o.explode??[0,0,0],a.explode??0)))):wt(t);return ct(n.length?n:[[0,0,0],[1,1,1]],600,340,{pad:24,azimuth:t.azimuth??45,elevation:t.elevation??30})}var At=t=>t.map(([a,n],o)=>(o?"L":"M")+Math.round(a*10)/10+" "+Math.round(n*10)/10).join("")+"Z";function mt(t,a,{explode:n=0,selected:o="all",cutaway:e=!1,pose:i={}}={},r=new Map){if(typeof n!="number"||!Number.isFinite(n)||n<0||n>1)throw Error("Motion mechanism: explode must be 0..1");if(typeof o!="string"||typeof e!="boolean")throw Error("Motion mechanism: selected must be text and cutaway boolean");if(!i||typeof i!="object"||Array.isArray(i))throw Error("Motion mechanism: pose must be an object");for(let c of Object.keys(i))if(!t.parts.some(u=>u.id===c))throw Error("Motion mechanism: unknown pose part "+c);let p=(a.azimuth??45)*$t/360,d=(a.elevation??30)*$t/360,m=[Math.cos(p)*Math.cos(d),Math.sin(p)*Math.cos(d),Math.sin(d)],s=[];for(let c of t.parts){if(e&&c.cover)continue;let u=i[c.id]??{};for(let $ of Object.keys(u))if(!["at","rotation","from","to"].includes($))throw Error("Motion mechanism: unsupported pose field "+$);let f={...c,...u},g=JSON.stringify(f),h=r.get(c.id);h?.key!==g&&(Y({parts:[f]}),h={key:g,...ot(f)},r.set(c.id,h));let M=_(f.explode??[0,0,0],n),O=Math.min(...h.points.map($=>$[2]))+M[2],N=o==="all"||o===c.id||o===c.group;if(h.line){let $=h.line.map(P=>I(P,M));s.push({floor:O,key:f.id+"_line",part:f.id,group:f.group,d:$.map((P,A)=>(A?"L":"M")+q(P,a).join(" ")).join(""),depth:tt($[Math.floor($.length/2)],a),line:!0,tone:1,material:f.material??"metal",active:N});continue}for(let[$,P]of h.faces.entries()){if(dt(P.normal,m)<=1e-4)continue;let w=P.points.map(S=>I(S,M)),T=P.holes?.map(S=>S.map(H=>I(H,M))),D=_(w.reduce((S,H)=>I(S,H),[0,0,0]),1/w.length),G=dt(P.normal,[-.25,-.4,.88]);s.push({floor:O,key:f.id+"_"+$,part:f.id,group:f.group,d:At(w.map(S=>q(S,a)))+(T??[]).map(S=>At(S.map(H=>q(H,a)))).join(""),depth:tt(D,a),line:!1,tone:G>.5?0:G>.1?1:G>-.4?2:3,material:f.material??"metal",active:N})}}if(s.length>8192)throw Error("Motion mechanism: face budget exceeded");return s.sort((c,u)=>c.floor-u.floor||c.depth-u.depth||c.key.localeCompare(u.key))}var z=(t,a,n,o,e,i={})=>({id:t,type:"box",label:a,at:n,size:o,group:e,...i}),F=(t,a,n,o,e,i,r={})=>({id:t,type:"cylinder",label:a,at:n,radius:o,height:e,group:i,...r});function ut(t,a,n,o,e=3,i=18){return[[-1,-1],[-1,1],[1,-1],[1,1]].map(([r,p],d)=>F(o+"_bolt_"+d,"\\\\u56FA\\\\u5B9A\\\\u87BA\\\\u6813",[t+r*i,a+p*i,n],e,3,o,{material:"dark",explode:[0,0,26]}))}function ft(){return{title:"\\\\u5206\\\\u5C42\\\\u7ED3\\\\u6784 \\\\xB7 \\\\u793A\\\\u610F\\\\u88C5\\\\u914D",groups:[{id:"base",label:"\\\\u5E95\\\\u5EA7",description:"\\\\u652F\\\\u6491\\\\u6574\\\\u4F53\\\\uFF0C\\\\u5E76\\\\u63D0\\\\u4F9B\\\\u5B89\\\\u88C5\\\\u4F4D\\\\u7F6E\\\\u3002"},{id:"board",label:"\\\\u529F\\\\u80FD\\\\u677F",description:"\\\\u8FDE\\\\u63A5\\\\u8F93\\\\u5165\\\\u4E0E\\\\u5904\\\\u7406\\\\u6A21\\\\u5757\\\\uFF1B\\\\u793A\\\\u610F\\\\u7ED3\\\\u6784\\\\uFF0C\\\\u4E0D\\\\u5BF9\\\\u5E94\\\\u7279\\\\u5B9A\\\\u4EA7\\\\u54C1\\\\u3002"},{id:"sink",label:"\\\\u6563\\\\u70ED\\\\u5C42",description:"\\\\u5C06\\\\u70ED\\\\u91CF\\\\u4F20\\\\u5230\\\\u66F4\\\\u5927\\\\u7684\\\\u8868\\\\u9762\\\\u79EF\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u4FDD\\\\u62A4\\\\u5185\\\\u90E8\\\\uFF1B\\\\u5256\\\\u5F00\\\\u9009\\\\u9879\\\\u901A\\\\u8FC7\\\\u9690\\\\u85CF\\\\u5916\\\\u58F3\\\\u5C55\\\\u793A\\\\u7ED3\\\\u6784\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[0,0,0],[120,85,10],"base",{round:6,material:"metal"}),...[-1,1].flatMap((t,a)=>[-1,1].map((n,o)=>F("foot_"+a+o,"\\\\u9632\\\\u6ED1\\\\u811A",[t*46,n*30,-8],6,7,"base",{material:"dark"}))),z("board","\\\\u529F\\\\u80FD\\\\u677F",[0,0,15],[96,62,4],"board",{round:3,material:"cool",explode:[0,0,35]}),z("chip","\\\\u5904\\\\u7406\\\\u6A21\\\\u5757",[-16,0,22],[25,24,10],"board",{round:2,material:"dark",explode:[0,0,35]}),z("connector","\\\\u8FDE\\\\u63A5\\\\u7AEF\\\\u53E3",[32,0,24],[16,36,14],"board",{round:2,material:"warm",explode:[0,0,35]}),...ut(0,0,20,"board",2,24),z("spreader","\\\\u5BFC\\\\u70ED\\\\u5E95\\\\u677F",[-16,0,32],[44,42,5],"sink",{round:2,material:"metal",explode:[-10,0,65]}),...Array.from({length:7},(t,a)=>z("fin_"+a,"\\\\u6563\\\\u70ED\\\\u9CCD\\\\u7247",[-34+a*6,0,44],[2.4,40,20],"sink",{round:1,material:"metal",explode:[-10,0,65]})),z("top","\\\\u9876\\\\u76D6",[0,0,61],[124,89,5],"cover",{round:6,cover:!0,material:"metal",explode:[12,0,85]}),z("side","\\\\u4FA7\\\\u677F",[0,-44,32],[124,4,58],"cover",{round:2,cover:!0,material:"metal",explode:[12,-22,50]})]}}function pt({driverTeeth:t=16,drivenTeeth:a=32,module:n=1.5}={}){let o=W({driverTeeth:t,drivenTeeth:a,module:n}),e=o.centerDistance;return{title:"\\\\u9F7F\\\\u8F6E\\\\u4F20\\\\u52A8 \\\\xB7 \\\\u7B80\\\\u5316\\\\u76F4\\\\u9F7F\\\\u8F6E\\\\u793A\\\\u610F",azimuth:70,elevation:55,groups:[{id:"frame",label:"\\\\u652F\\\\u67B6",description:"\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u4F4D\\\\u7F6E\\\\uFF1B\\\\u4E24\\\\u8F74\\\\u4E2D\\\\u5FC3\\\\u8DDD\\\\u7531\\\\u9F7F\\\\u6570\\\\u4E0E\\\\u6A21\\\\u6570\\\\u5171\\\\u540C\\\\u786E\\\\u5B9A\\\\u3002"},{id:"driver",label:"\\\\u4E3B\\\\u52A8\\\\u8F6E",description:"\\\\u8F93\\\\u5165\\\\u8F6C\\\\u901F\\\\uFF0C\\\\u7531\\\\u9F7F\\\\u6570\\\\u51B3\\\\u5B9A\\\\u8282\\\\u5706\\\\u534A\\\\u5F84\\\\u3002"},{id:"driven",label:"\\\\u4ECE\\\\u52A8\\\\u8F6E",description:"\\\\u5916\\\\u556E\\\\u5408\\\\u8F6C\\\\u5411\\\\u76F8\\\\u53CD\\\\uFF0C\\\\u8F6C\\\\u901F\\\\u6309\\\\u9F7F\\\\u6570\\\\u6BD4\\\\u53D8\\\\u5316\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u9690\\\\u85CF\\\\u76D6\\\\u677F\\\\u4EE5\\\\u89C2\\\\u5BDF\\\\u4F20\\\\u52A8\\\\uFF1B\\\\u4E0D\\\\u662F\\\\u52A0\\\\u5DE5\\\\u6216\\\\u53D7\\\\u529B\\\\u4EFF\\\\u771F\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[30,0,-8],[140,90,10],"frame",{round:6,material:"metal"}),...ut(30,0,0,"frame",3,32),...[0,e].flatMap((i,r)=>[F("bearing_"+r,"\\\\u8F74\\\\u627F\\\\u5EA7",[i,0,4],10,12,"frame",{inner:4,material:"dark"}),F("shaft_"+r,"\\\\u4F20\\\\u52A8\\\\u8F74",[i,0,16],3.8,28,r?"driven":"driver",{material:"metal",explode:[r?24:-24,0,20]}),F("hub_"+r,"\\\\u8F6E\\\\u6BC2",[i,0,27],6,6,r?"driven":"driver",{inner:3.8,material:"warm",explode:[r?24:-24,0,20]})]),{id:"driverGear",type:"gear",label:"\\\\u4E3B\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driver",at:[0,0,20],radius:o.driverRadius,teeth:t,module:n,height:7,inner:4,material:"accent",explode:[-24,0,20]},{id:"drivenGear",type:"gear",label:"\\\\u4ECE\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driven",at:[e,0,20],radius:o.drivenRadius,teeth:a,module:n,height:7,inner:4,material:"cool",rotation:o.drivenAngle,explode:[24,0,20]},z("cover","\\\\u9632\\\\u62A4\\\\u76D6\\\\u677F",[30,0,36],[140,90,4],"cover",{round:6,cover:!0,material:"metal",explode:[0,0,62]})]}}function ht({radius:t=20,rod:a=70,angle:n=0}={}){let o=X({radius:t,rod:a,angle:n,z:28});return{title:"\\\\u66F2\\\\u67C4\\\\u8FDE\\\\u6746 \\\\xB7 \\\\u65CB\\\\u8F6C\\\\u8F6C\\\\u4E3A\\\\u5F80\\\\u590D",groups:[{id:"frame",label:"\\\\u652F\\\\u67B6\\\\u4E0E\\\\u5BFC\\\\u8F68",description:"\\\\u652F\\\\u6491\\\\u8F74\\\\u5FC3\\\\uFF0C\\\\u9650\\\\u5236\\\\u6ED1\\\\u5757\\\\u6CBF\\\\u540C\\\\u4E00\\\\u65B9\\\\u5411\\\\u8FD0\\\\u52A8\\\\u3002"},{id:"crank",label:"\\\\u66F2\\\\u67C4",description:"\\\\u66F2\\\\u67C4\\\\u7ED5\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u65CB\\\\u8F6C\\\\u3002"},{id:"rod",label:"\\\\u8FDE\\\\u6746",description:"\\\\u8FDE\\\\u63A5\\\\u66F2\\\\u67C4\\\\u9500\\\\u548C\\\\u6ED1\\\\u5757\\\\uFF0C\\\\u957F\\\\u5EA6\\\\u4FDD\\\\u6301\\\\u4E0D\\\\u53D8\\\\u3002"},{id:"piston",label:"\\\\u6ED1\\\\u5757",description:"\\\\u6CBF\\\\u5BFC\\\\u8F68\\\\u5F80\\\\u590D\\\\uFF1B\\\\u5B8C\\\\u6574\\\\u884C\\\\u7A0B\\\\u7B49\\\\u4E8E\\\\u66F2\\\\u67C4\\\\u534A\\\\u5F84\\\\u7684\\\\u4E24\\\\u500D\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[35,0,-6],[175,80,10],"frame",{round:6,material:"metal"}),...ut(35,0,1,"frame",3,30),F("bearing","\\\\u66F2\\\\u8F74\\\\u8F74\\\\u627F",[0,0,7],11,15,"frame",{inner:4,material:"dark"}),F("axle","\\\\u66F2\\\\u8F74",[0,0,15],3.8,26,"crank",{material:"metal",explode:[0,-18,18]}),F("flywheel","\\\\u66F2\\\\u67C4\\\\u76D8",[0,0,20],t+6,6,"crank",{inner:4,material:"accent",explode:[0,-18,18]}),z("railA","\\\\u5BFC\\\\u8F68",[74,-16,13],[85,5,6],"frame",{round:1,material:"dark"}),z("railB","\\\\u5BFC\\\\u8F68",[74,16,13],[85,5,6],"frame",{round:1,material:"dark"}),F("crankPin","\\\\u66F2\\\\u67C4\\\\u9500",o.crank,3,12,"crank",{material:"warm",explode:[0,-18,18]}),{id:"link",type:"rod",label:"\\\\u8FDE\\\\u6746",from:o.crank,to:o.piston,radius:2.4,group:"rod",material:"metal",explode:[0,0,45]},z("piston","\\\\u6ED1\\\\u5757",[o.position,0,22],[18,24,16],"piston",{round:3,material:"cool",explode:[20,0,18]}),F("pistonPin","\\\\u6ED1\\\\u5757\\\\u9500",o.piston,3,10,"piston",{material:"warm",explode:[20,0,18]})]}}var St=`\\n.mui-mechanism{font:15px/1.7 system-ui,sans-serif;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:24px;padding:20px;max-width:100%;box-sizing:border-box}.mui-mechanism *{box-sizing:border-box}.mui-mechanism h2{font-size:22px;line-height:1.35;margin:0 0 8px;font-weight:750}.mui-mechanism p{margin:0;color:var(--canvas-muted)}\\n.mui-mechanism-svg{display:block;width:100%;height:auto;max-height:420px;touch-action:pan-y}.mui-mechanism-svg path{stroke:color-mix(in srgb,var(--canvas-ink) 38%,var(--canvas-bg));stroke-width:.8;stroke-linejoin:round;vector-effect:non-scaling-stroke;cursor:pointer;fill:var(--mech-base,var(--canvas-soft))}.mui-mechanism-svg [data-material=metal]{--mech-base:color-mix(in srgb,var(--canvas-muted) 32%,var(--canvas-bg))}.mui-mechanism-svg [data-material=dark]{--mech-base:color-mix(in srgb,var(--canvas-ink) 78%,var(--canvas-bg))}.mui-mechanism-svg [data-material=accent]{--mech-base:var(--canvas-accent)}.mui-mechanism-svg [data-material=cool]{--mech-base:color-mix(in srgb,#22998a 70%,var(--canvas-bg))}.mui-mechanism-svg [data-material=warm]{--mech-base:color-mix(in srgb,#dd9c42 75%,var(--canvas-bg))}\\n.mui-mechanism-svg [data-tone="0"]{fill:color-mix(in srgb,var(--mech-base) 74%,var(--canvas-bg))}.mui-mechanism-svg [data-tone="1"]{fill:var(--mech-base)}.mui-mechanism-svg [data-tone="2"]{fill:color-mix(in srgb,var(--mech-base) 85%,var(--canvas-ink))}.mui-mechanism-svg [data-tone="3"]{fill:color-mix(in srgb,var(--mech-base) 68%,var(--canvas-ink))}.mui-mechanism-svg [data-line]{fill:none;stroke:var(--mech-base);stroke-width:2}.mui-mechanism-svg [data-active=false]{opacity:.2}.mui-mechanism-svg [data-active=true]{opacity:1}\\n.mui-mechanism-nav{display:flex;flex-wrap:wrap;gap:7px;margin:8px 0 12px}.mui-mechanism button{font:inherit;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:999px;padding:6px 13px;cursor:pointer;min-height:36px}.mui-mechanism button[aria-pressed=true]{color:var(--canvas-bg);background:var(--canvas-ink);border-color:var(--canvas-ink)}.mui-mechanism button:focus-visible,.mui-mechanism input:focus-visible{outline:2px solid var(--canvas-accent);outline-offset:3px}.mui-mechanism button:disabled{opacity:.5;cursor:default}\\n.mui-mechanism-controls{display:flex;align-items:center;flex-wrap:wrap;gap:14px;padding:12px 14px;border-radius:16px;background:var(--canvas-soft);margin:8px 0}.mui-mechanism-controls label{display:flex;align-items:center;gap:9px;flex:1 1 180px;min-width:0}.mui-mechanism-controls input[type=range]{flex:1;min-width:70px;accent-color:var(--canvas-accent)}.mui-mechanism-controls input[type=checkbox]{accent-color:var(--canvas-accent)}.mui-mechanism-controls output{font-variant-numeric:tabular-nums;min-width:40px;text-align:right;font-weight:650}.mui-mechanism-readout{display:block;padding:10px 0;font-weight:700;font-variant-numeric:tabular-nums;color:var(--canvas-ink)}.mui-mechanism-description{min-height:0;font-size:14px}\\n.mui-mechanism[data-style=editorial]{border:0;border-top:1px solid var(--canvas-line);border-radius:0;padding:16px 0}.mui-mechanism[data-style=editorial] h2{font-family:ui-serif,Georgia,serif;font-weight:650}.mui-mechanism[data-style=editorial] .mui-mechanism-controls{border-radius:0;background:transparent;border-block:1px solid var(--canvas-line)}\\n.mui-mechanism[data-style=technical]{border-radius:10px}.mui-mechanism[data-style=technical] button,.mui-mechanism[data-style=technical] .mui-mechanism-controls{border-radius:6px}.mui-mechanism[data-style=technical] .mui-mechanism-readout{font-family:ui-monospace,Consolas,monospace}\\n.mui-mechanism[data-style=soft]{border:0;background:var(--canvas-soft);border-radius:28px 28px 28px 10px}.mui-mechanism[data-style=soft] .mui-mechanism-controls{background:var(--canvas-bg);border-radius:22px}.mui-mechanism[data-style=expressive] h2{font-size:28px;font-weight:850;border-left:5px solid var(--canvas-accent);padding-left:14px}.mui-mechanism[data-style=expressive]{border:0;border-radius:0}.mui-mechanism[data-style=prismframe]{border:1.5px solid var(--canvas-line);box-shadow:4px 5px 0 color-mix(in srgb,var(--canvas-accent) 14%,var(--canvas-bg))}.mui-mechanism[data-style=aurora]{border-radius:28px;box-shadow:0 16px 30px -25px #30204d66}.mui-mechanism[data-style=aurora] .mui-mechanism-controls{border-radius:24px}\\n@media(max-width:500px){.mui-mechanism{padding:14px;border-radius:20px}.mui-mechanism h2{font-size:20px}.mui-mechanism-controls{padding:10px}.mui-mechanism-nav{gap:5px}.mui-mechanism button{padding:6px 10px;font-size:14px}}\\n@media(prefers-reduced-motion:reduce){.mui-mechanism *{animation:none!important;transition:none!important}}\\n@media(forced-colors:active){.mui-mechanism-svg path{fill:Canvas;stroke:CanvasText}.mui-mechanism button[aria-pressed=true]{background:Highlight;color:HighlightText}}\\n`;var xt="http://www.w3.org/2000/svg",C=(t,a,n)=>{let o=document.createElement(t);return a&&(o.className=a),n!==void 0&&(o.textContent=n),o};function Ft(t){function a(o,e){let i=typeof o=="string"?document.querySelector(o):o;if(!i||!i.replaceChildren)throw Error("Motion mechanism: target element not found");Y(e);let r=structuredClone({...e,onSelect:void 0}),p=nt(r),d={explode:0,selected:"all",cutaway:!1,pose:{}},m=!1,s="",c="",u=0,f=new Map,g=new Map,h=new Map,M=[],O=C("section","mui-mechanism"),N=C("h2",null,r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$=document.createElementNS(xt,"svg"),P=document.createElementNS(xt,"g"),A=C("div","mui-mechanism-nav"),w=C("div","mui-mechanism-controls"),T=C("p","mui-mechanism-description"),D=C("output","mui-mechanism-readout"),G=C("style");G.textContent=St,N.hidden=r.title==="",O.setAttribute("aria-label",r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$.setAttribute("class","mui-mechanism-svg"),$.setAttribute("viewBox","0 0 600 340"),$.setAttribute("role","img"),$.setAttribute("aria-label","\\\\u53EF\\\\u62C6\\\\u89E3\\\\u7684\\\\u7ED3\\\\u6784\\\\u793A\\\\u610F\\\\u56FE\\\\uFF1B\\\\u4F7F\\\\u7528\\\\u4E0B\\\\u65B9\\\\u6309\\\\u94AE\\\\u9009\\\\u62E9\\\\u90E8\\\\u4EF6"),$.append(P),O.append(G,N,$,A,w,D,T),i.replaceChildren(O);let S=()=>r.groups?.length?r.groups:r.parts.map(l=>({id:l.id,label:l.label??l.id,description:l.description??""}));function H(l){r.bind?.selected?t.setState({[r.bind.selected]:l}):typeof e.onSelect=="function"?e.onSelect(l):Q({selected:l})}function K(){if(A.replaceChildren(),h.clear(),!r.bind?.selected&&typeof e.onSelect!="function"){A.hidden=!0;return}A.hidden=!1;for(let l of[{id:"all",label:"\\\\u5168\\\\u90E8",description:""},...S()]){let b=C("button",null,l.label);b.type="button",b.setAttribute("aria-pressed",String(d.selected===l.id)),b.addEventListener("click",()=>H(l.id)),h.set(l.id,b),A.append(b)}}let x,rt,L;if(r.bind?.explode){let l=C("label",null,"\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6");x=C("input"),x.type="range",x.min="0",x.max="1",x.step=".01",x.setAttribute("aria-label","\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6"),rt=C("output"),x.addEventListener("input",()=>t.setState({[r.bind.explode]:Number(x.value)})),l.append(x,rt),w.append(l)}if(r.bind?.cutaway&&r.parts.some(l=>l.cover)){let l=C("label",null,"\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3");L=C("input"),L.type="checkbox",L.setAttribute("aria-label","\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3"),L.addEventListener("change",()=>t.setState({[r.bind.cutaway]:L.checked})),l.prepend(L),w.append(l)}w.hidden=!w.childNodes.length;function jt(l){let b=JSON.stringify([l.explode,l.cutaway]);b!==s&&(p=nt(r,l),s=b);let E=mt(r,p,l,f),k=new Set;for(let j of E){k.add(j.key);let R=g.get(j.key);R||(R=document.createElementNS(xt,"path"),R.setAttribute("fill-rule","evenodd"),g.set(j.key,R));for(let[gt,bt]of Object.entries({d:j.d,"data-part":j.part,"data-material":j.material,"data-tone":j.tone,"data-active":j.active}))R.getAttribute(gt)!==String(bt)&&R.setAttribute(gt,String(bt));j.line?R.setAttribute("data-line",""):R.removeAttribute("data-line")}for(let[j,R]of g)k.has(j)||(R.remove(),g.delete(j));let Z=E.map(j=>j.key).join("|");if(Z!==c){for(let j of E)P.append(g.get(j.key));c=Z}u++}function Q(l={}){if(m)return;for(let k of Object.keys(l))if(!["explode","selected","cutaway","pose","parts","readout"].includes(k))throw Error("Motion mechanism: unknown update field "+k);if(l.parts){let k={...r,parts:l.parts};Y(k);let Z=nt(k);mt(k,Z,{...d,...l},new Map),r=k,p=Z,f.clear(),c="",s=""}let b={...d,...l};l.pose&&(b.pose=l.pose),jt(b),d=b;for(let[k,Z]of h)Z.setAttribute("aria-pressed",String(b.selected===k));let E=S().find(k=>k.id===b.selected)??r.parts.find(k=>k.id===b.selected);T.textContent=E?.description??(b.selected==="all"?"\\\\u9009\\\\u62E9\\\\u4E00\\\\u4E2A\\\\u90E8\\\\u4EF6\\\\uFF0C\\\\u67E5\\\\u770B\\\\u5B83\\\\u7684\\\\u804C\\\\u8D23\\\\uFF1B\\\\u62C6\\\\u89E3\\\\u53EA\\\\u5C55\\\\u793A\\\\u88C5\\\\u914D\\\\u5173\\\\u7CFB\\\\u3002":""),x&&(x.value=String(b.explode),rt.textContent=Math.round(b.explode*100)+"%"),L&&(L.checked=b.cutaway),l.readout!==void 0&&(D.textContent=String(l.readout))}return $.addEventListener("click",l=>{let b=l.target.closest("[data-part]");if(!b)return;let E=r.parts.find(k=>k.id===b.getAttribute("data-part"));E&&H(r.groups?.length?E.group??E.id:E.id)}),K(),M.push(t.subscribe(l=>{if(m)return;let b={};for(let[E,k]of Object.entries(r.bind??{})){if(!Object.hasOwn(l.state,k))throw Error("Motion mechanism: bind."+E+" names undeclared state "+k);b[E]=l.state[k]}O.dataset.style=l.theme?.visualStyle??"";for(let E of h.values())E.disabled=l.disabled;x&&(x.disabled=l.disabled),L&&(L.disabled=l.disabled),Q(b)})),Object.freeze({update:Q,pose:l=>Q({pose:l}),stats:()=>({frames:u,faces:g.size,parts:r.parts.length}),destroy(){m||(m=!0,M.forEach(l=>l()),g.clear(),f.clear(),i.replaceChildren())}})}function n(o,e,i={}){if(!["assembly","gears","crank"].includes(e))throw Error("Motion mechanism: demo must be assembly/gears/crank");let r=i.bind??{},p=()=>t.snapshot.state,d=(A,w)=>Object.hasOwn(r,A)?p()[r[A]]:w;for(let[A,w]of Object.entries(r))if(!["explode","selected","cutaway","rpm","teeth","running","angle","radius"].includes(A)||typeof w!="string"||!Object.hasOwn(p(),w))throw Error("Motion mechanism: invalid demo binding "+A);let m=d("angle",0)*Math.PI/180,s=m,c="",u=!1,f=Object.fromEntries(Object.entries(r).filter(([A])=>["explode","selected","cutaway"].includes(A)));function g(){return e==="assembly"?ft():e==="gears"?pt({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),module:i.module??1.5}):ht({radius:d("radius",20),rod:i.rod??70})}let h=a(o,{...g(),...i.title===void 0?{}:{title:i.title},bind:f}),M=!1;function O(A=0,w=!1,T=!0){if(M)return;let D=d("rpm",30),G=d("running",!1),S=d("angle",0)*Math.PI/180,H=s;S!==m?(H=S,m=S):G&&T&&!w&&(H+=D*Math.PI*2/60*A),s=H;let K=JSON.stringify([e,d("teeth",32),d("radius",20)]);if(K!==c&&(h.update({parts:g().parts}),c=K),e==="gears"){let x=W({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),rpm:D,angle:s,module:i.module??1.5});h.update({pose:{driverGear:{rotation:x.driverAngle},drivenGear:{rotation:x.drivenAngle}},readout:"\\\\u4E3B\\\\u52A8\\\\u8F6E "+t.formatNumber(x.driverRpm,0)+" rpm \\\\xB7 \\\\u4ECE\\\\u52A8\\\\u8F6E "+t.formatNumber(x.drivenRpm,2)+" rpm \\\\xB7 \\\\u9F7F\\\\u6570\\\\u6BD4 "+t.formatNumber(x.ratio,2)+"\\\\uFF08\\\\u8D1F\\\\u53F7\\\\u8868\\\\u793A\\\\u53CD\\\\u5411\\\\uFF09"})}else if(e==="crank"){let x=X({angle:s,radius:d("radius",20),rod:i.rod??70,z:28});h.update({pose:{crankPin:{at:x.crank},link:{from:x.crank,to:x.piston},piston:{at:[x.position,0,22]},pistonPin:{at:x.piston}},readout:"\\\\u66F2\\\\u67C4\\\\u89D2 "+t.formatNumber((s*180/Math.PI%360+360)%360,1)+"\\\\xB0 \\\\xB7 \\\\u6ED1\\\\u5757\\\\u4F4D\\\\u7F6E "+t.formatNumber(x.position,2)+" \\\\xB7 \\\\u884C\\\\u7A0B "+t.formatNumber(x.stroke,1)+"\\\\uFF08\\\\u793A\\\\u610F\\\\u957F\\\\u5EA6\\\\u5355\\\\u4F4D\\\\uFF09"})}u=w}let N=null,$=()=>{O(0,u,!0),e!=="assembly"&&(d("running",!1)&&!N?N=t.animate(({delta:A,reducedMotion:w,visible:T})=>{T&&!w?O(A,!1,!0):u!==w&&O(0,w,T)}):!d("running",!1)&&N&&(N(),N=null))},P=t.subscribe($);return O(),Object.freeze({...h,destroy(){M||(M=!0,N?.(),P(),h.destroy())}})}return Object.freeze({mount:a,mountDemo:n,gearPair:W,sliderCrank:X,follow:Mt,scenes:Object.freeze({assembly:ft,gears:pt,crank:ht})})}return _t(Tt);})();\\n\';\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const styleCache = /* @__PURE__ */ new WeakMap(), styleOf = (el2) => {\n let css = styleCache.get(el2);\n if (!css) {\n css = getComputedStyle(el2);\n styleCache.set(el2, css);\n }\n return css;\n };\n const target = (el2) => {\n if (!el2) return void 0;\n const tag = el2.tagName.toLowerCase(), id = el2.id;\n return { selector: id && id.length <= 64 ? "#" + CSS.escape(id) : tag, text: (el2.textContent ?? "").trim().replace(/\\s+/g, " ").slice(0, 120), tag };\n };\n const add = (code, value, el2) => {\n if (issues.length >= 40) return;\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const location = target(el2);\n const k2 = id + ":" + code + ":" + (location?.selector ?? "") + ":" + (location?.text ?? "") + ":" + Math.round(value ?? 0);\n if (!seen.has(k2) && issues.length < 40) {\n seen.add(k2);\n issues.push({ code, nodeId: id, ...location ? { target: location } : {}, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m2 = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m2 = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v2) => v2 <= 0.04045 ? v2 / 12.92 : ((v2 + 0.055) / 1.055) ** 2.4).reduce((s, v2, i) => s + v2 * [0.2126, 0.7152, 0.0722][i], 0);\n const blend = (front, back) => front.slice(0, 3).map((v2, i) => v2 * front[3] + back[i] * (1 - front[3])).concat(1);\n const background = (el2) => {\n const layers = [];\n let n = el2;\n for (let i = 0; n && i < 64; i++, n = n.parentElement) {\n const c = styleOf(n);\n if (c.backgroundImage !== "none") return null;\n const colorValue = color(c.backgroundColor);\n if (!colorValue) return null;\n if (colorValue[3] > 0) layers.push(colorValue);\n if (colorValue[3] === 1) {\n let out = layers.pop();\n while (layers.length) out = blend(layers.pop(), out);\n return out;\n }\n }\n return null;\n };\n let contentBottom = root.getBoundingClientRect().top;\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = styleOf(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m2 = el.getScreenCTM();\n if (m2) size *= Math.hypot(m2.c, m2.d);\n }\n if (size < 11.9) add("smallText", size, el);\n if (!(el instanceof SVGElement)) {\n const fg = color(css.color), bg = background(el);\n let opacitySafe = true, opacityDepth = 0;\n for (let a2 = el; a2; a2 = a2.parentElement) {\n if (++opacityDepth > 64 || parseFloat(styleOf(a2).opacity) < 1) {\n opacitySafe = false;\n break;\n }\n }\n if (fg && bg && opacitySafe) {\n coverage.contrastChecked++;\n const a2 = luminance(blend(fg, bg)), b2 = luminance(bg), ratio = (Math.max(a2, b2) + 0.05) / (Math.min(a2, b2) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n const range = document.createRange();\n range.selectNodeContents(el);\n const bounds = range.getBoundingClientRect();\n let a = el, depth = 0;\n while (a && a !== root.parentElement && depth++ < 24) {\n const c = styleOf(a), clip = a.getBoundingClientRect();\n if (["hidden", "clip"].includes(c.overflowX) && (bounds.left < clip.left - 2 || bounds.right > clip.right + 2) || ["hidden", "clip"].includes(c.overflowY) && (bounds.top < clip.top - 2 || bounds.bottom > clip.bottom + 2)) {\n add("clippedText", void 0, el);\n break;\n }\n a = a.parentElement;\n }\n } else coverage.contrastUncovered++;\n }\n if (text2 || el.matches("svg,canvas,img,video,input,select,textarea,button")) contentBottom = Math.max(contentBottom, box.bottom);\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n const rect = root.getBoundingClientRect(), gap = rect.bottom - contentBottom;\n if (!coverage.truncated && root.id === "canvas" && rect.height > 320 && gap > Math.max(96, rect.height * 0.25)) add("bottomWhitespace", gap, root);\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:16px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\n#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:var(--canvas-bg,#fff)}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:12px}button{border-radius:999px}.ui-primary{background:var(--canvas-ink,#182537);color:var(--canvas-bg,#fff)}.ui-callout{border-radius:0 12px 12px 0;background:color-mix(in srgb,var(--canvas-accent,#3e60d3) 5%,var(--canvas-bg,#fff))}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k2) => [k2, values[k2]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k2) => !(node2.stateKeys ?? []).includes(k2))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n ${node2.libraries?.includes("mechanism") ? MECHANISM_RUNTIME.replace(/<\\/script/gi, "<\\\\/script") + ";api.mechanism=__MotionMechanism.createMechanismAPI(api);" : ""}\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n visual: define(["spec", "stateKey", "warnings"], "Extended native charts, tables, plots, quiz, forms, diagrams, media and 3D"),\n heading: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "Section heading", "tone"),\n text: define(["text", "spans", "size", "weight", "color", "align", "lineHeight", "copyable", "title"], "Readable explanation; copyable:true adds a reusable text panel", "tone"),\n code: define(["code", "lang", "title", "wrap"], "Literal copyable code; displayed only, never executed"),\n callout: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "A short emphasized paragraph", "tone"),\n row: define(["children", "columns", "gap"], "Wrapping parallel content"),\n column: define(["children", "gap"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["title", "items"], "Ordered declared steps with an optional heading"),\n metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind", "variant"], "Selection from declared state options; variant:segmented for 2..8 short options, dropdown otherwise"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action", "href", "path", "variant"], "Agent follow-up, web link or host file opener", "icon"),\n link: define(["text", "href", "path", "variant"], "User-clicked webpage or local file button", "icon"),\n divider: define(["label"], "Quiet section divider"),\n table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "libraries", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/identifiers.js\n var IDENTIFIER_SOURCE = "[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}";\n var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");\n var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/ceil/floor/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = new RegExp(String.raw`\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|(${IDENTIFIER_SOURCE}(?:\\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m2 = token2.exec(source);\n if (!m2) fail2();\n offset = token2.lastIndex;\n tokens.push(m2[1] ? { number: Number(m2[1] + (m2[2] ?? "")) } : m2[3] ? { string: JSON.parse(m2[3]) } : m2[4] ?? m2[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };\n else if (["min", "max", "round", "ceil", "floor", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression2 = (e, at2) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n try {\n return compileExpression(e.expr);\n } catch (error) {\n error.message = "DSH UI: " + at2 + ": " + error.message.replace(/^DSH UI: /, "");\n error.path = at2;\n throw error;\n }\n }\n if (Array.isArray(e.args)) e.args = e.args.map((v2, i) => expression2(v2, at2 + ".args[" + i + "]"));\n if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2], at2 + ".map.fields." + k2);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k2 of Object.keys(doc2.derived)) doc2.derived[k2] = expression2(doc2.derived[k2], "derived." + k2);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression2(node2[field], "node." + node2.id + "." + field);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const [rowIndex, row] of node2.rows.entries()) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2], "node." + node2.id + ".rows[" + rowIndex + "]." + k2);\n }\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/visual-guard.js\n var ne = ["h1", "h2", "h3", "body", "muted", "caption"];\n var te = ["primary", "danger", "success", "ghost"];\n var ie = ["success", "warn", "danger", "accent"];\n var re = ["text", "email", "password", "color"];\n var se = ["info", "success", "warning", "error"];\n var U = ["bars", "line", "donut"];\n var oe = ["line", "area", "scatter"];\n var ae = ["16:9", "4:3", "1:1", "9:16"];\n var ue = ["box", "sphere", "cone", "cylinder", "torus"];\n var le = ["file", "dir"];\n var de = ["architecture", "it-state", "flowchart", "sequence", "state", "er", "timeline", "swimlane", "quadrant", "radar", "loop", "nested", "tree", "org-chart", "layers", "venn", "pyramid", "bar", "line", "gantt", "scatter", "high-level", "process", "medallion", "data-flow", "dp-integration", "dp-security-matrix"];\n var ce = ["focal", "backend", "store", "external", "input", "optional", "security"];\n var fe = ["light", "dark", "editorial"];\n var pe = ["solid", "dashed", "accent", "link"];\n var me = ["auto", "orthogonal", "straight"];\n var ge = ["bar", "line", "area", "pie", "scatter", "radar", "gauge", "funnel", "treemap", "sankey", "graph", "heatmap", "bigline", "wordCloud"];\n var tn = ["hero"];\n var ye = ["bar", "ring"];\n var be = ["info", "success", "warning", "danger"];\n var he = ["accent", "success", "warning", "danger"];\n var Ee = ["text", "num", "delta", "bar", "badge", "spark", "ring", "index", "group"];\n var b = (t, i, r = {}, e = {}) => {\n let s = Object.fromEntries(Object.entries(i).filter(([u]) => u !== "type" && !t.includes(u))), n = e.oneOfRequired ?? [], o = e.conditionalRequired ?? [], a = [...n.map((u) => ({ kind: "one-of-required", fields: u })), ...o];\n return { required: t, fields: i, optional: s, aliases: r, valueAliases: e.valueAliases ?? {}, oneOfRequired: n, conditionalRequired: o, rules: a, enums: e.enums ?? {}, nested: e.nested ?? {}, ...e.validator === void 0 ? {} : { validator: e.validator } };\n };\n var G = (t, i, r = {}, e = {}, s = {}) => ({ required: t, fields: i, enums: e, nested: r, aliases: s });\n var h = { type: "string", span: "number", id: "string" };\n var De = G(["label", "value"], { label: "string", value: "number", color: "string" });\n var rn = G(["label", "data"], { label: "string", color: "string", data: "array" }, { data: De });\n var sn = G(["title"], { title: "string", desc: "string" });\n var on = G(["key", "value"], { key: "string", value: "string" }, {}, {}, { label: "key" });\n var an = G(["title"], { title: "string", desc: "string", time: "string" });\n var un = G(["path", "newText"], { path: "string", oldText: "string-or-null", newText: "string" });\n var ln = G(["name", "value"], { name: "string", value: "number", min: "number", max: "number", step: "number", animateTo: "number", durationMs: "number", loop: "boolean" });\n var dn = G(["expr"], { expr: "string", label: "string", color: "string", kind: "string", params: "array" }, { params: ln }, { kind: oe });\n var cn = G(["shape"], { shape: "string", color: "string", position: "array", rotation: "array", scale: "unknown", size: "unknown" }, {}, { shape: ue });\n function Oe(t) {\n return G(["name"], { name: "string", type: "string", children: "array" }, t > 0 ? { children: Oe(t - 1) } : {}, { type: le }, { label: "name" });\n }\n var fn = Oe(6);\n var pn = G(["label", "items"], { label: "string", items: "nodes", content: "nodes" });\n var mn = G(["title", "items"], { title: "string", items: "nodes" });\n var gn = G(["id", "label"], { id: "string", label: "string", sub: "string", type: "string", x: "number", y: "number", w: "number", h: "number", tag: "string" }, {}, { type: ce });\n var yn = G(["from", "to"], { from: "string", to: "string", label: "string", kind: "string", route: "string" }, {}, { kind: pe, route: me });\n var bn = G(["label"], { label: "string", x: "number", y: "number", w: "number", h: "number" });\n var hn = G([], { paper: "string", "paper-2": "string", ink: "string", muted: "string", soft: "string", rule: "string", accent: "string", "accent-tint": "string", link: "string" });\n var V = b(["items"], { title: "string", gap: "number", panel: "boolean", append: "boolean", items: "nodes" });\n var T = { accordion: b(["items"], { ...h, items: "array" }, {}, { nested: { items: mn } }), audio: b(["src"], { ...h, src: "string", alt: "string", loop: "boolean" }, { url: "src", link: "src" }), avatar: b(["name"], { ...h, name: "string", color: "string" }), badge: b(["label"], { ...h, label: "string", tone: "string", icon: "string" }, { text: "label", value: "label" }, { enums: { tone: ie } }), breadcrumb: b(["items"], { ...h, items: "array" }), button: b(["label"], { ...h, label: "string", tone: "string", full: "boolean", small: "boolean", icon: "string", action: "string" }, {}, { enums: { tone: te } }), callout: b(["content"], { ...h, title: "string", content: "string", tone: "string" }, { kind: "tone", text: "content", body: "content", desc: "content" }, { enums: { tone: se }, valueAliases: { tone: { danger: "error", warn: "warning" } } }), card: b(["items"], { ...h, title: "string", items: "nodes", tone: "string", accent: "string" }, { label: "title", content: "items" }, { enums: { tone: be } }), chart: b([], { ...h, kind: "string", data: "array", series: "array", horizontal: "boolean", stacked: "boolean", filter: "string", palette: "array" }, {}, { oneOfRequired: [["data", "series"]], conditionalRequired: [{ kind: "required-if", when: { field: "kind", equals: "donut" }, required: ["data"] }], nested: { data: De, series: rn }, enums: { kind: U }, validator: { name: "chart-renderability" } }), checkbox: b(["label"], { ...h, label: "string", checked: "boolean", action: "string", group: "string" }), code: b(["code"], { ...h, lang: "string", code: "string", title: "string", wrap: "boolean" }, { content: "code", text: "code" }), col: b(["items"], { ...h, items: "nodes", gap: "number" }), copy: b(["text"], { ...h, label: "string", text: "string" }, { content: "text", code: "text", value: "text" }), diagram: b(["kind", "nodes"], { ...h, kind: "string", variant: "string", title: "string", nodes: "array", edges: "array", zones: "array", theme: "object" }, {}, { nested: { nodes: gn, edges: yn, zones: bn, theme: hn }, enums: { kind: de, variant: fe } }), diff: b(["diffs"], { ...h, diffs: "array" }, { items: "diffs", files: "diffs" }, { nested: { diffs: un } }), divider: b([], h), echart: b([], { ...h, title: "string", height: "number", preset: "string", data: "array", series: "array", links: "array", palette: "array", option: "object" }, {}, { oneOfRequired: [["option", "data", "series", "links"]], enums: { preset: ge } }), "file-tree": b(["items"], { ...h, items: "array" }, { nodes: "items" }, { nested: { items: fn } }), grid: b(["items"], { ...h, cols: "number", items: "nodes" }), image: b(["src"], { ...h, src: "string", alt: "string" }, { url: "src", link: "src" }), input: b([], { ...h, label: "string", placeholder: "string", value: "string", inputType: "string", action: "string", id: "string" }, {}, { enums: { inputType: re } }), json: b(["value"], { ...h, value: "unknown" }), keyvalue: b(["pairs"], { ...h, pairs: "array" }, { items: "pairs", rows: "pairs", entries: "pairs" }, { nested: { pairs: on } }), link: b(["label"], { ...h, label: "string", href: "string" }), list: b(["items"], { ...h, items: "array", filter: "string" }), mermaid: b(["code"], { ...h, code: "string" }), svg: b(["code"], { ...h, code: "string", title: "string", height: "number" }), plot: b(["series"], { ...h, series: "array", xMin: "number", xMax: "number", yMin: "number", yMax: "number", title: "string" }, {}, { nested: { series: dn } }), progress: b(["value"], { ...h, value: "number", label: "string", valueLabel: "string", variant: "string", target: "number" }, {}, { enums: { variant: ye } }), quiz: b(["question", "options"], { ...h, question: "string", options: "array", explanation: "string", id: "string", action: "string" }, { title: "question", text: "question", choices: "options", items: "options" }), radio: b(["options"], { ...h, label: "string", options: "array", selected: "number", action: "string", group: "string", answer: "unknown", explanation: "string" }, { items: "options" }), row: b(["items"], { ...h, items: "nodes", wrap: "boolean", spacer: "boolean" }), scene3d: b(["meshes"], { ...h, title: "string", meshes: "array", ambient: "number", background: "string" }, {}, { nested: { meshes: cn } }), select: b(["options"], { ...h, label: "string", options: "array", action: "string", selected: "number", id: "string" }, { items: "options" }), slider: b([], { ...h, label: "string", min: "number", max: "number", step: "number", value: "number", action: "string", id: "string" }), spacer: b([], h), hero: b(["title"], { ...h, title: "string", subtitle: "string", value: "string", label: "string", delta: "string", spark: "array", tone: "string" }, {}, { enums: { tone: he } }), stat: b(["label", "value"], { ...h, label: "string", value: "string", delta: "string", spark: "array", size: "string" }, {}, { enums: { size: tn } }), steps: b(["steps"], { ...h, steps: "array", current: "number" }, { items: "steps" }, { nested: { steps: sn } }), submit: b(["label"], { ...h, label: "string", action: "string", resetAction: "string", groups: "array" }), switch: b(["label"], { ...h, label: "string", checked: "boolean", action: "string" }), table: b(["columns", "rows"], { ...h, columns: "array", rows: "array", types: "array", total: "boolean", details: "array", filter: "string", filterColumn: "number", sortField: "string", export: "boolean" }, { headers: "columns", data: "rows", items: "rows" }), tabs: b(["tabs"], { ...h, tabs: "array" }, {}, { nested: { tabs: pn } }), text: b(["content"], { ...h, content: "string", size: "string", center: "boolean", copyable: "boolean", title: "string" }, { text: "content" }, { enums: { size: ne } }), textarea: b([], { ...h, label: "string", placeholder: "string", rows: "number", value: "string", action: "string", id: "string" }), timeline: b(["items"], { ...h, items: "array" }, {}, { nested: { items: an } }), video: b(["src"], { ...h, src: "string", alt: "string", poster: "string", loop: "boolean", muted: "boolean", aspectRatio: "string" }, { url: "src", link: "src" }, { enums: { aspectRatio: ae } }) };\n var q = new Set(Object.keys(T));\n function N(t) {\n if (typeof t != "object" || t === null) return false;\n let i = t;\n return typeof i.type != "string" || i.type === "" ? false : Array.isArray(i.items) ? q.has(i.type) : true;\n }\n function z(t) {\n if (typeof t != "object" || t === null) return null;\n let i = t;\n if (typeof i.type != "string" || i.type === "") return null;\n let r = q.has(i.type) ? T[i.type] : void 0, e = typeof i.title == "string" && r !== void 0 && !("title" in r.fields) ? i.title : void 0, s = { ...t };\n return e !== void 0 && delete s.title, { items: [s], ...e !== void 0 ? { title: e } : {}, ...i.panel === true ? { panel: true } : {}, ...i.append === true ? { append: true } : {} };\n }\n var m = { maxDepth: 8, maxNodes: 200, maxString: 2e3, maxCode: 12e3, maxMermaid: 8e3, maxGridCols: 12, maxTabs: 12, maxAccordionItems: 24, maxListItems: 50, maxOptions: 50, maxTableRows: 50, maxTableCols: 12, maxChartPoints: 60, maxPlotSeries: 8, maxPlotParams: 6, maxMeshes: 5, maxQuizOptions: 8, maxSteps: 24, maxTimelineItems: 24, maxBreadcrumbItems: 12, maxKeyValuePairs: 24, maxTreeDepth: 6, maxDiagramNodes: 9, maxDiagramEdges: 12, maxDiagramZones: 3, maxDiagramFocal: 2, maxDiagramLabel: 14, maxEChartOptionDepth: 10, maxEChartArrayLen: 500, maxEChartOptionNodes: 2e3 };\n function ke(t) {\n let i = t.columns, r = Array.isArray(i) && i.length > 0, e = r && Array.isArray(i) && typeof i[0] == "object" && i[0] !== null ? i.map($n) : i, s = kn(e), n = t.rows !== void 0 ? t.rows : t.data;\n if (Array.isArray(n) && n.length > 0 && typeof n[0] == "object" && n[0] !== null && !Array.isArray(n[0])) {\n let u = Array.isArray(t.columns) && t.columns.length > 0 && typeof t.columns[0] == "object" && t.columns[0] !== null ? t.columns.map(Sn).filter((d) => d !== void 0) : Object.keys(n[0]);\n n = n.map((d) => u.map((c) => wn(d[c])));\n }\n let o = null;\n if (!r && Array.isArray(n) && n.length > 0 && Array.isArray(n[0])) {\n let u = xe(n), d = u.length === 0 ? null : An(u);\n d !== null && xe(d.rows).length === d.rows.length && (o = d, s = d.columns.map((c) => c.slice(0, 128)));\n }\n if (s.length === 0 && !Array.isArray(t.columns)) return null;\n let a = xe(o === null ? n : o.rows);\n return Array.isArray(n) ? { columns: s.slice(0, m.maxTableCols), rows: a } : null;\n }\n function I(t) {\n return ke(t)?.rows ?? [];\n }\n function xn(t, i) {\n return !Array.isArray(t) || !Array.isArray(i) || i[0] !== "group" ? false : String(t[0] ?? "").trim() !== "" && t.slice(1).every((r) => String(r ?? "").trim() === "");\n }\n function C(t, i) {\n let r = I(t);\n return i >= 0 && i < r.length && !xn(r[i], t.types);\n }\n function kn(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableCols) break;\n if (typeof r == "string") i.push(r.slice(0, 128));\n else if (r !== null && typeof r == "object") {\n let e = r, s = typeof e.label == "string" ? e.label : typeof e.value == "string" ? e.value : typeof e.title == "string" ? e.title : JSON.stringify(r);\n i.push(s.slice(0, 128));\n }\n }\n return i;\n }\n function xe(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableRows) break;\n if (!Array.isArray(r)) continue;\n let e = [];\n for (let s of r) {\n if (e.length >= m.maxTableCols) break;\n typeof s == "string" ? e.push(s.slice(0, 256)) : typeof s == "number" && Number.isFinite(s) && e.push(s);\n }\n e.length > 0 && i.push(e);\n }\n return i;\n }\n function An(t) {\n let i = t[0];\n if (i === void 0 || i.length === 0) return null;\n let r = t.slice(1);\n if (r.length === 0) {\n let e = i.map((s) => String(s).trim());\n return e.every((s) => s !== "") ? { columns: e, rows: [] } : null;\n }\n return r.every((e) => e.length === i.length) ? { columns: i.map((e) => String(e).trim()), rows: r } : { columns: Array.from({ length: i.length }, (e, s) => `\\u5217${s + 1}`), rows: t };\n }\n function Sn(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return;\n let i = t;\n for (let r of ["key", "dataIndex", "title", "label"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n }\n function wn(t) {\n return typeof t == "string" || typeof t == "number" && Number.isFinite(t) ? t : t == null ? "" : JSON.stringify(t);\n }\n function $n(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return String(t);\n let i = t;\n for (let r of ["title", "label", "key", "dataIndex"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n return JSON.stringify(t);\n }\n function O(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function Ae(t) {\n let i = O(t);\n return i !== void 0 && typeof i.type == "string";\n }\n var Gn = ["label", "value", "delta", "spark", "size"];\n var Rn = { label: "title", name: "title", description: "desc", content: "desc", text: "desc", body: "desc", detail: "desc" };\n function Tn(t, i, r) {\n if (t.length === 0) return null;\n let e = [];\n for (let s = 0; s < t.length; s++) {\n let n = t[s], o = O(n);\n if (o === void 0) return null;\n if (Ae(n)) {\n e.push(r(n, `${i}.items[${s}]`));\n continue;\n }\n if (typeof o.label != "string" && typeof o.value != "string") return null;\n let a = { type: "stat" };\n for (let u of Gn) o[u] !== void 0 && (a[u] = o[u]);\n e.push(a);\n }\n return e;\n }\n function Cn(t, i, r, e) {\n let s = T[r];\n if (s === void 0) return t;\n let n = { ...t };\n for (let [o, a] of Object.entries(s.aliases)) {\n if (!(o in n)) continue;\n let u = `${i}.${o}`, d = a in n;\n d || (n[a] = n[o]), delete n[o], e.push({ kind: "alias", path: u, message: d ? `${u} is ignored because canonical field \'${a}\' is present` : `${u} normalized/adopted as \'${a}\'`, type: r, field: o, canonical: a });\n }\n for (let [o, a] of Object.entries(s.valueAliases)) {\n let u = n[o];\n if (typeof u != "string") continue;\n let d = a[u];\n d === void 0 || d === u || (n[o] = d, e.push({ kind: "alias", path: `${i}.${o}`, message: `${i}.${o} \'${u}\' normalized to \'${d}\'`, type: r, field: o, canonical: d }));\n }\n return n;\n }\n function Se(t, i, r, e, s) {\n if (Array.isArray(t)) return t.map((a, u) => Se(a, i, `${r}[${u}]`, e, s));\n let n = O(t);\n if (n === void 0) return t;\n let o = { ...n };\n for (let [a, u] of Object.entries(i.aliases)) !(a in o) || u in o || (o[u] = o[a], delete o[a], s.push({ kind: "alias", path: `${r}.${a}`, message: `${r}.${a} normalized/adopted as \'${u}\'`, type: e, field: a, canonical: u }));\n for (let [a, u] of Object.entries(i.nested)) o[a] !== void 0 && (o[a] = Se(o[a], u, `${r}.${a}`, e, s));\n return o;\n }\n function we(t) {\n if (Array.isArray(t)) return t.map(we);\n let i = O(t);\n if (i === void 0) return t;\n let r = { ...i };\n return r.type === void 0 && Array.isArray(r.children) && (r.type = "dir"), r.children !== void 0 && (r.children = we(r.children)), r;\n }\n function $e(t, i, r) {\n if (!Ae(t)) return t;\n let e = t.type, s = T[e];\n if (s === void 0) return t;\n let n = Cn(t, i, e, r);\n for (let [u, d] of Object.entries(s.nested)) n[u] !== void 0 && (n[u] = Se(n[u], d, `${i}.${u}`, e, r));\n let o = (u, d) => $e(u, d, r), a = (u, d) => Array.isArray(u) ? u.map((c, f) => o(c, `${d}[${f}]`)) : u;\n if (e === "file-tree" && n.items !== void 0 && (n.items = we(n.items)), e === "stat" && Array.isArray(n.items) && n.label === void 0 && n.value === void 0) {\n let u = Tn(n.items, i, o);\n if (u !== null) return r.push({ kind: "alias", path: `${i}.items`, message: `${i}.items normalized into a row of \'stat\' nodes`, type: e, field: "items", canonical: "row" }), { type: "row", items: u, ...n.span !== void 0 ? { span: n.span } : {} };\n }\n if (e === "row" || e === "col" || e === "grid" || e === "card" || e === "file-tree" || e === "timeline" || e === "breadcrumb") e !== "file-tree" && e !== "timeline" && e !== "breadcrumb" && (n.items = a(n.items, `${i}.items`));\n else if (e === "list" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n if (Ae(u)) return o(u, `${i}.items[${d}]`);\n if (Array.isArray(u) && u.length === 1 && typeof u[0] == "string") return u[0];\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c }, g = `${i}.items[${d}]`;\n for (let [x, $] of Object.entries(Rn)) {\n if (!(x in f)) continue;\n let J = $ in f;\n J || (f[$] = f[x]), delete f[x], r.push({ kind: "alias", path: `${g}.${x}`, type: e, field: x, canonical: $, message: J ? `${g}.${x} is ignored because canonical field \'${$}\' is present` : `${g}.${x} normalized/adopted as \'${$}\'` });\n }\n return !("title" in f) && typeof f.desc == "string" && (f.title = f.desc, delete f.desc, r.push({ kind: "alias", path: `${g}.desc`, type: e, field: "desc", canonical: "title", message: `${g}.desc normalized/adopted as \'title\'` })), f;\n });\n else if (e === "keyvalue" && Array.isArray(n.pairs)) n.pairs.length > 0 && n.pairs.every((u) => Array.isArray(u)) && (n.pairs = n.pairs.map((u) => {\n let d = u;\n return { key: d[0], value: d.length > 1 ? d[1] : "" };\n }));\n else if (e === "tabs" && Array.isArray(n.tabs)) n.tabs = n.tabs.map((u, d) => {\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c };\n if ("content" in f) {\n let g = `${i}.tabs[${d}].content`, x = "items" in f;\n x || (f.items = f.content), delete f.content, r.push({ kind: "alias", path: g, message: x ? `${g} is ignored because canonical field \'items\' is present` : `${g} normalized/adopted as \'items\'`, type: e, field: "content", canonical: "items" });\n }\n return f.items = Array.isArray(f.items) ? f.items.map((g, x) => o(g, `${i}.tabs[${d}].items[${x}]`)) : f.items === void 0 ? [] : [o(f.items, `${i}.tabs[${d}].items[0]`)], f;\n });\n else if (e === "accordion" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n let c = O(u);\n return c === void 0 ? u : { ...c, items: Array.isArray(c.items) ? c.items.map((f, g) => o(f, `${i}.items[${d}].items[${g}]`)) : c.items };\n });\n else if (e === "table" && Array.isArray(n.details)) {\n let u = { columns: n.columns, rows: n.rows, types: n.types };\n n.details = n.details.map((d, c) => !Array.isArray(d) || !C(u, c) ? d : d.map((f, g) => o(f, `${i}.details[${c}][${g}]`)));\n }\n return n;\n }\n function Ie(t) {\n let i = [];\n if (typeof t == "string") try {\n let s = JSON.parse(t);\n (O(s) !== void 0 || Array.isArray(s)) && (t = s, i.push({ kind: "alias", path: "spec", message: "double-encoded JSON string unwrapped into a spec value" }));\n } catch {\n }\n Array.isArray(t) && t.length > 0 && (t = { items: t }, i.push({ kind: "alias", path: "items", message: "root array normalized into an items envelope" }));\n let r = O(t);\n if (r === void 0) return { value: t, warnings: i };\n let e = { ...r };\n return N(e) ? { value: $e(e, "spec", i), warnings: i } : (Array.isArray(e.items) && (e.items = e.items.map((s, n) => $e(s, `items[${n}]`, i))), { value: e, warnings: i });\n }\n function F(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function _e(t) {\n let i = F(t);\n return i !== void 0 && typeof i.type == "string";\n }\n function Ge(t, i, r) {\n if (!_e(t)) return;\n let e = t.type, s = T[e];\n if (s === void 0) return;\n r(t, i, s);\n let n = (o, a) => Ge(o, a, r);\n if ((e === "row" || e === "col" || e === "grid" || e === "card") && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "list" && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "tabs" && Array.isArray(t.tabs)) t.tabs.forEach((o, a) => {\n let u = F(o);\n u !== void 0 && (Array.isArray(u.items) ? u.items.forEach((d, c) => n(d, `${i}.tabs[${a}].items[${c}]`)) : n(u.items, `${i}.tabs[${a}].items`));\n });\n else if (e === "accordion" && Array.isArray(t.items)) t.items.forEach((o, a) => {\n let u = F(o);\n u?.items !== void 0 && Array.isArray(u.items) && u.items.forEach((d, c) => n(d, `${i}.items[${a}].items[${c}]`));\n });\n else if (e === "table" && Array.isArray(t.details)) {\n let o = { columns: t.columns, rows: t.rows, types: t.types };\n t.details.forEach((a, u) => {\n Array.isArray(a) && C(o, u) && a.forEach((d, c) => n(d, `${i}.details[${u}][${c}]`));\n });\n }\n }\n function B(t, i, r, e) {\n t.push({ kind: "unknown-field", path: `${i}.${r}`, message: `${i}.${r}: unknown field for \'${e}\'`, type: e, field: r });\n }\n function Y(t, i, r, e, s) {\n let n = F(t);\n if (n !== void 0) {\n for (let o of Object.keys(n)) o in r.fields || B(s, i, o, e);\n for (let [o, a] of Object.entries(r.nested)) {\n let u = n[o];\n Array.isArray(u) ? u.forEach((d, c) => Y(d, `${i}.${o}[${c}]`, a, e, s)) : u !== void 0 && Y(u, `${i}.${o}`, a, e, s);\n }\n }\n }\n function Nn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n Array.isArray(o) ? o.forEach((a, u) => Y(a, `${i}.${s}[${u}]`, n, t.type, e)) : o !== void 0 && Y(o, `${i}.${s}`, n, t.type, e);\n }\n }\n function Pe(t) {\n let i = [], r = F(t);\n if (r === void 0) return i;\n let e = (s, n, o) => {\n for (let a of Object.keys(s)) a === "type" || a in o.fields || B(i, n, a, s.type);\n Nn(s, n, o, i), s.type === "list" && Array.isArray(s.items) && s.items.forEach((a, u) => {\n if (_e(a)) return;\n let d = F(a);\n if (d !== void 0) for (let c of Object.keys(d)) {\n if (c === "title" || c === "desc") continue;\n let f = `${n}.items[${u}]`;\n i.push({ kind: "unknown-field", path: `${f}.${c}`, message: `${f}.${c}: list items render \'title\' and \'desc\' only \\u2014 \'${c}\' is dropped`, type: "list", field: c });\n }\n });\n };\n if (Array.isArray(r.items) && !N(r)) {\n for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n r.items.forEach((s, n) => Ge(s, `items[${n}]`, e));\n } else if (typeof r.type == "string") Ge(r, "spec", e);\n else for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n return i;\n }\n function ve(t, i) {\n let r = (s, n, o) => {\n o > m.maxDepth || s.forEach((a, u) => e(a, `${n}[${u}]`, o));\n }, e = (s, n, o) => {\n if (!(o > m.maxDepth) && (i(s, n), !(o >= m.maxDepth))) switch (s.type) {\n case "row":\n case "col":\n case "grid":\n case "card":\n r(s.items, `${n}.items`, o + 1);\n break;\n case "tabs":\n s.tabs.forEach((a, u) => r(a.items, `${n}.tabs[${u}].items`, o + 1));\n break;\n case "accordion":\n s.items.forEach((a, u) => r(a.items, `${n}.items[${u}].items`, o + 1));\n break;\n case "list":\n s.items.forEach((a, u) => {\n a !== null && typeof a == "object" && "type" in a && e(a, `${n}.items[${u}]`, o + 1);\n });\n break;\n case "table":\n s.details?.slice(0, I(s).length).forEach((a, u) => {\n a !== null && C(s, u) && r(a, `${n}.details[${u}]`, o + 1);\n });\n break;\n }\n };\n r(t.items, "items", 0);\n }\n function Re(t) {\n let i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), e = [], s = [];\n ve(t, (n, o) => {\n if (n.type === "submit") {\n n.groups !== void 0 && s.push({ groups: n.groups, path: o });\n return;\n }\n let a, u;\n switch (n.type) {\n case "radio":\n if (n.group === void 0) return;\n a = { kind: "radio", key: n.group, label: n.label ?? n.group, options: n.options.slice(0, m.maxOptions), ...n.answer === void 0 ? {} : { answer: n.answer }, ...n.explanation === void 0 ? {} : { explanation: n.explanation } }, u = `${o}.group`;\n break;\n case "checkbox":\n if (n.group === void 0) return;\n a = { kind: "checkbox", key: n.group }, u = `${o}.group`;\n break;\n case "input":\n case "textarea":\n case "select":\n case "slider":\n if (n.id === void 0) return;\n a = { kind: "field", key: n.id, fieldType: n.type, secret: n.type === "input" && n.inputType === "password" }, u = `${o}.id`;\n break;\n default:\n return;\n }\n if (a === void 0) return;\n let d = i.get(a.key);\n if (d !== void 0) {\n (d.kind !== "checkbox" || a.kind !== "checkbox") && e.push(`${u} conflicts with ${r.get(a.key)}: submission key \'${a.key}\' is already used`);\n return;\n }\n i.set(a.key, a), r.set(a.key, u);\n });\n for (let { groups: n, path: o } of s) {\n let a = /* @__PURE__ */ new Set();\n n.forEach((u, d) => {\n let c = `${o}.groups[${d}]`;\n a.has(u) && e.push(`${c}: duplicate submission member \'${u}\'`), a.add(u);\n let f = i.get(u);\n f === void 0 ? e.push(`${c}: submit.groups references unknown submission member \'${u}\'`) : f.kind === "field" && f.secret && e.push(`${c}: submit.groups cannot require secret field \'${u}\'`);\n });\n }\n return { registry: { members: i }, diagnostics: e };\n }\n function En(t, i) {\n return typeof t == "string" && i.includes(t);\n }\n function p(t, i) {\n return typeof t == "string" ? t.slice(0, i) : void 0;\n }\n var Dn = /^(?:#[\\da-fA-F]{3,8}|rgba?\\([^)]{0,64}\\)|hsla?\\([^)]{0,64}\\)|var\\(--dsw-[\\w-]+(?:,\\s*#[0-9a-fA-F]{3,8})?\\))$/;\n function E(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n return i.length <= 64 && Dn.test(i) ? i : void 0;\n }\n function qe(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i.length > 2048)) return /^https?:\\/\\//i.test(i) || /^mailto:[^@\\s]+@[^@\\s]+$/i.test(i) ? i : void 0;\n }\n function K(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i === "" || i.length > 2048)) {\n if (/^https?:\\/\\//i.test(i)) return i;\n if (!(/^[a-z][a-z0-9+.-]*:/i.test(i) || /^[/\\\\]{2}/.test(i))) return i;\n }\n }\n function k(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, t)) : void 0;\n }\n function D(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, Math.trunc(t))) : void 0;\n }\n function w(t, i) {\n return En(t, i) ? t : void 0;\n }\n function y(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function l(t, i) {\n return i === void 0 ? {} : { [t]: i };\n }\n function On(t) {\n if (t.length > 2048) return;\n let i = t.indexOf("#"), r = i < 0 ? t : t.slice(0, i);\n if (r.includes("?")) return;\n let e;\n try {\n e = decodeURIComponent(r);\n } catch {\n return;\n }\n if (e === "" || /[\\u0000-\\u001f\\u007f]/.test(e) || /^[\\\\/]{2}/.test(e) || /^[a-z][a-z\\d+.-]*:/i.test(e) && !/^[a-z]:[\\\\/]/i.test(e)) return;\n if (i < 0) return { path: e };\n let s = /^L([1-9]\\d*)(?:-L([1-9]\\d*))?$/.exec(t.slice(i + 1));\n if (s === null) return;\n let n = Number(s[1]), o = s[2] === void 0 ? n : Number(s[2]);\n if (!(!Number.isSafeInteger(n) || !Number.isSafeInteger(o) || o < n)) return { path: e, line: n };\n }\n function ze(t) {\n let i = qe(t);\n if (i !== void 0) return { type: "external", href: i };\n if (typeof t != "string") return { type: "invalid" };\n let r = On(t.trim());\n return r === void 0 ? { type: "invalid" } : { type: "file", file: r };\n }\n function H(t, i) {\n switch (i) {\n case "string":\n return typeof t == "string";\n case "string-or-null":\n return t === null || typeof t == "string";\n case "number":\n return typeof t == "number" && Number.isFinite(t);\n case "boolean":\n return typeof t == "boolean";\n case "nodes":\n return Array.isArray(t);\n case "array":\n return Array.isArray(t);\n case "object":\n return y(t) !== void 0;\n case "unknown":\n return true;\n }\n }\n function j(t) {\n switch (t) {\n case "string-or-null":\n return "a string or null";\n case "number":\n return "a finite number";\n case "boolean":\n return "a boolean";\n case "nodes":\n case "array":\n return "an array";\n case "object":\n return "an object";\n case "unknown":\n return "a value";\n default:\n return "a string";\n }\n }\n function v(t, i, r) {\n return t.some((e) => e.startsWith(`${i}.${r} `) || e.includes(`\'${r}\'`) || e.includes(`requires ${r}`));\n }\n function Ke(t, i, r, e, s = []) {\n for (let [n, o] of Object.entries(r.fields)) s.includes(n) || t[n] === void 0 || !H(t[n], o) && !v(e, i, n) && e.push(`${i}.${n} must be ${j(o)}`);\n for (let [n, o] of Object.entries(r.enums)) s.includes(n) || t[n] === void 0 || !H(t[n], "string") || !o.includes(t[n]) && !v(e, i, n) && e.push(`${i}.${n} must be one of ${o.join(", ")}`);\n }\n function W(t, i, r, e) {\n let s = y(t);\n if (s === void 0) {\n e.push(`${i} must be an object`);\n return;\n }\n for (let n of r.required) {\n let o = r.fields[n];\n s[n] === void 0 ? v(e, i, n) || e.push(`${i}: requires ${n}${o === void 0 ? "" : ` (${j(o)})`}`) : o !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n }\n for (let [n, o] of Object.entries(r.fields)) s[n] !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n for (let [n, o] of Object.entries(r.enums)) s[n] !== void 0 && typeof s[n] == "string" && !o.includes(s[n]) && (v(e, i, n) || e.push(`${i}.${n} must be one of ${o.join(", ")}`));\n for (let [n, o] of Object.entries(r.nested)) {\n let a = s[n];\n a !== void 0 && (Array.isArray(a) ? a.forEach((u, d) => W(u, `${i}.${n}[${d}]`, o, e)) : W(a, `${i}.${n}`, o, e));\n }\n }\n function Mn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n o !== void 0 && (Array.isArray(o) ? o.forEach((a, u) => W(a, `${i}.${s}[${u}]`, n, e)) : W(o, `${i}.${s}`, n, e));\n }\n }\n function He(t) {\n let i = t.rows !== void 0 ? t.rows : t.data;\n return !Array.isArray(i) || i.length === 0 ? false : Array.isArray(i[0]);\n }\n function In(t, i, r, e) {\n let s = String(t.type), n = (a) => v(e, i, a), o = s === "table" && He(t) ? "columns" : null;\n for (let a of r.required) {\n let u = r.fields[a];\n if (u === void 0 || t[a] === void 0) {\n a !== o && !n(a) && e.push(`${i}: type \'${s}\' requires ${a}${u === void 0 ? "" : ` (${j(u)})`}`);\n continue;\n }\n !H(t[a], u) && !n(a) && e.push(`${i}.${a} must be ${j(u)}`);\n }\n Ke(t, i, r, e, ["type"]);\n for (let a of r.oneOfRequired) !a.some((u) => t[u] !== void 0) && !e.some((u) => u.includes(`requires ${a.join(" or ")}`)) && e.push(`${i}: type \'${s}\' requires one of ${a.join(" or ")}`);\n for (let a of r.conditionalRequired) if (t[a.when.field] === a.when.equals) for (let u of a.required) t[u] === void 0 && !n(u) && e.push(`${i}: type \'${s}\' requires ${u}${a.message === void 0 ? "" : ` (${a.message})`}`);\n Mn(t, i, r, e);\n }\n function _(t, i, r) {\n if (!Array.isArray(t)) return [];\n let e = [];\n for (let s of t) {\n if (i.remaining <= 0) break;\n i.remaining -= 1;\n let n = Je(s, i, r);\n n !== null && e.push(n);\n }\n return e;\n }\n function Fe(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 12)) {\n let e = E(r);\n e !== void 0 && i.push(e);\n }\n return i.length > 0 ? i : void 0;\n }\n function je(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 60)) {\n let e = typeof r == "number" ? r : Number(r);\n if (!Number.isFinite(e)) return;\n i.push(e);\n }\n return i.length >= 2 ? i : void 0;\n }\n function Je(t, i, r) {\n let e = _n(t, i, r);\n if (e === null) return null;\n let s = D(y(t)?.span, 2, 12), n = p(y(t)?.id, 64);\n return { ...e, ...l("span", s), ...l("id", n) };\n }\n function _n(t, i, r) {\n if (r > m.maxDepth) return null;\n let e = y(t);\n if (e === void 0) return null;\n let s = e.type;\n if (typeof s != "string") return null;\n switch (s) {\n case "text": {\n let n = p(e.content, m.maxString) ?? p(e.text, m.maxString);\n return n === void 0 ? null : { type: "text", content: n, ...l("copyable", e.copyable === true ? true : void 0), ...l("title", p(e.title, m.maxString)), ...l("size", w(e.size, ne)), ...l("center", e.center === true ? true : void 0) };\n }\n case "row":\n return { type: "row", items: _(e.items, i, r + 1), ...l("wrap", e.wrap === true ? true : void 0), ...l("spacer", e.spacer === true ? true : void 0) };\n case "col":\n return { type: "col", items: _(e.items, i, r + 1), ...l("gap", k(e.gap, 0, 96)) };\n case "grid":\n return { type: "grid", cols: D(e.cols, 1, m.maxGridCols) ?? 1, items: _(e.items, i, r + 1) };\n case "card":\n return { type: "card", items: _(e.items, i, r + 1), ...l("title", p(e.title, m.maxString)), ...l("tone", w(e.tone, be)), ...l("accent", E(e.accent)) };\n case "button": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "button", label: n, ...l("tone", w(e.tone, te)), ...l("full", e.full === true ? true : void 0), ...l("small", e.small === true ? true : void 0), ...l("icon", p(e.icon, 64)), ...l("action", p(e.action, 200)) };\n }\n case "input":\n return { type: "input", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("value", p(e.value, m.maxString)), ...l("inputType", w(e.inputType, re)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "select": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "select", options: n, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("id", p(e.id, 200)) };\n }\n case "checkbox": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "checkbox", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)) };\n }\n case "link": {\n let n = p(e.label, m.maxString);\n if (n === void 0) return null;\n let o = ze(e.href), a = o.type === "external" ? o.href : o.type === "file" ? String(e.href).trim() : void 0;\n return { type: "link", label: n, ...l("href", a) };\n }\n case "image": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "image", src: n, ...l("alt", p(e.alt, m.maxString)) };\n }\n case "audio": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "audio", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("loop", e.loop === true ? true : void 0) };\n }\n case "video": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "video", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("poster", K(e.poster)), ...l("loop", e.loop === true ? true : void 0), ...l("muted", e.muted === true ? true : void 0), ...l("aspectRatio", w(e.aspectRatio, ae)) };\n }\n case "badge": {\n let n = p(e.label, m.maxString) ?? p(e.text, m.maxString) ?? p(e.value, m.maxString);\n return n === void 0 ? null : { type: "badge", label: n, ...l("tone", w(e.tone, ie)), ...l("icon", p(e.icon, 64)) };\n }\n case "hero": {\n let n = p(e.title, m.maxString);\n return n === void 0 ? null : { type: "hero", title: n, ...l("subtitle", p(e.subtitle, m.maxString)), ...l("value", p(e.value, 128)), ...l("label", p(e.label, m.maxString)), ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("tone", w(e.tone, he)) };\n }\n case "stat": {\n let n = p(e.label, m.maxString), o = p(e.value, 128);\n return n === void 0 || o === void 0 ? null : { type: "stat", label: n, value: o, ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("size", e.size === "hero" ? "hero" : void 0) };\n }\n case "progress": {\n let n = k(e.value, 0, 100);\n return n === void 0 ? null : { type: "progress", value: n, ...l("label", p(e.label, m.maxString)), ...l("valueLabel", p(e.valueLabel, 64)), ...l("variant", w(e.variant, ye)), ...l("target", k(e.target, 0, 100)) };\n }\n case "divider":\n return { type: "divider" };\n case "spacer":\n return { type: "spacer" };\n case "avatar": {\n let n = p(e.name, 64);\n return n === void 0 ? null : { type: "avatar", name: n, ...l("color", E(e.color)) };\n }\n case "list": {\n let n = Pn(e.items, m.maxListItems, i, r + 1);\n return n === void 0 ? null : { type: "list", items: n, ...l("filter", p(e.filter, 64)) };\n }\n case "table": {\n let n = ke(e);\n if (n === null) return null;\n let { columns: o, rows: a } = n, u = Array.isArray(e.types) ? e.types : void 0, d = u === void 0 ? void 0 : o.map((g, x) => {\n let $ = u[x];\n return typeof $ == "string" && Ee.includes($) ? $ : "text";\n }), c = Array.isArray(e.details) ? e.details : void 0, f = c === void 0 ? void 0 : a.map((g, x) => {\n if (!C({ columns: o, rows: a, types: d }, x)) return null;\n let $ = _(c[x], i, r + 1);\n return $.length === 0 ? null : $;\n });\n return { type: "table", columns: o, rows: a, ...l("types", d), ...l("total", e.total === true ? true : void 0), ...l("export", e.export === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("filterColumn", D(e.filterColumn, 0, m.maxTableCols - 1)), ...l("sortField", p(e.sortField, 64)), ...l("details", f !== void 0 && f.some((g) => g !== null) ? f : void 0) };\n }\n case "chart": {\n let n = Te(e.data, m.maxChartPoints), o = Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0;\n return n === void 0 && o === void 0 ? null : { type: "chart", data: n ?? [], ...l("kind", w(e.kind, U)), ...l("series", o), ...l("horizontal", e.horizontal === true ? true : void 0), ...l("stacked", e.stacked === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("palette", Fe(e.palette)) };\n }\n case "tabs": {\n let n = vn(e.tabs, i, r);\n return n === void 0 ? null : { type: "tabs", tabs: n };\n }\n case "plot": {\n let n = qn(e.series, m.maxPlotSeries);\n return n === void 0 ? null : { type: "plot", series: n, ...l("xMin", k(e.xMin, -1e6, 1e6)), ...l("xMax", k(e.xMax, -1e6, 1e6)), ...l("yMin", k(e.yMin, -1e9, 1e9)), ...l("yMax", k(e.yMax, -1e9, 1e9)), ...l("title", p(e.title, m.maxString)) };\n }\n case "callout": {\n let n = p(e.content, m.maxString);\n return n === void 0 ? null : { type: "callout", content: n, ...l("tone", w(e.tone, se)), ...l("title", p(e.title, m.maxString)) };\n }\n case "steps": {\n let n = zn(e.steps);\n return n === void 0 ? null : { type: "steps", steps: n, ...l("current", D(e.current, 0, n.length)) };\n }\n case "keyvalue": {\n let n = Fn(e.pairs, m.maxKeyValuePairs);\n return n === void 0 ? null : { type: "keyvalue", pairs: n };\n }\n case "diff": {\n let n = jn(e.diffs);\n return n === void 0 ? null : { type: "diff", diffs: n };\n }\n case "json":\n return "value" in e ? { type: "json", value: e.value } : null;\n case "code": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "code", code: n, ...l("lang", p(e.lang, 64)), ...l("title", p(e.title, m.maxString)), ...l("wrap", e.wrap === true ? true : void 0) };\n }\n case "radio": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "radio", options: n, ...l("label", p(e.label, m.maxString)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)), ...l("answer", typeof e.answer == "number" && Number.isFinite(e.answer) && e.answer >= 0 && e.answer < n.length ? Math.trunc(e.answer) : typeof e.answer == "string" ? e.answer.slice(0, 512) : void 0), ...l("explanation", p(e.explanation, m.maxString)) };\n }\n case "submit": {\n let n = p(e.label, m.maxString), o = p(e.action, 200);\n return n === void 0 ? null : { type: "submit", label: n, ...l("action", o), ...l("resetAction", p(e.resetAction, 200)), ...l("groups", Q(e.groups, m.maxOptions, 200)) };\n }\n case "switch": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "switch", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)) };\n }\n case "slider": {\n let n = k(e.min, -1e9, 1e9) ?? 0, o = k(e.max, -1e9, 1e9) ?? 100, a = Math.min(n, o), u = Math.max(n, o), d = k(e.step, 1e-9, Math.max(u - a, 1e-9)), c = k(e.value, a, u) ?? a;\n return { type: "slider", min: a, max: u, ...l("step", d), value: c, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n }\n case "textarea":\n return { type: "textarea", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("rows", D(e.rows, 1, 30)), ...l("value", p(e.value, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "accordion": {\n let n = Ln(e.items, i, r);\n return n === void 0 ? null : { type: "accordion", items: n };\n }\n case "copy": {\n let n = p(e.text, m.maxCode);\n return n === void 0 ? null : { type: "copy", text: n, ...l("label", p(e.label, 128)) };\n }\n case "svg": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "svg", code: n, ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)) };\n }\n case "mermaid": {\n let n = p(e.code, m.maxMermaid);\n return n === void 0 ? null : { type: "mermaid", code: n };\n }\n case "scene3d": {\n let n = Vn(e.meshes);\n return n === void 0 ? null : { type: "scene3d", meshes: n, ...l("title", p(e.title, m.maxString)), ...l("ambient", k(e.ambient, 0, 2)), ...l("background", E(e.background)) };\n }\n case "diagram":\n return Bn(e);\n case "timeline": {\n let n = Yn(e.items, m.maxTimelineItems);\n return n === void 0 ? null : { type: "timeline", items: n };\n }\n case "file-tree": {\n let n = Qn(e.items, m.maxListItems);\n return n === void 0 ? null : { type: "file-tree", items: n };\n }\n case "breadcrumb": {\n let n = Q(e.items, m.maxBreadcrumbItems, m.maxString);\n return n === void 0 ? null : { type: "breadcrumb", items: n };\n }\n case "quiz": {\n let n = p(e.question, m.maxString), o = Zn(e.options, e.answer);\n return n === void 0 || o === void 0 ? null : { type: "quiz", question: n, options: o, ...l("explanation", p(e.explanation, m.maxString)), ...l("id", p(e.id, 200)), ...l("action", p(e.action, 200)) };\n }\n case "echart": {\n let n = e.data !== void 0 ? Te(e.data, m.maxChartPoints) : void 0, o = e.series !== void 0 && Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0, a = Array.isArray(e.links) ? e.links.slice(0, m.maxChartPoints).flatMap((c) => {\n let f = y(c), g = f === void 0 ? void 0 : p(f.from, 64), x = f === void 0 ? void 0 : p(f.to, 64);\n return g === void 0 || x === void 0 ? [] : [{ from: g, to: x, ...l("value", k(f.value, 0, 1e9)) }];\n }) : void 0, u = e.option !== void 0 ? Ce(e.option, 0, { count: m.maxEChartOptionNodes }) : void 0, d = u === void 0 || typeof u != "object" || u === null || Array.isArray(u) ? void 0 : u;\n return d === void 0 && n === void 0 && o === void 0 && (a === void 0 || a.length === 0) ? null : { type: "echart", ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)), ...l("preset", w(e.preset, ge)), ...l("data", n), ...l("series", o), ...l("links", a !== void 0 && a.length > 0 ? a : void 0), ...l("palette", Fe(e.palette)), ...l("option", d) };\n }\n default:\n return t;\n }\n }\n function Q(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n if (typeof s == "string") e.push(s.slice(0, r));\n else if (s !== null && typeof s == "object") {\n let n = s, o = typeof n.label == "string" ? n.label : typeof n.value == "string" ? n.value : typeof n.title == "string" ? n.title : JSON.stringify(s);\n e.push(o.slice(0, r));\n }\n }\n return e;\n }\n function Pn(t, i, r, e) {\n if (!Array.isArray(t)) return;\n let s = [];\n for (let n of t) {\n if (s.length >= i) break;\n if (typeof n == "string") {\n s.push(n.slice(0, m.maxString));\n continue;\n }\n let o = y(n);\n if (o !== void 0 && typeof o.type == "string") {\n if (r.remaining <= 0) break;\n r.remaining -= 1;\n let u = Je(o, r, e);\n u !== null && s.push(u);\n continue;\n }\n let a = o === void 0 ? void 0 : p(o.title, m.maxString);\n a !== void 0 && s.push({ title: a, ...l("desc", p(o?.desc, m.maxString)) });\n }\n return s;\n }\n function Te(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.label, 128), o = s === void 0 ? void 0 : k(s.value, -1e12, 1e12);\n n === void 0 || o === void 0 || r.push({ label: n, value: o, ...l("color", s === void 0 ? void 0 : E(s.color)) });\n }\n return r;\n }\n function Le(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128), a = n === void 0 ? void 0 : Te(n.data, r);\n o === void 0 || a === void 0 || e.push({ label: o, data: a, ...l("color", n === void 0 ? void 0 : E(n.color)) });\n }\n return e;\n }\n function vn(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxTabs) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128);\n if (o === void 0 || n === void 0) continue;\n let a = n.items !== void 0 ? n.items : n.content !== void 0 ? Array.isArray(n.content) ? n.content : [n.content] : void 0;\n e.push({ label: o, items: _(a, i, r + 1) });\n }\n return e;\n }\n function qn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.expr, 512);\n if (n === void 0 || s === void 0) continue;\n let o = [];\n if (Array.isArray(s.params)) for (let a of s.params) {\n if (o.length >= m.maxPlotParams) break;\n let u = y(a), d = u === void 0 ? void 0 : p(u.name, 64), c = u === void 0 ? void 0 : k(u.value, -1e9, 1e9);\n d === void 0 || c === void 0 || o.push({ name: d, value: c, ...l("min", u === void 0 ? void 0 : k(u.min, -1e9, 1e9)), ...l("max", u === void 0 ? void 0 : k(u.max, -1e9, 1e9)), ...l("step", u === void 0 ? void 0 : k(u.step, 1e-9, 1e9)), ...l("animateTo", u === void 0 ? void 0 : k(u.animateTo, -1e9, 1e9)), ...l("durationMs", u === void 0 ? void 0 : k(u.durationMs, 1, 12e4)), ...l("loop", u === void 0 ? void 0 : u.loop === true ? true : void 0) });\n }\n r.push({ expr: n, ...l("label", p(s.label, 128)), ...l("color", E(s.color)), ...l("kind", w(s.kind, oe)), ...l("params", o.length > 0 ? o : void 0) });\n }\n return r;\n }\n function zn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxSteps) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.title, 256);\n s !== void 0 && i.push({ title: s, ...l("desc", e === void 0 ? void 0 : p(e.desc, m.maxString)) });\n }\n return i;\n }\n function Fn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.key, 256), o = s === void 0 ? void 0 : p(s.value, m.maxString);\n n === void 0 || o === void 0 || r.push({ key: n, value: o });\n }\n return r;\n }\n function jn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= 24) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.path, 1024), n = e === void 0 ? void 0 : p(e.newText, 2e4);\n if (s === void 0 || n === void 0) continue;\n let o = e === void 0 ? void 0 : e.oldText;\n i.push({ path: s, newText: n, oldText: o === null || typeof o != "string" ? null : o.slice(0, 2e4) });\n }\n return i;\n }\n function Ln(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxAccordionItems) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.title, 256);\n o === void 0 || n === void 0 || e.push({ title: o, items: _(n.items, i, r + 1) });\n }\n return e;\n }\n function Vn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxMeshes) break;\n let e = y(r), s = e === void 0 ? void 0 : w(e.shape, ue);\n if (s === void 0) continue;\n let n = e === void 0 ? void 0 : k(e.scale, -1e6, 1e6) ?? Z(e.scale), o = e === void 0 ? void 0 : k(e.size, -1e6, 1e6) ?? Z(e.size);\n i.push({ shape: s, ...l("color", e === void 0 ? void 0 : E(e.color)), ...l("position", e === void 0 ? void 0 : Z(e.position)), ...l("rotation", e === void 0 ? void 0 : Z(e.rotation)), ...l("scale", n), ...l("size", o) });\n }\n return i;\n }\n function Z(t) {\n if (!Array.isArray(t) || t.length !== 3) return;\n let [i, r, e] = t;\n if (!(typeof i != "number" || !Number.isFinite(i) || typeof r != "number" || !Number.isFinite(r) || typeof e != "number" || !Number.isFinite(e))) return [Math.min(1e6, Math.max(-1e6, i)), Math.min(1e6, Math.max(-1e6, r)), Math.min(1e6, Math.max(-1e6, e))];\n }\n function P(t, i, r) {\n return Math.min(r, Math.max(i, Math.round(t / 4) * 4));\n }\n function Kn(t) {\n if (!Array.isArray(t)) return;\n let i = [], r = /* @__PURE__ */ new Set();\n for (let e of t) {\n if (i.length >= m.maxDiagramNodes) break;\n let s = y(e);\n if (s === void 0) continue;\n let n = p(s.id, 128), o = p(s.label, m.maxString);\n if (n === void 0 || o === void 0 || r.has(n)) continue;\n r.add(n);\n let a = w(s.type, ce), u = s.x === void 0 ? void 0 : P(k(s.x, -1e6, 1e6) ?? 0, 0, 1e6), d = s.y === void 0 ? void 0 : P(k(s.y, -1e6, 1e6) ?? 0, 0, 1e6), c = s.w === void 0 ? void 0 : P(k(s.w, -1e6, 1e6) ?? 96, 40, 2e3), f = s.h === void 0 ? void 0 : P(k(s.h, -1e6, 1e6) ?? 48, 24, 1200);\n i.push({ id: n, label: o, ...l("sub", p(s.sub, 256)), ...l("type", a), ...l("x", u), ...l("y", d), ...l("w", c), ...l("h", f), ...l("tag", p(s.tag, 32)) });\n }\n return i;\n }\n function Hn(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramEdges) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.from, 128), n = p(e.to, 128);\n s === void 0 || n === void 0 || i.push({ from: s, to: n, ...l("label", p(e.label, m.maxDiagramLabel)), ...l("kind", w(e.kind, pe)), ...l("route", w(e.route, me)) });\n }\n return i;\n }\n function Jn(t) {\n let i = y(t);\n if (i === void 0) return;\n let r = {};\n for (let e of ["paper", "paper-2", "ink", "muted", "soft", "rule", "accent", "accent-tint", "link"]) {\n let s = E(i[e]);\n s !== void 0 && (r[e] = s);\n }\n return Object.keys(r).length === 0 ? void 0 : r;\n }\n function Un(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramZones) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.label, 64);\n s !== void 0 && i.push({ label: s, ...l("x", e.x === void 0 ? void 0 : P(k(e.x, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("y", e.y === void 0 ? void 0 : P(k(e.y, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("w", e.w === void 0 ? void 0 : P(k(e.w, -1e6, 1e6) ?? 100, 40, 2e3)), ...l("h", e.h === void 0 ? void 0 : P(k(e.h, -1e6, 1e6) ?? 100, 40, 1200)) });\n }\n return i;\n }\n function Bn(t) {\n let i = y(t);\n if (i === void 0) return null;\n let r = w(i.kind, de);\n if (r === void 0) return null;\n let e = Kn(i.nodes);\n if (e === void 0) return null;\n let s = Hn(i.edges);\n if (s === void 0) return null;\n let n = Un(i.zones);\n return n === void 0 ? null : { type: "diagram", kind: r, nodes: e, edges: s, ...l("zones", n.length > 0 ? n : void 0), ...l("variant", w(i.variant, fe)), ...l("title", p(i.title, 256)), ...l("theme", Jn(i.theme)) };\n }\n function Yn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.title, 256);\n n !== void 0 && r.push({ title: n, ...l("desc", s === void 0 ? void 0 : p(s.desc, m.maxString)), ...l("time", s === void 0 ? void 0 : p(s.time, 128)) });\n }\n return r;\n }\n function Qn(t, i) {\n return Ue(t, i, m.maxTreeDepth);\n }\n function Ue(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.name, 256);\n if (o === void 0) continue;\n let a = n !== void 0 && r > 0 && Array.isArray(n.children) ? Ue(n.children, i, r - 1) : void 0;\n e.push({ name: o, ...l("type", n === void 0 ? void 0 : w(n.type, le)), ...l("children", a) });\n }\n return e;\n }\n function Zn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let s of t) {\n if (r.length >= m.maxQuizOptions) break;\n let n = y(s), o = typeof s == "string" ? p(s, 512) : n === void 0 ? void 0 : p(n.label, 512);\n o !== void 0 && r.push({ label: o, ...l("correct", n === void 0 ? void 0 : n.correct === true ? true : void 0), ...l("feedback", n === void 0 ? void 0 : p(n.feedback, m.maxString)) });\n }\n if (r.length === 0) return;\n if (r.some((s) => s.correct === true)) return r;\n let e = typeof i == "number" && Number.isFinite(i) ? Math.trunc(i) : typeof i == "string" ? r.findIndex((s) => s.label === i.slice(0, 512)) : -1;\n return e < 0 || e >= r.length ? r : r.map((s, n) => n === e ? { ...s, correct: true } : s);\n }\n var Wn = /<(?:script|img|svg|iframe|video|audio|object|embed|source)\\b|on[a-z]+\\s*=|javascript:/i;\n function Ce(t, i, r) {\n if (r.count <= 0 || (r.count -= 1, i > m.maxEChartOptionDepth)) return;\n if (typeof t == "string") {\n let n = t.slice(0, m.maxString);\n return n.toLowerCase().includes("url(") || Wn.test(n) ? void 0 : n;\n }\n if (typeof t == "number" && Number.isFinite(t) || typeof t == "boolean") return t;\n if (t === null) return null;\n if (Array.isArray(t)) {\n let n = Math.min(t.length, m.maxEChartArrayLen), o = [];\n for (let a = 0; a < n; a++) {\n let u = Ce(t[a], i + 1, r);\n u !== void 0 && o.push(u);\n }\n return o.length > 0 || t.length === 0 ? o : void 0;\n }\n let e = y(t);\n if (e === void 0) return;\n let s = {};\n for (let [n, o] of Object.entries(e)) {\n let a = Ce(o, i + 1, r);\n a !== void 0 && (n === "tooltip" && typeof a == "object" && a !== null && !Array.isArray(a) && (a.renderMode = "richText"), s[n] = a);\n }\n return Object.keys(s).length > 0 || Object.keys(e).length === 0 ? s : void 0;\n }\n function Be(t) {\n let i = y(t);\n if (i === void 0) return null;\n if (N(t)) {\n let e = z(t);\n return e === null ? null : Be(e);\n }\n if (!Array.isArray(i.items)) return null;\n let r = { remaining: m.maxNodes };\n return { ...l("title", p(i.title, m.maxString)), ...l("gap", k(i.gap, 0, 96)), ...l("panel", i.panel === true ? true : void 0), ...l("append", i.append === true ? true : void 0), items: _(i.items, r, 0) };\n }\n function Xn(t, i = Number.POSITIVE_INFINITY) {\n let r = 0, e = (n) => {\n if (Array.isArray(n)) for (let o of n) {\n if (r >= i) return;\n r += 1;\n let a = y(o);\n if (a !== void 0) {\n if (a.type === "tabs" && Array.isArray(a.tabs)) for (let u of a.tabs) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if (a.type === "accordion" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if ((a.type === "row" || a.type === "col" || a.type === "grid" || a.type === "card") && Array.isArray(a.items)) e(a.items);\n else if (a.type !== "file-tree") {\n if (a.type === "list" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && typeof d.type == "string" && e([d]);\n }\n else if (a.type === "table" && Array.isArray(a.details)) {\n let u = I(a).length;\n for (let d = 0; d < Math.min(a.details.length, u); d++) {\n if (r >= i) return;\n let c = a.details[d];\n Array.isArray(c) && C(a, d) && e(c);\n }\n }\n }\n }\n }\n }, s = y(t);\n return e(s === void 0 ? [] : s.items), r;\n }\n var et = q;\n function nt(t, i, r) {\n let e = 0, s = (d) => {\n let c = y(d);\n return c !== void 0 && typeof c.type == "string" && et.has(c.type);\n };\n function n(d, c) {\n if (Array.isArray(d)) {\n for (let f = 0; f < d.length; f++) if (o(d[f], `${c}[${f}]`), e >= i) return;\n }\n }\n function o(d, c) {\n if (e >= i || !s(d)) return;\n let f = y(d);\n if (f !== void 0) {\n if (e += 1, r(f, c), f.type === "tabs" && Array.isArray(f.tabs)) for (let g = 0; g < f.tabs.length; g++) a(f.tabs[g], `${c}.tabs[${g}]`);\n else if (f.type === "accordion" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) a(f.items[g], `${c}.items[${g}]`);\n else if ((f.type === "row" || f.type === "col" || f.type === "grid" || f.type === "card") && Array.isArray(f.items)) n(f.items, `${c}.items`);\n else if (f.type === "list" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) o(f.items[g], `${c}.items[${g}]`);\n else if (f.type === "table" && Array.isArray(f.details)) {\n let g = I(f).length;\n for (let x = 0; x < Math.min(f.details.length, g); x++) Array.isArray(f.details[x]) && C(f, x) && n(f.details[x], `${c}.details[${x}]`);\n }\n }\n }\n function a(d, c) {\n let f = y(d);\n if (f === void 0) return;\n let g = f.items !== void 0 ? f.items : f.content;\n Array.isArray(g) ? n(g, `${c}.items`) : o(g, `${c}.items`);\n }\n let u = y(t);\n return u === void 0 || (N(u) && s(t) ? o(t, "spec") : n(u.items, "items")), e;\n }\n function Ye(t, i = Number.POSITIVE_INFINITY) {\n return nt(t, i, () => {\n });\n }\n function tt(t, i = Number.POSITIVE_INFINITY) {\n return Ye(t, i);\n }\n function Qe(t) {\n let i = [], r = y(t);\n if (r === void 0) return { ok: false, errors: ["spec root must be an object"] };\n if (N(t)) {\n let a = z(t);\n return a !== null ? Qe(a) : { ok: false, errors: ["spec.items must be an array"] };\n }\n if (!Array.isArray(r.items)) return { ok: false, errors: ["spec.items must be an array"] };\n Ke(r, "spec", V, i, ["items"]);\n let e = 0, s = false, n = (a, u, d) => {\n if (!s) {\n if (!Array.isArray(a)) {\n i.push(`${d} must be an array`);\n return;\n }\n for (let c = 0; c < a.length; c++) {\n if (s || e >= m.maxNodes) {\n s || (i.push(`spec exceeds ${m.maxNodes} nodes; tail elided`), s = true);\n return;\n }\n e += 1;\n let f = `${d}[${c}]`;\n Xe(a[c], u, f, i, n);\n }\n }\n };\n n(r.items, 0, "items"), i.length === 0 && i.push(...Re(r).diagnostics);\n let o = [...new Set(i)];\n return { ok: o.length === 0, errors: o };\n }\n function Ze(t) {\n let i = Ie(t), r = Be(i.value), e = Qe(i.value), s = Ye(i.value, m.maxNodes + 1), n = r === null ? 0 : tt(r), o = r === null ? 0 : Xn(r), a = e.errors.filter((u) => !u.includes(": unknown type "));\n return r !== null && a.length === 0 && a.push(...Re(r).diagnostics), s > n && a.push(`repair dropped ${s - n} declared native node(s): declared ${s}, rendered ${n}`), { value: i.value, normalized: i.value, repaired: r, spec: r, errors: [...new Set(a)], warnings: [...i.warnings, ...Pe(i.value)], declaredCount: s, renderedCount: o, declaredNativeCount: s, renderedNativeCount: n, renderedTotalCount: o };\n }\n function it(t) {\n return t.errors.length > 0 && t.errors.every((i) => i.startsWith("spec exceeds ") || i.startsWith("repair dropped ")) && t.renderedNativeCount === m.maxNodes && t.declaredNativeCount === m.maxNodes + 1;\n }\n function Ne(t) {\n return t.spec !== null && (t.errors.length === 0 || it(t));\n }\n var rt = /^(items\\[\\d+\\](?:\\.(?:items\\[\\d+\\]|tabs\\[\\d+\\]\\.items\\[\\d+\\]|details\\[\\d+\\](?:\\[\\d+\\])?))*)/;\n function st(t) {\n let i = rt.exec(t);\n return i === null ? null : i[1] ?? null;\n }\n function Ve(t, i) {\n let r = [...i.matchAll(/(?:^|\\.)(items|tabs|details)\\[(\\d+)\\]|\\[(\\d+)\\]/g)];\n if (r.length === 0 || r[r.length - 1][1] === "tabs") return;\n let e = t;\n for (let s = 0; s < r.length; s++) {\n let n = r[s], o = n[1] === void 0 ? e : y(e)?.[n[1]], a = Number(n[2] ?? n[3]);\n if (!Array.isArray(o) || a >= o.length) return;\n if (s === r.length - 1) return { array: o, index: a, preserveIndex: n[1] === "details" };\n if (e = o[a], e === void 0) return;\n }\n }\n function ot(t) {\n try {\n return y(JSON.parse(JSON.stringify(t))) ?? null;\n } catch {\n return null;\n }\n }\n function at(t) {\n if (Ne(t)) return t.spec;\n if (t.spec === null) return null;\n let i = y(t.value);\n if (i === void 0) return null;\n let r = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set();\n for (let d of t.errors) {\n if (d.startsWith("spec exceeds ")) continue;\n let c = st(d);\n c !== null && (d === `${c}.details must not contain more entries than rows` ? e.add(c) : r.add(c));\n }\n if (r.size === 0 && e.size === 0) return null;\n let s = ot(N(i) ? z(i) : i);\n if (s === null) return null;\n let n = [...r].map((d) => Ve(s, d)).filter((d) => d !== void 0), o = [...e].map((d) => Ve(s, d)).filter((d) => d !== void 0);\n for (let { array: d, index: c } of o) {\n let f = y(d[c]);\n f?.type === "table" && Array.isArray(f.details) && (f.details.length = Math.min(f.details.length, I(f).length));\n }\n let a = /* @__PURE__ */ new Map();\n for (let { array: d, index: c, preserveIndex: f } of n) {\n if (f) {\n d[c] = null;\n continue;\n }\n let g = a.get(d);\n g === void 0 ? a.set(d, [c]) : g.push(c);\n }\n for (let [d, c] of a) {\n c.sort((f, g) => g - f);\n for (let f of c) d.splice(f, 1);\n }\n let u = Ze(s);\n return !Ne(u) || u.renderedNativeCount === 0 ? null : u.spec;\n }\n function We(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), (typeof s.value != "number" || !Number.isFinite(s.value)) && r.push(`${n}.value must be a finite number`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`);\n }\n }\n function ut(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`), Array.isArray(s.data) || r.push(`${n}.data must be an array`), We(s.data, `${n}.data`, r);\n }\n }\n function lt(t, i, r) {\n !Array.isArray(t.data) && !Array.isArray(t.series) && r.push(`${i}: type \'chart\' requires data or series (array)`), t.variant !== void 0 && r.push(`${i}.variant is unsupported; use kind`), t.data !== void 0 && !Array.isArray(t.data) && r.push(`${i}.data must be an array`), t.series !== void 0 && !Array.isArray(t.series) && r.push(`${i}.series must be an array`), t.kind !== void 0 && (typeof t.kind != "string" || !U.includes(t.kind)) && r.push(`${i}.kind must be bars, line, or donut`);\n let e = t.kind === void 0 ? "bars" : t.kind, s = Array.isArray(t.series) ? t.series : void 0;\n if (Array.isArray(t.data) && t.data.length === 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data must not be empty`), s !== void 0) {\n s.length === 0 && r.push(`${i}.series must not be empty`), e === "donut" && r.push(`${i}.series is only supported for bars and line`);\n for (let n = 0; n < s.length; n++) {\n let o = y(s[n]);\n o !== void 0 && Array.isArray(o.data) && o.data.length === 0 && r.push(`${i}.series[${n}].data must not be empty`);\n }\n }\n e === "donut" && t.data === void 0 && r.push(`${i}.data is required for donut`), e === "line" && t.data === void 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data is required for line (or provide series)`), We(t.data, `${i}.data`, r), ut(t.series, `${i}.series`, r);\n }\n function dt(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = t[e];\n if (y(s) === void 0) {\n if (!Array.isArray(s)) {\n r.push(`${i}[${e}] must be an array or object`);\n continue;\n }\n for (let n = 0; n < s.length; n++) {\n let o = s[n];\n typeof o != "string" && (typeof o != "number" || !Number.isFinite(o)) && r.push(`${i}[${e}][${n}] must be a string or finite number`);\n }\n }\n }\n }\n function Xe(t, i, r, e, s) {\n if (i > m.maxDepth) {\n e.push(`${r}: exceeds max depth ${m.maxDepth}`);\n return;\n }\n let n = y(t);\n if (n === void 0) {\n e.push(`${r}: must be an object`);\n return;\n }\n let o = n.type;\n if (typeof o != "string") {\n e.push(`${r}: missing string \'type\'`);\n return;\n }\n let a = (c) => {\n n[c] !== void 0 && typeof n[c] != "string" && e.push(`${r}: \'${c}\' must be a string`);\n }, u = (c) => {\n n[c] !== void 0 && (typeof n[c] != "number" || !Number.isFinite(n[c])) && e.push(`${r}: \'${c}\' must be a finite number`);\n };\n switch (o) {\n case "text":\n typeof n.content != "string" && typeof n.text != "string" && e.push(`${r}: type \'text\' requires content or text (string)`), a("content"), a("text");\n break;\n case "row":\n case "col":\n case "card":\n case "grid":\n Array.isArray(n.items) || e.push(`${r}: type \'${o}\' requires items (array)`), s(n.items, i + 1, `${r}.items`), o === "grid" && u("cols");\n break;\n case "button":\n case "checkbox":\n case "link":\n case "switch":\n typeof n.label != "string" && e.push(`${r}: type \'${o}\' requires label (string)`), a("label");\n break;\n case "image":\n case "audio":\n case "video":\n typeof n.src != "string" && e.push(`${r}: type \'${o}\' requires src (string)`), a("src"), a("alt"), o === "video" && a("poster");\n break;\n case "slider":\n a("label"), u("min"), u("max"), u("step"), u("value");\n break;\n case "input":\n case "textarea":\n a("label"), a("placeholder"), a("value");\n break;\n case "select":\n case "radio":\n Array.isArray(n.options) || e.push(`${r}: type \'${o}\' requires options (array)`);\n break;\n case "submit":\n typeof n.label != "string" && e.push(`${r}: type \'submit\' requires label (string)`);\n break;\n case "badge":\n typeof n.label != "string" && typeof n.text != "string" && typeof n.value != "string" && e.push(`${r}: type \'badge\' requires label, text, or value (string)`), a("label"), a("text"), a("value");\n break;\n case "hero":\n typeof n.title != "string" && e.push(`${r}: type \'hero\' requires title (string)`), a("subtitle");\n break;\n case "stat":\n typeof n.label != "string" && e.push(`${r}: type \'stat\' requires label (string)`), typeof n.value != "string" && e.push(`${r}: type \'stat\' requires value (string)`), a("delta");\n break;\n case "progress":\n (typeof n.value != "number" || !Number.isFinite(n.value) || n.value < 0 || n.value > 100) && e.push(`${r}: type \'progress\' requires value (number 0..100)`), u("value");\n break;\n case "avatar":\n typeof n.name != "string" && e.push(`${r}: type \'avatar\' requires name (string)`);\n break;\n case "list":\n if (Array.isArray(n.items) || e.push(`${r}: type \'list\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n f !== void 0 && typeof f.type == "string" && Xe(f, i + 1, `${r}.items[${c}]`, e, s);\n }\n break;\n case "table":\n if (!Array.isArray(n.columns) && !He(n) && e.push(`${r}: type \'table\' requires columns (array)`), Array.isArray(n.rows) || e.push(`${r}: type \'table\' requires rows (array)`), n.types !== void 0 && !Array.isArray(n.types) && e.push(`${r}.types must be an array of column cell types`), n.details !== void 0 && !Array.isArray(n.details) && e.push(`${r}.details must be an array aligned with rows`), Array.isArray(n.details)) {\n let c = { columns: n.columns, rows: n.rows, types: n.types }, f = I(c).length;\n n.details.length > f && e.push(`${r}.details must not contain more entries than rows`);\n for (let g = 0; g < Math.min(n.details.length, f); g++) {\n let x = n.details[g];\n if (!(x === null || !C(c, g))) {\n if (!Array.isArray(x)) {\n e.push(`${r}.details[${g}] must be an array or null`);\n continue;\n }\n s(x, i + 1, `${r}.details[${g}]`);\n }\n }\n }\n dt(n.rows, `${r}.rows`, e);\n break;\n case "chart":\n lt(n, r, e);\n break;\n case "tabs": {\n if (Array.isArray(n.tabs) || e.push(`${r}: type \'tabs\' requires tabs (array)`), Array.isArray(n.tabs)) for (let c = 0; c < n.tabs.length; c++) {\n let f = y(n.tabs[c]);\n if (f === void 0) {\n e.push(`${r}.tabs[${c}] must be an object`);\n continue;\n }\n typeof f.label != "string" && e.push(`${r}.tabs[${c}].label must be a string`), s(f.items, i + 1, `${r}.tabs[${c}].items`);\n }\n break;\n }\n case "plot":\n Array.isArray(n.series) || e.push(`${r}: type \'plot\' requires series (array)`);\n break;\n case "callout":\n typeof n.content != "string" && e.push(`${r}: type \'callout\' requires content (string)`);\n break;\n case "steps":\n Array.isArray(n.steps) || e.push(`${r}: type \'steps\' requires steps (array)`);\n break;\n case "keyvalue":\n Array.isArray(n.pairs) || e.push(`${r}: type \'keyvalue\' requires pairs (array)`);\n break;\n case "diff":\n Array.isArray(n.diffs) || e.push(`${r}: type \'diff\' requires diffs (array)`);\n break;\n case "json":\n "value" in n || e.push(`${r}: type \'json\' requires value`);\n break;\n case "code":\n typeof n.code != "string" && e.push(`${r}: type \'code\' requires code (string)`);\n break;\n case "accordion":\n if (Array.isArray(n.items) || e.push(`${r}: type \'accordion\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n if (f === void 0) {\n e.push(`${r}.items[${c}] must be an object`);\n continue;\n }\n typeof f.title != "string" && e.push(`${r}.items[${c}].title must be a string`), s(f.items, i + 1, `${r}.items[${c}].items`);\n }\n break;\n case "copy":\n typeof n.text != "string" && e.push(`${r}: type \'copy\' requires text (string)`);\n break;\n case "svg":\n typeof n.code != "string" && e.push(`${r}: type \'svg\' requires code (string)`), u("height");\n break;\n case "mermaid":\n typeof n.code != "string" && e.push(`${r}: type \'mermaid\' requires code (string)`);\n break;\n case "scene3d":\n Array.isArray(n.meshes) || e.push(`${r}: type \'scene3d\' requires meshes (array)`);\n break;\n case "timeline":\n Array.isArray(n.items) || e.push(`${r}: type \'timeline\' requires items (array)`);\n break;\n case "file-tree":\n Array.isArray(n.items) || e.push(`${r}: type \'file-tree\' requires items (array)`);\n break;\n case "breadcrumb":\n Array.isArray(n.items) || e.push(`${r}: type \'breadcrumb\' requires items (array)`);\n break;\n case "quiz":\n typeof n.question != "string" && e.push(`${r}: type \'quiz\' requires question (string)`), Array.isArray(n.options) || e.push(`${r}: type \'quiz\' requires options (array)`);\n break;\n case "diagram":\n typeof n.kind != "string" && e.push(`${r}: type \'diagram\' requires kind (string)`), Array.isArray(n.nodes) || e.push(`${r}: type \'diagram\' requires nodes (array)`), n.edges !== void 0 && !Array.isArray(n.edges) && e.push(`${r}: type \'diagram\' requires edges (array) when present`);\n break;\n case "echart":\n n.option === void 0 && n.data === void 0 && n.series === void 0 && (!Array.isArray(n.links) || n.links.length === 0) && e.push(`${r}: type \'echart\' requires option, data, series, or links`), u("height");\n break;\n default:\n e.push(`${r}: unknown type \'${o}\' (custom renderer?)`);\n }\n let d = T[o];\n d !== void 0 && In(n, r, d, e);\n }\n\n // lib/normalize-visual.js\n function normalizeVisual(value, schemas) {\n const unwrap = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) && Object.keys(v2).length === 1 && Array.isArray(v2.item) ? v2.item : v2;\n const scalar2 = (v2, kind) => kind === "number" && typeof v2 === "string" && v2.trim() !== "" && Number.isFinite(Number(v2)) ? Number(v2) : kind === "boolean" && (v2 === "true" || v2 === "false") ? v2 === "true" : v2;\n function record(input, schema, depth = 0) {\n if (!input || typeof input !== "object" || Array.isArray(input) || depth > 32) return input;\n const out2 = { ...input };\n for (const [key, v2] of Object.entries(input)) {\n const target = schema.aliases?.[key] ?? key, kind = schema.fields?.[target];\n if (kind === "array" || kind === "nodes") {\n let array2 = unwrap(v2);\n if (Array.isArray(array2)) array2 = array2.map((x) => kind === "nodes" ? node2(x, depth + 1) : schema.nested?.[target] ? record(x, schema.nested[target], depth + 1) : x);\n out2[key] = array2;\n } else out2[key] = scalar2(v2, kind);\n }\n return out2;\n }\n function node2(v2, depth) {\n if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) return v2;\n if (v2.type === "heading") {\n v2 = { ...v2, type: "text", content: v2.content ?? v2.text ?? v2.title, size: v2.size ?? "h3" };\n delete v2.text;\n delete v2.title;\n }\n if (["card", "row", "col", "grid"].includes(v2.type) && v2.items === void 0 && Array.isArray(unwrap(v2.children))) {\n v2 = { ...v2, items: unwrap(v2.children) };\n delete v2.children;\n }\n const out2 = record(v2, schemas[v2.type] ?? {}, depth);\n if (v2.type === "quiz" && Array.isArray(out2.options)) out2.options = out2.options.map((x) => record(x, { fields: { correct: "boolean" } }));\n if (v2.type === "table") {\n for (const key of ["rows", "data", "items", "details"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((row) => {\n row = unwrap(row);\n return key === "details" && Array.isArray(row) ? row.map((x) => node2(x, depth + 1)) : row;\n });\n }\n if (v2.type === "echart") {\n for (const key of ["data", "series", "links"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((x) => record(x, { fields: { value: "number", data: "array" }, nested: { data: { fields: { value: "number" } } } }));\n }\n return out2;\n }\n if (Array.isArray(value)) return { items: value.map((x) => node2(x, 0)) };\n if (!value || typeof value !== "object") return value;\n const out = { ...value }, items = unwrap(value.items);\n if (Array.isArray(items)) out.items = items.map((x) => node2(x, 0));\n return out;\n }\n\n // lib/visual.js\n var VISUAL_TYPES = Object.freeze([...q]);\n function validateVisual(value) {\n const encoded = JSON.stringify(value);\n if (!encoded || new TextEncoder().encode(encoded).length > 131072) throw Error("DSH UI: visual spec exceeds 128 KiB");\n const processed = Ze(normalizeVisual(value, T)), spec = Ne(processed) ? processed.spec : at(processed);\n if (!spec || !processed.renderedNativeCount) throw Error("DSH UI: visual spec: " + (processed.errors.slice(0, 4).join("; ") || "requires registered components"));\n const critical = /* @__PURE__ */ new Set(["quiz", "radio", "submit", "input", "textarea", "select", "slider", "checkbox", "switch"]);\n const inventory = (items, path = "items", result = []) => {\n for (const [n, v2] of (Array.isArray(items) ? items : []).entries()) {\n if (!v2 || typeof v2 !== "object") continue;\n const at2 = path + "[" + n + "]";\n if (critical.has(v2.type)) result.push({ type: v2.type, id: v2.id ?? v2.group ?? v2.question ?? v2.label, path: at2 });\n if (["row", "col", "grid", "card"].includes(v2.type)) inventory(v2.items, at2 + ".items", result);\n if (v2.type === "tabs") for (const [i, t] of (v2.tabs ?? []).entries()) inventory(t.items, at2 + ".tabs[" + i + "].items", result);\n if (v2.type === "accordion") for (const [i, t] of (v2.items ?? []).entries()) inventory(t.items, at2 + ".items[" + i + "].items", result);\n }\n return result;\n };\n const source = normalizeVisual(value, T), before = inventory(source.items), after = inventory(spec.items);\n const available = [...after], missing = before.filter((v2) => {\n const i = available.findIndex((n) => n.type === v2.type && n.id === v2.id);\n if (i < 0) return true;\n available.splice(i, 1);\n return false;\n });\n if (missing.length) throw Error("DSH UI: critical component was rejected at " + missing.map((v2) => v2.path + " (" + v2.type + ")").join(", ") + ". " + processed.errors.slice(0, 4).join("; "));\n const stableIds = /* @__PURE__ */ new Set();\n function walk(items) {\n for (const n of items) {\n if (n.id !== void 0) {\n if (stableIds.has(n.id)) throw Error("DSH UI: duplicate extended component id " + n.id);\n stableIds.add(n.id);\n }\n if (!VISUAL_TYPES.includes(n.type)) throw Error("DSH UI: unsupported visual component " + n.type);\n if (n.type === "input" && n.inputType === "password") throw Error("DSH UI: do not collect passwords or secrets in a UI");\n if (n.type !== "file-tree" && Array.isArray(n.items)) walk(n.items.filter((x) => x && typeof x === "object" && "type" in x));\n for (const t of n.tabs ?? []) walk(t.items ?? []);\n if (n.type === "table") {\n for (const d of n.details ?? []) if (d) walk(d);\n }\n }\n }\n walk(spec.items);\n delete spec.panel;\n delete spec.append;\n return { spec, warnings: processed.errors.slice(0, 12), count: processed.renderedNativeCount };\n }\n function visualDocument(value) {\n if (Array.isArray(value)) value = { items: value };\n const { spec, warnings } = validateVisual(value), title = spec.title || "\\u53EF\\u89C6\\u5316";\n const texts = [];\n function gather(v2) {\n if (!v2 || typeof v2 !== "object") return;\n for (const [k2, x] of Object.entries(v2)) {\n if (["title", "content", "label", "question", "explanation", "alt"].includes(k2) && typeof x === "string") texts.push(x);\n else if (x && typeof x === "object") Array.isArray(x) ? x.forEach(gather) : gather(x);\n }\n }\n gather(spec);\n return { version: 1, title, fallback: texts.join("\\n").slice(0, 8192) || title, nodes: [{ id: "visual", type: "visual", spec, warnings }] };\n }\n\n // lib/normalize-authoring.js\n var object = (v2) => v2 !== null && typeof v2 === "object" && !Array.isArray(v2);\n var own = (v2, k2) => Object.hasOwn(v2, k2);\n var singleItem = (v2) => object(v2) && Object.keys(v2).length === 1 && own(v2, "item");\n var array = (v2) => {\n let candidate = v2;\n for (let i = 0; i < 8 && singleItem(candidate); i++) candidate = candidate.item;\n return Array.isArray(candidate) ? candidate : v2;\n };\n var numericOps = /* @__PURE__ */ new Set(["add", "sub", "mul", "div", "min", "max", "round", "ceil", "floor", "abs", "lt", "lte", "gt", "gte"]);\n function number(v2) {\n if (typeof v2 !== "string" || !/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(v2.trim())) return v2;\n const n = Number(v2);\n return Number.isFinite(n) && (!Number.isInteger(n) || Number.isSafeInteger(n)) ? n : v2;\n }\n var boolean = (v2) => v2 === "true" ? true : v2 === "false" ? false : v2;\n function expression(e, numeric = false, logical = false) {\n if (!object(e)) return e;\n if (Object.keys(e).length === 1 && own(e, "expr") && typeof e.expr === "number" && Number.isFinite(e.expr)) {\n e.const = e.expr;\n delete e.expr;\n }\n if (own(e, "const")) {\n if (numeric) e.const = number(e.const);\n if (logical) e.const = boolean(e.const);\n }\n if (own(e, "args")) e.args = array(e.args);\n if (Array.isArray(e.args)) e.args.forEach((arg, i) => expression(arg, numericOps.has(e.op) || e.op === "if" && i > 0 && numeric, e.op === "if" && i === 0));\n if (object(e.map?.fields)) Object.values(e.map.fields).forEach((e2) => expression(e2));\n return e;\n }\n function normalizeAuthoring(doc2) {\n if (Array.isArray(doc2)) doc2 = visualDocument(doc2);\n if (object(doc2) && !own(doc2, "nodes") && (own(doc2, "items") || typeof doc2.type === "string")) doc2 = visualDocument(doc2);\n if (!object(doc2)) return doc2;\n if (own(doc2, "version")) doc2.version = number(doc2.version);\n if (object(doc2.presentation) && doc2.presentation.layout === "flow" && (!own(doc2.presentation, "preset") || doc2.presentation.preset === "flow")) {\n doc2.presentation.layout = "guide";\n doc2.presentation.preset = "flow";\n }\n if (object(doc2.state)) for (const k2 of Object.keys(doc2.state)) {\n let s = doc2.state[k2];\n if (typeof s === "string" && s.trim().startsWith("{")) {\n try {\n const parsed = JSON.parse(s);\n if (object(parsed)) s = parsed;\n } catch {\n }\n }\n if (singleItem(s) && object(s.item)) s = s.item;\n doc2.state[k2] = s;\n if (!object(s)) continue;\n if (own(s, "options")) s.options = array(s.options);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (own(s, field)) s[field] = number(s[field]);\n if (Array.isArray(s.options)) s.options = s.options.map(number);\n } else if (s.type === "boolean") {\n if (own(s, "default")) s.default = boolean(s.default);\n if (Array.isArray(s.options)) s.options = s.options.map(boolean);\n }\n }\n if (object(doc2.derived)) Object.values(doc2.derived).forEach((e) => expression(e));\n if (object(doc2.actions)) {\n for (const action of Object.values(doc2.actions)) if (object(action) && own(action, "stateKeys")) action.stateKeys = array(action.stateKeys);\n }\n function nodes(list) {\n list = array(list);\n if (!Array.isArray(list)) return list;\n for (const node2 of list) {\n if (!object(node2)) continue;\n if (node2.type === "code" && (node2.copyable === true || node2.copyable === "true")) delete node2.copyable;\n if (["slider", "input"].includes(node2.type) && typeof node2.bind === "string" && node2.bind.startsWith("state.")) {\n const spec = doc2.state?.[node2.bind.slice(6)];\n if (spec?.type === "number") {\n for (const field of ["min", "max", "step"]) if (own(node2, field) && number(node2[field]) === spec[field]) delete node2[field];\n }\n }\n if (["text", "heading", "callout"].includes(node2.type) && own(node2, "content")) {\n if (!own(node2, "text")) {\n node2.text = node2.content;\n delete node2.content;\n } else if (node2.text === node2.content) delete node2.content;\n }\n if (["text", "heading", "callout"].includes(node2.type) && typeof node2.text === "string") {\n const spans = array(node2.spans);\n if (Array.isArray(spans) && spans.every((s) => object(s) && typeof s.text === "string") && spans.map((s) => s.text).join("") === node2.text) delete node2.text;\n }\n if (node2.type === "table" && own(node2, "types")) {\n const columns = array(node2.columns), rows = array(node2.rows), types = array(node2.types);\n const allowed = ["id", "type", "label", "columns", "rows", "types"];\n if (Object.keys(node2).every((k2) => allowed.includes(k2)) && Array.isArray(columns) && columns.length && columns.every((c) => object(c) && typeof c.key === "string" && typeof c.label === "string" && Object.keys(c).every((k2) => ["key", "label", "unit"].includes(k2))) && new Set(columns.map((c) => c.key)).size === columns.length && Array.isArray(rows) && rows.every(object) && Array.isArray(types) && types.length === columns.length && types.every((t) => ["text", "num", "delta", "bar", "badge"].includes(t))) {\n const spec = { ...node2.label ? { title: node2.label } : {}, items: [{ type: "table", columns: columns.map((c) => c.label + (c.unit ? ` (${c.unit})` : "")), rows: rows.map((row) => columns.map((c) => row[c.key] ?? null)), types }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { ...id !== void 0 ? { id } : {}, type: "visual", spec });\n }\n }\n if (typeof node2.id === "string" && VISUAL_TYPES.includes(node2.type) && !own(COMPONENTS, node2.type)) {\n const spec = { items: [{ ...node2 }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { id, type: "visual", spec });\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && node2.columns.every((c) => object(c) && typeof c.key === "string") && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length && Array.isArray(node2.rows) && node2.rows.every((row) => Array.isArray(row) && row.length === node2.columns.length)) {\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c, i) => [c.key, row[i]])));\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && Array.isArray(node2.rows) && node2.rows.every(Array.isArray) && node2.columns.every((c) => object(c) && Number.isInteger(c.key) && c.key >= 0) && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length) {\n const columns = node2.columns.map((c) => ({ ...c, key: "col_" + c.key }));\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c) => ["col_" + c.key, row[c.key] ?? null])));\n node2.columns = columns;\n }\n if (node2.type === "visual" && typeof node2.id === "string") {\n node2.stateKey ??= "visual_" + node2.id;\n doc2.state ??= {};\n if (!own(doc2.state, node2.stateKey)) doc2.state[node2.stateKey] = { type: "json", default: {} };\n }\n if (node2.type === "sandbox") {\n if (!own(node2, "title")) node2.title = doc2.title;\n if (!own(node2, "fallback")) node2.fallback = doc2.fallback;\n }\n for (const field of ["children", "items", "columns", "libraries", "stateKeys", "dataKeys", "derivedKeys"]) if (own(node2, field)) node2[field] = array(node2[field]);\n if (["table", "chart"].includes(node2.type) && own(node2, "rows")) node2.rows = array(node2.rows);\n for (const field of ["decimals", "height"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (["row", "column"].includes(node2.type)) {\n if (own(node2, "gap")) node2.gap = number(node2.gap);\n if (node2.type === "row" && own(node2, "columns")) node2.columns = number(node2.columns);\n }\n if (["text", "heading", "callout"].includes(node2.type)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (own(node2, "spans")) node2.spans = array(node2.spans);\n if (Array.isArray(node2.spans)) {\n for (const span of node2.spans) if (object(span)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(span, field)) span[field] = number(span[field]);\n }\n }\n }\n if (node2.type === "details" && own(node2, "open")) node2.open = boolean(node2.open);\n if (node2.type === "text" && own(node2, "copyable")) node2.copyable = boolean(node2.copyable);\n if (node2.type === "code" && own(node2, "wrap")) node2.wrap = boolean(node2.wrap);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const row of node2.rows) if (object(row)) for (const cell of Object.values(row)) expression(cell);\n }\n for (const field of ["text", "value", "max", "rows"]) if (own(node2, field)) expression(node2[field], node2.type === "progress");\n if (["row", "column", "card", "details"].includes(node2.type) && own(node2, "children")) node2.children = nodes(node2.children);\n }\n return list;\n }\n if (own(doc2, "nodes")) doc2.nodes = nodes(doc2.nodes);\n return doc2;\n }\n\n // lib/typography.js\n var TEXT_PRESETS = Object.freeze(["reading", "brief", "comparison", "list", "callout", "scorecard", "flow", "minimal"]);\n var TYPE_FIELDS = Object.freeze(["size", "weight", "color", "align", "lineHeight"]);\n var TEXT_SIZES = Object.freeze({ sm: 14, md: 16, lg: 20, xl: 26, hero: 36 });\n var TEXT_COLORS = Object.freeze({ default: "var(--du-ink)", muted: "var(--du-muted)", accent: "var(--du-accent)", success: "var(--du-green)", warning: "var(--du-amber)", danger: "var(--du-red)", violet: "var(--du-violet)" });\n function validateTypography(value, at2 = "text") {\n const fail2 = (message) => {\n throw Error(`DSH UI: ${at2}.${message}`);\n };\n if (value.size !== void 0 && !(typeof value.size === "number" && Number.isFinite(value.size) && value.size >= 12 && value.size <= 48) && !Object.hasOwn(TEXT_SIZES, value.size)) fail2("size must be 12..48 px or sm/md/lg/xl/hero");\n if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail2("weight must be 400/500/600/700/800");\n if (value.color !== void 0 && (typeof value.color !== "string" || !Object.hasOwn(TEXT_COLORS, value.color) && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.color))) fail2("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");\n if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail2("align must be left/center/right");\n if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail2("lineHeight must be 1.2..2.4");\n }\n\n // lib/links.js\n function validateLink(node2) {\n const fail2 = (message) => {\n throw Error("DSH UI: " + message);\n };\n if ([node2.href, node2.path, node2.action].filter((v2) => v2 !== void 0).length !== 1) fail2(`node.${node2.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);\n if (node2.variant !== void 0 && !["primary", "secondary", "text"].includes(node2.variant)) fail2("link/button variant must be primary/secondary/text");\n if (node2.href !== void 0) {\n if (typeof node2.href !== "string" || node2.href.length > 8192 || /[\\u0000-\\u0020\\u007f]/.test(node2.href) || !/^https?:\\/\\//i.test(node2.href)) fail2("href must be an absolute http/https URL; encode spaces");\n let url;\n try {\n url = new URL(node2.href);\n } catch {\n fail2("invalid href URL");\n }\n if (!url.hostname || url.username || url.password) fail2("href must have a host and must not contain credentials");\n }\n if (node2.path !== void 0) {\n if (typeof node2.path !== "string" || !node2.path.trim() || node2.path.length > 8192 || /[\\u0000-\\u001f\\u007f]/.test(node2.path) || /^\\s*(?:[a-z][a-z\\d+.-]*:|[\\\\/]{2})/i.test(node2.path) && !/^\\s*[a-z]:[\\\\/]/i.test(node2.path)) fail2("path must be a local file path, not a URL, network path or command");\n }\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own2 = (o, k2) => Object.hasOwn(o, k2);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object2 = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at2) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at2} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at2) {\n if (!object2(value)) fail(`${at2} must be an object`);\n for (const k2 of Object.keys(value)) if (!allowed.includes(k2)) {\n const hint = at2 === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at2}.${k2}; allowed fields at ${at2}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k2 of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k2)) fail("unsafe property name");\n safeJson(value[k2], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k2));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k2, spec]) => [k2, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object2(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k2, s] of Object.entries(doc2.state)) {\n if (!own2(state2, k2)) fail(`missing state.${k2}`);\n const v2 = state2[k2];\n if (s.type === "number") {\n if (!finite(v2) || v2 < s.min || v2 > s.max) fail(`state.${k2} is outside its numeric range`);\n const offset = (v2 - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k2} does not match its step`);\n } else if (s.type === "json") {\n if (!object2(v2) && !Array.isArray(v2)) fail(`state.${k2} must be an array or object for type json`);\n safeJson(v2);\n if (new TextEncoder().encode(JSON.stringify(v2)).length > 16384) fail(`state.${k2} JSON exceeds 16 KiB`);\n } else if (s.type === "string") text(v2, `state.${k2}`);\n else if (typeof v2 !== "boolean") fail(`state.${k2} must be boolean`);\n if (s.options && !s.options.includes(v2)) fail(`invalid option for state.${k2}`);\n result[k2] = v2;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], ceil: [1, 1], floor: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);\n const [group, k2] = ref.split(".");\n if (!own2(doc2[group], k2)) fail(`unknown reference ${ref}`);\n return [group, k2];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k2] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k2];\n if (own2(derived, k2)) return derived[k2];\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n active.add(k2);\n const result2 = expression2(doc2.derived[k2]);\n active.delete(k2);\n derived[k2] = result2;\n return result2;\n };\n const expression2 = (e, item) => {\n budget();\n if (own2(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k2, value]) => {\n const out2 = expression2(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k2, out2];\n })));\n }\n if (own2(e, "const")) return e.const;\n if (own2(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!item || !own2(item, k2) || !scalar(item[k2])) fail("invalid item reference");\n return item[k2];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression2(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression2(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression2(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y2) => x + y2, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y2) => x * y2, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "ceil":\n out = Math.ceil(a[0]);\n break;\n case "floor":\n out = Math.floor(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k2 of Object.keys(doc2.derived)) resolve(`derived.${k2}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const resolveCell = (cell) => {\n const out = expression2(cell);\n if (!scalar(out)) fail("inline row formula cells must resolve to a string, boolean or finite number");\n return out;\n };\n const result = { derived, resolveValue: (value) => {\n if (Array.isArray(value)) return value.map((row) => object2(row) ? Object.fromEntries(Object.entries(row).map(([k2, cell]) => [k2, object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field)) ? resolveCell(cell) : cell])) : row);\n if (!object2(value)) return value;\n return expression2(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart") {\n const index = rows.findIndex((r) => !own2(r, n.labelKey) || !scalar(r[n.labelKey]) || !own2(r, n.valueKey) || !finite(r[n.valueKey]));\n if (index >= 0) {\n const row = rows[index], missing = [n.labelKey, n.valueKey].filter((k2) => !own2(row, k2));\n fail("chart requires labels and finite numeric values. node." + n.id + ".rows[" + index + "]: " + (missing.length ? "missing field(s) " + missing.join(", ") : n.valueKey + " must resolve to a finite number") + ". Available keys: " + Object.keys(row).slice(0, 16).join(", ") + ". For live values use inline rows:[{" + n.labelKey + \':"\\u9879\\u76EE",\' + n.valueKey + \':{ref:"derived.amount"}}]; static data labels alone contain no amounts. Keep all nodes/state/derived when correcting the document\');\n }\n }\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);\n if (n.type === "progress") {\n const v2 = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v2) || !finite(max) || max <= 0 || v2 < 0 || v2 > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const normalized = normalizeAuthoring(JSON.parse(json));\n safeJson(normalized);\n const doc2 = expandExpressions(normalized);\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density", "preset"], "presentation");\n if (doc2.presentation.preset !== void 0 && !TEXT_PRESETS.includes(doc2.presentation.preset)) fail("unknown presentation preset; use " + TEXT_PRESETS.join("/"));\n for (const [k2, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k2] !== void 0 && !allowed.includes(doc2.presentation[k2])) fail(`unknown presentation ${k2}`);\n }\n if (doc2.version !== 1) fail(own2(doc2, "version") ? "document.version must be 1" : "document.version is missing. render_ui creates a complete document, not a partial patch: send {version:1,title,fallback,nodes:[...]} for shared controls/formulas, or {title,items:[...]} for extended visuals. Include all content, not only data/derived");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object2(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k2 of Object.keys(doc2[group])) if (!validIdentifier(k2)) fail(`invalid key in ${group}: ${JSON.stringify(k2)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);\n }\n for (const [k2, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k2}`);\n if (s.type === "string" && (Array.isArray(s.default) || object2(s.default)) && !own2(s, "options")) s.type = "json";\n if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k2}; use number, string, boolean or json (arrays/objects)`);\n if (s.type === "json" && own2(s, "options")) fail(`state.${k2}: json state does not support select options; use scalar options or a canvas`);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (!finite(s[field])) fail(`state.${k2}.${field} must be a finite JSON number; received ${s[field] === null ? "null" : typeof s[field]}. Supply {type:"number",default:2,min:1,max:12,step:1}; do not omit limits or include units in numeric fields`);\n if (s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for state.${k2}: require min < max and step > 0; received min=${s.min}, max=${s.max}, step=${s.step}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k2}`);\n } else if (["min", "max", "step"].some((p2) => own2(s, p2))) fail(`numeric limits on non-number ${k2}`);\n if (s.options !== void 0 && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`state.${k2}.options must be a direct array of 1..64 scalar values, e.g. options:["3","5","7"], not {item:[...]}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n const expressionShapes = /* @__PURE__ */ new Set();\n for (const [k2, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k2]: option });\n function validateExpression(e, depth = 0, itemRows, at2 = "expression") {\n if (depth > LIMITS.depth) fail(at2 + ": expression nesting exceeds " + LIMITS.depth);\n const shape = JSON.stringify(e);\n if (!expressionShapes.has(shape)) {\n expressionShapes.add(shape);\n if (++expressions > LIMITS.expressions) fail(at2 + ": expression limit exceeded (128 distinct expressions). Reuse derived references instead of expanding long formulas; keep the complete document when retrying");\n }\n if (!object2(e)) fail(`${at2}: expression must be an object`);\n if (own2(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k2] = reference(doc2, e.map.source), rows = doc2.data[k2];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("map source must be object rows");\n if (!object2(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k3, value2] of Object.entries(e.map.fields)) {\n if (!validIdentifier(k3)) fail(`invalid map field ${JSON.stringify(k3).slice(0, 100)}; use a letter/underscore identifier such as powerW or \\u529F\\u7387, without spaces, dots or hyphens`);\n validateExpression(value2, depth + 1, rows, `${at2}.map.fields.${k3}`);\n }\n return;\n }\n if (own2(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own2(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!itemRows || !validIdentifier(k2) || itemRows.some((row) => !own2(row, k2) || !scalar(row[k2]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail(`${at2}: invalid operator or argument count for ${JSON.stringify(e.op)}; args must be a direct array${arity ? ` with ${arity[0]}..${arity[1]} expressions` : " and op must be registered"}. Received ${Array.isArray(e.args) ? e.args.length + " arguments" : typeof e.args}. Prefer {expr:"state.people * state.days"} for arithmetic; missing operands cannot be inferred`);\n e.args.forEach((a, i) => validateExpression(a, depth + 1, itemRows, `${at2}.args[${i}]`));\n }\n Object.entries(doc2.derived).forEach(([k2, e]) => validateExpression(e, 0, void 0, `derived.${k2}`));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k2) {\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n if (visited.has(k2)) return;\n active.add(k2);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k2]);\n active.delete(k2);\n visited.add(k2);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k2, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k2}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own2(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Map();\n let count2 = 0;\n const value = (v2, at2) => {\n if (object2(v2)) {\n if (own2(v2, "map")) fail("map belongs in derived");\n validateExpression(v2, 0, void 0, at2);\n } else if (!scalar(v2)) fail(`invalid value at ${at2}`);\n };\n function nodes(list, depth = 0, path = "nodes") {\n if (!Array.isArray(list)) fail(path === "nodes" ? \'document.nodes is missing or is not an array. State/derived define values but do not create visible UI. Include nodes:[{id:"heading",type:"heading",text:"..."},...] and actual controls in the SAME complete document; do not resend state/data/derived alone. Declared state keys: \' + Object.keys(doc2.state).join(", ") : path + " must be an array of child nodes; use children:[{id,type,...}]");\n if (depth > LIMITS.depth) fail(path + " exceeds maximum node depth " + LIMITS.depth);\n for (const [index, n] of list.entries()) {\n const at2 = `${path}[${index}]`;\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object2(n)) fail(`${at2} must be a node object`);\n if (!own2(n, "id")) fail(`${at2}.id is missing (type=${JSON.stringify(n.type)}). Every node, including sandbox, needs its own id; add e.g. id:"canvas". JSON field order does not matter`);\n if (!validIdentifier(n.id)) fail(`${at2}.id is invalid: ${JSON.stringify(n.id)}. Use 1..64 letters/numbers/underscores starting with a letter/underscore`);\n if (ids.has(n.id)) fail(`${at2}.id duplicates ${JSON.stringify(n.id)} first declared at ${ids.get(n.id)}. Give each node a unique id; state keys and node ids are separate namespaces`);\n ids.set(n.id, `${at2}.id`);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\\./.test(n.rows)) n.rows = { ref: n.rows };\n switch (n.type) {\n case "visual": {\n const previous = Array.isArray(n.warnings) ? n.warnings.filter((x) => typeof x === "string").map((x) => x.slice(0, 512)).slice(0, 12) : [];\n const checked = validateVisual(n.spec);\n n.spec = checked.spec;\n n.warnings = [.../* @__PURE__ */ new Set([...previous, ...checked.warnings])].slice(0, 12);\n count2 += checked.count;\n if (count2 > LIMITS.nodes) fail("too many nodes, including visual components");\n if (!validIdentifier(n.stateKey) || doc2.state[n.stateKey]?.type !== "json") fail("visual requires its own json stateKey");\n break;\n }\n case "sandbox": {\n text(n.title, `${at2}.title (canvas title)`);\n text(n.fallback, `${at2}.fallback (canvas fallback)`);\n if (!n.title.trim()) fail(`${at2}.title must not be empty`);\n if (!n.fallback.trim()) fail(`${at2}.fallback must not be empty`);\n if (typeof n.html !== "string" || !n.html.trim()) fail(`${at2}.html must be a non-empty HTML string; script/css/fallback belong beside html on the sandbox node, not inside it`);\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.libraries !== void 0 && (!Array.isArray(n.libraries) || n.libraries.length > 1 || n.libraries.some((v2) => v2 !== "mechanism"))) fail(\'canvas libraries supports only ["mechanism"] or []\');\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k2) => !own2(doc2[group], k2)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n if (n.gap !== void 0 && !(typeof n.gap === "number" && Number.isFinite(n.gap) && n.gap >= 0 && n.gap <= 40)) fail("gap must be 0..40 pixels");\n if (n.columns !== void 0 && (!Number.isInteger(n.columns) || n.columns < 1 || n.columns > 4)) fail("columns must be 1..4");\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open === "true" || n.open === "false") n.open = n.open === "true";\n if (n.open !== void 0 && typeof n.open !== "boolean") fail(`node.${n.id}.open must be boolean true or false`);\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (n.title !== void 0) text(n.title, "steps title");\n const at3 = `node.${n.id}.items`;\n if (!Array.isArray(n.items)) fail(`${at3} must be an array of 1..12 step objects, received ${n.items === null ? "null" : typeof n.items}. Use items:[{"title":"First step","description":"One sentence"}], not items:{item:[...]}. status is optional for a static guide`);\n if (!n.items.length || n.items.length > 12) fail(`${at3} requires 1..12 items; received ${n.items.length}. Split a longer guide into separate steps nodes`);\n for (const [i, item] of n.items.entries()) {\n const stepAt = `${at3}[${i}]`;\n fields(item, ["title", "description", "status"], stepAt);\n text(item.title, `${stepAt}.title`);\n if (item.description !== void 0) text(item.description, `${stepAt}.description`);\n if (item.status !== void 0 && !["pending", "active", "done", "error"].includes(item.status)) fail(`${stepAt}.status must be pending, active, done or error; omit status for a static guide`);\n }\n break;\n }\n case "heading":\n case "text":\n case "callout":\n if (n.type === "text") {\n if (n.title !== void 0) text(n.title, "text block title");\n if (n.copyable !== void 0 && typeof n.copyable !== "boolean") fail("copyable must be boolean");\n }\n validateTypography(n, `node.${n.id}`);\n if (n.spans !== void 0) {\n if (n.text !== void 0) fail(`node.${n.id}: use text or spans, not both`);\n if (!Array.isArray(n.spans) || !n.spans.length || n.spans.length > 80) fail("spans must contain 1..80 text fragments");\n for (const [i, span] of n.spans.entries()) {\n fields(span, ["text", ...TYPE_FIELDS], `node.${n.id}.spans[${i}]`);\n text(span.text, "span text");\n validateTypography(span, `node.${n.id}.spans[${i}]`);\n }\n } else value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k2] = reference(doc2, n.bind), spec = doc2.state[k2];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n if (n.type === "select" && n.variant !== void 0 && !["dropdown", "segmented"].includes(n.variant)) fail(`node.${n.id}.variant must be dropdown or segmented`);\n break;\n }\n case "code":\n if (typeof n.code !== "string" || n.code.length > SANDBOX_LIMITS.source) fail("code must be a string of at most 48 Ki characters");\n if (n.lang !== void 0) text(n.lang, "code language");\n if (n.title !== void 0) text(n.title, "code title");\n if (n.wrap !== void 0 && typeof n.wrap !== "boolean") fail("code wrap must be boolean");\n break;\n case "button":\n case "link":\n text(n.text, "button text");\n validateLink(n);\n if (n.action !== void 0 && !own2(doc2.actions, n.action)) fail("unknown action");\n break;\n case "divider":\n if (n.label !== void 0) text(n.label, "divider label");\n break;\n case "table": {\n if (n.label !== void 0) text(n.label, "table label");\n if (!Array.isArray(n.rows)) value(n.rows, "node." + n.id + ".rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n if (n.rows === void 0) fail("node." + n.id + \'.rows is missing; supply rows:[{label:"\\u9879\\u76EE",value:123}] or a rows binding, plus labelKey/valueKey matching its fields. Do not invent missing amounts\');\n if (!Array.isArray(n.rows)) value(n.rows, "node." + n.id + ".rows");\n if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "callout", "card", "metric", "button", "link", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (!["button", "link"].includes(n.type)) {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n if (["table", "chart"].includes(n.type) && Array.isArray(n.rows)) {\n for (const [i, row] of n.rows.entries()) if (object2(row)) {\n for (const [k2, cell] of Object.entries(row)) if (object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field))) value(cell, at2 + ".rows[" + i + "]." + k2);\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1, `${at2}.children`);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m2 = event.data;\n if (event.source !== frame.contentWindow || m2?.channel !== channel || m2.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m2.type === "ready") {\n connected = true;\n publish();\n } else if (m2.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m2.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m2.type === "height" && Number.isFinite(m2.payload) && m2.payload >= 0) frame.style.height = Math.max(32, Math.min(1e3, Math.ceil(m2.payload))) + "px";\n else if (m2.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m2.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
3653
+ var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target", "external", "file", "globe"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/mechanism-runtime-bundle.js\n var MECHANISM_RUNTIME = \'var __MotionMechanism=(()=>{var it=Object.defineProperty;var Ot=Object.getOwnPropertyDescriptor;var Et=Object.getOwnPropertyNames;var It=Object.prototype.hasOwnProperty;var zt=(t,a)=>{for(var n in a)it(t,n,{get:a[n],enumerable:!0})},Pt=(t,a,n,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let e of Et(a))!It.call(t,e)&&e!==n&&it(t,e,{get:()=>a[e],enumerable:!(o=Ot(a,e))||o.enumerable});return t};var _t=t=>Pt(it({},"__esModule",{value:!0}),t);var Tt={};zt(Tt,{createMechanismAPI:()=>Ft});var st=Math.PI/180,Ct=Math.sqrt(1.6);function yt({scale:t,azimuth:a=45,elevation:n=30}){let o=a*st,e=n*st;return{sinA:Math.sin(o),cosA:Math.cos(o),sinE:Math.sin(e),cosE:Math.cos(e),k:t*Ct}}function q([t,a,n],o){let{origin:e}=o,{sinA:i,cosA:r,sinE:p,cosE:d,k:m}=yt(o);return[e[0]+(t*i-a*r)*m,e[1]+((t*r+a*i)*p-n*d)*m]}function tt([t,a,n],o){let{sinA:e,cosA:i,sinE:r,cosE:p}=yt(o);return(t*i+a*e)*p+n*r}function vt({x:t,y:a,w:n,d:o,r:e},i=8){let r=Math.max(0,Math.min(e,n/2,o/2)),p=[[t+n-r,a+r,-90],[t+n-r,a+o-r,0],[t+r,a+o-r,90],[t+r,a+r,180]],d=[];for(let[m,s,c]of p){let u=r>0?i:0;for(let f=0;f<=u;f++){let g=(c+(u?90*f/u:45))*st;d.push([m+r*Math.cos(g),s+r*Math.sin(g)])}}return d}function lt(t,a,n,o=40){return Array.from({length:o},(e,i)=>{let r=i/o*Math.PI*2;return[t+n*Math.cos(r),a+n*Math.sin(r)]})}function ct(t,a,n,{pad:o=24,headroom:e=0,azimuth:i=45,elevation:r=30}={}){let p={origin:[0,0],scale:1,azimuth:i,elevation:r},d=t.map(M=>q(M,p)),m=d.map(([M])=>M),s=d.map(([,M])=>M),c=Math.min(...m),u=Math.max(...m),f=Math.min(...s),g=Math.max(...s),h=Math.min((a-o*2)/(u-c),(n-o*2-e)/(g-f));return{origin:[a/2-(c+u)/2*h,e+(n-e)/2-(f+g)/2*h],scale:h,azimuth:i,elevation:r}}var Nt=Object.freeze({parts:96,teeth:64,faces:8192}),Ht=t=>typeof t=="number"&&Number.isFinite(t),y=t=>{throw Error("Motion mechanism: "+t)},v=(t,a,n=-1e4,o=1e4)=>((!Ht(t)||t<n||t>o)&&y(a+" must be a finite number in "+n+".."+o),t),U=(t,a)=>((!Array.isArray(t)||t.length!==3)&&y(a+" must be [x,y,z]"),t.map((n,o)=>v(n,a+"["+o+"]"))),et=t=>typeof t=="string"&&/^[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}$/u.test(t)&&!["constructor","prototype","__proto__"].includes(t),kt=["box","cylinder","gear","rod","spring"],I=(t,a)=>t.map((n,o)=>n+a[o]),B=(t,a)=>t.map((n,o)=>n-a[o]),_=(t,a)=>t.map(n=>n*a),dt=(t,a)=>t.reduce((n,o,e)=>n+o*a[e],0),V=(t,a)=>[t[1]*a[2]-t[2]*a[1],t[2]*a[0]-t[0]*a[2],t[0]*a[1]-t[1]*a[0]],J=t=>{let a=Math.hypot(...t);return a<1e-6&&y("zero-length axis"),_(t,1/a)};function Y(t){(!t||typeof t!="object"||Array.isArray(t))&&y("scene must be an object"),(!Array.isArray(t.parts)||!t.parts.length||t.parts.length>Nt.parts)&&y("parts requires 1..96 objects");let a=new Set,n=new Set;for(let[o,e]of t.parts.entries()){let i="parts["+o+"]";(!e||typeof e!="object"||!et(e.id)||a.has(e.id))&&y(i+".id must be a unique identifier"),a.add(e.id),kt.includes(e.type)||y(i+".type must be "+kt.join("/")),e.group!==void 0&&(et(e.group)||y(i+".group must be an identifier"),n.add(e.group));for(let r of["label","description"])e[r]!==void 0&&(typeof e[r]!="string"||e[r].length>1024)&&y(i+"."+r+" must be short text");if(e.cover!==void 0&&typeof e.cover!="boolean"&&y(i+".cover must be boolean"),e.material!==void 0&&!["metal","dark","accent","warm","cool"].includes(e.material)&&y(i+".material must be metal/dark/accent/warm/cool"),e.at!==void 0&&U(e.at,i+".at"),e.explode!==void 0&&U(e.explode,i+".explode"),e.rotation!==void 0&&v(e.rotation,i+".rotation",-1e9,1e9),e.axis!==void 0&&!["x","y","z"].includes(e.axis)&&y(i+".axis must be x/y/z"),e.type==="box"){let r=U(e.size,i+".size");r.some(p=>p<=0||p>2e3)&&y(i+".size must be positive and <=2000"),e.round!==void 0&&v(e.round,i+".round",0,Math.min(r[0],r[1])/2)}if(["cylinder","gear"].includes(e.type)&&(v(e.radius,i+".radius",.1,1e3),v(e.height??8,i+".height",.1,1e3),e.inner!==void 0&&v(e.inner,i+".inner",0,e.radius-.01)),e.type==="gear"){let r=v(e.teeth,i+".teeth",6,64);Number.isInteger(r)||y(i+".teeth must be an integer"),e.module!==void 0&&v(e.module,i+".module",.1,e.radius/3)}if(["rod","spring"].includes(e.type)&&(U(e.from,i+".from"),U(e.to,i+".to"),Math.hypot(...B(e.to,e.from))<.1&&y(i+" endpoints must differ"),v(e.radius??2,i+".radius",.1,200)),e.type==="spring"){let r=v(e.turns??8,i+".turns",2,24);Number.isInteger(r)||y(i+".turns must be integer")}}if(t.groups!==void 0){(!Array.isArray(t.groups)||t.groups.length>12)&&y("groups must be an array of <=12 labels");let o=new Set;for(let e of t.groups)(!e||!et(e.id)||o.has(e.id)||!n.has(e.id)||typeof e.label!="string"||e.label.length>128)&&y("groups must name unique existing part groups"),o.add(e.id)}if(t.bounds!==void 0){(!Array.isArray(t.bounds)||t.bounds.length!==2)&&y("bounds must be [minXYZ,maxXYZ]");let[o,e]=t.bounds.map((i,r)=>U(i,"bounds["+r+"]"));o.some((i,r)=>i>=e[r])&&y("bounds min must be below max on every axis")}if(t.azimuth!==void 0&&v(t.azimuth,"azimuth",10,80),t.elevation!==void 0&&v(t.elevation,"elevation",15,70),t.title!==void 0&&(typeof t.title!="string"||t.title.length>256)&&y("title must be short text"),t.bind!==void 0){(!t.bind||typeof t.bind!="object"||Array.isArray(t.bind))&&y("bind must be an object");for(let[o,e]of Object.entries(t.bind))(!["explode","selected","cutaway"].includes(o)||!et(e))&&y("bind only accepts declared state keys for explode/selected/cutaway")}return t}function Lt(t){return t==="x"?[[0,1,0],[0,0,1],[1,0,0]]:t==="y"?[[0,0,1],[1,0,0],[0,1,0]]:[[1,0,0],[0,1,0],[0,0,1]]}var at=(t,a,n,o)=>I(I(_(t[0],a),_(t[1],n)),_(t[2],o));function Rt(t,a,n,o){let e=t.map(([m,s])=>at(n,m,s,-a/2)),i=t.map(([m,s])=>at(n,m,s,a/2)),r=[],p=o?.map(([m,s])=>at(n,m,s,a/2)),d=o?.map(([m,s])=>at(n,m,s,-a/2));r.push({points:i,holes:p?[p.slice().reverse()]:[],normal:n[2]},{points:e.slice().reverse(),holes:d?[d]:[],normal:_(n[2],-1)});for(let m=0;m<t.length;m++){let s=(m+1)%t.length;Math.hypot(...B(e[s],e[m]))<1e-6||(r.push({points:[e[m],e[s],i[s],i[m]],normal:J(V(B(e[s],e[m]),n[2]))}),o&&r.push({points:[d[s],d[m],p[m],p[s]],normal:J(V(B(d[m],d[s]),n[2]))}))}return r}function ot(t){let a=Lt(t.axis),n,o,e;if(t.type==="box"&&(n=vt({x:-t.size[0]/2,y:-t.size[1]/2,w:t.size[0],d:t.size[1],r:t.round??Math.min(2,t.size[0]/2,t.size[1]/2)},3),o=t.size[2]),t.type==="cylinder"&&(n=lt(0,0,t.radius,24),o=t.height??8),t.type==="gear"){let s=Math.PI*2/t.teeth,c=t.module??t.radius*2/t.teeth;n=[];for(let u=0;u<t.teeth;u++)for(let[f,g]of[[-.5,t.radius-c*.85],[-.32,t.radius-c*.85],[-.17,t.radius+c*.7],[.17,t.radius+c*.7],[.32,t.radius-c*.85]]){let h=(u+f)*s;n.push([Math.cos(h)*g,Math.sin(h)*g])}o=t.height??8}if(t.type==="rod"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0]));a=[c,V(s,c),s],n=lt(0,0,t.radius??2,16),o=Math.hypot(...B(t.to,t.from))}if(t.type==="spring"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0])),u=V(s,c),f=[];for(let g=0;g<=128;g++){let h=g/128,M=h*(t.turns??8)*Math.PI*2,O=Math.min(1,h*12,(1-h)*12);f.push(I(I(t.from,_(B(t.to,t.from),h)),I(_(c,Math.cos(M)*(t.radius??6)*O),_(u,Math.sin(M)*(t.radius??6)*O))))}return{line:f,points:f}}let i=t.rotation??0,r=Math.cos(i),p=Math.sin(i);n=n.map(([s,c])=>[s*r-c*p,s*p+c*r]);let d=t.inner?n.map(([s,c])=>{let u=Math.atan2(c,s);return[Math.cos(u)*t.inner,Math.sin(u)*t.inner]}):void 0;e=Rt(n,o,a,d);let m=t.type==="rod"?_(I(t.from,t.to),.5):t.at??[0,0,0];return e=e.map(s=>({...s,points:s.points.map(c=>I(c,m)),holes:s.holes?.map(c=>c.map(u=>I(u,m)))})),{faces:e,points:e.flatMap(s=>s.points)}}function wt(t){if(t.bounds){let[a,n]=t.bounds;return Array.from({length:8},(o,e)=>[e&1?n[0]:a[0],e&2?n[1]:a[1],e&4?n[2]:a[2]])}return t.parts.flatMap(a=>ot(a).points.flatMap(o=>[o,I(o,a.explode??[0,0,0])]))}function W({driverTeeth:t=16,drivenTeeth:a=32,rpm:n=30,angle:o=0,module:e=2}={}){for(let[i,r]of Object.entries({driverTeeth:t,drivenTeeth:a}))(!Number.isInteger(r)||r<6||r>64)&&y(i+" must be integer 6..64");return v(n,"rpm",-600,600),v(o,"angle",-1e9,1e9),v(e,"module",.1,10),{driverRadius:t*e/2,drivenRadius:a*e/2,centerDistance:(t+a)*e/2,driverAngle:o,drivenAngle:-o*t/a+Math.PI-Math.PI/a,driverRpm:n,drivenRpm:-n*t/a,ratio:a/t}}function X({angle:t=0,radius:a=20,rod:n=70,z:o=20}={}){v(t,"angle",-1e9,1e9),v(a,"radius",.1,200),v(n,"rod",.1,1e3),v(o,"z"),n<=a&&y("connecting rod length must exceed crank radius");let e=[a*Math.cos(t),a*Math.sin(t),o],i=e[0]+Math.sqrt(n*n-e[1]*e[1]);return{crank:e,piston:[i,0,o],position:i,stroke:a*2,angle:t}}function Mt(t,a,n,o=.16){return v(t,"value",-1e9,1e9),v(a,"target",-1e9,1e9),v(n,"delta",0,.1),v(o,"tau",.01,10),t+(a-t)*(1-Math.exp(-n/o))}var $t=Math.PI*2;function nt(t,a){Y(t);let n=a&&!t.bounds?t.parts.filter(o=>!a.cutaway||!o.cover).flatMap(o=>ot(o).points.map(e=>I(e,_(o.explode??[0,0,0],a.explode??0)))):wt(t);return ct(n.length?n:[[0,0,0],[1,1,1]],600,340,{pad:24,azimuth:t.azimuth??45,elevation:t.elevation??30})}var At=t=>t.map(([a,n],o)=>(o?"L":"M")+Math.round(a*10)/10+" "+Math.round(n*10)/10).join("")+"Z";function mt(t,a,{explode:n=0,selected:o="all",cutaway:e=!1,pose:i={}}={},r=new Map){if(typeof n!="number"||!Number.isFinite(n)||n<0||n>1)throw Error("Motion mechanism: explode must be 0..1");if(typeof o!="string"||typeof e!="boolean")throw Error("Motion mechanism: selected must be text and cutaway boolean");if(!i||typeof i!="object"||Array.isArray(i))throw Error("Motion mechanism: pose must be an object");for(let c of Object.keys(i))if(!t.parts.some(u=>u.id===c))throw Error("Motion mechanism: unknown pose part "+c);let p=(a.azimuth??45)*$t/360,d=(a.elevation??30)*$t/360,m=[Math.cos(p)*Math.cos(d),Math.sin(p)*Math.cos(d),Math.sin(d)],s=[];for(let c of t.parts){if(e&&c.cover)continue;let u=i[c.id]??{};for(let $ of Object.keys(u))if(!["at","rotation","from","to"].includes($))throw Error("Motion mechanism: unsupported pose field "+$);let f={...c,...u},g=JSON.stringify(f),h=r.get(c.id);h?.key!==g&&(Y({parts:[f]}),h={key:g,...ot(f)},r.set(c.id,h));let M=_(f.explode??[0,0,0],n),O=Math.min(...h.points.map($=>$[2]))+M[2],N=o==="all"||o===c.id||o===c.group;if(h.line){let $=h.line.map(P=>I(P,M));s.push({floor:O,key:f.id+"_line",part:f.id,group:f.group,d:$.map((P,A)=>(A?"L":"M")+q(P,a).join(" ")).join(""),depth:tt($[Math.floor($.length/2)],a),line:!0,tone:1,material:f.material??"metal",active:N});continue}for(let[$,P]of h.faces.entries()){if(dt(P.normal,m)<=1e-4)continue;let w=P.points.map(S=>I(S,M)),T=P.holes?.map(S=>S.map(H=>I(H,M))),D=_(w.reduce((S,H)=>I(S,H),[0,0,0]),1/w.length),G=dt(P.normal,[-.25,-.4,.88]);s.push({floor:O,key:f.id+"_"+$,part:f.id,group:f.group,d:At(w.map(S=>q(S,a)))+(T??[]).map(S=>At(S.map(H=>q(H,a)))).join(""),depth:tt(D,a),line:!1,tone:G>.5?0:G>.1?1:G>-.4?2:3,material:f.material??"metal",active:N})}}if(s.length>8192)throw Error("Motion mechanism: face budget exceeded");return s.sort((c,u)=>c.floor-u.floor||c.depth-u.depth||c.key.localeCompare(u.key))}var z=(t,a,n,o,e,i={})=>({id:t,type:"box",label:a,at:n,size:o,group:e,...i}),F=(t,a,n,o,e,i,r={})=>({id:t,type:"cylinder",label:a,at:n,radius:o,height:e,group:i,...r});function ut(t,a,n,o,e=3,i=18){return[[-1,-1],[-1,1],[1,-1],[1,1]].map(([r,p],d)=>F(o+"_bolt_"+d,"\\\\u56FA\\\\u5B9A\\\\u87BA\\\\u6813",[t+r*i,a+p*i,n],e,3,o,{material:"dark",explode:[0,0,26]}))}function ft(){return{title:"\\\\u5206\\\\u5C42\\\\u7ED3\\\\u6784 \\\\xB7 \\\\u793A\\\\u610F\\\\u88C5\\\\u914D",groups:[{id:"base",label:"\\\\u5E95\\\\u5EA7",description:"\\\\u652F\\\\u6491\\\\u6574\\\\u4F53\\\\uFF0C\\\\u5E76\\\\u63D0\\\\u4F9B\\\\u5B89\\\\u88C5\\\\u4F4D\\\\u7F6E\\\\u3002"},{id:"board",label:"\\\\u529F\\\\u80FD\\\\u677F",description:"\\\\u8FDE\\\\u63A5\\\\u8F93\\\\u5165\\\\u4E0E\\\\u5904\\\\u7406\\\\u6A21\\\\u5757\\\\uFF1B\\\\u793A\\\\u610F\\\\u7ED3\\\\u6784\\\\uFF0C\\\\u4E0D\\\\u5BF9\\\\u5E94\\\\u7279\\\\u5B9A\\\\u4EA7\\\\u54C1\\\\u3002"},{id:"sink",label:"\\\\u6563\\\\u70ED\\\\u5C42",description:"\\\\u5C06\\\\u70ED\\\\u91CF\\\\u4F20\\\\u5230\\\\u66F4\\\\u5927\\\\u7684\\\\u8868\\\\u9762\\\\u79EF\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u4FDD\\\\u62A4\\\\u5185\\\\u90E8\\\\uFF1B\\\\u5256\\\\u5F00\\\\u9009\\\\u9879\\\\u901A\\\\u8FC7\\\\u9690\\\\u85CF\\\\u5916\\\\u58F3\\\\u5C55\\\\u793A\\\\u7ED3\\\\u6784\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[0,0,0],[120,85,10],"base",{round:6,material:"metal"}),...[-1,1].flatMap((t,a)=>[-1,1].map((n,o)=>F("foot_"+a+o,"\\\\u9632\\\\u6ED1\\\\u811A",[t*46,n*30,-8],6,7,"base",{material:"dark"}))),z("board","\\\\u529F\\\\u80FD\\\\u677F",[0,0,15],[96,62,4],"board",{round:3,material:"cool",explode:[0,0,35]}),z("chip","\\\\u5904\\\\u7406\\\\u6A21\\\\u5757",[-16,0,22],[25,24,10],"board",{round:2,material:"dark",explode:[0,0,35]}),z("connector","\\\\u8FDE\\\\u63A5\\\\u7AEF\\\\u53E3",[32,0,24],[16,36,14],"board",{round:2,material:"warm",explode:[0,0,35]}),...ut(0,0,20,"board",2,24),z("spreader","\\\\u5BFC\\\\u70ED\\\\u5E95\\\\u677F",[-16,0,32],[44,42,5],"sink",{round:2,material:"metal",explode:[-10,0,65]}),...Array.from({length:7},(t,a)=>z("fin_"+a,"\\\\u6563\\\\u70ED\\\\u9CCD\\\\u7247",[-34+a*6,0,44],[2.4,40,20],"sink",{round:1,material:"metal",explode:[-10,0,65]})),z("top","\\\\u9876\\\\u76D6",[0,0,61],[124,89,5],"cover",{round:6,cover:!0,material:"metal",explode:[12,0,85]}),z("side","\\\\u4FA7\\\\u677F",[0,-44,32],[124,4,58],"cover",{round:2,cover:!0,material:"metal",explode:[12,-22,50]})]}}function pt({driverTeeth:t=16,drivenTeeth:a=32,module:n=1.5}={}){let o=W({driverTeeth:t,drivenTeeth:a,module:n}),e=o.centerDistance;return{title:"\\\\u9F7F\\\\u8F6E\\\\u4F20\\\\u52A8 \\\\xB7 \\\\u7B80\\\\u5316\\\\u76F4\\\\u9F7F\\\\u8F6E\\\\u793A\\\\u610F",azimuth:70,elevation:55,groups:[{id:"frame",label:"\\\\u652F\\\\u67B6",description:"\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u4F4D\\\\u7F6E\\\\uFF1B\\\\u4E24\\\\u8F74\\\\u4E2D\\\\u5FC3\\\\u8DDD\\\\u7531\\\\u9F7F\\\\u6570\\\\u4E0E\\\\u6A21\\\\u6570\\\\u5171\\\\u540C\\\\u786E\\\\u5B9A\\\\u3002"},{id:"driver",label:"\\\\u4E3B\\\\u52A8\\\\u8F6E",description:"\\\\u8F93\\\\u5165\\\\u8F6C\\\\u901F\\\\uFF0C\\\\u7531\\\\u9F7F\\\\u6570\\\\u51B3\\\\u5B9A\\\\u8282\\\\u5706\\\\u534A\\\\u5F84\\\\u3002"},{id:"driven",label:"\\\\u4ECE\\\\u52A8\\\\u8F6E",description:"\\\\u5916\\\\u556E\\\\u5408\\\\u8F6C\\\\u5411\\\\u76F8\\\\u53CD\\\\uFF0C\\\\u8F6C\\\\u901F\\\\u6309\\\\u9F7F\\\\u6570\\\\u6BD4\\\\u53D8\\\\u5316\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u9690\\\\u85CF\\\\u76D6\\\\u677F\\\\u4EE5\\\\u89C2\\\\u5BDF\\\\u4F20\\\\u52A8\\\\uFF1B\\\\u4E0D\\\\u662F\\\\u52A0\\\\u5DE5\\\\u6216\\\\u53D7\\\\u529B\\\\u4EFF\\\\u771F\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[30,0,-8],[140,90,10],"frame",{round:6,material:"metal"}),...ut(30,0,0,"frame",3,32),...[0,e].flatMap((i,r)=>[F("bearing_"+r,"\\\\u8F74\\\\u627F\\\\u5EA7",[i,0,4],10,12,"frame",{inner:4,material:"dark"}),F("shaft_"+r,"\\\\u4F20\\\\u52A8\\\\u8F74",[i,0,16],3.8,28,r?"driven":"driver",{material:"metal",explode:[r?24:-24,0,20]}),F("hub_"+r,"\\\\u8F6E\\\\u6BC2",[i,0,27],6,6,r?"driven":"driver",{inner:3.8,material:"warm",explode:[r?24:-24,0,20]})]),{id:"driverGear",type:"gear",label:"\\\\u4E3B\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driver",at:[0,0,20],radius:o.driverRadius,teeth:t,module:n,height:7,inner:4,material:"accent",explode:[-24,0,20]},{id:"drivenGear",type:"gear",label:"\\\\u4ECE\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driven",at:[e,0,20],radius:o.drivenRadius,teeth:a,module:n,height:7,inner:4,material:"cool",rotation:o.drivenAngle,explode:[24,0,20]},z("cover","\\\\u9632\\\\u62A4\\\\u76D6\\\\u677F",[30,0,36],[140,90,4],"cover",{round:6,cover:!0,material:"metal",explode:[0,0,62]})]}}function ht({radius:t=20,rod:a=70,angle:n=0}={}){let o=X({radius:t,rod:a,angle:n,z:28});return{title:"\\\\u66F2\\\\u67C4\\\\u8FDE\\\\u6746 \\\\xB7 \\\\u65CB\\\\u8F6C\\\\u8F6C\\\\u4E3A\\\\u5F80\\\\u590D",groups:[{id:"frame",label:"\\\\u652F\\\\u67B6\\\\u4E0E\\\\u5BFC\\\\u8F68",description:"\\\\u652F\\\\u6491\\\\u8F74\\\\u5FC3\\\\uFF0C\\\\u9650\\\\u5236\\\\u6ED1\\\\u5757\\\\u6CBF\\\\u540C\\\\u4E00\\\\u65B9\\\\u5411\\\\u8FD0\\\\u52A8\\\\u3002"},{id:"crank",label:"\\\\u66F2\\\\u67C4",description:"\\\\u66F2\\\\u67C4\\\\u7ED5\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u65CB\\\\u8F6C\\\\u3002"},{id:"rod",label:"\\\\u8FDE\\\\u6746",description:"\\\\u8FDE\\\\u63A5\\\\u66F2\\\\u67C4\\\\u9500\\\\u548C\\\\u6ED1\\\\u5757\\\\uFF0C\\\\u957F\\\\u5EA6\\\\u4FDD\\\\u6301\\\\u4E0D\\\\u53D8\\\\u3002"},{id:"piston",label:"\\\\u6ED1\\\\u5757",description:"\\\\u6CBF\\\\u5BFC\\\\u8F68\\\\u5F80\\\\u590D\\\\uFF1B\\\\u5B8C\\\\u6574\\\\u884C\\\\u7A0B\\\\u7B49\\\\u4E8E\\\\u66F2\\\\u67C4\\\\u534A\\\\u5F84\\\\u7684\\\\u4E24\\\\u500D\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[35,0,-6],[175,80,10],"frame",{round:6,material:"metal"}),...ut(35,0,1,"frame",3,30),F("bearing","\\\\u66F2\\\\u8F74\\\\u8F74\\\\u627F",[0,0,7],11,15,"frame",{inner:4,material:"dark"}),F("axle","\\\\u66F2\\\\u8F74",[0,0,15],3.8,26,"crank",{material:"metal",explode:[0,-18,18]}),F("flywheel","\\\\u66F2\\\\u67C4\\\\u76D8",[0,0,20],t+6,6,"crank",{inner:4,material:"accent",explode:[0,-18,18]}),z("railA","\\\\u5BFC\\\\u8F68",[74,-16,13],[85,5,6],"frame",{round:1,material:"dark"}),z("railB","\\\\u5BFC\\\\u8F68",[74,16,13],[85,5,6],"frame",{round:1,material:"dark"}),F("crankPin","\\\\u66F2\\\\u67C4\\\\u9500",o.crank,3,12,"crank",{material:"warm",explode:[0,-18,18]}),{id:"link",type:"rod",label:"\\\\u8FDE\\\\u6746",from:o.crank,to:o.piston,radius:2.4,group:"rod",material:"metal",explode:[0,0,45]},z("piston","\\\\u6ED1\\\\u5757",[o.position,0,22],[18,24,16],"piston",{round:3,material:"cool",explode:[20,0,18]}),F("pistonPin","\\\\u6ED1\\\\u5757\\\\u9500",o.piston,3,10,"piston",{material:"warm",explode:[20,0,18]})]}}var St=`\\n.mui-mechanism{font:15px/1.7 system-ui,sans-serif;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:24px;padding:20px;max-width:100%;box-sizing:border-box}.mui-mechanism *{box-sizing:border-box}.mui-mechanism h2{font-size:22px;line-height:1.35;margin:0 0 8px;font-weight:750}.mui-mechanism p{margin:0;color:var(--canvas-muted)}\\n.mui-mechanism-svg{display:block;width:100%;height:auto;max-height:420px;touch-action:pan-y}.mui-mechanism-svg path{stroke:color-mix(in srgb,var(--canvas-ink) 38%,var(--canvas-bg));stroke-width:.8;stroke-linejoin:round;vector-effect:non-scaling-stroke;cursor:pointer;fill:var(--mech-base,var(--canvas-soft))}.mui-mechanism-svg [data-material=metal]{--mech-base:color-mix(in srgb,var(--canvas-muted) 32%,var(--canvas-bg))}.mui-mechanism-svg [data-material=dark]{--mech-base:color-mix(in srgb,var(--canvas-ink) 78%,var(--canvas-bg))}.mui-mechanism-svg [data-material=accent]{--mech-base:var(--canvas-accent)}.mui-mechanism-svg [data-material=cool]{--mech-base:color-mix(in srgb,#22998a 70%,var(--canvas-bg))}.mui-mechanism-svg [data-material=warm]{--mech-base:color-mix(in srgb,#dd9c42 75%,var(--canvas-bg))}\\n.mui-mechanism-svg [data-tone="0"]{fill:color-mix(in srgb,var(--mech-base) 74%,var(--canvas-bg))}.mui-mechanism-svg [data-tone="1"]{fill:var(--mech-base)}.mui-mechanism-svg [data-tone="2"]{fill:color-mix(in srgb,var(--mech-base) 85%,var(--canvas-ink))}.mui-mechanism-svg [data-tone="3"]{fill:color-mix(in srgb,var(--mech-base) 68%,var(--canvas-ink))}.mui-mechanism-svg [data-line]{fill:none;stroke:var(--mech-base);stroke-width:2}.mui-mechanism-svg [data-active=false]{opacity:.2}.mui-mechanism-svg [data-active=true]{opacity:1}\\n.mui-mechanism-nav{display:flex;flex-wrap:wrap;gap:7px;margin:8px 0 12px}.mui-mechanism button{font:inherit;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:999px;padding:6px 13px;cursor:pointer;min-height:36px}.mui-mechanism button[aria-pressed=true]{color:var(--canvas-bg);background:var(--canvas-ink);border-color:var(--canvas-ink)}.mui-mechanism button:focus-visible,.mui-mechanism input:focus-visible{outline:2px solid var(--canvas-accent);outline-offset:3px}.mui-mechanism button:disabled{opacity:.5;cursor:default}\\n.mui-mechanism-controls{display:flex;align-items:center;flex-wrap:wrap;gap:14px;padding:12px 14px;border-radius:16px;background:var(--canvas-soft);margin:8px 0}.mui-mechanism-controls label{display:flex;align-items:center;gap:9px;flex:1 1 180px;min-width:0}.mui-mechanism-controls input[type=range]{flex:1;min-width:70px;accent-color:var(--canvas-accent)}.mui-mechanism-controls input[type=checkbox]{accent-color:var(--canvas-accent)}.mui-mechanism-controls output{font-variant-numeric:tabular-nums;min-width:40px;text-align:right;font-weight:650}.mui-mechanism-readout{display:block;padding:10px 0;font-weight:700;font-variant-numeric:tabular-nums;color:var(--canvas-ink)}.mui-mechanism-description{min-height:0;font-size:14px}\\n.mui-mechanism[data-style=editorial]{border:0;border-top:1px solid var(--canvas-line);border-radius:0;padding:16px 0}.mui-mechanism[data-style=editorial] h2{font-family:ui-serif,Georgia,serif;font-weight:650}.mui-mechanism[data-style=editorial] .mui-mechanism-controls{border-radius:0;background:transparent;border-block:1px solid var(--canvas-line)}\\n.mui-mechanism[data-style=technical]{border-radius:10px}.mui-mechanism[data-style=technical] button,.mui-mechanism[data-style=technical] .mui-mechanism-controls{border-radius:6px}.mui-mechanism[data-style=technical] .mui-mechanism-readout{font-family:ui-monospace,Consolas,monospace}\\n.mui-mechanism[data-style=soft]{border:0;background:var(--canvas-soft);border-radius:28px 28px 28px 10px}.mui-mechanism[data-style=soft] .mui-mechanism-controls{background:var(--canvas-bg);border-radius:22px}.mui-mechanism[data-style=expressive] h2{font-size:28px;font-weight:850;border-left:5px solid var(--canvas-accent);padding-left:14px}.mui-mechanism[data-style=expressive]{border:0;border-radius:0}.mui-mechanism[data-style=prismframe]{border:1.5px solid var(--canvas-line);box-shadow:4px 5px 0 color-mix(in srgb,var(--canvas-accent) 14%,var(--canvas-bg))}.mui-mechanism[data-style=aurora]{border-radius:28px;box-shadow:0 16px 30px -25px #30204d66}.mui-mechanism[data-style=aurora] .mui-mechanism-controls{border-radius:24px}\\n@media(max-width:500px){.mui-mechanism{padding:14px;border-radius:20px}.mui-mechanism h2{font-size:20px}.mui-mechanism-controls{padding:10px}.mui-mechanism-nav{gap:5px}.mui-mechanism button{padding:6px 10px;font-size:14px}}\\n@media(prefers-reduced-motion:reduce){.mui-mechanism *{animation:none!important;transition:none!important}}\\n@media(forced-colors:active){.mui-mechanism-svg path{fill:Canvas;stroke:CanvasText}.mui-mechanism button[aria-pressed=true]{background:Highlight;color:HighlightText}}\\n`;var xt="http://www.w3.org/2000/svg",C=(t,a,n)=>{let o=document.createElement(t);return a&&(o.className=a),n!==void 0&&(o.textContent=n),o};function Ft(t){function a(o,e){let i=typeof o=="string"?document.querySelector(o):o;if(!i||!i.replaceChildren)throw Error("Motion mechanism: target element not found");Y(e);let r=structuredClone({...e,onSelect:void 0}),p=nt(r),d={explode:0,selected:"all",cutaway:!1,pose:{}},m=!1,s="",c="",u=0,f=new Map,g=new Map,h=new Map,M=[],O=C("section","mui-mechanism"),N=C("h2",null,r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$=document.createElementNS(xt,"svg"),P=document.createElementNS(xt,"g"),A=C("div","mui-mechanism-nav"),w=C("div","mui-mechanism-controls"),T=C("p","mui-mechanism-description"),D=C("output","mui-mechanism-readout"),G=C("style");G.textContent=St,N.hidden=r.title==="",O.setAttribute("aria-label",r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$.setAttribute("class","mui-mechanism-svg"),$.setAttribute("viewBox","0 0 600 340"),$.setAttribute("role","img"),$.setAttribute("aria-label","\\\\u53EF\\\\u62C6\\\\u89E3\\\\u7684\\\\u7ED3\\\\u6784\\\\u793A\\\\u610F\\\\u56FE\\\\uFF1B\\\\u4F7F\\\\u7528\\\\u4E0B\\\\u65B9\\\\u6309\\\\u94AE\\\\u9009\\\\u62E9\\\\u90E8\\\\u4EF6"),$.append(P),O.append(G,N,$,A,w,D,T),i.replaceChildren(O);let S=()=>r.groups?.length?r.groups:r.parts.map(l=>({id:l.id,label:l.label??l.id,description:l.description??""}));function H(l){r.bind?.selected?t.setState({[r.bind.selected]:l}):typeof e.onSelect=="function"?e.onSelect(l):Q({selected:l})}function K(){if(A.replaceChildren(),h.clear(),!r.bind?.selected&&typeof e.onSelect!="function"){A.hidden=!0;return}A.hidden=!1;for(let l of[{id:"all",label:"\\\\u5168\\\\u90E8",description:""},...S()]){let b=C("button",null,l.label);b.type="button",b.setAttribute("aria-pressed",String(d.selected===l.id)),b.addEventListener("click",()=>H(l.id)),h.set(l.id,b),A.append(b)}}let x,rt,L;if(r.bind?.explode){let l=C("label",null,"\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6");x=C("input"),x.type="range",x.min="0",x.max="1",x.step=".01",x.setAttribute("aria-label","\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6"),rt=C("output"),x.addEventListener("input",()=>t.setState({[r.bind.explode]:Number(x.value)})),l.append(x,rt),w.append(l)}if(r.bind?.cutaway&&r.parts.some(l=>l.cover)){let l=C("label",null,"\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3");L=C("input"),L.type="checkbox",L.setAttribute("aria-label","\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3"),L.addEventListener("change",()=>t.setState({[r.bind.cutaway]:L.checked})),l.prepend(L),w.append(l)}w.hidden=!w.childNodes.length;function jt(l){let b=JSON.stringify([l.explode,l.cutaway]);b!==s&&(p=nt(r,l),s=b);let E=mt(r,p,l,f),k=new Set;for(let j of E){k.add(j.key);let R=g.get(j.key);R||(R=document.createElementNS(xt,"path"),R.setAttribute("fill-rule","evenodd"),g.set(j.key,R));for(let[gt,bt]of Object.entries({d:j.d,"data-part":j.part,"data-material":j.material,"data-tone":j.tone,"data-active":j.active}))R.getAttribute(gt)!==String(bt)&&R.setAttribute(gt,String(bt));j.line?R.setAttribute("data-line",""):R.removeAttribute("data-line")}for(let[j,R]of g)k.has(j)||(R.remove(),g.delete(j));let Z=E.map(j=>j.key).join("|");if(Z!==c){for(let j of E)P.append(g.get(j.key));c=Z}u++}function Q(l={}){if(m)return;for(let k of Object.keys(l))if(!["explode","selected","cutaway","pose","parts","readout"].includes(k))throw Error("Motion mechanism: unknown update field "+k);if(l.parts){let k={...r,parts:l.parts};Y(k);let Z=nt(k);mt(k,Z,{...d,...l},new Map),r=k,p=Z,f.clear(),c="",s=""}let b={...d,...l};l.pose&&(b.pose=l.pose),jt(b),d=b;for(let[k,Z]of h)Z.setAttribute("aria-pressed",String(b.selected===k));let E=S().find(k=>k.id===b.selected)??r.parts.find(k=>k.id===b.selected);T.textContent=E?.description??(b.selected==="all"?"\\\\u9009\\\\u62E9\\\\u4E00\\\\u4E2A\\\\u90E8\\\\u4EF6\\\\uFF0C\\\\u67E5\\\\u770B\\\\u5B83\\\\u7684\\\\u804C\\\\u8D23\\\\uFF1B\\\\u62C6\\\\u89E3\\\\u53EA\\\\u5C55\\\\u793A\\\\u88C5\\\\u914D\\\\u5173\\\\u7CFB\\\\u3002":""),x&&(x.value=String(b.explode),rt.textContent=Math.round(b.explode*100)+"%"),L&&(L.checked=b.cutaway),l.readout!==void 0&&(D.textContent=String(l.readout))}return $.addEventListener("click",l=>{let b=l.target.closest("[data-part]");if(!b)return;let E=r.parts.find(k=>k.id===b.getAttribute("data-part"));E&&H(r.groups?.length?E.group??E.id:E.id)}),K(),M.push(t.subscribe(l=>{if(m)return;let b={};for(let[E,k]of Object.entries(r.bind??{})){if(!Object.hasOwn(l.state,k))throw Error("Motion mechanism: bind."+E+" names undeclared state "+k);b[E]=l.state[k]}O.dataset.style=l.theme?.visualStyle??"";for(let E of h.values())E.disabled=l.disabled;x&&(x.disabled=l.disabled),L&&(L.disabled=l.disabled),Q(b)})),Object.freeze({update:Q,pose:l=>Q({pose:l}),stats:()=>({frames:u,faces:g.size,parts:r.parts.length}),destroy(){m||(m=!0,M.forEach(l=>l()),g.clear(),f.clear(),i.replaceChildren())}})}function n(o,e,i={}){if(!["assembly","gears","crank"].includes(e))throw Error("Motion mechanism: demo must be assembly/gears/crank");let r=i.bind??{},p=()=>t.snapshot.state,d=(A,w)=>Object.hasOwn(r,A)?p()[r[A]]:w;for(let[A,w]of Object.entries(r))if(!["explode","selected","cutaway","rpm","teeth","running","angle","radius"].includes(A)||typeof w!="string"||!Object.hasOwn(p(),w))throw Error("Motion mechanism: invalid demo binding "+A);let m=d("angle",0)*Math.PI/180,s=m,c="",u=!1,f=Object.fromEntries(Object.entries(r).filter(([A])=>["explode","selected","cutaway"].includes(A)));function g(){return e==="assembly"?ft():e==="gears"?pt({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),module:i.module??1.5}):ht({radius:d("radius",20),rod:i.rod??70})}let h=a(o,{...g(),...i.title===void 0?{}:{title:i.title},bind:f}),M=!1;function O(A=0,w=!1,T=!0){if(M)return;let D=d("rpm",30),G=d("running",!1),S=d("angle",0)*Math.PI/180,H=s;S!==m?(H=S,m=S):G&&T&&!w&&(H+=D*Math.PI*2/60*A),s=H;let K=JSON.stringify([e,d("teeth",32),d("radius",20)]);if(K!==c&&(h.update({parts:g().parts}),c=K),e==="gears"){let x=W({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),rpm:D,angle:s,module:i.module??1.5});h.update({pose:{driverGear:{rotation:x.driverAngle},drivenGear:{rotation:x.drivenAngle}},readout:"\\\\u4E3B\\\\u52A8\\\\u8F6E "+t.formatNumber(x.driverRpm,0)+" rpm \\\\xB7 \\\\u4ECE\\\\u52A8\\\\u8F6E "+t.formatNumber(x.drivenRpm,2)+" rpm \\\\xB7 \\\\u9F7F\\\\u6570\\\\u6BD4 "+t.formatNumber(x.ratio,2)+"\\\\uFF08\\\\u8D1F\\\\u53F7\\\\u8868\\\\u793A\\\\u53CD\\\\u5411\\\\uFF09"})}else if(e==="crank"){let x=X({angle:s,radius:d("radius",20),rod:i.rod??70,z:28});h.update({pose:{crankPin:{at:x.crank},link:{from:x.crank,to:x.piston},piston:{at:[x.position,0,22]},pistonPin:{at:x.piston}},readout:"\\\\u66F2\\\\u67C4\\\\u89D2 "+t.formatNumber((s*180/Math.PI%360+360)%360,1)+"\\\\xB0 \\\\xB7 \\\\u6ED1\\\\u5757\\\\u4F4D\\\\u7F6E "+t.formatNumber(x.position,2)+" \\\\xB7 \\\\u884C\\\\u7A0B "+t.formatNumber(x.stroke,1)+"\\\\uFF08\\\\u793A\\\\u610F\\\\u957F\\\\u5EA6\\\\u5355\\\\u4F4D\\\\uFF09"})}u=w}let N=null,$=()=>{O(0,u,!0),e!=="assembly"&&(d("running",!1)&&!N?N=t.animate(({delta:A,reducedMotion:w,visible:T})=>{T&&!w?O(A,!1,!0):u!==w&&O(0,w,T)}):!d("running",!1)&&N&&(N(),N=null))},P=t.subscribe($);return O(),Object.freeze({...h,destroy(){M||(M=!0,N?.(),P(),h.destroy())}})}return Object.freeze({mount:a,mountDemo:n,gearPair:W,sliderCrank:X,follow:Mt,scenes:Object.freeze({assembly:ft,gears:pt,crank:ht})})}return _t(Tt);})();\\n\';\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const styleCache = /* @__PURE__ */ new WeakMap(), styleOf = (el2) => {\n let css = styleCache.get(el2);\n if (!css) {\n css = getComputedStyle(el2);\n styleCache.set(el2, css);\n }\n return css;\n };\n const target = (el2) => {\n if (!el2) return void 0;\n const tag = el2.tagName.toLowerCase(), id = el2.id;\n return { selector: id && id.length <= 64 ? "#" + CSS.escape(id) : tag, text: (el2.textContent ?? "").trim().replace(/\\s+/g, " ").slice(0, 120), tag };\n };\n const add = (code, value, el2) => {\n if (issues.length >= 40) return;\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const location = target(el2);\n const k2 = id + ":" + code + ":" + (location?.selector ?? "") + ":" + (location?.text ?? "") + ":" + Math.round(value ?? 0);\n if (!seen.has(k2) && issues.length < 40) {\n seen.add(k2);\n issues.push({ code, nodeId: id, ...location ? { target: location } : {}, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m2 = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m2 = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v2) => v2 <= 0.04045 ? v2 / 12.92 : ((v2 + 0.055) / 1.055) ** 2.4).reduce((s, v2, i) => s + v2 * [0.2126, 0.7152, 0.0722][i], 0);\n const blend = (front, back) => front.slice(0, 3).map((v2, i) => v2 * front[3] + back[i] * (1 - front[3])).concat(1);\n const background = (el2) => {\n const layers = [];\n let n = el2;\n for (let i = 0; n && i < 64; i++, n = n.parentElement) {\n const c = styleOf(n);\n if (c.backgroundImage !== "none") return null;\n const colorValue = color(c.backgroundColor);\n if (!colorValue) return null;\n if (colorValue[3] > 0) layers.push(colorValue);\n if (colorValue[3] === 1) {\n let out = layers.pop();\n while (layers.length) out = blend(layers.pop(), out);\n return out;\n }\n }\n return null;\n };\n let contentBottom = root.getBoundingClientRect().top;\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = styleOf(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m2 = el.getScreenCTM();\n if (m2) size *= Math.hypot(m2.c, m2.d);\n }\n if (size < 11.9) add("smallText", size, el);\n if (!(el instanceof SVGElement)) {\n const fg = color(css.color), bg = background(el);\n let opacitySafe = true, opacityDepth = 0;\n for (let a2 = el; a2; a2 = a2.parentElement) {\n if (++opacityDepth > 64 || parseFloat(styleOf(a2).opacity) < 1) {\n opacitySafe = false;\n break;\n }\n }\n if (fg && bg && opacitySafe) {\n coverage.contrastChecked++;\n const a2 = luminance(blend(fg, bg)), b2 = luminance(bg), ratio = (Math.max(a2, b2) + 0.05) / (Math.min(a2, b2) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n const range = document.createRange();\n range.selectNodeContents(el);\n const bounds = range.getBoundingClientRect();\n let a = el, depth = 0;\n while (a && a !== root.parentElement && depth++ < 24) {\n const c = styleOf(a), clip = a.getBoundingClientRect();\n if (["hidden", "clip"].includes(c.overflowX) && (bounds.left < clip.left - 2 || bounds.right > clip.right + 2) || ["hidden", "clip"].includes(c.overflowY) && (bounds.top < clip.top - 2 || bounds.bottom > clip.bottom + 2)) {\n add("clippedText", void 0, el);\n break;\n }\n a = a.parentElement;\n }\n } else coverage.contrastUncovered++;\n }\n if (text2 || el.matches("svg,canvas,img,video,input,select,textarea,button")) contentBottom = Math.max(contentBottom, box.bottom);\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n const rect = root.getBoundingClientRect(), gap = rect.bottom - contentBottom;\n if (!coverage.truncated && root.id === "canvas" && rect.height > 320 && gap > Math.max(96, rect.height * 0.25)) add("bottomWhitespace", gap, root);\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:16px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\n#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:var(--canvas-bg,#fff)}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:12px}button{border-radius:999px}.ui-primary{background:var(--canvas-ink,#182537);color:var(--canvas-bg,#fff)}.ui-callout{border-radius:0 12px 12px 0;background:color-mix(in srgb,var(--canvas-accent,#3e60d3) 5%,var(--canvas-bg,#fff))}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/timeline.js\n function createTimelineAPI(animate, capture = false, notify = () => {\n }) {\n const timelines = /* @__PURE__ */ new Map();\n function timeline(options) {\n const { id = "main", duration, draw, loop = false, autoplay = true, chapters = [] } = options ?? {};\n if (typeof id !== "string" || !/^[A-Za-z_][\\w-]{0,63}$/.test(id) || timelines.has(id)) throw Error("Timeline id must be unique");\n if (!Number.isFinite(duration) || duration <= 0 || duration > 86400 || typeof draw !== "function") throw Error("Timeline requires positive duration and draw(time, info)");\n if (!Array.isArray(chapters) || chapters.length > 100 || chapters.some((c) => !c || typeof c.label !== "string" || !Number.isFinite(c.time) || c.time < 0 || c.time >= duration)) throw Error("Invalid timeline chapters");\n let time = 0, playing = !!autoplay && !capture, disposed = false, reduced = false, visible = true;\n const listeners = /* @__PURE__ */ new Set();\n const state2 = () => ({ id, time, duration, playing, loop: !!loop, reducedMotion: reduced, visible, chapters: chapters.map((c) => ({ time: c.time, label: c.label })) });\n const render = () => {\n draw(time, state2());\n notify(state2());\n for (const fn2 of listeners) fn2(state2());\n };\n const seek = (value) => {\n if (disposed) throw Error("Timeline disposed");\n if (!Number.isFinite(value)) throw Error("Timeline seek requires finite seconds");\n time = Math.max(0, Math.min(duration, value));\n render();\n return state2();\n };\n const api = Object.freeze({ state: state2, seek, play() {\n if (disposed) throw Error("Timeline disposed");\n playing = true;\n render();\n }, pause() {\n playing = false;\n render();\n }, replay() {\n playing = !capture;\n seek(0);\n }, chapter(index) {\n if (!Number.isInteger(index) || !chapters[index]) throw Error("Invalid chapter");\n playing = false;\n return seek(chapters[index].time);\n }, subscribe(fn2) {\n if (typeof fn2 !== "function") throw Error("Timeline listener required");\n listeners.add(fn2);\n fn2(state2());\n return () => listeners.delete(fn2);\n }, dispose() {\n if (disposed) return;\n disposed = true;\n stop();\n listeners.clear();\n timelines.delete(id);\n } });\n timelines.set(id, api);\n const stop = animate((info) => {\n reduced = !!info.reducedMotion;\n visible = info.visible !== false;\n if (!capture && playing && !reduced && visible) {\n const next = time + info.delta;\n time = loop ? next % duration : Math.min(duration, next);\n if (!loop && time === duration) playing = false;\n }\n render();\n });\n return api;\n }\n return { timeline, capture: Object.freeze({ list: () => [...timelines.values()].map((t) => t.state()), seek: (id, time) => {\n const t = timelines.get(id);\n if (!t) throw Error("Timeline not found: " + id);\n t.seek(time);\n t.pause();\n return t.state();\n } }) };\n }\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k2) => [k2, values[k2]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k2) => !(node2.stateKeys ?? []).includes(k2))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches&&!window.__DSHMotionRender;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n let soundTick=0,soundPlaying,soundTime,soundVisible;const timelineAPI=(${createTimelineAPI.toString()})(api.animate,!!window.__DSHMotionRender,s=>{if(snapshot.motionSound){const now=performance.now();if(now-soundTick>=100||s.playing!==soundPlaying||s.visible!==soundVisible||(!s.playing&&s.time!==soundTime)){soundTick=now;soundPlaying=s.playing;soundTime=s.time;soundVisible=s.visible;send(\'timeline\',s)}}});api.timeline=timelineAPI.timeline;\n Object.defineProperty(window,\'__DSHMotionCapture\',{value:timelineAPI.capture,writable:false});\n ${node2.libraries?.includes("mechanism") ? MECHANISM_RUNTIME.replace(/<\\/script/gi, "<\\\\/script") + ";api.mechanism=__MotionMechanism.createMechanismAPI(api);" : ""}\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n visual: define(["spec", "stateKey", "warnings"], "Extended native charts, tables, plots, quiz, forms, diagrams, media and 3D"),\n heading: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "Section heading", "tone"),\n text: define(["text", "spans", "size", "weight", "color", "align", "lineHeight", "copyable", "title"], "Readable explanation; copyable:true adds a reusable text panel", "tone"),\n code: define(["code", "lang", "title", "wrap"], "Literal copyable code; displayed only, never executed"),\n callout: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "A short emphasized paragraph", "tone"),\n row: define(["children", "columns", "gap"], "Wrapping parallel content"),\n column: define(["children", "gap"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["title", "items"], "Ordered declared steps with an optional heading"),\n metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind", "variant"], "Selection from declared state options; variant:segmented for 2..8 short options, dropdown otherwise"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action", "href", "path", "variant"], "Agent follow-up, web link or host file opener", "icon"),\n link: define(["text", "href", "path", "variant"], "User-clicked webpage or local file button", "icon"),\n divider: define(["label"], "Quiet section divider"),\n table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "libraries", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/identifiers.js\n var IDENTIFIER_SOURCE = "[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}";\n var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");\n var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/ceil/floor/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = new RegExp(String.raw`\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|(${IDENTIFIER_SOURCE}(?:\\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m2 = token2.exec(source);\n if (!m2) fail2();\n offset = token2.lastIndex;\n tokens.push(m2[1] ? { number: Number(m2[1] + (m2[2] ?? "")) } : m2[3] ? { string: JSON.parse(m2[3]) } : m2[4] ?? m2[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };\n else if (["min", "max", "round", "ceil", "floor", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression2 = (e, at2) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n try {\n return compileExpression(e.expr);\n } catch (error) {\n error.message = "DSH UI: " + at2 + ": " + error.message.replace(/^DSH UI: /, "");\n error.path = at2;\n throw error;\n }\n }\n if (Array.isArray(e.args)) e.args = e.args.map((v2, i) => expression2(v2, at2 + ".args[" + i + "]"));\n if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2], at2 + ".map.fields." + k2);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k2 of Object.keys(doc2.derived)) doc2.derived[k2] = expression2(doc2.derived[k2], "derived." + k2);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression2(node2[field], "node." + node2.id + "." + field);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const [rowIndex, row] of node2.rows.entries()) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2], "node." + node2.id + ".rows[" + rowIndex + "]." + k2);\n }\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/visual-guard.js\n var ne = ["h1", "h2", "h3", "body", "muted", "caption"];\n var te = ["primary", "danger", "success", "ghost"];\n var ie = ["success", "warn", "danger", "accent"];\n var re = ["text", "email", "password", "color"];\n var se = ["info", "success", "warning", "error"];\n var U = ["bars", "line", "donut"];\n var oe = ["line", "area", "scatter"];\n var ae = ["16:9", "4:3", "1:1", "9:16"];\n var ue = ["box", "sphere", "cone", "cylinder", "torus"];\n var le = ["file", "dir"];\n var de = ["architecture", "it-state", "flowchart", "sequence", "state", "er", "timeline", "swimlane", "quadrant", "radar", "loop", "nested", "tree", "org-chart", "layers", "venn", "pyramid", "bar", "line", "gantt", "scatter", "high-level", "process", "medallion", "data-flow", "dp-integration", "dp-security-matrix"];\n var ce = ["focal", "backend", "store", "external", "input", "optional", "security"];\n var fe = ["light", "dark", "editorial"];\n var pe = ["solid", "dashed", "accent", "link"];\n var me = ["auto", "orthogonal", "straight"];\n var ge = ["bar", "line", "area", "pie", "scatter", "radar", "gauge", "funnel", "treemap", "sankey", "graph", "heatmap", "bigline", "wordCloud"];\n var tn = ["hero"];\n var ye = ["bar", "ring"];\n var be = ["info", "success", "warning", "danger"];\n var he = ["accent", "success", "warning", "danger"];\n var Ee = ["text", "num", "delta", "bar", "badge", "spark", "ring", "index", "group"];\n var b = (t, i, r = {}, e = {}) => {\n let s = Object.fromEntries(Object.entries(i).filter(([u]) => u !== "type" && !t.includes(u))), n = e.oneOfRequired ?? [], o = e.conditionalRequired ?? [], a = [...n.map((u) => ({ kind: "one-of-required", fields: u })), ...o];\n return { required: t, fields: i, optional: s, aliases: r, valueAliases: e.valueAliases ?? {}, oneOfRequired: n, conditionalRequired: o, rules: a, enums: e.enums ?? {}, nested: e.nested ?? {}, ...e.validator === void 0 ? {} : { validator: e.validator } };\n };\n var G = (t, i, r = {}, e = {}, s = {}) => ({ required: t, fields: i, enums: e, nested: r, aliases: s });\n var h = { type: "string", span: "number", id: "string" };\n var De = G(["label", "value"], { label: "string", value: "number", color: "string" });\n var rn = G(["label", "data"], { label: "string", color: "string", data: "array" }, { data: De });\n var sn = G(["title"], { title: "string", desc: "string" });\n var on = G(["key", "value"], { key: "string", value: "string" }, {}, {}, { label: "key" });\n var an = G(["title"], { title: "string", desc: "string", time: "string" });\n var un = G(["path", "newText"], { path: "string", oldText: "string-or-null", newText: "string" });\n var ln = G(["name", "value"], { name: "string", value: "number", min: "number", max: "number", step: "number", animateTo: "number", durationMs: "number", loop: "boolean" });\n var dn = G(["expr"], { expr: "string", label: "string", color: "string", kind: "string", params: "array" }, { params: ln }, { kind: oe });\n var cn = G(["shape"], { shape: "string", color: "string", position: "array", rotation: "array", scale: "unknown", size: "unknown" }, {}, { shape: ue });\n function Oe(t) {\n return G(["name"], { name: "string", type: "string", children: "array" }, t > 0 ? { children: Oe(t - 1) } : {}, { type: le }, { label: "name" });\n }\n var fn = Oe(6);\n var pn = G(["label", "items"], { label: "string", items: "nodes", content: "nodes" });\n var mn = G(["title", "items"], { title: "string", items: "nodes" });\n var gn = G(["id", "label"], { id: "string", label: "string", sub: "string", type: "string", x: "number", y: "number", w: "number", h: "number", tag: "string" }, {}, { type: ce });\n var yn = G(["from", "to"], { from: "string", to: "string", label: "string", kind: "string", route: "string" }, {}, { kind: pe, route: me });\n var bn = G(["label"], { label: "string", x: "number", y: "number", w: "number", h: "number" });\n var hn = G([], { paper: "string", "paper-2": "string", ink: "string", muted: "string", soft: "string", rule: "string", accent: "string", "accent-tint": "string", link: "string" });\n var V = b(["items"], { title: "string", gap: "number", panel: "boolean", append: "boolean", items: "nodes" });\n var T = { accordion: b(["items"], { ...h, items: "array" }, {}, { nested: { items: mn } }), audio: b(["src"], { ...h, src: "string", alt: "string", loop: "boolean" }, { url: "src", link: "src" }), avatar: b(["name"], { ...h, name: "string", color: "string" }), badge: b(["label"], { ...h, label: "string", tone: "string", icon: "string" }, { text: "label", value: "label" }, { enums: { tone: ie } }), breadcrumb: b(["items"], { ...h, items: "array" }), button: b(["label"], { ...h, label: "string", tone: "string", full: "boolean", small: "boolean", icon: "string", action: "string" }, {}, { enums: { tone: te } }), callout: b(["content"], { ...h, title: "string", content: "string", tone: "string" }, { kind: "tone", text: "content", body: "content", desc: "content" }, { enums: { tone: se }, valueAliases: { tone: { danger: "error", warn: "warning" } } }), card: b(["items"], { ...h, title: "string", items: "nodes", tone: "string", accent: "string" }, { label: "title", content: "items" }, { enums: { tone: be } }), chart: b([], { ...h, kind: "string", data: "array", series: "array", horizontal: "boolean", stacked: "boolean", filter: "string", palette: "array" }, {}, { oneOfRequired: [["data", "series"]], conditionalRequired: [{ kind: "required-if", when: { field: "kind", equals: "donut" }, required: ["data"] }], nested: { data: De, series: rn }, enums: { kind: U }, validator: { name: "chart-renderability" } }), checkbox: b(["label"], { ...h, label: "string", checked: "boolean", action: "string", group: "string" }), code: b(["code"], { ...h, lang: "string", code: "string", title: "string", wrap: "boolean" }, { content: "code", text: "code" }), col: b(["items"], { ...h, items: "nodes", gap: "number" }), copy: b(["text"], { ...h, label: "string", text: "string" }, { content: "text", code: "text", value: "text" }), diagram: b(["kind", "nodes"], { ...h, kind: "string", variant: "string", title: "string", nodes: "array", edges: "array", zones: "array", theme: "object" }, {}, { nested: { nodes: gn, edges: yn, zones: bn, theme: hn }, enums: { kind: de, variant: fe } }), diff: b(["diffs"], { ...h, diffs: "array" }, { items: "diffs", files: "diffs" }, { nested: { diffs: un } }), divider: b([], h), echart: b([], { ...h, title: "string", height: "number", preset: "string", data: "array", series: "array", links: "array", palette: "array", option: "object" }, {}, { oneOfRequired: [["option", "data", "series", "links"]], enums: { preset: ge } }), "file-tree": b(["items"], { ...h, items: "array" }, { nodes: "items" }, { nested: { items: fn } }), grid: b(["items"], { ...h, cols: "number", items: "nodes" }), image: b(["src"], { ...h, src: "string", alt: "string" }, { url: "src", link: "src" }), input: b([], { ...h, label: "string", placeholder: "string", value: "string", inputType: "string", action: "string", id: "string" }, {}, { enums: { inputType: re } }), json: b(["value"], { ...h, value: "unknown" }), keyvalue: b(["pairs"], { ...h, pairs: "array" }, { items: "pairs", rows: "pairs", entries: "pairs" }, { nested: { pairs: on } }), link: b(["label"], { ...h, label: "string", href: "string" }), list: b(["items"], { ...h, items: "array", filter: "string" }), mermaid: b(["code"], { ...h, code: "string" }), svg: b(["code"], { ...h, code: "string", title: "string", height: "number" }), plot: b(["series"], { ...h, series: "array", xMin: "number", xMax: "number", yMin: "number", yMax: "number", title: "string" }, {}, { nested: { series: dn } }), progress: b(["value"], { ...h, value: "number", label: "string", valueLabel: "string", variant: "string", target: "number" }, {}, { enums: { variant: ye } }), quiz: b(["question", "options"], { ...h, question: "string", options: "array", explanation: "string", id: "string", action: "string" }, { title: "question", text: "question", choices: "options", items: "options" }), radio: b(["options"], { ...h, label: "string", options: "array", selected: "number", action: "string", group: "string", answer: "unknown", explanation: "string" }, { items: "options" }), row: b(["items"], { ...h, items: "nodes", wrap: "boolean", spacer: "boolean" }), scene3d: b(["meshes"], { ...h, title: "string", meshes: "array", ambient: "number", background: "string" }, {}, { nested: { meshes: cn } }), select: b(["options"], { ...h, label: "string", options: "array", action: "string", selected: "number", id: "string" }, { items: "options" }), slider: b([], { ...h, label: "string", min: "number", max: "number", step: "number", value: "number", action: "string", id: "string" }), spacer: b([], h), hero: b(["title"], { ...h, title: "string", subtitle: "string", value: "string", label: "string", delta: "string", spark: "array", tone: "string" }, {}, { enums: { tone: he } }), stat: b(["label", "value"], { ...h, label: "string", value: "string", delta: "string", spark: "array", size: "string" }, {}, { enums: { size: tn } }), steps: b(["steps"], { ...h, steps: "array", current: "number" }, { items: "steps" }, { nested: { steps: sn } }), submit: b(["label"], { ...h, label: "string", action: "string", resetAction: "string", groups: "array" }), switch: b(["label"], { ...h, label: "string", checked: "boolean", action: "string" }), table: b(["columns", "rows"], { ...h, columns: "array", rows: "array", types: "array", total: "boolean", details: "array", filter: "string", filterColumn: "number", sortField: "string", export: "boolean" }, { headers: "columns", data: "rows", items: "rows" }), tabs: b(["tabs"], { ...h, tabs: "array" }, {}, { nested: { tabs: pn } }), text: b(["content"], { ...h, content: "string", size: "string", center: "boolean", copyable: "boolean", title: "string" }, { text: "content" }, { enums: { size: ne } }), textarea: b([], { ...h, label: "string", placeholder: "string", rows: "number", value: "string", action: "string", id: "string" }), timeline: b(["items"], { ...h, items: "array" }, {}, { nested: { items: an } }), video: b(["src"], { ...h, src: "string", alt: "string", poster: "string", loop: "boolean", muted: "boolean", aspectRatio: "string" }, { url: "src", link: "src" }, { enums: { aspectRatio: ae } }) };\n var q = new Set(Object.keys(T));\n function N(t) {\n if (typeof t != "object" || t === null) return false;\n let i = t;\n return typeof i.type != "string" || i.type === "" ? false : Array.isArray(i.items) ? q.has(i.type) : true;\n }\n function z(t) {\n if (typeof t != "object" || t === null) return null;\n let i = t;\n if (typeof i.type != "string" || i.type === "") return null;\n let r = q.has(i.type) ? T[i.type] : void 0, e = typeof i.title == "string" && r !== void 0 && !("title" in r.fields) ? i.title : void 0, s = { ...t };\n return e !== void 0 && delete s.title, { items: [s], ...e !== void 0 ? { title: e } : {}, ...i.panel === true ? { panel: true } : {}, ...i.append === true ? { append: true } : {} };\n }\n var m = { maxDepth: 8, maxNodes: 200, maxString: 2e3, maxCode: 12e3, maxMermaid: 8e3, maxGridCols: 12, maxTabs: 12, maxAccordionItems: 24, maxListItems: 50, maxOptions: 50, maxTableRows: 50, maxTableCols: 12, maxChartPoints: 60, maxPlotSeries: 8, maxPlotParams: 6, maxMeshes: 5, maxQuizOptions: 8, maxSteps: 24, maxTimelineItems: 24, maxBreadcrumbItems: 12, maxKeyValuePairs: 24, maxTreeDepth: 6, maxDiagramNodes: 9, maxDiagramEdges: 12, maxDiagramZones: 3, maxDiagramFocal: 2, maxDiagramLabel: 14, maxEChartOptionDepth: 10, maxEChartArrayLen: 500, maxEChartOptionNodes: 2e3 };\n function ke(t) {\n let i = t.columns, r = Array.isArray(i) && i.length > 0, e = r && Array.isArray(i) && typeof i[0] == "object" && i[0] !== null ? i.map($n) : i, s = kn(e), n = t.rows !== void 0 ? t.rows : t.data;\n if (Array.isArray(n) && n.length > 0 && typeof n[0] == "object" && n[0] !== null && !Array.isArray(n[0])) {\n let u = Array.isArray(t.columns) && t.columns.length > 0 && typeof t.columns[0] == "object" && t.columns[0] !== null ? t.columns.map(Sn).filter((d) => d !== void 0) : Object.keys(n[0]);\n n = n.map((d) => u.map((c) => wn(d[c])));\n }\n let o = null;\n if (!r && Array.isArray(n) && n.length > 0 && Array.isArray(n[0])) {\n let u = xe(n), d = u.length === 0 ? null : An(u);\n d !== null && xe(d.rows).length === d.rows.length && (o = d, s = d.columns.map((c) => c.slice(0, 128)));\n }\n if (s.length === 0 && !Array.isArray(t.columns)) return null;\n let a = xe(o === null ? n : o.rows);\n return Array.isArray(n) ? { columns: s.slice(0, m.maxTableCols), rows: a } : null;\n }\n function I(t) {\n return ke(t)?.rows ?? [];\n }\n function xn(t, i) {\n return !Array.isArray(t) || !Array.isArray(i) || i[0] !== "group" ? false : String(t[0] ?? "").trim() !== "" && t.slice(1).every((r) => String(r ?? "").trim() === "");\n }\n function C(t, i) {\n let r = I(t);\n return i >= 0 && i < r.length && !xn(r[i], t.types);\n }\n function kn(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableCols) break;\n if (typeof r == "string") i.push(r.slice(0, 128));\n else if (r !== null && typeof r == "object") {\n let e = r, s = typeof e.label == "string" ? e.label : typeof e.value == "string" ? e.value : typeof e.title == "string" ? e.title : JSON.stringify(r);\n i.push(s.slice(0, 128));\n }\n }\n return i;\n }\n function xe(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableRows) break;\n if (!Array.isArray(r)) continue;\n let e = [];\n for (let s of r) {\n if (e.length >= m.maxTableCols) break;\n typeof s == "string" ? e.push(s.slice(0, 256)) : typeof s == "number" && Number.isFinite(s) && e.push(s);\n }\n e.length > 0 && i.push(e);\n }\n return i;\n }\n function An(t) {\n let i = t[0];\n if (i === void 0 || i.length === 0) return null;\n let r = t.slice(1);\n if (r.length === 0) {\n let e = i.map((s) => String(s).trim());\n return e.every((s) => s !== "") ? { columns: e, rows: [] } : null;\n }\n return r.every((e) => e.length === i.length) ? { columns: i.map((e) => String(e).trim()), rows: r } : { columns: Array.from({ length: i.length }, (e, s) => `\\u5217${s + 1}`), rows: t };\n }\n function Sn(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return;\n let i = t;\n for (let r of ["key", "dataIndex", "title", "label"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n }\n function wn(t) {\n return typeof t == "string" || typeof t == "number" && Number.isFinite(t) ? t : t == null ? "" : JSON.stringify(t);\n }\n function $n(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return String(t);\n let i = t;\n for (let r of ["title", "label", "key", "dataIndex"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n return JSON.stringify(t);\n }\n function O(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function Ae(t) {\n let i = O(t);\n return i !== void 0 && typeof i.type == "string";\n }\n var Gn = ["label", "value", "delta", "spark", "size"];\n var Rn = { label: "title", name: "title", description: "desc", content: "desc", text: "desc", body: "desc", detail: "desc" };\n function Tn(t, i, r) {\n if (t.length === 0) return null;\n let e = [];\n for (let s = 0; s < t.length; s++) {\n let n = t[s], o = O(n);\n if (o === void 0) return null;\n if (Ae(n)) {\n e.push(r(n, `${i}.items[${s}]`));\n continue;\n }\n if (typeof o.label != "string" && typeof o.value != "string") return null;\n let a = { type: "stat" };\n for (let u of Gn) o[u] !== void 0 && (a[u] = o[u]);\n e.push(a);\n }\n return e;\n }\n function Cn(t, i, r, e) {\n let s = T[r];\n if (s === void 0) return t;\n let n = { ...t };\n for (let [o, a] of Object.entries(s.aliases)) {\n if (!(o in n)) continue;\n let u = `${i}.${o}`, d = a in n;\n d || (n[a] = n[o]), delete n[o], e.push({ kind: "alias", path: u, message: d ? `${u} is ignored because canonical field \'${a}\' is present` : `${u} normalized/adopted as \'${a}\'`, type: r, field: o, canonical: a });\n }\n for (let [o, a] of Object.entries(s.valueAliases)) {\n let u = n[o];\n if (typeof u != "string") continue;\n let d = a[u];\n d === void 0 || d === u || (n[o] = d, e.push({ kind: "alias", path: `${i}.${o}`, message: `${i}.${o} \'${u}\' normalized to \'${d}\'`, type: r, field: o, canonical: d }));\n }\n return n;\n }\n function Se(t, i, r, e, s) {\n if (Array.isArray(t)) return t.map((a, u) => Se(a, i, `${r}[${u}]`, e, s));\n let n = O(t);\n if (n === void 0) return t;\n let o = { ...n };\n for (let [a, u] of Object.entries(i.aliases)) !(a in o) || u in o || (o[u] = o[a], delete o[a], s.push({ kind: "alias", path: `${r}.${a}`, message: `${r}.${a} normalized/adopted as \'${u}\'`, type: e, field: a, canonical: u }));\n for (let [a, u] of Object.entries(i.nested)) o[a] !== void 0 && (o[a] = Se(o[a], u, `${r}.${a}`, e, s));\n return o;\n }\n function we(t) {\n if (Array.isArray(t)) return t.map(we);\n let i = O(t);\n if (i === void 0) return t;\n let r = { ...i };\n return r.type === void 0 && Array.isArray(r.children) && (r.type = "dir"), r.children !== void 0 && (r.children = we(r.children)), r;\n }\n function $e(t, i, r) {\n if (!Ae(t)) return t;\n let e = t.type, s = T[e];\n if (s === void 0) return t;\n let n = Cn(t, i, e, r);\n for (let [u, d] of Object.entries(s.nested)) n[u] !== void 0 && (n[u] = Se(n[u], d, `${i}.${u}`, e, r));\n let o = (u, d) => $e(u, d, r), a = (u, d) => Array.isArray(u) ? u.map((c, f) => o(c, `${d}[${f}]`)) : u;\n if (e === "file-tree" && n.items !== void 0 && (n.items = we(n.items)), e === "stat" && Array.isArray(n.items) && n.label === void 0 && n.value === void 0) {\n let u = Tn(n.items, i, o);\n if (u !== null) return r.push({ kind: "alias", path: `${i}.items`, message: `${i}.items normalized into a row of \'stat\' nodes`, type: e, field: "items", canonical: "row" }), { type: "row", items: u, ...n.span !== void 0 ? { span: n.span } : {} };\n }\n if (e === "row" || e === "col" || e === "grid" || e === "card" || e === "file-tree" || e === "timeline" || e === "breadcrumb") e !== "file-tree" && e !== "timeline" && e !== "breadcrumb" && (n.items = a(n.items, `${i}.items`));\n else if (e === "list" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n if (Ae(u)) return o(u, `${i}.items[${d}]`);\n if (Array.isArray(u) && u.length === 1 && typeof u[0] == "string") return u[0];\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c }, g = `${i}.items[${d}]`;\n for (let [x, $] of Object.entries(Rn)) {\n if (!(x in f)) continue;\n let J = $ in f;\n J || (f[$] = f[x]), delete f[x], r.push({ kind: "alias", path: `${g}.${x}`, type: e, field: x, canonical: $, message: J ? `${g}.${x} is ignored because canonical field \'${$}\' is present` : `${g}.${x} normalized/adopted as \'${$}\'` });\n }\n return !("title" in f) && typeof f.desc == "string" && (f.title = f.desc, delete f.desc, r.push({ kind: "alias", path: `${g}.desc`, type: e, field: "desc", canonical: "title", message: `${g}.desc normalized/adopted as \'title\'` })), f;\n });\n else if (e === "keyvalue" && Array.isArray(n.pairs)) n.pairs.length > 0 && n.pairs.every((u) => Array.isArray(u)) && (n.pairs = n.pairs.map((u) => {\n let d = u;\n return { key: d[0], value: d.length > 1 ? d[1] : "" };\n }));\n else if (e === "tabs" && Array.isArray(n.tabs)) n.tabs = n.tabs.map((u, d) => {\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c };\n if ("content" in f) {\n let g = `${i}.tabs[${d}].content`, x = "items" in f;\n x || (f.items = f.content), delete f.content, r.push({ kind: "alias", path: g, message: x ? `${g} is ignored because canonical field \'items\' is present` : `${g} normalized/adopted as \'items\'`, type: e, field: "content", canonical: "items" });\n }\n return f.items = Array.isArray(f.items) ? f.items.map((g, x) => o(g, `${i}.tabs[${d}].items[${x}]`)) : f.items === void 0 ? [] : [o(f.items, `${i}.tabs[${d}].items[0]`)], f;\n });\n else if (e === "accordion" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n let c = O(u);\n return c === void 0 ? u : { ...c, items: Array.isArray(c.items) ? c.items.map((f, g) => o(f, `${i}.items[${d}].items[${g}]`)) : c.items };\n });\n else if (e === "table" && Array.isArray(n.details)) {\n let u = { columns: n.columns, rows: n.rows, types: n.types };\n n.details = n.details.map((d, c) => !Array.isArray(d) || !C(u, c) ? d : d.map((f, g) => o(f, `${i}.details[${c}][${g}]`)));\n }\n return n;\n }\n function Ie(t) {\n let i = [];\n if (typeof t == "string") try {\n let s = JSON.parse(t);\n (O(s) !== void 0 || Array.isArray(s)) && (t = s, i.push({ kind: "alias", path: "spec", message: "double-encoded JSON string unwrapped into a spec value" }));\n } catch {\n }\n Array.isArray(t) && t.length > 0 && (t = { items: t }, i.push({ kind: "alias", path: "items", message: "root array normalized into an items envelope" }));\n let r = O(t);\n if (r === void 0) return { value: t, warnings: i };\n let e = { ...r };\n return N(e) ? { value: $e(e, "spec", i), warnings: i } : (Array.isArray(e.items) && (e.items = e.items.map((s, n) => $e(s, `items[${n}]`, i))), { value: e, warnings: i });\n }\n function F(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function _e(t) {\n let i = F(t);\n return i !== void 0 && typeof i.type == "string";\n }\n function Ge(t, i, r) {\n if (!_e(t)) return;\n let e = t.type, s = T[e];\n if (s === void 0) return;\n r(t, i, s);\n let n = (o, a) => Ge(o, a, r);\n if ((e === "row" || e === "col" || e === "grid" || e === "card") && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "list" && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "tabs" && Array.isArray(t.tabs)) t.tabs.forEach((o, a) => {\n let u = F(o);\n u !== void 0 && (Array.isArray(u.items) ? u.items.forEach((d, c) => n(d, `${i}.tabs[${a}].items[${c}]`)) : n(u.items, `${i}.tabs[${a}].items`));\n });\n else if (e === "accordion" && Array.isArray(t.items)) t.items.forEach((o, a) => {\n let u = F(o);\n u?.items !== void 0 && Array.isArray(u.items) && u.items.forEach((d, c) => n(d, `${i}.items[${a}].items[${c}]`));\n });\n else if (e === "table" && Array.isArray(t.details)) {\n let o = { columns: t.columns, rows: t.rows, types: t.types };\n t.details.forEach((a, u) => {\n Array.isArray(a) && C(o, u) && a.forEach((d, c) => n(d, `${i}.details[${u}][${c}]`));\n });\n }\n }\n function B(t, i, r, e) {\n t.push({ kind: "unknown-field", path: `${i}.${r}`, message: `${i}.${r}: unknown field for \'${e}\'`, type: e, field: r });\n }\n function Y(t, i, r, e, s) {\n let n = F(t);\n if (n !== void 0) {\n for (let o of Object.keys(n)) o in r.fields || B(s, i, o, e);\n for (let [o, a] of Object.entries(r.nested)) {\n let u = n[o];\n Array.isArray(u) ? u.forEach((d, c) => Y(d, `${i}.${o}[${c}]`, a, e, s)) : u !== void 0 && Y(u, `${i}.${o}`, a, e, s);\n }\n }\n }\n function Nn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n Array.isArray(o) ? o.forEach((a, u) => Y(a, `${i}.${s}[${u}]`, n, t.type, e)) : o !== void 0 && Y(o, `${i}.${s}`, n, t.type, e);\n }\n }\n function Pe(t) {\n let i = [], r = F(t);\n if (r === void 0) return i;\n let e = (s, n, o) => {\n for (let a of Object.keys(s)) a === "type" || a in o.fields || B(i, n, a, s.type);\n Nn(s, n, o, i), s.type === "list" && Array.isArray(s.items) && s.items.forEach((a, u) => {\n if (_e(a)) return;\n let d = F(a);\n if (d !== void 0) for (let c of Object.keys(d)) {\n if (c === "title" || c === "desc") continue;\n let f = `${n}.items[${u}]`;\n i.push({ kind: "unknown-field", path: `${f}.${c}`, message: `${f}.${c}: list items render \'title\' and \'desc\' only \\u2014 \'${c}\' is dropped`, type: "list", field: c });\n }\n });\n };\n if (Array.isArray(r.items) && !N(r)) {\n for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n r.items.forEach((s, n) => Ge(s, `items[${n}]`, e));\n } else if (typeof r.type == "string") Ge(r, "spec", e);\n else for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n return i;\n }\n function ve(t, i) {\n let r = (s, n, o) => {\n o > m.maxDepth || s.forEach((a, u) => e(a, `${n}[${u}]`, o));\n }, e = (s, n, o) => {\n if (!(o > m.maxDepth) && (i(s, n), !(o >= m.maxDepth))) switch (s.type) {\n case "row":\n case "col":\n case "grid":\n case "card":\n r(s.items, `${n}.items`, o + 1);\n break;\n case "tabs":\n s.tabs.forEach((a, u) => r(a.items, `${n}.tabs[${u}].items`, o + 1));\n break;\n case "accordion":\n s.items.forEach((a, u) => r(a.items, `${n}.items[${u}].items`, o + 1));\n break;\n case "list":\n s.items.forEach((a, u) => {\n a !== null && typeof a == "object" && "type" in a && e(a, `${n}.items[${u}]`, o + 1);\n });\n break;\n case "table":\n s.details?.slice(0, I(s).length).forEach((a, u) => {\n a !== null && C(s, u) && r(a, `${n}.details[${u}]`, o + 1);\n });\n break;\n }\n };\n r(t.items, "items", 0);\n }\n function Re(t) {\n let i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), e = [], s = [];\n ve(t, (n, o) => {\n if (n.type === "submit") {\n n.groups !== void 0 && s.push({ groups: n.groups, path: o });\n return;\n }\n let a, u;\n switch (n.type) {\n case "radio":\n if (n.group === void 0) return;\n a = { kind: "radio", key: n.group, label: n.label ?? n.group, options: n.options.slice(0, m.maxOptions), ...n.answer === void 0 ? {} : { answer: n.answer }, ...n.explanation === void 0 ? {} : { explanation: n.explanation } }, u = `${o}.group`;\n break;\n case "checkbox":\n if (n.group === void 0) return;\n a = { kind: "checkbox", key: n.group }, u = `${o}.group`;\n break;\n case "input":\n case "textarea":\n case "select":\n case "slider":\n if (n.id === void 0) return;\n a = { kind: "field", key: n.id, fieldType: n.type, secret: n.type === "input" && n.inputType === "password" }, u = `${o}.id`;\n break;\n default:\n return;\n }\n if (a === void 0) return;\n let d = i.get(a.key);\n if (d !== void 0) {\n (d.kind !== "checkbox" || a.kind !== "checkbox") && e.push(`${u} conflicts with ${r.get(a.key)}: submission key \'${a.key}\' is already used`);\n return;\n }\n i.set(a.key, a), r.set(a.key, u);\n });\n for (let { groups: n, path: o } of s) {\n let a = /* @__PURE__ */ new Set();\n n.forEach((u, d) => {\n let c = `${o}.groups[${d}]`;\n a.has(u) && e.push(`${c}: duplicate submission member \'${u}\'`), a.add(u);\n let f = i.get(u);\n f === void 0 ? e.push(`${c}: submit.groups references unknown submission member \'${u}\'`) : f.kind === "field" && f.secret && e.push(`${c}: submit.groups cannot require secret field \'${u}\'`);\n });\n }\n return { registry: { members: i }, diagnostics: e };\n }\n function En(t, i) {\n return typeof t == "string" && i.includes(t);\n }\n function p(t, i) {\n return typeof t == "string" ? t.slice(0, i) : void 0;\n }\n var Dn = /^(?:#[\\da-fA-F]{3,8}|rgba?\\([^)]{0,64}\\)|hsla?\\([^)]{0,64}\\)|var\\(--dsw-[\\w-]+(?:,\\s*#[0-9a-fA-F]{3,8})?\\))$/;\n function E(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n return i.length <= 64 && Dn.test(i) ? i : void 0;\n }\n function qe(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i.length > 2048)) return /^https?:\\/\\//i.test(i) || /^mailto:[^@\\s]+@[^@\\s]+$/i.test(i) ? i : void 0;\n }\n function K(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i === "" || i.length > 2048)) {\n if (/^https?:\\/\\//i.test(i)) return i;\n if (!(/^[a-z][a-z0-9+.-]*:/i.test(i) || /^[/\\\\]{2}/.test(i))) return i;\n }\n }\n function k(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, t)) : void 0;\n }\n function D(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, Math.trunc(t))) : void 0;\n }\n function w(t, i) {\n return En(t, i) ? t : void 0;\n }\n function y(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function l(t, i) {\n return i === void 0 ? {} : { [t]: i };\n }\n function On(t) {\n if (t.length > 2048) return;\n let i = t.indexOf("#"), r = i < 0 ? t : t.slice(0, i);\n if (r.includes("?")) return;\n let e;\n try {\n e = decodeURIComponent(r);\n } catch {\n return;\n }\n if (e === "" || /[\\u0000-\\u001f\\u007f]/.test(e) || /^[\\\\/]{2}/.test(e) || /^[a-z][a-z\\d+.-]*:/i.test(e) && !/^[a-z]:[\\\\/]/i.test(e)) return;\n if (i < 0) return { path: e };\n let s = /^L([1-9]\\d*)(?:-L([1-9]\\d*))?$/.exec(t.slice(i + 1));\n if (s === null) return;\n let n = Number(s[1]), o = s[2] === void 0 ? n : Number(s[2]);\n if (!(!Number.isSafeInteger(n) || !Number.isSafeInteger(o) || o < n)) return { path: e, line: n };\n }\n function ze(t) {\n let i = qe(t);\n if (i !== void 0) return { type: "external", href: i };\n if (typeof t != "string") return { type: "invalid" };\n let r = On(t.trim());\n return r === void 0 ? { type: "invalid" } : { type: "file", file: r };\n }\n function H(t, i) {\n switch (i) {\n case "string":\n return typeof t == "string";\n case "string-or-null":\n return t === null || typeof t == "string";\n case "number":\n return typeof t == "number" && Number.isFinite(t);\n case "boolean":\n return typeof t == "boolean";\n case "nodes":\n return Array.isArray(t);\n case "array":\n return Array.isArray(t);\n case "object":\n return y(t) !== void 0;\n case "unknown":\n return true;\n }\n }\n function j(t) {\n switch (t) {\n case "string-or-null":\n return "a string or null";\n case "number":\n return "a finite number";\n case "boolean":\n return "a boolean";\n case "nodes":\n case "array":\n return "an array";\n case "object":\n return "an object";\n case "unknown":\n return "a value";\n default:\n return "a string";\n }\n }\n function v(t, i, r) {\n return t.some((e) => e.startsWith(`${i}.${r} `) || e.includes(`\'${r}\'`) || e.includes(`requires ${r}`));\n }\n function Ke(t, i, r, e, s = []) {\n for (let [n, o] of Object.entries(r.fields)) s.includes(n) || t[n] === void 0 || !H(t[n], o) && !v(e, i, n) && e.push(`${i}.${n} must be ${j(o)}`);\n for (let [n, o] of Object.entries(r.enums)) s.includes(n) || t[n] === void 0 || !H(t[n], "string") || !o.includes(t[n]) && !v(e, i, n) && e.push(`${i}.${n} must be one of ${o.join(", ")}`);\n }\n function W(t, i, r, e) {\n let s = y(t);\n if (s === void 0) {\n e.push(`${i} must be an object`);\n return;\n }\n for (let n of r.required) {\n let o = r.fields[n];\n s[n] === void 0 ? v(e, i, n) || e.push(`${i}: requires ${n}${o === void 0 ? "" : ` (${j(o)})`}`) : o !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n }\n for (let [n, o] of Object.entries(r.fields)) s[n] !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n for (let [n, o] of Object.entries(r.enums)) s[n] !== void 0 && typeof s[n] == "string" && !o.includes(s[n]) && (v(e, i, n) || e.push(`${i}.${n} must be one of ${o.join(", ")}`));\n for (let [n, o] of Object.entries(r.nested)) {\n let a = s[n];\n a !== void 0 && (Array.isArray(a) ? a.forEach((u, d) => W(u, `${i}.${n}[${d}]`, o, e)) : W(a, `${i}.${n}`, o, e));\n }\n }\n function Mn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n o !== void 0 && (Array.isArray(o) ? o.forEach((a, u) => W(a, `${i}.${s}[${u}]`, n, e)) : W(o, `${i}.${s}`, n, e));\n }\n }\n function He(t) {\n let i = t.rows !== void 0 ? t.rows : t.data;\n return !Array.isArray(i) || i.length === 0 ? false : Array.isArray(i[0]);\n }\n function In(t, i, r, e) {\n let s = String(t.type), n = (a) => v(e, i, a), o = s === "table" && He(t) ? "columns" : null;\n for (let a of r.required) {\n let u = r.fields[a];\n if (u === void 0 || t[a] === void 0) {\n a !== o && !n(a) && e.push(`${i}: type \'${s}\' requires ${a}${u === void 0 ? "" : ` (${j(u)})`}`);\n continue;\n }\n !H(t[a], u) && !n(a) && e.push(`${i}.${a} must be ${j(u)}`);\n }\n Ke(t, i, r, e, ["type"]);\n for (let a of r.oneOfRequired) !a.some((u) => t[u] !== void 0) && !e.some((u) => u.includes(`requires ${a.join(" or ")}`)) && e.push(`${i}: type \'${s}\' requires one of ${a.join(" or ")}`);\n for (let a of r.conditionalRequired) if (t[a.when.field] === a.when.equals) for (let u of a.required) t[u] === void 0 && !n(u) && e.push(`${i}: type \'${s}\' requires ${u}${a.message === void 0 ? "" : ` (${a.message})`}`);\n Mn(t, i, r, e);\n }\n function _(t, i, r) {\n if (!Array.isArray(t)) return [];\n let e = [];\n for (let s of t) {\n if (i.remaining <= 0) break;\n i.remaining -= 1;\n let n = Je(s, i, r);\n n !== null && e.push(n);\n }\n return e;\n }\n function Fe(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 12)) {\n let e = E(r);\n e !== void 0 && i.push(e);\n }\n return i.length > 0 ? i : void 0;\n }\n function je(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 60)) {\n let e = typeof r == "number" ? r : Number(r);\n if (!Number.isFinite(e)) return;\n i.push(e);\n }\n return i.length >= 2 ? i : void 0;\n }\n function Je(t, i, r) {\n let e = _n(t, i, r);\n if (e === null) return null;\n let s = D(y(t)?.span, 2, 12), n = p(y(t)?.id, 64);\n return { ...e, ...l("span", s), ...l("id", n) };\n }\n function _n(t, i, r) {\n if (r > m.maxDepth) return null;\n let e = y(t);\n if (e === void 0) return null;\n let s = e.type;\n if (typeof s != "string") return null;\n switch (s) {\n case "text": {\n let n = p(e.content, m.maxString) ?? p(e.text, m.maxString);\n return n === void 0 ? null : { type: "text", content: n, ...l("copyable", e.copyable === true ? true : void 0), ...l("title", p(e.title, m.maxString)), ...l("size", w(e.size, ne)), ...l("center", e.center === true ? true : void 0) };\n }\n case "row":\n return { type: "row", items: _(e.items, i, r + 1), ...l("wrap", e.wrap === true ? true : void 0), ...l("spacer", e.spacer === true ? true : void 0) };\n case "col":\n return { type: "col", items: _(e.items, i, r + 1), ...l("gap", k(e.gap, 0, 96)) };\n case "grid":\n return { type: "grid", cols: D(e.cols, 1, m.maxGridCols) ?? 1, items: _(e.items, i, r + 1) };\n case "card":\n return { type: "card", items: _(e.items, i, r + 1), ...l("title", p(e.title, m.maxString)), ...l("tone", w(e.tone, be)), ...l("accent", E(e.accent)) };\n case "button": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "button", label: n, ...l("tone", w(e.tone, te)), ...l("full", e.full === true ? true : void 0), ...l("small", e.small === true ? true : void 0), ...l("icon", p(e.icon, 64)), ...l("action", p(e.action, 200)) };\n }\n case "input":\n return { type: "input", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("value", p(e.value, m.maxString)), ...l("inputType", w(e.inputType, re)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "select": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "select", options: n, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("id", p(e.id, 200)) };\n }\n case "checkbox": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "checkbox", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)) };\n }\n case "link": {\n let n = p(e.label, m.maxString);\n if (n === void 0) return null;\n let o = ze(e.href), a = o.type === "external" ? o.href : o.type === "file" ? String(e.href).trim() : void 0;\n return { type: "link", label: n, ...l("href", a) };\n }\n case "image": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "image", src: n, ...l("alt", p(e.alt, m.maxString)) };\n }\n case "audio": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "audio", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("loop", e.loop === true ? true : void 0) };\n }\n case "video": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "video", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("poster", K(e.poster)), ...l("loop", e.loop === true ? true : void 0), ...l("muted", e.muted === true ? true : void 0), ...l("aspectRatio", w(e.aspectRatio, ae)) };\n }\n case "badge": {\n let n = p(e.label, m.maxString) ?? p(e.text, m.maxString) ?? p(e.value, m.maxString);\n return n === void 0 ? null : { type: "badge", label: n, ...l("tone", w(e.tone, ie)), ...l("icon", p(e.icon, 64)) };\n }\n case "hero": {\n let n = p(e.title, m.maxString);\n return n === void 0 ? null : { type: "hero", title: n, ...l("subtitle", p(e.subtitle, m.maxString)), ...l("value", p(e.value, 128)), ...l("label", p(e.label, m.maxString)), ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("tone", w(e.tone, he)) };\n }\n case "stat": {\n let n = p(e.label, m.maxString), o = p(e.value, 128);\n return n === void 0 || o === void 0 ? null : { type: "stat", label: n, value: o, ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("size", e.size === "hero" ? "hero" : void 0) };\n }\n case "progress": {\n let n = k(e.value, 0, 100);\n return n === void 0 ? null : { type: "progress", value: n, ...l("label", p(e.label, m.maxString)), ...l("valueLabel", p(e.valueLabel, 64)), ...l("variant", w(e.variant, ye)), ...l("target", k(e.target, 0, 100)) };\n }\n case "divider":\n return { type: "divider" };\n case "spacer":\n return { type: "spacer" };\n case "avatar": {\n let n = p(e.name, 64);\n return n === void 0 ? null : { type: "avatar", name: n, ...l("color", E(e.color)) };\n }\n case "list": {\n let n = Pn(e.items, m.maxListItems, i, r + 1);\n return n === void 0 ? null : { type: "list", items: n, ...l("filter", p(e.filter, 64)) };\n }\n case "table": {\n let n = ke(e);\n if (n === null) return null;\n let { columns: o, rows: a } = n, u = Array.isArray(e.types) ? e.types : void 0, d = u === void 0 ? void 0 : o.map((g, x) => {\n let $ = u[x];\n return typeof $ == "string" && Ee.includes($) ? $ : "text";\n }), c = Array.isArray(e.details) ? e.details : void 0, f = c === void 0 ? void 0 : a.map((g, x) => {\n if (!C({ columns: o, rows: a, types: d }, x)) return null;\n let $ = _(c[x], i, r + 1);\n return $.length === 0 ? null : $;\n });\n return { type: "table", columns: o, rows: a, ...l("types", d), ...l("total", e.total === true ? true : void 0), ...l("export", e.export === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("filterColumn", D(e.filterColumn, 0, m.maxTableCols - 1)), ...l("sortField", p(e.sortField, 64)), ...l("details", f !== void 0 && f.some((g) => g !== null) ? f : void 0) };\n }\n case "chart": {\n let n = Te(e.data, m.maxChartPoints), o = Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0;\n return n === void 0 && o === void 0 ? null : { type: "chart", data: n ?? [], ...l("kind", w(e.kind, U)), ...l("series", o), ...l("horizontal", e.horizontal === true ? true : void 0), ...l("stacked", e.stacked === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("palette", Fe(e.palette)) };\n }\n case "tabs": {\n let n = vn(e.tabs, i, r);\n return n === void 0 ? null : { type: "tabs", tabs: n };\n }\n case "plot": {\n let n = qn(e.series, m.maxPlotSeries);\n return n === void 0 ? null : { type: "plot", series: n, ...l("xMin", k(e.xMin, -1e6, 1e6)), ...l("xMax", k(e.xMax, -1e6, 1e6)), ...l("yMin", k(e.yMin, -1e9, 1e9)), ...l("yMax", k(e.yMax, -1e9, 1e9)), ...l("title", p(e.title, m.maxString)) };\n }\n case "callout": {\n let n = p(e.content, m.maxString);\n return n === void 0 ? null : { type: "callout", content: n, ...l("tone", w(e.tone, se)), ...l("title", p(e.title, m.maxString)) };\n }\n case "steps": {\n let n = zn(e.steps);\n return n === void 0 ? null : { type: "steps", steps: n, ...l("current", D(e.current, 0, n.length)) };\n }\n case "keyvalue": {\n let n = Fn(e.pairs, m.maxKeyValuePairs);\n return n === void 0 ? null : { type: "keyvalue", pairs: n };\n }\n case "diff": {\n let n = jn(e.diffs);\n return n === void 0 ? null : { type: "diff", diffs: n };\n }\n case "json":\n return "value" in e ? { type: "json", value: e.value } : null;\n case "code": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "code", code: n, ...l("lang", p(e.lang, 64)), ...l("title", p(e.title, m.maxString)), ...l("wrap", e.wrap === true ? true : void 0) };\n }\n case "radio": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "radio", options: n, ...l("label", p(e.label, m.maxString)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)), ...l("answer", typeof e.answer == "number" && Number.isFinite(e.answer) && e.answer >= 0 && e.answer < n.length ? Math.trunc(e.answer) : typeof e.answer == "string" ? e.answer.slice(0, 512) : void 0), ...l("explanation", p(e.explanation, m.maxString)) };\n }\n case "submit": {\n let n = p(e.label, m.maxString), o = p(e.action, 200);\n return n === void 0 ? null : { type: "submit", label: n, ...l("action", o), ...l("resetAction", p(e.resetAction, 200)), ...l("groups", Q(e.groups, m.maxOptions, 200)) };\n }\n case "switch": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "switch", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)) };\n }\n case "slider": {\n let n = k(e.min, -1e9, 1e9) ?? 0, o = k(e.max, -1e9, 1e9) ?? 100, a = Math.min(n, o), u = Math.max(n, o), d = k(e.step, 1e-9, Math.max(u - a, 1e-9)), c = k(e.value, a, u) ?? a;\n return { type: "slider", min: a, max: u, ...l("step", d), value: c, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n }\n case "textarea":\n return { type: "textarea", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("rows", D(e.rows, 1, 30)), ...l("value", p(e.value, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "accordion": {\n let n = Ln(e.items, i, r);\n return n === void 0 ? null : { type: "accordion", items: n };\n }\n case "copy": {\n let n = p(e.text, m.maxCode);\n return n === void 0 ? null : { type: "copy", text: n, ...l("label", p(e.label, 128)) };\n }\n case "svg": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "svg", code: n, ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)) };\n }\n case "mermaid": {\n let n = p(e.code, m.maxMermaid);\n return n === void 0 ? null : { type: "mermaid", code: n };\n }\n case "scene3d": {\n let n = Vn(e.meshes);\n return n === void 0 ? null : { type: "scene3d", meshes: n, ...l("title", p(e.title, m.maxString)), ...l("ambient", k(e.ambient, 0, 2)), ...l("background", E(e.background)) };\n }\n case "diagram":\n return Bn(e);\n case "timeline": {\n let n = Yn(e.items, m.maxTimelineItems);\n return n === void 0 ? null : { type: "timeline", items: n };\n }\n case "file-tree": {\n let n = Qn(e.items, m.maxListItems);\n return n === void 0 ? null : { type: "file-tree", items: n };\n }\n case "breadcrumb": {\n let n = Q(e.items, m.maxBreadcrumbItems, m.maxString);\n return n === void 0 ? null : { type: "breadcrumb", items: n };\n }\n case "quiz": {\n let n = p(e.question, m.maxString), o = Zn(e.options, e.answer);\n return n === void 0 || o === void 0 ? null : { type: "quiz", question: n, options: o, ...l("explanation", p(e.explanation, m.maxString)), ...l("id", p(e.id, 200)), ...l("action", p(e.action, 200)) };\n }\n case "echart": {\n let n = e.data !== void 0 ? Te(e.data, m.maxChartPoints) : void 0, o = e.series !== void 0 && Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0, a = Array.isArray(e.links) ? e.links.slice(0, m.maxChartPoints).flatMap((c) => {\n let f = y(c), g = f === void 0 ? void 0 : p(f.from, 64), x = f === void 0 ? void 0 : p(f.to, 64);\n return g === void 0 || x === void 0 ? [] : [{ from: g, to: x, ...l("value", k(f.value, 0, 1e9)) }];\n }) : void 0, u = e.option !== void 0 ? Ce(e.option, 0, { count: m.maxEChartOptionNodes }) : void 0, d = u === void 0 || typeof u != "object" || u === null || Array.isArray(u) ? void 0 : u;\n return d === void 0 && n === void 0 && o === void 0 && (a === void 0 || a.length === 0) ? null : { type: "echart", ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)), ...l("preset", w(e.preset, ge)), ...l("data", n), ...l("series", o), ...l("links", a !== void 0 && a.length > 0 ? a : void 0), ...l("palette", Fe(e.palette)), ...l("option", d) };\n }\n default:\n return t;\n }\n }\n function Q(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n if (typeof s == "string") e.push(s.slice(0, r));\n else if (s !== null && typeof s == "object") {\n let n = s, o = typeof n.label == "string" ? n.label : typeof n.value == "string" ? n.value : typeof n.title == "string" ? n.title : JSON.stringify(s);\n e.push(o.slice(0, r));\n }\n }\n return e;\n }\n function Pn(t, i, r, e) {\n if (!Array.isArray(t)) return;\n let s = [];\n for (let n of t) {\n if (s.length >= i) break;\n if (typeof n == "string") {\n s.push(n.slice(0, m.maxString));\n continue;\n }\n let o = y(n);\n if (o !== void 0 && typeof o.type == "string") {\n if (r.remaining <= 0) break;\n r.remaining -= 1;\n let u = Je(o, r, e);\n u !== null && s.push(u);\n continue;\n }\n let a = o === void 0 ? void 0 : p(o.title, m.maxString);\n a !== void 0 && s.push({ title: a, ...l("desc", p(o?.desc, m.maxString)) });\n }\n return s;\n }\n function Te(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.label, 128), o = s === void 0 ? void 0 : k(s.value, -1e12, 1e12);\n n === void 0 || o === void 0 || r.push({ label: n, value: o, ...l("color", s === void 0 ? void 0 : E(s.color)) });\n }\n return r;\n }\n function Le(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128), a = n === void 0 ? void 0 : Te(n.data, r);\n o === void 0 || a === void 0 || e.push({ label: o, data: a, ...l("color", n === void 0 ? void 0 : E(n.color)) });\n }\n return e;\n }\n function vn(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxTabs) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128);\n if (o === void 0 || n === void 0) continue;\n let a = n.items !== void 0 ? n.items : n.content !== void 0 ? Array.isArray(n.content) ? n.content : [n.content] : void 0;\n e.push({ label: o, items: _(a, i, r + 1) });\n }\n return e;\n }\n function qn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.expr, 512);\n if (n === void 0 || s === void 0) continue;\n let o = [];\n if (Array.isArray(s.params)) for (let a of s.params) {\n if (o.length >= m.maxPlotParams) break;\n let u = y(a), d = u === void 0 ? void 0 : p(u.name, 64), c = u === void 0 ? void 0 : k(u.value, -1e9, 1e9);\n d === void 0 || c === void 0 || o.push({ name: d, value: c, ...l("min", u === void 0 ? void 0 : k(u.min, -1e9, 1e9)), ...l("max", u === void 0 ? void 0 : k(u.max, -1e9, 1e9)), ...l("step", u === void 0 ? void 0 : k(u.step, 1e-9, 1e9)), ...l("animateTo", u === void 0 ? void 0 : k(u.animateTo, -1e9, 1e9)), ...l("durationMs", u === void 0 ? void 0 : k(u.durationMs, 1, 12e4)), ...l("loop", u === void 0 ? void 0 : u.loop === true ? true : void 0) });\n }\n r.push({ expr: n, ...l("label", p(s.label, 128)), ...l("color", E(s.color)), ...l("kind", w(s.kind, oe)), ...l("params", o.length > 0 ? o : void 0) });\n }\n return r;\n }\n function zn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxSteps) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.title, 256);\n s !== void 0 && i.push({ title: s, ...l("desc", e === void 0 ? void 0 : p(e.desc, m.maxString)) });\n }\n return i;\n }\n function Fn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.key, 256), o = s === void 0 ? void 0 : p(s.value, m.maxString);\n n === void 0 || o === void 0 || r.push({ key: n, value: o });\n }\n return r;\n }\n function jn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= 24) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.path, 1024), n = e === void 0 ? void 0 : p(e.newText, 2e4);\n if (s === void 0 || n === void 0) continue;\n let o = e === void 0 ? void 0 : e.oldText;\n i.push({ path: s, newText: n, oldText: o === null || typeof o != "string" ? null : o.slice(0, 2e4) });\n }\n return i;\n }\n function Ln(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxAccordionItems) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.title, 256);\n o === void 0 || n === void 0 || e.push({ title: o, items: _(n.items, i, r + 1) });\n }\n return e;\n }\n function Vn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxMeshes) break;\n let e = y(r), s = e === void 0 ? void 0 : w(e.shape, ue);\n if (s === void 0) continue;\n let n = e === void 0 ? void 0 : k(e.scale, -1e6, 1e6) ?? Z(e.scale), o = e === void 0 ? void 0 : k(e.size, -1e6, 1e6) ?? Z(e.size);\n i.push({ shape: s, ...l("color", e === void 0 ? void 0 : E(e.color)), ...l("position", e === void 0 ? void 0 : Z(e.position)), ...l("rotation", e === void 0 ? void 0 : Z(e.rotation)), ...l("scale", n), ...l("size", o) });\n }\n return i;\n }\n function Z(t) {\n if (!Array.isArray(t) || t.length !== 3) return;\n let [i, r, e] = t;\n if (!(typeof i != "number" || !Number.isFinite(i) || typeof r != "number" || !Number.isFinite(r) || typeof e != "number" || !Number.isFinite(e))) return [Math.min(1e6, Math.max(-1e6, i)), Math.min(1e6, Math.max(-1e6, r)), Math.min(1e6, Math.max(-1e6, e))];\n }\n function P(t, i, r) {\n return Math.min(r, Math.max(i, Math.round(t / 4) * 4));\n }\n function Kn(t) {\n if (!Array.isArray(t)) return;\n let i = [], r = /* @__PURE__ */ new Set();\n for (let e of t) {\n if (i.length >= m.maxDiagramNodes) break;\n let s = y(e);\n if (s === void 0) continue;\n let n = p(s.id, 128), o = p(s.label, m.maxString);\n if (n === void 0 || o === void 0 || r.has(n)) continue;\n r.add(n);\n let a = w(s.type, ce), u = s.x === void 0 ? void 0 : P(k(s.x, -1e6, 1e6) ?? 0, 0, 1e6), d = s.y === void 0 ? void 0 : P(k(s.y, -1e6, 1e6) ?? 0, 0, 1e6), c = s.w === void 0 ? void 0 : P(k(s.w, -1e6, 1e6) ?? 96, 40, 2e3), f = s.h === void 0 ? void 0 : P(k(s.h, -1e6, 1e6) ?? 48, 24, 1200);\n i.push({ id: n, label: o, ...l("sub", p(s.sub, 256)), ...l("type", a), ...l("x", u), ...l("y", d), ...l("w", c), ...l("h", f), ...l("tag", p(s.tag, 32)) });\n }\n return i;\n }\n function Hn(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramEdges) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.from, 128), n = p(e.to, 128);\n s === void 0 || n === void 0 || i.push({ from: s, to: n, ...l("label", p(e.label, m.maxDiagramLabel)), ...l("kind", w(e.kind, pe)), ...l("route", w(e.route, me)) });\n }\n return i;\n }\n function Jn(t) {\n let i = y(t);\n if (i === void 0) return;\n let r = {};\n for (let e of ["paper", "paper-2", "ink", "muted", "soft", "rule", "accent", "accent-tint", "link"]) {\n let s = E(i[e]);\n s !== void 0 && (r[e] = s);\n }\n return Object.keys(r).length === 0 ? void 0 : r;\n }\n function Un(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramZones) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.label, 64);\n s !== void 0 && i.push({ label: s, ...l("x", e.x === void 0 ? void 0 : P(k(e.x, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("y", e.y === void 0 ? void 0 : P(k(e.y, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("w", e.w === void 0 ? void 0 : P(k(e.w, -1e6, 1e6) ?? 100, 40, 2e3)), ...l("h", e.h === void 0 ? void 0 : P(k(e.h, -1e6, 1e6) ?? 100, 40, 1200)) });\n }\n return i;\n }\n function Bn(t) {\n let i = y(t);\n if (i === void 0) return null;\n let r = w(i.kind, de);\n if (r === void 0) return null;\n let e = Kn(i.nodes);\n if (e === void 0) return null;\n let s = Hn(i.edges);\n if (s === void 0) return null;\n let n = Un(i.zones);\n return n === void 0 ? null : { type: "diagram", kind: r, nodes: e, edges: s, ...l("zones", n.length > 0 ? n : void 0), ...l("variant", w(i.variant, fe)), ...l("title", p(i.title, 256)), ...l("theme", Jn(i.theme)) };\n }\n function Yn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.title, 256);\n n !== void 0 && r.push({ title: n, ...l("desc", s === void 0 ? void 0 : p(s.desc, m.maxString)), ...l("time", s === void 0 ? void 0 : p(s.time, 128)) });\n }\n return r;\n }\n function Qn(t, i) {\n return Ue(t, i, m.maxTreeDepth);\n }\n function Ue(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.name, 256);\n if (o === void 0) continue;\n let a = n !== void 0 && r > 0 && Array.isArray(n.children) ? Ue(n.children, i, r - 1) : void 0;\n e.push({ name: o, ...l("type", n === void 0 ? void 0 : w(n.type, le)), ...l("children", a) });\n }\n return e;\n }\n function Zn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let s of t) {\n if (r.length >= m.maxQuizOptions) break;\n let n = y(s), o = typeof s == "string" ? p(s, 512) : n === void 0 ? void 0 : p(n.label, 512);\n o !== void 0 && r.push({ label: o, ...l("correct", n === void 0 ? void 0 : n.correct === true ? true : void 0), ...l("feedback", n === void 0 ? void 0 : p(n.feedback, m.maxString)) });\n }\n if (r.length === 0) return;\n if (r.some((s) => s.correct === true)) return r;\n let e = typeof i == "number" && Number.isFinite(i) ? Math.trunc(i) : typeof i == "string" ? r.findIndex((s) => s.label === i.slice(0, 512)) : -1;\n return e < 0 || e >= r.length ? r : r.map((s, n) => n === e ? { ...s, correct: true } : s);\n }\n var Wn = /<(?:script|img|svg|iframe|video|audio|object|embed|source)\\b|on[a-z]+\\s*=|javascript:/i;\n function Ce(t, i, r) {\n if (r.count <= 0 || (r.count -= 1, i > m.maxEChartOptionDepth)) return;\n if (typeof t == "string") {\n let n = t.slice(0, m.maxString);\n return n.toLowerCase().includes("url(") || Wn.test(n) ? void 0 : n;\n }\n if (typeof t == "number" && Number.isFinite(t) || typeof t == "boolean") return t;\n if (t === null) return null;\n if (Array.isArray(t)) {\n let n = Math.min(t.length, m.maxEChartArrayLen), o = [];\n for (let a = 0; a < n; a++) {\n let u = Ce(t[a], i + 1, r);\n u !== void 0 && o.push(u);\n }\n return o.length > 0 || t.length === 0 ? o : void 0;\n }\n let e = y(t);\n if (e === void 0) return;\n let s = {};\n for (let [n, o] of Object.entries(e)) {\n let a = Ce(o, i + 1, r);\n a !== void 0 && (n === "tooltip" && typeof a == "object" && a !== null && !Array.isArray(a) && (a.renderMode = "richText"), s[n] = a);\n }\n return Object.keys(s).length > 0 || Object.keys(e).length === 0 ? s : void 0;\n }\n function Be(t) {\n let i = y(t);\n if (i === void 0) return null;\n if (N(t)) {\n let e = z(t);\n return e === null ? null : Be(e);\n }\n if (!Array.isArray(i.items)) return null;\n let r = { remaining: m.maxNodes };\n return { ...l("title", p(i.title, m.maxString)), ...l("gap", k(i.gap, 0, 96)), ...l("panel", i.panel === true ? true : void 0), ...l("append", i.append === true ? true : void 0), items: _(i.items, r, 0) };\n }\n function Xn(t, i = Number.POSITIVE_INFINITY) {\n let r = 0, e = (n) => {\n if (Array.isArray(n)) for (let o of n) {\n if (r >= i) return;\n r += 1;\n let a = y(o);\n if (a !== void 0) {\n if (a.type === "tabs" && Array.isArray(a.tabs)) for (let u of a.tabs) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if (a.type === "accordion" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if ((a.type === "row" || a.type === "col" || a.type === "grid" || a.type === "card") && Array.isArray(a.items)) e(a.items);\n else if (a.type !== "file-tree") {\n if (a.type === "list" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && typeof d.type == "string" && e([d]);\n }\n else if (a.type === "table" && Array.isArray(a.details)) {\n let u = I(a).length;\n for (let d = 0; d < Math.min(a.details.length, u); d++) {\n if (r >= i) return;\n let c = a.details[d];\n Array.isArray(c) && C(a, d) && e(c);\n }\n }\n }\n }\n }\n }, s = y(t);\n return e(s === void 0 ? [] : s.items), r;\n }\n var et = q;\n function nt(t, i, r) {\n let e = 0, s = (d) => {\n let c = y(d);\n return c !== void 0 && typeof c.type == "string" && et.has(c.type);\n };\n function n(d, c) {\n if (Array.isArray(d)) {\n for (let f = 0; f < d.length; f++) if (o(d[f], `${c}[${f}]`), e >= i) return;\n }\n }\n function o(d, c) {\n if (e >= i || !s(d)) return;\n let f = y(d);\n if (f !== void 0) {\n if (e += 1, r(f, c), f.type === "tabs" && Array.isArray(f.tabs)) for (let g = 0; g < f.tabs.length; g++) a(f.tabs[g], `${c}.tabs[${g}]`);\n else if (f.type === "accordion" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) a(f.items[g], `${c}.items[${g}]`);\n else if ((f.type === "row" || f.type === "col" || f.type === "grid" || f.type === "card") && Array.isArray(f.items)) n(f.items, `${c}.items`);\n else if (f.type === "list" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) o(f.items[g], `${c}.items[${g}]`);\n else if (f.type === "table" && Array.isArray(f.details)) {\n let g = I(f).length;\n for (let x = 0; x < Math.min(f.details.length, g); x++) Array.isArray(f.details[x]) && C(f, x) && n(f.details[x], `${c}.details[${x}]`);\n }\n }\n }\n function a(d, c) {\n let f = y(d);\n if (f === void 0) return;\n let g = f.items !== void 0 ? f.items : f.content;\n Array.isArray(g) ? n(g, `${c}.items`) : o(g, `${c}.items`);\n }\n let u = y(t);\n return u === void 0 || (N(u) && s(t) ? o(t, "spec") : n(u.items, "items")), e;\n }\n function Ye(t, i = Number.POSITIVE_INFINITY) {\n return nt(t, i, () => {\n });\n }\n function tt(t, i = Number.POSITIVE_INFINITY) {\n return Ye(t, i);\n }\n function Qe(t) {\n let i = [], r = y(t);\n if (r === void 0) return { ok: false, errors: ["spec root must be an object"] };\n if (N(t)) {\n let a = z(t);\n return a !== null ? Qe(a) : { ok: false, errors: ["spec.items must be an array"] };\n }\n if (!Array.isArray(r.items)) return { ok: false, errors: ["spec.items must be an array"] };\n Ke(r, "spec", V, i, ["items"]);\n let e = 0, s = false, n = (a, u, d) => {\n if (!s) {\n if (!Array.isArray(a)) {\n i.push(`${d} must be an array`);\n return;\n }\n for (let c = 0; c < a.length; c++) {\n if (s || e >= m.maxNodes) {\n s || (i.push(`spec exceeds ${m.maxNodes} nodes; tail elided`), s = true);\n return;\n }\n e += 1;\n let f = `${d}[${c}]`;\n Xe(a[c], u, f, i, n);\n }\n }\n };\n n(r.items, 0, "items"), i.length === 0 && i.push(...Re(r).diagnostics);\n let o = [...new Set(i)];\n return { ok: o.length === 0, errors: o };\n }\n function Ze(t) {\n let i = Ie(t), r = Be(i.value), e = Qe(i.value), s = Ye(i.value, m.maxNodes + 1), n = r === null ? 0 : tt(r), o = r === null ? 0 : Xn(r), a = e.errors.filter((u) => !u.includes(": unknown type "));\n return r !== null && a.length === 0 && a.push(...Re(r).diagnostics), s > n && a.push(`repair dropped ${s - n} declared native node(s): declared ${s}, rendered ${n}`), { value: i.value, normalized: i.value, repaired: r, spec: r, errors: [...new Set(a)], warnings: [...i.warnings, ...Pe(i.value)], declaredCount: s, renderedCount: o, declaredNativeCount: s, renderedNativeCount: n, renderedTotalCount: o };\n }\n function it(t) {\n return t.errors.length > 0 && t.errors.every((i) => i.startsWith("spec exceeds ") || i.startsWith("repair dropped ")) && t.renderedNativeCount === m.maxNodes && t.declaredNativeCount === m.maxNodes + 1;\n }\n function Ne(t) {\n return t.spec !== null && (t.errors.length === 0 || it(t));\n }\n var rt = /^(items\\[\\d+\\](?:\\.(?:items\\[\\d+\\]|tabs\\[\\d+\\]\\.items\\[\\d+\\]|details\\[\\d+\\](?:\\[\\d+\\])?))*)/;\n function st(t) {\n let i = rt.exec(t);\n return i === null ? null : i[1] ?? null;\n }\n function Ve(t, i) {\n let r = [...i.matchAll(/(?:^|\\.)(items|tabs|details)\\[(\\d+)\\]|\\[(\\d+)\\]/g)];\n if (r.length === 0 || r[r.length - 1][1] === "tabs") return;\n let e = t;\n for (let s = 0; s < r.length; s++) {\n let n = r[s], o = n[1] === void 0 ? e : y(e)?.[n[1]], a = Number(n[2] ?? n[3]);\n if (!Array.isArray(o) || a >= o.length) return;\n if (s === r.length - 1) return { array: o, index: a, preserveIndex: n[1] === "details" };\n if (e = o[a], e === void 0) return;\n }\n }\n function ot(t) {\n try {\n return y(JSON.parse(JSON.stringify(t))) ?? null;\n } catch {\n return null;\n }\n }\n function at(t) {\n if (Ne(t)) return t.spec;\n if (t.spec === null) return null;\n let i = y(t.value);\n if (i === void 0) return null;\n let r = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set();\n for (let d of t.errors) {\n if (d.startsWith("spec exceeds ")) continue;\n let c = st(d);\n c !== null && (d === `${c}.details must not contain more entries than rows` ? e.add(c) : r.add(c));\n }\n if (r.size === 0 && e.size === 0) return null;\n let s = ot(N(i) ? z(i) : i);\n if (s === null) return null;\n let n = [...r].map((d) => Ve(s, d)).filter((d) => d !== void 0), o = [...e].map((d) => Ve(s, d)).filter((d) => d !== void 0);\n for (let { array: d, index: c } of o) {\n let f = y(d[c]);\n f?.type === "table" && Array.isArray(f.details) && (f.details.length = Math.min(f.details.length, I(f).length));\n }\n let a = /* @__PURE__ */ new Map();\n for (let { array: d, index: c, preserveIndex: f } of n) {\n if (f) {\n d[c] = null;\n continue;\n }\n let g = a.get(d);\n g === void 0 ? a.set(d, [c]) : g.push(c);\n }\n for (let [d, c] of a) {\n c.sort((f, g) => g - f);\n for (let f of c) d.splice(f, 1);\n }\n let u = Ze(s);\n return !Ne(u) || u.renderedNativeCount === 0 ? null : u.spec;\n }\n function We(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), (typeof s.value != "number" || !Number.isFinite(s.value)) && r.push(`${n}.value must be a finite number`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`);\n }\n }\n function ut(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`), Array.isArray(s.data) || r.push(`${n}.data must be an array`), We(s.data, `${n}.data`, r);\n }\n }\n function lt(t, i, r) {\n !Array.isArray(t.data) && !Array.isArray(t.series) && r.push(`${i}: type \'chart\' requires data or series (array)`), t.variant !== void 0 && r.push(`${i}.variant is unsupported; use kind`), t.data !== void 0 && !Array.isArray(t.data) && r.push(`${i}.data must be an array`), t.series !== void 0 && !Array.isArray(t.series) && r.push(`${i}.series must be an array`), t.kind !== void 0 && (typeof t.kind != "string" || !U.includes(t.kind)) && r.push(`${i}.kind must be bars, line, or donut`);\n let e = t.kind === void 0 ? "bars" : t.kind, s = Array.isArray(t.series) ? t.series : void 0;\n if (Array.isArray(t.data) && t.data.length === 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data must not be empty`), s !== void 0) {\n s.length === 0 && r.push(`${i}.series must not be empty`), e === "donut" && r.push(`${i}.series is only supported for bars and line`);\n for (let n = 0; n < s.length; n++) {\n let o = y(s[n]);\n o !== void 0 && Array.isArray(o.data) && o.data.length === 0 && r.push(`${i}.series[${n}].data must not be empty`);\n }\n }\n e === "donut" && t.data === void 0 && r.push(`${i}.data is required for donut`), e === "line" && t.data === void 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data is required for line (or provide series)`), We(t.data, `${i}.data`, r), ut(t.series, `${i}.series`, r);\n }\n function dt(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = t[e];\n if (y(s) === void 0) {\n if (!Array.isArray(s)) {\n r.push(`${i}[${e}] must be an array or object`);\n continue;\n }\n for (let n = 0; n < s.length; n++) {\n let o = s[n];\n typeof o != "string" && (typeof o != "number" || !Number.isFinite(o)) && r.push(`${i}[${e}][${n}] must be a string or finite number`);\n }\n }\n }\n }\n function Xe(t, i, r, e, s) {\n if (i > m.maxDepth) {\n e.push(`${r}: exceeds max depth ${m.maxDepth}`);\n return;\n }\n let n = y(t);\n if (n === void 0) {\n e.push(`${r}: must be an object`);\n return;\n }\n let o = n.type;\n if (typeof o != "string") {\n e.push(`${r}: missing string \'type\'`);\n return;\n }\n let a = (c) => {\n n[c] !== void 0 && typeof n[c] != "string" && e.push(`${r}: \'${c}\' must be a string`);\n }, u = (c) => {\n n[c] !== void 0 && (typeof n[c] != "number" || !Number.isFinite(n[c])) && e.push(`${r}: \'${c}\' must be a finite number`);\n };\n switch (o) {\n case "text":\n typeof n.content != "string" && typeof n.text != "string" && e.push(`${r}: type \'text\' requires content or text (string)`), a("content"), a("text");\n break;\n case "row":\n case "col":\n case "card":\n case "grid":\n Array.isArray(n.items) || e.push(`${r}: type \'${o}\' requires items (array)`), s(n.items, i + 1, `${r}.items`), o === "grid" && u("cols");\n break;\n case "button":\n case "checkbox":\n case "link":\n case "switch":\n typeof n.label != "string" && e.push(`${r}: type \'${o}\' requires label (string)`), a("label");\n break;\n case "image":\n case "audio":\n case "video":\n typeof n.src != "string" && e.push(`${r}: type \'${o}\' requires src (string)`), a("src"), a("alt"), o === "video" && a("poster");\n break;\n case "slider":\n a("label"), u("min"), u("max"), u("step"), u("value");\n break;\n case "input":\n case "textarea":\n a("label"), a("placeholder"), a("value");\n break;\n case "select":\n case "radio":\n Array.isArray(n.options) || e.push(`${r}: type \'${o}\' requires options (array)`);\n break;\n case "submit":\n typeof n.label != "string" && e.push(`${r}: type \'submit\' requires label (string)`);\n break;\n case "badge":\n typeof n.label != "string" && typeof n.text != "string" && typeof n.value != "string" && e.push(`${r}: type \'badge\' requires label, text, or value (string)`), a("label"), a("text"), a("value");\n break;\n case "hero":\n typeof n.title != "string" && e.push(`${r}: type \'hero\' requires title (string)`), a("subtitle");\n break;\n case "stat":\n typeof n.label != "string" && e.push(`${r}: type \'stat\' requires label (string)`), typeof n.value != "string" && e.push(`${r}: type \'stat\' requires value (string)`), a("delta");\n break;\n case "progress":\n (typeof n.value != "number" || !Number.isFinite(n.value) || n.value < 0 || n.value > 100) && e.push(`${r}: type \'progress\' requires value (number 0..100)`), u("value");\n break;\n case "avatar":\n typeof n.name != "string" && e.push(`${r}: type \'avatar\' requires name (string)`);\n break;\n case "list":\n if (Array.isArray(n.items) || e.push(`${r}: type \'list\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n f !== void 0 && typeof f.type == "string" && Xe(f, i + 1, `${r}.items[${c}]`, e, s);\n }\n break;\n case "table":\n if (!Array.isArray(n.columns) && !He(n) && e.push(`${r}: type \'table\' requires columns (array)`), Array.isArray(n.rows) || e.push(`${r}: type \'table\' requires rows (array)`), n.types !== void 0 && !Array.isArray(n.types) && e.push(`${r}.types must be an array of column cell types`), n.details !== void 0 && !Array.isArray(n.details) && e.push(`${r}.details must be an array aligned with rows`), Array.isArray(n.details)) {\n let c = { columns: n.columns, rows: n.rows, types: n.types }, f = I(c).length;\n n.details.length > f && e.push(`${r}.details must not contain more entries than rows`);\n for (let g = 0; g < Math.min(n.details.length, f); g++) {\n let x = n.details[g];\n if (!(x === null || !C(c, g))) {\n if (!Array.isArray(x)) {\n e.push(`${r}.details[${g}] must be an array or null`);\n continue;\n }\n s(x, i + 1, `${r}.details[${g}]`);\n }\n }\n }\n dt(n.rows, `${r}.rows`, e);\n break;\n case "chart":\n lt(n, r, e);\n break;\n case "tabs": {\n if (Array.isArray(n.tabs) || e.push(`${r}: type \'tabs\' requires tabs (array)`), Array.isArray(n.tabs)) for (let c = 0; c < n.tabs.length; c++) {\n let f = y(n.tabs[c]);\n if (f === void 0) {\n e.push(`${r}.tabs[${c}] must be an object`);\n continue;\n }\n typeof f.label != "string" && e.push(`${r}.tabs[${c}].label must be a string`), s(f.items, i + 1, `${r}.tabs[${c}].items`);\n }\n break;\n }\n case "plot":\n Array.isArray(n.series) || e.push(`${r}: type \'plot\' requires series (array)`);\n break;\n case "callout":\n typeof n.content != "string" && e.push(`${r}: type \'callout\' requires content (string)`);\n break;\n case "steps":\n Array.isArray(n.steps) || e.push(`${r}: type \'steps\' requires steps (array)`);\n break;\n case "keyvalue":\n Array.isArray(n.pairs) || e.push(`${r}: type \'keyvalue\' requires pairs (array)`);\n break;\n case "diff":\n Array.isArray(n.diffs) || e.push(`${r}: type \'diff\' requires diffs (array)`);\n break;\n case "json":\n "value" in n || e.push(`${r}: type \'json\' requires value`);\n break;\n case "code":\n typeof n.code != "string" && e.push(`${r}: type \'code\' requires code (string)`);\n break;\n case "accordion":\n if (Array.isArray(n.items) || e.push(`${r}: type \'accordion\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n if (f === void 0) {\n e.push(`${r}.items[${c}] must be an object`);\n continue;\n }\n typeof f.title != "string" && e.push(`${r}.items[${c}].title must be a string`), s(f.items, i + 1, `${r}.items[${c}].items`);\n }\n break;\n case "copy":\n typeof n.text != "string" && e.push(`${r}: type \'copy\' requires text (string)`);\n break;\n case "svg":\n typeof n.code != "string" && e.push(`${r}: type \'svg\' requires code (string)`), u("height");\n break;\n case "mermaid":\n typeof n.code != "string" && e.push(`${r}: type \'mermaid\' requires code (string)`);\n break;\n case "scene3d":\n Array.isArray(n.meshes) || e.push(`${r}: type \'scene3d\' requires meshes (array)`);\n break;\n case "timeline":\n Array.isArray(n.items) || e.push(`${r}: type \'timeline\' requires items (array)`);\n break;\n case "file-tree":\n Array.isArray(n.items) || e.push(`${r}: type \'file-tree\' requires items (array)`);\n break;\n case "breadcrumb":\n Array.isArray(n.items) || e.push(`${r}: type \'breadcrumb\' requires items (array)`);\n break;\n case "quiz":\n typeof n.question != "string" && e.push(`${r}: type \'quiz\' requires question (string)`), Array.isArray(n.options) || e.push(`${r}: type \'quiz\' requires options (array)`);\n break;\n case "diagram":\n typeof n.kind != "string" && e.push(`${r}: type \'diagram\' requires kind (string)`), Array.isArray(n.nodes) || e.push(`${r}: type \'diagram\' requires nodes (array)`), n.edges !== void 0 && !Array.isArray(n.edges) && e.push(`${r}: type \'diagram\' requires edges (array) when present`);\n break;\n case "echart":\n n.option === void 0 && n.data === void 0 && n.series === void 0 && (!Array.isArray(n.links) || n.links.length === 0) && e.push(`${r}: type \'echart\' requires option, data, series, or links`), u("height");\n break;\n default:\n e.push(`${r}: unknown type \'${o}\' (custom renderer?)`);\n }\n let d = T[o];\n d !== void 0 && In(n, r, d, e);\n }\n\n // lib/normalize-visual.js\n function normalizeVisual(value, schemas) {\n const unwrap = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) && Object.keys(v2).length === 1 && Array.isArray(v2.item) ? v2.item : v2;\n const scalar2 = (v2, kind) => kind === "number" && typeof v2 === "string" && v2.trim() !== "" && Number.isFinite(Number(v2)) ? Number(v2) : kind === "boolean" && (v2 === "true" || v2 === "false") ? v2 === "true" : v2;\n function record(input, schema, depth = 0) {\n if (!input || typeof input !== "object" || Array.isArray(input) || depth > 32) return input;\n const out2 = { ...input };\n for (const [key, v2] of Object.entries(input)) {\n const target = schema.aliases?.[key] ?? key, kind = schema.fields?.[target];\n if (kind === "array" || kind === "nodes") {\n let array2 = unwrap(v2);\n if (Array.isArray(array2)) array2 = array2.map((x) => kind === "nodes" ? node2(x, depth + 1) : schema.nested?.[target] ? record(x, schema.nested[target], depth + 1) : x);\n out2[key] = array2;\n } else out2[key] = scalar2(v2, kind);\n }\n return out2;\n }\n function node2(v2, depth) {\n if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) return v2;\n if (v2.type === "heading") {\n v2 = { ...v2, type: "text", content: v2.content ?? v2.text ?? v2.title, size: v2.size ?? "h3" };\n delete v2.text;\n delete v2.title;\n }\n if (["card", "row", "col", "grid"].includes(v2.type) && v2.items === void 0 && Array.isArray(unwrap(v2.children))) {\n v2 = { ...v2, items: unwrap(v2.children) };\n delete v2.children;\n }\n const out2 = record(v2, schemas[v2.type] ?? {}, depth);\n if (v2.type === "quiz" && Array.isArray(out2.options)) out2.options = out2.options.map((x) => record(x, { fields: { correct: "boolean" } }));\n if (v2.type === "table") {\n for (const key of ["rows", "data", "items", "details"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((row) => {\n row = unwrap(row);\n return key === "details" && Array.isArray(row) ? row.map((x) => node2(x, depth + 1)) : row;\n });\n }\n if (v2.type === "echart") {\n for (const key of ["data", "series", "links"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((x) => record(x, { fields: { value: "number", data: "array" }, nested: { data: { fields: { value: "number" } } } }));\n }\n return out2;\n }\n if (Array.isArray(value)) return { items: value.map((x) => node2(x, 0)) };\n if (!value || typeof value !== "object") return value;\n const out = { ...value }, items = unwrap(value.items);\n if (Array.isArray(items)) out.items = items.map((x) => node2(x, 0));\n return out;\n }\n\n // lib/visual.js\n var VISUAL_TYPES = Object.freeze([...q]);\n function validateVisual(value) {\n const encoded = JSON.stringify(value);\n if (!encoded || new TextEncoder().encode(encoded).length > 131072) throw Error("DSH UI: visual spec exceeds 128 KiB");\n const processed = Ze(normalizeVisual(value, T)), spec = Ne(processed) ? processed.spec : at(processed);\n if (!spec || !processed.renderedNativeCount) throw Error("DSH UI: visual spec: " + (processed.errors.slice(0, 4).join("; ") || "requires registered components"));\n const critical = /* @__PURE__ */ new Set(["quiz", "radio", "submit", "input", "textarea", "select", "slider", "checkbox", "switch"]);\n const inventory = (items, path = "items", result = []) => {\n for (const [n, v2] of (Array.isArray(items) ? items : []).entries()) {\n if (!v2 || typeof v2 !== "object") continue;\n const at2 = path + "[" + n + "]";\n if (critical.has(v2.type)) result.push({ type: v2.type, id: v2.id ?? v2.group ?? v2.question ?? v2.label, path: at2 });\n if (["row", "col", "grid", "card"].includes(v2.type)) inventory(v2.items, at2 + ".items", result);\n if (v2.type === "tabs") for (const [i, t] of (v2.tabs ?? []).entries()) inventory(t.items, at2 + ".tabs[" + i + "].items", result);\n if (v2.type === "accordion") for (const [i, t] of (v2.items ?? []).entries()) inventory(t.items, at2 + ".items[" + i + "].items", result);\n }\n return result;\n };\n const source = normalizeVisual(value, T), before = inventory(source.items), after = inventory(spec.items);\n const available = [...after], missing = before.filter((v2) => {\n const i = available.findIndex((n) => n.type === v2.type && n.id === v2.id);\n if (i < 0) return true;\n available.splice(i, 1);\n return false;\n });\n if (missing.length) throw Error("DSH UI: critical component was rejected at " + missing.map((v2) => v2.path + " (" + v2.type + ")").join(", ") + ". " + processed.errors.slice(0, 4).join("; "));\n const stableIds = /* @__PURE__ */ new Set();\n function walk(items) {\n for (const n of items) {\n if (n.id !== void 0) {\n if (stableIds.has(n.id)) throw Error("DSH UI: duplicate extended component id " + n.id);\n stableIds.add(n.id);\n }\n if (!VISUAL_TYPES.includes(n.type)) throw Error("DSH UI: unsupported visual component " + n.type);\n if (n.type === "input" && n.inputType === "password") throw Error("DSH UI: do not collect passwords or secrets in a UI");\n if (n.type !== "file-tree" && Array.isArray(n.items)) walk(n.items.filter((x) => x && typeof x === "object" && "type" in x));\n for (const t of n.tabs ?? []) walk(t.items ?? []);\n if (n.type === "table") {\n for (const d of n.details ?? []) if (d) walk(d);\n }\n }\n }\n walk(spec.items);\n delete spec.panel;\n delete spec.append;\n return { spec, warnings: processed.errors.slice(0, 12), count: processed.renderedNativeCount };\n }\n function visualDocument(value) {\n if (Array.isArray(value)) value = { items: value };\n const { spec, warnings } = validateVisual(value), title = spec.title || "\\u53EF\\u89C6\\u5316";\n const texts = [];\n function gather(v2) {\n if (!v2 || typeof v2 !== "object") return;\n for (const [k2, x] of Object.entries(v2)) {\n if (["title", "content", "label", "question", "explanation", "alt"].includes(k2) && typeof x === "string") texts.push(x);\n else if (x && typeof x === "object") Array.isArray(x) ? x.forEach(gather) : gather(x);\n }\n }\n gather(spec);\n return { version: 1, title, fallback: texts.join("\\n").slice(0, 8192) || title, nodes: [{ id: "visual", type: "visual", spec, warnings }] };\n }\n\n // lib/normalize-authoring.js\n var object = (v2) => v2 !== null && typeof v2 === "object" && !Array.isArray(v2);\n var own = (v2, k2) => Object.hasOwn(v2, k2);\n var singleItem = (v2) => object(v2) && Object.keys(v2).length === 1 && own(v2, "item");\n var array = (v2) => {\n let candidate = v2;\n for (let i = 0; i < 8 && singleItem(candidate); i++) candidate = candidate.item;\n return Array.isArray(candidate) ? candidate : v2;\n };\n var numericOps = /* @__PURE__ */ new Set(["add", "sub", "mul", "div", "min", "max", "round", "ceil", "floor", "abs", "lt", "lte", "gt", "gte"]);\n function number(v2) {\n if (typeof v2 !== "string" || !/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(v2.trim())) return v2;\n const n = Number(v2);\n return Number.isFinite(n) && (!Number.isInteger(n) || Number.isSafeInteger(n)) ? n : v2;\n }\n var boolean = (v2) => v2 === "true" ? true : v2 === "false" ? false : v2;\n function expression(e, numeric = false, logical = false) {\n if (!object(e)) return e;\n if (Object.keys(e).length === 1 && own(e, "expr") && typeof e.expr === "number" && Number.isFinite(e.expr)) {\n e.const = e.expr;\n delete e.expr;\n }\n if (own(e, "const")) {\n if (numeric) e.const = number(e.const);\n if (logical) e.const = boolean(e.const);\n }\n if (own(e, "args")) e.args = array(e.args);\n if (Array.isArray(e.args)) e.args.forEach((arg, i) => expression(arg, numericOps.has(e.op) || e.op === "if" && i > 0 && numeric, e.op === "if" && i === 0));\n if (object(e.map?.fields)) Object.values(e.map.fields).forEach((e2) => expression(e2));\n return e;\n }\n function normalizeAuthoring(doc2) {\n if (Array.isArray(doc2)) doc2 = visualDocument(doc2);\n if (object(doc2) && !own(doc2, "nodes") && (own(doc2, "items") || typeof doc2.type === "string")) doc2 = visualDocument(doc2);\n if (!object(doc2)) return doc2;\n if (own(doc2, "version")) doc2.version = number(doc2.version);\n if (object(doc2.presentation) && doc2.presentation.layout === "flow" && (!own(doc2.presentation, "preset") || doc2.presentation.preset === "flow")) {\n doc2.presentation.layout = "guide";\n doc2.presentation.preset = "flow";\n }\n if (object(doc2.state)) for (const k2 of Object.keys(doc2.state)) {\n let s = doc2.state[k2];\n if (typeof s === "string" && s.trim().startsWith("{")) {\n try {\n const parsed = JSON.parse(s);\n if (object(parsed)) s = parsed;\n } catch {\n }\n }\n if (singleItem(s) && object(s.item)) s = s.item;\n doc2.state[k2] = s;\n if (!object(s)) continue;\n if (own(s, "options")) s.options = array(s.options);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (own(s, field)) s[field] = number(s[field]);\n if (Array.isArray(s.options)) s.options = s.options.map(number);\n } else if (s.type === "boolean") {\n if (own(s, "default")) s.default = boolean(s.default);\n if (Array.isArray(s.options)) s.options = s.options.map(boolean);\n }\n }\n if (object(doc2.derived)) Object.values(doc2.derived).forEach((e) => expression(e));\n if (object(doc2.actions)) {\n for (const action of Object.values(doc2.actions)) if (object(action) && own(action, "stateKeys")) action.stateKeys = array(action.stateKeys);\n }\n function nodes(list) {\n list = array(list);\n if (!Array.isArray(list)) return list;\n for (const node2 of list) {\n if (!object(node2)) continue;\n if (node2.type === "code" && (node2.copyable === true || node2.copyable === "true")) delete node2.copyable;\n if (["slider", "input"].includes(node2.type) && typeof node2.bind === "string" && node2.bind.startsWith("state.")) {\n const spec = doc2.state?.[node2.bind.slice(6)];\n if (spec?.type === "number") {\n for (const field of ["min", "max", "step"]) if (own(node2, field) && number(node2[field]) === spec[field]) delete node2[field];\n }\n }\n if (["text", "heading", "callout"].includes(node2.type) && own(node2, "content")) {\n if (!own(node2, "text")) {\n node2.text = node2.content;\n delete node2.content;\n } else if (node2.text === node2.content) delete node2.content;\n }\n if (["text", "heading", "callout"].includes(node2.type) && typeof node2.text === "string") {\n const spans = array(node2.spans);\n if (Array.isArray(spans) && spans.every((s) => object(s) && typeof s.text === "string") && spans.map((s) => s.text).join("") === node2.text) delete node2.text;\n }\n if (node2.type === "table" && own(node2, "types")) {\n const columns = array(node2.columns), rows = array(node2.rows), types = array(node2.types);\n const allowed = ["id", "type", "label", "columns", "rows", "types"];\n if (Object.keys(node2).every((k2) => allowed.includes(k2)) && Array.isArray(columns) && columns.length && columns.every((c) => object(c) && typeof c.key === "string" && typeof c.label === "string" && Object.keys(c).every((k2) => ["key", "label", "unit"].includes(k2))) && new Set(columns.map((c) => c.key)).size === columns.length && Array.isArray(rows) && rows.every(object) && Array.isArray(types) && types.length === columns.length && types.every((t) => ["text", "num", "delta", "bar", "badge"].includes(t))) {\n const spec = { ...node2.label ? { title: node2.label } : {}, items: [{ type: "table", columns: columns.map((c) => c.label + (c.unit ? ` (${c.unit})` : "")), rows: rows.map((row) => columns.map((c) => row[c.key] ?? null)), types }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { ...id !== void 0 ? { id } : {}, type: "visual", spec });\n }\n }\n if (typeof node2.id === "string" && VISUAL_TYPES.includes(node2.type) && !own(COMPONENTS, node2.type)) {\n const spec = { items: [{ ...node2 }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { id, type: "visual", spec });\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && node2.columns.every((c) => object(c) && typeof c.key === "string") && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length && Array.isArray(node2.rows) && node2.rows.every((row) => Array.isArray(row) && row.length === node2.columns.length)) {\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c, i) => [c.key, row[i]])));\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && Array.isArray(node2.rows) && node2.rows.every(Array.isArray) && node2.columns.every((c) => object(c) && Number.isInteger(c.key) && c.key >= 0) && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length) {\n const columns = node2.columns.map((c) => ({ ...c, key: "col_" + c.key }));\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c) => ["col_" + c.key, row[c.key] ?? null])));\n node2.columns = columns;\n }\n if (node2.type === "visual" && typeof node2.id === "string") {\n node2.stateKey ??= "visual_" + node2.id;\n doc2.state ??= {};\n if (!own(doc2.state, node2.stateKey)) doc2.state[node2.stateKey] = { type: "json", default: {} };\n }\n if (node2.type === "sandbox") {\n if (!own(node2, "title")) node2.title = doc2.title;\n if (!own(node2, "fallback")) node2.fallback = doc2.fallback;\n }\n for (const field of ["children", "items", "columns", "libraries", "stateKeys", "dataKeys", "derivedKeys"]) if (own(node2, field)) node2[field] = array(node2[field]);\n if (["table", "chart"].includes(node2.type) && own(node2, "rows")) node2.rows = array(node2.rows);\n for (const field of ["decimals", "height"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (["row", "column"].includes(node2.type)) {\n if (own(node2, "gap")) node2.gap = number(node2.gap);\n if (node2.type === "row" && own(node2, "columns")) node2.columns = number(node2.columns);\n }\n if (["text", "heading", "callout"].includes(node2.type)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (own(node2, "spans")) node2.spans = array(node2.spans);\n if (Array.isArray(node2.spans)) {\n for (const span of node2.spans) if (object(span)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(span, field)) span[field] = number(span[field]);\n }\n }\n }\n if (node2.type === "details" && own(node2, "open")) node2.open = boolean(node2.open);\n if (node2.type === "text" && own(node2, "copyable")) node2.copyable = boolean(node2.copyable);\n if (node2.type === "code" && own(node2, "wrap")) node2.wrap = boolean(node2.wrap);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const row of node2.rows) if (object(row)) for (const cell of Object.values(row)) expression(cell);\n }\n for (const field of ["text", "value", "max", "rows"]) if (own(node2, field)) expression(node2[field], node2.type === "progress");\n if (["row", "column", "card", "details"].includes(node2.type) && own(node2, "children")) node2.children = nodes(node2.children);\n }\n return list;\n }\n if (own(doc2, "nodes")) doc2.nodes = nodes(doc2.nodes);\n return doc2;\n }\n\n // lib/typography.js\n var TEXT_PRESETS = Object.freeze(["reading", "brief", "comparison", "list", "callout", "scorecard", "flow", "minimal"]);\n var TYPE_FIELDS = Object.freeze(["size", "weight", "color", "align", "lineHeight"]);\n var TEXT_SIZES = Object.freeze({ sm: 14, md: 16, lg: 20, xl: 26, hero: 36 });\n var TEXT_COLORS = Object.freeze({ default: "var(--du-ink)", muted: "var(--du-muted)", accent: "var(--du-accent)", success: "var(--du-green)", warning: "var(--du-amber)", danger: "var(--du-red)", violet: "var(--du-violet)" });\n function validateTypography(value, at2 = "text") {\n const fail2 = (message) => {\n throw Error(`DSH UI: ${at2}.${message}`);\n };\n if (value.size !== void 0 && !(typeof value.size === "number" && Number.isFinite(value.size) && value.size >= 12 && value.size <= 48) && !Object.hasOwn(TEXT_SIZES, value.size)) fail2("size must be 12..48 px or sm/md/lg/xl/hero");\n if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail2("weight must be 400/500/600/700/800");\n if (value.color !== void 0 && (typeof value.color !== "string" || !Object.hasOwn(TEXT_COLORS, value.color) && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.color))) fail2("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");\n if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail2("align must be left/center/right");\n if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail2("lineHeight must be 1.2..2.4");\n }\n\n // lib/links.js\n function validateLink(node2) {\n const fail2 = (message) => {\n throw Error("DSH UI: " + message);\n };\n if ([node2.href, node2.path, node2.action].filter((v2) => v2 !== void 0).length !== 1) fail2(`node.${node2.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);\n if (node2.variant !== void 0 && !["primary", "secondary", "text"].includes(node2.variant)) fail2("link/button variant must be primary/secondary/text");\n if (node2.href !== void 0) {\n if (typeof node2.href !== "string" || node2.href.length > 8192 || /[\\u0000-\\u0020\\u007f]/.test(node2.href) || !/^https?:\\/\\//i.test(node2.href)) fail2("href must be an absolute http/https URL; encode spaces");\n let url;\n try {\n url = new URL(node2.href);\n } catch {\n fail2("invalid href URL");\n }\n if (!url.hostname || url.username || url.password) fail2("href must have a host and must not contain credentials");\n }\n if (node2.path !== void 0) {\n if (typeof node2.path !== "string" || !node2.path.trim() || node2.path.length > 8192 || /[\\u0000-\\u001f\\u007f]/.test(node2.path) || /^\\s*(?:[a-z][a-z\\d+.-]*:|[\\\\/]{2})/i.test(node2.path) && !/^\\s*[a-z]:[\\\\/]/i.test(node2.path)) fail2("path must be a local file path, not a URL, network path or command");\n }\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own2 = (o, k2) => Object.hasOwn(o, k2);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object2 = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at2) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at2} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at2) {\n if (!object2(value)) fail(`${at2} must be an object`);\n for (const k2 of Object.keys(value)) if (!allowed.includes(k2)) {\n const hint = at2 === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at2}.${k2}; allowed fields at ${at2}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k2 of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k2)) fail("unsafe property name");\n safeJson(value[k2], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k2));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k2, spec]) => [k2, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object2(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k2, s] of Object.entries(doc2.state)) {\n if (!own2(state2, k2)) fail(`missing state.${k2}`);\n const v2 = state2[k2];\n if (s.type === "number") {\n if (!finite(v2) || v2 < s.min || v2 > s.max) fail(`state.${k2} is outside its numeric range`);\n const offset = (v2 - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k2} does not match its step`);\n } else if (s.type === "json") {\n if (!object2(v2) && !Array.isArray(v2)) fail(`state.${k2} must be an array or object for type json`);\n safeJson(v2);\n if (new TextEncoder().encode(JSON.stringify(v2)).length > 16384) fail(`state.${k2} JSON exceeds 16 KiB`);\n } else if (s.type === "string") text(v2, `state.${k2}`);\n else if (typeof v2 !== "boolean") fail(`state.${k2} must be boolean`);\n if (s.options && !s.options.includes(v2)) fail(`invalid option for state.${k2}`);\n result[k2] = v2;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], ceil: [1, 1], floor: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);\n const [group, k2] = ref.split(".");\n if (!own2(doc2[group], k2)) fail(`unknown reference ${ref}`);\n return [group, k2];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k2] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k2];\n if (own2(derived, k2)) return derived[k2];\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n active.add(k2);\n const result2 = expression2(doc2.derived[k2]);\n active.delete(k2);\n derived[k2] = result2;\n return result2;\n };\n const expression2 = (e, item) => {\n budget();\n if (own2(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k2, value]) => {\n const out2 = expression2(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k2, out2];\n })));\n }\n if (own2(e, "const")) return e.const;\n if (own2(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!item || !own2(item, k2) || !scalar(item[k2])) fail("invalid item reference");\n return item[k2];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression2(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression2(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression2(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y2) => x + y2, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y2) => x * y2, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "ceil":\n out = Math.ceil(a[0]);\n break;\n case "floor":\n out = Math.floor(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k2 of Object.keys(doc2.derived)) resolve(`derived.${k2}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const resolveCell = (cell) => {\n const out = expression2(cell);\n if (!scalar(out)) fail("inline row formula cells must resolve to a string, boolean or finite number");\n return out;\n };\n const result = { derived, resolveValue: (value) => {\n if (Array.isArray(value)) return value.map((row) => object2(row) ? Object.fromEntries(Object.entries(row).map(([k2, cell]) => [k2, object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field)) ? resolveCell(cell) : cell])) : row);\n if (!object2(value)) return value;\n return expression2(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart") {\n const index = rows.findIndex((r) => !own2(r, n.labelKey) || !scalar(r[n.labelKey]) || !own2(r, n.valueKey) || !finite(r[n.valueKey]));\n if (index >= 0) {\n const row = rows[index], missing = [n.labelKey, n.valueKey].filter((k2) => !own2(row, k2));\n fail("chart requires labels and finite numeric values. node." + n.id + ".rows[" + index + "]: " + (missing.length ? "missing field(s) " + missing.join(", ") : n.valueKey + " must resolve to a finite number") + ". Available keys: " + Object.keys(row).slice(0, 16).join(", ") + ". For live values use inline rows:[{" + n.labelKey + \':"\\u9879\\u76EE",\' + n.valueKey + \':{ref:"derived.amount"}}]; static data labels alone contain no amounts. Keep all nodes/state/derived when correcting the document\');\n }\n }\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);\n if (n.type === "progress") {\n const v2 = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v2) || !finite(max) || max <= 0 || v2 < 0 || v2 > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const normalized = normalizeAuthoring(JSON.parse(json));\n safeJson(normalized);\n const doc2 = expandExpressions(normalized);\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density", "preset"], "presentation");\n if (doc2.presentation.preset !== void 0 && !TEXT_PRESETS.includes(doc2.presentation.preset)) fail("unknown presentation preset; use " + TEXT_PRESETS.join("/"));\n for (const [k2, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k2] !== void 0 && !allowed.includes(doc2.presentation[k2])) fail(`unknown presentation ${k2}`);\n }\n if (doc2.version !== 1) fail(own2(doc2, "version") ? "document.version must be 1" : "document.version is missing. render_ui creates a complete document, not a partial patch: send {version:1,title,fallback,nodes:[...]} for shared controls/formulas, or {title,items:[...]} for extended visuals. Include all content, not only data/derived");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object2(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k2 of Object.keys(doc2[group])) if (!validIdentifier(k2)) fail(`invalid key in ${group}: ${JSON.stringify(k2)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);\n }\n for (const [k2, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k2}`);\n if (s.type === "string" && (Array.isArray(s.default) || object2(s.default)) && !own2(s, "options")) s.type = "json";\n if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k2}; use number, string, boolean or json (arrays/objects)`);\n if (s.type === "json" && own2(s, "options")) fail(`state.${k2}: json state does not support select options; use scalar options or a canvas`);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (!finite(s[field])) fail(`state.${k2}.${field} must be a finite JSON number; received ${s[field] === null ? "null" : typeof s[field]}. Supply {type:"number",default:2,min:1,max:12,step:1}; do not omit limits or include units in numeric fields`);\n if (s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for state.${k2}: require min < max and step > 0; received min=${s.min}, max=${s.max}, step=${s.step}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k2}`);\n } else if (["min", "max", "step"].some((p2) => own2(s, p2))) fail(`numeric limits on non-number ${k2}`);\n if (s.options !== void 0 && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`state.${k2}.options must be a direct array of 1..64 scalar values, e.g. options:["3","5","7"], not {item:[...]}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n const expressionShapes = /* @__PURE__ */ new Set();\n for (const [k2, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k2]: option });\n function validateExpression(e, depth = 0, itemRows, at2 = "expression") {\n if (depth > LIMITS.depth) fail(at2 + ": expression nesting exceeds " + LIMITS.depth);\n const shape = JSON.stringify(e);\n if (!expressionShapes.has(shape)) {\n expressionShapes.add(shape);\n if (++expressions > LIMITS.expressions) fail(at2 + ": expression limit exceeded (128 distinct expressions). Reuse derived references instead of expanding long formulas; keep the complete document when retrying");\n }\n if (!object2(e)) fail(`${at2}: expression must be an object`);\n if (own2(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k2] = reference(doc2, e.map.source), rows = doc2.data[k2];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("map source must be object rows");\n if (!object2(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k3, value2] of Object.entries(e.map.fields)) {\n if (!validIdentifier(k3)) fail(`invalid map field ${JSON.stringify(k3).slice(0, 100)}; use a letter/underscore identifier such as powerW or \\u529F\\u7387, without spaces, dots or hyphens`);\n validateExpression(value2, depth + 1, rows, `${at2}.map.fields.${k3}`);\n }\n return;\n }\n if (own2(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own2(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!itemRows || !validIdentifier(k2) || itemRows.some((row) => !own2(row, k2) || !scalar(row[k2]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail(`${at2}: invalid operator or argument count for ${JSON.stringify(e.op)}; args must be a direct array${arity ? ` with ${arity[0]}..${arity[1]} expressions` : " and op must be registered"}. Received ${Array.isArray(e.args) ? e.args.length + " arguments" : typeof e.args}. Prefer {expr:"state.people * state.days"} for arithmetic; missing operands cannot be inferred`);\n e.args.forEach((a, i) => validateExpression(a, depth + 1, itemRows, `${at2}.args[${i}]`));\n }\n Object.entries(doc2.derived).forEach(([k2, e]) => validateExpression(e, 0, void 0, `derived.${k2}`));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k2) {\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n if (visited.has(k2)) return;\n active.add(k2);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k2]);\n active.delete(k2);\n visited.add(k2);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k2, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k2}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own2(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Map();\n let count2 = 0;\n const value = (v2, at2) => {\n if (object2(v2)) {\n if (own2(v2, "map")) fail("map belongs in derived");\n validateExpression(v2, 0, void 0, at2);\n } else if (!scalar(v2)) fail(`invalid value at ${at2}`);\n };\n function nodes(list, depth = 0, path = "nodes") {\n if (!Array.isArray(list)) fail(path === "nodes" ? \'document.nodes is missing or is not an array. State/derived define values but do not create visible UI. Include nodes:[{id:"heading",type:"heading",text:"..."},...] and actual controls in the SAME complete document; do not resend state/data/derived alone. Declared state keys: \' + Object.keys(doc2.state).join(", ") : path + " must be an array of child nodes; use children:[{id,type,...}]");\n if (depth > LIMITS.depth) fail(path + " exceeds maximum node depth " + LIMITS.depth);\n for (const [index, n] of list.entries()) {\n const at2 = `${path}[${index}]`;\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object2(n)) fail(`${at2} must be a node object`);\n if (!own2(n, "id")) fail(`${at2}.id is missing (type=${JSON.stringify(n.type)}). Every node, including sandbox, needs its own id; add e.g. id:"canvas". JSON field order does not matter`);\n if (!validIdentifier(n.id)) fail(`${at2}.id is invalid: ${JSON.stringify(n.id)}. Use 1..64 letters/numbers/underscores starting with a letter/underscore`);\n if (ids.has(n.id)) fail(`${at2}.id duplicates ${JSON.stringify(n.id)} first declared at ${ids.get(n.id)}. Give each node a unique id; state keys and node ids are separate namespaces`);\n ids.set(n.id, `${at2}.id`);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\\./.test(n.rows)) n.rows = { ref: n.rows };\n switch (n.type) {\n case "visual": {\n const previous = Array.isArray(n.warnings) ? n.warnings.filter((x) => typeof x === "string").map((x) => x.slice(0, 512)).slice(0, 12) : [];\n const checked = validateVisual(n.spec);\n n.spec = checked.spec;\n n.warnings = [.../* @__PURE__ */ new Set([...previous, ...checked.warnings])].slice(0, 12);\n count2 += checked.count;\n if (count2 > LIMITS.nodes) fail("too many nodes, including visual components");\n if (!validIdentifier(n.stateKey) || doc2.state[n.stateKey]?.type !== "json") fail("visual requires its own json stateKey");\n break;\n }\n case "sandbox": {\n text(n.title, `${at2}.title (canvas title)`);\n text(n.fallback, `${at2}.fallback (canvas fallback)`);\n if (!n.title.trim()) fail(`${at2}.title must not be empty`);\n if (!n.fallback.trim()) fail(`${at2}.fallback must not be empty`);\n if (typeof n.html !== "string" || !n.html.trim()) fail(`${at2}.html must be a non-empty HTML string; script/css/fallback belong beside html on the sandbox node, not inside it`);\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.libraries !== void 0 && (!Array.isArray(n.libraries) || n.libraries.length > 1 || n.libraries.some((v2) => v2 !== "mechanism"))) fail(\'canvas libraries supports only ["mechanism"] or []\');\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k2) => !own2(doc2[group], k2)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n if (n.gap !== void 0 && !(typeof n.gap === "number" && Number.isFinite(n.gap) && n.gap >= 0 && n.gap <= 40)) fail("gap must be 0..40 pixels");\n if (n.columns !== void 0 && (!Number.isInteger(n.columns) || n.columns < 1 || n.columns > 4)) fail("columns must be 1..4");\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open === "true" || n.open === "false") n.open = n.open === "true";\n if (n.open !== void 0 && typeof n.open !== "boolean") fail(`node.${n.id}.open must be boolean true or false`);\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (n.title !== void 0) text(n.title, "steps title");\n const at3 = `node.${n.id}.items`;\n if (!Array.isArray(n.items)) fail(`${at3} must be an array of 1..12 step objects, received ${n.items === null ? "null" : typeof n.items}. Use items:[{"title":"First step","description":"One sentence"}], not items:{item:[...]}. status is optional for a static guide`);\n if (!n.items.length || n.items.length > 12) fail(`${at3} requires 1..12 items; received ${n.items.length}. Split a longer guide into separate steps nodes`);\n for (const [i, item] of n.items.entries()) {\n const stepAt = `${at3}[${i}]`;\n fields(item, ["title", "description", "status"], stepAt);\n text(item.title, `${stepAt}.title`);\n if (item.description !== void 0) text(item.description, `${stepAt}.description`);\n if (item.status !== void 0 && !["pending", "active", "done", "error"].includes(item.status)) fail(`${stepAt}.status must be pending, active, done or error; omit status for a static guide`);\n }\n break;\n }\n case "heading":\n case "text":\n case "callout":\n if (n.type === "text") {\n if (n.title !== void 0) text(n.title, "text block title");\n if (n.copyable !== void 0 && typeof n.copyable !== "boolean") fail("copyable must be boolean");\n }\n validateTypography(n, `node.${n.id}`);\n if (n.spans !== void 0) {\n if (n.text !== void 0) fail(`node.${n.id}: use text or spans, not both`);\n if (!Array.isArray(n.spans) || !n.spans.length || n.spans.length > 80) fail("spans must contain 1..80 text fragments");\n for (const [i, span] of n.spans.entries()) {\n fields(span, ["text", ...TYPE_FIELDS], `node.${n.id}.spans[${i}]`);\n text(span.text, "span text");\n validateTypography(span, `node.${n.id}.spans[${i}]`);\n }\n } else value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k2] = reference(doc2, n.bind), spec = doc2.state[k2];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n if (n.type === "select" && n.variant !== void 0 && !["dropdown", "segmented"].includes(n.variant)) fail(`node.${n.id}.variant must be dropdown or segmented`);\n break;\n }\n case "code":\n if (typeof n.code !== "string" || n.code.length > SANDBOX_LIMITS.source) fail("code must be a string of at most 48 Ki characters");\n if (n.lang !== void 0) text(n.lang, "code language");\n if (n.title !== void 0) text(n.title, "code title");\n if (n.wrap !== void 0 && typeof n.wrap !== "boolean") fail("code wrap must be boolean");\n break;\n case "button":\n case "link":\n text(n.text, "button text");\n validateLink(n);\n if (n.action !== void 0 && !own2(doc2.actions, n.action)) fail("unknown action");\n break;\n case "divider":\n if (n.label !== void 0) text(n.label, "divider label");\n break;\n case "table": {\n if (n.label !== void 0) text(n.label, "table label");\n if (!Array.isArray(n.rows)) value(n.rows, "node." + n.id + ".rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n if (n.rows === void 0) fail("node." + n.id + \'.rows is missing; supply rows:[{label:"\\u9879\\u76EE",value:123}] or a rows binding, plus labelKey/valueKey matching its fields. Do not invent missing amounts\');\n if (!Array.isArray(n.rows)) value(n.rows, "node." + n.id + ".rows");\n if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "callout", "card", "metric", "button", "link", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (!["button", "link"].includes(n.type)) {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n if (["table", "chart"].includes(n.type) && Array.isArray(n.rows)) {\n for (const [i, row] of n.rows.entries()) if (object2(row)) {\n for (const [k2, cell] of Object.entries(row)) if (object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field))) value(cell, at2 + ".rows[" + i + "]." + k2);\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1, `${at2}.children`);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var sound = payload.soundtrack;\n var audio;\n var unlocked = false;\n var soundState;\n var caption;\n if (payload.captions?.length && !window.__DSHMotionRender) {\n caption = document.createElement("div");\n caption.setAttribute("aria-live", "off");\n caption.style.cssText = "position:absolute;bottom:5%;left:10%;right:10%;text-align:center;white-space:pre-line;pointer-events:none;font:600 clamp(14px,2.1vw,28px)/1.4 system-ui;color:white;text-shadow:0 1px 4px black";\n const surface = document.getElementById("surface");\n surface.style.position = "relative";\n surface.append(caption);\n }\n var soundAllowed = () => unlocked && soundState?.playing && !soundState.reducedMotion && soundState.visible && !document.hidden;\n if (sound && !window.__DSHMotionRender && /^[\\w-]+\\.(wav|mp3|m4a|aac|ogg|flac)$/.test(sound.file)) {\n audio = document.createElement("audio");\n audio.src = sound.file;\n audio.preload = "auto";\n audio.volume = Math.max(0, Math.min(1, sound.volume ?? 0.3));\n const button = document.createElement("button");\n button.textContent = "\\u5F00\\u542F\\u914D\\u4E50";\n button.type = "button";\n button.addEventListener("click", () => {\n unlocked = !unlocked;\n button.textContent = unlocked ? "\\u5173\\u95ED\\u914D\\u4E50" : "\\u5F00\\u542F\\u914D\\u4E50";\n if (!soundAllowed()) audio.pause();\n else audio.play().then(() => {\n if (!soundAllowed()) audio.pause();\n }).catch(() => {\n unlocked = false;\n button.textContent = "\\u70B9\\u51FB\\u91CD\\u8BD5\\u914D\\u4E50";\n });\n });\n status.before(button);\n status.before(audio);\n }\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden, motionSound: !!audio || !!caption } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m2 = event.data;\n if (event.source !== frame.contentWindow || m2?.channel !== channel || m2.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m2.type === "ready") {\n connected = true;\n publish();\n } else if (m2.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m2.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m2.type === "height" && Number.isFinite(m2.payload) && m2.payload >= 0) frame.style.height = Math.max(32, Math.min(1e3, Math.ceil(m2.payload))) + "px";\n else if (m2.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m2.payload).slice(0, 1e3);\n else if (m2.type === "timeline" && m2.payload.id === "main") {\n soundState = m2.payload;\n if (caption) caption.textContent = payload.captions.find((c) => m2.payload.time >= c.start && m2.payload.time < c.end)?.text ?? "";\n if (!audio) return;\n const t = m2.payload.time;\n if (Number.isFinite(t) && Math.abs(audio.currentTime - t) > 0.2) audio.currentTime = t;\n if (!soundAllowed()) audio.pause();\n else if (audio.paused) audio.play().then(() => {\n if (!soundAllowed()) audio.pause();\n }).catch(() => {\n unlocked = false;\n status.textContent = "\\u8BF7\\u70B9\\u51FB\\u5F00\\u542F\\u914D\\u4E50\\u4EE5\\u5141\\u8BB8\\u64AD\\u653E\\u58F0\\u97F3\\u3002";\n });\n }\n });\n document.addEventListener("visibilitychange", () => {\n if (document.hidden) audio?.pause();\n if (connected) publish();\n });\n addEventListener("pagehide", () => audio?.pause());\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
3573
3654
 
3574
3655
  // lib/canvas-export.js
3575
- function standaloneCanvas(document2, node, state2, theme = {}) {
3656
+ function standaloneCanvas(document2, node, state2, theme = {}, soundtrack, captions) {
3576
3657
  validateState(document2, state2);
3577
3658
  const token = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");
3578
- const json = JSON.stringify({ document: document2, nodeId: node.id, state: state2, theme, nonce: token }).replace(/</g, "\\u003c");
3659
+ const json = JSON.stringify({ document: document2, nodeId: node.id, state: state2, theme, nonce: token, ...soundtrack ? { soundtrack } : {}, ...captions?.length ? { captions } : {} }).replace(/</g, "\\u003c");
3579
3660
  const escape = (s) => String(s).replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
3580
- return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${token}';style-src 'unsafe-inline';frame-src 'self';base-uri 'none';form-action 'none'"><title>${escape(node.title)}</title><style>body{margin:0;padding:24px;background:${theme.scheme === "dark" ? "#161b23" : "#f4f6fa"};color:${theme.scheme === "dark" ? "#e6edf6" : "#182537"};font:14px/1.6 system-ui,sans-serif}main{max-width:1100px;margin:auto}h1{font-size:22px}p{overflow-wrap:anywhere}#surface{background:${theme.scheme === "dark" ? "#161b23" : "#fff"};border-radius:12px;overflow:hidden}#status{min-height:1.6em}</style></head><body><main><h1>${escape(node.title)}</h1><p>DSH Motion UI \xB7 \u72EC\u7ACB\u526F\u672C\u3002\u5305\u542B\u5BFC\u51FA\u65F6\u53C2\u6570\uFF0C\u672C\u5730\u4EA4\u4E92\u4E0D\u4F1A\u4FDD\u5B58\u5230 DSH\uFF0C\u4E5F\u4E0D\u4F1A\u8C03\u7528 Agent\u3002</p><div id="surface"></div><p id="status" role="status"></p><details><summary>\u6587\u5B57\u8BF4\u660E</summary><p>${escape(node.fallback)}</p></details></main><script type="application/json" id="dsh-ui-export">${json}<\/script><script nonce="${token}">${EXPORT_RUNTIME.replace(/<\/script/gi, "<\\/script")}<\/script></body></html>`;
3661
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${token}';style-src 'unsafe-inline';img-src data:;media-src 'self';frame-src 'self';base-uri 'none';form-action 'none'"><title>${escape(node.title)}</title><style>body{margin:0;padding:24px;background:${theme.scheme === "dark" ? "#161b23" : "#f4f6fa"};color:${theme.scheme === "dark" ? "#e6edf6" : "#182537"};font:14px/1.6 system-ui,sans-serif}main{max-width:1100px;margin:auto}h1{font-size:22px}p{overflow-wrap:anywhere}#surface{background:${theme.scheme === "dark" ? "#161b23" : "#fff"};border-radius:12px;overflow:hidden}#status{min-height:1.6em}</style></head><body><main><h1>${escape(node.title)}</h1><p>DSH Motion UI \xB7 \u72EC\u7ACB\u526F\u672C\u3002\u5305\u542B\u5BFC\u51FA\u65F6\u53C2\u6570\uFF0C\u672C\u5730\u4EA4\u4E92\u4E0D\u4F1A\u4FDD\u5B58\u5230 DSH\uFF0C\u4E5F\u4E0D\u4F1A\u8C03\u7528 Agent\u3002</p><div id="surface"></div><p id="status" role="status"></p><details><summary>\u6587\u5B57\u8BF4\u660E</summary><p>${escape(node.fallback)}</p></details></main><script type="application/json" id="dsh-ui-export">${json}<\/script><script nonce="${token}">${EXPORT_RUNTIME.replace(/<\/script/gi, "<\\/script")}<\/script></body></html>`;
3581
3662
  }
3582
3663
 
3583
3664
  // src/view-settings.js
@@ -3969,7 +4050,7 @@ function Sandbox({ node, document: doc, state: state2, data, derived, disabled,
3969
4050
  }
3970
4051
 
3971
4052
  // lib/build-info.js
3972
- var BUILD_INFO = Object.freeze({ "version": "0.7.1", "id": "0.7.1+d92c9bf2bf64", "sourceHash": "d92c9bf2bf6407506977357f099a9c7935c744d97606dc631267a62be10735eb" });
4053
+ var BUILD_INFO = Object.freeze({ "version": "0.8.0", "id": "0.8.0+acc929de8316", "sourceHash": "acc929de831668ca6c1c354b76e8bce725640076d9563856ea98889a3646931c" });
3973
4054
 
3974
4055
  // lib/refinement.js
3975
4056
  var AUDIT_MESSAGES = Object.freeze({ overflow: "\u5185\u5BB9\u8D85\u51FA\u89C6\u53E3\u5BBD\u5EA6", smallText: "\u6587\u5B57\u5B9E\u9645\u663E\u793A\u5C3A\u5BF8\u5C0F\u4E8E 12px", contrast: "\u6587\u5B57\u4E0E\u80CC\u666F\u5BF9\u6BD4\u5EA6\u504F\u4F4E", missingLabel: "\u4EA4\u4E92\u63A7\u4EF6\u7F3A\u5C11\u53EF\u8BBF\u95EE\u540D\u79F0", runtimeError: "\u753B\u5E03\u62A5\u544A\u8FD0\u884C\u5F02\u5E38", clippedText: "\u6587\u5B57\u53EF\u80FD\u88AB\u9690\u85CF\u6216\u88C1\u5207", bottomWhitespace: "\u5185\u5BB9\u4E0B\u65B9\u5B58\u5728\u660E\u663E\u7A7A\u767D" });
@@ -4626,7 +4707,7 @@ function partGeometry(p2) {
4626
4707
  }) : void 0;
4627
4708
  faces = sweep(ring, height, f, inner);
4628
4709
  const center = p2.type === "rod" ? mul(add(p2.from, p2.to), 0.5) : p2.at ?? [0, 0, 0];
4629
- faces = faces.map((face) => ({ ...face, points: face.points.map((v2) => add(v2, center)), holes: face.holes?.map((h19) => h19.map((v2) => add(v2, center))) }));
4710
+ faces = faces.map((face) => ({ ...face, points: face.points.map((v2) => add(v2, center)), holes: face.holes?.map((h21) => h21.map((v2) => add(v2, center))) }));
4630
4711
  return { faces, points: faces.flatMap((f2) => f2.points) };
4631
4712
  }
4632
4713
  function sceneBounds(spec) {
@@ -4738,8 +4819,8 @@ function renderFaces(spec, projection, { explode = 0, selected = "all", cutaway
4738
4819
  for (const [index, face] of geometry.faces.entries()) {
4739
4820
  const facing = dot(face.normal, view);
4740
4821
  if (facing <= 1e-4) continue;
4741
- const points = face.points.map((v2) => add(v2, offset)), holes = face.holes?.map((h19) => h19.map((v2) => add(v2, offset))), center = mul(points.reduce((s, v2) => add(s, v2), [0, 0, 0]), 1 / points.length), light = dot(face.normal, [-0.25, -0.4, 0.88]);
4742
- faces.push({ floor, key: p2.id + "_" + index, part: p2.id, group: p2.group, d: path(points.map((v2) => iso(v2, projection))) + (holes ?? []).map((h19) => path(h19.map((v2) => iso(v2, projection)))).join(""), depth: depthOf(center, projection), line: false, tone: light > 0.5 ? 0 : light > 0.1 ? 1 : light > -0.4 ? 2 : 3, material: p2.material ?? "metal", active });
4822
+ const points = face.points.map((v2) => add(v2, offset)), holes = face.holes?.map((h21) => h21.map((v2) => add(v2, offset))), center = mul(points.reduce((s, v2) => add(s, v2), [0, 0, 0]), 1 / points.length), light = dot(face.normal, [-0.25, -0.4, 0.88]);
4823
+ faces.push({ floor, key: p2.id + "_" + index, part: p2.id, group: p2.group, d: path(points.map((v2) => iso(v2, projection))) + (holes ?? []).map((h21) => path(h21.map((v2) => iso(v2, projection)))).join(""), depth: depthOf(center, projection), line: false, tone: light > 0.5 ? 0 : light > 0.1 ? 1 : light > -0.4 ? 2 : 3, material: p2.material ?? "metal", active });
4743
4824
  }
4744
4825
  }
4745
4826
  if (faces.length > 8192) throw Error("Motion mechanism: face budget exceeded");
@@ -5907,18 +5988,39 @@ function MotionLibrary() {
5907
5988
  ));
5908
5989
  }
5909
5990
 
5991
+ // src/video-capabilities.js
5992
+ var import_react20 = __toESM(require("react"), 1);
5993
+ var h15 = import_react20.default.createElement;
5994
+ function VideoCapabilities() {
5995
+ const [report, setReport] = (0, import_react20.useState)(), [error, setError] = (0, import_react20.useState)(""), [busy, setBusy] = (0, import_react20.useState)(false);
5996
+ const check = async () => {
5997
+ setBusy(true);
5998
+ setError("");
5999
+ try {
6000
+ const r = await fetch("/api/plugins/dsh-generative-ui/media-capabilities", { credentials: "same-origin", cache: "no-store" });
6001
+ if (!r.ok) throw Error("\u89C6\u9891\u73AF\u5883\u68C0\u67E5\u5931\u8D25\uFF1AHTTP " + r.status);
6002
+ setReport(await r.json());
6003
+ } catch (e) {
6004
+ setError(e.message);
6005
+ } finally {
6006
+ setBusy(false);
6007
+ }
6008
+ };
6009
+ return h15("section", { "aria-label": "\u89C6\u9891\u5236\u4F5C\u73AF\u5883" }, h15("h4", null, "\u89C6\u9891\u5236\u4F5C"), h15("p", null, "\u53EF\u4EE5\u8BA9\u6A21\u578B\u5236\u4F5C\u53EF\u7F16\u8F91\u52A8\u6548\u5E76\u5BFC\u51FA MP4\uFF0C\u4E5F\u80FD\u68C0\u67E5\u3001\u622A\u53D6\u548C\u62FC\u63A5\u672C\u5730\u89C6\u9891\uFF0C\u6DFB\u52A0\u914D\u97F3\u3001\u591A\u8F68\u914D\u4E50\u4E0E\u5B9A\u65F6\u5B57\u5E55\u3002\u666E\u901A UI \u4E0D\u4F1A\u81EA\u52A8\u5BFC\u51FA\u89C6\u9891\u3002"), h15("button", { type: "button", className: "dgui-secondary", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u89C6\u9891\u73AF\u5883"), report && h15(import_react20.default.Fragment, null, h15("p", { role: "status" }, "\u6D4F\u89C8\u5668\uFF1A" + (report.browser ? "\u53EF\u7528" : "\u7F3A\u5931") + " \xB7 FFmpeg\uFF1A" + (report.ffmpeg ? "\u53EF\u7528" : "\u7F3A\u5931") + " \xB7 FFprobe\uFF1A" + (report.ffprobe ? "\u53EF\u7528" : "\u7F3A\u5931")), h15("p", null, "\u914D\u97F3\uFF1A" + (report.voice?.configured ? "MiniMax \u5DF2\u914D\u7F6E" : "\u672A\u914D\u7F6E") + "\u3002\u914D\u97F3\u4F1A\u8C03\u7528\u4ED8\u8D39 API\uFF1B\u4F7F\u7528\u5B98\u65B9 mmx \u8BA4\u8BC1\u6216 MINIMAX_API_KEY\uFF0C\u4E0D\u590D\u5236 DSH \u6A21\u578B\u5BC6\u94A5\u3002"), (!report.browser || !report.ffmpeg || !report.ffprobe) && h15("p", null, "\u9700\u8981\u672C\u673A Chrome/Edge \u6216 Chromium\uFF0C\u4EE5\u53CA FFmpeg/FFprobe\u3002\u53EF\u7528 DSH_MOTION_BROWSER\u3001DSH_MOTION_FFMPEG\u3001DSH_MOTION_FFPROBE \u914D\u7F6E\u8DEF\u5F84\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u4E0B\u8F7D\u5927\u578B\u8FD0\u884C\u65F6\u3002")), error && h15("p", { role: "alert" }, error));
6010
+ }
6011
+
5910
6012
  // src/settings.js
5911
- var import_react22 = __toESM(require("react"), 1);
6013
+ var import_react23 = __toESM(require("react"), 1);
5912
6014
 
5913
6015
  // src/runtime-diagnostics.js
5914
- var import_react20 = __toESM(require("react"), 1);
5915
- var h15 = import_react20.default.createElement;
6016
+ var import_react21 = __toESM(require("react"), 1);
6017
+ var h16 = import_react21.default.createElement;
5916
6018
  var activation = { active: false, channel: "\u672A\u6FC0\u6D3B", sidebar: false };
5917
6019
  function setRuntimeActivation(patch) {
5918
6020
  activation = { ...activation, ...patch };
5919
6021
  }
5920
6022
  function RuntimeDiagnostics() {
5921
- const [report, setReport] = (0, import_react20.useState)(), [error, setError] = (0, import_react20.useState)(""), [busy, setBusy] = (0, import_react20.useState)(false);
6023
+ const [report, setReport] = (0, import_react21.useState)(), [error, setError] = (0, import_react21.useState)(""), [busy, setBusy] = (0, import_react21.useState)(false);
5922
6024
  const check = async () => {
5923
6025
  setBusy(true);
5924
6026
  setError("");
@@ -5935,11 +6037,11 @@ function RuntimeDiagnostics() {
5935
6037
  setBusy(false);
5936
6038
  }
5937
6039
  };
5938
- return h15("section", { "aria-label": "\u8FD0\u884C\u72B6\u6001" }, h15("h4", null, "\u8FD0\u884C\u72B6\u6001"), h15("p", null, "\u5BA2\u6237\u7AEF\uFF1A" + (activation.active ? "\u5DF2\u6FC0\u6D3B" : "\u6B63\u5728\u6FC0\u6D3B") + " \xB7 " + activation.channel), h15("button", { className: "dgui-secondary", type: "button", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u8FD0\u884C\u72B6\u6001"), report && h15(import_react20.default.Fragment, null, h15("p", null, "\u6784\u5EFA\uFF1A" + report.build.id + (report.build.id === BUILD_INFO.id ? " \xB7 \u524D\u540E\u7AEF\u4E00\u81F4" : " \xB7 \u524D\u540E\u7AEF\u4E0D\u540C\uFF0C\u8BF7\u91CD\u542F\u5BBF\u4E3B\u5E76\u5237\u65B0")), h15("p", null, "\u672C\u5730\u8D44\u6E90\uFF1A" + (report.assets.every((a) => a.available) && report.assetRouteOK ? "\u6B63\u5E38" : "\u6709\u7F3A\u5931\u6216\u8DEF\u7531\u4E0D\u53EF\u7528")), h15("p", null, "\u540C\u8F6E\u4FEE\u590D\u63A5\u53E3\uFF1A" + (report.feedbackHookRegistered ? "\u5DF2\u6CE8\u518C" : "\u5F53\u524D\u5BBF\u4E3B\u4E0D\u53EF\u7528") + " \xB7 \u539F\u751F\u4FA7\u680F\uFF1A" + (activation.sidebar ? "\u5DF2\u63A5\u5165" : "\u5F53\u524D\u5BBF\u4E3B\u672A\u63D0\u4F9B")), h15("p", null, "\u63A7\u4EF6\u4E0E\u6A21\u578B\u811A\u672C\u5728\u6574\u8F6E\u7ED3\u675F\u540E\u542F\u7528\uFF1B\u4E0D\u6539\u53D8\u5BBF\u4E3B\u6743\u9650\u3002")), error && h15("p", { role: "alert" }, error));
6040
+ return h16("section", { "aria-label": "\u8FD0\u884C\u72B6\u6001" }, h16("h4", null, "\u8FD0\u884C\u72B6\u6001"), h16("p", null, "\u5BA2\u6237\u7AEF\uFF1A" + (activation.active ? "\u5DF2\u6FC0\u6D3B" : "\u6B63\u5728\u6FC0\u6D3B") + " \xB7 " + activation.channel), h16("button", { className: "dgui-secondary", type: "button", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u8FD0\u884C\u72B6\u6001"), report && h16(import_react21.default.Fragment, null, h16("p", null, "\u6784\u5EFA\uFF1A" + report.build.id + (report.build.id === BUILD_INFO.id ? " \xB7 \u524D\u540E\u7AEF\u4E00\u81F4" : " \xB7 \u524D\u540E\u7AEF\u4E0D\u540C\uFF0C\u8BF7\u91CD\u542F\u5BBF\u4E3B\u5E76\u5237\u65B0")), h16("p", null, "\u672C\u5730\u8D44\u6E90\uFF1A" + (report.assets.every((a) => a.available) && report.assetRouteOK ? "\u6B63\u5E38" : "\u6709\u7F3A\u5931\u6216\u8DEF\u7531\u4E0D\u53EF\u7528")), h16("p", null, "\u540C\u8F6E\u4FEE\u590D\u63A5\u53E3\uFF1A" + (report.feedbackHookRegistered ? "\u5DF2\u6CE8\u518C" : "\u5F53\u524D\u5BBF\u4E3B\u4E0D\u53EF\u7528") + " \xB7 \u539F\u751F\u4FA7\u680F\uFF1A" + (activation.sidebar ? "\u5DF2\u63A5\u5165" : "\u5F53\u524D\u5BBF\u4E3B\u672A\u63D0\u4F9B")), h16("p", null, "\u63A7\u4EF6\u4E0E\u6A21\u578B\u811A\u672C\u5728\u6574\u8F6E\u7ED3\u675F\u540E\u542F\u7528\uFF1B\u4E0D\u6539\u53D8\u5BBF\u4E3B\u6743\u9650\u3002")), error && h16("p", { role: "alert" }, error));
5939
6041
  }
5940
6042
 
5941
6043
  // src/scene-library.js
5942
- var import_react21 = __toESM(require("react"), 1);
6044
+ var import_react22 = __toESM(require("react"), 1);
5943
6045
 
5944
6046
  // lib/scene-library.js
5945
6047
  var SCENES = Object.freeze([
@@ -5954,28 +6056,28 @@ var SCENES = Object.freeze([
5954
6056
  ]);
5955
6057
 
5956
6058
  // src/scene-library.js
5957
- var h16 = import_react21.default.createElement;
6059
+ var h17 = import_react22.default.createElement;
5958
6060
  function SceneLibrary() {
5959
- const [open, setOpen] = (0, import_react21.useState)(false), [selected, select] = (0, import_react21.useState)("brief"), [status, setStatus] = (0, import_react21.useState)("");
6061
+ const [open, setOpen] = (0, import_react22.useState)(false), [selected, select] = (0, import_react22.useState)("brief"), [status, setStatus] = (0, import_react22.useState)("");
5960
6062
  const scene = SCENES.find((s) => s.id === selected);
5961
- return h16("section", { "aria-label": "\u573A\u666F\u6848\u4F8B\u5E93" }, h16("h4", null, "\u573A\u666F\u6848\u4F8B\u5E93"), h16("p", null, "\u6309\u7528\u9014\u9884\u89C8\u77ED\u6848\u4F8B\u3002\u6848\u4F8B\u5C55\u793A\u7ED3\u6784\uFF0C\u751F\u6210\u65F6\u4F1A\u9002\u914D\u5F53\u524D\u5F15\u5BFC\u98CE\u683C\uFF1B\u63A7\u4EF6\u5728\u6B64\u5904\u53EA\u4F5C\u9884\u89C8\u3002"), h16("button", { className: "dgui-secondary", type: "button", "aria-expanded": open, onClick: () => setOpen(!open) }, open ? "\u6536\u8D77\u6848\u4F8B" : "\u6D4F\u89C8\u6848\u4F8B"), open && h16(import_react21.default.Fragment, null, h16("div", { className: "dgui-row dgui-scene-choices", role: "group", "aria-label": "\u9009\u62E9\u6848\u4F8B" }, SCENES.map((s) => h16("button", { className: "dgui-secondary", key: s.id, type: "button", "aria-pressed": s.id === selected, onClick: () => {
6063
+ return h17("section", { "aria-label": "\u573A\u666F\u6848\u4F8B\u5E93" }, h17("h4", null, "\u573A\u666F\u6848\u4F8B\u5E93"), h17("p", null, "\u6309\u7528\u9014\u9884\u89C8\u77ED\u6848\u4F8B\u3002\u6848\u4F8B\u5C55\u793A\u7ED3\u6784\uFF0C\u751F\u6210\u65F6\u4F1A\u9002\u914D\u5F53\u524D\u5F15\u5BFC\u98CE\u683C\uFF1B\u63A7\u4EF6\u5728\u6B64\u5904\u53EA\u4F5C\u9884\u89C8\u3002"), h17("button", { className: "dgui-secondary", type: "button", "aria-expanded": open, onClick: () => setOpen(!open) }, open ? "\u6536\u8D77\u6848\u4F8B" : "\u6D4F\u89C8\u6848\u4F8B"), open && h17(import_react22.default.Fragment, null, h17("div", { className: "dgui-row dgui-scene-choices", role: "group", "aria-label": "\u9009\u62E9\u6848\u4F8B" }, SCENES.map((s) => h17("button", { className: "dgui-secondary", key: s.id, type: "button", "aria-pressed": s.id === selected, onClick: () => {
5962
6064
  select(s.id);
5963
6065
  setStatus("");
5964
- } }, s.name))), h16(UiView, { key: selected, record: { documentId: "scene-" + selected, document: validateDocument(scene.spec) }, sessionId: "scene-preview", preview: true }), h16("button", { className: "dgui-secondary", type: "button", onClick: async () => {
6066
+ } }, s.name))), h17(UiView, { key: selected, record: { documentId: "scene-" + selected, document: validateDocument(scene.spec) }, sessionId: "scene-preview", preview: true }), h17("button", { className: "dgui-secondary", type: "button", onClick: async () => {
5965
6067
  try {
5966
6068
  await navigator.clipboard.writeText(scene.prompt);
5967
6069
  setStatus("\u9700\u6C42\u5DF2\u590D\u5236\uFF0C\u53EF\u4EE5\u4FEE\u6539\u540E\u53D1\u7ED9\u6A21\u578B\u3002");
5968
6070
  } catch {
5969
6071
  setStatus("\u590D\u5236\u4E0D\u53EF\u7528\uFF0C\u8BF7\u590D\u5236\u4E0B\u9762\u7684\u9700\u6C42\u3002");
5970
6072
  }
5971
- } }, "\u590D\u5236\u6848\u4F8B\u9700\u6C42"), h16("p", null, scene.prompt), status && h16("p", { role: "status" }, status)));
6073
+ } }, "\u590D\u5236\u6848\u4F8B\u9700\u6C42"), h17("p", null, scene.prompt), status && h17("p", { role: "status" }, status)));
5972
6074
  }
5973
6075
 
5974
6076
  // src/settings.js
5975
- var h17 = import_react22.default.createElement;
6077
+ var h18 = import_react23.default.createElement;
5976
6078
  function ModeSettings({ scope: scope2 }) {
5977
- const [snapshot2, setSnapshot] = (0, import_react22.useState)(() => scope2.getSnapshot()), [busy, setBusy] = (0, import_react22.useState)(false), [message, setMessage] = (0, import_react22.useState)(""), pending2 = (0, import_react22.useRef)(false);
5978
- (0, import_react22.useEffect)(() => scope2.subscribe(() => setSnapshot(scope2.getSnapshot())), [scope2]);
6079
+ const [snapshot2, setSnapshot] = (0, import_react23.useState)(() => scope2.getSnapshot()), [busy, setBusy] = (0, import_react23.useState)(false), [message, setMessage] = (0, import_react23.useState)(""), pending2 = (0, import_react23.useRef)(false);
6080
+ (0, import_react23.useEffect)(() => scope2.subscribe(() => setSnapshot(scope2.getSnapshot())), [scope2]);
5979
6081
  const ready = snapshot2.status === "ready" && snapshot2.value !== void 0;
5980
6082
  async function change(mode, key2 = "designMode") {
5981
6083
  if (pending2.current || !ready) return;
@@ -5996,29 +6098,30 @@ function ModeSettings({ scope: scope2 }) {
5996
6098
  setBusy(false);
5997
6099
  }
5998
6100
  }
5999
- return h17(
6101
+ return h18(
6000
6102
  "section",
6001
6103
  { className: "dgui-root dgui-settings", "aria-label": "DSH Motion UI \u8BBE\u7F6E" },
6002
- h17("h3", null, "DSH Motion UI"),
6003
- h17("label", { htmlFor: "dgui-design-mode" }, "\u8BBE\u8BA1\u6A21\u5F0F"),
6004
- h17("select", { id: "dgui-design-mode", value: snapshot2.value?.designMode ?? "guided", disabled: !ready || busy, onChange: (e) => change(e.target.value) }, h17("option", { value: "guided" }, "\u5F15\u5BFC\u6A21\u5F0F"), h17("option", { value: "free" }, "\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F")),
6005
- h17("p", null, "\u5F15\u5BFC\u6A21\u5F0F\u63D0\u4F9B\u8BBE\u8BA1\u6280\u80FD\u3001\u7EC4\u4EF6\u534F\u8BAE\u4E0E\u793A\u4F8B\u3002\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F\u53EA\u63D0\u4F9B\u753B\u5E03\u63A5\u53E3\u4E0E\u4EA4\u4E92\u7EA6\u675F\uFF0C\u5E03\u5C40\u3001\u56FE\u5F62\u3001\u914D\u8272\u548C\u52A8\u753B\u7531\u6A21\u578B\u51B3\u5B9A\uFF1B\u4E24\u79CD\u6A21\u5F0F\u7684\u8FD0\u884C\u6743\u9650\u76F8\u540C\u3002"),
6006
- h17("p", null, "\u4E24\u79CD\u6A21\u5F0F\u90FD\u4F1A\u6307\u5BFC\u6A21\u578B\u5224\u65AD\u4F55\u65F6\u4E3B\u52A8\u4F7F\u7528 UI\uFF0C\u5E76\u4F18\u5148\u4EA4\u4ED8\u5C0F\u800C\u5B8C\u6574\u7684\u754C\u9762\u3002"),
6007
- h17("h4", null, "\u89C6\u89C9\u98CE\u683C\uFF08\u4EC5\u9650\u5F15\u5BFC\u6A21\u5F0F\uFF09"),
6008
- h17("p", null, "\u70B9\u51FB\u98CE\u683C\u5361\u7247\u5373\u4FDD\u5B58\uFF0C\u4ECE\u4E0B\u4E00\u6B21\u8BF7\u6C42\u5F00\u59CB\u751F\u6548\u3002\u4E0B\u65B9\u53EF\u5207\u6362\u6392\u7248\u9884\u89C8\uFF0C\u4EC5\u4F9B\u6BD4\u8F83\uFF0C\u4E0D\u9650\u5236\u751F\u6210\u6392\u7248\u3002\u81EA\u7531\u6A21\u5F0F\u4E0D\u6CE8\u5165\u98CE\u683C\u6307\u5BFC\u4E0E\u6848\u4F8B\uFF0C\u7531\u6A21\u578B\u81EA\u4E3B\u8BBE\u8BA1\u3002"),
6009
- h17(StyleOptions, { value: snapshot2.value?.visualStyle ?? DEFAULT_VISUAL_STYLE, disabled: !ready || busy || snapshot2.value?.designMode === "free", onChange: (value) => change(value, "visualStyle") }),
6010
- h17("p", null, "\u6587\u5B57\u3001\u5BF9\u6BD4\u3001\u5217\u8868\u3001\u6458\u8981\u4E0E\u6D41\u7A0B\u7684\u6392\u7248\u4EA4\u7ED9\u6A21\u578B\u6309\u5185\u5BB9\u81EA\u9009\u3002\u540C\u4E00\u56DE\u590D\u53EF\u7EC4\u5408\u591A\u5757\u4E0D\u540C\u6392\u7248\u7684\u754C\u9762\u3002"),
6011
- h17("p", null, "\u754C\u9762\u7EDF\u4E00\u901A\u8FC7\u6B63\u6587\u6807\u8BB0\u5B9A\u4F4D\u3002DSH \u4FA7\u680F\u7684\u201C\u667A\u80FD UI\u201D\u5165\u53E3\u53EF\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u7684\u754C\u9762\uFF0C\u6B63\u6587\u548C\u4FA7\u680F\u5171\u4EAB\u5DF2\u4FDD\u5B58\u53C2\u6570\u3002"),
6012
- h17("label", { htmlFor: "dgui-show-details" }, h17("input", { id: "dgui-show-details", type: "checkbox", checked: snapshot2.value?.showDetails === true, disabled: !ready || busy, onChange: (e) => change(e.target.checked, "showDetails") }), " \u663E\u793A\u754C\u9762\u8BE6\u60C5"),
6013
- h17("p", null, "\u9ED8\u8BA4\u9690\u85CF\u5E95\u90E8\u7684\u53C2\u6570\u72B6\u6001\u3001\u539F\u59CB\u8BF4\u660E\u3001\u663E\u793A\u68C0\u67E5\u548C\u7248\u672C\u5386\u53F2\u3002\u5BFC\u51FA\u4E0E\u91CD\u7F6E\u53EF\u901A\u8FC7\u753B\u5E03\u53F3\u4E0A\u89D2\u64CD\u4F5C\u83DC\u5355\u4F7F\u7528\uFF1B\u9519\u8BEF\u63D0\u793A\u59CB\u7EC8\u4FDD\u7559\u3002"),
6014
- h17("p", null, "\u6B64\u8BBE\u7F6E\u5F71\u54CD\u5F53\u524D profile \u540E\u7EED\u8BF7\u6C42\u3002\u5DF2\u6709\u4E0A\u4E0B\u6587\u53EF\u80FD\u4FDD\u7559\u65E7\u6307\u5BFC\uFF0C\u5BF9\u6BD4\u6A21\u5F0F\u65F6\u8BF7\u65B0\u5EFA\u4F1A\u8BDD\u3002"),
6015
- h17("label", null, h17("input", { type: "checkbox", checked: snapshot2.value?.autoRepair !== false, disabled: !ready || busy, onChange: (e) => change(e.target.checked, "autoRepair") }), " \u81EA\u52A8\u53CD\u9988\u754C\u9762\u751F\u6210\u95EE\u9898"),
6016
- h17("p", null, "\u6700\u591A\u4E24\u6B21\u53BB\u91CD\u63D0\u9192\uFF0C\u4E0D\u9650\u5236\u6A21\u578B\u601D\u8003\u65F6\u957F\uFF1B\u53D6\u6D88\u751F\u6210\u65F6\u4E0D\u518D\u89E6\u53D1\u4FEE\u590D\u3002"),
6017
- h17(SceneLibrary),
6018
- h17(MotionLibrary),
6019
- h17(RuntimeDiagnostics),
6020
- !ready && h17("p", { role: "status" }, snapshot2.status === "unavailable" ? "\u63D2\u4EF6\u8BBE\u7F6E\u4E0D\u53EF\u7528\uFF0C\u8BF7\u786E\u8BA4\u5BBF\u4E3B\u5DF2\u52A0\u8F7D\u65B0\u7248\u63D2\u4EF6\u3002" : "\u6B63\u5728\u8BFB\u53D6\u8BBE\u7F6E\u2026"),
6021
- message && h17("p", { role: "status" }, message)
6104
+ h18("h3", null, "DSH Motion UI"),
6105
+ h18("label", { htmlFor: "dgui-design-mode" }, "\u8BBE\u8BA1\u6A21\u5F0F"),
6106
+ h18("select", { id: "dgui-design-mode", value: snapshot2.value?.designMode ?? "guided", disabled: !ready || busy, onChange: (e) => change(e.target.value) }, h18("option", { value: "guided" }, "\u5F15\u5BFC\u6A21\u5F0F"), h18("option", { value: "free" }, "\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F")),
6107
+ h18("p", null, "\u5F15\u5BFC\u6A21\u5F0F\u63D0\u4F9B\u8BBE\u8BA1\u6280\u80FD\u3001\u7EC4\u4EF6\u534F\u8BAE\u4E0E\u793A\u4F8B\u3002\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F\u53EA\u63D0\u4F9B\u753B\u5E03\u63A5\u53E3\u4E0E\u4EA4\u4E92\u7EA6\u675F\uFF0C\u5E03\u5C40\u3001\u56FE\u5F62\u3001\u914D\u8272\u548C\u52A8\u753B\u7531\u6A21\u578B\u51B3\u5B9A\uFF1B\u4E24\u79CD\u6A21\u5F0F\u7684\u8FD0\u884C\u6743\u9650\u76F8\u540C\u3002"),
6108
+ h18("p", null, "\u4E24\u79CD\u6A21\u5F0F\u90FD\u4F1A\u6307\u5BFC\u6A21\u578B\u5224\u65AD\u4F55\u65F6\u4E3B\u52A8\u4F7F\u7528 UI\uFF0C\u5E76\u4F18\u5148\u4EA4\u4ED8\u5C0F\u800C\u5B8C\u6574\u7684\u754C\u9762\u3002"),
6109
+ h18("h4", null, "\u89C6\u89C9\u98CE\u683C\uFF08\u4EC5\u9650\u5F15\u5BFC\u6A21\u5F0F\uFF09"),
6110
+ h18("p", null, "\u70B9\u51FB\u98CE\u683C\u5361\u7247\u5373\u4FDD\u5B58\uFF0C\u4ECE\u4E0B\u4E00\u6B21\u8BF7\u6C42\u5F00\u59CB\u751F\u6548\u3002\u4E0B\u65B9\u53EF\u5207\u6362\u6392\u7248\u9884\u89C8\uFF0C\u4EC5\u4F9B\u6BD4\u8F83\uFF0C\u4E0D\u9650\u5236\u751F\u6210\u6392\u7248\u3002\u81EA\u7531\u6A21\u5F0F\u4E0D\u6CE8\u5165\u98CE\u683C\u6307\u5BFC\u4E0E\u6848\u4F8B\uFF0C\u7531\u6A21\u578B\u81EA\u4E3B\u8BBE\u8BA1\u3002"),
6111
+ h18(StyleOptions, { value: snapshot2.value?.visualStyle ?? DEFAULT_VISUAL_STYLE, disabled: !ready || busy || snapshot2.value?.designMode === "free", onChange: (value) => change(value, "visualStyle") }),
6112
+ h18("p", null, "\u6587\u5B57\u3001\u5BF9\u6BD4\u3001\u5217\u8868\u3001\u6458\u8981\u4E0E\u6D41\u7A0B\u7684\u6392\u7248\u4EA4\u7ED9\u6A21\u578B\u6309\u5185\u5BB9\u81EA\u9009\u3002\u540C\u4E00\u56DE\u590D\u53EF\u7EC4\u5408\u591A\u5757\u4E0D\u540C\u6392\u7248\u7684\u754C\u9762\u3002"),
6113
+ h18("p", null, "\u754C\u9762\u7EDF\u4E00\u901A\u8FC7\u6B63\u6587\u6807\u8BB0\u5B9A\u4F4D\u3002DSH \u4FA7\u680F\u7684\u201C\u667A\u80FD UI\u201D\u5165\u53E3\u53EF\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u7684\u754C\u9762\uFF0C\u6B63\u6587\u548C\u4FA7\u680F\u5171\u4EAB\u5DF2\u4FDD\u5B58\u53C2\u6570\u3002"),
6114
+ h18("label", { htmlFor: "dgui-show-details" }, h18("input", { id: "dgui-show-details", type: "checkbox", checked: snapshot2.value?.showDetails === true, disabled: !ready || busy, onChange: (e) => change(e.target.checked, "showDetails") }), " \u663E\u793A\u754C\u9762\u8BE6\u60C5"),
6115
+ h18("p", null, "\u9ED8\u8BA4\u9690\u85CF\u5E95\u90E8\u7684\u53C2\u6570\u72B6\u6001\u3001\u539F\u59CB\u8BF4\u660E\u3001\u663E\u793A\u68C0\u67E5\u548C\u7248\u672C\u5386\u53F2\u3002\u5BFC\u51FA\u4E0E\u91CD\u7F6E\u53EF\u901A\u8FC7\u753B\u5E03\u53F3\u4E0A\u89D2\u64CD\u4F5C\u83DC\u5355\u4F7F\u7528\uFF1B\u9519\u8BEF\u63D0\u793A\u59CB\u7EC8\u4FDD\u7559\u3002"),
6116
+ h18("p", null, "\u6B64\u8BBE\u7F6E\u5F71\u54CD\u5F53\u524D profile \u540E\u7EED\u8BF7\u6C42\u3002\u5DF2\u6709\u4E0A\u4E0B\u6587\u53EF\u80FD\u4FDD\u7559\u65E7\u6307\u5BFC\uFF0C\u5BF9\u6BD4\u6A21\u5F0F\u65F6\u8BF7\u65B0\u5EFA\u4F1A\u8BDD\u3002"),
6117
+ h18("label", null, h18("input", { type: "checkbox", checked: snapshot2.value?.autoRepair !== false, disabled: !ready || busy, onChange: (e) => change(e.target.checked, "autoRepair") }), " \u81EA\u52A8\u53CD\u9988\u754C\u9762\u751F\u6210\u95EE\u9898"),
6118
+ h18("p", null, "\u6700\u591A\u4E24\u6B21\u53BB\u91CD\u63D0\u9192\uFF0C\u4E0D\u9650\u5236\u6A21\u578B\u601D\u8003\u65F6\u957F\uFF1B\u53D6\u6D88\u751F\u6210\u65F6\u4E0D\u518D\u89E6\u53D1\u4FEE\u590D\u3002"),
6119
+ h18(SceneLibrary),
6120
+ h18(MotionLibrary),
6121
+ h18(VideoCapabilities),
6122
+ h18(RuntimeDiagnostics),
6123
+ !ready && h18("p", { role: "status" }, snapshot2.status === "unavailable" ? "\u63D2\u4EF6\u8BBE\u7F6E\u4E0D\u53EF\u7528\uFF0C\u8BF7\u786E\u8BA4\u5BBF\u4E3B\u5DF2\u52A0\u8F7D\u65B0\u7248\u63D2\u4EF6\u3002" : "\u6B63\u5728\u8BFB\u53D6\u8BBE\u7F6E\u2026"),
6124
+ message && h18("p", { role: "status" }, message)
6022
6125
  );
6023
6126
  }
6024
6127
 
@@ -6055,7 +6158,7 @@ var fenceUiDefinition = {
6055
6158
  };
6056
6159
 
6057
6160
  // src/fence-view.js
6058
- var import_react23 = __toESM(require("react"), 1);
6161
+ var import_react24 = __toESM(require("react"), 1);
6059
6162
  var import_client2 = require("react-dom/client");
6060
6163
 
6061
6164
  // lib/fences.js
@@ -6080,11 +6183,11 @@ function extractUiFences(text3) {
6080
6183
  }
6081
6184
 
6082
6185
  // src/fence-view.js
6083
- var h18 = import_react23.default.createElement;
6186
+ var h19 = import_react24.default.createElement;
6084
6187
  var roots3 = /* @__PURE__ */ new WeakMap();
6085
6188
  function FenceContent({ document: document2, sessionId, source, settled, sendPrompt }) {
6086
- const [record, setRecord] = (0, import_react23.useState)(), [error, setError] = (0, import_react23.useState)("");
6087
- (0, import_react23.useEffect)(() => {
6189
+ const [record, setRecord] = (0, import_react24.useState)(), [error, setError] = (0, import_react24.useState)("");
6190
+ (0, import_react24.useEffect)(() => {
6088
6191
  if (!settled) return;
6089
6192
  let active = true;
6090
6193
  fetch("/api/plugins/dsh-generative-ui/fence", { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ document: document2, sessionId, source }) }).then(async (r) => {
@@ -6101,7 +6204,7 @@ function FenceContent({ document: document2, sessionId, source, settled, sendPro
6101
6204
  active = false;
6102
6205
  };
6103
6206
  }, [document2, sessionId, source, settled]);
6104
- return h18(UiBoundary, { fallback: document2.fallback }, h18(UiView, { record: record ?? { document: document2, documentId: "fence-preview-" + source }, sessionId, sendPrompt, preview: !record }), error && h18("p", { role: "alert" }, error));
6207
+ return h19(UiBoundary, { fallback: document2.fallback }, h19(UiView, { record: record ?? { document: document2, documentId: "fence-preview-" + source }, sessionId, sendPrompt, preview: !record }), error && h19("p", { role: "alert" }, error));
6105
6208
  }
6106
6209
  function candidates(state2) {
6107
6210
  const steps = /* @__PURE__ */ new Map();
@@ -6145,8 +6248,8 @@ function dispose2(e) {
6145
6248
  e.entries.delete(e.key);
6146
6249
  }
6147
6250
  function FenceNodeView({ node, sessionId, sendPrompt }) {
6148
- const anchor = (0, import_react23.useRef)(null), state2 = node.data;
6149
- (0, import_react23.useLayoutEffect)(() => {
6251
+ const anchor = (0, import_react24.useRef)(null), state2 = node.data;
6252
+ (0, import_react24.useLayoutEffect)(() => {
6150
6253
  const scroll = anchor.current?.closest("[data-conversation-scroll]");
6151
6254
  if (!scroll) return;
6152
6255
  let entries = roots3.get(scroll);
@@ -6185,7 +6288,7 @@ function FenceNodeView({ node, sessionId, sendPrompt }) {
6185
6288
  const fingerprint = JSON.stringify(candidate.document) + ":" + candidate.error + ":" + e.state.settled;
6186
6289
  if (v2.fingerprint !== fingerprint) {
6187
6290
  v2.fingerprint = fingerprint;
6188
- v2.root.render(candidate.error ? h18("p", { className: "dgui-tool-error", role: "alert" }, "\u754C\u9762\u672A\u5B8C\u6210\uFF1A" + candidate.error) : h18(FenceContent, { document: candidate.document, source: candidate.key, sessionId, settled: e.state.settled, sendPrompt: e.sendPrompt }));
6291
+ v2.root.render(candidate.error ? h19("p", { className: "dgui-tool-error", role: "alert" }, "\u754C\u9762\u672A\u5B8C\u6210\uFF1A" + candidate.error) : h19(FenceContent, { document: candidate.document, source: candidate.key, sessionId, settled: e.state.settled, sendPrompt: e.sendPrompt }));
6189
6292
  }
6190
6293
  const block = [...scroll.querySelectorAll("div.md-code-block,.code-block,.code-block-small,pre")].find((b2) => !b2.closest("[data-dsh-generative-ui]") && String(b2.closest("[data-chat-turn]")?.dataset.chatTurn) === String(e.state.turn) && (b2.querySelector("code")?.textContent ?? b2.querySelector("pre")?.textContent ?? (b2.matches("pre") ? b2.textContent : "")).trim() === candidate.raw.trim());
6191
6294
  if (block) {
@@ -6212,7 +6315,7 @@ function FenceNodeView({ node, sessionId, sendPrompt }) {
6212
6315
  e.sendPrompt = sendPrompt;
6213
6316
  e.queue();
6214
6317
  }, [state2, sessionId, sendPrompt]);
6215
- return h18("span", { ref: anchor, hidden: true });
6318
+ return h19("span", { ref: anchor, hidden: true });
6216
6319
  }
6217
6320
 
6218
6321
  // src/visual-styles.js
@@ -6224,6 +6327,334 @@ var VISUAL_CSS = `
6224
6327
  @media(prefers-reduced-motion:reduce){[data-motion-visual] *,[data-motion-visual] *::before,[data-motion-visual] *::after{animation-duration:.001ms!important;transition-duration:.001ms!important}}
6225
6328
  `;
6226
6329
 
6330
+ // src/media-history.js
6331
+ var uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/;
6332
+ var allowedFiles = /* @__PURE__ */ new Set(["video.mp4", "poster.jpg", "source.html", "project.zip"]);
6333
+ function mediaRecord(message) {
6334
+ if (message?.isError) return null;
6335
+ for (const part of message?.content ?? []) {
6336
+ if (part.type !== "text" || typeof part.text !== "string" || part.text.length > 2e6) continue;
6337
+ try {
6338
+ const value = JSON.parse(part.text.split("\n", 1)[0]);
6339
+ if (!uuid.test(value.id) || !["render", "process"].includes(value.kind) || value.status !== "completed" || typeof value.sessionId !== "string" || !value.sessionId || value.sessionId.length > 256) continue;
6340
+ const files = (value.files ?? []).map((f) => typeof f === "string" ? f : f?.name).filter((f) => allowedFiles.has(f));
6341
+ if (!files.includes("video.mp4")) continue;
6342
+ const output = value.output ?? {}, positive = (n2) => typeof n2 === "number" && Number.isFinite(n2) && n2 > 0 ? n2 : null;
6343
+ return { id: value.id, sessionId: value.sessionId, kind: value.kind, files: [...new Set(files)], documentId: uuid.test(value.documentId) ? value.documentId : null, nodeId: typeof value.nodeId === "string" ? value.nodeId : null, duration: positive(output.duration), width: positive(output.width), height: positive(output.height), hasAudio: Array.isArray(output.audio) ? output.audio.length > 0 : null };
6344
+ } catch {
6345
+ }
6346
+ }
6347
+ return null;
6348
+ }
6349
+ function mediaAssetUrl(record, file) {
6350
+ if (!record || !uuid.test(record.id) || typeof record.sessionId !== "string" || !record.sessionId || !allowedFiles.has(file) || !record.files?.includes(file)) return null;
6351
+ return "/api/plugins/dsh-generative-ui/media?assetId=" + record.id + "&sessionId=" + encodeURIComponent(record.sessionId) + "&file=" + encodeURIComponent(file);
6352
+ }
6353
+ var mediaHistoryDefinition = {
6354
+ kind: "dshMotionMedia",
6355
+ target: "chat",
6356
+ match(event) {
6357
+ if (event.type === "turn/start") return { id: String(event.data.turn), role: "start" };
6358
+ if (event.type === "tool/result" && event.surfaceOp === "append" && mediaRecord(event.data.message)) return { id: String(event.data.turn), role: "update" };
6359
+ return null;
6360
+ },
6361
+ start(_context, { event }) {
6362
+ return { turn: event.data.turn, records: [] };
6363
+ },
6364
+ update({ state: state2 }, { event }) {
6365
+ const record = mediaRecord(event.data.message);
6366
+ if (!record) return state2;
6367
+ const key2 = record.kind === "render" && record.documentId ? record.documentId + ":" + record.nodeId : record.id;
6368
+ const index = state2.records.findIndex((r) => r.key === key2);
6369
+ if (index >= 0 && state2.records[index].id === record.id) return state2;
6370
+ const records2 = [...state2.records];
6371
+ if (index >= 0) records2[index] = { ...record, key: key2 };
6372
+ else records2.push({ ...record, key: key2 });
6373
+ return { ...state2, anchorSeq: state2.anchorSeq ?? event.seq, records: records2 };
6374
+ },
6375
+ publication: () => "immediate",
6376
+ buildViewNode(c) {
6377
+ if (!c.state) return null;
6378
+ return { key: c.key, id: c.id, kind: "dshMotionMedia", target: "chat", anchorSeq: c.state.anchorSeq ?? c.start?.event.seq ?? 0, location: c.start?.location ?? c.matches?.[0]?.location ?? { kind: "unresolved" }, visibility: c.state.records.length ? "visible" : "hidden", data: c.state };
6379
+ }
6380
+ };
6381
+
6382
+ // src/media-player.js
6383
+ var import_react25 = __toESM(require("react"), 1);
6384
+ var import_client3 = require("react-dom/client");
6385
+ var h20 = import_react25.default.createElement;
6386
+ var players = /* @__PURE__ */ new Set();
6387
+ var preferenceKey = "dsh-motion-ui:video-playback";
6388
+ function formatMediaTime(seconds) {
6389
+ const s = Math.max(0, Math.floor(Number.isFinite(seconds) ? seconds : 0));
6390
+ return (s >= 3600 ? Math.floor(s / 3600) + ":" : "") + String(Math.floor(s / 60) % 60).padStart(2, "0") + ":" + String(s % 60).padStart(2, "0");
6391
+ }
6392
+ function preferences() {
6393
+ try {
6394
+ const p2 = JSON.parse(localStorage.getItem(preferenceKey));
6395
+ return { volume: typeof p2?.volume === "number" && Number.isFinite(p2.volume) ? Math.max(0, Math.min(1, p2.volume)) : 0.8, muted: p2?.muted === true, rate: [0.5, 1, 1.25, 1.5, 2].includes(p2?.rate) ? p2.rate : 1 };
6396
+ } catch {
6397
+ return { volume: 0.8, muted: false, rate: 1 };
6398
+ }
6399
+ }
6400
+ function remember(v2) {
6401
+ try {
6402
+ localStorage.setItem(preferenceKey, JSON.stringify({ volume: v2.volume, muted: v2.muted, rate: v2.playbackRate }));
6403
+ } catch {
6404
+ }
6405
+ }
6406
+ function VideoPlayer({ record }) {
6407
+ const video = (0, import_react25.useRef)(null), root2 = (0, import_react25.useRef)(null), [prefs] = (0, import_react25.useState)(preferences), [playing, setPlaying] = (0, import_react25.useState)(false), [time, setTime] = (0, import_react25.useState)(0), [duration, setDuration] = (0, import_react25.useState)(record.duration ?? 0), [ready, setReady] = (0, import_react25.useState)(false), [volume, setVolume] = (0, import_react25.useState)(prefs.volume), [muted, setMuted] = (0, import_react25.useState)(prefs.muted), [rate, setRate] = (0, import_react25.useState)(prefs.rate), [fullscreen, setFullscreen] = (0, import_react25.useState)(false), [error, setError] = (0, import_react25.useState)(""), [notice, setNotice] = (0, import_react25.useState)("");
6408
+ const src = mediaAssetUrl(record, "video.mp4"), poster = mediaAssetUrl(record, "poster.jpg");
6409
+ const lastVolume = (0, import_react25.useRef)(prefs.volume || 0.8);
6410
+ (0, import_react25.useEffect)(() => {
6411
+ const v2 = video.current, container = root2.current;
6412
+ if (!v2) return;
6413
+ players.add(v2);
6414
+ v2.volume = prefs.volume;
6415
+ v2.muted = prefs.muted;
6416
+ v2.playbackRate = prefs.rate;
6417
+ const stop = () => v2.pause(), hidden = () => {
6418
+ if (document.hidden) stop();
6419
+ }, fs = () => setFullscreen(document.fullscreenElement === container);
6420
+ document.addEventListener("visibilitychange", hidden);
6421
+ window.addEventListener("pagehide", stop);
6422
+ document.addEventListener("fullscreenchange", fs);
6423
+ return () => {
6424
+ stop();
6425
+ players.delete(v2);
6426
+ document.removeEventListener("visibilitychange", hidden);
6427
+ window.removeEventListener("pagehide", stop);
6428
+ document.removeEventListener("fullscreenchange", fs);
6429
+ };
6430
+ }, [src]);
6431
+ async function toggle() {
6432
+ const v2 = video.current;
6433
+ if (!v2) return;
6434
+ setNotice("");
6435
+ if (!v2.paused) {
6436
+ v2.pause();
6437
+ return;
6438
+ }
6439
+ try {
6440
+ if (v2.ended) v2.currentTime = 0;
6441
+ await v2.play();
6442
+ } catch (e) {
6443
+ if (e.name !== "AbortError") setNotice("\u6682\u65F6\u65E0\u6CD5\u64AD\u653E\uFF0C\u8BF7\u91CD\u8BD5\u6216\u4E0B\u8F7D\u89C6\u9891\u3002");
6444
+ }
6445
+ }
6446
+ function seek(value) {
6447
+ const v2 = video.current;
6448
+ if (!v2 || !ready || !Number.isFinite(duration) || duration <= 0) return;
6449
+ v2.currentTime = Math.max(0, Math.min(duration, Number(value)));
6450
+ setTime(v2.currentTime);
6451
+ }
6452
+ function mute() {
6453
+ const v2 = video.current;
6454
+ if (v2.volume === 0) {
6455
+ v2.volume = lastVolume.current;
6456
+ v2.muted = false;
6457
+ } else v2.muted = !v2.muted;
6458
+ }
6459
+ async function full() {
6460
+ setNotice("");
6461
+ try {
6462
+ if (document.fullscreenElement === root2.current) await document.exitFullscreen();
6463
+ else if (root2.current.requestFullscreen) await root2.current.requestFullscreen();
6464
+ else if (video.current.webkitEnterFullscreen) video.current.webkitEnterFullscreen();
6465
+ else setNotice("\u6B64\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u5168\u5C4F\u3002");
6466
+ } catch {
6467
+ setNotice("\u6682\u65F6\u65E0\u6CD5\u8FDB\u5165\u5168\u5C4F\uFF0C\u8BF7\u91CD\u8BD5\u3002");
6468
+ }
6469
+ }
6470
+ function key2(e) {
6471
+ if (e.target !== video.current && e.target !== root2.current) return;
6472
+ const k2 = e.key.toLowerCase();
6473
+ if ([" ", "k", "m", "f", "arrowleft", "arrowright"].includes(k2)) {
6474
+ e.preventDefault();
6475
+ if (k2 === " " || k2 === "k") toggle();
6476
+ else if (k2 === "m") mute();
6477
+ else if (k2 === "f") full();
6478
+ else seek((video.current?.currentTime ?? 0) + (k2 === "arrowleft" ? -5 : 5));
6479
+ }
6480
+ }
6481
+ const button = (name, icon, fn2, extra = {}) => h20("button", { type: "button", "aria-label": name, title: name, onClick: fn2, ...extra }, h20(Icon, { name: icon }));
6482
+ return h20(
6483
+ "section",
6484
+ { ref: root2, className: "motion-video-player", "data-motion-video": record.id, "aria-label": "\u89C6\u9891\u64AD\u653E\u5668", onKeyDown: key2 },
6485
+ h20("video", {
6486
+ ref: video,
6487
+ src,
6488
+ poster: poster ?? void 0,
6489
+ preload: "metadata",
6490
+ playsInline: true,
6491
+ controls: false,
6492
+ tabIndex: 0,
6493
+ "aria-label": "\u89C6\u9891\u753B\u9762",
6494
+ onLoadedMetadata: (e) => {
6495
+ const v2 = e.currentTarget;
6496
+ setReady(true);
6497
+ setError("");
6498
+ if (Number.isFinite(v2.duration)) setDuration(v2.duration);
6499
+ },
6500
+ onTimeUpdate: (e) => setTime(e.currentTarget.currentTime),
6501
+ onDurationChange: (e) => {
6502
+ if (Number.isFinite(e.currentTarget.duration)) setDuration(e.currentTarget.duration);
6503
+ },
6504
+ onPlay: (e) => {
6505
+ for (const other of players) if (other !== e.currentTarget) other.pause();
6506
+ setPlaying(true);
6507
+ setError("");
6508
+ },
6509
+ onPause: () => setPlaying(false),
6510
+ onEnded: () => setPlaying(false),
6511
+ onVolumeChange: (e) => {
6512
+ if (e.currentTarget.volume > 0) lastVolume.current = e.currentTarget.volume;
6513
+ setVolume(e.currentTarget.volume);
6514
+ setMuted(e.currentTarget.muted);
6515
+ remember(e.currentTarget);
6516
+ },
6517
+ onRateChange: (e) => {
6518
+ setRate(e.currentTarget.playbackRate);
6519
+ remember(e.currentTarget);
6520
+ },
6521
+ onError: () => {
6522
+ setError("\u65E0\u6CD5\u64AD\u653E\u6B64\u89C6\u9891\u3002\u53EF\u4EE5\u91CD\u8BD5\u6216\u4E0B\u8F7D\u540E\u6253\u5F00\u3002");
6523
+ setReady(false);
6524
+ setPlaying(false);
6525
+ },
6526
+ onClick: toggle,
6527
+ onDoubleClick: full
6528
+ }),
6529
+ h20(
6530
+ "div",
6531
+ { className: "motion-video-controls" },
6532
+ h20("input", { className: "motion-video-seek", type: "range", min: 0, max: duration || 1, step: 0.05, value: Math.min(time, duration || 1), disabled: !ready, "aria-label": "\u64AD\u653E\u8FDB\u5EA6\uFF08\u79D2\uFF09", "aria-valuetext": formatMediaTime(time) + " / " + formatMediaTime(duration), onChange: (e) => seek(e.currentTarget.value) }),
6533
+ button(playing ? "\u6682\u505C\u89C6\u9891" : "\u64AD\u653E\u89C6\u9891", playing ? "pause" : "play", toggle, { disabled: !!error }),
6534
+ h20("output", { className: "motion-video-time", "aria-label": "\u64AD\u653E\u65F6\u95F4" }, formatMediaTime(time) + " / " + formatMediaTime(duration)),
6535
+ h20("div", { className: "motion-video-volume" }, button(muted || volume === 0 ? "\u53D6\u6D88\u9759\u97F3" : "\u9759\u97F3\u89C6\u9891", muted || volume === 0 ? "volumeOff" : "volume", mute, { "aria-pressed": muted || volume === 0 }), h20("input", { type: "range", min: 0, max: 1, step: 0.05, value: muted ? 0 : volume, "aria-label": "\u89C6\u9891\u97F3\u91CF", "aria-valuetext": Math.round((muted ? 0 : volume) * 100) + "%", onChange: (e) => {
6536
+ const v2 = video.current;
6537
+ v2.volume = Number(e.currentTarget.value);
6538
+ v2.muted = v2.volume === 0;
6539
+ } })),
6540
+ h20("select", { "aria-label": "\u64AD\u653E\u901F\u5EA6", title: "\u64AD\u653E\u901F\u5EA6", value: rate, onChange: (e) => {
6541
+ video.current.playbackRate = Number(e.currentTarget.value);
6542
+ } }, [0.5, 1, 1.25, 1.5, 2].map((v2) => h20("option", { key: v2, value: v2 }, v2 + "\xD7"))),
6543
+ button(fullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F\u64AD\u653E", fullscreen ? "minimize" : "fullscreen", full),
6544
+ h20("a", { href: src, download: "video.mp4", "aria-label": "\u4E0B\u8F7D\u89C6\u9891", title: "\u4E0B\u8F7D\u89C6\u9891" }, h20(Icon, { name: "download" })),
6545
+ record.files.includes("source.html") && h20("a", { className: "motion-video-source", href: mediaAssetUrl(record, "source.html"), download: "source.html" }, "\u6E90\u7801"),
6546
+ record.files.includes("project.zip") && h20("a", { className: "motion-video-source", href: mediaAssetUrl(record, "project.zip"), download: "project.zip" }, "\u5DE5\u7A0B")
6547
+ ),
6548
+ error && h20("div", { className: "motion-video-message", role: "alert" }, h20("span", null, error), h20("button", { type: "button", onClick: () => {
6549
+ setError("");
6550
+ video.current.load();
6551
+ } }, "\u91CD\u65B0\u52A0\u8F7D")),
6552
+ notice && h20("p", { className: "motion-video-message", role: "status" }, notice)
6553
+ );
6554
+ }
6555
+ function MediaRecords({ records: records2, sessionId }) {
6556
+ return h20(import_react25.default.Fragment, null, records2.filter((r) => r.sessionId === sessionId).map((record) => h20(VideoPlayer, { key: record.id, record })));
6557
+ }
6558
+ var mediaRoots = /* @__PURE__ */ new WeakMap();
6559
+ var allMediaRoots = /* @__PURE__ */ new Set();
6560
+ function disposeSurface(entry) {
6561
+ if (entry.disposed) return;
6562
+ entry.disposed = true;
6563
+ entry.observer.disconnect();
6564
+ entry.host.remove();
6565
+ entry.entries.delete(entry.key);
6566
+ allMediaRoots.delete(entry);
6567
+ queueMicrotask(() => entry.root.unmount());
6568
+ }
6569
+ function disposeMediaSurfaces() {
6570
+ for (const entry of [...allMediaRoots]) disposeSurface(entry);
6571
+ }
6572
+ function placeOutsideFold(entry) {
6573
+ if (!entry.anchor?.isConnected) return;
6574
+ let folded = null;
6575
+ for (let el = entry.anchor; el && el !== entry.scroll; el = el.parentElement) if (el.getAttribute("hidden") === "until-found") folded = el;
6576
+ if (!folded) return;
6577
+ const seat = folded.parentElement, parent = seat === entry.scroll ? entry.scroll : seat.parentElement, before = seat === entry.scroll ? null : seat.nextSibling;
6578
+ if (before === entry.host || !before && parent.lastChild === entry.host) return;
6579
+ try {
6580
+ if (parent.moveBefore) {
6581
+ parent.moveBefore(entry.host, before);
6582
+ return;
6583
+ }
6584
+ } catch {
6585
+ }
6586
+ const playing = [...entry.host.querySelectorAll("video")].filter((v2) => !v2.paused).map((v2) => ({ v: v2, time: v2.currentTime }));
6587
+ parent.insertBefore(entry.host, before);
6588
+ queueMicrotask(() => {
6589
+ for (const { v: v2, time } of playing) if (v2.isConnected) {
6590
+ if (Math.abs(v2.currentTime - time) > 0.2) v2.currentTime = time;
6591
+ v2.play().catch(() => {
6592
+ });
6593
+ }
6594
+ });
6595
+ }
6596
+ function MediaNodeView({ node, sessionId }) {
6597
+ const anchor = (0, import_react25.useRef)(null), [inline, setInline] = (0, import_react25.useState)(false), state2 = node.data;
6598
+ (0, import_react25.useLayoutEffect)(() => {
6599
+ const scroll = anchor.current?.closest("[data-conversation-scroll]");
6600
+ if (!scroll) {
6601
+ setInline(true);
6602
+ return;
6603
+ }
6604
+ let entries = mediaRoots.get(scroll);
6605
+ if (!entries) {
6606
+ entries = /* @__PURE__ */ new Map();
6607
+ mediaRoots.set(scroll, entries);
6608
+ }
6609
+ for (const other of [...entries.values()]) if (other.sessionId !== sessionId) disposeSurface(other);
6610
+ const key2 = sessionId + ":" + state2.turn;
6611
+ let entry = entries.get(key2);
6612
+ if (!state2.records?.length) {
6613
+ if (entry) disposeSurface(entry);
6614
+ return;
6615
+ }
6616
+ if (!entry) {
6617
+ let folded = null;
6618
+ for (let el = anchor.current; el && el !== scroll; el = el.parentElement) if (el.getAttribute("hidden") === "until-found") folded = el;
6619
+ const seat = folded?.parentElement ?? anchor.current.closest("[data-chat-turn]") ?? anchor.current;
6620
+ const host = document.createElement("div");
6621
+ host.dataset.motionMediaTurn = String(state2.turn);
6622
+ if (seat === scroll) scroll.append(host);
6623
+ else seat.after(host);
6624
+ entry = { key: key2, entries, host, root: (0, import_client3.createRoot)(host), sessionId, scroll, anchor: anchor.current, url: location.href };
6625
+ entry.observer = new MutationObserver(() => {
6626
+ if (location.href !== entry.url || !host.isConnected || !scroll.isConnected) disposeSurface(entry);
6627
+ else placeOutsideFold(entry);
6628
+ });
6629
+ entry.observer.observe(document.body, { subtree: true, childList: true, attributes: true, attributeFilter: ["hidden"] });
6630
+ entries.set(key2, entry);
6631
+ allMediaRoots.add(entry);
6632
+ }
6633
+ entry.anchor = anchor.current;
6634
+ placeOutsideFold(entry);
6635
+ const fingerprint = JSON.stringify(state2.records);
6636
+ if (entry.fingerprint !== fingerprint) {
6637
+ entry.fingerprint = fingerprint;
6638
+ entry.root.render(h20(MediaRecords, { records: state2.records ?? [], sessionId }));
6639
+ }
6640
+ }, [state2, sessionId]);
6641
+ return h20(import_react25.default.Fragment, null, h20("span", { ref: anchor, hidden: true }), inline && h20(MediaRecords, { records: state2.records ?? [], sessionId }));
6642
+ }
6643
+ function MediaToolView({ block, phase }) {
6644
+ if (block?.isError) return h20("p", { className: "dgui-tool-error", role: "alert" }, (block.content ?? []).filter((c) => c.type === "text").map((c) => c.text).join("\n"));
6645
+ return h20("p", { className: "dgui-pending", role: "status" }, phase === "preparing" || phase === "start" || typeof block?.argsRaw === "string" ? "\u6B63\u5728\u5236\u4F5C\u89C6\u9891\u2026" : "\u89C6\u9891\u5DF2\u751F\u6210\uFF0C\u53EF\u5728\u5BF9\u8BDD\u4E2D\u64AD\u653E\u3002");
6646
+ }
6647
+ var MEDIA_PLAYER_CSS = `
6648
+ .motion-video-player{position:relative;min-width:0;width:100%;margin:16px 0;border:1px solid #34363d;border-radius:22px;overflow:hidden;background:#101114;color:#f5f6f8;box-shadow:0 10px 26px -20px #0009;color-scheme:dark}
6649
+ .motion-video-player video{display:block;width:100%;max-height:72vh;aspect-ratio:16/9;object-fit:contain;background:#000;cursor:pointer}.motion-video-player video:focus-visible{outline:2px solid #a7c4ff;outline-offset:-3px}
6650
+ .motion-video-controls{display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:10px 14px 12px}.motion-video-controls .motion-video-seek{flex:0 0 100%;width:100%;margin:0;height:18px}.motion-video-controls input[type=range]{accent-color:#b7d0ff;cursor:pointer;min-width:0}.motion-video-controls input:disabled{cursor:default;opacity:.5}
6651
+ .motion-video-controls button,.motion-video-controls a,.motion-video-controls select{display:inline-flex;align-items:center;justify-content:center;flex:none;min-width:34px;min-height:34px;border:1px solid transparent;border-radius:10px;padding:6px;background:transparent;color:inherit;text-decoration:none;font:inherit;cursor:pointer}.motion-video-controls select{background:#24262d;padding:5px 7px;font-size:13px}.motion-video-controls button:hover,.motion-video-controls a:hover{background:#292c34}.motion-video-controls :focus-visible,.motion-video-message button:focus-visible{outline:2px solid #b7d0ff;outline-offset:2px}.motion-video-controls button:disabled{opacity:.4;cursor:default}
6652
+ .motion-video-time{font:12px ui-monospace,Consolas,monospace;white-space:nowrap;font-variant-numeric:tabular-nums;margin-right:auto}.motion-video-volume{display:flex;align-items:center;gap:4px}.motion-video-volume input{width:86px}.motion-video-controls a.motion-video-source{font-size:13px;padding-inline:8px}.motion-video-message{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin:0;padding:10px 16px;font-size:14px}.motion-video-message button{border:1px solid #73798a;background:#24262d;color:inherit;border-radius:10px;padding:6px 10px;cursor:pointer}
6653
+ .motion-video-player:fullscreen{display:flex;flex-direction:column;justify-content:center;width:100%;height:100%;border:0;border-radius:0;background:#000}.motion-video-player:fullscreen video{flex:1;min-height:0;max-height:none;aspect-ratio:auto;object-fit:contain}.motion-video-player:fullscreen .motion-video-controls{flex-shrink:0;background:#101114}
6654
+ @media(max-width:600px){.motion-video-controls{gap:6px;padding:8px 10px}.motion-video-volume input{width:62px}.motion-video-time{font-size:11px}.motion-video-player{border-radius:18px}.motion-video-controls button,.motion-video-controls a{min-width:32px;min-height:32px}}
6655
+ @media(forced-colors:active){.motion-video-player{border:1px solid CanvasText}.motion-video-controls button,.motion-video-controls a,.motion-video-controls select{border:1px solid ButtonText}.motion-video-controls input[type=range]{appearance:auto}}
6656
+ `;
6657
+
6227
6658
  // src/client.jsx
6228
6659
  var inject = ["slots", "sessions", "conversation", "uiConversation", "configForms"];
6229
6660
  function apply(ctx) {
@@ -6231,10 +6662,13 @@ function apply(ctx) {
6231
6662
  console.info("[motion-ui] client active; channel=conversation-events/fence-dom");
6232
6663
  const scope2 = ctx.configForms.get("motion-ui");
6233
6664
  configureViewSettings(scope2);
6234
- ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react24.default.createElement(ModeSettings, { ...props, scope: scope2 })));
6665
+ ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react26.default.createElement(ModeSettings, { ...props, scope: scope2 })));
6235
6666
  ctx.uiConversation.events.register(turnUiDefinition);
6236
6667
  ctx.uiConversation.events.register(streamUiDefinition);
6237
6668
  ctx.uiConversation.events.register(fenceUiDefinition);
6669
+ ctx.uiConversation.events.register(mediaHistoryDefinition);
6670
+ ctx.effect(() => disposeMediaSurfaces);
6671
+ ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({ name: "conversation.chat.node", key: "dshMotionMedia" }, MediaNodeView));
6238
6672
  ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({ name: "conversation.chat.node", key: "dshUiFences", inject: (sessionId) => ({ sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) }) }, FenceNodeView));
6239
6673
  ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({ name: "conversation.chat.node", key: "dshUiStream" }, StreamNodeView));
6240
6674
  ctx.slots.inject("conversation.chat.turnTail", () => ctx.slots.register({
@@ -6245,10 +6679,11 @@ function apply(ctx) {
6245
6679
  ctx.effect(() => {
6246
6680
  const style = document.createElement("style");
6247
6681
  style.dataset.plugin = "dsh-generative-ui";
6248
- style.textContent = CSS2 + VISUAL_CSS;
6682
+ style.textContent = CSS2 + VISUAL_CSS + MEDIA_PLAYER_CSS;
6249
6683
  document.head.append(style);
6250
6684
  return () => style.remove();
6251
6685
  });
6686
+ for (const name of ["render_video", "process_video"]) ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({ name: "tool.call.toolview", key: name }, MediaToolView));
6252
6687
  for (const name of ["render_ui", "render_canvas", "render_text", "render_mechanism", "render_scene"]) ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
6253
6688
  name: "tool.call.toolview",
6254
6689
  key: name,