@downcity/ui 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -29,6 +39,17 @@ __export(index_exports, {
29
39
  CardFooter: () => CardFooter,
30
40
  CardHeader: () => CardHeader,
31
41
  CardTitle: () => CardTitle,
42
+ Checkbox: () => Checkbox,
43
+ Dialog: () => Dialog,
44
+ DialogClose: () => DialogClose,
45
+ DialogContent: () => DialogContent,
46
+ DialogDescription: () => DialogDescription,
47
+ DialogFooter: () => DialogFooter,
48
+ DialogHeader: () => DialogHeader,
49
+ DialogOverlay: () => DialogOverlay,
50
+ DialogPortal: () => DialogPortal,
51
+ DialogTitle: () => DialogTitle,
52
+ DialogTrigger: () => DialogTrigger,
32
53
  DropdownMenu: () => DropdownMenu,
33
54
  DropdownMenuCheckboxItem: () => DropdownMenuCheckboxItem,
34
55
  DropdownMenuContent: () => DropdownMenuContent,
@@ -44,13 +65,43 @@ __export(index_exports, {
44
65
  DropdownMenuSubContent: () => DropdownMenuSubContent,
45
66
  DropdownMenuSubTrigger: () => DropdownMenuSubTrigger,
46
67
  DropdownMenuTrigger: () => DropdownMenuTrigger,
68
+ Input: () => Input,
69
+ Label: () => Label,
47
70
  Popover: () => Popover,
48
71
  PopoverContent: () => PopoverContent,
49
72
  PopoverTrigger: () => PopoverTrigger,
73
+ Separator: () => Separator,
74
+ Sheet: () => Sheet,
75
+ SheetClose: () => SheetClose,
76
+ SheetContent: () => SheetContent,
77
+ SheetDescription: () => SheetDescription,
78
+ SheetFooter: () => SheetFooter,
79
+ SheetHeader: () => SheetHeader,
80
+ SheetOverlay: () => SheetOverlay,
81
+ SheetPortal: () => SheetPortal,
82
+ SheetTitle: () => SheetTitle,
83
+ SheetTrigger: () => SheetTrigger,
84
+ Skeleton: () => Skeleton,
85
+ Tabs: () => Tabs,
86
+ TabsContent: () => TabsContent,
87
+ TabsList: () => TabsList,
88
+ TabsTrigger: () => TabsTrigger,
89
+ Textarea: () => Textarea,
50
90
  Toaster: () => Toaster,
91
+ Toggle: () => Toggle,
92
+ ToggleGroup: () => ToggleGroup,
93
+ ToggleGroupItem: () => ToggleGroupItem,
94
+ Tooltip: () => Tooltip,
95
+ TooltipContent: () => TooltipContent,
96
+ TooltipProvider: () => TooltipProvider,
97
+ TooltipTrigger: () => TooltipTrigger,
98
+ Workboard: () => Workboard,
51
99
  badgeVariants: () => badgeVariants,
100
+ buildWorkboardGameMapConfig: () => buildWorkboardGameMapConfig,
52
101
  buttonVariants: () => buttonVariants,
53
- cn: () => cn
102
+ cn: () => cn,
103
+ tabsListVariants: () => tabsListVariants,
104
+ toggleVariants: () => toggleVariants
54
105
  });
55
106
  module.exports = __toCommonJS(index_exports);
56
107
 
@@ -250,18 +301,183 @@ function CardFooter({ className, ...props }) {
250
301
  );
251
302
  }
252
303
 
253
- // src/components/dropdown-menu.tsx
254
- var import_menu = require("@base-ui/react/menu");
304
+ // src/components/checkbox.tsx
305
+ var import_checkbox = require("@base-ui/react/checkbox");
255
306
  var import_lucide_react = require("lucide-react");
256
307
  var import_jsx_runtime3 = require("react/jsx-runtime");
308
+ function Checkbox({ className, ...props }) {
309
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
310
+ import_checkbox.Checkbox.Root,
311
+ {
312
+ "data-slot": "checkbox",
313
+ className: cn(
314
+ "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
315
+ className
316
+ ),
317
+ ...props,
318
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
319
+ import_checkbox.Checkbox.Indicator,
320
+ {
321
+ "data-slot": "checkbox-indicator",
322
+ className: "grid place-content-center text-current transition-none [&>svg]:size-3.5",
323
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.CheckIcon, {})
324
+ }
325
+ )
326
+ }
327
+ );
328
+ }
329
+
330
+ // src/components/dialog.tsx
331
+ var import_dialog = require("@base-ui/react/dialog");
332
+ var import_lucide_react2 = require("lucide-react");
333
+ var import_jsx_runtime4 = require("react/jsx-runtime");
334
+ function Dialog(props) {
335
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dialog.Dialog.Root, { "data-slot": "dialog", ...props });
336
+ }
337
+ function DialogTrigger(props) {
338
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dialog.Dialog.Trigger, { "data-slot": "dialog-trigger", ...props });
339
+ }
340
+ function DialogPortal(props) {
341
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dialog.Dialog.Portal, { "data-slot": "dialog-portal", ...props });
342
+ }
343
+ function DialogClose(props) {
344
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dialog.Dialog.Close, { "data-slot": "dialog-close", ...props });
345
+ }
346
+ function DialogOverlay({ className, ...props }) {
347
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
348
+ import_dialog.Dialog.Backdrop,
349
+ {
350
+ "data-slot": "dialog-overlay",
351
+ className: cn(
352
+ "fixed inset-0 z-50 bg-black/20 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
353
+ className
354
+ ),
355
+ ...props
356
+ }
357
+ );
358
+ }
359
+ function DialogContent({
360
+ className,
361
+ children,
362
+ showCloseButton = true,
363
+ ...props
364
+ }) {
365
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(DialogPortal, { children: [
366
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DialogOverlay, {}),
367
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
368
+ import_dialog.Dialog.Popup,
369
+ {
370
+ "data-slot": "dialog-content",
371
+ className: cn(
372
+ "fixed top-1/2 left-1/2 z-50 w-[min(92vw,760px)] max-h-[86vh] -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-[24px] bg-card text-sm shadow-[0_22px_70px_rgba(15,23,42,0.12)] transition duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0 data-ending-style:scale-[0.985] data-starting-style:scale-[0.985]",
373
+ className
374
+ ),
375
+ ...props,
376
+ children: [
377
+ children,
378
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
379
+ import_dialog.Dialog.Close,
380
+ {
381
+ "data-slot": "dialog-close",
382
+ render: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { size: "icon-sm", variant: "ghost", className: "absolute top-3 right-3" }),
383
+ children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.XIcon, {}),
385
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "sr-only", children: "Close" })
386
+ ]
387
+ }
388
+ ) : null
389
+ ]
390
+ }
391
+ )
392
+ ] });
393
+ }
394
+ function DialogHeader({ className, ...props }) {
395
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
396
+ "div",
397
+ {
398
+ "data-slot": "dialog-header",
399
+ className: cn("flex flex-col gap-0.5 p-4 pr-12", className),
400
+ ...props
401
+ }
402
+ );
403
+ }
404
+ function DialogFooter({ className, ...props }) {
405
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
406
+ "div",
407
+ {
408
+ "data-slot": "dialog-footer",
409
+ className: cn("flex items-center justify-end gap-2 p-4", className),
410
+ ...props
411
+ }
412
+ );
413
+ }
414
+ function DialogTitle({ className, ...props }) {
415
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
416
+ import_dialog.Dialog.Title,
417
+ {
418
+ "data-slot": "dialog-title",
419
+ className: cn("text-base font-medium text-foreground", className),
420
+ ...props
421
+ }
422
+ );
423
+ }
424
+ function DialogDescription({ className, ...props }) {
425
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
426
+ import_dialog.Dialog.Description,
427
+ {
428
+ "data-slot": "dialog-description",
429
+ className: cn("text-sm text-muted-foreground", className),
430
+ ...props
431
+ }
432
+ );
433
+ }
434
+
435
+ // src/components/input.tsx
436
+ var import_input = require("@base-ui/react/input");
437
+ var import_jsx_runtime5 = require("react/jsx-runtime");
438
+ function Input({ className, type, ...props }) {
439
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
440
+ import_input.Input,
441
+ {
442
+ type,
443
+ "data-slot": "input",
444
+ className: cn(
445
+ "h-9 w-full min-w-0 rounded-[12px] border border-transparent bg-secondary/85 px-3 py-2 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:bg-secondary focus-visible:ring-3 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/45 disabled:opacity-50 aria-invalid:bg-destructive/5 aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
446
+ className
447
+ ),
448
+ ...props
449
+ }
450
+ );
451
+ }
452
+
453
+ // src/components/label.tsx
454
+ var import_jsx_runtime6 = require("react/jsx-runtime");
455
+ function Label({ className, ...props }) {
456
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
457
+ "label",
458
+ {
459
+ "data-slot": "label",
460
+ className: cn(
461
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
462
+ className
463
+ ),
464
+ ...props
465
+ }
466
+ );
467
+ }
468
+
469
+ // src/components/dropdown-menu.tsx
470
+ var import_menu = require("@base-ui/react/menu");
471
+ var import_lucide_react3 = require("lucide-react");
472
+ var import_jsx_runtime7 = require("react/jsx-runtime");
257
473
  function DropdownMenu({ ...props }) {
258
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
474
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
259
475
  }
260
476
  function DropdownMenuPortal({ ...props }) {
261
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Portal, { "data-slot": "dropdown-menu-portal", ...props });
477
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.Portal, { "data-slot": "dropdown-menu-portal", ...props });
262
478
  }
263
479
  function DropdownMenuTrigger({ ...props }) {
264
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
480
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
265
481
  }
266
482
  function DropdownMenuContent({
267
483
  align = "start",
@@ -271,7 +487,7 @@ function DropdownMenuContent({
271
487
  className,
272
488
  ...props
273
489
  }) {
274
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
490
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
275
491
  import_menu.Menu.Positioner,
276
492
  {
277
493
  className: "isolate z-50 outline-none",
@@ -279,7 +495,7 @@ function DropdownMenuContent({
279
495
  alignOffset,
280
496
  side,
281
497
  sideOffset,
282
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
498
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
283
499
  import_menu.Menu.Popup,
284
500
  {
285
501
  "data-slot": "dropdown-menu-content",
@@ -294,14 +510,14 @@ function DropdownMenuContent({
294
510
  ) });
295
511
  }
296
512
  function DropdownMenuGroup({ ...props }) {
297
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
513
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
298
514
  }
299
515
  function DropdownMenuLabel({
300
516
  className,
301
517
  inset,
302
518
  ...props
303
519
  }) {
304
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
520
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
305
521
  import_menu.Menu.GroupLabel,
306
522
  {
307
523
  "data-slot": "dropdown-menu-label",
@@ -320,7 +536,7 @@ function DropdownMenuItem({
320
536
  variant = "default",
321
537
  ...props
322
538
  }) {
323
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
539
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
324
540
  import_menu.Menu.Item,
325
541
  {
326
542
  "data-slot": "dropdown-menu-item",
@@ -335,7 +551,7 @@ function DropdownMenuItem({
335
551
  );
336
552
  }
337
553
  function DropdownMenuSub({ ...props }) {
338
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.SubmenuRoot, { "data-slot": "dropdown-menu-sub", ...props });
554
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.SubmenuRoot, { "data-slot": "dropdown-menu-sub", ...props });
339
555
  }
340
556
  function DropdownMenuSubTrigger({
341
557
  className,
@@ -343,7 +559,7 @@ function DropdownMenuSubTrigger({
343
559
  children,
344
560
  ...props
345
561
  }) {
346
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
562
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
347
563
  import_menu.Menu.SubmenuTrigger,
348
564
  {
349
565
  "data-slot": "dropdown-menu-sub-trigger",
@@ -355,7 +571,7 @@ function DropdownMenuSubTrigger({
355
571
  ...props,
356
572
  children: [
357
573
  children,
358
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.ChevronRightIcon, { className: "ml-auto" })
574
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.ChevronRightIcon, { className: "ml-auto" })
359
575
  ]
360
576
  }
361
577
  );
@@ -368,7 +584,7 @@ function DropdownMenuSubContent({
368
584
  className,
369
585
  ...props
370
586
  }) {
371
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
587
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
372
588
  DropdownMenuContent,
373
589
  {
374
590
  "data-slot": "dropdown-menu-sub-content",
@@ -391,7 +607,7 @@ function DropdownMenuCheckboxItem({
391
607
  inset,
392
608
  ...props
393
609
  }) {
394
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
610
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
395
611
  import_menu.Menu.CheckboxItem,
396
612
  {
397
613
  "data-slot": "dropdown-menu-checkbox-item",
@@ -403,12 +619,12 @@ function DropdownMenuCheckboxItem({
403
619
  checked,
404
620
  ...props,
405
621
  children: [
406
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
622
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
407
623
  "span",
408
624
  {
409
625
  className: "pointer-events-none absolute right-2 flex items-center justify-center",
410
626
  "data-slot": "dropdown-menu-checkbox-item-indicator",
411
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.CheckIcon, {}) })
627
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.CheckIcon, {}) })
412
628
  }
413
629
  ),
414
630
  children
@@ -417,7 +633,7 @@ function DropdownMenuCheckboxItem({
417
633
  );
418
634
  }
419
635
  function DropdownMenuRadioGroup({ ...props }) {
420
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.RadioGroup, { "data-slot": "dropdown-menu-radio-group", ...props });
636
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.RadioGroup, { "data-slot": "dropdown-menu-radio-group", ...props });
421
637
  }
422
638
  function DropdownMenuRadioItem({
423
639
  className,
@@ -425,7 +641,7 @@ function DropdownMenuRadioItem({
425
641
  inset,
426
642
  ...props
427
643
  }) {
428
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
644
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
429
645
  import_menu.Menu.RadioItem,
430
646
  {
431
647
  "data-slot": "dropdown-menu-radio-item",
@@ -436,12 +652,12 @@ function DropdownMenuRadioItem({
436
652
  ),
437
653
  ...props,
438
654
  children: [
439
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
655
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
440
656
  "span",
441
657
  {
442
658
  className: "pointer-events-none absolute right-2 flex items-center justify-center",
443
659
  "data-slot": "dropdown-menu-radio-item-indicator",
444
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.RadioItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.CheckIcon, {}) })
660
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_menu.Menu.RadioItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.CheckIcon, {}) })
445
661
  }
446
662
  ),
447
663
  children
@@ -453,7 +669,7 @@ function DropdownMenuSeparator({
453
669
  className,
454
670
  ...props
455
671
  }) {
456
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
672
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
457
673
  import_menu.Menu.Separator,
458
674
  {
459
675
  "data-slot": "dropdown-menu-separator",
@@ -466,7 +682,7 @@ function DropdownMenuShortcut({
466
682
  className,
467
683
  ...props
468
684
  }) {
469
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
685
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
470
686
  "span",
471
687
  {
472
688
  "data-slot": "dropdown-menu-shortcut",
@@ -481,12 +697,12 @@ function DropdownMenuShortcut({
481
697
 
482
698
  // src/components/popover.tsx
483
699
  var import_popover = require("@base-ui/react/popover");
484
- var import_jsx_runtime4 = require("react/jsx-runtime");
700
+ var import_jsx_runtime8 = require("react/jsx-runtime");
485
701
  function Popover({ ...props }) {
486
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_popover.Popover.Root, { "data-slot": "popover", ...props });
702
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_popover.Popover.Root, { "data-slot": "popover", ...props });
487
703
  }
488
704
  function PopoverTrigger({ ...props }) {
489
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_popover.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
705
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_popover.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
490
706
  }
491
707
  function PopoverContent({
492
708
  className,
@@ -496,7 +712,7 @@ function PopoverContent({
496
712
  alignOffset = 0,
497
713
  ...props
498
714
  }) {
499
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_popover.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
715
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_popover.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
500
716
  import_popover.Popover.Positioner,
501
717
  {
502
718
  side,
@@ -504,7 +720,7 @@ function PopoverContent({
504
720
  align,
505
721
  alignOffset,
506
722
  className: "isolate z-50",
507
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
723
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
508
724
  import_popover.Popover.Popup,
509
725
  {
510
726
  "data-slot": "popover-content",
@@ -519,21 +735,259 @@ function PopoverContent({
519
735
  ) });
520
736
  }
521
737
 
738
+ // src/components/separator.tsx
739
+ var import_separator = require("@base-ui/react/separator");
740
+ var import_jsx_runtime9 = require("react/jsx-runtime");
741
+ function Separator({
742
+ className,
743
+ orientation = "horizontal",
744
+ ...props
745
+ }) {
746
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
747
+ import_separator.Separator,
748
+ {
749
+ "data-slot": "separator",
750
+ orientation,
751
+ className: cn(
752
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
753
+ className
754
+ ),
755
+ ...props
756
+ }
757
+ );
758
+ }
759
+
760
+ // src/components/sheet.tsx
761
+ var import_dialog2 = require("@base-ui/react/dialog");
762
+ var import_lucide_react4 = require("lucide-react");
763
+ var import_jsx_runtime10 = require("react/jsx-runtime");
764
+ function Sheet({ ...props }) {
765
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dialog2.Dialog.Root, { "data-slot": "sheet", ...props });
766
+ }
767
+ function SheetTrigger({ ...props }) {
768
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dialog2.Dialog.Trigger, { "data-slot": "sheet-trigger", ...props });
769
+ }
770
+ function SheetClose({ ...props }) {
771
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dialog2.Dialog.Close, { "data-slot": "sheet-close", ...props });
772
+ }
773
+ function SheetPortal({ ...props }) {
774
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dialog2.Dialog.Portal, { "data-slot": "sheet-portal", ...props });
775
+ }
776
+ function SheetOverlay({ className, ...props }) {
777
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
778
+ import_dialog2.Dialog.Backdrop,
779
+ {
780
+ "data-slot": "sheet-overlay",
781
+ className: cn(
782
+ "fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
783
+ className
784
+ ),
785
+ ...props
786
+ }
787
+ );
788
+ }
789
+ function SheetContent({
790
+ className,
791
+ children,
792
+ side = "right",
793
+ showCloseButton = true,
794
+ ...props
795
+ }) {
796
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(SheetPortal, { children: [
797
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SheetOverlay, {}),
798
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
799
+ import_dialog2.Dialog.Popup,
800
+ {
801
+ "data-slot": "sheet-content",
802
+ "data-side": side,
803
+ className: cn(
804
+ "fixed z-50 flex flex-col gap-4 bg-background bg-clip-padding text-sm shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
805
+ className
806
+ ),
807
+ ...props,
808
+ children: [
809
+ children,
810
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
811
+ import_dialog2.Dialog.Close,
812
+ {
813
+ "data-slot": "sheet-close",
814
+ render: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { variant: "ghost", className: "absolute top-3 right-3", size: "icon-sm" }),
815
+ children: [
816
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.XIcon, {}),
817
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "sr-only", children: "Close" })
818
+ ]
819
+ }
820
+ ) : null
821
+ ]
822
+ }
823
+ )
824
+ ] });
825
+ }
826
+ function SheetHeader({ className, ...props }) {
827
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
828
+ "div",
829
+ {
830
+ "data-slot": "sheet-header",
831
+ className: cn("flex flex-col gap-0.5 p-4", className),
832
+ ...props
833
+ }
834
+ );
835
+ }
836
+ function SheetFooter({ className, ...props }) {
837
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
838
+ "div",
839
+ {
840
+ "data-slot": "sheet-footer",
841
+ className: cn("mt-auto flex flex-col gap-2 p-4", className),
842
+ ...props
843
+ }
844
+ );
845
+ }
846
+ function SheetTitle({ className, ...props }) {
847
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
848
+ import_dialog2.Dialog.Title,
849
+ {
850
+ "data-slot": "sheet-title",
851
+ className: cn("text-base font-medium text-foreground", className),
852
+ ...props
853
+ }
854
+ );
855
+ }
856
+ function SheetDescription({ className, ...props }) {
857
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
858
+ import_dialog2.Dialog.Description,
859
+ {
860
+ "data-slot": "sheet-description",
861
+ className: cn("text-sm text-muted-foreground", className),
862
+ ...props
863
+ }
864
+ );
865
+ }
866
+
867
+ // src/components/skeleton.tsx
868
+ var import_jsx_runtime11 = require("react/jsx-runtime");
869
+ function Skeleton({ className, ...props }) {
870
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
871
+ "div",
872
+ {
873
+ "data-slot": "skeleton",
874
+ className: cn("animate-pulse rounded-md bg-muted", className),
875
+ ...props
876
+ }
877
+ );
878
+ }
879
+
880
+ // src/components/tabs.tsx
881
+ var import_tabs = require("@base-ui/react/tabs");
882
+ var import_class_variance_authority3 = require("class-variance-authority");
883
+ var import_jsx_runtime12 = require("react/jsx-runtime");
884
+ function Tabs({
885
+ className,
886
+ orientation = "horizontal",
887
+ ...props
888
+ }) {
889
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
890
+ import_tabs.Tabs.Root,
891
+ {
892
+ "data-slot": "tabs",
893
+ "data-orientation": orientation,
894
+ className: cn("group/tabs flex gap-2 data-horizontal:flex-col", className),
895
+ ...props
896
+ }
897
+ );
898
+ }
899
+ var tabsListVariants = (0, import_class_variance_authority3.cva)(
900
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
901
+ {
902
+ variants: {
903
+ variant: {
904
+ default: "bg-muted",
905
+ line: "gap-1 bg-transparent"
906
+ }
907
+ },
908
+ defaultVariants: {
909
+ variant: "default"
910
+ }
911
+ }
912
+ );
913
+ function TabsList({
914
+ className,
915
+ variant = "default",
916
+ ...props
917
+ }) {
918
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
919
+ import_tabs.Tabs.List,
920
+ {
921
+ "data-slot": "tabs-list",
922
+ "data-variant": variant,
923
+ className: cn(tabsListVariants({ variant }), className),
924
+ ...props
925
+ }
926
+ );
927
+ }
928
+ function TabsTrigger({ className, ...props }) {
929
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
930
+ import_tabs.Tabs.Tab,
931
+ {
932
+ "data-slot": "tabs-trigger",
933
+ className: cn(
934
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
935
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
936
+ "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
937
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
938
+ className
939
+ ),
940
+ ...props
941
+ }
942
+ );
943
+ }
944
+ function TabsContent({ className, ...props }) {
945
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
946
+ import_tabs.Tabs.Panel,
947
+ {
948
+ "data-slot": "tabs-content",
949
+ className: cn("flex-1 text-sm outline-none", className),
950
+ ...props
951
+ }
952
+ );
953
+ }
954
+
955
+ // src/components/textarea.tsx
956
+ var React = __toESM(require("react"), 1);
957
+ var import_jsx_runtime13 = require("react/jsx-runtime");
958
+ var Textarea = React.forwardRef(
959
+ ({ className, ...props }, ref) => {
960
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
961
+ "textarea",
962
+ {
963
+ ref,
964
+ "data-slot": "textarea",
965
+ className: cn(
966
+ "flex min-h-[96px] w-full rounded-[16px] border border-transparent bg-secondary/85 px-3 py-2.5 text-sm outline-none transition placeholder:text-muted-foreground focus-visible:bg-secondary focus-visible:ring-3 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-55",
967
+ className
968
+ ),
969
+ ...props
970
+ }
971
+ );
972
+ }
973
+ );
974
+ Textarea.displayName = "Textarea";
975
+
522
976
  // src/components/sonner.tsx
523
- var import_lucide_react2 = require("lucide-react");
977
+ var import_lucide_react5 = require("lucide-react");
524
978
  var import_sonner = require("sonner");
525
- var import_jsx_runtime5 = require("react/jsx-runtime");
979
+ var import_jsx_runtime14 = require("react/jsx-runtime");
526
980
  function Toaster({ ...props }) {
527
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
981
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
528
982
  import_sonner.Toaster,
529
983
  {
530
984
  className: "toaster group",
531
985
  icons: {
532
- success: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.CircleCheckIcon, { className: "size-4" }),
533
- info: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.InfoIcon, { className: "size-4" }),
534
- warning: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.TriangleAlertIcon, { className: "size-4" }),
535
- error: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.OctagonXIcon, { className: "size-4" }),
536
- loading: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react2.Loader2Icon, { className: "size-4 animate-spin" })
986
+ success: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.CircleCheckIcon, { className: "size-4" }),
987
+ info: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.InfoIcon, { className: "size-4" }),
988
+ warning: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.TriangleAlertIcon, { className: "size-4" }),
989
+ error: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.OctagonXIcon, { className: "size-4" }),
990
+ loading: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Loader2Icon, { className: "size-4 animate-spin" })
537
991
  },
538
992
  style: {
539
993
  "--normal-bg": "var(--popover)",
@@ -550,6 +1004,3382 @@ function Toaster({ ...props }) {
550
1004
  }
551
1005
  );
552
1006
  }
