@kubex/zinc 1.1.28 → 1.1.29

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 (46) hide show
  1. package/custom-elements-manifest.config.js +2 -2
  2. package/dist/custom-elements.json +1483 -17
  3. package/dist/vscode.html-custom-data.json +40 -1
  4. package/dist/web-types.json +124 -3
  5. package/dist/zn.d.ts +670 -14
  6. package/dist/zn.min.js +1305 -925
  7. package/docs/pages/components/flow-builder-troubleshooter-demo.njk +106 -78
  8. package/docs/pages/components/flow-builder.md +422 -66
  9. package/docs/pages/components/page-builder.md +167 -0
  10. package/package.json +1 -1
  11. package/src/components/datepicker/datepicker.scss +0 -10
  12. package/src/components/flow-builder/flow-builder.component.ts +377 -16
  13. package/src/components/flow-builder/flow-builder.scss +398 -250
  14. package/src/components/flow-builder/flow-builder.test.ts +241 -4
  15. package/src/components/flow-builder/flow-layout.ts +42 -17
  16. package/src/components/flow-builder/flow.types.ts +168 -43
  17. package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.component.ts +300 -0
  18. package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.scss +222 -0
  19. package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.test.ts +125 -0
  20. package/src/components/flow-builder/modules/flow-branch-conditions/index.ts +12 -0
  21. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +184 -26
  22. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +170 -120
  23. package/src/components/flow-builder/modules/flow-node/flow-node.scss +42 -42
  24. package/src/components/flow-builder/modules/flow-step/flow-step.component.ts +2 -1
  25. package/src/components/flow-builder/modules/flow-step/flow-step.scss +25 -17
  26. package/src/components/icon-picker/icon-picker.component.ts +20 -37
  27. package/src/components/icon-picker/icon-picker.scss +5 -45
  28. package/src/components/page-builder/index.ts +14 -0
  29. package/src/components/page-builder/modules/page-palette-item/index.ts +12 -0
  30. package/src/components/page-builder/modules/page-palette-item/page-palette-item.component.ts +71 -0
  31. package/src/components/page-builder/modules/page-palette-item/page-palette-item.scss +70 -0
  32. package/src/components/page-builder/modules/page-palette-item/page-palette-item.test.ts +20 -0
  33. package/src/components/page-builder/modules/page-section-card/index.ts +12 -0
  34. package/src/components/page-builder/modules/page-section-card/page-section-card.component.ts +93 -0
  35. package/src/components/page-builder/modules/page-section-card/page-section-card.scss +92 -0
  36. package/src/components/page-builder/modules/page-section-card/page-section-card.test.ts +50 -0
  37. package/src/components/page-builder/page-builder.component.ts +1053 -0
  38. package/src/components/page-builder/page-builder.scss +494 -0
  39. package/src/components/page-builder/page-builder.test.ts +464 -0
  40. package/src/components/page-builder/page-registry.ts +48 -0
  41. package/src/components/page-builder/page.types.ts +75 -0
  42. package/src/events/events.ts +2 -0
  43. package/src/events/zn-page-change.ts +9 -0
  44. package/src/events/zn-page-selection-change.ts +7 -0
  45. package/src/zinc.ts +4 -0
  46. package/web-test-runner.config.js +6 -1
@@ -10,8 +10,11 @@
10
10
  }
11
11
 
12
12
  .builder {
13
+ --steps-width: 343px;
14
+ --side-width: 500px;
15
+
13
16
  display: grid;
14
- grid-template-columns: 343px minmax(0, 1fr) 343px;
17
+ grid-template-columns: var(--steps-width) minmax(0, 1fr) var(--side-width);
15
18
  grid-template-rows: auto minmax(0, 1fr);
16
19
  width: 100%;
17
20
  height: 100%;
@@ -19,6 +22,27 @@
19
22
  border: 1px solid rgb(var(--zn-border-color));
20
23
  border-radius: 8px;
21
24
  overflow: hidden;
25
+ transition: grid-template-columns 0.2s ease;
26
+
27
+ // Side panels tuck away via the canvas-edge chevrons. Their padding and
28
+ // border would floor the width above zero, so those collapse too.
29
+ &--steps-collapsed {
30
+ --steps-width: 0px;
31
+
32
+ .steps {
33
+ border-right: none;
34
+ }
35
+ }
36
+
37
+ &--side-collapsed {
38
+ --side-width: 0px;
39
+
40
+ .sidebar,
41
+ .inspector {
42
+ padding: 0;
43
+ border-left: none;
44
+ }
45
+ }
22
46
  }
