foundry-design-web-adapter 0.2.0-beta.1 → 0.2.0-beta.2

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/adapter.js CHANGED
@@ -81,6 +81,16 @@ function reviewSelection(draft, changeId, defaultSelected) {
81
81
  function reviewAfterValue(draft, changeId, fallback) {
82
82
  return draft.afterValues[changeId] ?? String(fallback);
83
83
  }
84
+ function humanizeProperty(property) {
85
+ return property.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").toLowerCase().replace(/^./, (character) => character.toUpperCase());
86
+ }
87
+ function reviewSummary(selectedCount, selectableCount, elementCount, unresolvedCount = 0) {
88
+ if (!selectableCount && !unresolvedCount) return "No design changes are waiting for review.";
89
+ const changes = `${selectedCount} ${selectedCount === 1 ? "change" : "changes"}`;
90
+ const elements = `${elementCount} ${elementCount === 1 ? "element" : "elements"}`;
91
+ const unresolved = unresolvedCount ? ` \xB7 ${unresolvedCount} ${unresolvedCount === 1 ? "change needs" : "changes need"} mapping` : "";
92
+ return `${changes} ready across ${elements}${unresolved}`;
93
+ }
84
94
 
85
95
  // src/canvas.ts
86
96
  function layerSelectionScore(signals) {
@@ -482,499 +492,412 @@ function baselineForContext(memory, targetId, breakpoint, theme, state) {
482
492
  );
483
493
  }
484
494
 
485
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/defaultAttributes.mjs
486
- var defaultAttributes = {
487
- xmlns: "http://www.w3.org/2000/svg",
488
- width: 24,
489
- height: 24,
490
- viewBox: "0 0 24 24",
491
- fill: "none",
492
- stroke: "currentColor",
493
- "stroke-width": 2,
494
- "stroke-linecap": "round",
495
- "stroke-linejoin": "round"
495
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/u/user-check.js
496
+ var data = {
497
+ "width": 24,
498
+ "height": 24,
499
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7L18 9.25L22 4.75M8 14H10C13.3137 14 16 16.6863 16 20C16 20.5523 15.5523 21 15 21H3C2.44772 21 2 20.5523 2 20C2 16.6863 4.68629 14 8 14ZM9 4C10.6569 4 12 5.34315 12 7C12 8.65685 10.6569 10 9 10C7.34315 10 6 8.65685 6 7C6 5.34315 7.34315 4 9 4Z"/>'
496
500
  };
501
+ var user_check_default = data;
497
502
 
498
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/createElement.mjs
499
- var createSVGElement = ([tag, attrs, children]) => {
500
- const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
501
- Object.keys(attrs).forEach((name) => {
502
- element.setAttribute(name, String(attrs[name]));
503
- });
504
- if (children?.length) {
505
- children.forEach((child) => {
506
- const childElement = createSVGElement(child);
507
- element.appendChild(childElement);
508
- });
509
- }
510
- return element;
511
- };
512
- var createElement = (iconNode, customAttrs = {}) => {
513
- const tag = "svg";
514
- const attrs = {
515
- ...defaultAttributes,
516
- ...customAttrs
517
- };
518
- return createSVGElement([tag, attrs, iconNode]);
503
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/a/activity.js
504
+ var data2 = {
505
+ "width": 24,
506
+ "height": 24,
507
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2 12H5L8 4L16 20L19 12H22"/>'
519
508
  };
509
+ var activity_default = data2;
520
510
 
521
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/shared/src/utils/hasA11yProp.mjs
522
- var hasA11yProp = (props) => {
523
- for (const prop in props) {
524
- if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
525
- return true;
526
- }
527
- }
528
- return false;
511
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/a/align-offset-left.js
512
+ var data3 = {
513
+ "width": 24,
514
+ "height": 24,
515
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 2V8M12 2V20M20 10V22"/>'
529
516
  };
517
+ var align_offset_left_default = data3;
530
518
 
531
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/shared/src/utils/mergeClasses.mjs
532
- var mergeClasses = (...classes) => classes.filter((className, index, array) => {
533
- return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
534
- }).join(" ").trim();
535
-
536
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/shared/src/utils/toCamelCase.mjs
537
- var toCamelCase = (string) => string.replace(
538
- /^([A-Z])|[\s-_]+(\w)/g,
539
- (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
540
- );
541
-
542
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/shared/src/utils/toPascalCase.mjs
543
- var toPascalCase = (string) => {
544
- const camelCase = toCamelCase(string);
545
- return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
519
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/a/arrow-down.js
520
+ var data4 = {
521
+ "width": 24,
522
+ "height": 24,
523
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12.1229L11.5875 18.8261C11.8153 19.058 12.1847 19.058 12.4125 18.8261L19 12.1229M12 5V18.0587"/>'
546
524
  };
525
+ var arrow_down_default = data4;
547
526
 
548
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/replaceElement.mjs
549
- var getAttrs = (element) => Array.from(element.attributes).reduce((attrs, attr) => {
550
- attrs[attr.name] = attr.value;
551
- return attrs;
552
- }, {});
553
- var getClassNames = (attrs) => {
554
- if (typeof attrs === "string") return attrs;
555
- if (!attrs || !attrs.class) return "";
556
- if (attrs.class && typeof attrs.class === "string") {
557
- return attrs.class.split(" ");
558
- }
559
- if (attrs.class && Array.isArray(attrs.class)) {
560
- return attrs.class;
561
- }
562
- return "";
563
- };
564
- var replaceElement = (element, { nameAttr, icons, attrs }) => {
565
- const iconName = element.getAttribute(nameAttr);
566
- if (iconName == null) return;
567
- const ComponentName = toPascalCase(iconName);
568
- const iconNode = icons[ComponentName];
569
- if (!iconNode) {
570
- return console.warn(
571
- `${element.outerHTML} icon name was not found in the provided icons object.`
572
- );
573
- }
574
- const elementAttrs = getAttrs(element);
575
- const ariaProps = hasA11yProp(elementAttrs) ? {} : { "aria-hidden": "true" };
576
- const iconAttrs = {
577
- ...defaultAttributes,
578
- "data-lucide": iconName,
579
- ...ariaProps,
580
- ...attrs,
581
- ...elementAttrs
582
- };
583
- const elementClassNames = getClassNames(elementAttrs);
584
- const className = getClassNames(attrs);
585
- const classNames = mergeClasses(
586
- "lucide",
587
- `lucide-${iconName}`,
588
- ...elementClassNames,
589
- ...className
590
- );
591
- if (classNames) {
592
- Object.assign(iconAttrs, {
593
- class: classNames
594
- });
595
- }
596
- const svgElement = createElement(iconNode, iconAttrs);
597
- return element.parentNode?.replaceChild(svgElement, element);
527
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/a/arrow-left.js
528
+ var data5 = {
529
+ "width": 24,
530
+ "height": 24,
531
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 12H5.94129M11.8771 5L5.17385 11.5875C4.94205 11.8153 4.94205 12.1847 5.17385 12.4125L11.8771 19"/>'
598
532
  };
533
+ var arrow_left_default = data5;
599
534
 
600
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/accessibility.mjs
601
- var Accessibility = [
602
- ["circle", { cx: "16", cy: "4", r: "1" }],
603
- ["path", { d: "m18 19 1-7-6 1" }],
604
- ["path", { d: "m5 8 3-3 5.5 3-2.36 3.5" }],
605
- ["path", { d: "M4.24 14.5a5 5 0 0 0 6.88 6" }],
606
- ["path", { d: "M13.76 17.5a5 5 0 0 0-6.88-6" }]
607
- ];
608
-
609
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/activity.mjs
610
- var Activity = [
611
- [
612
- "path",
613
- {
614
- d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"
615
- }
616
- ]
617
- ];
618
-
619
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/align-horizontal-space-around.mjs
620
- var AlignHorizontalSpaceAround = [
621
- ["rect", { width: "6", height: "10", x: "9", y: "7", rx: "2" }],
622
- ["path", { d: "M4 22V2" }],
623
- ["path", { d: "M20 22V2" }]
624
- ];
625
-
626
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/arrow-down.mjs
627
- var ArrowDown = [
628
- ["path", { d: "M12 5v14" }],
629
- ["path", { d: "m19 12-7 7-7-7" }]
630
- ];
535
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/a/arrow-up.js
536
+ var data6 = {
537
+ "width": 24,
538
+ "height": 24,
539
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 11.8771L11.5875 5.17385C11.8153 4.94205 12.1847 4.94205 12.4125 5.17385L19 11.8771M12 19V5.94129"/>'
540
+ };
541
+ var arrow_up_default = data6;
631
542
 
632
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/arrow-left.mjs
633
- var ArrowLeft = [
634
- ["path", { d: "m12 19-7-7 7-7" }],
635
- ["path", { d: "M19 12H5" }]
636
- ];
543
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/b/bookmark.js
544
+ var data7 = {
545
+ "width": 24,
546
+ "height": 24,
547
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5C4 3.3431 5.3431 2 7 2L17 2C18.6569 2 20 3.3431 20 5L20 20.9983C20 21.7895 19.1248 22.2673 18.4592 21.8395L12.8111 18.8514C12.317 18.5338 11.683 18.5338 11.1889 18.8514L5.5408 21.8395C4.8752 22.2673 4 21.7895 4 20.9983Z"/>'
548
+ };
549
+ var bookmark_default = data7;
637
550
 
638
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/arrow-up.mjs
639
- var ArrowUp = [
640
- ["path", { d: "m5 12 7-7 7 7" }],
641
- ["path", { d: "M12 19V5" }]
642
- ];
551
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/s/square.js
552
+ var data8 = {
553
+ "width": 24,
554
+ "height": 24,
555
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 3H18C19.6569 3 21 4.34315 21 6V18C21 19.6569 19.6569 21 18 21H6C4.34315 21 3 19.6569 3 18V6C3 4.34315 4.34315 3 6 3Z"/>'
556
+ };
557
+ var square_default = data8;
643
558
 
644
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/bookmark.mjs
645
- var Bookmark = [
646
- [
647
- "path",
648
- {
649
- d: "M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z"
650
- }
651
- ]
652
- ];
559
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/check.js
560
+ var data9 = {
561
+ "width": 24,
562
+ "height": 24,
563
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12L9.66667 17L19 7"/>'
564
+ };
565
+ var check_default = data9;
653
566
 
654
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/box.mjs
655
- var Box = [
656
- [
657
- "path",
658
- {
659
- d: "M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"
660
- }
661
- ],
662
- ["path", { d: "m3.3 7 8.7 5 8.7-5" }],
663
- ["path", { d: "M12 22V12" }]
664
- ];
567
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/chevron-down.js
568
+ var data10 = {
569
+ "width": 24,
570
+ "height": 24,
571
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 9L12 15L18 9"/>'
572
+ };
573
+ var chevron_down_default = data10;
665
574
 
666
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/check.mjs
667
- var Check = [["path", { d: "M20 6 9 17l-5-5" }]];
575
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/chevron-right.js
576
+ var data11 = {
577
+ "width": 24,
578
+ "height": 24,
579
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 6L15 12L9 18"/>'
580
+ };
581
+ var chevron_right_default = data11;
668
582
 
669
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/chevron-down.mjs
670
- var ChevronDown = [["path", { d: "m6 9 6 6 6-6" }]];
583
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/g/grid-3x2.js
584
+ var data12 = {
585
+ "width": 24,
586
+ "height": 24,
587
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 3H18C19.65685 3 21 4.34315 21 6V18C21 19.65685 19.65685 21 18 21H6C4.34315 21 3 19.65685 3 18V6C3 4.34315 4.34315 3 6 3ZM9 3V21M15 3V21M3 12H21"/>'
588
+ };
589
+ var grid_3x2_default = data12;
671
590
 
672
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/chevron-right.mjs
673
- var ChevronRight = [["path", { d: "m9 18 6-6-6-6" }]];
591
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/s/square-terminal.js
592
+ var data13 = {
593
+ "width": 24,
594
+ "height": 24,
595
+ "body": '<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M6 3H18C19.6569 3 21 4.34315 21 6V18C21 19.6569 19.6569 21 18 21H6C4.34315 21 3 19.6569 3 18V6C3 4.34315 4.34315 3 6 3Z"/><path d="M7 7L11 11L7 15M13 17H17"/></g>'
596
+ };
597
+ var square_terminal_default = data13;
674
598
 
675
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/columns-3.mjs
676
- var Columns3 = [
677
- ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
678
- ["path", { d: "M9 3v18" }],
679
- ["path", { d: "M15 3v18" }]
680
- ];
599
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/s/shapes.js
600
+ var data14 = {
601
+ "width": 24,
602
+ "height": 24,
603
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3L10 10M10 3L3 10M17.5 3L21 10H14L17.5 3ZM10 17.5C10 19.433 8.433 21 6.5 21C4.567 21 3 19.433 3 17.5C3 15.567 4.567 14 6.5 14C8.433 14 10 15.567 10 17.5ZM16 14H19C20.1046 14 21 14.8954 21 16V19C21 20.1046 20.1046 21 19 21H16C14.8954 21 14 20.1046 14 19V16C14 14.8954 14.8954 14 16 14Z"/>'
604
+ };
605
+ var shapes_default = data14;
681
606
 
682
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/command.mjs
683
- var Command = [
684
- ["path", { d: "M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" }]
685
- ];
607
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/circle-half.js
608
+ var data15 = {
609
+ "width": 24,
610
+ "height": 24,
611
+ "body": '<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2Z"/><path d="M12 6C15.3138 6 18 8.6862 18 12C18 15.3138 15.3138 18 12 18Z"/></g>'
612
+ };
613
+ var circle_half_default = data15;
686
614
 
687
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/component.mjs
688
- var Component = [
689
- [
690
- "path",
691
- {
692
- d: "M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z"
693
- }
694
- ],
695
- [
696
- "path",
697
- {
698
- d: "M2.297 11.293a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0z"
699
- }
700
- ],
701
- [
702
- "path",
703
- {
704
- d: "M8.916 17.912a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0z"
705
- }
706
- ],
707
- [
708
- "path",
709
- {
710
- d: "M8.916 4.674a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z"
711
- }
712
- ]
713
- ];
615
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/cursor.js
616
+ var data16 = {
617
+ "width": 24,
618
+ "height": 24,
619
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.3184 20.5112L3.0341 3.9139C2.8602 3.3677 3.3816 2.8558 3.9268 3.0373L20.5197 8.5617C21.1361 8.7669 21.1671 9.6243 20.5672 9.8732L13.4774 12.8146C13.3157 12.8817 13.1848 13.0065 13.1107 13.1647L9.6254 20.596C9.3541 21.174 8.5121 21.1195 8.3184 20.5112Z"/>'
620
+ };
621
+ var cursor_default = data16;
714
622
 
715
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/contrast.mjs
716
- var Contrast = [
717
- ["circle", { cx: "12", cy: "12", r: "10" }],
718
- ["path", { d: "M12 18a6 6 0 0 0 0-12v12z" }]
719
- ];
623
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/cursor-click.js
624
+ var data17 = {
625
+ "width": 24,
626
+ "height": 24,
627
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12.1748 5.76261L13.9549 3.98724M7.88236 4.69633L6.98121 2M4.70404 7.86707L2 6.96809M5.77258 12.14803L3.99248 13.9234M9.26992 9.88622L13.0143 21.6534C13.1515 22.0847 13.7482 22.1234 13.9403 21.7136L16.4099 16.4449C16.4625 16.3328 16.5551 16.2442 16.6697 16.1967L21.6933 14.1113C22.1184 13.9348 22.0964 13.3269 21.6597 13.1814L9.90251 9.26472C9.51618 9.13602 9.14671 9.49902 9.26992 9.88622Z"/>'
628
+ };
629
+ var cursor_click_default = data17;
720
630
 
721
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/eye-off.mjs
722
- var EyeOff = [
723
- [
724
- "path",
725
- {
726
- d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"
727
- }
728
- ],
729
- ["path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }],
730
- [
731
- "path",
732
- {
733
- d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"
734
- }
735
- ],
736
- ["path", { d: "m2 2 20 20" }]
737
- ];
631
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/e/eye.js
632
+ var data18 = {
633
+ "width": 24,
634
+ "height": 24,
635
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2 12C3.0523 7.3229 7.206 4 12 4C16.794 4 20.9477 7.3229 22 12C20.9477 16.6771 16.794 20 12 20C7.206 20 3.0523 16.6771 2 12ZM15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z"/>'
636
+ };
637
+ var eye_default = data18;
738
638
 
739
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/eye.mjs
740
- var Eye = [
741
- [
742
- "path",
743
- {
744
- d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"
745
- }
746
- ],
747
- ["circle", { cx: "12", cy: "12", r: "3" }]
748
- ];
639
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/e/eye-off.js
640
+ var data19 = {
641
+ "width": 24,
642
+ "height": 24,
643
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.035 18.035C16.3283 19.2786 14.2337 20 12 20C7.206 20 3.0523 16.6771 2 12C2.562 9.5021 4.0086 7.3904 5.965 5.965M9.8779 4.2211C10.565 4.076 11.2752 4 12 4C16.794 4 20.9477 7.3229 22 12C21.7487 13.1169 21.3206 14.1566 20.7491 15.0922M14.1213 14.1213C13.5785 14.6642 12.8285 15 12 15C10.3431 15 9 13.6569 9 12C9 11.1716 9.3358 10.4216 9.8787 9.8787M2 2L22 22"/>'
644
+ };
645
+ var eye_off_default = data19;
749
646
 
750
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/file-text.mjs
751
- var FileText = [
752
- [
753
- "path",
754
- {
755
- d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"
756
- }
757
- ],
758
- ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5" }],
759
- ["path", { d: "M10 9H8" }],
760
- ["path", { d: "M16 13H8" }],
761
- ["path", { d: "M16 17H8" }]
762
- ];
647
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/f/file-text.js
648
+ var data20 = {
649
+ "width": 24,
650
+ "height": 24,
651
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 2H8C5.79086 2 4 3.79086 4 6V18C4 20.2091 5.79086 22 8 22H16C18.2091 22 20 20.2091 20 18V8L14 2ZM14 2V5C14 6.65685 15.3431 8 17 8H20M8 13H12M8 17H16"/>'
652
+ };
653
+ var file_text_default = data20;
763
654
 
764
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/layers.mjs
765
- var Layers = [
766
- [
767
- "path",
768
- {
769
- d: "M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"
770
- }
771
- ],
772
- ["path", { d: "M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12" }],
773
- ["path", { d: "M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17" }]
774
- ];
655
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/l/layout-dashboard.js
656
+ var data21 = {
657
+ "width": 24,
658
+ "height": 24,
659
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 3H9C9.55228 3 10 3.44772 10 4V11C10 11.55228 9.55228 12 9 12H4C3.44772 12 3 11.55228 3 11V4C3 3.44772 3.44772 3 4 3ZM4 16H9C9.55228 16 10 16.44772 10 17V20C10 20.55228 9.55228 21 9 21H4C3.44772 21 3 20.55228 3 20V17C3 16.44772 3.44772 16 4 16ZM15 3H20C20.55228 3 21 3.44772 21 4V7C21 7.55228 20.55228 8 20 8H15C14.44772 8 14 7.55228 14 7V4C14 3.44772 14.44772 3 15 3ZM15 12H20C20.55228 12 21 12.44772 21 13V20C21 20.55228 20.55228 21 20 21H15C14.44772 21 14 20.55228 14 20V13C14 12.44772 14.44772 12 15 12Z"/>'
660
+ };
661
+ var layout_dashboard_default = data21;
775
662
 
776
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/layout-grid.mjs
777
- var LayoutGrid = [
778
- ["rect", { width: "7", height: "7", x: "3", y: "3", rx: "1" }],
779
- ["rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }],
780
- ["rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }],
781
- ["rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" }]
782
- ];
663
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/g/grid-squares.js
664
+ var data22 = {
665
+ "width": 24,
666
+ "height": 24,
667
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 16C3 14.8954 3.8954 14 5 14L8 14C9.1046 14 10 14.8954 10 16L10 19C10 20.1046 9.1046 21 8 21L5 21C3.8954 21 3 20.1046 3 19L3 16ZM3 5C3 3.8954 3.8954 3 5 3L8 3C9.1046 3 10 3.8954 10 5L10 8C10 9.1046 9.1046 10 8 10L5 10C3.8954 10 3 9.1046 3 8L3 5ZM14 16C14 14.8954 14.8954 14 16 14L19 14C20.1046 14 21 14.8954 21 16L21 19C21 20.1046 20.1046 21 19 21L16 21C14.8954 21 14 20.1046 14 19L14 16ZM14 5C14 3.8954 14.8954 3 16 3L19 3C20.1046 3 21 3.8954 21 5L21 8C21 9.1046 20.1046 10 19 10L16 10C14.8954 10 14 9.1046 14 8L14 5Z"/>'
668
+ };
669
+ var grid_squares_default = data22;
783
670
 
784
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/link-2.mjs
785
- var Link2 = [
786
- ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2" }],
787
- ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2" }],
788
- ["line", { x1: "8", x2: "16", y1: "12", y2: "12" }]
789
- ];
671
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/l/link.js
672
+ var data23 = {
673
+ "width": 24,
674
+ "height": 24,
675
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17H7C4.23858 17 2 14.7614 2 12C2 9.23858 4.23858 7 7 7H9M15 7H17C19.7614 7 22 9.23858 22 12C22 14.7614 19.7614 17 17 17H15M8 12H16"/>'
676
+ };
677
+ var link_default = data23;
790
678
 
791
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/lock.mjs
792
- var Lock = [
793
- ["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2" }],
794
- ["path", { d: "M7 11V7a5 5 0 0 1 10 0v4" }]
795
- ];
679
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/l/link-off.js
680
+ var data24 = {
681
+ "width": 24,
682
+ "height": 24,
683
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17L7 17C4.2386 17 2 14.7614 2 12C2 9.2386 4.2386 7 7 7M15 7L17 7C19.7614 7 22 9.2386 22 12C22 13.2135 21.5677 14.326 20.8488 15.1919M17 17L15 17M8 12L12 12M2 2L22 22"/>'
684
+ };
685
+ var link_off_default = data24;
796
686
 
797
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/maximize-2.mjs
798
- var Maximize2 = [
799
- ["path", { d: "M15 3h6v6" }],
800
- ["path", { d: "m21 3-7 7" }],
801
- ["path", { d: "m3 21 7-7" }],
802
- ["path", { d: "M9 21H3v-6" }]
803
- ];
687
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/l/lock.js
688
+ var data25 = {
689
+ "width": 24,
690
+ "height": 24,
691
+ "body": '<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M7.5 10V6.5C7.5 4.01472 9.51472 2 12 2C14.4853 2 16.5 4.01472 16.5 6.5V10M4 13V19C4 20.6569 5.34315 22 7 22H17C18.6569 22 20 20.6569 20 19V13C20 11.3431 18.6569 10 17 10H7C5.34315 10 4 11.3431 4 13Z"/><path fill="currentColor" d="M13.5 16C13.5 16.8284 12.8284 17.5 12 17.5C11.1716 17.5 10.5 16.8284 10.5 16C10.5 15.1716 11.1716 14.5 12 14.5C12.8284 14.5 13.5 15.1716 13.5 16Z" stroke="none"/></g>'
692
+ };
693
+ var lock_default = data25;
804
694
 
805
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/mouse-pointer-2.mjs
806
- var MousePointer2 = [
807
- [
808
- "path",
809
- {
810
- d: "M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z"
811
- }
812
- ]
813
- ];
695
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/m/maximize.js
696
+ var data26 = {
697
+ "width": 24,
698
+ "height": 24,
699
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3H6C4.34315 3 3 4.34315 3 6V9M15 3H18C19.65685 3 21 4.34315 21 6V9M21 15V18C21 19.65685 19.65685 21 18 21H15M3 15V18C3 19.65685 4.34315 21 6 21H9"/>'
700
+ };
701
+ var maximize_default = data26;
814
702
 
815
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/palette.mjs
816
- var Palette = [
817
- [
818
- "path",
819
- {
820
- d: "M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z"
821
- }
822
- ],
823
- ["circle", { cx: "13.5", cy: "6.5", r: ".5", fill: "currentColor" }],
824
- ["circle", { cx: "17.5", cy: "10.5", r: ".5", fill: "currentColor" }],
825
- ["circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor" }],
826
- ["circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor" }]
827
- ];
703
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/f/flower.js
704
+ var data27 = {
705
+ "width": 24,
706
+ "height": 24,
707
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.6 5.2162C9.6 3.8907 10.6745 2.8162 12 2.8162C13.3255 2.8162 14.4 3.8907 14.4 5.2162C14.4 6.5417 13.3255 7.6162 12 7.6162C10.6745 7.6162 9.6 6.5417 9.6 5.2162ZM16.7329 10.3986C16.7329 9.0731 17.8074 7.9986 19.1329 7.9986C20.4584 7.9986 21.5329 9.0731 21.5329 10.3986C21.5329 11.7241 20.4584 12.7986 19.1329 12.7986C17.8074 12.7986 16.7329 11.7241 16.7329 10.3986ZM14.0084 18.7838C14.0084 17.4583 15.0829 16.3838 16.4084 16.3838C17.7339 16.3838 18.8084 17.4583 18.8084 18.7838C18.8084 20.1093 17.7339 21.1838 16.4084 21.1838C15.0829 21.1838 14.0084 20.1093 14.0084 18.7838ZM5.1916 18.7838C5.1916 17.4583 6.2661 16.3838 7.5916 16.3838C8.9171 16.3838 9.9916 17.4583 9.9916 18.7838C9.9916 20.1093 8.9171 21.1838 7.5916 21.1838C6.2661 21.1838 5.1916 20.1093 5.1916 18.7838ZM2.4671 10.3986C2.4671 9.0731 3.5416 7.9986 4.8671 7.9986C6.1926 7.9986 7.2671 9.0731 7.2671 10.3986C7.2671 11.7241 6.1926 12.7986 4.8671 12.7986C3.5416 12.7986 2.4671 11.7241 2.4671 10.3986Z"/>'
708
+ };
709
+ var flower_default = data27;
828
710
 
829
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/panels-top-left.mjs
830
- var PanelsTopLeft = [
831
- ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
832
- ["path", { d: "M3 9h18" }],
833
- ["path", { d: "M9 21V9" }]
834
- ];
711
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/p/panel-right.js
712
+ var data28 = {
713
+ "width": 24,
714
+ "height": 24,
715
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 3H18C19.6569 3 21 4.34315 21 6V18C21 19.6569 19.6569 21 18 21H6C4.34315 21 3 19.6569 3 18V6C3 4.34315 4.34315 3 6 3ZM15 3V21"/>'
716
+ };
717
+ var panel_right_default = data28;
835
718
 
836
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/play.mjs
837
- var Play = [
838
- [
839
- "path",
840
- { d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z" }
841
- ]
842
- ];
719
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/p/play.js
720
+ var data29 = {
721
+ "width": 24,
722
+ "height": 24,
723
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4.00351C4 2.379713 5.83285 1.432756 7.157224 2.372305L19.578612 11.184397C20.140462 11.58299 20.140462 12.41701 19.578612 12.815603L7.157224 21.627695C5.83285 22.567244 4 21.620287 4 19.99649Z"/>'
724
+ };
725
+ var play_default = data29;
843
726
 
844
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/redo-2.mjs
845
- var Redo2 = [
846
- ["path", { d: "m15 14 5-5-5-5" }],
847
- ["path", { d: "M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13" }]
848
- ];
727
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/r/rotate-cw.js
728
+ var data30 = {
729
+ "width": 24,
730
+ "height": 24,
731
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.7883 10.0593C20.929 10.6966 21 11.3473 21 12C21 16.9706 16.9706 21 12 21C7.0294 21 3 16.9706 3 12C3 7.0294 7.0294 3 12 3C14.4831 3 16.8559 4.0259 18.5568 5.8349M19.7143 3L19.2707 6.105C19.2317 6.3784 18.9784 6.5683 18.705 6.5293L15.6 6.0857"/>'
732
+ };
733
+ var rotate_cw_default = data30;
849
734
 
850
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/rotate-ccw.mjs
851
- var RotateCcw = [
852
- ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }],
853
- ["path", { d: "M3 3v5h5" }]
854
- ];
735
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/r/refresh-ccw.js
736
+ var data31 = {
737
+ "width": 24,
738
+ "height": 24,
739
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.7883 13.9407C20.929 13.3034 21 12.6527 21 12C21 7.0294 16.9706 3 12 3C9.5169 3 7.1441 4.0259 5.4432 5.8349M4.2857 3L4.7293 6.105C4.7683 6.3784 5.0216 6.5683 5.295 6.5293L8.4 6.0857M3.2117 10.0593C3.071 10.6966 3 11.3473 3 12C3 16.9706 7.0294 21 12 21C14.4831 21 16.8559 19.9741 18.5568 18.1651M19.7143 21L19.2707 17.895C19.2317 17.6216 18.9784 17.4317 18.705 17.4707L15.6 17.9143"/>'
740
+ };
741
+ var refresh_ccw_default = data31;
855
742
 
856
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/save.mjs
857
- var Save = [
858
- [
859
- "path",
860
- {
861
- d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z"
862
- }
863
- ],
864
- ["path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" }],
865
- ["path", { d: "M7 3v4a1 1 0 0 0 1 1h7" }]
866
- ];
743
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/d/download.js
744
+ var data32 = {
745
+ "width": 24,
746
+ "height": 24,
747
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3V14M8 10L12 14L16 10M4 18V19C4 20.1046 4.89543 21 6 21H18C19.1046 21 20 20.1046 20 19V18"/>'
748
+ };
749
+ var download_default = data32;
867
750
 
868
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/sparkles.mjs
869
- var Sparkles = [
870
- [
871
- "path",
872
- {
873
- d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"
874
- }
875
- ],
876
- ["path", { d: "M20 2v4" }],
877
- ["path", { d: "M22 4h-4" }],
878
- ["circle", { cx: "4", cy: "20", r: "2" }]
879
- ];
751
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/s/star.js
752
+ var data33 = {
753
+ "width": 24,
754
+ "height": 24,
755
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.5386 2.8073C11.6164 2.6212 11.7983 2.5 12 2.5C12.2017 2.5 12.3836 2.6212 12.4614 2.8073L14.87 8.5744C14.9422 8.7473 15.1049 8.8653 15.2916 8.8802L21.5398 9.379C21.7413 9.3951 21.9133 9.531 21.9756 9.7233C22.0379 9.9157 21.9783 10.1266 21.8245 10.2578L17.0671 14.3162C16.924 14.4383 16.8615 14.6302 16.9053 14.8131L18.3593 20.8835C18.4064 21.0798 18.3307 21.2851 18.1675 21.404C18.0044 21.5229 17.7857 21.532 17.6132 21.4271L12.2598 18.1708C12.1002 18.0737 11.8998 18.0737 11.7402 18.1708L6.3868 21.4271C6.2143 21.532 5.9956 21.5229 5.8325 21.404C5.6693 21.2851 5.5936 21.0798 5.6407 20.8835L7.0947 14.8131C7.1385 14.6302 7.076 14.4383 6.9329 14.3162L2.1755 10.2578C2.0217 10.1266 1.962 9.9157 2.0244 9.7233C2.0867 9.531 2.2587 9.3951 2.4602 9.379L8.7084 8.8802C8.8951 8.8653 9.0578 8.7473 9.13 8.5744Z"/>'
756
+ };
757
+ var star_default = data33;
880
758
 
881
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/triangle-alert.mjs
882
- var TriangleAlert = [
883
- ["path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }],
884
- ["path", { d: "M12 9v4" }],
885
- ["path", { d: "M12 17h.01" }]
886
- ];
759
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/t/triangle-alert.js
760
+ var data34 = {
761
+ "width": 24,
762
+ "height": 24,
763
+ "body": '<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M14.4051 4.39215C13.3181 2.53595 10.6819 2.53595 9.5949 4.39215L2.40063 16.6777C1.28536 18.5822 2.63072 21 4.80572 21H19.1943C21.3693 21 22.7146 18.5822 21.5994 16.6777L14.4051 4.39215Z"/><path d="M12 9V13"/><path fill="currentColor" d="M13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16C12.5523 16 13 16.4477 13 17Z" stroke="none"/></g>'
764
+ };
765
+ var triangle_alert_default = data34;
887
766
 
888
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/type.mjs
889
- var Type = [
890
- ["path", { d: "M12 4v16" }],
891
- ["path", { d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2" }],
892
- ["path", { d: "M9 20h6" }]
893
- ];
767
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/c/cursor-text.js
768
+ var data35 = {
769
+ "width": 24,
770
+ "height": 24,
771
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3.5H12.9583M3 8.10055H5.98748M3 12.7011H5.98748M10.2669 10.0807L13.3776 20.1434C13.5147 20.5871 14.1112 20.627 14.3032 20.2053L16.3303 15.7538C16.3829 15.6384 16.4755 15.5473 16.5901 15.4983L20.6934 13.745C21.1183 13.5634 21.0964 12.9379 20.6598 12.7882L10.8992 9.44123C10.513 9.30882 10.1437 9.68231 10.2669 10.0807Z"/>'
772
+ };
773
+ var cursor_text_default = data35;
894
774
 
895
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/undo-2.mjs
896
- var Undo2 = [
897
- ["path", { d: "M9 14 4 9l5-5" }],
898
- ["path", { d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" }]
899
- ];
775
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/r/rotate-ccw.js
776
+ var data36 = {
777
+ "width": 24,
778
+ "height": 24,
779
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.2117 10.0593C3.071 10.6966 3 11.3473 3 12C3 16.9706 7.0294 21 12 21C16.9706 21 21 16.9706 21 12C21 7.0294 16.9706 3 12 3C9.5169 3 7.1441 4.0259 5.4432 5.8349M4.2857 3L4.7293 6.105C4.7683 6.3784 5.0216 6.5683 5.295 6.5293L8.4 6.0857"/>'
780
+ };
781
+ var rotate_ccw_default = data36;
900
782
 
901
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/unlink-2.mjs
902
- var Unlink2 = [["path", { d: "M15 7h2a5 5 0 0 1 0 10h-2m-6 0H7A5 5 0 0 1 7 7h2" }]];
783
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/p/pencil-ruler.js
784
+ var data37 = {
785
+ "width": 24,
786
+ "height": 24,
787
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.9371 21.3335C3.8326 21.3694 3.7228 21.3878 3.6122 21.3878C3.0599 21.3878 2.6122 20.9401 2.6122 20.3878C2.6122 20.2772 2.6306 20.1674 2.6665 20.0629L4.1467 15.7542C4.1961 15.6103 4.2777 15.4796 4.3853 15.372L14.7577 4.9996C15.3203 4.437 16.0834 4.121 16.879 4.121C17.6747 4.121 18.4377 4.437 19.0004 4.9996C19.563 5.5623 19.879 6.3253 19.879 7.121C19.879 7.9166 19.563 8.6797 19.0004 9.2423L8.628 19.6147C8.5204 19.7223 8.3897 19.8039 8.2458 19.8533L3.9371 21.3335ZM4.2218 15.5355L8.4645 19.7782M4.2925 2.8783C4.8551 2.3157 5.6182 1.9996 6.4139 1.9996C7.2095 1.9996 7.9726 2.3157 8.5352 2.8783L12.7071 7.0503L7.0503 12.7071L2.8783 8.5352C2.3157 7.9726 1.9996 7.2095 1.9996 6.4139C1.9996 5.6182 2.3157 4.8551 2.8783 4.2925L4.2925 2.8783ZM16.9497 11.2929L21.1217 15.4648C21.6843 16.0274 22.0004 16.7905 22.0004 17.5861C22.0004 18.3818 21.6843 19.1449 21.1217 19.7075L19.7075 21.1217C19.1449 21.6843 18.3818 22.0004 17.5861 22.0004C16.7905 22.0004 16.0274 21.6843 15.4648 21.1217L11.2929 16.9497L16.9497 11.2929ZM9.5251 3.8683L7.4038 5.9896M20.1317 14.4749L18.0104 16.5962"/>'
788
+ };
789
+ var pencil_ruler_default = data37;
903
790
 
904
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/wand-sparkles.mjs
905
- var WandSparkles = [
906
- [
907
- "path",
908
- {
909
- d: "m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72"
910
- }
911
- ],
912
- ["path", { d: "m14 7 3 3" }],
913
- ["path", { d: "M5 6v4" }],
914
- ["path", { d: "M19 14v4" }],
915
- ["path", { d: "M10 2v2" }],
916
- ["path", { d: "M7 8H3" }],
917
- ["path", { d: "M21 16h-4" }],
918
- ["path", { d: "M11 3H9" }]
919
- ];
791
+ // ../../node_modules/.pnpm/@iconify-icons+keyline-icons@2.0.0/node_modules/@iconify-icons/keyline-icons/data/x/x.js
792
+ var data38 = {
793
+ "width": 24,
794
+ "height": 24,
795
+ "body": '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7L17 17M17 7L7 17"/>'
796
+ };
797
+ var x_default = data38;
920
798
 
921
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/icons/x.mjs
922
- var X = [
923
- ["path", { d: "M18 6 6 18" }],
924
- ["path", { d: "m6 6 12 12" }]
925
- ];
799
+ // src/keyline-icons.ts
800
+ var KEYLINE_ICONS = {
801
+ accessibility: user_check_default,
802
+ activity: activity_default,
803
+ "align-horizontal-space-around": align_offset_left_default,
804
+ "arrow-down": arrow_down_default,
805
+ "arrow-left": arrow_left_default,
806
+ "arrow-up": arrow_up_default,
807
+ bookmark: bookmark_default,
808
+ box: square_default,
809
+ check: check_default,
810
+ "chevron-down": chevron_down_default,
811
+ "chevron-right": chevron_right_default,
812
+ "columns-3": grid_3x2_default,
813
+ command: square_terminal_default,
814
+ component: shapes_default,
815
+ contrast: circle_half_default,
816
+ eye: eye_default,
817
+ "eye-off": eye_off_default,
818
+ "file-text": file_text_default,
819
+ "layout-grid": layout_dashboard_default,
820
+ "layers-3": grid_squares_default,
821
+ "link-2": link_default,
822
+ lock: lock_default,
823
+ "maximize-2": maximize_default,
824
+ "mouse-pointer-2": cursor_default,
825
+ interact: cursor_click_default,
826
+ palette: flower_default,
827
+ "panels-top-left": panel_right_default,
828
+ play: play_default,
829
+ "redo-2": rotate_cw_default,
830
+ "rotate-ccw": refresh_ccw_default,
831
+ save: download_default,
832
+ sparkles: star_default,
833
+ "triangle-alert": triangle_alert_default,
834
+ type: cursor_text_default,
835
+ "undo-2": rotate_ccw_default,
836
+ "unlink-2": link_off_default,
837
+ "wand-sparkles": pencil_ruler_default,
838
+ x: x_default
839
+ };
840
+ function renderKeylineIcons(root) {
841
+ root.querySelectorAll("[data-foundry-icon]").forEach((placeholder) => {
842
+ const semanticName = placeholder.dataset.foundryIcon;
843
+ if (!semanticName) return;
844
+ const icon = KEYLINE_ICONS[semanticName];
845
+ if (!icon) return;
846
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
847
+ svg.setAttribute("viewBox", `0 0 ${icon.width ?? 24} ${icon.height ?? 24}`);
848
+ svg.setAttribute("aria-hidden", "true");
849
+ svg.setAttribute("focusable", "false");
850
+ svg.setAttribute("data-keyline-icon", semanticName);
851
+ svg.innerHTML = icon.body;
852
+ placeholder.replaceWith(svg);
853
+ });
854
+ }
926
855
 
927
- // ../../node_modules/.pnpm/lucide@1.37.0/node_modules/lucide/dist/esm/lucide.mjs
928
- var createIcons = ({
929
- icons = {},
930
- nameAttr = "data-lucide",
931
- attrs = {},
932
- root = document,
933
- inTemplates
934
- } = {}) => {
935
- if (!Object.values(icons).length) {
936
- throw new Error(
937
- "Please provide an icons object.\nIf you want to use all the icons you can import it like:\n `import { createIcons, icons } from 'lucide';\nlucide.createIcons({icons});`"
938
- );
856
+ // src/workspace.ts
857
+ var DEFAULT_WORKSPACE_STATE = {
858
+ layersOpen: true,
859
+ inspectorOpen: true,
860
+ utility: null,
861
+ tray: "hidden",
862
+ workbenchOpen: false,
863
+ comparisonOpen: false
864
+ };
865
+ function updateWorkspace(state, action) {
866
+ if (action.type === "toggle-layers") {
867
+ return { ...state, layersOpen: action.open ?? !state.layersOpen };
939
868
  }
940
- if (typeof root === "undefined") {
941
- throw new Error("`createIcons()` only works in a browser environment.");
942
- }
943
- const elementsToReplace = Array.from(root.querySelectorAll(`[${nameAttr}]`));
944
- elementsToReplace.forEach((element) => replaceElement(element, { nameAttr, icons, attrs }));
945
- if (inTemplates) {
946
- const templates = Array.from(root.querySelectorAll("template"));
947
- templates.forEach(
948
- (template) => createIcons({
949
- icons,
950
- nameAttr,
951
- attrs,
952
- root: template.content,
953
- inTemplates
954
- })
955
- );
869
+ if (action.type === "toggle-inspector") {
870
+ return { ...state, inspectorOpen: action.open ?? !state.inspectorOpen };
956
871
  }
957
- if (nameAttr === "data-lucide") {
958
- const deprecatedElements = root.querySelectorAll("[icon-name]");
959
- if (deprecatedElements.length > 0) {
960
- console.warn(
961
- "[Lucide] Some icons were found with the now deprecated icon-name attribute. These will still be replaced for backwards compatibility, but will no longer be supported in v1.0 and you should switch to data-lucide"
962
- );
963
- Array.from(deprecatedElements).forEach(
964
- (element) => replaceElement(element, { nameAttr: "icon-name", icons, attrs })
965
- );
966
- }
872
+ if (action.type === "open-utility") {
873
+ return { ...state, utility: state.utility === action.utility ? null : action.utility };
967
874
  }
968
- };
875
+ if (action.type === "close-utility") return { ...state, utility: null };
876
+ if (action.type === "set-tray") return { ...state, tray: action.tray };
877
+ if (action.type === "set-workbench") return { ...state, workbenchOpen: action.open };
878
+ return { ...state, comparisonOpen: action.open };
879
+ }
880
+ function clampUtilityRect(rect, bounds, minimum = { width: 280, height: 280 }) {
881
+ const availableWidth = Math.max(minimum.width, bounds.right - bounds.left);
882
+ const availableHeight = Math.max(minimum.height, bounds.bottom - bounds.top);
883
+ const width = Math.min(Math.max(rect.width, minimum.width), availableWidth);
884
+ const height = Math.min(Math.max(rect.height, minimum.height), availableHeight);
885
+ return {
886
+ x: Math.min(Math.max(rect.x, bounds.left), Math.max(bounds.left, bounds.right - width)),
887
+ y: Math.min(Math.max(rect.y, bounds.top), Math.max(bounds.top, bounds.bottom - height)),
888
+ width,
889
+ height
890
+ };
891
+ }
969
892
 
970
893
  // src/index.ts
971
894
  var CATEGORY_LABELS = {
972
- layout: "Layout",
973
- typography: "Type",
974
- color: "Color",
895
+ layout: "Layout and spacing",
896
+ typography: "Typography",
897
+ color: "Fill and stroke",
975
898
  effects: "Effects",
976
899
  content: "Content",
977
- accessibility: "A11y",
900
+ accessibility: "Accessibility",
978
901
  motion: "Motion"
979
902
  };
980
903
  var CATEGORY_ICONS = {
@@ -986,66 +909,32 @@ var CATEGORY_ICONS = {
986
909
  accessibility: "accessibility",
987
910
  motion: "play"
988
911
  };
989
- var FOUNDRY_ICONS = {
990
- Accessibility,
991
- Activity,
992
- AlignHorizontalSpaceAround,
993
- ArrowDown,
994
- ArrowLeft,
995
- ArrowUp,
996
- Box,
997
- Bookmark,
998
- ChevronDown,
999
- ChevronRight,
1000
- Check,
1001
- Columns3,
1002
- Component,
1003
- Command,
1004
- Contrast,
1005
- Eye,
1006
- EyeOff,
1007
- FileText,
1008
- LayoutGrid,
1009
- Layers3: Layers,
1010
- Link2,
1011
- Lock,
1012
- Maximize2,
1013
- MousePointer2,
1014
- Palette,
1015
- PanelsTopLeft,
1016
- Play,
1017
- Sparkles,
1018
- TriangleAlert,
1019
- Type,
1020
- Redo2,
1021
- RotateCcw,
1022
- Save,
1023
- Undo2,
1024
- Unlink2,
1025
- WandSparkles,
1026
- X
1027
- };
1028
912
  var CONTROL_SECTIONS = {
1029
913
  layout: [
1030
914
  {
1031
- label: "Constraints",
1032
- properties: ["widthMode", "heightMode", "minWidth", "maxWidth", "aspectRatio", "overflow"],
915
+ label: "Position and size",
916
+ properties: [
917
+ "widthMode",
918
+ "heightMode",
919
+ "width",
920
+ "height",
921
+ "minWidth",
922
+ "maxWidth",
923
+ "aspectRatio",
924
+ "overflow"
925
+ ],
1033
926
  columns: 2,
1034
927
  prefixes: {
1035
928
  widthMode: "W",
1036
929
  heightMode: "H",
930
+ width: "W",
931
+ height: "H",
1037
932
  minWidth: "Min",
1038
933
  maxWidth: "Max",
1039
934
  aspectRatio: "Ratio",
1040
935
  overflow: "Clip"
1041
936
  }
1042
937
  },
1043
- {
1044
- label: "Size",
1045
- properties: ["width", "height"],
1046
- columns: 2,
1047
- prefixes: { width: "W", height: "H" }
1048
- },
1049
938
  {
1050
939
  label: "Flow",
1051
940
  properties: [
@@ -1132,34 +1021,34 @@ var CONTROL_SECTIONS = {
1132
1021
  ]
1133
1022
  };
1134
1023
  var PANEL_CSS = `
1135
- :host { all:initial; --fdc-ink:#171717; --fdc-paper:#fafafa; --fdc-surface:#ffffff; --fdc-subtle:#f2f2f2; --fdc-line:#ebebeb; --fdc-signal:#0070f3; --fdc-signal-soft:#d3e5ff; --fdc-component:#7257d9; --fdc-component-soft:#f1edff; --fdc-muted:#6b6b6b; --fdc-font:"Geist Sans",Geist,Arial,sans-serif; font-family:var(--fdc-font); color:var(--fdc-ink); }
1024
+ :host { all:initial; color-scheme:dark; --fdc-ink:#f0f1f3; --fdc-paper:#141416; --fdc-surface:#1c1c1f; --fdc-subtle:#242428; --fdc-elevated:#29292e; --fdc-line:#303035; --fdc-signal:#3b82f6; --fdc-signal-soft:#172d50; --fdc-component:#9b87f5; --fdc-component-soft:#28233d; --fdc-muted:#9a9aa2; --fdc-font:"Geist Sans",Geist,Arial,sans-serif; font-family:var(--fdc-font); color:var(--fdc-ink); }
1136
1025
  *,*::before,*::after { box-sizing:border-box;font-family:inherit; }
1137
1026
  button,select,input { font:inherit; }
1138
1027
  button:focus-visible,select:focus-visible,input:focus-visible { outline:2px solid var(--fdc-signal);outline-offset:2px; }
1139
1028
  .outline { position:fixed;z-index:2147483645;pointer-events:none;border:1.5px solid var(--fdc-signal);box-shadow:0 0 0 1px rgb(255 255 255 / 90%),0 0 0 4px rgb(54 89 244 / 12%);transition:top 80ms linear,left 80ms linear,width 80ms linear,height 80ms linear; }
1140
1029
  .measure { position:absolute;left:-2px;top:-28px;height:25px;display:flex;align-items:center;padding:0 9px;color:white;background:var(--fdc-signal);border-radius:5px 5px 5px 0;font:650 10px/1 var(--fdc-font);letter-spacing:.02em;white-space:nowrap;box-shadow:0 4px 14px rgb(25 43 124 / 20%); }
1141
1030
  .cross::before,.cross::after { content:"";position:absolute;background:var(--fdc-signal); }.cross::before { width:11px;height:1px;left:-6px;top:-1px; }.cross::after { width:1px;height:11px;left:-1px;top:-6px; }
1142
- .panel { position:fixed;z-index:2147483646;top:12px;right:12px;width:328px;min-width:300px;max-width:min(520px,calc(100vw - 24px));max-height:calc(100vh - 24px);overflow:hidden;display:flex;flex-direction:column;color:var(--fdc-ink);background:var(--fdc-surface);border:1px solid var(--fdc-line);box-shadow:0 1px 2px rgb(0 0 0 / 5%),0 10px 28px rgb(0 0 0 / 10%);pointer-events:auto;border-radius:10px; }
1031
+ .panel { position:fixed;z-index:2147483646;top:12px;right:12px;width:352px;min-width:312px;max-width:min(520px,calc(100vw - 24px));max-height:calc(100vh - 24px);overflow:hidden;display:flex;flex-direction:column;color:var(--fdc-ink);background:var(--fdc-surface);border:1px solid var(--fdc-line);box-shadow:0 1px 2px rgb(0 0 0 / 5%),0 10px 28px rgb(0 0 0 / 10%);pointer-events:auto;border-radius:12px; }
1143
1032
  .top { flex:none;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }
1144
1033
  .top-identity { position:relative;min-height:44px;display:flex;align-items:center;padding:0 12px; }
1145
- .brand { flex:1;display:flex;align-items:center;gap:8px;min-width:0; }.brand-mark { width:14px;height:15px;display:flex;align-items:flex-end;gap:2px; }.brand-mark i { display:block;width:3px;background:var(--fdc-signal);border-radius:2px 2px 1px 1px; }.brand-mark i:nth-child(1){height:7px}.brand-mark i:nth-child(2){height:14px}.brand-mark i:nth-child(3){height:10px}
1034
+ .brand { flex:1;display:flex;align-items:center;min-width:0; }
1146
1035
  .brand-copy { display:flex;align-items:baseline;gap:5px; }.brand-copy b { font-size:13px;line-height:1;font-weight:550;letter-spacing:-.02em; }.brand-copy span { color:var(--fdc-muted);font:400 10px/1 var(--fdc-font); }
1147
1036
  .session-status { flex:none;margin-left:8px;display:flex;align-items:center;gap:5px;padding:4px 7px;border:0;color:#236c59;background:#eef8f4;border-radius:999px;font:500 10px/1 var(--fdc-font);cursor:pointer; }.session-status i { width:5px;height:5px;background:#2ca67f;border-radius:50%; }.session-status.saving { color:#6b570f;background:#fff8d8; }.session-status.saving i { background:#d5a91d;animation:fdc-pulse 1s ease-in-out infinite; }.session-status.error,.session-status.offline { color:#8b4d3d;background:#faece7; }.session-status.error i,.session-status.offline i { background:#d16d51; }.session-status.saved { color:#236c59;background:#eef8f4; }.status-popover { position:absolute;z-index:2;top:39px;right:40px;width:238px;padding:10px;border:1px solid var(--fdc-line);border-radius:8px;background:white;box-shadow:0 10px 28px rgb(0 0 0 / 14%); }.status-popover[hidden] { display:none; }.status-popover strong { display:block;font-size:11px;font-weight:550; }.status-popover span,.status-popover code { display:block;margin-top:5px;overflow:hidden;text-overflow:ellipsis;color:var(--fdc-muted);font:400 9px/1.45 var(--fdc-font);white-space:nowrap; }.status-popover button { width:100%;height:28px;margin-top:8px;border:1px solid var(--fdc-line);border-radius:5px;background:white;color:var(--fdc-ink);font-size:9px;cursor:pointer; }
1148
1037
  .top-identity>.close { flex:none;margin-left:4px; }.top-actions { min-height:40px;display:grid;grid-template-columns:repeat(6,minmax(0,1fr));align-items:center;padding:4px 8px;border-top:1px solid var(--fdc-line);background:var(--fdc-surface); }.top-actions .icon-button { justify-self:center; }.icon-button { width:32px;height:32px;display:grid;place-items:center;border:0;border-radius:6px;background:transparent;color:var(--fdc-muted);cursor:pointer; }.icon-button:hover { background:var(--fdc-subtle);color:var(--fdc-ink); }.icon-button.active { color:#0761d1;background:#edf6ff; }.icon-button:disabled { opacity:.35;cursor:not-allowed; }.icon-button:disabled:hover { color:var(--fdc-muted);background:transparent; }
1149
- .selection { padding:12px;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }.selection-heading { display:flex;align-items:center;justify-content:space-between;margin-bottom:8px; }.selection-kind { max-width:200px;overflow:hidden;text-overflow:ellipsis;padding:4px 6px;color:#4d4d4d;background:var(--fdc-subtle);border-radius:4px;font:500 10px/1 var(--fdc-font);text-transform:uppercase;letter-spacing:.02em;white-space:nowrap; }.selection-state { color:var(--fdc-muted);font:400 10px/1 var(--fdc-font); }.selection strong { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:15px;line-height:1.3;font-weight:550;letter-spacing:-.02em; }.selection code { display:block;margin-top:5px;overflow:hidden;text-overflow:ellipsis;color:var(--fdc-muted);font:400 10px/1.45 var(--fdc-font);white-space:nowrap; }.selection-stats { display:flex;gap:5px;margin-top:10px; }.selection-stats[hidden] { display:none; }.selection-stats span { padding:4px 6px;color:#4d4d4d;background:var(--fdc-subtle);border-radius:5px;font:400 10px/1 var(--fdc-font); }.selection-stats span:first-child { color:#0761d1;background:#edf6ff; }
1150
- .scope { display:grid;grid-template-columns:1fr 1fr;gap:6px;padding:11px 12px;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }.scope label { display:flex;flex-direction:column;gap:5px;color:var(--fdc-muted);font:500 10px/1.2 var(--fdc-font); }.scope select { width:100%;height:30px;padding:0 7px;border:1px solid var(--fdc-line);border-radius:5px;background:var(--fdc-surface);color:var(--fdc-ink);font:400 11px/1 var(--fdc-font);text-transform:none;letter-spacing:0;outline:none;cursor:pointer; }
1151
- .tool-shelf { position:fixed;z-index:2147483646;left:50%;bottom:18px;transform:translateX(-50%);display:flex;align-items:center;gap:6px;max-width:calc(100vw - 32px);padding:6px;background:var(--fdc-surface);border:1px solid var(--fdc-line);border-radius:12px;box-shadow:0 2px 2px rgb(0 0 0 / 4%),0 8px 16px -4px rgb(0 0 0 / 14%);pointer-events:auto; }
1152
- .tool-select,.tab { position:relative;flex:none;width:36px;height:36px;display:grid;place-items:center;padding:0;border:0;border-radius:6px;background:transparent;color:#4d4d4d;cursor:pointer; }.tool-select:hover,.tab:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }.tool-select.active,.tab.active { color:white;background:var(--fdc-ink); }.tool-select svg,.tab svg,.icon-button svg { width:16px;height:16px;stroke-width:1.75;pointer-events:none; }.tool-select::after,.tab::after { content:attr(data-tooltip);position:absolute;left:50%;bottom:calc(100% + 8px);transform:translate(-50%,3px);padding:6px 8px;border-radius:5px;background:var(--fdc-ink);color:white;font:400 11px/1 var(--fdc-font);white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .12s ease,transform .12s ease; }.tool-select:hover::after,.tool-select:focus-visible::after,.tab:not(:disabled):hover::after,.tab:not(:disabled):focus-visible::after { opacity:1;transform:translate(-50%,0); }.tool-divider { width:1px;height:24px;flex:none;background:var(--fdc-line); }.tabs { display:flex;gap:2px;overflow:visible;scrollbar-width:none; }.tab:disabled { color:#a1a1a1;cursor:default; }.tab:disabled:hover { background:transparent; }
1153
- .controls { min-height:210px;overflow:auto;background:var(--fdc-surface); }.inspector-heading { position:sticky;top:0;z-index:1;height:42px;display:flex;align-items:center;gap:8px;padding:0 12px;background:rgb(255 255 255 / 96%);border-bottom:1px solid var(--fdc-line);backdrop-filter:blur(8px); }.inspector-heading svg { width:15px;height:15px;stroke-width:1.75;color:#4d4d4d; }.inspector-heading strong { font-size:12px;font-weight:550; }.property-count { margin-left:auto;color:var(--fdc-muted);font:400 10px/1 var(--fdc-font);letter-spacing:.01em; }.property-section { padding:0;border-bottom:1px solid var(--fdc-line); }.section-head { width:100%;min-height:39px;display:flex;align-items:center;padding:0 8px 0 4px;background:white;color:#3f3f3f; }.section-head:hover { background:#fcfcfc; }.section-toggle { min-width:0;min-height:39px;flex:1;display:flex;align-items:center;gap:7px;padding:0 8px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer; }.section-toggle>svg { width:12px;height:12px;color:#858585;transition:transform .12s ease; }.property-section.collapsed .section-toggle>svg { transform:rotate(-90deg); }.section-head strong { font-size:11px;font-weight:500; }.section-grid { display:grid;gap:8px;padding:0 12px 12px; }.property-section.collapsed .section-grid { display:none; }.section-grid.two { grid-template-columns:1fr 1fr; }.section-grid.stacked .property-control { grid-template-columns:1fr;gap:6px; }.property-control { display:grid;grid-template-columns:minmax(0,1fr) 132px 24px;align-items:center;gap:7px;min-height:34px; }.property-label { overflow:hidden;text-overflow:ellipsis;color:#4d4d4d;font-size:11px;font-weight:400;white-space:nowrap; }.control-field { position:relative;display:flex;align-items:center;min-width:0;height:32px;border:1px solid var(--fdc-line);border-radius:5px;background:var(--fdc-paper);overflow:hidden;transition:border-color .12s ease,box-shadow .12s ease,background .12s ease; }.control-field:hover { background:var(--fdc-surface); }.control-field:focus-within { border-color:var(--fdc-signal);background:var(--fdc-surface);box-shadow:0 0 0 2px rgb(0 112 243 / 10%); }.control-reset { width:24px;height:24px;display:grid;place-items:center;padding:0;border:0;border-radius:4px;background:transparent;color:#8a8a8a;cursor:pointer;opacity:0; }.property-control:hover .control-reset,.compact-control:hover .control-reset,.control-reset:focus-visible { opacity:1; }.control-reset:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }.control-reset svg { width:12px;height:12px; }.compact-control { min-width:0;display:grid;grid-template-columns:minmax(0,1fr) 24px;gap:5px;align-items:center; }.compact-control .control-field { width:100%; }.field-prefix { min-width:28px;padding-left:8px;color:#7a7a7a;font:400 10px/1 var(--fdc-font); }.compact-control .field-prefix.wide { min-width:40px; }.property-control input,.property-control select,.compact-control input,.compact-control select { width:100%;min-width:0;height:30px;padding:0 7px;border:0;background:transparent;color:var(--fdc-ink);font:400 11px/1 var(--fdc-font);outline:none; }.property-control input[type="number"],.compact-control input[type="number"] { appearance:textfield; }.property-control input[type="number"]::-webkit-inner-spin-button,.property-control input[type="number"]::-webkit-outer-spin-button,.compact-control input[type="number"]::-webkit-inner-spin-button,.compact-control input[type="number"]::-webkit-outer-spin-button { margin:0;appearance:none; }.property-control select { font-family:var(--fdc-font); }.control-field .unit-select { width:40px;flex:none;padding:0 3px;color:#707070;font-size:9px;cursor:pointer; }[data-scrub-for] { cursor:ew-resize;user-select:none;touch-action:none; }.property-label[data-scrub-for]:hover,.field-prefix[data-scrub-for]:hover,[data-scrub-for].scrubbing { color:var(--fdc-signal); }.color-swatch { width:17px;height:17px;flex:none;margin-left:7px;border:1px solid rgb(0 0 0 / 10%);border-radius:3px;background:var(--swatch-color); }.color-swatch.transparent { background-color:white;background-image:linear-gradient(45deg,#d9d9d9 25%,transparent 25%),linear-gradient(-45deg,#d9d9d9 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#d9d9d9 75%),linear-gradient(-45deg,transparent 75%,#d9d9d9 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0; }.color-value { overflow:hidden;text-overflow:ellipsis;margin-left:7px;color:#4d4d4d;font:400 10px/1 var(--fdc-font);white-space:nowrap; }.color-picker { position:absolute;inset:0;width:100%!important;height:100%!important;opacity:0;cursor:pointer; }.unit { padding-right:7px;color:#7a7a7a;font:400 10px/1 var(--fdc-font); }.sr-only { position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0; }
1038
+ .selection { position:relative;padding:14px;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }.selection::before { content:"";position:absolute;top:13px;left:0;width:2px;height:0;background:var(--fdc-signal);border-radius:0 2px 2px 0;transition:height .18s ease; }.panel.has-selection .selection::before { height:24px; }.selection-heading { display:flex;align-items:center;justify-content:space-between;margin-bottom:9px; }.selection-kind { max-width:220px;overflow:hidden;text-overflow:ellipsis;padding:4px 6px;color:#4d4d4d;background:var(--fdc-subtle);border-radius:4px;font:500 10px/1 var(--fdc-font);text-transform:uppercase;letter-spacing:.025em;white-space:nowrap; }.selection-state { color:var(--fdc-muted);font:450 10px/1 var(--fdc-font); }.panel.has-selection .selection-state { color:#0761d1; }.selection strong { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:16px;line-height:1.3;font-weight:550;letter-spacing:-.025em; }.selection code { display:block;margin-top:5px;overflow:hidden;text-overflow:ellipsis;color:var(--fdc-muted);font:400 11px/1.45 var(--fdc-font);white-space:nowrap; }.selection-hint { display:block;margin-top:9px;color:#858585;font:400 10px/1.45 var(--fdc-font); }.selection-stats { display:flex;gap:5px;margin-top:10px; }.selection-stats[hidden] { display:none; }.selection-stats span { padding:5px 7px;color:#4d4d4d;background:var(--fdc-subtle);border-radius:5px;font:400 10px/1 var(--fdc-font); }.selection-stats span:first-child { color:#0761d1;background:#edf6ff; }.selection.selected-flash strong { animation:fdc-selection-title .2s ease-out; }
1039
+ .scope { display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:12px 14px;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }.scope label { display:flex;flex-direction:column;gap:6px;color:var(--fdc-muted);font:500 11px/1.2 var(--fdc-font); }.scope select { width:100%;height:34px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:6px;background:var(--fdc-surface);color:var(--fdc-ink);font:400 12px/1 var(--fdc-font);text-transform:none;letter-spacing:0;outline:none;cursor:pointer; }
1040
+ .tool-shelf { position:fixed;z-index:2147483646;left:50%;bottom:18px;transform:translateX(-50%);display:flex;align-items:center;gap:6px;max-width:calc(100vw - 32px);padding:6px;background:var(--fdc-surface);border:1px solid var(--fdc-line);border-radius:12px;box-shadow:0 2px 2px rgb(0 0 0 / 4%),0 8px 16px -4px rgb(0 0 0 / 14%);pointer-events:auto; }.mode-copy { min-width:96px;display:flex;flex-direction:column;gap:2px;padding:0 6px 0 1px; }.mode-copy strong { font-size:10px;font-weight:550;line-height:1.1; }.mode-copy span { color:var(--fdc-muted);font-size:9px;line-height:1.2;white-space:nowrap; }
1041
+ .tool-select,.tab { position:relative;flex:none;width:36px;height:36px;display:grid;place-items:center;padding:0;border:0;border-radius:6px;background:transparent;color:#4d4d4d;cursor:pointer; }.tool-select:hover,.tab:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }.tool-select.active,.tab.active { color:white;background:var(--fdc-ink); }.tool-select svg,.tab svg,.icon-button svg { width:16px;height:16px;pointer-events:none; }.tool-select::after,.tab::after { content:attr(data-tooltip);position:absolute;left:50%;bottom:calc(100% + 8px);transform:translate(-50%,3px);padding:6px 8px;border-radius:5px;background:var(--fdc-ink);color:white;font:400 11px/1 var(--fdc-font);white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .12s ease,transform .12s ease; }.tool-select:hover::after,.tool-select:focus-visible::after,.tab:not(:disabled):hover::after,.tab:not(:disabled):focus-visible::after { opacity:1;transform:translate(-50%,0); }.tool-divider { width:1px;height:24px;flex:none;background:var(--fdc-line); }.tabs { display:flex;gap:2px;overflow:visible;scrollbar-width:none; }.tab:disabled { color:#a1a1a1;cursor:default; }.tab:disabled:hover { background:transparent; }
1042
+ .controls { min-height:210px;overflow:auto;background:var(--fdc-surface); }.inspector-heading { position:sticky;top:0;z-index:1;height:42px;display:flex;align-items:center;gap:8px;padding:0 12px;background:rgb(255 255 255 / 96%);border-bottom:1px solid var(--fdc-line);backdrop-filter:blur(8px); }.inspector-heading svg { width:15px;height:15px;color:#4d4d4d; }.inspector-heading strong { font-size:12px;font-weight:550; }.property-count { margin-left:auto;color:var(--fdc-muted);font:400 10px/1 var(--fdc-font);letter-spacing:.01em; }.property-section { padding:0;border-bottom:1px solid var(--fdc-line); }.section-head { width:100%;min-height:39px;display:flex;align-items:center;padding:0 8px 0 4px;background:white;color:#3f3f3f; }.section-head:hover { background:#fcfcfc; }.section-toggle { min-width:0;min-height:39px;flex:1;display:flex;align-items:center;gap:7px;padding:0 8px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer; }.section-toggle>svg { width:12px;height:12px;color:#858585;transition:transform .12s ease; }.property-section.collapsed .section-toggle>svg { transform:rotate(-90deg); }.section-head strong { font-size:11px;font-weight:500; }.section-grid { display:grid;gap:8px;padding:0 12px 12px; }.property-section.collapsed .section-grid { display:none; }.section-grid.two { grid-template-columns:1fr 1fr; }.section-grid.stacked .property-control { grid-template-columns:1fr;gap:6px; }.property-control { display:grid;grid-template-columns:minmax(0,1fr) 132px 24px;align-items:center;gap:7px;min-height:34px; }.property-label { overflow:hidden;text-overflow:ellipsis;color:#4d4d4d;font-size:11px;font-weight:400;white-space:nowrap; }.control-field { position:relative;display:flex;align-items:center;min-width:0;height:32px;border:1px solid var(--fdc-line);border-radius:5px;background:var(--fdc-paper);overflow:hidden;transition:border-color .12s ease,box-shadow .12s ease,background .12s ease; }.control-field:hover { background:var(--fdc-surface); }.control-field:focus-within { border-color:var(--fdc-signal);background:var(--fdc-surface);box-shadow:0 0 0 2px rgb(0 112 243 / 10%); }.control-reset { width:24px;height:24px;display:grid;place-items:center;padding:0;border:0;border-radius:4px;background:transparent;color:#8a8a8a;cursor:pointer;opacity:0; }.property-control:hover .control-reset,.compact-control:hover .control-reset,.control-reset:focus-visible { opacity:1; }.control-reset:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }.control-reset svg { width:12px;height:12px; }.compact-control { min-width:0;display:grid;grid-template-columns:minmax(0,1fr) 24px;gap:5px;align-items:center; }.compact-control .control-field { width:100%; }.field-prefix { min-width:28px;padding-left:8px;color:#7a7a7a;font:400 10px/1 var(--fdc-font); }.compact-control .field-prefix.wide { min-width:40px; }.property-control input,.property-control select,.compact-control input,.compact-control select { width:100%;min-width:0;height:30px;padding:0 7px;border:0;background:transparent;color:var(--fdc-ink);font:400 11px/1 var(--fdc-font);outline:none; }.property-control input[type="number"],.compact-control input[type="number"] { appearance:textfield; }.property-control input[type="number"]::-webkit-inner-spin-button,.property-control input[type="number"]::-webkit-outer-spin-button,.compact-control input[type="number"]::-webkit-inner-spin-button,.compact-control input[type="number"]::-webkit-outer-spin-button { margin:0;appearance:none; }.property-control select { font-family:var(--fdc-font); }.control-field .unit-select { width:40px;flex:none;padding:0 3px;color:#707070;font-size:9px;cursor:pointer; }[data-scrub-for] { cursor:ew-resize;user-select:none;touch-action:none; }.property-label[data-scrub-for]:hover,.field-prefix[data-scrub-for]:hover,[data-scrub-for].scrubbing { color:var(--fdc-signal); }.color-swatch { width:17px;height:17px;flex:none;margin-left:7px;border:1px solid rgb(0 0 0 / 10%);border-radius:3px;background:var(--swatch-color); }.color-swatch.transparent { background-color:white;background-image:linear-gradient(45deg,#d9d9d9 25%,transparent 25%),linear-gradient(-45deg,#d9d9d9 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#d9d9d9 75%),linear-gradient(-45deg,transparent 75%,#d9d9d9 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0; }.color-value { overflow:hidden;text-overflow:ellipsis;margin-left:7px;color:#4d4d4d;font:400 10px/1 var(--fdc-font);white-space:nowrap; }.color-picker { position:absolute;inset:0;width:100%!important;height:100%!important;opacity:0;cursor:pointer; }.unit { padding-right:7px;color:#7a7a7a;font:400 10px/1 var(--fdc-font); }.sr-only { position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0; }
1154
1043
  .motion-list { padding:0 12px 12px; }.motion-row { padding:12px 0;border-bottom:1px solid var(--fdc-line); }.motion-title { display:flex;justify-content:space-between;gap:12px;margin-bottom:9px;font-size:12px;font-weight:550; }.motion-title code { color:var(--fdc-muted);font:400 10px/1.3 var(--fdc-font); }.motion-actions { display:grid;grid-template-columns:repeat(4,1fr);gap:4px; }.motion-actions button { min-height:30px;padding:0 5px;border:1px solid var(--fdc-line);background:var(--fdc-paper);border-radius:5px;color:var(--fdc-ink);font-size:10px;font-weight:400;cursor:pointer; }.motion-actions button:hover { border-color:#c7c7c7;background:var(--fdc-surface); }
1155
1044
  .motion-timeline { width:100%;margin:2px 0 10px;accent-color:var(--fdc-signal); }.motion-fields { display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px; }.motion-fields label { display:grid;grid-template-columns:auto 1fr;align-items:center;gap:5px;color:var(--fdc-muted);font-size:9px; }.motion-fields input { width:100%;height:28px;padding:0 6px;border:1px solid var(--fdc-line);border-radius:5px;background:var(--fdc-paper);color:var(--fdc-ink);font-size:10px; }
1156
1045
  .empty { padding:48px 28px;text-align:center;color:var(--fdc-muted);font-size:13px;line-height:1.6; }.empty::before { content:"\u2316";display:grid;place-items:center;width:38px;height:38px;margin:0 auto 13px;color:var(--fdc-signal);background:var(--fdc-signal-soft);border-radius:10px;font:18px/1 var(--fdc-font); }
1157
1046
  .change-dock { min-height:48px;display:grid;grid-template-columns:minmax(0,1fr) 30px 68px;align-items:center;gap:6px;padding:7px 8px;border-top:1px solid var(--fdc-line);background:white; }.change-dock[hidden] { display:none; }.change-dock-copy { min-width:0;padding-left:3px; }.change-dock-copy strong,.change-dock-copy span { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }.change-dock-copy strong { font-size:10px;font-weight:550; }.change-dock-copy span { margin-top:3px;color:var(--fdc-muted);font-size:9px; }.change-dock button { height:30px;border:1px solid var(--fdc-line);border-radius:5px;background:white;color:var(--fdc-ink);font-size:9px;cursor:pointer; }.change-dock .dock-review { color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }.change-dock svg { width:12px;height:12px; }.footer { display:grid;grid-template-columns:82px 1fr;gap:6px;padding:8px;background:var(--fdc-surface);border-top:1px solid var(--fdc-line); }.footer:has(.review[hidden]) { grid-template-columns:1fr; }.footer button[hidden] { display:none; }.footer button { min-height:36px;border:1px solid var(--fdc-line);border-radius:6px;background:var(--fdc-surface);color:var(--fdc-ink);font-size:11px;font-weight:450;cursor:pointer; }.footer button:hover { border-color:#d0d0d0;background:var(--fdc-paper); }.footer .review { align-items:center;justify-content:center;gap:7px;color:white;background:var(--fdc-ink);border-color:var(--fdc-ink); }.footer .review:not([hidden]) { display:flex; }.footer .review:hover { background:#2f2f2f; }.change-count { min-width:18px;height:18px;display:inline-grid;place-items:center;padding:0 5px;color:var(--fdc-ink);background:white;border-radius:999px;font:500 9px/1 var(--fdc-font); }.change-count[hidden] { display:none; }
1158
1047
  .review-view { min-height:0;flex:1;display:none;flex-direction:column;background:var(--fdc-surface); }.panel.reviewing .selection,.panel.reviewing .scope,.panel.reviewing .controls,.panel.reviewing>.footer,.panel.reviewing>.change-dock { display:none; }.panel.reviewing .review-view { display:flex; }.review-head { min-height:48px;display:flex;align-items:center;gap:8px;padding:0 10px;border-bottom:1px solid var(--fdc-line); }.review-head button { width:30px;height:30px;display:grid;place-items:center;padding:0;border:0;border-radius:5px;background:transparent;color:var(--fdc-muted);cursor:pointer; }.review-head button:hover { background:var(--fdc-subtle);color:var(--fdc-ink); }.review-head svg { width:15px;height:15px; }.review-head strong { font-size:12px;font-weight:550; }.review-head span { margin-left:auto;color:var(--fdc-muted);font-size:10px; }.review-body { min-height:160px;overflow-x:hidden;overflow-y:auto; }.review-toolbar { position:sticky;top:0;z-index:1;display:flex;gap:5px;padding:7px 8px;border-bottom:1px solid var(--fdc-line);background:rgb(255 255 255 / 96%);backdrop-filter:blur(8px); }.review-toolbar button { height:27px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:5px;background:white;color:#555;font-size:9px;cursor:pointer; }.review-toolbar button:last-child { margin-left:auto; }.review-empty { padding:42px 24px;color:var(--fdc-muted);font-size:12px;line-height:1.55;text-align:center; }.review-group { border-bottom:1px solid var(--fdc-line); }.review-group-title { width:100%;min-height:36px;display:flex;align-items:center;gap:7px;padding:0 12px;border:0;background:white;color:var(--fdc-muted);font-size:10px;font-weight:500;text-align:left;cursor:pointer; }.review-group-title span { margin-left:auto;font-size:9px; }.review-group-title svg { width:11px;height:11px;transition:transform .12s ease; }.review-group.collapsed .review-group-title svg { transform:rotate(-90deg); }.review-group.collapsed .review-card { display:none; }.review-card { display:grid;grid-template-columns:18px minmax(0,1fr);gap:8px;padding:9px 12px 10px; }.review-card.rejected { opacity:.62; }.review-card+.review-card { border-top:1px solid var(--fdc-line); }.review-card input[type="checkbox"] { width:14px;height:14px;margin:2px 0 0;accent-color:var(--fdc-ink); }.review-card-main { min-width:0; }.review-card-line { display:flex;align-items:center;gap:7px; }.review-card-line strong { min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:11px;font-weight:500;white-space:nowrap; }.review-card-tools { display:flex;gap:3px;margin-left:auto; }.review-card-tools button { height:23px;padding:0 6px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#666;font-size:8px;cursor:pointer; }.confidence-pill { flex:none;padding:3px 5px;border-radius:4px;background:#edf6ff;color:#0761d1;font-size:9px;text-transform:capitalize; }.confidence-pill.unresolved { color:#984a2b;background:#fff0e8; }.review-values { display:grid;grid-template-columns:minmax(0,1fr) 12px minmax(0,1fr);align-items:center;gap:4px;margin-top:7px; }.review-before { overflow:hidden;text-overflow:ellipsis;padding:7px;color:var(--fdc-muted);background:var(--fdc-subtle);border-radius:4px;font-size:10px;white-space:nowrap; }.review-values>span { color:var(--fdc-muted);font-size:10px;text-align:center; }.review-after { width:100%;height:28px;min-width:0;padding:0 7px;border:1px solid var(--fdc-line);border-radius:4px;background:white;font-size:10px;outline:none; }.review-after:focus { border-color:var(--fdc-signal);box-shadow:0 0 0 2px rgb(0 112 243 / 10%); }.review-source { margin-top:6px;overflow-wrap:anywhere;color:var(--fdc-muted);font-size:9px;line-height:1.45; }.review-actions { display:grid;grid-template-columns:82px 1fr;gap:6px;padding:8px;border-top:1px solid var(--fdc-line); }.review-actions button { min-height:36px;border:1px solid var(--fdc-line);border-radius:6px;background:white;font-size:11px;cursor:pointer; }.review-actions .apply { color:white;background:var(--fdc-ink);border-color:var(--fdc-ink); }.review-actions button:disabled { opacity:.45;cursor:not-allowed; }.run-summary { padding:14px 12px;border-bottom:1px solid var(--fdc-line); }.run-state { display:flex;align-items:center;gap:8px; }.run-state i { width:8px;height:8px;border-radius:50%;background:#a3a3a3; }.run-state i.active { background:var(--fdc-signal);box-shadow:0 0 0 4px rgb(0 112 243 / 10%); }.run-state i.passed { background:#2ca67f; }.run-state i.attention { background:#d16d51; }.run-state strong { font-size:12px;font-weight:550;text-transform:capitalize; }.run-summary p { margin:8px 0 0;color:var(--fdc-muted);font-size:10px;line-height:1.5; }.run-steps { padding:4px 12px 10px; }.run-step { display:grid;grid-template-columns:18px minmax(0,1fr);gap:7px;padding:8px 0;border-bottom:1px solid var(--fdc-line); }.run-step:last-child { border-bottom:0; }.run-step span:first-child { color:var(--fdc-muted);font-size:10px; }.run-step strong { display:block;font-size:10px;font-weight:500;text-transform:capitalize; }.run-step p { margin:3px 0 0;color:var(--fdc-muted);font-size:9px;line-height:1.45; }.result-list { padding:0 12px 12px; }.result-row { display:flex;align-items:flex-start;justify-content:space-between;gap:8px;padding:8px 0;border-top:1px solid var(--fdc-line);font-size:10px; }.result-row span:last-child { color:var(--fdc-muted);text-align:right; }.result-row.pass span:first-child { color:#23715c; }.result-row.fail span:first-child { color:#a24d30; }.run-files { padding:0 12px 12px;color:var(--fdc-muted);font-size:9px;line-height:1.5; }.run-files code { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
1159
1048
  .toast { position:fixed;left:50%;bottom:76px;transform:translate(-50%,8px);padding:9px 12px;background:var(--fdc-ink);color:white;border-radius:6px;font-size:11px;font-weight:450;opacity:0;transition:.15s ease;pointer-events:none;white-space:nowrap;box-shadow:0 8px 20px rgb(0 0 0 / 16%); }.toast.show { opacity:1;transform:translate(-50%,0); }
1160
- .resize-handle { position:absolute;width:9px;height:9px;border:1px solid white;border-radius:2px;background:var(--fdc-signal);box-shadow:0 1px 4px rgb(0 0 0 / 20%);pointer-events:auto;touch-action:none; }
1049
+ .resize-handle { position:absolute;width:9px;height:9px;min-width:9px;min-height:9px;aspect-ratio:1;padding:0;border:1px solid #f0f1f3;border-radius:1px;background:var(--fdc-signal);box-shadow:0 1px 4px rgb(0 0 0 / 28%);appearance:none;pointer-events:auto;touch-action:none; }
1161
1050
  .resize-handle[data-handle="n"]{top:-5px;left:calc(50% - 4px);cursor:ns-resize}.resize-handle[data-handle="s"]{bottom:-5px;left:calc(50% - 4px);cursor:ns-resize}.resize-handle[data-handle="e"]{right:-5px;top:calc(50% - 4px);cursor:ew-resize}.resize-handle[data-handle="w"]{left:-5px;top:calc(50% - 4px);cursor:ew-resize}.resize-handle[data-handle="ne"]{right:-5px;top:-5px;cursor:nesw-resize}.resize-handle[data-handle="nw"]{left:-5px;top:-5px;cursor:nwse-resize}.resize-handle[data-handle="se"]{right:-5px;bottom:-5px;cursor:nwse-resize}.resize-handle[data-handle="sw"]{left:-5px;bottom:-5px;cursor:nesw-resize}
1162
- .panel-resizer { position:absolute;z-index:3;top:84px;bottom:0;left:-4px;width:8px;border:0;background:transparent;cursor:ew-resize;touch-action:none; }.panel-resizer::after { content:"";position:absolute;top:50%;left:3px;width:2px;height:28px;transform:translateY(-50%);border-radius:2px;background:#d7d7d7;opacity:0;transition:opacity .12s ease; }.panel:hover .panel-resizer::after,.panel-resizer:focus-visible::after { opacity:1; }.radius-handle { position:absolute;top:7px;left:7px;width:10px;height:10px;border:2px solid white;border-radius:50%;background:#ff4d8d;box-shadow:0 1px 4px rgb(0 0 0 / 18%);pointer-events:auto;cursor:nwse-resize;touch-action:none; }
1051
+ .panel-resizer { position:absolute;z-index:3;top:84px;bottom:0;left:-4px;width:8px;border:0;background:transparent;cursor:ew-resize;touch-action:none; }.panel-resizer::after { content:"";position:absolute;top:50%;left:3px;width:2px;height:28px;transform:translateY(-50%);border-radius:2px;background:#4a4a50;opacity:0;transition:opacity .12s ease; }.panel:hover .panel-resizer::after,.panel-resizer:focus-visible::after { opacity:1; }.radius-handle { position:absolute;top:7px;left:7px;width:10px;height:10px;min-width:10px;min-height:10px;aspect-ratio:1;padding:0;border:2px solid #f0f1f3;border-radius:50%;background:#ff4d8d;box-shadow:0 1px 4px rgb(0 0 0 / 28%);appearance:none;pointer-events:auto;cursor:nwse-resize;touch-action:none; }
1163
1052
  .canvas-variant { position:fixed;z-index:2147483645;height:27px;max-width:180px;padding:0 25px 0 8px;border:1px solid #b8d5ff;border-radius:6px;background:white;color:#075fc5;font-size:9px;box-shadow:0 5px 14px rgb(0 0 0 / 10%);pointer-events:auto; }.canvas-variant[hidden] { display:none; }
1164
1053
  .onboarding-card { position:fixed;z-index:2147483647;left:50%;bottom:78px;width:286px;transform:translateX(-50%);padding:13px;border:1px solid var(--fdc-line);border-radius:10px;background:white;box-shadow:0 12px 32px rgb(0 0 0 / 14%);pointer-events:auto; }.onboarding-card[hidden] { display:none; }.onboarding-card-head { display:flex;align-items:center;gap:8px; }.onboarding-card-head svg { width:15px;height:15px;color:var(--fdc-signal); }.onboarding-card-head strong { font-size:11px;font-weight:550; }.onboarding-card p { margin:8px 0 11px;color:var(--fdc-muted);font-size:10px;line-height:1.5; }.onboarding-steps { display:grid;grid-template-columns:repeat(3,1fr);gap:5px; }.onboarding-steps span { padding:7px 5px;border:1px solid var(--fdc-line);border-radius:6px;color:#555;font-size:9px;line-height:1.35;text-align:center; }.onboarding-actions { display:flex;justify-content:flex-end;gap:5px;margin-top:10px; }.onboarding-actions button { height:28px;padding:0 9px;border:1px solid var(--fdc-line);border-radius:5px;background:white;font-size:9px;cursor:pointer; }.onboarding-actions .onboarding-start { color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }
1165
1054
  .review-details { margin-top:7px;color:var(--fdc-muted);font-size:9px; }.review-details summary { cursor:pointer;user-select:none; }.review-details[open] summary { margin-bottom:5px; }.review-details .review-source { display:block; }.review-details .impact-list { display:grid;gap:3px;margin-top:5px; }
@@ -1173,7 +1062,7 @@ var PANEL_CSS = `
1173
1062
  .selection-path { display:flex;align-items:center;gap:4px;margin-top:9px;min-width:0; }.selection-path button { min-width:0;height:25px;display:flex;align-items:center;gap:4px;padding:0 7px;border:1px solid var(--fdc-line);border-radius:5px;background:var(--fdc-paper);color:#555;font-size:9px;cursor:pointer; }.selection-path button:hover { color:var(--fdc-ink);border-color:#d2d2d2;background:white; }.selection-path button:disabled { opacity:.4;cursor:default; }.selection-path svg { width:11px;height:11px; }.selection-path .path-name { flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
1174
1063
  .selection-path[hidden] { display:none; }
1175
1064
  .layers-panel { position:fixed;z-index:2147483646;top:12px;left:12px;width:252px;max-height:calc(100vh - 24px);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--fdc-line);border-radius:10px;background:var(--fdc-surface);box-shadow:0 1px 2px rgb(0 0 0 / 5%),0 10px 28px rgb(0 0 0 / 10%);pointer-events:auto; }.layers-panel[hidden] { display:none; }.layers-head { min-height:44px;display:flex;align-items:center;gap:8px;padding:0 8px 0 12px;border-bottom:1px solid var(--fdc-line); }.layers-head svg { width:15px;height:15px; }.layers-head strong { font-size:12px;font-weight:550; }.layers-head span { color:var(--fdc-muted);font-size:9px; }.layers-head .icon-button { margin-left:auto; }.layers-search { padding:8px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.layers-search input { width:100%;height:30px;padding:0 9px;border:1px solid var(--fdc-line);border-radius:5px;background:white;color:var(--fdc-ink);font-size:10px;outline:none; }.layers-search input:focus { border-color:var(--fdc-signal);box-shadow:0 0 0 2px rgb(0 112 243 / 10%); }.layer-tree { min-height:120px;overflow:auto;padding:5px; }.layer-row { width:100%;height:30px;display:grid;grid-template-columns:14px 14px minmax(0,1fr) auto;align-items:center;gap:4px;padding:0 7px 0 calc(7px + var(--layer-depth) * 12px);border:0;border-radius:5px;background:transparent;color:#474747;text-align:left;cursor:pointer; }.layer-row:hover { background:var(--fdc-subtle); }.layer-row.selected { color:#075fc5;background:#eaf3ff; }.layer-row .chevron,.layer-row .layer-icon { width:12px;height:12px;color:#8a8a8a; }.layer-row .layer-label { overflow:hidden;text-overflow:ellipsis;font-size:10px;white-space:nowrap; }.layer-row .layer-meta { padding:2px 4px;border-radius:3px;background:#f0f0f0;color:#747474;font-size:8px;text-transform:uppercase; }.layer-row.selected .layer-meta { color:#075fc5;background:#d8e9ff; }.layers-empty { padding:34px 18px;color:var(--fdc-muted);font-size:10px;line-height:1.5;text-align:center; }
1176
- .layers-switch { display:grid;grid-template-columns:1fr 1fr;gap:3px;padding:5px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.layers-switch button { min-width:0;height:28px;display:flex;align-items:center;justify-content:center;gap:6px;padding:0 7px;border:0;border-radius:5px;background:transparent;color:var(--fdc-muted);font-size:10px;cursor:pointer; }.layers-switch button:hover { color:var(--fdc-ink);background:white; }.layers-switch button.active { color:var(--fdc-ink);background:white;box-shadow:0 0 0 1px var(--fdc-line),0 1px 2px rgb(0 0 0 / 5%); }.layers-switch button span { min-width:17px;height:17px;display:grid;place-items:center;padding:0 4px;border-radius:999px;background:var(--fdc-subtle);color:#747474;font-size:8px; }.layers-switch button[data-layer-view="components"].active { color:#5f46bf; }.layers-switch button[data-layer-view="components"].active span { color:#5f46bf;background:var(--fdc-component-soft); }.component-list { display:grid;gap:5px;padding:2px; }.component-card { overflow:hidden;border:1px solid var(--fdc-line);border-radius:7px;background:white; }.component-card:hover { border-color:#d7d0f3;box-shadow:0 2px 8px rgb(52 38 110 / 6%); }.component-card.selected { border-color:#c8bdf1;background:#fbfaff;box-shadow:0 0 0 2px rgb(114 87 217 / 8%); }.component-main { width:100%;min-height:52px;display:grid;grid-template-columns:30px minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 8px;border:0;background:transparent;color:var(--fdc-ink);text-align:left;cursor:pointer; }.component-main:disabled { cursor:default; }.component-mark { width:28px;height:28px;display:grid;place-items:center;border-radius:7px;color:var(--fdc-component);background:var(--fdc-component-soft); }.component-mark svg { width:14px;height:14px;stroke-width:1.8; }.component-copy { min-width:0; }.component-copy strong,.component-copy span { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }.component-copy strong { font-size:10px;font-weight:550; }.component-copy span { margin-top:4px;color:var(--fdc-muted);font-size:8px; }.component-status { display:flex;flex-direction:column;align-items:flex-end;gap:4px; }.component-status span { padding:2px 5px;border-radius:999px;color:#5f46bf;background:var(--fdc-component-soft);font-size:8px;white-space:nowrap; }.component-status small { color:#8b8b8b;font-size:8px;white-space:nowrap; }.component-variants { display:flex;gap:4px;overflow:hidden;padding:0 8px 8px 45px; }.component-variants span { max-width:88px;overflow:hidden;text-overflow:ellipsis;padding:3px 5px;border:1px solid #e6e1f7;border-radius:4px;color:#66598c;background:#faf9ff;font-size:8px;white-space:nowrap; }
1065
+ .layers-switch { display:grid;grid-template-columns:1fr 1fr;gap:3px;padding:5px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.layers-switch button { min-width:0;height:28px;display:flex;align-items:center;justify-content:center;gap:6px;padding:0 7px;border:0;border-radius:5px;background:transparent;color:var(--fdc-muted);font-size:10px;cursor:pointer; }.layers-switch button:hover { color:var(--fdc-ink);background:white; }.layers-switch button.active { color:var(--fdc-ink);background:white;box-shadow:0 0 0 1px var(--fdc-line),0 1px 2px rgb(0 0 0 / 5%); }.layers-switch button span { min-width:17px;height:17px;display:grid;place-items:center;padding:0 4px;border-radius:999px;background:var(--fdc-subtle);color:#747474;font-size:8px; }.layers-switch button[data-layer-view="components"].active { color:#5f46bf; }.layers-switch button[data-layer-view="components"].active span { color:#5f46bf;background:var(--fdc-component-soft); }.component-list { display:grid;gap:5px;padding:2px; }.component-card { overflow:hidden;border:1px solid var(--fdc-line);border-radius:7px;background:white; }.component-card:hover { border-color:#d7d0f3;box-shadow:0 2px 8px rgb(52 38 110 / 6%); }.component-card.selected { border-color:#c8bdf1;background:#fbfaff;box-shadow:0 0 0 2px rgb(114 87 217 / 8%); }.component-main { width:100%;min-height:52px;display:grid;grid-template-columns:30px minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 8px;border:0;background:transparent;color:var(--fdc-ink);text-align:left;cursor:pointer; }.component-main:disabled { cursor:default; }.component-mark { width:28px;height:28px;display:grid;place-items:center;border-radius:7px;color:var(--fdc-component);background:var(--fdc-component-soft); }.component-mark svg { width:14px;height:14px; }.component-copy { min-width:0; }.component-copy strong,.component-copy span { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }.component-copy strong { font-size:10px;font-weight:550; }.component-copy span { margin-top:4px;color:var(--fdc-muted);font-size:8px; }.component-status { display:flex;flex-direction:column;align-items:flex-end;gap:4px; }.component-status span { padding:2px 5px;border-radius:999px;color:#5f46bf;background:var(--fdc-component-soft);font-size:8px;white-space:nowrap; }.component-status small { color:#8b8b8b;font-size:8px;white-space:nowrap; }.component-variants { display:flex;gap:4px;overflow:hidden;padding:0 8px 8px 45px; }.component-variants span { max-width:88px;overflow:hidden;text-overflow:ellipsis;padding:3px 5px;border:1px solid #e6e1f7;border-radius:4px;color:#66598c;background:#faf9ff;font-size:8px;white-space:nowrap; }
1177
1066
  .layer-row { grid-template-columns:16px minmax(0,1fr);gap:1px;padding-right:4px;cursor:default; }.layer-row.dragging { opacity:.45; }.layer-row.drop-target { box-shadow:inset 0 2px 0 var(--fdc-signal); }.layer-spacer { width:1px;pointer-events:none; }.layer-toggle { width:16px;height:28px;display:grid;place-items:center;padding:0;border:0;background:transparent;color:#858585;cursor:pointer; }.layer-toggle:disabled { visibility:hidden; }.layer-toggle svg { width:11px;height:11px; }.layer-select { min-width:0;height:28px;display:grid;grid-template-columns:14px minmax(0,1fr) auto;align-items:center;gap:5px;padding:0 4px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer; }
1178
1067
  .health-panel { position:fixed;z-index:2147483646;top:12px;left:12px;width:304px;max-height:calc(100vh - 24px);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--fdc-line);border-radius:10px;background:var(--fdc-surface);box-shadow:0 1px 2px rgb(0 0 0 / 5%),0 10px 28px rgb(0 0 0 / 10%);pointer-events:auto; }.health-panel[hidden] { display:none; }.health-head { min-height:48px;display:flex;align-items:center;gap:8px;padding:0 8px 0 12px;border-bottom:1px solid var(--fdc-line); }.health-head>svg { width:15px;height:15px; }.health-head strong { font-size:12px;font-weight:550; }.health-head .icon-button { margin-left:auto; }.health-summary { display:grid;grid-template-columns:54px minmax(0,1fr);gap:10px;padding:12px;border-bottom:1px solid var(--fdc-line); }.health-score { width:54px;height:54px;display:grid;place-items:center;border-radius:50%;background:conic-gradient(var(--score-color) calc(var(--score) * 1%),#ececec 0); }.health-score::before { content:"";grid-area:1/1;width:42px;height:42px;border-radius:50%;background:white; }.health-score strong { z-index:1;grid-area:1/1;font-size:15px;font-weight:600; }.health-summary-copy { min-width:0;align-self:center; }.health-summary-copy strong { display:block;font-size:11px;font-weight:550; }.health-summary-copy span { display:block;margin-top:4px;color:var(--fdc-muted);font-size:9px;line-height:1.4; }.health-filters { display:flex;gap:4px;padding:7px 8px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.health-filters button { min-height:27px;padding:0 8px;border:1px solid transparent;border-radius:5px;background:transparent;color:#666;font-size:9px;cursor:pointer; }.health-filters button:hover,.health-filters button.active { border-color:var(--fdc-line);background:white;color:var(--fdc-ink); }.health-list { min-height:120px;overflow:auto;padding:6px; }.health-card { padding:10px;border:1px solid var(--fdc-line);border-radius:7px;background:white; }.health-card+.health-card { margin-top:6px; }.health-card-top { display:flex;align-items:center;gap:6px; }.health-severity { width:7px;height:7px;flex:none;border-radius:50%;background:#a3a3a3; }.health-severity.high { background:#d15d43; }.health-severity.medium { background:#d69b3c; }.health-severity.low { background:#4b84cb; }.health-card-top strong { min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:10px;font-weight:550;white-space:nowrap; }.health-card-top span:last-child { margin-left:auto;color:var(--fdc-muted);font-size:8px;text-transform:capitalize; }.health-card p { margin:7px 0 0;color:#5d5d5d;font-size:9px;line-height:1.45; }.health-evidence { margin-top:6px;padding:6px;border-radius:4px;background:var(--fdc-paper);color:#777;font-size:8px;line-height:1.4; }.health-actions { display:flex;gap:5px;margin-top:8px; }.health-actions button { min-height:27px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:5px;background:white;color:#555;font-size:9px;cursor:pointer; }.health-actions button:hover { border-color:#c8c8c8;color:var(--fdc-ink); }.health-actions .health-fix { margin-left:auto;color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }.health-actions .health-fix.previewed { color:#23715c;border-color:#bcded2;background:#edf8f4;cursor:default; }.health-actions .health-fix:disabled { opacity:1; }.health-actions .health-ignore { padding:0 6px;color:#888;border-color:transparent; }.health-footer { display:flex;align-items:center;gap:5px;padding:8px;border-top:1px solid var(--fdc-line); }.health-footer button { min-height:30px;padding:0 9px;border:1px solid var(--fdc-line);border-radius:5px;background:white;color:#555;font-size:9px;cursor:pointer; }.health-footer .health-rescan { flex:1;color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }.health-empty { padding:36px 18px;text-align:center;color:var(--fdc-muted);font-size:10px;line-height:1.5; }.health-empty svg { display:block;width:22px;height:22px;margin:0 auto 10px;color:#2b9a76; }
1179
1068
  .tool-select:disabled { color:#b6b6b6;cursor:default; }.tool-select:disabled:hover { background:transparent; }
@@ -1194,7 +1083,115 @@ var PANEL_CSS = `
1194
1083
  .component-actions { display:flex;gap:4px;padding:0 8px 8px 45px; }.component-actions button,.component-variants button { height:24px;padding:0 6px;border:1px solid #e6e1f7;border-radius:4px;color:#66598c;background:#faf9ff;font-size:8px;cursor:pointer; }.component-actions button:hover,.component-variants button:hover { border-color:#c8bdf1;background:#f4f0ff; }
1195
1084
  .token-provenance { grid-column:2;display:flex;align-items:center;gap:5px;margin-top:5px;color:#23715c;font-size:8px; }.token-provenance.literal { color:#985033; }.token-provenance::before { content:"";width:5px;height:5px;border-radius:50%;background:currentColor; }
1196
1085
  .workbench-matrix[hidden] { display:none; }
1197
- @media (max-width:680px){.panel{top:auto;right:8px;bottom:66px;left:8px;width:auto;max-height:58vh}.layers-panel,.health-panel,.library-panel{top:8px;right:8px;left:8px;width:auto;max-height:42vh}.scope{display:none}.controls{min-height:170px}.tool-shelf{right:8px;bottom:8px;left:8px;transform:none;max-width:none}.tabs{flex:1;overflow-x:auto}.tool-select::after,.tab::after{display:none}.footer{grid-template-columns:78px 1fr}.workbench-controls select,.workbench-controls button:not(.icon-button){max-width:92px}.workbench-matrix{grid-template-columns:76px repeat(var(--matrix-columns),minmax(90px,1fr))}}
1086
+ /* Foundry dark instrument theme */
1087
+ .panel,.layers-panel,.health-panel,.library-panel,.tool-shelf,.onboarding-card,.compare-bar,.command-palette,.status-popover,.canvas-variant { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line);box-shadow:0 1px 2px rgb(0 0 0 / 24%),0 14px 36px rgb(0 0 0 / 36%); }
1088
+ .top,.top-actions,.selection,.scope,.controls,.property-section,.change-dock,.footer,.review-view,.review-head,.review-group,.review-group-title,.review-actions,.layers-head,.layer-tree,.health-head,.health-list,.health-footer,.library-head,.library-actions,.library-body,.memory-card,.context-tools,.native-panel { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line); }
1089
+ .inspector-heading,.review-toolbar { background:rgb(28 28 31 / 96%);border-color:var(--fdc-line); }
1090
+ .section-head,.section-head:hover,.onboarding-step { color:var(--fdc-ink);background:var(--fdc-surface); }
1091
+ .icon-button,.tool-select,.tab,.section-toggle,.review-head button,.review-group-title,.compare-bar button { color:var(--fdc-muted); }
1092
+ .icon-button:hover,.review-head button:hover,.section-head:hover,.layer-row:hover,.command-item:hover,.command-item.active { color:var(--fdc-ink);background:var(--fdc-subtle); }
1093
+ .tool-select.active,.tab.active { color:var(--fdc-ink);background:#34343a; }.tool-select.inspect.active { color:white;background:var(--fdc-signal); }
1094
+ .icon-button.active,.section-head .section-action.active,.context-tools button.active { color:#9ec5ff;background:var(--fdc-signal-soft);border-color:#315482; }
1095
+ .tool-select::after,.tab::after { color:#141416;background:#f0f1f3;border:1px solid #ffffff; }
1096
+ .selection-kind,.selection-stats span,.layer-badge { color:#c8c8ce;background:var(--fdc-subtle); }.selection-stats span:first-child { color:#86b7ff;background:var(--fdc-signal-soft); }
1097
+ .selection-path button,.control-field,.native-search,.layers-search input,.review-after,.review-toolbar button,.review-card-tools button,.review-actions button,.change-dock button,.footer button,.status-popover button,.health-actions button,.health-footer button,.context-tools button,.native-chip,.variant-button,.library-actions button,.memory-card-actions button,.empty-state-actions button,.onboarding-actions button { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }
1098
+ .selection-path button:hover,.control-field:hover,.footer button:hover { color:var(--fdc-ink);background:#303036;border-color:#494950; }
1099
+ .scope select,.property-control input,.property-control select,.compact-control input,.compact-control select,.native-search,.command-palette input { color:var(--fdc-ink);background:var(--fdc-paper);border-color:var(--fdc-line); }
1100
+ .scope select option,.property-control select option,.compact-control select option { color:var(--fdc-ink);background:var(--fdc-paper); }
1101
+ .property-label,.section-head,.color-value,.layer-row,.command-item,.library-section-head { color:#d1d1d6; }.field-prefix,.unit,.control-field .unit-select,.section-toggle>svg,.layer-row .chevron,.layer-row .layer-icon,.command-item svg,.command-item small { color:var(--fdc-muted); }
1102
+ .layer-row.selected { color:#a9cbff;background:var(--fdc-signal-soft); }.layer-row.selected .layer-icon { color:#86b7ff; }
1103
+ .layer-row .layer-meta { color:#b5b5bc;background:var(--fdc-elevated); }.layer-row.selected .layer-meta { color:#a9cbff;background:#23416d; }
1104
+ .layers-search { background:var(--fdc-paper); }.layers-switch { background:var(--fdc-paper);border-color:var(--fdc-line); }.layers-switch button { color:var(--fdc-muted);background:transparent; }.layers-switch button:hover,.layers-switch button.active { color:var(--fdc-ink);background:var(--fdc-elevated); }.layers-switch button[data-layer-view="components"].active,.layers-switch button[data-layer-view="components"].active span { color:#c1b5f5;background:var(--fdc-component-soft); }
1105
+ .token-chip { color:#d1d1d6;background:var(--fdc-paper);border-color:var(--fdc-line); }.token-chip:hover { color:#9ec5ff;background:var(--fdc-signal-soft);border-color:#315482; }
1106
+ .review-summary { background:var(--fdc-paper); }.review-before { color:var(--fdc-muted);background:var(--fdc-subtle); }.review-sample { color:var(--fdc-muted);background:var(--fdc-paper);border-color:var(--fdc-line); }.review-sample::after { color:var(--fdc-muted);background:rgb(28 28 31 / 88%); }
1107
+ .confidence-pill { color:#9ec5ff;background:var(--fdc-signal-soft); }.confidence-pill.unresolved { color:#f2ae8f;background:#42271d; }
1108
+ .session-status,.session-status.saved { color:#83d8bb;background:#18352c; }.session-status.saving { color:#efd979;background:#3d3417; }.session-status.error,.session-status.offline { color:#f0a18b;background:#40251f; }
1109
+ .empty-state-icon { color:#9ec5ff;background:var(--fdc-signal-soft); }.onboarding-card-head span { color:#e7a68c;background:#36231d; }
1110
+ .change-count { color:var(--fdc-ink);background:var(--fdc-paper); }
1111
+ .change-dock .dock-review,.footer .review,.review-actions .apply,.onboarding-actions .onboarding-start,.health-actions .health-fix,.health-footer .health-rescan,.memory-card-actions button:first-child,.empty-state-actions button:first-child { color:#141416;background:#f0f1f3;border-color:#f0f1f3; }.change-dock .dock-review:hover,.footer .review:hover,.review-actions .apply:hover { color:#141416;background:#ffffff; }
1112
+ .panel-resizer::after { background:#4a4a50; }
1113
+ .empty-state { min-height:220px;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:36px 30px;text-align:center; }.empty-state-icon { width:38px;height:38px;display:grid;place-items:center;margin-bottom:14px;border-radius:10px; }.empty-state-icon svg { width:16px;height:16px; }.empty-state strong { font-size:13px;font-weight:550;letter-spacing:-.01em; }.empty-state p { max-width:230px;margin:7px 0 0;color:var(--fdc-muted);font-size:11px;line-height:1.55; }.empty-state-actions { display:flex;align-items:center;gap:6px;margin-top:16px; }.empty-state-actions button { height:30px;padding:0 10px;border:1px solid var(--fdc-line);border-radius:6px;font-size:10px;cursor:pointer; }.empty-state kbd { margin-top:12px;color:var(--fdc-muted);font:400 9px/1.4 var(--fdc-font); }
1114
+ .review-head strong { font-size:13px; }.review-summary { padding:13px 14px 12px;border-bottom:1px solid var(--fdc-line);background:#fcfcfc; }.review-summary strong { display:block;font-size:12px;font-weight:550;letter-spacing:-.01em; }.review-summary span { display:block;margin-top:4px;color:var(--fdc-muted);font-size:10px;line-height:1.45; }.review-summary.attention strong { color:#8b4d3d; }.review-toolbar button { height:28px;padding:0 9px;font-size:10px; }
1115
+ .onboarding-card { bottom:82px;width:340px;padding:16px;border-radius:12px;box-shadow:0 14px 38px rgb(0 0 0 / 15%); }.onboarding-card-head { gap:9px; }.onboarding-card-head span { width:26px;height:26px;display:grid;place-items:center;color:#a75031;background:#fbf1ed;border-radius:7px; }.onboarding-card-head svg { width:14px;height:14px;color:inherit; }.onboarding-card-head strong { font-size:13px;letter-spacing:-.015em; }.onboarding-card>p { margin:9px 0 14px;font-size:11px;line-height:1.55; }.onboarding-steps { display:grid;grid-template-columns:1fr;gap:1px;border:1px solid var(--fdc-line);border-radius:8px;overflow:hidden;background:var(--fdc-line); }.onboarding-step { display:grid;grid-template-columns:24px 1fr;gap:9px;padding:9px 10px;background:white;text-align:left; }.onboarding-step b { color:#8a8a8a;font-size:9px;font-weight:500;letter-spacing:.04em; }.onboarding-step strong { display:block;font-size:10px;font-weight:550; }.onboarding-step small { display:block;margin-top:2px;color:var(--fdc-muted);font-size:9px;line-height:1.35; }.onboarding-actions { gap:6px;margin-top:13px; }.onboarding-actions button { height:32px;padding:0 11px;border-radius:6px;font-size:10px; }
1116
+ .onboarding-card,.onboarding-step { color:var(--fdc-ink);background:var(--fdc-surface); }.onboarding-card-head span { color:#e7a68c;background:#36231d; }.onboarding-actions button { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }.onboarding-actions .onboarding-start { color:#141416;background:#f0f1f3;border-color:#f0f1f3; }
1117
+ .review-summary { color:var(--fdc-ink);background:var(--fdc-paper); }.empty-state-icon { color:#9ec5ff;background:var(--fdc-signal-soft); }
1118
+ .component-card,.health-card { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line); }.component-card.selected { color:var(--fdc-ink);background:var(--fdc-component-soft);border-color:#5c4b9e;box-shadow:0 0 0 2px rgb(155 135 245 / 10%); }.component-variants span,.component-actions button,.component-variants button { color:#c1b5f5;background:var(--fdc-component-soft);border-color:#4a406f; }.health-score::before { background:var(--fdc-surface); }.health-filters button { color:var(--fdc-muted); }.health-filters button:hover,.health-filters button.active { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }.health-card p,.health-evidence { color:var(--fdc-muted); }.mapping-chooser { color:#f0c9a8;background:#35291d;border-color:#665039; }.mapping-chooser>strong,.mapping-option,.mapping-option small { color:#e7c29f; }.review-card.locating { background:var(--fdc-signal-soft); }.baseline-badge { color:#83d8bb;background:#18352c; }
1119
+ /* Workspace ownership */
1120
+ .workspace-bar { position:fixed;z-index:2147483647;top:12px;left:50%;min-height:48px;display:flex;align-items:center;gap:5px;padding:6px;transform:translateX(-50%);color:var(--fdc-ink);background:rgb(28 28 31 / 96%);border:1px solid var(--fdc-line);border-radius:12px;box-shadow:0 2px 2px rgb(0 0 0 / 20%),0 14px 34px rgb(0 0 0 / 34%);backdrop-filter:blur(14px);pointer-events:auto; }.workspace-bar .brand { flex:none;padding:0 7px; }.workspace-bar .brand-copy b { font-size:12px; }.workspace-bar .session-status { margin:0; }.workspace-actions { display:flex;align-items:center;gap:2px; }.workspace-divider { width:1px;height:24px;background:var(--fdc-line); }.workspace-bar .icon-button { width:34px;height:34px; }.workspace-bar .icon-button.active { color:#9ec5ff;background:var(--fdc-signal-soft); }.workspace-bar .status-popover { top:44px;right:auto;left:58px; }
1121
+ .panel { top:72px;bottom:12px;max-height:none;overflow:clip; }.panel[hidden] { display:none; }.inspector-head { min-height:44px;display:flex;align-items:center;gap:7px;padding:0 8px 0 13px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-surface); }.inspector-head strong { font-size:12px;font-weight:550; }.inspector-head span { color:var(--fdc-muted);font-size:9px; }.inspector-head .icon-button { margin-left:auto; }.controls { min-height:0;flex:1; }.inspector-baseline { padding:0 12px 8px;border-bottom:1px solid var(--fdc-line); }.inspector-category { border-bottom:1px solid var(--fdc-line); }.inspector-category>.inspector-heading { position:sticky;top:0;z-index:2;height:44px;padding:0 8px 0 4px;background:rgb(28 28 31 / 97%); }.inspector-category>.inspector-heading .section-toggle { min-height:43px; }.inspector-category>.inspector-heading .section-toggle>svg { width:15px;height:15px;color:var(--fdc-muted);transform:none; }.inspector-category.collapsed>.category-body { display:none; }.inspector-category.collapsed>.inspector-heading .section-toggle>svg { transform:rotate(-90deg); }.inspector-category .property-section { margin-left:10px;border-left:1px solid var(--fdc-line); }.inspector-category .property-section .section-head { padding-left:6px; }.inspector-category[data-category="position"]>.category-body>.property-section>.section-head { display:none; }.category-body>.context-tools,.category-body>.native-panel,.category-body>.design-health { margin-left:10px; }
1122
+ .inspector-scroll { min-width:0;min-height:0;flex:1;overflow-x:hidden;overflow-y:auto;background:var(--fdc-surface); }
1123
+ .inspector-scroll::-webkit-scrollbar { width:6px; }
1124
+ .inspector-scroll::-webkit-scrollbar-track { background:transparent; }
1125
+ .inspector-scroll::-webkit-scrollbar-thumb { background:#4a4a50;border-radius:999px; }
1126
+ .inspector-scroll::-webkit-scrollbar-thumb:hover { background:#626269; }
1127
+ .inspector-scroll>.selection,.inspector-scroll>.scope,.inspector-scroll>.controls { width:100%;box-sizing:border-box; }
1128
+ .inspector-scroll>.controls { min-height:0;overflow:visible;flex:none; }
1129
+ /* Fluid inspector controls */
1130
+ .inspector-category .property-section { width:100%;margin-left:0;border-left:0; }
1131
+ .inspector-category .property-section .section-head { padding-left:10px; }
1132
+ .category-body>.context-tools,.category-body>.native-panel { width:100%;margin-left:0; }
1133
+ .category-body>.design-health { width:auto;margin:12px 14px 0; }
1134
+ .section-grid { width:100%;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:12px 14px 14px;box-sizing:border-box; }
1135
+ .section-grid.stacked { grid-template-columns:minmax(0,1fr); }
1136
+ .section-grid:not(.stacked)>:last-child:nth-child(odd) { grid-column:1/-1; }
1137
+ .property-control { min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:6px; }
1138
+ .property-control .property-label { min-height:13px;line-height:13px; }
1139
+ .property-control .control-field { width:100%;height:34px; }
1140
+ .property-control input,.property-control select { height:32px; }
1141
+ .section-grid.two { grid-template-columns:repeat(2,minmax(0,1fr));gap:8px; }
1142
+ .section-grid.two .compact-control { position:relative;display:block; }
1143
+ .compact-control .field-prefix,.compact-control .field-prefix.wide { width:44px;min-width:44px;box-sizing:border-box;padding-left:10px; }
1144
+ .section-grid.two .control-field { width:100%;height:34px; }
1145
+ .section-grid.two .compact-control input,.section-grid.two .compact-control select { height:32px; }
1146
+ .control-field>.control-reset { position:absolute;z-index:2;top:4px;right:4px;width:24px;height:24px; }
1147
+ .control-field>input { padding-right:32px; }
1148
+ .control-field:has(>select:not(.unit-select))>.control-reset { right:30px; }
1149
+ .control-field:has(>select:not(.unit-select))>select:not(.unit-select) { padding-right:56px!important; }
1150
+ .control-field:has(>.unit-select)>.control-reset { right:49px; }
1151
+ .control-field:has(>.unit)>.control-reset { right:25px; }
1152
+ /* Consistent inset chevrons for every select input */
1153
+ select { -webkit-appearance:none;appearance:none;padding-right:30px!important;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='%238f8f96' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 6.5 3 3 3-3'/%3E%3C/svg%3E")!important;background-repeat:no-repeat!important;background-position:right 9px center!important;background-size:16px 16px!important; }
1154
+ .control-field .unit-select { width:48px;padding-right:20px!important;padding-left:3px!important;background-position:right 3px center!important;background-size:14px 14px!important; }
1155
+ .layers-panel { top:72px;bottom:12px;max-height:none; }.layers-panel[hidden] { display:none; }
1156
+ .utility-panel { z-index:2147483646;max-height:none;min-width:280px;min-height:280px;box-shadow:0 2px 2px rgb(0 0 0 / 22%),0 18px 48px rgb(0 0 0 / 42%); }.utility-panel[hidden] { display:none; }.utility-handle { cursor:grab;user-select:none;touch-action:none; }.utility-handle:active { cursor:grabbing; }.utility-resizer { position:absolute;right:2px;bottom:2px;width:18px;height:18px;padding:0;border:0;background:transparent;cursor:nwse-resize; }.utility-resizer::after { content:"";position:absolute;right:3px;bottom:3px;width:7px;height:7px;border-right:1px solid var(--fdc-muted);border-bottom:1px solid var(--fdc-muted); }.health-panel,.library-panel { right:auto;max-height:none; }.health-list,.library-body { min-height:0;flex:1; }
1157
+ .change-tray { position:fixed;z-index:2147483646;right:var(--fdc-canvas-right,376px);bottom:12px;left:var(--fdc-canvas-left,276px);min-height:0;display:flex;flex-direction:column;align-items:stretch;padding:0;overflow:hidden;color:var(--fdc-ink);background:var(--fdc-surface);border:1px solid var(--fdc-line);border-radius:11px;box-shadow:0 2px 2px rgb(0 0 0 / 22%),0 18px 48px rgb(0 0 0 / 36%);pointer-events:auto; }.change-tray[hidden] { display:none; }.change-tray-summary { min-height:48px;display:grid;grid-template-columns:minmax(0,1fr) auto 32px 72px;align-items:center;gap:7px;padding:6px 7px 6px 11px; }.change-tray-summary .change-count { margin-right:2px; }.change-tray-summary button { height:32px;border:1px solid var(--fdc-line);border-radius:6px;color:var(--fdc-ink);background:var(--fdc-elevated);cursor:pointer; }.change-tray-summary .tray-compare { width:32px;display:grid;place-items:center;padding:0; }.change-tray-summary .tray-compare svg { width:13px;height:13px; }.change-tray-summary button:disabled { opacity:.35;cursor:not-allowed; }.change-tray.expanded { height:min(420px,45vh); }.change-tray.expanded .change-tray-summary { border-bottom:1px solid var(--fdc-line); }.change-tray .review-view:not([hidden]) { min-width:0;min-height:0;display:flex; }.change-tray .review-body { min-height:0;flex:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));align-content:start;overflow:auto; }.change-tray .review-group { min-width:0;border-right:1px solid var(--fdc-line); }.change-tray .review-actions { flex:none;grid-template-columns:100px minmax(180px,280px);justify-content:end; }.change-tray .review-head { flex:none; }.change-tray .review-head span { margin-left:auto; }
1158
+ /* Focused review list */
1159
+ .change-tray .review-body { display:block;overflow-x:hidden;overflow-y:auto; }
1160
+ .review-overview { position:sticky;top:0;z-index:3;display:flex;align-items:center;gap:12px;min-height:52px;padding:8px 12px;border-bottom:1px solid var(--fdc-line);background:rgb(20 20 22 / 97%);backdrop-filter:blur(10px); }
1161
+ .review-overview .review-summary { min-width:0;flex:1;padding:0;border:0;background:transparent; }
1162
+ .review-overview .review-summary strong { overflow:hidden;text-overflow:ellipsis;font-size:11px;white-space:nowrap; }
1163
+ .review-overview .review-summary span { overflow:hidden;text-overflow:ellipsis;margin-top:2px;font-size:9px;white-space:nowrap; }
1164
+ .review-overview .review-toolbar { position:static;z-index:auto;flex:none;padding:0;border:0;background:transparent;backdrop-filter:none; }
1165
+ .review-overview .review-toolbar button { height:28px;padding:0 8px;border-color:transparent;background:transparent;color:var(--fdc-muted);font-size:9px; }
1166
+ .review-overview .review-toolbar button:hover { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }
1167
+ .change-tray .review-group { border-right:0;border-bottom:1px solid var(--fdc-line); }
1168
+ .change-tray .review-group-title { position:sticky;top:52px;z-index:2;min-height:38px;padding:0 12px;background:rgb(28 28 31 / 98%); }
1169
+ .review-group-title .included-count { font-size:9px; }
1170
+ .review-card { min-height:50px;grid-template-columns:18px minmax(0,1fr);align-items:start;gap:9px;padding:8px 12px; }
1171
+ .review-card input[type="checkbox"] { margin-top:7px; }
1172
+ .review-card-line { min-height:32px;display:grid;grid-template-columns:minmax(120px,1fr) auto minmax(220px,320px) 30px;align-items:center;gap:8px; }
1173
+ .review-card-line>strong { font-size:10px; }
1174
+ .review-values { min-width:0;display:grid;grid-template-columns:minmax(72px,1fr) 12px minmax(90px,1fr);align-items:center;gap:5px;margin:0; }
1175
+ .review-before { min-width:0;overflow:hidden;text-overflow:ellipsis;padding:0 8px;color:var(--fdc-muted);background:transparent;font-size:10px;text-align:right;white-space:nowrap; }
1176
+ .review-after { height:30px;font-size:10px; }
1177
+ .review-more { position:relative;justify-self:end; }
1178
+ .review-more>summary { width:28px;height:28px;display:grid;place-items:center;border:1px solid transparent;border-radius:5px;color:var(--fdc-muted);font:600 11px/1 var(--fdc-font);letter-spacing:1px;list-style:none;cursor:pointer; }
1179
+ .review-more>summary::-webkit-details-marker { display:none; }
1180
+ .review-more>summary:hover,.review-more[open]>summary { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }
1181
+ .review-more .review-card-tools { position:absolute;z-index:5;right:0;top:32px;width:260px;display:flex;flex-direction:column;gap:2px;padding:4px;border:1px solid var(--fdc-line);border-radius:7px;background:var(--fdc-elevated);box-shadow:0 10px 24px rgb(0 0 0 / 34%); }
1182
+ .review-more .review-card-tools button { width:100%;height:27px;padding:0 7px;border:0;text-align:left;background:transparent; }
1183
+ .review-more .review-card-tools button:hover { background:var(--fdc-subtle); }
1184
+ .review-details { margin-top:3px;padding-top:3px;border-top:1px solid var(--fdc-line); }
1185
+ .review-details summary { min-height:27px;display:flex;align-items:center;padding:0 7px;color:var(--fdc-muted);font-size:8px;cursor:pointer; }
1186
+ .review-details[open] { padding-bottom:6px; }
1187
+ .review-details .review-source,.review-details .impact-list { padding-right:7px;padding-left:7px; }
1188
+ .review-visual { display:none; }
1189
+ @media (max-width:980px){.review-card-line{grid-template-columns:minmax(100px,1fr) auto minmax(190px,260px) 30px}.review-overview .review-summary span{display:none}}
1190
+ @media (max-width:760px){.review-card-line{grid-template-columns:minmax(0,1fr) auto 30px}.review-values{grid-column:1/-1;width:100%}.review-overview{align-items:flex-start}.review-overview .review-toolbar{margin-left:auto}.review-overview .review-toolbar button{padding:0 6px}}
1191
+ .tool-shelf { bottom:calc(18px + var(--fdc-tray-lift,0px)); }.tool-select[hidden],.tool-divider[hidden] { display:none; }.tool-select.interact.active { color:white;background:var(--fdc-signal); }.mode-copy { min-width:88px; }.canvas-actions-divider { margin-left:2px; }.multi-actions-divider { margin-left:2px; }
1192
+ .compare-bar { bottom:calc(78px + var(--fdc-tray-lift,0px)); }
1193
+ @keyframes fdc-selection-title { from { opacity:.45;transform:translateY(2px) } to { opacity:1;transform:none } }
1194
+ @media (max-width:680px){.workspace-bar{right:8px;left:8px;transform:none;overflow-x:auto}.workspace-bar .brand{padding-right:3px}.workspace-bar .brand-copy{display:none}.workspace-bar .status-popover{position:fixed;top:66px;right:8px;left:8px;width:auto}.panel{top:auto;right:8px;bottom:74px;left:8px;width:auto;max-height:56vh}.layers-panel{top:68px;right:8px;bottom:auto;left:8px;width:auto;max-height:42vh}.utility-panel{top:68px!important;right:8px!important;bottom:74px!important;left:8px!important;width:auto!important;height:auto!important;max-height:none}.utility-resizer{display:none}.scope{display:grid;grid-template-columns:1fr 1fr}.controls{min-height:170px}.change-tray{right:8px;bottom:8px;left:8px}.change-tray.expanded{height:48vh}.change-tray .review-body{grid-template-columns:1fr}.tool-shelf{right:8px;bottom:calc(8px + var(--fdc-tray-lift,0px));left:8px;transform:none;max-width:none}.mode-copy{min-width:0}.mode-copy span{display:none}.tool-select::after,.tab::after{display:none}.onboarding-card{right:12px;bottom:68px;left:12px;width:auto;transform:none}.workbench-controls select,.workbench-controls button:not(.icon-button){max-width:92px}.workbench-matrix{grid-template-columns:76px repeat(var(--matrix-columns),minmax(90px,1fr))}}
1198
1195
  @media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important}}
1199
1196
  `;
1200
1197
  function numberFrom(value) {
@@ -1513,12 +1510,12 @@ function renderPropertyControl(control, index, prefix) {
1513
1510
  "%"
1514
1511
  ].filter((unit) => unit !== control.unit).map((unit) => `<option>${unit}</option>`).join("")}</select>` : control.unit ? `<span class="unit">${control.unit}</span>` : "";
1515
1512
  const field = `${renderControlInput(control, index)}${unitControl}`;
1516
- const reset = `<button type="button" class="control-reset" data-reset-control="${index}" title="Reset ${escapeHtml(control.label)}" aria-label="Reset ${escapeHtml(control.label)}"><i data-lucide="rotate-ccw"></i></button>`;
1513
+ const reset = `<button type="button" class="control-reset" data-reset-control="${index}" title="Reset ${escapeHtml(control.label)}" aria-label="Reset ${escapeHtml(control.label)}"><i data-foundry-icon="rotate-ccw"></i></button>`;
1517
1514
  const scrubAttributes = control.kind === "number" ? ` data-scrub-for="${index}" title="Drag left or right to adjust ${escapeHtml(control.label)}. Hold Shift for larger steps or Option for finer steps."` : "";
1518
1515
  if (prefix) {
1519
- return `<label class="compact-control"><span class="sr-only">${escapeHtml(control.label)}</span><span class="control-field"><span class="field-prefix ${prefix.length > 2 ? "wide" : ""}"${scrubAttributes}>${escapeHtml(prefix)}</span>${field}</span>${reset}</label>`;
1516
+ return `<label class="compact-control"><span class="sr-only">${escapeHtml(control.label)}</span><span class="control-field"><span class="field-prefix ${prefix.length > 2 ? "wide" : ""}"${scrubAttributes}>${escapeHtml(prefix)}</span>${field}${reset}</span></label>`;
1520
1517
  }
1521
- return `<label class="property-control"><span class="property-label"${scrubAttributes}>${escapeHtml(control.label)}</span><span class="control-field">${field}</span>${reset}</label>`;
1518
+ return `<label class="property-control"><span class="property-label"${scrubAttributes}>${escapeHtml(control.label)}</span><span class="control-field">${field}${reset}</span></label>`;
1522
1519
  }
1523
1520
  function installFoundryInspector(options = {}) {
1524
1521
  const query = new URLSearchParams(location.search);
@@ -1540,7 +1537,46 @@ function installFoundryInspector(options = {}) {
1540
1537
  const host = document.createElement("div");
1541
1538
  host.dataset.foundryOverlay = "true";
1542
1539
  const shadow = host.attachShadow({ mode: "open" });
1543
- shadow.innerHTML = `<style>${PANEL_CSS}</style><div class="outline" hidden><span class="cross"></span><span class="measure"></span></div><div class="hover-outline" hidden></div><aside class="layers-panel" aria-label="Foundry layers" hidden><div class="layers-head"><i data-lucide="layers-3"></i><strong>Layers</strong><span data-layer-count></span><button class="icon-button close-layers" aria-label="Close layers"><i data-lucide="x"></i></button></div><div class="layers-search"><input type="search" aria-label="Search layers" placeholder="Search layers" /></div><div class="layer-tree"></div></aside><aside class="health-panel" aria-label="Design health" hidden><div class="health-head"><i data-lucide="activity"></i><strong>Design health</strong><button class="icon-button close-health" aria-label="Close design health"><i data-lucide="x"></i></button></div><div class="health-summary"></div><div class="health-filters" role="group" aria-label="Filter design health issues"></div><div class="health-list"></div><div class="health-footer"><button class="health-show-ignored" hidden></button><button class="health-rescan">Scan again</button></div></aside><aside class="panel" aria-label="Foundry design inspector"><div class="top"><div class="top-identity"><div class="brand"><span class="brand-mark"><i></i><i></i><i></i></span><span class="brand-copy"><b>Foundry</b><span>Inspector</span></span></div><span class="session-status"><i></i><span>Live</span></span><button class="icon-button close" title="Close inspector" aria-label="Close inspector"><i data-lucide="x"></i></button></div><div class="top-actions" role="toolbar" aria-label="Inspector actions"><button class="icon-button toggle-layers" title="Open layers" aria-label="Open layers"><i data-lucide="layers-3"></i></button></div></div><div class="selection"><div class="selection-heading"><small class="selection-kind">No layer</small><span class="selection-state">Ready</span></div><strong>Nothing selected</strong><code>Click any element to inspect it</code><div class="selection-stats" hidden><span data-selection-size></span><span data-selection-confidence></span></div><div class="selection-path" hidden><button data-select-parent aria-label="Select parent layer"><i data-lucide="chevron-right"></i><span>Parent</span></button><span class="path-name"></span><button data-select-child aria-label="Select first child layer"><span>Child</span><i data-lucide="chevron-down"></i></button></div></div><div class="scope"><label>Scope<select data-scope><option value="instance">Instance</option><option value="component">Component</option></select></label><label>Breakpoint<select data-breakpoint><option>current</option><option>mobile</option><option>tablet</option><option>desktop</option></select></label><label>Theme<select data-theme><option>current</option><option>light</option><option>dark</option></select></label></div><div class="controls"><div class="empty">Select an element to inspect its measured design controls.</div></div><div class="review-view" hidden><div class="review-head"><button class="review-back" aria-label="Back to inspector"><i data-lucide="arrow-left"></i></button><strong>Review and apply</strong><span class="review-count"></span></div><div class="review-body"></div><div class="review-actions"><button class="review-cancel">Back</button><button class="apply">Apply with agent</button></div></div><div class="footer"><button class="verify">Verify</button><button class="review"><span>Review changes</span><span class="change-count" hidden>0</span></button></div></aside><div class="tool-shelf" role="toolbar" aria-label="Design tools"><button class="tool-select inspect" data-tooltip="Select mode" title="Select mode: click any element" aria-label="Selection mode" aria-pressed="true"><i data-lucide="mouse-pointer-2"></i></button><span class="tool-divider"></span><div class="tabs"></div></div><div class="toast"></div>`;
1540
+ shadow.innerHTML = `<style>${PANEL_CSS}</style>
1541
+ <div class="outline" hidden><span class="cross"></span><span class="measure"></span></div>
1542
+ <div class="hover-outline" hidden></div>
1543
+ <header class="workspace-bar" aria-label="Foundry workspace">
1544
+ <div class="brand"><span class="brand-copy"><b>Foundry</b></span></div>
1545
+ <span class="session-status"><i></i><span>Live</span></span>
1546
+ <span class="workspace-divider"></span>
1547
+ <nav class="workspace-actions" aria-label="Workspace destinations">
1548
+ <button class="icon-button toggle-layers" title="Toggle layers" aria-label="Toggle layers" aria-pressed="true"><i data-foundry-icon="layers-3"></i></button>
1549
+ <button class="icon-button toggle-inspector" title="Toggle inspector" aria-label="Toggle inspector" aria-pressed="true"><i data-foundry-icon="panels-top-left"></i></button>
1550
+ <button class="icon-button open-health" title="Design health" aria-label="Open design health" aria-pressed="false"><i data-foundry-icon="activity"></i></button>
1551
+ <button class="icon-button open-workbench" title="State workbench" aria-label="Open state workbench" aria-pressed="false"><i data-foundry-icon="play"></i></button>
1552
+ <button class="icon-button open-library" title="Design memory" aria-label="Open design memory" aria-pressed="false"><i data-foundry-icon="bookmark"></i></button>
1553
+ <button class="icon-button open-commands" title="Commands" aria-label="Open commands"><i data-foundry-icon="command"></i></button>
1554
+ </nav>
1555
+ <span class="workspace-divider"></span>
1556
+ <button class="icon-button close" title="Exit Foundry" aria-label="Exit Foundry"><i data-foundry-icon="x"></i></button>
1557
+ </header>
1558
+ <aside class="layers-panel" aria-label="Foundry layers" hidden>
1559
+ <div class="layers-head"><i data-foundry-icon="layers-3"></i><strong>Layers</strong><span data-layer-count></span><button class="icon-button close-layers" aria-label="Close layers"><i data-foundry-icon="x"></i></button></div>
1560
+ <div class="layers-search"><input type="search" aria-label="Search layers" placeholder="Search layers" /></div><div class="layer-tree"></div>
1561
+ </aside>
1562
+ <aside class="health-panel utility-panel" data-utility="health" aria-label="Design health" hidden>
1563
+ <div class="health-head utility-handle"><i data-foundry-icon="activity"></i><strong>Design health</strong><button class="icon-button close-health" aria-label="Close design health"><i data-foundry-icon="x"></i></button></div>
1564
+ <div class="health-summary"></div><div class="health-filters" role="group" aria-label="Filter design health issues"></div><div class="health-list"></div><div class="health-footer"><button class="health-show-ignored" hidden></button><button class="health-rescan">Scan again</button></div><button class="utility-resizer" aria-label="Resize design health"></button>
1565
+ </aside>
1566
+ <aside class="panel" aria-label="Foundry design inspector">
1567
+ <div class="inspector-head"><strong>Inspector</strong><span>Selection properties</span><button class="icon-button toggle-inspector inspector-collapse" aria-label="Close inspector"><i data-foundry-icon="x"></i></button></div>
1568
+ <div class="inspector-scroll">
1569
+ <div class="selection"><div class="selection-heading"><small class="selection-kind">No layer</small><span class="selection-state">Ready</span></div><strong>Nothing selected</strong><code>Click any element to inspect it</code><div class="selection-stats" hidden><span data-selection-size></span><span data-selection-confidence></span></div><div class="selection-path" hidden><button data-select-parent aria-label="Select parent layer"><i data-foundry-icon="chevron-right"></i><span>Parent</span></button><span class="path-name"></span><button data-select-child aria-label="Select first child layer"><span>Child</span><i data-foundry-icon="chevron-down"></i></button></div></div>
1570
+ <div class="scope"><label>Scope<select data-scope><option value="instance">Instance</option><option value="component">Component</option></select></label><label>Breakpoint<select data-breakpoint><option>current</option><option>mobile</option><option>tablet</option><option>desktop</option></select></label><label>Theme<select data-theme><option>current</option><option>light</option><option>dark</option></select></label></div>
1571
+ <div class="controls"><div class="empty">Select an element to inspect its measured design controls.</div></div>
1572
+ </div>
1573
+ </aside>
1574
+ <section class="change-dock change-tray" aria-label="Foundry changes" hidden>
1575
+ <div class="change-tray-summary"><div class="change-dock-copy"><strong data-dock-count>No changes</strong><span data-dock-last>Edits will appear here</span></div><span class="change-count" hidden>0</span><button class="tray-compare" title="Compare changes" aria-label="Compare changes" disabled><i data-foundry-icon="contrast"></i></button><button class="dock-review">Review</button></div>
1576
+ <div class="review-view" hidden><div class="review-head"><button class="review-back" aria-label="Collapse change tray"><i data-foundry-icon="chevron-down"></i></button><strong>Review and apply</strong><span class="review-count"></span></div><div class="review-body"></div><div class="review-actions"><button class="review-cancel">Collapse</button><button class="apply">Apply with agent</button></div></div>
1577
+ </section>
1578
+ <div class="tool-shelf" role="toolbar" aria-label="Canvas tools"><button class="tool-select inspect" data-tooltip="Select" title="Select: click any element" aria-label="Select mode" aria-pressed="true"><i data-foundry-icon="mouse-pointer-2"></i></button><button class="tool-select interact" data-tooltip="Interact" title="Interact with the app" aria-label="Interact mode" aria-pressed="false"><i data-foundry-icon="interact"></i></button></div>
1579
+ <div class="toast"></div>`;
1544
1580
  document.body.append(host);
1545
1581
  shadow.querySelector(".layers-search").insertAdjacentHTML(
1546
1582
  "beforebegin",
@@ -1555,10 +1591,6 @@ function installFoundryInspector(options = {}) {
1555
1591
  "afterend",
1556
1592
  '<div class="status-popover" hidden><strong data-status-title>Session connected</strong><span data-status-detail>Changes are stored locally.</span><code data-status-project></code><code data-status-revision></code><button data-status-retry>Check connection</button></div>'
1557
1593
  );
1558
- shadow.querySelector(".footer").insertAdjacentHTML(
1559
- "beforebegin",
1560
- '<div class="change-dock" hidden><div class="change-dock-copy"><strong data-dock-count>No changes</strong><span data-dock-last>Edits will appear here</span></div><button class="dock-undo" title="Undo last preview" aria-label="Undo last preview"><i data-lucide="undo-2"></i></button><button class="dock-review">Review</button></div>'
1561
- );
1562
1594
  shadow.querySelector(".panel").insertAdjacentHTML(
1563
1595
  "beforeend",
1564
1596
  '<button class="panel-resizer" aria-label="Resize inspector panel" title="Drag to resize inspector"></button>'
@@ -1567,13 +1599,13 @@ function installFoundryInspector(options = {}) {
1567
1599
  onboarding.className = "onboarding-card";
1568
1600
  onboarding.hidden = true;
1569
1601
  onboarding.setAttribute("aria-label", "Getting started with Foundry");
1570
- onboarding.innerHTML = '<div class="onboarding-card-head"><i data-lucide="sparkles"></i><strong>Design directly on the real interface</strong></div><p>Click to inspect, refine with project-native values, then review once. Passed work becomes reusable local design memory.</p><div class="onboarding-steps"><span>1 \xB7 Select in Layers</span><span>2 \xB7 Refine visually</span><span>3 \xB7 Apply and verify</span></div><div class="onboarding-actions"><button class="onboarding-shortcuts">Explore commands</button><button class="onboarding-start">Start designing</button></div>';
1602
+ onboarding.innerHTML = '<div class="onboarding-card-head"><span><i data-foundry-icon="sparkles"></i></span><strong>Start with the interface</strong></div><p>Foundry stays in Select mode while you work. Click anything, refine measured values, then apply one reviewed batch.</p><div class="onboarding-steps"><div class="onboarding-step"><b>01</b><span><strong>Select</strong><small>Click the page or choose a layer.</small></span></div><div class="onboarding-step"><b>02</b><span><strong>Refine</strong><small>Adjust real layout, type, color, and motion.</small></span></div><div class="onboarding-step"><b>03</b><span><strong>Apply</strong><small>Review once, update source, and verify.</small></span></div></div><div class="onboarding-actions"><button class="onboarding-shortcuts">View shortcuts</button><button class="onboarding-start">Select an element</button></div>';
1571
1603
  shadow.append(onboarding);
1572
1604
  const compareBar = document.createElement("div");
1573
1605
  compareBar.className = "compare-bar";
1574
1606
  compareBar.hidden = true;
1575
1607
  compareBar.setAttribute("aria-label", "Preview comparison");
1576
- compareBar.innerHTML = `<strong>Compare</strong><button data-compare="before"><i data-lucide="eye-off"></i>Before</button><input data-compare-scrub type="range" min="0" max="100" value="100" aria-label="Scrub between before and after"/><button data-compare="after" class="active"><i data-lucide="eye"></i>After</button><button data-compare="split"><i data-lucide="columns-3"></i>Side by side</button><button data-compare="isolate"><i data-lucide="contrast"></i>Isolate</button><button data-compare="reset"><i data-lucide="rotate-ccw"></i>Reset element</button><button data-compare="close" aria-label="Close comparison"><i data-lucide="x"></i></button>`;
1608
+ compareBar.innerHTML = `<strong>Compare</strong><button data-compare="before"><i data-foundry-icon="eye-off"></i>Before</button><input data-compare-scrub type="range" min="0" max="100" value="100" aria-label="Scrub between before and after"/><button data-compare="after" class="active"><i data-foundry-icon="eye"></i>After</button><button data-compare="split"><i data-foundry-icon="columns-3"></i>Side by side</button><button data-compare="isolate"><i data-foundry-icon="contrast"></i>Isolate</button><button data-compare="reset"><i data-foundry-icon="rotate-ccw"></i>Reset element</button><button data-compare="close" aria-label="Close comparison"><i data-foundry-icon="x"></i></button>`;
1577
1609
  shadow.append(compareBar);
1578
1610
  const commandPalette = document.createElement("section");
1579
1611
  commandPalette.className = "command-palette";
@@ -1582,10 +1614,11 @@ function installFoundryInspector(options = {}) {
1582
1614
  commandPalette.innerHTML = `<input type="search" aria-label="Search commands" placeholder="Type a command"/><div class="command-list"></div>`;
1583
1615
  shadow.append(commandPalette);
1584
1616
  const libraryPanel = document.createElement("aside");
1585
- libraryPanel.className = "library-panel";
1617
+ libraryPanel.className = "library-panel utility-panel";
1618
+ libraryPanel.dataset.utility = "memory";
1586
1619
  libraryPanel.hidden = true;
1587
1620
  libraryPanel.setAttribute("aria-label", "Foundry design memory");
1588
- libraryPanel.innerHTML = `<div class="library-head"><i data-lucide="bookmark"></i><strong>Design memory</strong><span>Local to this project</span><button class="icon-button close-library" aria-label="Close design memory"><i data-lucide="x"></i></button></div><div class="library-actions"><button data-save-recipe disabled><i data-lucide="save"></i>Save treatment</button><button data-capture-baseline disabled><i data-lucide="check"></i>Save baseline</button></div><div class="library-body"></div>`;
1621
+ libraryPanel.innerHTML = `<div class="library-head utility-handle"><i data-foundry-icon="bookmark"></i><strong>Design memory</strong><span>Local to this project</span><button class="icon-button close-library" aria-label="Close design memory"><i data-foundry-icon="x"></i></button></div><div class="library-actions"><button data-save-recipe disabled><i data-foundry-icon="save"></i>Save treatment</button><button data-capture-baseline disabled><i data-foundry-icon="check"></i>Save baseline</button></div><div class="library-body"></div><button class="utility-resizer" aria-label="Resize design memory"></button>`;
1589
1622
  shadow.append(libraryPanel);
1590
1623
  shadow.querySelector(".outline").insertAdjacentHTML(
1591
1624
  "beforeend",
@@ -1602,23 +1635,23 @@ function installFoundryInspector(options = {}) {
1602
1635
  canvasVariant.hidden = true;
1603
1636
  canvasVariant.setAttribute("aria-label", "Component variant");
1604
1637
  shadow.append(canvasVariant);
1605
- shadow.querySelector(".top-actions").insertAdjacentHTML(
1606
- "afterbegin",
1607
- '<button class="icon-button open-health" title="Scan design health" aria-label="Scan design health"><i data-lucide="activity"></i></button><button class="icon-button open-workbench" title="Open state workbench" aria-label="Open state workbench"><i data-lucide="panels-top-left"></i></button><button class="icon-button open-library" title="Open design memory" aria-label="Open design memory"><i data-lucide="bookmark"></i></button><button class="icon-button open-compare" title="Compare changes" aria-label="Compare changes"><i data-lucide="contrast"></i></button><button class="icon-button open-commands" title="Open commands" aria-label="Open commands"><i data-lucide="command"></i></button>'
1608
- );
1609
1638
  shadow.querySelector(".scope").insertAdjacentHTML(
1610
1639
  "beforeend",
1611
1640
  '<label>State<select data-state><option value="current">Current</option></select></label>'
1612
1641
  );
1642
+ shadow.querySelector(".tool-shelf").querySelector(".interact").insertAdjacentHTML(
1643
+ "afterend",
1644
+ '<span class="mode-copy" aria-live="polite"><strong>Select mode</strong><span>Click any element</span></span>'
1645
+ );
1613
1646
  shadow.querySelector(".tool-shelf").insertAdjacentHTML(
1614
1647
  "beforeend",
1615
- '<span class="tool-divider canvas-actions-divider"></span><button class="tool-select undo" data-tooltip="Undo" aria-label="Undo preview" disabled><i data-lucide="undo-2"></i></button><button class="tool-select redo" data-tooltip="Redo" aria-label="Redo preview" disabled><i data-lucide="redo-2"></i></button><button class="tool-select align" data-tooltip="Align" aria-label="Align selected elements" disabled><i data-lucide="align-horizontal-space-around"></i></button><button class="tool-select distribute" data-tooltip="Distribute" aria-label="Distribute selected elements" disabled><i data-lucide="columns-3"></i></button>'
1648
+ '<span class="tool-divider canvas-actions-divider"></span><button class="tool-select undo" data-tooltip="Undo" aria-label="Undo preview" disabled><i data-foundry-icon="undo-2"></i></button><button class="tool-select redo" data-tooltip="Redo" aria-label="Redo preview" disabled><i data-foundry-icon="redo-2"></i></button><span class="tool-divider multi-actions-divider" hidden></span><button class="tool-select align" data-tooltip="Align" aria-label="Align selected elements" hidden><i data-foundry-icon="align-horizontal-space-around"></i></button><button class="tool-select distribute" data-tooltip="Distribute" aria-label="Distribute selected elements" hidden><i data-foundry-icon="columns-3"></i></button>'
1616
1649
  );
1617
1650
  const workbench = document.createElement("section");
1618
1651
  workbench.className = "workbench";
1619
1652
  workbench.hidden = true;
1620
1653
  workbench.setAttribute("aria-label", "Foundry state workbench");
1621
- workbench.innerHTML = `<header class="workbench-head"><strong>State workbench</strong><span class="workbench-context">Live application frame</span><div class="workbench-controls"><button data-workbench-matrix>Matrix</button><select data-workbench-viewport aria-label="Viewport"></select><select data-workbench-theme aria-label="Theme"><option value="current">Current theme</option></select><button data-workbench-state="hover">Hover</button><button data-workbench-state="focus">Focus</button><button data-workbench-motion>Reduce motion</button><button class="icon-button close-workbench" aria-label="Close state workbench"><i data-lucide="x"></i></button></div></header><div class="workbench-stage"><div class="workbench-matrix" hidden></div><div class="frame-shell"><span class="frame-label"></span><iframe title="Foundry live state preview"></iframe></div><div class="workbench-warning" hidden></div></div>`;
1654
+ workbench.innerHTML = `<header class="workbench-head"><strong>State workbench</strong><span class="workbench-context">Live application frame</span><div class="workbench-controls"><button data-workbench-matrix>Matrix</button><select data-workbench-viewport aria-label="Viewport"></select><select data-workbench-theme aria-label="Theme"><option value="current">Current theme</option></select><button data-workbench-state="hover">Hover</button><button data-workbench-state="focus">Focus</button><button data-workbench-motion>Reduce motion</button><button class="icon-button close-workbench" aria-label="Close state workbench"><i data-foundry-icon="x"></i></button></div></header><div class="workbench-stage"><div class="workbench-matrix" hidden></div><div class="frame-shell"><span class="frame-label"></span><iframe title="Foundry live state preview"></iframe></div><div class="workbench-warning" hidden></div></div>`;
1622
1655
  workbench.querySelector("[data-workbench-motion]").insertAdjacentHTML(
1623
1656
  "beforebegin",
1624
1657
  '<button data-workbench-state="active">Active</button><button data-workbench-state="disabled">Disabled</button>'
@@ -1628,30 +1661,33 @@ function installFoundryInspector(options = {}) {
1628
1661
  comparisonStage.className = "comparison-stage";
1629
1662
  comparisonStage.hidden = true;
1630
1663
  comparisonStage.setAttribute("aria-label", "Side by side comparison");
1631
- comparisonStage.innerHTML = `<header><strong>Before and after</strong><span>Source baseline compared with the current Foundry preview</span><button data-close-comparison-stage aria-label="Close side by side comparison"><i data-lucide="x"></i></button></header><div class="comparison-frames"><div class="comparison-frame"><span>Before</span><iframe data-comparison-before title="Before source preview"></iframe></div><div class="comparison-frame"><span>After</span><iframe data-comparison-after title="After Foundry preview"></iframe></div></div>`;
1664
+ comparisonStage.innerHTML = `<header><strong>Before and after</strong><span>Source baseline compared with the current Foundry preview</span><button data-close-comparison-stage aria-label="Close side by side comparison"><i data-foundry-icon="x"></i></button></header><div class="comparison-frames"><div class="comparison-frame"><span>Before</span><iframe data-comparison-before title="Before source preview"></iframe></div><div class="comparison-frame"><span>After</span><iframe data-comparison-after title="After Foundry preview"></iframe></div></div>`;
1632
1665
  shadow.append(comparisonStage);
1633
1666
  function renderIcons(root) {
1634
- createIcons({
1635
- root,
1636
- icons: FOUNDRY_ICONS,
1637
- attrs: {
1638
- "aria-hidden": "true",
1639
- focusable: "false"
1640
- }
1641
- });
1667
+ renderKeylineIcons(root);
1642
1668
  }
1643
1669
  renderIcons(shadow);
1644
1670
  const outline = shadow.querySelector(".outline");
1645
1671
  const panel = shadow.querySelector(".panel");
1646
- const tabs = shadow.querySelector(".tabs");
1647
1672
  const controlsRoot = shadow.querySelector(".controls");
1648
1673
  const inspectButton = shadow.querySelector(".inspect");
1674
+ const interactButton = shadow.querySelector(".interact");
1675
+ const workspaceBar = shadow.querySelector(".workspace-bar");
1649
1676
  const sessionStatus = shadow.querySelector(".session-status");
1650
1677
  const statusPopover = shadow.querySelector(".status-popover");
1651
1678
  const changeDock = shadow.querySelector(".change-dock");
1679
+ const trayCompare = shadow.querySelector(".tray-compare");
1652
1680
  const selectionKind = shadow.querySelector(".selection-kind");
1653
1681
  const selectionTitle = shadow.querySelector(".selection strong");
1654
1682
  const selectionCode = shadow.querySelector(".selection code");
1683
+ selectionCode.insertAdjacentHTML(
1684
+ "afterend",
1685
+ '<span class="selection-hint">Select mode stays on \xB7 click anywhere to begin</span>'
1686
+ );
1687
+ const selectionHint = shadow.querySelector(".selection-hint");
1688
+ const selectionRoot = shadow.querySelector(".selection");
1689
+ const modeCopyTitle = shadow.querySelector(".mode-copy strong");
1690
+ const modeCopyDetail = shadow.querySelector(".mode-copy span");
1655
1691
  const selectionState = shadow.querySelector(".selection-state");
1656
1692
  const selectionStats = shadow.querySelector(".selection-stats");
1657
1693
  const selectionSize = shadow.querySelector("[data-selection-size]");
@@ -1683,6 +1719,7 @@ function installFoundryInspector(options = {}) {
1683
1719
  const reviewCount = shadow.querySelector(".review-count");
1684
1720
  const applyButton = shadow.querySelector(".review-actions .apply");
1685
1721
  const reviewCancel = shadow.querySelector(".review-cancel");
1722
+ let workspaceState = { ...DEFAULT_WORKSPACE_STATE };
1686
1723
  let selected = null;
1687
1724
  let selectedElements = [];
1688
1725
  let layerEntries = [];
@@ -1691,7 +1728,6 @@ function installFoundryInspector(options = {}) {
1691
1728
  let layerView = sessionStorage.getItem(layerViewPreferenceKey) === "components" ? "components" : "layers";
1692
1729
  let clickCycle = { x: -1, y: -1, at: 0, index: -1, signature: "" };
1693
1730
  let inspecting = options.startInspecting ?? true;
1694
- let activeCategory = "layout";
1695
1731
  let selectedControls = [];
1696
1732
  let resizeObserver;
1697
1733
  let activeReviewPayload = null;
@@ -1705,6 +1741,7 @@ function installFoundryInspector(options = {}) {
1705
1741
  })();
1706
1742
  let reviewShowRejected = false;
1707
1743
  let reviewPoll;
1744
+ let lastReviewTrigger = null;
1708
1745
  let designGraph = null;
1709
1746
  const previewHistory = [];
1710
1747
  let historyCursor = 0;
@@ -1716,11 +1753,11 @@ function installFoundryInspector(options = {}) {
1716
1753
  let hydratedOnce = false;
1717
1754
  const collapsedSections = /* @__PURE__ */ new Set();
1718
1755
  try {
1719
- for (const key of JSON.parse(localStorage.getItem("__foundry_collapsed_sections") ?? "[]")) {
1756
+ for (const key of JSON.parse(sessionStorage.getItem("__foundry_collapsed_sections") ?? "[]")) {
1720
1757
  if (typeof key === "string") collapsedSections.add(key);
1721
1758
  }
1722
1759
  } catch {
1723
- localStorage.removeItem("__foundry_collapsed_sections");
1760
+ sessionStorage.removeItem("__foundry_collapsed_sections");
1724
1761
  }
1725
1762
  let comparisonActive = false;
1726
1763
  let isolatedComparisonElement = null;
@@ -1742,6 +1779,166 @@ function installFoundryInspector(options = {}) {
1742
1779
  let projectRevision = "";
1743
1780
  let designMemory = emptyDesignMemory();
1744
1781
  let matrixMode = false;
1782
+ let lastUtilityTrigger = null;
1783
+ const utilityRects = /* @__PURE__ */ new Map();
1784
+ function utilityStorageKey(utility) {
1785
+ return `__foundry_utility_rect:${utility}:${projectRoot}`;
1786
+ }
1787
+ function canvasBounds() {
1788
+ const layersRect = workspaceState.layersOpen ? layersPanel.getBoundingClientRect() : null;
1789
+ const inspectorRect = workspaceState.inspectorOpen ? panel.getBoundingClientRect() : null;
1790
+ const trayRect = !changeDock.hidden ? changeDock.getBoundingClientRect() : null;
1791
+ return {
1792
+ left: Math.round((layersRect?.right ?? 0) + 12),
1793
+ top: Math.round(workspaceBar.getBoundingClientRect().bottom + 12),
1794
+ right: Math.round((inspectorRect?.left ?? window.innerWidth) - 12),
1795
+ bottom: Math.round((trayRect?.top ?? window.innerHeight) - 12)
1796
+ };
1797
+ }
1798
+ function readUtilityRect(utility) {
1799
+ try {
1800
+ const value = JSON.parse(localStorage.getItem(utilityStorageKey(utility)) ?? "null");
1801
+ if (value && ["x", "y", "width", "height"].every((key) => Number.isFinite(value[key]))) {
1802
+ return value;
1803
+ }
1804
+ } catch {
1805
+ localStorage.removeItem(utilityStorageKey(utility));
1806
+ }
1807
+ return void 0;
1808
+ }
1809
+ function applyUtilityRect(utility) {
1810
+ const utilityPanel = utility === "health" ? healthPanel : libraryPanel;
1811
+ if (window.matchMedia("(max-width: 680px)").matches) {
1812
+ utilityPanel.style.removeProperty("left");
1813
+ utilityPanel.style.removeProperty("top");
1814
+ utilityPanel.style.removeProperty("width");
1815
+ utilityPanel.style.removeProperty("height");
1816
+ return;
1817
+ }
1818
+ const bounds = canvasBounds();
1819
+ const fallback = {
1820
+ x: bounds.left + 12,
1821
+ y: bounds.top + 12,
1822
+ width: 320,
1823
+ height: Math.min(560, Math.max(320, bounds.bottom - bounds.top - 24))
1824
+ };
1825
+ const rect = clampUtilityRect(
1826
+ utilityRects.get(utility) ?? readUtilityRect(utility) ?? fallback,
1827
+ bounds
1828
+ );
1829
+ utilityRects.set(utility, rect);
1830
+ Object.assign(utilityPanel.style, {
1831
+ left: `${rect.x}px`,
1832
+ top: `${rect.y}px`,
1833
+ width: `${rect.width}px`,
1834
+ height: `${rect.height}px`
1835
+ });
1836
+ }
1837
+ function positionWorkspaceSurfaces() {
1838
+ const bounds = canvasBounds();
1839
+ host.style.setProperty("--fdc-canvas-left", `${Math.max(12, bounds.left)}px`);
1840
+ host.style.setProperty(
1841
+ "--fdc-canvas-right",
1842
+ `${Math.max(12, window.innerWidth - bounds.right)}px`
1843
+ );
1844
+ host.style.setProperty(
1845
+ "--fdc-tray-lift",
1846
+ workspaceState.tray !== "hidden" ? `${Math.max(0, window.innerHeight - bounds.bottom)}px` : "0px"
1847
+ );
1848
+ if (workspaceState.utility) applyUtilityRect(workspaceState.utility);
1849
+ }
1850
+ function persistUtilityRect(utility, rect) {
1851
+ utilityRects.set(utility, rect);
1852
+ try {
1853
+ localStorage.setItem(utilityStorageKey(utility), JSON.stringify(rect));
1854
+ } catch {
1855
+ showToast("Panel position could not be saved in this browser");
1856
+ }
1857
+ }
1858
+ function setUtility(utility) {
1859
+ const closing = utility == null;
1860
+ if (!closing && shadow.activeElement instanceof HTMLElement) {
1861
+ lastUtilityTrigger = shadow.activeElement;
1862
+ }
1863
+ workspaceState = utility ? updateWorkspace(workspaceState, { type: "open-utility", utility }) : updateWorkspace(workspaceState, { type: "close-utility" });
1864
+ healthPanel.hidden = workspaceState.utility !== "health";
1865
+ libraryPanel.hidden = workspaceState.utility !== "memory";
1866
+ shadow.querySelector(".open-health").classList.toggle("active", workspaceState.utility === "health");
1867
+ shadow.querySelector(".open-library").classList.toggle("active", workspaceState.utility === "memory");
1868
+ shadow.querySelector(".open-health").setAttribute("aria-pressed", String(workspaceState.utility === "health"));
1869
+ shadow.querySelector(".open-library").setAttribute("aria-pressed", String(workspaceState.utility === "memory"));
1870
+ if (workspaceState.utility === "health") scanDesignHealth();
1871
+ if (workspaceState.utility === "memory") renderDesignMemory();
1872
+ positionWorkspaceSurfaces();
1873
+ if (closing) lastUtilityTrigger?.focus();
1874
+ }
1875
+ function installUtilityGeometry(utilityPanel, utility) {
1876
+ const handle = utilityPanel.querySelector(".utility-handle");
1877
+ const resizer = utilityPanel.querySelector(".utility-resizer");
1878
+ handle.addEventListener("pointerdown", (event) => {
1879
+ if (event.button !== 0 || event.target.closest("button")) return;
1880
+ const start = utilityPanel.getBoundingClientRect();
1881
+ const startX = event.clientX;
1882
+ const startY = event.clientY;
1883
+ handle.setPointerCapture(event.pointerId);
1884
+ const move = (pointerMove) => {
1885
+ const rect = clampUtilityRect(
1886
+ {
1887
+ x: start.x + pointerMove.clientX - startX,
1888
+ y: start.y + pointerMove.clientY - startY,
1889
+ width: start.width,
1890
+ height: start.height
1891
+ },
1892
+ canvasBounds()
1893
+ );
1894
+ Object.assign(utilityPanel.style, { left: `${rect.x}px`, top: `${rect.y}px` });
1895
+ utilityRects.set(utility, rect);
1896
+ };
1897
+ const finish = () => {
1898
+ handle.removeEventListener("pointermove", move);
1899
+ handle.removeEventListener("pointerup", finish);
1900
+ handle.removeEventListener("pointercancel", finish);
1901
+ const rect = utilityRects.get(utility);
1902
+ if (rect) persistUtilityRect(utility, rect);
1903
+ };
1904
+ handle.addEventListener("pointermove", move);
1905
+ handle.addEventListener("pointerup", finish);
1906
+ handle.addEventListener("pointercancel", finish);
1907
+ });
1908
+ resizer.addEventListener("pointerdown", (event) => {
1909
+ if (event.button !== 0) return;
1910
+ const start = utilityPanel.getBoundingClientRect();
1911
+ const startX = event.clientX;
1912
+ const startY = event.clientY;
1913
+ resizer.setPointerCapture(event.pointerId);
1914
+ const move = (pointerMove) => {
1915
+ const rect = clampUtilityRect(
1916
+ {
1917
+ x: start.x,
1918
+ y: start.y,
1919
+ width: start.width + pointerMove.clientX - startX,
1920
+ height: start.height + pointerMove.clientY - startY
1921
+ },
1922
+ canvasBounds()
1923
+ );
1924
+ Object.assign(utilityPanel.style, {
1925
+ width: `${rect.width}px`,
1926
+ height: `${rect.height}px`
1927
+ });
1928
+ utilityRects.set(utility, rect);
1929
+ };
1930
+ const finish = () => {
1931
+ resizer.removeEventListener("pointermove", move);
1932
+ resizer.removeEventListener("pointerup", finish);
1933
+ resizer.removeEventListener("pointercancel", finish);
1934
+ const rect = utilityRects.get(utility);
1935
+ if (rect) persistUtilityRect(utility, rect);
1936
+ };
1937
+ resizer.addEventListener("pointermove", move);
1938
+ resizer.addEventListener("pointerup", finish);
1939
+ resizer.addEventListener("pointercancel", finish);
1940
+ });
1941
+ }
1745
1942
  if (!sessionId || !token) {
1746
1943
  setSessionStatus(
1747
1944
  "offline",
@@ -1763,13 +1960,20 @@ function installFoundryInspector(options = {}) {
1763
1960
  function updateChangeCount(count, latest) {
1764
1961
  changeCount.textContent = String(count);
1765
1962
  changeCount.hidden = count === 0;
1766
- shadow.querySelector(".footer .review").hidden = count > 0;
1767
1963
  changeDock.hidden = count === 0;
1964
+ workspaceState = updateWorkspace(workspaceState, {
1965
+ type: "set-tray",
1966
+ tray: count === 0 ? "hidden" : workspaceState.tray === "expanded" ? "expanded" : "collapsed"
1967
+ });
1968
+ if (count === 0) reviewView.hidden = true;
1969
+ changeDock.classList.toggle("expanded", workspaceState.tray === "expanded");
1970
+ trayCompare.disabled = count === 0 || historyCursor === 0;
1768
1971
  changeDock.querySelector("[data-dock-count]").textContent = `${count} ${count === 1 ? "change" : "changes"} recorded`;
1769
1972
  if (latest) {
1770
1973
  lastRecordedSummary = `${latest.target?.label ?? "Element"} \xB7 ${latest.property} ${reviewValue(latest.before, latest.unit)} \u2192 ${reviewValue(latest.after, latest.unit)}`;
1771
1974
  }
1772
1975
  changeDock.querySelector("[data-dock-last]").textContent = lastRecordedSummary || "Ready to review";
1976
+ positionWorkspaceSurfaces();
1773
1977
  }
1774
1978
  function populateDesignContext() {
1775
1979
  if (!designGraph) return;
@@ -1822,6 +2026,8 @@ function installFoundryInspector(options = {}) {
1822
2026
  if (projectRoot !== nextProjectRoot || !hydratedOnce) {
1823
2027
  projectRoot = nextProjectRoot;
1824
2028
  designMemory = readDesignMemory(localStorage, projectRoot);
2029
+ utilityRects.clear();
2030
+ positionWorkspaceSurfaces();
1825
2031
  }
1826
2032
  projectRevision = changeSet.context.revision ?? "";
1827
2033
  designGraph = graph;
@@ -1887,13 +2093,10 @@ function installFoundryInspector(options = {}) {
1887
2093
  );
1888
2094
  }
1889
2095
  function openDesignMemory() {
1890
- libraryPanel.hidden = false;
1891
- shadow.querySelector(".open-library").classList.add("active");
1892
- renderDesignMemory();
2096
+ if (workspaceState.utility !== "memory") setUtility("memory");
1893
2097
  }
1894
2098
  function closeDesignMemory() {
1895
- libraryPanel.hidden = true;
1896
- shadow.querySelector(".open-library").classList.remove("active");
2099
+ if (workspaceState.utility === "memory") setUtility(null);
1897
2100
  }
1898
2101
  function saveSelectedRecipe() {
1899
2102
  if (!selected) return;
@@ -2200,7 +2403,7 @@ function installFoundryInspector(options = {}) {
2200
2403
  (variant) => `<button data-component-variant="${escapeHtml(variant.id)}" data-component-owner="${index}">${escapeHtml(variant.name)}</button>`
2201
2404
  ).join("");
2202
2405
  const remainingVariants = Math.max(0, entry.variants.length - 3);
2203
- return `<article class="component-card ${selectedComponent2 ? "selected" : ""}" data-component-row="${index}"><button class="component-main" data-component-index="${index}" aria-label="${liveCount ? `Select ${escapeHtml(entry.name)} component` : `${escapeHtml(entry.name)} component is not on the canvas`}" ${liveCount ? "" : "disabled"}><span class="component-mark"><i data-lucide="component"></i></span><span class="component-copy"><strong>${escapeHtml(entry.name)}</strong><span>${escapeHtml(entry.namespace)}</span></span><span class="component-status"><span>${liveCount ? `${liveCount} live` : "Indexed"}</span><small>${entry.variants.length ? `${entry.variants.length} variant${entry.variants.length === 1 ? "" : "s"}` : `${entry.indexedInstances} instance${entry.indexedInstances === 1 ? "" : "s"}`}</small></span></button>${variants ? `<div class="component-variants">${variants}${remainingVariants ? `<button data-component-index="${index}">+${remainingVariants}</button>` : ""}</div>` : ""}${liveCount > 1 ? `<div class="component-actions"><button data-select-all-instances="${index}">Select all ${liveCount} instances</button></div>` : ""}</article>`;
2406
+ return `<article class="component-card ${selectedComponent2 ? "selected" : ""}" data-component-row="${index}"><button class="component-main" data-component-index="${index}" aria-label="${liveCount ? `Select ${escapeHtml(entry.name)} component` : `${escapeHtml(entry.name)} component is not on the canvas`}" ${liveCount ? "" : "disabled"}><span class="component-mark"><i data-foundry-icon="component"></i></span><span class="component-copy"><strong>${escapeHtml(entry.name)}</strong><span>${escapeHtml(entry.namespace)}</span></span><span class="component-status"><span>${liveCount ? `${liveCount} live` : "Indexed"}</span><small>${entry.variants.length ? `${entry.variants.length} variant${entry.variants.length === 1 ? "" : "s"}` : `${entry.indexedInstances} instance${entry.indexedInstances === 1 ? "" : "s"}`}</small></span></button>${variants ? `<div class="component-variants">${variants}${remainingVariants ? `<button data-component-index="${index}">+${remainingVariants}</button>` : ""}</div>` : ""}${liveCount > 1 ? `<div class="component-actions"><button data-select-all-instances="${index}">Select all ${liveCount} instances</button></div>` : ""}</article>`;
2204
2407
  }).join("")}</div>` : '<div class="layers-empty">No components match this search.</div>';
2205
2408
  renderIcons(layerTree);
2206
2409
  layerTree.querySelectorAll("[data-component-row]").forEach((row) => {
@@ -2312,7 +2515,7 @@ function installFoundryInspector(options = {}) {
2312
2515
  const index = layerEntries.indexOf(entry);
2313
2516
  const meta = entry.instrumented ? "Mapped" : entry.kind;
2314
2517
  const collapsed = collapsedLayers.has(entry.element);
2315
- return `<div class="layer-row ${selectedElements.includes(entry.element) ? "selected" : ""}" style="--layer-depth:${Math.min(entry.depth, 8)}" data-layer-row="${index}" draggable="true"><button class="layer-toggle" data-layer-toggle="${index}" aria-label="${collapsed ? "Expand" : "Collapse"} ${escapeHtml(entry.label)}" aria-expanded="${!collapsed}" ${entry.hasChildren ? "" : "disabled"}><i data-lucide="${collapsed ? "chevron-right" : "chevron-down"}"></i></button><button class="layer-select" data-layer-index="${index}" aria-label="Select ${escapeHtml(entry.label)}"><i class="layer-icon" data-lucide="${entry.kind === "component" ? "component" : "box"}"></i><span class="layer-label">${escapeHtml(entry.label)}</span><span class="layer-meta">${escapeHtml(meta)}</span></button></div>`;
2518
+ return `<div class="layer-row ${selectedElements.includes(entry.element) ? "selected" : ""}" style="--layer-depth:${Math.min(entry.depth, 8)}" data-layer-row="${index}" draggable="true"><button class="layer-toggle" data-layer-toggle="${index}" aria-label="${collapsed ? "Expand" : "Collapse"} ${escapeHtml(entry.label)}" aria-expanded="${!collapsed}" ${entry.hasChildren ? "" : "disabled"}><i data-foundry-icon="${collapsed ? "chevron-right" : "chevron-down"}"></i></button><button class="layer-select" data-layer-index="${index}" aria-label="Select ${escapeHtml(entry.label)}"><i class="layer-icon" data-foundry-icon="${entry.kind === "component" ? "component" : "box"}"></i><span class="layer-label">${escapeHtml(entry.label)}</span><span class="layer-meta">${escapeHtml(meta)}</span></button></div>`;
2316
2519
  }).join(
2317
2520
  ""
2318
2521
  )}${range.after ? `<div class="layer-spacer" style="height:${range.after}px"></div>` : ""}` : '<div class="layers-empty">No visible layers match this search.</div>';
@@ -2402,19 +2605,41 @@ function installFoundryInspector(options = {}) {
2402
2605
  }
2403
2606
  const layersPreferenceKey = "__foundry_layers_visibility";
2404
2607
  function toggleLayers(force, remember = true) {
2405
- if (force !== false) healthPanel.hidden = true;
2406
- layersPanel.hidden = force == null ? !layersPanel.hidden : !force;
2608
+ workspaceState = updateWorkspace(workspaceState, {
2609
+ type: "toggle-layers",
2610
+ open: force
2611
+ });
2612
+ layersPanel.hidden = !workspaceState.layersOpen;
2407
2613
  const layersButton = shadow.querySelector(".toggle-layers");
2408
- const layersButtonLabel = layersPanel.hidden ? "Open layers" : "Close layers";
2614
+ const layersButtonLabel = workspaceState.layersOpen ? "Hide layers" : "Show layers";
2409
2615
  layersButton.setAttribute("aria-label", layersButtonLabel);
2410
2616
  layersButton.title = layersButtonLabel;
2411
- layersButton.classList.toggle("active", !layersPanel.hidden);
2412
- shadow.querySelector(".open-health").classList.remove("active");
2617
+ layersButton.setAttribute("aria-pressed", String(workspaceState.layersOpen));
2618
+ layersButton.classList.toggle("active", workspaceState.layersOpen);
2413
2619
  if (remember) {
2414
- sessionStorage.setItem(layersPreferenceKey, layersPanel.hidden ? "closed" : "open");
2620
+ sessionStorage.setItem(layersPreferenceKey, workspaceState.layersOpen ? "open" : "closed");
2415
2621
  }
2416
- if (!layersPanel.hidden) renderLayers();
2622
+ if (workspaceState.layersOpen) renderLayers();
2417
2623
  else previewLayer(null);
2624
+ positionWorkspaceSurfaces();
2625
+ }
2626
+ function toggleInspector(force) {
2627
+ workspaceState = updateWorkspace(workspaceState, {
2628
+ type: "toggle-inspector",
2629
+ open: force
2630
+ });
2631
+ panel.hidden = !workspaceState.inspectorOpen;
2632
+ shadow.querySelectorAll(".toggle-inspector").forEach((button) => {
2633
+ button.classList.toggle("active", workspaceState.inspectorOpen);
2634
+ button.setAttribute("aria-pressed", String(workspaceState.inspectorOpen));
2635
+ if (!button.classList.contains("inspector-collapse")) {
2636
+ button.setAttribute(
2637
+ "aria-label",
2638
+ workspaceState.inspectorOpen ? "Hide inspector" : "Show inspector"
2639
+ );
2640
+ }
2641
+ });
2642
+ positionWorkspaceSurfaces();
2418
2643
  }
2419
2644
  function selectionCandidatesAt(x, y, preferMappedTarget = false) {
2420
2645
  const hitElements = (root) => {
@@ -2451,9 +2676,8 @@ function installFoundryInspector(options = {}) {
2451
2676
  function updateHistoryActions() {
2452
2677
  shadow.querySelector(".undo").disabled = historyCursor === 0;
2453
2678
  shadow.querySelector(".redo").disabled = historyCursor >= previewHistory.length;
2454
- const compare = shadow.querySelector(".open-compare");
2455
- compare.disabled = historyCursor === 0;
2456
- compare.title = historyCursor ? "Compare changes (Shift-C)" : "Make a preview change to enable comparison";
2679
+ trayCompare.disabled = historyCursor === 0;
2680
+ trayCompare.title = historyCursor ? "Compare changes (Shift-C)" : "Make a preview change to enable comparison";
2457
2681
  }
2458
2682
  function pushHistory(entry) {
2459
2683
  previewHistory.splice(historyCursor);
@@ -2645,8 +2869,11 @@ function installFoundryInspector(options = {}) {
2645
2869
  if (matrixMode) renderWorkbenchMatrix();
2646
2870
  }
2647
2871
  function openWorkbench() {
2872
+ workspaceState = updateWorkspace(workspaceState, { type: "set-workbench", open: true });
2648
2873
  workbench.hidden = false;
2649
- shadow.querySelector(".open-workbench").classList.add("active");
2874
+ const workbenchButton = shadow.querySelector(".open-workbench");
2875
+ workbenchButton.classList.add("active");
2876
+ workbenchButton.setAttribute("aria-pressed", "true");
2650
2877
  resizeWorkbench();
2651
2878
  const frame = shadow.querySelector(".frame-shell iframe");
2652
2879
  const url = new URL(location.href);
@@ -2656,8 +2883,11 @@ function installFoundryInspector(options = {}) {
2656
2883
  if (matrixMode) renderWorkbenchMatrix();
2657
2884
  }
2658
2885
  function closeWorkbench() {
2886
+ workspaceState = updateWorkspace(workspaceState, { type: "set-workbench", open: false });
2659
2887
  workbench.hidden = true;
2660
- shadow.querySelector(".open-workbench").classList.remove("active");
2888
+ const workbenchButton = shadow.querySelector(".open-workbench");
2889
+ workbenchButton.classList.remove("active");
2890
+ workbenchButton.setAttribute("aria-pressed", "false");
2661
2891
  }
2662
2892
  function reviewValue(value, unit) {
2663
2893
  const rendered = typeof value === "string" ? value : JSON.stringify(value);
@@ -2669,23 +2899,6 @@ function installFoundryInspector(options = {}) {
2669
2899
  }
2670
2900
  return change.target.locator?.selector ?? "Source mapping unavailable";
2671
2901
  }
2672
- function reviewVisual(change, afterValue) {
2673
- const before = String(change.before);
2674
- const after = String(afterValue);
2675
- const property = String(change.property);
2676
- const colorValue = (value) => /^(#|rgb|hsl|oklch|transparent)/i.test(value.trim()) ? value.trim() : "#e8e8e8";
2677
- const numeric = (value) => Math.max(0, Number.parseFloat(value) || 0);
2678
- const sample = (value, label) => {
2679
- let style = "";
2680
- if (/color|fill|background/i.test(property)) style = `--sample-color:${colorValue(value)}`;
2681
- else if (/radius/i.test(property))
2682
- style = `--sample-radius:${Math.min(16, numeric(value))}px`;
2683
- else if (/width|height|gap|padding|margin|size/i.test(property))
2684
- style = `--sample-scale:${Math.max(0.45, Math.min(1.35, numeric(value) / Math.max(numeric(before), numeric(after), 1)))}`;
2685
- return `<span class="review-sample" data-label="${label}"><i style="${escapeHtml(style)}"></i></span>`;
2686
- };
2687
- return `<span class="review-visual">${sample(before, "Before")}${sample(after, "After")}</span>`;
2688
- }
2689
2902
  function persistReviewDraft() {
2690
2903
  try {
2691
2904
  sessionStorage.setItem(reviewDraftKey, JSON.stringify(reviewDraft));
@@ -2706,7 +2919,19 @@ function installFoundryInspector(options = {}) {
2706
2919
  const selectableCount = reviewBody.querySelectorAll(
2707
2920
  "[data-review-change]:not(:disabled)"
2708
2921
  ).length;
2922
+ const summary = reviewBody.querySelector(".review-summary");
2923
+ const elementCount = reviewBody.querySelectorAll(".review-group").length;
2924
+ const unresolvedCount = Number(summary?.dataset.unresolved ?? 0);
2709
2925
  reviewCount.textContent = `${selectedCount} of ${selectableCount} included`;
2926
+ if (summary) {
2927
+ summary.classList.toggle("attention", unresolvedCount > 0);
2928
+ summary.querySelector("strong").textContent = reviewSummary(
2929
+ selectedCount,
2930
+ selectableCount,
2931
+ elementCount,
2932
+ unresolvedCount
2933
+ );
2934
+ }
2710
2935
  reviewBody.querySelectorAll(".review-group").forEach((group) => {
2711
2936
  const included = group.querySelectorAll(
2712
2937
  "[data-review-change]:checked:not(:disabled)"
@@ -2726,11 +2951,14 @@ function installFoundryInspector(options = {}) {
2726
2951
  const rejectedCount = activeReviewPayload?.changeSet?.changes?.filter(
2727
2952
  (change) => change.status === "rejected" && String(change.before) !== String(change.after)
2728
2953
  ).length ?? 0;
2729
- reviewBody.innerHTML = changes.length || rejectedCount ? `<div class="review-toolbar"><button data-review-approve-exact>Approve exact</button><button data-review-toggle-rejected>${reviewShowRejected ? "Hide" : "Show"} rejected${rejectedCount ? ` \xB7 ${rejectedCount}` : ""}</button></div>${[
2954
+ const unresolvedCount = changes.filter(
2955
+ (change) => change.confidence === "unresolved" || change.mappingCandidates?.length > 1 && !change.selectedMappingId
2956
+ ).length;
2957
+ reviewBody.innerHTML = changes.length || rejectedCount ? `<div class="review-overview"><div class="review-summary" data-unresolved="${unresolvedCount}" aria-live="polite"><strong>Preparing review\u2026</strong><span>Only included, exactly mapped changes will be sent to your agent.</span></div><div class="review-toolbar"><button data-review-approve-exact>Include all</button><button data-review-toggle-rejected>${reviewShowRejected ? "Hide removed" : rejectedCount ? `${rejectedCount} removed` : "Removed"}</button></div></div>${[
2730
2958
  ...groups.values()
2731
2959
  ].map((group) => {
2732
2960
  const target = group[0].target;
2733
- return `<section class="review-group" data-review-target="${escapeHtml(target.id)}"><button class="review-group-title" aria-expanded="true"><i data-lucide="chevron-down"></i><strong>${escapeHtml(target.label)}</strong><span class="included-count"></span><span class="group-total">${group.length}</span></button>${group.map((change) => {
2961
+ return `<section class="review-group" data-review-target="${escapeHtml(target.id)}"><button class="review-group-title" aria-expanded="true"><i data-foundry-icon="chevron-down"></i><strong>${escapeHtml(target.label)}</strong><span class="included-count"></span><span class="group-total">${group.length}</span></button>${group.map((change) => {
2734
2962
  const unresolved = change.confidence === "unresolved" || change.mappingCandidates?.length > 1 && !change.selectedMappingId;
2735
2963
  const selectable = !unresolved && change.status !== "rejected";
2736
2964
  const checked = selectable && reviewSelection(reviewDraft, change.id, true);
@@ -2752,7 +2980,7 @@ function installFoundryInspector(options = {}) {
2752
2980
  componentInstances: component?.instances,
2753
2981
  unresolved
2754
2982
  });
2755
- return `<div class="review-card ${change.status === "rejected" ? "rejected" : ""}" data-review-card="${escapeHtml(change.id)}"><input aria-label="Include ${escapeHtml(change.property)} change" type="checkbox" data-review-change="${escapeHtml(change.id)}" ${checked ? "checked" : ""} ${selectable ? "" : "disabled"}/><span class="review-card-main"><span class="review-card-line"><strong>${escapeHtml(change.property)}</strong><span class="confidence-pill ${unresolved ? "unresolved" : ""}">${escapeHtml(change.status === "rejected" ? "rejected" : change.confidence)}</span><span class="review-card-tools"><button data-review-locate="${escapeHtml(change.id)}">Locate</button><button data-review-preview="${escapeHtml(change.id)}" title="Hold to preview before">Preview</button><button data-review-status="${escapeHtml(change.id)}" data-next-status="${change.status === "rejected" ? "draft" : "rejected"}">${change.status === "rejected" ? "Restore" : "Remove"}</button></span></span>${reviewVisual(change, afterValue)}<span class="review-values"><span class="review-before">${escapeHtml(reviewValue(change.before, change.unit))}</span><span>\u2192</span><input aria-label="New ${escapeHtml(change.property)} value" class="review-after" data-review-after="${escapeHtml(change.id)}" data-value-kind="${inputType}" type="${inputType}" value="${escapeHtml(afterValue)}" ${selectable ? "" : "disabled"}/></span>${mappingChooser}<details class="review-details"><summary>Mapping details</summary><span class="review-source">${escapeHtml(reviewSource(change))} \xB7 ${escapeHtml(change.scope)} \xB7 ${escapeHtml(change.context.breakpoint)} \xB7 ${escapeHtml(change.context.theme)}${change.token ? ` \xB7 ${escapeHtml(change.token)}` : ""}</span><span class="impact-list">${impact.map((message) => `<span class="impact-item ${unresolved || !change.token && message.includes("literal") ? "warning" : ""}">${escapeHtml(message)}</span>`).join("")}</span></details></span></div>`;
2983
+ return `<div class="review-card ${change.status === "rejected" ? "rejected" : ""}" data-review-card="${escapeHtml(change.id)}"><input aria-label="Include ${escapeHtml(change.property)} change" type="checkbox" data-review-change="${escapeHtml(change.id)}" ${checked ? "checked" : ""} ${selectable ? "" : "disabled"}/><div class="review-card-main"><div class="review-card-line"><strong title="${escapeHtml(change.property)}">${escapeHtml(humanizeProperty(change.property))}</strong><span class="confidence-pill ${unresolved ? "unresolved" : ""}">${escapeHtml(change.status === "rejected" ? "removed" : change.confidence)}</span><span class="review-values"><span class="review-before" title="Before: ${escapeHtml(reviewValue(change.before, change.unit))}">${escapeHtml(reviewValue(change.before, change.unit))}</span><span aria-hidden="true">\u2192</span><input aria-label="New ${escapeHtml(change.property)} value" class="review-after" data-review-after="${escapeHtml(change.id)}" data-value-kind="${inputType}" type="${inputType}" value="${escapeHtml(afterValue)}" ${selectable ? "" : "disabled"}/></span><details class="review-more"><summary aria-label="More actions for ${escapeHtml(humanizeProperty(change.property))}">\u2022\u2022\u2022</summary><div class="review-card-tools"><button data-review-locate="${escapeHtml(change.id)}">Locate</button><button data-review-preview="${escapeHtml(change.id)}" title="Hold to preview before">Preview before</button><button data-review-status="${escapeHtml(change.id)}" data-next-status="${change.status === "rejected" ? "draft" : "rejected"}">${change.status === "rejected" ? "Restore" : "Remove"}</button><details class="review-details"><summary>Source and scope</summary><span class="review-source">${escapeHtml(change.property)} \xB7 ${escapeHtml(reviewSource(change))} \xB7 ${escapeHtml(change.scope)} \xB7 ${escapeHtml(change.context.breakpoint)} \xB7 ${escapeHtml(change.context.theme)}${change.token ? ` \xB7 ${escapeHtml(change.token)}` : ""}</span><span class="impact-list">${impact.map((message) => `<span class="impact-item ${unresolved || !change.token && message.includes("literal") ? "warning" : ""}">${escapeHtml(message)}</span>`).join("")}</span></details></div></details></div>${mappingChooser}</div></div>`;
2756
2984
  }).join("")}</section>`;
2757
2985
  }).join("")}` : '<div class="review-empty">No unresolved design edits are waiting for review.</div>';
2758
2986
  applyButton.dataset.action = "apply";
@@ -2962,7 +3190,7 @@ function installFoundryInspector(options = {}) {
2962
3190
  else renderReviewList(pending);
2963
3191
  }
2964
3192
  async function refreshReview() {
2965
- if (!panel.classList.contains("reviewing") || !sessionId || !token) return;
3193
+ if (workspaceState.tray !== "expanded" || !sessionId || !token) return;
2966
3194
  try {
2967
3195
  const payload = await sessionRequest();
2968
3196
  const latestRun = payload.applyRuns?.at(-1);
@@ -2989,20 +3217,29 @@ function installFoundryInspector(options = {}) {
2989
3217
  showToast("Session connection is missing");
2990
3218
  return;
2991
3219
  }
2992
- panel.classList.add("reviewing");
3220
+ if (shadow.activeElement instanceof HTMLElement) lastReviewTrigger = shadow.activeElement;
3221
+ workspaceState = updateWorkspace(workspaceState, { type: "set-tray", tray: "expanded" });
3222
+ changeDock.classList.add("expanded");
2993
3223
  reviewView.hidden = false;
2994
3224
  outline.hidden = true;
3225
+ positionWorkspaceSurfaces();
2995
3226
  renderReviewPayload(await sessionRequest());
2996
3227
  clearInterval(reviewPoll);
2997
3228
  clearInterval(healthPoll);
2998
3229
  reviewPoll = setInterval(() => void refreshReview(), 1e3);
2999
3230
  }
3000
3231
  function closeReview() {
3001
- panel.classList.remove("reviewing");
3232
+ workspaceState = updateWorkspace(workspaceState, {
3233
+ type: "set-tray",
3234
+ tray: changeDock.hidden ? "hidden" : "collapsed"
3235
+ });
3236
+ changeDock.classList.remove("expanded");
3002
3237
  reviewView.hidden = true;
3003
3238
  clearInterval(reviewPoll);
3004
3239
  reviewPoll = void 0;
3005
3240
  updateOutline();
3241
+ positionWorkspaceSurfaces();
3242
+ lastReviewTrigger?.focus();
3006
3243
  }
3007
3244
  async function submitReviewedRun() {
3008
3245
  if (!activeReviewPayload) return;
@@ -3283,27 +3520,10 @@ function installFoundryInspector(options = {}) {
3283
3520
  }
3284
3521
  }
3285
3522
  function renderToolTabs() {
3286
- const categories = [
3287
- .../* @__PURE__ */ new Set([
3288
- "layout",
3289
- "typography",
3290
- "color",
3291
- "effects",
3292
- "content",
3293
- "accessibility",
3294
- ...selected?.getAnimations().length ? ["motion"] : []
3295
- ])
3296
- ];
3297
- tabs.innerHTML = categories.map(
3298
- (category) => `<button class="tab ${selected && activeCategory === category ? "active" : ""}" data-category="${category}" data-tooltip="${CATEGORY_LABELS[category]}" title="${CATEGORY_LABELS[category]} controls" aria-label="${CATEGORY_LABELS[category]} controls" ${selected ? "" : "disabled"}><i data-lucide="${CATEGORY_ICONS[category]}"></i></button>`
3299
- ).join("");
3300
- renderIcons(tabs);
3301
- tabs.querySelectorAll("[data-category]").forEach(
3302
- (button) => button.addEventListener("click", () => {
3303
- activeCategory = button.dataset.category;
3304
- renderControls();
3305
- })
3306
- );
3523
+ const multi = selectedElements.length > 1;
3524
+ shadow.querySelectorAll(".align,.distribute,.multi-actions-divider").forEach((element) => {
3525
+ element.hidden = !multi;
3526
+ });
3307
3527
  }
3308
3528
  function installNumberScrubbing() {
3309
3529
  controlsRoot.querySelectorAll("[data-scrub-for]").forEach((handle) => {
@@ -3496,21 +3716,22 @@ function installFoundryInspector(options = {}) {
3496
3716
  }
3497
3717
  function renderContextPanel(category) {
3498
3718
  if (!selected) return "";
3499
- const tokens = tokensForCategory(category).slice(0, 24);
3719
+ const supportsTokens = ["layout", "typography", "color", "effects"].includes(category);
3720
+ const tokens = supportsTokens ? tokensForCategory(category).slice(0, 24) : [];
3500
3721
  const component = selectedComponent();
3501
3722
  const variants = component?.variants ?? [];
3502
3723
  const tokenPanel = tokens.length ? `<section class="native-panel"><div class="native-panel-head"><strong>Project ${category === "typography" ? "styles" : "tokens"}</strong><span>${tokens.length}</span></div><input class="native-search" type="search" placeholder="Search project values" aria-label="Search project values"/><div class="native-grid">${tokens.map(
3503
3724
  (token2) => `<button class="native-chip" data-native-token="${escapeHtml(token2.id)}" data-token-search="${escapeHtml(`${token2.name} ${token2.value}`.toLowerCase())}" title="${escapeHtml(token2.value)}">${category === "color" ? `<span class="swatch" style="--token-color:${escapeHtml(token2.value)}"></span>` : ""}<span>${escapeHtml(token2.name)}</span></button>`
3504
3725
  ).join("")}</div></section>` : "";
3505
3726
  const contrast = category === "color" ? contrastRatio(getComputedStyle(selected).color, opaqueBackground(selected)) : null;
3506
- const health = category === "color" && contrast != null ? `<div class="design-health ${contrast >= 4.5 ? "pass" : "fail"}"><i data-lucide="contrast"></i><span>${contrast}:1 contrast \xB7 ${contrast >= 4.5 ? "AA pass" : "Needs attention"}</span></div>` : "";
3507
- const variantPanel = variants.length ? `<section class="native-panel"><div class="native-panel-head"><strong>${escapeHtml(component.name)} variants</strong><span>${component.instances} instances</span></div><div class="variant-list">${variants.map(
3727
+ const health = category === "color" && contrast != null ? `<div class="design-health ${contrast >= 4.5 ? "pass" : "fail"}"><i data-foundry-icon="contrast"></i><span>${contrast}:1 contrast \xB7 ${contrast >= 4.5 ? "AA pass" : "Needs attention"}</span></div>` : "";
3728
+ const variantPanel = category === "content" && variants.length ? `<section class="native-panel"><div class="native-panel-head"><strong>${escapeHtml(component.name)} variants</strong><span>${component.instances} instances</span></div><div class="variant-list">${variants.map(
3508
3729
  (variant) => `<button class="variant-button" data-variant="${escapeHtml(variant.id)}"><span>${escapeHtml(variant.name)}</span><code>${escapeHtml(
3509
3730
  Object.entries(variant.props).map(([key, value]) => `${key}=${value}`).join(" \xB7 ")
3510
3731
  )}</code></button>`
3511
3732
  ).join("")}</div></section>` : "";
3512
- const categoryTools = category === "layout" ? `<div class="context-tools"><button data-layout-action="tidy"><i data-lucide="wand-sparkles"></i>Tidy layout</button><button data-layout-action="up"><i data-lucide="arrow-up"></i>Move up</button><button data-layout-action="down"><i data-lucide="arrow-down"></i>Move down</button><button data-layout-action="lock"><i data-lucide="lock"></i>Lock ratio</button></div>` : category === "typography" ? `<div class="context-tools"><button data-type-preset="compact">Compact</button><button data-type-preset="body">Body</button><button data-type-preset="display">Display</button></div>` : category === "color" ? `<div class="context-tools"><button data-color-action="gradient">Linear gradient</button><button data-color-action="clear">Clear fill</button></div>` : "";
3513
- const tokenMode = designGraph?.tokens.length ?? 0 ? `<div class="context-tools"><button class="${tokenOnly ? "active" : ""}" data-token-only><i data-lucide="${tokenOnly ? "lock" : "unlink-2"}"></i>${tokenOnly ? "Token-only on" : "Token-only off"}</button></div>` : "";
3733
+ const categoryTools = category === "layout" ? `<div class="context-tools"><button data-layout-action="tidy"><i data-foundry-icon="wand-sparkles"></i>Tidy layout</button><button data-layout-action="up"><i data-foundry-icon="arrow-up"></i>Move up</button><button data-layout-action="down"><i data-foundry-icon="arrow-down"></i>Move down</button><button data-layout-action="lock"><i data-foundry-icon="lock"></i>Lock ratio</button></div>` : category === "typography" ? `<div class="context-tools"><button data-type-preset="compact">Compact</button><button data-type-preset="body">Body</button><button data-type-preset="display">Display</button></div>` : category === "color" ? `<div class="context-tools"><button data-color-action="gradient">Linear gradient</button><button data-color-action="clear">Clear fill</button></div>` : "";
3734
+ const tokenMode = category === "layout" && (designGraph?.tokens.length ?? 0) ? `<div class="context-tools"><button class="${tokenOnly ? "active" : ""}" data-token-only><i data-foundry-icon="${tokenOnly ? "lock" : "unlink-2"}"></i>${tokenOnly ? "Token-only on" : "Token-only off"}</button></div>` : "";
3514
3735
  return `${categoryTools}${tokenMode}${health}${variantPanel}${tokenPanel}`;
3515
3736
  }
3516
3737
  async function applyControlValue(control, value, operationLabel) {
@@ -3533,21 +3754,26 @@ function installFoundryInspector(options = {}) {
3533
3754
  await record(control, before, after, element, operationLabel);
3534
3755
  }
3535
3756
  function installContextActions(controls) {
3536
- controlsRoot.querySelector(".native-search")?.addEventListener("input", (event) => {
3537
- const queryValue = event.currentTarget.value.toLowerCase();
3538
- controlsRoot.querySelectorAll("[data-token-search]").forEach((chip) => {
3539
- chip.hidden = !chip.dataset.tokenSearch?.includes(queryValue);
3540
- });
3541
- });
3542
- controlsRoot.querySelector("[data-token-only]")?.addEventListener("click", () => {
3543
- tokenOnly = !tokenOnly;
3544
- renderControls();
3545
- });
3757
+ controlsRoot.querySelectorAll(".native-search").forEach(
3758
+ (search) => search.addEventListener("input", (event) => {
3759
+ const queryValue = event.currentTarget.value.toLowerCase();
3760
+ search.closest(".native-panel")?.querySelectorAll("[data-token-search]").forEach((chip) => {
3761
+ chip.hidden = !chip.dataset.tokenSearch?.includes(queryValue);
3762
+ });
3763
+ })
3764
+ );
3765
+ controlsRoot.querySelectorAll("[data-token-only]").forEach(
3766
+ (button) => button.addEventListener("click", () => {
3767
+ tokenOnly = !tokenOnly;
3768
+ renderControls();
3769
+ })
3770
+ );
3546
3771
  controlsRoot.querySelectorAll("[data-native-token]").forEach((button) => {
3547
3772
  button.addEventListener("click", () => {
3548
3773
  const token2 = designGraph?.tokens.find((item) => item.id === button.dataset.nativeToken);
3549
3774
  if (!token2) return;
3550
- const candidateProperties = activeCategory === "color" ? ["color", "backgroundColor", "borderColor"] : activeCategory === "typography" ? ["fontSize", "fontWeight", "lineHeight", "letterSpacing", "fontFamily"] : activeCategory === "effects" ? ["borderRadius"] : ["gap", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft"];
3775
+ const category = button.closest(".inspector-category")?.dataset.category ?? "layout";
3776
+ const candidateProperties = category === "color" ? ["color", "backgroundColor", "borderColor"] : category === "typography" ? ["fontSize", "fontWeight", "lineHeight", "letterSpacing", "fontFamily"] : category === "effects" ? ["borderRadius"] : ["gap", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft"];
3551
3777
  const control = controls.find((item) => item.property === activeControlProperty) ?? candidateProperties.map((property) => controls.find((item) => item.property === property)).find(Boolean);
3552
3778
  if (!control) return;
3553
3779
  const value = control.kind === "number" ? numberFrom(token2.value) : token2.value;
@@ -3703,7 +3929,8 @@ function installFoundryInspector(options = {}) {
3703
3929
  return;
3704
3930
  }
3705
3931
  comparisonActive = true;
3706
- shadow.querySelector(".open-compare").classList.add("active");
3932
+ workspaceState = updateWorkspace(workspaceState, { type: "set-comparison", open: true });
3933
+ trayCompare.classList.add("active");
3707
3934
  compareBar.hidden = false;
3708
3935
  compareBar.querySelector("[data-compare-scrub]").value = mode === "before" ? "0" : "100";
3709
3936
  compareBar.querySelectorAll("[data-compare]").forEach((button) => button.classList.toggle("active", button.dataset.compare === mode));
@@ -3804,7 +4031,8 @@ function installFoundryInspector(options = {}) {
3804
4031
  if (isolatedComparisonElement) toggleComparisonIsolation();
3805
4032
  showComparison("after");
3806
4033
  comparisonActive = false;
3807
- shadow.querySelector(".open-compare").classList.remove("active");
4034
+ workspaceState = updateWorkspace(workspaceState, { type: "set-comparison", open: false });
4035
+ trayCompare.classList.remove("active");
3808
4036
  compareBar.hidden = true;
3809
4037
  }
3810
4038
  const commands = [
@@ -3846,7 +4074,7 @@ function installFoundryInspector(options = {}) {
3846
4074
  const normalized = queryValue.trim().toLowerCase();
3847
4075
  const filtered = commands.filter((command) => command.label.toLowerCase().includes(normalized));
3848
4076
  commandPalette.querySelector(".command-list").innerHTML = filtered.length ? filtered.map(
3849
- (command, index) => `<button class="command-item ${index === 0 ? "active" : ""}" data-command="${command.id}"><i data-lucide="${command.icon}"></i><span>${command.label}</span><small>${command.shortcut}</small></button>`
4077
+ (command, index) => `<button class="command-item ${index === 0 ? "active" : ""}" data-command="${command.id}"><i data-foundry-icon="${command.icon}"></i><span>${command.label}</span><small>${command.shortcut}</small></button>`
3850
4078
  ).join("") : '<div class="layers-empty">No commands match.</div>';
3851
4079
  renderIcons(commandPalette);
3852
4080
  commandPalette.querySelectorAll("[data-command]").forEach(
@@ -4001,8 +4229,8 @@ function installFoundryInspector(options = {}) {
4001
4229
  return `<button class="${healthFilter === filter ? "active" : ""}" data-health-filter="${filter}" aria-pressed="${healthFilter === filter}">${label} ${count}</button>`;
4002
4230
  }).join("");
4003
4231
  healthList.innerHTML = filtered.length ? filtered.map(
4004
- (issue) => `<article class="health-card" data-health-issue="${escapeHtml(issue.id)}"><div class="health-card-top"><span class="health-severity ${issue.severity}"></span><strong>${escapeHtml(issue.title)}</strong><span>${escapeHtml(issue.severity)}</span></div><p>${escapeHtml(issue.description)}</p><div class="health-evidence"><strong>${escapeHtml(issue.elementLabel)}</strong><br/>${escapeHtml(issue.evidence)}</div><div class="health-actions"><button data-health-select="${escapeHtml(issue.id)}">Select</button><button class="health-ignore" data-health-ignore="${escapeHtml(issue.id)}">Ignore</button>${issue.fix ? `<button class="health-fix ${issue.previewed ? "previewed" : ""}" data-health-fix="${escapeHtml(issue.id)}" ${issue.previewed ? "disabled" : ""}>${issue.previewed ? '<i data-lucide="check"></i> Added to review' : escapeHtml(issue.fix.label)}</button>` : ""}</div></article>`
4005
- ).join("") : `<div class="health-empty"><i data-lucide="${visibleIssues.length ? "triangle-alert" : "check"}"></i>${visibleIssues.length ? "No issues match this filter." : "This viewport is looking healthy."}</div>`;
4232
+ (issue) => `<article class="health-card" data-health-issue="${escapeHtml(issue.id)}"><div class="health-card-top"><span class="health-severity ${issue.severity}"></span><strong>${escapeHtml(issue.title)}</strong><span>${escapeHtml(issue.severity)}</span></div><p>${escapeHtml(issue.description)}</p><div class="health-evidence"><strong>${escapeHtml(issue.elementLabel)}</strong><br/>${escapeHtml(issue.evidence)}</div><div class="health-actions"><button data-health-select="${escapeHtml(issue.id)}">Select</button><button class="health-ignore" data-health-ignore="${escapeHtml(issue.id)}">Ignore</button>${issue.fix ? `<button class="health-fix ${issue.previewed ? "previewed" : ""}" data-health-fix="${escapeHtml(issue.id)}" ${issue.previewed ? "disabled" : ""}>${issue.previewed ? '<i data-foundry-icon="check"></i> Added to review' : escapeHtml(issue.fix.label)}</button>` : ""}</div></article>`
4233
+ ).join("") : `<div class="health-empty"><i data-foundry-icon="${visibleIssues.length ? "triangle-alert" : "check"}"></i>${visibleIssues.length ? "No issues match this filter." : "This viewport is looking healthy."}</div>`;
4006
4234
  const ignoredCount = healthIssues.filter((issue) => ignoredHealthIssues.has(issue.id)).length;
4007
4235
  const ignoredButton = shadow.querySelector(".health-show-ignored");
4008
4236
  ignoredButton.hidden = ignoredCount === 0;
@@ -4084,123 +4312,159 @@ function installFoundryInspector(options = {}) {
4084
4312
  showToast("Health correction added to review");
4085
4313
  }
4086
4314
  function openHealth() {
4087
- layersPanel.hidden = true;
4088
- healthPanel.hidden = false;
4089
- shadow.querySelector(".open-health").classList.add("active");
4090
- shadow.querySelector(".toggle-layers").classList.remove("active");
4091
- scanDesignHealth();
4315
+ if (workspaceState.utility !== "health") setUtility("health");
4092
4316
  }
4093
4317
  function closeHealth() {
4094
- healthPanel.hidden = true;
4095
- shadow.querySelector(".open-health").classList.remove("active");
4318
+ if (workspaceState.utility === "health") setUtility(null);
4319
+ }
4320
+ function renderMotionControls(animations) {
4321
+ if (!animations.length) return "";
4322
+ return `<section class="inspector-category property-section ${collapsedSections.has("category:motion") ? "collapsed" : ""}" data-category="motion" data-section-key="category:motion"><div class="inspector-heading section-head"><button class="section-toggle" aria-expanded="${String(!collapsedSections.has("category:motion"))}"><i data-foundry-icon="play"></i><strong>Motion</strong></button><span class="property-count">${animations.length} active</span></div><div class="category-body motion-list">${animations.map((animation, index) => {
4323
+ const timing = animation.effect?.getComputedTiming();
4324
+ const authored = animation.effect?.getTiming();
4325
+ const duration = Number(timing?.duration ?? 0) || 1e3;
4326
+ return `<div class="motion-row" data-animation="${index}"><div class="motion-title"><span>Animation ${index + 1}</span><code>${Math.round(duration)} ms</code></div><input class="motion-timeline" data-motion-timeline type="range" min="0" max="${duration}" step="1" value="${Math.min(duration, Number(animation.currentTime ?? 0))}" aria-label="Animation timeline"/><div class="motion-fields"><label>Duration<input data-motion-duration type="number" min="0" step="10" value="${Math.round(duration)}"/></label><label>Delay<input data-motion-delay type="number" step="10" value="${Math.round(Number(authored?.delay ?? 0))}"/></label><label style="grid-column:1/-1">Easing<input data-motion-easing type="text" value="${escapeHtml(String(authored?.easing ?? "linear"))}"/></label></div><div class="motion-actions"><button data-action="toggle">${animation.playState === "paused" ? "Play" : "Pause"}</button><button data-action="slower">\xBD speed</button><button data-action="faster">2\xD7 speed</button><button data-action="restart">Restart</button></div></div>`;
4327
+ }).join("")}</div></section>`;
4328
+ }
4329
+ function installMotionControls(animations) {
4330
+ controlsRoot.querySelectorAll("[data-animation]").forEach((row) => {
4331
+ const animation = animations[Number(row.dataset.animation)];
4332
+ if (!animation) return;
4333
+ row.querySelector("[data-motion-timeline]").addEventListener("input", (event) => {
4334
+ animation.pause();
4335
+ animation.currentTime = Number(event.currentTarget.value);
4336
+ });
4337
+ const installTimingField = (selector, property, label) => {
4338
+ const field = row.querySelector(selector);
4339
+ field.addEventListener("change", () => {
4340
+ const effect = animation.effect;
4341
+ if (!effect) return;
4342
+ const before = effect.getTiming()[property];
4343
+ const after = property === "easing" ? field.value : Number(field.value);
4344
+ effect.updateTiming({ [property]: after });
4345
+ void record(
4346
+ {
4347
+ category: "motion",
4348
+ property: `animation.${row.dataset.animation}.${property}`,
4349
+ label,
4350
+ kind: property === "easing" ? "text" : "number",
4351
+ value: before,
4352
+ unit: property === "easing" ? void 0 : "ms",
4353
+ read: () => effect.getTiming()[property],
4354
+ apply: (value) => effect.updateTiming({ [property]: value })
4355
+ },
4356
+ before,
4357
+ after
4358
+ );
4359
+ });
4360
+ };
4361
+ installTimingField("[data-motion-duration]", "duration", "Duration");
4362
+ installTimingField("[data-motion-delay]", "delay", "Delay");
4363
+ installTimingField("[data-motion-easing]", "easing", "Easing");
4364
+ row.querySelectorAll("[data-action]").forEach(
4365
+ (button) => button.addEventListener("click", () => {
4366
+ const before = animation.playbackRate;
4367
+ if (button.dataset.action === "toggle")
4368
+ animation.playState === "paused" ? animation.play() : animation.pause();
4369
+ if (button.dataset.action === "slower") animation.playbackRate *= 0.5;
4370
+ if (button.dataset.action === "faster") animation.playbackRate *= 2;
4371
+ if (button.dataset.action === "restart") animation.currentTime = 0;
4372
+ void record(
4373
+ {
4374
+ category: "motion",
4375
+ property: `animation.${row.dataset.animation}.playbackRate`,
4376
+ label: "Playback rate",
4377
+ kind: "number",
4378
+ value: before,
4379
+ read: () => animation.playbackRate,
4380
+ apply: () => {
4381
+ }
4382
+ },
4383
+ before,
4384
+ animation.playbackRate
4385
+ );
4386
+ renderControls();
4387
+ })
4388
+ );
4389
+ });
4096
4390
  }
4097
4391
  function renderControls() {
4098
4392
  renderToolTabs();
4099
- if (activeCategory === "motion") {
4100
- const animations = selected?.getAnimations() ?? [];
4101
- controlsRoot.innerHTML = animations.length ? `<div class="inspector-heading"><i data-lucide="play"></i><strong>Motion</strong><span class="property-count">${animations.length} active</span></div><div class="motion-list">${animations.map((animation, index) => {
4102
- const timing = animation.effect?.getComputedTiming();
4103
- const authored = animation.effect?.getTiming();
4104
- const duration = Number(timing?.duration ?? 0) || 1e3;
4105
- return `<div class="motion-row" data-animation="${index}"><div class="motion-title"><span>Animation ${index + 1}</span><code>${Math.round(duration)} ms</code></div><input class="motion-timeline" data-motion-timeline type="range" min="0" max="${duration}" step="1" value="${Math.min(duration, Number(animation.currentTime ?? 0))}" aria-label="Animation timeline"/><div class="motion-fields"><label>Duration<input data-motion-duration type="number" min="0" step="10" value="${Math.round(duration)}"/></label><label>Delay<input data-motion-delay type="number" step="10" value="${Math.round(Number(authored?.delay ?? 0))}"/></label><label style="grid-column:1/-1">Easing<input data-motion-easing type="text" value="${escapeHtml(String(authored?.easing ?? "linear"))}"/></label></div><div class="motion-actions"><button data-action="toggle">${animation.playState === "paused" ? "Play" : "Pause"}</button><button data-action="slower">\xBD speed</button><button data-action="faster">2\xD7 speed</button><button data-action="restart">Restart</button></div></div>`;
4106
- }).join("")}</div>` : '<div class="empty">No CSS, transition, or Web Animation is active on this element.</div>';
4107
- renderIcons(controlsRoot);
4108
- controlsRoot.querySelectorAll("[data-animation]").forEach((row) => {
4109
- const animation = animations[Number(row.dataset.animation)];
4110
- if (!animation) return;
4111
- row.querySelector("[data-motion-timeline]").addEventListener("input", (event) => {
4112
- animation.pause();
4113
- animation.currentTime = Number(event.currentTarget.value);
4114
- });
4115
- const installTimingField = (selector, property, label) => {
4116
- const field = row.querySelector(selector);
4117
- field.addEventListener("change", () => {
4118
- const effect = animation.effect;
4119
- if (!effect) return;
4120
- const before = effect.getTiming()[property];
4121
- const after = property === "easing" ? field.value : Number(field.value);
4122
- effect.updateTiming({ [property]: after });
4123
- void record(
4124
- {
4125
- category: "motion",
4126
- property: `animation.${row.dataset.animation}.${property}`,
4127
- label,
4128
- kind: property === "easing" ? "text" : "number",
4129
- value: before,
4130
- unit: property === "easing" ? void 0 : "ms",
4131
- read: () => effect.getTiming()[property],
4132
- apply: (value) => effect.updateTiming({ [property]: value })
4133
- },
4134
- before,
4135
- after
4136
- );
4137
- });
4138
- };
4139
- installTimingField("[data-motion-duration]", "duration", "Duration");
4140
- installTimingField("[data-motion-delay]", "delay", "Delay");
4141
- installTimingField("[data-motion-easing]", "easing", "Easing");
4142
- row.querySelectorAll("[data-action]").forEach(
4143
- (button) => button.addEventListener("click", () => {
4144
- const before = animation.playbackRate;
4145
- if (button.dataset.action === "toggle")
4146
- animation.playState === "paused" ? animation.play() : animation.pause();
4147
- if (button.dataset.action === "slower") animation.playbackRate *= 0.5;
4148
- if (button.dataset.action === "faster") animation.playbackRate *= 2;
4149
- if (button.dataset.action === "restart") animation.currentTime = 0;
4150
- void record(
4151
- {
4152
- category: "motion",
4153
- property: `animation.${row.dataset.animation}.playbackRate`,
4154
- label: "Playback rate",
4155
- kind: "number",
4156
- value: before,
4157
- read: () => animation.playbackRate,
4158
- apply: () => {
4159
- }
4160
- },
4161
- before,
4162
- animation.playbackRate
4163
- );
4164
- renderControls();
4165
- })
4166
- );
4167
- });
4393
+ if (!selected) {
4394
+ renderSelectionEmptyState();
4168
4395
  return;
4169
4396
  }
4170
- let controls = selectedControls.filter((control) => control.category === activeCategory);
4171
- if (tokenOnly) {
4172
- controls = controls.filter(
4173
- (control) => matchingTokens(
4174
- designGraph?.tokens ?? [],
4175
- control.property,
4176
- `${control.value}${control.unit ?? ""}`
4177
- ).length > 0
4397
+ const groups = [
4398
+ {
4399
+ key: "position",
4400
+ category: "layout",
4401
+ label: "Position and size",
4402
+ icon: "maximize-2",
4403
+ sectionLabels: ["Position and size"]
4404
+ },
4405
+ {
4406
+ key: "layout",
4407
+ category: "layout",
4408
+ label: "Layout and spacing",
4409
+ icon: CATEGORY_ICONS.layout,
4410
+ sectionLabels: ["Flow", "Padding", "Margin"],
4411
+ showContext: true
4412
+ },
4413
+ ...["typography", "color", "effects", "content", "accessibility"].map(
4414
+ (category) => ({
4415
+ key: category,
4416
+ category,
4417
+ label: CATEGORY_LABELS[category],
4418
+ icon: CATEGORY_ICONS[category],
4419
+ showContext: true
4420
+ })
4421
+ )
4422
+ ];
4423
+ const indexedControls = selectedControls.map((control, index) => ({ control, index })).filter(
4424
+ ({ control }) => tokenOnly ? matchingTokens(
4425
+ designGraph?.tokens ?? [],
4426
+ control.property,
4427
+ `${control.value}${control.unit ?? ""}`
4428
+ ).length > 0 : true
4429
+ );
4430
+ const categoryMarkup = groups.map((group) => {
4431
+ const configuredCategorySections = CONTROL_SECTIONS[group.category] ?? [];
4432
+ const configuredSections = group.sectionLabels ? configuredCategorySections.filter(
4433
+ (section) => group.sectionLabels.includes(section.label)
4434
+ ) : configuredCategorySections;
4435
+ const groupProperties = new Set(
4436
+ configuredSections.flatMap((section) => section.properties)
4178
4437
  );
4179
- }
4180
- const configuredSections = CONTROL_SECTIONS[activeCategory] ?? [];
4181
- const renderedProperties = /* @__PURE__ */ new Set();
4182
- const sections = configuredSections.map((section) => {
4183
- const entries = section.properties.map((property) => {
4184
- const index = controls.findIndex((control) => control.property === property);
4185
- return index >= 0 ? { control: controls[index], index } : void 0;
4186
- }).filter((entry) => Boolean(entry));
4187
- entries.forEach(({ control }) => renderedProperties.add(control.property));
4188
- if (!entries.length) return "";
4189
- const sectionKey = `${activeCategory}:${section.label}`;
4190
- return `<section class="property-section ${collapsedSections.has(sectionKey) ? "collapsed" : ""}" data-section-key="${escapeHtml(sectionKey)}"><div class="section-head"><button class="section-toggle" aria-expanded="${String(!collapsedSections.has(sectionKey))}"><i data-lucide="chevron-down"></i><strong>${escapeHtml(section.label)}</strong></button>${section.label === "Padding" ? `<button class="section-action ${paddingLinked ? "active" : ""}" data-padding-link aria-label="${paddingLinked ? "Unlink padding values" : "Link padding values"}"><i data-lucide="${paddingLinked ? "link-2" : "unlink-2"}"></i></button>` : ""}</div><div class="section-grid ${section.columns === 2 ? "two" : ""} ${section.stacked ? "stacked" : ""}">${entries.map(
4191
- ({ control, index }) => renderPropertyControl(control, index, section.prefixes?.[control.property])
4192
- ).join("")}</div></section>`;
4438
+ const controls = indexedControls.filter(
4439
+ (entry) => entry.control.category === group.category && (!group.sectionLabels || groupProperties.has(entry.control.property))
4440
+ );
4441
+ if (!controls.length) return "";
4442
+ const renderedProperties = /* @__PURE__ */ new Set();
4443
+ const sections = configuredSections.map((section) => {
4444
+ const entries = section.properties.map((property) => controls.find((entry) => entry.control.property === property)).filter((entry) => Boolean(entry));
4445
+ entries.forEach(({ control }) => renderedProperties.add(control.property));
4446
+ if (!entries.length) return "";
4447
+ const sectionKey = `${group.key}:${section.label}`;
4448
+ return `<section class="property-section ${collapsedSections.has(sectionKey) ? "collapsed" : ""}" data-section-key="${escapeHtml(sectionKey)}"><div class="section-head"><button class="section-toggle" aria-expanded="${String(!collapsedSections.has(sectionKey))}"><i data-foundry-icon="chevron-down"></i><strong>${escapeHtml(section.label)}</strong></button>${section.label === "Padding" ? `<button class="section-action ${paddingLinked ? "active" : ""}" data-padding-link aria-label="${paddingLinked ? "Unlink padding values" : "Link padding values"}"><i data-foundry-icon="${paddingLinked ? "link-2" : "unlink-2"}"></i></button>` : ""}</div><div class="section-grid ${section.columns === 2 ? "two" : ""} ${section.stacked ? "stacked" : ""}">${entries.map(
4449
+ ({ control, index }) => renderPropertyControl(control, index, section.prefixes?.[control.property])
4450
+ ).join("")}</div></section>`;
4451
+ }).join("");
4452
+ const remaining = controls.filter(
4453
+ ({ control }) => !renderedProperties.has(control.property)
4454
+ );
4455
+ const remainingSection = remaining.length ? `<section class="property-section ${collapsedSections.has(`${group.key}:Other`) ? "collapsed" : ""}" data-section-key="${escapeHtml(`${group.key}:Other`)}"><div class="section-head"><button class="section-toggle" aria-expanded="${String(!collapsedSections.has(`${group.key}:Other`))}"><i data-foundry-icon="chevron-down"></i><strong>Other</strong></button></div><div class="section-grid">${remaining.map(({ control, index }) => renderPropertyControl(control, index)).join("")}</div></section>` : "";
4456
+ const categoryKey = `category:${group.key}`;
4457
+ return `<section class="inspector-category property-section ${collapsedSections.has(categoryKey) ? "collapsed" : ""}" data-category="${group.key}" data-section-key="${categoryKey}"><div class="inspector-heading section-head"><button class="section-toggle" aria-expanded="${String(!collapsedSections.has(categoryKey))}"><i data-foundry-icon="${group.icon}"></i><strong>${group.label}</strong></button><span class="property-count">${controls.length}</span></div><div class="category-body">${group.showContext ? renderContextPanel(group.category) : ""}${sections}${remainingSection}</div></section>`;
4193
4458
  }).join("");
4194
- const remaining = controls.map((control, index) => ({ control, index })).filter(({ control }) => !renderedProperties.has(control.property));
4195
- const remainingSection = remaining.length ? `<section class="property-section ${collapsedSections.has(`${activeCategory}:Other`) ? "collapsed" : ""}" data-section-key="${escapeHtml(`${activeCategory}:Other`)}"><div class="section-head"><button class="section-toggle" aria-expanded="${String(!collapsedSections.has(`${activeCategory}:Other`))}"><i data-lucide="chevron-down"></i><strong>Other</strong></button></div><div class="section-grid">${remaining.map(({ control, index }) => renderPropertyControl(control, index)).join("")}</div></section>` : "";
4196
- const currentBaseline = selected ? baselineForContext(
4459
+ const currentBaseline = baselineForContext(
4197
4460
  designMemory,
4198
4461
  foundryTargetId(selected),
4199
4462
  breakpoint.value,
4200
4463
  theme.value,
4201
4464
  state.value
4202
- ) : void 0;
4203
- controlsRoot.innerHTML = `<div class="inspector-heading"><i data-lucide="${CATEGORY_ICONS[activeCategory]}"></i><strong>${CATEGORY_LABELS[activeCategory]}</strong><span class="property-count">${controls.length} properties</span></div>${currentBaseline ? `<div style="padding:0 12px"><span class="baseline-badge">Verified baseline \xB7 ${escapeHtml(new Date(currentBaseline.verifiedAt).toLocaleDateString())}</span></div>` : ""}${renderContextPanel(activeCategory)}${controls.length ? `${sections}${remainingSection}` : '<div class="empty">No project-token controls are available for this category.</div>'}`;
4465
+ );
4466
+ const animations = selected.getAnimations();
4467
+ controlsRoot.innerHTML = `${currentBaseline ? `<div class="inspector-baseline"><span class="baseline-badge">Verified baseline \xB7 ${escapeHtml(new Date(currentBaseline.verifiedAt).toLocaleDateString())}</span></div>` : ""}${categoryMarkup}${renderMotionControls(animations)}`;
4204
4468
  renderIcons(controlsRoot);
4205
4469
  controlsRoot.querySelectorAll(".section-toggle").forEach((button) => {
4206
4470
  button.addEventListener("click", () => {
@@ -4212,24 +4476,26 @@ function installFoundryInspector(options = {}) {
4212
4476
  button.setAttribute("aria-expanded", String(!collapsed));
4213
4477
  if (collapsed) collapsedSections.add(key);
4214
4478
  else collapsedSections.delete(key);
4215
- localStorage.setItem(
4479
+ sessionStorage.setItem(
4216
4480
  "__foundry_collapsed_sections",
4217
4481
  JSON.stringify([...collapsedSections])
4218
4482
  );
4219
4483
  });
4220
4484
  });
4221
- controlsRoot.querySelector("[data-padding-link]")?.addEventListener("click", () => {
4222
- paddingLinked = !paddingLinked;
4223
- renderControls();
4224
- });
4225
- controls.forEach((control, index) => {
4485
+ controlsRoot.querySelectorAll("[data-padding-link]").forEach(
4486
+ (button) => button.addEventListener("click", () => {
4487
+ paddingLinked = !paddingLinked;
4488
+ renderControls();
4489
+ })
4490
+ );
4491
+ indexedControls.forEach(({ control, index }) => {
4226
4492
  const matches = matchingTokens(
4227
4493
  designGraph?.tokens ?? [],
4228
4494
  control.property,
4229
4495
  `${control.value}${control.unit ?? ""}`
4230
4496
  );
4231
- const tokenEligible = activeCategory === "layout" && /gap|padding|margin/i.test(control.property) || activeCategory === "typography" && /font|lineHeight|letterSpacing/i.test(control.property) || activeCategory === "color" && /color|background|fill|stroke/i.test(control.property) || activeCategory === "effects" && /radius|shadow|blur/i.test(control.property);
4232
- if (!tokenEligible || !tokensForCategory(activeCategory).length) return;
4497
+ const tokenEligible = control.category === "layout" && /gap|padding|margin/i.test(control.property) || control.category === "typography" && /font|lineHeight|letterSpacing/i.test(control.property) || control.category === "color" && /color|background|fill|stroke/i.test(control.property) || control.category === "effects" && /radius|shadow|blur/i.test(control.property);
4498
+ if (!tokenEligible || !tokensForCategory(control.category).length) return;
4233
4499
  const field = controlsRoot.querySelector(`[data-control="${index}"]`);
4234
4500
  const label = field?.closest("label");
4235
4501
  if (!label) return;
@@ -4247,7 +4513,7 @@ function installFoundryInspector(options = {}) {
4247
4513
  });
4248
4514
  controlsRoot.querySelectorAll("[data-reset-control]").forEach((button) => {
4249
4515
  button.addEventListener("click", () => {
4250
- const control = controls[Number(button.dataset.resetControl)];
4516
+ const control = selectedControls[Number(button.dataset.resetControl)];
4251
4517
  if (!control || !selected) return;
4252
4518
  const entry = previewHistory.find(
4253
4519
  (item) => item.element === selected && item.property === control.property
@@ -4276,7 +4542,7 @@ function installFoundryInspector(options = {}) {
4276
4542
  controlsRoot.querySelectorAll("[data-unit-control]").forEach((unitField) => {
4277
4543
  unitField.addEventListener("change", () => {
4278
4544
  const index = Number(unitField.dataset.unitControl);
4279
- const control = controls[index];
4545
+ const control = selectedControls[index];
4280
4546
  const valueField = controlsRoot.querySelector(
4281
4547
  `input[data-control="${index}"]`
4282
4548
  );
@@ -4321,7 +4587,8 @@ function installFoundryInspector(options = {}) {
4321
4587
  });
4322
4588
  const fieldRecorders = /* @__PURE__ */ new Map();
4323
4589
  controlsRoot.querySelectorAll("[data-control]").forEach((field) => {
4324
- const control = controls[Number(field.dataset.control)];
4590
+ const index = Number(field.dataset.control);
4591
+ const control = selectedControls[index];
4325
4592
  if (!control) return;
4326
4593
  const editedElement = selected;
4327
4594
  const recorder = createDebouncedChangeRecorder(180, (before, after) => {
@@ -4338,7 +4605,7 @@ function installFoundryInspector(options = {}) {
4338
4605
  }
4339
4606
  return record(control, before, after, editedElement);
4340
4607
  });
4341
- fieldRecorders.set(Number(field.dataset.control), recorder);
4608
+ fieldRecorders.set(index, recorder);
4342
4609
  field.addEventListener("focus", () => {
4343
4610
  activeControlProperty = control.property;
4344
4611
  });
@@ -4347,7 +4614,7 @@ function installFoundryInspector(options = {}) {
4347
4614
  const value = control.kind === "number" ? Number(field.value) : field.value;
4348
4615
  control.apply(value);
4349
4616
  if (paddingLinked && control.property.startsWith("padding")) {
4350
- controls.forEach((linkedControl, linkedIndex) => {
4617
+ indexedControls.forEach(({ control: linkedControl, index: linkedIndex }) => {
4351
4618
  if (linkedControl === control || !["paddingTop", "paddingRight", "paddingBottom", "paddingLeft"].includes(
4352
4619
  linkedControl.property
4353
4620
  ))
@@ -4367,18 +4634,20 @@ function installFoundryInspector(options = {}) {
4367
4634
  });
4368
4635
  controlsRoot.querySelectorAll("[data-token-control]").forEach((button) => {
4369
4636
  button.addEventListener("click", () => {
4637
+ const index = Number(button.dataset.tokenControl);
4370
4638
  const field = controlsRoot.querySelector(
4371
- `[data-control="${button.dataset.tokenControl}"]`
4639
+ `[data-control="${index}"]`
4372
4640
  );
4373
- const control = controls[Number(button.dataset.tokenControl)];
4641
+ const control = selectedControls[index];
4374
4642
  if (!field || !control) return;
4375
4643
  const raw = button.dataset.tokenValue ?? "";
4376
4644
  field.value = control.kind === "number" ? String(numberFrom(raw)) : raw;
4377
4645
  field.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
4378
4646
  });
4379
4647
  });
4380
- installContextActions(controls);
4648
+ installContextActions(selectedControls);
4381
4649
  installNumberScrubbing();
4650
+ installMotionControls(animations);
4382
4651
  }
4383
4652
  function select(element, additive = false) {
4384
4653
  if (element === host || host.contains(element)) return;
@@ -4398,14 +4667,16 @@ function installFoundryInspector(options = {}) {
4398
4667
  selected = element;
4399
4668
  }
4400
4669
  selectedControls = controlsFor(element);
4401
- if (activeCategory === "motion" && !element.getAnimations().length) {
4402
- activeCategory = "layout";
4403
- }
4404
4670
  const target = targetFor(element);
4671
+ panel.classList.add("has-selection");
4672
+ selectionRoot.classList.remove("selected-flash");
4673
+ void selectionRoot.offsetWidth;
4674
+ selectionRoot.classList.add("selected-flash");
4405
4675
  selectionKind.textContent = element.tagName.toLowerCase();
4406
4676
  selectionTitle.textContent = selectedElements.length > 1 ? `${selectedElements.length} elements` : target.label;
4407
4677
  selectionCode.textContent = element.dataset.foundrySource || foundrySelector(element);
4408
- selectionState.textContent = "Measured";
4678
+ selectionState.textContent = selectedElements.length > 1 ? "Multi-select" : "Selected";
4679
+ selectionHint.textContent = selectedElements.length > 1 ? `${selectedElements.length} layers \xB7 shared controls are shown` : "Shift-click adds layers \xB7 repeat a click to cycle overlaps";
4409
4680
  selectionConfidence.textContent = target.confidence === "instrumented" ? "Instrumented" : "Measured target";
4410
4681
  selectionStats.hidden = false;
4411
4682
  resizeObserver?.disconnect();
@@ -4420,6 +4691,16 @@ function installFoundryInspector(options = {}) {
4420
4691
  if (!libraryPanel.hidden) renderDesignMemory();
4421
4692
  if (matrixMode) renderWorkbenchMatrix();
4422
4693
  }
4694
+ function renderSelectionEmptyState() {
4695
+ controlsRoot.innerHTML = '<div class="empty-state"><span class="empty-state-icon"><i data-foundry-icon="mouse-pointer-2"></i></span><strong>Select something to begin</strong><p>Click any element on the page, or use Layers for a precise structural selection.</p><span class="empty-state-actions"><button data-empty-layers>Open Layers</button><button data-empty-interact>Interact with app</button></span><kbd>Shift-click adds \xB7 Option-click selects while interacting</kbd></div>';
4696
+ renderIcons(controlsRoot);
4697
+ controlsRoot.querySelector("[data-empty-layers]")?.addEventListener("click", () => toggleLayers(true));
4698
+ controlsRoot.querySelector("[data-empty-interact]")?.addEventListener("click", () => {
4699
+ inspecting = false;
4700
+ updateInspectionMode();
4701
+ showToast("Interaction mode on \xB7 Option-click still selects");
4702
+ });
4703
+ }
4423
4704
  function clearSelection() {
4424
4705
  selected = null;
4425
4706
  selectedElements = [];
@@ -4427,16 +4708,18 @@ function installFoundryInspector(options = {}) {
4427
4708
  sessionStorage.removeItem("__foundry_selected_selector");
4428
4709
  resizeObserver?.disconnect();
4429
4710
  outline.hidden = true;
4711
+ panel.classList.remove("has-selection");
4430
4712
  shadow.querySelectorAll(".multi-outline").forEach((item) => item.remove());
4431
4713
  selectionKind.textContent = "No layer";
4432
4714
  selectionTitle.textContent = "Nothing selected";
4433
4715
  selectionCode.textContent = "Click any element to inspect it";
4434
4716
  selectionState.textContent = "Ready";
4717
+ selectionHint.textContent = "Select mode stays on \xB7 click anywhere to begin";
4435
4718
  selectionStats.hidden = true;
4436
4719
  selectionPath.hidden = true;
4437
4720
  previewLayer(null);
4438
4721
  renderToolTabs();
4439
- controlsRoot.innerHTML = '<div class="empty">Select an element to inspect its measured design controls.</div>';
4722
+ renderSelectionEmptyState();
4440
4723
  updateCanvasActions();
4441
4724
  renderLayers();
4442
4725
  if (!libraryPanel.hidden) renderDesignMemory();
@@ -4591,13 +4874,17 @@ function installFoundryInspector(options = {}) {
4591
4874
  }
4592
4875
  function updateInspectionMode() {
4593
4876
  inspectButton.classList.toggle("active", inspecting);
4877
+ interactButton.classList.toggle("active", !inspecting);
4594
4878
  inspectButton.setAttribute("aria-pressed", String(inspecting));
4595
- inspectButton.setAttribute(
4596
- "aria-label",
4597
- inspecting ? "Selection mode on" : "Interaction mode on"
4598
- );
4599
- inspectButton.dataset.tooltip = inspecting ? "Select mode" : "Interact with app";
4600
- inspectButton.title = inspecting ? "Select mode: click any element" : "Interaction mode: use the app normally. Option-click still selects.";
4879
+ interactButton.setAttribute("aria-pressed", String(!inspecting));
4880
+ inspectButton.setAttribute("aria-label", "Select mode");
4881
+ interactButton.setAttribute("aria-label", "Interact mode");
4882
+ inspectButton.dataset.tooltip = "Select";
4883
+ interactButton.dataset.tooltip = "Interact";
4884
+ inspectButton.title = "Select mode: click any element";
4885
+ interactButton.title = "Interaction mode: use the app normally. Option-click still selects.";
4886
+ modeCopyTitle.textContent = inspecting ? "Select mode" : "Interact mode";
4887
+ modeCopyDetail.textContent = inspecting ? "Click any element" : "Option-click to select";
4601
4888
  }
4602
4889
  async function waitForStableGeometry(changes) {
4603
4890
  let previous = "";
@@ -4780,7 +5067,7 @@ function installFoundryInspector(options = {}) {
4780
5067
  method: "POST",
4781
5068
  body: JSON.stringify({ runId, results })
4782
5069
  });
4783
- if (panel.classList.contains("reviewing")) renderReviewPayload(payload);
5070
+ if (workspaceState.tray === "expanded") renderReviewPayload(payload);
4784
5071
  showToast(
4785
5072
  `${results.filter((result) => result.passed).length}/${results.length} changes verified`
4786
5073
  );
@@ -4911,19 +5198,27 @@ function installFoundryInspector(options = {}) {
4911
5198
  document.addEventListener("keydown", nudgeSelection);
4912
5199
  document.addEventListener("keyup", commitNudge);
4913
5200
  window.addEventListener("scroll", updateOutline, true);
4914
- window.addEventListener("resize", updateOutline);
5201
+ const handleWorkspaceResize = () => {
5202
+ updateOutline();
5203
+ positionWorkspaceSurfaces();
5204
+ };
5205
+ window.addEventListener("resize", handleWorkspaceResize);
4915
5206
  renderToolTabs();
5207
+ renderSelectionEmptyState();
4916
5208
  installResizeHandles();
4917
5209
  installRadiusHandle();
4918
5210
  installPanelResizer();
4919
5211
  updateHistoryActions();
4920
5212
  updateInspectionMode();
4921
5213
  inspectButton.addEventListener("click", () => {
4922
- inspecting = !inspecting;
5214
+ inspecting = true;
4923
5215
  updateInspectionMode();
4924
- showToast(
4925
- inspecting ? "Select mode on \xB7 click any element" : "Interaction mode on \xB7 use the app normally"
4926
- );
5216
+ showToast("Select mode on \xB7 click any element");
5217
+ });
5218
+ interactButton.addEventListener("click", () => {
5219
+ inspecting = false;
5220
+ updateInspectionMode();
5221
+ showToast("Interaction mode on \xB7 use the app normally");
4927
5222
  });
4928
5223
  const toggleStatusPopover = () => {
4929
5224
  statusPopover.hidden = !statusPopover.hidden;
@@ -4944,6 +5239,7 @@ function installFoundryInspector(options = {}) {
4944
5239
  onboarding.hidden = true;
4945
5240
  inspecting = true;
4946
5241
  updateInspectionMode();
5242
+ showToast("Select mode stays on \xB7 click any element to begin");
4947
5243
  });
4948
5244
  onboarding.querySelector(".onboarding-shortcuts")?.addEventListener("click", () => {
4949
5245
  localStorage.setItem("__foundry_onboarded", "1");
@@ -4974,6 +5270,8 @@ function installFoundryInspector(options = {}) {
4974
5270
  shadow.querySelector(".toggle-layers")?.addEventListener("click", () => toggleLayers());
4975
5271
  shadow.querySelector(".close-layers")?.addEventListener("click", () => toggleLayers(false));
4976
5272
  toggleLayers(sessionStorage.getItem(layersPreferenceKey) !== "closed", false);
5273
+ shadow.querySelectorAll(".toggle-inspector").forEach((button) => button.addEventListener("click", () => toggleInspector()));
5274
+ toggleInspector(true);
4977
5275
  layerViewButtons.forEach((button) => {
4978
5276
  button.addEventListener("click", () => {
4979
5277
  layerView = button.dataset.layerView === "components" ? "components" : "layers";
@@ -4983,7 +5281,10 @@ function installFoundryInspector(options = {}) {
4983
5281
  renderLayers();
4984
5282
  });
4985
5283
  });
4986
- shadow.querySelector(".open-health")?.addEventListener("click", openHealth);
5284
+ shadow.querySelector(".open-health")?.addEventListener(
5285
+ "click",
5286
+ () => workspaceState.utility === "health" ? closeHealth() : openHealth()
5287
+ );
4987
5288
  shadow.querySelector(".close-health")?.addEventListener("click", closeHealth);
4988
5289
  shadow.querySelector(".health-rescan")?.addEventListener("click", scanDesignHealth);
4989
5290
  shadow.querySelector(".health-show-ignored")?.addEventListener("click", () => {
@@ -4998,6 +5299,8 @@ function installFoundryInspector(options = {}) {
4998
5299
  libraryPanel.querySelector(".close-library")?.addEventListener("click", closeDesignMemory);
4999
5300
  libraryPanel.querySelector("[data-save-recipe]")?.addEventListener("click", saveSelectedRecipe);
5000
5301
  libraryPanel.querySelector("[data-capture-baseline]")?.addEventListener("click", saveManualBaseline);
5302
+ installUtilityGeometry(healthPanel, "health");
5303
+ installUtilityGeometry(libraryPanel, "memory");
5001
5304
  layerSearch.addEventListener("input", () => renderLayers());
5002
5305
  layerTree.addEventListener("scroll", () => {
5003
5306
  cancelAnimationFrame(layerScrollFrame);
@@ -5011,7 +5314,7 @@ function installFoundryInspector(options = {}) {
5011
5314
  const child = firstLayerChild(selected);
5012
5315
  if (child) select(child);
5013
5316
  });
5014
- shadow.querySelector(".open-compare")?.addEventListener("click", () => showComparison("after"));
5317
+ trayCompare.addEventListener("click", () => showComparison("after"));
5015
5318
  shadow.querySelector(".open-commands")?.addEventListener("click", openCommands);
5016
5319
  compareBar.querySelectorAll("[data-compare]").forEach(
5017
5320
  (button) => button.addEventListener("click", () => {
@@ -5061,8 +5364,6 @@ function installFoundryInspector(options = {}) {
5061
5364
  shadow.querySelector(".redo")?.addEventListener("click", () => void replayHistory(1));
5062
5365
  shadow.querySelector(".align")?.addEventListener("click", () => void alignSelected());
5063
5366
  shadow.querySelector(".distribute")?.addEventListener("click", () => void distributeSelected());
5064
- shadow.querySelector(".verify")?.addEventListener("click", () => void verify());
5065
- shadow.querySelector(".review")?.addEventListener("click", () => void openReview());
5066
5367
  shadow.querySelector(".review-back")?.addEventListener("click", closeReview);
5067
5368
  reviewCancel.addEventListener("click", () => {
5068
5369
  if (reviewCancel.dataset.action === "cancel") void cancelRun();
@@ -5117,7 +5418,7 @@ function installFoundryInspector(options = {}) {
5117
5418
  else if (!healthPanel.hidden) closeHealth();
5118
5419
  else if (comparisonActive) closeComparison();
5119
5420
  else if (!workbench.hidden) closeWorkbench();
5120
- else if (panel.classList.contains("reviewing")) closeReview();
5421
+ else if (workspaceState.tray === "expanded") closeReview();
5121
5422
  else clearSelection();
5122
5423
  }
5123
5424
  document.addEventListener("keydown", handleGlobalShortcuts);
@@ -5159,7 +5460,7 @@ function installFoundryInspector(options = {}) {
5159
5460
  document.removeEventListener("keyup", commitNudge);
5160
5461
  document.removeEventListener("keydown", handleGlobalShortcuts);
5161
5462
  window.removeEventListener("scroll", updateOutline, true);
5162
- window.removeEventListener("resize", updateOutline);
5463
+ window.removeEventListener("resize", handleWorkspaceResize);
5163
5464
  cancelAnimationFrame(selectionHoverFrame);
5164
5465
  host.remove();
5165
5466
  }
@@ -5179,57 +5480,3 @@ function installFoundryInspector(options = {}) {
5179
5480
  export {
5180
5481
  installFoundryInspector
5181
5482
  };
5182
- /*! Bundled license information:
5183
-
5184
- lucide/dist/esm/defaultAttributes.mjs:
5185
- lucide/dist/esm/createElement.mjs:
5186
- lucide/dist/esm/shared/src/utils/hasA11yProp.mjs:
5187
- lucide/dist/esm/shared/src/utils/mergeClasses.mjs:
5188
- lucide/dist/esm/shared/src/utils/toCamelCase.mjs:
5189
- lucide/dist/esm/shared/src/utils/toPascalCase.mjs:
5190
- lucide/dist/esm/replaceElement.mjs:
5191
- lucide/dist/esm/icons/accessibility.mjs:
5192
- lucide/dist/esm/icons/activity.mjs:
5193
- lucide/dist/esm/icons/align-horizontal-space-around.mjs:
5194
- lucide/dist/esm/icons/arrow-down.mjs:
5195
- lucide/dist/esm/icons/arrow-left.mjs:
5196
- lucide/dist/esm/icons/arrow-up.mjs:
5197
- lucide/dist/esm/icons/bookmark.mjs:
5198
- lucide/dist/esm/icons/box.mjs:
5199
- lucide/dist/esm/icons/check.mjs:
5200
- lucide/dist/esm/icons/chevron-down.mjs:
5201
- lucide/dist/esm/icons/chevron-right.mjs:
5202
- lucide/dist/esm/icons/columns-3.mjs:
5203
- lucide/dist/esm/icons/command.mjs:
5204
- lucide/dist/esm/icons/component.mjs:
5205
- lucide/dist/esm/icons/contrast.mjs:
5206
- lucide/dist/esm/icons/eye-off.mjs:
5207
- lucide/dist/esm/icons/eye.mjs:
5208
- lucide/dist/esm/icons/file-text.mjs:
5209
- lucide/dist/esm/icons/layers.mjs:
5210
- lucide/dist/esm/icons/layout-grid.mjs:
5211
- lucide/dist/esm/icons/link-2.mjs:
5212
- lucide/dist/esm/icons/lock.mjs:
5213
- lucide/dist/esm/icons/maximize-2.mjs:
5214
- lucide/dist/esm/icons/mouse-pointer-2.mjs:
5215
- lucide/dist/esm/icons/palette.mjs:
5216
- lucide/dist/esm/icons/panels-top-left.mjs:
5217
- lucide/dist/esm/icons/play.mjs:
5218
- lucide/dist/esm/icons/redo-2.mjs:
5219
- lucide/dist/esm/icons/rotate-ccw.mjs:
5220
- lucide/dist/esm/icons/save.mjs:
5221
- lucide/dist/esm/icons/sparkles.mjs:
5222
- lucide/dist/esm/icons/triangle-alert.mjs:
5223
- lucide/dist/esm/icons/type.mjs:
5224
- lucide/dist/esm/icons/undo-2.mjs:
5225
- lucide/dist/esm/icons/unlink-2.mjs:
5226
- lucide/dist/esm/icons/wand-sparkles.mjs:
5227
- lucide/dist/esm/icons/x.mjs:
5228
- lucide/dist/esm/lucide.mjs:
5229
- (**
5230
- * @license lucide v1.37.0 - ISC
5231
- *
5232
- * This source code is licensed under the ISC license.
5233
- * See the LICENSE file in the root directory of this source tree.
5234
- *)
5235
- */