@sienklogic/plan-build-run 2.27.2 → 2.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dashboard/bin/cli.js +3 -3
  3. package/dashboard/package.json +8 -5
  4. package/dashboard/public/css/command-center.css +382 -0
  5. package/dashboard/public/css/layout.css +481 -254
  6. package/dashboard/public/css/tokens.css +70 -61
  7. package/dashboard/public/js/sse-client.js +52 -82
  8. package/dashboard/public/js/theme-toggle.js +19 -14
  9. package/dashboard/src/components/Layout.tsx +99 -0
  10. package/dashboard/src/components/partials/ActivityStream.tsx +58 -0
  11. package/dashboard/src/components/partials/AttentionPanel.tsx +48 -0
  12. package/dashboard/src/components/partials/CurrentPhaseCard.tsx +50 -0
  13. package/dashboard/src/components/partials/PhaseTimeline.tsx +38 -0
  14. package/dashboard/src/components/partials/ProgressRing.tsx +51 -0
  15. package/dashboard/src/components/partials/QuickActions.tsx +30 -0
  16. package/dashboard/src/components/partials/StatusHeader.tsx +45 -0
  17. package/dashboard/src/global.d.ts +10 -0
  18. package/dashboard/src/index.tsx +134 -0
  19. package/dashboard/src/middleware/current-phase.ts +23 -0
  20. package/dashboard/src/routes/command-center.routes.tsx +69 -0
  21. package/dashboard/src/routes/index.routes.tsx +106 -0
  22. package/dashboard/src/services/dashboard.service.d.ts +39 -0
  23. package/dashboard/src/services/sse.service.ts +34 -0
  24. package/dashboard/src/services/todo.service.d.ts +21 -0
  25. package/dashboard/src/services/watcher.service.ts +35 -0
  26. package/dashboard/src/sse-handler.tsx +37 -0
  27. package/dashboard/src/watcher-setup.ts +25 -0
  28. package/package.json +1 -1
  29. package/plugins/copilot-pbr/plugin.json +1 -1
  30. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  31. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  32. package/dashboard/src/services/sse.service.js +0 -58
  33. package/dashboard/src/services/watcher.service.js +0 -48
@@ -1,17 +1,45 @@
1
1
  /* ============================================
2
- Towline Dashboard — Layout & Typography
2
+ PBR Dashboard — Layout & Component CSS
3
+ All color/spacing values use semantic tokens
4
+ from tokens.css — NO raw hex values.
3
5
  ============================================ */
4
6
 
