flexdesk 0.5.0 → 0.6.1

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 (70) hide show
  1. package/README.md +654 -1
  2. package/css/base.css +2868 -0
  3. package/css/flexdesk.css +2868 -0
  4. package/css/tokens.css +72 -0
  5. package/dist/canvas.js +390 -0
  6. package/dist/canvas.js.map +7 -0
  7. package/dist/charts.js +2 -2
  8. package/dist/{chunk-24MS7W5Y.js → chunk-6NG7YVBG.js} +2 -470
  9. package/dist/chunk-6NG7YVBG.js.map +7 -0
  10. package/dist/chunk-H4LT43RS.js +475 -0
  11. package/dist/chunk-H4LT43RS.js.map +7 -0
  12. package/dist/{chunk-KH2GJTKR.js → chunk-IYV5JVYB.js} +29 -1
  13. package/dist/chunk-IYV5JVYB.js.map +7 -0
  14. package/dist/chunk-SN4LSOAR.js +532 -0
  15. package/dist/chunk-SN4LSOAR.js.map +7 -0
  16. package/dist/{chunk-CNXP3SIN.js → chunk-ZMCRDOCF.js} +2 -2
  17. package/dist/flexdesk.css +2868 -0
  18. package/dist/flow.js +10030 -0
  19. package/dist/flow.js.map +7 -0
  20. package/dist/tiles.js +9 -9
  21. package/dist/tokens.css +72 -0
  22. package/dist/widgets.js +87 -5
  23. package/dist/widgets.js.map +3 -3
  24. package/dist/wm.js +4 -2
  25. package/dist/wm.js.map +1 -1
  26. package/package.json +9 -1
  27. package/src/canvas/canvas_adapter.js +523 -0
  28. package/src/canvas/edge_router.js +392 -0
  29. package/src/canvas/graph/connector_router.js +189 -0
  30. package/src/canvas/graph/history_service.js +170 -0
  31. package/src/canvas/graph/node_platform.js +116 -0
  32. package/src/canvas/index.js +16 -0
  33. package/src/flow/canvas_editor/editor.js +1081 -0
  34. package/src/flow/canvas_editor/index.js +16 -0
  35. package/src/flow/canvas_editor/layout.js +118 -0
  36. package/src/flow/canvas_editor/strings.js +37 -0
  37. package/src/flow/kit/always_before.js +325 -0
  38. package/src/flow/kit/catalogue.js +170 -0
  39. package/src/flow/kit/chip_input.js +461 -0
  40. package/src/flow/kit/dom.js +205 -0
  41. package/src/flow/kit/findings.js +129 -0
  42. package/src/flow/kit/history.js +173 -0
  43. package/src/flow/kit/index.js +38 -0
  44. package/src/flow/kit/keys.js +127 -0
  45. package/src/flow/kit/logic_graph.js +210 -0
  46. package/src/flow/kit/references.js +199 -0
  47. package/src/flow/kit/settings_panel.js +357 -0
  48. package/src/flow/kit/settings_schema.js +175 -0
  49. package/src/flow/kit/step_picker.js +209 -0
  50. package/src/flow/kit/strings.js +102 -0
  51. package/src/flow/kit/value_picker.js +238 -0
  52. package/src/flow/kit/widgets.js +763 -0
  53. package/src/flow/lanes/editor.js +1469 -0
  54. package/src/flow/lanes/index.js +26 -0
  55. package/src/flow/lanes/layout.js +525 -0
  56. package/src/flow/lanes/pipeline.js +327 -0
  57. package/src/flow/lanes/preview.js +109 -0
  58. package/src/flow/lanes/strings.js +98 -0
  59. package/src/flow/outline/editor.js +1511 -0
  60. package/src/flow/outline/index.js +20 -0
  61. package/src/flow/outline/mapping.js +286 -0
  62. package/src/flow/outline/menu.js +154 -0
  63. package/src/flow/outline/operations.js +738 -0
  64. package/src/flow/outline/recognise.js +755 -0
  65. package/src/flow/outline/strings.js +135 -0
  66. package/src/ui/components/data_table.js +40 -0
  67. package/src/ui/utils/scroll_lock.js +111 -0
  68. package/dist/chunk-24MS7W5Y.js.map +0 -7
  69. package/dist/chunk-KH2GJTKR.js.map +0 -7
  70. /package/dist/{chunk-CNXP3SIN.js.map → chunk-ZMCRDOCF.js.map} +0 -0
