flexdesk 0.4.7 → 0.6.0

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 (76) hide show
  1. package/README.md +1036 -301
  2. package/css/base.css +2958 -2
  3. package/css/flexdesk.css +2962 -4
  4. package/css/overrides.css +4 -2
  5. package/css/tokens.css +86 -0
  6. package/dist/canvas.js +390 -0
  7. package/dist/canvas.js.map +7 -0
  8. package/dist/charts.js +782 -782
  9. package/dist/{chunk-LH5TSOZW.js → chunk-6JSOVNID.js} +42 -2
  10. package/dist/{chunk-LH5TSOZW.js.map → chunk-6JSOVNID.js.map} +3 -3
  11. package/dist/{chunk-ELXVW542.js → chunk-6NG7YVBG.js} +3 -471
  12. package/dist/chunk-6NG7YVBG.js.map +7 -0
  13. package/dist/{chunk-F5FYDCOA.js → chunk-CNXP3SIN.js} +2373 -2373
  14. package/dist/{chunk-F5FYDCOA.js.map → chunk-CNXP3SIN.js.map} +7 -7
  15. package/dist/chunk-H4LT43RS.js +475 -0
  16. package/dist/chunk-H4LT43RS.js.map +7 -0
  17. package/dist/{chunk-WMGOJ3I6.js → chunk-KH2GJTKR.js} +3702 -2628
  18. package/dist/chunk-KH2GJTKR.js.map +7 -0
  19. package/dist/chunk-SN4LSOAR.js +532 -0
  20. package/dist/chunk-SN4LSOAR.js.map +7 -0
  21. package/dist/flexdesk.css +2962 -4
  22. package/dist/flow.js +10030 -0
  23. package/dist/flow.js.map +7 -0
  24. package/dist/tiles.js +2195 -2195
  25. package/dist/tokens.css +86 -0
  26. package/dist/widgets.js +5824 -5796
  27. package/dist/widgets.js.map +1 -1
  28. package/dist/wm.js +8077 -8074
  29. package/dist/wm.js.map +7 -7
  30. package/package.json +89 -81
  31. package/src/canvas/canvas_adapter.js +523 -0
  32. package/src/canvas/edge_router.js +392 -0
  33. package/src/canvas/graph/connector_router.js +189 -0
  34. package/src/canvas/graph/history_service.js +170 -0
  35. package/src/canvas/graph/node_platform.js +116 -0
  36. package/src/canvas/index.js +16 -0
  37. package/src/flow/canvas_editor/editor.js +1081 -0
  38. package/src/flow/canvas_editor/index.js +16 -0
  39. package/src/flow/canvas_editor/layout.js +118 -0
  40. package/src/flow/canvas_editor/strings.js +37 -0
  41. package/src/flow/kit/always_before.js +325 -0
  42. package/src/flow/kit/catalogue.js +170 -0
  43. package/src/flow/kit/chip_input.js +461 -0
  44. package/src/flow/kit/dom.js +205 -0
  45. package/src/flow/kit/findings.js +129 -0
  46. package/src/flow/kit/history.js +173 -0
  47. package/src/flow/kit/index.js +38 -0
  48. package/src/flow/kit/keys.js +127 -0
  49. package/src/flow/kit/logic_graph.js +210 -0
  50. package/src/flow/kit/references.js +199 -0
  51. package/src/flow/kit/settings_panel.js +357 -0
  52. package/src/flow/kit/settings_schema.js +175 -0
  53. package/src/flow/kit/step_picker.js +209 -0
  54. package/src/flow/kit/strings.js +102 -0
  55. package/src/flow/kit/value_picker.js +238 -0
  56. package/src/flow/kit/widgets.js +763 -0
  57. package/src/flow/lanes/editor.js +1469 -0
  58. package/src/flow/lanes/index.js +26 -0
  59. package/src/flow/lanes/layout.js +525 -0
  60. package/src/flow/lanes/pipeline.js +327 -0
  61. package/src/flow/lanes/preview.js +109 -0
  62. package/src/flow/lanes/strings.js +98 -0
  63. package/src/flow/outline/editor.js +1511 -0
  64. package/src/flow/outline/index.js +20 -0
  65. package/src/flow/outline/mapping.js +286 -0
  66. package/src/flow/outline/menu.js +154 -0
  67. package/src/flow/outline/operations.js +738 -0
  68. package/src/flow/outline/recognise.js +755 -0
  69. package/src/flow/outline/strings.js +135 -0
  70. package/src/tiling/landing_table.js +13 -5
  71. package/src/tiling/wm.js +3916 -3916
  72. package/src/ui/components/data_table.js +4205 -3294
  73. package/src/ui/components/row_activation.js +70 -0
  74. package/src/ui/components/table_values.js +423 -0
  75. package/dist/chunk-ELXVW542.js.map +0 -7
  76. package/dist/chunk-WMGOJ3I6.js.map +0 -7
package/css/base.css CHANGED
@@ -496,7 +496,9 @@
496
496
  .twm-preview-table th,
