@esfaenza/dpe-builder 20.3.7 → 20.3.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.
@@ -68,6 +68,13 @@
68
68
  */
69
69
  --dpe-not-compilable: #7c5cd6;
70
70
 
71
+ /*
72
+ * Velo della dialog modale (`::backdrop`). E' un token perche' la regola della casa e' «colori
73
+ * solo attraverso i token», e perche' l'ospite deve poter cambiare quanto la sua pagina resta
74
+ * visibile sotto la finestra.
75
+ */
76
+ --dpe-scrim: rgba(16, 18, 24, 0.55);
77
+
71
78
  /*
72
79
  * Colore per **famiglia** di categoria: sorgenti, trasformazioni, scritture, e cio' che il
73
80
  * compilatore non traduce in v1. La famiglia si deriva da `isSource`/`isSink`/
@@ -162,6 +169,8 @@
162
169
  --dpe-success: #63b57f;
163
170
  --dpe-info: #7ea6f0;
164
171
  --dpe-not-compilable: #a78bfa;
172
+ /* Su fondo scuro il velo deve pesare piu': la superficie sotto e' gia' scura. */
173
+ --dpe-scrim: rgba(4, 5, 8, 0.66);
165
174
  /*
166
175
  * Famiglie in tema scuro: tratto piu' chiaro e pastiglia scura. Le `-soft` chiare del tema
167
176
  * chiaro qui diventerebbero macchie luminose sulla card, cioe' l'icona pesarebbe piu' del
@@ -428,23 +437,57 @@ dpe-builder {
428
437
 
429
438
  /* ---------------------------------------------------------------------- corpo */
430
439
 
