dsh-motion-ui 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -72,7 +72,7 @@ function Icon({ name = "info", className = "" }) {
72
72
 
73
73
  // src/expressive-controls.js
74
74
  var h2 = import_react2.default.createElement;
75
- function ExpressiveAction({ tag = "button", text: text2, icon = "arrow", ...props }) {
75
+ function ExpressiveAction({ tag = "button", text: text3, icon = "arrow", ...props }) {
76
76
  const ref = (0, import_react2.useRef)(null);
77
77
  function move(e) {
78
78
  if (matchMedia("(prefers-reduced-motion: reduce)").matches || props.disabled) return;
@@ -84,7 +84,7 @@ function ExpressiveAction({ tag = "button", text: text2, icon = "arrow", ...prop
84
84
  e.currentTarget.style.setProperty("--du-mx", "0px");
85
85
  e.currentTarget.style.setProperty("--du-my", "0px");
86
86
  }
87
- return h2(tag, { ...props, ref, "aria-label": text2, className: (props.className ?? "") + " dgui-expressive-action", onPointerMove: move, onPointerLeave: leave }, h2("span", { className: "dgui-action-fill", "aria-hidden": true }), h2("span", { className: "dgui-action-label", "aria-hidden": true }, h2("span", null, text2), h2("span", null, text2)), h2("span", { className: "dgui-action-orb", "aria-hidden": true }, h2(Icon, { name: icon })));
87
+ return h2(tag, { ...props, ref, "aria-label": text3, className: (props.className ?? "") + " dgui-expressive-action", onPointerMove: move, onPointerLeave: leave }, h2("span", { className: "dgui-action-fill", "aria-hidden": true }), h2("span", { className: "dgui-action-label", "aria-hidden": true }, h2("span", null, text3), h2("span", null, text3)), h2("span", { className: "dgui-action-orb", "aria-hidden": true }, h2(Icon, { name: icon })));
88
88
  }
89
89
  function ElasticToggle({ id: id2, checked, disabled, onChange }) {
90
90
  const [stretch, setStretch] = (0, import_react2.useState)(false), timer = (0, import_react2.useRef)(), drag = (0, import_react2.useRef)(null), skip = (0, import_react2.useRef)(false);
@@ -226,12 +226,27 @@ var MECHANISM_RUNTIME = 'var __MotionMechanism=(()=>{var it=Object.definePropert
226
226
  // lib/visual-audit.js
227
227
  function measureVisual(root2, nodeId = "") {
228
228
  const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };
229
+ const styleCache = /* @__PURE__ */ new WeakMap(), styleOf = (el2) => {
230
+ let css = styleCache.get(el2);
231
+ if (!css) {
232
+ css = getComputedStyle(el2);
233
+ styleCache.set(el2, css);
234
+ }
235
+ return css;
236
+ };
237
+ const target = (el2) => {
238
+ if (!el2) return void 0;
239
+ const tag = el2.tagName.toLowerCase(), id2 = el2.id;
240
+ return { selector: id2 && id2.length <= 64 ? "#" + CSS.escape(id2) : tag, text: (el2.textContent ?? "").trim().replace(/\s+/g, " ").slice(0, 120), tag };
241
+ };
229
242
  const add2 = (code, value, el2) => {
243
+ if (issues.length >= 40) return;
230
244
  const id2 = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;
231
- const k2 = id2 + ":" + code + ":" + Math.round(value ?? 0);
245
+ const location2 = target(el2);
246
+ const k2 = id2 + ":" + code + ":" + (location2?.selector ?? "") + ":" + (location2?.text ?? "") + ":" + Math.round(value ?? 0);
232
247
  if (!seen.has(k2) && issues.length < 40) {
233
248
  seen.add(k2);
234
- issues.push({ code, nodeId: id2, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });
249
+ issues.push({ code, nodeId: id2, ...location2 ? { target: location2 } : {}, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });
235
250
  }
236
251
  };
237
252
  const color = (s) => {
@@ -248,6 +263,25 @@ function measureVisual(root2, nodeId = "") {
248
263
  return null;
249
264
  };
250
265
  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);
266
+ const blend = (front, back) => front.slice(0, 3).map((v2, i) => v2 * front[3] + back[i] * (1 - front[3])).concat(1);
267
+ const background = (el2) => {
268
+ const layers = [];
269
+ let n2 = el2;
270
+ for (let i = 0; n2 && i < 64; i++, n2 = n2.parentElement) {
271
+ const c = styleOf(n2);
272
+ if (c.backgroundImage !== "none") return null;
273
+ const colorValue = color(c.backgroundColor);
274
+ if (!colorValue) return null;
275
+ if (colorValue[3] > 0) layers.push(colorValue);
276
+ if (colorValue[3] === 1) {
277
+ let out = layers.pop();
278
+ while (layers.length) out = blend(layers.pop(), out);
279
+ return out;
280
+ }
281
+ }
282
+ return null;
283
+ };
284
+ let contentBottom = root2.getBoundingClientRect().top;
251
285
  const widthRoot = root2.id === "canvas" ? document.documentElement : root2;
252
286
  if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add2("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);
253
287
  const walker = document.createTreeWalker(root2, NodeFilter.SHOW_ELEMENT);
@@ -259,37 +293,49 @@ function measureVisual(root2, nodeId = "") {
259
293
  }
260
294
  coverage.elements++;
261
295
  if (el.matches("[data-canvas-phase=error]")) add2("runtimeError", void 0, el);
262
- const css = getComputedStyle(el), box2 = el.getBoundingClientRect();
296
+ const css = styleOf(el), box2 = el.getBoundingClientRect();
263
297
  if (!box2.width || !box2.height || css.visibility === "hidden" || css.display === "none") continue;
264
- const text2 = [...el.childNodes].some((n2) => n2.nodeType === 3 && n2.textContent.trim());
265
- if (text2) {
298
+ const text3 = [...el.childNodes].some((n2) => n2.nodeType === 3 && n2.textContent.trim());
299
+ if (text3) {
266
300
  let size = parseFloat(css.fontSize);
267
301
  if (el instanceof SVGElement && el.getScreenCTM) {
268
302
  const m2 = el.getScreenCTM();
269
303
  if (m2) size *= Math.hypot(m2.c, m2.d);
270
304
  }
271
305
  if (size < 11.9) add2("smallText", size, el);
272
- const fg = color(css.color);
273
- let ancestor = el, bg = null, depth = 0;
274
- while (ancestor && depth++ < 64) {
275
- const style = getComputedStyle(ancestor);
276
- if (style.backgroundImage !== "none") break;
277
- const c = color(style.backgroundColor);
278
- if (c?.[3] === 1) {
279
- bg = c;
280
- break;
306
+ if (!(el instanceof SVGElement)) {
307
+ const fg = color(css.color), bg = background(el);
308
+ let opacitySafe = true, opacityDepth = 0;
309
+ for (let a2 = el; a2; a2 = a2.parentElement) {
310
+ if (++opacityDepth > 64 || parseFloat(styleOf(a2).opacity) < 1) {
311
+ opacitySafe = false;
312
+ break;
313
+ }
314
+ }
315
+ if (fg && bg && opacitySafe) {
316
+ coverage.contrastChecked++;
317
+ const a2 = luminance(blend(fg, bg)), b2 = luminance(bg), ratio = (Math.max(a2, b2) + 0.05) / (Math.min(a2, b2) + 0.05);
318
+ if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add2("contrast", ratio, el);
319
+ } else coverage.contrastUncovered++;
320
+ const range = document.createRange();
321
+ range.selectNodeContents(el);
322
+ const bounds = range.getBoundingClientRect();
323
+ let a = el, depth = 0;
324
+ while (a && a !== root2.parentElement && depth++ < 24) {
325
+ const c = styleOf(a), clip = a.getBoundingClientRect();
326
+ 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)) {
327
+ add2("clippedText", void 0, el);
328
+ break;
329
+ }
330
+ a = a.parentElement;
281
331
  }
282
- if (c?.[3] > 0) break;
283
- ancestor = ancestor.parentElement;
284
- }
285
- if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {
286
- coverage.contrastChecked++;
287
- const a = luminance(fg), b2 = luminance(bg), ratio = (Math.max(a, b2) + 0.05) / (Math.min(a, b2) + 0.05);
288
- if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add2("contrast", ratio, el);
289
332
  } else coverage.contrastUncovered++;
290
333
  }
334
+ if (text3 || el.matches("svg,canvas,img,video,input,select,textarea,button")) contentBottom = Math.max(contentBottom, box2.bottom);
291
335
  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")) add2("missingLabel", void 0, el);
292
336
  }
337
+ const rect = root2.getBoundingClientRect(), gap = rect.bottom - contentBottom;
338
+ if (!coverage.truncated && root2.id === "canvas" && rect.height > 320 && gap > Math.max(96, rect.height * 0.25)) add2("bottomWhitespace", gap, root2);
293
339
  Object.defineProperty(issues, "coverage", { value: coverage });
294
340
  return issues;
295
341
  }
@@ -315,9 +361,9 @@ svg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);s
315
361
 
316
362
  // lib/sandbox.js
317
363
  var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });
318
- function canvasSnapshot(node, state, data, derived, disabled, theme) {
364
+ function canvasSnapshot(node, state2, data, derived, disabled, theme) {
319
365
  const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k2) => [k2, values[k2]]));
320
- return { state: pick(node.stateKeys, state), data: pick(node.dataKeys, data), derived: pick(node.derivedKeys, derived), disabled, theme };
366
+ return { state: pick(node.stateKeys, state2), data: pick(node.dataKeys, data), derived: pick(node.derivedKeys, derived), disabled, theme };
321
367
  }
