@dickpy/dsh-imagegen 1.5.7 → 1.5.9

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.
@@ -1,1065 +1,1187 @@
1
- /* Infinite canvas workspace — node-graph canvas styled after
2
- * basketikun/infinite-canvas: floating docks, card nodes, wire connections. */
3
-
4
- .root {
5
- position: relative;
6
- display: flex;
7
- flex: 1 1 auto;
8
- flex-direction: column;
9
- height: 100%;
10
- min-width: 0;
11
- min-height: 0;
12
- overflow: hidden;
13
- border: 1px solid var(--dsw-alias-border-l1);
14
- border-radius: 10px;
15
- background: var(--dsw-alias-bg-layer-1);
16
- color: var(--dsw-alias-label-primary);
17
- font-family: var(--dsw-font-family, inherit);
18
- user-select: none;
19
- }
20
-
21
- .selectCursor { cursor: default; }
22
- .panCursor { cursor: grab; }
23
- .panCursor:active { cursor: grabbing; }
24
-
25
- /* ------------------------------------------------------------- top bar */
26
-
27
- .topBar {
28
- display: flex;
29
- align-items: center;
30
- gap: 8px;
31
- padding: 8px 12px;
32
- border-bottom: 1px solid var(--dsw-alias-border-l1);
33
- flex: none;
34
- z-index: 40;
35
- background: var(--dsw-alias-bg-layer-1);
36
- }
37
-
38
- .projectSelect {
39
- max-width: 180px;
40
- height: 30px;
41
- padding: 0 8px;
42
- border-radius: 8px;
43
- border: 1px solid var(--dsw-alias-border-l1);
44
- background: transparent;
45
- color: var(--dsw-alias-label-primary);
46
- font-size: 12.5px;
47
- }
48
-
49
- .titleButton {
50
- height: 30px;
51
- padding: 0 10px;
52
- border: 1px solid transparent;
53
- border-radius: 8px;
54
- background: transparent;
55
- color: var(--dsw-alias-label-primary);
56
- font-size: 13px;
57
- font-weight: 600;
58
- max-width: 260px;
59
- overflow: hidden;
60
- text-overflow: ellipsis;
61
- white-space: nowrap;
62
- cursor: text;
63
- }
64
-
65
- .titleButton:hover { border-color: var(--dsw-alias-border-l1); }
66
-
67
- .titleInput {
68
- height: 30px;
69
- padding: 0 10px;
70
- border-radius: 8px;
71
- border: 1px solid var(--dsw-alias-brand-primary);
72
- background: transparent;
73
- color: var(--dsw-alias-label-primary);
74
- font-size: 13px;
75
- font-weight: 600;
76
- width: 240px;
77
- outline: none;
78
- }
79
-
80
- .topBarSpacer { flex: 1; }
81
-
82
- .saveState {
83
- font-size: 11.5px;
84
- color: var(--dsw-alias-label-tertiary);
85
- white-space: nowrap;
86
- }
87
-
88
- .saveState[data-state="error"] { color: var(--dsw-alias-label-error); }
89
- .saveState[data-state="saving"] { color: var(--dsw-alias-state-warn-primary, var(--dsw-alias-label-secondary)); }
90
-
91
- /* ---------------------------------------------------------- icon button */
92
-
93
- .iconButton {
94
- display: inline-flex;
95
- align-items: center;
96
- justify-content: center;
97
- gap: 5px;
98
- width: 30px;
99
- height: 30px;
100
- flex: none;
101
- border: none;
102
- border-radius: 8px;
103
- background: transparent;
104
- color: var(--dsw-alias-label-secondary);
105
- cursor: pointer;
106
- padding: 0;
107
- }
108
-
109
- .iconButton:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
110
- .iconButton[data-active] { background: color-mix(in srgb, var(--dsw-alias-brand-primary) 16%, transparent); color: var(--dsw-alias-brand-primary); }
111
- .iconButton:disabled { opacity: 0.35; cursor: not-allowed; }
112
- .iconButton:disabled:hover { background: transparent; color: var(--dsw-alias-label-secondary); }
113
-
114
- /* (node tools moved to the bottom-center dock above) */
115
-
116
- /* ------------------------------------------------------------- viewport */
117
-
118
- .viewport {
119
- position: relative;
120
- flex: 1;
121
- min-height: 0;
122
- overflow: hidden;
123
- touch-action: none;
124
- }
125
-
126
- .grid {
127
- position: absolute;
128
- inset: 0;
129
- pointer-events: none;
130
- opacity: 0.5;
131
- }
132
-
133
- .grid[data-mode="dots"] {
134
- background-image: radial-gradient(circle, color-mix(in srgb, var(--dsw-alias-label-primary) 30%, transparent) 1.1px, transparent 1.4px);
135
- }
136
-
137
- .grid[data-mode="lines"] {
138
- background-image:
139
- linear-gradient(color-mix(in srgb, var(--dsw-alias-label-primary) 9%, transparent) 1px, transparent 1px),
140
- linear-gradient(90deg, color-mix(in srgb, var(--dsw-alias-label-primary) 9%, transparent) 1px, transparent 1px);
141
- }
142
-
143
- .grid[data-mode="blank"] { background-image: none; }
144
-
145
- .grid[data-mode="diagonal"] {
146
- background-image: repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent) 0 1px, transparent 1px 16px);
147
- }
148
-
149
- .grid[data-mode="checker"] {
150
- background-image:
151
- conic-gradient(color-mix(in srgb, var(--dsw-alias-label-primary) 7%, transparent) 90deg, transparent 90deg 180deg, color-mix(in srgb, var(--dsw-alias-label-primary) 7%, transparent) 180deg 270deg, transparent 270deg);
152
- background-size: 48px 48px;
153
- }
154
-
155
- .grid[data-mode="image"] { background-image: none; }
156
-
157
- .gridScrim {
158
- position: absolute;
159
- inset: 0;
160
- background: var(--dsw-alias-bg-layer-1);
161
- opacity: 0.6;
162
- }
163
-
164
- /* ------------------------------------------------ background menu */
165
-
166
- .backgroundMenu {
167
- position: absolute;
168
- transform: translate(-50%, -100%);
169
- z-index: 45;
170
- min-width: 168px;
171
- padding: 5px;
172
- border-radius: 11px;
173
- border: 1px solid var(--dsw-alias-border-l1);
174
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
175
- box-shadow: 0 16px 40px rgb(15 23 42 / 20%);
176
- display: flex;
177
- flex-direction: column;
178
- }
179
-
180
- .backgroundMenu button {
181
- display: flex;
182
- align-items: center;
183
- justify-content: space-between;
184
- border: none;
185
- border-radius: 7px;
186
- background: transparent;
187
- color: var(--dsw-alias-label-primary);
188
- font-size: 12.5px;
189
- padding: 7px 10px;
190
- cursor: pointer;
191
- text-align: left;
192
- }
193
-
194
- .backgroundMenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
195
-
196
- .backgroundMenu button[data-active] {
197
- color: var(--dsw-alias-brand-primary);
198
- background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);
199
- }
200
-
201
- .backgroundMenuDivider {
202
- height: 1px;
203
- margin: 4px 6px;
204
- background: var(--dsw-alias-border-l1);
205
- }
206
-
207
- .world {
208
- position: absolute;
209
- left: 0;
210
- top: 0;
211
- transform-origin: 0 0;
212
- }
213
-
214
- .marquee {
215
- position: absolute;
216
- z-index: 20;
217
- border: 1px solid var(--dsw-alias-brand-primary);
218
- background: color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent);
219
- border-radius: 4px;
220
- pointer-events: none;
221
- }
222
-
223
- /* ------------------------------------------------------------ nodes */
224
-
225
- .node {
226
- position: absolute;
227
- display: flex;
228
- flex-direction: column;
229
- border-radius: 14px;
230
- border: 1.5px solid var(--dsw-alias-border-l1);
231
- background: var(--dsw-alias-bg-layer-1);
232
- box-shadow: 0 8px 24px rgb(15 23 42 / 12%);
233
- overflow: visible;
234
- cursor: grab;
235
- touch-action: none;
236
- }
237
-
238
- .node:active { cursor: grabbing; }
239
-
240
- .nodeGlow {
241
- position: absolute;
242
- inset: -6px;
243
- border-radius: 18px;
244
- pointer-events: none;
245
- opacity: 0;
246
- transition: opacity 0.15s ease;
247
- }
248
-
249
- .nodeSelected {
250
- border-color: var(--dsw-alias-brand-primary);
251
- z-index: 2;
252
- }
253
-
254
- .nodeSelected .nodeGlow {
255
- opacity: 1;
256
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);
257
- }
258
-
259
- .nodeRelated { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent); }
260
-
261
- .nodeConnectTarget {
262
- border-color: var(--dsw-alias-brand-primary);
263
- box-shadow: 0 0 0 4px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent);
264
- }
265
-
266
- .nodeHeader {
267
- display: flex;
268
- align-items: center;
269
- gap: 6px;
270
- padding: 7px 12px 5px;
271
- font-size: 11.5px;
272
- color: var(--dsw-alias-label-secondary);
273
- cursor: inherit;
274
- flex: none;
275
- }
276
-
277
- .nodeTitle {
278
- font-weight: 600;
279
- overflow: hidden;
280
- text-overflow: ellipsis;
281
- white-space: nowrap;
282
- }
283
-
284
- .nodeSize {
285
- margin-left: auto;
286
- font-size: 10.5px;
287
- color: var(--dsw-alias-label-tertiary);
288
- font-variant-numeric: tabular-nums;
289
- }
290
-
291
- .nodeSpinner {
292
- width: 11px;
293
- height: 11px;
294
- flex: none;
295
- border-radius: 50%;
296
- border: 1.5px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);
297
- border-top-color: var(--dsw-alias-brand-primary);
298
- animation: canvasSpin 0.8s linear infinite;
299
- }
300
-
301
- .nodeBody {
302
- flex: 1;
303
- min-height: 0;
304
- margin: 0 8px 8px;
305
- border-radius: 9px;
306
- overflow: hidden;
307
- background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);
308
- display: flex;
309
- align-items: center;
310
- justify-content: center;
311
- pointer-events: none;
312
- }
313
-
314
- .nodeBody img {
315
- width: 100%;
316
- height: 100%;
317
- object-fit: contain;
318
- display: block;
319
- }
320
-
321
- .imageInfo {
322
- position: absolute;
323
- top: 6px;
324
- z-index: 2;
325
- padding: 3px 8px;
326
- border-radius: 6px;
327
- background: color-mix(in srgb, var(--dsw-alias-label-primary) 62%, transparent);
328
- color: var(--dsw-alias-bg-layer-1);
329
- font-size: 10.5px;
330
- line-height: 1.4;
331
- pointer-events: none;
332
- backdrop-filter: blur(3px);
333
- max-width: calc(100% - 90px);
334
- overflow: hidden;
335
- text-overflow: ellipsis;
336
- white-space: nowrap;
337
- }
338
-
339
- .imageInfoLeft { left: 6px; font-weight: 600; }
340
-
341
- .imageInfoRight {
342
- right: 6px;
343
- left: auto;
344
- font-variant-numeric: tabular-nums;
345
- opacity: 0.85;
346
- }
347
-
348
- .nodeState,
349
- .nodeStateError {
350
- display: flex;
351
- flex-direction: column;
352
- align-items: center;
353
- gap: 8px;
354
- font-size: 12px;
355
- color: var(--dsw-alias-label-secondary);
356
- padding: 12px;
357
- text-align: center;
358
- pointer-events: auto;
359
- }
360
-
361
- .nodeStateError { color: var(--dsw-alias-label-error); }
362
-
363
- .nodeStateError button {
364
- border: none;
365
- border-radius: 7px;
366
- padding: 4px 12px;
367
- background: var(--dsw-alias-interactive-bg-hover);
368
- color: var(--dsw-alias-label-primary);
369
- font-size: 12px;
370
- cursor: pointer;
371
- }
372
-
373
- .nodeEmpty {
374
- display: flex;
375
- flex-direction: column;
376
- align-items: center;
377
- gap: 8px;
378
- border: 1.5px dashed color-mix(in srgb, var(--dsw-alias-label-primary) 24%, transparent);
379
- border-radius: 9px;
380
- margin: 6px;
381
- padding: 14px;
382
- background: transparent;
383
- color: var(--dsw-alias-label-tertiary);
384
- font-size: 12px;
385
- cursor: pointer;
386
- }
387
-
388
- .nodeEmpty:hover {
389
- border-color: var(--dsw-alias-brand-primary);
390
- color: var(--dsw-alias-brand-primary);
391
- }
392
-
393
- .textNode { cursor: default; }
394
-
395
- /* image nodes render as bare cards: the picture fills the frame */
396
- .imageNode .nodeBody { margin: 6px; }
397
-
398
- .textArea {
399
- flex: 1;
400
- min-height: 0;
401
- margin: 0 8px 8px;
402
- border: none;
403
- resize: none;
404
- outline: none;
405
- background: transparent;
406
- color: var(--dsw-alias-label-primary);
407
- font-size: 13px;
408
- line-height: 1.55;
409
- padding: 4px 6px;
410
- cursor: text;
411
- pointer-events: auto;
412
- }
413
-
414
- .textArea::placeholder { color: var(--dsw-alias-label-tertiary); }
415
-
416
- /* --------------------------------------------------- bottom dock */
417
-
418
- .dock {
419
- position: absolute;
420
- left: 50%;
421
- bottom: 14px;
422
- transform: translateX(-50%);
423
- z-index: 30;
424
- display: flex;
425
- align-items: center;
426
- gap: 2px;
427
- padding: 6px;
428
- border-radius: 13px;
429
- border: 1px solid var(--dsw-alias-border-l1);
430
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);
431
- box-shadow: 0 10px 30px rgb(15 23 42 / 14%);
432
- backdrop-filter: blur(10px);
433
- }
434
-
435
- .dock .iconButton {
436
- position: relative;
437
- overflow: hidden;
438
- width: 40px;
439
- height: 40px;
440
- border-radius: 11px;
441
- transition: transform 0.18s cubic-bezier(0.34, 1.9, 0.64, 1), background 0.15s ease, color 0.15s ease, box-shadow 0.18s ease;
442
- }
443
-
444
- /* water-wave sheen sweeping across + gentle lift on hover */
445
- .dock .iconButton::before {
446
- content: '';
447
- position: absolute;
448
- top: -4px;
449
- bottom: -4px;
450
- left: -150%;
451
- width: 65%;
452
- background: linear-gradient(105deg, transparent, color-mix(in srgb, currentColor 26%, transparent), transparent);
453
- transform: skewX(-18deg);
454
- opacity: 0;
455
- pointer-events: none;
456
- }
457
-
458
- .dock .iconButton:not(:disabled):hover {
459
- transform: translateY(calc(-3px - var(--dock-lift, 0px)));
460
- box-shadow: 0 6px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 20%, transparent);
461
- }
462
-
463
- .dock .iconButton:not(:disabled):hover::before {
464
- animation: dockShine 0.55s ease forwards;
465
- }
466
-
467
- .dock .iconButton:not(:disabled):active {
468
- transform: translateY(-1px) scale(0.96);
469
- }
470
-
471
- @keyframes dockShine {
472
- 0% { left: -150%; opacity: 1; }
473
- 100% { left: 170%; opacity: 1; }
474
- }
475
-
476
- .dock .iconButton[data-active] {
477
- background: var(--dsw-alias-label-primary);
478
- color: var(--dsw-alias-bg-layer-1);
479
- }
480
-
481
- .dock .iconButton[data-active]:hover { background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-1); }
482
-
483
- .dockDivider {
484
- width: 1px;
485
- height: 18px;
486
- margin: 0 4px;
487
- background: var(--dsw-alias-border-l1);
488
- }
489
-
490
- /* ------------------------------------------------- floating composer */
491
-
492
- .composer {
493
- position: absolute;
494
- z-index: 35;
495
- width: 560px;
496
- display: flex;
497
- flex-direction: column;
498
- gap: 8px;
499
- padding: 10px;
500
- border-radius: 14px;
501
- border: 1px solid var(--dsw-alias-border-l1);
502
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
503
- box-shadow: 0 16px 44px rgb(15 23 42 / 18%);
504
- backdrop-filter: blur(10px);
505
- }
506
-
507
- .composerPrompt {
508
- width: 100%;
509
- min-height: 38px;
510
- max-height: 120px;
511
- resize: none;
512
- border: none;
513
- outline: none;
514
- background: transparent;
515
- color: var(--dsw-alias-label-primary);
516
- font-size: 13px;
517
- line-height: 1.5;
518
- padding: 2px 4px;
519
- cursor: text;
520
- }
521
-
522
- .composerPrompt::placeholder { color: var(--dsw-alias-label-tertiary); }
523
-
524
- .composerMeta { display: flex; }
525
-
526
- .composerChip {
527
- display: inline-flex;
528
- align-items: center;
529
- gap: 5px;
530
- font-size: 11px;
531
- padding: 2px 9px;
532
- border-radius: 999px;
533
- border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent);
534
- color: var(--dsw-alias-brand-primary);
535
- background: color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent);
536
- }
537
-
538
- .composerControls {
539
- display: flex;
540
- align-items: center;
541
- gap: 6px;
542
- }
543
-
544
- .composerControls select {
545
- height: 28px;
546
- border-radius: 999px;
547
- border: 1px solid var(--dsw-alias-border-l1);
548
- background: transparent;
549
- color: var(--dsw-alias-label-primary);
550
- font-size: 11.5px;
551
- padding: 0 8px;
552
- min-width: 0;
553
- max-width: 128px;
554
- }
555
-
556
- .composerSend {
557
- margin-left: auto;
558
- width: 34px;
559
- height: 34px;
560
- flex: none;
561
- border: none;
562
- border-radius: 50%;
563
- background: var(--dsw-alias-label-primary);
564
- color: var(--dsw-alias-bg-layer-1);
565
- cursor: pointer;
566
- display: inline-flex;
567
- align-items: center;
568
- justify-content: center;
569
- }
570
-
571
- .composerSend:hover { opacity: 0.88; }
572
- .composerSend:disabled { opacity: 0.35; cursor: not-allowed; }
573
-
574
- /* ------------------------------------------------------ config node */
575
-
576
- .configNode {
577
- padding: 0 14px 14px;
578
- cursor: grab;
579
- }
580
-
581
- .configNode .nodeHeader { padding: 10px 2px 6px; font-size: 12px; }
582
-
583
- .configLinks {
584
- display: flex;
585
- align-items: center;
586
- margin: 4px 0 10px;
587
- flex: none;
588
- }
589
-
590
- .configLinks .composerChip {
591
- font-size: 11px;
592
- padding: 3px 10px;
593
- }
594
-
595
- .configHint {
596
- flex: 1;
597
- min-height: 0;
598
- margin: 0;
599
- font-size: 11.5px;
600
- line-height: 1.7;
601
- color: var(--dsw-alias-label-tertiary);
602
- overflow: auto;
603
- }
604
-
605
- /* connection handles */
606
-
607
- .handle {
608
- position: absolute;
609
- top: 50%;
610
- width: 12px;
611
- height: 12px;
612
- border-radius: 50%;
613
- transform: translateY(-50%) scale(0.6);
614
- background: var(--dsw-alias-bg-layer-1);
615
- border: 2px solid var(--dsw-alias-brand-primary);
616
- opacity: 0;
617
- transition: opacity 0.12s ease, transform 0.12s ease;
618
- cursor: crosshair;
619
- z-index: 3;
620
- }
621
-
622
- .handleLeft { left: -7px; }
623
- .handleRight { right: -7px; }
624
-
625
- .node:hover .handle,
626
- .nodeSelected .handle,
627
- .nodeConnectTarget .handle {
628
- opacity: 1;
629
- transform: translateY(-50%) scale(1);
630
- }
631
-
632
- .handle:hover { background: var(--dsw-alias-brand-primary); }
633
-
634
- .resizeHandle {
635
- position: absolute;
636
- right: -5px;
637
- bottom: -5px;
638
- width: 14px;
639
- height: 14px;
640
- border-radius: 4px;
641
- background: var(--dsw-alias-brand-primary);
642
- border: 2px solid var(--dsw-alias-bg-layer-1);
643
- cursor: nwse-resize;
644
- z-index: 3;
645
- }
646
-
647
- /* hover toolbar */
648
-
649
- .hoverToolbar {
650
- position: absolute;
651
- top: -36px;
652
- left: 50%;
653
- transform: translateX(-50%);
654
- display: flex;
655
- gap: 2px;
656
- padding: 4px;
657
- border-radius: 10px;
658
- border: 1px solid var(--dsw-alias-border-l1);
659
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);
660
- box-shadow: 0 8px 22px rgb(15 23 42 / 14%);
661
- opacity: 0;
662
- pointer-events: none;
663
- transition: opacity 0.12s ease;
664
- z-index: 4;
665
- }
666
-
667
- .node:hover .hoverToolbar,
668
- .nodeSelected .hoverToolbar {
669
- opacity: 1;
670
- pointer-events: auto;
671
- }
672
-
673
- /* -------------------------------------------------------- connections */
674
-
675
- .connectionLayer {
676
- position: absolute;
677
- overflow: visible;
678
- pointer-events: none;
679
- z-index: 0;
680
- }
681
-
682
- .connectionPath {
683
- fill: none;
684
- stroke: color-mix(in srgb, var(--dsw-alias-label-primary) 38%, transparent);
685
- stroke-width: 2;
686
- stroke-opacity: 0.85;
687
- pointer-events: none;
688
- }
689
-
690
- .connectionActive {
691
- stroke: var(--dsw-alias-brand-primary);
692
- stroke-width: 3;
693
- stroke-opacity: 1;
694
- filter: drop-shadow(0 0 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent));
695
- }
696
-
697
- .connectionPreview {
698
- fill: none;
699
- stroke: var(--dsw-alias-brand-primary);
700
- stroke-width: 2;
701
- stroke-dasharray: 5 5;
702
- pointer-events: none;
703
- }
704
-
705
- /* --------------------------------------------------------- empty hint */
706
-
707
- .emptyHint {
708
- position: absolute;
709
- left: 50%;
710
- top: 44%;
711
- transform: translate(-50%, -50%);
712
- display: flex;
713
- flex-direction: column;
714
- align-items: center;
715
- gap: 6px;
716
- text-align: center;
717
- color: var(--dsw-alias-label-tertiary);
718
- pointer-events: none;
719
- z-index: 5;
720
- }
721
-
722
- .emptyHint strong {
723
- font-size: 16px;
724
- color: var(--dsw-alias-label-secondary);
725
- }
726
-
727
- .emptyHint span { font-size: 12.5px; max-width: 320px; line-height: 1.6; }
728
-
729
- /* ------------------------------------------------------------ zoom dock */
730
-
731
- .zoomDock {
732
- position: absolute;
733
- left: 14px;
734
- bottom: 14px;
735
- z-index: 30;
736
- display: flex;
737
- align-items: center;
738
- gap: 6px;
739
- padding: 6px 8px;
740
- border-radius: 12px;
741
- border: 1px solid var(--dsw-alias-border-l1);
742
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 88%, transparent);
743
- box-shadow: 0 10px 30px rgb(15 23 42 / 12%);
744
- backdrop-filter: blur(10px);
745
- }
746
-
747
- .zoomDock input[type="range"] {
748
- width: 96px;
749
- accent-color: var(--dsw-alias-brand-primary);
750
- }
751
-
752
- .zoomValue {
753
- width: 40px;
754
- text-align: right;
755
- font-size: 11.5px;
756
- color: var(--dsw-alias-label-secondary);
757
- font-variant-numeric: tabular-nums;
758
- }
759
-
760
- /* -------------------------------------------------------------- minimap */
761
-
762
- .minimap {
763
- position: absolute;
764
- left: 14px;
765
- bottom: 62px;
766
- z-index: 30;
767
- width: 220px;
768
- height: 150px;
769
- border-radius: 12px;
770
- border: 1px solid var(--dsw-alias-border-l1);
771
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 88%, transparent);
772
- box-shadow: 0 10px 30px rgb(15 23 42 / 12%);
773
- overflow: hidden;
774
- backdrop-filter: blur(10px);
775
- }
776
-
777
- .minimapCanvas {
778
- position: relative;
779
- width: 100%;
780
- height: 100%;
781
- cursor: crosshair;
782
- }
783
-
784
- .minimapNode {
785
- position: absolute;
786
- border-radius: 2px;
787
- opacity: 0.8;
788
- }
789
-
790
- .minimapImage { background: var(--dsw-alias-brand-primary); }
791
- .minimapText { background: color-mix(in srgb, var(--dsw-alias-label-primary) 40%, transparent); }
792
- .minimapSelected { outline: 1.5px solid var(--dsw-alias-brand-primary); }
793
-
794
- .minimapViewport {
795
- position: absolute;
796
- border: 1.5px solid var(--dsw-alias-brand-primary);
797
- background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);
798
- border-radius: 2px;
799
- pointer-events: none;
800
- }
801
-
802
- /* ------------------------------------------------------------ inspector */
803
-
804
- .inspectorRow {
805
- display: flex;
806
- gap: 8px;
807
- }
808
-
809
- .inspectorRow > * { flex: 1; min-width: 0; }
810
-
811
- /* --------------------------------------------------------- context menu */
812
-
813
- .contextMenu {
814
- position: fixed;
815
- z-index: 90;
816
- min-width: 176px;
817
- padding: 5px;
818
- border-radius: 11px;
819
- border: 1px solid var(--dsw-alias-border-l1);
820
- background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
821
- box-shadow: 0 16px 40px rgb(15 23 42 / 20%);
822
- display: flex;
823
- flex-direction: column;
824
- }
825
-
826
- .contextMenu button {
827
- display: flex;
828
- align-items: center;
829
- gap: 8px;
830
- border: none;
831
- border-radius: 7px;
832
- background: transparent;
833
- color: var(--dsw-alias-label-primary);
834
- font-size: 12.5px;
835
- padding: 7px 10px;
836
- cursor: pointer;
837
- text-align: left;
838
- }
839
-
840
- .contextMenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
841
- .contextMenu button[data-danger] { color: var(--dsw-alias-label-error); }
842
-
843
- /* ---------------------------------------------------------- error toast */
844
-
845
- .errorToast {
846
- position: absolute;
847
- left: 50%;
848
- bottom: 18px;
849
- transform: translateX(-50%);
850
- z-index: 60;
851
- display: flex;
852
- align-items: center;
853
- gap: 10px;
854
- max-width: min(560px, 80%);
855
- padding: 9px 12px;
856
- border-radius: 10px;
857
- border: 1px solid color-mix(in srgb, var(--dsw-alias-label-error) 35%, transparent);
858
- background: color-mix(in srgb, var(--dsw-alias-label-error) 12%, var(--dsw-alias-bg-layer-1));
859
- color: var(--dsw-alias-label-error);
860
- font-size: 12.5px;
861
- box-shadow: 0 12px 30px rgb(15 23 42 / 18%);
862
- }
863
-
864
- .errorToast button {
865
- border: none;
866
- background: transparent;
867
- color: inherit;
868
- cursor: pointer;
869
- padding: 2px;
870
- display: inline-flex;
871
- flex: none;
872
- }
873
-
874
- /* ---------------------------------------------------------- picker modal */
875
-
876
- .modalBackdrop {
877
- position: absolute;
878
- inset: 0;
879
- z-index: 70;
880
- background: color-mix(in srgb, var(--dsw-alias-label-primary) 32%, transparent);
881
- display: flex;
882
- align-items: center;
883
- justify-content: center;
884
- }
885
-
886
- .picker {
887
- width: min(720px, 92%);
888
- max-height: 84%;
889
- display: flex;
890
- flex-direction: column;
891
- border-radius: 14px;
892
- border: 1px solid var(--dsw-alias-border-l1);
893
- background: var(--dsw-alias-bg-layer-1);
894
- box-shadow: 0 24px 60px rgb(15 23 42 / 26%);
895
- overflow: hidden;
896
- }
897
-
898
- .pickerHeader {
899
- display: flex;
900
- align-items: center;
901
- justify-content: space-between;
902
- padding: 12px 14px;
903
- font-size: 14px;
904
- border-bottom: 1px solid var(--dsw-alias-border-l1);
905
- }
906
-
907
- .pickerHeader button {
908
- border: none;
909
- background: transparent;
910
- color: var(--dsw-alias-label-secondary);
911
- font-size: 18px;
912
- cursor: pointer;
913
- padding: 0 4px;
914
- }
915
-
916
- .pickerTabs {
917
- display: flex;
918
- gap: 4px;
919
- padding: 10px 14px 0;
920
- }
921
-
922
- .pickerTabs button {
923
- border: none;
924
- border-radius: 8px 8px 0 0;
925
- background: transparent;
926
- color: var(--dsw-alias-label-secondary);
927
- font-size: 12.5px;
928
- padding: 7px 12px;
929
- cursor: pointer;
930
- }
931
-
932
- .pickerTabs button[data-active] {
933
- background: var(--dsw-alias-interactive-bg-hover);
934
- color: var(--dsw-alias-brand-primary);
935
- }
936
-
937
- .pickerBody {
938
- flex: 1;
939
- min-height: 0;
940
- overflow: auto;
941
- padding: 14px;
942
- }
943
-
944
- .pickerGrid {
945
- display: grid;
946
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
947
- gap: 10px;
948
- }
949
-
950
- .pickerCard {
951
- display: flex;
952
- flex-direction: column;
953
- gap: 6px;
954
- border: 1.5px solid var(--dsw-alias-border-l1);
955
- border-radius: 10px;
956
- background: transparent;
957
- padding: 6px;
958
- cursor: pointer;
959
- text-align: left;
960
- color: var(--dsw-alias-label-primary);
961
- }
962
-
963
- .pickerCard[data-selected] {
964
- border-color: var(--dsw-alias-brand-primary);
965
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 25%, transparent);
966
- }
967
-
968
- .pickerCard img {
969
- width: 100%;
970
- height: 110px;
971
- object-fit: cover;
972
- border-radius: 7px;
973
- }
974
-
975
- .pickerCardPrompt {
976
- font-size: 11.5px;
977
- overflow: hidden;
978
- text-overflow: ellipsis;
979
- white-space: nowrap;
980
- }
981
-
982
- .pickerCard small {
983
- color: var(--dsw-alias-label-tertiary);
984
- font-size: 10.5px;
985
- }
986
-
987
- .pickerFooter {
988
- display: flex;
989
- align-items: center;
990
- justify-content: space-between;
991
- padding-top: 12px;
992
- font-size: 12.5px;
993
- color: var(--dsw-alias-label-secondary);
994
- }
995
-
996
- .pickerFooter button,
997
- .generateForm button {
998
- height: 32px;
999
- padding: 0 16px;
1000
- border: none;
1001
- border-radius: 8px;
1002
- background: var(--dsw-alias-brand-primary);
1003
- color: var(--dsw-alias-bg-base, #fff);
1004
- font-size: 12.5px;
1005
- font-weight: 600;
1006
- cursor: pointer;
1007
- display: inline-flex;
1008
- align-items: center;
1009
- gap: 6px;
1010
- }
1011
-
1012
- .pickerFooter button:disabled,
1013
- .generateForm button:disabled { opacity: 0.45; cursor: not-allowed; }
1014
-
1015
- .uploadBox {
1016
- display: flex;
1017
- flex-direction: column;
1018
- align-items: center;
1019
- justify-content: center;
1020
- gap: 8px;
1021
- min-height: 220px;
1022
- border: 1.5px dashed color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);
1023
- border-radius: 12px;
1024
- color: var(--dsw-alias-label-secondary);
1025
- cursor: pointer;
1026
- text-align: center;
1027
- }
1028
-
1029
- .uploadBox:hover { border-color: var(--dsw-alias-brand-primary); }
1030
- .uploadBox input { display: none; }
1031
- .uploadBox small { color: var(--dsw-alias-label-tertiary); font-size: 11px; }
1032
-
1033
- .uploadIcon { color: var(--dsw-alias-brand-primary); }
1034
-
1035
- .generateForm {
1036
- display: flex;
1037
- flex-direction: column;
1038
- gap: 10px;
1039
- }
1040
-
1041
- .generateForm textarea {
1042
- min-height: 110px;
1043
- resize: vertical;
1044
- border-radius: 9px;
1045
- border: 1px solid var(--dsw-alias-border-l1);
1046
- background: transparent;
1047
- color: var(--dsw-alias-label-primary);
1048
- font-size: 12.5px;
1049
- padding: 8px 10px;
1050
- outline: none;
1051
- }
1052
-
1053
- .generateForm select {
1054
- height: 30px;
1055
- border-radius: 8px;
1056
- border: 1px solid var(--dsw-alias-border-l1);
1057
- background: transparent;
1058
- color: var(--dsw-alias-label-primary);
1059
- font-size: 12.5px;
1060
- padding: 0 8px;
1061
- }
1062
-
1063
- @keyframes canvasSpin {
1064
- to { transform: rotate(360deg); }
1065
- }
1
+ /* Infinite canvas workspace — node-graph canvas styled after
2
+ * basketikun/infinite-canvas: floating docks, card nodes, wire connections. */
3
+
4
+ .root {
5
+ position: relative;
6
+ display: flex;
7
+ flex: 1 1 auto;
8
+ flex-direction: column;
9
+ height: 100%;
10
+ min-width: 0;
11
+ min-height: 0;
12
+ overflow: hidden;
13
+ border: 1px solid var(--dsw-alias-border-l1);
14
+ border-radius: 10px;
15
+ background: var(--dsw-alias-bg-layer-1);
16
+ color: var(--dsw-alias-label-primary);
17
+ font-family: var(--dsw-font-family, inherit);
18
+ user-select: none;
19
+ }
20
+
21
+ .selectCursor { cursor: default; }
22
+ .panCursor { cursor: grab; }
23
+ .panCursor:active { cursor: grabbing; }
24
+
25
+ /* ------------------------------------------------------------- top bar */
26
+
27
+ .topBar {
28
+ display: flex;
29
+ align-items: center;
30
+ gap: 8px;
31
+ padding: 8px 12px;
32
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
33
+ flex: none;
34
+ z-index: 40;
35
+ background: var(--dsw-alias-bg-layer-1);
36
+ }
37
+
38
+ .projectSelect {
39
+ max-width: 180px;
40
+ height: 30px;
41
+ padding: 0 8px;
42
+ border-radius: 8px;
43
+ border: 1px solid var(--dsw-alias-border-l1);
44
+ background: transparent;
45
+ color: var(--dsw-alias-label-primary);
46
+ font-size: 12.5px;
47
+ }
48
+
49
+ .titleButton {
50
+ height: 30px;
51
+ padding: 0 10px;
52
+ border: 1px solid transparent;
53
+ border-radius: 8px;
54
+ background: transparent;
55
+ color: var(--dsw-alias-label-primary);
56
+ font-size: 13px;
57
+ font-weight: 600;
58
+ max-width: 260px;
59
+ overflow: hidden;
60
+ text-overflow: ellipsis;
61
+ white-space: nowrap;
62
+ cursor: text;
63
+ }
64
+
65
+ .titleButton:hover { border-color: var(--dsw-alias-border-l1); }
66
+
67
+ .titleInput {
68
+ height: 30px;
69
+ padding: 0 10px;
70
+ border-radius: 8px;
71
+ border: 1px solid var(--dsw-alias-brand-primary);
72
+ background: transparent;
73
+ color: var(--dsw-alias-label-primary);
74
+ font-size: 13px;
75
+ font-weight: 600;
76
+ width: 240px;
77
+ outline: none;
78
+ }
79
+
80
+ .topBarSpacer { flex: 1; }
81
+
82
+ .saveState {
83
+ font-size: 11.5px;
84
+ color: var(--dsw-alias-label-tertiary);
85
+ white-space: nowrap;
86
+ }
87
+
88
+ .saveState[data-state="error"] { color: var(--dsw-alias-label-error); }
89
+ .saveState[data-state="saving"] { color: var(--dsw-alias-state-warn-primary, var(--dsw-alias-label-secondary)); }
90
+
91
+ /* ---------------------------------------------------------- icon button */
92
+
93
+ .iconButton {
94
+ display: inline-flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ gap: 5px;
98
+ width: 30px;
99
+ height: 30px;
100
+ flex: none;
101
+ border: none;
102
+ border-radius: 8px;
103
+ background: transparent;
104
+ color: var(--dsw-alias-label-secondary);
105
+ cursor: pointer;
106
+ padding: 0;
107
+ }
108
+
109
+ .iconButton:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
110
+ .iconButton[data-active] { background: color-mix(in srgb, var(--dsw-alias-brand-primary) 16%, transparent); color: var(--dsw-alias-brand-primary); }
111
+ .iconButton:disabled { opacity: 0.35; cursor: not-allowed; }
112
+ .iconButton:disabled:hover { background: transparent; color: var(--dsw-alias-label-secondary); }
113
+
114
+ /* (node tools moved to the bottom-center dock above) */
115
+
116
+ /* ------------------------------------------------------------- viewport */
117
+
118
+ .viewport {
119
+ position: relative;
120
+ flex: 1;
121
+ min-height: 0;
122
+ overflow: hidden;
123
+ touch-action: none;
124
+ }
125
+
126
+ .grid {
127
+ position: absolute;
128
+ inset: 0;
129
+ pointer-events: none;
130
+ opacity: 0.5;
131
+ }
132
+
133
+ /* Interactive backdrops live in <canvas> elements (the fluid flowmap dot
134
+ * field, the WebGL fluid sim, and the reactbits-style shader backdrops);
135
+ * they render themselves at full strength (the 0.5 grid dimming stays off). */
136
+ .flowCanvas {
137
+ position: absolute;
138
+ inset: 0;
139
+ width: 100%;
140
+ height: 100%;
141
+ }
142
+
143
+ /* WebGL "liquid ether" fluid simulation, same placement as the flow canvas. */
144
+ .liquidCanvas {
145
+ position: absolute;
146
+ inset: 0;
147
+ width: 100%;
148
+ height: 100%;
149
+ }
150
+
151
+ /* Fullscreen-shader backdrops (floating lines / galaxy / silk) and the 2D
152
+ * wave lines share one placement; floating lines screen-blends over dark
153
+ * surfaces (set from JS, the light theme uses its own light backdrop). */
154
+ .sceneCanvas {
155
+ position: absolute;
156
+ inset: 0;
157
+ width: 100%;
158
+ height: 100%;
159
+ }
160
+
161
+ .grid[data-mode="flow"],
162
+ .grid[data-mode="liquid"],
163
+ .grid[data-mode="floatingLines"],
164
+ .grid[data-mode="galaxy"],
165
+ .grid[data-mode="silk"],
166
+ .grid[data-mode="waves"],
167
+ .grid[data-mode="faultyTerminal"],
168
+ .grid[data-mode="dotField"],
169
+ .grid[data-mode="dotGrid"],
170
+ .grid[data-mode="shapeGrid"] {
171
+ opacity: 1;
172
+ }
173
+
174
+ .grid[data-mode="dots"] {
175
+ background-image: radial-gradient(circle, color-mix(in srgb, var(--dsw-alias-label-primary) 30%, transparent) 1.1px, transparent 1.4px);
176
+ }
177
+
178
+ .grid[data-mode="lines"] {
179
+ background-image:
180
+ linear-gradient(color-mix(in srgb, var(--dsw-alias-label-primary) 9%, transparent) 1px, transparent 1px),
181
+ linear-gradient(90deg, color-mix(in srgb, var(--dsw-alias-label-primary) 9%, transparent) 1px, transparent 1px);
182
+ }
183
+
184
+ .grid[data-mode="blank"] { background-image: none; }
185
+
186
+ .grid[data-mode="image"] { background-image: none; }
187
+
188
+ .gridScrim {
189
+ position: absolute;
190
+ inset: 0;
191
+ background: var(--dsw-alias-bg-layer-1);
192
+ opacity: 0.6;
193
+ }
194
+
195
+ /* ------------------------------------------------ background menu */
196
+
197
+ .backgroundMenu {
198
+ position: absolute;
199
+ transform: translate(-50%, -100%);
200
+ z-index: 45;
201
+ min-width: 168px;
202
+ padding: 5px;
203
+ border-radius: 11px;
204
+ border: 1px solid var(--dsw-alias-border-l1);
205
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
206
+ box-shadow: 0 16px 40px rgb(15 23 42 / 20%);
207
+ display: flex;
208
+ flex-direction: column;
209
+ }
210
+
211
+ .backgroundMenu button {
212
+ display: flex;
213
+ align-items: center;
214
+ justify-content: flex-start;
215
+ border: none;
216
+ border-radius: 7px;
217
+ background: transparent;
218
+ color: var(--dsw-alias-label-primary);
219
+ font-size: 12.5px;
220
+ padding: 7px 10px;
221
+ cursor: pointer;
222
+ text-align: left;
223
+ }
224
+
225
+ .backgroundMenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
226
+
227
+ .backgroundMenu button[data-active] {
228
+ color: var(--dsw-alias-brand-primary);
229
+ background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);
230
+ }
231
+
232
+ .backgroundMenuDivider {
233
+ height: 1px;
234
+ margin: 4px 6px;
235
+ background: var(--dsw-alias-border-l1);
236
+ }
237
+
238
+ .world {
239
+ position: absolute;
240
+ left: 0;
241
+ top: 0;
242
+ transform-origin: 0 0;
243
+ }
244
+
245
+ .marquee {
246
+ position: absolute;
247
+ z-index: 20;
248
+ border: 1px solid var(--dsw-alias-brand-primary);
249
+ background: color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent);
250
+ border-radius: 4px;
251
+ pointer-events: none;
252
+ }
253
+
254
+ /* ------------------------------------------------------------ nodes */
255
+
256
+ .node {
257
+ position: absolute;
258
+ display: flex;
259
+ flex-direction: column;
260
+ border-radius: 14px;
261
+ border: 1.5px solid var(--dsw-alias-border-l1);
262
+ background: var(--dsw-alias-bg-layer-1);
263
+ box-shadow: 0 8px 24px rgb(15 23 42 / 12%);
264
+ overflow: visible;
265
+ cursor: grab;
266
+ touch-action: none;
267
+ }
268
+
269
+ .node:active { cursor: grabbing; }
270
+
271
+ .nodeGlow {
272
+ position: absolute;
273
+ inset: -6px;
274
+ border-radius: 18px;
275
+ pointer-events: none;
276
+ opacity: 0;
277
+ transition: opacity 0.15s ease;
278
+ }
279
+
280
+ .nodeSelected {
281
+ border-color: var(--dsw-alias-brand-primary);
282
+ z-index: 2;
283
+ }
284
+
285
+ .nodeSelected .nodeGlow {
286
+ opacity: 1;
287
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);
288
+ }
289
+
290
+ .nodeRelated { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent); }
291
+
292
+ .nodeConnectTarget {
293
+ border-color: var(--dsw-alias-brand-primary);
294
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent);
295
+ }
296
+
297
+ .nodeHeader {
298
+ display: flex;
299
+ align-items: center;
300
+ gap: 6px;
301
+ padding: 7px 12px 5px;
302
+ font-size: 11.5px;
303
+ color: var(--dsw-alias-label-secondary);
304
+ cursor: inherit;
305
+ flex: none;
306
+ }
307
+
308
+ .nodeTitle {
309
+ font-weight: 600;
310
+ overflow: hidden;
311
+ text-overflow: ellipsis;
312
+ white-space: nowrap;
313
+ }
314
+
315
+ .nodeSize {
316
+ margin-left: auto;
317
+ font-size: 10.5px;
318
+ color: var(--dsw-alias-label-tertiary);
319
+ font-variant-numeric: tabular-nums;
320
+ }
321
+
322
+ .nodeSpinner {
323
+ width: 11px;
324
+ height: 11px;
325
+ flex: none;
326
+ border-radius: 50%;
327
+ border: 1.5px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);
328
+ border-top-color: var(--dsw-alias-brand-primary);
329
+ animation: canvasSpin 0.8s linear infinite;
330
+ }
331
+
332
+ .nodeBody {
333
+ flex: 1;
334
+ min-height: 0;
335
+ margin: 0 8px 8px;
336
+ border-radius: 9px;
337
+ overflow: hidden;
338
+ background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);
339
+ display: flex;
340
+ align-items: center;
341
+ justify-content: center;
342
+ pointer-events: none;
343
+ }
344
+
345
+ .nodeBody img {
346
+ width: 100%;
347
+ height: 100%;
348
+ object-fit: contain;
349
+ display: block;
350
+ }
351
+
352
+ .imageInfo {
353
+ position: absolute;
354
+ top: 6px;
355
+ z-index: 2;
356
+ padding: 3px 8px;
357
+ border-radius: 6px;
358
+ background: color-mix(in srgb, var(--dsw-alias-label-primary) 62%, transparent);
359
+ color: var(--dsw-alias-bg-layer-1);
360
+ font-size: 10.5px;
361
+ line-height: 1.4;
362
+ pointer-events: none;
363
+ backdrop-filter: blur(3px);
364
+ max-width: calc(100% - 90px);
365
+ overflow: hidden;
366
+ text-overflow: ellipsis;
367
+ white-space: nowrap;
368
+ }
369
+
370
+ .imageInfoLeft { left: 6px; font-weight: 600; }
371
+
372
+ .imageInfoRight {
373
+ right: 6px;
374
+ left: auto;
375
+ font-variant-numeric: tabular-nums;
376
+ opacity: 0.85;
377
+ }
378
+
379
+ .nodeState,
380
+ .nodeStateError {
381
+ display: flex;
382
+ flex-direction: column;
383
+ align-items: center;
384
+ gap: 8px;
385
+ font-size: 12px;
386
+ color: var(--dsw-alias-label-secondary);
387
+ padding: 12px;
388
+ text-align: center;
389
+ pointer-events: auto;
390
+ }
391
+
392
+ .nodeStateError { color: var(--dsw-alias-label-error); }
393
+
394
+ .nodeStateError button {
395
+ border: none;
396
+ border-radius: 7px;
397
+ padding: 4px 12px;
398
+ background: var(--dsw-alias-interactive-bg-hover);
399
+ color: var(--dsw-alias-label-primary);
400
+ font-size: 12px;
401
+ cursor: pointer;
402
+ }
403
+
404
+ .nodeEmpty {
405
+ display: flex;
406
+ flex-direction: column;
407
+ align-items: center;
408
+ gap: 8px;
409
+ border: 1.5px dashed color-mix(in srgb, var(--dsw-alias-label-primary) 24%, transparent);
410
+ border-radius: 9px;
411
+ margin: 6px;
412
+ padding: 14px;
413
+ background: transparent;
414
+ color: var(--dsw-alias-label-tertiary);
415
+ font-size: 12px;
416
+ cursor: pointer;
417
+ /* .nodeBody disables pointer events for node dragging; the upload button
418
+ * inside must opt back in or its onClick never fires. */
419
+ pointer-events: auto;
420
+ }
421
+
422
+ .nodeEmpty:hover {
423
+ border-color: var(--dsw-alias-brand-primary);
424
+ color: var(--dsw-alias-brand-primary);
425
+ }
426
+
427
+ .textNode { cursor: default; }
428
+
429
+ /* image nodes render as bare cards: the picture fills the frame */
430
+ .imageNode .nodeBody { margin: 6px; }
431
+
432
+ .textArea {
433
+ flex: 1;
434
+ min-height: 0;
435
+ margin: 0 8px 8px;
436
+ border: none;
437
+ resize: none;
438
+ outline: none;
439
+ background: transparent;
440
+ color: var(--dsw-alias-label-primary);
441
+ font-size: 13px;
442
+ line-height: 1.55;
443
+ padding: 4px 6px;
444
+ cursor: text;
445
+ pointer-events: auto;
446
+ }
447
+
448
+ .textArea::placeholder { color: var(--dsw-alias-label-tertiary); }
449
+
450
+ /* --------------------------------------------------- bottom dock */
451
+
452
+ .dock {
453
+ position: absolute;
454
+ left: 50%;
455
+ bottom: 14px;
456
+ transform: translateX(-50%);
457
+ z-index: 30;
458
+ display: flex;
459
+ align-items: center;
460
+ gap: 2px;
461
+ padding: 6px;
462
+ border-radius: 13px;
463
+ border: 1px solid var(--dsw-alias-border-l1);
464
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);
465
+ box-shadow: 0 10px 30px rgb(15 23 42 / 14%);
466
+ backdrop-filter: blur(10px);
467
+ }
468
+
469
+ /* macOS-dock magnification: the pointermove handler on .dock feeds a gaussian
470
+ * falloff into --dock-scale / --dock-lift, so the hovered icon swells and lifts
471
+ * while neighbours rise and fall like a zipper as the pointer slides across. */
472
+ .dock .iconButton {
473
+ position: relative;
474
+ width: 40px;
475
+ height: 40px;
476
+ border-radius: 11px;
477
+ transform: translateY(var(--dock-lift, 0px)) scale(var(--dock-scale, 1));
478
+ transform-origin: 50% 100%;
479
+ transition: transform 0.16s cubic-bezier(0.33, 1, 0.68, 1), background 0.15s ease, color 0.15s ease, box-shadow 0.18s ease;
480
+ }
481
+
482
+ .dock .iconButton:not(:disabled):hover {
483
+ z-index: 2;
484
+ box-shadow: 0 6px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 20%, transparent);
485
+ }
486
+
487
+ .dock .iconButton:not(:disabled):active {
488
+ transform: translateY(var(--dock-lift, 0px)) scale(0.94);
489
+ }
490
+
491
+ .dock .iconButton[data-active] {
492
+ background: var(--dsw-alias-label-primary);
493
+ color: var(--dsw-alias-bg-layer-1);
494
+ }
495
+
496
+ .dock .iconButton[data-active]:hover { background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-1); }
497
+
498
+ .dockDivider {
499
+ width: 1px;
500
+ height: 18px;
501
+ margin: 0 4px;
502
+ background: var(--dsw-alias-border-l1);
503
+ }
504
+
505
+ /* ------------------------------------------------- floating composer */
506
+
507
+ .composer {
508
+ position: absolute;
509
+ z-index: 35;
510
+ width: 560px;
511
+ display: flex;
512
+ flex-direction: column;
513
+ gap: 8px;
514
+ padding: 10px;
515
+ border-radius: 14px;
516
+ border: 1px solid var(--dsw-alias-border-l1);
517
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
518
+ box-shadow: 0 16px 44px rgb(15 23 42 / 18%);
519
+ backdrop-filter: blur(10px);
520
+ }
521
+
522
+ .composerPrompt {
523
+ width: 100%;
524
+ min-height: 38px;
525
+ max-height: 120px;
526
+ resize: none;
527
+ border: none;
528
+ outline: none;
529
+ background: transparent;
530
+ color: var(--dsw-alias-label-primary);
531
+ font-size: 13px;
532
+ line-height: 1.5;
533
+ padding: 2px 4px;
534
+ cursor: text;
535
+ }
536
+
537
+ .composerPrompt::placeholder { color: var(--dsw-alias-label-tertiary); }
538
+
539
+ .composerMeta { display: flex; }
540
+
541
+ .composerChip {
542
+ display: inline-flex;
543
+ align-items: center;
544
+ gap: 5px;
545
+ font-size: 11px;
546
+ padding: 2px 9px;
547
+ border-radius: 999px;
548
+ border: 1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent);
549
+ color: var(--dsw-alias-brand-primary);
550
+ background: color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent);
551
+ }
552
+
553
+ .composerControls {
554
+ display: flex;
555
+ align-items: center;
556
+ gap: 6px;
557
+ }
558
+
559
+ .composerControls select {
560
+ height: 28px;
561
+ border-radius: 999px;
562
+ border: 1px solid var(--dsw-alias-border-l1);
563
+ background: transparent;
564
+ color: var(--dsw-alias-label-primary);
565
+ font-size: 11.5px;
566
+ padding: 0 8px;
567
+ min-width: 0;
568
+ max-width: 128px;
569
+ }
570
+
571
+ /* custom dropdown button + popup (styled replacement for native <select>) */
572
+ .composerSelect {
573
+ display: inline-flex;
574
+ align-items: center;
575
+ gap: 6px;
576
+ height: 28px;
577
+ padding: 0 8px 0 11px;
578
+ border-radius: 999px;
579
+ border: 1px solid var(--dsw-alias-border-l1);
580
+ background: transparent;
581
+ color: var(--dsw-alias-label-primary);
582
+ font-size: 11.5px;
583
+ min-width: 0;
584
+ max-width: 138px;
585
+ cursor: pointer;
586
+ transition: background 0.15s ease, border-color 0.15s ease;
587
+ }
588
+
589
+ .composerSelect:hover { background: var(--dsw-alias-interactive-bg-hover); }
590
+ .composerSelect[data-open] { border-color: var(--dsw-alias-brand-primary); color: var(--dsw-alias-brand-primary); }
591
+ .composerSelect svg { flex: none; opacity: 0.65; }
592
+ .composerSelect[data-open] svg { opacity: 0.9; }
593
+
594
+ .composerSelectValue {
595
+ overflow: hidden;
596
+ text-overflow: ellipsis;
597
+ white-space: nowrap;
598
+ min-width: 0;
599
+ }
600
+
601
+ .composerSelectMenu {
602
+ position: fixed;
603
+ z-index: 95;
604
+ max-height: 264px;
605
+ overflow: auto;
606
+ padding: 5px;
607
+ border-radius: 11px;
608
+ border: 1px solid var(--dsw-alias-border-l1);
609
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 97%, transparent);
610
+ box-shadow: 0 14px 38px rgb(15 23 42 / 18%);
611
+ backdrop-filter: blur(10px);
612
+ }
613
+
614
+ .composerSelectMenu button {
615
+ display: block;
616
+ width: 100%;
617
+ border: none;
618
+ border-radius: 7px;
619
+ background: transparent;
620
+ color: var(--dsw-alias-label-primary);
621
+ font-size: 12.5px;
622
+ line-height: 1.45;
623
+ padding: 7px 10px;
624
+ cursor: pointer;
625
+ text-align: left;
626
+ white-space: nowrap;
627
+ }
628
+
629
+ .composerSelectMenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
630
+ .composerSelectMenu button[data-selected] {
631
+ color: var(--dsw-alias-brand-primary);
632
+ background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);
633
+ }
634
+
635
+ .composerSend {
636
+ margin-left: auto;
637
+ width: 34px;
638
+ height: 34px;
639
+ flex: none;
640
+ border: none;
641
+ border-radius: 50%;
642
+ background: var(--dsw-alias-label-primary);
643
+ color: var(--dsw-alias-bg-layer-1);
644
+ cursor: pointer;
645
+ display: inline-flex;
646
+ align-items: center;
647
+ justify-content: center;
648
+ }
649
+
650
+ .composerSend:hover { opacity: 0.88; }
651
+ .composerSend:disabled { opacity: 0.35; cursor: not-allowed; }
652
+
653
+ /* ------------------------------------------------------ config node */
654
+
655
+ .configNode {
656
+ padding: 0 14px 14px;
657
+ cursor: grab;
658
+ }
659
+
660
+ .configNode .nodeHeader { padding: 10px 2px 6px; font-size: 12px; }
661
+
662
+ .configLinks {
663
+ display: flex;
664
+ align-items: center;
665
+ margin: 4px 0 10px;
666
+ flex: none;
667
+ }
668
+
669
+ .configLinks .composerChip {
670
+ font-size: 11px;
671
+ padding: 3px 10px;
672
+ }
673
+
674
+ .configHint {
675
+ flex: 1;
676
+ min-height: 0;
677
+ margin: 0;
678
+ font-size: 11.5px;
679
+ line-height: 1.7;
680
+ color: var(--dsw-alias-label-tertiary);
681
+ overflow: auto;
682
+ }
683
+
684
+ /* connection handles */
685
+
686
+ .handle {
687
+ position: absolute;
688
+ top: 50%;
689
+ width: 12px;
690
+ height: 12px;
691
+ border-radius: 50%;
692
+ transform: translateY(-50%) scale(0.6);
693
+ background: var(--dsw-alias-bg-layer-1);
694
+ border: 2px solid var(--dsw-alias-brand-primary);
695
+ opacity: 0;
696
+ transition: opacity 0.12s ease, transform 0.12s ease;
697
+ cursor: crosshair;
698
+ z-index: 3;
699
+ }
700
+
701
+ .handleLeft { left: -7px; }
702
+ .handleRight { right: -7px; }
703
+
704
+ .node:hover .handle,
705
+ .nodeSelected .handle,
706
+ .nodeConnectTarget .handle {
707
+ opacity: 1;
708
+ transform: translateY(-50%) scale(1);
709
+ }
710
+
711
+ .handle:hover { background: var(--dsw-alias-brand-primary); }
712
+
713
+ /* The source handle doubles as a quick-add button (hover opens the node
714
+ * picker, drag connects) so it reads as a Dify-style big ⊕. */
715
+ .handleRight {
716
+ display: flex;
717
+ align-items: center;
718
+ justify-content: center;
719
+ width: 20px;
720
+ height: 20px;
721
+ right: -10px;
722
+ font-size: 13px;
723
+ font-weight: 600;
724
+ line-height: 1;
725
+ color: var(--dsw-alias-brand-primary);
726
+ }
727
+
728
+ .handleRight::after { content: '+'; }
729
+
730
+ .handleRight:hover { color: var(--dsw-alias-bg-layer-1); transform: translateY(-50%) scale(1.12); }
731
+
732
+ .resizeHandle {
733
+ position: absolute;
734
+ right: -5px;
735
+ bottom: -5px;
736
+ width: 14px;
737
+ height: 14px;
738
+ border-radius: 4px;
739
+ background: var(--dsw-alias-brand-primary);
740
+ border: 2px solid var(--dsw-alias-bg-layer-1);
741
+ cursor: nwse-resize;
742
+ z-index: 3;
743
+ }
744
+
745
+ /* hover toolbar */
746
+
747
+ .hoverToolbar {
748
+ position: absolute;
749
+ top: -36px;
750
+ left: 50%;
751
+ transform: translateX(-50%);
752
+ display: flex;
753
+ gap: 2px;
754
+ padding: 4px;
755
+ border-radius: 10px;
756
+ border: 1px solid var(--dsw-alias-border-l1);
757
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);
758
+ box-shadow: 0 8px 22px rgb(15 23 42 / 14%);
759
+ opacity: 0;
760
+ pointer-events: none;
761
+ transition: opacity 0.12s ease;
762
+ z-index: 4;
763
+ }
764
+
765
+ .node:hover .hoverToolbar,
766
+ .nodeSelected .hoverToolbar {
767
+ opacity: 1;
768
+ pointer-events: auto;
769
+ }
770
+
771
+ /* -------------------------------------------------------- connections */
772
+
773
+ .connectionLayer {
774
+ position: absolute;
775
+ overflow: visible;
776
+ pointer-events: none;
777
+ z-index: 0;
778
+ }
779
+
780
+ .connectionPath {
781
+ fill: none;
782
+ stroke-width: 1.8;
783
+ stroke-opacity: 0.9;
784
+ pointer-events: none;
785
+ }
786
+
787
+ .connectionActive {
788
+ stroke-width: 2.6;
789
+ stroke-opacity: 1;
790
+ filter: drop-shadow(0 0 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, transparent));
791
+ }
792
+
793
+ .connectionPreview {
794
+ fill: none;
795
+ stroke: var(--dsw-alias-brand-primary);
796
+ stroke-width: 2;
797
+ stroke-dasharray: 5 5;
798
+ pointer-events: none;
799
+ }
800
+
801
+ /* Flow overlay: a soft light band glides from the path start (source) toward
802
+ * its end (target), echoing the direction of the gradient and arrowhead. */
803
+ .connectionFlow {
804
+ fill: none;
805
+ stroke: var(--dsw-alias-brand-primary);
806
+ stroke-width: 2;
807
+ stroke-linecap: round;
808
+ stroke-dasharray: 30 90;
809
+ opacity: 0.4;
810
+ pointer-events: none;
811
+ animation: connectionFlow 1.6s linear infinite;
812
+ }
813
+
814
+ .connectionFlowActive {
815
+ stroke: var(--dsw-alias-brand-primary);
816
+ opacity: 0.85;
817
+ }
818
+
819
+ @keyframes connectionFlow {
820
+ to { stroke-dashoffset: -120; }
821
+ }
822
+
823
+ @media (prefers-reduced-motion: reduce) {
824
+ .connectionFlow { animation: none; opacity: 0.35; }
825
+ }
826
+
827
+ /* --------------------------------------------------------- empty hint */
828
+
829
+ .emptyHint {
830
+ position: absolute;
831
+ left: 50%;
832
+ top: 44%;
833
+ transform: translate(-50%, -50%);
834
+ display: flex;
835
+ flex-direction: column;
836
+ align-items: center;
837
+ gap: 6px;
838
+ text-align: center;
839
+ color: var(--dsw-alias-label-tertiary);
840
+ pointer-events: none;
841
+ z-index: 5;
842
+ }
843
+
844
+ .emptyHint strong {
845
+ font-size: 16px;
846
+ color: var(--dsw-alias-label-secondary);
847
+ }
848
+
849
+ .emptyHint span { font-size: 12.5px; max-width: 320px; line-height: 1.6; }
850
+
851
+ /* ------------------------------------------------------------ zoom dock */
852
+
853
+ .zoomDock {
854
+ position: absolute;
855
+ left: 14px;
856
+ bottom: 14px;
857
+ z-index: 30;
858
+ display: flex;
859
+ align-items: center;
860
+ gap: 6px;
861
+ padding: 6px 8px;
862
+ border-radius: 12px;
863
+ border: 1px solid var(--dsw-alias-border-l1);
864
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 88%, transparent);
865
+ box-shadow: 0 10px 30px rgb(15 23 42 / 12%);
866
+ backdrop-filter: blur(10px);
867
+ }
868
+
869
+ .zoomDock input[type="range"] {
870
+ width: 96px;
871
+ accent-color: var(--dsw-alias-brand-primary);
872
+ }
873
+
874
+ .zoomValue {
875
+ width: 40px;
876
+ text-align: right;
877
+ font-size: 11.5px;
878
+ color: var(--dsw-alias-label-secondary);
879
+ font-variant-numeric: tabular-nums;
880
+ }
881
+
882
+ /* -------------------------------------------------------------- minimap */
883
+
884
+ .minimap {
885
+ position: absolute;
886
+ left: 14px;
887
+ bottom: 62px;
888
+ z-index: 30;
889
+ width: 220px;
890
+ height: 150px;
891
+ border-radius: 12px;
892
+ border: 1px solid var(--dsw-alias-border-l1);
893
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 88%, transparent);
894
+ box-shadow: 0 10px 30px rgb(15 23 42 / 12%);
895
+ overflow: hidden;
896
+ backdrop-filter: blur(10px);
897
+ }
898
+
899
+ .minimapCanvas {
900
+ position: relative;
901
+ width: 100%;
902
+ height: 100%;
903
+ cursor: crosshair;
904
+ }
905
+
906
+ .minimapNode {
907
+ position: absolute;
908
+ border-radius: 2px;
909
+ opacity: 0.8;
910
+ }
911
+
912
+ .minimapImage { background: var(--dsw-alias-brand-primary); }
913
+ .minimapText { background: color-mix(in srgb, var(--dsw-alias-label-primary) 40%, transparent); }
914
+ .minimapSelected { outline: 1.5px solid var(--dsw-alias-brand-primary); }
915
+
916
+ .minimapViewport {
917
+ position: absolute;
918
+ border: 1.5px solid var(--dsw-alias-brand-primary);
919
+ background: color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);
920
+ border-radius: 2px;
921
+ pointer-events: none;
922
+ }
923
+
924
+ /* ------------------------------------------------------------ inspector */
925
+
926
+ .inspectorRow {
927
+ display: flex;
928
+ gap: 8px;
929
+ }
930
+
931
+ .inspectorRow > * { flex: 1; min-width: 0; }
932
+
933
+ /* --------------------------------------------------------- context menu */
934
+
935
+ .contextMenu {
936
+ position: fixed;
937
+ z-index: 90;
938
+ min-width: 176px;
939
+ padding: 5px;
940
+ border-radius: 11px;
941
+ border: 1px solid var(--dsw-alias-border-l1);
942
+ background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
943
+ box-shadow: 0 16px 40px rgb(15 23 42 / 20%);
944
+ display: flex;
945
+ flex-direction: column;
946
+ }
947
+
948
+ .contextMenu button {
949
+ display: flex;
950
+ align-items: center;
951
+ gap: 8px;
952
+ border: none;
953
+ border-radius: 7px;
954
+ background: transparent;
955
+ color: var(--dsw-alias-label-primary);
956
+ font-size: 12.5px;
957
+ padding: 7px 10px;
958
+ cursor: pointer;
959
+ text-align: left;
960
+ }
961
+
962
+ .contextMenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
963
+ .contextMenu button[data-danger] { color: var(--dsw-alias-label-error); }
964
+
965
+ /* ---------------------------------------------------------- error toast */
966
+
967
+ .errorToast {
968
+ position: absolute;
969
+ left: 50%;
970
+ bottom: 18px;
971
+ transform: translateX(-50%);
972
+ z-index: 60;
973
+ display: flex;
974
+ align-items: center;
975
+ gap: 10px;
976
+ max-width: min(560px, 80%);
977
+ padding: 9px 12px;
978
+ border-radius: 10px;
979
+ border: 1px solid color-mix(in srgb, var(--dsw-alias-label-error) 35%, transparent);
980
+ background: color-mix(in srgb, var(--dsw-alias-label-error) 12%, var(--dsw-alias-bg-layer-1));
981
+ color: var(--dsw-alias-label-error);
982
+ font-size: 12.5px;
983
+ box-shadow: 0 12px 30px rgb(15 23 42 / 18%);
984
+ }
985
+
986
+ .errorToast button {
987
+ border: none;
988
+ background: transparent;
989
+ color: inherit;
990
+ cursor: pointer;
991
+ padding: 2px;
992
+ display: inline-flex;
993
+ flex: none;
994
+ }
995
+
996
+ /* ---------------------------------------------------------- picker modal */
997
+
998
+ .modalBackdrop {
999
+ position: absolute;
1000
+ inset: 0;
1001
+ z-index: 70;
1002
+ background: color-mix(in srgb, var(--dsw-alias-label-primary) 32%, transparent);
1003
+ display: flex;
1004
+ align-items: center;
1005
+ justify-content: center;
1006
+ }
1007
+
1008
+ .picker {
1009
+ width: min(720px, 92%);
1010
+ max-height: 84%;
1011
+ display: flex;
1012
+ flex-direction: column;
1013
+ border-radius: 14px;
1014
+ border: 1px solid var(--dsw-alias-border-l1);
1015
+ background: var(--dsw-alias-bg-layer-1);
1016
+ box-shadow: 0 24px 60px rgb(15 23 42 / 26%);
1017
+ overflow: hidden;
1018
+ }
1019
+
1020
+ .pickerHeader {
1021
+ display: flex;
1022
+ align-items: center;
1023
+ justify-content: space-between;
1024
+ padding: 12px 14px;
1025
+ font-size: 14px;
1026
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
1027
+ }
1028
+
1029
+ .pickerHeader button {
1030
+ border: none;
1031
+ background: transparent;
1032
+ color: var(--dsw-alias-label-secondary);
1033
+ font-size: 18px;
1034
+ cursor: pointer;
1035
+ padding: 0 4px;
1036
+ }
1037
+
1038
+ .pickerTabs {
1039
+ display: flex;
1040
+ gap: 4px;
1041
+ padding: 10px 14px 0;
1042
+ }
1043
+
1044
+ .pickerTabs button {
1045
+ border: none;
1046
+ border-radius: 8px 8px 0 0;
1047
+ background: transparent;
1048
+ color: var(--dsw-alias-label-secondary);
1049
+ font-size: 12.5px;
1050
+ padding: 7px 12px;
1051
+ cursor: pointer;
1052
+ }
1053
+
1054
+ .pickerTabs button[data-active] {
1055
+ background: var(--dsw-alias-interactive-bg-hover);
1056
+ color: var(--dsw-alias-brand-primary);
1057
+ }
1058
+
1059
+ .pickerBody {
1060
+ flex: 1;
1061
+ min-height: 0;
1062
+ overflow: auto;
1063
+ padding: 14px;
1064
+ }
1065
+
1066
+ .pickerGrid {
1067
+ display: grid;
1068
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
1069
+ gap: 10px;
1070
+ }
1071
+
1072
+ .pickerCard {
1073
+ display: flex;
1074
+ flex-direction: column;
1075
+ gap: 6px;
1076
+ border: 1.5px solid var(--dsw-alias-border-l1);
1077
+ border-radius: 10px;
1078
+ background: transparent;
1079
+ padding: 6px;
1080
+ cursor: pointer;
1081
+ text-align: left;
1082
+ color: var(--dsw-alias-label-primary);
1083
+ }
1084
+
1085
+ .pickerCard[data-selected] {
1086
+ border-color: var(--dsw-alias-brand-primary);
1087
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 25%, transparent);
1088
+ }
1089
+
1090
+ .pickerCard img {
1091
+ width: 100%;
1092
+ height: 110px;
1093
+ object-fit: cover;
1094
+ border-radius: 7px;
1095
+ }
1096
+
1097
+ .pickerCardPrompt {
1098
+ font-size: 11.5px;
1099
+ overflow: hidden;
1100
+ text-overflow: ellipsis;
1101
+ white-space: nowrap;
1102
+ }
1103
+
1104
+ .pickerCard small {
1105
+ color: var(--dsw-alias-label-tertiary);
1106
+ font-size: 10.5px;
1107
+ }
1108
+
1109
+ .pickerFooter {
1110
+ display: flex;
1111
+ align-items: center;
1112
+ justify-content: space-between;
1113
+ padding-top: 12px;
1114
+ font-size: 12.5px;
1115
+ color: var(--dsw-alias-label-secondary);
1116
+ }
1117
+
1118
+ .pickerFooter button,
1119
+ .generateForm button {
1120
+ height: 32px;
1121
+ padding: 0 16px;
1122
+ border: none;
1123
+ border-radius: 8px;
1124
+ background: var(--dsw-alias-brand-primary);
1125
+ color: var(--dsw-alias-bg-base, #fff);
1126
+ font-size: 12.5px;
1127
+ font-weight: 600;
1128
+ cursor: pointer;
1129
+ display: inline-flex;
1130
+ align-items: center;
1131
+ gap: 6px;
1132
+ }
1133
+
1134
+ .pickerFooter button:disabled,
1135
+ .generateForm button:disabled { opacity: 0.45; cursor: not-allowed; }
1136
+
1137
+ .uploadBox {
1138
+ display: flex;
1139
+ flex-direction: column;
1140
+ align-items: center;
1141
+ justify-content: center;
1142
+ gap: 8px;
1143
+ min-height: 220px;
1144
+ border: 1.5px dashed color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);
1145
+ border-radius: 12px;
1146
+ color: var(--dsw-alias-label-secondary);
1147
+ cursor: pointer;
1148
+ text-align: center;
1149
+ }
1150
+
1151
+ .uploadBox:hover { border-color: var(--dsw-alias-brand-primary); }
1152
+ .uploadBox input { display: none; }
1153
+ .uploadBox small { color: var(--dsw-alias-label-tertiary); font-size: 11px; }
1154
+
1155
+ .uploadIcon { color: var(--dsw-alias-brand-primary); }
1156
+
1157
+ .generateForm {
1158
+ display: flex;
1159
+ flex-direction: column;
1160
+ gap: 10px;
1161
+ }
1162
+
1163
+ .generateForm textarea {
1164
+ min-height: 110px;
1165
+ resize: vertical;
1166
+ border-radius: 9px;
1167
+ border: 1px solid var(--dsw-alias-border-l1);
1168
+ background: transparent;
1169
+ color: var(--dsw-alias-label-primary);
1170
+ font-size: 12.5px;
1171
+ padding: 8px 10px;
1172
+ outline: none;
1173
+ }
1174
+
1175
+ .generateForm select {
1176
+ height: 30px;
1177
+ border-radius: 8px;
1178
+ border: 1px solid var(--dsw-alias-border-l1);
1179
+ background: transparent;
1180
+ color: var(--dsw-alias-label-primary);
1181
+ font-size: 12.5px;
1182
+ padding: 0 8px;
1183
+ }
1184
+
1185
+ @keyframes canvasSpin {
1186
+ to { transform: rotate(360deg); }
1187
+ }