1007
+
1008
+ // src/components/toggle.tsx
1009
+ var import_toggle = require("@base-ui/react/toggle");
1010
+ var import_class_variance_authority4 = require("class-variance-authority");
1011
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1012
+ var toggleVariants = (0, import_class_variance_authority4.cva)(
1013
+ "group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1014
+ {
1015
+ variants: {
1016
+ variant: {
1017
+ default: "bg-transparent",
1018
+ outline: "border border-input bg-transparent hover:bg-muted"
1019
+ },
1020
+ size: {
1021
+ default: "h-8 min-w-8 px-2",
1022
+ sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-1.5 text-[0.8rem]",
1023
+ lg: "h-9 min-w-9 px-2.5"
1024
+ }
1025
+ },
1026
+ defaultVariants: {
1027
+ variant: "default",
1028
+ size: "default"
1029
+ }
1030
+ }
1031
+ );
1032
+ function Toggle({
1033
+ className,
1034
+ variant = "default",
1035
+ size = "default",
1036
+ ...props
1037
+ }) {
1038
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1039
+ import_toggle.Toggle,
1040
+ {
1041
+ "data-slot": "toggle",
1042
+ className: cn(toggleVariants({ variant, size, className })),
1043
+ ...props
1044
+ }
1045
+ );
1046
+ }
1047
+
1048
+ // src/components/toggle-group.tsx
1049
+ var React2 = __toESM(require("react"), 1);
1050
+ var import_toggle2 = require("@base-ui/react/toggle");
1051
+ var import_toggle_group = require("@base-ui/react/toggle-group");
1052
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1053
+ var ToggleGroupContext = React2.createContext({
1054
+ size: "default",
1055
+ variant: "default",
1056
+ spacing: 0,
1057
+ orientation: "horizontal"
1058
+ });
1059
+ function ToggleGroup({
1060
+ className,
1061
+ variant,
1062
+ size,
1063
+ spacing = 0,
1064
+ orientation = "horizontal",
1065
+ children,
1066
+ ...props
1067
+ }) {
1068
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1069
+ import_toggle_group.ToggleGroup,
1070
+ {
1071
+ "data-slot": "toggle-group",
1072
+ "data-variant": variant,
1073
+ "data-size": size,
1074
+ "data-spacing": spacing,
1075
+ "data-orientation": orientation,
1076
+ style: { "--gap": spacing },
1077
+ className: cn(
1078
+ "group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-lg data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-vertical:flex-col data-vertical:items-stretch",
1079
+ className
1080
+ ),
1081
+ ...props,
1082
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleGroupContext.Provider, { value: { variant, size, spacing, orientation }, children })
1083
+ }
1084
+ );
1085
+ }
1086
+ function ToggleGroupItem({
1087
+ className,
1088
+ children,
1089
+ variant = "default",
1090
+ size = "default",
1091
+ ...props
1092
+ }) {
1093
+ const context = React2.useContext(ToggleGroupContext);
1094
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1095
+ import_toggle2.Toggle,
1096
+ {
1097
+ "data-slot": "toggle-group-item",
1098
+ "data-variant": context.variant || variant,
1099
+ "data-size": context.size || size,
1100
+ "data-spacing": context.spacing,
1101
+ className: cn(
1102
+ "shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t",
1103
+ toggleVariants({
1104
+ variant: context.variant || variant,
1105
+ size: context.size || size
1106
+ }),
1107
+ className
1108
+ ),
1109
+ ...props,
1110
+ children
1111
+ }
1112
+ );
1113
+ }
1114
+
1115
+ // src/components/tooltip.tsx
1116
+ var import_tooltip = require("@base-ui/react/tooltip");
1117
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1118
+ function TooltipProvider({
1119
+ delay = 0,
1120
+ ...props
1121
+ }) {
1122
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1123
+ import_tooltip.Tooltip.Provider,
1124
+ {
1125
+ "data-slot": "tooltip-provider",
1126
+ delay,
1127
+ ...props
1128
+ }
1129
+ );
1130
+ }
1131
+ function Tooltip({ ...props }) {
1132
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_tooltip.Tooltip.Root, { "data-slot": "tooltip", ...props });
1133
+ }
1134
+ function TooltipTrigger({ ...props }) {
1135
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_tooltip.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
1136
+ }
1137
+ function TooltipContent({
1138
+ className,
1139
+ side = "top",
1140
+ sideOffset = 4,
1141
+ align = "center",
1142
+ alignOffset = 0,
1143
+ children,
1144
+ ...props
1145
+ }) {
1146
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_tooltip.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1147
+ import_tooltip.Tooltip.Positioner,
1148
+ {
1149
+ align,
1150
+ alignOffset,
1151
+ side,
1152
+ sideOffset,
1153
+ className: "isolate z-50",
1154
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1155
+ import_tooltip.Tooltip.Popup,
1156
+ {
1157
+ "data-slot": "tooltip-content",
1158
+ className: cn(
1159
+ "z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
1160
+ className
1161
+ ),
1162
+ ...props,
1163
+ children: [
1164
+ children,
1165
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_tooltip.Tooltip.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" })
1166
+ ]
1167
+ }
1168
+ )
1169
+ }
1170
+ ) });
1171
+ }
1172
+
1173
+ // src/components/workboard.tsx
1174
+ var React7 = __toESM(require("react"), 1);
1175
+ var import_lucide_react7 = require("lucide-react");
1176
+
1177
+ // src/components/workboard-game-atlas.tsx
1178
+ var React4 = __toESM(require("react"), 1);
1179
+
1180
+ // src/components/workboard-stage-map.tsx
1181
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1182
+ var TILE_SIZE = 40;
1183
+ var GRID_COLS = 40;
1184
+ var GRID_ROWS = 24;
1185
+ var STAGE_WIDTH = TILE_SIZE * GRID_COLS;
1186
+ var STAGE_HEIGHT = TILE_SIZE * GRID_ROWS;
1187
+ var WORKBOARD_TOWN_PLAZA_POINT = { x: 800, y: 480 };
1188
+ var WORKBOARD_ZONE_GATE_POINTS = {
1189
+ engaged: { x: 560, y: 400 },
1190
+ steady: { x: 1040, y: 400 },
1191
+ quiet: { x: 560, y: 560 },
1192
+ drift: { x: 1040, y: 560 }
1193
+ };
1194
+ var WORKBOARD_ZONE_LAYOUT = {
1195
+ engaged: { x: 2.5, y: 12.5, w: 35, h: 29.167, hubX: 20, hubY: 27.083 },
1196
+ steady: { x: 62.5, y: 12.5, w: 35, h: 29.167, hubX: 80, hubY: 27.083 },
1197
+ quiet: { x: 2.5, y: 58.333, w: 35, h: 33.333, hubX: 20, hubY: 75 },
1198
+ drift: { x: 62.5, y: 58.333, w: 35, h: 33.333, hubX: 80, hubY: 75 }
1199
+ };
1200
+ var ZONE_PIXEL_PALETTE = {
1201
+ engaged: {
1202
+ fill: "rgba(195,230,214,0.9)",
1203
+ fillStrong: "rgba(126,190,162,0.96)",
1204
+ stroke: "rgba(39,110,80,0.95)",
1205
+ line: "rgba(52,144,111,0.78)",
1206
+ shadow: "rgba(37,86,66,0.24)"
1207
+ },
1208
+ steady: {
1209
+ fill: "rgba(225,235,184,0.92)",
1210
+ fillStrong: "rgba(186,207,103,0.96)",
1211
+ stroke: "rgba(112,132,38,0.92)",
1212
+ line: "rgba(145,161,63,0.72)",
1213
+ shadow: "rgba(98,112,35,0.2)"
1214
+ },
1215
+ quiet: {
1216
+ fill: "rgba(225,221,211,0.94)",
1217
+ fillStrong: "rgba(190,183,169,0.98)",
1218
+ stroke: "rgba(103,96,87,0.9)",
1219
+ line: "rgba(130,124,112,0.7)",
1220
+ shadow: "rgba(84,78,71,0.18)"
1221
+ },
1222
+ drift: {
1223
+ fill: "rgba(245,214,178,0.94)",
1224
+ fillStrong: "rgba(231,162,92,0.96)",
1225
+ stroke: "rgba(161,91,32,0.92)",
1226
+ line: "rgba(194,121,55,0.78)",
1227
+ shadow: "rgba(146,78,28,0.2)"
1228
+ }
1229
+ };
1230
+ var TOWN_PATH_TILES = [
1231
+ { col: 0, row: 10, cols: 40, rows: 4 },
1232
+ { col: 19, row: 0, cols: 2, rows: 24 },
1233
+ { col: 12, row: 7, cols: 7, rows: 2 },
1234
+ { col: 21, row: 7, cols: 7, rows: 2 },
1235
+ { col: 12, row: 15, cols: 7, rows: 2 },
1236
+ { col: 21, row: 15, cols: 7, rows: 2 }
1237
+ ];
1238
+ var TOWN_WATER_TILES = [
1239
+ { col: 0, row: 0, cols: 10, rows: 2 },
1240
+ { col: 30, row: 0, cols: 10, rows: 2 },
1241
+ { col: 0, row: 22, cols: 11, rows: 2 },
1242
+ { col: 29, row: 22, cols: 11, rows: 2 },
1243
+ { col: 0, row: 2, cols: 2, rows: 5 },
1244
+ { col: 38, row: 17, cols: 2, rows: 5 }
1245
+ ];
1246
+ var TOWN_FENCE_TILES = [
1247
+ { col: 2, row: 2, cols: 15, rows: 1 },
1248
+ { col: 23, row: 2, cols: 15, rows: 1 },
1249
+ { col: 2, row: 22, cols: 15, rows: 1 },
1250
+ { col: 23, row: 22, cols: 15, rows: 1 }
1251
+ ];
1252
+ var TOWN_BUILDINGS = [
1253
+ {
1254
+ col: 1,
1255
+ row: 3,
1256
+ cols: 14,
1257
+ rows: 7,
1258
+ zoneId: "engaged",
1259
+ floor: "rgba(230,199,170,0.98)",
1260
+ wall: "rgba(135,73,56,0.96)",
1261
+ entrance: "bottom",
1262
+ walls: [
1263
+ { col: 5, row: 3, cols: 1, rows: 7 },
1264
+ { col: 10, row: 3, cols: 1, rows: 7 },
1265
+ { col: 1, row: 6, cols: 14, rows: 1 }
1266
+ ],
1267
+ props: [
1268
+ { col: 2, row: 4, cols: 1, rows: 1, kind: "desk" },
1269
+ { col: 7, row: 4, cols: 2, rows: 1, kind: "shelf" },
1270
+ { col: 12, row: 4, cols: 1, rows: 1, kind: "desk" },
1271
+ { col: 2, row: 8, cols: 2, rows: 1, kind: "table" },
1272
+ { col: 7, row: 8, cols: 1, rows: 1, kind: "sofa" },
1273
+ { col: 12, row: 8, cols: 1, rows: 1, kind: "sofa" }
1274
+ ]
1275
+ },
1276
+ {
1277
+ col: 25,
1278
+ row: 3,
1279
+ cols: 14,
1280
+ rows: 7,
1281
+ zoneId: "steady",
1282
+ floor: "rgba(244,236,174,0.98)",
1283
+ wall: "rgba(118,95,68,0.96)",
1284
+ entrance: "bottom",
1285
+ walls: [
1286
+ { col: 29, row: 3, cols: 1, rows: 7 },
1287
+ { col: 34, row: 3, cols: 1, rows: 7 },
1288
+ { col: 25, row: 6, cols: 14, rows: 1 }
1289
+ ],
1290
+ props: [
1291
+ { col: 26, row: 4, cols: 1, rows: 1, kind: "desk" },
1292
+ { col: 31, row: 4, cols: 2, rows: 1, kind: "shelf" },
1293
+ { col: 36, row: 4, cols: 1, rows: 1, kind: "desk" },
1294
+ { col: 26, row: 8, cols: 2, rows: 1, kind: "table" },
1295
+ { col: 31, row: 8, cols: 1, rows: 1, kind: "bed" },
1296
+ { col: 36, row: 8, cols: 1, rows: 1, kind: "sofa" }
1297
+ ]
1298
+ },
1299
+ {
1300
+ col: 1,
1301
+ row: 14,
1302
+ cols: 14,
1303
+ rows: 8,
1304
+ zoneId: "quiet",
1305
+ floor: "rgba(231,226,207,0.98)",
1306
+ wall: "rgba(116,107,97,0.96)",
1307
+ entrance: "top",
1308
+ walls: [
1309
+ { col: 5, row: 14, cols: 1, rows: 8 },
1310
+ { col: 10, row: 14, cols: 1, rows: 8 },
1311
+ { col: 1, row: 18, cols: 14, rows: 1 }
1312
+ ],
1313
+ props: [
1314
+ { col: 2, row: 15, cols: 1, rows: 1, kind: "bed" },
1315
+ { col: 7, row: 15, cols: 2, rows: 1, kind: "shelf" },
1316
+ { col: 12, row: 15, cols: 1, rows: 1, kind: "bed" },
1317
+ { col: 2, row: 20, cols: 2, rows: 1, kind: "table" },
1318
+ { col: 7, row: 20, cols: 1, rows: 1, kind: "sofa" },
1319
+ { col: 12, row: 20, cols: 1, rows: 1, kind: "sofa" }
1320
+ ]
1321
+ },
1322
+ {
1323
+ col: 25,
1324
+ row: 14,
1325
+ cols: 14,
1326
+ rows: 8,
1327
+ zoneId: "drift",
1328
+ floor: "rgba(244,211,166,0.98)",
1329
+ wall: "rgba(155,85,43,0.96)",
1330
+ entrance: "top",
1331
+ walls: [
1332
+ { col: 29, row: 14, cols: 1, rows: 8 },
1333
+ { col: 34, row: 14, cols: 1, rows: 8 },
1334
+ { col: 25, row: 18, cols: 14, rows: 1 }
1335
+ ],
1336
+ props: [
1337
+ { col: 26, row: 15, cols: 1, rows: 1, kind: "desk" },
1338
+ { col: 31, row: 15, cols: 2, rows: 1, kind: "shelf" },
1339
+ { col: 36, row: 15, cols: 1, rows: 1, kind: "desk" },
1340
+ { col: 26, row: 20, cols: 2, rows: 1, kind: "table" },
1341
+ { col: 31, row: 20, cols: 1, rows: 1, kind: "sofa" },
1342
+ { col: 36, row: 20, cols: 1, rows: 1, kind: "sofa" }
1343
+ ]
1344
+ }
1345
+ ];
1346
+ var TOWN_TREE_POINTS = [
1347
+ { col: 19, row: 2 },
1348
+ { col: 20, row: 21 },
1349
+ { col: 7, row: 2 },
1350
+ { col: 32, row: 2 },
1351
+ { col: 17, row: 4 },
1352
+ { col: 22, row: 4 },
1353
+ { col: 17, row: 19 },
1354
+ { col: 22, row: 19 }
1355
+ ];
1356
+ var TOWN_SHRUB_POINTS = [
1357
+ { col: 16, row: 8 },
1358
+ { col: 23, row: 8 },
1359
+ { col: 16, row: 15 },
1360
+ { col: 23, row: 15 },
1361
+ { col: 4, row: 2 },
1362
+ { col: 35, row: 2 },
1363
+ { col: 4, row: 22 },
1364
+ { col: 35, row: 22 }
1365
+ ];
1366
+ var TOWN_FLOWER_POINTS = [
1367
+ { col: 6, row: 11 },
1368
+ { col: 11, row: 12 },
1369
+ { col: 16, row: 9 },
1370
+ { col: 23, row: 14 },
1371
+ { col: 29, row: 11 },
1372
+ { col: 34, row: 12 },
1373
+ { col: 18, row: 5 },
1374
+ { col: 21, row: 18 },
1375
+ { col: 3, row: 21 },
1376
+ { col: 36, row: 2 }
1377
+ ];
1378
+ function tileToRect(tile) {
1379
+ return {
1380
+ x: tile.col * TILE_SIZE,
1381
+ y: tile.row * TILE_SIZE,
1382
+ width: tile.cols * TILE_SIZE,
1383
+ height: tile.rows * TILE_SIZE
1384
+ };
1385
+ }
1386
+ function estimateTextWidth(text) {
1387
+ return Array.from(text).reduce((acc, char) => acc + (char.charCodeAt(0) > 255 ? 9 : 6), 0);
1388
+ }
1389
+ function fitPixelLabel(text, maxWidth) {
1390
+ if (estimateTextWidth(text) <= maxWidth) return text;
1391
+ let current = "";
1392
+ for (const char of Array.from(text)) {
1393
+ const next = `${current}${char}`;
1394
+ if (estimateTextWidth(`${next}...`) > maxWidth) {
1395
+ return current.length > 0 ? `${current}...` : text;
1396
+ }
1397
+ current = next;
1398
+ }
1399
+ return current;
1400
+ }
1401
+ function TileRectSvg(props) {
1402
+ const rect2 = tileToRect(props.tile);
1403
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1404
+ "rect",
1405
+ {
1406
+ x: rect2.x,
1407
+ y: rect2.y,
1408
+ width: rect2.width,
1409
+ height: rect2.height,
1410
+ fill: props.fill,
1411
+ stroke: props.stroke,
1412
+ strokeWidth: props.stroke ? 2 : void 0,
1413
+ opacity: props.opacity
1414
+ }
1415
+ );
1416
+ }
1417
+ function renderGrassTiles() {
1418
+ return Array.from({ length: GRID_COLS * GRID_ROWS }, (_, index) => {
1419
+ const col = index % GRID_COLS;
1420
+ const row = Math.floor(index / GRID_COLS);
1421
+ const fill = (col + row) % 2 === 0 ? "rgba(104,136,76,0.98)" : "rgba(91,124,70,0.98)";
1422
+ const rect2 = tileToRect({ col, row, cols: 1, rows: 1 });
1423
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1424
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x, y: rect2.y, width: TILE_SIZE, height: TILE_SIZE, fill }),
1425
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 6, y: rect2.y + 8, width: "4", height: "4", fill: "rgba(40,78,45,0.26)" }),
1426
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 27, y: rect2.y + 25, width: "4", height: "4", fill: "rgba(142,161,89,0.18)" })
1427
+ ] }, `grass-${col}-${row}`);
1428
+ });
1429
+ }
1430
+ function renderTownPath(tile, index) {
1431
+ const rect2 = tileToRect(tile);
1432
+ const cobbles = Array.from({ length: tile.cols * tile.rows }, (_, cobbleIndex) => {
1433
+ const col = tile.col + cobbleIndex % tile.cols;
1434
+ const row = tile.row + Math.floor(cobbleIndex / tile.cols);
1435
+ const x = col * TILE_SIZE + ((col + row) % 2 === 0 ? 8 : 22);
1436
+ const y = row * TILE_SIZE + ((col * 3 + row) % 2 === 0 ? 10 : 24);
1437
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y, width: "8", height: "5", fill: "rgba(134,105,67,0.24)" }, `town-path-cobble-${index}-${cobbleIndex}`);
1438
+ });
1439
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1440
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: rect2.height, fill: "rgba(193,165,104,0.98)" }),
1441
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: "4", fill: "rgba(116,92,62,0.34)" }),
1442
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x, y: rect2.y + rect2.height - 4, width: rect2.width, height: "4", fill: "rgba(116,92,62,0.28)" }),
1443
+ cobbles
1444
+ ] }, `town-path-${index}`);
1445
+ }
1446
+ function renderTownWater(tile, index) {
1447
+ const rect2 = tileToRect(tile);
1448
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: rect2.height, fill: "rgba(82,139,149,0.9)" }),
1450
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 8, y: rect2.y + 10, width: Math.max(12, rect2.width - 16), height: "4", fill: "rgba(160,205,199,0.34)" }),
1451
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 18, y: rect2.y + rect2.height - 14, width: Math.max(18, rect2.width - 48), height: "4", fill: "rgba(53,103,112,0.24)" })
1452
+ ] }, `town-water-${index}`);
1453
+ }
1454
+ function renderTownFence(tile, index) {
1455
+ const rect2 = tileToRect(tile);
1456
+ const posts = Array.from({ length: tile.cols }, (_, postIndex) => {
1457
+ const x = rect2.x + postIndex * TILE_SIZE + 16;
1458
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y: rect2.y + 8, width: "8", height: "24", fill: "rgba(111,78,47,0.88)" }, `town-fence-post-${index}-${postIndex}`);
1459
+ });
1460
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1461
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 8, y: rect2.y + 15, width: rect2.width - 16, height: "6", fill: "rgba(151,104,61,0.82)" }),
1462
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 8, y: rect2.y + 25, width: rect2.width - 16, height: "5", fill: "rgba(126,88,54,0.7)" }),
1463
+ posts
1464
+ ] }, `town-fence-${index}`);
1465
+ }
1466
+ function renderTownPlaza() {
1467
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1468
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TileRectSvg, { tile: { col: 17, row: 9, cols: 6, rows: 6 }, fill: "rgba(211,189,128,0.96)", stroke: "rgba(126,97,58,0.36)" }),
1469
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TileRectSvg, { tile: { col: 18, row: 10, cols: 4, rows: 4 }, fill: "rgba(232,210,148,0.98)", stroke: "rgba(126,97,58,0.32)" }),
1470
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "776", y: "456", width: "48", height: "48", fill: "rgba(116,160,178,0.92)", stroke: "rgba(64,91,105,0.76)", strokeWidth: "4" }),
1471
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "788", y: "468", width: "24", height: "24", fill: "rgba(178,226,228,0.88)" }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "796", y: "444", width: "8", height: "24", fill: "rgba(101,112,109,0.9)" }),
1473
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "784", y: "516", width: "32", height: "12", fill: "rgba(113,79,48,0.86)" }),
1474
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "736", y: "436", width: "8", height: "8", fill: "rgba(238,228,183,0.9)" }),
1475
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "856", y: "436", width: "8", height: "8", fill: "rgba(238,228,183,0.9)" }),
1476
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "736", y: "556", width: "8", height: "8", fill: "rgba(238,228,183,0.9)" }),
1477
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "856", y: "556", width: "8", height: "8", fill: "rgba(238,228,183,0.9)" })
1478
+ ] }, "town-plaza");
1479
+ }
1480
+ function renderTree(point, index) {
1481
+ const x = point.col * TILE_SIZE;
1482
+ const y = point.row * TILE_SIZE;
1483
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1484
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 17, y: y + 22, width: "8", height: "12", fill: "rgba(103,73,42,0.92)" }),
1485
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 10, y: y + 10, width: "22", height: "18", fill: "rgba(58,145,77,0.95)" }),
1486
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 14, y: y + 4, width: "14", height: "12", fill: "rgba(80,174,86,0.96)" }),
1487
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 8, y: y + 18, width: "26", height: "8", fill: "rgba(38,122,67,0.84)" })
1488
+ ] }, `tree-${index}`);
1489
+ }
1490
+ function renderShrub(point, index) {
1491
+ const x = point.col * TILE_SIZE;
1492
+ const y = point.row * TILE_SIZE;
1493
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1494
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 8, y: y + 18, width: "24", height: "12", fill: "rgba(53,111,61,0.86)" }),
1495
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 14, y: y + 12, width: "14", height: "10", fill: "rgba(72,132,67,0.9)" }),
1496
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 5, y: y + 27, width: "30", height: "5", fill: "rgba(33,76,43,0.32)" })
1497
+ ] }, `shrub-${index}`);
1498
+ }
1499
+ function renderFlower(point, index) {
1500
+ const x = point.col * TILE_SIZE;
1501
+ const y = point.row * TILE_SIZE;
1502
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1503
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 11, y: y + 13, width: "4", height: "4", fill: "rgba(240,97,135,0.86)" }),
1504
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 24, y: y + 20, width: "4", height: "4", fill: "rgba(248,219,82,0.9)" }),
1505
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 17, y: y + 26, width: "4", height: "4", fill: "rgba(134,104,218,0.76)" })
1506
+ ] }, `flower-${index}`);
1507
+ }
1508
+ function renderTownProp(prop, index) {
1509
+ const rect2 = tileToRect(prop);
1510
+ const x = rect2.x + 6;
1511
+ const y = rect2.y + 7;
1512
+ if (prop.kind === "bed") {
1513
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1514
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y, width: "28", height: "24", fill: "rgba(178,112,68,0.88)" }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 4, y: y + 4, width: "20", height: "8", fill: "rgba(249,209,122,0.9)" }),
1516
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 4, y: y + 14, width: "20", height: "7", fill: "rgba(208,94,67,0.78)" })
1517
+ ] }, `town-prop-${index}`);
1518
+ }
1519
+ if (prop.kind === "shelf") {
1520
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1521
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y, width: Math.max(24, rect2.width - 12), height: "9", fill: "rgba(124,83,56,0.92)" }),
1522
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y: y + 12, width: Math.max(24, rect2.width - 12), height: "9", fill: "rgba(124,83,56,0.84)" }),
1523
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 5, y: y + 3, width: "5", height: "4", fill: "rgba(229,195,96,0.9)" })
1524
+ ] }, `town-prop-${index}`);
1525
+ }
1526
+ if (prop.kind === "table") {
1527
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1528
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 3, y: y + 5, width: Math.max(28, rect2.width - 18), height: "18", fill: "rgba(156,103,64,0.92)" }),
1529
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 8, y: y + 9, width: "6", height: "6", fill: "rgba(236,226,188,0.9)" })
1530
+ ] }, `town-prop-${index}`);
1531
+ }
1532
+ if (prop.kind === "sofa") {
1533
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1534
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y: y + 4, width: "26", height: "19", fill: "rgba(99,143,178,0.88)" }),
1535
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 4, y: y + 8, width: "18", height: "7", fill: "rgba(145,185,211,0.9)" })
1536
+ ] }, `town-prop-${index}`);
1537
+ }
1538
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1539
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y: y + 4, width: "26", height: "16", fill: "rgba(124,83,56,0.92)" }),
1540
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 4, y, width: "18", height: "8", fill: "rgba(194,214,221,0.9)" })
1541
+ ] }, `town-prop-${index}`);
1542
+ }
1543
+ function renderTownBuilding(building, activeZoneId) {
1544
+ const rect2 = tileToRect(building);
1545
+ const active = building.zoneId === activeZoneId;
1546
+ const doorX = rect2.x + rect2.width / 2 - 24;
1547
+ const doorY = building.entrance === "top" ? rect2.y - 6 : rect2.y + rect2.height - 10;
1548
+ const stepY = building.entrance === "top" ? rect2.y - 22 : rect2.y + rect2.height + 6;
1549
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1550
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: doorX + 4, y: stepY, width: "40", height: "22", fill: "rgba(193,165,104,0.92)", opacity: "0.9" }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x - 6, y: rect2.y - 6, width: rect2.width + 12, height: rect2.height + 12, fill: building.wall, opacity: active ? 1 : 0.82 }),
1552
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + 8, y: rect2.y + 8, width: rect2.width - 16, height: rect2.height - 16, fill: building.floor }),
1553
+ Array.from({ length: building.cols * building.rows }, (_, index) => {
1554
+ const col = building.col + index % building.cols;
1555
+ const row = building.row + Math.floor(index / building.cols);
1556
+ const tile = tileToRect({ col, row, cols: 1, rows: 1 });
1557
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1558
+ "rect",
1559
+ {
1560
+ x: tile.x + 8,
1561
+ y: tile.y + 8,
1562
+ width: TILE_SIZE - 16,
1563
+ height: TILE_SIZE - 16,
1564
+ fill: (col + row) % 2 === 0 ? "rgba(255,255,255,0.16)" : "rgba(0,0,0,0.04)"
1565
+ },
1566
+ `${building.zoneId}-floor-${col}-${row}`
1567
+ );
1568
+ }),
1569
+ building.walls.map((wall, index) => {
1570
+ const wallRect = tileToRect(wall);
1571
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1572
+ "rect",
1573
+ {
1574
+ x: wallRect.x + 4,
1575
+ y: wallRect.y + 4,
1576
+ width: wallRect.width - 8,
1577
+ height: wallRect.height - 8,
1578
+ fill: building.wall,
1579
+ opacity: "0.88"
1580
+ },
1581
+ `${building.zoneId}-wall-${index}`
1582
+ );
1583
+ }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: doorX, y: doorY, width: "48", height: "16", fill: "rgba(226,204,139,0.98)" }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: doorX + 8, y: doorY + 4, width: "32", height: "8", fill: "rgba(91,65,44,0.55)" }),
1586
+ building.props.map(renderTownProp),
1587
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x - 8, y: rect2.y - 8, width: rect2.width + 16, height: rect2.height + 16, fill: "none", stroke: active ? ZONE_PIXEL_PALETTE[building.zoneId].stroke : "rgba(17,17,19,0.34)", strokeWidth: active ? 5 : 3 })
1588
+ ] }, `town-building-${building.zoneId}`);
1589
+ }
1590
+ function PixelAtlasMap(props) {
1591
+ const activeZoneId = props.zones.find((zone) => zone.active)?.id;
1592
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1593
+ "svg",
1594
+ {
1595
+ viewBox: `0 0 ${props.stageWidth} ${props.stageHeight}`,
1596
+ className: "pointer-events-none absolute inset-0 h-full w-full",
1597
+ preserveAspectRatio: "xMidYMid meet",
1598
+ shapeRendering: "crispEdges",
1599
+ "aria-hidden": "true",
1600
+ children: [
1601
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: 0, y: 0, width: STAGE_WIDTH, height: STAGE_HEIGHT, fill: "rgba(247,244,236,0.98)" }),
1602
+ renderGrassTiles(),
1603
+ TOWN_WATER_TILES.map(renderTownWater),
1604
+ TOWN_PATH_TILES.map(renderTownPath),
1605
+ renderTownPlaza(),
1606
+ TOWN_FENCE_TILES.map(renderTownFence),
1607
+ TOWN_SHRUB_POINTS.map(renderShrub),
1608
+ TOWN_TREE_POINTS.map(renderTree),
1609
+ TOWN_FLOWER_POINTS.map(renderFlower),
1610
+ TOWN_BUILDINGS.map((building) => renderTownBuilding(building, activeZoneId)),
1611
+ props.zones.map((zone) => {
1612
+ const building = TOWN_BUILDINGS.find((item) => item.zoneId === zone.id);
1613
+ if (!building) return null;
1614
+ const layout = WORKBOARD_ZONE_LAYOUT[zone.id];
1615
+ const active = zone.active;
1616
+ const palette = ZONE_PIXEL_PALETTE[zone.id];
1617
+ const rect2 = tileToRect(building);
1618
+ const label = fitPixelLabel(zone.title, 112);
1619
+ const signWidth = Math.max(104, estimateTextWidth(label) + 34);
1620
+ const signX = rect2.x + 14;
1621
+ const signY = rect2.y - 30;
1622
+ const hubX = layout.hubX / 100 * STAGE_WIDTH;
1623
+ const hubY = layout.hubY / 100 * STAGE_HEIGHT;
1624
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
1625
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: signX - 5, y: signY + 5, width: signWidth, height: "22", fill: "rgba(72,50,33,0.34)" }),
1626
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: signX, y: signY, width: signWidth, height: "22", fill: "rgba(250,236,178,0.98)", stroke: palette.stroke, strokeWidth: active ? 4 : 3 }),
1627
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: signX + 7, y: signY + 22, width: "6", height: "16", fill: "rgba(111,78,47,0.86)" }),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: signX + signWidth - 13, y: signY + 22, width: "6", height: "16", fill: "rgba(111,78,47,0.86)" }),
1629
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: hubX - 16, y: hubY - 16, width: "32", height: "32", fill: "rgba(255,252,247,0.94)", stroke: palette.stroke, strokeWidth: "3" }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: hubX - 8, y: hubY - 8, width: "16", height: "16", fill: palette.fillStrong }),
1631
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: hubX - 3, y: hubY - 3, width: "6", height: "6", fill: palette.stroke }),
1632
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1633
+ "text",
1634
+ {
1635
+ x: signX + 10,
1636
+ y: signY + 15,
1637
+ fill: "rgba(17,17,19,0.78)",
1638
+ fontSize: "10",
1639
+ fontWeight: "700",
1640
+ fontFamily: "var(--font-geist-mono, var(--font-sans))",
1641
+ children: label
1642
+ }
1643
+ ),
1644
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: rect2.x + rect2.width - 44, y: rect2.y + 14, width: "30", height: "24", fill: palette.fillStrong, stroke: "rgba(17,17,19,0.34)", strokeWidth: "2" }),
1645
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1646
+ "text",
1647
+ {
1648
+ x: rect2.x + rect2.width - 29,
1649
+ y: rect2.y + 31,
1650
+ textAnchor: "end",
1651
+ fill: palette.stroke,
1652
+ fontSize: "15",
1653
+ fontWeight: "800",
1654
+ fontFamily: "var(--font-geist-mono, var(--font-sans))",
1655
+ children: zone.count
1656
+ }
1657
+ )
1658
+ ] }, `zone-${zone.id}`);
1659
+ })
1660
+ ]
1661
+ }
1662
+ );
1663
+ }
1664
+ function PixelRoute(props) {
1665
+ if (props.points.length < 2) return null;
1666
+ const d = props.points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
1667
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1668
+ "path",
1669
+ {
1670
+ d,
1671
+ fill: "none",
1672
+ className: props.className,
1673
+ strokeWidth: 3,
1674
+ strokeLinecap: "square",
1675
+ strokeLinejoin: "miter",
1676
+ strokeDasharray: props.dashed ? "8 8" : void 0
1677
+ }
1678
+ );
1679
+ }
1680
+ function PixelHoverTag(props) {
1681
+ if (!props.tag) return null;
1682
+ const text = fitPixelLabel(props.tag.label, 160);
1683
+ const width = Math.max(78, estimateTextWidth(text) + 18);
1684
+ const height = 20;
1685
+ const x = Math.min(Math.max(props.tag.x - width / 2, 6), props.stageWidth - width - 6);
1686
+ const y = Math.min(Math.max(props.tag.y - height - 14, 6), props.stageHeight - height - 6);
1687
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { pointerEvents: "none", children: [
1688
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x, y, width, height, fill: "rgba(255,252,247,0.98)", stroke: "rgba(17,17,19,0.44)", strokeWidth: "2" }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: x + 10, y: y + height, width: "10", height: "6", fill: "rgba(255,252,247,0.98)", stroke: "rgba(17,17,19,0.44)", strokeWidth: "2" }),
1690
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1691
+ "text",
1692
+ {
1693
+ x: x + 8,
1694
+ y: y + 13,
1695
+ fill: "rgba(17,17,19,0.72)",
1696
+ fontSize: "10",
1697
+ fontWeight: "700",
1698
+ fontFamily: "var(--font-geist-mono, var(--font-sans))",
1699
+ children: text
1700
+ }
1701
+ )
1702
+ ] });
1703
+ }
1704
+
1705
+ // src/components/workboard-pixel-agent.tsx
1706
+ var React3 = __toESM(require("react"), 1);
1707
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1708
+ var PIXEL_PALETTES = [
1709
+ {
1710
+ skin: "#f1c7a5",
1711
+ hair: "#4c3327",
1712
+ outfit: "#3f7c63",
1713
+ accent: "#d4eadf",
1714
+ outline: "#241a16"
1715
+ },
1716
+ {
1717
+ skin: "#dbb08a",
1718
+ hair: "#2d2a3b",
1719
+ outfit: "#8b6b37",
1720
+ accent: "#ead6bf",
1721
+ outline: "#231f18"
1722
+ },
1723
+ {
1724
+ skin: "#f0d1b5",
1725
+ hair: "#70462d",
1726
+ outfit: "#667b42",
1727
+ accent: "#dde8c7",
1728
+ outline: "#2a251d"
1729
+ },
1730
+ {
1731
+ skin: "#c98d66",
1732
+ hair: "#3b281f",
1733
+ outfit: "#925a45",
1734
+ accent: "#efdfd1",
1735
+ outline: "#241b16"
1736
+ }
1737
+ ];
1738
+ function hashText(value) {
1739
+ let hash = 0;
1740
+ for (const char of value) {
1741
+ hash = hash * 31 + char.charCodeAt(0) >>> 0;
1742
+ }
1743
+ return hash;
1744
+ }
1745
+ function rect(x, y, w, h, fill) {
1746
+ return `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="${fill}" />`;
1747
+ }
1748
+ function buildPixelAvatarSvg(params) {
1749
+ const seed = hashText(`${params.agentId}:${params.name}`);
1750
+ const palette = PIXEL_PALETTES[seed % PIXEL_PALETTES.length];
1751
+ const hairVariant = seed % 3;
1752
+ const eyeVariant = (seed >> 2) % 2;
1753
+ const accentVariant = (seed >> 4) % 3;
1754
+ const facingUp = params.direction === "up";
1755
+ const facingSide = params.direction === "left" || params.direction === "right";
1756
+ const parts = [
1757
+ `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" shape-rendering="crispEdges">`,
1758
+ rect(0, 0, 16, 16, "transparent"),
1759
+ rect(3, 2, 10, 2, palette.hair),
1760
+ rect(2, 4, 12, 1, palette.hair),
1761
+ rect(3, 5, 10, 5, palette.skin),
1762
+ rect(4, 10, 8, 4, palette.outfit),
1763
+ rect(2, 10, 2, 3, palette.outfit),
1764
+ rect(12, 10, 2, 3, palette.outfit),
1765
+ rect(5, 14, 2, 2, palette.outline),
1766
+ rect(9, 14, 2, 2, palette.outline),
1767
+ rect(4, 11, 1, 3, palette.outline),
1768
+ rect(11, 11, 1, 3, palette.outline),
1769
+ rect(6, 4, 4, 1, palette.accent)
1770
+ ];
1771
+ if (facingUp) {
1772
+ parts.push(
1773
+ rect(3, 4, 10, 5, palette.hair),
1774
+ rect(5, 8, 6, 2, palette.hair),
1775
+ rect(6, 11, 4, 2, palette.accent)
1776
+ );
1777
+ } else if (facingSide) {
1778
+ parts.push(
1779
+ rect(5, 6, 1, 1, palette.outline),
1780
+ rect(9, 7, 2, 1, palette.outline),
1781
+ rect(8, 8, 2, 1, "#9d6f4d"),
1782
+ rect(11, 5, 2, 4, palette.hair)
1783
+ );
1784
+ } else {
1785
+ parts.push(
1786
+ rect(6, 6, 1, 1, palette.outline),
1787
+ rect(9, 6, 1, 1, palette.outline),
1788
+ rect(7, 8, 2, 1, "#9d6f4d")
1789
+ );
1790
+ }
1791
+ if (hairVariant === 0) {
1792
+ parts.push(rect(2, 3, 1, 4, palette.hair), rect(13, 3, 1, 4, palette.hair));
1793
+ } else if (hairVariant === 1) {
1794
+ parts.push(rect(2, 3, 2, 2, palette.hair), rect(12, 3, 2, 2, palette.hair));
1795
+ } else {
1796
+ parts.push(rect(4, 1, 8, 1, palette.hair), rect(3, 2, 1, 2, palette.hair), rect(12, 2, 1, 2, palette.hair));
1797
+ }
1798
+ if (!facingUp && eyeVariant === 1) {
1799
+ parts.push(rect(5, 6, 1, 1, palette.outline), rect(10, 6, 1, 1, palette.outline));
1800
+ }
1801
+ if (accentVariant === 0) {
1802
+ parts.push(rect(6, 11, 4, 1, palette.accent));
1803
+ } else if (accentVariant === 1) {
1804
+ parts.push(rect(4, 12, 8, 1, palette.accent));
1805
+ } else {
1806
+ parts.push(rect(7, 10, 2, 3, palette.accent));
1807
+ }
1808
+ parts.push(rect(4, 9, 1, 1, palette.outline), rect(11, 9, 1, 1, palette.outline), `</svg>`);
1809
+ return parts.join("");
1810
+ }
1811
+ function svgToDataUri(svg) {
1812
+ return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
1813
+ }
1814
+ function WorkboardPixelAgent(props) {
1815
+ const src = React3.useMemo(
1816
+ () => svgToDataUri(buildPixelAvatarSvg({ agentId: props.agentId, name: props.name, direction: props.direction })),
1817
+ [props.agentId, props.name, props.direction]
1818
+ );
1819
+ const flipped = props.direction === "left";
1820
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1821
+ "span",
1822
+ {
1823
+ className: cn(
1824
+ "relative inline-flex overflow-visible",
1825
+ props.faded ? "opacity-65" : "opacity-100",
1826
+ props.className
1827
+ ),
1828
+ style: { width: props.size, height: props.size },
1829
+ "aria-hidden": "true",
1830
+ children: [
1831
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "absolute bottom-[1px] left-1/2 h-[4px] w-[70%] -translate-x-1/2 bg-[rgba(45,36,25,0.24)]" }),
1832
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1833
+ "img",
1834
+ {
1835
+ src,
1836
+ alt: "",
1837
+ width: props.size,
1838
+ height: props.size,
1839
+ draggable: false,
1840
+ className: "h-full w-full [image-rendering:pixelated]",
1841
+ style: {
1842
+ animation: props.walking ? "workboard-sprite-step 0.42s steps(2, end) infinite" : void 0,
1843
+ transform: flipped ? "scaleX(-1)" : void 0
1844
+ }
1845
+ }
1846
+ )
1847
+ ]
1848
+ }
1849
+ );
1850
+ }
1851
+
1852
+ // src/components/workboard-room-layout.ts
1853
+ var WORKBOARD_ROOM_PALETTE = {
1854
+ engaged: {
1855
+ floorA: "rgba(217,160,111,0.98)",
1856
+ floorB: "rgba(198,139,94,0.98)",
1857
+ wall: "rgba(107,58,45,0.98)",
1858
+ wallLight: "rgba(154,86,61,0.94)",
1859
+ rug: "rgba(183,69,50,0.72)",
1860
+ rugStrong: "rgba(226,118,77,0.86)",
1861
+ accent: "rgba(39,110,80,0.95)"
1862
+ },
1863
+ steady: {
1864
+ floorA: "rgba(218,190,111,0.98)",
1865
+ floorB: "rgba(197,166,91,0.98)",
1866
+ wall: "rgba(94,76,51,0.98)",
1867
+ wallLight: "rgba(139,113,70,0.94)",
1868
+ rug: "rgba(148,169,72,0.72)",
1869
+ rugStrong: "rgba(188,207,91,0.88)",
1870
+ accent: "rgba(112,132,38,0.92)"
1871
+ },
1872
+ quiet: {
1873
+ floorA: "rgba(205,194,166,0.98)",
1874
+ floorB: "rgba(186,174,148,0.98)",
1875
+ wall: "rgba(89,82,73,0.98)",
1876
+ wallLight: "rgba(126,117,103,0.94)",
1877
+ rug: "rgba(123,132,144,0.62)",
1878
+ rugStrong: "rgba(171,179,186,0.86)",
1879
+ accent: "rgba(103,96,87,0.9)"
1880
+ },
1881
+ drift: {
1882
+ floorA: "rgba(223,166,95,0.98)",
1883
+ floorB: "rgba(202,137,75,0.98)",
1884
+ wall: "rgba(121,66,36,0.98)",
1885
+ wallLight: "rgba(172,94,49,0.94)",
1886
+ rug: "rgba(196,89,44,0.72)",
1887
+ rugStrong: "rgba(236,145,65,0.9)",
1888
+ accent: "rgba(161,91,32,0.92)"
1889
+ }
1890
+ };
1891
+ var LARGE_ROOM_FLOORS = [
1892
+ { col: 2, row: 3, cols: 8, rows: 6 },
1893
+ { col: 11, row: 3, cols: 8, rows: 6 },
1894
+ { col: 21, row: 3, cols: 8, rows: 6 },
1895
+ { col: 30, row: 3, cols: 8, rows: 6 },
1896
+ { col: 2, row: 15, cols: 8, rows: 7 },
1897
+ { col: 11, row: 15, cols: 8, rows: 7 },
1898
+ { col: 21, row: 15, cols: 8, rows: 7 },
1899
+ { col: 30, row: 15, cols: 8, rows: 7 }
1900
+ ];
1901
+ var LARGE_ROOM_CORRIDORS = [
1902
+ { col: 1, row: 10, cols: 38, rows: 4 },
1903
+ { col: 19, row: 0, cols: 2, rows: 24 },
1904
+ { col: 9, row: 8, cols: 11, rows: 2 },
1905
+ { col: 20, row: 8, cols: 11, rows: 2 },
1906
+ { col: 9, row: 14, cols: 11, rows: 2 },
1907
+ { col: 20, row: 14, cols: 11, rows: 2 }
1908
+ ];
1909
+ var LARGE_ROOM_WALLS = [
1910
+ { col: 1, row: 2, cols: 38, rows: 1 },
1911
+ { col: 1, row: 22, cols: 38, rows: 1 },
1912
+ { col: 1, row: 2, cols: 1, rows: 21 },
1913
+ { col: 38, row: 2, cols: 1, rows: 21 },
1914
+ { col: 10, row: 3, cols: 1, rows: 6 },
1915
+ { col: 20, row: 3, cols: 1, rows: 6 },
1916
+ { col: 29, row: 3, cols: 1, rows: 6 },
1917
+ { col: 10, row: 15, cols: 1, rows: 7 },
1918
+ { col: 20, row: 15, cols: 1, rows: 7 },
1919
+ { col: 29, row: 15, cols: 1, rows: 7 },
1920
+ { col: 2, row: 9, cols: 17, rows: 1 },
1921
+ { col: 21, row: 9, cols: 17, rows: 1 },
1922
+ { col: 2, row: 14, cols: 17, rows: 1 },
1923
+ { col: 21, row: 14, cols: 17, rows: 1 }
1924
+ ];
1925
+ var LARGE_ROOM_DOORS = [
1926
+ { col: 5, row: 9, cols: 2, rows: 1 },
1927
+ { col: 14, row: 9, cols: 2, rows: 1 },
1928
+ { col: 24, row: 9, cols: 2, rows: 1 },
1929
+ { col: 33, row: 9, cols: 2, rows: 1 },
1930
+ { col: 5, row: 14, cols: 2, rows: 1 },
1931
+ { col: 14, row: 14, cols: 2, rows: 1 },
1932
+ { col: 24, row: 14, cols: 2, rows: 1 },
1933
+ { col: 33, row: 14, cols: 2, rows: 1 },
1934
+ { col: 20, row: 5, cols: 1, rows: 2 },
1935
+ { col: 20, row: 17, cols: 1, rows: 2 }
1936
+ ];
1937
+ var LARGE_ROOM_EXTERIOR_PATHS = [
1938
+ { col: 0, row: 10, cols: 40, rows: 4 },
1939
+ { col: 19, row: 0, cols: 2, rows: 24 },
1940
+ { col: 0, row: 0, cols: 6, rows: 1 },
1941
+ { col: 34, row: 0, cols: 6, rows: 1 },
1942
+ { col: 0, row: 23, cols: 6, rows: 1 },
1943
+ { col: 34, row: 23, cols: 6, rows: 1 }
1944
+ ];
1945
+ var LARGE_ROOM_TREES = [
1946
+ { col: 1, row: 2 },
1947
+ { col: 13, row: 1 },
1948
+ { col: 26, row: 1 },
1949
+ { col: 38, row: 2 },
1950
+ { col: 1, row: 22 },
1951
+ { col: 13, row: 22 },
1952
+ { col: 26, row: 22 },
1953
+ { col: 38, row: 22 }
1954
+ ];
1955
+ var LARGE_ROOM_SHRUBS = [
1956
+ { col: 6, row: 1 },
1957
+ { col: 12, row: 9 },
1958
+ { col: 27, row: 9 },
1959
+ { col: 33, row: 1 },
1960
+ { col: 6, row: 22 },
1961
+ { col: 12, row: 14 },
1962
+ { col: 27, row: 14 },
1963
+ { col: 33, row: 22 }
1964
+ ];
1965
+ function createRoomPlan(zoneId) {
1966
+ const focusedRugs = {
1967
+ engaged: [
1968
+ { col: 17, row: 9, cols: 6, rows: 6 },
1969
+ { col: 2, row: 3, cols: 8, rows: 6 },
1970
+ { col: 30, row: 3, cols: 8, rows: 6 }
1971
+ ],
1972
+ steady: [
1973
+ { col: 2, row: 10, cols: 36, rows: 4 },
1974
+ { col: 18, row: 3, cols: 4, rows: 19 }
1975
+ ],
1976
+ quiet: [
1977
+ { col: 17, row: 9, cols: 6, rows: 6 },
1978
+ { col: 2, row: 15, cols: 8, rows: 7 },
1979
+ { col: 30, row: 15, cols: 8, rows: 7 }
1980
+ ],
1981
+ drift: [
1982
+ { col: 16, row: 8, cols: 8, rows: 8 },
1983
+ { col: 2, row: 3, cols: 8, rows: 6 },
1984
+ { col: 30, row: 15, cols: 8, rows: 7 }
1985
+ ]
1986
+ };
1987
+ const focusedProps = {
1988
+ engaged: [
1989
+ { id: "engaged-board", kind: "board", x: 140, y: 654 },
1990
+ { id: "engaged-blueprint", kind: "blueprint", x: 1260, y: 650 },
1991
+ { id: "engaged-console-a", kind: "console", x: 710, y: 158 },
1992
+ { id: "engaged-rack-a", kind: "rack", x: 1352, y: 152 },
1993
+ { id: "engaged-table-a", kind: "table", x: 206, y: 206 },
1994
+ { id: "engaged-table-b", kind: "table", x: 1214, y: 688 }
1995
+ ],
1996
+ steady: [
1997
+ { id: "steady-board", kind: "board", x: 140, y: 654 },
1998
+ { id: "steady-blueprint", kind: "blueprint", x: 1260, y: 650 },
1999
+ { id: "steady-bench-a", kind: "bench", x: 210, y: 200 },
2000
+ { id: "steady-rack-a", kind: "rack", x: 706, y: 156 },
2001
+ { id: "steady-crate-a", kind: "crate", x: 904, y: 682 },
2002
+ { id: "steady-console-a", kind: "console", x: 1326, y: 192 }
2003
+ ],
2004
+ quiet: [
2005
+ { id: "quiet-board", kind: "board", x: 140, y: 654 },
2006
+ { id: "quiet-blueprint", kind: "blueprint", x: 1260, y: 650 },
2007
+ { id: "quiet-bed-a", kind: "bed", x: 196, y: 182 },
2008
+ { id: "quiet-bed-b", kind: "bed", x: 1292, y: 182 },
2009
+ { id: "quiet-bed-c", kind: "bed", x: 684, y: 684 },
2010
+ { id: "quiet-plant-a", kind: "plant", x: 906, y: 166 }
2011
+ ],
2012
+ drift: [
2013
+ { id: "drift-board", kind: "board", x: 140, y: 654 },
2014
+ { id: "drift-blueprint", kind: "blueprint", x: 1260, y: 650 },
2015
+ { id: "drift-console-a", kind: "console", x: 706, y: 156 },
2016
+ { id: "drift-rack-a", kind: "rack", x: 1328, y: 190 },
2017
+ { id: "drift-crate-a", kind: "crate", x: 210, y: 684 },
2018
+ { id: "drift-bench-a", kind: "bench", x: 1190, y: 686 }
2019
+ ]
2020
+ };
2021
+ return {
2022
+ floors: LARGE_ROOM_FLOORS,
2023
+ corridors: LARGE_ROOM_CORRIDORS,
2024
+ rugs: focusedRugs[zoneId],
2025
+ walls: LARGE_ROOM_WALLS,
2026
+ doors: LARGE_ROOM_DOORS,
2027
+ exteriorPaths: LARGE_ROOM_EXTERIOR_PATHS,
2028
+ trees: LARGE_ROOM_TREES,
2029
+ shrubs: LARGE_ROOM_SHRUBS,
2030
+ props: focusedProps[zoneId]
2031
+ };
2032
+ }
2033
+ var WORKBOARD_ROOM_PLANS = {
2034
+ engaged: createRoomPlan("engaged"),
2035
+ steady: createRoomPlan("steady"),
2036
+ quiet: createRoomPlan("quiet"),
2037
+ drift: createRoomPlan("drift")
2038
+ };
2039
+ var WORKBOARD_FOCUSED_STATIONS_BY_ZONE = {
2040
+ engaged: [
2041
+ { x: 250, y: 206 },
2042
+ { x: 686, y: 194 },
2043
+ { x: 1236, y: 206 },
2044
+ { x: 360, y: 460 },
2045
+ { x: 940, y: 460 },
2046
+ { x: 250, y: 714 },
2047
+ { x: 686, y: 730 },
2048
+ { x: 1236, y: 714 }
2049
+ ],
2050
+ steady: [
2051
+ { x: 246, y: 196 },
2052
+ { x: 668, y: 206 },
2053
+ { x: 934, y: 206 },
2054
+ { x: 1350, y: 196 },
2055
+ { x: 366, y: 480 },
2056
+ { x: 250, y: 728 },
2057
+ { x: 800, y: 730 },
2058
+ { x: 1350, y: 728 }
2059
+ ],
2060
+ quiet: [
2061
+ { x: 250, y: 206 },
2062
+ { x: 688, y: 206 },
2063
+ { x: 1238, y: 206 },
2064
+ { x: 360, y: 480 },
2065
+ { x: 940, y: 480 },
2066
+ { x: 250, y: 714 },
2067
+ { x: 688, y: 730 },
2068
+ { x: 1238, y: 714 }
2069
+ ],
2070
+ drift: [
2071
+ { x: 250, y: 206 },
2072
+ { x: 688, y: 194 },
2073
+ { x: 1238, y: 206 },
2074
+ { x: 360, y: 480 },
2075
+ { x: 940, y: 480 },
2076
+ { x: 250, y: 714 },
2077
+ { x: 800, y: 730 },
2078
+ { x: 1238, y: 714 }
2079
+ ]
2080
+ };
2081
+ var WORKBOARD_FOCUSED_PATROL_ROUTES = {
2082
+ engaged: [
2083
+ [
2084
+ { x: 240, y: 200 },
2085
+ { x: 800, y: 200 },
2086
+ { x: 1360, y: 200 },
2087
+ { x: 1360, y: 480 },
2088
+ { x: 1360, y: 720 },
2089
+ { x: 800, y: 720 },
2090
+ { x: 240, y: 720 },
2091
+ { x: 240, y: 480 }
2092
+ ],
2093
+ [
2094
+ { x: 420, y: 320 },
2095
+ { x: 800, y: 320 },
2096
+ { x: 1180, y: 320 },
2097
+ { x: 1180, y: 480 },
2098
+ { x: 1180, y: 620 },
2099
+ { x: 800, y: 620 },
2100
+ { x: 420, y: 620 },
2101
+ { x: 420, y: 480 }
2102
+ ],
2103
+ [
2104
+ { x: 240, y: 480 },
2105
+ { x: 800, y: 480 },
2106
+ { x: 1360, y: 480 },
2107
+ { x: 800, y: 480 },
2108
+ { x: 800, y: 200 },
2109
+ { x: 800, y: 720 },
2110
+ { x: 800, y: 480 }
2111
+ ]
2112
+ ],
2113
+ steady: [
2114
+ [
2115
+ { x: 240, y: 480 },
2116
+ { x: 800, y: 480 },
2117
+ { x: 1360, y: 480 },
2118
+ { x: 1360, y: 720 },
2119
+ { x: 800, y: 720 },
2120
+ { x: 240, y: 720 }
2121
+ ],
2122
+ [
2123
+ { x: 240, y: 200 },
2124
+ { x: 800, y: 200 },
2125
+ { x: 1360, y: 200 },
2126
+ { x: 1360, y: 480 },
2127
+ { x: 800, y: 480 },
2128
+ { x: 240, y: 480 }
2129
+ ],
2130
+ [
2131
+ { x: 800, y: 160 },
2132
+ { x: 800, y: 800 },
2133
+ { x: 1080, y: 800 },
2134
+ { x: 1080, y: 480 },
2135
+ { x: 520, y: 480 },
2136
+ { x: 520, y: 800 },
2137
+ { x: 800, y: 800 }
2138
+ ]
2139
+ ],
2140
+ quiet: [
2141
+ [
2142
+ { x: 240, y: 200 },
2143
+ { x: 800, y: 200 },
2144
+ { x: 1360, y: 200 },
2145
+ { x: 1360, y: 720 },
2146
+ { x: 800, y: 720 },
2147
+ { x: 240, y: 720 }
2148
+ ],
2149
+ [
2150
+ { x: 420, y: 480 },
2151
+ { x: 800, y: 480 },
2152
+ { x: 1180, y: 480 },
2153
+ { x: 1180, y: 640 },
2154
+ { x: 800, y: 640 },
2155
+ { x: 420, y: 640 }
2156
+ ],
2157
+ [
2158
+ { x: 800, y: 200 },
2159
+ { x: 800, y: 720 },
2160
+ { x: 420, y: 720 },
2161
+ { x: 420, y: 480 },
2162
+ { x: 1180, y: 480 },
2163
+ { x: 1180, y: 720 },
2164
+ { x: 800, y: 720 }
2165
+ ]
2166
+ ],
2167
+ drift: [
2168
+ [
2169
+ { x: 240, y: 200 },
2170
+ { x: 800, y: 200 },
2171
+ { x: 1360, y: 200 },
2172
+ { x: 1360, y: 620 },
2173
+ { x: 800, y: 720 },
2174
+ { x: 240, y: 620 }
2175
+ ],
2176
+ [
2177
+ { x: 240, y: 480 },
2178
+ { x: 800, y: 480 },
2179
+ { x: 1360, y: 480 },
2180
+ { x: 1360, y: 720 },
2181
+ { x: 800, y: 720 },
2182
+ { x: 240, y: 720 }
2183
+ ],
2184
+ [
2185
+ { x: 800, y: 160 },
2186
+ { x: 800, y: 720 },
2187
+ { x: 1080, y: 620 },
2188
+ { x: 1080, y: 320 },
2189
+ { x: 520, y: 320 },
2190
+ { x: 520, y: 620 },
2191
+ { x: 800, y: 720 }
2192
+ ]
2193
+ ]
2194
+ };
2195
+
2196
+ // src/components/workboard-stage.tsx
2197
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2198
+ var WORKBOARD_STAGE_HEIGHT = 960;
2199
+ var WORKBOARD_STAGE_WIDTH = 1600;
2200
+ var NODE_PLACEMENTS = [
2201
+ { left: 18, top: 26, delay: 0 },
2202
+ { left: 42, top: 19, delay: 0.4 },
2203
+ { left: 66, top: 29, delay: 0.8 },
2204
+ { left: 29, top: 54, delay: 1.2 },
2205
+ { left: 57, top: 56, delay: 1.6 },
2206
+ { left: 75, top: 47, delay: 2 },
2207
+ { left: 14, top: 70, delay: 2.4 },
2208
+ { left: 46, top: 74, delay: 2.8 }
2209
+ ];
2210
+ var WORKBOARD_ZONE_DEFINITIONS = [
2211
+ {
2212
+ id: "engaged",
2213
+ title: "\u5C55\u5F00\u4E2D",
2214
+ subtitle: "active field",
2215
+ description: "\u5F53\u524D\u5BF9\u5916\u6700\u6709\u52A8\u52BF\u7684\u4E00\u7EC4 agent\u3002",
2216
+ badge: "Live",
2217
+ areaClassName: "bg-[linear-gradient(145deg,rgba(238,248,244,0.92),rgba(248,251,249,0.78))]",
2218
+ borderClassName: "border-emerald-300/65",
2219
+ glowClassName: "bg-[radial-gradient(circle,rgba(52,144,111,0.18),transparent_70%)]",
2220
+ nodeClassName: "border-emerald-300/70 bg-[linear-gradient(145deg,rgba(248,252,250,0.98),rgba(235,247,242,0.94))]",
2221
+ lineClassName: "stroke-emerald-400/55"
2222
+ },
2223
+ {
2224
+ id: "steady",
2225
+ title: "\u6301\u7EED\u63A8\u8FDB",
2226
+ subtitle: "steady lane",
2227
+ description: "\u5904\u4E8E\u7A33\u5B9A\u8282\u594F\uFF0C\u6301\u7EED\u5411\u524D\u63A8\u8FDB\u7684\u4E00\u7EC4 agent\u3002",
2228
+ badge: "Steady",
2229
+ areaClassName: "bg-[linear-gradient(145deg,rgba(244,246,236,0.9),rgba(252,250,244,0.75))]",
2230
+ borderClassName: "border-lime-300/60",
2231
+ glowClassName: "bg-[radial-gradient(circle,rgba(151,169,72,0.16),transparent_72%)]",
2232
+ nodeClassName: "border-lime-300/65 bg-[linear-gradient(145deg,rgba(252,252,247,0.98),rgba(243,246,233,0.95))]",
2233
+ lineClassName: "stroke-lime-400/50"
2234
+ },
2235
+ {
2236
+ id: "quiet",
2237
+ title: "\u9759\u5019\u4E2D",
2238
+ subtitle: "quiet deck",
2239
+ description: "\u6682\u65F6\u5B89\u9759\u3001\u7B49\u5F85\u4E0B\u4E00\u6B21\u89E6\u53D1\u7684\u4E00\u7EC4 agent\u3002",
2240
+ badge: "Quiet",
2241
+ areaClassName: "bg-[linear-gradient(145deg,rgba(244,243,239,0.92),rgba(251,250,248,0.76))]",
2242
+ borderClassName: "border-stone-300/65",
2243
+ glowClassName: "bg-[radial-gradient(circle,rgba(130,124,112,0.14),transparent_72%)]",
2244
+ nodeClassName: "border-stone-300/65 bg-[linear-gradient(145deg,rgba(252,251,249,0.98),rgba(241,239,234,0.96))]",
2245
+ lineClassName: "stroke-stone-400/50"
2246
+ },
2247
+ {
2248
+ id: "drift",
2249
+ title: "\u8F7B\u5FAE\u6CE2\u52A8",
2250
+ subtitle: "watch deck",
2251
+ description: "\u51FA\u73B0\u4E2D\u65AD\u3001\u544A\u8B66\u6216\u9700\u8981\u91CD\u65B0\u89C2\u5BDF\u7684\u4E00\u7EC4 agent\u3002",
2252
+ badge: "Watch",
2253
+ areaClassName: "bg-[linear-gradient(145deg,rgba(251,241,235,0.92),rgba(252,248,244,0.76))]",
2254
+ borderClassName: "border-amber-300/70",
2255
+ glowClassName: "bg-[radial-gradient(circle,rgba(194,121,55,0.18),transparent_72%)]",
2256
+ nodeClassName: "border-amber-300/70 bg-[linear-gradient(145deg,rgba(253,250,245,0.98),rgba(249,239,229,0.95))]",
2257
+ lineClassName: "stroke-amber-400/55"
2258
+ }
2259
+ ];
2260
+ function createHoverTag(params) {
2261
+ return {
2262
+ id: params.id,
2263
+ label: params.label,
2264
+ x: params.point.x,
2265
+ y: params.point.y
2266
+ };
2267
+ }
2268
+ function resolveAgentGlyph(item) {
2269
+ const hasIssue = item.snapshot.current.some((entry) => entry.status === "issue") || item.snapshot.recent.some((entry) => entry.status === "issue") || item.snapshot.signals.some((entry) => entry.tone === "warning");
2270
+ if (hasIssue) {
2271
+ return {
2272
+ label: "!",
2273
+ className: "border-amber-700/50 bg-amber-400 text-amber-950"
2274
+ };
2275
+ }
2276
+ if (item.snapshot.current.some((entry) => entry.status === "active")) {
2277
+ return {
2278
+ label: ">",
2279
+ className: "border-emerald-700/45 bg-emerald-400 text-emerald-950"
2280
+ };
2281
+ }
2282
+ if (item.running) {
2283
+ return {
2284
+ label: "~",
2285
+ className: "border-lime-700/45 bg-lime-300 text-lime-950"
2286
+ };
2287
+ }
2288
+ return {
2289
+ label: ".",
2290
+ className: "border-stone-500/45 bg-stone-300 text-stone-800"
2291
+ };
2292
+ }
2293
+ function resolveZoneId(item) {
2294
+ const hasIssue = item.snapshot.current.some((entry) => entry.status === "issue") || item.snapshot.recent.some((entry) => entry.status === "issue") || item.snapshot.signals.some((entry) => entry.tone === "warning");
2295
+ if (hasIssue) return "drift";
2296
+ const hasActive = item.snapshot.current.some((entry) => entry.status === "active");
2297
+ if (hasActive) return "engaged";
2298
+ const hasRecentMotion = item.running && (item.snapshot.current.length > 0 || item.snapshot.recent.length > 0 || item.currentCount > 0);
2299
+ if (hasRecentMotion) return "steady";
2300
+ return "quiet";
2301
+ }
2302
+ function resolveZoneDefinition(zoneId) {
2303
+ return WORKBOARD_ZONE_DEFINITIONS.find((item) => item.id === zoneId) || WORKBOARD_ZONE_DEFINITIONS[0];
2304
+ }
2305
+ function formatWorkboardRelativeTime(value) {
2306
+ if (!value) return "-";
2307
+ const date = new Date(value);
2308
+ if (Number.isNaN(date.getTime())) return value;
2309
+ const delta = Math.max(0, Date.now() - date.getTime());
2310
+ const minutes = Math.floor(delta / 6e4);
2311
+ if (minutes < 1) return "just now";
2312
+ if (minutes < 60) return `${minutes}m ago`;
2313
+ const hours = Math.floor(minutes / 60);
2314
+ if (hours < 24) return `${hours}h ago`;
2315
+ const days = Math.floor(hours / 24);
2316
+ return `${days}d ago`;
2317
+ }
2318
+ function buildWorkboardTilePath(params) {
2319
+ const midX = params.from.x + (params.to.x - params.from.x) * 0.5;
2320
+ return `M ${params.from.x} ${params.from.y} H ${midX} V ${params.to.y} H ${params.to.x}`;
2321
+ }
2322
+ function toStagePoint(zoneId, placement) {
2323
+ const zone = WORKBOARD_ZONE_LAYOUT[zoneId];
2324
+ const left = zone.x + zone.w * placement.left / 100;
2325
+ const top = zone.y + zone.h * placement.top / 100;
2326
+ return {
2327
+ x: left / 100 * WORKBOARD_STAGE_WIDTH,
2328
+ y: top / 100 * WORKBOARD_STAGE_HEIGHT
2329
+ };
2330
+ }
2331
+ function toZoneHubPoint(zoneId) {
2332
+ const zone = WORKBOARD_ZONE_LAYOUT[zoneId];
2333
+ return {
2334
+ x: zone.hubX / 100 * WORKBOARD_STAGE_WIDTH,
2335
+ y: zone.hubY / 100 * WORKBOARD_STAGE_HEIGHT
2336
+ };
2337
+ }
2338
+ function deriveStageNodes(board) {
2339
+ const items = board?.agents || [];
2340
+ const buckets = /* @__PURE__ */ new Map();
2341
+ items.forEach((item) => {
2342
+ const zoneId = resolveZoneId(item);
2343
+ const group = buckets.get(zoneId) || [];
2344
+ group.push(item);
2345
+ buckets.set(zoneId, group);
2346
+ });
2347
+ return WORKBOARD_ZONE_DEFINITIONS.flatMap((zone) => {
2348
+ const group = buckets.get(zone.id) || [];
2349
+ return group.map((item, index) => ({
2350
+ item,
2351
+ zone,
2352
+ placement: NODE_PLACEMENTS[index % NODE_PLACEMENTS.length]
2353
+ }));
2354
+ });
2355
+ }
2356
+ function deriveFocusedClusterNodes(items, zoneId) {
2357
+ const stations = WORKBOARD_FOCUSED_STATIONS_BY_ZONE[zoneId];
2358
+ return items.map((item, index) => {
2359
+ const station = stations[index % stations.length];
2360
+ return {
2361
+ item,
2362
+ x: station.x,
2363
+ y: station.y,
2364
+ delay: index * 0.18
2365
+ };
2366
+ });
2367
+ }
2368
+ function buildOverviewPatrolRoute(params) {
2369
+ const anchor = toStagePoint(params.zoneId, params.placement);
2370
+ const hub = toZoneHubPoint(params.zoneId);
2371
+ const gate = WORKBOARD_ZONE_GATE_POINTS[params.zoneId];
2372
+ const laneIndex = Math.round((params.placement.left + params.placement.top) / 32) % 3;
2373
+ const laneOffset = (laneIndex - 1) * 10;
2374
+ const roadY = params.zoneId === "engaged" || params.zoneId === "steady" ? 460 : 500;
2375
+ const plazaLane = {
2376
+ x: WORKBOARD_TOWN_PLAZA_POINT.x + laneOffset,
2377
+ y: WORKBOARD_TOWN_PLAZA_POINT.y + (roadY < WORKBOARD_TOWN_PLAZA_POINT.y ? -10 : 10)
2378
+ };
2379
+ return [
2380
+ anchor,
2381
+ { x: anchor.x, y: hub.y },
2382
+ hub,
2383
+ { x: gate.x, y: hub.y },
2384
+ gate,
2385
+ { x: gate.x, y: roadY },
2386
+ { x: plazaLane.x, y: roadY },
2387
+ plazaLane,
2388
+ WORKBOARD_TOWN_PLAZA_POINT,
2389
+ plazaLane,
2390
+ { x: plazaLane.x, y: roadY },
2391
+ { x: gate.x, y: roadY },
2392
+ gate,
2393
+ { x: gate.x, y: hub.y },
2394
+ hub,
2395
+ { x: anchor.x, y: hub.y },
2396
+ anchor
2397
+ ];
2398
+ }
2399
+ function buildFocusedPatrolRoute(params) {
2400
+ const routes = WORKBOARD_FOCUSED_PATROL_ROUTES[params.zoneId];
2401
+ return routes[params.index % routes.length];
2402
+ }
2403
+ function WorkboardStageZone(props) {
2404
+ const layout = WORKBOARD_ZONE_LAYOUT[props.zone.id];
2405
+ const hubPoint = {
2406
+ x: layout.hubX / 100 * WORKBOARD_STAGE_WIDTH,
2407
+ y: layout.hubY / 100 * WORKBOARD_STAGE_HEIGHT
2408
+ };
2409
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2410
+ "button",
2411
+ {
2412
+ type: "button",
2413
+ onClick: () => props.onSelect?.(props.zone.id),
2414
+ onMouseEnter: () => props.onHoverChange?.(
2415
+ createHoverTag({
2416
+ id: `zone-${props.zone.id}`,
2417
+ label: `${props.zone.title} \xB7 ${props.count}`,
2418
+ point: { x: hubPoint.x + 24, y: hubPoint.y - 18 }
2419
+ })
2420
+ ),
2421
+ onMouseLeave: () => props.onHoverChange?.(null),
2422
+ onFocus: () => props.onHoverChange?.(
2423
+ createHoverTag({
2424
+ id: `zone-${props.zone.id}`,
2425
+ label: `${props.zone.title} \xB7 ${props.count}`,
2426
+ point: { x: hubPoint.x + 24, y: hubPoint.y - 18 }
2427
+ })
2428
+ ),
2429
+ onBlur: () => props.onHoverChange?.(null),
2430
+ className: "absolute z-10 bg-transparent text-left focus:outline-none",
2431
+ "aria-label": `${props.zone.title} ${props.count}`,
2432
+ style: {
2433
+ left: `${layout.x}%`,
2434
+ top: `${layout.y}%`,
2435
+ width: `${layout.w}%`,
2436
+ height: `${layout.h}%`,
2437
+ clipPath: "polygon(0 0,100% 0,100% calc(100% - 16px),calc(100% - 16px) calc(100% - 16px),calc(100% - 16px) 100%,0 100%)"
2438
+ }
2439
+ }
2440
+ );
2441
+ }
2442
+ function WorkboardStageAgentNode(props) {
2443
+ const compact = props.mode === "overview";
2444
+ const avatarSize = compact ? 28 : 36;
2445
+ const direction = "direction" in props.point ? props.point.direction : void 0;
2446
+ const walking = "state" in props.point ? props.point.state === "walking" : false;
2447
+ const glyph = resolveAgentGlyph(props.item);
2448
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2449
+ "button",
2450
+ {
2451
+ type: "button",
2452
+ onClick: () => props.onSelect?.(props.item.id),
2453
+ onMouseEnter: () => props.onHoverChange?.(
2454
+ createHoverTag({
2455
+ id: `agent-${props.item.id}`,
2456
+ label: `${props.item.name} \xB7 ${props.item.posture}`,
2457
+ point: props.point
2458
+ })
2459
+ ),
2460
+ onMouseLeave: () => props.onHoverChange?.(null),
2461
+ onFocus: () => props.onHoverChange?.(
2462
+ createHoverTag({
2463
+ id: `agent-${props.item.id}`,
2464
+ label: `${props.item.name} \xB7 ${props.item.posture}`,
2465
+ point: props.point
2466
+ })
2467
+ ),
2468
+ onBlur: () => props.onHoverChange?.(null),
2469
+ className: cn(
2470
+ "group absolute z-20 -translate-x-1/2 -translate-y-1/2 transition-all duration-300 focus:outline-none",
2471
+ props.active ? "scale-[1.08]" : "hover:scale-[1.04] focus-visible:scale-[1.04]",
2472
+ props.faded ? "opacity-30 saturate-50" : "opacity-100"
2473
+ ),
2474
+ style: {
2475
+ left: props.point.x,
2476
+ top: props.point.y
2477
+ },
2478
+ "aria-label": props.item.name,
2479
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "relative block", children: [
2480
+ props.active ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
2481
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2482
+ "span",
2483
+ {
2484
+ className: "pointer-events-none absolute -inset-2 border border-foreground/45",
2485
+ style: { animation: "workboard-pulse 1.6s steps(2, end) infinite" }
2486
+ }
2487
+ ),
2488
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "pointer-events-none absolute -left-1 -top-1 h-1.5 w-1.5 bg-foreground/70" }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "pointer-events-none absolute -right-1 -bottom-1 h-1.5 w-1.5 bg-foreground/60" })
2490
+ ] }) : null,
2491
+ !props.active && !props.faded ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "pointer-events-none absolute -inset-1 border border-foreground/22 opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-visible:opacity-100" }) : null,
2492
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2493
+ WorkboardPixelAgent,
2494
+ {
2495
+ agentId: props.item.id,
2496
+ name: props.item.name,
2497
+ size: avatarSize,
2498
+ active: props.active,
2499
+ faded: props.faded,
2500
+ direction,
2501
+ walking,
2502
+ className: cn(
2503
+ props.active ? "shadow-[0_0_0_1px_rgba(17,17,19,0.14),0_3px_0_rgba(17,17,19,0.22)]" : "",
2504
+ compact ? "" : "scale-[1.03]"
2505
+ )
2506
+ }
2507
+ ),
2508
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2509
+ "span",
2510
+ {
2511
+ className: cn(
2512
+ "absolute -bottom-1 -right-1 grid size-3 place-items-center border text-[8px] font-bold leading-none",
2513
+ glyph.className
2514
+ ),
2515
+ "aria-hidden": "true",
2516
+ children: glyph.label
2517
+ }
2518
+ )
2519
+ ] })
2520
+ }
2521
+ );
2522
+ }
2523
+
2524
+ // src/components/workboard-game-atlas.tsx
2525
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2526
+ var PIXEL_PANEL_CLIP = "polygon(0 6px,6px 6px,6px 0,calc(100% - 6px) 0,calc(100% - 6px) 6px,100% 6px,100% calc(100% - 6px),calc(100% - 6px) calc(100% - 6px),calc(100% - 0px) 100%,6px 100%,6px calc(100% - 6px),0 calc(100% - 6px))";
2527
+ function WorkboardAtlasPortalSign(props) {
2528
+ const zone = props.zones.find((item) => item.id === props.activeZoneId) || props.zones[0];
2529
+ if (!zone) return null;
2530
+ const point = toZoneHubPoint(zone.id);
2531
+ const left = Math.min(Math.max(point.x + 22, 18), WORKBOARD_STAGE_WIDTH - 198);
2532
+ const top = Math.min(Math.max(point.y - 54, 76), WORKBOARD_STAGE_HEIGHT - 120);
2533
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2534
+ "button",
2535
+ {
2536
+ type: "button",
2537
+ onClick: () => props.onSelectZone(zone.id),
2538
+ className: "absolute z-30 w-40 border-[3px] border-[#6e4d2f] bg-[#f8de8d] px-3 py-2 text-left shadow-[5px_5px_0_rgba(72,50,33,0.28)] transition-[filter,transform] hover:-translate-y-0.5 hover:brightness-105 focus:outline-none focus-visible:-translate-y-0.5",
2539
+ style: { left, top, clipPath: PIXEL_PANEL_CLIP },
2540
+ children: [
2541
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute left-3 top-full h-5 w-2 bg-[#6e4d2f]" }),
2542
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute right-3 top-full h-5 w-2 bg-[#6e4d2f]" }),
2543
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "block text-[9px] uppercase tracking-[0.18em] text-[#6e4d2f]/70", children: "zone gate" }),
2544
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "mt-1 block truncate text-sm font-semibold leading-5 tracking-[-0.04em] text-[#352516]", children: zone.title }),
2545
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "mt-1 grid grid-cols-[1fr_auto] items-center gap-2", children: [
2546
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "h-2 border border-[#6e4d2f]/35 bg-[#fff1bd]", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2547
+ "span",
2548
+ {
2549
+ className: "block h-full bg-[#6e4d2f]/70",
2550
+ style: { width: `${Math.max(8, Math.min(100, zone.count * 18))}%` }
2551
+ }
2552
+ ) }),
2553
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[10px] font-semibold text-[#6e4d2f]/75", children: zone.count })
2554
+ ] })
2555
+ ]
2556
+ }
2557
+ );
2558
+ }
2559
+ function WorkboardGameAtlas(props) {
2560
+ const [hoveredTag, setHoveredTag] = React4.useState(null);
2561
+ const zones = props.gameMap.zones;
2562
+ const actors = props.gameMap.actors;
2563
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2564
+ "div",
2565
+ {
2566
+ className: "relative overflow-hidden border-2 border-border/70 bg-[linear-gradient(145deg,rgba(251,250,247,0.96),rgba(245,248,245,0.88))]",
2567
+ style: { width: WORKBOARD_STAGE_WIDTH, height: WORKBOARD_STAGE_HEIGHT, clipPath: PIXEL_PANEL_CLIP, imageRendering: "pixelated" },
2568
+ children: [
2569
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "absolute left-3 top-3 z-20 px-1", children: [
2570
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "text-[10px] uppercase tracking-[0.2em] text-foreground/42", children: "world atlas" }),
2571
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-1 text-[11px] text-foreground/66", children: "enter a zone" })
2572
+ ] }),
2573
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2574
+ "div",
2575
+ {
2576
+ className: "absolute right-3 top-3 z-20 border border-border/50 bg-background/72 px-2 py-1 text-right",
2577
+ style: { clipPath: PIXEL_PANEL_CLIP },
2578
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "text-[10px] uppercase tracking-[0.16em] text-foreground/42", children: props.flowMode })
2579
+ }
2580
+ ),
2581
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PixelAtlasMap, { zones, stageWidth: WORKBOARD_STAGE_WIDTH, stageHeight: WORKBOARD_STAGE_HEIGHT }),
2582
+ zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2583
+ WorkboardStageZone,
2584
+ {
2585
+ zone: resolveZoneDefinition(zone.id),
2586
+ count: zone.count,
2587
+ active: zone.id === props.activeZoneId,
2588
+ onSelect: props.onSelectZone,
2589
+ onHoverChange: setHoveredTag
2590
+ },
2591
+ zone.id
2592
+ )),
2593
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2594
+ WorkboardAtlasPortalSign,
2595
+ {
2596
+ activeZoneId: props.activeZoneId,
2597
+ zones,
2598
+ onSelectZone: props.onSelectZone
2599
+ }
2600
+ ),
2601
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2602
+ "svg",
2603
+ {
2604
+ viewBox: `0 0 ${WORKBOARD_STAGE_WIDTH} ${WORKBOARD_STAGE_HEIGHT}`,
2605
+ className: "pointer-events-none absolute inset-0 h-full w-full",
2606
+ preserveAspectRatio: "xMidYMid meet",
2607
+ "aria-hidden": "true",
2608
+ children: [
2609
+ props.gameMap.corridors.map((route) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2610
+ PixelRoute,
2611
+ {
2612
+ points: route.points,
2613
+ className: cn("stroke-foreground/8", route.active ? "opacity-100" : "opacity-60"),
2614
+ dashed: true
2615
+ },
2616
+ route.id
2617
+ )),
2618
+ actors.map((actor) => {
2619
+ const faded = actor.zoneId !== props.activeZoneId;
2620
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("g", { opacity: faded ? 0.18 : 0.72, children: [
2621
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2622
+ "rect",
2623
+ {
2624
+ x: actor.overviewGate.x - 5,
2625
+ y: actor.overviewGate.y - 5,
2626
+ width: "10",
2627
+ height: "10",
2628
+ fill: "rgba(255,252,247,0.92)",
2629
+ stroke: "rgba(17,17,19,0.36)",
2630
+ strokeWidth: "2"
2631
+ }
2632
+ ),
2633
+ props.selectedAgentId === actor.id ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2634
+ "rect",
2635
+ {
2636
+ x: actor.overviewGate.x - 9,
2637
+ y: actor.overviewGate.y - 9,
2638
+ width: "18",
2639
+ height: "18",
2640
+ fill: "none",
2641
+ stroke: "rgba(17,17,19,0.42)",
2642
+ strokeWidth: "2",
2643
+ strokeDasharray: "3 4"
2644
+ }
2645
+ ) : null
2646
+ ] }, `gate-${actor.id}`);
2647
+ })
2648
+ ]
2649
+ }
2650
+ ),
2651
+ actors.map((actor) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2652
+ WorkboardStageAgentNode,
2653
+ {
2654
+ item: actor.agent,
2655
+ zone: resolveZoneDefinition(actor.zoneId),
2656
+ point: props.motionFrames[actor.id] || actor.overviewAnchor,
2657
+ active: props.selectedAgentId === actor.id,
2658
+ faded: actor.zoneId !== props.activeZoneId,
2659
+ mode: "overview",
2660
+ onSelect: (agentId) => props.onSelectAgent?.(agentId, actor.zoneId),
2661
+ onHoverChange: setHoveredTag
2662
+ },
2663
+ actor.id
2664
+ )),
2665
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2666
+ "svg",
2667
+ {
2668
+ viewBox: `0 0 ${WORKBOARD_STAGE_WIDTH} ${WORKBOARD_STAGE_HEIGHT}`,
2669
+ className: "pointer-events-none absolute inset-0 h-full w-full",
2670
+ preserveAspectRatio: "xMidYMid meet",
2671
+ "aria-hidden": "true",
2672
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PixelHoverTag, { tag: hoveredTag, stageWidth: WORKBOARD_STAGE_WIDTH, stageHeight: WORKBOARD_STAGE_HEIGHT })
2673
+ }
2674
+ )
2675
+ ]
2676
+ }
2677
+ );
2678
+ }
2679
+
2680
+ // src/components/workboard-game-inspector.tsx
2681
+ var import_lucide_react6 = require("lucide-react");
2682
+ var import_core = require("@pxlkit/core");
2683
+ var import_effects = require("@pxlkit/effects");
2684
+ var import_feedback = require("@pxlkit/feedback");
2685
+ var import_gamification = require("@pxlkit/gamification");
2686
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2687
+ var PIXEL_PANEL_CLIP2 = "polygon(0 6px,6px 6px,6px 0,calc(100% - 6px) 0,calc(100% - 6px) 6px,100% 6px,100% calc(100% - 6px),calc(100% - 6px) calc(100% - 6px),calc(100% - 0px) 100%,6px 100%,6px calc(100% - 6px),0 calc(100% - 6px))";
2688
+ function activityIcon(kind) {
2689
+ if (kind === "focus") return import_gamification.Crown;
2690
+ if (kind === "progress") return import_effects.RadarPing;
2691
+ return import_feedback.Clock;
2692
+ }
2693
+ function ActivityLine(props) {
2694
+ const icon = activityIcon(props.item.kind);
2695
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("li", { className: "flex items-start gap-2 border-b border-border/50 py-2 last:border-b-0", children: [
2696
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "mt-0.5 inline-flex size-5 items-center justify-center border border-border/60 bg-background/82 text-foreground/70", children: (0, import_core.isAnimatedIcon)(icon) ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_core.AnimatedPxlKitIcon, { icon, size: 14, colorful: true, speed: 0.8 }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_core.PxlKitIcon, { icon, size: 14, colorful: true }) }),
2697
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "min-w-0 flex-1", children: [
2698
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
2699
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-sm font-medium text-foreground", children: props.item.title }),
2700
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "border border-border/50 bg-background/72 px-1.5 py-0.5 text-[10px] uppercase tracking-[0.12em] text-foreground/54", children: props.item.status })
2701
+ ] }),
2702
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mt-1 text-sm leading-6 text-muted-foreground", children: props.item.summary })
2703
+ ] })
2704
+ ] });
2705
+ }
2706
+ function CueLine(props) {
2707
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2708
+ "li",
2709
+ {
2710
+ className: cn(
2711
+ "flex items-start justify-between gap-3 border-b border-border/50 py-2 text-sm last:border-b-0",
2712
+ props.item.tone === "warning" ? "text-amber-800" : "text-foreground"
2713
+ ),
2714
+ children: [
2715
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "inline-flex items-center gap-1.5 text-foreground/48", children: [
2716
+ props.item.tone === "warning" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_core.PxlKitIcon, { icon: import_feedback.WarningTriangle, size: 12, colorful: true }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_core.PxlKitIcon, { icon: import_feedback.Sparkles, size: 12, colorful: true }),
2717
+ props.item.label
2718
+ ] }),
2719
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "border border-border/50 bg-background/72 px-1.5 py-0.5 font-medium", children: props.item.value })
2720
+ ]
2721
+ }
2722
+ );
2723
+ }
2724
+ function PixelStat(props) {
2725
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "border border-border/60 bg-background/72 px-2 py-1.5", children: [
2726
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "text-[10px] uppercase tracking-[0.14em] text-foreground/42", children: props.label }),
2727
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mt-1 text-sm font-medium text-foreground", children: props.value })
2728
+ ] });
2729
+ }
2730
+ function SpriteRoster(props) {
2731
+ const visiblePeers = props.peers.filter((item) => item.id !== props.selectedAgentId).slice(0, 6);
2732
+ if (visiblePeers.length === 0) {
2733
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "border border-dashed border-border/70 bg-background/70 px-3 py-2 text-sm text-muted-foreground", children: "\u5F53\u524D\u533A\u57DF\u6CA1\u6709\u5176\u4ED6 sprite\u3002" });
2734
+ }
2735
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "grid gap-1.5", children: visiblePeers.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2736
+ "button",
2737
+ {
2738
+ type: "button",
2739
+ onClick: () => props.onSelectAgent?.(item.id),
2740
+ className: "inline-flex items-center justify-between gap-2 border border-border/70 bg-background/90 px-2 py-1.5 text-sm text-foreground transition-colors hover:border-foreground/20",
2741
+ children: [
2742
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
2743
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex h-5 min-w-5 items-center justify-center border border-border/60 bg-background/72 px-1 text-[10px] uppercase tracking-[0.12em] text-foreground/54", children: index + 1 }),
2744
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(WorkboardPixelAgent, { agentId: item.id, name: item.name, size: 18 }),
2745
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: item.name })
2746
+ ] }),
2747
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-[10px] uppercase tracking-[0.12em] text-foreground/42", children: item.momentum })
2748
+ ]
2749
+ },
2750
+ item.id
2751
+ )) });
2752
+ }
2753
+ function WorkboardGameInspector(props) {
2754
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("aside", { className: "absolute bottom-3 right-3 z-30 w-[min(420px,calc(100%-24px))]", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2755
+ "div",
2756
+ {
2757
+ className: "relative border-2 border-border/70 bg-[rgba(255,252,247,0.94)] shadow-[0_6px_0_rgba(17,17,19,0.12)] backdrop-blur-[1px]",
2758
+ style: { clipPath: PIXEL_PANEL_CLIP2 },
2759
+ children: [
2760
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "pointer-events-none absolute left-2 top-2 h-2 w-2 bg-foreground/16" }),
2761
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "pointer-events-none absolute right-2 top-2 h-2 w-2 bg-foreground/10" }),
2762
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "pointer-events-none absolute bottom-2 left-2 h-2 w-2 bg-foreground/10" }),
2763
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2764
+ "button",
2765
+ {
2766
+ type: "button",
2767
+ onClick: props.onToggleCollapsed,
2768
+ className: "flex w-full items-center justify-between px-3 py-2 text-left",
2769
+ "aria-expanded": !props.collapsed,
2770
+ children: [
2771
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs uppercase tracking-[0.16em] text-foreground/46", children: "codex log" }),
2772
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "inline-flex items-center gap-1 text-xs text-foreground/56", children: [
2773
+ props.collapsed ? "Open" : "Close",
2774
+ props.collapsed ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react6.ChevronUpIcon, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react6.ChevronDownIcon, { className: "size-3.5" })
2775
+ ] })
2776
+ ]
2777
+ }
2778
+ ),
2779
+ !props.collapsed ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "border-t-2 border-border/70 px-3 pb-3 pt-2", children: [
2780
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "border border-border/60 bg-background/72 px-2.5 py-2", children: [
2781
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
2782
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
2783
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[10px] uppercase tracking-[0.16em] text-foreground/42", children: "active zone" }),
2784
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { className: "mt-1 text-xl font-semibold tracking-[-0.04em] text-foreground", children: props.activeZone.title })
2785
+ ] }),
2786
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "border border-border/60 bg-background px-1.5 py-0.5 text-[10px] uppercase tracking-[0.14em] text-foreground/52", children: props.stageLevel === "clusters" ? "world" : "room" })
2787
+ ] }),
2788
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "mt-2 text-sm leading-6 text-muted-foreground", children: props.activeZone.description }),
2789
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "mt-1 text-[11px] uppercase tracking-[0.14em] text-foreground/42", children: props.activeZone.subtitle })
2790
+ ] }),
2791
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3", children: [
2792
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-xs uppercase tracking-[0.12em] text-foreground/46", children: "nearby sprites" }),
2793
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mt-2 max-h-28 overflow-auto pr-1", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2794
+ SpriteRoster,
2795
+ {
2796
+ peers: props.selectedPeers,
2797
+ selectedAgentId: props.selected?.id || "",
2798
+ onSelectAgent: props.onSelectAgent
2799
+ }
2800
+ ) })
2801
+ ] }),
2802
+ props.selected ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3 border-t-2 border-border/70 pt-3", children: [
2803
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
2804
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
2805
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(WorkboardPixelAgent, { agentId: props.selected.id, name: props.selected.name, size: 24, active: true }),
2806
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
2807
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-xs uppercase tracking-[0.12em] text-foreground/46", children: "selected sprite" }),
2808
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm font-semibold text-foreground", children: props.selected.name })
2809
+ ] })
2810
+ ] }),
2811
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "border border-border/60 bg-background px-1.5 py-0.5 text-[10px] uppercase tracking-[0.14em] text-foreground/52", children: formatWorkboardRelativeTime(props.selected.collectedAt) })
2812
+ ] }),
2813
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3 grid grid-cols-3 gap-1.5", children: [
2814
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PixelStat, { label: "posture", value: props.selected.posture }),
2815
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PixelStat, { label: "tempo", value: props.selected.momentum }),
2816
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PixelStat, { label: "life", value: props.selected.running ? "live" : "quiet" })
2817
+ ] }),
2818
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3 border border-border/60 bg-background/78 px-2.5 py-2", children: [
2819
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[10px] uppercase tracking-[0.14em] text-foreground/42", children: "speech line" }),
2820
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { className: "mt-1 text-sm leading-6 text-foreground", children: [
2821
+ "\u201C",
2822
+ props.selected.snapshot.current[0]?.summary || props.selected.headline,
2823
+ "\u201D"
2824
+ ] }),
2825
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "mt-1 text-[11px] text-muted-foreground", children: props.selected.statusText })
2826
+ ] }),
2827
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3", children: [
2828
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-xs uppercase tracking-[0.12em] text-foreground/46", children: "quest beats" }),
2829
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "mt-1 border border-border/60 bg-background/74 px-2 py-1", children: (props.selected.snapshot.current || []).slice(0, 3).map((item) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ActivityLine, { item }, item.id)) })
2830
+ ] }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3", children: [
2832
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-xs uppercase tracking-[0.12em] text-foreground/46", children: "recent drops" }),
2833
+ (props.selected.snapshot.recent || []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "mt-1 border border-dashed border-border/60 bg-background/70 px-2 py-2 text-sm text-muted-foreground", children: "\u6682\u65E0\u8FD1\u671F\u7247\u6BB5\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "mt-1 border border-border/60 bg-background/74 px-2 py-1", children: (props.selected.snapshot.recent || []).slice(0, 3).map((item) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ActivityLine, { item }, item.id)) })
2834
+ ] }),
2835
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-3", children: [
2836
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-xs uppercase tracking-[0.12em] text-foreground/46", children: "world cues" }),
2837
+ (props.selected.snapshot.signals || []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "mt-1 border border-dashed border-border/60 bg-background/70 px-2 py-2 text-sm text-muted-foreground", children: "\u5F53\u524D\u6CA1\u6709\u516C\u5F00\u7EBF\u7D22\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "mt-1 border border-border/60 bg-background/74 px-2 py-1", children: (props.selected.snapshot.signals || []).slice(0, 4).map((item) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CueLine, { item }, item.label)) })
2838
+ ] })
2839
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mt-3 border border-dashed border-border/60 bg-background/70 px-3 py-3 text-sm text-muted-foreground", children: "\u9009\u4E2D\u4E00\u4E2A sprite \u540E\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5B83\u7684\u516C\u5F00\u7247\u6BB5\u4E0E\u7EBF\u7D22\u3002" })
2840
+ ] }) : null
2841
+ ]
2842
+ }
2843
+ ) });
2844
+ }
2845
+
2846
+ // src/components/workboard-game-map.ts
2847
+ var OVERVIEW_ROUTE_DWELL = 0.22;
2848
+ var FOCUSED_ROUTE_DWELL = 0.28;
2849
+ var PIXEL_STEP_SIZE = 2;
2850
+ function resolveOverviewGate(params) {
2851
+ if (params.zoneId === "engaged" || params.zoneId === "quiet") {
2852
+ return params.route[1] || params.route[0] || toZoneHubPoint(params.zoneId);
2853
+ }
2854
+ return params.route[2] || params.route[1] || params.route[0] || toZoneHubPoint(params.zoneId);
2855
+ }
2856
+ var FOCUSED_PROP_ITEMS = {
2857
+ engaged: [],
2858
+ steady: [],
2859
+ quiet: [],
2860
+ drift: []
2861
+ };
2862
+ var FOCUSED_AREA_LABELS = {
2863
+ engaged: [
2864
+ { id: "engaged-briefing", label: "briefing node", x: 166, y: 118 },
2865
+ { id: "engaged-relay", label: "relay desk", x: 660, y: 118 },
2866
+ { id: "engaged-dispatch", label: "dispatch rack", x: 1194, y: 118 }
2867
+ ],
2868
+ steady: [
2869
+ { id: "steady-focus", label: "focus lane", x: 166, y: 118 },
2870
+ { id: "steady-desk", label: "steady desk", x: 660, y: 118 },
2871
+ { id: "steady-throughput", label: "throughput rail", x: 1194, y: 118 }
2872
+ ],
2873
+ quiet: [
2874
+ { id: "quiet-standby", label: "standby desk", x: 166, y: 118 },
2875
+ { id: "quiet-idle", label: "idle rail", x: 660, y: 118 },
2876
+ { id: "quiet-sleep", label: "sleep shelf", x: 1194, y: 118 }
2877
+ ],
2878
+ drift: [
2879
+ { id: "drift-watch", label: "watch point", x: 166, y: 118 },
2880
+ { id: "drift-issue", label: "issue console", x: 660, y: 118 },
2881
+ { id: "drift-signal", label: "signal rack", x: 1194, y: 118 }
2882
+ ]
2883
+ };
2884
+ function buildZones(params) {
2885
+ return WORKBOARD_ZONE_DEFINITIONS.map((zone) => ({
2886
+ id: zone.id,
2887
+ title: zone.title,
2888
+ subtitle: zone.subtitle,
2889
+ description: zone.description,
2890
+ badge: zone.badge,
2891
+ count: params.board.agents.filter((item) => resolveZoneId(item) === zone.id).length,
2892
+ active: zone.id === params.activeZoneId,
2893
+ hub: toZoneHubPoint(zone.id)
2894
+ }));
2895
+ }
2896
+ function buildActors(params) {
2897
+ const stageNodes = deriveStageNodes(params.board);
2898
+ const focusedLookup = /* @__PURE__ */ new Map();
2899
+ WORKBOARD_ZONE_DEFINITIONS.forEach((zone) => {
2900
+ const items = params.board.agents.filter((item) => resolveZoneId(item) === zone.id);
2901
+ const focusedNodes = deriveFocusedClusterNodes(items, zone.id);
2902
+ focusedNodes.forEach((node, index) => {
2903
+ focusedLookup.set(node.item.id, {
2904
+ anchor: { x: node.x, y: node.y },
2905
+ routeId: `patrol-${zone.id}-${index % 3}`
2906
+ });
2907
+ });
2908
+ });
2909
+ return stageNodes.map((node) => {
2910
+ const overviewRoute = buildOverviewPatrolRoute({
2911
+ zoneId: node.zone.id,
2912
+ placement: node.placement
2913
+ });
2914
+ const focused = focusedLookup.get(node.item.id);
2915
+ return {
2916
+ id: node.item.id,
2917
+ agent: node.item,
2918
+ zoneId: node.zone.id,
2919
+ overviewAnchor: overviewRoute[0] || toZoneHubPoint(node.zone.id),
2920
+ overviewRoute,
2921
+ overviewGate: resolveOverviewGate({
2922
+ zoneId: node.zone.id,
2923
+ route: overviewRoute
2924
+ }),
2925
+ focusedAnchor: focused?.anchor,
2926
+ focusedStation: focused?.anchor,
2927
+ focusedRouteId: focused?.routeId,
2928
+ active: node.item.id === params.selectedAgentId
2929
+ };
2930
+ });
2931
+ }
2932
+ function buildPatrols(params) {
2933
+ const laneCount = Math.max(
2934
+ 1,
2935
+ Math.min(
2936
+ 3,
2937
+ params.board.agents.filter((item) => resolveZoneId(item) === params.activeZoneId).length
2938
+ )
2939
+ );
2940
+ return Array.from({ length: laneCount }, (_, index) => ({
2941
+ id: `patrol-${params.activeZoneId}-${index}`,
2942
+ kind: "patrol",
2943
+ points: buildFocusedPatrolRoute({ index, zoneId: params.activeZoneId }),
2944
+ zoneId: params.activeZoneId,
2945
+ dwellRatio: FOCUSED_ROUTE_DWELL,
2946
+ snapSize: PIXEL_STEP_SIZE,
2947
+ label: `lane ${index + 1}`,
2948
+ active: index === 0
2949
+ }));
2950
+ }
2951
+ function buildCorridors(params) {
2952
+ return params.actors.map((actor) => ({
2953
+ id: `corridor-${actor.id}`,
2954
+ kind: "corridor",
2955
+ points: actor.overviewRoute,
2956
+ zoneId: actor.zoneId,
2957
+ dwellRatio: OVERVIEW_ROUTE_DWELL,
2958
+ snapSize: PIXEL_STEP_SIZE,
2959
+ label: actor.agent.name,
2960
+ active: actor.zoneId === params.activeZoneId
2961
+ }));
2962
+ }
2963
+ function buildWorkboardGameMapConfig(params) {
2964
+ const zones = buildZones(params);
2965
+ const actors = buildActors(params);
2966
+ const patrols = buildPatrols(params);
2967
+ const corridors = buildCorridors({ actors, activeZoneId: params.activeZoneId });
2968
+ return {
2969
+ board: params.board,
2970
+ activeZoneId: params.activeZoneId,
2971
+ selectedAgentId: params.selectedAgentId,
2972
+ zones,
2973
+ actors,
2974
+ corridors,
2975
+ patrols,
2976
+ pointsOfInterest: [
2977
+ ...FOCUSED_PROP_ITEMS[params.activeZoneId],
2978
+ {
2979
+ id: `${params.activeZoneId}-hub`,
2980
+ kind: "hub",
2981
+ x: 800,
2982
+ y: 480,
2983
+ active: true
2984
+ }
2985
+ ],
2986
+ areaLabels: FOCUSED_AREA_LABELS[params.activeZoneId]
2987
+ };
2988
+ }
2989
+
2990
+ // src/components/workboard-game-room.tsx
2991
+ var React5 = __toESM(require("react"), 1);
2992
+
2993
+ // src/components/workboard-room-field.tsx
2994
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2995
+ var TILE_SIZE2 = 40;
2996
+ var GRID_COLS2 = 40;
2997
+ var GRID_ROWS2 = 24;
2998
+ var STAGE_WIDTH2 = TILE_SIZE2 * GRID_COLS2;
2999
+ var STAGE_HEIGHT2 = TILE_SIZE2 * GRID_ROWS2;
3000
+ function tileToRect2(tile) {
3001
+ return {
3002
+ x: tile.col * TILE_SIZE2,
3003
+ y: tile.row * TILE_SIZE2,
3004
+ width: tile.cols * TILE_SIZE2,
3005
+ height: tile.rows * TILE_SIZE2
3006
+ };
3007
+ }
3008
+ function estimateTextWidth2(text) {
3009
+ return Array.from(text).reduce((acc, char) => acc + (char.charCodeAt(0) > 255 ? 9 : 6), 0);
3010
+ }
3011
+ function renderGrassTiles2() {
3012
+ return Array.from({ length: GRID_COLS2 * GRID_ROWS2 }, (_, index) => {
3013
+ const col = index % GRID_COLS2;
3014
+ const row = Math.floor(index / GRID_COLS2);
3015
+ const rect2 = tileToRect2({ col, row, cols: 1, rows: 1 });
3016
+ const fill = (col + row) % 2 === 0 ? "rgba(104,136,76,0.98)" : "rgba(91,124,70,0.98)";
3017
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3018
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: TILE_SIZE2, height: TILE_SIZE2, fill }),
3019
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x + 6, y: rect2.y + 8, width: "4", height: "4", fill: "rgba(40,78,45,0.24)" }),
3020
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x + 27, y: rect2.y + 25, width: "4", height: "4", fill: "rgba(142,161,89,0.18)" })
3021
+ ] }, `room-grass-${col}-${row}`);
3022
+ });
3023
+ }
3024
+ function renderPath(tile, index) {
3025
+ const rect2 = tileToRect2(tile);
3026
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3027
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: rect2.height, fill: "rgba(210,184,120,0.98)" }),
3028
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y + rect2.height - 5, width: rect2.width, height: "5", fill: "rgba(137,104,67,0.28)" }),
3029
+ Array.from({ length: Math.max(1, tile.cols * tile.rows) }, (_, chipIndex) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3030
+ "rect",
3031
+ {
3032
+ x: rect2.x + 8 + chipIndex % Math.max(1, tile.cols) * TILE_SIZE2,
3033
+ y: rect2.y + 10 + Math.floor(chipIndex / Math.max(1, tile.cols)) * TILE_SIZE2,
3034
+ width: "12",
3035
+ height: "4",
3036
+ fill: "rgba(96,74,51,0.16)"
3037
+ },
3038
+ `room-path-chip-${index}-${chipIndex}`
3039
+ ))
3040
+ ] }, `room-path-${index}`);
3041
+ }
3042
+ function renderTree2(point, index) {
3043
+ const x = point.col * TILE_SIZE2;
3044
+ const y = point.row * TILE_SIZE2;
3045
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3046
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 17, y: y + 22, width: "8", height: "18", fill: "rgba(92,62,40,0.94)" }),
3047
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 10, y: y + 10, width: "22", height: "18", fill: "rgba(74,126,76,0.98)" }),
3048
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 5, y: y + 17, width: "32", height: "16", fill: "rgba(61,112,65,0.98)" }),
3049
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 14, y: y + 4, width: "18", height: "12", fill: "rgba(91,150,82,0.96)" })
3050
+ ] }, `room-tree-${index}`);
3051
+ }
3052
+ function renderShrub2(point, index) {
3053
+ const x = point.col * TILE_SIZE2;
3054
+ const y = point.row * TILE_SIZE2;
3055
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3056
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 5, y: y + 22, width: "12", height: "9", fill: "rgba(70,121,66,0.96)" }),
3057
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 15, y: y + 18, width: "18", height: "12", fill: "rgba(87,142,75,0.96)" }),
3058
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: x + 28, y: y + 24, width: "7", height: "7", fill: "rgba(58,103,58,0.9)" })
3059
+ ] }, `room-shrub-${index}`);
3060
+ }
3061
+ function renderFloor(tile, index, palette) {
3062
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("g", { children: Array.from({ length: tile.cols * tile.rows }, (_, plankIndex) => {
3063
+ const col = tile.col + plankIndex % tile.cols;
3064
+ const row = tile.row + Math.floor(plankIndex / tile.cols);
3065
+ const rect2 = tileToRect2({ col, row, cols: 1, rows: 1 });
3066
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3067
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: TILE_SIZE2, height: TILE_SIZE2, fill: (col + row) % 2 === 0 ? palette.floorA : palette.floorB }),
3068
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y + TILE_SIZE2 - 4, width: TILE_SIZE2, height: "4", fill: "rgba(81,56,39,0.2)" }),
3069
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x + 10, y: rect2.y + 12, width: "10", height: "4", fill: "rgba(248,214,149,0.13)" })
3070
+ ] }, `room-plank-${index}-${col}-${row}`);
3071
+ }) }, `room-floor-${index}`);
3072
+ }
3073
+ function renderBlock(tile, index, fill, stroke) {
3074
+ const rect2 = tileToRect2(tile);
3075
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3076
+ "rect",
3077
+ {
3078
+ x: rect2.x,
3079
+ y: rect2.y,
3080
+ width: rect2.width,
3081
+ height: rect2.height,
3082
+ fill,
3083
+ stroke,
3084
+ strokeWidth: stroke ? 2 : void 0
3085
+ },
3086
+ `room-block-${index}`
3087
+ );
3088
+ }
3089
+ function renderWall(tile, index, palette) {
3090
+ const rect2 = tileToRect2(tile);
3091
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3092
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: rect2.height, fill: palette.wall }),
3093
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x + 4, y: rect2.y + 4, width: Math.max(0, rect2.width - 8), height: Math.max(0, rect2.height - 8), fill: palette.wallLight }),
3094
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: "5", fill: "rgba(242,168,97,0.32)" })
3095
+ ] }, `room-wall-${index}`);
3096
+ }
3097
+ function renderDoor(tile, index) {
3098
+ const rect2 = tileToRect2(tile);
3099
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3100
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: rect2.height, fill: "rgba(215,184,110,0.98)" }),
3101
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x + 8, y: rect2.y + 10, width: Math.max(10, rect2.width - 16), height: "5", fill: "rgba(95,69,43,0.34)" })
3102
+ ] }, `room-door-${index}`);
3103
+ }
3104
+ function renderRug(tile, index, palette) {
3105
+ const rect2 = tileToRect2(tile);
3106
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3107
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x, y: rect2.y, width: rect2.width, height: rect2.height, fill: index === 0 ? palette.rug : palette.rugStrong }),
3108
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: rect2.x + 8, y: rect2.y + 8, width: Math.max(0, rect2.width - 16), height: Math.max(0, rect2.height - 16), fill: "none", stroke: palette.accent, strokeWidth: "3", opacity: "0.42" })
3109
+ ] }, `room-rug-${index}`);
3110
+ }
3111
+ function renderRoomProp(prop) {
3112
+ if (prop.kind === "hub") return null;
3113
+ if (prop.kind === "board") {
3114
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3115
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y, width: "170", height: "82", fill: "rgba(196,127,73,0.98)", stroke: "rgba(94,61,39,0.9)", strokeWidth: "4" }),
3116
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 12, y: prop.y + 12, width: "54", height: "24", fill: "rgba(255,241,189,0.92)" }),
3117
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 78, y: prop.y + 12, width: "72", height: "18", fill: "rgba(255,241,189,0.86)" }),
3118
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 18, y: prop.y + 48, width: "132", height: "18", fill: "rgba(255,241,189,0.78)" })
3119
+ ] });
3120
+ }
3121
+ if (prop.kind === "blueprint") {
3122
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3123
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y + 22, width: "120", height: "34", fill: "rgba(111,78,47,0.9)" }),
3124
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 10, y: prop.y, width: "100", height: "64", fill: "rgba(67,116,138,0.96)", stroke: "rgba(53,37,22,0.6)", strokeWidth: "3" }),
3125
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 22, y: prop.y + 12, width: "30", height: "18", fill: "none", stroke: "rgba(219,236,224,0.78)", strokeWidth: "3" }),
3126
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: `M ${prop.x + 64} ${prop.y + 16} H ${prop.x + 94} V ${prop.y + 42} H ${prop.x + 44}`, fill: "none", stroke: "rgba(219,236,224,0.7)", strokeWidth: "3" })
3127
+ ] });
3128
+ }
3129
+ if (prop.kind === "desk" || prop.kind === "table") {
3130
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3131
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y, width: prop.kind === "table" ? 48 : 32, height: prop.kind === "table" ? 24 : 12, fill: "rgba(126,91,67,0.94)" }),
3132
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 4, y: prop.y + 16, width: "6", height: "14", fill: "rgba(77,57,43,0.9)" }),
3133
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 32, y: prop.y + 16, width: "6", height: "14", fill: "rgba(77,57,43,0.9)" })
3134
+ ] });
3135
+ }
3136
+ if (prop.kind === "rack") {
3137
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3138
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y, width: "14", height: "36", fill: "rgba(88,82,75,0.92)" }),
3139
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 5, y: prop.y + 6, width: "24", height: "5", fill: "rgba(166,149,112,0.88)" }),
3140
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 5, y: prop.y + 18, width: "24", height: "5", fill: "rgba(166,149,112,0.88)" }),
3141
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 5, y: prop.y + 30, width: "24", height: "5", fill: "rgba(166,149,112,0.88)" })
3142
+ ] });
3143
+ }
3144
+ if (prop.kind === "console") {
3145
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3146
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y, width: "34", height: "22", fill: "rgba(72,95,86,0.94)" }),
3147
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 7, y: prop.y + 6, width: "18", height: "6", fill: "rgba(215,236,222,0.92)" }),
3148
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 7, y: prop.y + 22, width: "6", height: "12", fill: "rgba(56,64,60,0.88)" }),
3149
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 22, y: prop.y + 22, width: "6", height: "12", fill: "rgba(56,64,60,0.88)" })
3150
+ ] });
3151
+ }
3152
+ if (prop.kind === "bench") {
3153
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3154
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y, width: "44", height: "10", fill: "rgba(145,108,76,0.92)" }),
3155
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 7, y: prop.y + 10, width: "5", height: "14", fill: "rgba(82,62,49,0.9)" }),
3156
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 32, y: prop.y + 10, width: "5", height: "14", fill: "rgba(82,62,49,0.9)" })
3157
+ ] });
3158
+ }
3159
+ if (prop.kind === "plant") {
3160
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3161
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 6, y: prop.y + 18, width: "16", height: "12", fill: "rgba(127,90,63,0.92)" }),
3162
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 3, y: prop.y + 8, width: "22", height: "14", fill: "rgba(100,145,80,0.92)" }),
3163
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 10, y: prop.y, width: "8", height: "12", fill: "rgba(136,179,101,0.9)" })
3164
+ ] });
3165
+ }
3166
+ if (prop.kind === "bed") {
3167
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3168
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y, width: "52", height: "34", fill: "rgba(111,82,63,0.95)" }),
3169
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 5, y: prop.y + 5, width: "18", height: "12", fill: "rgba(238,229,198,0.94)" }),
3170
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 25, y: prop.y + 5, width: "22", height: "24", fill: "rgba(151,168,181,0.84)" })
3171
+ ] });
3172
+ }
3173
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3174
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x, y: prop.y + 4, width: "20", height: "18", fill: "rgba(143,105,70,0.9)" }),
3175
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: prop.x + 20, y: prop.y + 8, width: "14", height: "14", fill: "rgba(177,136,94,0.9)" })
3176
+ ] });
3177
+ }
3178
+ function renderAreaLabel(label, index) {
3179
+ const width = Math.max(72, estimateTextWidth2(label.label) + 16);
3180
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { opacity: "0.94", children: [
3181
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: label.x, y: label.y, width, height: "20", fill: "rgba(250,236,178,0.94)", stroke: "rgba(110,77,47,0.64)", strokeWidth: "2" }),
3182
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3183
+ "text",
3184
+ {
3185
+ x: label.x + 7,
3186
+ y: label.y + 14,
3187
+ fill: "rgba(17,17,19,0.72)",
3188
+ fontSize: "9",
3189
+ fontWeight: "700",
3190
+ fontFamily: "var(--font-geist-mono, var(--font-sans))",
3191
+ children: label.label
3192
+ }
3193
+ )
3194
+ ] }, `room-label-${index}`);
3195
+ }
3196
+ function renderHub(zone, palette) {
3197
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("g", { children: [
3198
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: 736, y: 422, width: "128", height: "116", fill: "rgba(250,236,178,0.94)", stroke: palette.accent, strokeWidth: "4" }),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: 758, y: 444, width: "84", height: "70", fill: palette.rugStrong, opacity: "0.9" }),
3200
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: 788, y: 470, width: "28", height: "22", fill: palette.accent, opacity: "0.92" }),
3201
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: 774, y: 540, width: "52", height: "14", fill: "rgba(111,78,47,0.82)" }),
3202
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3203
+ "text",
3204
+ {
3205
+ x: "800",
3206
+ y: "414",
3207
+ textAnchor: "middle",
3208
+ fill: palette.accent,
3209
+ fontSize: "10",
3210
+ fontWeight: "800",
3211
+ fontFamily: "var(--font-geist-mono, var(--font-sans))",
3212
+ children: zone.badge.toUpperCase()
3213
+ }
3214
+ )
3215
+ ] });
3216
+ }
3217
+ function WorkboardRoomField(props) {
3218
+ const plan = WORKBOARD_ROOM_PLANS[props.zone.id];
3219
+ const palette = WORKBOARD_ROOM_PALETTE[props.zone.id];
3220
+ const externalPoi = props.pointsOfInterest.filter((item) => item.kind !== "hub");
3221
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3222
+ "svg",
3223
+ {
3224
+ viewBox: `0 0 ${props.stageWidth} ${props.stageHeight}`,
3225
+ className: "pointer-events-none absolute inset-0 h-full w-full",
3226
+ preserveAspectRatio: "xMidYMid meet",
3227
+ shapeRendering: "crispEdges",
3228
+ "aria-hidden": "true",
3229
+ children: [
3230
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("rect", { x: 0, y: 0, width: STAGE_WIDTH2, height: STAGE_HEIGHT2, fill: "rgba(247,244,236,0.98)" }),
3231
+ renderGrassTiles2(),
3232
+ plan.exteriorPaths.map(renderPath),
3233
+ plan.trees.map(renderTree2),
3234
+ plan.shrubs.map(renderShrub2),
3235
+ plan.floors.map((tile, index) => renderFloor(tile, index, palette)),
3236
+ plan.corridors.map((tile, index) => renderBlock(tile, index, "rgba(203,171,104,0.96)", "rgba(92,67,45,0.2)")),
3237
+ plan.rugs.map((tile, index) => renderRug(tile, index, palette)),
3238
+ plan.props.map((prop) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("g", { opacity: "0.96", children: renderRoomProp(prop) }, prop.id)),
3239
+ externalPoi.map((poi) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("g", { opacity: "0.58", children: renderRoomProp(poi) }, poi.id)),
3240
+ props.areaLabels.map(renderAreaLabel),
3241
+ plan.walls.map((tile, index) => renderWall(tile, index, palette)),
3242
+ plan.doors.map(renderDoor),
3243
+ renderHub(props.zone, palette)
3244
+ ]
3245
+ }
3246
+ );
3247
+ }
3248
+
3249
+ // src/components/workboard-game-room.tsx
3250
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3251
+ var PIXEL_PANEL_CLIP3 = "polygon(0 6px,6px 6px,6px 0,calc(100% - 6px) 0,calc(100% - 6px) 6px,100% 6px,100% calc(100% - 6px),calc(100% - 6px) calc(100% - 6px),calc(100% - 0px) 100%,6px 100%,6px calc(100% - 6px),0 calc(100% - 6px))";
3252
+ function resolveRoomPoint(params) {
3253
+ return params.motionFrames?.[params.agentId] || params.fallback;
3254
+ }
3255
+ function ActiveSpeechBubble(props) {
3256
+ if (!props.item || !props.point) return null;
3257
+ const line = props.item.snapshot.current[0]?.summary || props.item.snapshot.recent[0]?.summary || props.item.headline;
3258
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3259
+ "div",
3260
+ {
3261
+ className: "pointer-events-none absolute z-30 max-w-[20rem] border-[3px] border-[#6e4d2f] bg-[#fff1bd] px-3 py-2 text-sm shadow-[5px_5px_0_rgba(72,50,33,0.22)]",
3262
+ style: {
3263
+ left: Math.min(Math.max(props.point.x + 28, 48), WORKBOARD_STAGE_WIDTH - 260),
3264
+ top: Math.min(Math.max(props.point.y - 74, 20), WORKBOARD_STAGE_HEIGHT - 72),
3265
+ clipPath: PIXEL_PANEL_CLIP3
3266
+ },
3267
+ children: [
3268
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("p", { className: "text-[9px] uppercase tracking-[0.14em] text-[#6e4d2f]/70", children: [
3269
+ props.item.name,
3270
+ " \xB7 ",
3271
+ props.item.posture
3272
+ ] }),
3273
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("p", { className: "mt-1 leading-6 text-[#352516]", children: [
3274
+ "\u201C",
3275
+ line,
3276
+ "\u201D"
3277
+ ] }),
3278
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "absolute -bottom-[11px] left-5 block h-[11px] w-[16px] border-x-[3px] border-b-[3px] border-[#6e4d2f] bg-[#fff1bd]" })
3279
+ ]
3280
+ }
3281
+ );
3282
+ }
3283
+ function resolveQuestEntries(item) {
3284
+ if (!item) return [];
3285
+ return [...item.snapshot.current, ...item.snapshot.recent].slice(0, 3);
3286
+ }
3287
+ function WorkboardRoomQuestLedger(props) {
3288
+ const entries = resolveQuestEntries(props.item);
3289
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3290
+ "div",
3291
+ {
3292
+ className: "pointer-events-none absolute left-[128px] top-[662px] z-10 w-64 border-[3px] border-[#6e4d2f] bg-[#c48752] px-3 py-2 shadow-[5px_5px_0_rgba(72,50,33,0.24)]",
3293
+ style: { clipPath: PIXEL_PANEL_CLIP3 },
3294
+ children: [
3295
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
3296
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-[9px] uppercase tracking-[0.18em] text-[#fff1bd]/80", children: "wall board" }),
3297
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-[9px] uppercase tracking-[0.14em] text-[#fff1bd]/70", children: props.item ? props.item.posture : "empty" })
3298
+ ] }),
3299
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "mt-2 space-y-1.5", children: entries.length > 0 ? entries.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "grid grid-cols-[1.5rem_1fr] gap-2 bg-[#fff1bd]/88 px-1.5 py-1 text-xs shadow-[2px_2px_0_rgba(72,50,33,0.18)]", children: [
3300
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "grid h-5 place-items-center border border-[#6e4d2f]/35 bg-[#f8de8d] text-[9px] font-semibold text-[#6e4d2f]/70", children: [
3301
+ "Q",
3302
+ index + 1
3303
+ ] }),
3304
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "min-w-0", children: [
3305
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "block truncate font-semibold leading-5 text-[#352516]", children: entry.title }),
3306
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "block truncate text-[11px] leading-4 text-[#6e4d2f]/70", children: entry.status })
3307
+ ] })
3308
+ ] }, entry.id)) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "bg-[#fff1bd]/88 px-2 py-1 text-xs leading-5 text-[#6e4d2f]/70", children: "No public quest beats." }) })
3309
+ ]
3310
+ }
3311
+ );
3312
+ }
3313
+ function WorkboardRoomMiniMap(props) {
3314
+ const miniWidth = 144;
3315
+ const miniHeight = 88;
3316
+ const scaleX = miniWidth / WORKBOARD_STAGE_WIDTH;
3317
+ const scaleY = miniHeight / WORKBOARD_STAGE_HEIGHT;
3318
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3319
+ "div",
3320
+ {
3321
+ className: "pointer-events-none absolute left-[1228px] top-[662px] z-10 border-[3px] border-[#6e4d2f] bg-[#8a6040] p-2 shadow-[5px_5px_0_rgba(72,50,33,0.24)]",
3322
+ style: { clipPath: PIXEL_PANEL_CLIP3 },
3323
+ "aria-hidden": "true",
3324
+ children: [
3325
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "mb-1 text-[9px] uppercase tracking-[0.16em] text-[#fff1bd]/75", children: "floor plan" }),
3326
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("svg", { width: miniWidth, height: miniHeight, viewBox: `0 0 ${miniWidth} ${miniHeight}`, shapeRendering: "crispEdges", children: [
3327
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: "0", y: "0", width: miniWidth, height: miniHeight, fill: "rgba(241,225,166,0.95)" }),
3328
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: "6", y: "6", width: miniWidth - 12, height: miniHeight - 12, fill: "rgba(255,241,189,0.9)", stroke: "rgba(110,77,47,0.42)", strokeWidth: "2" }),
3329
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("line", { x1: "12", y1: miniHeight / 2, x2: miniWidth - 12, y2: miniHeight / 2, stroke: "rgba(110,77,47,0.18)", strokeWidth: "2" }),
3330
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("line", { x1: miniWidth / 2, y1: "12", x2: miniWidth / 2, y2: miniHeight - 12, stroke: "rgba(110,77,47,0.18)", strokeWidth: "2" }),
3331
+ props.nodes.map((node) => {
3332
+ const active = node.item.id === props.activeItemId;
3333
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3334
+ "rect",
3335
+ {
3336
+ x: Math.max(8, Math.min(miniWidth - 10, node.x * scaleX)),
3337
+ y: Math.max(8, Math.min(miniHeight - 10, node.y * scaleY)),
3338
+ width: active ? 6 : 4,
3339
+ height: active ? 6 : 4,
3340
+ fill: active ? "rgba(53,37,22,0.86)" : "rgba(110,77,47,0.48)"
3341
+ },
3342
+ node.item.id
3343
+ );
3344
+ }),
3345
+ props.activePoint ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3346
+ "rect",
3347
+ {
3348
+ x: Math.max(8, Math.min(miniWidth - 12, props.activePoint.x * scaleX)) - 3,
3349
+ y: Math.max(8, Math.min(miniHeight - 12, props.activePoint.y * scaleY)) - 3,
3350
+ width: "10",
3351
+ height: "10",
3352
+ fill: "none",
3353
+ stroke: "rgba(53,37,22,0.86)",
3354
+ strokeWidth: "2"
3355
+ }
3356
+ ) : null
3357
+ ] })
3358
+ ]
3359
+ }
3360
+ );
3361
+ }
3362
+ function RoomEntranceSign(props) {
3363
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3364
+ "div",
3365
+ {
3366
+ className: "pointer-events-none absolute left-[674px] top-[850px] z-10 border-[3px] border-[#6e4d2f] bg-[#fff1bd] px-3 py-2 text-center shadow-[4px_4px_0_rgba(72,50,33,0.22)]",
3367
+ style: { clipPath: PIXEL_PANEL_CLIP3 },
3368
+ "aria-hidden": "true",
3369
+ children: [
3370
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-[9px] uppercase tracking-[0.18em] text-[#6e4d2f]/65", children: props.zone.subtitle }),
3371
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "mt-1 text-[11px] font-bold uppercase tracking-[0.12em] text-[#352516]", children: [
3372
+ props.flowMode,
3373
+ " room"
3374
+ ] })
3375
+ ]
3376
+ }
3377
+ );
3378
+ }
3379
+ function buildRoomPolylinePath(points) {
3380
+ return points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
3381
+ }
3382
+ function RoomPatrolTrail(props) {
3383
+ const d = buildRoomPolylinePath(props.route.points);
3384
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("g", { opacity: props.route.active ? 0.68 : 0.34, children: [
3385
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3386
+ "path",
3387
+ {
3388
+ d,
3389
+ fill: "none",
3390
+ stroke: "rgba(101,75,52,0.34)",
3391
+ strokeWidth: props.route.active ? 12 : 8,
3392
+ strokeLinecap: "square",
3393
+ strokeLinejoin: "miter"
3394
+ }
3395
+ ),
3396
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3397
+ "path",
3398
+ {
3399
+ d,
3400
+ fill: "none",
3401
+ stroke: "rgba(245,211,142,0.38)",
3402
+ strokeWidth: props.route.active ? 4 : 3,
3403
+ strokeDasharray: "6 12",
3404
+ strokeLinecap: "square",
3405
+ strokeLinejoin: "miter"
3406
+ }
3407
+ ),
3408
+ props.route.points.map((point, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3409
+ "rect",
3410
+ {
3411
+ x: point.x - 4,
3412
+ y: point.y - 4,
3413
+ width: "8",
3414
+ height: "8",
3415
+ fill: "rgba(245,211,142,0.52)"
3416
+ },
3417
+ `${props.route.id}-trail-${index}`
3418
+ ))
3419
+ ] });
3420
+ }
3421
+ function RoomHubMapObject(props) {
3422
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3423
+ "div",
3424
+ {
3425
+ className: "pointer-events-none absolute z-20 -translate-x-1/2 -translate-y-1/2",
3426
+ style: { left: props.point.x, top: props.point.y },
3427
+ "aria-hidden": "true",
3428
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "relative h-24 w-28", children: [
3429
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute left-4 top-5 h-14 w-20 border-[3px] border-[#6e4d2f] bg-[#f8de8d] shadow-[4px_4px_0_rgba(72,50,33,0.28)]" }),
3430
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute left-8 top-8 h-7 w-12 bg-[#6b8f83]" }),
3431
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute left-11 top-11 h-2 w-6 bg-[#cde6d9]" }),
3432
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute left-7 top-[3.9rem] h-3 w-4 bg-[#6e4d2f]" }),
3433
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute right-7 top-[3.9rem] h-3 w-4 bg-[#6e4d2f]" }),
3434
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "absolute left-1/2 top-0 -translate-x-1/2 border-2 border-[#6e4d2f] bg-[#fff1bd] px-2 py-1 text-center shadow-[3px_3px_0_rgba(72,50,33,0.18)]", children: [
3435
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-[8px] uppercase tracking-[0.13em] text-[#6e4d2f]/70", children: props.badge }),
3436
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "max-w-20 truncate text-[10px] font-bold leading-3 text-[#352516]", children: props.title })
3437
+ ] })
3438
+ ] })
3439
+ }
3440
+ );
3441
+ }
3442
+ function renderRoomStationObject(params) {
3443
+ const deskFill = params.active ? "rgba(158,107,65,0.98)" : "rgba(138,96,65,0.84)";
3444
+ const chairFill = params.active ? "rgba(93,128,103,0.95)" : "rgba(91,91,78,0.72)";
3445
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("g", { opacity: params.active ? 0.96 : 0.66, children: [
3446
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x - 23, y: params.node.y - 19, width: "46", height: "24", fill: deskFill, stroke: "rgba(72,50,33,0.56)", strokeWidth: "3" }),
3447
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x - 15, y: params.node.y - 14, width: "18", height: "7", fill: "rgba(231,211,148,0.76)" }),
3448
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x + 7, y: params.node.y - 15, width: "10", height: "9", fill: "rgba(79,102,96,0.9)" }),
3449
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x - 12, y: params.node.y + 8, width: "24", height: "12", fill: chairFill }),
3450
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x - 21, y: params.node.y + 22, width: "8", height: "7", fill: "rgba(72,50,33,0.34)" }),
3451
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x + 13, y: params.node.y + 22, width: "8", height: "7", fill: "rgba(72,50,33,0.34)" }),
3452
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x + 20, y: params.node.y - 26, width: "22", height: "14", fill: "rgba(250,236,178,0.92)", stroke: "rgba(110,77,47,0.54)", strokeWidth: "2" }),
3453
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3454
+ "text",
3455
+ {
3456
+ x: params.node.x + 31,
3457
+ y: params.node.y - 16,
3458
+ textAnchor: "middle",
3459
+ fill: "rgba(72,50,33,0.78)",
3460
+ fontSize: "8",
3461
+ fontWeight: "800",
3462
+ fontFamily: "var(--font-geist-mono, var(--font-sans))",
3463
+ children: params.index + 1
3464
+ }
3465
+ ),
3466
+ params.active ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("rect", { x: params.node.x - 29, y: params.node.y - 25, width: "58", height: "58", fill: "none", stroke: "rgba(17,17,19,0.42)", strokeWidth: "2", strokeDasharray: "4 5" }) : null
3467
+ ] }, `focused-station-${params.node.item.id}`);
3468
+ }
3469
+ function WorkboardGameRoom(props) {
3470
+ const [hoveredTag, setHoveredTag] = React5.useState(null);
3471
+ const hubPoint = React5.useMemo(
3472
+ () => props.gameMap.pointsOfInterest.find((item) => item.kind === "hub") || {
3473
+ id: `${props.zone.id}-hub-fallback`,
3474
+ kind: "hub",
3475
+ x: WORKBOARD_STAGE_WIDTH / 2,
3476
+ y: WORKBOARD_STAGE_HEIGHT / 2
3477
+ },
3478
+ [props.gameMap.pointsOfInterest, props.zone.id]
3479
+ );
3480
+ const center = { x: hubPoint.x, y: hubPoint.y };
3481
+ const roomNodes = React5.useMemo(
3482
+ () => props.gameMap.actors.filter((actor) => actor.zoneId === props.zone.id && actor.focusedAnchor).map((actor) => ({
3483
+ item: actor.agent,
3484
+ x: actor.focusedAnchor?.x || hubPoint.x,
3485
+ y: actor.focusedAnchor?.y || hubPoint.y,
3486
+ routeId: actor.focusedRouteId
3487
+ })),
3488
+ [hubPoint.x, hubPoint.y, props.gameMap.actors, props.zone.id]
3489
+ );
3490
+ const activeItem = React5.useMemo(
3491
+ () => props.items.find((item) => item.id === props.selectedAgentId) || props.items[0] || null,
3492
+ [props.items, props.selectedAgentId]
3493
+ );
3494
+ const activeNode = React5.useMemo(
3495
+ () => activeItem ? roomNodes.find((entry) => entry.item.id === activeItem.id) || null : null,
3496
+ [activeItem, roomNodes]
3497
+ );
3498
+ const activePoint = React5.useMemo(() => {
3499
+ if (!activeItem || !activeNode) return null;
3500
+ return resolveRoomPoint({
3501
+ agentId: activeNode.item.id,
3502
+ fallback: { x: activeNode.x, y: activeNode.y },
3503
+ motionFrames: props.motionFrames
3504
+ });
3505
+ }, [activeItem, activeNode, props.motionFrames]);
3506
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3507
+ "div",
3508
+ {
3509
+ className: cn(
3510
+ "relative overflow-hidden border-2 bg-[linear-gradient(145deg,rgba(251,250,247,0.96),rgba(245,248,245,0.88))]",
3511
+ props.zone.borderClassName
3512
+ ),
3513
+ style: { width: WORKBOARD_STAGE_WIDTH, height: WORKBOARD_STAGE_HEIGHT, clipPath: PIXEL_PANEL_CLIP3, imageRendering: "pixelated" },
3514
+ children: [
3515
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3516
+ WorkboardRoomField,
3517
+ {
3518
+ zone: props.zone,
3519
+ stageWidth: WORKBOARD_STAGE_WIDTH,
3520
+ stageHeight: WORKBOARD_STAGE_HEIGHT,
3521
+ pointsOfInterest: props.gameMap.pointsOfInterest,
3522
+ areaLabels: props.gameMap.areaLabels
3523
+ }
3524
+ ),
3525
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("pointer-events-none absolute left-1/2 top-1/2 h-56 w-56 -translate-x-1/2 -translate-y-1/2", props.zone.glowClassName) }),
3526
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RoomEntranceSign, { zone: props.zone, flowMode: props.flowMode }),
3527
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3528
+ "svg",
3529
+ {
3530
+ viewBox: `0 0 ${WORKBOARD_STAGE_WIDTH} ${WORKBOARD_STAGE_HEIGHT}`,
3531
+ className: "pointer-events-none absolute inset-0 h-full w-full",
3532
+ preserveAspectRatio: "xMidYMid meet",
3533
+ "aria-hidden": "true",
3534
+ children: [
3535
+ props.gameMap.patrols.map((route) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RoomPatrolTrail, { route }, route.id)),
3536
+ activePoint ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("g", { children: [
3537
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3538
+ "path",
3539
+ {
3540
+ d: buildWorkboardTilePath({ from: center, to: activePoint }),
3541
+ fill: "none",
3542
+ stroke: "rgba(245,211,142,0.58)",
3543
+ strokeWidth: "10",
3544
+ strokeOpacity: "0.52",
3545
+ strokeLinecap: "square"
3546
+ }
3547
+ ),
3548
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3549
+ "rect",
3550
+ {
3551
+ x: activePoint.x - 14,
3552
+ y: activePoint.y - 14,
3553
+ width: "28",
3554
+ height: "28",
3555
+ fill: "none",
3556
+ className: props.zone.lineClassName,
3557
+ strokeWidth: "2",
3558
+ strokeDasharray: "4 5",
3559
+ style: { animation: "workboard-dash 1.5s linear infinite" }
3560
+ }
3561
+ ),
3562
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3563
+ "rect",
3564
+ {
3565
+ x: center.x - 7,
3566
+ y: center.y - 7,
3567
+ width: "14",
3568
+ height: "14",
3569
+ fill: "none",
3570
+ className: props.zone.lineClassName,
3571
+ strokeWidth: "2",
3572
+ strokeOpacity: "0.72"
3573
+ }
3574
+ )
3575
+ ] }) : null,
3576
+ roomNodes.map((node) => {
3577
+ const point = resolveRoomPoint({
3578
+ agentId: node.item.id,
3579
+ fallback: { x: node.x, y: node.y },
3580
+ motionFrames: props.motionFrames
3581
+ });
3582
+ const path = buildWorkboardTilePath({ from: center, to: point });
3583
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3584
+ "path",
3585
+ {
3586
+ d: path,
3587
+ fill: "none",
3588
+ className: cn(
3589
+ props.zone.lineClassName,
3590
+ props.selectedAgentId === node.item.id ? "opacity-78" : "opacity-34"
3591
+ ),
3592
+ strokeWidth: props.selectedAgentId === node.item.id ? 2.8 : 1.5,
3593
+ strokeDasharray: props.selectedAgentId === node.item.id ? "6 8" : "4 10",
3594
+ style: {
3595
+ animation: `workboard-dash ${props.flowMode === "turbo" ? "1.6s" : "2.8s"} linear infinite`
3596
+ }
3597
+ },
3598
+ `focused-line-${node.item.id}`
3599
+ );
3600
+ }),
3601
+ roomNodes.map(
3602
+ (node, index) => renderRoomStationObject({
3603
+ node,
3604
+ index,
3605
+ active: props.selectedAgentId === node.item.id
3606
+ })
3607
+ )
3608
+ ]
3609
+ }
3610
+ ),
3611
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RoomHubMapObject, { badge: props.zone.badge, title: props.zone.title, point: hubPoint }),
3612
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3613
+ "div",
3614
+ {
3615
+ className: "pointer-events-none absolute z-20 border-2 border-[#6e4d2f]/70 bg-[#fff1bd]/90 px-2 py-1 text-[10px] uppercase tracking-[0.14em] text-[#6e4d2f]/70 shadow-[3px_3px_0_rgba(72,50,33,0.16)]",
3616
+ style: { left: hubPoint.x + 38, top: hubPoint.y + 18, clipPath: PIXEL_PANEL_CLIP3 },
3617
+ children: [
3618
+ "sprites ",
3619
+ props.items.length
3620
+ ]
3621
+ }
3622
+ ),
3623
+ roomNodes.map((node) => {
3624
+ const point = resolveRoomPoint({
3625
+ agentId: node.item.id,
3626
+ fallback: { x: node.x, y: node.y },
3627
+ motionFrames: props.motionFrames
3628
+ });
3629
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3630
+ WorkboardStageAgentNode,
3631
+ {
3632
+ item: node.item,
3633
+ zone: props.zone,
3634
+ point,
3635
+ active: props.selectedAgentId === node.item.id,
3636
+ faded: false,
3637
+ mode: "focused",
3638
+ onSelect: props.onSelectAgent,
3639
+ onHoverChange: setHoveredTag
3640
+ },
3641
+ `focused-node-${node.item.id}`
3642
+ );
3643
+ }),
3644
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(WorkboardRoomQuestLedger, { item: activeItem }),
3645
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(WorkboardRoomMiniMap, { activePoint, activeItemId: activeItem?.id, nodes: roomNodes }),
3646
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ActiveSpeechBubble, { item: activeItem, point: activePoint }),
3647
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3648
+ "svg",
3649
+ {
3650
+ viewBox: `0 0 ${WORKBOARD_STAGE_WIDTH} ${WORKBOARD_STAGE_HEIGHT}`,
3651
+ className: "pointer-events-none absolute inset-0 h-full w-full",
3652
+ preserveAspectRatio: "xMidYMid meet",
3653
+ "aria-hidden": "true",
3654
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PixelHoverTag, { tag: hoveredTag, stageWidth: WORKBOARD_STAGE_WIDTH, stageHeight: WORKBOARD_STAGE_HEIGHT })
3655
+ }
3656
+ )
3657
+ ]
3658
+ }
3659
+ );
3660
+ }
3661
+
3662
+ // src/components/workboard-motion.ts
3663
+ var React6 = __toESM(require("react"), 1);
3664
+ function distance(a, b) {
3665
+ return Math.hypot(b.x - a.x, b.y - a.y);
3666
+ }
3667
+ function resolveDirection(params) {
3668
+ const dx = params.to.x - params.from.x;
3669
+ const dy = params.to.y - params.from.y;
3670
+ if (Math.abs(dx) >= Math.abs(dy)) {
3671
+ return dx < 0 ? "left" : "right";
3672
+ }
3673
+ return dy < 0 ? "up" : "down";
3674
+ }
3675
+ function resolveRouteFrame(params) {
3676
+ if (params.route.length < 2) {
3677
+ return {
3678
+ ...params.route[0] || { x: 0, y: 0 },
3679
+ direction: "down",
3680
+ state: "dwell"
3681
+ };
3682
+ }
3683
+ const dwellRatio = Math.min(Math.max(params.dwellRatio || 0, 0), 0.72);
3684
+ if (dwellRatio > 0) {
3685
+ const legCount = params.route.length;
3686
+ const legProgress = params.progress % 1 * legCount;
3687
+ const legIndex = Math.floor(legProgress) % legCount;
3688
+ const localProgress = legProgress - Math.floor(legProgress);
3689
+ const from = params.route[legIndex];
3690
+ const to = params.route[(legIndex + 1) % params.route.length];
3691
+ const travelRatio = 1 - dwellRatio;
3692
+ const direction = resolveDirection({ from, to });
3693
+ if (localProgress > travelRatio) {
3694
+ return {
3695
+ ...to,
3696
+ direction,
3697
+ state: "dwell"
3698
+ };
3699
+ }
3700
+ const easedProgress = Math.min(localProgress / travelRatio, 1);
3701
+ return {
3702
+ x: from.x + (to.x - from.x) * easedProgress,
3703
+ y: from.y + (to.y - from.y) * easedProgress,
3704
+ direction,
3705
+ state: "walking"
3706
+ };
3707
+ }
3708
+ const segments = params.route.map((point, index) => {
3709
+ const next = params.route[(index + 1) % params.route.length];
3710
+ return {
3711
+ from: point,
3712
+ to: next,
3713
+ length: distance(point, next)
3714
+ };
3715
+ });
3716
+ const totalLength = segments.reduce((acc, segment) => acc + segment.length, 0);
3717
+ if (totalLength <= 0) {
3718
+ return {
3719
+ ...params.route[0],
3720
+ direction: "down",
3721
+ state: "dwell"
3722
+ };
3723
+ }
3724
+ let cursor = params.progress % 1 * totalLength;
3725
+ for (const segment of segments) {
3726
+ if (cursor <= segment.length) {
3727
+ const ratio = segment.length <= 0 ? 0 : cursor / segment.length;
3728
+ return {
3729
+ x: segment.from.x + (segment.to.x - segment.from.x) * ratio,
3730
+ y: segment.from.y + (segment.to.y - segment.from.y) * ratio,
3731
+ direction: resolveDirection({ from: segment.from, to: segment.to }),
3732
+ state: "walking"
3733
+ };
3734
+ }
3735
+ cursor -= segment.length;
3736
+ }
3737
+ return {
3738
+ ...params.route[0],
3739
+ direction: "down",
3740
+ state: "dwell"
3741
+ };
3742
+ }
3743
+ function snapPoint(params) {
3744
+ const snapSize = params.snapSize || 0;
3745
+ if (snapSize <= 0) {
3746
+ return params.point;
3747
+ }
3748
+ return {
3749
+ ...params.point,
3750
+ x: Math.round(params.point.x / snapSize) * snapSize,
3751
+ y: Math.round(params.point.y / snapSize) * snapSize
3752
+ };
3753
+ }
3754
+ function useWorkboardMotion(params) {
3755
+ const [frames, setFrames] = React6.useState({});
3756
+ React6.useEffect(() => {
3757
+ if (params.nodes.length === 0) {
3758
+ setFrames({});
3759
+ return;
3760
+ }
3761
+ const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
3762
+ if (reduceMotion) {
3763
+ const stillFrames = params.nodes.reduce(
3764
+ (acc, node) => {
3765
+ acc[node.id] = {
3766
+ x: node.anchor.x,
3767
+ y: node.anchor.y,
3768
+ direction: "down",
3769
+ state: "dwell"
3770
+ };
3771
+ return acc;
3772
+ },
3773
+ {}
3774
+ );
3775
+ setFrames(stillFrames);
3776
+ return;
3777
+ }
3778
+ let rafId = 0;
3779
+ let start = performance.now();
3780
+ const frame = (now) => {
3781
+ const elapsed = (now - start) / 1e3;
3782
+ const flowFactor = params.flowMode === "turbo" ? 1.45 : 0.78;
3783
+ const nextFrames = params.nodes.reduce(
3784
+ (acc, node) => {
3785
+ if (node.mode === "route" && node.route && node.route.length > 1) {
3786
+ const routePoint = resolveRouteFrame({
3787
+ route: node.route,
3788
+ progress: elapsed * node.speed * 0.09 * flowFactor + node.phase * 0.07,
3789
+ dwellRatio: node.dwellRatio
3790
+ });
3791
+ acc[node.id] = snapPoint({ point: routePoint, snapSize: node.snapSize });
3792
+ return acc;
3793
+ }
3794
+ const t = elapsed * node.speed * flowFactor + node.phase;
3795
+ const driftX = Math.sin(t) * node.swayX + Math.cos(t * 0.61 + node.phase) * node.swayX * 0.4;
3796
+ const driftY = Math.cos(t * 0.9 + node.phase * 0.8) * node.swayY + Math.sin(t * 0.55) * node.swayY * 0.35;
3797
+ const point = {
3798
+ x: node.anchor.x + driftX,
3799
+ y: node.anchor.y + driftY
3800
+ };
3801
+ acc[node.id] = snapPoint({
3802
+ snapSize: node.snapSize,
3803
+ point: {
3804
+ ...point,
3805
+ direction: resolveDirection({ from: node.anchor, to: point }),
3806
+ state: "walking"
3807
+ }
3808
+ });
3809
+ return acc;
3810
+ },
3811
+ {}
3812
+ );
3813
+ setFrames(nextFrames);
3814
+ rafId = window.requestAnimationFrame(frame);
3815
+ };
3816
+ rafId = window.requestAnimationFrame(frame);
3817
+ return () => {
3818
+ window.cancelAnimationFrame(rafId);
3819
+ };
3820
+ }, [params.flowMode, params.nodes]);
3821
+ return frames;
3822
+ }
3823
+
3824
+ // src/components/workboard.tsx
3825
+ var import_jsx_runtime25 = require("react/jsx-runtime");
3826
+ var PIXEL_PANEL_CLIP4 = "polygon(0 6px,6px 6px,6px 0,calc(100% - 6px) 0,calc(100% - 6px) 6px,100% 6px,100% calc(100% - 6px),calc(100% - 6px) calc(100% - 6px),calc(100% - 0px) 100%,6px 100%,6px calc(100% - 6px),0 calc(100% - 6px))";
3827
+ function resolveSelectedAgent(params) {
3828
+ const items = params.board?.agents || [];
3829
+ if (items.length === 0) return null;
3830
+ return items.find((item) => item.id === params.selectedAgentId) || items[0] || null;
3831
+ }
3832
+ function resolveZoneLead(params) {
3833
+ const items = (params.board?.agents || []).filter((item) => resolveZoneId(item) === params.zoneId);
3834
+ if (items.length === 0) return null;
3835
+ return items.find((item) => item.snapshot.current.some((entry) => entry.status === "active")) || items.find((item) => item.running) || items[0] || null;
3836
+ }
3837
+ function useWorkboardStageViewportScale(params) {
3838
+ const [size, setSize] = React7.useState({ width: WORKBOARD_STAGE_WIDTH, height: WORKBOARD_STAGE_HEIGHT });
3839
+ React7.useEffect(() => {
3840
+ const element = params.viewportRef.current;
3841
+ if (!element) return void 0;
3842
+ const updateSize = () => {
3843
+ const rect2 = element.getBoundingClientRect();
3844
+ setSize({
3845
+ width: Math.max(1, rect2.width),
3846
+ height: Math.max(1, rect2.height)
3847
+ });
3848
+ };
3849
+ updateSize();
3850
+ if (typeof ResizeObserver === "undefined") {
3851
+ window.addEventListener("resize", updateSize);
3852
+ return () => window.removeEventListener("resize", updateSize);
3853
+ }
3854
+ const observer = new ResizeObserver(updateSize);
3855
+ observer.observe(element);
3856
+ return () => observer.disconnect();
3857
+ }, [params.viewportRef]);
3858
+ const horizontalPadding = params.isFullscreen ? 0 : 16;
3859
+ const verticalHudReserve = params.isFullscreen ? 0 : 20;
3860
+ const widthScale = (size.width - horizontalPadding) / WORKBOARD_STAGE_WIDTH;
3861
+ const heightScale = (size.height - verticalHudReserve) / WORKBOARD_STAGE_HEIGHT;
3862
+ const rawScale = params.isFullscreen ? Math.max(widthScale, heightScale) : Math.min(widthScale, heightScale);
3863
+ return Math.max(params.isFullscreen ? 1 : 0.72, Math.min(params.isFullscreen ? 4 : 1.35, rawScale || 1));
3864
+ }
3865
+ function WorkboardScaledStage(props) {
3866
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3867
+ "div",
3868
+ {
3869
+ className: "relative shrink-0",
3870
+ style: {
3871
+ width: WORKBOARD_STAGE_WIDTH * props.scale,
3872
+ height: WORKBOARD_STAGE_HEIGHT * props.scale
3873
+ },
3874
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3875
+ "div",
3876
+ {
3877
+ className: "absolute left-0 top-0",
3878
+ style: {
3879
+ width: WORKBOARD_STAGE_WIDTH,
3880
+ height: WORKBOARD_STAGE_HEIGHT,
3881
+ transform: `scale(${props.scale})`,
3882
+ transformOrigin: "left top",
3883
+ imageRendering: "pixelated"
3884
+ },
3885
+ children: props.children
3886
+ }
3887
+ )
3888
+ }
3889
+ );
3890
+ }
3891
+ function WorkboardGameHud(props) {
3892
+ const worldLine = [
3893
+ `sprites ${props.board.summary.totalAgents}`,
3894
+ `live ${props.board.summary.liveAgents}`,
3895
+ `active ${props.board.summary.activeAgents}`,
3896
+ `quiet ${props.board.summary.quietAgents}`,
3897
+ props.selected ? `focus ${props.selected.name}` : "focus world",
3898
+ `tick ${formatWorkboardRelativeTime(props.board.collectedAt)}`
3899
+ ];
3900
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
3901
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "absolute inset-x-2 top-2 z-40 flex flex-wrap items-start justify-between gap-2", children: [
3902
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3903
+ "div",
3904
+ {
3905
+ className: "border-2 border-border/70 bg-[rgba(255,252,247,0.92)] px-3 py-2 shadow-[0_3px_0_rgba(17,17,19,0.12)]",
3906
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
3907
+ children: [
3908
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-[10px] uppercase tracking-[0.2em] text-foreground/42", children: props.stageLevel === "clusters" ? "world map" : `${props.activeZone.title} room` }),
3909
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-1 text-lg font-semibold leading-none tracking-[-0.06em] text-foreground", children: "Workboard Game World" }),
3910
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 text-[10px] uppercase tracking-[0.16em] text-foreground/42", children: worldLine.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(React7.Fragment, { children: [
3911
+ index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-foreground/20", children: "/" }) : null,
3912
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: item })
3913
+ ] }, item)) })
3914
+ ]
3915
+ }
3916
+ ),
3917
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-wrap justify-end gap-1.5", children: [
3918
+ props.stageLevel === "agents" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3919
+ "button",
3920
+ {
3921
+ type: "button",
3922
+ onClick: props.onBackToAtlas,
3923
+ className: "border-2 border-border/70 bg-[rgba(255,252,247,0.9)] px-2 py-1 text-[11px] uppercase tracking-[0.14em] shadow-[0_2px_0_rgba(17,17,19,0.12)] transition-[filter] hover:brightness-105",
3924
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
3925
+ children: "world"
3926
+ }
3927
+ ) : null,
3928
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3929
+ "button",
3930
+ {
3931
+ type: "button",
3932
+ onClick: props.onToggleFlowMode,
3933
+ className: "border-2 border-border/70 bg-[rgba(255,252,247,0.9)] px-2 py-1 text-[11px] uppercase tracking-[0.14em] shadow-[0_2px_0_rgba(17,17,19,0.12)] transition-[filter] hover:brightness-105",
3934
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
3935
+ "aria-pressed": props.flowMode === "turbo",
3936
+ children: props.flowMode
3937
+ }
3938
+ ),
3939
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3940
+ "button",
3941
+ {
3942
+ type: "button",
3943
+ onClick: () => props.onRefresh?.(),
3944
+ className: "inline-flex items-center gap-1.5 border-2 border-border/70 bg-[rgba(255,252,247,0.9)] px-2 py-1 text-[11px] uppercase tracking-[0.14em] shadow-[0_2px_0_rgba(17,17,19,0.12)] transition-[filter] hover:brightness-105 disabled:opacity-45",
3945
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
3946
+ disabled: !props.onRefresh,
3947
+ children: [
3948
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.RefreshCwIcon, { className: cn("size-3.5", props.loading ? "animate-spin" : "") }),
3949
+ "tick"
3950
+ ]
3951
+ }
3952
+ ),
3953
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3954
+ "button",
3955
+ {
3956
+ type: "button",
3957
+ onClick: props.onToggleFullscreen,
3958
+ className: "inline-flex items-center gap-1.5 border-2 border-border/70 bg-[rgba(255,252,247,0.9)] px-2 py-1 text-[11px] uppercase tracking-[0.14em] shadow-[0_2px_0_rgba(17,17,19,0.12)] transition-[filter] hover:brightness-105",
3959
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
3960
+ "aria-pressed": props.isFullscreen,
3961
+ children: [
3962
+ props.isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.Maximize2Icon, { className: "size-3.5" }),
3963
+ props.isFullscreen ? "exit" : "full"
3964
+ ]
3965
+ }
3966
+ )
3967
+ ] })
3968
+ ] }),
3969
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "absolute inset-x-2 bottom-2 z-40 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3970
+ "div",
3971
+ {
3972
+ className: "flex max-w-full gap-1 overflow-x-auto border-2 border-border/70 bg-[rgba(255,252,247,0.9)] px-2 py-1.5 shadow-[0_3px_0_rgba(17,17,19,0.12)]",
3973
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
3974
+ "aria-label": "Workboard zone portals",
3975
+ children: props.zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3976
+ WorkboardZonePortalButton,
3977
+ {
3978
+ zone,
3979
+ current: zone.id === props.activeZone.id,
3980
+ onSelect: props.onSelectZone
3981
+ },
3982
+ zone.id
3983
+ ))
3984
+ }
3985
+ ) }),
3986
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "pointer-events-none absolute bottom-[4.7rem] left-2 z-40 hidden border-2 border-border/60 bg-[rgba(255,252,247,0.82)] px-2 py-1 text-[9px] uppercase tracking-[0.13em] text-foreground/44 shadow-[0_2px_0_rgba(17,17,19,0.1)] md:block", style: { clipPath: PIXEL_PANEL_CLIP4 }, children: "left/right switch zone / enter open / esc world" })
3987
+ ] });
3988
+ }
3989
+ function WorkboardZonePortalButton(props) {
3990
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3991
+ "button",
3992
+ {
3993
+ type: "button",
3994
+ onClick: () => props.onSelect?.(props.zone.id),
3995
+ className: cn(
3996
+ "group inline-flex min-w-24 items-center gap-2 border border-border/50 px-2 py-1 text-left transition-[filter,transform] duration-200 hover:-translate-y-0.5 hover:brightness-105 focus:outline-none focus-visible:-translate-y-0.5",
3997
+ props.current ? "bg-foreground text-background" : "bg-[rgba(255,252,247,0.76)] text-foreground"
3998
+ ),
3999
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
4000
+ "aria-pressed": props.current,
4001
+ children: [
4002
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4003
+ "span",
4004
+ {
4005
+ className: cn(
4006
+ "grid size-5 place-items-center border text-[10px] font-semibold leading-none",
4007
+ props.current ? "border-background/70" : "border-foreground/35"
4008
+ ),
4009
+ "aria-hidden": "true",
4010
+ children: props.zone.count
4011
+ }
4012
+ ),
4013
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "min-w-0", children: [
4014
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "block truncate text-[10px] font-semibold uppercase tracking-[0.13em]", children: props.zone.badge }),
4015
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: cn("block truncate text-[9px]", props.current ? "text-background/70" : "text-foreground/46"), children: "portal" })
4016
+ ] })
4017
+ ]
4018
+ }
4019
+ );
4020
+ }
4021
+ function WorkboardWorldPortalOverlay(props) {
4022
+ if (!props.portal) return null;
4023
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4024
+ "div",
4025
+ {
4026
+ className: "pointer-events-none absolute inset-0 z-50 grid place-items-center bg-[rgba(255,252,247,0.18)]",
4027
+ "aria-hidden": "true",
4028
+ children: [
4029
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "absolute inset-y-0 left-0 w-1/2 origin-left bg-[rgba(17,17,19,0.82)] workboard-portal-left" }),
4030
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "absolute inset-y-0 right-0 w-1/2 origin-right bg-[rgba(17,17,19,0.82)] workboard-portal-right" }),
4031
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4032
+ "div",
4033
+ {
4034
+ className: "relative z-10 border-2 border-background/80 bg-[rgba(17,17,19,0.88)] px-4 py-3 text-center text-background shadow-[0_4px_0_rgba(17,17,19,0.2)] workboard-portal-label",
4035
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
4036
+ children: [
4037
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-[10px] uppercase tracking-[0.22em] text-background/58", children: props.portal.mode === "enter" ? "enter room" : "return atlas" }),
4038
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-1 text-base font-semibold tracking-[-0.05em]", children: props.portal.label })
4039
+ ]
4040
+ }
4041
+ )
4042
+ ]
4043
+ },
4044
+ props.portal.key
4045
+ );
4046
+ }
4047
+ function WorkboardGameStyles() {
4048
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("style", { children: `
4049
+ @keyframes workboard-dash {
4050
+ from { stroke-dashoffset: 0; }
4051
+ to { stroke-dashoffset: 18; }
4052
+ }
4053
+ @keyframes workboard-pulse {
4054
+ 0% { opacity: 0.15; transform: scale(0.98); }
4055
+ 50% { opacity: 0.5; transform: scale(1.08); }
4056
+ 100% { opacity: 0.15; transform: scale(0.98); }
4057
+ }
4058
+ @keyframes workboard-sprite-step {
4059
+ 0% { translate: 0 0; }
4060
+ 50% { translate: 0 -1px; }
4061
+ 100% { translate: 0 0; }
4062
+ }
4063
+ @keyframes workboard-world-scan {
4064
+ 0% { transform: translateY(-16px); opacity: 0.08; }
4065
+ 50% { opacity: 0.18; }
4066
+ 100% { transform: translateY(16px); opacity: 0.08; }
4067
+ }
4068
+ @keyframes workboard-portal-left {
4069
+ 0% { transform: scaleX(0); }
4070
+ 35% { transform: scaleX(1); }
4071
+ 70% { transform: scaleX(1); }
4072
+ 100% { transform: scaleX(0); }
4073
+ }
4074
+ @keyframes workboard-portal-right {
4075
+ 0% { transform: scaleX(0); }
4076
+ 35% { transform: scaleX(1); }
4077
+ 70% { transform: scaleX(1); }
4078
+ 100% { transform: scaleX(0); }
4079
+ }
4080
+ @keyframes workboard-portal-label {
4081
+ 0% { opacity: 0; transform: translateY(6px) scale(0.96); }
4082
+ 28% { opacity: 1; transform: translateY(0) scale(1); }
4083
+ 74% { opacity: 1; transform: translateY(0) scale(1); }
4084
+ 100% { opacity: 0; transform: translateY(-6px) scale(0.98); }
4085
+ }
4086
+ .workboard-portal-left { animation: workboard-portal-left 560ms steps(7, end) both; }
4087
+ .workboard-portal-right { animation: workboard-portal-right 560ms steps(7, end) both; }
4088
+ .workboard-portal-label { animation: workboard-portal-label 560ms steps(6, end) both; }
4089
+ @media (prefers-reduced-motion: reduce) {
4090
+ .workboard-portal-left,
4091
+ .workboard-portal-right,
4092
+ .workboard-portal-label {
4093
+ animation-duration: 1ms;
4094
+ }
4095
+ }
4096
+ ` });
4097
+ }
4098
+ function resolveAdjacentZoneId(params) {
4099
+ if (params.zones.length === 0) return params.activeZoneId;
4100
+ const currentIndex = Math.max(
4101
+ 0,
4102
+ params.zones.findIndex((zone) => zone.id === params.activeZoneId)
4103
+ );
4104
+ const nextIndex = (currentIndex + params.direction + params.zones.length) % params.zones.length;
4105
+ return params.zones[nextIndex]?.id || params.activeZoneId;
4106
+ }
4107
+ function Workboard(props) {
4108
+ const { board, loading, selectedAgentId, onRefresh, onSelectAgent, className } = props;
4109
+ const selected = resolveSelectedAgent({ board, selectedAgentId });
4110
+ const containerRef = React7.useRef(null);
4111
+ const stageViewportRef = React7.useRef(null);
4112
+ const [stageLevel, setStageLevel] = React7.useState("clusters");
4113
+ const [detailsCollapsed, setDetailsCollapsed] = React7.useState(true);
4114
+ const [flowMode, setFlowMode] = React7.useState("cruise");
4115
+ const [isFullscreen, setIsFullscreen] = React7.useState(false);
4116
+ const [portal, setPortal] = React7.useState(null);
4117
+ const previousSelectedIdRef = React7.useRef(selected?.id);
4118
+ const [activeZoneId, setActiveZoneId] = React7.useState(
4119
+ () => selected ? resolveZoneId(selected) : "engaged"
4120
+ );
4121
+ React7.useEffect(() => {
4122
+ if (!selected?.id) {
4123
+ previousSelectedIdRef.current = void 0;
4124
+ return;
4125
+ }
4126
+ if (selected.id === previousSelectedIdRef.current) return;
4127
+ previousSelectedIdRef.current = selected.id;
4128
+ setActiveZoneId(resolveZoneId(selected));
4129
+ }, [selected]);
4130
+ React7.useEffect(() => {
4131
+ if (!portal) return void 0;
4132
+ const timeout = window.setTimeout(() => setPortal(null), 620);
4133
+ return () => window.clearTimeout(timeout);
4134
+ }, [portal]);
4135
+ React7.useEffect(() => {
4136
+ const onFullscreenChange = () => {
4137
+ setIsFullscreen(document.fullscreenElement === containerRef.current);
4138
+ };
4139
+ document.addEventListener("fullscreenchange", onFullscreenChange);
4140
+ return () => document.removeEventListener("fullscreenchange", onFullscreenChange);
4141
+ }, []);
4142
+ const activeZone = resolveZoneDefinition(activeZoneId);
4143
+ const activeZoneItems = React7.useMemo(
4144
+ () => (board?.agents || []).filter((item) => resolveZoneId(item) === activeZoneId),
4145
+ [activeZoneId, board]
4146
+ );
4147
+ const selectedPeers = React7.useMemo(
4148
+ () => (board?.agents || []).filter((item) => resolveZoneId(item) === activeZoneId),
4149
+ [activeZoneId, board]
4150
+ );
4151
+ const gameMap = React7.useMemo(
4152
+ () => board ? buildWorkboardGameMapConfig({
4153
+ board,
4154
+ activeZoneId,
4155
+ selectedAgentId: selected?.id
4156
+ }) : null,
4157
+ [activeZoneId, board, selected?.id]
4158
+ );
4159
+ const motionNodes = React7.useMemo(() => {
4160
+ if (!gameMap) return [];
4161
+ if (stageLevel === "clusters") {
4162
+ return gameMap.actors.map((actor, index) => {
4163
+ const route = gameMap.corridors.find((item) => item.id === `corridor-${actor.id}`);
4164
+ return {
4165
+ id: actor.id,
4166
+ anchor: actor.overviewAnchor,
4167
+ swayX: 6 + index % 3 * 2.5,
4168
+ swayY: 4 + index % 4 * 1.7,
4169
+ phase: index * 0.9,
4170
+ speed: 0.8 + index % 5 * 0.08,
4171
+ mode: "route",
4172
+ route: route?.points || actor.overviewRoute,
4173
+ dwellRatio: route?.dwellRatio,
4174
+ snapSize: route?.snapSize
4175
+ };
4176
+ });
4177
+ }
4178
+ return gameMap.actors.filter((actor) => actor.zoneId === activeZoneId && actor.focusedAnchor).map((actor, index) => {
4179
+ const route = gameMap.patrols.find((item) => item.id === actor.focusedRouteId);
4180
+ const fallbackPoint = actor.focusedAnchor || {
4181
+ x: WORKBOARD_STAGE_WIDTH / 2,
4182
+ y: WORKBOARD_STAGE_HEIGHT / 2
4183
+ };
4184
+ return {
4185
+ id: actor.id,
4186
+ anchor: fallbackPoint,
4187
+ swayX: 9 + index % 3 * 2.2,
4188
+ swayY: 6 + index % 4 * 1.6,
4189
+ phase: index * 0.82,
4190
+ speed: 0.95 + index % 5 * 0.1,
4191
+ mode: "route",
4192
+ route: route?.points || gameMap.patrols[index % Math.max(gameMap.patrols.length, 1)]?.points || [fallbackPoint],
4193
+ dwellRatio: route?.dwellRatio,
4194
+ snapSize: route?.snapSize
4195
+ };
4196
+ });
4197
+ }, [activeZoneId, gameMap, stageLevel]);
4198
+ const motionFrames = useWorkboardMotion({ nodes: motionNodes, flowMode });
4199
+ const stageScale = useWorkboardStageViewportScale({
4200
+ viewportRef: stageViewportRef,
4201
+ isFullscreen
4202
+ });
4203
+ const triggerPortal = React7.useCallback((label, mode) => {
4204
+ setPortal((prev) => ({
4205
+ key: (prev?.key || 0) + 1,
4206
+ label,
4207
+ mode
4208
+ }));
4209
+ }, []);
4210
+ const openZone = React7.useCallback(
4211
+ (zoneId) => {
4212
+ triggerPortal(resolveZoneDefinition(zoneId).title, "enter");
4213
+ setActiveZoneId(zoneId);
4214
+ setStageLevel("agents");
4215
+ setDetailsCollapsed(true);
4216
+ const lead = resolveZoneLead({ board, zoneId });
4217
+ if (lead) onSelectAgent?.(lead.id);
4218
+ },
4219
+ [board, onSelectAgent, triggerPortal]
4220
+ );
4221
+ const openAgent = React7.useCallback(
4222
+ (agentId) => {
4223
+ const item = (board?.agents || []).find((entry) => entry.id === agentId);
4224
+ if (!item) return;
4225
+ const nextZoneId = resolveZoneId(item);
4226
+ if (stageLevel === "clusters" || nextZoneId !== activeZoneId) {
4227
+ triggerPortal(resolveZoneDefinition(nextZoneId).title, "enter");
4228
+ }
4229
+ setActiveZoneId(nextZoneId);
4230
+ setStageLevel("agents");
4231
+ setDetailsCollapsed(true);
4232
+ onSelectAgent?.(agentId);
4233
+ },
4234
+ [activeZoneId, board, onSelectAgent, stageLevel, triggerPortal]
4235
+ );
4236
+ const backToAtlas = React7.useCallback(() => {
4237
+ triggerPortal("World Atlas", "world");
4238
+ setStageLevel("clusters");
4239
+ }, [triggerPortal]);
4240
+ const handleWorldKeyDown = React7.useCallback(
4241
+ (event) => {
4242
+ if (!gameMap) return;
4243
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
4244
+ event.preventDefault();
4245
+ const nextZoneId = resolveAdjacentZoneId({
4246
+ zones: gameMap.zones,
4247
+ activeZoneId,
4248
+ direction: event.key === "ArrowRight" ? 1 : -1
4249
+ });
4250
+ setActiveZoneId(nextZoneId);
4251
+ return;
4252
+ }
4253
+ if (event.key === "Enter" && stageLevel === "clusters") {
4254
+ event.preventDefault();
4255
+ openZone(activeZoneId);
4256
+ return;
4257
+ }
4258
+ if (event.key === "Escape" && stageLevel === "agents") {
4259
+ event.preventDefault();
4260
+ backToAtlas();
4261
+ }
4262
+ },
4263
+ [activeZoneId, backToAtlas, gameMap, openZone, stageLevel]
4264
+ );
4265
+ const toggleFullscreen = React7.useCallback(async () => {
4266
+ const container = containerRef.current;
4267
+ if (!container) return;
4268
+ if (document.fullscreenElement === container) {
4269
+ await document.exitFullscreen();
4270
+ return;
4271
+ }
4272
+ if (document.fullscreenElement) await document.exitFullscreen();
4273
+ await container.requestFullscreen();
4274
+ }, []);
4275
+ if (!board || !gameMap) {
4276
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4277
+ "div",
4278
+ {
4279
+ className: cn(
4280
+ "grid min-h-72 place-items-center border-2 border-dashed border-border/70 bg-[linear-gradient(145deg,rgba(247,244,236,0.84),rgba(255,255,255,0.95))] text-sm text-muted-foreground",
4281
+ className
4282
+ ),
4283
+ style: { clipPath: PIXEL_PANEL_CLIP4 },
4284
+ children: loading ? "\u6B63\u5728\u751F\u6210 workboard game world..." : "\u5F53\u524D\u6CA1\u6709\u53EF\u5C55\u793A\u7684 workboard game world\u3002"
4285
+ }
4286
+ );
4287
+ }
4288
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("section", { className: cn("min-h-full", className), children: [
4289
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(WorkboardGameStyles, {}),
4290
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4291
+ "section",
4292
+ {
4293
+ ref: containerRef,
4294
+ tabIndex: 0,
4295
+ onKeyDown: handleWorldKeyDown,
4296
+ className: cn(
4297
+ "relative overflow-hidden bg-[linear-gradient(145deg,rgba(236,232,218,0.96),rgba(255,252,247,0.98)_42%,rgba(217,231,224,0.76))] outline-none focus-visible:ring-2 focus-visible:ring-foreground/30",
4298
+ isFullscreen ? "h-[100dvh] rounded-none" : "border-2 border-border/70 p-2 shadow-[0_8px_0_rgba(17,17,19,0.12)]"
4299
+ ),
4300
+ style: isFullscreen ? void 0 : { clipPath: PIXEL_PANEL_CLIP4 },
4301
+ children: [
4302
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "pointer-events-none absolute inset-0 z-10 bg-[linear-gradient(rgba(17,17,19,0.04)_1px,transparent_1px),linear-gradient(90deg,rgba(17,17,19,0.04)_1px,transparent_1px)] bg-[size:18px_18px] opacity-40" }),
4303
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4304
+ "div",
4305
+ {
4306
+ className: "pointer-events-none absolute inset-x-0 top-0 z-10 h-16 bg-[linear-gradient(180deg,transparent,rgba(17,17,19,0.08),transparent)]",
4307
+ style: { animation: "workboard-world-scan 4.5s steps(6, end) infinite" }
4308
+ }
4309
+ ),
4310
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4311
+ WorkboardGameHud,
4312
+ {
4313
+ board,
4314
+ stageLevel,
4315
+ activeZone,
4316
+ selected,
4317
+ flowMode,
4318
+ loading,
4319
+ isFullscreen,
4320
+ zones: gameMap.zones,
4321
+ onSelectZone: openZone,
4322
+ onBackToAtlas: backToAtlas,
4323
+ onToggleFlowMode: () => setFlowMode((prev) => prev === "cruise" ? "turbo" : "cruise"),
4324
+ onRefresh,
4325
+ onToggleFullscreen: toggleFullscreen
4326
+ }
4327
+ ),
4328
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4329
+ "div",
4330
+ {
4331
+ ref: stageViewportRef,
4332
+ className: cn(
4333
+ "z-20 grid w-full place-items-center",
4334
+ isFullscreen ? "absolute inset-0 overflow-hidden" : "relative overflow-auto border-2 border-border/70 bg-[linear-gradient(145deg,rgba(251,250,247,0.96),rgba(245,248,245,0.88))]"
4335
+ ),
4336
+ style: isFullscreen ? void 0 : { minHeight: 720, clipPath: PIXEL_PANEL_CLIP4 },
4337
+ children: [
4338
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(WorkboardScaledStage, { scale: stageScale, children: stageLevel === "clusters" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4339
+ WorkboardGameAtlas,
4340
+ {
4341
+ board,
4342
+ gameMap,
4343
+ activeZoneId,
4344
+ selectedAgentId: selected?.id,
4345
+ flowMode,
4346
+ motionFrames,
4347
+ onSelectZone: openZone,
4348
+ onSelectAgent: (agentId) => openAgent(agentId)
4349
+ }
4350
+ ) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4351
+ WorkboardGameRoom,
4352
+ {
4353
+ zone: activeZone,
4354
+ items: activeZoneItems,
4355
+ gameMap,
4356
+ selectedAgentId: selected?.id,
4357
+ motionFrames,
4358
+ flowMode,
4359
+ onSelectAgent: openAgent
4360
+ }
4361
+ ) }),
4362
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(WorkboardWorldPortalOverlay, { portal }),
4363
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4364
+ WorkboardGameInspector,
4365
+ {
4366
+ selected,
4367
+ activeZone,
4368
+ selectedPeers,
4369
+ stageLevel,
4370
+ collapsed: detailsCollapsed,
4371
+ onToggleCollapsed: () => setDetailsCollapsed((prev) => !prev),
4372
+ onSelectAgent: openAgent
4373
+ }
4374
+ )
4375
+ ]
4376
+ }
4377
+ )
4378
+ ]
4379
+ }
4380
+ )
4381
+ ] });
4382
+ }
553
4383
  // Annotate the CommonJS export names for ESM import in node:
