@esfaenza/dpe-builder 20.3.1 → 20.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  /*
2
- * Tema dell'editor DPE — da includere negli `styles` dell'applicazione ospite, in
3
- * quest'ordine:
2
+ * Foglio di stile **unico** dell'editor DPE.
3
+ *
4
+ * Uso: si collega una volta, in quest'ordine, e non serve altro.
4
5
  *
5
6
  * "styles": [
6
7
  * "node_modules/@foblex/flow/styles/default.scss",
@@ -8,19 +9,32 @@
8
9
  * "src/styles.css"
9
10
  * ]
10
11
  *
11
- * Contiene **soltanto** le due cose che non possono stare nel CSS incapsulato dei componenti:
12
+ * Niente incapsulamento, niente `:host`, niente `::ng-deep`, niente `!important`: CSS standard
13
+ * con selettori di classe e di elemento, che si legge e funziona identico dentro e fuori Angular.
14
+ * I componenti non dichiarano `styles` ne' `styleUrl` — tutte le regole stanno qui.
12
15
  *
13
- * 1. le variabili di tema, cosi' l'app ospite le sovrascrive per integrarsi nel proprio
14
- * design system senza toccare la libreria (compresi i token `--ff-*` di @foblex/flow,
15
- * che si ritematizza **cosi'** e non sovrascrivendone le regole: hanno la stessa
16
- * specificita' delle nostre e chi vince dipenderebbe dall'ordine di caricamento dei
17
- * fogli nell'host);
18
- * 2. gli stili degli archi: i path SVG delle connessioni sono creati a runtime da
19
- * @foblex/flow e non portano l'attributo di scope Angular, quindi un selettore scoped non
20
- * li raggiunge mai.
16
+ * Regole della casa, per non perdere la semplicita' al primo ritocco:
21
17
  *
22
- * Tutto il resto e' component-scoped. Se un giorno servisse davvero un controllo condiviso
23
- * qui, va motivato in commento.
18
+ * 1. **Ogni** classe comincia per `dpe-`: e' l'unica cosa che tiene separato questo foglio da
19
+ * quello dell'app ospite, ora che non c'e' piu' un incapsulamento a farlo.
20
+ * 2. Nessun selettore di elemento nudo. Un elemento si stila sempre dentro un contenitore
21
+ * nostro (`dpe-sql-preview pre`), altrimenti la regola esce dall'editor.
22
+ * 3. Colori solo attraverso i token `--dpe-*`: un colore cablato resta invisibile fino al primo
23
+ * tema scuro.
24
+ * 4. L'ordine dei blocchi conta: dove due regole hanno la stessa specificita' decide l'ordine,
25
+ * e i punti in cui questo e' voluto sono segnalati in commento.
26
+ * 5. Dove si contende un elemento con @foblex/flow, il selettore **dichiara** di che specificita'
27
+ * ha bisogno (`dpe-canvas .dpe-flow .dpe-node`, non `.dpe-node`). Con l'incapsulamento
28
+ * vincevamo per via dell'attributo di scope che Angular aggiungeva ai selettori: era una
29
+ * specificita' regalata dal framework, e senza di essa la card del nodo tornava larga 120px
30
+ * e centrata. Il conto va fatto, non sperato: vedi la sezione «canvas».
31
+ */
32
+
33
+ /* ==================================================================== token */
34
+ /*
35
+ * `.dpe-builder` e' la radice dell'editor, `.dpe-theme` quella di un componente usato da solo
36
+ * (il catalogo). Sono le due classi su cui l'app ospite sovrascrive i token per entrare nel
37
+ * proprio design system, senza toccare la libreria.
24
38
  */
25
39
 
26
40
  .dpe-builder,
@@ -94,7 +108,9 @@
94
108
 
95
109
  /*
96
110
  * I token di @foblex/flow allineati ai nostri: canvas, sfondo, minimappa e spessore degli
97
- * archi li disegna la libreria, e questo e' il punto previsto per ritematizzarli.
111
+ * archi li disegna la libreria, e questo e' il punto previsto per ritematizzarli. Si passa
112
+ * dalle variabili e **non** dalle sue regole: quelle hanno la stessa specificita' delle
113
+ * nostre e chi vince dipenderebbe dall'ordine dei fogli nell'app ospite.
98
114
  */
99
115
  --ff-canvas-background-color: var(--dpe-canvas-bg);
100
116
  --ff-flow-background-color: var(--dpe-canvas-bg);
@@ -110,17 +126,19 @@
110
126
  --ff-minimap-view-border-color: var(--dpe-accent);
111
127
  }
112
128
 
129
+ /* =============================================================== tema scuro */
113
130
  /*
114
131
  * Variante scura: si attiva con `data-dpe-theme="dark"` sul contenitore e ridefinisce i **soli
115
132
  * token**.
116
133
  *
117
- * I selettori sono tre e non uno per una ragione di cascata, non di gusto: se l'attributo sta su
118
- * un **antenato** dell'editor (il caso normale: l'ospite lo mette sul proprio contenitore), la
134
+ * I selettori sono cinque e non uno per una ragione di cascata, non di gusto: se l'attributo sta
135
+ * su un **antenato** dell'editor (il caso normale: l'ospite lo mette sul proprio contenitore), la
119
136
  * regola `.dpe-builder` qui sopra riassegna i token chiari **sull'elemento stesso** e vince sui
120
- * valori scuri ereditati. Il risultato e' un tema a metà — testo chiaro su superfici chiare, cioe'
121
- * illeggibile. `[data-dpe-theme='dark'] .dpe-builder` ha specificita' (0,2,0) e batte `.dpe-builder`
122
- * (0,1,0); l'ultimo selettore copre il caso in cui l'attributo sia sulla radice dell'editor.
137
+ * valori scuri ereditati. Il risultato e' un tema a meta' — testo chiaro su superfici chiare,
138
+ * cioe' illeggibile. `[data-dpe-theme='dark'] .dpe-builder` ha specificita' (0,2,0) e batte
139
+ * `.dpe-builder` (0,1,0); gli ultimi due coprono il caso in cui l'attributo stia sulla radice.
123
140
  */
141
+
124
142
  [data-dpe-theme='dark'],
125
143
  [data-dpe-theme='dark'] .dpe-builder,
126
144
  [data-dpe-theme='dark'] .dpe-theme,
@@ -163,7 +181,721 @@
163
181
  --dpe-shadow-lg: 0 18px 44px rgb(0 0 0 / 55%);
164
182
  }
165
183
 