322
368
  function canvasPatch(message, node) {
323
369
  if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");
@@ -364,7 +410,7 @@ function sandboxDocument(node, channel, nonce) {
364
410
  }
365
411
 
366
412
  // lib/components.js
367
- var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });
413
+ var define = (fields3, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields3), purpose, presentation });
368
414
  var COMPONENTS = Object.freeze({
369
415
  visual: define(["spec", "stateKey", "warnings"], "Extended native charts, tables, plots, quiz, forms, diagrams, media and 3D"),
370
416
  heading: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "Section heading", "tone"),
@@ -402,10 +448,10 @@ var validIdentifier = (value) => typeof value === "string" && pattern.test(value
402
448
 
403
449
  // lib/author-expression.js
404
450
  function compileExpression(source) {
405
- const fail3 = () => {
451
+ const fail4 = () => {
406
452
  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");
407
453
  };
408
- if (typeof source !== "string" || !source.trim() || source.length > 2048) fail3();
454
+ if (typeof source !== "string" || !source.trim() || source.length > 2048) fail4();
409
455
  const tokens = [];
410
456
  let offset = 0;
411
457
  const token = new RegExp(String.raw`\s*(?:(\d+(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?|("(?:[^"\\]|\\.)*")|(${IDENTIFIER_SOURCE}(?:\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");
@@ -413,18 +459,18 @@ function compileExpression(source) {
413
459
  if (!source.slice(offset).trim()) break;
414
460
  token.lastIndex = offset;
415
461
  const m2 = token.exec(source);
416
- if (!m2) fail3();
462
+ if (!m2) fail4();
417
463
  offset = token.lastIndex;
418
464
  tokens.push(m2[1] ? { number: Number(m2[1] + (m2[2] ?? "")) } : m2[3] ? { string: JSON.parse(m2[3]) } : m2[4] ?? m2[5]);
419
- if (tokens.length > 256) fail3();
465
+ if (tokens.length > 256) fail4();
420
466
  }
421
467
  let pos = 0;
422
468
  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] };
423
469
  const take = (t) => {
424
- if (tokens[pos++] !== t) fail3();
470
+ if (tokens[pos++] !== t) fail4();
425
471
  };
426
472
  function parse(min = 0, depth = 0) {
427
- if (depth > 12) fail3();
473
+ if (depth > 12) fail4();
428
474
  const t = tokens[pos++];
429
475
  let out;
430
476
  if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };
@@ -442,11 +488,11 @@ function compileExpression(source) {
442
488
  while (tokens[pos] === ",") {
443
489
  pos++;
444
490
  args.push(parse(0, depth + 1));
445
- if (args.length > 8) fail3();
491
+ if (args.length > 8) fail4();
446
492
  }
447
493
  take(")");
448
494
  out = { op: t, args };
449
- } else fail3();
495
+ } else fail4();
450
496
  while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {
451
497
  const [op, precedence] = operators[tokens[pos++]];
452
498
  out = { op, args: [out, parse(precedence + 1, depth + 1)] };
@@ -460,28 +506,34 @@ function compileExpression(source) {
460
506
  return out;
461
507
  }
462
508
  const result = parse();
463
- if (pos !== tokens.length) fail3();
509
+ if (pos !== tokens.length) fail4();
464
510
  return result;
465
511
  }
466
512
  function expandExpressions(doc) {
467
- const expression2 = (e) => {
513
+ const expression2 = (e, at2) => {
468
514
  if (!e || typeof e !== "object" || Array.isArray(e)) return e;
469
515
  if (Object.hasOwn(e, "expr")) {
470
516
  if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");
471
- return compileExpression(e.expr);
517
+ try {
518
+ return compileExpression(e.expr);
519
+ } catch (error) {
520
+ error.message = "DSH UI: " + at2 + ": " + error.message.replace(/^DSH UI: /, "");
521
+ error.path = at2;
522
+ throw error;
523
+ }
472
524
  }
473
- if (Array.isArray(e.args)) e.args = e.args.map(expression2);
474
- if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2]);
525
+ if (Array.isArray(e.args)) e.args = e.args.map((v2, i) => expression2(v2, at2 + ".args[" + i + "]"));
526
+ 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);
475
527
  return e;
476
528
  };
477
- if (doc.derived && typeof doc.derived === "object") for (const k2 of Object.keys(doc.derived)) doc.derived[k2] = expression2(doc.derived[k2]);
529
+ if (doc.derived && typeof doc.derived === "object") for (const k2 of Object.keys(doc.derived)) doc.derived[k2] = expression2(doc.derived[k2], "derived." + k2);
478
530
  const walk = (nodes) => {
479
531
  if (!Array.isArray(nodes)) return;
480
532
  for (const node of nodes) {
481
533
  if (!node || typeof node !== "object") continue;
482
- for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node, field)) node[field] = expression2(node[field]);
534
+ for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node, field)) node[field] = expression2(node[field], "node." + node.id + "." + field);
483
535
  if (["table", "chart"].includes(node.type) && Array.isArray(node.rows)) {
484
- for (const row of node.rows) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2]);
536
+ for (const [rowIndex, row] of node.rows.entries()) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2], "node." + node.id + ".rows[" + rowIndex + "]." + k2);
485
537
  }
486
538
  walk(node.children);
487
539
  }
@@ -2326,6 +2378,10 @@ function number(v2) {
2326
2378
  var boolean = (v2) => v2 === "true" ? true : v2 === "false" ? false : v2;
2327
2379
  function expression(e, numeric = false, logical = false) {
2328
2380
  if (!object(e)) return e;
2381
+ if (Object.keys(e).length === 1 && own(e, "expr") && typeof e.expr === "number" && Number.isFinite(e.expr)) {
2382
+ e.const = e.expr;
2383
+ delete e.expr;
2384
+ }
2329
2385
  if (own(e, "const")) {
2330
2386
  if (numeric) e.const = number(e.const);
2331
2387
  if (logical) e.const = boolean(e.const);
@@ -2340,6 +2396,10 @@ function normalizeAuthoring(doc) {
2340
2396
  if (object(doc) && !own(doc, "nodes") && (own(doc, "items") || typeof doc.type === "string")) doc = visualDocument(doc);
2341
2397
  if (!object(doc)) return doc;
2342
2398
  if (own(doc, "version")) doc.version = number(doc.version);
2399
+ if (object(doc.presentation) && doc.presentation.layout === "flow" && (!own(doc.presentation, "preset") || doc.presentation.preset === "flow")) {
2400
+ doc.presentation.layout = "guide";
2401
+ doc.presentation.preset = "flow";
2402
+ }
2343
2403
  if (object(doc.state)) for (const k2 of Object.keys(doc.state)) {
2344
2404
  let s = doc.state[k2];
2345
2405
  if (typeof s === "string" && s.trim().startsWith("{")) {
@@ -2370,6 +2430,13 @@ function normalizeAuthoring(doc) {
2370
2430
  if (!Array.isArray(list)) return list;
2371
2431
  for (const node of list) {
2372
2432
  if (!object(node)) continue;
2433
+ if (node.type === "code" && (node.copyable === true || node.copyable === "true")) delete node.copyable;
2434
+ if (["slider", "input"].includes(node.type) && typeof node.bind === "string" && node.bind.startsWith("state.")) {
2435
+ const spec = doc.state?.[node.bind.slice(6)];
2436
+ if (spec?.type === "number") {
2437
+ for (const field of ["min", "max", "step"]) if (own(node, field) && number(node[field]) === spec[field]) delete node[field];
2438
+ }
2439
+ }
2373
2440
  if (["text", "heading", "callout"].includes(node.type) && own(node, "content")) {
2374
2441
  if (!own(node, "text")) {
2375
2442
  node.text = node.content;
@@ -2430,6 +2497,9 @@ function normalizeAuthoring(doc) {
2430
2497
  if (node.type === "details" && own(node, "open")) node.open = boolean(node.open);
2431
2498
  if (node.type === "text" && own(node, "copyable")) node.copyable = boolean(node.copyable);
2432
2499
  if (node.type === "code" && own(node, "wrap")) node.wrap = boolean(node.wrap);
2500
+ if (["table", "chart"].includes(node.type) && Array.isArray(node.rows)) {
2501
+ for (const row of node.rows) if (object(row)) for (const cell of Object.values(row)) expression(cell);
2502
+ }
2433
2503
  for (const field of ["text", "value", "max", "rows"]) if (own(node, field)) expression(node[field], node.type === "progress");
2434
2504
  if (["row", "column", "card", "details"].includes(node.type) && own(node, "children")) node.children = nodes(node.children);
2435
2505
  }
@@ -2445,14 +2515,14 @@ var TYPE_FIELDS = Object.freeze(["size", "weight", "color", "align", "lineHeight
2445
2515
  var TEXT_SIZES = Object.freeze({ sm: 14, md: 16, lg: 20, xl: 26, hero: 36 });
2446
2516
  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)" });
2447
2517
  function validateTypography(value, at2 = "text") {
2448
- const fail3 = (message) => {
2518
+ const fail4 = (message) => {
2449
2519
  throw Error(`DSH UI: ${at2}.${message}`);
2450
2520
  };
2451
- 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)) fail3("size must be 12..48 px or sm/md/lg/xl/hero");
2452
- if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail3("weight must be 400/500/600/700/800");
2453
- 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))) fail3("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");
2454
- if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail3("align must be left/center/right");
2455
- if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail3("lineHeight must be 1.2..2.4");
2521
+ 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)) fail4("size must be 12..48 px or sm/md/lg/xl/hero");
2522
+ if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail4("weight must be 400/500/600/700/800");
2523
+ 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))) fail4("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");
2524
+ if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail4("align must be left/center/right");
2525
+ if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail4("lineHeight must be 1.2..2.4");
2456
2526
  }
2457
2527
  function typographyStyle(value) {
2458
2528
  return { fontSize: value.size === void 0 ? void 0 : TEXT_SIZES[value.size] ?? value.size, fontWeight: value.weight, color: value.color === void 0 ? void 0 : TEXT_COLORS[value.color] ?? value.color, textAlign: value.align, lineHeight: value.lineHeight };
@@ -2460,23 +2530,23 @@ function typographyStyle(value) {
2460
2530
 
2461
2531
  // lib/links.js
2462
2532
  function validateLink(node) {
2463
- const fail3 = (message) => {
2533
+ const fail4 = (message) => {
2464
2534
  throw Error("DSH UI: " + message);
2465
2535
  };
2466
- if ([node.href, node.path, node.action].filter((v2) => v2 !== void 0).length !== 1) fail3(`node.${node.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);
2467
- if (node.variant !== void 0 && !["primary", "secondary", "text"].includes(node.variant)) fail3("link/button variant must be primary/secondary/text");
2536
+ if ([node.href, node.path, node.action].filter((v2) => v2 !== void 0).length !== 1) fail4(`node.${node.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);
2537
+ if (node.variant !== void 0 && !["primary", "secondary", "text"].includes(node.variant)) fail4("link/button variant must be primary/secondary/text");
2468
2538
  if (node.href !== void 0) {
2469
- if (typeof node.href !== "string" || node.href.length > 8192 || /[\u0000-\u0020\u007f]/.test(node.href) || !/^https?:\/\//i.test(node.href)) fail3("href must be an absolute http/https URL; encode spaces");
2539
+ if (typeof node.href !== "string" || node.href.length > 8192 || /[\u0000-\u0020\u007f]/.test(node.href) || !/^https?:\/\//i.test(node.href)) fail4("href must be an absolute http/https URL; encode spaces");
2470
2540
  let url;
2471
2541
  try {
2472
2542
  url = new URL(node.href);
2473
2543
  } catch {
2474
- fail3("invalid href URL");
2544
+ fail4("invalid href URL");
2475
2545
  }
2476
- if (!url.hostname || url.username || url.password) fail3("href must have a host and must not contain credentials");
2546
+ if (!url.hostname || url.username || url.password) fail4("href must have a host and must not contain credentials");
2477
2547
  }
2478
2548
  if (node.path !== void 0) {
2479
- if (typeof node.path !== "string" || !node.path.trim() || node.path.length > 8192 || /[\u0000-\u001f\u007f]/.test(node.path) || /^\s*(?:[a-z][a-z\d+.-]*:|[\\/]{2})/i.test(node.path) && !/^\s*[a-z]:[\\/]/i.test(node.path)) fail3("path must be a local file path, not a URL, network path or command");
2549
+ if (typeof node.path !== "string" || !node.path.trim() || node.path.length > 8192 || /[\u0000-\u001f\u007f]/.test(node.path) || /^\s*(?:[a-z][a-z\d+.-]*:|[\\/]{2})/i.test(node.path) && !/^\s*[a-z]:[\\/]/i.test(node.path)) fail4("path must be a local file path, not a URL, network path or command");
2480
2550
  }
2481
2551
  }
2482
2552
 
@@ -2523,12 +2593,12 @@ function safeJson(value, depth = 0, source = false) {
2523
2593
  function initialState(doc) {
2524
2594
  return Object.fromEntries(Object.entries(doc.state).map(([k2, spec]) => [k2, spec.default]));
2525
2595
  }
2526
- function validateState(doc, state) {
2527
- if (!object2(state) || Object.keys(state).length !== Object.keys(doc.state).length) fail("state keys do not match the document");
2596
+ function validateState(doc, state2) {
2597
+ if (!object2(state2) || Object.keys(state2).length !== Object.keys(doc.state).length) fail("state keys do not match the document");
2528
2598
  const result = {};
2529
2599
  for (const [k2, s] of Object.entries(doc.state)) {
2530
- if (!own2(state, k2)) fail(`missing state.${k2}`);
2531
- const v2 = state[k2];
2600
+ if (!own2(state2, k2)) fail(`missing state.${k2}`);
2601
+ const v2 = state2[k2];
2532
2602
  if (s.type === "number") {
2533
2603
  if (!finite(v2) || v2 < s.min || v2 > s.max) fail(`state.${k2} is outside its numeric range`);
2534
2604
  const offset = (v2 - s.min) / s.step;
@@ -2551,7 +2621,7 @@ function reference(doc, ref) {
2551
2621
  if (!own2(doc[group], k2)) fail(`unknown reference ${ref}`);
2552
2622
  return [group, k2];
2553
2623
  }
2554
- function evaluate(doc, state) {
2624
+ function evaluate(doc, state2) {
2555
2625
  const derived = {}, active = /* @__PURE__ */ new Set();
2556
2626
  let steps = 0, generatedRows = 0;
2557
2627
  const budget = () => {
@@ -2560,7 +2630,7 @@ function evaluate(doc, state) {
2560
2630
  const resolve = (ref) => {
2561
2631
  budget();
2562
2632
  const [group, k2] = reference(doc, ref);
2563
- if (group !== "derived") return (group === "state" ? state : doc.data)[k2];
2633
+ if (group !== "derived") return (group === "state" ? state2 : doc.data)[k2];
2564
2634
  if (own2(derived, k2)) return derived[k2];
2565
2635
  if (active.has(k2)) fail(`cyclic calculation ${k2}`);
2566
2636
  active.add(k2);
@@ -2792,7 +2862,7 @@ function validateDocument(input) {
2792
2862
  const value = (v2, at2) => {
2793
2863
  if (object2(v2)) {
2794
2864
  if (own2(v2, "map")) fail("map belongs in derived");
2795
- validateExpression(v2);
2865
+ validateExpression(v2, 0, void 0, at2);
2796
2866
  } else if (!scalar(v2)) fail(`invalid value at ${at2}`);
2797
2867
  };
2798
2868
  function nodes(list, depth = 0, path2 = "nodes") {
@@ -2924,7 +2994,7 @@ function validateDocument(input) {
2924
2994
  break;
2925
2995
  case "table": {
2926
2996
  if (n2.label !== void 0) text(n2.label, "table label");
2927
- if (!Array.isArray(n2.rows)) value(n2.rows, "table rows");
2997
+ if (!Array.isArray(n2.rows)) value(n2.rows, "node." + n2.id + ".rows");
2928
2998
  if (!Array.isArray(n2.columns) || !n2.columns.length || n2.columns.length > 16) fail("invalid table columns");
2929
2999
  const cols = /* @__PURE__ */ new Set();
2930
3000
  for (const c of n2.columns) {
@@ -2937,7 +3007,8 @@ function validateDocument(input) {
2937
3007
  break;
2938
3008
  }
2939
3009
  case "chart":
2940
- if (!Array.isArray(n2.rows)) value(n2.rows, "chart rows");
3010
+ if (n2.rows === void 0) fail("node." + n2.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');
3011
+ if (!Array.isArray(n2.rows)) value(n2.rows, "node." + n2.id + ".rows");
2941
3012
  if (!["bar", "line"].includes(n2.kind) || !validIdentifier(n2.labelKey) || !validIdentifier(n2.valueKey)) fail("invalid chart");
2942
3013
  text(n2.label, "chart label");
2943
3014
  if (n2.unit !== void 0) text(n2.unit, "chart unit");
@@ -2966,8 +3037,8 @@ function validateDocument(input) {
2966
3037
  evaluate(doc, defaults);
2967
3038
  return doc;
2968
3039
  }
2969
- function followupPrompt(doc, state, actionKey, provenance) {
2970
- const values = validateState(doc, state), action = doc.actions[actionKey];
3040
+ function followupPrompt(doc, state2, actionKey, provenance) {
3041
+ const values = validateState(doc, state2), action = doc.actions[actionKey];
2971
3042
  if (!action) fail("unknown follow-up action");
2972
3043
  const selected = Object.fromEntries(action.stateKeys.map((k2) => [k2, values[k2]]));
2973
3044
  const { derived } = evaluate(doc, values);
@@ -3050,12 +3121,12 @@ async function request(url, options) {
3050
3121
  function useSavedState(record, sessionId, preview = false) {
3051
3122
  const doc = record.document;
3052
3123
  const schemaKey = JSON.stringify(doc.state);
3053
- const [state, setState] = (0, import_react4.useState)(() => initialState(doc));
3124
+ const [state2, setState] = (0, import_react4.useState)(() => initialState(doc));
3054
3125
  const [ready, setReady] = (0, import_react4.useState)(false), [status, setStatus] = (0, import_react4.useState)("\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026");
3055
3126
  const [issue, setIssue] = (0, import_react4.useState)(null), [epoch, setEpoch] = (0, import_react4.useState)(0), [tick, wake] = (0, import_react4.useState)(0);
3056
3127
  const refs = (0, import_react4.useRef)({ revision: 0, saved: "", saving: false, blocked: true, alive: true, generation: 0, loading: false });
3057
- const liveState = (0, import_react4.useRef)(state);
3058
- liveState.current = state;
3128
+ const liveState = (0, import_react4.useRef)(state2);
3129
+ liveState.current = state2;
3059
3130
  const receive = (0, import_react4.useRef)(null);
3060
3131
  (0, import_react4.useEffect)(() => {
3061
3132
  if (preview) return;
@@ -3131,7 +3202,7 @@ function useSavedState(record, sessionId, preview = false) {
3131
3202
  };
3132
3203
  }, [record.documentId, sessionId, schemaKey, preview]);
3133
3204
  (0, import_react4.useEffect)(() => {
3134
- const r = refs.current, signature = JSON.stringify(state);
3205
+ const r = refs.current, signature = JSON.stringify(state2);
3135
3206
  if (!ready || r.blocked || r.saving) return;
3136
3207
  if (signature === r.saved) {
3137
3208
  setStatus((previous) => /等待保存|准备保存/.test(previous) ? "\u53C2\u6570\u5DF2\u4FDD\u5B58" : previous);
@@ -3143,7 +3214,7 @@ function useSavedState(record, sessionId, preview = false) {
3143
3214
  if (r.alive) setStatus("\u6B63\u5728\u4FDD\u5B58\u53C2\u6570\u2026");
3144
3215
  const revision2 = r.revision;
3145
3216
  try {
3146
- const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision: revision2, state }) }));
3217
+ const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision: revision2, state: state2 }) }));
3147
3218
  if (saved.revision !== revision2 + 1 || JSON.stringify(saved.state) !== signature) throw new Error("Unexpected save response");
3148
3219
  r.revision = saved.revision;
3149
3220
  r.saved = signature;
@@ -3164,7 +3235,7 @@ function useSavedState(record, sessionId, preview = false) {
3164
3235
  }
3165
3236
  }, 350);
3166
3237
  return () => clearTimeout(timer);
3167
- }, [state, ready, tick, record.documentId, sessionId]);
3238
+ }, [state2, ready, tick, record.documentId, sessionId]);
3168
3239
  function retry() {
3169
3240
  const r = refs.current;
3170
3241
  if (r.loading || r.saving) return;
@@ -3178,7 +3249,7 @@ function useSavedState(record, sessionId, preview = false) {
3178
3249
  setStatus("\u53C2\u6570\u5DF2\u4FEE\u6539\uFF0C\u7B49\u5F85\u4FDD\u5B58\u2026");
3179
3250
  wake((n2) => n2 + 1);
3180
3251
  }
3181
- return { state: preview ? initialState(doc) : state, setState, ready: !preview && ready, status: preview ? "\u751F\u6210\u9884\u89C8 \xB7 \u5B8C\u6210\u6821\u9A8C\u540E\u53EF\u64CD\u4F5C" : status, issue, epoch, retry, useRemote: () => load(), keepLocal: () => load(true) };
3252
+ return { state: preview ? initialState(doc) : state2, setState, ready: !preview && ready, status: preview ? "\u751F\u6210\u9884\u89C8 \xB7 \u5B8C\u6210\u6821\u9A8C\u540E\u53EF\u64CD\u4F5C" : status, issue, epoch, retry, useRemote: () => load(), keepLocal: () => load(true) };
3182
3253
  }
3183
3254
 
3184
3255
  // lib/tool-json.js
@@ -3498,13 +3569,13 @@ function CanvasPreview({ node }) {
3498
3569
  var import_react8 = __toESM(require("react"), 1);
3499
3570
 
3500
3571
  // lib/export-runtime-bundle.js
3501
- 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 add = (code, value, el2) => {\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const k2 = id + ":" + code + ":" + Math.round(value ?? 0);\n if (!seen.has(k2) && issues.length < 40) {\n seen.add(k2);\n issues.push({ code, nodeId: id, ...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 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 = getComputedStyle(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 const fg = color(css.color);\n let ancestor = el, bg = null, depth = 0;\n while (ancestor && depth++ < 64) {\n const style = getComputedStyle(ancestor);\n if (style.backgroundImage !== "none") break;\n const c = color(style.backgroundColor);\n if (c?.[3] === 1) {\n bg = c;\n break;\n }\n if (c?.[3] > 0) break;\n ancestor = ancestor.parentElement;\n }\n if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {\n coverage.contrastChecked++;\n const a = luminance(fg), b2 = luminance(bg), ratio = (Math.max(a, b2) + 0.05) / (Math.min(a, 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 }\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 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) => {\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 return compileExpression(e.expr);\n }\n if (Array.isArray(e.args)) e.args = e.args.map(expression2);\n if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.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]);\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]);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const row of node2.rows) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[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 (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.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 (["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 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);\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, "table 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 (!Array.isArray(n.rows)) value(n.rows, "chart 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';
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';
3502
3573
 
3503
3574
  // lib/canvas-export.js
3504
- function standaloneCanvas(document2, node, state, theme = {}) {
3505
- validateState(document2, state);
3575
+ function standaloneCanvas(document2, node, state2, theme = {}) {
3576
+ validateState(document2, state2);
3506
3577
  const token = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");
3507
- const json = JSON.stringify({ document: document2, nodeId: node.id, state, theme, nonce: token }).replace(/</g, "\\u003c");
3578
+ const json = JSON.stringify({ document: document2, nodeId: node.id, state: state2, theme, nonce: token }).replace(/</g, "\\u003c");
3508
3579
  const escape = (s) => String(s).replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
3509
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>`;
3510
3581
  }
@@ -3529,11 +3600,11 @@ function grammarPrompt(id2) {
3529
3600
  \u8868\u9762\u4E0E\u8FB9\u754C\uFF1A${g.surfaces}
3530
3601
  \u63A7\u4EF6\u4E0E\u53CD\u9988\uFF1A${g.controls}
3531
3602
  \u907F\u514D\uFF1A${g.avoid}
3532
- \u540C\u4E00\u4EFB\u52A1\u5728\u6B64\u98CE\u683C\u4E0B\u5E94\u5177\u6709\u53EF\u8FA8\u8BC6\u7684\u5C42\u7EA7\u4E0E\u6784\u56FE\uFF0C\u4E0D\u80FD\u53EA\u6362\u5F3A\u8C03\u8272\u3002\u6240\u6709\u98CE\u683C\u5171\u7528\u539F\u751F\u4EA4\u4E92\u80FD\u529B\uFF1B\u52A8\u753B\u53EA\u56DE\u5E94\u771F\u5B9E\u64CD\u4F5C\u3001\u652F\u6301 reduced motion\u3002\u4FDD\u6301\u5185\u5BB9\u5B8C\u6574\u548C DOM \u9605\u8BFB\u987A\u5E8F\uFF0C\u4E0D\u4E3A\u4E86\u98CE\u683C\u91CD\u6392\u8BA1\u7B97\u542B\u4E49\u3002\u7528\u6237\u660E\u786E\u6307\u5B9A\u7684\u5C3A\u5BF8\u3001\u989C\u8272\u4E0E\u5E03\u5C40\u4F18\u5148\u3002\u7981\u6B62\u73BB\u7483\u6750\u8D28\u3002\u793A\u4F8B\u6F14\u793A\u6784\u56FE\uFF0C\u4E0D\u8981\u6C42\u6BCF\u6B21\u8F93\u51FA\u6240\u6709\u6A21\u5757\uFF1B\u7B80\u5355\u9700\u6C42\u7528\u7B80\u77ED\u6B63\u6587\u6216\u4E00\u7EC4\u6570\u5B57\uFF0C\u4E0D\u80FD\u4E3A\u4E86\u5C55\u793A\u98CE\u683C\u6269\u5199\u5185\u5BB9\u3002`;
3603
+ \u540C\u4E00\u4EFB\u52A1\u5E94\u6709\u53EF\u8FA8\u8BC6\u7684\u6784\u56FE\u4E0E\u5C42\u7EA7\uFF0C\u4E0D\u80FD\u53EA\u6362\u5F3A\u8C03\u8272\u3002\u4FDD\u6301\u5185\u5BB9\u548CDOM\u9605\u8BFB\u987A\u5E8F\u3002\u539F\u751F\u4EA4\u4E92\u5171\u7528\uFF0C\u8282\u594F\u968F\u98CE\u683C\u53D8\u5316\uFF1B\u7981\u6B62\u73BB\u7483\u3002\u793A\u4F8B\u5C55\u793A\u8BED\u8A00\uFF0C\u4E0D\u8981\u6C42\u6BCF\u6B21\u4F7F\u7528\u5168\u90E8\u6A21\u5757\u3002`;
3533
3604
  }
3534
3605
  function grammarExample(id2) {
3535
3606
  const heading = { type: "heading", text: "\u5148\u4EA4\u4ED8\u4E00\u4E2A\u53EF\u7528\u7248\u672C" }, body = { type: "text", text: "\u628A\u76EE\u6807\u7F29\u5C0F\uFF0C\u628A\u5173\u952E\u4F53\u9A8C\u505A\u597D\u3002" }, note = { type: "text", text: "\u5148\u9A8C\u8BC1\uFF0C\u518D\u9010\u6B65\u5B8C\u5584\u3002", color: "muted" };
3536
- const choice = (title, text2) => ({ type: "card", title, children: [{ type: "text", text: text2 }] });
3607
+ const choice = (title, text3) => ({ type: "card", title, children: [{ type: "text", text: text3 }] });
3537
3608
  const choices = [choice("\u5148\u505A\u5C0F\u7248\u672C", "\u9A8C\u8BC1\u91CD\u70B9"), choice("\u5148\u94FA\u5168\u529F\u80FD", "\u8986\u76D6\u9700\u6C42")];
3538
3609
  const metrics = [{ type: "metric", label: "\u63A8\u8FDB\u9636\u6BB5", value: 3, unit: "\u6B65" }, { type: "metric", label: "\u6838\u5FC3\u76EE\u6807", value: 1, unit: "\u4E2A" }];
3539
3610
  const flow = { type: "steps", items: [{ title: "\u660E\u786E\u76EE\u6807", description: "\u5148\u6293\u4F4F\u91CD\u70B9\u3002" }, { title: "\u89E3\u91CA\u5173\u7CFB", description: "\u7528\u56FE\u5F62\u8BF4\u660E\u3002" }, { title: "\u7ED9\u51FA\u884C\u52A8", description: "\u6536\u6210\u4E0B\u4E00\u6B65\u3002" }] };
@@ -3745,7 +3816,7 @@ function ActionMenu({ label, children }) {
3745
3816
  // src/sandbox.js
3746
3817
  var h6 = import_react8.default.createElement;
3747
3818
  var randomToken = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");
3748
- function Sandbox({ node, document: doc, state, data, derived, disabled, preview, update, onAudit }) {
3819
+ function Sandbox({ node, document: doc, state: state2, data, derived, disabled, preview, update, onAudit }) {
3749
3820
  const showDetails = useViewDetails();
3750
3821
  const frame2 = (0, import_react8.useRef)(null), latest = (0, import_react8.useRef)(null), connected = (0, import_react8.useRef)(false), loads = (0, import_react8.useRef)(0), visible = (0, import_react8.useRef)(true), errorKind = (0, import_react8.useRef)("");
3751
3822
  const [error, setError] = (0, import_react8.useState)(""), [stopped, setStopped] = (0, import_react8.useState)(false), [generation, setGeneration] = (0, import_react8.useState)(0);
@@ -3755,7 +3826,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
3755
3826
  const sourceKey = JSON.stringify(node);
3756
3827
  const config = (0, import_react8.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
3757
3828
  const srcDoc = (0, import_react8.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
3758
- latest.current = { node, state, data, derived, disabled, update, onAudit };
3829
+ latest.current = { node, state: state2, data, derived, disabled, update, onAudit };
3759
3830
  const publish2 = () => {
3760
3831
  const el = frame2.current, current2 = latest.current;
3761
3832
  if (!el || !connected.current) return;
@@ -3841,7 +3912,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
3841
3912
  }, [config, preview, stopped]);
3842
3913
  (0, import_react8.useEffect)(() => {
3843
3914
  publish2();
3844
- }, [state, data, derived, disabled, config, token]);
3915
+ }, [state2, data, derived, disabled, config, token]);
3845
3916
  const inactive = preview || stopped;
3846
3917
  const restart = () => {
3847
3918
  setStopped(false);
@@ -3853,7 +3924,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
3853
3924
  const theme = Object.fromEntries(["bg", "ink", "muted", "accent", "line", "soft"].map((k2) => [k2, css.getPropertyValue("--du-" + k2).trim()]));
3854
3925
  theme.visualStyle = el.closest(".dgui-root")?.dataset.visualStyle ?? "";
3855
3926
  theme.scheme = document.body.hasAttribute("data-ds-dark-theme") || el.closest("[data-preview-theme=dark]") ? "dark" : "light";
3856
- const url = URL.createObjectURL(new Blob([standaloneCanvas(doc, node, state, theme)], { type: "text/html;charset=utf-8" }));
3927
+ const url = URL.createObjectURL(new Blob([standaloneCanvas(doc, node, state2, theme)], { type: "text/html;charset=utf-8" }));
3857
3928
  const link = document.createElement("a");
3858
3929
  link.href = url;
3859
3930
  link.download = (node.title.replace(/[<>:"/\\|?*\x00-\x1f]/g, "_").slice(0, 80) || "dsh-ui") + ".html";
@@ -3898,10 +3969,10 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
3898
3969
  }
3899
3970
 
3900
3971
  // lib/build-info.js
3901
- var BUILD_INFO = Object.freeze({ "version": "0.7.0", "id": "0.7.0+6adc22f63978", "sourceHash": "6adc22f639783dee4cfb7400828727748c020f09b8e912e4500dde67fc871562" });
3972
+ var BUILD_INFO = Object.freeze({ "version": "0.7.1", "id": "0.7.1+d92c9bf2bf64", "sourceHash": "d92c9bf2bf6407506977357f099a9c7935c744d97606dc631267a62be10735eb" });
3902
3973
 
3903
3974
  // lib/refinement.js
3904
- 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" });
3975
+ 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" });
3905
3976
 
3906
3977
  // src/current-document.js
3907
3978
  var import_react9 = require("react");
@@ -4243,6 +4314,104 @@ function focusUi(id2, sessionId) {
4243
4314
  notifyUi();
4244
4315
  }
4245
4316
 
4317
+ // lib/scene-entry.js
4318
+ var object3 = (v2) => v2 !== null && typeof v2 === "object" && !Array.isArray(v2);
4319
+ var fail2 = (at2, message) => {
4320
+ throw Error("DSH UI: " + at2 + " " + message);
4321
+ };
4322
+ var fields2 = (v2, allowed, at2) => {
4323
+ if (!object3(v2)) fail2(at2, "must be an object");
4324
+ for (const k2 of Object.keys(v2)) if (!allowed.includes(k2)) fail2(at2 + "." + k2, "is not supported; use " + allowed.join(", "));
4325
+ };
4326
+ var text2 = (v2, at2) => {
4327
+ if (typeof v2 !== "string" || !v2.trim() || v2.length > 8192) fail2(at2, "must be non-empty text of at most8192 characters");
4328
+ return v2;
4329
+ };
4330
+ var num = (v2, at2, min, max, integer = false) => {
4331
+ if (typeof v2 !== "number" || !Number.isFinite(v2) || v2 < min || v2 > max || integer && !Number.isInteger(v2)) fail2(at2, `must be ${integer ? "an integer" : "a number"} in ${min}..${max}; supply actual or explicitly assumed values`);
4332
+ return v2;
4333
+ };
4334
+ var metric = (id2, label, ref, unit2 = "", decimals = 0) => ({ id: id2, type: "metric", label, value: { ref: "derived." + ref }, unit: unit2, decimals });
4335
+ var state = (value, max, step = 1) => ({ type: "number", default: value, min: 0, max, step });
4336
+ var SCENE_IDS = Object.freeze(["flow", "comparison", "allocation", "budget"]);
4337
+ function sceneDocument(args = {}) {
4338
+ if (new TextEncoder().encode(JSON.stringify(args)).length > LIMITS.bytes) fail2("render_scene", "exceeds128KiB");
4339
+ fields2(args, ["scene", "title", "items", "total", "unit", "values"], "render_scene");
4340
+ if (!SCENE_IDS.includes(args.scene)) fail2("scene", "must be " + SCENE_IDS.join("/"));
4341
+ const used = { flow: ["items"], comparison: ["items"], allocation: ["items", "total", "unit"], budget: ["values"] }[args.scene];
4342
+ for (const k2 of Object.keys(args)) if (!["scene", "title", ...used].includes(k2)) fail2(k2, "does not apply to " + args.scene);
4343
+ const doc = { version: 1, title: args.title ?? { flow: "\u6B65\u9AA4\u6307\u5F15", comparison: "\u65B9\u6848\u5BF9\u6BD4", allocation: "\u65F6\u95F4\u4E0E\u6570\u91CF\u5206\u914D", budget: "\u65C5\u884C\u9884\u7B97\u4F30\u7B97" }[args.scene], fallback: "", nodes: [] };
4344
+ text2(doc.title, "title");
4345
+ if (args.scene === "flow" || args.scene === "comparison" || args.scene === "allocation") {
4346
+ const [min, max] = args.scene === "flow" ? [1, 12] : args.scene === "comparison" ? [2, 4] : [2, 8];
4347
+ if (!Array.isArray(args.items) || args.items.length < min || args.items.length > max) fail2("items", `requires a direct array of ${min}..${max} complete objects`);
4348
+ args.items.forEach((v2, i) => {
4349
+ fields2(v2, args.scene === "flow" ? ["title", "description"] : args.scene === "comparison" ? ["title", "description", "value", "unit", "points"] : ["label", "percent"], "items[" + i + "]");
4350
+ text2(v2[args.scene === "allocation" ? "label" : "title"], "items[" + i + "]." + (args.scene === "allocation" ? "label" : "title"));
4351
+ if (v2.description !== void 0) text2(v2.description, "items[" + i + "].description");
4352
+ });
4353
+ }
4354
+ if (args.scene === "flow") {
4355
+ doc.presentation = { layout: "guide", preset: "flow" };
4356
+ doc.nodes = [{ id: "steps", type: "steps", items: structuredClone(args.items) }];
4357
+ doc.fallback = args.items.map((v2, i) => i + 1 + ". " + v2.title + (v2.description ? "\uFF1A" + v2.description : "")).join("\n");
4358
+ } else if (args.scene === "comparison") {
4359
+ doc.presentation = { layout: "comparison", preset: "comparison" };
4360
+ doc.nodes = [{ id: "options", type: "row", columns: args.items.length, children: args.items.map((v2, i) => {
4361
+ const children = [];
4362
+ if (v2.description) children.push({ id: "description_" + i, type: "text", text: v2.description });
4363
+ if (v2.value !== void 0) {
4364
+ if (!["number", "string", "boolean"].includes(typeof v2.value)) fail2("items[" + i + "].value", "must be scalar");
4365
+ if (v2.unit !== void 0) text2(v2.unit, "items[" + i + "].unit");
4366
+ children.push({ id: "value_" + i, type: "metric", label: v2.title, value: v2.value, ...v2.unit ? { unit: v2.unit } : {} });
4367
+ } else if (v2.unit !== void 0) fail2("items[" + i + "].unit", "requires a value");
4368
+ if (v2.points !== void 0) {
4369
+ if (!Array.isArray(v2.points) || v2.points.length > 8) fail2("items[" + i + "].points", "requires up to8 texts");
4370
+ v2.points.forEach((t, j2) => children.push({ id: "point_" + i + "_" + j2, type: "text", text: text2(t, "items[" + i + "].points[" + j2 + "]") }));
4371
+ }
4372
+ if (!children.length) fail2("items[" + i + "]", "needs description, value or points, not only a title");
4373
+ return { id: "option_" + i, type: "card", title: v2.title, children };
4374
+ }) }];
4375
+ doc.fallback = args.items.map((v2) => [v2.title, v2.description, v2.value === void 0 ? "" : String(v2.value) + (v2.unit ?? ""), ...v2.points ?? []].filter(Boolean).join("\uFF1B")).join("\n");
4376
+ } else if (args.scene === "allocation") {
4377
+ const total = num(args.total, "total", 1e-3, 1e5);
4378
+ if (Math.abs(total * 1e3 - Math.round(total * 1e3)) > 1e-7) fail2("total", "supports up to3 decimals");
4379
+ const unit2 = args.unit ?? "\u5206\u949F";
4380
+ text2(unit2, "unit");
4381
+ let sum = 0;
4382
+ args.items.forEach((v2, i) => sum += num(v2.percent, "items[" + i + "].percent", 0, 100));
4383
+ if (Math.abs(sum - 100) > 1e-6) fail2("items.percent", "must sum to100; received " + sum);
4384
+ doc.presentation = { layout: "workbench" };
4385
+ doc.state = { total: state(total, Math.max(total * 3, 100), Number.isInteger(total) ? 1 : 1e-3) };
4386
+ doc.derived = Object.fromEntries(args.items.map((v2, i) => ["part_" + i, { expr: "state.total * " + v2.percent + " / 100" }]));
4387
+ doc.nodes = [{ id: "total", type: "slider", label: "\u603B\u91CF\uFF08" + unit2 + "\uFF09", bind: "state.total" }, { id: "allocation", type: "row", columns: Math.min(args.items.length, 4), children: args.items.map((v2, i) => metric("part_" + i, v2.label, "part_" + i, unit2, 2)) }, { id: "distribution", type: "chart", kind: "bar", label: "\u5206\u914D\u7ED3\u679C", unit: unit2, labelKey: "label", valueKey: "value", rows: args.items.map((v2, i) => ({ label: v2.label, value: { ref: "derived.part_" + i } })) }];
4388
+ doc.fallback = "\u521D\u59CB\u603B\u91CF " + total + unit2 + "\uFF1B" + args.items.map((v2) => v2.label + " " + v2.percent + "%").join("\uFF0C") + "\u3002\u8C03\u8282\u603B\u91CF\u540E\u6309\u76F8\u540C\u6BD4\u4F8B\u5206\u914D\u3002";
4389
+ } else {
4390
+ fields2(args.values, ["people", "nights", "roomRate", "transportPerPerson"], "values");
4391
+ const v2 = args.values;
4392
+ num(v2.people, "values.people", 1, 100, true);
4393
+ num(v2.nights, "values.nights", 1, 365, true);
4394
+ for (const k2 of ["roomRate", "transportPerPerson"]) {
4395
+ num(v2[k2], "values." + k2, 0, 1e5);
4396
+ if (Math.abs(v2[k2] * 100 - Math.round(v2[k2] * 100)) > 1e-6) fail2("values." + k2, "supports up to2 decimal places");
4397
+ }
4398
+ doc.presentation = { layout: "workbench" };
4399
+ doc.state = { people: { ...state(v2.people, 100), min: 1 }, nights: { ...state(v2.nights, 365), min: 1 }, roomRate: state(v2.roomRate, 1e5, 0.01), transportPerPerson: state(v2.transportPerPerson, 1e5, 0.01) };
4400
+ doc.derived = { rooms: { expr: "ceil(state.people / 2)" }, lodging: { expr: "derived.rooms * state.nights * state.roomRate" }, transport: { expr: "state.people * state.transportPerPerson" }, total: { expr: "derived.lodging + derived.transport" }, lodgingShare: { expr: "derived.total > 0 ? round(derived.lodging / derived.total * 1000) / 10 : 0" }, transportShare: { expr: "derived.total > 0 ? round(derived.transport / derived.total * 1000) / 10 : 0" } };
4401
+ doc.nodes = [{ id: "parameters", type: "card", title: "\u8C03\u6574\u53C2\u6570", children: Object.entries({ people: "\u4EBA\u6570\uFF08\u4EBA\uFF09", nights: "\u5165\u4F4F\u665A\u6570\uFF08\u665A\uFF09", roomRate: "\u6BCF\u623F\u6BCF\u665A\uFF08\u5143\uFF09", transportPerPerson: "\u6BCF\u4EBA\u4EA4\u901A\uFF08\u5143\uFF09" }).map(([k2, label]) => ({ id: k2, type: k2 === "people" || k2 === "nights" ? "slider" : "input", label, bind: "state." + k2 })) }, { id: "totals", type: "row", columns: 3, children: [metric("rooms", "\u623F\u95F4\u6570", "rooms", "\u95F4"), metric("lodging", "\u4F4F\u5BBF", "lodging", "\u5143", 2), metric("total", "\u603B\u8BA1", "total", "\u5143", 2)] }, { id: "costs", type: "table", columns: [{ key: "label", label: "\u9879\u76EE" }, { key: "value", label: "\u91D1\u989D", unit: "\u5143" }, { key: "share", label: "\u5360\u6BD4", unit: "%" }], rows: [{ label: "\u4F4F\u5BBF", value: { ref: "derived.lodging" }, share: { ref: "derived.lodgingShare" } }, { label: "\u4EA4\u901A", value: { ref: "derived.transport" }, share: { ref: "derived.transportShare" } }] }, { id: "distribution", type: "chart", kind: "bar", label: "\u4F4F\u5BBF\u4E0E\u4EA4\u901A", unit: "\u5143", labelKey: "label", valueKey: "value", rows: [{ label: "\u4F4F\u5BBF", value: { ref: "derived.lodging" } }, { label: "\u4EA4\u901A", value: { ref: "derived.transport" } }] }, { id: "basis", type: "text", text: "\u4E24\u4F4D\u6210\u4EBA\u4E00\u95F4\u623F\uFF0C\u623F\u95F4\u6570\u5411\u4E0A\u53D6\u6574\uFF1B\u4F4F\u5BBF = \u623F\u95F4\u6570 \xD7 \u5165\u4F4F\u665A\u6570 \xD7 \u6BCF\u623F\u6BCF\u665A\uFF0C\u4EA4\u901A\u6309\u4EBA\u6570\u8BA1\u7B97\u3002\u53EA\u8BA1\u7B97\u8F93\u5165\u7684\u4F4F\u5BBF\u4E0E\u4EA4\u901A\uFF0C\u672A\u542B\u5176\u4ED6\u8D39\u7528\uFF1B\u8F93\u5165\u4EF7\u683C\u7531\u7528\u6237\u6216\u56DE\u7B54\u63D0\u4F9B\u3002" }];
4402
+ doc.fallback = "\u6309\u8F93\u5165\u4EF7\u683C\u4F30\u7B97\u4F4F\u5BBF\u4E0E\u4EA4\u901A\uFF1A" + v2.people + "\u4EBA\uFF0C" + v2.nights + "\u665A\uFF0C\u623F\u4EF7" + v2.roomRate + "\u5143\uFF0C\u6BCF\u4EBA\u4EA4\u901A" + v2.transportPerPerson + "\u5143\u3002\u4E24\u4F4D\u6210\u4EBA\u4E00\u95F4\u623F\uFF0C\u623F\u95F4\u6570\u5411\u4E0A\u53D6\u6574\uFF1B\u4E0D\u662F\u5B9E\u65F6\u4EF7\u683C\u6216\u62A5\u4EF7\u3002";
4403
+ }
4404
+ return validateDocument(doc);
4405
+ }
4406
+ function previewScene(raw) {
4407
+ try {
4408
+ if (typeof raw !== "string" || raw.length > LIMITS.bytes) return null;
4409
+ return sceneDocument(JSON.parse(raw));
4410
+ } catch {
4411
+ return null;
4412
+ }
4413
+ }
4414
+
4246
4415
  // lib/third-party/anatomy-iso.mjs
4247
4416
  var AZIMUTH = 45;
4248
4417
  var ELEVATION = 30;
@@ -4307,16 +4476,16 @@ function fitProjection(points, width, height, { pad = 24, headroom = 0, azimuth
4307
4476
  // lib/mechanism-geometry.js
4308
4477
  var MECHANISM_LIMITS = Object.freeze({ parts: 96, teeth: 64, faces: 8192 });
4309
4478
  var finite2 = (v2) => typeof v2 === "number" && Number.isFinite(v2);
4310
- var fail2 = (s) => {
4479
+ var fail3 = (s) => {
4311
4480
  throw Error("Motion mechanism: " + s);
4312
4481
  };
4313
- var num = (v2, label, min = -1e4, max = 1e4) => {
4314
- if (!finite2(v2) || v2 < min || v2 > max) fail2(label + " must be a finite number in " + min + ".." + max);
4482
+ var num2 = (v2, label, min = -1e4, max = 1e4) => {
4483
+ if (!finite2(v2) || v2 < min || v2 > max) fail3(label + " must be a finite number in " + min + ".." + max);
4315
4484
  return v2;
4316
4485
  };
4317
4486
  var vector = (v2, label) => {
4318
- if (!Array.isArray(v2) || v2.length !== 3) fail2(label + " must be [x,y,z]");
4319
- return v2.map((x, i) => num(x, label + "[" + i + "]"));
4487
+ if (!Array.isArray(v2) || v2.length !== 3) fail3(label + " must be [x,y,z]");
4488
+ return v2.map((x, i) => num2(x, label + "[" + i + "]"));
4320
4489
  };
4321
4490
  var id = (v2) => typeof v2 === "string" && /^[\p{L}_][\p{L}\p{M}\p{N}_]{0,63}$/u.test(v2) && !["constructor", "prototype", "__proto__"].includes(v2);
4322
4491
  var kinds = ["box", "cylinder", "gear", "rod", "spring"];
@@ -4327,74 +4496,74 @@ var dot = (a, b2) => a.reduce((s, v2, i) => s + v2 * b2[i], 0);
4327
4496
  var cross = (a, b2) => [a[1] * b2[2] - a[2] * b2[1], a[2] * b2[0] - a[0] * b2[2], a[0] * b2[1] - a[1] * b2[0]];
4328
4497
  var unit = (a) => {
4329
4498
  const len = Math.hypot(...a);
4330
- if (len < 1e-6) fail2("zero-length axis");
4499
+ if (len < 1e-6) fail3("zero-length axis");
4331
4500
  return mul(a, 1 / len);
4332
4501
  };
4333
4502
  function validateScene(spec) {
4334
- if (!spec || typeof spec !== "object" || Array.isArray(spec)) fail2("scene must be an object");
4335
- if (!Array.isArray(spec.parts) || !spec.parts.length || spec.parts.length > MECHANISM_LIMITS.parts) fail2("parts requires 1..96 objects");
4503
+ if (!spec || typeof spec !== "object" || Array.isArray(spec)) fail3("scene must be an object");
4504
+ if (!Array.isArray(spec.parts) || !spec.parts.length || spec.parts.length > MECHANISM_LIMITS.parts) fail3("parts requires 1..96 objects");
4336
4505
  const seen = /* @__PURE__ */ new Set(), groups = /* @__PURE__ */ new Set();
4337
4506
  for (const [i, p2] of spec.parts.entries()) {
4338
4507
  const at2 = "parts[" + i + "]";
4339
- if (!p2 || typeof p2 !== "object" || !id(p2.id) || seen.has(p2.id)) fail2(at2 + ".id must be a unique identifier");
4508
+ if (!p2 || typeof p2 !== "object" || !id(p2.id) || seen.has(p2.id)) fail3(at2 + ".id must be a unique identifier");
4340
4509
  seen.add(p2.id);
4341
- if (!kinds.includes(p2.type)) fail2(at2 + ".type must be " + kinds.join("/"));
4510
+ if (!kinds.includes(p2.type)) fail3(at2 + ".type must be " + kinds.join("/"));
4342
4511
  if (p2.group !== void 0) {
4343
- if (!id(p2.group)) fail2(at2 + ".group must be an identifier");
4512
+ if (!id(p2.group)) fail3(at2 + ".group must be an identifier");
4344
4513
  groups.add(p2.group);
4345
4514
  }
4346
- for (const k2 of ["label", "description"]) if (p2[k2] !== void 0 && (typeof p2[k2] !== "string" || p2[k2].length > 1024)) fail2(at2 + "." + k2 + " must be short text");
4347
- if (p2.cover !== void 0 && typeof p2.cover !== "boolean") fail2(at2 + ".cover must be boolean");
4348
- if (p2.material !== void 0 && !["metal", "dark", "accent", "warm", "cool"].includes(p2.material)) fail2(at2 + ".material must be metal/dark/accent/warm/cool");
4515
+ for (const k2 of ["label", "description"]) if (p2[k2] !== void 0 && (typeof p2[k2] !== "string" || p2[k2].length > 1024)) fail3(at2 + "." + k2 + " must be short text");
4516
+ if (p2.cover !== void 0 && typeof p2.cover !== "boolean") fail3(at2 + ".cover must be boolean");
4517
+ if (p2.material !== void 0 && !["metal", "dark", "accent", "warm", "cool"].includes(p2.material)) fail3(at2 + ".material must be metal/dark/accent/warm/cool");
4349
4518
  if (p2.at !== void 0) vector(p2.at, at2 + ".at");
4350
4519
  if (p2.explode !== void 0) vector(p2.explode, at2 + ".explode");
4351
- if (p2.rotation !== void 0) num(p2.rotation, at2 + ".rotation", -1e9, 1e9);
4352
- if (p2.axis !== void 0 && !["x", "y", "z"].includes(p2.axis)) fail2(at2 + ".axis must be x/y/z");
4520
+ if (p2.rotation !== void 0) num2(p2.rotation, at2 + ".rotation", -1e9, 1e9);
4521
+ if (p2.axis !== void 0 && !["x", "y", "z"].includes(p2.axis)) fail3(at2 + ".axis must be x/y/z");
4353
4522
  if (p2.type === "box") {
4354
4523
  const size = vector(p2.size, at2 + ".size");
4355
- if (size.some((v2) => v2 <= 0 || v2 > 2e3)) fail2(at2 + ".size must be positive and <=2000");
4356
- if (p2.round !== void 0) num(p2.round, at2 + ".round", 0, Math.min(size[0], size[1]) / 2);
4524
+ if (size.some((v2) => v2 <= 0 || v2 > 2e3)) fail3(at2 + ".size must be positive and <=2000");
4525
+ if (p2.round !== void 0) num2(p2.round, at2 + ".round", 0, Math.min(size[0], size[1]) / 2);
4357
4526
  }
4358
4527
  if (["cylinder", "gear"].includes(p2.type)) {
4359
- num(p2.radius, at2 + ".radius", 0.1, 1e3);
4360
- num(p2.height ?? 8, at2 + ".height", 0.1, 1e3);
4361
- if (p2.inner !== void 0) num(p2.inner, at2 + ".inner", 0, p2.radius - 0.01);
4528
+ num2(p2.radius, at2 + ".radius", 0.1, 1e3);
4529
+ num2(p2.height ?? 8, at2 + ".height", 0.1, 1e3);
4530
+ if (p2.inner !== void 0) num2(p2.inner, at2 + ".inner", 0, p2.radius - 0.01);
4362
4531
  }
4363
4532
  if (p2.type === "gear") {
4364
- const teeth = num(p2.teeth, at2 + ".teeth", 6, 64);
4365
- if (!Number.isInteger(teeth)) fail2(at2 + ".teeth must be an integer");
4366
- if (p2.module !== void 0) num(p2.module, at2 + ".module", 0.1, p2.radius / 3);
4533
+ const teeth = num2(p2.teeth, at2 + ".teeth", 6, 64);
4534
+ if (!Number.isInteger(teeth)) fail3(at2 + ".teeth must be an integer");
4535
+ if (p2.module !== void 0) num2(p2.module, at2 + ".module", 0.1, p2.radius / 3);
4367
4536
  }
4368
4537
  if (["rod", "spring"].includes(p2.type)) {
4369
4538
  vector(p2.from, at2 + ".from");
4370
4539
  vector(p2.to, at2 + ".to");
4371
- if (Math.hypot(...sub(p2.to, p2.from)) < 0.1) fail2(at2 + " endpoints must differ");
4372
- num(p2.radius ?? 2, at2 + ".radius", 0.1, 200);
4540
+ if (Math.hypot(...sub(p2.to, p2.from)) < 0.1) fail3(at2 + " endpoints must differ");
4541
+ num2(p2.radius ?? 2, at2 + ".radius", 0.1, 200);
4373
4542
  }
4374
4543
  if (p2.type === "spring") {
4375
- const turns = num(p2.turns ?? 8, at2 + ".turns", 2, 24);
4376
- if (!Number.isInteger(turns)) fail2(at2 + ".turns must be integer");
4544
+ const turns = num2(p2.turns ?? 8, at2 + ".turns", 2, 24);
4545
+ if (!Number.isInteger(turns)) fail3(at2 + ".turns must be integer");
4377
4546
  }
4378
4547
  }
4379
4548
  if (spec.groups !== void 0) {
4380
- if (!Array.isArray(spec.groups) || spec.groups.length > 12) fail2("groups must be an array of <=12 labels");
4549
+ if (!Array.isArray(spec.groups) || spec.groups.length > 12) fail3("groups must be an array of <=12 labels");
4381
4550
  const ids = /* @__PURE__ */ new Set();
4382
4551
  for (const g of spec.groups) {
4383
- if (!g || !id(g.id) || ids.has(g.id) || !groups.has(g.id) || typeof g.label !== "string" || g.label.length > 128) fail2("groups must name unique existing part groups");
4552
+ if (!g || !id(g.id) || ids.has(g.id) || !groups.has(g.id) || typeof g.label !== "string" || g.label.length > 128) fail3("groups must name unique existing part groups");
4384
4553
  ids.add(g.id);
4385
4554
  }
4386
4555
  }
4387
4556
  if (spec.bounds !== void 0) {
4388
- if (!Array.isArray(spec.bounds) || spec.bounds.length !== 2) fail2("bounds must be [minXYZ,maxXYZ]");
4557
+ if (!Array.isArray(spec.bounds) || spec.bounds.length !== 2) fail3("bounds must be [minXYZ,maxXYZ]");
4389
4558
  const [a, b2] = spec.bounds.map((v2, i) => vector(v2, "bounds[" + i + "]"));
4390
- if (a.some((v2, i) => v2 >= b2[i])) fail2("bounds min must be below max on every axis");
4559
+ if (a.some((v2, i) => v2 >= b2[i])) fail3("bounds min must be below max on every axis");
4391
4560
  }
4392
- if (spec.azimuth !== void 0) num(spec.azimuth, "azimuth", 10, 80);
4393
- if (spec.elevation !== void 0) num(spec.elevation, "elevation", 15, 70);
4394
- if (spec.title !== void 0 && (typeof spec.title !== "string" || spec.title.length > 256)) fail2("title must be short text");
4561
+ if (spec.azimuth !== void 0) num2(spec.azimuth, "azimuth", 10, 80);
4562
+ if (spec.elevation !== void 0) num2(spec.elevation, "elevation", 15, 70);
4563
+ if (spec.title !== void 0 && (typeof spec.title !== "string" || spec.title.length > 256)) fail3("title must be short text");
4395
4564
  if (spec.bind !== void 0) {
4396
- if (!spec.bind || typeof spec.bind !== "object" || Array.isArray(spec.bind)) fail2("bind must be an object");
4397
- for (const [k2, v2] of Object.entries(spec.bind)) if (!["explode", "selected", "cutaway"].includes(k2) || !id(v2)) fail2("bind only accepts declared state keys for explode/selected/cutaway");
4565
+ if (!spec.bind || typeof spec.bind !== "object" || Array.isArray(spec.bind)) fail3("bind must be an object");
4566
+ for (const [k2, v2] of Object.entries(spec.bind)) if (!["explode", "selected", "cutaway"].includes(k2) || !id(v2)) fail3("bind only accepts declared state keys for explode/selected/cutaway");
4398
4567
  }
4399
4568
  return spec;
4400
4569
  }
@@ -4471,18 +4640,18 @@ function sceneBounds(spec) {
4471
4640
  });
4472
4641
  }
4473
4642
  function gearPair({ driverTeeth = 16, drivenTeeth = 32, rpm = 30, angle = 0, module: module2 = 2 } = {}) {
4474
- for (const [k2, v2] of Object.entries({ driverTeeth, drivenTeeth })) if (!Number.isInteger(v2) || v2 < 6 || v2 > 64) fail2(k2 + " must be integer 6..64");
4475
- num(rpm, "rpm", -600, 600);
4476
- num(angle, "angle", -1e9, 1e9);
4477
- num(module2, "module", 0.1, 10);
4643
+ for (const [k2, v2] of Object.entries({ driverTeeth, drivenTeeth })) if (!Number.isInteger(v2) || v2 < 6 || v2 > 64) fail3(k2 + " must be integer 6..64");
4644
+ num2(rpm, "rpm", -600, 600);
4645
+ num2(angle, "angle", -1e9, 1e9);
4646
+ num2(module2, "module", 0.1, 10);
4478
4647
  return { driverRadius: driverTeeth * module2 / 2, drivenRadius: drivenTeeth * module2 / 2, centerDistance: (driverTeeth + drivenTeeth) * module2 / 2, driverAngle: angle, drivenAngle: -angle * driverTeeth / drivenTeeth + Math.PI - Math.PI / drivenTeeth, driverRpm: rpm, drivenRpm: -rpm * driverTeeth / drivenTeeth, ratio: drivenTeeth / driverTeeth };
4479
4648
  }
4480
4649
  function sliderCrank({ angle = 0, radius = 20, rod = 70, z: z2 = 20 } = {}) {
4481
- num(angle, "angle", -1e9, 1e9);
4482
- num(radius, "radius", 0.1, 200);
4483
- num(rod, "rod", 0.1, 1e3);
4484
- num(z2, "z");
4485
- if (rod <= radius) fail2("connecting rod length must exceed crank radius");
4650
+ num2(angle, "angle", -1e9, 1e9);
4651
+ num2(radius, "radius", 0.1, 200);
4652
+ num2(rod, "rod", 0.1, 1e3);
4653
+ num2(z2, "z");
4654
+ if (rod <= radius) fail3("connecting rod length must exceed crank radius");
4486
4655
  const crank = [radius * Math.cos(angle), radius * Math.sin(angle), z2], x = crank[0] + Math.sqrt(rod * rod - crank[1] * crank[1]);
4487
4656
  return { crank, piston: [x, 0, z2], position: x, stroke: radius * 2, angle };
4488
4657
  }
@@ -4609,27 +4778,27 @@ var n = (value, min, max, step = 1) => ({ type: "number", default: value, min, m
4609
4778
  function mechanismExample(name) {
4610
4779
  if (!MECHANISM_SCENES.some((s) => s.id === name)) throw Error("Motion mechanism: scene must be assembly/gears/crank");
4611
4780
  const scene = { assembly: assemblyScene, gears: gearsScene, crank: crankScene }[name]();
4612
- const state = { explode: n(name === "assembly" ? 0.45 : 0, 0, 1, 0.01), selected: { type: "string", default: "all" }, cutaway: { type: "boolean", default: name === "gears" } };
4781
+ const state2 = { explode: n(name === "assembly" ? 0.45 : 0, 0, 1, 0.01), selected: { type: "string", default: "all" }, cutaway: { type: "boolean", default: name === "gears" } };
4613
4782
  const bind = { explode: "explode", selected: "selected", cutaway: "cutaway" }, nodes = [];
4614
4783
  if (name !== "assembly") {
4615
- Object.assign(state, { rpm: n(20, 0, 90), running: { type: "boolean", default: false }, angle: n(0, 0, 360) });
4784
+ Object.assign(state2, { rpm: n(20, 0, 90), running: { type: "boolean", default: false }, angle: n(0, 0, 360) });
4616
4785
  Object.assign(bind, { rpm: "rpm", running: "running", angle: "angle" });
4617
4786
  nodes.push({ id: "rpm", type: "slider", label: "\u8F93\u5165\u8F6C\u901F\uFF08rpm\uFF09", bind: "state.rpm" }, { id: "angle", type: "slider", label: "\u624B\u52A8\u89D2\u5EA6\uFF08\xB0\uFF0C\u6682\u505C\u65F6\u8C03\u8282\uFF09", bind: "state.angle" }, { id: "running", type: "toggle", label: "\u8FD0\u884C\u673A\u68B0\u793A\u610F", bind: "state.running" });
4618
4787
  }
4619
4788
  if (name === "gears") {
4620
- state.teeth = n(32, 16, 48);
4789
+ state2.teeth = n(32, 16, 48);
4621
4790
  bind.teeth = "teeth";
4622
4791
  nodes.unshift({ id: "teeth", type: "slider", label: "\u4ECE\u52A8\u8F6E\u9F7F\u6570\uFF08\u4E3B\u52A8\u8F6E16\u9F7F\uFF09", bind: "state.teeth" });
4623
4792
  }
4624
4793
  if (name === "crank") {
4625
- state.radius = n(20, 10, 28);
4794
+ state2.radius = n(20, 10, 28);
4626
4795
  bind.radius = "radius";
4627
4796
  nodes.unshift({ id: "radius", type: "slider", label: "\u66F2\u67C4\u534A\u5F84\uFF08\u793A\u610F\u957F\u5EA6\u5355\u4F4D\uFF09", bind: "state.radius" });
4628
4797
  }
4629
4798
  const fallback = name === "assembly" ? "\u5E95\u5EA7\u652F\u6491\u529F\u80FD\u677F\uFF0C\u5904\u7406\u6A21\u5757\u4E0A\u65B9\u4E3A\u6563\u70ED\u5C42\uFF0C\u5916\u58F3\u4FDD\u62A4\u5185\u90E8\u3002\u62C6\u89E3\u8868\u793A\u88C5\u914D\u5173\u7CFB\uFF0C\u4E0D\u8868\u793A\u53D7\u529B\u8FD0\u52A8\u3002" : name === "gears" ? "\u5916\u556E\u5408\u9F7F\u8F6E\u53CD\u5411\u8F6C\u52A8\u3002\u4E3B\u52A8\u8F6E16\u9F7F\u300120 rpm\uFF0C\u4ECE\u52A8\u8F6E\u9ED8\u8BA432\u9F7F\u3001-10 rpm\uFF0C\u4E2D\u5FC3\u8DDD\u7531\u6A21\u6570\u548C\u9F7F\u6570\u786E\u5B9A\u3002\u9F7F\u5F62\u4E3A\u7B80\u5316\u793A\u610F\uFF0C\u4E0D\u7528\u4E8E\u52A0\u5DE5\u3002" : "\u65CB\u8F6C\u66F2\u67C4\u5E26\u52A8\u5B9A\u957F\u8FDE\u6746\uFF0C\u6ED1\u5757\u6CBF\u5BFC\u8F68\u5F80\u590D\u3002\u9ED8\u8BA4\u534A\u5F8420\u3001\u6746\u957F70\uFF0C\u5B8C\u6574\u884C\u7A0B40\uFF0C\u4F4D\u7F6E\u7531\u51E0\u4F55\u7EA6\u675F\u8BA1\u7B97\u3002\u975E\u52A8\u529B\u5B66\u4EFF\u771F\u3002";
4630
- nodes.unshift({ id: "mechanism", type: "sandbox", title: scene.title, fallback, height: 560, libraries: ["mechanism"], stateKeys: Object.keys(state), html: '<div id="diagram"><section class="mui-mechanism">' + sceneSvg(scene, { explode: state.explode.default, cutaway: state.cutaway.default, preview: true }) + "<p>" + fallback + "</p></section></div>", css: MECHANISM_CSS, script: 'const diagram=DSHUI.mechanism.mountDemo("#diagram",' + JSON.stringify(name) + ',{title:"",bind:' + JSON.stringify(bind) + '});addEventListener("pagehide",()=>diagram.destroy(),{once:true});' });
4799
+ nodes.unshift({ id: "mechanism", type: "sandbox", title: scene.title, fallback, height: 560, libraries: ["mechanism"], stateKeys: Object.keys(state2), html: '<div id="diagram"><section class="mui-mechanism">' + sceneSvg(scene, { explode: state2.explode.default, cutaway: state2.cutaway.default, preview: true }) + "<p>" + fallback + "</p></section></div>", css: MECHANISM_CSS, script: 'const diagram=DSHUI.mechanism.mountDemo("#diagram",' + JSON.stringify(name) + ',{title:"",bind:' + JSON.stringify(bind) + '});addEventListener("pagehide",()=>diagram.destroy(),{once:true});' });
4631
4800
  nodes.push({ id: "accuracy", type: "text", text: fallback });
4632
- return validateDocument({ version: 1, title: scene.title, fallback, state, nodes });
4801
+ return validateDocument({ version: 1, title: scene.title, fallback, state: state2, nodes });
4633
4802
  }
4634
4803
 
4635
4804
  // lib/mechanism-entry.js
@@ -4688,7 +4857,7 @@ function dispose(entry) {
4688
4857
  function publish(entry, calls, invalidated = []) {
4689
4858
  for (const key2 of invalidated) entry.previews.delete(key2);
4690
4859
  for (const call of calls) {
4691
- const doc = call.name === "render_mechanism" ? previewMechanism(call.raw) : call.name === "render_text" ? previewText(call.raw) : previewDocument(call.raw);
4860
+ const doc = call.name === "render_scene" ? previewScene(call.raw) : call.name === "render_mechanism" ? previewMechanism(call.raw) : call.name === "render_text" ? previewText(call.raw) : previewDocument(call.raw);
4692
4861
  const canvas = call.name === "render_canvas" ? previewCanvas(call.raw) : null;
4693
4862
  if (doc || canvas) entry.previews.set(call.callId, { call, doc, canvas });
4694
4863
  }
@@ -4752,21 +4921,21 @@ var import_react15 = __toESM(require("react"), 1);
4752
4921
  var JSX = __toESM(require("react/jsx-runtime"), 1);
4753
4922
 
4754
4923
  // src/visual-state.js
4755
- function visualStateSignature(state = {}, defaults = {}) {
4924
+ function visualStateSignature(state2 = {}, defaults = {}) {
4756
4925
  const sorted = (value) => Object.fromEntries(Object.entries(value ?? {}).sort(([a], [b2]) => a.localeCompare(b2)));
4757
- return JSON.stringify({ answers: sorted(state.answers), multiAnswers: sorted(state.multiAnswers), fields: sorted({ ...defaults, ...state.fields }), locked: state.locked === true });
4926
+ return JSON.stringify({ answers: sorted(state2.answers), multiAnswers: sorted(state2.multiAnswers), fields: sorted({ ...defaults, ...state2.fields }), locked: state2.locked === true });
4758
4927
  }
4759
4928
 
4760
4929
  // lib/visual-defaults.js
4761
4930
  function visualDefaults(spec) {
4762
- const fields2 = {};
4931
+ const fields3 = {};
4763
4932
  const walk = (items) => {
4764
4933
  for (const n2 of items ?? []) {
4765
4934
  if (!n2 || typeof n2 !== "object") continue;
4766
4935
  if (n2.id) {
4767
- if (["input", "textarea"].includes(n2.type) && typeof n2.value === "string") fields2[n2.id] = n2.value;
4768
- if (n2.type === "slider") fields2[n2.id] = String(n2.value ?? n2.min ?? 0);
4769
- if (n2.type === "select" && Number.isInteger(n2.selected) && typeof n2.options?.[n2.selected] === "string") fields2[n2.id] = n2.options[n2.selected];
4936
+ if (["input", "textarea"].includes(n2.type) && typeof n2.value === "string") fields3[n2.id] = n2.value;
4937
+ if (n2.type === "slider") fields3[n2.id] = String(n2.value ?? n2.min ?? 0);
4938
+ if (n2.type === "select" && Number.isInteger(n2.selected) && typeof n2.options?.[n2.selected] === "string") fields3[n2.id] = n2.options[n2.selected];
4770
4939
  }
4771
4940
  if (["card", "row", "col", "grid"].includes(n2.type)) walk(n2.items);
4772
4941
  if (n2.type === "tabs") for (const t of n2.tabs ?? []) walk(t.items);
@@ -4774,7 +4943,7 @@ function visualDefaults(spec) {
4774
4943
  }
4775
4944
  };
4776
4945
  walk(spec.items);
4777
- return fields2;
4946
+ return fields3;
4778
4947
  }
4779
4948
 
4780
4949
  // src/visual-view.js
@@ -4817,15 +4986,15 @@ function loadVisual() {
4817
4986
  });
4818
4987
  return pending;
4819
4988
  }
4820
- function VisualView({ node, state, update, disabled, preview, sendPrompt, openFile, provenance, documentTitle }) {
4989
+ function VisualView({ node, state: state2, update, disabled, preview, sendPrompt, openFile, provenance, documentTitle }) {
4821
4990
  const defaults = visualDefaults(node.spec), stateSignature = (v2) => visualStateSignature(v2, defaults);
4822
4991
  const showDetails = useViewDetails();
4823
4992
  const [core, setCore] = (0, import_react15.useState)(), [error, setError] = (0, import_react15.useState)(""), [epoch, setEpoch] = (0, import_react15.useState)(0), [busy, setBusy] = (0, import_react15.useState)(false), [feedback, setFeedback] = (0, import_react15.useState)("");
4824
- const last = (0, import_react15.useRef)(stateSignature(state)), latest = (0, import_react15.useRef)(state), sending = (0, import_react15.useRef)(false), source = (0, import_react15.useRef)(node.spec);
4825
- latest.current = state;
4993
+ const last = (0, import_react15.useRef)(stateSignature(state2)), latest = (0, import_react15.useRef)(state2), sending = (0, import_react15.useRef)(false), source = (0, import_react15.useRef)(node.spec);
4994
+ latest.current = state2;
4826
4995
  if (source.current !== node.spec) {
4827
4996
  source.current = node.spec;
4828
- last.current = stateSignature(state);
4997
+ last.current = stateSignature(state2);
4829
4998
  }
4830
4999
  (0, import_react15.useEffect)(() => {
4831
5000
  let live = true;
@@ -4839,12 +5008,12 @@ function VisualView({ node, state, update, disabled, preview, sendPrompt, openFi
4839
5008
  };
4840
5009
  }, []);
4841
5010
  (0, import_react15.useEffect)(() => {
4842
- const serialized = stateSignature(state);
5011
+ const serialized = stateSignature(state2);
4843
5012
  if (serialized !== last.current) {
4844
5013
  last.current = serialized;
4845
5014
  setEpoch((e) => e + 1);
4846
5015
  }
4847
- }, [state]);
5016
+ }, [state2]);
4848
5017
  const changed = (next) => {
4849
5018
  if (disabled || preview) return;
4850
5019
  const serialized = stateSignature(next);
@@ -4887,7 +5056,7 @@ function VisualView({ node, state, update, disabled, preview, sendPrompt, openFi
4887
5056
  setError("\u5BFC\u51FA\u5931\u8D25\uFF1A" + e.message);
4888
5057
  }
4889
5058
  };
4890
- const content = h10(core.ErrorBoundary, { label: "Motion UI" }, h10(core.GenuiBlock, { key: epoch, spec, initialState: state, animateEntrance: !preview, onStateChange: preview ? () => {
5059
+ const content = h10(core.ErrorBoundary, { label: "Motion UI" }, h10(core.GenuiBlock, { key: epoch, spec, initialState: state2, animateEntrance: !preview, onStateChange: preview ? () => {
4891
5060
  } : changed }));
4892
5061
  return h10("section", { "data-ui-node": node.id, "data-motion-visual": true }, h10("div", { inert: disabled || preview || busy ? "" : void 0, "aria-busy": busy }, h10(core.GenuiActionContext.Provider, { value: action }, h10(core.FileLinkOpenContext.Provider, { value: disabled || preview ? void 0 : openFile }, content))), showDetails && !preview && h10("div", { className: "dgui-row" }, h10("button", { type: "button", disabled, onClick: () => exportAs("html") }, "\u5BFC\u51FA HTML"), h10("button", { type: "button", disabled, onClick: () => exportAs("json") }, "\u5BFC\u51FA JSON")), error && h10("p", { role: "alert" }, error), feedback && h10("p", { role: "status" }, feedback));
4893
5062
  }
@@ -4909,7 +5078,7 @@ function diagnoseDelivery(input) {
4909
5078
  const document2 = validateDocument(input), diagnostics = deliveryDiagnostics(document2);
4910
5079
  return { valid: true, complete: diagnostics.length === 0, document: document2, diagnostics };
4911
5080
  } catch (e) {
4912
- return { valid: false, complete: false, diagnostics: [{ severity: "error", path: "document", message: e.message }] };
5081
+ return { valid: false, complete: false, diagnostics: [{ severity: "error", path: e.path ?? e.message.match(/(?:^DSH UI: |unknown field )((?:node|nodes|derived|state|document|presentation)(?:\.[\p{L}\p{N}_]+|\[\d+\])+)/u)?.[1] ?? "document", message: e.message }] };
4913
5082
  }
4914
5083
  }
4915
5084
  function resolveSourceFence(raw, { svg = false } = {}) {
@@ -4932,17 +5101,17 @@ function resolveSourceFence(raw, { svg = false } = {}) {
4932
5101
  // src/copy-block.js
4933
5102
  var import_react16 = __toESM(require("react"), 1);
4934
5103
  var h11 = import_react16.default.createElement;
4935
- async function copyContent(text2) {
5104
+ async function copyContent(text3) {
4936
5105
  try {
4937
5106
  if (typeof navigator.clipboard?.writeText === "function") {
4938
- await navigator.clipboard.writeText(text2);
5107
+ await navigator.clipboard.writeText(text3);
4939
5108
  return true;
4940
5109
  }
4941
5110
  } catch {
4942
5111
  }
4943
5112
  const active = document.activeElement, selection = window.getSelection(), ranges = selection ? Array.from({ length: selection.rangeCount }, (_2, i) => selection.getRangeAt(i).cloneRange()) : [];
4944
5113
  const field = document.createElement("textarea");
4945
- field.value = text2;
5114
+ field.value = text3;
4946
5115
  field.readOnly = true;
4947
5116
  field.style.cssText = "position:fixed;left:-10000px;top:0;opacity:0";
4948
5117
  document.body.append(field);
@@ -4974,18 +5143,18 @@ var COPY_BLOCK_CSS = `
4974
5143
  @media(prefers-reduced-motion:reduce){.motion-copy-button .dgui-icon,.motion-copy-button path{animation:none!important;transition:none!important}}
4975
5144
  @media(max-width:600px){.motion-copy-block{padding:14px 16px;border-radius:20px}}
4976
5145
  `;
4977
- function CopyBlock({ text: text2, children, title, lang, code = false, wrap = false, disabled = false, style, nodeId, copyLabel, copiedLabel }) {
5146
+ function CopyBlock({ text: text3, children, title, lang, code = false, wrap = false, disabled = false, style, nodeId, copyLabel, copiedLabel }) {
4978
5147
  const [status, setStatus] = (0, import_react16.useState)("idle"), timer = (0, import_react16.useRef)();
4979
5148
  (0, import_react16.useEffect)(() => () => clearTimeout(timer.current), []);
4980
5149
  const label = status === "done" ? copiedLabel ?? "\u5DF2\u590D\u5236" : status === "error" ? "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5185\u5BB9" : copyLabel ?? (code ? "\u590D\u5236\u4EE3\u7801" : "\u590D\u5236\u6587\u672C");
4981
5150
  async function copy2() {
4982
5151
  clearTimeout(timer.current);
4983
5152
  setStatus("copying");
4984
- const ok = await copyContent(text2);
5153
+ const ok = await copyContent(text3);
4985
5154
  setStatus(ok ? "done" : "error");
4986
5155
  timer.current = setTimeout(() => setStatus("idle"), 2e3);
4987
5156
  }
4988
- return h11("section", { className: "motion-copy-block", "data-copy-status": status, "data-code": code || void 0, "data-ui-node": nodeId, style }, h11("style", null, COPY_BLOCK_CSS), h11("div", { className: "motion-copy-bar" }, code && h11("span", { "aria-hidden": true }, "\u3008/\u3009"), h11("span", { className: "motion-copy-title" }, title ?? (code ? lang || "\u4EE3\u7801" : "\u6587\u672C")), h11("button", { className: "motion-copy-button", type: "button", title: label, "aria-label": label, "data-status": status, disabled: disabled || status === "copying", onClick: copy2 }, h11(Icon, { name: status === "done" ? "check" : status === "error" ? "warning" : "copy" })), h11("span", { className: "motion-copy-sr", role: "status", "aria-live": "polite" }, status === "done" ? "\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" : status === "error" ? label : "")), code ? h11("pre", { className: "motion-copy-code", "data-wrap": wrap || void 0 }, h11("code", { "data-language": lang }, text2)) : h11("div", { className: "motion-copy-body" }, children ?? text2));
5157
+ return h11("section", { className: "motion-copy-block", "data-copy-status": status, "data-code": code || void 0, "data-ui-node": nodeId, style }, h11("style", null, COPY_BLOCK_CSS), h11("div", { className: "motion-copy-bar" }, code && h11("span", { "aria-hidden": true }, "\u3008/\u3009"), h11("span", { className: "motion-copy-title" }, title ?? (code ? lang || "\u4EE3\u7801" : "\u6587\u672C")), h11("button", { className: "motion-copy-button", type: "button", title: label, "aria-label": label, "data-status": status, disabled: disabled || status === "copying", onClick: copy2 }, h11(Icon, { name: status === "done" ? "check" : status === "error" ? "warning" : "copy" })), h11("span", { className: "motion-copy-sr", role: "status", "aria-live": "polite" }, status === "done" ? "\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" : status === "error" ? label : "")), code ? h11("pre", { className: "motion-copy-code", "data-wrap": wrap || void 0 }, h11("code", { "data-language": lang }, text3)) : h11("div", { className: "motion-copy-body" }, children ?? text3));
4989
5158
  }
4990
5159
 
4991
5160
  // src/view.js
@@ -5008,9 +5177,9 @@ function NumericInput({ id: id2, spec, value, onChange, invalidChanged, disabled
5008
5177
  disabled,
5009
5178
  "aria-invalid": invalid,
5010
5179
  onChange(e) {
5011
- const text2 = e.target.value;
5012
- setDraft(text2);
5013
- const n2 = Number(text2), bad = text2.trim() === "" || !Number.isFinite(n2) || n2 < spec.min || n2 > spec.max || Math.abs((n2 - spec.min) / spec.step - Math.round((n2 - spec.min) / spec.step)) > 1e-6;
5180
+ const text3 = e.target.value;
5181
+ setDraft(text3);
5182
+ const n2 = Number(text3), bad = text3.trim() === "" || !Number.isFinite(n2) || n2 < spec.min || n2 > spec.max || Math.abs((n2 - spec.min) / spec.step - Math.round((n2 - spec.min) / spec.step)) > 1e-6;
5014
5183
  setInvalid(bad);
5015
5184
  invalidChanged(id2, bad);
5016
5185
  if (!bad) onChange(n2);
@@ -5093,7 +5262,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
5093
5262
  canvasAudits.current.set(id2, { coverage: coverage ? { ...coverage, nodeId: id2 } : void 0, issues: issues.filter((i) => Object.hasOwn(AUDIT_MESSAGES, i.code)).slice(0, 40).map((i) => ({ ...i, nodeId: id2 })) });
5094
5263
  collectAudit();
5095
5264
  };
5096
- const { state, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
5265
+ const { state: state2, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
5097
5266
  const [error, setError] = (0, import_react17.useState)(""), [actionStatus, setActionStatus] = (0, import_react17.useState)("");
5098
5267
  const [busy, setBusy] = (0, import_react17.useState)(false), [invalidFields, setInvalidFields] = (0, import_react17.useState)({});
5099
5268
  const pending2 = (0, import_react17.useRef)(false);
@@ -5103,15 +5272,15 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
5103
5272
  const invalidChanged = import_react17.default.useCallback((id2, invalid) => setInvalidFields((previous) => previous[id2] === invalid ? previous : { ...previous, [id2]: invalid }), []);
5104
5273
  let computed;
5105
5274
  try {
5106
- computed = evaluate(doc, state);
5275
+ computed = evaluate(doc, state2);
5107
5276
  } catch (e) {
5108
5277
  computed = { error: e.message };
5109
5278
  }
5110
- const currentState = (0, import_react17.useRef)(state);
5111
- currentState.current = state;
5279
+ const currentState = (0, import_react17.useRef)(state2);
5280
+ currentState.current = state2;
5112
5281
  (0, import_react17.useEffect)(() => {
5113
5282
  collectAudit();
5114
- }, [state, ready, collectAudit]);
5283
+ }, [state2, ready, collectAudit]);
5115
5284
  const updatePatch = (patch) => {
5116
5285
  const next = validateState(doc, { ...currentState.current, ...patch });
5117
5286
  currentState.current = next;
@@ -5134,7 +5303,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
5134
5303
  setActionStatus("\u6B63\u5728\u53D1\u9001\u2026");
5135
5304
  setError("");
5136
5305
  try {
5137
- const prompt = followupPrompt(doc, state, actionKey, { documentId: record.documentId, sourceCallId: record.callId, sourceSessionId: record.sessionId, viewedSessionId: sessionId });
5306
+ const prompt = followupPrompt(doc, state2, actionKey, { documentId: record.documentId, sourceCallId: record.callId, sourceSessionId: record.sessionId, viewedSessionId: sessionId });
5138
5307
  await sendPrompt(prompt);
5139
5308
  setActionStatus("\u5DF2\u52A0\u5165\u5F53\u524D\u4F1A\u8BDD\u961F\u5217");
5140
5309
  } catch (e) {
@@ -5151,11 +5320,11 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
5151
5320
  const copy2 = () => n2.spans ? n2.spans.map((span, i) => h12("span", { key: i, style: typographyStyle(span) }, span.text)) : display(resolve(n2.text));
5152
5321
  switch (n2.type) {
5153
5322
  case "visual":
5154
- return h12(VisualView, { key: n2.id, node: n2, state: state[n2.stateKey], update: (value) => updatePatch({ [n2.stateKey]: value }), disabled, preview, sendPrompt, openFile, documentTitle: doc.title, provenance: { documentId: record.documentId, sourceSessionId: record.sessionId, viewedSessionId: sessionId } });
5323
+ return h12(VisualView, { key: n2.id, node: n2, state: state2[n2.stateKey], update: (value) => updatePatch({ [n2.stateKey]: value }), disabled, preview, sendPrompt, openFile, documentTitle: doc.title, provenance: { documentId: record.documentId, sourceSessionId: record.sessionId, viewedSessionId: sessionId } });
5155
5324
  case "code":
5156
5325
  return h12(CopyBlock, { key: n2.id, nodeId: n2.id, text: n2.code, lang: n2.lang, title: n2.title, wrap: n2.wrap, code: true, disabled: preview });
5157
5326
  case "sandbox":
5158
- return h12(Sandbox, { key: n2.id, node: n2, document: doc, state, data: doc.data, derived: computed.derived ?? {}, disabled, preview: preview || !ready, update: updatePatch, onAudit });
5327
+ return h12(Sandbox, { key: n2.id, node: n2, document: doc, state: state2, data: doc.data, derived: computed.derived ?? {}, disabled, preview: preview || !ready, update: updatePatch, onAudit });
5159
5328
  case "heading":
5160
5329
  return h12("h4", { ...props, className: "dgui-section-title" }, n2.icon && h12(Icon, { name: n2.icon }), h12("span", null, copy2()));
5161
5330
  case "text":
@@ -5184,7 +5353,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
5184
5353
  case "slider":
5185
5354
  case "select":
5186
5355
  case "toggle": {
5187
- const k2 = n2.bind.split(".")[1], spec = doc.state[k2], v2 = state[k2], id2 = `dgui-${record.documentId}-${n2.id}-${viewId}`;
5356
+ const k2 = n2.bind.split(".")[1], spec = doc.state[k2], v2 = state2[k2], id2 = `dgui-${record.documentId}-${n2.id}-${viewId}`;
5188
5357
  let control;
5189
5358
  if (n2.type === "select" && n2.variant === "segmented" && spec.options.length >= 2 && spec.options.length <= 8) control = h12(SegmentedControl, { id: id2, label: n2.label, options: spec.options, value: v2, disabled: !ready, onChange: (value) => update(k2, value) });
5190
5359
  else if (n2.type === "select") control = h12("select", { id: id2, value: spec.options.indexOf(v2), disabled: !ready, onChange: (e) => update(k2, spec.options[Number(e.target.value)]) }, spec.options.map((o, i) => h12("option", { key: i, value: i }, display(o))));
@@ -5333,7 +5502,7 @@ var turnUiDefinition = {
5333
5502
  };
5334
5503
 
5335
5504
  // src/stream-history.js
5336
- var names = /* @__PURE__ */ new Set(["render_ui", "render_canvas", "render_text", "render_mechanism"]);
5505
+ var names = /* @__PURE__ */ new Set(["render_ui", "render_canvas", "render_text", "render_mechanism", "render_scene"]);
5337
5506
  var streamUiDefinition = {
5338
5507
  kind: "dshUiStream",
5339
5508
  target: "chat",
@@ -5345,37 +5514,37 @@ var streamUiDefinition = {
5345
5514
  start(_context, { event }) {
5346
5515
  return { turn: event.data.turn, calls: [], invalidated: [], settled: false };
5347
5516
  },
5348
- update({ state }, { event }) {
5349
- if (event.type === "turn/end") return { ...state, calls: [], settled: true };
5350
- if (state.settled) return state;
5517
+ update({ state: state2 }, { event }) {
5518
+ if (event.type === "turn/end") return { ...state2, calls: [], settled: true };
5519
+ if (state2.settled) return state2;
5351
5520
  if (event.type === "tool/call") {
5352
5521
  const call2 = { key: `${event.data.step}:durable:${event.data.callId}`, callId: event.data.callId, name: event.data.name, raw: event.data.arguments ?? event.data.argsRaw ?? "" };
5353
- if (typeof call2.raw !== "string" || call2.raw.length > LIMITS.bytes) return state;
5354
- return { ...state, anchorSeq: state.anchorSeq ?? event.seq, calls: [...state.calls.filter((c) => c.callId !== call2.callId), call2].slice(-24) };
5522
+ if (typeof call2.raw !== "string" || call2.raw.length > LIMITS.bytes) return state2;
5523
+ return { ...state2, anchorSeq: state2.anchorSeq ?? event.seq, calls: [...state2.calls.filter((c) => c.callId !== call2.callId), call2].slice(-24) };
5355
5524
  }
5356
- if (event.type === "llm/retry") return { ...state, invalidated: [...state.invalidated, ...state.calls.filter((c) => c.key.startsWith(`${event.data.step}:`)).map((c) => c.callId)].slice(-48), calls: state.calls.filter((c) => !c.key.startsWith(`${event.data.step}:`)) };
5525
+ if (event.type === "llm/retry") return { ...state2, invalidated: [...state2.invalidated, ...state2.calls.filter((c) => c.key.startsWith(`${event.data.step}:`)).map((c) => c.callId)].slice(-48), calls: state2.calls.filter((c) => !c.key.startsWith(`${event.data.step}:`)) };
5357
5526
  if (event.type === "tool/result") {
5358
- if (!event.data.message.isError) return state;
5359
- return { ...state, invalidated: [...state.invalidated, event.data.callId].slice(-48), calls: state.calls.filter((c) => c.callId !== event.data.callId) };
5527
+ if (!event.data.message.isError) return state2;
5528
+ return { ...state2, invalidated: [...state2.invalidated, event.data.callId].slice(-48), calls: state2.calls.filter((c) => c.callId !== event.data.callId) };
5360
5529
  }
5361
- const chunk = event.type === "chunkrow/tool-call-chunks" ? { ...event.data, argumentsDelta: event.data.args.join("") } : event.data.chunk, key2 = `${event.data.step}:${chunk.index}`, previous = state.calls.find((c) => c.key === key2);
5530
+ const chunk = event.type === "chunkrow/tool-call-chunks" ? { ...event.data, argumentsDelta: event.data.args.join("") } : event.data.chunk, key2 = `${event.data.step}:${chunk.index}`, previous = state2.calls.find((c) => c.key === key2);
5362
5531
  const name = chunk.name ?? previous?.name;
5363
- if (!names.has(name)) return state;
5532
+ if (!names.has(name)) return state2;
5364
5533
  const raw = (previous?.raw ?? "") + (chunk.argumentsDelta ?? "");
5365
- if (raw.length > LIMITS.bytes) return { ...state, calls: state.calls.filter((c) => c.key !== key2) };
5534
+ if (raw.length > LIMITS.bytes) return { ...state2, calls: state2.calls.filter((c) => c.key !== key2) };
5366
5535
  const call = { key: key2, name, callId: previous?.callId ?? String(chunk.id), raw };
5367
- return { ...state, anchorSeq: state.anchorSeq ?? event.seq, calls: [...state.calls.filter((c) => c.key !== key2), call].slice(-24) };
5536
+ return { ...state2, anchorSeq: state2.anchorSeq ?? event.seq, calls: [...state2.calls.filter((c) => c.key !== key2), call].slice(-24) };
5368
5537
  },
5369
5538
  publication: () => "immediate",
5370
- buildLocationData({ state }, scope2, previous) {
5371
- if (scope2 !== "turn" || !state) return null;
5372
- if (previous?.value === state) return previous;
5373
- return { kind: "turn", turn: state.turn, key: "dshUiStream", value: state };
5539
+ buildLocationData({ state: state2 }, scope2, previous) {
5540
+ if (scope2 !== "turn" || !state2) return null;
5541
+ if (previous?.value === state2) return previous;
5542
+ return { kind: "turn", turn: state2.turn, key: "dshUiStream", value: state2 };
5374
5543
  },
5375
5544
  buildViewNode(context) {
5376
- const state = context.state;
5377
- if (!state) return null;
5378
- return { key: context.key, id: context.id, kind: "dshUiStream", target: "chat", anchorSeq: state.anchorSeq ?? context.start?.event.seq ?? 0, location: context.start?.location ?? context.matches[0]?.location ?? { kind: "unresolved" }, visibility: state.settled || state.anchorSeq === void 0 ? "hidden" : "visible", data: state };
5545
+ const state2 = context.state;
5546
+ if (!state2) return null;
5547
+ return { key: context.key, id: context.id, kind: "dshUiStream", target: "chat", anchorSeq: state2.anchorSeq ?? context.start?.event.seq ?? 0, location: context.start?.location ?? context.matches[0]?.location ?? { kind: "unresolved" }, visibility: state2.settled || state2.anchorSeq === void 0 ? "hidden" : "visible", data: state2 };
5379
5548
  }
5380
5549
  };
5381
5550
 
@@ -5501,10 +5670,10 @@ ${root} .dgui-steps li[data-step-status=active]{border-color:var(--du-accent)}${
5501
5670
  var import_react18 = __toESM(require("react"), 1);
5502
5671
  var h13 = import_react18.default.createElement;
5503
5672
  var PREVIEW_LAYOUTS = [["text", "\u6587\u5B57\u8BF4\u660E"], ["comparison", "\u53CC\u5217\u5BF9\u6BD4"], ["list", "\u5206\u9694\u5217\u8868"], ["summary", "\u6570\u636E\u6458\u8981"], ["controls", "\u63A7\u4EF6\u8868\u5355"], ["flow", "\u6D41\u7A0B\u56FE\u89E3"]];
5504
- var header = (text2) => h13("div", { className: "dgui-header" }, h13("strong", { className: "dgui-header-title" }, text2));
5505
- var copy = (text2) => h13("p", { className: "dgui-copy" }, text2);
5506
- var card = (title, text2) => h13("div", { key: title, className: "dgui-card" }, h13("strong", { className: "dgui-section-title" }, title), copy(text2));
5507
- var metric = (number2, label) => h13("div", { key: label, className: "dgui-metric" }, h13("span", { className: "dgui-metric-label" }, label), h13("strong", null, number2));
5673
+ var header = (text3) => h13("div", { className: "dgui-header" }, h13("strong", { className: "dgui-header-title" }, text3));
5674
+ var copy = (text3) => h13("p", { className: "dgui-copy" }, text3);
5675
+ var card = (title, text3) => h13("div", { key: title, className: "dgui-card" }, h13("strong", { className: "dgui-section-title" }, title), copy(text3));
5676
+ var metric2 = (number2, label) => h13("div", { key: label, className: "dgui-metric" }, h13("span", { className: "dgui-metric-label" }, label), h13("strong", null, number2));
5508
5677
  function StyleSample({ styleId, layout = "text" }) {
5509
5678
  let body, title;
5510
5679
  if (layout === "text") {
@@ -5517,13 +5686,13 @@ function StyleSample({ styleId, layout = "text" }) {
5517
5686
  body = h13("div", { className: "dgui-row" }, card("\u5148\u505A\u5C0F\u7248\u672C", "\u9A8C\u8BC1\u91CD\u70B9"), card("\u5148\u94FA\u5168\u529F\u80FD", "\u8986\u76D6\u9700\u6C42"));
5518
5687
  } else if (layout === "summary") {
5519
5688
  title = "\u8BA9\u91CD\u70B9\u4E00\u773C\u53EF\u89C1";
5520
- body = h13("div", { className: "dgui-row" }, metric("3", "\u63A8\u8FDB\u9636\u6BB5"), metric("1", "\u6838\u5FC3\u76EE\u6807"));
5689
+ body = h13("div", { className: "dgui-row" }, metric2("3", "\u63A8\u8FDB\u9636\u6BB5"), metric2("1", "\u6838\u5FC3\u76EE\u6807"));
5521
5690
  } else if (layout === "controls") {
5522
5691
  title = "\u8BA9\u53C2\u6570\u76F4\u63A5\u8BF4\u8BDD";
5523
5692
  body = h13("div", { className: "dgui-column" }, h13("div", { className: "dgui-control" }, h13("span", { className: "dgui-control-label" }, "\u6BCF\u5468\u6295\u5165"), h13("output", null, "12 \u5C0F\u65F6"), h13("span", { className: "dgui-sample-track" }, h13("i"))), h13("div", { className: "dgui-sample-options" }, ["\u8F7B\u91CF", "\u5747\u8861", "\u6DF1\u5165"].map((t, i) => h13("span", { key: t, "data-selected": i === 1 || void 0 }, t))));
5524
5693
  } else {
5525
5694
  title = "\u628A\u590D\u6742\u95EE\u9898\u8BB2\u6E05\u695A";
5526
- body = h13("ol", { className: "dgui-steps", "data-sample-layout": layout }, ["\u660E\u786E\u76EE\u6807", "\u89E3\u91CA\u5173\u7CFB", "\u7ED9\u51FA\u884C\u52A8"].map((text2, i) => h13("li", { key: text2 }, h13("span", { className: "dgui-step-dot" }, layout === "list" ? "\u2713" : String(i + 1).padStart(2, "0")), h13("div", null, h13("strong", null, text2), layout === "list" && h13("p", null, ["\u5148\u6293\u4F4F\u91CD\u70B9", "\u7528\u56FE\u5F62\u8BF4\u660E", "\u6536\u6210\u4E0B\u4E00\u6B65"][i])))));
5695
+ body = h13("ol", { className: "dgui-steps", "data-sample-layout": layout }, ["\u660E\u786E\u76EE\u6807", "\u89E3\u91CA\u5173\u7CFB", "\u7ED9\u51FA\u884C\u52A8"].map((text3, i) => h13("li", { key: text3 }, h13("span", { className: "dgui-step-dot" }, layout === "list" ? "\u2713" : String(i + 1).padStart(2, "0")), h13("div", null, h13("strong", null, text3), layout === "list" && h13("p", null, ["\u5148\u6293\u4F4F\u91CD\u70B9", "\u7528\u56FE\u5F62\u8BF4\u660E", "\u6536\u6210\u4E0B\u4E00\u6B65"][i])))));
5527
5696
  }
5528
5697
  return h13("div", { className: "dgui-root dgui-style-preview", "data-preset": "brief", "data-visual-style": styleId, "data-layout": layout, "aria-hidden": true }, header(title), h13("div", { className: "dgui-content" }, body));
5529
5698
  }
@@ -5683,7 +5852,7 @@ var READING_CSS = `
5683
5852
  `;
5684
5853
 
5685
5854
  // src/styles.js
5686
- var CSS = `
5855
+ var CSS2 = `
5687
5856
  .dgui-chart-data-button{margin-left:auto;border:0;background:transparent;color:var(--du-muted);font:inherit;cursor:pointer;padding:4px 8px}.dgui-chart-data-button:hover{color:var(--du-accent)}.dgui-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip-path:inset(50%)!important;white-space:nowrap!important;border:0!important}.dgui-canvas{position:relative}.dgui-action-menu{position:absolute;top:6px;right:6px;z-index:2}.dgui-menu-trigger{width:32px;height:32px;border:1px solid var(--du-line);border-radius:8px;background:var(--du-bg);color:var(--du-muted);font-size:24px;line-height:1;cursor:pointer}.dgui-menu-content{position:absolute;top:38px;right:0;display:grid;min-width:156px;padding:5px;border:1px solid var(--du-line);border-radius:10px;background:var(--du-bg);box-shadow:0 6px 20px #0002}.dgui-menu-content button{border:0;border-radius:6px;background:transparent;color:var(--du-ink);padding:9px 12px;text-align:left;font:inherit;white-space:nowrap;cursor:pointer}.dgui-menu-content button:hover{background:var(--du-soft)}.dgui-menu-content button:disabled{opacity:.45;cursor:default}.dgui-action-menu button:focus-visible{outline:2px solid var(--du-accent);outline-offset:2px}
5688
5857
  .dgui-root.dgui-settings{border:0;border-radius:0;box-shadow:none;background:transparent;padding:0;margin:0;max-width:720px;display:flex;flex-direction:column;gap:14px;font-size:13px;line-height:1.65}
5689
5858
  .dgui-settings h3{font-size:14px;font-weight:600;margin:0}.dgui-settings label{font-weight:500}.dgui-settings p{color:var(--du-muted)}
@@ -5865,18 +6034,18 @@ var fenceUiDefinition = {
5865
6034
  start(_c, { event }) {
5866
6035
  return { turn: event.data.turn, blocks: [], settled: false };
5867
6036
  },
5868
- update({ state }, { event }) {
5869
- if (event.type === "turn/end") return { ...state, settled: true };
5870
- if (state.settled) return state;
6037
+ update({ state: state2 }, { event }) {
6038
+ if (event.type === "turn/end") return { ...state2, settled: true };
6039
+ if (state2.settled) return state2;
5871
6040
  const step = event.data.step;
5872
- if (event.type === "llm/retry") return { ...state, invalidated: [...state.invalidated ?? [], step].slice(-48), blocks: state.blocks.filter((b2) => b2.step !== step) };
6041
+ if (event.type === "llm/retry") return { ...state2, invalidated: [...state2.invalidated ?? [], step].slice(-48), blocks: state2.blocks.filter((b2) => b2.step !== step) };
5873
6042
  if (event.type === "assistant/message") {
5874
6043
  const blocks = (event.data.message?.content ?? []).flatMap((b2, index) => b2.type === "text" ? [{ step, index, text: b2.text }] : []);
5875
- return { ...state, everUi: state.everUi || blocks.some((b2) => /(?:```|~~~)(?:dsh-ui|motion-ui|svg)/i.test(b2.text)), anchorSeq: state.anchorSeq ?? event.seq, blocks: [...state.blocks.filter((b2) => b2.step !== step), ...blocks].slice(-48) };
6044
+ return { ...state2, everUi: state2.everUi || blocks.some((b2) => /(?:```|~~~)(?:dsh-ui|motion-ui|svg)/i.test(b2.text)), anchorSeq: state2.anchorSeq ?? event.seq, blocks: [...state2.blocks.filter((b2) => b2.step !== step), ...blocks].slice(-48) };
5876
6045
  }
5877
- const chunk = event.type === "chunkrow/text-chunks" ? { index: event.data.index, text: event.data.texts.join("") } : event.data.chunk, previous = state.blocks.find((b2) => b2.step === step && b2.index === chunk.index), text2 = (previous?.text ?? "") + (chunk.text ?? chunk.delta ?? "");
5878
- if (text2.length > 262144) return state;
5879
- return { ...state, everUi: state.everUi || /(?:```|~~~)(?:dsh-ui|motion-ui|svg)/i.test(text2), anchorSeq: state.anchorSeq ?? event.seq, blocks: [...state.blocks.filter((b2) => b2 !== previous), { step, index: chunk.index, text: text2 }].slice(-48) };
6046
+ const chunk = event.type === "chunkrow/text-chunks" ? { index: event.data.index, text: event.data.texts.join("") } : event.data.chunk, previous = state2.blocks.find((b2) => b2.step === step && b2.index === chunk.index), text3 = (previous?.text ?? "") + (chunk.text ?? chunk.delta ?? "");
6047
+ if (text3.length > 262144) return state2;
6048
+ return { ...state2, everUi: state2.everUi || /(?:```|~~~)(?:dsh-ui|motion-ui|svg)/i.test(text3), anchorSeq: state2.anchorSeq ?? event.seq, blocks: [...state2.blocks.filter((b2) => b2 !== previous), { step, index: chunk.index, text: text3 }].slice(-48) };
5880
6049
  },
5881
6050
  publication: () => "immediate",
5882
6051
  buildViewNode(c) {
@@ -5890,9 +6059,9 @@ var import_react23 = __toESM(require("react"), 1);
5890
6059
  var import_client2 = require("react-dom/client");
5891
6060
 
5892
6061
  // lib/fences.js
5893
- function extractUiFences(text2) {
5894
- if (typeof text2 !== "string" || new TextEncoder().encode(text2).length > 262144) return [];
5895
- const lines = text2.split("\n"), out = [];
6062
+ function extractUiFences(text3) {
6063
+ if (typeof text3 !== "string" || new TextEncoder().encode(text3).length > 262144) return [];
6064
+ const lines = text3.split("\n"), out = [];
5896
6065
  let fence = null;
5897
6066
  for (const line of lines) {
5898
6067
  if (!fence) {
@@ -5934,28 +6103,28 @@ function FenceContent({ document: document2, sessionId, source, settled, sendPro
5934
6103
  }, [document2, sessionId, source, settled]);
5935
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));
5936
6105
  }
5937
- function candidates(state) {
6106
+ function candidates(state2) {
5938
6107
  const steps = /* @__PURE__ */ new Map();
5939
- for (const b2 of state.blocks) {
6108
+ for (const b2 of state2.blocks) {
5940
6109
  if (!steps.has(b2.step)) steps.set(b2.step, []);
5941
6110
  steps.get(b2.step).push(b2);
5942
6111
  }
5943
6112
  const all = [];
5944
6113
  for (const [step, blocks] of steps) {
5945
- const text2 = blocks.sort((a, b2) => a.index - b2.index).map((b2) => b2.text).join("\n");
5946
- for (const [fence, index] of extractUiFences(text2).map((f, i) => [f, i])) {
6114
+ const text3 = blocks.sort((a, b2) => a.index - b2.index).map((b2) => b2.text).join("\n");
6115
+ for (const [fence, index] of extractUiFences(text3).map((f, i) => [f, i])) {
5947
6116
  let spec;
5948
6117
  try {
5949
- if (state.settled) {
6118
+ if (state2.settled) {
5950
6119
  const result = resolveSourceFence(fence.raw, { svg: fence.language === "svg" });
5951
6120
  if (result.marker) continue;
5952
- all.push({ key: `${state.turn}:${step}:${index}`, raw: fence.raw, document: result.document, error: result.valid ? void 0 : result.diagnostics.map((d) => d.message).join("; ") });
6121
+ all.push({ key: `${state2.turn}:${step}:${index}`, raw: fence.raw, document: result.document, error: result.valid ? void 0 : result.diagnostics.map((d) => d.message).join("; ") });
5953
6122
  continue;
5954
6123
  }
5955
6124
  spec = fence.language === "svg" ? fence.complete ? { items: [{ type: "svg", title: "SVG", code: fence.raw }] } : null : pt(fence.raw);
5956
6125
  if (!spec) continue;
5957
6126
  const document2 = validateDocument(spec);
5958
- all.push({ key: `${state.turn}:${step}:${index}`, raw: fence.raw, document: document2 });
6127
+ all.push({ key: `${state2.turn}:${step}:${index}`, raw: fence.raw, document: document2 });
5959
6128
  } catch {
5960
6129
  }
5961
6130
  }
@@ -5976,7 +6145,7 @@ function dispose2(e) {
5976
6145
  e.entries.delete(e.key);
5977
6146
  }
5978
6147
  function FenceNodeView({ node, sessionId, sendPrompt }) {
5979
- const anchor = (0, import_react23.useRef)(null), state = node.data;
6148
+ const anchor = (0, import_react23.useRef)(null), state2 = node.data;
5980
6149
  (0, import_react23.useLayoutEffect)(() => {
5981
6150
  const scroll = anchor.current?.closest("[data-conversation-scroll]");
5982
6151
  if (!scroll) return;
@@ -5986,7 +6155,7 @@ function FenceNodeView({ node, sessionId, sendPrompt }) {
5986
6155
  roots3.set(scroll, entries);
5987
6156
  }
5988
6157
  for (const e2 of entries.values()) if (e2.sessionId !== sessionId) dispose2(e2);
5989
- const key2 = sessionId + ":" + state.turn;
6158
+ const key2 = sessionId + ":" + state2.turn;
5990
6159
  let e = entries.get(key2);
5991
6160
  if (!e) {
5992
6161
  e = { key: key2, entries, sessionId, url: location.href, views: /* @__PURE__ */ new Map(), scroll, seat: anchor.current.closest("[data-chat-turn]") ?? anchor.current };
@@ -6039,10 +6208,10 @@ function FenceNodeView({ node, sessionId, sendPrompt }) {
6039
6208
  e.observer = new MutationObserver(e.queue);
6040
6209
  e.observer.observe(document.body, { subtree: true, childList: true, characterData: true });
6041
6210
  }
6042
- e.state = state;
6211
+ e.state = state2;
6043
6212
  e.sendPrompt = sendPrompt;
6044
6213
  e.queue();
6045
- }, [state, sessionId, sendPrompt]);
6214
+ }, [state2, sessionId, sendPrompt]);
6046
6215
  return h18("span", { ref: anchor, hidden: true });
6047
6216
  }
6048
6217
 
@@ -6076,11 +6245,11 @@ function apply(ctx) {
6076
6245
  ctx.effect(() => {
6077
6246
  const style = document.createElement("style");
6078
6247
  style.dataset.plugin = "dsh-generative-ui";
6079
- style.textContent = CSS + VISUAL_CSS;
6248
+ style.textContent = CSS2 + VISUAL_CSS;
6080
6249
  document.head.append(style);
6081
6250
  return () => style.remove();
6082
6251
  });
6083
- for (const name of ["render_ui", "render_canvas", "render_text", "render_mechanism"]) ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
6252
+ for (const name of ["render_ui", "render_canvas", "render_text", "render_mechanism", "render_scene"]) ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
6084
6253
  name: "tool.call.toolview",
6085
6254
  key: name,
6086
6255
  inject: (sessionId) => ({ sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })