symphifo 0.1.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.
@@ -0,0 +1,1528 @@
1
+ /* ============================================================================
2
+ SYMPHIFO DASHBOARD
3
+ Closed local operations theme: high-contrast green, hard edges, dark neutral surface.
4
+ ============================================================================ */
5
+
6
+ :root {
7
+ /* ── Neutral grayscale ──────────────────────────────────────────────────── */
8
+ --void: #000000;
9
+ --abyss: #040e04;
10
+ --crypt: #0b160b;
11
+ --stone: #141e14;
12
+ --cobble: #1d291d;
13
+ --dungeon: #283028;
14
+ --ash: #344034;
15
+ --iron: #5e6f5e;
16
+ --silver: #7a8e7a;
17
+ --slate: #a0b4a0;
18
+ --bone: #ccdacc;
19
+ --frost: #eff5ef;
20
+
21
+ /* ── Plague green spectrum ──────────────────────────────────────────────── */
22
+ --plague: #3dff14;
23
+ --blight: #44ea12;
24
+ --toxin: #2abb0e;
25
+ --ooze: #1a6c0a;
26
+ --mold: #0c2b06;
27
+
28
+ /* ── Semantic ───────────────────────────────────────────────────────────── */
29
+ --ok: #34d399;
30
+ --warn: #f59e0b;
31
+ --danger: #fb7185;
32
+ --info: #60a5fa;
33
+
34
+ /* ── Glow shortcuts ─────────────────────────────────────────────────────── */
35
+ --glow-weak: 0 0 10px rgba(55, 200, 15, 0.14);
36
+ --glow-mid: 0 0 18px rgba(65, 220, 20, 0.24);
37
+ --glow-strong: 0 0 28px rgba(78, 248, 26, 0.40);
38
+ }
39
+
40
+ /* ── Reset ────────────────────────────────────────────────────────────────── */
41
+
42
+ * {
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ ::selection {
47
+ background-color: rgba(70, 230, 20, 0.22);
48
+ color: var(--frost);
49
+ }
50
+
51
+ ::-webkit-scrollbar { width: 5px; height: 5px; }
52
+ ::-webkit-scrollbar-track { background: var(--abyss); }
53
+ ::-webkit-scrollbar-thumb { background: var(--ash); }
54
+ ::-webkit-scrollbar-thumb:hover { background: var(--toxin); }
55
+
56
+ /* ── Body ─────────────────────────────────────────────────────────────────── */
57
+
58
+ body {
59
+ margin: 0;
60
+ font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
61
+ background: var(--void);
62
+ color: var(--bone);
63
+ -webkit-font-smoothing: antialiased;
64
+ -moz-osx-font-smoothing: grayscale;
65
+ }
66
+
67
+ /* ── Shell ────────────────────────────────────────────────────────────────── */
68
+
69
+ .shell {
70
+ max-width: 1140px;
71
+ margin: 0 auto;
72
+ padding: 24px;
73
+ }
74
+
75
+ /* ── Topbar ───────────────────────────────────────────────────────────────── */
76
+
77
+ .topbar {
78
+ display: flex;
79
+ justify-content: space-between;
80
+ align-items: center;
81
+ gap: 12px;
82
+ margin-bottom: 20px;
83
+ padding-bottom: 16px;
84
+ border-bottom: 1px solid var(--ash);
85
+ }
86
+
87
+ h1 {
88
+ margin: 0;
89
+ font-size: 1.1rem;
90
+ font-weight: 600;
91
+ letter-spacing: 0.02em;
92
+ color: var(--frost);
93
+ }
94
+
95
+ h2 {
96
+ margin: 0;
97
+ font-size: 0.85rem;
98
+ font-weight: 600;
99
+ letter-spacing: 0.04em;
100
+ text-transform: uppercase;
101
+ color: var(--slate);
102
+ }
103
+
104
+ .eyebrow {
105
+ margin: 0;
106
+ color: var(--plague);
107
+ font-weight: 700;
108
+ text-transform: uppercase;
109
+ letter-spacing: 0.14em;
110
+ font-size: 0.7rem;
111
+ text-shadow: 0 0 12px rgba(61, 255, 20, 0.3);
112
+ }
113
+
114
+ .muted {
115
+ margin: 4px 0 0;
116
+ color: var(--silver);
117
+ font-size: 0.8rem;
118
+ }
119
+
120
+ .badges {
121
+ display: flex;
122
+ align-items: center;
123
+ gap: 8px;
124
+ }
125
+
126
+ .badge {
127
+ background: var(--stone);
128
+ padding: 6px 12px;
129
+ border: 1px solid var(--ash);
130
+ font-size: 0.72rem;
131
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
132
+ letter-spacing: 0.03em;
133
+ color: var(--slate);
134
+ text-transform: uppercase;
135
+ transition: border-color 150ms, opacity 150ms;
136
+ }
137
+
138
+ /* ── Health badge states ───────────────────────────────────────────────────── */
139
+
140
+ .badge-health-ok {
141
+ border-color: var(--ok);
142
+ color: var(--ok);
143
+ }
144
+
145
+ .badge-health-warn {
146
+ border-color: var(--warn);
147
+ color: var(--warn);
148
+ }
149
+
150
+ .badge-health-offline {
151
+ border-color: var(--danger);
152
+ color: var(--danger);
153
+ animation: offline-pulse 2s ease-in-out infinite;
154
+ }
155
+
156
+ @keyframes offline-pulse {
157
+ 0%, 100% { opacity: 1; }
158
+ 50% { opacity: 0.5; }
159
+ }
160
+
161
+ .badge-refreshing {
162
+ opacity: 0.5;
163
+ border-color: var(--toxin);
164
+ }
165
+
166
+ /* ── Issue count & batch toolbar ───────────────────────────────────────────── */
167
+
168
+ .issue-count {
169
+ font-size: 0.68rem;
170
+ color: var(--iron);
171
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
172
+ letter-spacing: 0.02em;
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 6px;
176
+ flex-wrap: wrap;
177
+ }
178
+
179
+ .batch-info {
180
+ color: var(--plague);
181
+ font-weight: 600;
182
+ }
183
+
184
+ /* ── Issue checkbox ───────────────────────────────────────────────────────── */
185
+
186
+ .issue-select {
187
+ display: inline-flex;
188
+ align-items: center;
189
+ cursor: pointer;
190
+ margin-right: 6px;
191
+ vertical-align: middle;
192
+ }
193
+
194
+ .issue-select input {
195
+ display: none;
196
+ }
197
+
198
+ .issue-checkbox {
199
+ width: 14px;
200
+ height: 14px;
201
+ border: 1px solid var(--ash);
202
+ background: var(--abyss);
203
+ display: inline-block;
204
+ transition: border-color 150ms, background 150ms;
205
+ position: relative;
206
+ }
207
+
208
+ .issue-select input:checked + .issue-checkbox {
209
+ border-color: var(--toxin);
210
+ background: var(--mold);
211
+ }
212
+
213
+ .issue-select input:checked + .issue-checkbox::after {
214
+ content: "";
215
+ position: absolute;
216
+ top: 2px;
217
+ left: 4px;
218
+ width: 4px;
219
+ height: 7px;
220
+ border: solid var(--plague);
221
+ border-width: 0 2px 2px 0;
222
+ transform: rotate(45deg);
223
+ }
224
+
225
+ .issue-checkbox:hover {
226
+ border-color: var(--dungeon);
227
+ }
228
+
229
+ /* ── Layout ───────────────────────────────────────────────────────────────── */
230
+
231
+ .layout {
232
+ display: grid;
233
+ gap: 16px;
234
+ }
235
+
236
+ /* ── Cards ────────────────────────────────────────────────────────────────── */
237
+
238
+ .card {
239
+ background: var(--crypt);
240
+ border: 1px solid var(--ash);
241
+ padding: 16px;
242
+ transition: border-color 200ms;
243
+ }
244
+
245
+ .card:hover {
246
+ border-color: var(--dungeon);
247
+ }
248
+
249
+ /* ── KPI grid ─────────────────────────────────────────────────────────────── */
250
+
251
+ .grid {
252
+ display: grid;
253
+ gap: 2px;
254
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
255
+ }
256
+
257
+ .kpi {
258
+ background: var(--stone);
259
+ border: 1px solid var(--ash);
260
+ padding: 16px 14px;
261
+ text-align: center;
262
+ transition: border-color 200ms, box-shadow 200ms, background 200ms;
263
+ }
264
+
265
+ .kpi:hover {
266
+ border-color: rgba(61, 255, 20, 0.25);
267
+ box-shadow: var(--glow-weak);
268
+ }
269
+
270
+ .kpi .label {
271
+ font-size: 0.65rem;
272
+ text-transform: uppercase;
273
+ letter-spacing: 0.08em;
274
+ color: var(--iron);
275
+ margin: 0 0 6px;
276
+ }
277
+
278
+ .kpi .value {
279
+ margin: 0;
280
+ font-size: 2rem;
281
+ font-weight: 800;
282
+ line-height: 1.1;
283
+ color: var(--frost);
284
+ font-variant-numeric: tabular-nums;
285
+ letter-spacing: -0.02em;
286
+ }
287
+
288
+ .kpi .value.accent {
289
+ color: var(--plague);
290
+ text-shadow: 0 0 16px rgba(61, 255, 20, 0.2);
291
+ }
292
+
293
+ .kpi .value.warn {
294
+ color: var(--warn);
295
+ }
296
+
297
+ .kpi .value.danger {
298
+ color: var(--danger);
299
+ }
300
+
301
+ .kpi .desc {
302
+ margin: 4px 0 0;
303
+ font-size: 0.68rem;
304
+ color: var(--silver);
305
+ }
306
+
307
+ /* ── Clickable KPIs ──────────────────────────────────────────────────────── */
308
+
309
+ .kpi-clickable {
310
+ cursor: pointer;
311
+ user-select: none;
312
+ }
313
+
314
+ .kpi-clickable:active {
315
+ background: var(--cobble);
316
+ }
317
+
318
+ .kpi-active {
319
+ border-color: var(--toxin);
320
+ box-shadow: var(--glow-mid);
321
+ background: var(--cobble);
322
+ }
323
+
324
+ /* ── Toolbar ──────────────────────────────────────────────────────────────── */
325
+
326
+ .toolbar {
327
+ display: flex;
328
+ justify-content: space-between;
329
+ align-items: center;
330
+ gap: 12px;
331
+ margin-bottom: 12px;
332
+ }
333
+
334
+ .toolbar-right {
335
+ display: flex;
336
+ align-items: center;
337
+ gap: 8px;
338
+ flex-wrap: wrap;
339
+ }
340
+
341
+ .toolbar-right label {
342
+ font-size: 0.7rem;
343
+ text-transform: uppercase;
344
+ letter-spacing: 0.06em;
345
+ color: var(--iron);
346
+ }
347
+
348
+ /* ── Form controls ────────────────────────────────────────────────────────── */
349
+
350
+ select,
351
+ input,
352
+ button {
353
+ background: var(--abyss);
354
+ color: var(--bone);
355
+ border: 1px solid var(--ash);
356
+ padding: 6px 10px;
357
+ font-size: 0.78rem;
358
+ font-family: inherit;
359
+ transition: border-color 150ms, box-shadow 150ms;
360
+ }
361
+
362
+ select:focus,
363
+ input:focus {
364
+ outline: none;
365
+ border-color: var(--toxin);
366
+ box-shadow: 0 0 0 1px var(--ooze);
367
+ }
368
+
369
+ button {
370
+ cursor: pointer;
371
+ font-weight: 500;
372
+ }
373
+
374
+ button:hover {
375
+ border-color: var(--toxin);
376
+ }
377
+
378
+ button:active {
379
+ background: var(--stone);
380
+ }
381
+
382
+ button:disabled {
383
+ opacity: 0.5;
384
+ cursor: not-allowed;
385
+ }
386
+
387
+ /* ── Issue list ───────────────────────────────────────────────────────────── */
388
+
389
+ .issue-list {
390
+ display: grid;
391
+ gap: 8px;
392
+ }
393
+
394
+ .issue-card {
395
+ border: 1px solid var(--ash);
396
+ padding: 14px;
397
+ background: var(--stone);
398
+ transition: border-color 200ms, box-shadow 200ms;
399
+ }
400
+
401
+ .issue-card:hover {
402
+ border-color: rgba(61, 255, 20, 0.2);
403
+ box-shadow: var(--glow-weak);
404
+ }
405
+
406
+ .issue-title {
407
+ margin: 0;
408
+ font-size: 0.92rem;
409
+ font-weight: 600;
410
+ color: var(--frost);
411
+ }
412
+
413
+ .issue-card > .muted {
414
+ font-size: 0.78rem;
415
+ margin-top: 6px;
416
+ color: var(--silver);
417
+ }
418
+
419
+ /* ── Meta row ─────────────────────────────────────────────────────────────── */
420
+
421
+ .meta {
422
+ margin-top: 8px;
423
+ display: flex;
424
+ gap: 8px;
425
+ flex-wrap: wrap;
426
+ align-items: center;
427
+ color: var(--iron);
428
+ font-size: 0.75rem;
429
+ }
430
+
431
+ .meta span {
432
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
433
+ font-size: 0.7rem;
434
+ }
435
+
436
+ /* ── State badges ─────────────────────────────────────────────────────────── */
437
+
438
+ .state-badge {
439
+ padding: 2px 8px;
440
+ border: 1px solid currentColor;
441
+ font-size: 0.68rem;
442
+ font-weight: 600;
443
+ text-transform: uppercase;
444
+ letter-spacing: 0.06em;
445
+ }
446
+
447
+ .state-Todo { color: var(--slate); }
448
+ .state-In_Progress { color: var(--plague); text-shadow: 0 0 8px rgba(61, 255, 20, 0.25); }
449
+ .state-In_Review { color: var(--info); }
450
+ .state-Blocked { color: var(--danger); }
451
+ .state-Done { color: var(--ok); }
452
+ .state-Cancelled { color: var(--warn); }
453
+
454
+ /* ── Tags ─────────────────────────────────────────────────────────────────── */
455
+
456
+ .tag {
457
+ border: 1px solid var(--ash);
458
+ padding: 2px 8px;
459
+ font-size: 0.68rem;
460
+ color: var(--silver);
461
+ transition: border-color 150ms;
462
+ word-break: break-all;
463
+ overflow-wrap: break-word;
464
+ max-width: 100%;
465
+ }
466
+
467
+ .tag:hover {
468
+ border-color: var(--dungeon);
469
+ }
470
+
471
+ .tag-ok {
472
+ border-color: var(--toxin);
473
+ color: var(--toxin);
474
+ }
475
+
476
+ .tag-missing {
477
+ border-color: var(--danger, #ff4444);
478
+ color: var(--danger, #ff4444);
479
+ }
480
+
481
+ /* ── Action buttons ───────────────────────────────────────────────────────── */
482
+
483
+ .actions {
484
+ margin-top: 10px;
485
+ display: flex;
486
+ flex-wrap: wrap;
487
+ gap: 6px;
488
+ align-items: center;
489
+ }
490
+
491
+ .action-button {
492
+ background: var(--cobble);
493
+ color: var(--slate);
494
+ border: 1px solid var(--ash);
495
+ padding: 4px 10px;
496
+ font-size: 0.7rem;
497
+ font-weight: 500;
498
+ text-transform: uppercase;
499
+ letter-spacing: 0.04em;
500
+ cursor: pointer;
501
+ transition: border-color 150ms, color 150ms, box-shadow 150ms;
502
+ }
503
+
504
+ .action-button:hover {
505
+ border-color: var(--toxin);
506
+ color: var(--frost);
507
+ box-shadow: var(--glow-weak);
508
+ }
509
+
510
+ .action-button:active {
511
+ background: var(--dungeon);
512
+ }
513
+
514
+ .action-button:disabled {
515
+ opacity: 0.5;
516
+ cursor: not-allowed;
517
+ box-shadow: none;
518
+ }
519
+
520
+ /* ── More button (secondary actions toggle) ──────────────────────────────── */
521
+
522
+ .btn-more {
523
+ background: var(--cobble);
524
+ color: var(--iron);
525
+ border: 1px solid var(--ash);
526
+ padding: 4px 8px;
527
+ font-size: 0.8rem;
528
+ font-weight: 700;
529
+ cursor: pointer;
530
+ letter-spacing: 0.1em;
531
+ line-height: 1;
532
+ min-width: 28px;
533
+ text-align: center;
534
+ }
535
+
536
+ .btn-more:hover {
537
+ border-color: var(--toxin);
538
+ color: var(--frost);
539
+ }
540
+
541
+ /* ── Secondary actions (hidden by default) ───────────────────────────────── */
542
+
543
+ .actions-secondary {
544
+ display: none;
545
+ gap: 6px;
546
+ flex-wrap: wrap;
547
+ }
548
+
549
+ .actions-secondary.actions-secondary-visible {
550
+ display: flex;
551
+ }
552
+
553
+ /* ── History list ─────────────────────────────────────────────────────────── */
554
+
555
+ .history {
556
+ margin: 8px 0 0;
557
+ padding: 0;
558
+ list-style: none;
559
+ font-size: 0.7rem;
560
+ color: var(--iron);
561
+ }
562
+
563
+ .history li {
564
+ padding: 2px 0;
565
+ border-bottom: 1px solid rgba(52, 64, 52, 0.4);
566
+ word-break: break-word;
567
+ overflow-wrap: break-word;
568
+ }
569
+
570
+ .history li:last-child {
571
+ border-bottom: none;
572
+ }
573
+
574
+ /* ── Mono utility ─────────────────────────────────────────────────────────── */
575
+
576
+ .mono {
577
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
578
+ }
579
+
580
+ /* ── Events panel ─────────────────────────────────────────────────────────── */
581
+
582
+ .events {
583
+ max-height: 320px;
584
+ overflow: auto;
585
+ display: grid;
586
+ gap: 6px;
587
+ }
588
+
589
+ .event {
590
+ background: var(--stone);
591
+ border: 1px solid var(--ash);
592
+ border-left: 3px solid var(--iron);
593
+ padding: 8px 10px;
594
+ font-size: 0.78rem;
595
+ transition: border-color 150ms;
596
+ }
597
+
598
+ .event:hover {
599
+ border-color: var(--dungeon);
600
+ }
601
+
602
+ .event .mono {
603
+ font-size: 0.68rem;
604
+ color: var(--iron);
605
+ margin-bottom: 2px;
606
+ }
607
+
608
+ .event-runner { border-left-color: var(--plague); }
609
+ .event-error { border-left-color: var(--danger); }
610
+ .event-manual { border-left-color: var(--info); }
611
+ .event-progress { border-left-color: var(--warn); }
612
+ .event-info { border-left-color: var(--iron); }
613
+
614
+ /* ── Toast notification ───────────────────────────────────────────────────── */
615
+
616
+ .toast {
617
+ position: fixed;
618
+ bottom: 20px;
619
+ right: 20px;
620
+ z-index: 100;
621
+ display: flex;
622
+ flex-direction: column;
623
+ gap: 8px;
624
+ pointer-events: none;
625
+ }
626
+
627
+ .toast-item {
628
+ background: var(--stone);
629
+ border: 1px solid var(--danger);
630
+ padding: 10px 16px;
631
+ font-size: 0.78rem;
632
+ color: var(--frost);
633
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
634
+ pointer-events: auto;
635
+ animation: toast-in 200ms ease-out;
636
+ max-width: 360px;
637
+ }
638
+
639
+ .toast-item.toast-success {
640
+ border-color: var(--ok);
641
+ }
642
+
643
+ .toast-item.toast-warn {
644
+ border-color: var(--warn);
645
+ }
646
+
647
+ @keyframes toast-in {
648
+ from {
649
+ opacity: 0;
650
+ transform: translateY(8px);
651
+ }
652
+ to {
653
+ opacity: 1;
654
+ transform: translateY(0);
655
+ }
656
+ }
657
+
658
+ .toast-item.toast-out {
659
+ animation: toast-out 150ms ease-in forwards;
660
+ }
661
+
662
+ @keyframes toast-out {
663
+ to {
664
+ opacity: 0;
665
+ transform: translateY(-4px);
666
+ }
667
+ }
668
+
669
+ /* ── Loading skeleton ─────────────────────────────────────────────────────── */
670
+
671
+ .skeleton {
672
+ background: linear-gradient(
673
+ 90deg,
674
+ var(--stone) 25%,
675
+ var(--cobble) 50%,
676
+ var(--stone) 75%
677
+ );
678
+ background-size: 200% 100%;
679
+ animation: shimmer 1.5s infinite;
680
+ height: 1em;
681
+ }
682
+
683
+ @keyframes shimmer {
684
+ 0% { background-position: 200% 0; }
685
+ 100% { background-position: -200% 0; }
686
+ }
687
+
688
+ /* ── Accent button ────────────────────────────────────────────────────────── */
689
+
690
+ .btn-accent {
691
+ background: var(--mold);
692
+ color: var(--plague);
693
+ border: 1px solid var(--ooze);
694
+ font-weight: 600;
695
+ letter-spacing: 0.04em;
696
+ }
697
+
698
+ .btn-accent:hover {
699
+ border-color: var(--toxin);
700
+ box-shadow: var(--glow-weak);
701
+ }
702
+
703
+ .btn-accent:disabled {
704
+ opacity: 0.4;
705
+ cursor: not-allowed;
706
+ }
707
+
708
+ /* ── Create issue form ────────────────────────────────────────────────────── */
709
+
710
+ .create-form {
711
+ background: var(--stone);
712
+ border: 1px solid var(--ash);
713
+ padding: 14px;
714
+ margin-bottom: 12px;
715
+ }
716
+
717
+ .create-form-grid {
718
+ display: grid;
719
+ grid-template-columns: 1fr 1fr;
720
+ gap: 10px;
721
+ }
722
+
723
+ .create-form-grid .span-2 {
724
+ grid-column: span 2;
725
+ }
726
+
727
+ .form-group label {
728
+ display: block;
729
+ font-size: 0.68rem;
730
+ text-transform: uppercase;
731
+ letter-spacing: 0.06em;
732
+ color: var(--iron);
733
+ margin-bottom: 4px;
734
+ }
735
+
736
+ .form-group .hint {
737
+ text-transform: none;
738
+ letter-spacing: normal;
739
+ color: var(--ash);
740
+ }
741
+
742
+ .form-group input,
743
+ .form-group textarea {
744
+ width: 100%;
745
+ background: var(--abyss);
746
+ color: var(--bone);
747
+ border: 1px solid var(--ash);
748
+ padding: 6px 10px;
749
+ font-size: 0.78rem;
750
+ font-family: inherit;
751
+ }
752
+
753
+ .form-group textarea {
754
+ resize: vertical;
755
+ min-height: 40px;
756
+ }
757
+
758
+ .create-form-actions {
759
+ display: flex;
760
+ justify-content: flex-end;
761
+ gap: 8px;
762
+ margin-top: 12px;
763
+ }
764
+
765
+ /* ── Error detail (collapsible in issue card) ─────────────────────────────── */
766
+
767
+ .error-detail {
768
+ margin-top: 8px;
769
+ }
770
+
771
+ .error-detail summary {
772
+ cursor: pointer;
773
+ font-size: 0.7rem;
774
+ font-weight: 600;
775
+ color: var(--danger);
776
+ text-transform: uppercase;
777
+ letter-spacing: 0.04em;
778
+ list-style: none;
779
+ user-select: none;
780
+ }
781
+
782
+ .error-detail summary::before {
783
+ content: "▸ ";
784
+ }
785
+
786
+ .error-detail[open] summary::before {
787
+ content: "▾ ";
788
+ }
789
+
790
+ .error-detail pre {
791
+ margin: 6px 0 0;
792
+ padding: 8px 10px;
793
+ background: var(--abyss);
794
+ border: 1px solid rgba(251, 113, 133, 0.2);
795
+ color: var(--slate);
796
+ font-size: 0.7rem;
797
+ white-space: pre-wrap;
798
+ word-break: break-word;
799
+ max-height: 200px;
800
+ overflow: auto;
801
+ line-height: 1.5;
802
+ }
803
+
804
+ /* ── Blocked-by indicator ─────────────────────────────────────────────────── */
805
+
806
+ .blocked-by {
807
+ display: inline-flex;
808
+ align-items: center;
809
+ gap: 4px;
810
+ font-size: 0.68rem;
811
+ color: var(--danger);
812
+ padding: 2px 8px;
813
+ border: 1px solid rgba(251, 113, 133, 0.3);
814
+ }
815
+
816
+ .blocked-by::before {
817
+ content: "⛓";
818
+ font-size: 0.6rem;
819
+ }
820
+
821
+ /* ── Note/comment input ───────────────────────────────────────────────────── */
822
+
823
+ .note-form {
824
+ margin-top: 8px;
825
+ display: flex;
826
+ gap: 6px;
827
+ }
828
+
829
+ .note-form input {
830
+ flex: 1;
831
+ background: var(--abyss);
832
+ color: var(--bone);
833
+ border: 1px solid var(--ash);
834
+ padding: 4px 8px;
835
+ font-size: 0.72rem;
836
+ }
837
+
838
+ .note-form input::placeholder {
839
+ color: var(--ash);
840
+ }
841
+
842
+ /* ── Session/pipeline detail panel ────────────────────────────────────────── */
843
+
844
+ .session-panel {
845
+ margin-top: 10px;
846
+ background: var(--abyss);
847
+ border: 1px solid var(--ash);
848
+ padding: 10px;
849
+ max-height: 300px;
850
+ overflow: auto;
851
+ }
852
+
853
+ .session-panel .session-header {
854
+ font-size: 0.7rem;
855
+ font-weight: 600;
856
+ text-transform: uppercase;
857
+ letter-spacing: 0.04em;
858
+ color: var(--iron);
859
+ margin-bottom: 8px;
860
+ }
861
+
862
+ .session-panel .pipeline-step {
863
+ display: flex;
864
+ gap: 8px;
865
+ align-items: center;
866
+ padding: 4px 0;
867
+ border-bottom: 1px solid rgba(52, 64, 52, 0.3);
868
+ font-size: 0.72rem;
869
+ }
870
+
871
+ .session-panel .pipeline-step:last-child {
872
+ border-bottom: none;
873
+ }
874
+
875
+ .session-panel .step-provider {
876
+ color: var(--plague);
877
+ font-weight: 600;
878
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
879
+ font-size: 0.68rem;
880
+ }
881
+
882
+ .session-panel .step-status {
883
+ color: var(--silver);
884
+ }
885
+
886
+ .session-panel .step-duration {
887
+ color: var(--iron);
888
+ margin-left: auto;
889
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
890
+ font-size: 0.68rem;
891
+ }
892
+
893
+ .session-panel .session-output {
894
+ margin-top: 8px;
895
+ padding: 8px;
896
+ background: var(--crypt);
897
+ border: 1px solid var(--ash);
898
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
899
+ font-size: 0.68rem;
900
+ color: var(--slate);
901
+ white-space: pre-wrap;
902
+ word-break: break-word;
903
+ max-height: 180px;
904
+ overflow: auto;
905
+ line-height: 1.5;
906
+ }
907
+
908
+ .session-loading {
909
+ text-align: center;
910
+ padding: 12px;
911
+ color: var(--iron);
912
+ font-size: 0.72rem;
913
+ }
914
+
915
+ /* ── Edit form (inline, reuses create-form-grid) ──────────────────────────── */
916
+
917
+ .edit-form {
918
+ margin-top: 10px;
919
+ background: var(--abyss);
920
+ border: 1px solid var(--ash);
921
+ padding: 12px;
922
+ }
923
+
924
+ /* ── Delete confirmation ──────────────────────────────────────────────────── */
925
+
926
+ .delete-confirm {
927
+ margin-top: 8px;
928
+ display: flex;
929
+ align-items: center;
930
+ gap: 8px;
931
+ padding: 8px 10px;
932
+ background: rgba(251, 113, 133, 0.06);
933
+ border: 1px solid rgba(251, 113, 133, 0.25);
934
+ font-size: 0.72rem;
935
+ color: var(--danger);
936
+ }
937
+
938
+ .btn-danger {
939
+ background: rgba(251, 113, 133, 0.15);
940
+ color: var(--danger);
941
+ border: 1px solid var(--danger);
942
+ font-weight: 600;
943
+ }
944
+
945
+ .btn-danger:hover {
946
+ background: rgba(251, 113, 133, 0.25);
947
+ }
948
+
949
+ /* ── Concurrency inline control ───────────────────────────────────────────── */
950
+
951
+ .concurrency-control {
952
+ display: inline-flex;
953
+ align-items: center;
954
+ gap: 4px;
955
+ }
956
+
957
+ .concurrency-input {
958
+ width: 48px;
959
+ padding: 2px 4px;
960
+ font-size: 0.72rem;
961
+ text-align: center;
962
+ }
963
+
964
+ .concurrency-btn {
965
+ font-size: 0.7em;
966
+ }
967
+
968
+ /* ── Progress bar ─────────────────────────────────────────────────────────── */
969
+
970
+ .progress-bar {
971
+ display: flex;
972
+ height: 4px;
973
+ background: var(--stone);
974
+ margin-top: 8px;
975
+ overflow: hidden;
976
+ }
977
+
978
+ .progress-segment {
979
+ height: 100%;
980
+ transition: width 300ms ease;
981
+ }
982
+
983
+ .progress-done { background: var(--ok); }
984
+ .progress-running { background: var(--plague); }
985
+ .progress-blocked { background: var(--danger); }
986
+
987
+ /* ── Split form (inline in issue card) ────────────────────────────────────── */
988
+
989
+ .split-form {
990
+ margin-top: 10px;
991
+ background: var(--abyss);
992
+ border: 1px solid var(--ash);
993
+ padding: 10px;
994
+ }
995
+
996
+ .split-label {
997
+ display: block;
998
+ font-size: 0.68rem;
999
+ text-transform: uppercase;
1000
+ letter-spacing: 0.06em;
1001
+ color: var(--iron);
1002
+ margin-bottom: 6px;
1003
+ }
1004
+
1005
+ .split-form textarea {
1006
+ width: 100%;
1007
+ background: var(--crypt);
1008
+ color: var(--bone);
1009
+ border: 1px solid var(--ash);
1010
+ padding: 8px 10px;
1011
+ font-size: 0.78rem;
1012
+ font-family: inherit;
1013
+ resize: vertical;
1014
+ min-height: 60px;
1015
+ }
1016
+
1017
+ .split-form-actions {
1018
+ display: flex;
1019
+ justify-content: flex-end;
1020
+ gap: 6px;
1021
+ margin-top: 8px;
1022
+ }
1023
+
1024
+ /* ── Selected issue (detail panel active) ─────────────────────────────────── */
1025
+
1026
+ .issue-selected {
1027
+ border-color: var(--toxin);
1028
+ background: var(--cobble);
1029
+ }
1030
+
1031
+ /* ── Running issue pulse ──────────────────────────────────────────────────── */
1032
+
1033
+ .issue-running {
1034
+ border-left: 3px solid var(--plague);
1035
+ animation: running-pulse 3s ease-in-out infinite;
1036
+ }
1037
+
1038
+ @keyframes running-pulse {
1039
+ 0%, 100% { border-left-color: var(--plague); box-shadow: none; }
1040
+ 50% { border-left-color: var(--blight); box-shadow: inset 3px 0 8px -4px rgba(61, 255, 20, 0.15); }
1041
+ }
1042
+
1043
+ /* ── History collapsible ──────────────────────────────────────────────────── */
1044
+
1045
+ .history-detail {
1046
+ margin-top: 4px;
1047
+ }
1048
+
1049
+ .history-detail summary {
1050
+ cursor: pointer;
1051
+ font-size: 0.65rem;
1052
+ color: var(--iron);
1053
+ list-style: none;
1054
+ user-select: none;
1055
+ }
1056
+
1057
+ .history-detail summary::before {
1058
+ content: "▸ ";
1059
+ }
1060
+
1061
+ .history-detail[open] summary::before {
1062
+ content: "▾ ";
1063
+ }
1064
+
1065
+ .history-detail .history {
1066
+ margin-top: 4px;
1067
+ }
1068
+
1069
+ /* ── Collapsed section ────────────────────────────────────────────────────── */
1070
+
1071
+ .collapsed-section details summary {
1072
+ cursor: pointer;
1073
+ list-style: none;
1074
+ user-select: none;
1075
+ }
1076
+
1077
+ .collapsed-section details summary::before {
1078
+ content: "▸ ";
1079
+ color: var(--iron);
1080
+ }
1081
+
1082
+ .collapsed-section details[open] summary::before {
1083
+ content: "▾ ";
1084
+ }
1085
+
1086
+ /* ── Two-panel layout (desktop >= 900px) ─────────────────────────────────── */
1087
+
1088
+ .issues-master-detail {
1089
+ display: block;
1090
+ }
1091
+
1092
+ .detail-panel {
1093
+ display: none;
1094
+ }
1095
+
1096
+ .detail-placeholder {
1097
+ text-align: center;
1098
+ padding: 32px 16px;
1099
+ color: var(--iron);
1100
+ font-size: 0.78rem;
1101
+ }
1102
+
1103
+ .detail-panel .detail-issue-header {
1104
+ display: flex;
1105
+ align-items: center;
1106
+ gap: 8px;
1107
+ font-size: 0.78rem;
1108
+ font-weight: 600;
1109
+ color: var(--frost);
1110
+ margin: 0 0 10px;
1111
+ padding-bottom: 8px;
1112
+ border-bottom: 1px solid var(--ash);
1113
+ }
1114
+
1115
+ .detail-panel .detail-issue-header .mono {
1116
+ color: var(--plague);
1117
+ font-size: 0.72rem;
1118
+ }
1119
+
1120
+ .btn-close-detail {
1121
+ margin-left: auto;
1122
+ background: transparent;
1123
+ border: 1px solid var(--ash);
1124
+ color: var(--iron);
1125
+ font-size: 1rem;
1126
+ line-height: 1;
1127
+ padding: 2px 6px;
1128
+ cursor: pointer;
1129
+ }
1130
+
1131
+ .btn-close-detail:hover {
1132
+ color: var(--frost);
1133
+ border-color: var(--toxin);
1134
+ }
1135
+
1136
+ .detail-panel .session-panel {
1137
+ margin-top: 0;
1138
+ max-height: none;
1139
+ border: none;
1140
+ padding: 0;
1141
+ background: transparent;
1142
+ }
1143
+
1144
+ @media (min-width: 900px) {
1145
+ .shell {
1146
+ max-width: 1400px;
1147
+ }
1148
+
1149
+ .issues-master-detail {
1150
+ display: grid;
1151
+ grid-template-columns: 60% 40%;
1152
+ gap: 0;
1153
+ }
1154
+
1155
+ .master-panel {
1156
+ border-right: 1px solid var(--ash);
1157
+ padding-right: 16px;
1158
+ max-height: 80vh;
1159
+ overflow-y: auto;
1160
+ }
1161
+
1162
+ .detail-panel {
1163
+ display: block;
1164
+ padding-left: 16px;
1165
+ position: sticky;
1166
+ top: 0;
1167
+ max-height: 80vh;
1168
+ overflow-y: auto;
1169
+ }
1170
+
1171
+ /* Hide inline session panels on desktop */
1172
+ .issue-card .session-panel {
1173
+ display: none;
1174
+ }
1175
+ }
1176
+
1177
+ /* ── Responsive ───────────────────────────────────────────────────────────── */
1178
+
1179
+ @media (max-width: 899px) {
1180
+
1181
+ /* ── Shell & topbar ────────────────────────────────────────────────────── */
1182
+
1183
+ .shell {
1184
+ padding: 10px;
1185
+ }
1186
+
1187
+ .topbar {
1188
+ flex-direction: column;
1189
+ align-items: flex-start;
1190
+ }
1191
+
1192
+ .badges {
1193
+ flex-wrap: wrap;
1194
+ width: 100%;
1195
+ }
1196
+
1197
+ /* Truncate subtitle on narrow screens */
1198
+ #subtitle {
1199
+ overflow: hidden;
1200
+ text-overflow: ellipsis;
1201
+ white-space: nowrap;
1202
+ max-width: 100%;
1203
+ }
1204
+
1205
+ h1 {
1206
+ font-size: 0.95rem;
1207
+ }
1208
+
1209
+ /* ── Toolbar & filters ─────────────────────────────────────────────────── */
1210
+
1211
+ .toolbar {
1212
+ flex-direction: column;
1213
+ align-items: flex-start;
1214
+ }
1215
+
1216
+ .toolbar-right {
1217
+ width: 100%;
1218
+ flex-direction: column;
1219
+ align-items: stretch;
1220
+ }
1221
+
1222
+ .toolbar-right label {
1223
+ margin-top: 4px;
1224
+ }
1225
+
1226
+ .toolbar-right select,
1227
+ .toolbar-right input {
1228
+ width: 100%;
1229
+ min-height: 44px;
1230
+ }
1231
+
1232
+ .toolbar-right button {
1233
+ width: 100%;
1234
+ min-height: 44px;
1235
+ }
1236
+
1237
+ /* Make "+ New" prominent on mobile */
1238
+ .toolbar-right .btn-accent {
1239
+ font-size: 0.88rem;
1240
+ padding: 10px;
1241
+ }
1242
+
1243
+ /* ── KPI grid ──────────────────────────────────────────────────────────── */
1244
+
1245
+ .grid {
1246
+ grid-template-columns: repeat(2, 1fr);
1247
+ }
1248
+
1249
+ .kpi {
1250
+ padding: 12px 8px;
1251
+ min-height: 0;
1252
+ overflow: hidden;
1253
+ }
1254
+
1255
+ .kpi .value {
1256
+ font-size: 1.5rem;
1257
+ }
1258
+
1259
+ .kpi .label {
1260
+ font-size: 0.6rem;
1261
+ word-break: break-word;
1262
+ }
1263
+
1264
+ .kpi .desc {
1265
+ font-size: 0.6rem;
1266
+ word-break: break-word;
1267
+ }
1268
+
1269
+ /* ── Issue cards ────────────────────────────────────────────────────────── */
1270
+
1271
+ .issue-card {
1272
+ padding: 10px;
1273
+ }
1274
+
1275
+ /* 1. Issue title with checkbox: prevent overflow, wrap properly */
1276
+ .issue-title {
1277
+ font-size: 0.84rem;
1278
+ display: flex;
1279
+ align-items: flex-start;
1280
+ gap: 6px;
1281
+ word-break: break-word;
1282
+ overflow-wrap: break-word;
1283
+ }
1284
+
1285
+ .issue-title .issue-select {
1286
+ flex-shrink: 0;
1287
+ margin-right: 0;
1288
+ /* 44px touch target for checkbox */
1289
+ min-width: 44px;
1290
+ min-height: 44px;
1291
+ justify-content: center;
1292
+ }
1293
+
1294
+ .issue-card > .muted {
1295
+ font-size: 0.72rem;
1296
+ }
1297
+
1298
+ .meta {
1299
+ font-size: 0.7rem;
1300
+ }
1301
+
1302
+ /* ── Action buttons: 44px touch targets, full-width stacked ────────── */
1303
+
1304
+ .actions {
1305
+ flex-direction: column;
1306
+ }
1307
+
1308
+ .actions .action-button {
1309
+ width: 100%;
1310
+ text-align: center;
1311
+ min-height: 44px;
1312
+ padding: 10px;
1313
+ font-size: 0.76rem;
1314
+ }
1315
+
1316
+ .actions .btn-more {
1317
+ width: 100%;
1318
+ text-align: center;
1319
+ min-height: 44px;
1320
+ padding: 10px;
1321
+ font-size: 0.88rem;
1322
+ }
1323
+
1324
+ /* 3. Secondary actions: full-width stacked column */
1325
+ .actions-secondary {
1326
+ width: 100%;
1327
+ flex-direction: column;
1328
+ }
1329
+
1330
+ .actions-secondary .action-button {
1331
+ width: 100%;
1332
+ text-align: center;
1333
+ }
1334
+
1335
+ /* ── 2. Batch toolbar: full-width stacked ──────────────────────────── */
1336
+
1337
+ .issue-count {
1338
+ width: 100%;
1339
+ flex-direction: column;
1340
+ align-items: stretch;
1341
+ }
1342
+
1343
+ .issue-count .action-button {
1344
+ width: 100%;
1345
+ min-height: 44px;
1346
+ text-align: center;
1347
+ padding: 10px;
1348
+ }
1349
+
1350
+ /* ── 4. Note form: send button full-width ──────────────────────────── */
1351
+
1352
+ .note-form {
1353
+ flex-direction: column;
1354
+ }
1355
+
1356
+ .note-form input {
1357
+ min-height: 44px;
1358
+ }
1359
+
1360
+ .note-form .action-button {
1361
+ width: 100%;
1362
+ min-height: 44px;
1363
+ text-align: center;
1364
+ }
1365
+
1366
+ /* ── 5. Split form: textarea + buttons full-width ──────────────────── */
1367
+
1368
+ .split-form textarea {
1369
+ min-height: 80px;
1370
+ }
1371
+
1372
+ .split-form-actions {
1373
+ flex-direction: column;
1374
+ }
1375
+
1376
+ .split-form-actions .action-button {
1377
+ width: 100%;
1378
+ min-height: 44px;
1379
+ text-align: center;
1380
+ }
1381
+
1382
+ /* ── 6. Edit form & Create form ────────────────────────────────────── */
1383
+
1384
+ .create-form-grid {
1385
+ grid-template-columns: 1fr;
1386
+ }
1387
+
1388
+ .create-form-grid .span-2 {
1389
+ grid-column: span 1;
1390
+ }
1391
+
1392
+ .create-form {
1393
+ padding: 10px;
1394
+ }
1395
+
1396
+ .create-form-actions {
1397
+ flex-direction: column;
1398
+ }
1399
+
1400
+ .create-form-actions button,
1401
+ .create-form-actions .action-button {
1402
+ width: 100%;
1403
+ min-height: 44px;
1404
+ text-align: center;
1405
+ }
1406
+
1407
+ .edit-form {
1408
+ padding: 10px;
1409
+ }
1410
+
1411
+ .form-group input,
1412
+ .form-group textarea {
1413
+ min-height: 44px;
1414
+ }
1415
+
1416
+ /* ── 7. Delete confirm: stacked, full-width buttons ────────────────── */
1417
+
1418
+ .delete-confirm {
1419
+ flex-direction: column;
1420
+ align-items: stretch;
1421
+ }
1422
+
1423
+ .delete-confirm button,
1424
+ .delete-confirm .action-button {
1425
+ width: 100%;
1426
+ min-height: 44px;
1427
+ text-align: center;
1428
+ }
1429
+
1430
+ /* ── 8. Session panel: inline on mobile with scroll ────────────────── */
1431
+
1432
+ .session-panel {
1433
+ max-height: 50vh;
1434
+ overflow-y: auto;
1435
+ -webkit-overflow-scrolling: touch;
1436
+ }
1437
+
1438
+ .session-panel .pipeline-step {
1439
+ flex-wrap: wrap;
1440
+ gap: 4px;
1441
+ }
1442
+
1443
+ .session-panel .step-duration {
1444
+ margin-left: 0;
1445
+ width: 100%;
1446
+ }
1447
+
1448
+ /* ── 10. Event cards: prevent text overflow ─────────────────────────── */
1449
+
1450
+ .events {
1451
+ max-height: 200px;
1452
+ }
1453
+
1454
+ .event {
1455
+ overflow: hidden;
1456
+ }
1457
+
1458
+ .event .mono {
1459
+ word-break: break-all;
1460
+ overflow-wrap: break-word;
1461
+ }
1462
+
1463
+ .event > div:last-child {
1464
+ word-break: break-word;
1465
+ overflow-wrap: break-word;
1466
+ }
1467
+
1468
+ /* ── 15. Detail panel: hidden on mobile ────────────────────────────── */
1469
+ /* Already display:none by default (no min-width:900px) — reinforce */
1470
+
1471
+ .detail-panel {
1472
+ display: none !important;
1473
+ }
1474
+
1475
+ /* ── 18. History entries: wrap long mono text ───────────────────────── */
1476
+
1477
+ .history li {
1478
+ word-break: break-word;
1479
+ overflow-wrap: break-word;
1480
+ }
1481
+
1482
+ /* ── 19. Toast: bottom-center on mobile with safe margin ───────────── */
1483
+
1484
+ .toast {
1485
+ bottom: 24px;
1486
+ right: 10px;
1487
+ left: 10px;
1488
+ align-items: stretch;
1489
+ }
1490
+
1491
+ .toast-item {
1492
+ max-width: none;
1493
+ text-align: center;
1494
+ }
1495
+
1496
+ /* ── 20. Master panel: no max-height on mobile (full page scroll) ──── */
1497
+
1498
+ .master-panel {
1499
+ max-height: none;
1500
+ overflow-y: visible;
1501
+ }
1502
+
1503
+ /* ── General touch targets: all standalone buttons ─────────────────── */
1504
+
1505
+ button {
1506
+ min-height: 44px;
1507
+ }
1508
+
1509
+ select {
1510
+ min-height: 44px;
1511
+ }
1512
+
1513
+ /* ── Concurrency control on mobile ─────────────────────────────────── */
1514
+
1515
+ .concurrency-control {
1516
+ flex-wrap: wrap;
1517
+ width: 100%;
1518
+ }
1519
+
1520
+ .concurrency-input {
1521
+ min-height: 44px;
1522
+ width: 64px;
1523
+ }
1524
+
1525
+ .concurrency-btn {
1526
+ min-height: 44px;
1527
+ }
1528
+ }