code.css
⎇
Raw
1@layer components {
2 /* --- File tree --- */
3 .file-tree {
4 width: 100%;
5 border: 1px solid var(--color-border);
6 border-radius: var(--radius-lg);
7 border-collapse: separate;
8 border-spacing: 0;
9 overflow: hidden;
10 margin-bottom: var(--space-6);
11 table-layout: auto;
12 }
13 .file-tree-row + .file-tree-row td {
14 border-top: 1px solid var(--color-border-muted);
15 }
16 .file-tree-row:hover {
17 background: var(--color-bg-subtle);
18 }
19 .file-icon,
20 .file-name,
21 .file-size {
22 padding: var(--space-2) var(--space-3);
23 font-size: var(--text-sm);
24 vertical-align: middle;
25 }
26 .file-icon {
27 width: 2.25rem;
28 padding-right: var(--space-1);
29 text-align: center;
30 line-height: 0;
31 }
32 .file-name {
33 width: 100%;
34 overflow-wrap: anywhere;
35 }
36 .file-name a {
37 color: var(--color-link);
38 text-decoration: none;
39 }
40 .file-name a:hover {
41 text-decoration: underline;
42 }
43 .file-name a.file-name-dir {
44 font-weight: 500;
45 }
46 .file-size {
47 text-align: right;
48 color: var(--color-text-muted);
49 font-size: var(--text-xs);
50 white-space: nowrap;
51 padding-right: var(--space-4);
52 }
53 .file-icon-dir {
54 color: var(--color-link);
55 }
56 .file-icon-file {
57 color: var(--color-text-muted);
58 }
59 .tree-icon {
60 display: inline-block;
61 vertical-align: text-bottom;
62 }
63 .file-tree-row-up .file-name a {
64 color: var(--color-text-muted);
65 }
66 .file-tree-row-up .file-name a:hover {
67 color: var(--color-link);
68 }
69
70 /* --- File blob --- */
71 .file-blob-header {
72 display: flex;
73 align-items: center;
74 justify-content: space-between;
75 flex-wrap: wrap;
76 gap: var(--space-2) var(--space-3);
77 padding: var(--space-2) var(--space-4);
78 background: var(--color-bg-subtle);
79 border: 1px solid var(--color-border);
80 border-radius: var(--radius-lg) var(--radius-lg) 0 0;
81 }
82 .file-blob-name {
83 font-size: var(--text-sm);
84 font-weight: 500;
85 flex: 1 1 8rem;
86 min-width: 0;
87 overflow-wrap: anywhere;
88 }
89 .file-blob-actions {
90 display: flex;
91 align-items: center;
92 flex-wrap: wrap;
93 gap: var(--space-2);
94 margin-left: auto;
95 }
96 /* Anchor the delete popup to the whole header, so it never runs off the
97 left edge when the button sits far from the right edge. */
98 .file-blob-header {
99 position: relative;
100 }
101 .file-blob-header .confirm-details {
102 position: static;
103 }
104 .file-blob-header .confirm-popup {
105 max-width: 100%;
106 }
107 .file-blob-body {
108 border: 1px solid var(--color-border);
109 border-top: none;
110 border-radius: 0 0 var(--radius-lg) var(--radius-lg);
111 overflow: auto;
112 min-width: 0;
113 }
114 .file-edit-textarea {
115 display: block;
116 width: 100%;
117 font-family: var(--font-mono);
118 font-size: var(--text-sm);
119 line-height: 1.6;
120 padding: var(--space-4);
121 background: var(--color-bg);
122 color: var(--color-text);
123 border: none;
124 resize: vertical;
125 min-height: 20rem;
126 tab-size: 4;
127 }
128 .file-edit-textarea:focus {
129 outline: 2px solid var(--color-accent);
130 outline-offset: -2px;
131 }
132
133 /* Blob line-number table */
134 .blob-table {
135 min-width: 100%;
136 border-collapse: collapse;
137 font-family: var(--font-mono);
138 font-size: var(--text-sm);
139 line-height: 1.6;
140 background-color: var(--code-bg);
141 color: var(--code-fg);
142 }
143 .blob-ln {
144 width: 1%;
145 min-width: 3rem;
146 text-align: right;
147 padding: 0 var(--space-3);
148 color: var(--color-text-muted);
149 border-right: 1px solid var(--color-border-muted);
150 user-select: none;
151 white-space: nowrap;
152 vertical-align: top;
153 }
154 .blob-ln a {
155 color: inherit;
156 text-decoration: none;
157 }
158 .blob-ln a:hover {
159 color: var(--color-link);
160 }
161 .blob-code {
162 padding: 0 var(--space-4);
163 white-space: pre;
164 vertical-align: top;
165 tab-size: 4;
166 }
167 .blob-table tr:target {
168 background: color-mix(in srgb, var(--color-link) 12%, transparent);
169 }
170 .blob-table tr:target .blob-ln {
171 background: color-mix(in srgb, var(--color-link) 20%, transparent);
172 }
173 .file-download-notice {
174 padding: clamp(var(--space-6), 6vw, var(--space-8)) var(--space-4);
175 text-align: center;
176 color: var(--color-text-muted);
177 }
178 .file-download-notice p {
179 margin-bottom: var(--space-4);
180 }
181 .file-media {
182 padding: var(--space-4);
183 display: flex;
184 justify-content: center;
185 background: var(--color-bg-subtle);
186 }
187 .file-media-img {
188 max-width: 100%;
189 height: auto;
190 display: block;
191 }
192 .file-media-audio {
193 width: 100%;
194 max-width: 600px;
195 }
196 .file-media-video {
197 max-width: 100%;
198 max-height: 80vh;
199 }
200
201 /* --- Commit list --- */
202 .commit-list {
203 display: flex;
204 flex-direction: column;
205 }
206 .commit-item {
207 display: flex;
208 flex-direction: column;
209 padding: var(--space-3) 0;
210 border-bottom: 1px solid var(--color-border-muted);
211 gap: var(--space-1);
212 }
213 .commit-item:last-child {
214 border-bottom: none;
215 }
216 .commit-subject {
217 color: var(--color-text);
218 text-decoration: none;
219 font-size: var(--text-sm);
220 font-weight: 500;
221 overflow-wrap: anywhere;
222 }
223 .commit-subject:hover {
224 color: var(--color-link);
225 }
226 .commit-meta {
227 display: flex;
228 align-items: center;
229 justify-content: space-between;
230 flex-wrap: wrap;
231 gap: var(--space-1) var(--space-3);
232 font-size: var(--text-xs);
233 color: var(--color-text-muted);
234 }
235 .commit-meta-right {
236 display: flex;
237 align-items: center;
238 flex-wrap: wrap;
239 gap: var(--space-2);
240 margin-left: auto;
241 }
242 .commit-date {
243 white-space: nowrap;
244 }
245
246 /* --- Commit detail --- */
247 .commit-page-top {
248 display: flex;
249 align-items: center;
250 justify-content: space-between;
251 flex-wrap: wrap;
252 gap: var(--space-2);
253 margin-bottom: var(--space-4);
254 }
255 .commit-card {
256 border: 1px solid var(--color-border);
257 border-radius: var(--radius-lg);
258 margin-bottom: var(--space-4);
259 overflow: hidden;
260 min-width: 0;
261 }
262 .commit-card-subject {
263 font-size: var(--text-xl);
264 font-weight: 600;
265 padding: var(--space-4) clamp(var(--space-4), 3vw, var(--space-6));
266 border-bottom: 1px solid var(--color-border);
267 line-height: 1.3;
268 overflow-wrap: anywhere;
269 }
270 .commit-card-subject-empty {
271 color: var(--color-text-muted);
272 font-style: italic;
273 font-weight: 400;
274 font-size: var(--text-sm);
275 }
276 .commit-card-body {
277 padding: var(--space-4) clamp(var(--space-4), 3vw, var(--space-6));
278 font-family: inherit;
279 font-size: var(--text-sm);
280 color: var(--color-text-muted);
281 border-bottom: 1px solid var(--color-border);
282 white-space: pre-wrap;
283 overflow-wrap: anywhere;
284 }
285 .commit-card-meta {
286 padding: var(--space-3) clamp(var(--space-4), 3vw, var(--space-6));
287 display: flex;
288 flex-direction: column;
289 gap: var(--space-1);
290 background: var(--color-bg-subtle);
291 }
292 .commit-card-meta-row {
293 display: flex;
294 align-items: baseline;
295 gap: var(--space-1) var(--space-3);
296 font-size: var(--text-sm);
297 flex-wrap: wrap;
298 }
299 .commit-meta-label {
300 font-weight: 600;
301 color: var(--color-text-muted);
302 min-width: 6rem;
303 font-size: var(--text-xs);
304 text-transform: uppercase;
305 letter-spacing: 0.04em;
306 }
307 .commit-meta-value {
308 min-width: 0;
309 overflow-wrap: anywhere;
310 }
311 .commit-sha-full {
312 font-size: var(--text-xs);
313 background: var(--color-bg-inset);
314 padding: 2px var(--space-2);
315 border-radius: var(--radius-sm);
316 }
317 .commit-stats-bar {
318 font-size: var(--text-sm);
319 color: var(--color-text-muted);
320 margin-bottom: var(--space-3);
321 }
322
323 /* --- Commit layout (file nav + diffs) ---
324 Flex wrap with two bases: the nav wants 14rem, the diffs want at least
325 34rem and take all spare space. When both do not fit on one row, the
326 diffs wrap below the nav and both stretch to full width. */
327 .commit-layout {
328 display: flex;
329 flex-wrap: wrap;
330 gap: var(--space-4);
331 align-items: flex-start;
332 container-type: inline-size;
333 }
334 .commit-file-nav {
335 flex: 1 1 14rem;
336 min-width: 0;
337 max-width: 100%;
338 }
339 .commit-layout:has(.file-nav-details:not([open])) .commit-file-nav {
340 flex: 0 1 auto;
341 }
342 .commit-diffs {
343 flex: 999 1 min(100%, 34rem);
344 min-width: 0;
345 }
346 /* The one width query: the file nav only sticks when it sits beside the
347 diffs. Stacked on top it would cover the diff while scrolling. */
348 @container (min-width: 50rem) {
349 .commit-file-nav {
350 position: sticky;
351 top: calc(3.5rem + var(--space-3));
352 max-height: calc(100vh - 3.5rem - var(--space-6));
353 overflow-y: auto;
354 }
355 }
356
357 /* --- File nav sidebar --- */
358 .file-nav-details {
359 border: 1px solid var(--color-border);
360 border-radius: var(--radius-lg);
361 background: var(--color-bg-subtle);
362 overflow: hidden;
363 }
364 .file-nav-toggle {
365 display: flex;
366 align-items: center;
367 gap: var(--space-2);
368 padding: var(--space-2) var(--space-3);
369 font-size: var(--text-sm);
370 font-weight: 500;
371 cursor: pointer;
372 list-style: none;
373 user-select: none;
374 border-bottom: 1px solid var(--color-border);
375 }
376 .file-nav-toggle::-webkit-details-marker {
377 display: none;
378 }
379 .file-nav-details:not([open]) .file-nav-toggle {
380 border-bottom: none;
381 }
382 .file-nav-toggle-icon {
383 font-size: 0.8em;
384 color: var(--color-text-muted);
385 transition: transform 0.15s;
386 }
387 .file-nav-details:not([open]) > .file-nav-toggle .file-nav-toggle-icon {
388 transform: rotate(-90deg);
389 }
390 .file-nav-list {
391 padding: var(--space-1) 0;
392 list-style: none;
393 }
394 .file-nav-item {
395 display: flex;
396 align-items: center;
397 gap: var(--space-2);
398 padding: var(--space-1) var(--space-3);
399 font-size: var(--text-xs);
400 text-decoration: none;
401 color: var(--color-text);
402 overflow: hidden;
403 }
404 .file-nav-item:hover {
405 background: var(--color-bg-inset);
406 }
407 .file-nav-status,
408 .diff-status-badge {
409 flex-shrink: 0;
410 width: 1.125rem;
411 height: 1.125rem;
412 display: inline-flex;
413 align-items: center;
414 justify-content: center;
415 border-radius: var(--radius-sm);
416 font-size: 10px;
417 font-weight: 700;
418 font-family: var(--font-mono);
419 }
420 .file-nav-status {
421 width: 1rem;
422 height: 1rem;
423 font-size: 9px;
424 }
425 .file-status-added,
426 .diff-status-added {
427 background: var(--color-success-bg);
428 color: var(--color-success);
429 }
430 .file-status-deleted,
431 .diff-status-deleted {
432 background: var(--color-danger-bg);
433 color: var(--color-danger);
434 }
435 .file-status-modified,
436 .diff-status-modified {
437 background: var(--color-accent-bg);
438 color: var(--color-accent);
439 }
440 .file-status-renamed,
441 .file-status-copied,
442 .diff-status-renamed,
443 .diff-status-copied {
444 background: var(--color-merged-bg);
445 color: var(--color-merged);
446 }
447 .file-nav-name {
448 flex: 1;
449 min-width: 0;
450 overflow: hidden;
451 text-overflow: ellipsis;
452 white-space: nowrap;
453 font-family: var(--font-mono);
454 }
455 .file-nav-stat {
456 flex-shrink: 0;
457 display: flex;
458 gap: var(--space-1);
459 font-size: var(--text-xs);
460 font-family: var(--font-mono);
461 }
462 .nav-add {
463 color: var(--color-success);
464 }
465 .nav-del {
466 color: var(--color-danger);
467 }
468 .nav-binary {
469 color: var(--color-text-muted);
470 font-size: var(--text-xs);
471 }
472 .file-nav-dir > details > .file-nav-list {
473 padding-left: var(--space-4);
474 }
475 .file-nav-dir-toggle {
476 display: flex;
477 align-items: center;
478 gap: var(--space-1);
479 padding: var(--space-1) var(--space-3);
480 font-size: var(--text-xs);
481 font-family: var(--font-mono);
482 color: var(--color-text-muted);
483 cursor: pointer;
484 list-style: none;
485 user-select: none;
486 }
487 .file-nav-dir-toggle::-webkit-details-marker {
488 display: none;
489 }
490 .file-nav-dir > details:not([open]) > .file-nav-dir-toggle .file-nav-toggle-icon {
491 transform: rotate(-90deg);
492 }
493
494 /* --- Diff file cards --- */
495 .diff-file {
496 border: 1px solid var(--color-border);
497 border-radius: var(--radius-lg);
498 margin-bottom: var(--space-4);
499 overflow: hidden;
500 min-width: 0;
501 /* Skip layout and paint of files that are off screen. Big diffs
502 otherwise block the first paint for many seconds. */
503 content-visibility: auto;
504 contain-intrinsic-size: auto 40rem;
505 }
506 .diff-file-header {
507 display: flex;
508 align-items: center;
509 justify-content: space-between;
510 gap: var(--space-2) var(--space-3);
511 padding: var(--space-2) var(--space-3);
512 background: var(--color-bg-subtle);
513 cursor: pointer;
514 list-style: none;
515 user-select: none;
516 flex-wrap: wrap;
517 }
518 .diff-file-header::-webkit-details-marker {
519 display: none;
520 }
521 .diff-file-header-left {
522 display: flex;
523 align-items: center;
524 gap: var(--space-2);
525 min-width: 0;
526 flex: 1 1 12rem;
527 }
528 .diff-file-header-right {
529 display: flex;
530 align-items: center;
531 gap: var(--space-2);
532 flex-shrink: 0;
533 flex-wrap: wrap;
534 margin-left: auto;
535 }
536 .diff-file-toggle-icon {
537 font-size: 0.7em;
538 color: var(--color-text-muted);
539 flex-shrink: 0;
540 transition: transform 0.15s;
541 }
542 .diff-file:not([open]) .diff-file-toggle-icon {
543 transform: rotate(-90deg);
544 }
545 .diff-file-path {
546 font-size: var(--text-sm);
547 font-weight: 500;
548 min-width: 0;
549 overflow-wrap: anywhere;
550 }
551 .diff-rename-arrow {
552 font-size: var(--text-xs);
553 color: var(--color-text-muted);
554 min-width: 0;
555 overflow-wrap: anywhere;
556 }
557 .diff-stat-add,
558 .diff-stat-del,
559 .diff-stat-binary {
560 font-size: var(--text-sm);
561 font-family: var(--font-mono);
562 font-weight: 600;
563 white-space: nowrap;
564 }
565 .diff-stat-add {
566 color: var(--color-success);
567 }
568 .diff-stat-del {
569 color: var(--color-danger);
570 }
571 .diff-stat-binary {
572 color: var(--color-text-muted);
573 font-weight: 400;
574 }
575 .diff-file-header .btn-xs {
576 font-family: var(--font-mono);
577 }
578
579 /* --- Diff file body --- */
580 .diff-binary-notice {
581 padding: var(--space-4);
582 font-size: var(--text-sm);
583 color: var(--color-text-muted);
584 font-style: italic;
585 }
586 .diff-hunk {
587 border-top: 1px solid var(--color-border-muted);
588 overflow-x: auto;
589 }
590 .diff-file-body {
591 border-top: 1px solid var(--color-border);
592 }
593 .diff-hunk:first-child {
594 border-top: none;
595 }
596 .diff-hunk-header {
597 padding: var(--space-1) var(--space-3);
598 font-size: var(--text-xs);
599 background: color-mix(in srgb, var(--color-merged-bg) 50%, var(--color-bg));
600 color: var(--color-merged);
601 border-bottom: 1px solid var(--color-border-muted);
602 white-space: pre;
603 }
604
605 /* --- Diff rows ---
606 One div per row, one span for both line numbers, one span for the code.
607 Line numbers and the sign are CSS generated content. Big diffs are bound
608 by HTML parsing, so fewer elements per row is what makes them fast. */
609 .diff-rows {
610 width: max-content;
611 min-width: 100%;
612 font-family: var(--font-mono);
613 font-size: var(--text-xs);
614 line-height: 1.5;
615 tab-size: 4;
616 }
617 .diff-row {
618 display: flex;
619 }
620 .diff-ln {
621 display: flex;
622 flex: none;
623 color: var(--color-text-muted);
624 }
625 .diff-ln::before,
626 .diff-ln::after {
627 display: block;
628 width: calc(max(var(--ln-digits, 3), 3) * 1ch + 2 * var(--space-2));
629 text-align: right;
630 padding: 0 var(--space-2);
631 border-right: 1px solid var(--color-border-muted);
632 white-space: nowrap;
633 }
634 .diff-ln::before {
635 content: attr(data-old);
636 }
637 .diff-ln::after {
638 content: attr(data-new);
639 }
640 .diff-code {
641 flex: 1;
642 padding-right: var(--space-3);
643 white-space: pre;
644 }
645 /* Whole character widths and no margin keep the tab grid of the code
646 aligned with a 4-space indent. */
647 .diff-code::before {
648 content: " ";
649 display: inline-block;
650 width: 4ch;
651 text-align: center;
652 }
653 .diff-row-add {
654 background: color-mix(in srgb, var(--color-success-bg) 70%, transparent);
655 }
656 .diff-row-del {
657 background: color-mix(in srgb, var(--color-danger-bg) 70%, transparent);
658 }
659 .diff-row-add .diff-ln,
660 .diff-row-add .diff-code::before {
661 background: color-mix(in srgb, var(--color-success-bg) 90%, transparent);
662 }
663 .diff-row-del .diff-ln,
664 .diff-row-del .diff-code::before {
665 background: color-mix(in srgb, var(--color-danger-bg) 90%, transparent);
666 }
667 .diff-row-add .diff-code::before {
668 content: "+";
669 color: var(--color-success);
670 font-weight: 700;
671 }
672 .diff-row-del .diff-code::before {
673 content: "-";
674 color: var(--color-danger);
675 font-weight: 700;
676 }
677 .diff-ctrl {
678 color: #f0f0f0;
679 background: #c0392b;
680 border-radius: 2px;
681 font-weight: bold;
682 padding: 0 1px;
683 }
684 /* Token colors and --code-bg/--code-fg come from /assets/code-theme.css,
685 generated from the chroma themes at runtime. */
686}
687