@levistudio/redline 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,994 @@
1
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
2
+
3
+ :root {
4
+ --bg: #fafaf8;
5
+ --surface: #ffffff;
6
+ --border: #e8e6e1;
7
+ --text: #1a1a1a;
8
+ --text-muted: #6b6b6b;
9
+ --accent: #d97706;
10
+ --accent-light: #fff7ed;
11
+ --highlight: #fff3cd;
12
+ --highlight-active: #ffe8a0;
13
+ --thread-bg: #f7f7f5;
14
+ --agent-bg: #f0f4ff;
15
+ --radius: 6px;
16
+ --shadow: 0 1px 4px rgba(0,0,0,0.08), 0 4px 16px rgba(0,0,0,0.06);
17
+ }
18
+
19
+ body {
20
+ background: var(--bg);
21
+ color: var(--text);
22
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
23
+ font-size: 16px;
24
+ line-height: 1.7;
25
+ }
26
+
27
+ /* ── Layout ── */
28
+ .layout {
29
+ display: flex;
30
+ max-width: 1160px;
31
+ margin: 0 auto;
32
+ padding: 48px 24px;
33
+ gap: 32px;
34
+ align-items: stretch;
35
+ }
36
+
37
+ .reader-col {
38
+ flex: 1;
39
+ min-width: 0;
40
+ }
41
+
42
+ .sidebar-col {
43
+ width: 300px;
44
+ flex-shrink: 0;
45
+ position: relative;
46
+ }
47
+
48
+ /* ── Header ── */
49
+ .doc-header {
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: space-between;
53
+ margin-bottom: 32px;
54
+ }
55
+
56
+ .doc-title {
57
+ font-size: 13px;
58
+ font-weight: 500;
59
+ color: var(--text-muted);
60
+ letter-spacing: 0.02em;
61
+ text-transform: uppercase;
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 10px;
65
+ }
66
+
67
+ .round-badge {
68
+ font-size: 11px;
69
+ font-weight: 600;
70
+ padding: 2px 8px;
71
+ border-radius: 10px;
72
+ background: var(--thread-bg);
73
+ border: 1px solid var(--border);
74
+ color: var(--text-muted);
75
+ text-transform: none;
76
+ letter-spacing: 0;
77
+ white-space: nowrap;
78
+ }
79
+ .round-badge.repeat {
80
+ background: #fff3e0;
81
+ border-color: #ffcc80;
82
+ color: #e65100;
83
+ }
84
+ .round-badge.clickable { cursor: pointer; user-select: none; }
85
+ .round-badge.clickable:hover { filter: brightness(0.95); }
86
+
87
+ .round-picker {
88
+ position: absolute;
89
+ top: calc(100% + 8px);
90
+ left: 0;
91
+ background: white;
92
+ border: 1px solid var(--border);
93
+ border-radius: var(--radius);
94
+ box-shadow: var(--shadow);
95
+ z-index: 50;
96
+ min-width: 220px;
97
+ overflow: hidden;
98
+ }
99
+ .round-picker-item {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 10px;
103
+ padding: 9px 14px;
104
+ font-size: 13px;
105
+ color: var(--text);
106
+ text-decoration: none;
107
+ border-bottom: 1px solid var(--border);
108
+ }
109
+ .round-picker-item:last-child { border-bottom: none; }
110
+ .round-picker-item:hover { background: var(--thread-bg); }
111
+ .round-picker-item.current { font-weight: 600; pointer-events: none; color: var(--text-muted); }
112
+ .round-picker-meta { font-size: 11px; color: var(--text-muted); margin-left: auto; }
113
+
114
+ .btn-resolve {
115
+ background: var(--accent);
116
+ color: white;
117
+ border: none;
118
+ padding: 8px 18px;
119
+ border-radius: var(--radius);
120
+ font-size: 14px;
121
+ font-weight: 500;
122
+ cursor: pointer;
123
+ transition: opacity 0.15s;
124
+ }
125
+ .btn-resolve:hover { opacity: 0.85; }
126
+ .btn-resolve:disabled { opacity: 0.4; cursor: default; }
127
+
128
+ .btn-accept {
129
+ background: white;
130
+ color: #374151;
131
+ border: 1.5px solid #d1d5db;
132
+ padding: 8px 18px;
133
+ border-radius: var(--radius);
134
+ font-size: 14px;
135
+ font-weight: 500;
136
+ cursor: pointer;
137
+ transition: border-color 0.15s, color 0.15s;
138
+ min-width: 168px;
139
+ text-align: center;
140
+ }
141
+ .btn-accept:hover:not(:disabled) { border-color: #9ca3af; color: #111827; }
142
+ .btn-accept:disabled { opacity: 0.4; cursor: default; }
143
+
144
+ .header-actions { display: flex; gap: 8px; align-items: center; }
145
+
146
+ /* Asymmetric status: hidden when healthy, visible only when the agent process
147
+ is gone for good. Recovery requires restarting redline, so no green/clear
148
+ counterpart — absence is the signal. */
149
+ .agent-status[hidden] { display: none; }
150
+ .agent-status {
151
+ display: inline-flex;
152
+ align-items: center;
153
+ gap: 6px;
154
+ padding: 4px 10px;
155
+ font-size: 12px;
156
+ font-weight: 500;
157
+ color: #b71c1c;
158
+ background: #fef2f2;
159
+ border: 1px solid #fecaca;
160
+ border-radius: 12px;
161
+ cursor: help;
162
+ user-select: none;
163
+ }
164
+ .agent-status::before {
165
+ content: "";
166
+ display: inline-block;
167
+ width: 7px;
168
+ height: 7px;
169
+ border-radius: 50%;
170
+ background: #b71c1c;
171
+ }
172
+
173
+ /* Persistent neutral pill for --no-agent runs. Communicates "this session is
174
+ intentionally agent-less", distinct from the asymmetric error variant above. */
175
+ .manual-mode-pill {
176
+ display: inline-flex;
177
+ align-items: center;
178
+ padding: 4px 10px;
179
+ font-size: 12px;
180
+ font-weight: 500;
181
+ color: var(--text-muted);
182
+ background: #f3f4f6;
183
+ border: 1px solid #d1d5db;
184
+ border-radius: 12px;
185
+ cursor: help;
186
+ user-select: none;
187
+ }
188
+
189
+ /* ── Prose ── */
190
+ .prose {
191
+ background: var(--surface);
192
+ border: 1px solid var(--border);
193
+ border-radius: var(--radius);
194
+ padding: 48px 56px;
195
+ user-select: text;
196
+ }
197
+
198
+ .prose h1, .prose h2, .prose h3, .prose h4 {
199
+ font-weight: 600;
200
+ line-height: 1.3;
201
+ margin: 1.8em 0 0.6em;
202
+ color: var(--text);
203
+ }
204
+ .prose h1 { font-size: 1.9em; margin-top: 0; }
205
+ .prose h2 { font-size: 1.4em; border-bottom: 1px solid var(--border); padding-bottom: 0.3em; }
206
+ .prose h3 { font-size: 1.22em; margin-top: 2em; }
207
+ .prose h4 {
208
+ font-size: 0.85em;
209
+ margin-top: 1.6em;
210
+ text-transform: uppercase;
211
+ letter-spacing: 0.06em;
212
+ color: var(--text-muted);
213
+ }
214
+
215
+ .prose p { margin: 0.9em 0; }
216
+ .prose img { max-width: 100%; height: auto; display: block; margin: 1.2em auto; border-radius: 4px; }
217
+ .prose .broken-img {
218
+ display: block;
219
+ padding: 14px 18px;
220
+ margin: 1.2em auto;
221
+ background: var(--thread-bg);
222
+ border: 1px dashed var(--border);
223
+ border-radius: 4px;
224
+ font-size: 13px;
225
+ color: var(--text-muted);
226
+ text-align: center;
227
+ font-style: italic;
228
+ }
229
+ .prose ul, .prose ol { margin: 0.9em 0; padding-left: 1.6em; }
230
+ .prose li { margin: 0.3em 0; }
231
+ .prose li:has(> input[type="checkbox"]) { list-style: none; margin-left: -1.4em; }
232
+ .prose li > input[type="checkbox"] {
233
+ appearance: none;
234
+ -webkit-appearance: none;
235
+ width: 14px; height: 14px;
236
+ border: 1.5px solid #c5c5bf;
237
+ border-radius: 3px;
238
+ vertical-align: -2px;
239
+ margin-right: 7px;
240
+ cursor: default;
241
+ background: white;
242
+ }
243
+ .prose li > input[type="checkbox"]:checked {
244
+ background-color: var(--accent);
245
+ border-color: var(--accent);
246
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'><path d='M3 7l3 3 5-6' stroke='white' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
247
+ background-repeat: no-repeat;
248
+ background-position: center;
249
+ }
250
+ .prose blockquote {
251
+ border-left: 3px solid var(--border);
252
+ margin: 1em 0;
253
+ padding: 0.4em 1em;
254
+ color: var(--text-muted);
255
+ }
256
+ .prose code {
257
+ font-family: "SF Mono", "Fira Code", Menlo, monospace;
258
+ font-size: 0.875em;
259
+ background: #f0efeb;
260
+ padding: 0.15em 0.4em;
261
+ border-radius: 3px;
262
+ }
263
+ .prose pre {
264
+ background: #f6f8fa;
265
+ color: #24292f;
266
+ /* Right padding bumped to give the language label its own visual gutter
267
+ so code content doesn't appear to crowd the right edge. */
268
+ padding: 1em 1.6em 1em 1.2em;
269
+ border-radius: var(--radius);
270
+ border: 1px solid #e1e4e8;
271
+ overflow-x: auto;
272
+ margin: 1.2em 0;
273
+ position: relative;
274
+ }
275
+ .prose pre[data-language]::before {
276
+ content: attr(data-language);
277
+ position: absolute;
278
+ top: 0.4em;
279
+ right: 0.6em;
280
+ font-family: "SF Mono", "Fira Code", Menlo, monospace;
281
+ font-size: 0.7em;
282
+ color: #6e7781;
283
+ text-transform: lowercase;
284
+ letter-spacing: 0.04em;
285
+ pointer-events: none;
286
+ }
287
+ .prose pre code {
288
+ background: none;
289
+ padding: 0;
290
+ font-size: 0.85em;
291
+ color: inherit;
292
+ }
293
+ .prose a { color: #1d4ed8; text-decoration: underline; text-underline-offset: 2px; }
294
+ .prose a:hover { color: #1e40af; }
295
+ .prose hr { border: none; border-top: 1px solid var(--border); margin: 2em 0; }
296
+ .prose table {
297
+ width: 100%;
298
+ border-collapse: separate;
299
+ border-spacing: 0;
300
+ margin: 1.2em 0;
301
+ border: 1px solid var(--border);
302
+ border-radius: 6px;
303
+ overflow: hidden;
304
+ font-size: 14px;
305
+ }
306
+ .prose th, .prose td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--border); }
307
+ .prose th { background: #f5f5f3; font-weight: 600; }
308
+ .prose tr:last-child td { border-bottom: none; }
309
+ .prose tbody tr:nth-child(even) td { background: #fafaf9; }
310
+ .prose strong { font-weight: 600; }
311
+ .prose del, .prose s { color: #94a3b8; }
312
+
313
+ /* ── Highlights — box-shadow underline avoids any layout shift ── */
314
+ mark.rl-highlight {
315
+ background: rgba(255, 236, 153, 0.45);
316
+ box-shadow: inset 0 -1.5px 0 0 #e8b84b;
317
+ border-radius: 2px;
318
+ cursor: pointer;
319
+ transition: background 0.1s;
320
+ }
321
+ mark.rl-highlight:hover {
322
+ background: rgba(255, 220, 100, 0.65);
323
+ }
324
+ /* Active highlight: amber ring traces the exact span tied to the active card.
325
+ Works for overlapping highlights too — the ring outlines whichever <mark>
326
+ is active, even when nested inside another. */
327
+ mark.rl-highlight.active {
328
+ background: rgba(255, 220, 100, 0.65);
329
+ box-shadow: inset 0 -1.5px 0 0 #e8b84b, 0 0 0 1.5px var(--accent);
330
+ border-radius: 2px;
331
+ }
332
+ mark.rl-highlight.resolved {
333
+ background: rgba(200, 230, 201, 0.45);
334
+ box-shadow: inset 0 -1.5px 0 0 #81c784;
335
+ }
336
+ mark.rl-highlight.rl-pending {
337
+ background: rgba(255, 183, 77, 0.55);
338
+ box-shadow: inset 0 -2px 0 0 #e65100;
339
+ border-radius: 2px;
340
+ cursor: default;
341
+ }
342
+ /* Image-wrapping marks: use a ring instead of underline since images are blocks */
343
+ mark.rl-highlight.rl-img {
344
+ display: block;
345
+ width: fit-content;
346
+ margin: 1.2em auto;
347
+ background: transparent;
348
+ box-shadow: 0 0 0 3px #e8b84b;
349
+ border-radius: 4px;
350
+ line-height: 0;
351
+ padding: 0;
352
+ }
353
+ mark.rl-highlight.rl-img > img { margin: 0; }
354
+ mark.rl-highlight.rl-img.resolved { box-shadow: 0 0 0 3px #81c784; }
355
+ mark.rl-highlight.rl-img.rl-pending { box-shadow: 0 0 0 3px #e65100; }
356
+ mark.rl-highlight.rl-img:hover, mark.rl-highlight.rl-img.active {
357
+ box-shadow: 0 0 0 3px #c0392b;
358
+ }
359
+ /* Hover affordance on images so it's discoverable that you can comment */
360
+ .prose img { cursor: pointer; transition: box-shadow 0.15s; }
361
+ .prose img:hover { box-shadow: 0 0 0 2px rgba(217,119,6,0.4); border-radius: 4px; }
362
+
363
+
364
+ /* ── Sidebar ── */
365
+ .sidebar-empty {
366
+ font-size: 13px;
367
+ color: var(--text-muted);
368
+ text-align: center;
369
+ padding: 24px 0;
370
+ }
371
+
372
+ .comment-card {
373
+ position: absolute;
374
+ width: 100%;
375
+ background: var(--surface);
376
+ border: 1px solid var(--border);
377
+ border-radius: var(--radius);
378
+ overflow: hidden;
379
+ transition: border-color 0.15s, box-shadow 0.15s;
380
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06);
381
+ }
382
+ .comment-card.active { border-color: var(--accent); box-shadow: 0 2px 8px rgba(217,119,6,0.12); }
383
+ .comment-card.resolved { opacity: 0.55; }
384
+ .comment-card.resolved .comment-body { display: none; }
385
+ .comment-card.resolved.expanded .comment-body { display: block; }
386
+ .comment-card.resolved .comment-quote { cursor: pointer; }
387
+ .comment-card.resolved .comment-quote::after {
388
+ content: '▸';
389
+ float: right;
390
+ margin-left: 8px;
391
+ opacity: 0.5;
392
+ font-style: normal;
393
+ }
394
+ .comment-card.resolved.expanded .comment-quote::after { content: '▾'; }
395
+
396
+ .comment-quote {
397
+ padding: 10px 14px;
398
+ font-size: 12.5px;
399
+ color: var(--text-muted);
400
+ background: var(--thread-bg);
401
+ border-bottom: 1px solid var(--border);
402
+ font-style: italic;
403
+ white-space: nowrap;
404
+ overflow: hidden;
405
+ text-overflow: ellipsis;
406
+ }
407
+ .comment-card.resolved .comment-quote { border-bottom: none; }
408
+ .comment-card.resolved.expanded .comment-quote { border-bottom: 1px solid var(--border); }
409
+
410
+ /* Last agent reply shown on collapsed resolved cards */
411
+ .card-commitment {
412
+ padding: 7px 14px 9px;
413
+ font-size: 12px;
414
+ color: #3b5bdb;
415
+ line-height: 1.5;
416
+ border-top: 1px solid var(--border);
417
+ }
418
+ .comment-card.resolved.expanded .card-commitment { display: none; }
419
+
420
+ .comment-thread { padding: 10px 14px; }
421
+
422
+ /* ── Comment navigator ── */
423
+ #comment-nav {
424
+ position: sticky;
425
+ top: 0;
426
+ z-index: 5;
427
+ background: var(--surface);
428
+ border-bottom: 1px solid var(--border);
429
+ padding: 8px 12px;
430
+ display: flex;
431
+ align-items: center;
432
+ gap: 8px;
433
+ font-size: 12px;
434
+ color: var(--text-muted);
435
+ }
436
+ #comment-nav .nav-count {
437
+ flex: 1;
438
+ font-weight: 500;
439
+ }
440
+ #comment-nav button {
441
+ background: none;
442
+ border: 1px solid var(--border);
443
+ border-radius: var(--radius);
444
+ padding: 3px 9px;
445
+ font-size: 12px;
446
+ cursor: pointer;
447
+ color: var(--text);
448
+ line-height: 1.4;
449
+ }
450
+ #comment-nav button:hover { background: var(--thread-bg); }
451
+ #comment-nav button:disabled { opacity: 0.3; cursor: default; }
452
+
453
+ /* Soften the swap when the nav hides and the status banner appears
454
+ (and vice versa) — display can't transition, so just fade the
455
+ *appearance* with a brief animation. */
456
+ #comment-nav, #sidebar-status-banner { animation: rl-fade-in 0.18s ease-out; }
457
+ @keyframes rl-fade-in { from { opacity: 0; } to { opacity: 1; } }
458
+
459
+ .thread-entry {
460
+ margin-bottom: 10px;
461
+ }
462
+ .thread-entry:last-child { margin-bottom: 0; }
463
+
464
+ .thread-role {
465
+ font-size: 11px;
466
+ font-weight: 600;
467
+ text-transform: uppercase;
468
+ letter-spacing: 0.05em;
469
+ margin-bottom: 3px;
470
+ }
471
+ .thread-role.human { color: var(--accent); }
472
+ .thread-role.agent { color: #3b5bdb; }
473
+
474
+ .thread-message {
475
+ font-size: 13.5px;
476
+ line-height: 1.5;
477
+ color: var(--text);
478
+ }
479
+
480
+ /* ── Verdict footer on agent replies ── */
481
+ .verdict {
482
+ margin-top: 6px;
483
+ font-size: 12px;
484
+ line-height: 1.45;
485
+ display: flex;
486
+ gap: 6px;
487
+ align-items: baseline;
488
+ }
489
+ .verdict-icon {
490
+ font-size: 11px;
491
+ flex-shrink: 0;
492
+ line-height: 1.5;
493
+ }
494
+ .verdict.revise { color: #92400e; }
495
+
496
+ /* Warm-tinted resolve button when the latest verdict implies an edit */
497
+ .btn-resolve-comment.revise {
498
+ border-color: #f59e0b;
499
+ color: #92400e;
500
+ }
501
+ .btn-resolve-comment.revise:hover {
502
+ background: #fffbeb;
503
+ border-color: #d97706;
504
+ }
505
+
506
+ /* Per-card verdict badge on resolved cards (next to ✓ Resolved) */
507
+ .verdict-badge {
508
+ display: inline-flex;
509
+ align-items: center;
510
+ margin-left: 6px;
511
+ padding: 1px 6px;
512
+ font-size: 10.5px;
513
+ font-weight: 600;
514
+ text-transform: uppercase;
515
+ letter-spacing: 0.04em;
516
+ border-radius: 3px;
517
+ font-style: normal;
518
+ }
519
+ .verdict-badge.revise { background: #fef3c7; color: #92400e; }
520
+ .verdict-badge.accept { background: #e5e7eb; color: var(--text-muted); }
521
+
522
+ /* Round-level secondary action (under the primary banner button) */
523
+ .round-secondary {
524
+ margin-top: 8px;
525
+ font-size: 12.5px;
526
+ color: var(--text-muted);
527
+ text-align: center;
528
+ }
529
+ .round-secondary button {
530
+ background: none;
531
+ border: none;
532
+ padding: 0;
533
+ color: var(--accent);
534
+ cursor: pointer;
535
+ font: inherit;
536
+ text-decoration: underline;
537
+ text-underline-offset: 2px;
538
+ }
539
+ .round-secondary button:hover { color: #c2410c; }
540
+
541
+ .thinking-dots { display: flex; gap: 4px; align-items: center; padding: 2px 0; }
542
+ .thinking-dots span {
543
+ width: 6px; height: 6px; border-radius: 50%;
544
+ background: #3b5bdb; opacity: 0.4;
545
+ animation: thinking-bounce 1.2s infinite ease-in-out;
546
+ }
547
+ .thinking-dots span:nth-child(2) { animation-delay: 0.2s; }
548
+ .thinking-dots span:nth-child(3) { animation-delay: 0.4s; }
549
+ @keyframes thinking-bounce {
550
+ 0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
551
+ 40% { transform: translateY(-4px); opacity: 1; }
552
+ }
553
+
554
+ .comment-actions {
555
+ display: flex;
556
+ gap: 8px;
557
+ padding: 8px 14px;
558
+ border-top: 1px solid var(--border);
559
+ }
560
+
561
+ .btn-reply {
562
+ font-size: 12px;
563
+ padding: 4px 10px;
564
+ border-radius: var(--radius);
565
+ border: 1px solid var(--border);
566
+ background: white;
567
+ cursor: pointer;
568
+ color: var(--text-muted);
569
+ transition: all 0.1s;
570
+ }
571
+ .btn-reply:hover { border-color: var(--text-muted); color: var(--text); }
572
+
573
+ .btn-reopen {
574
+ font-size: 12px;
575
+ padding: 4px 10px;
576
+ border-radius: var(--radius);
577
+ border: 1px solid #3b5bdb;
578
+ background: white;
579
+ cursor: pointer;
580
+ color: #3b5bdb;
581
+ transition: all 0.1s;
582
+ }
583
+ .btn-reopen:hover { background: #eef2ff; }
584
+
585
+ .btn-resolve-comment {
586
+ font-size: 12px;
587
+ padding: 4px 10px;
588
+ border-radius: var(--radius);
589
+ border: 1px solid transparent;
590
+ background: #e8f5e9;
591
+ color: #2e7d32;
592
+ cursor: pointer;
593
+ transition: all 0.1s;
594
+ }
595
+ .btn-resolve-comment:hover { background: #c8e6c9; }
596
+
597
+ /* ── Reply input ── */
598
+ .reply-form {
599
+ display: none;
600
+ padding: 8px 14px;
601
+ border-top: 1px solid var(--border);
602
+ background: var(--thread-bg);
603
+ }
604
+ .reply-form.open { display: block; }
605
+
606
+ .reply-input {
607
+ width: 100%;
608
+ border: 1px solid var(--border);
609
+ border-radius: var(--radius);
610
+ padding: 7px 10px;
611
+ font-size: 13px;
612
+ font-family: inherit;
613
+ resize: vertical;
614
+ min-height: 64px;
615
+ background: white;
616
+ }
617
+ .reply-input:focus { outline: none; border-color: var(--accent); }
618
+
619
+ .reply-submit {
620
+ margin-top: 6px;
621
+ background: var(--accent);
622
+ color: white;
623
+ border: none;
624
+ padding: 5px 12px;
625
+ border-radius: var(--radius);
626
+ font-size: 12px;
627
+ cursor: pointer;
628
+ }
629
+ .reply-submit:hover { opacity: 0.85; }
630
+
631
+ /* ── New comment form in sidebar ── */
632
+ .new-comment-form {
633
+ position: absolute;
634
+ width: 100%;
635
+ background: var(--surface);
636
+ border: 1px solid var(--accent);
637
+ border-radius: var(--radius);
638
+ overflow: hidden;
639
+ box-shadow: 0 2px 8px rgba(217,119,6,0.12);
640
+ z-index: 10;
641
+ }
642
+
643
+ .new-comment-quote {
644
+ padding: 10px 14px;
645
+ font-size: 12.5px;
646
+ color: var(--text-muted);
647
+ background: var(--accent-light);
648
+ border-bottom: 1px solid var(--border);
649
+ font-style: italic;
650
+ white-space: nowrap;
651
+ overflow: hidden;
652
+ text-overflow: ellipsis;
653
+ }
654
+
655
+ .new-comment-body {
656
+ padding: 10px 14px;
657
+ }
658
+
659
+ .new-comment-actions {
660
+ display: flex;
661
+ justify-content: flex-end;
662
+ gap: 8px;
663
+ margin-top: 8px;
664
+ }
665
+
666
+ .btn-cancel-inline {
667
+ background: none;
668
+ border: 1px solid var(--border);
669
+ padding: 5px 12px;
670
+ border-radius: var(--radius);
671
+ font-size: 12px;
672
+ cursor: pointer;
673
+ color: var(--text-muted);
674
+ }
675
+
676
+ /* ── kbd shortcut label ── */
677
+ .reply-submit kbd {
678
+ display: inline-block;
679
+ font-size: 10px;
680
+ font-family: inherit;
681
+ opacity: 0.7;
682
+ margin-left: 5px;
683
+ font-style: normal;
684
+ }
685
+
686
+ /* ── Resolved badge ── */
687
+ .resolved-badge {
688
+ display: inline-block;
689
+ font-size: 11px;
690
+ font-weight: 600;
691
+ color: #2e7d32;
692
+ background: #e8f5e9;
693
+ padding: 2px 7px;
694
+ border-radius: 10px;
695
+ float: right;
696
+ margin-left: 8px;
697
+ }
698
+
699
+ /* ── Review submitted sidebar banner ── */
700
+ #sidebar-status-banner {
701
+ display: none;
702
+ padding: 10px 14px;
703
+ margin-bottom: 14px;
704
+ background: #e8f5e9;
705
+ border-bottom: 1px solid #a5d6a7;
706
+ color: #2e7d32;
707
+ font-size: 13px;
708
+ font-weight: 500;
709
+ align-items: center;
710
+ gap: 8px;
711
+ }
712
+ #sidebar-status-banner.revising {
713
+ background: #fff3e0;
714
+ border-bottom-color: #ffb74d;
715
+ color: #e65100;
716
+ flex-direction: column;
717
+ align-items: flex-start;
718
+ gap: 0;
719
+ }
720
+ #sidebar-status-banner.error {
721
+ background: #fdecea;
722
+ border-bottom-color: #f5c2c0;
723
+ color: #a01818;
724
+ }
725
+ .revising-header { display: flex; align-items: center; gap: 8px; }
726
+ #revision-stream {
727
+ display: none;
728
+ margin-top: 8px;
729
+ width: 100%;
730
+ max-height: 220px;
731
+ overflow-y: auto;
732
+ background: rgba(0,0,0,0.05);
733
+ border-radius: 4px;
734
+ padding: 7px 9px;
735
+ font-family: 'Menlo','Monaco',monospace;
736
+ font-size: 11px;
737
+ white-space: pre-wrap;
738
+ word-break: break-word;
739
+ line-height: 1.5;
740
+ box-sizing: border-box;
741
+ }
742
+ #revision-stream .rs-thinking { color: #9a7b3f; font-style: italic; opacity: 0.75; }
743
+ #revision-stream .rs-text { color: #5a3a00; }
744
+ .revising-spinner {
745
+ display: inline-block;
746
+ width: 12px; height: 12px;
747
+ border: 2px solid #ffb74d;
748
+ border-top-color: transparent;
749
+ border-radius: 50%;
750
+ animation: spinner-rotate 0.8s linear infinite;
751
+ flex-shrink: 0;
752
+ }
753
+ @keyframes spinner-rotate { to { transform: rotate(360deg); } }
754
+ .revising-dots span {
755
+ animation: dot-blink 1.4s infinite both;
756
+ opacity: 0;
757
+ }
758
+ .revising-dots span:nth-child(1) { animation-delay: 0s; }
759
+ .revising-dots span:nth-child(2) { animation-delay: 0.2s; }
760
+ .revising-dots span:nth-child(3) { animation-delay: 0.4s; }
761
+ @keyframes dot-blink {
762
+ 0%, 60%, 100% { opacity: 0; }
763
+ 30% { opacity: 1; }
764
+ }
765
+
766
+ /* ── Done banner ── */
767
+ #done-banner { display: none; }
768
+
769
+ /* ── Diff overlay ── */
770
+ #diff-overlay {
771
+ display: none;
772
+ position: fixed;
773
+ inset: 0;
774
+ background: rgba(0,0,0,0.45);
775
+ z-index: 100;
776
+ align-items: flex-start;
777
+ justify-content: center;
778
+ padding: 40px 24px;
779
+ overflow-y: auto;
780
+ }
781
+ #diff-overlay.open { display: flex; }
782
+ #diff-panel {
783
+ background: white;
784
+ border-radius: 8px;
785
+ box-shadow: 0 8px 40px rgba(0,0,0,0.18);
786
+ width: 100%;
787
+ max-width: 820px;
788
+ overflow: hidden;
789
+ display: flex;
790
+ flex-direction: column;
791
+ }
792
+ #diff-panel-header {
793
+ display: flex;
794
+ align-items: center;
795
+ padding: 16px 20px;
796
+ border-bottom: 1px solid var(--border);
797
+ gap: 12px;
798
+ }
799
+ #diff-panel-header h2 {
800
+ flex: 1;
801
+ font-size: 15px;
802
+ font-weight: 600;
803
+ margin: 0;
804
+ }
805
+ #diff-panel-body {
806
+ overflow-y: auto;
807
+ max-height: 65vh;
808
+ padding: 8px 40px 40px;
809
+ }
810
+ .diff-prose { max-width: 660px; margin: 0 auto; }
811
+ .diff-prose h1 { font-size: 2em; font-weight: 700; margin: 1.5em 0 0.5em; }
812
+ .diff-prose h2 { font-size: 1.4em; font-weight: 700; margin: 1.4em 0 0.4em; padding-bottom: 0.25em; border-bottom: 1px solid var(--border); }
813
+ .diff-prose h3 { font-size: 1.1em; font-weight: 600; margin: 1.2em 0 0.3em; }
814
+ .diff-prose p { margin: 0.8em 0; line-height: 1.7; }
815
+ .diff-prose pre { background: #f6f8fa; border-radius: 6px; padding: 14px 16px; overflow-x: auto; font-size: 13px; }
816
+ .diff-prose code { font-family: 'Menlo','Monaco',monospace; font-size: 0.875em; background: #f0f0ed; padding: 1px 4px; border-radius: 3px; }
817
+ .diff-prose pre code { background: none; padding: 0; }
818
+ .diff-prose a { color: #1d4ed8; text-decoration: underline; text-underline-offset: 2px; }
819
+ .diff-prose a:hover { color: #1e40af; }
820
+ .diff-prose ul, .diff-prose ol { padding-left: 1.5em; margin: 0.8em 0; }
821
+ .diff-prose li { margin: 0.3em 0; line-height: 1.7; }
822
+ .diff-block { border-radius: 4px; margin: 2px -12px; padding: 2px 12px; }
823
+ .diff-block-add { background: #e6ffed; border-left: 3px solid #28a745; }
824
+ .diff-block-del { background: #ffeef0; border-left: 3px solid #d73a49; opacity: 0.8; }
825
+ .diff-block-mod { background: #fffbe6; border-left: 3px solid #f0ad00; }
826
+ ins.diff-word-add { background: #acf2bd; text-decoration: none; border-radius: 2px; padding: 0 1px; }
827
+ del.diff-word-del { background: #fdb8c0; border-radius: 2px; padding: 0 1px; }
828
+ .diff-no-changes { padding: 24px 0; color: var(--text-muted); }
829
+ .btn-diff-compare {
830
+ font-size: 12px;
831
+ padding: 4px 10px;
832
+ border-radius: var(--radius);
833
+ border: 1px solid var(--border);
834
+ background: white;
835
+ cursor: pointer;
836
+ color: var(--text-muted);
837
+ transition: all 0.1s;
838
+ }
839
+ .btn-diff-compare:hover { color: var(--text); border-color: #aaa; }
840
+ .btn-diff-accept {
841
+ background: #2e7d32;
842
+ color: white;
843
+ border: none;
844
+ padding: 8px 18px;
845
+ border-radius: var(--radius);
846
+ font-size: 14px;
847
+ font-weight: 500;
848
+ cursor: pointer;
849
+ }
850
+ .btn-diff-accept:hover { opacity: 0.85; }
851
+ .btn-diff-feedback {
852
+ background: none;
853
+ border: 1px solid var(--border);
854
+ padding: 8px 18px;
855
+ border-radius: var(--radius);
856
+ font-size: 14px;
857
+ cursor: pointer;
858
+ color: var(--text);
859
+ }
860
+ .btn-diff-feedback:hover { background: var(--thread-bg); }
861
+ .btn-diff-close {
862
+ background: none;
863
+ border: none;
864
+ cursor: pointer;
865
+ color: var(--text-muted);
866
+ font-size: 16px;
867
+ padding: 4px 8px;
868
+ border-radius: 4px;
869
+ line-height: 1;
870
+ }
871
+ .btn-diff-close:hover { background: var(--thread-bg); color: var(--text); }
872
+
873
+ /* ── Empty-rail hint (cold-open only) ── */
874
+ .empty-rail-hint {
875
+ padding: 14px 16px;
876
+ font-size: 13px;
877
+ color: var(--text-muted);
878
+ font-style: italic;
879
+ text-align: center;
880
+ opacity: 0.75;
881
+ }
882
+
883
+ /* ── Revision banner ── */
884
+ .revision-banner {
885
+ display: flex;
886
+ align-items: center;
887
+ gap: 10px;
888
+ padding: 8px 14px;
889
+ background: #eff6ff;
890
+ border: 1px solid #bfdbfe;
891
+ border-radius: var(--radius);
892
+ margin-bottom: 14px;
893
+ font-size: 13.5px;
894
+ color: #1e40af;
895
+ }
896
+ .revision-banner-text { flex: 1; }
897
+ .revision-banner-link {
898
+ background: none;
899
+ border: none;
900
+ cursor: pointer;
901
+ color: #1d4ed8;
902
+ font-size: 13.5px;
903
+ font-weight: 500;
904
+ padding: 0;
905
+ text-decoration: underline;
906
+ text-underline-offset: 2px;
907
+ }
908
+ .revision-banner-link:hover { color: #1e40af; }
909
+ .revision-banner-dismiss {
910
+ background: none;
911
+ border: none;
912
+ cursor: pointer;
913
+ color: #60a5fa;
914
+ font-size: 13px;
915
+ padding: 1px 4px;
916
+ border-radius: 3px;
917
+ line-height: 1;
918
+ opacity: 0.7;
919
+ flex-shrink: 0;
920
+ }
921
+ .revision-banner-dismiss:hover { opacity: 1; background: rgba(96,165,250,0.15); }
922
+
923
+ /* ── Context banner ── */
924
+ .context-banner {
925
+ display: flex;
926
+ align-items: flex-start;
927
+ gap: 10px;
928
+ padding: 9px 14px;
929
+ background: #fffbeb;
930
+ border: 1px solid #fde68a;
931
+ border-radius: var(--radius);
932
+ margin-bottom: 14px;
933
+ font-size: 13.5px;
934
+ color: #78350f;
935
+ line-height: 1.5;
936
+ }
937
+ .context-label {
938
+ font-weight: 600;
939
+ text-transform: uppercase;
940
+ letter-spacing: 0.05em;
941
+ font-size: 10.5px;
942
+ color: #b45309;
943
+ white-space: nowrap;
944
+ padding-top: 2px;
945
+ flex-shrink: 0;
946
+ }
947
+ .context-text { flex: 1; }
948
+ .context-dismiss {
949
+ background: none;
950
+ border: none;
951
+ cursor: pointer;
952
+ color: #b45309;
953
+ font-size: 13px;
954
+ padding: 1px 4px;
955
+ border-radius: 3px;
956
+ line-height: 1;
957
+ opacity: 0.6;
958
+ flex-shrink: 0;
959
+ }
960
+ .context-dismiss:hover { opacity: 1; background: rgba(180,83,9,0.1); }
961
+
962
+ /* ── First-run security banner ── */
963
+ /* Visible only on the first run on a given browser. Dismissal sets
964
+ localStorage `redline-security-ack` so it never shows again on this
965
+ machine, regardless of which doc you open. Hidden by default in the
966
+ HTML; main.ts removes the `hidden` attribute when no ack is found. */
967
+ .first-run-banner[hidden] { display: none; }
968
+ .first-run-banner {
969
+ display: flex;
970
+ align-items: center;
971
+ gap: 10px;
972
+ padding: 8px 14px;
973
+ background: #fef2f2;
974
+ border: 1px solid #fecaca;
975
+ border-radius: var(--radius);
976
+ margin-bottom: 14px;
977
+ font-size: 13px;
978
+ color: #7f1d1d;
979
+ line-height: 1.5;
980
+ }
981
+ .first-run-icon { font-size: 14px; flex-shrink: 0; }
982
+ .first-run-text { flex: 1; }
983
+ .first-run-dismiss {
984
+ background: white;
985
+ border: 1px solid #fca5a5;
986
+ color: #7f1d1d;
987
+ cursor: pointer;
988
+ font-size: 12px;
989
+ font-weight: 500;
990
+ padding: 3px 10px;
991
+ border-radius: 4px;
992
+ flex-shrink: 0;
993
+ }
994
+ .first-run-dismiss:hover { background: #fee2e2; }