prreviewbuddy 0.46.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/static/shell.css CHANGED
@@ -4,9 +4,11 @@
4
4
  * content itself. This file owns only the full-page furniture that a 460px column beside a GitHub
5
5
  * diff never needed: the rail, the document pane, the assistant.
6
6
  *
7
- * The light/dark split is structural, not decorative. Dark is the operator's furniture — where you
8
- * navigate and where you ask. Light is the review document. Moving between them tells you whether
9
- * you are reading the review or working the tool. */
7
+ * The split between furniture and document is structural, not decorative. The furniture is where
8
+ * you navigate and where you ask; the document is the review. Moving between them tells you whether
9
+ * you are reading the review or working the tool. In the dark theme the split is dark against light.
10
+ * In the light theme it is grey chrome around a white document, and the document stays the
11
+ * brightest thing on the screen. The document pane is light in both: its palette is `.prb-doc`'s. */
10
12
 
11
13
  @font-face {
12
14
  font-family: 'Comfortaa';
@@ -16,33 +18,92 @@
16
18
  }
17
19
 
18
20
  :root {
19
- --bg: #0b0f17;
20
- --surface: #121826;
21
- --surface-2: #1b2232;
21
+ /* ── The theme ──
22
+ `data-theme` on <html> is rendered by the server from the reviewer's choice (see theme.ts).
23
+ System leaves both schemes open, and the browser picks from the device, live. */
24
+ color-scheme: light dark;
25
+
26
+ /* Every colour the furniture uses is one of these, and each is a `light-dark(light, dark)` pair
27
+ that the browser resolves from `color-scheme`. That is what lets System follow the device with
28
+ no listener and no reload, and what keeps both themes in one table rather than two that drift.
29
+ A furniture rule names a token and never a colour: shell_theme.test.ts holds that line, so a
30
+ new shade has to be added here, beside its other half, or not at all.
31
+
32
+ Light values are held to 4.5:1 for every piece of informational text on the palest surface it
33
+ sits on (shell_theme.test.ts computes it). That is why muted is darker than a light theme's
34
+ usual grey, and secondary darker again, so the three steps still read as three. */
35
+ --bg: light-dark(#f3f4f7, #0b0f17);
36
+ --surface: light-dark(#f8f9fb, #121826);
37
+ /* Cards, menus, dialogs and the bulk bar: the things that sit on top. One value with --surface in
38
+ the dark theme; white in the light one, which is what makes a card read as lifted off the grey. */
39
+ --surface-raised: light-dark(#ffffff, #121826);
40
+ --surface-2: light-dark(#eceef2, #1b2232);
41
+ /* A row under the pointer in the rail. The dark theme lifts it to --surface; the light theme
42
+ darkens it, because a paler row on a pale rail is invisible. */
43
+ --surface-hover: light-dark(#e8ebef, #121826);
22
44
  --brand: #9333ea;
23
- --brand-hover: #7c3aed;
24
- --brand-muted: rgba(147, 51, 234, 0.15);
25
- --text-primary: #f8fafc;
26
- --text-secondary: #94a3b8;
27
- --text-muted: #64748b;
28
- --border: rgba(255, 255, 255, 0.08);
45
+ --brand-hover: light-dark(#7427e8, #7c3aed);
46
+ --brand-muted: light-dark(#f3e8ff, rgba(147, 51, 234, 0.15));
47
+ /* Brand-coloured words on a light or tinted ground, where #9333ea itself is too pale to read. */
48
+ --brand-ink: light-dark(#6b21a8, #c4a5f5);
49
+ /* Text and marks on a filled --brand control. White in both, because the fill is the same. */
50
+ --on-brand: #ffffff;
51
+ --on-brand-quiet: rgba(255, 255, 255, 0.8);
52
+ --text-primary: light-dark(#20242a, #f8fafc);
53
+ --text-secondary: light-dark(#4b5462, #94a3b8);
54
+ --text-muted: light-dark(#626b79, #64748b);
55
+ --link: light-dark(#7e22ce, #c4b5fd);
56
+ --border: light-dark(#e2e5ea, rgba(255, 255, 255, 0.08));
29
57
  /* Hover used to reach for the brand. Purple then marked the row you happened to be over as
30
58
  loudly as the row you had chosen, so it stopped meaning "chosen". Hover gets a brighter
31
59
  neutral; purple keeps focus, selection and the primary action. */
32
- --border-strong: rgba(255, 255, 255, 0.22);
33
- --danger: #f87171;
34
- --warning: #fbbf24;
35
- --success: #4ade80;
36
- --wordmark-accent:#a855f7;
60
+ --border-strong: light-dark(#c9ced6, rgba(255, 255, 255, 0.22));
61
+ /* A faint wash for a row under the pointer, or the row you are on, over whatever is behind it. */
62
+ --wash: light-dark(rgba(15, 23, 42, 0.04), rgba(255, 255, 255, 0.04));
63
+ --wash-strong: light-dark(rgba(15, 23, 42, 0.06), rgba(255, 255, 255, 0.06));
64
+ --backdrop: light-dark(rgba(15, 23, 42, 0.32), rgba(2, 6, 23, 0.55));
65
+ --shadow-soft: light-dark(rgba(15, 23, 42, 0.08), rgba(0, 0, 0, 0.12));
66
+ --shadow-float: light-dark(rgba(15, 23, 42, 0.14), rgba(0, 0, 0, 0.36));
67
+ --bg-elevated: light-dark(#ffffff, #1f1f24);
68
+
69
+ /* Status. The bare name is a mark or a word on a plain surface; -subtle is a tinted ground;
70
+ -ink is the word written on that ground; -border outlines it. */
71
+ --danger: light-dark(#c12c35, #f87171);
72
+ --danger-subtle: light-dark(#fdedee, rgba(207, 34, 46, 0.16));
73
+ --danger-ink: light-dark(#a40e26, #ff9b9b);
74
+ --danger-ink-strong: light-dark(#86061d, #ffb3b3);
75
+ --danger-border: light-dark(rgba(193, 44, 53, 0.45), rgba(207, 34, 46, 0.55));
76
+ /* The notice that says the server has stopped: a solid band, not a tint. */
77
+ --danger-band: light-dark(#fdedee, #4a1d1d);
78
+ --danger-band-ink:light-dark(#7a1f26, #ffd9d9);
79
+ --warning: light-dark(#8a5c00, #fbbf24);
80
+ --warning-subtle: light-dark(#fff5d6, rgba(210, 153, 34, 0.16));
81
+ --warning-ink: light-dark(#7a5200, #ffd18a);
82
+ --warning-wash: light-dark(rgba(212, 167, 44, 0.16), rgba(251, 191, 36, 0.1));
83
+ --warning-wash-faint: light-dark(rgba(212, 167, 44, 0.03), rgba(251, 191, 36, 0.02));
84
+ --success: light-dark(#13733a, #4ade80);
85
+ --success-subtle: light-dark(#eaf8ef, rgba(46, 160, 67, 0.14));
86
+ --success-ink: light-dark(#116329, #7ee2a8);
87
+ --success-border: light-dark(rgba(19, 115, 58, 0.4), rgba(46, 160, 67, 0.55));
88
+ --neutral-subtle: light-dark(rgba(15, 23, 42, 0.06), rgba(139, 148, 158, 0.16));
89
+ --merged-subtle: light-dark(#f3e8ff, rgba(163, 113, 247, 0.18));
90
+ --merged-ink: light-dark(#6b21a8, #d2a8ff);
91
+ --unread-wash: light-dark(rgba(147, 51, 234, 0.06), rgba(139, 92, 246, 0.09));
92
+ /* The three attention dots in the rail. Marks, not words, so 3:1 is their bar. */
93
+ --attention-high: light-dark(#c12c35, #f87171);
94
+ --attention-medium: light-dark(#c28a00, #f0b232);
95
+ --attention-low: light-dark(#aab1bc, #475569);
96
+
97
+ --wordmark-accent:light-dark(#7e22ce, #a855f7);
37
98
  --wordmark-ink: var(--text-primary);
38
99
 
39
100
  /* Scrollbars, in the brand's purple rather than the OS grey, and one pair per surface.
40
- The shell is near-black and the document pane is near-white, so a single colour cannot serve
41
- both: the lighter `#a855f7` is what stays legible on the dark furniture, and the deeper
42
- `#9333ea` is what has contrast against the pane. Named by surface so putting one on the wrong
43
- side reads as a mistake at the call site. */
44
- --scroll-shell: rgba(168, 85, 247, 0.45);
45
- --scroll-shell-hover: rgba(168, 85, 247, 0.75);
101
+ The dark furniture is near-black and the document pane is near-white, so one colour cannot
102
+ serve both: the lighter `#a855f7` is what stays legible on dark, and the deeper `#9333ea` is
103
+ what has contrast against light, which in the light theme is the furniture too. Named by
104
+ surface so putting one on the wrong side reads as a mistake at the call site. */
105
+ --scroll-shell: light-dark(rgba(147, 51, 234, 0.32), rgba(168, 85, 247, 0.45));
106
+ --scroll-shell-hover: light-dark(rgba(147, 51, 234, 0.58), rgba(168, 85, 247, 0.75));
46
107
  --scroll-pane: rgba(147, 51, 234, 0.32);
47
108
  --scroll-pane-hover: rgba(147, 51, 234, 0.58);
48
109
  --scroll-width: 8px;
@@ -102,6 +163,10 @@
102
163
  --strip-height: 36px;
103
164
  }
104
165
 
166
+ /* A stated theme pins the scheme, so the device no longer decides. */
167
+ :root[data-theme='light'] { color-scheme: light; }
168
+ :root[data-theme='dark'] { color-scheme: dark; }
169
+
105
170
  * { box-sizing: border-box; }
106
171
 
107
172
  html, body {
@@ -500,11 +565,11 @@ body[data-restarting] .prb-body { opacity: 0.55; pointer-events: none; }
500
565
  padding: 22px 24px;
501
566
  border: 1px solid var(--border);
502
567
  border-radius: 12px;
503
- background: var(--surface);
568
+ background: var(--surface-raised);
504
569
  color: var(--text-primary);
505
570
  font: inherit;
506
571
  }
507
- .prb-dialog::backdrop { background: rgba(2, 6, 23, 0.55); }
572
+ .prb-dialog::backdrop { background: var(--backdrop); }
508
573
  .prb-dialog h2 { margin: 0 0 10px; font-size: var(--t-section); }
509
574
  .prb-dialog p { margin: 0 0 10px; font-size: var(--t-body); line-height: var(--lh-body); color: var(--text-secondary); }
510
575
  .prb-dialog-reassure { color: var(--text-tertiary, var(--text-secondary)); }
@@ -523,9 +588,9 @@ body[data-restarting] .prb-body { opacity: 0.55; pointer-events: none; }
523
588
  .prb-dialog-actions button:hover { border-color: var(--border-strong); }
524
589
  /* The destructive action is the one that gets the colour; the way out stays quiet. */
525
590
  .prb-dialog-danger {
526
- border-color: rgba(207, 34, 46, 0.55) !important;
527
- background: rgba(207, 34, 46, 0.14) !important;
528
- color: #ff9b9b !important;
591
+ border-color: var(--danger-border) !important;
592
+ background: var(--danger-subtle) !important;
593
+ color: var(--danger-ink) !important;
529
594
  }
530
595
  .prb-dialog-danger:disabled { opacity: 0.6; cursor: default; }
531
596
 
@@ -536,8 +601,8 @@ body[data-restarting] .prb-body { opacity: 0.55; pointer-events: none; }
536
601
  top: 0;
537
602
  z-index: 20;
538
603
  padding: 10px 18px;
539
- background: #4a1d1d;
540
- color: #ffd9d9;
604
+ background: var(--danger-band);
605
+ color: var(--danger-band-ink);
541
606
  font-size: var(--t-meta);
542
607
  }
543
608
  body[data-server-stopped] .prb-body,
@@ -834,7 +899,7 @@ a.prb-rail-item { text-decoration: none; }
834
899
  cursor: pointer;
835
900
  }
836
901
  .prb-rail-subhead .prb-rail-heading { flex: 1; }
837
- .prb-rail-subhead:hover { background: var(--surface); }
902
+ .prb-rail-subhead:hover { background: var(--surface-hover); }
838
903
  .prb-rail-subhead:hover .prb-rail-heading,
839
904
  .prb-rail-subhead:hover .prb-rail-twisty { color: var(--text-primary); }
840
905
  .prb-rail-subhead:focus-visible { outline: 2px solid var(--brand-hover); outline-offset: -2px; }
@@ -875,7 +940,7 @@ a.prb-rail-item { text-decoration: none; }
875
940
  color: var(--text-secondary);
876
941
  cursor: pointer;
877
942
  }
878
- .prb-rail-item:hover { background: var(--surface); color: var(--text-primary); }
943
+ .prb-rail-item:hover { background: var(--surface-hover); color: var(--text-primary); }
879
944
  .prb-rail-item[aria-current='true'] {
880
945
  background: var(--brand-muted);
881
946
  border-left-color: var(--brand);
@@ -953,7 +1018,7 @@ a.prb-rail-item { text-decoration: none; }
953
1018
  * over the ones still open beside it.
954
1019
  */
955
1020
  .prb-rail-count-done {
956
- color: #4ade80;
1021
+ color: var(--success);
957
1022
  font-weight: 700;
958
1023
  }
959
1024
 
@@ -966,9 +1031,9 @@ a.prb-rail-item { text-decoration: none; }
966
1031
  align-self: center;
967
1032
  background: var(--text-muted);
968
1033
  }
969
- .prb-attention[data-attention='high'] { background: #f87171; }
970
- .prb-attention[data-attention='medium'] { background: #f0b232; }
971
- .prb-attention[data-attention='low'] { background: #475569; }
1034
+ .prb-attention[data-attention='high'] { background: var(--attention-high); }
1035
+ .prb-attention[data-attention='medium'] { background: var(--attention-medium); }
1036
+ .prb-attention[data-attention='low'] { background: var(--attention-low); }
972
1037
 
973
1038
  /* ── Document pane ──
974
1039
  Wrapped in .pr-helper-sidebar so every reused component finds the pill tokens and the type
@@ -1004,6 +1069,10 @@ a.prb-rail-item { text-decoration: none; }
1004
1069
  --pane-warning: #9a6700;
1005
1070
  --pane-success: #1a7f37;
1006
1071
 
1072
+ /* Light in both themes, and native controls in here with it. Without this the dark theme's
1073
+ `color-scheme` would draw this pane's inputs, checkboxes and selects dark on a white page. */
1074
+ color-scheme: light;
1075
+
1007
1076
  overflow-y: auto;
1008
1077
  background: var(--pane-bg);
1009
1078
  }
@@ -1597,7 +1666,7 @@ a.prb-rail-item { text-decoration: none; }
1597
1666
  .prb-dialog-primary {
1598
1667
  border-color: var(--brand) !important;
1599
1668
  background: var(--brand) !important;
1600
- color: #ffffff !important;
1669
+ color: var(--on-brand) !important;
1601
1670
  }
1602
1671
 
1603
1672
  .prb-msg { font-size: var(--t-body); line-height: var(--lh-body); }
@@ -1614,7 +1683,7 @@ a.prb-rail-item { text-decoration: none; }
1614
1683
  padding: 8px 12px;
1615
1684
  border-radius: 12px 12px 2px 12px;
1616
1685
  background: var(--brand);
1617
- color: #fff;
1686
+ color: var(--on-brand);
1618
1687
  }
1619
1688
  .prb-msg-assistant {
1620
1689
  color: var(--text-secondary);
@@ -1648,7 +1717,7 @@ a.prb-rail-item { text-decoration: none; }
1648
1717
  .prb-md li + li { margin-top: 4px; }
1649
1718
  .prb-md strong { color: var(--text-primary); font-weight: 600; }
1650
1719
  /* A lighter purple than --brand, which is a fill colour and reads as near-black text on this pane. */
1651
- .prb-md a { color: #c4b5fd; }
1720
+ .prb-md a { color: var(--link); }
1652
1721
  .prb-md blockquote {
1653
1722
  margin: 0 0 10px;
1654
1723
  padding-left: 10px;
@@ -1682,8 +1751,8 @@ a.prb-rail-item { text-decoration: none; }
1682
1751
  color: var(--text-secondary);
1683
1752
  }
1684
1753
  .prb-md .pr-helper-code-copy:hover {
1685
- border-color: #c4b5fd;
1686
- color: #c4b5fd;
1754
+ border-color: var(--link);
1755
+ color: var(--link);
1687
1756
  }
1688
1757
  .prb-md .pr-helper-code-copy.copied {
1689
1758
  border-color: var(--success);
@@ -1723,7 +1792,7 @@ a.prb-rail-item { text-decoration: none; }
1723
1792
 
1724
1793
  .prb-md .pr-helper-msg-copy:hover {
1725
1794
  opacity: 1;
1726
- color: #c4b5fd;
1795
+ color: var(--link);
1727
1796
  }
1728
1797
 
1729
1798
  .prb-md .pr-helper-msg-copy.copied {
@@ -1793,7 +1862,7 @@ a.prb-rail-item { text-decoration: none; }
1793
1862
  border-radius: 8px;
1794
1863
  border: 0;
1795
1864
  background: var(--brand);
1796
- color: #fff;
1865
+ color: var(--on-brand);
1797
1866
  font: inherit;
1798
1867
  font-weight: 600;
1799
1868
  cursor: pointer;
@@ -2007,7 +2076,7 @@ a.prb-rail-item { text-decoration: none; }
2007
2076
  that is already carrying the state. */
2008
2077
  .prb-fresh[data-state='changed'] {
2009
2078
  border-left-color: var(--warning);
2010
- background: linear-gradient(90deg, rgba(251, 191, 36, 0.1), transparent 360px);
2079
+ background: linear-gradient(90deg, var(--warning-wash), transparent 360px);
2011
2080
  }
2012
2081
  /* No reading measure on the panel's children.
2013
2082
  A 78ch cap was here to stop prose running to 110ch on a wide screen, and it cost more than it
@@ -2145,7 +2214,7 @@ a.prb-rail-item { text-decoration: none; }
2145
2214
  padding: 12px 18px;
2146
2215
  border-bottom: 1px solid var(--border);
2147
2216
  border-left: 3px solid var(--warning);
2148
- background: linear-gradient(90deg, rgba(251, 191, 36, 0.09), rgba(251, 191, 36, 0.02));
2217
+ background: linear-gradient(90deg, var(--warning-wash), var(--warning-wash-faint));
2149
2218
  font-size: var(--t-meta);
2150
2219
  line-height: var(--lh-body);
2151
2220
  }
@@ -2194,7 +2263,7 @@ a.prb-rail-item { text-decoration: none; }
2194
2263
  }
2195
2264
  /* The row the reader is standing on, marked rather than moved, so the list stays a timeline. Its
2196
2265
  own faint ground says "here" without competing with the row they are being sent to. */
2197
- .prb-lineage-row[data-current] { background: rgba(255, 255, 255, 0.04); }
2266
+ .prb-lineage-row[data-current] { background: var(--wash); }
2198
2267
  .prb-lineage-name { flex: none; font-weight: 400; color: var(--text-primary); }
2199
2268
  .prb-lineage-here,
2200
2269
  .prb-lineage-latest {
@@ -2206,7 +2275,7 @@ a.prb-rail-item { text-decoration: none; }
2206
2275
  letter-spacing: 0.03em;
2207
2276
  text-transform: uppercase;
2208
2277
  }
2209
- .prb-lineage-latest { background: var(--brand); color: #fff; }
2278
+ .prb-lineage-latest { background: var(--brand); color: var(--on-brand); }
2210
2279
  /* Outlined, not filled: it names where the reader already is, which is the one row on this list
2211
2280
  they have no reason to click. */
2212
2281
  .prb-lineage-here { border: 1px solid var(--border); color: var(--text-muted); font-weight: 400; }
@@ -2232,9 +2301,9 @@ a.prb-rail-item { text-decoration: none; }
2232
2301
  text-transform: uppercase;
2233
2302
  white-space: nowrap;
2234
2303
  }
2235
- .prb-lineage-risk[data-risk="high"] { background: rgba(207, 34, 46, 0.16); color: #ff9b9b; }
2236
- .prb-lineage-risk[data-risk="medium"] { background: rgba(210, 153, 34, 0.16); color: #ffd18a; }
2237
- .prb-lineage-risk[data-risk="low"] { background: rgba(46, 160, 67, 0.14); color: #7ee2a8; }
2304
+ .prb-lineage-risk[data-risk="high"] { background: var(--danger-subtle); color: var(--danger-ink); }
2305
+ .prb-lineage-risk[data-risk="medium"] { background: var(--warning-subtle); color: var(--warning-ink); }
2306
+ .prb-lineage-risk[data-risk="low"] { background: var(--success-subtle); color: var(--success-ink); }
2238
2307
  .prb-lineage-open {
2239
2308
  flex: none;
2240
2309
  margin-left: auto;
@@ -2262,13 +2331,13 @@ a.prb-rail-item { text-decoration: none; }
2262
2331
  border: 1px solid var(--brand);
2263
2332
  border-radius: 7px;
2264
2333
  background: var(--brand);
2265
- color: #fff;
2334
+ color: var(--on-brand);
2266
2335
  font: inherit;
2267
2336
  font-size: var(--t-meta);
2268
2337
  font-weight: 600;
2269
2338
  cursor: pointer;
2270
2339
  }
2271
- .prb-update-btn:hover:not(:disabled) { filter: brightness(1.08); color: #fff; }
2340
+ .prb-update-btn:hover:not(:disabled) { filter: brightness(1.08); color: var(--on-brand); }
2272
2341
  .prb-update-btn:disabled { opacity: 0.55; cursor: default; }
2273
2342
 
2274
2343
  /* The two disclosures on the controls line, styled as one thing because they are peers: a quiet
@@ -2482,7 +2551,7 @@ a.prb-rail-item { text-decoration: none; }
2482
2551
  color: #1f2328;
2483
2552
  cursor: pointer;
2484
2553
  }
2485
- .prb-progress-open:hover { border-color: var(--border-strong); color: var(--text-primary); }
2554
+ .prb-progress-open:hover { border-color: rgba(15, 23, 42, 0.3); color: var(--pane-ink); }
2486
2555
 
2487
2556
  .prb-progress-elapsed {
2488
2557
  margin: 20px 0 0;
@@ -2504,7 +2573,7 @@ a.prb-rail-item { text-decoration: none; }
2504
2573
  background: #ffffff;
2505
2574
  color: #1f2328;
2506
2575
  }
2507
- .prb-progress-failure .prb-job-retry:hover { border-color: var(--border-strong); color: var(--text-primary); }
2576
+ .prb-progress-failure .prb-job-retry:hover { border-color: rgba(15, 23, 42, 0.3); color: var(--pane-ink); }
2508
2577
 
2509
2578
  /* ── Responsive ──
2510
2579
  The assistant is the first thing to fold, then the rail. The review document never folds; it is
@@ -2642,7 +2711,7 @@ a.prb-rail-item { text-decoration: none; }
2642
2711
  font-size: var(--t-micro);
2643
2712
  cursor: pointer;
2644
2713
  }
2645
- .prb-code-open:hover { border-color: var(--border-strong); color: var(--text-primary); }
2714
+ .prb-code-open:hover { border-color: rgba(15, 23, 42, 0.3); color: var(--pane-ink); }
2646
2715
  /* Only the first of the two pushes right; the second sits beside it. */
2647
2716
  .prb-code-open ~ .prb-code-open { margin-left: 0; }
2648
2717
  /* Blue, the colour every route out to the pull request uses, so the two buttons read as two
@@ -2787,7 +2856,7 @@ a.prb-rail-item { text-decoration: none; }
2787
2856
  text-align: left;
2788
2857
  }
2789
2858
  .prb-code-more { cursor: pointer; }
2790
- .prb-code-more:hover { color: var(--text-primary); }
2859
+ .prb-code-more:hover { color: var(--pane-ink); }
2791
2860
 
2792
2861
  /* A file row and a citation both open code now, so both have to look like they will. */
2793
2862
  .prb-pane .pr-helper-guide-file { cursor: pointer; }
@@ -2904,7 +2973,7 @@ a.prb-rail-item { text-decoration: none; }
2904
2973
  .prb-index-select[aria-pressed="true"] {
2905
2974
  border-color: var(--brand);
2906
2975
  background: var(--brand);
2907
- color: #ffffff;
2976
+ color: var(--on-brand);
2908
2977
  }
2909
2978
 
2910
2979
  /* Wraps, so a narrow window gives the search its own line and puts the filters beneath it rather
@@ -2944,7 +3013,7 @@ a.prb-rail-item { text-decoration: none; }
2944
3013
  .prb-index-author:hover { border-color: var(--border-strong); }
2945
3014
  .prb-index-author:focus-visible { outline: none; border-color: var(--brand); }
2946
3015
  /* Filled like a pressed pill once it narrows the list, so a filtered view is never mistaken for all of it. */
2947
- .prb-index-author[data-active] { border-color: var(--brand); background-color: var(--brand); color: #ffffff; }
3016
+ .prb-index-author[data-active] { border-color: var(--brand); background-color: var(--brand); color: var(--on-brand); }
2948
3017
  /* Status: one control where five chips were. The box is the label, so "Status:" reads as part of the
2949
3018
  control rather than a caption beside it; the select inside is bare and carries the chevron. Same
2950
3019
  border, radius, height and fill-when-narrowing as the author filter beside it. */
@@ -2971,8 +3040,8 @@ a.prb-rail-item { text-decoration: none; }
2971
3040
  cursor: pointer;
2972
3041
  }
2973
3042
  .prb-index-status select:focus-visible { outline: none; }
2974
- .prb-index-status:has(select[data-active]) { border-color: var(--brand); background-color: var(--brand); color: rgba(255, 255, 255, 0.8); }
2975
- .prb-index-status select[data-active] { color: #ffffff; }
3043
+ .prb-index-status:has(select[data-active]) { border-color: var(--brand); background-color: var(--brand); color: var(--on-brand-quiet); }
3044
+ .prb-index-status select[data-active] { color: var(--on-brand); }
2976
3045
  /* Fetch updates: the secondary treatment Check for updates and Mark reviewed use, at the selects'
2977
3046
  height so the row lines up. What a run did shows in its own label for a moment, not in a row. */
2978
3047
  .prb-index-fetch-button {
@@ -2997,46 +3066,39 @@ a.prb-rail-item { text-decoration: none; }
2997
3066
  gap: 8px;
2998
3067
  }
2999
3068
 
3000
- /* ── Pages ──
3001
- Ordinary numbered pagination, because these are saved work items: a page boundary is somewhere a
3002
- person can come back to and a scroll position is not. Hidden by the client whenever the list it
3003
- is paging fits on one page, since one page is not a choice. */
3004
- .prb-index-pager {
3005
- display: flex;
3006
- align-items: center;
3007
- justify-content: center;
3008
- gap: 6px;
3009
- margin-top: 20px;
3069
+ /* ── Sections and Load more ──
3070
+ Waiting and Done sit under the working list as disclosures: headed at the weight of the count
3071
+ line, because they are the same kind of thing, a count of cards, and must not outrank the list
3072
+ above them. Load more is one per section, quiet, and centred under the cards it extends. */
3073
+ .prb-index-section { margin-top: 24px; }
3074
+ .prb-index-section[hidden] { display: none; }
3075
+ .prb-index-section-head {
3076
+ margin: 0 2px 10px;
3077
+ font-size: var(--t-meta);
3078
+ font-weight: 600;
3079
+ color: var(--text-secondary);
3080
+ cursor: pointer;
3010
3081
  }
3011
- .prb-index-pager[hidden] { display: none; }
3012
- .prb-index-pages { display: flex; gap: 4px; }
3013
- .prb-index-page {
3014
- min-width: 30px;
3015
- padding: 6px 10px;
3082
+ .prb-index-section-head:hover { color: var(--text-primary); }
3083
+ .prb-index-more {
3084
+ display: block;
3085
+ margin: 12px auto 0;
3086
+ padding: 6px 14px;
3016
3087
  border: 1px solid var(--border);
3017
3088
  border-radius: 8px;
3018
3089
  background: transparent;
3019
3090
  color: var(--text-secondary);
3020
3091
  font: inherit;
3021
3092
  font-size: var(--t-meta);
3022
- font-variant-numeric: tabular-nums;
3023
3093
  cursor: pointer;
3024
3094
  }
3025
- .prb-index-page:hover:not(:disabled) { color: var(--text-primary); border-color: var(--border-strong); }
3026
- /* Plainly unavailable at the ends, rather than a control that looks live and does nothing. */
3027
- .prb-index-page:disabled { opacity: 0.4; cursor: default; }
3028
- /* The page you are on, filled the way the selected filter is: this bar has one job and it is to
3029
- say which of these numbers is the answer. */
3030
- .prb-index-page[aria-current="page"] {
3031
- border-color: var(--brand);
3032
- background: var(--brand);
3033
- color: #ffffff;
3034
- }
3095
+ .prb-index-more[hidden] { display: none; }
3096
+ .prb-index-more:hover { color: var(--text-primary); border-color: var(--border-strong); }
3035
3097
  .prb-card {
3036
3098
  position: relative;
3037
3099
  border: 1px solid var(--border);
3038
3100
  border-radius: 12px;
3039
- background: var(--surface);
3101
+ background: var(--surface-raised);
3040
3102
  }
3041
3103
  .prb-card:hover { border-color: var(--border-strong); }
3042
3104
  .prb-card[hidden] { display: none; }
@@ -3082,8 +3144,8 @@ a.prb-rail-item { text-decoration: none; }
3082
3144
  padding: 12px 16px;
3083
3145
  border: 1px solid var(--brand);
3084
3146
  border-radius: 12px;
3085
- background: var(--surface);
3086
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
3147
+ background: var(--surface-raised);
3148
+ box-shadow: 0 6px 20px var(--shadow-soft);
3087
3149
  }
3088
3150
  .prb-bulk[hidden] { display: none; }
3089
3151
  .prb-bulk-count {
@@ -3181,7 +3243,7 @@ a.prb-rail-item { text-decoration: none; }
3181
3243
  padding: 1px 6px;
3182
3244
  border-radius: 999px;
3183
3245
  background: var(--brand);
3184
- color: #fff;
3246
+ color: var(--on-brand);
3185
3247
  font-size: var(--t-pill);
3186
3248
  font-weight: 700;
3187
3249
  letter-spacing: 0.03em;
@@ -3355,7 +3417,7 @@ a.prb-rail-item { text-decoration: none; }
3355
3417
  color: var(--text-muted);
3356
3418
  white-space: nowrap;
3357
3419
  }
3358
- .prb-card-lens[data-lens="kiss"] { border-color: var(--brand); color: #c4a5f5; }
3420
+ .prb-card-lens[data-lens="kiss"] { border-color: var(--brand); color: var(--brand-ink); }
3359
3421
 
3360
3422
  .prb-card-status,
3361
3423
  .prb-card-pr-state,
@@ -3370,16 +3432,30 @@ a.prb-rail-item { text-decoration: none; }
3370
3432
  white-space: nowrap;
3371
3433
  }
3372
3434
  .prb-card-status { border: 1px solid var(--border); color: var(--text-tertiary, var(--text-secondary)); }
3373
- .prb-card-status[data-status="new"] { border-color: var(--brand); color: #c4a5f5; }
3374
- .prb-card-status[data-status="complete"] { border-color: rgba(46, 160, 67, 0.5); color: #7ee2a8; }
3435
+ .prb-card-status[data-status="new"] { border-color: var(--brand); color: var(--brand-ink); }
3436
+ .prb-card-status[data-status="complete"] { border-color: var(--success-border); color: var(--success-ink); }
3375
3437
  /* The upstream's state, beside the reviewer's. Filled where the status is outlined, so the two read
3376
3438
  as different kinds of fact. Merged takes the forge's own purple; closed is muted rather than red,
3377
3439
  because red on this card already means high risk. */
3378
- .prb-card-pr-state[data-pr-state="merged"] { background: rgba(163, 113, 247, 0.18); color: #d2a8ff; }
3379
- .prb-card-pr-state[data-pr-state="closed"] { background: rgba(139, 148, 158, 0.16); color: var(--text-secondary); }
3380
- .prb-card-risk[data-risk="high"] { background: rgba(207, 34, 46, 0.16); color: #ff9b9b; }
3381
- .prb-card-risk[data-risk="medium"] { background: rgba(210, 153, 34, 0.16); color: #ffd18a; }
3382
- .prb-card-risk[data-risk="low"] { background: rgba(46, 160, 67, 0.14); color: #7ee2a8; }
3440
+ .prb-card-pr-state[data-pr-state="merged"] { background: var(--merged-subtle); color: var(--merged-ink); }
3441
+ .prb-card-pr-state[data-pr-state="closed"] { background: var(--neutral-subtle); color: var(--text-secondary); }
3442
+ .prb-card-risk[data-risk="high"] { background: var(--danger-subtle); color: var(--danger-ink); }
3443
+ .prb-card-risk[data-risk="medium"] { background: var(--warning-subtle); color: var(--warning-ink); }
3444
+ .prb-card-risk[data-risk="low"] { background: var(--success-subtle); color: var(--success-ink); }
3445
+ /* Why a card is where it is: a Waiting review back in Active, or a Done one that moved. A sentence,
3446
+ so it is not set in capitals like the pills beside it, and tinted like the brand because it is
3447
+ news about the change, as "PR updated" is. */
3448
+ .prb-card-lifecycle {
3449
+ flex: none;
3450
+ padding: 2px 7px;
3451
+ border-radius: 999px;
3452
+ font-size: var(--t-meta);
3453
+ font-weight: 600;
3454
+ white-space: nowrap;
3455
+ background: var(--brand-muted);
3456
+ color: var(--brand-ink);
3457
+ }
3458
+ .prb-card-lifecycle[hidden] { display: none; }
3383
3459
 
3384
3460
  /* Over the card rather than inside its link, so pinning cannot be a mis-click into the review. */
3385
3461
  .prb-card-pin {
@@ -3469,8 +3545,8 @@ a.prb-rail-item { text-decoration: none; }
3469
3545
  padding: 5px;
3470
3546
  border: 1px solid var(--border);
3471
3547
  border-radius: 9px;
3472
- background: var(--surface);
3473
- box-shadow: 0 10px 28px rgba(0, 0, 0, 0.36);
3548
+ background: var(--surface-raised);
3549
+ box-shadow: 0 10px 28px var(--shadow-float);
3474
3550
  text-align: left;
3475
3551
  }
3476
3552
  .prb-menu-item {
@@ -3488,9 +3564,12 @@ a.prb-rail-item { text-decoration: none; }
3488
3564
  }
3489
3565
  .prb-menu-item:hover { background: var(--surface-2); color: var(--text-primary); }
3490
3566
  .prb-menu-item:focus-visible { outline: 2px solid var(--brand-hover); outline-offset: -2px; }
3491
- .prb-menu-item-danger { color: #ff9b9b; }
3492
- .prb-menu-item-danger:hover { background: rgba(207, 34, 46, 0.16); color: #ffb3b3; }
3567
+ .prb-menu-item-danger { color: var(--danger-ink); }
3568
+ .prb-menu-item-danger:hover { background: var(--danger-subtle); color: var(--danger-ink-strong); }
3493
3569
  .prb-menu-item[disabled] { opacity: 0.6; cursor: default; }
3570
+ /* `display: block` above beats the `hidden` attribute, and the lifecycle items are hidden that way:
3571
+ without this, the move that would do nothing is still drawn and still reachable by keyboard. */
3572
+ .prb-menu-item[hidden] { display: none; }
3494
3573
 
3495
3574
  /* The confirmation is the same panel in its second state, so the question appears where the person
3496
3575
  was already looking rather than in a modal over the middle of the screen. */
@@ -3525,7 +3604,7 @@ a.prb-rail-item { text-decoration: none; }
3525
3604
  }
3526
3605
  .prb-menu-error {
3527
3606
  margin: 6px 4px 2px;
3528
- color: #ff9b9b;
3607
+ color: var(--danger-ink);
3529
3608
  font-size: var(--t-micro);
3530
3609
  line-height: var(--lh-body);
3531
3610
  }
@@ -3543,9 +3622,9 @@ a.prb-rail-item { text-decoration: none; }
3543
3622
  }
3544
3623
  .prb-complete:hover { border-color: var(--border-strong); color: var(--text-primary); }
3545
3624
  .prb-complete[aria-pressed="true"] {
3546
- border-color: rgba(46, 160, 67, 0.55);
3547
- background: rgba(46, 160, 67, 0.14);
3548
- color: #7ee2a8;
3625
+ border-color: var(--success-border);
3626
+ background: var(--success-subtle);
3627
+ color: var(--success-ink);
3549
3628
  }
3550
3629
 
3551
3630
  /* ── Diagrams ──
@@ -3591,7 +3670,7 @@ a.prb-rail-item { text-decoration: none; }
3591
3670
  text-align: left;
3592
3671
  cursor: pointer;
3593
3672
  }
3594
- .prb-diagram-toggle:hover { color: var(--text-primary); }
3673
+ .prb-diagram-toggle:hover { color: var(--pane-ink); }
3595
3674
  .prb-diagram-disclosure {
3596
3675
  font-size: 9px; /* the disclosure caret, sized to the mark, not the type scale */
3597
3676
  color: #8c959f;
@@ -3637,7 +3716,7 @@ a.prb-rail-item { text-decoration: none; }
3637
3716
  }
3638
3717
  .prb-diagram-zoom { min-width: 26px; font-variant-numeric: tabular-nums; }
3639
3718
  .prb-diagram-zoom:hover,
3640
- .prb-diagram-redraw:hover { border-color: var(--border-strong); color: var(--text-primary); }
3719
+ .prb-diagram-redraw:hover { border-color: rgba(15, 23, 42, 0.3); color: var(--pane-ink); }
3641
3720
  .prb-diagram-redraw[disabled] { opacity: 0.5; cursor: default; }
3642
3721
 
3643
3722
  .prb-diagram-caption {
@@ -4662,8 +4741,9 @@ a.prb-rail-item { text-decoration: none; }
4662
4741
  * So the native one is turned off and the same chevron the rest of the product uses is drawn in its
4663
4742
  * place: inset from the edge by the padding the text has on the other side, and in the muted grey
4664
4743
  * the borders and the quiet icons already read as. The colour is written into the drawing as a
4665
- * literal because a data URI cannot take a custom property; `%2364748b` is `--text-muted`, and the
4666
- * two change together or not at all. Same for the filled state below, which is `#ffffff`.
4744
+ * literal because a data URI cannot take a custom property; `%2364748b` is the dark `--text-muted`,
4745
+ * and it serves the light theme unchanged because the light `--text-muted` is within a hair of it.
4746
+ * Change either and check the other. Same for the filled state below, which is `--on-brand`.
4667
4747
  *
4668
4748
  * Both selects in the workspace are listed here rather than each carrying its own copy: it is one
4669
4749
  * control with two sizes, and a caret that differed between them would be a bug nobody could name. */
@@ -4717,6 +4797,12 @@ a.prb-rail-item { text-decoration: none; }
4717
4797
  margin: 0;
4718
4798
  accent-color: var(--brand);
4719
4799
  }
4800
+ /* What a choice does, beside its name rather than under it, so three short choices stay three
4801
+ short lines. A <small> rather than a span, because `.prb-field span` is the field's caption. */
4802
+ .prb-settings-choice-help {
4803
+ font-size: var(--t-meta);
4804
+ color: var(--text-secondary);
4805
+ }
4720
4806
  .prb-settings-help {
4721
4807
  margin: 0;
4722
4808
  max-width: 46rem;
@@ -4773,7 +4859,7 @@ a.prb-rail-item { text-decoration: none; }
4773
4859
  }
4774
4860
  .prb-notification:first-child { border-top: 0; }
4775
4861
  /* Unread carries a tint as well as the dot and the weight, so it reads at a glance down a long list. */
4776
- .prb-notification[data-read='false'] { background: rgba(139, 92, 246, 0.09); }
4862
+ .prb-notification[data-read='false'] { background: var(--unread-wash); }
4777
4863
  .prb-notification-open {
4778
4864
  flex: 1;
4779
4865
  min-width: 0;
@@ -4785,7 +4871,7 @@ a.prb-rail-item { text-decoration: none; }
4785
4871
  text-decoration: none;
4786
4872
  }
4787
4873
  /* The whole row is the link, so the row lights up rather than the title underlining. */
4788
- a.prb-notification-open:hover { background: rgba(255, 255, 255, 0.04); }
4874
+ a.prb-notification-open:hover { background: var(--wash); }
4789
4875
  a.prb-notification-open:focus-visible { outline: 2px solid var(--brand-hover); outline-offset: -2px; }
4790
4876
  .prb-notification-dot {
4791
4877
  flex: none;
@@ -4836,9 +4922,9 @@ a.prb-notification-open:focus-visible { outline: 2px solid var(--brand-hover); o
4836
4922
  border: 1px solid var(--border);
4837
4923
  border-left: 3px solid var(--success);
4838
4924
  border-radius: 8px;
4839
- background: var(--bg-elevated, #1f1f24);
4925
+ background: var(--bg-elevated);
4840
4926
  color: var(--text-primary);
4841
- box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
4927
+ box-shadow: 0 6px 24px var(--shadow-float);
4842
4928
  font-size: var(--t-body);
4843
4929
  }
4844
4930
  .prb-toast[data-kind='failed'] { border-left-color: var(--danger); }
@@ -4859,7 +4945,7 @@ a.prb-notification-open:focus-visible { outline: 2px solid var(--brand-hover); o
4859
4945
  line-height: 1;
4860
4946
  cursor: pointer;
4861
4947
  }
4862
- .prb-toast-close:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.06); }
4948
+ .prb-toast-close:hover { color: var(--text-primary); background: var(--wash-strong); }
4863
4949
  .prb-toast-open:focus-visible,
4864
4950
  .prb-toast-close:focus-visible { outline: 2px solid var(--brand-hover); outline-offset: 2px; }
4865
4951