497
497
  .twm-preview-table td {
498
498
  border-bottom: 1px solid #2a2a2a;
499
- padding: var(--space-sm) 8px;
499
+ /* 0.5.0: the row-geometry tokens (tokens.css). Unset, these fall back to
500
+ * exactly the 0.4 padding. */
501
+ padding: var(--twm-dt-cell-pad-block, var(--space-sm)) var(--twm-dt-cell-pad-inline, 8px);
500
502
  white-space: nowrap;
501
503
  /* Never spill text past the column. Once columns are locked to fixed
502
504
  * widths, over-long content is clipped with an ellipsis; the full
@@ -598,6 +600,125 @@ body.twm-dt-col-resizing {
598
600
  .twm-preview-table:not(.twm-preview-table--readonly) tr:hover td {
599
601
  background: rgba(255, 255, 255, 0.04);
600
602
  }
603
+ /* ── 0.5.0 DataTable options. Each rule below matches only a class or an
604
+ * attribute a 0.5.0 option sets, so a table that asks for none of them is
605
+ * styled exactly as in 0.4. ───────────────────────────────────────────── */
606
+
607
+ /* The row-geometry tokens for the NORMAL density's line height. Compact
608
+ * declares its own on the cells (with the token in front), as 0.4 did; normal
609
+ * never declared one, so this one is NOT on the cells. It is on the ROW GROUPS,
610
+ * which only this component creates, and the cells inherit it. Unset, it
611
+ * computes to `unset` — inheritance from the table, which is exactly what no
612
+ * declaration gives. A declaration on the cells themselves, however weak
613
+ * (`:where()`), would beat any consumer rule for the cells that sits in a
614
+ * cascade LAYER (unlayered author styles outrank every layer, whatever their
615
+ * specificity) and any zero-specificity one loaded before this sheet; on the
616
+ * row groups, a consumer's rule for the cells, the rows or the table still
617
+ * wins, as it did in 0.4. */
618
+ :where(.twm-preview-table) > :where(thead, tbody, tfoot) {
619
+ line-height: var(--twm-dt-cell-line-height);
620
+ }
621
+ /* `firstColumn: 'plain'` — the first column is a column like the others, not
622
+ * the time column this component was built around (120–150px, grey, 500).
623
+ * One class more than both time rules, so the order of the two sheets cannot
624
+ * matter. The header keeps the header's weight and colour. */
625
+ .twm-preview-table.twm-dt--first-plain th:first-child,
626
+ .twm-preview-table.twm-dt--first-plain td:first-child {
627
+ width: auto;
628
+ min-width: 80px;
629
+ max-width: none;
630
+ }
631
+ .twm-preview-table.twm-dt--first-plain td:first-child {
632
+ font-weight: inherit;
633
+ color: inherit;
634
+ }
635
+ .twm-preview-table.twm-dt--first-plain th:first-child {
636
+ font-weight: 600;
637
+ color: #aaa;
638
+ }
639
+ /* `onRowActivate` / `clickable` — a row that opens looks like it: a pointer,
640
+ * and a hover even on a readonly table. Never over a selected row, whose
641
+ * colour has to survive the pointer (see the selection rule's note), and never
642
+ * over the empty or failed state's row, which opens nothing. */
643
+ .twm-preview-table.twm-dt--clickable tbody tr:not(.twm-dt-spacer):not(.data-table__empty-row) {
644
+ cursor: pointer;
645
+ }
646
+ .twm-preview-table.twm-dt--clickable tbody tr:not(.twm-dt-spacer):not(.data-table__empty-row):not(.selected):hover td {
647
+ background: var(--state-hover, rgba(255, 255, 255, 0.05));
648
+ }
649
+ /* `activeRow` — the row that is OPEN. A left edge, not a background: hover
650
+ * and selection keep theirs. */
651
+ .twm-preview-table tbody tr.twm-dt-row--active > td:first-child {
652
+ box-shadow: inset 2px 0 0 0 var(--accent-bright, #007acc);
653
+ }
654
+ /* `rowIcon` — drawn from `data-twm-icon` so the icon's NAME is not cell
655
+ * text (not in a copy, not in the clipped-cell tooltip). The span carries the
656
+ * icon font's class; the pseudo-element inherits its font and ligatures. Top
657
+ * aligned on a line height of 1, so it cannot make its row taller. */
658
+ .twm-preview-table td .twm-dt-row-icon {
659
+ display: inline-block;
660
+ font-size: 1.15em;
661
+ line-height: 1;
662
+ vertical-align: top;
663
+ margin-right: 4px;
664
+ opacity: 0.85;
665
+ }
666
+ .twm-preview-table td .twm-dt-row-icon::before {
667
+ content: attr(data-twm-icon);
668
+ }
669
+ .twm-preview-table td .twm-dt-row-icon--muted { color: var(--text-muted, #888); }
670
+ .twm-preview-table td .twm-dt-row-icon--info { color: var(--color-info, #2196f3); }
671
+ .twm-preview-table td .twm-dt-row-icon--success { color: var(--color-success, #3fb950); }
672
+ .twm-preview-table td .twm-dt-row-icon--warn { color: var(--color-warning, #ff9800); }
673
+ .twm-preview-table td .twm-dt-row-icon--danger { color: var(--color-danger, #c74e4e); }
674
+ /* THESE CELLS ARE OFTEN A ROW'S FIRST CELL, and the first cell is the time
675
+ * column's: `.twm-preview-table td:first-child` (0,2,1, grey and weight 500,
676
+ * declared twice, the second copy far below), `firstColumn: 'plain'` (0,3,1,
677
+ * `color: inherit`) and the compact density's cell padding (0,2,1, in
678
+ * overrides.css) all reach them. A rule of the same weight LOSES to whichever
679
+ * comes later — which drew a failure in an empty list grey, exactly like an
680
+ * empty state, and gave both 2px of padding under compact. So each rule below
681
+ * is (0,3,2) or more: the wrapper and `tbody` in front of the cell's class,
682
+ * which no first-column or density rule matches, and the order of the sheets
683
+ * cannot matter. */
684
+ /* `nullDisplay` — a NULL reads as one, not as the text "NULL". */
685
+ .twm-data-table-component .twm-preview-table tbody td.twm-dt-cell--null {
686
+ color: var(--text-dim, #666);
687
+ font-style: italic;
688
+ }
689
+ /* `emptyState` and `setError` with no rows: the box's own words, which may
690
+ * wrap — muted for an empty state, red for a failure, in both densities. Quiet
691
+ * while loading — an empty table that is still loading is not empty. */
692
+ .twm-data-table-component .twm-preview-table tbody td.twm-data-table__empty-cell.twm-data-table__empty-cell--state,
693
+ .twm-data-table-component .twm-preview-table tbody td.twm-data-table__empty-cell.twm-data-table__empty-cell--error {
694
+ text-align: center;
695
+ padding: 16px;
696
+ white-space: normal;
697
+ font-weight: normal;
698
+ color: var(--text-muted, #888);
699
+ }
700
+ .twm-data-table-component .twm-preview-table tbody td.twm-data-table__empty-cell.twm-data-table__empty-cell--error {
701
+ color: var(--color-danger, #c74e4e);
702
+ }
703
+ .twm-data-table-component--loading .twm-preview-table td.twm-data-table__empty-cell--state {
704
+ visibility: hidden;
705
+ }
706
+ /* `setError` with rows: a banner over the rows that are KEPT. */
707
+ .twm-data-table__error {
708
+ flex: 0 0 auto;
709
+ display: flex;
710
+ align-items: center;
711
+ gap: 6px;
712
+ padding: 4px 8px;
713
+ font-size: var(--font-size-sm, 12px);
714
+ color: var(--color-danger, #c74e4e);
715
+ background: rgba(199, 78, 78, 0.12);
716
+ border-bottom: 1px solid rgba(199, 78, 78, 0.4);
717
+ }
718
+ .twm-data-table__error .twm-data-table__error-icon {
719
+ font-size: 16px;
720
+ line-height: 1;
721
+ }
601
722
  /* Wizard mode: uniform column widths, no selection */
602
723
  .twm-preview-table-wrap--wizard .twm-preview-table {
603
724
  table-layout: auto;
@@ -1508,7 +1629,7 @@ body.twm-window-maximized .twm-resize-handle {
1508
1629
  }
1509
1630
  .twm-preview-table th, .twm-preview-table td {
1510
1631
  border-bottom: 1px solid #2a2a2a;
1511
- padding: var(--space-sm) 8px;
1632
+ padding: var(--twm-dt-cell-pad-block, var(--space-sm)) var(--twm-dt-cell-pad-inline, 8px);
1512
1633
  white-space: nowrap;
1513
1634
  }
1514
1635
  .twm-preview-table th {
@@ -4898,3 +5019,2838 @@ button.twm-about-dialog__btn--close:focus {
4898
5019
  .twm-autoscroll-bar--active .twm-autoscroll-thumb {
4899
5020
  background: rgba(255, 255, 255, 0.45);
4900
5021
  }
5022
+
5023
+
5024
+ /* ══ FLOW · KIT ═══════════════════════════════════════════════════════ */
5025
+ /* The shared flow-editor kit (36 §3, §3.12): the settings panel and its
5026
+ * fields, the generic widgets, reference chips and the chip input, the two
5027
+ * pickers and the findings strip. Every colour is a token (`tokens.css`'s
5028
+ * `--twm-flow-*` and the canonical ones); a category's TONE picks a pair.
5029
+ * Every class here is set by a module under src/flow/kit/, and every class
5030
+ * those modules set has a rule here — tests/flow_kit_css.test.mjs holds both
5031
+ * directions, because jsdom applies no stylesheet. */
5032
+
5033
+ /* `hidden` must win over the `display: flex` these blocks use. */
5034
+ .twm-flow-panel[hidden],
5035
+ .twm-flow-panel [hidden],
5036
+ .twm-flow-popover [hidden],
5037
+ .twm-flow-strip[hidden],
5038
+ .twm-flow-strip [hidden] {
5039
+ display: none !important;
5040
+ }
5041
+
5042
+ /* ── the settings panel ─────────────────────────────────────────────── */
5043
+ .twm-flow-panel {
5044
+ display: flex;
5045
+ flex-direction: column;
5046
+ gap: 14px;
5047
+ min-width: 0;
5048
+ box-sizing: border-box;
5049
+ padding: 16px 20px 28px;
5050
+ background: var(--surface-1);
5051
+ color: var(--text-body);
5052
+ font-family: var(--font-family-sans);
5053
+ font-size: var(--font-size-sm);
5054
+ line-height: 1.4;
5055
+ }
5056
+ .twm-flow-panel .twm-btn {
5057
+ min-height: 26px;
5058
+ padding: 0 9px;
5059
+ font-size: var(--font-size-sm);
5060
+ border-radius: 3px;
5061
+ }
5062
+ .twm-flow-panel__readonly {
5063
+ margin: 0;
5064
+ padding: 8px 10px;
5065
+ border-radius: var(--radius-sm);
5066
+ background: var(--twm-flow-warning-bg);
5067
+ border: 1px solid var(--twm-flow-warning-line);
5068
+ color: var(--twm-flow-warning-text);
5069
+ }
5070
+ .twm-flow-panel__head {
5071
+ display: flex;
5072
+ flex-wrap: wrap;
5073
+ gap: 12px;
5074
+ align-items: flex-start;
5075
+ }
5076
+ .twm-flow-panel__icon {
5077
+ flex: 0 0 34px;
5078
+ height: 34px;
5079
+ display: flex;
5080
+ align-items: center;
5081
+ justify-content: center;
5082
+ border-radius: 7px;
5083
+ }
5084
+ .twm-flow-panel__icon .material-symbols-outlined { font-size: 20px; }
5085
+ .twm-flow-panel__icon--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
5086
+ .twm-flow-panel__icon--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
5087
+ .twm-flow-panel__icon--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
5088
+ .twm-flow-panel__icon--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
5089
+ .twm-flow-panel__icon--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
5090
+ .twm-flow-panel__icon--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
5091
+ .twm-flow-panel__titles {
5092
+ flex: 1 1 240px;
5093
+ min-width: 0;
5094
+ display: flex;
5095
+ flex-direction: column;
5096
+ gap: 2px;
5097
+ }
5098
+ .twm-flow-panel__type {
5099
+ font-size: var(--font-size-xs);
5100
+ color: var(--twm-flow-muted);
5101
+ text-transform: uppercase;
5102
+ letter-spacing: .05em;
5103
+ }
5104
+ .twm-flow-panel__title {
5105
+ margin: 0;
5106
+ font-size: 17px;
5107
+ font-weight: var(--font-weight-semibold);
5108
+ color: var(--text-primary);
5109
+ overflow-wrap: anywhere;
5110
+ }
5111
+ .twm-flow-panel__title-input {
5112
+ box-sizing: border-box;
5113
+ width: 100%;
5114
+ margin-left: -5px;
5115
+ padding: 1px 4px;
5116
+ font: inherit;
5117
+ font-size: 17px;
5118
+ font-weight: var(--font-weight-semibold);
5119
+ color: var(--text-primary);
5120
+ background: transparent;
5121
+ border: 1px solid transparent;
5122
+ border-radius: 3px;
5123
+ user-select: text;
5124
+ }
5125
+ .twm-flow-panel__title-input:hover { border-color: var(--twm-flow-control-border); }
5126
+ .twm-flow-panel__title-input:focus {
5127
+ outline: none;
5128
+ border-color: var(--twm-flow-focus);
5129
+ background: var(--twm-flow-control-bg);
5130
+ }
5131
+ .twm-flow-panel__where { color: var(--twm-flow-muted); }
5132
+ .twm-flow-panel__actions {
5133
+ display: flex;
5134
+ flex-wrap: wrap;
5135
+ gap: 6px;
5136
+ align-items: flex-start;
5137
+ }
5138
+ .twm-flow-panel__action { white-space: nowrap; }
5139
+ .twm-flow-panel__action-wrap {
5140
+ display: inline-flex;
5141
+ flex-direction: column;
5142
+ gap: 2px;
5143
+ max-width: 240px;
5144
+ }
5145
+ .twm-flow-panel__refusal {
5146
+ font-size: var(--font-size-xs);
5147
+ color: var(--twm-flow-warning);
5148
+ }
5149
+ .twm-flow-panel__description { margin: 0; color: var(--text-secondary); }
5150
+ .twm-flow-panel__id {
5151
+ padding: 6px 9px;
5152
+ font-family: var(--font-family-mono);
5153
+ font-size: var(--font-size-xs);
5154
+ color: var(--text-secondary);
5155
+ background: var(--surface-0);
5156
+ border: 1px solid var(--border-default);
5157
+ border-radius: var(--radius-sm);
5158
+ overflow-wrap: anywhere;
5159
+ }
5160
+ .twm-flow-panel__findings {
5161
+ margin: 0;
5162
+ padding: 0;
5163
+ list-style: none;
5164
+ display: flex;
5165
+ flex-direction: column;
5166
+ gap: 4px;
5167
+ }
5168
+ .twm-flow-panel__finding {
5169
+ display: flex;
5170
+ gap: 6px;
5171
+ align-items: flex-start;
5172
+ color: var(--twm-flow-error);
5173
+ }
5174
+ .twm-flow-panel__finding--warning { color: var(--twm-flow-warning); }
5175
+ .twm-flow-panel__finding-icon.material-symbols-outlined { font-size: 15px; line-height: 18px; }
5176
+ .twm-flow-panel__finding-text { min-width: 0; overflow-wrap: anywhere; }
5177
+ .twm-flow-panel__slot {
5178
+ display: flex;
5179
+ flex-direction: column;
5180
+ gap: 8px;
5181
+ min-width: 0;
5182
+ }
5183
+ .twm-flow-panel__fields {
5184
+ display: flex;
5185
+ flex-direction: column;
5186
+ gap: 13px;
5187
+ }
5188
+ .twm-flow-panel__note {
5189
+ margin: 0;
5190
+ padding: 8px 10px;
5191
+ border-radius: var(--radius-sm);
5192
+ background: var(--state-hover);
5193
+ color: var(--text-secondary);
5194
+ }
5195
+ .twm-flow-panel__note--info { border-left: 2px solid var(--twm-flow-blue-line); }
5196
+ .twm-flow-panel__note--warning {
5197
+ background: var(--twm-flow-warning-bg);
5198
+ color: var(--twm-flow-warning-text);
5199
+ }
5200
+
5201
+ /* ── a field: its label, its control, its finding, its help ─────────── */
5202
+ .twm-flow-field {
5203
+ display: flex;
5204
+ flex-wrap: wrap;
5205
+ gap: 4px 16px;
5206
+ align-items: flex-start;
5207
+ min-width: 0;
5208
+ }
5209
+ .twm-flow-field__label {
5210
+ flex: 0 0 150px;
5211
+ min-width: 0;
5212
+ padding-top: 5px;
5213
+ color: var(--text-secondary);
5214
+ }
5215
+ .twm-flow-field__name { overflow-wrap: anywhere; }
5216
+ .twm-flow-field__required { color: var(--twm-flow-error); }
5217
+ .twm-flow-field__body {
5218
+ flex: 1 1 280px;
5219
+ min-width: 0;
5220
+ display: flex;
5221
+ flex-direction: column;
5222
+ gap: 5px;
5223
+ }
5224
+ .twm-flow-field__error {
5225
+ margin: 0;
5226
+ display: flex;
5227
+ gap: 5px;
5228
+ align-items: flex-start;
5229
+ color: var(--twm-flow-error);
5230
+ }
5231
+ .twm-flow-field__error-icon.material-symbols-outlined { font-size: 15px; line-height: 17px; }
5232
+ .twm-flow-field__error-text { min-width: 0; overflow-wrap: anywhere; }
5233
+ .twm-flow-field--warning .twm-flow-field__error { color: var(--twm-flow-warning); }
5234
+ .twm-flow-field--error > .twm-flow-field__body > .twm-flow-input,
5235
+ .twm-flow-field--error > .twm-flow-field__body > .twm-flow-refbox,
5236
+ .twm-flow-field--error > .twm-flow-field__body > .twm-flow-togglechips {
5237
+ border-color: var(--twm-flow-error);
5238
+ }
5239
+ .twm-flow-field__help {
5240
+ margin: 0;
5241
+ font-size: var(--font-size-xs);
5242
+ color: var(--twm-flow-muted);
5243
+ }
5244
+ .twm-flow-field__note {
5245
+ margin: 0;
5246
+ padding-top: 5px;
5247
+ font-size: var(--font-size-xs);
5248
+ color: var(--twm-flow-muted);
5249
+ }
5250
+ .twm-flow-field__kept {
5251
+ font-family: var(--font-family-mono);
5252
+ color: var(--text-secondary);
5253
+ }
5254
+ .twm-flow-field__refusal {
5255
+ margin: 0;
5256
+ padding: 6px 8px;
5257
+ border-radius: var(--radius-sm);
5258
+ background: var(--twm-flow-warning-bg);
5259
+ border: 1px solid var(--twm-flow-warning-line);
5260
+ color: var(--twm-flow-warning-text);
5261
+ }
5262
+ .twm-flow-field--group > .twm-flow-field__body { gap: 8px; }
5263
+ .twm-flow-field__group {
5264
+ display: flex;
5265
+ flex-direction: column;
5266
+ gap: 8px;
5267
+ min-width: 0;
5268
+ }
5269
+ .twm-flow-field__group > .twm-flow-field__summary {
5270
+ display: flex;
5271
+ align-items: center;
5272
+ gap: 6px;
5273
+ min-height: 26px;
5274
+ color: var(--text-secondary);
5275
+ cursor: pointer;
5276
+ list-style: none;
5277
+ }
5278
+ .twm-flow-field__group > .twm-flow-field__summary::-webkit-details-marker { display: none; }
5279
+ .twm-flow-field__group > .twm-flow-field__summary::before {
5280
+ content: '▸';
5281
+ flex: 0 0 auto;
5282
+ color: var(--twm-flow-muted);
5283
+ }
5284
+ .twm-flow-field__group[open] > .twm-flow-field__summary::before { content: '▾'; }
5285
+ .twm-flow-field__group > .twm-flow-field__summary:focus-visible {
5286
+ outline: 2px solid var(--twm-flow-focus);
5287
+ outline-offset: 1px;
5288
+ }
5289
+ .twm-flow-field__summary-text {
5290
+ min-width: 0;
5291
+ color: var(--twm-flow-muted);
5292
+ overflow-wrap: anywhere;
5293
+ }
5294
+ .twm-flow-field__group > .twm-flow-field > .twm-flow-field__label { flex-basis: 120px; }
5295
+ .twm-flow-field__rows {
5296
+ display: flex;
5297
+ flex-direction: column;
5298
+ gap: 5px;
5299
+ min-width: 0;
5300
+ }
5301
+ .twm-flow-field__row {
5302
+ display: flex;
5303
+ gap: 6px;
5304
+ align-items: center;
5305
+ min-width: 0;
5306
+ }
5307
+ .twm-flow-field__row > .twm-flow-input { flex: 0 0 34%; min-width: 0; }
5308
+ .twm-flow-field__row > .twm-flow-input--select { flex: 0 0 auto; width: auto; }
5309
+ .twm-flow-field__row > .twm-flow-refbox { flex: 1 1 auto; }
5310
+ .twm-flow-field__slot {
5311
+ display: flex;
5312
+ flex: 1 1 auto;
5313
+ min-width: 0;
5314
+ }
5315
+ .twm-flow-field__slot > .twm-flow-refbox { flex: 1 1 auto; }
5316
+ .twm-flow-field__add { align-self: flex-start; border-style: dashed; }
5317
+ .twm-flow-field__remove { flex: 0 0 26px; padding: 0; }
5318
+ .twm-flow-field__remove .twm-btn__glyph.material-symbols-outlined { font-size: 15px; }
5319
+
5320
+ /* ── controls ───────────────────────────────────────────────────────── */
5321
+ .twm-flow-input {
5322
+ box-sizing: border-box;
5323
+ width: 100%;
5324
+ min-width: 0;
5325
+ height: 26px;
5326
+ padding: 0 8px;
5327
+ font: inherit;
5328
+ font-size: var(--font-size-sm);
5329
+ color: var(--text-primary);
5330
+ background: var(--twm-flow-control-bg);
5331
+ border: 1px solid var(--twm-flow-control-border);
5332
+ border-radius: 3px;
5333
+ user-select: text;
5334
+ }
5335
+ .twm-flow-input:focus {
5336
+ outline: none;
5337
+ border-color: var(--twm-flow-focus);
5338
+ box-shadow: 0 0 0 1px var(--twm-flow-focus);
5339
+ }
5340
+ .twm-flow-input:disabled { opacity: 0.6; cursor: not-allowed; }
5341
+ .twm-flow-input--select { padding-right: 4px; cursor: pointer; }
5342
+ .twm-flow-input--area {
5343
+ height: auto;
5344
+ min-height: 52px;
5345
+ padding: 5px 8px;
5346
+ line-height: 1.4;
5347
+ resize: vertical;
5348
+ }
5349
+ .twm-flow-checkbox {
5350
+ margin: 6px 0 0;
5351
+ accent-color: var(--twm-flow-focus);
5352
+ }
5353
+
5354
+ /* ── a chip input, and the box with its Insert a value ──────────────── */
5355
+ .twm-flow-refbox {
5356
+ display: flex;
5357
+ align-items: flex-start;
5358
+ gap: 6px;
5359
+ min-width: 0;
5360
+ min-height: 26px;
5361
+ box-sizing: border-box;
5362
+ padding: 3px 4px 3px 8px;
5363
+ background: var(--twm-flow-control-bg);
5364
+ border: 1px solid var(--twm-flow-control-border);
5365
+ border-radius: 3px;
5366
+ }
5367
+ .twm-flow-refbox:focus-within {
5368
+ border-color: var(--twm-flow-focus);
5369
+ box-shadow: 0 0 0 1px var(--twm-flow-focus);
5370
+ }
5371
+ .twm-flow-refbox--mono { background: var(--surface-0); }
5372
+ .twm-flow-refbox__insert {
5373
+ flex: 0 0 auto;
5374
+ height: 20px;
5375
+ padding: 0 6px;
5376
+ font-family: var(--font-family-mono);
5377
+ font-size: var(--font-size-xs);
5378
+ color: var(--twm-flow-blue-fg);
5379
+ background: var(--surface-2);
5380
+ border: 1px solid var(--twm-flow-control-border);
5381
+ border-radius: 3px;
5382
+ cursor: pointer;
5383
+ }
5384
+ .twm-flow-refbox__insert:hover { border-color: var(--twm-flow-focus); }
5385
+ .twm-flow-refbox__insert:focus-visible {
5386
+ outline: 2px solid var(--twm-flow-focus);
5387
+ outline-offset: 1px;
5388
+ }
5389
+ .twm-flow-chipinput {
5390
+ position: relative;
5391
+ flex: 1 1 auto;
5392
+ min-width: 0;
5393
+ min-height: 18px;
5394
+ line-height: 18px;
5395
+ color: var(--text-primary);
5396
+ white-space: pre-wrap;
5397
+ overflow-wrap: anywhere;
5398
+ outline: none;
5399
+ cursor: text;
5400
+ -webkit-user-select: text;
5401
+ user-select: text;
5402
+ }
5403
+ .twm-flow-chipinput--mono {
5404
+ font-family: var(--font-family-mono);
5405
+ font-size: var(--font-size-sm);
5406
+ line-height: 21px;
5407
+ }
5408
+ .twm-flow-chipinput--multiline { min-height: 36px; }
5409
+ .twm-flow-chipinput--empty::before {
5410
+ content: attr(data-placeholder);
5411
+ position: absolute;
5412
+ left: 0;
5413
+ top: 0;
5414
+ color: var(--text-muted);
5415
+ pointer-events: none;
5416
+ }
5417
+ .twm-flow-chipinput[contenteditable="false"] { cursor: default; }
5418
+ .twm-flow-chip {
5419
+ display: inline-flex;
5420
+ align-items: center;
5421
+ height: 18px;
5422
+ padding: 0 6px;
5423
+ margin: 0 1px;
5424
+ box-sizing: border-box;
5425
+ border: 1px solid transparent;
5426
+ border-radius: 3px;
5427
+ font-family: var(--font-family-sans);
5428
+ font-size: var(--font-size-xs);
5429
+ line-height: 16px;
5430
+ white-space: nowrap;
5431
+ vertical-align: baseline;
5432
+ cursor: default;
5433
+ }
5434
+ .twm-flow-chip--violet { background: var(--twm-flow-violet-bg); border-color: var(--twm-flow-violet-line); color: var(--twm-flow-violet-fg); }
5435
+ .twm-flow-chip--teal { background: var(--twm-flow-teal-bg); border-color: var(--twm-flow-teal-line); color: var(--twm-flow-teal-fg); }
5436
+ .twm-flow-chip--amber { background: var(--twm-flow-amber-bg); border-color: var(--twm-flow-amber-line); color: var(--twm-flow-amber-fg); }
5437
+ .twm-flow-chip--grey { background: var(--twm-flow-grey-bg); border-color: var(--twm-flow-grey-line); color: var(--twm-flow-grey-fg); }
5438
+ .twm-flow-chip--blue { background: var(--twm-flow-blue-bg); border-color: var(--twm-flow-blue-line); color: var(--twm-flow-blue-fg); }
5439
+ .twm-flow-chip--indigo { background: var(--twm-flow-indigo-bg); border-color: var(--twm-flow-indigo-line); color: var(--twm-flow-indigo-fg); }
5440
+ .twm-flow-chip.twm-flow-chip--unknown {
5441
+ border-style: dashed;
5442
+ border-color: var(--twm-flow-error);
5443
+ color: var(--twm-flow-error);
5444
+ }
5445
+
5446
+ /* ── chips that toggle: enum-chips, upstream-columns ────────────────── */
5447
+ .twm-flow-togglechips {
5448
+ display: flex;
5449
+ flex-wrap: wrap;
5450
+ gap: 4px;
5451
+ align-items: center;
5452
+ min-height: 26px;
5453
+ box-sizing: border-box;
5454
+ padding: 3px 6px;
5455
+ background: var(--twm-flow-control-bg);
5456
+ border: 1px solid var(--twm-flow-control-border);
5457
+ border-radius: 3px;
5458
+ }
5459
+ .twm-flow-togglechip {
5460
+ height: 18px;
5461
+ padding: 0 8px;
5462
+ font: inherit;
5463
+ font-size: var(--font-size-xs);
5464
+ color: var(--twm-flow-muted);
5465
+ background: transparent;
5466
+ border: 1px solid var(--border-strong);
5467
+ border-radius: 9px;
5468
+ cursor: pointer;
5469
+ }
5470
+ .twm-flow-togglechip[aria-pressed="true"] {
5471
+ color: var(--text-primary);
5472
+ background: var(--surface-3);
5473
+ border-color: var(--surface-3);
5474
+ }
5475
+ .twm-flow-togglechip.twm-flow-togglechip--missing {
5476
+ border-style: dashed;
5477
+ border-color: var(--twm-flow-warning);
5478
+ color: var(--twm-flow-warning);
5479
+ }
5480
+ .twm-flow-togglechip:disabled { cursor: default; opacity: 0.7; }
5481
+ .twm-flow-togglechip:focus-visible {
5482
+ outline: 2px solid var(--twm-flow-focus);
5483
+ outline-offset: 1px;
5484
+ }
5485
+
5486
+ /* ── choice-cards ───────────────────────────────────────────────────── */
5487
+ .twm-flow-choices {
5488
+ display: flex;
5489
+ flex-direction: column;
5490
+ gap: 6px;
5491
+ padding-top: 4px;
5492
+ }
5493
+ .twm-flow-choice {
5494
+ display: flex;
5495
+ align-items: flex-start;
5496
+ gap: 8px;
5497
+ color: var(--text-primary);
5498
+ cursor: pointer;
5499
+ }
5500
+ .twm-flow-choice__radio {
5501
+ flex: 0 0 auto;
5502
+ margin: 2px 0 0;
5503
+ accent-color: var(--twm-flow-focus);
5504
+ }
5505
+ .twm-flow-choice__words {
5506
+ display: flex;
5507
+ flex-direction: column;
5508
+ gap: 1px;
5509
+ min-width: 0;
5510
+ }
5511
+ .twm-flow-choice__label { overflow-wrap: anywhere; }
5512
+ .twm-flow-choice__sub {
5513
+ font-size: var(--font-size-xs);
5514
+ color: var(--twm-flow-muted);
5515
+ }
5516
+
5517
+ /* ── the popover both pickers are drawn in ──────────────────────────── */
5518
+ .twm-flow-popover {
5519
+ position: fixed;
5520
+ z-index: var(--z-popover);
5521
+ display: flex;
5522
+ flex-direction: column;
5523
+ box-sizing: border-box;
5524
+ max-width: calc(100vw - 16px);
5525
+ max-height: calc(100vh - 16px);
5526
+ background: var(--surface-1);
5527
+ color: var(--text-body);
5528
+ border: 1px solid var(--twm-flow-control-border);
5529
+ border-radius: var(--radius-md);
5530
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
5531
+ font-family: var(--font-family-sans);
5532
+ font-size: var(--font-size-sm);
5533
+ line-height: 1.4;
5534
+ outline: none;
5535
+ }
5536
+ .twm-flow-popover--picker { width: 420px; }
5537
+ .twm-flow-popover--values { width: 430px; }
5538
+
5539
+ /* ── the step picker ────────────────────────────────────────────────── */
5540
+ .twm-flow-picker {
5541
+ display: flex;
5542
+ flex-direction: column;
5543
+ flex: 1 1 auto;
5544
+ min-height: 0;
5545
+ }
5546
+ .twm-flow-picker__head {
5547
+ display: flex;
5548
+ flex-direction: column;
5549
+ gap: 2px;
5550
+ padding: 12px 14px 8px;
5551
+ }
5552
+ .twm-flow-picker__title {
5553
+ font-size: var(--font-size-md);
5554
+ font-weight: var(--font-weight-semibold);
5555
+ color: var(--text-primary);
5556
+ }
5557
+ .twm-flow-picker__where { color: var(--twm-flow-muted); }
5558
+ .twm-flow-picker__search,
5559
+ .twm-flow-values__search {
5560
+ display: flex;
5561
+ align-items: center;
5562
+ gap: 6px;
5563
+ height: 28px;
5564
+ box-sizing: border-box;
5565
+ padding: 0 8px;
5566
+ background: var(--surface-0);
5567
+ border: 1px solid var(--twm-flow-control-border);
5568
+ border-radius: 3px;
5569
+ }
5570
+ .twm-flow-picker__search { margin: 0 14px 8px; }
5571
+ .twm-flow-picker__search:focus-within,
5572
+ .twm-flow-values__search:focus-within { border-color: var(--twm-flow-focus); }
5573
+ .twm-flow-picker__search-icon.material-symbols-outlined,
5574
+ .twm-flow-values__search-icon.material-symbols-outlined {
5575
+ font-size: 15px;
5576
+ color: var(--twm-flow-muted);
5577
+ }
5578
+ .twm-flow-picker__input,
5579
+ .twm-flow-values__input {
5580
+ flex: 1 1 auto;
5581
+ min-width: 0;
5582
+ height: 24px;
5583
+ padding: 0;
5584
+ font: inherit;
5585
+ color: var(--text-primary);
5586
+ background: transparent;
5587
+ border: 0;
5588
+ outline: none;
5589
+ user-select: text;
5590
+ }
5591
+ .twm-flow-picker__list {
5592
+ display: flex;
5593
+ flex-direction: column;
5594
+ flex: 1 1 auto;
5595
+ min-height: 0;
5596
+ overflow-y: auto;
5597
+ padding: 0 6px 6px;
5598
+ }
5599
+ .twm-flow-picker__group { display: flex; flex-direction: column; }
5600
+ .twm-flow-picker__group-label {
5601
+ padding: 6px 8px 3px;
5602
+ font-size: 10px;
5603
+ font-weight: var(--font-weight-semibold);
5604
+ letter-spacing: .08em;
5605
+ text-transform: uppercase;
5606
+ color: var(--twm-flow-muted);
5607
+ }
5608
+ .twm-flow-picker__items { display: flex; flex-direction: column; }
5609
+ .twm-flow-picker__items--grid {
5610
+ display: grid;
5611
+ grid-template-columns: repeat(2, minmax(0, 1fr));
5612
+ gap: 0 4px;
5613
+ }
5614
+ .twm-flow-picker__option {
5615
+ display: flex;
5616
+ align-items: center;
5617
+ gap: 10px;
5618
+ padding: 5px 8px;
5619
+ border-radius: var(--radius-sm);
5620
+ color: var(--text-primary);
5621
+ cursor: pointer;
5622
+ }
5623
+ .twm-flow-picker__option:hover { background: var(--state-hover); }
5624
+ .twm-flow-picker__option.twm-flow-picker__option--active { background: var(--state-selected); }
5625
+ .twm-flow-picker__option.twm-flow-picker__option--refused { cursor: not-allowed; }
5626
+ .twm-flow-picker__option--refused .twm-flow-picker__label { color: var(--twm-flow-muted); }
5627
+ .twm-flow-picker__option--refused .twm-flow-picker__chip { opacity: 0.5; }
5628
+ .twm-flow-picker__chip {
5629
+ flex: 0 0 22px;
5630
+ height: 22px;
5631
+ display: flex;
5632
+ align-items: center;
5633
+ justify-content: center;
5634
+ border-radius: 5px;
5635
+ }
5636
+ .twm-flow-picker__chip .material-symbols-outlined { font-size: 15px; }
5637
+ .twm-flow-picker__chip--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
5638
+ .twm-flow-picker__chip--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
5639
+ .twm-flow-picker__chip--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
5640
+ .twm-flow-picker__chip--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
5641
+ .twm-flow-picker__chip--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
5642
+ .twm-flow-picker__chip--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
5643
+ .twm-flow-picker__words {
5644
+ display: flex;
5645
+ flex-direction: column;
5646
+ min-width: 0;
5647
+ }
5648
+ .twm-flow-picker__label { overflow-wrap: anywhere; }
5649
+ .twm-flow-picker__sub,
5650
+ .twm-flow-picker__description {
5651
+ font-size: var(--font-size-xs);
5652
+ color: var(--twm-flow-muted);
5653
+ }
5654
+ .twm-flow-picker__refusal {
5655
+ font-size: var(--font-size-xs);
5656
+ color: var(--twm-flow-warning);
5657
+ }
5658
+ .twm-flow-picker__empty {
5659
+ margin: 0;
5660
+ padding: 4px 14px 10px;
5661
+ color: var(--twm-flow-muted);
5662
+ }
5663
+ .twm-flow-picker__foot {
5664
+ display: flex;
5665
+ flex-wrap: wrap;
5666
+ align-items: center;
5667
+ gap: 6px 14px;
5668
+ padding: 8px 14px;
5669
+ border-top: 1px solid var(--border-strong);
5670
+ font-size: var(--font-size-xs);
5671
+ color: var(--twm-flow-muted);
5672
+ }
5673
+ .twm-flow-picker__keys { flex: 1 1 auto; }
5674
+ .twm-flow-picker__paste {
5675
+ padding: 0;
5676
+ font: inherit;
5677
+ font-size: var(--font-size-xs);
5678
+ color: var(--twm-flow-blue-fg);
5679
+ background: transparent;
5680
+ border: 0;
5681
+ cursor: pointer;
5682
+ }
5683
+ .twm-flow-picker__paste:hover { text-decoration: underline; }
5684
+ .twm-flow-picker__paste:focus-visible {
5685
+ outline: 2px solid var(--twm-flow-focus);
5686
+ outline-offset: 1px;
5687
+ }
5688
+
5689
+ /* ── Insert a value ─────────────────────────────────────────────────── */
5690
+ .twm-flow-values {
5691
+ display: flex;
5692
+ flex-direction: column;
5693
+ flex: 1 1 auto;
5694
+ min-height: 0;
5695
+ }
5696
+ .twm-flow-values__head {
5697
+ display: flex;
5698
+ flex-direction: column;
5699
+ gap: 8px;
5700
+ padding: 12px 14px 8px;
5701
+ }
5702
+ .twm-flow-values__title {
5703
+ font-size: var(--font-size-md);
5704
+ font-weight: var(--font-weight-semibold);
5705
+ color: var(--text-primary);
5706
+ }
5707
+ .twm-flow-values__crumb {
5708
+ display: flex;
5709
+ align-items: center;
5710
+ gap: 8px;
5711
+ padding: 0 14px 6px;
5712
+ }
5713
+ .twm-flow-values__back {
5714
+ display: inline-flex;
5715
+ align-items: center;
5716
+ gap: 2px;
5717
+ height: 22px;
5718
+ padding: 0 6px 0 2px;
5719
+ font: inherit;
5720
+ color: var(--text-secondary);
5721
+ background: transparent;
5722
+ border: 1px solid var(--twm-flow-control-border);
5723
+ border-radius: 3px;
5724
+ cursor: pointer;
5725
+ }
5726
+ .twm-flow-values__back .material-symbols-outlined { font-size: 16px; }
5727
+ .twm-flow-values__back:focus-visible {
5728
+ outline: 2px solid var(--twm-flow-focus);
5729
+ outline-offset: 1px;
5730
+ }
5731
+ .twm-flow-values__path { color: var(--twm-flow-muted); }
5732
+ .twm-flow-values__list {
5733
+ display: flex;
5734
+ flex-direction: column;
5735
+ flex: 1 1 auto;
5736
+ min-height: 0;
5737
+ overflow-y: auto;
5738
+ padding: 0 6px 6px;
5739
+ }
5740
+ .twm-flow-values__group { display: flex; flex-direction: column; }
5741
+ .twm-flow-values__group-label {
5742
+ display: flex;
5743
+ flex-wrap: wrap;
5744
+ align-items: baseline;
5745
+ gap: 6px;
5746
+ padding: 8px 8px 3px;
5747
+ }
5748
+ .twm-flow-values__group-name {
5749
+ font-size: 10px;
5750
+ font-weight: var(--font-weight-semibold);
5751
+ letter-spacing: .08em;
5752
+ text-transform: uppercase;
5753
+ color: var(--twm-flow-muted);
5754
+ }
5755
+ .twm-flow-values__group-sub,
5756
+ .twm-flow-values__group-empty {
5757
+ font-size: var(--font-size-xs);
5758
+ color: var(--twm-flow-muted);
5759
+ }
5760
+ .twm-flow-values__grid {
5761
+ display: grid;
5762
+ grid-template-columns: repeat(2, minmax(0, 1fr));
5763
+ gap: 0 4px;
5764
+ }
5765
+ .twm-flow-values__chips {
5766
+ display: flex;
5767
+ flex-wrap: wrap;
5768
+ gap: 4px;
5769
+ padding: 2px 8px;
5770
+ }
5771
+ .twm-flow-values__option {
5772
+ color: var(--text-primary);
5773
+ cursor: pointer;
5774
+ }
5775
+ .twm-flow-values__option--row {
5776
+ display: flex;
5777
+ justify-content: space-between;
5778
+ gap: 8px;
5779
+ padding: 4px 8px;
5780
+ border-radius: var(--radius-sm);
5781
+ }
5782
+ .twm-flow-values__option--chip {
5783
+ display: inline-flex;
5784
+ align-items: center;
5785
+ height: 22px;
5786
+ box-sizing: border-box;
5787
+ padding: 0 8px;
5788
+ border: 1px solid var(--border-strong);
5789
+ border-radius: 11px;
5790
+ }
5791
+ .twm-flow-values__option:hover { background: var(--state-hover); }
5792
+ .twm-flow-values__option.twm-flow-values__option--active {
5793
+ background: var(--state-selected);
5794
+ box-shadow: inset 0 0 0 1px var(--twm-flow-focus);
5795
+ }
5796
+ .twm-flow-values__label { min-width: 0; overflow-wrap: anywhere; }
5797
+ .twm-flow-values__type {
5798
+ flex: 0 0 auto;
5799
+ font-size: var(--font-size-xs);
5800
+ color: var(--twm-flow-muted);
5801
+ }
5802
+ .twm-flow-values__empty {
5803
+ margin: 0;
5804
+ padding: 8px;
5805
+ color: var(--twm-flow-muted);
5806
+ }
5807
+ .twm-flow-values__foot {
5808
+ display: flex;
5809
+ flex-direction: column;
5810
+ gap: 3px;
5811
+ padding: 8px 14px 10px;
5812
+ border-top: 1px solid var(--border-strong);
5813
+ font-size: var(--font-size-xs);
5814
+ color: var(--twm-flow-muted);
5815
+ }
5816
+ .twm-flow-values__note { overflow-wrap: anywhere; }
5817
+ .twm-flow-values__inserts {
5818
+ min-height: 15px;
5819
+ overflow-wrap: anywhere;
5820
+ }
5821
+
5822
+ /* ── the findings strip ─────────────────────────────────────────────── */
5823
+ .twm-flow-strip {
5824
+ display: flex;
5825
+ flex-direction: column;
5826
+ gap: 4px;
5827
+ padding: 6px 12px;
5828
+ background: var(--twm-flow-error-bg);
5829
+ border-bottom: 1px solid var(--twm-flow-error-line);
5830
+ color: var(--twm-flow-error-text);
5831
+ font-size: var(--font-size-sm);
5832
+ }
5833
+ .twm-flow-strip.twm-flow-strip--warning {
5834
+ background: var(--twm-flow-warning-bg);
5835
+ border-bottom-color: var(--twm-flow-warning-line);
5836
+ color: var(--twm-flow-warning-text);
5837
+ }
5838
+ .twm-flow-strip__head {
5839
+ display: flex;
5840
+ align-items: center;
5841
+ gap: 8px;
5842
+ }
5843
+ .twm-flow-strip__icon.material-symbols-outlined { font-size: 16px; }
5844
+ .twm-flow-strip__title { font-weight: var(--font-weight-semibold); }
5845
+ .twm-flow-strip__list {
5846
+ margin: 0;
5847
+ padding: 0 0 0 24px;
5848
+ list-style: none;
5849
+ display: flex;
5850
+ flex-direction: column;
5851
+ gap: 2px;
5852
+ }
5853
+ .twm-flow-strip__line {
5854
+ display: flex;
5855
+ flex-wrap: wrap;
5856
+ align-items: center;
5857
+ gap: 4px 8px;
5858
+ }
5859
+ .twm-flow-strip__line--warning { color: var(--twm-flow-warning); }
5860
+ .twm-flow-strip__text { min-width: 0; overflow-wrap: anywhere; }
5861
+ .twm-flow-strip .twm-flow-strip__go {
5862
+ min-height: 22px;
5863
+ padding: 0 8px;
5864
+ color: inherit;
5865
+ background: transparent;
5866
+ border-color: var(--twm-flow-error-line);
5867
+ border-radius: 3px;
5868
+ }
5869
+ /* ══ end FLOW · KIT ══ */
5870
+
5871
+
5872
+ /* ══ FLOW · CANVAS ════════════════════════════════════════════════════ */
5873
+ /* Owned by the canvas agent (B) (36 §2): the canvas kernel (twm-canvas,
5874
+ * twm-edge) and the canvas editor (twm-flow-graph). Every class here is set by
5875
+ * a module under src/canvas/ or src/flow/canvas_editor/, and every class those
5876
+ * modules set has a rule here — tests/flow_canvas_css.test.mjs holds both
5877
+ * directions, and holds the node box (208 × 34 + 22 a row) to the editor's
5878
+ * CANVAS_NODE, because the edges are anchored by arithmetic, not measured. */
5879
+
5880
+ /* ── the kernel: the surface ────────────────────────────────────────── */
5881
+ /* The ground is SEVEN background layers, in this order, because
5882
+ * `CanvasAdapter._apply` writes seven sizes and positions: 1. a grain, 2. a
5883
+ * soft light from the upper left, 3–4. a coarse rule every fifth cell, 5–6. a
5884
+ * fine grid — the unit a drag snaps to — and 7. under it all, a gradient. Only
5885
+ * the four GRID layers follow the pan and the zoom. An embedder restyling the
5886
+ * ground keeps seven layers, or the browser cycles a short list and layer 5
5887
+ * takes layer 1's size. */
5888
+ .twm-canvas {
5889
+ position: absolute;
5890
+ inset: 0;
5891
+ overflow: hidden;
5892
+ cursor: default;
5893
+ outline: none;
5894
+ background-color: var(--surface-0);
5895
+ background-image:
5896
+ 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"),
5897
+ radial-gradient(120% 90% at 22% 0%, rgba(255, 255, 255, 0.055) 0%, rgba(255, 255, 255, 0) 55%),
5898
+ linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
5899
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
5900
+ linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
5901
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
5902
+ linear-gradient(160deg, #2b2e33 0%, #212327 55%, #1b1d20 100%);
5903
+ background-blend-mode: overlay, screen, normal, normal, normal, normal, normal;
5904
+ box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.55), inset 0 0 120px rgba(0, 0, 0, 0.35);
5905
+ }
5906
+ .twm-canvas:focus-visible {
5907
+ box-shadow: inset 0 0 0 1px var(--twm-flow-focus), inset 0 0 120px rgba(0, 0, 0, 0.35);
5908
+ }
5909
+ .twm-canvas__surface { position: absolute; transform-origin: 0 0; }
5910
+ /* The edge layer takes no pointer: a line that wants one (a hit path) opts
5911
+ * back in with `pointer-events: stroke`. */
5912
+ .twm-canvas__edges { position: absolute; overflow: visible; pointer-events: none; }
5913
+ .twm-canvas__nodes { position: absolute; }
5914
+ .twm-canvas__marquee {
5915
+ position: absolute;
5916
+ pointer-events: none;
5917
+ border: 1px solid var(--accent-bright);
5918
+ background: rgba(0, 122, 204, 0.12);
5919
+ }
5920
+ .twm-canvas__marquee[hidden] { display: none; }
5921
+
5922
+ /* ── the kernel: a crow's foot ──────────────────────────────────────── */
5923
+ .twm-edge__marker line { stroke: #5a7f96; stroke-width: 1.4; }
5924
+ .twm-edge__marker circle { fill: none; stroke: #5a7f96; stroke-width: 1.4; }
5925
+
5926
+ /* ── the canvas editor ──────────────────────────────────────────────── */
5927
+ .twm-flow-graph [hidden] { display: none !important; }
5928
+
5929
+ /* The editor fills its host: a flex column in any parent that gives it a
5930
+ * height. `container-type: inline-size` is for the narrow layouts below, and
5931
+ * safe here: the editor's width comes from its parent, never its contents. */
5932
+ .twm-flow-graph {
5933
+ flex: 1 1 auto;
5934
+ height: 100%;
5935
+ min-height: 0;
5936
+ min-width: 0;
5937
+ display: flex;
5938
+ flex-direction: column;
5939
+ box-sizing: border-box;
5940
+ background: var(--surface-0);
5941
+ color: var(--text-body);
5942
+ font-family: var(--font-family-sans);
5943
+ font-size: var(--font-size-sm);
5944
+ container-type: inline-size;
5945
+ container-name: twm-flow-graph;
5946
+ }
5947
+ .twm-flow-graph__toolbar {
5948
+ display: flex;
5949
+ flex-wrap: wrap;
5950
+ align-items: center;
5951
+ gap: 6px;
5952
+ padding: 6px 8px;
5953
+ background: var(--surface-1);
5954
+ border-bottom: 1px solid var(--border-default);
5955
+ }
5956
+ .twm-flow-graph .twm-flow-graph__tool {
5957
+ min-height: 26px;
5958
+ padding: 0 9px;
5959
+ font-size: var(--font-size-sm);
5960
+ border-radius: 3px;
5961
+ }
5962
+ .twm-flow-graph__tool .twm-btn__glyph.material-symbols-outlined { font-size: 16px; }
5963
+ .twm-flow-graph__tool--busy { cursor: progress; }
5964
+ .twm-flow-graph__status {
5965
+ margin-left: auto;
5966
+ color: var(--twm-flow-muted);
5967
+ font-size: var(--font-size-xs);
5968
+ }
5969
+ .twm-flow-graph__toolbar-end { display: inline-flex; align-items: center; gap: 6px; }
5970
+ .twm-flow-graph__toolbar-end:empty { display: none; }
5971
+ .twm-flow-graph__why,
5972
+ .twm-flow-graph__message,
5973
+ .twm-flow-graph__readonly,
5974
+ .twm-flow-graph__banner {
5975
+ margin: 0;
5976
+ padding: 4px 10px;
5977
+ font-size: var(--font-size-xs);
5978
+ line-height: 1.4;
5979
+ }
5980
+ .twm-flow-graph__why { color: var(--twm-flow-muted); border-bottom: 1px solid var(--border-subtle); }
5981
+ .twm-flow-graph__message:empty { display: none; }
5982
+ .twm-flow-graph__message--warning { color: var(--twm-flow-warning); }
5983
+ .twm-flow-graph__message--ok { color: var(--twm-flow-ok); }
5984
+ .twm-flow-graph__readonly {
5985
+ background: var(--twm-flow-warning-bg);
5986
+ color: var(--twm-flow-warning-text);
5987
+ border-bottom: 1px solid var(--twm-flow-warning-line);
5988
+ }
5989
+ .twm-flow-graph__banner {
5990
+ background: var(--twm-flow-blue-bg);
5991
+ color: var(--twm-flow-blue-fg);
5992
+ border-bottom: 1px solid var(--twm-flow-blue-line);
5993
+ }
5994
+
5995
+ /* Three columns; the CANVAS is the one that flexes — `flex: 1 1 0px` AND
5996
+ * `min-width: 0`, or an open settings panel squeezes the palette instead. */
5997
+ .twm-flow-graph__body { flex: 1 1 0px; min-height: 0; display: flex; flex-direction: row; }
5998
+ .twm-flow-graph__palette {
5999
+ flex: 0 0 176px;
6000
+ min-width: 0;
6001
+ overflow-y: auto;
6002
+ box-sizing: border-box;
6003
+ padding: 8px;
6004
+ display: flex;
6005
+ flex-direction: column;
6006
+ gap: 2px;
6007
+ background: var(--surface-1);
6008
+ border-right: 1px solid var(--border-default);
6009
+ }
6010
+ .twm-flow-graph__palette-title { margin: 2px 0 6px; font-size: var(--font-size-sm); font-weight: 600; }
6011
+ .twm-flow-graph__palette-group {
6012
+ margin: 10px 0 2px;
6013
+ font-size: var(--font-size-xs);
6014
+ font-weight: 600;
6015
+ letter-spacing: 0.06em;
6016
+ text-transform: uppercase;
6017
+ color: var(--twm-flow-muted);
6018
+ }
6019
+ /* A press must not select the label's text, and a touch press must not pan the
6020
+ * page instead of dragging. */
6021
+ .twm-flow-graph__palette-item {
6022
+ display: flex;
6023
+ align-items: center;
6024
+ gap: 6px;
6025
+ width: 100%;
6026
+ min-height: 26px;
6027
+ padding: 3px 6px;
6028
+ text-align: left;
6029
+ background: none;
6030
+ border: 1px solid transparent;
6031
+ border-radius: 3px;
6032
+ color: inherit;
6033
+ font: inherit;
6034
+ cursor: pointer;
6035
+ user-select: none;
6036
+ touch-action: none;
6037
+ }
6038
+ .twm-flow-graph__palette-item:hover:not(:disabled) { background: var(--state-hover); border-color: var(--border-default); }
6039
+ .twm-flow-graph__palette-item:focus-visible { outline: none; border-color: var(--twm-flow-focus); }
6040
+ .twm-flow-graph__palette-item:disabled { opacity: 0.45; cursor: not-allowed; }
6041
+ .twm-flow-graph__palette-icon {
6042
+ flex: 0 0 20px;
6043
+ height: 20px;
6044
+ display: inline-flex;
6045
+ align-items: center;
6046
+ justify-content: center;
6047
+ border-radius: 4px;
6048
+ }
6049
+ .twm-flow-graph__palette-icon .material-symbols-outlined,
6050
+ .twm-flow-graph__node-icon .material-symbols-outlined { font-size: 15px; }
6051
+ .twm-flow-graph__palette-icon--violet, .twm-flow-graph__node-icon--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
6052
+ .twm-flow-graph__palette-icon--teal, .twm-flow-graph__node-icon--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
6053
+ .twm-flow-graph__palette-icon--amber, .twm-flow-graph__node-icon--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
6054
+ .twm-flow-graph__palette-icon--grey, .twm-flow-graph__node-icon--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
6055
+ .twm-flow-graph__palette-icon--blue, .twm-flow-graph__node-icon--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
6056
+ .twm-flow-graph__palette-icon--indigo, .twm-flow-graph__node-icon--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
6057
+ .twm-flow-graph__palette-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6058
+ .twm-flow-graph__palette-why {
6059
+ margin: 0 0 4px 32px;
6060
+ font-size: var(--font-size-xs);
6061
+ color: var(--twm-flow-muted);
6062
+ }
6063
+ .twm-flow-graph__canvas { position: relative; flex: 1 1 0px; min-width: 0; min-height: 0; }
6064
+ .twm-flow-graph__canvas--drop { outline: 2px dashed var(--twm-flow-focus); outline-offset: -2px; }
6065
+ .twm-flow-graph__aside {
6066
+ flex: 0 0 300px;
6067
+ min-width: 0;
6068
+ min-height: 0;
6069
+ overflow-y: auto;
6070
+ background: var(--surface-1);
6071
+ border-left: 1px solid var(--border-default);
6072
+ }
6073
+ .twm-flow-graph__connection {
6074
+ display: flex;
6075
+ flex-direction: column;
6076
+ align-items: flex-start;
6077
+ gap: 8px;
6078
+ padding: 16px 20px;
6079
+ }
6080
+ .twm-flow-graph__connection-title { margin: 0; font-size: var(--font-size-md); font-weight: 600; }
6081
+ .twm-flow-graph__connection-line { margin: 0; color: var(--twm-flow-muted); overflow-wrap: anywhere; }
6082
+ .twm-flow-graph .twm-flow-graph__connection-remove { min-height: 26px; padding: 0 9px; font-size: var(--font-size-sm); }
6083
+
6084
+ /* A narrow editor: under 900px the side columns take less, and under 740px the
6085
+ * canvas takes the whole width on top with the palette and the settings side
6086
+ * by side under it — a container query, on the editor's own width. */
6087
+ @container twm-flow-graph (max-width: 900px) {
6088
+ .twm-flow-graph__palette { flex: 0 0 150px; }
6089
+ .twm-flow-graph__aside { flex: 0 0 232px; }
6090
+ }
6091
+ @container twm-flow-graph (max-width: 740px) {
6092
+ .twm-flow-graph__body {
6093
+ display: grid;
6094
+ grid-template-columns: minmax(132px, 2fr) minmax(0, 3fr);
6095
+ grid-template-rows: minmax(220px, 11fr) minmax(0, 9fr);
6096
+ }
6097
+ .twm-flow-graph__canvas { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
6098
+ .twm-flow-graph__palette { grid-column: 1; grid-row: 2; min-height: 0; border-right: 0; border-top: 1px solid var(--border-default); }
6099
+ .twm-flow-graph__aside { grid-column: 2; grid-row: 2; border-left: 0; border-top: 1px solid var(--border-default); }
6100
+ }
6101
+
6102
+ /* ── a node ─────────────────────────────────────────────────────────── */
6103
+ /* THE BOX IS ARITHMETIC: a line meets a port at `header + row × i + row / 2`
6104
+ * (layout.js's portAnchor), so the header and a row are exactly these heights.
6105
+ * A consumer that passes `node: {width, header, row}` sets the three custom
6106
+ * properties on the editor's root. */
6107
+ .twm-flow-graph__node {
6108
+ position: absolute;
6109
+ box-sizing: border-box;
6110
+ width: var(--twm-canvas-node-width, 208px);
6111
+ background: var(--surface-2);
6112
+ border: 1px solid var(--border-strong);
6113
+ border-radius: 4px;
6114
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.55);
6115
+ color: var(--text-body);
6116
+ font-size: var(--font-size-xs);
6117
+ outline: none;
6118
+ }
6119
+ .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); }
6120
+ .twm-flow-graph__node--picked {
6121
+ border-color: var(--twm-flow-focus);
6122
+ box-shadow: 0 0 0 1px var(--twm-flow-focus), 0 6px 18px rgba(0, 0, 0, 0.45);
6123
+ }
6124
+ .twm-flow-graph__node--connect-source { outline: 2px solid var(--twm-flow-focus); outline-offset: 1px; }
6125
+ .twm-flow-graph__node--error { border-color: var(--twm-flow-error); }
6126
+ .twm-flow-graph__node--warning { border-color: var(--twm-flow-warning); }
6127
+ .twm-flow-graph__node--skipped { opacity: 0.55; }
6128
+ .twm-flow-graph__node-head {
6129
+ box-sizing: border-box;
6130
+ height: var(--twm-canvas-node-header, 34px);
6131
+ display: flex;
6132
+ align-items: center;
6133
+ gap: 6px;
6134
+ padding: 0 8px;
6135
+ background: var(--surface-3);
6136
+ border-bottom: 1px solid var(--border-strong);
6137
+ border-radius: 3px 3px 0 0;
6138
+ font-size: var(--font-size-sm);
6139
+ font-weight: 600;
6140
+ user-select: none;
6141
+ cursor: move;
6142
+ }
6143
+ .twm-flow-graph--readonly .twm-flow-graph__node-head { cursor: default; }
6144
+ .twm-flow-graph__node-icon {
6145
+ flex: 0 0 20px;
6146
+ height: 20px;
6147
+ display: inline-flex;
6148
+ align-items: center;
6149
+ justify-content: center;
6150
+ border-radius: 4px;
6151
+ }
6152
+ .twm-flow-graph__node-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6153
+ /* ONE LINE, and never more than half the header: a tag that wrapped squeezed
6154
+ * the title beside it to a few letters. */
6155
+ .twm-flow-graph__node-tag {
6156
+ margin-left: auto;
6157
+ flex: none;
6158
+ max-width: 50%;
6159
+ padding: 1px 5px;
6160
+ overflow: hidden;
6161
+ text-overflow: ellipsis;
6162
+ white-space: nowrap;
6163
+ font-size: var(--font-size-xs);
6164
+ font-weight: 500;
6165
+ color: #b8cbe0;
6166
+ background: rgba(127, 154, 198, 0.18);
6167
+ border-radius: 2px;
6168
+ }
6169
+ .twm-flow-graph__node-row {
6170
+ box-sizing: border-box;
6171
+ height: var(--twm-canvas-node-row, 22px);
6172
+ display: flex;
6173
+ align-items: center;
6174
+ justify-content: space-between;
6175
+ }
6176
+ .twm-flow-graph__node-gap { flex: 1 1 auto; }
6177
+ .twm-flow-graph__node-summary,
6178
+ .twm-flow-graph__node-run {
6179
+ margin: 0;
6180
+ padding: 2px 8px 4px;
6181
+ color: var(--twm-flow-muted);
6182
+ overflow-wrap: anywhere;
6183
+ }
6184
+ .twm-flow-graph__node-summary:empty,
6185
+ .twm-flow-graph__node-run:empty { display: none; }
6186
+ .twm-flow-graph__node-findings { padding: 0 8px; }
6187
+ .twm-flow-graph__node-finding { margin: 4px 0; color: var(--twm-flow-error); overflow-wrap: anywhere; }
6188
+ .twm-flow-graph__node-finding--warning { color: var(--twm-flow-warning); }
6189
+ .twm-flow-graph__node-run[data-state="completed"], .twm-flow-graph__node-run[data-tone="ok"] { color: var(--twm-flow-ok); }
6190
+ .twm-flow-graph__node-run[data-state="failed"], .twm-flow-graph__node-run[data-tone="error"] { color: var(--twm-flow-error); }
6191
+ .twm-flow-graph__node-run[data-tone="warning"] { color: var(--twm-flow-warning); }
6192
+ .twm-flow-graph__node-run[data-state="running"] { color: var(--twm-flow-focus); }
6193
+ .twm-flow-graph__node-run[data-state="skipped"],
6194
+ .twm-flow-graph__node-run[data-state="cancelled"],
6195
+ .twm-flow-graph__node-run[data-state="not-reached"] { font-style: italic; }
6196
+
6197
+ /* ── a port ─────────────────────────────────────────────────────────── */
6198
+ .twm-flow-graph__port {
6199
+ display: flex;
6200
+ align-items: center;
6201
+ gap: 4px;
6202
+ height: var(--twm-canvas-node-row, 22px);
6203
+ padding: 0 6px;
6204
+ background: none;
6205
+ border: 0;
6206
+ color: inherit;
6207
+ font: inherit;
6208
+ font-size: var(--font-size-xs);
6209
+ cursor: crosshair;
6210
+ }
6211
+ .twm-flow-graph__port:disabled { cursor: default; }
6212
+ .twm-flow-graph__port:focus-visible { outline: 1px solid var(--twm-flow-focus); outline-offset: -1px; }
6213
+ .twm-flow-graph__port--in { margin-left: -6px; }
6214
+ .twm-flow-graph__port--out { flex-direction: row-reverse; margin-right: -6px; }
6215
+ .twm-flow-graph__port-dot {
6216
+ flex: 0 0 10px;
6217
+ width: 10px;
6218
+ height: 10px;
6219
+ box-sizing: border-box;
6220
+ border-radius: 50%;
6221
+ background: var(--surface-3);
6222
+ border: 2px solid var(--twm-flow-focus);
6223
+ }
6224
+ .twm-flow-graph__port-label { white-space: nowrap; }
6225
+ .twm-flow-graph__port-count { color: var(--twm-flow-muted); white-space: nowrap; }
6226
+ .twm-flow-graph__port-count:empty { display: none; }
6227
+ .twm-flow-graph__port:hover:not(:disabled) .twm-flow-graph__port-dot { background: var(--twm-flow-focus); }
6228
+ .twm-flow-graph__port--data { opacity: 0.7; }
6229
+ .twm-flow-graph__port--data .twm-flow-graph__port-dot { border-color: #8a8f98; border-radius: 2px; }
6230
+ .twm-flow-graph--connecting .twm-flow-graph__port--in:not(:disabled) .twm-flow-graph__port-dot {
6231
+ background: var(--twm-flow-focus);
6232
+ box-shadow: 0 0 0 3px rgba(0, 122, 204, 0.35);
6233
+ }
6234
+ .twm-flow-graph__port--taken .twm-flow-graph__port-dot { border-color: var(--twm-flow-ok); background: var(--twm-flow-ok); }
6235
+ .twm-flow-graph__port--taken .twm-flow-graph__port-count { color: var(--twm-flow-ok); }
6236
+ .twm-flow-graph__port--untaken { opacity: 0.5; }
6237
+
6238
+ /* ── a line ─────────────────────────────────────────────────────────── */
6239
+ .twm-flow-graph__edge { fill: none; stroke: #8fb4d8; stroke-width: 1.6; }
6240
+ .twm-flow-graph__edge--picked { stroke: var(--twm-flow-focus); stroke-width: 2.4; }
6241
+ /* A loop's body handing back to the loop: DASHED, and routed under both steps
6242
+ * by the kernel's `returnEdge`, so it reads as "round again", not as one more
6243
+ * step forward. */
6244
+ .twm-flow-graph__edge--back { stroke-dasharray: 6 4; }
6245
+ .twm-flow-graph__edge--taken { stroke: var(--twm-flow-ok); }
6246
+ .twm-flow-graph__edge--untaken { opacity: 0.35; }
6247
+ /* The 14px target a 1.6px line cannot be. It opts back into the pointer the
6248
+ * edge layer turns off. */
6249
+ .twm-flow-graph__edge-hit { fill: none; stroke: transparent; stroke-width: 14; pointer-events: stroke; cursor: pointer; }
6250
+
6251
+ /* ── the palette drag's ghost ───────────────────────────────────────── */
6252
+ /* It lives on <body>, follows the pointer and never takes it — `pointer-events:
6253
+ * none`, or the release lands on the ghost rather than on the canvas. */
6254
+ .twm-flow-graph__ghost {
6255
+ position: fixed;
6256
+ z-index: var(--z-toast);
6257
+ pointer-events: none;
6258
+ display: flex;
6259
+ align-items: center;
6260
+ gap: 6px;
6261
+ padding: 4px 8px;
6262
+ background: var(--surface-2);
6263
+ border: 1px solid var(--twm-flow-focus);
6264
+ border-radius: 3px;
6265
+ color: var(--text-body);
6266
+ font-family: var(--font-family-sans);
6267
+ font-size: var(--font-size-sm);
6268
+ opacity: 0.92;
6269
+ box-shadow: var(--shadow-md);
6270
+ }
6271
+ .twm-flow-graph__ghost .material-symbols-outlined { font-size: 16px; }
6272
+ .twm-flow-graph__ghost-label { white-space: nowrap; }
6273
+ /* ══ end FLOW · CANVAS ══ */
6274
+
6275
+
6276
+ /* ══ FLOW · OUTLINE ═══════════════════════════════════════════════════ */
6277
+ /* The outline editor (36 §6, the Main, AddStep, StepMenu and Run mocks): a
6278
+ * logic flow drawn as a list of blocks. A row is indented 22px a level
6279
+ * (`--twm-outline-depth`, set by src/flow/outline/editor.js, whose
6280
+ * OUTLINE_INDENT is the same number); its guides are the lines at 14px +
6281
+ * 22px a level. Every class here is set by a module under src/flow/outline/,
6282
+ * and every class those modules set has a rule here —
6283
+ * tests/flow_outline_css.test.mjs holds both directions. */
6284
+
6285
+ .twm-flow-outline[hidden],
6286
+ .twm-flow-outline [hidden],
6287
+ .twm-flow-popover--menu [hidden] {
6288
+ display: none !important;
6289
+ }
6290
+
6291
+ .twm-flow-outline {
6292
+ container: twm-flow-outline / inline-size;
6293
+ display: flex;
6294
+ flex-direction: column;
6295
+ height: 100%;
6296
+ min-height: 0;
6297
+ box-sizing: border-box;
6298
+ background: var(--surface-0);
6299
+ color: var(--text-body);
6300
+ font-family: var(--font-family-sans);
6301
+ font-size: var(--font-size-sm);
6302
+ line-height: 1.4;
6303
+ outline: none;
6304
+ }
6305
+ .twm-flow-outline--dragging,
6306
+ .twm-flow-outline--dragging * {
6307
+ cursor: grabbing !important;
6308
+ user-select: none;
6309
+ }
6310
+ .twm-flow-outline--readonly .twm-flow-outline__keys { display: none; }
6311
+ .twm-flow-outline--run .twm-flow-outline__type { display: none; }
6312
+
6313
+ /* ── the toolbar ────────────────────────────────────────────────────── */
6314
+ .twm-flow-outline__toolbar {
6315
+ display: flex;
6316
+ flex-wrap: wrap;
6317
+ align-items: center;
6318
+ gap: 6px;
6319
+ padding: 6px 10px;
6320
+ background: var(--surface-1);
6321
+ border-bottom: 1px solid var(--border-default);
6322
+ }
6323
+ .twm-flow-outline__toolbar .twm-btn {
6324
+ min-height: 26px;
6325
+ padding: 0 9px;
6326
+ font-size: var(--font-size-sm);
6327
+ border-radius: 3px;
6328
+ }
6329
+ .twm-flow-outline__tool { white-space: nowrap; }
6330
+ .twm-flow-outline__tool--busy { cursor: progress; opacity: .7; }
6331
+ .twm-flow-outline__sep {
6332
+ width: 1px;
6333
+ height: 18px;
6334
+ margin: 0 4px;
6335
+ background: var(--border-default);
6336
+ }
6337
+ .twm-flow-outline__tool-wrap {
6338
+ display: inline-flex;
6339
+ align-items: center;
6340
+ gap: 6px;
6341
+ }
6342
+ .twm-flow-outline__refusal {
6343
+ max-width: 260px;
6344
+ font-size: var(--font-size-xs);
6345
+ color: var(--twm-flow-warning);
6346
+ }
6347
+ .twm-flow-outline__status {
6348
+ margin-left: 8px;
6349
+ color: var(--twm-flow-muted);
6350
+ }
6351
+ .twm-flow-outline__spacer { flex: 1 1 auto; }
6352
+ .twm-flow-outline__toolbar-end {
6353
+ display: flex;
6354
+ align-items: center;
6355
+ gap: 6px;
6356
+ }
6357
+
6358
+ /* ── the banners: read only, and the run drawn ─────────────────────── */
6359
+ .twm-flow-outline__readonly {
6360
+ display: flex;
6361
+ align-items: flex-start;
6362
+ gap: 8px;
6363
+ padding: 6px 12px;
6364
+ background: var(--twm-flow-warning-bg);
6365
+ border-bottom: 1px solid var(--twm-flow-warning-line);
6366
+ color: var(--twm-flow-warning-text);
6367
+ }
6368
+ .twm-flow-outline__readonly-icon {
6369
+ flex: 0 0 auto;
6370
+ font-size: 16px;
6371
+ color: var(--twm-flow-warning);
6372
+ }
6373
+ .twm-flow-outline__readonly-text { min-width: 0; }
6374
+ .twm-flow-outline__banner {
6375
+ display: flex;
6376
+ align-items: center;
6377
+ gap: 8px;
6378
+ padding: 6px 12px;
6379
+ background: var(--twm-flow-blue-bg);
6380
+ border-bottom: 1px solid var(--twm-flow-blue-line);
6381
+ color: var(--twm-flow-blue-fg);
6382
+ }
6383
+ .twm-flow-outline__banner-icon {
6384
+ flex: 0 0 auto;
6385
+ font-size: 16px;
6386
+ color: var(--twm-flow-blue-dot);
6387
+ }
6388
+ .twm-flow-outline__banner-text { min-width: 0; }
6389
+
6390
+ /* ── the three columns ──────────────────────────────────────────────── */
6391
+ /* Side by side, each column scrolling on its own inside the editor's height —
6392
+ * the list's keys line stays at its foot and a long panel scrolls past a
6393
+ * short outline; in a narrow editor they wrap, one under the other, and the
6394
+ * body scrolls as one. */
6395
+ .twm-flow-outline__body {
6396
+ display: flex;
6397
+ flex-wrap: nowrap;
6398
+ align-items: stretch;
6399
+ flex: 1 1 auto;
6400
+ min-height: 0;
6401
+ overflow: hidden;
6402
+ }
6403
+ .twm-flow-outline__list {
6404
+ flex: 0 1 440px;
6405
+ min-width: 300px;
6406
+ max-width: 100%;
6407
+ min-height: 0;
6408
+ box-sizing: border-box;
6409
+ display: flex;
6410
+ flex-direction: column;
6411
+ border-right: 1px solid var(--border-default);
6412
+ }
6413
+ @container twm-flow-outline (max-width: 1000px) {
6414
+ .twm-flow-outline__body {
6415
+ flex-wrap: wrap;
6416
+ overflow: auto;
6417
+ }
6418
+ .twm-flow-outline__list { flex: 1 1 100%; border-right: 0; }
6419
+ .twm-flow-outline__settings,
6420
+ .twm-flow-outline__aside { overflow: visible; }
6421
+ }
6422
+ .twm-flow-outline__settings {
6423
+ flex: 3 1 460px;
6424
+ min-width: 0;
6425
+ box-sizing: border-box;
6426
+ overflow: auto;
6427
+ background: var(--surface-1);
6428
+ border-right: 1px solid var(--border-default);
6429
+ }
6430
+ .twm-flow-outline__aside {
6431
+ flex: 1 1 300px;
6432
+ min-width: 260px;
6433
+ box-sizing: border-box;
6434
+ padding: 16px;
6435
+ overflow: auto;
6436
+ }
6437
+
6438
+ /* ── the list's head, find, the status line ─────────────────────────── */
6439
+ .twm-flow-outline__list-head {
6440
+ flex: 0 0 auto;
6441
+ display: flex;
6442
+ align-items: center;
6443
+ gap: 8px;
6444
+ padding: 10px 12px 8px;
6445
+ }
6446
+ .twm-flow-outline__heading {
6447
+ margin: 0;
6448
+ font-size: 11px;
6449
+ font-weight: var(--font-weight-semibold);
6450
+ letter-spacing: .06em;
6451
+ text-transform: uppercase;
6452
+ color: var(--text-secondary);
6453
+ }
6454
+ .twm-flow-outline__count { color: var(--twm-flow-muted); }
6455
+ .twm-flow-outline__fold-all {
6456
+ height: 22px;
6457
+ padding: 0 7px;
6458
+ border: 0;
6459
+ border-radius: 3px;
6460
+ background: transparent;
6461
+ color: var(--text-secondary);
6462
+ font: inherit;
6463
+ cursor: pointer;
6464
+ }
6465
+ .twm-flow-outline__fold-all:hover:not(:disabled) { background: var(--state-hover); }
6466
+ .twm-flow-outline__fold-all:disabled { cursor: default; opacity: .45; }
6467
+ .twm-flow-outline__find {
6468
+ flex: 0 0 auto;
6469
+ box-sizing: border-box;
6470
+ width: calc(100% - 24px);
6471
+ height: 26px;
6472
+ margin: 0 12px 8px;
6473
+ padding: 0 8px;
6474
+ background: var(--twm-flow-control-bg);
6475
+ border: 1px solid var(--twm-flow-control-border);
6476
+ border-radius: 3px;
6477
+ color: var(--text-primary);
6478
+ font: inherit;
6479
+ }
6480
+ .twm-flow-outline__find:focus {
6481
+ outline: none;
6482
+ border-color: var(--twm-flow-focus);
6483
+ }
6484
+ .twm-flow-outline__scroll {
6485
+ flex: 1 1 auto;
6486
+ min-height: 0;
6487
+ overflow: auto;
6488
+ padding: 0 8px 12px;
6489
+ }
6490
+ .twm-flow-outline__message {
6491
+ flex: 0 0 auto;
6492
+ margin: 0 12px 6px;
6493
+ font-size: 11px;
6494
+ color: var(--twm-flow-warning-text);
6495
+ }
6496
+ .twm-flow-outline__keys {
6497
+ flex: 0 0 auto;
6498
+ margin: 0;
6499
+ padding: 10px 12px;
6500
+ border-top: 1px solid var(--border-subtle);
6501
+ font-size: 11px;
6502
+ color: var(--twm-flow-muted);
6503
+ }
6504
+
6505
+ /* ── the tree and its rows ──────────────────────────────────────────── */
6506
+ .twm-flow-outline__tree {
6507
+ position: relative;
6508
+ display: flex;
6509
+ flex-direction: column;
6510
+ }
6511
+ .twm-flow-outline__item,
6512
+ .twm-flow-outline__inside,
6513
+ .twm-flow-outline__arm {
6514
+ display: flex;
6515
+ flex-direction: column;
6516
+ }
6517
+ .twm-flow-outline__item { outline: none; }
6518
+ .twm-flow-outline__item:focus-visible > .twm-flow-outline__row {
6519
+ outline: 2px solid var(--twm-flow-focus);
6520
+ outline-offset: -2px;
6521
+ }
6522
+ .twm-flow-outline__item--flow { margin-bottom: 6px; }
6523
+ .twm-flow-outline__item--context > .twm-flow-outline__row { opacity: .55; }
6524
+ .twm-flow-outline__row {
6525
+ position: relative;
6526
+ display: flex;
6527
+ align-items: center;
6528
+ gap: 4px;
6529
+ box-sizing: border-box;
6530
+ padding-left: calc(8px + var(--twm-outline-depth, 0) * 22px);
6531
+ border-radius: 4px;
6532
+ }
6533
+ .twm-flow-outline__row--step { min-height: 42px; }
6534
+ .twm-flow-outline__row--step:hover,
6535
+ .twm-flow-outline__row--flow:hover { background-color: var(--state-hover); }
6536
+ .twm-flow-outline__row--flow {
6537
+ gap: 10px;
6538
+ padding: 8px 10px;
6539
+ background: var(--surface-1);
6540
+ border: 1px solid var(--border-subtle);
6541
+ }
6542
+ .twm-flow-outline__row--selected,
6543
+ .twm-flow-outline__row--selected:hover {
6544
+ background: var(--twm-flow-blue-bg);
6545
+ box-shadow: inset 0 0 0 1px var(--twm-flow-focus);
6546
+ }
6547
+ .twm-flow-outline__row--off .twm-flow-outline__title {
6548
+ font-style: italic;
6549
+ color: var(--text-dim);
6550
+ }
6551
+ .twm-flow-outline__row--off .twm-flow-outline__chip { opacity: .45; }
6552
+ .twm-flow-outline__row--dragging { opacity: .45; }
6553
+ .twm-flow-outline__guide {
6554
+ position: absolute;
6555
+ top: 0;
6556
+ bottom: 0;
6557
+ left: calc(14px + var(--twm-outline-guide, 0) * 22px);
6558
+ width: 1px;
6559
+ background: var(--border-default);
6560
+ pointer-events: none;
6561
+ }
6562
+
6563
+ /* an arm: its words in its tone — Then green, Otherwise grey, a failure amber */
6564
+ .twm-flow-outline__row--arm {
6565
+ height: 24px;
6566
+ gap: 6px;
6567
+ padding-left: calc(24px + var(--twm-outline-depth, 0) * 22px);
6568
+ font-size: 11px;
6569
+ font-weight: var(--font-weight-semibold);
6570
+ color: var(--twm-flow-muted);
6571
+ }
6572
+ .twm-flow-outline__row--then { color: var(--twm-flow-ok); }
6573
+ .twm-flow-outline__row--else { color: var(--text-secondary); }
6574
+ .twm-flow-outline__row--fail { color: var(--twm-flow-warning); }
6575
+ .twm-flow-outline__row--arm.twm-flow-outline__row--off { color: var(--text-dim); }
6576
+ .twm-flow-outline__arm-icon { font-size: 13px; }
6577
+ .twm-flow-outline__arm-label { white-space: nowrap; }
6578
+ .twm-flow-outline__arm-note {
6579
+ margin-left: auto;
6580
+ padding-right: 8px;
6581
+ font-weight: var(--font-weight-regular);
6582
+ color: var(--text-muted);
6583
+ }
6584
+ .twm-flow-outline__arm-remove {
6585
+ width: 20px;
6586
+ height: 20px;
6587
+ margin-left: auto;
6588
+ margin-right: 6px;
6589
+ display: flex;
6590
+ align-items: center;
6591
+ justify-content: center;
6592
+ padding: 0;
6593
+ border: 0;
6594
+ border-radius: 3px;
6595
+ background: transparent;
6596
+ color: var(--text-secondary);
6597
+ opacity: .6;
6598
+ cursor: pointer;
6599
+ }
6600
+ .twm-flow-outline__arm-note + .twm-flow-outline__arm-remove { margin-left: 0; }
6601
+ .twm-flow-outline__arm-remove .material-symbols-outlined { font-size: 14px; }
6602
+ .twm-flow-outline__row:hover > .twm-flow-outline__arm-remove,
6603
+ .twm-flow-outline__arm-remove:focus-visible { opacity: 1; }
6604
+ .twm-flow-outline__arm-remove:hover { background: var(--state-hover); }
6605
+
6606
+ /* a foot: Next row, Go on with the next row, Then wait for every branch */
6607
+ .twm-flow-outline__row--foot {
6608
+ height: 26px;
6609
+ gap: 6px;
6610
+ padding-left: calc(24px + var(--twm-outline-depth, 0) * 22px);
6611
+ font-size: 11px;
6612
+ color: var(--twm-flow-muted);
6613
+ }
6614
+ .twm-flow-outline__foot-icon { font-size: 13px; }
6615
+ .twm-flow-outline__foot-label { white-space: nowrap; }
6616
+ .twm-flow-outline__foot-note {
6617
+ margin-left: auto;
6618
+ padding-right: 8px;
6619
+ color: var(--text-muted);
6620
+ }
6621
+
6622
+ /* an add row: Add a step, Add a step to the loop, Add a branch */
6623
+ .twm-flow-outline__row--add { padding: 2px 8px 6px calc(24px + var(--twm-outline-depth, 0) * 22px); }
6624
+ .twm-flow-outline__row--add-top { padding-left: 8px; }
6625
+ .twm-flow-outline__row--add-top .twm-flow-outline__add { width: 100%; }
6626
+ .twm-flow-outline__add {
6627
+ box-sizing: border-box;
6628
+ display: flex;
6629
+ align-items: center;
6630
+ gap: 6px;
6631
+ height: 26px;
6632
+ padding: 0 9px;
6633
+ border: 1px dashed var(--border-strong);
6634
+ border-radius: 4px;
6635
+ background: transparent;
6636
+ color: var(--text-secondary);
6637
+ font: inherit;
6638
+ font-size: 11px;
6639
+ cursor: pointer;
6640
+ }
6641
+ .twm-flow-outline__add .material-symbols-outlined { font-size: 14px; }
6642
+ .twm-flow-outline__add:hover,
6643
+ .twm-flow-outline__add:focus-visible {
6644
+ color: var(--twm-flow-blue-fg);
6645
+ border-color: var(--twm-flow-focus);
6646
+ outline: none;
6647
+ }
6648
+ .twm-flow-outline__add-label { white-space: nowrap; }
6649
+
6650
+ /* a step row's parts */
6651
+ .twm-flow-outline__grip {
6652
+ flex: 0 0 12px;
6653
+ display: flex;
6654
+ color: var(--text-muted);
6655
+ opacity: 0;
6656
+ cursor: grab;
6657
+ touch-action: none;
6658
+ }
6659
+ .twm-flow-outline__grip .material-symbols-outlined { font-size: 14px; }
6660
+ .twm-flow-outline__row:hover > .twm-flow-outline__grip,
6661
+ .twm-flow-outline__row--selected > .twm-flow-outline__grip { opacity: 1; }
6662
+ .twm-flow-outline__grip--off { visibility: hidden; }
6663
+ .twm-flow-outline__fold {
6664
+ flex: 0 0 18px;
6665
+ width: 18px;
6666
+ height: 18px;
6667
+ display: flex;
6668
+ align-items: center;
6669
+ justify-content: center;
6670
+ padding: 0;
6671
+ border: 0;
6672
+ border-radius: 3px;
6673
+ background: transparent;
6674
+ color: var(--text-secondary);
6675
+ cursor: pointer;
6676
+ }
6677
+ .twm-flow-outline__fold:hover { background: var(--state-hover); }
6678
+ .twm-flow-outline__fold .material-symbols-outlined { font-size: 16px; }
6679
+ .twm-flow-outline__fold-space { flex: 0 0 18px; }
6680
+ .twm-flow-outline__chip {
6681
+ flex: 0 0 24px;
6682
+ height: 24px;
6683
+ display: flex;
6684
+ align-items: center;
6685
+ justify-content: center;
6686
+ margin-left: 5px;
6687
+ border-radius: 5px;
6688
+ }
6689
+ .twm-flow-outline__row--flow > .twm-flow-outline__chip { margin-left: 0; }
6690
+ .twm-flow-outline__chip .material-symbols-outlined { font-size: 15px; }
6691
+ .twm-flow-outline__chip--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
6692
+ .twm-flow-outline__chip--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
6693
+ .twm-flow-outline__chip--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
6694
+ .twm-flow-outline__chip--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
6695
+ .twm-flow-outline__chip--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
6696
+ .twm-flow-outline__chip--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
6697
+ .twm-flow-outline__words {
6698
+ flex: 1 1 auto;
6699
+ min-width: 0;
6700
+ display: flex;
6701
+ flex-direction: column;
6702
+ gap: 1px;
6703
+ padding: 5px 4px;
6704
+ }
6705
+ .twm-flow-outline__line {
6706
+ display: flex;
6707
+ align-items: baseline;
6708
+ gap: 7px;
6709
+ min-width: 0;
6710
+ }
6711
+ .twm-flow-outline__title {
6712
+ min-width: 0;
6713
+ overflow: hidden;
6714
+ white-space: nowrap;
6715
+ text-overflow: ellipsis;
6716
+ font-weight: var(--font-weight-medium);
6717
+ color: var(--text-primary);
6718
+ }
6719
+ .twm-flow-outline__row--flow .twm-flow-outline__title { font-weight: var(--font-weight-semibold); }
6720
+ .twm-flow-outline__type {
6721
+ font-size: 11px;
6722
+ white-space: nowrap;
6723
+ color: var(--text-muted);
6724
+ }
6725
+ .twm-flow-outline__summary {
6726
+ overflow: hidden;
6727
+ white-space: nowrap;
6728
+ text-overflow: ellipsis;
6729
+ font-size: 11px;
6730
+ color: var(--text-secondary);
6731
+ }
6732
+ .twm-flow-outline__summary--mono {
6733
+ font-family: var(--font-family-mono);
6734
+ font-size: 11px;
6735
+ }
6736
+ .twm-flow-outline__summary--error { color: var(--twm-flow-error); }
6737
+ .twm-flow-outline__summary--warning { color: var(--twm-flow-warning); }
6738
+ .twm-flow-outline__note {
6739
+ flex: 0 0 auto;
6740
+ padding: 1px 6px;
6741
+ border-radius: 8px;
6742
+ background: var(--surface-2);
6743
+ font-size: 11px;
6744
+ white-space: nowrap;
6745
+ color: var(--text-secondary);
6746
+ }
6747
+ .twm-flow-outline__run {
6748
+ flex: 0 0 auto;
6749
+ display: inline-flex;
6750
+ align-items: center;
6751
+ height: 20px;
6752
+ padding: 0 7px;
6753
+ border-radius: 10px;
6754
+ font-size: 11px;
6755
+ white-space: nowrap;
6756
+ }
6757
+ .twm-flow-outline__run--ok { background: color-mix(in srgb, var(--twm-flow-ok) 14%, transparent); color: var(--twm-flow-ok); }
6758
+ .twm-flow-outline__run--warn { background: var(--twm-flow-warning-bg); color: var(--twm-flow-warning); }
6759
+ .twm-flow-outline__run--fail { background: var(--twm-flow-error-bg); color: var(--twm-flow-error); }
6760
+ .twm-flow-outline__run--skip { background: var(--twm-flow-grey-bg); color: var(--text-muted); }
6761
+ .twm-flow-outline__run--running { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
6762
+ .twm-flow-outline__badge {
6763
+ flex: 0 0 auto;
6764
+ display: flex;
6765
+ color: var(--twm-flow-error);
6766
+ }
6767
+ .twm-flow-outline__badge--warning { color: var(--twm-flow-warning); }
6768
+ .twm-flow-outline__badge .material-symbols-outlined { font-size: 15px; }
6769
+ .twm-flow-outline__menu {
6770
+ flex: 0 0 24px;
6771
+ width: 24px;
6772
+ height: 24px;
6773
+ margin-right: 4px;
6774
+ display: flex;
6775
+ align-items: center;
6776
+ justify-content: center;
6777
+ padding: 0;
6778
+ border: 0;
6779
+ border-radius: 3px;
6780
+ background: transparent;
6781
+ color: var(--text-secondary);
6782
+ opacity: .6;
6783
+ cursor: pointer;
6784
+ }
6785
+ .twm-flow-outline__menu .material-symbols-outlined { font-size: 16px; }
6786
+ .twm-flow-outline__row:hover > .twm-flow-outline__menu,
6787
+ .twm-flow-outline__row--selected > .twm-flow-outline__menu,
6788
+ .twm-flow-outline__menu:focus-visible { opacity: 1; }
6789
+ .twm-flow-outline__menu:hover { background: var(--state-hover); }
6790
+
6791
+ /* "+" between two rows: drawn on a row's bottom edge at the indent of the
6792
+ * list it adds to, shown on the row's hover AND on its own focus; only its
6793
+ * circle takes the pointer, so it never covers the row below */
6794
+ .twm-flow-outline__gap {
6795
+ position: absolute;
6796
+ z-index: 2;
6797
+ left: calc(8px + var(--twm-outline-depth, 0) * 22px);
6798
+ right: 8px;
6799
+ bottom: -7px;
6800
+ height: 14px;
6801
+ padding: 0;
6802
+ border: 0;
6803
+ background: transparent;
6804
+ opacity: 0;
6805
+ pointer-events: none;
6806
+ }
6807
+ .twm-flow-outline__row:hover > .twm-flow-outline__gap,
6808
+ .twm-flow-outline__gap:hover,
6809
+ .twm-flow-outline__gap:focus-visible {
6810
+ opacity: 1;
6811
+ outline: none;
6812
+ }
6813
+ .twm-flow-outline__gap-line {
6814
+ position: absolute;
6815
+ left: 10px;
6816
+ right: 0;
6817
+ top: 6px;
6818
+ height: 2px;
6819
+ border-radius: 1px;
6820
+ background: var(--twm-flow-focus);
6821
+ }
6822
+ .twm-flow-outline__gap-plus {
6823
+ position: absolute;
6824
+ left: 0;
6825
+ top: -2px;
6826
+ width: 18px;
6827
+ height: 18px;
6828
+ display: flex;
6829
+ align-items: center;
6830
+ justify-content: center;
6831
+ border-radius: 9px;
6832
+ background: var(--twm-flow-focus);
6833
+ color: #ffffff;
6834
+ font-size: 13px;
6835
+ pointer-events: none;
6836
+ cursor: pointer;
6837
+ }
6838
+ /* the circle takes the pointer only while it is drawn: an invisible "+" must
6839
+ * not catch a press meant for the top-left corner of the row below */
6840
+ .twm-flow-outline__row:hover > .twm-flow-outline__gap .twm-flow-outline__gap-plus,
6841
+ .twm-flow-outline__gap:focus-visible .twm-flow-outline__gap-plus { pointer-events: auto; }
6842
+ .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); }
6843
+
6844
+ /* the grip drag: a ghost under the pointer, and a drop line naming the place */
6845
+ .twm-flow-outline__ghost {
6846
+ position: fixed;
6847
+ z-index: var(--z-popover);
6848
+ box-sizing: border-box;
6849
+ display: flex;
6850
+ align-items: center;
6851
+ gap: 9px;
6852
+ min-width: 200px;
6853
+ max-width: 320px;
6854
+ height: 40px;
6855
+ padding: 0 10px;
6856
+ background: var(--surface-2);
6857
+ border: 1px solid var(--twm-flow-focus);
6858
+ border-radius: 4px;
6859
+ box-shadow: 0 10px 24px rgba(0, 0, 0, 0.6);
6860
+ color: var(--text-primary);
6861
+ font-family: var(--font-family-sans);
6862
+ font-size: var(--font-size-sm);
6863
+ pointer-events: none;
6864
+ transform: rotate(-1.5deg);
6865
+ }
6866
+ .twm-flow-outline__ghost .twm-flow-outline__chip { margin-left: 0; }
6867
+ .twm-flow-outline__ghost-grip { font-size: 14px; color: var(--text-secondary); }
6868
+ .twm-flow-outline__ghost-title {
6869
+ overflow: hidden;
6870
+ white-space: nowrap;
6871
+ text-overflow: ellipsis;
6872
+ font-weight: var(--font-weight-medium);
6873
+ }
6874
+ .twm-flow-outline__drop {
6875
+ position: absolute;
6876
+ z-index: 3;
6877
+ left: calc(8px + var(--twm-outline-depth, 0) * 22px);
6878
+ right: 8px;
6879
+ height: 2px;
6880
+ margin-top: -1px;
6881
+ border-radius: 1px;
6882
+ background: var(--twm-flow-focus);
6883
+ pointer-events: none;
6884
+ }
6885
+ .twm-flow-outline__drop-label {
6886
+ position: absolute;
6887
+ right: 8px;
6888
+ top: -9px;
6889
+ box-sizing: border-box;
6890
+ max-width: calc(100% - 16px);
6891
+ min-height: 18px;
6892
+ display: flex;
6893
+ align-items: center;
6894
+ padding: 1px 7px;
6895
+ border-radius: 3px;
6896
+ background: var(--twm-flow-focus);
6897
+ color: #ffffff;
6898
+ font-size: 11px;
6899
+ line-height: 1.35;
6900
+ }
6901
+ .twm-flow-outline__drop--refused { background: var(--twm-flow-warning); }
6902
+ .twm-flow-outline__drop--refused .twm-flow-outline__drop-label {
6903
+ background: var(--surface-2);
6904
+ border: 1px solid var(--twm-flow-warning-line);
6905
+ color: var(--twm-flow-warning-text);
6906
+ }
6907
+
6908
+ /* the step menu (StepMenu mock), in the kit's popover */
6909
+ .twm-flow-popover--menu { width: 260px; }
6910
+ .twm-flow-outline__menu-list {
6911
+ position: relative;
6912
+ display: flex;
6913
+ flex-direction: column;
6914
+ box-sizing: border-box;
6915
+ padding: 5px;
6916
+ }
6917
+ .twm-flow-outline__menu-sub {
6918
+ position: absolute;
6919
+ left: calc(100% - 4px);
6920
+ z-index: 1;
6921
+ width: 190px;
6922
+ background: var(--surface-1);
6923
+ border: 1px solid var(--twm-flow-control-border);
6924
+ border-radius: var(--radius-md);
6925
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
6926
+ }
6927
+ .twm-flow-outline__menu-item {
6928
+ display: flex;
6929
+ align-items: center;
6930
+ justify-content: space-between;
6931
+ gap: 12px;
6932
+ min-height: 26px;
6933
+ padding: 3px 8px;
6934
+ border: 0;
6935
+ border-radius: 4px;
6936
+ background: transparent;
6937
+ color: var(--text-primary);
6938
+ font: inherit;
6939
+ text-align: left;
6940
+ cursor: pointer;
6941
+ }
6942
+ .twm-flow-outline__menu-item:hover:not(:disabled),
6943
+ .twm-flow-outline__menu-item:focus-visible,
6944
+ .twm-flow-outline__menu-item--open {
6945
+ outline: none;
6946
+ background: var(--twm-flow-blue-bg);
6947
+ }
6948
+ .twm-flow-outline__menu-item:disabled {
6949
+ color: var(--text-dim);
6950
+ cursor: not-allowed;
6951
+ }
6952
+ .twm-flow-outline__menu-item--danger { color: var(--twm-flow-error); }
6953
+ .twm-flow-outline__menu-item--danger:disabled { color: var(--text-dim); }
6954
+ .twm-flow-outline__menu-words {
6955
+ display: flex;
6956
+ align-items: center;
6957
+ gap: 8px;
6958
+ min-width: 0;
6959
+ }
6960
+ .twm-flow-outline__menu-label { overflow-wrap: anywhere; }
6961
+ .twm-flow-outline__menu-key {
6962
+ flex: 0 0 auto;
6963
+ font-size: 11px;
6964
+ color: var(--text-muted);
6965
+ }
6966
+ .twm-flow-outline__menu-sep {
6967
+ height: 1px;
6968
+ margin: 4px 6px;
6969
+ background: var(--border-default);
6970
+ }
6971
+ .twm-flow-outline__menu-chip {
6972
+ flex: 0 0 20px;
6973
+ height: 20px;
6974
+ display: flex;
6975
+ align-items: center;
6976
+ justify-content: center;
6977
+ border-radius: 4px;
6978
+ }
6979
+ .twm-flow-outline__menu-chip .material-symbols-outlined { font-size: 14px; }
6980
+ .twm-flow-outline__menu-chip--violet { background: var(--twm-flow-violet-bg); color: var(--twm-flow-violet-fg); }
6981
+ .twm-flow-outline__menu-chip--teal { background: var(--twm-flow-teal-bg); color: var(--twm-flow-teal-fg); }
6982
+ .twm-flow-outline__menu-chip--amber { background: var(--twm-flow-amber-bg); color: var(--twm-flow-amber-fg); }
6983
+ .twm-flow-outline__menu-chip--grey { background: var(--twm-flow-grey-bg); color: var(--twm-flow-grey-fg); }
6984
+ .twm-flow-outline__menu-chip--blue { background: var(--twm-flow-blue-bg); color: var(--twm-flow-blue-fg); }
6985
+ .twm-flow-outline__menu-chip--indigo { background: var(--twm-flow-indigo-bg); color: var(--twm-flow-indigo-fg); }
6986
+ /* ══ end FLOW · OUTLINE ══ */
6987
+
6988
+
6989
+ /* ══ FLOW · LANES ═════════════════════════════════════════════════════ */
6990
+ /* Owned by the lanes agent (D) (36 §2): the lane editor (twm-flow-lanes). */
6991
+ /*
6992
+ * The lane editor: a data flow drawn as lanes, left to right. Every class is
6993
+ * set by src/flow/lanes/editor.js, and every one it sets has a rule here
6994
+ * (tests/flow_lanes_css.test.mjs).
6995
+ *
6996
+ * THE CARD SIZES BELOW MUST MATCH `LANE_GEOMETRY` in src/flow/lanes/layout.js
6997
+ * — the layout places cards and draws wires from those numbers, the sheet
6998
+ * sizes and clips the cards, and the suite holds the two equal.
6999
+ */
7000
+ .twm-flow-lanes [hidden] {
7001
+ display: none !important;
7002
+ }
7003
+ .twm-flow-lanes {
7004
+ --twm-lanes-wire: #5b9bd5;
7005
+ --twm-lanes-surface: #1b1b1c;
7006
+ --twm-lanes-ring: #1683c4;
7007
+ display: flex;
7008
+ flex-direction: column;
7009
+ box-sizing: border-box;
7010
+ height: 100%;
7011
+ min-height: 0;
7012
+ min-width: 0;
7013
+ background: var(--surface-0);
7014
+ color: var(--text-body);
7015
+ font-family: var(--font-family-sans);
7016
+ font-size: var(--font-size-sm);
7017
+ line-height: 1.4;
7018
+ }
7019
+ .twm-flow-lanes--regular {
7020
+ --twm-lanes-card-w: 200px;
7021
+ --twm-lanes-card-h: 62px;
7022
+ --twm-lanes-notch: 12px;
7023
+ --twm-lanes-icon-w: 50px;
7024
+ --twm-lanes-icon-w-source: 40px;
7025
+ }
7026
+ .twm-flow-lanes--small {
7027
+ --twm-lanes-card-w: 160px;
7028
+ --twm-lanes-card-h: 50px;
7029
+ --twm-lanes-notch: 10px;
7030
+ --twm-lanes-icon-w: 42px;
7031
+ --twm-lanes-icon-w-source: 34px;
7032
+ }
7033
+ .twm-flow-lanes--strip {
7034
+ --twm-lanes-card-w: 92px;
7035
+ --twm-lanes-card-h: 26px;
7036
+ --twm-lanes-notch: 8px;
7037
+ }
7038
+ .twm-flow-lanes--auto {
7039
+ height: auto;
7040
+ }
7041
+ .twm-flow-lanes--compact {
7042
+ height: auto;
7043
+ background: transparent;
7044
+ }
7045
+ .twm-flow-lanes--readonly .twm-flow-lanes__flow {
7046
+ background: #1a1a1b;
7047
+ }
7048
+
7049
+ /* ── read only ──────────────────────────────────────────────────────── */
7050
+ .twm-flow-lanes__readonly {
7051
+ flex: 0 0 auto;
7052
+ padding: 7px 12px;
7053
+ background: var(--twm-flow-warning-bg);
7054
+ border-bottom: 1px solid var(--twm-flow-warning-line);
7055
+ color: var(--twm-flow-warning-text);
7056
+ }
7057
+ .twm-flow-lanes__readonly-line {
7058
+ margin: 0;
7059
+ }
7060
+
7061
+ /* ── the toolbar ────────────────────────────────────────────────────── */
7062
+ .twm-flow-lanes__toolbar {
7063
+ flex: 0 0 auto;
7064
+ display: flex;
7065
+ flex-wrap: wrap;
7066
+ align-items: center;
7067
+ gap: 6px;
7068
+ padding: 6px 10px;
7069
+ background: var(--surface-1);
7070
+ border-bottom: 1px solid var(--border-default);
7071
+ }
7072
+ .twm-flow-lanes__toolbar .twm-btn,
7073
+ .twm-flow-lanes__form .twm-btn {
7074
+ min-height: 26px;
7075
+ padding: 0 9px;
7076
+ font-size: var(--font-size-sm);
7077
+ border-radius: 3px;
7078
+ }
7079
+ .twm-flow-lanes__toolbar-slot,
7080
+ .twm-flow-lanes__actions,
7081
+ .twm-flow-lanes__action {
7082
+ display: flex;
7083
+ flex-wrap: wrap;
7084
+ align-items: center;
7085
+ gap: 6px;
7086
+ }
7087
+ .twm-flow-lanes__toolbar-sep {
7088
+ width: 1px;
7089
+ height: 18px;
7090
+ margin: 0 4px;
7091
+ background: var(--surface-3);
7092
+ }
7093
+ .twm-flow-lanes__action--busy .twm-btn {
7094
+ cursor: progress;
7095
+ }
7096
+ .twm-flow-lanes__refusal {
7097
+ color: var(--twm-flow-warning);
7098
+ font-size: var(--font-size-xs);
7099
+ }
7100
+ .twm-flow-lanes__status {
7101
+ margin-left: 8px;
7102
+ color: #a0a0a0;
7103
+ }
7104
+ .twm-flow-lanes__spacer {
7105
+ flex: 1 1 auto;
7106
+ }
7107
+ .twm-flow-lanes__show-label {
7108
+ color: var(--twm-flow-muted);
7109
+ }
7110
+ .twm-flow-lanes__show {
7111
+ display: flex;
7112
+ border: 1px solid var(--surface-3);
7113
+ border-radius: 3px;
7114
+ overflow: hidden;
7115
+ }
7116
+ .twm-flow-lanes__show-btn {
7117
+ height: 24px;
7118
+ padding: 0 10px;
7119
+ border: 0;
7120
+ background: var(--surface-2);
7121
+ color: #c8c8c8;
7122
+ font: inherit;
7123
+ cursor: pointer;
7124
+ }
7125
+ .twm-flow-lanes__show-btn + .twm-flow-lanes__show-btn {
7126
+ border-left: 1px solid var(--surface-3);
7127
+ }
7128
+ .twm-flow-lanes__show-btn[aria-pressed="true"] {
7129
+ background: #0f6fa8;
7130
+ color: var(--text-bright);
7131
+ }
7132
+ .twm-flow-lanes__show-btn:focus-visible,
7133
+ .twm-flow-lanes__param:focus-visible,
7134
+ .twm-flow-lanes__param-add:focus-visible,
7135
+ .twm-flow-lanes__add-source:focus-visible,
7136
+ .twm-flow-lanes__tab:focus-visible,
7137
+ .twm-flow-lanes__datatab:focus-visible,
7138
+ .twm-flow-lanes__menu-item:focus-visible {
7139
+ outline: 2px solid var(--twm-lanes-ring);
7140
+ outline-offset: -2px;
7141
+ }
7142
+
7143
+ /* ── parameters ─────────────────────────────────────────────────────── */
7144
+ .twm-flow-lanes__params {
7145
+ flex: 0 0 auto;
7146
+ display: flex;
7147
+ flex-wrap: wrap;
7148
+ align-items: center;
7149
+ gap: 8px 12px;
7150
+ padding: 7px 12px;
7151
+ background: #222223;
7152
+ border-bottom: 1px solid var(--border-default);
7153
+ }
7154
+ .twm-flow-lanes__params-title {
7155
+ font-size: var(--font-size-xs);
7156
+ font-weight: 600;
7157
+ letter-spacing: .06em;
7158
+ text-transform: uppercase;
7159
+ color: #c4c4c4;
7160
+ }
7161
+ .twm-flow-lanes__param {
7162
+ display: flex;
7163
+ align-items: center;
7164
+ gap: 8px;
7165
+ height: 24px;
7166
+ padding: 0 9px;
7167
+ border: 1px solid var(--surface-3);
7168
+ border-radius: 12px;
7169
+ background: var(--twm-flow-control-bg);
7170
+ color: var(--text-primary);
7171
+ font: inherit;
7172
+ cursor: pointer;
7173
+ }
7174
+ .twm-flow-lanes__param:hover,
7175
+ .twm-flow-lanes__param-add:hover,
7176
+ .twm-flow-lanes__add-source:hover {
7177
+ background: rgba(255, 255, 255, 0.06);
7178
+ }
7179
+ .twm-flow-lanes__param-name {
7180
+ font-family: var(--font-family-mono);
7181
+ color: var(--twm-flow-violet-fg);
7182
+ }
7183
+ .twm-flow-lanes__param-line {
7184
+ color: var(--twm-flow-muted);
7185
+ }
7186
+ .twm-flow-lanes__param-add {
7187
+ display: flex;
7188
+ align-items: center;
7189
+ gap: 5px;
7190
+ height: 24px;
7191
+ padding: 0 8px;
7192
+ border: 1px dashed #4a4a4a;
7193
+ border-radius: 12px;
7194
+ background: transparent;
7195
+ color: #b0b0b0;
7196
+ font: inherit;
7197
+ font-size: var(--font-size-xs);
7198
+ cursor: pointer;
7199
+ }
7200
+ .twm-flow-lanes__param-add .material-symbols-outlined,
7201
+ .twm-flow-lanes__add-source .material-symbols-outlined {
7202
+ font-size: 14px;
7203
+ }
7204
+ .twm-flow-lanes__params-help {
7205
+ color: #a0a0a0;
7206
+ font-size: var(--font-size-xs);
7207
+ }
7208
+
7209
+ /* ── the lanes ──────────────────────────────────────────────────────── */
7210
+ .twm-flow-lanes__flow {
7211
+ flex: 0 1 auto;
7212
+ min-height: 0;
7213
+ overflow-y: auto;
7214
+ background: var(--twm-lanes-surface);
7215
+ border-bottom: 1px solid var(--border-default);
7216
+ }
7217
+ .twm-flow-lanes__banner {
7218
+ margin: 8px 16px 0;
7219
+ padding: 6px 10px;
7220
+ border-radius: var(--radius-sm);
7221
+ background: var(--twm-flow-blue-bg);
7222
+ color: var(--twm-flow-blue-fg);
7223
+ }
7224
+ .twm-flow-lanes__scroller {
7225
+ overflow-x: auto;
7226
+ padding: 14px 0 6px;
7227
+ }
7228
+ /* The page's own scrollbars may be light; these sit on dark surfaces. */
7229
+ .twm-flow-lanes__scroller,
7230
+ .twm-flow-lanes__flow,
7231
+ .twm-flow-lanes__settings,
7232
+ .twm-flow-lanes__databody {
7233
+ scrollbar-color: #4a4a4a transparent;
7234
+ }
7235
+ .twm-flow-lanes__surface {
7236
+ position: relative;
7237
+ z-index: 0;
7238
+ margin: 0 16px;
7239
+ }
7240
+ .twm-flow-lanes__empty {
7241
+ margin: 0;
7242
+ padding: 18px 16px 4px;
7243
+ color: var(--twm-flow-muted);
7244
+ }
7245
+ /* A lane: its band is a pseudo-element, so the lane itself has no border and
7246
+ * a card's `left`/`top` inside it are exactly the layout's numbers. */
7247
+ .twm-flow-lanes__lane {
7248
+ position: absolute;
7249
+ left: 0;
7250
+ right: 0;
7251
+ }
7252
+ .twm-flow-lanes__lane::before {
7253
+ content: '';
7254
+ position: absolute;
7255
+ inset: 0;
7256
+ box-sizing: border-box;
7257
+ border: 1px dashed #2c2c2c;
7258
+ border-radius: 6px;
7259
+ background: rgba(255, 255, 255, 0.018);
7260
+ }
7261
+ .twm-flow-lanes__lane--unconnected::before {
7262
+ border-color: var(--twm-flow-warning-line);
7263
+ }
7264
+ .twm-flow-lanes__flag {
7265
+ position: absolute;
7266
+ top: -8px;
7267
+ left: 12px;
7268
+ padding: 0 6px;
7269
+ font-size: 10px;
7270
+ line-height: 16px;
7271
+ color: var(--twm-flow-warning);
7272
+ background: var(--twm-lanes-surface);
7273
+ }
7274
+ .twm-flow-lanes__wires {
7275
+ position: absolute;
7276
+ left: 0;
7277
+ top: 0;
7278
+ z-index: 1;
7279
+ overflow: visible;
7280
+ pointer-events: none;
7281
+ }
7282
+ .twm-flow-lanes__wire {
7283
+ fill: none;
7284
+ stroke: var(--twm-lanes-wire);
7285
+ stroke-width: 2;
7286
+ stroke-linecap: round;
7287
+ stroke-linejoin: round;
7288
+ }
7289
+ .twm-flow-lanes__wire--cycle {
7290
+ stroke: var(--twm-flow-error);
7291
+ stroke-dasharray: 4 3;
7292
+ }
7293
+ .twm-flow-lanes__port {
7294
+ fill: var(--twm-lanes-wire);
7295
+ stroke: var(--twm-lanes-surface);
7296
+ stroke-width: 3;
7297
+ }
7298
+
7299
+ /* ── a card: an unclipped holder (focus, selection, "+") round a clipped body ── */
7300
+ .twm-flow-lanes__node {
7301
+ position: absolute;
7302
+ z-index: 2;
7303
+ width: var(--twm-lanes-card-w);
7304
+ height: var(--twm-lanes-card-h);
7305
+ }
7306
+ .twm-flow-lanes__node--teal,
7307
+ .twm-flow-lanes__tab--teal {
7308
+ --twm-lanes-icon-bg: var(--twm-flow-teal-icon-bg);
7309
+ --twm-lanes-text-bg: var(--twm-flow-teal-text-bg);
7310
+ --twm-lanes-fg: var(--twm-flow-teal-fg);
7311
+ --twm-lanes-dot: var(--twm-flow-teal-dot);
7312
+ }
7313
+ .twm-flow-lanes__node--indigo,
7314
+ .twm-flow-lanes__tab--indigo {
7315
+ --twm-lanes-icon-bg: var(--twm-flow-indigo-icon-bg);
7316
+ --twm-lanes-text-bg: var(--twm-flow-indigo-text-bg);
7317
+ --twm-lanes-fg: var(--twm-flow-indigo-fg);
7318
+ --twm-lanes-dot: var(--twm-flow-indigo-dot);
7319
+ }
7320
+ .twm-flow-lanes__node--violet,
7321
+ .twm-flow-lanes__tab--violet {
7322
+ --twm-lanes-icon-bg: var(--twm-flow-violet-icon-bg);
7323
+ --twm-lanes-text-bg: var(--twm-flow-violet-text-bg);
7324
+ --twm-lanes-fg: var(--twm-flow-violet-fg);
7325
+ --twm-lanes-dot: var(--twm-flow-violet-dot);
7326
+ }
7327
+ .twm-flow-lanes__node--amber,
7328
+ .twm-flow-lanes__tab--amber {
7329
+ --twm-lanes-icon-bg: var(--twm-flow-amber-icon-bg);
7330
+ --twm-lanes-text-bg: var(--twm-flow-amber-text-bg);
7331
+ --twm-lanes-fg: var(--twm-flow-amber-fg);
7332
+ --twm-lanes-dot: var(--twm-flow-amber-dot);
7333
+ }
7334
+ .twm-flow-lanes__node--blue,
7335
+ .twm-flow-lanes__tab--blue {
7336
+ --twm-lanes-icon-bg: var(--twm-flow-blue-icon-bg);
7337
+ --twm-lanes-text-bg: var(--twm-flow-blue-text-bg);
7338
+ --twm-lanes-fg: var(--twm-flow-blue-fg);
7339
+ --twm-lanes-dot: var(--twm-flow-blue-dot);
7340
+ }
7341
+ .twm-flow-lanes__node--grey,
7342
+ .twm-flow-lanes__tab--grey {
7343
+ --twm-lanes-icon-bg: var(--twm-flow-grey-icon-bg);
7344
+ --twm-lanes-text-bg: var(--twm-flow-grey-text-bg);
7345
+ --twm-lanes-fg: var(--twm-flow-grey-fg);
7346
+ --twm-lanes-dot: var(--twm-flow-grey-dot);
7347
+ }
7348
+ .twm-flow-lanes__card {
7349
+ display: block;
7350
+ width: 100%;
7351
+ height: 100%;
7352
+ padding: 0;
7353
+ border: 0;
7354
+ background: transparent;
7355
+ color: inherit;
7356
+ font: inherit;
7357
+ text-align: left;
7358
+ cursor: pointer;
7359
+ outline: none;
7360
+ }
7361
+ /* The ring is a `drop-shadow` on the unclipped holder: a clip-path cuts a
7362
+ * box-shadow off, a filter on its parent follows the clipped shape. */
7363
+ .twm-flow-lanes__node--warning .twm-flow-lanes__card {
7364
+ filter: drop-shadow(0 0 1px var(--twm-flow-warning)) drop-shadow(0 0 1px var(--twm-flow-warning));
7365
+ }
7366
+ .twm-flow-lanes__node--error .twm-flow-lanes__card {
7367
+ filter: drop-shadow(0 0 1px var(--twm-flow-error)) drop-shadow(0 0 1px var(--twm-flow-error));
7368
+ }
7369
+ .twm-flow-lanes__node--selected .twm-flow-lanes__card,
7370
+ .twm-flow-lanes__card:focus-visible {
7371
+ filter: drop-shadow(0 0 1px var(--twm-lanes-ring)) drop-shadow(0 0 1px var(--twm-lanes-ring))
7372
+ drop-shadow(0 0 5px rgba(22, 131, 196, 0.8));
7373
+ }
7374
+ .twm-flow-lanes__card:hover .twm-flow-lanes__body {
7375
+ filter: brightness(1.12);
7376
+ }
7377
+ .twm-flow-lanes__body {
7378
+ display: flex;
7379
+ width: 100%;
7380
+ height: 100%;
7381
+ background: var(--twm-lanes-text-bg);
7382
+ }
7383
+ /* Three shapes: a source flat on the left, a step notched, a sink flat on the right. */
7384
+ .twm-flow-lanes__node--source .twm-flow-lanes__body {
7385
+ clip-path: polygon(0 0, calc(100% - var(--twm-lanes-notch)) 0, 100% 50%,
7386
+ calc(100% - var(--twm-lanes-notch)) 100%, 0 100%);
7387
+ }
7388
+ .twm-flow-lanes__node--transform .twm-flow-lanes__body,
7389
+ .twm-flow-lanes__node--operation .twm-flow-lanes__body {
7390
+ clip-path: polygon(0 0, calc(100% - var(--twm-lanes-notch)) 0, 100% 50%,
7391
+ calc(100% - var(--twm-lanes-notch)) 100%, 0 100%, var(--twm-lanes-notch) 50%);
7392
+ }
7393
+ .twm-flow-lanes__node--sink .twm-flow-lanes__body {
7394
+ clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, var(--twm-lanes-notch) 50%);
7395
+ }
7396
+ .twm-flow-lanes__icon {
7397
+ flex: 0 0 var(--twm-lanes-icon-w);
7398
+ display: flex;
7399
+ align-items: center;
7400
+ justify-content: center;
7401
+ box-sizing: border-box;
7402
+ padding-left: calc(var(--twm-lanes-notch) - 2px);
7403
+ background: var(--twm-lanes-icon-bg);
7404
+ color: var(--twm-lanes-fg);
7405
+ overflow: hidden;
7406
+ }
7407
+ .twm-flow-lanes__node--source .twm-flow-lanes__icon {
7408
+ flex-basis: var(--twm-lanes-icon-w-source);
7409
+ padding-left: 0;
7410
+ }
7411
+ .twm-flow-lanes__icon .material-symbols-outlined {
7412
+ font-size: 18px;
7413
+ line-height: 1;
7414
+ }
7415
+ .twm-flow-lanes__sep {
7416
+ flex: 0 0 1px;
7417
+ background: rgba(255, 255, 255, 0.08);
7418
+ }
7419
+ .twm-flow-lanes__text {
7420
+ flex: 1 1 auto;
7421
+ min-width: 0;
7422
+ display: flex;
7423
+ flex-direction: column;
7424
+ justify-content: center;
7425
+ gap: 1px;
7426
+ padding: 0 18px 0 9px;
7427
+ }
7428
+ .twm-flow-lanes__title,
7429
+ .twm-flow-lanes__sub,
7430
+ .twm-flow-lanes__line {
7431
+ white-space: nowrap;
7432
+ overflow: hidden;
7433
+ text-overflow: ellipsis;
7434
+ }
7435
+ .twm-flow-lanes__title {
7436
+ color: #ececec;
7437
+ font-weight: 600;
7438
+ }
7439
+ .twm-flow-lanes__sub {
7440
+ color: #b0b0b0;
7441
+ font-size: var(--font-size-xs);
7442
+ }
7443
+ .twm-flow-lanes__line {
7444
+ font-size: 10px;
7445
+ }
7446
+ .twm-flow-lanes__line--ok { color: var(--twm-flow-ok); }
7447
+ .twm-flow-lanes__line--warning { color: var(--twm-flow-warning); }
7448
+ .twm-flow-lanes__line--error { color: var(--twm-flow-error); }
7449
+ .twm-flow-lanes__line--muted { color: #b0b0b0; }
7450
+ .twm-flow-lanes__line--info { color: var(--twm-flow-blue-fg); }
7451
+ /* "+" on the card's right tip: on hover, on focus and on the chosen card —
7452
+ * never on hover alone. */
7453
+ .twm-flow-lanes__add {
7454
+ position: absolute;
7455
+ right: -14px;
7456
+ top: -9px;
7457
+ z-index: 3;
7458
+ width: 18px;
7459
+ height: 18px;
7460
+ display: flex;
7461
+ align-items: center;
7462
+ justify-content: center;
7463
+ padding: 0;
7464
+ border: 1px solid #4a4a4a;
7465
+ border-radius: 9px;
7466
+ background: var(--surface-1);
7467
+ color: #d0d0d0;
7468
+ cursor: pointer;
7469
+ opacity: 0;
7470
+ }
7471
+ .twm-flow-lanes__node:hover .twm-flow-lanes__add,
7472
+ .twm-flow-lanes__node:focus-within .twm-flow-lanes__add,
7473
+ .twm-flow-lanes__node--selected .twm-flow-lanes__add {
7474
+ opacity: 1;
7475
+ }
7476
+ .twm-flow-lanes__add:hover,
7477
+ .twm-flow-lanes__add:focus-visible {
7478
+ background: var(--twm-lanes-ring);
7479
+ border-color: var(--twm-lanes-ring);
7480
+ color: var(--text-bright);
7481
+ outline: none;
7482
+ }
7483
+ .twm-flow-lanes__add .material-symbols-outlined {
7484
+ font-size: 14px;
7485
+ line-height: 1;
7486
+ }
7487
+
7488
+ /* the small cards: a title and one line */
7489
+ .twm-flow-lanes--small .twm-flow-lanes__sub {
7490
+ display: none;
7491
+ }
7492
+ .twm-flow-lanes--small .twm-flow-lanes__text {
7493
+ padding: 0 16px 0 8px;
7494
+ }
7495
+ .twm-flow-lanes--small .twm-flow-lanes__line {
7496
+ font-size: 10.5px;
7497
+ }
7498
+ .twm-flow-lanes--small .twm-flow-lanes__icon .material-symbols-outlined {
7499
+ font-size: 14px;
7500
+ }
7501
+
7502
+ /* the compact strip: a title a card, and nothing to press */
7503
+ .twm-flow-lanes--compact .twm-flow-lanes__flow {
7504
+ background: transparent;
7505
+ border-bottom: 0;
7506
+ overflow: visible;
7507
+ }
7508
+ .twm-flow-lanes--compact .twm-flow-lanes__scroller {
7509
+ padding: 0;
7510
+ }
7511
+ .twm-flow-lanes--compact .twm-flow-lanes__surface {
7512
+ margin: 0;
7513
+ }
7514
+ .twm-flow-lanes--strip .twm-flow-lanes__lane::before {
7515
+ display: none;
7516
+ }
7517
+ .twm-flow-lanes--strip .twm-flow-lanes__body {
7518
+ background: var(--twm-lanes-icon-bg);
7519
+ }
7520
+ .twm-flow-lanes--strip .twm-flow-lanes__text {
7521
+ padding: 0 12px 0 13px;
7522
+ }
7523
+ .twm-flow-lanes--strip .twm-flow-lanes__node--source .twm-flow-lanes__text {
7524
+ padding: 0 12px 0 8px;
7525
+ }
7526
+ .twm-flow-lanes--strip .twm-flow-lanes__node--sink .twm-flow-lanes__text {
7527
+ padding: 0 6px 0 13px;
7528
+ }
7529
+ .twm-flow-lanes--strip .twm-flow-lanes__title {
7530
+ color: #e6e6e6;
7531
+ font-size: 10.5px;
7532
+ font-weight: 400;
7533
+ }
7534
+
7535
+ /* ── under the lanes: Add a source ──────────────────────────────────── */
7536
+ .twm-flow-lanes__foot {
7537
+ display: flex;
7538
+ flex-wrap: wrap;
7539
+ align-items: center;
7540
+ gap: 10px 16px;
7541
+ padding: 4px 16px 12px;
7542
+ }
7543
+ .twm-flow-lanes__add-source {
7544
+ display: flex;
7545
+ align-items: center;
7546
+ gap: 6px;
7547
+ height: 28px;
7548
+ padding: 0 12px;
7549
+ border: 1px dashed #4a4a4a;
7550
+ border-radius: var(--radius-sm);
7551
+ background: transparent;
7552
+ color: #b8b8b8;
7553
+ font: inherit;
7554
+ cursor: pointer;
7555
+ }
7556
+ .twm-flow-lanes__hint {
7557
+ color: #9a9a9a;
7558
+ font-size: var(--font-size-xs);
7559
+ }
7560
+
7561
+ /* ── a tab per step ─────────────────────────────────────────────────── */
7562
+ .twm-flow-lanes__tabs {
7563
+ flex: 0 0 auto;
7564
+ display: flex;
7565
+ flex-wrap: wrap;
7566
+ align-items: stretch;
7567
+ gap: 0 2px;
7568
+ padding: 0 12px;
7569
+ background: var(--surface-1);
7570
+ border-bottom: 1px solid var(--border-default);
7571
+ }
7572
+ .twm-flow-lanes__tab,
7573
+ .twm-flow-lanes__datatab {
7574
+ display: flex;
7575
+ align-items: center;
7576
+ gap: 7px;
7577
+ height: 32px;
7578
+ padding: 0 11px;
7579
+ border: 0;
7580
+ border-bottom: 2px solid transparent;
7581
+ background: transparent;
7582
+ color: #b4b4b4;
7583
+ font: inherit;
7584
+ cursor: pointer;
7585
+ }
7586
+ .twm-flow-lanes__tab:hover,
7587
+ .twm-flow-lanes__datatab:hover {
7588
+ background: rgba(255, 255, 255, 0.05);
7589
+ }
7590
+ .twm-flow-lanes__tab[aria-selected="true"],
7591
+ .twm-flow-lanes__datatab[aria-pressed="true"] {
7592
+ border-bottom-color: var(--twm-lanes-ring);
7593
+ color: var(--text-bright);
7594
+ }
7595
+ .twm-flow-lanes__tab-dot {
7596
+ flex: 0 0 7px;
7597
+ height: 7px;
7598
+ border-radius: 4px;
7599
+ background: var(--twm-lanes-dot);
7600
+ }
7601
+ .twm-flow-lanes__tab-label {
7602
+ max-width: 220px;
7603
+ white-space: nowrap;
7604
+ overflow: hidden;
7605
+ text-overflow: ellipsis;
7606
+ }
7607
+
7608
+ /* ── the dock: the settings beside what the step gives ──────────────── */
7609
+ .twm-flow-lanes__dock {
7610
+ flex: 1 1 0;
7611
+ min-height: 240px;
7612
+ display: flex;
7613
+ align-items: stretch;
7614
+ }
7615
+ .twm-flow-lanes--auto .twm-flow-lanes__dock {
7616
+ flex: 0 0 auto;
7617
+ }
7618
+ .twm-flow-lanes__settings {
7619
+ flex: 1 1 400px;
7620
+ min-width: 260px;
7621
+ min-height: 0;
7622
+ overflow-y: auto;
7623
+ background: #232324;
7624
+ border-right: 1px solid var(--border-default);
7625
+ }
7626
+ .twm-flow-lanes__settings .twm-flow-panel {
7627
+ background: transparent;
7628
+ }
7629
+ .twm-flow-lanes__settings-hint {
7630
+ margin: 0;
7631
+ padding: 16px 20px;
7632
+ color: var(--twm-flow-muted);
7633
+ }
7634
+ .twm-flow-lanes__data {
7635
+ flex: 1.2 1 440px;
7636
+ min-width: 0;
7637
+ min-height: 0;
7638
+ display: flex;
7639
+ flex-direction: column;
7640
+ }
7641
+ .twm-flow-lanes__datatabs {
7642
+ flex: 0 0 auto;
7643
+ display: flex;
7644
+ align-items: stretch;
7645
+ gap: 0 2px;
7646
+ padding: 0 12px;
7647
+ border-bottom: 1px solid var(--border-default);
7648
+ }
7649
+ .twm-flow-lanes__datastate {
7650
+ display: flex;
7651
+ align-items: center;
7652
+ gap: 6px;
7653
+ min-width: 0;
7654
+ color: #a0a0a0;
7655
+ font-size: var(--font-size-xs);
7656
+ white-space: nowrap;
7657
+ }
7658
+ .twm-flow-lanes__datastate-text {
7659
+ overflow: hidden;
7660
+ text-overflow: ellipsis;
7661
+ }
7662
+ .twm-flow-lanes__datastate-dot {
7663
+ flex: 0 0 7px;
7664
+ height: 7px;
7665
+ border-radius: 4px;
7666
+ }
7667
+ .twm-flow-lanes__datastate--ok .twm-flow-lanes__datastate-dot { background: var(--twm-flow-ok); }
7668
+ .twm-flow-lanes__datastate--busy .twm-flow-lanes__datastate-dot { background: var(--twm-flow-warning); }
7669
+ .twm-flow-lanes__datastate--error .twm-flow-lanes__datastate-dot { background: var(--twm-flow-error); }
7670
+ .twm-flow-lanes__databody {
7671
+ flex: 1 1 0;
7672
+ min-height: 0;
7673
+ display: flex;
7674
+ flex-direction: column;
7675
+ padding: 0 14px 12px;
7676
+ overflow: auto;
7677
+ }
7678
+ .twm-flow-lanes__caption {
7679
+ flex: 0 0 auto;
7680
+ margin: 0;
7681
+ padding: 8px 0 6px;
7682
+ color: #b4b4b4;
7683
+ }
7684
+ /* A DataTable fills this box, so the box has a size: one with none draws a
7685
+ * header and no rows. */
7686
+ .twm-flow-lanes__table {
7687
+ flex: 1 1 0;
7688
+ min-height: 120px;
7689
+ border: 1px solid #333;
7690
+ border-radius: 3px;
7691
+ overflow: hidden;
7692
+ }
7693
+ .twm-flow-lanes__cell--new,
7694
+ .twm-flow-lanes__cell--changed {
7695
+ background: rgba(22, 131, 196, 0.07);
7696
+ }
7697
+ .twm-flow-lanes__error {
7698
+ flex: 0 0 auto;
7699
+ margin: 8px 0 0;
7700
+ padding: 7px 10px;
7701
+ border-radius: var(--radius-sm);
7702
+ background: var(--twm-flow-error-bg);
7703
+ border: 1px solid var(--twm-flow-error-line);
7704
+ color: var(--twm-flow-error-text);
7705
+ }
7706
+ .twm-flow-lanes__nodata {
7707
+ margin: 0;
7708
+ padding: 12px 0;
7709
+ color: var(--twm-flow-muted);
7710
+ }
7711
+ .twm-flow-lanes__columns {
7712
+ list-style: none;
7713
+ margin: 0;
7714
+ padding: 0;
7715
+ display: grid;
7716
+ grid-template-columns: repeat(2, minmax(0, 1fr));
7717
+ gap: 4px 12px;
7718
+ }
7719
+ .twm-flow-lanes__column {
7720
+ display: flex;
7721
+ align-items: baseline;
7722
+ gap: 8px;
7723
+ min-width: 0;
7724
+ padding: 5px 8px;
7725
+ border-bottom: 1px solid var(--border-subtle);
7726
+ }
7727
+ .twm-flow-lanes__column--new,
7728
+ .twm-flow-lanes__column--changed {
7729
+ background: rgba(22, 131, 196, 0.14);
7730
+ }
7731
+ .twm-flow-lanes__column-name {
7732
+ font-family: var(--font-family-mono);
7733
+ font-size: var(--font-size-xs);
7734
+ color: #e6e6e6;
7735
+ }
7736
+ .twm-flow-lanes__column-type {
7737
+ color: #9a9a9a;
7738
+ font-size: var(--font-size-xs);
7739
+ }
7740
+ .twm-flow-lanes__column--new .twm-flow-lanes__column-type,
7741
+ .twm-flow-lanes__column--changed .twm-flow-lanes__column-type {
7742
+ color: #9fd0f0;
7743
+ }
7744
+ .twm-flow-lanes__column-origin {
7745
+ margin-left: auto;
7746
+ color: #a0a0a0;
7747
+ font-size: var(--font-size-xs);
7748
+ text-align: right;
7749
+ }
7750
+ .twm-flow-lanes__rejects {
7751
+ list-style: none;
7752
+ margin: 0;
7753
+ padding: 0;
7754
+ display: flex;
7755
+ flex-direction: column;
7756
+ gap: 4px;
7757
+ }
7758
+ .twm-flow-lanes__reject {
7759
+ display: flex;
7760
+ flex-wrap: wrap;
7761
+ align-items: baseline;
7762
+ gap: 4px 12px;
7763
+ padding: 7px 10px;
7764
+ background: var(--twm-flow-warning-bg);
7765
+ border: 1px solid var(--twm-flow-warning-line);
7766
+ border-radius: var(--radius-sm);
7767
+ }
7768
+ .twm-flow-lanes__reject-key {
7769
+ font-family: var(--font-family-mono);
7770
+ font-size: var(--font-size-xs);
7771
+ color: #ecc788;
7772
+ }
7773
+ .twm-flow-lanes__reject-value {
7774
+ color: var(--text-primary);
7775
+ }
7776
+ .twm-flow-lanes__reject-reason {
7777
+ flex: 1 1 260px;
7778
+ color: #d0c0a4;
7779
+ }
7780
+
7781
+ /* ── a parameter's form and a card's menu, in the kit's popover ─────── */
7782
+ .twm-flow-lanes__popover {
7783
+ min-width: 220px;
7784
+ }
7785
+ .twm-flow-lanes__form {
7786
+ display: flex;
7787
+ flex-direction: column;
7788
+ gap: 8px;
7789
+ box-sizing: border-box;
7790
+ width: 320px;
7791
+ max-width: 100%;
7792
+ padding: 12px;
7793
+ }
7794
+ .twm-flow-lanes__form-title {
7795
+ font-weight: 600;
7796
+ color: var(--text-primary);
7797
+ }
7798
+ .twm-flow-lanes__form-row {
7799
+ display: grid;
7800
+ grid-template-columns: 90px minmax(0, 1fr);
7801
+ align-items: center;
7802
+ gap: 8px;
7803
+ }
7804
+ .twm-flow-lanes__form-label {
7805
+ color: #c8c8c8;
7806
+ }
7807
+ .twm-flow-lanes__form-control {
7808
+ display: block;
7809
+ min-width: 0;
7810
+ }
7811
+ .twm-flow-lanes__form-refusal {
7812
+ margin: 0;
7813
+ color: var(--twm-flow-error);
7814
+ }
7815
+ .twm-flow-lanes__form-actions {
7816
+ display: flex;
7817
+ flex-wrap: wrap;
7818
+ justify-content: flex-end;
7819
+ gap: 6px;
7820
+ }
7821
+ .twm-flow-lanes__menu {
7822
+ display: flex;
7823
+ flex-direction: column;
7824
+ min-width: 200px;
7825
+ padding: 4px;
7826
+ }
7827
+ .twm-flow-lanes__menu-item {
7828
+ display: flex;
7829
+ align-items: center;
7830
+ gap: 8px;
7831
+ height: 28px;
7832
+ padding: 0 10px;
7833
+ border: 0;
7834
+ border-radius: 3px;
7835
+ background: transparent;
7836
+ color: var(--text-body);
7837
+ font: inherit;
7838
+ text-align: left;
7839
+ cursor: pointer;
7840
+ }
7841
+ .twm-flow-lanes__menu-item:hover,
7842
+ .twm-flow-lanes__menu-item:focus-visible {
7843
+ background: var(--state-active);
7844
+ }
7845
+ .twm-flow-lanes__menu-item:disabled {
7846
+ opacity: 0.45;
7847
+ cursor: not-allowed;
7848
+ }
7849
+ .twm-flow-lanes__menu-item--danger {
7850
+ color: var(--twm-flow-error);
7851
+ }
7852
+ .twm-flow-lanes__menu-item .material-symbols-outlined {
7853
+ font-size: 16px;
7854
+ line-height: 1;
7855
+ }
7856
+ /* ══ end FLOW · LANES ══ */