5
- /* --- Custom Properties --- */
6
- :root {
7
- --content-max-width: 960px;
7
+ /* --- Reset & Base --- */
8
+ *, *::before, *::after {
9
+ box-sizing: border-box;
8
10
  }
9
11
 
10
- /* --- Typography Override --- */
11
12
  html {
12
13
  font-family: var(--font-sans);
13
- font-size: 15px;
14
- letter-spacing: -0.01em;
14
+ font-size: var(--font-size-base, 14px);
15
+ line-height: var(--line-height-base, 1.5);
16
+ letter-spacing: -0.011em;
17
+ background: var(--color-surface);
18
+ color: var(--color-text);
19
+ -webkit-font-smoothing: antialiased;
20
+ -moz-osx-font-smoothing: grayscale;
21
+ }
22
+
23
+ code, pre, kbd, samp {
24
+ font-family: var(--font-mono);
25
+ font-size: 0.9em;
26
+ line-height: var(--line-height-mono, 1.6);
27
+ }
28
+
29
+ body {
30
+ margin: 0;
31
+ min-height: 100vh;
32
+ display: flex;
33
+ }
34
+
35
+ a {
36
+ color: var(--color-accent);
37
+ text-decoration: none;
38
+ }
39
+
40
+ a:hover {
41
+ color: var(--color-accent-hover);
42
+ text-decoration: underline;
15
43
  }
16
44
 
17
45
  code, pre, kbd, samp {
@@ -19,76 +47,198 @@ code, pre, kbd, samp {
19
47
  font-size: 0.875em;
20
48
  }
21
49
 
22
- h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.025em; line-height: 1.2; margin-bottom: var(--space-sm); }
23
- h2 { font-size: 1.35rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1.3; margin-top: var(--space-2xl); margin-bottom: var(--space-md); }
24
- h3 { font-size: 1.1rem; font-weight: 600; line-height: 1.4; }
50
+ h1 {
51
+ font-size: 1.75rem;
52
+ font-weight: 700;
53
+ letter-spacing: -0.025em;
54
+ line-height: 1.2;
55
+ margin-top: 0;
56
+ margin-bottom: var(--space-sm);
57
+ }
58
+
59
+ h2 {
60
+ font-size: 1.35rem;
61
+ font-weight: 600;
62
+ letter-spacing: -0.02em;
63
+ line-height: 1.3;
64
+ margin-top: var(--space-2xl);
65
+ margin-bottom: var(--space-md);
66
+ }
25
67
 
26
- p { line-height: 1.65; }
68
+ h3 {
69
+ font-size: 1.1rem;
70
+ font-weight: 600;
71
+ line-height: 1.4;
72
+ margin-top: var(--space-lg);
73
+ margin-bottom: var(--space-sm);
74
+ }
27
75
 
28
- small { font-size: 0.8125rem; color: var(--color-text-dim); }
76
+ p {
77
+ line-height: 1.65;
78
+ margin-top: 0;
79
+ margin-bottom: var(--space-md);
80
+ }
29
81
 
30
- /* --- Sidebar: Current Phase Card --- */
31
- .sidebar-current-phase {
82
+ small {
83
+ font-size: 0.8125rem;
84
+ color: var(--color-text-dim);
85
+ }
86
+
87
+ ul, ol {
88
+ padding-left: var(--space-lg);
89
+ }
90
+
91
+ /* --- App Layout --- */
92
+ .sidebar {
93
+ position: fixed;
94
+ top: 0;
95
+ left: 0;
96
+ width: var(--size-sidebar);
97
+ height: 100vh;
98
+ background: var(--color-surface-raised);
99
+ border-right: 1px solid var(--color-border);
100
+ display: flex;
101
+ flex-direction: column;
102
+ overflow-y: auto;
103
+ z-index: 10;
104
+ }
105
+
106
+ .main-content {
107
+ margin-left: var(--size-sidebar);
108
+ flex: 1;
109
+ padding: var(--space-lg) var(--space-xl);
110
+ min-height: 100vh;
111
+ background: var(--color-surface);
112
+ max-width: 100%;
113
+ }
114
+
115
+ /* --- Sidebar Brand --- */
116
+ .sidebar__brand {
32
117
  padding: var(--space-md) var(--space-lg);
33
118
  border-bottom: 1px solid var(--color-border);
34
- margin-bottom: var(--space-sm);
119
+ display: flex;
120
+ flex-direction: column;
35
121
  }
36
122
 
37
- .sidebar-current-phase small {
123
+ .sidebar__brand-name {
124
+ font-size: 1rem;
125
+ font-weight: 700;
126
+ letter-spacing: 0.05em;
38
127
  text-transform: uppercase;
39
- letter-spacing: 0.04em;
40
- font-size: 0.6875rem;
128
+ color: var(--color-accent);
129
+ }
130
+
131
+ .sidebar__brand-subtitle {
132
+ font-size: 0.75rem;
41
133
  color: var(--color-text-dim);
134
+ letter-spacing: 0.02em;
42
135
  }
43
136
 
44
- .sidebar-current-phase a {
45
- display: block;
46
- text-decoration: none;
47
- color: inherit;
48
- margin-top: var(--space-xs);
49
- line-height: 1.4;
137
+ /* --- Sidebar Navigation --- */
138
+ .sidebar__nav {
139
+ list-style: none;
140
+ padding: var(--space-sm) 0;
141
+ margin: 0;
142
+ flex: 1;
50
143
  }
51
144
 
52
- .sidebar-current-phase a strong {
53
- font-size: 0.875rem;
54
- display: block;
145
+ .sidebar__nav li {
146
+ padding: 0;
55
147
  }
56
148
 
57
- .sidebar-current-phase a span {
149
+ .sidebar__nav-link {
58
150
  display: block;
59
- font-size: 0.8125rem;
151
+ padding: var(--space-sm) var(--space-lg);
152
+ font-size: 0.875rem;
153
+ font-weight: 500;
60
154
  color: var(--color-text-dim);
155
+ text-decoration: none;
156
+ border-radius: 0;
157
+ transition: background-color var(--transition-fast), color var(--transition-fast);
158
+ border-left: 3px solid transparent;
61
159
  }
62
160
 
63
- .sidebar-current-phase .phase-status {
64
- font-size: 0.75rem;
65
- text-transform: capitalize;
161
+ .sidebar__nav-link:hover {
162
+ background: var(--color-surface-hover);
163
+ color: var(--color-text);
164
+ text-decoration: none;
165
+ }
166
+
167
+ .sidebar__nav-link--active,
168
+ .sidebar__nav-link[aria-current="page"] {
169
+ background: var(--color-surface-hover);
66
170
  color: var(--color-accent);
67
- margin-top: 2px;
171
+ border-left-color: var(--color-accent);
172
+ font-weight: 600;
68
173
  }
69
174
 
70
- /* --- Sidebar: Next Action --- */
71
- .sidebar-next-action {
72
- padding: var(--space-sm) var(--space-lg);
73
- border-bottom: 1px solid var(--color-border);
74
- overflow: hidden;
175
+ /* --- Sidebar Footer --- */
176
+ .sidebar__footer {
177
+ padding: var(--space-md) var(--space-lg);
178
+ border-top: 1px solid var(--color-border);
179
+ display: flex;
180
+ align-items: center;
181
+ gap: var(--space-sm);
75
182
  }
76
183
 
77
- .sidebar-next-action small {
78
- text-transform: uppercase;
79
- letter-spacing: 0.04em;
80
- font-size: 0.6875rem;
184
+ /* --- Theme Toggle Button --- */
185
+ .theme-btn {
186
+ background: none;
187
+ border: 1px solid var(--color-border);
188
+ border-radius: var(--radius-sm);
189
+ padding: var(--space-xs) var(--space-sm);
190
+ cursor: pointer;
81
191
  color: var(--color-text-dim);
82
- display: block;
192
+ font-size: 0.875rem;
193
+ transition: background-color var(--transition-fast), color var(--transition-fast);
194
+ }
195
+
196
+ .theme-btn:hover {
197
+ background: var(--color-surface-hover);
198
+ color: var(--color-text);
199
+ }
200
+
201
+ .theme-btn__icon {
202
+ display: inline-block;
203
+ line-height: 1;
204
+ }
205
+
206
+ /* --- SSE Status Dot --- */
207
+ #sse-status {
208
+ display: inline-block;
209
+ width: 8px;
210
+ height: 8px;
211
+ border-radius: var(--radius-lg);
212
+ background: var(--color-border);
213
+ transition: background-color var(--transition-base);
214
+ flex-shrink: 0;
215
+ }
216
+
217
+ #sse-status[data-connected="true"] {
218
+ background: var(--status-complete, green);
219
+ }
220
+
221
+ #sse-status[data-connected="false"] {
222
+ background: var(--color-text-muted);
223
+ }
224
+
225
+ /* --- Skip Link (Accessibility) --- */
226
+ .skip-link {
227
+ position: absolute;
228
+ left: -9999px;
229
+ top: 0;
230
+ z-index: 1000;
231
+ padding: var(--space-sm) var(--space-md);
232
+ background: var(--color-accent);
233
+ color: var(--color-surface);
234
+ text-decoration: none;
235
+ font-weight: 600;
83
236
  }
84
237
 
85
- .sidebar-next-action__cmd {
238
+ .skip-link:focus {
239
+ left: 0;
86
240
  display: block;
87
- font-size: 0.75rem;
88
- margin-top: 2px;
89
- overflow: hidden;
90
- text-overflow: ellipsis;
91
- white-space: nowrap;
241
+ text-align: center;
92
242
  }
93
243
 
94
244
  /* --- Card Component --- */
@@ -141,62 +291,45 @@ th {
141
291
  color: var(--color-text-dim);
142
292
  white-space: nowrap;
143
293
  padding: var(--table-cell-padding);
294
+ border-bottom: 1px solid var(--color-border);
295
+ text-align: left;
144
296
  }
145
297
 
146
298
  td {
147
299
  vertical-align: top;
148
300
  line-height: 1.5;
149
301
  padding: var(--table-cell-padding);
302
+ border-bottom: 1px solid var(--color-border);
303
+ }
304
+
305
+ tr:last-child td {
306
+ border-bottom: none;
150
307
  }
151
308
 
152
309
  /* --- Progress Bar --- */
153
310
  progress {
154
311
  height: 0.5rem;
155
- border-radius: 999px;
312
+ border-radius: var(--radius-lg);
313
+ background: var(--color-border);
314
+ overflow: hidden;
315
+ appearance: none;
316
+ -webkit-appearance: none;
156
317
  }
157
318
 
158
319
  progress::-webkit-progress-bar {
159
320
  background: var(--color-border);
160
- border-radius: 999px;
321
+ border-radius: var(--radius-lg);
161
322
  }
162
323
 
163
324
  progress::-webkit-progress-value {
164
325
  background: var(--color-accent);
165
- border-radius: 999px;
326
+ border-radius: var(--radius-lg);
166
327
  transition: width var(--transition-base);
167
328
  }
168
329
 
169
330
  progress::-moz-progress-bar {
170
331
  background: var(--color-accent);
171
- border-radius: 999px;
172
- }
173
-
174
- /* --- Details/Summary --- */
175
- details {
176
- margin: var(--space-sm) 0;
177
- border: none;
178
- }
179
-
180
- details summary {
181
- font-size: 0.875rem;
182
- font-weight: 500;
183
- cursor: pointer;
184
- padding: var(--space-xs) 0;
185
- color: var(--color-accent);
186
- }
187
-
188
- details summary:hover {
189
- text-decoration: underline;
190
- }
191
-
192
- details ul {
193
- margin-top: var(--space-xs);
194
- padding-left: var(--space-lg);
195
- }
196
-
197
- details li {
198
- font-size: 0.875rem;
199
- line-height: 1.6;
332
+ border-radius: var(--radius-lg);
200
333
  }
201
334
 
202
335
  /* --- Inline Code --- */
@@ -205,9 +338,10 @@ details li {
205
338
  padding: 0.15em 0.4em;
206
339
  border-radius: var(--radius-sm);
207
340
  background: var(--color-surface-hover);
341
+ color: var(--color-text);
208
342
  }
209
343
 
210
- /* --- Markdown Body (rendered markdown content) --- */
344
+ /* --- Markdown Body --- */
211
345
  .markdown-body h1 { font-size: 1.5rem; margin-top: var(--space-xl); margin-bottom: var(--space-sm); }
212
346
  .markdown-body h2 { font-size: 1.25rem; margin-top: var(--space-xl); margin-bottom: var(--space-sm); }
213
347
  .markdown-body h3 { font-size: 1.05rem; margin-top: var(--space-lg); margin-bottom: var(--space-xs); }
@@ -231,11 +365,12 @@ details li {
231
365
  }
232
366
 
233
367
  .markdown-body pre {
234
- background: var(--overlay-bg);
368
+ background: var(--color-surface-raised);
235
369
  border-radius: var(--radius-sm);
236
370
  padding: var(--space-md);
237
371
  overflow-x: auto;
238
372
  margin: var(--space-md) 0;
373
+ border: 1px solid var(--color-border);
239
374
  }
240
375
 
241
376
  .markdown-body pre code {
@@ -251,29 +386,41 @@ details li {
251
386
  padding: var(--space-sm) var(--space-md);
252
387
  }
253
388
 
254
- .markdown-body ul.contains-task-list {
255
- list-style: none;
256
- padding-left: var(--space-sm);
389
+ .markdown-body hr {
390
+ border: none;
391
+ border-top: 1px solid var(--color-border);
392
+ margin: var(--space-lg) 0;
257
393
  }
258
394
 
259
- .markdown-body ul.contains-task-list li {
260
- position: relative;
261
- padding-left: var(--space-xs);
395
+ /* --- Details/Summary --- */
396
+ details {
397
+ margin: var(--space-sm) 0;
398
+ border: none;
262
399
  }
263
400
 
264
- .markdown-body img {
265
- max-width: 100%;
266
- height: auto;
267
- border-radius: var(--radius-sm);
401
+ details summary {
402
+ font-size: 0.875rem;
403
+ font-weight: 500;
404
+ cursor: pointer;
405
+ padding: var(--space-xs) 0;
406
+ color: var(--color-accent);
268
407
  }
269
408
 
270
- .markdown-body hr {
271
- border: none;
272
- border-top: 1px solid var(--color-border);
273
- margin: var(--space-lg) 0;
409
+ details summary:hover {
410
+ text-decoration: underline;
411
+ }
412
+
413
+ details ul {
414
+ margin-top: var(--space-xs);
415
+ padding-left: var(--space-lg);
274
416
  }
275
417
 
276
- /* --- Phase Timeline (homepage) --- */
418
+ details li {
419
+ font-size: 0.875rem;
420
+ line-height: 1.6;
421
+ }
422
+
423
+ /* --- Phase Timeline --- */
277
424
  .phase-timeline {
278
425
  list-style: none;
279
426
  padding: 0;
@@ -299,6 +446,7 @@ details li {
299
446
  align-items: baseline;
300
447
  flex: 1;
301
448
  min-width: 0;
449
+ color: var(--color-text);
302
450
  }
303
451
 
304
452
  .step-label strong {
@@ -314,7 +462,7 @@ details li {
314
462
  white-space: nowrap;
315
463
  }
316
464
 
317
- /* --- Activity Feed (homepage) --- */
465
+ /* --- Activity Feed --- */
318
466
  .activity-feed {
319
467
  list-style: none;
320
468
  padding: 0;
@@ -341,6 +489,7 @@ details li {
341
489
  white-space: nowrap;
342
490
  min-width: 0;
343
491
  flex: 1;
492
+ color: var(--color-text);
344
493
  }
345
494
 
346
495
  .activity-time {
@@ -349,7 +498,7 @@ details li {
349
498
  font-size: 0.8rem;
350
499
  }
351
500
 
352
- /* Phase Navigation */
501
+ /* --- Phase Navigation --- */
353
502
  .phase-nav {
354
503
  display: grid;
355
504
  grid-template-columns: 1fr auto 1fr;
@@ -369,81 +518,98 @@ details li {
369
518
  text-align: right;
370
519
  }
371
520
 
372
- /* --- Back Link --- */
373
- main > p:first-of-type > a[href="/"] {
374
- font-size: 0.875rem;
375
- color: var(--color-text-dim);
376
- text-decoration: none;
521
+ /* --- Commit Timeline --- */
522
+ .commit-timeline {
523
+ list-style: none;
524
+ padding: 0 0 0 var(--space-md);
525
+ margin: 0 0 var(--space-lg);
526
+ border-left: 2px solid var(--color-border);
377
527
  }
378
528
 
379
- main > p:first-of-type > a[href="/"]:hover {
380
- color: var(--color-accent);
529
+ .commit-timeline__item {
530
+ display: flex;
531
+ flex-wrap: wrap;
532
+ align-items: center;
533
+ gap: var(--space-xs);
534
+ padding: var(--space-xs) 0;
535
+ border-bottom: 1px solid var(--color-border);
536
+ position: relative;
381
537
  }
382
538
 
383
- /* --- SSE Connection Status --- */
384
- #sse-status {
385
- display: inline-block;
539
+ .commit-timeline__item::before {
540
+ content: '';
541
+ position: absolute;
542
+ left: calc(-1 * var(--space-md) - 1px);
543
+ top: 50%;
544
+ transform: translateY(-50%);
386
545
  width: 8px;
387
546
  height: 8px;
388
- border-radius: 50%;
389
- margin-left: var(--space-sm);
390
- vertical-align: middle;
391
- transition: background-color var(--transition-base);
547
+ border-radius: var(--radius-lg);
548
+ background: var(--color-accent);
549
+ border: 2px solid var(--color-surface);
392
550
  }
393
551
 
394
- #sse-status[data-connected="true"] {
395
- background-color: var(--status-complete);
552
+ .commit-timeline__hash {
553
+ font-size: 0.75rem;
554
+ color: var(--color-text-muted);
555
+ font-family: var(--font-mono);
396
556
  }
397
557
 
398
- #sse-status[data-connected="false"] {
399
- background-color: var(--status-not-started);
558
+ .commit-timeline__task {
559
+ flex: 1;
560
+ font-size: 0.875rem;
561
+ min-width: 0;
562
+ overflow: hidden;
563
+ text-overflow: ellipsis;
564
+ white-space: nowrap;
400
565
  }
401
566
 
402
- /* --- Skip Link (Accessibility) --- */
403
- .skip-link {
404
- position: absolute;
405
- left: -9999px;
406
- top: 0;
407
- z-index: 1000;
408
- padding: var(--space-sm) var(--space-md);
409
- background: var(--tblr-primary);
410
- color: var(--tblr-primary-fg, #fff);
411
- text-decoration: none;
412
- font-weight: 600;
567
+ .commit-timeline__meta {
568
+ font-size: 0.8125rem;
569
+ color: var(--color-text-muted);
570
+ display: flex;
571
+ align-items: center;
572
+ gap: var(--space-xs);
413
573
  }
414
574
 
415
- .skip-link:focus {
416
- position: static;
417
- display: block;
418
- text-align: center;
575
+ /* --- Sidebar: Current Phase Card --- */
576
+ .sidebar-current-phase {
577
+ padding: var(--space-md) var(--space-lg);
578
+ border-bottom: 1px solid var(--color-border);
579
+ margin-bottom: var(--space-sm);
419
580
  }
420
581
 
421
- /* --- Focus Visible --- */
422
- :focus-visible {
423
- outline: 2px solid var(--tblr-primary);
424
- outline-offset: 2px;
582
+ .sidebar-current-phase small {
583
+ text-transform: uppercase;
584
+ letter-spacing: 0.04em;
585
+ font-size: 0.6875rem;
586
+ color: var(--color-text-dim);
425
587
  }
426
588
 
427
- /* --- Error Card --- */
428
- .error-card {
429
- border-left: 4px solid var(--tblr-danger);
430
- padding: var(--space-lg);
431
- margin: var(--space-lg) 0;
432
- background: var(--color-surface-raised);
433
- border-radius: var(--radius-md);
589
+ .sidebar-current-phase a {
590
+ display: block;
591
+ text-decoration: none;
592
+ color: inherit;
593
+ margin-top: var(--space-xs);
594
+ line-height: 1.4;
434
595
  }
435
596
 
436
- .error-card__icon {
437
- font-size: 1.5rem;
438
- margin-bottom: var(--space-sm);
597
+ .sidebar-current-phase a strong {
598
+ font-size: 0.875rem;
599
+ display: block;
439
600
  }
440
601
 
441
- .error-card__message {
442
- margin-bottom: var(--space-md);
602
+ .sidebar-current-phase a span {
603
+ display: block;
604
+ font-size: 0.8125rem;
605
+ color: var(--color-text-dim);
443
606
  }
444
607
 
445
- .error-card__action a {
446
- font-size: 0.875rem;
608
+ .sidebar-current-phase .phase-status {
609
+ font-size: 0.75rem;
610
+ text-transform: capitalize;
611
+ color: var(--color-accent);
612
+ margin-top: 2px;
447
613
  }
448
614
 
449
615
  /* --- Hero Stats Grid --- */
@@ -453,9 +619,18 @@ main > p:first-of-type > a[href="/"]:hover {
453
619
  gap: var(--space-md);
454
620
  }
455
621
 
456
- /* --- Stat Values --- */
457
- .stat-value { font-size: 2rem; font-weight: 700; line-height: 1.2; }
458
- .stat-unit { font-size: 0.875rem; color: var(--color-dim); margin-left: 0.25rem; }
622
+ .stat-value {
623
+ font-size: 2rem;
624
+ font-weight: 700;
625
+ line-height: 1.2;
626
+ color: var(--color-text);
627
+ }
628
+
629
+ .stat-unit {
630
+ font-size: 0.875rem;
631
+ color: var(--color-text-dim);
632
+ margin-left: 0.25rem;
633
+ }
459
634
 
460
635
  /* --- Quick Actions --- */
461
636
  .quick-actions {
@@ -466,11 +641,36 @@ main > p:first-of-type > a[href="/"]:hover {
466
641
  }
467
642
 
468
643
  /* --- Bar Chart --- */
469
- .bar-chart-row { display: flex; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-xs); }
470
- .bar-chart-label { min-width: 160px; font-size: 0.875rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
471
- .bar-chart-bar { height: 1.5rem; border-radius: var(--radius-sm); background: var(--tblr-primary); color: var(--tblr-primary-fg, #fff); font-size: 0.75rem; display: flex; align-items: center; padding-left: var(--space-sm); min-width: 2rem; transition: width var(--transition-base); }
644
+ .bar-chart-row {
645
+ display: flex;
646
+ align-items: center;
647
+ gap: var(--space-sm);
648
+ margin-bottom: var(--space-xs);
649
+ }
472
650
 
473
- /* --- Loading Bar --- */
651
+ .bar-chart-label {
652
+ min-width: 160px;
653
+ font-size: 0.875rem;
654
+ white-space: nowrap;
655
+ overflow: hidden;
656
+ text-overflow: ellipsis;
657
+ color: var(--color-text);
658
+ }
659
+
660
+ .bar-chart-bar {
661
+ height: 1.5rem;
662
+ border-radius: var(--radius-sm);
663
+ background: var(--color-accent);
664
+ color: var(--color-surface);
665
+ font-size: 0.75rem;
666
+ display: flex;
667
+ align-items: center;
668
+ padding-left: var(--space-sm);
669
+ min-width: 2rem;
670
+ transition: width var(--transition-base);
671
+ }
672
+
673
+ /* --- Loading Bar (HTMX) --- */
474
674
  .loading-bar {
475
675
  position: fixed;
476
676
  top: 0;
@@ -483,7 +683,7 @@ main > p:first-of-type > a[href="/"]:hover {
483
683
 
484
684
  .htmx-request .loading-bar {
485
685
  display: block;
486
- background: var(--tblr-primary);
686
+ background: var(--color-accent);
487
687
  animation: loading-shimmer 1.2s ease-in-out infinite;
488
688
  }
489
689
 
@@ -492,16 +692,136 @@ main > p:first-of-type > a[href="/"]:hover {
492
692
  100% { transform: translateX(100%); }
493
693
  }
494
694
 
695
+ /* --- Error Card --- */
696
+ .error-card {
697
+ border-left: 4px solid var(--status-blocked, var(--color-accent));
698
+ padding: var(--space-lg);
699
+ margin: var(--space-lg) 0;
700
+ background: var(--color-surface-raised);
701
+ border-radius: var(--radius-md);
702
+ }
703
+
704
+ .error-card__icon {
705
+ font-size: 1.5rem;
706
+ margin-bottom: var(--space-sm);
707
+ }
708
+
709
+ .error-card__message {
710
+ margin-bottom: var(--space-md);
711
+ color: var(--color-text);
712
+ }
713
+
714
+ .error-card__action a {
715
+ font-size: 0.875rem;
716
+ }
717
+
718
+ /* --- Config page --- */
719
+ .config-section {
720
+ margin-bottom: var(--space-md);
721
+ }
722
+
723
+ .config-section summary {
724
+ cursor: pointer;
725
+ list-style: none;
726
+ }
727
+
728
+ .config-section summary::-webkit-details-marker {
729
+ display: none;
730
+ }
731
+
732
+ .config-row {
733
+ display: flex;
734
+ align-items: center;
735
+ gap: var(--space-md);
736
+ margin-bottom: var(--space-sm);
737
+ }
738
+
739
+ .config-row label {
740
+ min-width: 160px;
741
+ font-weight: 500;
742
+ color: var(--color-text);
743
+ }
744
+
745
+ .config-row input[type="text"],
746
+ .config-row input[type="number"],
747
+ .config-row select {
748
+ flex: 1;
749
+ background: var(--color-surface);
750
+ color: var(--color-text);
751
+ border: 1px solid var(--color-border);
752
+ border-radius: var(--radius-sm);
753
+ padding: var(--space-xs) var(--space-sm);
754
+ }
755
+
756
+ .config-fieldset {
757
+ border: 1px solid var(--card-border);
758
+ border-radius: var(--radius-md);
759
+ padding: var(--space-md);
760
+ margin-bottom: var(--space-md);
761
+ }
762
+
763
+ .config-toggle-row {
764
+ display: flex;
765
+ align-items: center;
766
+ margin-bottom: var(--space-xs);
767
+ }
768
+
769
+ .config-toggle-row label {
770
+ display: flex;
771
+ align-items: center;
772
+ gap: var(--space-sm);
773
+ cursor: pointer;
774
+ color: var(--color-text);
775
+ }
776
+
777
+ .config-raw-json {
778
+ width: 100%;
779
+ font-family: var(--font-mono);
780
+ font-size: 0.85rem;
781
+ background: var(--color-surface-raised);
782
+ color: var(--color-text);
783
+ border: 1px solid var(--color-border);
784
+ border-radius: var(--radius-sm);
785
+ padding: var(--space-sm);
786
+ }
787
+
788
+ .config-actions {
789
+ display: flex;
790
+ align-items: center;
791
+ gap: var(--space-md);
792
+ margin-top: var(--space-lg);
793
+ }
794
+
795
+ .config-hint {
796
+ color: var(--color-text-dim);
797
+ font-size: 0.85rem;
798
+ margin-bottom: var(--space-sm);
799
+ }
800
+
801
+ .config-feedback--success {
802
+ color: var(--status-complete, green);
803
+ font-weight: 500;
804
+ }
805
+
806
+ .config-feedback--error {
807
+ color: var(--status-blocked, red);
808
+ font-weight: 500;
809
+ }
810
+
811
+ /* --- Focus Visible --- */
812
+ :focus-visible {
813
+ outline: 2px solid var(--color-accent);
814
+ outline-offset: 2px;
815
+ }
816
+
495
817
  /* ============================================
496
818
  Responsive Breakpoints
497
819
  ============================================ */
498
820
 
499
- /* Mobile: compact typography */
500
821
  @media (max-width: 768px) {
501
822
  h1 { font-size: 1.4rem; }
502
823
  h2 { font-size: 1.15rem; }
503
824
 
504
- /* Tables: ensure horizontal scroll on mobile */
505
825
  table {
506
826
  font-size: 0.8125rem;
507
827
  }
@@ -511,7 +831,6 @@ main > p:first-of-type > a[href="/"]:hover {
511
831
  padding: 0 var(--space-md);
512
832
  }
513
833
 
514
- /* Hero stat cards: 2-column grid on mobile */
515
834
  .hero-stats {
516
835
  grid-template-columns: repeat(2, 1fr);
517
836
  }
@@ -520,19 +839,12 @@ main > p:first-of-type > a[href="/"]:hover {
520
839
  font-size: 1.5rem;
521
840
  }
522
841
 
523
- /* Bar chart: narrower labels */
524
842
  .bar-chart-label {
525
843
  min-width: 100px;
526
844
  font-size: 0.75rem;
527
845
  }
528
-
529
- /* Filter form: compact on mobile */
530
- .grid[style*="grid-template-columns: 1fr 1fr 2fr"] {
531
- grid-template-columns: 1fr 1fr !important;
532
- }
533
846
  }
534
847
 
535
- /* Small mobile */
536
848
  @media (max-width: 480px) {
537
849
  html {
538
850
  font-size: 14px;
@@ -542,101 +854,16 @@ main > p:first-of-type > a[href="/"]:hover {
542
854
  padding: var(--space-sm) var(--space-md);
543
855
  }
544
856
 
545
- /* Stack hero stats to single column on very small screens */
546
857
  .hero-stats {
547
858
  grid-template-columns: 1fr;
548
859
  }
549
860
 
550
- /* Bar chart: even narrower labels */
551
861
  .bar-chart-label {
552
862
  min-width: 80px;
553
863
  font-size: 0.7rem;
554
864
  }
555
865
 
556
- /* Quick action buttons: full width stack */
557
866
  .quick-actions {
558
867
  flex-direction: column;
559
868
  }
560
-
561
- .quick-actions a[role="button"] {
562
- width: 100%;
563
- text-align: center;
564
- }
565
- }
566
-
567
- /* --- Commit Timeline --- */
568
- .commit-timeline {
569
- list-style: none;
570
- padding: 0;
571
- margin: 0 0 var(--space-lg);
572
- border-left: 2px solid var(--color-border);
573
- padding-left: var(--space-md);
574
- }
575
-
576
- .commit-timeline__item {
577
- display: flex;
578
- flex-wrap: wrap;
579
- align-items: center;
580
- gap: var(--space-xs);
581
- padding: var(--space-xs) 0;
582
- border-bottom: 1px solid var(--color-border);
583
- position: relative;
584
- }
585
-
586
- .commit-timeline__item::before {
587
- content: '';
588
- position: absolute;
589
- left: calc(-1 * var(--space-md) - 1px);
590
- top: 50%;
591
- transform: translateY(-50%);
592
- width: 8px;
593
- height: 8px;
594
- border-radius: 50%;
595
- background: var(--color-accent);
596
- border: 2px solid var(--color-surface);
597
- }
598
-
599
- .commit-timeline__hash {
600
- font-size: 0.75rem;
601
- color: var(--color-text-muted);
602
- }
603
-
604
- .commit-timeline__task {
605
- flex: 1;
606
- font-size: 0.875rem;
607
- min-width: 0;
608
- overflow: hidden;
609
- text-overflow: ellipsis;
610
- white-space: nowrap;
611
869
  }
612
-
613
- .commit-timeline__meta {
614
- font-size: 0.8125rem;
615
- color: var(--color-text-muted);
616
- display: flex;
617
- align-items: center;
618
- gap: var(--space-xs);
619
- }
620
-
621
- /* Config page */
622
- .config-section { margin-bottom: var(--spacing-md); }
623
- .config-section summary { cursor: pointer; list-style: none; }
624
- .config-section summary::-webkit-details-marker { display: none; }
625
- .config-row {
626
- display: flex;
627
- align-items: center;
628
- gap: var(--spacing-md);
629
- margin-bottom: var(--spacing-sm);
630
- }
631
- .config-row label { min-width: 160px; font-weight: 500; }
632
- .config-row input[type="text"],
633
- .config-row input[type="number"],
634
- .config-row select { flex: 1; }
635
- .config-fieldset { border: 1px solid var(--card-border); border-radius: var(--radius); padding: var(--spacing-md); margin-bottom: var(--spacing-md); }
636
- .config-toggle-row { display: flex; align-items: center; margin-bottom: var(--spacing-xs); }
637
- .config-toggle-row label { display: flex; align-items: center; gap: var(--spacing-sm); cursor: pointer; }
638
- .config-raw-json { width: 100%; font-family: var(--font-mono, monospace); font-size: 0.85rem; }
639
- .config-actions { display: flex; align-items: center; gap: var(--spacing-md); margin-top: var(--spacing-lg); }
640
- .config-hint { color: var(--muted); font-size: 0.85rem; margin-bottom: var(--spacing-sm); }
641
- .config-feedback--success { color: var(--color-success, green); font-weight: 500; }
642
- .config-feedback--error { color: var(--color-error, red); font-weight: 500; }