@dickpy/dsh-imagegen 1.2.3 → 1.4.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 (45) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +203 -181
  3. package/cordis.patch.yml +8 -8
  4. package/docs/images/multi-model-comparison.png +0 -0
  5. package/lib/client.js +2711 -1318
  6. package/lib/client.js.map +1 -1
  7. package/lib/index.js +830 -155
  8. package/package.json +70 -68
  9. package/src/agent-image-tools.ts +418 -316
  10. package/src/client/ImageGenPanel.tsx +1703 -1476
  11. package/src/client/SettingsCard.tsx +936 -648
  12. package/src/client/TemplateLibrary.tsx +336 -336
  13. package/src/client/api.ts +193 -193
  14. package/src/client/channels-form.ts +263 -0
  15. package/src/client/controller.ts +46 -46
  16. package/src/client/conversation-sync.ts +14 -0
  17. package/src/client/css-modules.d.ts +5 -5
  18. package/src/client/helpers.ts +33 -33
  19. package/src/client/image-toolview.module.css +73 -73
  20. package/src/client/image-toolview.tsx +170 -152
  21. package/src/client/index.ts +32 -22
  22. package/src/client/locales.ts +610 -484
  23. package/src/client/mount.tsx +185 -96
  24. package/src/client/panel.module.css +1713 -1445
  25. package/src/client/settings-card.module.css +1023 -536
  26. package/src/client/settings-form.ts +336 -336
  27. package/src/client/settings-scope.ts +298 -250
  28. package/src/client/sidebar-entry.ts +148 -102
  29. package/src/client/templates.module.css +453 -453
  30. package/src/engine.ts +520 -464
  31. package/src/gallery-store.ts +286 -280
  32. package/src/generation-runtime.ts +79 -48
  33. package/src/history-store.ts +250 -238
  34. package/src/image-format.ts +11 -0
  35. package/src/image-models.ts +19 -19
  36. package/src/index.ts +318 -212
  37. package/src/model-catalog.ts +115 -0
  38. package/src/presets.ts +71 -0
  39. package/src/prompt-enhancer.ts +137 -79
  40. package/src/protocol.ts +338 -253
  41. package/src/routes.ts +916 -738
  42. package/src/task-queue.ts +113 -103
  43. package/src/templates/cases.json +10196 -10196
  44. package/src/templates-store.ts +278 -278
  45. package/src/updater.ts +117 -117
@@ -1,1563 +1,1831 @@
1
- /**
2
- * dsh-imagegen studio styles. Scoped by the plugin's own data attributes so
3
- * nothing leaks into the rest of the GUI; colors ride the dsh --dsw-* tokens
4
- * and interactive controls reuse the system primitives (Button / Pill), so
5
- * the studio follows the active theme (light/dark and skins) by construction.
6
- * The center-column hide rules are attribute-scoped and must stay in this
7
- * stylesheet (it is imported by mount.tsx, so the styles load with the
8
- * plugin).
9
- */
10
-
11
- /* --- center-column takeover (global rules, attribute-scoped) ----------------- */
12
-
13
- /* The panel container rides inside the conversation grid item as an extra
14
- trailing child; hidden unless the panel is active. The position rule covers
15
- both shells: the legacy `[data-pane="conversation"]` and the rc.6+
16
- AppFrame class-based column ([class*="centerCol"]) — without a positioned
17
- ancestor the absolutely-positioned view resolves against the frame. */
1
+ /**
2
+ * dsh-imagegen studio styles. Scoped by the plugin's own data attributes so
3
+ * nothing leaks into the rest of the GUI; colors ride the dsh --dsw-* tokens
4
+ * and interactive controls reuse the system primitives (Button / Pill), so
5
+ * the studio follows the active theme (light/dark and skins) by construction.
6
+ * The center-column hide rules are attribute-scoped and must stay in this
7
+ * stylesheet (it is imported by mount.tsx, so the styles load with the
8
+ * plugin).
9
+ */
10
+
11
+ /* --- center-column takeover (global rules, attribute-scoped) ----------------- */
12
+
13
+ /* The panel container rides inside the conversation grid item as an extra
14
+ trailing child; hidden unless the panel is active. The position rule covers
15
+ both shells: the legacy `[data-pane="conversation"]` and the rc.6+
16
+ AppFrame class-based column ([class*="centerCol"]) — without a positioned
17
+ ancestor the absolutely-positioned view resolves against the frame. */
18
18
  [data-pane='conversation'],
19
19
  [class*='centerCol'] {
20
20
  position: relative;
21
+ min-width: 0;
22
+ min-height: 0;
21
23
  }
22
-
23
- /* The panel container rides inside the conversation grid item as an extra
24
- trailing child; hidden unless the panel is active. */
24
+
25
+ /* The panel container rides inside the conversation grid item as an extra
26
+ trailing child; hidden unless the panel is active. */
25
27
  [data-dsh-imagegen-view] {
26
- position: absolute;
27
- inset: 0;
28
+ position: relative;
29
+ grid-column: 1;
30
+ grid-row: 1;
28
31
  display: none;
29
32
  z-index: 60;
33
+ min-width: 0;
34
+ min-height: 0;
30
35
  background: var(--dsw-alias-bg-base);
31
36
  }
37
+
38
+ /* The center column is single-occupant; the :not() guards keep the sibling
39
+ panels (task board / ssh) from fighting over visibility if both activation
40
+ attributes ever coexist. */
41
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane='conversation'],
42
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*='centerCol'] {
43
+ display: grid !important;
44
+ grid-template-columns: minmax(0, 1fr) 8px minmax(320px, clamp(320px, var(--dsh-imagegen-chat-width, 36%), 70%));
45
+ grid-template-rows: minmax(0, 1fr);
46
+ gap: 1px;
47
+ overflow: hidden;
48
+ background: var(--dsw-alias-border-l1);
49
+ }
32
50
 
33
- /* The center column is single-occupant; the :not() guards keep the sibling
34
- panels (task board / ssh) from fighting over visibility if both activation
35
- attributes ever coexist. */
36
51
  html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-dsh-imagegen-view] {
37
52
  display: block;
38
53
  }
39
54
 
40
- /* While the panel is active, the conversation content underneath is hidden
41
- (it stays mounted and stateful). */
42
- html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane='conversation'] > :not([data-dsh-imagegen-view]),
43
- html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*='centerCol'] > :not([data-dsh-imagegen-view]) {
44
- display: none !important;
55
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-slot='conversation'] {
56
+ grid-column: 3;
57
+ grid-row: 1;
58
+ align-items: stretch;
59
+ display: flex !important;
60
+ width: auto;
61
+ min-width: 0;
62
+ min-height: 0;
63
+ overflow: hidden;
64
+ background: var(--dsw-alias-bg-base);
45
65
  }
46
66
 
