@memberjunction/ng-dashboards 5.48.0 → 5.49.0

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.
Files changed (49) hide show
  1. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +2 -2
  2. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
  3. package/dist/Lists/services/list-set-operations.service.d.ts.map +1 -1
  4. package/dist/Lists/services/list-set-operations.service.js +29 -12
  5. package/dist/Lists/services/list-set-operations.service.js.map +1 -1
  6. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +7 -1
  7. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
  8. package/dist/PredictiveStudio/components/ps-pipelines.component.js +11 -4
  9. package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
  10. package/dist/Testing/components/testing-runs.component.d.ts.map +1 -1
  11. package/dist/Testing/components/testing-runs.component.js +35 -25
  12. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  13. package/dist/Testing/services/testing-instrumentation.service.d.ts +5 -0
  14. package/dist/Testing/services/testing-instrumentation.service.d.ts.map +1 -1
  15. package/dist/Testing/services/testing-instrumentation.service.js +8 -2
  16. package/dist/Testing/services/testing-instrumentation.service.js.map +1 -1
  17. package/dist/ThemeStudio/theme-agent-context.d.ts +64 -0
  18. package/dist/ThemeStudio/theme-agent-context.d.ts.map +1 -0
  19. package/dist/ThemeStudio/theme-agent-context.js +129 -0
  20. package/dist/ThemeStudio/theme-agent-context.js.map +1 -0
  21. package/dist/ThemeStudio/theme-manager-dashboard.component.d.ts +62 -0
  22. package/dist/ThemeStudio/theme-manager-dashboard.component.d.ts.map +1 -0
  23. package/dist/ThemeStudio/theme-manager-dashboard.component.js +464 -0
  24. package/dist/ThemeStudio/theme-manager-dashboard.component.js.map +1 -0
  25. package/dist/ThemeStudio/theme-manager-resource.component.d.ts +31 -0
  26. package/dist/ThemeStudio/theme-manager-resource.component.d.ts.map +1 -0
  27. package/dist/ThemeStudio/theme-manager-resource.component.js +97 -0
  28. package/dist/ThemeStudio/theme-manager-resource.component.js.map +1 -0
  29. package/dist/ThemeStudio/theme-studio-dashboard.component.d.ts +351 -0
  30. package/dist/ThemeStudio/theme-studio-dashboard.component.d.ts.map +1 -0
  31. package/dist/ThemeStudio/theme-studio-dashboard.component.js +2931 -0
  32. package/dist/ThemeStudio/theme-studio-dashboard.component.js.map +1 -0
  33. package/dist/ThemeStudio/theme-studio-resource.component.d.ts +28 -0
  34. package/dist/ThemeStudio/theme-studio-resource.component.d.ts.map +1 -0
  35. package/dist/ThemeStudio/theme-studio-resource.component.js +96 -0
  36. package/dist/ThemeStudio/theme-studio-resource.component.js.map +1 -0
  37. package/dist/ThemeStudio/theme-studio.constants.d.ts +79 -0
  38. package/dist/ThemeStudio/theme-studio.constants.d.ts.map +1 -0
  39. package/dist/ThemeStudio/theme-studio.constants.js +217 -0
  40. package/dist/ThemeStudio/theme-studio.constants.js.map +1 -0
  41. package/dist/core-dashboards.module.d.ts +56 -52
  42. package/dist/core-dashboards.module.d.ts.map +1 -1
  43. package/dist/core-dashboards.module.js +24 -1
  44. package/dist/core-dashboards.module.js.map +1 -1
  45. package/dist/public-api.d.ts +4 -0
  46. package/dist/public-api.d.ts.map +1 -1
  47. package/dist/public-api.js +4 -0
  48. package/dist/public-api.js.map +1 -1
  49. package/package.json +63 -60
