PageSourceSearch

https://www.hamienet.com/assets/PuppetStudio-CgI-FH8Z.js

js hamienet.com collected 2026-10-02 05:01:54 UTC 444,514 bytes, 7,093 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports, R as React } from "./vendor-react-Bay9Y7Lb.js";
2import { d9 as Image$1, aW as X, ba as Info, b2 as Upload, b7 as Check, f0 as PenLine, cM as RefreshCw, cd as Save, cf as Plus, b5 as Trash2, g2 as Undo, g3 as Redo, dt as ZoomIn, ds as ZoomOut, c4 as RotateCcw, bF as ChevronRight, cC as ChevronDown, bA as Eye, ck as Layers } from "./vendor-D0P4XgNj.js";
3import { d as defaultBackgroundConfig, a as defaultBackgroundPresets, m as mergeAllConfigsWithGorilla, c as createAnimator, b as defaultClothingGraphics, g as getDefaultBodyActions, e as defaultActionRules, f as defaultPuppetConfigs, B as BackgroundParticlesCanvas, P as PuppetCharacter, p as parseSvgSocketsAndPlugs } from "./StagePuppetEngine-CmAn6HAX.js";
4import { d as defaultPercussionGraphics, a as defaultMelodicGraphics } from "./InstrumentMappings-UYUlFRMy.js";
5import { l as GM_INSTRUMENTS, G as GM_PERCUSSION_MAP } from "./utils-CEVb7nN1.js";
6import { u as useAnimationFrame } from "./vendor-framer-B-4FZk1Z.js";
7import "./vendor-i18n-BC7ZMXWQ.js";
8import "./synth-Fr-K52Ox.js";
9import "./vendor-react-three-BCww3P1x.js";
10import "./wasm-synth-adapter-DpNGIIyM.js";
11import "./vendor-spessasynth-DH8n6o_V.js";
12import "./vendor-audio-D-wTggbx.js";
13import "./IkMath-D6fi1ppd.js";
14import "./vendor-gsap-50Lx19ak.js";
15import "./index-w5lXls15.js";
16const BODY_PARTS = [
17  { id: "head", label: "Head", required: true },
18  { id: "body", label: "Body (Torso)", required: true },
19  { id: "upper_arm_l", label: "Left Upper Arm (Point Right →)", required: false },
20  { id: "lower_arm_l", label: "Left Lower Arm (Point Right →)", required: false },
21  { id: "hand_l", label: "Left Hand (Point Right →)", required: false },
22  { id: "upper_arm_r", label: "Right Upper Arm (Point Right →)", required: false },
23  { id: "lower_arm_r", label: "Right Lower Arm (Point Right →)", required: false },
24  { id: "hand_r", label: "Right Hand (Point Right →)", required: false },
25  { id: "leg_l", label: "Left Leg (Point Down ↓)", required: false },
26  { id: "foot_l", label: "Left Foot", required: false },
27  { id: "leg_r", label: "Right Leg (Point Down ↓)", required: false },
28  { id: "foot_r", label: "Right Foot", required: false }
29];
30const RiggingBuilder = ({ existingSvg, onApplySvg, onClose }) => {
31  const [images, setImages] = reactExports.useState(() => {
32    const parsed = {};
33    if (existingSvg) {
34      try {
35        const parser = new DOMParser();
36        const doc = parser.parseFromString(`<svg>${existingSvg}</svg>`, "image/svg+xml");
37        BODY_PARTS.forEach((part) => {
38          const group = doc.querySelector(`#${part.id}`);
39          if (group) {
40            const img = group.querySelector("image");
41            if (img) {
42              const href = img.getAttribute("href");
43              const width = parseFloat(img.getAttribute("width") || "0");
44              const height = parseFloat(img.getAttribute("height") || "0");
45              if (href && href.startsWith("data:image/")) {
46                parsed[part.id] = { dataUrl: href, width, height };
47              }
48            }
49          }
50        });
51      } catch (e) {
52        console.error("Error parsing existing SVG", e);
53      }
54    }
55    return parsed;
56  });
57  const [isGenerating, setIsGenerating] = reactExports.useState(false);
58  const handleFileChange = async (partId, file) => {
59    if (!file || !file.type.startsWith("image/")) return;
60    return new Promise((resolve) => {
61      const reader = new FileReader();
62      reader.onload = (e) => {
63        var _a;
64        const dataUrl = (_a = e.target) == null ? void 0 : _a.result;
65        const img = new Image();
66        img.onload = () => {
67          setImages((prev) => ({
68            ...prev,
69            [partId]: { dataUrl, width: img.width, height: img.height }
70          }));
71          resolve();
72        };
73        img.src = dataUrl;
74      };
75      reader.readAsDataURL(file);
76    });
77  };
78  const handleRemove = (partId) => {
79    setImages((prev) => {
80      const next = { ...prev };
81      delete next[partId];
82      return next;
83    });
84  };
85  const generateSvg = () => {
86    var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
87    setIsGenerating(true);
88    try {
89      const bodyW = ((_a = images.body) == null ? void 0 : _a.width) || 120;
90      const bodyH = ((_b = images.body) == null ? void 0 : _b.height) || 150;
91      const headW = ((_c = images.head) == null ? void 0 : _c.width) || 100;
92      const headH = ((_d = images.head) == null ? void 0 : _d.height) || 100;
93      const uawL = ((_e = images.upper_arm_l) == null ? void 0 : _e.width) || 40;
94      const uahL = ((_f = images.upper_arm_l) == null ? void 0 : _f.height) || 15;
95      const lawL = ((_g = images.lower_arm_l) == null ? void 0 : _g.width) || 40;
96      const lahL = ((_h = images.lower_arm_l) == null ? void 0 : _h.height) || 12;
97      const hwL = ((_i = images.hand_l) == null ? void 0 : _i.width) || 20;
98      const hhL = ((_j = images.hand_l) == null ? void 0 : _j.height) || 20;
99      const uawR = ((_k = images.upper_arm_r) == null ? void 0 : _k.width) || 40;
100      const uahR = ((_l = images.upper_arm_r) == null ? void 0 : _l.height) || 15;
101      const lawR = ((_m = images.lower_arm_r) == null ? void 0 : _m.width) || 40;
102      const lahR = ((_n = images.lower_arm_r) == null ? void 0 : _n.height) || 12;
103      const hwR = ((_o = images.hand_r) == null ? void 0 : _o.width) || 20;
104      const hhR = ((_p = images.hand_r) == null ? void 0 : _p.height) || 20;
105      const legwL = ((_q = images.leg_l) == null ? void 0 : _q.width) || 20;
106      const leghL = ((_r = images.leg_l) == null ? void 0 : _r.height) || 60;
107      const footwL = ((_s = images.foot_l) == null ? void 0 : _s.width) || 30;
108      const foothL = ((_t = images.foot_l) == null ? void 0 : _t.height) || 15;
109      const legwR = ((_u = images.leg_r) == null ? void 0 : _u.width) || 20;
110      const leghR = ((_v = images.leg_r) == null ? void 0 : _v.height) || 60;
111      const footwR = ((_w = images.foot_r) == null ? void 0 : _w.width) || 30;
112      const foothR = ((_x = images.foot_r) == null ? void 0 : _x.height) || 15;
113      const shoulderL_X = -bodyW * 0.4;
114      const shoulderL_Y = -bodyH * 0.85;
115      const shoulderR_X = bodyW * 0.4;
116      const shoulderR_Y = -bodyH * 0.85;
117      const elbowL_X = shoulderL_X - uawL;
118      const elbowL_Y = shoulderL_Y;
119      const elbowR_X = shoulderR_X + uawR;
120      const elbowR_Y = shoulderR_Y;
121      const handL_X = elbowL_X - lawL;
122      const handL_Y = elbowL_Y;
123      const handR_X = elbowR_X + lawR;
124      const handR_Y = elbowR_Y;
125      const mouth_X = 0;
126      const mouth_Y = -bodyH - headH * 0.3;
127      let svgParts = "";
128      svgParts += `  <!-- Invisible standard sockets for auto-discovery -->
129`;
130      svgParts += `  <circle id="socket_mouth" cx="${mouth_X}" cy="${mouth_Y}" r="1" opacity="0" />
131`;
132      svgParts += `  <circle id="socket_shoulder_l" cx="${shoulderL_X}" cy="${shoulderL_Y}" r="1" opacity="0" />
133`;
134      svgParts += `  <circle id="socket_shoulder_r" cx="${shoulderR_X}" cy="${shoulderR_Y}" r="1" opacity="0" />
135`;
136      svgParts += `  <circle id="socket_elbow_l" cx="${elbowL_X}" cy="${elbowL_Y}" r="1" opacity="0" />
137`;
138      svgParts += `  <circle id="socket_elbow_r" cx="${elbowR_X}" cy="${elbowR_Y}" r="1" opacity="0" />
139`;
140      svgParts += `  <circle id="socket_hand_l" cx="${handL_X}" cy="${handL_Y}" r="1" opacity="0" />
141`;
142      svgParts += `  <circle id="socket_hand_r" cx="${handR_X}" cy="${handR_Y}" r="1" opacity="0" />
143
144`;
145      const getGroupOrEmpty = (id, content) => {
146        return `  <g id="${id}">${content}</g>
147`;
148      };
149      const legL_X = -bodyW * 0.25;
150      const legL_Y = 0;
151      let legLContent = "";
152      if (images.leg_l) {
153        legLContent += `
154    <image href="${images.leg_l.dataUrl}" x="${-legwL / 2}" y="0" width="${legwL}" height="${leghL}" />`;
155      }
156      let footLContent = "";
157      if (images.foot_l) {
158        footLContent = `<image href="${images.foot_l.dataUrl}" x="${-footwL / 2}" y="${-foothL / 2}" width="${footwL}" height="${foothL}" />`;
159      }
160      legLContent += `
161    <g id="foot_l" transform="translate(0, ${leghL})">${footLContent}</g>
162  `;
163      svgParts += `  <!-- Left Leg & Foot -->
164`;
165      svgParts += `  <g id="leg_l" transform="translate(${legL_X}, ${legL_Y})">${legLContent}</g>
166
167`;
168      const legR_X = bodyW * 0.25;
169      const legR_Y = 0;
170      let legRContent = "";
171      if (images.leg_r) {
172        legRContent += `
173    <image href="${images.leg_r.dataUrl}" x="${-legwR / 2}" y="0" width="${legwR}" height="${leghR}" />`;
174      }
175      let footRContent = "";
176      if (images.foot_r) {
177        footRContent = `<image href="${images.foot_r.dataUrl}" x="${-footwR / 2}" y="${-foothR / 2}" width="${footwR}" height="${foothR}" />`;
178      }
179      legRContent += `
180    <g id="foot_r" transform="translate(0, ${leghR})">${footRContent}</g>
181  `;
182      svgParts += `  <!-- Right Leg & Foot -->
183`;
184      svgParts += `  <g id="leg_r" transform="translate(${legR_X}, ${legR_Y})">${legRContent}</g>
185
186`;
187      svgParts += `  <!-- Torso -->
188`;
189      if (images.body) {
190        svgParts += getGroupOrEmpty("body", `
191    <image href="${images.body.dataUrl}" x="${-bodyW / 2}" y="${-bodyH}" width="${bodyW}" height="${bodyH}" />
192  `);
193      } else {
194        svgParts += `  <g id="body"></g>
195`;
196      }
197      svgParts += `  <!-- Head -->
198`;
199      if (images.head) {
200        svgParts += getGroupOrEmpty("head", `
201    <image href="${images.head.dataUrl}" x="${-headW / 2}" y="${-bodyH - headH}" width="${headW}" height="${headH}" />
202  `);
203      } else {
204        svgParts += `  <g id="head"></g>
205`;
206      }
207      svgParts += `  <!-- Arm hierarchies (flat sibling segments for IK calculations) -->
208`;
209      svgParts += `  <g id="shoulder_l" opacity="0"></g>
210`;
211      svgParts += `  <g id="shoulder_r" opacity="0"></g>
212`;
213      svgParts += `  <g id="elbow_l" opacity="0"></g>
214`;
215      svgParts += `  <g id="elbow_r" opacity="0"></g>
216`;
217      if (images.upper_arm_l) {
218        svgParts += getGroupOrEmpty("upper_arm_l", `
219    <image href="${images.upper_arm_l.dataUrl}" x="0" y="${-uahL / 2}" width="${uawL}" height="${uahL}" />
220  `);
221      } else {
222        svgParts += `  <g id="upper_arm_l"></g>
223`;
224      }
225      if (images.upper_arm_r) {
226        svgParts += getGroupOrEmpty("upper_arm_r", `
227    <image href="${images.upper_arm_r.dataUrl}" x="0" y="${-uahR / 2}" width="${uawR}" height="${uahR}" />
228  `);
229      } else {
230        svgParts += `  <g id="upper_arm_r"></g>
231`;
232      }
233      if (images.lower_arm_l) {
234        svgParts += getGroupOrEmpty("lower_arm_l", `
235    <image href="${images.lower_arm_l.dataUrl}" x="0" y="${-lahL / 2}" width="${lawL}" height="${lahL}" />
236  `);
237      } else {
238        svgParts += `  <g id="lower_arm_l"></g>
239`;
240      }
241      if (images.lower_arm_r) {
242        svgParts += getGroupOrEmpty("lower_arm_r", `
243    <image href="${images.lower_arm_r.dataUrl}" x="0" y="${-lahR / 2}" width="${lawR}" height="${lahR}" />
244  `);
245      } else {
246        svgParts += `  <g id="lower_arm_r"></g>
247`;
248      }
249      let handLContent = "";
250      if (images.hand_l) {
251        handLContent += `
252    <image href="${images.hand_l.dataUrl}" x="${-hwL / 2}" y="${-hhL / 2}" width="${hwL}" height="${hhL}" />`;
253      }
254      handLContent += `
255    <!-- Dynamic Instrument Injection Point -->
256    <g id="instrument" transform="translate(0,0)"></g>
257  `;
258      svgParts += `  <g id="hand_l">${handLContent}</g>
259`;
260      if (images.hand_r) {
261        svgParts += getGroupOrEmpty("hand_r", `
262    <image href="${images.hand_r.dataUrl}" x="${-hwR / 2}" y="${-hhR / 2}" width="${hwR}" height="${hhR}" />
263  `);
264      } else {
265        svgParts += `  <g id="hand_r"></g>
266`;
267      }
268      onApplySvg(svgParts);
269    } catch (e) {
270      console.error("Error generating SVG", e);
271      alert("An error occurred while generating the SVG.");
272    } finally {
273      setIsGenerating(false);
274    }
275  };
276  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 bg-black/80 z-50 flex items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#111] border border-zinc-800 rounded-xl shadow-2xl w-full max-w-4xl max-h-[90vh] flex flex-col", children: [
277    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-zinc-800 bg-zinc-900/50", children: [
278      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
279        /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-lg font-bold text-white flex items-center gap-2", children: [
280          /* @__PURE__ */ jsxRuntimeExports.jsx(Image$1, { size: 20, className: "text-indigo-400" }),
281          "Rigging Assistant (PNG to SVG Wrapper)"
282        ] }),
283        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-1", children: "Upload separate PNG images for body parts. The system will automatically bundle them into a compatible SVG." })
284      ] }),
285      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "p-2 text-zinc-400 hover:text-white rounded hover:bg-zinc-800 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 20 }) })
286    ] }),
287    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-indigo-950/20 border-b border-indigo-500/20 text-indigo-200 text-sm flex gap-3", children: [
288      /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { size: 20, className: "shrink-0 mt-0.5 text-indigo-400" }),
289      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
290        /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Important Rigging Rules:" }),
291        /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc ml-5 mt-1 opacity-90 space-y-0.5", children: [
292          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
293            "All ",
294            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Arm" }),
295            " pieces (upper, lower, hands) must be drawn horizontally pointing to the right (→)."
296          ] }),
297          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
298            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Legs" }),
299            " should be drawn vertically pointing down (↓)."
300          ] }),
301          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
302            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Body" }),
303            " and ",
304            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Head" }),
305            " should face forward."
306          ] }),
307          /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: "Transparent PNGs are highly recommended." })
308        ] })
309      ] })
310    ] }),
311    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-4 bg-[#0a0a0a] custom-scrollbar", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-4", children: BODY_PARTS.map((part) => {
312      const hasImage = !!images[part.id];
313      return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `border ${hasImage ? "border-emerald-500/50 bg-emerald-950/10" : "border-zinc-800 bg-[#111]"} rounded-lg p-3 relative transition-colors`, children: [
314        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs font-bold text-zinc-300 mb-2 truncate", children: [
315          part.label,
316          " ",
317          part.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-rose-500", children: "*" })
318        ] }),
319        hasImage ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative group rounded bg-black border border-zinc-800 h-24 flex items-center justify-center overflow-hidden", children: [
320          /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: images[part.id].dataUrl, className: "max-w-full max-h-full object-contain", alt: part.label }),
321          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2", children: [
322            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "bg-indigo-600 hover:bg-indigo-500 text-white p-2 rounded-full shadow-lg cursor-pointer transition-colors", title: "Replace Image", children: [
323              /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 16 }),
324              /* @__PURE__ */ jsxRuntimeExports.jsx(
325                "input",
326                {
327                  type: "file",
328                  accept: "image/png,image/jpeg,image/webp",
329                  className: "hidden",
330                  onChange: (e) => {
331                    var _a;
332                    const file = (_a = e.target.files) == null ? void 0 : _a[0];
333                    if (file) handleFileChange(part.id, file);
334                    e.target.value = "";
335                  }
336                }
337              )
338            ] }),
339            /* @__PURE__ */ jsxRuntimeExports.jsx(
340              "button",
341              {
342                onClick: () => handleRemove(part.id),
343                className: "bg-rose-600 hover:bg-rose-500 text-white p-2 rounded-full shadow-lg transition-colors",
344                title: "Remove Image",
345                children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 16 })
346              }
347            )
348          ] })
349        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "border-2 border-dashed border-zinc-700 hover:border-indigo-500 hover:bg-indigo-500/5 rounded h-24 flex flex-col items-center justify-center cursor-pointer transition-colors text-zinc-500 hover:text-indigo-400", children: [
350          /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 20, className: "mb-2" }),
351          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium", children: "Upload PNG" }),
352          /* @__PURE__ */ jsxRuntimeExports.jsx(
353            "input",
354            {
355              type: "file",
356              accept: "image/png,image/jpeg,image/webp",
357              className: "hidden",
358              onChange: (e) => {
359                var _a;
360                const file = (_a = e.target.files) == null ? void 0 : _a[0];
361                if (file) handleFileChange(part.id, file);
362                e.target.value = "";
363              }
364            }
365          )
366        ] })
367      ] }, part.id);
368    }) }) }),
369    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border-t border-zinc-800 bg-zinc-900/50 flex justify-end gap-3", children: [
370      /* @__PURE__ */ jsxRuntimeExports.jsx(
371        "button",
372        {
373          onClick: onClose,
374          className: "px-4 py-2 text-sm font-bold text-zinc-400 hover:text-white hover:bg-zinc-800 rounded transition-colors",
375          children: "Cancel"
376        }
377      ),
378      /* @__PURE__ */ jsxRuntimeExports.jsx(
379        "button",
380        {
381          onClick: generateSvg,
382          disabled: isGenerating || !images["head"] || !images["body"],
383          className: "flex items-center gap-2 px-6 py-2 bg-indigo-600 hover:bg-indigo-500 disabled:bg-zinc-800 disabled:text-zinc-500 text-white text-sm font-bold rounded transition-colors",
384          children: isGenerating ? "Generating..." : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
385            /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 16 }),
386            " Generate & Apply SVG"
387          ] })
388        }
389      )
390    ] })
391  ] }) });
392};
393function getFamilyDefaultPlugs(family) {
394  switch (family) {
395    case "family_14_percussive":
396    case "percussion":
397    case "family_1_chromatic_percussion":
398      return ["hand_l", "hand_r"];
399    case "family_0_pianos":
400    case "family_2_organs":
401    case "family_10_synth_lead":
402    case "family_11_synth_pad":
403    case "family_12_synth_effects":
404    case "keys":
405      return ["keys_l", "keys_r"];
406    case "family_3_guitars":
407    case "family_4_basses":
408    case "family_5_strings":
409    case "family_6_ensemble":
410    case "family_13_ethnic":
411    case "strings":
412      return ["fret_hand", "strum_hand"];
413    case "family_7_brass":
414    case "family_8_reed":
415    case "family_9_pipe":
416    case "winds":
417      return ["mouthpiece", "keys_l", "keys_r"];
418    case "family_15_sound_effects":
419    default:
420      return ["hand_l", "hand_r"];
421  }
422}
423function PuppetStudio() {
424  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y;
425  const [activeTab, setActiveTab] = reactExports.useState("characters");
426  const [backgroundConfig, setBackgroundConfig] = reactExports.useState(defaultBackgroundConfig);
427  const [backgroundPresets, setBackgroundPresets] = reactExports.useState(defaultBackgroundPresets);
428  const [selectedPresetId, setSelectedPresetId] = reactExports.useState(null);
429  const [customBackgrounds, setCustomBackgrounds] = reactExports.useState([]);
430  const [configs, setConfigs] = reactExports.useState({});
431  const [selectedId, setSelectedId] = reactExports.useState(null);
432  const [instrumentConfigs, setInstrumentConfigs] = reactExports.useState({ melodic: {}, percussion: {} });
433  const [selectedInstKey, setSelectedInstKey] = reactExports.useState(null);
434  const [clothingConfigs, setClothingConfigs] = reactExports.useState({});
435  const [selectedClothingId, setSelectedClothingId] = reactExports.useState(null);
436  const [saveStatus, setSaveStatus] = reactExports.useState("idle");
437  const [loading, setLoading] = reactExports.useState(true);
438  const [jsonError, setJsonError] = reactExports.useState(null);
439  const [showSkeleton, setShowSkeleton] = reactExports.useState(false);
440  const [showActionPaths, setShowActionPaths] = reactExports.useState(false);
441  const [isOptionsCollapsed, setIsOptionsCollapsed] = reactExports.useState(false);
442  const [viewBoxZoom, setViewBoxZoom] = reactExports.useState(1);
443  const [uploadError, setUploadError] = reactExports.useState(null);
444  const [showRiggingBuilder, setShowRiggingBuilder] = reactExports.useState(false);
445  const [selectedPartId, setSelectedPartId] = reactExports.useState(null);
446  const [viewZoom, setViewZoom] = reactExports.useState(1);
447  const [viewPanX, setViewPanX] = reactExports.useState(0);
448  const [viewPanY, setViewPanY] = reactExports.useState(0);
449  const [undoStack, setUndoStack] = reactExports.useState([]);
450  const [redoStack, setRedoStack] = reactExports.useState([]);
451  const [globalActions, setGlobalActions] = reactExports.useState([]);
452  const [globalActionRules, setGlobalActionRules] = reactExports.useState([]);
453  const [selectedActionId, setSelectedActionId] = reactExports.useState(null);
454  const [selectedActionRuleId, setSelectedActionRuleId] = reactExports.useState(null);
455  const [selectedChannelIdx, setSelectedChannelIdx] = reactExports.useState(null);
456  const pushUndo = () => {
457    const snapshot = {
458      configs: JSON.parse(JSON.stringify(configs)),
459      instrumentConfigs: JSON.parse(JSON.stringify(instrumentConfigs)),
460      clothingConfigs: JSON.parse(JSON.stringify(clothingConfigs)),
461      backgroundConfig: JSON.parse(JSON.stringify(backgroundConfig)),
462      backgroundPresets: JSON.parse(JSON.stringify(backgroundPresets))
463    };
464    setUndoStack((prev) => [...prev.slice(-49), snapshot]);
465    setRedoStack([]);
466  };
467  const undo = () => {
468    if (undoStack.length === 0) return;
469    const previous = undoStack[undoStack.length - 1];
470    const current = {
471      configs: JSON.parse(JSON.stringify(configs)),
472      instrumentConfigs: JSON.parse(JSON.stringify(instrumentConfigs)),
473      clothingConfigs: JSON.parse(JSON.stringify(clothingConfigs)),
474      backgroundConfig: JSON.parse(JSON.stringify(backgroundConfig)),
475      backgroundPresets: JSON.parse(JSON.stringify(backgroundPresets))
476    };
477    setRedoStack((prev) => [...prev, current]);
478    setUndoStack((prev) => prev.slice(0, -1));
479    setConfigs(previous.configs);
480    setInstrumentConfigs(previous.instrumentConfigs);
481    setClothingConfigs(previous.clothingConfigs);
482    setBackgroundConfig(previous.backgroundConfig);
483    setBackgroundPresets(previous.backgroundPresets);
484  };
485  const redo = () => {
486    if (redoStack.length === 0) return;
487    const next = redoStack[redoStack.length - 1];
488    const current = {
489      configs: JSON.parse(JSON.stringify(configs)),
490      instrumentConfigs: JSON.parse(JSON.stringify(instrumentConfigs)),
491      clothingConfigs: JSON.parse(JSON.stringify(clothingConfigs)),
492      backgroundConfig: JSON.parse(JSON.stringify(backgroundConfig)),
493      backgroundPresets: JSON.parse(JSON.stringify(backgroundPresets))
494    };
495    setUndoStack((prev) => [...prev, current]);
496    setRedoStack((prev) => prev.slice(0, -1));
497    setConfigs(next.configs);
498    setInstrumentConfigs(next.instrumentConfigs);
499    setClothingConfigs(next.clothingConfigs);
500    setBackgroundConfig(next.backgroundConfig);
501    setBackgroundPresets(next.backgroundPresets);
502  };
503  const currentConfigToEdit = reactExports.useMemo(() => {
504    if (selectedPresetId === null) return backgroundConfig;
505    const preset = backgroundPresets.find((p) => p.id === selectedPresetId);
506    return preset ? preset.config : backgroundConfig;
507  }, [selectedPresetId, backgroundConfig, backgroundPresets]);
508  const updateActiveConfig = (updater) => {
509    pushUndo();
510    if (selectedPresetId === null) {
511      setBackgroundConfig((prev) => updater(prev));
512    } else {
513      setBackgroundPresets((prev) => prev.map((p) => {
514        if (p.id === selectedPresetId) {
515          return { ...p, config: updater(p.config) };
516        }
517        return p;
518      }));
519    }
520  };
521  const handleConfigChange = (id, updates) => {
522    setConfigs((prev) => ({ ...prev, [id]: { ...prev[id], ...updates } }));
523  };
524  const handleIkChange = (id, arm, field, value) => {
525    setConfigs((prev) => {
526      const current = prev[id];
527      const updatedArm = { ...current[arm] || {}, [field]: value };
528      return { ...prev, [id]: { ...current, [arm]: updatedArm } };
529    });
530  };
531  const [previewCharId, setPreviewCharId] = reactExports.useState("percussion");
532  const [previewInstKey, setPreviewInstKey] = reactExports.useState(null);
533  const [previewClothingId, setPreviewClothingId] = reactExports.useState(null);
534  reactExports.useEffect(() => {
535    var _a2;
536    if (activeTab === "instruments" && selectedInstKey) {
537      const type = selectedInstKey.startsWith("m_") ? "melodic" : "percussion";
538      const index = parseInt(selectedInstKey.split("_")[1]);
539      const instDef = (_a2 = instrumentConfigs[type]) == null ? void 0 : _a2[index];
540      if (instDef && instDef.characterId) {
541        setPreviewCharId(instDef.characterId);
542      } else {
543        let targetCharId = "family_0_pianos";
544        if (selectedInstKey.startsWith("p_")) {
545          targetCharId = "percussion";
546        } else {
547          const program = parseInt(selectedInstKey.split("_")[1]);
548          if (!isNaN(program)) {
549            const familyIndex = Math.floor(program / 8);
550            const familyKeys = [
551              "family_0_pianos",
552              "family_1_chromatic_percussion",
553              "family_2_organs",
554              "family_3_guitars",
555              "family_4_basses",
556              "family_5_strings",
557              "family_6_ensemble",
558              "family_7_brass",
559              "family_8_reed",
560              "family_9_pipe",
561              "family_10_synth_lead",
562              "family_11_synth_pad",
563              "family_12_synth_effects",
564              "family_13_ethnic",
565              "family_14_percussive",
566              "family_15_sound_effects"
567            ];
568            targetCharId = familyKeys[familyIndex] || "family_0_pianos";
569          }
570        }
571        setPreviewCharId(targetCharId);
572      }
573      if (instDef && instDef.clothingId) {
574        setPreviewClothingId(instDef.clothingId);
575      } else {
576        setPreviewClothingId(null);
577      }
578    }
579  }, [selectedInstKey, activeTab, instrumentConfigs]);
580  const [isPlaying, setIsPlaying] = reactExports.useState(false);
581  const [playMode, setPlayMode] = reactExports.useState("instrument");
582  const [collapsedGroups, setCollapsedGroups] = reactExports.useState({ character: true, clothing: true, accessory: true });
583  const [expandedClothingParts, setExpandedClothingParts] = reactExports.useState({});
584  const [expandedCharacterParts, setExpandedCharacterParts] = reactExports.useState({});
585  const getDisplayClassName = (part) => {
586    var _a2, _b2;
587    const customContent = (_a2 = selectedClothingDef == null ? void 0 : selectedClothingDef.parts) == null ? void 0 : _a2[part];
588    if (customContent) {
589      const match = customContent.match(/class=["']([^"']+)["']/i);
590      if (match) return ` (${match[1]})`;
591    }
592    const defaultDef = selectedClothingId ? defaultClothingGraphics[selectedClothingId] : null;
593    const defaultContent = (_b2 = defaultDef == null ? void 0 : defaultDef.parts) == null ? void 0 : _b2[part];
594    if (defaultContent) {
595      const match = defaultContent.match(/class=["']([^"']+)["']/i);
596      if (match) return ` (${match[1]})`;
597    }
598    const clothId = (selectedClothingDef == null ? void 0 : selectedClothingDef.id) || selectedClothingId || "custom";
599    let classLabel = `clothing-${clothId}-${part}`;
600    if (clothId === "tuxedo") {
601      if (part.includes("arm")) classLabel = "clothing-tuxedo-sleeve";
602      else if (part.includes("leg")) classLabel = "clothing-tuxedo-pants";
603    } else if (clothId === "dress") {
604      if (part.includes("arm")) classLabel = "clothing-dress-sleeve";
605    }
606    return ` (${classLabel})`;
607  };
608  const [tempo, setTempo] = reactExports.useState(120);
609  const [visibility, setVisibility] = reactExports.useState({
610    head: true,
611    body: true,
612    upper_arm_l: true,
613    lower_arm_l: true,
614    hand_l: true,
615    upper_arm_r: true,
616    lower_arm_r: true,
617    hand_r: true,
618    leg_l: true,
619    leg_r: true,
620    foot_l: true,
621    foot_r: true,
622    instrument: true,
623    clothing_body: true,
624    clothing_head: true,
625    clothing_upper_arm_l: true,
626    clothing_lower_arm_l: true,
627    clothing_hand_l: true,
628    clothing_upper_arm_r: true,
629    clothing_lower_arm_r: true,
630    clothing_hand_r: true,
631    clothing_leg_l: true,
632    clothing_leg_r: true,
633    clothing_foot_l: true,
634    clothing_foot_r: true
635  });
636  const [editMode, setEditMode] = reactExports.useState("none");
637  const [draggingPoint, setDraggingPoint] = reactExports.useState(null);
638  const mergedConfigs = reactExports.useMemo(() => mergeAllConfigsWithGorilla(configs), [configs]);
639  const selectedConfig = selectedId ? mergedConfigs[selectedId] : null;
640  const selectedInstType = (selectedInstKey == null ? void 0 : selectedInstKey.startsWith("m_")) ? "melodic" : "percussion";
641  const selectedInstIndex = selectedInstKey ? parseInt(selectedInstKey.split("_")[1]) : 0;
642  const selectedInstSvg = selectedInstKey ? instrumentConfigs[selectedInstType][selectedInstIndex] : null;
643  const selectedClothingDef = selectedClothingId ? clothingConfigs[selectedClothingId] : null;
644  reactExports.useEffect(() => {
645    const defaultVisibility = {
646      head: true,
647      body: true,
648      upper_arm_l: true,
649      lower_arm_l: true,
650      hand_l: true,
651      upper_arm_r: true,
652      lower_arm_r: true,
653      hand_r: true,
654      leg_l: true,
655      leg_r: true,
656      foot_l: true,
657      foot_r: true,
658      instrument: true,
659      clothing_body: true,
660      clothing_head: true,
661      clothing_upper_arm_l: true,
662      clothing_lower_arm_l: true,
663      clothing_hand_l: true,
664      clothing_upper_arm_r: true,
665      clothing_lower_arm_r: true,
666      clothing_hand_r: true,
667      clothing_leg_l: true,
668      clothing_leg_r: true,
669      clothing_foot_l: true,
670      clothing_foot_r: true
671    };
672    const configVisibility = (selectedConfig == null ? void 0 : selectedConfig.visibility) || defaultVisibility;
673    const keys = Object.keys(defaultVisibility);
674    const hasMismatch = keys.some((key) => {
675      const localVal = visibility[key] !== false;
676      const configVal = configVisibility[key] !== false;
677      return localVal !== configVal;
678    });
679    if (hasMismatch) {
680      setVisibility({
681        ...defaultVisibility,
682        ...configVisibility
683      });
684    }
685  }, [selectedConfig, visibility]);
686  const editingInstKey = activeTab === "instruments" ? selectedInstKey : previewInstKey;
687  const editingInstType = (editingInstKey == null ? void 0 : editingInstKey.startsWith("m_")) ? "melodic" : "percussion";
688  const editingInstIndex = editingInstKey ? parseInt(editingInstKey.split("_")[1]) : 0;
689  const [tickId, setTickId] = reactExports.useState(0);
690  const animatorRef = reactExports.useRef(null);
691  const lastEventTimeRef = reactExports.useRef(0);
692  const mockEventsRef = reactExports.useRef([]);
693  const activePreviewConfig = activeTab === "characters" ? selectedConfig : previewCharId ? mergedConfigs[previewCharId] : null;
694  const isInherited = (field, subfield) => {
695    var _a2;
696    if (!selectedConfig || selectedConfig.id === "percussion") return false;
697    const raw = configs[selectedConfig.id];
698    if (!raw) return false;
699    if (subfield) {
700      return ((_a2 = raw[field]) == null ? void 0 : _a2[subfield]) === void 0;
701    }
702    return raw[field] === void 0;
703  };
704  const getInstDef = (key) => {
705    var _a2;
706    if (!key) return null;
707    const type = key.startsWith("m_") ? "melodic" : "percussion";
708    const index = parseInt(key.split("_")[1]);
709    return ((_a2 = instrumentConfigs[type]) == null ? void 0 : _a2[index]) || null;
710  };
711  const activePreviewInst = activeTab === "characters" ? getInstDef(previewInstKey) : selectedInstSvg;
712  const activePreviewClothing = activeTab === "clothing" ? selectedClothingDef : previewClothingId ? clothingConfigs[previewClothingId] : null;
713  const previewSvgRef = reactExports.useRef(null);
714  const getProjectedCoords = (selector, localPt) => {
715    if (!previewSvgRef.current || !activePreviewConfig) return null;
716    const charScale = activePreviewConfig.scale ?? 1;
717    const anchorX = activePreviewConfig.anchorX ?? 0;
718    const anchorY = activePreviewConfig.anchorY ?? 0;
719    return {
720      x: (localPt.x + anchorX) * charScale,
721      y: (localPt.y + anchorY) * charScale
722    };
723  };
724  const getProjectedPt = (selector, localPt) => {
725    const projected = getProjectedCoords(selector, localPt);
726    return projected || { x: localPt.x, y: localPt.y };
727  };
728  const getInstrumentLabel = (type, indexStr) => {
729    const num = parseInt(indexStr);
730    if (type === "melodic") return `${num} - ${GM_INSTRUMENTS[num] || `Prog ${num}`}`;
731    return `${num} - ${GM_PERCUSSION_MAP[num] || `Perc ${num}`}`;
732  };
733  const handleZOrderChange = (part, val) => {
734    const instKey = activeTab === "characters" ? previewInstKey : selectedInstKey;
735    if (!instKey) return;
736    const type = instKey.startsWith("m_") ? "melodic" : "percussion";
737    const index = parseInt(instKey.split("_")[1]);
738    setInstrumentConfigs((prev) => {
739      const typeObj = prev[type];
740      const instObj = typeObj[index] || {};
741      const zo = { ...instObj.zOrder || {} };
742      zo[part] = val;
743      return {
744        ...prev,
745        [type]: {
746          ...typeObj,
747          [index]: {
748            ...instObj,
749            zOrder: zo
750          }
751        }
752      };
753    });
754  };
755  const handleClothingMouseDown = (jointId, e) => {
756    var _a2, _b2;
757    if (document.activeElement instanceof HTMLElement) {
758      document.activeElement.blur();
759    }
760    if (activeTab !== "clothing" || !selectedClothingDef) return;
761    e.stopPropagation();
762    e.preventDefault();
763    setSelectedPartId(jointId);
764    setExpandedClothingParts((prev) => ({ ...prev, [jointId]: true }));
765    if (e.detail === 2) {
766      pushUndo();
767      const currentTransform2 = ((_a2 = selectedClothingDef.transforms) == null ? void 0 : _a2[jointId]) || { scaleX: 1, scaleY: 1, rotation: 0 };
768      setClothingConfigs((prev) => ({
769        ...prev,
770        [selectedClothingDef.id]: {
771          ...selectedClothingDef,
772          transforms: {
773            ...selectedClothingDef.transforms,
774            [jointId]: {
775              ...currentTransform2,
776              x: 0,
777              y: 0
778            }
779          }
780        }
781      }));
782      return;
783    }
784    pushUndo();
785    const targetEl = e.target;
786    const wrapper = targetEl.closest(".custom-clothing-mount");
787    if (!wrapper) return;
788    const svg = wrapper.ownerSVGElement || wrapper.closest("svg");
789    if (!svg) return;
790    const wrapperCTM = wrapper.getScreenCTM();
791    if (!wrapperCTM) return;
792    const inverseMatrix = wrapperCTM.inverse();
793    const pt = svg.createSVGPoint();
794    pt.x = e.clientX;
795    pt.y = e.clientY;
796    const localP = pt.matrixTransform(inverseMatrix);
797    const currentTransform = ((_b2 = selectedClothingDef.transforms) == null ? void 0 : _b2[jointId]) || { x: 0, y: 0 };
798    setDraggingPoint({
799      target: "clothing",
800      jointId,
801      startX: currentTransform.x || 0,
802      startY: currentTransform.y || 0,
803      startLocalX: localP.x,
804      startLocalY: localP.y,
805      inverseMatrix
806    });
807  };
808  const handleBodyPartMouseDown = (partId, e) => {
809    var _a2, _b2, _c2;
810    if (document.activeElement instanceof HTMLElement) {
811      document.activeElement.blur();
812    }
813    if (activeTab !== "characters" || !selectedConfig) return;
814    e.stopPropagation();
815    e.preventDefault();
816    setSelectedPartId(partId);
817    if (e.detail === 2) {
818      pushUndo();
819      handleConfigChange(selectedConfig.id, {
820        transforms: {
821          ...selectedConfig.transforms,
822          [partId]: {
823            ...((_a2 = selectedConfig.transforms) == null ? void 0 : _a2[partId]) || { scaleX: 1, scaleY: 1, rotation: 0 },
824            x: 0,
825            y: 0
826          }
827        }
828      });
829      return;
830    }
831    pushUndo();
832    const svg = previewSvgRef.current;
833    if (!svg) return;
834    const pt = svg.createSVGPoint();
835    pt.x = e.clientX;
836    pt.y = e.clientY;
837    const svgP = pt.matrixTransform((_b2 = svg.getScreenCTM()) == null ? void 0 : _b2.inverse());
838    const currentTransform = ((_c2 = selectedConfig.transforms) == null ? void 0 : _c2[partId]) || { x: 0, y: 0 };
839    setDraggingPoint({
840      target: "bodyPart",
841      jointId: partId,
842      startX: currentTransform.x || 0,
843      startY: currentTransform.y || 0,
844      mouseStartX: svgP.x,
845      mouseStartY: svgP.y
846    });
847  };
848  const handleInstrumentMouseDown = (partType, e) => {
849    if (document.activeElement instanceof HTMLElement) {
850      document.activeElement.blur();
851    }
852    if (activeTab !== "instruments" || !selectedInstKey) return;
853    e.stopPropagation();
854    e.preventDefault();
855    setSelectedPartId(partType === "main" ? "instrument" : "accessory");
856    const instType = selectedInstKey.startsWith("m_") ? "melodic" : "percussion";
857    const instIndex = parseInt(selectedInstKey.split("_")[1]);
858    const instDef = instrumentConfigs[instType][instIndex];
859    if (!instDef) return;
860    let currentDef;
861    if (typeof instDef === "string") {
862      currentDef = {
863        svgContent: instDef,
864        mountPoint: "body"
865      };
866    } else {
867      currentDef = instDef;
868    }
869    const isAccessory = partType === "accessory";
870    const currentTransform = isAccessory ? currentDef.accessoryTransform || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 } : currentDef.transform || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
871    if (e.detail === 2) {
872      pushUndo();
873      const resetTransform = {
874        ...currentTransform,
875        x: 0,
876        y: 0
877      };
878      setInstrumentConfigs((prev) => ({
879        ...prev,
880        [instType]: {
881          ...prev[instType],
882          [instIndex]: {
883            ...currentDef,
884            [isAccessory ? "accessoryTransform" : "transform"]: resetTransform
885          }
886        }
887      }));
888      return;
889    }
890    pushUndo();
891    const targetEl = e.target;
892    const wrapper = targetEl.closest(".custom-instrument-mount");
893    if (!wrapper) return;
894    const svg = wrapper.ownerSVGElement || wrapper.closest("svg");
895    if (!svg) return;
896    const wrapperCTM = wrapper.getScreenCTM();
897    if (!wrapperCTM) return;
898    const inverseMatrix = wrapperCTM.inverse();
899    const pt = svg.createSVGPoint();
900    pt.x = e.clientX;
901    pt.y = e.clientY;
902    const localP = pt.matrixTransform(inverseMatrix);
903    setDraggingPoint({
904      target: partType === "main" ? "instrument" : "accessory",
905      startX: currentTransform.x || 0,
906      startY: currentTransform.y || 0,
907      startLocalX: localP.x,
908      startLocalY: localP.y,
909      inverseMatrix
910    });
911  };
912  const isPlayingRef = reactExports.useRef(isPlaying);
913  isPlayingRef.current = isPlaying;
914  const playModeRef = reactExports.useRef(playMode);
915  playModeRef.current = playMode;
916  const activePreviewConfigRef = reactExports.useRef(activePreviewConfig);
917  activePreviewConfigRef.current = activePreviewConfig;
918  const activePreviewInstRef = reactExports.useRef(activePreviewInst);
919  activePreviewInstRef.current = activePreviewInst;
920  const tempoRef = reactExports.useRef(tempo);
921  tempoRef.current = tempo;
922  const globalActionsRef = reactExports.useRef(globalActions);
923  globalActionsRef.current = globalActions;
924  const selectedActionIdRef = reactExports.useRef(selectedActionId);
925  selectedActionIdRef.current = selectedActionId;
926  reactExports.useEffect(() => {
927    if (activePreviewConfig) {
928      animatorRef.current = createAnimator(activePreviewConfig);
929    } else {
930      animatorRef.current = null;
931    }
932  }, [activePreviewConfig, activeTab]);
933  useAnimationFrame((time) => {
934    const currentConfig = activePreviewConfigRef.current;
935    const currentInst = activePreviewInstRef.current;
936    const currentIsPlaying = isPlayingRef.current;
937    const currentTempo = tempoRef.current;
938    const currentPlayMode = playModeRef.current;
939    if (!animatorRef.current || !currentConfig) return;
940    animatorRef.current.forceWave = currentIsPlaying && currentPlayMode === "wave" && activeTab !== "actions";
941    animatorRef.current.disableRandomIdle = true;
942    if (activeTab === "actions") {
943      animatorRef.current.actionEngine.setActions(globalActionsRef.current);
944      if (currentIsPlaying) {
945        animatorRef.current.actionEngine.forceActionId = selectedActionIdRef.current;
946      } else {
947        animatorRef.current.actionEngine.forceActionId = null;
948        animatorRef.current.actionEngine.clearActive();
949      }
950    } else {
951      if (currentIsPlaying && currentPlayMode === "wave") {
952        animatorRef.current.actionEngine.forceActionId = "idle_wave";
953      } else {
954        animatorRef.current.actionEngine.forceActionId = null;
955        if (!currentIsPlaying) {
956          animatorRef.current.actionEngine.clearActive();
957        }
958      }
959    }
960    let activeEvents = [];
961    if (currentIsPlaying && currentPlayMode !== "wave" && activeTab !== "actions") {
962      const interval = 6e4 / currentTempo;
963      if (time - lastEventTimeRef.current > interval) {
964        const noteNum = 40 + Math.floor(Math.random() * 40);
965        mockEventsRef.current = [{
966          noteNumber: noteNum,
967          velocity: 100,
968          // Hard hit
969          startTime: time,
970          duration: 200
971        }];
972        lastEventTimeRef.current = time;
973      }
974      activeEvents = mockEventsRef.current.filter((e) => time < e.startTime + e.duration);
975      mockEventsRef.current = activeEvents;
976    }
977    const isSongPlaying = activeTab === "actions" ? currentIsPlaying : currentIsPlaying && currentPlayMode !== "wave";
978    animatorRef.current.tick(time, activeEvents, currentTempo / 60, isSongPlaying, currentInst);
979    setTickId((prev) => prev + 1);
980  });
981  const containerRef = reactExports.useRef(null);
982  reactExports.useEffect(() => {
983    const el = containerRef.current;
984    if (!el) return;
985    const handleWheel = (e) => {
986      e.preventDefault();
987      const zoomIntensity = 0.1;
988      setViewZoom((prev) => {
989        const delta = -e.deltaY;
990        let nextZoom = prev + (delta > 0 ? zoomIntensity : -zoomIntensity) * prev;
991        nextZoom = Math.max(0.25, Math.min(8, nextZoom));
992        return nextZoom;
993      });
994    };
995    el.addEventListener("wheel", handleWheel, { passive: false });
996    return () => {
997      el.removeEventListener("wheel", handleWheel);
998    };
999  }, [activePreviewConfig, activeTab]);
1000  reactExports.useEffect(() => {
1001    const handleGlobalKeyDown = (e) => {
1002      var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2;
1003      if (((_a2 = document.activeElement) == null ? void 0 : _a2.tagName) === "INPUT" || ((_b2 = document.activeElement) == null ? void 0 : _b2.tagName) === "TEXTAREA" || ((_c2 = document.activeElement) == null ? void 0 : _c2.tagName) === "SELECT") {
1004        return;
1005      }
1006      if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "z") {
1007        e.preventDefault();
1008        undo();
1009      } else if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "y") {
1010        e.preventDefault();
1011        redo();
1012      }
1013      if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
1014        if (!selectedPartId) return;
1015        e.preventDefault();
1016        const step = e.shiftKey ? 10 : 1;
1017        let dx = 0;
1018        let dy = 0;
1019        if (e.key === "ArrowLeft") dx = -step;
1020        if (e.key === "ArrowRight") dx = step;
1021        if (e.key === "ArrowUp") dy = -step;
1022        if (e.key === "ArrowDown") dy = step;
1023        pushUndo();
1024        if (activeTab === "clothing" && selectedClothingDef) {
1025          if (editMode.startsWith("clothing_plug_")) {
1026            const parts = editMode.split("_");
1027            const pointKey = parts[2];
1028            const partName = parts.slice(3).join("_");
1029            const currentPlugs = selectedClothingDef.plugs || {};
1030            const partPlugs = currentPlugs[partName] || {};
1031            const val = partPlugs[pointKey] || { x: 0, y: 0 };
1032            const newX = (val.x || 0) + dx;
1033            const newY = (val.y || 0) + dy;
1034            setClothingConfigs((prev) => ({
1035              ...prev,
1036              [selectedClothingDef.id]: {
1037                ...selectedClothingDef,
1038                plugs: {
1039                  ...currentPlugs,
1040                  [partName]: {
1041                    ...partPlugs,
1042                    [pointKey]: { x: newX, y: newY }
1043                  }
1044                }
1045              }
1046            }));
1047          } else {
1048            const currentTransform = ((_d2 = selectedClothingDef.transforms) == null ? void 0 : _d2[selectedPartId]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
1049            let localDx = dx;
1050            let localDy = dy;
1051            const wrapper = document.querySelector(`.custom-clothing-mount[data-target-joint="${selectedPartId}"]`);
1052            if (wrapper) {
1053              const matrix = (_g2 = (_f2 = (_e2 = wrapper.transform) == null ? void 0 : _e2.baseVal) == null ? void 0 : _f2.consolidate()) == null ? void 0 : _g2.matrix;
1054              if (matrix) {
1055                const a = matrix.a;
1056                const b = matrix.b;
1057                const denom = a * a + b * b;
1058                if (denom > 1e-4) {
1059                  localDx = (dx * a + dy * b) / denom;
1060                  localDy = (dy * a - dx * b) / denom;
1061                }
1062              }
1063            }
1064            setClothingConfigs((prev) => ({
1065              ...prev,
1066              [selectedClothingDef.id]: {
1067                ...selectedClothingDef,
1068                transforms: {
1069                  ...selectedClothingDef.transforms,
1070                  [selectedPartId]: {
1071                    ...currentTransform,
1072                    x: (currentTransform.x || 0) + localDx,
1073                    y: (currentTransform.y || 0) + localDy
1074                  }
1075                }
1076              }
1077            }));
1078          }
1079        } else if (activeTab === "characters" && selectedConfig) {
1080          if (editMode.startsWith("socket_")) {
1081            const socketName = editMode.replace("socket_", "");
1082            const svgCoords = parseSvgSocketsAndPlugs(selectedConfig.svgContent);
1083            const svgVal = svgCoords[`socket_${socketName}`];
1084            const configVal = (_h2 = selectedConfig.sockets) == null ? void 0 : _h2[socketName];
1085            const val = configVal || svgVal || { x: 0, y: 0 };
1086            const newX = (val.x || 0) + dx;
1087            const newY = (val.y || 0) + dy;
1088            const currentSockets = selectedConfig.sockets || {};
1089            handleConfigChange(selectedConfig.id, {
1090              sockets: {
1091                ...currentSockets,
1092                [socketName]: { x: newX, y: newY }
1093              }
1094            });
1095          } else {
1096            const currentTransform = ((_i2 = selectedConfig.transforms) == null ? void 0 : _i2[selectedPartId]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
1097            handleConfigChange(selectedConfig.id, {
1098              transforms: {
1099                ...selectedConfig.transforms,
1100                [selectedPartId]: {
1101                  ...currentTransform,
1102                  x: (currentTransform.x || 0) + dx,
1103                  y: (currentTransform.y || 0) + dy
1104                }
1105              }
1106            });
1107          }
1108        } else if (activeTab === "instruments" && selectedInstKey) {
1109          const instType = selectedInstKey.startsWith("m_") ? "melodic" : "percussion";
1110          const instIndex = parseInt(selectedInstKey.split("_")[1]);
1111          const instObj = instrumentConfigs[instType][instIndex];
1112          if (instObj) {
1113            let currentDef;
1114            if (typeof instObj === "string") {
1115              currentDef = {
1116                svgContent: instObj,
1117                mountPoint: "body"
1118              };
1119            } else {
1120              currentDef = instObj;
1121            }
1122            if (editMode.startsWith("plug_")) {
1123              const plugName = editMode.replace("plug_", "");
1124              const svgCoords = parseSvgSocketsAndPlugs(currentDef.svgContent);
1125              const svgVal = svgCoords[`plug_${plugName}`];
1126              const configVal = (_j2 = currentDef.plugs) == null ? void 0 : _j2[plugName];
1127              const val = configVal || svgVal || { x: 0, y: 0 };
1128              const newX = (val.x || 0) + dx;
1129              const newY = (val.y || 0) + dy;
1130              const updated = {
1131                ...currentDef,
1132                plugs: {
1133                  ...currentDef.plugs || {},
1134                  [plugName]: { ...((_k2 = currentDef.plugs) == null ? void 0 : _k2[plugName]) || {}, x: newX, y: newY }
1135                }
1136              };
1137              setInstrumentConfigs((prev) => ({
1138                ...prev,
1139                [instType]: {
1140                  ...prev[instType],
1141                  [instIndex]: updated
1142                }
1143              }));
1144            } else {
1145              const isAccessory = selectedPartId === "accessory";
1146              const transformField = isAccessory ? "accessoryTransform" : "transform";
1147              const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
1148              let localDx = dx;
1149              let localDy = dy;
1150              const partType = isAccessory ? "accessory" : "main";
1151              const wrapper = document.querySelector(`.custom-instrument-mount[data-instrument-part="${partType}"]`);
1152              if (wrapper) {
1153                const matrix = (_n2 = (_m2 = (_l2 = wrapper.transform) == null ? void 0 : _l2.baseVal) == null ? void 0 : _m2.consolidate()) == null ? void 0 : _n2.matrix;
1154                if (matrix) {
1155                  const a = matrix.a;
1156                  const b = matrix.b;
1157                  const denom = a * a + b * b;
1158                  if (denom > 1e-4) {
1159                    localDx = (dx * a + dy * b) / denom;
1160                    localDy = (dy * a - dx * b) / denom;
1161                  }
1162                }
1163              }
1164              setInstrumentConfigs((prev) => ({
1165                ...prev,
1166                [instType]: {
1167                  ...prev[instType],
1168                  [instIndex]: {
1169                    ...currentDef,
1170                    [transformField]: {
1171                      ...currentTransform,
1172                      x: (currentTransform.x || 0) + localDx,
1173                      y: (currentTransform.y || 0) + localDy
1174                    }
1175                  }
1176                }
1177              }));
1178            }
1179          }
1180        }
1181      }
1182    };
1183    window.addEventListener("keydown", handleGlobalKeyDown);
1184    return () => {
1185      window.removeEventListener("keydown", handleGlobalKeyDown);
1186    };
1187  }, [selectedPartId, activeTab, configs, instrumentConfigs, clothingConfigs, selectedClothingDef, selectedConfig, editMode, selectedInstKey, pushUndo, handleConfigChange]);
1188  reactExports.useEffect(() => {
1189    if (activeTab === "instruments") {
1190      setSelectedPartId("instrument");
1191    } else if (activeTab === "clothing") {
1192      setSelectedPartId("body");
1193    } else {
1194      setSelectedPartId("body");
1195    }
1196  }, [activeTab]);
1197  reactExports.useEffect(() => {
1198    loadConfigs();
1199  }, []);
1200  const loadConfigs = async () => {
1201    setLoading(true);
1202    try {
1203      const [charRes, instRes, clothRes, bgRes, presetsRes] = await Promise.all([
1204        fetch("/api/admin/settings/stage_characters_config", { headers: { "Authorization": "Bearer " + localStorage.getItem("admin_token") } }),
1205        fetch("/api/admin/settings/stage_instruments_config", { headers: { "Authorization": "Bearer " + localStorage.getItem("admin_token") } }),
1206        fetch("/api/admin/settings/stage_clothing_config", { headers: { "Authorization": "Bearer " + localStorage.getItem("admin_token") } }),
1207        fetch("/api/admin/settings/stage_background_config", { headers: { "Authorization": "Bearer " + localStorage.getItem("admin_token") } }),
1208        fetch("/api/admin/settings/stage_background_presets", { headers: { "Authorization": "Bearer " + localStorage.getItem("admin_token") } })
1209      ]);
1210      if (charRes.ok) {
1211        const data = await charRes.json();
1212        if (data && data.value && Object.keys(data.value).length > 0) {
1213          setConfigs(data.value);
1214          setSelectedId(Object.keys(data.value)[0]);
1215          setPreviewCharId(Object.keys(data.value)[0]);
1216        } else seedDefaults();
1217      } else seedDefaults();
1218      if (instRes.ok) {
1219        const data = await instRes.json();
1220        if (data && data.value && data.value.melodic && data.value.percussion) {
1221          setInstrumentConfigs(data.value);
1222          setSelectedInstKey("m_0");
1223        } else seedInstDefaults();
1224      } else seedInstDefaults();
1225      if (clothRes.ok) {
1226        const data = await clothRes.json();
1227        if (data && data.value && Object.keys(data.value).length > 0) {
1228          const merged = { ...defaultClothingGraphics };
1229          Object.entries(data.value).forEach(([id, savedDef]) => {
1230            if (merged[id]) {
1231              merged[id] = {
1232                ...merged[id],
1233                ...savedDef,
1234                parts: {
1235                  ...merged[id].parts,
1236                  ...savedDef.parts
1237                },
1238                gluing: (() => {
1239                  const defaultGluing = merged[id].gluing || {};
1240                  const savedGluing = savedDef.gluing || {};
1241                  const mergedGluing = { ...defaultGluing };
1242                  Object.entries(savedGluing).forEach(([part, partGlue]) => {
1243                    mergedGluing[part] = {
1244                      ...defaultGluing[part] || {},
1245                      ...partGlue
1246                    };
1247                  });
1248                  return mergedGluing;
1249                })()
1250              };
1251            } else {
1252              merged[id] = savedDef;
1253            }
1254          });
1255          setClothingConfigs(merged);
1256          setSelectedClothingId(Object.keys(merged)[0]);
1257          setPreviewClothingId(Object.keys(merged)[0]);
1258        } else seedClothingDefaults();
1259      } else seedClothingDefaults();
1260      if (bgRes.ok) {
1261        const data = await bgRes.json();
1262        if (data && data.value) {
1263          setBackgroundConfig(data.value);
1264        } else setBackgroundConfig(defaultBackgroundConfig);
1265      } else setBackgroundConfig(defaultBackgroundConfig);
1266      if (presetsRes.ok) {
1267        const data = await presetsRes.json();
1268        if (data && data.value && Array.isArray(data.value)) {
1269          setBackgroundPresets(data.value);
1270        } else setBackgroundPresets(defaultBackgroundPresets);
1271      } else setBackgroundPresets(defaultBackgroundPresets);
1272      const customBgRes = await fetch("/api/admin/backgrounds", { headers: { "Authorization": "Bearer " + localStorage.getItem("admin_token") } });
1273      if (customBgRes.ok) {
1274        let customBgs = await customBgRes.json();
1275        const presetBgs = defaultBackgroundPresets.map((p) => {
1276          var _a2;
1277          return (_a2 = p.config.image) == null ? void 0 : _a2.url;
1278        }).filter(Boolean);
1279        customBgs = [.../* @__PURE__ */ new Set([...presetBgs, ...customBgs])];
1280        setCustomBackgrounds(customBgs);
1281      }
1282    } catch (e) {
1283      console.error("Failed to load configs", e);
1284      seedDefaults();
1285      seedInstDefaults();
1286      seedClothingDefaults();
1287    } finally {
1288      setLoading(false);
1289    }
1290  };
1291  reactExports.useEffect(() => {
1292    if (Object.keys(configs).length > 0 && globalActions.length === 0) {
1293      const firstWithActions = Object.values(configs).find((c) => c.actions && c.actions.length > 0);
1294      setGlobalActions((firstWithActions == null ? void 0 : firstWithActions.actions) ? JSON.parse(JSON.stringify(firstWithActions.actions)) : getDefaultBodyActions());
1295      const firstWithRules = Object.values(configs).find((c) => c.actionRules && c.actionRules.length > 0);
1296      setGlobalActionRules((firstWithRules == null ? void 0 : firstWithRules.actionRules) ? JSON.parse(JSON.stringify(firstWithRules.actionRules)) : defaultActionRules.map((r) => ({ ...r })));
1297    }
1298  }, [configs]);
1299  const seedDefaults = () => {
1300    setConfigs(defaultPuppetConfigs);
1301    setSelectedId(Object.keys(defaultPuppetConfigs)[0]);
1302    setPreviewCharId(Object.keys(defaultPuppetConfigs)[0]);
1303  };
1304  const seedInstDefaults = () => {
1305    setInstrumentConfigs({ melodic: { ...defaultMelodicGraphics }, percussion: { ...defaultPercussionGraphics } });
1306    setSelectedInstKey("m_0");
1307  };
1308  const seedClothingDefaults = () => {
1309    setClothingConfigs(defaultClothingGraphics);
1310    setSelectedClothingId(Object.keys(defaultClothingGraphics)[0]);
1311    setPreviewClothingId(Object.keys(defaultClothingGraphics)[0]);
1312  };
1313  const handleSave = async () => {
1314    setSaveStatus("saving");
1315    try {
1316      await Promise.all([
1317        fetch("/api/admin/settings/stage_characters_config", {
1318          method: "POST",
1319          headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("admin_token") },
1320          body: JSON.stringify({ value: configs })
1321        }),
1322        fetch("/api/admin/settings/stage_instruments_config", {
1323          method: "POST",
1324          headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("admin_token") },
1325          body: JSON.stringify({ value: instrumentConfigs })
1326        }),
1327        fetch("/api/admin/settings/stage_clothing_config", {
1328          method: "POST",
1329          headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("admin_token") },
1330          body: JSON.stringify({ value: clothingConfigs })
1331        }),
1332        fetch("/api/admin/settings/stage_background_config", {
1333          method: "POST",
1334          headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("admin_token") },
1335          body: JSON.stringify({ value: backgroundConfig })
1336        }),
1337        fetch("/api/admin/settings/stage_background_presets", {
1338          method: "POST",
1339          headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("admin_token") },
1340          body: JSON.stringify({ value: backgroundPresets })
1341        })
1342      ]);
1343      setSaveStatus("saved");
1344      setTimeout(() => setSaveStatus("idle"), 3e3);
1345    } catch (e) {
1346      console.error(e);
1347      setSaveStatus("failed");
1348      setTimeout(() => setSaveStatus("idle"), 3e3);
1349    }
1350  };
1351  const handleSvgUpload = (e, id) => {
1352    var _a2;
1353    const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
1354    if (!file) return;
1355    const reader = new FileReader();
1356    reader.onload = (event) => {
1357      var _a3;
1358      try {
1359        const content = (_a3 = event.target) == null ? void 0 : _a3.result;
1360        if (!content.includes("<svg") || !content.includes("</svg>")) {
1361          setUploadError("Invalid SVG file format");
1362          return;
1363        }
1364        const match = content.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i);
1365        const svgInner = match ? match[1] : content;
1366        handleConfigChange(id, { svgContent: svgInner });
1367        setUploadError(null);
1368      } catch (err) {
1369        setUploadError("Failed to parse SVG file");
1370      }
1371    };
1372    reader.readAsText(file);
1373  };
1374  const handleInstSvgUpload = (e) => {
1375    var _a2;
1376    const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
1377    if (!file || !selectedInstKey) return;
1378    const reader = new FileReader();
1379    reader.onload = (event) => {
1380      var _a3;
1381      try {
1382        const content = (_a3 = event.target) == null ? void 0 : _a3.result;
1383        if (!content.includes("<svg") || !content.includes("</svg>")) {
1384          setUploadError("Invalid SVG file format");
1385          return;
1386        }
1387        const match = content.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i);
1388        const svgInner = match ? match[1] : content;
1389        const isAccessory = selectedPartId === "accessory";
1390        setInstrumentConfigs((prev) => {
1391          const typeObj = prev[selectedInstType];
1392          const instObj = typeObj[selectedInstIndex];
1393          let currentDef;
1394          if (typeof instObj === "string") {
1395            currentDef = {
1396              svgContent: instObj,
1397              mountPoint: "body"
1398            };
1399          } else if (!instObj) {
1400            currentDef = {
1401              svgContent: "",
1402              mountPoint: "body"
1403            };
1404          } else {
1405            currentDef = instObj;
1406          }
1407          if (isAccessory) {
1408            currentDef = {
1409              ...currentDef,
1410              accessorySvg: svgInner,
1411              accessoryMountPoint: currentDef.accessoryMountPoint || "hand_r"
1412            };
1413          } else {
1414            currentDef = {
1415              ...currentDef,
1416              svgContent: svgInner
1417            };
1418          }
1419          return {
1420            ...prev,
1421            [selectedInstType]: {
1422              ...typeObj,
1423              [selectedInstIndex]: currentDef
1424            }
1425          };
1426        });
1427        setUploadError(null);
1428      } catch (err) {
1429        setUploadError("Failed to parse SVG file");
1430      }
1431    };
1432    reader.readAsText(file);
1433  };
1434  const handleGlobalBgUpload = async (e) => {
1435    var _a2;
1436    const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
1437    if (!file) return;
1438    setUploadError(null);
1439    const formData = new FormData();
1440    formData.append("background", file);
1441    try {
1442      const res = await fetch("/api/admin/upload-global-background", {
1443        method: "POST",
1444        headers: {
1445          "Authorization": "Bearer " + localStorage.getItem("admin_token")
1446        },
1447        body: formData
1448      });
1449      if (!res.ok) {
1450        const errData = await res.json();
1451        throw new Error(errData.error || "Upload failed");
1452      }
1453      const data = await res.json();
1454      setCustomBackgrounds((prev) => [...prev, data.url]);
1455      updateActiveConfig((prev) => ({
1456        ...prev,
1457        type: "image",
1458        image: {
1459          ...prev.image || { size: "cover", position: "center center", repeat: "no-repeat", blur: 0 },
1460          url: data.url
1461        }
1462      }));
1463      alert("Custom background uploaded successfully. You can select it in the gallery below.");
1464    } catch (err) {
1465      setUploadError(err.message || "Failed to upload image");
1466    }
1467  };
1468  const handleDeleteGlobalBg = async (bgUrl) => {
1469    var _a2;
1470    if (!confirm("Are you sure you want to delete this custom background option from the gallery?")) return;
1471    const filename = bgUrl.split("/").pop();
1472    if (!filename) return;
1473    try {
1474      const res = await fetch(`/api/admin/backgrounds/${filename}`, {
1475        method: "DELETE",
1476        headers: {
1477          "Authorization": "Bearer " + localStorage.getItem("admin_token")
1478        }
1479      });
1480      if (!res.ok) {
1481        const errData = await res.json();
1482        throw new Error(errData.error || "Delete failed");
1483      }
1484      setCustomBackgrounds((prev) => prev.filter((url) => url !== bgUrl));
1485      if (((_a2 = currentConfigToEdit.image) == null ? void 0 : _a2.url) === bgUrl) {
1486        updateActiveConfig((prev) => ({
1487          ...prev,
1488          type: "image",
1489          image: {
1490            ...prev.image || {},
1491            url: "/assets/visualizers/orchestra/background-forest.webp"
1492          }
1493        }));
1494      }
1495      alert("Custom background deleted successfully.");
1496    } catch (err) {
1497      setUploadError(err.message || "Failed to delete background");
1498    }
1499  };
1500  const handleJsonUpdate = (id, jsonStr) => {
1501    try {
1502      const parsed = JSON.parse(jsonStr);
1503      handleConfigChange(id, { noteMap: parsed });
1504      setJsonError(null);
1505    } catch (e) {
1506      setJsonError(e.message);
1507    }
1508  };
1509  const handleAdd = () => {
1510    const id = `new_puppet_${Date.now()}`;
1511    const defaultCfg = Object.values(defaultPuppetConfigs)[0];
1512    setConfigs((prev) => ({ ...prev, [id]: { ...defaultCfg, id, name: "New Puppet" } }));
1513    setSelectedId(id);
1514  };
1515  const handleDelete = (id) => {
1516    if (!confirm("Are you sure?")) return;
1517    const newConfigs = { ...configs };
1518    delete newConfigs[id];
1519    setConfigs(newConfigs);
1520    if (selectedId === id) setSelectedId(Object.keys(newConfigs)[0] || null);
1521  };
1522  if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-8 text-zinc-400", children: "Loading Puppet Studio..." });
1523  const JOINTS_LIST = ["body", "head", "foot_r", "foot_l", "hand_l", "hand_r", "upper_arm_l", "upper_arm_r", "lower_arm_l", "lower_arm_r", "leg_l", "leg_r"];
1524  const TRIGGER_LABELS_MAP = { playing: "While Playing", idle: "While Idle", note_on: "On Note", always: "Always" };
1525  const WAVEFORM_LABELS_MAP = { sine: "Sine", cosine: "Cosine", triangle: "Triangle", abs_sine: "Abs Sine 
1525(Tap)" };
1526  const addBodyAction = () => {
1527    pushUndo();
1528    const newId = `custom_${Date.now()}`;
1529    const a = { id: newId, name: "New Action", category: "body", trigger: "playing", priority: 50, duration: 2e3, tempoSync: false, loop: true, blendInMs: 500, blendOutMs: 500, channels: [], affectedJoints: [] };
1530    setGlobalActions((prev) => [...prev, a]);
1531    setSelectedActionId(newId);
1532  };
1533  const removeBodyAction = (id) => {
1534    pushUndo();
1535    setGlobalActions((prev) => prev.filter((a) => a.id !== id));
1536    if (selectedActionId === id) setSelectedActionId(null);
1537  };
1538  const cloneBodyAction = (id) => {
1539    pushUndo();
1540    const src = globalActions.find((a) => a.id === id);
1541    if (!src) return;
1542    const newId = `${src.id}_copy`;
1543    setGlobalActions((prev) => [...prev, { ...JSON.parse(JSON.stringify(src)), id: newId, name: src.name + " Copy" }]);
1544    setSelectedActionId(newId);
1545  };
1546  const updateBodyAction = (id, updates) => setGlobalActions((prev) => prev.map((a) => a.id === id ? { ...a, ...updates } : a));
1547  const addBodyChannel = (actionId) => {
1548    const ch = { joint: "body", property: "y", type: "wave", waveform: "sine", frequency: 1, amplitude: 10, amplitudeBase: 0, intensityScale: 0, phase: 0, offset: 0 };
1549    setGlobalActions((prev) => prev.map((a) => a.id === actionId ? { ...a, channels: [...a.channels, ch] } : a));
1550  };
1551  const removeBodyChannel = (actionId, idx) => {
1552    setGlobalActions((prev) => prev.map((a) => a.id === actionId ? { ...a, channels: a.channels.filter((_, i) => i !== idx) } : a));
1553    if (selectedChannelIdx === idx) setSelectedChannelIdx(null);
1554  };
1555  const updateBodyChannel = (actionId, idx, updates) => setGlobalActions((prev) => prev.map((a) => a.id === actionId ? { ...a, channels: a.channels.map((c, i) => i === idx ? { ...c, ...updates } : c) } : a));
1556  const addBodyKeyframe = (actionId, channelIdx) => {
1557    var _a2;
1558    const action = globalActions.find((a) => a.id === actionId);
1559    const channel = action == null ? void 0 : action.channels[channelIdx];
1560    if (!channel) return;
1561    const times = ((_a2 = channel.keyframes) == null ? void 0 : _a2.map((k) => k.time)) || [];
1562    const t = times.length > 0 ? Math.min(1, (times[times.length - 1] || 0) + 0.1) : 0.5;
1563    const nkf = [...channel.keyframes || [], { time: Math.round(t * 100) / 100, value: 0, easing: "sine" }].sort((a, b) => a.time - b.time);
1564    updateBodyChannel(actionId, channelIdx, { keyframes: nkf });
1565  };
1566  const addBodyRule = () => {
1567    const r = { id: `rule_${Date.now()}`, name: "New Rule", actionIds: [], enabled: true, condition: { scope: "all" } };
1568    setGlobalActionRules((prev) => [...prev, r]);
1569    setSelectedActionRuleId(r.id);
1570  };
1571  const updateBodyRule = (id, updates) => setGlobalActionRules((prev) => prev.map((r) => r.id === id ? { ...r, ...updates } : r));
1572  const removeBodyRule = (id) => {
1573    setGlobalActionRules((prev) => prev.filter((r) => r.id !== id));
1574    if (selectedActionRuleId === id) setSelectedActionRuleId(null);
1575  };
1576  const saveActionsToConfigs = () => {
1577    setConfigs((prev) => {
1578      const next = { ...prev };
1579      Object.keys(next).forEach((cid) => {
1580        next[cid] = { ...next[cid], actions: globalActions, actionRules: globalActionRules };
1581      });
1582      return next;
1583    });
1584  };
1585  const bg = currentConfigToEdit || defaultBackgroundConfig;
1586  let bgStyle = {};
1587  if (bg.type === "color") {
1588    bgStyle = { backgroundColor: bg.color };
1589  } else if (bg.type === "gradient") {
1590    const { type, angle, stops } = bg.gradient;
1591    const stopStr = stops.slice().sort((a, b) => a.offset - b.offset).map((s) => `${s.color} ${s.offset}%`).join(", ");
1592    if (type === "radial") {
1593      bgStyle = { background: `radial-gradient(circle, ${stopStr})` };
1594    } else {
1595      bgStyle = { background: `linear-gradient(${angle}deg, ${stopStr})` };
1596    }
1597  } else if (bg.type === "image") {
1598    bgStyle = { backgroundColor: bg.color || "#050505" };
1599  }
1600  const imageStyle = bg.type === "image" ? {
1601    backgroundImage: `url("${bg.image.url}")`,
1602    backgroundSize: bg.image.size,
1603    backgroundPosition: bg.image.position,
1604    backgroundRepeat: bg.image.repeat,
1605    filter: bg.image.blur ? `blur(${bg.image.blur}px)` : void 0,
1606    transform: bg.image.blur ? "scale(1.05)" : void 0
1607  } : {};
1608  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full bg-[#0a0a0a] text-zinc-200", children: [
1609    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-4 border-b border-zinc-800 bg-[#111]", children: [
1610      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1611        /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-xl font-bold text-white flex items-center gap-2", children: [
1612          /* @__PURE__ */ jsxRuntimeExports.jsx(PenLine, { size: 20, className: "text-indigo-400" }),
1613          " Puppet Studio"
1614        ] }),
1615        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-400", children: "Configure SVGs and IK Mappings for Real-Time Stage Performance" })
1616      ] }),
1617      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1618        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: loadConfigs, className: "p-2 rounded bg-zinc-800 hover:bg-zinc-700 text-zinc-300", title: "Reload from server", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 18 }) }),
1619        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => {
1620          if (confirm("Reset to defaults? This will erase all your custom puppets AND instruments!")) {
1621            seedDefaults();
1622            seedInstDefaults();
1623            seedClothingDefaults();
1624          }
1625        }, className: "px-4 py-2 bg-red-600/80 hover:bg-red-500 text-white rounded font-bold", children: "Reset to Defaults" }),
1626        /* @__PURE__ */ jsxRuntimeExports.jsxs(
1627          "button",
1628          {
1629            onClick: handleSave,
1630            disabled: saveStatus === "saving",
1631            className: `flex items-center gap-2 px-4 py-2 text-white rounded font-bold transition-all duration-200 disabled:opacity-50 ${saveStatus === "saved" ? "bg-emerald-600 hover:bg-emerald-500" : saveStatus === "failed" ? "bg-rose-600 hover:bg-rose-500" : "bg-indigo-600 hover:bg-indigo-500"}`,
1632            children: [
1633              /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 18 }),
1634              " ",
1635              saveStatus === "saving" ? "Saving..." : saveStatus === "saved" ? "Saved" : saveStatus === "failed" ? "Failed" : "Save All"
1636            ]
1637          }
1638        )
1639      ] })
1640    ] }),
1641    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-4 px-4 bg-[#111] border-b border-zinc-800", children: [
1642      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("characters"), className: `px-4 py-3 text-sm font-bold border-b-2 ${activeTab === "characters" ? "border-indigo-500 text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`, children: "Characters" }),
1643      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("instruments"), className: `px-4 py-3 text-sm font-bold border-b-2 ${activeTab === "instruments" ? "border-indigo-500 text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`, children: "Instruments" }),
1644      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("clothing"), className: `px-4 py-3 text-sm font-bold border-b-2 ${activeTab === "clothing" ? "border-indigo-500 text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`, children: "Clothing" }),
1645      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => {
1646        setActiveTab("actions");
1647        setShowActionPaths(true);
1648      }, className: `px-4 py-3 text-sm font-bold border-b-2 ${activeTab === "actions" ? "border-indigo-500 text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`, children: "Actions" }),
1649      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("rules"), className: `px-4 py-3 text-sm font-bold border-b-2 ${activeTab === "rules" ? "border-indigo-500 text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`, children: "Rigging Rules" }),
1650      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("background"), className: `px-4 py-3 text-sm font-bold border-b-2 ${activeTab === "background" ? "border-indigo-500 text-indigo-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`, children: "Background" })
1651    ] }),
1652    activeTab === "rules" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-8 bg-[#0a0a0a] text-zinc-300", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-4xl mx-auto space-y-8", children: [
1653      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1654        /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-2xl font-bold text-white mb-4", children: "Core Rigging Rules" }),
1655        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400", children: "To make sure your parts work perfectly in the Puppet Engine system, follow these core rules when designing your SVG or PNG assets." })
1656      ] }),
1657      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#111] border border-zinc-800 p-6 rounded-lg space-y-4", children: [
1658        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-indigo-400", children: "1. Naming & Organization (The SVG wrapper)" }),
1659        /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
1660          "You will need to wrap your PNGs in an SVG file and assign specific ",
1661          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-emerald-400 bg-zinc-900 px-1 rounded", children: "id" }),
1662          " attributes to groups. The system looks for these EXACT IDs to know what to animate:"
1663        ] }),
1664        /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc ml-6 space-y-1 text-sm font-mono text-zinc-400", children: [
1665          /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: 'id="head"' }),
1666          /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: 'id="body"' }),
1667          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1668            'id="upper_arm_l" ',
1669            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Left upper arm)" })
1670          ] }),
1671          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1672            'id="lower_arm_l" ',
1673            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Left lower arm)" })
1674          ] }),
1675          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1676            'id="hand_l" ',
1677            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Left hand)" })
1678          ] }),
1679          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1680            'id="upper_arm_r" ',
1681            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Right upper arm)" })
1682          ] }),
1683          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1684            'id="lower_arm_r" ',
1685            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Right lower arm)" })
1686          ] }),
1687          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1688            'id="hand_r" ',
1689            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Right hand)" })
1690          ] }),
1691          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1692            'id="leg_l" ',
1693            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Left leg)" })
1694          ] }),
1695          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1696            'id="foot_l" ',
1697            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Left foot)" })
1698          ] }),
1699          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1700            'id="leg_r" ',
1701            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Right leg)" })
1702          ] }),
1703          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1704            'id="foot_r" ',
1705            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-sans", children: "(Right foot)" })
1706          ] })
1707        ] }),
1708        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs bg-zinc-900 border border-zinc-800 p-2 rounded text-zinc-500", children: "Note: For the arms, left (_l) and right (_r) are from the character's perspective." })
1709      ] }),
1710      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#111] border border-zinc-800 p-6 rounded-lg space-y-4", children: [
1711        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-indigo-400", children: "2. Orientation & Default Poses" }),
1712        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "For the mathematical inverse kinematics (IK) engine to calculate joints correctly:" }),
1713        /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc ml-6 space-y-3", children: [
1714          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1715            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Body & Head:" }),
1716            " Should be drawn upright facing forward."
1717          ] }),
1718          /* @__P
1718URE__ */ jsxRuntimeExports.jsxs("li", { children: [
1719            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Legs:" }),
1720            " Should be drawn vertically (pointing down)."
1721          ] }),
1722          /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1723            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Arms (Crucial):" }),
1724            " All arm parts (upper_arm, lower_arm, hand) MUST be drawn perfectly horizontal, pointing to the right, as if the character is T-posing but with only their right side outstretched.",
1725            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 pl-4 border-l-2 border-indigo-500 text-sm text-zinc-400 space-y-2", children: [
1726              /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
1727                /* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: "Why?" }),
1728                " The engine assumes a 0-degree rotation is pointing right. If you draw the arm pointing down, the engine will mathematically bend it wrong when playing an instrument."
1729              ] }),
1730              /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
1731                /* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: "Wait, even the left arm?" }),
1732                " Yes! Draw the left arm pieces pointing right as well. The engine will flip/rotate them to the correct position when attaching them to the body."
1733              ] })
1734            ] })
1735          ] })
1736        ] })
1737      ] }),
1738      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#111] border border-zinc-800 p-6 rounded-lg space-y-4", children: [
1739        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-indigo-400", children: "3. Origins and Pivot Points (Sockets)" }),
1740        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Because you are wrapping PNGs, you don't get natural center-points from vector shapes. The system will try to pivot items based on their bounding boxes (e.g., lower arm pivots at the edge of the upper arm)." }),
1741        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-indigo-950/20 border border-indigo-500/20 p-4 rounded text-sm text-indigo-200", children: [
1742          /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Pro-tip:" }),
1743          " In your SVG, you can define invisible circles with specific IDs to tell the engine EXACTLY where joints should connect:",
1744          /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-none mt-2 space-y-1 font-mono text-xs", children: [
1745            /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1746              '<circle id="socket_shoulder_l" cx="..." cy="..." r="1" opacity="0" /> ',
1747              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-sans text-zinc-400", children: "(Where the left arm attaches to the body)" })
1748            ] }),
1749            /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
1750              '<circle id="socket_mouth" cx="..." cy="..." r="1" opacity="0" /> ',
1751              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-sans text-zinc-400", children: "(Where instruments like flutes attach)" })
1752            ] })
1753          ] })
1754        ] })
1755      ] }),
1756      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#111] border border-zinc-800 p-6 rounded-lg space-y-4", children: [
1757        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-indigo-400", children: "4. Canvas Size" }),
1758        /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
1759          "A square canvas is best (e.g., ",
1760          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-emerald-400 bg-zinc-900 px-1 rounded", children: "800x800" }),
1761          " or ",
1762          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-emerald-400 bg-zinc-900 px-1 rounded", children: "1000x1000" }),
1763          "). Make sure your parts are scaled consistently relative to each other."
1764        ] })
1765      ] })
1766    ] }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
1767      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-64 resize-x overflow-y-auto overflow-x-hidden min-w-[200px] max-w-[500px] border-r border-zinc-800 bg-[#0d0d0d] flex flex-col shrink-0 custom-scrollbar", children: [
1768        activeTab === "characters" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1769          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 border-b border-zinc-800 flex flex-col gap-2", children: [
1770            /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleAdd, className: "w-full flex items-center justify-center gap-2 px-3 py-2 bg-zinc-800 hover:bg-zinc-700 text-white rounded text-sm", children: [
1771              /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }),
1772              " Add Puppet"
1773            ] }),
1774            /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => setShowRiggingBuilder(true), className: "w-full flex items-center justify-center gap-2 px-3 py-2 bg-indigo-600/20 hover:bg-indigo-600/30 border border-indigo-500/30 text-indigo-300 hover:text-indigo-200 rounded text-sm font-bold transition-colors", children: [
1775              /* @__PURE__ */ jsxRuntimeExports.jsx(Image$1, { size: 16 }),
1776              " PNG Asset Builder"
1777            ] })
1778          ] }),
1779          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-2 space-y-1 custom-scrollbar", children: Object.values(configs).map((c) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1780            "div",
1781            {
1782              onClick: () => setSelectedId(c.id),
1783              className: `flex items-center justify-between p-3 rounded cursor-pointer transition-colors ${selectedId === c.id ? "bg-indigo-600/20 text-indigo-300 border border-indigo-600/30" : "hover:bg-zinc-800 text-zinc-400 border border-transparent"}`,
1784              children: [
1785                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "truncate", children: [
1786                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm truncate", children: c.name }),
1787                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs opacity-60 uppercase tracking-wider mt-0.5", children: c.family })
1788                ] }),
1789                /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
1790                  e.stopPropagation();
1791                  handleDelete(c.id);
1792                }, className: "text-zinc-600 hover:text-red-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) })
1793              ]
1794            },
1795            c.id
1796          )) })
1797        ] }),
1798        activeTab === "clothing" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1799          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 border-b border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => {
1800            const id = `new_clothing_${Date.now()}`;
1801            setClothingConfigs((prev) => ({ ...prev, [id]: { id, parts: {} } }));
1802            setSelectedClothingId(id);
1803          }, className: "w-full flex items-center justify-center gap-2 px-3 py-2 bg-zinc-800 hover:bg-zinc-700 text-white rounded text-sm", children: [
1804            /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }),
1805            " Add Clothing"
1806          ] }) }),
1807          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-2 space-y-1 custom-scrollbar", children: Object.values(clothingConfigs).map((c) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1808            "div",
1809            {
1810              onClick: () => setSelectedClothingId(c.id),
1811              className: `flex items-center justify-between p-3 rounded cursor-pointer transition-colors ${selectedClothingId === c.id ? "bg-indigo-600/20 text-indigo-300 border border-indigo-600/30" : "hover:bg-zinc-800 text-zinc-400 border border-transparent"}`,
1812              children: [
1813                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm truncate", children: c.id }) }),
1814                /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
1815                  e.stopPropagation();
1816                  if (!confirm("Are you sure?")) return;
1817                  const newConfigs = { ...clothingConfigs };
1818                  delete newConfigs[c.id];
1819                  setClothingConfigs(newConfigs);
1820                  if (selectedClothingId === c.id) setSelectedClothingId(Object.keys(newConfigs)[0] || null);
1821                }, className: "text-zinc-600 hover:text-red-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) })
1822              ]
1823            },
1824            c.id
1825          )) })
1826        ] }),
1827        activeTab === "instruments" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-2 space-y-1 custom-scrollbar", children: [
1828          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-500 uppercase tracking-wider p-2", children: "Melodic (1-128)" }),
1829          Object.keys(instrumentConfigs.melodic).map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1830            "div",
1831            {
1832              onClick: () => setSelectedInstKey(`m_${k}`),
1833              className: `p-2 text-sm rounded cursor-pointer truncate ${selectedInstKey === `m_${k}` ? "bg-indigo-600/20 text-indigo-300" : "hover:bg-zinc-800 text-zinc-400"}`,
1834              children: getInstrumentLabel("melodic", k)
1835            },
1836            `m_${k}`
1837          )),
1838          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-500 uppercase tracking-wider p-2 mt-4", children: "Percussion (Ch 10)" }),
1839          Object.keys(instrumentConfigs.percussion).map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1840            "div",
1841            {
1842              onClick: () => setSelectedInstKey(`p_${k}`),
1843              className: `p-2 text-sm rounded cursor-pointer truncate ${selectedInstKey === `p_${k}` ? "bg-indigo-600/20 text-indigo-300" : "hover:bg-zinc-800 text-zinc-400"}`,
1844              children: getInstrumentLabel("percussion", k)
1845            },
1846            `p_${k}`
1847          ))
1848        ] }),
1849        activeTab === "actions" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1850          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-zinc-800 bg-[#111] shrink-0", children: [
1851            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-400 uppercase tracking-widest text-indigo-400", children: "Body Actions" }),
1852            /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: addBodyAction, className: "text-indigo-400 hover:text-indigo-300 text-xs flex items-center gap-1", children: [
1853              /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 12 }),
1854              " Add"
1855            ] })
1856          ] }),
1857          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-y-auto shrink-0 border-b border-zinc-800", style: { maxHeight: "50%" }, children: globalActions.filter((a) => a.category === "body").map((action) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick: () => {
1858            setSelectedActionId(action.id);
1859            setSelectedActionRuleId(null);
1860            setSelectedChannelIdx(null);
1861          }, className: `flex items-center justify-between px-4 py-2.5 cursor-pointer border-b border-zinc-900 hover:bg-zinc-800 group ${selectedActionId === action.id ? "bg-indigo-900/30 border-l-2 border-l-indigo-500" : ""}`, children: [
1862            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1863              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-medium text-zinc-200", children: action.name }),
1864              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-500", children: [
1865                TRIGGER_LABELS_MAP[action.trigger],
1866                " · ",
1867                action.channels.length,
1868                " ch · p",
1869                action.priority
1870              ] })
1871            ] }),
1872            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1 opacity-0 group-hover:opacity-100", children: [
1873              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
1874                e.stopPropagation();
1875                cloneBodyAction(action.id);
1876              }, className: "p-1 text-zinc-500 hover:text-zinc-200", title: "Clone", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 12 }) }),
1877              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
1878                e.stopPropagation();
1879                removeBodyAction(action.id);
1880              }, className: "p-1 text-zinc-500 hover:text-red-400", title: "Delete", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 12 }) })
1881            ] })
1882          ] }, action.id)) }),
1883          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-zinc-800 bg-[#111] shrink-0", children: [
1884            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-400 uppercase tracking-widest text-indigo-400", children: "Action Rules" }),
1885            /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: addBodyRule, className: "text-indigo-400 hover:text-indigo-300 text-xs flex items-center gap-1", children: [
1886              /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 12 }),
1887              " Add"
1888            ] })
1889          ] }),
1890          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-y-auto flex-1", children: globalActionRules.map((rule) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick: () => {
1891            setSelectedActionRuleId(rule.id);
1892            setSelectedActionId(null);
1893          }, className: `flex items-center justify-between px-4 py-2.5 cursor-pointer border-b border-zinc-900 hover:bg-zinc-800 group ${selectedActionRuleId === rule.id ? "bg-indigo-900/30 border-l-2 border-l-indigo-500" : ""}`, children: [
1894            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1895              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1896                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `w-1.5 h-1.5 rounded-full ${rule.enabled ? "bg-green-400" : "bg-zinc-600"}` }),
1897                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-zinc-200", children: rule.name })
1898              ] }),
1899              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-500 ml-3.5", children: [
1900                rule.condition.scope === "all" ? "All characters" : rule.condition.scope === "family" ? `Families: ${(rule.condition.families || []).join(", ")}` : `Selected: ${(rule.condition.characterIds || []).join(", ")}`,
1901                " · ",
1902                rule.actionIds.length,
1903                " action",
1904                rule.actionIds.length !== 1 ? "s" : ""
1905              ] })
1906            ] }),
1907            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
1908              e.stopPropagation();
1909              removeBodyRule(rule.id);
1910            }, className: "p-1 text-zinc-500 hover:text-red-400 opacity-0 group-hover:opacity-100", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 12 }) })
1911          ] }, rule.id)) }),
1912          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 border-t border-zinc-800 bg-[#111] shrink-0", children: [
1913            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => {
1914              saveActionsToConfigs();
1915              handleSave();
1916            }, className: "w-full py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-bold rounded", children: "Save Actions" }),
1917            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-600 text-center mt-1", children: "Applies to all characters" })
1918          ] })
1919        ] }),
1920        activeTab === "background" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1921          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between px-4 py-3 border-b border-zinc-800 bg-[#111] shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-400 uppercase tracking-widest text-indigo-400", children: "Backgrounds" }) }),
1922          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-2 space-y-1 custom-scrollbar", children: [
1923            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1924              "div",
1925              {
1926                onClick: () => {
1927                  setSelectedPresetId(null);
1928                },
1929                className: `p-3 rounded cursor-pointer border hover:bg-zinc-800 transition-colors ${selectedPresetId === null ? "bg-indigo-600/20 text-indigo-300 border-indigo-600/30" : "text-zinc-400 border-transparent"}`,
1930                children: [
1931                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm", children: "Global Default Stage" }),
1932                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs opacity-60 mt-0.5", children: "Applies when no tags match" })
1933                ]
1934              }
1935            ),
1936            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t border-zinc-800 my-2" }),
1937            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-zinc-500 uppercase tracking-widest px-3 block mb-1", children: "Tag-Based Presets" }),
1938            backgroundPresets.map((preset) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1939              "div",
1940              {
1941                onClick: () => {
1942                  setSelectedPresetId(preset.id);
1943                },
1944                className: `p-3 rounded cursor-pointer border hover:bg-zinc-800 transition-colors ${selectedPresetId === preset.id ? "bg-indigo-600/20 text-indigo-300 border-indigo-600/30" : "text-zinc-400 border-transparent"}`,
1945                children: [
1946                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm", children: preset.name }),
1947                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs opacity-60 capitalize mt-0.5", children: [
1948                    preset.config.type,
1949                    " · tags: ",
1950                    preset.tags.length > 0 ? preset.tags.join(", ") : "none"
1951                  ] })
1952                ]
1953              },
1954              preset.id
1955            ))
1956          ] })
1957        ] })
1958      ] }),
1959      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 bg-[#0a0a0a] flex flex-col relative overflow-hidden", children: activePreviewConfig ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1960        "div",
1961        {
1962          ref: containerRef,
1963          className: "flex-1 flex items-center justify-center p-4 relative overflow-hidden focus:outline-none",
1964          style: bgStyle,
1965          tabIndex: 0,
1966          onMouseDown: (e) => {
1967            if (document.activeElement instanceof HTMLElement) {
1968              document.activeElement.blur();
1969            }
1970            if (e.target === e.currentTarget || e.target.classList.contains("bg-black/80")) {
1971              e.preventDefault();
1972              setDraggingPoint({
1973                target: "pan",
1974                startX: viewPanX,
1975                startY: viewPanY,
1976                mouseStartX: e.clientX,
1977                mouseStartY: e.clientY
1978              });
1979            }
1980          },
1981          onClick: (e) => {
1982            if (editMode === "none" || !activePreviewConfig) return;
1983            pushUndo();
1984            const svg = previewSvgRef.current || e.currentTarget.querySelector("svg");
1985            if (!svg) return;
1986            const pt = svg.createSVGPoint();
1987            pt.x = e.clientX;
1988            pt.y = e.clientY;
1989            const svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
1990            const charScale = activePreviewConfig.scale ?? 1;
1991            const anchorX = activePreviewConfig.anchorX ?? 0;
1992            const anchorY = activePreviewConfig.anchorY ?? 0;
1993            const innerX = Math.round(svgP.x / charScale - anchorX);
1994            const innerY = Math.round(svgP.y / charScale - anchorY);
1995            const anchorModeX = Math.round(svgP.x / charScale);
1996            const anchorModeY = Math.round(svgP.y / charScale);
1997            if (activeTab === "characters" && !previewInstKey) {
1998              if (editMode === "anchor") {
1999                handleConfigChange(activePreviewConfig.id, { anchorX: anchorModeX, anchorY: anchorModeY });
2000              } else if (editMode === "shoulder_l") {
2001                handleIkChange(activePreviewConfig.id, "ikLeftArm", "originX", innerX);
2002                handleIkChange(activePreviewConfig.id, "ikLeftArm", "originY", innerY);
2003              } else if (editMode === "shoulder_r") {
2004                handleIkChange(activePreviewConfig.id, "ikRightArm", "originX", innerX);
2005                handleIkChange(activePreviewConfig.id, "ikRightArm", "originY", innerY);
2006              } else if (editMode.startsWith("socket_")) {
2007                const socketName = editMode.replace("socket_", "");
2008                const currentSockets = activePreviewConfig.sockets || {};
2009                handleConfigChange(activePreviewConfig.id, {
2010                  sockets: {
2011                    ...currentSockets,
2012                    [socketName]: { x: innerX, y: innerY }
2013                  }
2014                });
2015              }
2016            } else if (activeTab === "instruments" || activeTab === "characters" && previewInstKey) {
2017              if (editMode.startsWith("plug_")) {
2018                const plugName = editMode.replace("plug_", "");
2019                const targetCoords = getLocalSpacePt(".custom-instrument-svg") || { x: localX, y: localY };
2020                setInstrumentConfigs((prev) => {
2021                  const typeObj = prev[editingInstType];
2022                  const instObj = typeObj[editingInstIndex] || {};
2023                  const currentPlugs = instObj.plugs || {};
2024                  const updated = {
2025                    ...instObj,
2026                    plugs: {
2027                      ...currentPlugs,
2028                      [plugName]: { ...currentPlugs[plugName] || {}, x: targetCoords.x, y: targetCoords.y }
2029                    }
2030                  };
2031                  return {
2032                    ...prev,
2033                    [editingInstType]: {
2034                      ...typeObj,
2035                      [editingInstIndex]: updated
2036                    }
2037                  };
2038                });
2039              } else {
2040                const updateMotion = (hand, point, lX, lY) => {
2041                  const finalX = localX;
2042                  const finalY = localY;
2043                  setInstrumentConfigs((prev) => {
2044                    const typeObj = prev[editingInstType];
2045                    const instObj = typeObj[editingInstIndex] || {};
2046                    const motionObj = instObj[hand] || { logic: "none", start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
2047                    let newRestPose = instObj.restPose || {};
2048                    if (point === "start") {
2049                      newRestPose = {
2050                        ...newRestPose,
2051                        [hand === "leftHandMotion" ? "leftHand" : "rightHand"]: { x: finalX, y: finalY }
2052                      };
2053                    }
2054                    return {
2055                      ...prev,
2056                      [editingInstType]: {
2057                        ...typeObj,
2058                        [editingInstIndex]: {
2059                          ...instObj,
2060                          [hand]: { ...motionObj, [point]: { x: finalX, y: finalY } },
2061                          restPose: newRestPose
2062                        }
2063                      }
2064                    };
2065                  });
2066                };
2067                if (editMode === "path_l_start") updateMotion("leftHandMotion", "start");
2068                else if (editMode === "path_l_end") updateMotion("leftHandMotion", "end");
2069                else if (editMode === "path_r_start") updateMotion("rightHandMotion", "start");
2070                else if (editMode === "path_r_end") updateMotion("rightHandMotion", "end");
2071                else if (editMode === "head_anchor") {
2072                  setInstrumentConfigs((prev) => {
2073                    const typeObj = prev[editingInstType];
2074                    const instObj = typeObj[editingInstIndex] || {};
2075                    return {
2076                      ...prev,
2077                      [editingInstType]: {
2078                        ...typeObj,
2079                        [editingInstIndex]: {
2080                          ...instObj,
2081                          headAnchor: { x: localX, y: localY }
2082                        }
2083                      }
2084                    };
2085                  });
2086                }
2087              }
2088            } else if (activeTab === "clothing" && selectedClothingDef) {
2089              if (editMode.startsWith("clothing_plug_")) {
2090                const parts = editMode.split("_");
2091                const pointKey = parts[2];
2092                const partName = parts.slice(3).join("_");
2093                const targetCoords = getLocalSpacePt(`.custom-clothing-mount[data-target-joint="${partName}"] .custom-clothing-offset`) || { x: localX, y: localY };
2094                setClothingConfigs((prev) => {
2095                  const clothObj = prev[selectedClothingDef.id];
2096                  if (!clothObj) return prev;
2097                  const currentPlugs = clothObj.plugs || {};
2098                  const partPlugs = currentPlugs[partName] || {};
2099                  return {
2100                    ...prev,
2101                    [selectedClothingDef.id]: {
2102                      ...clothObj,
2103                      plugs: {
2104                        ...currentPlugs,
2105                        [partName]: {
2106                          ...partPlugs,
2107                          [pointKey]: { x: targetCoords.x, y: targetCoords.y }
2108                        }
2109                      }
2110                    }
2111                  };
2112                });
2113              }
2114            }
2115          },
2116          onMouseMove: (e) => {
2117            var _a2, _b2, _c2;
2118            if (!draggingPoint || !activePreviewConfig) return;
2119            if (draggingPoint.target === "pan") {
2120              const deltaX = e.clientX - draggingPoint.mouseStartX;
2121              const deltaY = e.clientY - draggingPoint.mouseStartY;
2122              setViewPanX(draggingPoint.startX - deltaX / viewZoom);
2123              setViewPanY(draggingPoint.startY - deltaY / viewZoom);
2124              return;
2125            }
2126            const svg = previewSvgRef.current || e.currentTarget.querySelector("svg");
2127            if (!svg) return;
2128            const pt = svg.createSVGPoint();
2129            pt.x = e.clientX;
2130            pt.y = e.clientY;
2131            const svgP = pt.matrixTransform((_a2 = svg.getScreenCTM()) == null ? void 0 : _a2.inverse());
2132            if (draggingPoint.target === "socket" && activePreviewConfig) {
2133              const socketName = draggingPoint.jointId;
2134              const charScale = activePreviewConfig.scale || 1;
2135              const anchorX = activePreviewConfig.anchorX ?? 0;
2136              const anchorY = activePreviewConfig.anchorY ?? 0;
2137              const newX = Math.round(svgP.x / charScale - anchorX);
2138              const newY = Math.round(svgP.y / charScale - anchorY);
2139              const currentSockets = activePreviewConfig.sockets || {};
2140              handleConfigChange(activePreviewConfig.id, {
2141                sockets: {
2142                  ...currentSockets,
2143                  [socketName]: { x: newX, y: newY }
2144                }
2145              });
2146              return;
2147            }
2148            if (draggingPoint.target === "plug") {
2149              const targetEl = svg.querySelector(".custom-instrument-svg");
2150              if (targetEl) {
2151                const activeEl = targetEl.querySelector("svg") || targetEl.firstElementChild || targetEl;
2152                const ctm = activeEl.getScreenCTM();
2153                if (ctm) {
2154                  const ptLocal = svg.createSVGPoint();
2155                  ptLocal.x = e.clientX;
2156                  ptLocal.y = e.clientY;
2157                  const localP = ptLocal.matrixTransform(ctm.inverse());
2158                  const newX = Math.round(localP.x);
2159                  const newY = Math.round(localP.y);
2160                  const plugName = draggingPoint.jointId;
2161                  setInstrumentConfigs((prev) => {
2162                    const typeObj = prev[editingInstType];
2163                    const instObj = typeObj[editingInstIndex] || {};
2164                    const currentPlugs = instObj.plugs || {};
2165                    const updated = {
2166                      ...instObj,
2167                      plugs: {
2168                        ...currentPlugs,
2169                        [plugName]: { ...currentPlugs[plugName] || {}, x: newX, y: newY }
2170                      }
2171                    };
2172                    return {
2173                      ...prev,
2174                      [editingInstType]: {
2175                        ...typeObj,
2176                        [editingInstIndex]: updated
2177                      }
2178                    };
2179                  });
2180                }
2181              }
2182              return;
2183            }
2184            if (draggingPoint.target === "clothing_plug" && selectedClothingDef) {
2185              const partName = draggingPoint.plugPart;
2186              const pointKey = draggingPoint.plugKey;
2187              const targetEl = svg.querySelector(`.custom-clothing-mount[data-target-joint="${partName}"] .custom-clothing-offset`);
2188              if (targetEl) {
2189                const activeEl = targetEl.querySelector("svg") || targetEl.firstElementChild || targetEl;
2190                const ctm = activeEl.getScreenCTM();
2191                if (ctm) {
2192                  const ptLocal = svg.createSVGPoint();
2193                  ptLocal.x = e.clientX;
2194                  ptLocal.y = e.clientY;
2195                  const localP = ptLocal.matrixTransform(ctm.inverse());
2196                  const newX = Math.round(localP.x);
2197                  const newY = Math.round(localP.y);
2198                  setClothingConfigs((prev) => {
2199                    const clothObj = prev[selectedClothingDef.id];
2200                    if (!clothObj) return prev;
2201                    const currentPlugs = clothObj.plugs || {};
2202                    const partPlugs = currentPlugs[partName] || {};
2203                    return {
2204                      ...prev,
2205                      [selectedClothingDef.id]: {
2206                        ...clothObj,
2207                        plugs: {
2208                          ...currentPlugs,
2209                          [partName]: {
2210                            ...partPlugs,
2211                            [pointKey]: { x: newX, y: newY }
2212                          }
2213                        }
2214                      }
2215                    };
2216                  });
2217                }
2218              }
2219              return;
2220            }
2221            if (draggingPoint.target === "clothing" && selectedClothingDef && draggingPoint.inverseMatrix) {
2222              const jointId = draggingPoint.jointId;
2223              const ptLocal = svg.createSVGPoint();
2224              ptLocal.x = e.clientX;
2225              ptLocal.y = e.clientY;
2226              const localP = ptLocal.matrixTransform(draggingPoint.inverseMatrix);
2227              const localDeltaX = localP.x - draggingPoint.startLocalX;
2228              const localDeltaY = localP.y - draggingPoint.startLocalY;
2229              const newX = Math.round(draggingPoint.startX + localDeltaX);
2230              const newY = Math.round(draggingPoint.startY + localDeltaY);
2231              const currentTransform = ((_b2 = selectedClothingDef.transforms) == null ? void 0 : _b2[jointId]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
2232              setClothingConfigs((prev) => ({
2233                ...prev,
2234                [selectedClothingDef.id]: {
2235                  ...selectedClothingDef,
2236                  transforms: {
2237                    ...selectedClothingDef.transforms,
2238                    [jointId]: {
2239                      ...currentTransform,
2240                      x: newX,
2241                      y: newY
2242                    }
2243                  }
2244                }
2245              }));
2246              return;
2247            }
2248            if ((draggingPoint.target === "instrument" || draggingPoint.target === "accessory") && selectedInstKey && draggingPoint.inverseMatrix) {
2249              const isAccessory = draggingPoint.target === "accessory";
2250              const ptLocal = svg.createSVGPoint();
2251              ptLocal.x = e.clientX;
2252              ptLocal.y = e.clientY;
2253              const localP = ptLocal.matrixTransform(draggingPoint.inverseMatrix);
2254              const localDeltaX = localP.x - draggingPoint.startLocalX;
2255              const localDeltaY = localP.y - draggingPoint.startLocalY;
2256              const newX = Math.round(draggingPoint.startX + localDeltaX);
2257              const newY = Math.round(draggingPoint.startY + localDeltaY);
2258              setInstrumentConfigs((prev) => {
2259                const typeObj = prev[editingInstType];
2260                const instObj = typeObj[editingInstIndex];
2261                if (!instObj) return prev;
2262                let currentDef;
2263                if (typeof instObj === "string") {
2264                  currentDef = {
2265                    svgContent: instObj,
2266                    mountPoint: "body"
2267                  };
2268                } else {
2269                  currentDef = instObj;
2270                }
2271                const transformField = isAccessory ? "accessoryTransform" : "transform";
2272                const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
2273                return {
2274                  ...prev,
2275                  [editingInstType]: {
2276                    ...typeObj,
2277                    [editingInstIndex]: {
2278                      ...currentDef,
2279                      [transformField]: {
2280                        ...currentTransform,
2281                        x: newX,
2282                        y: newY
2283                      }
2284                    }
2285                  }
2286                };
2287              });
2288              return;
2289            }
2290            if (draggingPoint.target === "action_keyframe") {
2291              const actionId = draggingPoint.actionId;
2292              const channelIdx = draggingPoint.channelIdx;
2293              const keyframeIdx = draggingPoint.keyframeIdx;
2294              const jx = draggingPoint.jx;
2295              const jy = draggingPoint.jy;
2296              const maxV = draggingPoint.maxV;
2297              const newTime = (svgP.x - (jx - 15)) / 30;
2298              const clampedTime = Math.round(Math.max(0, Math.min(1, newTime)) * 100) / 100;
2299              const newValue = (jy - 12 - svgP.y) / 8 * maxV;
2300              const clampedValue = Math.round(newValue * 10) / 10;
2301              const action = globalActions.find((a) => a.id === actionId);
2302              const channel = action == null ? void 0 : action.channels[channelIdx];
2303              if (channel && channel.keyframes) {
2304                const nk = [...channel.keyframes];
2305                nk[keyframeIdx] = {
2306                  ...nk[keyframeIdx],
2307                  time: clampedTime,
2308                  value: clampedValue
2309                };
2310                nk.sort((a, b) => a.time - b.time);
2311                const newIdx = nk.findIndex((k) => k.time === clampedTime && k.value === clampedValue);
2312                if (newIdx !== -1) {
2313                  setDraggingPoint((prev) => ({
2314                    ...prev,
2315                    keyframeIdx: newIdx
2316                  }));
2317                }
2318                updateBodyChannel(actionId, channelIdx, { keyframes: nk });
2319              }
2320              return;
2321            }
2322            if (draggingPoint.target === "action_wave_amp") {
2323              const actionId = draggingPoint.actionId;
2324              const channelIdx = draggingPoint.channelIdx;
2325              const isVertical = draggingPoint.isVertical;
2326              const isX = draggingPoint.isX;
2327              const jx = draggingPoint.jx;
2328              const jy = draggingPoint.jy;
2329              let newAmp = 0;
2330              if (isX) {
2331                newAmp = Math.abs(svgP.x - jx) / 0.3;
2332              } else if (isVertical) {
2333                newAmp = Math.abs(svgP.y - jy) / 0.3;
2334              } else {
2335                newAmp = Math.abs(svgP.y - (jy - 15)) / 0.3;
2336              }
2337              newAmp = Math.round(newAmp * 10) / 10;
2338              const action = globalActions.find((a) => a.id === actionId);
2339              const channel = action == null ? void 0 : action.channels[channelIdx];
2340              if (channel) {
2341                const currentAmp = channel.amplitude || 10;
2342                const signedAmp = currentAmp < 0 ? -newAmp : newAmp;
2343                updateBodyChannel(actionId, channelIdx, { amplitude: signedAmp });
2344              }
2345              return;
2346            }
2347            if (draggingPoint.target === "bodyPart" && selectedConfig) {
2348              const partId = draggingPoint.jointId;
2349              const deltaX = svgP.x - draggingPoint.mouseStartX;
2350              const deltaY = svgP.y - draggingPoint.mouseStartY;
2351              const charScale = selectedConfig.scale || 1;
2352              const newX = Math.round(draggingPoint.startX + deltaX / charScale);
2353              const newY = Math.round(draggingPoint.startY + deltaY / charScale);
2354              const currentTransform = ((_c2 = selectedConfig.transforms) == null ? void 0 : _c2[partId]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
2355              handleConfigChange(selectedConfig.id, {
2356                transforms: {
2357                  ...selectedConfig.transforms,
2358                  [partId]: {
2359                    ...currentTransform,
2360                    x: newX,
2361                    y: newY
2362                  }
2363                }
2364              });
2365              return;
2366            }
2367            setInstrumentConfigs((prev) => {
2368              const typeObj = prev[editingInstType];
2369              const instObj = typeObj[editingInstIndex] || {};
2370              const hand = draggingPoint.hand;
2371              draggingPoint.point;
2372              instObj[hand] || {};
2373              if (draggingPoint.target === "headAnchor") {
2374                return {
2375                  ...prev,
2376                  [editingInstType]: {
2377                    ...typeObj,
2378                    [editingInstIndex]: {
2379                      ...instObj,
2380                      headAnchor: { x: localX, y: localY }
2381                    }
2382                  }
2383                };
2384              } else if (draggingPoint.hand) {
2385                const hand2 = draggingPoint.hand;
2386                const point2 = draggingPoint.point;
2387                const motionObj2 = instObj[hand2] || { logic: "none", start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
2388                let newRestPose = instObj.restPose || {};
2389                if (point2 === "start") {
2390                  newRestPose = {
2391                    ...newRestPose,
2392                    [hand2 === "leftHandMotion" ? "leftHand" : "rightHand"]: { x: localX, y: localY }
2393                  };
2394                }
2395                return {
2396                  ...prev,
2397                  [editingInstType]: {
2398                    ...typeObj,
2399                    [editingInstIndex]: {
2400                      ...instObj,
2401                      [hand2]: { ...motionObj2, [point2]: { x: localX, y: localY } },
2402                      restPose: newRestPose
2403                    }
2404                  }
2405                };
2406              }
2407              return prev;
2408            });
2409          },
2410          onMouseUp: () => setDraggingPoint(null),
2411          onMouseLeave: () => setDraggingPoint(null),
2412          children: [
2413            bg.type === "image" && ((_a = bg.image) == null ? void 0 : _a.url) && /* @__P
2413URE__ */ jsxRuntimeExports.jsx(
2414              "div",
2415              {
2416                className: "absolute inset-0 bg-cover bg-center",
2417                style: {
2418                  ...imageStyle,
2419                  zIndex: 1
2420                }
2421              }
2422            ),
2423            ((_b = bg.overlay) == null ? void 0 : _b.enabled) && /* @__PURE__ */ jsxRuntimeExports.jsx(
2424              "div",
2425              {
2426                className: "absolute inset-0 pointer-events-none",
2427                style: {
2428                  backgroundColor: bg.overlay.color,
2429                  opacity: bg.overlay.opacity,
2430                  zIndex: 2
2431                }
2432              }
2433            ),
2434            ((_c = bg.particles) == null ? void 0 : _c.enabled) && /* @__PURE__ */ jsxRuntimeExports.jsx(BackgroundParticlesCanvas, { config: bg.particles, isPlaying: isPlaying || activeTab !== "actions" && playMode === "wave" }),
2435            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute top-4 right-4 flex items-center gap-2 z-20 select-none", children: [
2436              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-950/90 backdrop-blur rounded border border-zinc-800 p-0.5 shadow-lg", children: [
2437                /* @__PURE__ */ jsxRuntimeExports.jsx(
2438                  "button",
2439                  {
2440                    onClick: undo,
2441                    disabled: undoStack.length === 0,
2442                    className: "p-1.5 hover:bg-zinc-800 rounded disabled:opacity-30 disabled:hover:bg-transparent text-zinc-300 hover:text-white transition-colors",
2443                    title: "Undo (Ctrl+Z)",
2444                    children: /* @__PURE__ */ jsxRuntimeExports.jsx(Undo, { className: "w-4 h-4" })
2445                  }
2446                ),
2447                /* @__PURE__ */ jsxRuntimeExports.jsx(
2448                  "button",
2449                  {
2450                    onClick: redo,
2451                    disabled: redoStack.length === 0,
2452                    className: "p-1.5 hover:bg-zinc-800 rounded disabled:opacity-30 disabled:hover:bg-transparent text-zinc-300 hover:text-white transition-colors",
2453                    title: "Redo (Ctrl+Y)",
2454                    children: /* @__PURE__ */ jsxRuntimeExports.jsx(Redo, { className: "w-4 h-4" })
2455                  }
2456                )
2457              ] }),
2458              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-950/90 backdrop-blur rounded border border-zinc-800 p-0.5 shadow-lg", children: [
2459                /* @__PURE__ */ jsxRuntimeExports.jsx(
2460                  "button",
2461                  {
2462                    onClick: () => setViewZoom((prev) => Math.min(8, prev + 0.25)),
2463                    className: "p-1.5 hover:bg-zinc-800 rounded text-zinc-300 hover:text-white transition-colors",
2464                    title: "Zoom In",
2465                    children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomIn, { className: "w-4 h-4" })
2466                  }
2467                ),
2468                /* @__PURE__ */ jsxRuntimeExports.jsx(
2469                  "button",
2470                  {
2471                    onClick: () => setViewZoom((prev) => Math.max(0.25, prev - 0.25)),
2472                    className: "p-1.5 hover:bg-zinc-800 rounded text-zinc-300 hover:text-white transition-colors",
2473                    title: "Zoom Out",
2474                    children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomOut, { className: "w-4 h-4" })
2475                  }
2476                ),
2477                /* @__PURE__ */ jsxRuntimeExports.jsx(
2478                  "button",
2479                  {
2480                    onClick: () => {
2481                      setViewZoom(1);
2482                      setViewPanX(0);
2483                      setViewPanY(0);
2484                    },
2485                    className: "p-1.5 hover:bg-zinc-800 rounded text-zinc-300 hover:text-white transition-colors",
2486                    title: "Reset View",
2487                    children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { className: "w-4 h-4" })
2488                  }
2489                )
2490              ] })
2491            ] }),
2492            selectedPartId && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute bottom-4 left-4 bg-zinc-950/90 backdrop-blur text-xs px-2.5 py-1 rounded border border-zinc-800 text-zinc-400 select-none z-20 pointer-events-none animate-fadeIn", children: [
2493              "Selected Part: ",
2494              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-indigo-400 font-mono font-bold", children: selectedPartId })
2495            ] }),
2496            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute bottom-4 right-4 bg-zinc-950/90 backdrop-blur p-2 rounded border border-zinc-800 shadow-lg z-20 pointer-events-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
2497              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setIsPlaying(!isPlaying), className: "px-3 py-1 bg-indigo-600 hover:bg-indigo-500 rounded text-white font-bold text-xs", children: isPlaying ? "Pause" : "Play" }),
2498              activeTab !== "actions" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-xs", children: [
2499                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1 cursor-pointer text-zinc-300 hover:text-white select-none", children: [
2500                  /* @__PURE__ */ jsxRuntimeExports.jsx(
2501                    "input",
2502                    {
2503                      type: "radio",
2504                      name: "playMode",
2505                      value: "instrument",
2506                      checked: playMode === "instrument",
2507                      onChange: () => setPlayMode("instrument"),
2508                      className: "accent-indigo-600"
2509                    }
2510                  ),
2511                  "Play"
2512                ] }),
2513                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1 cursor-pointer text-zinc-300 hover:text-white select-none", children: [
2514                  /* @__PURE__ */ jsxRuntimeExports.jsx(
2515                    "input",
2516                    {
2517                      type: "radio",
2518                      name: "playMode",
2519                      value: "wave",
2520                      checked: playMode === "wave",
2521                      onChange: () => setPlayMode("wave"),
2522                      className: "accent-indigo-600"
2523                    }
2524                  ),
2525                  "Wave"
2526                ] })
2527              ] }),
2528              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs border-l border-zinc-700 pl-3 ml-1", children: [
2529                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "BPM:" }),
2530                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "range", min: "40", max: "240", value: tempo, onChange: (e) => setTempo(parseInt(e.target.value)), className: "w-20" }),
2531                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-8 text-right font-mono text-zinc-300", children: tempo })
2532              ] })
2533            ] }) }),
2534            animatorRef.current && /* @__PURE__ */ jsxRuntimeExports.jsxs(
2535              "svg",
2536              {
2537                ref: previewSvgRef,
2538                width: "100%",
2539                height: "100%",
2540                viewBox: `${-(80 / viewZoom) + viewPanX} ${100 * (activePreviewConfig.scale ?? 1) - 40 - 100 / viewZoom + viewPanY} ${160 / viewZoom} ${200 / viewZoom}`,
2541                className: `relative z-10 overflow-visible ${editMode !== "none" && activeTab === "characters" ? "cursor-crosshair" : ""}`,
2542                children: [
2543                  /* @__PURE__ */ jsxRuntimeExports.jsx(
2544                    PuppetCharacter,
2545                    {
2546                      tickId,
2547                      config: activePreviewConfig,
2548                      state: animatorRef.current.getState(),
2549                      x: 0,
2550                      y: 0,
2551                      isSoloed: false,
2552                      isHidden: false,
2553                      instrumentName: activeTab === "instruments" ? getInstrumentLabel(selectedInstType, selectedInstIndex.toString()) : "",
2554                      showSkeleton,
2555                      visibility,
2556                      specificGraphic: activePreviewInst,
2557                      clothingGraphic: activePreviewClothing,
2558                      onClothingMouseDown: handleClothingMouseDown,
2559                      onBodyPartMouseDown: handleBodyPartMouseDown,
2560                      onInstrumentMouseDown: handleInstrumentMouseDown,
2561                      isCharacterTab: activeTab === "characters",
2562                      showActionPaths,
2563                      activeTab,
2564                      selectedActionId,
2565                      globalActions,
2566                      onActionOverlayMouseDown: setDraggingPoint,
2567                      viewZoom,
2568                      isPlaying: isPlaying || activeTab !== "actions" && playMode === "wave"
2569                    }
2570                  ),
2571                  editMode !== "none" && /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
2572                    activeTab === "characters" && /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { pointerEvents: "none", opacity: "0.3", children: [
2573                      /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "-1000", y1: "0", x2: "1000", y2: "0", stroke: "white", strokeWidth: "1", strokeDasharray: "5" }),
2574                      /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "-1000", y1: 100 * (activePreviewConfig.scale ?? 1), x2: "1000", y2: 100 * (activePreviewConfig.scale ?? 1), stroke: "#10b981", strokeWidth: "1", strokeDasharray: "5", opacity: "0.5" }),
2575                      /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "0", y1: "-1000", x2: "0", y2: "1000", stroke: "white", strokeWidth: "1", strokeDasharray: "5" })
2576                    ] }),
2577                    (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { pointerEvents: "none", opacity: "0.3", children: [
2578                      /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "-1000", y1: "0", x2: "1000", y2: "0", stroke: "white", strokeWidth: "1", strokeDasharray: "5" }),
2579                      /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "-1000", y1: 100 * (activePreviewConfig.scale ?? 1), x2: "1000", y2: 100 * (activePreviewConfig.scale ?? 1), stroke: "#10b981", strokeWidth: "1", strokeDasharray: "5", opacity: "0.5" }),
2580                      /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "0", y1: "-1000", x2: "0", y2: "1000", stroke: "white", strokeWidth: "1", strokeDasharray: "5" })
2581                    ] }),
2582                    (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && (activePreviewInst == null ? void 0 : activePreviewInst.leftHandMotion) && (() => {
2583                      const startProj = getProjectedPt(".custom-instrument-svg", activePreviewInst.leftHandMotion.start);
2584                      const endProj = getProjectedPt(".custom-instrument-svg", activePreviewInst.leftHandMotion.end);
2585                      return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
2586                        /* @__PURE__ */ jsxRuntimeExports.jsx("line", { pointerEvents: "none", x1: startProj.x, y1: startProj.y, x2: endProj.x, y2: endProj.y, stroke: "#f43f5e", strokeWidth: "2", strokeDasharray: "4", opacity: "0.7" }),
2587                        /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { onMouseDown: (e) => {
2588                          e.stopPropagation();
2589                          setDraggingPoint({ hand: "leftHandMotion", point: "start" });
2590                        }, className: "cursor-grab active:cursor-grabbing", cx: startProj.x, cy: startProj.y, r: "5", fill: "#f43f5e", stroke: "white", strokeWidth: "1" }),
2591                        /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { onMouseDown: (e) => {
2592                          e.stopPropagation();
2593                          setDraggingPoint({ hand: "leftHandMotion", point: "end" });
2594                        }, className: "cursor-grab active:cursor-grabbing", cx: endProj.x, cy: endProj.y, r: "4", fill: "#111", stroke: "#f43f5e", strokeWidth: "2" })
2595                      ] });
2596                    })(),
2597                    (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && (activePreviewInst == null ? void 0 : activePreviewInst.rightHandMotion) && (() => {
2598                      const startProj = getProjectedPt(".custom-instrument-svg", activePreviewInst.rightHandMotion.start);
2599                      const endProj = getProjectedPt(".custom-instrument-svg", activePreviewInst.rightHandMotion.end);
2600                      return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
2601                        /* @__PURE__ */ jsxRuntimeExports.jsx("line", { pointerEvents: "none", x1: startProj.x, y1: startProj.y, x2: endProj.x, y2: endProj.y, stroke: "#3b82f6", strokeWidth: "2", strokeDasharray: "4", opacity: "0.7" }),
2602                        /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { onMouseDown: (e) => {
2603                          e.stopPropagation();
2604                          setDraggingPoint({ hand: "rightHandMotion", point: "start" });
2605                        }, className: "cursor-grab active:cursor-grabbing", cx: startProj.x, cy: startProj.y, r: "5", fill: "#3b82f6", stroke: "white", strokeWidth: "1" }),
2606                        /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { onMouseDown: (e) => {
2607                          e.stopPropagation();
2608                          setDraggingPoint({ hand: "rightHandMotion", point: "end" });
2609                        }, className: "cursor-grab active:cursor-grabbing", cx: endProj.x, cy: endProj.y, r: "4", fill: "#111", stroke: "#3b82f6", strokeWidth: "2" })
2610                      ] });
2611                    })(),
2612                    activeTab === "characters" && activePreviewConfig && (() => {
2613                      const svgCoords = parseSvgSocketsAndPlugs(activePreviewConfig.svgContent);
2614                      const sockets = {};
2615                      Object.entries(svgCoords).forEach(([key, pt]) => {
2616                        if (key.startsWith("socket_")) {
2617                          sockets[key.replace("socket_", "")] = pt;
2618                        }
2619                      });
2620                      if (activePreviewConfig.sockets) {
2621                        Object.entries(activePreviewConfig.sockets).forEach(([key, pt]) => {
2622                          sockets[key] = pt;
2623                        });
2624                      }
2625                      return Object.entries(sockets).map(([name, pt]) => {
2626                        const isSelected = editMode === `socket_${name}`;
2627                        const projected = getProjectedPt(".custom-character-svg", pt);
2628                        return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { transform: `translate(${projected.x}, ${projected.y})`, children: [
2629                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2630                            "circle",
2631                            {
2632                              r: (isSelected ? 5 : 3.5) / viewZoom,
2633                              fill: isSelected ? "#10b981" : "#6366f1",
2634                              stroke: "white",
2635                              strokeWidth: (isSelected ? 1.5 : 0.75) / viewZoom,
2636                              className: "cursor-grab active:cursor-grabbing",
2637                              onMouseDown: (e) => {
2638                                e.stopPropagation();
2639                                e.preventDefault();
2640                                pushUndo();
2641                                setEditMode(`socket_${name}`);
2642                                setDraggingPoint({
2643                                  target: "socket",
2644                                  jointId: name
2645                                });
2646                              }
2647                            }
2648                          ),
2649                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2650                            "text",
2651                            {
2652                              y: -7 / viewZoom,
2653                              textAnchor: "middle",
2654                              fill: isSelected ? "#10b981" : "#a5b4fc",
2655                              fontSize: 6 / viewZoom,
2656                              fontWeight: "bold",
2657                              className: "pointer-events-none select-none",
2658                              style: { paintOrder: "stroke", stroke: "#000", strokeWidth: `${1.5 / viewZoom}px` },
2659                              children: name
2660                            }
2661                          )
2662                        ] }, name);
2663                      });
2664                    })(),
2665                    (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && activePreviewInst && (() => {
2666                      const svgCoords = parseSvgSocketsAndPlugs(activePreviewInst.svgContent);
2667                      const plugs = {};
2668                      const defaultPlugs = getFamilyDefaultPlugs(activePreviewInst.family || "other");
2669                      const configPlugs = Object.keys(activePreviewInst.plugs || {});
2670                      const allPlugs = Array.from(/* @__PURE__ */ new Set([...defaultPlugs, ...configPlugs]));
2671                      allPlugs.forEach((name) => {
2672                        var _a2;
2673                        const svgVal = svgCoords[`plug_${name}`];
2674                        const configVal = (_a2 = activePreviewInst.plugs) == null ? void 0 : _a2[name];
2675                        const val = configVal || svgVal;
2676                        if (val) plugs[name] = val;
2677                      });
2678                      return Object.entries(plugs).map(([name, pt]) => {
2679                        const projected = getProjectedPt(".custom-instrument-svg", pt);
2680                        const isSelected = editMode === `plug_${name}`;
2681                        return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { transform: `translate(${projected.x}, ${projected.y})`, children: [
2682                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2683                            "circle",
2684                            {
2685                              r: (isSelected ? 5 : 3.5) / viewZoom,
2686                              fill: isSelected ? "#10b981" : "#f59e0b",
2687                              stroke: "white",
2688                              strokeWidth: (isSelected ? 1.5 : 0.75) / viewZoom,
2689                              className: "cursor-grab active:cursor-grabbing",
2690                              onMouseDown: (e) => {
2691                                e.stopPropagation();
2692                                e.preventDefault();
2693                                pushUndo();
2694                                setEditMode(`plug_${name}`);
2695                                setDraggingPoint({
2696                                  target: "plug",
2697                                  jointId: name
2698                                });
2699                              }
2700                            }
2701                          ),
2702                          /* @__P
2702URE__ */ jsxRuntimeExports.jsx(
2703                            "text",
2704                            {
2705                              y: -7 / viewZoom,
2706                              textAnchor: "middle",
2707                              fill: isSelected ? "#10b981" : "#fcd34d",
2708                              fontSize: 6 / viewZoom,
2709                              fontWeight: "bold",
2710                              className: "pointer-events-none select-none",
2711                              style: { paintOrder: "stroke", stroke: "#000", strokeWidth: `${1.5 / viewZoom}px` },
2712                              children: name
2713                            }
2714                          )
2715                        ] }, name);
2716                      });
2717                    })(),
2718                    activeTab === "clothing" && activePreviewClothing && (() => {
2719                      const overlays = [];
2720                      Object.keys(activePreviewClothing.parts).forEach((part) => {
2721                        var _a2, _b2, _c2, _d2, _e2;
2722                        const glue = (_a2 = activePreviewClothing.gluing) == null ? void 0 : _a2[part];
2723                        if (!glue || glue.type === "none") return;
2724                        const svgContent = activePreviewClothing.parts[part] || "";
2725                        const svgCoords = parseSvgSocketsAndPlugs(svgContent);
2726                        const p1Val = ((_c2 = (_b2 = activePreviewClothing.plugs) == null ? void 0 : _b2[part]) == null ? void 0 : _c2.p1) || svgCoords["plug_p1"] || glue.p1;
2727                        const p2Val = ((_e2 = (_d2 = activePreviewClothing.plugs) == null ? void 0 : _d2[part]) == null ? void 0 : _e2.p2) || svgCoords["plug_p2"] || glue.p2;
2728                        if (p1Val) {
2729                          const projected = getProjectedPt(`.custom-clothing-mount[data-target-joint="${part}"] .custom-clothing-offset`, p1Val);
2730                          const keyName = `clothing_plug_p1_${part}`;
2731                          const isSelected = editMode === keyName;
2732                          overlays.push(
2733                            /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { transform: `translate(${projected.x}, ${projected.y})`, children: [
2734                              /* @__PURE__ */ jsxRuntimeExports.jsx(
2735                                "circle",
2736                                {
2737                                  r: (isSelected ? 5 : 3.5) / viewZoom,
2738                                  fill: isSelected ? "#10b981" : "#ec4899",
2739                                  stroke: "white",
2740                                  strokeWidth: (isSelected ? 1.5 : 0.75) / viewZoom,
2741                                  className: "cursor-grab active:cursor-grabbing",
2742                                  onMouseDown: (e) => {
2743                                    e.stopPropagation();
2744                                    e.preventDefault();
2745                                    pushUndo();
2746                                    setEditMode(keyName);
2747                                    setDraggingPoint({ target: "clothing_plug", plugPart: part, plugKey: "p1" });
2748                                  }
2749                                }
2750                              ),
2751                              /* @__PURE__ */ jsxRuntimeExports.jsxs(
2752                                "text",
2753                                {
2754                                  y: -7 / viewZoom,
2755                                  textAnchor: "middle",
2756                                  fill: isSelected ? "#10b981" : "#fbcfe8",
2757                                  fontSize: 6 / viewZoom,
2758                                  fontWeight: "bold",
2759                                  className: "pointer-events-none select-none",
2760                                  style: { paintOrder: "stroke", stroke: "#000", strokeWidth: `${1.5 / viewZoom}px` },
2761                                  children: [
2762                                    part,
2763                                    "_p1"
2764                                  ]
2765                                }
2766                              )
2767                            ] }, `${part}_p1`)
2768                          );
2769                        }
2770                        if (glue.type === "two-point" && p2Val) {
2771                          const projected = getProjectedPt(`.custom-clothing-mount[data-target-joint="${part}"] .custom-clothing-offset`, p2Val);
2772                          const keyName = `clothing_plug_p2_${part}`;
2773                          const isSelected = editMode === keyName;
2774                          overlays.push(
2775                            /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { transform: `translate(${projected.x}, ${projected.y})`, children: [
2776                              /* @__PURE__ */ jsxRuntimeExports.jsx(
2777                                "circle",
2778                                {
2779                                  r: (isSelected ? 5 : 3.5) / viewZoom,
2780                                  fill: isSelected ? "#10b981" : "#ec4899",
2781                                  stroke: "white",
2782                                  strokeWidth: (isSelected ? 1.5 : 0.75) / viewZoom,
2783                                  className: "cursor-grab active:cursor-grabbing",
2784                                  onMouseDown: (e) => {
2785                                    e.stopPropagation();
2786                                    e.preventDefault();
2787                                    pushUndo();
2788                                    setEditMode(keyName);
2789                                    setDraggingPoint({ target: "clothing_plug", plugPart: part, plugKey: "p2" });
2790                                  }
2791                                }
2792                              ),
2793                              /* @__PURE__ */ jsxRuntimeExports.jsxs(
2794                                "text",
2795                                {
2796                                  y: -7 / viewZoom,
2797                                  textAnchor: "middle",
2798                                  fill: isSelected ? "#10b981" : "#fbcfe8",
2799                                  fontSize: 6 / viewZoom,
2800                                  fontWeight: "bold",
2801                                  className: "pointer-events-none select-none",
2802                                  style: { paintOrder: "stroke", stroke: "#000", strokeWidth: `${1.5 / viewZoom}px` },
2803                                  children: [
2804                                    part,
2805                                    "_p2"
2806                                  ]
2807                                }
2808                              )
2809                            ] }, `${part}_p2`)
2810                          );
2811                        }
2812                      });
2813                      return overlays;
2814                    })()
2815                  ] })
2816                ]
2817              }
2818            )
2819          ]
2820        }
2821      ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex items-center justify-center text-zinc-600", children: "Select a config to preview" }) }),
2822      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-[500px] border-l border-zinc-800 overflow-y-auto p-6 bg-[#050505] custom-scrollbar flex flex-col", children: [
2823        activePreviewConfig && activeTab !== "background" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6 border border-zinc-800 rounded-lg bg-[#0a0a0a] overflow-hidden flex flex-col shrink-0", children: [
2824          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 border-b border-zinc-800 bg-zinc-900 flex items-center justify-between", children: [
2825            /* @__PURE__ */ jsxRuntimeExports.jsxs(
2826              "div",
2827              {
2828                className: "flex items-center gap-2 cursor-pointer hover:text-white transition-colors text-zinc-400 font-bold text-sm",
2829                onClick: () => setIsOptionsCollapsed(!isOptionsCollapsed),
2830                children: [
2831                  isOptionsCollapsed ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 16 }),
2832                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "IK Preview" })
2833                ]
2834              }
2835            ),
2836            /* @__PURE__ */ jsxRuntimeExports.jsxs(
2837              "button",
2838              {
2839                onClick: () => setShowSkeleton(!showSkeleton),
2840                className: `flex items-center gap-1 text-xs px-2 py-1 rounded ${showSkeleton ? "bg-indigo-600/30 text-indigo-400" : "bg-zinc-800 text-zinc-500"}`,
2841                children: [
2842                  /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 12 }),
2843                  " ",
2844                  showSkeleton ? "Hide Skeleton" : "Show Skeleton"
2845                ]
2846              }
2847            ),
2848            /* @__PURE__ */ jsxRuntimeExports.jsxs(
2849              "button",
2850              {
2851                onClick: () => setShowActionPaths(!showActionPaths),
2852                className: `flex items-center gap-1 text-xs px-2 py-1 rounded ${showActionPaths ? "bg-emerald-600/30 text-emerald-400" : "bg-zinc-800 text-zinc-500"}`,
2853                children: [
2854                  /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 12 }),
2855                  " ",
2856                  showActionPaths ? "Hide Actions" : "Show Actions"
2857                ]
2858              }
2859            )
2860          ] }),
2861          !isOptionsCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 border-b border-zinc-800 bg-[#111] grid grid-cols-2 gap-2 text-xs", children: [
2862            activeTab !== "characters" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "col-span-2 flex items-center justify-between bg-zinc-900 p-2 rounded border border-zinc-800 mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
2863              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-500 text-xs font-bold uppercase tracking-wider whitespace-nowrap", children: activeTab === "instruments" ? "Assigned Character:" : "Preview Character:" }),
2864              /* @__PURE__ */ jsxRuntimeExports.jsxs(
2865                "select",
2866                {
2867                  value: activeTab === "instruments" && (selectedInstSvg == null ? void 0 : selectedInstSvg.characterId) ? selectedInstSvg.characterId : previewCharId,
2868                  onChange: (e) => {
2869                    const val = e.target.value;
2870                    setPreviewCharId(val);
2871                    if (activeTab === "instruments" && selectedInstKey) {
2872                      const instType = selectedInstKey.startsWith("m_") ? "melodic" : "percussion";
2873                      const instIndex = parseInt(selectedInstKey.split("_")[1]);
2874                      const currentInst = instrumentConfigs[instType][instIndex] || { svgContent: "", mountPoint: "body" };
2875                      setInstrumentConfigs((prev) => ({
2876                        ...prev,
2877                        [instType]: {
2878                          ...prev[instType],
2879                          [instIndex]: {
2880                            ...typeof currentInst === "string" ? { svgContent: currentInst, mountPoint: "body" } : currentInst,
2881                            characterId: val === "" ? void 0 : val
2882                          }
2883                        }
2884                      }));
2885                    }
2886                  },
2887                  className: "bg-[#111] border border-zinc-700 rounded p-1 text-white text-xs flex-1",
2888                  children: [
2889                    activeTab === "instruments" && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "(Default for Family)" }),
2890                    Object.keys(configs).map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: k, children: configs[k].name }, k))
2891                  ]
2892                }
2893              )
2894            ] }) }),
2895            activeTab !== "instruments" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "col-span-2 flex items-center justify-between bg-zinc-900 p-2 rounded border border-zinc-800 mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
2896              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-500 text-xs font-bold uppercase tracking-wider whitespace-nowrap", children: "Preview Instrument:" }),
2897              /* @__PURE__ */ jsxRuntimeExports.jsxs(
2898                "select",
2899                {
2900                  value: previewInstKey || "",
2901                  onChange: (e) => setPreviewInstKey(e.target.value || null),
2902                  className: "bg-[#111] border border-zinc-700 rounded p-1 text-white text-xs flex-1",
2903                  children: [
2904                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "None" }),
2905                    /* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Melodic", children: Object.keys(instrumentConfigs.melodic).map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: `m_${k}`, children: getInstrumentLabel("melodic", k) }, `m_${k}`)) }),
2906                    /* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Percussion", children: Object.keys(instrumentConfigs.percussion).map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: `p_${k}`, children: getInstrumentLabel("percussion", k) }, `p_${k}`)) })
2907                  ]
2908                }
2909              )
2910            ] }) }),
2911            activeTab !== "clothing" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "col-span-2 flex items-center justify-between bg-zinc-900 p-2 rounded border border-zinc-800 mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
2912              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-500 text-xs font-bold uppercase tracking-wider whitespace-nowrap", children: activeTab === "instruments" ? "Assigned Clothing:" : "Preview Clothing:" }),
2913              /* @__PURE__ */ jsxRuntimeExports.jsxs(
2914                "select",
2915                {
2916                  value: activeTab === "instruments" && (selectedInstSvg == null ? void 0 : selectedInstSvg.clothingId) ? selectedInstSvg.clothingId : previewClothingId || "",
2917                  onChange: (e) => {
2918                    const val = e.target.value || null;
2919                    setPreviewClothingId(val);
2920                    if (activeTab === "instruments" && selectedInstKey) {
2921                      const instType = selectedInstKey.startsWith("m_") ? "melodic" : "percussion";
2922                      const instIndex = parseInt(selectedInstKey.split("_")[1]);
2923                      const currentInst = instrumentConfigs[instType][instIndex] || { svgContent: "", mountPoint: "body" };
2924                      setInstrumentConfigs((prev) => ({
2925                        ...prev,
2926                        [instType]: {
2927                          ...prev[instType],
2928                          [instIndex]: {
2929                            ...typeof currentInst === "string" ? { svgContent: currentInst, mountPoint: "body" } : currentInst,
2930                            clothingId: val === null ? void 0 : val
2931                          }
2932                        }
2933                      }));
2934                    }
2935                  },
2936                  className: "bg-[#111] border border-zinc-700 rounded p-1 text-white text-xs flex-1",
2937                  children: [
2938                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: activeTab === "instruments" ? "(Randomly Assigned)" : "None" }),
2939                    activeTab === "instruments" && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "No Clothing" }),
2940                    Object.keys(clothingConfigs).map((k) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: k, children: k }, k))
2941                  ]
2942                }
2943              )
2944            ] }) }),
2945            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 space-y-1 mt-2", children: [
2946              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-1 uppercase tracking-wider text-[10px]", children: "Parts Visibility & Z-Layer Order" }),
2947              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-x-auto rounded border border-zinc-800 bg-zinc-950", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-left text-xs border-collapse", children: [
2948                /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-zinc-800 bg-zinc-900 text-zinc-400 font-semibold text-[10px]", children: [
2949                  /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-2", children: "Part" }),
2950                  /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-2 text-center", children: "Visible" }),
2951                  /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "p-2 text-center w-24", children: "Z-Order" })
2952                ] }) }),
2953                /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: (() => {
2954                  const staticOrder = [
2955                    "head",
2956                    "clothing_head",
2957                    "body",
2958                    "clothing_body",
2959                    "upper_arm_l",
2960                    "clothing_upper_arm_l",
2961                    "lower_arm_l",
2962                    "clothing_lower_arm_l",
2963                    "hand_l",
2964                    "clothing_hand_l",
2965                    "upper_arm_r",
2966                    "clothing_upper_arm_r",
2967                    "lower_arm_r",
2968                    "clothing_lower_arm_r",
2969                    "hand_r",
2970                    "clothing_hand_r",
2971                    "leg_l",
2972                    "clothing_leg_l",
2973                    "foot_l",
2974                    "clothing_foot_l",
2975                    "leg_r",
2976                    "clothing_leg_r",
2977                    "foot_r",
2978                    "clothing_foot_r",
2979                    "instrument"
2980                  ];
2981                  const sortKeys = (keys) => {
2982                    return [...keys].sort((a, b) => {
2983                      let idxA = staticOrder.indexOf(a);
2984                      let idxB = staticOrder.indexOf(b);
2985                      if (idxA === -1) idxA = 999;
2986                      if (idxB === -1) idxB = 999;
2987                      return idxA - idxB;
2988                    });
2989                  };
2990                  const bodyParts = [
2991                    "head",
2992                    "body",
2993                    "upper_arm_l",
2994                    "lower_arm_l",
2995                    "hand_l",
2996                    "upper_arm_r",
2997                    "lower_arm_r",
2998                    "hand_r",
2999                    "leg_l",
3000                    "foot_l",
3001                    "leg_r",
3002                    "foot_r"
3003                  ];
3004                  const allKeys = Object.keys(visibility);
3005                  const groups = [
3006                    {
3007                      id: "character",
3008                      name: "Character",
3009                      icon: "👤",
3010                      keys: allKeys.filter((k) => !k.startsWith("clothing_") && k !== "instrument" && bodyParts.includes(k))
3011                    },
3012                    {
3013                      id: "clothing",
3014                      name: "Clothing",
3015                      icon: "👕",
3016                      keys: allKeys.filter((k) => k.startsWith("clothing_"))
3017                    },
3018                    {
3019                      id: "accessory",
3020                      name: "Accessory",
3021                      icon: "🎸",
3022                      keys: allKeys.filter((k) => !k.startsWith("clothing_") && k !== "instrument" && !bodyParts.includes(k)).concat(allKeys.includes("instrument") ? ["instrument"] : [])
3023                    }
3024                  ];
3025                  return groups.map((group) => {
3026                    const isCollapsed = collapsedGroups[group.id];
3027                    const sortedKeys = sortKeys(group.keys);
3028                    return /* @__PURE__ */ jsxRuntimeExports.jsxs(React.Fragment, { children: [
3029                      /* @__PURE__ */ jsxRuntimeExports.jsxs(
3030                        "tr",
3031                        {
3032                          className: "bg-zinc-900/80 border-b border-zinc-800 cursor-pointer select-none hover:bg-zinc-900 text-zinc-300 font-bold",
3033                          onClick: () => setCollapsedGroups((prev) => ({ ...prev, [group.id]: !prev[group.id] })),
3034                          children: [
3035                            /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-[11px] hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
3036                              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500 w-3 inline-block", children: isCollapsed ? "▶" : "▼" }),
3037                              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: group.icon }),
3038                              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: group.name }),
3039                              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-500 font-normal text-[10px]", children: [
3040                                "(",
3041                                sortedKeys.length,
3042                                " items)"
3043                              ] })
3044                            ] }) }),
3045                            /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-center", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3046                              "input",
3047                              {
3048                                type: "checkbox",
3049                                checked: group.keys.length > 0 && group.keys.every((k) => !!visibility[k]),
3050                                onChange: (e) => {
3051                                  const targetVal = e.target.checked;
3052                                  if (!selectedId) return;
3053                                  pushUndo();
3054                                  const next = { ...visibility };
3055                                  group.keys.forEach((k) => {
3056                                    next[k] = targetVal;
3057                                  });
3058                                  setVisibility(next);
3059                                  handleConfigChange(selectedId, { visibility: next });
3060                                },
3061                                className: "rounded bg-zinc-850 border-zinc-700 text-indigo-600 focus:ring-indigo-500 cursor-pointer pointer-events-auto relative z-50"
3062                              }
3063                            ) }),
3064                            /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 w-24" })
3065                          ]
3066                        }
3067                      ),
3068                      !isCollapsed && sortedKeys.map((part) => {
3069                        var _a2, _b2;
3070                        const defaults = {
3071                          leg_l: 1,
3072                          clothing_leg_l: 1.5,
3073                          leg_r: 2,
3074                          clothing_leg_r: 2.5,
3075                          foot_l: 3,
3076                          foot_r: 4,
3077                          body: 5,
3078                          clothing_body: 5.5,
3079                          head: 6,
3080                          clothing_head: 6.5,
3081                          upper_arm_r: 7,
3082                          clothing_upper_arm_r: 7.2,
3083                          lower_arm_r: 8,
3084                          clothing_lower_arm_r: 8.2,
3085                          hand_r: 9,
3086                          clothing_hand_r: 9.2,
3087                          instrument: 10,
3088                          upper_arm_l: 11,
3089                          clothing_upper_arm_l: 11.2,
3090                          lower_arm_l: 12,
3091                          clothing_lower_arm_l: 12.2,
3092                          hand_l: 13,
3093                          clothing_hand_l: 13.2
3094                        };
3095                        const isZEditable = activeTab === "characters" ? !!selectedId : !!activePreviewInst;
3096                        const currentZ = activeTab === "characters" ? ((_a2 = selectedConfig == null ? void 0 : selectedConfig.baseZOrder) == null ? void 0 : _a2[part]) ?? defaults[part] ?? 0 : ((_b2 = activePreviewInst == null ? void 0 : activePreviewInst.zOrder) == null ? void 0 : _b2[part]) ?? defaults[part] ?? 0;
3097                        return /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-zinc-900 hover:bg-zinc-900/40 bg-zinc-950/20", children: [
3098                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 pl-6 text-zinc-300 capitalize font-medium text-[11px]", children: part.startsWith("clothing_") ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
3099                            part.replace("clothing_", "Clothing ").replace("_l", " (L)").replace("_r", " (R)"),
3100                            " ",
3101                            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-500 font-normal lowercase italic text-[10px]", children: [
3102                              "(linked to ",
3103                              part.replace("clothing_", "").replace("_l", " (L)").replace("_r", " (R)"),
3104                              ")"
3105                            ] })
3106                          ] }) : part.replace("_l", " (L)").replace("_r", " (R)") }),
3107                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-center", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3108                            "input",
3109                            {
3110                              type: "checkbox",
3111                              checked: !!visibility[part],
3112                              onChange: () => {
3113                                if (!selectedId) return;
3114                                pushUndo();
3115                                const next = { ...visibility, [part]: !visibility[part] };
3116                                setVisibility(next);
3117                                handleConfigChange(selectedId, { visibility: next });
3118                              },
3119                              className: "rounded bg-zinc-850 border-zinc-700 text-indigo-600 focus:ring-indigo-500 cursor-pointer pointer-events-auto relative z-50"
3120                            }
3121                          ) }),
3122                          /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "p-2 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3123                            "input",
3124                            {
3125                              type: "number",
3126                              step: "any",
3127                              value: currentZ,
3128                              disabled: !isZEditable,
3129                              onChange: (e) => {
3130                                const val = parseFloat(e.target.value) || 0;
3131                                if (activeTab === "characters") {
3132                                  if (!selectedId) return;
3133                                  pushUndo();
3134                                  const currentBaseZ = (selectedConfig == null ? void 0 : selectedConfig.baseZOrder) || {};
3135                                  const nextBaseZ = { ...currentBaseZ, [part]: val };
3136                                  handleConfigChange(selectedId, { baseZOrder: nextBaseZ });
3137                                } else {
3138                                  handleZOrderChange(part, val);
3139                                }
3140                              },
3141                              className: "w-16 bg-zinc-900 border border-zinc-800 rounded px-1 py-0.5 text-center text-zinc-200 text-xs font-mono disabled:opacity-40 disabled:cursor-not-allowed"
3142                            }
3143                          ) })
3144                        ] }, part);
3145                      })
3146                    ] }, group.id);
3147                  });
3148                })() })
3149              ] }) }),
3150              !activePreviewInst && activeTab !== "characters" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500 italic mt-1", children: "Select an instrument to edit Z-order values." })
3151            ] }),
3152            (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 grid grid-cols-2 gap-2 mt-2", children: [
3153              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3154                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-1 uppercase tracking-wider text-[10px]", children: "Left Hand Logic" }),
3155                /* @__PURE__ */ jsxRuntimeExports.jsxs(
3156                  "select",
3157                  {
3158                    value: ((_d = activePreviewInst == null ? void 0 : activePreviewInst.leftHandMotion) == null ? void 0 : _d.logic) || "none",
3159                    onChange: (e) => {
3160                      const logic = e.target.value;
3161                      setInstrumentConfigs((prev) => {
3162                        const typeObj = prev[editingInstType];
3163                        const instObj = typeObj[editingInstIndex] || {};
3164                        const m = instObj.leftHandMotion || { logic: "none", start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
3165                        return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, leftHandMotion: { ...m, logic } } } };
3166                      });
3167                    },
3168                    className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-[10px]",
3169                    children: [
3170                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None (Fixed Point)" }),
3171                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "oscillate", children: "Oscillate (Sine)" }),
3172                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "strike", children: "Strike (Bounce)" }),
3173                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pitch_map", children: "Pitch Map (Slide)" }),
3174                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "phrase_bow", children: "Phrase Bow" })
3175                    ]
3176                  }
3177                )
3178              ] }),
3179              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3180                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-1 uppercase tracking-wider text-[10px]", children: "Right Hand Logic" }),
3181                /* @__PURE__ */ jsxRuntimeExports.jsxs(
3182                  "select",
3183                  {
3184                    value: ((_e = activePreviewInst == null ? void 0 : activePreviewInst.rightHandMotion) == null ? void 0 : _e.logic) || "none",
3185                    onChange: (e) => {
3186                      const logic = e.target.value;
3187                      setInstrumentConfigs((prev) => {
3188                        const typeObj = prev[editingInstType];
3189                        const instObj = typeObj[editingInstIndex] || {};
3190                        const m = instObj.rightHandMotion || { logic: "none", start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
3191                        return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, rightHandMotion: { ...m, logic } } } };
3192                      });
3193                    },
3194                    className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-[10px]",
3195                    children: [
3196                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None (Fixed Point)" }),
3197                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "oscillate", children: "Oscillate (Sine)" }),
3198                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "strike", children: "Strike (Bounce)" }),
3199                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pitch_map", children: "Pitch Map (Slide)" }),
3200                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "phrase_bow", children: "Phrase Bow" })
3201                    ]
3202                  }
3203                )
3204              ] })
3205            ] }),
3206            (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 mt-3 border-t border-zinc-800 pt-3 space-y-2", children: [
3207              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-2 uppercase tracking-wider text-[10px]", children: "Body Behavior (when playing)" }),
3208              [
3209                { key: "bodySway", label: "Body Sway", defaultVal: 20, max: 60, step: 0.5 },
3210                { key: "headSway", label: "Head Sway", defaultVal: 1, max: 5, step: 0.1 },
3211                { key: "fingerFlutter", label: "Finger Flutter", defaultVal: 2, max: 10, step: 0.5 },
3212                { key: "grooveSway", label: "Groove Sway", defaultVal: 1, max: 3, step: 0.1 },
3213                { key: "headRotation", label: "Head Rotation", defaultVal: 1, max: 3, step: 0.1 },
3214                { key: "footTap", label: "Foot Tap", defaultVal: 1, max: 3, step: 0.1 }
3215              ].map(({ key, label, defaultVal, max, step }) => {
3216                var _a2;
3217                const currentVal = ((_a2 = activePreviewInst == null ? void 0 : activePreviewInst.bodyBehavior) == null ? void 0 : _a2[key]) ?? defaultVal;
3218                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
3219                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-400 text-[10px] w-24 shrink-0", children: label }),
3220                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3221                    "input",
3222                    {
3223                      type: "range",
3224                      min: 0,
3225                      max,
3226                      step,
3227                      value: currentVal,
3228                      onChange: (e) => {
3229                        const val = parseFloat(e.target.value);
3230                        setInstrumentConfigs((prev) => {
3231                          const typeObj = prev[editingInstType];
3232                          const instObj = typeObj[editingInstIndex] || {};
3233                          const bb = instObj.bodyBehavior || {};
3234                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, bodyBehavior: { ...bb, [key]: val } } } };
3235                        });
3236                      },
3237                      className: "flex-1 accent-indigo-500"
3238                    }
3239                  ),
3240                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-300 text-[10px] w-8 text-right", children: currentVal }),
3241                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3242                    "button",
3243                    {
3244                      onClick: () => {
3245                        setInstrumentConfigs((prev) => {
3246                          const typeObj = prev[editingInstType];
3247                          const instObj = typeObj[editingInstIndex] || {};
3248                          const bb = { ...instObj.bodyBehavior || {} };
3249                          bb[key] = defaultVal;
3250                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, bodyBehavior: bb } } };
3251                        });
3252                      },
3253                      title: "Reset to default",
3254                      className: "text-zinc-600 hover:text-zinc-300 text-[9px]",
3255                      children: "↺"
3256                    }
3257                  )
3258                ] }, key);
3259              }),
3260              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 text-zinc-500 font-bold mb-2 uppercase tracking-wider text-[10px]", children: "Idle Behavior (when not playing)" }),
3261              [
3262                { key: "bodySway", label: "Body Sway (Mult)", defaultVal: 1, max: 2, step: 0.1 },
3263                { key: "headSway", label: "Head Sway (Mult)", defaultVal: 1, max: 2, step: 0.1 },
3264                { key: "armSway", label: "Arm Sway (Mult)", defaultVal: 1, max: 2, step: 0.1 }
3265              ].map(({ key, label, defaultVal, max, step }) => {
3266                var _a2;
3267                const currentVal = ((_a2 = activePreviewInst == null ? void 0 : activePreviewInst.idleBehavior) == null ? void 0 : _a2[key]) ?? defaultVal;
3268                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
3269                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-400 text-[10px] w-24 shrink-0", children: label }),
3270                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3271                    "input",
3272                    {
3273                      type: "range",
3274                      min: 0,
3275                      max,
3276                      step,
3277                      value: currentVal,
3278                      onChange: (e) => {
3279                        const val = parseFloat(e.target.value);
3280                        setInstrumentConfigs((prev) => {
3281                          const typeObj = prev[editingInstType];
3282                          const instObj = typeObj[editingInstIndex] || {};
3283                          const ib = instObj.idleBehavior || {};
3284                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, idleBehavior: { ...ib, [key]: val } } } };
3285                        });
3286                      },
3287                      className: "flex-1 accent-indigo-500"
3288                    }
3289                  ),
3290                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-300 text-[10px] w-8 text-right", children: currentVal }),
3291                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3292                    "button",
3293                    {
3294                      onClick: () => {
3295                        setInstrumentConfigs((prev) => {
3296                          const typeObj = prev[editingInstType];
3297                          const instObj = typeObj[editingInstIndex] || {};
3298                          const ib = { ...instObj.idleBehavior || {} };
3299                          ib[key] = defaultVal;
3300                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, idleBehavior: ib } } };
3301                        });
3302                      },
3303                      title: "Reset to default",
3304                      className: "text-zinc-600 hover:text-zinc-300 text-[9px]",
3305                      children: "↺"
3306                    }
3307                  )
3308                ] }, key);
3309              }),
3310              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 border-t border-zinc-800 pt-3 space-y-2", children: [
3311                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-1 uppercase tracking-wider text-[10px]", children: "Head/Mouth Anchor" }),
3312                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
3313                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400", children: "Lock head to instrument (mouthpiece)" }),
3314                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3315                    "button",
3316                    {
3317                      onClick: () => {
3318                        setInstrumentConfigs((prev) => {
3319                          const typeObj = prev[editingInstType];
3320                          const instObj = typeObj[editingInstIndex] || {};
3321                          const newInst = { ...instObj };
3322                          if (newInst.headAnchor) {
3323                            delete newInst.headAnchor;
3324                          } else {
3325                            newInst.headAnchor = { x: 0, y: -70 };
3326                          }
3327                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: newInst } };
3328                        });
3329                      },
3330                      className: `px-2 py-1 rounded text-[10px] font-bold transition-colors ${(activePreviewInst == null ? void 0 : activePreviewInst.headAnchor) ? "bg-emerald-600/30 text-emerald-400 border border-emerald-500/30" : "bg-zinc-800 text-zinc-500"}`,
3331                      children: (activePreviewInst == null ? void 0 : activePreviewInst.headAnchor) ? "Locked (Green Dot)" : "Unlocked"
3332                    }
3333                  )
3334                ] })
3335              ] }),
3336              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 border-t border-zinc-800 pt-3 space-y-2", children: [
3337                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-2 uppercase tracking-wider text-[10px]", children: "Motion Physics & Rest Pose" }),
3338                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2 bg-black/20 p-1.5 rounded", children: [
3339                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3340                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[8px] text-zinc-500 uppercase", children: "Left Hand rest (X,Y)" }),
3341                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1", children: [
3342                      /* @__PURE__ */ jsxRuntimeExports.jsx(
3343                        "input",
3344                        {
3345                          type: "number",
3346                          placeholder: "X",
3347                          value: ((_g = (_f = activePreviewInst == null ? void 0 : activePreviewInst.restPose) == null ? void 0 : _f.leftHand) == null ? void 0 : _g.x) ?? "",
3348                          onChange: (e) => {
3349                            const val = parseFloat(e.target.value);
3350                            setInstrumentConfigs((prev) => {
3351                              const typeObj = prev[editingInstType];
3352                              const instObj = typeObj[editingInstIndex] || {};
3353                              const rp = instObj.restPose || {};
3354                              return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, restPose: { ...rp, leftHand: isNaN(val) ? void 0 : { ...rp.leftHand || {}, x: val } } } } };
3355                            });
3356                          },
3357                          className: "w-1/2 bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3358                        }
3359                      ),
3360                      /* @__PURE__ */ jsxRuntimeExports.jsx(
3361                        "input",
3362                        {
3363                          type: "number",
3364                          placeholder: "Y",
3365                          value: ((_i = (_h = activePreviewInst == null ? void 0 : activePreviewInst.restPose) == null ? void 0 : _h.leftHand) == null ? void 0 : _i.y) ?? "",
3366                          onChange: (e) => {
3367                            const val = parseFloat(e.target.value);
3368                            setInstrumentConfigs((prev) => {
3369                              const typeObj = prev[editingInstType];
3370                              const instObj = typeObj[editingInstIndex] || {};
3371                              const rp = instObj.restPose || {};
3372                              return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, restPose: { ...rp, leftHand: isNaN(val) ? void 0 : { ...rp.leftHand || {}, y: val } } } } };
3373                            });
3374                          },
3375                          className: "w-1/2 bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3376                        }
3377                      )
3378                    ] })
3379                  ] }),
3380                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3381                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[8px] text-zinc-500 uppercase", children: "Right Hand rest (X,Y)" }),
3382                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1", children: [
3383                      /* @__PURE__ */ jsxRuntimeExports.jsx(
3384                        "input",
3385                        {
3386                          type: "number",
3387                          placeholder: "X",
3388                          value: ((_k = (_j = activePreviewInst == null ? void 0 : activePreviewInst.restPose) == null ? void 0 : _j.rightHand) == null ? void 0 : _k.x) ?? "",
3389                          onChange: (e) => {
3390                            const val = parseFloat(e.target.value);
3391                            setInstrumentConfigs((prev) => {
3392                              const typeObj = prev[editingInstType];
3393                              const instObj = typeObj[editingInstIndex] || {};
3394                              const rp = instObj.restPose || {};
3395                              return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, restPose: { ...rp, rightHand: isNaN(val) ? void 0 : { ...rp.rightHand || {}, x: val } } } } };
3396                            });
3397                          },
3398                          className: "w-1/2 bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3399                        }
3400                      ),
3401                      /* @__PURE__ */ jsxRuntimeExports.jsx(
3402                        "input",
3403                        {
3404                          type: "number",
3405                          placeholder: "Y",
3406                          value: ((_m = (_l = activePreviewInst == null ? void 0 : activePreviewInst.restPose) == null ? void 0 : _l.rightHand) == null ? void 0 : _m.y) ?? "",
3407                          onChange: (e) => {
3408                            const val = parseFloat(e.target.value);
3409                            setInstrumentConfigs((prev) => {
3410                              const typeObj = prev[editingInstType];
3411                              const instObj = typeObj[editingInstIndex] || {};
3412                              const rp = instObj.restPose || {};
3413                              return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, restPose: { ...rp, rightHand: isNaN(val) ? void 0 : { ...rp.rightHand || {}, y: val } } } } };
3414                            });
3415                          },
3416                          className: "w-1/2 bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3417                        }
3418                      )
3419                    ] })
3420                  ] })
3421                ] }),
3422                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-3 gap-1 bg-black/20 p-1.5 rounded", children: [
3423                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3424                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[8px] text-zinc-500 uppercase", children: "Min Note" }),
3425                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3426                      "input",
3427                      {
3428                        type: "number",
3429                        value: ((_n = activePreviewInst == null ? void 0 : activePreviewInst.noteRange) == null ? void 0 : _n.minNote) ?? "",
3430                        onChange: (e) => {
3431                          const val = parseInt(e.target.value);
3432                          setInstrumentConfigs((prev) => {
3433                            const typeObj = prev[editingInstType];
3434                            const instObj = typeObj[editingInstIndex] || {};
3435                            const nr = instObj.noteRange || {};
3436                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, noteRange: { ...nr, minNote: isNaN(val) ? void 0 : val } } } };
3437                          });
3438                        },
3439                        className: "w-full bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3440                      }
3441                    )
3442                  ] }),
3443                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3444                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[8px] text-zinc-500 uppercase", children: "Max Note" }),
3445                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3446                      "input",
3447                      {
3448                        type: "number",
3449                        value: ((_o = activePreviewInst == null ? void 0 : activePreviewInst.noteRange) == null ? void 0 : _o.maxNote) ?? "",
3450                        onChange: (e) => {
3451                          const val = parseInt(e.target.value);
3452                          setInstrumentConfigs((prev) => {
3453                            const typeObj = prev[editingInstType];
3454                            const instObj = typeObj[editingInstIndex] || {};
3455                            const nr = instObj.noteRange || {};
3456                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, noteRange: { ...nr, maxNote: isNaN(val) ? void 0 : val } } } };
3457                          });
3458                        },
3459                        className: "w-full bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3460                      }
3461                    )
3462                  ] }),
3463                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3464                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[8px] text-zinc-500 uppercase", children: "Width (px)" }),
3465                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3466                      "input",
3467                      {
3468                        type: "number",
3469                        value: ((_p = activePreviewInst == null ? void 0 : activePreviewInst.noteRange) == null ? void 0 : _p.physicalLength) ?? "",
3470                        onChange: (e) => {
3471                          const val = parseInt(e.target.value);
3472                          setInstrumentConfigs((prev) => {
3473                            const typeObj = prev[editingInstType];
3474                            const instObj = typeObj[editingInstIndex] || {};
3475                            const nr = instObj.noteRange || {};
3476                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, noteRange: { ...nr, physicalLength: isNaN(val) ? void 0 : val } } } };
3477                          });
3478                        },
3479                        className: "w-full bg-zinc-900 border border-zinc-700 rounded p-0.5 text-white text-[9px]"
3480                      }
3481                    )
3482                  ] })
3483                ] }),
3484                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 bg-black/20 p-1.5 rounded", children: [
3485                  { key: "swayFrequency", label: "Sway Freq", defaultVal: 5e-3, min: 1e-3, max: 0.05, step: 1e-3 },
3486                  { key: "strikeFrequency", label: "Strike Freq", defaultVal: 0.02, min: 5e-3, max: 0.1, step: 5e-3 },
3487                  { key: "strikeAmplitude", label: "Strike Amp", defaultVal: 10, min: 0, max: 40, step: 1 },
3488                  { key: "bowPhaseStep", label: "Bow Step", defaultVal: 0.05, min: 0.01, max: 0.2, step: 0.01 },
3489                  { key: "bowGapMs", label: "Bow Gap (ms)", defaultVal: 500, min: 50, max: 2e3, step: 50 },
3490                  { key: "strumSpeedMult", label: "Strum Speed", defaultVal: 0.03, min: 5e-3, max: 0.15, step: 5e-3 },
3491                  { key: "strumVerticalAmp", label: "Strum Vert", defaultVal: 15, min: 0, max: 60, step: 1 },
3492                  { key: "strumHorizontalAmp", label: "Strum Horiz", defaultVal: 5, min: 0, max: 30, step: 1 },
3493                  { key: "ikLerpL", label: "IK Lerp L", defaultVal: 0.3, min: 0.01, max: 1, step: 0.01 },
3494                  { key: "ikLerpR", label: "IK Lerp R", defaultVal: 0.3, min: 0.01, max: 1, step: 0.01 }
3495                ].map(({ key, label, defaultVal, min, max, step }) => {
3496                  var _a2;
3497                  const currentVal = ((_a2 = activePreviewInst == null ? void 0 : activePreviewInst.motionPhysics) == null ? void 0 : _a2[key]) ?? defaultVal;
3498                  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
3499                    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-400 text-xs w-24 shrink-0", children: label }),
3500                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3501                      "input",
3502                      {
3503                        type: "range",
3504                        min,
3505                        max,
3506                        step,
3507                        value: currentVal,
3508                        onChange: (e) => {
3509                          const val = parseFloat(e.target.value);
3510                          setInstrumentConfigs((prev) => {
3511                            const typeObj = prev[editingInstType];
3512                            const instObj = typeObj[editingInstIndex] || {};
3513                            const mp = instObj.motionPhysics || {};
3514                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, motionPhysics: { ...mp, [key]: val } } } };
3515                          });
3516                        },
3517                        className: "flex-1 accent-indigo-500 h-1"
3518                      }
3519                    ),
3520                    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-300 text-xs w-10 text-right", children: currentVal }),
3521                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3522                      "button",
3523                      {
3524                        onClick: () => {
3525                          setInstrumentConfigs((prev) => {
3526                            const typeObj = prev[editingInstType];
3527                            const instObj = typeObj[editingInstIndex] || {};
3528                            const mp = { ...instObj.motionPhysics || {} };
3529                            delete mp[key];
3530                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, motionPhysics: Object.keys(mp).length > 0 ? mp : void 0 } } };
3531                          });
3532                        },
3533                        className: "text-zinc-500 hover:text-zinc-300 text-xs",
3534                        children: "↺"
3535                      }
3536                    )
3537                  ] }, key);
3538                }) })
3539              ] })
3540            ] }),
3541            (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 mt-3 border-t border-zinc-800 pt-3 space-y-2", children: [
3542              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
3543                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-400 font-bold uppercase tracking-wider text-xs", children: "Instrument Playing Actions" }),
3544                /* @__PURE__ */ jsxRuntimeExports.jsxs(
3545                  "button",
3546                  {
3547                    onClick: () => {
3548                      setInstrumentConfigs((prev) => {
3549                        const typeObj = prev[editingInstType];
3550                        const instObj = typeObj[editingInstIndex] || {};
3551                        const actions = instObj.actions || [];
3552                        const newAction = {
3553                          id: `inst_${editingInstType}_${editingInstIndex}_${Date.now()}`,
3554                          name: "New Instrument Action",
3555                          category: "instrument",
3556                          trigger: "playing",
3557                          priority: 60,
3558                          duration: 2e3,
3559                          tempoSync: true,
3560                          loop: true,
3561                          blendInMs: 300,
3562                          blendOutMs: 300,
3563                          channels: [],
3564                          affectedJoints: []
3565                        };
3566                        return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions: [...actions, newAction] } } };
3567                      });
3568                    },
3569                    className: "text-indigo-400 hover:text-indigo-300 text-[10px] flex items-center gap-0.5",
3570                    children: [
3571                      /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 10 }),
3572                      " Add"
3573                    ]
3574                  }
3575                )
3576              ] }),
3577              ((activePreviewInst == null ? void 0 : activePreviewInst.actions) || []).length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 text-xs italic", children: "No instrument-specific actions. Uses body actions from the Actions tab." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1.5", children: ((activePreviewInst == null ? void 0 : activePreviewInst.actions) || []).map((action, aIdx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900 rounded border border-zinc-800 p-2 space-y-1.5", children: [
3578                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
3579                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3580                    "input",
3581                    {
3582                      value: action.name,
3583                      onChange: (e) => {
3584                        setInstrumentConfigs((prev) => {
3585                          const typeObj = prev[editingInstType];
3586                          const instObj = typeObj[editingInstIndex] || {};
3587                          const actions = [...instObj.actions || []];
3588                          actions[aIdx] = { ...actions[aIdx], name: e.target.value };
3589                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3590                        });
3591                      },
3592                      className: "bg-transparent text-zinc-200 text-[10px] font-bold border-b border-zinc-700 flex-1 focus:outline-none focus:border-indigo-500"
3593                    }
3594                  ),
3595                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 ml-2", children: [
3596                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[8px] px-1 rounded ${action.trigger === "playing" ? "bg-blue-900/50 text-blue-300" : "bg-amber-900/50 text-amber-300"}`, children: action.trigger }),
3597                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[8px] text-zinc-600", children: [
3598                      action.channels.length,
3599                      "ch"
3600                    ] }),
3601                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3602                      "button",
3603                      {
3604                        onClick: () => {
3605                          setInstrumentConfigs((prev) => {
3606                            const typeObj = prev[editingInstType];
3607                            const instObj = typeObj[editingInstIndex] || {};
3608                            const actions = (instObj.actions || []).filter((_, i) => i !== aIdx);
3609                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3610                          });
3611                        },
3612                        className: "text-zinc-600 hover:text-red-400",
3613                        children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
3614                      }
3615                    )
3616                  ] })
3617                ] }),
3618                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-[9px]", children: [
3619                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
3620                    "select",
3621                    {
3622                      value: action.trigger,
3623                      onChange: (e) => {
3624                        setInstrumentConfigs((prev) => {
3625                          const typeObj = prev[editingInstType];
3626                          const instObj = typeObj[editingInstIndex] || {};
3627                          const actions = [...instObj.actions || []];
3628                          actions[aIdx] = { ...actions[aIdx], trigger: e.target.value };
3629                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3630                        });
3631                      },
3632                      className: "bg-zinc-800 border border-zinc-700 text-zinc-300 rounded px-1 py-0.5",
3633                      children: [
3634                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "playing", children: "Playing" }),
3635                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "idle", children: "Idle" }),
3636                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "note_on", children: "Note On" }),
3637                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "always", children: "Always" })
3638                      ]
3639                    }
3640                  ),
3641                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-600", children: "P:" }),
3642                  /* @__PURE__ */ jsxRuntimeExports.jsx(
3643                    "input",
3644                    {
3645                      type: "number",
3646                      value: action.priority,
3647                      onChange: (e) => {
3648                        setInstrumentConfigs((prev) => {
3649                          const typeObj = prev[editingInstType];
3650                          const instObj = typeObj[editingInstIndex] || {};
3651                          const actions = [...instObj.actions || []];
3652                          actions[aIdx] = { ...actions[aIdx], priority: parseInt(e.target.value) || 0 };
3653                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3654                        });
3655                      },
3656                      className: "w-10 bg-zinc-800 border border-zinc-700 text-zinc-300 rounded px-1 py-0.5"
3657                    }
3658                  ),
3659                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1 text-zinc-400 cursor-pointer", children: [
3660                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3661                      "input",
3662                      {
3663                        type: "checkbox",
3664                        checked: action.loop,
3665                        onChange: (e) => {
3666                          setInstrumentConfigs((prev) => {
3667                            const typeObj = prev[editingInstType];
3668                            const instObj = typeObj[editingInstIndex] || {};
3669                            const actions = [...instObj.actions || []];
3670                            actions[aIdx] = { ...actions[aIdx], loop: e.target.checked };
3671                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3672                          });
3673                        },
3674                        className: "accent-indigo-500"
3675                      }
3676                    ),
3677                    "Loop"
3678                  ] }),
3679                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1 text-zinc-400 cursor-pointer", children: [
3680                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3681                      "input",
3682                      {
3683                        type: "checkbox",
3684                        checked: action.tempoSync,
3685                        onChange: (e) => {
3686                          setInstrumentConfigs((prev) => {
3687                            const typeObj = prev[editingInstType];
3688                            const instObj = typeObj[editingInstIndex] || {};
3689                            const actions = [...instObj.actions || []];
3690                            actions[aIdx] = { ...actions[aIdx], tempoSync: e.target.checked };
3691                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3692                          });
3693                        },
3694                        className: "accent-indigo-500"
3695                      }
3696                    ),
3697                    "Sync"
3698                  ] })
3699                ] }),
3700                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
3701                  action.channels.map((ch, cIdx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-[8px] bg-black/30 rounded px-1.5 py-1", children: [
3702                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-1 rounded ${ch.type === "wave" ? "bg-blue-900/50 text-blue-300" : "bg-purple-900/50 text-purple-300"}`, children: ch.type }),
3703                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-300", children: [
3704                      ch.joint,
3705                      ".",
3706                      ch.property
3707                    ] }),
3708                    ch.type === "wave" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-600", children: [
3709                      "f=",
3710                      ch.frequency,
3711                      " a=",
3712                      ch.amplitude
3713                    ] }),
3714                    ch.type === "keyframe" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-600", children: [
3715                      (ch.keyframes || []).length,
3716                      " kf"
3717                    ] }),
3718                    /* @__PURE__ */ jsxRuntimeExports.jsx(
3719                      "button",
3720                      {
3721                        onClick: () => {
3722                          setInstrumentConfigs((prev) => {
3723                            const typeObj = prev[editingInstType];
3724                            const instObj = typeObj[editingInstIndex] || {};
3725                            const actions = [...instObj.actions || []];
3726                            actions[aIdx] = { ...actions[aIdx], channels: actions[aIdx].channels.filter((_, i) => i !== cIdx) };
3727                            return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3728                          });
3729                        },
3730                        className: "text-zinc-600 hover:text-red-400 ml-auto",
3731                        children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 8 })
3732                      }
3733                    )
3734                  ] }, cIdx)),
3735                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
3736                    "button",
3737                    {
3738                      onClick: () => {
3739                        const newCh = { joint: "body", property: "y", type: "wave", waveform: "sine", frequency: 1, amplitude: 5, amplitudeBase: 0, intensityScale: 1, phase: 0, offset: 0 };
3740                        setInstrumentConfigs((prev) => {
3741                          const typeObj = prev[editingInstType];
3742                          const instObj = typeObj[editingInstIndex] || {};
3743                          const actions = [...instObj.actions || []];
3744                          actions[aIdx] = { ...actions[aIdx], channels: [...actions[aIdx].channels, newCh] };
3745                          return { ...prev, [editingInstType]: { ...typeObj, [editingInstIndex]: { ...instObj, actions } } };
3746                        });
3747                      },
3748                      className: "text-indigo-400 hover:text-indigo-300 text-[8px] flex items-center gap-0.5",
3749                      children: [
3750                        /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 8 }),
3751                        " Add Channel"
3752                      ]
3753                    }
3754                  )
3755                ] })
3756              ] }, action.id || aIdx)) })
3757            ] }),
3758            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 space-y-1 mt-2", children: [
3759              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 font-bold mb-1 uppercase tracking-wider", children: "Interactive Edit Mode" }),
3760              /* @__PURE__ */ jsxRuntimeExports.jsxs(
3761                "select",
3762                {
3763                  value: editMode,
3764                  onChange: (e) => setEditMode(e.target.value),
3765                  className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white",
3766                  children: [
3767                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None (View Only)" }),
3768                    activeTab === "characters" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3769                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "anchor", children: "Reposition Anchor (X, Y)" }),
3770                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "shoulder_l", children: "Reposition Left Shoulder (IK Base)" }),
3771                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "shoulder_r", children: "Reposition Right Shoulder (IK Base)" }),
3772                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_mouth", children: "Place Mouth Socket Pin" }),
3773                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_shoulder_l", children: "Place Left Shoulder Socket Pin" }),
3774                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_shoulder_r", children: "Place Right Shoulder Socket Pin" }),
3775                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_elbow_l", children: "Place Left Elbow Socket Pin" }),
3776                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_elbow_r", children: "Place Right Elbow Socket Pin" }),
3777                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_hand_l", children: "Place Left Hand Socket Pin" }),
3778                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "socket_hand_r", children: "Place Right Hand Socket Pin" })
3779                    ] }),
3780                    (activeTab === "instruments" || activeTab === "characters" && previewInstKey) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3781                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "head_anchor", children: "Edit Head Anchor (Mouthpiece Pos)" }),
3782                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "plug_mouthpiece", children: "Place Mouthpiece Plug Pin" }),
3783                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "plug_hand_l", children: "Place Left Hand Grip Plug Pin" }),
3784                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "plug_hand_r", children: "Place Right Hand Grip Plug Pin" }),
3785                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "path_l_start", children: "Edit Left Hand (Path Start / Rest)" }),
3786                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "path_l_end", children: "Edit Left Hand (Path End)" }),
3787                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "path_r_start", children: "Edit Right Hand (Path Start / Rest)" }),
3788                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "path_r_end", children: "Edit Right Hand (Path End)" })
3789                    ] }),
3790                    activeTab === "clothing" && activePreviewClothing && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: Object.keys(activePreviewClothing.parts).map((part) => {
3791                      var _a2;
3792                      const glue = (_a2 = activePreviewClothing.gluing) == null ? void 0 : _a2[part];
3793                      if (!glue || glue.type === "none") return null;
3794                      return /* @__PURE__ */ jsxRuntimeExports.jsxs(React.Fragment, { children: [
3795                        /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: `clothing_plug_p1_${part}`, children: [
3796                          "Place ",
3797                          part,
3798                          " Plug P1 Pin"
3799                        ] }),
3800                        glue.type === "two-point" && /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: `clothing_plug_p2_${part}`, children: [
3801                          "Place ",
3802                          part,
3803                          " Plug P2 Pin"
3804                        ] })
3805                      ] }, part);
3806                    }) })
3807                  ]
3808                }
3809              ),
3810              editMode !== "none" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-emerald-400 mt-1", children: "Click anywhere in the preview below to set coordinates." }),
3811              (() => {
3812                var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2;
3813                if (editMode === "none") return null;
3814                let label = "Active Coordinates";
3815                let currentX = 0;
3816                let currentY = 0;
3817                let updateCoords = () => {
3818                };
3819                if (activeTab === "characters" && selectedConfig) {
3820                  if (editMode === "anchor") {
3821                    label = "Anchor Position";
3822                    currentX = selectedConfig.anchorX ?? 0;
3823                    currentY = selectedConfig.anchorY ?? 0;
3824                    updateCoords = (x, y) => handleConfigChange(selectedConfig.id, { anchorX: x, anchorY: y });
3825                  } else if (editMode === "shoulder_l") {
3826                    label = "Left Shoulder (IK Base)";
3827                    currentX = ((_a2 = selectedConfig.ikLeftArm) == null ? void 0 : _a2.originX) ?? -30;
3828                    currentY = ((_b2 = selectedConfig.ikLeftArm) == null ? void 0 : _b2.originY) ?? -20;
3829                    updateCoords = (x, y) => {
3830                      handleIkChange(selectedConfig.id, "ikLeftArm", "originX", x);
3831                      handleIkChange(selectedConfig.id, "ikLeftArm", "originY", y);
3832                    };
3833                  } else if (editMode === "shoulder_r") {
3834                    label = "Right Shoulder (IK Base)";
3835                    currentX = ((_c2 = selectedConfig.ikRightArm) == null ? void 0 : _c2.originX) ?? 30;
3836                    currentY = ((_d2 = selectedConfig.ikRightArm) == null ? void 0 : _d2.originY) ?? -20;
3837                    updateCoords = (x, y) => {
3838                      handleIkChange(selectedConfig.id, "ikRightArm", "originX", x);
3839                      handleIkChange(selectedConfig.id, "ikRightArm", "originY", y);
3840                    };
3841                  } else if (editMode.startsWith("socket_")) {
3842                    const socketName = editMode.replace("socket_", "");
3843                    label = `${socketName.replace("_", " ")} Socket`;
3844                    const svgCoords = parseSvgSocketsAndPlugs(selectedConfig.svgContent);
3845                    const svgVal = svgCoords[`socket_${socketName}`];
3846                    const configVal = (_e2 = selectedConfig.sockets) == null ? void 0 : _e2[socketName];
3847                    const val = configVal || svgVal || { x: 0, y: 0 };
3848                    currentX = val.x;
3849                    currentY = val.y;
3850                    updateCoords = (x, y) => {
3851                      const currentSockets = selectedConfig.sockets || {};
3852                      handleConfigChange(selectedConfig.id, {
3853                        sockets: {
3854                          ...currentSockets,
3855                          [socketName]: { x, y }
3856                        }
3857                      });
3858                    };
3859                  }
3860                } else if ((activeTab === "instruments" || activeTab === "characters" && previewInstKey) && editingInstType && editingInstIndex !== void 0) {
3861                  const typeObj = instrumentConfigs[editingInstType];
3862                  const instObj = (typeObj == null ? void 0 : typeObj[editingInstIndex]) || {};
3863                  if (editMode === "head_anchor") {
3864                    label = "Head Anchor";
3865                    currentX = ((_f2 = instObj.headAnchor) == null ? void 0 : _f2.x) ?? 0;
3866                    currentY = ((_g2 = instObj.headAnchor) == null ? void 0 : _g2.y) ?? 0;
3867                    updateCoords = (x, y) => {
3868                      setInstrumentConfigs((prev) => {
3869                        const tObj = prev[editingInstType];
3870                        const iObj = tObj[editingInstIndex] || {};
3871                        return {
3872                          ...prev,
3873                          [editingInstType]: {
3874                            ...tObj,
3875                            [editingInstIndex]: { ...iObj, headAnchor: { x, y } }
3876                          }
3877                        };
3878                      });
3879                    };
3880                  } else if (editMode.startsWith("plug_")) {
3881                    const plugName = editMode.replace("plug_", "");
3882                    label = `${plugName.replace("_", " ")} Plug`;
3883                    const plugVal = ((_h2 = instObj.plugs) == null ? void 0 : _h2[plugName]) || { x: 0, y: 0 };
3884                    currentX = plugVal.x;
3885                    currentY = plugVal.y;
3886                    updateCoords = (x, y) => {
3887                      setInstrumentConfigs((prev) => {
3888                        const tObj = prev[editingInstType];
3889                        const iObj = tObj[editingInstIndex] || {};
3890                        const currentPlugs = iObj.plugs || {};
3891                        return {
3892                          ...prev,
3893                          [editingInstType]: {
3894                            ...tObj,
3895                            [editingInstIndex]: {
3896                              ...iObj,
3897                              plugs: {
3898                                ...currentPlugs,
3899                                [plugName]: { ...currentPlugs[plugName] || {}, x, y }
3900                              }
3901                            }
3902                          }
3903                        };
3904                      });
3905                    };
3906                  } else if (editMode.startsWith("path_")) {
3907                    const isLeft = editMode.includes("_l_");
3908                    const isStart = editMode.endsWith("_start");
3909                    const handKey = isLeft ? "leftHandMotion" : "rightHandMotion";
3910                    const pointKey = isStart ? "start" : "end";
3911                    label = `${isLeft ? "Left" : "Right"} Hand Path ${isStart ? "Start" : "End"}`;
3912                    const motionObj = instObj[handKey] || { logic: "none", start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
3913                    currentX = ((_i2 = motionObj[pointKey]) == null ? void 0 : _i2.x) ?? 0;
3914                    currentY = ((_j2 = motionObj[pointKey]) == null ? void 0 : _j2.y) ?? 0;
3915                    updateCoords = (x, y) => {
3916                      setInstrumentConfigs((prev) => {
3917                        const tObj = prev[editingInstType];
3918                        const iObj = tObj[editingInstIndex] || {};
3919                        const mObj = iObj[handKey] || { logic: "none", start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
3920                        const updatedMotion = {
3921                          ...mObj,
3922                          [pointKey]: { x, y }
3923                        };
3924                        let newRestPose = iObj.restPose || {};
3925                        if (isStart) {
3926                          newRestPose = {
3927                            ...newRestPose,
3928                            [isLeft ? "leftHand" : "rightHand"]: { x, y }
3929                          };
3930                        }
3931                        return {
3932                          ...prev,
3933                          [editingInstType]: {
3934                            ...tObj,
3935                            [editingInstIndex]: {
3936                              ...iObj,
3937                              [handKey]: updatedMotion,
3938                              restPose: newRestPose
3939                            }
3940                          }
3941                        };
3942                      });
3943                    };
3944                  }
3945                } else if (activeTab === "clothing" && selectedClothingDef) {
3946                  if (editMode.startsWith("clothing_plug_")) {
3947                    const parts = editMode.split("_");
3948                    const pointKey = parts[2];
3949                    const partName = parts.slice(3).join("_");
3950                    label = `${partName.replace("_", " ")} Plug (${pointKey.toUpperCase()})`;
3951                    const currentPlugs = selectedClothingDef.plugs || {};
3952                    const partPlugs = currentPlugs[partName] || {};
3953                    const val = partPlugs[pointKey] || { x: 0, y: 0 };
3954                    currentX = val.x;
3955                    currentY = val.y;
3956                    updateCoords = (x, y) => {
3957                      setClothingConfigs((prev) => ({
3958                        ...prev,
3959                        [selectedClothingDef.id]: {
3960                          ...selectedClothingDef,
3961                          plugs: {
3962                            ...currentPlugs,
3963                            [partName]: {
3964                              ...partPlugs,
3965                              [pointKey]: { x, y }
3966                            }
3967                          }
3968                        }
3969                      }));
3970                    };
3971                  }
3972                }
3973                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 bg-emerald-950/20 border border-emerald-500/30 rounded p-2 text-xs space-y-1.5 animate-fadeIn", children: [
3974                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold text-emerald-400 flex items-center justify-between", children: [
3975                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
3976                      label,
3977                      " Coordinates"
3978                    ] }),
3979                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500 font-mono", children: "Precision Adjust" })
3980                  ] }),
3981                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
3982                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3983                      /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[9px] text-zinc-500 uppercase font-semibold", children: "X Position" }),
3984                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
3985                        /* @__PURE__ */ jsxRuntimeExports.jsx(
3986                          "button",
3987                          {
3988                            type: "button",
3989                            onClick: () => updateCoords(currentX - 1, currentY),
3990                            className: "px-1.5 py-0.5 bg-zinc-800 border border-zinc-700 hover:bg-zinc-700 rounded text-zinc-300 text-[10px] font-bold",
3991                            children: "-"
3992                          }
3993                        ),
3994                        /* @__PURE__ */ jsxRuntimeExports.jsx(
3995                          "input",
3996                          {
3997                            type: "number",
3998                            value: currentX,
3999                            onChange: (e) => updateCoords(parseFloat(e.target.value) || 0, currentY),
4000                            className: "w-full bg-zinc-900 border border-zinc-700 rounded px-1 py-0.5 text-white font-mono text-center text-xs"
4001                          }
4002                        ),
4003                        /* @__PURE__ */ jsxRuntimeExports.jsx(
4004                          "button",
4005                          {
4006                            type: "button",
4007                            onClick: () => updateCoords(currentX + 1, currentY),
4008                            className: "px-1.5 py-0.5 bg-zinc-800 border border-zinc-700 hover:bg-zinc-700 rounded text-zinc-300 text-[10px] font-bold",
4009                            children: "+"
4010                          }
4011                        )
4012                      ] })
4013                    ] }),
4014                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4015                      /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[9px] text-zinc-500 uppercase font-semibold", children: "Y Position" }),
4016                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
4017                        /* @__PURE__ */ jsxRuntimeExports.jsx(
4018                          "button",
4019                          {
4020                            type: "button",
4021                            onClick: () => updateCoords(currentX, currentY - 1),
4022                            className: "px-1.5 py-0.5 bg-zinc-800 border border-zinc-700 hover:bg-zinc-700 rounded text-zinc-300 text-[10px] font-bold",
4023                            children: "-"
4024                          }
4025                        ),
4026                        /* @__PURE__ */ jsxRuntimeExports.jsx(
4027                          "input",
4028                          {
4029                            type: "number",
4030                            value: currentY,
4031                            onChange: (e) => updateCoords(currentX, parseFloat(e.target.value) || 0),
4032                            className: "w-full bg-zinc-900 border border-zinc-700 rounded px-1 py-0.5 text-white font-mono text-center text-xs"
4033                          }
4034                        ),
4035                        /* @__PURE__ */ jsxRuntimeExports.jsx(
4036                          "button",
4037                          {
4038                            type: "button",
4039                            onClick: () => updateCoords(currentX, currentY + 1),
4040                            className: "px-1.5 py-0.5 bg-zinc-800 border border-zinc-700 hover:bg-zinc-700 rounded text-zinc-300 text-[10px] font-bold",
4041                            children: "+"
4042                          }
4043                        )
4044                      ] })
4045                    ] })
4046                  ] })
4047                ] });
4048              })()
4049            ] })
4050          ] })
4051        ] }),
4052        activeTab === "characters" && selectedConfig && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-4xl space-y-8", children: [
4053          (() => {
4054            const svgCoords = parseSvgSocketsAndPlugs(selectedConfig.svgContent);
4055            const expected = ["mouth", "shoulder_l", "shoulder_r", "elbow_l", "elbow_r", "hand_l", "hand_r"];
4056            const missing = expected.filter((name) => {
4057              var _a2;
4058              const hasInSvg = svgCoords[`socket_${name}`] !== void 0;
4059              const hasInConfig = ((_a2 = selectedConfig.sockets) == null ? void 0 : _a2[name]) !== void 0;
4060              return !hasInSvg && !hasInConfig;
4061            });
4062            if (missing.length === 0) return null;
4063            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-amber-950/40 border border-amber-800 text-amber-200 p-3 rounded-lg flex flex-col gap-1 text-xs", children: [
4064              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold flex items-center gap-1.5 text-amber-400", children: [
4065                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: "⚠️" }),
4066                " Missing Character Sockets"
4067              ] }),
4068              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400 font-normal", children: "The following sockets are missing from both the SVG file and database overrides. Click the 🎯 Pin button next to a socket below to calibrate it on the canvas." }),
4069              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1.5 mt-1.5", children: missing.map((w) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 bg-amber-900/40 border border-amber-700/50 rounded text-amber-300 font-mono font-semibold", children: [
4070                "socket_",
4071                w
4072              ] }, w)) })
4073            ] });
4074          })(),
4075          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 gap-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
4076            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4077              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: "Identifier (Key)" }),
4078              /* @__PURE__ */ jsxRuntimeExports.jsx(
4079                "input",
4080                {
4081                  type: "text",
4082                  value: selectedConfig.id,
4083                  onChange: (e) => {
4084                    const newId = e.target.value;
4085                    const newConfigs = { ...configs };
4086                    newConfigs[newId] = { ...selectedConfig, id: newId };
4087                    delete newConfigs[selectedId];
4088                    setConfigs(newConfigs);
4089                    setSelectedId(newId);
4090                  },
4091                  className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white font-mono text-sm"
4092                }
4093              )
4094            ] }),
4095            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4096              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: "Display Name" }),
4097              /* @__PURE__ */ jsxRuntimeExports.jsx(
4098                "input",
4099                {
4100                  type: "text",
4101                  value: selectedConfig.name,
4102                  onChange: (e) => handleConfigChange(selectedConfig.id, { name: e.target.value }),
4103                  className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white"
4104                }
4105              )
4106            ] }),
4107            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4108              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: "Animation Family" }),
4109              /* @__PURE__ */ jsxRuntimeExports.jsxs(
4110                "select",
4111                {
4112                  value: selectedConfig.family,
4113                  onChange: (e) => handleConfigChange(selectedConfig.id, { family: e.target.value }),
4114                  className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white",
4115                  children: [
4116                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "percussion", children: "Percussion" }),
4117                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "keys", children: "Keys" }),
4118                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "strings", children: "Strings" }),
4119                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "winds", children: "Winds" }),
4120                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "other", children: "Other / Generic" })
4121                  ]
4122                }
4123              )
4124            ] }),
4125            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
4126              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4127                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: [
4128                  "Scale factor ",
4129                  isInherited("scale") && /* @__P
4129URE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-indigo-400 lowercase italic normal-case ml-1", children: "(gorilla default)" })
4130                ] }),
4131                /* @__PURE__ */ jsxRuntimeExports.jsx(
4132                  "input",
4133                  {
4134                    type: "number",
4135                    step: "0.1",
4136                    value: selectedConfig.scale,
4137                    onChange: (e) => handleConfigChange(selectedConfig.id, { scale: parseFloat(e.target.value) || 1 }),
4138                    className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white"
4139                  }
4140                )
4141              ] }),
4142              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
4143                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4144                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: [
4145                    "Anchor X ",
4146                    isInherited("anchorX") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-indigo-400 lowercase italic normal-case ml-1", children: "(gorilla default)" })
4147                  ] }),
4148                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4149                    "input",
4150                    {
4151                      type: "number",
4152                      value: selectedConfig.anchorX,
4153                      onChange: (e) => handleConfigChange(selectedConfig.id, { anchorX: parseInt(e.target.value) || 0 }),
4154                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white"
4155                    }
4156                  )
4157                ] }),
4158                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4159                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: [
4160                    "Anchor Y ",
4161                    isInherited("anchorY") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-indigo-400 lowercase italic normal-case ml-1", children: "(gorilla default)" })
4162                  ] }),
4163                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4164                    "input",
4165                    {
4166                      type: "number",
4167                      value: selectedConfig.anchorY,
4168                      onChange: (e) => handleConfigChange(selectedConfig.id, { anchorY: parseInt(e.target.value) || 0 }),
4169                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white"
4170                    }
4171                  )
4172                ] })
4173              ] }),
4174              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2 mt-4", children: [
4175                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4176                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: [
4177                    "Instrument Scale ",
4178                    isInherited("instrumentScale") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-indigo-400 lowercase italic normal-case ml-1", children: "(gorilla default)" })
4179                  ] }),
4180                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4181                    "input",
4182                    {
4183                      type: "number",
4184                      step: "0.05",
4185                      value: selectedConfig.instrumentScale ?? 1,
4186                      onChange: (e) => handleConfigChange(selectedConfig.id, { instrumentScale: parseFloat(e.target.value) || 1 }),
4187                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white"
4188                    }
4189                  )
4190                ] }),
4191                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4192                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: [
4193                    "Instrument Rotation ",
4194                    isInherited("instrumentRotation") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-indigo-400 lowercase italic normal-case ml-1", children: "(gorilla default)" })
4195                  ] }),
4196                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4197                    "input",
4198                    {
4199                      type: "number",
4200                      value: selectedConfig.instrumentRotation ?? 0,
4201                      onChange: (e) => handleConfigChange(selectedConfig.id, { instrumentRotation: parseInt(e.target.value) || 0 }),
4202                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-2 text-white"
4203                    }
4204                  )
4205                ] })
4206              ] })
4207            ] }),
4208            "                  "
4209          ] }) }),
4210          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-indigo-900/50 rounded-lg p-4 bg-indigo-900/10", children: [
4211            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "flex items-center gap-2 text-sm font-bold text-indigo-400 uppercase tracking-wider mb-4", children: "2-Bone Inverse Kinematics Overrides" }),
4212            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-8", children: [
4213              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
4214                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-400 border-b border-zinc-800 pb-1", children: "Left Arm" }),
4215                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
4216                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4217                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-[10px] uppercase text-zinc-500", children: [
4218                      "Upper Length ",
4219                      isInherited("ikLeftArm", "upperArmLength") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-indigo-400 lowercase italic block", children: "(gorilla default)" })
4220                    ] }),
4221                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: ((_q = selectedConfig.ikLeftArm) == null ? void 0 : _q.upperArmLength) || 40, onChange: (e) => handleIkChange(selectedConfig.id, "ikLeftArm", "upperArmLength", parseInt(e.target.value)), className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-sm" })
4222                  ] }),
4223                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4224                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-[10px] uppercase text-zinc-500", children: [
4225                      "Lower Length ",
4226                      isInherited("ikLeftArm", "lowerArmLength") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-indigo-400 lowercase italic block", children: "(gorilla default)" })
4227                    ] }),
4228                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: ((_r = selectedConfig.ikLeftArm) == null ? void 0 : _r.lowerArmLength) || 40, onChange: (e) => handleIkChange(selectedConfig.id, "ikLeftArm", "lowerArmLength", parseInt(e.target.value)), className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-sm" })
4229                  ] }),
4230                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 mt-2", children: [
4231                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-[10px] uppercase text-zinc-500 mb-1", children: [
4232                      "Bend Direction ",
4233                      isInherited("ikLeftArm", "bendDirection") && /* @__P
4233URE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-indigo-400 lowercase italic ml-1", children: "(gorilla default)" })
4234                    ] }),
4235                    /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: ((_s = selectedConfig.ikLeftArm) == null ? void 0 : _s.bendDirection) || 1, onChange: (e) => handleIkChange(selectedConfig.id, "ikLeftArm", "bendDirection", parseInt(e.target.value)), className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-sm", children: [
4236                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 1, children: "Natural (1)" }),
4237                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: -1, children: "Inverted (-1)" })
4238                    ] })
4239                  ] })
4240                ] })
4241              ] }),
4242              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
4243                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-400 border-b border-zinc-800 pb-1", children: "Right Arm" }),
4244                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
4245                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4246                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-[10px] uppercase text-zinc-500", children: [
4247                      "Upper Length ",
4248                      isInherited("ikRightArm", "upperArmLength") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-indigo-400 lowercase italic block", children: "(gorilla default)" })
4249                    ] }),
4250                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: ((_t = selectedConfig.ikRightArm) == null ? void 0 : _t.upperArmLength) || 40, onChange: (e) => handleIkChange(selectedConfig.id, "ikRightArm", "upperArmLength", parseInt(e.target.value)), className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-sm" })
4251                  ] }),
4252                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4253                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-[10px] uppercase text-zinc-500", children: [
4254                      "Lower Length ",
4255                      isInherited("ikRightArm", "lowerArmLength") && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-indigo-400 lowercase italic block", children: "(gorilla default)" })
4256                    ] }),
4257                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: ((_u = selectedConfig.ikRightArm) == null ? void 0 : _u.lowerArmLength) || 40, onChange: (e) => handleIkChange(selectedConfig.id, "ikRightArm", "lowerArmLength", parseInt(e.target.value)), className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-sm" })
4258                  ] }),
4259                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 mt-2", children: [
4260                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-[10px] uppercase text-zinc-500 mb-1", children: [
4261                      "Bend Direction ",
4262                      isInherited("ikRightArm", "bendDirection") && /* @__P
4262URE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-indigo-400 lowercase italic ml-1", children: "(gorilla default)" })
4263                    ] }),
4264                    /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: ((_v = selectedConfig.ikRightArm) == null ? void 0 : _v.bendDirection) || -1, onChange: (e) => handleIkChange(selectedConfig.id, "ikRightArm", "bendDirection", parseInt(e.target.value)), className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-sm", children: [
4265                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 1, children: "Natural (1)" }),
4266                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: -1, children: "Inverted (-1)" })
4267                    ] })
4268                  ] })
4269                ] })
4270              ] })
4271            ] })
4272          ] }),
4273          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
4274            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-xs font-bold text-indigo-400 uppercase tracking-wider mb-2", children: [
4275              /* @__PURE__ */ jsxRuntimeExports.jsx(PenLine, { size: 16 }),
4276              " Character Sockets / Reference Joints"
4277            ] }),
4278            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 mb-3", children: "Define skeletal socket positions for attachment alignment. Click 🎯 next to a socket to click-position it on the preview canvas." }),
4279            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 max-h-60 overflow-y-auto custom-scrollbar pr-1", children: ["mouth", "shoulder_l", "shoulder_r", "elbow_l", "elbow_r", "hand_l", "hand_r"].map((socketName) => {
4280              var _a2, _b2, _c2;
4281              const svgCoords = parseSvgSocketsAndPlugs(selectedConfig.svgContent);
4282              const svgVal = svgCoords[`socket_${socketName}`];
4283              const configVal = (_a2 = selectedConfig.sockets) == null ? void 0 : _a2[socketName];
4284              const isSvgOnly = svgVal && !configVal;
4285              const displayX = (configVal == null ? void 0 : configVal.x) ?? (svgVal == null ? void 0 : svgVal.x) ?? "";
4286              const displayY = (configVal == null ? void 0 : configVal.y) ?? (svgVal == null ? void 0 : svgVal.y) ?? "";
4287              const rawSocketVal = (_c2 = (_b2 = configs[selectedConfig.id]) == null ? void 0 : _b2.sockets) == null ? void 0 : _c2[socketName];
4288              const isGorillaDefault = selectedConfig.id !== "percussion" && !rawSocketVal && configVal;
4289              const isEditingThis = editMode === `socket_${socketName}`;
4290              return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `bg-black/40 border rounded p-2 grid grid-cols-12 gap-2 items-center ${isEditingThis ? "border-emerald-500 bg-emerald-950/10" : "border-zinc-800"}`, children: [
4291                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-3 text-xs font-bold text-zinc-400 truncate flex items-center gap-1", children: [
4292                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: socketName }),
4293                  isSvgOnly && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] bg-zinc-800 text-zinc-400 px-1 rounded", children: "SVG" }),
4294                  isGorillaDefault && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] bg-indigo-950/80 text-indigo-300 border border-indigo-700/50 px-1 rounded", title: "Inherited from Gorilla default", children: "Gorilla Default" }),
4295                  !svgVal && !configVal && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] bg-red-900/40 text-red-400 px-1 rounded", children: "Missing" })
4296                ] }),
4297                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-3", children: [
4298                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Parent Joint" }),
4299                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
4300                    "select",
4301                    {
4302                      disabled: true,
4303                      value: socketName === "mouth" || socketName === "head" ? "head" : "body",
4304                      className: "w-full bg-zinc-950 border border-zinc-800 rounded p-1 text-zinc-400 text-[10px] cursor-not-allowed opacity-80",
4305                      children: [
4306                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "head", children: "head" }),
4307                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "body", children: "body" })
4308                      ]
4309                    }
4310                  )
4311                ] }),
4312                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [
4313                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "X Coord" }),
4314                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4315                    "input",
4316                    {
4317                      type: "number",
4318                      value: displayX,
4319                      placeholder: svgVal ? `SVG: ${svgVal.x}` : "None",
4320                      onChange: (e) => {
4321                        const val = parseFloat(e.target.value);
4322                        const currentSockets = selectedConfig.sockets || {};
4323                        handleConfigChange(selectedConfig.id, {
4324                          sockets: {
4325                            ...currentSockets,
4326                            [socketName]: { x: isNaN(val) ? 0 : val, y: (configVal == null ? void 0 : configVal.y) ?? (svgVal == null ? void 0 : svgVal.y) ?? 0 }
4327                          }
4328                        });
4329                      },
4330                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-[10px]"
4331                    }
4332                  )
4333                ] }),
4334                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [
4335                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Y Coord" }),
4336                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4337                    "input",
4338                    {
4339                      type: "number",
4340                      value: displayY,
4341                      placeholder: svgVal ? `SVG: ${svgVal.y}` : "None",
4342                      onChange: (e) => {
4343                        const val = parseFloat(e.target.value);
4344                        const currentSockets = selectedConfig.sockets || {};
4345                        handleConfigChange(selectedConfig.id, {
4346                          sockets: {
4347                            ...currentSockets,
4348                            [socketName]: { x: (configVal == null ? void 0 : configVal.x) ?? (svgVal == null ? void 0 : svgVal.x) ?? 0, y: isNaN(val) ? 0 : val }
4349                          }
4350                        });
4351                      },
4352                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-[10px]"
4353                    }
4354                  )
4355                ] }),
4356                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "col-span-2 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4357                  "button",
4358                  {
4359                    type: "button",
4360                    onClick: () => setEditMode(isEditingThis ? "none" : `socket_${socketName}`),
4361                    className: `p-1.5 rounded border transition-colors ${isEditingThis ? "bg-emerald-600 border-emerald-500 text-white" : "bg-zinc-800 border-zinc-700 text-zinc-400 hover:bg-zinc-750 hover:text-white"}`,
4362                    title: "Pin on Canvas",
4363                    children: "🎯"
4364                  }
4365                ) })
4366              ] }, socketName);
4367            }) })
4368          ] }),
4369          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
4370            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-xs font-bold text-indigo-400 uppercase tracking-wider mb-2", children: [
4371              /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 16 }),
4372              " Character Body Parts (SVGs & Transforms)"
4373            ] }),
4374            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 mb-3", children: "Customize individual body part SVGs and adjust translations, scales, and rotation for character parts." }),
4375            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4 max-h-[500px] overflow-y-auto custom-scrollbar pr-1 mb-4", children: ["head", "body", "upper_arm_l", "lower_arm_l", "hand_l", "upper_arm_r", "lower_arm_r", "hand_r", "leg_l", "foot_l", "leg_r", "foot_r"].map((part) => {
4376              var _a2;
4377              const isExpanded = !!expandedCharacterParts[part];
4378              const isEmpty = !selectedConfig || !selectedConfig.parts || !selectedConfig.parts[part];
4379              const isSelected = selectedPartId === part;
4380              const t = ((_a2 = selectedConfig.transforms) == null ? void 0 : _a2[part]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
4381              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
4382                "div",
4383                {
4384                  onClick: () => setSelectedPartId(part),
4385                  className: `transition-all duration-200 border rounded p-3 flex flex-col gap-2 cursor-pointer ${isSelected ? "bg-indigo-950/20 border-indigo-500 ring-1 ring-indigo-500/50 shadow-[0_0_8px_rgba(99,102,241,0.2)]" : "bg-black border border-zinc-800 hover:border-zinc-700"}`,
4386                  children: [
4387                    /* @__PURE__ */ jsxRuntimeExports.jsxs(
4388                      "div",
4389                      {
4390                        className: "flex items-center justify-between cursor-pointer select-none",
4391                        onClick: (e) => {
4392                          setSelectedPartId(part);
4393                          setExpandedCharacterParts((prev) => ({ ...prev, [part]: !prev[part] }));
4394                        },
4395                        children: [
4396                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4397                            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 text-[10px] w-3 inline-block", children: isExpanded ? "▼" : "▶" }),
4398                            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: `block text-xs uppercase tracking-wider cursor-pointer ${isEmpty ? "text-zinc-500 opacity-60" : "font-bold text-indigo-400"}`, children: part })
4399                          ] }),
4400                          /* @__PURE__ */ jsxRuntimeExports.jsxs(
4401                            "label",
4402                            {
4403                              onClick: (e) => e.stopPropagation(),
4404                              className: "cursor-pointer flex items-center gap-1 text-[10px] px-2 py-0.5 bg-zinc-850 hover:bg-zinc-800 border border-zinc-700 text-zinc-300 rounded transition-colors",
4405                              children: [
4406                                /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 10 }),
4407                                " Upload SVG",
4408                                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", accept: ".svg", className: "hidden", onChange: (e) => {
4409                                  var _a3;
4410                                  pushUndo();
4411                                  const file = (_a3 = e.target.files) == null ? void 0 : _a3[0];
4412                                  if (!file) return;
4413                                  const reader = new FileReader();
4414                                  reader.onload = (event) => {
4415                                    var _a4;
4416                                    try {
4417                                      const content = (_a4 = event.target) == null ? void 0 : _a4.result;
4418                                      if (!content.includes("<svg") || !content.includes("</svg>")) {
4419                                        alert("Invalid SVG file format");
4420                                        return;
4421                                      }
4422                                      const match = content.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i);
4423                                      const svgInner = match ? match[1] : content;
4424                                      const currentParts = selectedConfig.parts || {};
4425                                      handleConfigChange(selectedConfig.id, {
4426                                        parts: {
4427                                          ...currentParts,
4428                                          [part]: svgInner
4429                                        }
4430                                      });
4431                                    } catch (err) {
4432                                      alert("Failed to parse SVG file");
4433                                    }
4434                                  };
4435                                  reader.readAsText(file);
4436                                } })
4437                              ]
4438                            }
4439                          )
4440                        ]
4441                      }
4442                    ),
4443                    isExpanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick: (e) => e.stopPropagation(), className: "bg-zinc-900 border border-zinc-800 p-2.5 rounded flex flex-col gap-2 animate-fadeIn cursor-default mt-1", children: [
4444                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-5 gap-2", children: [
4445                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4446                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Scale X" }),
4447                          /* @__PURE__ */ jsxRuntimeExports.jsx(
4448                            "input",
4449                            {
4450                              type: "number",
4451                              step: "0.05",
4452                              value: t.scaleX ?? 1,
4453                              onChange: (e) => {
4454                                pushUndo();
4455                                const val = parseFloat(e.target.value);
4456                                handleConfigChange(selectedConfig.id, {
4457                                  transforms: {
4458                                    ...selectedConfig.transforms,
4459                                    [part]: { ...t, scaleX: isNaN(val) ? 1 : val }
4460                                  }
4461                                });
4462                              },
4463                              className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
4464                            }
4465                          )
4466                        ] }),
4467                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4468                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Scale Y" }),
4469                          /* @__PURE__ */ jsxRuntimeExports.jsx(
4470                            "input",
4471                            {
4472                              type: "number",
4473                              step: "0.05",
4474                              value: t.scaleY ?? 1,
4475                              onChange: (e) => {
4476                                pushUndo();
4477                                const val = parseFloat(e.target.value);
4478                                handleConfigChange(selectedConfig.id, {
4479                                  transforms: {
4480                                    ...selectedConfig.transforms,
4481                                    [part]: { ...t, scaleY: isNaN(val) ? 1 : val }
4482                                  }
4483                                });
4484                              },
4485                              className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
4486                            }
4487                          )
4488                        ] }),
4489                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4490                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Offset X" }),
4491                          /* @__PURE__ */ jsxRuntimeExports.jsx(
4492                            "input",
4493                            {
4494                              type: "number",
4495                              value: t.x ?? 0,
4496                              onChange: (e) => {
4497                                pushUndo();
4498                                const val = parseFloat(e.target.value) || 0;
4499                                handleConfigChange(selectedConfig.id, {
4500                                  transforms: {
4501                                    ...selectedConfig.transforms,
4502                                    [part]: { ...t, x: val }
4503                                  }
4504                                });
4505                              },
4506                              className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
4507                            }
4508                          )
4509                        ] }),
4510                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4511                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Offset Y" }),
4512                          /* @__PURE__ */ jsxRuntimeExports.jsx(
4513                            "input",
4514                            {
4515                              type: "number",
4516                              value: t.y ?? 0,
4517                              onChange: (e) => {
4518                                pushUndo();
4519                                const val = parseFloat(e.target.value) || 0;
4520                                handleConfigChange(selectedConfig.id, {
4521                                  transforms: {
4522                                    ...selectedConfig.transforms,
4523                                    [part]: { ...t, y: val }
4524                                  }
4525                                });
4526                              },
4527                              className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
4528                            }
4529                          )
4530                        ] }),
4531                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4532                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Rot (deg)" }),
4533                          /* @__PURE__ */ jsxRuntimeExports.jsx(
4534                            "input",
4535                            {
4536                              type: "number",
4537                              value: t.rotation ?? 0,
4538                              onChange: (e) => {
4539                                pushUndo();
4540                                const val = parseFloat(e.target.value) || 0;
4541                                handleConfigChange(selectedConfig.id, {
4542                                  transforms: {
4543                                    ...selectedConfig.transforms,
4544                                    [part]: { ...t, rotation: val }
4545                                  }
4546                                });
4547                              },
4548                              className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
4549                            }
4550                          )
4551                        ] })
4552                      ] }),
4553                      !isEmpty && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mt-2 border-t border-zinc-800 pt-2", children: [
4554                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-400", children: "✓ Custom SVG loaded" }),
4555                        /* @__PURE__ */ jsxRuntimeExports.jsx(
4556                          "button",
4557                          {
4558                            onClick: (e) => {
4559                              e.stopPropagation();
4560                              pushUndo();
4561                              const currentParts = { ...selectedConfig.parts || {} };
4562                              delete currentParts[part];
4563                              handleConfigChange(selectedConfig.id, { parts: currentParts });
4564                            },
4565                            className: "text-red-400 hover:text-red-300 text-[10px]",
4566                            children: "Remove SVG"
4567                          }
4568                        )
4569                      ] })
4570                    ] })
4571                  ]
4572                },
4573                part
4574              );
4575            }) })
4576          ] }),
4577          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
4578            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-xs font-bold text-indigo-400 uppercase tracking-wider mb-2", children: [
4579              /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 16 }),
4580              " Layer Rendering Order (Z)"
4581            ] }),
4582            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 mb-3", children: "Override the default rendering depth (zIndex) for character body parts and clothing layers." }),
4583            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 max-h-60 overflow-y-auto custom-scrollbar pr-1", children: Object.entries({
4584              leg_l: 1,
4585              clothing_leg_l: 1.5,
4586              leg_r: 2,
4587              clothing_leg_r: 2.5,
4588              foot_l: 3,
4589              foot_r: 4,
4590              body: 5,
4591              clothing_body: 5.5,
4592              head: 6,
4593              clothing_head: 6.5,
4594              upper_arm_r: 7,
4595              clothing_upper_arm_r: 7.2,
4596              lower_arm_r: 8,
4597              clothing_lower_arm_r: 8.2,
4598              hand_r: 9,
4599              clothing_hand_r: 9.2,
4600              instrument: 10,
4601              upper_arm_l: 11,
4602              clothing_upper_arm_l: 11.2,
4603              lower_arm_l: 12,
4604              clothing_lower_arm_l: 12.2,
4605              hand_l: 13,
4606              clothing_hand_l: 13.2
4607            }).map(([part, defaultZ]) => {
4608              var _a2, _b2;
4609              const currentZ = ((_a2 = selectedConfig.baseZOrder) == null ? void 0 : _a2[part]) ?? defaultZ;
4610              const isOverridden = ((_b2 = selectedConfig.baseZOrder) == null ? void 0 : _b2[part]) !== void 0;
4611              return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-black/40 border border-zinc-800 rounded p-2 flex items-center justify-between gap-4", children: [
4612                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs font-bold text-zinc-400 truncate flex items-center gap-1.5", children: [
4613                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: part }),
4614                  !isOverridden && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] bg-zinc-800/60 text-zinc-500 px-1 rounded uppercase font-semibold", children: "default" })
4615                ] }),
4616                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4617                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4618                    "input",
4619                    {
4620                      type: "number",
4621                      step: "0.1",
4622                      value: currentZ,
4623                      onChange: (e) => {
4624                        const val = parseFloat(e.target.value);
4625                        const baseZOrder = selectedConfig.baseZOrder || {};
4626                        handleConfigChange(selectedConfig.id, {
4627                          baseZOrder: {
4628                            ...baseZOrder,
4629                            [part]: isNaN(val) ? defaultZ : val
4630                          }
4631                        });
4632                      },
4633                      className: "w-16 bg-zinc-900 border border-zinc-700 rounded p-1 text-white text-[10px] text-right font-mono"
4634                    }
4635                  ),
4636                  isOverridden && /* @__PURE__ */ jsxRuntimeExports.jsx(
4637                    "button",
4638                    {
4639                      onClick: () => {
4640                        const baseZOrder = { ...selectedConfig.baseZOrder || {} };
4641                        delete baseZOrder[part];
4642                        handleConfigChange(selectedConfig.id, {
4643                          baseZOrder: Object.keys(baseZOrder).length > 0 ? baseZOrder : void 0
4644                        });
4645                      },
4646                      title: "Reset override",
4647                      className: "text-zinc-650 hover:text-zinc-400 text-[10px] font-bold",
4648                      children: "↺"
4649                    }
4650                  )
4651                ] })
4652              ] }, part);
4653            }) })
4654          ] }),
4655          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
4656            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
4657              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-xs font-bold text-zinc-500 uppercase tracking-wider", children: [
4658                /* @__PURE__ */ jsxRuntimeExports.jsx(Image$1, { size: 16 }),
4659                " SVG Source Code"
4660              ] }),
4661              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "cursor-pointer flex items-center gap-1 text-xs px-3 py-1 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded transition-colors", children: [
4662                /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 14 }),
4663                " Upload SVG",
4664                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", accept: ".svg", className: "hidden", onChange: (e) => handleSvgUpload(e, selectedConfig.id) })
4665              ] }) })
4666            ] }),
4667            uploadError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-500 text-xs mb-2", children: uploadError }),
4668            /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500 mb-2", children: [
4669              "Must contain GSAP targets: ",
4670              /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-indigo-400", children: 'id="head"' }),
4671              ", ",
4672              /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-indigo-400", children: 'id="body"' }),
4673              ", ",
4674              /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-indigo-400", children: 'id="hand_l"' }),
4675              ", ",
4676              /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-indigo-400", children: 'id="hand_r"' }),
4677              "."
4678            ] }),
4679            /* @__PURE__ */ jsxRuntimeExports.jsx(
4680              "textarea",
4681              {
4682                value: selectedConfig.svgContent,
4683                onChange: (e) => handleConfigChange(selectedConfig.id, { svgContent: e.target.value }),
4684                className: "w-full h-48 bg-black border border-zinc-700 rounded p-3 text-emerald-400 font-mono text-sm resize-y"
4685              }
4686            )
4687          ] }),
4688          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
4689            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "flex items-center gap-2 text-xs font-bold text-zinc-500 uppercase tracking-wider mb-3", children: "IK Note Mapping (JSON)" }),
4690            /* @__PURE__ */ jsxRuntimeExports.jsx(
4691              "textarea",
4692              {
4693                defaultValue: JSON.stringify(selectedConfig.noteMap, null, 2),
4694                onChange: (e) => handleJsonUpdate(selectedConfig.id, e.target.value),
4695                className: `w-full h-48 bg-black border ${jsonError ? "border-red-500" : "border-zinc-700"} rounded p-3 text-amber-400 font-mono text-sm resize-y`
4696              }
4697            ),
4698            jsonError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-500 text-xs mt-2", children: jsonError })
4699          ] })
4700        ] }),
4701        activeTab === "instruments" && selectedInstKey && (() => {
4702          var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2;
4703          const isAccessory = selectedPartId === "accessory";
4704          const activeSvgContent = isAccessory ? typeof selectedInstSvg === "object" ? selectedInstSvg == null ? void 0 : selectedInstSvg.accessorySvg : "" : typeof selectedInstSvg === "string" ? selectedInstSvg : selectedInstSvg == null ? void 0 : selectedInstSvg.svgContent;
4705          const activeTransform = isAccessory ? typeof selectedInstSvg === "object" ? selectedInstSvg == null ? void 0 : selectedInstSvg.accessoryTransform : void 0 : typeof selectedInstSvg === "object" ? selectedInstSvg == null ? void 0 : selectedInstSvg.transform : void 0;
4706          const svgCoords = parseSvgSocketsAndPlugs(typeof selectedInstSvg === "string" ? selectedInstSvg : (selectedInstSvg == null ? void 0 : selectedInstSvg.svgContent) || "");
4707          return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-4xl space-y-8", children: [
4708            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
4709              /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white border-b border-zinc-800 pb-2", children: "Instrument Parts" }),
4710              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4711                /* @__PURE__ */ jsxRuntimeExports.jsxs(
4712                  "div",
4713                  {
4714                    onClick: () => setSelectedPartId("instrument"),
4715                    className: `transition-all duration-200 border rounded p-3 flex flex-col gap-1 cursor-pointer ${selectedPartId === "instrument" || selectedPartId !== "accessory" ? "bg-indigo-950/20 border-indigo-500 ring-1 ring-indigo-500/50 shadow-[0_0_8px_rgba(99,102,241,0.2)]" : "bg-black border border-zinc-800 hover:border-zinc-700"}`,
4716                    children: [
4717                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs uppercase tracking-wider font-bold text-indigo-400", children: "Main Instrument" }),
4718                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500", children: "Root / Body Mounted" })
4719                    ]
4720                  }
4721                ),
4722                /* @__PURE__ */ jsxRuntimeExports.jsxs(
4723                  "div",
4724                  {
4725                    onClick: () => setSelectedPartId("accessory"),
4726                    className: `transition-all duration-200 border rounded p-3 flex flex-col gap-1 cursor-pointer ${selectedPartId === "accessory" ? "bg-indigo-950/20 border-indigo-500 ring-1 ring-indigo-500/50 shadow-[0_0_8px_rgba(99,102,241,0.2)]" : "bg-black border border-zinc-800 hover:border-zinc-700"}`,
4727                    children: [
4728                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs uppercase tracking-wider font-bold text-indigo-400", children: "Accessory" }),
4729                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500", children: "e.g. Bow, Drumstick" })
4730                    ]
4731                  }
4732                )
4733              ] })
4734            ] }),
4735            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
4736              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
4737                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-xs font-bold text-zinc-500 uppercase tracking-wider", children: [
4738                  /* @__PURE__ */ jsxRuntimeExports.jsx(Image$1, { size: 16 }),
4739                  " ",
4740                  isAccessory ? "Accessory" : "Instrument",
4741                  " SVG Graphic (",
4742                  getInstrumentLabel(selectedInstType, selectedInstIndex.toString()),
4743                  ")"
4744                ] }),
4745                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "cursor-pointer flex items-center gap-1 text-xs px-3 py-1 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded transition-colors", children: [
4746                  /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 14 }),
4747                  " Upload SVG",
4748                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", accept: ".svg", className: "hidden", onChange: handleInstSvgUpload })
4749                ] }) })
4750              ] }),
4751              uploadError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-500 text-xs mb-2", children: uploadError }),
4752              /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500 mb-2", children: [
4753                "Must contain an ",
4754                /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-indigo-400", children: 'id="instrument"' }),
4755                " root group tag."
4756              ] }),
4757              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-4 bg-[#0a0a0a] border border-zinc-700 rounded p-4 flex items-center justify-center h-[300px] relative", children: activeSvgContent ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
4758                "svg",
4759                {
4760                  width: "100%",
4761                  height: "100%",
4762                  viewBox: "-200 -200 400 400",
4763                  className: "overflow-visible",
4764                  children: [
4765                    /* @__PURE__ */ jsxRuntimeExports.jsx(
4766                      "g",
4767                      {
4768                        transform: activeTransform ? `translate(${activeTransform.x || 0}, ${activeTransform.y || 0}) scale(${activeTransform.scaleX ?? activeTransform.scale ?? 1}, ${activeTransform.scaleY ?? activeTransform.scale ?? 1}) rotate(${activeTransform.rotation || 0})` : "",
4769                        dangerouslySetInnerHTML: { __html: activeSvgContent }
4770                      }
4771                    ),
4772                    /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "0", cy: "0", r: "3", fill: "#ef4444", opacity: "0.5" }),
4773                    /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M-15,0 L15,0 M0,-15 L0,15", stroke: "#ef4444", strokeWidth: "1", opacity: "0.5" })
4774                  ]
4775                }
4776              ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-600 text-sm", children: [
4777                "No SVG data available for ",
4778                isAccessory ? "Accessory" : "Main Instrument"
4779              ] }) }),
4780              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
4781                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-5 gap-2 bg-zinc-900 border border-zinc-700 p-3 rounded", children: [
4782                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4783                    /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Scale X" }),
4784                    /* @__PURE__ */ jsxRuntimeExports.jsx(
4785                      "input",
4786                      {
4787                        type: "number",
4788                        step: "0.1",
4789                        value: (activeTransform == null ? void 0 : activeTransform.scaleX) ?? (activeTransform == null ? void 0 : activeTransform.scale) ?? 1,
4790                        onChange: (e) => {
4791                          const val = parseFloat(e.target.value);
4792                          setInstrumentConfigs((prev) => {
4793                            const typeObj = prev[selectedInstType];
4794                            const instObj = typeObj[selectedInstIndex];
4795                            const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4796                            const transformField = isAccessory ? "accessoryTransform" : "transform";
4797                            const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
4798                            return {
4799                              ...prev,
4800                              [selectedInstType]: {
4801                                ...typeObj,
4802                                [selectedInstIndex]: {
4803                                  ...currentDef,
4804                                  [transformField]: {
4805                                    ...currentTransform,
4806                                    scaleX: isNaN(val) ? 1 : val
4807                                  }
4808                                }
4809                              }
4810                            };
4811                          });
4812                        },
4813                        className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-sm"
4814                      }
4815                    )
4816                  ] }),
4817                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4818                    /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Scale Y" }),
4819                    /* @__PURE__ */ jsxRuntimeExports.jsx(
4820                      "input",
4821                      {
4822                        type: "number",
4823                        step: "0.1",
4824                        value: (activeTransform == null ? void 0 : activeTransform.scaleY) ?? (activeTransform == null ? void 0 : activeTransform.scale) ?? 1,
4825                        onChange: (e) => {
4826                          const val = parseFloat(e.target.value);
4827                          setInstrumentConfigs((prev) => {
4828                            const typeObj = prev[selectedInstType];
4829                            const instObj = typeObj[selectedInstIndex];
4830                            const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4831                            const transformField = isAccessory ? "accessoryTransform" : "transform";
4832                            const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
4833                            return {
4834                              ...prev,
4835                              [selectedInstType]: {
4836                                ...typeObj,
4837                                [selectedInstIndex]: {
4838                                  ...currentDef,
4839                                  [transformField]: {
4840                                    ...currentTransform,
4841                                    scaleY: isNaN(val) ? 1 : val
4842                                  }
4843                                }
4844                              }
4845                            };
4846                          });
4847                        },
4848                        className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-sm"
4849                      }
4850                    )
4851                  ] }),
4852                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4853                    /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Rotation (deg)" }),
4854                    /* @__PURE__ */ jsxRuntimeExports.jsx(
4855                      "input",
4856                      {
4857                        type: "number",
4858                        value: (activeTransform == null ? void 0 : activeTransform.rotation) ?? 0,
4859                        onChange: (e) => {
4860                          const val = parseFloat(e.target.value) || 0;
4861                          setInstrumentConfigs((prev) => {
4862                            const typeObj = prev[selectedInstType];
4863                            const instObj = typeObj[selectedInstIndex];
4864                            const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4865                            const transformField = isAccessory ? "accessoryTransform" : "transform";
4866                            const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
4867                            return {
4868                              ...prev,
4869                              [selectedInstType]: {
4870                                ...typeObj,
4871                                [selectedInstIndex]: {
4872                                  ...currentDef,
4873                                  [transformField]: {
4874                                    ...currentTransform,
4875                                    rotation: val
4876                                  }
4877                                }
4878                              }
4879                            };
4880                          });
4881                        },
4882                        className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-sm"
4883                      }
4884                    )
4885                  ] }),
4886                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4887                    /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Offset X" }),
4888                    /* @__PURE__ */ jsxRuntimeExports.jsx(
4889                      "input",
4890                      {
4891                        type: "number",
4892                        value: (activeTransform == null ? void 0 : activeTransform.x) ?? 0,
4893                        onChange: (e) => {
4894                          const val = parseFloat(e.target.value) || 0;
4895                          setInstrumentConfigs((prev) => {
4896                            const typeObj = prev[selectedInstType];
4897                            const instObj = typeObj[selectedInstIndex];
4898                            const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4899                            const transformField = isAccessory ? "accessoryTransform" : "transform";
4900                            const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
4901                            return {
4902                              ...prev,
4903                              [selectedInstType]: {
4904                                ...typeObj,
4905                                [selectedInstIndex]: {
4906                                  ...currentDef,
4907                                  [transformField]: {
4908                                    ...currentTransform,
4909                                    x: val
4910                                  }
4911                                }
4912                              }
4913                            };
4914                          });
4915                        },
4916                        className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-sm"
4917                      }
4918                    )
4919                  ] }),
4920                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
4921                    /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Offset Y" }),
4922                    /* @__PURE__ */ jsxRuntimeExports.jsx(
4923                      "input",
4924                      {
4925                        type: "number",
4926                        value: (activeTransform == null ? void 0 : activeTransform.y) ?? 0,
4927                        onChange: (e) => {
4928                          const val = parseFloat(e.target.value) || 0;
4929                          setInstrumentConfigs((prev) => {
4930                            const typeObj = prev[selectedInstType];
4931                            const instObj = typeObj[selectedInstIndex];
4932                            const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4933                            const transformField = isAccessory ? "accessoryTransform" : "transform";
4934                            const currentTransform = currentDef[transformField] || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
4935                            return {
4936                              ...prev,
4937                              [selectedInstType]: {
4938                                ...typeObj,
4939                                [selectedInstIndex]: {
4940                                  ...currentDef,
4941                                  [transformField]: {
4942                                    ...currentTransform,
4943                                    y: val
4944                                  }
4945                                }
4946                              }
4947                            };
4948                          });
4949                        },
4950                        className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-sm"
4951                      }
4952                    )
4953                  ] })
4954                ] }),
4955                isAccessory && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900 border border-zinc-700 p-3 rounded", children: [
4956                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-400 uppercase mb-1", children: "Accessory Mount Point" }),
4957                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4958                    "select",
4959                    {
4960                      value: (typeof selectedInstSvg === "object" ? selectedInstSvg == null ? void 0 : selectedInstSvg.accessoryMountPoint : "") || "hand_r",
4961                      onChange: (e) => {
4962                        const val = e.target.value;
4963                        setInstrumentConfigs((prev) => {
4964                          const typeObj = prev[selectedInstType];
4965                          const instObj = typeObj[selectedInstIndex];
4966                          const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4967                          return {
4968                            ...prev,
4969                            [selectedInstType]: {
4970                              ...typeObj,
4971                              [selectedInstIndex]: {
4972                                ...currentDef,
4973                                accessoryMountPoint: val
4974                              }
4975                            }
4976                          };
4977                        });
4978                      },
4979                      className: "w-full bg-black border border-zinc-700 rounded p-2 text-white text-sm",
4980                      children: ["root", "body", "hand_l", "hand_r", "front", "head"].map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: opt, children: opt }, opt))
4981                    }
4982                  )
4983                ] }),
4984                !isAccessory && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900 border border-zinc-700 p-3 rounded", children: [
4985                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-400 uppercase mb-1", children: "Main Instrument Mount Point" }),
4986                  /* @__PURE__ */ jsxRuntimeExports.jsx(
4987                    "select",
4988                    {
4989                      value: (typeof selectedInstSvg === "object" ? selectedInstSvg == null ? void 0 : selectedInstSvg.mountPoint : "") || "body",
4990                      onChange: (e) => {
4991                        const val = e.target.value;
4992                        setInstrumentConfigs((prev) => {
4993                          const typeObj = prev[selectedInstType];
4994                          const instObj = typeObj[selectedInstIndex];
4995                          const currentDef = typeof instObj === "string" ? { svgContent: instObj, mountPoint: "body" } : instObj;
4996                          return {
4997                            ...prev,
4998                            [selectedInstType]: {
4999                              ...typeObj,
5000                              [selectedInstIndex]: {
5001                                ...currentDef,
5002                                mountPoint: val
5003                              }
5004                            }
5005                          };
5006                        });
5007                      },
5008                      className: "w-full bg-black border border-zinc-700 rounded p-2 text-white text-sm",
5009                      children: ["root", "body", "hand_l", "hand_r", "front", "head"].map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: opt, children: opt }, opt))
5010                    }
5011                  )
5012                ] })
5013              ] })
5014            ] }),
5015            selectedInstSvg && typeof selectedInstSvg !== "object" ? null : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
5016              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900 border border-zinc-700 p-3 rounded space-y-3", children: [
5017                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-indigo-400 uppercase tracking-wider", children: "Gluing & Alignment" }),
5018                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: "Bind instrument plugs to character body parts. You can add multiple gluing points. The first entry is usually the primary anchor." }),
5019                (() => {
5020                  const instObj = selectedInstSvg;
5021                  let gluingArray = Array.isArray(instObj.gluing) ? instObj.gluing : instObj.gluing ? [instObj.gluing] : [];
5022                  if (gluingArray.length === 0 && instObj.headAnchor) {
5023                    gluingArray = [{ type: "one-point", ip: instObj.headAnchor, t1: "head", tp: { x: 0, y: 0 } }];
5024                  }
5025                  const availablePlugs = Array.from(/* @__PURE__ */ new Set([...getFamilyDefaultPlugs(instObj.family || "other"), ...Object.keys(instObj.plugs || {})]));
5026                  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
5027                    gluingArray.map((glue, idx) => {
5028                      var _a3;
5029                      return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-black/40 border border-zinc-800 p-2 rounded relative", children: [
5030                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5031                          "button",
5032                          {
5033                            type: "button",
5034                            onClick: () => {
5035                              const newGluing = [...gluingArray];
5036                              newGluing.splice(idx, 1);
5037                              setInstrumentConfigs((prev) => {
5038                                const typeObj = prev[selectedInstType];
5039                                const io = typeObj[selectedInstIndex] || {};
5040                                return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing.length > 0 ? newGluing : void 0 } } };
5041                              });
5042                            },
5043                            className: "absolute top-1 right-1 text-red-500 hover:text-red-400 text-xs px-1",
5044                            children: "✕"
5045                          }
5046                        ),
5047                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2 mt-2", children: [
5048                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5049                            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase", children: "Gluing Type" }),
5050                            /* @__PURE__ */ jsxRuntimeExports.jsxs(
5051                              "select",
5052                              {
5053                                value: glue.type || "none",
5054                                onChange: (e) => {
5055                                  const val = e.target.value;
5056                                  const newGluing = [...gluingArray];
5057                                  newGluing[idx] = { ...glue, type: val };
5058                                  setInstrumentConfigs((prev) => {
5059                                    const typeObj = prev[selectedInstType];
5060                                    const io = typeObj[selectedInstIndex] || {};
5061                                    return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing } } };
5062                                  });
5063                                },
5064                                className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-xs",
5065                                children: [
5066                                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None / Disabled" }),
5067                                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "one-point", children: "1-Point Glue" })
5068                                ]
5069                              }
5070                            )
5071                          ] }),
5072                          glue.type === "one-point" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
5073                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5074                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase", children: "Instrument Plug" }),
5075                              /* @__PURE__ */ jsxRuntimeExports.jsx(
5076                                "select",
5077                                {
5078                                  value: glue.plugName || ((_a3 = Object.entries(instObj.plugs || {}).find(([k, v]) => {
5079                                    var _a4, _b3;
5080                                    return (v == null ? void 0 : v.x) === ((_a4 = glue.ip) == null ? void 0 : _a4.x) && (v == null ? void 0 : v.y) === ((_b3 = glue.ip) == null ? void 0 : _b3.y);
5081                                  })) == null ? void 0 : _a3[0]) || "mouthpiece",
5082                                  onChange: (e) => {
5083                                    const val = e.target.value;
5084                                    const plugs = instObj.plugs || {};
5085                                    let ip = { x: 0, y: 0 };
5086                                    if (val === "mouthpiece") ip = plugs.mouthpiece || { x: 0, y: 0 };
5087                                    else ip = plugs[val] || { x: 0, y: 0 };
5088                                    const newGluing = [...gluingArray];
5089                                    newGluing[idx] = { ...glue, plugName: val, ip };
5090                                    setInstrumentConfigs((prev) => {
5091                                      const typeObj = prev[selectedInstType];
5092                                      const io = typeObj[selectedInstIndex] || {};
5093                                      return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing } } };
5094                                    });
5095                                  },
5096                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-xs",
5097                                  children: availablePlugs.map((part) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: part, children: part }, part))
5098                                }
5099                              )
5100                            ] }),
5101                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5102                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase", children: "Target Body Part" }),
5103                              /* @__PURE__ */ jsxRuntimeExports.jsx(
5104                                "select",
5105                                {
5106                                  value: glue.t1 || "head",
5107                                  onChange: (e) => {
5108                                    const val = e.target.value;
5109                                    const newGluing = [...gluingArray];
5110                                    newGluing[idx] = { ...glue, t1: val };
5111                                    setInstrumentConfigs((prev) => {
5112                                      const typeObj = prev[selectedInstType];
5113                                      const io = typeObj[selectedInstIndex] || {};
5114                                      return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing } } };
5115                                    });
5116                                  },
5117                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-xs",
5118                                  children: ["head", "body", "shoulder_l", "elbow_l", "hand_l", "shoulder_r", "elbow_r", "hand_r", "leg_l", "foot_l", "leg_r", "foot_r"].map((part) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: part, children: part }, part))
5119                                }
5120                              )
5121                            ] }),
5122                            (glue.t1 === "hand_l" || glue.t1 === "hand_r") && /* @__P
5122URE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [
5123                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase", children: "Hand Grip Offset (from instrument anchor)" }),
5124                              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-2 mt-1", children: ["x", "y"].map((axis) => {
5125                                var _a4;
5126                                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
5127                                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500 uppercase", children: axis }),
5128                                  /* @__PURE__ */ jsxRuntimeExports.jsx(
5129                                    "input",
5130                                    {
5131                                      type: "number",
5132                                      value: ((_a4 = glue.tp) == null ? void 0 : _a4[axis]) ?? 0,
5133                                      step: 1,
5134                                      onChange: (e) => {
5135                                        const raw = e.target.value;
5136                                        if (raw === "" || raw === "-") return;
5137                                        const val = parseFloat(raw);
5138                                        if (isNaN(val)) return;
5139                                        const newGluing = [...gluingArray];
5140                                        const otherAxis = axis === "x" ? "y" : "x";
5141                                        newGluing[idx] = { ...glue, tp: { ...glue.tp || { [otherAxis]: 0 }, [axis]: val } };
5142                                        setInstrumentConfigs((prev) => {
5143                                          const typeObj = prev[selectedInstType];
5144                                          const io = typeObj[selectedInstIndex] || {};
5145                                          return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing } } };
5146                                        });
5147                                      },
5148                                      onKeyDown: (e) => {
5149                                        var _a5;
5150                                        if (e.key === "ArrowUp" || e.key === "ArrowDown") {
5151                                          e.preventDefault();
5152                                          const step = e.shiftKey ? 5 : 1;
5153                                          const dir = e.key === "ArrowUp" ? -1 : 1;
5154                                          const current = ((_a5 = glue.tp) == null ? void 0 : _a5[axis]) ?? 0;
5155                                          const val = current + dir * step;
5156                                          const newGluing = [...gluingArray];
5157                                          const otherAxis = axis === "x" ? "y" : "x";
5158                                          newGluing[idx] = { ...glue, tp: { ...glue.tp || { [otherAxis]: 0 }, [axis]: val } };
5159                                          setInstrumentConfigs((prev) => {
5160                                            const typeObj = prev[selectedInstType];
5161                                            const io = typeObj[selectedInstIndex] || {};
5162                                            return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing } } };
5163                                          });
5164                                        }
5165                                      },
5166                                      className: "w-16 bg-black border border-zinc-700 rounded p-1 text-white text-xs"
5167                                    }
5168                                  )
5169                                ] }, axis);
5170                              }) }),
5171                              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] text-zinc-600 mt-0.5", children: "Offset from instrument anchor. (0,0)=anchor point. Arrow keys ±1, Shift+Arrow ±5." })
5172                            ] })
5173                          ] })
5174                        ] })
5175                      ] }, idx);
5176                    }),
5177                    /* @__PURE__ */ jsxRuntimeExports.jsx(
5178                      "button",
5179                      {
5180                        type: "button",
5181                        onClick: () => {
5182                          const newGluing = [...gluingArray, { type: "one-point", t1: "head", tp: { x: 0, y: 0 } }];
5183                          setInstrumentConfigs((prev) => {
5184                            const typeObj = prev[selectedInstType];
5185                            const io = typeObj[selectedInstIndex] || {};
5186                            return { ...prev, [selectedInstType]: { ...typeObj, [selectedInstIndex]: { ...io, gluing: newGluing } } };
5187                          });
5188                        },
5189                        className: "text-xs bg-zinc-800 text-zinc-300 px-2 py-1 rounded hover:bg-zinc-700",
5190                        children: "+ Add Gluing Point"
5191                      }
5192                    )
5193                  ] });
5194                })()
5195              ] }),
5196              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900 border border-zinc-700 p-3 rounded space-y-3", children: [
5197                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-indigo-400 uppercase tracking-wider", children: "Instrument Plugs & Alignment Points" }),
5198                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: "Specify plug coordinates on the instrument (e.g. where hands grip or mouth locks). Select the target character socket it associates with. Click 🎯 to click-position on preview." }),
5199                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 text-zinc-300", children: (() => {
5200                  const defaultPlugs = getFamilyDefaultPlugs((selectedInstSvg == null ? void 0 : selectedInstSvg.family) || "other");
5201                  const configPlugs = Object.keys((selectedInstSvg == null ? void 0 : selectedInstSvg.plugs) || {});
5202                  const allPlugs = Array.from(/* @__PURE__ */ new Set([...defaultPlugs, ...configPlugs]));
5203                  const availableSockets = Array.from(/* @__PURE__ */ new Set([
5204                    "mouth",
5205                    "shoulder_l",
5206                    "shoulder_r",
5207                    "elbow_l",
5208                    "elbow_r",
5209                    "hand_l",
5210                    "hand_r",
5211                    ...Object.keys((selectedConfig == null ? void 0 : selectedConfig.sockets) || {})
5212                  ]));
5213                  const getAssociatedSocket = (name, plug) => {
5214                    if (plug == null ? void 0 : plug.socket) return plug.socket;
5215                    if (name === "mouthpiece") return "mouth";
5216                    if (name === "hand_l") return "hand_l";
5217                    if (name === "hand_r") return "hand_r";
5218                    return "none";
5219                  };
5220                  return allPlugs.map((plugName) => {
5221                    var _a3;
5222                    const svgVal = svgCoords[`plug_${plugName}`];
5223                    const configVal = (_a3 = selectedInstSvg.plugs) == null ? void 0 : _a3[plugName];
5224                    const isSvgOnly = svgVal && !configVal;
5225                    const displayX = (configVal == null ? void 0 : configVal.x) ?? (svgVal == null ? void 0 : svgVal.x) ?? "";
5226                    const displayY = (configVal == null ? void 0 : configVal.y) ?? (svgVal == null ? void 0 : svgVal.y) ?? "";
5227                    const currentSocket = getAssociatedSocket(plugName, configVal);
5228                    const isEditingThis = editMode === `plug_${plugName}`;
5229                    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `bg-black/40 border rounded p-2 grid grid-cols-12 gap-2 items-center ${isEditingThis ? "border-emerald-500 bg-emerald-950/10" : "border-zinc-800"}`, children: [
5230                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-3 text-xs font-bold text-zinc-400 truncate flex flex-col gap-0.5", children: [
5231                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", title: plugName, children: plugName }),
5232                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1", children: [
5233                          isSvgOnly && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[7px] bg-zinc-805 text-zinc-400 px-1 rounded", children: "SVG" }),
5234                          !svgVal && !configVal && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[7px] bg-red-900/40 text-red-400 px-1 rounded", children: "Missing" })
5235                        ] })
5236                      ] }),
5237                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [
5238                        /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "X Coord" }),
5239                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5240                          "input",
5241                          {
5242                            type: "number",
5243                            value: displayX,
5244                            placeholder: svgVal ? `SVG: ${svgVal.x}` : "None",
5245                            onChange: (e) => {
5246                              const val = parseFloat(e.target.value);
5247                              setInstrumentConfigs((prev) => {
5248                                const typeObj = prev[selectedInstType];
5249                                const instObj = typeObj[selectedInstIndex] || {};
5250                                const currentPlugs = instObj.plugs || {};
5251                                const newX = isNaN(val) ? 0 : val;
5252                                const newY = (configVal == null ? void 0 : configVal.y) ?? (svgVal == null ? void 0 : svgVal.y) ?? 0;
5253                                const updated = {
5254                                  ...instObj,
5255                                  plugs: {
5256                                    ...currentPlugs,
5257                                    [plugName]: { ...currentPlugs[plugName] || {}, x: newX, y: newY }
5258                                  }
5259                                };
5260                                return {
5261                                  ...prev,
5262                                  [selectedInstType]: {
5263                                    ...typeObj,
5264                                    [selectedInstIndex]: updated
5265                                  }
5266                                };
5267                              });
5268                            },
5269                            className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5270                          }
5271                        )
5272                      ] }),
5273                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [
5274                        /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Y Coord" }),
5275                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5276                          "input",
5277                          {
5278                            type: "number",
5279                            value: displayY,
5280                            placeholder: svgVal ? `SVG: ${svgVal.y}` : "None",
5281                            onChange: (e) => {
5282                              const val = parseFloat(e.target.value);
5283                              setInstrumentConfigs((prev) => {
5284                                const typeObj = prev[selectedInstType];
5285                                const instObj = typeObj[selectedInstIndex] || {};
5286                                const currentPlugs = instObj.plugs || {};
5287                                const newX = (configVal == null ? void 0 : configVal.x) ?? (svgVal == null ? void 0 : svgVal.x) ?? 0;
5288                                const newY = isNaN(val) ? 0 : val;
5289                                const updated = {
5290                                  ...instObj,
5291                                  plugs: {
5292                                    ...currentPlugs,
5293                                    [plugName]: { ...currentPlugs[plugName] || {}, x: newX, y: newY }
5294                                  }
5295                                };
5296                                return {
5297                                  ...prev,
5298                                  [selectedInstType]: {
5299                                    ...typeObj,
5300                                    [selectedInstIndex]: updated
5301                                  }
5302                                };
5303                              });
5304                            },
5305                            className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5306                          }
5307                        )
5308                      ] }),
5309                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-3", children: [
5310                        /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Socket" }),
5311                        /* @__PURE__ */ jsxRuntimeExports.jsxs(
5312                          "select",
5313                          {
5314                            value: currentSocket,
5315                            onChange: (e) => {
5316                              const socketVal = e.target.value;
5317                              pushUndo();
5318                              setInstrumentConfigs((prev) => {
5319                                const typeObj = prev[selectedInstType];
5320                                const instObj = typeObj[selectedInstIndex] || {};
5321                                const currentPlugs = instObj.plugs || {};
5322                                const currentCoords = configVal || svgVal || { x: 0, y: 0 };
5323                                return {
5324                                  ...prev,
5325                                  [selectedInstType]: {
5326                                    ...typeObj,
5327                                    [selectedInstIndex]: {
5328                                      ...instObj,
5329                                      plugs: {
5330                                        ...currentPlugs,
5331                                        [plugName]: {
5332                                          ...currentCoords,
5333                                          socket: socketVal
5334                                        }
5335                                      }
5336                                    }
5337                                  }
5338                                };
5339                              });
5340                            },
5341                            className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]",
5342                            children: [
5343                              /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None" }),
5344                              availableSockets.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: s, children: s }, s))
5345                            ]
5346                          }
5347                        )
5348                      ] }),
5349                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 flex justify-end gap-1", children: [
5350                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5351                          "button",
5352                          {
5353                            type: "button",
5354                            onClick: () => setEditMode(isEditingThis ? "none" : `plug_${plugName}`),
5355                            className: `p-1 rounded border transition-colors ${isEditingThis ? "bg-emerald-600 border-emerald-500 text-white" : "bg-zinc-800 border-zinc-700 text-zinc-400 hover:bg-zinc-750 hover:text-white"}`,
5356                            title: "Pin on Canvas",
5357                            children: "🎯"
5358                          }
5359                        ),
5360                        !isSvgOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
5361                          "button",
5362                          {
5363                            type: "button",
5364                            onClick: () => {
5365                              pushUndo();
5366                              setInstrumentConfigs((prev) => {
5367                                const typeObj = prev[selectedInstType];
5368                                const instObj = typeObj[selectedInstIndex] || {};
5369                                const currentPlugs = instObj.plugs ? { ...instObj.plugs } : {
5370                                  mouthpiece: { x: 0, y: -50, socket: "mouth" },
5371                                  hand_l: { x: 0, y: 0, socket: "hand_l" },
5372                                  hand_r: { x: 0, y: 0, socket: "hand_r" }
5373                                };
5374                                delete currentPlugs[plugName];
5375                                return {
5376                                  ...prev,
5377                                  [selectedInstType]: {
5378                                    ...typeObj,
5379                                    [selectedInstIndex]: {
5380                                      ...instObj,
5381                                      plugs: currentPlugs
5382                                    }
5383                                  }
5384                                };
5385                              });
5386                            },
5387                            className: "p-1 rounded border bg-red-950/20 border-red-900/40 text-red-400 hover:bg-red-900/30 transition-colors",
5388                            title: "Remove Plug",
5389                            children: "✕"
5390                          }
5391                        )
5392                      ] })
5393                    ] }, plugName);
5394                  });
5395                })() }),
5396                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5 border-t border-zinc-800/60 pt-2.5", children: [
5397                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[9px] text-zinc-500 uppercase font-bold", children: "Add Custom Plug / Alignment Point" }),
5398                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
5399                    /* @__PURE__ */ jsxRuntimeExports.jsx(
5400                      "input",
5401                      {
5402                        type: "text",
5403                        id: "new-plug-name-input",
5404                        placeholder: "Name (e.g. strap)",
5405                        className: "flex-1 bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5406                      }
5407                    ),
5408                    (() => {
5409                      const availableSockets = Array.from(/* @__PURE__ */ new Set([
5410                        "mouth",
5411                        "shoulder_l",
5412                        "shoulder_r",
5413                        "elbow_l",
5414                        "elbow_r",
5415                        "hand_l",
5416                        "hand_r",
5417                        ...Object.keys((selectedConfig == null ? void 0 : selectedConfig.sockets) || {})
5418                      ]));
5419                      return /* @__PURE__ */ jsxRuntimeExports.jsxs(
5420                        "select",
5421                        {
5422                          id: "new-plug-socket-select",
5423                          className: "w-24 bg-black border border-zinc-700 rounded p-1 text-white text-[10px]",
5424                          children: [
5425                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "No Socket" }),
5426                            availableSockets.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: s, children: s }, s))
5427                          ]
5428                        }
5429                      );
5430                    })(),
5431                    /* @__PURE__ */ jsxRuntimeExports.jsx(
5432                      "button",
5433                      {
5434                        type: "button",
5435                        onClick: () => {
5436                          var _a3, _b3;
5437                          const input = document.getElementById("new-plug-name-input");
5438                          const socketSelect = document.getElementById("new-plug-socket-select");
5439                          const name = (_b3 = (_a3 = input == null ? void 0 : input.value) == null ? void 0 : _a3.trim()) == null ? void 0 : _b3.toLowerCase();
5440                          const socketVal = (socketSelect == null ? void 0 : socketSelect.value) || "none";
5441                          if (name && selectedInstSvg) {
5442                            pushUndo();
5443                            setInstrumentConfigs((prev) => {
5444                              const typeObj = prev[selectedInstType];
5445                              const instObj = typeObj[selectedInstIndex] || {};
5446                              const currentPlugs = instObj.plugs || {};
5447                              return {
5448                                ...prev,
5449                                [selectedInstType]: {
5450                                  ...typeObj,
5451                                  [selectedInstIndex]: {
5452                                    ...instObj,
5453                                    plugs: {
5454                                      ...currentPlugs,
5455                                      [name]: currentPlugs[name] || { x: 0, y: 0, socket: socketVal }
5456                                    }
5457                                  }
5458                                }
5459                              };
5460                            });
5461                            input.value = "";
5462                            socketSelect.value = "none";
5463                          }
5464                        },
5465                        className: "bg-indigo-600 hover:bg-indigo-500 text-white rounded px-2 text-[10px] font-bold",
5466                        children: "Add"
5467                      }
5468                    )
5469                  ] })
5470                ] })
5471              ] }),
5472              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-900 border border-zinc-700 p-3 rounded space-y-4", children: [
5473                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-indigo-400 uppercase tracking-wider", children: "Motion Physics & Rest Pose" }),
5474                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
5475                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Rest Pose (Fallback positions for hands)" }),
5476                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4 bg-black/40 p-2 border border-zinc-800 rounded", children: [
5477                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5478                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[9px] text-zinc-500 uppercase mb-1", children: "Left Hand (X, Y)" }),
5479                      /* @__P
5479URE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
5480                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5481                          "input",
5482                          {
5483                            type: "number",
5484                            placeholder: "X (e.g. -30)",
5485                            value: ((_b2 = (_a2 = selectedInstSvg.restPose) == null ? void 0 : _a2.leftHand) == null ? void 0 : _b2.x) ?? "",
5486                            onChange: (e) => {
5487                              const val = parseFloat(e.target.value);
5488                              setInstrumentConfigs((prev) => {
5489                                const typeObj = prev[selectedInstType];
5490                                const instObj = typeObj[selectedInstIndex] || {};
5491                                const rp = instObj.restPose || {};
5492                                const lh = rp.leftHand || {};
5493                                return {
5494                                  ...prev,
5495                                  [selectedInstType]: {
5496                                    ...typeObj,
5497                                    [selectedInstIndex]: {
5498                                      ...instObj,
5499                                      restPose: { ...rp, leftHand: isNaN(val) ? void 0 : { ...lh, x: val } }
5500                                    }
5501                                  }
5502                                };
5503                              });
5504                            },
5505                            className: "w-1/2 bg-black border border-zinc-700 rounded p-1 text-white text-xs"
5506                          }
5507                        ),
5508                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5509                          "input",
5510                          {
5511                            type: "number",
5512                            placeholder: "Y (e.g. 10)",
5513                            value: ((_d2 = (_c2 = selectedInstSvg.restPose) == null ? void 0 : _c2.leftHand) == null ? void 0 : _d2.y) ?? "",
5514                            onChange: (e) => {
5515                              const val = parseFloat(e.target.value);
5516                              setInstrumentConfigs((prev) => {
5517                                const typeObj = prev[selectedInstType];
5518                                const instObj = typeObj[selectedInstIndex] || {};
5519                                const rp = instObj.restPose || {};
5520                                const lh = rp.leftHand || {};
5521                                return {
5522                                  ...prev,
5523                                  [selectedInstType]: {
5524                                    ...typeObj,
5525                                    [selectedInstIndex]: {
5526                                      ...instObj,
5527                                      restPose: { ...rp, leftHand: isNaN(val) ? void 0 : { ...lh, y: val } }
5528                                    }
5529                                  }
5530                                };
5531                              });
5532                            },
5533                            className: "w-1/2 bg-black border border-zinc-700 rounded p-1 text-white text-xs"
5534                          }
5535                        )
5536                      ] })
5537                    ] }),
5538                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5539                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[9px] text-zinc-500 uppercase mb-1", children: "Right Hand (X, Y)" }),
5540                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
5541                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5542                          "input",
5543                          {
5544                            type: "number",
5545                            placeholder: "X (e.g. 30)",
5546                            value: ((_f2 = (_e2 = selectedInstSvg.restPose) == null ? void 0 : _e2.rightHand) == null ? void 0 : _f2.x) ?? "",
5547                            onChange: (e) => {
5548                              const val = parseFloat(e.target.value);
5549                              setInstrumentConfigs((prev) => {
5550                                const typeObj = prev[selectedInstType];
5551                                const instObj = typeObj[selectedInstIndex] || {};
5552                                const rp = instObj.restPose || {};
5553                                const rh = rp.rightHand || {};
5554                                return {
5555                                  ...prev,
5556                                  [selectedInstType]: {
5557                                    ...typeObj,
5558                                    [selectedInstIndex]: {
5559                                      ...instObj,
5560                                      restPose: { ...rp, rightHand: isNaN(val) ? void 0 : { ...rh, x: val } }
5561                                    }
5562                                  }
5563                                };
5564                              });
5565                            },
5566                            className: "w-1/2 bg-black border border-zinc-700 rounded p-1 text-white text-xs"
5567                          }
5568                        ),
5569                        /* @__PURE__ */ jsxRuntimeExports.jsx(
5570                          "input",
5571                          {
5572                            type: "number",
5573                            placeholder: "Y (e.g. 10)",
5574                            value: ((_h2 = (_g2 = selectedInstSvg.restPose) == null ? void 0 : _g2.rightHand) == null ? void 0 : _h2.y) ?? "",
5575                            onChange: (e) => {
5576                              const val = parseFloat(e.target.value);
5577                              setInstrumentConfigs((prev) => {
5578                                const typeObj = prev[selectedInstType];
5579                                const instObj = typeObj[selectedInstIndex] || {};
5580                                const rp = instObj.restPose || {};
5581                                const rh = rp.rightHand || {};
5582                                return {
5583                                  ...prev,
5584                                  [selectedInstType]: {
5585                                    ...typeObj,
5586                                    [selectedInstIndex]: {
5587                                      ...instObj,
5588                                      restPose: { ...rp, rightHand: isNaN(val) ? void 0 : { ...rh, y: val } }
5589                                    }
5590                                  }
5591                                };
5592                              });
5593                            },
5594                            className: "w-1/2 bg-black border border-zinc-700 rounded p-1 text-white text-xs"
5595                          }
5596                        )
5597                      ] })
5598                    ] })
5599                  ] })
5600                ] }),
5601                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
5602                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "Note Range & Physical Spread" }),
5603                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-3 gap-2 bg-black/40 p-2 border border-zinc-800 rounded", children: [
5604                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5605                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[9px] text-zinc-500 uppercase mb-1", children: "Min Note (0-127)" }),
5606                      /* @__PURE__ */ jsxRuntimeExports.jsx(
5607                        "input",
5608                        {
5609                          type: "number",
5610                          placeholder: "Min",
5611                          value: ((_i2 = selectedInstSvg.noteRange) == null ? void 0 : _i2.minNote) ?? "",
5612                          onChange: (e) => {
5613                            const val = parseInt(e.target.value);
5614                            setInstrumentConfigs((prev) => {
5615                              const typeObj = prev[selectedInstType];
5616                              const instObj = typeObj[selectedInstIndex] || {};
5617                              const nr = instObj.noteRange || {};
5618                              return {
5619                                ...prev,
5620                                [selectedInstType]: {
5621                                  ...typeObj,
5622                                  [selectedInstIndex]: {
5623                                    ...instObj,
5624                                    noteRange: { ...nr, minNote: isNaN(val) ? void 0 : val }
5625                                  }
5626                                }
5627                              };
5628                            });
5629                          },
5630                          className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5631                        }
5632                      )
5633                    ] }),
5634                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5635                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[9px] text-zinc-500 uppercase mb-1", children: "Max Note (0-127)" }),
5636                      /* @__PURE__ */ jsxRuntimeExports.jsx(
5637                        "input",
5638                        {
5639                          type: "number",
5640                          placeholder: "Max",
5641                          value: ((_j2 = selectedInstSvg.noteRange) == null ? void 0 : _j2.maxNote) ?? "",
5642                          onChange: (e) => {
5643                            const val = parseInt(e.target.value);
5644                            setInstrumentConfigs((prev) => {
5645                              const typeObj = prev[selectedInstType];
5646                              const instObj = typeObj[selectedInstIndex] || {};
5647                              const nr = instObj.noteRange || {};
5648                              return {
5649                                ...prev,
5650                                [selectedInstType]: {
5651                                  ...typeObj,
5652                                  [selectedInstIndex]: {
5653                                    ...instObj,
5654                                    noteRange: { ...nr, maxNote: isNaN(val) ? void 0 : val }
5655                                  }
5656                                }
5657                              };
5658                            });
5659                          },
5660                          className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5661                        }
5662                      )
5663                    ] }),
5664                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5665                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[9px] text-zinc-500 uppercase mb-1", children: "Physical Width (px)" }),
5666                      /* @__PURE__ */ jsxRuntimeExports.jsx(
5667                        "input",
5668                        {
5669                          type: "number",
5670                          placeholder: "Width",
5671                          value: ((_k2 = selectedInstSvg.noteRange) == null ? void 0 : _k2.physicalLength) ?? "",
5672                          onChange: (e) => {
5673                            const val = parseInt(e.target.value);
5674                            setInstrumentConfigs((prev) => {
5675                              const typeObj = prev[selectedInstType];
5676                              const instObj = typeObj[selectedInstIndex] || {};
5677                              const nr = instObj.noteRange || {};
5678                              return {
5679                                ...prev,
5680                                [selectedInstType]: {
5681                                  ...typeObj,
5682                                  [selectedInstIndex]: {
5683                                    ...instObj,
5684                                    noteRange: { ...nr, physicalLength: isNaN(val) ? void 0 : val }
5685                                  }
5686                                }
5687                              };
5688                            });
5689                          },
5690                          className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5691                        }
5692                      )
5693                    ] })
5694                  ] })
5695                ] }),
5696                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
5697                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-400 uppercase font-bold", children: "IK Smooth & Motion Physics" }),
5698                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-black/40 p-2 border border-zinc-800 rounded space-y-2", children: [
5699                    { key: "swayFrequency", label: "Sway Frequency", defaultVal: 5e-3, min: 1e-3, max: 0.05, step: 1e-3 },
5700                    { key: "strikeFrequency", label: "Strike Frequency", defaultVal: 0.02, min: 5e-3, max: 0.1, step: 5e-3 },
5701                    { key: "strikeAmplitude", label: "Strike Amp (px)", defaultVal: 10, min: 0, max: 40, step: 1 },
5702                    { key: "bowPhaseStep", label: "Bow Phase Step", defaultVal: 0.05, min: 0.01, max: 0.2, step: 0.01 },
5703                    { key: "bowGapMs", label: "Bow Gap (ms)", defaultVal: 500, min: 50, max: 2e3, step: 50 },
5704                    { key: "strumSpeedMult", label: "Strum Speed Mult", defaultVal: 0.03, min: 5e-3, max: 0.15, step: 5e-3 },
5705                    { key: "strumVerticalAmp", label: "Strum Vert Amp", defaultVal: 15, min: 0, max: 60, step: 1 },
5706                    { key: "strumHorizontalAmp", label: "Strum Horiz Amp", defaultVal: 5, min: 0, max: 30, step: 1 },
5707                    { key: "ikLerpL", label: "IK Lerp Left", defaultVal: 0.3, min: 0.01, max: 1, step: 0.01 },
5708                    { key: "ikLerpR", label: "IK Lerp Right", defaultVal: 0.3, min: 0.01, max: 1, step: 0.01 }
5709                  ].map(({ key, label, defaultVal, min, max, step }) => {
5710                    var _a3;
5711                    const currentVal = ((_a3 = selectedInstSvg.motionPhysics) == null ? void 0 : _a3[key]) ?? defaultVal;
5712                    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
5713                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-400 text-xs w-28 shrink-0", children: label }),
5714                      /* @__PURE__ */ jsxRuntimeExports.jsx(
5715                        "input",
5716                        {
5717                          type: "range",
5718                          min,
5719                          max,
5720                          step,
5721                          value: currentVal,
5722                          onChange: (e) => {
5723                            const val = parseFloat(e.target.value);
5724                            setInstrumentConfigs((prev) => {
5725                              const typeObj = prev[selectedInstType];
5726                              const instObj = typeObj[selectedInstIndex] || {};
5727                              const mp = instObj.motionPhysics || {};
5728                              return {
5729                                ...prev,
5730                                [selectedInstType]: {
5731                                  ...typeObj,
5732                                  [selectedInstIndex]: {
5733                                    ...instObj,
5734                                    motionPhysics: { ...mp, [key]: val }
5735                                  }
5736                                }
5737                              };
5738                            });
5739                          },
5740                          className: "flex-1 accent-indigo-500 h-1"
5741                        }
5742                      ),
5743                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-300 text-xs w-10 text-right", children: currentVal }),
5744                      /* @__PURE__ */ jsxRuntimeExports.jsx(
5745                        "button",
5746                        {
5747                          onClick: () => {
5748                            setInstrumentConfigs((prev) => {
5749                              const typeObj = prev[selectedInstType];
5750                              const instObj = typeObj[selectedInstIndex] || {};
5751                              const mp = { ...instObj.motionPhysics || {} };
5752                              delete mp[key];
5753                              return {
5754                                ...prev,
5755                                [selectedInstType]: {
5756                                  ...typeObj,
5757                                  [selectedInstIndex]: {
5758                                    ...instObj,
5759                                    motionPhysics: Object.keys(mp).length > 0 ? mp : void 0
5760                                  }
5761                                }
5762                              };
5763                            });
5764                          },
5765                          title: "Reset override",
5766                          className: "text-zinc-500 hover:text-zinc-300 text-xs",
5767                          children: "↺"
5768                        }
5769                      )
5770                    ] }, key);
5771                  }) })
5772                ] })
5773              ] })
5774            ] }),
5775            /* @__PURE__ */ jsxRuntimeExports.jsx(
5776              "textarea",
5777              {
5778                value: selectedInstSvg ? typeof selectedInstSvg === "string" ? selectedInstSvg : JSON.stringify(selectedInstSvg, null, 2) : "",
5779                onChange: (e) => {
5780                  try {
5781                    const parsed = JSON.parse(e.target.value);
5782                    setInstrumentConfigs((prev) => ({
5783                      ...prev,
5784                      [selectedInstType]: { ...prev[selectedInstType], [selectedInstIndex]: parsed }
5785                    }));
5786                  } catch {
5787                  }
5788                },
5789                className: "w-full h-64 bg-black border border-zinc-700 rounded p-3 text-emerald-400 font-mono text-sm resize-y"
5790              }
5791            )
5792          ] });
5793        })(),
5794        activeTab === "clothing" && selectedClothingDef && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-4xl space-y-8", children: [
5795          (() => {
5796            const warnings = [];
5797            Object.keys(selectedClothingDef.parts).forEach((part) => {
5798              var _a2, _b2, _c2, _d2, _e2;
5799              const glue = (_a2 = selectedClothingDef.gluing) == null ? void 0 : _a2[part];
5800              if (!glue || glue.type === "none") return;
5801              const svgContent = selectedClothingDef.parts[part] || "";
5802              const svgCoords = parseSvgSocketsAndPlugs(svgContent);
5803              const hasP1 = svgCoords["plug_p1"] !== void 0 || ((_c2 = (_b2 = selectedClothingDef.plugs) == null ? void 0 : _b2[part]) == null ? void 0 : _c2.p1) !== void 0 || glue.p1 !== void 0;
5804              const hasP2 = svgCoords["plug_p2"] !== void 0 || ((_e2 = (_d2 = selectedClothingDef.plugs) == null ? void 0 : _d2[part]) == null ? void 0 : _e2.p2) !== void 0 || glue.p2 !== void 0;
5805              const missing = [];
5806              if (!hasP1) missing.push("p1");
5807              if (glue.type === "two-point" && !hasP2) missing.push("p2");
5808              if (missing.length > 0) {
5809                warnings.push({ part, missing });
5810              }
5811            });
5812            if (warnings.length === 0) return null;
5813            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-amber-950/40 border border-amber-800 text-amber-200 p-3 rounded-lg flex flex-col gap-1 text-xs", children: [
5814              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold flex items-center gap-1.5 text-amber-400", children: [
5815                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: "⚠️" }),
5816                " Missing Clothing Gluing Plugs"
5817              ] }),
5818              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400 font-normal", children: "The following clothing parts have gluing enabled but are missing plugs in their SVG/config overrides:" }),
5819              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 space-y-1", children: warnings.map((w) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
5820                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-indigo-400 font-semibold uppercase font-mono", children: w.part }),
5821                ":",
5822                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex gap-1", children: w.missing.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-1.5 py-0.5 bg-amber-900/40 border border-amber-700/50 rounded text-[10px] text-amber-300 font-mono font-semibold", children: [
5823                  "plug_",
5824                  m
5825                ] }, m)) })
5826              ] }, w.part)) })
5827            ] });
5828          })(),
5829          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-800 rounded-lg p-4 bg-zinc-900/50", children: [
5830            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-xs font-bold text-zinc-500 uppercase tracking-wider", children: [
5831              /* @__PURE__ */ jsxRuntimeExports.jsx(PenLine, { size: 16 }),
5832              " Clothing Config"
5833            ] }) }),
5834            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4", children: [
5835              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase tracking-wider mb-2", children: "ID (Name)" }),
5836              /* @__PURE__ */ jsxRuntimeExports.jsx(
5837                "input",
5838                {
5839                  type: "text",
5840                  value: selectedClothingDef.id,
5841                  onChange: (e) => {
5842                    const newId = e.target.value;
5843                    const oldId = selectedClothingDef.id;
5844                    if (newId === oldId) return;
5845                    setClothingConfigs((prev) => {
5846                      const newConfigs = { ...prev };
5847                      newConfigs[newId] = { ...newConfigs[oldId], id: newId };
5848                      delete newConfigs[oldId];
5849                      return newConfigs;
5850                    });
5851                    setSelectedClothingId(newId);
5852                  },
5853                  className: "w-full bg-black border border-zinc-700 rounded p-2 text-white"
5854                }
5855              )
5856            ] }),
5857            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 mt-8", children: [
5858              /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-white border-b border-zinc-800 pb-2", children: "Clothing Parts (SVGs)" }),
5859              ["head", "body", "upper_arm_l", "lower_arm_l", "hand_l", "upper_arm_r", "lower_arm_r", "hand_r", "leg_l", "foot_l", "leg_r", "foot_r"].map((part) => {
5860                var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2;
5861                const isExpanded = !!expandedClothingParts[part];
5862                const classSuffix = getDisplayClassName(part);
5863                const isEmpty = !selectedClothingDef || !selectedClothingDef.parts[part];
5864                const isSelected = selectedPartId === part;
5865                return /* @__PURE__ */ jsxRuntimeExports.jsxs(
5866                  "div",
5867                  {
5868                    onClick: () => setSelectedPartId(part),
5869                    className: `transition-all duration-200 border rounded p-3 flex flex-col gap-2 cursor-pointer ${isSelected ? "bg-indigo-950/20 border-indigo-500 ring-1 ring-indigo-500/50 shadow-[0_0_8px_rgba(99,102,241,0.2)]" : "bg-black border border-zinc-800 hover:border-zinc-700"}`,
5870                    children: [
5871                      /* @__PURE__ */ jsxRuntimeExports.jsxs(
5872                        "div",
5873                        {
5874                          className: "flex items-center justify-between cursor-pointer select-none",
5875                          onClick: (e) => {
5876                            setSelectedPartId(part);
5877                            setExpandedClothingParts((prev) => ({ ...prev, [part]: !prev[part] }));
5878                          },
5879                          children: [
5880                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
5881                              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 text-[10px] w-3 inline-block", children: isExpanded ? "▼" : "▶" }),
5882                              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `block text-xs uppercase tracking-wider cursor-pointer ${isEmpty ? "text-zinc-500 opacity-60" : "font-bold text-indigo-400"}`, children: [
5883                                part,
5884                                classSuffix
5885                              ] })
5886                            ] }),
5887                            /* @__PURE__ */ jsxRuntimeExports.jsxs(
5888                              "label",
5889                              {
5890                                onClick: (e) => e.stopPropagation(),
5891                                className: "cursor-pointer flex items-center gap-1 text-[10px] px-2 py-0.5 bg-zinc-850 hover:bg-zinc-800 border border-zinc-700 text-zinc-300 rounded transition-colors",
5892                                children: [
5893                                  /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 10 }),
5894                                  " Upload SVG",
5895                                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", accept: ".svg", className: "hidden", onChange: (e) => {
5896                                    var _a3;
5897                                    pushUndo();
5898                                    const file = (_a3 = e.target.files) == null ? void 0 : _a3[0];
5899                                    if (!file) return;
5900                                    const reader = new FileReader();
5901                                    reader.onload = (event) => {
5902                                      var _a4;
5903                                      try {
5904                                        const content = (_a4 = event.target) == null ? void 0 : _a4.result;
5905                                        if (!content.includes("<svg") || !content.includes("</svg>")) {
5906                                          alert("Invalid SVG file format");
5907                                          return;
5908                                        }
5909                                        const match = content.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i);
5910                                        const svgInner = match ? match[1] : content;
5911                                        setClothingConfigs((prev) => ({
5912                                          ...prev,
5913                                          [selectedClothingDef.id]: {
5914                                            ...selectedClothingDef,
5915                                            parts: {
5916                                              ...selectedClothingDef.parts,
5917                                              [part]: svgInner
5918                                            }
5919                                          }
5920                                        }));
5921                                      } catch (err) {
5922                                        alert("Failed to parse SVG file");
5923                                      }
5924                                    };
5925                                    reader.readAsText(file);
5926                                  } })
5927                                ]
5928                              }
5929                            )
5930                          ]
5931                        }
5932                      ),
5933                      isExpanded && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
5934                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick: (e) => e.stopPropagation(), className: "bg-zinc-900 border border-zinc-800 p-2.5 rounded flex flex-col gap-2 animate-fadeIn cursor-default", children: [
5935                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between border-b border-zinc-800 pb-1.5 mb-1.5", children: [
5936                            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-zinc-400 uppercase", children: "Positioning & Alignment" }),
5937                            /* @__PURE__ */ jsxRuntimeExports.jsxs(
5938                              "select",
5939                              {
5940                                value: ((_b2 = (_a2 = selectedClothingDef.gluing) == null ? void 0 : _a2[part]) == null ? void 0 : _b2.type) || "none",
5941                                onChange: (e) => {
5942                                  var _a3;
5943                                  pushUndo();
5944                                  const val = e.target.value;
5945                                  const currentGluing = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "none", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "shoulder_l", t2: "elbow_l" };
5946                                  setClothingConfigs((prev) => ({
5947                                    ...prev,
5948                                    [selectedClothingDef.id]: {
5949                                      ...selectedClothingDef,
5950                                      gluing: {
5951                                        ...selectedClothingDef.gluing,
5952                                        [part]: { ...currentGluing, type: val }
5953                                      }
5954                                    }
5955                                  }));
5956                                },
5957                                className: "bg-black border border-zinc-700 rounded px-1.5 py-0.5 text-[9px] text-zinc-300",
5958                                children: [
5959                                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "Standard Offset" }),
5960                                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "one-point", children: "1-Point Glue" }),
5961                                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "two-point", children: "2-Point Glue (Stretch)" })
5962                                ]
5963                              }
5964                            )
5965                          ] }),
5966                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-5 gap-2", children: [
5967                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5968                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Scale X" }),
5969                              /* @__PURE__ */ jsxRuntimeExports.jsx(
5970                                "input",
5971                                {
5972                                  type: "number",
5973                                  step: "0.1",
5974                                  value: ((_d2 = (_c2 = selectedClothingDef.transforms) == null ? void 0 : _c2[part]) == null ? void 0 : _d2.scaleX) ?? 1,
5975                                  onChange: (e) => {
5976                                    var _a3;
5977                                    pushUndo();
5978                                    const val = parseFloat(e.target.value);
5979                                    const currentTransform = ((_a3 = selectedClothingDef.transforms) == null ? void 0 : _a3[part]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
5980                                    setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, transforms: { ...selectedClothingDef.transforms, [part]: { ...currentTransform, scaleX: val } } } }));
5981                                  },
5982                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
5983                                }
5984                              )
5985                            ] }),
5986                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5987                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Scale Y" }),
5988                              /* @__PURE__ */ jsxRuntimeExports.jsx(
5989                                "input",
5990                                {
5991                                  type: "number",
5992                                  step: "0.1",
5993                                  value: ((_f2 = (_e2 = selectedClothingDef.transforms) == null ? void 0 : _e2[part]) == null ? void 0 : _f2.scaleY) ?? 1,
5994                                  onChange: (e) => {
5995                                    var _a3;
5996                                    pushUndo();
5997                                    const val = parseFloat(e.target.value);
5998                                    const currentTransform = ((_a3 = selectedClothingDef.transforms) == null ? void 0 : _a3[part]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
5999                                    setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, transforms: { ...selectedClothingDef.transforms, [part]: { ...currentTransform, scaleY: val } } } }));
6000                                  },
6001                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
6002                                }
6003                              )
6004                            ] }),
6005                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6006                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Offset X" }),
6007                              /* @__PURE__ */ jsxRuntimeExports.jsx(
6008                                "input",
6009                                {
6010                                  type: "number",
6011                                  value: ((_h2 = (_g2 = selectedClothingDef.transforms) == null ? void 0 : _g2[part]) == null ? void 0 : _h2.x) ?? 0,
6012                                  onChange: (e) => {
6013                                    var _a3;
6014                                    pushUndo();
6015                                    const val = parseFloat(e.target.value) || 0;
6016                                    const currentTransform = ((_a3 = selectedClothingDef.transforms) == null ? void 0 : _a3[part]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
6017                                    setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, transforms: { ...selectedClothingDef.transforms, [part]: { ...currentTransform, x: val } } } }));
6018                                  },
6019                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
6020                                }
6021                              )
6022                            ] }),
6023                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6024                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Offset Y" }),
6025                              /* @__PURE__ */ jsxRuntimeExports.jsx(
6026                                "input",
6027                                {
6028                                  type: "number",
6029                                  value: ((_j2 = (_i2 = selectedClothingDef.transforms) == null ? void 0 : _i2[part]) == null ? void 0 : _j2.y) ?? 0,
6030                                  onChange: (e) => {
6031                                    var _a3;
6032                                    pushUndo();
6033                                    const val = parseFloat(e.target.value) || 0;
6034                                    const currentTransform = ((_a3 = selectedClothingDef.transforms) == null ? void 0 : _a3[part]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
6035                                    setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, transforms: { ...selectedClothingDef.transforms, [part]: { ...currentTransform, y: val } } } }));
6036                                  },
6037                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
6038                                }
6039                              )
6040                            ] }),
6041                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6042                              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] text-zinc-500 uppercase", children: "Rotation (deg)" }),
6043                              /* @__PURE__ */ jsxRuntimeExports.jsx(
6044                                "input",
6045                                {
6046                                  type: "number",
6047                                  value: ((_l2 = (_k2 = selectedClothingDef.transforms) == null ? void 0 : _k2[part]) == null ? void 0 : _l2.rotation) ?? 0,
6048                                  onChange: (e) => {
6049                                    var _a3;
6050                                    pushUndo();
6051                                    const val = parseFloat(e.target.value) || 0;
6052                                    const currentTransform = ((_a3 = selectedClothingDef.transforms) == null ? void 0 : _a3[part]) || { x: 0, y: 0, scaleX: 1, scaleY: 1, rotation: 0 };
6053                                    setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, transforms: { ...selectedClothingDef.transforms, [part]: { ...currentTransform, rotation: val } } } }));
6054                                  },
6055                                  className: "w-full bg-black border border-zinc-700 rounded p-1 text-white text-[10px]"
6056                                }
6057                              )
6058                            ] })
6059                          ] }),
6060                          ((_n2 = (_m2 = selectedClothingDef.gluing) == null ? void 0 : _m2[part]) == null ? void 0 : _n2.type) && ((_p2 = (_o2 = selectedClothingDef.gluing) == null ? void 0 : _o2[part]) == null ? void 0 : _p2.type) !== "none" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs bg-black/40 p-2 rounded mt-2", children: [
6061                            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
6062                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[9px] text-zinc-500 font-bold uppercase flex items-center justify-between", children: [
6063                                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Point 1 (Start Anchor)" }),
6064                                /* @__PURE__ */ jsxRuntimeExports.jsx(
6065                                  "button",
6066                                  {
6067                                    type: "button",
6068                                    onClick: () => setEditMode(editMode === `clothing_plug_p1_${part}` ? "none" : `clothing_plug_p1_${part}`),
6069                                    className: `px-1 py-0.5 rounded text-[8px] border transition-colors ${editMode === `clothing_plug_p1_${part}` ? "bg-emerald-600 border-emerald-500 text-white font-bold" : "bg-zinc-850 border-zinc-700 text-zinc-400 hover:text-white"}`,
6070                                    children: "🎯 Pin"
6071                                  }
6072                                )
6073                              ] }),
6074                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-1.5", children: [
6075                                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6076                                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Local X" }),
6077                                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6078                                    "input",
6079                                    {
6080                                      type: "number",
6081                                      value: ((_s2 = (_r2 = (_q2 = selectedClothingDef.gluing) == null ? void 0 : _q2[part]) == null ? void 0 : _r2.p1) == null ? void 0 : _s2.x) ?? 0,
6082                                      onChange: (e) => {
6083                                        var _a3;
6084                                        const val = parseFloat(e.target.value) || 0;
6085                                        const cg = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "one-point", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "body", t2: "body" };
6086                                        setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, gluing: { ...selectedClothingDef.gluing, [part]: { ...cg, p1: { ...cg.p1 || { y: 0 }, x: val } } } } }));
6087                                      },
6088                                      className: "w-full bg-black border border-zinc-700 rounded p-0.5 text-white text-[10px]"
6089                                    }
6090                                  )
6091                                ] }),
6092                                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6093                                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Local Y" }),
6094                                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6095                                    "input",
6096                                    {
6097                                      type: "number",
6098                                      value: ((_v2 = (_u2 = (_t2 = selectedClothingDef.gluing) == null ? void 0 : _t2[part]) == null ? void 0 : _u2.p1) == null ? void 0 : _v2.y) ?? 0,
6099                                      onChange: (e) => {
6100                                        var _a3;
6101                                        const val = parseFloat(e.target.value) || 0;
6102                                        const cg = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "one-point", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "body", t2: "body" };
6103                                        setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, gluing: { ...selectedClothingDef.gluing, [part]: { ...cg, p1: { ...cg.p1 || { x: 0 }, y: val } } } } }));
6104                                      },
6105                                      className: "w-full bg-black border border-zinc-700 rounded p-0.5 text-white text-[10px]"
6106                                    }
6107                                  )
6108                                ] })
6109                              ] }),
6110                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6111                                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Target Joint 1" }),
6112                                /* @__PURE__ */ jsxRuntimeExports.jsx(
6113                                  "select",
6114                                  {
6115                                    value: ((_x2 = (_w2 = selectedClothingDef.gluing) == null ? void 0 : _w2[part]) == null ? void 0 : _x2.t1) || "body",
6116                                    onChange: (e) => {
6117                                      var _a3;
6118                                      const val = e.target.value;
6119                                      const cg = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "one-point", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "body", t2: "body" };
6120                                      setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, gluing: { ...selectedClothingDef.gluing, [part]: { ...cg, t1: val } } } }));
6121                                    },
6122                                    className: "w-full bg-black border border-zinc-700 rounded p-0.5 text-white text-[10px]",
6123                                    children: ["head", "body", "shoulder_l", "elbow_l", "hand_l", "shoulder_r", "elbow_r", "hand_r", "leg_l", "foot_l", "leg_r", "foot_r"].map((j) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: j, children: j }, j))
6124                                  }
6125                                )
6126                              ] })
6127                            ] }),
6128                            ((_z2 = (_y2 = selectedClothingDef.gluing) == null ? void 0 : _y2[part]) == null ? void 0 : _z2.type) === "two-point" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 border-l border-zinc-800 pl-3", children: [
6129                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[9px] text-zinc-500 font-bold uppercase flex items-center justify-between", children: [
6130                                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Point 2 (End Anchor)" }),
6131                                /* @__PURE__ */ jsxRuntimeExports.jsx(
6132                                  "button",
6133                                  {
6134                                    type: "button",
6135                                    onClick: () => setEditMode(editMode === `clothing_plug_p2_${part}` ? "none" : `clothing_plug_p2_${part}`),
6136                                    className: `px-1 py-0.5 rounded text-[8px] border transition-colors ${editMode === `clothing_plug_p2_${part}` ? "bg-emerald-600 border-emerald-500 text-white font-bold" : "bg-zinc-850 border-zinc-700 text-zinc-400 hover:text-white"}`,
6137                                    children: "🎯 Pin"
6138                                  }
6139                                )
6140                              ] }),
6141                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-1.5", children: [
6142                                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6143                                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Local X" }),
6144                                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6145                                    "input",
6146                                    {
6147                                      type: "number",
6148                                      value: ((_C2 = (_B2 = (_A2 = selectedClothingDef.gluing) == null ? void 0 : _A2[part]) == null ? void 0 : _B2.p2) == null ? void 0 : _C2.x) ?? 0,
6149                                      onChange: (e) => {
6150                                        var _a3;
6151                                        const val = parseFloat(e.target.value) || 0;
6152                                        const cg = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "two-point", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "body", t2: "body" };
6153                                        setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, gluing: { ...selectedClothingDef.gluing, [part]: { ...cg, p2: { ...cg.p2 || { y: 0 }, x: val } } } } }));
6154                                      },
6155                                      className: "w-full bg-black border border-zinc-700 rounded p-0.5 text-white text-[10px]"
6156                                    }
6157                                  )
6158                                ] }),
6159                                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6160                                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Local Y" }),
6161                                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6162                                    "input",
6163                                    {
6164                                      type: "number",
6165                                      value: ((_F2 = (_E2 = (_D2 = selectedClothingDef.gluing) == null ? void 0 : _D2[part]) == null ? void 0 : _E2.p2) == null ? void 0 : _F2.y) ?? 40,
6166                                      onChange: (e) => {
6167                                        var _a3;
6168                                        const val = parseFloat(e.target.value) || 0;
6169                                        const cg = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "two-point", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "body", t2: "body" };
6170                                        setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, gluing: { ...selectedClothingDef.gluing, [part]: { ...cg, p2: { ...cg.p2 || { x: 0 }, y: val } } } } }));
6171                                      },
6172                                      className: "w-full bg-black border border-zinc-700 rounded p-0.5 text-white text-[10px]"
6173                                    }
6174                                  )
6175                                ] })
6176                              ] }),
6177                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6178                                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[8px] text-zinc-500 uppercase", children: "Target Joint 2" }),
6179                                /* @__PURE__ */ jsxRuntimeExports.jsx(
6180                                  "select",
6181                                  {
6182                                    value: ((_H2 = (_G2 = selectedClothingDef.gluing) == null ? void 0 : _G2[part]) == null ? void 0 : _H2.t2) || "elbow_l",
6183                                    onChange: (e) => {
6184                                      var _a3;
6185                                      const val = e.target.value;
6186                                      const cg = ((_a3 = selectedClothingDef.gluing) == null ? void 0 : _a3[part]) || { type: "two-point", p1: { x: 0, y: 0 }, p2: { x: 0, y: 40 }, t1: "body", t2: "body" };
6187                                      setClothingConfigs((prev) => ({ ...prev, [selectedClothingDef.id]: { ...selectedClothingDef, gluing: { ...selectedClothingDef.gluing, [part]: { ...cg, t2: val } } } }));
6188                                    },
6189                                    className: "w-full bg-black border border-zinc-700 rounded p-0.5 text-white text-[10px]",
6190                                    children: ["head", "body", "shoulder_l", "elbow_l", "hand_l", "shoulder_r", "elbow_r", "hand_r", "leg_l", "foot_l", "leg_r", "foot_r"].map((j) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: j, children: j }, j))
6191                                  }
6192                                )
6193                              ] })
6194                            ] })
6195                          ] })
6196                        ] }),
6197                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-4 mt-2", children: [
6198                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
6199                            "textarea",
6200                            {
6201                              value: selectedClothingDef.parts[part] || "",
6202                              onChange: (e) => {
6203                                setClothingConfigs((prev) => ({
6204                                  ...prev,
6205                                  [selectedClothingDef.id]: {
6206                                    ...selectedClothingDef,
6207                                    parts: {
6208                                      ...selectedClothingDef.parts,
6209                                      [part]: e.target.value
6210                                    }
6211                                  }
6212                                }));
6213                              },
6214                              placeholder: `<g class="clothing-${selectedClothingDef.id}-${part}">...</g>`,
6215                              className: "w-full h-24 bg-zinc-900 border border-zinc-700 rounded p-2 text-emerald-400 font-mono text-xs resize-y"
6216                            }
6217                          ) }),
6218                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-32 h-32 bg-zinc-900 border border-zinc-700 rounded flex items-center justify-center overflow-hidden shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "-50 -50 100 100", className: "w-full h-full overflow-visible", children: /* @__PURE__ */ jsxRuntimeExports.jsx("g", { dangerouslySetInnerHTML: { __html: selectedClothingDef.parts[part] || "" } }) }) })
6219                        ] })
6220                      ] })
6221                    ]
6222                  },
6223                  part
6224                );
6225              })
6226            ] })
6227          ] })
6228        ] }),
6229        activeTab === "actions" && (() => {
6230          const selAction = globalActions.find((a) => a.id === selectedActionId) || null;
6231          const selRule = globalActionRules.find((r) => r.id === selectedActionRuleId) || null;
6232          if (selAction) {
6233            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
6234              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
6235                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { value: selAction.name, onChange: (e) => updateBodyAction(selAction.id, { name: e.target.value }), className: "text-xl font-bold bg-transparent border-b border-zinc-700 text-white focus:outline-none focus:border-indigo-500 flex-1" }),
6236                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs bg-zinc-800 text-zinc-400 px-2 py-1 rounded font-mono", children: selAction.id })
6237              ] }),
6238              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
6239                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6240                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Trigger" }),
6241                  /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: selAction.trigger, onChange: (e) => updateBodyAction(selAction.id, { trigger: e.target.value }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5", children: [
6242                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "playing", children: "While Playing" }),
6243                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "idle", children: "While Idle" }),
6244                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "note_on", children: "On Note" }),
6245                    /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "always", children: "Always" })
6246                  ] })
6247                ] }),
6248                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6249                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Priority" }),
6250                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: selAction.priority, onChange: (e) => updateBodyAction(selAction.id, { priority: parseInt(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6251                ] }),
6252                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6253                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Duration (ms)" }),
6254                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: selAction.duration, onChange: (e) => updateBodyAction(selAction.id, { duration: parseInt(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6255                ] }),
6256                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
6257                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-300 cursor-pointer", children: [
6258                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: selAction.loop, onChange: (e) => updateBodyAction(selAction.id, { loop: e.target.checked }), className: "accent-indigo-500" }),
6259                    "Loop"
6260                  ] }),
6261                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-300 cursor-pointer", children: [
6262                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: selAction.tempoSync, onChange: (e) => updateBodyAction(selAction.id, { tempoSync: e.target.checked }), className: "accent-indigo-500" }),
6263                    "Tempo Sync"
6264                  ] })
6265                ] }),
6266                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6267                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Blend In (ms)" }),
6268                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: selAction.blendInMs, onChange: (e) => updateBodyAction(selAction.id, { blendInMs: parseInt(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6269                ] }),
6270                /* @__P
6270URE__ */ jsxRuntimeExports.jsxs("div", { children: [
6271                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Blend Out (ms)" }),
6272                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: selAction.blendOutMs, onChange: (e) => updateBodyAction(selAction.id, { blendOutMs: parseInt(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6273                ] })
6274              ] }),
6275              selAction.trigger === "idle" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4 bg-zinc-900 rounded p-4", children: [
6276                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6277                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Min Interval (ms)" }),
6278                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: selAction.minInterval ?? 1e4, onChange: (e) => updateBodyAction(selAction.id, { minInterval: parseInt(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6279                ] }),
6280                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6281                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Max Interval (ms)" }),
6282                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: selAction.maxInterval ?? 3e4, onChange: (e) => updateBodyAction(selAction.id, { maxInterval: parseInt(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6283                ] })
6284              ] }),
6285              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6286                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
6287                  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-zinc-300 uppercase tracking-widest", children: "Channels" }),
6288                  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () =>
6288 addBodyChannel(selAction.id), className: "text-xs text-indigo-400 hover:text-indigo-300 flex items-center gap-1", children: [
6289                    /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 12 }),
6290                    " Add Channel"
6291                  ] })
6292                ] }),
6293                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
6294                  selAction.channels.map((ch, idx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `border rounded-lg overflow-hidden ${selectedChannelIdx === idx ? "border-indigo-500" : "border-zinc-800"}`, children: [
6295                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick: () => setSelectedChannelIdx(selectedChannelIdx === idx ? null : idx), className: "flex items-center justify-between px-4 py-2.5 bg-zinc-900 cursor-pointer hover:bg-zinc-800", children: [
6296                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
6297                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs px-2 py-0.5 rounded font-mono ${ch.type === "wave" ? "bg-blue-900 text-blue-300" : "bg-purple-900 text-purple-300"}`, children: ch.type }),
6298                        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-zinc-200 font-medium", children: [
6299                          " ",
6300                          ch.joint
6301                        ] }),
6302                        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-zinc-500", children: [
6303                          ".",
6304                          ch.property
6305                        ] })
6306                      ] }),
6307                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
6308                        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
6309                          e.stopPropagation();
6310                          removeBodyChannel(selAction.id, idx);
6311                        }, className: "p-1 text-zinc-600 hover:text-red-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 12 }) }),
6312                        selectedChannelIdx === idx ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14, className: "text-zinc-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "text-zinc-500" })
6313                      ] })
6314                    ] }),
6315                    selectedChannelIdx === idx && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-950 space-y-4", children: [
6316                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-3 gap-3", children: [
6317                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6318                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Joint" }),
6319                          /* @__PURE__ */ jsxRuntimeExports.jsx("select", { value: ch.joint, onChange: (e) => updateBodyChannel(selAction.id, idx, { joint: e.target.value }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5", children: JOINTS_LIST.map((j) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: j, children: j }, j)) })
6320                        ] }),
6321                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6322                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Property" }),
6323                          /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: ch.property, onChange: (e) => updateBodyChannel(selAction.id, idx, { property: e.target.value }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5", children: [
6324                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "x", children: "x" }),
6325                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "y", children: "y" }),
6326                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "rotation", children: "rotation" })
6327                          ] })
6328                        ] }),
6329                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6330                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Type" }),
6331                          /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: ch.type, onChange: (e) => updateBodyChannel(selAction.id, idx, { type: e.target.value, keyframes: e.target.value === "keyframe" ? [{ time: 0, value: 0, easing: "sine" }, { time: 1, value: 0, easing: "sine" }] : void 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5", children: [
6332                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "wave", children: "Wave (formula)" }),
6333                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "keyframe", children: "Keyframe" })
6334                          ] })
6335                        ] })
6336                      ] }),
6337                      ch.type === "wave" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-3 gap-3", children: [
6338                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6339                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Waveform" }),
6340                          /* @__PURE__ */ jsxRuntimeExports.jsx("select", { value: ch.waveform ?? "sine", onChange: (e) => updateBodyChannel(selAction.id, idx, { waveform: e.target.value }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5", children: Object.entries(WAVEFORM_LABELS_MAP).map(([v, l]) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: v, children: l }, v)) })
6341                        ] }),
6342                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6343                          /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-xs text-zinc-500 block mb-1", children: [
6344                            "Frequency (",
6345                            selAction.tempoSync ? "cycles/beat" : "Hz",
6346                            ")"
6347                          ] }),
6348                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.01", value: ch.frequency ?? 1, onChange: (e) => updateBodyChannel(selAction.id, idx, { frequency: parseFloat(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6349                        ] }),
6350                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6351                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Phase (rad)" }),
6352                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.01", value: ch.phase ?? 0, onChange: (e) => updateBodyChannel(selAction.id, idx, { phase: parseFloat(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6353                        ] }),
6354                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6355                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Amplitude Base" }),
6356                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.1", value: ch.amplitudeBase ?? 0, onChange: (e) => updateBodyChannel(selAction.id, idx, { amplitudeBase: parseFloat(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6357                        ] }),
6358                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6359                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Amplitude (×intensity)" }),
6360                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.1", value: ch.amplitude ?? 1, onChange: (e) => updateBodyChannel(selAction.id, idx, { amplitude: parseFloat(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6361                        ] }),
6362                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6363                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Intensity Scale" }),
6364                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.1", min: "0", max: "1", value: ch.intensityScale ?? 0, onChange: (e) => updateBodyChannel(selAction.id, idx, { intensityScale: parseFloat(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6365                        ] }),
6366                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6367                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Offset" }),
6368                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.1", value: ch.offset ?? 0, onChange: (e) => updateBodyChannel(selAction.id, idx, { offset: parseFloat(e.target.value) || 0 }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5" })
6369                        ] }),
6370                        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "col-span-2 flex items-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-600 font-mono p-2 bg-zinc-900 rounded w-full", children: [
6371                          "result = ",
6372                          ch.waveform ?? "sin",
6373                          "(t × ",
6374                          ch.frequency ?? 1,
6375                          ") × (",
6376                          ch.amplitudeBase ?? 0,
6377                          " + ",
6378                          ch.amplitude ?? 1,
6379                          " × intensity) + ",
6380                          ch.offset ?? 0
6381                        ] }) })
6382                      ] }),
6383                      ch.type === "keyframe" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
6384                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
6385                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-500", children: "Keyframes" }),
6386                          /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => addBodyKeyframe(selAction.id, idx), className: "text-xs text-indigo-400 hover:text-indigo-300 flex items-center gap-1", children: [
6387                            /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 10 }),
6388                            " Add"
6389                          ] })
6390                        ] }),
6391                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-16 bg-zinc-900 rounded overflow-hidden border border-zinc-800", children: [
6392                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-x-2 top-1/2 h-px bg-zinc-700" }),
6393                          (ch.keyframes || []).map((kf, ki) => {
6394                            const maxV = Math.max(20, ...(ch.keyframes || []).map((k) => Math.abs(k.value)));
6395                            return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute w-3 h-3 rounded-full bg-indigo-400 border-2 border-white -translate-x-1/2 -translate-y-1/2 cursor-pointer", style: { left: `${kf.time * 100}%`, top: `${50 - kf.value / maxV * 45}%` }, title: `t=${kf.time}, v=${kf.value}` }, ki);
6396                          })
6397                        ] }),
6398                        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "max-h-40 overflow-y-auto space-y-1", children: (ch.keyframes || []).map((kf, ki) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
6399                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-600 w-4", children: ki }),
6400                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-500", children: "t=" }),
6401                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.01", min: "0", max: "1", value: kf.time, onChange: (e) => {
6402                            const nk = [...ch.keyframes || []];
6403                            nk[ki] = { ...nk[ki], time: parseFloat(e.target.value) || 0 };
6404                            updateBodyChannel(selAction.id, idx, { keyframes: nk.sort((a, b) => a.time - b.time) });
6405                          }, className: "w-16 bg-zinc-800 border border-zinc-700 text-zinc-200 rounded px-1 py-0.5" }),
6406                          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-zinc-500", children: "v=" }),
6407                          /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", step: "0.1", value: kf.value, onChange: (e) => {
6408                            const nk = [...ch.keyframes || []];
6409                            nk[ki] = { ...nk[ki], value: parseFloat(e.target.value) || 0 };
6410                            updateBodyChannel(selAction.id, idx, { keyframes: nk });
6411                          }, className: "w-16 bg-zinc-800 border border-zinc-700 text-zinc-200 rounded px-1 py-0.5" }),
6412                          /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: kf.easing ?? "sine", onChange: (e) => {
6413                            const nk = [...ch.keyframes || []];
6414                            nk[ki] = { ...nk[ki], easing: e.target.value };
6415                            updateBodyChannel(selAction.id, idx, { keyframes: nk });
6416                          }, className: "flex-1 bg-zinc-800 border border-zinc-700 text-zinc-200 rounded px-1 py-0.5", children: [
6417                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "linear", children: "Linear" }),
6418                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "sine", children: "Sine" }),
6419                            /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "ease-in-out", children: "Ease In-Out" })
6420                          ] }),
6421                          /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => {
6422                            updateBodyChannel(selAction.id, idx, { keyframes: (ch.keyframes || []).filter((_, i) => i !== ki) });
6423                          }, className: "text-zinc-600 hover:text-red-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 }) })
6424                        ] }, ki)) })
6425                      ] })
6426                    ] })
6427                  ] }, idx)),
6428                  selAction.channels.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-8 text-zinc-600 text-sm border border-dashed border-zinc-800 rounded-lg", children: "No channels yet. Add a channel to animate a joint." })
6429                ] })
6430              ] })
6431            ] });
6432          } else if (selRule) {
6433            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
6434              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
6435                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { value: selRule.name, onChange: (e) => updateBodyRule(selRule.id, { name: e.target.value }), className: "text-xl font-bold bg-transparent border-b border-zinc-700 text-white focus:outline-none focus:border-indigo-500 flex-1" }),
6436                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-300", children: [
6437                  /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: selRule.enabled, onChange: (e) => updateBodyRule(selRule.id, { enabled: e.target.checked }), className: "accent-indigo-500" }),
6438                  "Enabled"
6439                ] })
6440              ] }),
6441              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
6442                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6443                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-2", children: "Applies To" }),
6444                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: ["all", "family", "selected"].map((scope) => /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-300 cursor-pointer", children: [
6445                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "radio", name: `scope-${selRule.id}`, value: scope, checked: selRule.condition.scope === scope, onChange: () => updateBodyRule(selRule.id, { condition: { ...selRule.condition, scope } }), className: "accent-indigo-500" }),
6446                    scope === "all" ? "All Characters" : scope === "family" ? "Specific Families" : "Selected Characters"
6447                  ] }, scope)) }),
6448                  selRule.condition.scope === "family" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-3 space-y-1", children: ["percussion", "keys", "strings", "winds", "other"].map((fam) => /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-400 cursor-pointer", children: [
6449                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: (selRule.condition.families || []).includes(fam), onChange: (e) => {
6450                      const f = selRule.condition.families || [];
6451                      updateBodyRule(selRule.id, { condition: { ...selRule.condition, families: e.target.checked ? [...f, fam] : f.filter((x) => x !== fam) } });
6452                    }, className: "accent-indigo-500" }),
6453                    fam.charAt(0).toUpperCase() + fam.slice(1)
6454                  ] }, fam)) }),
6455                  selRule.condition.scope === "selected" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3", children: [
6456                    /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-1", children: "Character IDs (comma separated)" }),
6457                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "text", value: (selRule.condition.characterIds || []).join(", "), onChange: (e) => updateBodyRule(selRule.id, { condition: { ...selRule.condition, characterIds: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) } }), className: "w-full bg-zinc-800 border border-zinc-700 text-zinc-200 text-sm rounded px-2 py-1.5", placeholder: "e.g. family_5_strings" })
6458                  ] })
6459                ] }),
6460                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6461                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-500 block mb-2", children: "Actions to Apply" }),
6462                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 max-h-64 overflow-y-auto", children: globalActions.map((action) => /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-300 cursor-pointer p-1.5 rounded hover:bg-zinc-800", children: [
6463                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: selRule.actionIds.includes(action.id), onChange: (e) => {
6464                      const ids = selRule.actionIds;
6465                      updateBodyRule(selRule.id, { actionIds: e.target.checked ? [...ids, action.id] : ids.filter((id) => id !== action.id) });
6466                    }, className: "accent-indigo-500" }),
6467                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: action.name }),
6468                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-600 text-xs", children: [
6469                      "(",
6470                      TRIGGER_LABELS_MAP[action.trigger],
6471                      ")"
6472                    ] })
6473                  ] }, action.id)) })
6474                ] })
6475              ] })
6476            ] });
6477          } else {
6478            return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex items-center justify-center text-zinc-600 text-sm py-12", children: "Select an action or rule to edit it." });
6479          }
6480        })(),
6481        activeTab === "background" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
6482          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6483            /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-bold text-white mb-1", children: selectedPresetId === null ? "Global Default Background" : `Preset: ${(_w = backgroundPresets.find((p) => p.id === selectedPresetId)) == null ? void 0 : _w.name}` }),
6484            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 font-sans", children: selectedPresetId === null ? "Configure the global background used when no track tags match any presets." : "Configure this preset's background settings and matching tags." })
6485          ] }),
6486          selectedPresetId !== null && (() => {
6487            const preset = backgroundPresets.find((p) => p.id === selectedPresetId);
6488            if (!preset) return null;
6489            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 border border-zinc-800 p-4 rounded-lg space-y-2 animate-fadeIn", children: [
6490              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-300 font-bold uppercase tracking-wider block", children: "Matching Tags (comma separated)" }),
6491              /* @__PURE__ */ jsxRuntimeExports.jsx(
6492                "input",
6493                {
6494                  type: "text",
6495                  value: preset.tags.join(", "),
6496                  onChange: (e) => {
6497                    const newTags = e.target.value.split(",").map((t) => t.trim()).filter(Boolean);
6498                    pushUndo();
6499                    setBackgroundPresets((prev) => prev.map((p) => {
6500                      if (p.id === selectedPresetId) {
6501                        return { ...p, tags: newTags };
6502                      }
6503                      return p;
6504                    }));
6505                  },
6506                  className: "w-full bg-zinc-900 border border-zinc-700 text-zinc-300 text-xs px-2.5 py-1.5 rounded",
6507                  placeholder: "e.g. classical, orchestra, piano"
6508                }
6509              ),
6510              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 font-sans", children: "Tracks with tags matching any of these terms will automatically load this background." })
6511            ] });
6512          })(),
6513          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
6514            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-400 font-bold uppercase tracking-wider block", children: "Background Type" }),
6515            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 gap-1.5 bg-zinc-950 p-1 rounded border border-zinc-800", children: ["color", "gradient", "image"].map((type) => /* @__PURE__ */ jsxRuntimeExports.jsx(
6516              "button",
6517              {
6518                onClick: () => {
6519                  updateActiveConfig((prev) => ({ ...prev, type }));
6520                },
6521                className: `py-1.5 text-xs font-bold rounded capitalize transition-all ${currentConfigToEdit.type === type ? "bg-indigo-600 text-white shadow-md" : "text-zinc-400 hover:text-zinc-200"}`,
6522                children: type
6523              },
6524              type
6525            )) })
6526          ] }),
6527          currentConfigToEdit.type === "color" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-zinc-950 border border-zinc-800 p-4 rounded-lg space-y-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
6528            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-300 font-medium", children: "Solid Background Color" }),
6529            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
6530              /* @__PURE__ */ jsxRuntimeExports.jsx(
6531                "input",
6532                {
6533                  type: "color",
6534                  value: currentConfigToEdit.color || "#0c0c14",
6535                  onChange: (e) => {
6536                    updateActiveConfig((prev) => ({ ...prev, color: e.target.value }));
6537                  },
6538                  className: "w-8 h-8 rounded border border-zinc-700 bg-transparent cursor-pointer"
6539                }
6540              ),
6541              /* @__PURE__ */ jsxRuntimeExports.jsx(
6542                "input",
6543                {
6544                  type: "text",
6545                  value: currentConfigToEdit.color || "#0c0c14",
6546                  onChange: (e) => {
6547                    updateActiveConfig((prev) => ({ ...prev, color: e.target.value }));
6548                  },
6549                  className: "w-24 bg-zinc-900 border border-zinc-700 text-zinc-300 text-xs px-2 py-1.5 rounded font-mono"
6550                }
6551              )
6552            ] })
6553          ] }) }),
6554          currentConfigToEdit.type === "gradient" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 border border-zinc-800 p-4 rounded-lg space-y-4", children: [
6555            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
6556              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6557                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block mb-1", children: "Shape" }),
6558                /* @__PURE__ */ jsxRuntimeExports.jsxs(
6559                  "select",
6560                  {
6561                    value: ((_x = currentConfigToEdit.gradient) == null ? void 0 : _x.type) || "linear",
6562                    onChange: (e) => {
6563                      updateActiveConfig((prev) => ({
6564                        ...prev,
6565                        gradient: { ...prev.gradient, type: e.target.value }
6566                      }));
6567                    },
6568                    className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1.5 text-zinc-300 text-xs",
6569                    children: [
6570                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "linear", children: "Linear" }),
6571                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "radial", children: "Radial" })
6572                    ]
6573                  }
6574                )
6575              ] }),
6576              ((_y = currentConfigToEdit.gradient) == null ? void 0 : _y.type) === "linear" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6577                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block mb-1", children: [
6578                  "Angle (",
6579                  ((_z = currentConfigToEdit.gradient) == null ? void 0 : _z.angle) || 0,
6580                  "°)"
6581                ] }),
6582                /* @__PURE__ */ jsxRuntimeExports.jsx(
6583                  "input",
6584                  {
6585                    type: "range",
6586                    min: "0",
6587                    max: "360",
6588                    value: ((_A = currentConfigToEdit.gradient) == null ? void 0 : _A.angle) || 0,
6589                    onChange: (e) => {
6590                      updateActiveConfig((prev) => ({
6591                        ...prev,
6592                        gradient: { ...prev.gradient, angle: parseInt(e.target.value) || 0 }
6593                      }));
6594                    },
6595                    className: "w-full accent-indigo-500 h-1.5 rounded-lg bg-zinc-800 cursor-pointer"
6596                  }
6597                )
6598              ] })
6599            ] }),
6600            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
6601              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
6602                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-300 font-medium", children: "Color Stops" }),
6603                /* @__PURE__ */ jsxRuntimeExports.jsxs(
6604                  "button",
6605                  {
6606                    onClick: () => {
6607                      updateActiveConfig((prev) => {
6608                        var _a2;
6609                        const stops = ((_a2 = prev.gradient) == null ? void 0 : _a2.stops) || [];
6610                        const newOffset = stops.length > 0 ? Math.min(100, stops[stops.length - 1].offset + 20) : 50;
6611                        return {
6612                          ...prev,
6613                          gradient: {
6614                            ...prev.gradient,
6615                            stops: [...stops, { color: "#4f46e5", offset: newOffset }]
6616                          }
6617                        };
6618                      });
6619                    },
6620                    className: "text-xs text-indigo-400 hover:text-indigo-300 flex items-center gap-1 font-bold",
6621                    children: [
6622                      /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 12 }),
6623                      " Add Stop"
6624                    ]
6625                  }
6626                )
6627              ] }),
6628              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 max-h-48 overflow-y-auto pr-1", children: (_C = (_B = currentConfigToEdit.gradient) == null ? void 0 : _B.stops) == null ? void 0 : _C.map((stop, idx) => {
6629                var _a2;
6630                return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between bg-zinc-900 border border-zinc-850 p-2 rounded gap-2 animate-fadeIn", children: [
6631                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6632                    "input",
6633                    {
6634                      type: "color",
6635                      value: stop.color,
6636                      onChange: (e) => {
6637                        updateActiveConfig((prev) => {
6638                          var _a3;
6639                          const stops = [...((_a3 = prev.gradient) == null ? void 0 : _a3.stops) || []];
6640                          stops[idx] = { ...stops[idx], color: e.target.value };
6641                          return { ...prev, gradient: { ...prev.gradient, stops } };
6642                        });
6643                      },
6644                      className: "w-6 h-6 rounded border border-zinc-700 bg-transparent cursor-pointer"
6645                    }
6646                  ),
6647                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex items-center gap-2", children: [
6648                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-zinc-500 font-mono w-8", children: [
6649                      stop.offset,
6650                      "%"
6651                    ] }),
6652                    /* @__PURE__ */ jsxRuntimeExports.jsx(
6653                      "input",
6654                      {
6655                        type: "range",
6656                        min: "0",
6657                        max: "100",
6658                        value: stop.offset,
6659                        onChange: (e) => {
6660                          updateActiveConfig((prev) => {
6661                            var _a3;
6662                            const stops = [...((_a3 = prev.gradient) == null ? void 0 : _a3.stops) || []];
6663                            stops[idx] = { ...stops[idx], offset: parseInt(e.target.value) || 0 };
6664                            return { ...prev, gradient: { ...prev.gradient, stops } };
6665                          });
6666                        },
6667                        className: "flex-1 accent-indigo-500 h-1 rounded-lg bg-zinc-800 cursor-pointer"
6668                      }
6669                    )
6670                  ] }),
6671                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6672                    "button",
6673                    {
6674                      onClick: () => {
6675                        updateActiveConfig((prev) => {
6676                          var _a3;
6677                          const stops = (((_a3 = prev.gradient) == null ? void 0 : _a3.stops) || []).filter((_, i) => i !== idx);
6678                          return { ...prev, gradient: { ...prev.gradient, stops } };
6679                        });
6680                      },
6681                      disabled: (((_a2 = currentConfigToEdit.gradient) == null ? void 0 : _a2.stops) || []).length <= 2,
6682                      className: "text-zinc-500 hover:text-red-400 disabled:opacity-30 disabled:hover:text-zinc-500 transition-colors",
6683                      children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 12 })
6684                    }
6685                  )
6686                ] }, idx);
6687              }) })
6688            ] })
6689          ] }),
6690          currentConfigToEdit.type === "image" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 border border-zinc-800 p-4 rounded-lg space-y-4", children: [
6691            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
6692              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block", children: "Image URL / Path" }),
6693              /* @__PURE__ */ jsxRuntimeExports.jsx(
6694                "input",
6695                {
6696                  type: "text",
6697                  value: ((_D = currentConfigToEdit.image) == null ? void 0 : _D.url) || "",
6698                  onChange: (e) => {
6699                    updateActiveConfig((prev) => ({
6700                      ...prev,
6701                      image: { ...prev.image, url: e.target.value }
6702                    }));
6703                  },
6704                  className: "w-full bg-zinc-900 border border-zinc-700 text-zinc-350 text-xs px-2.5 py-1.5 rounded",
6705                  placeholder: "e.g. /assets/visualizers/orchestra/background-forest.webp"
6706                }
6707              )
6708            ] }),
6709            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 pt-1 border-t border-zinc-900", children: [
6710              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
6711                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block", children: "Or Upload Default Background" }),
6712                uploadError && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-red-400 font-sans", children: uploadError })
6713              ] }),
6714              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
6715                /* @__PURE__ */ jsxRuntimeExports.jsx(
6716                  "input",
6717                  {
6718                    type: "file",
6719                    accept: "image/png, image/jpeg, image/jpg, image/webp",
6720                    onChange: handleGlobalBgUpload,
6721                    className: "hidden",
6722                    id: "global-bg-upload-input"
6723                  }
6724                ),
6725                /* @__PURE__ */ jsxRuntimeExports.jsxs(
6726                  "label",
6727                  {
6728                    htmlFor: "global-bg-upload-input",
6729                    className: "flex items-center gap-1 px-2.5 py-1.5 bg-indigo-600 hover:bg-indigo-750 text-white rounded text-[11px] font-bold cursor-pointer transition-colors shadow-sm",
6730                    children: [
6731                      /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 12 }),
6732                      " Upload Image"
6733                    ]
6734                  }
6735                ),
6736                ((_E = currentConfigToEdit.image) == null ? void 0 : _E.url) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-zinc-500 font-mono truncate max-w-xs block", children: [
6737                  "Current: ",
6738                  currentConfigToEdit.image.url.split("/").pop()
6739                ] })
6740              ] })
6741            ] }),
6742            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2 pt-2 border-t border-zinc-900", children: [
6743              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block", children: "Custom Background Options Gallery" }),
6744              customBackgrounds.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-600 text-[10px] italic p-3 text-center bg-zinc-900/50 rounded border border-zinc-850", children: "No custom backgrounds uploaded yet." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 gap-2.5 max-h-48 overflow-y-auto pr-1", children: customBackgrounds.map((bgUrl) => {
6745                var _a2;
6746                const isSelected = ((_a2 = currentConfigToEdit.image) == null ? void 0 : _a2.url) === bgUrl;
6747                return /* @__PURE__ */ jsxRuntimeExports.jsxs(
6748                  "div",
6749                  {
6750                    className: `relative group rounded overflow-hidden border cursor-pointer aspect-video bg-zinc-950 transition-all ${isSelected ? "border-indigo-500 shadow-[0_0_8px_rgba(99,102,241,0.4)]" : "border-zinc-800 hover:border-zinc-700"}`,
6751                    onClick: () => {
6752                      updateActiveConfig((prev) => ({
6753                        ...prev,
6754                        image: { ...prev.image, url: bgUrl }
6755                      }));
6756                    },
6757                    children: [
6758                      /* @__PURE__ */ jsxRuntimeExports.jsx(
6759                        "img",
6760                        {
6761                          src: bgUrl,
6762                          alt: "Custom background",
6763                          className: "w-full h-full object-cover"
6764                        }
6765                      ),
6766                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-1.5", children: [
6767                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-white font-bold bg-zinc-900/80 px-1 rounded", children: isSelected ? "Active" : "Select" }),
6768                        /* @__PURE__ */ jsxRuntimeExports.jsx(
6769                          "button",
6770                          {
6771                            onClick: (e) => {
6772                              e.stopPropagation();
6773                              handleDeleteGlobalBg(bgUrl);
6774                            },
6775                            className: "p-1 bg-red-600/90 text-white rounded hover:bg-red-700 transition-colors shadow",
6776                            title: "Delete from options",
6777                            children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
6778                          }
6779                        )
6780                      ] })
6781                    ]
6782                  },
6783                  bgUrl
6784                );
6785              }) })
6786            ] }),
6787            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
6788              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6789                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block mb-1", children: "Image Size" }),
6790                /* @__PURE__ */ jsxRuntimeExports.jsxs(
6791                  "select",
6792                  {
6793                    value: ((_F = currentConfigToEdit.image) == null ? void 0 : _F.size) || "cover",
6794                    onChange: (e) => {
6795                      updateActiveConfig((prev) => ({
6796                        ...prev,
6797                        image: { ...prev.image, size: e.target.value }
6798                      }));
6799                    },
6800                    className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1.5 text-zinc-300 text-xs",
6801                    children: [
6802                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "cover", children: "Cover (Fill)" }),
6803                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "contain", children: "Contain (Fit)" }),
6804                      /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "auto", children: "Auto (Original)" })
6805                    ]
6806                  }
6807                )
6808              ] }),
6809              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6810                /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block mb-1", children: [
6811                  "Blur (",
6812                  ((_G = currentConfigToEdit.image) == null ? void 0 : _G.blur) || 0,
6813                  "px)"
6814                ] }),
6815                /* @__PURE__ */ jsxRuntimeExports.jsx(
6816                  "input",
6817                  {
6818                    type: "range",
6819                    min: "0",
6820                    max: "20",
6821                    value: ((_H = currentConfigToEdit.image) == null ? void 0 : _H.blur) || 0,
6822                    onChange: (e) => {
6823                      updateActiveConfig((prev) => ({
6824                        ...prev,
6825                        image: { ...prev.image, blur: parseInt(e.target.value) || 0 }
6826                      }));
6827                    },
6828                    className: "w-full accent-indigo-500 h-1.5 rounded-lg bg-zinc-800 cursor-pointer"
6829                  }
6830                )
6831              ] })
6832            ] })
6833          ] }),
6834          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 border border-zinc-800 p-4 rounded-lg space-y-4", children: [
6835            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
6836              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
6837                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-200 font-bold uppercase tracking-wider font-sans", children: "Backdrop Overlay Tint" }),
6838                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500", children: "Darken or color-tint the background behind musicians." })
6839              ] }),
6840              /* @__PURE__ */ jsxRuntimeExports.jsx(
6841                "input",
6842                {
6843                  type: "checkbox",
6844                  checked: ((_I = currentConfigToEdit.overlay) == null ? void 0 : _I.enabled) || false,
6845                  onChange: (e) => {
6846                    updateActiveConfig((prev) => ({
6847                      ...prev,
6848                      overlay: { ...prev.overlay, enabled: e.target.checked }
6849                    }));
6850                  },
6851                  className: "accent-indigo-500 w-4 h-4 cursor-pointer"
6852                }
6853              )
6854            ] }),
6855            ((_J = currentConfigToEdit.overlay) == null ? void 0 : _J.enabled) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4 pt-2 border-t border-zinc-900 items-center", children: [
6856              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
6857                /* @__PURE__ */ jsxRuntimeExports.jsx(
6858                  "input",
6859                  {
6860                    type: "color",
6861                    value: ((_K = currentConfigToEdit.overlay) == null ? void 0 : _K.color) || "#000000",
6862                    onChange: (e) => {
6863                      updateActiveConfig((prev) => ({
6864                        ...prev,
6865                        overlay: { ...prev.overlay, color: e.target.value }
6866                      }));
6867                    },
6868                    className: "w-6 h-6 rounded border border-zinc-700 bg-transparent cursor-pointer animate-fadeIn"
6869                  }
6870                ),
6871                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-mono uppercase", children: (_L = currentConfigToEdit.overlay) == null ? void 0 : _L.color })
6872              ] }),
6873              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6874                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-zinc-500 mb-1", children: [
6875                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Opacity" }),
6876                  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
6877                    Math.round((((_M = currentConfigToEdit.overlay) == null ? void 0 : _M.opacity) || 0) * 100),
6878                    "%"
6879                  ] })
6880                ] }),
6881                /* @__PURE__ */ jsxRuntimeExports.jsx(
6882                  "input",
6883                  {
6884                    type: "range",
6885                    min: "0",
6886                    max: "1",
6887                    step: "0.05",
6888                    value: ((_N = currentConfigToEdit.overlay) == null ? void 0 : _N.opacity) || 0,
6889                    onChange: (e) => {
6890                      updateActiveConfig((prev) => ({
6891                        ...prev,
6892                        overlay: { ...prev.overlay, opacity: parseFloat(e.target.value) || 0 }
6893                      }));
6894                    },
6895                    className: "w-full accent-indigo-500 h-1.5 rounded-lg bg-zinc-800 cursor-pointer"
6896                  }
6897                )
6898              ] })
6899            ] })
6900          ] }),
6901          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-950 border border-zinc-800 p-4 rounded-lg space-y-4", children: [
6902            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
6903              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
6904                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-zinc-200 font-bold uppercase tracking-wider font-sans", children: "Dynamic Particles" }),
6905                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500", children: "Interactive background animations." })
6906              ] }),
6907              /* @__PURE__ */ jsxRuntimeExports.jsx(
6908                "input",
6909                {
6910                  type: "checkbox",
6911                  checked: ((_O = currentConfigToEdit.particles) == null ? void 0 : _O.enabled) || false,
6912                  onChange: (e) => {
6913                    updateActiveConfig((prev) => ({
6914                      ...prev,
6915                      particles: { ...prev.particles, enabled: e.target.checked }
6916                    }));
6917                  },
6918                  className: "accent-indigo-500 w-4 h-4 cursor-pointer"
6919                }
6920              )
6921            ] }),
6922            ((_P = currentConfigToEdit.particles) == null ? void 0 : _P.enabled) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3 pt-2 border-t border-zinc-900 animate-fadeIn", children: [
6923              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
6924                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6925                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block mb-1", children: "Particle Style" }),
6926                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
6927                    "select",
6928                    {
6929                      value: ((_Q = currentConfigToEdit.particles) == null ? void 0 : _Q.type) || "stars",
6930                      onChange: (e) => {
6931                        updateActiveConfig((prev) => ({
6932                          ...prev,
6933                          particles: { ...prev.particles, type: e.target.value }
6934                        }));
6935                      },
6936                      className: "w-full bg-zinc-900 border border-zinc-700 rounded p-1.5 text-zinc-350 text-xs",
6937                      children: [
6938                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "stars", children: "Twinkling Stars" }),
6939                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "notes", children: "Floating Notes" }),
6940                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "bubbles", children: "Rising Bubbles" }),
6941                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "snow", children: "Falling Snow" }),
6942                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "rain", children: "Rain" }),
6943                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "confetti", children: "Confetti" }),
6944                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "fireflies", children: "Fireflies" }),
6945                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "hearts", children: "Hearts" }),
6946                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "autumn_leaves", children: "Autumn Leaves" }),
6947                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "matrix", children: "Matrix Code" }),
6948                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "dust", children: "Dust Particles" }),
6949                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "sparkles", children: "Sparkles" }),
6950                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "floating_orbs", children: "Floating Orbs" }),
6951                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "laser_lines", children: "Laser Lines" })
6952                      ]
6953                    }
6954                  )
6955                ] }),
6956                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6957                  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-zinc-400 font-bold uppercase tracking-wider block mb-1", children: "Particle Color" }),
6958                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [
6959                    /* @__PURE__ */ jsxRuntimeExports.jsx(
6960                      "input",
6961                      {
6962                        type: "color",
6963                        value: ((_R = currentConfigToEdit.particles) == null ? void 0 : _R.color) || "#ffffff",
6964                        onChange: (e) => {
6965                          updateActiveConfig((prev) => ({
6966                            ...prev,
6967                            particles: { ...prev.particles, color: e.target.value }
6968                          }));
6969                        },
6970                        className: "w-6 h-6 rounded border border-zinc-700 bg-transparent cursor-pointer"
6971                      }
6972                    ),
6973                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-mono uppercase", children: (_S = currentConfigToEdit.particles) == null ? void 0 : _S.color })
6974                  ] })
6975                ] })
6976              ] }),
6977              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
6978                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
6979                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-zinc-500 mb-1", children: [
6980                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Count" }),
6981                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: ((_T = currentConfigToEdit.particles) == null ? void 0 : _T.count) || 50 })
6982                  ] }),
6983                  /* @__PURE__ */ jsxRuntimeExports.jsx(
6984                    "input",
6985                    {
6986                      type: "range",
6987                      min: "10",
6988                      max: "200",
6989                      step: "5",
6990                      value: ((_U = currentConfigToEdit.particles) == null ? void 0 : _U.count) || 50,
6991                      onChange: (e) => {
6992                        updateActiveConfig((prev) => ({
6993                          ...prev,
6994                          particles: { ...prev.particles, count: parseInt(e.target.value) || 50 }
6995                        }));
6996                      },
6997                      className: "w-full accent-indigo-500 h-1.5 rounded-lg bg-zinc-800 cursor-pointer"
6998                    }
6999                  )
7000                ] }),
7001                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
7002                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-zinc-500 mb-1", children: [
7003                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Speed" }),
7004                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
7005                      ((_V = currentConfigToEdit.particles) == null ? void 0 : _V.speed) || 1,
7006                      "x"
7007                    ] })
7008                  ] }),
7009                  /* @__PURE__ */ jsxRuntimeExports.jsx(
7010                    "input",
7011                    {
7012                      type: "range",
7013                      min: "0.1",
7014                      max: "5",
7015                      step: "0.1",
7016                      value: ((_W = currentConfigToEdit.particles) == null ? void 0 : _W.speed) || 1,
7017                      onChange: (e) => {
7018                        updateActiveConfig((prev) => ({
7019                          ...prev,
7020                          particles: { ...prev.particles, speed: parseFloat(e.target.value) || 1 }
7021                        }));
7022                      },
7023                      className: "w-full accent-indigo-500 h-1.5 rounded-lg bg-zinc-800 cursor-pointer"
7024                    }
7025                  )
7026                ] }),
7027                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
7028                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-zinc-500 mb-1", children: [
7029                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Size" }),
7030                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
7031                      ((_X = currentConfigToEdit.particles) == null ? void 0 : _X.size) || 2,
7032                      "px"
7033                    ] })
7034                  ] }),
7035                  /* @__PURE__ */ jsxRuntimeExports.jsx(
7036                    "input",
7037                    {
7038                      type: "range",
7039                      min: "1",
7040                      max: "10",
7041                      step: "0.5",
7042                      value: ((_Y = currentConfigToEdit.particles) == null ? void 0 : _Y.size) || 2,
7043                      onChange: (e) => {
7044                        updateActiveConfig((prev) => ({
7045                          ...prev,
7046                          particles: { ...prev.particles, size: parseFloat(e.target.value) || 2 }
7047                        }));
7048                      },
7049                      className: "w-full accent-indigo-500 h-1.5 rounded-lg bg-zinc-800 cursor-pointer"
7050                    }
7051                  )
7052                ] })
7053              ] })
7054            ] })
7055          ] }),
7056          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pt-4 border-t border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
7057            "button",
7058            {
7059              onClick: handleSave,
7060              className: "w-full py-2.5 bg-indigo-650 hover:bg-indigo-600 text-white text-sm font-bold rounded-lg transition-colors flex items-center justify-center gap-2 shadow-md shadow-indigo-650/10",
7061              children: [
7062                /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
7063                " Save Background Config"
7064              ]
7065            }
7066          ) })
7067        ] }),
7068        !selectedConfig && activeTab === "characters" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex items-center justify-center text-zinc-600", children: "Select a puppet configuration to edit" })
7069      ] }),
7070      showRiggingBuilder && /* @__PURE__ */ jsxRuntimeExports.jsx(
7071        RiggingBuilder,
7072        {
7073          existingSvg: selectedConfig == null ? void 0 : selectedConfig.svgContent,
7074          onClose: () => setShowRiggingBuilder(false),
7075          onApplySvg: (svgContent) => {
7076            if (!selectedId) {
7077              const id = `new_puppet_${Date.now()}`;
7078              const defaultCfg = Object.values(defaultPuppetConfigs)[0];
7079              setConfigs((prev) => ({ ...prev, [id]: { ...defaultCfg, id, name: "Rigged Character", svgContent } }));
7080              setSelectedId(id);
7081            } else {
7082              handleConfigChange(selectedId, { svgContent });
7083            }
7084            setShowRiggingBuilder(false);
7085          }
7086        }
7087      )
7088    ] })
7089  ] });
7090}
7091export {
7092  PuppetStudio as default
7093};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.