166
- /* ---------------------------------------------------------------- archi */
184
+ /* ========================================================= famiglie di nodo */
185
+ /*
186
+ * Un blocco solo per i tre posti che mostrano un nodo (card sul canvas, voce della palette, testa
187
+ * dell'ispettore): la classe la calcola `dpeNodeIconFamilyClass()` e assegna i due token che la
188
+ * pastiglia dell'icona legge. Prima era ripetuto identico in tre fogli incapsulati — e' il
189
+ * genere di duplicazione che il foglio unico elimina.
190
+ */
191
+
192
+ .dpe-family--source {
193
+ --dpe-cat: var(--dpe-cat-source, #2f7d8f);
194
+ --dpe-cat-soft: var(--dpe-cat-source-soft, #dbecf0);
195
+ }
196
+
197
+ .dpe-family--transform {
198
+ --dpe-cat: var(--dpe-cat-transform, #3b6fd4);
199
+ --dpe-cat-soft: var(--dpe-cat-transform-soft, #e2eafb);
200
+ }
201
+
202
+ .dpe-family--sink {
203
+ --dpe-cat: var(--dpe-cat-sink, #1c8a5c);
204
+ --dpe-cat-soft: var(--dpe-cat-sink-soft, #dcf1e8);
205
+ }
206
+
207
+ .dpe-family--uncompilable {
208
+ --dpe-cat: var(--dpe-cat-uncompilable, #7c5cd6);
209
+ --dpe-cat-soft: var(--dpe-cat-uncompilable-soft, #ebe6fa);
210
+ }
211
+
212
+ /* ================================================================== guscio */
213
+ /*
214
+ * L'elemento del componente radice. Prima era un `:host`: e' lo stesso selettore, scritto in CSS
215
+ * standard — il tag di un componente e' un elemento come un altro.
216
+ */
217
+
218
+ dpe-builder {
219
+ display: block;
220
+ width: 100%;
221
+ /*
222
+ * `100%` di un contenitore che l'ospite dimensiona, ma **mai** piu' alto di quello: senza il
223
+ * `max-height`, un ospite che monta l'editor in un contenitore ad altezza automatica lo
224
+ * lascerebbe crescere quanto il contenuto, e i pannelli inferiori finirebbero fuori schermo.
225
+ */
226
+ height: 100%;
227
+ max-height: 100%;
228
+ min-height: 0;
229
+ overflow: hidden;
230
+ }
231
+
232
+ /*
233
+ * Colonna flex e **non** una griglia a righe percentuali.
234
+ *
235
+ * Con `grid-template-rows: … minmax(200px, 34%)` il pannello inferiore restava vuoto pur avendo
236
+ * le righe nel DOM: la percentuale si risolve contro l'altezza del contenitore e il contributo
237
+ * automatico di un'area scorrevole (`overflow: auto`) al dimensionamento della traccia e' **zero**,
238
+ * quindi bastava un anello indefinito nella catena delle altezze per far collassare la riga.
239
+ * Nella colonna flex l'altezza del pannello e' dichiarata in pixel (`flex-basis`) e non dipende
240
+ * da nessuna percentuale: e' il difetto che si vede solo guardando, e la forma robusta e' questa.
241
+ *
242
+ * `min-height: 0` su ogni contenitore di un'area scorrevole non e' rumore: senza, un elemento
243
+ * flex si rifiuta di rimpicciolirsi sotto il proprio contenuto e l'area scorrevole sfonda il
244
+ * guscio invece di scorrere.
245
+ *
246
+ * Colore e font stanno qui e non sull'elemento `dpe-builder`: e' lo stesso elemento che porta
247
+ * `.dpe-builder`, cioe' quello dove i token sono definiti, quindi `var(--dpe-text)` si risolve
248
+ * sempre — anche quando nessun antenato dichiara il tema.
249
+ */
250
+ .dpe-shell {
251
+ display: flex;
252
+ flex-direction: column;
253
+ width: 100%;
254
+ height: 100%;
255
+ min-height: 0;
256
+ overflow: hidden;
257
+ background: var(--dpe-surface-alt, #f7f8fa);
258
+ color: var(--dpe-text, #1a1c23);
259
+ font: inherit;
260
+ }
261
+
262
+ /* --------------------------------------------------------------------- barra */
263
+
264
+ .dpe-shell__bar {
265
+ display: flex;
266
+ flex: 0 0 auto;
267
+ align-items: center;
268
+ gap: 16px;
269
+ padding: 8px 12px;
270
+ border-bottom: 1px solid var(--dpe-border, #e2e5eb);
271
+ background: var(--dpe-surface, #fff);
272
+ }
273
+
274
+ .dpe-shell__title {
275
+ display: flex;
276
+ align-items: baseline;
277
+ gap: 8px;
278
+ min-width: 0;
279
+ }
280
+
281
+ .dpe-shell__sub,
282
+ .dpe-shell__label {
283
+ color: var(--dpe-text-muted, #6b7086);
284
+ font-size: 11px;
285
+ }
286
+
287
+ /*
288
+ * Indicatore di stato sporco. Colore **e** simbolo: il colore da solo non basta a distinguere
289
+ * due stati per chi non lo percepisce, e questo e' l'indicatore su cui si decide se salvare.
290
+ */
291
+ .dpe-shell__dirty {
292
+ flex: 0 0 auto;
293
+ color: var(--dpe-text-subtle, #98a2b3);
294
+ font-size: 11px;
295
+ white-space: nowrap;
296
+ }
297
+
298
+ .dpe-shell__dirty--on {
299
+ color: var(--dpe-warning, #b7791f);
300
+ font-weight: 600;
301
+ }
302
+
303
+ .dpe-shell__group {
304
+ display: flex;
305
+ align-items: center;
306
+ gap: 6px;
307
+ }
308
+
309
+ .dpe-shell__status {
310
+ margin-left: auto;
311
+ }
312
+
313
+ /*
314
+ * Il gruppo del comando primario si stacca dagli altri: un separatore verticale e un margine,
315
+ * perche' «Salva» scrive mentre annulla/ripeti/riordina disfano. Accostarli li fa pesare uguale,
316
+ * che e' il difetto rilevato.
317
+ */
318
+ .dpe-shell__group--primary {
319
+ padding-left: 14px;
320
+ border-left: 1px solid var(--dpe-border, #e2e5eb);
321
+ }
322
+
323
+ /* Badge del dialetto: in sola lettura, quindi non ha ne' bordo cliccabile ne' cursore. */
324
+ .dpe-shell__dialect {
325
+ flex: 0 0 auto;
326
+ padding: 3px 8px;
327
+ border: 1px solid var(--dpe-border, #e2e5eb);
328
+ border-radius: 999px;
329
+ background: var(--dpe-surface-alt, #f7f8fa);
330
+ color: var(--dpe-text-muted, #6b7086);
331
+ font-size: 11px;
332
+ white-space: nowrap;
333
+ cursor: help;
334
+ }
335
+
336
+ .dpe-shell__dialect strong {
337
+ color: var(--dpe-text, #1a1c23);
338
+ }
339
+
340
+ /* Avviso transitorio del salvataggio riuscito. */
341
+ .dpe-shell__toast {
342
+ flex: 0 0 auto;
343
+ padding: 2px 8px;
344
+ border: 1px solid var(--dpe-success, #22a06b);
345
+ border-radius: 999px;
346
+ color: var(--dpe-success, #22a06b);
347
+ font-size: 11px;
348
+ font-weight: 600;
349
+ white-space: nowrap;
350
+ }
351
+
352
+ .dpe-shell__btn {
353
+ padding: 4px 9px;
354
+ border: 1px solid var(--dpe-border, #e2e5eb);
355
+ border-radius: var(--dpe-radius-xs, 6px);
356
+ background: var(--dpe-surface, #fff);
357
+ color: var(--dpe-text, #1a1c23);
358
+ font: inherit;
359
+ font-size: 11px;
360
+ cursor: pointer;
361
+ }
362
+
363
+ .dpe-shell__btn:hover:not(:disabled) {
364
+ background: var(--dpe-surface-alt, #f7f8fa);
365
+ }
366
+
367
+ .dpe-shell__btn:disabled {
368
+ opacity: 0.45;
369
+ cursor: not-allowed;
370
+ }
371
+
372
+ .dpe-shell__btn--primary {
373
+ border-color: var(--dpe-accent, #2f7d8f);
374
+ background: var(--dpe-accent, #2f7d8f);
375
+ color: var(--dpe-accent-contrast, #fff);
376
+ }
377
+
378
+ .dpe-shell__btn--primary:hover:not(:disabled) {
379
+ border-color: var(--dpe-accent-strong, #226270);
380
+ background: var(--dpe-accent-strong, #226270);
381
+ }
382
+
383
+ .dpe-shell__pill {
384
+ padding: 2px 8px;
385
+ border: 1px solid var(--dpe-border, #e2e5eb);
386
+ border-radius: 999px;
387
+ background: var(--dpe-surface-alt, #f7f8fa);
388
+ color: var(--dpe-text-muted, #6b7086);
389
+ font-size: 11px;
390
+ }
391
+
392
+ .dpe-shell__pill--ok {
393
+ border-color: var(--dpe-success, #22a06b);
394
+ color: var(--dpe-success, #22a06b);
395
+ }
396
+
397
+ .dpe-shell__pill--error {
398
+ border-color: var(--dpe-error, #dc2626);
399
+ color: var(--dpe-error, #dc2626);
400
+ }
401
+
402
+ .dpe-shell__pill--busy {
403
+ border-color: var(--dpe-info, #3b6fd4);
404
+ color: var(--dpe-info, #3b6fd4);
405
+ }
406
+
407
+ /* Banner di riga intera: disallineamento del dialetto, salvataggio fallito. Non e' un tooltip. */
408
+ .dpe-shell__warn {
409
+ display: flex;
410
+ flex: 0 0 auto;
411
+ flex-direction: column;
412
+ gap: 6px;
413
+ padding: 10px 12px;
414
+ border-bottom: 1px solid var(--dpe-warning, #b7791f);
415
+ background: color-mix(in srgb, var(--dpe-warning, #b7791f) 10%, var(--dpe-surface, #fff));
416
+ font-size: 12px;
417
+ }
418
+
419
+ .dpe-shell__warn--error {
420
+ border-bottom-color: var(--dpe-error, #dc2626);
421
+ background: color-mix(in srgb, var(--dpe-error, #dc2626) 8%, var(--dpe-surface, #fff));
422
+ }
423
+
424
+ .dpe-shell__warn p {
425
+ margin: 0;
426
+ line-height: 1.5;
427
+ }
428
+
429
+ /* ---------------------------------------------------------------------- corpo */
430
+
431
+ .dpe-shell__body {
432
+ display: grid;
433
+ flex: 1 1 auto;
434
+ grid-template-columns: 210px minmax(0, 1fr) 340px;
435
+ min-height: 0;
436
+ border-bottom: 1px solid var(--dpe-border, #e2e5eb);
437
+ }
438
+
439
+ .dpe-shell__palette,
440
+ .dpe-shell__inspector {
441
+ min-height: 0;
442
+ max-height: 100%;
443
+ }
444
+
445
+ .dpe-shell__inspector {
446
+ border-left: 1px solid var(--dpe-border, #e2e5eb);
447
+ background: var(--dpe-surface, #fff);
448
+ }
449
+
450
+ /* Il canvas ha bisogno di un'altezza esplicita, e in una griglia la prende dalla riga. */
451
+ .dpe-shell__canvas {
452
+ min-width: 0;
453
+ min-height: 0;
454
+ height: 100%;
455
+ }
456
+
457
+ /* ------------------------------------------------------------------ pannelli */
458
+
459
+ /* Altezza in pixel: e' cio' che rende il pannello indipendente dalla catena delle percentuali. */
460
+ .dpe-shell__bottom {
461
+ display: flex;
462
+ flex: 0 0 280px;
463
+ flex-direction: column;
464
+ min-height: 0;
465
+ background: var(--dpe-surface, #fff);
466
+ }
467
+
468
+ .dpe-shell__tabs {
469
+ display: flex;
470
+ flex: 0 0 auto;
471
+ gap: 2px;
472
+ padding: 0 8px;
473
+ border-bottom: 1px solid var(--dpe-border, #e2e5eb);
474
+ background: var(--dpe-surface-alt, #f7f8fa);
475
+ }
476
+
477
+ .dpe-shell__tab {
478
+ padding: 6px 10px;
479
+ border: 0;
480
+ border-bottom: 2px solid transparent;
481
+ background: transparent;
482
+ color: var(--dpe-text-muted, #6b7086);
483
+ font: inherit;
484
+ font-size: 11px;
485
+ cursor: pointer;
486
+ }
487
+
488
+ .dpe-shell__tab--active {
489
+ border-bottom-color: var(--dpe-accent, #2f7d8f);
490
+ color: var(--dpe-text, #1a1c23);
491
+ font-weight: 600;
492
+ }
493
+
494
+ /*
495
+ * Riquadro del pannello inferiore. La classe sta **sull'elemento del componente** (`<dpe-schema-panel
496
+ * class="dpe-shell__panel">`), quindi qui non si dichiara `overflow`: lo scorrimento lo dichiara il
497
+ * pannello sul proprio selettore di elemento. Con l'incapsulamento le due regole avevano la stessa
498
+ * specificita' e vinceva quella caricata per ultima — cioe' nessuno dei due autori decideva. Ora
499
+ * sono su proprieta' distinte e non c'e' niente da vincere.
500
+ */
501
+ .dpe-shell__panel {
502
+ flex: 1 1 auto;
503
+ min-height: 0;
504
+ }
505
+
506
+ /* ================================================================== canvas */
507
+ /*
508
+ * Tutto cio' che vive dentro `f-flow` lo disegna @foblex/flow, e i suoi selettori sono piu' forti
509
+ * di quanto sembri: il tema si scrive due volte, una per l'elemento e una per la classe, ed e' la
510
+ * seconda forma quella che vince. La card e' `.f-flow .f-node` = **(0,2,0)**, il connettore
511
+ * `.f-flow .f-connector-target:not(.f-node)` = **(0,3,0)**.
512
+ *
513
+ * Per questo il canvas mette la classe `dpe-flow` sul suo `<f-flow>` e i selettori qui sotto
514
+ * partono da `dpe-canvas .dpe-flow`: la card diventa (0,2,2) e i connettori, che aggiungono
515
+ * `.dpe-node`, (0,3,1). Si vince per specificita' dichiarata, non per ordine di caricamento e non
516
+ * con `!important` — che vincerebbe anche dove non serve e lascerebbe l'ospite senza modo di
517
+ * ritematizzare.
518
+ *
519
+ * Nota storica: prima queste regole stavano nel CSS incapsulato del componente, e Angular
520
+ * aggiungeva l'attributo di scope a **ogni** compound del selettore. Era da li' che arrivava la
521
+ * specificita' necessaria — cioe' dal framework, non dal foglio. Qui e' scritta.
522
+ */
523
+
524
+ dpe-canvas {
525
+ display: block;
526
+ position: relative;
527
+ width: 100%;
528
+ height: 100%;
529
+ overflow: hidden;
530
+ background: var(--dpe-canvas-bg, #f4f5f7);
531
+ }
532
+
533
+ /*
534
+ * Senza altezza esplicita il canvas non si vede: e' l'errore piu' comune con @foblex/flow. Il
535
+ * selettore parte da `dpe-canvas` perche' `f-flow` e' un elemento della libreria e una regola
536
+ * nuda uscirebbe dall'editor.
537
+ */
538
+ dpe-canvas .dpe-flow {
539
+ display: block;
540
+ width: 100%;
541
+ height: 100%;
542
+ }
543
+
544
+ dpe-canvas .dpe-flow .dpe-minimap {
545
+ position: absolute;
546
+ right: 12px;
547
+ bottom: 12px;
548
+ width: 180px;
549
+ height: 120px;
550
+ border: 1px solid var(--dpe-border, #e2e5eb);
551
+ border-radius: var(--dpe-radius, 10px);
552
+ background: var(--dpe-surface, #fff);
553
+ box-shadow: var(--dpe-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));
554
+ overflow: hidden;
555
+ }
556
+
557
+ dpe-canvas .dpe-flow .dpe-viewport-reset {
558
+ position: absolute;
559
+ right: 12px;
560
+ /* 12 (bordo) + 120 (minimappa) + 8 (respiro) */
561
+ bottom: 140px;
562
+ z-index: 1;
563
+ padding: 5px 10px;
564
+ border: 1px solid var(--dpe-border, #e2e5eb);
565
+ border-radius: var(--dpe-radius-xs, 6px);
566
+ background: var(--dpe-surface, #fff);
567
+ box-shadow: var(--dpe-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));
568
+ color: var(--dpe-text-muted, #6b7086);
569
+ font: inherit;
570
+ font-size: 11px;
571
+ cursor: pointer;
572
+ transition: opacity 0.15s ease, visibility 0.15s ease;
573
+ }
574
+
575
+ /* `visibility` e non `display`: si dissolve e nel frattempo esce dall'ordine di tabulazione. */
576
+ dpe-canvas .dpe-flow .dpe-viewport-reset--hidden {
577
+ opacity: 0;
578
+ visibility: hidden;
579
+ }
580
+
581
+ /* ---------------------------------------------------------------------- nodo */
582
+
583
+ dpe-canvas .dpe-flow .dpe-node {
584
+ position: absolute;
585
+ display: flex;
586
+ flex-direction: column;
587
+ box-sizing: border-box;
588
+ width: 230px;
589
+ border: 1px solid var(--dpe-border, #e2e5eb);
590
+ border-left: 4px solid var(--dpe-border-strong, #cfd4de);
591
+ border-radius: var(--dpe-radius-lg, 12px);
592
+ background: var(--dpe-surface, #fff);
593
+ box-shadow: var(--dpe-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));
594
+ color: var(--dpe-text, #1a1c23);
595
+ font: inherit;
596
+ /*
597
+ * Allineamento dichiarato: il tema di @foblex/flow centra il testo dentro il nodo, e la card
598
+ * ne usciva con titolo e sottotipo in mezzo — cioe' l'unica riga che si legge per prima
599
+ * cambiava posizione a ogni larghezza. Un'intestazione si legge a sinistra.
600
+ */
601
+ text-align: left;
602
+ cursor: grab;
603
+ user-select: none;
604
+ transition: box-shadow 0.12s ease, border-color 0.12s ease;
605
+ }
606
+
607
+ /*
608
+ * Larghezza per numero di porte di ingresso: le porte stanno in fila sul bordo superiore.
609
+ * Questi valori sono la copia di `PORT_WIDTHS` in `dpe-canvas.model.ts`, che li passa a dagre:
610
+ * se divergono, il layout automatico lascia i nodi larghi sovrapposti. Sono classi e non stili
611
+ * inline perche' la libreria riscrive `style` del nodo a ogni riposizionamento.
612
+ */
613
+ dpe-canvas .dpe-flow .dpe-node--ports-2 {
614
+ width: 260px;
615
+ }
616
+
617
+ dpe-canvas .dpe-flow .dpe-node--ports-3 {
618
+ width: 320px;
619
+ }
620
+
621
+ dpe-canvas .dpe-flow .dpe-node--ports-4 {
622
+ width: 380px;
623
+ }
624
+
625
+ dpe-canvas .dpe-flow .dpe-node:hover {
626
+ box-shadow: var(--dpe-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));
627
+ }
628
+
629
+ dpe-canvas .dpe-flow .dpe-node--selected {
630
+ border-color: var(--dpe-accent, #2f7d8f);
631
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--dpe-accent, #2f7d8f) 22%, transparent);
632
+ }
633
+
634
+ dpe-canvas .dpe-flow .dpe-node--error {
635
+ border-color: var(--dpe-error, #dc2626);
636
+ }
637
+
638
+ dpe-canvas .dpe-flow .dpe-node--warning {
639
+ border-color: var(--dpe-warning, #b7791f);
640
+ }
641
+
642
+ /*
643
+ * Valido ma non compilabile: bordo tratteggiato **e** colore proprio. Il tratteggio dice "non
644
+ * arriva all'SQL", il colore dice "non e' un errore tuo". Un solo segnale non basta: il
645
+ * tratteggio da solo si legge come "incompleto".
646
+ */
647
+ dpe-canvas .dpe-flow .dpe-node--not-compilable {
648
+ border-color: var(--dpe-not-compilable, #7c5cd6);
649
+ border-style: dashed;
650
+ }
651
+
652
+ /*
653
+ * Fascia colorata sul bordo sinistro: **lo stesso colore dell'icona**, cioe' quello della
654
+ * famiglia. Prima erano due sistemi di colore (fascia per gruppi di collezioni, icona per
655
+ * famiglia) e sulla stessa card avrebbero detto due cose diverse.
656
+ *
657
+ * Sta **dopo** i modificatori di gravita' di proposito: ha la loro stessa specificita', quindi
658
+ * vince per ordine e la fascia resta della famiglia anche su un nodo in errore, dove il rosso
659
+ * prende gli altri tre lati. Spostare questo blocco piu' in alto cambia il disegno.
660
+ */
661
+ dpe-canvas .dpe-flow .dpe-node {
662
+ border-left-color: var(--dpe-cat, var(--dpe-border-strong, #cfd4de));
663
+ }
664
+
665
+ /* ------------------------------------------------------------------- porte */
666
+
667
+ dpe-canvas .dpe-flow .dpe-node__ports {
668
+ display: flex;
669
+ justify-content: space-around;
670
+ gap: 6px;
671
+ padding: 0 10px;
672
+ /* Le porte sporgono sul bordo superiore: e' il punto in cui gli archi arrivano. */
673
+ margin-top: -6px;
674
+ min-height: 6px;
675
+ }
676
+
677
+ dpe-canvas .dpe-flow .dpe-node__ports--labelled {
678
+ min-height: 18px;
679
+ }
680
+
681
+ dpe-canvas .dpe-flow .dpe-port {
682
+ display: flex;
683
+ flex-direction: column;
684
+ align-items: center;
685
+ gap: 2px;
686
+ min-width: 0;
687
+ }
688
+
689
+ dpe-canvas .dpe-flow .dpe-port__label {
690
+ max-width: 96px;
691
+ overflow: hidden;
692
+ color: var(--dpe-text-subtle, #98a2b3);
693
+ font-size: 9px;
694
+ text-overflow: ellipsis;
695
+ white-space: nowrap;
696
+ letter-spacing: 0.02em;
697
+ text-transform: uppercase;
698
+ }
699
+
700
+ /*
701
+ * Il tema di @foblex/flow posiziona i connettori in `absolute` con un offset pensato per uscite
702
+ * sul fianco. Qui tornano nel flusso, e il selettore parte da `f-flow` perche' la regola del
703
+ * tema (`f-flow .f-connector-source:not(.f-node)`) ha specificita' maggiore di una sola classe:
704
+ * si pareggia e si vince per ordine, ed e' il motivo per cui questo foglio va caricato **dopo**
705
+ * `@foblex/flow/styles/default.scss`.
706
+ */
707
+ dpe-canvas .dpe-flow .dpe-connector {
708
+ box-sizing: border-box;
709
+ flex: 0 0 auto;
710
+ cursor: crosshair;
711
+ transition: transform 0.12s ease, background-color 0.12s ease;
712
+ }
713
+
714
+ dpe-canvas .dpe-flow .dpe-node .dpe-connector--in {
715
+ position: relative;
716
+ left: auto;
717
+ top: auto;
718
+ right: auto;
719
+ bottom: auto;
720
+ width: 22px;
721
+ height: 6px;
722
+ border: 0;
723
+ border-radius: 3px;
724
+ background: var(--dpe-border-strong, #cfd4de);
725
+ }
726
+
727
+ /* Il capo dell'arco arriva qui: si allarga al passaggio per essere un bersaglio raggiungibile. */
728
+ dpe-canvas .dpe-flow .dpe-node .dpe-connector--in:hover {
729
+ background: var(--dpe-accent, #2f7d8f);
730
+ transform: scaleY(1.6);
731
+ }
732
+
733
+ /* Riferimento non risolto: la porta lo dice, perche' l'arco non e' disegnabile. */
734
+ dpe-canvas .dpe-flow .dpe-node .dpe-connector--in.dpe-connector--broken {
735
+ background: var(--dpe-edge-broken, #dc2626);
736
+ }
737
+
738
+ dpe-canvas .dpe-flow .dpe-node__out {
739
+ display: flex;
740
+ justify-content: center;
741
+ padding-bottom: 0;
742
+ }
743
+
744
+ dpe-canvas .dpe-flow .dpe-node .dpe-connector--out {
745
+ position: relative;
746
+ left: auto;
747
+ top: auto;
748
+ right: auto;
749
+ bottom: auto;
750
+ width: 12px;
751
+ height: 12px;
752
+ border: 2px solid var(--dpe-surface, #fff);
753
+ border-radius: 50%;
754
+ background: var(--dpe-border-strong, #cfd4de);
755
+ /* Sporge oltre il bordo inferiore: e' lì che gli archi partono. */
756
+ margin-bottom: -6px;
757
+ /*
758
+ * `--ff-connector-connected-color` e' il token con cui la libreria colora un connettore
759
+ * collegato: la sua regola ha specificita' (0,4,1) e non si batte con una classe, ma la
760
+ * variabile si eredita. Senza, un'uscita collegata tornerebbe al colore della libreria.
761
+ */
762
+ --ff-connector-connected-color: var(--dpe-accent, #2f7d8f);
763
+ }
764
+
765
+ dpe-canvas .dpe-flow .dpe-node .dpe-connector--out:hover {
766
+ transform: scale(1.25);
767
+ background: var(--dpe-accent, #2f7d8f);
768
+ }
769
+
770
+ /* ------------------------------------------------------------ intestazione */
771
+
772
+ dpe-canvas .dpe-flow .dpe-node__head {
773
+ display: flex;
774
+ align-items: center;
775
+ gap: 8px;
776
+ padding: 8px 8px 2px 10px;
777
+ }
778
+
779
+ /*
780
+ * Pastiglia dell'icona: identica a quella della palette, per misura e colori. I due token
781
+ * `--dpe-cat`/`--dpe-cat-soft` li assegna la classe di famiglia (sezione «famiglie di nodo»).
782
+ */
783
+ dpe-canvas .dpe-flow .dpe-node__icon {
784
+ display: inline-flex;
785
+ flex: 0 0 auto;
786
+ align-items: center;
787
+ justify-content: center;
788
+ width: 26px;
789
+ height: 26px;
790
+ border-radius: var(--dpe-radius-sm, 8px);
791
+ background: var(--dpe-cat-soft, #eef0f4);
792
+ color: var(--dpe-cat, #6b7086);
793
+ }
794
+
795
+ dpe-canvas .dpe-flow .dpe-node__text {
796
+ display: flex;
797
+ flex-direction: column;
798
+ min-width: 0;
799
+ flex: 1 1 auto;
800
+ }
801
+
802
+ dpe-canvas .dpe-flow .dpe-node__title {
803
+ overflow: hidden;
804
+ font-size: 13px;
805
+ font-weight: 600;
806
+ text-overflow: ellipsis;
807
+ white-space: nowrap;
808
+ }
809
+
810
+ dpe-canvas .dpe-flow .dpe-node__sub {
811
+ overflow: hidden;
812
+ color: var(--dpe-text-muted, #6b7086);
813
+ font-size: 11px;
814
+ text-overflow: ellipsis;
815
+ white-space: nowrap;
816
+ }
817
+
818
+ dpe-canvas .dpe-flow .dpe-node__dot {
819
+ padding: 0 4px;
820
+ color: var(--dpe-text-subtle, #98a2b3);
821
+ }
822
+
823
+ dpe-canvas .dpe-flow .dpe-node__btn {
824
+ flex: 0 0 auto;
825
+ width: 20px;
826
+ height: 20px;
827
+ padding: 0;
828
+ border: 1px solid transparent;
829
+ border-radius: var(--dpe-radius-xs, 6px);
830
+ background: transparent;
831
+ color: var(--dpe-text-muted, #6b7086);
832
+ font: inherit;
833
+ font-size: 12px;
834
+ line-height: 1;
835
+ cursor: pointer;
836
+ }
837
+
838
+ dpe-canvas .dpe-flow .dpe-node__btn:hover {
839
+ border-color: var(--dpe-border, #e2e5eb);
840
+ background: var(--dpe-surface-alt, #f7f8fa);
841
+ color: var(--dpe-text, #1a1c23);
842
+ }
843
+
844
+ dpe-canvas .dpe-flow .dpe-node__btn--remove:hover {
845
+ border-color: var(--dpe-error, #dc2626);
846
+ color: var(--dpe-error, #dc2626);
847
+ }
848
+
849
+ dpe-canvas .dpe-flow .dpe-node__meta {
850
+ display: flex;
851
+ flex-wrap: wrap;
852
+ align-items: center;
853
+ gap: 4px;
854
+ padding: 0 10px 8px;
855
+ min-height: 18px;
856
+ }
857
+
858
+ dpe-canvas .dpe-flow .dpe-node__name {
859
+ overflow: hidden;
860
+ max-width: 130px;
861
+ color: var(--dpe-text-subtle, #98a2b3);
862
+ font-family: var(--dpe-font-mono, monospace);
863
+ font-size: 10px;
864
+ text-overflow: ellipsis;
865
+ white-space: nowrap;
866
+ }
867
+
868
+ dpe-canvas .dpe-flow .dpe-badge {
869
+ padding: 1px 6px;
870
+ border: 1px solid var(--dpe-border, #e2e5eb);
871
+ border-radius: 999px;
872
+ background: var(--dpe-surface-alt, #f7f8fa);
873
+ color: var(--dpe-text-muted, #6b7086);
874
+ font-size: 10px;
875
+ white-space: nowrap;
876
+ }
877
+
878
+ dpe-canvas .dpe-flow .dpe-badge--error {
879
+ border-color: var(--dpe-error, #dc2626);
880
+ color: var(--dpe-error, #dc2626);
881
+ }
882
+
883
+ dpe-canvas .dpe-flow .dpe-badge--warning {
884
+ border-color: var(--dpe-warning, #b7791f);
885
+ color: var(--dpe-warning, #b7791f);
886
+ }
887
+
888
+ dpe-canvas .dpe-flow .dpe-badge--info {
889
+ border-color: var(--dpe-info, #3b6fd4);
890
+ color: var(--dpe-info, #3b6fd4);
891
+ }
892
+
893
+ dpe-canvas .dpe-flow .dpe-badge--not-compilable {
894
+ border-color: var(--dpe-not-compilable, #7c5cd6);
895
+ color: var(--dpe-not-compilable, #7c5cd6);
896
+ }
897
+
898
+ /* =================================================================== archi */
167
899
  /*
168
900
  * Gli archi si colorano impostando le custom properties del tema di @foblex/flow, non
169
901
  * sovrascrivendone le regole: `f-flow .f-connection .f-connection-path` ha la stessa
@@ -216,7 +948,1013 @@
216
948
  * e, arrivando dopo nel foglio, vince — ma riguarda solo `stroke-dasharray`, che il tema di
217
949
  * @foblex/flow non imposta: nessun conflitto reale.
218
950
  */
219
- f-flow .dpe-edge--broken .f-connection-path,
220
- f-flow .dpe-edge--creating .f-connection-path {
951
+ dpe-canvas .dpe-flow .dpe-edge--broken .f-connection-path,
952
+ dpe-canvas .dpe-flow .dpe-edge--creating .f-connection-path {
221
953
  stroke-dasharray: 6 4;
222
954
  }
955
+
956
+ /* ================================================================= palette */
957
+
958
+ dpe-node-palette {
959
+ display: flex;
960
+ flex-direction: column;
961
+ gap: 4px;
962
+ padding: 8px;
963
+ overflow: auto;
964
+ background: var(--dpe-surface, #fff);
965
+ border-right: 1px solid var(--dpe-border, #e2e5eb);
966
+ }
967
+
968
+ dpe-node-palette h3 {
969
+ margin: 0;
970
+ color: var(--dpe-text-muted, #6b7086);
971
+ font-size: 11px;
972
+ font-weight: 700;
973
+ letter-spacing: 0.04em;
974
+ text-transform: uppercase;
975
+ }
976
+
977
+ dpe-node-palette input[type='search'] {
978
+ box-sizing: border-box;
979
+ width: 100%;
980
+ padding: 5px 7px;
981
+ border: 1px solid var(--dpe-border, #e2e5eb);
982
+ border-radius: var(--dpe-radius-xs, 6px);
983
+ background: var(--dpe-surface, #fff);
984
+ color: var(--dpe-text, #1a1c23);
985
+ font: inherit;
986
+ font-size: 12px;
987
+ }
988
+
989
+ /* Intestazione di gruppo: piu' piccola del titolo della palette, e non cliccabile. */
990
+ dpe-node-palette .dpe-palette__group {
991
+ margin: 8px 2px 2px;
992
+ color: var(--dpe-text-subtle, #98a2b3);
993
+ font-size: 10px;
994
+ font-weight: 700;
995
+ letter-spacing: 0.06em;
996
+ text-transform: uppercase;
997
+ }
998
+
999
+ /*
1000
+ * TRAPPOLA @foblex/flow, la stessa dei nodi in un punto dove non era prevista: al termine di
1001
+ * un trascinamento la libreria **riscrive l'attributo style** della voce. Durante il gesto la
1002
+ * nasconde con display none e alla fine la ripristina scrivendo il display originale, oppure
1003
+ * block se non ce n'era. Il nostro display originale era vuoto — arriva dal CSS, non da uno
1004
+ * stile inline — quindi sull'elemento resta scritto display block.
1005
+ *
1006
+ * Conseguenza vista nel browser: un display flex qui sopravviveva fino al primo
1007
+ * trascinamento e poi no, e titolo e descrizione, che erano flex item, tornavano inline e si
1008
+ * attaccavano sulla stessa riga. Solo sulle voci trascinate, solo dopo il gesto: nessuno
1009
+ * screenshot iniziale lo mostrava.
1010
+ *
1011
+ * C'e' un secondo strato, scoperto misurando: il tema della libreria dichiara sulla stessa
1012
+ * classe .f-external-item un display inline-flex in **riga**. Quindi la voce e' inline-flex
1013
+ * finche' non la si trascina e block dopo: due valori, nessuno dei due nostro.
1014
+ *
1015
+ * Correzione **strutturale**: il layout non dipende dal display di questo elemento. La voce e'
1016
+ * un involucro qualunque — inline-flex o block, indifferente — e dentro c'e' **un solo**
1017
+ * figlio, .dpe-palette__body, che porta la riga. Un unico figlio si comporta allo stesso
1018
+ * modo in entrambi i casi, ed e' questo che rende il difetto irripetibile. Niente !important
1019
+ * e niente ripristino a mano dopo il gesto: sarebbe una gara di specificita' con chi riscrive
1020
+ * lo stile, e la si perde al prossimo aggiornamento.
1021
+ *
1022
+ * Corollario per l'icona: **non** diventa un secondo figlio del bottone. Sta dentro
1023
+ * .dpe-palette__body con l'etichetta, altrimenti dopo un trascinamento i due figli
1024
+ * tornerebbero a impilarsi.
1025
+ */
1026
+ dpe-node-palette .dpe-palette__item {
1027
+ box-sizing: border-box;
1028
+ width: 100%;
1029
+ padding: 4px 6px;
1030
+ border: 1px solid transparent;
1031
+ border-radius: var(--dpe-radius-xs, 6px);
1032
+ background: transparent;
1033
+ color: var(--dpe-text, #1a1c23);
1034
+ font: inherit;
1035
+ text-align: left;
1036
+ cursor: grab;
1037
+ }
1038
+
1039
+ dpe-node-palette .dpe-palette__item:hover {
1040
+ background: var(--dpe-surface-alt, #f7f8fa);
1041
+ border-color: var(--dpe-border, #e2e5eb);
1042
+ }
1043
+
1044
+ dpe-node-palette .dpe-palette__item:focus-visible {
1045
+ outline: 2px solid var(--dpe-accent, #2f7d8f);
1046
+ outline-offset: 1px;
1047
+ }
1048
+
1049
+ /*
1050
+ * L'involucro interno: unico figlio della voce, quindi indifferente al display di chi lo
1051
+ * contiene. Qui vive il layout della riga.
1052
+ */
1053
+ dpe-node-palette .dpe-palette__body {
1054
+ display: flex;
1055
+ align-items: center;
1056
+ gap: 8px;
1057
+ width: 100%;
1058
+ min-width: 0;
1059
+ }
1060
+
1061
+ /*
1062
+ * Pastiglia dell'icona. Sfondo tenue e tratto pieno della famiglia: gli stessi due token
1063
+ * che colorano la card sul canvas, cosi' cio' che si trascina e cio' che compare hanno lo
1064
+ * stesso colore.
1065
+ */
1066
+ dpe-node-palette .dpe-palette__icon {
1067
+ display: inline-flex;
1068
+ flex: 0 0 auto;
1069
+ align-items: center;
1070
+ justify-content: center;
1071
+ width: 24px;
1072
+ height: 24px;
1073
+ border-radius: var(--dpe-radius-xs, 6px);
1074
+ background: var(--dpe-cat-soft, #eef0f4);
1075
+ color: var(--dpe-cat, #6b7086);
1076
+ }
1077
+
1078
+ dpe-node-palette .dpe-palette__label {
1079
+ flex: 1 1 auto;
1080
+ overflow: hidden;
1081
+ min-width: 0;
1082
+ font-size: 12px;
1083
+ text-overflow: ellipsis;
1084
+ white-space: nowrap;
1085
+ }
1086
+
1087
+ /*
1088
+ * Non compilabile in v1: si distingue **prima** di trascinarlo, non dopo. Segno compatto e
1089
+ * non una terza riga — l'informazione per esteso sta nel titolo, con la descrizione.
1090
+ */
1091
+ dpe-node-palette .dpe-palette__flag {
1092
+ flex: 0 0 auto;
1093
+ padding: 0 5px;
1094
+ border: 1px solid var(--dpe-not-compilable, #7c5cd6);
1095
+ border-radius: 999px;
1096
+ color: var(--dpe-not-compilable, #7c5cd6);
1097
+ font-size: 9px;
1098
+ font-weight: 700;
1099
+ letter-spacing: 0.04em;
1100
+ }
1101
+
1102
+ dpe-node-palette .dpe-palette__empty {
1103
+ margin: 6px 2px;
1104
+ color: var(--dpe-text-muted, #6b7086);
1105
+ font-size: 11px;
1106
+ }
1107
+
1108
+ /* =============================================================== icona nodo */
1109
+
1110
+ dpe-node-icon {
1111
+ display: inline-flex;
1112
+ flex: 0 0 auto;
1113
+ line-height: 0;
1114
+ }
1115
+
1116
+ /* ======================================================== form (ispettori) */
1117
+ /*
1118
+ * Stili condivisi da tutti gli ispettori. Prima erano un foglio incluso per riferimento in
1119
+ * quindici componenti — quindi quindici copie nel bundle; qui e' una copia sola.
1120
+ */
1121
+
1122
+ .dpe-form {
1123
+ display: flex;
1124
+ flex-direction: column;
1125
+ gap: 12px;
1126
+ font-size: 12px;
1127
+ }
1128
+
1129
+ .dpe-field {
1130
+ display: flex;
1131
+ flex-direction: column;
1132
+ gap: 3px;
1133
+ }
1134
+
1135
+ .dpe-field__label {
1136
+ color: var(--dpe-text-muted, #6b7086);
1137
+ font-size: 11px;
1138
+ font-weight: 600;
1139
+ }
1140
+
1141
+ .dpe-field__hint {
1142
+ color: var(--dpe-text-subtle, #98a2b3);
1143
+ font-size: 10px;
1144
+ }
1145
+
1146
+ /* Un rilievo del backend sul campo: si mostra sotto, non in un tooltip. */
1147
+ .dpe-field__issue {
1148
+ color: var(--dpe-error, #dc2626);
1149
+ font-size: 10px;
1150
+ }
1151
+
1152
+ .dpe-field__issue--warning {
1153
+ color: var(--dpe-warning, #b7791f);
1154
+ }
1155
+
1156
+ .dpe-field__issue--info {
1157
+ color: var(--dpe-info, #3b6fd4);
1158
+ }
1159
+
1160
+ .dpe-form input[type='text'],
1161
+ .dpe-form input[type='number'],
1162
+ .dpe-form input[type='search'],
1163
+ .dpe-form select,
1164
+ .dpe-form textarea {
1165
+ box-sizing: border-box;
1166
+ width: 100%;
1167
+ padding: 5px 7px;
1168
+ border: 1px solid var(--dpe-border, #e2e5eb);
1169
+ border-radius: var(--dpe-radius-xs, 6px);
1170
+ background: var(--dpe-surface, #fff);
1171
+ color: var(--dpe-text, #1a1c23);
1172
+ font: inherit;
1173
+ font-size: 12px;
1174
+ }
1175
+
1176
+ .dpe-form input:focus-visible,
1177
+ .dpe-form select:focus-visible,
1178
+ .dpe-form textarea:focus-visible {
1179
+ outline: 2px solid var(--dpe-accent, #2f7d8f);
1180
+ outline-offset: 1px;
1181
+ }
1182
+
1183
+ .dpe-form input[aria-invalid='true'] {
1184
+ border-color: var(--dpe-error, #dc2626);
1185
+ }
1186
+
1187
+ .dpe-form textarea {
1188
+ min-height: 56px;
1189
+ font-family: var(--dpe-font-mono, monospace);
1190
+ resize: vertical;
1191
+ }
1192
+
1193
+ .dpe-check {
1194
+ display: flex;
1195
+ align-items: center;
1196
+ gap: 6px;
1197
+ }
1198
+
1199
+ .dpe-check input {
1200
+ margin: 0;
1201
+ }
1202
+
1203
+ .dpe-row {
1204
+ display: flex;
1205
+ gap: 8px;
1206
+ }
1207
+
1208
+ .dpe-row > * {
1209
+ flex: 1 1 0;
1210
+ min-width: 0;
1211
+ }
1212
+
1213
+ .dpe-table {
1214
+ width: 100%;
1215
+ border-collapse: collapse;
1216
+ font-size: 11px;
1217
+ }
1218
+
1219
+ .dpe-table th {
1220
+ padding: 3px 4px;
1221
+ color: var(--dpe-text-muted, #6b7086);
1222
+ font-size: 10px;
1223
+ font-weight: 600;
1224
+ text-align: left;
1225
+ }
1226
+
1227
+ .dpe-table td {
1228
+ padding: 2px 4px;
1229
+ vertical-align: top;
1230
+ }
1231
+
1232
+ .dpe-table input,
1233
+ .dpe-table select {
1234
+ padding: 3px 5px;
1235
+ font-size: 11px;
1236
+ }
1237
+
1238
+ .dpe-btn {
1239
+ padding: 4px 9px;
1240
+ border: 1px solid var(--dpe-border, #e2e5eb);
1241
+ border-radius: var(--dpe-radius-xs, 6px);
1242
+ background: var(--dpe-surface, #fff);
1243
+ color: var(--dpe-text, #1a1c23);
1244
+ font: inherit;
1245
+ font-size: 11px;
1246
+ cursor: pointer;
1247
+ }
1248
+
1249
+ .dpe-btn:hover:not(:disabled) {
1250
+ background: var(--dpe-surface-alt, #f7f8fa);
1251
+ }
1252
+
1253
+ .dpe-btn:disabled {
1254
+ opacity: 0.5;
1255
+ cursor: not-allowed;
1256
+ }
1257
+
1258
+ .dpe-btn--danger:hover:not(:disabled) {
1259
+ border-color: var(--dpe-error, #dc2626);
1260
+ color: var(--dpe-error, #dc2626);
1261
+ }
1262
+
1263
+ .dpe-btn--icon {
1264
+ padding: 2px 6px;
1265
+ }
1266
+
1267
+ .dpe-section {
1268
+ display: flex;
1269
+ flex-direction: column;
1270
+ gap: 6px;
1271
+ padding-top: 8px;
1272
+ border-top: 1px solid var(--dpe-border-subtle, #eef0f4);
1273
+ }
1274
+
1275
+ .dpe-section__title {
1276
+ margin: 0;
1277
+ font-size: 11px;
1278
+ font-weight: 700;
1279
+ letter-spacing: 0.03em;
1280
+ text-transform: uppercase;
1281
+ color: var(--dpe-text-muted, #6b7086);
1282
+ }
1283
+
1284
+ /* Avviso "non e' un errore tuo": stesso colore del badge del nodo non compilabile. */
1285
+ .dpe-note {
1286
+ padding: 6px 8px;
1287
+ border: 1px solid var(--dpe-border, #e2e5eb);
1288
+ border-left: 3px solid var(--dpe-info, #3b6fd4);
1289
+ border-radius: var(--dpe-radius-xs, 6px);
1290
+ background: var(--dpe-surface-alt, #f7f8fa);
1291
+ color: var(--dpe-text-muted, #6b7086);
1292
+ font-size: 11px;
1293
+ line-height: 1.45;
1294
+ }
1295
+
1296
+ .dpe-note--not-compilable {
1297
+ border-left-color: var(--dpe-not-compilable, #7c5cd6);
1298
+ }
1299
+
1300
+ .dpe-note--warning {
1301
+ border-left-color: var(--dpe-warning, #b7791f);
1302
+ }
1303
+
1304
+ .dpe-note--danger {
1305
+ border-left-color: var(--dpe-error, #dc2626);
1306
+ }
1307
+
1308
+ .dpe-empty {
1309
+ color: var(--dpe-text-subtle, #98a2b3);
1310
+ font-size: 11px;
1311
+ font-style: italic;
1312
+ }
1313
+
1314
+ /* Dialetto citato nell'editor di espressioni: e' testo tecnico, quindi monospaziato. */
1315
+ .dpe-expr__dialect {
1316
+ font-family: var(--dpe-font-mono, monospace);
1317
+ font-weight: 600;
1318
+ }
1319
+
1320
+ /* =============================================================== ispettore */
1321
+
1322
+ dpe-node-inspector {
1323
+ display: block;
1324
+ padding: 12px;
1325
+ overflow: auto;
1326
+ }
1327
+
1328
+ .dpe-inspector__head {
1329
+ display: flex;
1330
+ align-items: center;
1331
+ gap: 8px;
1332
+ margin-bottom: 10px;
1333
+ }
1334
+
1335
+ /* Pastiglia identica a quella della palette e della card: stessa misura, stessi token. */
1336
+ .dpe-inspector__icon {
1337
+ display: inline-flex;
1338
+ flex: 0 0 auto;
1339
+ align-items: center;
1340
+ justify-content: center;
1341
+ width: 26px;
1342
+ height: 26px;
1343
+ border-radius: var(--dpe-radius-sm, 8px);
1344
+ background: var(--dpe-cat-soft, #eef0f4);
1345
+ color: var(--dpe-cat, #6b7086);
1346
+ }
1347
+
1348
+ .dpe-inspector__name {
1349
+ flex: 1 1 auto;
1350
+ overflow: hidden;
1351
+ min-width: 0;
1352
+ text-overflow: ellipsis;
1353
+ white-space: nowrap;
1354
+ }
1355
+
1356
+ .dpe-inspector__category {
1357
+ /* All'estremita' opposta del titolo, come prima di avere l'icona in testa. */
1358
+ margin-left: auto;
1359
+ flex: 0 0 auto;
1360
+ color: var(--dpe-text-muted, #6b7086);
1361
+ font-size: 11px;
1362
+ text-transform: uppercase;
1363
+ letter-spacing: 0.04em;
1364
+ }
1365
+
1366
+ .dpe-columns {
1367
+ display: flex;
1368
+ flex-wrap: wrap;
1369
+ gap: 4px;
1370
+ }
1371
+
1372
+ .dpe-column {
1373
+ padding: 1px 6px;
1374
+ border: 1px solid var(--dpe-border, #e2e5eb);
1375
+ border-radius: 999px;
1376
+ background: var(--dpe-surface-alt, #f7f8fa);
1377
+ font-size: 10px;
1378
+ }
1379
+
1380
+ .dpe-column--nullable {
1381
+ border-style: dashed;
1382
+ }
1383
+
1384
+ .dpe-multi__names {
1385
+ display: flex;
1386
+ flex-wrap: wrap;
1387
+ gap: 4px;
1388
+ margin: 8px 0;
1389
+ padding: 0;
1390
+ list-style: none;
1391
+ }
1392
+
1393
+ .dpe-multi__name {
1394
+ padding: 1px 6px;
1395
+ border: 1px solid var(--dpe-border, #e2e5eb);
1396
+ border-radius: 999px;
1397
+ background: var(--dpe-surface-alt, #f7f8fa);
1398
+ font-family: var(--dpe-font-mono, monospace);
1399
+ font-size: 10px;
1400
+ }
1401
+
1402
+ /* ============================================================ diagnostiche */
1403
+
1404
+ dpe-diagnostics-panel {
1405
+ display: flex;
1406
+ flex-direction: column;
1407
+ overflow: auto;
1408
+ background: var(--dpe-surface, #fff);
1409
+ font-size: 12px;
1410
+ }
1411
+
1412
+ .dpe-diag__head {
1413
+ display: flex;
1414
+ align-items: center;
1415
+ gap: 10px;
1416
+ padding: 8px 10px;
1417
+ border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);
1418
+ }
1419
+
1420
+ .dpe-diag__count {
1421
+ color: var(--dpe-text-muted, #6b7086);
1422
+ font-size: 11px;
1423
+ }
1424
+
1425
+ .dpe-diag__row {
1426
+ display: flex;
1427
+ gap: 8px;
1428
+ width: 100%;
1429
+ padding: 6px 10px;
1430
+ border: 0;
1431
+ border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);
1432
+ border-left: 3px solid transparent;
1433
+ background: transparent;
1434
+ color: inherit;
1435
+ font: inherit;
1436
+ font-size: 11px;
1437
+ text-align: left;
1438
+ cursor: pointer;
1439
+ }
1440
+
1441
+ .dpe-diag__row:hover {
1442
+ background: var(--dpe-surface-alt, #f7f8fa);
1443
+ }
1444
+
1445
+ .dpe-diag__row:focus-visible {
1446
+ outline: 2px solid var(--dpe-accent, #2f7d8f);
1447
+ outline-offset: -2px;
1448
+ }
1449
+
1450
+ .dpe-diag__row--Error {
1451
+ border-left-color: var(--dpe-error, #dc2626);
1452
+ }
1453
+
1454
+ .dpe-diag__row--Warning {
1455
+ border-left-color: var(--dpe-warning, #b7791f);
1456
+ }
1457
+
1458
+ .dpe-diag__row--Info {
1459
+ border-left-color: var(--dpe-info, #3b6fd4);
1460
+ }
1461
+
1462
+ /* Vince sulla gravita': non e' un problema dell'utente, e si deve vedere subito. Vince per
1463
+ ordine, quindi resta **dopo** i tre blocchi di gravita'. */
1464
+ .dpe-diag__row--not-compilable {
1465
+ border-left-color: var(--dpe-not-compilable, #7c5cd6);
1466
+ background: color-mix(in srgb, var(--dpe-not-compilable, #7c5cd6) 6%, transparent);
1467
+ }
1468
+
1469
+ .dpe-diag__code {
1470
+ flex: 0 0 auto;
1471
+ font-family: var(--dpe-font-mono, monospace);
1472
+ font-size: 10px;
1473
+ color: var(--dpe-text-muted, #6b7086);
1474
+ }
1475
+
1476
+ .dpe-diag__text {
1477
+ flex: 1 1 auto;
1478
+ }
1479
+
1480
+ .dpe-diag__where {
1481
+ color: var(--dpe-text-subtle, #98a2b3);
1482
+ font-size: 10px;
1483
+ }
1484
+
1485
+ .dpe-diag__tag {
1486
+ flex: 0 0 auto;
1487
+ padding: 0 6px;
1488
+ border: 1px solid currentcolor;
1489
+ border-radius: 999px;
1490
+ font-size: 9px;
1491
+ text-transform: uppercase;
1492
+ }
1493
+
1494
+ .dpe-diag__tag--not-compilable {
1495
+ color: var(--dpe-not-compilable, #7c5cd6);
1496
+ }
1497
+
1498
+ .dpe-diag__tag--dialect {
1499
+ color: var(--dpe-info, #3b6fd4);
1500
+ }
1501
+
1502
+ .dpe-diag__empty {
1503
+ padding: 10px;
1504
+ color: var(--dpe-text-subtle, #98a2b3);
1505
+ font-size: 11px;
1506
+ font-style: italic;
1507
+ }
1508
+
1509
+ /* ================================================================== schema */
1510
+
1511
+ dpe-schema-panel {
1512
+ display: block;
1513
+ overflow: auto;
1514
+ padding: 8px 10px;
1515
+ background: var(--dpe-surface, #fff);
1516
+ font-size: 12px;
1517
+ }
1518
+
1519
+ .dpe-schema__node {
1520
+ padding: 6px 0;
1521
+ border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);
1522
+ }
1523
+
1524
+ .dpe-schema__head {
1525
+ display: flex;
1526
+ align-items: baseline;
1527
+ gap: 8px;
1528
+ }
1529
+
1530
+ .dpe-schema__name {
1531
+ font-family: var(--dpe-font-mono, monospace);
1532
+ font-size: 11px;
1533
+ font-weight: 700;
1534
+ }
1535
+
1536
+ .dpe-schema__node--selected .dpe-schema__name {
1537
+ color: var(--dpe-accent, #2f7d8f);
1538
+ }
1539
+
1540
+ .dpe-schema__category {
1541
+ color: var(--dpe-text-subtle, #98a2b3);
1542
+ font-size: 10px;
1543
+ text-transform: uppercase;
1544
+ }
1545
+
1546
+ .dpe-schema__line {
1547
+ display: flex;
1548
+ flex-wrap: wrap;
1549
+ align-items: baseline;
1550
+ gap: 4px;
1551
+ margin-top: 3px;
1552
+ }
1553
+
1554
+ .dpe-schema__label {
1555
+ min-width: 62px;
1556
+ color: var(--dpe-text-muted, #6b7086);
1557
+ font-size: 10px;
1558
+ }
1559
+
1560
+ .dpe-col {
1561
+ padding: 1px 6px;
1562
+ border: 1px solid var(--dpe-border, #e2e5eb);
1563
+ border-radius: 999px;
1564
+ background: var(--dpe-surface-alt, #f7f8fa);
1565
+ font-size: 10px;
1566
+ }
1567
+
1568
+ .dpe-col--nullable {
1569
+ border-style: dashed;
1570
+ }
1571
+
1572
+ /* Colonna che compare **qui**: un alias nuovo o una colonna calcolata. */
1573
+ .dpe-col--new {
1574
+ border-color: var(--dpe-accent, #2f7d8f);
1575
+ color: var(--dpe-accent-strong, #226270);
1576
+ font-weight: 600;
1577
+ }
1578
+
1579
+ .dpe-col--dropped {
1580
+ border-color: var(--dpe-warning, #b7791f);
1581
+ color: var(--dpe-warning, #b7791f);
1582
+ text-decoration: line-through;
1583
+ }
1584
+
1585
+ .dpe-schema__tag {
1586
+ padding: 0 6px;
1587
+ border: 1px solid var(--dpe-not-compilable, #7c5cd6);
1588
+ border-radius: 999px;
1589
+ color: var(--dpe-not-compilable, #7c5cd6);
1590
+ font-size: 9px;
1591
+ text-transform: uppercase;
1592
+ }
1593
+
1594
+ .dpe-schema__empty {
1595
+ color: var(--dpe-text-subtle, #98a2b3);
1596
+ font-size: 11px;
1597
+ font-style: italic;
1598
+ }
1599
+
1600
+ /* ============================================================ SQL generato */
1601
+
1602
+ dpe-sql-preview {
1603
+ display: block;
1604
+ overflow: auto;
1605
+ padding: 8px 10px;
1606
+ background: var(--dpe-surface, #fff);
1607
+ font-size: 12px;
1608
+ }
1609
+
1610
+ .dpe-sql__bar {
1611
+ display: flex;
1612
+ align-items: center;
1613
+ gap: 8px;
1614
+ margin-bottom: 8px;
1615
+ }
1616
+
1617
+ .dpe-sql__btn {
1618
+ padding: 4px 9px;
1619
+ border: 1px solid var(--dpe-border, #e2e5eb);
1620
+ border-radius: var(--dpe-radius-xs, 6px);
1621
+ background: var(--dpe-surface, #fff);
1622
+ color: var(--dpe-text, #1a1c23);
1623
+ font: inherit;
1624
+ font-size: 11px;
1625
+ cursor: pointer;
1626
+ }
1627
+
1628
+ .dpe-sql__btn:disabled {
1629
+ opacity: 0.5;
1630
+ cursor: not-allowed;
1631
+ }
1632
+
1633
+ .dpe-sql__note {
1634
+ color: var(--dpe-text-muted, #6b7086);
1635
+ font-size: 10px;
1636
+ }
1637
+
1638
+ .dpe-sql__section {
1639
+ margin-bottom: 10px;
1640
+ }
1641
+
1642
+ .dpe-sql__title {
1643
+ margin: 0 0 2px;
1644
+ font-size: 11px;
1645
+ font-weight: 700;
1646
+ text-transform: uppercase;
1647
+ letter-spacing: 0.03em;
1648
+ color: var(--dpe-text-muted, #6b7086);
1649
+ }
1650
+
1651
+ /* L'SQL e la tabella dei parametri: elementi nudi, quindi sempre dentro il componente. */
1652
+ dpe-sql-preview pre {
1653
+ margin: 4px 0;
1654
+ padding: 8px;
1655
+ border: 1px solid var(--dpe-border, #e2e5eb);
1656
+ border-radius: var(--dpe-radius-xs, 6px);
1657
+ background: var(--dpe-surface-sunken, #eef0f4);
1658
+ font-family: var(--dpe-font-mono, monospace);
1659
+ font-size: 11px;
1660
+ white-space: pre-wrap;
1661
+ word-break: break-word;
1662
+ }
1663
+
1664
+ dpe-sql-preview table {
1665
+ width: 100%;
1666
+ border-collapse: collapse;
1667
+ font-size: 10px;
1668
+ }
1669
+
1670
+ dpe-sql-preview th,
1671
+ dpe-sql-preview td {
1672
+ padding: 2px 5px;
1673
+ border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);
1674
+ text-align: left;
1675
+ }
1676
+
1677
+ .dpe-sql__empty {
1678
+ color: var(--dpe-text-subtle, #98a2b3);
1679
+ font-size: 11px;
1680
+ font-style: italic;
1681
+ }
1682
+
1683
+ /* =============================================================== catalogo */
1684
+ /*
1685
+ * Il catalogo e' un componente riusabile e non una pagina della demo (ADR 0019): tutti i colori
1686
+ * passano dai token, cosi' l'ospite lo ritematizza come il resto dell'editor. La radice del suo
1687
+ * template porta `.dpe-theme`, quindi funziona anche montato da solo, fuori dall'editor.
1688
+ */
1689
+
1690
+ dpe-catalog {
1691
+ display: block;
1692
+ /*
1693
+ * Altezza piena: senza, la sezione con `height: 100%` misura su un elemento di altezza
1694
+ * automatica e il catalogo si ferma a meta' pagina, lasciando sotto una fascia vuota. E' il
1695
+ * tipo di difetto che il compilatore non vede e che si nota solo guardando.
1696
+ */
1697
+ height: 100%;
1698
+ min-height: 0;
1699
+ overflow: hidden;
1700
+ }
1701
+
1702
+ .dpe-cat {
1703
+ /*
1704
+ * Colonna **flex** e non griglia a righe fisse: il banner d'errore c'e' o non c'e', e con
1705
+ * `grid-template-rows` a quattro voci le righe si spostavano di una quando manca — il piede
1706
+ * prendeva la riga elastica e l'elenco si stringeva sul contenuto, lasciando sotto una fascia
1707
+ * vuota. Con flex e' l'elenco a dichiararsi elastico, indipendentemente da quanti fratelli ha.
1708
+ */
1709
+ display: flex;
1710
+ flex-direction: column;
1711
+ height: 100%;
1712
+ background: var(--dpe-surface-alt);
1713
+ color: var(--dpe-text);
1714
+ font-family: var(--dpe-font);
1715
+ }
1716
+
1717
+ .dpe-cat__bar {
1718
+ display: flex;
1719
+ flex: 0 0 auto;
1720
+ align-items: center;
1721
+ gap: 10px;
1722
+ padding: 10px 14px;
1723
+ border-bottom: 1px solid var(--dpe-border);
1724
+ background: var(--dpe-surface);
1725
+ }
1726
+
1727
+ .dpe-cat__title {
1728
+ margin: 0;
1729
+ font-size: 14px;
1730
+ font-weight: 600;
1731
+ }
1732
+
1733
+ .dpe-cat__count {
1734
+ color: var(--dpe-text-muted);
1735
+ font-size: 11px;
1736
+ }
1737
+
1738
+ .dpe-cat__filter {
1739
+ flex: 0 1 260px;
1740
+ margin-left: auto;
1741
+ padding: 5px 8px;
1742
+ border: 1px solid var(--dpe-border-strong);
1743
+ border-radius: var(--dpe-radius-xs);
1744
+ background: var(--dpe-surface);
1745
+ color: inherit;
1746
+ font: inherit;
1747
+ font-size: 12px;
1748
+ }
1749
+
1750
+ .dpe-cat__btn {
1751
+ padding: 4px 9px;
1752
+ border: 1px solid var(--dpe-border-strong);
1753
+ border-radius: var(--dpe-radius-xs);
1754
+ background: var(--dpe-surface);
1755
+ color: inherit;
1756
+ font: inherit;
1757
+ font-size: 11px;
1758
+ white-space: nowrap;
1759
+ cursor: pointer;
1760
+ }
1761
+
1762
+ .dpe-cat__btn:hover:not(:disabled) {
1763
+ border-color: var(--dpe-accent);
1764
+ color: var(--dpe-accent-strong);
1765
+ }
1766
+
1767
+ .dpe-cat__btn:disabled {
1768
+ color: var(--dpe-text-subtle);
1769
+ cursor: not-allowed;
1770
+ }
1771
+
1772
+ .dpe-cat__btn--primary:not(:disabled) {
1773
+ border-color: var(--dpe-accent-strong);
1774
+ background: var(--dpe-accent);
1775
+ color: var(--dpe-accent-contrast);
1776
+ font-weight: 600;
1777
+ }
1778
+
1779
+ .dpe-cat__btn--danger:not(:disabled) {
1780
+ border-color: var(--dpe-error);
1781
+ color: var(--dpe-error);
1782
+ }
1783
+
1784
+ .dpe-cat__btn:focus-visible,
1785
+ .dpe-cat__filter:focus-visible,
1786
+ .dpe-cat__input:focus-visible,
1787
+ .dpe-cat__open:focus-visible {
1788
+ outline: 2px solid var(--dpe-accent);
1789
+ outline-offset: -2px;
1790
+ }
1791
+
1792
+ .dpe-cat__error {
1793
+ display: flex;
1794
+ gap: 8px;
1795
+ align-items: baseline;
1796
+ margin: 0;
1797
+ padding: 7px 14px;
1798
+ border-bottom: 1px solid var(--dpe-border);
1799
+ background: color-mix(in srgb, var(--dpe-error) 10%, var(--dpe-surface));
1800
+ color: var(--dpe-error);
1801
+ font-size: 11px;
1802
+ }
1803
+
1804
+ .dpe-cat__dismiss {
1805
+ margin-left: auto;
1806
+ border: 0;
1807
+ background: transparent;
1808
+ color: inherit;
1809
+ font: inherit;
1810
+ cursor: pointer;
1811
+ }
1812
+
1813
+ .dpe-cat__list {
1814
+ flex: 1 1 auto;
1815
+ min-height: 0;
1816
+ margin: 0;
1817
+ padding: 8px 10px;
1818
+ overflow: auto;
1819
+ list-style: none;
1820
+ }
1821
+
1822
+ .dpe-cat__item {
1823
+ margin-bottom: 6px;
1824
+ border: 1px solid var(--dpe-border);
1825
+ border-radius: var(--dpe-radius);
1826
+ background: var(--dpe-surface);
1827
+ box-shadow: var(--dpe-shadow-sm);
1828
+ }
1829
+
1830
+ /* Attesa di una scrittura: si vede, ma l'elenco non lampeggia e resta leggibile. */
1831
+ .dpe-cat__item--busy {
1832
+ opacity: 0.72;
1833
+ }
1834
+
1835
+ .dpe-cat__row {
1836
+ display: flex;
1837
+ align-items: center;
1838
+ gap: 10px;
1839
+ padding: 6px 10px;
1840
+ }
1841
+
1842
+ /*
1843
+ * Un `<button>` per riga, come nel progetto di riferimento: apre. I comandi della riga sono
1844
+ * **fratelli** e non figli — un bottone dentro un bottone non e' HTML valido e il click interno
1845
+ * finirebbe comunque all'esterno.
1846
+ */
1847
+ .dpe-cat__open {
1848
+ display: grid;
1849
+ flex: 1 1 auto;
1850
+ gap: 2px;
1851
+ padding: 5px 4px;
1852
+ border: 0;
1853
+ background: transparent;
1854
+ color: inherit;
1855
+ font: inherit;
1856
+ text-align: left;
1857
+ cursor: pointer;
1858
+ }
1859
+
1860
+ .dpe-cat__label {
1861
+ font-size: 13px;
1862
+ font-weight: 600;
1863
+ }
1864
+
1865
+ .dpe-cat__meta,
1866
+ .dpe-cat__desc {
1867
+ color: var(--dpe-text-muted);
1868
+ font-size: 11px;
1869
+ }
1870
+
1871
+ .dpe-cat__name {
1872
+ font-family: var(--dpe-font-mono);
1873
+ font-size: 10px;
1874
+ }
1875
+
1876
+ .dpe-cat__dot {
1877
+ color: var(--dpe-text-subtle);
1878
+ }
1879
+
1880
+ .dpe-cat__flag {
1881
+ flex: 0 0 auto;
1882
+ padding: 2px 7px;
1883
+ border: 1px solid var(--dpe-border-strong);
1884
+ border-radius: var(--dpe-radius-xs);
1885
+ color: var(--dpe-text-muted);
1886
+ font-size: 10px;
1887
+ }
1888
+
1889
+ .dpe-cat__flag--errors {
1890
+ border-color: var(--dpe-error);
1891
+ background: color-mix(in srgb, var(--dpe-error) 8%, transparent);
1892
+ color: var(--dpe-error);
1893
+ }
1894
+
1895
+ .dpe-cat__actions,
1896
+ .dpe-cat__confirm {
1897
+ display: flex;
1898
+ flex: 0 0 auto;
1899
+ gap: 6px;
1900
+ align-items: center;
1901
+ font-size: 11px;
1902
+ }
1903
+
1904
+ .dpe-cat__empty {
1905
+ padding: 18px 12px;
1906
+ color: var(--dpe-text-muted);
1907
+ font-size: 12px;
1908
+ text-align: center;
1909
+ }
1910
+
1911
+ .dpe-cat__foot {
1912
+ flex: 0 0 auto;
1913
+ padding: 10px 14px;
1914
+ border-top: 1px solid var(--dpe-border);
1915
+ background: var(--dpe-surface);
1916
+ }
1917
+
1918
+ .dpe-cat__form {
1919
+ display: flex;
1920
+ flex-wrap: wrap;
1921
+ gap: 8px;
1922
+ align-items: flex-end;
1923
+ }
1924
+
1925
+ .dpe-cat__form--inline {
1926
+ padding: 8px 12px 10px;
1927
+ border-top: 1px solid var(--dpe-border-subtle);
1928
+ background: var(--dpe-surface-sunken);
1929
+ border-radius: 0 0 var(--dpe-radius) var(--dpe-radius);
1930
+ }
1931
+
1932
+ .dpe-cat__field {
1933
+ display: grid;
1934
+ gap: 3px;
1935
+ font-size: 11px;
1936
+ color: var(--dpe-text-muted);
1937
+ }
1938
+
1939
+ .dpe-cat__input {
1940
+ width: 200px;
1941
+ padding: 5px 8px;
1942
+ border: 1px solid var(--dpe-border-strong);
1943
+ border-radius: var(--dpe-radius-xs);
1944
+ background: var(--dpe-surface);
1945
+ color: var(--dpe-text);
1946
+ font: inherit;
1947
+ font-size: 12px;
1948
+ }
1949
+
1950
+ .dpe-cat__input:disabled {
1951
+ background: var(--dpe-surface-sunken);
1952
+ color: var(--dpe-text-subtle);
1953
+ }
1954
+
1955
+ .dpe-cat__hint {
1956
+ margin: 8px 0 0;
1957
+ color: var(--dpe-text-muted);
1958
+ font-size: 11px;
1959
+ line-height: 1.45;
1960
+ }