554
4384
  0 && (module.exports = {
555
4385
  Badge,
@@ -561,6 +4391,17 @@ function Toaster({ ...props }) {
561
4391
  CardFooter,
562
4392
  CardHeader,
563
4393
  CardTitle,
4394
+ Checkbox,
4395
+ Dialog,
4396
+ DialogClose,
4397
+ DialogContent,
4398
+ DialogDescription,
4399
+ DialogFooter,
4400
+ DialogHeader,
4401
+ DialogOverlay,
4402
+ DialogPortal,
4403
+ DialogTitle,
4404
+ DialogTrigger,
564
4405
  DropdownMenu,
565
4406
  DropdownMenuCheckboxItem,
566
4407
  DropdownMenuContent,
@@ -576,11 +4417,41 @@ function Toaster({ ...props }) {
576
4417
  DropdownMenuSubContent,
577
4418
  DropdownMenuSubTrigger,
578
4419
  DropdownMenuTrigger,
4420
+ Input,
4421
+ Label,
579
4422
  Popover,
580
4423
  PopoverContent,
581
4424
  PopoverTrigger,
4425
+ Separator,
4426
+ Sheet,
4427
+ SheetClose,
4428
+ SheetContent,
4429
+ SheetDescription,
4430
+ SheetFooter,
4431
+ SheetHeader,
4432
+ SheetOverlay,
4433
+ SheetPortal,
4434
+ SheetTitle,
4435
+ SheetTrigger,
4436
+ Skeleton,
4437
+ Tabs,
4438
+ TabsContent,
4439
+ TabsList,
4440
+ TabsTrigger,
4441
+ Textarea,
582
4442
  Toaster,
4443
+ Toggle,
4444
+ ToggleGroup,
4445
+ ToggleGroupItem,
4446
+ Tooltip,
4447
+ TooltipContent,
4448
+ TooltipProvider,
4449
+ TooltipTrigger,
4450
+ Workboard,
583
4451
  badgeVariants,
4452
+ buildWorkboardGameMapConfig,
584
4453
  buttonVariants,
585
- cn
4454
+ cn,
4455
+ tabsListVariants,
4456
+ toggleVariants
586
4457
  });