@@ -0,0 +1,2931 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ /**
8
+ * @fileoverview Theme Studio dashboard (org-theming Phase 5) — the polished authoring
9
+ * surface for brand themes, matching theme-studio-mockup-v2: a preview-primary layout
10
+ * with a collapsible, resizable slide-panel editor, three switchable preview surfaces
11
+ * (Explorer UI style-guide, Skip reports, agent output), and a fullscreen mode.
12
+ *
13
+ * Preview fidelity (proposal 16.2 / decision #4): every surface is fed by the SAME
14
+ * derivation module as the save path (@memberjunction/theme-engine). The mockup's
15
+ * parallel `--p-*` + JS color math is replaced by the real derived `--mj-*` token map,
16
+ * pushed onto the preview canvas — so hovers, dark re-point, and status colors are the
17
+ * true generator output, not an approximation.
18
+ *
19
+ * Customization escalates in order (design feedback v1.1): seeds → token overrides
20
+ * (visual token browser + recipes) → custom CSS (escape hatch, CodeMirror-backed).
21
+ * @module ThemeStudio
22
+ */
23
+ import { Component, HostListener, ViewChild, } from '@angular/core';
24
+ import { autocompletion } from '@codemirror/autocomplete';
25
+ import { RunView } from '@memberjunction/core';
26
+ import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
27
+ import { BaseDashboard } from '@memberjunction/ng-shared';
28
+ import { UserInfoEngine } from '@memberjunction/core-entities';
29
+ import { MJNotificationService } from '@memberjunction/ng-notifications';
30
+ import { derive, emitOverlayCss, emitScopedCustomCss, MJ_DEFAULT_SEEDS, } from '@memberjunction/theme-engine';
31
+ import { buildCssWarnings, isBuiltInTheme, MJ_CHROME_SELECTOR_INFO, MJ_CHROME_SELECTORS, parseOverridesJson, pickWorstOnPrimary, THEME_RECIPES, TOKEN_CATEGORIES, TOKEN_PREVIEW_TARGETS, } from './theme-studio.constants';
32
+ import { buildThemeStudioAgentContext, resolveThemeByIDOrName } from './theme-agent-context';
33
+ import * as i0 from "@angular/core";
34
+ import * as i1 from "@memberjunction/ng-shared";
35
+ import * as i2 from "@angular/forms";
36
+ import * as i3 from "@memberjunction/ng-ui-components";
37
+ import * as i4 from "@memberjunction/ng-code-editor";
38
+ const _c0 = ["previewCanvas"];
39
+ const _c1 = ["nameInput"];
40
+ const _c2 = ["stage"];
41
+ const _c3 = ["cssCm"];
42
+ const _c4 = ["galDialog"];
43
+ const _forTrack0 = ($index, $item) => $item.name;
44
+ const _forTrack1 = ($index, $item) => $item.value;
45
+ const _forTrack2 = ($index, $item) => $item.recipe.id;
46
+ const _forTrack3 = ($index, $item) => $item.id;
47
+ const _forTrack4 = ($index, $item) => $item.key;
48
+ const _forTrack5 = ($index, $item) => $item.selector;
49
+ function ThemeStudioDashboardComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
50
+ const _r2 = i0.ɵɵgetCurrentView();
51
+ i0.ɵɵelementStart(0, "input", 86, 2);
52
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Conditional_9_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.currentName, $event) || (ctx_r2.currentName = $event); return i0.ɵɵresetView($event); });
53
+ i0.ɵɵlistener("keydown.enter", function ThemeStudioDashboardComponent_Conditional_9_Template_input_keydown_enter_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.commitRename()); })("keydown.escape", function ThemeStudioDashboardComponent_Conditional_9_Template_input_keydown_escape_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.cancelRename()); })("blur", function ThemeStudioDashboardComponent_Conditional_9_Template_input_blur_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.commitRename()); });
54
+ i0.ɵɵelementEnd();
55
+ } if (rf & 2) {
56
+ const ctx_r2 = i0.ɵɵnextContext();
57
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.currentName);
58
+ } }
59
+ function ThemeStudioDashboardComponent_Conditional_10_Conditional_2_Template(rf, ctx) { if (rf & 1) {
60
+ const _r5 = i0.ɵɵgetCurrentView();
61
+ i0.ɵɵelementStart(0, "button", 89);
62
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_10_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.startRename()); });
63
+ i0.ɵɵelement(1, "i", 90);
64
+ i0.ɵɵelementEnd();
65
+ } }
66
+ function ThemeStudioDashboardComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
67
+ const _r4 = i0.ɵɵgetCurrentView();
68
+ i0.ɵɵelementStart(0, "b", 87);
69
+ i0.ɵɵlistener("dblclick", function ThemeStudioDashboardComponent_Conditional_10_Template_b_dblclick_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.startRename()); });
70
+ i0.ɵɵtext(1);
71
+ i0.ɵɵelementEnd();
72
+ i0.ɵɵconditionalCreate(2, ThemeStudioDashboardComponent_Conditional_10_Conditional_2_Template, 2, 0, "button", 88);
73
+ } if (rf & 2) {
74
+ const ctx_r2 = i0.ɵɵnextContext();
75
+ i0.ɵɵadvance();
76
+ i0.ɵɵtextInterpolate(ctx_r2.currentName);
77
+ i0.ɵɵadvance();
78
+ i0.ɵɵconditional(!ctx_r2.isBuiltInSelected ? 2 : -1);
79
+ } }
80
+ function ThemeStudioDashboardComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
81
+ i0.ɵɵelementStart(0, "span", 11);
82
+ i0.ɵɵtext(1, "DEFAULT");
83
+ i0.ɵɵelementEnd();
84
+ } }
85
+ function ThemeStudioDashboardComponent_Conditional_14_For_3_For_3_Template(rf, ctx) { if (rf & 1) {
86
+ i0.ɵɵelement(0, "i");
87
+ } if (rf & 2) {
88
+ const c_r9 = ctx.$implicit;
89
+ i0.ɵɵstyleProp("background", c_r9);
90
+ } }
91
+ function ThemeStudioDashboardComponent_Conditional_14_For_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
92
+ i0.ɵɵelementStart(0, "span", 11);
93
+ i0.ɵɵtext(1, "DEFAULT");
94
+ i0.ɵɵelementEnd();
95
+ } }
96
+ function ThemeStudioDashboardComponent_Conditional_14_For_3_Template(rf, ctx) { if (rf & 1) {
97
+ const _r7 = i0.ɵɵgetCurrentView();
98
+ i0.ɵɵelementStart(0, "button", 95);
99
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_14_For_3_Template_button_click_0_listener() { const t_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.selectTheme(t_r8)); });
100
+ i0.ɵɵelementStart(1, "span", 9);
101
+ i0.ɵɵrepeaterCreate(2, ThemeStudioDashboardComponent_Conditional_14_For_3_For_3_Template, 1, 2, "i", 96, i0.ɵɵrepeaterTrackByIndex);
102
+ i0.ɵɵelementEnd();
103
+ i0.ɵɵelementStart(4, "b");
104
+ i0.ɵɵtext(5);
105
+ i0.ɵɵelementEnd();
106
+ i0.ɵɵconditionalCreate(6, ThemeStudioDashboardComponent_Conditional_14_For_3_Conditional_6_Template, 2, 0, "span", 11);
107
+ i0.ɵɵelementEnd();
108
+ } if (rf & 2) {
109
+ const t_r8 = ctx.$implicit;
110
+ const ctx_r2 = i0.ɵɵnextContext(2);
111
+ i0.ɵɵclassProp("on", ctx_r2.isCurrentTheme(t_r8.id));
112
+ i0.ɵɵadvance(2);
113
+ i0.ɵɵrepeater(t_r8.swatches);
114
+ i0.ɵɵadvance(3);
115
+ i0.ɵɵtextInterpolate(t_r8.name);
116
+ i0.ɵɵadvance();
117
+ i0.ɵɵconditional(t_r8.isDefault ? 6 : -1);
118
+ } }
119
+ function ThemeStudioDashboardComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
120
+ const _r6 = i0.ɵɵgetCurrentView();
121
+ i0.ɵɵelementStart(0, "div", 91);
122
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_14_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.themePickerOpen = false); });
123
+ i0.ɵɵelementEnd();
124
+ i0.ɵɵelementStart(1, "div", 92);
125
+ i0.ɵɵrepeaterCreate(2, ThemeStudioDashboardComponent_Conditional_14_For_3_Template, 7, 4, "button", 93, _forTrack3);
126
+ i0.ɵɵelementStart(4, "button", 94);
127
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_14_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.newTheme()); });
128
+ i0.ɵɵelement(5, "i", 46);
129
+ i0.ɵɵtext(6, " New theme");
130
+ i0.ɵɵelementEnd()();
131
+ } if (rf & 2) {
132
+ const ctx_r2 = i0.ɵɵnextContext();
133
+ i0.ɵɵadvance(2);
134
+ i0.ɵɵrepeater(ctx_r2.themes);
135
+ } }
136
+ function ThemeStudioDashboardComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
137
+ i0.ɵɵelementStart(0, "span", 14);
138
+ i0.ɵɵelement(1, "i", 97);
139
+ i0.ɵɵtext(2, " Built-in \u00B7 read-only");
140
+ i0.ɵɵelementEnd();
141
+ } }
142
+ function ThemeStudioDashboardComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
143
+ i0.ɵɵelementStart(0, "span", 15);
144
+ i0.ɵɵelement(1, "i", 98);
145
+ i0.ɵɵtext(2, " Draft previewing on your workspace");
146
+ i0.ɵɵelementEnd();
147
+ } }
148
+ function ThemeStudioDashboardComponent_Conditional_24_Template(rf, ctx) { if (rf & 1) {
149
+ const _r10 = i0.ɵɵgetCurrentView();
150
+ i0.ɵɵelementStart(0, "button", 99);
151
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_24_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.saveAsCopy()); });
152
+ i0.ɵɵtext(1, "Save as copy");
153
+ i0.ɵɵelementEnd();
154
+ } }
155
+ function ThemeStudioDashboardComponent_Conditional_25_Template(rf, ctx) { if (rf & 1) {
156
+ const _r11 = i0.ɵɵgetCurrentView();
157
+ i0.ɵɵelementStart(0, "button", 100);
158
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_25_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.save()); });
159
+ i0.ɵɵtext(1);
160
+ i0.ɵɵelementEnd();
161
+ } if (rf & 2) {
162
+ const ctx_r2 = i0.ɵɵnextContext();
163
+ i0.ɵɵproperty("disabled", ctx_r2.saving);
164
+ i0.ɵɵadvance();
165
+ i0.ɵɵtextInterpolate(ctx_r2.saving ? "Saving\u2026" : "Save theme");
166
+ } }
167
+ function ThemeStudioDashboardComponent_Conditional_38_For_9_Template(rf, ctx) { if (rf & 1) {
168
+ const _r13 = i0.ɵɵgetCurrentView();
169
+ i0.ɵɵelementStart(0, "button", 107);
170
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_38_For_9_Template_button_click_0_listener() { const p_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.choosePreset(p_r14)); });
171
+ i0.ɵɵelementStart(1, "span", 108);
172
+ i0.ɵɵelement(2, "span", 109);
173
+ i0.ɵɵelementStart(3, "span", 110);
174
+ i0.ɵɵelement(4, "span", 111)(5, "span", 112);
175
+ i0.ɵɵelementStart(6, "span", 113);
176
+ i0.ɵɵelement(7, "span", 114)(8, "span", 114)(9, "span", 115);
177
+ i0.ɵɵelementEnd()()();
178
+ i0.ɵɵelementStart(10, "b");
179
+ i0.ɵɵtext(11);
180
+ i0.ɵɵelementEnd()();
181
+ } if (rf & 2) {
182
+ const p_r14 = ctx.$implicit;
183
+ i0.ɵɵadvance();
184
+ i0.ɵɵstyleProp("border-radius", p_r14.seeds.radius ?? 8, "px");
185
+ i0.ɵɵadvance();
186
+ i0.ɵɵstyleProp("background", p_r14.seeds.primary);
187
+ i0.ɵɵadvance(5);
188
+ i0.ɵɵstyleProp("background", p_r14.seeds.accent ?? p_r14.seeds.primary);
189
+ i0.ɵɵadvance();
190
+ i0.ɵɵstyleProp("background", p_r14.seeds.tertiary ?? p_r14.seeds.accent ?? p_r14.seeds.primary);
191
+ i0.ɵɵadvance();
192
+ i0.ɵɵstyleProp("background", p_r14.seeds.primary)("border-radius", (p_r14.seeds.radius ?? 8) / 2, "px");
193
+ i0.ɵɵadvance(2);
194
+ i0.ɵɵtextInterpolate(p_r14.name);
195
+ } }
196
+ function ThemeStudioDashboardComponent_Conditional_38_Template(rf, ctx) { if (rf & 1) {
197
+ const _r12 = i0.ɵɵgetCurrentView();
198
+ i0.ɵɵelementStart(0, "div", 101);
199
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_38_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.closePresetGallery()); });
200
+ i0.ɵɵelementEnd();
201
+ i0.ɵɵelementStart(1, "div", 102, 3)(3, "h2");
202
+ i0.ɵɵtext(4, "Start a new theme");
203
+ i0.ɵɵelementEnd();
204
+ i0.ɵɵelementStart(5, "p", 103);
205
+ i0.ɵɵtext(6, "Pick a personality first \u2014 everything derives from a few seeds, so you can tune it all after.");
206
+ i0.ɵɵelementEnd();
207
+ i0.ɵɵelementStart(7, "div", 104);
208
+ i0.ɵɵrepeaterCreate(8, ThemeStudioDashboardComponent_Conditional_38_For_9_Template, 12, 13, "button", 105, _forTrack0);
209
+ i0.ɵɵelementEnd();
210
+ i0.ɵɵelementStart(10, "div", 106)(11, "button", 17);
211
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_38_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.closePresetGallery()); });
212
+ i0.ɵɵtext(12, "Start blank (MJ defaults)");
213
+ i0.ɵɵelementEnd()()();
214
+ } if (rf & 2) {
215
+ const ctx_r2 = i0.ɵɵnextContext();
216
+ i0.ɵɵadvance(8);
217
+ i0.ɵɵrepeater(ctx_r2.presets);
218
+ } }
219
+ function ThemeStudioDashboardComponent_Conditional_43_Template(rf, ctx) { if (rf & 1) {
220
+ const _r15 = i0.ɵɵgetCurrentView();
221
+ i0.ɵɵelementStart(0, "div", 34)(1, "mj-view-toggle", 23);
222
+ i0.ɵɵlistener("KeyChange", function ThemeStudioDashboardComponent_Conditional_43_Template_mj_view_toggle_KeyChange_1_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onModeToggle($event)); });
223
+ i0.ɵɵelementEnd();
224
+ i0.ɵɵelementStart(2, "button", 116);
225
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_43_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.toggleFullscreen(false)); });
226
+ i0.ɵɵtext(3, "Exit full screen ");
227
+ i0.ɵɵelementStart(4, "span", 117);
228
+ i0.ɵɵtext(5, "Esc");
229
+ i0.ɵɵelementEnd()()();
230
+ } if (rf & 2) {
231
+ const ctx_r2 = i0.ɵɵnextContext();
232
+ i0.ɵɵadvance();
233
+ i0.ɵɵproperty("Options", ctx_r2.modeOptions)("ActiveKey", ctx_r2.previewMode);
234
+ } }
235
+ function ThemeStudioDashboardComponent_Conditional_45_For_9_Template(rf, ctx) { if (rf & 1) {
236
+ const _r17 = i0.ɵɵgetCurrentView();
237
+ i0.ɵɵelementStart(0, "b", 181);
238
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_45_For_9_Template_b_click_0_listener() { const ɵ$index_193_r18 = i0.ɵɵrestoreView(_r17).$index; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.mockNav = ɵ$index_193_r18); })("keydown.enter", function ThemeStudioDashboardComponent_Conditional_45_For_9_Template_b_keydown_enter_0_listener() { const ɵ$index_193_r18 = i0.ɵɵrestoreView(_r17).$index; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.mockNav = ɵ$index_193_r18); })("keydown.space", function ThemeStudioDashboardComponent_Conditional_45_For_9_Template_b_keydown_space_0_listener($event) { const ɵ$index_193_r18 = i0.ɵɵrestoreView(_r17).$index; const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.mockNav = ɵ$index_193_r18; return i0.ɵɵresetView($event.preventDefault()); });
239
+ i0.ɵɵtext(1);
240
+ i0.ɵɵelementEnd();
241
+ } if (rf & 2) {
242
+ const item_r19 = ctx.$implicit;
243
+ const ɵ$index_193_r18 = ctx.$index;
244
+ const ctx_r2 = i0.ɵɵnextContext(2);
245
+ i0.ɵɵclassProp("on", ctx_r2.mockNav === ɵ$index_193_r18);
246
+ i0.ɵɵadvance();
247
+ i0.ɵɵtextInterpolate(item_r19);
248
+ } }
249
+ function ThemeStudioDashboardComponent_Conditional_45_For_33_Template(rf, ctx) { if (rf & 1) {
250
+ const _r20 = i0.ɵɵgetCurrentView();
251
+ i0.ɵɵelementStart(0, "i", 189);
252
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_45_For_33_Template_i_click_0_listener() { const ɵ$index_235_r21 = i0.ɵɵrestoreView(_r20).$index; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.mockTab = ɵ$index_235_r21); })("keydown.enter", function ThemeStudioDashboardComponent_Conditional_45_For_33_Template_i_keydown_enter_0_listener() { const ɵ$index_235_r21 = i0.ɵɵrestoreView(_r20).$index; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.mockTab = ɵ$index_235_r21); })("keydown.space", function ThemeStudioDashboardComponent_Conditional_45_For_33_Template_i_keydown_space_0_listener($event) { const ɵ$index_235_r21 = i0.ɵɵrestoreView(_r20).$index; const ctx_r2 = i0.ɵɵnextContext(2); ctx_r2.mockTab = ɵ$index_235_r21; return i0.ɵɵresetView($event.preventDefault()); });
253
+ i0.ɵɵtext(1);
254
+ i0.ɵɵelementEnd();
255
+ } if (rf & 2) {
256
+ const t_r22 = ctx.$implicit;
257
+ const ɵ$index_235_r21 = ctx.$index;
258
+ const ctx_r2 = i0.ɵɵnextContext(2);
259
+ i0.ɵɵclassProp("on", ctx_r2.mockTab === ɵ$index_235_r21);
260
+ i0.ɵɵattribute("aria-selected", ctx_r2.mockTab === ɵ$index_235_r21);
261
+ i0.ɵɵadvance();
262
+ i0.ɵɵtextInterpolate(t_r22);
263
+ } }
264
+ function ThemeStudioDashboardComponent_Conditional_45_Conditional_146_Template(rf, ctx) { if (rf & 1) {
265
+ i0.ɵɵelementStart(0, "b", 190);
266
+ i0.ɵɵtext(1, "Renewal funnel");
267
+ i0.ɵɵelementEnd();
268
+ i0.ɵɵelementStart(2, "b", 190);
269
+ i0.ɵɵtext(3, "Engagement");
270
+ i0.ɵɵelementEnd();
271
+ } }
272
+ function ThemeStudioDashboardComponent_Conditional_45_Template(rf, ctx) { if (rf & 1) {
273
+ const _r16 = i0.ɵɵgetCurrentView();
274
+ i0.ɵɵelementStart(0, "div", 36)(1, "div", 118);
275
+ i0.ɵɵtext(2, "Explorer UI \u00B7 shell + page chrome + ng-ui-components \u00B7 hover & tab around \u2014 states are live");
276
+ i0.ɵɵelementEnd();
277
+ i0.ɵɵelementStart(3, "div", 119)(4, "div", 120)(5, "span", 121);
278
+ i0.ɵɵelement(6, "i", 122);
279
+ i0.ɵɵelementEnd();
280
+ i0.ɵɵelementStart(7, "span", 123);
281
+ i0.ɵɵrepeaterCreate(8, ThemeStudioDashboardComponent_Conditional_45_For_9_Template, 2, 3, "b", 124, i0.ɵɵrepeaterTrackByIdentity);
282
+ i0.ɵɵelementEnd();
283
+ i0.ɵɵelementStart(10, "span", 125);
284
+ i0.ɵɵelement(11, "i", 126);
285
+ i0.ɵɵtext(12, " Search everything\u2026");
286
+ i0.ɵɵelementEnd();
287
+ i0.ɵɵelement(13, "span", 127);
288
+ i0.ɵɵelementStart(14, "span", 128);
289
+ i0.ɵɵtext(15, "AC");
290
+ i0.ɵɵelementEnd()();
291
+ i0.ɵɵelementStart(16, "div", 129)(17, "div", 130)(18, "span", 131);
292
+ i0.ɵɵelement(19, "i", 132);
293
+ i0.ɵɵelementEnd();
294
+ i0.ɵɵelementStart(20, "div")(21, "div", 133);
295
+ i0.ɵɵtext(22, "Membership Overview");
296
+ i0.ɵɵelementEnd();
297
+ i0.ɵɵelementStart(23, "div", 134);
298
+ i0.ɵɵtext(24, "mj-page-layout \u00B7 mj-page-header \u00B7 mj-page-body");
299
+ i0.ɵɵelementEnd()();
300
+ i0.ɵɵelementStart(25, "div", 135)(26, "button", 136);
301
+ i0.ɵɵtext(27, "Export");
302
+ i0.ɵɵelementEnd();
303
+ i0.ɵɵelementStart(28, "button", 137);
304
+ i0.ɵɵtext(29, "New record");
305
+ i0.ɵɵelementEnd()()();
306
+ i0.ɵɵelementStart(30, "div", 138)(31, "span", 139);
307
+ i0.ɵɵrepeaterCreate(32, ThemeStudioDashboardComponent_Conditional_45_For_33_Template, 2, 4, "i", 140, i0.ɵɵrepeaterTrackByIdentity);
308
+ i0.ɵɵelementEnd()()();
309
+ i0.ɵɵelementStart(34, "div", 141)(35, "div", 142)(36, "span", 143);
310
+ i0.ɵɵtext(37, "mjButton \u2014 primary \u00B7 secondary \u00B7 outline \u00B7 danger");
311
+ i0.ɵɵelementEnd();
312
+ i0.ɵɵelementStart(38, "div", 144)(39, "button", 137);
313
+ i0.ɵɵtext(40, "Save");
314
+ i0.ɵɵelementEnd();
315
+ i0.ɵɵelementStart(41, "button", 136);
316
+ i0.ɵɵtext(42, "Cancel");
317
+ i0.ɵɵelementEnd();
318
+ i0.ɵɵelementStart(43, "button", 145);
319
+ i0.ɵɵtext(44, "Configure");
320
+ i0.ɵɵelementEnd();
321
+ i0.ɵɵelementStart(45, "button", 146);
322
+ i0.ɵɵtext(46, "Delete");
323
+ i0.ɵɵelementEnd()()();
324
+ i0.ɵɵelementStart(47, "div", 142)(48, "span", 143);
325
+ i0.ɵɵtext(49, "Button states \u2014 rest \u00B7 hover \u00B7 active \u00B7 focus \u00B7 disabled");
326
+ i0.ɵɵelementEnd();
327
+ i0.ɵɵelementStart(50, "div", 147)(51, "button", 137);
328
+ i0.ɵɵtext(52, "Rest");
329
+ i0.ɵɵelementEnd();
330
+ i0.ɵɵelementStart(53, "button", 148);
331
+ i0.ɵɵtext(54, "Hover");
332
+ i0.ɵɵelementEnd();
333
+ i0.ɵɵelementStart(55, "button", 149);
334
+ i0.ɵɵtext(56, "Active");
335
+ i0.ɵɵelementEnd();
336
+ i0.ɵɵelementStart(57, "button", 150);
337
+ i0.ɵɵtext(58, "Focus");
338
+ i0.ɵɵelementEnd();
339
+ i0.ɵɵelementStart(59, "button", 151);
340
+ i0.ɵɵtext(60, "Disabled");
341
+ i0.ɵɵelementEnd()();
342
+ i0.ɵɵelementStart(61, "div", 147)(62, "button", 136);
343
+ i0.ɵɵtext(63, "Rest");
344
+ i0.ɵɵelementEnd();
345
+ i0.ɵɵelementStart(64, "button", 152);
346
+ i0.ɵɵtext(65, "Hover");
347
+ i0.ɵɵelementEnd();
348
+ i0.ɵɵelementStart(66, "button", 153);
349
+ i0.ɵɵtext(67, "Active");
350
+ i0.ɵɵelementEnd();
351
+ i0.ɵɵelementStart(68, "button", 154);
352
+ i0.ɵɵtext(69, "Focus");
353
+ i0.ɵɵelementEnd();
354
+ i0.ɵɵelementStart(70, "button", 155);
355
+ i0.ɵɵtext(71, "Disabled");
356
+ i0.ɵɵelementEnd()();
357
+ i0.ɵɵelementStart(72, "div", 147)(73, "button", 145);
358
+ i0.ɵɵtext(74, "Rest");
359
+ i0.ɵɵelementEnd();
360
+ i0.ɵɵelementStart(75, "button", 156);
361
+ i0.ɵɵtext(76, "Hover");
362
+ i0.ɵɵelementEnd();
363
+ i0.ɵɵelementStart(77, "button", 157);
364
+ i0.ɵɵtext(78, "Active");
365
+ i0.ɵɵelementEnd();
366
+ i0.ɵɵelementStart(79, "button", 158);
367
+ i0.ɵɵtext(80, "Focus");
368
+ i0.ɵɵelementEnd();
369
+ i0.ɵɵelementStart(81, "button", 159);
370
+ i0.ɵɵtext(82, "Disabled");
371
+ i0.ɵɵelementEnd()();
372
+ i0.ɵɵelementStart(83, "div", 147)(84, "button", 146);
373
+ i0.ɵɵtext(85, "Rest");
374
+ i0.ɵɵelementEnd();
375
+ i0.ɵɵelementStart(86, "button", 160);
376
+ i0.ɵɵtext(87, "Hover");
377
+ i0.ɵɵelementEnd();
378
+ i0.ɵɵelementStart(88, "button", 161);
379
+ i0.ɵɵtext(89, "Active");
380
+ i0.ɵɵelementEnd();
381
+ i0.ɵɵelementStart(90, "button", 162);
382
+ i0.ɵɵtext(91, "Focus");
383
+ i0.ɵɵelementEnd();
384
+ i0.ɵɵelementStart(92, "button", 163);
385
+ i0.ɵɵtext(93, "Disabled");
386
+ i0.ɵɵelementEnd()()();
387
+ i0.ɵɵelementStart(94, "div", 142)(95, "span", 143);
388
+ i0.ɵɵtext(96, "mj-input \u00B7 mj-combobox \u00B7 mj-switch");
389
+ i0.ɵɵelementEnd();
390
+ i0.ɵɵelementStart(97, "div", 144)(98, "span", 164);
391
+ i0.ɵɵtext(99, "Northwind Tra");
392
+ i0.ɵɵelementEnd();
393
+ i0.ɵɵelementStart(100, "span", 165);
394
+ i0.ɵɵtext(101, "Member type ");
395
+ i0.ɵɵelement(102, "i", 166);
396
+ i0.ɵɵelementEnd()();
397
+ i0.ɵɵelementStart(103, "div", 144)(104, "span", 167);
398
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_45_Template_span_click_104_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.mockSwitchA = !ctx_r2.mockSwitchA); })("keydown.enter", function ThemeStudioDashboardComponent_Conditional_45_Template_span_keydown_enter_104_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.mockSwitchA = !ctx_r2.mockSwitchA); })("keydown.space", function ThemeStudioDashboardComponent_Conditional_45_Template_span_keydown_space_104_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); ctx_r2.mockSwitchA = !ctx_r2.mockSwitchA; return i0.ɵɵresetView($event.preventDefault()); });
399
+ i0.ɵɵelementEnd();
400
+ i0.ɵɵelementStart(105, "span", 168);
401
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_45_Template_span_click_105_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.mockSwitchB = !ctx_r2.mockSwitchB); })("keydown.enter", function ThemeStudioDashboardComponent_Conditional_45_Template_span_keydown_enter_105_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.mockSwitchB = !ctx_r2.mockSwitchB); })("keydown.space", function ThemeStudioDashboardComponent_Conditional_45_Template_span_keydown_space_105_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); ctx_r2.mockSwitchB = !ctx_r2.mockSwitchB; return i0.ɵɵresetView($event.preventDefault()); });
402
+ i0.ɵɵelementEnd();
403
+ i0.ɵɵelementStart(106, "span", 169);
404
+ i0.ɵɵtext(107, "Auto-renew");
405
+ i0.ɵɵelementEnd()()();
406
+ i0.ɵɵelementStart(108, "div", 170)(109, "span", 143);
407
+ i0.ɵɵtext(110, "mj-filter-chip");
408
+ i0.ɵɵelementEnd();
409
+ i0.ɵɵelementStart(111, "div", 144)(112, "span", 171);
410
+ i0.ɵɵtext(113, "Active");
411
+ i0.ɵɵelementEnd();
412
+ i0.ɵɵelementStart(114, "span", 172);
413
+ i0.ɵɵtext(115, "Lapsed");
414
+ i0.ɵɵelementEnd();
415
+ i0.ɵɵelementStart(116, "span", 172);
416
+ i0.ɵɵtext(117, "Pending");
417
+ i0.ɵɵelementEnd()()();
418
+ i0.ɵɵelementStart(118, "div", 170)(119, "span", 143);
419
+ i0.ɵɵtext(120, "mj-stat-badge \u00B7 mj-progress-bar");
420
+ i0.ɵɵelementEnd();
421
+ i0.ɵɵelementStart(121, "div", 144)(122, "span", 173);
422
+ i0.ɵɵtext(123, "1,204 Members");
423
+ i0.ɵɵelementEnd();
424
+ i0.ɵɵelementStart(124, "span", 174);
425
+ i0.ɵɵtext(125, "Active");
426
+ i0.ɵɵelementEnd();
427
+ i0.ɵɵelementStart(126, "span", 175);
428
+ i0.ɵɵtext(127, "Expiring");
429
+ i0.ɵɵelementEnd()();
430
+ i0.ɵɵelementStart(128, "div", 144)(129, "span", 176);
431
+ i0.ɵɵelement(130, "i");
432
+ i0.ɵɵelementEnd();
433
+ i0.ɵɵelementStart(131, "span", 169);
434
+ i0.ɵɵtext(132, "64%");
435
+ i0.ɵɵelementEnd()()();
436
+ i0.ɵɵelementStart(133, "div", 170)(134, "span", 143);
437
+ i0.ɵɵtext(135, "mj-left-nav \u00B7 mj-accordion \u00B7 mj-alert");
438
+ i0.ɵɵelementEnd();
439
+ i0.ɵɵelementStart(136, "div", 177)(137, "b", 178);
440
+ i0.ɵɵelement(138, "i", 179);
441
+ i0.ɵɵtext(139, " Overview");
442
+ i0.ɵɵelementEnd();
443
+ i0.ɵɵelementStart(140, "b", 180);
444
+ i0.ɵɵelement(141, "i", 132);
445
+ i0.ɵɵtext(142, " Members");
446
+ i0.ɵɵelementEnd();
447
+ i0.ɵɵelementStart(143, "b", 181);
448
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_45_Template_b_click_143_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.mockAccordionOpen = !ctx_r2.mockAccordionOpen); })("keydown.enter", function ThemeStudioDashboardComponent_Conditional_45_Template_b_keydown_enter_143_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.mockAccordionOpen = !ctx_r2.mockAccordionOpen); })("keydown.space", function ThemeStudioDashboardComponent_Conditional_45_Template_b_keydown_space_143_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(); ctx_r2.mockAccordionOpen = !ctx_r2.mockAccordionOpen; return i0.ɵɵresetView($event.preventDefault()); });
449
+ i0.ɵɵelement(144, "i", 182);
450
+ i0.ɵɵtext(145, " Reports ");
451
+ i0.ɵɵelementEnd();
452
+ i0.ɵɵconditionalCreate(146, ThemeStudioDashboardComponent_Conditional_45_Conditional_146_Template, 4, 0);
453
+ i0.ɵɵelementEnd();
454
+ i0.ɵɵelementStart(147, "div", 183);
455
+ i0.ɵɵelement(148, "i");
456
+ i0.ɵɵtext(149, "12 imports finished overnight");
457
+ i0.ɵɵelementEnd()();
458
+ i0.ɵɵelementStart(150, "div", 170)(151, "span", 143);
459
+ i0.ɵɵtext(152, "mj-dialog \u00B7 mj-dialog-actions");
460
+ i0.ɵɵelementEnd();
461
+ i0.ɵɵelementStart(153, "div", 184)(154, "div", 185);
462
+ i0.ɵɵtext(155, "Rename view");
463
+ i0.ɵɵelementEnd();
464
+ i0.ɵɵelementStart(156, "div", 186)(157, "span", 187);
465
+ i0.ɵɵtext(158, "Q3 Renewal Pipeline");
466
+ i0.ɵɵelementEnd()();
467
+ i0.ɵɵelementStart(159, "div", 188)(160, "button", 137);
468
+ i0.ɵɵtext(161, "Save");
469
+ i0.ɵɵelementEnd();
470
+ i0.ɵɵelementStart(162, "button", 136);
471
+ i0.ɵɵtext(163, "Cancel");
472
+ i0.ɵɵelementEnd()()()()()()();
473
+ } if (rf & 2) {
474
+ const ctx_r2 = i0.ɵɵnextContext();
475
+ i0.ɵɵadvance(8);
476
+ i0.ɵɵrepeater(ctx_r2.mockNavItems);
477
+ i0.ɵɵadvance(24);
478
+ i0.ɵɵrepeater(ctx_r2.mockTabs);
479
+ i0.ɵɵadvance(72);
480
+ i0.ɵɵclassProp("off", !ctx_r2.mockSwitchA);
481
+ i0.ɵɵattribute("aria-checked", ctx_r2.mockSwitchA);
482
+ i0.ɵɵadvance();
483
+ i0.ɵɵclassProp("off", !ctx_r2.mockSwitchB);
484
+ i0.ɵɵattribute("aria-checked", ctx_r2.mockSwitchB);
485
+ i0.ɵɵadvance(38);
486
+ i0.ɵɵattribute("aria-expanded", ctx_r2.mockAccordionOpen);
487
+ i0.ɵɵadvance();
488
+ i0.ɵɵclassProp("fa-chevron-down", ctx_r2.mockAccordionOpen)("fa-chevron-right", !ctx_r2.mockAccordionOpen);
489
+ i0.ɵɵadvance(2);
490
+ i0.ɵɵconditional(ctx_r2.mockAccordionOpen ? 146 : -1);
491
+ } }
492
+ function ThemeStudioDashboardComponent_Conditional_46_For_41_Template(rf, ctx) { if (rf & 1) {
493
+ i0.ɵɵelementStart(0, "div", 208)(1, "span", 219);
494
+ i0.ɵɵtext(2);
495
+ i0.ɵɵelementEnd();
496
+ i0.ɵɵelement(3, "span", 220);
497
+ i0.ɵɵelementEnd();
498
+ } if (rf & 2) {
499
+ const h_r23 = ctx.$implicit;
500
+ const ɵ$index_522_r24 = ctx.$index;
501
+ const ctx_r2 = i0.ɵɵnextContext(2);
502
+ i0.ɵɵadvance(2);
503
+ i0.ɵɵtextInterpolate(ctx_r2.barValues[ɵ$index_522_r24]);
504
+ i0.ɵɵadvance();
505
+ i0.ɵɵstyleProp("height", h_r23, "%")("background", ctx_r2.vizColors[ɵ$index_522_r24 % ctx_r2.vizColors.length]);
506
+ } }
507
+ function ThemeStudioDashboardComponent_Conditional_46_For_44_Template(rf, ctx) { if (rf & 1) {
508
+ i0.ɵɵelementStart(0, "span");
509
+ i0.ɵɵtext(1);
510
+ i0.ɵɵelementEnd();
511
+ } if (rf & 2) {
512
+ const c_r25 = ctx.$implicit;
513
+ i0.ɵɵadvance();
514
+ i0.ɵɵtextInterpolate(c_r25);
515
+ } }
516
+ function ThemeStudioDashboardComponent_Conditional_46_Template(rf, ctx) { if (rf & 1) {
517
+ i0.ɵɵelementStart(0, "div", 36)(1, "div", 191)(2, "div", 192);
518
+ i0.ɵɵelement(3, "span", 193);
519
+ i0.ɵɵelementStart(4, "div")(5, "div", 194);
520
+ i0.ɵɵtext(6, "Acme Analytics");
521
+ i0.ɵɵelementEnd();
522
+ i0.ɵɵelementStart(7, "div", 195);
523
+ i0.ɵɵtext(8, "Q2 Pipeline Overview");
524
+ i0.ɵɵelementEnd()();
525
+ i0.ɵɵelementStart(9, "div", 196);
526
+ i0.ɵɵtext(10, "Generated \u00B7 Jul 2026");
527
+ i0.ɵɵelementEnd()();
528
+ i0.ɵɵelementStart(11, "div", 197)(12, "div", 198)(13, "div", 199)(14, "div", 200);
529
+ i0.ɵɵtext(15, "$4.2M");
530
+ i0.ɵɵelementEnd();
531
+ i0.ɵɵelementStart(16, "div", 201);
532
+ i0.ɵɵtext(17, "Pipeline value");
533
+ i0.ɵɵelementEnd();
534
+ i0.ɵɵelementStart(18, "div", 202);
535
+ i0.ɵɵtext(19, "\u25B2 12.4%");
536
+ i0.ɵɵelementEnd()();
537
+ i0.ɵɵelementStart(20, "div", 199)(21, "div", 200);
538
+ i0.ɵɵtext(22, "318");
539
+ i0.ɵɵelementEnd();
540
+ i0.ɵɵelementStart(23, "div", 201);
541
+ i0.ɵɵtext(24, "Open deals");
542
+ i0.ɵɵelementEnd();
543
+ i0.ɵɵelementStart(25, "div", 202);
544
+ i0.ɵɵtext(26, "\u25B2 6.1%");
545
+ i0.ɵɵelementEnd()();
546
+ i0.ɵɵelementStart(27, "div", 199)(28, "div", 200);
547
+ i0.ɵɵtext(29, "27%");
548
+ i0.ɵɵelementEnd();
549
+ i0.ɵɵelementStart(30, "div", 201);
550
+ i0.ɵɵtext(31, "Win rate");
551
+ i0.ɵɵelementEnd();
552
+ i0.ɵɵelementStart(32, "div", 203);
553
+ i0.ɵɵtext(33, "\u25BC 1.8%");
554
+ i0.ɵɵelementEnd()()();
555
+ i0.ɵɵelementStart(34, "div", 204)(35, "div", 205);
556
+ i0.ɵɵtext(36, "Pipeline by stage");
557
+ i0.ɵɵelementEnd();
558
+ i0.ɵɵelementStart(37, "div", 206);
559
+ i0.ɵɵtext(38, "Value in each stage, current quarter");
560
+ i0.ɵɵelementEnd();
561
+ i0.ɵɵelementStart(39, "div", 207);
562
+ i0.ɵɵrepeaterCreate(40, ThemeStudioDashboardComponent_Conditional_46_For_41_Template, 4, 5, "div", 208, i0.ɵɵrepeaterTrackByIndex);
563
+ i0.ɵɵelementEnd();
564
+ i0.ɵɵelementStart(42, "div", 209);
565
+ i0.ɵɵrepeaterCreate(43, ThemeStudioDashboardComponent_Conditional_46_For_44_Template, 2, 1, "span", null, i0.ɵɵrepeaterTrackByIdentity);
566
+ i0.ɵɵelementEnd()();
567
+ i0.ɵɵelementStart(45, "table", 210)(46, "thead")(47, "tr")(48, "th");
568
+ i0.ɵɵtext(49, "Account");
569
+ i0.ɵɵelementEnd();
570
+ i0.ɵɵelementStart(50, "th");
571
+ i0.ɵɵtext(51, "Stage");
572
+ i0.ɵɵelementEnd();
573
+ i0.ɵɵelementStart(52, "th", 211);
574
+ i0.ɵɵtext(53, "Value");
575
+ i0.ɵɵelementEnd();
576
+ i0.ɵɵelementStart(54, "th", 211);
577
+ i0.ɵɵtext(55, "Close");
578
+ i0.ɵɵelementEnd()()();
579
+ i0.ɵɵelementStart(56, "tbody")(57, "tr")(58, "td")(59, "b");
580
+ i0.ɵɵtext(60, "Northwind Traders");
581
+ i0.ɵɵelementEnd()();
582
+ i0.ɵɵelementStart(61, "td");
583
+ i0.ɵɵtext(62, "Negotiate");
584
+ i0.ɵɵelementEnd();
585
+ i0.ɵɵelementStart(63, "td", 211);
586
+ i0.ɵɵtext(64, "$820,000");
587
+ i0.ɵɵelementEnd();
588
+ i0.ɵɵelementStart(65, "td", 211);
589
+ i0.ɵɵtext(66, "Aug 12");
590
+ i0.ɵɵelementEnd()();
591
+ i0.ɵɵelementStart(67, "tr")(68, "td")(69, "b");
592
+ i0.ɵɵtext(70, "Contoso Ltd");
593
+ i0.ɵɵelementEnd()();
594
+ i0.ɵɵelementStart(71, "td");
595
+ i0.ɵɵtext(72, "Propose");
596
+ i0.ɵɵelementEnd();
597
+ i0.ɵɵelementStart(73, "td", 211);
598
+ i0.ɵɵtext(74, "$465,000");
599
+ i0.ɵɵelementEnd();
600
+ i0.ɵɵelementStart(75, "td", 211);
601
+ i0.ɵɵtext(76, "Sep 03");
602
+ i0.ɵɵelementEnd()();
603
+ i0.ɵɵelementStart(77, "tr")(78, "td")(79, "b");
604
+ i0.ɵɵtext(80, "Fabrikam Inc");
605
+ i0.ɵɵelementEnd()();
606
+ i0.ɵɵelementStart(81, "td");
607
+ i0.ɵɵtext(82, "Commit");
608
+ i0.ɵɵelementEnd();
609
+ i0.ɵɵelementStart(83, "td", 211);
610
+ i0.ɵɵtext(84, "$1,240,000");
611
+ i0.ɵɵelementEnd();
612
+ i0.ɵɵelementStart(85, "td", 211);
613
+ i0.ɵɵtext(86, "Jul 29");
614
+ i0.ɵɵelementEnd()()()();
615
+ i0.ɵɵelementStart(87, "p", 212)(88, "b");
616
+ i0.ɵɵtext(89, "Summary.");
617
+ i0.ɵɵelementEnd();
618
+ i0.ɵɵtext(90, " Northwind expanded into two of Acme's core regions this quarter, hired a new VP of Partnerships, and repriced its mid-tier plan 8% below Acme's.");
619
+ i0.ɵɵelementEnd();
620
+ i0.ɵɵelementStart(91, "div", 213)(92, "div", 214);
621
+ i0.ɵɵelement(93, "span", 215);
622
+ i0.ɵɵelementStart(94, "span")(95, "b");
623
+ i0.ɵɵtext(96, "Regional expansion");
624
+ i0.ɵɵelementEnd();
625
+ i0.ɵɵtext(97, " \u2014 opened Denver and Austin offices");
626
+ i0.ɵɵelementEnd();
627
+ i0.ɵɵelementStart(98, "span", 175);
628
+ i0.ɵɵtext(99, "High impact");
629
+ i0.ɵɵelementEnd()();
630
+ i0.ɵɵelementStart(100, "div", 214);
631
+ i0.ɵɵelement(101, "span", 215);
632
+ i0.ɵɵelementStart(102, "span")(103, "b");
633
+ i0.ɵɵtext(104, "Pricing move");
634
+ i0.ɵɵelementEnd();
635
+ i0.ɵɵtext(105, " \u2014 mid-tier repriced to $79/seat");
636
+ i0.ɵɵelementEnd();
637
+ i0.ɵɵelementStart(106, "span", 173);
638
+ i0.ɵɵtext(107, "Watch");
639
+ i0.ɵɵelementEnd()();
640
+ i0.ɵɵelementStart(108, "div", 214);
641
+ i0.ɵɵelement(109, "span", 215);
642
+ i0.ɵɵelementStart(110, "span")(111, "b");
643
+ i0.ɵɵtext(112, "Positioning shift");
644
+ i0.ɵɵelementEnd();
645
+ i0.ɵɵtext(113, " \u2014 \"live in 30 days\" campaign");
646
+ i0.ɵɵelementEnd();
647
+ i0.ɵɵelementStart(114, "span", 216);
648
+ i0.ɵɵtext(115, "Monitor");
649
+ i0.ɵɵelementEnd()()();
650
+ i0.ɵɵelementStart(116, "table", 210)(117, "thead")(118, "tr")(119, "th");
651
+ i0.ɵɵtext(120, "Source");
652
+ i0.ɵɵelementEnd();
653
+ i0.ɵɵelementStart(121, "th");
654
+ i0.ɵɵtext(122, "Type");
655
+ i0.ɵɵelementEnd();
656
+ i0.ɵɵelementStart(123, "th", 211);
657
+ i0.ɵɵtext(124, "Confidence");
658
+ i0.ɵɵelementEnd()()();
659
+ i0.ɵɵelementStart(125, "tbody")(126, "tr")(127, "td")(128, "b");
660
+ i0.ɵɵtext(129, "Northwind press release");
661
+ i0.ɵɵelementEnd()();
662
+ i0.ɵɵelementStart(130, "td");
663
+ i0.ɵɵtext(131, "Primary");
664
+ i0.ɵɵelementEnd();
665
+ i0.ɵɵelementStart(132, "td", 211);
666
+ i0.ɵɵtext(133, "High");
667
+ i0.ɵɵelementEnd()();
668
+ i0.ɵɵelementStart(134, "tr")(135, "td")(136, "b");
669
+ i0.ɵɵtext(137, "G2 pricing capture");
670
+ i0.ɵɵelementEnd()();
671
+ i0.ɵɵelementStart(138, "td");
672
+ i0.ɵɵtext(139, "Primary");
673
+ i0.ɵɵelementEnd();
674
+ i0.ɵɵelementStart(140, "td", 211);
675
+ i0.ɵɵtext(141, "High");
676
+ i0.ɵɵelementEnd()();
677
+ i0.ɵɵelementStart(142, "tr")(143, "td")(144, "b");
678
+ i0.ɵɵtext(145, "LinkedIn hiring signals");
679
+ i0.ɵɵelementEnd()();
680
+ i0.ɵɵelementStart(146, "td");
681
+ i0.ɵɵtext(147, "Inferred");
682
+ i0.ɵɵelementEnd();
683
+ i0.ɵɵelementStart(148, "td", 211);
684
+ i0.ɵɵtext(149, "Medium");
685
+ i0.ɵɵelementEnd()()()()();
686
+ i0.ɵɵelementStart(150, "div", 217)(151, "span");
687
+ i0.ɵɵtext(152);
688
+ i0.ɵɵelementEnd();
689
+ i0.ɵɵelement(153, "span", 218);
690
+ i0.ɵɵelementStart(154, "span");
691
+ i0.ɵɵtext(155, "as of Jul 2026");
692
+ i0.ɵɵelementEnd()()()();
693
+ } if (rf & 2) {
694
+ const ctx_r2 = i0.ɵɵnextContext();
695
+ i0.ɵɵadvance(40);
696
+ i0.ɵɵrepeater(ctx_r2.barHeights);
697
+ i0.ɵɵadvance(3);
698
+ i0.ɵɵrepeater(ctx_r2.barCats);
699
+ i0.ɵɵadvance(109);
700
+ i0.ɵɵtextInterpolate(ctx_r2.footerNotice);
701
+ } }
702
+ function ThemeStudioDashboardComponent_For_67_Template(rf, ctx) { if (rf & 1) {
703
+ const _r26 = i0.ɵɵgetCurrentView();
704
+ i0.ɵɵelementStart(0, "button", 221);
705
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_For_67_Template_button_click_0_listener() { const p_r27 = i0.ɵɵrestoreView(_r26).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.applyPreset(p_r27)); });
706
+ i0.ɵɵelementStart(1, "span", 9);
707
+ i0.ɵɵelement(2, "i")(3, "i")(4, "i");
708
+ i0.ɵɵelementEnd();
709
+ i0.ɵɵelementStart(5, "small");
710
+ i0.ɵɵtext(6);
711
+ i0.ɵɵelementEnd()();
712
+ } if (rf & 2) {
713
+ const p_r27 = ctx.$implicit;
714
+ i0.ɵɵproperty("title", p_r27.name);
715
+ i0.ɵɵadvance(2);
716
+ i0.ɵɵstyleProp("background", p_r27.seeds.primary);
717
+ i0.ɵɵadvance();
718
+ i0.ɵɵstyleProp("background", p_r27.seeds.accent);
719
+ i0.ɵɵadvance();
720
+ i0.ɵɵstyleProp("background", p_r27.seeds.tertiary || p_r27.seeds.accent);
721
+ i0.ɵɵadvance(2);
722
+ i0.ɵɵtextInterpolate(p_r27.name);
723
+ } }
724
+ function ThemeStudioDashboardComponent_Conditional_129_Conditional_4_Template(rf, ctx) { if (rf & 1) {
725
+ i0.ɵɵelementStart(0, "span");
726
+ i0.ɵɵtext(1);
727
+ i0.ɵɵelementEnd();
728
+ } if (rf & 2) {
729
+ const worst_r28 = i0.ɵɵnextContext();
730
+ i0.ɵɵadvance();
731
+ i0.ɵɵtextInterpolate1(" \u2192 ", worst_r28.check.suggestion.hex);
732
+ } }
733
+ function ThemeStudioDashboardComponent_Conditional_129_Template(rf, ctx) { if (rf & 1) {
734
+ i0.ɵɵelementStart(0, "span", 222);
735
+ i0.ɵɵtext(1);
736
+ i0.ɵɵelementStart(2, "em", 223);
737
+ i0.ɵɵtext(3);
738
+ i0.ɵɵelementEnd();
739
+ i0.ɵɵconditionalCreate(4, ThemeStudioDashboardComponent_Conditional_129_Conditional_4_Template, 2, 1, "span");
740
+ i0.ɵɵelementEnd();
741
+ } if (rf & 2) {
742
+ const worst_r28 = ctx;
743
+ const ctx_r2 = i0.ɵɵnextContext();
744
+ i0.ɵɵclassProp("warn", !worst_r28.check.passes);
745
+ i0.ɵɵproperty("title", "light " + ((ctx_r2.onPrimaryDetail.light == null ? null : ctx_r2.onPrimaryDetail.light.ratio) ?? "\u2014") + ":1 \u00B7 dark " + ((ctx_r2.onPrimaryDetail.dark == null ? null : ctx_r2.onPrimaryDetail.dark.ratio) ?? "\u2014") + ":1");
746
+ i0.ɵɵadvance();
747
+ i0.ɵɵtextInterpolate2(" ", worst_r28.check.passes ? "\u2713" : "\u26A0", " ", worst_r28.check.ratio, ":1 ");
748
+ i0.ɵɵadvance(2);
749
+ i0.ɵɵtextInterpolate(worst_r28.mode);
750
+ i0.ɵɵadvance();
751
+ i0.ɵɵconditional(!worst_r28.check.passes && worst_r28.check.suggestion ? 4 : -1);
752
+ } }
753
+ function ThemeStudioDashboardComponent_Conditional_130_Conditional_0_Template(rf, ctx) { if (rf & 1) {
754
+ i0.ɵɵelementStart(0, "div", 224);
755
+ i0.ɵɵtext(1);
756
+ i0.ɵɵelementEnd();
757
+ } if (rf & 2) {
758
+ const d_r29 = ctx;
759
+ const l_r30 = i0.ɵɵnextContext();
760
+ i0.ɵɵadvance();
761
+ i0.ɵɵtextInterpolate4("Per mode: light ", l_r30.ratio, ":1 ", l_r30.passes ? "\u2713" : "\u26A0", " \u00B7 dark ", d_r29.ratio, ":1 ", d_r29.passes ? "\u2713" : "\u26A0");
762
+ } }
763
+ function ThemeStudioDashboardComponent_Conditional_130_Template(rf, ctx) { if (rf & 1) {
764
+ i0.ɵɵconditionalCreate(0, ThemeStudioDashboardComponent_Conditional_130_Conditional_0_Template, 2, 4, "div", 224);
765
+ } if (rf & 2) {
766
+ let tmp_4_0;
767
+ const ctx_r2 = i0.ɵɵnextContext();
768
+ i0.ɵɵconditional((tmp_4_0 = ctx_r2.onPrimaryDetail.dark) ? 0 : -1, tmp_4_0);
769
+ } }
770
+ function ThemeStudioDashboardComponent_For_144_Template(rf, ctx) { if (rf & 1) {
771
+ i0.ɵɵelementStart(0, "option", 63);
772
+ i0.ɵɵtext(1);
773
+ i0.ɵɵelementEnd();
774
+ } if (rf & 2) {
775
+ const f_r31 = ctx.$implicit;
776
+ i0.ɵɵproperty("value", f_r31.value);
777
+ i0.ɵɵadvance();
778
+ i0.ɵɵtextInterpolate(f_r31.label);
779
+ } }
780
+ function ThemeStudioDashboardComponent_Conditional_211_Template(rf, ctx) { if (rf & 1) {
781
+ const _r32 = i0.ɵɵgetCurrentView();
782
+ i0.ɵɵelementStart(0, "button", 225);
783
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_211_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.resetViz()); });
784
+ i0.ɵɵtext(1, "reset");
785
+ i0.ɵɵelementEnd();
786
+ } }
787
+ function ThemeStudioDashboardComponent_For_216_Template(rf, ctx) { if (rf & 1) {
788
+ const _r33 = i0.ɵɵgetCurrentView();
789
+ i0.ɵɵelementStart(0, "label", 226)(1, "span", 227);
790
+ i0.ɵɵtext(2);
791
+ i0.ɵɵelementEnd();
792
+ i0.ɵɵelementStart(3, "input", 228);
793
+ i0.ɵɵlistener("input", function ThemeStudioDashboardComponent_For_216_Template_input_input_3_listener($event) { const ɵ$index_1029_r34 = i0.ɵɵrestoreView(_r33).$index; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.editViz(ɵ$index_1029_r34, $event)); });
794
+ i0.ɵɵelementEnd()();
795
+ } if (rf & 2) {
796
+ const c_r35 = ctx.$implicit;
797
+ const ɵ$index_1029_r34 = ctx.$index;
798
+ i0.ɵɵstyleProp("background", c_r35);
799
+ i0.ɵɵadvance(2);
800
+ i0.ɵɵtextInterpolate(ɵ$index_1029_r34 + 1);
801
+ i0.ɵɵadvance();
802
+ i0.ɵɵproperty("value", c_r35);
803
+ } }
804
+ function ThemeStudioDashboardComponent_For_239_Template(rf, ctx) { if (rf & 1) {
805
+ const _r36 = i0.ɵɵgetCurrentView();
806
+ i0.ɵɵelementStart(0, "div", 51)(1, "div", 52);
807
+ i0.ɵɵtext(2);
808
+ i0.ɵɵelementStart(3, "small");
809
+ i0.ɵɵtext(4);
810
+ i0.ɵɵelementEnd()();
811
+ i0.ɵɵelementStart(5, "div", 53)(6, "mj-switch", 62);
812
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_For_239_Template_mj_switch_ngModelChange_6_listener() { const rs_r37 = i0.ɵɵrestoreView(_r36).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.toggleRecipe(rs_r37.recipe)); });
813
+ i0.ɵɵelementEnd()()();
814
+ } if (rf & 2) {
815
+ const rs_r37 = ctx.$implicit;
816
+ i0.ɵɵadvance(2);
817
+ i0.ɵɵtextInterpolate(rs_r37.recipe.name);
818
+ i0.ɵɵadvance(2);
819
+ i0.ɵɵtextInterpolate(rs_r37.recipe.description);
820
+ i0.ɵɵadvance(2);
821
+ i0.ɵɵproperty("ngModel", rs_r37.on);
822
+ i0.ɵɵattribute("aria-label", "Toggle " + rs_r37.recipe.name);
823
+ } }
824
+ function ThemeStudioDashboardComponent_Conditional_246_Template(rf, ctx) { if (rf & 1) {
825
+ const _r38 = i0.ɵɵgetCurrentView();
826
+ i0.ɵɵelementStart(0, "p", 85);
827
+ i0.ɵɵtext(1);
828
+ i0.ɵɵelementStart(2, "button", 229);
829
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_246_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r38); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.toggleAdvanced()); });
830
+ i0.ɵɵtext(3, "Edit");
831
+ i0.ɵɵelementEnd()();
832
+ } if (rf & 2) {
833
+ const ctx_r2 = i0.ɵɵnextContext();
834
+ i0.ɵɵadvance();
835
+ i0.ɵɵtextInterpolate1("", ctx_r2.advancedSummary, " ");
836
+ } }
837
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_4_Template(rf, ctx) { if (rf & 1) {
838
+ i0.ɵɵelementStart(0, "span", 255);
839
+ i0.ɵɵtext(1);
840
+ i0.ɵɵelementEnd();
841
+ } if (rf & 2) {
842
+ const g_r41 = i0.ɵɵnextContext().$implicit;
843
+ i0.ɵɵadvance();
844
+ i0.ɵɵtextInterpolate1("", g_r41.modified, " modified");
845
+ } }
846
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
847
+ i0.ɵɵelementStart(0, "span", 261);
848
+ i0.ɵɵtext(1, "modified");
849
+ i0.ɵɵelementEnd();
850
+ } }
851
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
852
+ const _r44 = i0.ɵɵgetCurrentView();
853
+ i0.ɵɵelementStart(0, "input", 266);
854
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_5_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r44); const ctx_r2 = i0.ɵɵnextContext(5); i0.ɵɵtwoWayBindingSet(ctx_r2.editingTokenValue, $event) || (ctx_r2.editingTokenValue = $event); return i0.ɵɵresetView($event); });
855
+ i0.ɵɵlistener("keydown.enter", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_5_Template_input_keydown_enter_0_listener() { i0.ɵɵrestoreView(_r44); const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.commitTokenEdit()); })("keydown.escape", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_5_Template_input_keydown_escape_0_listener() { i0.ɵɵrestoreView(_r44); const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.cancelTokenEdit()); })("blur", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_5_Template_input_blur_0_listener() { i0.ɵɵrestoreView(_r44); const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.commitTokenEdit()); });
856
+ i0.ɵɵelementEnd();
857
+ } if (rf & 2) {
858
+ const ctx_r2 = i0.ɵɵnextContext(5);
859
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.editingTokenValue);
860
+ } }
861
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
862
+ const _r45 = i0.ɵɵgetCurrentView();
863
+ i0.ɵɵelementStart(0, "label", 263)(1, "input", 228);
864
+ i0.ɵɵlistener("input", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_6_Template_input_input_1_listener($event) { i0.ɵɵrestoreView(_r45); const t_r43 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.onTokenColorInput(t_r43.name, $event)); });
865
+ i0.ɵɵelementEnd();
866
+ i0.ɵɵelementStart(2, "span", 267);
867
+ i0.ɵɵtext(3);
868
+ i0.ɵɵelementEnd()();
869
+ } if (rf & 2) {
870
+ const t_r43 = i0.ɵɵnextContext().$implicit;
871
+ i0.ɵɵproperty("title", t_r43.value);
872
+ i0.ɵɵadvance();
873
+ i0.ɵɵproperty("value", t_r43.colorValue);
874
+ i0.ɵɵadvance(2);
875
+ i0.ɵɵtextInterpolate(t_r43.value);
876
+ } }
877
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_7_Template(rf, ctx) { if (rf & 1) {
878
+ const _r46 = i0.ɵɵgetCurrentView();
879
+ i0.ɵɵelementStart(0, "button", 268);
880
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_7_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r46); const t_r43 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.beginTokenEdit(t_r43)); });
881
+ i0.ɵɵtext(1);
882
+ i0.ɵɵelementEnd();
883
+ } if (rf & 2) {
884
+ const t_r43 = i0.ɵɵnextContext().$implicit;
885
+ i0.ɵɵproperty("title", "Edit " + t_r43.name);
886
+ i0.ɵɵadvance();
887
+ i0.ɵɵtextInterpolate(t_r43.value);
888
+ } }
889
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_8_Template(rf, ctx) { if (rf & 1) {
890
+ const _r47 = i0.ɵɵgetCurrentView();
891
+ i0.ɵɵelementStart(0, "button", 269);
892
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r47); const t_r43 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.resetTokenOverride(t_r43.name)); });
893
+ i0.ɵɵelement(1, "i", 270);
894
+ i0.ɵɵelementEnd();
895
+ } }
896
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Template(rf, ctx) { if (rf & 1) {
897
+ const _r42 = i0.ɵɵgetCurrentView();
898
+ i0.ɵɵelementStart(0, "div", 258);
899
+ i0.ɵɵlistener("mouseenter", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Template_div_mouseenter_0_listener() { const t_r43 = i0.ɵɵrestoreView(_r42).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.highlightTokenTargets(t_r43.name)); })("mouseleave", function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Template_div_mouseleave_0_listener() { i0.ɵɵrestoreView(_r42); const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.clearTokenHighlight()); });
900
+ i0.ɵɵelement(1, "span", 259);
901
+ i0.ɵɵelementStart(2, "code", 260);
902
+ i0.ɵɵtext(3);
903
+ i0.ɵɵelementEnd();
904
+ i0.ɵɵconditionalCreate(4, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_4_Template, 2, 0, "span", 261);
905
+ i0.ɵɵconditionalCreate(5, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_5_Template, 1, 1, "input", 262)(6, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_6_Template, 4, 3, "label", 263)(7, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_7_Template, 2, 2, "button", 264);
906
+ i0.ɵɵconditionalCreate(8, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Conditional_8_Template, 2, 0, "button", 265);
907
+ i0.ɵɵelementEnd();
908
+ } if (rf & 2) {
909
+ const t_r43 = ctx.$implicit;
910
+ const ctx_r2 = i0.ɵɵnextContext(4);
911
+ i0.ɵɵclassProp("mod", t_r43.overridden);
912
+ i0.ɵɵadvance();
913
+ i0.ɵɵstyleProp("background", t_r43.value);
914
+ i0.ɵɵadvance();
915
+ i0.ɵɵproperty("title", t_r43.name);
916
+ i0.ɵɵadvance();
917
+ i0.ɵɵtextInterpolate(t_r43.name);
918
+ i0.ɵɵadvance();
919
+ i0.ɵɵconditional(t_r43.overridden ? 4 : -1);
920
+ i0.ɵɵadvance();
921
+ i0.ɵɵconditional(ctx_r2.editingToken === t_r43.name ? 5 : t_r43.isColor ? 6 : 7);
922
+ i0.ɵɵadvance(3);
923
+ i0.ɵɵconditional(t_r43.overridden ? 8 : -1);
924
+ } }
925
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_Template(rf, ctx) { if (rf & 1) {
926
+ i0.ɵɵrepeaterCreate(0, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_For_1_Template, 9, 9, "div", 257, _forTrack0);
927
+ } if (rf & 2) {
928
+ const g_r41 = i0.ɵɵnextContext().$implicit;
929
+ i0.ɵɵrepeater(g_r41.rows);
930
+ } }
931
+ function ThemeStudioDashboardComponent_Conditional_247_For_27_Template(rf, ctx) { if (rf & 1) {
932
+ const _r40 = i0.ɵɵgetCurrentView();
933
+ i0.ɵɵelementStart(0, "div", 240)(1, "button", 254);
934
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_For_27_Template_button_click_1_listener() { const g_r41 = i0.ɵɵrestoreView(_r40).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.toggleTokenCategory(g_r41.key)); });
935
+ i0.ɵɵelement(2, "i", 182);
936
+ i0.ɵɵtext(3);
937
+ i0.ɵɵconditionalCreate(4, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_4_Template, 2, 1, "span", 255);
938
+ i0.ɵɵelementStart(5, "span", 256);
939
+ i0.ɵɵtext(6);
940
+ i0.ɵɵelementEnd()();
941
+ i0.ɵɵconditionalCreate(7, ThemeStudioDashboardComponent_Conditional_247_For_27_Conditional_7_Template, 2, 0);
942
+ i0.ɵɵelementEnd();
943
+ } if (rf & 2) {
944
+ const g_r41 = ctx.$implicit;
945
+ const ctx_r2 = i0.ɵɵnextContext(2);
946
+ i0.ɵɵadvance(2);
947
+ i0.ɵɵclassProp("fa-chevron-down", ctx_r2.isTokenCategoryOpen(g_r41.key))("fa-chevron-right", !ctx_r2.isTokenCategoryOpen(g_r41.key));
948
+ i0.ɵɵadvance();
949
+ i0.ɵɵtextInterpolate1(" ", g_r41.label, " ");
950
+ i0.ɵɵadvance();
951
+ i0.ɵɵconditional(g_r41.modified > 0 ? 4 : -1);
952
+ i0.ɵɵadvance(2);
953
+ i0.ɵɵtextInterpolate(g_r41.rows.length);
954
+ i0.ɵɵadvance();
955
+ i0.ɵɵconditional(ctx_r2.isTokenCategoryOpen(g_r41.key) ? 7 : -1);
956
+ } }
957
+ function ThemeStudioDashboardComponent_Conditional_247_For_42_Template(rf, ctx) { if (rf & 1) {
958
+ const _r48 = i0.ɵɵgetCurrentView();
959
+ i0.ɵɵelementStart(0, "button", 271);
960
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_For_42_Template_button_click_0_listener() { const s_r49 = i0.ɵɵrestoreView(_r48).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.insertChromeSelector(s_r49.selector)); });
961
+ i0.ɵɵtext(1);
962
+ i0.ɵɵelementEnd();
963
+ } if (rf & 2) {
964
+ const s_r49 = ctx.$implicit;
965
+ i0.ɵɵproperty("title", s_r49.description);
966
+ i0.ɵɵadvance();
967
+ i0.ɵɵtextInterpolate(s_r49.selector);
968
+ } }
969
+ function ThemeStudioDashboardComponent_Conditional_247_For_48_Template(rf, ctx) { if (rf & 1) {
970
+ i0.ɵɵelementStart(0, "option", 63);
971
+ i0.ɵɵtext(1);
972
+ i0.ɵɵelementEnd();
973
+ } if (rf & 2) {
974
+ const n_r50 = ctx.$implicit;
975
+ i0.ɵɵproperty("value", n_r50);
976
+ i0.ɵɵadvance();
977
+ i0.ɵɵtextInterpolate(n_r50);
978
+ } }
979
+ function ThemeStudioDashboardComponent_Conditional_247_For_53_Template(rf, ctx) { if (rf & 1) {
980
+ i0.ɵɵelementStart(0, "p", 250);
981
+ i0.ɵɵelement(1, "i", 272);
982
+ i0.ɵɵtext(2);
983
+ i0.ɵɵelementEnd();
984
+ } if (rf & 2) {
985
+ const w_r51 = ctx.$implicit;
986
+ i0.ɵɵadvance(2);
987
+ i0.ɵɵtextInterpolate1(" ", w_r51);
988
+ } }
989
+ function ThemeStudioDashboardComponent_Conditional_247_Conditional_63_Template(rf, ctx) { if (rf & 1) {
990
+ const _r52 = i0.ɵɵgetCurrentView();
991
+ i0.ɵɵelementStart(0, "div", 253)(1, "button", 273);
992
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_Conditional_63_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r52); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.copyGeneratedCss()); });
993
+ i0.ɵɵelement(2, "i", 274);
994
+ i0.ɵɵtext(3, " Copy");
995
+ i0.ɵɵelementEnd();
996
+ i0.ɵɵelementStart(4, "div", 275);
997
+ i0.ɵɵelement(5, "mj-code-editor", 276);
998
+ i0.ɵɵelementEnd()();
999
+ } if (rf & 2) {
1000
+ const ctx_r2 = i0.ɵɵnextContext(2);
1001
+ i0.ɵɵadvance(5);
1002
+ i0.ɵɵproperty("value", ctx_r2.generatedCss);
1003
+ } }
1004
+ function ThemeStudioDashboardComponent_Conditional_247_Template(rf, ctx) { if (rf & 1) {
1005
+ const _r39 = i0.ɵɵgetCurrentView();
1006
+ i0.ɵɵelementStart(0, "div", 230)(1, "span", 231)(2, "b");
1007
+ i0.ɵɵtext(3, "1");
1008
+ i0.ɵɵelementEnd();
1009
+ i0.ɵɵtext(4, " Seeds");
1010
+ i0.ɵɵelementEnd();
1011
+ i0.ɵɵelement(5, "i", 232);
1012
+ i0.ɵɵelementStart(6, "span", 233)(7, "b");
1013
+ i0.ɵɵtext(8, "2");
1014
+ i0.ɵɵelementEnd();
1015
+ i0.ɵɵtext(9, " Token overrides");
1016
+ i0.ɵɵelementEnd();
1017
+ i0.ɵɵelement(10, "i", 232);
1018
+ i0.ɵɵelementStart(11, "span", 234)(12, "b");
1019
+ i0.ɵɵtext(13, "3");
1020
+ i0.ɵɵelementEnd();
1021
+ i0.ɵɵtext(14, " Custom CSS");
1022
+ i0.ɵɵelementEnd()();
1023
+ i0.ɵɵelementStart(15, "p", 50);
1024
+ i0.ɵɵtext(16, "Escalate in order. Seeds (above) cover most themes; token overrides refine specific surfaces; custom CSS is the escape hatch for what tokens can't express.");
1025
+ i0.ɵɵelementEnd();
1026
+ i0.ɵɵelementStart(17, "div", 235)(18, "div", 236)(19, "span", 237);
1027
+ i0.ɵɵtext(20, "2");
1028
+ i0.ɵɵelementEnd();
1029
+ i0.ɵɵtext(21, "Token overrides");
1030
+ i0.ɵɵelementEnd();
1031
+ i0.ɵɵelementStart(22, "p", 50);
1032
+ i0.ɵɵtext(23, "The full derived token contract, grouped and searchable. Click a swatch to override; hover a row to see where it's used in the preview. Overrides apply over the derived tokens (both modes).");
1033
+ i0.ɵɵelementEnd();
1034
+ i0.ɵɵelementStart(24, "input", 238);
1035
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Conditional_247_Template_input_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r39); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.tokenSearch, $event) || (ctx_r2.tokenSearch = $event); return i0.ɵɵresetView($event); });
1036
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Conditional_247_Template_input_ngModelChange_24_listener() { i0.ɵɵrestoreView(_r39); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onTokenSearchChanged()); });
1037
+ i0.ɵɵelementEnd();
1038
+ i0.ɵɵelementStart(25, "div", 239);
1039
+ i0.ɵɵrepeaterCreate(26, ThemeStudioDashboardComponent_Conditional_247_For_27_Template, 8, 8, "div", 240, _forTrack4);
1040
+ i0.ɵɵelementEnd()();
1041
+ i0.ɵɵelementStart(28, "div", 235)(29, "div", 236)(30, "span", 241);
1042
+ i0.ɵɵtext(31, "3");
1043
+ i0.ɵɵelementEnd();
1044
+ i0.ɵɵtext(32, "Custom CSS");
1045
+ i0.ɵɵelementStart(33, "span", 242);
1046
+ i0.ɵɵtext(34, "escape hatch");
1047
+ i0.ɵɵelementEnd()();
1048
+ i0.ɵɵelementStart(35, "p", 50);
1049
+ i0.ɵɵtext(36, "Only for what tokens can't express. Appended to the theme overlay, auto-scoped to this theme. ");
1050
+ i0.ɵɵelementStart(37, "code");
1051
+ i0.ɵɵtext(38, "@import");
1052
+ i0.ɵɵelementEnd();
1053
+ i0.ɵɵtext(39, " is not supported and is removed on save.");
1054
+ i0.ɵɵelementEnd();
1055
+ i0.ɵɵelementStart(40, "div", 243);
1056
+ i0.ɵɵrepeaterCreate(41, ThemeStudioDashboardComponent_Conditional_247_For_42_Template, 2, 2, "button", 244, _forTrack5);
1057
+ i0.ɵɵelementEnd();
1058
+ i0.ɵɵelementStart(43, "div", 245)(44, "select", 246);
1059
+ i0.ɵɵlistener("change", function ThemeStudioDashboardComponent_Conditional_247_Template_select_change_44_listener($event) { i0.ɵɵrestoreView(_r39); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onInsertTokenPick($event)); });
1060
+ i0.ɵɵelementStart(45, "option", 247);
1061
+ i0.ɵɵtext(46, "Insert token\u2026");
1062
+ i0.ɵɵelementEnd();
1063
+ i0.ɵɵrepeaterCreate(47, ThemeStudioDashboardComponent_Conditional_247_For_48_Template, 2, 2, "option", 63, i0.ɵɵrepeaterTrackByIdentity);
1064
+ i0.ɵɵelementEnd()();
1065
+ i0.ɵɵelementStart(49, "div", 248)(50, "mj-code-editor", 249, 4);
1066
+ i0.ɵɵlistener("change", function ThemeStudioDashboardComponent_Conditional_247_Template_mj_code_editor_change_50_listener($event) { i0.ɵɵrestoreView(_r39); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onCssEditorChange($event)); });
1067
+ i0.ɵɵelementEnd()();
1068
+ i0.ɵɵrepeaterCreate(52, ThemeStudioDashboardComponent_Conditional_247_For_53_Template, 3, 1, "p", 250, i0.ɵɵrepeaterTrackByIdentity);
1069
+ i0.ɵɵelementStart(54, "p", 251);
1070
+ i0.ɵɵtext(55, "The canvas preview of custom CSS is approximate \u2014 the mock's markup differs from the real chrome. Use the workspace preview to author against reality:");
1071
+ i0.ɵɵelementEnd();
1072
+ i0.ɵɵelementStart(56, "button", 27);
1073
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_Template_button_click_56_listener() { i0.ɵɵrestoreView(_r39); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.toggleWorkspacePreview()); });
1074
+ i0.ɵɵelement(57, "i", 182);
1075
+ i0.ɵɵtext(58);
1076
+ i0.ɵɵelementEnd()();
1077
+ i0.ɵɵelementStart(59, "div", 235)(60, "button", 252);
1078
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Conditional_247_Template_button_click_60_listener() { i0.ɵɵrestoreView(_r39); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.showGeneratedCss = !ctx_r2.showGeneratedCss); });
1079
+ i0.ɵɵelement(61, "i", 182);
1080
+ i0.ɵɵtext(62);
1081
+ i0.ɵɵelementEnd();
1082
+ i0.ɵɵconditionalCreate(63, ThemeStudioDashboardComponent_Conditional_247_Conditional_63_Template, 6, 1, "div", 253);
1083
+ i0.ɵɵelementEnd();
1084
+ } if (rf & 2) {
1085
+ const ctx_r2 = i0.ɵɵnextContext();
1086
+ i0.ɵɵadvance(24);
1087
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.tokenSearch);
1088
+ i0.ɵɵadvance(2);
1089
+ i0.ɵɵrepeater(ctx_r2.tokenGroups);
1090
+ i0.ɵɵadvance(15);
1091
+ i0.ɵɵrepeater(ctx_r2.chromeSelectorInfo);
1092
+ i0.ɵɵadvance(6);
1093
+ i0.ɵɵrepeater(ctx_r2.overridableTokens);
1094
+ i0.ɵɵadvance(3);
1095
+ i0.ɵɵproperty("value", ctx_r2.customCss)("extensions", ctx_r2.cssEditorExtensions)("lineWrapping", true);
1096
+ i0.ɵɵadvance(2);
1097
+ i0.ɵɵrepeater(ctx_r2.cssWarnings);
1098
+ i0.ɵɵadvance(4);
1099
+ i0.ɵɵproperty("variant", ctx_r2.workspacePreviewOn ? "warning" : "outline");
1100
+ i0.ɵɵadvance();
1101
+ i0.ɵɵclassProp("fa-eye", !ctx_r2.workspacePreviewOn)("fa-eye-slash", ctx_r2.workspacePreviewOn);
1102
+ i0.ɵɵadvance();
1103
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.workspacePreviewOn ? "End workspace preview" : "Preview on my workspace", " ");
1104
+ i0.ɵɵadvance(3);
1105
+ i0.ɵɵclassProp("fa-eye", !ctx_r2.showGeneratedCss)("fa-eye-slash", ctx_r2.showGeneratedCss);
1106
+ i0.ɵɵadvance();
1107
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.showGeneratedCss ? "Hide" : "View", " generated CSS ");
1108
+ i0.ɵɵadvance();
1109
+ i0.ɵɵconditional(ctx_r2.showGeneratedCss ? 63 : -1);
1110
+ } }
1111
+ /** Panel sizing (Q3): resizable with a min, an advanced-mode preset, and a preview floor. */
1112
+ const PANEL_MIN_WIDTH = 392;
1113
+ const PANEL_ADVANCED_WIDTH = 600;
1114
+ const PREVIEW_MIN_WIDTH = 640;
1115
+ const PANEL_MAX_FRACTION = 0.55;
1116
+ /** User-settings key for a manually-dragged panel width. */
1117
+ const PANEL_WIDTH_KEY = 'mj.themeStudio.panelWidth.v1';
1118
+ /** Brand-overlay id used for the temporary "Preview on my workspace" application. */
1119
+ const WORKSPACE_PREVIEW_ID = 'theme-studio-draft-preview';
1120
+ let ThemeStudioDashboardComponent = class ThemeStudioDashboardComponent extends BaseDashboard {
1121
+ cdRef;
1122
+ themeService;
1123
+ previewCanvas;
1124
+ nameInput;
1125
+ stageEl;
1126
+ cssCm;
1127
+ galDialog;
1128
+ themesChangedSub;
1129
+ presets = [
1130
+ { name: 'MJ Default', seeds: { ...MJ_DEFAULT_SEEDS } },
1131
+ { name: 'Cool Professional', seeds: { primary: '#4f46e5', accent: '#22d3ee', tertiary: '#0ea5e9', neutralChroma: 0.02, vibrancy: 1, radius: 8, depth: 1 } },
1132
+ { name: 'Warm Editorial', seeds: { primary: '#b45309', accent: '#e11d48', tertiary: '#d97706', neutralChroma: 0.05, vibrancy: 1.05, radius: 14, depth: 1 } },
1133
+ { name: 'High Contrast', seeds: { primary: '#0f172a', accent: '#2563eb', tertiary: '#0891b2', neutralChroma: 0, vibrancy: 1.2, radius: 4, depth: 1 } },
1134
+ { name: 'Muted Enterprise', seeds: { primary: '#0f766e', accent: '#64748b', tertiary: '#0e7490', neutralChroma: 0.03, vibrancy: 0.8, radius: 8, depth: 0.8 } },
1135
+ ];
1136
+ fontOptions = [
1137
+ { label: 'Inter (default)', value: MJ_DEFAULT_SEEDS.fontFamily },
1138
+ { label: 'Georgia (serif)', value: "'Georgia', 'Times New Roman', serif" },
1139
+ { label: 'Trebuchet', value: "'Trebuchet MS', Verdana, sans-serif" },
1140
+ { label: 'System UI', value: "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" },
1141
+ ];
1142
+ /** Height %s + labels for the demo bar chart. */
1143
+ barHeights = [64, 88, 72, 96, 80, 100];
1144
+ barValues = ['$0.5M', '$0.9M', '$0.7M', '$1.1M', '$0.8M', '$1.2M'];
1145
+ barCats = ['Prospect', 'Qualify', 'Propose', 'Negotiate', 'Commit', 'Won'];
1146
+ seeds = { ...MJ_DEFAULT_SEEDS };
1147
+ derived = derive(this.seeds);
1148
+ themes = [];
1149
+ currentThemeId = null;
1150
+ currentName = 'New Theme';
1151
+ previewMode = 'light';
1152
+ activeView = 'explorer';
1153
+ panelCollapsed = false;
1154
+ fullscreen = false;
1155
+ editingName = false;
1156
+ nameBackup = '';
1157
+ themePickerOpen = false;
1158
+ saving = false;
1159
+ /** Preset gallery shown as step one of "New theme" (Q1#2). */
1160
+ presetGalleryOpen = false;
1161
+ /** Toolbar segmented controls (mj-view-toggle options). */
1162
+ surfaceOptions = [
1163
+ { key: 'explorer', label: 'Explorer UI' },
1164
+ { key: 'artifact', label: 'Artifact' },
1165
+ ];
1166
+ modeOptions = [
1167
+ { key: 'light', label: 'Light', icon: 'fa-solid fa-sun' },
1168
+ { key: 'dark', label: 'Dark', icon: 'fa-solid fa-moon' },
1169
+ ];
1170
+ /** Preview-only branding/density knobs (not part of the seed contract yet). */
1171
+ footerNotice = 'Confidential';
1172
+ baseFontSize = 14;
1173
+ density = 16;
1174
+ /** Interactive-mock state (Q1#6) — clickable tabs/nav/switches/accordion so the
1175
+ * derived state token families (hover/active/focus) demonstrate themselves live. */
1176
+ mockNavItems = ['Dashboards', 'Data', 'Agents'];
1177
+ mockNav = 0;
1178
+ mockTabs = ['Overview', 'Members', 'Renewals'];
1179
+ mockTab = 0;
1180
+ mockSwitchA = true;
1181
+ mockSwitchB = false;
1182
+ mockAccordionOpen = false;
1183
+ /** Advanced customization (persisted): per-token overrides + raw scoped CSS. */
1184
+ advancedOpen = false;
1185
+ tokenOverrides = {};
1186
+ customCss = '';
1187
+ showGeneratedCss = false;
1188
+ /** Visual token browser state (Q2#1). */
1189
+ tokenSearch = '';
1190
+ tokenGroups = [];
1191
+ openTokenCats = new Set();
1192
+ editingToken = null;
1193
+ editingTokenValue = '';
1194
+ editingTokenOriginal = '';
1195
+ editingTokenWasOverridden = false;
1196
+ /** Recipes (Q2#3): curated intents expanded to token sets. On/off is tracked by
1197
+ * PROVENANCE — `activeRecipeKeys` records exactly which override keys each active
1198
+ * recipe produced, so hand-set overrides never masquerade as an active recipe and
1199
+ * toggling off removes only keys the recipe still owns. */
1200
+ chromeSelectorInfo = MJ_CHROME_SELECTOR_INFO;
1201
+ recipeStates = [];
1202
+ activeRecipeKeys = new Map();
1203
+ /** Inline custom-CSS validation results (Q3#6). */
1204
+ cssWarnings = [];
1205
+ /** Panel sizing (Q3#1/#2). */
1206
+ panelWidth = PANEL_MIN_WIDTH;
1207
+ panelResizing = false;
1208
+ manualPanelWidth = null;
1209
+ /** "Preview on my workspace" (Q3#8). */
1210
+ workspacePreviewOn = false;
1211
+ priorOverlayId = null;
1212
+ workspacePreviewTimer;
1213
+ /** CodeMirror extensions for the custom-CSS editor: MJ selector + token completions. */
1214
+ cssEditorExtensions = [
1215
+ autocompletion({ override: [(ctx) => this.mjCssCompletionSource(ctx)] }),
1216
+ ];
1217
+ tokenHighlightEl = null;
1218
+ appliedVarKeys = new Set();
1219
+ liveTokenCache = null;
1220
+ /** Sheet count the cache was built against — lazy-loaded chunks add stylesheets. */
1221
+ liveTokenCacheSheetCount = -1;
1222
+ constructor(cdRef, themeService) {
1223
+ super();
1224
+ this.cdRef = cdRef;
1225
+ this.themeService = themeService;
1226
+ }
1227
+ ngAfterViewInit() {
1228
+ this.syncPanelWidth();
1229
+ this.applyPreviewVars();
1230
+ }
1231
+ async GetResourceDisplayName(_data) {
1232
+ return 'Theme Studio';
1233
+ }
1234
+ initDashboard() {
1235
+ this.seeds = { ...MJ_DEFAULT_SEEDS };
1236
+ this.loadPersistedPanelWidth();
1237
+ this.refreshRecipeStates();
1238
+ this.recompute();
1239
+ // Keep the switcher list fresh when themes change in the Manage Themes tab.
1240
+ this.themesChangedSub = this.themeService.ThemesChanged$.subscribe(() => {
1241
+ this.loadData();
1242
+ });
1243
+ this.registerAgentTools();
1244
+ }
1245
+ ngOnDestroy() {
1246
+ this.themesChangedSub?.unsubscribe();
1247
+ clearTimeout(this.agentContextTimer);
1248
+ clearTimeout(this.workspacePreviewTimer);
1249
+ if (this.workspacePreviewOn) {
1250
+ void this.endWorkspacePreview(false);
1251
+ }
1252
+ super.ngOnDestroy();
1253
+ }
1254
+ /** Toggle the theme switcher; refresh the list on open so deletes/renames made in the
1255
+ * Manage Themes tab are reflected without a hard refresh. */
1256
+ async toggleThemePicker() {
1257
+ this.themePickerOpen = !this.themePickerOpen;
1258
+ if (this.themePickerOpen) {
1259
+ await this.loadData();
1260
+ }
1261
+ }
1262
+ async loadData() {
1263
+ try {
1264
+ const rv = new RunView();
1265
+ const result = await rv.RunView({
1266
+ EntityName: 'MJ: Themes',
1267
+ OrderBy: 'Name',
1268
+ ResultType: 'entity_object',
1269
+ });
1270
+ this.themes = (result.Success ? result.Results : []).map((t) => ({
1271
+ id: t.ID,
1272
+ name: t.Name,
1273
+ isDefault: t.IsDefault,
1274
+ swatches: this.swatchesFor(t.Seeds),
1275
+ }));
1276
+ }
1277
+ catch {
1278
+ this.themes = [];
1279
+ }
1280
+ this.publishAgentContext();
1281
+ this.cdRef.detectChanges();
1282
+ }
1283
+ swatchesFor(seedsJson) {
1284
+ try {
1285
+ const s = JSON.parse(seedsJson);
1286
+ return [s.primary, s.accent ?? s.primary, s.tertiary ?? s.accent ?? s.primary];
1287
+ }
1288
+ catch {
1289
+ return ['#0076b6', '#38a9d9', '#8b5cf6'];
1290
+ }
1291
+ }
1292
+ // ========================================
1293
+ // Derivation — the single source feeding every preview surface + validation + save
1294
+ // ========================================
1295
+ recompute() {
1296
+ this.derived = derive(this.seeds);
1297
+ this.reexpandActiveRecipes();
1298
+ this.applyPreviewVars();
1299
+ this.rebuildTokenBrowser();
1300
+ this.refreshWorkspacePreviewDebounced();
1301
+ }
1302
+ /** The text-on-primary contrast headline, reporting the WORST of light and dark (Q1#3). */
1303
+ get onPrimaryWorst() {
1304
+ const detail = this.onPrimaryDetail;
1305
+ return pickWorstOnPrimary(detail.light, detail.dark);
1306
+ }
1307
+ /** Per-mode text-on-primary detail shown alongside the worst-of-both headline. */
1308
+ get onPrimaryDetail() {
1309
+ return {
1310
+ light: this.derived.contrast.light.find((c) => c.name === 'text-on-primary'),
1311
+ dark: this.derived.contrast.dark.find((c) => c.name === 'text-on-primary'),
1312
+ };
1313
+ }
1314
+ /** All 10 derived categorical colors (--mj-viz-1..10) — the full chart-palette contract. */
1315
+ get vizColors() {
1316
+ return Array.from({ length: 10 }, (_, i) => this.derived.overlayVars[`--mj-viz-${i + 1}`]).filter(Boolean);
1317
+ }
1318
+ get vizOverridden() {
1319
+ return !!this.seeds.vizPalette && this.seeds.vizPalette.length > 0;
1320
+ }
1321
+ /** Dark-mode primary the theme derives (ramp step), shown as a note on the Brand card. */
1322
+ get darkPrimary() {
1323
+ return this.derived.tokens.dark['--mj-brand-primary'];
1324
+ }
1325
+ /** Secondary (deep brand) derived for light mode. */
1326
+ get secondaryColor() {
1327
+ return this.derived.tokens.light['--mj-brand-secondary'];
1328
+ }
1329
+ editViz(index, event) {
1330
+ const color = event.target.value;
1331
+ const arr = [...(this.seeds.vizPalette ?? this.vizColors)];
1332
+ arr[index] = color;
1333
+ this.seeds.vizPalette = arr;
1334
+ this.recompute();
1335
+ this.publishAgentContextDebounced();
1336
+ }
1337
+ resetViz() {
1338
+ delete this.seeds.vizPalette;
1339
+ this.recompute();
1340
+ }
1341
+ /**
1342
+ * Push the derived token map onto the preview canvas as scoped CSS vars — the
1343
+ * fidelity guarantee. Also sets preview-only density/size vars and the mode attr so
1344
+ * any [data-theme="dark"] rules inside the canvas resolve. Stale keys from removed
1345
+ * overrides (e.g. a recipe toggled off) are cleared before re-applying.
1346
+ */
1347
+ applyPreviewVars() {
1348
+ const el = this.previewCanvas?.nativeElement;
1349
+ if (!el)
1350
+ return;
1351
+ // Advanced token overrides win, layered last — mirrors emitOverlayCss's merge order.
1352
+ const vars = { ...this.derived.overlayVars, ...this.derived.tokens[this.previewMode], ...this.tokenOverrides };
1353
+ for (const k of this.appliedVarKeys) {
1354
+ if (!(k in vars))
1355
+ el.style.removeProperty(k);
1356
+ }
1357
+ this.appliedVarKeys = new Set(Object.keys(vars));
1358
+ for (const [k, v] of Object.entries(vars)) {
1359
+ el.style.setProperty(k, v);
1360
+ }
1361
+ el.style.setProperty('--ts-space', `${this.density}px`);
1362
+ el.style.setProperty('--ts-fs', `${this.baseFontSize}px`);
1363
+ el.setAttribute('data-theme', this.previewMode);
1364
+ this.applyPreviewCustomCss(el);
1365
+ }
1366
+ /** Inject the raw custom CSS into the preview, scoped to the canvas so it only affects
1367
+ * the preview (approximate — the mock's markup differs from live chrome selectors). */
1368
+ applyPreviewCustomCss(el) {
1369
+ const STYLE_ID = 'ts-preview-custom';
1370
+ let style = el.querySelector(`style#${STYLE_ID}`);
1371
+ const css = this.customCss.trim();
1372
+ if (!css) {
1373
+ style?.remove();
1374
+ return;
1375
+ }
1376
+ if (!style) {
1377
+ style = document.createElement('style');
1378
+ style.id = STYLE_ID;
1379
+ el.appendChild(style);
1380
+ }
1381
+ el.setAttribute('data-ts-preview', '1');
1382
+ // Same hoist-then-scope as the live overlay so @keyframes/@font-face work in preview too.
1383
+ style.textContent = emitScopedCustomCss('[data-ts-preview="1"]', css);
1384
+ }
1385
+ // ========================================
1386
+ // Advanced customization — token browser + recipes + raw CSS
1387
+ // ========================================
1388
+ /** Token names in the derived contract (completion, insert picker, validation). */
1389
+ get overridableTokens() {
1390
+ const names = new Set([...Object.keys(this.derived.overlayVars), ...Object.keys(this.derived.tokens.light)]);
1391
+ return Array.from(names).sort();
1392
+ }
1393
+ /** Overrides/custom CSS don't change derivation — re-apply the preview layer, refresh
1394
+ * the browser rows + recipe states, and keep any live workspace preview in sync. */
1395
+ onAdvancedChanged() {
1396
+ this.applyPreviewVars();
1397
+ this.rebuildTokenBrowser();
1398
+ this.refreshWorkspacePreviewDebounced();
1399
+ this.publishAgentContextDebounced();
1400
+ }
1401
+ /** Expand/collapse the Advanced card, auto-widening the panel while it's open (Q3#2). */
1402
+ toggleAdvanced() {
1403
+ this.advancedOpen = !this.advancedOpen;
1404
+ this.syncPanelWidth();
1405
+ }
1406
+ /** Closed-state summary — "3 token overrides · 14 lines CSS" (Q3#7). */
1407
+ get advancedSummary() {
1408
+ const overrideCount = Object.keys(this.tokenOverrides).length;
1409
+ const cssLines = this.customCss.trim() ? this.customCss.trim().split('\n').length : 0;
1410
+ if (!overrideCount && !cssLines)
1411
+ return null;
1412
+ const parts = [];
1413
+ if (overrideCount)
1414
+ parts.push(`${overrideCount} token override${overrideCount === 1 ? '' : 's'}`);
1415
+ if (cssLines)
1416
+ parts.push(`${cssLines} line${cssLines === 1 ? '' : 's'} CSS`);
1417
+ return parts.join(' · ');
1418
+ }
1419
+ // ---- Visual token browser (Q2#1) ----
1420
+ /** Rebuild the grouped, searchable token rows. */
1421
+ rebuildTokenBrowser() {
1422
+ const q = this.tokenSearch.trim().toLowerCase();
1423
+ const names = new Set([
1424
+ ...Object.keys(this.derived.overlayVars),
1425
+ ...Object.keys(this.derived.tokens.light),
1426
+ ...Object.keys(this.tokenOverrides),
1427
+ ]);
1428
+ const groups = TOKEN_CATEGORIES.map((c) => ({ key: c.key, label: c.label, rows: [], modified: 0 }));
1429
+ const other = { key: 'other', label: 'Other', rows: [], modified: 0 };
1430
+ for (const name of Array.from(names).sort()) {
1431
+ if (q && !name.toLowerCase().includes(q))
1432
+ continue;
1433
+ const derivedVal = this.derived.tokens[this.previewMode][name] ?? this.derived.overlayVars[name] ?? '';
1434
+ const overridden = name in this.tokenOverrides;
1435
+ const value = overridden ? this.tokenOverrides[name] : derivedVal;
1436
+ const hex = /^#[0-9a-fA-F]{6}$/.test(value.trim());
1437
+ const row = { name, value, overridden, isColor: hex, colorValue: hex ? value.trim() : '#000000' };
1438
+ const catIndex = TOKEN_CATEGORIES.findIndex((c) => c.match.test(name));
1439
+ const group = catIndex >= 0 ? groups[catIndex] : other;
1440
+ group.rows.push(row);
1441
+ if (overridden)
1442
+ group.modified++;
1443
+ }
1444
+ this.tokenGroups = [...groups, other].filter((g) => g.rows.length > 0);
1445
+ }
1446
+ onTokenSearchChanged() {
1447
+ this.rebuildTokenBrowser();
1448
+ }
1449
+ toggleTokenCategory(key) {
1450
+ if (this.openTokenCats.has(key)) {
1451
+ this.openTokenCats.delete(key);
1452
+ }
1453
+ else {
1454
+ this.openTokenCats.add(key);
1455
+ }
1456
+ }
1457
+ /** A category is open when toggled open, or always while a search narrows the rows. */
1458
+ isTokenCategoryOpen(key) {
1459
+ return this.tokenSearch.trim().length > 0 || this.openTokenCats.has(key);
1460
+ }
1461
+ setTokenOverride(name, value) {
1462
+ this.tokenOverrides = { ...this.tokenOverrides, [name]: value };
1463
+ this.releaseRecipeOwnership(name);
1464
+ this.onAdvancedChanged();
1465
+ }
1466
+ resetTokenOverride(name) {
1467
+ const next = { ...this.tokenOverrides };
1468
+ delete next[name];
1469
+ this.tokenOverrides = next;
1470
+ this.releaseRecipeOwnership(name);
1471
+ if (this.editingToken === name)
1472
+ this.editingToken = null;
1473
+ this.onAdvancedChanged();
1474
+ }
1475
+ onTokenColorInput(name, event) {
1476
+ this.setTokenOverride(name, event.target.value);
1477
+ }
1478
+ /** Begin inline text editing for a non-color token value. */
1479
+ beginTokenEdit(row) {
1480
+ this.editingToken = row.name;
1481
+ this.editingTokenValue = row.value;
1482
+ this.editingTokenOriginal = row.value;
1483
+ this.editingTokenWasOverridden = row.overridden;
1484
+ }
1485
+ commitTokenEdit() {
1486
+ if (!this.editingToken)
1487
+ return;
1488
+ const name = this.editingToken;
1489
+ const value = this.editingTokenValue.trim();
1490
+ this.editingToken = null;
1491
+ // An unchanged, previously-underived value is a no-op — don't mark it modified.
1492
+ if (!value || (!this.editingTokenWasOverridden && value === this.editingTokenOriginal))
1493
+ return;
1494
+ this.setTokenOverride(name, value);
1495
+ }
1496
+ cancelTokenEdit() {
1497
+ this.editingToken = null;
1498
+ }
1499
+ // ---- Reverse highlight (Q2#2): token row hover → outline preview elements ----
1500
+ /** Outline the preview elements that use `token` (exact by construction — the canvas
1501
+ * markup is ours; see TOKEN_PREVIEW_TARGETS). Unmapped tokens simply don't highlight. */
1502
+ highlightTokenTargets(token) {
1503
+ const canvas = this.previewCanvas?.nativeElement;
1504
+ if (!canvas)
1505
+ return;
1506
+ const selectors = TOKEN_PREVIEW_TARGETS[token];
1507
+ if (!selectors?.length) {
1508
+ this.clearTokenHighlight();
1509
+ return;
1510
+ }
1511
+ if (!this.tokenHighlightEl || !this.tokenHighlightEl.isConnected) {
1512
+ this.tokenHighlightEl = document.createElement('style');
1513
+ this.tokenHighlightEl.id = 'ts-token-highlight';
1514
+ canvas.appendChild(this.tokenHighlightEl);
1515
+ }
1516
+ const scoped = selectors.map((s) => `.ts-canvas ${s}`).join(', ');
1517
+ // Fixed magenta on purpose: an inspector affordance that must stand out on any theme.
1518
+ this.tokenHighlightEl.textContent = `${scoped} { outline: 2px solid #e935c1 !important; outline-offset: 2px; }`;
1519
+ }
1520
+ clearTokenHighlight() {
1521
+ if (this.tokenHighlightEl)
1522
+ this.tokenHighlightEl.textContent = '';
1523
+ }
1524
+ // ---- Recipes (Q2#3) — provenance-tracked ----
1525
+ /** Toggle a recipe: expand its token set into overrides (recording ownership), or
1526
+ * remove exactly the keys it still owns. Keys the user hand-edited after enabling
1527
+ * were released from ownership at edit time and are never touched here. */
1528
+ toggleRecipe(recipe) {
1529
+ const owned = this.activeRecipeKeys.get(recipe.id);
1530
+ const next = { ...this.tokenOverrides };
1531
+ if (owned) {
1532
+ for (const k of owned)
1533
+ delete next[k];
1534
+ this.activeRecipeKeys.delete(recipe.id);
1535
+ }
1536
+ else {
1537
+ const tokens = recipe.tokens(this.derived, this.seeds);
1538
+ const keys = Object.keys(tokens);
1539
+ if (keys.length === 0)
1540
+ return;
1541
+ Object.assign(next, tokens);
1542
+ this.activeRecipeKeys.set(recipe.id, keys);
1543
+ }
1544
+ this.tokenOverrides = next;
1545
+ this.refreshRecipeStates();
1546
+ this.onAdvancedChanged();
1547
+ }
1548
+ /** Derive the on/off rows shown in the Recipes card from the provenance map. */
1549
+ refreshRecipeStates() {
1550
+ this.recipeStates = THEME_RECIPES.map((recipe) => ({ recipe, on: this.activeRecipeKeys.has(recipe.id) }));
1551
+ }
1552
+ /** A hand edit (set or reset) takes ownership of `name` away from any active recipe,
1553
+ * so recipe toggle-off / re-expansion never clobbers or deletes the user's value.
1554
+ * A recipe left with no owned keys is effectively off. */
1555
+ releaseRecipeOwnership(name) {
1556
+ let changed = false;
1557
+ for (const [id, keys] of this.activeRecipeKeys) {
1558
+ if (!keys.includes(name))
1559
+ continue;
1560
+ const remaining = keys.filter((k) => k !== name);
1561
+ if (remaining.length > 0) {
1562
+ this.activeRecipeKeys.set(id, remaining);
1563
+ }
1564
+ else {
1565
+ this.activeRecipeKeys.delete(id);
1566
+ }
1567
+ changed = true;
1568
+ }
1569
+ if (changed)
1570
+ this.refreshRecipeStates();
1571
+ }
1572
+ /** Re-expand active recipes from the CURRENT derived theme so their values follow the
1573
+ * brand as seeds change. Only recipe-owned keys are rewritten; keys a recipe no
1574
+ * longer produces are dropped from both the overrides and the ownership record. */
1575
+ reexpandActiveRecipes() {
1576
+ if (this.activeRecipeKeys.size === 0)
1577
+ return;
1578
+ const next = { ...this.tokenOverrides };
1579
+ for (const recipe of THEME_RECIPES) {
1580
+ const owned = this.activeRecipeKeys.get(recipe.id);
1581
+ if (!owned)
1582
+ continue;
1583
+ const tokens = recipe.tokens(this.derived, this.seeds);
1584
+ const remaining = [];
1585
+ for (const key of owned) {
1586
+ if (key in tokens) {
1587
+ next[key] = tokens[key];
1588
+ remaining.push(key);
1589
+ }
1590
+ else {
1591
+ delete next[key];
1592
+ }
1593
+ }
1594
+ if (remaining.length > 0) {
1595
+ this.activeRecipeKeys.set(recipe.id, remaining);
1596
+ }
1597
+ else {
1598
+ this.activeRecipeKeys.delete(recipe.id);
1599
+ }
1600
+ }
1601
+ this.tokenOverrides = next;
1602
+ this.refreshRecipeStates();
1603
+ }
1604
+ /** Rebuild provenance for a freshly loaded override set (no stored provenance):
1605
+ * a recipe is considered active only when every key it would produce is present
1606
+ * with EXACTLY the value it would produce — since active recipes track the seeds
1607
+ * (see reexpandActiveRecipes), a saved active recipe always value-matches. */
1608
+ inferActiveRecipes() {
1609
+ this.activeRecipeKeys.clear();
1610
+ for (const recipe of THEME_RECIPES) {
1611
+ const tokens = recipe.tokens(this.derived, this.seeds);
1612
+ const keys = Object.keys(tokens);
1613
+ if (keys.length > 0 && keys.every((k) => this.tokenOverrides[k] === tokens[k])) {
1614
+ this.activeRecipeKeys.set(recipe.id, keys);
1615
+ }
1616
+ }
1617
+ this.refreshRecipeStates();
1618
+ }
1619
+ // ---- Custom CSS editor (Q3#4/#5/#6) ----
1620
+ onCssEditorChange(value) {
1621
+ this.customCss = value;
1622
+ this.validateCustomCss();
1623
+ this.onAdvancedChanged();
1624
+ }
1625
+ /** All completions offered: real chrome selectors + the theme's derived token names. */
1626
+ get cssSuggestions() {
1627
+ return [...MJ_CHROME_SELECTORS, ...this.overridableTokens];
1628
+ }
1629
+ /** CodeMirror completion source over the MJ chrome selectors + `--mj-*` tokens. */
1630
+ mjCssCompletionSource(context) {
1631
+ const word = context.matchBefore(/[-\w.]+/);
1632
+ if (!word || (word.text.length < 2 && !context.explicit))
1633
+ return null;
1634
+ return {
1635
+ from: word.from,
1636
+ options: this.cssSuggestions.map((s) => ({ label: s, type: s.startsWith('--') ? 'variable' : 'type' })),
1637
+ validFor: /^[-\w.]*$/,
1638
+ };
1639
+ }
1640
+ /** Insert a chrome selector at the caret; on an empty line, scaffold a full rule. */
1641
+ insertChromeSelector(selector) {
1642
+ const view = this.cssCm?.view;
1643
+ if (!view) {
1644
+ const prefix = this.customCss.trim() ? `${this.customCss.replace(/\s+$/, '')}\n\n` : '';
1645
+ this.onCssEditorChange(`${prefix}${selector} {\n \n}`);
1646
+ return;
1647
+ }
1648
+ const pos = view.state.selection.main.head;
1649
+ const line = view.state.doc.lineAt(pos);
1650
+ if (line.text.trim().length === 0) {
1651
+ const opener = `${selector} {\n `;
1652
+ view.dispatch({
1653
+ changes: { from: pos, insert: `${opener}\n}` },
1654
+ selection: { anchor: pos + opener.length },
1655
+ });
1656
+ }
1657
+ else {
1658
+ view.dispatch({
1659
+ changes: { from: pos, insert: selector },
1660
+ selection: { anchor: pos + selector.length },
1661
+ });
1662
+ }
1663
+ view.focus();
1664
+ }
1665
+ /** Insert-token picker (same enumeration the overrides use). */
1666
+ onInsertTokenPick(event) {
1667
+ const select = event.target;
1668
+ const token = select.value;
1669
+ select.value = '';
1670
+ if (!token)
1671
+ return;
1672
+ const text = `var(${token})`;
1673
+ const view = this.cssCm?.view;
1674
+ if (!view) {
1675
+ this.onCssEditorChange(this.customCss + text);
1676
+ return;
1677
+ }
1678
+ const pos = view.state.selection.main.head;
1679
+ view.dispatch({ changes: { from: pos, insert: text }, selection: { anchor: pos + text.length } });
1680
+ view.focus();
1681
+ }
1682
+ /** Inline validation at edit time (Q3#6): @import removal + unknown --mj-* names. */
1683
+ validateCustomCss() {
1684
+ this.cssWarnings = buildCssWarnings(this.customCss, this.knownMjTokens());
1685
+ }
1686
+ /** The full known --mj-* set: the derived contract ∪ every token the live app defines. */
1687
+ knownMjTokens() {
1688
+ const known = new Set(this.overridableTokens);
1689
+ for (const t of this.collectLiveMjTokens())
1690
+ known.add(t);
1691
+ return known;
1692
+ }
1693
+ /** Scan loaded stylesheets for every defined `--mj-*` custom property, so the
1694
+ * unknown-name warning validates against the real base contract (no false positives
1695
+ * on base tokens outside the derived overlay, e.g. --mj-shadow-sm). Re-scans when
1696
+ * the stylesheet count changes (lazy-loaded chunks add sheets after first scan). */
1697
+ collectLiveMjTokens() {
1698
+ if (this.liveTokenCache && document.styleSheets.length === this.liveTokenCacheSheetCount) {
1699
+ return this.liveTokenCache;
1700
+ }
1701
+ this.liveTokenCacheSheetCount = document.styleSheets.length;
1702
+ const set = new Set();
1703
+ for (const sheet of Array.from(document.styleSheets)) {
1704
+ let rules;
1705
+ try {
1706
+ rules = sheet.cssRules;
1707
+ }
1708
+ catch {
1709
+ continue; // cross-origin sheet
1710
+ }
1711
+ for (const rule of Array.from(rules)) {
1712
+ this.collectTokensFromRule(rule, set);
1713
+ }
1714
+ }
1715
+ this.liveTokenCache = set;
1716
+ return set;
1717
+ }
1718
+ collectTokensFromRule(rule, set) {
1719
+ if (rule instanceof CSSStyleRule) {
1720
+ for (const prop of Array.from(rule.style)) {
1721
+ if (prop.startsWith('--mj-'))
1722
+ set.add(prop);
1723
+ }
1724
+ }
1725
+ const children = rule.cssRules;
1726
+ if (children) {
1727
+ for (const child of Array.from(children)) {
1728
+ this.collectTokensFromRule(child, set);
1729
+ }
1730
+ }
1731
+ }
1732
+ /** The actual overlay CSS this theme produces (tokens + advanced layer) — read-only view. */
1733
+ get generatedCss() {
1734
+ return emitOverlayCss(this.currentThemeId ?? 'preview', this.derived, {
1735
+ overrides: this.tokenOverrides,
1736
+ customCss: this.customCss,
1737
+ });
1738
+ }
1739
+ async copyGeneratedCss() {
1740
+ try {
1741
+ await navigator.clipboard.writeText(this.generatedCss);
1742
+ this.notify('Generated CSS copied to clipboard.');
1743
+ }
1744
+ catch {
1745
+ this.notify('Copy failed — select the text and copy manually.');
1746
+ }
1747
+ }
1748
+ // ========================================
1749
+ // View / panel / fullscreen chrome
1750
+ // ========================================
1751
+ setView(view) {
1752
+ this.activeView = view;
1753
+ }
1754
+ setPreviewMode(mode) {
1755
+ this.previewMode = mode;
1756
+ this.applyPreviewVars();
1757
+ this.rebuildTokenBrowser();
1758
+ this.publishAgentContextDebounced();
1759
+ }
1760
+ /** mj-view-toggle (KeyChange) adapter for the light/dark segment. */
1761
+ onModeToggle(key) {
1762
+ this.setPreviewMode(key === 'dark' ? 'dark' : 'light');
1763
+ }
1764
+ /** mj-view-toggle (KeyChange) adapter for the preview-surface chips. */
1765
+ onSurfaceToggle(key) {
1766
+ this.setView(key === 'artifact' ? 'artifact' : 'explorer');
1767
+ this.publishAgentContextDebounced();
1768
+ }
1769
+ togglePanel() {
1770
+ this.panelCollapsed = !this.panelCollapsed;
1771
+ this.publishAgentContextDebounced();
1772
+ }
1773
+ // ---- Panel resize (Q3#1): drag handle, clamped, persisted per user ----
1774
+ /** Clamp a requested panel width: >= the design minimum, <= 55% of the stage, and
1775
+ * never eating the canvas below its ~640px floor (the resize clamps, not the preview). */
1776
+ clampPanelWidth(width) {
1777
+ const stageWidth = this.stageEl?.nativeElement.clientWidth ?? window.innerWidth;
1778
+ const max = Math.max(PANEL_MIN_WIDTH, Math.min(stageWidth * PANEL_MAX_FRACTION, stageWidth - PREVIEW_MIN_WIDTH));
1779
+ return Math.round(Math.min(max, Math.max(PANEL_MIN_WIDTH, width)));
1780
+ }
1781
+ /** Manually-dragged width wins; otherwise auto-widen while Advanced is open (Q3#2). */
1782
+ syncPanelWidth() {
1783
+ this.panelWidth = this.clampPanelWidth(this.manualPanelWidth ?? (this.advancedOpen ? PANEL_ADVANCED_WIDTH : PANEL_MIN_WIDTH));
1784
+ }
1785
+ loadPersistedPanelWidth() {
1786
+ try {
1787
+ const raw = UserInfoEngine.Instance.GetSetting(PANEL_WIDTH_KEY);
1788
+ const parsed = raw ? parseInt(raw, 10) : NaN;
1789
+ if (Number.isFinite(parsed) && parsed >= PANEL_MIN_WIDTH) {
1790
+ this.manualPanelWidth = parsed;
1791
+ }
1792
+ }
1793
+ catch {
1794
+ // no persisted width — defaults apply
1795
+ }
1796
+ this.syncPanelWidth();
1797
+ }
1798
+ startPanelResize(event) {
1799
+ event.preventDefault();
1800
+ const handle = event.target;
1801
+ this.panelResizing = true;
1802
+ const startX = event.clientX;
1803
+ const startWidth = this.panelWidth;
1804
+ const onMove = (e) => {
1805
+ this.panelWidth = this.clampPanelWidth(startWidth + (startX - e.clientX));
1806
+ this.cdRef.detectChanges();
1807
+ };
1808
+ const end = () => {
1809
+ handle.removeEventListener('pointermove', onMove);
1810
+ handle.removeEventListener('pointerup', end);
1811
+ handle.removeEventListener('pointercancel', end);
1812
+ this.panelResizing = false;
1813
+ this.manualPanelWidth = this.panelWidth;
1814
+ UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_KEY, String(this.panelWidth));
1815
+ this.cdRef.detectChanges();
1816
+ };
1817
+ // Pointer capture routes all events to the handle until release: drags ending
1818
+ // outside the window still fire pointerup, pointercancel (touch interruption) is
1819
+ // handled, and the listeners die with the element if the component is destroyed.
1820
+ handle.setPointerCapture(event.pointerId);
1821
+ handle.addEventListener('pointermove', onMove);
1822
+ handle.addEventListener('pointerup', end);
1823
+ handle.addEventListener('pointercancel', end);
1824
+ }
1825
+ onWindowResize() {
1826
+ this.syncPanelWidth();
1827
+ }
1828
+ /** Prefer the native Fullscreen API — it promotes the canvas to the browser's top
1829
+ * layer, so it fills the real screen regardless of any transformed/`contain`ed
1830
+ * ancestor, and browser Esc reliably exits. Falls back to CSS-fixed overlay if the
1831
+ * API is unavailable or rejects. */
1832
+ async toggleFullscreen(on) {
1833
+ try {
1834
+ if (on) {
1835
+ const el = this.previewCanvas?.nativeElement;
1836
+ if (el?.requestFullscreen) {
1837
+ await el.requestFullscreen();
1838
+ return; // state syncs via fullscreenchange
1839
+ }
1840
+ }
1841
+ else if (document.fullscreenElement) {
1842
+ await document.exitFullscreen();
1843
+ return;
1844
+ }
1845
+ }
1846
+ catch {
1847
+ /* fall through to CSS fallback */
1848
+ }
1849
+ this.fullscreen = on;
1850
+ this.cdRef.detectChanges();
1851
+ }
1852
+ onFullscreenChange() {
1853
+ this.fullscreen = !!document.fullscreenElement;
1854
+ this.cdRef.detectChanges();
1855
+ }
1856
+ onEscape() {
1857
+ if (this.presetGalleryOpen) {
1858
+ this.presetGalleryOpen = false;
1859
+ this.cdRef.detectChanges();
1860
+ return;
1861
+ }
1862
+ // Only needed for the CSS fallback; native fullscreen handles Esc itself.
1863
+ if (this.fullscreen && !document.fullscreenElement) {
1864
+ this.fullscreen = false;
1865
+ this.cdRef.detectChanges();
1866
+ }
1867
+ }
1868
+ onDensityChanged() {
1869
+ this.applyPreviewVars();
1870
+ }
1871
+ onBaseSizeChanged() {
1872
+ this.applyPreviewVars();
1873
+ }
1874
+ // ========================================
1875
+ // Editing
1876
+ // ========================================
1877
+ applyPreset(preset) {
1878
+ this.seeds = { ...preset.seeds };
1879
+ if (!this.currentThemeId) {
1880
+ this.currentName = this.uniqueName(preset.name);
1881
+ }
1882
+ this.recompute();
1883
+ }
1884
+ uniqueName(base) {
1885
+ const taken = new Set(this.themes.map((t) => t.name.trim().toLowerCase()));
1886
+ if (!taken.has(base.trim().toLowerCase()))
1887
+ return base;
1888
+ for (let i = 2; i < 1000; i++) {
1889
+ const candidate = `${base} ${i}`;
1890
+ if (!taken.has(candidate.toLowerCase()))
1891
+ return candidate;
1892
+ }
1893
+ return `${base} ${Date.now()}`;
1894
+ }
1895
+ onSeedsChanged() {
1896
+ this.recompute();
1897
+ this.publishAgentContextDebounced();
1898
+ }
1899
+ async selectTheme(item) {
1900
+ this.themePickerOpen = false;
1901
+ const md = this.ProviderToUse;
1902
+ const entity = await md.GetEntityObject('MJ: Themes');
1903
+ if (!(await entity.Load(item.id))) {
1904
+ this.cdRef.detectChanges();
1905
+ return;
1906
+ }
1907
+ this.currentThemeId = entity.ID;
1908
+ this.currentName = entity.Name;
1909
+ try {
1910
+ this.seeds = { ...MJ_DEFAULT_SEEDS, ...JSON.parse(entity.Seeds) };
1911
+ }
1912
+ catch {
1913
+ this.seeds = { ...MJ_DEFAULT_SEEDS };
1914
+ }
1915
+ this.tokenOverrides = parseOverridesJson(entity.Overrides);
1916
+ this.customCss = entity.CustomCSS ?? '';
1917
+ this.validateCustomCss();
1918
+ // Provenance from the outgoing theme must not survive into the loaded one; the
1919
+ // loaded overrides carry no provenance, so rebuild it by exact value match.
1920
+ this.activeRecipeKeys.clear();
1921
+ this.recompute();
1922
+ this.inferActiveRecipes();
1923
+ this.publishAgentContext();
1924
+ // Async continuation under the OnPush resource wrapper: refresh the header pill,
1925
+ // editor inputs, and preview now that the loaded theme is in place.
1926
+ this.cdRef.detectChanges();
1927
+ }
1928
+ get currentIsDefault() {
1929
+ const id = this.currentThemeId;
1930
+ return id ? this.themes.find((t) => UUIDsEqual(t.id, id))?.isDefault ?? false : false;
1931
+ }
1932
+ /** Whether a picker row is the currently-loaded theme (case-insensitive GUID compare). */
1933
+ isCurrentTheme(id) {
1934
+ return !!this.currentThemeId && UUIDsEqual(id, this.currentThemeId);
1935
+ }
1936
+ /** The protected built-in theme is read-only — editing/saving over it is blocked. */
1937
+ get isBuiltInSelected() {
1938
+ return isBuiltInTheme(this.currentThemeId);
1939
+ }
1940
+ /** Fork the current seeds into a new, editable theme (used to customize the built-in). */
1941
+ saveAsCopy() {
1942
+ this.currentThemeId = null;
1943
+ this.currentName = this.uniqueName(`${this.currentName} Copy`);
1944
+ this.notify(`Editing a copy — "${this.currentName}". Save to create it.`);
1945
+ }
1946
+ /** Inline-rename the current theme in the header. For a saved theme the new name is
1947
+ * persisted immediately on commit; for an unsaved draft it persists on Save. */
1948
+ startRename() {
1949
+ if (this.isBuiltInSelected) {
1950
+ this.notify('The built-in theme is read-only — use "Save as copy" to rename it.');
1951
+ return;
1952
+ }
1953
+ this.nameBackup = this.currentName;
1954
+ this.editingName = true;
1955
+ setTimeout(() => this.nameInput?.nativeElement.select());
1956
+ }
1957
+ async commitRename() {
1958
+ if (!this.editingName)
1959
+ return;
1960
+ this.editingName = false;
1961
+ this.currentName = this.currentName.trim() || this.nameBackup || 'Untitled theme';
1962
+ // No change, unsaved draft, or built-in → nothing to persist now.
1963
+ if (this.currentName === this.nameBackup || !this.currentThemeId || this.isBuiltInSelected)
1964
+ return;
1965
+ try {
1966
+ const md = this.ProviderToUse;
1967
+ const entity = await md.GetEntityObject('MJ: Themes');
1968
+ if (!(await entity.Load(this.currentThemeId)))
1969
+ return;
1970
+ entity.Name = this.currentName;
1971
+ if (await entity.Save()) {
1972
+ await this.loadData();
1973
+ this.themeService.NotifyThemesChanged();
1974
+ this.notify(`Renamed to "${this.currentName}".`);
1975
+ }
1976
+ else {
1977
+ const msg = entity.LatestResult?.CompleteMessage ?? 'unknown error';
1978
+ this.currentName = this.nameBackup;
1979
+ this.notify(/UQ_Theme_Name|UNIQUE KEY/i.test(msg) ? `A theme named "${entity.Name}" already exists — choose a different name.` : `Rename failed: ${msg}`, 'error');
1980
+ }
1981
+ }
1982
+ catch (e) {
1983
+ this.currentName = this.nameBackup;
1984
+ this.notify(`Rename failed: ${e instanceof Error ? e.message : String(e)}`, 'error');
1985
+ }
1986
+ finally {
1987
+ this.cdRef.detectChanges();
1988
+ }
1989
+ }
1990
+ cancelRename() {
1991
+ this.currentName = this.nameBackup;
1992
+ this.editingName = false;
1993
+ }
1994
+ /**
1995
+ * Start a fresh, unsaved draft. From the UI this opens on the preset gallery
1996
+ * (choosing a personality first, Q1#2); agent-driven calls skip straight to the
1997
+ * MJ default seeds.
1998
+ */
1999
+ newTheme(showGallery = true) {
2000
+ this.themePickerOpen = false;
2001
+ this.currentThemeId = null;
2002
+ this.currentName = 'New Theme';
2003
+ this.seeds = { ...MJ_DEFAULT_SEEDS };
2004
+ this.tokenOverrides = {};
2005
+ this.customCss = '';
2006
+ this.cssWarnings = [];
2007
+ this.activeRecipeKeys.clear();
2008
+ this.refreshRecipeStates();
2009
+ this.recompute();
2010
+ this.presetGalleryOpen = showGallery;
2011
+ if (showGallery)
2012
+ this.focusPresetGallery();
2013
+ }
2014
+ /** Move focus into the gallery once it renders — aria-modal without focus is a trap
2015
+ * for keyboard/AT users (Esc + Tab must operate on the dialog, not what's behind it). */
2016
+ focusPresetGallery() {
2017
+ setTimeout(() => this.galDialog?.nativeElement.focus());
2018
+ }
2019
+ /** Preset gallery: pick a personality card as step one of a new theme. */
2020
+ choosePreset(preset) {
2021
+ this.presetGalleryOpen = false;
2022
+ this.applyPreset(preset);
2023
+ this.cdRef.detectChanges();
2024
+ }
2025
+ /** Close the gallery keeping the MJ-default draft (the "start blank" path). */
2026
+ closePresetGallery() {
2027
+ this.presetGalleryOpen = false;
2028
+ }
2029
+ discard() {
2030
+ const id = this.currentThemeId;
2031
+ const current = id ? this.themes.find((t) => UUIDsEqual(t.id, id)) : undefined;
2032
+ if (current) {
2033
+ this.selectTheme(current);
2034
+ }
2035
+ else {
2036
+ this.newTheme(false);
2037
+ }
2038
+ }
2039
+ // ========================================
2040
+ // Persistence
2041
+ // ========================================
2042
+ async save() {
2043
+ if (this.isBuiltInSelected) {
2044
+ this.notify('The built-in theme is read-only — use "Save as copy" to customize it.');
2045
+ return;
2046
+ }
2047
+ const name = this.currentName.trim();
2048
+ if (!name) {
2049
+ this.notify('Give the theme a name before saving.');
2050
+ return;
2051
+ }
2052
+ // If this isn't already a loaded theme but the name matches an existing one, treat
2053
+ // Save as an UPDATE to that theme (names are unique, so a match is unambiguous) —
2054
+ // rather than blocking and forcing the user to make a new theme.
2055
+ if (!this.currentThemeId) {
2056
+ const existing = this.themes.find((t) => t.name.trim().toLowerCase() === name.toLowerCase());
2057
+ if (existing) {
2058
+ if (isBuiltInTheme(existing.id)) {
2059
+ this.notify('The built-in theme is read-only — rename it to save a copy.');
2060
+ return;
2061
+ }
2062
+ this.currentThemeId = existing.id;
2063
+ }
2064
+ }
2065
+ this.saving = true;
2066
+ try {
2067
+ const md = this.ProviderToUse;
2068
+ const entity = await md.GetEntityObject('MJ: Themes');
2069
+ if (this.currentThemeId) {
2070
+ if (!(await entity.Load(this.currentThemeId))) {
2071
+ this.notify('Could not load the theme to update — it may have been deleted. Refresh and try again.', 'error');
2072
+ return;
2073
+ }
2074
+ }
2075
+ else {
2076
+ entity.NewRecord();
2077
+ entity.Status = 'Active';
2078
+ }
2079
+ entity.Name = name;
2080
+ entity.Seeds = JSON.stringify(this.seeds);
2081
+ entity.Overrides = Object.keys(this.tokenOverrides).length ? JSON.stringify(this.tokenOverrides) : null;
2082
+ entity.CustomCSS = this.customCss.trim() || null;
2083
+ if (await entity.Save()) {
2084
+ const wasNew = !this.currentThemeId;
2085
+ this.currentThemeId = entity.ID;
2086
+ // While the draft preview is on, BrandOverlayId is the preview id — the theme
2087
+ // the user actually has applied is the one the preview will restore.
2088
+ const liveOverlayId = this.workspacePreviewOn ? this.priorOverlayId : this.themeService.BrandOverlayId;
2089
+ if (UUIDsEqual(liveOverlayId, entity.ID) || (!wasNew && entity.IsDefault)) {
2090
+ await this.applyLive();
2091
+ }
2092
+ await this.loadData();
2093
+ this.themeService.NotifyThemesChanged();
2094
+ this.notify(`Saved "${entity.Name}".`);
2095
+ }
2096
+ else {
2097
+ this.notify(`Save failed: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`, 'error');
2098
+ }
2099
+ }
2100
+ catch (e) {
2101
+ const msg = e instanceof Error ? e.message : String(e);
2102
+ this.notify(/UQ_Theme_Name|UNIQUE KEY/i.test(msg) ? `A theme named "${name}" already exists — choose a different name.` : `Save failed: ${msg}`, 'error');
2103
+ }
2104
+ finally {
2105
+ this.saving = false;
2106
+ this.cdRef.detectChanges();
2107
+ }
2108
+ }
2109
+ async setAsDefault() {
2110
+ if (this.currentThemeId)
2111
+ await this.setDefaultById(this.currentThemeId);
2112
+ }
2113
+ /**
2114
+ * Make theme `id` the single org default and apply it live. Clears any other
2115
+ * default first (app-layer enforcement — there is no DB unique index), then applies
2116
+ * the persisted seeds via ThemeService so the running app re-themes immediately.
2117
+ */
2118
+ async setDefaultById(id) {
2119
+ try {
2120
+ const md = this.ProviderToUse;
2121
+ const rv = new RunView();
2122
+ const others = await rv.RunView({
2123
+ EntityName: 'MJ: Themes',
2124
+ ExtraFilter: `IsDefault = 1 AND ID <> '${id}'`,
2125
+ ResultType: 'entity_object',
2126
+ });
2127
+ if (others.Success) {
2128
+ for (const other of others.Results) {
2129
+ other.IsDefault = false;
2130
+ if (!(await other.Save())) {
2131
+ this.notify(`Could not clear the previous default "${other.Name}": ${other.LatestResult?.CompleteMessage ?? 'unknown error'}`, 'error');
2132
+ return;
2133
+ }
2134
+ }
2135
+ }
2136
+ const entity = await md.GetEntityObject('MJ: Themes');
2137
+ if (!(await entity.Load(id)))
2138
+ return;
2139
+ entity.IsDefault = true;
2140
+ if (!(await entity.Save())) {
2141
+ this.notify(`Could not set default: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`, 'error');
2142
+ return;
2143
+ }
2144
+ let seeds;
2145
+ try {
2146
+ seeds = { ...MJ_DEFAULT_SEEDS, ...JSON.parse(entity.Seeds) };
2147
+ }
2148
+ catch {
2149
+ seeds = { ...MJ_DEFAULT_SEEDS };
2150
+ }
2151
+ this.abandonWorkspacePreview();
2152
+ this.themeService.RegisterBrandTheme({ id: entity.ID, name: entity.Name, seeds, overrides: entity.Overrides, customCss: entity.CustomCSS });
2153
+ await this.themeService.ApplyBrandOverlay(entity.ID);
2154
+ await this.loadData();
2155
+ this.themeService.NotifyThemesChanged();
2156
+ this.notify(`"${entity.Name}" is now the default and is applied.`);
2157
+ }
2158
+ catch (e) {
2159
+ this.notify(`Could not set default: ${e instanceof Error ? e.message : String(e)}`, 'error');
2160
+ }
2161
+ finally {
2162
+ this.cdRef.detectChanges();
2163
+ }
2164
+ }
2165
+ /** Apply the current (edited) theme to the live app via ThemeService (used on save). */
2166
+ async applyLive() {
2167
+ if (!this.currentThemeId)
2168
+ return;
2169
+ // A real apply supersedes any draft workspace preview — abandon it (no restore;
2170
+ // the overlay applied below takes over) so a later toggle-off can't revert this.
2171
+ this.abandonWorkspacePreview();
2172
+ this.themeService.RegisterBrandTheme({
2173
+ id: this.currentThemeId,
2174
+ name: this.currentName,
2175
+ seeds: this.seeds,
2176
+ overrides: this.tokenOverrides,
2177
+ customCss: this.customCss,
2178
+ });
2179
+ await this.themeService.ApplyBrandOverlay(this.currentThemeId);
2180
+ }
2181
+ /**
2182
+ * Apply this theme to the current user's workspace now and remember it as their
2183
+ * choice (persists across sessions). Distinct from "Set as org default", which is
2184
+ * the organization-wide fallback for everyone.
2185
+ */
2186
+ async applyToMe() {
2187
+ if (!this.currentThemeId)
2188
+ return;
2189
+ await this.applyLive();
2190
+ await this.themeService.SetSelectedBrandTheme(this.currentThemeId);
2191
+ this.notify(`Applied "${this.currentName}" to your workspace — it stays applied across sessions.`);
2192
+ this.cdRef.detectChanges();
2193
+ }
2194
+ // ---- "Preview on my workspace" (Q3#8): draft against the REAL chrome ----
2195
+ /**
2196
+ * Temporarily apply the in-memory draft (seeds + overrides + custom CSS) to the real
2197
+ * app chrome so custom-CSS selectors are authored against reality. The preview stays
2198
+ * on while you navigate other tabs (that's the point — the Studio tab is cached, not
2199
+ * destroyed) and reverts on toggle-off or when the Studio tab is closed. It is never
2200
+ * persisted ({ persist: false }), so a reload always restores the user's real theme.
2201
+ */
2202
+ async toggleWorkspacePreview() {
2203
+ if (this.workspacePreviewOn) {
2204
+ await this.endWorkspacePreview();
2205
+ return;
2206
+ }
2207
+ this.priorOverlayId = this.themeService.BrandOverlayId;
2208
+ this.registerDraftPreview();
2209
+ await this.themeService.ApplyBrandOverlay(WORKSPACE_PREVIEW_ID, { persist: false });
2210
+ this.workspacePreviewOn = true;
2211
+ this.notify('Draft applied to your workspace for preview — edits update live. Toggle off to revert.', 'info');
2212
+ this.cdRef.detectChanges();
2213
+ }
2214
+ registerDraftPreview() {
2215
+ this.themeService.RegisterBrandTheme({
2216
+ id: WORKSPACE_PREVIEW_ID,
2217
+ name: `${this.currentName} (draft preview)`,
2218
+ seeds: this.seeds,
2219
+ overrides: this.tokenOverrides,
2220
+ customCss: this.customCss,
2221
+ });
2222
+ }
2223
+ /** While the workspace preview is on, keep it tracking the draft (debounced). */
2224
+ refreshWorkspacePreviewDebounced() {
2225
+ if (!this.workspacePreviewOn)
2226
+ return;
2227
+ clearTimeout(this.workspacePreviewTimer);
2228
+ this.workspacePreviewTimer = setTimeout(() => {
2229
+ if (!this.workspacePreviewOn)
2230
+ return;
2231
+ this.registerDraftPreview();
2232
+ void this.themeService.ApplyBrandOverlay(WORKSPACE_PREVIEW_ID, { persist: false });
2233
+ }, 400);
2234
+ }
2235
+ /** Drop the draft preview WITHOUT restoring the prior overlay — used when a real
2236
+ * apply (Apply to me / save-of-live-theme / set org default) is about to take over
2237
+ * the workspace, so a later toggle-off can't silently revert what the user applied. */
2238
+ abandonWorkspacePreview() {
2239
+ if (!this.workspacePreviewOn)
2240
+ return;
2241
+ this.workspacePreviewOn = false;
2242
+ clearTimeout(this.workspacePreviewTimer);
2243
+ this.priorOverlayId = null;
2244
+ }
2245
+ async endWorkspacePreview(notifyUser = true) {
2246
+ if (!this.workspacePreviewOn)
2247
+ return;
2248
+ this.workspacePreviewOn = false;
2249
+ clearTimeout(this.workspacePreviewTimer);
2250
+ if (this.priorOverlayId) {
2251
+ await this.themeService.ApplyBrandOverlay(this.priorOverlayId);
2252
+ }
2253
+ else {
2254
+ this.themeService.ClearBrandOverlay();
2255
+ }
2256
+ this.priorOverlayId = null;
2257
+ if (notifyUser) {
2258
+ this.notify('Workspace preview ended — your previous theme is back.');
2259
+ this.cdRef.detectChanges();
2260
+ }
2261
+ }
2262
+ notify(message, style = 'success') {
2263
+ MJNotificationService.Instance.CreateSimpleNotification(message, style, 2500);
2264
+ }
2265
+ // ---------------------------------------------------------------
2266
+ // Agent context + tools (read / preview-state / user-scoped only —
2267
+ // see the SAFETY BOUNDARY in theme-agent-context.ts)
2268
+ // ---------------------------------------------------------------
2269
+ agentContextTimer;
2270
+ summaryRows() {
2271
+ return this.themes.map((t) => ({
2272
+ ID: t.id,
2273
+ Name: t.name,
2274
+ Status: 'Active',
2275
+ IsDefault: t.isDefault,
2276
+ BuiltIn: isBuiltInTheme(t.id),
2277
+ }));
2278
+ }
2279
+ publishAgentContext() {
2280
+ this.navigationService.SetAgentContext(this, buildThemeStudioAgentContext({
2281
+ Themes: this.summaryRows(),
2282
+ CurrentThemeID: this.currentThemeId,
2283
+ CurrentThemeName: this.currentName,
2284
+ IsBuiltInSelected: this.isBuiltInSelected,
2285
+ PreviewMode: this.previewMode,
2286
+ PreviewSurface: this.activeView,
2287
+ EditorPanelOpen: !this.panelCollapsed,
2288
+ Seeds: this.seeds,
2289
+ OverrideTokenCount: Object.keys(this.tokenOverrides).length,
2290
+ HasCustomCss: this.customCss.trim().length > 0,
2291
+ Contrast: this.derived.contrast,
2292
+ }));
2293
+ }
2294
+ /** Coalesce slider-drag bursts into one context publish. */
2295
+ publishAgentContextDebounced() {
2296
+ clearTimeout(this.agentContextTimer);
2297
+ this.agentContextTimer = setTimeout(() => this.publishAgentContext(), 300);
2298
+ }
2299
+ registerAgentTools() {
2300
+ this.navigationService.SetAgentClientTools(this, [
2301
+ {
2302
+ Name: 'ListThemes',
2303
+ Description: 'Reload and return the saved brand themes available in the studio.',
2304
+ ParameterSchema: { type: 'object', properties: {} },
2305
+ Handler: async () => {
2306
+ await this.loadData();
2307
+ return { Success: true, Data: { ThemeNames: this.themes.map((t) => t.name).slice(0, 25) } };
2308
+ },
2309
+ },
2310
+ {
2311
+ Name: 'SelectTheme',
2312
+ Description: 'Load a saved theme into the editor, referenced by ID or name (partial, case-insensitive match accepted).',
2313
+ ParameterSchema: {
2314
+ type: 'object',
2315
+ properties: { theme: { type: 'string', description: 'The theme ID or name.' } },
2316
+ required: ['theme'],
2317
+ },
2318
+ Handler: async (params) => {
2319
+ const resolved = resolveThemeByIDOrName(this.summaryRows(), params['theme']);
2320
+ if (!resolved.ok) {
2321
+ return { Success: false, ErrorMessage: resolved.error };
2322
+ }
2323
+ const item = this.themes.find((t) => UUIDsEqual(t.id, resolved.value.ID));
2324
+ if (!item) {
2325
+ return { Success: false, ErrorMessage: 'Theme list changed — run ListThemes and retry.' };
2326
+ }
2327
+ await this.selectTheme(item);
2328
+ return { Success: true, Data: { CurrentThemeName: this.currentName } };
2329
+ },
2330
+ },
2331
+ {
2332
+ Name: 'NewTheme',
2333
+ Description: 'Start a fresh, unsaved theme draft from the MJ default seeds (nothing persists until the user saves).',
2334
+ ParameterSchema: { type: 'object', properties: {} },
2335
+ Handler: async () => {
2336
+ this.newTheme(false);
2337
+ this.cdRef.detectChanges();
2338
+ return { Success: true, Data: { CurrentThemeName: this.currentName } };
2339
+ },
2340
+ },
2341
+ {
2342
+ Name: 'ApplyPreset',
2343
+ Description: `Apply a named starting preset to the in-memory draft. Available presets: ${this.presets.map((p) => p.name).join(', ')}.`,
2344
+ ParameterSchema: {
2345
+ type: 'object',
2346
+ properties: { preset: { type: 'string', description: 'The preset name (partial match accepted).' } },
2347
+ required: ['preset'],
2348
+ },
2349
+ Handler: async (params) => {
2350
+ const ref = typeof params['preset'] === 'string' ? params['preset'].trim().toLowerCase() : '';
2351
+ const preset = this.presets.find((p) => p.name.toLowerCase() === ref)
2352
+ ?? this.presets.find((p) => p.name.toLowerCase().includes(ref));
2353
+ if (!ref || !preset) {
2354
+ return { Success: false, ErrorMessage: `Unknown preset. Available: ${this.presets.map((p) => p.name).join(', ')}.` };
2355
+ }
2356
+ this.presetGalleryOpen = false;
2357
+ this.applyPreset(preset);
2358
+ this.publishAgentContext();
2359
+ this.cdRef.detectChanges();
2360
+ return { Success: true, Data: { Preset: preset.name } };
2361
+ },
2362
+ },
2363
+ {
2364
+ Name: 'SetSeeds',
2365
+ Description: 'Update one or more brand seeds on the IN-MEMORY draft (preview only — the user saves from the UI). Colors are hex like #0076b6.',
2366
+ ParameterSchema: {
2367
+ type: 'object',
2368
+ properties: {
2369
+ primary: { type: 'string', description: 'Primary brand hex color.' },
2370
+ accent: { type: 'string', description: 'Accent hex color.' },
2371
+ tertiary: { type: 'string', description: 'Tertiary hex color.' },
2372
+ neutralChroma: { type: 'number', description: 'Brand tint in grays, 0–0.08.' },
2373
+ vibrancy: { type: 'number', description: 'Ramp saturation multiplier, 0.5–1.4.' },
2374
+ radius: { type: 'number', description: 'Base corner radius in px, 0–20.' },
2375
+ depth: { type: 'number', description: 'Brand shadow strength, 0–1.' },
2376
+ },
2377
+ },
2378
+ Handler: async (params) => this.handleSetSeeds(params),
2379
+ },
2380
+ {
2381
+ Name: 'SetPreviewMode',
2382
+ Description: "Switch the preview between 'light' and 'dark'.",
2383
+ ParameterSchema: {
2384
+ type: 'object',
2385
+ properties: { mode: { type: 'string', description: "'light' | 'dark'" } },
2386
+ required: ['mode'],
2387
+ },
2388
+ Handler: async (params) => {
2389
+ const mode = params['mode'];
2390
+ if (mode !== 'light' && mode !== 'dark') {
2391
+ return { Success: false, ErrorMessage: "mode must be 'light' or 'dark'." };
2392
+ }
2393
+ this.setPreviewMode(mode);
2394
+ this.cdRef.detectChanges();
2395
+ return { Success: true, Data: { PreviewMode: this.previewMode } };
2396
+ },
2397
+ },
2398
+ {
2399
+ Name: 'SetPreviewSurface',
2400
+ Description: "Switch the preview surface between 'explorer' (chrome style guide) and 'artifact' (generated report).",
2401
+ ParameterSchema: {
2402
+ type: 'object',
2403
+ properties: { surface: { type: 'string', description: "'explorer' | 'artifact'" } },
2404
+ required: ['surface'],
2405
+ },
2406
+ Handler: async (params) => {
2407
+ const surface = params['surface'];
2408
+ if (surface !== 'explorer' && surface !== 'artifact') {
2409
+ return { Success: false, ErrorMessage: "surface must be 'explorer' or 'artifact'." };
2410
+ }
2411
+ this.setView(surface);
2412
+ this.cdRef.detectChanges();
2413
+ return { Success: true, Data: { PreviewSurface: this.activeView } };
2414
+ },
2415
+ },
2416
+ {
2417
+ Name: 'ApplyToMe',
2418
+ Description: "Apply the currently-loaded SAVED theme to the CURRENT USER's workspace (a per-user preference — not the org default). Fails on an unsaved draft.",
2419
+ ParameterSchema: { type: 'object', properties: {} },
2420
+ Handler: async () => {
2421
+ if (!this.currentThemeId) {
2422
+ return { Success: false, ErrorMessage: 'The draft is unsaved — the user must save it first.' };
2423
+ }
2424
+ await this.applyToMe();
2425
+ return { Success: true, Data: { AppliedThemeName: this.currentName } };
2426
+ },
2427
+ },
2428
+ ]);
2429
+ }
2430
+ /** Validate + apply a partial seed update from the agent (clamped to the UI ranges). */
2431
+ handleSetSeeds(params) {
2432
+ const HEX = /^#[0-9a-fA-F]{6}$/;
2433
+ const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
2434
+ const next = { ...this.seeds };
2435
+ let changed = 0;
2436
+ for (const key of ['primary', 'accent', 'tertiary']) {
2437
+ const v = params[key];
2438
+ if (v !== undefined) {
2439
+ if (typeof v !== 'string' || !HEX.test(v.trim())) {
2440
+ return { Success: false, ErrorMessage: `${key} must be a 6-digit hex color like #0076b6.` };
2441
+ }
2442
+ next[key] = v.trim().toLowerCase();
2443
+ changed++;
2444
+ }
2445
+ }
2446
+ const numeric = [
2447
+ { key: 'neutralChroma', lo: 0, hi: 0.08 },
2448
+ { key: 'vibrancy', lo: 0.5, hi: 1.4 },
2449
+ { key: 'radius', lo: 0, hi: 20 },
2450
+ { key: 'depth', lo: 0, hi: 1 },
2451
+ ];
2452
+ for (const { key, lo, hi } of numeric) {
2453
+ const v = params[key];
2454
+ if (v !== undefined) {
2455
+ if (typeof v !== 'number' || !Number.isFinite(v)) {
2456
+ return { Success: false, ErrorMessage: `${key} must be a number between ${lo} and ${hi}.` };
2457
+ }
2458
+ next[key] = clamp(v, lo, hi);
2459
+ changed++;
2460
+ }
2461
+ }
2462
+ if (changed === 0) {
2463
+ return { Success: false, ErrorMessage: 'Provide at least one seed to change.' };
2464
+ }
2465
+ this.seeds = next;
2466
+ this.recompute();
2467
+ this.publishAgentContext();
2468
+ this.cdRef.detectChanges();
2469
+ return { Success: true, Data: { SeedsChanged: changed, ContrastPasses: this.derived.contrast.passes } };
2470
+ }
2471
+ static ɵfac = function ThemeStudioDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ThemeStudioDashboardComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1.ThemeService)); };
2472
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ThemeStudioDashboardComponent, selectors: [["mj-theme-studio-dashboard"]], viewQuery: function ThemeStudioDashboardComponent_Query(rf, ctx) { if (rf & 1) {
2473
+ i0.ɵɵviewQuery(_c0, 5)(_c1, 5)(_c2, 5)(_c3, 5)(_c4, 5);
2474
+ } if (rf & 2) {
2475
+ let _t;
2476
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.previewCanvas = _t.first);
2477
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.nameInput = _t.first);
2478
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.stageEl = _t.first);
2479
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.cssCm = _t.first);
2480
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.galDialog = _t.first);
2481
+ } }, hostBindings: function ThemeStudioDashboardComponent_HostBindings(rf, ctx) { if (rf & 1) {
2482
+ i0.ɵɵlistener("resize", function ThemeStudioDashboardComponent_resize_HostBindingHandler() { return ctx.onWindowResize(); }, i0.ɵɵresolveWindow)("fullscreenchange", function ThemeStudioDashboardComponent_fullscreenchange_HostBindingHandler() { return ctx.onFullscreenChange(); }, i0.ɵɵresolveDocument)("keydown.escape", function ThemeStudioDashboardComponent_keydown_escape_HostBindingHandler() { return ctx.onEscape(); }, i0.ɵɵresolveDocument);
2483
+ } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 248, vars: 71, consts: [["stage", ""], ["previewCanvas", ""], ["nameInput", ""], ["galDialog", ""], ["cssCm", ""], ["Title", "Theme Studio", "Icon", "fa-solid fa-palette", "Subtitle", "Organization theme & branding"], ["meta", ""], [1, "theme-pick-wrap"], [1, "theme-pick"], [1, "sw"], ["maxlength", "80", "aria-label", "Theme name", 1, "name-input", 3, "ngModel"], [1, "badge"], ["type", "button", "title", "Switch theme", "aria-label", "Switch theme", 1, "pick-caret", 3, "click"], [1, "fa-solid", "fa-chevron-down", "caret"], [1, "readonly-note"], [1, "preview-note"], ["actions", ""], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], ["mjButton", "", "variant", "outline", "size", "sm", "title", "Apply this theme to your workspace now \u2014 it persists across sessions until you pick another", 3, "click", "disabled"], ["mjButton", "", "variant", "outline", "size", "sm", "title", "Make this the organization-wide default theme for everyone", 3, "click", "disabled"], ["mjButton", "", "variant", "primary", "size", "sm"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "disabled"], ["toolbar", ""], [3, "KeyChange", "Options", "ActiveKey"], [1, "toolbar-spacer"], ["mjButton", "", "variant", "icon", "ariaLabel", "Full screen preview", "title", "Full screen preview", 3, "click"], [1, "fa-solid", "fa-expand"], ["mjButton", "", "size", "sm", 3, "click", "variant"], [1, "fa-solid", "fa-sliders"], [3, "Padding", "Flex"], [1, "ts-stage"], [1, "pv-wrap"], [1, "pv-inner"], [1, "ts-canvas"], [1, "fs-bar"], [1, "pv-scroll"], [1, "pv-view"], ["aria-label", "Theme editor", 1, "ts-panel"], ["role", "separator", "aria-orientation", "vertical", "aria-label", "Resize editor panel", "title", "Drag to resize", 1, "panel-resize", 3, "pointerdown"], [1, "panel-h"], [1, "ic"], [1, "fa-solid", "fa-palette"], ["type", "button", "title", "Collapse panel", 1, "collapse-btn", 3, "click"], [1, "fa-solid", "fa-chevron-right"], [1, "panel-body"], [1, "card"], [1, "fa-solid", "fa-plus"], [1, "preset-row"], ["type", "button", 1, "preset", 3, "title"], [1, "scope"], [1, "sub"], [1, "row"], [1, "lab"], [1, "ctl"], [1, "clr"], ["type", "color", 3, "ngModelChange", "ngModel"], [1, "hex"], [1, "derived-note"], [1, "clr", "static"], [1, "sw-box"], [1, "ok", 3, "warn", "title"], [1, "fa-solid", "fa-font"], [3, "ngModelChange", "ngModel"], [3, "value"], ["type", "range", "min", "0.5", "max", "1.4", "step", "0.05", 3, "ngModelChange", "ngModel"], [1, "val"], ["type", "range", "min", "0", "max", "0.08", "step", "0.005", 3, "ngModelChange", "ngModel"], ["type", "range", "min", "12", "max", "18", "step", "1", 3, "ngModelChange", "ngModel"], [1, "fa-solid", "fa-square"], ["type", "range", "min", "0", "max", "20", "step", "1", 3, "ngModelChange", "ngModel"], ["type", "range", "min", "0", "max", "1", "step", "0.1", 3, "ngModelChange", "ngModel"], [1, "miniseg"], ["type", "button", 3, "click"], [1, "fa-solid", "fa-chart-column"], ["type", "button", 1, "reset-link"], [1, "swrow"], [1, "chip-clr", 3, "background"], [1, "fa-solid", "fa-image"], [1, "tinput", 3, "ngModelChange", "ngModel"], [1, "sub", 2, "margin", "8px 0 0"], [1, "fa-solid", "fa-wand-magic-sparkles"], [1, "card", "adv-card"], [1, "adv-head", 3, "click"], [1, "fa-solid", "fa-code"], [1, "fa-solid", "caret"], [1, "adv-summary"], ["maxlength", "80", "aria-label", "Theme name", 1, "name-input", 3, "ngModelChange", "keydown.enter", "keydown.escape", "blur", "ngModel"], [1, "theme-name", 3, "dblclick"], ["type", "button", "title", "Rename theme", "aria-label", "Rename theme", 1, "rename-btn"], ["type", "button", "title", "Rename theme", "aria-label", "Rename theme", 1, "rename-btn", 3, "click"], [1, "fa-solid", "fa-pen"], [1, "menu-backdrop", 3, "click"], [1, "theme-menu"], ["type", "button", 1, "theme-menu-item", 3, "on"], ["type", "button", 1, "theme-menu-new", 3, "click"], ["type", "button", 1, "theme-menu-item", 3, "click"], [3, "background"], [1, "fa-solid", "fa-lock"], [1, "fa-solid", "fa-eye"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "gal-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-label", "Start a new theme", "tabindex", "-1", 1, "gal"], [1, "gal-sub"], [1, "gal-grid"], ["type", "button", 1, "gal-card"], [1, "gal-foot"], ["type", "button", 1, "gal-card", 3, "click"], [1, "gal-mock"], [1, "gal-mock-bar"], [1, "gal-mock-body"], [1, "gal-line"], [1, "gal-line", "short"], [1, "gal-mock-row"], [1, "gal-dot"], [1, "gal-btn"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "kbd"], [1, "zone-lab"], [1, "mx"], [1, "mx-shell"], [1, "mx-appico"], [1, "fa-solid", "fa-table-cells-large"], [1, "mx-nav"], ["tabindex", "0", "role", "button", 3, "on"], ["tabindex", "0", 1, "mx-search"], [1, "fa-solid", "fa-magnifying-glass"], [1, "mx-sp"], ["tabindex", "0", 1, "mx-av"], [1, "mx-ph"], [1, "mx-ph-top"], [1, "mx-ph-ico"], [1, "fa-solid", "fa-users"], [1, "mx-ph-title"], [1, "mx-ph-sub"], [1, "mx-ph-actions"], [1, "mx-btn", "sec"], [1, "mx-btn", "pri"], [1, "mx-toolbar"], ["role", "tablist", 1, "mx-tabs"], ["tabindex", "0", "role", "tab", 3, "on"], [1, "mx-body"], [1, "mx-cell", "wide"], [1, "mx-cap"], [1, "mx-row"], [1, "mx-btn", "out"], [1, "mx-btn", "dgr"], [1, "mx-row", "states-row"], [1, "mx-btn", "pri", "is-hover"], [1, "mx-btn", "pri", "is-active"], [1, "mx-btn", "pri", "is-focus"], ["disabled", "", 1, "mx-btn", "pri"], [1, "mx-btn", "sec", "is-hover"], [1, "mx-btn", "sec", "is-active"], [1, "mx-btn", "sec", "is-focus"], ["disabled", "", 1, "mx-btn", "sec"], [1, "mx-btn", "out", "is-hover"], [1, "mx-btn", "out", "is-active"], [1, "mx-btn", "out", "is-focus"], ["disabled", "", 1, "mx-btn", "out"], [1, "mx-btn", "dgr", "is-hover"], [1, "mx-btn", "dgr", "is-active"], [1, "mx-btn", "dgr", "is-focus"], ["disabled", "", 1, "mx-btn", "dgr"], [1, "mx-input", "focus", 2, "flex", "1"], ["tabindex", "0", 1, "mx-input", 2, "flex", "1"], [1, "fa-solid", "fa-chevron-down"], ["role", "switch", "tabindex", "0", "aria-label", "Toggle switch", 1, "mx-swch", 3, "click", "keydown.enter", "keydown.space"], ["role", "switch", "tabindex", "0", "aria-label", "Toggle auto-renew", 1, "mx-swch", 3, "click", "keydown.enter", "keydown.space"], [1, "mx-lbl"], [1, "mx-cell"], ["tabindex", "0", 1, "mx-chip", "on"], ["tabindex", "0", 1, "mx-chip"], [1, "mx-stat", "brand"], [1, "mx-stat", "suc"], [1, "mx-stat", "wrn"], [1, "mx-prog"], [1, "mx-lnav"], ["tabindex", "0", 1, "on"], [1, "fa-solid", "fa-house"], ["tabindex", "0"], ["tabindex", "0", "role", "button", 3, "click", "keydown.enter", "keydown.space"], [1, "fa-solid"], [1, "mx-alert"], [1, "mx-dlg"], [1, "mx-dlg-t"], [1, "mx-dlg-b"], [1, "mx-input", "focus", 2, "width", "100%"], [1, "mx-dlg-a"], ["tabindex", "0", "role", "tab", 3, "click", "keydown.enter", "keydown.space"], ["tabindex", "0", 1, "mx-acc-item"], [1, "report"], [1, "rhead"], [1, "logo"], [1, "ti"], [1, "su"], [1, "rt"], [1, "rbody"], [1, "kpis"], [1, "kpi"], [1, "n"], [1, "l"], [1, "d", "up"], [1, "d", "dn"], [1, "chart"], [1, "ct"], [1, "cs"], [1, "bars"], [1, "bar"], [1, "cats"], [1, "grid"], [1, "r"], [1, "ag-sum"], [1, "ag-finds"], [1, "ag-find"], [1, "fdot"], [1, "mx-stat", "neu"], [1, "rfoot"], [1, "dot"], [1, "bv"], [1, "fill"], ["type", "button", 1, "preset", 3, "click", "title"], [1, "ok", 3, "title"], [1, "mode-tag"], [1, "derived-note", "contrast-detail"], ["type", "button", 1, "reset-link", 3, "click"], [1, "chip-clr"], [1, "chip-num"], ["type", "color", 3, "input", "value"], ["type", "button", 1, "reset-link", "adv-edit", 3, "click"], ["aria-hidden", "true", 1, "ladder"], [1, "ladder-step", "done"], [1, "fa-solid", "fa-arrow-right"], [1, "ladder-step"], [1, "ladder-step", "esc"], [1, "adv-sec"], [1, "adv-lab"], [1, "step-num"], ["type", "search", "placeholder", "Search tokens (e.g. hover, surface, viz)\u2026", "spellcheck", "false", 1, "tinput", "tok-search", 3, "ngModelChange", "ngModel"], [1, "tok-groups"], [1, "tok-group"], [1, "step-num", "esc"], [1, "esc-tag"], [1, "sel-chips"], ["type", "button", 1, "sel-chip", 3, "title"], [1, "css-tools"], ["aria-label", "Insert a token at the cursor", 1, "tok-pick", 3, "change"], ["value", ""], [1, "adv-css-editor"], ["language", "css", "setup", "basic", "placeholder", "mj-shell { box-shadow: none; }", 3, "change", "value", "extensions", "lineWrapping"], [1, "css-warn"], [1, "sub", "adv-note"], ["type", "button", 1, "adv-add", 3, "click"], [1, "gen-css"], ["type", "button", 1, "tok-group-h", 3, "click"], [1, "tok-mod-count"], [1, "tok-count"], [1, "tok-row", 3, "mod"], [1, "tok-row", 3, "mouseenter", "mouseleave"], [1, "tok-sw"], [1, "tok-name", 3, "title"], [1, "tok-badge"], ["spellcheck", "false", 1, "tinput", "tok-edit", 3, "ngModel"], [1, "tok-clr", 3, "title"], ["type", "button", 1, "tok-val-btn", 3, "title"], ["type", "button", "title", "Reset to derived value", 1, "tok-reset"], ["spellcheck", "false", 1, "tinput", "tok-edit", 3, "ngModelChange", "keydown.enter", "keydown.escape", "blur", "ngModel"], [1, "tok-val"], ["type", "button", 1, "tok-val-btn", 3, "click", "title"], ["type", "button", "title", "Reset to derived value", 1, "tok-reset", 3, "click"], [1, "fa-solid", "fa-rotate-left"], ["type", "button", 1, "sel-chip", 3, "click", "title"], [1, "fa-solid", "fa-triangle-exclamation"], ["type", "button", 1, "gen-copy", 3, "click"], [1, "fa-solid", "fa-copy"], [1, "gen-css-editor"], ["language", "css", "setup", "minimal", "readonly", "", 3, "value"]], template: function ThemeStudioDashboardComponent_Template(rf, ctx) { if (rf & 1) {
2484
+ const _r1 = i0.ɵɵgetCurrentView();
2485
+ i0.ɵɵelementStart(0, "mj-page-layout")(1, "mj-page-header", 5)(2, "div", 6)(3, "div", 7)(4, "div", 8)(5, "span", 9);
2486
+ i0.ɵɵelement(6, "i")(7, "i")(8, "i");
2487
+ i0.ɵɵelementEnd();
2488
+ i0.ɵɵconditionalCreate(9, ThemeStudioDashboardComponent_Conditional_9_Template, 2, 1, "input", 10)(10, ThemeStudioDashboardComponent_Conditional_10_Template, 3, 2);
2489
+ i0.ɵɵconditionalCreate(11, ThemeStudioDashboardComponent_Conditional_11_Template, 2, 0, "span", 11);
2490
+ i0.ɵɵelementStart(12, "button", 12);
2491
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleThemePicker()); });
2492
+ i0.ɵɵelement(13, "i", 13);
2493
+ i0.ɵɵelementEnd()();
2494
+ i0.ɵɵconditionalCreate(14, ThemeStudioDashboardComponent_Conditional_14_Template, 7, 0);
2495
+ i0.ɵɵelementEnd();
2496
+ i0.ɵɵconditionalCreate(15, ThemeStudioDashboardComponent_Conditional_15_Template, 3, 0, "span", 14);
2497
+ i0.ɵɵconditionalCreate(16, ThemeStudioDashboardComponent_Conditional_16_Template, 3, 0, "span", 15);
2498
+ i0.ɵɵelementEnd();
2499
+ i0.ɵɵelementStart(17, "div", 16)(18, "button", 17);
2500
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.discard()); });
2501
+ i0.ɵɵtext(19, "Discard");
2502
+ i0.ɵɵelementEnd();
2503
+ i0.ɵɵelementStart(20, "button", 18);
2504
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.applyToMe()); });
2505
+ i0.ɵɵtext(21, "Apply to me");
2506
+ i0.ɵɵelementEnd();
2507
+ i0.ɵɵelementStart(22, "button", 19);
2508
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_22_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.setAsDefault()); });
2509
+ i0.ɵɵtext(23, "Set as org default");
2510
+ i0.ɵɵelementEnd();
2511
+ i0.ɵɵconditionalCreate(24, ThemeStudioDashboardComponent_Conditional_24_Template, 2, 0, "button", 20)(25, ThemeStudioDashboardComponent_Conditional_25_Template, 2, 2, "button", 21);
2512
+ i0.ɵɵelementEnd();
2513
+ i0.ɵɵelementStart(26, "div", 22)(27, "mj-view-toggle", 23);
2514
+ i0.ɵɵlistener("KeyChange", function ThemeStudioDashboardComponent_Template_mj_view_toggle_KeyChange_27_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSurfaceToggle($event)); });
2515
+ i0.ɵɵelementEnd();
2516
+ i0.ɵɵelement(28, "span", 24);
2517
+ i0.ɵɵelementStart(29, "mj-view-toggle", 23);
2518
+ i0.ɵɵlistener("KeyChange", function ThemeStudioDashboardComponent_Template_mj_view_toggle_KeyChange_29_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onModeToggle($event)); });
2519
+ i0.ɵɵelementEnd();
2520
+ i0.ɵɵelementStart(30, "button", 25);
2521
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_30_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleFullscreen(true)); });
2522
+ i0.ɵɵelement(31, "i", 26);
2523
+ i0.ɵɵelementEnd();
2524
+ i0.ɵɵelementStart(32, "button", 27);
2525
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_32_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.togglePanel()); });
2526
+ i0.ɵɵelement(33, "i", 28);
2527
+ i0.ɵɵtext(34, " Edit theme");
2528
+ i0.ɵɵelementEnd()()();
2529
+ i0.ɵɵelementStart(35, "mj-page-body", 29)(36, "div", 30, 0);
2530
+ i0.ɵɵconditionalCreate(38, ThemeStudioDashboardComponent_Conditional_38_Template, 13, 0);
2531
+ i0.ɵɵelementStart(39, "div", 31)(40, "div", 32)(41, "div", 33, 1);
2532
+ i0.ɵɵconditionalCreate(43, ThemeStudioDashboardComponent_Conditional_43_Template, 6, 2, "div", 34);
2533
+ i0.ɵɵelementStart(44, "div", 35);
2534
+ i0.ɵɵconditionalCreate(45, ThemeStudioDashboardComponent_Conditional_45_Template, 164, 12, "div", 36);
2535
+ i0.ɵɵconditionalCreate(46, ThemeStudioDashboardComponent_Conditional_46_Template, 156, 1, "div", 36);
2536
+ i0.ɵɵelementEnd()()()();
2537
+ i0.ɵɵelementStart(47, "aside", 37)(48, "div", 38);
2538
+ i0.ɵɵlistener("pointerdown", function ThemeStudioDashboardComponent_Template_div_pointerdown_48_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.startPanelResize($event)); });
2539
+ i0.ɵɵelementEnd();
2540
+ i0.ɵɵelementStart(49, "div", 39)(50, "span", 40);
2541
+ i0.ɵɵelement(51, "i", 41);
2542
+ i0.ɵɵelementEnd();
2543
+ i0.ɵɵelementStart(52, "div")(53, "h2");
2544
+ i0.ɵɵtext(54, "Edit theme");
2545
+ i0.ɵɵelementEnd();
2546
+ i0.ɵɵelementStart(55, "small");
2547
+ i0.ɵɵtext(56, "One theme serves light & dark");
2548
+ i0.ɵɵelementEnd()();
2549
+ i0.ɵɵelementStart(57, "button", 42);
2550
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_57_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.togglePanel()); });
2551
+ i0.ɵɵelement(58, "i", 43);
2552
+ i0.ɵɵelementEnd()();
2553
+ i0.ɵɵelementStart(59, "div", 44)(60, "div", 45)(61, "h3")(62, "span", 40);
2554
+ i0.ɵɵelement(63, "i", 46);
2555
+ i0.ɵɵelementEnd();
2556
+ i0.ɵɵtext(64, "Start from a preset");
2557
+ i0.ɵɵelementEnd();
2558
+ i0.ɵɵelementStart(65, "div", 47);
2559
+ i0.ɵɵrepeaterCreate(66, ThemeStudioDashboardComponent_For_67_Template, 7, 8, "button", 48, _forTrack0);
2560
+ i0.ɵɵelementEnd()();
2561
+ i0.ɵɵelementStart(68, "div", 45)(69, "h3")(70, "span", 40);
2562
+ i0.ɵɵelement(71, "i", 46);
2563
+ i0.ɵɵelementEnd();
2564
+ i0.ɵɵtext(72, "Brand colors");
2565
+ i0.ɵɵelementStart(73, "span", 49);
2566
+ i0.ɵɵtext(74, "Everywhere");
2567
+ i0.ɵɵelementEnd()();
2568
+ i0.ɵɵelementStart(75, "p", 50);
2569
+ i0.ɵɵtext(76, "Anchor colors only. Ramps, hovers, and dark-mode values derive automatically.");
2570
+ i0.ɵɵelementEnd();
2571
+ i0.ɵɵelementStart(77, "div", 51)(78, "div", 52);
2572
+ i0.ɵɵtext(79, "Primary");
2573
+ i0.ɵɵelementStart(80, "small");
2574
+ i0.ɵɵtext(81, "Buttons, links, headers");
2575
+ i0.ɵɵelementEnd()();
2576
+ i0.ɵɵelementStart(82, "div", 53)(83, "span", 54)(84, "input", 55);
2577
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_84_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.primary, $event) || (ctx.seeds.primary = $event); return i0.ɵɵresetView($event); });
2578
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_84_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2579
+ i0.ɵɵelementEnd();
2580
+ i0.ɵɵelementStart(85, "span", 56);
2581
+ i0.ɵɵtext(86);
2582
+ i0.ɵɵelementEnd()()()();
2583
+ i0.ɵɵelementStart(87, "div", 57);
2584
+ i0.ɵɵelement(88, "i");
2585
+ i0.ɵɵtext(89, "Dark mode uses derived ");
2586
+ i0.ɵɵelementStart(90, "code");
2587
+ i0.ɵɵtext(91);
2588
+ i0.ɵɵelementEnd();
2589
+ i0.ɵɵtext(92, " (ramp step)");
2590
+ i0.ɵɵelementEnd();
2591
+ i0.ɵɵelementStart(93, "div", 51)(94, "div", 52);
2592
+ i0.ɵɵtext(95, "Accent");
2593
+ i0.ɵɵelementStart(96, "small");
2594
+ i0.ɵɵtext(97, "Highlights, KPI accents");
2595
+ i0.ɵɵelementEnd()();
2596
+ i0.ɵɵelementStart(98, "div", 53)(99, "span", 54)(100, "input", 55);
2597
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_100_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.accent, $event) || (ctx.seeds.accent = $event); return i0.ɵɵresetView($event); });
2598
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_100_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2599
+ i0.ɵɵelementEnd();
2600
+ i0.ɵɵelementStart(101, "span", 56);
2601
+ i0.ɵɵtext(102);
2602
+ i0.ɵɵelementEnd()()()();
2603
+ i0.ɵɵelementStart(103, "div", 51)(104, "div", 52);
2604
+ i0.ɵɵtext(105, "Tertiary");
2605
+ i0.ɵɵelementStart(106, "small");
2606
+ i0.ɵɵtext(107, "Secondary actions, info");
2607
+ i0.ɵɵelementEnd()();
2608
+ i0.ɵɵelementStart(108, "div", 53)(109, "span", 54)(110, "input", 55);
2609
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_110_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.tertiary, $event) || (ctx.seeds.tertiary = $event); return i0.ɵɵresetView($event); });
2610
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_110_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2611
+ i0.ɵɵelementEnd();
2612
+ i0.ɵɵelementStart(111, "span", 56);
2613
+ i0.ɵɵtext(112);
2614
+ i0.ɵɵelementEnd()()()();
2615
+ i0.ɵɵelementStart(113, "div", 51)(114, "div", 52);
2616
+ i0.ɵɵtext(115, "Secondary");
2617
+ i0.ɵɵelementStart(116, "small");
2618
+ i0.ɵɵtext(117, "Derived \u2014 deep surfaces");
2619
+ i0.ɵɵelementEnd()();
2620
+ i0.ɵɵelementStart(118, "div", 53)(119, "span", 58);
2621
+ i0.ɵɵelement(120, "span", 59);
2622
+ i0.ɵɵelementStart(121, "span", 56);
2623
+ i0.ɵɵtext(122);
2624
+ i0.ɵɵelementEnd()()()();
2625
+ i0.ɵɵelementStart(123, "div", 51)(124, "div", 52);
2626
+ i0.ɵɵtext(125, "Text on primary");
2627
+ i0.ɵɵelementStart(126, "small");
2628
+ i0.ɵɵtext(127, "Worst of light & dark");
2629
+ i0.ɵɵelementEnd()();
2630
+ i0.ɵɵelementStart(128, "div", 53);
2631
+ i0.ɵɵconditionalCreate(129, ThemeStudioDashboardComponent_Conditional_129_Template, 5, 7, "span", 60);
2632
+ i0.ɵɵelementEnd()();
2633
+ i0.ɵɵconditionalCreate(130, ThemeStudioDashboardComponent_Conditional_130_Template, 1, 1);
2634
+ i0.ɵɵelementEnd();
2635
+ i0.ɵɵelementStart(131, "div", 45)(132, "h3")(133, "span", 40);
2636
+ i0.ɵɵelement(134, "i", 61);
2637
+ i0.ɵɵelementEnd();
2638
+ i0.ɵɵtext(135, "Typography");
2639
+ i0.ɵɵelementStart(136, "span", 49);
2640
+ i0.ɵɵtext(137, "Everywhere");
2641
+ i0.ɵɵelementEnd()();
2642
+ i0.ɵɵelementStart(138, "div", 51)(139, "div", 52);
2643
+ i0.ɵɵtext(140, "Font family");
2644
+ i0.ɵɵelementEnd();
2645
+ i0.ɵɵelementStart(141, "div", 53)(142, "select", 62);
2646
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_select_ngModelChange_142_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.fontFamily, $event) || (ctx.seeds.fontFamily = $event); return i0.ɵɵresetView($event); });
2647
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_select_ngModelChange_142_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2648
+ i0.ɵɵrepeaterCreate(143, ThemeStudioDashboardComponent_For_144_Template, 2, 2, "option", 63, _forTrack1);
2649
+ i0.ɵɵelementEnd()()();
2650
+ i0.ɵɵelementStart(145, "div", 51)(146, "div", 52);
2651
+ i0.ɵɵtext(147, "Vibrancy");
2652
+ i0.ɵɵelementStart(148, "small");
2653
+ i0.ɵɵtext(149, "Brand ramp saturation");
2654
+ i0.ɵɵelementEnd()();
2655
+ i0.ɵɵelementStart(150, "div", 53)(151, "input", 64);
2656
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_151_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.vibrancy, $event) || (ctx.seeds.vibrancy = $event); return i0.ɵɵresetView($event); });
2657
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_151_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2658
+ i0.ɵɵelementEnd();
2659
+ i0.ɵɵelementStart(152, "span", 65);
2660
+ i0.ɵɵtext(153);
2661
+ i0.ɵɵelementEnd()()();
2662
+ i0.ɵɵelementStart(154, "div", 51)(155, "div", 52);
2663
+ i0.ɵɵtext(156, "Neutral character");
2664
+ i0.ɵɵelementStart(157, "small");
2665
+ i0.ɵɵtext(158, "Brand tint in grays");
2666
+ i0.ɵɵelementEnd()();
2667
+ i0.ɵɵelementStart(159, "div", 53)(160, "input", 66);
2668
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_160_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.neutralChroma, $event) || (ctx.seeds.neutralChroma = $event); return i0.ɵɵresetView($event); });
2669
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_160_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2670
+ i0.ɵɵelementEnd();
2671
+ i0.ɵɵelementStart(161, "span", 65);
2672
+ i0.ɵɵtext(162);
2673
+ i0.ɵɵelementEnd()()();
2674
+ i0.ɵɵelementStart(163, "div", 51)(164, "div", 52);
2675
+ i0.ɵɵtext(165, "Base size");
2676
+ i0.ɵɵelementStart(166, "small");
2677
+ i0.ɵɵtext(167, "Generated content");
2678
+ i0.ɵɵelementEnd()();
2679
+ i0.ɵɵelementStart(168, "div", 53)(169, "input", 67);
2680
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_169_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.baseFontSize, $event) || (ctx.baseFontSize = $event); return i0.ɵɵresetView($event); });
2681
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_169_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onBaseSizeChanged()); });
2682
+ i0.ɵɵelementEnd();
2683
+ i0.ɵɵelementStart(170, "span", 65);
2684
+ i0.ɵɵtext(171);
2685
+ i0.ɵɵelementEnd()()()();
2686
+ i0.ɵɵelementStart(172, "div", 45)(173, "h3")(174, "span", 40);
2687
+ i0.ɵɵelement(175, "i", 68);
2688
+ i0.ɵɵelementEnd();
2689
+ i0.ɵɵtext(176, "Shape & density");
2690
+ i0.ɵɵelementStart(177, "span", 49);
2691
+ i0.ɵɵtext(178, "Generated content");
2692
+ i0.ɵɵelementEnd()();
2693
+ i0.ɵɵelementStart(179, "p", 50);
2694
+ i0.ɵɵtext(180, "Applies to Skip / agent components. Explorer chrome keeps MJ shape.");
2695
+ i0.ɵɵelementEnd();
2696
+ i0.ɵɵelementStart(181, "div", 51)(182, "div", 52);
2697
+ i0.ɵɵtext(183, "Corner radius");
2698
+ i0.ɵɵelementEnd();
2699
+ i0.ɵɵelementStart(184, "div", 53)(185, "input", 69);
2700
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_185_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.radius, $event) || (ctx.seeds.radius = $event); return i0.ɵɵresetView($event); });
2701
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_185_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2702
+ i0.ɵɵelementEnd();
2703
+ i0.ɵɵelementStart(186, "span", 65);
2704
+ i0.ɵɵtext(187);
2705
+ i0.ɵɵelementEnd()()();
2706
+ i0.ɵɵelementStart(188, "div", 51)(189, "div", 52);
2707
+ i0.ɵɵtext(190, "Elevation depth");
2708
+ i0.ɵɵelementStart(191, "small");
2709
+ i0.ɵɵtext(192, "Brand shadow strength");
2710
+ i0.ɵɵelementEnd()();
2711
+ i0.ɵɵelementStart(193, "div", 53)(194, "input", 70);
2712
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_194_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.seeds.depth, $event) || (ctx.seeds.depth = $event); return i0.ɵɵresetView($event); });
2713
+ i0.ɵɵlistener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_194_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSeedsChanged()); });
2714
+ i0.ɵɵelementEnd();
2715
+ i0.ɵɵelementStart(195, "span", 65);
2716
+ i0.ɵɵtext(196);
2717
+ i0.ɵɵelementEnd()()();
2718
+ i0.ɵɵelementStart(197, "div", 51)(198, "div", 52);
2719
+ i0.ɵɵtext(199, "Density");
2720
+ i0.ɵɵelementEnd();
2721
+ i0.ɵɵelementStart(200, "div", 53)(201, "div", 71)(202, "button", 72);
2722
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_202_listener() { i0.ɵɵrestoreView(_r1); ctx.density = 16; return i0.ɵɵresetView(ctx.onDensityChanged()); });
2723
+ i0.ɵɵtext(203, "Comfortable");
2724
+ i0.ɵɵelementEnd();
2725
+ i0.ɵɵelementStart(204, "button", 72);
2726
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_button_click_204_listener() { i0.ɵɵrestoreView(_r1); ctx.density = 9; return i0.ɵɵresetView(ctx.onDensityChanged()); });
2727
+ i0.ɵɵtext(205, "Compact");
2728
+ i0.ɵɵelementEnd()()()()();
2729
+ i0.ɵɵelementStart(206, "div", 45)(207, "h3")(208, "span", 40);
2730
+ i0.ɵɵelement(209, "i", 73);
2731
+ i0.ɵɵelementEnd();
2732
+ i0.ɵɵtext(210, "Chart palette ");
2733
+ i0.ɵɵconditionalCreate(211, ThemeStudioDashboardComponent_Conditional_211_Template, 2, 0, "button", 74);
2734
+ i0.ɵɵelementEnd();
2735
+ i0.ɵɵelementStart(212, "p", 50);
2736
+ i0.ɵɵtext(213);
2737
+ i0.ɵɵelementEnd();
2738
+ i0.ɵɵelementStart(214, "div", 75);
2739
+ i0.ɵɵrepeaterCreate(215, ThemeStudioDashboardComponent_For_216_Template, 4, 4, "label", 76, i0.ɵɵrepeaterTrackByIndex);
2740
+ i0.ɵɵelementEnd()();
2741
+ i0.ɵɵelementStart(217, "div", 45)(218, "h3")(219, "span", 40);
2742
+ i0.ɵɵelement(220, "i", 77);
2743
+ i0.ɵɵelementEnd();
2744
+ i0.ɵɵtext(221, "Logo & branding");
2745
+ i0.ɵɵelementEnd();
2746
+ i0.ɵɵelementStart(222, "div", 51)(223, "div", 52);
2747
+ i0.ɵɵtext(224, "Footer notice");
2748
+ i0.ɵɵelementStart(225, "small");
2749
+ i0.ɵɵtext(226, "Shown in generated output");
2750
+ i0.ɵɵelementEnd()();
2751
+ i0.ɵɵelementStart(227, "div", 53)(228, "input", 78);
2752
+ i0.ɵɵtwoWayListener("ngModelChange", function ThemeStudioDashboardComponent_Template_input_ngModelChange_228_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.footerNotice, $event) || (ctx.footerNotice = $event); return i0.ɵɵresetView($event); });
2753
+ i0.ɵɵelementEnd()()();
2754
+ i0.ɵɵelementStart(229, "p", 79);
2755
+ i0.ɵɵtext(230, "Logo variant uploads (light / dark / wordmark) are coming with the asset pipeline \u2014 no recolor knob needed.");
2756
+ i0.ɵɵelementEnd()();
2757
+ i0.ɵɵelementStart(231, "div", 45)(232, "h3")(233, "span", 40);
2758
+ i0.ɵɵelement(234, "i", 80);
2759
+ i0.ɵɵelementEnd();
2760
+ i0.ɵɵtext(235, "Recipes");
2761
+ i0.ɵɵelementEnd();
2762
+ i0.ɵɵelementStart(236, "p", 50);
2763
+ i0.ɵɵtext(237, "Curated looks, expanded to token overrides underneath \u2014 fully reversible.");
2764
+ i0.ɵɵelementEnd();
2765
+ i0.ɵɵrepeaterCreate(238, ThemeStudioDashboardComponent_For_239_Template, 7, 4, "div", 51, _forTrack2);
2766
+ i0.ɵɵelementEnd();
2767
+ i0.ɵɵelementStart(240, "div", 81)(241, "h3", 82);
2768
+ i0.ɵɵlistener("click", function ThemeStudioDashboardComponent_Template_h3_click_241_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleAdvanced()); });
2769
+ i0.ɵɵelementStart(242, "span", 40);
2770
+ i0.ɵɵelement(243, "i", 83);
2771
+ i0.ɵɵelementEnd();
2772
+ i0.ɵɵtext(244, "Advanced ");
2773
+ i0.ɵɵelement(245, "i", 84);
2774
+ i0.ɵɵelementEnd();
2775
+ i0.ɵɵconditionalCreate(246, ThemeStudioDashboardComponent_Conditional_246_Template, 4, 1, "p", 85);
2776
+ i0.ɵɵconditionalCreate(247, ThemeStudioDashboardComponent_Conditional_247_Template, 64, 16);
2777
+ i0.ɵɵelementEnd()()()()()();
2778
+ } if (rf & 2) {
2779
+ let tmp_39_0;
2780
+ let tmp_40_0;
2781
+ i0.ɵɵadvance(6);
2782
+ i0.ɵɵstyleProp("background", ctx.seeds.primary);
2783
+ i0.ɵɵadvance();
2784
+ i0.ɵɵstyleProp("background", ctx.seeds.accent);
2785
+ i0.ɵɵadvance();
2786
+ i0.ɵɵstyleProp("background", ctx.seeds.tertiary);
2787
+ i0.ɵɵadvance();
2788
+ i0.ɵɵconditional(ctx.editingName ? 9 : 10);
2789
+ i0.ɵɵadvance(2);
2790
+ i0.ɵɵconditional(ctx.currentIsDefault ? 11 : -1);
2791
+ i0.ɵɵadvance(3);
2792
+ i0.ɵɵconditional(ctx.themePickerOpen ? 14 : -1);
2793
+ i0.ɵɵadvance();
2794
+ i0.ɵɵconditional(ctx.isBuiltInSelected ? 15 : -1);
2795
+ i0.ɵɵadvance();
2796
+ i0.ɵɵconditional(ctx.workspacePreviewOn ? 16 : -1);
2797
+ i0.ɵɵadvance(4);
2798
+ i0.ɵɵproperty("disabled", !ctx.currentThemeId);
2799
+ i0.ɵɵadvance(2);
2800
+ i0.ɵɵproperty("disabled", !ctx.currentThemeId);
2801
+ i0.ɵɵadvance(2);
2802
+ i0.ɵɵconditional(ctx.isBuiltInSelected ? 24 : 25);
2803
+ i0.ɵɵadvance(3);
2804
+ i0.ɵɵproperty("Options", ctx.surfaceOptions)("ActiveKey", ctx.activeView);
2805
+ i0.ɵɵadvance(2);
2806
+ i0.ɵɵproperty("Options", ctx.modeOptions)("ActiveKey", ctx.previewMode);
2807
+ i0.ɵɵadvance(3);
2808
+ i0.ɵɵproperty("variant", ctx.panelCollapsed ? "outline" : "secondary");
2809
+ i0.ɵɵadvance(3);
2810
+ i0.ɵɵproperty("Padding", false)("Flex", true);
2811
+ i0.ɵɵadvance();
2812
+ i0.ɵɵclassProp("collapsed", ctx.panelCollapsed);
2813
+ i0.ɵɵadvance(2);
2814
+ i0.ɵɵconditional(ctx.presetGalleryOpen ? 38 : -1);
2815
+ i0.ɵɵadvance(3);
2816
+ i0.ɵɵclassProp("fullscreen", ctx.fullscreen);
2817
+ i0.ɵɵadvance(2);
2818
+ i0.ɵɵconditional(ctx.fullscreen ? 43 : -1);
2819
+ i0.ɵɵadvance(2);
2820
+ i0.ɵɵconditional(ctx.activeView === "explorer" ? 45 : -1);
2821
+ i0.ɵɵadvance();
2822
+ i0.ɵɵconditional(ctx.activeView === "artifact" ? 46 : -1);
2823
+ i0.ɵɵadvance();
2824
+ i0.ɵɵstyleProp("width", ctx.panelCollapsed ? 0 : ctx.panelWidth, "px");
2825
+ i0.ɵɵclassProp("resizing", ctx.panelResizing);
2826
+ i0.ɵɵadvance(19);
2827
+ i0.ɵɵrepeater(ctx.presets);
2828
+ i0.ɵɵadvance(18);
2829
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.primary);
2830
+ i0.ɵɵadvance(2);
2831
+ i0.ɵɵtextInterpolate(ctx.seeds.primary);
2832
+ i0.ɵɵadvance(2);
2833
+ i0.ɵɵstyleProp("background", ctx.darkPrimary);
2834
+ i0.ɵɵadvance(3);
2835
+ i0.ɵɵtextInterpolate(ctx.darkPrimary);
2836
+ i0.ɵɵadvance(9);
2837
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.accent);
2838
+ i0.ɵɵadvance(2);
2839
+ i0.ɵɵtextInterpolate(ctx.seeds.accent);
2840
+ i0.ɵɵadvance(8);
2841
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.tertiary);
2842
+ i0.ɵɵadvance(2);
2843
+ i0.ɵɵtextInterpolate(ctx.seeds.tertiary);
2844
+ i0.ɵɵadvance(8);
2845
+ i0.ɵɵstyleProp("background", ctx.secondaryColor);
2846
+ i0.ɵɵadvance(2);
2847
+ i0.ɵɵtextInterpolate(ctx.secondaryColor);
2848
+ i0.ɵɵadvance(7);
2849
+ i0.ɵɵconditional((tmp_39_0 = ctx.onPrimaryWorst) ? 129 : -1, tmp_39_0);
2850
+ i0.ɵɵadvance();
2851
+ i0.ɵɵconditional((tmp_40_0 = ctx.onPrimaryDetail.light) ? 130 : -1, tmp_40_0);
2852
+ i0.ɵɵadvance(12);
2853
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.fontFamily);
2854
+ i0.ɵɵadvance();
2855
+ i0.ɵɵrepeater(ctx.fontOptions);
2856
+ i0.ɵɵadvance(8);
2857
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.vibrancy);
2858
+ i0.ɵɵadvance(2);
2859
+ i0.ɵɵtextInterpolate(ctx.seeds.vibrancy);
2860
+ i0.ɵɵadvance(7);
2861
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.neutralChroma);
2862
+ i0.ɵɵadvance(2);
2863
+ i0.ɵɵtextInterpolate(ctx.seeds.neutralChroma);
2864
+ i0.ɵɵadvance(7);
2865
+ i0.ɵɵtwoWayProperty("ngModel", ctx.baseFontSize);
2866
+ i0.ɵɵadvance(2);
2867
+ i0.ɵɵtextInterpolate1("", ctx.baseFontSize, "px");
2868
+ i0.ɵɵadvance(14);
2869
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.radius);
2870
+ i0.ɵɵadvance(2);
2871
+ i0.ɵɵtextInterpolate1("", ctx.seeds.radius, "px");
2872
+ i0.ɵɵadvance(7);
2873
+ i0.ɵɵtwoWayProperty("ngModel", ctx.seeds.depth);
2874
+ i0.ɵɵadvance(2);
2875
+ i0.ɵɵtextInterpolate(ctx.seeds.depth);
2876
+ i0.ɵɵadvance(6);
2877
+ i0.ɵɵclassProp("on", ctx.density === 16);
2878
+ i0.ɵɵadvance(2);
2879
+ i0.ɵɵclassProp("on", ctx.density === 9);
2880
+ i0.ɵɵadvance(7);
2881
+ i0.ɵɵconditional(ctx.vizOverridden ? 211 : -1);
2882
+ i0.ɵɵadvance(2);
2883
+ i0.ɵɵtextInterpolate1("Series 1 follows Primary until you override it ", ctx.vizOverridden ? "(overridden)" : "", ".");
2884
+ i0.ɵɵadvance(2);
2885
+ i0.ɵɵrepeater(ctx.vizColors);
2886
+ i0.ɵɵadvance(13);
2887
+ i0.ɵɵtwoWayProperty("ngModel", ctx.footerNotice);
2888
+ i0.ɵɵadvance(10);
2889
+ i0.ɵɵrepeater(ctx.recipeStates);
2890
+ i0.ɵɵadvance(7);
2891
+ i0.ɵɵclassProp("fa-chevron-down", ctx.advancedOpen)("fa-chevron-right", !ctx.advancedOpen);
2892
+ i0.ɵɵadvance();
2893
+ i0.ɵɵconditional(!ctx.advancedOpen && ctx.advancedSummary ? 246 : -1);
2894
+ i0.ɵɵadvance();
2895
+ i0.ɵɵconditional(ctx.advancedOpen ? 247 : -1);
2896
+ } }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.RangeValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MaxLengthValidator, i2.NgModel, i3.MJButtonDirective, i3.MJPageHeaderComponent, i3.MJPageLayoutComponent, i3.MJPageBodyComponent, i3.MJViewToggleComponent, i3.MJSwitchComponent, i4.CodeEditorComponent], styles: ["\n\n\n\n\n\n\n\n[_nghost-%COMP%] { display: block; width: 100%; height: 100%; }\n\n\n\n.theme-pick-wrap[_ngcontent-%COMP%] { position: relative; }\n.theme-pick[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 8px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 9px; padding: 5px 6px 5px 10px; color: var(--mj-text-primary); font: inherit; }\n.theme-pick[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%], .theme-menu-item[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] { display: flex; }\n.theme-pick[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] i[_ngcontent-%COMP%], .theme-menu-item[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 9px; height: 16px; display: block; margin-left: -3px; border-radius: 3px; border: 1.5px solid var(--mj-bg-surface); }\n.theme-pick[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child, .theme-menu-item[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child { margin-left: 0; }\n.theme-pick[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { font-size: 13px; font-weight: 700; }\n.theme-pick[_ngcontent-%COMP%] .theme-name[_ngcontent-%COMP%] { cursor: text; }\n.theme-pick[_ngcontent-%COMP%] .name-input[_ngcontent-%COMP%] { font: inherit; font-size: 13px; font-weight: 700; color: var(--mj-text-primary); background: var(--mj-bg-surface); border: 1px solid var(--mj-brand-primary); border-radius: 6px; padding: 2px 7px; min-width: 120px; outline: none; }\n.rename-btn[_ngcontent-%COMP%] { border: 0; background: transparent; color: var(--mj-text-muted); cursor: pointer; font-size: 11px; padding: 2px 4px; line-height: 1; border-radius: 5px; }\n.rename-btn[_ngcontent-%COMP%]:hover { color: var(--mj-brand-primary); background: var(--mj-bg-surface-hover); }\n.pick-caret[_ngcontent-%COMP%] { border: 0; background: transparent; cursor: pointer; padding: 4px 5px; margin-left: 2px; border-radius: 6px; display: inline-flex; align-items: center; }\n.pick-caret[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.theme-pick[_ngcontent-%COMP%] .caret[_ngcontent-%COMP%] { font-size: 11px; color: var(--mj-text-muted); }\n.badge[_ngcontent-%COMP%] { font-size: 9.5px; font-weight: 700; letter-spacing: .04em; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); padding: 2px 6px; border-radius: 20px; }\n.menu-backdrop[_ngcontent-%COMP%] { position: fixed; inset: 0; z-index: 19; }\n.theme-menu[_ngcontent-%COMP%] { position: absolute; top: calc(100% + 6px); left: 0; z-index: 20; min-width: 240px; background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 10px; box-shadow: var(--mj-shadow-lg); padding: 6px; }\n.theme-menu-item[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 8px 9px; border: 0; border-radius: 8px; background: transparent; cursor: pointer; color: var(--mj-text-primary); font: inherit; }\n.theme-menu-item[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.theme-menu-item.on[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); }\n.theme-menu-item[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { font-size: 13px; font-weight: 600; }\n.theme-menu-new[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 7px; width: 100%; padding: 8px 9px; margin-top: 4px; border: 0; border-top: 1px solid var(--mj-border-subtle); background: transparent; color: var(--mj-brand-primary); font: inherit; font-weight: 600; cursor: pointer; }\n.readonly-note[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); margin-left: 8px; }\n.toolbar-spacer[_ngcontent-%COMP%] { flex: 1; }\n\n\n\n.ts-stage[_ngcontent-%COMP%] { flex: 1; display: flex; min-height: 0; overflow: hidden; position: relative; background: var(--mj-bg-page); }\n.pv-wrap[_ngcontent-%COMP%] { flex: 1; min-width: 0; overflow: auto; padding: 22px 26px 60px; }\n.pv-inner[_ngcontent-%COMP%] { max-width: 1240px; margin: 0 auto; }\n\n\n\n.ts-panel[_ngcontent-%COMP%] { flex-shrink: 0; width: 392px; position: relative; background: var(--mj-bg-surface); border-left: 1px solid var(--mj-border-default); display: flex; flex-direction: column; min-height: 0; transition: width .25s cubic-bezier(.4,0,.2,1); overflow: hidden; }\n.ts-panel.resizing[_ngcontent-%COMP%] { transition: none; user-select: none; }\n.panel-resize[_ngcontent-%COMP%] { position: absolute; left: 0; top: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 5; touch-action: none; }\n.panel-resize[_ngcontent-%COMP%]:hover, .ts-panel.resizing[_ngcontent-%COMP%] .panel-resize[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent); }\n.ts-stage.collapsed[_ngcontent-%COMP%] .panel-resize[_ngcontent-%COMP%] { display: none; }\n.ts-stage.collapsed[_ngcontent-%COMP%] .ts-panel[_ngcontent-%COMP%] { width: 0; border-left: none; }\n.ts-stage.collapsed[_ngcontent-%COMP%] .panel-h[_ngcontent-%COMP%], .ts-stage.collapsed[_ngcontent-%COMP%] .panel-body[_ngcontent-%COMP%] { opacity: 0; pointer-events: none; }\n.panel-h[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 9px; padding: 13px 14px; border-bottom: 1px solid var(--mj-border-default); flex-shrink: 0; min-width: 392px; }\n.panel-h[_ngcontent-%COMP%] .ic[_ngcontent-%COMP%] { width: 26px; height: 26px; border-radius: 7px; background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); display: grid; place-items: center; flex-shrink: 0; }\n.panel-h[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] { margin: 0; font-size: 14.5px; font-weight: 700; }\n.panel-h[_ngcontent-%COMP%] small[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-size: 11.5px; display: block; font-weight: 500; }\n.collapse-btn[_ngcontent-%COMP%] { margin-left: auto; width: 30px; height: 30px; border: 1px solid var(--mj-border-default); border-radius: 8px; background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); display: grid; place-items: center; cursor: pointer; }\n.collapse-btn[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); }\n.panel-body[_ngcontent-%COMP%] { flex: 1; overflow: auto; padding: 14px; min-width: 392px; }\n\n\n\n.card[_ngcontent-%COMP%] { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 12px; padding: 14px 15px; margin-bottom: 12px; box-shadow: var(--mj-shadow-sm); }\n.card[_ngcontent-%COMP%] > h3[_ngcontent-%COMP%] { margin: 0 0 4px; font-size: 13.5px; font-weight: 700; display: flex; align-items: center; gap: 8px; }\n.card[_ngcontent-%COMP%] > h3[_ngcontent-%COMP%] .ic[_ngcontent-%COMP%] { width: 21px; height: 21px; border-radius: 6px; background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); display: grid; place-items: center; font-size: 11px; }\n.card[_ngcontent-%COMP%] > .sub[_ngcontent-%COMP%] { margin: 0 0 10px; font-size: 11.5px; color: var(--mj-text-muted); }\n.scope[_ngcontent-%COMP%] { font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--mj-text-muted); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); padding: 2px 6px; border-radius: 5px; margin-left: auto; }\n.reset-link[_ngcontent-%COMP%] { margin-left: auto; border: 0; background: transparent; color: var(--mj-text-link); font: inherit; font-size: 11.5px; cursor: pointer; }\n.row[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; border-top: 1px solid var(--mj-border-subtle); }\n.row[_ngcontent-%COMP%]:first-of-type { border-top: 0; }\n.lab[_ngcontent-%COMP%] { font-size: 12.5px; font-weight: 600; }\n.lab[_ngcontent-%COMP%] small[_ngcontent-%COMP%] { display: block; font-weight: 500; color: var(--mj-text-muted); font-size: 11px; margin-top: 1px; }\n.ctl[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n.clr[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 7px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 4px 8px 4px 4px; }\n.clr[_ngcontent-%COMP%] input[type=color][_ngcontent-%COMP%] { appearance: none; -webkit-appearance: none; width: 24px; height: 24px; border: 0; border-radius: 6px; background: none; cursor: pointer; padding: 0; }\n.clr.static[_ngcontent-%COMP%] .sw-box[_ngcontent-%COMP%] { width: 24px; height: 24px; border-radius: 6px; display: block; border: 1px solid rgba(0,0,0,.15); }\n.hex[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 11.5px; color: var(--mj-text-secondary); min-width: 58px; text-transform: uppercase; }\n.derived-note[_ngcontent-%COMP%] { font-size: 11px; color: var(--mj-text-muted); padding-top: 7px; display: flex; align-items: center; gap: 6px; }\n.derived-note[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 14px; height: 14px; border-radius: 4px; border: 1px solid rgba(0,0,0,.15); display: inline-block; }\n.derived-note[_ngcontent-%COMP%] code[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 10.5px; }\ninput[type=range][_ngcontent-%COMP%] { appearance: none; -webkit-appearance: none; width: 104px; height: 4px; border-radius: 3px; background: var(--mj-border-strong); cursor: pointer; }\ninput[type=range][_ngcontent-%COMP%]::-webkit-slider-thumb { -webkit-appearance: none; width: 15px; height: 15px; border-radius: 50%; background: var(--mj-brand-primary); border: 2px solid var(--mj-bg-surface); }\n.val[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 11.5px; color: var(--mj-text-secondary); min-width: 44px; text-align: right; }\nselect[_ngcontent-%COMP%], .tinput[_ngcontent-%COMP%] { font: inherit; font-size: 12.5px; color: var(--mj-text-primary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 6px 9px; }\nselect[_ngcontent-%COMP%] { cursor: pointer; min-width: 120px; }\n.tinput[_ngcontent-%COMP%] { width: 170px; }\n.miniseg[_ngcontent-%COMP%] { display: inline-flex; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 2px; }\n.miniseg[_ngcontent-%COMP%] button[_ngcontent-%COMP%] { border: 0; background: transparent; color: var(--mj-text-secondary); font: inherit; font-size: 11.5px; font-weight: 600; padding: 4px 9px; border-radius: 6px; cursor: pointer; }\n.miniseg[_ngcontent-%COMP%] button.on[_ngcontent-%COMP%] { background: var(--mj-bg-surface); color: var(--mj-text-primary); box-shadow: var(--mj-shadow-sm); }\n.ok[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 700; color: var(--mj-status-success-text); background: var(--mj-status-success-bg); border: 1px solid var(--mj-status-success-border); padding: 3px 8px; border-radius: 20px; white-space: nowrap; }\n.ok.warn[_ngcontent-%COMP%] { color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); }\n.preset-row[_ngcontent-%COMP%] { display: flex; flex-wrap: wrap; gap: 8px; }\n.preset[_ngcontent-%COMP%] { display: flex; flex-direction: column; align-items: center; gap: 5px; border: 1px solid var(--mj-border-default); border-radius: 9px; background: var(--mj-bg-surface); padding: 8px 6px; cursor: pointer; width: 64px; }\n.preset[_ngcontent-%COMP%]:hover { border-color: var(--mj-brand-primary); background: var(--mj-bg-surface-hover); }\n.preset[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] { display: flex; }\n.preset[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 10px; height: 18px; display: block; margin-left: -3px; border-radius: 3px; border: 1.5px solid var(--mj-bg-surface); }\n.preset[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child { margin-left: 0; }\n.preset[_ngcontent-%COMP%] small[_ngcontent-%COMP%] { font-size: 9.5px; color: var(--mj-text-muted); text-align: center; line-height: 1.15; }\n.swrow[_ngcontent-%COMP%] { display: flex; flex-wrap: wrap; gap: 7px; padding-top: 4px; }\n.chip-clr[_ngcontent-%COMP%] { position: relative; width: 38px; height: 38px; border-radius: 9px; border: 1px solid rgba(0,0,0,.12); cursor: pointer; overflow: hidden; }\n.chip-clr[_ngcontent-%COMP%] input[type=color][_ngcontent-%COMP%] { position: absolute; inset: -4px; width: 46px; height: 46px; border: 0; padding: 0; cursor: pointer; opacity: 0; }\n.chip-num[_ngcontent-%COMP%] { position: absolute; left: 4px; top: 2px; font-size: 9.5px; font-weight: 700; color: rgba(255,255,255,.92); text-shadow: 0 1px 2px rgba(0,0,0,.4); }\n\n\n\n.ts-canvas[_ngcontent-%COMP%] { border-radius: 16px; border: 1px solid var(--mj-border-default); overflow: hidden; box-shadow: var(--mj-shadow-lg); background: var(--mj-bg-page); font-family: var(--mj-font-family); font-size: var(--ts-fs, 14px); color: var(--mj-text-primary); }\n.ts-canvas.fullscreen[_ngcontent-%COMP%] { position: fixed; inset: 0; z-index: 40; border-radius: 0; border: 0; overflow: auto; }\n.pv-scroll[_ngcontent-%COMP%] { padding: var(--ts-space, 16px); display: flex; flex-direction: column; gap: var(--ts-space, 16px); }\n.zone-lab[_ngcontent-%COMP%] { font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--mj-text-muted); margin-bottom: 6px; display: flex; align-items: center; gap: 6px; }\n.zone-lab[_ngcontent-%COMP%]::before { content: \"\"; width: 5px; height: 5px; border-radius: 50%; background: var(--mj-brand-accent); }\n\n\n\n.mx[_ngcontent-%COMP%] { background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-lg, 12px); overflow: hidden; }\n.mx-shell[_ngcontent-%COMP%] { height: 44px; background: var(--mj-bg-surface); border-bottom: 1px solid var(--mj-border-default); display: flex; align-items: center; gap: 11px; padding: 0 12px; font-size: .82em; }\n.mx-appico[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.mx-nav[_ngcontent-%COMP%] { display: flex; gap: 3px; }\n.mx-nav[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { padding: 5px 11px; border-radius: var(--mj-radius-sm, 6px); color: var(--mj-text-secondary); font-weight: 500; cursor: pointer; transition: background .12s ease, color .12s ease; }\n.mx-nav[_ngcontent-%COMP%] b[_ngcontent-%COMP%]:hover:not(.on) { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n.mx-nav[_ngcontent-%COMP%] b.on[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); color: var(--mj-brand-primary); }\n.mx-search[_ngcontent-%COMP%] { flex: 0 1 190px; min-width: 100px; display: flex; align-items: center; gap: 6px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-sm, 6px); padding: 4px 9px; color: var(--mj-text-muted); }\n.mx-sp[_ngcontent-%COMP%] { flex: 1; }\n.mx-av[_ngcontent-%COMP%] { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-brand-on-primary); display: grid; place-items: center; font-size: .72em; font-weight: 700; }\n.mx-ph[_ngcontent-%COMP%] { background: var(--mj-bg-surface); border-bottom: 1px solid var(--mj-border-default); padding: 11px 14px 0; }\n.mx-ph-top[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; padding-bottom: 10px; }\n.mx-ph-ico[_ngcontent-%COMP%] { width: 30px; height: 30px; border-radius: var(--mj-radius-sm, 6px); background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); display: grid; place-items: center; flex-shrink: 0; }\n.mx-ph-title[_ngcontent-%COMP%] { font-size: .95em; font-weight: 700; }\n.mx-ph-sub[_ngcontent-%COMP%] { font-size: .72em; color: var(--mj-text-muted); }\n.mx-ph-actions[_ngcontent-%COMP%] { margin-left: auto; display: flex; align-items: center; gap: 7px; }\n.mx-toolbar[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; padding: 8px 0 10px; border-top: 1px solid var(--mj-border-default); }\n.mx-tabs[_ngcontent-%COMP%] { display: flex; gap: 2px; }\n.mx-tabs[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-style: normal; font-size: .78em; font-weight: 600; color: var(--mj-text-secondary); padding: 5px 10px 7px; border-bottom: 2px solid transparent; cursor: pointer; transition: color .12s ease, border-color .12s ease; }\n.mx-tabs[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:hover:not(.on) { color: var(--mj-text-primary); border-bottom-color: var(--mj-border-strong); }\n.mx-tabs[_ngcontent-%COMP%] i.on[_ngcontent-%COMP%] { color: var(--mj-brand-primary); border-bottom-color: var(--mj-brand-primary); }\n.mx-body[_ngcontent-%COMP%] { padding: 12px; display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 10px; }\n.mx-cell[_ngcontent-%COMP%] { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); padding: 10px 11px; min-width: 0; }\n.mx-cell.wide[_ngcontent-%COMP%] { grid-column: span 2; }\n@media (max-width: 760px) { .mx-cell.wide[_ngcontent-%COMP%] { grid-column: span 1; } }\n.mx-cap[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: .62em; color: var(--mj-text-muted); letter-spacing: .04em; margin-bottom: 8px; display: block; }\n.mx-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }\n.mx-row[_ngcontent-%COMP%] + .mx-row[_ngcontent-%COMP%] { margin-top: 7px; }\n.mx-btn[_ngcontent-%COMP%] { font: inherit; font-size: .74em; font-weight: 600; padding: 5.5px 11px; border-radius: var(--mj-radius-sm, 6px); cursor: pointer; border: 1px solid transparent; transition: background .12s ease, color .12s ease, border-color .12s ease; }\n.mx-btn.pri[_ngcontent-%COMP%] { background: var(--mj-brand-primary); color: var(--mj-brand-on-primary); }\n.mx-btn.sec[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-primary); border-color: var(--mj-border-default); }\n.mx-btn.out[_ngcontent-%COMP%] { background: transparent; color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n.mx-btn.dgr[_ngcontent-%COMP%] { background: transparent; color: var(--mj-status-error); border-color: var(--mj-status-error); }\n\n\n\n\n\n\n.mx-btn[_ngcontent-%COMP%]:disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }\n.mx-btn.pri[_ngcontent-%COMP%]:hover, .mx-btn.pri.is-hover[_ngcontent-%COMP%] { background: var(--mj-brand-primary-hover); }\n.mx-btn.pri[_ngcontent-%COMP%]:active, .mx-btn.pri.is-active[_ngcontent-%COMP%] { background: var(--mj-brand-primary-active); }\n.mx-btn.sec[_ngcontent-%COMP%]:hover, .mx-btn.sec.is-hover[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); }\n.mx-btn.sec[_ngcontent-%COMP%]:active, .mx-btn.sec.is-active[_ngcontent-%COMP%] { background: var(--mj-bg-surface-active); }\n.mx-btn.out[_ngcontent-%COMP%]:hover, .mx-btn.out.is-hover[_ngcontent-%COMP%] { color: var(--mj-brand-primary-hover); border-color: var(--mj-brand-primary-hover); background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n.mx-btn.out[_ngcontent-%COMP%]:active, .mx-btn.out.is-active[_ngcontent-%COMP%] { color: var(--mj-brand-primary-active); border-color: var(--mj-brand-primary-active); background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); }\n.mx-btn.dgr[_ngcontent-%COMP%]:hover, .mx-btn.dgr.is-hover[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); }\n.mx-btn.dgr[_ngcontent-%COMP%]:active, .mx-btn.dgr.is-active[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-status-error) 18%, transparent); }\n.ts-canvas[_ngcontent-%COMP%] [_ngcontent-%COMP%]:focus-visible, .mx-btn.is-focus[_ngcontent-%COMP%] { outline: 2px solid var(--mj-border-focus); outline-offset: 2px; }\n.states-row[_ngcontent-%COMP%] { align-items: center; }\n.mx-input[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-sm, 6px); padding: 5px 9px; font-size: .74em; color: var(--mj-text-secondary); min-width: 0; }\n.mx-input.focus[_ngcontent-%COMP%] { border-color: var(--mj-brand-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent); }\n.mx-swch[_ngcontent-%COMP%] { width: 32px; height: 18px; border-radius: 20px; background: var(--mj-brand-primary); position: relative; flex-shrink: 0; cursor: pointer; transition: background .15s ease; }\n.mx-swch[_ngcontent-%COMP%]:hover { background: var(--mj-brand-primary-hover); }\n.mx-swch.off[_ngcontent-%COMP%]:hover { background: var(--mj-text-muted); }\n.mx-swch[_ngcontent-%COMP%]::after { content: \"\"; position: absolute; top: 2px; right: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--mj-brand-on-primary); }\n.mx-swch.off[_ngcontent-%COMP%] { background: var(--mj-border-strong); }\n.mx-swch.off[_ngcontent-%COMP%]::after { right: auto; left: 2px; }\n.mx-lbl[_ngcontent-%COMP%] { font-size: .72em; color: var(--mj-text-secondary); }\n.mx-chip[_ngcontent-%COMP%] { font-size: .7em; font-weight: 600; padding: 4px 10px; border-radius: 16px; border: 1px solid var(--mj-border-default); color: var(--mj-text-secondary); background: var(--mj-bg-surface); cursor: pointer; transition: background .12s ease, border-color .12s ease; }\n.mx-chip[_ngcontent-%COMP%]:hover:not(.on) { background: var(--mj-bg-surface-hover); border-color: var(--mj-border-strong); }\n.mx-chip.on[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent); color: var(--mj-brand-primary); }\n.mx-stat[_ngcontent-%COMP%] { font-size: .66em; font-weight: 700; letter-spacing: .03em; padding: 3px 9px; border-radius: 14px; }\n.mx-stat.brand[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); color: var(--mj-brand-primary); }\n.mx-stat.neu[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); border: 1px solid var(--mj-border-default); }\n.mx-stat.suc[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.mx-stat.wrn[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.mx-prog[_ngcontent-%COMP%] { height: 7px; border-radius: 6px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); overflow: hidden; flex: 1; }\n.mx-prog[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { display: block; height: 100%; width: 64%; background: var(--mj-brand-primary); }\n.mx-lnav[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 3px; margin-bottom: 8px; }\n.mx-lnav[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 7px; font-size: .74em; font-weight: 500; color: var(--mj-text-secondary); padding: 6px 9px; border-radius: var(--mj-radius-sm, 6px); cursor: pointer; transition: background .12s ease, color .12s ease; }\n.mx-lnav[_ngcontent-%COMP%] b[_ngcontent-%COMP%]:hover:not(.on) { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n.mx-lnav[_ngcontent-%COMP%] b.on[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); color: var(--mj-brand-primary); font-weight: 600; }\n.mx-lnav[_ngcontent-%COMP%] b.mx-acc-item[_ngcontent-%COMP%] { padding-left: 28px; font-weight: 400; }\n.mx-alert[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; font-size: .72em; font-weight: 600; border-radius: var(--mj-radius-sm, 6px); padding: 8px 10px; border: 1px solid var(--mj-status-info-border); background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.mx-alert[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }\n.mx-dlg[_ngcontent-%COMP%] { border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); overflow: hidden; }\n.mx-dlg-t[_ngcontent-%COMP%] { padding: 8px 11px; background: var(--mj-bg-surface-sunken); font-size: .76em; font-weight: 700; color: var(--mj-text-primary); }\n.mx-dlg-b[_ngcontent-%COMP%] { padding: 10px 11px; }\n.mx-dlg-a[_ngcontent-%COMP%] { display: flex; gap: 7px; padding: 9px 11px; border-top: 1px solid var(--mj-border-default); }\n\n\n\n.pv-grid[_ngcontent-%COMP%] { display: grid; grid-template-columns: minmax(0, 2fr) minmax(240px, 1fr); gap: var(--ts-space, 16px); align-items: start; }\n@media (max-width: 1180px) { .pv-grid[_ngcontent-%COMP%] { grid-template-columns: 1fr; } }\n.report[_ngcontent-%COMP%] { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-lg, 12px); overflow: hidden; box-shadow: var(--mj-shadow-brand-md); }\n.rhead[_ngcontent-%COMP%] { background: linear-gradient(105deg, var(--mj-brand-primary), color-mix(in srgb, var(--mj-brand-primary) 62%, black)); color: var(--mj-brand-on-primary); padding: 14px 16px; display: flex; align-items: center; gap: 12px; }\n.logo[_ngcontent-%COMP%] { width: 34px; height: 34px; border-radius: 9px; background: var(--mj-brand-on-primary); flex-shrink: 0; background-image: var(--mj-logo-mark); background-repeat: no-repeat; background-position: center; background-size: 70%; }\n.rhead[_ngcontent-%COMP%] .ti[_ngcontent-%COMP%] { font-size: 1.15em; font-weight: 700; line-height: 1.1; }\n.rhead[_ngcontent-%COMP%] .su[_ngcontent-%COMP%] { font-size: .82em; opacity: .85; margin-top: 1px; }\n.rhead[_ngcontent-%COMP%] .rt[_ngcontent-%COMP%] { margin-left: auto; font-size: .72em; font-weight: 600; opacity: .9; text-align: right; }\n.rbody[_ngcontent-%COMP%] { padding: var(--ts-space, 16px); display: flex; flex-direction: column; gap: var(--ts-space, 16px); }\n.kpis[_ngcontent-%COMP%] { display: grid; grid-template-columns: repeat(3, 1fr); gap: 11px; }\n.kpi[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); padding: 11px; border-top: 3px solid var(--mj-brand-accent); }\n.kpi[_ngcontent-%COMP%] .n[_ngcontent-%COMP%] { font-size: 1.7em; font-weight: 750; line-height: 1; }\n.kpi[_ngcontent-%COMP%] .l[_ngcontent-%COMP%] { font-size: .76em; color: var(--mj-text-muted); margin-top: 4px; }\n.kpi[_ngcontent-%COMP%] .d[_ngcontent-%COMP%] { font-size: .72em; font-weight: 700; margin-top: 5px; display: inline-flex; gap: 3px; }\n.kpi[_ngcontent-%COMP%] .d.up[_ngcontent-%COMP%] { color: var(--mj-status-success); } .kpi[_ngcontent-%COMP%] .d.dn[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n.chart[_ngcontent-%COMP%] .ct[_ngcontent-%COMP%] { font-size: .86em; font-weight: 700; margin-bottom: 2px; }\n.chart[_ngcontent-%COMP%] .cs[_ngcontent-%COMP%] { font-size: .74em; color: var(--mj-text-muted); margin-bottom: 12px; }\n.bars[_ngcontent-%COMP%] { display: flex; align-items: flex-end; gap: 10px; height: 120px; border-bottom: 1.5px solid var(--mj-border-default); }\n.bar[_ngcontent-%COMP%] { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 5px; }\n.bar[_ngcontent-%COMP%] .fill[_ngcontent-%COMP%] { width: 100%; border-radius: 5px 5px 0 0; min-height: 4px; }\n.bar[_ngcontent-%COMP%] .bv[_ngcontent-%COMP%] { font-size: .72em; font-weight: 700; color: var(--mj-text-secondary); }\n.cats[_ngcontent-%COMP%] { display: flex; gap: 10px; margin-top: 7px; }\n.cats[_ngcontent-%COMP%] span[_ngcontent-%COMP%] { flex: 1; text-align: center; font-size: .68em; color: var(--mj-text-muted); font-weight: 500; }\ntable.grid[_ngcontent-%COMP%] { width: 100%; border-collapse: collapse; font-size: .8em; }\ntable.grid[_ngcontent-%COMP%] th[_ngcontent-%COMP%] { text-align: left; font-size: .92em; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)); padding: 7px 10px; font-weight: 700; border-bottom: 1px solid var(--mj-border-default); }\ntable.grid[_ngcontent-%COMP%] th.r[_ngcontent-%COMP%], table.grid[_ngcontent-%COMP%] td.r[_ngcontent-%COMP%] { text-align: right; }\ntable.grid[_ngcontent-%COMP%] td[_ngcontent-%COMP%] { padding: 7px 10px; border-bottom: 1px solid var(--mj-border-default); color: var(--mj-text-secondary); }\ntable.grid[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:nth-child(even) td[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); }\ntable.grid[_ngcontent-%COMP%] td[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { color: var(--mj-text-primary); font-weight: 600; }\n.rfoot[_ngcontent-%COMP%] { padding: 11px 16px; border-top: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); font-size: .72em; color: var(--mj-text-muted); display: flex; align-items: center; gap: 8px; }\n.rfoot[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%] { width: 4px; height: 4px; border-radius: 50%; background: var(--mj-text-muted); }\n.side-stack[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: var(--ts-space, 16px); }\n.mini[_ngcontent-%COMP%] { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-lg, 12px); padding: 13px; box-shadow: var(--mj-shadow-brand-sm); }\n.mini[_ngcontent-%COMP%] .mt[_ngcontent-%COMP%] { font-size: .82em; font-weight: 700; margin-bottom: 2px; }\n.mini[_ngcontent-%COMP%] .ms[_ngcontent-%COMP%] { font-size: .72em; color: var(--mj-text-muted); margin-bottom: 10px; }\n.alertrow[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 7px; }\n.alert[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; font-size: .76em; font-weight: 600; border-radius: var(--mj-radius-sm, 6px); padding: 7px 10px; border: 1px solid; }\n.alert.suc[_ngcontent-%COMP%] { color: var(--mj-status-success-text); background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); }\n.alert.wrn[_ngcontent-%COMP%] { color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); }\n.alert.err[_ngcontent-%COMP%] { color: var(--mj-status-error-text); background: var(--mj-status-error-bg); border-color: var(--mj-status-error-border); }\n.alert[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }\n.ramp[_ngcontent-%COMP%] { display: flex; border-radius: var(--mj-radius-sm, 6px); overflow: hidden; height: 34px; border: 1px solid var(--mj-border-default); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { flex: 1; }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(1) { background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(2) { background: color-mix(in srgb, var(--mj-brand-primary) 22%, var(--mj-bg-surface)); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(3) { background: color-mix(in srgb, var(--mj-brand-primary) 38%, var(--mj-bg-surface)); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(4) { background: color-mix(in srgb, var(--mj-brand-primary) 55%, var(--mj-bg-surface)); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(5) { background: color-mix(in srgb, var(--mj-brand-primary) 72%, var(--mj-bg-surface)); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(6) { background: color-mix(in srgb, var(--mj-brand-primary) 88%, var(--mj-bg-surface)); }\n.ramp[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:nth-child(7) { background: var(--mj-brand-primary); }\n.ag-sum[_ngcontent-%COMP%] { font-size: .85em; color: var(--mj-text-secondary); line-height: 1.6; margin: 0 0 12px; }\n.ag-sum[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { color: var(--mj-text-primary); }\n.ag-finds[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }\n.ag-find[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); background: var(--mj-bg-surface-card); font-size: .8em; }\n.ag-find[_ngcontent-%COMP%] .fdot[_ngcontent-%COMP%] { width: 8px; height: 8px; border-radius: 50%; background: var(--mj-brand-primary); flex-shrink: 0; }\n.ag-find[_ngcontent-%COMP%] .mx-stat[_ngcontent-%COMP%] { margin-left: auto; flex-shrink: 0; }\n\n\n\n.fs-bar[_ngcontent-%COMP%] { position: fixed; top: 14px; right: 16px; z-index: 41; display: flex; align-items: center; gap: 8px; }\n.fs-bar[_ngcontent-%COMP%] mj-view-toggle[_ngcontent-%COMP%], .fs-bar[_ngcontent-%COMP%] button[_ngcontent-%COMP%] { box-shadow: var(--mj-shadow-lg); }\n.kbd[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 10.5px; border: 1px solid var(--mj-border-strong); border-radius: 5px; padding: 1px 5px; color: var(--mj-text-muted); margin-left: 6px; }\n\n\n\n.adv-head[_ngcontent-%COMP%] { cursor: pointer; user-select: none; }\n.adv-head[_ngcontent-%COMP%] .caret[_ngcontent-%COMP%] { margin-left: auto; font-size: 12px; color: var(--mj-text-muted); }\n.adv-card[_ngcontent-%COMP%] .sub[_ngcontent-%COMP%] { margin: 0 0 10px; font-size: 11.5px; color: var(--mj-text-muted); }\n.adv-card[_ngcontent-%COMP%] .sub[_ngcontent-%COMP%] code[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 11px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-subtle); border-radius: 4px; padding: 0 4px; }\n.adv-sec[_ngcontent-%COMP%] { padding: 10px 0; border-top: 1px solid var(--mj-border-subtle); }\n.adv-sec[_ngcontent-%COMP%]:first-of-type { border-top: 0; }\n.adv-lab[_ngcontent-%COMP%] { font-size: 12px; font-weight: 700; color: var(--mj-text-primary); margin-bottom: 4px; }\n.adv-note[_ngcontent-%COMP%] { margin-top: 6px !important; font-style: italic; }\n.ovr-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }\n.ovr-key[_ngcontent-%COMP%] { flex: 3 1 0; width: auto; min-width: 0; }\n.ovr-val[_ngcontent-%COMP%] { flex: 2 1 0; width: auto; min-width: 0; }\n.ovr-del[_ngcontent-%COMP%] { flex: 0 0 auto; border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); color: var(--mj-text-muted); border-radius: 7px; width: 28px; height: 28px; cursor: pointer; display: grid; place-items: center; }\n.ovr-del[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); border-color: color-mix(in srgb, var(--mj-status-error) 45%, transparent); }\n.adv-add[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 6px; border: 1px dashed var(--mj-border-strong); background: transparent; color: var(--mj-text-link); font: inherit; font-size: 12px; font-weight: 600; padding: 6px 10px; border-radius: 8px; cursor: pointer; }\n.adv-add[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.adv-css-wrap[_ngcontent-%COMP%] { position: relative; }\n.adv-css[_ngcontent-%COMP%] { display: block; width: 100%; box-sizing: border-box; font-family: var(--mj-font-family-mono); font-size: 12px; line-height: 1.5; color: var(--mj-text-primary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 9px 10px; resize: vertical; }\n.adv-css[_ngcontent-%COMP%]:focus { outline: none; border-color: var(--mj-brand-primary); }\n.css-ac[_ngcontent-%COMP%] { position: absolute; z-index: 30; left: 0; right: 0; top: 100%; margin: 4px 0 0; padding: 4px; list-style: none; max-height: 210px; overflow: auto; background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 8px; box-shadow: var(--mj-shadow-lg); }\n.css-ac[_ngcontent-%COMP%] li[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; font-family: var(--mj-font-family-mono); font-size: 12px; color: var(--mj-text-primary); cursor: pointer; }\n.css-ac[_ngcontent-%COMP%] li[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-muted); width: 12px; text-align: center; }\n.css-ac[_ngcontent-%COMP%] li[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.css-ac[_ngcontent-%COMP%] li.on[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface)); }\n.gen-css[_ngcontent-%COMP%] { position: relative; margin-top: 8px; }\n.gen-css[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] { max-height: 260px; overflow: auto; margin: 0; font-family: var(--mj-font-family-mono); font-size: 11px; line-height: 1.5; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 10px; white-space: pre; }\n.gen-copy[_ngcontent-%COMP%] { position: absolute; top: 8px; right: 8px; display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); color: var(--mj-text-secondary); font: inherit; font-size: 11px; padding: 4px 8px; border-radius: 6px; cursor: pointer; }\n.gen-copy[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n\n\n\n.preview-note[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border: 1px solid var(--mj-status-warning-border); padding: 2px 8px; border-radius: 20px; margin-left: 8px; }\n\n\n\n.ok[_ngcontent-%COMP%] .mode-tag[_ngcontent-%COMP%] { font-style: normal; font-weight: 600; opacity: .75; text-transform: uppercase; font-size: 9px; letter-spacing: .05em; }\n.contrast-detail[_ngcontent-%COMP%] { padding-top: 4px; }\n\n\n\n.gal-backdrop[_ngcontent-%COMP%] { position: absolute; inset: 0; z-index: 24; background: var(--mj-bg-overlay, color-mix(in srgb, var(--mj-text-primary) 35%, transparent)); }\n.gal[_ngcontent-%COMP%] { position: absolute; z-index: 25; left: 50%; top: 48px; transform: translateX(-50%); width: min(640px, calc(100% - 48px)); background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 14px; box-shadow: var(--mj-shadow-lg); padding: 20px 22px 16px; }\n.gal[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] { margin: 0 0 4px; font-size: 17px; font-weight: 750; }\n.gal[_ngcontent-%COMP%] .gal-sub[_ngcontent-%COMP%] { margin: 0 0 14px; font-size: 12.5px; color: var(--mj-text-muted); }\n.gal-grid[_ngcontent-%COMP%] { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }\n.gal-card[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--mj-border-default); border-radius: 11px; background: var(--mj-bg-surface); padding: 10px; cursor: pointer; text-align: left; font: inherit; transition: border-color .12s ease, box-shadow .12s ease; }\n.gal-card[_ngcontent-%COMP%]:hover { border-color: var(--mj-brand-primary); box-shadow: var(--mj-shadow-sm); }\n.gal-card[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { font-size: 12.5px; font-weight: 650; color: var(--mj-text-primary); }\n.gal-mock[_ngcontent-%COMP%] { display: block; overflow: hidden; border: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card); }\n.gal-mock-bar[_ngcontent-%COMP%] { display: block; height: 18px; }\n.gal-mock-body[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 5px; padding: 8px; }\n.gal-line[_ngcontent-%COMP%] { display: block; height: 5px; border-radius: 3px; background: var(--mj-border-default); width: 80%; }\n.gal-line.short[_ngcontent-%COMP%] { width: 55%; }\n.gal-mock-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 5px; margin-top: 2px; }\n.gal-dot[_ngcontent-%COMP%] { width: 11px; height: 11px; border-radius: 50%; display: block; }\n.gal-btn[_ngcontent-%COMP%] { display: block; width: 34px; height: 12px; margin-left: auto; }\n.gal-foot[_ngcontent-%COMP%] { display: flex; justify-content: flex-start; margin-top: 12px; }\n\n\n\n.ladder[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 4px 0 8px; }\n.ladder[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-muted); }\n.ladder-step[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 650; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 20px; padding: 3px 10px 3px 4px; }\n.ladder-step[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { width: 17px; height: 17px; border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-text-inverse); display: grid; place-items: center; font-size: 10px; font-weight: 700; }\n.ladder-step.esc[_ngcontent-%COMP%] { border-style: dashed; color: var(--mj-status-warning-text); }\n.ladder-step.esc[_ngcontent-%COMP%] b[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.step-num[_ngcontent-%COMP%] { width: 17px; height: 17px; border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-text-inverse); display: inline-grid; place-items: center; font-size: 10px; font-weight: 700; margin-right: 7px; }\n.step-num.esc[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.esc-tag[_ngcontent-%COMP%] { font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border: 1px solid var(--mj-status-warning-border); padding: 1px 7px; border-radius: 12px; margin-left: 8px; }\n.adv-summary[_ngcontent-%COMP%] { margin: 6px 0 0; font-size: 12px; color: var(--mj-text-secondary); display: flex; align-items: center; gap: 8px; }\n.adv-summary[_ngcontent-%COMP%] .adv-edit[_ngcontent-%COMP%] { margin-left: 0; }\n\n\n\n.tok-search[_ngcontent-%COMP%] { width: 100%; box-sizing: border-box; margin-bottom: 8px; }\n.tok-groups[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 4px; }\n.tok-group[_ngcontent-%COMP%] { border: 1px solid var(--mj-border-subtle); border-radius: 9px; overflow: hidden; }\n.tok-group-h[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; border: 0; background: var(--mj-bg-surface-card); color: var(--mj-text-primary); font: inherit; font-size: 12px; font-weight: 650; padding: 7px 10px; cursor: pointer; }\n.tok-group-h[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.tok-group-h[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { font-size: 10px; color: var(--mj-text-muted); width: 11px; }\n.tok-count[_ngcontent-%COMP%] { margin-left: auto; font-size: 10.5px; font-weight: 600; color: var(--mj-text-muted); }\n.tok-mod-count[_ngcontent-%COMP%] { font-size: 9.5px; font-weight: 700; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); padding: 1px 7px; border-radius: 12px; }\n.tok-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 7px; padding: 5px 10px; border-top: 1px solid var(--mj-border-subtle); }\n.tok-row[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-card); }\n.tok-row.mod[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent); }\n.tok-sw[_ngcontent-%COMP%] { width: 16px; height: 16px; border-radius: 4px; border: 1px solid var(--mj-border-default); flex-shrink: 0; }\n.tok-name[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 10.5px; color: var(--mj-text-primary); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.tok-badge[_ngcontent-%COMP%] { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); padding: 1px 6px; border-radius: 10px; flex-shrink: 0; }\n.tok-clr[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; flex-shrink: 0; }\n.tok-clr[_ngcontent-%COMP%] input[type=color][_ngcontent-%COMP%] { appearance: none; -webkit-appearance: none; width: 20px; height: 20px; border: 0; border-radius: 5px; background: none; cursor: pointer; padding: 0; }\n.tok-val[_ngcontent-%COMP%], .tok-val-btn[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 10px; color: var(--mj-text-secondary); max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.tok-val-btn[_ngcontent-%COMP%] { border: 1px dashed transparent; background: transparent; padding: 2px 5px; border-radius: 5px; cursor: pointer; flex-shrink: 0; }\n.tok-val-btn[_ngcontent-%COMP%]:hover { border-color: var(--mj-border-strong); color: var(--mj-text-primary); }\n.tok-edit[_ngcontent-%COMP%] { flex: 1 1 auto; min-width: 90px; width: auto; font-family: var(--mj-font-family-mono); font-size: 10.5px; padding: 3px 7px; }\n.tok-reset[_ngcontent-%COMP%] { flex: 0 0 auto; border: 0; background: transparent; color: var(--mj-text-muted); cursor: pointer; padding: 2px 4px; border-radius: 5px; font-size: 10.5px; }\n.tok-reset[_ngcontent-%COMP%]:hover { color: var(--mj-status-error); background: var(--mj-bg-surface-hover); }\n\n\n\n.sel-chips[_ngcontent-%COMP%] { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }\n.sel-chip[_ngcontent-%COMP%] { font-family: var(--mj-font-family-mono); font-size: 10.5px; font-weight: 600; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 14px; padding: 3px 9px; cursor: pointer; transition: color .12s ease, border-color .12s ease; }\n.sel-chip[_ngcontent-%COMP%]:hover { color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n.css-tools[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }\n.tok-pick[_ngcontent-%COMP%] { font: inherit; font-size: 11.5px; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 5px 8px; cursor: pointer; max-width: 100%; }\n.adv-css-editor[_ngcontent-%COMP%] { height: clamp(220px, 34vh, 460px); border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; margin-bottom: 6px; }\n\n\n\n.adv-css-editor[_ngcontent-%COMP%] .cm-editor { height: 100%; }\n.adv-css-editor[_ngcontent-%COMP%] mj-code-editor { display: block; height: 100%; }\n.css-warn[_ngcontent-%COMP%] { display: flex; align-items: flex-start; gap: 7px; margin: 6px 0 0; font-size: 11.5px; color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border: 1px solid var(--mj-status-warning-border); border-radius: 8px; padding: 6px 9px; }\n.css-warn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { margin-top: 1px; flex-shrink: 0; }\n.gen-css-editor[_ngcontent-%COMP%] { height: 260px; margin-top: 8px; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.gen-css-editor[_ngcontent-%COMP%] .cm-editor { height: 100%; }\n.gen-css-editor[_ngcontent-%COMP%] mj-code-editor { display: block; height: 100%; }\n\n@media (max-width: 900px) {\n .ts-panel[_ngcontent-%COMP%] { position: absolute; right: 0; top: 0; bottom: 0; z-index: 10; box-shadow: var(--mj-shadow-lg); }\n .kpis[_ngcontent-%COMP%] { grid-template-columns: 1fr 1fr; }\n}"] });
2897
+ };
2898
+ ThemeStudioDashboardComponent = __decorate([
2899
+ RegisterClass(BaseDashboard, 'ThemeStudioDashboard')
2900
+ ], ThemeStudioDashboardComponent);
2901
+ export { ThemeStudioDashboardComponent };
2902
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ThemeStudioDashboardComponent, [{
2903
+ type: Component,
2904
+ args: [{ standalone: false, selector: 'mj-theme-studio-dashboard', template: "<mj-page-layout>\n <mj-page-header Title=\"Theme Studio\" Icon=\"fa-solid fa-palette\" Subtitle=\"Organization theme &amp; branding\">\n <!-- [meta] = state: which theme is loaded (picker) + its read-only flag. -->\n <div meta>\n <div class=\"theme-pick-wrap\">\n <div class=\"theme-pick\">\n <span class=\"sw\">\n <i [style.background]=\"seeds.primary\"></i>\n <i [style.background]=\"seeds.accent\"></i>\n <i [style.background]=\"seeds.tertiary\"></i>\n </span>\n @if (editingName) {\n <input #nameInput class=\"name-input\" [(ngModel)]=\"currentName\"\n (keydown.enter)=\"commitRename()\" (keydown.escape)=\"cancelRename()\" (blur)=\"commitRename()\"\n maxlength=\"80\" aria-label=\"Theme name\" />\n } @else {\n <b class=\"theme-name\" (dblclick)=\"startRename()\">{{ currentName }}</b>\n @if (!isBuiltInSelected) {\n <button type=\"button\" class=\"rename-btn\" title=\"Rename theme\" aria-label=\"Rename theme\" (click)=\"startRename()\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n }\n }\n @if (currentIsDefault) { <span class=\"badge\">DEFAULT</span> }\n <button type=\"button\" class=\"pick-caret\" title=\"Switch theme\"\n aria-label=\"Switch theme\" (click)=\"toggleThemePicker()\">\n <i class=\"fa-solid fa-chevron-down caret\"></i>\n </button>\n </div>\n @if (themePickerOpen) {\n <div class=\"menu-backdrop\" (click)=\"themePickerOpen = false\"></div>\n <div class=\"theme-menu\">\n @for (t of themes; track t.id) {\n <button type=\"button\" class=\"theme-menu-item\" [class.on]=\"isCurrentTheme(t.id)\" (click)=\"selectTheme(t)\">\n <span class=\"sw\">\n @for (c of t.swatches; track $index) { <i [style.background]=\"c\"></i> }\n </span>\n <b>{{ t.name }}</b>\n @if (t.isDefault) { <span class=\"badge\">DEFAULT</span> }\n </button>\n }\n <button type=\"button\" class=\"theme-menu-new\" (click)=\"newTheme()\"><i class=\"fa-solid fa-plus\"></i> New theme</button>\n </div>\n }\n </div>\n @if (isBuiltInSelected) {\n <span class=\"readonly-note\"><i class=\"fa-solid fa-lock\"></i> Built-in \u00B7 read-only</span>\n }\n @if (workspacePreviewOn) {\n <span class=\"preview-note\"><i class=\"fa-solid fa-eye\"></i> Draft previewing on your workspace</span>\n }\n </div>\n\n <!-- [actions] = verbs: secondary actions, then the one primary CTA rightmost. -->\n <div actions>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"discard()\">Discard</button>\n <button mjButton variant=\"outline\" size=\"sm\" [disabled]=\"!currentThemeId\"\n title=\"Apply this theme to your workspace now \u2014 it persists across sessions until you pick another\"\n (click)=\"applyToMe()\">Apply to me</button>\n <button mjButton variant=\"outline\" size=\"sm\" [disabled]=\"!currentThemeId\"\n title=\"Make this the organization-wide default theme for everyone\" (click)=\"setAsDefault()\">Set as org default</button>\n @if (isBuiltInSelected) {\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"saveAsCopy()\">Save as copy</button>\n } @else {\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"saving\" (click)=\"save()\">{{ saving ? 'Saving\u2026' : 'Save theme' }}</button>\n }\n </div>\n\n <!-- [toolbar] = secondary controls: preview surface / mode, fullscreen, panel toggle. -->\n <div toolbar>\n <mj-view-toggle [Options]=\"surfaceOptions\" [ActiveKey]=\"activeView\"\n (KeyChange)=\"onSurfaceToggle($event)\"></mj-view-toggle>\n <span class=\"toolbar-spacer\"></span>\n <mj-view-toggle [Options]=\"modeOptions\" [ActiveKey]=\"previewMode\"\n (KeyChange)=\"onModeToggle($event)\"></mj-view-toggle>\n <button mjButton variant=\"icon\" ariaLabel=\"Full screen preview\" title=\"Full screen preview\"\n (click)=\"toggleFullscreen(true)\"><i class=\"fa-solid fa-expand\"></i></button>\n <button mjButton [variant]=\"panelCollapsed ? 'outline' : 'secondary'\" size=\"sm\"\n (click)=\"togglePanel()\"><i class=\"fa-solid fa-sliders\"></i> Edit theme</button>\n </div>\n </mj-page-header>\n\n <mj-page-body [Padding]=\"false\" [Flex]=\"true\">\n <!-- Stage: preview (primary) + slide panel -->\n <div #stage class=\"ts-stage\" [class.collapsed]=\"panelCollapsed\">\n\n <!-- New-theme preset gallery (Q1#2): pick a personality before tuning seeds.\n Deliberately NOT mj-dialog (conscious exception): the gallery is positioned\n within the stage so the preview stays visible behind it, while mj-dialog is\n a viewport-centered overlay. Focus lands on the dialog when it opens and\n the document-level Escape handler closes it. -->\n @if (presetGalleryOpen) {\n <div class=\"gal-backdrop\" (click)=\"closePresetGallery()\"></div>\n <div #galDialog class=\"gal\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Start a new theme\" tabindex=\"-1\">\n <h2>Start a new theme</h2>\n <p class=\"gal-sub\">Pick a personality first \u2014 everything derives from a few seeds, so you can tune it all after.</p>\n <div class=\"gal-grid\">\n @for (p of presets; track p.name) {\n <button type=\"button\" class=\"gal-card\" (click)=\"choosePreset(p)\">\n <span class=\"gal-mock\" [style.border-radius.px]=\"p.seeds.radius ?? 8\">\n <span class=\"gal-mock-bar\" [style.background]=\"p.seeds.primary\"></span>\n <span class=\"gal-mock-body\">\n <span class=\"gal-line\"></span>\n <span class=\"gal-line short\"></span>\n <span class=\"gal-mock-row\">\n <span class=\"gal-dot\" [style.background]=\"p.seeds.accent ?? p.seeds.primary\"></span>\n <span class=\"gal-dot\" [style.background]=\"p.seeds.tertiary ?? p.seeds.accent ?? p.seeds.primary\"></span>\n <span class=\"gal-btn\" [style.background]=\"p.seeds.primary\"\n [style.border-radius.px]=\"(p.seeds.radius ?? 8) / 2\"></span>\n </span>\n </span>\n </span>\n <b>{{ p.name }}</b>\n </button>\n }\n </div>\n <div class=\"gal-foot\">\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"closePresetGallery()\">Start blank (MJ defaults)</button>\n </div>\n </div>\n }\n\n <div class=\"pv-wrap\">\n <div class=\"pv-inner\">\n <div #previewCanvas class=\"ts-canvas\" [class.fullscreen]=\"fullscreen\">\n <!-- Fullscreen floating controls (inside canvas so they render in the top layer) -->\n @if (fullscreen) {\n <div class=\"fs-bar\">\n <mj-view-toggle [Options]=\"modeOptions\" [ActiveKey]=\"previewMode\"\n (KeyChange)=\"onModeToggle($event)\"></mj-view-toggle>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"toggleFullscreen(false)\">Exit full screen <span class=\"kbd\">Esc</span></button>\n </div>\n }\n <div class=\"pv-scroll\">\n\n <!-- ============ Explorer UI style guide (interactive \u2014 Q1#6) ============ -->\n @if (activeView === 'explorer') {\n <div class=\"pv-view\">\n <div class=\"zone-lab\">Explorer UI \u00B7 shell + page chrome + ng-ui-components \u00B7 hover &amp; tab around \u2014 states are live</div>\n <div class=\"mx\">\n <div class=\"mx-shell\">\n <span class=\"mx-appico\"><i class=\"fa-solid fa-table-cells-large\"></i></span>\n <span class=\"mx-nav\">\n @for (item of mockNavItems; track item; let i = $index) {\n <b [class.on]=\"mockNav === i\" tabindex=\"0\" role=\"button\"\n (click)=\"mockNav = i\" (keydown.enter)=\"mockNav = i\"\n (keydown.space)=\"mockNav = i; $event.preventDefault()\">{{ item }}</b>\n }\n </span>\n <span class=\"mx-search\" tabindex=\"0\"><i class=\"fa-solid fa-magnifying-glass\"></i> Search everything\u2026</span>\n <span class=\"mx-sp\"></span>\n <span class=\"mx-av\" tabindex=\"0\">AC</span>\n </div>\n <div class=\"mx-ph\">\n <div class=\"mx-ph-top\">\n <span class=\"mx-ph-ico\"><i class=\"fa-solid fa-users\"></i></span>\n <div>\n <div class=\"mx-ph-title\">Membership Overview</div>\n <div class=\"mx-ph-sub\">mj-page-layout \u00B7 mj-page-header \u00B7 mj-page-body</div>\n </div>\n <div class=\"mx-ph-actions\">\n <button class=\"mx-btn sec\">Export</button>\n <button class=\"mx-btn pri\">New record</button>\n </div>\n </div>\n <div class=\"mx-toolbar\">\n <span class=\"mx-tabs\" role=\"tablist\">\n @for (t of mockTabs; track t; let i = $index) {\n <i [class.on]=\"mockTab === i\" tabindex=\"0\" role=\"tab\" [attr.aria-selected]=\"mockTab === i\"\n (click)=\"mockTab = i\" (keydown.enter)=\"mockTab = i\"\n (keydown.space)=\"mockTab = i; $event.preventDefault()\">{{ t }}</i>\n }\n </span>\n </div>\n </div>\n <div class=\"mx-body\">\n <div class=\"mx-cell wide\">\n <span class=\"mx-cap\">mjButton \u2014 primary \u00B7 secondary \u00B7 outline \u00B7 danger</span>\n <div class=\"mx-row\">\n <button class=\"mx-btn pri\">Save</button>\n <button class=\"mx-btn sec\">Cancel</button>\n <button class=\"mx-btn out\">Configure</button>\n <button class=\"mx-btn dgr\">Delete</button>\n </div>\n </div>\n <div class=\"mx-cell wide\">\n <span class=\"mx-cap\">Button states \u2014 rest \u00B7 hover \u00B7 active \u00B7 focus \u00B7 disabled</span>\n <div class=\"mx-row states-row\">\n <button class=\"mx-btn pri\">Rest</button>\n <button class=\"mx-btn pri is-hover\">Hover</button>\n <button class=\"mx-btn pri is-active\">Active</button>\n <button class=\"mx-btn pri is-focus\">Focus</button>\n <button class=\"mx-btn pri\" disabled>Disabled</button>\n </div>\n <div class=\"mx-row states-row\">\n <button class=\"mx-btn sec\">Rest</button>\n <button class=\"mx-btn sec is-hover\">Hover</button>\n <button class=\"mx-btn sec is-active\">Active</button>\n <button class=\"mx-btn sec is-focus\">Focus</button>\n <button class=\"mx-btn sec\" disabled>Disabled</button>\n </div>\n <div class=\"mx-row states-row\">\n <button class=\"mx-btn out\">Rest</button>\n <button class=\"mx-btn out is-hover\">Hover</button>\n <button class=\"mx-btn out is-active\">Active</button>\n <button class=\"mx-btn out is-focus\">Focus</button>\n <button class=\"mx-btn out\" disabled>Disabled</button>\n </div>\n <div class=\"mx-row states-row\">\n <button class=\"mx-btn dgr\">Rest</button>\n <button class=\"mx-btn dgr is-hover\">Hover</button>\n <button class=\"mx-btn dgr is-active\">Active</button>\n <button class=\"mx-btn dgr is-focus\">Focus</button>\n <button class=\"mx-btn dgr\" disabled>Disabled</button>\n </div>\n </div>\n <div class=\"mx-cell wide\">\n <span class=\"mx-cap\">mj-input \u00B7 mj-combobox \u00B7 mj-switch</span>\n <div class=\"mx-row\">\n <span class=\"mx-input focus\" style=\"flex:1\">Northwind Tra</span>\n <span class=\"mx-input\" tabindex=\"0\" style=\"flex:1\">Member type <i class=\"fa-solid fa-chevron-down\"></i></span>\n </div>\n <div class=\"mx-row\">\n <span class=\"mx-swch\" [class.off]=\"!mockSwitchA\" role=\"switch\" tabindex=\"0\"\n [attr.aria-checked]=\"mockSwitchA\" aria-label=\"Toggle switch\"\n (click)=\"mockSwitchA = !mockSwitchA\" (keydown.enter)=\"mockSwitchA = !mockSwitchA\"\n (keydown.space)=\"mockSwitchA = !mockSwitchA; $event.preventDefault()\"></span>\n <span class=\"mx-swch\" [class.off]=\"!mockSwitchB\" role=\"switch\" tabindex=\"0\"\n [attr.aria-checked]=\"mockSwitchB\" aria-label=\"Toggle auto-renew\"\n (click)=\"mockSwitchB = !mockSwitchB\" (keydown.enter)=\"mockSwitchB = !mockSwitchB\"\n (keydown.space)=\"mockSwitchB = !mockSwitchB; $event.preventDefault()\"></span>\n <span class=\"mx-lbl\">Auto-renew</span>\n </div>\n </div>\n <div class=\"mx-cell\">\n <span class=\"mx-cap\">mj-filter-chip</span>\n <div class=\"mx-row\">\n <span class=\"mx-chip on\" tabindex=\"0\">Active</span>\n <span class=\"mx-chip\" tabindex=\"0\">Lapsed</span>\n <span class=\"mx-chip\" tabindex=\"0\">Pending</span>\n </div>\n </div>\n <div class=\"mx-cell\">\n <span class=\"mx-cap\">mj-stat-badge \u00B7 mj-progress-bar</span>\n <div class=\"mx-row\"><span class=\"mx-stat brand\">1,204 Members</span><span class=\"mx-stat suc\">Active</span><span class=\"mx-stat wrn\">Expiring</span></div>\n <div class=\"mx-row\"><span class=\"mx-prog\"><i></i></span><span class=\"mx-lbl\">64%</span></div>\n </div>\n <div class=\"mx-cell\">\n <span class=\"mx-cap\">mj-left-nav \u00B7 mj-accordion \u00B7 mj-alert</span>\n <div class=\"mx-lnav\">\n <b class=\"on\" tabindex=\"0\"><i class=\"fa-solid fa-house\"></i> Overview</b>\n <b tabindex=\"0\"><i class=\"fa-solid fa-users\"></i> Members</b>\n <b tabindex=\"0\" role=\"button\" [attr.aria-expanded]=\"mockAccordionOpen\"\n (click)=\"mockAccordionOpen = !mockAccordionOpen\" (keydown.enter)=\"mockAccordionOpen = !mockAccordionOpen\"\n (keydown.space)=\"mockAccordionOpen = !mockAccordionOpen; $event.preventDefault()\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"mockAccordionOpen\" [class.fa-chevron-right]=\"!mockAccordionOpen\"></i> Reports\n </b>\n @if (mockAccordionOpen) {\n <b class=\"mx-acc-item\" tabindex=\"0\">Renewal funnel</b>\n <b class=\"mx-acc-item\" tabindex=\"0\">Engagement</b>\n }\n </div>\n <div class=\"mx-alert\"><i></i>12 imports finished overnight</div>\n </div>\n <div class=\"mx-cell\">\n <span class=\"mx-cap\">mj-dialog \u00B7 mj-dialog-actions</span>\n <div class=\"mx-dlg\">\n <div class=\"mx-dlg-t\">Rename view</div>\n <div class=\"mx-dlg-b\"><span class=\"mx-input focus\" style=\"width:100%\">Q3 Renewal Pipeline</span></div>\n <div class=\"mx-dlg-a\"><button class=\"mx-btn pri\">Save</button><button class=\"mx-btn sec\">Cancel</button></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- ============ Artifact \u2014 one generated document, styled by the theme ============ -->\n @if (activeView === 'artifact') {\n <div class=\"pv-view\">\n <div class=\"report\">\n <div class=\"rhead\">\n <span class=\"logo\"></span>\n <div><div class=\"ti\">Acme Analytics</div><div class=\"su\">Q2 Pipeline Overview</div></div>\n <div class=\"rt\">Generated \u00B7 Jul 2026</div>\n </div>\n <div class=\"rbody\">\n <div class=\"kpis\">\n <div class=\"kpi\"><div class=\"n\">$4.2M</div><div class=\"l\">Pipeline value</div><div class=\"d up\">\u25B2 12.4%</div></div>\n <div class=\"kpi\"><div class=\"n\">318</div><div class=\"l\">Open deals</div><div class=\"d up\">\u25B2 6.1%</div></div>\n <div class=\"kpi\"><div class=\"n\">27%</div><div class=\"l\">Win rate</div><div class=\"d dn\">\u25BC 1.8%</div></div>\n </div>\n <div class=\"chart\">\n <div class=\"ct\">Pipeline by stage</div>\n <div class=\"cs\">Value in each stage, current quarter</div>\n <div class=\"bars\">\n @for (h of barHeights; track $index; let i = $index) {\n <div class=\"bar\">\n <span class=\"bv\">{{ barValues[i] }}</span>\n <span class=\"fill\" [style.height.%]=\"h\" [style.background]=\"vizColors[i % vizColors.length]\"></span>\n </div>\n }\n </div>\n <div class=\"cats\">\n @for (c of barCats; track c) { <span>{{ c }}</span> }\n </div>\n </div>\n <table class=\"grid\">\n <thead><tr><th>Account</th><th>Stage</th><th class=\"r\">Value</th><th class=\"r\">Close</th></tr></thead>\n <tbody>\n <tr><td><b>Northwind Traders</b></td><td>Negotiate</td><td class=\"r\">$820,000</td><td class=\"r\">Aug 12</td></tr>\n <tr><td><b>Contoso Ltd</b></td><td>Propose</td><td class=\"r\">$465,000</td><td class=\"r\">Sep 03</td></tr>\n <tr><td><b>Fabrikam Inc</b></td><td>Commit</td><td class=\"r\">$1,240,000</td><td class=\"r\">Jul 29</td></tr>\n </tbody>\n </table>\n <p class=\"ag-sum\"><b>Summary.</b> Northwind expanded into two of Acme's core regions this quarter,\n hired a new VP of Partnerships, and repriced its mid-tier plan 8% below Acme's.</p>\n <div class=\"ag-finds\">\n <div class=\"ag-find\"><span class=\"fdot\"></span><span><b>Regional expansion</b> \u2014 opened Denver and Austin offices</span><span class=\"mx-stat wrn\">High impact</span></div>\n <div class=\"ag-find\"><span class=\"fdot\"></span><span><b>Pricing move</b> \u2014 mid-tier repriced to $79/seat</span><span class=\"mx-stat brand\">Watch</span></div>\n <div class=\"ag-find\"><span class=\"fdot\"></span><span><b>Positioning shift</b> \u2014 \"live in 30 days\" campaign</span><span class=\"mx-stat neu\">Monitor</span></div>\n </div>\n <table class=\"grid\">\n <thead><tr><th>Source</th><th>Type</th><th class=\"r\">Confidence</th></tr></thead>\n <tbody>\n <tr><td><b>Northwind press release</b></td><td>Primary</td><td class=\"r\">High</td></tr>\n <tr><td><b>G2 pricing capture</b></td><td>Primary</td><td class=\"r\">High</td></tr>\n <tr><td><b>LinkedIn hiring signals</b></td><td>Inferred</td><td class=\"r\">Medium</td></tr>\n </tbody>\n </table>\n </div>\n <div class=\"rfoot\"><span>{{ footerNotice }}</span><span class=\"dot\"></span><span>as of Jul 2026</span></div>\n </div>\n </div>\n }\n\n </div>\n </div>\n </div>\n </div>\n\n <!-- Slide panel: editor (resizable \u2014 Q3#1/#2) -->\n <aside class=\"ts-panel\" aria-label=\"Theme editor\" [class.resizing]=\"panelResizing\"\n [style.width.px]=\"panelCollapsed ? 0 : panelWidth\">\n <div class=\"panel-resize\" role=\"separator\" aria-orientation=\"vertical\" aria-label=\"Resize editor panel\"\n title=\"Drag to resize\" (pointerdown)=\"startPanelResize($event)\"></div>\n <div class=\"panel-h\">\n <span class=\"ic\"><i class=\"fa-solid fa-palette\"></i></span>\n <div><h2>Edit theme</h2><small>One theme serves light &amp; dark</small></div>\n <button type=\"button\" class=\"collapse-btn\" (click)=\"togglePanel()\" title=\"Collapse panel\"><i class=\"fa-solid fa-chevron-right\"></i></button>\n </div>\n <div class=\"panel-body\">\n\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-plus\"></i></span>Start from a preset</h3>\n <div class=\"preset-row\">\n @for (p of presets; track p.name) {\n <button type=\"button\" class=\"preset\" (click)=\"applyPreset(p)\" [title]=\"p.name\">\n <span class=\"sw\"><i [style.background]=\"p.seeds.primary\"></i><i [style.background]=\"p.seeds.accent\"></i><i [style.background]=\"p.seeds.tertiary || p.seeds.accent\"></i></span>\n <small>{{ p.name }}</small>\n </button>\n }\n </div>\n </div>\n\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-plus\"></i></span>Brand colors<span class=\"scope\">Everywhere</span></h3>\n <p class=\"sub\">Anchor colors only. Ramps, hovers, and dark-mode values derive automatically.</p>\n <div class=\"row\"><div class=\"lab\">Primary<small>Buttons, links, headers</small></div>\n <div class=\"ctl\"><span class=\"clr\"><input type=\"color\" [(ngModel)]=\"seeds.primary\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"hex\">{{ seeds.primary }}</span></span></div></div>\n <div class=\"derived-note\"><i [style.background]=\"darkPrimary\"></i>Dark mode uses derived <code>{{ darkPrimary }}</code> (ramp step)</div>\n <div class=\"row\"><div class=\"lab\">Accent<small>Highlights, KPI accents</small></div>\n <div class=\"ctl\"><span class=\"clr\"><input type=\"color\" [(ngModel)]=\"seeds.accent\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"hex\">{{ seeds.accent }}</span></span></div></div>\n <div class=\"row\"><div class=\"lab\">Tertiary<small>Secondary actions, info</small></div>\n <div class=\"ctl\"><span class=\"clr\"><input type=\"color\" [(ngModel)]=\"seeds.tertiary\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"hex\">{{ seeds.tertiary }}</span></span></div></div>\n <div class=\"row\"><div class=\"lab\">Secondary<small>Derived \u2014 deep surfaces</small></div>\n <div class=\"ctl\"><span class=\"clr static\"><span class=\"sw-box\" [style.background]=\"secondaryColor\"></span><span class=\"hex\">{{ secondaryColor }}</span></span></div></div>\n <div class=\"row\"><div class=\"lab\">Text on primary<small>Worst of light &amp; dark</small></div>\n <div class=\"ctl\">\n @if (onPrimaryWorst; as worst) {\n <span class=\"ok\" [class.warn]=\"!worst.check.passes\"\n [title]=\"'light ' + (onPrimaryDetail.light?.ratio ?? '\u2014') + ':1 \u00B7 dark ' + (onPrimaryDetail.dark?.ratio ?? '\u2014') + ':1'\">\n {{ worst.check.passes ? '\u2713' : '\u26A0' }} {{ worst.check.ratio }}:1 <em class=\"mode-tag\">{{ worst.mode }}</em>\n @if (!worst.check.passes && worst.check.suggestion) { <span> \u2192 {{ worst.check.suggestion.hex }}</span> }\n </span>\n }\n </div></div>\n @if (onPrimaryDetail.light; as l) {\n @if (onPrimaryDetail.dark; as d) {\n <div class=\"derived-note contrast-detail\">Per mode: light {{ l.ratio }}:1 {{ l.passes ? '\u2713' : '\u26A0' }} \u00B7 dark {{ d.ratio }}:1 {{ d.passes ? '\u2713' : '\u26A0' }}</div>\n }\n }\n </div>\n\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-font\"></i></span>Typography<span class=\"scope\">Everywhere</span></h3>\n <div class=\"row\"><div class=\"lab\">Font family</div>\n <div class=\"ctl\"><select [(ngModel)]=\"seeds.fontFamily\" (ngModelChange)=\"onSeedsChanged()\">\n @for (f of fontOptions; track f.value) {\n <option [value]=\"f.value\">{{ f.label }}</option>\n }\n </select></div></div>\n <div class=\"row\"><div class=\"lab\">Vibrancy<small>Brand ramp saturation</small></div>\n <div class=\"ctl\"><input type=\"range\" min=\"0.5\" max=\"1.4\" step=\"0.05\" [(ngModel)]=\"seeds.vibrancy\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"val\">{{ seeds.vibrancy }}</span></div></div>\n <div class=\"row\"><div class=\"lab\">Neutral character<small>Brand tint in grays</small></div>\n <div class=\"ctl\"><input type=\"range\" min=\"0\" max=\"0.08\" step=\"0.005\" [(ngModel)]=\"seeds.neutralChroma\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"val\">{{ seeds.neutralChroma }}</span></div></div>\n <div class=\"row\"><div class=\"lab\">Base size<small>Generated content</small></div>\n <div class=\"ctl\"><input type=\"range\" min=\"12\" max=\"18\" step=\"1\" [(ngModel)]=\"baseFontSize\" (ngModelChange)=\"onBaseSizeChanged()\"><span class=\"val\">{{ baseFontSize }}px</span></div></div>\n </div>\n\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-square\"></i></span>Shape &amp; density<span class=\"scope\">Generated content</span></h3>\n <p class=\"sub\">Applies to Skip / agent components. Explorer chrome keeps MJ shape.</p>\n <div class=\"row\"><div class=\"lab\">Corner radius</div>\n <div class=\"ctl\"><input type=\"range\" min=\"0\" max=\"20\" step=\"1\" [(ngModel)]=\"seeds.radius\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"val\">{{ seeds.radius }}px</span></div></div>\n <div class=\"row\"><div class=\"lab\">Elevation depth<small>Brand shadow strength</small></div>\n <div class=\"ctl\"><input type=\"range\" min=\"0\" max=\"1\" step=\"0.1\" [(ngModel)]=\"seeds.depth\" (ngModelChange)=\"onSeedsChanged()\"><span class=\"val\">{{ seeds.depth }}</span></div></div>\n <div class=\"row\"><div class=\"lab\">Density</div>\n <div class=\"ctl\"><div class=\"miniseg\">\n <button type=\"button\" [class.on]=\"density === 16\" (click)=\"density = 16; onDensityChanged()\">Comfortable</button>\n <button type=\"button\" [class.on]=\"density === 9\" (click)=\"density = 9; onDensityChanged()\">Compact</button>\n </div></div></div>\n </div>\n\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-chart-column\"></i></span>Chart palette\n @if (vizOverridden) {\n <button type=\"button\" class=\"reset-link\" (click)=\"resetViz()\">reset</button>\n }\n </h3>\n <p class=\"sub\">Series 1 follows Primary until you override it {{ vizOverridden ? '(overridden)' : '' }}.</p>\n <div class=\"swrow\">\n @for (c of vizColors; track $index; let i = $index) {\n <label class=\"chip-clr\" [style.background]=\"c\">\n <span class=\"chip-num\">{{ i + 1 }}</span>\n <input type=\"color\" [value]=\"c\" (input)=\"editViz(i, $event)\">\n </label>\n }\n </div>\n </div>\n\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-image\"></i></span>Logo &amp; branding</h3>\n <div class=\"row\"><div class=\"lab\">Footer notice<small>Shown in generated output</small></div>\n <div class=\"ctl\"><input class=\"tinput\" [(ngModel)]=\"footerNotice\"></div></div>\n <p class=\"sub\" style=\"margin:8px 0 0\">Logo variant uploads (light / dark / wordmark) are coming with the asset pipeline \u2014 no recolor knob needed.</p>\n </div>\n\n <!-- Recipes (Q2#3): curated intents that expand to reversible token sets. -->\n <div class=\"card\">\n <h3><span class=\"ic\"><i class=\"fa-solid fa-wand-magic-sparkles\"></i></span>Recipes</h3>\n <p class=\"sub\">Curated looks, expanded to token overrides underneath \u2014 fully reversible.</p>\n @for (rs of recipeStates; track rs.recipe.id) {\n <div class=\"row\">\n <div class=\"lab\">{{ rs.recipe.name }}<small>{{ rs.recipe.description }}</small></div>\n <div class=\"ctl\">\n <mj-switch [ngModel]=\"rs.on\" (ngModelChange)=\"toggleRecipe(rs.recipe)\"\n [attr.aria-label]=\"'Toggle ' + rs.recipe.name\"></mj-switch>\n </div>\n </div>\n }\n </div>\n\n <!-- Advanced: the explicit escalation ladder \u2014 seeds \u2192 token overrides \u2192 CSS (Q3#9). -->\n <div class=\"card adv-card\">\n <h3 class=\"adv-head\" (click)=\"toggleAdvanced()\">\n <span class=\"ic\"><i class=\"fa-solid fa-code\"></i></span>Advanced\n <i class=\"fa-solid caret\" [class.fa-chevron-down]=\"advancedOpen\" [class.fa-chevron-right]=\"!advancedOpen\"></i>\n </h3>\n @if (!advancedOpen && advancedSummary) {\n <p class=\"adv-summary\">{{ advancedSummary }}\n <button type=\"button\" class=\"reset-link adv-edit\" (click)=\"toggleAdvanced()\">Edit</button>\n </p>\n }\n @if (advancedOpen) {\n <div class=\"ladder\" aria-hidden=\"true\">\n <span class=\"ladder-step done\"><b>1</b> Seeds</span>\n <i class=\"fa-solid fa-arrow-right\"></i>\n <span class=\"ladder-step\"><b>2</b> Token overrides</span>\n <i class=\"fa-solid fa-arrow-right\"></i>\n <span class=\"ladder-step esc\"><b>3</b> Custom CSS</span>\n </div>\n <p class=\"sub\">Escalate in order. Seeds (above) cover most themes; token overrides refine specific surfaces; custom CSS is the escape hatch for what tokens can't express.</p>\n\n <!-- Step 2: visual token browser (Q2#1) -->\n <div class=\"adv-sec\">\n <div class=\"adv-lab\"><span class=\"step-num\">2</span>Token overrides</div>\n <p class=\"sub\">The full derived token contract, grouped and searchable. Click a swatch to override; hover a row to see where it's used in the preview. Overrides apply over the derived tokens (both modes).</p>\n <input class=\"tinput tok-search\" type=\"search\" placeholder=\"Search tokens (e.g. hover, surface, viz)\u2026\"\n [(ngModel)]=\"tokenSearch\" (ngModelChange)=\"onTokenSearchChanged()\" spellcheck=\"false\">\n <div class=\"tok-groups\">\n @for (g of tokenGroups; track g.key) {\n <div class=\"tok-group\">\n <button type=\"button\" class=\"tok-group-h\" (click)=\"toggleTokenCategory(g.key)\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"isTokenCategoryOpen(g.key)\" [class.fa-chevron-right]=\"!isTokenCategoryOpen(g.key)\"></i>\n {{ g.label }}\n @if (g.modified > 0) { <span class=\"tok-mod-count\">{{ g.modified }} modified</span> }\n <span class=\"tok-count\">{{ g.rows.length }}</span>\n </button>\n @if (isTokenCategoryOpen(g.key)) {\n @for (t of g.rows; track t.name) {\n <div class=\"tok-row\" [class.mod]=\"t.overridden\"\n (mouseenter)=\"highlightTokenTargets(t.name)\" (mouseleave)=\"clearTokenHighlight()\">\n <span class=\"tok-sw\" [style.background]=\"t.value\"></span>\n <code class=\"tok-name\" [title]=\"t.name\">{{ t.name }}</code>\n @if (t.overridden) { <span class=\"tok-badge\">modified</span> }\n @if (editingToken === t.name) {\n <input class=\"tinput tok-edit\" [(ngModel)]=\"editingTokenValue\" spellcheck=\"false\"\n (keydown.enter)=\"commitTokenEdit()\" (keydown.escape)=\"cancelTokenEdit()\" (blur)=\"commitTokenEdit()\">\n } @else if (t.isColor) {\n <label class=\"tok-clr\" [title]=\"t.value\">\n <input type=\"color\" [value]=\"t.colorValue\" (input)=\"onTokenColorInput(t.name, $event)\">\n <span class=\"tok-val\">{{ t.value }}</span>\n </label>\n } @else {\n <button type=\"button\" class=\"tok-val-btn\" [title]=\"'Edit ' + t.name\" (click)=\"beginTokenEdit(t)\">{{ t.value }}</button>\n }\n @if (t.overridden) {\n <button type=\"button\" class=\"tok-reset\" title=\"Reset to derived value\" (click)=\"resetTokenOverride(t.name)\"><i class=\"fa-solid fa-rotate-left\"></i></button>\n }\n </div>\n }\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Step 3: custom CSS \u2014 the escape hatch (Q3#4/#5/#6/#8) -->\n <div class=\"adv-sec\">\n <div class=\"adv-lab\"><span class=\"step-num esc\">3</span>Custom CSS<span class=\"esc-tag\">escape hatch</span></div>\n <p class=\"sub\">Only for what tokens can't express. Appended to the theme overlay, auto-scoped to this theme. <code>&#64;import</code> is not supported and is removed on save.</p>\n <div class=\"sel-chips\">\n @for (s of chromeSelectorInfo; track s.selector) {\n <button type=\"button\" class=\"sel-chip\" [title]=\"s.description\" (click)=\"insertChromeSelector(s.selector)\">{{ s.selector }}</button>\n }\n </div>\n <div class=\"css-tools\">\n <select class=\"tok-pick\" (change)=\"onInsertTokenPick($event)\" aria-label=\"Insert a token at the cursor\">\n <option value=\"\">Insert token\u2026</option>\n @for (n of overridableTokens; track n) { <option [value]=\"n\">{{ n }}</option> }\n </select>\n </div>\n <div class=\"adv-css-editor\">\n <mj-code-editor #cssCm language=\"css\" setup=\"basic\"\n [value]=\"customCss\" (change)=\"onCssEditorChange($event)\"\n [extensions]=\"cssEditorExtensions\" [lineWrapping]=\"true\"\n placeholder=\"mj-shell &#123; box-shadow: none; &#125;\"></mj-code-editor>\n </div>\n @for (w of cssWarnings; track w) {\n <p class=\"css-warn\"><i class=\"fa-solid fa-triangle-exclamation\"></i> {{ w }}</p>\n }\n <p class=\"sub adv-note\">The canvas preview of custom CSS is approximate \u2014 the mock's markup differs from the real chrome. Use the workspace preview to author against reality:</p>\n <button mjButton [variant]=\"workspacePreviewOn ? 'warning' : 'outline'\" size=\"sm\" (click)=\"toggleWorkspacePreview()\">\n <i class=\"fa-solid\" [class.fa-eye]=\"!workspacePreviewOn\" [class.fa-eye-slash]=\"workspacePreviewOn\"></i>\n {{ workspacePreviewOn ? 'End workspace preview' : 'Preview on my workspace' }}\n </button>\n </div>\n\n <div class=\"adv-sec\">\n <button type=\"button\" class=\"adv-add\" (click)=\"showGeneratedCss = !showGeneratedCss\">\n <i class=\"fa-solid\" [class.fa-eye]=\"!showGeneratedCss\" [class.fa-eye-slash]=\"showGeneratedCss\"></i>\n {{ showGeneratedCss ? 'Hide' : 'View' }} generated CSS\n </button>\n @if (showGeneratedCss) {\n <div class=\"gen-css\">\n <button type=\"button\" class=\"gen-copy\" (click)=\"copyGeneratedCss()\"><i class=\"fa-solid fa-copy\"></i> Copy</button>\n <div class=\"gen-css-editor\">\n <mj-code-editor language=\"css\" setup=\"minimal\" readonly [value]=\"generatedCss\"></mj-code-editor>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n </div>\n </aside>\n </div>\n </mj-page-body>\n</mj-page-layout>\n", styles: ["/* Theme Studio (v2 layout). Page chrome comes from the shared trio (mj-page-layout /\n mj-page-header / mj-page-body) + mjButton / mj-view-toggle; this file styles the\n theme picker chip (header meta slot), the preview stage + slide-panel editor, and\n the preview canvas. The studio's own controls use the live app --mj-* tokens; the\n preview canvas uses the derived --mj-* vars pushed inline by applyPreviewVars().\n Radius applies app-wide \u2014 MJ chrome components consume var(--mj-radius-*) \u2014 so the\n Explorer mock (mx-*) uses the radius tokens too, matching the real app. */\n:host { display: block; width: 100%; height: 100%; }\n\n/* ---------- theme picker chip (projected into the header [meta] slot) ---------- */\n.theme-pick-wrap { position: relative; }\n.theme-pick { display: inline-flex; align-items: center; gap: 8px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 9px; padding: 5px 6px 5px 10px; color: var(--mj-text-primary); font: inherit; }\n.theme-pick .sw, .theme-menu-item .sw { display: flex; }\n.theme-pick .sw i, .theme-menu-item .sw i { width: 9px; height: 16px; display: block; margin-left: -3px; border-radius: 3px; border: 1.5px solid var(--mj-bg-surface); }\n.theme-pick .sw i:first-child, .theme-menu-item .sw i:first-child { margin-left: 0; }\n.theme-pick b { font-size: 13px; font-weight: 700; }\n.theme-pick .theme-name { cursor: text; }\n.theme-pick .name-input { font: inherit; font-size: 13px; font-weight: 700; color: var(--mj-text-primary); background: var(--mj-bg-surface); border: 1px solid var(--mj-brand-primary); border-radius: 6px; padding: 2px 7px; min-width: 120px; outline: none; }\n.rename-btn { border: 0; background: transparent; color: var(--mj-text-muted); cursor: pointer; font-size: 11px; padding: 2px 4px; line-height: 1; border-radius: 5px; }\n.rename-btn:hover { color: var(--mj-brand-primary); background: var(--mj-bg-surface-hover); }\n.pick-caret { border: 0; background: transparent; cursor: pointer; padding: 4px 5px; margin-left: 2px; border-radius: 6px; display: inline-flex; align-items: center; }\n.pick-caret:hover { background: var(--mj-bg-surface-hover); }\n.theme-pick .caret { font-size: 11px; color: var(--mj-text-muted); }\n.badge { font-size: 9.5px; font-weight: 700; letter-spacing: .04em; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); padding: 2px 6px; border-radius: 20px; }\n.menu-backdrop { position: fixed; inset: 0; z-index: 19; }\n.theme-menu { position: absolute; top: calc(100% + 6px); left: 0; z-index: 20; min-width: 240px; background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 10px; box-shadow: var(--mj-shadow-lg); padding: 6px; }\n.theme-menu-item { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 8px 9px; border: 0; border-radius: 8px; background: transparent; cursor: pointer; color: var(--mj-text-primary); font: inherit; }\n.theme-menu-item:hover { background: var(--mj-bg-surface-hover); }\n.theme-menu-item.on { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); }\n.theme-menu-item b { font-size: 13px; font-weight: 600; }\n.theme-menu-new { display: flex; align-items: center; gap: 7px; width: 100%; padding: 8px 9px; margin-top: 4px; border: 0; border-top: 1px solid var(--mj-border-subtle); background: transparent; color: var(--mj-brand-primary); font: inherit; font-weight: 600; cursor: pointer; }\n.readonly-note { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); margin-left: 8px; }\n.toolbar-spacer { flex: 1; }\n\n/* ---------- stage ---------- */\n.ts-stage { flex: 1; display: flex; min-height: 0; overflow: hidden; position: relative; background: var(--mj-bg-page); }\n.pv-wrap { flex: 1; min-width: 0; overflow: auto; padding: 22px 26px 60px; }\n.pv-inner { max-width: 1240px; margin: 0 auto; }\n\n/* ---------- slide panel (resizable \u2014 Q3) ---------- */\n.ts-panel { flex-shrink: 0; width: 392px; position: relative; background: var(--mj-bg-surface); border-left: 1px solid var(--mj-border-default); display: flex; flex-direction: column; min-height: 0; transition: width .25s cubic-bezier(.4,0,.2,1); overflow: hidden; }\n.ts-panel.resizing { transition: none; user-select: none; }\n.panel-resize { position: absolute; left: 0; top: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 5; touch-action: none; }\n.panel-resize:hover, .ts-panel.resizing .panel-resize { background: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent); }\n.ts-stage.collapsed .panel-resize { display: none; }\n.ts-stage.collapsed .ts-panel { width: 0; border-left: none; }\n.ts-stage.collapsed .panel-h, .ts-stage.collapsed .panel-body { opacity: 0; pointer-events: none; }\n.panel-h { display: flex; align-items: center; gap: 9px; padding: 13px 14px; border-bottom: 1px solid var(--mj-border-default); flex-shrink: 0; min-width: 392px; }\n.panel-h .ic { width: 26px; height: 26px; border-radius: 7px; background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); display: grid; place-items: center; flex-shrink: 0; }\n.panel-h h2 { margin: 0; font-size: 14.5px; font-weight: 700; }\n.panel-h small { color: var(--mj-text-muted); font-size: 11.5px; display: block; font-weight: 500; }\n.collapse-btn { margin-left: auto; width: 30px; height: 30px; border: 1px solid var(--mj-border-default); border-radius: 8px; background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); display: grid; place-items: center; cursor: pointer; }\n.collapse-btn:hover { color: var(--mj-text-primary); }\n.panel-body { flex: 1; overflow: auto; padding: 14px; min-width: 392px; }\n\n/* ---------- editor cards ---------- */\n.card { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 12px; padding: 14px 15px; margin-bottom: 12px; box-shadow: var(--mj-shadow-sm); }\n.card > h3 { margin: 0 0 4px; font-size: 13.5px; font-weight: 700; display: flex; align-items: center; gap: 8px; }\n.card > h3 .ic { width: 21px; height: 21px; border-radius: 6px; background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); display: grid; place-items: center; font-size: 11px; }\n.card > .sub { margin: 0 0 10px; font-size: 11.5px; color: var(--mj-text-muted); }\n.scope { font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--mj-text-muted); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); padding: 2px 6px; border-radius: 5px; margin-left: auto; }\n.reset-link { margin-left: auto; border: 0; background: transparent; color: var(--mj-text-link); font: inherit; font-size: 11.5px; cursor: pointer; }\n.row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; border-top: 1px solid var(--mj-border-subtle); }\n.row:first-of-type { border-top: 0; }\n.lab { font-size: 12.5px; font-weight: 600; }\n.lab small { display: block; font-weight: 500; color: var(--mj-text-muted); font-size: 11px; margin-top: 1px; }\n.ctl { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n.clr { display: inline-flex; align-items: center; gap: 7px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 4px 8px 4px 4px; }\n.clr input[type=color] { appearance: none; -webkit-appearance: none; width: 24px; height: 24px; border: 0; border-radius: 6px; background: none; cursor: pointer; padding: 0; }\n.clr.static .sw-box { width: 24px; height: 24px; border-radius: 6px; display: block; border: 1px solid rgba(0,0,0,.15); }\n.hex { font-family: var(--mj-font-family-mono); font-size: 11.5px; color: var(--mj-text-secondary); min-width: 58px; text-transform: uppercase; }\n.derived-note { font-size: 11px; color: var(--mj-text-muted); padding-top: 7px; display: flex; align-items: center; gap: 6px; }\n.derived-note i { width: 14px; height: 14px; border-radius: 4px; border: 1px solid rgba(0,0,0,.15); display: inline-block; }\n.derived-note code { font-family: var(--mj-font-family-mono); font-size: 10.5px; }\ninput[type=range] { appearance: none; -webkit-appearance: none; width: 104px; height: 4px; border-radius: 3px; background: var(--mj-border-strong); cursor: pointer; }\ninput[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 15px; height: 15px; border-radius: 50%; background: var(--mj-brand-primary); border: 2px solid var(--mj-bg-surface); }\n.val { font-family: var(--mj-font-family-mono); font-size: 11.5px; color: var(--mj-text-secondary); min-width: 44px; text-align: right; }\nselect, .tinput { font: inherit; font-size: 12.5px; color: var(--mj-text-primary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 6px 9px; }\nselect { cursor: pointer; min-width: 120px; }\n.tinput { width: 170px; }\n.miniseg { display: inline-flex; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 2px; }\n.miniseg button { border: 0; background: transparent; color: var(--mj-text-secondary); font: inherit; font-size: 11.5px; font-weight: 600; padding: 4px 9px; border-radius: 6px; cursor: pointer; }\n.miniseg button.on { background: var(--mj-bg-surface); color: var(--mj-text-primary); box-shadow: var(--mj-shadow-sm); }\n.ok { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 700; color: var(--mj-status-success-text); background: var(--mj-status-success-bg); border: 1px solid var(--mj-status-success-border); padding: 3px 8px; border-radius: 20px; white-space: nowrap; }\n.ok.warn { color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); }\n.preset-row { display: flex; flex-wrap: wrap; gap: 8px; }\n.preset { display: flex; flex-direction: column; align-items: center; gap: 5px; border: 1px solid var(--mj-border-default); border-radius: 9px; background: var(--mj-bg-surface); padding: 8px 6px; cursor: pointer; width: 64px; }\n.preset:hover { border-color: var(--mj-brand-primary); background: var(--mj-bg-surface-hover); }\n.preset .sw { display: flex; }\n.preset .sw i { width: 10px; height: 18px; display: block; margin-left: -3px; border-radius: 3px; border: 1.5px solid var(--mj-bg-surface); }\n.preset .sw i:first-child { margin-left: 0; }\n.preset small { font-size: 9.5px; color: var(--mj-text-muted); text-align: center; line-height: 1.15; }\n.swrow { display: flex; flex-wrap: wrap; gap: 7px; padding-top: 4px; }\n.chip-clr { position: relative; width: 38px; height: 38px; border-radius: 9px; border: 1px solid rgba(0,0,0,.12); cursor: pointer; overflow: hidden; }\n.chip-clr input[type=color] { position: absolute; inset: -4px; width: 46px; height: 46px; border: 0; padding: 0; cursor: pointer; opacity: 0; }\n.chip-num { position: absolute; left: 4px; top: 2px; font-size: 9.5px; font-weight: 700; color: rgba(255,255,255,.92); text-shadow: 0 1px 2px rgba(0,0,0,.4); }\n\n/* ---------- preview canvas ---------- */\n.ts-canvas { border-radius: 16px; border: 1px solid var(--mj-border-default); overflow: hidden; box-shadow: var(--mj-shadow-lg); background: var(--mj-bg-page); font-family: var(--mj-font-family); font-size: var(--ts-fs, 14px); color: var(--mj-text-primary); }\n.ts-canvas.fullscreen { position: fixed; inset: 0; z-index: 40; border-radius: 0; border: 0; overflow: auto; }\n.pv-scroll { padding: var(--ts-space, 16px); display: flex; flex-direction: column; gap: var(--ts-space, 16px); }\n.zone-lab { font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--mj-text-muted); margin-bottom: 6px; display: flex; align-items: center; gap: 6px; }\n.zone-lab::before { content: \"\"; width: 5px; height: 5px; border-radius: 50%; background: var(--mj-brand-accent); }\n\n/* mini-Explorer style guide (chrome \u2014 fixed radii, brand colors follow theme) */\n.mx { background: var(--mj-bg-page); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-lg, 12px); overflow: hidden; }\n.mx-shell { height: 44px; background: var(--mj-bg-surface); border-bottom: 1px solid var(--mj-border-default); display: flex; align-items: center; gap: 11px; padding: 0 12px; font-size: .82em; }\n.mx-appico { color: var(--mj-brand-primary); }\n.mx-nav { display: flex; gap: 3px; }\n.mx-nav b { padding: 5px 11px; border-radius: var(--mj-radius-sm, 6px); color: var(--mj-text-secondary); font-weight: 500; cursor: pointer; transition: background .12s ease, color .12s ease; }\n.mx-nav b:hover:not(.on) { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n.mx-nav b.on { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); color: var(--mj-brand-primary); }\n.mx-search { flex: 0 1 190px; min-width: 100px; display: flex; align-items: center; gap: 6px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-sm, 6px); padding: 4px 9px; color: var(--mj-text-muted); }\n.mx-sp { flex: 1; }\n.mx-av { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-brand-on-primary); display: grid; place-items: center; font-size: .72em; font-weight: 700; }\n.mx-ph { background: var(--mj-bg-surface); border-bottom: 1px solid var(--mj-border-default); padding: 11px 14px 0; }\n.mx-ph-top { display: flex; align-items: center; gap: 10px; padding-bottom: 10px; }\n.mx-ph-ico { width: 30px; height: 30px; border-radius: var(--mj-radius-sm, 6px); background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); display: grid; place-items: center; flex-shrink: 0; }\n.mx-ph-title { font-size: .95em; font-weight: 700; }\n.mx-ph-sub { font-size: .72em; color: var(--mj-text-muted); }\n.mx-ph-actions { margin-left: auto; display: flex; align-items: center; gap: 7px; }\n.mx-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 0 10px; border-top: 1px solid var(--mj-border-default); }\n.mx-tabs { display: flex; gap: 2px; }\n.mx-tabs i { font-style: normal; font-size: .78em; font-weight: 600; color: var(--mj-text-secondary); padding: 5px 10px 7px; border-bottom: 2px solid transparent; cursor: pointer; transition: color .12s ease, border-color .12s ease; }\n.mx-tabs i:hover:not(.on) { color: var(--mj-text-primary); border-bottom-color: var(--mj-border-strong); }\n.mx-tabs i.on { color: var(--mj-brand-primary); border-bottom-color: var(--mj-brand-primary); }\n.mx-body { padding: 12px; display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 10px; }\n.mx-cell { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); padding: 10px 11px; min-width: 0; }\n.mx-cell.wide { grid-column: span 2; }\n@media (max-width: 760px) { .mx-cell.wide { grid-column: span 1; } }\n.mx-cap { font-family: var(--mj-font-family-mono); font-size: .62em; color: var(--mj-text-muted); letter-spacing: .04em; margin-bottom: 8px; display: block; }\n.mx-row { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }\n.mx-row + .mx-row { margin-top: 7px; }\n.mx-btn { font: inherit; font-size: .74em; font-weight: 600; padding: 5.5px 11px; border-radius: var(--mj-radius-sm, 6px); cursor: pointer; border: 1px solid transparent; transition: background .12s ease, color .12s ease, border-color .12s ease; }\n.mx-btn.pri { background: var(--mj-brand-primary); color: var(--mj-brand-on-primary); }\n.mx-btn.sec { background: var(--mj-bg-surface-sunken); color: var(--mj-text-primary); border-color: var(--mj-border-default); }\n.mx-btn.out { background: transparent; color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n.mx-btn.dgr { background: transparent; color: var(--mj-status-error); border-color: var(--mj-status-error); }\n\n/* Interactive states (Q1#6): driven by the derived -hover/-active tokens pushed onto\n the canvas, so mousing/tabbing around the preview demonstrates the derived state\n families live \u2014 including the per-mode hover inversion (light hovers darken, dark\n hovers lighten). The .is-* classes force the same states for the static states row. */\n.mx-btn:disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }\n.mx-btn.pri:hover, .mx-btn.pri.is-hover { background: var(--mj-brand-primary-hover); }\n.mx-btn.pri:active, .mx-btn.pri.is-active { background: var(--mj-brand-primary-active); }\n.mx-btn.sec:hover, .mx-btn.sec.is-hover { background: var(--mj-bg-surface-hover); }\n.mx-btn.sec:active, .mx-btn.sec.is-active { background: var(--mj-bg-surface-active); }\n.mx-btn.out:hover, .mx-btn.out.is-hover { color: var(--mj-brand-primary-hover); border-color: var(--mj-brand-primary-hover); background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n.mx-btn.out:active, .mx-btn.out.is-active { color: var(--mj-brand-primary-active); border-color: var(--mj-brand-primary-active); background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); }\n.mx-btn.dgr:hover, .mx-btn.dgr.is-hover { background: var(--mj-status-error-bg); }\n.mx-btn.dgr:active, .mx-btn.dgr.is-active { background: color-mix(in srgb, var(--mj-status-error) 18%, transparent); }\n.ts-canvas :focus-visible, .mx-btn.is-focus { outline: 2px solid var(--mj-border-focus); outline-offset: 2px; }\n.states-row { align-items: center; }\n.mx-input { display: flex; align-items: center; gap: 6px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-sm, 6px); padding: 5px 9px; font-size: .74em; color: var(--mj-text-secondary); min-width: 0; }\n.mx-input.focus { border-color: var(--mj-brand-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent); }\n.mx-swch { width: 32px; height: 18px; border-radius: 20px; background: var(--mj-brand-primary); position: relative; flex-shrink: 0; cursor: pointer; transition: background .15s ease; }\n.mx-swch:hover { background: var(--mj-brand-primary-hover); }\n.mx-swch.off:hover { background: var(--mj-text-muted); }\n.mx-swch::after { content: \"\"; position: absolute; top: 2px; right: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--mj-brand-on-primary); }\n.mx-swch.off { background: var(--mj-border-strong); }\n.mx-swch.off::after { right: auto; left: 2px; }\n.mx-lbl { font-size: .72em; color: var(--mj-text-secondary); }\n.mx-chip { font-size: .7em; font-weight: 600; padding: 4px 10px; border-radius: 16px; border: 1px solid var(--mj-border-default); color: var(--mj-text-secondary); background: var(--mj-bg-surface); cursor: pointer; transition: background .12s ease, border-color .12s ease; }\n.mx-chip:hover:not(.on) { background: var(--mj-bg-surface-hover); border-color: var(--mj-border-strong); }\n.mx-chip.on { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent); color: var(--mj-brand-primary); }\n.mx-stat { font-size: .66em; font-weight: 700; letter-spacing: .03em; padding: 3px 9px; border-radius: 14px; }\n.mx-stat.brand { background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); color: var(--mj-brand-primary); }\n.mx-stat.neu { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); border: 1px solid var(--mj-border-default); }\n.mx-stat.suc { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.mx-stat.wrn { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.mx-prog { height: 7px; border-radius: 6px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); overflow: hidden; flex: 1; }\n.mx-prog i { display: block; height: 100%; width: 64%; background: var(--mj-brand-primary); }\n.mx-lnav { display: flex; flex-direction: column; gap: 3px; margin-bottom: 8px; }\n.mx-lnav b { display: flex; align-items: center; gap: 7px; font-size: .74em; font-weight: 500; color: var(--mj-text-secondary); padding: 6px 9px; border-radius: var(--mj-radius-sm, 6px); cursor: pointer; transition: background .12s ease, color .12s ease; }\n.mx-lnav b:hover:not(.on) { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n.mx-lnav b.on { background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface)); color: var(--mj-brand-primary); font-weight: 600; }\n.mx-lnav b.mx-acc-item { padding-left: 28px; font-weight: 400; }\n.mx-alert { display: flex; align-items: center; gap: 8px; font-size: .72em; font-weight: 600; border-radius: var(--mj-radius-sm, 6px); padding: 8px 10px; border: 1px solid var(--mj-status-info-border); background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.mx-alert i { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }\n.mx-dlg { border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); overflow: hidden; }\n.mx-dlg-t { padding: 8px 11px; background: var(--mj-bg-surface-sunken); font-size: .76em; font-weight: 700; color: var(--mj-text-primary); }\n.mx-dlg-b { padding: 10px 11px; }\n.mx-dlg-a { display: flex; gap: 7px; padding: 9px 11px; border-top: 1px solid var(--mj-border-default); }\n\n/* Skip / agent report (generated content \u2014 follows --mj-radius-*) */\n.pv-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(240px, 1fr); gap: var(--ts-space, 16px); align-items: start; }\n@media (max-width: 1180px) { .pv-grid { grid-template-columns: 1fr; } }\n.report { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-lg, 12px); overflow: hidden; box-shadow: var(--mj-shadow-brand-md); }\n.rhead { background: linear-gradient(105deg, var(--mj-brand-primary), color-mix(in srgb, var(--mj-brand-primary) 62%, black)); color: var(--mj-brand-on-primary); padding: 14px 16px; display: flex; align-items: center; gap: 12px; }\n.logo { width: 34px; height: 34px; border-radius: 9px; background: var(--mj-brand-on-primary); flex-shrink: 0; background-image: var(--mj-logo-mark); background-repeat: no-repeat; background-position: center; background-size: 70%; }\n.rhead .ti { font-size: 1.15em; font-weight: 700; line-height: 1.1; }\n.rhead .su { font-size: .82em; opacity: .85; margin-top: 1px; }\n.rhead .rt { margin-left: auto; font-size: .72em; font-weight: 600; opacity: .9; text-align: right; }\n.rbody { padding: var(--ts-space, 16px); display: flex; flex-direction: column; gap: var(--ts-space, 16px); }\n.kpis { display: grid; grid-template-columns: repeat(3, 1fr); gap: 11px; }\n.kpi { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); padding: 11px; border-top: 3px solid var(--mj-brand-accent); }\n.kpi .n { font-size: 1.7em; font-weight: 750; line-height: 1; }\n.kpi .l { font-size: .76em; color: var(--mj-text-muted); margin-top: 4px; }\n.kpi .d { font-size: .72em; font-weight: 700; margin-top: 5px; display: inline-flex; gap: 3px; }\n.kpi .d.up { color: var(--mj-status-success); } .kpi .d.dn { color: var(--mj-status-error); }\n.chart .ct { font-size: .86em; font-weight: 700; margin-bottom: 2px; }\n.chart .cs { font-size: .74em; color: var(--mj-text-muted); margin-bottom: 12px; }\n.bars { display: flex; align-items: flex-end; gap: 10px; height: 120px; border-bottom: 1.5px solid var(--mj-border-default); }\n.bar { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 5px; }\n.bar .fill { width: 100%; border-radius: 5px 5px 0 0; min-height: 4px; }\n.bar .bv { font-size: .72em; font-weight: 700; color: var(--mj-text-secondary); }\n.cats { display: flex; gap: 10px; margin-top: 7px; }\n.cats span { flex: 1; text-align: center; font-size: .68em; color: var(--mj-text-muted); font-weight: 500; }\ntable.grid { width: 100%; border-collapse: collapse; font-size: .8em; }\ntable.grid th { text-align: left; font-size: .92em; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)); padding: 7px 10px; font-weight: 700; border-bottom: 1px solid var(--mj-border-default); }\ntable.grid th.r, table.grid td.r { text-align: right; }\ntable.grid td { padding: 7px 10px; border-bottom: 1px solid var(--mj-border-default); color: var(--mj-text-secondary); }\ntable.grid tr:nth-child(even) td { background: var(--mj-bg-surface-card); }\ntable.grid td b { color: var(--mj-text-primary); font-weight: 600; }\n.rfoot { padding: 11px 16px; border-top: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); font-size: .72em; color: var(--mj-text-muted); display: flex; align-items: center; gap: 8px; }\n.rfoot .dot { width: 4px; height: 4px; border-radius: 50%; background: var(--mj-text-muted); }\n.side-stack { display: flex; flex-direction: column; gap: var(--ts-space, 16px); }\n.mini { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-lg, 12px); padding: 13px; box-shadow: var(--mj-shadow-brand-sm); }\n.mini .mt { font-size: .82em; font-weight: 700; margin-bottom: 2px; }\n.mini .ms { font-size: .72em; color: var(--mj-text-muted); margin-bottom: 10px; }\n.alertrow { display: flex; flex-direction: column; gap: 7px; }\n.alert { display: flex; align-items: center; gap: 8px; font-size: .76em; font-weight: 600; border-radius: var(--mj-radius-sm, 6px); padding: 7px 10px; border: 1px solid; }\n.alert.suc { color: var(--mj-status-success-text); background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); }\n.alert.wrn { color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); }\n.alert.err { color: var(--mj-status-error-text); background: var(--mj-status-error-bg); border-color: var(--mj-status-error-border); }\n.alert i { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }\n.ramp { display: flex; border-radius: var(--mj-radius-sm, 6px); overflow: hidden; height: 34px; border: 1px solid var(--mj-border-default); }\n.ramp i { flex: 1; }\n.ramp i:nth-child(1) { background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)); }\n.ramp i:nth-child(2) { background: color-mix(in srgb, var(--mj-brand-primary) 22%, var(--mj-bg-surface)); }\n.ramp i:nth-child(3) { background: color-mix(in srgb, var(--mj-brand-primary) 38%, var(--mj-bg-surface)); }\n.ramp i:nth-child(4) { background: color-mix(in srgb, var(--mj-brand-primary) 55%, var(--mj-bg-surface)); }\n.ramp i:nth-child(5) { background: color-mix(in srgb, var(--mj-brand-primary) 72%, var(--mj-bg-surface)); }\n.ramp i:nth-child(6) { background: color-mix(in srgb, var(--mj-brand-primary) 88%, var(--mj-bg-surface)); }\n.ramp i:nth-child(7) { background: var(--mj-brand-primary); }\n.ag-sum { font-size: .85em; color: var(--mj-text-secondary); line-height: 1.6; margin: 0 0 12px; }\n.ag-sum b { color: var(--mj-text-primary); }\n.ag-finds { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }\n.ag-find { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); background: var(--mj-bg-surface-card); font-size: .8em; }\n.ag-find .fdot { width: 8px; height: 8px; border-radius: 50%; background: var(--mj-brand-primary); flex-shrink: 0; }\n.ag-find .mx-stat { margin-left: auto; flex-shrink: 0; }\n\n/* ---------- fullscreen bar ---------- */\n.fs-bar { position: fixed; top: 14px; right: 16px; z-index: 41; display: flex; align-items: center; gap: 8px; }\n.fs-bar mj-view-toggle, .fs-bar button { box-shadow: var(--mj-shadow-lg); }\n.kbd { font-family: var(--mj-font-family-mono); font-size: 10.5px; border: 1px solid var(--mj-border-strong); border-radius: 5px; padding: 1px 5px; color: var(--mj-text-muted); margin-left: 6px; }\n\n/* ---------- advanced section ---------- */\n.adv-head { cursor: pointer; user-select: none; }\n.adv-head .caret { margin-left: auto; font-size: 12px; color: var(--mj-text-muted); }\n.adv-card .sub { margin: 0 0 10px; font-size: 11.5px; color: var(--mj-text-muted); }\n.adv-card .sub code { font-family: var(--mj-font-family-mono); font-size: 11px; background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-subtle); border-radius: 4px; padding: 0 4px; }\n.adv-sec { padding: 10px 0; border-top: 1px solid var(--mj-border-subtle); }\n.adv-sec:first-of-type { border-top: 0; }\n.adv-lab { font-size: 12px; font-weight: 700; color: var(--mj-text-primary); margin-bottom: 4px; }\n.adv-note { margin-top: 6px !important; font-style: italic; }\n.ovr-row { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }\n.ovr-key { flex: 3 1 0; width: auto; min-width: 0; }\n.ovr-val { flex: 2 1 0; width: auto; min-width: 0; }\n.ovr-del { flex: 0 0 auto; border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); color: var(--mj-text-muted); border-radius: 7px; width: 28px; height: 28px; cursor: pointer; display: grid; place-items: center; }\n.ovr-del:hover { color: var(--mj-status-error); border-color: color-mix(in srgb, var(--mj-status-error) 45%, transparent); }\n.adv-add { display: inline-flex; align-items: center; gap: 6px; border: 1px dashed var(--mj-border-strong); background: transparent; color: var(--mj-text-link); font: inherit; font-size: 12px; font-weight: 600; padding: 6px 10px; border-radius: 8px; cursor: pointer; }\n.adv-add:hover { background: var(--mj-bg-surface-hover); }\n.adv-css-wrap { position: relative; }\n.adv-css { display: block; width: 100%; box-sizing: border-box; font-family: var(--mj-font-family-mono); font-size: 12px; line-height: 1.5; color: var(--mj-text-primary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 9px 10px; resize: vertical; }\n.adv-css:focus { outline: none; border-color: var(--mj-brand-primary); }\n.css-ac { position: absolute; z-index: 30; left: 0; right: 0; top: 100%; margin: 4px 0 0; padding: 4px; list-style: none; max-height: 210px; overflow: auto; background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 8px; box-shadow: var(--mj-shadow-lg); }\n.css-ac li { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; font-family: var(--mj-font-family-mono); font-size: 12px; color: var(--mj-text-primary); cursor: pointer; }\n.css-ac li i { font-size: 10px; color: var(--mj-text-muted); width: 12px; text-align: center; }\n.css-ac li:hover { background: var(--mj-bg-surface-hover); }\n.css-ac li.on { background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface)); }\n.gen-css { position: relative; margin-top: 8px; }\n.gen-css pre { max-height: 260px; overflow: auto; margin: 0; font-family: var(--mj-font-family-mono); font-size: 11px; line-height: 1.5; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 10px; white-space: pre; }\n.gen-copy { position: absolute; top: 8px; right: 8px; display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); color: var(--mj-text-secondary); font: inherit; font-size: 11px; padding: 4px 8px; border-radius: 6px; cursor: pointer; }\n.gen-copy:hover { background: var(--mj-bg-surface-hover); }\n\n/* ---------- header notes ---------- */\n.preview-note { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border: 1px solid var(--mj-status-warning-border); padding: 2px 8px; border-radius: 20px; margin-left: 8px; }\n\n/* ---------- contrast headline (worst-of-both) ---------- */\n.ok .mode-tag { font-style: normal; font-weight: 600; opacity: .75; text-transform: uppercase; font-size: 9px; letter-spacing: .05em; }\n.contrast-detail { padding-top: 4px; }\n\n/* ---------- new-theme preset gallery ---------- */\n.gal-backdrop { position: absolute; inset: 0; z-index: 24; background: var(--mj-bg-overlay, color-mix(in srgb, var(--mj-text-primary) 35%, transparent)); }\n.gal { position: absolute; z-index: 25; left: 50%; top: 48px; transform: translateX(-50%); width: min(640px, calc(100% - 48px)); background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 14px; box-shadow: var(--mj-shadow-lg); padding: 20px 22px 16px; }\n.gal h2 { margin: 0 0 4px; font-size: 17px; font-weight: 750; }\n.gal .gal-sub { margin: 0 0 14px; font-size: 12.5px; color: var(--mj-text-muted); }\n.gal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }\n.gal-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--mj-border-default); border-radius: 11px; background: var(--mj-bg-surface); padding: 10px; cursor: pointer; text-align: left; font: inherit; transition: border-color .12s ease, box-shadow .12s ease; }\n.gal-card:hover { border-color: var(--mj-brand-primary); box-shadow: var(--mj-shadow-sm); }\n.gal-card b { font-size: 12.5px; font-weight: 650; color: var(--mj-text-primary); }\n.gal-mock { display: block; overflow: hidden; border: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card); }\n.gal-mock-bar { display: block; height: 18px; }\n.gal-mock-body { display: flex; flex-direction: column; gap: 5px; padding: 8px; }\n.gal-line { display: block; height: 5px; border-radius: 3px; background: var(--mj-border-default); width: 80%; }\n.gal-line.short { width: 55%; }\n.gal-mock-row { display: flex; align-items: center; gap: 5px; margin-top: 2px; }\n.gal-dot { width: 11px; height: 11px; border-radius: 50%; display: block; }\n.gal-btn { display: block; width: 34px; height: 12px; margin-left: auto; }\n.gal-foot { display: flex; justify-content: flex-start; margin-top: 12px; }\n\n/* ---------- escalation ladder (Q3#9) ---------- */\n.ladder { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 4px 0 8px; }\n.ladder > i { font-size: 10px; color: var(--mj-text-muted); }\n.ladder-step { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 650; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 20px; padding: 3px 10px 3px 4px; }\n.ladder-step b { width: 17px; height: 17px; border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-text-inverse); display: grid; place-items: center; font-size: 10px; font-weight: 700; }\n.ladder-step.esc { border-style: dashed; color: var(--mj-status-warning-text); }\n.ladder-step.esc b { background: var(--mj-status-warning); }\n.step-num { width: 17px; height: 17px; border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-text-inverse); display: inline-grid; place-items: center; font-size: 10px; font-weight: 700; margin-right: 7px; }\n.step-num.esc { background: var(--mj-status-warning); }\n.esc-tag { font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border: 1px solid var(--mj-status-warning-border); padding: 1px 7px; border-radius: 12px; margin-left: 8px; }\n.adv-summary { margin: 6px 0 0; font-size: 12px; color: var(--mj-text-secondary); display: flex; align-items: center; gap: 8px; }\n.adv-summary .adv-edit { margin-left: 0; }\n\n/* ---------- visual token browser (Q2#1) ---------- */\n.tok-search { width: 100%; box-sizing: border-box; margin-bottom: 8px; }\n.tok-groups { display: flex; flex-direction: column; gap: 4px; }\n.tok-group { border: 1px solid var(--mj-border-subtle); border-radius: 9px; overflow: hidden; }\n.tok-group-h { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; border: 0; background: var(--mj-bg-surface-card); color: var(--mj-text-primary); font: inherit; font-size: 12px; font-weight: 650; padding: 7px 10px; cursor: pointer; }\n.tok-group-h:hover { background: var(--mj-bg-surface-hover); }\n.tok-group-h > i { font-size: 10px; color: var(--mj-text-muted); width: 11px; }\n.tok-count { margin-left: auto; font-size: 10.5px; font-weight: 600; color: var(--mj-text-muted); }\n.tok-mod-count { font-size: 9.5px; font-weight: 700; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); padding: 1px 7px; border-radius: 12px; }\n.tok-row { display: flex; align-items: center; gap: 7px; padding: 5px 10px; border-top: 1px solid var(--mj-border-subtle); }\n.tok-row:hover { background: var(--mj-bg-surface-card); }\n.tok-row.mod { background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent); }\n.tok-sw { width: 16px; height: 16px; border-radius: 4px; border: 1px solid var(--mj-border-default); flex-shrink: 0; }\n.tok-name { font-family: var(--mj-font-family-mono); font-size: 10.5px; color: var(--mj-text-primary); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.tok-badge { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--mj-brand-primary); background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent); padding: 1px 6px; border-radius: 10px; flex-shrink: 0; }\n.tok-clr { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; flex-shrink: 0; }\n.tok-clr input[type=color] { appearance: none; -webkit-appearance: none; width: 20px; height: 20px; border: 0; border-radius: 5px; background: none; cursor: pointer; padding: 0; }\n.tok-val, .tok-val-btn { font-family: var(--mj-font-family-mono); font-size: 10px; color: var(--mj-text-secondary); max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.tok-val-btn { border: 1px dashed transparent; background: transparent; padding: 2px 5px; border-radius: 5px; cursor: pointer; flex-shrink: 0; }\n.tok-val-btn:hover { border-color: var(--mj-border-strong); color: var(--mj-text-primary); }\n.tok-edit { flex: 1 1 auto; min-width: 90px; width: auto; font-family: var(--mj-font-family-mono); font-size: 10.5px; padding: 3px 7px; }\n.tok-reset { flex: 0 0 auto; border: 0; background: transparent; color: var(--mj-text-muted); cursor: pointer; padding: 2px 4px; border-radius: 5px; font-size: 10.5px; }\n.tok-reset:hover { color: var(--mj-status-error); background: var(--mj-bg-surface-hover); }\n\n/* ---------- custom-CSS escape hatch (Q3#4/#5/#6) ---------- */\n.sel-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }\n.sel-chip { font-family: var(--mj-font-family-mono); font-size: 10.5px; font-weight: 600; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 14px; padding: 3px 9px; cursor: pointer; transition: color .12s ease, border-color .12s ease; }\n.sel-chip:hover { color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n.css-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }\n.tok-pick { font: inherit; font-size: 11.5px; color: var(--mj-text-secondary); background: var(--mj-bg-surface-sunken); border: 1px solid var(--mj-border-default); border-radius: 8px; padding: 5px 8px; cursor: pointer; max-width: 100%; }\n.adv-css-editor { height: clamp(220px, 34vh, 460px); border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; margin-bottom: 6px; }\n/* CodeMirror renders outside this component's encapsulation scope (ng-code-editor is\n encapsulation-None), so ::ng-deep is required to size the editor to its shell. */\n.adv-css-editor ::ng-deep .cm-editor { height: 100%; }\n.adv-css-editor ::ng-deep mj-code-editor { display: block; height: 100%; }\n.css-warn { display: flex; align-items: flex-start; gap: 7px; margin: 6px 0 0; font-size: 11.5px; color: var(--mj-status-warning-text); background: var(--mj-status-warning-bg); border: 1px solid var(--mj-status-warning-border); border-radius: 8px; padding: 6px 9px; }\n.css-warn i { margin-top: 1px; flex-shrink: 0; }\n.gen-css-editor { height: 260px; margin-top: 8px; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.gen-css-editor ::ng-deep .cm-editor { height: 100%; }\n.gen-css-editor ::ng-deep mj-code-editor { display: block; height: 100%; }\n\n@media (max-width: 900px) {\n .ts-panel { position: absolute; right: 0; top: 0; bottom: 0; z-index: 10; box-shadow: var(--mj-shadow-lg); }\n .kpis { grid-template-columns: 1fr 1fr; }\n}\n"] }]
2905
+ }], () => [{ type: i0.ChangeDetectorRef }, { type: i1.ThemeService }], { previewCanvas: [{
2906
+ type: ViewChild,
2907
+ args: ['previewCanvas']
2908
+ }], nameInput: [{
2909
+ type: ViewChild,
2910
+ args: ['nameInput']
2911
+ }], stageEl: [{
2912
+ type: ViewChild,
2913
+ args: ['stage']
2914
+ }], cssCm: [{
2915
+ type: ViewChild,
2916
+ args: ['cssCm']
2917
+ }], galDialog: [{
2918
+ type: ViewChild,
2919
+ args: ['galDialog']
2920
+ }], onWindowResize: [{
2921
+ type: HostListener,
2922
+ args: ['window:resize']
2923
+ }], onFullscreenChange: [{
2924
+ type: HostListener,
2925
+ args: ['document:fullscreenchange']
2926
+ }], onEscape: [{
2927
+ type: HostListener,
2928
+ args: ['document:keydown.escape']
2929
+ }] }); })();
2930
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ThemeStudioDashboardComponent, { className: "ThemeStudioDashboardComponent", filePath: "src/ThemeStudio/theme-studio-dashboard.component.ts", lineNumber: 113 }); })();
2931
+ //# sourceMappingURL=theme-studio-dashboard.component.js.map