440
+ /*
441
+ * Due colonne e non tre (ADR 0026): i 340px dell'ispettore vanno al canvas, che e' cio' per cui
442
+ * esiste un editor di DAG. Un nodo si modifica nella dialog, e tenere **entrambi** i posti
443
+ * significherebbe due form che scrivono gli stessi campi dello stesso nodo.
444
+ */
431
445
  .dpe-shell__body {
432
446
  display: grid;
433
447
  flex: 1 1 auto;
434
- grid-template-columns: 210px minmax(0, 1fr) 340px;
448
+ grid-template-columns: 210px minmax(0, 1fr);
435
449
  min-height: 0;
436
450
  border-bottom: 1px solid var(--dpe-border, #e2e5eb);
437
451
  }
438
452
 
439
- .dpe-shell__palette,
440
- .dpe-shell__inspector {
453
+ .dpe-shell__palette {
441
454
  min-height: 0;
442
455
  max-height: 100%;
443
456
  }
444
457
 
445
- .dpe-shell__inspector {
446
- border-left: 1px solid var(--dpe-border, #e2e5eb);
458
+ /*
459
+ * Striscia della selezione multipla: l'unico contenuto che era **solo** della colonna di destra.
460
+ * Neutra di proposito — selezionare tre nodi non e' un avviso — con l'avviso vero dentro, sulla
461
+ * `.dpe-note--warning` che gia' esiste.
462
+ */
463
+ .dpe-shell__multi {
464
+ display: flex;
465
+ flex: 0 0 auto;
466
+ flex-wrap: wrap;
467
+ align-items: center;
468
+ gap: 10px;
469
+ padding: 8px 12px;
470
+ border-bottom: 1px solid var(--dpe-border, #e2e5eb);
447
471
  background: var(--dpe-surface, #fff);
472
+ color: var(--dpe-text, #1a1c23);
473
+ font-size: 12px;
474
+ }
475
+
476
+ .dpe-shell__multi-head {
477
+ display: flex;
478
+ flex: 1 1 260px;
479
+ flex-wrap: wrap;
480
+ align-items: center;
481
+ gap: 8px;
482
+ min-width: 0;
483
+ }
484
+
485
+ .dpe-shell__multi .dpe-multi__names {
486
+ margin: 0;
487
+ }
488
+
489
+ .dpe-shell__multi .dpe-note {
490
+ flex: 1 1 100%;
448
491
  }
449
492
 
450
493
  /* Il canvas ha bisogno di un'altezza esplicita, e in una griglia la prende dalla riga. */
@@ -1117,13 +1160,19 @@ dpe-node-icon {
1117
1160
  /*
1118
1161
  * Stili condivisi da tutti gli ispettori. Prima erano un foglio incluso per riferimento in
1119
1162
  * quindici componenti — quindi quindici copie nel bundle; qui e' una copia sola.
1163
+ *
1164
+ * **La scala tipografica e' stata alzata una volta, qui** (ADR 0026). Queste classi — `dpe-field`,
1165
+ * `dpe-row`, `dpe-section`, `dpe-table`, `dpe-btn`, `dpe-empty` — le usano **solo** i dodici
1166
+ * ispettori di categoria e i due editor condivisi che includono, e il loro unico contenitore e'
1167
+ * ora la dialog di modifica, larga fino a 1180px. Gli 11px, e i 10px delle intestazioni di
1168
+ * tabella, erano la tipografia dei 316px della colonna laterale: quei 316px non ci sono piu'.
1120
1169
  */
1121
1170
 
1122
1171
  .dpe-form {
1123
1172
  display: flex;
1124
1173
  flex-direction: column;
1125
1174
  gap: 12px;
1126
- font-size: 12px;
1175
+ font-size: 13px;
1127
1176
  }
1128
1177
 
1129
1178
  .dpe-field {
@@ -1134,19 +1183,20 @@ dpe-node-icon {
1134
1183
 
1135
1184
  .dpe-field__label {
1136
1185
  color: var(--dpe-text-muted, #6b7086);
1137
- font-size: 11px;
1186
+ font-size: 12px;
1138
1187
  font-weight: 600;
1139
1188
  }
1140
1189
 
1141
1190
  .dpe-field__hint {
1142
1191
  color: var(--dpe-text-subtle, #98a2b3);
1143
- font-size: 10px;
1192
+ font-size: 11px;
1144
1193
  }
1145
1194
 
1146
1195
  /* Un rilievo del backend sul campo: si mostra sotto, non in un tooltip. */
1147
1196
  .dpe-field__issue {
1148
1197
  color: var(--dpe-error, #dc2626);
1149
- font-size: 10px;
1198
+ font-size: 11px;
1199
+ line-height: 1.45;
1150
1200
  }
1151
1201
 
1152
1202
  .dpe-field__issue--warning {
@@ -1164,13 +1214,13 @@ dpe-node-icon {
1164
1214
  .dpe-form textarea {
1165
1215
  box-sizing: border-box;
1166
1216
  width: 100%;
1167
- padding: 5px 7px;
1217
+ padding: 6px 8px;
1168
1218
  border: 1px solid var(--dpe-border, #e2e5eb);
1169
1219
  border-radius: var(--dpe-radius-xs, 6px);
1170
1220
  background: var(--dpe-surface, #fff);
1171
1221
  color: var(--dpe-text, #1a1c23);
1172
1222
  font: inherit;
1173
- font-size: 12px;
1223
+ font-size: 13px;
1174
1224
  }
1175
1225
 
1176
1226
  .dpe-form input:focus-visible,
@@ -1210,39 +1260,50 @@ dpe-node-icon {
1210
1260
  min-width: 0;
1211
1261
  }
1212
1262
 
1263
+ /*
1264
+ * Un bottone dentro una `.dpe-row` e' un'**azione accanto a un campo**, non un campo: si dimensiona
1265
+ * sul proprio testo. Diviso in parti uguali come gli altri figli, nella colonna larga della dialog
1266
+ * «Rinomina» diventava un bottone da quattrocento pixel accanto a un campo da quattrocento, e i
1267
+ * bottoni «rimuovi» delle liste altrettanto. Nei 316px della vecchia colonna non si vedeva, perche'
1268
+ * nessuno dei due aveva spazio da sprecare.
1269
+ */
1270
+ .dpe-row > button {
1271
+ flex: 0 0 auto;
1272
+ }
1273
+
1213
1274
  .dpe-table {
1214
1275
  width: 100%;
1215
1276
  border-collapse: collapse;
1216
- font-size: 11px;
1277
+ font-size: 12px;
1217
1278
  }
1218
1279
 
1219
1280
  .dpe-table th {
1220
- padding: 3px 4px;
1281
+ padding: 5px 6px;
1221
1282
  color: var(--dpe-text-muted, #6b7086);
1222
- font-size: 10px;
1283
+ font-size: 12px;
1223
1284
  font-weight: 600;
1224
1285
  text-align: left;
1225
1286
  }
1226
1287
 
1227
1288
  .dpe-table td {
1228
- padding: 2px 4px;
1289
+ padding: 4px 6px;
1229
1290
  vertical-align: top;
1230
1291
  }
1231
1292
 
1232
1293
  .dpe-table input,
1233
1294
  .dpe-table select {
1234
- padding: 3px 5px;
1235
- font-size: 11px;
1295
+ padding: 5px 6px;
1296
+ font-size: 12px;
1236
1297
  }
1237
1298
 
1238
1299
  .dpe-btn {
1239
- padding: 4px 9px;
1300
+ padding: 5px 10px;
1240
1301
  border: 1px solid var(--dpe-border, #e2e5eb);
1241
1302
  border-radius: var(--dpe-radius-xs, 6px);
1242
1303
  background: var(--dpe-surface, #fff);
1243
1304
  color: var(--dpe-text, #1a1c23);
1244
1305
  font: inherit;
1245
- font-size: 11px;
1306
+ font-size: 12px;
1246
1307
  cursor: pointer;
1247
1308
  }
1248
1309
 
@@ -1274,7 +1335,7 @@ dpe-node-icon {
1274
1335
 
1275
1336
  .dpe-section__title {
1276
1337
  margin: 0;
1277
- font-size: 11px;
1338
+ font-size: 12px;
1278
1339
  font-weight: 700;
1279
1340
  letter-spacing: 0.03em;
1280
1341
  text-transform: uppercase;
@@ -1289,7 +1350,7 @@ dpe-node-icon {
1289
1350
  border-radius: var(--dpe-radius-xs, 6px);
1290
1351
  background: var(--dpe-surface-alt, #f7f8fa);
1291
1352
  color: var(--dpe-text-muted, #6b7086);
1292
- font-size: 11px;
1353
+ font-size: 12px;
1293
1354
  line-height: 1.45;
1294
1355
  }
1295
1356
 
@@ -1307,7 +1368,7 @@ dpe-node-icon {
1307
1368
 
1308
1369
  .dpe-empty {
1309
1370
  color: var(--dpe-text-subtle, #98a2b3);
1310
- font-size: 11px;
1371
+ font-size: 12px;
1311
1372
  font-style: italic;
1312
1373
  }
1313
1374
 
@@ -1317,86 +1378,398 @@ dpe-node-icon {
1317
1378
  font-weight: 600;
1318
1379
  }
1319
1380
 
1320
- /* =============================================================== ispettore */
1381
+ /* ================================================= ispettore e fatti del nodo */
1382
+ /*
1383
+ * I due componenti che stanno nelle colonne della dialog. **Nessuno dei due dichiara
1384
+ * `overflow`**: lo scorrimento e' della colonna che li contiene, e due contenitori annidati con
1385
+ * `overflow-y: auto` sono il modo tipico di ritrovarsi due barre e non sapere quale scorre. Anche
1386
+ * il `padding` e' della colonna, per la regola della casa: il posizionamento e' del contenitore.
1387
+ *
1388
+ * `display: block` va dichiarato: un elemento personalizzato e' `inline` per difetto, e un
1389
+ * contenitore inline con dentro dei blocchi rende un layout che sembra rotto senza errori.
1390
+ */
1321
1391
 
1322
- dpe-node-inspector {
1392
+ dpe-node-inspector,
1393
+ dpe-node-facts {
1323
1394
  display: block;
1324
- padding: 12px;
1325
- overflow: auto;
1326
1395
  }
1327
1396
 
1328
- .dpe-inspector__head {
1397
+ /*
1398
+ * Le due liste sotto sono nate nell'ispettore. `.dpe-columns`/`.dpe-column` ora servono a
1399
+ * `dpe-node-facts`, e `.dpe-multi__*` alla striscia della selezione multipla nel guscio: i nomi
1400
+ * restano perche' sono cio' che rendono, non dove stanno.
1401
+ */
1402
+
1403
+ .dpe-columns {
1404
+ display: flex;
1405
+ flex-wrap: wrap;
1406
+ gap: 4px;
1407
+ }
1408
+
1409
+ .dpe-column {
1410
+ padding: 2px 7px;
1411
+ border: 1px solid var(--dpe-border, #e2e5eb);
1412
+ border-radius: 999px;
1413
+ background: var(--dpe-surface-alt, #f7f8fa);
1414
+ font-size: 11px;
1415
+ }
1416
+
1417
+ .dpe-column--nullable {
1418
+ border-style: dashed;
1419
+ }
1420
+
1421
+ .dpe-multi__names {
1422
+ display: flex;
1423
+ flex-wrap: wrap;
1424
+ gap: 4px;
1425
+ margin: 8px 0;
1426
+ padding: 0;
1427
+ list-style: none;
1428
+ }
1429
+
1430
+ .dpe-multi__name {
1431
+ padding: 2px 7px;
1432
+ border: 1px solid var(--dpe-border, #e2e5eb);
1433
+ border-radius: 999px;
1434
+ background: var(--dpe-surface-alt, #f7f8fa);
1435
+ font-family: var(--dpe-font-mono, monospace);
1436
+ font-size: 11px;
1437
+ }
1438
+
1439
+ /* ========================================================= dialog del nodo */
1440
+ /*
1441
+ * La finestra di modifica di un nodo: elemento `<dialog>` nativo aperto con `showModal()`
1442
+ * (ADR 0026). Dal browser arrivano Esc, il focus trap, il fondo inerte, `::backdrop` e il top
1443
+ * layer — cioe' **nessun `z-index`**: in tutto questo foglio ne esiste uno solo, e vale 1.
1444
+ *
1445
+ * Tre trappole, che costerebbero un giro di verifica ciascuna.
1446
+ *
1447
+ * 1. **Il foglio dell'agente utente va disfatto in modo esplicito.** `<dialog>` arriva con
1448
+ * `padding: 1em`, `border: solid`, `background: canvas` e `color: canvastext`, piu'
1449
+ * `max-width`/`max-height: calc(100% - 6px - 2em)` sulla forma modale. `color: canvastext`
1450
+ * **ignora il tema**: senza `color: var(--dpe-text, …)` il testo della dialog resta nero anche
1451
+ * sotto `data-dpe-theme="dark"`. E i due `max-*` vanno riscritti, altrimenti le misure qui
1452
+ * sotto non si applicano.
1453
+ * 2. **`::backdrop` non erede i token in modo affidabile.** Storicamente non erede da nessuno; la
1454
+ * revisione recente della specifica lo fa eredere dall'elemento originante, con supporto
1455
+ * disuguale. Quindi si scrive `var(--dpe-scrim, …)` **con ripiego**: dove l'eredita' funziona
1456
+ * l'ospite ritematizza, dove non funziona vale il valore scritto e il risultato e' comunque
1457
+ * giusto.
1458
+ * 3. **Non si stila la dialog chiusa.** Il foglio dell'agente utente le da' `display: none`; le
1459
+ * regole di layout valgono su `dialog[open]`, altrimenti si vince su quel `display: none` e la
1460
+ * finestra e' visibile all'avvio.
1461
+ */
1462
+
1463
+ /*
1464
+ * Il componente non deve occupare una riga nella colonna flex del guscio: cio' che si vede e' la
1465
+ * dialog, e la dialog vive nel top layer.
1466
+ */
1467
+ dpe-node-dialog {
1468
+ display: contents;
1469
+ }
1470
+
1471
+ .dpe-dialog {
1472
+ /* Le misure: **altezza fissa**, non `max-height`. Con l'altezza automatica la finestra si
1473
+ ridimensiona quando si aggiunge una riga di mappatura o cambia `transformType`, e il contenuto
1474
+ si sposta sotto il puntatore mentre si lavora. I due `max-*` ripetono le stesse misure solo per
1475
+ disfare quelli del foglio dell'agente utente. */
1476
+ box-sizing: border-box;
1477
+ width: min(1180px, 92vw);
1478
+ max-width: min(1180px, 92vw);
1479
+ height: min(760px, 88vh);
1480
+ max-height: min(760px, 88vh);
1481
+ margin: auto;
1482
+ padding: 0;
1483
+ border: 1px solid var(--dpe-border-strong, #cfd4de);
1484
+ border-radius: var(--dpe-radius-lg, 12px);
1485
+ background: var(--dpe-surface, #fff);
1486
+ /* Senza questa riga il testo resta `canvastext` e il tema scuro non lo raggiunge. */
1487
+ color: var(--dpe-text, #1a1c23);
1488
+ box-shadow: var(--dpe-shadow-lg, 0 18px 44px rgb(16 24 40 / 18%));
1489
+ font: inherit;
1490
+ /* Lo scorrimento sta sulle due colonne interne, **mai** sulla dialog. */
1491
+ overflow: hidden;
1492
+ /*
1493
+ * Contenitore della container query che impila le colonne (in fondo al blocco).
1494
+ *
1495
+ * Sta qui e **non** su `.dpe-dialog__body`, e non e' un dettaglio: una container query non puo'
1496
+ * stilare il **proprio** contenitore, solo i suoi discendenti. Con `container-type` sul corpo la
1497
+ * regola `@container` che cambia `grid-template-columns` del corpo non si applicava mai —
1498
+ * misurato: a 800px di finestra il corpo restava a due colonne, senza nessun errore. La
1499
+ * larghezza che decide resta quella del corpo, perche' il corpo riempie la dialog.
1500
+ */
1501
+ container-type: inline-size;
1502
+ }
1503
+
1504
+ .dpe-dialog::backdrop {
1505
+ background: var(--dpe-scrim, rgba(16, 18, 24, 0.55));
1506
+ }
1507
+
1508
+ /* Layout solo sull'elemento **aperto**: vedi la trappola 3. */
1509
+ .dpe-dialog[open] {
1329
1510
  display: flex;
1511
+ flex-direction: column;
1512
+ }
1513
+
1514
+ /* ------------------------------------------------------------------ testata */
1515
+
1516
+ .dpe-dialog__head {
1517
+ display: flex;
1518
+ flex: 0 0 auto;
1330
1519
  align-items: center;
1331
- gap: 8px;
1332
- margin-bottom: 10px;
1520
+ gap: 10px;
1521
+ padding: 12px 14px;
1522
+ border-bottom: 1px solid var(--dpe-border, #e2e5eb);
1523
+ background: var(--dpe-surface, #fff);
1333
1524
  }
1334
1525
 
1335
1526
  /* Pastiglia identica a quella della palette e della card: stessa misura, stessi token. */
1336
- .dpe-inspector__icon {
1527
+ .dpe-dialog__icon {
1337
1528
  display: inline-flex;
1338
1529
  flex: 0 0 auto;
1339
1530
  align-items: center;
1340
1531
  justify-content: center;
1341
- width: 26px;
1342
- height: 26px;
1532
+ width: 28px;
1533
+ height: 28px;
1343
1534
  border-radius: var(--dpe-radius-sm, 8px);
1344
1535
  background: var(--dpe-cat-soft, #eef0f4);
1345
1536
  color: var(--dpe-cat, #6b7086);
1346
1537
  }
1347
1538
 
1348
- .dpe-inspector__name {
1349
- flex: 1 1 auto;
1539
+ .dpe-dialog__label {
1350
1540
  overflow: hidden;
1351
1541
  min-width: 0;
1542
+ color: var(--dpe-text, #1a1c23);
1543
+ font-size: 15px;
1352
1544
  text-overflow: ellipsis;
1353
1545
  white-space: nowrap;
1354
1546
  }
1355
1547
 
1356
- .dpe-inspector__category {
1357
- /* All'estremita' opposta del titolo, come prima di avere l'icona in testa. */
1358
- margin-left: auto;
1548
+ .dpe-dialog__category {
1359
1549
  flex: 0 0 auto;
1360
1550
  color: var(--dpe-text-muted, #6b7086);
1361
- font-size: 11px;
1362
- text-transform: uppercase;
1551
+ font-size: 12px;
1363
1552
  letter-spacing: 0.04em;
1553
+ text-transform: uppercase;
1364
1554
  }
1365
1555
 
1366
- .dpe-columns {
1556
+ /* Nome tecnico: e' la chiave con cui i nodi a valle si riferiscono a questo, quindi monospaziato. */
1557
+ .dpe-dialog__name {
1558
+ flex: 0 1 auto;
1559
+ overflow: hidden;
1560
+ /* `margin-left: auto` lo spinge a destra, accanto al comando di chiusura. */
1561
+ margin-left: auto;
1562
+ color: var(--dpe-text-muted, #6b7086);
1563
+ font-family: var(--dpe-font-mono, monospace);
1564
+ font-size: 12px;
1565
+ text-overflow: ellipsis;
1566
+ white-space: nowrap;
1567
+ }
1568
+
1569
+ /* -------------------------------------------------------------------- corpo */
1570
+
1571
+ /*
1572
+ * Due colonne: i campi a sinistra, i fatti dal backend a destra. `min-height: 0` non e' rumore —
1573
+ * senza, un figlio flex non scende sotto il proprio contenuto e il fondo del form viene tagliato
1574
+ * **senza** barra di scorrimento (la stessa lezione gia' pagata sul pannello inferiore).
1575
+ *
1576
+ * L'impilamento sotto i 900px lo decide una **container query** e non una media query, perche' cio'
1577
+ * che conta e' la larghezza del contenitore e non quella della finestra del browser: e' la
1578
+ * dipendenza vera, e dichiararla e' gratis adesso e costosa dopo. Il `container-type` sta sulla
1579
+ * dialog — vedi il commento la' sopra, e' l'unico posto dove funziona.
1580
+ */
1581
+ .dpe-dialog__body {
1582
+ display: grid;
1583
+ flex: 1 1 auto;
1584
+ grid-template-columns: minmax(0, 1fr) 300px;
1585
+ min-height: 0;
1586
+ }
1587
+
1588
+ /*
1589
+ * Le due colonne che scorrono **nella modalita' affiancata**. Chi scorre sta scritto qui, una volta,
1590
+ * perche' e' la riga che si sbaglia:
1591
+ *
1592
+ * - **affiancate** (corpo oltre 900px): scorrono `.dpe-dialog__main` e `.dpe-dialog__side`, una per
1593
+ * conto proprio, e il corpo **non** scorre;
1594
+ * - **impilate** (corpo fino a 900px): scorre **il corpo**, e le due aree tornano ad altezza
1595
+ * automatica. Vedi la container query in fondo al blocco.
1596
+ *
1597
+ * Le due modalita' sono **mutuamente esclusive**, non sovrapposte: due contenitori annidati con
1598
+ * `overflow-y: auto` danno due barre e nessuno sa quale scorre — nel progetto di riferimento il
1599
+ * commento che lo dichiarava nominava perfino il contenitore sbagliato.
1600
+ *
1601
+ * Nessuno scorrimento annidato dentro le colonne: `dpe-node-inspector` e `dpe-node-facts` non
1602
+ * dichiarano `overflow`.
1603
+ *
1604
+ * `scrollbar-gutter: stable`: senza, la comparsa della barra stringe la colonna, il contenuto che
1605
+ * dipende dalla larghezza rientra sotto la soglia, la barra sparisce, e il ciclo non finisce.
1606
+ * `overscroll-behavior: contain`: la rotella a fondo corsa non deve proseguire nel canvas, che
1607
+ * sotto **zooma**.
1608
+ *
1609
+ * **Guardia per il futuro**: il giorno in cui un ispettore introducesse una tendina scritta a mano
1610
+ * (`position: absolute`), quella tendina non potrebbe stare qui dentro — verrebbe tagliata in
1611
+ * silenzio. Oggi non e' un problema perche' gli elenchi sono `<select>` e `<datalist>` **nativi**,
1612
+ * che il browser rende fuori dal layout e che nessun `overflow` puo' tagliare.
1613
+ */
1614
+ .dpe-dialog__main,
1615
+ .dpe-dialog__side {
1616
+ min-width: 0;
1617
+ min-height: 0;
1618
+ padding: 14px;
1619
+ overflow: auto;
1620
+ overscroll-behavior: contain;
1621
+ scrollbar-gutter: stable;
1622
+ }
1623
+
1624
+ .dpe-dialog__side {
1367
1625
  display: flex;
1368
- flex-wrap: wrap;
1369
- gap: 4px;
1626
+ flex-direction: column;
1627
+ gap: 10px;
1628
+ border-left: 1px solid var(--dpe-border, #e2e5eb);
1629
+ background: var(--dpe-surface-alt, #f7f8fa);
1370
1630
  }
1371
1631
 
1372
- .dpe-column {
1632
+ /*
1633
+ * La pastiglia «non compilabile» (**I10**) in testa alla colonna dei fatti.
1634
+ *
1635
+ * Le regole di `.dpe-badge` esistono gia', ma **dichiarano la specificita' che serve a battere
1636
+ * @foblex/flow** (`dpe-canvas .dpe-flow .dpe-badge`): fuori dal canvas non arrivano, e riusare la
1637
+ * classe senza questa regola darebbe una pastiglia senza pastiglia — testo nudo, nessun errore e
1638
+ * nessun modo di accorgersene se non guardando. Stessi token del badge sulla card, cosi' i due
1639
+ * posti dicono la stessa cosa con lo stesso aspetto invece di divergere.
1640
+ */
1641
+ dpe-node-facts .dpe-badge {
1642
+ display: inline-block;
1643
+ margin-right: 6px;
1373
1644
  padding: 1px 6px;
1374
1645
  border: 1px solid var(--dpe-border, #e2e5eb);
1375
1646
  border-radius: 999px;
1376
- background: var(--dpe-surface-alt, #f7f8fa);
1377
- font-size: 10px;
1647
+ background: var(--dpe-surface, #fff);
1648
+ color: var(--dpe-text-muted, #6b7086);
1649
+ font-size: 11px;
1650
+ white-space: nowrap;
1378
1651
  }
1379
1652
 
1380
- .dpe-column--nullable {
1381
- border-style: dashed;
1653
+ dpe-node-facts .dpe-badge--not-compilable {
1654
+ border-color: var(--dpe-not-compilable, #7c5cd6);
1655
+ color: var(--dpe-not-compilable, #7c5cd6);
1382
1656
  }
1383
1657
 
1384
- .dpe-multi__names {
1658
+ /*
1659
+ * Sotto i 900px di **corpo** le colonne si impilano, i fatti sotto i campi — e **lo scorrimento
1660
+ * diventa uno solo**, quello del corpo. Si scorre una volta, dal primo campo fino ai rilievi in
1661
+ * fondo.
1662
+ *
1663
+ * Perche' l'altezza non si ripartisce fra le due righe: ripartendola (`1.6fr` / `1fr`) su una
1664
+ * finestra alta 760px il form riceveva **399px** e i fatti in sola lettura se ne prendevano **249**
1665
+ * — misurato, con la mappatura dei campi visibile per **una riga sola** e due rilievi con spazio in
1666
+ * abbondanza sotto. E su un nodo con sei rilievi il form si stringeva ancora: e' lo stesso muro di
1667
+ * avvisi che mettere i fatti **di fianco** evita, rientrato dalla porta di servizio. Con righe
1668
+ * dimensionate sul contenuto nessuna delle due cede altezza all'altra, e cio' che non entra si
1669
+ * raggiunge scorrendo.
1670
+ *
1671
+ * `scrollbar-gutter` e `overscroll-behavior` si spostano **qui**, sul contenitore che scorre in
1672
+ * questa modalita'. Sulle due aree diventano inerti da se', perche' non sono piu' contenitori
1673
+ * scorrevoli: non serve annullarle.
1674
+ *
1675
+ * L'ordine conta. Queste regole hanno la **stessa** specificita' di quelle sopra — una container
1676
+ * query non ne aggiunge — quindi devono stare dopo. Spostare questo blocco piu' in alto rimette due
1677
+ * `overflow: auto` annidati senza che niente lo segnali.
1678
+ */
1679
+ @container (max-width: 900px) {
1680
+ /*
1681
+ * **Colonna flex, non griglia.** Con `grid-template-rows: auto auto` Chrome ha compresso la prima
1682
+ * riga allo spazio che restava — misurato: **479px per un contenuto di 1026** — e il form, ormai
1683
+ * con `overflow: visible`, dipingeva **sopra** la colonna dei fatti. Non un taglio: due testi
1684
+ * sovrapposti. In colonna flex con `flex: 0 0 auto` l'altezza di ciascuna area **e'** il proprio
1685
+ * contenuto e non c'e' niente da ripartire; cio' che eccede lo scorre il corpo.
1686
+ */
1687
+ .dpe-dialog__body {
1688
+ display: flex;
1689
+ flex-direction: column;
1690
+ /* `min-height: 0` resta dichiarato sopra: senza, questo contenitore non scende sotto il proprio
1691
+ contenuto e il fondo viene tagliato **senza** barra di scorrimento. */
1692
+ overflow-y: auto;
1693
+ overscroll-behavior: contain;
1694
+ scrollbar-gutter: stable;
1695
+ }
1696
+
1697
+ .dpe-dialog__main,
1698
+ .dpe-dialog__side {
1699
+ /* `0 0 auto`: base sul contenuto, e **nessuna** compressione. E' la riga che tiene separate le
1700
+ due aree. */
1701
+ flex: 0 0 auto;
1702
+ overflow: visible;
1703
+ }
1704
+
1705
+ .dpe-dialog__side {
1706
+ border-top: 1px solid var(--dpe-border, #e2e5eb);
1707
+ border-left: 0;
1708
+ }
1709
+ }
1710
+
1711
+ /* --------------------------------------------------------------------- piede */
1712
+
1713
+ .dpe-dialog__foot {
1385
1714
  display: flex;
1386
- flex-wrap: wrap;
1387
- gap: 4px;
1388
- margin: 8px 0;
1389
- padding: 0;
1390
- list-style: none;
1715
+ flex: 0 0 auto;
1716
+ align-items: center;
1717
+ gap: 10px;
1718
+ padding: 10px 14px;
1719
+ border-top: 1px solid var(--dpe-border, #e2e5eb);
1720
+ background: var(--dpe-surface-alt, #f7f8fa);
1391
1721
  }
1392
1722
 
1393
- .dpe-multi__name {
1394
- padding: 1px 6px;
1395
- border: 1px solid var(--dpe-border, #e2e5eb);
1396
- border-radius: 999px;
1723
+ /*
1724
+ * La nota che dice come si torna indietro. E' obbligatoria, non decorativa: le modifiche sono gia'
1725
+ * nel documento e **chiudere non annulla**, quindi l'unico modo di disfare e' ↶ nella barra.
1726
+ */
1727
+ .dpe-dialog__note {
1728
+ flex: 1 1 auto;
1729
+ margin: 0;
1730
+ color: var(--dpe-text-muted, #6b7086);
1731
+ font-size: 12px;
1732
+ line-height: 1.45;
1733
+ }
1734
+
1735
+ /*
1736
+ * I comandi della finestra hanno una classe propria e non `.dpe-btn`: `.dpe-btn` e' degli
1737
+ * ispettori, ed e' l'insieme di classi su cui l'ADR 0026 ha alzato la scala tipografica proprio
1738
+ * perche' lo usano **solo** loro. Riusarla qui renderebbe falsa quell'affermazione al primo
1739
+ * ritocco.
1740
+ */
1741
+ .dpe-dialog__btn {
1742
+ flex: 0 0 auto;
1743
+ padding: 6px 12px;
1744
+ border: 1px solid var(--dpe-border-strong, #cfd4de);
1745
+ border-radius: var(--dpe-radius-xs, 6px);
1746
+ background: var(--dpe-surface, #fff);
1747
+ color: var(--dpe-text, #1a1c23);
1748
+ font: inherit;
1749
+ font-size: 12px;
1750
+ cursor: pointer;
1751
+ }
1752
+
1753
+ .dpe-dialog__btn:hover {
1397
1754
  background: var(--dpe-surface-alt, #f7f8fa);
1398
- font-family: var(--dpe-font-mono, monospace);
1399
- font-size: 10px;
1755
+ }
1756
+
1757
+ .dpe-dialog__btn:focus-visible {
1758
+ outline: 2px solid var(--dpe-accent, #2f7d8f);
1759
+ outline-offset: 1px;
1760
+ }
1761
+
1762
+ .dpe-dialog__btn--icon {
1763
+ padding: 4px 9px;
1764
+ border-color: transparent;
1765
+ background: transparent;
1766
+ color: var(--dpe-text-muted, #6b7086);
1767
+ font-size: 13px;
1768
+ }
1769
+
1770
+ .dpe-dialog__btn--danger:hover {
1771
+ border-color: var(--dpe-error, #dc2626);
1772
+ color: var(--dpe-error, #dc2626);
1400
1773
  }
1401
1774
 
1402
1775
  /* ============================================================ diagnostiche */