@worca/ui 0.38.0 → 0.41.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.
package/app/styles.css CHANGED
@@ -10,6 +10,16 @@
10
10
  --bg: #ffffff;
11
11
  --bg-secondary: #f8fafc;
12
12
  --bg-tertiary: #f1f5f9;
13
+ /* Card / panel surface. `--surface` was used in several places
14
+ * (`.run-card`, sidebar widgets, settings cards) without ever
15
+ * being defined, so it silently resolved to `unset` → no
16
+ * background. That was invisible while the page background and
17
+ * cards were both white, but the moment a parent panel tinted
18
+ * itself gray (e.g. `.pipelines-tier-section` → `--bg-secondary`)
19
+ * the cards turned transparent. Alias it to `--bg` so cards
20
+ * always render on a white (light) / dark-slate (dark) surface
21
+ * regardless of what's behind them. */
22
+ --surface: var(--bg);
13
23
  --border: #e2e8f0;
14
24
  --border-subtle: rgba(226, 232, 240, 0.6);
15
25
  --muted: #94a3b8;
@@ -145,15 +155,50 @@ h1, h2, h3, h4, h5, h6 {
145
155
  }
146
156
 
147
157
  .sidebar.collapsed .sidebar-section-header,
148
- .sidebar.collapsed .sidebar-item span,
158
+ /* `.sidebar-item-left > span` targets only label spans — the outer
159
+ `.sidebar-item-left` is itself a span and would have been swept up
160
+ by the broader `.sidebar-item span` selector, hiding the icon too. */
161
+ .sidebar.collapsed .sidebar-item-left > span,
149
162
  .sidebar.collapsed .conn-label,
