foundry-design-web-adapter 0.2.0-beta.2 → 0.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +14 -0
- package/dist/adapter.js +1055 -213
- package/dist/index.d.ts.map +1 -1
- package/dist/keyline-icons.d.ts.map +1 -1
- package/dist/ui-foundations.d.ts +8 -0
- package/dist/ui-foundations.d.ts.map +1 -0
- package/dist/workspace.d.ts +10 -4
- package/dist/workspace.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/adapter.js
CHANGED
|
@@ -797,7 +797,15 @@ var data38 = {
|
|
|
797
797
|
var x_default = data38;
|
|
798
798
|
|
|
799
799
|
// src/keyline-icons.ts
|
|
800
|
-
|
|
800
|
+
function normalizeKeylineIcon(icon) {
|
|
801
|
+
const onePixelStroke = icon.body.replace(/stroke-width="[^"]+"/g, 'stroke-width="1"');
|
|
802
|
+
const nonScalingStroke = onePixelStroke.replace(
|
|
803
|
+
/<(path|circle|rect|line|polyline|polygon|ellipse)\b(?![^>]*vector-effect)/g,
|
|
804
|
+
'<$1 vector-effect="non-scaling-stroke"'
|
|
805
|
+
);
|
|
806
|
+
return { ...icon, body: nonScalingStroke };
|
|
807
|
+
}
|
|
808
|
+
var RAW_KEYLINE_ICONS = {
|
|
801
809
|
accessibility: user_check_default,
|
|
802
810
|
activity: activity_default,
|
|
803
811
|
"align-horizontal-space-around": align_offset_left_default,
|
|
@@ -837,6 +845,12 @@ var KEYLINE_ICONS = {
|
|
|
837
845
|
"wand-sparkles": pencil_ruler_default,
|
|
838
846
|
x: x_default
|
|
839
847
|
};
|
|
848
|
+
var KEYLINE_ICONS = Object.fromEntries(
|
|
849
|
+
Object.entries(RAW_KEYLINE_ICONS).map(([semantic, icon]) => [
|
|
850
|
+
semantic,
|
|
851
|
+
normalizeKeylineIcon(icon)
|
|
852
|
+
])
|
|
853
|
+
);
|
|
840
854
|
function renderKeylineIcons(root) {
|
|
841
855
|
root.querySelectorAll("[data-foundry-icon]").forEach((placeholder) => {
|
|
842
856
|
const semanticName = placeholder.dataset.foundryIcon;
|
|
@@ -847,18 +861,51 @@ function renderKeylineIcons(root) {
|
|
|
847
861
|
svg.setAttribute("viewBox", `0 0 ${icon.width ?? 24} ${icon.height ?? 24}`);
|
|
848
862
|
svg.setAttribute("aria-hidden", "true");
|
|
849
863
|
svg.setAttribute("focusable", "false");
|
|
864
|
+
svg.setAttribute("fill", "none");
|
|
865
|
+
svg.setAttribute("stroke-width", "1");
|
|
850
866
|
svg.setAttribute("data-keyline-icon", semanticName);
|
|
851
867
|
svg.innerHTML = icon.body;
|
|
852
868
|
placeholder.replaceWith(svg);
|
|
853
869
|
});
|
|
854
870
|
}
|
|
855
871
|
|
|
872
|
+
// src/ui-foundations.ts
|
|
873
|
+
var FOUNDRY_UI_FOUNDATION_CSS = `
|
|
874
|
+
:host {
|
|
875
|
+
--fdc-space-1:4px;
|
|
876
|
+
--fdc-space-2:8px;
|
|
877
|
+
--fdc-space-3:12px;
|
|
878
|
+
--fdc-space-4:16px;
|
|
879
|
+
--fdc-space-5:20px;
|
|
880
|
+
--fdc-space-6:24px;
|
|
881
|
+
--fdc-space-7:28px;
|
|
882
|
+
--fdc-space-8:32px;
|
|
883
|
+
--fdc-radius-xs:4px;
|
|
884
|
+
--fdc-radius-sm:8px;
|
|
885
|
+
--fdc-radius-md:12px;
|
|
886
|
+
--fdc-radius-lg:16px;
|
|
887
|
+
--fdc-control-sm:32px;
|
|
888
|
+
--fdc-control-md:36px;
|
|
889
|
+
--fdc-control-lg:40px;
|
|
890
|
+
--fdc-icon-sm:12px;
|
|
891
|
+
--fdc-icon-md:16px;
|
|
892
|
+
--fdc-icon-lg:20px;
|
|
893
|
+
--fdc-type-caption:12px;
|
|
894
|
+
--fdc-type-body:16px;
|
|
895
|
+
--fdc-type-heading:20px;
|
|
896
|
+
}
|
|
897
|
+
`;
|
|
898
|
+
|
|
856
899
|
// src/workspace.ts
|
|
900
|
+
function resolveInterfaceTheme(preference, systemPrefersDark) {
|
|
901
|
+
return preference === "system" ? systemPrefersDark ? "dark" : "light" : preference;
|
|
902
|
+
}
|
|
857
903
|
var DEFAULT_WORKSPACE_STATE = {
|
|
858
904
|
layersOpen: true,
|
|
859
905
|
inspectorOpen: true,
|
|
860
906
|
utility: null,
|
|
861
|
-
|
|
907
|
+
changeSummaryVisible: false,
|
|
908
|
+
reviewOpen: false,
|
|
862
909
|
workbenchOpen: false,
|
|
863
910
|
comparisonOpen: false
|
|
864
911
|
};
|
|
@@ -873,7 +920,14 @@ function updateWorkspace(state, action) {
|
|
|
873
920
|
return { ...state, utility: state.utility === action.utility ? null : action.utility };
|
|
874
921
|
}
|
|
875
922
|
if (action.type === "close-utility") return { ...state, utility: null };
|
|
876
|
-
if (action.type === "set-
|
|
923
|
+
if (action.type === "set-change-summary") {
|
|
924
|
+
return {
|
|
925
|
+
...state,
|
|
926
|
+
changeSummaryVisible: action.visible,
|
|
927
|
+
reviewOpen: action.visible ? state.reviewOpen : false
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
if (action.type === "set-review") return { ...state, reviewOpen: action.open };
|
|
877
931
|
if (action.type === "set-workbench") return { ...state, workbenchOpen: action.open };
|
|
878
932
|
return { ...state, comparisonOpen: action.open };
|
|
879
933
|
}
|
|
@@ -914,14 +968,19 @@ var CONTROL_SECTIONS = {
|
|
|
914
968
|
{
|
|
915
969
|
label: "Position and size",
|
|
916
970
|
properties: [
|
|
917
|
-
"
|
|
918
|
-
"
|
|
971
|
+
"left",
|
|
972
|
+
"top",
|
|
919
973
|
"width",
|
|
920
974
|
"height",
|
|
975
|
+
"widthMode",
|
|
976
|
+
"heightMode",
|
|
921
977
|
"minWidth",
|
|
922
978
|
"maxWidth",
|
|
923
979
|
"aspectRatio",
|
|
924
|
-
"overflow"
|
|
980
|
+
"overflow",
|
|
981
|
+
"rotate",
|
|
982
|
+
"scaleX",
|
|
983
|
+
"scaleY"
|
|
925
984
|
],
|
|
926
985
|
columns: 2,
|
|
927
986
|
prefixes: {
|
|
@@ -932,7 +991,12 @@ var CONTROL_SECTIONS = {
|
|
|
932
991
|
minWidth: "Min",
|
|
933
992
|
maxWidth: "Max",
|
|
934
993
|
aspectRatio: "Ratio",
|
|
935
|
-
overflow: "Clip"
|
|
994
|
+
overflow: "Clip",
|
|
995
|
+
left: "X",
|
|
996
|
+
top: "Y",
|
|
997
|
+
rotate: "\xB0",
|
|
998
|
+
scaleX: "FX",
|
|
999
|
+
scaleY: "FY"
|
|
936
1000
|
}
|
|
937
1001
|
},
|
|
938
1002
|
{
|
|
@@ -988,17 +1052,29 @@ var CONTROL_SECTIONS = {
|
|
|
988
1052
|
}
|
|
989
1053
|
],
|
|
990
1054
|
color: [
|
|
991
|
-
{ label: "Appearance", properties: ["
|
|
992
|
-
{ label: "
|
|
1055
|
+
{ label: "Appearance", properties: ["opacity"] },
|
|
1056
|
+
{ label: "Fill", properties: ["color", "backgroundColor", "backgroundImage"], stacked: true }
|
|
993
1057
|
],
|
|
994
1058
|
effects: [
|
|
995
1059
|
{
|
|
996
|
-
label: "Corners
|
|
997
|
-
properties: [
|
|
1060
|
+
label: "Corners",
|
|
1061
|
+
properties: [
|
|
1062
|
+
"borderRadius",
|
|
1063
|
+
"borderTopLeftRadius",
|
|
1064
|
+
"borderTopRightRadius",
|
|
1065
|
+
"borderBottomLeftRadius",
|
|
1066
|
+
"borderBottomRightRadius"
|
|
1067
|
+
],
|
|
998
1068
|
columns: 2,
|
|
999
|
-
prefixes: {
|
|
1069
|
+
prefixes: {
|
|
1070
|
+
borderRadius: "All",
|
|
1071
|
+
borderTopLeftRadius: "TL",
|
|
1072
|
+
borderTopRightRadius: "TR",
|
|
1073
|
+
borderBottomLeftRadius: "BL",
|
|
1074
|
+
borderBottomRightRadius: "BR"
|
|
1075
|
+
}
|
|
1000
1076
|
},
|
|
1001
|
-
{ label: "Stroke", properties: ["borderColor"] },
|
|
1077
|
+
{ label: "Stroke", properties: ["borderWidth", "borderColor"] },
|
|
1002
1078
|
{
|
|
1003
1079
|
label: "Effects",
|
|
1004
1080
|
properties: ["boxShadow", "filter"],
|
|
@@ -1021,70 +1097,71 @@ var CONTROL_SECTIONS = {
|
|
|
1021
1097
|
]
|
|
1022
1098
|
};
|
|
1023
1099
|
var PANEL_CSS = `
|
|
1100
|
+
${FOUNDRY_UI_FOUNDATION_CSS}
|
|
1024
1101
|
: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); }
|
|
1025
1102
|
*,*::before,*::after { box-sizing:border-box;font-family:inherit; }
|
|
1026
1103
|
button,select,input { font:inherit; }
|
|
1027
|
-
button:focus-visible,select:focus-visible,input:focus-visible { outline:
|
|
1028
|
-
.outline { position:fixed;z-index:2147483645;pointer-events:none;border:
|
|
1029
|
-
.measure { position:absolute;left:-
|
|
1030
|
-
.cross::before,.cross::after { content:"";position:absolute;background:var(--fdc-signal); }.cross::before { width:
|
|
1031
|
-
.panel { position:fixed;z-index:2147483646;top:12px;right:12px;width:
|
|
1104
|
+
button:focus-visible,select:focus-visible,input:focus-visible { outline:4px solid var(--fdc-signal);outline-offset:4px; }
|
|
1105
|
+
.outline { position:fixed;z-index:2147483645;pointer-events:none;border:1px 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; }
|
|
1106
|
+
.measure { position:absolute;left:-4px;top:-28px;height:24px;display:flex;align-items:center;padding:0 8px;color:white;background:var(--fdc-signal);border-radius:4px 4px 4px 0;font:650 12px/1 var(--fdc-font);letter-spacing:.02em;white-space:nowrap;box-shadow:0 4px 16px rgb(25 43 124 / 20%); }
|
|
1107
|
+
.cross::before,.cross::after { content:"";position:absolute;background:var(--fdc-signal); }.cross::before { width:12px;height:1px;left:-8px;top:-1px; }.cross::after { width:1px;height:12px;left:-1px;top:-8px; }
|
|
1108
|
+
.panel { position:fixed;z-index:2147483646;top:12px;right:12px;width:384px;min-width:340px;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 4px rgb(0 0 0 / 5%),0 12px 28px rgb(0 0 0 / 10%);pointer-events:auto;border-radius:12px; }
|
|
1032
1109
|
.top { flex:none;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }
|
|
1033
1110
|
.top-identity { position:relative;min-height:44px;display:flex;align-items:center;padding:0 12px; }
|
|
1034
1111
|
.brand { flex:1;display:flex;align-items:center;min-width:0; }
|
|
1035
|
-
.brand-copy { display:flex;align-items:baseline;gap:
|
|
1036
|
-
.session-status { flex:none;margin-left:8px;display:flex;align-items:center;gap:
|
|
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:
|
|
1038
|
-
.selection { position:relative;padding:
|
|
1039
|
-
.scope { display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:12px
|
|
1040
|
-
.tool-shelf { position:fixed;z-index:2147483646;left:50%;bottom:
|
|
1041
|
-
.tool-select,.tab { position:relative;flex:none;width:36px;height:36px;display:grid;place-items:center;padding:0;border:0;border-radius:
|
|
1042
|
-
.controls { min-height:
|
|
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:
|
|
1044
|
-
.motion-timeline { width:100%;margin:
|
|
1045
|
-
.empty { padding:48px 28px;text-align:center;color:var(--fdc-muted);font-size:
|
|
1046
|
-
.change-dock { min-height:48px;display:grid;grid-template-columns:minmax(0,1fr)
|
|
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
|
|
1048
|
-
.toast { position:fixed;left:50%;bottom:76px;transform:translate(-50%,8px);padding:
|
|
1049
|
-
.resize-handle { position:absolute;width:
|
|
1050
|
-
.resize-handle[data-handle="n"]{top:-
|
|
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:
|
|
1052
|
-
.canvas-variant { position:fixed;z-index:2147483645;height:
|
|
1053
|
-
.onboarding-card { position:fixed;z-index:2147483647;left:50%;bottom:
|
|
1054
|
-
.review-details { margin-top:
|
|
1112
|
+
.brand-copy { display:flex;align-items:baseline;gap:4px; }.brand-copy b { font-size:12px;line-height:1;font-weight:550;letter-spacing:-.02em; }.brand-copy span { color:var(--fdc-muted);font:400 12px/1 var(--fdc-font); }
|
|
1113
|
+
.session-status { flex:none;margin-left:8px;display:flex;align-items:center;gap:4px;padding:4px 8px;border:0;color:#236c59;background:#eef8f4;border-radius:1000px;font:500 12px/1 var(--fdc-font);cursor:pointer; }.session-status i { width:4px;height:4px;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:40px;right:40px;width:240px;padding:12px;border:1px solid var(--fdc-line);border-radius:8px;background:white;box-shadow:0 12px 28px rgb(0 0 0 / 14%); }.status-popover[hidden] { display:none; }.status-popover strong { display:block;font-size:12px;font-weight:550; }.status-popover span,.status-popover code { display:block;margin-top:4px;overflow:hidden;text-overflow:ellipsis;color:var(--fdc-muted);font:400 8px/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:4px;background:white;color:var(--fdc-ink);font-size:8px;cursor:pointer; }
|
|
1114
|
+
.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:8px;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; }
|
|
1115
|
+
.selection { position:relative;padding:16px;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }.selection::before { content:"";position:absolute;top:12px;left:0;width:4px;height:0;background:var(--fdc-signal);border-radius:0 4px 4px 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:8px; }.selection-kind { max-width:220px;overflow:hidden;text-overflow:ellipsis;padding:4px 8px;color:#4d4d4d;background:var(--fdc-subtle);border-radius:4px;font:500 12px/1 var(--fdc-font);text-transform:uppercase;letter-spacing:.025em;white-space:nowrap; }.selection-state { color:var(--fdc-muted);font:450 12px/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:4px;overflow:hidden;text-overflow:ellipsis;color:var(--fdc-muted);font:400 12px/1.45 var(--fdc-font);white-space:nowrap; }.selection-hint { display:block;margin-top:8px;color:#858585;font:400 12px/1.45 var(--fdc-font); }.selection-stats { display:flex;gap:4px;margin-top:12px; }.selection-stats[hidden] { display:none; }.selection-stats span { padding:4px 8px;color:#4d4d4d;background:var(--fdc-subtle);border-radius:4px;font:400 12px/1 var(--fdc-font); }.selection-stats span:first-child { color:#0761d1;background:#edf6ff; }.selection.selected-flash strong { animation:fdc-selection-title .2s ease-out; }
|
|
1116
|
+
.scope { display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:12px 16px;background:var(--fdc-surface);border-bottom:1px solid var(--fdc-line); }.scope label { display:flex;flex-direction:column;gap:8px;color:var(--fdc-muted);font:500 12px/1.2 var(--fdc-font); }.scope select { width:100%;height:36px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:8px;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; }
|
|
1117
|
+
.tool-shelf { position:fixed;z-index:2147483646;left:50%;bottom:20px;transform:translateX(-50%);display:flex;align-items:center;gap:8px;max-width:calc(100vw - 32px);padding:8px;background:var(--fdc-surface);border:1px solid var(--fdc-line);border-radius:12px;box-shadow:0 4px 4px 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:4px;padding:0 8px 0 1px; }.mode-copy strong { font-size:12px;font-weight:550;line-height:1.1; }.mode-copy span { color:var(--fdc-muted);font-size:8px;line-height:1.2;white-space:nowrap; }
|
|
1118
|
+
.tool-select,.tab { position:relative;flex:none;width:36px;height:36px;display:grid;place-items:center;padding:0;border:0;border-radius:8px;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,.icon-button svg { width:20px;height:20px;pointer-events:none; }.tab 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%,4px);padding:8px 8px;border-radius:4px;background:var(--fdc-ink);color:white;font:400 12px/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:4px;overflow:visible;scrollbar-width:none; }.tab:disabled { color:#a1a1a1;cursor:default; }.tab:disabled:hover { background:transparent; }
|
|
1119
|
+
.controls { min-height:212px;overflow:auto;background:var(--fdc-surface); }.inspector-heading { position:sticky;top:0;z-index:1;height:44px;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:16px;height:16px;color:#4d4d4d; }.inspector-heading strong { font-size:12px;font-weight:550; }.property-count { margin-left:auto;color:var(--fdc-muted);font:400 12px/1 var(--fdc-font);letter-spacing:.01em; }.property-section { padding:0;border-bottom:1px solid var(--fdc-line); }.section-head { width:100%;min-height:40px;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:40px;flex:1;display:flex;align-items:center;gap:8px;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:12px;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:8px; }.property-control { display:grid;grid-template-columns:minmax(0,1fr) 132px 24px;align-items:center;gap:8px;min-height:36px; }.property-label { overflow:hidden;text-overflow:ellipsis;color:#4d4d4d;font-size:12px;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:4px;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 4px 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:4px;align-items:center; }.compact-control .control-field { width:100%; }.field-prefix { min-width:28px;padding-left:8px;color:#7a7a7a;font:400 12px/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:32px;padding:0 8px;border:0;background:transparent;color:var(--fdc-ink);font:400 12px/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 4px;color:#707070;font-size:8px;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:16px;height:16px;flex:none;margin-left:8px;border:1px solid rgb(0 0 0 / 10%);border-radius:4px;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:8px;color:#4d4d4d;font:400 12px/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:8px;color:#7a7a7a;font:400 12px/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; }
|
|
1120
|
+
.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:8px;font-size:12px;font-weight:550; }.motion-title code { color:var(--fdc-muted);font:400 12px/1.3 var(--fdc-font); }.motion-actions { display:grid;grid-template-columns:repeat(4,1fr);gap:4px; }.motion-actions button { min-height:32px;padding:0 4px;border:1px solid var(--fdc-line);background:var(--fdc-paper);border-radius:4px;color:var(--fdc-ink);font-size:12px;font-weight:400;cursor:pointer; }.motion-actions button:hover { border-color:#c7c7c7;background:var(--fdc-surface); }
|
|
1121
|
+
.motion-timeline { width:100%;margin:4px 0 12px;accent-color:var(--fdc-signal); }.motion-fields { display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px; }.motion-fields label { display:grid;grid-template-columns:auto 1fr;align-items:center;gap:4px;color:var(--fdc-muted);font-size:8px; }.motion-fields input { width:100%;height:28px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:var(--fdc-paper);color:var(--fdc-ink);font-size:12px; }
|
|
1122
|
+
.empty { padding:48px 28px;text-align:center;color:var(--fdc-muted);font-size:12px;line-height:1.6; }.empty::before { content:"\u2316";display:grid;place-items:center;width:40px;height:40px;margin:0 auto 12px;color:var(--fdc-signal);background:var(--fdc-signal-soft);border-radius:12px;font:20px/1 var(--fdc-font); }
|
|
1123
|
+
.change-dock { min-height:48px;display:grid;grid-template-columns:minmax(0,1fr) 32px 68px;align-items:center;gap:8px;padding:8px 8px;border-top:1px solid var(--fdc-line);background:white; }.change-dock[hidden] { display:none; }.change-dock-copy { min-width:0;padding-left:4px; }.change-dock-copy strong,.change-dock-copy span { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }.change-dock-copy strong { font-size:12px;font-weight:550; }.change-dock-copy span { margin-top:4px;color:var(--fdc-muted);font-size:8px; }.change-dock button { height:32px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:var(--fdc-ink);font-size:8px;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:84px 1fr;gap:8px;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:8px;background:var(--fdc-surface);color:var(--fdc-ink);font-size:12px;font-weight:450;cursor:pointer; }.footer button:hover { border-color:#d0d0d0;background:var(--fdc-paper); }.footer .review { align-items:center;justify-content:center;gap:8px;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:20px;height:20px;display:inline-grid;place-items:center;padding:0 4px;color:var(--fdc-ink);background:white;border-radius:1000px;font:500 8px/1 var(--fdc-font); }.change-count[hidden] { display:none; }
|
|
1124
|
+
.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 12px;border-bottom:1px solid var(--fdc-line); }.review-head button { width:32px;height:32px;display:grid;place-items:center;padding:0;border:0;border-radius:4px;background:transparent;color:var(--fdc-muted);cursor:pointer; }.review-head button:hover { background:var(--fdc-subtle);color:var(--fdc-ink); }.review-head svg { width:16px;height:16px; }.review-head strong { font-size:12px;font-weight:550; }.review-head span { margin-left:auto;color:var(--fdc-muted);font-size:12px; }.review-body { min-height:160px;overflow-x:hidden;overflow-y:auto; }.review-toolbar { position:sticky;top:0;z-index:1;display:flex;gap:4px;padding:8px 8px;border-bottom:1px solid var(--fdc-line);background:rgb(255 255 255 / 96%);backdrop-filter:blur(8px); }.review-toolbar button { height:28px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#555;font-size:8px;cursor:pointer; }.review-toolbar button:last-child { margin-left:auto; }.review-empty { padding:44px 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:8px;padding:0 12px;border:0;background:white;color:var(--fdc-muted);font-size:12px;font-weight:500;text-align:left;cursor:pointer; }.review-group-title span { margin-left:auto;font-size:8px; }.review-group-title svg { width:12px;height:12px;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:20px minmax(0,1fr);gap:8px;padding:8px 12px 12px; }.review-card.rejected { opacity:.62; }.review-card+.review-card { border-top:1px solid var(--fdc-line); }.review-card input[type="checkbox"] { width:16px;height:16px;margin:4px 0 0;accent-color:var(--fdc-ink); }.review-card-main { min-width:0; }.review-card-line { display:flex;align-items:center;gap:8px; }.review-card-line strong { min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:12px;font-weight:500;white-space:nowrap; }.review-card-tools { display:flex;gap:4px;margin-left:auto; }.review-card-tools button { height:24px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#666;font-size:8px;cursor:pointer; }.confidence-pill { flex:none;padding:4px 4px;border-radius:4px;background:#edf6ff;color:#0761d1;font-size:8px;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:8px; }.review-before { overflow:hidden;text-overflow:ellipsis;padding:8px;color:var(--fdc-muted);background:var(--fdc-subtle);border-radius:4px;font-size:12px;white-space:nowrap; }.review-values>span { color:var(--fdc-muted);font-size:12px;text-align:center; }.review-after { width:100%;height:28px;min-width:0;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;font-size:12px;outline:none; }.review-after:focus { border-color:var(--fdc-signal);box-shadow:0 0 0 4px rgb(0 112 243 / 10%); }.review-source { margin-top:8px;overflow-wrap:anywhere;color:var(--fdc-muted);font-size:8px;line-height:1.45; }.review-actions { display:grid;grid-template-columns:84px 1fr;gap:8px;padding:8px;border-top:1px solid var(--fdc-line); }.review-actions button { min-height:36px;border:1px solid var(--fdc-line);border-radius:8px;background:white;font-size:12px;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:16px 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:12px;line-height:1.5; }.run-steps { padding:4px 12px 12px; }.run-step { display:grid;grid-template-columns:20px minmax(0,1fr);gap:8px;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:12px; }.run-step strong { display:block;font-size:12px;font-weight:500;text-transform:capitalize; }.run-step p { margin:4px 0 0;color:var(--fdc-muted);font-size:8px;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:12px; }.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:8px;line-height:1.5; }.run-files code { display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
|
|
1125
|
+
.toast { position:fixed;left:50%;bottom:76px;transform:translate(-50%,8px);padding:8px 12px;background:var(--fdc-ink);color:white;border-radius:8px;font-size:12px;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); }
|
|
1126
|
+
.resize-handle { position:absolute;width:8px;height:8px;min-width:8px;min-height:8px;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; }
|
|
1127
|
+
.resize-handle[data-handle="n"]{top:-4px;left:calc(50% - 4px);cursor:ns-resize}.resize-handle[data-handle="s"]{bottom:-4px;left:calc(50% - 4px);cursor:ns-resize}.resize-handle[data-handle="e"]{right:-4px;top:calc(50% - 4px);cursor:ew-resize}.resize-handle[data-handle="w"]{left:-4px;top:calc(50% - 4px);cursor:ew-resize}.resize-handle[data-handle="ne"]{right:-4px;top:-4px;cursor:nesw-resize}.resize-handle[data-handle="nw"]{left:-4px;top:-4px;cursor:nwse-resize}.resize-handle[data-handle="se"]{right:-4px;bottom:-4px;cursor:nwse-resize}.resize-handle[data-handle="sw"]{left:-4px;bottom:-4px;cursor:nesw-resize}
|
|
1128
|
+
.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:4px;width:4px;height:28px;transform:translateY(-50%);border-radius:4px;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:8px;left:8px;width:12px;height:12px;min-width:12px;min-height:12px;aspect-ratio:1;padding:0;border:4px 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; }
|
|
1129
|
+
.canvas-variant { position:fixed;z-index:2147483645;height:28px;max-width:180px;padding:0 24px 0 8px;border:1px solid #b8d5ff;border-radius:8px;background:white;color:#075fc5;font-size:8px;box-shadow:0 4px 16px rgb(0 0 0 / 10%);pointer-events:auto; }.canvas-variant[hidden] { display:none; }
|
|
1130
|
+
.onboarding-card { position:fixed;z-index:2147483647;left:50%;bottom:80px;width:288px;transform:translateX(-50%);padding:12px;border:1px solid var(--fdc-line);border-radius:12px;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:16px;height:16px;color:var(--fdc-signal); }.onboarding-card-head strong { font-size:12px;font-weight:550; }.onboarding-card p { margin:8px 0 12px;color:var(--fdc-muted);font-size:12px;line-height:1.5; }.onboarding-steps { display:grid;grid-template-columns:repeat(3,1fr);gap:4px; }.onboarding-steps span { padding:8px 4px;border:1px solid var(--fdc-line);border-radius:8px;color:#555;font-size:8px;line-height:1.35;text-align:center; }.onboarding-actions { display:flex;justify-content:flex-end;gap:4px;margin-top:12px; }.onboarding-actions button { height:28px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;font-size:8px;cursor:pointer; }.onboarding-actions .onboarding-start { color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }
|
|
1131
|
+
.review-details { margin-top:8px;color:var(--fdc-muted);font-size:8px; }.review-details summary { cursor:pointer;user-select:none; }.review-details[open] summary { margin-bottom:4px; }.review-details .review-source { display:block; }.review-details .impact-list { display:grid;gap:4px;margin-top:4px; }
|
|
1055
1132
|
@keyframes fdc-pulse { 50% { opacity:.35; } }
|
|
1056
1133
|
@media (prefers-reduced-motion:reduce){.session-status i,.section-head>svg,.toast,.tool-select::after,.tab::after{animation:none!important;transition:none!important}}
|
|
1057
1134
|
.multi-outline { position:fixed;z-index:2147483644;border:1px dashed var(--fdc-signal);background:rgb(0 112 243 / 4%);pointer-events:none; }
|
|
1058
1135
|
.hover-outline { position:fixed;z-index:2147483643;border:1px solid rgb(0 112 243 / 62%);background:rgb(0 112 243 / 4%);pointer-events:none; }
|
|
1059
|
-
.hover-outline::after { content:attr(data-label);position:absolute;left:-1px;top:-1px;transform:translateY(-100%);max-width:180px;padding:4px
|
|
1136
|
+
.hover-outline::after { content:attr(data-label);position:absolute;left:-1px;top:-1px;transform:translateY(-100%);max-width:180px;padding:4px 8px;border-radius:4px 4px 4px 0;background:#0070f3;color:white;font:500 12px/1.2 var(--fdc-font);overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
|
|
1060
1137
|
.snap-guide { position:fixed;z-index:2147483644;pointer-events:none;background:#ff4d8d;box-shadow:0 0 0 1px rgb(255 255 255 / 80%); }.snap-guide.vertical { width:1px;top:0;bottom:0; }.snap-guide.horizontal { height:1px;left:0;right:0; }
|
|
1061
|
-
.spacing-guide { position:fixed;z-index:2147483644;pointer-events:auto;background:#ff4d8d; }.spacing-guide.horizontal { height:1px;cursor:ew-resize; }.spacing-guide.vertical { width:1px;cursor:ns-resize; }.spacing-guide span { position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);padding:
|
|
1062
|
-
.selection-path { display:flex;align-items:center;gap:4px;margin-top:
|
|
1138
|
+
.spacing-guide { position:fixed;z-index:2147483644;pointer-events:auto;background:#ff4d8d; }.spacing-guide.horizontal { height:1px;cursor:ew-resize; }.spacing-guide.vertical { width:1px;cursor:ns-resize; }.spacing-guide span { position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);padding:4px 4px;border-radius:4px;background:#ff4d8d;color:white;font:600 8px/1 var(--fdc-font);white-space:nowrap; }
|
|
1139
|
+
.selection-path { display:flex;align-items:center;gap:4px;margin-top:8px;min-width:0; }.selection-path button { min-width:0;height:24px;display:flex;align-items:center;gap:4px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:var(--fdc-paper);color:#555;font-size:8px;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:12px;height:12px; }.selection-path .path-name { flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }
|
|
1063
1140
|
.selection-path[hidden] { display:none; }
|
|
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:
|
|
1065
|
-
.layers-switch { display:grid;grid-template-columns:1fr 1fr;gap:
|
|
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
|
|
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:
|
|
1141
|
+
.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:12px;background:var(--fdc-surface);box-shadow:0 1px 4px rgb(0 0 0 / 5%),0 12px 28px rgb(0 0 0 / 10%);pointer-events:auto; }.layers-panel[hidden] { display:none; }.layers-head { min-height:44px;display:flex;flex:none;align-items:center;gap:8px;padding:0 8px 0 12px;border-bottom:1px solid var(--fdc-line); }.layers-head svg { width:16px;height:16px; }.layers-head strong { font-size:12px;font-weight:550; }.layers-head span { color:var(--fdc-muted);font-size:8px; }.layers-head .icon-button { margin-left:auto; }.layers-search { flex:none;padding:8px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.layers-search input { width:100%;height:32px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:var(--fdc-ink);font-size:12px;outline:none; }.layers-search input:focus { border-color:var(--fdc-signal);box-shadow:0 0 0 4px rgb(0 112 243 / 10%); }.layer-tree { min-height:120px;overflow:auto;padding:4px; }.layer-row { width:100%;height:32px;display:grid;grid-template-columns:16px 16px minmax(0,1fr) auto;align-items:center;gap:4px;padding:0 8px 0 calc(8px + var(--layer-depth) * 12px);border:0;border-radius:4px;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:12px;white-space:nowrap; }.layer-row .layer-meta { padding:4px 4px;border-radius:4px;background:#f0f0f0;color:#747474;font-size:8px;text-transform:uppercase; }.layer-row.selected .layer-meta { color:#075fc5;background:#d8e9ff; }.layers-empty { padding:36px 20px;color:var(--fdc-muted);font-size:12px;line-height:1.5;text-align:center; }
|
|
1142
|
+
.layers-switch { display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:4px;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:8px;padding:0 8px;border:0;border-radius:4px;background:transparent;color:var(--fdc-muted);font-size:12px;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 4px rgb(0 0 0 / 5%); }.layers-switch button span { min-width:16px;height:16px;display:grid;place-items:center;padding:0 4px;border-radius:1000px;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:4px;padding:4px; }.component-card { overflow:hidden;border:1px solid var(--fdc-line);border-radius:8px;background:white; }.component-card:hover { border-color:#d7d0f3;box-shadow:0 4px 8px rgb(52 38 110 / 6%); }.component-card.selected { border-color:#c8bdf1;background:#fbfaff;box-shadow:0 0 0 4px rgb(114 87 217 / 8%); }.component-main { width:100%;min-height:52px;display:grid;grid-template-columns:32px minmax(0,1fr) auto;align-items:center;gap:8px;padding:8px 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:8px;color:var(--fdc-component);background:var(--fdc-component-soft); }.component-mark svg { width:16px;height:16px; }.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:12px;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:4px 4px;border-radius:1000px;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 44px; }.component-variants span { max-width:88px;overflow:hidden;text-overflow:ellipsis;padding:4px 4px;border:1px solid #e6e1f7;border-radius:4px;color:#66598c;background:#faf9ff;font-size:8px;white-space:nowrap; }
|
|
1143
|
+
.layer-tree { position:relative;scrollbar-gutter:stable; }.layer-selection-glide { position:absolute;z-index:0;top:0;right:4px;left:4px;height:32px;border:1px solid rgb(72 132 220 / 22%);border-radius:8px;background:var(--fdc-signal-soft);transform:translateY(var(--layer-glide-y));transition:transform .24s cubic-bezier(.16,1,.3,1),height .18s cubic-bezier(.16,1,.3,1);pointer-events:none; }.layer-row { position:relative;z-index:1;grid-template-columns:16px minmax(0,1fr);gap:1px;padding-right:4px;cursor:default; }.layer-row.entering { animation:layer-row-enter .22s cubic-bezier(.16,1,.3,1) both;animation-delay:min(calc(var(--layer-position) * 18ms),90ms); }.layer-row.selected { background:transparent; }.layer-row.dragging { opacity:.45; }.layer-row.drop-target { box-shadow:inset 0 4px 0 var(--fdc-signal); }.layer-branch { position:absolute;z-index:-1;top:-1px;bottom:-1px;left:var(--layer-branch-left);width:1px;background:var(--fdc-line);transform-origin:top;animation:layer-branch-draw .28s cubic-bezier(.16,1,.3,1) both;pointer-events:none; }.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;transition:color .16s ease; }.layer-toggle:hover { color:var(--fdc-ink); }.layer-toggle:disabled { visibility:hidden; }.layer-toggle svg { width:12px;height:12px;transition:transform .24s cubic-bezier(.16,1,.3,1); }.layer-select { min-width:0;height:28px;display:grid;grid-template-columns:16px minmax(0,1fr) auto;align-items:center;gap:4px;padding:0 4px;border:0;border-radius:4px;background:transparent;color:inherit;text-align:left;cursor:pointer;outline:none; }.layer-select:focus-visible { box-shadow:inset 0 0 0 1px var(--fdc-signal); }.layer-select:active .layer-icon { transform:scale(.88); }.layer-icon { transition:color .16s ease,transform .16s cubic-bezier(.16,1,.3,1); }@keyframes layer-row-enter { from { opacity:0;transform:translateY(-4px); } to { opacity:1;transform:translateY(0); } }@keyframes layer-branch-draw { from { opacity:0;transform:scaleY(0); } to { opacity:1;transform:scaleY(1); } }
|
|
1144
|
+
.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:12px;background:var(--fdc-surface);box-shadow:0 1px 4px rgb(0 0 0 / 5%),0 12px 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:16px;height:16px; }.health-head strong { font-size:12px;font-weight:550; }.health-head .icon-button { margin-left:auto; }.health-summary { display:grid;grid-template-columns:56px minmax(0,1fr);gap:12px;padding:12px;border-bottom:1px solid var(--fdc-line); }.health-score { width:56px;height:56px;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:44px;height:44px;border-radius:50%;background:white; }.health-score strong { z-index:1;grid-area:1/1;font-size:16px;font-weight:600; }.health-summary-copy { min-width:0;align-self:center; }.health-summary-copy strong { display:block;font-size:12px;font-weight:550; }.health-summary-copy span { display:block;margin-top:4px;color:var(--fdc-muted);font-size:8px;line-height:1.4; }.health-filters { display:flex;gap:4px;padding:8px 8px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.health-filters button { min-height:28px;padding:0 8px;border:1px solid transparent;border-radius:4px;background:transparent;color:#666;font-size:8px;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:8px; }.health-card { padding:12px;border:1px solid var(--fdc-line);border-radius:8px;background:white; }.health-card+.health-card { margin-top:8px; }.health-card-top { display:flex;align-items:center;gap:8px; }.health-severity { width:8px;height:8px;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:12px;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:8px 0 0;color:#5d5d5d;font-size:8px;line-height:1.45; }.health-evidence { margin-top:8px;padding:8px;border-radius:4px;background:var(--fdc-paper);color:#777;font-size:8px;line-height:1.4; }.health-actions { display:flex;gap:4px;margin-top:8px; }.health-actions button { min-height:28px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#555;font-size:8px;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 8px;color:#888;border-color:transparent; }.health-footer { display:flex;align-items:center;gap:4px;padding:8px;border-top:1px solid var(--fdc-line); }.health-footer button { min-height:32px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#555;font-size:8px;cursor:pointer; }.health-footer .health-rescan { flex:1;color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }.health-empty { padding:36px 20px;text-align:center;color:var(--fdc-muted);font-size:12px;line-height:1.5; }.health-empty svg { display:block;width:24px;height:24px;margin:0 auto 12px;color:#2b9a76; }
|
|
1068
1145
|
.tool-select:disabled { color:#b6b6b6;cursor:default; }.tool-select:disabled:hover { background:transparent; }
|
|
1069
|
-
.token-row { grid-column:2;display:flex;flex-wrap:wrap;gap:
|
|
1070
|
-
.section-head .section-action { width:24px;height:24px;display:grid;place-items:center;margin-left:auto;padding:0;border:0;border-radius:4px;background:transparent;color:var(--fdc-muted);cursor:pointer; }.section-head .section-action:hover,.section-head .section-action.active { color:var(--fdc-signal);background:#edf6ff; }.section-head .section-action svg { width:
|
|
1071
|
-
.context-tools { display:flex;flex-wrap:wrap;gap:
|
|
1072
|
-
.native-panel { padding:
|
|
1073
|
-
.variant-list { display:grid;gap:
|
|
1074
|
-
.compare-bar { position:fixed;z-index:2147483646;left:50%;bottom:
|
|
1075
|
-
.command-palette { position:fixed;z-index:2147483647;left:50%;top:18%;transform:translateX(-50%);width:min(480px,calc(100vw - 32px));overflow:hidden;border:1px solid #d8d8d8;border-radius:
|
|
1076
|
-
.comparison-stage { position:fixed;z-index:2147483647;inset:
|
|
1077
|
-
.impact-list { display:grid;gap:4px;margin-top:
|
|
1078
|
-
.mapping-chooser { grid-column:2;margin-top:
|
|
1079
|
-
.workbench { position:fixed;z-index:2147483647;inset:
|
|
1080
|
-
.library-panel { position:fixed;z-index:2147483647;top:12px;right:352px;width:300px;max-height:calc(100vh - 24px);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--fdc-line);border-radius:
|
|
1081
|
-
.review-visual { display:grid;grid-template-columns:1fr 1fr;gap:
|
|
1082
|
-
.workbench-matrix { display:grid;grid-template-columns:92px repeat(var(--matrix-columns),minmax(
|
|
1083
|
-
.component-actions { display:flex;gap:4px;padding:0 8px 8px
|
|
1084
|
-
.token-provenance { grid-column:2;display:flex;align-items:center;gap:
|
|
1146
|
+
.token-row { grid-column:2;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px; }.token-chip { height:24px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:1000px;background:var(--fdc-paper);color:#4d4d4d;font-size:8px;cursor:pointer; }.token-chip:hover { border-color:#b7d5ff;color:#0761d1;background:#edf6ff; }
|
|
1147
|
+
.section-head .section-action { width:24px;height:24px;display:grid;place-items:center;margin-left:auto;padding:0;border:0;border-radius:4px;background:transparent;color:var(--fdc-muted);cursor:pointer; }.section-head .section-action:hover,.section-head .section-action.active { color:var(--fdc-signal);background:#edf6ff; }.section-head .section-action svg { width:12px;height:12px; }
|
|
1148
|
+
.context-tools { display:flex;flex-wrap:wrap;gap:4px;padding:8px 12px;border-bottom:1px solid var(--fdc-line);background:var(--fdc-surface); }.context-tools button { min-height:28px;display:flex;align-items:center;gap:4px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#4d4d4d;font-size:8px;cursor:pointer; }.context-tools button:hover { border-color:#c8c8c8;color:var(--fdc-ink); }.context-tools button.active { color:#075fc5;border-color:#bad7ff;background:#edf6ff; }.context-tools svg { width:12px;height:12px; }
|
|
1149
|
+
.native-panel { padding:12px 12px;border-bottom:1px solid var(--fdc-line); }.native-panel-head { display:flex;align-items:center;margin-bottom:8px; }.native-panel-head strong { font-size:12px;font-weight:550; }.native-panel-head span { margin-left:auto;color:var(--fdc-muted);font-size:8px; }.native-search { width:100%;height:28px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:var(--fdc-paper);font-size:8px;outline:none; }.native-search:focus { border-color:var(--fdc-signal); }.native-grid { display:flex;flex-wrap:wrap;gap:4px;margin-top:8px; }.native-chip { min-height:28px;display:flex;align-items:center;gap:4px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#4d4d4d;font-size:8px;cursor:pointer; }.native-chip:hover { border-color:#bdd7fb;background:#f5f9ff; }.native-chip .swatch { width:12px;height:12px;border:1px solid rgb(0 0 0 / 10%);border-radius:4px;background:var(--token-color); }.design-health { display:flex;align-items:center;gap:8px;margin-top:8px;padding:8px 8px;border-radius:4px;background:#f3f3f3;color:#575757;font-size:8px; }.design-health.pass { color:#23715c;background:#edf8f4; }.design-health.fail { color:#9a4930;background:#fff0e9; }.design-health svg { width:12px;height:12px; }
|
|
1150
|
+
.variant-list { display:grid;gap:4px;margin-top:8px; }.variant-button { min-height:32px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;font-size:8px;cursor:pointer; }.variant-button code { overflow:hidden;text-overflow:ellipsis;color:var(--fdc-muted);font-size:8px;white-space:nowrap; }
|
|
1151
|
+
.compare-bar { position:fixed;z-index:2147483646;left:50%;bottom:80px;transform:translateX(-50%);display:flex;align-items:center;gap:4px;padding:8px;border:1px solid var(--fdc-line);border-radius:8px;background:white;box-shadow:0 8px 24px rgb(0 0 0 / 14%);pointer-events:auto; }.compare-bar[hidden] { display:none; }.compare-bar strong { padding:0 8px;font-size:12px;font-weight:550; }.compare-bar button { height:32px;display:flex;align-items:center;gap:4px;padding:0 8px;border:0;border-radius:4px;background:transparent;color:#555;font-size:8px;cursor:pointer; }.compare-bar button:hover,.compare-bar button.active { color:white;background:var(--fdc-ink); }.compare-bar svg { width:12px;height:12px; }.compare-bar input[type="range"] { width:96px;accent-color:var(--fdc-ink);cursor:ew-resize; }
|
|
1152
|
+
.command-palette { position:fixed;z-index:2147483647;left:50%;top:18%;transform:translateX(-50%);width:min(480px,calc(100vw - 32px));overflow:hidden;border:1px solid #d8d8d8;border-radius:12px;background:white;box-shadow:0 24px 80px rgb(0 0 0 / 24%);pointer-events:auto; }.command-palette[hidden] { display:none; }.command-search { display:flex;align-items:center;border-bottom:1px solid var(--fdc-line);background:var(--fdc-paper); }.command-palette input { min-width:0;flex:1;width:auto;height:48px;padding:0 16px;border:0;font-size:12px;outline:none; }.command-search .icon-button { flex:none;margin-right:8px; }.command-list { max-height:320px;overflow:auto;padding:4px; }.command-item { width:100%;min-height:40px;display:flex;align-items:center;gap:8px;padding:0 12px;border:0;border-radius:8px;background:transparent;color:#333;text-align:left;font-size:12px;cursor:pointer; }.command-item:hover,.command-item.active { background:var(--fdc-subtle); }.command-item svg { width:16px;height:16px;color:#777; }.command-item small { margin-left:auto;color:#8a8a8a;font-size:8px; }
|
|
1153
|
+
.comparison-stage { position:fixed;z-index:2147483647;inset:12px;display:flex;flex-direction:column;overflow:hidden;border:1px solid #303030;border-radius:12px;background:#111;box-shadow:0 24px 80px rgb(0 0 0 / 35%);pointer-events:auto; }.comparison-stage[hidden] { display:none; }.comparison-stage header { min-height:48px;display:flex;align-items:center;padding:0 8px 0 16px;color:white;border-bottom:1px solid #292929;background:#171717; }.comparison-stage header strong { font-size:12px;font-weight:550; }.comparison-stage header span { margin-left:8px;color:#8d8d8d;font-size:12px; }.comparison-stage header button { width:32px;height:32px;display:grid;place-items:center;margin-left:auto;padding:0;border:0;border-radius:4px;background:transparent;color:#aaa;cursor:pointer; }.comparison-stage header button:hover { color:white;background:#292929; }.comparison-stage header svg { width:16px;height:16px; }.comparison-frames { min-height:0;flex:1;display:grid;grid-template-columns:1fr 1fr;gap:1px;background:#343434; }.comparison-frame { position:relative;min-width:0;min-height:0;background:white; }.comparison-frame span { position:absolute;z-index:1;top:12px;left:12px;padding:4px 8px;border-radius:4px;background:rgb(17 17 17 / 88%);color:white;font-size:8px; }.comparison-frame iframe { width:100%;height:100%;display:block;border:0;background:white; }
|
|
1154
|
+
.impact-list { display:grid;gap:4px;margin-top:8px; }.impact-item { display:flex;align-items:flex-start;gap:4px;color:#666;font-size:8px;line-height:1.35; }.impact-item::before { content:"";width:4px;height:4px;flex:none;margin-top:4px;border-radius:50%;background:#9a9a9a; }.impact-item.warning { color:#985033; }.impact-item.warning::before { background:#d16d51; }
|
|
1155
|
+
.mapping-chooser { grid-column:2;margin-top:8px;padding:8px;background:#fff9ed;border:1px solid #f4ddb2;border-radius:8px; }.mapping-chooser>strong { display:block;margin-bottom:4px;color:#80561c;font-size:8px;font-weight:550; }.mapping-option { display:flex;align-items:flex-start;gap:8px;padding:4px 0;color:#5f4b2d;font-size:8px;line-height:1.35;cursor:pointer; }.mapping-option input { margin:1px 0 0;accent-color:var(--fdc-signal); }.mapping-option small { display:block;color:#8b7758;font-size:8px; }
|
|
1156
|
+
.workbench { position:fixed;z-index:2147483647;inset:12px;display:flex;flex-direction:column;overflow:hidden;border:1px solid #303030;border-radius:12px;background:#111;box-shadow:0 24px 80px rgb(0 0 0 / 35%);pointer-events:auto; }.workbench[hidden] { display:none; }.workbench-head { min-height:48px;display:flex;align-items:center;gap:8px;padding:0 8px 0 16px;color:white;border-bottom:1px solid #292929;background:#171717; }.workbench-head strong { font-size:12px;font-weight:550; }.workbench-context { color:#8d8d8d;font-size:12px; }.workbench-controls { display:flex;align-items:center;gap:4px;margin-left:auto; }.workbench-controls button,.workbench-controls select { height:32px;padding:0 8px;border:1px solid #343434;border-radius:8px;background:#202020;color:#d7d7d7;font-size:12px;cursor:pointer; }.workbench-controls button.active { color:#111;background:white;border-color:white; }.workbench-controls .icon-button { width:32px;padding:0; }.workbench-stage { min-height:0;flex:1;display:flex;align-items:flex-start;justify-content:center;overflow:auto;padding:28px;background-color:#151515;background-image:linear-gradient(#202020 1px,transparent 1px),linear-gradient(90deg,#202020 1px,transparent 1px);background-size:24px 24px; }.frame-shell { position:relative;flex:none;border-radius:8px;background:white;box-shadow:0 0 0 1px #333,0 20px 60px rgb(0 0 0 / 35%);overflow:hidden; }.frame-label { position:absolute;left:0;top:-20px;color:#8f8f8f;font-size:8px; }.frame-shell iframe { display:block;width:100%;height:100%;border:0;background:white; }.workbench-warning { position:absolute;left:50%;bottom:20px;transform:translateX(-50%);max-width:520px;padding:8px 12px;border:1px solid #3b3b3b;border-radius:8px;background:#1d1d1d;color:#aaa;font-size:12px;line-height:1.4; }
|
|
1157
|
+
.library-panel { position:fixed;z-index:2147483647;top:12px;right:352px;width:300px;max-height:calc(100vh - 24px);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--fdc-line);border-radius:12px;background:white;box-shadow:0 12px 32px rgb(0 0 0 / 14%);pointer-events:auto; }.library-panel[hidden] { display:none; }.library-head { min-height:48px;display:flex;align-items:center;gap:8px;padding:0 8px 0 12px;border-bottom:1px solid var(--fdc-line); }.library-head svg { width:16px;height:16px; }.library-head strong { font-size:12px;font-weight:550; }.library-head span { color:var(--fdc-muted);font-size:8px; }.library-head .icon-button { margin-left:auto; }.library-actions { display:flex;gap:4px;padding:8px;border-bottom:1px solid var(--fdc-line); }.library-actions button { min-height:32px;display:flex;align-items:center;justify-content:center;gap:8px;flex:1;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#4d4d4d;font-size:8px;cursor:pointer; }.library-actions button:disabled { opacity:.45;cursor:not-allowed; }.library-actions svg { width:12px;height:12px; }.library-body { min-height:120px;overflow:auto;padding:8px; }.library-section+.library-section { margin-top:12px; }.library-section-head { display:flex;align-items:center;margin:0 4px 8px;color:#666;font-size:8px;text-transform:uppercase;letter-spacing:.04em; }.library-section-head span { margin-left:auto;text-transform:none;letter-spacing:0; }.memory-card { padding:8px;border:1px solid var(--fdc-line);border-radius:8px;background:white; }.memory-card+.memory-card { margin-top:4px; }.memory-card-top { display:flex;align-items:center;gap:8px; }.memory-card-top strong { min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:12px;font-weight:550;white-space:nowrap; }.memory-status { width:8px;height:8px;flex:none;border-radius:50%;background:#2ca67f; }.memory-card p { margin:4px 0 0;color:var(--fdc-muted);font-size:8px;line-height:1.45; }.memory-card-actions { display:flex;gap:4px;margin-top:8px; }.memory-card-actions button { height:28px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;background:white;color:#555;font-size:8px;cursor:pointer; }.memory-card-actions button:first-child { flex:1;color:white;border-color:var(--fdc-ink);background:var(--fdc-ink); }.library-empty { padding:20px 12px;color:var(--fdc-muted);font-size:8px;line-height:1.5;text-align:center; }
|
|
1158
|
+
.review-visual { display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-top:8px; }.review-sample { position:relative;min-height:36px;display:grid;place-items:center;overflow:hidden;border:1px solid var(--fdc-line);border-radius:4px;background:#fafafa;color:#777;font-size:8px; }.review-sample::after { content:attr(data-label);position:absolute;left:4px;bottom:4px;padding:4px 4px;border-radius:4px;background:rgb(255 255 255 / 84%);color:#777;font-size:8px; }.review-sample>i { width:32px;height:16px;display:block;border:1px solid #bbb;background:var(--sample-color,#e8e8e8);border-radius:var(--sample-radius,4px);transform:scale(var(--sample-scale,1)); }.review-card.locating { background:#f5f9ff; }.review-group-title .included-count { margin-left:auto;color:#23715c; }.review-group-title .group-total { margin-left:4px; }.baseline-badge { display:inline-flex;align-items:center;gap:4px;margin-top:8px;padding:4px 8px;border-radius:4px;color:#23715c;background:#edf8f4;font-size:8px; }.baseline-badge::before { content:"";width:4px;height:4px;border-radius:50%;background:#2ca67f; }
|
|
1159
|
+
.workbench-matrix { display:grid;grid-template-columns:92px repeat(var(--matrix-columns),minmax(112px,1fr));gap:1px;width:min(900px,100%);margin:0 auto 24px;padding:1px;background:#303030;border-radius:8px;overflow:hidden; }.matrix-cell { min-height:52px;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:4px;padding:8px;border:0;background:#1d1d1d;color:#ddd;font-size:8px;text-align:left;cursor:pointer; }.matrix-cell:hover { background:#252525; }.matrix-cell.header { min-height:32px;color:#888;background:#181818;cursor:default; }.matrix-cell strong { font-size:8px;font-weight:500; }.matrix-cell span { color:#777;font-size:8px; }.matrix-cell.verified span { color:#68caa8; }.workbench-stage.matrix-mode { display:block; }.workbench-stage.matrix-mode .frame-shell { margin:0 auto; }
|
|
1160
|
+
.component-actions { display:flex;gap:4px;padding:0 8px 8px 44px; }.component-actions button,.component-variants button { height:24px;padding:0 8px;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; }
|
|
1161
|
+
.token-provenance { grid-column:2;display:flex;align-items:center;gap:4px;margin-top:4px;color:#23715c;font-size:8px; }.token-provenance.literal { color:#985033; }.token-provenance::before { content:"";width:4px;height:4px;border-radius:50%;background:currentColor; }
|
|
1085
1162
|
.workbench-matrix[hidden] { display:none; }
|
|
1086
1163
|
/* 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
|
|
1164
|
+
.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 4px rgb(0 0 0 / 24%),0 16px 36px rgb(0 0 0 / 36%); }
|
|
1088
1165
|
.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
1166
|
.inspector-heading,.review-toolbar { background:rgb(28 28 31 / 96%);border-color:var(--fdc-line); }
|
|
1090
1167
|
.section-head,.section-head:hover,.onboarding-step { color:var(--fdc-ink);background:var(--fdc-surface); }
|
|
@@ -1099,106 +1176,208 @@ var PANEL_CSS = `
|
|
|
1099
1176
|
.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
1177
|
.scope select option,.property-control select option,.compact-control select option { color:var(--fdc-ink);background:var(--fdc-paper); }
|
|
1101
1178
|
.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:
|
|
1179
|
+
.layer-row.selected { color:#a9cbff;background:transparent; }.layer-row.selected .layer-icon { color:#86b7ff; }
|
|
1103
1180
|
.layer-row .layer-meta { color:#b5b5bc;background:var(--fdc-elevated); }.layer-row.selected .layer-meta { color:#a9cbff;background:#23416d; }
|
|
1104
1181
|
.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
1182
|
.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; }
|
|
1183
|
+
.section-actions { flex:none;display:flex;align-items:center;gap:4px; }.section-action,.section-actions button,.category-action,.token-menu-trigger { height:28px;display:inline-flex;align-items:center;justify-content:center;gap:4px;padding:0 8px;border:1px solid transparent;border-radius:4px;color:var(--fdc-muted);background:transparent;font:500 8px/1 var(--fdc-font);cursor:pointer; }.section-action:hover,.section-actions button:hover,.category-action:hover,.token-menu-trigger:hover { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }.section-action svg,.category-action svg,.token-menu-trigger svg { width:12px;height:12px; }.type-presets button { width:28px;padding:0; }.category-action { margin-left:auto; }.inspector-heading .property-count { margin-left:4px; }
|
|
1184
|
+
.token-menu-wrap { position:relative;display:flex;align-items:center;margin-top:4px; }.token-menu-trigger { width:28px;padding:0; }.token-menu { position:absolute;z-index:8;top:32px;right:0;width:232px;max-height:220px;overflow:auto;padding:4px;border:1px solid var(--fdc-line);border-radius:8px;background:var(--fdc-elevated);box-shadow:0 16px 36px rgb(0 0 0 / 38%); }.token-menu[hidden] { display:none; }.token-option { width:100%;height:32px;display:grid;grid-template-columns:16px minmax(0,1fr) auto;align-items:center;gap:8px;padding:0 8px;border:0;border-radius:4px;color:var(--fdc-ink);background:transparent;text-align:left;cursor:pointer; }.token-option:hover { background:var(--fdc-subtle); }.token-option .swatch { width:12px;height:12px;border:1px solid rgb(255 255 255 / 14%);border-radius:4px;background:var(--token-color); }.token-option span { overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:8px; }.token-option code { color:var(--fdc-muted);font:400 8px/1 var(--fdc-font); }
|
|
1185
|
+
.color-picker-trigger { width:100%;height:32px;display:flex;align-items:center;gap:8px;padding:0 32px 0 8px;border:0;background:transparent;color:var(--fdc-ink);font:400 12px/1 var(--fdc-font);text-align:left;cursor:pointer; }.color-picker-trigger .color-swatch { margin-left:0; }.color-popover { position:fixed;z-index:2147483647;width:280px;padding:12px;border:1px solid var(--fdc-line);border-radius:12px;color:var(--fdc-ink);background:var(--fdc-elevated);box-shadow:0 20px 60px rgb(0 0 0 / 48%);pointer-events:auto; }.color-popover[hidden] { display:none; }.color-popover-head { height:28px;display:flex;align-items:center;margin-bottom:8px; }.color-popover-head strong { font-size:12px;font-weight:550; }.color-popover-head button { margin-left:auto; }.color-plane { position:relative;width:100%;height:152px;overflow:hidden;border-radius:8px;background:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,transparent),hsl(var(--picker-hue) 100% 50%);cursor:crosshair;touch-action:none; }.color-plane-handle { position:absolute;width:12px;height:12px;transform:translate(-50%,-50%);border:4px solid white;border-radius:50%;box-shadow:0 1px 4px #000;pointer-events:none; }.color-sliders { display:grid;gap:8px;margin-top:8px; }.color-sliders label { display:grid;grid-template-columns:36px minmax(0,1fr);align-items:center;gap:8px;color:var(--fdc-muted);font-size:8px; }.color-sliders input[type="range"] { width:100%;accent-color:var(--fdc-signal); }.color-fields { display:grid;grid-template-columns:minmax(0,1fr) 36px;gap:8px;margin-top:8px; }.color-fields input { min-width:0;height:32px;padding:0 8px;border:1px solid var(--fdc-line);border-radius:4px;color:var(--fdc-ink);background:var(--fdc-paper);font:400 12px/1 var(--fdc-font);outline:none; }.color-fields button { height:32px;display:grid;place-items:center;padding:0;border:1px solid var(--fdc-line);border-radius:4px;color:var(--fdc-muted);background:var(--fdc-paper);cursor:pointer; }.color-fields button:hover { color:var(--fdc-ink); }.color-fields svg { width:12px;height:12px; }.color-popover-section { margin-top:12px;padding-top:8px;border-top:1px solid var(--fdc-line); }.color-popover-section strong { display:block;margin-bottom:8px;color:var(--fdc-muted);font-size:8px;font-weight:500;text-transform:uppercase;letter-spacing:.04em; }.color-swatches { display:flex;flex-wrap:wrap;gap:8px; }.color-swatches button { width:24px;height:24px;padding:0;border:1px solid rgb(255 255 255 / 16%);border-radius:4px;background:var(--picker-swatch);cursor:pointer; }.color-swatches button:hover { box-shadow:0 0 0 4px var(--fdc-signal); }
|
|
1106
1186
|
.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
1187
|
.confidence-pill { color:#9ec5ff;background:var(--fdc-signal-soft); }.confidence-pill.unresolved { color:#f2ae8f;background:#42271d; }
|
|
1108
1188
|
.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
1189
|
.empty-state-icon { color:#9ec5ff;background:var(--fdc-signal-soft); }.onboarding-card-head span { color:#e7a68c;background:#36231d; }
|
|
1110
1190
|
.change-count { color:var(--fdc-ink);background:var(--fdc-paper); }
|
|
1191
|
+
.compare-bar button:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }
|
|
1192
|
+
.compare-bar button.active { color:#141416;background:#f0f1f3; }
|
|
1193
|
+
.toast { color:#141416;background:#f0f1f3;border:1px solid #ffffff;box-shadow:0 8px 20px rgb(0 0 0 / 30%); }
|
|
1111
1194
|
.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
1195
|
.panel-resizer::after { background:#4a4a50; }
|
|
1113
|
-
.empty-state { min-height:220px;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:36px
|
|
1114
|
-
.review-head strong { font-size:
|
|
1115
|
-
.onboarding-card { bottom:
|
|
1196
|
+
.empty-state { min-height:220px;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:36px 32px;text-align:center; }.empty-state-icon { width:40px;height:40px;display:grid;place-items:center;margin-bottom:16px;border-radius:12px; }.empty-state-icon svg { width:16px;height:16px; }.empty-state strong { font-size:12px;font-weight:550;letter-spacing:-.01em; }.empty-state p { max-width:232px;margin:8px 0 0;color:var(--fdc-muted);font-size:12px;line-height:1.55; }.empty-state-actions { display:flex;align-items:center;gap:8px;margin-top:16px; }.empty-state-actions button { height:32px;padding:0 12px;border:1px solid var(--fdc-line);border-radius:8px;font-size:12px;cursor:pointer; }.empty-state kbd { margin-top:12px;color:var(--fdc-muted);font:400 8px/1.4 var(--fdc-font); }
|
|
1197
|
+
.review-head strong { font-size:12px; }.review-summary { padding:12px 16px 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:12px;line-height:1.45; }.review-summary.attention strong { color:#8b4d3d; }.review-toolbar button { height:28px;padding:0 8px;font-size:12px; }
|
|
1198
|
+
.onboarding-card { bottom:84px;width:340px;padding:16px;border-radius:12px;box-shadow:0 16px 40px rgb(0 0 0 / 15%); }.onboarding-card-head { gap:8px; }.onboarding-card-head span { width:28px;height:28px;display:grid;place-items:center;color:#a75031;background:#fbf1ed;border-radius:8px; }.onboarding-card-head svg { width:16px;height:16px;color:inherit; }.onboarding-card-head strong { font-size:12px;letter-spacing:-.015em; }.onboarding-card>p { margin:8px 0 16px;font-size:12px;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:8px;padding:8px 12px;background:white;text-align:left; }.onboarding-step b { color:#8a8a8a;font-size:8px;font-weight:500;letter-spacing:.04em; }.onboarding-step strong { display:block;font-size:12px;font-weight:550; }.onboarding-step small { display:block;margin-top:4px;color:var(--fdc-muted);font-size:8px;line-height:1.35; }.onboarding-actions { gap:8px;margin-top:12px; }.onboarding-actions button { height:32px;padding:0 12px;border-radius:8px;font-size:12px; }
|
|
1116
1199
|
.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
1200
|
.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
|
|
1201
|
+
.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 4px 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
1202
|
/* Workspace ownership */
|
|
1120
|
-
.workspace-bar { position:fixed;z-index:2147483647;top:12px;left:50%;min-height:48px;display:flex;align-items:center;gap:
|
|
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:
|
|
1203
|
+
.workspace-bar { position:fixed;z-index:2147483647;top:12px;left:50%;min-height:48px;display:flex;align-items:center;gap:4px;padding:8px;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 4px 4px rgb(0 0 0 / 20%),0 16px 36px rgb(0 0 0 / 34%);backdrop-filter:blur(16px);pointer-events:auto; }.workspace-bar .brand { flex:none;padding:0 8px; }.workspace-bar .brand-copy b { font-size:12px; }.workspace-bar .session-status { margin:0; }.workspace-actions { display:flex;align-items:center;gap:4px; }.workspace-divider { width:1px;height:24px;background:var(--fdc-line); }.workspace-bar .icon-button { width:36px;height:36px; }.workspace-bar .icon-button.active { color:#9ec5ff;background:var(--fdc-signal-soft); }.workspace-bar .status-popover { top:44px;right:auto;left:60px; }
|
|
1204
|
+
.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:8px;padding:0 8px 0 12px;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:8px; }.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:44px; }.inspector-category>.inspector-heading .section-toggle>svg { width:16px;height:16px;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:12px;border-left:1px solid var(--fdc-line); }.inspector-category .property-section .section-head { padding-left:8px; }.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:12px; }
|
|
1122
1205
|
.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:
|
|
1206
|
+
.inspector-scroll::-webkit-scrollbar { width:8px; }
|
|
1124
1207
|
.inspector-scroll::-webkit-scrollbar-track { background:transparent; }
|
|
1125
|
-
.inspector-scroll::-webkit-scrollbar-thumb { background:#4a4a50;border-radius:
|
|
1208
|
+
.inspector-scroll::-webkit-scrollbar-thumb { background:#4a4a50;border-radius:1000px; }
|
|
1126
1209
|
.inspector-scroll::-webkit-scrollbar-thumb:hover { background:#626269; }
|
|
1127
1210
|
.inspector-scroll>.selection,.inspector-scroll>.scope,.inspector-scroll>.controls { width:100%;box-sizing:border-box; }
|
|
1128
1211
|
.inspector-scroll>.controls { min-height:0;overflow:visible;flex:none; }
|
|
1129
1212
|
/* Fluid inspector controls */
|
|
1130
1213
|
.inspector-category .property-section { width:100%;margin-left:0;border-left:0; }
|
|
1131
|
-
.inspector-category .property-section .section-head { padding-left:
|
|
1214
|
+
.inspector-category .property-section .section-head { padding-left:12px; }
|
|
1132
1215
|
.category-body>.context-tools,.category-body>.native-panel { width:100%;margin-left:0; }
|
|
1133
|
-
.category-body>.design-health { width:auto;margin:12px
|
|
1134
|
-
.section-grid { width:100%;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:12px
|
|
1216
|
+
.category-body>.design-health { width:auto;margin:12px 16px 0; }
|
|
1217
|
+
.section-grid { width:100%;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:12px 16px 16px;box-sizing:border-box; }
|
|
1135
1218
|
.section-grid.stacked { grid-template-columns:minmax(0,1fr); }
|
|
1136
1219
|
.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:
|
|
1138
|
-
.property-control .property-label { min-height:
|
|
1139
|
-
.property-control .control-field { width:100%;height:
|
|
1220
|
+
.property-control { min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:8px; }
|
|
1221
|
+
.property-control .property-label { min-height:12px;line-height:12px; }
|
|
1222
|
+
.property-control .control-field { width:100%;height:36px; }
|
|
1140
1223
|
.property-control input,.property-control select { height:32px; }
|
|
1141
1224
|
.section-grid.two { grid-template-columns:repeat(2,minmax(0,1fr));gap:8px; }
|
|
1142
1225
|
.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:
|
|
1144
|
-
.section-grid.two .control-field { width:100%;height:
|
|
1226
|
+
.compact-control .field-prefix,.compact-control .field-prefix.wide { width:44px;min-width:44px;box-sizing:border-box;padding-left:12px; }
|
|
1227
|
+
.section-grid.two .control-field { width:100%;height:36px; }
|
|
1145
1228
|
.section-grid.two .compact-control input,.section-grid.two .compact-control select { height:32px; }
|
|
1146
1229
|
.control-field>.control-reset { position:absolute;z-index:2;top:4px;right:4px;width:24px;height:24px; }
|
|
1147
1230
|
.control-field>input { padding-right:32px; }
|
|
1148
|
-
.control-field:has(>select:not(.unit-select))>.control-reset { right:
|
|
1231
|
+
.control-field:has(>select:not(.unit-select))>.control-reset { right:32px; }
|
|
1149
1232
|
.control-field:has(>select:not(.unit-select))>select:not(.unit-select) { padding-right:56px!important; }
|
|
1150
|
-
.control-field:has(>.unit-select)>.control-reset { right:
|
|
1151
|
-
.control-field:has(>.unit)>.control-reset { right:
|
|
1233
|
+
.control-field:has(>.unit-select)>.control-reset { right:48px; }
|
|
1234
|
+
.control-field:has(>.unit)>.control-reset { right:24px; }
|
|
1152
1235
|
/* Consistent inset chevrons for every select input */
|
|
1153
|
-
select { -webkit-appearance:none;appearance:none;padding-right:
|
|
1154
|
-
.control-field .unit-select { width:48px;padding-right:20px!important;padding-left:
|
|
1155
|
-
.layers-panel { top:72px;bottom:
|
|
1156
|
-
|
|
1157
|
-
.
|
|
1236
|
+
select { -webkit-appearance:none;appearance:none;padding-right:32px!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 8px center!important;background-size:16px 16px!important; }
|
|
1237
|
+
.control-field .unit-select { width:48px;padding-right:20px!important;padding-left:4px!important;background-position:right 4px center!important;background-size:16px 16px!important; }
|
|
1238
|
+
.layers-panel { top:72px;bottom:auto;max-height:min(560px,calc(100vh - 84px)); }.layers-panel[hidden] { display:none; }.layers-switch { flex:none; }
|
|
1239
|
+
/* Compact tree rhythm: rows use the panel width while hierarchy remains legible. */
|
|
1240
|
+
.layer-tree { padding:4px 4px;scrollbar-gutter:auto;scrollbar-width:thin;scrollbar-color:#4a4a50 transparent; }
|
|
1241
|
+
.layer-tree::-webkit-scrollbar { width:8px; }
|
|
1242
|
+
.layer-tree::-webkit-scrollbar-track { background:transparent; }
|
|
1243
|
+
.layer-tree::-webkit-scrollbar-thumb { background:#4a4a50;border-radius:1000px; }
|
|
1244
|
+
.layer-row { padding-left:calc(4px + var(--layer-depth) * 12px);padding-right:4px; }
|
|
1245
|
+
.layer-selection-glide { right:4px;left:4px; }
|
|
1246
|
+
.layer-toggle,.layer-select { height:32px; }
|
|
1247
|
+
.layer-select { padding-right:4px;padding-left:4px; }
|
|
1248
|
+
.layer-row .layer-meta { margin-right:4px; }
|
|
1249
|
+
.component-list { padding-right:0;padding-left:0; }
|
|
1250
|
+
.component-main { padding-right:8px;padding-left:8px; }
|
|
1251
|
+
.component-variants,.component-actions { padding-right:8px;padding-left:40px; }
|
|
1252
|
+
/* Keep every inspector field on the same 36px interaction rhythm. */
|
|
1253
|
+
.property-control .control-field,.section-grid.two .control-field,.compact-control .control-field { height:36px; }
|
|
1254
|
+
.property-control input,.property-control select,.section-grid.two .compact-control input,.section-grid.two .compact-control select { height:36px; }
|
|
1255
|
+
.control-field>.control-reset { top:4px; }
|
|
1256
|
+
.utility-panel { z-index:2147483646;max-height:none;min-width:280px;min-height:280px;box-shadow:0 4px 4px rgb(0 0 0 / 22%),0 20px 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:4px;bottom:4px;width:20px;height:20px;padding:0;border:0;background:transparent;cursor:nwse-resize; }.utility-resizer::after { content:"";position:absolute;right:4px;bottom:4px;width:8px;height:8px;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; }
|
|
1257
|
+
.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:12px;box-shadow:0 4px 4px rgb(0 0 0 / 22%),0 20px 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:8px;padding:8px 8px 8px 12px; }.change-tray-summary .change-count { margin-right:4px; }.change-tray-summary button { height:32px;border:1px solid var(--fdc-line);border-radius:8px;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:12px;height:12px; }.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
1258
|
/* Focused review list */
|
|
1159
1259
|
.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(
|
|
1260
|
+
.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(12px); }
|
|
1161
1261
|
.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:
|
|
1163
|
-
.review-overview .review-summary span { overflow:hidden;text-overflow:ellipsis;margin-top:
|
|
1262
|
+
.review-overview .review-summary strong { overflow:hidden;text-overflow:ellipsis;font-size:12px;white-space:nowrap; }
|
|
1263
|
+
.review-overview .review-summary span { overflow:hidden;text-overflow:ellipsis;margin-top:4px;font-size:8px;white-space:nowrap; }
|
|
1164
1264
|
.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:
|
|
1265
|
+
.review-overview .review-toolbar button { height:28px;padding:0 8px;border-color:transparent;background:transparent;color:var(--fdc-muted);font-size:8px; }
|
|
1166
1266
|
.review-overview .review-toolbar button:hover { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }
|
|
1167
1267
|
.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:
|
|
1169
|
-
.review-group-title .included-count { font-size:
|
|
1170
|
-
.review-card { min-height:
|
|
1171
|
-
.review-card input[type="checkbox"] { margin-top:
|
|
1172
|
-
.review-card-line { min-height:32px;display:grid;grid-template-columns:minmax(120px,1fr) auto minmax(220px,320px)
|
|
1173
|
-
.review-card-line>strong { font-size:
|
|
1174
|
-
.review-values { min-width:0;display:grid;grid-template-columns:minmax(72px,1fr) 12px minmax(
|
|
1175
|
-
.review-before { min-width:0;overflow:hidden;text-overflow:ellipsis;padding:0 8px;color:var(--fdc-muted);background:transparent;font-size:
|
|
1176
|
-
.review-after { height:
|
|
1268
|
+
.change-tray .review-group-title { position:sticky;top:52px;z-index:2;min-height:40px;padding:0 12px;background:rgb(28 28 31 / 98%); }
|
|
1269
|
+
.review-group-title .included-count { font-size:8px; }
|
|
1270
|
+
.review-card { min-height:52px;grid-template-columns:20px minmax(0,1fr);align-items:start;gap:8px;padding:8px 12px; }
|
|
1271
|
+
.review-card input[type="checkbox"] { margin-top:8px; }
|
|
1272
|
+
.review-card-line { min-height:32px;display:grid;grid-template-columns:minmax(120px,1fr) auto minmax(220px,320px) 32px;align-items:center;gap:8px; }
|
|
1273
|
+
.review-card-line>strong { font-size:12px; }
|
|
1274
|
+
.review-values { min-width:0;display:grid;grid-template-columns:minmax(72px,1fr) 12px minmax(92px,1fr);align-items:center;gap:4px;margin:0; }
|
|
1275
|
+
.review-before { min-width:0;overflow:hidden;text-overflow:ellipsis;padding:0 8px;color:var(--fdc-muted);background:transparent;font-size:12px;text-align:right;white-space:nowrap; }
|
|
1276
|
+
.review-after { height:32px;font-size:12px; }
|
|
1177
1277
|
.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:
|
|
1278
|
+
.review-more>summary { width:28px;height:28px;display:grid;place-items:center;border:1px solid transparent;border-radius:4px;color:var(--fdc-muted);font:600 12px/1 var(--fdc-font);letter-spacing:1px;list-style:none;cursor:pointer; }
|
|
1179
1279
|
.review-more>summary::-webkit-details-marker { display:none; }
|
|
1180
1280
|
.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:
|
|
1182
|
-
.review-more .review-card-tools button { width:100%;height:
|
|
1281
|
+
.review-more .review-card-tools { position:absolute;z-index:5;right:0;top:32px;width:260px;display:flex;flex-direction:column;gap:4px;padding:4px;border:1px solid var(--fdc-line);border-radius:8px;background:var(--fdc-elevated);box-shadow:0 12px 24px rgb(0 0 0 / 34%); }
|
|
1282
|
+
.review-more .review-card-tools button { width:100%;height:28px;padding:0 8px;border:0;text-align:left;background:transparent; }
|
|
1183
1283
|
.review-more .review-card-tools button:hover { background:var(--fdc-subtle); }
|
|
1184
|
-
.review-details { margin-top:
|
|
1185
|
-
.review-details summary { min-height:
|
|
1186
|
-
.review-details[open] { padding-bottom:
|
|
1187
|
-
.review-details .review-source,.review-details .impact-list { padding-right:
|
|
1284
|
+
.review-details { margin-top:4px;padding-top:4px;border-top:1px solid var(--fdc-line); }
|
|
1285
|
+
.review-details summary { min-height:28px;display:flex;align-items:center;padding:0 8px;color:var(--fdc-muted);font-size:8px;cursor:pointer; }
|
|
1286
|
+
.review-details[open] { padding-bottom:8px; }
|
|
1287
|
+
.review-details .review-source,.review-details .impact-list { padding-right:8px;padding-left:8px; }
|
|
1188
1288
|
.review-visual { display:none; }
|
|
1189
|
-
@media (max-width:980px){.review-card-line{grid-template-columns:minmax(100px,1fr) auto minmax(
|
|
1190
|
-
@media (max-width:760px){.review-card-line{grid-template-columns:minmax(0,1fr) auto
|
|
1191
|
-
.tool-shelf { bottom:calc(
|
|
1192
|
-
.compare-bar { bottom:calc(
|
|
1193
|
-
@keyframes fdc-selection-title { from { opacity:.45;transform:translateY(
|
|
1194
|
-
@media (max-width:680px){.workspace-bar{right:8px;left:8px;transform:none;overflow-x:auto}.workspace-bar .brand{padding-right:
|
|
1195
|
-
|
|
1289
|
+
@media (max-width:980px){.review-card-line{grid-template-columns:minmax(100px,1fr) auto minmax(192px,260px) 32px}.review-overview .review-summary span{display:none}}
|
|
1290
|
+
@media (max-width:760px){.review-card-line{grid-template-columns:minmax(0,1fr) auto 32px}.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 8px}}
|
|
1291
|
+
.tool-shelf { bottom:calc(20px + 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:4px; }.multi-actions-divider { margin-left:4px; }
|
|
1292
|
+
.compare-bar { bottom:calc(80px + var(--fdc-tray-lift,0px)); }
|
|
1293
|
+
@keyframes fdc-selection-title { from { opacity:.45;transform:translateY(4px) } to { opacity:1;transform:none } }
|
|
1294
|
+
@media (max-width:680px){.workspace-bar{right:8px;left:8px;transform:none;overflow-x:auto}.workspace-bar .brand{padding-right:4px}.workspace-bar .brand-copy{display:none}.workspace-bar .status-popover{position:fixed;top:68px;right:8px;left:8px;width:auto}.panel{top:calc(76px + min(32vh,220px));right:8px;bottom:76px;left:8px;width:auto;max-height:none}.layers-panel{top:68px;right:8px;bottom:auto;left:8px;width:auto;max-height:min(32vh,220px)}.utility-panel{top:68px!important;right:8px!important;bottom:76px!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:172px}.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(92px,1fr))}}
|
|
1295
|
+
/* Shared dock geometry and focused review takeover. */
|
|
1296
|
+
.panel,.layers-panel,.change-tray { width:var(--fdc-dock-width,384px); }
|
|
1297
|
+
.layers-panel { max-width:min(520px,calc(100vw - 24px)); }
|
|
1298
|
+
.change-tray { z-index:2147483647;right:12px;bottom:12px;left:auto;height:48px;min-height:48px; }
|
|
1299
|
+
.change-tray-summary { min-height:48px;grid-template-columns:minmax(0,1fr) 32px 72px; }
|
|
1300
|
+
.panel.change-summary-visible .inspector-scroll { padding-bottom:60px;scroll-padding-bottom:60px; }
|
|
1301
|
+
.tool-shelf { bottom:20px; }
|
|
1302
|
+
.compare-bar { bottom:80px; }
|
|
1303
|
+
.review-takeover { position:fixed;z-index:2147483647;inset:0;display:grid;place-items:center;padding:24px;background:rgb(8 8 10 / 72%);backdrop-filter:blur(8px);pointer-events:auto; }
|
|
1304
|
+
.review-takeover[hidden] { display:none; }
|
|
1305
|
+
.review-modal { width:min(1120px,calc(100vw - 48px));height:min(760px,calc(100vh - 48px));display:flex;overflow:hidden;color:var(--fdc-ink);background:var(--fdc-surface);border:1px solid var(--fdc-line);border-radius:12px;box-shadow:0 24px 80px rgb(0 0 0 / 52%); }
|
|
1306
|
+
.review-modal .review-view { width:100%;min-width:0;min-height:0;display:flex; }
|
|
1307
|
+
.review-modal .review-head { flex:none;min-height:52px;padding:0 16px; }
|
|
1308
|
+
.review-modal .review-body { min-height:0;flex:1;display:block;overflow-x:hidden;overflow-y:auto; }
|
|
1309
|
+
.review-modal .review-group { border-right:0;border-bottom:1px solid var(--fdc-line); }
|
|
1310
|
+
.review-modal .review-group-title { position:sticky;top:52px;z-index:2;background:rgb(28 28 31 / 98%); }
|
|
1311
|
+
.review-modal .review-actions { position:sticky;bottom:0;flex:none;grid-template-columns:100px minmax(220px,320px);justify-content:end;padding:12px 16px;background:rgb(28 28 31 / 98%);backdrop-filter:blur(12px); }
|
|
1312
|
+
/* Review is a reading surface, so it uses a larger type scale than the dense inspector. */
|
|
1313
|
+
.review-modal .review-head strong { font-size:16px;font-weight:600;letter-spacing:-.015em; }
|
|
1314
|
+
.review-modal .review-head span { font-size:12px; }
|
|
1315
|
+
.review-modal .review-overview { min-height:60px;padding:12px 16px; }
|
|
1316
|
+
.review-modal .review-overview .review-summary strong { font-size:16px;font-weight:600; }
|
|
1317
|
+
.review-modal .review-overview .review-summary span { margin-top:4px;font-size:12px;line-height:1.45; }
|
|
1318
|
+
.review-modal .review-overview .review-toolbar button { height:36px;padding:0 12px;font-size:12px; }
|
|
1319
|
+
.review-modal .review-group-title { min-height:48px;padding:0 16px;font-size:12px; }
|
|
1320
|
+
.review-modal .review-group-title strong { font-size:16px;font-weight:600; }
|
|
1321
|
+
.review-modal .review-group-title .included-count,.review-modal .review-group-title .group-total { font-size:12px; }
|
|
1322
|
+
.review-modal .review-card { min-height:64px;gap:12px;padding:12px 16px; }
|
|
1323
|
+
.review-modal .review-card input[type="checkbox"] { width:16px;height:16px;margin-top:8px; }
|
|
1324
|
+
.review-modal .review-card-line { min-height:36px;gap:12px; }
|
|
1325
|
+
.review-modal .review-card-line>strong { font-size:16px;font-weight:550; }
|
|
1326
|
+
.review-modal .confidence-pill { padding:4px 8px;font-size:12px; }
|
|
1327
|
+
.review-modal .review-before { padding:0 8px;font-size:12px; }
|
|
1328
|
+
.review-modal .review-after { height:36px;padding:0 12px;font-size:12px; }
|
|
1329
|
+
.review-modal .review-more>summary { width:32px;height:32px;font-size:12px; }
|
|
1330
|
+
.review-modal .review-more .review-card-tools { top:36px; }
|
|
1331
|
+
.review-modal .review-more .review-card-tools button { height:32px;padding:0 8px;font-size:12px; }
|
|
1332
|
+
.review-modal .review-details summary { min-height:32px;font-size:12px; }
|
|
1333
|
+
.review-modal .review-source { font-size:12px;line-height:1.5; }
|
|
1334
|
+
.review-modal .impact-list,.review-modal .impact-list li { font-size:12px;line-height:1.5; }
|
|
1335
|
+
.review-modal .review-actions button { min-height:44px;font-size:12px;font-weight:550; }
|
|
1336
|
+
.review-modal .run-state strong { font-size:16px; }
|
|
1337
|
+
.review-modal .run-summary p { font-size:12px; }
|
|
1338
|
+
.review-modal .run-step strong,.review-modal .result-row { font-size:12px; }
|
|
1339
|
+
.review-modal .run-step p,.review-modal .run-files { font-size:12px; }
|
|
1340
|
+
.interface-theme-menu { position:fixed;z-index:2147483647;width:164px;padding:4px;border:1px solid var(--fdc-line);border-radius:8px;color:var(--fdc-ink);background:var(--fdc-elevated);box-shadow:0 16px 36px rgb(0 0 0 / 34%);pointer-events:auto; }
|
|
1341
|
+
.interface-theme-menu[hidden] { display:none; }
|
|
1342
|
+
.interface-theme-menu button { width:100%;height:32px;display:grid;grid-template-columns:minmax(0,1fr) 16px;align-items:center;padding:0 8px;border:0;border-radius:4px;color:var(--fdc-muted);background:transparent;font-size:12px;text-align:left;cursor:pointer; }
|
|
1343
|
+
.interface-theme-menu button:hover { color:var(--fdc-ink);background:var(--fdc-subtle); }
|
|
1344
|
+
.interface-theme-menu button[aria-checked="true"] { color:var(--fdc-ink);background:var(--fdc-subtle); }
|
|
1345
|
+
.interface-theme-menu button svg { width:12px;height:12px;color:var(--fdc-signal); }
|
|
1346
|
+
.interface-theme-menu button:not([aria-checked="true"]) svg { visibility:hidden; }
|
|
1347
|
+
:host([data-interface-theme="light"]) { color-scheme:light;--fdc-ink:#141416;--fdc-paper:#f0f1f3;--fdc-surface:#ffffff;--fdc-subtle:#f0f1f3;--fdc-elevated:#f7f7f8;--fdc-line:#dedfe2;--fdc-signal:#2563eb;--fdc-signal-soft:#e8f0ff;--fdc-component:#7259d6;--fdc-component-soft:#f0edff;--fdc-muted:#666870; }
|
|
1348
|
+
:host([data-interface-theme="light"]) .panel,:host([data-interface-theme="light"]) .layers-panel,:host([data-interface-theme="light"]) .health-panel,:host([data-interface-theme="light"]) .library-panel,:host([data-interface-theme="light"]) .tool-shelf,:host([data-interface-theme="light"]) .onboarding-card,:host([data-interface-theme="light"]) .compare-bar,:host([data-interface-theme="light"]) .command-palette,:host([data-interface-theme="light"]) .status-popover,:host([data-interface-theme="light"]) .canvas-variant,:host([data-interface-theme="light"]) .workspace-bar,:host([data-interface-theme="light"]) .change-tray,:host([data-interface-theme="light"]) .review-modal { color:var(--fdc-ink);background:rgb(255 255 255 / 97%);border-color:var(--fdc-line);box-shadow:0 1px 4px rgb(0 0 0 / 8%),0 16px 36px rgb(0 0 0 / 14%); }
|
|
1349
|
+
:host([data-interface-theme="light"]) .top,:host([data-interface-theme="light"]) .top-actions,:host([data-interface-theme="light"]) .selection,:host([data-interface-theme="light"]) .scope,:host([data-interface-theme="light"]) .controls,:host([data-interface-theme="light"]) .property-section,:host([data-interface-theme="light"]) .change-dock,:host([data-interface-theme="light"]) .footer,:host([data-interface-theme="light"]) .review-view,:host([data-interface-theme="light"]) .review-head,:host([data-interface-theme="light"]) .review-group,:host([data-interface-theme="light"]) .review-group-title,:host([data-interface-theme="light"]) .review-actions,:host([data-interface-theme="light"]) .layers-head,:host([data-interface-theme="light"]) .layer-tree,:host([data-interface-theme="light"]) .health-head,:host([data-interface-theme="light"]) .health-list,:host([data-interface-theme="light"]) .health-footer,:host([data-interface-theme="light"]) .library-head,:host([data-interface-theme="light"]) .library-actions,:host([data-interface-theme="light"]) .library-body,:host([data-interface-theme="light"]) .memory-card,:host([data-interface-theme="light"]) .context-tools,:host([data-interface-theme="light"]) .native-panel,:host([data-interface-theme="light"]) .section-head,:host([data-interface-theme="light"]) .onboarding-step { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line); }
|
|
1350
|
+
:host([data-interface-theme="light"]) .inspector-heading,:host([data-interface-theme="light"]) .review-toolbar,:host([data-interface-theme="light"]) .review-overview,:host([data-interface-theme="light"]) .review-modal .review-actions { color:var(--fdc-ink);background:rgb(255 255 255 / 97%);border-color:var(--fdc-line); }
|
|
1351
|
+
:host([data-interface-theme="light"]) .review-modal .review-group-title { background:rgb(247 247 248 / 98%); }
|
|
1352
|
+
:host([data-interface-theme="light"]) .property-label,:host([data-interface-theme="light"]) .section-head,:host([data-interface-theme="light"]) .color-value,:host([data-interface-theme="light"]) .layer-row,:host([data-interface-theme="light"]) .command-item,:host([data-interface-theme="light"]) .library-section-head { color:#303136; }
|
|
1353
|
+
:host([data-interface-theme="light"]) .selection-path button,:host([data-interface-theme="light"]) .control-field,:host([data-interface-theme="light"]) .native-search,:host([data-interface-theme="light"]) .layers-search input,:host([data-interface-theme="light"]) .review-after,:host([data-interface-theme="light"]) .review-toolbar button,:host([data-interface-theme="light"]) .review-card-tools button,:host([data-interface-theme="light"]) .review-actions button,:host([data-interface-theme="light"]) .change-dock button,:host([data-interface-theme="light"]) .footer button,:host([data-interface-theme="light"]) .status-popover button,:host([data-interface-theme="light"]) .health-actions button,:host([data-interface-theme="light"]) .health-footer button,:host([data-interface-theme="light"]) .context-tools button,:host([data-interface-theme="light"]) .native-chip,:host([data-interface-theme="light"]) .variant-button,:host([data-interface-theme="light"]) .library-actions button,:host([data-interface-theme="light"]) .memory-card-actions button,:host([data-interface-theme="light"]) .empty-state-actions button,:host([data-interface-theme="light"]) .onboarding-actions button { color:var(--fdc-ink);background:var(--fdc-elevated);border-color:var(--fdc-line); }
|
|
1354
|
+
:host([data-interface-theme="light"]) .scope select,:host([data-interface-theme="light"]) .property-control input,:host([data-interface-theme="light"]) .property-control select,:host([data-interface-theme="light"]) .compact-control input,:host([data-interface-theme="light"]) .compact-control select,:host([data-interface-theme="light"]) .native-search,:host([data-interface-theme="light"]) .command-palette input { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line); }
|
|
1355
|
+
:host([data-interface-theme="light"]) .scope select option,:host([data-interface-theme="light"]) .property-control select option,:host([data-interface-theme="light"]) .compact-control select option { color:var(--fdc-ink);background:var(--fdc-surface); }
|
|
1356
|
+
:host([data-interface-theme="light"]) .layers-search,:host([data-interface-theme="light"]) .layers-switch,:host([data-interface-theme="light"]) .review-summary { background:var(--fdc-paper);border-color:var(--fdc-line); }
|
|
1357
|
+
:host([data-interface-theme="light"]) .layers-switch button:hover,:host([data-interface-theme="light"]) .layers-switch button.active,:host([data-interface-theme="light"]) .health-filters button:hover,:host([data-interface-theme="light"]) .health-filters button.active { color:var(--fdc-ink);background:var(--fdc-surface); }
|
|
1358
|
+
:host([data-interface-theme="light"]) .component-card,:host([data-interface-theme="light"]) .health-card { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line); }
|
|
1359
|
+
:host([data-interface-theme="light"]) .layer-row.selected { color:#1458b8;background:transparent; }
|
|
1360
|
+
:host([data-interface-theme="light"]) .layer-row .layer-meta { color:#65676e;background:var(--fdc-subtle); }
|
|
1361
|
+
:host([data-interface-theme="light"]) .layer-row.selected .layer-meta { color:#1458b8;background:#dceaff; }
|
|
1362
|
+
:host([data-interface-theme="light"]) .tool-select.active,:host([data-interface-theme="light"]) .tab.active { color:var(--fdc-ink);background:#e4e5e8; }
|
|
1363
|
+
:host([data-interface-theme="light"]) .tool-select.inspect.active { color:white;background:var(--fdc-signal); }
|
|
1364
|
+
:host([data-interface-theme="light"]) .change-dock .dock-review,:host([data-interface-theme="light"]) .review-actions .apply,:host([data-interface-theme="light"]) .health-footer .health-rescan { color:#f0f1f3;background:#141416;border-color:#141416; }
|
|
1365
|
+
:host([data-interface-theme="light"]) .session-status,:host([data-interface-theme="light"]) .session-status.saved { color:#236c59;background:#eef8f4; }
|
|
1366
|
+
:host([data-interface-theme="light"]) .interface-theme-menu { color:var(--fdc-ink);background:var(--fdc-surface);border-color:var(--fdc-line);box-shadow:0 16px 36px rgb(0 0 0 / 16%); }
|
|
1367
|
+
.control-field { height:36px;border-radius:8px; }
|
|
1368
|
+
.compact-control .field-prefix,.compact-control .field-prefix.wide { width:36px;min-width:36px;height:100%;display:grid;place-items:center;padding:0;border-right:1px solid var(--fdc-line);background:rgb(255 255 255 / 2%);color:var(--fdc-muted);font:500 12px/1 var(--fdc-font); }
|
|
1369
|
+
.field-prefix svg { width:12px;height:12px; }
|
|
1370
|
+
.property-control input,.property-control select,.compact-control input,.compact-control select { height:36px;font-size:12px;font-weight:400; }
|
|
1371
|
+
.control-field .unit-select { width:44px;padding-right:24px!important;background-position:right 8px center!important; }
|
|
1372
|
+
.section-grid { gap:8px;padding:0 16px 16px; }
|
|
1373
|
+
@media (max-width:680px){.panel,.layers-panel{width:auto}.panel-resizer{display:none}.change-tray{right:8px;bottom:8px;left:auto;width:calc(100vw - 16px)}.review-takeover{padding:8px}.review-modal{width:calc(100vw - 16px);height:calc(100vh - 16px);border-radius:12px}.review-modal .review-actions{grid-template-columns:84px 1fr}.panel.change-summary-visible .inspector-scroll{padding-bottom:60px}}
|
|
1374
|
+
@media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important}.layer-row.entering,.layer-branch{animation:none!important}}
|
|
1196
1375
|
`;
|
|
1197
1376
|
function numberFrom(value) {
|
|
1198
1377
|
const parsed = Number.parseFloat(value);
|
|
1199
1378
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
1200
1379
|
}
|
|
1201
|
-
function pxControl(element, computed, category, property, label, max = 600) {
|
|
1380
|
+
function pxControl(element, computed, category, property, label, max = 600, min = 0) {
|
|
1202
1381
|
return {
|
|
1203
1382
|
category,
|
|
1204
1383
|
property: String(property),
|
|
@@ -1206,7 +1385,7 @@ function pxControl(element, computed, category, property, label, max = 600) {
|
|
|
1206
1385
|
kind: "number",
|
|
1207
1386
|
value: numberFrom(String(computed[property])),
|
|
1208
1387
|
unit: "px",
|
|
1209
|
-
min
|
|
1388
|
+
min,
|
|
1210
1389
|
max,
|
|
1211
1390
|
step: 1,
|
|
1212
1391
|
read: () => numberFrom(getComputedStyle(element)[property]),
|
|
@@ -1248,6 +1427,45 @@ function numberStyleControl(element, computed, category, property, label, min, m
|
|
|
1248
1427
|
)
|
|
1249
1428
|
};
|
|
1250
1429
|
}
|
|
1430
|
+
function degreeControl(element, computed) {
|
|
1431
|
+
const read = () => numberFrom(getComputedStyle(element).rotate || "0");
|
|
1432
|
+
return {
|
|
1433
|
+
category: "layout",
|
|
1434
|
+
property: "rotate",
|
|
1435
|
+
label: "Rotation",
|
|
1436
|
+
kind: "number",
|
|
1437
|
+
value: numberFrom(computed.rotate || "0"),
|
|
1438
|
+
unit: "deg",
|
|
1439
|
+
min: -360,
|
|
1440
|
+
max: 360,
|
|
1441
|
+
step: 1,
|
|
1442
|
+
read,
|
|
1443
|
+
apply: (value) => element.style.setProperty("rotate", `${value}deg`)
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
function scaleAxisControl(element, computed, axis) {
|
|
1447
|
+
const readScale = () => {
|
|
1448
|
+
const raw = getComputedStyle(element).scale;
|
|
1449
|
+
if (!raw || raw === "none") return [1, 1];
|
|
1450
|
+
const values = raw.split(/\s+/).map(numberFrom);
|
|
1451
|
+
return [values[0] || 1, values[1] ?? values[0] ?? 1];
|
|
1452
|
+
};
|
|
1453
|
+
const initial = computed.scale && computed.scale !== "none" ? readScale() : [1, 1];
|
|
1454
|
+
return {
|
|
1455
|
+
category: "layout",
|
|
1456
|
+
property: axis === "x" ? "scaleX" : "scaleY",
|
|
1457
|
+
label: axis === "x" ? "Flip horizontal" : "Flip vertical",
|
|
1458
|
+
kind: "select",
|
|
1459
|
+
options: ["1", "-1"],
|
|
1460
|
+
value: String(axis === "x" ? initial[0] : initial[1]),
|
|
1461
|
+
read: () => String(axis === "x" ? readScale()[0] : readScale()[1]),
|
|
1462
|
+
apply: (value) => {
|
|
1463
|
+
const current = readScale();
|
|
1464
|
+
current[axis === "x" ? 0 : 1] = Number(value);
|
|
1465
|
+
element.style.setProperty("scale", `${current[0]} ${current[1]}`);
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1251
1469
|
function sizingModeControl(element, computed, axis) {
|
|
1252
1470
|
const capitalized = axis === "width" ? "Width" : "Height";
|
|
1253
1471
|
const minProperty = axis === "width" ? "minWidth" : "minHeight";
|
|
@@ -1292,6 +1510,10 @@ function sizingModeControl(element, computed, axis) {
|
|
|
1292
1510
|
function controlsFor(element) {
|
|
1293
1511
|
const computed = getComputedStyle(element);
|
|
1294
1512
|
const controls = [
|
|
1513
|
+
...computed.position !== "static" ? [
|
|
1514
|
+
pxControl(element, computed, "layout", "left", "X position", 5e3, -5e3),
|
|
1515
|
+
pxControl(element, computed, "layout", "top", "Y position", 5e3, -5e3)
|
|
1516
|
+
] : [],
|
|
1295
1517
|
sizingModeControl(element, computed, "width"),
|
|
1296
1518
|
sizingModeControl(element, computed, "height"),
|
|
1297
1519
|
styleControl(element, computed, "layout", "minWidth", "Minimum width"),
|
|
@@ -1304,6 +1526,9 @@ function controlsFor(element) {
|
|
|
1304
1526
|
"auto",
|
|
1305
1527
|
"scroll"
|
|
1306
1528
|
]),
|
|
1529
|
+
degreeControl(element, computed),
|
|
1530
|
+
scaleAxisControl(element, computed, "x"),
|
|
1531
|
+
scaleAxisControl(element, computed, "y"),
|
|
1307
1532
|
pxControl(element, computed, "layout", "width", "Width", 1600),
|
|
1308
1533
|
pxControl(element, computed, "layout", "height", "Height", 1200),
|
|
1309
1534
|
styleControl(element, computed, "layout", "display", "Display", "select", [
|
|
@@ -1360,6 +1585,10 @@ function controlsFor(element) {
|
|
|
1360
1585
|
numberStyleControl(element, computed, "color", "opacity", "Opacity", 0, 1, 0.05),
|
|
1361
1586
|
styleControl(element, computed, "color", "backgroundImage", "Gradient"),
|
|
1362
1587
|
pxControl(element, computed, "effects", "borderRadius", "Corner radius", 200),
|
|
1588
|
+
pxControl(element, computed, "effects", "borderTopLeftRadius", "Top left radius", 200),
|
|
1589
|
+
pxControl(element, computed, "effects", "borderTopRightRadius", "Top right radius", 200),
|
|
1590
|
+
pxControl(element, computed, "effects", "borderBottomLeftRadius", "Bottom left radius", 200),
|
|
1591
|
+
pxControl(element, computed, "effects", "borderBottomRightRadius", "Bottom right radius", 200),
|
|
1363
1592
|
pxControl(element, computed, "effects", "borderWidth", "Border width", 32),
|
|
1364
1593
|
styleControl(element, computed, "effects", "borderColor", "Border color", "color"),
|
|
1365
1594
|
styleControl(element, computed, "effects", "boxShadow", "Shadow"),
|
|
@@ -1465,15 +1694,67 @@ function controlsFor(element) {
|
|
|
1465
1694
|
}
|
|
1466
1695
|
});
|
|
1467
1696
|
}
|
|
1468
|
-
|
|
1697
|
+
const textBearing = element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || Boolean(element.textContent?.trim());
|
|
1698
|
+
const editableText = element.childElementCount === 0 || ["BUTTON", "A", "LABEL", "SUMMARY"].includes(element.tagName);
|
|
1699
|
+
return controls.filter((control) => {
|
|
1700
|
+
if (control.category === "typography") return textBearing;
|
|
1701
|
+
if (control.property === "textContent") return textBearing && editableText;
|
|
1702
|
+
if (control.property === "color") return textBearing;
|
|
1703
|
+
return true;
|
|
1704
|
+
});
|
|
1469
1705
|
}
|
|
1470
1706
|
function colorForInput(value) {
|
|
1471
1707
|
const canvas = document.createElement("canvas");
|
|
1472
1708
|
canvas.width = canvas.height = 1;
|
|
1473
1709
|
const context = canvas.getContext("2d");
|
|
1474
1710
|
if (!context) return "#000000";
|
|
1711
|
+
context.fillStyle = "#000000";
|
|
1475
1712
|
context.fillStyle = value;
|
|
1476
|
-
|
|
1713
|
+
const normalized = context.fillStyle;
|
|
1714
|
+
if (normalized.startsWith("#")) return normalized;
|
|
1715
|
+
const channels = normalized.match(/[\d.]+/g)?.slice(0, 3).map(Number);
|
|
1716
|
+
if (!channels || channels.length < 3) return "#000000";
|
|
1717
|
+
return `#${channels.map((channel2) => Math.round(channel2).toString(16).padStart(2, "0")).join("")}`;
|
|
1718
|
+
}
|
|
1719
|
+
function hexChannels(value) {
|
|
1720
|
+
const hex = colorForInput(value).slice(1);
|
|
1721
|
+
return [
|
|
1722
|
+
Number.parseInt(hex.slice(0, 2), 16),
|
|
1723
|
+
Number.parseInt(hex.slice(2, 4), 16),
|
|
1724
|
+
Number.parseInt(hex.slice(4, 6), 16)
|
|
1725
|
+
];
|
|
1726
|
+
}
|
|
1727
|
+
function colorAlpha(value) {
|
|
1728
|
+
const slash = value.match(/\/\s*([\d.]+)%?\s*\)/);
|
|
1729
|
+
if (slash) return value.includes("%") ? Number(slash[1]) / 100 : Number(slash[1]);
|
|
1730
|
+
const comma = value.match(/rgba?\([^)]*,\s*([\d.]+)\s*\)$/);
|
|
1731
|
+
return comma ? Number(comma[1]) : isTransparentColor(value) ? 0 : 1;
|
|
1732
|
+
}
|
|
1733
|
+
function rgbToHsv(red, green, blue) {
|
|
1734
|
+
const r = red / 255;
|
|
1735
|
+
const g = green / 255;
|
|
1736
|
+
const b = blue / 255;
|
|
1737
|
+
const maximum = Math.max(r, g, b);
|
|
1738
|
+
const minimum = Math.min(r, g, b);
|
|
1739
|
+
const delta = maximum - minimum;
|
|
1740
|
+
let hue = 0;
|
|
1741
|
+
if (delta) {
|
|
1742
|
+
if (maximum === r) hue = 60 * ((g - b) / delta % 6);
|
|
1743
|
+
else if (maximum === g) hue = 60 * ((b - r) / delta + 2);
|
|
1744
|
+
else hue = 60 * ((r - g) / delta + 4);
|
|
1745
|
+
}
|
|
1746
|
+
if (hue < 0) hue += 360;
|
|
1747
|
+
return [hue, maximum ? delta / maximum : 0, maximum];
|
|
1748
|
+
}
|
|
1749
|
+
function hsvToRgb(hue, saturation, value) {
|
|
1750
|
+
const chroma = value * saturation;
|
|
1751
|
+
const x = chroma * (1 - Math.abs(hue / 60 % 2 - 1));
|
|
1752
|
+
const match = value - chroma;
|
|
1753
|
+
const [r, g, b] = hue < 60 ? [chroma, x, 0] : hue < 120 ? [x, chroma, 0] : hue < 180 ? [0, chroma, x] : hue < 240 ? [0, x, chroma] : hue < 300 ? [x, 0, chroma] : [chroma, 0, x];
|
|
1754
|
+
return [r, g, b].map((channel2) => Math.round((channel2 + match) * 255));
|
|
1755
|
+
}
|
|
1756
|
+
function rgbHex(red, green, blue) {
|
|
1757
|
+
return `#${[red, green, blue].map((channel2) => Math.max(0, Math.min(255, channel2)).toString(16).padStart(2, "0")).join("")}`;
|
|
1477
1758
|
}
|
|
1478
1759
|
function escapeHtml(value) {
|
|
1479
1760
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
@@ -1497,7 +1778,7 @@ function renderControlInput(control, index) {
|
|
|
1497
1778
|
const rawValue = String(control.value);
|
|
1498
1779
|
const value2 = colorForInput(rawValue);
|
|
1499
1780
|
const transparent = isTransparentColor(rawValue);
|
|
1500
|
-
return `<span class="color-swatch ${transparent ? "transparent" : ""}" style="--swatch-color:${value2}"></span><span class="color-value">${transparent ? "Transparent" : escapeHtml(value2.toUpperCase())}</span
|
|
1781
|
+
return `<button type="button" class="color-picker-trigger" id="${id}" data-color-control="${index}" aria-label="Edit ${escapeHtml(control.label)}"><span class="color-swatch ${transparent ? "transparent" : ""}" style="--swatch-color:${value2}"></span><span class="color-value">${transparent ? "Transparent" : escapeHtml(value2.toUpperCase())}</span></button>`;
|
|
1501
1782
|
}
|
|
1502
1783
|
const type = control.kind === "number" ? "number" : "text";
|
|
1503
1784
|
const value = displayValue(control);
|
|
@@ -1513,7 +1794,9 @@ function renderPropertyControl(control, index, prefix) {
|
|
|
1513
1794
|
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>`;
|
|
1514
1795
|
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."` : "";
|
|
1515
1796
|
if (prefix) {
|
|
1516
|
-
|
|
1797
|
+
const prefixIcon = prefix === "Ratio" ? "maximize-2" : prefix === "Clip" ? "box" : void 0;
|
|
1798
|
+
const prefixContent = prefixIcon ? `<i data-foundry-icon="${prefixIcon}"></i>` : escapeHtml(prefix);
|
|
1799
|
+
return `<label class="compact-control"><span class="sr-only">${escapeHtml(control.label)}</span><span class="control-field"><span class="field-prefix" aria-hidden="true" title="${escapeHtml(control.label)}"${scrubAttributes}>${prefixContent}</span>${field}${reset}</span></label>`;
|
|
1517
1800
|
}
|
|
1518
1801
|
return `<label class="property-control"><span class="property-label"${scrubAttributes}>${escapeHtml(control.label)}</span><span class="control-field">${field}${reset}</span></label>`;
|
|
1519
1802
|
}
|
|
@@ -1535,7 +1818,14 @@ function installFoundryInspector(options = {}) {
|
|
|
1535
1818
|
const sessionId = options.sessionId ?? query.get("__foundry_session") ?? "";
|
|
1536
1819
|
const token = options.token ?? query.get("__foundry_token") ?? "";
|
|
1537
1820
|
const host = document.createElement("div");
|
|
1821
|
+
const interfaceThemeKey = "__foundry_interface_theme";
|
|
1822
|
+
const systemDarkTheme = window.matchMedia("(prefers-color-scheme: dark)");
|
|
1823
|
+
const storedInterfaceTheme = localStorage.getItem(interfaceThemeKey);
|
|
1824
|
+
let interfaceThemePreference = storedInterfaceTheme === "light" || storedInterfaceTheme === "dark" ? storedInterfaceTheme : "system";
|
|
1825
|
+
const resolvedInterfaceTheme = () => resolveInterfaceTheme(interfaceThemePreference, systemDarkTheme.matches);
|
|
1538
1826
|
host.dataset.foundryOverlay = "true";
|
|
1827
|
+
host.dataset.interfaceTheme = resolvedInterfaceTheme();
|
|
1828
|
+
host.dataset.interfaceThemePreference = interfaceThemePreference;
|
|
1539
1829
|
const shadow = host.attachShadow({ mode: "open" });
|
|
1540
1830
|
shadow.innerHTML = `<style>${PANEL_CSS}</style>
|
|
1541
1831
|
<div class="outline" hidden><span class="cross"></span><span class="measure"></span></div>
|
|
@@ -1551,13 +1841,15 @@ function installFoundryInspector(options = {}) {
|
|
|
1551
1841
|
<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
1842
|
<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
1843
|
<button class="icon-button open-commands" title="Commands" aria-label="Open commands"><i data-foundry-icon="command"></i></button>
|
|
1844
|
+
<button class="icon-button interface-theme-trigger" title="Interface theme: System" aria-label="Interface theme: System" aria-haspopup="menu" aria-expanded="false"><i data-foundry-icon="contrast"></i></button>
|
|
1554
1845
|
</nav>
|
|
1555
1846
|
<span class="workspace-divider"></span>
|
|
1556
1847
|
<button class="icon-button close" title="Exit Foundry" aria-label="Exit Foundry"><i data-foundry-icon="x"></i></button>
|
|
1557
1848
|
</header>
|
|
1849
|
+
<div class="interface-theme-menu" role="menu" aria-label="Interface theme" hidden><button role="menuitemradio" aria-checked="true" data-interface-theme-choice="system"><span>System</span><i data-foundry-icon="check"></i></button><button role="menuitemradio" aria-checked="false" data-interface-theme-choice="light"><span>Light</span><i data-foundry-icon="check"></i></button><button role="menuitemradio" aria-checked="false" data-interface-theme-choice="dark"><span>Dark</span><i data-foundry-icon="check"></i></button></div>
|
|
1558
1850
|
<aside class="layers-panel" aria-label="Foundry layers" hidden>
|
|
1559
1851
|
<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>
|
|
1852
|
+
<div class="layers-search"><input type="search" aria-label="Search layers" placeholder="Search layers" /></div><div class="layer-tree" role="tree" aria-label="Canvas layers"></div>
|
|
1561
1853
|
</aside>
|
|
1562
1854
|
<aside class="health-panel utility-panel" data-utility="health" aria-label="Design health" hidden>
|
|
1563
1855
|
<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>
|
|
@@ -1572,8 +1864,10 @@ function installFoundryInspector(options = {}) {
|
|
|
1572
1864
|
</div>
|
|
1573
1865
|
</aside>
|
|
1574
1866
|
<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><
|
|
1576
|
-
|
|
1867
|
+
<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><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>
|
|
1868
|
+
</section>
|
|
1869
|
+
<section class="review-takeover" role="dialog" aria-modal="true" aria-label="Review and apply changes" hidden>
|
|
1870
|
+
<div class="review-modal"><div class="review-view"><div class="review-head"><button class="review-back" aria-label="Back to canvas"><i data-foundry-icon="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>
|
|
1577
1871
|
</section>
|
|
1578
1872
|
<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
1873
|
<div class="toast"></div>`;
|
|
@@ -1611,8 +1905,15 @@ function installFoundryInspector(options = {}) {
|
|
|
1611
1905
|
commandPalette.className = "command-palette";
|
|
1612
1906
|
commandPalette.hidden = true;
|
|
1613
1907
|
commandPalette.setAttribute("aria-label", "Foundry commands");
|
|
1614
|
-
commandPalette.
|
|
1908
|
+
commandPalette.setAttribute("role", "dialog");
|
|
1909
|
+
commandPalette.innerHTML = `<div class="command-search"><input type="search" aria-label="Search commands" placeholder="Type a command"/><button class="icon-button close-commands" aria-label="Close commands" title="Close commands"><i data-foundry-icon="x"></i></button></div><div class="command-list"></div>`;
|
|
1615
1910
|
shadow.append(commandPalette);
|
|
1911
|
+
const colorPopover = document.createElement("section");
|
|
1912
|
+
colorPopover.className = "color-popover";
|
|
1913
|
+
colorPopover.hidden = true;
|
|
1914
|
+
colorPopover.setAttribute("role", "dialog");
|
|
1915
|
+
colorPopover.setAttribute("aria-label", "Color editor");
|
|
1916
|
+
shadow.append(colorPopover);
|
|
1616
1917
|
const libraryPanel = document.createElement("aside");
|
|
1617
1918
|
libraryPanel.className = "library-panel utility-panel";
|
|
1618
1919
|
libraryPanel.dataset.utility = "memory";
|
|
@@ -1673,6 +1974,10 @@ function installFoundryInspector(options = {}) {
|
|
|
1673
1974
|
const inspectButton = shadow.querySelector(".inspect");
|
|
1674
1975
|
const interactButton = shadow.querySelector(".interact");
|
|
1675
1976
|
const workspaceBar = shadow.querySelector(".workspace-bar");
|
|
1977
|
+
const interfaceThemeTrigger = shadow.querySelector(
|
|
1978
|
+
".interface-theme-trigger"
|
|
1979
|
+
);
|
|
1980
|
+
const interfaceThemeMenu = shadow.querySelector(".interface-theme-menu");
|
|
1676
1981
|
const sessionStatus = shadow.querySelector(".session-status");
|
|
1677
1982
|
const statusPopover = shadow.querySelector(".status-popover");
|
|
1678
1983
|
const changeDock = shadow.querySelector(".change-dock");
|
|
@@ -1709,21 +2014,66 @@ function installFoundryInspector(options = {}) {
|
|
|
1709
2014
|
const healthSummary = shadow.querySelector(".health-summary");
|
|
1710
2015
|
const healthFilters = shadow.querySelector(".health-filters");
|
|
1711
2016
|
const healthList = shadow.querySelector(".health-list");
|
|
1712
|
-
const changeCount = shadow.querySelector(".change-count");
|
|
1713
2017
|
const scope = shadow.querySelector("[data-scope]");
|
|
1714
2018
|
const breakpoint = shadow.querySelector("[data-breakpoint]");
|
|
1715
2019
|
const theme = shadow.querySelector("[data-theme]");
|
|
1716
2020
|
const state = shadow.querySelector("[data-state]");
|
|
1717
|
-
const
|
|
2021
|
+
const reviewTakeover = shadow.querySelector(".review-takeover");
|
|
2022
|
+
const reviewModal = shadow.querySelector(".review-modal");
|
|
1718
2023
|
const reviewBody = shadow.querySelector(".review-body");
|
|
1719
2024
|
const reviewCount = shadow.querySelector(".review-count");
|
|
1720
2025
|
const applyButton = shadow.querySelector(".review-actions .apply");
|
|
1721
2026
|
const reviewCancel = shadow.querySelector(".review-cancel");
|
|
2027
|
+
function applyInterfaceTheme(preference, persist = true) {
|
|
2028
|
+
interfaceThemePreference = preference;
|
|
2029
|
+
const resolved = resolvedInterfaceTheme();
|
|
2030
|
+
host.dataset.interfaceTheme = resolved;
|
|
2031
|
+
host.dataset.interfaceThemePreference = preference;
|
|
2032
|
+
const label = preference[0].toUpperCase() + preference.slice(1);
|
|
2033
|
+
interfaceThemeTrigger.title = `Interface theme: ${label}`;
|
|
2034
|
+
interfaceThemeTrigger.setAttribute("aria-label", `Interface theme: ${label}`);
|
|
2035
|
+
interfaceThemeMenu.querySelectorAll("[data-interface-theme-choice]").forEach(
|
|
2036
|
+
(button) => button.setAttribute(
|
|
2037
|
+
"aria-checked",
|
|
2038
|
+
String(button.dataset.interfaceThemeChoice === preference)
|
|
2039
|
+
)
|
|
2040
|
+
);
|
|
2041
|
+
if (persist) localStorage.setItem(interfaceThemeKey, preference);
|
|
2042
|
+
}
|
|
2043
|
+
function closeInterfaceThemeMenu(restoreFocus = false) {
|
|
2044
|
+
interfaceThemeMenu.hidden = true;
|
|
2045
|
+
interfaceThemeTrigger.setAttribute("aria-expanded", "false");
|
|
2046
|
+
if (restoreFocus) interfaceThemeTrigger.focus();
|
|
2047
|
+
}
|
|
2048
|
+
function openInterfaceThemeMenu() {
|
|
2049
|
+
const rect = interfaceThemeTrigger.getBoundingClientRect();
|
|
2050
|
+
const menuWidth = 164;
|
|
2051
|
+
interfaceThemeMenu.style.top = `${Math.round(rect.bottom + 8)}px`;
|
|
2052
|
+
interfaceThemeMenu.style.left = `${Math.round(Math.min(window.innerWidth - menuWidth - 8, Math.max(8, rect.right - menuWidth)))}px`;
|
|
2053
|
+
interfaceThemeMenu.hidden = false;
|
|
2054
|
+
interfaceThemeTrigger.setAttribute("aria-expanded", "true");
|
|
2055
|
+
interfaceThemeMenu.querySelector('[aria-checked="true"]')?.focus();
|
|
2056
|
+
}
|
|
2057
|
+
applyInterfaceTheme(interfaceThemePreference, false);
|
|
2058
|
+
const handleSystemThemeChange = () => {
|
|
2059
|
+
if (interfaceThemePreference === "system") applyInterfaceTheme("system", false);
|
|
2060
|
+
};
|
|
2061
|
+
systemDarkTheme.addEventListener("change", handleSystemThemeChange);
|
|
2062
|
+
const handleInterfaceThemeDismiss = (event) => {
|
|
2063
|
+
if (interfaceThemeMenu.hidden) return;
|
|
2064
|
+
const path = event.composedPath();
|
|
2065
|
+
if (!path.includes(interfaceThemeMenu) && !path.includes(interfaceThemeTrigger)) {
|
|
2066
|
+
closeInterfaceThemeMenu();
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
document.addEventListener("pointerdown", handleInterfaceThemeDismiss, true);
|
|
1722
2070
|
let workspaceState = { ...DEFAULT_WORKSPACE_STATE };
|
|
1723
2071
|
let selected = null;
|
|
1724
2072
|
let selectedElements = [];
|
|
1725
2073
|
let layerEntries = [];
|
|
1726
2074
|
const collapsedLayers = /* @__PURE__ */ new WeakSet();
|
|
2075
|
+
let visibleLayerElements = /* @__PURE__ */ new Set();
|
|
2076
|
+
let layerGlideTop = null;
|
|
1727
2077
|
const layerViewPreferenceKey = "__foundry_layer_view";
|
|
1728
2078
|
let layerView = sessionStorage.getItem(layerViewPreferenceKey) === "components" ? "components" : "layers";
|
|
1729
2079
|
let clickCycle = { x: -1, y: -1, at: 0, index: -1, signature: "" };
|
|
@@ -1740,18 +2090,34 @@ function installFoundryInspector(options = {}) {
|
|
|
1740
2090
|
}
|
|
1741
2091
|
})();
|
|
1742
2092
|
let reviewShowRejected = false;
|
|
2093
|
+
const collapsedReviewGroups = /* @__PURE__ */ new Set();
|
|
1743
2094
|
let reviewPoll;
|
|
1744
2095
|
let lastReviewTrigger = null;
|
|
2096
|
+
let reviewScrollTop = 0;
|
|
2097
|
+
let reviewSuspended = false;
|
|
2098
|
+
let suspendedPreviewRestore;
|
|
2099
|
+
const dockReviewButton = shadow.querySelector(".dock-review");
|
|
2100
|
+
const dockWidthKey = "__foundry_dock_width";
|
|
2101
|
+
const legacyDockWidthKey = "__foundry_panel_width";
|
|
2102
|
+
const storedDockWidth = Number(
|
|
2103
|
+
localStorage.getItem(dockWidthKey) ?? localStorage.getItem(legacyDockWidthKey)
|
|
2104
|
+
);
|
|
2105
|
+
let dockWidth = Number.isFinite(storedDockWidth) ? Math.max(340, Math.min(520, storedDockWidth)) : 384;
|
|
2106
|
+
host.style.setProperty("--fdc-dock-width", `${Math.round(dockWidth)}px`);
|
|
1745
2107
|
let designGraph = null;
|
|
1746
2108
|
const previewHistory = [];
|
|
1747
2109
|
let historyCursor = 0;
|
|
1748
2110
|
let paddingLinked = true;
|
|
2111
|
+
let radiusLinked = true;
|
|
1749
2112
|
let tokenOnly = false;
|
|
1750
2113
|
let activeControlProperty = "";
|
|
2114
|
+
const recentColors = /* @__PURE__ */ new Set();
|
|
2115
|
+
let activeColor;
|
|
1751
2116
|
let lastRecordedSummary = "";
|
|
1752
2117
|
let statusResetTimer;
|
|
1753
2118
|
let hydratedOnce = false;
|
|
1754
2119
|
const collapsedSections = /* @__PURE__ */ new Set();
|
|
2120
|
+
let sectionPreferenceTouched = sessionStorage.getItem("__foundry_collapsed_sections") != null;
|
|
1755
2121
|
try {
|
|
1756
2122
|
for (const key of JSON.parse(sessionStorage.getItem("__foundry_collapsed_sections") ?? "[]")) {
|
|
1757
2123
|
if (typeof key === "string") collapsedSections.add(key);
|
|
@@ -1841,10 +2207,7 @@ function installFoundryInspector(options = {}) {
|
|
|
1841
2207
|
"--fdc-canvas-right",
|
|
1842
2208
|
`${Math.max(12, window.innerWidth - bounds.right)}px`
|
|
1843
2209
|
);
|
|
1844
|
-
host.style.setProperty(
|
|
1845
|
-
"--fdc-tray-lift",
|
|
1846
|
-
workspaceState.tray !== "hidden" ? `${Math.max(0, window.innerHeight - bounds.bottom)}px` : "0px"
|
|
1847
|
-
);
|
|
2210
|
+
host.style.setProperty("--fdc-tray-lift", "0px");
|
|
1848
2211
|
if (workspaceState.utility) applyUtilityRect(workspaceState.utility);
|
|
1849
2212
|
}
|
|
1850
2213
|
function persistUtilityRect(utility, rect) {
|
|
@@ -1958,15 +2321,17 @@ function installFoundryInspector(options = {}) {
|
|
|
1958
2321
|
}
|
|
1959
2322
|
}
|
|
1960
2323
|
function updateChangeCount(count, latest) {
|
|
1961
|
-
changeCount.textContent = String(count);
|
|
1962
|
-
changeCount.hidden = count === 0;
|
|
1963
2324
|
changeDock.hidden = count === 0;
|
|
1964
2325
|
workspaceState = updateWorkspace(workspaceState, {
|
|
1965
|
-
type: "set-
|
|
1966
|
-
|
|
2326
|
+
type: "set-change-summary",
|
|
2327
|
+
visible: count > 0
|
|
1967
2328
|
});
|
|
1968
|
-
|
|
1969
|
-
|
|
2329
|
+
panel.classList.toggle("change-summary-visible", count > 0);
|
|
2330
|
+
if (count === 0) {
|
|
2331
|
+
reviewTakeover.hidden = true;
|
|
2332
|
+
reviewSuspended = false;
|
|
2333
|
+
dockReviewButton.textContent = "Review";
|
|
2334
|
+
}
|
|
1970
2335
|
trayCompare.disabled = count === 0 || historyCursor === 0;
|
|
1971
2336
|
changeDock.querySelector("[data-dock-count]").textContent = `${count} ${count === 1 ? "change" : "changes"} recorded`;
|
|
1972
2337
|
if (latest) {
|
|
@@ -2511,15 +2876,38 @@ function installFoundryInspector(options = {}) {
|
|
|
2511
2876
|
);
|
|
2512
2877
|
const range = visible.length > 120 && !queryValue ? virtualRange(visible.length, previousScrollTop, layerTree.clientHeight || 320, 30, 8) : { start: 0, end: visible.length, before: 0, after: 0 };
|
|
2513
2878
|
const rendered = visible.slice(range.start, range.end);
|
|
2514
|
-
|
|
2879
|
+
const hasRenderedSelection = rendered.some((entry) => selectedElements.includes(entry.element));
|
|
2880
|
+
const previouslyVisible = visibleLayerElements;
|
|
2881
|
+
visibleLayerElements = new Set(visible.map((entry) => entry.element));
|
|
2882
|
+
layerTree.innerHTML = visible.length ? `${range.before ? `<div class="layer-spacer" style="height:${range.before}px"></div>` : ""}${rendered.map((entry, renderedPosition) => {
|
|
2515
2883
|
const index = layerEntries.indexOf(entry);
|
|
2516
2884
|
const meta = entry.instrumented ? "Mapped" : entry.kind;
|
|
2517
2885
|
const collapsed = collapsedLayers.has(entry.element);
|
|
2518
|
-
|
|
2886
|
+
const position = range.start + renderedPosition;
|
|
2887
|
+
const depth = Math.min(entry.depth, 8);
|
|
2888
|
+
const selectedLayer = selectedElements.includes(entry.element);
|
|
2889
|
+
const entering = previouslyVisible.has(entry.element) ? "" : " entering";
|
|
2890
|
+
const branch = depth ? `<span class="layer-branch" aria-hidden="true"></span>` : "";
|
|
2891
|
+
return `<div class="layer-row ${selectedLayer ? "selected" : ""}${entering}" style="--layer-depth:${depth};--layer-position:${Math.min(renderedPosition, 5)};--layer-branch-left:${10 + (depth - 1) * 10}px" data-layer-row="${index}" draggable="true">${branch}<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}" role="treeitem" aria-level="${depth + 1}" aria-posinset="${position + 1}" aria-setsize="${visible.length}" aria-selected="${selectedLayer}" ${entry.hasChildren ? `aria-expanded="${!collapsed}"` : ""} tabindex="${selectedLayer || !hasRenderedSelection && renderedPosition === 0 ? "0" : "-1"}" 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>`;
|
|
2519
2892
|
}).join(
|
|
2520
2893
|
""
|
|
2521
2894
|
)}${range.after ? `<div class="layer-spacer" style="height:${range.after}px"></div>` : ""}` : '<div class="layers-empty">No visible layers match this search.</div>';
|
|
2522
2895
|
layerTree.scrollTop = previousScrollTop;
|
|
2896
|
+
const selectedRow = layerTree.querySelector(".layer-row.selected");
|
|
2897
|
+
if (selectedRow) {
|
|
2898
|
+
const targetTop = selectedRow.offsetTop;
|
|
2899
|
+
const glide = document.createElement("span");
|
|
2900
|
+
glide.className = "layer-selection-glide";
|
|
2901
|
+
glide.setAttribute("aria-hidden", "true");
|
|
2902
|
+
glide.style.setProperty("--layer-glide-y", `${layerGlideTop ?? targetTop}px`);
|
|
2903
|
+
layerTree.prepend(glide);
|
|
2904
|
+
requestAnimationFrame(() => {
|
|
2905
|
+
glide.style.setProperty("--layer-glide-y", `${targetTop}px`);
|
|
2906
|
+
});
|
|
2907
|
+
layerGlideTop = targetTop;
|
|
2908
|
+
} else {
|
|
2909
|
+
layerGlideTop = null;
|
|
2910
|
+
}
|
|
2523
2911
|
renderIcons(layerTree);
|
|
2524
2912
|
layerTree.querySelectorAll("[data-layer-row]").forEach((row) => {
|
|
2525
2913
|
const entry = layerEntries[Number(row.dataset.layerRow)];
|
|
@@ -2601,6 +2989,73 @@ function installFoundryInspector(options = {}) {
|
|
|
2601
2989
|
select(entry.element, event.shiftKey);
|
|
2602
2990
|
entry.element.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
2603
2991
|
});
|
|
2992
|
+
button.addEventListener("keydown", (event) => {
|
|
2993
|
+
const buttons = [...layerTree.querySelectorAll("[data-layer-index]")];
|
|
2994
|
+
const currentIndex = buttons.indexOf(button);
|
|
2995
|
+
const focusAt = (index) => {
|
|
2996
|
+
const target = buttons[index];
|
|
2997
|
+
if (!target) return;
|
|
2998
|
+
buttons.forEach((item) => item.tabIndex = item === target ? 0 : -1);
|
|
2999
|
+
target.focus();
|
|
3000
|
+
target.closest(".layer-row")?.scrollIntoView({ block: "nearest" });
|
|
3001
|
+
};
|
|
3002
|
+
if (event.key === "ArrowDown") {
|
|
3003
|
+
event.preventDefault();
|
|
3004
|
+
focusAt(Math.min(buttons.length - 1, currentIndex + 1));
|
|
3005
|
+
return;
|
|
3006
|
+
}
|
|
3007
|
+
if (event.key === "ArrowUp") {
|
|
3008
|
+
event.preventDefault();
|
|
3009
|
+
focusAt(Math.max(0, currentIndex - 1));
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
3012
|
+
if (event.key === "Home") {
|
|
3013
|
+
event.preventDefault();
|
|
3014
|
+
focusAt(0);
|
|
3015
|
+
return;
|
|
3016
|
+
}
|
|
3017
|
+
if (event.key === "End") {
|
|
3018
|
+
event.preventDefault();
|
|
3019
|
+
focusAt(buttons.length - 1);
|
|
3020
|
+
return;
|
|
3021
|
+
}
|
|
3022
|
+
if (event.key === "ArrowRight" && entry.hasChildren) {
|
|
3023
|
+
event.preventDefault();
|
|
3024
|
+
if (collapsedLayers.has(entry.element)) {
|
|
3025
|
+
collapsedLayers.delete(entry.element);
|
|
3026
|
+
renderLayers(false);
|
|
3027
|
+
requestAnimationFrame(
|
|
3028
|
+
() => layerTree.querySelector(
|
|
3029
|
+
`[data-layer-index="${layerEntries.indexOf(entry)}"]`
|
|
3030
|
+
)?.focus()
|
|
3031
|
+
);
|
|
3032
|
+
} else {
|
|
3033
|
+
const next = buttons[currentIndex + 1];
|
|
3034
|
+
const nextEntry = next ? layerEntries[Number(next.dataset.layerIndex)] : void 0;
|
|
3035
|
+
if (nextEntry && nextEntry.depth > entry.depth) focusAt(currentIndex + 1);
|
|
3036
|
+
}
|
|
3037
|
+
return;
|
|
3038
|
+
}
|
|
3039
|
+
if (event.key !== "ArrowLeft") return;
|
|
3040
|
+
event.preventDefault();
|
|
3041
|
+
if (entry.hasChildren && !collapsedLayers.has(entry.element)) {
|
|
3042
|
+
collapsedLayers.add(entry.element);
|
|
3043
|
+
renderLayers(false);
|
|
3044
|
+
requestAnimationFrame(
|
|
3045
|
+
() => layerTree.querySelector(
|
|
3046
|
+
`[data-layer-index="${layerEntries.indexOf(entry)}"]`
|
|
3047
|
+
)?.focus()
|
|
3048
|
+
);
|
|
3049
|
+
return;
|
|
3050
|
+
}
|
|
3051
|
+
for (let index = currentIndex - 1; index >= 0; index -= 1) {
|
|
3052
|
+
const candidate2 = layerEntries[Number(buttons[index]?.dataset.layerIndex)];
|
|
3053
|
+
if (candidate2 && candidate2.depth < entry.depth) {
|
|
3054
|
+
focusAt(index);
|
|
3055
|
+
break;
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
});
|
|
2604
3059
|
});
|
|
2605
3060
|
}
|
|
2606
3061
|
const layersPreferenceKey = "__foundry_layers_visibility";
|
|
@@ -2954,11 +3409,12 @@ function installFoundryInspector(options = {}) {
|
|
|
2954
3409
|
const unresolvedCount = changes.filter(
|
|
2955
3410
|
(change) => change.confidence === "unresolved" || change.mappingCandidates?.length > 1 && !change.selectedMappingId
|
|
2956
3411
|
).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>${[
|
|
3412
|
+
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-compare>Compare</button><button data-review-approve-exact>Include all</button><button data-review-toggle-rejected>${reviewShowRejected ? "Hide removed" : rejectedCount ? `${rejectedCount} removed` : "Removed"}</button></div></div>${[
|
|
2958
3413
|
...groups.values()
|
|
2959
3414
|
].map((group) => {
|
|
2960
3415
|
const target = group[0].target;
|
|
2961
|
-
|
|
3416
|
+
const collapsed = collapsedReviewGroups.has(target.id);
|
|
3417
|
+
return `<section class="review-group ${collapsed ? "collapsed" : ""}" data-review-target="${escapeHtml(target.id)}"><button class="review-group-title" aria-expanded="${String(!collapsed)}"><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) => {
|
|
2962
3418
|
const unresolved = change.confidence === "unresolved" || change.mappingCandidates?.length > 1 && !change.selectedMappingId;
|
|
2963
3419
|
const selectable = !unresolved && change.status !== "rejected";
|
|
2964
3420
|
const checked = selectable && reviewSelection(reviewDraft, change.id, true);
|
|
@@ -3005,6 +3461,9 @@ function installFoundryInspector(options = {}) {
|
|
|
3005
3461
|
const group = button.closest(".review-group");
|
|
3006
3462
|
if (!group) return;
|
|
3007
3463
|
group.classList.toggle("collapsed");
|
|
3464
|
+
const targetId = group.dataset.reviewTarget;
|
|
3465
|
+
if (group.classList.contains("collapsed")) collapsedReviewGroups.add(targetId);
|
|
3466
|
+
else collapsedReviewGroups.delete(targetId);
|
|
3008
3467
|
button.setAttribute("aria-expanded", String(!group.classList.contains("collapsed")));
|
|
3009
3468
|
})
|
|
3010
3469
|
);
|
|
@@ -3020,6 +3479,10 @@ function installFoundryInspector(options = {}) {
|
|
|
3020
3479
|
reviewShowRejected = !reviewShowRejected;
|
|
3021
3480
|
if (activeReviewPayload) renderReviewPayload(activeReviewPayload);
|
|
3022
3481
|
});
|
|
3482
|
+
reviewBody.querySelector("[data-review-compare]")?.addEventListener("click", () => {
|
|
3483
|
+
suspendReview();
|
|
3484
|
+
showComparison("after");
|
|
3485
|
+
});
|
|
3023
3486
|
reviewBody.querySelectorAll("[data-review-status]").forEach(
|
|
3024
3487
|
(button) => button.addEventListener("click", async () => {
|
|
3025
3488
|
button.disabled = true;
|
|
@@ -3043,10 +3506,15 @@ function installFoundryInspector(options = {}) {
|
|
|
3043
3506
|
if (!element) return;
|
|
3044
3507
|
const before = () => rawElementValue(element, change.property, change.before, change.unit);
|
|
3045
3508
|
const after = () => rawElementValue(element, change.property, change.after, change.unit);
|
|
3046
|
-
button.
|
|
3047
|
-
button.addEventListener("
|
|
3048
|
-
|
|
3049
|
-
|
|
3509
|
+
button.title = "Show the before value on the canvas";
|
|
3510
|
+
button.addEventListener("click", () => {
|
|
3511
|
+
before();
|
|
3512
|
+
suspendedPreviewRestore = after;
|
|
3513
|
+
select(element);
|
|
3514
|
+
suspendReview();
|
|
3515
|
+
element.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
|
|
3516
|
+
showToast("Before value shown \xB7 Return to continue reviewing");
|
|
3517
|
+
});
|
|
3050
3518
|
});
|
|
3051
3519
|
reviewBody.querySelectorAll("[data-review-locate]").forEach((button) => {
|
|
3052
3520
|
const change = changes.find((item) => item.id === button.dataset.reviewLocate);
|
|
@@ -3061,9 +3529,9 @@ function installFoundryInspector(options = {}) {
|
|
|
3061
3529
|
button.addEventListener("mouseleave", () => previewLayer(null));
|
|
3062
3530
|
button.addEventListener("click", () => {
|
|
3063
3531
|
select(element);
|
|
3064
|
-
|
|
3532
|
+
suspendReview();
|
|
3065
3533
|
element.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
|
|
3066
|
-
showToast("Located on the live canvas");
|
|
3534
|
+
showToast("Located on the live canvas \xB7 Return to continue reviewing");
|
|
3067
3535
|
});
|
|
3068
3536
|
});
|
|
3069
3537
|
reviewBody.querySelectorAll("[data-mapping-choice]").forEach(
|
|
@@ -3085,7 +3553,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3085
3553
|
updateReviewSelection();
|
|
3086
3554
|
}
|
|
3087
3555
|
const runStateLabels = {
|
|
3088
|
-
queued: "
|
|
3556
|
+
queued: "Queued for agent",
|
|
3089
3557
|
claimed: "Agent connected",
|
|
3090
3558
|
applying: "Applying source changes",
|
|
3091
3559
|
rebuilding: "Rebuilding and checking",
|
|
@@ -3134,11 +3602,11 @@ function installFoundryInspector(options = {}) {
|
|
|
3134
3602
|
const attention = ["needs_attention", "failed"].includes(run.state);
|
|
3135
3603
|
const passed = run.state === "passed";
|
|
3136
3604
|
const active = ["queued", "claimed", "applying", "rebuilding", "verifying"].includes(run.state);
|
|
3137
|
-
const latestMessage = run.messages.at(-1)?.message ?? run.error ?? "Apply run created.";
|
|
3605
|
+
const latestMessage = run.state === "queued" ? "The reviewed changes are queued. Keep your coding agent active, or ask it to apply your reviewed Foundry changes." : run.messages.at(-1)?.message ?? run.error ?? "Apply run created.";
|
|
3138
3606
|
captureVerifiedRun(run);
|
|
3139
3607
|
reviewCount.textContent = `Attempt ${run.attempts}`;
|
|
3140
3608
|
reviewBody.innerHTML = `<div class="run-summary"><div class="run-state"><i class="${passed ? "passed" : attention ? "attention" : active ? "active" : ""}"></i><strong>${escapeHtml(runStateLabels[run.state] ?? run.state)}</strong></div><p>${escapeHtml(latestMessage)}</p></div><div class="run-steps">${run.messages.map(
|
|
3141
|
-
(message, index) => `<div class="run-step"><span>${String(index + 1).padStart(2, "0")}</span><div><strong>${escapeHtml(runStateLabels[message.state] ?? message.state)}</strong><p>${escapeHtml(message.message)}</p></div></div>`
|
|
3609
|
+
(message, index) => `<div class="run-step"><span>${String(index + 1).padStart(2, "0")}</span><div><strong>${escapeHtml(runStateLabels[message.state] ?? message.state)}</strong><p>${escapeHtml(message.state === "queued" ? "Ready for the active coding agent to claim." : message.message)}</p></div></div>`
|
|
3142
3610
|
).join(
|
|
3143
3611
|
""
|
|
3144
3612
|
)}</div>${run.changedFiles.length ? `<div class="run-files"><strong>Changed files</strong>${run.changedFiles.map((file) => `<code>${escapeHtml(file)}</code>`).join("")}</div>` : ""}${run.validationResults.length ? `<div class="result-list">${run.validationResults.map((result) => `<div class="result-row ${result.passed ? "pass" : "fail"}"><span>${result.passed ? "Passed" : "Failed"} \xB7 ${escapeHtml(result.name)}</span><span>${escapeHtml(result.summary ?? "")}</span></div>`).join("")}</div>` : ""}${run.verificationResults.length ? `<div class="result-list">${run.verificationResults.map((result) => `<div class="result-row ${result.passed ? "pass" : "fail"}"><span>${result.passed ? "Matched" : "Mismatch"} \xB7 ${escapeHtml(result.property)}</span><span>${escapeHtml(reviewValue(result.requested))} \u2192 ${escapeHtml(reviewValue(result.rendered))}</span></div>`).join("")}</div>` : ""}`;
|
|
@@ -3168,6 +3636,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3168
3636
|
}
|
|
3169
3637
|
}
|
|
3170
3638
|
function renderReviewPayload(payload) {
|
|
3639
|
+
const preservedScrollTop = reviewBody.scrollTop || reviewScrollTop;
|
|
3171
3640
|
activeReviewPayload = payload;
|
|
3172
3641
|
const activeChanges = payload.changeSet.changes.filter(
|
|
3173
3642
|
(change) => change.status !== "rejected" && String(change.before) !== String(change.after)
|
|
@@ -3183,14 +3652,21 @@ function installFoundryInspector(options = {}) {
|
|
|
3183
3652
|
"needs_attention",
|
|
3184
3653
|
"failed"
|
|
3185
3654
|
].includes(latestRun.state);
|
|
3655
|
+
if (activeOrAttention) {
|
|
3656
|
+
const latestMessage = latestRun.messages?.at(-1)?.message;
|
|
3657
|
+
changeDock.querySelector("[data-dock-last]").textContent = latestMessage ?? runStateLabels[latestRun.state] ?? latestRun.state;
|
|
3658
|
+
}
|
|
3186
3659
|
const pending = payload.changeSet.changes.filter(
|
|
3187
3660
|
(change) => String(change.before) !== String(change.after) && (["draft", "approved", "unresolved"].includes(change.status) || reviewShowRejected && change.status === "rejected")
|
|
3188
3661
|
);
|
|
3189
3662
|
if (activeOrAttention || !pending.length && latestRun) renderApplyRun(latestRun);
|
|
3190
3663
|
else renderReviewList(pending);
|
|
3664
|
+
requestAnimationFrame(() => {
|
|
3665
|
+
if (workspaceState.reviewOpen) reviewBody.scrollTop = preservedScrollTop;
|
|
3666
|
+
});
|
|
3191
3667
|
}
|
|
3192
3668
|
async function refreshReview() {
|
|
3193
|
-
if (workspaceState.
|
|
3669
|
+
if (!workspaceState.reviewOpen || !sessionId || !token) return;
|
|
3194
3670
|
try {
|
|
3195
3671
|
const payload = await sessionRequest();
|
|
3196
3672
|
const latestRun = payload.applyRuns?.at(-1);
|
|
@@ -3217,29 +3693,38 @@ function installFoundryInspector(options = {}) {
|
|
|
3217
3693
|
showToast("Session connection is missing");
|
|
3218
3694
|
return;
|
|
3219
3695
|
}
|
|
3220
|
-
if (shadow.activeElement instanceof HTMLElement)
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3696
|
+
if (!reviewSuspended && shadow.activeElement instanceof HTMLElement)
|
|
3697
|
+
lastReviewTrigger = shadow.activeElement;
|
|
3698
|
+
suspendedPreviewRestore?.();
|
|
3699
|
+
suspendedPreviewRestore = void 0;
|
|
3700
|
+
reviewSuspended = false;
|
|
3701
|
+
dockReviewButton.textContent = "Review";
|
|
3702
|
+
workspaceState = updateWorkspace(workspaceState, { type: "set-review", open: true });
|
|
3703
|
+
reviewTakeover.hidden = false;
|
|
3224
3704
|
outline.hidden = true;
|
|
3225
|
-
positionWorkspaceSurfaces();
|
|
3226
3705
|
renderReviewPayload(await sessionRequest());
|
|
3706
|
+
requestAnimationFrame(() => {
|
|
3707
|
+
reviewBody.scrollTop = reviewScrollTop;
|
|
3708
|
+
shadow.querySelector(".review-back")?.focus();
|
|
3709
|
+
});
|
|
3227
3710
|
clearInterval(reviewPoll);
|
|
3228
3711
|
clearInterval(healthPoll);
|
|
3229
3712
|
reviewPoll = setInterval(() => void refreshReview(), 1e3);
|
|
3230
3713
|
}
|
|
3231
|
-
function closeReview() {
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
});
|
|
3236
|
-
changeDock.classList.remove("expanded");
|
|
3237
|
-
reviewView.hidden = true;
|
|
3714
|
+
function closeReview(restoreFocus = true) {
|
|
3715
|
+
reviewScrollTop = reviewBody.scrollTop;
|
|
3716
|
+
workspaceState = updateWorkspace(workspaceState, { type: "set-review", open: false });
|
|
3717
|
+
reviewTakeover.hidden = true;
|
|
3238
3718
|
clearInterval(reviewPoll);
|
|
3239
3719
|
reviewPoll = void 0;
|
|
3240
3720
|
updateOutline();
|
|
3241
|
-
|
|
3242
|
-
|
|
3721
|
+
if (restoreFocus) lastReviewTrigger?.focus();
|
|
3722
|
+
}
|
|
3723
|
+
function suspendReview() {
|
|
3724
|
+
reviewSuspended = true;
|
|
3725
|
+
dockReviewButton.textContent = "Return";
|
|
3726
|
+
closeReview(false);
|
|
3727
|
+
dockReviewButton.focus();
|
|
3243
3728
|
}
|
|
3244
3729
|
async function submitReviewedRun() {
|
|
3245
3730
|
if (!activeReviewPayload) return;
|
|
@@ -3716,13 +4201,8 @@ function installFoundryInspector(options = {}) {
|
|
|
3716
4201
|
}
|
|
3717
4202
|
function renderContextPanel(category) {
|
|
3718
4203
|
if (!selected) return "";
|
|
3719
|
-
const supportsTokens = ["layout", "typography", "color", "effects"].includes(category);
|
|
3720
|
-
const tokens = supportsTokens ? tokensForCategory(category).slice(0, 24) : [];
|
|
3721
4204
|
const component = selectedComponent();
|
|
3722
4205
|
const variants = component?.variants ?? [];
|
|
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(
|
|
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>`
|
|
3725
|
-
).join("")}</div></section>` : "";
|
|
3726
4206
|
const contrast = category === "color" ? contrastRatio(getComputedStyle(selected).color, opaqueBackground(selected)) : null;
|
|
3727
4207
|
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
4208
|
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(
|
|
@@ -3730,9 +4210,7 @@ function installFoundryInspector(options = {}) {
|
|
|
3730
4210
|
Object.entries(variant.props).map(([key, value]) => `${key}=${value}`).join(" \xB7 ")
|
|
3731
4211
|
)}</code></button>`
|
|
3732
4212
|
).join("")}</div></section>` : "";
|
|
3733
|
-
|
|
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>` : "";
|
|
3735
|
-
return `${categoryTools}${tokenMode}${health}${variantPanel}${tokenPanel}`;
|
|
4213
|
+
return `${health}${variantPanel}`;
|
|
3736
4214
|
}
|
|
3737
4215
|
async function applyControlValue(control, value, operationLabel) {
|
|
3738
4216
|
if (!selected) return;
|
|
@@ -3844,13 +4322,18 @@ function installFoundryInspector(options = {}) {
|
|
|
3844
4322
|
});
|
|
3845
4323
|
controlsRoot.querySelectorAll("[data-color-action]").forEach((button) => {
|
|
3846
4324
|
button.addEventListener("click", () => {
|
|
3847
|
-
const
|
|
3848
|
-
if (!
|
|
3849
|
-
|
|
4325
|
+
const gradient = controls.find((item) => item.property === "backgroundImage");
|
|
4326
|
+
if (!gradient) return;
|
|
4327
|
+
if (button.dataset.colorAction === "clear") {
|
|
4328
|
+
const fill = controls.find((item) => item.property === "backgroundColor");
|
|
4329
|
+
if (fill) void applyControlValue(fill, "transparent", "Clear fill color");
|
|
4330
|
+
void applyControlValue(gradient, "none", "Clear fill gradient");
|
|
4331
|
+
return;
|
|
4332
|
+
}
|
|
3850
4333
|
void applyControlValue(
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
4334
|
+
gradient,
|
|
4335
|
+
"linear-gradient(135deg, currentColor 0%, transparent 100%)",
|
|
4336
|
+
"Add linear gradient"
|
|
3854
4337
|
);
|
|
3855
4338
|
});
|
|
3856
4339
|
});
|
|
@@ -3878,6 +4361,13 @@ function installFoundryInspector(options = {}) {
|
|
|
3878
4361
|
const siblings = [...parent.children].filter((item) => item !== element);
|
|
3879
4362
|
const index = Math.max(0, Math.min(Number(value), siblings.length));
|
|
3880
4363
|
parent.insertBefore(element, siblings[index] ?? null);
|
|
4364
|
+
} else if (property === "rotate") element.style.rotate = `${value}${unit ?? "deg"}`;
|
|
4365
|
+
else if (property === "scaleX" || property === "scaleY") {
|
|
4366
|
+
const raw = getComputedStyle(element).scale;
|
|
4367
|
+
const parts = !raw || raw === "none" ? [1, 1] : raw.split(/\s+/).map(numberFrom);
|
|
4368
|
+
const x = property === "scaleX" ? Number(value) : parts[0] ?? 1;
|
|
4369
|
+
const y = property === "scaleY" ? Number(value) : parts[1] ?? parts[0] ?? 1;
|
|
4370
|
+
element.style.scale = `${x} ${y}`;
|
|
3881
4371
|
} else if (property === "textContent") element.textContent = String(value);
|
|
3882
4372
|
else if (["aria-label", "role", "tabindex", "alt", "src"].includes(property))
|
|
3883
4373
|
element.setAttribute(property, String(value));
|
|
@@ -4049,8 +4539,14 @@ function installFoundryInspector(options = {}) {
|
|
|
4049
4539
|
{ id: "redo", label: "Redo preview", shortcut: "\u21E7\u2318Z", icon: "redo-2" },
|
|
4050
4540
|
{ id: "review", label: "Review changes", shortcut: "", icon: "file-text" }
|
|
4051
4541
|
];
|
|
4052
|
-
|
|
4542
|
+
let commandReturnFocus = null;
|
|
4543
|
+
function closeCommands(restoreFocus = true) {
|
|
4053
4544
|
commandPalette.hidden = true;
|
|
4545
|
+
if (restoreFocus && commandReturnFocus?.isConnected) commandReturnFocus.focus();
|
|
4546
|
+
commandReturnFocus = null;
|
|
4547
|
+
}
|
|
4548
|
+
function runCommand(id) {
|
|
4549
|
+
closeCommands(false);
|
|
4054
4550
|
if (id === "health") openHealth();
|
|
4055
4551
|
if (id === "layers") toggleLayers(true);
|
|
4056
4552
|
if (id === "compare") showComparison("after");
|
|
@@ -4082,6 +4578,7 @@ function installFoundryInspector(options = {}) {
|
|
|
4082
4578
|
);
|
|
4083
4579
|
}
|
|
4084
4580
|
function openCommands() {
|
|
4581
|
+
commandReturnFocus = shadow.activeElement;
|
|
4085
4582
|
commandPalette.hidden = false;
|
|
4086
4583
|
const input = commandPalette.querySelector("input");
|
|
4087
4584
|
input.value = "";
|
|
@@ -4388,6 +4885,180 @@ function installFoundryInspector(options = {}) {
|
|
|
4388
4885
|
);
|
|
4389
4886
|
});
|
|
4390
4887
|
}
|
|
4888
|
+
function activeColorValue() {
|
|
4889
|
+
if (!activeColor) return "#000000";
|
|
4890
|
+
const [red, green, blue] = hsvToRgb(activeColor.hue, activeColor.saturation, activeColor.value);
|
|
4891
|
+
return activeColor.alpha >= 0.999 ? rgbHex(red, green, blue) : `rgba(${red}, ${green}, ${blue}, ${Math.round(activeColor.alpha * 100) / 100})`;
|
|
4892
|
+
}
|
|
4893
|
+
function refreshColorPopover() {
|
|
4894
|
+
if (!activeColor) return;
|
|
4895
|
+
const plane = colorPopover.querySelector(".color-plane");
|
|
4896
|
+
const handle = colorPopover.querySelector(".color-plane-handle");
|
|
4897
|
+
const hex = colorPopover.querySelector("[data-color-hex]");
|
|
4898
|
+
const hue = colorPopover.querySelector("[data-color-hue]");
|
|
4899
|
+
const alpha = colorPopover.querySelector("[data-color-alpha]");
|
|
4900
|
+
if (plane) plane.style.setProperty("--picker-hue", String(activeColor.hue));
|
|
4901
|
+
if (handle) {
|
|
4902
|
+
handle.style.left = `${activeColor.saturation * 100}%`;
|
|
4903
|
+
handle.style.top = `${(1 - activeColor.value) * 100}%`;
|
|
4904
|
+
}
|
|
4905
|
+
if (hex) hex.value = colorForInput(activeColorValue()).toUpperCase();
|
|
4906
|
+
if (hue) hue.value = String(Math.round(activeColor.hue));
|
|
4907
|
+
if (alpha) alpha.value = String(Math.round(activeColor.alpha * 100));
|
|
4908
|
+
}
|
|
4909
|
+
function previewActiveColor() {
|
|
4910
|
+
if (!activeColor) return;
|
|
4911
|
+
const value = activeColorValue();
|
|
4912
|
+
activeColor.control.apply(value);
|
|
4913
|
+
const trigger = controlsRoot.querySelector(
|
|
4914
|
+
`[data-color-control="${activeColor.index}"]`
|
|
4915
|
+
);
|
|
4916
|
+
const swatch = trigger?.querySelector(".color-swatch");
|
|
4917
|
+
const label = trigger?.querySelector(".color-value");
|
|
4918
|
+
if (swatch) {
|
|
4919
|
+
swatch.classList.toggle("transparent", activeColor.alpha === 0);
|
|
4920
|
+
swatch.style.setProperty("--swatch-color", colorForInput(value));
|
|
4921
|
+
}
|
|
4922
|
+
if (label) label.textContent = activeColor.alpha === 0 ? "Transparent" : value.toUpperCase();
|
|
4923
|
+
refreshColorPopover();
|
|
4924
|
+
updateOutline();
|
|
4925
|
+
}
|
|
4926
|
+
function commitActiveColor(before) {
|
|
4927
|
+
if (!activeColor) return;
|
|
4928
|
+
const after = activeColor.control.read();
|
|
4929
|
+
if (String(before) === String(after)) return;
|
|
4930
|
+
recentColors.delete(String(after));
|
|
4931
|
+
recentColors.add(String(after));
|
|
4932
|
+
while (recentColors.size > 8) recentColors.delete(recentColors.values().next().value);
|
|
4933
|
+
pushHistory({
|
|
4934
|
+
element: activeColor.element,
|
|
4935
|
+
property: activeColor.control.property,
|
|
4936
|
+
before,
|
|
4937
|
+
after,
|
|
4938
|
+
category: activeColor.control.category,
|
|
4939
|
+
label: activeColor.control.label
|
|
4940
|
+
});
|
|
4941
|
+
void record(activeColor.control, before, after, activeColor.element, "Choose color");
|
|
4942
|
+
}
|
|
4943
|
+
function setActiveColor(value) {
|
|
4944
|
+
if (!activeColor) return;
|
|
4945
|
+
const [red, green, blue] = hexChannels(value);
|
|
4946
|
+
const [hue, saturation, brightness] = rgbToHsv(red, green, blue);
|
|
4947
|
+
activeColor.hue = hue;
|
|
4948
|
+
activeColor.saturation = saturation;
|
|
4949
|
+
activeColor.value = brightness;
|
|
4950
|
+
activeColor.alpha = colorAlpha(value);
|
|
4951
|
+
previewActiveColor();
|
|
4952
|
+
}
|
|
4953
|
+
function openColorEditor(trigger, index) {
|
|
4954
|
+
const control = selectedControls[index];
|
|
4955
|
+
if (!control || control.kind !== "color" || !selected) return;
|
|
4956
|
+
const [red, green, blue] = hexChannels(String(control.read()));
|
|
4957
|
+
const [hue, saturation, value] = rgbToHsv(red, green, blue);
|
|
4958
|
+
activeColor = {
|
|
4959
|
+
index,
|
|
4960
|
+
control,
|
|
4961
|
+
element: selected,
|
|
4962
|
+
hue,
|
|
4963
|
+
saturation,
|
|
4964
|
+
value,
|
|
4965
|
+
alpha: colorAlpha(String(control.read()))
|
|
4966
|
+
};
|
|
4967
|
+
const tokens = tokensForCategory("color").slice(0, 18);
|
|
4968
|
+
colorPopover.innerHTML = `<div class="color-popover-head"><strong>${escapeHtml(control.label)}</strong><button class="icon-button" data-close-color aria-label="Close color editor"><i data-foundry-icon="x"></i></button></div><div class="color-plane" style="--picker-hue:${hue}"><span class="color-plane-handle"></span></div><div class="color-sliders"><label>Hue<input data-color-hue type="range" min="0" max="359" value="${Math.round(hue)}"/></label><label>Alpha<input data-color-alpha type="range" min="0" max="100" value="${Math.round(activeColor.alpha * 100)}"/></label></div><div class="color-fields"><input data-color-hex aria-label="Hex color" value="${colorForInput(String(control.read())).toUpperCase()}"/><button data-eyedropper aria-label="Pick color from page" title="Eyedropper"><i data-foundry-icon="palette"></i></button></div>${tokens.length ? `<div class="color-popover-section"><strong>Project colors</strong><div class="color-swatches">${tokens.map((token2) => `<button data-color-value="${escapeHtml(token2.value)}" style="--picker-swatch:${escapeHtml(token2.value)}" aria-label="Use ${escapeHtml(token2.name)}" title="${escapeHtml(`${token2.name} \xB7 ${token2.value}`)}"></button>`).join("")}</div></div>` : ""}${recentColors.size ? `<div class="color-popover-section"><strong>Recent</strong><div class="color-swatches">${[
|
|
4969
|
+
...recentColors
|
|
4970
|
+
].reverse().map(
|
|
4971
|
+
(color) => `<button data-color-value="${escapeHtml(color)}" style="--picker-swatch:${escapeHtml(color)}" aria-label="Use recent color ${escapeHtml(color)}"></button>`
|
|
4972
|
+
).join("")}</div></div>` : ""}`;
|
|
4973
|
+
renderIcons(colorPopover);
|
|
4974
|
+
colorPopover.hidden = false;
|
|
4975
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
4976
|
+
const popoverRect = colorPopover.getBoundingClientRect();
|
|
4977
|
+
const left = Math.max(8, Math.min(window.innerWidth - popoverRect.width - 8, triggerRect.left));
|
|
4978
|
+
const preferredTop = triggerRect.bottom + 6;
|
|
4979
|
+
const top = preferredTop + popoverRect.height <= window.innerHeight - 8 ? preferredTop : Math.max(8, triggerRect.top - popoverRect.height - 6);
|
|
4980
|
+
colorPopover.style.left = `${Math.round(left)}px`;
|
|
4981
|
+
colorPopover.style.top = `${Math.round(top)}px`;
|
|
4982
|
+
refreshColorPopover();
|
|
4983
|
+
colorPopover.querySelector("[data-close-color]")?.addEventListener("click", () => {
|
|
4984
|
+
colorPopover.hidden = true;
|
|
4985
|
+
activeColor = void 0;
|
|
4986
|
+
trigger.focus();
|
|
4987
|
+
});
|
|
4988
|
+
const plane = colorPopover.querySelector(".color-plane");
|
|
4989
|
+
plane.addEventListener("pointerdown", (event) => {
|
|
4990
|
+
if (!activeColor) return;
|
|
4991
|
+
const before = activeColor.control.read();
|
|
4992
|
+
plane.setPointerCapture(event.pointerId);
|
|
4993
|
+
const update = (pointer) => {
|
|
4994
|
+
if (!activeColor) return;
|
|
4995
|
+
const rect = plane.getBoundingClientRect();
|
|
4996
|
+
activeColor.saturation = Math.max(
|
|
4997
|
+
0,
|
|
4998
|
+
Math.min(1, (pointer.clientX - rect.left) / rect.width)
|
|
4999
|
+
);
|
|
5000
|
+
activeColor.value = 1 - Math.max(0, Math.min(1, (pointer.clientY - rect.top) / rect.height));
|
|
5001
|
+
previewActiveColor();
|
|
5002
|
+
};
|
|
5003
|
+
const finish = (pointer) => {
|
|
5004
|
+
update(pointer);
|
|
5005
|
+
commitActiveColor(before);
|
|
5006
|
+
plane.removeEventListener("pointermove", update);
|
|
5007
|
+
plane.removeEventListener("pointerup", finish);
|
|
5008
|
+
plane.removeEventListener("pointercancel", finish);
|
|
5009
|
+
};
|
|
5010
|
+
update(event);
|
|
5011
|
+
plane.addEventListener("pointermove", update);
|
|
5012
|
+
plane.addEventListener("pointerup", finish);
|
|
5013
|
+
plane.addEventListener("pointercancel", finish);
|
|
5014
|
+
});
|
|
5015
|
+
const bindSlider = (selector, apply) => {
|
|
5016
|
+
const slider = colorPopover.querySelector(selector);
|
|
5017
|
+
let before = control.read();
|
|
5018
|
+
slider.addEventListener("pointerdown", () => {
|
|
5019
|
+
before = control.read();
|
|
5020
|
+
});
|
|
5021
|
+
slider.addEventListener("input", () => {
|
|
5022
|
+
apply(Number(slider.value));
|
|
5023
|
+
previewActiveColor();
|
|
5024
|
+
});
|
|
5025
|
+
slider.addEventListener("change", () => commitActiveColor(before));
|
|
5026
|
+
};
|
|
5027
|
+
bindSlider("[data-color-hue]", (next) => {
|
|
5028
|
+
if (activeColor) activeColor.hue = next;
|
|
5029
|
+
});
|
|
5030
|
+
bindSlider("[data-color-alpha]", (next) => {
|
|
5031
|
+
if (activeColor) activeColor.alpha = next / 100;
|
|
5032
|
+
});
|
|
5033
|
+
const hexField = colorPopover.querySelector("[data-color-hex]");
|
|
5034
|
+
let hexBefore = control.read();
|
|
5035
|
+
hexField.addEventListener("focus", () => {
|
|
5036
|
+
hexBefore = control.read();
|
|
5037
|
+
});
|
|
5038
|
+
hexField.addEventListener("change", () => {
|
|
5039
|
+
setActiveColor(hexField.value);
|
|
5040
|
+
commitActiveColor(hexBefore);
|
|
5041
|
+
});
|
|
5042
|
+
colorPopover.querySelectorAll("[data-color-value]").forEach((button) => {
|
|
5043
|
+
button.addEventListener("click", () => {
|
|
5044
|
+
const before = control.read();
|
|
5045
|
+
setActiveColor(button.dataset.colorValue ?? "#000000");
|
|
5046
|
+
commitActiveColor(before);
|
|
5047
|
+
});
|
|
5048
|
+
});
|
|
5049
|
+
colorPopover.querySelector("[data-eyedropper]")?.addEventListener("click", async () => {
|
|
5050
|
+
const EyeDropper = window.EyeDropper;
|
|
5051
|
+
if (!EyeDropper) {
|
|
5052
|
+
showToast("Eyedropper is not available in this browser");
|
|
5053
|
+
return;
|
|
5054
|
+
}
|
|
5055
|
+
const before = control.read();
|
|
5056
|
+
const result = await new EyeDropper().open().catch(() => void 0);
|
|
5057
|
+
if (!result) return;
|
|
5058
|
+
setActiveColor(result.sRGBHex);
|
|
5059
|
+
commitActiveColor(before);
|
|
5060
|
+
});
|
|
5061
|
+
}
|
|
4391
5062
|
function renderControls() {
|
|
4392
5063
|
renderToolTabs();
|
|
4393
5064
|
if (!selected) {
|
|
@@ -4405,20 +5076,55 @@ function installFoundryInspector(options = {}) {
|
|
|
4405
5076
|
{
|
|
4406
5077
|
key: "layout",
|
|
4407
5078
|
category: "layout",
|
|
4408
|
-
label: "Layout
|
|
5079
|
+
label: "Layout",
|
|
4409
5080
|
icon: CATEGORY_ICONS.layout,
|
|
4410
5081
|
sectionLabels: ["Flow", "Padding", "Margin"],
|
|
4411
5082
|
showContext: true
|
|
4412
5083
|
},
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
5084
|
+
{
|
|
5085
|
+
key: "typography",
|
|
5086
|
+
category: "typography",
|
|
5087
|
+
label: "Typography",
|
|
5088
|
+
icon: CATEGORY_ICONS.typography,
|
|
5089
|
+
showContext: true
|
|
5090
|
+
},
|
|
5091
|
+
{
|
|
5092
|
+
key: "appearance",
|
|
5093
|
+
category: "color",
|
|
5094
|
+
label: "Appearance",
|
|
5095
|
+
icon: "eye",
|
|
5096
|
+
sectionLabels: ["Appearance"]
|
|
5097
|
+
},
|
|
5098
|
+
{
|
|
5099
|
+
key: "fill",
|
|
5100
|
+
category: "color",
|
|
5101
|
+
label: "Fill",
|
|
5102
|
+
icon: CATEGORY_ICONS.color,
|
|
5103
|
+
sectionLabels: ["Fill"],
|
|
5104
|
+
showContext: true
|
|
5105
|
+
},
|
|
5106
|
+
{
|
|
5107
|
+
key: "stroke",
|
|
5108
|
+
category: "effects",
|
|
5109
|
+
label: "Stroke",
|
|
5110
|
+
icon: "box",
|
|
5111
|
+
sectionLabels: ["Stroke"]
|
|
5112
|
+
},
|
|
5113
|
+
{
|
|
5114
|
+
key: "effects",
|
|
5115
|
+
category: "effects",
|
|
5116
|
+
label: "Effects",
|
|
5117
|
+
icon: CATEGORY_ICONS.effects,
|
|
5118
|
+
sectionLabels: ["Corners", "Effects"],
|
|
5119
|
+
showContext: true
|
|
5120
|
+
},
|
|
5121
|
+
...["content", "accessibility"].map((category) => ({
|
|
5122
|
+
key: category,
|
|
5123
|
+
category,
|
|
5124
|
+
label: CATEGORY_LABELS[category],
|
|
5125
|
+
icon: CATEGORY_ICONS[category],
|
|
5126
|
+
showContext: true
|
|
5127
|
+
}))
|
|
4422
5128
|
];
|
|
4423
5129
|
const indexedControls = selectedControls.map((control, index) => ({ control, index })).filter(
|
|
4424
5130
|
({ control }) => tokenOnly ? matchingTokens(
|
|
@@ -4445,7 +5151,8 @@ function installFoundryInspector(options = {}) {
|
|
|
4445
5151
|
entries.forEach(({ control }) => renderedProperties.add(control.property));
|
|
4446
5152
|
if (!entries.length) return "";
|
|
4447
5153
|
const sectionKey = `${group.key}:${section.label}`;
|
|
4448
|
-
|
|
5154
|
+
const sectionActions = section.label === "Position and size" ? '<span class="section-actions"><button class="section-action" data-layout-action="lock" aria-label="Lock aspect ratio" title="Lock aspect ratio"><i data-foundry-icon="lock"></i></button></span>' : section.label === "Padding" ? `<span class="section-actions"><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></span>` : section.label === "Typeface" ? '<span class="section-actions type-presets"><button data-type-preset="compact">S</button><button data-type-preset="body">M</button><button data-type-preset="display">L</button></span>' : section.label === "Fill" ? '<span class="section-actions"><button class="section-action" data-color-action="gradient" aria-label="Add linear gradient" title="Add gradient"><i data-foundry-icon="sparkles"></i></button><button class="section-action" data-color-action="clear" aria-label="Clear fill" title="Clear fill"><i data-foundry-icon="x"></i></button></span>' : section.label === "Corners" ? `<span class="section-actions"><button class="section-action ${radiusLinked ? "active" : ""}" data-radius-link aria-label="${radiusLinked ? "Edit corner radii independently" : "Link corner radii"}"><i data-foundry-icon="${radiusLinked ? "link-2" : "unlink-2"}"></i></button></span>` : "";
|
|
5155
|
+
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>${sectionActions}</div><div class="section-grid ${section.columns === 2 ? "two" : ""} ${section.stacked ? "stacked" : ""}">${entries.map(
|
|
4449
5156
|
({ control, index }) => renderPropertyControl(control, index, section.prefixes?.[control.property])
|
|
4450
5157
|
).join("")}</div></section>`;
|
|
4451
5158
|
}).join("");
|
|
@@ -4454,7 +5161,8 @@ function installFoundryInspector(options = {}) {
|
|
|
4454
5161
|
);
|
|
4455
5162
|
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
5163
|
const categoryKey = `category:${group.key}`;
|
|
4457
|
-
|
|
5164
|
+
const categoryAction = group.key === "layout" ? '<button class="category-action" data-layout-action="tidy"><i data-foundry-icon="wand-sparkles"></i><span>Tidy</span></button>' : "";
|
|
5165
|
+
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>${categoryAction}<span class="property-count">${controls.length}</span></div><div class="category-body">${group.showContext ? renderContextPanel(group.category) : ""}${sections}${remainingSection}</div></section>`;
|
|
4458
5166
|
}).join("");
|
|
4459
5167
|
const currentBaseline = baselineForContext(
|
|
4460
5168
|
designMemory,
|
|
@@ -4476,6 +5184,7 @@ function installFoundryInspector(options = {}) {
|
|
|
4476
5184
|
button.setAttribute("aria-expanded", String(!collapsed));
|
|
4477
5185
|
if (collapsed) collapsedSections.add(key);
|
|
4478
5186
|
else collapsedSections.delete(key);
|
|
5187
|
+
sectionPreferenceTouched = true;
|
|
4479
5188
|
sessionStorage.setItem(
|
|
4480
5189
|
"__foundry_collapsed_sections",
|
|
4481
5190
|
JSON.stringify([...collapsedSections])
|
|
@@ -4488,6 +5197,12 @@ function installFoundryInspector(options = {}) {
|
|
|
4488
5197
|
renderControls();
|
|
4489
5198
|
})
|
|
4490
5199
|
);
|
|
5200
|
+
controlsRoot.querySelectorAll("[data-radius-link]").forEach(
|
|
5201
|
+
(button) => button.addEventListener("click", () => {
|
|
5202
|
+
radiusLinked = !radiusLinked;
|
|
5203
|
+
renderControls();
|
|
5204
|
+
})
|
|
5205
|
+
);
|
|
4491
5206
|
indexedControls.forEach(({ control, index }) => {
|
|
4492
5207
|
const matches = matchingTokens(
|
|
4493
5208
|
designGraph?.tokens ?? [],
|
|
@@ -4495,7 +5210,8 @@ function installFoundryInspector(options = {}) {
|
|
|
4495
5210
|
`${control.value}${control.unit ?? ""}`
|
|
4496
5211
|
);
|
|
4497
5212
|
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
|
-
|
|
5213
|
+
const availableTokens = tokensForCategory(control.category);
|
|
5214
|
+
if (!tokenEligible || !availableTokens.length) return;
|
|
4499
5215
|
const field = controlsRoot.querySelector(`[data-control="${index}"]`);
|
|
4500
5216
|
const label = field?.closest("label");
|
|
4501
5217
|
if (!label) return;
|
|
@@ -4503,14 +5219,27 @@ function installFoundryInspector(options = {}) {
|
|
|
4503
5219
|
"beforeend",
|
|
4504
5220
|
matches.length ? `<span class="token-provenance">Uses ${escapeHtml(matches[0].name)}</span>` : '<span class="token-provenance literal">Literal value \xB7 consider a project token</span>'
|
|
4505
5221
|
);
|
|
4506
|
-
if (!matches.length) return;
|
|
4507
5222
|
label.insertAdjacentHTML(
|
|
4508
5223
|
"beforeend",
|
|
4509
|
-
`<span class="token-
|
|
4510
|
-
(token2) => `<button type="button" class="token-
|
|
4511
|
-
).join("")}</span>`
|
|
5224
|
+
`<span class="token-menu-wrap"><button type="button" class="token-menu-trigger" data-token-menu-trigger="${index}" aria-expanded="false" aria-label="Choose a project token"><i data-foundry-icon="bookmark"></i></button><span class="token-menu" data-token-menu="${index}" hidden>${availableTokens.map(
|
|
5225
|
+
(token2) => `<button type="button" class="token-option" data-token-control="${index}" data-token-value="${escapeHtml(token2.value)}" title="${escapeHtml(token2.value)}">${control.category === "color" ? `<span class="swatch" style="--token-color:${escapeHtml(token2.value)}"></span>` : ""}<span>${escapeHtml(token2.name)}</span><code>${escapeHtml(token2.value)}</code></button>`
|
|
5226
|
+
).join("")}</span></span>`
|
|
4512
5227
|
);
|
|
4513
5228
|
});
|
|
5229
|
+
renderIcons(controlsRoot);
|
|
5230
|
+
controlsRoot.querySelectorAll("[data-token-menu-trigger]").forEach((button) => {
|
|
5231
|
+
button.addEventListener("click", () => {
|
|
5232
|
+
const menu = controlsRoot.querySelector(
|
|
5233
|
+
`[data-token-menu="${button.dataset.tokenMenuTrigger}"]`
|
|
5234
|
+
);
|
|
5235
|
+
if (!menu) return;
|
|
5236
|
+
controlsRoot.querySelectorAll("[data-token-menu]").forEach((candidate2) => {
|
|
5237
|
+
if (candidate2 !== menu) candidate2.hidden = true;
|
|
5238
|
+
});
|
|
5239
|
+
menu.hidden = !menu.hidden;
|
|
5240
|
+
button.setAttribute("aria-expanded", String(!menu.hidden));
|
|
5241
|
+
});
|
|
5242
|
+
});
|
|
4514
5243
|
controlsRoot.querySelectorAll("[data-reset-control]").forEach((button) => {
|
|
4515
5244
|
button.addEventListener("click", () => {
|
|
4516
5245
|
const control = selectedControls[Number(button.dataset.resetControl)];
|
|
@@ -4628,10 +5357,38 @@ function installFoundryInspector(options = {}) {
|
|
|
4628
5357
|
fieldRecorders.get(linkedIndex)?.push(linkedBefore, value);
|
|
4629
5358
|
});
|
|
4630
5359
|
}
|
|
5360
|
+
const radiusProperties = [
|
|
5361
|
+
"borderTopLeftRadius",
|
|
5362
|
+
"borderTopRightRadius",
|
|
5363
|
+
"borderBottomLeftRadius",
|
|
5364
|
+
"borderBottomRightRadius"
|
|
5365
|
+
];
|
|
5366
|
+
if (radiusLinked && (control.property === "borderRadius" || radiusProperties.includes(control.property))) {
|
|
5367
|
+
indexedControls.forEach(({ control: linkedControl, index: linkedIndex }) => {
|
|
5368
|
+
if (linkedControl === control || !radiusProperties.includes(linkedControl.property))
|
|
5369
|
+
return;
|
|
5370
|
+
const linkedBefore = linkedControl.read();
|
|
5371
|
+
linkedControl.apply(value);
|
|
5372
|
+
const linkedField = controlsRoot.querySelector(
|
|
5373
|
+
`[data-control="${linkedIndex}"]`
|
|
5374
|
+
);
|
|
5375
|
+
if (linkedField) linkedField.value = String(value);
|
|
5376
|
+
fieldRecorders.get(linkedIndex)?.push(linkedBefore, value);
|
|
5377
|
+
});
|
|
5378
|
+
}
|
|
4631
5379
|
updateOutline();
|
|
4632
5380
|
recorder.push(before, value);
|
|
4633
5381
|
});
|
|
4634
5382
|
});
|
|
5383
|
+
controlsRoot.querySelectorAll("[data-color-control]").forEach((button) => {
|
|
5384
|
+
button.addEventListener("click", () => {
|
|
5385
|
+
const index = Number(button.dataset.colorControl);
|
|
5386
|
+
const control = selectedControls[index];
|
|
5387
|
+
if (!control) return;
|
|
5388
|
+
activeControlProperty = control.property;
|
|
5389
|
+
openColorEditor(button, index);
|
|
5390
|
+
});
|
|
5391
|
+
});
|
|
4635
5392
|
controlsRoot.querySelectorAll("[data-token-control]").forEach((button) => {
|
|
4636
5393
|
button.addEventListener("click", () => {
|
|
4637
5394
|
const index = Number(button.dataset.tokenControl);
|
|
@@ -4639,8 +5396,16 @@ function installFoundryInspector(options = {}) {
|
|
|
4639
5396
|
`[data-control="${index}"]`
|
|
4640
5397
|
);
|
|
4641
5398
|
const control = selectedControls[index];
|
|
4642
|
-
if (!
|
|
5399
|
+
if (!control) return;
|
|
4643
5400
|
const raw = button.dataset.tokenValue ?? "";
|
|
5401
|
+
if (control.kind === "color") {
|
|
5402
|
+
void applyControlValue(control, raw, "Use project color").then(() => {
|
|
5403
|
+
if (selected) selectedControls = controlsFor(selected);
|
|
5404
|
+
renderControls();
|
|
5405
|
+
});
|
|
5406
|
+
return;
|
|
5407
|
+
}
|
|
5408
|
+
if (!field) return;
|
|
4644
5409
|
field.value = control.kind === "number" ? String(numberFrom(raw)) : raw;
|
|
4645
5410
|
field.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
4646
5411
|
});
|
|
@@ -4651,6 +5416,8 @@ function installFoundryInspector(options = {}) {
|
|
|
4651
5416
|
}
|
|
4652
5417
|
function select(element, additive = false) {
|
|
4653
5418
|
if (element === host || host.contains(element)) return;
|
|
5419
|
+
colorPopover.hidden = true;
|
|
5420
|
+
activeColor = void 0;
|
|
4654
5421
|
if (additive && selectedElements.includes(element)) {
|
|
4655
5422
|
selectedElements = selectedElements.filter((item) => item !== element);
|
|
4656
5423
|
if (!selectedElements.length) {
|
|
@@ -4666,6 +5433,40 @@ function installFoundryInspector(options = {}) {
|
|
|
4666
5433
|
selectedElements = [element];
|
|
4667
5434
|
selected = element;
|
|
4668
5435
|
}
|
|
5436
|
+
if (!sectionPreferenceTouched) {
|
|
5437
|
+
const categoryKeys = [
|
|
5438
|
+
"position",
|
|
5439
|
+
"layout",
|
|
5440
|
+
"typography",
|
|
5441
|
+
"appearance",
|
|
5442
|
+
"fill",
|
|
5443
|
+
"stroke",
|
|
5444
|
+
"effects",
|
|
5445
|
+
"content",
|
|
5446
|
+
"accessibility",
|
|
5447
|
+
"motion"
|
|
5448
|
+
];
|
|
5449
|
+
categoryKeys.forEach((key) => collapsedSections.add(`category:${key}`));
|
|
5450
|
+
collapsedSections.delete("category:position");
|
|
5451
|
+
collapsedSections.delete("category:layout");
|
|
5452
|
+
collapsedSections.delete("category:appearance");
|
|
5453
|
+
collapsedSections.delete("category:fill");
|
|
5454
|
+
const isText = element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element.children.length === 0 && Boolean(element.textContent?.trim());
|
|
5455
|
+
const isMedia = element instanceof HTMLImageElement;
|
|
5456
|
+
if (isText) {
|
|
5457
|
+
collapsedSections.delete("category:typography");
|
|
5458
|
+
collapsedSections.delete("category:content");
|
|
5459
|
+
}
|
|
5460
|
+
if (isMedia) {
|
|
5461
|
+
collapsedSections.delete("category:content");
|
|
5462
|
+
collapsedSections.delete("category:accessibility");
|
|
5463
|
+
}
|
|
5464
|
+
if (Number.parseFloat(getComputedStyle(element).borderWidth) > 0)
|
|
5465
|
+
collapsedSections.delete("category:stroke");
|
|
5466
|
+
if (getComputedStyle(element).boxShadow !== "none" || Number.parseFloat(getComputedStyle(element).borderRadius) > 0)
|
|
5467
|
+
collapsedSections.delete("category:effects");
|
|
5468
|
+
if (element.getAnimations().length) collapsedSections.delete("category:motion");
|
|
5469
|
+
}
|
|
4669
5470
|
selectedControls = controlsFor(element);
|
|
4670
5471
|
const target = targetFor(element);
|
|
4671
5472
|
panel.classList.add("has-selection");
|
|
@@ -4702,6 +5503,8 @@ function installFoundryInspector(options = {}) {
|
|
|
4702
5503
|
});
|
|
4703
5504
|
}
|
|
4704
5505
|
function clearSelection() {
|
|
5506
|
+
colorPopover.hidden = true;
|
|
5507
|
+
activeColor = void 0;
|
|
4705
5508
|
selected = null;
|
|
4706
5509
|
selectedElements = [];
|
|
4707
5510
|
selectedControls = [];
|
|
@@ -5067,25 +5870,25 @@ function installFoundryInspector(options = {}) {
|
|
|
5067
5870
|
method: "POST",
|
|
5068
5871
|
body: JSON.stringify({ runId, results })
|
|
5069
5872
|
});
|
|
5070
|
-
if (workspaceState.
|
|
5873
|
+
if (workspaceState.reviewOpen) renderReviewPayload(payload);
|
|
5071
5874
|
showToast(
|
|
5072
5875
|
`${results.filter((result) => result.passed).length}/${results.length} changes verified`
|
|
5073
5876
|
);
|
|
5074
5877
|
}
|
|
5075
5878
|
function installPanelResizer() {
|
|
5076
5879
|
const resizer = shadow.querySelector(".panel-resizer");
|
|
5077
|
-
const savedWidth = Number(localStorage.getItem("__foundry_panel_width"));
|
|
5078
|
-
if (Number.isFinite(savedWidth) && savedWidth >= 300) panel.style.width = `${savedWidth}px`;
|
|
5079
5880
|
resizer.addEventListener("pointerdown", (event) => {
|
|
5080
|
-
if (event.button !== 0) return;
|
|
5881
|
+
if (event.button !== 0 || window.matchMedia("(max-width: 680px)").matches) return;
|
|
5081
5882
|
const startX = event.clientX;
|
|
5082
|
-
const startWidth =
|
|
5883
|
+
const startWidth = dockWidth;
|
|
5083
5884
|
resizer.setPointerCapture(event.pointerId);
|
|
5084
5885
|
event.preventDefault();
|
|
5085
5886
|
const move = (pointer) => {
|
|
5086
5887
|
const maximum = Math.min(520, window.innerWidth - 24);
|
|
5087
|
-
const next = Math.max(
|
|
5088
|
-
|
|
5888
|
+
const next = Math.max(340, Math.min(maximum, startWidth + startX - pointer.clientX));
|
|
5889
|
+
dockWidth = Math.round(next);
|
|
5890
|
+
host.style.setProperty("--fdc-dock-width", `${dockWidth}px`);
|
|
5891
|
+
positionWorkspaceSurfaces();
|
|
5089
5892
|
};
|
|
5090
5893
|
const finish = (pointer) => {
|
|
5091
5894
|
resizer.removeEventListener("pointermove", move);
|
|
@@ -5093,10 +5896,8 @@ function installFoundryInspector(options = {}) {
|
|
|
5093
5896
|
resizer.removeEventListener("pointercancel", finish);
|
|
5094
5897
|
if (resizer.hasPointerCapture(pointer.pointerId))
|
|
5095
5898
|
resizer.releasePointerCapture(pointer.pointerId);
|
|
5096
|
-
localStorage.setItem(
|
|
5097
|
-
|
|
5098
|
-
String(Math.round(panel.getBoundingClientRect().width))
|
|
5099
|
-
);
|
|
5899
|
+
localStorage.setItem(dockWidthKey, String(dockWidth));
|
|
5900
|
+
localStorage.removeItem(legacyDockWidthKey);
|
|
5100
5901
|
};
|
|
5101
5902
|
resizer.addEventListener("pointermove", move);
|
|
5102
5903
|
resizer.addEventListener("pointerup", finish);
|
|
@@ -5232,6 +6033,16 @@ function installFoundryInspector(options = {}) {
|
|
|
5232
6033
|
}
|
|
5233
6034
|
});
|
|
5234
6035
|
statusPopover.querySelector("[data-status-retry]").addEventListener("click", () => void hydrateSession());
|
|
6036
|
+
interfaceThemeTrigger.addEventListener("click", () => {
|
|
6037
|
+
if (interfaceThemeMenu.hidden) openInterfaceThemeMenu();
|
|
6038
|
+
else closeInterfaceThemeMenu();
|
|
6039
|
+
});
|
|
6040
|
+
interfaceThemeMenu.querySelectorAll("[data-interface-theme-choice]").forEach(
|
|
6041
|
+
(button) => button.addEventListener("click", () => {
|
|
6042
|
+
applyInterfaceTheme(button.dataset.interfaceThemeChoice);
|
|
6043
|
+
closeInterfaceThemeMenu(true);
|
|
6044
|
+
})
|
|
6045
|
+
);
|
|
5235
6046
|
changeDock.querySelector(".dock-undo")?.addEventListener("click", () => void replayHistory(-1));
|
|
5236
6047
|
changeDock.querySelector(".dock-review")?.addEventListener("click", () => void openReview());
|
|
5237
6048
|
onboarding.querySelector(".onboarding-start")?.addEventListener("click", () => {
|
|
@@ -5332,13 +6143,14 @@ function installFoundryInspector(options = {}) {
|
|
|
5332
6143
|
);
|
|
5333
6144
|
comparisonStage.querySelector("[data-close-comparison-stage]").addEventListener("click", closeSplitComparison);
|
|
5334
6145
|
const commandInput = commandPalette.querySelector("input");
|
|
6146
|
+
commandPalette.querySelector(".close-commands")?.addEventListener("click", () => closeCommands());
|
|
5335
6147
|
commandInput.addEventListener("input", () => renderCommands(commandInput.value));
|
|
5336
6148
|
commandInput.addEventListener("keydown", (event) => {
|
|
5337
6149
|
if (event.key === "Enter") {
|
|
5338
6150
|
const active = commandPalette.querySelector(".command-item.active");
|
|
5339
6151
|
if (active) runCommand(active.dataset.command);
|
|
5340
6152
|
}
|
|
5341
|
-
if (event.key === "Escape")
|
|
6153
|
+
if (event.key === "Escape") closeCommands();
|
|
5342
6154
|
});
|
|
5343
6155
|
shadow.querySelector(".close")?.addEventListener("click", destroyInspector);
|
|
5344
6156
|
shadow.querySelector(".open-workbench")?.addEventListener("click", openWorkbench);
|
|
@@ -5364,7 +6176,7 @@ function installFoundryInspector(options = {}) {
|
|
|
5364
6176
|
shadow.querySelector(".redo")?.addEventListener("click", () => void replayHistory(1));
|
|
5365
6177
|
shadow.querySelector(".align")?.addEventListener("click", () => void alignSelected());
|
|
5366
6178
|
shadow.querySelector(".distribute")?.addEventListener("click", () => void distributeSelected());
|
|
5367
|
-
shadow.querySelector(".review-back")?.addEventListener("click", closeReview);
|
|
6179
|
+
shadow.querySelector(".review-back")?.addEventListener("click", () => closeReview());
|
|
5368
6180
|
reviewCancel.addEventListener("click", () => {
|
|
5369
6181
|
if (reviewCancel.dataset.action === "cancel") void cancelRun();
|
|
5370
6182
|
else closeReview();
|
|
@@ -5374,6 +6186,25 @@ function installFoundryInspector(options = {}) {
|
|
|
5374
6186
|
if (applyButton.dataset.action === "retry") void retryRun();
|
|
5375
6187
|
});
|
|
5376
6188
|
function handleGlobalShortcuts(event) {
|
|
6189
|
+
if (workspaceState.reviewOpen && event.key === "Tab") {
|
|
6190
|
+
const focusable = [
|
|
6191
|
+
...reviewModal.querySelectorAll(
|
|
6192
|
+
'button:not(:disabled),input:not(:disabled),select:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex="-1"])'
|
|
6193
|
+
)
|
|
6194
|
+
].filter((element) => element.offsetParent !== null);
|
|
6195
|
+
if (focusable.length) {
|
|
6196
|
+
const first = focusable[0];
|
|
6197
|
+
const last = focusable.at(-1);
|
|
6198
|
+
if (event.shiftKey && shadow.activeElement === first) {
|
|
6199
|
+
event.preventDefault();
|
|
6200
|
+
last.focus();
|
|
6201
|
+
} else if (!event.shiftKey && shadow.activeElement === last) {
|
|
6202
|
+
event.preventDefault();
|
|
6203
|
+
first.focus();
|
|
6204
|
+
}
|
|
6205
|
+
}
|
|
6206
|
+
return;
|
|
6207
|
+
}
|
|
5377
6208
|
const editable = event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement || event.target instanceof HTMLSelectElement || event.target instanceof HTMLElement && event.target.isContentEditable;
|
|
5378
6209
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
|
|
5379
6210
|
event.preventDefault();
|
|
@@ -5412,13 +6243,22 @@ function installFoundryInspector(options = {}) {
|
|
|
5412
6243
|
return;
|
|
5413
6244
|
}
|
|
5414
6245
|
if (event.key !== "Escape") return;
|
|
5415
|
-
if (
|
|
5416
|
-
|
|
6246
|
+
if (workspaceState.reviewOpen) {
|
|
6247
|
+
const nested = reviewModal.querySelector("details[open]");
|
|
6248
|
+
if (nested) nested.open = false;
|
|
6249
|
+
else closeReview();
|
|
6250
|
+
return;
|
|
6251
|
+
}
|
|
6252
|
+
if (!interfaceThemeMenu.hidden) closeInterfaceThemeMenu(true);
|
|
6253
|
+
else if (!colorPopover.hidden) {
|
|
6254
|
+
colorPopover.hidden = true;
|
|
6255
|
+
activeColor = void 0;
|
|
6256
|
+
} else if (!comparisonStage.hidden) closeSplitComparison();
|
|
6257
|
+
else if (!commandPalette.hidden) closeCommands();
|
|
5417
6258
|
else if (!libraryPanel.hidden) closeDesignMemory();
|
|
5418
6259
|
else if (!healthPanel.hidden) closeHealth();
|
|
5419
6260
|
else if (comparisonActive) closeComparison();
|
|
5420
6261
|
else if (!workbench.hidden) closeWorkbench();
|
|
5421
|
-
else if (workspaceState.tray === "expanded") closeReview();
|
|
5422
6262
|
else clearSelection();
|
|
5423
6263
|
}
|
|
5424
6264
|
document.addEventListener("keydown", handleGlobalShortcuts);
|
|
@@ -5452,6 +6292,8 @@ function installFoundryInspector(options = {}) {
|
|
|
5452
6292
|
cancelAnimationFrame(layerScrollFrame);
|
|
5453
6293
|
cancelAnimationFrame(mutationFrame);
|
|
5454
6294
|
layerMutationObserver.disconnect();
|
|
6295
|
+
systemDarkTheme.removeEventListener("change", handleSystemThemeChange);
|
|
6296
|
+
document.removeEventListener("pointerdown", handleInterfaceThemeDismiss, true);
|
|
5455
6297
|
clearInterval(reviewPoll);
|
|
5456
6298
|
document.removeEventListener("click", handlePointer, true);
|
|
5457
6299
|
document.removeEventListener("dblclick", handleTextEdit, true);
|