@worca/app 0.1.0 → 1.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,20 @@
25
25
  --amber-bg:#FCE8C8; --amber:#E6962A; --amber-ink:#A66510;
26
26
  --seq:#B7B7BC;
27
27
 
28
+ /* Question/ask amber wash (design §9, C3). --amber-bg is the SOLID amber; this
29
+ is the pale field it sits on. Task 11 adds --amber-wash-2/--amber-line/
30
+ --radio-ring beside it. */
31
+ --amber-wash:#FEF7EC;
32
+
33
+ /* Question panel (design §9): the remaining literals in the Running mockup that
34
+ no existing token already carries. The two hexes §9 also lists as "new" are
35
+ NOT added — they are already the values of --violet (:24) and --peach-ink
36
+ (:21); use those tokens.
37
+ Do NOT name those two hexes here, or anywhere else in this stylesheet: Task 12
38
+ asserts each appears EXACTLY ONCE, and its regex reads the raw file, so a
39
+ mention inside a comment counts as a second occurrence and reds the test. */
40
+ --amber-wash-2:#FEFAF3; --amber-line:#F5D9A8; --radio-ring:#D6D6D2;
41
+
28
42
  --r-card:24px;
29
43
  --r-ctrl:14px;
30
44
  --shadow:0 6px 28px rgba(25,25,27,.05), 0 1px 2px rgba(25,25,27,.04);