47
- /* --- sidebar entry row ------------------------------------------------------- */
48
-
49
- .entry {
50
- display: flex;
51
- align-items: center;
52
- gap: 8px;
67
+ /* DSH's native conversation root is a flex item with an intrinsic width.
68
+ Stretch that direct child to the complete chat column so its hero composer
69
+ can center itself inside the resized pane instead of leaving a blank rail
70
+ on the right. */
71
+ html[data-dsh-imagegen-active] [data-slot='conversation'] > [data-phase] {
72
+ align-self: stretch;
73
+ flex: 1 1 auto;
53
74
  width: 100%;
54
- height: 32px;
55
- padding: 0 12px;
56
- background: transparent;
57
- border: none;
58
- border-radius: 8px;
59
- color: var(--dsw-alias-label-secondary);
60
- cursor: pointer;
61
- font-size: 13px;
62
- white-space: nowrap;
63
- }
64
-
65
- .entry:hover {
66
- background: var(--dsw-specific-sidebar-nav-item-hover);
67
- color: var(--dsw-alias-label-primary);
75
+ max-width: none;
76
+ min-width: 0;
68
77
  }
69
78
 
70
- .entry[data-active] {
71
- background: var(--dsw-specific-sidebar-nav-item-active);
72
- color: var(--dsw-alias-label-primary);
73
- font-weight: 600;
79
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-dsh-imagegen-chat-resizer] {
80
+ grid-column: 2;
81
+ grid-row: 1;
74
82
  }
75
83
 
76
- .entryIcon {
77
- display: inline-flex;
84
+ .chatResizer {
85
+ position: relative;
86
+ z-index: 70;
87
+ display: none;
88
+ width: 8px;
89
+ min-width: 8px;
78
90
  align-items: center;
79
91
  justify-content: center;
80
- flex: none;
81
- }
82
-
83
- .entryLabel {
84
- overflow: hidden;
85
- text-overflow: ellipsis;
92
+ color: var(--dsw-alias-label-tertiary);
93
+ background: var(--dsw-alias-border-l1);
94
+ cursor: col-resize;
95
+ touch-action: none;
86
96
  }
87
97
 
88
- /* Collapsed rail: icon-only, centered, matching the shell's 56px rail. */
89
- [data-dsh-frame][data-sidebar-collapsed] .entry {
90
- justify-content: center;
91
- padding: 0;
92
- width: 100%;
98
+ .chatResizer::before {
99
+ width: 3px;
100
+ height: 36px;
101
+ border-radius: 3px;
102
+ background: currentColor;
103
+ content: '';
104
+ opacity: .55;
93
105
  }
94
106
 
95
- [data-dsh-frame][data-sidebar-collapsed] .entryLabel {
96
- display: none;
107
+ .chatResizer:hover,
108
+ .chatResizer:focus-visible {
109
+ color: var(--dsw-alias-brand-primary);
110
+ outline: none;
111
+ background: var(--dsw-alias-bg-layer-2);
97
112
  }
98
113
 
99
- /* --- panel frame -------------------------------------------------------------- */
100
-
101
- .view {
102
- overflow: hidden;
114
+ /* Keep the handle above shell defaults: some skins set display:none on
115
+ unrecognised children of the conversation frame. */
116
+ html[data-dsh-imagegen-active] [data-dsh-imagegen-chat-resizer] {
117
+ display: flex !important;
103
118
  }
104
119
 
105
- /* The shell does not ship a global `box-sizing: border-box` reset, so scope
106
- one to the panel subtree: without it, `height: 100%` + padding grows past
107
- the container and clips the footer off the bottom of the screen. */
108
- .panel,
109
- .panel *,
110
- .panel *::before,
111
- .panel *::after {
112
- box-sizing: border-box;
120
+ /* Hide only unrelated center-column plugin children. */
121
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane='conversation'] > :not([data-dsh-imagegen-view]):not([data-slot='conversation']):not([data-dsh-imagegen-chat-resizer]),
122
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*='centerCol'] > :not([data-dsh-imagegen-view]):not([data-slot='conversation']):not([data-dsh-imagegen-chat-resizer]) {
123
+ display: none !important;
113
124
  }
114
125
 
115
- .panel {
116
- position: relative;
117
- display: flex;
118
- flex-direction: column;
119
- height: 100%;
120
- min-width: 0;
121
- min-height: 0;
122
- overflow: hidden;
123
- padding: 14px 16px 16px;
124
- gap: 10px;
125
- background: var(--dsw-alias-bg-base);
126
- color: var(--dsw-alias-label-primary);
127
- font-family: var(--dsw-font-family);
126
+ /* The shell can have any number of plugin entries between the New Session
127
+ tabs and its workspace region. Hide the whole middle run while image
128
+ generation owns the frame, without relying on a plugin allow-list. */
129
+ html[data-dsh-imagegen-active] [data-dsh-imagegen-sidebar-root] > :not([data-dsh-imagegen-session-tabs]):not([class*='logoRow']):not([class*='regionArea']):not([class*='footArea']) {
130
+ display: none !important;
128
131
  }
129
132
 
130
- .panelHeader {
131
- display: flex;
132
- align-items: center;
133
- justify-content: space-between;
134
- gap: 12px;
135
- flex: none;
136
- }
133
+ @media (max-width: 760px) {
134
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane='conversation'],
135
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*='centerCol'] {
136
+ grid-template-columns: minmax(0, 1fr);
137
+ grid-template-rows: minmax(0, 1fr) minmax(340px, 0.9fr);
138
+ overflow-y: auto;
139
+ }
137
140
 
138
- .panelHeading {
139
- display: flex;
140
- align-items: baseline;
141
- gap: 10px;
142
- min-width: 0;
143
- }
141
+ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-slot='conversation'] {
142
+ grid-column: 1;
143
+ grid-row: 2;
144
+ }
144
145
 
145
- .panelTitle {
146
- margin: 0;
147
- font-size: 16px;
148
- font-weight: 700;
149
- color: var(--dsw-alias-label-primary);
150
- white-space: nowrap;
146
+ html[data-dsh-imagegen-active] [data-dsh-imagegen-chat-resizer] {
147
+ display: none !important;
148
+ }
151
149
  }
152
150
 
153
- /* GitHub icon button next to the title (opens the repo). */
154
- .githubLink {
155
- display: inline-flex;
156
- align-items: center;
157
- justify-content: center;
158
- flex: none;
159
- width: 22px;
160
- height: 22px;
161
- border-radius: 6px;
162
- color: var(--dsw-alias-label-secondary);
163
- text-decoration: none;
164
- transition: color 0.12s, background 0.12s;
151
+ /* --- sidebar entry row ------------------------------------------------------- */
152
+
153
+ .entry {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: 8px;
157
+ width: 100%;
158
+ height: 32px;
159
+ padding: 0 12px;
160
+ background: transparent;
161
+ border: none;
162
+ border-radius: 8px;
163
+ color: var(--dsw-alias-label-secondary);
164
+ cursor: pointer;
165
+ font-size: 13px;
166
+ white-space: nowrap;
167
+ }
168
+
169
+ .entry:hover {
170
+ background: var(--dsw-specific-sidebar-nav-item-hover);
171
+ color: var(--dsw-alias-label-primary);
172
+ }
173
+
174
+ .entry[data-active] {
175
+ background: var(--dsw-specific-sidebar-nav-item-active);
176
+ color: var(--dsw-alias-label-primary);
177
+ font-weight: 600;
178
+ }
179
+
180
+ .entryIcon {
181
+ display: inline-flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ flex: none;
185
+ }
186
+
187
+ .entryLabel {
188
+ overflow: hidden;
189
+ text-overflow: ellipsis;
165
190
  }
166
191
 
167
- .githubLink:hover {
168
- color: var(--dsw-alias-label-primary);
169
- background: var(--dsw-alias-bg-layer-2);
192
+ /* New Session + Image Generation tabs share the shell's top action row. */
193
+ .sessionTabs {
194
+ display: grid;
195
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
196
+ gap: 2px;
197
+ width: 100%;
198
+ min-width: 0;
199
+ padding: 3px;
200
+ border: 1px solid var(--dsw-alias-border-l1);
201
+ border-radius: 9px;
202
+ background: var(--dsw-alias-bg-layer-1);
170
203
  }
171
204
 
172
- /* --- connection status and update notice -------------------------------------- */
173
-
174
- .connectionStatus {
205
+ .sessionTab {
175
206
  display: inline-flex;
176
207
  align-items: center;
208
+ justify-content: center;
177
209
  gap: 6px;
178
- flex: none;
179
- height: 28px;
180
- padding: 0 10px;
181
- border: 1px solid var(--dsw-alias-label-error);
182
- border-radius: 8px;
210
+ min-width: 0;
211
+ height: 30px;
212
+ padding: 0 8px;
213
+ border: 0;
214
+ border-radius: 7px;
215
+ color: var(--dsw-alias-label-secondary);
183
216
  background: transparent;
184
- color: var(--dsw-alias-label-error);
217
+ cursor: pointer;
185
218
  font: inherit;
186
219
  font-size: 12px;
187
- line-height: 1;
188
220
  white-space: nowrap;
189
221
  }
190
222
 
191
- .connectionStatus[data-connected='true'] {
192
- border-color: var(--dsw-alias-state-success-primary);
193
- color: var(--dsw-alias-state-success-primary);
194
- }
195
-
196
- .connectionDot {
197
- width: 6px;
198
- height: 6px;
199
- border-radius: 50%;
200
- background: currentColor;
201
- }
202
-
203
- .updateBanner {
204
- display: flex;
205
- align-items: center;
206
- justify-content: space-between;
207
- gap: 12px;
208
- flex: none;
209
- padding: 7px 10px 7px 12px;
210
- font-size: 12px;
211
- line-height: 1.5;
212
- border-radius: 10px;
213
- border: 1px solid var(--dsw-alias-state-warn-primary);
214
- color: var(--dsw-alias-state-warn-primary);
215
- overflow-wrap: anywhere;
216
- }
217
-
218
- .updateBanner[data-kind='ok'] {
219
- color: var(--dsw-alias-state-success-primary);
220
- border-color: var(--dsw-alias-state-success-primary);
221
- }
222
-
223
- .updateText {
224
- min-width: 0;
223
+ .sessionTab:hover,
224
+ .sessionTab[data-active] {
225
+ color: var(--dsw-alias-label-primary);
226
+ background: var(--dsw-specific-sidebar-nav-item-active);
225
227
  }
226
228
 
227
- .updateActions {
229
+ .sessionTabIcon {
228
230
  display: inline-flex;
229
- align-items: center;
230
- gap: 10px;
231
231
  flex: none;
232
+ align-items: center;
233
+ justify-content: center;
232
234
  }
233
235
 
234
- .updateRelease {
235
- color: inherit;
236
- text-decoration: underline;
237
- text-underline-offset: 2px;
238
- white-space: nowrap;
239
- }
240
-
241
- @media (max-width: 700px) {
242
- .panelHeader {
243
- align-items: flex-start;
244
- }
245
-
246
- .panelHeading {
247
- align-items: flex-start;
248
- flex-direction: column;
249
- gap: 2px;
250
- }
251
-
252
- .updateBanner {
253
- align-items: flex-start;
254
- flex-direction: column;
255
- }
256
-
257
- .updateActions {
258
- width: 100%;
259
- justify-content: space-between;
260
- }
236
+ .sessionTabLabel {
237
+ min-width: 0;
238
+ overflow: hidden;
239
+ text-overflow: ellipsis;
261
240
  }
262
241
 
263
- /* --- studio split: left config sidebar (narrow) + right canvas (wide) --------- */
264
-
265
- .studio {
266
- display: flex;
267
- gap: 14px;
268
- flex: 1;
242
+ /* The history surface occupies the shell's workspace/session region while
243
+ image generation is active. The shell's own tree stays mounted underneath
244
+ so closing the tab restores it without a React remount. */
245
+ [class*='regionArea'] {
246
+ position: relative;
269
247
  min-height: 0;
270
- min-width: 0;
271
248
  }
272
249
 
273
- .config {
274
- display: flex;
275
- flex-direction: column;
276
- gap: 12px;
277
- flex: none;
278
- width: 300px;
279
- min-width: 260px;
280
- max-width: 340px;
281
- height: 100%;
250
+ .sidebarHistoryHost {
251
+ position: absolute;
252
+ z-index: 30;
253
+ inset: 0;
254
+ display: none;
255
+ min-width: 0;
282
256
  min-height: 0;
257
+ padding: 6px 4px;
283
258
  overflow: hidden;
259
+ background: var(--dsw-alias-bg-base);
284
260
  }
285
261
 
286
- /* The cards scroll in their own scrollport; the footer stays a fixed sibling
287
- below, so nothing ever hides underneath it (text and edit modes alike). */
288
- .configScroll {
262
+ html[data-dsh-imagegen-active] .sidebarHistoryHost {
289
263
  display: flex;
290
- flex-direction: column;
291
- gap: 12px;
292
- flex: 1;
293
- min-height: 0;
294
- overflow-y: auto;
295
- padding-right: 2px;
296
- scrollbar-width: thin;
297
- scrollbar-color: var(--dsw-alias-border-l2) transparent;
298
264
  }
299
265
 
300
- .configScroll::-webkit-scrollbar {
301
- width: 8px;
266
+ .sidebarHistoryHost .history {
267
+ width: 100%;
268
+ height: 100%;
269
+ border: 0;
270
+ border-radius: 8px;
271
+ background: transparent;
302
272
  }
303
273
 
304
- .configScroll::-webkit-scrollbar-thumb {
305
- background: var(--dsw-alias-border-l2);
306
- border-radius: 999px;
274
+ [data-dsh-frame][data-sidebar-collapsed] .sidebarHistoryHost {
275
+ display: none;
307
276
  }
308
-
309
- .canvas {
310
- position: relative;
311
- flex: 1;
277
+
278
+ /* Collapsed rail: icon-only, centered, matching the shell's 56px rail. */
279
+ [data-dsh-frame][data-sidebar-collapsed] .entry {
280
+ justify-content: center;
281
+ padding: 0;
282
+ width: 100%;
283
+ }
284
+
285
+ [data-dsh-frame][data-sidebar-collapsed] .entryLabel {
286
+ display: none;
287
+ }
288
+
289
+ /* --- panel frame -------------------------------------------------------------- */
290
+
291
+ .view {
292
+ width: 100%;
312
293
  min-width: 0;
313
294
  min-height: 0;
314
- display: flex;
315
- flex-direction: column;
316
- border: 1px solid var(--dsw-alias-border-l1);
317
- border-radius: 12px;
318
- background: var(--dsw-alias-bg-layer-1);
319
295
  overflow: hidden;
320
296
  }
297
+
298
+ /* The shell does not ship a global `box-sizing: border-box` reset, so scope
299
+ one to the panel subtree: without it, `height: 100%` + padding grows past
300
+ the container and clips the footer off the bottom of the screen. */
301
+ .panel,
302
+ .panel *,
303
+ .panel *::before,
304
+ .panel *::after {
305
+ box-sizing: border-box;
306
+ }
307
+
308
+ .panel {
309
+ position: relative;
310
+ display: flex;
311
+ flex-direction: column;
312
+ height: 100%;
313
+ min-width: 0;
314
+ min-height: 0;
315
+ overflow: hidden;
316
+ padding: 14px 16px 16px;
317
+ gap: 10px;
318
+ background: var(--dsw-alias-bg-base);
319
+ color: var(--dsw-alias-label-primary);
320
+ font-family: var(--dsw-font-family);
321
+ }
322
+
323
+ .panelHeader {
324
+ display: flex;
325
+ align-items: center;
326
+ justify-content: space-between;
327
+ gap: 12px;
328
+ flex: none;
329
+ }
330
+
331
+ .panelHeading {
332
+ display: flex;
333
+ align-items: baseline;
334
+ gap: 10px;
335
+ min-width: 0;
336
+ }
337
+
338
+ .panelTitle {
339
+ margin: 0;
340
+ font-size: 16px;
341
+ font-weight: 700;
342
+ color: var(--dsw-alias-label-primary);
343
+ white-space: nowrap;
344
+ }
345
+
346
+ /* GitHub icon button next to the title (opens the repo). */
347
+ .githubLink {
348
+ display: inline-flex;
349
+ align-items: center;
350
+ justify-content: center;
351
+ flex: none;
352
+ width: 22px;
353
+ height: 22px;
354
+ border-radius: 6px;
355
+ color: var(--dsw-alias-label-secondary);
356
+ text-decoration: none;
357
+ transition: color 0.12s, background 0.12s;
358
+ }
359
+
360
+ .githubLink:hover {
361
+ color: var(--dsw-alias-label-primary);
362
+ background: var(--dsw-alias-bg-layer-2);
363
+ }
364
+
365
+ /* --- connection status and update notice -------------------------------------- */
366
+
367
+ .connectionStatus {
368
+ display: inline-flex;
369
+ align-items: center;
370
+ gap: 6px;
371
+ flex: none;
372
+ height: 28px;
373
+ padding: 0 10px;
374
+ border: 1px solid var(--dsw-alias-label-error);
375
+ border-radius: 8px;
376
+ background: transparent;
377
+ color: var(--dsw-alias-label-error);
378
+ font: inherit;
379
+ font-size: 12px;
380
+ line-height: 1;
381
+ white-space: nowrap;
382
+ }
383
+
384
+ .connectionStatus[data-connected='true'] {
385
+ border-color: var(--dsw-alias-state-success-primary);
386
+ color: var(--dsw-alias-state-success-primary);
387
+ }
388
+
389
+ .connectionDot {
390
+ width: 6px;
391
+ height: 6px;
392
+ border-radius: 50%;
393
+ background: currentColor;
394
+ }
395
+
396
+ .updateBanner {
397
+ display: flex;
398
+ align-items: center;
399
+ justify-content: space-between;
400
+ gap: 12px;
401
+ flex: none;
402
+ padding: 7px 10px 7px 12px;
403
+ font-size: 12px;
404
+ line-height: 1.5;
405
+ border-radius: 10px;
406
+ border: 1px solid var(--dsw-alias-state-warn-primary);
407
+ color: var(--dsw-alias-state-warn-primary);
408
+ overflow-wrap: anywhere;
409
+ }
410
+
411
+ .updateBanner[data-kind='ok'] {
412
+ color: var(--dsw-alias-state-success-primary);
413
+ border-color: var(--dsw-alias-state-success-primary);
414
+ }
415
+
416
+ .updateText {
417
+ min-width: 0;
418
+ }
419
+
420
+ .updateActions {
421
+ display: inline-flex;
422
+ align-items: center;
423
+ gap: 10px;
424
+ flex: none;
425
+ }
426
+
427
+ .updateRelease {
428
+ color: inherit;
429
+ text-decoration: underline;
430
+ text-underline-offset: 2px;
431
+ white-space: nowrap;
432
+ }
433
+
434
+ @media (max-width: 700px) {
435
+ .panelHeader {
436
+ align-items: flex-start;
437
+ }
438
+
439
+ .panelHeading {
440
+ align-items: flex-start;
441
+ flex-direction: column;
442
+ gap: 2px;
443
+ }
444
+
445
+ .updateBanner {
446
+ align-items: flex-start;
447
+ flex-direction: column;
448
+ }
449
+
450
+ .updateActions {
451
+ width: 100%;
452
+ justify-content: space-between;
453
+ }
454
+ }
455
+
456
+ /* --- studio split: left history + middle generation workspace ----------------- */
321
457
 
322
- .taskTray {
323
- position: absolute;
324
- z-index: 6;
325
- top: 12px;
326
- right: 12px;
327
- width: min(360px, calc(100% - 24px));
328
- max-height: calc(100% - 24px);
458
+ .studio {
329
459
  display: flex;
330
- flex-direction: column;
331
- overflow: hidden;
332
- border: 1px solid var(--dsw-alias-border-l2);
333
- border-radius: 9px;
334
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);
335
- box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
336
- backdrop-filter: blur(10px);
460
+ min-width: 0;
461
+ min-height: 0;
462
+ flex: 1;
337
463
  }
338
464
 
339
- .taskTray[data-open='false'] { width: auto; max-width: calc(100% - 24px); }
340
- .taskTrayHeader { display: flex; align-items: stretch; min-height: 34px; color: var(--dsw-alias-label-primary); font-size: 12px; font-weight: 600; border-bottom: 1px solid var(--dsw-alias-border-l1); }
341
- .taskTray[data-open='false'] .taskTrayHeader { border-bottom: 0; }
342
- .taskTrayToggle { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; padding: 8px 10px; border: 0; color: inherit; background: transparent; cursor: pointer; font: inherit; font-size: inherit; font-weight: inherit; text-align: left; }
343
- .taskTrayToggle:hover { background: var(--dsw-alias-bg-layer-2); }
344
- .taskTrayCount { min-width: 18px; padding: 1px 5px; border-radius: 999px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); font-size: 11px; font-weight: 500; text-align: center; }
345
- .taskTrayChevron { margin-left: auto; color: var(--dsw-alias-label-tertiary); font-size: 12px; font-weight: 400; }
346
- .taskTrayClose { width: 32px; border: 0; border-left: 1px solid var(--dsw-alias-border-l1); color: var(--dsw-alias-label-tertiary); background: transparent; cursor: pointer; font: inherit; font-size: 17px; }
347
- .taskTrayClose:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }
348
- .taskTray[data-open='false'] .taskTrayToggle { min-height: 34px; }
349
- .taskRows { min-height: 0; overflow-y: auto; }
350
- .taskTray[data-open='false'] .taskRows { display: none; }
351
- .taskRow { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 7px; align-items: center; padding: 7px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }
352
- .taskRow:first-of-type { border-top: 0; }
353
- .taskStatus { color: var(--dsw-alias-label-tertiary); font-size: 11px; white-space: nowrap; }
354
- .taskRow[data-status='running'] .taskStatus { color: var(--dsw-alias-brand-primary); }
355
- .taskRow[data-status='failed'] .taskStatus { color: var(--dsw-alias-label-error); }
356
- .taskPrompt { overflow: hidden; color: var(--dsw-alias-label-secondary); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
357
- .taskRow button { padding: 2px 7px; border: 0; border-radius: 5px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font: inherit; font-size: 11px; }
358
- .taskRow button:hover { color: var(--dsw-alias-brand-primary); }
359
-
360
- .configGuide { position: fixed; inset: 0; z-index: 1100; display: grid; place-items: center; padding: 20px; background: rgb(0 0 0 / 35%); }
361
- .configGuideBody { display: flex; width: min(360px, 100%); flex-direction: column; gap: 12px; padding: 18px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1); box-shadow: 0 14px 40px rgb(0 0 0 / 20%); }
362
- .configGuideBody span { color: var(--dsw-alias-label-secondary); font-size: 13px; line-height: 1.55; }
363
- .configGuideBody button { align-self: flex-end; min-height: 30px; padding: 0 12px; border: 0; border-radius: 7px; color: var(--dsw-alias-bg-layer-1); background: var(--dsw-alias-brand-primary); cursor: pointer; font: inherit; font-size: 12px; }
364
-
365
- /* --- history column (far right) ------------------------------------------------ */
366
-
367
- .history {
465
+ .generation {
368
466
  display: flex;
369
- flex-direction: column;
370
- flex: none;
371
- width: 240px;
372
- min-width: 200px;
373
- max-width: 280px;
467
+ width: 100%;
468
+ gap: 14px;
469
+ min-width: 0;
374
470
  min-height: 0;
375
- border: 1px solid var(--dsw-alias-border-l1);
376
- border-radius: 12px;
377
- background: var(--dsw-alias-bg-layer-1);
378
- overflow: hidden;
379
471
  }
472
+
473
+ .config {
474
+ display: flex;
475
+ flex-direction: column;
476
+ gap: 12px;
477
+ flex: none;
478
+ width: min(300px, 42%);
479
+ min-width: 220px;
480
+ max-width: 300px;
481
+ height: 100%;
482
+ min-height: 0;
483
+ overflow: hidden;
484
+ }
485
+
486
+ /* The cards scroll in their own scrollport; the footer stays a fixed sibling
487
+ below, so nothing ever hides underneath it (text and edit modes alike). */
488
+ .configScroll {
489
+ display: flex;
490
+ flex-direction: column;
491
+ gap: 12px;
492
+ flex: 1;
493
+ min-height: 0;
494
+ overflow-y: auto;
495
+ padding-right: 2px;
496
+ scrollbar-width: thin;
497
+ scrollbar-color: var(--dsw-alias-border-l2) transparent;
498
+ }
499
+
500
+ .configScroll::-webkit-scrollbar {
501
+ width: 8px;
502
+ }
503
+
504
+ .configScroll::-webkit-scrollbar-thumb {
505
+ background: var(--dsw-alias-border-l2);
506
+ border-radius: 999px;
507
+ }
508
+
509
+ .canvas {
510
+ position: relative;
511
+ flex: 1;
512
+ min-width: 0;
513
+ min-height: 0;
514
+ display: flex;
515
+ flex-direction: column;
516
+ border: 1px solid var(--dsw-alias-border-l1);
517
+ border-radius: 12px;
518
+ background: var(--dsw-alias-bg-layer-1);
519
+ overflow: hidden;
520
+ }
521
+
522
+ .taskTray {
523
+ position: absolute;
524
+ z-index: 6;
525
+ top: 12px;
526
+ right: 12px;
527
+ width: min(360px, calc(100% - 24px));
528
+ max-height: calc(100% - 24px);
529
+ display: flex;
530
+ flex-direction: column;
531
+ overflow: hidden;
532
+ border: 1px solid var(--dsw-alias-border-l2);
533
+ border-radius: 9px;
534
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);
535
+ box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
536
+ backdrop-filter: blur(10px);
537
+ }
538
+
539
+ .taskTray[data-open='false'] { width: auto; max-width: calc(100% - 24px); }
540
+ .taskTrayHeader { display: flex; align-items: stretch; min-height: 34px; color: var(--dsw-alias-label-primary); font-size: 12px; font-weight: 600; border-bottom: 1px solid var(--dsw-alias-border-l1); }
541
+ .taskTray[data-open='false'] .taskTrayHeader { border-bottom: 0; }
542
+ .taskTrayToggle { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; padding: 8px 10px; border: 0; color: inherit; background: transparent; cursor: pointer; font: inherit; font-size: inherit; font-weight: inherit; text-align: left; }
543
+ .taskTrayToggle:hover { background: var(--dsw-alias-bg-layer-2); }
544
+ .taskTrayCount { min-width: 18px; padding: 1px 5px; border-radius: 999px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); font-size: 11px; font-weight: 500; text-align: center; }
545
+ .taskTrayChevron { margin-left: auto; color: var(--dsw-alias-label-tertiary); font-size: 12px; font-weight: 400; }
546
+ .taskTrayClose { width: 32px; border: 0; border-left: 1px solid var(--dsw-alias-border-l1); color: var(--dsw-alias-label-tertiary); background: transparent; cursor: pointer; font: inherit; font-size: 17px; }
547
+ .taskTrayClose:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }
548
+ .taskTray[data-open='false'] .taskTrayToggle { min-height: 34px; }
549
+ .taskRows { min-height: 0; overflow-y: auto; }
550
+ .taskTray[data-open='false'] .taskRows { display: none; }
551
+ .taskRow { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 7px; align-items: center; padding: 7px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }
552
+ .taskRow:first-of-type { border-top: 0; }
553
+ .taskStatus { color: var(--dsw-alias-label-tertiary); font-size: 11px; white-space: nowrap; }
554
+ .taskRow[data-status='running'] .taskStatus { color: var(--dsw-alias-brand-primary); }
555
+ .taskRow[data-status='failed'] .taskStatus { color: var(--dsw-alias-label-error); }
556
+ .taskPrompt { overflow: hidden; color: var(--dsw-alias-label-secondary); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
557
+ .taskRow button { padding: 2px 7px; border: 0; border-radius: 5px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font: inherit; font-size: 11px; }
558
+ .taskRow button:hover { color: var(--dsw-alias-brand-primary); }
559
+
560
+ .configGuide { position: fixed; inset: 0; z-index: 1100; display: grid; place-items: center; padding: 20px; background: rgb(0 0 0 / 35%); }
561
+ .configGuideBody { display: flex; width: min(360px, 100%); flex-direction: column; gap: 12px; padding: 18px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1); box-shadow: 0 14px 40px rgb(0 0 0 / 20%); }
562
+ .configGuideBody span { color: var(--dsw-alias-label-secondary); font-size: 13px; line-height: 1.55; }
563
+ .configGuideBody button { align-self: flex-end; min-height: 30px; padding: 0 12px; border: 0; border-radius: 7px; color: var(--dsw-alias-bg-layer-1); background: var(--dsw-alias-brand-primary); cursor: pointer; font: inherit; font-size: 12px; }
564
+
565
+ /* --- history surface (rendered into the shell sidebar) ----------------------- */
380
566
 
381
- .historyHeader {
567
+ .history {
382
568
  display: flex;
383
- align-items: center;
384
- justify-content: space-between;
385
- gap: 8px;
386
- padding: 10px 12px;
387
- border-bottom: 1px solid var(--dsw-alias-border-l1);
388
- flex: none;
389
- }
390
-
391
- .historyFilters {
392
- display: grid;
393
- grid-template-columns: 1fr 1fr;
394
- gap: 6px;
395
- padding: 8px 10px;
396
- border-bottom: 1px solid var(--dsw-alias-border-l1);
397
- }
398
-
399
- .historySearch,
400
- .historyFilters select,
401
- .gallerySearch {
569
+ flex-direction: column;
570
+ width: auto;
402
571
  min-width: 0;
403
- min-height: 29px;
404
- box-sizing: border-box;
405
- padding: 0 8px;
406
- border: 1px solid var(--dsw-alias-border-l2);
407
- border-radius: 7px;
408
- color: var(--dsw-alias-label-primary);
409
- background: var(--dsw-alias-bg-layer-2);
410
- font: inherit;
411
- font-size: 11px;
412
- }
413
-
414
- .historySearch { grid-column: 1 / -1; }
415
- .gallerySearch { width: 156px; }
416
- .galleryTagInput { width: 130px; min-height: 29px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 7px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); font: inherit; font-size: 11px; }
417
- .galleryBulkButton { min-height: 29px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 7px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); cursor: pointer; font: inherit; font-size: 11px; }
418
- .galleryBulkButton:hover:not(:disabled) { color: var(--dsw-alias-brand-primary); border-color: var(--dsw-alias-brand-primary); }
419
- .galleryBulkButton:disabled { opacity: .45; cursor: default; }
420
-
421
- .historyTitle {
422
- font-size: 13px;
423
- font-weight: 600;
424
- color: var(--dsw-alias-label-primary);
572
+ max-width: none;
573
+ min-height: 0;
574
+ border: 1px solid var(--dsw-alias-border-l1);
575
+ border-radius: 12px;
576
+ background: var(--dsw-alias-bg-layer-1);
577
+ overflow: hidden;
578
+ }
579
+
580
+ .historyHeader {
581
+ display: flex;
582
+ align-items: center;
583
+ justify-content: space-between;
584
+ gap: 8px;
585
+ padding: 10px 12px;
586
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
587
+ flex: none;
588
+ }
589
+
590
+ .historyFilters {
591
+ display: grid;
592
+ grid-template-columns: 1fr 1fr;
593
+ gap: 6px;
594
+ padding: 8px 10px;
595
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
596
+ }
597
+
598
+ .historySearch,
599
+ .historyFilters select,
600
+ .gallerySearch {
601
+ min-width: 0;
602
+ min-height: 29px;
603
+ box-sizing: border-box;
604
+ padding: 0 8px;
605
+ border: 1px solid var(--dsw-alias-border-l2);
606
+ border-radius: 7px;
607
+ color: var(--dsw-alias-label-primary);
608
+ background: var(--dsw-alias-bg-layer-2);
609
+ font: inherit;
610
+ font-size: 11px;
611
+ }
612
+
613
+ .historySearch { grid-column: 1 / -1; }
614
+ .gallerySearch { width: 156px; }
615
+ .galleryTagInput { width: 130px; min-height: 29px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 7px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); font: inherit; font-size: 11px; }
616
+ .galleryBulkButton { min-height: 29px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 7px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); cursor: pointer; font: inherit; font-size: 11px; }
617
+ .galleryBulkButton:hover:not(:disabled) { color: var(--dsw-alias-brand-primary); border-color: var(--dsw-alias-brand-primary); }
618
+ .galleryBulkButton:disabled { opacity: .45; cursor: default; }
619
+
620
+ .historyTitle {
621
+ font-size: 13px;
622
+ font-weight: 600;
623
+ color: var(--dsw-alias-label-primary);
624
+ }
625
+
626
+ .historyClear {
627
+ padding: 2px 8px;
628
+ font: inherit;
629
+ font-size: 11.5px;
630
+ color: var(--dsw-alias-label-tertiary);
631
+ background: transparent;
632
+ border: 1px solid var(--dsw-alias-border-l2);
633
+ border-radius: 999px;
634
+ cursor: pointer;
635
+ }
636
+
637
+ .historyClear:hover {
638
+ color: var(--dsw-alias-label-error);
639
+ border-color: var(--dsw-alias-label-error);
640
+ }
641
+
642
+ .historyList {
643
+ flex: 1;
644
+ min-height: 0;
645
+ overflow-y: auto;
646
+ display: flex;
647
+ flex-direction: column;
648
+ gap: 8px;
649
+ padding: 10px;
650
+ scrollbar-width: thin;
651
+ scrollbar-color: var(--dsw-alias-border-l2) transparent;
652
+ }
653
+
654
+ .historyList::-webkit-scrollbar {
655
+ width: 8px;
656
+ }
657
+
658
+ .historyList::-webkit-scrollbar-thumb {
659
+ background: var(--dsw-alias-border-l2);
660
+ border-radius: 999px;
661
+ }
662
+
663
+ .historyEmpty {
664
+ flex: 1;
665
+ display: flex;
666
+ align-items: center;
667
+ justify-content: center;
668
+ padding: 20px;
669
+ font-size: 12px;
670
+ line-height: 1.6;
671
+ text-align: center;
672
+ color: var(--dsw-alias-label-tertiary);
673
+ }
674
+
675
+ .historyItem {
676
+ display: flex;
677
+ flex-direction: column;
678
+ gap: 6px;
679
+ padding: 8px;
680
+ border: 1px solid var(--dsw-alias-border-l1);
681
+ border-radius: 10px;
682
+ background: var(--dsw-alias-bg-layer-2);
683
+ flex: none;
684
+ }
685
+
686
+ .historyItem:hover {
687
+ border-color: var(--dsw-alias-border-l2);
688
+ }
689
+
690
+ .historyItem[data-active] {
691
+ border-color: var(--dsw-alias-brand-primary);
692
+ }
693
+
694
+ .historyMain {
695
+ display: flex;
696
+ gap: 8px;
697
+ align-items: flex-start;
698
+ padding: 0;
699
+ background: transparent;
700
+ border: none;
701
+ font: inherit;
702
+ color: inherit;
703
+ text-align: left;
704
+ cursor: pointer;
705
+ min-width: 0;
706
+ }
707
+
708
+ .historyThumb {
709
+ width: 52px;
710
+ height: 52px;
711
+ border-radius: 8px;
712
+ object-fit: cover;
713
+ background: var(--dsw-alias-bg-base);
714
+ flex: none;
715
+ }
716
+
717
+ .historyThumbPlaceholder {
718
+ width: 52px;
719
+ height: 52px;
720
+ border-radius: 8px;
721
+ background: var(--dsw-alias-bg-layer-3);
722
+ flex: none;
723
+ }
724
+
725
+ .historyInfo {
726
+ flex: 1;
727
+ min-width: 0;
728
+ display: flex;
729
+ flex-direction: column;
730
+ gap: 4px;
731
+ }
732
+
733
+ .historyPrompt {
734
+ font-size: 12px;
735
+ line-height: 1.4;
736
+ color: var(--dsw-alias-label-primary);
737
+ display: -webkit-box;
738
+ -webkit-line-clamp: 2;
739
+ -webkit-box-orient: vertical;
740
+ overflow: hidden;
741
+ }
742
+
743
+ .historyMeta {
744
+ font-size: 11px;
745
+ color: var(--dsw-alias-label-tertiary);
746
+ white-space: nowrap;
747
+ overflow: hidden;
748
+ text-overflow: ellipsis;
749
+ }
750
+
751
+ .historyActions {
752
+ display: flex;
753
+ gap: 6px;
754
+ justify-content: flex-end;
755
+ }
756
+
757
+ .historyAction {
758
+ padding: 2px 8px;
759
+ font: inherit;
760
+ font-size: 11.5px;
761
+ color: var(--dsw-alias-label-secondary);
762
+ background: transparent;
763
+ border: 1px solid var(--dsw-alias-border-l2);
764
+ border-radius: 999px;
765
+ cursor: pointer;
766
+ }
767
+
768
+ .historyAction:hover {
769
+ color: var(--dsw-alias-label-primary);
770
+ border-color: var(--dsw-alias-label-dimmed);
771
+ }
772
+
773
+ .historyAction[data-danger]:hover {
774
+ color: var(--dsw-alias-label-error);
775
+ border-color: var(--dsw-alias-label-error);
776
+ }
777
+
778
+ /* --- cards (system-aligned rounded group chrome) ------------------------------ */
779
+
780
+ .card {
781
+ display: flex;
782
+ flex-direction: column;
783
+ gap: 10px;
784
+ padding: 12px;
785
+ background: var(--dsw-alias-bg-layer-2);
786
+ border: 1px solid var(--dsw-alias-border-l1);
787
+ border-radius: 12px;
788
+ flex: none;
789
+ }
790
+
791
+ /* --- mode tabs (system Pill switcher) ------------------------------------------ */
792
+
793
+ .modeRow {
794
+ display: flex;
795
+ gap: 8px;
796
+ align-items: center;
797
+ }
798
+
799
+ .modePill {
800
+ flex: 1;
801
+ justify-content: center;
802
+ height: 28px;
803
+ font-size: 13px;
804
+ }
805
+
806
+ /* --- reference image upload (edit mode) ---------------------------------------- */
807
+
808
+ .uploadBox {
809
+ display: flex;
810
+ flex-direction: column;
811
+ align-items: center;
812
+ justify-content: center;
813
+ gap: 6px;
814
+ min-height: 128px;
815
+ padding: 16px;
816
+ color: var(--dsw-alias-label-secondary);
817
+ background: transparent;
818
+ border: 1.5px dashed var(--dsw-alias-border-l2);
819
+ border-radius: 12px;
820
+ cursor: pointer;
821
+ font: inherit;
822
+ font-size: 12.5px;
823
+ text-align: center;
824
+ }
825
+
826
+ .uploadBox:hover {
827
+ color: var(--dsw-alias-label-primary);
828
+ border-color: var(--dsw-alias-label-dimmed);
829
+ background: var(--dsw-alias-interactive-bg-hover);
830
+ }
831
+
832
+ .uploadBox:focus-visible {
833
+ outline: 2px solid var(--dsw-alias-brand-primary);
834
+ outline-offset: 1px;
835
+ }
836
+
837
+ .uploadIcon {
838
+ display: inline-flex;
839
+ color: var(--dsw-alias-label-tertiary);
840
+ }
841
+
842
+ .uploadHint {
843
+ font-size: 11px;
844
+ color: var(--dsw-alias-label-tertiary);
845
+ }
846
+
847
+ .reference {
848
+ display: flex;
849
+ flex-direction: column;
850
+ gap: 8px;
851
+ }
852
+
853
+ .referenceImage {
854
+ width: 100%;
855
+ max-height: 176px;
856
+ object-fit: contain;
857
+ border-radius: 10px;
858
+ background: var(--dsw-alias-bg-base);
859
+ border: 1px solid var(--dsw-alias-border-l1);
860
+ }
861
+
862
+ .referenceActions {
863
+ display: flex;
864
+ gap: 8px;
865
+ }
866
+
867
+ .hiddenFile {
868
+ display: none;
869
+ }
870
+
871
+ /* --- prompt -------------------------------------------------------------------- */
872
+
873
+ .prompt {
874
+ width: 100%;
875
+ min-height: 120px;
876
+ padding: 10px 12px;
877
+ font-size: 13px;
878
+ line-height: 1.6;
879
+ color: var(--dsw-alias-label-primary);
880
+ background: var(--dsw-alias-bg-layer-3);
881
+ border: 1px solid var(--dsw-alias-border-l2);
882
+ border-radius: 10px;
883
+ outline: none;
884
+ resize: vertical;
885
+ font-family: inherit;
886
+ box-sizing: border-box;
887
+ }
888
+
889
+ .prompt:focus-visible {
890
+ border-color: var(--dsw-alias-brand-primary);
891
+ }
892
+
893
+ .prompt::placeholder {
894
+ color: var(--dsw-alias-label-tertiary);
895
+ }
896
+
897
+ .promptFooter {
898
+ display: flex;
899
+ align-items: center;
900
+ justify-content: space-between;
901
+ gap: 8px;
902
+ margin-top: -6px;
903
+ }
904
+
905
+ .templatesButton {
906
+ display: inline-flex;
907
+ align-items: center;
908
+ gap: 6px;
909
+ height: 26px;
910
+ padding: 0 12px;
911
+ border: 1px solid var(--dsw-alias-brand-primary);
912
+ border-radius: 999px;
913
+ background: linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, transparent));
914
+ color: var(--dsw-alias-brand-primary);
915
+ font-size: 12px;
916
+ font-weight: 600;
917
+ font-family: inherit;
918
+ cursor: pointer;
919
+ box-shadow: 0 1px 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);
920
+ transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
921
+ }
922
+
923
+ .templatesButton svg {
924
+ flex: none;
925
+ }
926
+
927
+ .templatesButton:hover {
928
+ background: linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 24%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent));
929
+ color: var(--dsw-alias-brand-primary);
930
+ transform: translateY(-1px);
931
+ box-shadow: 0 2px 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);
932
+ }
933
+
934
+ .templatesButton:active {
935
+ transform: translateY(0);
936
+ }
937
+
938
+ .enhanceButton {
939
+ height: 26px;
940
+ margin-left: auto;
941
+ padding: 0 11px;
942
+ border: 1px solid var(--dsw-alias-border-l2);
943
+ border-radius: 999px;
944
+ color: var(--dsw-alias-label-secondary);
945
+ background: var(--dsw-alias-bg-layer-2);
946
+ font: inherit;
947
+ font-size: 12px;
948
+ cursor: pointer;
949
+ }
950
+
951
+ .enhanceButton:hover:not(:disabled) {
952
+ color: var(--dsw-alias-brand-primary);
953
+ border-color: var(--dsw-alias-brand-primary);
954
+ }
955
+
956
+ .enhanceButton:disabled { opacity: 0.5; cursor: default; }
957
+
958
+ .promptCount {
959
+ font-size: 11px;
960
+ color: var(--dsw-alias-label-tertiary);
961
+ font-variant-numeric: tabular-nums;
962
+ }
963
+
964
+ /* --- parameter groups ----------------------------------------------------------- */
965
+
966
+ .paramGroup {
967
+ display: flex;
968
+ flex-direction: column;
969
+ gap: 8px;
970
+ }
971
+
972
+ .paramLabel {
973
+ font-size: 12px;
974
+ font-weight: 600;
975
+ color: var(--dsw-alias-label-secondary);
976
+ }
977
+
978
+ .optionRow {
979
+ display: flex;
980
+ gap: 6px;
981
+ flex-wrap: wrap;
982
+ }
983
+
984
+ .optionGrid {
985
+ display: grid;
986
+ grid-template-columns: repeat(3, 1fr);
987
+ gap: 6px;
988
+ }
989
+
990
+ .optionPill {
991
+ justify-content: center;
992
+ }
993
+
994
+ .paramHint {
995
+ font-size: 11px;
996
+ line-height: 1.45;
997
+ color: var(--dsw-alias-label-tertiary);
998
+ }
999
+
1000
+ /* --- footer: model dropdown + generate button (fixed under the scroll) -------- */
1001
+
1002
+ .footer {
1003
+ display: flex;
1004
+ flex-direction: column;
1005
+ align-items: stretch;
1006
+ gap: 8px;
1007
+ flex: none;
1008
+ padding: 10px 2px 0 0;
1009
+ border-top: 1px solid var(--dsw-alias-border-l1);
1010
+ }
1011
+
1012
+ .modelWrap {
1013
+ display: flex;
1014
+ flex-direction: column;
1015
+ gap: 5px;
1016
+ min-width: 0;
1017
+ }
1018
+
1019
+ .modelLabel {
1020
+ font-size: 12px;
1021
+ font-weight: 600;
1022
+ color: var(--dsw-alias-label-secondary);
1023
+ }
1024
+
1025
+ .modelSelect {
1026
+ width: 100%;
1027
+ height: 36px;
1028
+ display: flex;
1029
+ align-items: center;
1030
+ justify-content: space-between;
1031
+ gap: 8px;
1032
+ padding: 0 12px;
1033
+ font-size: 13px;
1034
+ color: var(--dsw-alias-label-primary);
1035
+ background: var(--dsw-alias-bg-layer-2);
1036
+ border: 1px solid var(--dsw-alias-border-l2);
1037
+ border-radius: 18px;
1038
+ outline: none;
1039
+ font-family: inherit;
1040
+ cursor: pointer;
1041
+ text-align: left;
1042
+ }
1043
+
1044
+ .modelSelect:focus-visible {
1045
+ border-color: var(--dsw-alias-brand-primary);
1046
+ }
1047
+
1048
+ .modelSelect:disabled {
1049
+ opacity: 0.55;
1050
+ cursor: default;
1051
+ }
1052
+
1053
+ /* Model dropdown trigger + upward-opening menu. */
1054
+ .modelMenu {
1055
+ position: relative;
1056
+ display: block;
1057
+ min-width: 0;
1058
+ }
1059
+
1060
+ /* The list opens UPWARD (absolute above the trigger) so it never hides
1061
+ behind the footer edge below. */
1062
+ .modelMenuList {
1063
+ position: absolute;
1064
+ left: 0;
1065
+ right: 0;
1066
+ bottom: calc(100% + 6px);
1067
+ z-index: 40;
1068
+ display: flex;
1069
+ flex-direction: column;
1070
+ padding: 4px;
1071
+ background: var(--dsw-alias-bg-layer-2);
1072
+ border: 1px solid var(--dsw-alias-border-l2);
1073
+ border-radius: 12px;
1074
+ box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18);
1075
+ overflow: hidden;
1076
+ }
1077
+
1078
+ .modelMenuItem {
1079
+ display: block;
1080
+ width: 100%;
1081
+ padding: 7px 10px;
1082
+ font: inherit;
1083
+ font-size: 13px;
1084
+ color: var(--dsw-alias-label-primary);
1085
+ background: transparent;
1086
+ border: none;
1087
+ border-radius: 8px;
1088
+ cursor: pointer;
1089
+ text-align: left;
1090
+ white-space: nowrap;
1091
+ overflow: hidden;
1092
+ text-overflow: ellipsis;
1093
+ }
1094
+
1095
+ .modelMenuItem:hover {
1096
+ background: var(--dsw-alias-bg-hover);
1097
+ }
1098
+
1099
+ .modelMenuItem[data-selected] {
1100
+ color: var(--dsw-alias-brand-primary);
1101
+ font-weight: 600;
1102
+ background: var(--dsw-alias-bg-layer-1);
1103
+ }
1104
+
1105
+ .generateButton {
1106
+ width: 100%;
1107
+ }
1108
+
1109
+ .generateInner {
1110
+ display: inline-flex;
1111
+ align-items: center;
1112
+ gap: 7px;
1113
+ }
1114
+
1115
+ /* --- canvas states --------------------------------------------------------------- */
1116
+
1117
+ .canvasState {
1118
+ flex: 1;
1119
+ display: flex;
1120
+ flex-direction: column;
1121
+ align-items: center;
1122
+ justify-content: center;
1123
+ gap: 8px;
1124
+ padding: 24px;
1125
+ text-align: center;
1126
+ color: var(--dsw-alias-label-tertiary);
1127
+ }
1128
+
1129
+ .canvasStateTitle {
1130
+ font-size: 14px;
1131
+ font-weight: 600;
1132
+ color: var(--dsw-alias-label-secondary);
1133
+ }
1134
+
1135
+ .canvasStateHint {
1136
+ font-size: 12px;
1137
+ max-width: 380px;
1138
+ line-height: 1.6;
1139
+ }
1140
+
1141
+ .canvasEmptyIcon {
1142
+ display: inline-flex;
1143
+ margin-bottom: 4px;
1144
+ color: var(--dsw-alias-label-tertiary);
1145
+ }
1146
+
1147
+ .canvasError {
1148
+ margin: 14px;
1149
+ padding: 10px 14px;
1150
+ font-size: 12.5px;
1151
+ line-height: 1.6;
1152
+ color: var(--dsw-alias-label-error);
1153
+ background: var(--dsw-alias-bg-layer-2);
1154
+ border: 1px solid var(--dsw-alias-label-error);
1155
+ border-radius: 10px;
1156
+ overflow-wrap: anywhere;
1157
+ flex: none;
1158
+ }
1159
+
1160
+ .canvasBody {
1161
+ flex: 1;
1162
+ min-height: 0;
1163
+ display: flex;
1164
+ flex-direction: column;
1165
+ gap: 10px;
1166
+ overflow-y: auto;
1167
+ padding: 14px;
1168
+ scrollbar-width: thin;
1169
+ scrollbar-color: var(--dsw-alias-border-l2) transparent;
1170
+ }
1171
+
1172
+ .canvasBody::-webkit-scrollbar {
1173
+ width: 8px;
1174
+ }
1175
+
1176
+ .canvasBody::-webkit-scrollbar-thumb {
1177
+ background: var(--dsw-alias-border-l2);
1178
+ border-radius: 999px;
1179
+ }
1180
+
1181
+ .canvasMeta {
1182
+ flex: none;
1183
+ display: flex;
1184
+ align-items: center;
1185
+ gap: 8px;
1186
+ font-size: 12px;
1187
+ color: var(--dsw-alias-label-tertiary);
1188
+ }
1189
+
1190
+ .canvasHistoryTag {
1191
+ padding: 1px 8px;
1192
+ font-size: 11px;
1193
+ color: var(--dsw-alias-label-secondary);
1194
+ background: var(--dsw-alias-bg-layer-2);
1195
+ border: 1px solid var(--dsw-alias-border-l2);
1196
+ border-radius: 999px;
1197
+ white-space: nowrap;
1198
+ }
1199
+
1200
+ /* --- result grid ----------------------------------------------------------------- */
1201
+
1202
+ .grid {
1203
+ display: grid;
1204
+ flex: 1;
1205
+ min-height: 0;
1206
+ gap: 14px;
1207
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1208
+ grid-template-rows: repeat(2, minmax(0, 1fr));
1209
+ }
1210
+
1211
+ .grid[data-count='1'] .imageCard {
1212
+ grid-area: 1 / 1 / 3 / 3;
1213
+ }
1214
+
1215
+ .imageCard {
1216
+ position: relative;
1217
+ display: flex;
1218
+ flex-direction: column;
1219
+ margin: 0;
1220
+ border: 1px solid var(--dsw-alias-border-l1);
1221
+ border-radius: 12px;
1222
+ overflow: hidden;
1223
+ background: var(--dsw-alias-bg-layer-2);
1224
+ cursor: zoom-in;
1225
+ min-height: 0;
1226
+ }
1227
+
1228
+ .imageCard:focus-visible {
1229
+ outline: 2px solid var(--dsw-alias-brand-primary);
1230
+ outline-offset: 1px;
1231
+ }
1232
+
1233
+ .image {
1234
+ display: block;
1235
+ flex: 1;
1236
+ min-height: 0;
1237
+ width: 100%;
1238
+ object-fit: cover;
1239
+ background: var(--dsw-alias-bg-base);
1240
+ }
1241
+
1242
+ .imageCaption {
1243
+ padding: 7px 10px;
1244
+ font-size: 11px;
1245
+ line-height: 1.5;
1246
+ color: var(--dsw-alias-label-tertiary);
1247
+ white-space: nowrap;
1248
+ overflow: hidden;
1249
+ text-overflow: ellipsis;
1250
+ border-top: 1px solid var(--dsw-alias-border-l1);
1251
+ }
1252
+
1253
+ .download {
1254
+ position: absolute;
1255
+ top: 8px;
1256
+ right: 8px;
1257
+ padding: 2px 10px;
1258
+ font-size: 12px;
1259
+ line-height: 20px;
1260
+ font-weight: 500;
1261
+ color: var(--dsw-alias-label-primary);
1262
+ background: var(--dsw-alias-bg-mask-1);
1263
+ border: 1px solid var(--dsw-alias-border-l2);
1264
+ border-radius: 999px;
1265
+ text-decoration: none;
1266
+ opacity: 0;
1267
+ transition: opacity 0.12s;
1268
+ backdrop-filter: blur(4px);
1269
+ }
1270
+
1271
+ .imageCard:hover .download {
1272
+ opacity: 1;
1273
+ }
1274
+
1275
+ .download:hover {
1276
+ background: var(--dsw-alias-bg-base);
1277
+ }
1278
+
1279
+ /* Add-to-gallery pill (top-left, mirrors .download; shows on card hover). */
1280
+ .galleryAdd {
1281
+ position: absolute;
1282
+ top: 8px;
1283
+ left: 8px;
1284
+ display: inline-flex;
1285
+ align-items: center;
1286
+ gap: 5px;
1287
+ padding: 2px 10px;
1288
+ font: inherit;
1289
+ font-size: 12px;
1290
+ line-height: 20px;
1291
+ font-weight: 500;
1292
+ color: var(--dsw-alias-label-primary);
1293
+ background: var(--dsw-alias-bg-mask-1);
1294
+ border: 1px solid var(--dsw-alias-border-l2);
1295
+ border-radius: 999px;
1296
+ cursor: pointer;
1297
+ opacity: 0;
1298
+ transition: opacity 0.12s;
1299
+ backdrop-filter: blur(4px);
1300
+ }
1301
+
1302
+ .imageCard:hover .galleryAdd {
1303
+ opacity: 1;
1304
+ }
1305
+
1306
+ .galleryAdd:hover {
1307
+ background: var(--dsw-alias-bg-base);
1308
+ }
1309
+
1310
+ .galleryAdd:disabled {
1311
+ opacity: 0.4;
1312
+ cursor: default;
425
1313
  }
426
1314
 
427
- .historyClear {
428
- padding: 2px 8px;
429
- font: inherit;
430
- font-size: 11.5px;
431
- color: var(--dsw-alias-label-tertiary);
432
- background: transparent;
1315
+ /* Add-to-conversation action sits below the gallery action on hover. */
1316
+ .conversationAdd {
1317
+ position: absolute;
1318
+ top: 38px;
1319
+ left: 8px;
1320
+ display: inline-flex;
1321
+ align-items: center;
1322
+ gap: 5px;
1323
+ padding: 2px 10px;
433
1324
  border: 1px solid var(--dsw-alias-border-l2);
434
1325
  border-radius: 999px;
1326
+ color: var(--dsw-alias-label-primary);
1327
+ background: var(--dsw-alias-bg-mask-1);
435
1328
  cursor: pointer;
1329
+ font: inherit;
1330
+ font-size: 12px;
1331
+ line-height: 20px;
1332
+ font-weight: 500;
1333
+ opacity: 0;
1334
+ transition: opacity 0.12s;
1335
+ backdrop-filter: blur(4px);
436
1336
  }
437
1337
 
438
- .historyClear:hover {
439
- color: var(--dsw-alias-label-error);
440
- border-color: var(--dsw-alias-label-error);
1338
+ .imageCard:hover .conversationAdd,
1339
+ .conversationAdd:focus-visible {
1340
+ opacity: 1;
441
1341
  }
442
1342
 
443
- .historyList {
444
- flex: 1;
445
- min-height: 0;
446
- overflow-y: auto;
447
- display: flex;
448
- flex-direction: column;
449
- gap: 8px;
450
- padding: 10px;
451
- scrollbar-width: thin;
452
- scrollbar-color: var(--dsw-alias-border-l2) transparent;
1343
+ .conversationAdd:hover {
1344
+ background: var(--dsw-alias-bg-base);
453
1345
  }
454
1346
 
455
- .historyList::-webkit-scrollbar {
456
- width: 8px;
1347
+ .conversationAdd:disabled {
1348
+ opacity: 0.4;
1349
+ cursor: default;
457
1350
  }
458
-
459
- .historyList::-webkit-scrollbar-thumb {
460
- background: var(--dsw-alias-border-l2);
461
- border-radius: 999px;
1351
+
1352
+ /* Hover hint for the click-to-zoom behavior. */
1353
+ .zoomHint {
1354
+ position: absolute;
1355
+ left: 8px;
1356
+ bottom: 8px;
1357
+ display: inline-flex;
1358
+ align-items: center;
1359
+ gap: 5px;
1360
+ padding: 2px 10px;
1361
+ font-size: 12px;
1362
+ line-height: 20px;
1363
+ font-weight: 500;
1364
+ color: var(--dsw-alias-label-primary);
1365
+ background: var(--dsw-alias-bg-mask-1);
1366
+ border: 1px solid var(--dsw-alias-border-l2);
1367
+ border-radius: 999px;
1368
+ opacity: 0;
1369
+ transition: opacity 0.12s;
1370
+ backdrop-filter: blur(4px);
1371
+ pointer-events: none;
1372
+ }
1373
+
1374
+ .imageCard:hover .zoomHint {
1375
+ opacity: 1;
1376
+ }
1377
+
1378
+ /* --- spinner --------------------------------------------------------------------- */
1379
+
1380
+ .spinner,
1381
+ .bigSpinner {
1382
+ display: inline-block;
1383
+ flex: none;
1384
+ border-radius: 50%;
1385
+ border: 2px solid currentColor;
1386
+ border-top-color: transparent;
1387
+ animation: dshImageGenSpin 800ms linear infinite;
1388
+ }
1389
+
1390
+ .spinner {
1391
+ width: 11px;
1392
+ height: 11px;
1393
+ }
1394
+
1395
+ .bigSpinner {
1396
+ width: 30px;
1397
+ height: 30px;
1398
+ border-width: 3px;
1399
+ color: var(--dsw-alias-state-business-primary);
1400
+ margin-bottom: 6px;
1401
+ }
1402
+
1403
+ /* --- full-screen image preview (lightbox) -------------------------------------- */
1404
+
1405
+ .lightbox {
1406
+ position: fixed;
1407
+ inset: 0;
1408
+ z-index: 1000;
1409
+ display: flex;
1410
+ align-items: center;
1411
+ justify-content: center;
1412
+ padding: 24px;
1413
+ background: rgba(0, 0, 0, 0.72);
1414
+ backdrop-filter: blur(6px);
1415
+ }
1416
+
1417
+ .lightboxClose {
1418
+ position: absolute;
1419
+ top: 16px;
1420
+ right: 16px;
1421
+ display: inline-flex;
1422
+ align-items: center;
1423
+ justify-content: center;
1424
+ width: 38px;
1425
+ height: 38px;
1426
+ color: #fff;
1427
+ background: rgba(255, 255, 255, 0.14);
1428
+ border: 1px solid rgba(255, 255, 255, 0.28);
1429
+ border-radius: 50%;
1430
+ cursor: pointer;
1431
+ }
1432
+
1433
+ .lightboxClose:hover {
1434
+ background: rgba(255, 255, 255, 0.26);
1435
+ }
1436
+
1437
+ .lightboxNav {
1438
+ position: absolute;
1439
+ top: 50%;
1440
+ transform: translateY(-50%);
1441
+ display: inline-flex;
1442
+ align-items: center;
1443
+ justify-content: center;
1444
+ width: 42px;
1445
+ height: 42px;
1446
+ color: #fff;
1447
+ background: rgba(255, 255, 255, 0.14);
1448
+ border: 1px solid rgba(255, 255, 255, 0.28);
1449
+ border-radius: 50%;
1450
+ cursor: pointer;
1451
+ }
1452
+
1453
+ .lightboxNav:hover {
1454
+ background: rgba(255, 255, 255, 0.26);
1455
+ }
1456
+
1457
+ .lightboxNav[data-dir='prev'] {
1458
+ left: max(20px, calc(50% - 640px));
1459
+ }
1460
+
1461
+ .lightboxNav[data-dir='next'] {
1462
+ right: max(20px, calc(50% - 640px));
1463
+ }
1464
+
1465
+ .lightboxFigure {
1466
+ display: flex;
1467
+ flex-direction: column;
1468
+ gap: 10px;
1469
+ margin: 0;
1470
+ max-width: min(1100px, calc(100vw - 160px));
1471
+ width: min(1100px, calc(100vw - 160px));
1472
+ height: min(820px, calc(100vh - 48px));
1473
+ min-height: 0;
1474
+ }
1475
+
1476
+ .lightboxStage {
1477
+ flex: 1;
1478
+ min-height: 0;
1479
+ position: relative;
1480
+ overflow: auto;
1481
+ border-radius: 10px;
1482
+ background: rgba(255, 255, 255, 0.04);
1483
+ }
1484
+
1485
+ .lightboxScaleFrame {
1486
+ display: flex;
1487
+ align-items: center;
1488
+ justify-content: center;
1489
+ min-width: 100%;
1490
+ min-height: 100%;
1491
+ }
1492
+
1493
+ .lightboxImage {
1494
+ display: block;
1495
+ max-width: 100%;
1496
+ max-height: 100%;
1497
+ object-fit: contain;
1498
+ border-radius: 10px;
1499
+ box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
1500
+ }
1501
+
1502
+ .lightboxTools {
1503
+ display: flex;
1504
+ align-items: center;
1505
+ justify-content: center;
1506
+ gap: 6px;
1507
+ }
1508
+
1509
+ .lightboxTool,
1510
+ .lightboxZoomLevel,
1511
+ .lightboxCopy {
1512
+ display: inline-flex;
1513
+ align-items: center;
1514
+ justify-content: center;
1515
+ color: #fff;
1516
+ background: rgba(255, 255, 255, 0.14);
1517
+ border: 1px solid rgba(255, 255, 255, 0.28);
1518
+ cursor: pointer;
1519
+ }
1520
+
1521
+ .lightboxTool,
1522
+ .lightboxZoomLevel {
1523
+ height: 32px;
1524
+ }
1525
+
1526
+ .lightboxTool {
1527
+ width: 32px;
1528
+ border-radius: 50%;
1529
+ }
1530
+
1531
+ .lightboxZoomLevel {
1532
+ min-width: 58px;
1533
+ padding: 0 9px;
1534
+ border-radius: 999px;
1535
+ font: inherit;
1536
+ font-size: 12px;
1537
+ font-variant-numeric: tabular-nums;
1538
+ }
1539
+
1540
+ .lightboxTool:hover,
1541
+ .lightboxZoomLevel:hover,
1542
+ .lightboxCopy:hover {
1543
+ background: rgba(255, 255, 255, 0.26);
1544
+ }
1545
+
1546
+ .lightboxCaptionRow {
1547
+ display: flex;
1548
+ align-items: flex-start;
1549
+ gap: 8px;
1550
+ min-width: 0;
1551
+ }
1552
+
1553
+ .lightboxCaption {
1554
+ flex: 1;
1555
+ min-width: 0;
1556
+ font-size: 12px;
1557
+ line-height: 1.6;
1558
+ color: rgba(255, 255, 255, 0.9);
1559
+ display: -webkit-box;
1560
+ -webkit-line-clamp: 3;
1561
+ -webkit-box-orient: vertical;
1562
+ overflow: hidden;
1563
+ }
1564
+
1565
+ .lightboxCopy {
1566
+ flex: none;
1567
+ gap: 5px;
1568
+ min-height: 28px;
1569
+ padding: 4px 9px;
1570
+ border-radius: 999px;
1571
+ font: inherit;
1572
+ font-size: 12px;
1573
+ white-space: nowrap;
1574
+ }
1575
+
1576
+ .lightboxMeta {
1577
+ display: flex;
1578
+ align-items: center;
1579
+ justify-content: space-between;
1580
+ gap: 12px;
1581
+ }
1582
+
1583
+ .lightboxIndex {
1584
+ font-size: 12px;
1585
+ color: rgba(255, 255, 255, 0.8);
1586
+ font-variant-numeric: tabular-nums;
1587
+ }
1588
+
1589
+ .lightboxActions {
1590
+ display: inline-flex;
1591
+ align-items: center;
1592
+ gap: 8px;
1593
+ }
1594
+
1595
+ .lightboxDownload,
1596
+ .lightboxEdit {
1597
+ padding: 4px 14px;
1598
+ font: inherit;
1599
+ font-size: 12.5px;
1600
+ font-weight: 500;
1601
+ color: #fff;
1602
+ background: rgba(255, 255, 255, 0.14);
1603
+ border: 1px solid rgba(255, 255, 255, 0.28);
1604
+ border-radius: 999px;
1605
+ text-decoration: none;
1606
+ cursor: pointer;
1607
+ }
1608
+
1609
+ .lightboxDownload:hover,
1610
+ .lightboxEdit:hover {
1611
+ background: rgba(255, 255, 255, 0.26);
1612
+ }
1613
+
1614
+ .lightboxEdit {
1615
+ color: #fff;
1616
+ background: rgba(255, 255, 255, 0.14);
1617
+ border: 1px solid rgba(255, 255, 255, 0.28);
1618
+ border-radius: 999px;
1619
+ }
1620
+
1621
+ @media (max-width: 720px) {
1622
+ .lightbox {
1623
+ padding: 16px;
1624
+ }
1625
+
1626
+ .lightboxFigure {
1627
+ width: calc(100vw - 32px);
1628
+ max-width: none;
1629
+ }
1630
+
1631
+ .lightboxNav[data-dir='prev'] {
1632
+ left: 20px;
1633
+ }
1634
+
1635
+ .lightboxNav[data-dir='next'] {
1636
+ right: 20px;
1637
+ }
1638
+
1639
+ .lightboxCaptionRow,
1640
+ .lightboxMeta {
1641
+ align-items: stretch;
1642
+ flex-direction: column;
1643
+ }
1644
+
1645
+ .lightboxCopy,
1646
+ .lightboxActions {
1647
+ align-self: flex-end;
1648
+ }
1649
+ }
1650
+
1651
+ @keyframes dshImageGenSpin {
1652
+ to { transform: rotate(360deg); }
1653
+ }
1654
+
1655
+ /* Transient "added to gallery" toast, centered above the canvas bottom. */
1656
+ .galleryToast {
1657
+ position: absolute;
1658
+ left: 50%;
1659
+ bottom: 24px;
1660
+ transform: translateX(-50%);
1661
+ z-index: 30;
1662
+ display: inline-flex;
1663
+ align-items: center;
1664
+ gap: 7px;
1665
+ padding: 6px 16px;
1666
+ font-size: 13px;
1667
+ font-weight: 500;
1668
+ color: var(--dsw-alias-label-primary);
1669
+ background: var(--dsw-alias-bg-mask-1);
1670
+ border: 1px solid var(--dsw-alias-border-l2);
1671
+ border-radius: 999px;
1672
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
1673
+ backdrop-filter: blur(6px);
1674
+ pointer-events: none;
1675
+ animation: dshImageGenToastIn 160ms ease-out;
1676
+ }
1677
+
1678
+ @keyframes dshImageGenToastIn {
1679
+ from { opacity: 0; transform: translate(-50%, 6px); }
1680
+ to { opacity: 1; transform: translate(-50%, 0); }
462
1681
  }
463
1682
 
464
- .historyEmpty {
465
- flex: 1;
466
- display: flex;
467
- align-items: center;
468
- justify-content: center;
469
- padding: 20px;
470
- font-size: 12px;
471
- line-height: 1.6;
472
- text-align: center;
473
- color: var(--dsw-alias-label-tertiary);
474
- }
475
-
476
- .historyItem {
477
- display: flex;
478
- flex-direction: column;
479
- gap: 6px;
480
- padding: 8px;
481
- border: 1px solid var(--dsw-alias-border-l1);
482
- border-radius: 10px;
483
- background: var(--dsw-alias-bg-layer-2);
484
- flex: none;
485
- }
486
-
487
- .historyItem:hover {
488
- border-color: var(--dsw-alias-border-l2);
489
- }
490
-
491
- .historyItem[data-active] {
492
- border-color: var(--dsw-alias-brand-primary);
493
- }
494
-
495
- .historyMain {
496
- display: flex;
497
- gap: 8px;
498
- align-items: flex-start;
499
- padding: 0;
500
- background: transparent;
501
- border: none;
502
- font: inherit;
503
- color: inherit;
504
- text-align: left;
505
- cursor: pointer;
506
- min-width: 0;
507
- }
508
-
509
- .historyThumb {
510
- width: 52px;
511
- height: 52px;
512
- border-radius: 8px;
513
- object-fit: cover;
514
- background: var(--dsw-alias-bg-base);
515
- flex: none;
516
- }
517
-
518
- .historyThumbPlaceholder {
519
- width: 52px;
520
- height: 52px;
521
- border-radius: 8px;
522
- background: var(--dsw-alias-bg-layer-3);
523
- flex: none;
524
- }
525
-
526
- .historyInfo {
527
- flex: 1;
528
- min-width: 0;
529
- display: flex;
530
- flex-direction: column;
531
- gap: 4px;
532
- }
533
-
534
- .historyPrompt {
535
- font-size: 12px;
536
- line-height: 1.4;
537
- color: var(--dsw-alias-label-primary);
538
- display: -webkit-box;
539
- -webkit-line-clamp: 2;
540
- -webkit-box-orient: vertical;
541
- overflow: hidden;
542
- }
543
-
544
- .historyMeta {
545
- font-size: 11px;
546
- color: var(--dsw-alias-label-tertiary);
547
- white-space: nowrap;
548
- overflow: hidden;
549
- text-overflow: ellipsis;
550
- }
551
-
552
- .historyActions {
553
- display: flex;
554
- gap: 6px;
555
- justify-content: flex-end;
556
- }
557
-
558
- .historyAction {
559
- padding: 2px 8px;
560
- font: inherit;
561
- font-size: 11.5px;
562
- color: var(--dsw-alias-label-secondary);
563
- background: transparent;
564
- border: 1px solid var(--dsw-alias-border-l2);
565
- border-radius: 999px;
566
- cursor: pointer;
567
- }
568
-
569
- .historyAction:hover {
570
- color: var(--dsw-alias-label-primary);
571
- border-color: var(--dsw-alias-label-dimmed);
572
- }
573
-
574
- .historyAction[data-danger]:hover {
575
- color: var(--dsw-alias-label-error);
576
- border-color: var(--dsw-alias-label-error);
577
- }
578
-
579
- /* --- cards (system-aligned rounded group chrome) ------------------------------ */
580
-
581
- .card {
582
- display: flex;
583
- flex-direction: column;
584
- gap: 10px;
585
- padding: 12px;
586
- background: var(--dsw-alias-bg-layer-2);
587
- border: 1px solid var(--dsw-alias-border-l1);
588
- border-radius: 12px;
589
- flex: none;
590
- }
591
-
592
- /* --- mode tabs (system Pill switcher) ------------------------------------------ */
593
-
594
- .modeRow {
595
- display: flex;
596
- gap: 8px;
597
- align-items: center;
598
- }
599
-
600
- .modePill {
601
- flex: 1;
602
- justify-content: center;
603
- height: 28px;
604
- font-size: 13px;
605
- }
606
-
607
- /* --- reference image upload (edit mode) ---------------------------------------- */
608
-
609
- .uploadBox {
610
- display: flex;
611
- flex-direction: column;
612
- align-items: center;
613
- justify-content: center;
614
- gap: 6px;
615
- min-height: 128px;
616
- padding: 16px;
617
- color: var(--dsw-alias-label-secondary);
618
- background: transparent;
619
- border: 1.5px dashed var(--dsw-alias-border-l2);
620
- border-radius: 12px;
621
- cursor: pointer;
622
- font: inherit;
623
- font-size: 12.5px;
624
- text-align: center;
625
- }
626
-
627
- .uploadBox:hover {
628
- color: var(--dsw-alias-label-primary);
629
- border-color: var(--dsw-alias-label-dimmed);
630
- background: var(--dsw-alias-interactive-bg-hover);
631
- }
632
-
633
- .uploadBox:focus-visible {
634
- outline: 2px solid var(--dsw-alias-brand-primary);
635
- outline-offset: 1px;
636
- }
637
-
638
- .uploadIcon {
639
- display: inline-flex;
640
- color: var(--dsw-alias-label-tertiary);
641
- }
642
-
643
- .uploadHint {
644
- font-size: 11px;
645
- color: var(--dsw-alias-label-tertiary);
646
- }
647
-
648
- .reference {
649
- display: flex;
650
- flex-direction: column;
651
- gap: 8px;
652
- }
653
-
654
- .referenceImage {
655
- width: 100%;
656
- max-height: 176px;
657
- object-fit: contain;
658
- border-radius: 10px;
659
- background: var(--dsw-alias-bg-base);
660
- border: 1px solid var(--dsw-alias-border-l1);
661
- }
662
-
663
- .referenceActions {
664
- display: flex;
665
- gap: 8px;
666
- }
667
-
668
- .hiddenFile {
669
- display: none;
670
- }
671
-
672
- /* --- prompt -------------------------------------------------------------------- */
673
-
674
- .prompt {
675
- width: 100%;
676
- min-height: 120px;
677
- padding: 10px 12px;
678
- font-size: 13px;
679
- line-height: 1.6;
680
- color: var(--dsw-alias-label-primary);
681
- background: var(--dsw-alias-bg-layer-3);
682
- border: 1px solid var(--dsw-alias-border-l2);
683
- border-radius: 10px;
684
- outline: none;
685
- resize: vertical;
686
- font-family: inherit;
687
- box-sizing: border-box;
688
- }
689
-
690
- .prompt:focus-visible {
691
- border-color: var(--dsw-alias-brand-primary);
692
- }
693
-
694
- .prompt::placeholder {
695
- color: var(--dsw-alias-label-tertiary);
696
- }
697
-
698
- .promptFooter {
699
- display: flex;
700
- align-items: center;
701
- justify-content: space-between;
702
- gap: 8px;
703
- margin-top: -6px;
704
- }
705
-
706
- .templatesButton {
707
- display: inline-flex;
708
- align-items: center;
709
- gap: 6px;
710
- height: 26px;
711
- padding: 0 12px;
712
- border: 1px solid var(--dsw-alias-brand-primary);
713
- border-radius: 999px;
714
- background: linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, transparent));
715
- color: var(--dsw-alias-brand-primary);
716
- font-size: 12px;
717
- font-weight: 600;
718
- font-family: inherit;
719
- cursor: pointer;
720
- box-shadow: 0 1px 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);
721
- transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
722
- }
723
-
724
- .templatesButton svg {
725
- flex: none;
726
- }
727
-
728
- .templatesButton:hover {
729
- background: linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 24%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent));
730
- color: var(--dsw-alias-brand-primary);
731
- transform: translateY(-1px);
732
- box-shadow: 0 2px 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);
733
- }
734
-
735
- .templatesButton:active {
736
- transform: translateY(0);
737
- }
738
-
739
- .enhanceButton {
740
- height: 26px;
741
- margin-left: auto;
742
- padding: 0 11px;
743
- border: 1px solid var(--dsw-alias-border-l2);
744
- border-radius: 999px;
745
- color: var(--dsw-alias-label-secondary);
746
- background: var(--dsw-alias-bg-layer-2);
747
- font: inherit;
748
- font-size: 12px;
749
- cursor: pointer;
750
- }
751
-
752
- .enhanceButton:hover:not(:disabled) {
753
- color: var(--dsw-alias-brand-primary);
754
- border-color: var(--dsw-alias-brand-primary);
755
- }
756
-
757
- .enhanceButton:disabled { opacity: 0.5; cursor: default; }
758
-
759
- .promptCount {
760
- font-size: 11px;
761
- color: var(--dsw-alias-label-tertiary);
762
- font-variant-numeric: tabular-nums;
763
- }
764
-
765
- /* --- parameter groups ----------------------------------------------------------- */
766
-
767
- .paramGroup {
768
- display: flex;
769
- flex-direction: column;
770
- gap: 8px;
771
- }
772
-
773
- .paramLabel {
774
- font-size: 12px;
775
- font-weight: 600;
776
- color: var(--dsw-alias-label-secondary);
777
- }
778
-
779
- .optionRow {
780
- display: flex;
781
- gap: 6px;
782
- flex-wrap: wrap;
783
- }
784
-
785
- .optionGrid {
786
- display: grid;
787
- grid-template-columns: repeat(3, 1fr);
788
- gap: 6px;
789
- }
790
-
791
- .optionPill {
792
- justify-content: center;
793
- }
794
-
795
- .paramHint {
796
- font-size: 11px;
797
- line-height: 1.45;
798
- color: var(--dsw-alias-label-tertiary);
799
- }
800
-
801
- /* --- footer: model dropdown + generate button (fixed under the scroll) -------- */
802
-
803
- .footer {
804
- display: flex;
805
- flex-direction: column;
806
- align-items: stretch;
807
- gap: 8px;
808
- flex: none;
809
- padding: 10px 2px 0 0;
810
- border-top: 1px solid var(--dsw-alias-border-l1);
811
- }
812
-
813
- .modelWrap {
814
- display: flex;
815
- flex-direction: column;
816
- gap: 5px;
817
- min-width: 0;
818
- }
819
-
820
- .modelLabel {
821
- font-size: 12px;
822
- font-weight: 600;
823
- color: var(--dsw-alias-label-secondary);
824
- }
825
-
826
- .modelSelect {
827
- width: 100%;
828
- height: 36px;
829
- display: flex;
830
- align-items: center;
831
- justify-content: space-between;
832
- gap: 8px;
833
- padding: 0 12px;
834
- font-size: 13px;
835
- color: var(--dsw-alias-label-primary);
836
- background: var(--dsw-alias-bg-layer-2);
837
- border: 1px solid var(--dsw-alias-border-l2);
838
- border-radius: 18px;
839
- outline: none;
840
- font-family: inherit;
841
- cursor: pointer;
842
- text-align: left;
843
- }
844
-
845
- .modelSelect:focus-visible {
846
- border-color: var(--dsw-alias-brand-primary);
847
- }
848
-
849
- .modelSelect:disabled {
850
- opacity: 0.55;
851
- cursor: default;
852
- }
853
-
854
- /* Model dropdown trigger + upward-opening menu. */
855
- .modelMenu {
856
- position: relative;
857
- display: block;
858
- min-width: 0;
859
- }
860
-
861
- /* The list opens UPWARD (absolute above the trigger) so it never hides
862
- behind the footer edge below. */
863
- .modelMenuList {
864
- position: absolute;
865
- left: 0;
866
- right: 0;
867
- bottom: calc(100% + 6px);
868
- z-index: 40;
869
- display: flex;
870
- flex-direction: column;
871
- padding: 4px;
872
- background: var(--dsw-alias-bg-layer-2);
873
- border: 1px solid var(--dsw-alias-border-l2);
874
- border-radius: 12px;
875
- box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18);
876
- overflow: hidden;
877
- }
878
-
879
- .modelMenuItem {
880
- display: block;
881
- width: 100%;
882
- padding: 7px 10px;
883
- font: inherit;
884
- font-size: 13px;
885
- color: var(--dsw-alias-label-primary);
886
- background: transparent;
887
- border: none;
888
- border-radius: 8px;
889
- cursor: pointer;
890
- text-align: left;
891
- white-space: nowrap;
892
- overflow: hidden;
893
- text-overflow: ellipsis;
894
- }
895
-
896
- .modelMenuItem:hover {
897
- background: var(--dsw-alias-bg-hover);
898
- }
899
-
900
- .modelMenuItem[data-selected] {
901
- color: var(--dsw-alias-brand-primary);
902
- font-weight: 600;
903
- background: var(--dsw-alias-bg-layer-1);
904
- }
905
-
906
- .generateButton {
907
- width: 100%;
908
- }
909
-
910
- .generateInner {
911
- display: inline-flex;
912
- align-items: center;
913
- gap: 7px;
914
- }
915
-
916
- /* --- canvas states --------------------------------------------------------------- */
917
-
918
- .canvasState {
919
- flex: 1;
920
- display: flex;
921
- flex-direction: column;
922
- align-items: center;
923
- justify-content: center;
924
- gap: 8px;
925
- padding: 24px;
926
- text-align: center;
927
- color: var(--dsw-alias-label-tertiary);
928
- }
929
-
930
- .canvasStateTitle {
931
- font-size: 14px;
932
- font-weight: 600;
933
- color: var(--dsw-alias-label-secondary);
934
- }
935
-
936
- .canvasStateHint {
937
- font-size: 12px;
938
- max-width: 380px;
939
- line-height: 1.6;
940
- }
941
-
942
- .canvasEmptyIcon {
943
- display: inline-flex;
944
- margin-bottom: 4px;
945
- color: var(--dsw-alias-label-tertiary);
946
- }
947
-
948
- .canvasError {
949
- margin: 14px;
950
- padding: 10px 14px;
951
- font-size: 12.5px;
952
- line-height: 1.6;
953
- color: var(--dsw-alias-label-error);
954
- background: var(--dsw-alias-bg-layer-2);
955
- border: 1px solid var(--dsw-alias-label-error);
956
- border-radius: 10px;
957
- overflow-wrap: anywhere;
958
- flex: none;
959
- }
960
-
961
- .canvasBody {
962
- flex: 1;
963
- min-height: 0;
964
- display: flex;
965
- flex-direction: column;
966
- gap: 10px;
967
- overflow-y: auto;
968
- padding: 14px;
969
- scrollbar-width: thin;
970
- scrollbar-color: var(--dsw-alias-border-l2) transparent;
971
- }
972
-
973
- .canvasBody::-webkit-scrollbar {
974
- width: 8px;
975
- }
976
-
977
- .canvasBody::-webkit-scrollbar-thumb {
978
- background: var(--dsw-alias-border-l2);
979
- border-radius: 999px;
980
- }
981
-
982
- .canvasMeta {
983
- flex: none;
984
- display: flex;
985
- align-items: center;
986
- gap: 8px;
987
- font-size: 12px;
988
- color: var(--dsw-alias-label-tertiary);
989
- }
990
-
991
- .canvasHistoryTag {
992
- padding: 1px 8px;
993
- font-size: 11px;
994
- color: var(--dsw-alias-label-secondary);
995
- background: var(--dsw-alias-bg-layer-2);
996
- border: 1px solid var(--dsw-alias-border-l2);
997
- border-radius: 999px;
998
- white-space: nowrap;
999
- }
1000
-
1001
- /* --- result grid ----------------------------------------------------------------- */
1002
-
1003
- .grid {
1004
- display: grid;
1005
- flex: 1;
1006
- min-height: 0;
1007
- gap: 14px;
1008
- grid-template-columns: repeat(2, minmax(0, 1fr));
1009
- grid-template-rows: repeat(2, minmax(0, 1fr));
1010
- }
1011
-
1012
- .grid[data-count='1'] .imageCard {
1013
- grid-area: 1 / 1 / 3 / 3;
1014
- }
1015
-
1016
- .imageCard {
1017
- position: relative;
1018
- display: flex;
1019
- flex-direction: column;
1020
- margin: 0;
1021
- border: 1px solid var(--dsw-alias-border-l1);
1022
- border-radius: 12px;
1023
- overflow: hidden;
1024
- background: var(--dsw-alias-bg-layer-2);
1025
- cursor: zoom-in;
1026
- min-height: 0;
1027
- }
1028
-
1029
- .imageCard:focus-visible {
1030
- outline: 2px solid var(--dsw-alias-brand-primary);
1031
- outline-offset: 1px;
1032
- }
1033
-
1034
- .image {
1035
- display: block;
1036
- flex: 1;
1037
- min-height: 0;
1038
- width: 100%;
1039
- object-fit: cover;
1040
- background: var(--dsw-alias-bg-base);
1041
- }
1042
-
1043
- .imageCaption {
1044
- padding: 7px 10px;
1045
- font-size: 11px;
1046
- line-height: 1.5;
1047
- color: var(--dsw-alias-label-tertiary);
1048
- white-space: nowrap;
1049
- overflow: hidden;
1050
- text-overflow: ellipsis;
1051
- border-top: 1px solid var(--dsw-alias-border-l1);
1052
- }
1053
-
1054
- .download {
1055
- position: absolute;
1056
- top: 8px;
1057
- right: 8px;
1058
- padding: 2px 10px;
1059
- font-size: 12px;
1060
- line-height: 20px;
1061
- font-weight: 500;
1062
- color: var(--dsw-alias-label-primary);
1063
- background: var(--dsw-alias-bg-mask-1);
1064
- border: 1px solid var(--dsw-alias-border-l2);
1065
- border-radius: 999px;
1066
- text-decoration: none;
1067
- opacity: 0;
1068
- transition: opacity 0.12s;
1069
- backdrop-filter: blur(4px);
1070
- }
1071
-
1072
- .imageCard:hover .download {
1073
- opacity: 1;
1074
- }
1075
-
1076
- .download:hover {
1077
- background: var(--dsw-alias-bg-base);
1078
- }
1079
-
1080
- /* Add-to-gallery pill (top-left, mirrors .download; shows on card hover). */
1081
- .galleryAdd {
1082
- position: absolute;
1083
- top: 8px;
1084
- left: 8px;
1085
- display: inline-flex;
1086
- align-items: center;
1087
- gap: 5px;
1088
- padding: 2px 10px;
1089
- font: inherit;
1090
- font-size: 12px;
1091
- line-height: 20px;
1092
- font-weight: 500;
1093
- color: var(--dsw-alias-label-primary);
1094
- background: var(--dsw-alias-bg-mask-1);
1095
- border: 1px solid var(--dsw-alias-border-l2);
1096
- border-radius: 999px;
1097
- cursor: pointer;
1098
- opacity: 0;
1099
- transition: opacity 0.12s;
1100
- backdrop-filter: blur(4px);
1101
- }
1102
-
1103
- .imageCard:hover .galleryAdd {
1104
- opacity: 1;
1105
- }
1106
-
1107
- .galleryAdd:hover {
1108
- background: var(--dsw-alias-bg-base);
1109
- }
1110
-
1111
- .galleryAdd:disabled {
1112
- opacity: 0.4;
1113
- cursor: default;
1114
- }
1115
-
1116
- /* Hover hint for the click-to-zoom behavior. */
1117
- .zoomHint {
1118
- position: absolute;
1119
- left: 8px;
1120
- bottom: 8px;
1121
- display: inline-flex;
1122
- align-items: center;
1123
- gap: 5px;
1124
- padding: 2px 10px;
1125
- font-size: 12px;
1126
- line-height: 20px;
1127
- font-weight: 500;
1128
- color: var(--dsw-alias-label-primary);
1129
- background: var(--dsw-alias-bg-mask-1);
1130
- border: 1px solid var(--dsw-alias-border-l2);
1131
- border-radius: 999px;
1132
- opacity: 0;
1133
- transition: opacity 0.12s;
1134
- backdrop-filter: blur(4px);
1135
- pointer-events: none;
1136
- }
1137
-
1138
- .imageCard:hover .zoomHint {
1139
- opacity: 1;
1140
- }
1141
-
1142
- /* --- spinner --------------------------------------------------------------------- */
1143
-
1144
- .spinner,
1145
- .bigSpinner {
1146
- display: inline-block;
1147
- flex: none;
1148
- border-radius: 50%;
1149
- border: 2px solid currentColor;
1150
- border-top-color: transparent;
1151
- animation: dshImageGenSpin 800ms linear infinite;
1152
- }
1153
-
1154
- .spinner {
1155
- width: 11px;
1156
- height: 11px;
1157
- }
1158
-
1159
- .bigSpinner {
1160
- width: 30px;
1161
- height: 30px;
1162
- border-width: 3px;
1163
- color: var(--dsw-alias-state-business-primary);
1164
- margin-bottom: 6px;
1165
- }
1166
-
1167
- /* --- full-screen image preview (lightbox) -------------------------------------- */
1168
-
1169
- .lightbox {
1170
- position: fixed;
1171
- inset: 0;
1172
- z-index: 1000;
1173
- display: flex;
1174
- align-items: center;
1175
- justify-content: center;
1176
- padding: 24px;
1177
- background: rgba(0, 0, 0, 0.72);
1178
- backdrop-filter: blur(6px);
1179
- }
1180
-
1181
- .lightboxClose {
1182
- position: absolute;
1183
- top: 16px;
1184
- right: 16px;
1185
- display: inline-flex;
1186
- align-items: center;
1187
- justify-content: center;
1188
- width: 38px;
1189
- height: 38px;
1190
- color: #fff;
1191
- background: rgba(255, 255, 255, 0.14);
1192
- border: 1px solid rgba(255, 255, 255, 0.28);
1193
- border-radius: 50%;
1194
- cursor: pointer;
1195
- }
1196
-
1197
- .lightboxClose:hover {
1198
- background: rgba(255, 255, 255, 0.26);
1199
- }
1200
-
1201
- .lightboxNav {
1202
- position: absolute;
1203
- top: 50%;
1204
- transform: translateY(-50%);
1205
- display: inline-flex;
1206
- align-items: center;
1207
- justify-content: center;
1208
- width: 42px;
1209
- height: 42px;
1210
- color: #fff;
1211
- background: rgba(255, 255, 255, 0.14);
1212
- border: 1px solid rgba(255, 255, 255, 0.28);
1213
- border-radius: 50%;
1214
- cursor: pointer;
1215
- }
1216
-
1217
- .lightboxNav:hover {
1218
- background: rgba(255, 255, 255, 0.26);
1219
- }
1220
-
1221
- .lightboxNav[data-dir='prev'] {
1222
- left: max(20px, calc(50% - 640px));
1223
- }
1224
-
1225
- .lightboxNav[data-dir='next'] {
1226
- right: max(20px, calc(50% - 640px));
1227
- }
1228
-
1229
- .lightboxFigure {
1230
- display: flex;
1231
- flex-direction: column;
1232
- gap: 10px;
1233
- margin: 0;
1234
- max-width: min(1100px, calc(100vw - 160px));
1235
- width: min(1100px, calc(100vw - 160px));
1236
- height: min(820px, calc(100vh - 48px));
1237
- min-height: 0;
1238
- }
1239
-
1240
- .lightboxStage {
1241
- flex: 1;
1242
- min-height: 0;
1243
- position: relative;
1244
- overflow: auto;
1245
- border-radius: 10px;
1246
- background: rgba(255, 255, 255, 0.04);
1247
- }
1248
-
1249
- .lightboxScaleFrame {
1250
- display: flex;
1251
- align-items: center;
1252
- justify-content: center;
1253
- min-width: 100%;
1254
- min-height: 100%;
1255
- }
1256
-
1257
- .lightboxImage {
1258
- display: block;
1259
- max-width: 100%;
1260
- max-height: 100%;
1261
- object-fit: contain;
1262
- border-radius: 10px;
1263
- box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
1264
- }
1265
-
1266
- .lightboxTools {
1267
- display: flex;
1268
- align-items: center;
1269
- justify-content: center;
1270
- gap: 6px;
1271
- }
1272
-
1273
- .lightboxTool,
1274
- .lightboxZoomLevel,
1275
- .lightboxCopy {
1276
- display: inline-flex;
1277
- align-items: center;
1278
- justify-content: center;
1279
- color: #fff;
1280
- background: rgba(255, 255, 255, 0.14);
1281
- border: 1px solid rgba(255, 255, 255, 0.28);
1282
- cursor: pointer;
1283
- }
1284
-
1285
- .lightboxTool,
1286
- .lightboxZoomLevel {
1287
- height: 32px;
1288
- }
1289
-
1290
- .lightboxTool {
1291
- width: 32px;
1292
- border-radius: 50%;
1293
- }
1294
-
1295
- .lightboxZoomLevel {
1296
- min-width: 58px;
1297
- padding: 0 9px;
1298
- border-radius: 999px;
1299
- font: inherit;
1300
- font-size: 12px;
1301
- font-variant-numeric: tabular-nums;
1302
- }
1303
-
1304
- .lightboxTool:hover,
1305
- .lightboxZoomLevel:hover,
1306
- .lightboxCopy:hover {
1307
- background: rgba(255, 255, 255, 0.26);
1308
- }
1309
-
1310
- .lightboxCaptionRow {
1311
- display: flex;
1312
- align-items: flex-start;
1313
- gap: 8px;
1314
- min-width: 0;
1315
- }
1316
-
1317
- .lightboxCaption {
1318
- flex: 1;
1319
- min-width: 0;
1320
- font-size: 12px;
1321
- line-height: 1.6;
1322
- color: rgba(255, 255, 255, 0.9);
1323
- display: -webkit-box;
1324
- -webkit-line-clamp: 3;
1325
- -webkit-box-orient: vertical;
1326
- overflow: hidden;
1327
- }
1328
-
1329
- .lightboxCopy {
1330
- flex: none;
1331
- gap: 5px;
1332
- min-height: 28px;
1333
- padding: 4px 9px;
1334
- border-radius: 999px;
1335
- font: inherit;
1336
- font-size: 12px;
1337
- white-space: nowrap;
1338
- }
1339
-
1340
- .lightboxMeta {
1341
- display: flex;
1342
- align-items: center;
1343
- justify-content: space-between;
1344
- gap: 12px;
1345
- }
1346
-
1347
- .lightboxIndex {
1348
- font-size: 12px;
1349
- color: rgba(255, 255, 255, 0.8);
1350
- font-variant-numeric: tabular-nums;
1351
- }
1352
-
1353
- .lightboxActions {
1354
- display: inline-flex;
1355
- align-items: center;
1356
- gap: 8px;
1357
- }
1358
-
1359
- .lightboxDownload,
1360
- .lightboxEdit {
1361
- padding: 4px 14px;
1362
- font: inherit;
1363
- font-size: 12.5px;
1364
- font-weight: 500;
1365
- color: #fff;
1366
- background: rgba(255, 255, 255, 0.14);
1367
- border: 1px solid rgba(255, 255, 255, 0.28);
1368
- border-radius: 999px;
1369
- text-decoration: none;
1370
- cursor: pointer;
1371
- }
1372
-
1373
- .lightboxDownload:hover,
1374
- .lightboxEdit:hover {
1375
- background: rgba(255, 255, 255, 0.26);
1376
- }
1377
-
1378
- .lightboxEdit {
1379
- color: #fff;
1380
- background: rgba(255, 255, 255, 0.14);
1381
- border: 1px solid rgba(255, 255, 255, 0.28);
1382
- border-radius: 999px;
1383
- }
1384
-
1385
- @media (max-width: 720px) {
1386
- .lightbox {
1387
- padding: 16px;
1388
- }
1389
-
1390
- .lightboxFigure {
1391
- width: calc(100vw - 32px);
1392
- max-width: none;
1393
- }
1394
-
1395
- .lightboxNav[data-dir='prev'] {
1396
- left: 20px;
1397
- }
1398
-
1399
- .lightboxNav[data-dir='next'] {
1400
- right: 20px;
1401
- }
1402
-
1403
- .lightboxCaptionRow,
1404
- .lightboxMeta {
1405
- align-items: stretch;
1406
- flex-direction: column;
1407
- }
1408
-
1409
- .lightboxCopy,
1410
- .lightboxActions {
1411
- align-self: flex-end;
1412
- }
1413
- }
1414
-
1415
- @keyframes dshImageGenSpin {
1416
- to { transform: rotate(360deg); }
1417
- }
1418
-
1419
- /* Transient "added to gallery" toast, centered above the canvas bottom. */
1420
- .galleryToast {
1683
+ .conversationToast {
1421
1684
  position: absolute;
1422
1685
  left: 50%;
1423
1686
  bottom: 24px;
1424
- transform: translateX(-50%);
1425
1687
  z-index: 30;
1426
1688
  display: inline-flex;
1427
1689
  align-items: center;
1428
1690
  gap: 7px;
1691
+ max-width: calc(100% - 32px);
1429
1692
  padding: 6px 16px;
1430
- font-size: 13px;
1431
- font-weight: 500;
1432
- color: var(--dsw-alias-label-primary);
1433
- background: var(--dsw-alias-bg-mask-1);
1434
1693
  border: 1px solid var(--dsw-alias-border-l2);
1435
1694
  border-radius: 999px;
1436
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
1437
- backdrop-filter: blur(6px);
1695
+ color: var(--dsw-alias-label-primary);
1696
+ background: var(--dsw-alias-bg-mask-1);
1697
+ box-shadow: 0 8px 24px rgb(0 0 0 / 22%);
1698
+ font-size: 13px;
1699
+ font-weight: 500;
1438
1700
  pointer-events: none;
1701
+ transform: translateX(-50%);
1439
1702
  animation: dshImageGenToastIn 160ms ease-out;
1703
+ backdrop-filter: blur(6px);
1440
1704
  }
1441
-
1442
- @keyframes dshImageGenToastIn {
1443
- from { opacity: 0; transform: translate(-50%, 6px); }
1444
- to { opacity: 1; transform: translate(-50%, 0); }
1445
- }
1446
-
1447
- @media (prefers-reduced-motion: reduce) {
1448
- .download, .spinner, .bigSpinner {
1449
- transition: none;
1450
- animation-duration: 1.5s;
1451
- }
1452
- }
1453
-
1454
- /* --- gallery workspace -------------------------------------------------------- */
1455
- .config[data-gallery='true'] .configScroll > *:not(:first-child),
1456
- .config[data-gallery='true'] .footer,
1457
- .canvas[data-gallery='true'] > .canvasState,
1458
- .canvas[data-gallery='true'] > .canvasError,
1459
- .canvas[data-gallery='true'] > .canvasBody,
1460
- .studio:has(.config[data-gallery='true']) > .history { display: none; }
1461
- .config[data-gallery='true'] .configScroll { display: flex; flex: none; overflow: visible; order: 1; }
1462
- .config[data-gallery='true'] .galleryFilters { order: 2; flex: 1; min-height: 0; }
1463
- .galleryFilters { padding: 18px 14px; overflow-y: auto; overflow-x: hidden; }
1464
- .galleryFilterHeading { margin: 0 4px 10px; color: var(--dsw-alias-label-tertiary); font-size: 12px; font-weight: 600; }
1465
- .galleryFilter { display: flex; align-items: center; justify-content: space-between; width: 100%; min-height: 34px; padding: 0 10px; border: 0; border-radius: 9px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; text-align: left; }
1466
- .galleryFilter:hover, .galleryFilter[data-active] { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent); }
1467
- .galleryFilterCount { min-width: 20px; padding: 1px 6px; border-radius: 999px; color: var(--dsw-alias-label-tertiary); background: var(--dsw-alias-bg-layer-2); font-size: 11px; text-align: center; }
1468
- .galleryFilterDivider { height: 1px; margin: 18px 4px; background: var(--dsw-alias-border-l1); }
1469
- .galleryRatioList { display: flex; flex-wrap: wrap; gap: 6px; }
1470
- .galleryRatio { padding: 6px 10px; border: 0; border-radius: 999px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font-size: 12px; }
1471
- .galleryRatio[data-active] { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 13%, transparent); }
1472
- .galleryTagFilterList { display: flex; flex-wrap: wrap; gap: 6px; }
1473
- .galleryTagFilter { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 100%; min-height: 27px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font: inherit; font-size: 11px; }
1474
- .galleryTagFilter span:first-child { overflow: hidden; max-width: 112px; text-overflow: ellipsis; white-space: nowrap; }
1475
- .galleryTagFilter span:last-child { color: var(--dsw-alias-label-tertiary); font-size: 10px; }
1476
- .galleryTagFilter:hover, .galleryTagFilter[data-active] { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent); }
1477
- .galleryFilterNote { margin: 20px 4px 0; color: var(--dsw-alias-label-quaternary); font-size: 11px; line-height: 1.5; }
1478
- .galleryWorkspace { position: absolute; inset: 0; display: flex; width: 100%; height: 100%; min-width: 0; min-height: 0; flex-direction: column; overflow: hidden; padding: 22px 24px 26px; box-sizing: border-box; }
1479
- .galleryToolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex: none; min-width: 0; margin-bottom: 18px; }
1480
- .galleryHeading { display: inline; margin: 0; color: var(--dsw-alias-label-primary); font-size: 20px; font-weight: 700; }
1481
- .galleryCount { margin-left: 8px; color: var(--dsw-alias-label-tertiary); font-size: 13px; }
1482
- .galleryToolbarActions { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
1483
- .gallerySelectMode, .galleryBulkButton, .gallerySelectionClear { min-height: 30px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 7px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); cursor: pointer; font: inherit; font-size: 12px; }
1484
- .gallerySelectMode:hover, .gallerySelectMode[data-active], .galleryBulkButton:hover:not(:disabled) { color: var(--dsw-alias-brand-primary); border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 38%, var(--dsw-alias-border-l1)); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent); }
1485
- .galleryBulkButton:disabled { cursor: not-allowed; opacity: .45; }
1486
- .gallerySelectionBar { display: flex; align-items: center; gap: 10px; flex: none; min-width: 0; margin: -4px 0 16px; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 35%, var(--dsw-alias-border-l1)); border-radius: 9px; background: color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, var(--dsw-alias-bg-layer-1)); }
1487
- .gallerySelectionBar strong { flex: none; color: var(--dsw-alias-brand-primary); font-size: 12px; }
1488
- .gallerySelectionClear { margin-left: auto; }
1489
- .gallerySelectionClear:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }
1490
- .galleryTagInput, .gallerySearch { min-width: 0; height: 30px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 7px; outline: none; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1); font: inherit; font-size: 12px; }
1491
- .galleryTagInput { flex: 1 1 190px; }
1492
- .galleryTagInput:focus, .gallerySearch:focus { border-color: var(--dsw-alias-brand-primary); }
1493
- .galleryViewToggle { display: flex; padding: 3px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 9px; background: var(--dsw-alias-bg-layer-1); }
1494
- .galleryViewToggle button, .gallerySort, .galleryClear { min-height: 30px; padding: 0 10px; border: 0; border-radius: 7px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; font: inherit; font-size: 12px; }
1495
- .galleryViewToggle button[data-active], .galleryViewToggle button:hover, .gallerySort:hover, .galleryClear:hover { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent); }
1496
- .gallerySort { border: 1px solid var(--dsw-alias-border-l1); background: var(--dsw-alias-bg-layer-1); }
1497
- .galleryClear { border: 1px solid var(--dsw-alias-border-l1); }
1498
- .compareControl { display: flex; flex-direction: column; gap: 6px; margin: 0 0 10px; }
1499
- .compareToggle, .compareModelChoices label { display: flex; align-items: center; gap: 6px; color: var(--dsw-alias-label-secondary); font-size: 12px; cursor: pointer; }
1500
- .compareToggle input, .compareModelChoices input { accent-color: var(--dsw-alias-brand-primary); }
1501
- .compareModelChoices { display: flex; flex-wrap: wrap; gap: 6px; }
1502
- .compareModelChoices label { padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 5px; font-size: 10px; }
1503
- .comparisonBoard { position: absolute; z-index: 4; top: 126px; right: 14px; bottom: 14px; left: 14px; display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; background: var(--dsw-alias-bg-layer-1); box-shadow: 0 8px 24px rgb(0 0 0 / 12%); }
1504
- .comparisonBoard > header { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid var(--dsw-alias-border-l1); }
1505
- .comparisonBoard > header div { display: flex; align-items: baseline; gap: 7px; }
1506
- .comparisonBoard > header strong { color: var(--dsw-alias-label-primary); font-size: 13px; }
1507
- .comparisonBoard > header span { color: var(--dsw-alias-label-tertiary); font-size: 11px; }
1508
- .comparisonBoard > header button { min-height: 28px; padding: 0 9px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 5px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font: inherit; font-size: 11px; }
1509
- .comparisonGrid { display: grid; flex: 1; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; overflow: auto; padding: 12px; }
1510
- .comparisonGrid article { display: flex; min-width: 0; flex-direction: column; gap: 7px; }
1511
- .comparisonGrid article > strong { color: var(--dsw-alias-label-primary); font-size: 12px; }
1512
- .comparisonGrid article > span { display: grid; min-height: 160px; place-items: center; color: var(--dsw-alias-label-tertiary); background: var(--dsw-alias-bg-layer-2); font-size: 12px; }
1513
- .comparisonGrid img { display: block; width: 100%; min-height: 160px; max-height: calc(100vh - 260px); object-fit: contain; background: var(--dsw-alias-bg-base); }
1514
- .comparisonFullscreen { position: fixed; z-index: 1200; inset: 0; overflow: auto; padding: 54px 24px 24px; background: rgb(0 0 0 / 92%); }
1515
- .comparisonFullscreenGrid { display: grid; min-height: 100%; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); align-items: start; gap: 18px; }
1516
- .comparisonFullscreen figure { min-width: 0; margin: 0; }
1517
- .comparisonFullscreen figcaption { margin-bottom: 8px; color: #fff; font-size: 13px; font-weight: 600; }
1518
- .comparisonFullscreen img { display: block; width: 100%; margin-bottom: 10px; background: #111; }
1519
- .galleryMasonry { display: grid; flex: 1 1 auto; width: 100%; height: 0; max-width: 100%; min-width: 0; min-height: 0; box-sizing: border-box; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: max-content; align-content: start; gap: 16px; overflow-y: scroll; overflow-x: hidden; overscroll-behavior: contain; padding: 2px 8px 16px 2px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2) transparent; }
1520
- .galleryMasonry::-webkit-scrollbar { width: 8px; }
1521
- .galleryMasonry::-webkit-scrollbar-thumb { background: var(--dsw-alias-border-l2); border-radius: 999px; }
1522
- .galleryCard { position: relative; display: block; width: 100%; margin: 0; overflow: hidden; border: 1px solid var(--dsw-alias-border-l1); border-radius: 14px; background: var(--dsw-alias-bg-layer-1); box-shadow: 0 5px 18px rgb(24 32 54 / 7%); }
1523
- .galleryCard[data-selected] { border-color: var(--dsw-alias-brand-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent), 0 5px 18px rgb(24 32 54 / 7%); }
1524
- .gallerySelect { position: absolute; z-index: 2; top: 9px; right: 9px; display: grid; width: 26px; height: 26px; place-items: center; border: 1px solid rgb(255 255 255 / 75%); border-radius: 7px; background: rgb(0 0 0 / 58%); cursor: pointer; }
1525
- .gallerySelect input { width: 16px; height: 16px; margin: 0; accent-color: var(--dsw-alias-brand-primary); cursor: pointer; }
1526
- .galleryImageButton { position: relative; display: block; width: 100%; padding: 0; border: 0; background: var(--dsw-alias-bg-base); cursor: zoom-in; }
1527
- .galleryImageButton[data-selecting] { cursor: pointer; }
1528
- .galleryImage { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
1529
- .galleryMasonry[data-view='masonry'] .galleryCard:nth-child(3n + 1) .galleryImage { aspect-ratio: 4 / 5; }
1530
- .galleryMasonry[data-view='masonry'] .galleryCard:nth-child(3n + 2) .galleryImage { aspect-ratio: 4 / 3; }
1531
- .galleryMasonry[data-view='masonry'] .galleryCard:nth-child(3n) .galleryImage { aspect-ratio: 3 / 4; }
1532
- .galleryBadge { position: absolute; top: 10px; left: 10px; padding: 4px 9px; border-radius: 999px; color: #fff; background: rgb(18 23 36 / 76%); font-size: 11px; backdrop-filter: blur(4px); }
1533
- .galleryCardFooter { display: flex; align-items: center; gap: 9px; min-width: 0; padding: 10px 12px; }
1534
- .galleryAvatar { display: grid; flex: none; width: 27px; height: 27px; place-items: center; border-radius: 50%; color: #fff; background: var(--dsw-alias-brand-primary); font-size: 12px; font-weight: 700; }
1535
- .galleryCardInfo { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 2px; }
1536
- .galleryCardInfo strong, .galleryCardInfo small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1537
- .galleryCardInfo strong { color: var(--dsw-alias-label-primary); font-size: 12px; }
1538
- .galleryCardInfo small { color: var(--dsw-alias-label-tertiary); font-size: 10px; }
1539
- .galleryTags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
1540
- .galleryTags button { overflow: hidden; max-width: 96px; min-height: 19px; padding: 1px 6px; border: 0; border-radius: 4px; color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent); cursor: pointer; font: inherit; font-size: 10px; line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; }
1541
- .galleryTags button:hover { background: color-mix(in srgb, var(--dsw-alias-brand-primary) 17%, transparent); }
1542
- .galleryTags .galleryTagEdit { flex: none; color: var(--dsw-alias-label-tertiary); background: transparent; }
1543
- .galleryTagEditor { display: flex; align-items: center; gap: 6px; padding: 0 12px 10px 48px; }
1544
- .galleryTagEditor input { min-width: 0; flex: 1; height: 27px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; outline: none; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); font: inherit; font-size: 11px; }
1545
- .galleryTagEditor input:focus { border-color: var(--dsw-alias-brand-primary); }
1546
- .galleryTagEditor button { height: 27px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); cursor: pointer; font: inherit; font-size: 11px; }
1547
- .galleryTagEditor button[type='submit'] { color: var(--dsw-alias-brand-primary); }
1548
- .galleryRemove { flex: none; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%; color: var(--dsw-alias-label-tertiary); background: transparent; cursor: pointer; font-size: 18px; }
1549
- .galleryRemove:hover { color: var(--dsw-alias-state-error); background: var(--dsw-alias-bg-layer-2); }
1550
-
1551
- @media (max-width: 1100px) {
1552
- .galleryMasonry { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1553
- }
1554
-
1705
+
1706
+ @media (prefers-reduced-motion: reduce) {
1707
+ .download, .spinner, .bigSpinner {
1708
+ transition: none;
1709
+ animation-duration: 1.5s;
1710
+ }
1711
+ }
1712
+
1713
+ /* --- gallery workspace -------------------------------------------------------- */
1714
+ .config[data-gallery='true'] .configScroll > *:not(:first-child),
1715
+ .config[data-gallery='true'] .footer,
1716
+ .canvas[data-gallery='true'] > .canvasState,
1717
+ .canvas[data-gallery='true'] > .canvasError,
1718
+ .canvas[data-gallery='true'] > .canvasBody,
1719
+ .studio:has(.config[data-gallery='true']) > .history { display: none; }
1720
+ .config[data-gallery='true'] .configScroll { display: flex; flex: none; overflow: visible; order: 1; }
1721
+ .config[data-gallery='true'] .galleryFilters { order: 2; flex: 1; min-height: 0; }
1722
+ .galleryFilters { padding: 18px 14px; overflow-y: auto; overflow-x: hidden; }
1723
+ .galleryFilterHeading { margin: 0 4px 10px; color: var(--dsw-alias-label-tertiary); font-size: 12px; font-weight: 600; }
1724
+ .galleryFilter { display: flex; align-items: center; justify-content: space-between; width: 100%; min-height: 34px; padding: 0 10px; border: 0; border-radius: 9px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; text-align: left; }
1725
+ .galleryFilter:hover, .galleryFilter[data-active] { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent); }
1726
+ .galleryFilterCount { min-width: 20px; padding: 1px 6px; border-radius: 999px; color: var(--dsw-alias-label-tertiary); background: var(--dsw-alias-bg-layer-2); font-size: 11px; text-align: center; }
1727
+ .galleryFilterDivider { height: 1px; margin: 18px 4px; background: var(--dsw-alias-border-l1); }
1728
+ .galleryRatioList { display: flex; flex-wrap: wrap; gap: 6px; }
1729
+ .galleryRatio { padding: 6px 10px; border: 0; border-radius: 999px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font-size: 12px; }
1730
+ .galleryRatio[data-active] { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 13%, transparent); }
1731
+ .galleryTagFilterList { display: flex; flex-wrap: wrap; gap: 6px; }
1732
+ .galleryTagFilter { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 100%; min-height: 27px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font: inherit; font-size: 11px; }
1733
+ .galleryTagFilter span:first-child { overflow: hidden; max-width: 112px; text-overflow: ellipsis; white-space: nowrap; }
1734
+ .galleryTagFilter span:last-child { color: var(--dsw-alias-label-tertiary); font-size: 10px; }
1735
+ .galleryTagFilter:hover, .galleryTagFilter[data-active] { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent); }
1736
+ .galleryFilterNote { margin: 20px 4px 0; color: var(--dsw-alias-label-quaternary); font-size: 11px; line-height: 1.5; }
1737
+ .galleryWorkspace { position: absolute; inset: 0; display: flex; width: 100%; height: 100%; min-width: 0; min-height: 0; flex-direction: column; overflow: hidden; padding: 22px 24px 26px; box-sizing: border-box; }
1738
+ .galleryToolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex: none; min-width: 0; margin-bottom: 18px; }
1739
+ .galleryHeading { display: inline; margin: 0; color: var(--dsw-alias-label-primary); font-size: 20px; font-weight: 700; }
1740
+ .galleryCount { margin-left: 8px; color: var(--dsw-alias-label-tertiary); font-size: 13px; }
1741
+ .galleryToolbarActions { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
1742
+ .gallerySelectMode, .galleryBulkButton, .gallerySelectionClear { min-height: 30px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 7px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); cursor: pointer; font: inherit; font-size: 12px; }
1743
+ .gallerySelectMode:hover, .gallerySelectMode[data-active], .galleryBulkButton:hover:not(:disabled) { color: var(--dsw-alias-brand-primary); border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 38%, var(--dsw-alias-border-l1)); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent); }
1744
+ .galleryBulkButton:disabled { cursor: not-allowed; opacity: .45; }
1745
+ .gallerySelectionBar { display: flex; align-items: center; gap: 10px; flex: none; min-width: 0; margin: -4px 0 16px; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 35%, var(--dsw-alias-border-l1)); border-radius: 9px; background: color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, var(--dsw-alias-bg-layer-1)); }
1746
+ .gallerySelectionBar strong { flex: none; color: var(--dsw-alias-brand-primary); font-size: 12px; }
1747
+ .gallerySelectionClear { margin-left: auto; }
1748
+ .gallerySelectionClear:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }
1749
+ .galleryTagInput, .gallerySearch { min-width: 0; height: 30px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 7px; outline: none; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1); font: inherit; font-size: 12px; }
1750
+ .galleryTagInput { flex: 1 1 190px; }
1751
+ .galleryTagInput:focus, .gallerySearch:focus { border-color: var(--dsw-alias-brand-primary); }
1752
+ .galleryViewToggle { display: flex; padding: 3px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 9px; background: var(--dsw-alias-bg-layer-1); }
1753
+ .galleryViewToggle button, .gallerySort, .galleryClear { min-height: 30px; padding: 0 10px; border: 0; border-radius: 7px; color: var(--dsw-alias-label-secondary); background: transparent; cursor: pointer; font: inherit; font-size: 12px; }
1754
+ .galleryViewToggle button[data-active], .galleryViewToggle button:hover, .gallerySort:hover, .galleryClear:hover { color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent); }
1755
+ .gallerySort { border: 1px solid var(--dsw-alias-border-l1); background: var(--dsw-alias-bg-layer-1); }
1756
+ .galleryClear { border: 1px solid var(--dsw-alias-border-l1); }
1757
+ .compareControl { display: flex; flex-direction: column; gap: 6px; margin: 0 0 10px; }
1758
+ .compareToggle, .compareModelChoices label { display: flex; align-items: center; gap: 6px; color: var(--dsw-alias-label-secondary); font-size: 12px; cursor: pointer; }
1759
+ .compareToggle input, .compareModelChoices input { accent-color: var(--dsw-alias-brand-primary); }
1760
+ .compareModelChoices { display: flex; flex-wrap: wrap; gap: 6px; }
1761
+ .compareModelChoices label { padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 5px; font-size: 10px; }
1762
+ .comparisonBoard { position: absolute; z-index: 4; top: 14px; right: 14px; bottom: 14px; left: 14px; display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; background: var(--dsw-alias-bg-layer-1); box-shadow: 0 8px 24px rgb(0 0 0 / 12%); }
1763
+ .comparisonBoard > header { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid var(--dsw-alias-border-l1); }
1764
+ .comparisonBoard > header div { display: flex; align-items: baseline; gap: 7px; }
1765
+ .comparisonBoard > header strong { color: var(--dsw-alias-label-primary); font-size: 13px; }
1766
+ .comparisonBoard > header span { color: var(--dsw-alias-label-tertiary); font-size: 11px; }
1767
+ .comparisonBoard > header button { min-height: 28px; padding: 0 9px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 5px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); cursor: pointer; font: inherit; font-size: 11px; }
1768
+ .comparisonGrid { display: grid; flex: 1; min-height: 0; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); grid-template-rows: minmax(0, 1fr); gap: 12px; overflow: auto; padding: 12px; }
1769
+ .comparisonGrid article { display: flex; height: 100%; min-width: 0; min-height: 0; flex-direction: column; gap: 7px; }
1770
+ .comparisonGrid article > strong { color: var(--dsw-alias-label-primary); font-size: 12px; }
1771
+ .comparisonImageButton { display: flex; width: 100%; min-height: 0; flex: 1; padding: 0; overflow: hidden; border: 0; cursor: zoom-in; background: var(--dsw-alias-bg-base); }
1772
+ .comparisonImageButton:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -2px; }
1773
+ .comparisonGrid article > span { display: grid; flex: 1; min-height: 0; place-items: center; color: var(--dsw-alias-label-tertiary); background: var(--dsw-alias-bg-layer-2); font-size: 12px; }
1774
+ .comparisonGrid img { display: block; width: 100%; height: 100%; min-height: 0; max-height: none; flex: 1; object-fit: contain; background: var(--dsw-alias-bg-base); }
1775
+ .comparisonFullscreen { position: fixed; z-index: 1200; inset: 0; overflow: auto; padding: 54px 24px 24px; background: rgb(0 0 0 / 92%); }
1776
+ .comparisonFullscreenGrid { display: grid; min-height: 100%; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); align-items: start; gap: 18px; }
1777
+ .comparisonFullscreen figure { min-width: 0; margin: 0; }
1778
+ .comparisonFullscreen figcaption { margin-bottom: 8px; color: #fff; font-size: 13px; font-weight: 600; }
1779
+ .comparisonFullscreen img { display: block; width: 100%; margin-bottom: 10px; background: #111; }
1780
+ .historyItem[data-comparison] { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 55%, var(--dsw-alias-border-l1)); }
1781
+ .galleryMasonry { display: grid; flex: 1 1 auto; width: 100%; height: 0; max-width: 100%; min-width: 0; min-height: 0; box-sizing: border-box; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: max-content; align-content: start; gap: 16px; overflow-y: scroll; overflow-x: hidden; overscroll-behavior: contain; padding: 2px 8px 16px 2px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2) transparent; }
1782
+ .galleryMasonry::-webkit-scrollbar { width: 8px; }
1783
+ .galleryMasonry::-webkit-scrollbar-thumb { background: var(--dsw-alias-border-l2); border-radius: 999px; }
1784
+ .galleryCard { position: relative; display: block; width: 100%; margin: 0; overflow: hidden; border: 1px solid var(--dsw-alias-border-l1); border-radius: 14px; background: var(--dsw-alias-bg-layer-1); box-shadow: 0 5px 18px rgb(24 32 54 / 7%); }
1785
+ .galleryCard[data-selected] { border-color: var(--dsw-alias-brand-primary); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent), 0 5px 18px rgb(24 32 54 / 7%); }
1786
+ .gallerySelect { position: absolute; z-index: 2; top: 9px; right: 9px; display: grid; width: 26px; height: 26px; place-items: center; border: 1px solid rgb(255 255 255 / 75%); border-radius: 7px; background: rgb(0 0 0 / 58%); cursor: pointer; }
1787
+ .gallerySelect input { width: 16px; height: 16px; margin: 0; accent-color: var(--dsw-alias-brand-primary); cursor: pointer; }
1788
+ .galleryImageButton { position: relative; display: block; width: 100%; padding: 0; border: 0; background: var(--dsw-alias-bg-base); cursor: zoom-in; }
1789
+ .galleryImageButton[data-selecting] { cursor: pointer; }
1790
+ .galleryImage { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
1791
+ .galleryMasonry[data-view='masonry'] .galleryCard:nth-child(3n + 1) .galleryImage { aspect-ratio: 4 / 5; }
1792
+ .galleryMasonry[data-view='masonry'] .galleryCard:nth-child(3n + 2) .galleryImage { aspect-ratio: 4 / 3; }
1793
+ .galleryMasonry[data-view='masonry'] .galleryCard:nth-child(3n) .galleryImage { aspect-ratio: 3 / 4; }
1794
+ .galleryBadge { position: absolute; top: 10px; left: 10px; padding: 4px 9px; border-radius: 999px; color: #fff; background: rgb(18 23 36 / 76%); font-size: 11px; backdrop-filter: blur(4px); }
1795
+ .galleryCardFooter { display: flex; align-items: center; gap: 9px; min-width: 0; padding: 10px 12px; }
1796
+ .galleryAvatar { display: grid; flex: none; width: 27px; height: 27px; place-items: center; border-radius: 50%; color: #fff; background: var(--dsw-alias-brand-primary); font-size: 12px; font-weight: 700; }
1797
+ .galleryCardInfo { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 2px; }
1798
+ .galleryCardInfo strong, .galleryCardInfo small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1799
+ .galleryCardInfo strong { color: var(--dsw-alias-label-primary); font-size: 12px; }
1800
+ .galleryCardInfo small { color: var(--dsw-alias-label-tertiary); font-size: 10px; }
1801
+ .galleryTags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
1802
+ .galleryTags button { overflow: hidden; max-width: 96px; min-height: 19px; padding: 1px 6px; border: 0; border-radius: 4px; color: var(--dsw-alias-brand-primary); background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent); cursor: pointer; font: inherit; font-size: 10px; line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; }
1803
+ .galleryTags button:hover { background: color-mix(in srgb, var(--dsw-alias-brand-primary) 17%, transparent); }
1804
+ .galleryTags .galleryTagEdit { flex: none; color: var(--dsw-alias-label-tertiary); background: transparent; }
1805
+ .galleryTagEditor { display: flex; align-items: center; gap: 6px; padding: 0 12px 10px 48px; }
1806
+ .galleryTagEditor input { min-width: 0; flex: 1; height: 27px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; outline: none; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); font: inherit; font-size: 11px; }
1807
+ .galleryTagEditor input:focus { border-color: var(--dsw-alias-brand-primary); }
1808
+ .galleryTagEditor button { height: 27px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); cursor: pointer; font: inherit; font-size: 11px; }
1809
+ .galleryTagEditor button[type='submit'] { color: var(--dsw-alias-brand-primary); }
1810
+ .galleryRemove { flex: none; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%; color: var(--dsw-alias-label-tertiary); background: transparent; cursor: pointer; font-size: 18px; }
1811
+ .galleryRemove:hover { color: var(--dsw-alias-state-error); background: var(--dsw-alias-bg-layer-2); }
1812
+
1813
+ @media (max-width: 1100px) {
1814
+ .galleryMasonry { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1815
+ }
1816
+
1555
1817
  @media (max-width: 760px) {
1556
- .studio { flex-direction: column; overflow: auto; }
1818
+ .studio {
1819
+ grid-template-columns: minmax(0, 1fr);
1820
+ grid-template-rows: minmax(220px, 36%) minmax(0, 1fr);
1821
+ overflow-y: auto;
1822
+ }
1823
+ .history { grid-column: 1; grid-row: 1; min-height: 220px; }
1824
+ .generation { grid-column: 1; grid-row: 2; flex-direction: column; min-height: 0; }
1557
1825
  .config { width: auto; max-width: none; height: auto; min-height: 0; }
1558
1826
  .config[data-gallery='true'] { flex: none; }
1559
1827
  .canvas { min-height: 560px; }
1560
- .galleryToolbar { align-items: flex-start; flex-direction: column; }
1561
- .galleryToolbarActions { width: 100%; flex-wrap: wrap; }
1562
- .galleryMasonry { grid-template-columns: 1fr; }
1563
- }
1828
+ .galleryToolbar { align-items: flex-start; flex-direction: column; }
1829
+ .galleryToolbarActions { width: 100%; flex-wrap: wrap; }
1830
+ .galleryMasonry { grid-template-columns: 1fr; }
1831
+ }