orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1// repos.bythewood.me. One hand written stylesheet rather than Bootstrap, since
2// this site is dense text (file trees, diffs, commit lists) and a framework
3// does not help with any of it.
4//
5// The palette is the one analytics, auth, logging and status share, written as
6// custom properties here because there is no Sass variable file to import from
7// a separate module. When a colour changes there it has to change here too.
8
9:root {
10 --bg: #0e0d0a;
11 --surface: #1c1a15;
12 --raised: #24211a;
13 --sunken: #090806;
14 --line: rgba(107, 158, 120, 0.34);
15 --line-strong: rgba(107, 158, 120, 0.45);
16
17 --bright: #ede8e0;
18 --text: #ddd7cd;
19 --muted: #b3aba2;
20 --faint: #8a8279;
21
22 --accent: #6b9e78;
23 --accent-lift: #7db88c;
24 --accent-dim: rgba(107, 158, 120, 0.16);
25 --link: #7db88c;
26 --link-lift: #95cca2;
27
28 --add: #7db88c;
29 --add-bg: rgba(125, 184, 140, 0.12);
30 --del: #c47055;
31 --del-bg: rgba(196, 112, 85, 0.12);
32 --warn: #c9a84c;
33 --warn-bg: rgba(201, 168, 76, 0.10);
34
35 // Newsreader is kept for repository names alone. Everything else is the one
36 // face the rest of the estate sets, so --sans and --mono are the same family
37 // here the way they are in the shared Bootstrap variables.
38 --serif: "Newsreader", ui-serif, Georgia, "Times New Roman", serif;
39 --sans: "Monaspace Argon", ui-monospace, "Cascadia Code", Consolas, "SF Mono", Menlo, monospace;
40 --mono: var(--sans);
41
42 --t-xs: 0.75rem;
43 --t-sm: 0.8125rem;
44 --t-base: 0.92rem;
45 --t-md: 1.0625rem;
46 --t-lg: 1.375rem;
47 --t-xl: 1.75rem;
48
49 --radius: 0.25rem;
50 --radius-sm: 0.2rem;
51 --wrap: 1140px;
52 --bar: 52px;
53
54 // One tracking value, used everywhere a label is set in caps.
55 --track: 0.1em;
56}
57
58*, *::before, *::after { box-sizing: border-box; }
59
60html { -webkit-text-size-adjust: 100%; }
61
62body {
63 margin: 0;
64 background: var(--bg);
65 color: var(--text);
66 font-family: var(--sans);
67 font-size: var(--t-base);
68 line-height: 1.7;
69 letter-spacing: 0.01em;
70 -webkit-font-smoothing: antialiased;
71
72 background-image:
73 linear-gradient(rgba(107, 158, 120, 0.028) 1px, transparent 1px),
74 linear-gradient(90deg, rgba(107, 158, 120, 0.028) 1px, transparent 1px);
75 background-size: 32px 32px;
76 background-position: center top;
77}
78
79code, pre, .mono { font-family: var(--mono); }
80
81.size, .num, .meta time, .count, .tokens td { font-variant-numeric: tabular-nums; }
82
83a {
84 color: var(--link);
85 text-decoration: none;
86 transition: color 0.12s ease;
87}
88a:hover { color: var(--link-lift); text-decoration: underline; }
89
90:focus-visible {
91 outline: 2px solid var(--accent);
92 outline-offset: 2px;
93 border-radius: 2px;
94}
95
96::selection { background: var(--accent-dim); }
97
98h1, h2, h3, h4 {
99 text-wrap: balance;
100 font-weight: 600;
101 line-height: 1.25;
102 margin: 0;
103}
104
105.pagetitle, .commitfull h2, section > h2,
106.emptystate h2, .loginbox h1, .notfound h1, .markdown h1, .markdown h2 {
107 font-family: var(--sans);
108 font-weight: 700;
109 letter-spacing: -0.01em;
110}
111
112.repohead h1, .repocard .name {
113 font-family: var(--serif);
114 font-weight: 600;
115 letter-spacing: -0.01em;
116}
117
118.wrap {
119 max-width: var(--wrap);
120 margin: 0 auto;
121 padding: 0 1.5rem;
122}
123
124@media (prefers-reduced-motion: reduce) {
125 *, *::before, *::after {
126 animation-duration: 0.01ms !important;
127 transition-duration: 0.01ms !important;
128 }
129}
130
131.topbar {
132 position: sticky;
133 top: 0;
134 z-index: 50;
135 background: var(--sunken);
136 border-bottom: 1px solid rgba(107, 158, 120, 0.3);
137
138 .wrap {
139 display: flex;
140 align-items: center;
141 gap: 0.85rem;
142 height: var(--bar);
143 }
144
145 // The wordmark the other four sites set: caps, tracked, with the identity
146 // dot after it. The serif is kept for repository names and nothing else.
147 .brand {
148 display: inline-flex;
149 align-items: center;
150 gap: 0.6rem;
151 font-family: var(--sans);
152 font-weight: 600;
153 font-size: 0.78rem;
154 text-transform: uppercase;
155 letter-spacing: var(--track);
156 color: #ede8e0;
157
158 svg { width: 16px; height: 16px; color: var(--accent); flex: none; }
159 &:hover { color: #ede8e0; text-decoration: none; }
160 &:hover svg { color: var(--accent-lift); }
161
162 &::after {
163 content: "";
164 width: 6px;
165 height: 6px;
166 border-radius: 50%;
167 background: var(--accent);
168 }
169 }
170
171 .context {
172 display: flex;
173 align-items: center;
174 gap: 0.4rem;
175 min-width: 0;
176 flex: 1;
177 font-family: var(--mono);
178 font-size: var(--t-sm);
179
180 .sep { color: var(--faint); }
181
182 a { color: var(--muted); &:hover { color: var(--text); } }
183
184 .here {
185 color: var(--text);
186 overflow: hidden;
187 text-overflow: ellipsis;
188 white-space: nowrap;
189 }
190
191 .ref {
192 color: var(--muted);
193 background: var(--raised);
194 border-radius: 3px;
195 padding: 0.05rem 0.4rem;
196 font-size: var(--t-xs);
197 white-space: nowrap;
198 }
199 }
200
201 nav {
202 display: flex;
203 align-items: center;
204 gap: 0.4rem;
205 font-size: 0.8rem;
206 flex: none;
207
208 a {
209 padding: 0.3rem 0.7rem;
210 color: rgba(221, 215, 205, 0.8);
211 text-transform: lowercase;
212 letter-spacing: 0.05em;
213 &:hover { color: #ede8e0; text-decoration: none; }
214 }
215
216 // The sign in and account links read as the button the other four put in
217 // the same corner.
218 a:last-child {
219 border: 1px solid rgba(221, 215, 205, 0.28);
220 border-radius: var(--radius);
221 text-transform: none;
222 letter-spacing: 0.01em;
223 &:hover { border-color: rgba(221, 215, 205, 0.5); }
224 }
225 }
226}
227
228main.wrap { padding-top: 2rem; padding-bottom: 3rem; }
229
230.footer {
231 border-top: 1px solid var(--line);
232 margin-top: 5rem;
233 padding: 2.25rem 0 2.5rem;
234 font-size: var(--t-sm);
235
236 .cols {
237 display: grid;
238 grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr));
239 gap: 2rem;
240 }
241
242 // The `// Section` heading the other four sites set in their footers.
243 .h5 {
244 font-family: var(--sans);
245 font-size: 0.7rem;
246 font-weight: 600;
247 letter-spacing: 0.12em;
248 text-transform: uppercase;
249 color: var(--warn);
250 margin-bottom: 0.7rem;
251 }
252
253 .about p { margin: 0; color: var(--muted); max-width: 46ch; }
254
255 ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
256 a { color: var(--muted); &:hover { color: var(--text); } }
257
258}
259
260// The strip under the footer, matching the one the other four sites close on.
261.footer-bar {
262 border-top: 1px solid rgba(107, 158, 120, 0.2);
263 padding: 1rem 0;
264
265 .wrap {
266 display: flex;
267 align-items: center;
268 justify-content: space-between;
269 gap: 1rem;
270 flex-wrap: wrap;
271 }
272
273 small { color: var(--faint); font-size: var(--t-xs); }
274
275 .footer-bar-link {
276 display: inline-flex;
277 color: var(--faint);
278 &:hover { color: var(--accent-lift); }
279 }
280}
281
282.pagehead {
283 display: flex;
284 align-items: baseline;
285 justify-content: space-between;
286 gap: 1rem;
287 flex-wrap: wrap;
288 margin-bottom: 1.5rem;
289}
290
291.pagetitle {
292 font-size: var(--t-xl);
293 letter-spacing: -0.02em;
294 display: flex;
295 align-items: center;
296 gap: 0.65rem;
297}
298
299.count {
300 font-family: var(--mono);
301 font-size: var(--t-xs);
302 font-weight: 400;
303 color: var(--muted);
304 background: var(--raised);
305 border-radius: 999px;
306 padding: 0.1rem 0.5rem;
307}
308
309.badge {
310 font-size: var(--t-xs);
311 font-weight: 500;
312 letter-spacing: 0.02em;
313 padding: 0.1rem 0.45rem;
314 border-radius: 3px;
315 border: 1px solid;
316 white-space: nowrap;
317
318 &.mirror { color: var(--link); border-color: rgba(132, 169, 201, 0.4); }
319 &.archived { color: var(--faint); border-color: var(--line-strong); }
320 &.empty { color: var(--faint); border-color: var(--line-strong); }
321 &.default { color: var(--add); border-color: rgba(127, 176, 105, 0.4); }
322 &.annotated { color: var(--muted); border-color: var(--line-strong); }
323
324 &.gone {
325 color: var(--bg);
326 background: var(--warn);
327 border-color: var(--warn);
328 font-weight: 600;
329 }
330}
331
332.hint { color: var(--muted); font-size: var(--t-sm); }
333.empty { color: var(--faint); }
334.error { color: var(--del); }
335.warn { color: var(--warn); }
336
337// Its own element rather than a rule on `code`, since the same prose mentions
338// commands inline and one selector would turn those sentences into blocks.
339pre.cmd {
340 display: block;
341 font-family: var(--mono);
342 font-size: var(--t-sm);
343 line-height: 1.7;
344 background: var(--sunken);
345 border: 1px solid var(--line);
346 border-radius: var(--radius);
347 padding: 0.7rem 0.85rem;
348 margin: 0.6rem 0;
349 overflow-x: auto;
350 white-space: pre-wrap;
351 word-break: break-word;
352 color: var(--text);
353 user-select: all;
354}
355
356p code, li code, .hint code, td code {
357 font-family: var(--mono);
358 font-size: 0.9em;
359 background: var(--raised);
360 border-radius: 3px;
361 padding: 0.05rem 0.3rem;
362 color: var(--text);
363}
364
365.notice {
366 background: var(--surface);
367 border: 1px solid var(--line);
368 border-radius: var(--radius);
369 padding: 1rem 1.15rem;
370 margin-bottom: 1.5rem;
371}
372
373.emptystate {
374 background: var(--surface);
375 border: 1px solid var(--line);
376 border-radius: var(--radius);
377 padding: 1.5rem 1.65rem;
378
379 h2 { font-size: var(--t-md); margin-bottom: 0.4rem; }
380 p { margin: 0.5rem 0; color: var(--muted); }
381}
382
383button, .btn {
384 font-family: var(--sans);
385 font-size: var(--t-sm);
386 font-weight: 500;
387 background: var(--raised);
388 color: var(--text);
389 border: 1px solid var(--line-strong);
390 border-radius: var(--radius);
391 padding: 0.3rem 0.75rem;
392 cursor: pointer;
393 transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;
394 white-space: nowrap;
395
396 &:hover { border-color: var(--muted); background: var(--line); text-decoration: none; }
397}
398
399.btn {
400 display: inline-block;
401 padding: 0.6rem 1.1rem;
402 border: 1px solid transparent;
403 border-radius: var(--radius);
404 background: none;
405 font-size: 0.82rem;
406 font-weight: 500;
407 letter-spacing: 0.04em;
408 color: var(--muted);
409 &:hover { text-decoration: none; }
410}
411
412.btn-primary {
413 background: var(--accent-dim);
414 border-color: var(--accent);
415 color: var(--accent-lift);
416 &:hover { background: rgba(107, 158, 120, 0.26); border-color: var(--accent); }
417}
418
419// Matches Bootstrap's .btn-sm as the other four resolve it, since a button
420// beside body text should be the same object on every site here.
421.btn-sm {
422 padding: 0.25rem 0.5rem;
423 font-size: 0.805rem;
424 border-radius: var(--radius-sm);
425 letter-spacing: 0.02em;
426}
427
428.btn-ghost {
429 border-color: rgba(221, 215, 205, 0.28);
430 color: var(--text);
431 &:hover { border-color: rgba(221, 215, 205, 0.5); background: rgba(221, 215, 205, 0.05); color: var(--text); }
432}
433
434button.primary {
435 background: var(--accent);
436 border-color: var(--accent);
437 color: #17130c;
438 &:hover { background: var(--accent-lift); border-color: var(--accent-lift); }
439}
440
441button.danger:hover { border-color: var(--del); color: var(--del); background: var(--del-bg); }
442
443button.linkish {
444 background: none;
445 border: none;
446 color: var(--muted);
447 padding: 0;
448 font-size: var(--t-sm);
449 &:hover { color: var(--text); background: none; text-decoration: underline; }
450}
451
452form.inline { display: inline-flex; gap: 0.5rem; align-items: center; }
453
454input[type="text"], input[type="password"], input[type="url"] {
455 font-family: var(--mono);
456 font-size: var(--t-sm);
457 background: var(--sunken);
458 color: var(--text);
459 border: 1px solid var(--line);
460 border-radius: var(--radius);
461 padding: 0.4rem 0.65rem;
462 width: 100%;
463 transition: border-color 0.12s ease;
464
465 &:focus { border-color: var(--accent); }
466 &[readonly] { color: var(--muted); cursor: pointer; }
467}
468
469.repolist { list-style: none; padding: 0; margin: 0; }
470
471.repocard {
472 border-top: 1px solid var(--line);
473 padding: 0.85rem 0;
474 display: grid;
475 gap: 0.25rem;
476
477 &:last-child { border-bottom: 1px solid var(--line); }
478
479 .row { display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; }
480
481 .name {
482 font-family: var(--serif);
483 font-size: var(--t-lg);
484 font-weight: 600;
485 color: var(--text);
486 letter-spacing: -0.01em;
487 &:hover { color: var(--accent); text-decoration: none; }
488 }
489
490 .desc { margin: 0; color: var(--muted); max-width: 68ch; }
491
492 .meta {
493 margin: 0;
494 color: var(--faint);
495 font-size: var(--t-sm);
496 display: flex;
497 flex-wrap: wrap;
498 gap: 0.35rem 1.1rem;
499 }
500
501 .syncerr { color: var(--del); font-size: var(--t-sm); margin: 0; }
502}
503
504.topics { margin: 0; display: flex; flex-wrap: wrap; gap: 0.35rem; }
505
506.topic {
507 font-size: var(--t-xs);
508 color: var(--muted);
509 background: var(--raised);
510 border-radius: 999px;
511 padding: 0.05rem 0.55rem;
512}
513
514.repohead {
515 margin-bottom: 1.25rem;
516
517 .titlerow {
518 display: flex;
519 align-items: center;
520 gap: 0.6rem;
521 flex-wrap: wrap;
522 margin-bottom: 0.35rem;
523 }
524
525 h1 {
526 font-family: var(--mono);
527 font-size: var(--t-lg);
528 letter-spacing: -0.02em;
529 a { color: var(--text); &:hover { color: var(--accent); text-decoration: none; } }
530 }
531
532 .desc { margin: 0 0 0.5rem; color: var(--muted); max-width: 68ch; }
533}
534
535.repotabs {
536 display: flex;
537 gap: 0.25rem;
538 margin-top: 0.9rem;
539 border-bottom: 1px solid var(--line);
540 overflow-x: auto;
541 scrollbar-width: none;
542 &::-webkit-scrollbar { display: none; }
543
544 a {
545 display: flex;
546 align-items: center;
547 gap: 0.4rem;
548 padding: 0.45rem 0.75rem;
549 color: var(--muted);
550 font-size: var(--t-sm);
551 border-bottom: 2px solid transparent;
552 margin-bottom: -1px;
553 white-space: nowrap;
554
555 &:hover { color: var(--text); text-decoration: none; }
556 &[aria-current="page"] {
557 color: var(--text);
558 border-bottom-color: var(--accent);
559 font-weight: 500;
560 }
561 }
562}
563
564.toolbar {
565 display: flex;
566 align-items: center;
567 gap: 0.75rem;
568 margin-bottom: 1rem;
569 flex-wrap: wrap;
570
571 .stat { color: var(--faint); font-size: var(--t-sm); }
572 .spacer { flex: 1; }
573}
574
575.crumbs .leaf { color: var(--text); }
576
577.crumbs {
578 font-family: var(--mono);
579 font-size: var(--t-sm);
580 color: var(--faint);
581 a { color: var(--link); }
582}
583
584.refswitch {
585 position: relative;
586
587 summary {
588 cursor: pointer;
589 list-style: none;
590 display: inline-flex;
591 align-items: center;
592 gap: 0.4rem;
593 background: var(--raised);
594 border: 1px solid var(--line-strong);
595 border-radius: var(--radius);
596 padding: 0.3rem 0.7rem;
597 font-family: var(--mono);
598 font-size: var(--t-sm);
599 color: var(--text);
600
601 &::-webkit-details-marker { display: none; }
602 &::after {
603 content: "";
604 width: 0; height: 0;
605 border-left: 4px solid transparent;
606 border-right: 4px solid transparent;
607 border-top: 5px solid var(--muted);
608 }
609 &:hover { border-color: var(--muted); }
610 }
611
612 .refmenu {
613 position: absolute;
614 z-index: 40;
615 top: calc(100% + 4px);
616 left: 0;
617 min-width: 240px;
618 max-height: 340px;
619 overflow-y: auto;
620 background: var(--raised);
621 border: 1px solid var(--line-strong);
622 border-radius: var(--radius);
623 padding: 0.4rem 0;
624 box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
625
626 h4 {
627 margin: 0.4rem 0.85rem 0.2rem;
628 font-size: var(--t-xs);
629 font-weight: 600;
630 letter-spacing: 0.06em;
631 text-transform: uppercase;
632 color: var(--faint);
633 }
634 ul { list-style: none; margin: 0; padding: 0; }
635 li a {
636 display: block;
637 padding: 0.25rem 0.85rem;
638 font-family: var(--mono);
639 font-size: var(--t-sm);
640 color: var(--text);
641 &:hover { background: var(--line); text-decoration: none; }
642 }
643 }
644}
645
646.tree {
647 width: 100%;
648 border-collapse: collapse;
649 border: 1px solid var(--line);
650 border-radius: var(--radius);
651 overflow: hidden;
652 font-family: var(--mono);
653 font-size: var(--t-sm);
654 // A file listing is scanned rather than read, so it drops the body line-height.
655 line-height: 1.45;
656
657 td {
658 padding: 0.25rem 0.85rem;
659 border-bottom: 1px solid var(--line);
660 }
661 tr:last-child td { border-bottom: none; }
662 tr:hover td { background: var(--surface); }
663
664 .icon {
665 width: 1.75rem;
666 padding-right: 0;
667 color: var(--faint);
668 svg { display: block; width: 15px; height: 15px; }
669 }
670 tr.dir .icon { color: var(--accent); }
671
672 .name a { color: var(--link); }
673 .size { text-align: right; color: var(--faint); white-space: nowrap; }
674 .submodule { color: var(--muted); }
675}
676
677.readme {
678 margin-top: 1.75rem;
679 border: 1px solid var(--line);
680 border-radius: var(--radius);
681 overflow: hidden;
682
683 .readmehead {
684 background: var(--surface);
685 border-bottom: 1px solid var(--line);
686 padding: 0.5rem 1.15rem;
687 color: var(--muted);
688 font-family: var(--mono);
689 font-size: var(--t-sm);
690 }
691 .markdown { padding: 1.5rem 1.75rem; }
692}
693
694.markdown {
695 > * { max-width: 72ch; }
696 > pre, > table { max-width: none; }
697
698 h1, h2 { border-bottom: 1px solid var(--line); padding-bottom: 0.3rem; margin: 1.75rem 0 0.85rem; }
699 h1 { font-size: var(--t-lg); }
700 h2 { font-size: var(--t-md); }
701 h3 { font-size: var(--t-base); margin: 1.5rem 0 0.6rem; }
702 > :first-child { margin-top: 0; }
703
704 p, ul, ol { margin: 0.85rem 0; }
705 li { margin: 0.25rem 0; }
706
707 img { max-width: 100%; }
708
709 table { border-collapse: collapse; display: block; overflow-x: auto; }
710 th, td { border: 1px solid var(--line); padding: 0.35rem 0.7rem; text-align: left; }
711 th { background: var(--surface); }
712
713 blockquote {
714 margin: 1rem 0;
715 padding: 0.1rem 0 0.1rem 1rem;
716 border-left: 2px solid var(--line-strong);
717 color: var(--muted);
718 }
719
720 pre {
721 background: var(--sunken);
722 border: 1px solid var(--line);
723 border-radius: var(--radius);
724 padding: 0.85rem 1rem;
725 overflow-x: auto;
726 font-size: var(--t-sm);
727 }
728 code {
729 background: var(--raised);
730 padding: 0.1rem 0.35rem;
731 border-radius: 3px;
732 font-size: 0.9em;
733 }
734 pre code { background: none; padding: 0; }
735
736 hr { border: none; border-top: 1px solid var(--line); margin: 1.75rem 0; }
737}
738
739.code {
740 border: 1px solid var(--line);
741 border-radius: var(--radius);
742 background: var(--sunken);
743 overflow-x: auto;
744 font-size: var(--t-sm);
745
746 pre { margin: 0; padding: 0.85rem 0; }
747 &.plain { margin: 0; padding: 0.85rem 1rem; white-space: pre; }
748
749 // chroma emits style="outline:none" inline on every line-number anchor, and
750 // an inline style beats any author selector, so the site's focus ring has to
751 // be restored with !important or those links are keyboard-invisible.
752 a:focus-visible {
753 outline: 2px solid var(--accent) !important;
754 outline-offset: -2px;
755 }
756
757 // chroma's line numbers.
758 .lnt, .ln {
759 color: var(--faint);
760 user-select: none;
761 padding-right: 1rem;
762 }
763}
764
765.commits { list-style: none; padding: 0; margin: 0; }
766
767.commit {
768 border-top: 1px solid var(--line);
769 padding: 0.7rem 0;
770 &:last-child { border-bottom: 1px solid var(--line); }
771
772 .subject {
773 display: block;
774 color: var(--text);
775 font-weight: 500;
776 margin-bottom: 0.15rem;
777 &:hover { color: var(--link-lift); }
778 }
779
780 .meta {
781 color: var(--faint);
782 font-size: var(--t-sm);
783 display: flex;
784 flex-wrap: wrap;
785 gap: 0.5rem 0.85rem;
786 }
787 .meta code { color: var(--accent); font-size: var(--t-xs); }
788}
789
790.commitfull {
791 h2 { font-size: var(--t-md); margin-bottom: 0.6rem; }
792
793 .body {
794 background: var(--surface);
795 border-left: 2px solid var(--line-strong);
796 border-radius: 0 var(--radius) var(--radius) 0;
797 padding: 0.8rem 1.1rem;
798 white-space: pre-wrap;
799 color: var(--muted);
800 font-family: var(--mono);
801 font-size: var(--t-sm);
802 margin: 0 0 1rem;
803 }
804
805 .meta {
806 color: var(--faint);
807 font-size: var(--t-sm);
808 margin: 0.3rem 0;
809 code { font-size: var(--t-xs); color: var(--accent); }
810 }
811
812 .diffstat {
813 margin: 1.5rem 0 0.85rem;
814 font-size: var(--t-sm);
815 color: var(--muted);
816 }
817}
818
819ins { color: var(--add); text-decoration: none; font-weight: 500; }
820del { color: var(--del); text-decoration: none; font-weight: 500; }
821
822.pager {
823 margin-top: 1.5rem;
824 display: flex;
825 gap: 0.75rem;
826}
827
828.difffile {
829 border: 1px solid var(--line);
830 border-radius: var(--radius);
831 margin-bottom: 1.25rem;
832 // Not `overflow: hidden`. Clipping here would make this box the containing
833 // block for the sticky header below, which would then stick to the box and
834 // float over its own hunks. The corners are squared off on the header instead.
835 overflow: visible;
836
837 .diffhead {
838 // Sticky under the topbar, so the filename stays put while a long file's
839 // hunks scroll.
840 position: sticky;
841 top: calc(var(--bar) - 1px);
842 z-index: 10;
843 border-radius: var(--radius) var(--radius) 0 0;
844 background: var(--surface);
845 border-bottom: 1px solid var(--line);
846 padding: 0.5rem 0.85rem;
847 display: flex;
848 align-items: center;
849 // A flex item will not shrink below its min-content width, so without the
850 // wrap and the min-width below a deeply nested path sets the width of this
851 // header, and with it the whole page's horizontal scroll.
852 flex-wrap: wrap;
853 gap: 0.7rem;
854 font-size: var(--t-sm);
855
856 code {
857 font-family: var(--mono);
858 color: var(--text);
859 min-width: 0;
860 overflow-wrap: anywhere;
861 }
862 .counts { margin-left: auto; font-size: var(--t-xs); white-space: nowrap; }
863 }
864
865 .binary { padding: 0.9rem; color: var(--faint); margin: 0; font-size: var(--t-sm); }
866
867 .status {
868 font-size: var(--t-xs);
869 font-weight: 600;
870 letter-spacing: 0.04em;
871 text-transform: uppercase;
872 padding: 0.05rem 0.4rem;
873 border-radius: 3px;
874
875 &.added { color: var(--add); background: var(--add-bg); }
876 &.deleted { color: var(--del); background: var(--del-bg); }
877 &.renamed { color: var(--link); background: rgba(132, 169, 201, 0.1); }
878 &.copied { color: var(--link); background: rgba(132, 169, 201, 0.1); }
879 &.modified { color: var(--warn); background: var(--warn-bg); }
880 }
881}
882
883.hunk {
884 width: 100%;
885 border-collapse: collapse;
886 font-family: var(--mono);
887 font-size: var(--t-sm);
888 line-height: 1.55;
889
890 td { padding: 0 0.5rem; }
891
892 .num {
893 width: 1%;
894 min-width: 3.25rem;
895 text-align: right;
896 color: var(--faint);
897 background: var(--sunken);
898 user-select: none;
899 // A wrapped code line must not drag its line numbers down with it.
900 vertical-align: top;
901 border-right: 1px solid var(--line);
902 font-size: var(--t-xs);
903 }
904
905 .code {
906 white-space: pre-wrap;
907 word-break: break-word;
908 border: none;
909 border-radius: 0;
910 background: none;
911 }
912
913 // A marker column in the text itself, so add and delete survive being read
914 // without colour: copy-pasted, printed, or by anyone colour blind.
915 tr.add .code::before,
916 tr.del .code::before,
917 tr.context .code::before {
918 display: inline-block;
919 width: 1ch;
920 margin-right: 0.5ch;
921 color: var(--faint);
922 }
923 tr.add .code::before { content: "+"; color: var(--add); }
924 tr.del .code::before { content: "-"; color: var(--del); }
925 tr.context .code::before { content: " "; }
926
927 tr.add td { background: var(--add-bg); }
928 tr.del td { background: var(--del-bg); }
929 tr.add .num { background: rgba(127, 176, 105, 0.14); }
930 tr.del .num { background: rgba(209, 101, 107, 0.14); }
931
932 // `.hunkhead` is the row itself, so this has to be tr.hunkhead rather than a
933 // descendant. The rule separates hunks, so the first one in a file skips it.
934 tr.hunkhead td {
935 background: var(--raised);
936 color: var(--faint);
937 padding: 0.25rem 0.85rem;
938 font-size: var(--t-xs);
939 border-top: 1px solid var(--line);
940 }
941 tr.hunkhead:first-child td { border-top: none; }
942}
943
944.refs, .tokens {
945 width: 100%;
946 border-collapse: collapse;
947 border: 1px solid var(--line);
948 border-radius: var(--radius);
949 overflow: hidden;
950 font-size: var(--t-sm);
951
952 td { padding: 0.55rem 0.85rem; border-bottom: 1px solid var(--line); }
953 tr:last-child td { border-bottom: none; }
954 tr:hover td { background: var(--surface); }
955
956 .name { font-family: var(--mono); font-weight: 500; }
957 .subject { color: var(--muted); }
958 .when, .dl { color: var(--faint); white-space: nowrap; }
959 .dl { text-align: right; }
960 .dl a { margin-left: 0.75rem; }
961}
962
963.clonebox {
964 margin-top: 2.5rem;
965 border: 1px solid var(--line);
966 border-radius: var(--radius);
967 background: var(--surface);
968 padding: 1.15rem 1.35rem;
969
970 h3 {
971 font-size: var(--t-xs);
972 font-weight: 600;
973 letter-spacing: 0.06em;
974 text-transform: uppercase;
975 color: var(--faint);
976 margin-bottom: 0.5rem;
977 }
978 h3 + p, h3 + input { margin-top: 0; }
979 input { margin-bottom: 0.35rem; }
980 > h3:not(:first-child) { margin-top: 1.25rem; }
981}
982
983// The 100MB ceiling Cloudflare puts on one request is invisible until a push
984// fails, so the meter has to show it before that.
985.meter {
986 margin: 0.85rem 0 0;
987 color: var(--faint);
988 font-size: var(--t-xs);
989 display: grid;
990 gap: 0.35rem;
991
992 .bar {
993 display: block;
994 height: 5px;
995 background: var(--sunken);
996 border: 1px solid var(--line);
997 border-radius: 3px;
998 overflow: hidden;
999
1000 span {
1001 display: block;
1002 height: 100%;
1003 background: var(--add);
1004 transition: width 0.3s ease;
1005 }
1006 }
1007
1008 // Past about three quarters it stops being trivia and starts being a warning.
1009 &.warn .bar span { background: var(--warn); }
1010 &.over .bar span { background: var(--del); }
1011}
1012
1013.pushlimit {
1014 margin-top: 1.25rem;
1015 border: 1px solid rgba(224, 164, 88, 0.3);
1016 border-radius: var(--radius);
1017 background: var(--warn-bg);
1018 padding: 1rem 1.15rem;
1019
1020 h4 {
1021 font-size: var(--t-sm);
1022 color: var(--warn);
1023 margin-bottom: 0.5rem;
1024 }
1025 p { margin: 0.6rem 0; font-size: var(--t-sm); color: var(--muted); }
1026 code { background: var(--sunken); }
1027 strong { color: var(--text); }
1028}
1029
1030.firstpush {
1031 align-self: flex-start;
1032
1033 summary {
1034 cursor: pointer;
1035 list-style: none;
1036 font-size: var(--t-sm);
1037 color: var(--muted);
1038 border: 1px solid var(--line-strong);
1039 border-radius: var(--radius);
1040 padding: 0.3rem 0.75rem;
1041 &::-webkit-details-marker { display: none; }
1042 &::before { content: "+ "; color: var(--accent); }
1043 &:hover { color: var(--text); border-color: var(--muted); }
1044 }
1045 &[open] summary::before { content: "\2212 "; }
1046
1047 .firstpushbody {
1048 margin-top: 0.85rem;
1049 border: 1px solid var(--line);
1050 border-radius: var(--radius);
1051 background: var(--surface);
1052 padding: 1.15rem 1.35rem;
1053 p { margin: 0 0 0.5rem; color: var(--muted); font-size: var(--t-sm); }
1054 }
1055}
1056
1057.loginbox {
1058 max-width: 360px;
1059 margin: 4rem auto;
1060
1061 h1 { font-size: var(--t-lg); margin-bottom: 0.5rem; }
1062 label { display: block; margin: 1rem 0 0.5rem; font-size: var(--t-sm); color: var(--muted); }
1063 button { width: 100%; padding: 0.45rem; margin-top: 0.85rem; }
1064}
1065
1066// Top and bottom, so a section following a panel like the README gets the same
1067// air as one following another section. Adjacent margins collapse, so two
1068// sections in a row still sit 2.5rem apart rather than 5.
1069section { margin: 2.5rem 0; }
1070section > h2 {
1071 font-size: var(--t-md);
1072 border-bottom: 1px solid var(--line);
1073 padding-bottom: 0.4rem;
1074 margin-bottom: 1rem;
1075}
1076
1077.tokennew {
1078 border-color: rgba(217, 154, 78, 0.35);
1079 background: var(--accent-dim);
1080 input { margin: 0.6rem 0; }
1081}
1082
1083.editbox {
1084 margin-top: 1.75rem;
1085 summary { cursor: pointer; color: var(--muted); font-size: var(--t-sm); }
1086 label { display: block; margin: 0.85rem 0 0.35rem; font-size: var(--t-sm); color: var(--muted); }
1087 button { margin-top: 0.85rem; }
1088}
1089
1090// The same shape the other four sites use for a 404: an amber caps label, a
1091// plain heading, the description the handler set, and a way back. Left aligned
1092// like every other page here rather than centred on its own.
1093.section-label {
1094 font-size: 0.7rem;
1095 font-weight: 600;
1096 letter-spacing: 0.12em;
1097 text-transform: uppercase;
1098 color: var(--warn);
1099}
1100
1101.notfound {
1102 padding: 3rem 0 5rem;
1103
1104 h1 {
1105 font-family: var(--sans);
1106 font-size: 2.3rem;
1107 font-weight: 700;
1108 color: var(--bright);
1109 letter-spacing: -0.01em;
1110 margin: 0.6rem 0 0.75rem;
1111 }
1112
1113 p { color: var(--muted); margin: 0 0 1.5rem; }
1114}
1115
1116@media (min-width: 1400px) {
1117 :root { --wrap: 1320px; }
1118}
1119
1120@media (max-width: 700px) {
1121 :root { --wrap: 100%; }
1122
1123 .topbar .context .sep:first-child, .topbar .context { font-size: var(--t-xs); }
1124 .footer .cols { grid-template-columns: 1fr; gap: 1.75rem; }
1125 .wrap { padding: 0 1rem; }
1126 main.wrap { padding-top: 1.25rem; }
1127
1128 .pagehead { flex-direction: column; align-items: stretch; gap: 0.75rem; }
1129
1130 .hunk .num { min-width: 2.25rem; }
1131 .difffile .diffhead { position: static; }
1132
1133 .repocard .meta { gap: 0.35rem 0.7rem; }
1134 .refs .subject, .tokens .subject { display: none; }
1135}
1136
1137// Home hero -----------------------------------------------------------------
1138//
1139// The same shape analytics, logging and status open with. Values are matched to
1140// their pages.scss rather than reinvented, since the point is that the four
1141// look like one suite.
1142
1143.hero {
1144 background: var(--sunken);
1145 border-bottom: 1px solid rgba(107, 158, 120, 0.3);
1146 padding: 4rem 0;
1147
1148 .hero-eyebrow {
1149 display: inline-flex;
1150 align-items: center;
1151 gap: 0.55rem;
1152 font-size: 0.72rem;
1153 font-weight: 600;
1154 letter-spacing: 0.12em;
1155 text-transform: uppercase;
1156 color: var(--warn);
1157 background: rgba(201, 168, 76, 0.16);
1158 border: 1px solid rgba(201, 168, 76, 0.5);
1159 padding: 0.35rem 0.75rem;
1160 border-radius: 999px;
1161 }
1162
1163 .eyebrow-dot {
1164 width: 6px;
1165 height: 6px;
1166 border-radius: 50%;
1167 background: var(--accent);
1168 }
1169
1170 .hero-title {
1171 font-family: var(--sans);
1172 font-size: clamp(2rem, 5vw, 3.2rem);
1173 font-weight: 700;
1174 line-height: 1.1;
1175 color: #ede8e0;
1176 letter-spacing: -0.01em;
1177 margin-top: 1.5rem;
1178
1179 .accent { color: var(--accent-lift); }
1180 }
1181
1182 .hero-sub {
1183 color: var(--muted);
1184 font-size: 1rem;
1185 line-height: 1.7;
1186 margin: 1.25rem 0 0;
1187 max-width: 620px;
1188 }
1189
1190 .hero-ctas {
1191 display: flex;
1192 gap: 0.75rem;
1193 flex-wrap: wrap;
1194 margin-top: 1.75rem;
1195
1196 }
1197}
1198
1199.stat-strip {
1200 padding: 1.5rem 0;
1201 border-bottom: 1px solid rgba(107, 158, 120, 0.3);
1202
1203 .stat-row {
1204 display: grid;
1205 grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
1206 gap: 1.5rem;
1207 }
1208
1209 .stat { text-align: center; }
1210
1211 .stat-label {
1212 font-size: 0.66rem;
1213 font-weight: 600;
1214 letter-spacing: 0.12em;
1215 text-transform: uppercase;
1216 color: var(--faint);
1217 }
1218
1219 .stat-value {
1220 font-size: 1.75rem;
1221 font-weight: 700;
1222 color: var(--accent-lift);
1223 letter-spacing: -0.01em;
1224 line-height: 1.2;
1225 margin-top: 0.2rem;
1226 font-variant-numeric: tabular-nums;
1227 }
1228
1229 // A date is a longer string than a count and would otherwise set the row
1230 // height for the three tiles beside it.
1231 .stat-value-sm { font-size: 1.05rem; }
1232}