package/css/flexdesk.css CHANGED
@@ -713,6 +713,39 @@ body.twm-dt-col-resizing {
713
713
  color: var(--text-dim, #666);
714
714
  font-style: italic;
715
715
  }
716
+ /* 0.6.1 `diff` — one side of a comparison. A row that is NEW on this side is
717
+ * green, one that is GONE on this side red, a changed row carries an amber
718
+ * left edge and its changed cells an amber fill, and a GAP — the place a row
719
+ * holds on the other side — is hatched, so the eye reads it as "nothing here"
720
+ * rather than as an empty row. (0,3,2) and up, for `twm-dt-cell--null`'s
721
+ * reason above; a selected row keeps its own colour (`:not(.selected)`). */
722
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--added:not(.selected) > td {
723
+ background: color-mix(in srgb, var(--color-success, #3fb950) 16%, transparent);
724
+ }
725
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--removed:not(.selected) > td {
726
+ background: color-mix(in srgb, var(--color-danger, #c74e4e) 18%, transparent);
727
+ }
728
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--removed > td {
729
+ text-decoration: line-through;
730
+ text-decoration-color: color-mix(in srgb, var(--color-danger, #c74e4e) 70%, transparent);
731
+ }
732
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--added > td:first-child {
733
+ box-shadow: inset 3px 0 0 0 var(--color-success, #3fb950);
734
+ }
735
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--removed > td:first-child {
736
+ box-shadow: inset 3px 0 0 0 var(--color-danger, #c74e4e);
737
+ }
738
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--changed > td:first-child {
739
+ box-shadow: inset 3px 0 0 0 var(--color-warning, #ff9800);
740
+ }
741
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff:not(.selected) > td.twm-dt-diff__cell--changed {
742
+ background: color-mix(in srgb, var(--color-warning, #ff9800) 22%, transparent);
743
+ }
744
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-diff--gap > td.twm-dt-diff__gap {
745
+ background: repeating-linear-gradient(135deg,
746
+ transparent 0 6px,
747
+ color-mix(in srgb, var(--text-muted, #888) 14%, transparent) 6px 7px);
748
+ }
716
749
  /* `emptyState` and `setError` with no rows: the box's own words, which may
717
750
  * wrap — muted for an empty state, red for a failure, in both densities. Quiet
718
751
  * while loading — an empty table that is still loading is not empty. */
@@ -7381,3 +7414,2838 @@ tr:hover .twm-row-action { opacity: 1; }
7381
7414
  .twm-autoscroll-bar--active .twm-autoscroll-thumb {
7382
7415
  background: rgba(255, 255, 255, 0.45);
7383
7416
  }
7417
+
7418
+
7419
+ /* ══ FLOW · KIT ═══════════════════════════════════════════════════════ */
7420
+ /* The shared flow-editor kit (36 §3, §3.12): the settings panel and its
7421
+ * fields, the generic widgets, reference chips and the chip input, the two
7422
+ * pickers and the findings strip. Every colour is a token (`tokens.css`'s
7423
+ * `--twm-flow-*` and the canonical ones); a category's TONE picks a pair.
7424
+ * Every class here is set by a module under src/flow/kit/, and every class
7425
+ * those modules set has a rule here — tests/flow_kit_css.test.mjs holds both
7426
+ * directions, because jsdom applies no stylesheet. */
7427
+
7428
+ /* `hidden` must win over the `display: flex` these blocks use. */
7429
+ .twm-flow-panel[hidden],
7430
+ .twm-flow-panel [hidden],
7431
+ .twm-flow-popover [hidden],
7432
+ .twm-flow-strip[hidden],
7433
+ .twm-flow-strip [hidden] {
7434
+ display: none !important;
7435
+ }
7436
+
7437
+ /* ── the settings panel ─────────────────────────────────────────────── */
7438
+ .twm-flow-panel {
7439
+ display: flex;
7440
+ flex-direction: column;
7441
+ gap: 14px;
7442
+ min-width: 0;
7443
+ box-sizing: border-box;
7444
+ padding: 16px 20px 28px;
7445
+ background: var(--surface-1);
7446
+ color: var(--text-body);
7447
+ font-family: var(--font-family-sans);
7448
+ font-size: var(--font-size-sm);
7449
+ line-height: 1.4;
7450
+ }
7451
+ .twm-flow-panel .twm-btn {
7452
+ min-height: 26px;
7453
+ padding: 0 9px;
7454
+ font-size: var(--font-size-sm);
7455
+ border-radius: 3px;
7456
+ }
7457
+ .twm-flow-panel__readonly {
7458
+ margin: 0;
7459
+ padding: 8px 10px;
7460
+ border-radius: var(--radius-sm);
7461
+ background: var(--twm-flow-warning-bg);
7462
+ border: 1px solid var(--twm-flow-warning-line);
7463
+ color: var(--twm-flow-warning-text);
7464
+ }
7465
+ .twm-flow-panel__head {
7466
+ display: flex;
7467
+ flex-wrap: wrap;
7468
+ gap: 12px;
7469
+ align-items: flex-start;
7470
+ }
7471
+ .twm-flow-panel__icon {
7472
+ flex: 0 0 34px;
7473
+ height: 34px;
7474
+ display: flex;
7475
+ align-items: center;
7476
+ justify-content: center;
7477
+ border-radius: 7px;
7478
+ }
7479
+ .twm-flow-panel__icon .material-symbols-outlined { font-size: 20px; }
7480
+ .twm-flow-panel__icon--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
7481
+ .twm-flow-panel__icon--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
7482
+ .twm-flow-panel__icon--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
7483
+ .twm-flow-panel__icon--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
7484
+ .twm-flow-panel__icon--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
7485
+ .twm-flow-panel__icon--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
7486
+ .twm-flow-panel__titles {
7487
+ flex: 1 1 240px;
7488
+ min-width: 0;
7489
+ display: flex;
7490
+ flex-direction: column;
7491
+ gap: 2px;
7492
+ }
7493
+ .twm-flow-panel__type {
7494
+ font-size: var(--font-size-xs);
7495
+ color: var(--twm-flow-muted);
7496
+ text-transform: uppercase;
7497
+ letter-spacing: .05em;
7498
+ }
7499
+ .twm-flow-panel__title {
7500
+ margin: 0;
7501
+ font-size: 17px;
7502
+ font-weight: var(--font-weight-semibold);
7503
+ color: var(--text-primary);
7504
+ overflow-wrap: anywhere;
7505
+ }
7506
+ .twm-flow-panel__title-input {
7507
+ box-sizing: border-box;
7508
+ width: 100%;
7509
+ margin-left: -5px;
7510
+ padding: 1px 4px;
7511
+ font: inherit;
7512
+ font-size: 17px;
7513
+ font-weight: var(--font-weight-semibold);
7514
+ color: var(--text-primary);
7515
+ background: transparent;
7516
+ border: 1px solid transparent;
7517
+ border-radius: 3px;
7518
+ user-select: text;
7519
+ }
7520
+ .twm-flow-panel__title-input:hover { border-color: var(--twm-flow-control-border); }
7521
+ .twm-flow-panel__title-input:focus {
7522
+ outline: none;
7523
+ border-color: var(--twm-flow-focus);
7524
+ background: var(--twm-flow-control-bg);
7525
+ }
7526
+ .twm-flow-panel__where { color: var(--twm-flow-muted); }
7527
+ .twm-flow-panel__actions {
7528
+ display: flex;
7529
+ flex-wrap: wrap;
7530
+ gap: 6px;
7531
+ align-items: flex-start;
7532
+ }
7533
+ .twm-flow-panel__action { white-space: nowrap; }
7534
+ .twm-flow-panel__action-wrap {
7535
+ display: inline-flex;
7536
+ flex-direction: column;
7537
+ gap: 2px;
7538
+ max-width: 240px;
7539
+ }
7540
+ .twm-flow-panel__refusal {
7541
+ font-size: var(--font-size-xs);
7542
+ color: var(--twm-flow-warning);
7543
+ }
7544
+ .twm-flow-panel__description { margin: 0; color: var(--text-secondary); }
7545
+ .twm-flow-panel__id {
7546
+ padding: 6px 9px;
7547
+ font-family: var(--font-family-mono);
7548
+ font-size: var(--font-size-xs);
7549
+ color: var(--text-secondary);
7550
+ background: var(--surface-0);
7551
+ border: 1px solid var(--border-default);
7552
+ border-radius: var(--radius-sm);
7553
+ overflow-wrap: anywhere;
7554
+ }
7555
+ .twm-flow-panel__findings {
7556
+ margin: 0;
7557
+ padding: 0;
7558
+ list-style: none;
7559
+ display: flex;
7560
+ flex-direction: column;
7561
+ gap: 4px;
7562
+ }
7563
+ .twm-flow-panel__finding {
7564
+ display: flex;
7565
+ gap: 6px;
7566
+ align-items: flex-start;
7567
+ color: var(--twm-flow-error);
7568
+ }
7569
+ .twm-flow-panel__finding--warning { color: var(--twm-flow-warning); }
7570
+ .twm-flow-panel__finding-icon.material-symbols-outlined { font-size: 15px; line-height: 18px; }
7571
+ .twm-flow-panel__finding-text { min-width: 0; overflow-wrap: anywhere; }
7572
+ .twm-flow-panel__slot {
7573
+ display: flex;
7574
+ flex-direction: column;
7575
+ gap: 8px;
7576
+ min-width: 0;
7577
+ }
7578
+ .twm-flow-panel__fields {
7579
+ display: flex;
7580
+ flex-direction: column;
7581
+ gap: 13px;
7582
+ }
7583
+ .twm-flow-panel__note {
7584
+ margin: 0;
7585
+ padding: 8px 10px;
7586
+ border-radius: var(--radius-sm);
7587
+ background: var(--state-hover);
7588
+ color: var(--text-secondary);
7589
+ }
7590
+ .twm-flow-panel__note--info { border-left: 2px solid var(--twm-flow-blue-line); }
7591
+ .twm-flow-panel__note--warning {
7592
+ background: var(--twm-flow-warning-bg);
7593
+ color: var(--twm-flow-warning-text);
7594
+ }
7595
+
7596
+ /* ── a field: its label, its control, its finding, its help ─────────── */
7597
+ .twm-flow-field {
7598
+ display: flex;
7599
+ flex-wrap: wrap;
7600
+ gap: 4px 16px;
7601
+ align-items: flex-start;
7602
+ min-width: 0;
7603
+ }
7604
+ .twm-flow-field__label {
7605
+ flex: 0 0 150px;
7606
+ min-width: 0;
7607
+ padding-top: 5px;
7608
+ color: var(--text-secondary);
7609
+ }
7610
+ .twm-flow-field__name { overflow-wrap: anywhere; }
7611
+ .twm-flow-field__required { color: var(--twm-flow-error); }
7612
+ .twm-flow-field__body {
7613
+ flex: 1 1 280px;
7614
+ min-width: 0;
7615
+ display: flex;
7616
+ flex-direction: column;
7617
+ gap: 5px;
7618
+ }
7619
+ .twm-flow-field__error {
7620
+ margin: 0;
7621
+ display: flex;
7622
+ gap: 5px;
7623
+ align-items: flex-start;
7624
+ color: var(--twm-flow-error);
7625
+ }
7626
+ .twm-flow-field__error-icon.material-symbols-outlined { font-size: 15px; line-height: 17px; }
7627
+ .twm-flow-field__error-text { min-width: 0; overflow-wrap: anywhere; }
7628
+ .twm-flow-field--warning .twm-flow-field__error { color: var(--twm-flow-warning); }
7629
+ .twm-flow-field--error > .twm-flow-field__body > .twm-flow-input,
7630
+ .twm-flow-field--error > .twm-flow-field__body > .twm-flow-refbox,
7631
+ .twm-flow-field--error > .twm-flow-field__body > .twm-flow-togglechips {
7632
+ border-color: var(--twm-flow-error);
7633
+ }
7634
+ .twm-flow-field__help {
7635
+ margin: 0;
7636
+ font-size: var(--font-size-xs);
7637
+ color: var(--twm-flow-muted);
7638
+ }
7639
+ .twm-flow-field__note {
7640
+ margin: 0;
7641
+ padding-top: 5px;
7642
+ font-size: var(--font-size-xs);
7643
+ color: var(--twm-flow-muted);
7644
+ }
7645
+ .twm-flow-field__kept {
7646
+ font-family: var(--font-family-mono);
7647
+ color: var(--text-secondary);
7648
+ }
7649
+ .twm-flow-field__refusal {
7650
+ margin: 0;
7651
+ padding: 6px 8px;
7652
+ border-radius: var(--radius-sm);
7653
+ background: var(--twm-flow-warning-bg);
7654
+ border: 1px solid var(--twm-flow-warning-line);
7655
+ color: var(--twm-flow-warning-text);
7656
+ }
7657
+ .twm-flow-field--group > .twm-flow-field__body { gap: 8px; }
7658
+ .twm-flow-field__group {
7659
+ display: flex;
7660
+ flex-direction: column;
7661
+ gap: 8px;
7662
+ min-width: 0;
7663
+ }
7664
+ .twm-flow-field__group > .twm-flow-field__summary {
7665
+ display: flex;
7666
+ align-items: center;
7667
+ gap: 6px;
7668
+ min-height: 26px;
7669
+ color: var(--text-secondary);
7670
+ cursor: pointer;
7671
+ list-style: none;
7672
+ }
7673
+ .twm-flow-field__group > .twm-flow-field__summary::-webkit-details-marker { display: none; }
7674
+ .twm-flow-field__group > .twm-flow-field__summary::before {
7675
+ content: '▸';
7676
+ flex: 0 0 auto;
7677
+ color: var(--twm-flow-muted);
7678
+ }
7679
+ .twm-flow-field__group[open] > .twm-flow-field__summary::before { content: '▾'; }
7680
+ .twm-flow-field__group > .twm-flow-field__summary:focus-visible {
7681
+ outline: 2px solid var(--twm-flow-focus);
7682
+ outline-offset: 1px;
7683
+ }
7684
+ .twm-flow-field__summary-text {
7685
+ min-width: 0;
7686
+ color: var(--twm-flow-muted);
7687
+ overflow-wrap: anywhere;
7688
+ }
7689
+ .twm-flow-field__group > .twm-flow-field > .twm-flow-field__label { flex-basis: 120px; }
7690
+ .twm-flow-field__rows {
7691
+ display: flex;
7692
+ flex-direction: column;
7693
+ gap: 5px;
7694
+ min-width: 0;
7695
+ }
7696
+ .twm-flow-field__row {
7697
+ display: flex;
7698
+ gap: 6px;
7699
+ align-items: center;
7700
+ min-width: 0;
7701
+ }
7702
+ .twm-flow-field__row > .twm-flow-input { flex: 0 0 34%; min-width: 0; }
7703
+ .twm-flow-field__row > .twm-flow-input--select { flex: 0 0 auto; width: auto; }
7704
+ .twm-flow-field__row > .twm-flow-refbox { flex: 1 1 auto; }
7705
+ .twm-flow-field__slot {
7706
+ display: flex;
7707
+ flex: 1 1 auto;
7708
+ min-width: 0;
7709
+ }
7710
+ .twm-flow-field__slot > .twm-flow-refbox { flex: 1 1 auto; }
7711
+ .twm-flow-field__add { align-self: flex-start; border-style: dashed; }
7712
+ .twm-flow-field__remove { flex: 0 0 26px; padding: 0; }
7713
+ .twm-flow-field__remove .twm-btn__glyph.material-symbols-outlined { font-size: 15px; }
7714
+
7715
+ /* ── controls ───────────────────────────────────────────────────────── */
7716
+ .twm-flow-input {
7717
+ box-sizing: border-box;
7718
+ width: 100%;
7719
+ min-width: 0;
7720
+ height: 26px;
7721
+ padding: 0 8px;
7722
+ font: inherit;
7723
+ font-size: var(--font-size-sm);
7724
+ color: var(--text-primary);
7725
+ background: var(--twm-flow-control-bg);
7726
+ border: 1px solid var(--twm-flow-control-border);
7727
+ border-radius: 3px;
7728
+ user-select: text;
7729
+ }
7730
+ .twm-flow-input:focus {
7731
+ outline: none;
7732
+ border-color: var(--twm-flow-focus);
7733
+ box-shadow: 0 0 0 1px var(--twm-flow-focus);
7734
+ }
7735
+ .twm-flow-input:disabled { opacity: 0.6; cursor: not-allowed; }
7736
+ .twm-flow-input--select { padding-right: 4px; cursor: pointer; }
7737
+ .twm-flow-input--area {
7738
+ height: auto;
7739
+ min-height: 52px;
7740
+ padding: 5px 8px;
7741
+ line-height: 1.4;
7742
+ resize: vertical;
7743
+ }
7744
+ .twm-flow-checkbox {
7745
+ margin: 6px 0 0;
7746
+ accent-color: var(--twm-flow-focus);
7747
+ }
7748
+
7749
+ /* ── a chip input, and the box with its Insert a value ──────────────── */
7750
+ .twm-flow-refbox {
7751
+ display: flex;
7752
+ align-items: flex-start;
7753
+ gap: 6px;
7754
+ min-width: 0;
7755
+ min-height: 26px;
7756
+ box-sizing: border-box;
7757
+ padding: 3px 4px 3px 8px;
7758
+ background: var(--twm-flow-control-bg);
7759
+ border: 1px solid var(--twm-flow-control-border);
7760
+ border-radius: 3px;
7761
+ }
7762
+ .twm-flow-refbox:focus-within {
7763
+ border-color: var(--twm-flow-focus);
7764
+ box-shadow: 0 0 0 1px var(--twm-flow-focus);
7765
+ }
7766
+ .twm-flow-refbox--mono { background: var(--surface-0); }
7767
+ .twm-flow-refbox__insert {
7768
+ flex: 0 0 auto;
7769
+ height: 20px;
7770
+ padding: 0 6px;
7771
+ font-family: var(--font-family-mono);
7772
+ font-size: var(--font-size-xs);
7773
+ color: var(--twm-flow-blue-fg);
7774
+ background: var(--surface-2);
7775
+ border: 1px solid var(--twm-flow-control-border);
7776
+ border-radius: 3px;
7777
+ cursor: pointer;
7778
+ }
7779
+ .twm-flow-refbox__insert:hover { border-color: var(--twm-flow-focus); }
7780
+ .twm-flow-refbox__insert:focus-visible {
7781
+ outline: 2px solid var(--twm-flow-focus);
7782
+ outline-offset: 1px;
7783
+ }
7784
+ .twm-flow-chipinput {
7785
+ position: relative;
7786
+ flex: 1 1 auto;
7787
+ min-width: 0;
7788
+ min-height: 18px;
7789
+ line-height: 18px;
7790
+ color: var(--text-primary);
7791
+ white-space: pre-wrap;
7792
+ overflow-wrap: anywhere;
7793
+ outline: none;
7794
+ cursor: text;
7795
+ -webkit-user-select: text;
7796
+ user-select: text;
7797
+ }
7798
+ .twm-flow-chipinput--mono {
7799
+ font-family: var(--font-family-mono);
7800
+ font-size: var(--font-size-sm);
7801
+ line-height: 21px;
7802
+ }
7803
+ .twm-flow-chipinput--multiline { min-height: 36px; }
7804
+ .twm-flow-chipinput--empty::before {
7805
+ content: attr(data-placeholder);
7806
+ position: absolute;
7807
+ left: 0;
7808
+ top: 0;
7809
+ color: var(--text-muted);
7810
+ pointer-events: none;
7811
+ }
7812
+ .twm-flow-chipinput[contenteditable="false"] { cursor: default; }
7813
+ .twm-flow-chip {
7814
+ display: inline-flex;
7815
+ align-items: center;
7816
+ height: 18px;
7817
+ padding: 0 6px;
7818
+ margin: 0 1px;
7819
+ box-sizing: border-box;
7820
+ border: 1px solid transparent;
7821
+ border-radius: 3px;
7822
+ font-family: var(--font-family-sans);
7823
+ font-size: var(--font-size-xs);
7824
+ line-height: 16px;
7825
+ white-space: nowrap;
7826
+ vertical-align: baseline;
7827
+ cursor: default;
7828
+ }
7829
+ .twm-flow-chip--violet { background: var(--twm-flow-violet-bg); border-color: var(--twm-flow-violet-line); color: var(--twm-flow-violet-fg); }
7830
+ .twm-flow-chip--teal { background: var(--twm-flow-teal-bg); border-color: var(--twm-flow-teal-line); color: var(--twm-flow-teal-fg); }
7831
+ .twm-flow-chip--amber { background: var(--twm-flow-amber-bg); border-color: var(--twm-flow-amber-line); color: var(--twm-flow-amber-fg); }
7832
+ .twm-flow-chip--grey { background: var(--twm-flow-grey-bg); border-color: var(--twm-flow-grey-line); color: var(--twm-flow-grey-fg); }
7833
+ .twm-flow-chip--blue { background: var(--twm-flow-blue-bg); border-color: var(--twm-flow-blue-line); color: var(--twm-flow-blue-fg); }
7834
+ .twm-flow-chip--indigo { background: var(--twm-flow-indigo-bg); border-color: var(--twm-flow-indigo-line); color: var(--twm-flow-indigo-fg); }
7835
+ .twm-flow-chip.twm-flow-chip--unknown {
7836
+ border-style: dashed;
7837
+ border-color: var(--twm-flow-error);
7838
+ color: var(--twm-flow-error);
7839
+ }
7840
+
7841
+ /* ── chips that toggle: enum-chips, upstream-columns ────────────────── */
7842
+ .twm-flow-togglechips {
7843
+ display: flex;
7844
+ flex-wrap: wrap;
7845
+ gap: 4px;
7846
+ align-items: center;
7847
+ min-height: 26px;
7848
+ box-sizing: border-box;
7849
+ padding: 3px 6px;
7850
+ background: var(--twm-flow-control-bg);
7851
+ border: 1px solid var(--twm-flow-control-border);
7852
+ border-radius: 3px;
7853
+ }
7854
+ .twm-flow-togglechip {
7855
+ height: 18px;
7856
+ padding: 0 8px;
7857
+ font: inherit;
7858
+ font-size: var(--font-size-xs);
7859
+ color: var(--twm-flow-muted);
7860
+ background: transparent;
7861
+ border: 1px solid var(--border-strong);
7862
+ border-radius: 9px;
7863
+ cursor: pointer;
7864
+ }
7865
+ .twm-flow-togglechip[aria-pressed="true"] {
7866
+ color: var(--text-primary);
7867
+ background: var(--surface-3);
7868
+ border-color: var(--surface-3);
7869
+ }
7870
+ .twm-flow-togglechip.twm-flow-togglechip--missing {
7871
+ border-style: dashed;
7872
+ border-color: var(--twm-flow-warning);
7873
+ color: var(--twm-flow-warning);
7874
+ }
7875
+ .twm-flow-togglechip:disabled { cursor: default; opacity: 0.7; }
7876
+ .twm-flow-togglechip:focus-visible {
7877
+ outline: 2px solid var(--twm-flow-focus);
7878
+ outline-offset: 1px;
7879
+ }
7880
+
7881
+ /* ── choice-cards ───────────────────────────────────────────────────── */
7882
+ .twm-flow-choices {
7883
+ display: flex;
7884
+ flex-direction: column;
7885
+ gap: 6px;
7886
+ padding-top: 4px;
7887
+ }
7888
+ .twm-flow-choice {
7889
+ display: flex;
7890
+ align-items: flex-start;
7891
+ gap: 8px;
7892
+ color: var(--text-primary);
7893
+ cursor: pointer;
7894
+ }
7895
+ .twm-flow-choice__radio {
7896
+ flex: 0 0 auto;
7897
+ margin: 2px 0 0;
7898
+ accent-color: var(--twm-flow-focus);
7899
+ }
7900
+ .twm-flow-choice__words {
7901
+ display: flex;
7902
+ flex-direction: column;
7903
+ gap: 1px;
7904
+ min-width: 0;
7905
+ }
7906
+ .twm-flow-choice__label { overflow-wrap: anywhere; }
7907
+ .twm-flow-choice__sub {
7908
+ font-size: var(--font-size-xs);
7909
+ color: var(--twm-flow-muted);
7910
+ }
7911
+
7912
+ /* ── the popover both pickers are drawn in ──────────────────────────── */
7913
+ .twm-flow-popover {
7914
+ position: fixed;
7915
+ z-index: var(--z-popover);
7916
+ display: flex;
7917
+ flex-direction: column;
7918
+ box-sizing: border-box;
7919
+ max-width: calc(100vw - 16px);
7920
+ max-height: calc(100vh - 16px);
7921
+ background: var(--surface-1);
7922
+ color: var(--text-body);
7923
+ border: 1px solid var(--twm-flow-control-border);
7924
+ border-radius: var(--radius-md);
7925
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
7926
+ font-family: var(--font-family-sans);
7927
+ font-size: var(--font-size-sm);
7928
+ line-height: 1.4;
7929
+ outline: none;
7930
+ }
7931
+ .twm-flow-popover--picker { width: 420px; }
7932
+ .twm-flow-popover--values { width: 430px; }
7933
+
7934
+ /* ── the step picker ────────────────────────────────────────────────── */
7935
+ .twm-flow-picker {
7936
+ display: flex;
7937
+ flex-direction: column;
7938
+ flex: 1 1 auto;
7939
+ min-height: 0;
7940
+ }
7941
+ .twm-flow-picker__head {
7942
+ display: flex;
7943
+ flex-direction: column;
7944
+ gap: 2px;
7945
+ padding: 12px 14px 8px;
7946
+ }
7947
+ .twm-flow-picker__title {
7948
+ font-size: var(--font-size-md);
7949
+ font-weight: var(--font-weight-semibold);
7950
+ color: var(--text-primary);
7951
+ }
7952
+ .twm-flow-picker__where { color: var(--twm-flow-muted); }
7953
+ .twm-flow-picker__search,
7954
+ .twm-flow-values__search {
7955
+ display: flex;
7956
+ align-items: center;
7957
+ gap: 6px;
7958
+ height: 28px;
7959
+ box-sizing: border-box;
7960
+ padding: 0 8px;
7961
+ background: var(--surface-0);
7962
+ border: 1px solid var(--twm-flow-control-border);
7963
+ border-radius: 3px;
7964
+ }
7965
+ .twm-flow-picker__search { margin: 0 14px 8px; }
7966
+ .twm-flow-picker__search:focus-within,
7967
+ .twm-flow-values__search:focus-within { border-color: var(--twm-flow-focus); }
7968
+ .twm-flow-picker__search-icon.material-symbols-outlined,
7969
+ .twm-flow-values__search-icon.material-symbols-outlined {
7970
+ font-size: 15px;
7971
+ color: var(--twm-flow-muted);
7972
+ }
7973
+ .twm-flow-picker__input,
7974
+ .twm-flow-values__input {
7975
+ flex: 1 1 auto;
7976
+ min-width: 0;
7977
+ height: 24px;
7978
+ padding: 0;
7979
+ font: inherit;
7980
+ color: var(--text-primary);
7981
+ background: transparent;
7982
+ border: 0;
7983
+ outline: none;
7984
+ user-select: text;
7985
+ }
7986
+ .twm-flow-picker__list {
7987
+ display: flex;
7988
+ flex-direction: column;
7989
+ flex: 1 1 auto;
7990
+ min-height: 0;
7991
+ overflow-y: auto;
7992
+ padding: 0 6px 6px;
7993
+ }
7994
+ .twm-flow-picker__group { display: flex; flex-direction: column; }
7995
+ .twm-flow-picker__group-label {
7996
+ padding: 6px 8px 3px;
7997
+ font-size: 10px;
7998
+ font-weight: var(--font-weight-semibold);
7999
+ letter-spacing: .08em;
8000
+ text-transform: uppercase;
8001
+ color: var(--twm-flow-muted);
8002
+ }
8003
+ .twm-flow-picker__items { display: flex; flex-direction: column; }
8004
+ .twm-flow-picker__items--grid {
8005
+ display: grid;
8006
+ grid-template-columns: repeat(2, minmax(0, 1fr));
8007
+ gap: 0 4px;
8008
+ }
8009
+ .twm-flow-picker__option {
8010
+ display: flex;
8011
+ align-items: center;
8012
+ gap: 10px;
8013
+ padding: 5px 8px;
8014
+ border-radius: var(--radius-sm);
8015
+ color: var(--text-primary);
8016
+ cursor: pointer;
8017
+ }
8018
+ .twm-flow-picker__option:hover { background: var(--state-hover); }
8019
+ .twm-flow-picker__option.twm-flow-picker__option--active { background: var(--state-selected); }
8020
+ .twm-flow-picker__option.twm-flow-picker__option--refused { cursor: not-allowed; }
8021
+ .twm-flow-picker__option--refused .twm-flow-picker__label { color: var(--twm-flow-muted); }
8022
+ .twm-flow-picker__option--refused .twm-flow-picker__chip { opacity: 0.5; }
8023
+ .twm-flow-picker__chip {
8024
+ flex: 0 0 22px;
8025
+ height: 22px;
8026
+ display: flex;
8027
+ align-items: center;
8028
+ justify-content: center;
8029
+ border-radius: 5px;
8030
+ }
8031
+ .twm-flow-picker__chip .material-symbols-outlined { font-size: 15px; }
8032
+ .twm-flow-picker__chip--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
8033
+ .twm-flow-picker__chip--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
8034
+ .twm-flow-picker__chip--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
8035
+ .twm-flow-picker__chip--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
8036
+ .twm-flow-picker__chip--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
8037
+ .twm-flow-picker__chip--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
8038
+ .twm-flow-picker__words {
8039
+ display: flex;
8040
+ flex-direction: column;
8041
+ min-width: 0;
8042
+ }
8043
+ .twm-flow-picker__label { overflow-wrap: anywhere; }
8044
+ .twm-flow-picker__sub,
8045
+ .twm-flow-picker__description {
8046
+ font-size: var(--font-size-xs);
8047
+ color: var(--twm-flow-muted);
8048
+ }
8049
+ .twm-flow-picker__refusal {
8050
+ font-size: var(--font-size-xs);
8051
+ color: var(--twm-flow-warning);
8052
+ }
8053
+ .twm-flow-picker__empty {
8054
+ margin: 0;
8055
+ padding: 4px 14px 10px;
8056
+ color: var(--twm-flow-muted);
8057
+ }
8058
+ .twm-flow-picker__foot {
8059
+ display: flex;
8060
+ flex-wrap: wrap;
8061
+ align-items: center;
8062
+ gap: 6px 14px;
8063
+ padding: 8px 14px;
8064
+ border-top: 1px solid var(--border-strong);
8065
+ font-size: var(--font-size-xs);
8066
+ color: var(--twm-flow-muted);
8067
+ }
8068
+ .twm-flow-picker__keys { flex: 1 1 auto; }
8069
+ .twm-flow-picker__paste {
8070
+ padding: 0;
8071
+ font: inherit;
8072
+ font-size: var(--font-size-xs);
8073
+ color: var(--twm-flow-blue-fg);
8074
+ background: transparent;
8075
+ border: 0;
8076
+ cursor: pointer;
8077
+ }
8078
+ .twm-flow-picker__paste:hover { text-decoration: underline; }
8079
+ .twm-flow-picker__paste:focus-visible {
8080
+ outline: 2px solid var(--twm-flow-focus);
8081
+ outline-offset: 1px;
8082
+ }
8083
+
8084
+ /* ── Insert a value ─────────────────────────────────────────────────── */
8085
+ .twm-flow-values {
8086
+ display: flex;
8087
+ flex-direction: column;
8088
+ flex: 1 1 auto;
8089
+ min-height: 0;
8090
+ }
8091
+ .twm-flow-values__head {
8092
+ display: flex;
8093
+ flex-direction: column;
8094
+ gap: 8px;
8095
+ padding: 12px 14px 8px;
8096
+ }
8097
+ .twm-flow-values__title {
8098
+ font-size: var(--font-size-md);
8099
+ font-weight: var(--font-weight-semibold);
8100
+ color: var(--text-primary);
8101
+ }
8102
+ .twm-flow-values__crumb {
8103
+ display: flex;
8104
+ align-items: center;
8105
+ gap: 8px;
8106
+ padding: 0 14px 6px;
8107
+ }
8108
+ .twm-flow-values__back {
8109
+ display: inline-flex;
8110
+ align-items: center;
8111
+ gap: 2px;
8112
+ height: 22px;
8113
+ padding: 0 6px 0 2px;
8114
+ font: inherit;
8115
+ color: var(--text-secondary);
8116
+ background: transparent;
8117
+ border: 1px solid var(--twm-flow-control-border);
8118
+ border-radius: 3px;
8119
+ cursor: pointer;
8120
+ }
8121
+ .twm-flow-values__back .material-symbols-outlined { font-size: 16px; }
8122
+ .twm-flow-values__back:focus-visible {
8123
+ outline: 2px solid var(--twm-flow-focus);
8124
+ outline-offset: 1px;
8125
+ }
8126
+ .twm-flow-values__path { color: var(--twm-flow-muted); }
8127
+ .twm-flow-values__list {
8128
+ display: flex;
8129
+ flex-direction: column;
8130
+ flex: 1 1 auto;
8131
+ min-height: 0;
8132
+ overflow-y: auto;
8133
+ padding: 0 6px 6px;
8134
+ }
8135
+ .twm-flow-values__group { display: flex; flex-direction: column; }
8136
+ .twm-flow-values__group-label {
8137
+ display: flex;
8138
+ flex-wrap: wrap;
8139
+ align-items: baseline;
8140
+ gap: 6px;
8141
+ padding: 8px 8px 3px;
8142
+ }
8143
+ .twm-flow-values__group-name {
8144
+ font-size: 10px;
8145
+ font-weight: var(--font-weight-semibold);
8146
+ letter-spacing: .08em;
8147
+ text-transform: uppercase;
8148
+ color: var(--twm-flow-muted);
8149
+ }
8150
+ .twm-flow-values__group-sub,
8151
+ .twm-flow-values__group-empty {
8152
+ font-size: var(--font-size-xs);
8153
+ color: var(--twm-flow-muted);
8154
+ }
8155
+ .twm-flow-values__grid {
8156
+ display: grid;
8157
+ grid-template-columns: repeat(2, minmax(0, 1fr));
8158
+ gap: 0 4px;
8159
+ }
8160
+ .twm-flow-values__chips {
8161
+ display: flex;
8162
+ flex-wrap: wrap;
8163
+ gap: 4px;
8164
+ padding: 2px 8px;
8165
+ }
8166
+ .twm-flow-values__option {
8167
+ color: var(--text-primary);
8168
+ cursor: pointer;
8169
+ }
8170
+ .twm-flow-values__option--row {
8171
+ display: flex;
8172
+ justify-content: space-between;
8173
+ gap: 8px;
8174
+ padding: 4px 8px;
8175
+ border-radius: var(--radius-sm);
8176
+ }
8177
+ .twm-flow-values__option--chip {
8178
+ display: inline-flex;
8179
+ align-items: center;
8180
+ height: 22px;
8181
+ box-sizing: border-box;
8182
+ padding: 0 8px;
8183
+ border: 1px solid var(--border-strong);
8184
+ border-radius: 11px;
8185
+ }
8186
+ .twm-flow-values__option:hover { background: var(--state-hover); }
8187
+ .twm-flow-values__option.twm-flow-values__option--active {
8188
+ background: var(--state-selected);
8189
+ box-shadow: inset 0 0 0 1px var(--twm-flow-focus);
8190
+ }
8191
+ .twm-flow-values__label { min-width: 0; overflow-wrap: anywhere; }
8192
+ .twm-flow-values__type {
8193
+ flex: 0 0 auto;
8194
+ font-size: var(--font-size-xs);
8195
+ color: var(--twm-flow-muted);
8196
+ }
8197
+ .twm-flow-values__empty {
8198
+ margin: 0;
8199
+ padding: 8px;
8200
+ color: var(--twm-flow-muted);
8201
+ }
8202
+ .twm-flow-values__foot {
8203
+ display: flex;
8204
+ flex-direction: column;
8205
+ gap: 3px;
8206
+ padding: 8px 14px 10px;
8207
+ border-top: 1px solid var(--border-strong);
8208
+ font-size: var(--font-size-xs);
8209
+ color: var(--twm-flow-muted);
8210
+ }
8211
+ .twm-flow-values__note { overflow-wrap: anywhere; }
8212
+ .twm-flow-values__inserts {
8213
+ min-height: 15px;
8214
+ overflow-wrap: anywhere;
8215
+ }
8216
+
8217
+ /* ── the findings strip ─────────────────────────────────────────────── */
8218
+ .twm-flow-strip {
8219
+ display: flex;
8220
+ flex-direction: column;
8221
+ gap: 4px;
8222
+ padding: 6px 12px;
8223
+ background: var(--twm-flow-error-bg);
8224
+ border-bottom: 1px solid var(--twm-flow-error-line);
8225
+ color: var(--twm-flow-error-text);
8226
+ font-size: var(--font-size-sm);
8227
+ }
8228
+ .twm-flow-strip.twm-flow-strip--warning {
8229
+ background: var(--twm-flow-warning-bg);
8230
+ border-bottom-color: var(--twm-flow-warning-line);
8231
+ color: var(--twm-flow-warning-text);
8232
+ }
8233
+ .twm-flow-strip__head {
8234
+ display: flex;
8235
+ align-items: center;
8236
+ gap: 8px;
8237
+ }
8238
+ .twm-flow-strip__icon.material-symbols-outlined { font-size: 16px; }
8239
+ .twm-flow-strip__title { font-weight: var(--font-weight-semibold); }
8240
+ .twm-flow-strip__list {
8241
+ margin: 0;
8242
+ padding: 0 0 0 24px;
8243
+ list-style: none;
8244
+ display: flex;
8245
+ flex-direction: column;
8246
+ gap: 2px;
8247
+ }
8248
+ .twm-flow-strip__line {
8249
+ display: flex;
8250
+ flex-wrap: wrap;
8251
+ align-items: center;
8252
+ gap: 4px 8px;
8253
+ }
8254
+ .twm-flow-strip__line--warning { color: var(--twm-flow-warning); }
8255
+ .twm-flow-strip__text { min-width: 0; overflow-wrap: anywhere; }
8256
+ .twm-flow-strip .twm-flow-strip__go {
8257
+ min-height: 22px;
8258
+ padding: 0 8px;
8259
+ color: inherit;
8260
+ background: transparent;
8261
+ border-color: var(--twm-flow-error-line);
8262
+ border-radius: 3px;
8263
+ }
8264
+ /* ══ end FLOW · KIT ══ */
8265
+
8266
+
8267
+ /* ══ FLOW · CANVAS ════════════════════════════════════════════════════ */
8268
+ /* Owned by the canvas agent (B) (36 §2): the canvas kernel (twm-canvas,
8269
+ * twm-edge) and the canvas editor (twm-flow-graph). Every class here is set by
8270
+ * a module under src/canvas/ or src/flow/canvas_editor/, and every class those
8271
+ * modules set has a rule here — tests/flow_canvas_css.test.mjs holds both
8272
+ * directions, and holds the node box (208 × 34 + 22 a row) to the editor's
8273
+ * CANVAS_NODE, because the edges are anchored by arithmetic, not measured. */
8274
+
8275
+ /* ── the kernel: the surface ────────────────────────────────────────── */
8276
+ /* The ground is SEVEN background layers, in this order, because
8277
+ * `CanvasAdapter._apply` writes seven sizes and positions: 1. a grain, 2. a
8278
+ * soft light from the upper left, 3–4. a coarse rule every fifth cell, 5–6. a
8279
+ * fine grid — the unit a drag snaps to — and 7. under it all, a gradient. Only
8280
+ * the four GRID layers follow the pan and the zoom. An embedder restyling the
8281
+ * ground keeps seven layers, or the browser cycles a short list and layer 5
8282
+ * takes layer 1's size. */
8283
+ .twm-canvas {
8284
+ position: absolute;
8285
+ inset: 0;
8286
+ overflow: hidden;
8287
+ cursor: default;
8288
+ outline: none;
8289
+ background-color: var(--surface-0);
8290
+ background-image:
8291
+ url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27160%27%20height%3D%27160%27%3E%3Cfilter%20id%3D%27n%27%3E%3CfeTurbulence%20type%3D%27fractalNoise%27%20baseFrequency%3D%270.85%27%20numOctaves%3D%273%27%20stitchTiles%3D%27stitch%27%2F%3E%3CfeColorMatrix%20type%3D%27saturate%27%20values%3D%270%27%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%27160%27%20height%3D%27160%27%20filter%3D%27url%28%23n%29%27%20opacity%3D%270.5%27%2F%3E%3C%2Fsvg%3E"),
8292
+ radial-gradient(120% 90% at 22% 0%, rgba(255, 255, 255, 0.055) 0%, rgba(255, 255, 255, 0) 55%),
8293
+ linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
8294
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
8295
+ linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
8296
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
8297
+ linear-gradient(160deg, #2b2e33 0%, #212327 55%, #1b1d20 100%);
8298
+ background-blend-mode: overlay, screen, normal, normal, normal, normal, normal;
8299
+ box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.55), inset 0 0 120px rgba(0, 0, 0, 0.35);
8300
+ }
8301
+ .twm-canvas:focus-visible {
8302
+ box-shadow: inset 0 0 0 1px var(--twm-flow-focus), inset 0 0 120px rgba(0, 0, 0, 0.35);
8303
+ }
8304
+ .twm-canvas__surface { position: absolute; transform-origin: 0 0; }
8305
+ /* The edge layer takes no pointer: a line that wants one (a hit path) opts
8306
+ * back in with `pointer-events: stroke`. */
8307
+ .twm-canvas__edges { position: absolute; overflow: visible; pointer-events: none; }
8308
+ .twm-canvas__nodes { position: absolute; }
8309
+ .twm-canvas__marquee {
8310
+ position: absolute;
8311
+ pointer-events: none;
8312
+ border: 1px solid var(--accent-bright);
8313
+ background: rgba(0, 122, 204, 0.12);
8314
+ }
8315
+ .twm-canvas__marquee[hidden] { display: none; }
8316
+
8317
+ /* ── the kernel: a crow's foot ──────────────────────────────────────── */
8318
+ .twm-edge__marker line { stroke: #5a7f96; stroke-width: 1.4; }
8319
+ .twm-edge__marker circle { fill: none; stroke: #5a7f96; stroke-width: 1.4; }
8320
+
8321
+ /* ── the canvas editor ──────────────────────────────────────────────── */
8322
+ .twm-flow-graph [hidden] { display: none !important; }
8323
+
8324
+ /* The editor fills its host: a flex column in any parent that gives it a
8325
+ * height. `container-type: inline-size` is for the narrow layouts below, and
8326
+ * safe here: the editor's width comes from its parent, never its contents. */
8327
+ .twm-flow-graph {
8328
+ flex: 1 1 auto;
8329
+ height: 100%;
8330
+ min-height: 0;
8331
+ min-width: 0;
8332
+ display: flex;
8333
+ flex-direction: column;
8334
+ box-sizing: border-box;
8335
+ background: var(--surface-0);
8336
+ color: var(--text-body);
8337
+ font-family: var(--font-family-sans);
8338
+ font-size: var(--font-size-sm);
8339
+ container-type: inline-size;
8340
+ container-name: twm-flow-graph;
8341
+ }
8342
+ .twm-flow-graph__toolbar {
8343
+ display: flex;
8344
+ flex-wrap: wrap;
8345
+ align-items: center;
8346
+ gap: 6px;
8347
+ padding: 6px 8px;
8348
+ background: var(--surface-1);
8349
+ border-bottom: 1px solid var(--border-default);
8350
+ }
8351
+ .twm-flow-graph .twm-flow-graph__tool {
8352
+ min-height: 26px;
8353
+ padding: 0 9px;
8354
+ font-size: var(--font-size-sm);
8355
+ border-radius: 3px;
8356
+ }
8357
+ .twm-flow-graph__tool .twm-btn__glyph.material-symbols-outlined { font-size: 16px; }
8358
+ .twm-flow-graph__tool--busy { cursor: progress; }
8359
+ .twm-flow-graph__status {
8360
+ margin-left: auto;
8361
+ color: var(--twm-flow-muted);
8362
+ font-size: var(--font-size-xs);
8363
+ }
8364
+ .twm-flow-graph__toolbar-end { display: inline-flex; align-items: center; gap: 6px; }
8365
+ .twm-flow-graph__toolbar-end:empty { display: none; }
8366
+ .twm-flow-graph__why,
8367
+ .twm-flow-graph__message,
8368
+ .twm-flow-graph__readonly,
8369
+ .twm-flow-graph__banner {
8370
+ margin: 0;
8371
+ padding: 4px 10px;
8372
+ font-size: var(--font-size-xs);
8373
+ line-height: 1.4;
8374
+ }
8375
+ .twm-flow-graph__why { color: var(--twm-flow-muted); border-bottom: 1px solid var(--border-subtle); }
8376
+ .twm-flow-graph__message:empty { display: none; }
8377
+ .twm-flow-graph__message--warning { color: var(--twm-flow-warning); }
8378
+ .twm-flow-graph__message--ok { color: var(--twm-flow-ok); }
8379
+ .twm-flow-graph__readonly {
8380
+ background: var(--twm-flow-warning-bg);
8381
+ color: var(--twm-flow-warning-text);
8382
+ border-bottom: 1px solid var(--twm-flow-warning-line);
8383
+ }
8384
+ .twm-flow-graph__banner {
8385
+ background: var(--twm-flow-blue-bg);
8386
+ color: var(--twm-flow-blue-fg);
8387
+ border-bottom: 1px solid var(--twm-flow-blue-line);
8388
+ }
8389
+
8390
+ /* Three columns; the CANVAS is the one that flexes — `flex: 1 1 0px` AND
8391
+ * `min-width: 0`, or an open settings panel squeezes the palette instead. */
8392
+ .twm-flow-graph__body { flex: 1 1 0px; min-height: 0; display: flex; flex-direction: row; }
8393
+ .twm-flow-graph__palette {
8394
+ flex: 0 0 176px;
8395
+ min-width: 0;
8396
+ overflow-y: auto;
8397
+ box-sizing: border-box;
8398
+ padding: 8px;
8399
+ display: flex;
8400
+ flex-direction: column;
8401
+ gap: 2px;
8402
+ background: var(--surface-1);
8403
+ border-right: 1px solid var(--border-default);
8404
+ }
8405
+ .twm-flow-graph__palette-title { margin: 2px 0 6px; font-size: var(--font-size-sm); font-weight: 600; }
8406
+ .twm-flow-graph__palette-group {
8407
+ margin: 10px 0 2px;
8408
+ font-size: var(--font-size-xs);
8409
+ font-weight: 600;
8410
+ letter-spacing: 0.06em;
8411
+ text-transform: uppercase;
8412
+ color: var(--twm-flow-muted);
8413
+ }
8414
+ /* A press must not select the label's text, and a touch press must not pan the
8415
+ * page instead of dragging. */
8416
+ .twm-flow-graph__palette-item {
8417
+ display: flex;
8418
+ align-items: center;
8419
+ gap: 6px;
8420
+ width: 100%;
8421
+ min-height: 26px;
8422
+ padding: 3px 6px;
8423
+ text-align: left;
8424
+ background: none;
8425
+ border: 1px solid transparent;
8426
+ border-radius: 3px;
8427
+ color: inherit;
8428
+ font: inherit;
8429
+ cursor: pointer;
8430
+ user-select: none;
8431
+ touch-action: none;
8432
+ }
8433
+ .twm-flow-graph__palette-item:hover:not(:disabled) { background: var(--state-hover); border-color: var(--border-default); }
8434
+ .twm-flow-graph__palette-item:focus-visible { outline: none; border-color: var(--twm-flow-focus); }
8435
+ .twm-flow-graph__palette-item:disabled { opacity: 0.45; cursor: not-allowed; }
8436
+ .twm-flow-graph__palette-icon {
8437
+ flex: 0 0 20px;
8438
+ height: 20px;
8439
+ display: inline-flex;
8440
+ align-items: center;
8441
+ justify-content: center;
8442
+ border-radius: 4px;
8443
+ }
8444
+ .twm-flow-graph__palette-icon .material-symbols-outlined,
8445
+ .twm-flow-graph__node-icon .material-symbols-outlined { font-size: 15px; }
8446
+ .twm-flow-graph__palette-icon--violet, .twm-flow-graph__node-icon--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
8447
+ .twm-flow-graph__palette-icon--teal, .twm-flow-graph__node-icon--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
8448
+ .twm-flow-graph__palette-icon--amber, .twm-flow-graph__node-icon--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
8449
+ .twm-flow-graph__palette-icon--grey, .twm-flow-graph__node-icon--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
8450
+ .twm-flow-graph__palette-icon--blue, .twm-flow-graph__node-icon--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
8451
+ .twm-flow-graph__palette-icon--indigo, .twm-flow-graph__node-icon--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
8452
+ .twm-flow-graph__palette-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
8453
+ .twm-flow-graph__palette-why {
8454
+ margin: 0 0 4px 32px;
8455
+ font-size: var(--font-size-xs);
8456
+ color: var(--twm-flow-muted);
8457
+ }
8458
+ .twm-flow-graph__canvas { position: relative; flex: 1 1 0px; min-width: 0; min-height: 0; }
8459
+ .twm-flow-graph__canvas--drop { outline: 2px dashed var(--twm-flow-focus); outline-offset: -2px; }
8460
+ .twm-flow-graph__aside {
8461
+ flex: 0 0 300px;
8462
+ min-width: 0;
8463
+ min-height: 0;
8464
+ overflow-y: auto;
8465
+ background: var(--surface-1);
8466
+ border-left: 1px solid var(--border-default);
8467
+ }
8468
+ .twm-flow-graph__connection {
8469
+ display: flex;
8470
+ flex-direction: column;
8471
+ align-items: flex-start;
8472
+ gap: 8px;
8473
+ padding: 16px 20px;
8474
+ }
8475
+ .twm-flow-graph__connection-title { margin: 0; font-size: var(--font-size-md); font-weight: 600; }
8476
+ .twm-flow-graph__connection-line { margin: 0; color: var(--twm-flow-muted); overflow-wrap: anywhere; }
8477
+ .twm-flow-graph .twm-flow-graph__connection-remove { min-height: 26px; padding: 0 9px; font-size: var(--font-size-sm); }
8478
+
8479
+ /* A narrow editor: under 900px the side columns take less, and under 740px the
8480
+ * canvas takes the whole width on top with the palette and the settings side
8481
+ * by side under it — a container query, on the editor's own width. */
8482
+ @container twm-flow-graph (max-width: 900px) {
8483
+ .twm-flow-graph__palette { flex: 0 0 150px; }
8484
+ .twm-flow-graph__aside { flex: 0 0 232px; }
8485
+ }
8486
+ @container twm-flow-graph (max-width: 740px) {
8487
+ .twm-flow-graph__body {
8488
+ display: grid;
8489
+ grid-template-columns: minmax(132px, 2fr) minmax(0, 3fr);
8490
+ grid-template-rows: minmax(220px, 11fr) minmax(0, 9fr);
8491
+ }
8492
+ .twm-flow-graph__canvas { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
8493
+ .twm-flow-graph__palette { grid-column: 1; grid-row: 2; min-height: 0; border-right: 0; border-top: 1px solid var(--border-default); }
8494
+ .twm-flow-graph__aside { grid-column: 2; grid-row: 2; border-left: 0; border-top: 1px solid var(--border-default); }
8495
+ }
8496
+
8497
+ /* ── a node ─────────────────────────────────────────────────────────── */
8498
+ /* THE BOX IS ARITHMETIC: a line meets a port at `header + row × i + row / 2`
8499
+ * (layout.js's portAnchor), so the header and a row are exactly these heights.
8500
+ * A consumer that passes `node: {width, header, row}` sets the three custom
8501
+ * properties on the editor's root. */
8502
+ .twm-flow-graph__node {
8503
+ position: absolute;
8504
+ box-sizing: border-box;
8505
+ width: var(--twm-canvas-node-width, 208px);
8506
+ background: var(--surface-2);
8507
+ border: 1px solid var(--border-strong);
8508
+ border-radius: 4px;
8509
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.55);
8510
+ color: var(--text-body);
8511
+ font-size: var(--font-size-xs);
8512
+ outline: none;
8513
+ }
8514
+ .twm-flow-graph__node:focus-visible { box-shadow: 0 0 0 2px var(--twm-flow-focus), 0 2px 12px rgba(0, 0, 0, 0.55); }
8515
+ .twm-flow-graph__node--picked {
8516
+ border-color: var(--twm-flow-focus);
8517
+ box-shadow: 0 0 0 1px var(--twm-flow-focus), 0 6px 18px rgba(0, 0, 0, 0.45);
8518
+ }
8519
+ .twm-flow-graph__node--connect-source { outline: 2px solid var(--twm-flow-focus); outline-offset: 1px; }
8520
+ .twm-flow-graph__node--error { border-color: var(--twm-flow-error); }
8521
+ .twm-flow-graph__node--warning { border-color: var(--twm-flow-warning); }
8522
+ .twm-flow-graph__node--skipped { opacity: 0.55; }
8523
+ .twm-flow-graph__node-head {
8524
+ box-sizing: border-box;
8525
+ height: var(--twm-canvas-node-header, 34px);
8526
+ display: flex;
8527
+ align-items: center;
8528
+ gap: 6px;
8529
+ padding: 0 8px;
8530
+ background: var(--surface-3);
8531
+ border-bottom: 1px solid var(--border-strong);
8532
+ border-radius: 3px 3px 0 0;
8533
+ font-size: var(--font-size-sm);
8534
+ font-weight: 600;
8535
+ user-select: none;
8536
+ cursor: move;
8537
+ }
8538
+ .twm-flow-graph--readonly .twm-flow-graph__node-head { cursor: default; }
8539
+ .twm-flow-graph__node-icon {
8540
+ flex: 0 0 20px;
8541
+ height: 20px;
8542
+ display: inline-flex;
8543
+ align-items: center;
8544
+ justify-content: center;
8545
+ border-radius: 4px;
8546
+ }
8547
+ .twm-flow-graph__node-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
8548
+ /* ONE LINE, and never more than half the header: a tag that wrapped squeezed
8549
+ * the title beside it to a few letters. */
8550
+ .twm-flow-graph__node-tag {
8551
+ margin-left: auto;
8552
+ flex: none;
8553
+ max-width: 50%;
8554
+ padding: 1px 5px;
8555
+ overflow: hidden;
8556
+ text-overflow: ellipsis;
8557
+ white-space: nowrap;
8558
+ font-size: var(--font-size-xs);
8559
+ font-weight: 500;
8560
+ color: #b8cbe0;
8561
+ background: rgba(127, 154, 198, 0.18);
8562
+ border-radius: 2px;
8563
+ }
8564
+ .twm-flow-graph__node-row {
8565
+ box-sizing: border-box;
8566
+ height: var(--twm-canvas-node-row, 22px);
8567
+ display: flex;
8568
+ align-items: center;
8569
+ justify-content: space-between;
8570
+ }
8571
+ .twm-flow-graph__node-gap { flex: 1 1 auto; }
8572
+ .twm-flow-graph__node-summary,
8573
+ .twm-flow-graph__node-run {
8574
+ margin: 0;
8575
+ padding: 2px 8px 4px;
8576
+ color: var(--twm-flow-muted);
8577
+ overflow-wrap: anywhere;
8578
+ }
8579
+ .twm-flow-graph__node-summary:empty,
8580
+ .twm-flow-graph__node-run:empty { display: none; }
8581
+ .twm-flow-graph__node-findings { padding: 0 8px; }
8582
+ .twm-flow-graph__node-finding { margin: 4px 0; color: var(--twm-flow-error); overflow-wrap: anywhere; }
8583
+ .twm-flow-graph__node-finding--warning { color: var(--twm-flow-warning); }
8584
+ .twm-flow-graph__node-run[data-state="completed"], .twm-flow-graph__node-run[data-tone="ok"] { color: var(--twm-flow-ok); }
8585
+ .twm-flow-graph__node-run[data-state="failed"], .twm-flow-graph__node-run[data-tone="error"] { color: var(--twm-flow-error); }
8586
+ .twm-flow-graph__node-run[data-tone="warning"] { color: var(--twm-flow-warning); }
8587
+ .twm-flow-graph__node-run[data-state="running"] { color: var(--twm-flow-focus); }
8588
+ .twm-flow-graph__node-run[data-state="skipped"],
8589
+ .twm-flow-graph__node-run[data-state="cancelled"],
8590
+ .twm-flow-graph__node-run[data-state="not-reached"] { font-style: italic; }
8591
+
8592
+ /* ── a port ─────────────────────────────────────────────────────────── */
8593
+ .twm-flow-graph__port {
8594
+ display: flex;
8595
+ align-items: center;
8596
+ gap: 4px;
8597
+ height: var(--twm-canvas-node-row, 22px);
8598
+ padding: 0 6px;
8599
+ background: none;
8600
+ border: 0;
8601
+ color: inherit;
8602
+ font: inherit;
8603
+ font-size: var(--font-size-xs);
8604
+ cursor: crosshair;
8605
+ }
8606
+ .twm-flow-graph__port:disabled { cursor: default; }
8607
+ .twm-flow-graph__port:focus-visible { outline: 1px solid var(--twm-flow-focus); outline-offset: -1px; }
8608
+ .twm-flow-graph__port--in { margin-left: -6px; }
8609
+ .twm-flow-graph__port--out { flex-direction: row-reverse; margin-right: -6px; }
8610
+ .twm-flow-graph__port-dot {
8611
+ flex: 0 0 10px;
8612
+ width: 10px;
8613
+ height: 10px;
8614
+ box-sizing: border-box;
8615
+ border-radius: 50%;
8616
+ background: var(--surface-3);
8617
+ border: 2px solid var(--twm-flow-focus);
8618
+ }
8619
+ .twm-flow-graph__port-label { white-space: nowrap; }
8620
+ .twm-flow-graph__port-count { color: var(--twm-flow-muted); white-space: nowrap; }
8621
+ .twm-flow-graph__port-count:empty { display: none; }
8622
+ .twm-flow-graph__port:hover:not(:disabled) .twm-flow-graph__port-dot { background: var(--twm-flow-focus); }
8623
+ .twm-flow-graph__port--data { opacity: 0.7; }
8624
+ .twm-flow-graph__port--data .twm-flow-graph__port-dot { border-color: #8a8f98; border-radius: 2px; }
8625
+ .twm-flow-graph--connecting .twm-flow-graph__port--in:not(:disabled) .twm-flow-graph__port-dot {
8626
+ background: var(--twm-flow-focus);
8627
+ box-shadow: 0 0 0 3px rgba(0, 122, 204, 0.35);
8628
+ }
8629
+ .twm-flow-graph__port--taken .twm-flow-graph__port-dot { border-color: var(--twm-flow-ok); background: var(--twm-flow-ok); }
8630
+ .twm-flow-graph__port--taken .twm-flow-graph__port-count { color: var(--twm-flow-ok); }
8631
+ .twm-flow-graph__port--untaken { opacity: 0.5; }
8632
+
8633
+ /* ── a line ─────────────────────────────────────────────────────────── */
8634
+ .twm-flow-graph__edge { fill: none; stroke: #8fb4d8; stroke-width: 1.6; }
8635
+ .twm-flow-graph__edge--picked { stroke: var(--twm-flow-focus); stroke-width: 2.4; }
8636
+ /* A loop's body handing back to the loop: DASHED, and routed under both steps
8637
+ * by the kernel's `returnEdge`, so it reads as "round again", not as one more
8638
+ * step forward. */
8639
+ .twm-flow-graph__edge--back { stroke-dasharray: 6 4; }
8640
+ .twm-flow-graph__edge--taken { stroke: var(--twm-flow-ok); }
8641
+ .twm-flow-graph__edge--untaken { opacity: 0.35; }
8642
+ /* The 14px target a 1.6px line cannot be. It opts back into the pointer the
8643
+ * edge layer turns off. */
8644
+ .twm-flow-graph__edge-hit { fill: none; stroke: transparent; stroke-width: 14; pointer-events: stroke; cursor: pointer; }
8645
+
8646
+ /* ── the palette drag's ghost ───────────────────────────────────────── */
8647
+ /* It lives on <body>, follows the pointer and never takes it — `pointer-events:
8648
+ * none`, or the release lands on the ghost rather than on the canvas. */
8649
+ .twm-flow-graph__ghost {
8650
+ position: fixed;
8651
+ z-index: var(--z-toast);
8652
+ pointer-events: none;
8653
+ display: flex;
8654
+ align-items: center;
8655
+ gap: 6px;
8656
+ padding: 4px 8px;
8657
+ background: var(--surface-2);
8658
+ border: 1px solid var(--twm-flow-focus);
8659
+ border-radius: 3px;
8660
+ color: var(--text-body);
8661
+ font-family: var(--font-family-sans);
8662
+ font-size: var(--font-size-sm);
8663
+ opacity: 0.92;
8664
+ box-shadow: var(--shadow-md);
8665
+ }
8666
+ .twm-flow-graph__ghost .material-symbols-outlined { font-size: 16px; }
8667
+ .twm-flow-graph__ghost-label { white-space: nowrap; }
8668
+ /* ══ end FLOW · CANVAS ══ */
8669
+
8670
+
8671
+ /* ══ FLOW · OUTLINE ═══════════════════════════════════════════════════ */
8672
+ /* The outline editor (36 §6, the Main, AddStep, StepMenu and Run mocks): a
8673
+ * logic flow drawn as a list of blocks. A row is indented 22px a level
8674
+ * (`--twm-outline-depth`, set by src/flow/outline/editor.js, whose
8675
+ * OUTLINE_INDENT is the same number); its guides are the lines at 14px +
8676
+ * 22px a level. Every class here is set by a module under src/flow/outline/,
8677
+ * and every class those modules set has a rule here —
8678
+ * tests/flow_outline_css.test.mjs holds both directions. */
8679
+
8680
+ .twm-flow-outline[hidden],
8681
+ .twm-flow-outline [hidden],
8682
+ .twm-flow-popover--menu [hidden] {
8683
+ display: none !important;
8684
+ }
8685
+
8686
+ .twm-flow-outline {
8687
+ container: twm-flow-outline / inline-size;
8688
+ display: flex;
8689
+ flex-direction: column;
8690
+ height: 100%;
8691
+ min-height: 0;
8692
+ box-sizing: border-box;
8693
+ background: var(--surface-0);
8694
+ color: var(--text-body);
8695
+ font-family: var(--font-family-sans);
8696
+ font-size: var(--font-size-sm);
8697
+ line-height: 1.4;
8698
+ outline: none;
8699
+ }
8700
+ .twm-flow-outline--dragging,
8701
+ .twm-flow-outline--dragging * {
8702
+ cursor: grabbing !important;
8703
+ user-select: none;
8704
+ }
8705
+ .twm-flow-outline--readonly .twm-flow-outline__keys { display: none; }
8706
+ .twm-flow-outline--run .twm-flow-outline__type { display: none; }
8707
+
8708
+ /* ── the toolbar ────────────────────────────────────────────────────── */
8709
+ .twm-flow-outline__toolbar {
8710
+ display: flex;
8711
+ flex-wrap: wrap;
8712
+ align-items: center;
8713
+ gap: 6px;
8714
+ padding: 6px 10px;
8715
+ background: var(--surface-1);
8716
+ border-bottom: 1px solid var(--border-default);
8717
+ }
8718
+ .twm-flow-outline__toolbar .twm-btn {
8719
+ min-height: 26px;
8720
+ padding: 0 9px;
8721
+ font-size: var(--font-size-sm);
8722
+ border-radius: 3px;
8723
+ }
8724
+ .twm-flow-outline__tool { white-space: nowrap; }
8725
+ .twm-flow-outline__tool--busy { cursor: progress; opacity: .7; }
8726
+ .twm-flow-outline__sep {
8727
+ width: 1px;
8728
+ height: 18px;
8729
+ margin: 0 4px;
8730
+ background: var(--border-default);
8731
+ }
8732
+ .twm-flow-outline__tool-wrap {
8733
+ display: inline-flex;
8734
+ align-items: center;
8735
+ gap: 6px;
8736
+ }
8737
+ .twm-flow-outline__refusal {
8738
+ max-width: 260px;
8739
+ font-size: var(--font-size-xs);
8740
+ color: var(--twm-flow-warning);
8741
+ }
8742
+ .twm-flow-outline__status {
8743
+ margin-left: 8px;
8744
+ color: var(--twm-flow-muted);
8745
+ }
8746
+ .twm-flow-outline__spacer { flex: 1 1 auto; }
8747
+ .twm-flow-outline__toolbar-end {
8748
+ display: flex;
8749
+ align-items: center;
8750
+ gap: 6px;
8751
+ }
8752
+
8753
+ /* ── the banners: read only, and the run drawn ─────────────────────── */
8754
+ .twm-flow-outline__readonly {
8755
+ display: flex;
8756
+ align-items: flex-start;
8757
+ gap: 8px;
8758
+ padding: 6px 12px;
8759
+ background: var(--twm-flow-warning-bg);
8760
+ border-bottom: 1px solid var(--twm-flow-warning-line);
8761
+ color: var(--twm-flow-warning-text);
8762
+ }
8763
+ .twm-flow-outline__readonly-icon {
8764
+ flex: 0 0 auto;
8765
+ font-size: 16px;
8766
+ color: var(--twm-flow-warning);
8767
+ }
8768
+ .twm-flow-outline__readonly-text { min-width: 0; }
8769
+ .twm-flow-outline__banner {
8770
+ display: flex;
8771
+ align-items: center;
8772
+ gap: 8px;
8773
+ padding: 6px 12px;
8774
+ background: var(--twm-flow-blue-bg);
8775
+ border-bottom: 1px solid var(--twm-flow-blue-line);
8776
+ color: var(--twm-flow-blue-fg);
8777
+ }
8778
+ .twm-flow-outline__banner-icon {
8779
+ flex: 0 0 auto;
8780
+ font-size: 16px;
8781
+ color: var(--twm-flow-blue-dot);
8782
+ }
8783
+ .twm-flow-outline__banner-text { min-width: 0; }
8784
+
8785
+ /* ── the three columns ──────────────────────────────────────────────── */
8786
+ /* Side by side, each column scrolling on its own inside the editor's height —
8787
+ * the list's keys line stays at its foot and a long panel scrolls past a
8788
+ * short outline; in a narrow editor they wrap, one under the other, and the
8789
+ * body scrolls as one. */
8790
+ .twm-flow-outline__body {
8791
+ display: flex;
8792
+ flex-wrap: nowrap;
8793
+ align-items: stretch;
8794
+ flex: 1 1 auto;
8795
+ min-height: 0;
8796
+ overflow: hidden;
8797
+ }
8798
+ .twm-flow-outline__list {
8799
+ flex: 0 1 440px;
8800
+ min-width: 300px;
8801
+ max-width: 100%;
8802
+ min-height: 0;
8803
+ box-sizing: border-box;
8804
+ display: flex;
8805
+ flex-direction: column;
8806
+ border-right: 1px solid var(--border-default);
8807
+ }
8808
+ @container twm-flow-outline (max-width: 1000px) {
8809
+ .twm-flow-outline__body {
8810
+ flex-wrap: wrap;
8811
+ overflow: auto;
8812
+ }
8813
+ .twm-flow-outline__list { flex: 1 1 100%; border-right: 0; }
8814
+ .twm-flow-outline__settings,
8815
+ .twm-flow-outline__aside { overflow: visible; }
8816
+ }
8817
+ .twm-flow-outline__settings {
8818
+ flex: 3 1 460px;
8819
+ min-width: 0;
8820
+ box-sizing: border-box;
8821
+ overflow: auto;
8822
+ background: var(--surface-1);
8823
+ border-right: 1px solid var(--border-default);
8824
+ }
8825
+ .twm-flow-outline__aside {
8826
+ flex: 1 1 300px;
8827
+ min-width: 260px;
8828
+ box-sizing: border-box;
8829
+ padding: 16px;
8830
+ overflow: auto;
8831
+ }
8832
+
8833
+ /* ── the list's head, find, the status line ─────────────────────────── */
8834
+ .twm-flow-outline__list-head {
8835
+ flex: 0 0 auto;
8836
+ display: flex;
8837
+ align-items: center;
8838
+ gap: 8px;
8839
+ padding: 10px 12px 8px;
8840
+ }
8841
+ .twm-flow-outline__heading {
8842
+ margin: 0;
8843
+ font-size: 11px;
8844
+ font-weight: var(--font-weight-semibold);
8845
+ letter-spacing: .06em;
8846
+ text-transform: uppercase;
8847
+ color: var(--text-secondary);
8848
+ }
8849
+ .twm-flow-outline__count { color: var(--twm-flow-muted); }
8850
+ .twm-flow-outline__fold-all {
8851
+ height: 22px;
8852
+ padding: 0 7px;
8853
+ border: 0;
8854
+ border-radius: 3px;
8855
+ background: transparent;
8856
+ color: var(--text-secondary);
8857
+ font: inherit;
8858
+ cursor: pointer;
8859
+ }
8860
+ .twm-flow-outline__fold-all:hover:not(:disabled) { background: var(--state-hover); }
8861
+ .twm-flow-outline__fold-all:disabled { cursor: default; opacity: .45; }
8862
+ .twm-flow-outline__find {
8863
+ flex: 0 0 auto;
8864
+ box-sizing: border-box;
8865
+ width: calc(100% - 24px);
8866
+ height: 26px;
8867
+ margin: 0 12px 8px;
8868
+ padding: 0 8px;
8869
+ background: var(--twm-flow-control-bg);
8870
+ border: 1px solid var(--twm-flow-control-border);
8871
+ border-radius: 3px;
8872
+ color: var(--text-primary);
8873
+ font: inherit;
8874
+ }
8875
+ .twm-flow-outline__find:focus {
8876
+ outline: none;
8877
+ border-color: var(--twm-flow-focus);
8878
+ }
8879
+ .twm-flow-outline__scroll {
8880
+ flex: 1 1 auto;
8881
+ min-height: 0;
8882
+ overflow: auto;
8883
+ padding: 0 8px 12px;
8884
+ }
8885
+ .twm-flow-outline__message {
8886
+ flex: 0 0 auto;
8887
+ margin: 0 12px 6px;
8888
+ font-size: 11px;
8889
+ color: var(--twm-flow-warning-text);
8890
+ }
8891
+ .twm-flow-outline__keys {
8892
+ flex: 0 0 auto;
8893
+ margin: 0;
8894
+ padding: 10px 12px;
8895
+ border-top: 1px solid var(--border-subtle);
8896
+ font-size: 11px;
8897
+ color: var(--twm-flow-muted);
8898
+ }
8899
+
8900
+ /* ── the tree and its rows ──────────────────────────────────────────── */
8901
+ .twm-flow-outline__tree {
8902
+ position: relative;
8903
+ display: flex;
8904
+ flex-direction: column;
8905
+ }
8906
+ .twm-flow-outline__item,
8907
+ .twm-flow-outline__inside,
8908
+ .twm-flow-outline__arm {
8909
+ display: flex;
8910
+ flex-direction: column;
8911
+ }
8912
+ .twm-flow-outline__item { outline: none; }
8913
+ .twm-flow-outline__item:focus-visible > .twm-flow-outline__row {
8914
+ outline: 2px solid var(--twm-flow-focus);
8915
+ outline-offset: -2px;
8916
+ }
8917
+ .twm-flow-outline__item--flow { margin-bottom: 6px; }
8918
+ .twm-flow-outline__item--context > .twm-flow-outline__row { opacity: .55; }
8919
+ .twm-flow-outline__row {
8920
+ position: relative;
8921
+ display: flex;
8922
+ align-items: center;
8923
+ gap: 4px;
8924
+ box-sizing: border-box;
8925
+ padding-left: calc(8px + var(--twm-outline-depth, 0) * 22px);
8926
+ border-radius: 4px;
8927
+ }
8928
+ .twm-flow-outline__row--step { min-height: 42px; }
8929
+ .twm-flow-outline__row--step:hover,
8930
+ .twm-flow-outline__row--flow:hover { background-color: var(--state-hover); }
8931
+ .twm-flow-outline__row--flow {
8932
+ gap: 10px;
8933
+ padding: 8px 10px;
8934
+ background: var(--surface-1);
8935
+ border: 1px solid var(--border-subtle);
8936
+ }
8937
+ .twm-flow-outline__row--selected,
8938
+ .twm-flow-outline__row--selected:hover {
8939
+ background: var(--twm-flow-blue-bg);
8940
+ box-shadow: inset 0 0 0 1px var(--twm-flow-focus);
8941
+ }
8942
+ .twm-flow-outline__row--off .twm-flow-outline__title {
8943
+ font-style: italic;
8944
+ color: var(--text-dim);
8945
+ }
8946
+ .twm-flow-outline__row--off .twm-flow-outline__chip { opacity: .45; }
8947
+ .twm-flow-outline__row--dragging { opacity: .45; }
8948
+ .twm-flow-outline__guide {
8949
+ position: absolute;
8950
+ top: 0;
8951
+ bottom: 0;
8952
+ left: calc(14px + var(--twm-outline-guide, 0) * 22px);
8953
+ width: 1px;
8954
+ background: var(--border-default);
8955
+ pointer-events: none;
8956
+ }
8957
+
8958
+ /* an arm: its words in its tone — Then green, Otherwise grey, a failure amber */
8959
+ .twm-flow-outline__row--arm {
8960
+ height: 24px;
8961
+ gap: 6px;
8962
+ padding-left: calc(24px + var(--twm-outline-depth, 0) * 22px);
8963
+ font-size: 11px;
8964
+ font-weight: var(--font-weight-semibold);
8965
+ color: var(--twm-flow-muted);
8966
+ }
8967
+ .twm-flow-outline__row--then { color: var(--twm-flow-ok); }
8968
+ .twm-flow-outline__row--else { color: var(--text-secondary); }
8969
+ .twm-flow-outline__row--fail { color: var(--twm-flow-warning); }
8970
+ .twm-flow-outline__row--arm.twm-flow-outline__row--off { color: var(--text-dim); }
8971
+ .twm-flow-outline__arm-icon { font-size: 13px; }
8972
+ .twm-flow-outline__arm-label { white-space: nowrap; }
8973
+ .twm-flow-outline__arm-note {
8974
+ margin-left: auto;
8975
+ padding-right: 8px;
8976
+ font-weight: var(--font-weight-regular);
8977
+ color: var(--text-muted);
8978
+ }
8979
+ .twm-flow-outline__arm-remove {
8980
+ width: 20px;
8981
+ height: 20px;
8982
+ margin-left: auto;
8983
+ margin-right: 6px;
8984
+ display: flex;
8985
+ align-items: center;
8986
+ justify-content: center;
8987
+ padding: 0;
8988
+ border: 0;
8989
+ border-radius: 3px;
8990
+ background: transparent;
8991
+ color: var(--text-secondary);
8992
+ opacity: .6;
8993
+ cursor: pointer;
8994
+ }
8995
+ .twm-flow-outline__arm-note + .twm-flow-outline__arm-remove { margin-left: 0; }
8996
+ .twm-flow-outline__arm-remove .material-symbols-outlined { font-size: 14px; }
8997
+ .twm-flow-outline__row:hover > .twm-flow-outline__arm-remove,
8998
+ .twm-flow-outline__arm-remove:focus-visible { opacity: 1; }
8999
+ .twm-flow-outline__arm-remove:hover { background: var(--state-hover); }
9000
+
9001
+ /* a foot: Next row, Go on with the next row, Then wait for every branch */
9002
+ .twm-flow-outline__row--foot {
9003
+ height: 26px;
9004
+ gap: 6px;
9005
+ padding-left: calc(24px + var(--twm-outline-depth, 0) * 22px);
9006
+ font-size: 11px;
9007
+ color: var(--twm-flow-muted);
9008
+ }
9009
+ .twm-flow-outline__foot-icon { font-size: 13px; }
9010
+ .twm-flow-outline__foot-label { white-space: nowrap; }
9011
+ .twm-flow-outline__foot-note {
9012
+ margin-left: auto;
9013
+ padding-right: 8px;
9014
+ color: var(--text-muted);
9015
+ }
9016
+
9017
+ /* an add row: Add a step, Add a step to the loop, Add a branch */
9018
+ .twm-flow-outline__row--add { padding: 2px 8px 6px calc(24px + var(--twm-outline-depth, 0) * 22px); }
9019
+ .twm-flow-outline__row--add-top { padding-left: 8px; }
9020
+ .twm-flow-outline__row--add-top .twm-flow-outline__add { width: 100%; }
9021
+ .twm-flow-outline__add {
9022
+ box-sizing: border-box;
9023
+ display: flex;
9024
+ align-items: center;
9025
+ gap: 6px;
9026
+ height: 26px;
9027
+ padding: 0 9px;
9028
+ border: 1px dashed var(--border-strong);
9029
+ border-radius: 4px;
9030
+ background: transparent;
9031
+ color: var(--text-secondary);
9032
+ font: inherit;
9033
+ font-size: 11px;
9034
+ cursor: pointer;
9035
+ }
9036
+ .twm-flow-outline__add .material-symbols-outlined { font-size: 14px; }
9037
+ .twm-flow-outline__add:hover,
9038
+ .twm-flow-outline__add:focus-visible {
9039
+ color: var(--twm-flow-blue-fg);
9040
+ border-color: var(--twm-flow-focus);
9041
+ outline: none;
9042
+ }
9043
+ .twm-flow-outline__add-label { white-space: nowrap; }
9044
+
9045
+ /* a step row's parts */
9046
+ .twm-flow-outline__grip {
9047
+ flex: 0 0 12px;
9048
+ display: flex;
9049
+ color: var(--text-muted);
9050
+ opacity: 0;
9051
+ cursor: grab;
9052
+ touch-action: none;
9053
+ }
9054
+ .twm-flow-outline__grip .material-symbols-outlined { font-size: 14px; }
9055
+ .twm-flow-outline__row:hover > .twm-flow-outline__grip,
9056
+ .twm-flow-outline__row--selected > .twm-flow-outline__grip { opacity: 1; }
9057
+ .twm-flow-outline__grip--off { visibility: hidden; }
9058
+ .twm-flow-outline__fold {
9059
+ flex: 0 0 18px;
9060
+ width: 18px;
9061
+ height: 18px;
9062
+ display: flex;
9063
+ align-items: center;
9064
+ justify-content: center;
9065
+ padding: 0;
9066
+ border: 0;
9067
+ border-radius: 3px;
9068
+ background: transparent;
9069
+ color: var(--text-secondary);
9070
+ cursor: pointer;
9071
+ }
9072
+ .twm-flow-outline__fold:hover { background: var(--state-hover); }
9073
+ .twm-flow-outline__fold .material-symbols-outlined { font-size: 16px; }
9074
+ .twm-flow-outline__fold-space { flex: 0 0 18px; }
9075
+ .twm-flow-outline__chip {
9076
+ flex: 0 0 24px;
9077
+ height: 24px;
9078
+ display: flex;
9079
+ align-items: center;
9080
+ justify-content: center;
9081
+ margin-left: 5px;
9082
+ border-radius: 5px;
9083
+ }
9084
+ .twm-flow-outline__row--flow > .twm-flow-outline__chip { margin-left: 0; }
9085
+ .twm-flow-outline__chip .material-symbols-outlined { font-size: 15px; }
9086
+ .twm-flow-outline__chip--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
9087
+ .twm-flow-outline__chip--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
9088
+ .twm-flow-outline__chip--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
9089
+ .twm-flow-outline__chip--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
9090
+ .twm-flow-outline__chip--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
9091
+ .twm-flow-outline__chip--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
9092
+ .twm-flow-outline__words {
9093
+ flex: 1 1 auto;
9094
+ min-width: 0;
9095
+ display: flex;
9096
+ flex-direction: column;
9097
+ gap: 1px;
9098
+ padding: 5px 4px;
9099
+ }
9100
+ .twm-flow-outline__line {
9101
+ display: flex;
9102
+ align-items: baseline;
9103
+ gap: 7px;
9104
+ min-width: 0;
9105
+ }
9106
+ .twm-flow-outline__title {
9107
+ min-width: 0;
9108
+ overflow: hidden;
9109
+ white-space: nowrap;
9110
+ text-overflow: ellipsis;
9111
+ font-weight: var(--font-weight-medium);
9112
+ color: var(--text-primary);
9113
+ }
9114
+ .twm-flow-outline__row--flow .twm-flow-outline__title { font-weight: var(--font-weight-semibold); }
9115
+ .twm-flow-outline__type {
9116
+ font-size: 11px;
9117
+ white-space: nowrap;
9118
+ color: var(--text-muted);
9119
+ }
9120
+ .twm-flow-outline__summary {
9121
+ overflow: hidden;
9122
+ white-space: nowrap;
9123
+ text-overflow: ellipsis;
9124
+ font-size: 11px;
9125
+ color: var(--text-secondary);
9126
+ }
9127
+ .twm-flow-outline__summary--mono {
9128
+ font-family: var(--font-family-mono);
9129
+ font-size: 11px;
9130
+ }
9131
+ .twm-flow-outline__summary--error { color: var(--twm-flow-error); }
9132
+ .twm-flow-outline__summary--warning { color: var(--twm-flow-warning); }
9133
+ .twm-flow-outline__note {
9134
+ flex: 0 0 auto;
9135
+ padding: 1px 6px;
9136
+ border-radius: 8px;
9137
+ background: var(--surface-2);
9138
+ font-size: 11px;
9139
+ white-space: nowrap;
9140
+ color: var(--text-secondary);
9141
+ }
9142
+ .twm-flow-outline__run {
9143
+ flex: 0 0 auto;
9144
+ display: inline-flex;
9145
+ align-items: center;
9146
+ height: 20px;
9147
+ padding: 0 7px;
9148
+ border-radius: 10px;
9149
+ font-size: 11px;
9150
+ white-space: nowrap;
9151
+ }
9152
+ .twm-flow-outline__run--ok { background: color-mix(in srgb, var(--twm-flow-ok) 14%, transparent); color: var(--twm-flow-ok); }
9153
+ .twm-flow-outline__run--warn { background: var(--twm-flow-warning-bg); color: var(--twm-flow-warning); }
9154
+ .twm-flow-outline__run--fail { background: var(--twm-flow-error-bg); color: var(--twm-flow-error); }
9155
+ .twm-flow-outline__run--skip { background: var(--twm-flow-grey-bg); color: var(--text-muted); }
9156
+ .twm-flow-outline__run--running { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
9157
+ .twm-flow-outline__badge {
9158
+ flex: 0 0 auto;
9159
+ display: flex;
9160
+ color: var(--twm-flow-error);
9161
+ }
9162
+ .twm-flow-outline__badge--warning { color: var(--twm-flow-warning); }
9163
+ .twm-flow-outline__badge .material-symbols-outlined { font-size: 15px; }
9164
+ .twm-flow-outline__menu {
9165
+ flex: 0 0 24px;
9166
+ width: 24px;
9167
+ height: 24px;
9168
+ margin-right: 4px;
9169
+ display: flex;
9170
+ align-items: center;
9171
+ justify-content: center;
9172
+ padding: 0;
9173
+ border: 0;
9174
+ border-radius: 3px;
9175
+ background: transparent;
9176
+ color: var(--text-secondary);
9177
+ opacity: .6;
9178
+ cursor: pointer;
9179
+ }
9180
+ .twm-flow-outline__menu .material-symbols-outlined { font-size: 16px; }
9181
+ .twm-flow-outline__row:hover > .twm-flow-outline__menu,
9182
+ .twm-flow-outline__row--selected > .twm-flow-outline__menu,
9183
+ .twm-flow-outline__menu:focus-visible { opacity: 1; }
9184
+ .twm-flow-outline__menu:hover { background: var(--state-hover); }
9185
+
9186
+ /* "+" between two rows: drawn on a row's bottom edge at the indent of the
9187
+ * list it adds to, shown on the row's hover AND on its own focus; only its
9188
+ * circle takes the pointer, so it never covers the row below */
9189
+ .twm-flow-outline__gap {
9190
+ position: absolute;
9191
+ z-index: 2;
9192
+ left: calc(8px + var(--twm-outline-depth, 0) * 22px);
9193
+ right: 8px;
9194
+ bottom: -7px;
9195
+ height: 14px;
9196
+ padding: 0;
9197
+ border: 0;
9198
+ background: transparent;
9199
+ opacity: 0;
9200
+ pointer-events: none;
9201
+ }
9202
+ .twm-flow-outline__row:hover > .twm-flow-outline__gap,
9203
+ .twm-flow-outline__gap:hover,
9204
+ .twm-flow-outline__gap:focus-visible {
9205
+ opacity: 1;
9206
+ outline: none;
9207
+ }
9208
+ .twm-flow-outline__gap-line {
9209
+ position: absolute;
9210
+ left: 10px;
9211
+ right: 0;
9212
+ top: 6px;
9213
+ height: 2px;
9214
+ border-radius: 1px;
9215
+ background: var(--twm-flow-focus);
9216
+ }
9217
+ .twm-flow-outline__gap-plus {
9218
+ position: absolute;
9219
+ left: 0;
9220
+ top: -2px;
9221
+ width: 18px;
9222
+ height: 18px;
9223
+ display: flex;
9224
+ align-items: center;
9225
+ justify-content: center;
9226
+ border-radius: 9px;
9227
+ background: var(--twm-flow-focus);
9228
+ color: #ffffff;
9229
+ font-size: 13px;
9230
+ pointer-events: none;
9231
+ cursor: pointer;
9232
+ }
9233
+ /* the circle takes the pointer only while it is drawn: an invisible "+" must
9234
+ * not catch a press meant for the top-left corner of the row below */
9235
+ .twm-flow-outline__row:hover > .twm-flow-outline__gap .twm-flow-outline__gap-plus,
9236
+ .twm-flow-outline__gap:focus-visible .twm-flow-outline__gap-plus { pointer-events: auto; }
9237
+ .twm-flow-outline__gap:focus-visible .twm-flow-outline__gap-plus { box-shadow: 0 0 0 2px var(--surface-0), 0 0 0 4px var(--twm-flow-focus); }
9238
+
9239
+ /* the grip drag: a ghost under the pointer, and a drop line naming the place */
9240
+ .twm-flow-outline__ghost {
9241
+ position: fixed;
9242
+ z-index: var(--z-popover);
9243
+ box-sizing: border-box;
9244
+ display: flex;
9245
+ align-items: center;
9246
+ gap: 9px;
9247
+ min-width: 200px;
9248
+ max-width: 320px;
9249
+ height: 40px;
9250
+ padding: 0 10px;
9251
+ background: var(--surface-2);
9252
+ border: 1px solid var(--twm-flow-focus);
9253
+ border-radius: 4px;
9254
+ box-shadow: 0 10px 24px rgba(0, 0, 0, 0.6);
9255
+ color: var(--text-primary);
9256
+ font-family: var(--font-family-sans);
9257
+ font-size: var(--font-size-sm);
9258
+ pointer-events: none;
9259
+ transform: rotate(-1.5deg);
9260
+ }
9261
+ .twm-flow-outline__ghost .twm-flow-outline__chip { margin-left: 0; }
9262
+ .twm-flow-outline__ghost-grip { font-size: 14px; color: var(--text-secondary); }
9263
+ .twm-flow-outline__ghost-title {
9264
+ overflow: hidden;
9265
+ white-space: nowrap;
9266
+ text-overflow: ellipsis;
9267
+ font-weight: var(--font-weight-medium);
9268
+ }
9269
+ .twm-flow-outline__drop {
9270
+ position: absolute;
9271
+ z-index: 3;
9272
+ left: calc(8px + var(--twm-outline-depth, 0) * 22px);
9273
+ right: 8px;
9274
+ height: 2px;
9275
+ margin-top: -1px;
9276
+ border-radius: 1px;
9277
+ background: var(--twm-flow-focus);
9278
+ pointer-events: none;
9279
+ }
9280
+ .twm-flow-outline__drop-label {
9281
+ position: absolute;
9282
+ right: 8px;
9283
+ top: -9px;
9284
+ box-sizing: border-box;
9285
+ max-width: calc(100% - 16px);
9286
+ min-height: 18px;
9287
+ display: flex;
9288
+ align-items: center;
9289
+ padding: 1px 7px;
9290
+ border-radius: 3px;
9291
+ background: var(--twm-flow-focus);
9292
+ color: #ffffff;
9293
+ font-size: 11px;
9294
+ line-height: 1.35;
9295
+ }
9296
+ .twm-flow-outline__drop--refused { background: var(--twm-flow-warning); }
9297
+ .twm-flow-outline__drop--refused .twm-flow-outline__drop-label {
9298
+ background: var(--surface-2);
9299
+ border: 1px solid var(--twm-flow-warning-line);
9300
+ color: var(--twm-flow-warning-text);
9301
+ }
9302
+
9303
+ /* the step menu (StepMenu mock), in the kit's popover */
9304
+ .twm-flow-popover--menu { width: 260px; }
9305
+ .twm-flow-outline__menu-list {
9306
+ position: relative;
9307
+ display: flex;
9308
+ flex-direction: column;
9309
+ box-sizing: border-box;
9310
+ padding: 5px;
9311
+ }
9312
+ .twm-flow-outline__menu-sub {
9313
+ position: absolute;
9314
+ left: calc(100% - 4px);
9315
+ z-index: 1;
9316
+ width: 190px;
9317
+ background: var(--surface-1);
9318
+ border: 1px solid var(--twm-flow-control-border);
9319
+ border-radius: var(--radius-md);
9320
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
9321
+ }
9322
+ .twm-flow-outline__menu-item {
9323
+ display: flex;
9324
+ align-items: center;
9325
+ justify-content: space-between;
9326
+ gap: 12px;
9327
+ min-height: 26px;
9328
+ padding: 3px 8px;
9329
+ border: 0;
9330
+ border-radius: 4px;
9331
+ background: transparent;
9332
+ color: var(--text-primary);
9333
+ font: inherit;
9334
+ text-align: left;
9335
+ cursor: pointer;
9336
+ }
9337
+ .twm-flow-outline__menu-item:hover:not(:disabled),
9338
+ .twm-flow-outline__menu-item:focus-visible,
9339
+ .twm-flow-outline__menu-item--open {
9340
+ outline: none;
9341
+ background: var(--twm-flow-blue-bg);
9342
+ }
9343
+ .twm-flow-outline__menu-item:disabled {
9344
+ color: var(--text-dim);
9345
+ cursor: not-allowed;
9346
+ }
9347
+ .twm-flow-outline__menu-item--danger { color: var(--twm-flow-error); }
9348
+ .twm-flow-outline__menu-item--danger:disabled { color: var(--text-dim); }
9349
+ .twm-flow-outline__menu-words {
9350
+ display: flex;
9351
+ align-items: center;
9352
+ gap: 8px;
9353
+ min-width: 0;
9354
+ }
9355
+ .twm-flow-outline__menu-label { overflow-wrap: anywhere; }
9356
+ .twm-flow-outline__menu-key {
9357
+ flex: 0 0 auto;
9358
+ font-size: 11px;
9359
+ color: var(--text-muted);
9360
+ }
9361
+ .twm-flow-outline__menu-sep {
9362
+ height: 1px;
9363
+ margin: 4px 6px;
9364
+ background: var(--border-default);
9365
+ }
9366
+ .twm-flow-outline__menu-chip {
9367
+ flex: 0 0 20px;
9368
+ height: 20px;
9369
+ display: flex;
9370
+ align-items: center;
9371
+ justify-content: center;
9372
+ border-radius: 4px;
9373
+ }
9374
+ .twm-flow-outline__menu-chip .material-symbols-outlined { font-size: 14px; }
9375
+ .twm-flow-outline__menu-chip--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
9376
+ .twm-flow-outline__menu-chip--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
9377
+ .twm-flow-outline__menu-chip--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
9378
+ .twm-flow-outline__menu-chip--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
9379
+ .twm-flow-outline__menu-chip--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
9380
+ .twm-flow-outline__menu-chip--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
9381
+ /* ══ end FLOW · OUTLINE ══ */
9382
+
9383
+
9384
+ /* ══ FLOW · LANES ═════════════════════════════════════════════════════ */
9385
+ /* Owned by the lanes agent (D) (36 §2): the lane editor (twm-flow-lanes). */
9386
+ /*
9387
+ * The lane editor: a data flow drawn as lanes, left to right. Every class is
9388
+ * set by src/flow/lanes/editor.js, and every one it sets has a rule here
9389
+ * (tests/flow_lanes_css.test.mjs).
9390
+ *
9391
+ * THE CARD SIZES BELOW MUST MATCH `LANE_GEOMETRY` in src/flow/lanes/layout.js
9392
+ * — the layout places cards and draws wires from those numbers, the sheet
9393
+ * sizes and clips the cards, and the suite holds the two equal.
9394
+ */
9395
+ .twm-flow-lanes [hidden] {
9396
+ display: none !important;
9397
+ }
9398
+ .twm-flow-lanes {
9399
+ --twm-lanes-wire: #5b9bd5;
9400
+ --twm-lanes-surface: #1b1b1c;
9401
+ --twm-lanes-ring: #1683c4;
9402
+ display: flex;
9403
+ flex-direction: column;
9404
+ box-sizing: border-box;
9405
+ height: 100%;
9406
+ min-height: 0;
9407
+ min-width: 0;
9408
+ background: var(--surface-0);
9409
+ color: var(--text-body);
9410
+ font-family: var(--font-family-sans);
9411
+ font-size: var(--font-size-sm);
9412
+ line-height: 1.4;
9413
+ }
9414
+ .twm-flow-lanes--regular {
9415
+ --twm-lanes-card-w: 200px;
9416
+ --twm-lanes-card-h: 62px;
9417
+ --twm-lanes-notch: 12px;
9418
+ --twm-lanes-icon-w: 50px;
9419
+ --twm-lanes-icon-w-source: 40px;
9420
+ }
9421
+ .twm-flow-lanes--small {
9422
+ --twm-lanes-card-w: 160px;
9423
+ --twm-lanes-card-h: 50px;
9424
+ --twm-lanes-notch: 10px;
9425
+ --twm-lanes-icon-w: 42px;
9426
+ --twm-lanes-icon-w-source: 34px;
9427
+ }
9428
+ .twm-flow-lanes--strip {
9429
+ --twm-lanes-card-w: 92px;
9430
+ --twm-lanes-card-h: 26px;
9431
+ --twm-lanes-notch: 8px;
9432
+ }
9433
+ .twm-flow-lanes--auto {
9434
+ height: auto;
9435
+ }
9436
+ .twm-flow-lanes--compact {
9437
+ height: auto;
9438
+ background: transparent;
9439
+ }
9440
+ .twm-flow-lanes--readonly .twm-flow-lanes__flow {
9441
+ background: #1a1a1b;
9442
+ }
9443
+
9444
+ /* ── read only ──────────────────────────────────────────────────────── */
9445
+ .twm-flow-lanes__readonly {
9446
+ flex: 0 0 auto;
9447
+ padding: 7px 12px;
9448
+ background: var(--twm-flow-warning-bg);
9449
+ border-bottom: 1px solid var(--twm-flow-warning-line);
9450
+ color: var(--twm-flow-warning-text);
9451
+ }
9452
+ .twm-flow-lanes__readonly-line {
9453
+ margin: 0;
9454
+ }
9455
+
9456
+ /* ── the toolbar ────────────────────────────────────────────────────── */
9457
+ .twm-flow-lanes__toolbar {
9458
+ flex: 0 0 auto;
9459
+ display: flex;
9460
+ flex-wrap: wrap;
9461
+ align-items: center;
9462
+ gap: 6px;
9463
+ padding: 6px 10px;
9464
+ background: var(--surface-1);
9465
+ border-bottom: 1px solid var(--border-default);
9466
+ }
9467
+ .twm-flow-lanes__toolbar .twm-btn,
9468
+ .twm-flow-lanes__form .twm-btn {
9469
+ min-height: 26px;
9470
+ padding: 0 9px;
9471
+ font-size: var(--font-size-sm);
9472
+ border-radius: 3px;
9473
+ }
9474
+ .twm-flow-lanes__toolbar-slot,
9475
+ .twm-flow-lanes__actions,
9476
+ .twm-flow-lanes__action {
9477
+ display: flex;
9478
+ flex-wrap: wrap;
9479
+ align-items: center;
9480
+ gap: 6px;
9481
+ }
9482
+ .twm-flow-lanes__toolbar-sep {
9483
+ width: 1px;
9484
+ height: 18px;
9485
+ margin: 0 4px;
9486
+ background: var(--surface-3);
9487
+ }
9488
+ .twm-flow-lanes__action--busy .twm-btn {
9489
+ cursor: progress;
9490
+ }
9491
+ .twm-flow-lanes__refusal {
9492
+ color: var(--twm-flow-warning);
9493
+ font-size: var(--font-size-xs);
9494
+ }
9495
+ .twm-flow-lanes__status {
9496
+ margin-left: 8px;
9497
+ color: #a0a0a0;
9498
+ }
9499
+ .twm-flow-lanes__spacer {
9500
+ flex: 1 1 auto;
9501
+ }
9502
+ .twm-flow-lanes__show-label {
9503
+ color: var(--twm-flow-muted);
9504
+ }
9505
+ .twm-flow-lanes__show {
9506
+ display: flex;
9507
+ border: 1px solid var(--surface-3);
9508
+ border-radius: 3px;
9509
+ overflow: hidden;
9510
+ }
9511
+ .twm-flow-lanes__show-btn {
9512
+ height: 24px;
9513
+ padding: 0 10px;
9514
+ border: 0;
9515
+ background: var(--surface-2);
9516
+ color: #c8c8c8;
9517
+ font: inherit;
9518
+ cursor: pointer;
9519
+ }
9520
+ .twm-flow-lanes__show-btn + .twm-flow-lanes__show-btn {
9521
+ border-left: 1px solid var(--surface-3);
9522
+ }
9523
+ .twm-flow-lanes__show-btn[aria-pressed="true"] {
9524
+ background: #0f6fa8;
9525
+ color: var(--text-bright);
9526
+ }
9527
+ .twm-flow-lanes__show-btn:focus-visible,
9528
+ .twm-flow-lanes__param:focus-visible,
9529
+ .twm-flow-lanes__param-add:focus-visible,
9530
+ .twm-flow-lanes__add-source:focus-visible,
9531
+ .twm-flow-lanes__tab:focus-visible,
9532
+ .twm-flow-lanes__datatab:focus-visible,
9533
+ .twm-flow-lanes__menu-item:focus-visible {
9534
+ outline: 2px solid var(--twm-lanes-ring);
9535
+ outline-offset: -2px;
9536
+ }
9537
+
9538
+ /* ── parameters ─────────────────────────────────────────────────────── */
9539
+ .twm-flow-lanes__params {
9540
+ flex: 0 0 auto;
9541
+ display: flex;
9542
+ flex-wrap: wrap;
9543
+ align-items: center;
9544
+ gap: 8px 12px;
9545
+ padding: 7px 12px;
9546
+ background: #222223;
9547
+ border-bottom: 1px solid var(--border-default);
9548
+ }
9549
+ .twm-flow-lanes__params-title {
9550
+ font-size: var(--font-size-xs);
9551
+ font-weight: 600;
9552
+ letter-spacing: .06em;
9553
+ text-transform: uppercase;
9554
+ color: #c4c4c4;
9555
+ }
9556
+ .twm-flow-lanes__param {
9557
+ display: flex;
9558
+ align-items: center;
9559
+ gap: 8px;
9560
+ height: 24px;
9561
+ padding: 0 9px;
9562
+ border: 1px solid var(--surface-3);
9563
+ border-radius: 12px;
9564
+ background: var(--twm-flow-control-bg);
9565
+ color: var(--text-primary);
9566
+ font: inherit;
9567
+ cursor: pointer;
9568
+ }
9569
+ .twm-flow-lanes__param:hover,
9570
+ .twm-flow-lanes__param-add:hover,
9571
+ .twm-flow-lanes__add-source:hover {
9572
+ background: rgba(255, 255, 255, 0.06);
9573
+ }
9574
+ .twm-flow-lanes__param-name {
9575
+ font-family: var(--font-family-mono);
9576
+ color: var(--twm-flow-violet-fg);
9577
+ }
9578
+ .twm-flow-lanes__param-line {
9579
+ color: var(--twm-flow-muted);
9580
+ }
9581
+ .twm-flow-lanes__param-add {
9582
+ display: flex;
9583
+ align-items: center;
9584
+ gap: 5px;
9585
+ height: 24px;
9586
+ padding: 0 8px;
9587
+ border: 1px dashed #4a4a4a;
9588
+ border-radius: 12px;
9589
+ background: transparent;
9590
+ color: #b0b0b0;
9591
+ font: inherit;
9592
+ font-size: var(--font-size-xs);
9593
+ cursor: pointer;
9594
+ }
9595
+ .twm-flow-lanes__param-add .material-symbols-outlined,
9596
+ .twm-flow-lanes__add-source .material-symbols-outlined {
9597
+ font-size: 14px;
9598
+ }
9599
+ .twm-flow-lanes__params-help {
9600
+ color: #a0a0a0;
9601
+ font-size: var(--font-size-xs);
9602
+ }
9603
+
9604
+ /* ── the lanes ──────────────────────────────────────────────────────── */
9605
+ .twm-flow-lanes__flow {
9606
+ flex: 0 1 auto;
9607
+ min-height: 0;
9608
+ overflow-y: auto;
9609
+ background: var(--twm-lanes-surface);
9610
+ border-bottom: 1px solid var(--border-default);
9611
+ }
9612
+ .twm-flow-lanes__banner {
9613
+ margin: 8px 16px 0;
9614
+ padding: 6px 10px;
9615
+ border-radius: var(--radius-sm);
9616
+ background: var(--twm-flow-blue-bg);
9617
+ color: var(--twm-flow-blue-fg);
9618
+ }
9619
+ .twm-flow-lanes__scroller {
9620
+ overflow-x: auto;
9621
+ padding: 14px 0 6px;
9622
+ }
9623
+ /* The page's own scrollbars may be light; these sit on dark surfaces. */
9624
+ .twm-flow-lanes__scroller,
9625
+ .twm-flow-lanes__flow,
9626
+ .twm-flow-lanes__settings,
9627
+ .twm-flow-lanes__databody {
9628
+ scrollbar-color: #4a4a4a transparent;
9629
+ }
9630
+ .twm-flow-lanes__surface {
9631
+ position: relative;
9632
+ z-index: 0;
9633
+ margin: 0 16px;
9634
+ }
9635
+ .twm-flow-lanes__empty {
9636
+ margin: 0;
9637
+ padding: 18px 16px 4px;
9638
+ color: var(--twm-flow-muted);
9639
+ }
9640
+ /* A lane: its band is a pseudo-element, so the lane itself has no border and
9641
+ * a card's `left`/`top` inside it are exactly the layout's numbers. */
9642
+ .twm-flow-lanes__lane {
9643
+ position: absolute;
9644
+ left: 0;
9645
+ right: 0;
9646
+ }
9647
+ .twm-flow-lanes__lane::before {
9648
+ content: '';
9649
+ position: absolute;
9650
+ inset: 0;
9651
+ box-sizing: border-box;
9652
+ border: 1px dashed #2c2c2c;
9653
+ border-radius: 6px;
9654
+ background: rgba(255, 255, 255, 0.018);
9655
+ }
9656
+ .twm-flow-lanes__lane--unconnected::before {
9657
+ border-color: var(--twm-flow-warning-line);
9658
+ }
9659
+ .twm-flow-lanes__flag {
9660
+ position: absolute;
9661
+ top: -8px;
9662
+ left: 12px;
9663
+ padding: 0 6px;
9664
+ font-size: 10px;
9665
+ line-height: 16px;
9666
+ color: var(--twm-flow-warning);
9667
+ background: var(--twm-lanes-surface);
9668
+ }
9669
+ .twm-flow-lanes__wires {
9670
+ position: absolute;
9671
+ left: 0;
9672
+ top: 0;
9673
+ z-index: 1;
9674
+ overflow: visible;
9675
+ pointer-events: none;
9676
+ }
9677
+ .twm-flow-lanes__wire {
9678
+ fill: none;
9679
+ stroke: var(--twm-lanes-wire);
9680
+ stroke-width: 2;
9681
+ stroke-linecap: round;
9682
+ stroke-linejoin: round;
9683
+ }
9684
+ .twm-flow-lanes__wire--cycle {
9685
+ stroke: var(--twm-flow-error);
9686
+ stroke-dasharray: 4 3;
9687
+ }
9688
+ .twm-flow-lanes__port {
9689
+ fill: var(--twm-lanes-wire);
9690
+ stroke: var(--twm-lanes-surface);
9691
+ stroke-width: 3;
9692
+ }
9693
+
9694
+ /* ── a card: an unclipped holder (focus, selection, "+") round a clipped body ── */
9695
+ .twm-flow-lanes__node {
9696
+ position: absolute;
9697
+ z-index: 2;
9698
+ width: var(--twm-lanes-card-w);
9699
+ height: var(--twm-lanes-card-h);
9700
+ }
9701
+ .twm-flow-lanes__node--teal,
9702
+ .twm-flow-lanes__tab--teal {
9703
+ --twm-lanes-icon-bg: var(--twm-flow-teal-icon-bg);
9704
+ --twm-lanes-text-bg: var(--twm-flow-teal-text-bg);
9705
+ --twm-lanes-fg: var(--twm-flow-teal-fg);
9706
+ --twm-lanes-dot: var(--twm-flow-teal-dot);
9707
+ }
9708
+ .twm-flow-lanes__node--indigo,
9709
+ .twm-flow-lanes__tab--indigo {
9710
+ --twm-lanes-icon-bg: var(--twm-flow-indigo-icon-bg);
9711
+ --twm-lanes-text-bg: var(--twm-flow-indigo-text-bg);
9712
+ --twm-lanes-fg: var(--twm-flow-indigo-fg);
9713
+ --twm-lanes-dot: var(--twm-flow-indigo-dot);
9714
+ }
9715
+ .twm-flow-lanes__node--violet,
9716
+ .twm-flow-lanes__tab--violet {
9717
+ --twm-lanes-icon-bg: var(--twm-flow-violet-icon-bg);
9718
+ --twm-lanes-text-bg: var(--twm-flow-violet-text-bg);
9719
+ --twm-lanes-fg: var(--twm-flow-violet-fg);
9720
+ --twm-lanes-dot: var(--twm-flow-violet-dot);
9721
+ }
9722
+ .twm-flow-lanes__node--amber,
9723
+ .twm-flow-lanes__tab--amber {
9724
+ --twm-lanes-icon-bg: var(--twm-flow-amber-icon-bg);
9725
+ --twm-lanes-text-bg: var(--twm-flow-amber-text-bg);
9726
+ --twm-lanes-fg: var(--twm-flow-amber-fg);
9727
+ --twm-lanes-dot: var(--twm-flow-amber-dot);
9728
+ }
9729
+ .twm-flow-lanes__node--blue,
9730
+ .twm-flow-lanes__tab--blue {
9731
+ --twm-lanes-icon-bg: var(--twm-flow-blue-icon-bg);
9732
+ --twm-lanes-text-bg: var(--twm-flow-blue-text-bg);
9733
+ --twm-lanes-fg: var(--twm-flow-blue-fg);
9734
+ --twm-lanes-dot: var(--twm-flow-blue-dot);
9735
+ }
9736
+ .twm-flow-lanes__node--grey,
9737
+ .twm-flow-lanes__tab--grey {
9738
+ --twm-lanes-icon-bg: var(--twm-flow-grey-icon-bg);
9739
+ --twm-lanes-text-bg: var(--twm-flow-grey-text-bg);
9740
+ --twm-lanes-fg: var(--twm-flow-grey-fg);
9741
+ --twm-lanes-dot: var(--twm-flow-grey-dot);
9742
+ }
9743
+ .twm-flow-lanes__card {
9744
+ display: block;
9745
+ width: 100%;
9746
+ height: 100%;
9747
+ padding: 0;
9748
+ border: 0;
9749
+ background: transparent;
9750
+ color: inherit;
9751
+ font: inherit;
9752
+ text-align: left;
9753
+ cursor: pointer;
9754
+ outline: none;
9755
+ }
9756
+ /* The ring is a `drop-shadow` on the unclipped holder: a clip-path cuts a
9757
+ * box-shadow off, a filter on its parent follows the clipped shape. */
9758
+ .twm-flow-lanes__node--warning .twm-flow-lanes__card {
9759
+ filter: drop-shadow(0 0 1px var(--twm-flow-warning)) drop-shadow(0 0 1px var(--twm-flow-warning));
9760
+ }
9761
+ .twm-flow-lanes__node--error .twm-flow-lanes__card {
9762
+ filter: drop-shadow(0 0 1px var(--twm-flow-error)) drop-shadow(0 0 1px var(--twm-flow-error));
9763
+ }
9764
+ .twm-flow-lanes__node--selected .twm-flow-lanes__card,
9765
+ .twm-flow-lanes__card:focus-visible {
9766
+ filter: drop-shadow(0 0 1px var(--twm-lanes-ring)) drop-shadow(0 0 1px var(--twm-lanes-ring))
9767
+ drop-shadow(0 0 5px rgba(22, 131, 196, 0.8));
9768
+ }
9769
+ .twm-flow-lanes__card:hover .twm-flow-lanes__body {
9770
+ filter: brightness(1.12);
9771
+ }
9772
+ .twm-flow-lanes__body {
9773
+ display: flex;
9774
+ width: 100%;
9775
+ height: 100%;
9776
+ background: var(--twm-lanes-text-bg);
9777
+ }
9778
+ /* Three shapes: a source flat on the left, a step notched, a sink flat on the right. */
9779
+ .twm-flow-lanes__node--source .twm-flow-lanes__body {
9780
+ clip-path: polygon(0 0, calc(100% - var(--twm-lanes-notch)) 0, 100% 50%,
9781
+ calc(100% - var(--twm-lanes-notch)) 100%, 0 100%);
9782
+ }
9783
+ .twm-flow-lanes__node--transform .twm-flow-lanes__body,
9784
+ .twm-flow-lanes__node--operation .twm-flow-lanes__body {
9785
+ clip-path: polygon(0 0, calc(100% - var(--twm-lanes-notch)) 0, 100% 50%,
9786
+ calc(100% - var(--twm-lanes-notch)) 100%, 0 100%, var(--twm-lanes-notch) 50%);
9787
+ }
9788
+ .twm-flow-lanes__node--sink .twm-flow-lanes__body {
9789
+ clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, var(--twm-lanes-notch) 50%);
9790
+ }
9791
+ .twm-flow-lanes__icon {
9792
+ flex: 0 0 var(--twm-lanes-icon-w);
9793
+ display: flex;
9794
+ align-items: center;
9795
+ justify-content: center;
9796
+ box-sizing: border-box;
9797
+ padding-left: calc(var(--twm-lanes-notch) - 2px);
9798
+ background: var(--twm-lanes-icon-bg);
9799
+ color: var(--twm-lanes-fg);
9800
+ overflow: hidden;
9801
+ }
9802
+ .twm-flow-lanes__node--source .twm-flow-lanes__icon {
9803
+ flex-basis: var(--twm-lanes-icon-w-source);
9804
+ padding-left: 0;
9805
+ }
9806
+ .twm-flow-lanes__icon .material-symbols-outlined {
9807
+ font-size: 18px;
9808
+ line-height: 1;
9809
+ }
9810
+ .twm-flow-lanes__sep {
9811
+ flex: 0 0 1px;
9812
+ background: rgba(255, 255, 255, 0.08);
9813
+ }
9814
+ .twm-flow-lanes__text {
9815
+ flex: 1 1 auto;
9816
+ min-width: 0;
9817
+ display: flex;
9818
+ flex-direction: column;
9819
+ justify-content: center;
9820
+ gap: 1px;
9821
+ padding: 0 18px 0 9px;
9822
+ }
9823
+ .twm-flow-lanes__title,
9824
+ .twm-flow-lanes__sub,
9825
+ .twm-flow-lanes__line {
9826
+ white-space: nowrap;
9827
+ overflow: hidden;
9828
+ text-overflow: ellipsis;
9829
+ }
9830
+ .twm-flow-lanes__title {
9831
+ color: #ececec;
9832
+ font-weight: 600;
9833
+ }
9834
+ .twm-flow-lanes__sub {
9835
+ color: #b0b0b0;
9836
+ font-size: var(--font-size-xs);
9837
+ }
9838
+ .twm-flow-lanes__line {
9839
+ font-size: 10px;
9840
+ }
9841
+ .twm-flow-lanes__line--ok { color: var(--twm-flow-ok); }
9842
+ .twm-flow-lanes__line--warning { color: var(--twm-flow-warning); }
9843
+ .twm-flow-lanes__line--error { color: var(--twm-flow-error); }
9844
+ .twm-flow-lanes__line--muted { color: #b0b0b0; }
9845
+ .twm-flow-lanes__line--info { color: var(--twm-flow-blue-fg); }
9846
+ /* "+" on the card's right tip: on hover, on focus and on the chosen card —
9847
+ * never on hover alone. */
9848
+ .twm-flow-lanes__add {
9849
+ position: absolute;
9850
+ right: -14px;
9851
+ top: -9px;
9852
+ z-index: 3;
9853
+ width: 18px;
9854
+ height: 18px;
9855
+ display: flex;
9856
+ align-items: center;
9857
+ justify-content: center;
9858
+ padding: 0;
9859
+ border: 1px solid #4a4a4a;
9860
+ border-radius: 9px;
9861
+ background: var(--surface-1);
9862
+ color: #d0d0d0;
9863
+ cursor: pointer;
9864
+ opacity: 0;
9865
+ }
9866
+ .twm-flow-lanes__node:hover .twm-flow-lanes__add,
9867
+ .twm-flow-lanes__node:focus-within .twm-flow-lanes__add,
9868
+ .twm-flow-lanes__node--selected .twm-flow-lanes__add {
9869
+ opacity: 1;
9870
+ }
9871
+ .twm-flow-lanes__add:hover,
9872
+ .twm-flow-lanes__add:focus-visible {
9873
+ background: var(--twm-lanes-ring);
9874
+ border-color: var(--twm-lanes-ring);
9875
+ color: var(--text-bright);
9876
+ outline: none;
9877
+ }
9878
+ .twm-flow-lanes__add .material-symbols-outlined {
9879
+ font-size: 14px;
9880
+ line-height: 1;
9881
+ }
9882
+
9883
+ /* the small cards: a title and one line */
9884
+ .twm-flow-lanes--small .twm-flow-lanes__sub {
9885
+ display: none;
9886
+ }
9887
+ .twm-flow-lanes--small .twm-flow-lanes__text {
9888
+ padding: 0 16px 0 8px;
9889
+ }
9890
+ .twm-flow-lanes--small .twm-flow-lanes__line {
9891
+ font-size: 10.5px;
9892
+ }
9893
+ .twm-flow-lanes--small .twm-flow-lanes__icon .material-symbols-outlined {
9894
+ font-size: 14px;
9895
+ }
9896
+
9897
+ /* the compact strip: a title a card, and nothing to press */
9898
+ .twm-flow-lanes--compact .twm-flow-lanes__flow {
9899
+ background: transparent;
9900
+ border-bottom: 0;
9901
+ overflow: visible;
9902
+ }
9903
+ .twm-flow-lanes--compact .twm-flow-lanes__scroller {
9904
+ padding: 0;
9905
+ }
9906
+ .twm-flow-lanes--compact .twm-flow-lanes__surface {
9907
+ margin: 0;
9908
+ }
9909
+ .twm-flow-lanes--strip .twm-flow-lanes__lane::before {
9910
+ display: none;
9911
+ }
9912
+ .twm-flow-lanes--strip .twm-flow-lanes__body {
9913
+ background: var(--twm-lanes-icon-bg);
9914
+ }
9915
+ .twm-flow-lanes--strip .twm-flow-lanes__text {
9916
+ padding: 0 12px 0 13px;
9917
+ }
9918
+ .twm-flow-lanes--strip .twm-flow-lanes__node--source .twm-flow-lanes__text {
9919
+ padding: 0 12px 0 8px;
9920
+ }
9921
+ .twm-flow-lanes--strip .twm-flow-lanes__node--sink .twm-flow-lanes__text {
9922
+ padding: 0 6px 0 13px;
9923
+ }
9924
+ .twm-flow-lanes--strip .twm-flow-lanes__title {
9925
+ color: #e6e6e6;
9926
+ font-size: 10.5px;
9927
+ font-weight: 400;
9928
+ }
9929
+
9930
+ /* ── under the lanes: Add a source ──────────────────────────────────── */
9931
+ .twm-flow-lanes__foot {
9932
+ display: flex;
9933
+ flex-wrap: wrap;
9934
+ align-items: center;
9935
+ gap: 10px 16px;
9936
+ padding: 4px 16px 12px;
9937
+ }
9938
+ .twm-flow-lanes__add-source {
9939
+ display: flex;
9940
+ align-items: center;
9941
+ gap: 6px;
9942
+ height: 28px;
9943
+ padding: 0 12px;
9944
+ border: 1px dashed #4a4a4a;
9945
+ border-radius: var(--radius-sm);
9946
+ background: transparent;
9947
+ color: #b8b8b8;
9948
+ font: inherit;
9949
+ cursor: pointer;
9950
+ }
9951
+ .twm-flow-lanes__hint {
9952
+ color: #9a9a9a;
9953
+ font-size: var(--font-size-xs);
9954
+ }
9955
+
9956
+ /* ── a tab per step ─────────────────────────────────────────────────── */
9957
+ .twm-flow-lanes__tabs {
9958
+ flex: 0 0 auto;
9959
+ display: flex;
9960
+ flex-wrap: wrap;
9961
+ align-items: stretch;
9962
+ gap: 0 2px;
9963
+ padding: 0 12px;
9964
+ background: var(--surface-1);
9965
+ border-bottom: 1px solid var(--border-default);
9966
+ }
9967
+ .twm-flow-lanes__tab,
9968
+ .twm-flow-lanes__datatab {
9969
+ display: flex;
9970
+ align-items: center;
9971
+ gap: 7px;
9972
+ height: 32px;
9973
+ padding: 0 11px;
9974
+ border: 0;
9975
+ border-bottom: 2px solid transparent;
9976
+ background: transparent;
9977
+ color: #b4b4b4;
9978
+ font: inherit;
9979
+ cursor: pointer;
9980
+ }
9981
+ .twm-flow-lanes__tab:hover,
9982
+ .twm-flow-lanes__datatab:hover {
9983
+ background: rgba(255, 255, 255, 0.05);
9984
+ }
9985
+ .twm-flow-lanes__tab[aria-selected="true"],
9986
+ .twm-flow-lanes__datatab[aria-pressed="true"] {
9987
+ border-bottom-color: var(--twm-lanes-ring);
9988
+ color: var(--text-bright);
9989
+ }
9990
+ .twm-flow-lanes__tab-dot {
9991
+ flex: 0 0 7px;
9992
+ height: 7px;
9993
+ border-radius: 4px;
9994
+ background: var(--twm-lanes-dot);
9995
+ }
9996
+ .twm-flow-lanes__tab-label {
9997
+ max-width: 220px;
9998
+ white-space: nowrap;
9999
+ overflow: hidden;
10000
+ text-overflow: ellipsis;
10001
+ }
10002
+
10003
+ /* ── the dock: the settings beside what the step gives ──────────────── */
10004
+ .twm-flow-lanes__dock {
10005
+ flex: 1 1 0;
10006
+ min-height: 240px;
10007
+ display: flex;
10008
+ align-items: stretch;
10009
+ }
10010
+ .twm-flow-lanes--auto .twm-flow-lanes__dock {
10011
+ flex: 0 0 auto;
10012
+ }
10013
+ .twm-flow-lanes__settings {
10014
+ flex: 1 1 400px;
10015
+ min-width: 260px;
10016
+ min-height: 0;
10017
+ overflow-y: auto;
10018
+ background: #232324;
10019
+ border-right: 1px solid var(--border-default);
10020
+ }
10021
+ .twm-flow-lanes__settings .twm-flow-panel {
10022
+ background: transparent;
10023
+ }
10024
+ .twm-flow-lanes__settings-hint {
10025
+ margin: 0;
10026
+ padding: 16px 20px;
10027
+ color: var(--twm-flow-muted);
10028
+ }
10029
+ .twm-flow-lanes__data {
10030
+ flex: 1.2 1 440px;
10031
+ min-width: 0;
10032
+ min-height: 0;
10033
+ display: flex;
10034
+ flex-direction: column;
10035
+ }
10036
+ .twm-flow-lanes__datatabs {
10037
+ flex: 0 0 auto;
10038
+ display: flex;
10039
+ align-items: stretch;
10040
+ gap: 0 2px;
10041
+ padding: 0 12px;
10042
+ border-bottom: 1px solid var(--border-default);
10043
+ }
10044
+ .twm-flow-lanes__datastate {
10045
+ display: flex;
10046
+ align-items: center;
10047
+ gap: 6px;
10048
+ min-width: 0;
10049
+ color: #a0a0a0;
10050
+ font-size: var(--font-size-xs);
10051
+ white-space: nowrap;
10052
+ }
10053
+ .twm-flow-lanes__datastate-text {
10054
+ overflow: hidden;
10055
+ text-overflow: ellipsis;
10056
+ }
10057
+ .twm-flow-lanes__datastate-dot {
10058
+ flex: 0 0 7px;
10059
+ height: 7px;
10060
+ border-radius: 4px;
10061
+ }
10062
+ .twm-flow-lanes__datastate--ok .twm-flow-lanes__datastate-dot { background: var(--twm-flow-ok); }
10063
+ .twm-flow-lanes__datastate--busy .twm-flow-lanes__datastate-dot { background: var(--twm-flow-warning); }
10064
+ .twm-flow-lanes__datastate--error .twm-flow-lanes__datastate-dot { background: var(--twm-flow-error); }
10065
+ .twm-flow-lanes__databody {
10066
+ flex: 1 1 0;
10067
+ min-height: 0;
10068
+ display: flex;
10069
+ flex-direction: column;
10070
+ padding: 0 14px 12px;
10071
+ overflow: auto;
10072
+ }
10073
+ .twm-flow-lanes__caption {
10074
+ flex: 0 0 auto;
10075
+ margin: 0;
10076
+ padding: 8px 0 6px;
10077
+ color: #b4b4b4;
10078
+ }
10079
+ /* A DataTable fills this box, so the box has a size: one with none draws a
10080
+ * header and no rows. */
10081
+ .twm-flow-lanes__table {
10082
+ flex: 1 1 0;
10083
+ min-height: 120px;
10084
+ border: 1px solid #333;
10085
+ border-radius: 3px;
10086
+ overflow: hidden;
10087
+ }
10088
+ .twm-flow-lanes__cell--new,
10089
+ .twm-flow-lanes__cell--changed {
10090
+ background: rgba(22, 131, 196, 0.07);
10091
+ }
10092
+ .twm-flow-lanes__error {
10093
+ flex: 0 0 auto;
10094
+ margin: 8px 0 0;
10095
+ padding: 7px 10px;
10096
+ border-radius: var(--radius-sm);
10097
+ background: var(--twm-flow-error-bg);
10098
+ border: 1px solid var(--twm-flow-error-line);
10099
+ color: var(--twm-flow-error-text);
10100
+ }
10101
+ .twm-flow-lanes__nodata {
10102
+ margin: 0;
10103
+ padding: 12px 0;
10104
+ color: var(--twm-flow-muted);
10105
+ }
10106
+ .twm-flow-lanes__columns {
10107
+ list-style: none;
10108
+ margin: 0;
10109
+ padding: 0;
10110
+ display: grid;
10111
+ grid-template-columns: repeat(2, minmax(0, 1fr));
10112
+ gap: 4px 12px;
10113
+ }
10114
+ .twm-flow-lanes__column {
10115
+ display: flex;
10116
+ align-items: baseline;
10117
+ gap: 8px;
10118
+ min-width: 0;
10119
+ padding: 5px 8px;
10120
+ border-bottom: 1px solid var(--border-subtle);
10121
+ }
10122
+ .twm-flow-lanes__column--new,
10123
+ .twm-flow-lanes__column--changed {
10124
+ background: rgba(22, 131, 196, 0.14);
10125
+ }
10126
+ .twm-flow-lanes__column-name {
10127
+ font-family: var(--font-family-mono);
10128
+ font-size: var(--font-size-xs);
10129
+ color: #e6e6e6;
10130
+ }
10131
+ .twm-flow-lanes__column-type {
10132
+ color: #9a9a9a;
10133
+ font-size: var(--font-size-xs);
10134
+ }
10135
+ .twm-flow-lanes__column--new .twm-flow-lanes__column-type,
10136
+ .twm-flow-lanes__column--changed .twm-flow-lanes__column-type {
10137
+ color: #9fd0f0;
10138
+ }
10139
+ .twm-flow-lanes__column-origin {
10140
+ margin-left: auto;
10141
+ color: #a0a0a0;
10142
+ font-size: var(--font-size-xs);
10143
+ text-align: right;
10144
+ }
10145
+ .twm-flow-lanes__rejects {
10146
+ list-style: none;
10147
+ margin: 0;
10148
+ padding: 0;
10149
+ display: flex;
10150
+ flex-direction: column;
10151
+ gap: 4px;
10152
+ }
10153
+ .twm-flow-lanes__reject {
10154
+ display: flex;
10155
+ flex-wrap: wrap;
10156
+ align-items: baseline;
10157
+ gap: 4px 12px;
10158
+ padding: 7px 10px;
10159
+ background: var(--twm-flow-warning-bg);
10160
+ border: 1px solid var(--twm-flow-warning-line);
10161
+ border-radius: var(--radius-sm);
10162
+ }
10163
+ .twm-flow-lanes__reject-key {
10164
+ font-family: var(--font-family-mono);
10165
+ font-size: var(--font-size-xs);
10166
+ color: #ecc788;
10167
+ }
10168
+ .twm-flow-lanes__reject-value {
10169
+ color: var(--text-primary);
10170
+ }
10171
+ .twm-flow-lanes__reject-reason {
10172
+ flex: 1 1 260px;
10173
+ color: #d0c0a4;
10174
+ }
10175
+
10176
+ /* ── a parameter's form and a card's menu, in the kit's popover ─────── */
10177
+ .twm-flow-lanes__popover {
10178
+ min-width: 220px;
10179
+ }
10180
+ .twm-flow-lanes__form {
10181
+ display: flex;
10182
+ flex-direction: column;
10183
+ gap: 8px;
10184
+ box-sizing: border-box;
10185
+ width: 320px;
10186
+ max-width: 100%;
10187
+ padding: 12px;
10188
+ }
10189
+ .twm-flow-lanes__form-title {
10190
+ font-weight: 600;
10191
+ color: var(--text-primary);
10192
+ }
10193
+ .twm-flow-lanes__form-row {
10194
+ display: grid;
10195
+ grid-template-columns: 90px minmax(0, 1fr);
10196
+ align-items: center;
10197
+ gap: 8px;
10198
+ }
10199
+ .twm-flow-lanes__form-label {
10200
+ color: #c8c8c8;
10201
+ }
10202
+ .twm-flow-lanes__form-control {
10203
+ display: block;
10204
+ min-width: 0;
10205
+ }
10206
+ .twm-flow-lanes__form-refusal {
10207
+ margin: 0;
10208
+ color: var(--twm-flow-error);
10209
+ }
10210
+ .twm-flow-lanes__form-actions {
10211
+ display: flex;
10212
+ flex-wrap: wrap;
10213
+ justify-content: flex-end;
10214
+ gap: 6px;
10215
+ }
10216
+ .twm-flow-lanes__menu {
10217
+ display: flex;
10218
+ flex-direction: column;
10219
+ min-width: 200px;
10220
+ padding: 4px;
10221
+ }
10222
+ .twm-flow-lanes__menu-item {
10223
+ display: flex;
10224
+ align-items: center;
10225
+ gap: 8px;
10226
+ height: 28px;
10227
+ padding: 0 10px;
10228
+ border: 0;
10229
+ border-radius: 3px;
10230
+ background: transparent;
10231
+ color: var(--text-body);
10232
+ font: inherit;
10233
+ text-align: left;
10234
+ cursor: pointer;
10235
+ }
10236
+ .twm-flow-lanes__menu-item:hover,
10237
+ .twm-flow-lanes__menu-item:focus-visible {
10238
+ background: var(--state-active);
10239
+ }
10240
+ .twm-flow-lanes__menu-item:disabled {
10241
+ opacity: 0.45;
10242
+ cursor: not-allowed;
10243
+ }
10244
+ .twm-flow-lanes__menu-item--danger {
10245
+ color: var(--twm-flow-error);
10246
+ }
10247
+ .twm-flow-lanes__menu-item .material-symbols-outlined {
10248
+ font-size: 16px;
10249
+ line-height: 1;
10250
+ }
10251
+ /* ══ end FLOW · LANES ══ */