23
47
 
24
48
  // Full-width action bar above the three panels; hidden unless actions are slotted.
@@ -54,58 +78,119 @@
54
78
  display: flex;
55
79
  flex-direction: column;
56
80
  min-height: 0;
81
+ // Clip cleanly while the column animates to zero width.
82
+ min-width: 0;
83
+ overflow: hidden;
57
84
  background: rgb(var(--zn-panel));
58
85
  }
59
86
 
60
- // Colour the slotted zn-navbar's active tab to match the steps panel surface,
61
- // rather than the navbar's default body colour.
62
- .steps {
63
- --zn-active-nav-background: var(--zn-panel);
87
+ .canvas-cell {
88
+ grid-row: 2;
89
+ position: relative;
90
+ min-width: 0;
91
+ min-height: 0;
64
92
  }
65
93
 
66
- // Left column (steps panel).
67
- .steps {
68
- border-right: 1px solid rgb(var(--zn-border-color));
69
- }
94
+ // Chevrons straddling the canvas edges — tuck a side panel away / bring it back.
95
+ .panel-toggle {
96
+ position: absolute;
97
+ top: 50%;
98
+ z-index: 6;
99
+ transform: translateY(-50%);
100
+ display: flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ width: 24px;
104
+ height: 24px;
105
+ padding: 0;
106
+ border-radius: 50%;
107
+ color: rgb(var(--zn-color-muted-text));
108
+ background: rgb(var(--zn-panel));
109
+ border: 1px solid rgb(var(--zn-border-color));
110
+ box-shadow: 0 1px 3px rgba(var(--zn-shadow), 0.4);
111
+ cursor: pointer;
112
+ transition: left 0.2s ease, right 0.2s ease, color 0.12s ease, border-color 0.12s ease;
70
113
 
71
- // Right column (version history / errors, or the node/branch editor).
72
- .sidebar,
73
- .inspector {
74
- border-left: 1px solid rgb(var(--zn-border-color));
75
- }
114
+ &:hover {
115
+ color: rgb(var(--zn-text));
116
+ border-color: rgb(var(--zn-color-border-active));
117
+ }
76
118
 
77
- // The editor slides in from the right when a node or branch is selected.
78
- .inspector {
79
- animation: inspector-in 0.18s ease;
80
- }
119
+ &--left {
120
+ left: -12px;
81
121
 
82
- @keyframes inspector-in {
83
- from {
84
- transform: translateX(32px);
85
- opacity: 0.3;
122
+ // With the panel tucked away, sit fully inside the canvas.
123
+ &.panel-toggle--tucked {
124
+ left: 8px;
125
+ }
86
126
  }
87
127
 
88
- to {
89
- transform: translateX(0);
90
- opacity: 1;
128
+ &--right {
129
+ right: -12px;
130
+
131
+ &.panel-toggle--tucked {
132
+ right: 8px;
133
+ }
91
134
  }
92
135
  }
93
136
 
94
- .canvas-cell {
95
- grid-row: 2;
96
- position: relative;
97
- min-width: 0;
98
- min-height: 0;
99
- }
137
+ // --- Steps panel (left column) -----------------------------------------------
100
138
 
101
- // --- Steps panel -----------------------------------------------------------------
139
+ .steps {
140
+ // Colour the slotted zn-navbar's active tab to match the steps panel surface,
141
+ // rather than the navbar's default body colour.
142
+ --zn-active-nav-background: var(--zn-panel);
102
143
 
103
- // The registry-driven steps panel fills the column below the title block.
104
- .steps-content {
105
- flex: 1;
106
- min-height: 0;
107
- display: flex;
108
- flex-direction: column;
144
+ border-right: 1px solid rgb(var(--zn-border-color));
145
+
146
+ // The registry-driven steps panel fills the column below the title block.
147
+ &-content {
148
+ flex: 1;
149
+ min-height: 0;
150
+ display: flex;
151
+ flex-direction: column;
152
+ }
153
+
154
+ // Each tab panel fills the zn-tabs content area and lets its category list scroll.
155
+ &-panel {
156
+ display: flex;
157
+ flex-direction: column;
158
+ min-height: 0;
159
+ height: 100%;
160
+ }
161
+
162
+ // Per-tab hint, shown beneath the tab bar with a divider before the categories.
163
+ &-hint {
164
+ margin: 0;
165
+ padding: 12px var(--zn-base-gap);
166
+ font-size: 0.8125rem;
167
+ line-height: 1.4;
168
+ color: rgb(var(--zn-color-muted-text));
169
+ }
170
+
171
+ &-scroll {
172
+ @include wc.scrollbars;
173
+ flex: 1;
174
+ min-height: 0;
175
+ overflow-y: auto;
176
+ padding-bottom: 16px;
177
+
178
+ // Divider above every category (and between the hint/tabs and the first one).
179
+ zn-flow-step-group {
180
+ display: block;
181
+ border-top: 1px solid rgb(var(--zn-border-color));
182
+ }
183
+ }
184
+
185
+ &-uncategorized {
186
+ padding: 8px var(--zn-base-gap);
187
+ }
188
+
189
+ &-empty {
190
+ padding: 16px var(--zn-base-gap);
191
+ font-size: 0.8125rem;
192
+ color: rgb(var(--zn-color-muted-text));
193
+ }
109
194
  }
110
195
 
111
196
  // Slotted <zn-flow-step>s are type declarations only — never displayed.
@@ -133,47 +218,6 @@
133
218
  padding: 12px 12px 8px;
134
219
  }
135
220
 
136
- // Each tab panel fills the zn-tabs content area and lets its category list scroll.
137
- .steps-panel {
138
- display: flex;
139
- flex-direction: column;
140
- min-height: 0;
141
- height: 100%;
142
- }
143
-
144
- // Per-tab hint, shown beneath the tab bar with a divider before the categories.
145
- .steps-hint {
146
- margin: 0;
147
- padding: 12px var(--zn-base-gap);
148
- font-size: 0.8125rem;
149
- line-height: 1.4;
150
- color: rgb(var(--zn-color-muted-text));
151
- }
152
-
153
- .steps-scroll {
154
- @include wc.scrollbars;
155
- flex: 1;
156
- min-height: 0;
157
- overflow-y: auto;
158
- padding-bottom: 16px;
159
-
160
- // Divider above every category (and between the hint/tabs and the first one).
161
- zn-flow-step-group {
162
- display: block;
163
- border-top: 1px solid rgb(var(--zn-border-color));
164
- }
165
- }
166
-
167
- .steps-uncategorized {
168
- padding: 8px var(--zn-base-gap);
169
- }
170
-
171
- .steps-empty {
172
- padding: 16px var(--zn-base-gap);
173
- font-size: 0.8125rem;
174
- color: rgb(var(--zn-color-muted-text));
175
- }
176
-
177
221
  .step {
178
222
  display: flex;
179
223
  align-items: center;
@@ -217,188 +261,201 @@
217
261
  }
218
262
  }
219
263
 
220
- // --- Inspector ---------------------------------------------------------------
264
+ // --- Inspector (right column while a node / branch is selected) ---------------
221
265
 
222
- .inspector-empty {
223
- display: flex;
224
- flex-direction: column;
225
- align-items: center;
226
- justify-content: center;
227
- gap: 10px;
228
- height: 100%;
229
- padding: 24px;
230
- text-align: center;
231
- color: rgb(var(--zn-color-muted-text));
232
- font-size: 0.8125rem;
233
- }
234
-
235
- .inspector-head {
236
- display: flex;
237
- align-items: center;
238
- gap: 12px;
239
- padding: 16px;
240
- border-bottom: 1px solid rgb(var(--zn-border-color));
266
+ .inspector {
267
+ border-left: 1px solid rgb(var(--zn-border-color));
268
+ // The editor slides in from the right when a node or branch is selected.
269
+ animation: inspector-in 0.18s ease;
241
270
 
242
- &__icon {
243
- --node-accent: rgb(var(--zn-color-primary));
271
+ &-empty {
244
272
  display: flex;
273
+ flex-direction: column;
245
274
  align-items: center;
246
275
  justify-content: center;
247
- flex: 0 0 auto;
248
- width: 36px;
249
- height: 36px;
250
- border-radius: 8px;
251
- color: var(--node-accent);
252
- background: color-mix(in srgb, var(--node-accent) 14%, transparent);
253
- }
254
-
255
- // Long labels truncate rather than pushing the close button out of the panel.
256
- &__text {
257
- flex: 1;
258
- min-width: 0;
276
+ gap: 10px;
277
+ height: 100%;
278
+ padding: 24px;
279
+ text-align: center;
280
+ color: rgb(var(--zn-color-muted-text));
281
+ font-size: 0.8125rem;
259
282
  }
260
283
 
261
- // Title + badges (e.g. the Loop tag) on one line: the title shrinks with an
262
- // ellipsis while the badge always stays visible.
263
- &__title-row {
284
+ &-head {
264
285
  display: flex;
265
286
  align-items: center;
266
- gap: 6px;
267
- min-width: 0;
287
+ gap: 12px;
288
+ padding: 16px;
289
+ border-bottom: 1px solid rgb(var(--zn-border-color));
290
+
291
+ &__icon {
292
+ --node-accent: rgb(var(--zn-color-primary));
293
+ display: flex;
294
+ align-items: center;
295
+ justify-content: center;
296
+ flex: 0 0 auto;
297
+ width: 36px;
298
+ height: 36px;
299
+ border-radius: 8px;
300
+ color: var(--node-accent);
301
+ background: color-mix(in srgb, var(--node-accent) 14%, transparent);
302
+ }
268
303
 
269
- .inspector-head__title {
304
+ // Long labels truncate rather than pushing the close button out of the panel.
305
+ &__text {
306
+ flex: 1;
270
307
  min-width: 0;
271
308
  }
272
- }
273
309
 
274
- &__title {
275
- font-size: 0.875rem;
276
- font-weight: 600;
310
+ // Title + badges (e.g. the Loop tag) on one line: the title shrinks with an
311
+ // ellipsis while the badge always stays visible.
312
+ &__title-row {
313
+ display: flex;
314
+ align-items: center;
315
+ gap: 6px;
316
+ min-width: 0;
317
+
318
+ .inspector-head__title {
319
+ min-width: 0;
320
+ }
321
+ }
322
+
323
+ &__title {
324
+ font-size: 0.875rem;
325
+ font-weight: 600;
326
+ }
327
+
328
+ &__title,
329
+ &__type {
330
+ overflow: hidden;
331
+ text-overflow: ellipsis;
332
+ white-space: nowrap;
333
+ }
334
+
335
+ &__type {
336
+ font-size: 0.75rem;
337
+ color: rgb(var(--zn-color-muted-text));
338
+ }
277
339
  }
278
340
 
279
- &__title,
280
- &__type {
281
- overflow: hidden;
282
- text-overflow: ellipsis;
283
- white-space: nowrap;
341
+ &-body {
342
+ @include wc.scrollbars;
343
+ display: flex;
344
+ flex-direction: column;
345
+ gap: 14px;
346
+ flex: 1;
347
+ min-height: 0;
348
+ overflow-y: auto;
349
+ padding: 16px;
284
350
  }
285
351
 
286
- &__type {
352
+ &-hint {
353
+ margin: 0;
287
354
  font-size: 0.75rem;
288
355
  color: rgb(var(--zn-color-muted-text));
289
356
  }
290
- }
291
357
 
292
- .inspector-body {
293
- @include wc.scrollbars;
294
- display: flex;
295
- flex-direction: column;
296
- gap: 14px;
297
- flex: 1;
298
- min-height: 0;
299
- overflow-y: auto;
300
- padding: 16px;
301
- }
358
+ // Marks a loop branch in the editor head, matching its amber pill and wire.
359
+ &-loop-tag {
360
+ display: inline-flex;
361
+ align-items: center;
362
+ flex: 0 0 auto;
363
+ gap: 3px;
364
+ padding: 2px 8px;
365
+ border-radius: 999px;
366
+ font-size: 0.6875rem;
367
+ font-weight: 600;
368
+ line-height: 1;
369
+ color: rgb(var(--zn-color-warning));
370
+ background: color-mix(in srgb, rgb(var(--zn-color-warning)) 14%, transparent);
371
+ }
302
372
 
303
- .inspector-hint {
304
- margin: 0;
305
- font-size: 0.75rem;
306
- color: rgb(var(--zn-color-muted-text));
307
- }
373
+ &-close {
374
+ display: flex;
375
+ align-items: center;
376
+ justify-content: center;
377
+ flex: 0 0 auto;
378
+ margin-left: auto;
379
+ width: 28px;
380
+ height: 28px;
381
+ padding: 0;
382
+ border-radius: 6px;
383
+ color: rgb(var(--zn-color-muted-text));
384
+ background: transparent;
385
+ cursor: pointer;
308
386
 
309
- // Marks a loop branch in the editor head, matching its amber pill and wire.
310
- .inspector-loop-tag {
311
- display: inline-flex;
312
- align-items: center;
313
- flex: 0 0 auto;
314
- gap: 3px;
315
- padding: 2px 8px;
316
- border-radius: 999px;
317
- font-size: 0.6875rem;
318
- font-weight: 600;
319
- line-height: 1;
320
- color: rgb(var(--zn-color-warning));
321
- background: color-mix(in srgb, rgb(var(--zn-color-warning)) 14%, transparent);
387
+ &:hover {
388
+ background: rgb(var(--zn-color-tab));
389
+ color: rgb(var(--zn-text));
390
+ }
391
+ }
322
392
  }
323
393
 
324
- .inspector-close {
325
- display: flex;
326
- align-items: center;
327
- justify-content: center;
328
- flex: 0 0 auto;
329
- margin-left: auto;
330
- width: 28px;
331
- height: 28px;
332
- padding: 0;
333
- border-radius: 6px;
334
- color: rgb(var(--zn-color-muted-text));
335
- background: transparent;
336
- cursor: pointer;
394
+ @keyframes inspector-in {
395
+ from {
396
+ transform: translateX(32px);
397
+ opacity: 0.3;
398
+ }
337
399
 
338
- &:hover {
339
- background: rgb(var(--zn-color-tab));
340
- color: rgb(var(--zn-text));
400
+ to {
401
+ transform: translateX(0);
402
+ opacity: 1;
341
403
  }
342
404
  }
343
405
 
344
- // --- Sidebar (right rail) ----------------------------------------------------
406
+ // --- Sidebar (right rail: status / errors / version history) ------------------
345
407
 
346
408
  .sidebar {
347
409
  @include wc.scrollbars;
410
+ border-left: 1px solid rgb(var(--zn-border-color));
348
411
  overflow-y: auto;
349
412
  padding: 16px;
350
- }
351
413
 
352
- .sidebar-section__head {
353
- display: flex;
354
- align-items: center;
355
- justify-content: space-between;
356
- margin-bottom: 10px;
357
- font-size: 0.8125rem;
358
- font-weight: 600;
359
- }
414
+ &-section__head {
415
+ display: flex;
416
+ align-items: center;
417
+ justify-content: space-between;
418
+ margin-bottom: 10px;
419
+ font-size: 0.8125rem;
420
+ font-weight: 600;
421
+ }
360
422
 
361
- .sidebar-count {
362
- min-width: 20px;
363
- padding: 0 6px;
364
- font-size: 0.75rem;
365
- line-height: 18px;
366
- text-align: center;
367
- border-radius: 9px;
368
- color: rgb(var(--zn-color-muted-text));
369
- background: rgb(var(--zn-color-tab));
370
- }
423
+ &-count {
424
+ min-width: 20px;
425
+ padding: 0 6px;
426
+ font-size: 0.75rem;
427
+ line-height: 18px;
428
+ text-align: center;
429
+ border-radius: 9px;
430
+ color: rgb(var(--zn-color-muted-text));
431
+ background: rgb(var(--zn-color-tab));
432
+ }
371
433
 
372
- .sidebar-empty {
373
- margin: 0;
374
- font-size: 0.75rem;
375
- color: rgb(var(--zn-color-muted-text));
376
- }
434
+ &-empty {
435
+ margin: 0;
436
+ font-size: 0.75rem;
437
+ color: rgb(var(--zn-color-muted-text));
438
+ }
377
439
 
378
- .sidebar-error {
379
- display: flex;
380
- align-items: center;
381
- gap: 8px;
382
- width: 100%;
383
- margin-bottom: 6px;
384
- padding: 8px 10px;
385
- font-size: 0.8125rem;
386
- text-align: left;
387
- color: rgb(var(--zn-color-error));
388
- background: color-mix(in srgb, rgb(var(--zn-color-error)) 7%, transparent);
389
- border: 1px solid color-mix(in srgb, rgb(var(--zn-color-error)) 25%, transparent);
390
- border-radius: 8px;
391
- cursor: pointer;
440
+ &-error {
441
+ display: flex;
442
+ align-items: center;
443
+ gap: 8px;
444
+ width: 100%;
445
+ margin-bottom: 6px;
446
+ padding: 8px 10px;
447
+ font-size: 0.8125rem;
448
+ text-align: left;
449
+ color: rgb(var(--zn-color-error));
450
+ background: color-mix(in srgb, rgb(var(--zn-color-error)) 7%, transparent);
451
+ border: 1px solid color-mix(in srgb, rgb(var(--zn-color-error)) 25%, transparent);
452
+ border-radius: 8px;
453
+ cursor: pointer;
454
+ }
392
455
  }
393
456
 
394
457
  // --- "+" picker popover ------------------------------------------------------
395
458
 
396
- .picker-backdrop {
397
- position: fixed;
398
- inset: 0;
399
- z-index: 20;
400
- }
401
-
402
459
  .picker {
403
460
  position: fixed;
404
461
  z-index: 21;
@@ -411,52 +468,143 @@
411
468
  border-radius: 8px;
412
469
  box-shadow: 0 6px 24px rgba(var(--zn-shadow), 0.5);
413
470
  @include wc.scrollbars;
471
+
472
+ &-backdrop {
473
+ position: fixed;
474
+ inset: 0;
475
+ z-index: 20;
476
+ }
477
+
478
+ &-group {
479
+ padding: 8px 8px 4px;
480
+ font-size: 0.6875rem;
481
+ font-weight: 600;
482
+ text-transform: uppercase;
483
+ letter-spacing: 0.04em;
484
+ color: rgb(var(--zn-color-muted-text));
485
+ }
486
+
487
+ &-item {
488
+ display: flex;
489
+ align-items: center;
490
+ gap: 10px;
491
+ width: 100%;
492
+ padding: 7px 8px;
493
+ font-size: 0.8125rem;
494
+ text-align: left;
495
+ background: transparent;
496
+ border-radius: 6px;
497
+ cursor: pointer;
498
+
499
+ &:hover {
500
+ background: rgb(var(--zn-color-tab));
501
+ }
502
+
503
+ &__icon {
504
+ --node-accent: rgb(var(--zn-color-primary));
505
+ display: flex;
506
+ align-items: center;
507
+ justify-content: center;
508
+ flex: 0 0 auto;
509
+ width: 26px;
510
+ height: 26px;
511
+ border-radius: 6px;
512
+ color: var(--node-accent);
513
+ background: color-mix(in srgb, var(--node-accent) 14%, transparent);
514
+ }
515
+ }
516
+
517
+ &-empty {
518
+ margin: 0;
519
+ padding: 10px;
520
+ font-size: 0.75rem;
521
+ color: rgb(var(--zn-color-muted-text));
522
+ }
414
523
  }
415
524
 
416
- .picker-group {
417
- padding: 8px 8px 4px;
418
- font-size: 0.6875rem;
419
- font-weight: 600;
420
- text-transform: uppercase;
421
- letter-spacing: 0.04em;
525
+ // --- Auto-save overlays --------------------------------------------------------
526
+
527
+ // Bottom-left status pill: flashes green as a save lands, then keeps a quiet
528
+ // "last saved Xm ago".
529
+ .save-status {
530
+ position: absolute;
531
+ left: 16px;
532
+ bottom: 16px;
533
+ z-index: 5;
534
+ display: flex;
535
+ align-items: center;
536
+ gap: 6px;
537
+ padding: 5px 10px;
538
+ font-size: 0.75rem;
422
539
  color: rgb(var(--zn-color-muted-text));
540
+ background: rgb(var(--zn-panel));
541
+ border: 1px solid rgb(var(--zn-border-color));
542
+ border-radius: 8px;
543
+ box-shadow: 0 1px 3px rgba(var(--zn-shadow), 0.4);
544
+ pointer-events: none;
545
+ transition: color 0.15s ease, border-color 0.15s ease;
546
+
547
+ &--saved {
548
+ color: rgb(var(--zn-color-success));
549
+ border-color: color-mix(in srgb, rgb(var(--zn-color-success)) 45%, transparent);
550
+ }
423
551
  }
424
552
 
425
- .picker-item {
553
+ // Top-centre prompt offering a differing auto-saved draft after a load.
554
+ .restore-banner {
555
+ position: absolute;
556
+ top: 16px;
557
+ left: 50%;
558
+ transform: translateX(-50%);
559
+ z-index: 5;
426
560
  display: flex;
427
561
  align-items: center;
428
- gap: 10px;
429
- width: 100%;
430
- padding: 7px 8px;
562
+ // On a narrow canvas the message keeps sensible line lengths and the
563
+ // buttons wrap below it, instead of squeezing to a word per line.
564
+ flex-wrap: wrap;
565
+ justify-content: center;
566
+ gap: 8px;
567
+ width: max-content;
568
+ max-width: calc(100% - 32px);
569
+ padding: 8px 12px;
431
570
  font-size: 0.8125rem;
432
- text-align: left;
433
- background: transparent;
434
- border-radius: 6px;
435
- cursor: pointer;
571
+ color: rgb(var(--zn-text));
572
+ background: rgb(var(--zn-panel));
573
+ border: 1px solid rgb(var(--zn-border-color));
574
+ border-radius: 8px;
575
+ box-shadow: 0 2px 8px rgba(var(--zn-shadow), 0.5);
436
576
 
437
- &:hover {
438
- background: rgb(var(--zn-color-tab));
577
+ span {
578
+ flex: 1 1 auto;
579
+ min-width: min(160px, 100%);
439
580
  }
440
581
 
441
- &__icon {
442
- --node-accent: rgb(var(--zn-color-primary));
443
- display: flex;
444
- align-items: center;
445
- justify-content: center;
582
+ button {
446
583
  flex: 0 0 auto;
447
- width: 26px;
448
- height: 26px;
584
+ padding: 3px 10px;
585
+ font-size: 0.75rem;
586
+ font-weight: 600;
449
587
  border-radius: 6px;
450
- color: var(--node-accent);
451
- background: color-mix(in srgb, var(--node-accent) 14%, transparent);
588
+ cursor: pointer;
452
589
  }
453
- }
454
590
 
455
- .picker-empty {
456
- margin: 0;
457
- padding: 10px;
458
- font-size: 0.75rem;
459
- color: rgb(var(--zn-color-muted-text));
591
+ &__restore {
592
+ color: rgb(var(--zn-panel));
593
+ background: rgb(var(--zn-color-primary));
594
+
595
+ &:hover {
596
+ filter: brightness(1.1);
597
+ }
598
+ }
599
+
600
+ &__dismiss {
601
+ color: rgb(var(--zn-color-muted-text));
602
+ background: transparent;
603
+
604
+ &:hover {
605
+ background: rgb(var(--zn-color-tab));
606
+ }
607
+ }
460
608
  }
461
609
 
462
610
  // --- Move banner -------------------------------------------------------------