150
- .sidebar.collapsed .logo-text {
163
+ .sidebar.collapsed .logo-text,
164
+ .sidebar.collapsed .sidebar-project-section,
165
+ .sidebar.collapsed .sidebar-new-run-chevron-dropdown {
151
166
  display: none;
152
167
  }
153
168
 
169
+ /* In the collapsed rail, nav items become icon-only — center them so they
170
+ sit under the toggle button rather than floating against the left edge. */
171
+ .sidebar.collapsed .sidebar-item {
172
+ justify-content: center;
173
+ margin: 2px 6px;
174
+ padding: 8px 6px;
175
+ }
176
+ .sidebar.collapsed .sidebar-item-left {
177
+ gap: 0;
178
+ }
179
+ .sidebar.collapsed .sidebar-new-run {
180
+ padding: 4px 6px;
181
+ }
182
+ .sidebar.collapsed .sidebar-new-run-split {
183
+ width: auto;
184
+ }
185
+ .sidebar.collapsed .sidebar-footer {
186
+ justify-content: center;
187
+ padding: 12px 6px;
188
+ }
189
+
154
190
  .sidebar-logo {
155
- padding: 20px 16px 12px;
191
+ padding: 16px 12px 12px 16px;
156
192
  border-bottom: 1px solid var(--border-subtle);
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: space-between;
196
+ gap: 8px;
197
+ }
198
+
199
+ .sidebar.collapsed .sidebar-logo {
200
+ justify-content: center;
201
+ padding: 16px 6px 12px;
157
202
  }
158
203
 
159
204
  .logo-text {
@@ -164,6 +209,35 @@ h1, h2, h3, h4, h5, h6 {
164
209
  color: var(--fg);
165
210
  }
166
211
 
212
+ .sidebar-toggle-btn {
213
+ display: inline-flex;
214
+ align-items: center;
215
+ justify-content: center;
216
+ width: 28px;
217
+ height: 28px;
218
+ padding: 0;
219
+ border: 1px solid transparent;
220
+ border-radius: var(--radius);
221
+ background: transparent;
222
+ color: var(--muted);
223
+ cursor: pointer;
224
+ flex-shrink: 0;
225
+ transition:
226
+ background var(--transition-fast),
227
+ color var(--transition-fast),
228
+ border-color var(--transition-fast);
229
+ }
230
+
231
+ .sidebar-toggle-btn:hover {
232
+ background: var(--border);
233
+ color: var(--fg);
234
+ }
235
+
236
+ .sidebar-toggle-btn:focus-visible {
237
+ outline: none;
238
+ border-color: var(--accent);
239
+ }
240
+
167
241
  /* --- 6. Sidebar Sections --- */
168
242
  .sidebar-section {
169
243
  padding: 8px 0;
@@ -400,529 +474,1072 @@ h1, h2, h3, h4, h5, h6 {
400
474
  color: #ffffff;
401
475
  }
402
476
 
477
+ .action-btn--ghost {
478
+ border-color: transparent;
479
+ color: var(--text-muted);
480
+ }
481
+
482
+ .action-btn--ghost:hover {
483
+ border-color: var(--border);
484
+ color: var(--text);
485
+ }
486
+
403
487
  .action-btn:disabled {
404
488
  opacity: 0.6;
405
489
  cursor: not-allowed;
406
490
  }
407
491
 
408
- .action-btn:disabled:hover {
409
- background: var(--bg-secondary);
410
- color: inherit;
411
- }
412
-
413
- .error-dialog-body {
492
+ .run-stage-actions {
414
493
  display: flex;
415
494
  align-items: center;
416
- gap: 16px;
417
- padding: 8px 0;
418
- }
419
- .error-dialog-body p {
420
- margin: 0;
421
- font-size: 14px;
422
- line-height: 1.5;
423
- }
424
- .error-dialog-icon {
425
- color: var(--status-error);
426
- flex-shrink: 0;
495
+ justify-content: flex-end;
496
+ gap: 6px;
497
+ padding: 0 0 4px;
498
+ flex-wrap: wrap;
427
499
  }
428
500
 
429
- /* --- 10. Run Header --- */
430
- .run-header {
431
- display: flex;
432
- align-items: flex-start;
433
- justify-content: space-between;
434
- padding: 16px 0;
435
- margin-bottom: 16px;
436
- border-bottom: 1px solid var(--border-subtle);
501
+ /* --- Run Timeline ---
502
+ Local tokens layered on the global palette. --text-strong gives a
503
+ WCAG-AA-safe muted color for labels (4.5:1 on white at 12-13px), avoiding
504
+ the very pale --muted (#94a3b8). All other colors route through brand vars
505
+ so dark mode and theme tweaks land for free. */
506
+ .run-timeline {
507
+ --tl-text-strong: #475569;
508
+ --tl-row-alt-bg: rgba(15, 23, 42, 0.04);
509
+ --tl-row-divider: rgba(15, 23, 42, 0.08);
510
+ --tl-grid-line: rgba(15, 23, 42, 0.05);
511
+ --tl-axis-line: rgba(15, 23, 42, 0.18);
512
+ --tl-axis-tick: rgba(15, 23, 42, 0.28);
513
+ --tl-axis-label: rgba(15, 23, 42, 0.62);
514
+ --tl-row-label: rgba(15, 23, 42, 0.78);
515
+ --tl-row-label-count: rgba(15, 23, 42, 0.45);
516
+ --tl-loopback-default-opacity: 0.7;
517
+ --tl-loopback-hint: rgba(15, 23, 42, 0.4);
518
+ --tl-bar-stroke: rgba(15, 23, 42, 0.22);
519
+ --tl-bar-shadow: rgba(15, 23, 42, 0.22);
520
+ --timeline-gap-fill: rgba(15, 23, 42, 0.04);
521
+ --timeline-gap-dot: rgba(15, 23, 42, 0.32);
522
+
523
+ padding: 16px 20px 24px;
524
+ background: var(--bg, #fff);
525
+ border: 1px solid var(--border-subtle, rgba(226, 232, 240, 0.6));
526
+ border-radius: 10px;
527
+ overflow-x: auto;
528
+ position: relative;
437
529
  }
438
530
 
439
- .run-header-left {
531
+ /* worca-ui drives dark mode via [data-theme="dark"] on the html element,
532
+ not via prefers-color-scheme. Both selectors here so the timeline tokens
533
+ flip with the rest of the chrome. */
534
+ [data-theme="dark"] .run-timeline,
535
+ .run-timeline[data-theme="dark"] {
536
+ --tl-text-strong: #cbd5e1;
537
+ --tl-row-alt-bg: rgba(255, 255, 255, 0.04);
538
+ --tl-row-divider: rgba(255, 255, 255, 0.1);
539
+ --tl-grid-line: rgba(255, 255, 255, 0.07);
540
+ --tl-axis-line: rgba(255, 255, 255, 0.22);
541
+ --tl-axis-tick: rgba(255, 255, 255, 0.35);
542
+ --tl-axis-label: rgba(255, 255, 255, 0.7);
543
+ --tl-row-label: rgba(255, 255, 255, 0.9);
544
+ --tl-row-label-count: rgba(255, 255, 255, 0.55);
545
+ --tl-loopback-hint: rgba(255, 255, 255, 0.5);
546
+ --tl-bar-stroke: rgba(255, 255, 255, 0.32);
547
+ --tl-bar-shadow: rgba(0, 0, 0, 0.45);
548
+ --timeline-gap-fill: rgba(255, 255, 255, 0.06);
549
+ --timeline-gap-dot: rgba(255, 255, 255, 0.4);
550
+ }
551
+
552
+ /* Top stats summary */
553
+ .timeline-summary {
554
+ display: flex;
555
+ align-items: center;
556
+ gap: 28px;
557
+ /* Right-padding reserves space for the absolutely-positioned .timeline-toolbar
558
+ anchored at top:16px / right:20px so the stats never run under the buttons. */
559
+ padding: 4px 260px 16px 0;
560
+ flex-wrap: wrap;
561
+ }
562
+ .summary-stat {
440
563
  display: flex;
441
- align-items: center;
442
- gap: 12px;
564
+ flex-direction: column;
565
+ gap: 2px;
566
+ min-width: 64px;
443
567
  }
444
-
445
- .run-title {
446
- font-size: 22px;
568
+ .summary-stat-label {
569
+ font-size: 11px;
570
+ text-transform: uppercase;
571
+ letter-spacing: 0.04em;
572
+ color: var(--tl-text-strong);
573
+ font-weight: 500;
574
+ }
575
+ .summary-stat-value {
576
+ font-size: 18px;
447
577
  font-weight: 600;
448
- color: var(--fg);
449
- letter-spacing: -0.01em;
578
+ color: var(--fg, #0f172a);
579
+ font-variant-numeric: tabular-nums;
580
+ }
581
+ .summary-spacer {
582
+ flex: 1;
450
583
  }
451
584
 
452
- .run-header-right {
585
+ /* Toolbar — anchored to the top-right corner of the timeline box.
586
+ Stacks the zoom button group above the keyboard-hint text, both right-aligned. */
587
+ .timeline-toolbar {
588
+ position: absolute;
589
+ top: 16px;
590
+ right: 20px;
591
+ z-index: 2;
453
592
  display: flex;
593
+ flex-direction: column;
594
+ align-items: flex-end;
595
+ gap: 6px;
596
+ }
597
+ .timeline-toolbar-group {
598
+ display: inline-flex;
599
+ border: 1px solid var(--border, #e2e8f0);
600
+ border-radius: 6px;
601
+ overflow: hidden;
602
+ background: var(--bg, #fff);
603
+ }
604
+ .timeline-zoom-btn {
605
+ display: inline-flex;
454
606
  align-items: center;
455
- gap: 16px;
607
+ justify-content: center;
608
+ min-width: 30px;
609
+ height: 28px;
610
+ padding: 0 8px;
611
+ border: none;
612
+ background: transparent;
613
+ color: var(--tl-text-strong);
614
+ cursor: pointer;
615
+ user-select: none;
616
+ border-right: 1px solid var(--border, #e2e8f0);
617
+ }
618
+ .timeline-zoom-btn:last-child {
619
+ border-right: none;
620
+ }
621
+ .timeline-zoom-btn:hover {
622
+ background: var(--bg-secondary, #f8fafc);
623
+ color: var(--fg, #0f172a);
624
+ }
625
+ .timeline-zoom-btn:active {
626
+ background: var(--bg-tertiary, #f1f5f9);
627
+ }
628
+ .timeline-zoom-btn:focus-visible {
629
+ outline: 2px solid var(--accent, #3b82f6);
630
+ outline-offset: -2px;
631
+ z-index: 1;
632
+ }
633
+ .timeline-toolbar-hint {
634
+ font-size: 11px;
635
+ color: var(--tl-text-strong);
636
+ text-align: right;
456
637
  }
457
638
 
458
- .run-meta {
459
- font-size: 13px;
460
- color: var(--muted);
639
+ /* SVG wrapper */
640
+ .timeline-svg-wrap {
641
+ position: relative;
642
+ overflow: visible;
461
643
  }
462
644
 
463
- .meta-label {
464
- font-weight: 500;
465
- color: var(--fg);
466
- opacity: 0.7;
645
+ /* Row backgrounds */
646
+ .row-bg-alt {
647
+ fill: var(--tl-row-alt-bg);
648
+ }
649
+ .row-divider {
650
+ stroke: var(--tl-row-divider);
651
+ stroke-width: 1;
652
+ shape-rendering: crispEdges;
653
+ }
654
+ .grid-line {
655
+ stroke: var(--tl-grid-line);
656
+ stroke-width: 1;
657
+ shape-rendering: crispEdges;
467
658
  }
468
659
 
469
- .meta-value {
660
+ /* Row labels — match the uppercase tracking used by .pipeline-stage-name so
661
+ timeline rows read like the stage section headers elsewhere in the UI. */
662
+ .row-label {
663
+ font-size: 12px;
470
664
  font-weight: 600;
471
- color: var(--fg);
665
+ fill: var(--tl-row-label);
666
+ font-family: var(--sl-font-sans, system-ui, sans-serif);
667
+ text-transform: uppercase;
668
+ letter-spacing: 0.03em;
472
669
  }
473
-
474
- .run-pr-link {
475
- color: var(--accent);
476
- text-decoration: none;
670
+ .row-label-count {
671
+ font-size: 11px;
477
672
  font-weight: 500;
673
+ fill: var(--tl-row-label-count);
674
+ text-transform: none;
675
+ letter-spacing: 0;
478
676
  }
479
-
480
- .run-pr-link:hover {
481
- text-decoration: underline;
677
+ .loopback-hint {
678
+ font-size: 10px;
679
+ fill: var(--tl-loopback-hint);
680
+ pointer-events: none;
482
681
  }
483
682
 
484
- .run-meta-grid {
485
- display: flex;
486
- flex-direction: column;
487
- gap: 6px;
488
- padding: 12px 16px;
489
- background: var(--bg-hover);
490
- border-radius: var(--radius-md);
491
- margin-bottom: 8px;
492
- font-size: 13px;
493
- color: var(--muted);
494
- font-variant-numeric: tabular-nums;
683
+ /* Bars
684
+ Default: thin contrasting hairline stroke so bar edges read clearly without
685
+ any per-bar divider. Hover/active: lift via translateY + drop-shadow so the
686
+ bar "raises" off the chart. Active state persists while the iteration drawer
687
+ is open (driven by the .is-active class). Reduced-motion drops the lift. */
688
+ .timeline-bar {
689
+ cursor: pointer;
690
+ stroke: var(--tl-bar-stroke);
691
+ stroke-width: 1;
692
+ transition:
693
+ filter 130ms ease,
694
+ transform 130ms ease,
695
+ stroke-width 130ms ease;
696
+ /* SVG rect transforms relative to the SVG viewport origin, not the rect
697
+ itself — fine for translateY since we want a small vertical lift. */
698
+ }
699
+ .timeline-bar:hover,
700
+ .timeline-bar.is-active {
701
+ filter: drop-shadow(0 3px 6px var(--tl-bar-shadow));
702
+ transform: translateY(-1px);
703
+ stroke-width: 1.25;
495
704
  }
496
-
497
- .run-meta-row {
498
- display: flex;
499
- flex-wrap: wrap;
500
- gap: 4px 20px;
705
+ .timeline-bar:focus-visible {
706
+ /* Subtle keyboard-focus indicator — no bold ring. The raised+shadow state
707
+ above also kicks in on focus via :focus-visible :is() below. */
708
+ outline: 1.5px dashed var(--accent, #3b82f6);
709
+ outline-offset: 2px;
501
710
  }
502
-
503
- .timing-strip {
504
- display: flex;
505
- flex-wrap: wrap;
506
- gap: 4px 20px;
507
- font-size: 13px;
508
- color: var(--muted);
711
+ .timeline-bar:focus-visible {
712
+ filter: drop-shadow(0 3px 6px var(--tl-bar-shadow));
713
+ transform: translateY(-1px);
714
+ }
715
+ @media (prefers-reduced-motion: reduce) {
716
+ .timeline-bar,
717
+ .timeline-bar:hover,
718
+ .timeline-bar.is-active,
719
+ .timeline-bar:focus-visible {
720
+ transform: none;
721
+ }
722
+ }
723
+ .bar-label {
724
+ font-size: 10px;
725
+ font-weight: 600;
726
+ fill: #fff;
727
+ font-family: var(--sl-font-sans, system-ui, sans-serif);
509
728
  font-variant-numeric: tabular-nums;
729
+ letter-spacing: 0.02em;
510
730
  }
511
731
 
512
- .timing-strip-item {
513
- white-space: nowrap;
732
+ /* Gaps */
733
+ .timeline-gap {
734
+ cursor: default;
514
735
  }
515
-
516
- .run-card .timing-strip {
517
- font-size: 12px;
518
- gap: 6px 16px;
519
- padding-left: 26px;
736
+ .timeline-gap:focus-visible {
737
+ outline: 2px solid var(--accent, #3b82f6);
738
+ outline-offset: 1px;
520
739
  }
521
-
522
- .stage-detail .timing-strip {
523
- margin-bottom: 8px;
524
- padding-bottom: 8px;
525
- border-bottom: 1px solid var(--border);
740
+ .gap-bg {
741
+ fill: var(--timeline-gap-fill);
526
742
  }
527
-
528
- .run-info-section {
529
- padding: 12px 16px;
530
- background: var(--bg-hover);
531
- border-radius: var(--radius-md);
532
- margin-bottom: 8px;
533
- display: flex;
534
- flex-direction: column;
535
- gap: 6px;
743
+ .gap-dot {
744
+ fill: var(--timeline-gap-dot);
536
745
  }
537
746
 
538
- /* Project / Branch / Pipeline-Template / Worktree rows inside
539
- `.run-info-section` all share the same label-value typography so the
540
- block reads as a uniform stack. Mirror .run-group below it. */
541
- .run-project,
542
- .run-branch,
543
- .run-template,
544
- .run-worktree {
545
- display: flex;
546
- align-items: center;
547
- gap: 6px;
548
- font-size: 13px;
747
+ /* Loopbacks */
748
+ .loopback {
749
+ stroke-opacity: var(--tl-loopback-default-opacity);
750
+ transition: stroke-opacity 120ms ease, stroke-width 120ms ease;
549
751
  }
550
-
551
- .pipeline-cost-strip {
552
- display: flex;
553
- flex-wrap: wrap;
554
- gap: 4px 20px;
555
- font-size: 13px;
556
- font-weight: 600;
557
- color: var(--fg);
752
+ .loopback.highlight {
753
+ stroke-opacity: 1;
754
+ stroke-width: 2.5;
558
755
  }
559
756
 
560
- /* Pipeline timing bar */
561
- .pipeline-timing-bar-container {
562
- margin-top: 8px;
757
+ /* Time axis */
758
+ .axis-baseline {
759
+ stroke: var(--tl-axis-line);
760
+ stroke-width: 1;
761
+ shape-rendering: crispEdges;
563
762
  }
564
-
565
- .pipeline-timing-bar-label {
566
- font-size: 13px;
567
- font-weight: 600;
568
- margin-bottom: 4px;
763
+ .axis-tick {
764
+ stroke: var(--tl-axis-tick);
765
+ stroke-width: 1;
766
+ shape-rendering: crispEdges;
569
767
  }
570
-
571
- .pipeline-timing-bar {
572
- display: flex;
573
- height: 22px;
574
- border-radius: 6px;
575
- overflow: hidden;
576
- background: var(--surface);
768
+ .axis-label {
769
+ font-size: 11px;
770
+ fill: var(--tl-axis-label);
771
+ font-family: var(--sl-font-sans, system-ui, sans-serif);
772
+ font-variant-numeric: tabular-nums;
577
773
  }
578
774
 
579
- .timing-bar-segment {
775
+ /* Legend */
776
+ .timeline-legend {
580
777
  display: flex;
581
778
  align-items: center;
582
- justify-content: center;
583
- min-width: 0;
584
- transition: opacity 0.15s;
585
- cursor: default;
586
- }
587
-
588
- .timing-bar-segment:hover {
589
- opacity: 0.85;
779
+ gap: 18px;
780
+ padding: 14px 0 4px;
781
+ margin-top: 8px;
782
+ border-top: 1px solid var(--border-subtle, rgba(226, 232, 240, 0.6));
783
+ flex-wrap: wrap;
590
784
  }
591
-
592
- .timing-bar-thinking {
593
- background: var(--status-blocked, #f59e0b);
785
+ .legend-item {
786
+ display: inline-flex;
787
+ align-items: center;
788
+ gap: 6px;
789
+ font-size: 11px;
790
+ color: var(--tl-text-strong);
594
791
  }
595
-
596
- .timing-bar-tools {
597
- background: var(--status-in-progress, #3b82f6);
792
+ .legend-swatch {
793
+ display: inline-block;
794
+ width: 12px;
795
+ height: 12px;
796
+ border-radius: 3px;
797
+ background: var(--muted);
598
798
  }
599
-
600
- .timing-bar-rest {
601
- background: var(--muted, #94a3b8);
602
- opacity: 0.4;
799
+ .legend-swatch--gap {
800
+ background:
801
+ radial-gradient(circle, var(--timeline-gap-dot) 0.6px, transparent 1.2px),
802
+ var(--timeline-gap-fill);
803
+ background-size: 5px 5px;
804
+ border: 1px solid var(--tl-row-divider);
603
805
  }
604
-
605
- .timing-bar-segment-text {
606
- font-size: 11px;
607
- font-weight: 600;
608
- color: #fff;
609
- white-space: nowrap;
610
- overflow: hidden;
611
- text-overflow: ellipsis;
612
- padding: 0 6px;
613
- text-shadow: 0 1px 2px rgba(0,0,0,0.3);
806
+ .legend-loopback {
807
+ /* Inline SVG arc + chevron; inherits color from the legend-item color, so
808
+ it tracks the rest of the legend chrome in both themes. */
809
+ color: var(--accent, #3b82f6);
810
+ flex-shrink: 0;
614
811
  }
615
812
 
616
- .pipeline-timing-bar-legend {
617
- display: flex;
618
- flex-wrap: wrap;
619
- gap: 4px 16px;
620
- margin-top: 6px;
813
+ /* Tooltip */
814
+ .timeline-tooltip {
815
+ position: fixed;
816
+ z-index: 1000;
817
+ background: var(--bg, #fff);
818
+ border: 1px solid var(--border, #e2e8f0);
819
+ border-radius: 8px;
820
+ box-shadow: 0 10px 28px rgba(15, 23, 42, 0.12), 0 2px 6px rgba(15, 23, 42, 0.08);
821
+ padding: 10px 12px;
822
+ pointer-events: none;
823
+ min-width: 200px;
824
+ max-width: 280px;
621
825
  font-size: 12px;
826
+ line-height: 1.55;
827
+ color: var(--fg, #0f172a);
622
828
  }
623
-
624
- .timing-bar-legend-item {
829
+ .tooltip-header {
625
830
  display: flex;
626
831
  align-items: center;
627
- gap: 4px;
832
+ gap: 6px;
833
+ font-weight: 600;
834
+ margin-bottom: 6px;
835
+ padding-bottom: 6px;
836
+ border-bottom: 1px solid var(--border-subtle, rgba(226, 232, 240, 0.6));
628
837
  }
629
-
630
- .timing-bar-legend-swatch {
631
- width: 10px;
632
- height: 10px;
633
- border-radius: 2px;
838
+ .tooltip-hue-dot {
839
+ display: inline-block;
840
+ width: 8px;
841
+ height: 8px;
842
+ border-radius: 50%;
843
+ flex-shrink: 0;
634
844
  }
635
-
636
- .timing-bar-legend-label {
637
- color: var(--fg);
845
+ .tooltip-header-sub {
846
+ font-weight: 400;
847
+ color: var(--tl-text-strong);
848
+ font-size: 11px;
849
+ }
850
+ .tooltip-bead-sub {
851
+ font-size: 11px;
852
+ color: var(--tl-text-strong);
853
+ margin-top: -2px;
854
+ margin-bottom: 4px;
855
+ line-height: 1.35;
856
+ }
857
+ .tooltip-bead-id {
858
+ font-family: var(--sl-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
859
+ font-size: 10.5px;
860
+ background: var(--tl-row-alt, rgba(148, 163, 184, 0.12));
861
+ padding: 1px 5px;
862
+ border-radius: 3px;
863
+ margin-right: 4px;
864
+ }
865
+ .tooltip-row {
866
+ display: flex;
867
+ justify-content: space-between;
868
+ gap: 14px;
869
+ }
870
+ .tooltip-label {
871
+ color: var(--tl-text-strong);
638
872
  font-weight: 500;
639
873
  }
640
-
641
- .timing-bar-legend-value {
642
- color: var(--muted);
874
+ .tooltip-value {
875
+ font-family: var(--sl-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
876
+ font-variant-numeric: tabular-nums;
877
+ color: var(--fg, #0f172a);
878
+ }
879
+ .tooltip-status {
880
+ text-transform: capitalize;
643
881
  }
882
+ .tooltip-status.status-completed { color: var(--status-completed); }
883
+ .tooltip-status.status-running, .tooltip-status.status-in_progress { color: var(--status-running); }
884
+ .tooltip-status.status-failed { color: var(--status-failed); }
885
+ .tooltip-status.status-paused { color: var(--status-paused); }
886
+ .tooltip-status.status-interrupted { color: var(--status-interrupted); }
644
887
 
645
- .stage-totals-strip {
888
+ /* --- Iteration drawer --- */
889
+ .iteration-drawer::part(panel) {
890
+ width: 420px;
891
+ max-width: 90vw;
892
+ }
893
+ .iteration-drawer::part(header) {
894
+ border-bottom: 1px solid var(--border-subtle, rgba(226, 232, 240, 0.6));
895
+ }
896
+ .drawer-body {
646
897
  display: flex;
647
- gap: 20px;
648
- padding: 6px 0 2px;
898
+ flex-direction: column;
899
+ gap: 14px;
649
900
  font-size: 13px;
901
+ color: var(--fg, #0f172a);
902
+ }
903
+ .drawer-title {
904
+ display: flex;
905
+ align-items: center;
906
+ gap: 8px;
907
+ margin: 0 0 4px;
908
+ font-size: 16px;
650
909
  font-weight: 600;
651
- color: var(--fg);
910
+ color: var(--fg, #0f172a);
911
+ outline: none;
652
912
  }
653
-
654
- .stage-totals-item {
913
+ .drawer-hue-dot {
914
+ display: inline-block;
915
+ width: 10px;
916
+ height: 10px;
917
+ border-radius: 50%;
918
+ }
919
+ .drawer-title-sub {
920
+ font-weight: 400;
921
+ color: var(--tl-text-strong);
922
+ font-size: 13px;
923
+ }
924
+ .drawer-status-row {
655
925
  display: inline-flex;
656
926
  align-items: center;
657
- gap: 4px;
927
+ gap: 8px;
928
+ padding: 6px 12px;
929
+ border-radius: 999px;
930
+ background: var(--bg-secondary, #f8fafc);
931
+ align-self: flex-start;
658
932
  }
659
-
660
- .stage-info-strip {
933
+ .drawer-status-pill {
934
+ display: inline-block;
935
+ width: 8px;
936
+ height: 8px;
937
+ border-radius: 50%;
938
+ }
939
+ .drawer-status-text {
940
+ font-size: 12px;
941
+ font-weight: 600;
942
+ text-transform: capitalize;
943
+ }
944
+ .drawer-status-text.status-completed { color: var(--status-completed); }
945
+ .drawer-status-text.status-running, .drawer-status-text.status-in_progress { color: var(--status-running); }
946
+ .drawer-status-text.status-failed { color: var(--status-failed); }
947
+ .drawer-fields {
948
+ display: grid;
949
+ grid-template-columns: max-content 1fr;
950
+ gap: 8px 18px;
951
+ margin: 0;
952
+ }
953
+ .drawer-label {
954
+ color: var(--tl-text-strong);
955
+ font-weight: 500;
956
+ font-size: 12px;
957
+ text-transform: uppercase;
958
+ letter-spacing: 0.04em;
959
+ align-self: center;
960
+ }
961
+ .drawer-value {
962
+ margin: 0;
963
+ font-family: var(--sl-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
964
+ font-variant-numeric: tabular-nums;
965
+ color: var(--fg, #0f172a);
966
+ }
967
+ .drawer-bead {
968
+ font-family: inherit;
661
969
  display: flex;
970
+ align-items: baseline;
971
+ gap: 6px;
662
972
  flex-wrap: wrap;
663
- gap: 4px 20px;
973
+ }
974
+ .drawer-bead-id {
975
+ font-family: var(--sl-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
976
+ font-size: 11px;
977
+ background: var(--tl-row-alt, rgba(148, 163, 184, 0.12));
978
+ padding: 1px 6px;
979
+ border-radius: 3px;
980
+ }
981
+ .drawer-raw-json {
982
+ margin-top: 4px;
983
+ }
984
+ .drawer-raw-json summary {
985
+ cursor: pointer;
986
+ color: var(--tl-text-strong);
987
+ font-size: 12px;
988
+ user-select: none;
989
+ }
990
+ .drawer-raw-json pre {
991
+ font-size: 11px;
992
+ font-family: var(--sl-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
993
+ background: var(--bg-secondary, #f8fafc);
994
+ border: 1px solid var(--border, #e2e8f0);
995
+ border-radius: 6px;
996
+ padding: 10px;
997
+ overflow-x: auto;
998
+ white-space: pre;
999
+ margin-top: 6px;
1000
+ max-height: 280px;
1001
+ }
1002
+ .drawer-run-detail-link {
1003
+ color: var(--accent, #3b82f6);
1004
+ text-decoration: none;
664
1005
  font-size: 13px;
665
- color: var(--muted);
666
- padding: 4px 0;
1006
+ font-weight: 500;
667
1007
  }
668
-
669
- .stage-info-item {
670
- display: inline-flex;
671
- align-items: center;
672
- gap: 4px;
673
- white-space: nowrap;
1008
+ .drawer-run-detail-link:hover {
1009
+ text-decoration: underline;
674
1010
  }
675
1011
 
676
- .text-muted {
677
- color: var(--muted);
678
- opacity: 0.7;
1012
+ @media (prefers-reduced-motion: reduce) {
1013
+ .timeline-bar,
1014
+ .loopback {
1015
+ transition: none;
1016
+ }
679
1017
  }
680
1018
 
681
- .iteration-detail .timing-strip {
682
- margin-bottom: 8px;
683
- padding-bottom: 8px;
684
- border-bottom: 1px solid var(--border);
1019
+ .action-btn:disabled:hover {
1020
+ background: var(--bg-secondary);
1021
+ color: inherit;
685
1022
  }
686
1023
 
687
- /* --- 11. Stage Timeline --- */
688
- .stage-timeline {
1024
+ .error-dialog-body {
689
1025
  display: flex;
690
1026
  align-items: center;
691
- justify-content: safe center;
692
- padding: 28px 16px;
693
- gap: 0;
694
- overflow-x: auto;
1027
+ gap: 16px;
1028
+ padding: 8px 0;
1029
+ }
1030
+ .error-dialog-body p {
1031
+ margin: 0;
1032
+ font-size: 14px;
1033
+ line-height: 1.5;
1034
+ }
1035
+ .error-dialog-icon {
1036
+ color: var(--status-error);
1037
+ flex-shrink: 0;
695
1038
  }
696
1039
 
697
- .stage-node {
1040
+ /* --- 10. Run Header --- */
1041
+ .run-header {
698
1042
  display: flex;
699
- flex-direction: column;
700
- align-items: center;
701
- gap: 8px;
702
- position: relative;
703
- min-width: 90px;
1043
+ align-items: flex-start;
1044
+ justify-content: space-between;
1045
+ padding: 16px 0;
1046
+ margin-bottom: 16px;
1047
+ border-bottom: 1px solid var(--border-subtle);
704
1048
  }
705
1049
 
706
- .stage-icon {
707
- width: 52px;
708
- height: 52px;
709
- border-radius: 50%;
1050
+ .run-header-left {
710
1051
  display: flex;
711
1052
  align-items: center;
712
- justify-content: center;
713
- font-size: 18px;
714
- border: 3px solid var(--border);
715
- background: var(--bg);
716
- transition: border-color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
1053
+ gap: 12px;
717
1054
  }
718
1055
 
719
- .stage-icon svg {
720
- width: 22px;
721
- height: 22px;
1056
+ .run-title {
1057
+ font-size: 22px;
1058
+ font-weight: 600;
1059
+ color: var(--fg);
1060
+ letter-spacing: -0.01em;
722
1061
  }
723
1062
 
724
- .stage-node.status-pending .stage-icon {
725
- border-color: var(--status-pending);
1063
+ .run-header-right {
1064
+ display: flex;
1065
+ align-items: center;
1066
+ gap: 16px;
726
1067
  }
727
1068
 
728
- .stage-node.status-in-progress .stage-icon {
729
- border-color: var(--status-in-progress);
730
- box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);
1069
+ .run-meta {
1070
+ font-size: 13px;
1071
+ color: var(--muted);
731
1072
  }
732
1073
 
733
- .stage-node.status-completed .stage-icon {
734
- border-color: var(--status-completed);
735
- background: var(--status-completed);
736
- color: #ffffff;
737
- transform: scale(1.05);
1074
+ .meta-label {
1075
+ font-weight: 500;
1076
+ color: var(--fg);
1077
+ opacity: 0.7;
738
1078
  }
739
1079
 
740
- .stage-node.status-error .stage-icon {
741
- border-color: var(--status-error);
742
- box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.15);
1080
+ .meta-value {
1081
+ font-weight: 600;
1082
+ color: var(--fg);
743
1083
  }
744
1084
 
745
- .stage-node.status-interrupted .stage-icon {
746
- border-color: var(--status-interrupted);
1085
+ .run-pr-link {
1086
+ color: var(--accent);
1087
+ text-decoration: none;
1088
+ font-weight: 500;
747
1089
  }
748
1090
 
749
- .stage-label {
750
- font-size: 11px;
751
- font-weight: 500;
1091
+ .run-pr-link:hover {
1092
+ text-decoration: underline;
1093
+ }
1094
+
1095
+ .run-meta-grid {
1096
+ display: flex;
1097
+ flex-direction: column;
1098
+ gap: 6px;
1099
+ padding: 12px 16px;
1100
+ background: var(--bg-hover);
1101
+ border-radius: var(--radius-md);
1102
+ margin-bottom: 8px;
1103
+ font-size: 13px;
752
1104
  color: var(--muted);
753
- text-align: center;
754
- white-space: nowrap;
755
- text-transform: uppercase;
756
- letter-spacing: 0.04em;
1105
+ font-variant-numeric: tabular-nums;
757
1106
  }
758
1107
 
759
- /* --- 12. Spin Animation --- */
760
- .icon-spin {
761
- animation: icon-spin 1.5s linear infinite;
1108
+ .run-meta-row {
1109
+ display: flex;
1110
+ flex-wrap: wrap;
1111
+ gap: 4px 20px;
762
1112
  }
763
1113
 
764
- @keyframes icon-spin {
765
- from { transform: rotate(0deg); }
766
- to { transform: rotate(360deg); }
1114
+ .timing-strip {
1115
+ display: flex;
1116
+ flex-wrap: wrap;
1117
+ gap: 4px 20px;
1118
+ font-size: 13px;
1119
+ color: var(--muted);
1120
+ font-variant-numeric: tabular-nums;
767
1121
  }
768
1122
 
769
- .effort-zap-icon {
770
- width: 12px;
771
- height: 12px;
772
- vertical-align: -1px;
773
- margin-right: 2px;
1123
+ .timing-strip-item {
1124
+ white-space: nowrap;
774
1125
  }
775
1126
 
776
- /* --- 13. Stage Connector --- */
777
- .stage-connector {
778
- width: 36px;
779
- height: 4px;
780
- background: var(--border);
781
- border-radius: 2px;
782
- flex-shrink: 0;
783
- align-self: center;
784
- margin-bottom: 24px;
785
- transition: background var(--transition-fast);
1127
+ .run-card .timing-strip {
1128
+ font-size: 12px;
1129
+ gap: 6px 16px;
1130
+ padding-left: 26px;
786
1131
  }
787
1132
 
788
- .stage-connector.completed {
789
- background: var(--status-completed);
1133
+ .stage-detail .timing-strip {
1134
+ margin-bottom: 8px;
1135
+ padding-bottom: 8px;
1136
+ border-bottom: 1px solid var(--border);
790
1137
  }
791
1138
 
792
- /* --- 13b. Prompt Panel --- */
793
- .run-prompt-panel {
794
- margin-bottom: 16px;
1139
+ .run-info-section {
1140
+ padding: 12px 16px;
1141
+ background: var(--bg-hover);
1142
+ border-radius: var(--radius-md);
1143
+ margin-bottom: 8px;
1144
+ display: flex;
1145
+ flex-direction: column;
1146
+ gap: 6px;
795
1147
  }
796
1148
 
797
- .run-prompt-summary {
1149
+ /* Project / Branch / Pipeline-Template / Worktree rows inside
1150
+ `.run-info-section` all share the same label-value typography so the
1151
+ block reads as a uniform stack. Mirror .run-group below it. */
1152
+ .run-project,
1153
+ .run-branch,
1154
+ .run-template,
1155
+ .run-worktree {
1156
+ display: flex;
1157
+ align-items: center;
1158
+ gap: 6px;
798
1159
  font-size: 13px;
799
- font-weight: 500;
800
- color: var(--muted);
801
- text-transform: uppercase;
802
- letter-spacing: 0.04em;
803
1160
  }
804
1161
 
805
- .run-prompt-body {
1162
+ .pipeline-cost-strip {
1163
+ display: flex;
1164
+ flex-wrap: wrap;
1165
+ gap: 4px 20px;
806
1166
  font-size: 13px;
1167
+ font-weight: 600;
807
1168
  color: var(--fg);
808
- line-height: 1.6;
809
- white-space: pre-wrap;
810
- word-break: break-word;
811
- max-height: 400px;
812
- overflow-y: auto;
813
- padding: 8px 0;
814
1169
  }
815
1170
 
816
- /* --- 14. Stage Detail & Panel --- */
817
- .stage-panels {
1171
+ /* Pipeline timing bar */
1172
+ .pipeline-timing-bar-actions {
818
1173
  display: flex;
819
- flex-direction: column;
820
- gap: 8px;
821
- margin-top: 16px;
1174
+ justify-content: flex-end;
1175
+ margin-bottom: 8px;
822
1176
  }
823
1177
 
824
- sl-details.stage-panel {
825
- --border-color: var(--border-subtle);
826
- --border-radius: var(--radius-lg);
1178
+ .pipeline-timing-bar-container {
1179
+ margin-top: 8px;
827
1180
  }
828
1181
 
829
- sl-details.stage-panel::part(base) {
830
- border: 1px solid var(--border-subtle);
831
- border-radius: var(--radius-lg);
832
- background: var(--bg-secondary);
833
- box-shadow: var(--shadow-sm);
1182
+ .pipeline-timing-bar-label {
1183
+ font-size: 13px;
1184
+ font-weight: 600;
1185
+ margin-bottom: 4px;
834
1186
  }
835
1187
 
836
- sl-details.stage-panel::part(header) {
837
- padding: 12px 16px;
1188
+ .pipeline-timing-bar {
1189
+ display: flex;
1190
+ height: 22px;
1191
+ border-radius: 6px;
1192
+ overflow: hidden;
1193
+ background: var(--surface);
838
1194
  }
839
1195
 
840
- sl-details.stage-panel::part(content) {
841
- padding: 0 16px 16px;
1196
+ .timing-bar-segment {
1197
+ display: flex;
1198
+ align-items: center;
1199
+ justify-content: center;
1200
+ min-width: 0;
1201
+ transition: opacity 0.15s;
1202
+ cursor: default;
842
1203
  }
843
1204
 
844
- .stage-content-wrapper {
845
- position: relative;
1205
+ .timing-bar-segment:hover {
1206
+ opacity: 0.85;
846
1207
  }
847
1208
 
848
- .stage-copy-btn {
849
- position: absolute;
850
- top: 0;
851
- right: 0;
852
- display: inline-flex;
853
- align-items: center;
854
- gap: 4px;
855
- padding: 2px 8px;
856
- font-size: 11px;
857
- font-family: inherit;
858
- color: var(--fg-muted);
859
- background: transparent;
860
- border: 1px solid var(--border-subtle);
861
- border-radius: var(--radius-sm);
862
- cursor: pointer;
863
- transition: color 0.15s, border-color 0.15s;
864
- z-index: 1;
1209
+ .timing-bar-thinking {
1210
+ background: var(--status-blocked, #f59e0b);
865
1211
  }
866
1212
 
867
- .stage-copy-btn:hover {
868
- color: var(--fg);
869
- border-color: var(--fg-muted);
1213
+ .timing-bar-tools {
1214
+ background: var(--status-in-progress, #3b82f6);
870
1215
  }
871
1216
 
872
- .stage-copy-btn svg {
873
- flex-shrink: 0;
1217
+ .timing-bar-rest {
1218
+ background: var(--muted, #94a3b8);
1219
+ opacity: 0.4;
874
1220
  }
875
1221
 
876
- .stage-panel-header {
1222
+ .timing-bar-segment-text {
1223
+ font-size: 11px;
1224
+ font-weight: 600;
1225
+ color: #fff;
1226
+ white-space: nowrap;
1227
+ overflow: hidden;
1228
+ text-overflow: ellipsis;
1229
+ padding: 0 6px;
1230
+ text-shadow: 0 1px 2px rgba(0,0,0,0.3);
1231
+ }
1232
+
1233
+ .pipeline-timing-bar-legend {
877
1234
  display: flex;
878
- align-items: center;
879
- gap: 10px;
880
- width: 100%;
1235
+ flex-wrap: wrap;
1236
+ gap: 4px 16px;
1237
+ margin-top: 6px;
1238
+ font-size: 12px;
881
1239
  }
882
1240
 
883
- .stage-panel-icon {
1241
+ .timing-bar-legend-item {
884
1242
  display: flex;
885
1243
  align-items: center;
1244
+ gap: 4px;
886
1245
  }
887
1246
 
888
- .stage-panel-icon svg {
889
- width: 16px;
890
- height: 16px;
1247
+ .timing-bar-legend-swatch {
1248
+ width: 10px;
1249
+ height: 10px;
1250
+ border-radius: 2px;
891
1251
  }
892
1252
 
893
- .stage-panel-label {
1253
+ .timing-bar-legend-label {
1254
+ color: var(--fg);
894
1255
  font-weight: 500;
895
- font-size: 14px;
896
1256
  }
897
1257
 
898
- .stage-panel-meta {
899
- display: flex;
900
- gap: 12px;
901
- margin-left: auto;
902
- margin-right: 8px;
903
- font-size: 12px;
1258
+ .timing-bar-legend-value {
904
1259
  color: var(--muted);
905
- font-variant-numeric: tabular-nums;
906
1260
  }
907
1261
 
908
- .stage-meta-item {
1262
+ .stage-totals-strip {
1263
+ display: flex;
1264
+ gap: 20px;
1265
+ padding: 6px 0 2px;
1266
+ font-size: 13px;
1267
+ font-weight: 600;
1268
+ color: var(--fg);
1269
+ }
1270
+
1271
+ .stage-totals-item {
909
1272
  display: inline-flex;
910
1273
  align-items: center;
911
1274
  gap: 4px;
912
- white-space: nowrap;
913
1275
  }
914
1276
 
915
- .stage-meta-icon {
1277
+ .stage-info-strip {
1278
+ display: flex;
1279
+ flex-wrap: wrap;
1280
+ gap: 4px 20px;
1281
+ font-size: 13px;
1282
+ color: var(--muted);
1283
+ padding: 4px 0;
1284
+ }
1285
+
1286
+ .stage-info-item {
916
1287
  display: inline-flex;
917
- opacity: 0.6;
1288
+ align-items: center;
1289
+ gap: 4px;
1290
+ white-space: nowrap;
918
1291
  }
919
1292
 
920
- .stage-meta-iteration {
921
- color: var(--status-in-progress);
922
- font-weight: 600;
1293
+ .text-muted {
1294
+ color: var(--muted);
1295
+ opacity: 0.7;
923
1296
  }
924
1297
 
925
- .stage-detail {
1298
+ .iteration-detail .timing-strip {
1299
+ margin-bottom: 8px;
1300
+ padding-bottom: 8px;
1301
+ border-bottom: 1px solid var(--border);
1302
+ }
1303
+
1304
+ /* --- 11. Stage Timeline --- */
1305
+ .stage-timeline {
1306
+ display: flex;
1307
+ align-items: center;
1308
+ justify-content: safe center;
1309
+ padding: 28px 16px;
1310
+ gap: 0;
1311
+ overflow-x: auto;
1312
+ }
1313
+
1314
+ .stage-node {
1315
+ display: flex;
1316
+ flex-direction: column;
1317
+ align-items: center;
1318
+ gap: 8px;
1319
+ position: relative;
1320
+ min-width: 90px;
1321
+ }
1322
+
1323
+ .stage-icon {
1324
+ width: 52px;
1325
+ height: 52px;
1326
+ border-radius: 50%;
1327
+ display: flex;
1328
+ align-items: center;
1329
+ justify-content: center;
1330
+ font-size: 18px;
1331
+ border: 3px solid var(--border);
1332
+ background: var(--bg);
1333
+ transition: border-color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
1334
+ }
1335
+
1336
+ .stage-icon svg {
1337
+ width: 22px;
1338
+ height: 22px;
1339
+ }
1340
+
1341
+ .stage-node.status-pending .stage-icon {
1342
+ border-color: var(--status-pending);
1343
+ }
1344
+
1345
+ .stage-node.status-in-progress .stage-icon {
1346
+ border-color: var(--status-in-progress);
1347
+ box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);
1348
+ }
1349
+
1350
+ .stage-node.status-completed .stage-icon {
1351
+ border-color: var(--status-completed);
1352
+ background: var(--status-completed);
1353
+ color: #ffffff;
1354
+ transform: scale(1.05);
1355
+ }
1356
+
1357
+ .stage-node.status-error .stage-icon {
1358
+ border-color: var(--status-error);
1359
+ box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.15);
1360
+ }
1361
+
1362
+ .stage-node.status-interrupted .stage-icon {
1363
+ border-color: var(--status-interrupted);
1364
+ }
1365
+
1366
+ .stage-label {
1367
+ font-size: 11px;
1368
+ font-weight: 500;
1369
+ color: var(--muted);
1370
+ text-align: center;
1371
+ white-space: nowrap;
1372
+ text-transform: uppercase;
1373
+ letter-spacing: 0.04em;
1374
+ }
1375
+
1376
+ /* --- 12. Spin Animation --- */
1377
+ .icon-spin {
1378
+ animation: icon-spin 1.5s linear infinite;
1379
+ }
1380
+
1381
+ @keyframes icon-spin {
1382
+ from { transform: rotate(0deg); }
1383
+ to { transform: rotate(360deg); }
1384
+ }
1385
+
1386
+ .effort-zap-icon {
1387
+ width: 12px;
1388
+ height: 12px;
1389
+ vertical-align: -1px;
1390
+ margin-right: 2px;
1391
+ }
1392
+
1393
+ /* --- 13. Stage Connector --- */
1394
+ .stage-connector {
1395
+ width: 36px;
1396
+ height: 4px;
1397
+ background: var(--border);
1398
+ border-radius: 2px;
1399
+ flex-shrink: 0;
1400
+ align-self: center;
1401
+ margin-bottom: 24px;
1402
+ transition: background var(--transition-fast);
1403
+ }
1404
+
1405
+ .stage-connector.completed {
1406
+ background: var(--status-completed);
1407
+ }
1408
+
1409
+ /* --- 13b. Prompt Panel --- */
1410
+ .run-prompt-panel {
1411
+ margin-bottom: 16px;
1412
+ }
1413
+
1414
+ .run-prompt-summary {
1415
+ font-size: 13px;
1416
+ font-weight: 500;
1417
+ color: var(--muted);
1418
+ text-transform: uppercase;
1419
+ letter-spacing: 0.04em;
1420
+ }
1421
+
1422
+ .run-prompt-body {
1423
+ font-size: 13px;
1424
+ color: var(--fg);
1425
+ line-height: 1.6;
1426
+ white-space: pre-wrap;
1427
+ word-break: break-word;
1428
+ max-height: 400px;
1429
+ overflow-y: auto;
1430
+ padding: 8px 0;
1431
+ }
1432
+
1433
+ /* --- 14. Stage Detail & Panel --- */
1434
+ .stage-panels {
1435
+ display: flex;
1436
+ flex-direction: column;
1437
+ gap: 8px;
1438
+ margin-top: 16px;
1439
+ }
1440
+
1441
+ sl-details.stage-panel {
1442
+ --border-color: var(--border-subtle);
1443
+ --border-radius: var(--radius-lg);
1444
+ }
1445
+
1446
+ sl-details.stage-panel::part(base) {
1447
+ border: 1px solid var(--border-subtle);
1448
+ border-radius: var(--radius-lg);
1449
+ background: var(--bg-secondary);
1450
+ box-shadow: var(--shadow-sm);
1451
+ }
1452
+
1453
+ sl-details.stage-panel::part(header) {
1454
+ padding: 12px 16px;
1455
+ }
1456
+
1457
+ sl-details.stage-panel::part(content) {
1458
+ padding: 0 16px 16px;
1459
+ }
1460
+
1461
+ .stage-content-wrapper {
1462
+ position: relative;
1463
+ }
1464
+
1465
+ .stage-copy-btn {
1466
+ position: absolute;
1467
+ top: 0;
1468
+ right: 0;
1469
+ display: inline-flex;
1470
+ align-items: center;
1471
+ gap: 4px;
1472
+ padding: 2px 8px;
1473
+ font-size: 11px;
1474
+ font-family: inherit;
1475
+ color: var(--fg-muted);
1476
+ background: transparent;
1477
+ border: 1px solid var(--border-subtle);
1478
+ border-radius: var(--radius-sm);
1479
+ cursor: pointer;
1480
+ transition: color 0.15s, border-color 0.15s;
1481
+ z-index: 1;
1482
+ }
1483
+
1484
+ .stage-copy-btn:hover {
1485
+ color: var(--fg);
1486
+ border-color: var(--fg-muted);
1487
+ }
1488
+
1489
+ .stage-copy-btn svg {
1490
+ flex-shrink: 0;
1491
+ }
1492
+
1493
+ .stage-panel-header {
1494
+ display: flex;
1495
+ align-items: center;
1496
+ gap: 10px;
1497
+ width: 100%;
1498
+ }
1499
+
1500
+ .stage-panel-icon {
1501
+ display: flex;
1502
+ align-items: center;
1503
+ }
1504
+
1505
+ .stage-panel-icon svg {
1506
+ width: 16px;
1507
+ height: 16px;
1508
+ }
1509
+
1510
+ .stage-panel-label {
1511
+ font-weight: 500;
1512
+ font-size: 14px;
1513
+ }
1514
+
1515
+ .stage-panel-meta {
1516
+ display: flex;
1517
+ gap: 12px;
1518
+ margin-left: auto;
1519
+ margin-right: 8px;
1520
+ font-size: 12px;
1521
+ color: var(--muted);
1522
+ font-variant-numeric: tabular-nums;
1523
+ }
1524
+
1525
+ .stage-meta-item {
1526
+ display: inline-flex;
1527
+ align-items: center;
1528
+ gap: 4px;
1529
+ white-space: nowrap;
1530
+ }
1531
+
1532
+ .stage-meta-icon {
1533
+ display: inline-flex;
1534
+ opacity: 0.6;
1535
+ }
1536
+
1537
+ .stage-meta-iteration {
1538
+ color: var(--status-in-progress);
1539
+ font-weight: 600;
1540
+ }
1541
+
1542
+ .stage-detail {
926
1543
  padding: 4px 0;
927
1544
  }
928
1545
 
@@ -2942,7 +3559,18 @@ sl-option.template-grouped::part(label) {
2942
3559
  font-weight: 500;
2943
3560
  }
2944
3561
 
2945
- /* Description wraps below name, aligned with label */
3562
+ /* Description wraps below name, aligned with the label's left edge.
3563
+ * Shoelace renders the option as `[checked-icon] [prefix] [label] [suffix]`
3564
+ * on a single flex row. With `flex-wrap: wrap`, the suffix lands on
3565
+ * a new line — but at the parent's left edge, NOT under the label.
3566
+ * We push it back so "ID: foo" sits directly under "Foo" instead of
3567
+ * indented to the prefix slot. Shoelace's prefix slot is ~24px wide
3568
+ * by default; we use the same offset as the label's apparent x.
3569
+ *
3570
+ * The 14px is empirical: 24px ::part(base) padding-left minus the
3571
+ * ~10px the prefix slot is currently empty (no checkmark on
3572
+ * non-selected items). Adjust if Shoelace changes its inner spacing.
3573
+ */
2946
3574
  sl-option.template-grouped::part(suffix) {
2947
3575
  flex-basis: 100%;
2948
3576
  font-size: 11px;
@@ -2951,7 +3579,7 @@ sl-option.template-grouped::part(suffix) {
2951
3579
  white-space: nowrap;
2952
3580
  overflow: hidden;
2953
3581
  text-overflow: ellipsis;
2954
- padding: 0 0 4px;
3582
+ padding: 0 0 4px 14px;
2955
3583
  }
2956
3584
 
2957
3585
  /* Fix contrast on selected/current option description */
@@ -3112,6 +3740,9 @@ sl-option.template-grouped:focus::part(suffix) {
3112
3740
 
3113
3741
  .sidebar.collapsed .sidebar-new-run-btn-primary {
3114
3742
  padding: 8px;
3743
+ /* Chevron half is hidden — drop the divider so the button reads as a
3744
+ single icon control, not a button with a stray edge. */
3745
+ border-right: 0;
3115
3746
  }
3116
3747
 
3117
3748
  /* Stage restart button */
@@ -5962,780 +6593,2091 @@ sl-tooltip.bead-tooltip::part(body) {
5962
6593
  font-size: 22px;
5963
6594
  font-weight: 600;
5964
6595
  color: var(--fg);
5965
- font-variant-numeric: tabular-nums;
6596
+ font-variant-numeric: tabular-nums;
6597
+ }
6598
+
6599
+ .fleet-circuit-breaker-alert,
6600
+ .fleet-user-halt-alert {
6601
+ display: block;
6602
+ }
6603
+
6604
+ .fleet-circuit-breaker-alert .cb-trip-reason,
6605
+ .fleet-circuit-breaker-alert .cb-unstarted-count {
6606
+ display: block;
6607
+ margin-top: 4px;
6608
+ font-size: 12.5px;
6609
+ color: var(--fg);
6610
+ opacity: 0.85;
6611
+ }
6612
+
6613
+ .fleet-actions {
6614
+ display: flex;
6615
+ flex-wrap: wrap;
6616
+ gap: 10px;
6617
+ align-items: center;
6618
+ }
6619
+
6620
+ /* Run-detail "Fleet:" / "Workspace:" group line above the Branch row.
6621
+ Mirrors .run-branch exactly: same font-size, gap, and value weight.
6622
+ The only visual difference is the accent-colored anchor + underline-
6623
+ on-hover affordance signalling it's clickable. */
6624
+ .run-group {
6625
+ display: flex;
6626
+ align-items: center;
6627
+ gap: 6px;
6628
+ font-size: 13px;
6629
+ }
6630
+
6631
+ .run-group-link {
6632
+ /* Inherits font-family + font-size from .run-group → matches the plain
6633
+ <span class="meta-value"> on the Branch line, just colored and
6634
+ underlined-on-hover to read as a link. */
6635
+ color: var(--accent);
6636
+ font-weight: 600;
6637
+ text-decoration: none;
6638
+ word-break: break-all;
6639
+ }
6640
+
6641
+ .run-group-link:hover {
6642
+ text-decoration: underline;
6643
+ }
6644
+
6645
+ /* Run-card "Fleet:" / "Workspace:" meta-item — sized by parent
6646
+ .run-card-meta (12px). Same coloring as .run-group-link but no
6647
+ monospace. */
6648
+ .run-card-group-link {
6649
+ color: var(--accent);
6650
+ font-weight: 600;
6651
+ text-decoration: none;
6652
+ word-break: break-all;
6653
+ }
6654
+
6655
+ .run-card-group-link:hover {
6656
+ text-decoration: underline;
6657
+ }
6658
+
6659
+ /* Sidebar fleet-header clickable feedback */
6660
+ .fleet-header-clickable {
6661
+ transition: background-color var(--transition-fast);
6662
+ }
6663
+
6664
+ .fleet-header-clickable:hover {
6665
+ background-color: color-mix(in srgb, var(--accent) 6%, transparent);
6666
+ }
6667
+
6668
+ /* Fleet list view (route: /#/fleet-runs) — one `fleet-card` per fleet.
6669
+ No wrapping border / shared background; each card carries its own
6670
+ chrome plus the layered stack-of-cards shadow. Gap matches the
6671
+ gap between pipeline cards in run-list for visual consistency. */
6672
+ .fleet-list {
6673
+ display: flex;
6674
+ flex-direction: column;
6675
+ gap: 16px;
6676
+ }
6677
+
6678
+ .fleet-list-row {
6679
+ display: flex;
6680
+ align-items: center;
6681
+ gap: 12px;
6682
+ padding: 12px 16px;
6683
+ border-bottom: 1px solid var(--border-subtle);
6684
+ cursor: pointer;
6685
+ transition: background-color var(--transition-fast);
6686
+ }
6687
+
6688
+ .fleet-list-row:last-child {
6689
+ border-bottom: none;
6690
+ }
6691
+
6692
+ .fleet-list-row:hover {
6693
+ background-color: color-mix(in srgb, var(--accent) 6%, transparent);
6694
+ }
6695
+
6696
+ .fleet-list-row-title {
6697
+ font-size: 14px;
6698
+ font-weight: 600;
6699
+ color: var(--fg);
6700
+ flex: 1 1 auto;
6701
+ min-width: 0;
6702
+ overflow: hidden;
6703
+ text-overflow: ellipsis;
6704
+ white-space: nowrap;
6705
+ }
6706
+
6707
+ .fleet-list-row-badge {
6708
+ flex-shrink: 0;
6709
+ }
6710
+
6711
+ .fleet-list-row-meta {
6712
+ font-size: 12px;
6713
+ color: var(--muted);
6714
+ flex-shrink: 0;
6715
+ }
6716
+
6717
+ .fleet-list-row-id {
6718
+ font-family: var(--sl-font-mono);
6719
+ font-size: 11.5px;
6720
+ color: var(--muted);
6721
+ background: var(--bg-tertiary);
6722
+ padding: 2px 8px;
6723
+ border-radius: 4px;
6724
+ flex-shrink: 0;
6725
+ }
6726
+
6727
+ .fleet-list-loading,
6728
+ .fleet-list-empty {
6729
+ padding: 24px;
6730
+ text-align: center;
6731
+ color: var(--muted);
6732
+ display: flex;
6733
+ flex-direction: column;
6734
+ align-items: center;
6735
+ gap: 12px;
6736
+ }
6737
+
6738
+ .fleet-detail-empty {
6739
+ padding: 64px 24px;
6740
+ text-align: center;
6741
+ color: var(--muted);
6742
+ display: flex;
6743
+ flex-direction: column;
6744
+ align-items: center;
6745
+ gap: 12px;
6746
+ max-width: 540px;
6747
+ margin: 0 auto;
6748
+ }
6749
+
6750
+ .fleet-detail-empty sl-icon {
6751
+ font-size: 48px;
6752
+ color: var(--muted);
6753
+ opacity: 0.6;
6754
+ }
6755
+
6756
+ .fleet-detail-empty h2 {
6757
+ margin: 8px 0 0 0;
6758
+ font-size: 18px;
6759
+ color: var(--fg);
6760
+ }
6761
+
6762
+ .fleet-detail-empty p {
6763
+ margin: 0;
6764
+ line-height: 1.5;
6765
+ }
6766
+
6767
+ .fleet-detail-empty code {
6768
+ font-size: 12px;
6769
+ background: var(--bg-2, var(--border));
6770
+ padding: 1px 6px;
6771
+ border-radius: 4px;
6772
+ }
6773
+
6774
+ .fleet-detail-empty-hint {
6775
+ font-size: 13px;
6776
+ opacity: 0.85;
6777
+ }
6778
+
6779
+ .fleet-detail-empty-hint a {
6780
+ color: var(--accent, var(--fg));
6781
+ }
6782
+
6783
+ /* --- Workspace: tier styling --- */
6784
+
6785
+ .workspace-card-tiers {
6786
+ display: flex;
6787
+ flex-direction: column;
6788
+ gap: 6px;
6789
+ margin-top: 8px;
6790
+ }
6791
+
6792
+ .workspace-tier-row {
6793
+ display: flex;
6794
+ align-items: center;
6795
+ gap: 8px;
6796
+ }
6797
+
6798
+ .tier-label {
6799
+ font-size: 11px;
6800
+ font-weight: 600;
6801
+ color: var(--muted);
6802
+ text-transform: uppercase;
6803
+ letter-spacing: 0.05em;
6804
+ min-width: 60px;
6805
+ flex-shrink: 0;
6806
+ }
6807
+
6808
+ .tier-status {
6809
+ display: inline-flex;
6810
+ align-items: center;
6811
+ flex-shrink: 0;
6812
+ }
6813
+
6814
+ .tier-children {
6815
+ display: flex;
6816
+ flex-wrap: wrap;
6817
+ gap: 4px;
6818
+ }
6819
+
6820
+ .tier-child {
6821
+ font-size: 12px;
6822
+ padding: 2px 8px;
6823
+ border-radius: 4px;
6824
+ background: var(--bg-tertiary);
6825
+ border: 1px solid var(--border);
6826
+ }
6827
+
6828
+ /* --- Workspace: DAG graph --- */
6829
+
6830
+ .dag-preview {
6831
+ overflow-x: auto;
6832
+ border: 1px solid var(--border);
6833
+ border-radius: var(--radius);
6834
+ background: var(--bg-secondary);
6835
+ padding: 16px;
6836
+ }
6837
+
6838
+ .dag-preview svg {
6839
+ display: block;
6840
+ }
6841
+
6842
+ .workspace-dag-panel {
6843
+ display: flex;
6844
+ flex-direction: column;
6845
+ gap: 8px;
6846
+ }
6847
+
6848
+
6849
+
6850
+ .workspace-dag-svg {
6851
+ overflow-x: auto;
6852
+ }
6853
+
6854
+ /* --- Workspace run card --- */
6855
+
6856
+ /* --- Plan stage artifact strip (run-detail) --- */
6857
+
6858
+ .plan-artifact-strip {
6859
+ display: flex;
6860
+ align-items: center;
6861
+ flex-wrap: wrap;
6862
+ gap: 8px;
6863
+ margin: 10px 0 4px;
6864
+ }
6865
+ .plan-artifact-strip .plan-file-chip {
6866
+ font-family: var(--font-mono);
6867
+ font-size: 12px;
6868
+ color: var(--fg-muted);
6869
+ background: var(--bg-secondary);
6870
+ padding: 2px 6px;
6871
+ border-radius: 4px;
6872
+ max-width: 360px;
6873
+ overflow: hidden;
6874
+ text-overflow: ellipsis;
6875
+ white-space: nowrap;
6876
+ }
6877
+ .plan-loading,
6878
+ .plan-error {
6879
+ display: flex;
6880
+ align-items: center;
6881
+ gap: 8px;
6882
+ padding: 20px;
6883
+ color: var(--fg-muted);
6884
+ }
6885
+
6886
+ /* W-061: plan revision selector inside the plan dialog */
6887
+ .plan-iter-selector {
6888
+ display: flex;
6889
+ flex-wrap: wrap;
6890
+ align-items: center;
6891
+ gap: 6px;
6892
+ margin: 0 0 12px;
6893
+ padding-bottom: 12px;
6894
+ border-bottom: 1px solid var(--border, var(--bg-secondary));
6895
+ }
6896
+
6897
+ /* --- sl-dialog: wider markdown-body dialogs (plan, guide) --- */
6898
+
6899
+ sl-dialog.markdown-dialog::part(panel) {
6900
+ /* Default sl-dialog is ~31rem wide — too narrow for prose with code
6901
+ blocks. Cap at 90vw so it stays comfortable on small viewports. */
6902
+ width: min(960px, 90vw);
6903
+ max-width: min(960px, 90vw);
6904
+ }
6905
+ sl-dialog.markdown-dialog::part(body) {
6906
+ /* Give the body breathing room and let it scroll vertically instead
6907
+ of the whole dialog growing without bound. */
6908
+ max-height: 70vh;
6909
+ overflow: auto;
6910
+ }
6911
+
6912
+ /* --- Markdown body styling (used by guide-content + workspace-plan-content) --- */
6913
+
6914
+ .markdown-body {
6915
+ font-family: var(--sl-font-sans, system-ui, sans-serif);
6916
+ font-size: 14px;
6917
+ line-height: 1.55;
6918
+ color: var(--fg);
6919
+ }
6920
+ .markdown-body h1,
6921
+ .markdown-body h2,
6922
+ .markdown-body h3,
6923
+ .markdown-body h4 {
6924
+ margin: 1.2em 0 0.5em;
6925
+ line-height: 1.25;
6926
+ font-weight: 600;
6927
+ }
6928
+ .markdown-body h1 { font-size: 1.5em; }
6929
+ .markdown-body h2 { font-size: 1.25em; border-bottom: 1px solid var(--border-subtle); padding-bottom: 4px; }
6930
+ .markdown-body h3 { font-size: 1.1em; }
6931
+ .markdown-body p { margin: 0.6em 0; }
6932
+ .markdown-body ul,
6933
+ .markdown-body ol { margin: 0.6em 0; padding-left: 1.5em; }
6934
+ .markdown-body li { margin: 0.25em 0; }
6935
+ .markdown-body code {
6936
+ font-family: var(--font-mono);
6937
+ font-size: 0.9em;
6938
+ background: var(--bg-secondary);
6939
+ padding: 1px 5px;
6940
+ border-radius: 3px;
6941
+ }
6942
+ .markdown-body pre {
6943
+ background: var(--bg-secondary);
6944
+ border: 1px solid var(--border-subtle);
6945
+ border-radius: 6px;
6946
+ padding: 10px 12px;
6947
+ overflow-x: auto;
6948
+ font-size: 12.5px;
6949
+ }
6950
+ .markdown-body pre code {
6951
+ background: transparent;
6952
+ padding: 0;
6953
+ border-radius: 0;
6954
+ }
6955
+ .markdown-body blockquote {
6956
+ border-left: 3px solid var(--border);
6957
+ padding: 4px 12px;
6958
+ margin: 0.6em 0;
6959
+ color: var(--fg-muted);
6960
+ }
6961
+ .markdown-body a { color: var(--accent); }
6962
+ .markdown-body table {
6963
+ border-collapse: collapse;
6964
+ margin: 0.8em 0;
6965
+ }
6966
+ .markdown-body th,
6967
+ .markdown-body td {
6968
+ border: 1px solid var(--border-subtle);
6969
+ padding: 4px 8px;
6970
+ text-align: left;
6971
+ }
6972
+
6973
+ /* --- Markdown context overrides --- */
6974
+
6975
+ .markdown-inline.markdown-body {
6976
+ display: inline;
6977
+ font-size: inherit;
6978
+ line-height: inherit;
6979
+ }
6980
+ .markdown-inline.markdown-body p {
6981
+ display: inline;
6982
+ margin: 0;
6983
+ }
6984
+ .markdown-inline.markdown-body code {
6985
+ font-size: 0.85em;
6986
+ }
6987
+
6988
+ .agent-prompt-content .markdown-body {
6989
+ white-space: normal;
6990
+ font-size: 12px;
6991
+ line-height: 1.5;
6992
+ }
6993
+ .agent-prompt-content .markdown-body h1,
6994
+ .agent-prompt-content .markdown-body h2,
6995
+ .agent-prompt-content .markdown-body h3 {
6996
+ margin: 0.8em 0 0.3em;
6997
+ }
6998
+
6999
+ .bead-tooltip-excerpt.markdown-body {
7000
+ white-space: normal;
7001
+ font-size: 12px;
7002
+ max-height: 200px;
7003
+ overflow-y: auto;
7004
+ /* Inherit the tooltip's (light) text color instead of --fg, which is the
7005
+ main-panel foreground and renders dark-on-dark inside the tooltip. */
7006
+ color: inherit;
7007
+ }
7008
+ .bead-tooltip-excerpt.markdown-body p {
7009
+ margin: 0.3em 0;
7010
+ }
7011
+ .bead-tooltip-excerpt.markdown-body pre {
7012
+ font-size: 11px;
7013
+ max-height: 120px;
7014
+ overflow: auto;
7015
+ }
7016
+ /* The base markdown code/blockquote/link colors assume the light main panel;
7017
+ re-tint them for the dark tooltip surface so they stay legible. */
7018
+ .bead-tooltip-excerpt.markdown-body code,
7019
+ .bead-tooltip-excerpt.markdown-body pre {
7020
+ background: rgba(255, 255, 255, 0.1);
7021
+ border-color: rgba(255, 255, 255, 0.15);
7022
+ }
7023
+ .bead-tooltip-excerpt.markdown-body blockquote {
7024
+ color: inherit;
7025
+ opacity: 0.8;
7026
+ border-left-color: rgba(255, 255, 255, 0.3);
7027
+ }
7028
+
7029
+ .workspace-run-card .workspace-card-root,
7030
+ .workspace-run-card .workspace-card-name {
7031
+ font-family: var(--font-mono);
7032
+ font-size: 12px;
7033
+ color: var(--fg-muted);
7034
+ }
7035
+
7036
+ /* --- Workspace forms: external-repo picker --- */
7037
+
7038
+ .repo-checklist-actions {
7039
+ display: flex;
7040
+ align-items: center;
7041
+ gap: 12px;
7042
+ margin-top: 12px;
7043
+ flex-wrap: wrap;
7044
+ }
7045
+ .ws-external-tag {
7046
+ margin-left: 8px;
7047
+ }
7048
+
7049
+ /* --- Workspace forms: Dependency Graph label --- */
7050
+
7051
+ .dag-preview-block {
7052
+ margin-top: 16px;
7053
+ }
7054
+ .dag-preview-label {
7055
+ display: block;
7056
+ margin-bottom: 8px;
7057
+ }
7058
+
7059
+ /* --- Workspace edit: scan-for-additions status + Available tag --- */
7060
+
7061
+ .ws-edit-scan-status {
7062
+ display: flex;
7063
+ align-items: center;
7064
+ gap: 8px;
7065
+ font-size: 13px;
7066
+ color: var(--fg-muted);
7067
+ margin-bottom: 12px;
7068
+ }
7069
+ .ws-edit-scan-error {
7070
+ margin-bottom: 12px;
7071
+ }
7072
+ .ws-edit-new-tag {
7073
+ margin-left: 8px;
7074
+ }
7075
+
7076
+ /* --- Workspace create: Parent Directory row --- */
7077
+
7078
+ .parent-dir-row {
7079
+ display: flex;
7080
+ gap: 8px;
7081
+ align-items: stretch;
7082
+ }
7083
+ .parent-dir-row .input-parent-dir {
7084
+ flex: 1;
7085
+ }
7086
+ .parent-dir-suggestions {
7087
+ margin-top: 8px;
7088
+ border: 1px solid var(--border);
7089
+ border-radius: 6px;
7090
+ background: var(--bg);
7091
+ overflow: hidden;
7092
+ }
7093
+ .parent-dir-suggestions-label {
7094
+ padding: 6px 12px;
7095
+ font-size: 11px;
7096
+ text-transform: uppercase;
7097
+ letter-spacing: 0.04em;
7098
+ color: var(--fg-muted);
7099
+ background: var(--bg-secondary);
7100
+ border-bottom: 1px solid var(--border-subtle);
7101
+ }
7102
+ .parent-dir-suggestion-item {
7103
+ display: flex;
7104
+ align-items: center;
7105
+ gap: 8px;
7106
+ width: 100%;
7107
+ padding: 8px 12px;
7108
+ background: transparent;
7109
+ border: none;
7110
+ border-bottom: 1px solid var(--border-subtle);
7111
+ cursor: pointer;
7112
+ font-family: var(--font-mono);
7113
+ font-size: 13px;
7114
+ color: var(--fg);
7115
+ text-align: left;
7116
+ }
7117
+ .parent-dir-suggestion-item:last-child {
7118
+ border-bottom: none;
7119
+ }
7120
+ .parent-dir-suggestion-item:hover {
7121
+ background: var(--bg-hover);
7122
+ }
7123
+ .parent-dir-suggestion-item svg {
7124
+ flex-shrink: 0;
7125
+ color: var(--fg-muted);
7126
+ }
7127
+
7128
+ /* --- Configuration → Workspaces list --- */
7129
+
7130
+ .workspaces-config-empty {
7131
+ display: flex;
7132
+ flex-direction: column;
7133
+ align-items: center;
7134
+ justify-content: center;
7135
+ text-align: center;
7136
+ padding: 64px 24px;
7137
+ gap: 12px;
7138
+ color: var(--fg-muted);
7139
+ }
7140
+ .workspaces-config-empty .empty-icon {
7141
+ color: var(--fg-muted);
7142
+ opacity: 0.5;
7143
+ margin-bottom: 8px;
7144
+ }
7145
+ .workspaces-config-empty h3 {
7146
+ margin: 0;
7147
+ color: var(--fg);
7148
+ }
7149
+ .workspaces-config-empty p {
7150
+ max-width: 480px;
7151
+ margin: 0 0 12px;
7152
+ line-height: 1.5;
7153
+ }
7154
+
7155
+ .workspaces-config-table {
7156
+ padding: 16px;
7157
+ overflow-x: auto;
7158
+ }
7159
+ .workspaces-config-table table {
7160
+ width: 100%;
7161
+ border-collapse: collapse;
7162
+ font-size: 14px;
7163
+ }
7164
+ .workspaces-config-table thead th {
7165
+ text-align: left;
7166
+ font-weight: 600;
7167
+ padding: 8px 12px;
7168
+ border-bottom: 1px solid var(--border);
7169
+ color: var(--fg-muted);
7170
+ text-transform: uppercase;
7171
+ font-size: 11px;
7172
+ letter-spacing: 0.04em;
7173
+ }
7174
+ .workspaces-config-table tbody td {
7175
+ padding: 12px;
7176
+ border-bottom: 1px solid var(--border);
7177
+ vertical-align: middle;
7178
+ }
7179
+ .workspaces-config-table tbody tr:hover {
7180
+ background: var(--bg-hover);
7181
+ }
7182
+ .workspaces-config-table .ws-name strong {
7183
+ font-weight: 600;
7184
+ }
7185
+ .workspaces-config-table .ws-path code,
7186
+ .workspaces-config-table .ws-umbrella {
7187
+ font-family: var(--font-mono);
7188
+ font-size: 12px;
7189
+ color: var(--fg-muted);
7190
+ }
7191
+ .workspaces-config-table .ws-tiers {
7192
+ color: var(--fg-muted);
7193
+ font-size: 12px;
7194
+ margin-left: 4px;
7195
+ }
7196
+ .workspaces-config-table .ws-dash {
7197
+ color: var(--fg-muted);
7198
+ opacity: 0.5;
7199
+ }
7200
+ .workspaces-config-table .actions-col {
7201
+ text-align: right;
7202
+ }
7203
+ .workspaces-config-table .ws-actions {
7204
+ display: flex;
7205
+ gap: 4px;
7206
+ justify-content: flex-end;
7207
+ }
7208
+ .ws-action-btn {
7209
+ background: transparent;
7210
+ border: 1px solid var(--border);
7211
+ border-radius: 4px;
7212
+ padding: 4px 6px;
7213
+ cursor: pointer;
7214
+ color: var(--fg);
7215
+ display: inline-flex;
7216
+ align-items: center;
7217
+ justify-content: center;
7218
+ }
7219
+ .ws-action-btn:hover {
7220
+ background: var(--bg-hover);
7221
+ }
7222
+ .ws-action-btn--danger:hover {
7223
+ background: rgba(220, 38, 38, 0.1);
7224
+ color: rgb(220, 38, 38);
7225
+ border-color: rgba(220, 38, 38, 0.4);
7226
+ }
7227
+
7228
+ .dag-graph-node rect {
7229
+ rx: 6;
7230
+ fill: var(--bg);
7231
+ stroke: var(--border);
7232
+ stroke-width: 1.5;
7233
+ }
7234
+
7235
+ .dag-graph-node text {
7236
+ font-size: 12px;
7237
+ font-family: var(--sl-font-sans);
7238
+ fill: var(--fg);
7239
+ }
7240
+
7241
+ .dag-graph-edge {
7242
+ fill: none;
7243
+ stroke: var(--border);
7244
+ stroke-width: 2;
7245
+ }
7246
+
7247
+ .dag-graph-node--status-pending rect { stroke: var(--status-pending); }
7248
+ .dag-graph-node--status-running rect { stroke: var(--status-running); }
7249
+ .dag-graph-node--status-completed rect { stroke: var(--status-completed); }
7250
+ .dag-graph-node--status-failed rect { stroke: var(--status-failed); }
7251
+ .dag-graph-node--status-paused rect { stroke: var(--status-paused); }
7252
+ .dag-graph-node--status-blocked rect { stroke: var(--status-blocked); }
7253
+ .dag-graph-node--status-planning rect { stroke: var(--status-running); }
7254
+ .dag-graph-node--status-integration-testing rect { stroke: var(--status-running); }
7255
+ .dag-graph-node--status-integration-failed rect { stroke: var(--status-failed); }
7256
+
7257
+ /* --- Workspace: conflict icon --- */
7258
+
7259
+ .conflict-icon {
7260
+ color: var(--status-blocked);
7261
+ }
7262
+
7263
+ /* Graphify cache location — selectable monospace path (W-053 cache relocation) */
7264
+ .graphify-codebox {
7265
+ display: block;
7266
+ margin: 0.25rem 0 0.75rem;
7267
+ padding: 0.4rem 0.6rem;
7268
+ background: var(--bg-secondary);
7269
+ border: 1px solid var(--border-subtle);
7270
+ border-radius: var(--radius);
7271
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
7272
+ font-size: 0.85rem;
7273
+ color: var(--fg);
7274
+ word-break: break-all;
7275
+ user-select: all;
7276
+ }
7277
+
7278
+ /* A monospace value/command box with a copy button pinned to the right. */
7279
+ .graphify-copy-row {
7280
+ display: flex;
7281
+ align-items: center;
7282
+ gap: 0.4rem;
7283
+ margin: 0.25rem 0 0.75rem;
7284
+ }
7285
+
7286
+ .graphify-copy-row .graphify-codebox {
7287
+ flex: 1;
7288
+ min-width: 0;
7289
+ margin: 0;
7290
+ }
7291
+
7292
+ /* Shown when the graphify CLI is missing/incompatible. */
7293
+ .graphify-not-installed {
7294
+ margin: 0 0 0.75rem;
7295
+ }
7296
+
7297
+ /* Caution color (action needed: install) on the message text only — not the
7298
+ install-command code box, which keeps normal monospace styling. */
7299
+ .graphify-not-installed .settings-tab-description {
7300
+ color: var(--status-paused);
7301
+ }
7302
+
7303
+ /* Code Review Graph (CRG) — mirrors graphify-* classes above */
7304
+ .crg-codebox {
7305
+ display: block;
7306
+ margin: 0.25rem 0 0.75rem;
7307
+ padding: 0.4rem 0.6rem;
7308
+ background: var(--bg-secondary);
7309
+ border: 1px solid var(--border-subtle);
7310
+ border-radius: var(--radius);
7311
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
7312
+ font-size: 0.85rem;
7313
+ color: var(--fg);
7314
+ word-break: break-all;
7315
+ user-select: all;
7316
+ }
7317
+
7318
+ .crg-copy-row {
7319
+ display: flex;
7320
+ align-items: center;
7321
+ gap: 0.4rem;
7322
+ margin: 0.25rem 0 0.75rem;
7323
+ }
7324
+
7325
+ .crg-copy-row .crg-codebox {
7326
+ flex: 1;
7327
+ min-width: 0;
7328
+ margin: 0;
7329
+ }
7330
+
7331
+ .crg-not-installed {
7332
+ margin: 0 0 0.75rem;
7333
+ }
7334
+
7335
+ .crg-not-installed .settings-tab-description {
7336
+ color: var(--status-paused);
7337
+ }
7338
+
7339
+ .crg-coming-soon {
7340
+ color: var(--muted);
7341
+ font-style: italic;
7342
+ }
7343
+
7344
+ .crg-stage-tools {
7345
+ margin: 1rem 0;
7346
+ }
7347
+
7348
+ .crg-stage-tools-grid {
7349
+ display: grid;
7350
+ gap: 0.4rem;
7351
+ margin-top: 0.5rem;
7352
+ }
7353
+
7354
+ .crg-stage-tools-entry {
7355
+ display: flex;
7356
+ gap: 0.75rem;
7357
+ align-items: baseline;
7358
+ font-size: 0.85rem;
7359
+ }
7360
+
7361
+ .crg-stage-role {
7362
+ font-weight: 600;
7363
+ min-width: 6rem;
7364
+ color: var(--fg);
7365
+ }
7366
+
7367
+ .crg-stage-tool-list {
7368
+ color: var(--muted);
7369
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
7370
+ font-size: 0.8rem;
7371
+ word-break: break-all;
7372
+ }
7373
+
7374
+ /* --- Pipelines view --- */
7375
+
7376
+ .pipelines-view {
7377
+ padding: 24px 0;
7378
+ }
7379
+
7380
+ .pipelines-content {
7381
+ display: flex;
7382
+ flex-direction: column;
7383
+ gap: 24px;
7384
+ }
7385
+
7386
+ .pipelines-loading-spinner {
7387
+ display: flex;
7388
+ justify-content: center;
7389
+ padding: 48px;
7390
+ font-size: 32px;
7391
+ }
7392
+
7393
+ /*
7394
+ * Tier sections are sl-details collapsibles. The summary slot holds a
7395
+ * 2-row grid: top row [icon | TITLE | count | spacer], bottom row a
7396
+ * one-line description that wraps under the title. Shoelace's own
7397
+ * chevron sits to the right of our summary content.
7398
+ */
7399
+ .pipelines-tier-section {
7400
+ margin-bottom: 0;
7401
+ }
7402
+ .pipelines-tier-section::part(base) {
7403
+ border: 1px solid var(--border-subtle, var(--border));
7404
+ border-radius: var(--radius-lg);
7405
+ /* Match the new-run-section panel chrome so the tier sections
7406
+ * read as the same kind of grouping (gray-tinted surface holding
7407
+ * a heading + a stack of items). Previously these were on the
7408
+ * default `--surface`, which left the cards floating with no
7409
+ * visual hierarchy against the page background. */
7410
+ background: var(--bg-secondary);
7411
+ }
7412
+ .pipelines-tier-section::part(header) {
7413
+ padding: 12px 16px;
7414
+ }
7415
+ .pipelines-tier-section::part(content) {
7416
+ padding: 12px 16px 16px;
7417
+ }
7418
+
7419
+ /* The summary's flex container: lay out icon + title + count + desc. */
7420
+ .tier-section-header {
7421
+ display: grid;
7422
+ grid-template-columns: auto auto auto 1fr;
7423
+ grid-template-rows: auto auto;
7424
+ align-items: center;
7425
+ gap: 4px 10px;
7426
+ width: 100%;
7427
+ }
7428
+ .tier-section-icon {
7429
+ display: inline-flex;
7430
+ align-items: center;
7431
+ color: var(--fg-muted);
7432
+ grid-row: 1;
7433
+ }
7434
+ .tier-section-title {
7435
+ font-size: 12px;
7436
+ font-weight: 600;
7437
+ letter-spacing: 0.08em;
7438
+ text-transform: uppercase;
7439
+ color: var(--fg-muted);
7440
+ grid-row: 1;
7441
+ }
7442
+ .tier-section-count {
7443
+ grid-row: 1;
7444
+ font-size: 11px;
7445
+ justify-self: start;
7446
+ }
7447
+ .tier-section-desc {
7448
+ grid-row: 2;
7449
+ grid-column: 2 / -1;
7450
+ margin: 0;
7451
+ color: var(--fg-muted);
7452
+ font-size: 13px;
7453
+ line-height: 1.4;
7454
+ font-weight: 400;
7455
+ text-transform: none;
7456
+ letter-spacing: 0;
7457
+ }
7458
+
7459
+ /*
7460
+ * Empty-tier placeholder — sits inside an otherwise normal
7461
+ * .pipelines-tier-section so the page never collapses around an empty
7462
+ * tier. Uses the dashed Settings-style border to read as "absence,
7463
+ * not error".
7464
+ */
7465
+ .tier-section-empty {
7466
+ display: flex;
7467
+ flex-direction: column;
7468
+ gap: 6px;
7469
+ padding: 18px 20px;
7470
+ border: 1px dashed var(--border-subtle, var(--border));
7471
+ border-radius: var(--radius-lg);
7472
+ background: var(--surface);
7473
+ }
7474
+ .tier-section-empty-title {
7475
+ font-weight: 600;
7476
+ font-size: 13px;
7477
+ color: var(--fg);
5966
7478
  }
5967
-
5968
- .fleet-circuit-breaker-alert,
5969
- .fleet-user-halt-alert {
5970
- display: block;
7479
+ .tier-section-empty-desc {
7480
+ margin: 0;
7481
+ font-size: 13px;
7482
+ line-height: 1.4;
7483
+ color: var(--fg-muted);
5971
7484
  }
5972
7485
 
5973
- .fleet-circuit-breaker-alert .cb-trip-reason,
5974
- .fleet-circuit-breaker-alert .cb-unstarted-count {
5975
- display: block;
5976
- margin-top: 4px;
5977
- font-size: 12.5px;
5978
- color: var(--fg);
5979
- opacity: 0.85;
7486
+ .pipelines-grid {
7487
+ display: grid;
7488
+ /* Cards 50% wider than the original 320px min — fewer per row, more
7489
+ room for the description text and tag chips to breathe. The gap
7490
+ scales with the new width so the grid still feels balanced. */
7491
+ grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
7492
+ gap: 20px;
5980
7493
  }
5981
7494
 
5982
- .fleet-actions {
5983
- display: flex;
5984
- flex-wrap: wrap;
5985
- gap: 10px;
5986
- align-items: center;
7495
+ .template-card {
7496
+ /* +50% on the original 140px to stay proportional with the wider
7497
+ grid track; longer descriptions now have headroom before the card
7498
+ needs to grow further. */
7499
+ min-height: 210px;
5987
7500
  }
5988
7501
 
5989
- /* Run-detail "Fleet:" / "Workspace:" group line above the Branch row.
5990
- Mirrors .run-branch exactly: same font-size, gap, and value weight.
5991
- The only visual difference is the accent-colored anchor + underline-
5992
- on-hover affordance signalling it's clickable. */
5993
- .run-group {
5994
- display: flex;
5995
- align-items: center;
5996
- gap: 6px;
5997
- font-size: 13px;
7502
+ /*
7503
+ * "ID: <slug>" badge — pill-shaped with a subtle gray background to
7504
+ * read as a handle/identifier chip rather than incidental text. Sits
7505
+ * inline with the file-text icon, name, and Default badge on the
7506
+ * card's top row (mirrors the tier section header layout). Uses
7507
+ * Settings-style tokens (--bg-secondary, --border-subtle) so it
7508
+ * lands in the same visual family as our other chips and badges.
7509
+ */
7510
+ .template-card-id-badge {
7511
+ display: inline-flex;
7512
+ align-items: baseline;
7513
+ gap: 4px;
7514
+ padding: 2px 8px;
7515
+ border-radius: 9999px;
7516
+ background: var(--bg-secondary);
7517
+ border: 1px solid var(--border-subtle, var(--border));
7518
+ max-width: max-content;
7519
+ min-width: 0;
5998
7520
  }
5999
-
6000
- .run-group-link {
6001
- /* Inherits font-family + font-size from .run-group → matches the plain
6002
- <span class="meta-value"> on the Branch line, just colored and
6003
- underlined-on-hover to read as a link. */
6004
- color: var(--accent);
7521
+ .template-card-id-label {
7522
+ font-size: 10px;
6005
7523
  font-weight: 600;
6006
- text-decoration: none;
6007
- word-break: break-all;
7524
+ letter-spacing: 0.06em;
7525
+ text-transform: uppercase;
7526
+ color: var(--fg-muted);
7527
+ flex-shrink: 0;
7528
+ }
7529
+ .template-card-id {
7530
+ font-family: var(--sl-font-mono);
7531
+ font-size: 12px;
7532
+ color: var(--fg);
7533
+ background: transparent;
7534
+ padding: 0;
7535
+ white-space: nowrap;
7536
+ overflow: hidden;
7537
+ text-overflow: ellipsis;
6008
7538
  }
6009
7539
 
6010
- .run-group-link:hover {
6011
- text-decoration: underline;
7540
+ /*
7541
+ * Template cards inherit `cursor: pointer` and a hover lift from the
7542
+ * base `.run-card` rule. The `--clickable` modifier is added by the
7543
+ * view only when an edit/duplicate handler is wired up; in the degraded
7544
+ * read-only state we strip those affordances so the card looks (and
7545
+ * feels) inert.
7546
+ */
7547
+ .template-card:not(.template-card--clickable) {
7548
+ cursor: default;
7549
+ }
7550
+ .template-card:not(.template-card--clickable):hover {
7551
+ background: var(--surface);
7552
+ box-shadow: none;
7553
+ transform: none;
7554
+ }
7555
+ .template-card--clickable:focus-visible {
7556
+ outline: 2px solid var(--accent, #4f9eff);
7557
+ outline-offset: 2px;
6012
7558
  }
6013
7559
 
6014
- /* Run-card "Fleet:" / "Workspace:" meta-item — sized by parent
6015
- .run-card-meta (12px). Same coloring as .run-group-link but no
6016
- monospace. */
6017
- .run-card-group-link {
6018
- color: var(--accent);
7560
+ .template-default-badge {
7561
+ margin-right: 8px;
6019
7562
  font-weight: 600;
6020
- text-decoration: none;
6021
- word-break: break-all;
6022
7563
  }
6023
7564
 
6024
- .run-card-group-link:hover {
6025
- text-decoration: underline;
7565
+ /*
7566
+ * Top row is just icon + name + (optional) ★ Default. The shared
7567
+ * `.run-card-title { flex: 1 }` rule does the right thing here:
7568
+ * the title soaks up the horizontal space and pushes the Default
7569
+ * badge to the right edge.
7570
+ *
7571
+ * The "ID:slug" handle and the description below it are both
7572
+ * indented to align with the title's left edge (i.e. past the
7573
+ * icon's column). The icon is 16px wide and the .run-card-top
7574
+ * gap is 10px, so 26px of left padding aligns subsequent rows
7575
+ * with the title.
7576
+ */
7577
+ .template-card-id-row {
7578
+ display: flex;
7579
+ margin-top: 6px;
7580
+ padding-left: 26px;
7581
+ }
7582
+ .template-card .run-card-meta {
7583
+ padding-left: 26px;
6026
7584
  }
6027
7585
 
6028
- /* Sidebar fleet-header clickable feedback */
6029
- .fleet-header-clickable {
6030
- transition: background-color var(--transition-fast);
7586
+ /*
7587
+ * Buttons pin to the card's bottom so cards of varying heights
7588
+ * (description length, badge presence) line their action rows up
7589
+ * with each other in a tier-section grid. `margin-top: auto` on
7590
+ * the last child of a column-flex container absorbs the extra
7591
+ * vertical space.
7592
+ */
7593
+ .template-card .run-card-actions {
7594
+ margin-top: auto;
6031
7595
  }
6032
7596
 
6033
- .fleet-header-clickable:hover {
6034
- background-color: color-mix(in srgb, var(--accent) 6%, transparent);
7597
+ .template-tier-badge {
7598
+ font-size: 12px;
7599
+ text-transform: uppercase;
7600
+ letter-spacing: 0.04em;
6035
7601
  }
6036
7602
 
6037
- /* Fleet list view (route: /#/fleet-runs) — one `fleet-card` per fleet.
6038
- No wrapping border / shared background; each card carries its own
6039
- chrome plus the layered stack-of-cards shadow. Gap matches the
6040
- gap between pipeline cards in run-list for visual consistency. */
6041
- .fleet-list {
6042
- display: flex;
6043
- flex-direction: column;
6044
- gap: 16px;
7603
+ .template-card .run-card-stages sl-tag {
7604
+ margin-right: 4px;
7605
+ margin-bottom: 4px;
6045
7606
  }
6046
7607
 
6047
- .fleet-list-row {
7608
+ .pipelines-empty {
6048
7609
  display: flex;
7610
+ flex-direction: column;
6049
7611
  align-items: center;
6050
- gap: 12px;
6051
- padding: 12px 16px;
6052
- border-bottom: 1px solid var(--border-subtle);
6053
- cursor: pointer;
6054
- transition: background-color var(--transition-fast);
7612
+ justify-content: center;
7613
+ text-align: center;
7614
+ padding: 64px 24px;
7615
+ gap: 16px;
7616
+ color: var(--fg-muted);
6055
7617
  }
6056
7618
 
6057
- .fleet-list-row:last-child {
6058
- border-bottom: none;
7619
+ .pipelines-empty .empty-state-icon {
7620
+ color: var(--fg-muted);
7621
+ opacity: 0.5;
7622
+ margin-bottom: 8px;
6059
7623
  }
6060
7624
 
6061
- .fleet-list-row:hover {
6062
- background-color: color-mix(in srgb, var(--accent) 6%, transparent);
7625
+ .pipelines-empty h2 {
7626
+ margin: 0;
7627
+ color: var(--fg);
7628
+ font-size: 20px;
7629
+ font-weight: 600;
6063
7630
  }
6064
7631
 
6065
- .fleet-list-row-title {
6066
- font-size: 14px;
6067
- font-weight: 600;
6068
- color: var(--fg);
6069
- flex: 1 1 auto;
6070
- min-width: 0;
6071
- overflow: hidden;
6072
- text-overflow: ellipsis;
6073
- white-space: nowrap;
7632
+ .pipelines-empty p {
7633
+ max-width: 480px;
7634
+ margin: 0 0 16px;
7635
+ line-height: 1.5;
7636
+ color: var(--fg-muted);
6074
7637
  }
6075
7638
 
6076
- .fleet-list-row-badge {
6077
- flex-shrink: 0;
7639
+ .pipelines-empty .empty-state-actions {
7640
+ display: flex;
7641
+ gap: 8px;
7642
+ margin-bottom: 8px;
6078
7643
  }
6079
7644
 
6080
- .fleet-list-row-meta {
6081
- font-size: 12px;
6082
- color: var(--muted);
6083
- flex-shrink: 0;
7645
+ .pipelines-empty .empty-state-hint {
7646
+ font-size: 13px;
7647
+ color: var(--fg-muted);
7648
+ border-top: 1px solid var(--border);
7649
+ padding-top: 16px;
6084
7650
  }
6085
7651
 
6086
- .fleet-list-row-id {
6087
- font-family: var(--sl-font-mono);
6088
- font-size: 11.5px;
6089
- color: var(--muted);
6090
- background: var(--bg-tertiary);
6091
- padding: 2px 8px;
6092
- border-radius: 4px;
6093
- flex-shrink: 0;
7652
+ /* Deep-link card for template-driven settings (W-062 Phase 6) */
7653
+ .pipelines-deep-link-card {
7654
+ border: 1px solid var(--border-subtle);
7655
+ border-radius: var(--radius-lg);
7656
+ background: var(--bg-secondary);
7657
+ padding: 16px;
7658
+ margin-bottom: 24px;
7659
+ box-shadow: var(--shadow-sm);
6094
7660
  }
6095
7661
 
6096
- .fleet-list-loading,
6097
- .fleet-list-empty {
6098
- padding: 24px;
6099
- text-align: center;
6100
- color: var(--muted);
7662
+ .pipelines-deep-link-content {
6101
7663
  display: flex;
6102
- flex-direction: column;
6103
7664
  align-items: center;
6104
- gap: 12px;
7665
+ gap: 16px;
6105
7666
  }
6106
7667
 
6107
- .fleet-detail-empty {
6108
- padding: 64px 24px;
6109
- text-align: center;
6110
- color: var(--muted);
7668
+ .pipelines-deep-link-icon {
6111
7669
  display: flex;
6112
- flex-direction: column;
6113
7670
  align-items: center;
6114
- gap: 12px;
6115
- max-width: 540px;
6116
- margin: 0 auto;
7671
+ justify-content: center;
7672
+ width: 40px;
7673
+ height: 40px;
7674
+ background: var(--bg-tertiary);
7675
+ border-radius: var(--radius);
7676
+ color: var(--accent);
7677
+ flex-shrink: 0;
6117
7678
  }
6118
7679
 
6119
- .fleet-detail-empty sl-icon {
6120
- font-size: 48px;
6121
- color: var(--muted);
6122
- opacity: 0.6;
7680
+ .pipelines-deep-link-text {
7681
+ flex: 1;
6123
7682
  }
6124
7683
 
6125
- .fleet-detail-empty h2 {
6126
- margin: 8px 0 0 0;
6127
- font-size: 18px;
7684
+ .pipelines-deep-link-title {
7685
+ font-size: 14px;
7686
+ font-weight: 600;
6128
7687
  color: var(--fg);
7688
+ margin-bottom: 4px;
6129
7689
  }
6130
7690
 
6131
- .fleet-detail-empty p {
6132
- margin: 0;
6133
- line-height: 1.5;
6134
- }
6135
-
6136
- .fleet-detail-empty code {
6137
- font-size: 12px;
6138
- background: var(--bg-2, var(--border));
6139
- padding: 1px 6px;
6140
- border-radius: 4px;
7691
+ .pipelines-deep-link-desc {
7692
+ font-size: 13px;
7693
+ color: var(--muted);
7694
+ line-height: 1.4;
6141
7695
  }
6142
7696
 
6143
- .fleet-detail-empty-hint {
7697
+ .pipelines-deep-link-btn {
7698
+ display: inline-flex;
7699
+ align-items: center;
7700
+ gap: 8px;
7701
+ padding: 8px 16px;
6144
7702
  font-size: 13px;
6145
- opacity: 0.85;
7703
+ font-weight: 500;
7704
+ color: var(--fg);
7705
+ background: var(--bg-tertiary);
7706
+ border: 1px solid var(--border);
7707
+ border-radius: var(--radius);
7708
+ text-decoration: none;
7709
+ cursor: pointer;
7710
+ transition: var(--transition-fast);
7711
+ white-space: nowrap;
6146
7712
  }
6147
7713
 
6148
- .fleet-detail-empty-hint a {
6149
- color: var(--accent, var(--fg));
7714
+ .pipelines-deep-link-btn:hover {
7715
+ background: var(--bg);
7716
+ border-color: var(--border-subtle);
7717
+ color: var(--fg-active);
6150
7718
  }
6151
7719
 
6152
- /* --- Workspace: tier styling --- */
6153
7720
 
6154
- .workspace-card-tiers {
7721
+ /* ─── Pipelines Editor ─────────────────────────────────────────────── */
7722
+
7723
+ .pipelines-editor {
6155
7724
  display: flex;
6156
7725
  flex-direction: column;
6157
- gap: 6px;
6158
- margin-top: 8px;
7726
+ height: 100%;
7727
+ max-height: calc(100vh - 120px);
6159
7728
  }
6160
7729
 
6161
- .workspace-tier-row {
7730
+ /*
7731
+ * Editor sub-header: lives below the page chrome's "Edit Template" title.
7732
+ * Shows the template name + scope badge on the left, view-mode toggle on
7733
+ * the right. No back button here — the page chrome already provides one.
7734
+ */
7735
+ .editor-subheader {
7736
+ display: flex;
7737
+ align-items: center;
7738
+ gap: 12px;
7739
+ padding: 12px 16px;
7740
+ border-bottom: 1px solid var(--border);
7741
+ background: var(--bg);
7742
+ position: sticky;
7743
+ top: 0;
7744
+ z-index: 10;
7745
+ }
7746
+
7747
+ .editor-subheader-title-group {
6162
7748
  display: flex;
6163
7749
  align-items: center;
6164
7750
  gap: 8px;
7751
+ flex: 1;
7752
+ min-width: 0;
6165
7753
  }
6166
7754
 
6167
- .tier-label {
6168
- font-size: 11px;
7755
+ /*
7756
+ * Inline editable Name + ID + read-only Storage in the editor
7757
+ * subheader. All three share the same gray-pill chassis
7758
+ * (`.editor-field-pill`) so the row reads as a single field group;
7759
+ * size/weight variants live on the per-pill modifier class.
7760
+ *
7761
+ * Name is the widest (flex-grow), ID is mid-width with a monospace
7762
+ * input, Storage is a fixed compact pill showing the tier.
7763
+ */
7764
+ .editor-field-pill {
7765
+ display: inline-flex;
7766
+ align-items: center;
7767
+ gap: 4px;
7768
+ padding: 2px 4px 2px 8px;
7769
+ border-radius: 9999px;
7770
+ background: var(--bg-secondary);
7771
+ border: 1px solid var(--border-subtle, var(--border));
7772
+ min-width: 0;
7773
+ }
7774
+ .editor-field-pill-label {
7775
+ font-size: 10px;
6169
7776
  font-weight: 600;
6170
- color: var(--muted);
7777
+ letter-spacing: 0.06em;
6171
7778
  text-transform: uppercase;
6172
- letter-spacing: 0.05em;
6173
- min-width: 60px;
7779
+ color: var(--fg-muted);
6174
7780
  flex-shrink: 0;
6175
7781
  }
6176
7782
 
6177
- .tier-status {
6178
- display: inline-flex;
6179
- align-items: center;
6180
- flex-shrink: 0;
7783
+ .editor-name-pill {
7784
+ flex: 1 1 240px;
7785
+ padding-right: 4px;
6181
7786
  }
6182
-
6183
- .tier-children {
6184
- display: flex;
6185
- flex-wrap: wrap;
6186
- gap: 4px;
7787
+ .editor-name-input {
7788
+ flex: 1;
7789
+ min-width: 0;
7790
+ }
7791
+ .editor-name-input::part(form-control-input) {
7792
+ font-weight: 600;
7793
+ }
7794
+ .editor-name-input::part(base) {
7795
+ border: none;
7796
+ background: transparent;
7797
+ box-shadow: none;
7798
+ min-height: 22px;
6187
7799
  }
6188
7800
 
6189
- .tier-child {
7801
+ .editor-id-badge {
7802
+ flex: 0 1 240px;
7803
+ }
7804
+ .editor-id-input {
7805
+ flex: 1;
7806
+ min-width: 0;
7807
+ }
7808
+ .editor-id-input::part(form-control-input) {
7809
+ font-family: var(--sl-font-mono);
6190
7810
  font-size: 12px;
6191
- padding: 2px 8px;
6192
- border-radius: 4px;
6193
- background: var(--bg-tertiary);
6194
- border: 1px solid var(--border);
7811
+ padding: 0 6px;
6195
7812
  }
6196
-
6197
- /* --- Workspace: DAG graph --- */
6198
-
6199
- .dag-preview {
6200
- overflow-x: auto;
6201
- border: 1px solid var(--border);
6202
- border-radius: var(--radius);
6203
- background: var(--bg-secondary);
6204
- padding: 16px;
7813
+ .editor-id-input::part(base) {
7814
+ border: none;
7815
+ background: transparent;
7816
+ box-shadow: none;
7817
+ min-height: 22px;
6205
7818
  }
6206
7819
 
6207
- .dag-preview svg {
6208
- display: block;
7820
+ .editor-storage-pill {
7821
+ flex: 0 0 auto;
7822
+ padding: 2px 10px 2px 8px;
6209
7823
  }
6210
7824
 
6211
- .workspace-dag-panel {
7825
+ /*
7826
+ * Description section sits above the tab group inside the scroll
7827
+ * area — outside any tab so it always shows. Matches the
7828
+ * settings-section header style (h3.settings-section-title +
7829
+ * settings-field + label + textarea) so the editor reads like
7830
+ * the rest of the app.
7831
+ */
7832
+ .editor-description-section {
6212
7833
  display: flex;
6213
7834
  flex-direction: column;
6214
- gap: 8px;
7835
+ gap: 12px;
7836
+ padding-bottom: 16px;
7837
+ margin-bottom: 4px;
7838
+ }
7839
+ .editor-description-input {
7840
+ width: 100%;
7841
+ }
7842
+ .editor-description-input::part(textarea) {
7843
+ font-size: 13px;
7844
+ line-height: 1.5;
7845
+ color: var(--fg);
7846
+ }
7847
+ .editor-storage-value {
7848
+ font-size: 12px;
7849
+ font-weight: 500;
7850
+ color: var(--fg);
7851
+ text-transform: capitalize;
6215
7852
  }
6216
7853
 
7854
+ /*
7855
+ * Visual error state on a field pill — used when the ID collides
7856
+ * with an existing template in the same tier. The border turns
7857
+ * warning-amber to match the inline badge that appears next to
7858
+ * the input and the disabled Save button.
7859
+ */
7860
+ .editor-field-pill--invalid {
7861
+ border-color: var(--sl-color-warning-600, #d97706);
7862
+ }
7863
+ .editor-id-collision-badge {
7864
+ flex-shrink: 0;
7865
+ }
6217
7866
 
7867
+ .editor-subheader-title {
7868
+ font-size: 16px;
7869
+ font-weight: 600;
7870
+ margin: 0;
7871
+ color: var(--fg);
7872
+ white-space: nowrap;
7873
+ overflow: hidden;
7874
+ text-overflow: ellipsis;
7875
+ }
6218
7876
 
6219
- .workspace-dag-svg {
6220
- overflow-x: auto;
7877
+ .icon-btn {
7878
+ background: none;
7879
+ border: none;
7880
+ padding: 4px;
7881
+ border-radius: 4px;
7882
+ cursor: pointer;
7883
+ color: var(--fg-muted);
7884
+ transition: var(--transition-fast);
6221
7885
  }
6222
7886
 
6223
- /* --- Workspace run card --- */
7887
+ .icon-btn:hover {
7888
+ background: var(--bg-secondary);
7889
+ color: var(--fg);
7890
+ }
6224
7891
 
6225
- /* --- Plan stage artifact strip (run-detail) --- */
7892
+ .editor-mode-toggle {
7893
+ margin-left: auto;
7894
+ }
6226
7895
 
6227
- .plan-artifact-strip {
6228
- display: flex;
6229
- align-items: center;
6230
- flex-wrap: wrap;
6231
- gap: 8px;
6232
- margin: 10px 0 4px;
7896
+ /*
7897
+ * Read-only badge in the editor subheader. Sits next to the tier
7898
+ * badge whenever we're viewing a built-in template; visually warns
7899
+ * the user that nothing they type here will save.
7900
+ */
7901
+ .editor-readonly-badge {
7902
+ margin-left: 4px;
6233
7903
  }
6234
- .plan-artifact-strip .plan-file-chip {
6235
- font-family: var(--font-mono);
6236
- font-size: 12px;
7904
+
7905
+ /*
7906
+ * Editor content gate: when readOnly, the form controls inside each
7907
+ * tab panel (and the JSON view) become non-interactive — but the
7908
+ * tab nav stays clickable so users can move between Models /
7909
+ * Stages / Agents / etc. to inspect the whole template. We scope
7910
+ * pointer-events:none to the panels (not the whole content) so the
7911
+ * `<sl-tab slot="nav">` items still take clicks.
7912
+ *
7913
+ * `aria-disabled="true"` on the wrapper tells assistive tech the
7914
+ * surface is locked; the per-panel muted opacity signals "look,
7915
+ * don't touch". Inputs visually keep their value so users can still
7916
+ * read and copy from them.
7917
+ *
7918
+ * Cheaper than threading a `disabled` flag through every section
7919
+ * and every input; tradeoff is screen readers won't announce each
7920
+ * control as disabled — only the panel container. Acceptable for a
7921
+ * read-only inspector mode.
7922
+ */
7923
+ .editor-content--readonly sl-tab-panel,
7924
+ .editor-content--readonly .editor-section--json {
7925
+ pointer-events: none;
7926
+ opacity: 0.7;
7927
+ user-select: text; /* let users still highlight + copy values */
7928
+ }
7929
+ .editor-content--readonly sl-tab-panel *,
7930
+ .editor-content--readonly .editor-section--json * {
7931
+ cursor: default !important;
7932
+ }
7933
+
7934
+ /*
7935
+ * Editor uses the same .settings-tab-content / .settings-section-title /
7936
+ * .settings-cards primitives as Project Settings — define one supporting
7937
+ * helper here (the lead-in paragraph under a section title) and a few
7938
+ * tab-group tweaks so the editor's tab nav sits naturally inside its
7939
+ * scroll container.
7940
+ */
7941
+ .settings-section-desc {
7942
+ margin: -2px 0 14px;
6237
7943
  color: var(--fg-muted);
7944
+ font-size: 13px;
7945
+ line-height: 1.5;
7946
+ }
7947
+ .settings-section-desc code {
6238
7948
  background: var(--bg-secondary);
6239
- padding: 2px 6px;
7949
+ padding: 1px 5px;
6240
7950
  border-radius: 4px;
6241
- max-width: 360px;
6242
- overflow: hidden;
6243
- text-overflow: ellipsis;
6244
- white-space: nowrap;
6245
- }
6246
- .plan-loading,
6247
- .plan-error {
6248
- display: flex;
6249
- align-items: center;
6250
- gap: 8px;
6251
- padding: 20px;
6252
- color: var(--fg-muted);
7951
+ font-size: 12px;
6253
7952
  }
6254
7953
 
6255
- /* W-061: plan revision selector inside the plan dialog */
6256
- .plan-iter-selector {
7954
+ .editor-tab-group {
7955
+ --indicator-color: var(--accent, var(--sl-color-primary-600, #4f9eff));
7956
+ /* Keep Shoelace's default track color (subtle border under the tab
7957
+ * row) so the editor matches the Project Settings convention of a
7958
+ * horizontal line between the nav and the panel content. Used to
7959
+ * be `transparent` which suppressed that divider. */
7960
+ }
7961
+ .editor-tab-group::part(base) {
7962
+ /* Hand the scroll to .editor-content so the tab nav stays sticky. */
7963
+ height: 100%;
7964
+ }
7965
+ /*
7966
+ * Tab nav style mirrors the project Settings tabs: 13px medium,
7967
+ * 10/16 padding, and a clear gap between the icon and the label
7968
+ * so the icon doesn't visually fuse with the first letter.
7969
+ */
7970
+ .editor-tab-group sl-tab::part(base) {
7971
+ font-size: 13px;
7972
+ font-weight: 500;
7973
+ padding: 10px 16px;
7974
+ gap: 6px;
6257
7975
  display: flex;
6258
- flex-wrap: wrap;
6259
7976
  align-items: center;
6260
- gap: 6px;
6261
- margin: 0 0 12px;
6262
- padding-bottom: 12px;
6263
- border-bottom: 1px solid var(--border, var(--bg-secondary));
6264
7977
  }
6265
-
6266
- /* --- sl-dialog: wider markdown-body dialogs (plan, guide) --- */
6267
-
6268
- sl-dialog.markdown-dialog::part(panel) {
6269
- /* Default sl-dialog is ~31rem wide — too narrow for prose with code
6270
- blocks. Cap at 90vw so it stays comfortable on small viewports. */
6271
- width: min(960px, 90vw);
6272
- max-width: min(960px, 90vw);
7978
+ .editor-tab-group sl-tab svg {
7979
+ width: 14px;
7980
+ height: 14px;
7981
+ flex-shrink: 0;
6273
7982
  }
6274
- sl-dialog.markdown-dialog::part(body) {
6275
- /* Give the body breathing room and let it scroll vertically instead
6276
- of the whole dialog growing without bound. */
6277
- max-height: 70vh;
6278
- overflow: auto;
7983
+ .editor-tab-group sl-tab-panel::part(base) {
7984
+ padding: 16px 4px 0;
6279
7985
  }
6280
7986
 
6281
- /* --- Markdown body styling (used by guide-content + workspace-plan-content) --- */
7987
+ /*
7988
+ * Pipeline tab holds three sections (Stage configuration, Loop
7989
+ * limits, Circuit breaker) on one panel — the same shape as the
7990
+ * Project Settings → Pipeline tab. Each section is its own
7991
+ * `.settings-tab-content` flex column with gap:20px between fields
7992
+ * but no margin above the section heading, so without an explicit
7993
+ * separator they jam right up against each other. Give the three
7994
+ * direct children real vertical breathing room.
7995
+ */
7996
+ .editor-pipeline-tab {
7997
+ display: flex;
7998
+ flex-direction: column;
7999
+ gap: 32px;
8000
+ }
8001
+ .editor-pipeline-tab > .settings-tab-content + .settings-tab-content {
8002
+ /* Visual separator on top of the gap so it reads as a fresh
8003
+ * section rather than a continuation of the previous one. */
8004
+ border-top: 1px solid var(--border-subtle, var(--border));
8005
+ padding-top: 24px;
8006
+ }
6282
8007
 
6283
- .markdown-body {
6284
- font-family: var(--sl-font-sans, system-ui, sans-serif);
6285
- font-size: 14px;
6286
- line-height: 1.55;
6287
- color: var(--fg);
8008
+ /*
8009
+ * Shared chrome for the template action dialogs (Create / Duplicate /
8010
+ * Rename / Import). Wraps the Settings-style form primitives so the
8011
+ * dialog body looks like a one-screen mini Settings tab.
8012
+ */
8013
+ .template-action-dialog::part(panel) {
8014
+ min-width: min(520px, 100vw - 32px);
6288
8015
  }
6289
- .markdown-body h1,
6290
- .markdown-body h2,
6291
- .markdown-body h3,
6292
- .markdown-body h4 {
6293
- margin: 1.2em 0 0.5em;
6294
- line-height: 1.25;
6295
- font-weight: 600;
8016
+ .template-action-dialog .dialog-lead {
8017
+ margin: 0 0 14px;
8018
+ color: var(--fg-muted);
8019
+ font-size: 13px;
8020
+ line-height: 1.5;
6296
8021
  }
6297
- .markdown-body h1 { font-size: 1.5em; }
6298
- .markdown-body h2 { font-size: 1.25em; border-bottom: 1px solid var(--border-subtle); padding-bottom: 4px; }
6299
- .markdown-body h3 { font-size: 1.1em; }
6300
- .markdown-body p { margin: 0.6em 0; }
6301
- .markdown-body ul,
6302
- .markdown-body ol { margin: 0.6em 0; padding-left: 1.5em; }
6303
- .markdown-body li { margin: 0.25em 0; }
6304
- .markdown-body code {
6305
- font-family: var(--font-mono);
6306
- font-size: 0.9em;
8022
+ .template-action-dialog .dialog-lead code {
6307
8023
  background: var(--bg-secondary);
6308
8024
  padding: 1px 5px;
6309
- border-radius: 3px;
8025
+ border-radius: 4px;
8026
+ font-size: 12px;
6310
8027
  }
6311
- .markdown-body pre {
6312
- background: var(--bg-secondary);
6313
- border: 1px solid var(--border-subtle);
6314
- border-radius: 6px;
6315
- padding: 10px 12px;
6316
- overflow-x: auto;
6317
- font-size: 12.5px;
8028
+ .template-action-dialog .settings-field {
8029
+ margin-bottom: 14px;
6318
8030
  }
6319
- .markdown-body pre code {
6320
- background: transparent;
6321
- padding: 0;
6322
- border-radius: 0;
8031
+ .template-action-dialog .dialog-error {
8032
+ margin-top: 8px;
6323
8033
  }
6324
- .markdown-body blockquote {
6325
- border-left: 3px solid var(--border);
6326
- padding: 4px 12px;
6327
- margin: 0.6em 0;
8034
+ .template-action-dialog .dialog-bundle-list {
8035
+ margin: 4px 0 0;
8036
+ padding-left: 18px;
8037
+ font-size: 13px;
6328
8038
  color: var(--fg-muted);
6329
8039
  }
6330
- .markdown-body a { color: var(--accent); }
6331
- .markdown-body table {
6332
- border-collapse: collapse;
6333
- margin: 0.8em 0;
8040
+ .template-action-dialog .dialog-bundle-list code {
8041
+ font-family: var(--sl-font-mono);
8042
+ color: var(--fg);
6334
8043
  }
6335
- .markdown-body th,
6336
- .markdown-body td {
6337
- border: 1px solid var(--border-subtle);
6338
- padding: 4px 8px;
6339
- text-align: left;
8044
+
8045
+ .editor-content {
8046
+ flex: 1;
8047
+ overflow-y: auto;
8048
+ padding: 16px;
8049
+ display: flex;
8050
+ flex-direction: column;
8051
+ gap: 24px;
6340
8052
  }
6341
8053
 
6342
- /* --- Markdown context overrides --- */
8054
+ /* Editor Sections */
6343
8055
 
6344
- .markdown-inline.markdown-body {
6345
- display: inline;
6346
- font-size: inherit;
6347
- line-height: inherit;
8056
+ .editor-section {
8057
+ max-width: 900px;
6348
8058
  }
6349
- .markdown-inline.markdown-body p {
6350
- display: inline;
8059
+
8060
+ .editor-section--json {
8061
+ max-width: 1000px;
8062
+ }
8063
+
8064
+ .section-header {
8065
+ display: flex;
8066
+ align-items: center;
8067
+ justify-content: space-between;
8068
+ margin-bottom: 12px;
8069
+ }
8070
+
8071
+ .section-title {
8072
+ font-size: 15px;
8073
+ font-weight: 600;
6351
8074
  margin: 0;
8075
+ color: var(--fg);
6352
8076
  }
6353
- .markdown-inline.markdown-body code {
6354
- font-size: 0.85em;
8077
+
8078
+ /* Stages List */
8079
+
8080
+ .stages-list {
8081
+ display: flex;
8082
+ flex-direction: column;
8083
+ gap: 8px;
8084
+ }
8085
+
8086
+ .stage-row {
8087
+ display: flex;
8088
+ align-items: center;
8089
+ gap: 12px;
8090
+ padding: 12px;
8091
+ background: var(--bg-secondary);
8092
+ border: 1px solid var(--border);
8093
+ border-radius: var(--radius);
8094
+ transition: var(--transition-fast);
6355
8095
  }
6356
8096
 
6357
- .agent-prompt-content .markdown-body {
6358
- white-space: normal;
6359
- font-size: 12px;
6360
- line-height: 1.5;
8097
+ .stage-row--disabled {
8098
+ opacity: 0.5;
6361
8099
  }
6362
- .agent-prompt-content .markdown-body h1,
6363
- .agent-prompt-content .markdown-body h2,
6364
- .agent-prompt-content .markdown-body h3 {
6365
- margin: 0.8em 0 0.3em;
8100
+
8101
+ .stage-row-info {
8102
+ display: flex;
8103
+ align-items: center;
8104
+ gap: 8px;
8105
+ flex: 1;
6366
8106
  }
6367
8107
 
6368
- .bead-tooltip-excerpt.markdown-body {
6369
- white-space: normal;
6370
- font-size: 12px;
6371
- max-height: 200px;
6372
- overflow-y: auto;
6373
- /* Inherit the tooltip's (light) text color instead of --fg, which is the
6374
- main-panel foreground and renders dark-on-dark inside the tooltip. */
6375
- color: inherit;
8108
+ .stage-name {
8109
+ font-weight: 500;
8110
+ font-family: var(--sl-font-mono);
6376
8111
  }
6377
- .bead-tooltip-excerpt.markdown-body p {
6378
- margin: 0.3em 0;
8112
+
8113
+ .stage-row.disabled .stage-name {
8114
+ text-decoration: line-through;
6379
8115
  }
6380
- .bead-tooltip-excerpt.markdown-body pre {
6381
- font-size: 11px;
6382
- max-height: 120px;
6383
- overflow: auto;
8116
+
8117
+ .stage-row-agent {
8118
+ width: 200px;
6384
8119
  }
6385
- /* The base markdown code/blockquote/link colors assume the light main panel;
6386
- re-tint them for the dark tooltip surface so they stay legible. */
6387
- .bead-tooltip-excerpt.markdown-body code,
6388
- .bead-tooltip-excerpt.markdown-body pre {
6389
- background: rgba(255, 255, 255, 0.1);
6390
- border-color: rgba(255, 255, 255, 0.15);
8120
+
8121
+ /* Agents Matrix */
8122
+
8123
+ .agents-matrix {
8124
+ display: flex;
8125
+ flex-direction: column;
8126
+ gap: 8px;
6391
8127
  }
6392
- .bead-tooltip-excerpt.markdown-body blockquote {
6393
- color: inherit;
6394
- opacity: 0.8;
6395
- border-left-color: rgba(255, 255, 255, 0.3);
8128
+
8129
+ .agent-row {
8130
+ display: flex;
8131
+ align-items: center;
8132
+ gap: 12px;
8133
+ padding: 10px 12px;
8134
+ background: var(--bg-secondary);
8135
+ border: 1px solid var(--border);
8136
+ border-radius: var(--radius);
6396
8137
  }
6397
8138
 
6398
- .workspace-run-card .workspace-card-root,
6399
- .workspace-run-card .workspace-card-name {
6400
- font-family: var(--font-mono);
6401
- font-size: 12px;
6402
- color: var(--fg-muted);
8139
+ .agent-name {
8140
+ flex: 0 0 100px;
8141
+ font-weight: 500;
8142
+ font-family: var(--sl-font-mono);
6403
8143
  }
6404
8144
 
6405
- /* --- Workspace forms: external-repo picker --- */
8145
+ .agent-fields {
8146
+ display: grid;
8147
+ grid-template-columns: 1fr 1fr 1fr;
8148
+ gap: 8px;
8149
+ flex: 1;
8150
+ }
6406
8151
 
6407
- .repo-checklist-actions {
8152
+ .agent-field {
6408
8153
  display: flex;
6409
- align-items: center;
8154
+ flex-direction: column;
8155
+ gap: 4px;
8156
+ }
8157
+
8158
+ /* Loops Grid */
8159
+
8160
+ .loops-grid {
8161
+ display: grid;
8162
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
6410
8163
  gap: 12px;
6411
- margin-top: 12px;
6412
- flex-wrap: wrap;
6413
8164
  }
6414
- .ws-external-tag {
6415
- margin-left: 8px;
8165
+
8166
+ .loop-field {
8167
+ display: flex;
8168
+ flex-direction: column;
8169
+ gap: 4px;
6416
8170
  }
6417
8171
 
6418
- /* --- Workspace forms: Dependency Graph label --- */
8172
+ /* Circuit Breaker Grid */
6419
8173
 
6420
- .dag-preview-block {
6421
- margin-top: 16px;
6422
- }
6423
- .dag-preview-label {
6424
- display: block;
6425
- margin-bottom: 8px;
8174
+ .circuit-breaker-grid {
8175
+ display: grid;
8176
+ grid-template-columns: 1fr 1fr;
8177
+ gap: 16px;
6426
8178
  }
6427
8179
 
6428
- /* --- Workspace edit: scan-for-additions status + Available tag --- */
8180
+ .cb-field {
8181
+ display: flex;
8182
+ flex-direction: column;
8183
+ gap: 8px;
8184
+ }
6429
8185
 
6430
- .ws-edit-scan-status {
8186
+ .cb-field-row {
6431
8187
  display: flex;
6432
8188
  align-items: center;
6433
8189
  gap: 8px;
6434
- font-size: 13px;
6435
- color: var(--fg-muted);
6436
- margin-bottom: 12px;
6437
- }
6438
- .ws-edit-scan-error {
6439
- margin-bottom: 12px;
6440
- }
6441
- .ws-edit-new-tag {
6442
- margin-left: 8px;
6443
8190
  }
6444
8191
 
6445
- /* --- Workspace create: Parent Directory row --- */
8192
+ /* Governance */
6446
8193
 
6447
- .parent-dir-row {
8194
+ .governance-content {
6448
8195
  display: flex;
6449
- gap: 8px;
6450
- align-items: stretch;
6451
- }
6452
- .parent-dir-row .input-parent-dir {
6453
- flex: 1;
8196
+ flex-direction: column;
8197
+ gap: 24px;
6454
8198
  }
6455
- .parent-dir-suggestions {
6456
- margin-top: 8px;
8199
+
8200
+ /* JSON Editor */
8201
+
8202
+ .json-editor-wrapper {
8203
+ background: var(--bg-secondary);
6457
8204
  border: 1px solid var(--border);
6458
- border-radius: 6px;
6459
- background: var(--bg);
6460
- overflow: hidden;
8205
+ border-radius: var(--radius);
8206
+ padding: 4px;
6461
8207
  }
6462
- .parent-dir-suggestions-label {
6463
- padding: 6px 12px;
6464
- font-size: 11px;
6465
- text-transform: uppercase;
6466
- letter-spacing: 0.04em;
8208
+
8209
+ .json-editor {
8210
+ font-family: var(--sl-font-mono);
8211
+ font-size: 13px;
8212
+ line-height: 1.5;
8213
+ min-height: 300px;
8214
+ resize: vertical;
8215
+ }
8216
+
8217
+ .json-editor-hint {
8218
+ font-size: 12px;
6467
8219
  color: var(--fg-muted);
6468
- background: var(--bg-secondary);
6469
- border-bottom: 1px solid var(--border-subtle);
8220
+ margin-top: 8px;
6470
8221
  }
6471
- .parent-dir-suggestion-item {
6472
- display: flex;
6473
- align-items: center;
6474
- gap: 8px;
6475
- width: 100%;
6476
- padding: 8px 12px;
6477
- background: transparent;
6478
- border: none;
6479
- border-bottom: 1px solid var(--border-subtle);
6480
- cursor: pointer;
6481
- font-family: var(--font-mono);
8222
+
8223
+ /* Diff view styles */
8224
+ .diff-hint {
6482
8225
  font-size: 13px;
6483
- color: var(--fg);
6484
- text-align: left;
8226
+ color: var(--fg-muted);
8227
+ margin-bottom: 16px;
8228
+ line-height: 1.5;
6485
8229
  }
6486
- .parent-dir-suggestion-item:last-child {
6487
- border-bottom: none;
8230
+
8231
+ .diff-reset-icon {
8232
+ display: inline-block;
8233
+ vertical-align: middle;
8234
+ margin: 0 4px;
8235
+ color: var(--accent);
6488
8236
  }
6489
- .parent-dir-suggestion-item:hover {
6490
- background: var(--bg-hover);
8237
+
8238
+ .diff-no-changes {
8239
+ text-align: center;
8240
+ padding: 48px 24px;
8241
+ color: var(--status-completed);
6491
8242
  }
6492
- .parent-dir-suggestion-item svg {
6493
- flex-shrink: 0;
8243
+
8244
+ .diff-no-changes svg {
8245
+ margin-bottom: 16px;
8246
+ color: var(--status-completed);
8247
+ }
8248
+
8249
+ .diff-no-changes h3 {
8250
+ margin: 0 0 8px 0;
8251
+ font-size: 16px;
8252
+ font-weight: 600;
8253
+ }
8254
+
8255
+ .diff-no-changes p {
8256
+ margin: 0;
6494
8257
  color: var(--fg-muted);
6495
8258
  }
6496
8259
 
6497
- /* --- Configuration → Workspaces list --- */
8260
+ .diff-empty,
8261
+ .diff-loading {
8262
+ padding: 24px;
8263
+ text-align: center;
8264
+ color: var(--fg-muted);
8265
+ }
6498
8266
 
6499
- .workspaces-config-empty {
8267
+ .diff-loading {
6500
8268
  display: flex;
6501
- flex-direction: column;
6502
8269
  align-items: center;
6503
8270
  justify-content: center;
6504
- text-align: center;
6505
- padding: 64px 24px;
6506
8271
  gap: 12px;
6507
- color: var(--fg-muted);
6508
- }
6509
- .workspaces-config-empty .empty-icon {
6510
- color: var(--fg-muted);
6511
- opacity: 0.5;
6512
- margin-bottom: 8px;
6513
- }
6514
- .workspaces-config-empty h3 {
6515
- margin: 0;
6516
- color: var(--fg);
6517
- }
6518
- .workspaces-config-empty p {
6519
- max-width: 480px;
6520
- margin: 0 0 12px;
6521
- line-height: 1.5;
6522
8272
  }
6523
8273
 
6524
- .workspaces-config-table {
6525
- padding: 16px;
8274
+ .diff-table-container {
6526
8275
  overflow-x: auto;
8276
+ border: 1px solid var(--border);
8277
+ border-radius: var(--radius);
6527
8278
  }
6528
- .workspaces-config-table table {
8279
+
8280
+ .diff-table {
6529
8281
  width: 100%;
6530
8282
  border-collapse: collapse;
6531
- font-size: 14px;
8283
+ font-size: 13px;
6532
8284
  }
6533
- .workspaces-config-table thead th {
8285
+
8286
+ .diff-table th {
6534
8287
  text-align: left;
8288
+ padding: 10px 12px;
8289
+ background: var(--bg-secondary);
8290
+ border-bottom: 2px solid var(--border);
6535
8291
  font-weight: 600;
6536
- padding: 8px 12px;
6537
- border-bottom: 1px solid var(--border);
6538
- color: var(--fg-muted);
6539
- text-transform: uppercase;
8292
+ color: var(--fg);
8293
+ position: sticky;
8294
+ top: 0;
8295
+ }
8296
+
8297
+ .diff-table td {
8298
+ padding: 10px 12px;
8299
+ border-bottom: 1px solid var(--border-subtle);
8300
+ vertical-align: top;
8301
+ }
8302
+
8303
+ .diff-row--changed {
8304
+ background: rgba(251, 191, 36, 0.05);
8305
+ }
8306
+
8307
+ .diff-row--changed .diff-path {
8308
+ font-weight: 600;
8309
+ }
8310
+
8311
+ .diff-path code {
8312
+ display: block;
8313
+ font-family: ui-monospace, 'SF Mono', 'Menlo', monospace;
6540
8314
  font-size: 11px;
6541
- letter-spacing: 0.04em;
8315
+ color: var(--fg-muted);
8316
+ margin-bottom: 4px;
8317
+ }
8318
+
8319
+ .diff-label {
8320
+ display: block;
8321
+ font-size: 12px;
8322
+ color: var(--fg);
8323
+ }
8324
+
8325
+ .diff-value {
8326
+ font-family: ui-monospace, 'SF Mono', 'Menlo', monospace;
8327
+ font-size: 12px;
8328
+ max-width: 300px;
8329
+ overflow-x: auto;
8330
+ white-space: pre-wrap;
8331
+ word-break: break-all;
6542
8332
  }
6543
- .workspaces-config-table tbody td {
6544
- padding: 12px;
6545
- border-bottom: 1px solid var(--border);
6546
- vertical-align: middle;
8333
+
8334
+ .diff-value--builtin {
8335
+ color: var(--fg-muted);
8336
+ background: var(--bg-tertiary);
8337
+ padding: 4px 8px;
8338
+ border-radius: 4px;
6547
8339
  }
6548
- .workspaces-config-table tbody tr:hover {
6549
- background: var(--bg-hover);
8340
+
8341
+ .diff-value--current {
8342
+ color: var(--fg);
8343
+ background: rgba(59, 130, 246, 0.1);
8344
+ padding: 4px 8px;
8345
+ border-radius: 4px;
6550
8346
  }
6551
- .workspaces-config-table .ws-name strong {
6552
- font-weight: 600;
8347
+
8348
+ .diff-actions {
8349
+ white-space: nowrap;
6553
8350
  }
6554
- .workspaces-config-table .ws-path code,
6555
- .workspaces-config-table .ws-umbrella {
6556
- font-family: var(--font-mono);
8351
+
8352
+ /* Common field styles */
8353
+
8354
+ .field-label {
6557
8355
  font-size: 12px;
8356
+ font-weight: 500;
6558
8357
  color: var(--fg-muted);
6559
8358
  }
6560
- .workspaces-config-table .ws-tiers {
6561
- color: var(--fg-muted);
8359
+
8360
+ .field-hint {
6562
8361
  font-size: 12px;
6563
- margin-left: 4px;
6564
- }
6565
- .workspaces-config-table .ws-dash {
6566
8362
  color: var(--fg-muted);
6567
- opacity: 0.5;
6568
- }
6569
- .workspaces-config-table .actions-col {
6570
- text-align: right;
6571
8363
  }
6572
- .workspaces-config-table .ws-actions {
8364
+
8365
+ /* Footer */
8366
+
8367
+ .editor-footer {
6573
8368
  display: flex;
6574
- gap: 4px;
8369
+ align-items: center;
6575
8370
  justify-content: flex-end;
8371
+ gap: 8px;
8372
+ padding: 12px 16px;
8373
+ border-top: 1px solid var(--border);
8374
+ background: var(--bg);
8375
+ position: sticky;
8376
+ bottom: 0;
8377
+ z-index: 10;
6576
8378
  }
6577
- .ws-action-btn {
6578
- background: transparent;
6579
- border: 1px solid var(--border);
6580
- border-radius: 4px;
6581
- padding: 4px 6px;
6582
- cursor: pointer;
6583
- color: var(--fg);
6584
- display: inline-flex;
6585
- align-items: center;
6586
- justify-content: center;
8379
+
8380
+ /* Save alert */
8381
+
8382
+ .editor-save-alert {
8383
+ margin-bottom: 16px;
6587
8384
  }
6588
- .ws-action-btn:hover {
6589
- background: var(--bg-hover);
8385
+
8386
+ .editor-validation-alert {
8387
+ margin-bottom: 16px;
6590
8388
  }
6591
- .ws-action-btn--danger:hover {
6592
- background: rgba(220, 38, 38, 0.1);
6593
- color: rgb(220, 38, 38);
6594
- border-color: rgba(220, 38, 38, 0.4);
8389
+
8390
+ .validation-list {
8391
+ margin: 8px 0 0 16px;
8392
+ padding-left: 20px;
8393
+ font-size: 13px;
6595
8394
  }
6596
8395
 
6597
- .dag-graph-node rect {
6598
- rx: 6;
6599
- fill: var(--bg);
6600
- stroke: var(--border);
6601
- stroke-width: 1.5;
8396
+ .validation-list li {
8397
+ margin-bottom: 4px;
6602
8398
  }
6603
8399
 
6604
- .dag-graph-node text {
6605
- font-size: 12px;
6606
- font-family: var(--sl-font-sans);
6607
- fill: var(--fg);
8400
+ .validation-list code {
8401
+ font-family: var(--sl-font-mono);
8402
+ background: var(--bg-tertiary);
8403
+ padding: 2px 4px;
8404
+ border-radius: 3px;
6608
8405
  }
6609
8406
 
6610
- .dag-graph-edge {
6611
- fill: none;
6612
- stroke: var(--border);
6613
- stroke-width: 2;
8407
+ /* Loading state */
8408
+
8409
+ .editor-loading {
8410
+ display: flex;
8411
+ align-items: center;
8412
+ justify-content: center;
8413
+ padding: 40px;
8414
+ font-size: 14px;
8415
+ color: var(--fg-muted);
8416
+ gap: 8px;
6614
8417
  }
6615
8418
 
6616
- .dag-graph-node--status-pending rect { stroke: var(--status-pending); }
6617
- .dag-graph-node--status-running rect { stroke: var(--status-running); }
6618
- .dag-graph-node--status-completed rect { stroke: var(--status-completed); }
6619
- .dag-graph-node--status-failed rect { stroke: var(--status-failed); }
6620
- .dag-graph-node--status-paused rect { stroke: var(--status-paused); }
6621
- .dag-graph-node--status-blocked rect { stroke: var(--status-blocked); }
6622
- .dag-graph-node--status-planning rect { stroke: var(--status-running); }
6623
- .dag-graph-node--status-integration-testing rect { stroke: var(--status-running); }
6624
- .dag-graph-node--status-integration-failed rect { stroke: var(--status-failed); }
8419
+ /* ===========================================================================
8420
+ * Help mode (W-061 prototype, prototype/W-061-help-mode-toggle)
8421
+ *
8422
+ * Two concerns:
8423
+ * 1. The right-edge "Docs" tab (.help-edge-tab) — always visible at 75%
8424
+ * opacity, fully opaque on hover/active.
8425
+ * 2. Per-surface "?" badges (.help-badge) — hidden until body has the
8426
+ * .help-mode-active class.
8427
+ *
8428
+ * Colour: violet (~#7c3aed) — deliberately chosen so help mode reads as
8429
+ * "informational / secondary" and never competes with the blue used for
8430
+ * primary actions + running state, the green used for completed, the
8431
+ * orange used for caution, or the red used for failed.
8432
+ *
8433
+ * Animation: each badge radiates a slow sonar wave outward and fades to
8434
+ * transparent, like a discoverability signal. `prefers-reduced-motion`
8435
+ * collapses the wave to a static dim halo.
8436
+ * ===========================================================================
8437
+ */
8438
+
8439
+ /* --- Edge tab --------------------------------------------------------- */
8440
+
8441
+ .help-edge-tab-root {
8442
+ position: fixed;
8443
+ inset: 0;
8444
+ pointer-events: none;
8445
+ z-index: 1000;
8446
+ }
6625
8447
 
6626
- /* --- Workspace: conflict icon --- */
8448
+ /* Vertical pill anchored ~100px from the top of the viewport (deliberately
8449
+ off-centre so it sits above the eye line and doesn't compete with
8450
+ sidebar/main content for the visual centre). */
8451
+ .help-edge-tab {
8452
+ position: fixed;
8453
+ right: 0;
8454
+ top: 100px;
8455
+ transform: translateX(0);
8456
+ transform-origin: right center;
8457
+ pointer-events: auto;
6627
8458
 
6628
- .conflict-icon {
6629
- color: var(--status-blocked);
8459
+ display: inline-flex;
8460
+ flex-direction: column;
8461
+ align-items: center;
8462
+ justify-content: center;
8463
+ /* Sized to wrap the rotated content (icon ~20px + 10px gap + "Docs"
8464
+ label ~38px ≈ 68px length, 20px max thickness). Height bumped +25%
8465
+ (84 → 105) per the user's request to give the rotated content more
8466
+ padding at the top and bottom of the tab. */
8467
+ width: 30px;
8468
+ height: 105px;
8469
+ padding: 0;
8470
+ border: 1px solid #c4b5fd; /* violet-300 */
8471
+ border-right: none;
8472
+ border-top-left-radius: 8px;
8473
+ border-bottom-left-radius: 8px;
8474
+ background: rgba(124, 58, 237, 0.1); /* violet-600 @ 10% */
8475
+ color: #5b21b6; /* violet-800 */
8476
+ font-size: 16px;
8477
+ font-weight: 600;
8478
+ letter-spacing: 0.04em;
8479
+ cursor: pointer;
8480
+ opacity: 0.75;
8481
+ box-shadow: -2px 0 8px rgba(0, 0, 0, 0.06);
8482
+ transition: opacity 160ms ease, background-color 120ms ease, color 120ms ease,
8483
+ transform 180ms ease, box-shadow 180ms ease;
6630
8484
  }
6631
8485
 
6632
- /* Graphify cache location — selectable monospace path (W-053 cache relocation) */
6633
- .graphify-codebox {
6634
- display: block;
6635
- margin: 0.25rem 0 0.75rem;
6636
- padding: 0.4rem 0.6rem;
6637
- background: var(--bg-secondary);
6638
- border: 1px solid var(--border-subtle);
6639
- border-radius: var(--radius);
6640
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
6641
- font-size: 0.85rem;
6642
- color: var(--fg);
6643
- word-break: break-all;
6644
- user-select: all;
8486
+ .help-edge-tab:hover,
8487
+ .help-edge-tab:focus-visible {
8488
+ opacity: 1;
8489
+ color: #4c1d95; /* violet-900 */
8490
+ background: rgba(124, 58, 237, 0.18);
8491
+ transform: translateX(-2px);
8492
+ box-shadow: -4px 0 12px rgba(0, 0, 0, 0.08);
8493
+ outline: none;
6645
8494
  }
6646
8495
 
6647
- /* A monospace value/command box with a copy button pinned to the right. */
6648
- .graphify-copy-row {
6649
- display: flex;
6650
- align-items: center;
6651
- gap: 0.4rem;
6652
- margin: 0.25rem 0 0.75rem;
8496
+ .help-edge-tab:focus-visible {
8497
+ box-shadow: -4px 0 12px rgba(0, 0, 0, 0.08), 0 0 0 2px #7c3aed;
6653
8498
  }
6654
8499
 
6655
- .graphify-copy-row .graphify-codebox {
6656
- flex: 1;
6657
- min-width: 0;
6658
- margin: 0;
8500
+ .help-edge-tab--active {
8501
+ opacity: 1;
8502
+ background: #7c3aed; /* violet-600 */
8503
+ color: #fff;
8504
+ border-color: #6d28d9; /* violet-700 */
6659
8505
  }
6660
8506
 
6661
- /* Shown when the graphify CLI is missing/incompatible. */
6662
- .graphify-not-installed {
6663
- margin: 0 0 0.75rem;
8507
+ .help-edge-tab--active:hover,
8508
+ .help-edge-tab--active:focus-visible {
8509
+ background: #6d28d9;
8510
+ color: #fff;
6664
8511
  }
6665
8512
 
6666
- /* Caution color (action needed: install) on the message text only — not the
6667
- install-command code box, which keeps normal monospace styling. */
6668
- .graphify-not-installed .settings-tab-description {
6669
- color: var(--status-paused);
8513
+ /* Inner row is icon + "Docs". Rotating the entire row -90deg (counter-
8514
+ clockwise) makes both the icon and the label share the same rotation,
8515
+ reading bottom-to-top along the right edge (head tilted left). */
8516
+ .help-edge-tab__inner {
8517
+ display: inline-flex;
8518
+ flex-direction: row;
8519
+ align-items: center;
8520
+ gap: 10px;
8521
+ transform: rotate(-90deg);
8522
+ transform-origin: center center;
8523
+ white-space: nowrap;
6670
8524
  }
6671
8525
 
6672
- /* Code Review Graph (CRG) — mirrors graphify-* classes above */
6673
- .crg-codebox {
6674
- display: block;
6675
- margin: 0.25rem 0 0.75rem;
6676
- padding: 0.4rem 0.6rem;
6677
- background: var(--bg-secondary);
6678
- border: 1px solid var(--border-subtle);
6679
- border-radius: var(--radius);
6680
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
6681
- font-size: 0.85rem;
6682
- color: var(--fg);
6683
- word-break: break-all;
6684
- user-select: all;
8526
+ .help-edge-tab__icon {
8527
+ display: inline-flex;
8528
+ align-items: center;
8529
+ justify-content: center;
6685
8530
  }
6686
8531
 
6687
- .crg-copy-row {
6688
- display: flex;
8532
+ .help-edge-tab__label {
8533
+ /* Matches the sidebar's WORCA wordmark (.logo-text) — JetBrains Mono
8534
+ family + bold weight + wide letter-spacing — so the affordance reads
8535
+ as part of the brand vocabulary rather than a generic side tab. */
8536
+ font-family: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
8537
+ font-weight: 700;
8538
+ letter-spacing: 0.08em;
8539
+ line-height: 1;
8540
+ }
8541
+
8542
+ /* --- Per-surface help badge ------------------------------------------- */
8543
+
8544
+ /* Hidden by default. Once help-mode-active flips on the body, every badge
8545
+ reveals at the top-right of its parent and emits a slow sonar wave that
8546
+ radiates outward then fades.
8547
+
8548
+ The badge is a real <a> — keyboard reachable when visible, opens the
8549
+ doc in a new tab, never depends on JS for click handling. */
8550
+ .help-badge {
8551
+ display: none;
8552
+ position: absolute;
8553
+ /* Vertically centred on the host's right edge — gives the sonar wave
8554
+ equal headroom above and below the badge so it doesn't overflow
8555
+ the host's bounding box. With disc 27px and wave max scale 1.5,
8556
+ max wave diameter is ~40px → fits inside any host ≥ 40px tall
8557
+ (typical sl-tab ~40px, panel headers larger). */
8558
+ top: 50%;
8559
+ right: 6px;
8560
+ transform: translateY(-50%);
8561
+ z-index: 5;
8562
+
6689
8563
  align-items: center;
6690
- gap: 0.4rem;
6691
- margin: 0.25rem 0 0.75rem;
8564
+ justify-content: center;
8565
+ /* Solid disc 27×27 — entire badge scaled up 50% (18 → 27). Icon, wave
8566
+ base, and clickable hit target all grow proportionally. */
8567
+ width: 27px;
8568
+ height: 27px;
8569
+ border-radius: 50%;
8570
+ /* Solid disc at 75% opacity — rgba on the background only so the
8571
+ ::after sonar wave's own opacity animation (0.55 → 0) isn't dimmed
8572
+ by parent inheritance. The white glyph stays fully visible. */
8573
+ background: rgba(124, 58, 237, 0.75); /* violet-600 @ 75% */
8574
+ color: #fff;
8575
+ text-decoration: none;
8576
+ transition: transform 120ms ease, background-color 120ms ease;
6692
8577
  }
6693
8578
 
6694
- .crg-copy-row .crg-codebox {
6695
- flex: 1;
6696
- min-width: 0;
6697
- margin: 0;
8579
+ /* Plain text "?" glyph — no container artifact (lucide's question-mark
8580
+ variants all wrap the ? in some outline shape). Sized + weighted to
8581
+ fill the 27px disc with a comfortable optical balance. */
8582
+ .help-badge__glyph {
8583
+ display: inline-flex;
8584
+ align-items: center;
8585
+ justify-content: center;
8586
+ font-family: var(--sl-font-sans, system-ui, sans-serif);
8587
+ font-size: 18px;
8588
+ font-weight: 700;
8589
+ line-height: 1;
8590
+ /* Most "?" glyphs sit slightly above the optical centre of their
8591
+ em-box because of the descender-free shape. Nudge down 1px so it
8592
+ reads centred in the disc. */
8593
+ margin-top: 1px;
6698
8594
  }
6699
8595
 
6700
- .crg-not-installed {
6701
- margin: 0 0 0.75rem;
8596
+ /* The sonar wave — a same-colour pseudo-element behind the badge that
8597
+ slowly grows outward and fades. Sits at z-index 0 (badge itself is
8598
+ at z-index 5) so it appears under the badge during expansion. */
8599
+ .help-badge::after {
8600
+ content: '';
8601
+ position: absolute;
8602
+ inset: 0;
8603
+ border-radius: 50%;
8604
+ background: #7c3aed;
8605
+ opacity: 0;
8606
+ z-index: -1;
8607
+ pointer-events: none;
6702
8608
  }
6703
8609
 
6704
- .crg-not-installed .settings-tab-description {
6705
- color: var(--status-paused);
8610
+ body.help-mode-active .help-badge {
8611
+ display: inline-flex;
6706
8612
  }
6707
8613
 
6708
- .crg-coming-soon {
6709
- color: var(--muted);
6710
- font-style: italic;
8614
+ body.help-mode-active .help-badge::after {
8615
+ animation: help-badge-sonar 2.4s ease-out infinite;
6711
8616
  }
6712
8617
 
6713
- .crg-stage-tools {
6714
- margin: 1rem 0;
8618
+ /* Auto-relative any direct parent of a badge so absolute positioning has
8619
+ a containing block. Modern browsers (Chrome 105+, Safari 15.4+,
8620
+ Firefox 121+) all support :has(). For sl-tab specifically, also force
8621
+ overflow: visible so the badge (and especially the sonar wave) isn't
8622
+ clipped against the tab strip's edge. */
8623
+ body.help-mode-active *:has(> .help-badge) {
8624
+ position: relative;
6715
8625
  }
6716
8626
 
6717
- .crg-stage-tools-grid {
6718
- display: grid;
6719
- gap: 0.4rem;
6720
- margin-top: 0.5rem;
8627
+ body.help-mode-active sl-tab {
8628
+ overflow: visible;
6721
8629
  }
6722
8630
 
6723
- .crg-stage-tools-entry {
6724
- display: flex;
6725
- gap: 0.75rem;
6726
- align-items: baseline;
6727
- font-size: 0.85rem;
8631
+ .help-badge:hover,
8632
+ .help-badge:focus-visible {
8633
+ /* Compose the hover lift with the vertical-centre translate so the
8634
+ badge doesn't jump when hovered. */
8635
+ transform: translateY(-50%) scale(1.1);
8636
+ /* Full opacity on hover so the affordance reads stronger. */
8637
+ background: #6d28d9; /* violet-700, opaque */
8638
+ outline: none;
6728
8639
  }
6729
8640
 
6730
- .crg-stage-role {
6731
- font-weight: 600;
6732
- min-width: 6rem;
6733
- color: var(--fg);
8641
+ /* Sonar wave: scale 1 → 1.5 from the 27px badge → max diameter ~40px,
8642
+ centred on a badge that's vertically centred on the host. Wave fits
8643
+ the host's bounding box on any host ≥ 40px tall (typical sl-tab
8644
+ ~40px, panel headers larger; thin inline hosts may graze the edge). */
8645
+ @keyframes help-badge-sonar {
8646
+ 0% {
8647
+ transform: scale(1);
8648
+ opacity: 0.55;
8649
+ }
8650
+ 100% {
8651
+ transform: scale(1.5);
8652
+ opacity: 0;
8653
+ }
6734
8654
  }
6735
8655
 
6736
- .crg-stage-tool-list {
6737
- color: var(--muted);
6738
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
6739
- font-size: 0.8rem;
6740
- word-break: break-all;
8656
+ @media (prefers-reduced-motion: reduce) {
8657
+ body.help-mode-active .help-badge::after {
8658
+ animation: none;
8659
+ opacity: 0.22;
8660
+ transform: scale(1.3);
8661
+ }
8662
+ .help-edge-tab {
8663
+ transition: none;
8664
+ }
8665
+ }
8666
+
8667
+ /* Dark-mode — violet stays violet, but we lift the idle background so it
8668
+ doesn't blend into dark panels. */
8669
+ :root[data-theme='dark'] .help-edge-tab,
8670
+ .sl-theme-dark .help-edge-tab {
8671
+ background: rgba(124, 58, 237, 0.22);
8672
+ color: #e9d5ff; /* violet-200 */
8673
+ border-color: #6d28d9;
8674
+ box-shadow: -2px 0 8px rgba(0, 0, 0, 0.4);
8675
+ }
8676
+
8677
+ :root[data-theme='dark'] .help-edge-tab:hover,
8678
+ :root[data-theme='dark'] .help-edge-tab:focus-visible,
8679
+ .sl-theme-dark .help-edge-tab:hover,
8680
+ .sl-theme-dark .help-edge-tab:focus-visible {
8681
+ background: rgba(124, 58, 237, 0.35);
8682
+ color: #f5f3ff;
6741
8683
  }