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