@@ -188,9 +202,6 @@ body{
188
202
  .child-q.ok { color: var(--green); font-size: 12px; animation: none; }
189
203
  .child-q.bad { color: var(--red); font-size: 12px; animation: none; }
190
204
 
191
- /* Overview cards are clickable to focus */
192
- #run-list .run-card .run-top { cursor: pointer; }
193
-
194
205
  .side-project{margin:0 4px 22px;padding-bottom:22px;border-bottom:1px solid var(--line);}
195
206
  .side-project .sp-label{display:block;font-size:11px;font-weight:600;letter-spacing:.08em;
196
207
  text-transform:uppercase;color:var(--ink-3);margin:0 4px 8px;}
@@ -209,12 +220,22 @@ body{
209
220
 
210
221
  /* ---------- Main ---------- */
211
222
  .main{flex:1;min-width:0;padding:26px 32px 40px;overflow-y:auto;}
212
- /* History view drops the scroll container's TOP padding so the sticky pills
213
- toolbar + per-project headers can pin flush to the very top of the scroll
214
- area. Without this, .main's 26px top padding leaves a band above the stuck
215
- header where scrolled cards peek through (the reported bug). The inset is
216
- re-applied inside the view (below) so the unscrolled layout is unchanged. */
217
- body.view-history .main{padding-top:0;}
223
+ /* History becomes a two-screen track: .main stops scrolling and becomes the
224
+ bounded column, the view takes the remainder, and each screen owns its own
225
+ scrollport. Dropping the container's TOP padding is what lets the sticky pills
226
+ toolbar + per-project headers pin flush to the very top of that scrollport —
227
+ without it, .main's 26px top padding leaves a band above the stuck header
228
+ where scrolled cards peek through (the reported bug). The inset is re-applied
229
+ on the topbar (below) so the unscrolled layout is unchanged.
230
+ The compact top-nav (<1080px) is a SIBLING above the views inside .main, so a
231
+ plain height:100% here would push the track past the viewport and
232
+ overflow:hidden would clip both screens' bottoms off-screen. */
233
+ body.view-history .main{display:flex;flex-direction:column;overflow:hidden;padding:0;}
234
+ /* .main's 32px gutter goes with padding:0, so the compact top-nav (<1080px, a
235
+ SIBLING of the views inside .main) must re-apply it or it lands 20px left of
236
+ the list content, which keeps its own 32px on .hist-screen. flex:0 0 auto
237
+ stops the wrapped 12-button nav from being squeezed once .main is a column. */
238
+ body.view-history .topnav{margin:12px 32px 0;flex:0 0 auto;}
218
239
  .topbar{display:flex;align-items:flex-start;justify-content:space-between;
219
240
  gap:24px;margin-bottom:22px;}
220
241
  .topbar h1{font-size:26px;font-weight:700;letter-spacing:-.025em;margin:0 0 4px;}
@@ -273,7 +294,7 @@ body.view-history .main{padding-top:0;}
273
294
  .hint{display:block;color:var(--ink-3);font-size:12px;margin-top:7px;line-height:1.45;}
274
295
  .hint.err{color:var(--red-ink);}
275
296
 
276
- .input,.select,.textarea,
297
+ .input,.select,.textarea,.ta-hl-back,
277
298
  input[type="text"],input[type="number"],textarea,select{
278
299
  width:100%;font-family:inherit;font-size:14px;color:var(--ink);
279
300
  background:var(--field);border:1.5px solid transparent;border-radius:var(--r-ctrl);
@@ -362,6 +383,78 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
362
383
  .file .state{color:var(--ink-3);font-size:12.5px;}
363
384
  .file-load{display:inline-block;margin-top:8px;}
364
385
 
386
+ /* extra-file pills: one removable pill per selected file, under the picker */
387
+ .extras-pills{display:flex;flex-wrap:wrap;gap:7px;margin-top:9px;}
388
+ .extra-pill{display:inline-flex;align-items:center;gap:5px;background:var(--field);border:1px solid var(--line-2);
389
+ color:var(--ink-2);font-weight:600;font-size:12px;padding:4px 6px 4px 12px;border-radius:999px;max-width:260px;}
390
+ .extra-pill-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
391
+ .extra-pill-x{border:0;background:transparent;color:var(--ink-3);cursor:pointer;font-family:inherit;
392
+ font-size:14px;line-height:1;padding:3px 6px;border-radius:50%;transition:.15s;}
393
+ .extra-pill-x:hover{color:var(--red-ink);background:var(--red-bg);}
394
+
395
+ /* @-mention popup: attached-file completions anchored under the prompt caret */
396
+ .mention-popup{position:fixed;z-index:70;min-width:180px;max-width:320px;max-height:210px;overflow-y:auto;
397
+ background:var(--panel);border:1px solid var(--line-2);border-radius:12px;box-shadow:var(--shadow);padding:5px;}
398
+ .mention-item{display:block;width:100%;text-align:left;border:0;background:transparent;color:var(--ink-2);
399
+ font-family:inherit;font-weight:500;font-size:12.5px;padding:7px 10px;border-radius:8px;cursor:pointer;
400
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
401
+ .mention-item:hover{background:var(--field);}
402
+ .mention-item.sel{background:var(--field);color:var(--ink);}
403
+
404
+ /* @-mention highlighting: a textarea cannot colour part of its own text, so a
405
+ backdrop mirrors the text underneath it and paints the valid mentions. The
406
+ textarea keeps its glyphs (and its caret, selection, spellcheck and undo
407
+ stack) but renders them transparent; the backdrop carries the field fill it
408
+ gave up. .mention-ok sets COLOUR ONLY — any metric-affecting property would
409
+ advance the backdrop's glyphs differently and drift the two layers apart.
410
+
411
+ Two box-model choices, both load-bearing, neither optional:
412
+
413
+ 1. The wrapper is inline-block, NOT block. A textarea is inline-block by UA
414
+ default, so the inline margin-top:11px on #prompt/#promptMarkdown does not
415
+ collapse today; a block wrapper would turn it into a collapsible block
416
+ margin that escapes through .source-pane and .field (neither has a border
417
+ or padding to stop it) and merges with the preceding margin-bottom:18px,
418
+ deleting the gap.
419
+ 2. It deliberately does NOT set vertical-align. An inline-block with no
420
+ in-flow line boxes takes its baseline from its bottom margin edge
421
+ (CSS 2.1 s10.8.1), and the only in-flow child here is a display:block
422
+ textarea — whose internal content is a separate rendering context and
423
+ contributes no line box to the wrapper. So the wrapper resolves exactly
424
+ where the bare textarea did (whose UA overflow:auto gave it the same
425
+ rule). vertical-align:top would instead align it to the line-box top,
426
+ deleting the strut descent below it and shrinking #prompt-pane and
427
+ #markdown-pane by ~6px. Making the textarea display:block removes the
428
+ line box INSIDE the wrapper, which is what keeps the backdrop's height
429
+ equal to the textarea's. */
430
+ .ta-hl{position:relative;display:inline-block;width:100%;}
431
+ .ta-hl > textarea.textarea,
432
+ .ta-hl > textarea.textarea:focus{display:block;position:relative;z-index:1;
433
+ background:transparent;color:transparent;caret-color:var(--ink);}
434
+ .ta-hl > textarea.textarea::selection{background:rgba(25,25,27,.16);}
435
+ /* font-weight/style/variant/stretch are the ONLY text-layout properties the two
436
+ layers do not already share: Chrome's UA `font: -webkit-small-control`
437
+ shorthand on <textarea> resets them, while this div would inherit them from
438
+ body (Poppins ships 400/500/600/700, so this is not hypothetical). Pin them to
439
+ the textarea's reset values. Do NOT pin letter-spacing/word-spacing/
440
+ text-indent/text-align/text-transform/tab-size — those are outside the font
441
+ shorthand, so both layers inherit them, and pinning would CREATE the
442
+ divergence it means to prevent. */
443
+ .ta-hl-back{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;
444
+ line-height:1.5;white-space:pre-wrap;overflow-wrap:break-word;border-color:transparent;
445
+ font-weight:400;font-style:normal;font-variant:normal;font-stretch:normal;}
446
+ .ta-hl:focus-within .ta-hl-back{background:#fff;}
447
+ .mention-ok{color:var(--blue-ink);}
448
+
449
+ /* High Contrast forces the textarea's transparent text back to CanvasText while
450
+ its background stays transparent, so both layers' glyphs would paint at once,
451
+ and it flattens --blue-ink to black anyway. Opt the whole trick out. */
452
+ @media (forced-colors: active){
453
+ .ta-hl-back{display:none;}
454
+ .ta-hl > textarea.textarea,
455
+ .ta-hl > textarea.textarea:focus{color:CanvasText;background:Canvas;}
456
+ }
457
+
365
458
  /* switch */
366
459
  .switch-row{display:flex;align-items:center;gap:12px;}
367
460
  .switch{width:44px;height:26px;border-radius:999px;background:var(--line-2);position:relative;
@@ -546,12 +639,22 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
546
639
 
547
640
  /* ---------- Running ---------- */
548
641
  .run-list{display:flex;flex-direction:column;gap:18px;}
642
+
643
+ /* "N pipelines are waiting on your answers" — inert status line above the list
644
+ (design D14). Amber family; the circle inverts to --panel so it still reads
645
+ against the pale wash. */
646
+ .run-ask-banner{display:flex;align-items:center;gap:12px;margin:0 0 18px;padding:13px 18px;
647
+ background:var(--amber-wash);border:1px solid var(--amber);border-radius:16px;}
648
+ .run-ask-banner[hidden]{display:none;} /* author display:flex beats the UA [hidden] rule */
649
+ .run-ask-banner .rab-mark{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
650
+ width:26px;height:26px;border-radius:50%;background:var(--panel);
651
+ color:var(--amber-ink);font-weight:700;font-size:14px;}
652
+ .run-ask-banner .rab-text{flex:1;font-weight:500;font-size:13px;color:var(--amber-ink);}
653
+
549
654
  .run-card{padding:22px 24px;}
550
- .run-top{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:18px;}
551
655
  .run-title{font-weight:700;font-size:16px;letter-spacing:-.01em;display:flex;align-items:center;gap:10px;}
552
656
  .run-title .hash{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);font-weight:500;}
553
657
  .run-title.title-provisional{opacity:.65;font-style:italic;}
554
- .run-meta{display:flex;align-items:center;gap:10px;color:var(--ink-3);font-size:12.5px;margin-top:4px;}
555
658
  .pill-run{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:999px;
556
659
  font-weight:600;font-size:12.5px;white-space:nowrap;}
557
660
  .pill-run .pdot{width:7px;height:7px;border-radius:50%;animation:pulse 1.3s ease-in-out infinite;}
@@ -574,20 +677,15 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
574
677
  /* empty state for the running list */
575
678
  .run-empty{color:var(--ink-3);padding:24px;text-align:center;}
576
679
 
577
- .run-foot{display:flex;align-items:center;gap:10px;}
578
680
  .chip{background:var(--field);color:var(--ink-2);font-weight:600;font-size:12px;padding:7px 13px;border-radius:999px;}
579
- .chip.qcount{background:var(--amber-bg);color:var(--amber-ink);}
580
- .btn-stop.sm{margin-left:auto;padding:8px 15px;font-size:12px;}
581
- .btn-pause.sm{margin-left:auto;padding:8px 15px;font-size:12px;}
582
- .btn-resume.sm{margin-left:auto;padding:8px 15px;font-size:12px;}
583
- .btn-pause.sm + .btn-stop.sm{margin-left:0;}
584
681
 
585
682
  /* expand to live log */
586
683
  .btn-expand{margin-left:auto;display:inline-flex;align-items:center;gap:7px;background:var(--field);
587
684
  border:none;border-radius:999px;padding:8px 15px;font-family:inherit;font-weight:600;font-size:12px;
588
685
  color:var(--ink-2);cursor:pointer;transition:background .15s;}
589
686
  .btn-expand:hover{background:var(--line-2);}
590
- .btn-expand + .btn-stop.sm{margin-left:0;}
687
+ /* The `.btn-expand + .btn-stop.sm` reset that sat here keyed off a `.btn-stop.sm`
688
+ rule the card redesign removed; nothing emits that pair any more. */
591
689
  .btn-expand .chev{transition:transform .2s;}
592
690
  .btn-expand[aria-expanded="true"] .chev{transform:rotate(180deg);}
593
691
  .run-log{margin-top:16px;}
@@ -611,7 +709,6 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
611
709
  /* run card: pills drop to a full-width second row under "Live log" (order puts
612
710
  the bar after the autoscroll switch so row 1 stays label ⟷ switch) */
613
711
  .run-log-head .log-filters{order:1;flex-basis:100%;}
614
- .logs-panel .log-filters{margin-top:8px;}
615
712
 
616
713
  /* needs-attention card + paused stage */
617
714
  .run-card.attention{border:1.5px solid var(--amber);box-shadow:0 0 0 4px var(--amber-bg),var(--shadow);}
@@ -619,32 +716,87 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
619
716
  color:var(--amber-ink);font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px;vertical-align:middle;}
620
717
  .attn-flag svg{stroke:var(--amber-ink);}
621
718
 
622
- /* ---------- Questions panel ---------- */
623
- .qpanel,.question-card{margin-top:18px;border:1.5px solid var(--amber-bg);background:#FFFDF8;border-radius:18px;padding:20px 22px;}
624
- .qpanel-head{display:flex;align-items:center;gap:10px;margin-bottom:6px;}
719
+ /* ---------- Questions panel (run card + run detail) ---------- */
720
+ /* The CARD is the base (design §4.3: 19px number circles, 12.5px options); the
721
+ detail screen scales up through `.rd-questions .qpanel …` (§5.4), which wins on
722
+ SPECIFICITY, so this block's position in the file does not matter.
723
+ The legacy `q-`-prefixed twin selectors that used to share every rule here had
724
+ ZERO emitters left in ui/ and test/ and are dropped with this rewrite. They are
725
+ deliberately NOT spelled out below, even though the suite's sweep strips comments
726
+ first — keeping the prose free of them means a future sweep that forgets to
727
+ strip still passes. */
728
+ .qpanel{margin-top:18px;padding:14px 16px 13px;background:var(--amber-wash);
729
+ border:1px solid var(--amber-bg);border-radius:14px;}
730
+ .qpanel-head{display:flex;align-items:center;gap:11px;}
625
731
  .qpanel-head svg{stroke:var(--amber-ink);flex:0 0 auto;}
626
- .qpanel-head b{font-size:15px;font-weight:700;}
627
- .qpanel-head .qcount{margin-left:auto;background:var(--amber-bg);color:var(--amber-ink);
628
- font-weight:700;font-size:11.5px;padding:5px 11px;border-radius:999px;}
629
- .qblock,.q-block{padding:18px 0;border-top:1px solid var(--line);}
630
- .qblock:first-of-type,.q-block:first-of-type{border-top:none;}
631
- .qtext,.q-question{font-weight:600;font-size:14px;margin:0 0 12px;display:flex;align-items:flex-start;gap:10px;line-height:1.45;}
632
- .qtext .qn{flex:0 0 auto;width:22px;height:22px;border-radius:50%;background:var(--ink);color:#fff;
633
- font-size:11.5px;font-weight:700;display:grid;place-items:center;margin-top:1px;}
634
- .qopts,.q-options{display:flex;flex-direction:column;align-items:stretch;gap:9px;margin-bottom:11px;}
635
- .qopt,.q-option{font-family:inherit;font-weight:600;font-size:13px;color:var(--ink);background:#fff;
636
- border:1.5px solid var(--line-2);border-radius:11px;padding:12px 16px;cursor:pointer;transition:.14s;text-align:left;width:100%;}
637
- .qopt:hover,.q-option:hover{border-color:var(--ink-3);}
638
- .qopt.sel,.q-option.selected{background:var(--ink);color:#fff;border-color:var(--ink);}
639
- .qopt:focus-visible,.q-option:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
640
- .qfree,.q-free input{width:100%;font-family:inherit;font-size:13.5px;color:var(--ink);background:var(--field);
641
- border:1.5px solid transparent;border-radius:11px;padding:11px 14px;transition:.14s;}
642
- .qfree::placeholder,.q-free input::placeholder{color:var(--ink-3);}
643
- .qfree:focus,.q-free input:focus{outline:none;background:#fff;border-color:var(--ink);}
644
- .qfree.has{background:#fff;border-color:var(--ink);}
645
- .q-free{display:flex;gap:8px;align-items:stretch;}
646
- .q-free-label{display:block;font-size:12px;color:var(--ink-3);margin:4px 0;line-height:1.45;}
647
- .qpanel-foot,.q-submit-row{margin-top:18px;padding-top:18px;border-top:1px solid var(--line);display:flex;justify-content:flex-end;}
732
+ .qpanel-head b{flex:1;min-width:0;font-weight:600;font-size:12.5px;color:var(--amber-ink);}
733
+ .qpanel-head .qcount{margin-left:auto;flex:0 0 auto;background:var(--amber-bg);color:var(--amber-ink);
734
+ font-weight:700;font-size:11.5px;padding:4px 10px;border-radius:999px;}
735
+ .qblock{padding:13px 0 0;}
736
+ .qtext{font-weight:500;font-size:13px;margin:0 0 9px;display:flex;align-items:flex-start;
737
+ gap:9px;line-height:1.45;}
738
+ .qtext .qn{flex:0 0 auto;width:19px;height:19px;border-radius:50%;background:var(--ink);color:#fff;
739
+ font-family:var(--mono);font-size:10.5px;font-weight:600;display:grid;place-items:center;margin-top:1px;}
740
+ /* the option column and the free-text field line up under the number circle */
741
+ .qopts{display:flex;flex-direction:column;align-items:stretch;gap:7px;margin:0 0 7px;padding-left:28px;}
742
+ .qopt{display:flex;align-items:center;gap:8px;font-family:inherit;font-weight:500;font-size:12.5px;
743
+ color:var(--ink);background:var(--panel);border:1.5px solid var(--line);border-radius:11px;
744
+ padding:10px 14px;cursor:pointer;transition:.14s;text-align:left;width:100%;}
745
+ /* Radio + white check drawn entirely in CSS: renderClarifyBody keeps emitting a
746
+ bare <button> with one text node (§4.3 — styling only, no markup change), and
747
+ an inline data-URI background needs no extra element and no positioning context. */
748
+ .qopt::before{content:'';flex:0 0 auto;width:15px;height:15px;border-radius:50%;
749
+ border:1.5px solid var(--radio-ring);background:var(--panel);}
750
+ .qopt.sel::before{border-color:var(--green);
751
+ background:var(--green) center/9px 9px no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.6' stroke-linecap='round' stroke-linejoin='round'><path d='M5 13l4 4L19 7'/></svg>");}
752
+ .qopt:hover{border-color:var(--ink-3);}
753
+ .qopt.sel{background:var(--green-bg);color:var(--ink);border-color:var(--green);}
754
+ .qopt:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
755
+ .qfree{width:100%;font-family:inherit;font-size:12.5px;color:var(--ink);background:var(--field);
756
+ border:1.5px solid var(--line);border-radius:11px;padding:10px 14px;transition:.14s;}
757
+ .qfree::placeholder{color:var(--ink-3);}
758
+ /* `.has` is toggled by renderClarifyBody's own input handler the moment the field
759
+ holds a non-empty, non-option value — the green border IS that state. */
760
+ .qfree:focus{outline:none;background:var(--panel);border-color:var(--green);}
761
+ .qfree.has{background:var(--panel);border-color:var(--green);}
762
+ .qblock > .qfree{margin-left:28px;width:calc(100% - 28px);}
763
+ .qpanel-foot{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:14px;}
764
+ .qpanel-foot .btn-go{padding:9px 18px;font-size:12px;gap:8px;}
765
+ /* secondary "Open run" — card only (§4.3) */
766
+ .qopen{padding:9px 16px;border:1.5px solid var(--line-2);border-radius:999px;background:var(--panel);
767
+ font-family:inherit;font-weight:600;font-size:12px;color:var(--ink);cursor:pointer;transition:.14s;}
768
+ .qopen:hover{background:var(--field);}
769
+ .qopen:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
770
+
771
+ /* ---- run-detail variant: the mockup's larger metrics (design §5.4) ---- */
772
+ /* NO `animation` here: Task 6 already put `animation:wr-rise …` on the
773
+ `.rd-questions` WRAPPER (and neutralizes it under reduced motion). Animating
774
+ the child too nests the two transforms — 20px of travel and opacity squared.
775
+ `margin-top:0` also stays where Task 6 put it (its EOF rule comes LATER in the
776
+ file, so it still wins); this rule must not restate it. */
777
+ .rd-questions .qpanel{padding:22px 24px 20px;background:var(--amber-wash-2);
778
+ border:1.5px solid var(--amber-line);border-radius:var(--r-card);}
779
+ .rd-questions .qpanel-head{gap:12px;padding-bottom:16px;border-bottom:1px solid var(--amber-line);}
780
+ .rd-questions .qpanel-head b{font-size:15px;color:var(--ink);}
781
+ .rd-questions .qpanel-head .qcount{font-weight:600;font-size:11.5px;padding:5px 12px;}
782
+ .rd-questions .qblock{padding-top:18px;}
783
+ .rd-questions .qtext{font-weight:600;font-size:14px;line-height:1.5;gap:11px;margin-bottom:12px;}
784
+ .rd-questions .qtext .qn{width:22px;height:22px;font-size:11.5px;}
785
+ /* the detail panel is wide enough to drop the number-circle indent */
786
+ .rd-questions .qopts{gap:9px;margin:12px 0 0;padding-left:0;}
787
+ .rd-questions .qblock > .qfree{margin-left:0;width:100%;padding:13px 16px;border-radius:13px;font-size:13.5px;}
788
+ .rd-questions .qopt{gap:11px;padding:13px 16px;border-radius:13px;font-size:13.5px;}
789
+ .rd-questions .qopt::before{width:17px;height:17px;}
790
+ .rd-questions .qopt.sel::before{background-size:10px 10px;}
791
+ .rd-questions .qpanel-foot{margin-top:20px;padding-top:16px;border-top:1px solid var(--amber-line);}
792
+ .rd-questions .qpanel-foot .btn-go{padding:13px 22px;font-size:13.5px;gap:9px;}
793
+
794
+ /* "N of M answered" (§5.4): left slot of the footer, submit on the right. The
795
+ base .qpanel-foot is justify-content:flex-end — with a counter present the row
796
+ becomes space-between, and `margin-right:auto` on the counter achieves that
797
+ WITHOUT a second .qpanel-foot rule that the footer test would then contradict. */
798
+ .qanswered{margin-right:auto;font:500 11.5px var(--mono);color:var(--ink-3);}
799
+ .rd-questions .qanswered{font-size:12.5px;}
648
800
 
649
801
  /* ---------- Gate (cycle gate) ---------- */
650
802
  .gate-intro{font-size:13px;color:var(--ink-2);margin:0 0 14px;line-height:1.5;}
@@ -666,15 +818,8 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
666
818
  .gate-actions{display:flex;gap:10px;flex-wrap:wrap;}
667
819
  .gate-actions .btn{flex:1 1 auto;}
668
820
 
669
- /* ---------- History rows ---------- */
670
- .hist-row{display:flex;align-items:center;gap:14px;padding:15px 4px;border-top:1px solid var(--line);}
671
- .hist-row:first-child{border-top:none;}
672
- .hist-row .h-meta{flex:1;min-width:0;}
673
- .hist-row .h-meta b{display:block;font-weight:600;font-size:14.5px;}
674
- .hist-row .h-meta small{color:var(--ink-3);font-size:12px;}
675
- .hist-row .hash{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);}
676
-
677
- /* status badge — shared family colors (app.js historyBadge: green/red/running) */
821
+ /* status badge shared family colors (green/red/running/waiting/violet), used by
822
+ guardrails-view.mjs, models-view.mjs and the chat-connection state pill */
678
823
  .badge{display:inline-flex;align-items:center;font-size:10.5px;font-weight:700;letter-spacing:.06em;
679
824
  text-transform:uppercase;padding:5px 10px;border-radius:8px;flex:0 0 auto;white-space:nowrap;
680
825
  background:var(--field);color:var(--ink-3);}
@@ -686,21 +831,19 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
686
831
  .badge.hist-retained-badge{background:var(--amber-bg);color:var(--amber-ink);}
687
832
  .badge.hist-retained-badge[hidden]{display:none;}
688
833
 
689
- /* ---------- History cards (expandable) ---------- */
834
+ /* ---------- History cards (navigate to the detail screen) ---------- */
690
835
  .hist-card{padding:18px 22px;}
691
- .hist-head{display:flex;align-items:center;gap:13px;cursor:pointer;}
836
+ /* flex-start, not center: the card is now three stacked lines (title, meta,
837
+ branch) and the icon/aside must pin to the top of that block. */
838
+ .hist-head{display:flex;align-items:flex-start;gap:13px;cursor:pointer;}
692
839
  .hist-head:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
693
840
  .hist-head .h-meta{flex:1;min-width:0;}
694
- .hist-head .h-meta b{display:block;font-weight:600;font-size:14.5px;}
695
- .hist-head .h-meta small{color:var(--ink-3);font-size:12px;}
841
+ /* one line, ellipsized (the `flex:1;min-width:0` above is what makes it work). */
842
+ .hist-head .h-meta b{display:block;font-weight:600;font-size:14.5px;
843
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
696
844
  .hist-head .hash{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);}
697
- .hist-head .chev{color:var(--ink-3);transition:transform .2s;flex:0 0 auto;}
698
- .hist-head[aria-expanded="true"] .chev{transform:rotate(180deg);}
699
845
  .hist-head .h-meta b{cursor:pointer;}
700
846
  .hist-head .h-meta b:hover{text-decoration:underline;}
701
- .hist-detail{margin-top:16px;padding-top:16px;border-top:1px solid var(--line);}
702
- .hist-detail[hidden]{display:none;}
703
- .hist-detail .detail-error{color:var(--red-ink);font-size:12.5px;}
704
847
  .retained-banner{margin:0 0 18px;padding:16px 18px;border:1.5px solid var(--amber);
705
848
  border-radius:14px;background:var(--amber-bg);color:var(--amber-ink);font-size:12.5px;line-height:1.55;}
706
849
  .retained-banner[hidden]{display:none;}
@@ -713,15 +856,8 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
713
856
  white-space:pre-wrap;word-break:break-all;}
714
857
  .retained-banner a{color:var(--amber-ink);font-weight:700;}
715
858
  .hist-empty{color:var(--ink-3);font-size:13px;padding:22px 4px;text-align:center;}
716
- .hist-section{margin-top:16px;padding-top:16px;border-top:1px solid var(--line);}
717
- .hist-section-title{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-3);font-weight:700;margin-bottom:10px;}
718
- .hist-answer{font-size:12.5px;color:var(--ink-2);margin-top:6px;}
719
859
 
720
860
  /* ---------- History project-filter pills ---------- */
721
- /* Re-apply (inside the scrolling view) the top inset that body.view-history
722
- removed from .main, so the unscrolled layout is unchanged while the scroll
723
- container itself has no top padding for position:sticky to fight. */
724
- .view[data-view="history"]{padding-top:26px;}
725
861
  /* The project-filter pills become a persistent sticky toolbar pinned to the top
726
862
  of the scroll area while the list scrolls underneath. Opaque background +
727
863
  z-index above the per-project header (z-index:3) so scrolled cards never
@@ -753,6 +889,17 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
753
889
  ::-webkit-scrollbar-track{background:transparent;}
754
890
 
755
891
  /* ---------- reduced motion ---------- */
892
+ /* DECISION (D7). Spec §8 proposes extending this block to a blanket
893
+ `animation:none`. We do NOT: D7 keeps the Running view behaviorally untouched,
894
+ and the run-graph's own reduced-motion block (1240-1245) already neutralizes
895
+ its pulses with deliberate box-shadow substitutes that a blanket rule would
896
+ leave orphaned. Do not add the History-redesign animations to the list below,
897
+ either — `@media` contributes no specificity, so a (0,1,0) `animation:none`
898
+ here loses on source order to the (0,1,0) `animation:shipit-…` rules appended
899
+ at EOF. The four names below work only because each is declared *before* this
900
+ block. The ship-it animations are neutralized by a second
901
+ `@media (prefers-reduced-motion: reduce)` block placed AFTER them at the end
902
+ of the file. */
756
903
  @media (prefers-reduced-motion: reduce){
757
904
  .pdot,.cur,.child-dot,.child-q{animation:none;}
758
905
  *{transition:none !important;}
@@ -801,27 +948,42 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
801
948
  }
802
949
 
803
950
  /* ---------- per-pipeline cost (per-node cost is the graph's .nrun .cost) ---------- */
804
- .run-meta .run-cost{font-family:var(--mono);font-weight:600;color:var(--ink-2);}
805
- .run-meta .run-cost:not(:empty)::before{content:'·';margin:0 8px;color:var(--ink-3);}
806
- .h-meta .hist-total{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-left:10px;}
951
+ /* The `.run-meta .run-cost` pair that lived here went with `.run-meta` itself:
952
+ the redesigned card emits `.run-cost` inside `.rc-seg`, which owns its own
953
+ type scale and prints its separator as a real `.rc-dot` node. */
954
+ /* Edited IN PLACE, not appended: this selector is (0,2,0) and an appended bare
955
+ `.hist-total{…}` (0,1,0) would never win. The `margin-left:10px` is gone — the
956
+ v2 meta line is a flex row with its own gap. */
957
+ .h-meta .hist-total{font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--ink);}
807
958
  .h-meta .hist-total:empty{display:none;}
808
959
 
809
960
  /* ---------- per-pipeline duration (twin of cost) ---------- */
810
- .run-meta .run-time{font-family:var(--mono);font-weight:600;color:var(--ink-2);}
811
- .run-meta .run-time:not(:empty)::before{content:'·';margin:0 8px;color:var(--ink-3);}
812
- .h-meta .hist-time{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-left:10px;}
961
+ /* `.run-meta .run-time` removed with its cost twin above, for the same reason. */
962
+ /* Same in-place treatment as `.h-meta .hist-total` above. */
963
+ .h-meta .hist-time{font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--ink);}
813
964
  .h-meta .hist-time:empty{display:none;}
814
965
 
815
966
  /* Branch name under the date/cost (left column). */
816
- .h-meta .hist-branch{display:block;font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-top:4px;}
817
- .h-meta .hist-branch:empty{display:none;}
818
-
819
- /* Right-side cluster, before the chevron: lines changed, merge pill, Create PR. */
820
- .hist-aside{display:flex;align-items:center;gap:10px;flex:0 0 auto;}
967
+ .h-meta .hist-branch{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);margin-top:4px;}
968
+ .h-meta .hist-branch[hidden]{display:none;} /* author display:flex beats the UA [hidden] rule */
969
+ .hist-branch .hist-branch-src{color:var(--ink-3);font-weight:500;}
970
+ .hist-branch .hist-branch-arrow{flex:0 0 auto;color:var(--ink-3);}
971
+ .hist-branch .hist-branch-arrow[hidden]{display:none;}
972
+ .hist-branch-copy{display:inline-flex;align-items:center;justify-content:center;padding:3px;background:none;border:0;border-radius:6px;color:var(--ink-3);cursor:pointer;}
973
+ .hist-branch-copy:hover{background:var(--line);color:var(--ink);}
974
+ .hist-branch-copy .ico-check{display:none;}
975
+ .hist-branch-copy.copied .ico-copy{display:none;}
976
+ .hist-branch-copy.copied .ico-check{display:block;color:var(--green-ink);}
977
+
978
+ /* Right-side cluster on the card: Create PR + the open-detail chevron button.
979
+ `align-self:center` (not the parent's `align-items:flex-start`) pins the cluster
980
+ to the card's vertical middle, the same escape hatch `.hist-card .hist-sic` uses
981
+ on the other side of the row. */
982
+ .hist-aside{display:flex;align-items:center;align-self:center;gap:10px;flex:0 0 auto;}
983
+ /* Base rule only. The v2 card hosts `.hist-diff` INSIDE `.hist-diff-pill`, whose
984
+ appended `.hist-diff-pill .hist-diff` (0,2,0) outranks this; the tints come from
985
+ the bare `.diff-add`/`.diff-del` rules further down. */
821
986
  .hist-diff{display:inline-flex;gap:6px;font-family:var(--mono);font-size:12px;font-weight:700;}
822
- .hist-diff:empty{display:none;}
823
- .hist-diff .diff-add{color:var(--green-ink);}
824
- .hist-diff .diff-del{color:var(--red-ink);}
825
987
 
826
988
  .hist-merge{font-size:10.5px;font-weight:700;letter-spacing:.04em;padding:3px 8px;border-radius:999px;white-space:nowrap;}
827
989
  .hist-merge[hidden]{display:none;}
@@ -831,26 +993,29 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
831
993
 
832
994
  .hist-pr{padding:6px 12px;font-size:12px;flex:0 0 auto;}
833
995
  .hist-pr[hidden]{display:none;}
834
- .hist-pr-link{font-size:12px;font-weight:600;color:var(--green-ink);text-decoration:none;white-space:nowrap;}
835
- .hist-pr-link:hover{text-decoration:underline;}
836
- .hist-pr-link.merged{color:var(--muted, #888);}
837
-
838
- /* Delete action under the expanded card's stepper. Filled red to read as the
839
- single destructive action (scoped to .hist-delete so the existing soft
840
- .btn-danger rule is left untouched). */
841
- .hist-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:14px;}
996
+ /* These three rules are the ONLY thing that styles a PR link, so the History
997
+ DETAIL header's `.hd-pr-link` joins the selector lists IN PLACE. Appending a
998
+ separate `.hd-pr-link{…}` at EOF instead would ship the detail link as a default
999
+ UA anchor — browser blue, underlined — and MERGED would lose its grey. */
1000
+ .hist-pr-link,.hd-pr-link{font-size:12px;font-weight:600;color:var(--green-ink);text-decoration:none;white-space:nowrap;}
1001
+ .hist-pr-link:hover,.hd-pr-link:hover{text-decoration:underline;}
1002
+ .hist-pr-link.merged,.hd-pr-link.merged{color:var(--muted, #888);}
1003
+
1004
+ /* Discard-worktree button. The class moved from the retired card accordion to the
1005
+ detail screen's banner block; nothing about it was card-position-dependent. */
842
1006
  .hist-discard{display:inline-flex;align-items:center;padding:6px 12px;font-size:12px;
843
1007
  color:var(--amber-ink);border-color:var(--amber);background:var(--amber-bg);}
844
1008
  .hist-discard:hover:not(:disabled){background:var(--amber-bg);filter:brightness(.97);}
845
1009
  .hist-discard:disabled{opacity:.6;cursor:default;}
846
1010
  .hist-discard[hidden]{display:none;}
847
- .hist-delete,.pl-remove{display:inline-flex;align-items:center;gap:6px;background:var(--red-ink,#d9534f);
1011
+ /* This block is SHARED with the Plugins view's `.pl-remove`; the retired
1012
+ `.hist-delete` arms were removed from the selector lists, the block stays. */
1013
+ .pl-remove{display:inline-flex;align-items:center;gap:6px;background:var(--red-ink,#d9534f);
848
1014
  border:1.5px solid var(--red-ink,#d9534f);color:#fff;font-family:inherit;font-weight:600;
849
1015
  font-size:12px;padding:6px 12px;border-radius:8px;cursor:pointer;}
850
- .hist-delete:hover:not(:disabled),.pl-remove:hover:not(:disabled){filter:brightness(0.95);}
851
- .hist-delete:disabled,.pl-remove:disabled{opacity:.6;cursor:default;}
852
- .hist-delete[hidden]{display:none;}
853
- .hist-delete svg,.pl-remove svg{display:block;}
1016
+ .pl-remove:hover:not(:disabled){filter:brightness(0.95);}
1017
+ .pl-remove:disabled{opacity:.6;cursor:default;}
1018
+ .pl-remove svg{display:block;}
854
1019
 
855
1020
  /* ========================================================================== */
856
1021
  /* Pipeline Composer — drag/drop canvas, wires, palette, saved list */
@@ -1142,53 +1307,29 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
1142
1307
  .run-flow .node.is-active .fan .fl{color:var(--blue-ink);}
1143
1308
  @keyframes sqPulse{0%,100%{opacity:1;}50%{opacity:.38;}}
1144
1309
 
1145
- /* "Sub-agents" disclosure pill + its tree panel (shared by Run + History). */
1146
- .subs-bar,.clarify-bar,.logs-bar,.diff-bar,.overview-bar{margin-top:14px;}
1147
- .subs-bar[hidden],.clarify-bar[hidden],.logs-bar[hidden],.diff-bar[hidden],.overview-bar[hidden]{display:none;}
1148
- /* (.subs-panel rule already covers .clarify-panel/.logs-panel via the shared class) */
1149
- .logs-panel .log{min-height:0;max-height:340px;margin-top:8px;}
1150
- .btn-subs{display:inline-flex;align-items:center;gap:9px;background:var(--field);border:none;border-radius:999px;padding:9px 15px 9px 13px;font-family:inherit;font-weight:600;font-size:12.5px;color:var(--ink-2);cursor:pointer;transition:background .15s;}
1151
- .btn-subs:hover{background:var(--line-2);}
1152
- .btn-subs .ico{width:15px;height:15px;stroke:var(--ink-2);stroke-width:1.9;}
1153
- .btn-subs .sb-count{display:inline-flex;align-items:center;gap:6px;background:var(--blue-bg);color:var(--blue-ink);font-weight:700;font-size:11px;padding:3px 9px;border-radius:999px;}
1154
- .btn-subs .sb-count.grey{background:#fff;color:var(--ink-3);box-shadow:inset 0 0 0 1px var(--line-2);}
1155
- .btn-subs .chev{transition:transform .2s;stroke:var(--ink-3);}
1156
- .btn-subs[aria-expanded="true"] .chev{transform:rotate(180deg);}
1157
- .subs-panel{margin-top:14px;border:1px solid var(--line);border-radius:18px;background:#FBFBF9;padding:8px 20px 16px;}
1158
- .subs-panel[hidden]{display:none;}
1159
- .subs-legend{display:flex;align-items:center;gap:18px;padding:12px 0 4px;font-size:11.5px;font-weight:600;color:var(--ink-3);}
1160
- .subs-legend .lk{display:flex;align-items:center;gap:7px;}
1161
- .subs-legend .sq{width:9px;height:9px;border-radius:2px;}
1162
- .subs-legend .sq.on{background:var(--blue);}
1163
- .subs-legend .sq.off{background:var(--ink-3);opacity:.5;}
1164
- .subs-step{padding:13px 0;border-top:1px solid var(--line);}
1165
- .subs-step:first-of-type{border-top:none;}
1166
- .subs-step-head{display:flex;align-items:center;gap:10px;}
1167
- .subs-step-head .dot{width:10px;height:10px;border-radius:50%;flex:0 0 auto;}
1168
- .subs-step-head b{font-size:13.5px;font-weight:600;letter-spacing:-.01em;}
1169
- .subs-step-head .subs-stat{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:999px;letter-spacing:.02em;text-transform:uppercase;}
1170
- .subs-step-head .subs-stat.run{background:var(--blue-bg);color:var(--blue-ink);}
1171
- .subs-step-head .subs-stat.done{background:var(--green-bg);color:var(--green-ink);}
1172
- .subs-step-head .subs-stat.stop{background:var(--red-bg);color:var(--red-ink);}
1173
- .subs-step-head .subs-n{margin-left:auto;font-size:11.5px;font-weight:600;color:var(--ink-3);}
1174
- .subs-step .subs-empty{margin-top:8px;padding-left:5px;font-size:12px;font-weight:500;color:var(--ink-3);font-style:italic;}
1175
- .subs-tree{list-style:none;margin:8px 0 0;padding:0 0 0 5px;}
1176
- .subs-tree li{position:relative;padding:6px 0 6px 28px;font-size:12.5px;font-weight:500;color:var(--ink-2);display:flex;align-items:center;gap:9px;}
1177
- .subs-tree li::before{content:"";position:absolute;left:5px;top:-3px;height:calc(50% + 3px);width:1.5px;background:var(--line-2);}
1178
- .subs-tree li::after{content:"";position:absolute;left:5px;top:50%;width:15px;height:1.5px;background:var(--line-2);}
1179
- .subs-tree li .led{width:7px;height:7px;border-radius:2px;flex:0 0 auto;background:var(--ink-3);opacity:.55;}
1180
- .subs-tree li .led.on{background:var(--blue);opacity:1;}
1181
- .subs-tree li .ag-name{min-width:0;}
1182
- .subs-tree li .st{margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:500;padding:2px 8px;border-radius:6px;white-space:nowrap;}
1183
- .subs-tree li .st.done{background:var(--green-bg);color:var(--green-ink);}
1184
- .subs-tree li .st.run{background:var(--blue-bg);color:var(--blue-ink);}
1185
- .subs-tree li .st.stop{background:var(--red-bg);color:var(--red-ink);}
1310
+ /* Selector lists that used to pair the retired run-card tree with the History
1311
+ detail's Agents tab. `.subs-stat` is only ever styled here, so a bare appended
1312
+ `.subs-stat.stop{}` would tie on specificity and still lose to this rule's
1313
+ ancestor scope extend in place, never duplicate. Same for `.st`,
1314
+ `.agent-type-pill` and the full-row `.subs-skills` rule below. */
1315
+ .rd-ag-head .subs-stat,.hd-ag-head .subs-stat{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:999px;letter-spacing:.02em;text-transform:uppercase;}
1316
+ .rd-ag-head .subs-stat.run,.hd-ag-head .subs-stat.run{background:var(--blue-bg);color:var(--blue-ink);}
1317
+ .rd-ag-head .subs-stat.done,.hd-ag-head .subs-stat.done{background:var(--green-bg);color:var(--green-ink);}
1318
+ .rd-ag-head .subs-stat.stop,.hd-ag-head .subs-stat.stop{background:var(--red-bg);color:var(--red-ink);}
1319
+ .hd-ag-row .st{margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:500;padding:2px 8px;border-radius:6px;white-space:nowrap;}
1320
+ .hd-ag-row .st.done{background:var(--green-bg);color:var(--green-ink);}
1321
+ .hd-ag-row .st.run{background:var(--blue-bg);color:var(--blue-ink);}
1322
+ .hd-ag-row .st.stop{background:var(--red-bg);color:var(--red-ink);}
1186
1323
 
1187
1324
  /* Skill / MCP pills — main-agent group header + per sub-agent row. Flex-wrap so
1188
1325
  pills reflow onto multiple lines as the window shrinks (cf. .agent-chips, .fan). */
1189
1326
  .subs-skills{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;}
1190
- .subs-tree li{flex-wrap:wrap;} /* let the pill row drop below name/status */
1191
- .subs-tree li .subs-skills{flex:0 0 100%;margin-top:6px;} /* own full row, aligned under .ag-name */
1327
+ /* The BASE .subs-skills rule above is unscoped and reaches the Agents tab on its
1328
+ own; this FULL-ROW rule is not, and buildHdAgents emits skillPillsHtml into
1329
+ BOTH the group head and every row. Without the extension the pills stay inline
1330
+ — and in the head they land to the right of `.hd-ag-meta{margin-left:auto}`,
1331
+ jammed against the card edge. */
1332
+ .hd-ag-head .subs-skills,.rd-ag-head .subs-skills,.hd-ag-row .subs-skills{flex:0 0 100%;margin-top:6px;} /* own full row, aligned under the name cell */
1192
1333
  .skill-pill{font-size:10.5px;font-weight:700;letter-spacing:.01em;padding:2px 9px;border-radius:999px;white-space:nowrap;}
1193
1334
  .skill-pill.is-skill{background:var(--blue-bg);color:var(--blue-ink);}
1194
1335
  .skill-pill.is-mcp{background:var(--green-bg);color:var(--green-ink);box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--green-ink) 18%, transparent);}
@@ -1204,7 +1345,7 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
1204
1345
  /* Sub-agent type pill — the raw Task/Agent subagent_type, inline next to the row
1205
1346
  name (cf. skill pills). Uses the shared violet token (defined :root, l.24) so it
1206
1347
  reads as agent metadata, distinct from the skill (blue) / MCP (green) pills. */
1207
- .subs-tree li .agent-type-pill{font-size:10.5px;font-weight:700;letter-spacing:.01em;padding:2px 9px;border-radius:999px;white-space:nowrap;background:var(--violet-bg);color:var(--violet-ink);}
1348
+ .rd-ag-name .agent-type-pill,.hd-ag-row .agent-type-pill{font-size:10.5px;font-weight:700;letter-spacing:.01em;padding:2px 9px;border-radius:999px;white-space:nowrap;background:var(--violet-bg);color:var(--violet-ink);}
1208
1349
  /* graphify-use count badge (amber) — how many times an agent / sub-agent invoked the
1209
1350
  graphify CLI. Rendered INLINE: in the phase/node header next to the status, and on a
1210
1351
  sub-agent row right after the violet type pill. inline-block + parent flex `gap` size
@@ -1295,7 +1436,6 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
1295
1436
  .wf-filter{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;}
1296
1437
 
1297
1438
  /* Run Results view (Layer 1 mechanical + Layer 2 overview) */
1298
- .results-section{margin-top:14px;}
1299
1439
  .results-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px;}
1300
1440
  .results-chip{font-size:12px;background:var(--chip-bg,#f1f1f4);border:1px solid var(--line);border-radius:999px;padding:2px 10px;}
1301
1441
  .results-clean{color:var(--green-ink,#1a7f37);font-size:13px;padding:6px 0;}
@@ -1495,7 +1635,9 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
1495
1635
  .cost-banner .cb-text{color:var(--ink-2);}
1496
1636
  .cost-banner .cb-text .mono{font-family:var(--mono);font-weight:600;color:var(--ink);}
1497
1637
  .cost-banner .cb-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:10px;}
1498
- .hist-pausenote{font-size:11.5px;font-weight:600;color:var(--amber-ink);margin-left:10px;}
1638
+ /* No margin-left: that only made sense when the note trailed .hist-total inline.
1639
+ In the v2 card it is a direct child of .h-meta on its own line. */
1640
+ .hist-pausenote{font-size:11.5px;font-weight:600;color:var(--amber-ink);}
1499
1641
  .hist-pausenote.total{color:var(--red-ink);}
1500
1642
 
1501
1643
  @media (max-width:1080px){
@@ -1555,3 +1697,832 @@ fieldset.source legend{font-weight:600;font-size:13px;padding:0 6px;color:var(--
1555
1697
  .mvx-env-row .select{flex:0 0 auto;}
1556
1698
  .mvx-warn{color:var(--red,#c0392b);}
1557
1699
  .pl-baseurl{word-break:break-all;}
1700
+
1701
+ /* ---------- History two-screen shell ---------- */
1702
+ .view[data-view="history"]{flex:1 1 auto;min-height:0;padding:0;position:relative;}
1703
+ .hist-shell{position:relative;height:100%;overflow:hidden;}
1704
+ /* NO top padding on the scroller itself — sticky pills must pin flush to the
1705
+ scrollport top (see the comments at the .main and .hist-filter rules). */
1706
+ .hist-screen{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;padding:0 32px 40px;
1707
+ transition:transform .46s cubic-bezier(.65,.02,.28,1);}
1708
+ .hist-screen-list .topbar{padding-top:26px;}
1709
+ .hist-screen-list{transform:translateX(0);}
1710
+ .hist-screen-detail{transform:translateX(100%);padding:0;background:var(--bg);}
1711
+ .hist-shell.detail-open .hist-screen-list{transform:translateX(-100%);}
1712
+ .hist-shell.detail-open .hist-screen-detail{transform:translateX(0);}
1713
+ .hist-shell.no-anim .hist-screen{transition:none;}
1714
+
1715
+ /* style.css has NO base .mono rule (only ancestor-scoped ones), so class="mono"
1716
+ alone renders in Poppins. Scope a base rule to the new subtrees only — a
1717
+ global one would touch every other view. */
1718
+ .hd .mono,.hist-card .mono,#shipit-modal .mono{font-family:var(--mono);}
1719
+
1720
+ /* Card, not a full-bleed band: same border/radius/shadow language as `.card`, and
1721
+ its own 20px/32px margin box supplies the inset the screen itself cannot —
1722
+ `.hist-screen-detail` keeps `padding:0` so the sticky `.hd-tabs` can still pin
1723
+ flush to the scrollport top. Inner padding drops 32 -> 24 so the title lands a
1724
+ card-like distance from the border instead of 56px from the viewport edge. */
1725
+ .hd-header{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
1726
+ box-shadow:var(--shadow);margin:20px 32px 0;padding:20px 24px 18px;}
1727
+ .hd-row1{display:flex;align-items:center;gap:14px;}
1728
+ .hd-title{margin:0;min-width:0;flex:1;font:700 22px/1.25 var(--sans);letter-spacing:-.02em;
1729
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
1730
+ .hd-body{padding:0 32px 40px;}
1731
+ .hd-graph{margin-top:18px;}
1732
+ /* History detail only: a run-graph node is a link into the Logs tab's `source`
1733
+ filter (wireHdGraphLogLinks). `.linked` is added only when the run HAS a Logs
1734
+ tab, so an inert graph never shows a pointer, and the Done bookend carries no
1735
+ data-log-source so it stays unstyled. The live Running card renders the same
1736
+ markup and is deliberately untouched by this rule. Specificity (0,4,0) beats
1737
+ `.run-flow .node{cursor:default}` (1114) regardless of source order — that
1738
+ base rule is pinned by test/ui-run-flow-css.test.mjs:55 and must not move. The
1739
+ ring is the stylesheet's standard focus treatment (1940-1952) rather than the
1740
+ node's own --c accent: --c is a pastel set inline by runNode (860) and would
1741
+ sit near 2:1 against the graph's #FBFBF9 field. */
1742
+ .hd-graph.linked .run-node[data-log-source]{cursor:pointer;}
1743
+ .hd-graph.linked .run-node[data-log-source]:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
1744
+ .hd-error{margin-top:24px;color:var(--red-ink);font-size:12.5px;}
1745
+ .hd-error[hidden]{display:none;}
1746
+ .hist-sic{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;
1747
+ border-radius:50%;flex:0 0 auto;}
1748
+ .hist-sic .sic[hidden]{display:none;}
1749
+ .hist-sic.st-done{background:var(--green-bg);color:var(--green-ink);}
1750
+ .hist-sic.st-stopped,.hist-sic.st-error{background:var(--red-bg);color:var(--red-ink);}
1751
+ .hist-sic.st-paused{background:var(--amber-bg);color:var(--amber-ink);}
1752
+
1753
+ /* ---------- History detail: meta line, branch row, actions, banners ---------- */
1754
+ /* .diff-add/.diff-del exist ONLY as `.hist-diff .diff-add|.diff-del` (837-838).
1755
+ The detail meta uses those classes OUTSIDE that scope, so promote the colors to
1756
+ bare rules (same values); Task 11 folds the now-redundant scoped pair away. */
1757
+ .diff-add{color:var(--green-ink);}
1758
+ .diff-del{color:var(--red-ink);}
1759
+
1760
+ /* Row 2 = status pip + meta line. The 12px top gap moved here from `.hd-meta`
1761
+ IN PLACE: leaving it on the child would stack under this row's own margin and
1762
+ double the space under the title. */
1763
+ .hd-row2{display:flex;align-items:center;gap:10px;margin-top:12px;}
1764
+ /* Meta line is now a flex CHILD, so it takes the row's leftover width (min-width:0
1765
+ lets it wrap instead of pushing the pip off-row). */
1766
+ .hd-meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-width:0;flex:1;
1767
+ font:400 12.5px var(--mono);color:var(--ink-3);}
1768
+ /* 30px is the row-1 size; on a 12.5px meta line the pip shrinks to match the text. */
1769
+ .hd-row2 .hd-sic{width:24px;height:24px;}
1770
+ .hd-meta .strong{font-weight:700;color:var(--ink);} /* no global .strong rule exists */
1771
+ .hd-diffcounts{display:inline-flex;align-items:center;gap:6px;}
1772
+ .hd-dot{font-weight:700;color:var(--ink);}
1773
+ .hd-status-word{font:600 12.5px var(--sans);}
1774
+ /* shared with the Task-11 list card's .hist-status-word (same st-* families) */
1775
+ .hd-status-word.st-done,.hist-status-word.st-done{color:var(--green-ink);}
1776
+ .hd-status-word.st-stopped,.hd-status-word.st-error,
1777
+ .hist-status-word.st-stopped,.hist-status-word.st-error{color:var(--red-ink);}
1778
+ .hd-status-word.st-paused,.hist-status-word.st-paused{color:var(--amber-ink);}
1779
+ /* 14px -> 6px: the branch chip and the Resume/Archive buttons carry ~8px of their
1780
+ own vertical padding, so the row reads far further from the meta line than the
1781
+ number says. 6px + that padding lands on the same optical gap as row1->row2. */
1782
+ .hd-row3{display:flex;align-items:center;gap:8px;margin-top:6px;min-width:0;}
1783
+ .hd-base{color:var(--ink-3);font-size:12px;white-space:nowrap;}
1784
+ .hd-base[hidden]{display:none;}
1785
+ .hd-branch-copy{display:flex;align-items:center;gap:9px;min-width:0;padding:8px 12px;
1786
+ border:1px solid var(--line);border-radius:9px;background:var(--field);
1787
+ font:700 12px var(--mono);color:var(--ink);cursor:pointer;}
1788
+ .hd-branch-copy[hidden]{display:none;}
1789
+ .hd-branch-copy:hover{border-color:var(--ink-3);background:var(--panel);}
1790
+ .hd-branch-name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
1791
+ .hd-branch-copy .ico-check{display:none;}
1792
+ .hd-branch-copy.copied .ico-copy{display:none;}
1793
+ .hd-branch-copy.copied .ico-check{display:inline;color:var(--green-ink);}
1794
+ /* the design's green "Copied" caption, driven off copyBranchToClipboard's own
1795
+ 1200ms .copied window — no extra JS */
1796
+ .hd-copied{display:none;font:500 11.5px var(--sans);color:var(--green-ink);}
1797
+ .hd-branch-copy.copied + .hd-copied{display:inline;}
1798
+ .hd-spacer{flex:1 1 24px;}
1799
+ /* .btn-ghost (388-389) sets no `display` and already gives border-radius:999px —
1800
+ these two icon+label buttons need the flex row themselves or their SVG lands on
1801
+ the text baseline with no gap (unlike .hd-archive below, which ships its own).
1802
+ They also need .btn-ghost's `padding:13px 20px` cut to the compact scale, or the
1803
+ row mixes heights. Every other place this file pairs .btn-ghost with compact
1804
+ controls does the same override (.hist-pr, .ws-actions, .pl-actions,
1805
+ .grv-actions, .mv-card). */
1806
+ .hd-back,.hd-resume{display:inline-flex;align-items:center;gap:8px;padding:8px 15px;}
1807
+ .hd-resume[hidden]{display:none;}
1808
+ /* 9px, not the 8px its siblings use: this one is 12.5px type against .hd-back's
1809
+ 13.5px, so equal padding renders it 36px tall in a row of 38px buttons
1810
+ (measured in headless Chrome). The extra pixel per side matches .hd-pr, which
1811
+ is the same type size and already pays it. */
1812
+ .hd-archive{display:flex;align-items:center;gap:8px;padding:9px 15px;border:1.5px solid var(--red-bg);
1813
+ border-radius:999px;background:var(--panel);font:600 12.5px var(--sans);color:var(--red-ink);cursor:pointer;}
1814
+ .hd-archive[hidden]{display:none;}
1815
+ .hd-archive:hover:not([disabled]){background:var(--red-bg);border-color:var(--red);}
1816
+ .hd-archive[disabled]{opacity:.55;cursor:not-allowed;}
1817
+ /* align-items:flex-start, NOT the default stretch: `.badge.hist-retained-badge`
1818
+ (696) and `.hist-discard` (856) are inline-flex with no width, so a stretching
1819
+ column blows both up to the full body width. Only the two BANNERS want the full
1820
+ row — an unstretched `.cost-banner` renders ~738px inside a 1068px column and
1821
+ its own `.cb-actions{justify-content:flex-end}` then right-aligns short of the
1822
+ edge. */
1823
+ .hd-banners{display:flex;flex-direction:column;align-items:flex-start;gap:12px;}
1824
+ /* Both reused banners carry legacy margins from their old hosts —
1825
+ `.retained-banner{margin:0 0 18px}` (714) and `.cost-banner{margin-top:12px}`
1826
+ (1505) — which double up with this column's own `gap:12px`. Zero them here
1827
+ rather than editing the shared rules. */
1828
+ .hd-banners .retained-banner,.hd-banners .cost-banner{align-self:stretch;margin:0;}
1829
+ /* NOT `.hd-banners:empty` — the container always holds three template children
1830
+ (badge, banner, discard button), just hidden, so :empty never matches and the
1831
+ top margin would always apply. Key the margin off "has a visible child". */
1832
+ .hd-banners:has(> :not([hidden])){margin-top:18px;}
1833
+ /* .hist-discard's existing rules (856-860) are card-scoped only by position; keep
1834
+ them and let the detail banner button ride them unchanged. */
1835
+
1836
+ /* Destructive confirm (spec §5.2). The id keeps it out of .btn-primary's way with
1837
+ no !important. confirmModal removes the class on close, so it never leaks. */
1838
+ #confirm-ok.danger{background:var(--red-ink);border-color:var(--red-ink);color:#fff;}
1839
+
1840
+ /* ---------- History detail: section tabs ---------- */
1841
+ .hd-tabs{position:sticky;top:0;z-index:5;display:flex;align-items:center;flex-wrap:wrap;gap:8px;
1842
+ padding:18px 0 14px;background:var(--bg);}
1843
+ .hd-tab{display:flex;align-items:center;gap:9px;padding:10px 17px;border:1.5px solid var(--line);
1844
+ border-radius:999px;background:var(--panel);font:600 13.5px var(--sans);color:var(--ink-2);cursor:pointer;}
1845
+ .hd-tab:hover{border-color:var(--ink-3);color:var(--ink);}
1846
+ .hd-tab.active{background:var(--ink);color:#fff;border-color:var(--ink);}
1847
+ .hd-tab-badge{padding:2px 8px;border-radius:999px;background:var(--field);color:var(--ink-3);
1848
+ font:600 10.5px var(--mono);}
1849
+ .hd-tab.active .hd-tab-badge{background:var(--blue-bg);color:var(--blue-ink);}
1850
+ .hd-sec{margin-top:4px;}
1851
+ /* Explicit twin, not redundancy insurance: the UA [hidden] rule is (0,0,0) and
1852
+ loses to any author `display`, so the moment a later task gives .hd-sec (or a
1853
+ .hd-sec-* body) a display value, the inactive panels would all render at once. */
1854
+ .hd-sec[hidden]{display:none;}
1855
+
1856
+ /* ---------- History detail: Diff tab ---------- */
1857
+ .hd-diff{display:grid;grid-template-columns:minmax(280px,340px) 1fr;gap:18px;align-items:start;}
1858
+ @media (max-width:900px){.hd-diff{grid-template-columns:1fr;}}
1859
+ .hd-diff-list,.hd-diff-pane{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;}
1860
+ .hd-diff-list-head,.hd-diff-pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;
1861
+ padding:15px 18px;border-bottom:1px solid var(--line);font-size:12.5px;}
1862
+ .hd-diff-rows{padding:6px;max-height:520px;overflow-y:auto;}
1863
+ .hd-diff-proj{padding:8px 12px 2px;color:var(--ink-3);font-size:11px;}
1864
+ .hd-diff-file{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:9px;cursor:pointer;}
1865
+ .hd-diff-file:hover,.hd-diff-file.active{background:var(--field);}
1866
+ .hd-diff-file:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;}
1867
+ .hd-diff-file.deleted .hd-diff-path{opacity:.55;text-decoration:line-through;}
1868
+ .hd-diff-file.new .hd-diff-path{color:var(--green-ink);}
1869
+ /* direction:rtl ellipsizes at the START (the file name matters more than the
1870
+ directory). It also reorders a LEADING NEUTRAL character to the end, so
1871
+ `.github/workflows/ci.yml` would render as `github/workflows/ci.yml.` — the
1872
+ ::before LRM (U+200E) is a strong LTR anchor that pins the dot in place while
1873
+ keeping the start-ellipsis. It lives in CSS, not in textContent, so the
1874
+ `/src\/a\.js/` assertions stay clean. */
1875
+ .hd-diff-file .hd-diff-path{flex:1;min-width:0;font-size:12px;color:var(--ink-2);
1876
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;direction:rtl;text-align:left;}
1877
+ .hd-diff-file .hd-diff-path::before{content:"\200E";}
1878
+ .hd-diff-counts{font-size:11.5px;white-space:nowrap;}
1879
+ /* hdFileCountsHtml's binary chip is a `.hint`, and `.hint` (style.css:283) is
1880
+ `display:block;margin-top:7px` — inside these flex rows it would sit visibly
1881
+ low. Same reset for the pane head. */
1882
+ .hd-diff-counts .hint,.hd-diff-pane-head .hint{display:inline;margin-top:0;}
1883
+ /* The `.hd-diff-path` ellipsis rule is scoped to `.hd-diff-file`, so the SAME class
1884
+ in the pane head is unstyled and WRAPS: measured 49.8px -> 69px on a 78-char
1885
+ path, while the identical path ellipsizes one column to the left. */
1886
+ .hd-diff-pane-head .hd-diff-path{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
1887
+ /* The patch is the tall thing on this screen, so it scrolls INSIDE its pane
1888
+ rather than pushing the whole detail screen down — same cap and mechanism as
1889
+ `.hd-diff-rows` opposite it, which keeps the two panes the same height.
1890
+ Uncapped, a real patch measured 7479px and owned the screen's whole scroll.
1891
+
1892
+ The grid is what makes the row TINT correct. `.hd-dl` used to size itself with
1893
+ `width:max-content;min-width:100%`, but max-content is EACH ROW'S OWN content:
1894
+ in a 336-row patch that produced 11 different row widths (708…1015px), so every
1895
+ line shorter than the longest had its --green-bg/--red-bg band stop mid-pane
1896
+ and the padding land against the text instead of the edge. A single column of
1897
+ `minmax(max-content,1fr)` is sized by the WIDEST row (1fr keeps it filling the
1898
+ pane when the patch is narrow) and stretch makes every row match it — measured
1899
+ uniform at 1015px with 0 of 217 tinted rows stopping short. D4 forbids syntax
1900
+ highlighting, so this tint is the pane's only visual signal — it has to hold. */
1901
+ .hd-diff-body{padding:12px 0;font:400 12px/1.85 var(--mono);color:var(--ink-2);
1902
+ display:grid;grid-template-columns:minmax(max-content,1fr);
1903
+ max-height:520px;overflow-x:auto;overflow-y:auto;}
1904
+ .hd-diff-body.hint,.hd-diff-none{padding:18px;}
1905
+ .hd-dl{padding:0 18px;white-space:pre;}
1906
+ .hd-dl-hunk{color:var(--ink-3);background:var(--field);}
1907
+ .hd-dl-add{background:var(--green-bg);}
1908
+ .hd-dl-del{background:var(--red-bg);}
1909
+ .hd-diff-trunc{padding:10px 18px 0;}
1910
+ .hd-diff-empty{margin-top:24px;padding:40px;text-align:center;color:var(--ink-2);
1911
+ background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
1912
+
1913
+ /* ---------- History detail: Overview tab ---------- */
1914
+ .hd-ov{display:flex;flex-direction:column;gap:18px;}
1915
+ .hd-ov-verdict{display:flex;align-items:center;gap:12px;padding:16px 20px;background:var(--panel);
1916
+ border:1px solid var(--line);border-radius:var(--r-card);font:500 13.5px var(--sans);}
1917
+ .hd-ov-verdict.clean{color:var(--green-ink);}
1918
+ .hd-ov-verdict.warn{color:var(--amber-ink);}
1919
+ .hd-ov-verdict.none{color:var(--ink-2);} /* the class the results-less arm emits */
1920
+ .hd-ov-chip{padding:5px 12px;border-radius:999px;font:600 11.5px var(--sans);}
1921
+ .hd-ov-chip.clean,.hd-ov-chip.st-done{background:var(--green-bg);color:var(--green-ink);}
1922
+ .hd-ov-chip.warn,.hd-ov-chip.st-paused{background:var(--amber-bg);color:var(--amber-ink);}
1923
+ .hd-ov-chip.st-stopped,.hd-ov-chip.st-error{background:var(--red-bg);color:var(--red-ink);}
1924
+ .hd-ov-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:18px;}
1925
+ .hd-ov-card{padding:20px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
1926
+ .hd-ov-label{font:600 10.5px var(--sans);letter-spacing:.14em;color:var(--ink-3);}
1927
+ .hd-ov-value{margin-top:10px;font-size:22px;color:var(--ink);}
1928
+ .hd-ov-sub{margin-top:6px;font-size:11.5px;color:var(--ink-3);overflow-wrap:anywhere;}
1929
+ .hd-ov-task{padding:22px 24px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
1930
+ .hd-ov-task-h{font:600 13px var(--sans);}
1931
+ /* overflow-wrap:anywhere like its sibling .hd-ov-sub — prompts routinely carry
1932
+ absolute paths and URLs, and `.hist-screen{overflow-x:hidden}` would silently
1933
+ CLIP an unbroken token rather than let it scroll. */
1934
+ .hd-ov-task p{margin:10px 0 0;max-width:74ch;font:400 13.5px/1.75 var(--sans);color:var(--ink-2);
1935
+ white-space:pre-wrap;overflow-wrap:anywhere;}
1936
+ .hd-ov-more{margin-top:8px;border:none;background:none;color:var(--blue-ink);font:500 12.5px var(--sans);cursor:pointer;padding:0;}
1937
+ .hd-ov-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px;}
1938
+ .hd-ov-tag{padding:6px 12px;border:1px solid var(--line);border-radius:999px;font-size:11.5px;color:var(--ink-2);}
1939
+
1940
+ /* ---------- History detail: Agents tab ---------- */
1941
+ .hd-ag-group{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
1942
+ overflow:hidden;margin-bottom:18px;}
1943
+ .hd-ag-head{display:flex;align-items:center;flex-wrap:wrap;gap:12px;padding:15px 20px;
1944
+ border-bottom:1px solid var(--line);font-size:13px;}
1945
+ .hd-ag-meta{color:var(--ink-3);font-size:11.5px;margin-left:auto;}
1946
+ .hd-ag-none{padding:12px 20px;}
1947
+ .hd-ag-row{display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:12px 20px;border-top:1px solid var(--line);}
1948
+ /* NOT `.hd-ag-row:first-of-type` — `:first-of-type` is per ELEMENT TYPE, and
1949
+ `.hd-ag-head` is the first `div` in the card, so no row would ever match it and
1950
+ the first row's border would double up with the head's `border-bottom`. */
1951
+ .hd-ag-head + .hd-ag-row{border-top:none;}
1952
+ .hd-ag-name{min-width:0;flex:1 1 200px;font:500 13px var(--sans);color:var(--ink);
1953
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
1954
+ /* NO `.hd-ag-row .st{margin-left:auto}` here — the in-place extension of
1955
+ `.hd-ag-row .st` already carries `margin-left:auto` along with the font;
1956
+ a second bare rule is pure duplication. */
1957
+ .hd-ag-dur{width:90px;text-align:right;font-size:11.5px;color:var(--ink-2);}
1958
+ .hd-ag-cost{width:80px;text-align:right;font-size:11.5px;color:var(--ink-2);}
1959
+
1960
+ /* ---------- History detail: Clarify tab ---------- */
1961
+ .hd-cl{display:flex;flex-direction:column;gap:14px;}
1962
+ .hd-cl-card{padding:20px 24px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
1963
+ .hd-cl-q,.hd-cl-a{display:flex;gap:12px;align-items:flex-start;}
1964
+ .hd-cl-a{margin-top:12px;color:var(--ink-2);}
1965
+ .hd-cl-q > span:last-child{font:600 13.5px/1.6 var(--sans);}
1966
+ .hd-cl-a > span:last-child{font:400 13.5px/1.7 var(--sans);}
1967
+ .hd-cl-chip{flex:0 0 auto;padding:3px 9px;border-radius:7px;font-size:10.5px;font-weight:600;}
1968
+ .hd-cl-chip.ask{background:var(--field);color:var(--ink-2);}
1969
+ .hd-cl-chip.ans{background:var(--green-bg);color:var(--green-ink);}
1970
+ /* `.hint` (:283) ships `margin-top:7px`; the shorthand replaces it outright so the
1971
+ caption hugs the block it introduces instead of floating mid-gap. */
1972
+ .hd-cl-caption{margin:4px 0 -6px;}
1973
+
1974
+ /* ---------- History detail: Logs tab ---------- */
1975
+ /* History-scoped ONLY: the shared `.log` / `.log-filters` markup is the Running
1976
+ view's, and `.run-log .log` keeps its own sizes there (D7 — the Running view is
1977
+ untouched). Neither rule sets `display`, so `.hd-sec[hidden]` (:1703) still hides
1978
+ the whole panel and no `[hidden]` twin is needed. */
1979
+ .hd-sec-logs .log{background:var(--panel);border:1px solid var(--line);border-radius:16px;
1980
+ min-height:260px;max-height:520px;overflow-y:auto;padding:18px 20px;}
1981
+ .hd-sec-logs .log-filters{margin-bottom:10px;}
1982
+
1983
+ /* ---------- History detail: PR controls + the "Ship it?" modal ---------- */
1984
+ /* Detail-header PR controls (spec §5.2: black pill). `.hd-pr-link` carries no rule
1985
+ of its own — its colour, its removed underline and the MERGED grey all come from
1986
+ the `.hist-pr-link` selector lists at :848-:850, extended in place. */
1987
+ .hd-pr{padding:9px 18px;border:1.5px solid var(--ink);border-radius:999px;background:var(--ink);
1988
+ font:600 12.5px var(--sans);color:#fff;cursor:pointer;flex:0 0 auto;}
1989
+ .hd-pr[hidden]{display:none;}
1990
+ .hd-pr:hover{opacity:.88;}
1991
+ .hd-pr-link{flex:0 0 auto;font:600 12.5px var(--sans);}
1992
+ .hd-pr-link[hidden]{display:none;}
1993
+
1994
+ /* WIDTH GOES ON `#shipit-modal .card`, NOT `.shipit-card`. The markup is
1995
+ `<div class="card shipit-card">` inside `.viewer-modal`, and
1996
+ `.viewer-modal .card{width:min(860px,100%);…}` (:782) is (0,2,0): a bare
1997
+ `.shipit-card{width:…}` (0,1,0) loses no matter where it is appended, and the
1998
+ dialog would ship ~1.5x the design width. Precedents: `.folder-modal .card`
1999
+ (:786) and `.confirm-modal .card` (:1306). Everything else below only ties with
2000
+ `.card` (:263) and wins on source order, so it stays bare. */
2001
+ #shipit-modal .card{width:min(560px,100%);}
2002
+ .shipit-card{padding:32px 28px 24px;text-align:center;
2003
+ animation:shipit-rise .34s cubic-bezier(.2,.7,.3,1) both;}
2004
+ @keyframes shipit-rise{0%{transform:translateY(10px);opacity:0}100%{transform:translateY(0);opacity:1}}
2005
+ .shipit-ico-wrap{position:relative;display:grid;place-items:center;width:74px;height:74px;margin:0 auto;}
2006
+ .shipit-spark{position:absolute;inset:0;border-radius:50%;background:var(--green-bg);
2007
+ animation:shipit-spark .9s ease-out .12s both;}
2008
+ .shipit-ico{position:relative;display:grid;place-items:center;width:60px;height:60px;border-radius:50%;
2009
+ background:var(--green-bg);color:var(--green-ink);animation:shipit-pop .42s cubic-bezier(.2,.8,.25,1) both;}
2010
+ @keyframes shipit-pop{0%{transform:scale(.72);opacity:0}60%{transform:scale(1.06)}100%{transform:scale(1);opacity:1}}
2011
+ @keyframes shipit-spark{0%{transform:scale(.4);opacity:0}45%{opacity:1}100%{transform:scale(1.9);opacity:0}}
2012
+ .shipit-card h2{margin:18px 0 0;font:700 20px/1.25 var(--sans);letter-spacing:-.02em;}
2013
+ .shipit-sub{margin:8px 0 0;font:400 13.5px/1.6 var(--sans);color:var(--ink-2);}
2014
+ .shipit-summary{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:8px;
2015
+ margin-top:18px;padding:14px;background:var(--field);border-radius:14px;font-size:12px;color:var(--ink-2);}
2016
+ .shipit-summary[hidden]{display:none;}
2017
+ /* An empty flex child still eats a `gap`, so a results-less run ("+12 −3", no file
2018
+ count) would render a stray 8px hole. Hide the value spans by NAME — a blanket
2019
+ `> span:empty` would also hide `.shipit-break`, whose whole job is to be an empty
2020
+ full-width line break. Precedent: `.h-meta .hist-total:empty` (:807). */
2021
+ .shipit-files:empty,.shipit-add:empty,.shipit-del:empty,.shipit-base:empty{display:none;}
2022
+ .shipit-files:empty + .shipit-dot{display:none;}
2023
+ .shipit-break{flex-basis:100%;height:0;}
2024
+ .shipit-branch{color:var(--ink);word-break:break-all;}
2025
+ .shipit-actions{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:22px;}
2026
+ .shipit-ok{padding:11px 22px;border:1.5px solid var(--ink);border-radius:999px;background:var(--ink);
2027
+ font:600 13.5px var(--sans);color:#fff;cursor:pointer;}
2028
+ .shipit-err{margin-top:12px;}
2029
+ /* MANDATORY twin: the node is `class="hint err" hidden`, and `.hint` (:283) sets
2030
+ display:block — an author rule always beats the UA `[hidden]{display:none}`.
2031
+ Without this the modal permanently carries an empty 12px-margin block (and a
2032
+ stray node in the a11y tree). */
2033
+ .shipit-err[hidden]{display:none;}
2034
+
2035
+ /* Reduced motion for the three ship-it animations. This block MUST sit AFTER the
2036
+ rules that declare them: `@media` contributes no specificity, so naming
2037
+ `.shipit-card` in the kill list at :763 would tie at (0,1,0) and LOSE on source
2038
+ order — the animation would still play. (The four names already at :763 work
2039
+ only because each is declared before it, and the run-graph block at :1246
2040
+ likewise follows its animations.) */
2041
+ @media (prefers-reduced-motion: reduce){
2042
+ .shipit-card,.shipit-ico{animation:none;}
2043
+ /* `.shipit-spark` needs its END STATE too, not just `animation:none`. Its
2044
+ keyframes are `both`-filled and finish at opacity:0; kill the animation alone
2045
+ and it computes `opacity:1; transform:none` — a permanent 74px --green-bg disc
2046
+ ringing the 60px icon. */
2047
+ .shipit-spark{animation:none;opacity:0;}
2048
+ }
2049
+
2050
+ /* ---------- History list card v2 ---------- */
2051
+ /* Appended at EOF, after every surviving `.hist-*` rule — the History block is not
2052
+ contiguous (it also lives at ~796-862 and ~1516), so a mid-file append would lose
2053
+ the source-order tie against those. Where a redesigned element KEEPS an existing
2054
+ class name (.hist-total, .hist-time, .hist-pausenote, .h-meta b) the rule was
2055
+ edited in place instead; those are never restated here. */
2056
+ /* card icon is 36px; scoped so the detail header's 30px .hd-sic keeps its size */
2057
+ .hist-card .hist-sic{width:36px;height:36px;align-self:center;}
2058
+ .hist-meta-line{display:flex;align-items:center;flex-wrap:wrap;gap:7px;margin-top:5px;}
2059
+ .hist-meta-line .hm-seg{display:inline-flex;align-items:center;gap:7px;}
2060
+ .hist-meta-line .hm-seg[hidden]{display:none;} /* author display beats the UA [hidden] rule */
2061
+ .hm-dot{font:700 16px/1 var(--mono);color:var(--ink);}
2062
+ .hist-status-word{font:600 12px var(--sans);display:inline-flex;align-items:center;gap:7px;}
2063
+ /* the design's 7px status accent dot before the word; currentColor = family ink */
2064
+ .hist-meta-line .hist-status-word::before{content:'';width:7px;height:7px;border-radius:50%;
2065
+ background:currentColor;flex:0 0 auto;}
2066
+ .hist-day,.hist-clock{font:400 12.5px var(--mono);color:var(--ink-3);}
2067
+ .hist-diff-pill{display:inline-flex;align-items:center;gap:8px;padding:4px 11px;
2068
+ border:1px solid var(--line);border-radius:999px;background:var(--panel);font-size:12px;}
2069
+ .hist-diff-pill[hidden]{display:none;}
2070
+ .hist-diff-pill .hist-diff{display:inline-flex;gap:6px;font-weight:700;}
2071
+ .hist-diff-pill .hist-diff[hidden],.hist-nodiff[hidden]{display:none;}
2072
+ .hist-nodiff{color:var(--ink-3);}
2073
+ .hist-open{display:flex;align-items:center;justify-content:center;width:30px;height:30px;
2074
+ border:1px solid var(--line);border-radius:9px;background:var(--panel);color:var(--ink-2);cursor:pointer;}
2075
+ .hist-open:hover{background:var(--ink);color:#fff;border-color:var(--ink);}
2076
+ /* "Copied" caption on the card — same CSS-only mechanism as .hd-copied */
2077
+ .hist-copied{display:none;font:500 11px var(--sans);color:var(--green-ink);}
2078
+ .hist-branch-copy.copied + .hist-copied{display:inline;}
2079
+
2080
+ /* ---------- focus visibility (History redesign) ----------
2081
+ Every other interactive control in this stylesheet carries a ring (.btn,
2082
+ .btn-go, .btn-stop, .nav button, .hist-head, .seg button, .info-tip, .ws-head,
2083
+ .proj-del, .ch-hit); none of the new controls did. `.btn-ghost` declares no
2084
+ ring to inherit and carries no `btn` class, so `.hd-back`, `.hd-resume` and
2085
+ `.shipit-cancel` had nothing at all — which matters most for `.hd-back`, the
2086
+ node openHistDetail focuses programmatically, and for the `.hd-tab` tablist.
2087
+ `.hd-diff-file` already has its own (inset) ring and is not repeated here. */
2088
+ .hd-tab:focus-visible,.hd-back:focus-visible,.hd-resume:focus-visible,
2089
+ .hd-archive:focus-visible,.hd-pr:focus-visible,.hd-pr-link:focus-visible,
2090
+ .hd-branch-copy:focus-visible,.hd-sec:focus-visible,.hist-open:focus-visible,
2091
+ .hist-branch-copy:focus-visible,.shipit-ok:focus-visible,.shipit-cancel:focus-visible{
2092
+ outline:2px solid var(--ink);outline-offset:2px;}
2093
+
2094
+ /* ---------- Running list card v2 (.rc-*) ----------
2095
+ Appended at EOF, after every surviving `.run-*` / `.btn-*` rule — the Running
2096
+ block is not contiguous (it also lives at ~557-600 and ~1109) and .btn-pause /
2097
+ .btn-resume / .btn-stop have base rules at 237-254, so a mid-file append would
2098
+ lose the source-order tie. Same reasoning as the History list card v2 block. */
2099
+ /* margin-bottom replaces `.run-top`'s own 18px, which this task deletes:
2100
+ `.run-flow-wrap` (:1109) has only a BOTTOM margin, so without this the graph
2101
+ would sit flush against the header until Task 4 adds `.rc-detailed{margin-top:18px}`. */
2102
+ .rc-head{display:flex;align-items:flex-start;gap:13px;cursor:pointer;margin-bottom:18px;}
2103
+ .rc-head:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2104
+ .rc-sic{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;
2105
+ border-radius:50%;flex:0 0 auto;align-self:center;}
2106
+ .rc-sic .sic[hidden]{display:none;}
2107
+ .rc-sic.st-blue{background:var(--blue-bg);color:var(--blue-ink);}
2108
+ .rc-sic.st-amber{background:var(--amber-bg);color:var(--amber-ink);}
2109
+ .rc-sic.st-green{background:var(--green-bg);color:var(--green-ink);}
2110
+ .rc-sic.st-red{background:var(--red-bg);color:var(--red-ink);}
2111
+ .rc-sic .sic-spin{animation:wr-spin 1.15s linear infinite;transform-origin:50% 50%;}
2112
+ .rc-body{flex:1;min-width:0;}
2113
+ .rc-title{display:block;font-weight:600;font-size:14.5px;letter-spacing:-.01em;
2114
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
2115
+ .rc-meta{display:flex;align-items:center;flex-wrap:wrap;gap:7px;margin-top:5px;
2116
+ color:var(--ink-3);font-size:12.5px;}
2117
+ .rc-meta .rc-seg{display:inline-flex;align-items:center;gap:7px;}
2118
+ .rc-dot{font:700 16px/1 var(--mono);color:var(--ink);}
2119
+ .rc-status-word{font:600 12px var(--sans);display:inline-flex;align-items:center;gap:7px;}
2120
+ /* the 7px status accent dot before the word; currentColor = the family ink */
2121
+ .rc-meta .rc-status-word::before{content:'';width:7px;height:7px;border-radius:50%;
2122
+ background:currentColor;flex:0 0 auto;}
2123
+ .rc-status-word.st-peach{color:var(--peach-ink);}
2124
+ .rc-status-word.st-blue{color:var(--blue-ink);}
2125
+ .rc-status-word.st-violet{color:var(--violet-ink);}
2126
+ .rc-status-word.st-amber{color:var(--amber-ink);}
2127
+ .rc-status-word.st-green{color:var(--green-ink);}
2128
+ .rc-status-word.st-red{color:var(--red-ink);}
2129
+ .rc-meta .run-time,.rc-meta .run-cost{font-weight:700;color:var(--ink);}
2130
+ .rc-branch{display:flex;align-items:center;gap:6px;margin-top:6px;min-width:0;
2131
+ font-family:var(--mono);font-size:12px;font-weight:600;color:var(--ink-2);}
2132
+ .rc-branch[hidden]{display:none;} /* author display:flex beats the UA [hidden] rule */
2133
+ .rc-base{color:var(--ink-3);font-weight:500;white-space:nowrap;}
2134
+ .rc-base[hidden]{display:none;}
2135
+ .rc-branch-copy{display:inline-flex;align-items:center;gap:8px;min-width:12ch;
2136
+ padding:4px 10px;border:1px solid var(--line);border-radius:9px;background:var(--field);
2137
+ font:700 11.5px var(--mono);color:var(--ink);cursor:pointer;}
2138
+ .rc-branch-copy:hover{border-color:var(--ink-3);background:var(--panel);}
2139
+ .rc-branch-name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
2140
+ .rc-branch-copy .ico-check{display:none;}
2141
+ .rc-branch-copy.copied .ico-copy{display:none;}
2142
+ .rc-branch-copy.copied .ico-check{display:inline;color:var(--green-ink);}
2143
+ /* "Copied" caption — the CSS-only mechanism .hd-copied / .hist-copied use, driven
2144
+ off copyBranchToClipboard's own 1200ms `.copied` window (app.js:3666-3672). */
2145
+ .rc-copied{display:none;font:500 11px var(--sans);color:var(--green-ink);}
2146
+ .rc-branch-copy.copied + .rc-copied{display:inline;}
2147
+ .rc-acts{display:flex;align-items:center;gap:8px;flex:0 0 auto;align-self:center;margin-left:auto;}
2148
+ .rc-qpill{display:inline-flex;align-items:center;padding:5px 11px;border-radius:999px;
2149
+ background:var(--amber-bg);color:var(--amber-ink);font:700 11.5px var(--sans);white-space:nowrap;}
2150
+ .rc-qpill[hidden]{display:none;}
2151
+ /* the four 30px icon buttons; .rc-open mirrors .hist-open exactly */
2152
+ .rc-acts .btn-pause,.rc-acts .btn-resume,.rc-acts .btn-stop,.rc-open{
2153
+ display:inline-flex;align-items:center;justify-content:center;gap:0;
2154
+ width:30px;height:30px;padding:0;border-radius:9px;background:var(--panel);cursor:pointer;}
2155
+ .rc-acts .btn-pause,.rc-acts .btn-resume{border:1px solid var(--amber);color:var(--amber-ink);}
2156
+ .rc-acts .btn-pause:hover,.rc-acts .btn-resume:hover{background:var(--amber-bg);}
2157
+ .rc-acts .btn-stop{border:1px solid var(--red);color:var(--red-ink);}
2158
+ .rc-acts .btn-stop:hover{background:var(--red-bg);}
2159
+ /* The base `.btn-pause[hidden],.btn-resume[hidden]` rule (254) ties on specificity
2160
+ with `.rc-acts .btn-pause` above and would LOSE on source order — a paused card
2161
+ would show both buttons. Re-state it at the cluster's specificity. */
2162
+ .rc-acts .btn-pause[hidden],.rc-acts .btn-resume[hidden]{display:none;}
2163
+ .rc-open{border:1px solid var(--line);color:var(--ink-2);}
2164
+ .rc-open:hover{background:var(--ink);color:#fff;border-color:var(--ink);}
2165
+ .rc-open:focus-visible,.rc-branch-copy:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2166
+ /* ---------- Running redesign: shared keyframes (C2 — declared ONCE, here) ----------
2167
+ @keyframes are name-resolved, not cascaded, so their position relative to the
2168
+ rules that use them is irrelevant; what matters is that there is exactly one of
2169
+ each. Tasks 5, 6, 7, 10 and 12 grep before adding and add nothing. */
2170
+ @keyframes wr-spin{to{transform:rotate(360deg);}}
2171
+ @keyframes wr-pulse{0%,100%{opacity:1;transform:scale(1);}50%{opacity:.45;transform:scale(.82);}}
2172
+ @keyframes wr-rise{0%{transform:translateY(10px);opacity:0;}100%{transform:translateY(0);opacity:1;}}
2173
+ @keyframes wr-blink{0%,49%{opacity:1;}50%,100%{opacity:0;}}
2174
+ /* Placed AFTER the rule it neutralizes — source order, not specificity, is what wins. */
2175
+ @media (prefers-reduced-motion: reduce){
2176
+ .rc-sic .sic-spin{animation:none;}
2177
+ }
2178
+
2179
+ /* ---------- Running list: density toggle + compact card body ---------- */
2180
+ /* .topbar is `justify-content:space-between` with three children now; pushing the
2181
+ pill right keeps pill + toggle together as the right-hand group. */
2182
+ #running-status-pill{margin-left:auto;}
2183
+ .run-density{display:inline-flex;align-items:center;gap:2px;padding:3px;border-radius:999px;
2184
+ background:var(--field);flex:0 0 auto;align-self:center;}
2185
+ /* `.rc-dseg`, not `.rd-seg`: the density toggle is LIST chrome, and the Global
2186
+ Constraints reserve `.rd-*` for the run DETAIL — `.rd-seg` also sits one
2187
+ character from C1's `secClass:'rd-sec'`, which the tab engine writes into the
2188
+ detail screen. */
2189
+ .run-density .rc-dseg{display:inline-flex;align-items:center;justify-content:center;
2190
+ width:32px;height:28px;padding:0;border:0;border-radius:999px;background:transparent;
2191
+ color:var(--ink-2);cursor:pointer;transition:background .15s,color .15s;}
2192
+ .run-density .rc-dseg:hover{color:var(--ink);}
2193
+ .run-density .rc-dseg[aria-pressed="true"]{background:var(--ink);color:#fff;}
2194
+ .run-density .rc-dseg:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2195
+ /* One body per density. The other is display:none — which zeroes its scrollers, so
2196
+ setRunDensity stashes .log scrollTop + .run-flow-wrap scrollLeft across the flip. */
2197
+ .run-card[data-density="compact"] .rc-detailed{display:none;}
2198
+ .run-card[data-density="detailed"] .rc-compact{display:none;}
2199
+ .rc-compact{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-top:14px;}
2200
+ .rc-step-chip{padding:4px 10px;border-radius:999px;font:700 11px var(--mono);
2201
+ letter-spacing:.04em;background:var(--field);color:var(--ink-2);white-space:nowrap;}
2202
+ .rc-step-chip.st-blue{background:var(--blue-bg);color:var(--blue-ink);}
2203
+ .rc-step-chip.st-amber{background:var(--amber-bg);color:var(--amber-ink);}
2204
+ .rc-step-chip.st-green{background:var(--green-bg);color:var(--green-ink);}
2205
+ .rc-step-chip.st-red{background:var(--red-bg);color:var(--red-ink);}
2206
+ .rc-step-name{min-width:0;font:600 14.5px var(--sans);color:var(--ink);
2207
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
2208
+ .rc-step-model{font:400 12px var(--mono);color:var(--ink-3);margin-left:auto;white-space:nowrap;}
2209
+ .rc-step-model[hidden]{display:none;}
2210
+ /* .run-top's old 18px bottom margin used to open this gap. */
2211
+ .rc-detailed{margin-top:18px;}
2212
+
2213
+ /* ---------- Running two-screen shell (twin of the History track, 1591-1603) ---------- */
2214
+ .view[data-view="running"]{flex:1 1 auto;min-height:0;padding:0;position:relative;}
2215
+ .run-shell{position:relative;height:100%;overflow:hidden;}
2216
+ /* NO top padding on the scroller itself — T7's sticky .rd-tabs must pin flush to
2217
+ the scrollport top, exactly as .hist-screen does for .hd-tabs. */
2218
+ .run-screen{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;padding:0 32px 40px;
2219
+ transition:transform .46s cubic-bezier(.65,.02,.28,1);}
2220
+ .run-screen-list .topbar{padding-top:26px;}
2221
+ .run-screen-list{transform:translateX(0);}
2222
+ .run-screen-detail{transform:translateX(100%);padding:0;background:var(--bg);}
2223
+ .run-shell.detail-open .run-screen-list{transform:translateX(-100%);}
2224
+ .run-shell.detail-open .run-screen-detail{transform:translateX(0);}
2225
+ .run-shell.no-anim .run-screen{transition:none;}
2226
+ /* Same reasoning as body.view-history .main (222) and .topnav (227): .main stops
2227
+ scrolling and becomes the bounded column so each screen owns its scrollport,
2228
+ and the compact top-nav (<1080px, a SIBLING of the views) re-applies the gutter
2229
+ .main just dropped. */
2230
+ body.view-running .main{display:flex;flex-direction:column;overflow:hidden;padding:0;}
2231
+ body.view-running .topnav{margin:12px 32px 0;flex:0 0 auto;}
2232
+ /* style.css has no base .mono rule (only ancestor-scoped ones) — scope one to the
2233
+ new subtree, exactly as :1608 does for .hd/.hist-card/#shipit-modal. */
2234
+ .rd .mono{font-family:var(--mono);}
2235
+
2236
+ /* ---------- Running detail: header card ---------- */
2237
+ /* Card, not a full-bleed band: .run-screen-detail keeps padding:0 so the sticky
2238
+ tabs can pin, and this margin box supplies the inset (mirrors .hd-header:1615). */
2239
+ .rd-header{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
2240
+ box-shadow:var(--shadow);margin:20px 32px 0;padding:20px 24px 18px;}
2241
+ .rd-body{padding:0 32px 40px;}
2242
+ .rd-row1{display:flex;align-items:center;gap:14px;}
2243
+ .rd-title{margin:0;min-width:0;flex:1;font:700 22px/1.25 var(--sans);letter-spacing:-.02em;
2244
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
2245
+ .rd-status{flex:0 0 auto;}
2246
+ .rd-status[hidden]{display:none;}
2247
+ /* The design's slower, softer pulse; .pill-run .pdot (567) supplies the 7px dot
2248
+ and the family fill, this only re-times it. `.parked` = nothing is running. */
2249
+ .rd-status .pdot{animation:wr-pulse 1.6s ease-in-out infinite;}
2250
+ .rd-status.parked .pdot{animation:none;}
2251
+ .rd-meta{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-width:0;margin-top:12px;
2252
+ font:400 12.5px var(--mono);color:var(--ink-3);}
2253
+ .rd-meta .strong{font-weight:700;color:var(--ink);}
2254
+ .rd-dot{font-weight:700;color:var(--ink);}
2255
+ .rd-row3{display:flex;align-items:center;gap:8px;margin-top:6px;min-width:0;}
2256
+ .rd-base{color:var(--ink-3);font-size:12px;white-space:nowrap;}
2257
+ .rd-base[hidden]{display:none;}
2258
+ .rd-branch-copy{display:flex;align-items:center;gap:9px;min-width:16ch;padding:8px 12px;
2259
+ border:1px solid var(--line);border-radius:9px;background:var(--field);
2260
+ font:700 12px var(--mono);color:var(--ink);cursor:pointer;}
2261
+ .rd-branch-copy[hidden]{display:none;}
2262
+ .rd-branch-copy:hover{border-color:var(--ink-3);background:var(--panel);}
2263
+ .rd-branch-name{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
2264
+ .rd-branch-copy .ico-check{display:none;}
2265
+ .rd-branch-copy.copied .ico-copy{display:none;}
2266
+ .rd-branch-copy.copied .ico-check{display:inline;color:var(--green-ink);}
2267
+ .rd-copied{display:none;font:500 11.5px var(--sans);color:var(--green-ink);}
2268
+ .rd-branch-copy.copied + .rd-copied{display:inline;}
2269
+ .rd-spacer{flex:1 1 24px;}
2270
+ .rd-pause{display:flex;align-items:center;gap:8px;padding:9px 15px;border:1.5px solid var(--amber-bg);
2271
+ border-radius:999px;background:var(--panel);font:600 12.5px var(--sans);color:var(--amber-ink);cursor:pointer;}
2272
+ .rd-pause[hidden]{display:none;}
2273
+ .rd-pause:hover:not([disabled]){background:var(--amber-bg);border-color:var(--amber);}
2274
+ .rd-pause[disabled]{opacity:.55;cursor:not-allowed;}
2275
+ /* Only one of the two glyphs shows; data-action decides which. */
2276
+ .rd-pause[data-action="pause"] .ico-play,.rd-pause[data-action="resume"] .ico-pause{display:none;}
2277
+ .rd-stop{display:flex;align-items:center;gap:8px;padding:9px 15px;border:1.5px solid var(--red-bg);
2278
+ border-radius:999px;background:var(--panel);font:600 12.5px var(--sans);color:var(--red-ink);cursor:pointer;}
2279
+ .rd-stop[hidden]{display:none;}
2280
+ .rd-stop:hover:not([disabled]){background:var(--red-bg);border-color:var(--red);}
2281
+ .rd-error{margin-top:24px;color:var(--red-ink);font-size:12.5px;}
2282
+ .rd-error[hidden]{display:none;}
2283
+ /* .btn-ghost declares no focus ring and .rd-back is focused programmatically by
2284
+ openRunDetail — same reasoning as the .hd-back arm. */
2285
+ .rd-back{display:inline-flex;align-items:center;gap:8px;padding:8px 15px;}
2286
+ .rd-back:focus-visible,.rd-pause:focus-visible,.rd-stop:focus-visible,
2287
+ .rd-branch-copy:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2288
+
2289
+ /* MUST sit after the rules above: @media contributes no specificity, so an
2290
+ earlier placement would lose the source-order tie (see the note at :1927-1932). */
2291
+ @media (prefers-reduced-motion: reduce){
2292
+ .run-screen{transition:none;}
2293
+ .rd-status .pdot,.rd-status.parked .pdot{animation:none;}
2294
+ }
2295
+
2296
+ /* ---------- Running detail: pipeline graph ---------- */
2297
+ /* The dot-grid panel spec §5.3 asks for is already `.run-flow-wrap` —
2298
+ radial-gradient var(--line-2) 1.1px at 22px 22px, 18px radius, horizontal
2299
+ scroll. This only supplies the margin box; the wrap's own legacy
2300
+ `margin:0 0 18px` is zeroed so it does not double up with .rd-graph's. */
2301
+ .rd-graph{margin-top:18px;}
2302
+ .rd-graph .run-flow-wrap{margin:0;}
2303
+
2304
+ /* ---------- Running detail: banners ---------- */
2305
+ /* align-items:flex-start, NOT the default stretch: `.hist-discard` is an
2306
+ inline-flex button with no width and a stretching column would blow it up to
2307
+ the full body width. Only the two BANNERS want the full row. Same shape as
2308
+ .hd-banners. */
2309
+ .rd-banners{display:flex;flex-direction:column;align-items:flex-start;gap:12px;}
2310
+ /* Both reused banners carry legacy margins from their old hosts —
2311
+ `.retained-banner{margin:0 0 18px}` and `.cost-banner{margin-top:12px}` —
2312
+ which double up with this column's own gap. */
2313
+ .rd-banners .retained-banner,.rd-banners .cost-banner{align-self:stretch;margin:0;}
2314
+ /* NOT `:empty` — the container always holds its two template children, just
2315
+ hidden. Key the margin off "has a visible child", as .hd-banners does. */
2316
+ .rd-banners:has(> :not([hidden])){margin-top:18px;}
2317
+
2318
+ /* ---------- Running detail: question panel ---------- */
2319
+ /* Container only — the panel's own restyle (larger metrics, green-tinted picked
2320
+ options, the "N of M answered" footer, "Open run") is T11 for BOTH mounts. */
2321
+ .rd-questions{margin-top:18px;animation:wr-rise .3s cubic-bezier(.2,.7,.3,1) both;}
2322
+ /* Explicit twin: the UA [hidden] rule is (0,0,0) and loses to any author
2323
+ `display`, so without this the panel would render even while hidden. */
2324
+ .rd-questions[hidden]{display:none;}
2325
+ /* .qpanel ships `margin-top:18px` which would double up with the wrapper's.
2326
+ T11 rewrites the .qpanel block mid-file but does NOT restate this rule, so it
2327
+ stays the last word on margin-top for the detail mount. */
2328
+ .rd-questions .qpanel{margin-top:0;}
2329
+
2330
+ /* MUST sit after the rule it neutralizes — @media contributes no specificity. */
2331
+ @media (prefers-reduced-motion: reduce){
2332
+ .rd-questions{animation:none;}
2333
+ }
2334
+
2335
+ /* ---------- Running detail: tab bodies ---------- */
2336
+ /* NB: no `.mono` rule here. `.rd .mono{font-family:var(--mono);}` already ships
2337
+ and `#run-detail-tpl`'s root IS `<div class="rd">`, so the subtree is covered;
2338
+ a second `#run-detail .mono` would be dead weight. (History's twin is the
2339
+ `.hd .mono,.hist-card .mono,#shipit-modal .mono` rule mid-file.) */
2340
+
2341
+ /* Section tabs (§5.5 + C12). WITHOUT these rules the pill row renders as three
2342
+ unstyled native buttons and nothing pins on scroll. Twin of
2343
+ `.hd-tabs`/`.hd-tab`/`.hd-tab-badge`/`.hd-sec`; `.run-screen-detail` keeps
2344
+ `padding:0` precisely so `top:0` pins flush to the scrollport (D12).
2345
+ NO horizontal margin, deliberately: both hosts live INSIDE `.rd-body`, which
2346
+ carries `padding:0 32px 40px` — the exact shape of `.hd-body` and `.hd-tabs`,
2347
+ which carries no margin for precisely this reason. Adding `margin:0 32px` here
2348
+ would double the inset to 64px AND stop the pinned bar's `background:var(--bg)`
2349
+ 32px short on each side, so scrolled content would show through the gutters
2350
+ behind it. */
2351
+ .rd-tabs{position:sticky;top:0;z-index:5;display:flex;align-items:center;flex-wrap:wrap;gap:8px;
2352
+ padding:18px 0 14px;background:var(--bg);}
2353
+ .rd-tab{display:flex;align-items:center;gap:9px;padding:10px 17px;border:1.5px solid var(--line);
2354
+ border-radius:999px;background:var(--panel);font:600 13.5px var(--sans);color:var(--ink-2);cursor:pointer;}
2355
+ .rd-tab:hover{border-color:var(--ink-3);color:var(--ink);}
2356
+ .rd-tab.active{background:var(--ink);color:#fff;border-color:var(--ink);}
2357
+ .rd-tab:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2358
+ .rd-tab-badge{padding:2px 8px;border-radius:999px;background:var(--field);color:var(--ink-3);
2359
+ font:600 10.5px var(--mono);}
2360
+ .rd-tab.active .rd-tab-badge{background:var(--blue-bg);color:var(--blue-ink);}
2361
+ /* .rd-sections needs no rule of its own — the inset comes from .rd-body's
2362
+ padding, exactly as .hd-sections does. */
2363
+ .rd-sec{margin-top:4px;}
2364
+ /* Explicit twin, exactly as `.hd-sec[hidden]`: the UA [hidden] rule is (0,0,0)
2365
+ and loses to any author `display`, so the moment a `.rd-sec-*` body gets one,
2366
+ every inactive panel would render at once. */
2367
+ .rd-sec[hidden]{display:none;}
2368
+ .rd-sec:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2369
+
2370
+ /* Live log tab (§5.6): white pane, --line border, 16px radius, bounded height.
2371
+ The pane is the shared `.log` markup inside a `.run-log` block, so `.run-log .log`
2372
+ is (0,2,0) and so is this — source order is what makes it win, which is why the
2373
+ rule lives at the END of the file and must not be moved above it. */
2374
+ .rd-sec-logs .log{min-height:300px;max-height:520px;
2375
+ background:var(--panel);border:1px solid var(--line);border-radius:16px;}
2376
+ /* §9's fourth keyframe: the blinking green caret at the tail of a LIVE log.
2377
+ CSS-only (a ::after on the pane) so no JS has to keep an element last after
2378
+ every append; Task 9 stamps `.rd-terminal` on the screen when the run ends and
2379
+ the caret disappears — "the log stops growing" (D8). */
2380
+ .rd-sec-logs .log::after{content:'';display:inline-block;width:7px;height:13px;
2381
+ vertical-align:-2px;margin-left:2px;background:var(--green);
2382
+ animation:wr-blink 1.05s step-end infinite;}
2383
+ /* Descendant form on purpose: Task 9 stamps `.rd-terminal` on the SCREEN
2384
+ (`screen.classList.toggle('rd-terminal', terminal)`), which is an ancestor of
2385
+ `.rd-sec-logs` — do not "fix" this to `.rd-terminal.rd-sec-logs`. */
2386
+ .rd-terminal .rd-sec-logs .log::after{display:none;}
2387
+ /* The pane's OTHER empty state: a live run whose filter matches none of its
2388
+ lines. A caret blinking after "(no lines match the filter)" reads as a tail
2389
+ about to print. Keyed on `data-empty` and not on emptiness in general —
2390
+ rdRepaintLog stamps it only when r.logLines is non-empty, so a fresh live run
2391
+ with zero lines correctly keeps its caret. */
2392
+ .rd-sec-logs .log[data-empty]::after{display:none;}
2393
+
2394
+ /* Overview tab (§5.7). The stat cards, the task card and the chips deliberately
2395
+ reuse History's `.hd-ov-*` rules — hdStatCard emits those class names, so
2396
+ re-declaring them here would fork one card design into two. Only the
2397
+ current-state banner is new. */
2398
+ .rd-ov-state{display:flex;align-items:center;flex-wrap:wrap;gap:12px;padding:16px 20px;
2399
+ background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);}
2400
+ .rd-ov-chip{padding:5px 12px;border-radius:999px;font:600 11.5px var(--sans);
2401
+ background:var(--field);color:var(--ink-2);}
2402
+ .rd-ov-chip.st-blue{background:var(--blue-bg);color:var(--blue-ink);}
2403
+ .rd-ov-chip.st-amber{background:var(--amber-bg);color:var(--amber-ink);}
2404
+ .rd-ov-chip.st-green{background:var(--green-bg);color:var(--green-ink);}
2405
+ .rd-ov-chip.st-red{background:var(--red-bg);color:var(--red-ink);}
2406
+ .rd-ov-copy{min-width:0;font:400 13px var(--sans);color:var(--ink-2);}
2407
+
2408
+ /* Agents tab (§5.8). History's card shell, but the spec's four-column GRID row
2409
+ instead of its flex row — which is why these carry their own class names
2410
+ rather than extending `.hd-ag-*`. */
2411
+ .rd-ag-group{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;}
2412
+ .rd-ag-group + .rd-ag-group{margin-top:14px;}
2413
+ .rd-ag-head{display:flex;align-items:center;flex-wrap:wrap;gap:12px;padding:15px 20px;
2414
+ border-bottom:1px solid var(--line);}
2415
+ .rd-ag-head b{font-size:13.5px;font-weight:600;letter-spacing:-.01em;}
2416
+ .rd-ag-meta{color:var(--ink-3);font-size:11.5px;margin-left:auto;}
2417
+ .rd-ag-none{padding:12px 20px;}
2418
+ .rd-ag-row{display:grid;grid-template-columns:1fr 130px 96px 84px;align-items:center;gap:10px;
2419
+ padding:12px 20px;border-top:1px solid var(--line);}
2420
+ /* NOT `:first-of-type` — `.rd-ag-head` is the first div in the card, so no row
2421
+ would ever match it (the same trap the `.hd-ag-head + .hd-ag-row` rule
2422
+ documents). */
2423
+ .rd-ag-head + .rd-ag-row{border-top:none;}
2424
+ .rd-ag-name{display:flex;align-items:center;gap:9px;min-width:0;font:500 13px var(--sans);color:var(--ink);}
2425
+ .rd-ag-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
2426
+ .rd-ag-dot{width:7px;height:7px;border-radius:50%;flex:0 0 auto;background:var(--ink-3);}
2427
+ .rd-ag-dot.run{background:var(--blue);animation:wr-pulse 1.6s ease-in-out infinite;}
2428
+ .rd-ag-dot.done{background:var(--green);}
2429
+ .rd-ag-dot.stop{background:var(--red);}
2430
+ .rd-ag-state{font:500 12px var(--sans);}
2431
+ .rd-ag-state.run{color:var(--blue-ink);}
2432
+ .rd-ag-state.done{color:var(--green-ink);}
2433
+ .rd-ag-state.stop{color:var(--red-ink);}
2434
+ .rd-ag-dur,.rd-ag-cost{text-align:right;font-size:11.5px;color:var(--ink-2);}
2435
+ /* skillPillsHtml emits `.subs-skills` into the head AND every row; in a grid row
2436
+ it must claim a full line of its own, the grid twin of the flex rule above. */
2437
+ .rd-ag-row .subs-skills{grid-column:1/-1;margin-top:6px;}
2438
+ /* AFTER the rules it neutralizes — source order, not specificity, is what makes
2439
+ this win in this stylesheet. */
2440
+ @media (prefers-reduced-motion: reduce){
2441
+ .rd-ag-dot.run{animation:none;}
2442
+ .rd-sec-logs .log::after{animation:none;}
2443
+ }
2444
+
2445
+ /* ---------- Running detail: terminal state (D8) ---------- */
2446
+ /* NOTE: `.rd-status.parked .pdot{animation:none;}` is NOT repeated here — the
2447
+ header CSS already ships it (its (0,3,0) beats `.pill-run .pdot`), and a second
2448
+ copy would only make the sweep noisier. This task adds the class. */
2449
+
2450
+ /* A finished run stops moving. `runStepperView` only nulls activeId when the
2451
+ status is exactly 'done', so a STOPPED or ERRORED run's frontier node can still
2452
+ be `now` and its wire would march forever. Neutralize the three motions the
2453
+ graph carries rather than fighting the adapter.
2454
+ VERIFIED selector shapes at HEAD: nodes carry BOTH `node` and `run-node`
2455
+ (`.run-flow .node.run-node`), the glow rule is `.run-flow .node.is-active`, the
2456
+ wire rule is `.run-flow .wires path.wire-live` and the fan rule is
2457
+ `.run-flow .node .fan .sq.on`. Each override below is one class deeper than the
2458
+ rule it beats, so it wins on specificity, not source order. */
2459
+ .rd-graph.settled .run-flow .wires path.wire-live{animation:none;}
2460
+ /* Belt-and-braces: `runStatusOf` already returns 'stopped'/'done' for every node
2461
+ once the run is halted, so a terminal graph carries no `.is-active` — these two
2462
+ are no-ops today and exist only so a future adapter change cannot resurrect the
2463
+ glow. `.is-paused` is included because a run halted while parked keeps
2464
+ `nodeStatus === 'pause'`. */
2465
+ .rd-graph.settled .run-flow .run-node.is-active{animation:none;}
2466
+ .rd-graph.settled .run-flow .run-node.is-paused{animation:none;}
2467
+ .rd-graph.settled .run-flow .run-node .fan .sq.on{animation:none;}
2468
+
2469
+ .rd-history-link{flex:0 0 auto;font:600 12.5px var(--sans);color:var(--blue-ink);text-decoration:none;}
2470
+ .rd-history-link:hover{text-decoration:underline;}
2471
+ .rd-history-link[hidden]{display:none;}
2472
+ .rd-history-link:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2473
+
2474
+ /* ---------- "Stop this pipeline?" confirm modal (design §6) ---------- */
2475
+ /* WIDTH GOES ON `#stop-modal .card`, NOT `.stop-card`. The markup is
2476
+ `<div class="card stop-card">` inside `.viewer-modal`, and
2477
+ `.viewer-modal .card{width:min(860px,100%);…}` (:786) is (0,2,0): a bare
2478
+ `.stop-card{width:…}` (0,1,0) loses no matter where it is appended. Exact
2479
+ precedent: `#shipit-modal .card` (:1864). */
2480
+ #stop-modal .card{width:min(560px,100%);}
2481
+ .stop-card{padding:24px;animation:wr-rise .28s cubic-bezier(.2,.7,.3,1) both;}
2482
+ .stop-title{margin:0 0 12px;font:700 17px/1.25 var(--sans);letter-spacing:-.015em;}
2483
+ .stop-body{margin:0;font:400 13.5px/1.6 var(--sans);color:var(--ink-2);}
2484
+ .stop-ident{margin-top:14px;padding:11px 13px;background:var(--field);border-radius:14px;
2485
+ font:400 12px/1.6 var(--mono);color:var(--ink-2);word-break:break-all;}
2486
+ /* author display rule beats the UA [hidden] rule — a branch-less run must not
2487
+ leave a blank mono line in the block */
2488
+ .stop-ident-branch[hidden]{display:none;}
2489
+ .stop-err{margin-top:12px;}
2490
+ /* MANDATORY twin: the node is `class="hint err" hidden` and `.hint` (:285) sets
2491
+ display:block, which always beats the UA `[hidden]{display:none}`. Same as
2492
+ `.shipit-err[hidden]` (:1896). */
2493
+ .stop-err[hidden]{display:none;}
2494
+ .stop-actions{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin-top:22px;}
2495
+ .stop-cancel{padding:11px 20px;border:1.5px solid var(--line-2);border-radius:999px;
2496
+ background:var(--panel);font:600 13.5px var(--sans);color:var(--ink);cursor:pointer;}
2497
+ .stop-cancel:hover{background:var(--field);}
2498
+ .stop-confirm{padding:11px 20px;border:1.5px solid transparent;border-radius:999px;
2499
+ background:var(--red-bg);font:600 13.5px var(--sans);color:var(--red-ink);cursor:pointer;}
2500
+ /* The mockup's hover is #F7D2CD — a shade §9 does not name and no token carries.
2501
+ brightness() keeps the darker-on-hover intent inside the existing palette (and
2502
+ out of Task 12's "one occurrence per new literal" assertion). */
2503
+ .stop-confirm:hover{filter:brightness(.97);}
2504
+ .stop-confirm:disabled{opacity:.6;cursor:default;}
2505
+ .stop-cancel:focus-visible,.stop-confirm:focus-visible{outline:2px solid var(--ink);outline-offset:2px;}
2506
+
2507
+ /* ---------- reduced motion for the Running redesign ---------- */
2508
+ /* MUST be the LAST block in the file: @media contributes no specificity, so a
2509
+ (0,1,0) `animation:none` here would LOSE the source-order tie against any
2510
+ `animation:wr-*` rule appended after it — exactly the trap documented at
2511
+ :748-763 for the four legacy names and at :1927-1940 for the ship-it set. */
2512
+ @media (prefers-reduced-motion: reduce){
2513
+ /* #stop-modal is a top-level overlay, outside the shell — named explicitly. */
2514
+ #stop-modal .card{animation:none;}
2515
+ /* PSEUDO-ELEMENTS DO NOT INHERIT `animation`, so the `*` blanket below cannot
2516
+ reach the live-log caret — it has to be named. (Task 7's own reduced-motion
2517
+ block already carries this rule; the duplicate here is deliberate belt-and-
2518
+ braces, because this block is the one guaranteed to be last.) */
2519
+ .rd-sec-logs .log::after{animation:none;}
2520
+ /* One scoped blanket for every ELEMENT inside the two Running screens: the
2521
+ status avatar spinner, the pulsing status/agent accent dots and the question
2522
+ panel's rise. `!important` (like the `*{transition:none !important}` rule in
2523
+ the legacy block) because enumerating them would restate selectors owned by
2524
+ Tasks 3/6/7/8 and silently rot the day one of them is renamed. The run-graph's
2525
+ own reduced-motion block (:1253-1258) is unaffected — it substitutes
2526
+ box-shadows, and only its redundant `animation:none` is overridden. */
2527
+ .run-shell *{animation:none !important;}
2528
+ }