internal/web/static/style.css
1502 lines · 51272 bytes
1/* gitbay stylesheet — Harbor: black and white ground, two accents with
2 separate jobs. Blue is what you can do (links, buttons, focus); orange
3 is where you are and what wants you (active nav, counts, pending state,
4 unverified signatures). Orange is never a button, so the two never
5 compete. One file, light and dark via prefers-color-scheme. Tokens
6 first; components use tokens only. No external requests: Atkinson
7 Hyperlegible is served from this origin. */
8
9@font-face {
10 font-family: "Atkinson Hyperlegible Next";
11 font-style: normal;
12 font-weight: 400 700;
13 font-display: swap;
14 src: url(/static/fonts/atkinson-next-roman.woff2) format("woff2");
15}
16@font-face {
17 font-family: "Atkinson Hyperlegible Next";
18 font-style: italic;
19 font-weight: 400 700;
20 font-display: swap;
21 src: url(/static/fonts/atkinson-next-italic.woff2) format("woff2");
22}
23@font-face {
24 font-family: "Atkinson Hyperlegible Mono";
25 font-style: normal;
26 font-weight: 400 600;
27 font-display: swap;
28 src: url(/static/fonts/atkinson-mono-roman.woff2) format("woff2");
29}
30
31:root {
32 /* declare native light+dark support: correct form controls and
33 scrollbars per scheme, and opt out of browser auto-darkening */
34 color-scheme: light dark;
35
36 /* ground and ink */
37 --bg: #ffffff;
38 --fg: #0d0d0d;
39 --muted: #595959; /* 7.00:1 on white */
40 --faint: #eaeaea; /* hairlines, row separators */
41 --line: #d4d4d4; /* control borders, table edges */
42 --surface: #ffffff;
43 --hover: #f5f5f5;
44 --code-bg: #f5f5f5;
45 --fill-subtle: #ececec; /* hunk headers, summary hover */
46 --diff-add: #e4f6ea; /* row grounds: tinted enough to scan, light
47 enough that syntax colors stay legible */
48 --diff-del: #fdeaea;
49
50 /* blue: what you can do */
51 --accent: #0000f0; /* links, focus — 9.30:1 on white */
52 --accent-fg: #ffffff;
53 --fill: #0000f0; /* button grounds; white on it is 9.30:1 */
54
55 /* orange: where you are, what wants you */
56 --mark: #e4572e; /* bars and underlines — non-text, 3.0 bar */
57 --warn: #c2410c; /* the same orange at text size — 5.18:1 */
58
59 /* semantic */
60 --ok: #0a7d3c;
61 --bad: #c62828;
62 --done: #6b21a8; /* merged */
63 --neutral: #595959;
64
65 /* the rail is black in both schemes: the one brand constant */
66 --shell-bg: #000000;
67 --shell-fg: #f2f2f2;
68 --shell-muted: #8f8f8f;
69 --shell-line: #1c1c1c;
70 --shell-hover: #141414;
71 --shell-mark: #ff6b3d; /* 7.42:1 on black, both schemes */
72
73 /* type */
74 --sans: "Atkinson Hyperlegible Next", -apple-system, BlinkMacSystemFont,
75 "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
76 --mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono",
77 SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
78 --fs-0: 0.78rem;
79 --fs-1: 0.85rem;
80 --fs-2: 0.92rem;
81 --fs-3: 1rem;
82 --fs-4: 1.2rem;
83 --fs-5: 1.6rem;
84
85 /* spacing */
86 --sp-1: 0.25rem;
87 --sp-2: 0.5rem;
88 --sp-3: 0.75rem;
89 --sp-4: 1rem;
90 --sp-5: 1.5rem;
91 --sp-6: 2.5rem;
92
93 --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23595959' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
94
95 /* radii: 2px everywhere — chart plates, not pills */
96 --r-sm: 2px;
97 --r-md: 2px;
98 --r-lg: 2px;
99 --r-pill: 2px;
100}
101@media (prefers-color-scheme: dark) {
102 :root {
103 --bg: #0a0a0a;
104 --fg: #f2f2f2;
105 --muted: #a1a1a1; /* 7.66:1 on #0a0a0a */
106 --faint: #1c1c1c;
107 --line: #2e2e2e;
108 --surface: #0f0f0f;
109 --hover: #161616;
110 --code-bg: #050505;
111 --fill-subtle: #161616;
112 --diff-add: #0d2a18;
113 --diff-del: #2c1113;
114 --accent: #6272ff; /* pure #0000f0 is 2.13:1 here. Picked against
115 the lightest ground it lands on, not the page:
116 a link wrapping inline code sits on #161616,
117 where the old #5b6bff was 4.30:1. Now 4.63:1
118 there and 5.06:1 on the page. */
119 --accent-fg: #ffffff;
120 --fill: #0000f0; /* fills stay pure; white on it clears 9:1 */
121 --mark: #ff6b3d;
122 --warn: #ff6b3d;
123 --ok: #3fce7a;
124 --bad: #ff6b6b;
125 --done: #c084fc;
126 --neutral: #a1a1a1;
127 --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23a1a1a1' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
128 }
129}
130
131* { box-sizing: border-box; }
132html { font-size: 15px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
133body {
134 margin: 0;
135 background: var(--bg);
136 color: var(--fg);
137 font: var(--fs-3)/1.6 var(--sans);
138 min-height: 100vh;
139}
140
141a { color: var(--accent); text-decoration: none; }
142a:hover { text-decoration: underline; }
143
144/* one authored focus ring, so keyboard position is never the browser's
145 guess. Blue, because focus is an interactive state. */
146:focus-visible {
147 outline: 2px solid var(--accent);
148 outline-offset: 2px;
149 border-radius: 1px;
150}
151/* the shell is black in both schemes, and --accent is a dark blue in the
152 light one — a ring nobody could see. The shell's own mark clears 7:1 on
153 black either way. */
154.rail :focus-visible { outline-color: var(--shell-mark); }
155
156/* visually hidden, still read aloud: for headings a sighted reader gets
157 from the layout but a screen reader would otherwise miss */
158.vh {
159 position: absolute;
160 width: 1px; height: 1px;
161 margin: -1px; padding: 0; border: 0;
162 clip-path: inset(50%);
163 overflow: hidden;
164 white-space: nowrap;
165}
166/* the rail runs ahead of the content in source order, so give keyboard
167 and screen-reader users a way past it */
168a.skip {
169 position: absolute;
170 left: var(--sp-3); top: -3rem;
171 z-index: 50;
172 background: var(--fill);
173 color: #ffffff;
174 padding: var(--sp-2) var(--sp-4);
175 font-weight: 600;
176}
177a.skip:focus { top: var(--sp-3); text-decoration: none; }
178
179h1 { font-size: var(--fs-5); font-weight: 700; line-height: 1.18;
180 margin: 0 0 var(--sp-3); letter-spacing: -0.025em; text-wrap: balance; }
181h2 { font-size: var(--fs-4); font-weight: 700; line-height: 1.3;
182 margin: var(--sp-5) 0 var(--sp-3); letter-spacing: -0.015em; }
183h3 { font-size: var(--fs-3); font-weight: 600; margin: var(--sp-5) 0 var(--sp-2); }
184
185code, pre, .code, td.mode, td.size {
186 font-family: var(--mono);
187 font-size: var(--fs-1);
188}
189
190/* ---- shell: black rail, content pane ---- */
191.shell { display: flex; align-items: stretch; min-height: 100vh; }
192
193.rail {
194 flex: none;
195 width: 13rem;
196 background: var(--shell-bg);
197 color: var(--shell-fg);
198 border-right: 1px solid var(--shell-line);
199 position: sticky;
200 top: 0;
201 height: 100vh;
202 display: flex;
203 flex-direction: column;
204}
205a.brand {
206 display: flex;
207 align-items: center;
208 gap: var(--sp-2);
209 padding: var(--sp-3) var(--sp-4);
210 color: var(--shell-fg);
211 font-weight: 700;
212 font-size: var(--fs-3);
213 letter-spacing: -0.02em;
214 border-bottom: 1px solid var(--shell-line);
215}
216a.brand:hover { text-decoration: none; color: #ffffff; }
217a.brand svg.mark { display: block; flex: none; }
218a.brand span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
219
220.railbody { flex: 1; overflow-y: auto; padding: var(--sp-3) 0; }
221ul.raillist { list-style: none; margin: 0; padding: 0; }
222ul.raillist a {
223 display: block;
224 padding: 0.28rem var(--sp-4);
225 color: var(--shell-fg);
226 font-size: var(--fs-2);
227 border-left: 3px solid transparent;
228 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
229}
230ul.raillist a:hover { background: var(--shell-hover); text-decoration: none; }
231/* orange marks position — the rail's only accent */
232ul.raillist a[aria-current] {
233 border-left-color: var(--shell-mark);
234 background: var(--shell-hover);
235 font-weight: 600;
236}
237ul.raillist .owner { color: var(--shell-muted); }
238ul.raillist.wide a { white-space: normal; padding-top: var(--sp-1); padding-bottom: var(--sp-1); }
239ul.raillist.wide b { display: block; font-weight: 500; font-size: var(--fs-1); }
240ul.raillist.wide .owner { font-size: var(--fs-0); }
241
242.raillabel {
243 display: flex;
244 align-items: center;
245 gap: var(--sp-2);
246 margin: var(--sp-4) 0 var(--sp-1);
247 padding: 0 var(--sp-4);
248 font-family: var(--mono);
249 font-size: var(--fs-0);
250 font-weight: 500;
251 letter-spacing: 0.1em;
252 text-transform: uppercase;
253 color: var(--shell-muted);
254}
255.raillabel .count {
256 font-family: var(--sans);
257 font-size: var(--fs-0);
258 font-weight: 700;
259 letter-spacing: 0;
260 background: var(--shell-mark);
261 color: #000000;
262 padding: 0 0.35rem;
263 border-radius: var(--r-sm);
264}
265/* pinned above the account cell: always reachable, never scrolled away */
266.railpinned {
267 flex: none;
268 padding: var(--sp-2) 0;
269 border-top: 1px solid var(--shell-line);
270}
271.railfoot {
272 flex: none;
273 border-top: 1px solid var(--shell-line);
274 /* same vertical rhythm as the page footer, so the two rules line up
275 when the page is scrolled to the bottom; horizontal padding stays on
276 the rail's own grid so the avatar aligns with the nav items above */
277 padding: var(--sp-4) var(--sp-4) var(--sp-5);
278 display: flex;
279 align-items: center;
280 gap: var(--sp-3);
281 font-size: var(--fs-2);
282 line-height: 1.4;
283}
284.railfoot a { color: var(--shell-fg); }
285a.railuser { display: inline-flex; align-items: center; gap: var(--sp-2); }
286/* a descendant cannot cancel an ancestor's underline, so the link carries
287 none and the name draws its own — the avatar square stays undecorated */
288a.railuser:hover { text-decoration: none; }
289a.railuser:hover .uname { text-decoration: underline; }
290.railfoot .railsettings { color: var(--shell-muted); display: inline-flex; }
291.railfoot .railsettings:hover { color: var(--shell-fg); }
292.railfoot form { margin-left: auto; }
293.railfoot .linklike {
294 background: none; border: 0; padding: 0; cursor: pointer;
295 color: var(--shell-muted); font: inherit; text-decoration: underline;
296}
297.railfoot .linklike:hover { color: var(--shell-fg); }
298.avatar {
299 width: 1.4rem; height: 1.4rem; flex: none;
300 display: inline-grid; place-items: center;
301 background: var(--fill);
302 color: #ffffff;
303 font-size: var(--fs-0);
304 font-weight: 700;
305 border-radius: var(--r-sm);
306}
307
308.pane { flex: 1; min-width: 0; display: flex; flex-direction: column; }
309.content {
310 flex: 1;
311 padding: var(--sp-5) var(--sp-5) var(--sp-6);
312 width: 100%;
313}
314
315/* ---- repo header: identity and tabs on every page, the rest once ---- */
316.repohead {
317 padding: var(--sp-4) var(--sp-5) 0;
318 border-bottom: 1px solid var(--line);
319}
320.repohead .identity { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
321.repohead .identity .grow { flex: 1; }
322/* h1 on the repo home, p elsewhere so each page keeps its own h1 — but
323 identical in size, because the tabs sit below this and navigation must
324 not move when you use it */
325.repotitle {
326 margin: 0;
327 font-size: var(--fs-4);
328 font-weight: 700;
329 letter-spacing: -0.02em;
330 line-height: 1.3;
331}
332.repotitle a { color: var(--fg); }
333.repotitle a.owner { color: var(--muted); font-weight: 400; }
334.repotitle a:hover { color: var(--accent); text-decoration: none; }
335.repotitle .sep { color: var(--muted); margin: 0 0.12em; font-weight: 400; }
336.repodesc { margin: var(--sp-2) 0 0; color: var(--muted); font-size: var(--fs-2); max-width: 62ch; }
337.repometa { margin: var(--sp-1) 0 0; color: var(--muted); font-size: var(--fs-1); }
338.repohead .topics { margin: var(--sp-2) 0 0; }
339
340button.btn {
341 font: inherit;
342 font-size: var(--fs-1);
343 font-weight: 600;
344 padding: 0.15rem 0.7rem;
345 border: 1px solid var(--line);
346 border-radius: var(--r-sm);
347 background: var(--bg);
348 color: var(--fg);
349 cursor: pointer;
350}
351button.btn:hover { border-color: var(--accent); color: var(--accent); }
352button.btn[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
353form.inline { display: inline; }
354
355nav.tabs {
356 display: flex;
357 gap: var(--sp-1);
358 margin-top: var(--sp-4);
359 overflow-x: auto;
360 /* with overflow-y left visible the browser computes it to auto, which
361 is a vertical drag on touch; the strip scrolls sideways only. */
362 overflow-y: hidden;
363 scrollbar-width: none;
364}
365nav.tabs::-webkit-scrollbar { display: none; }
366nav.tabs a {
367 display: inline-flex;
368 align-items: center;
369 gap: var(--sp-2);
370 padding: var(--sp-2) var(--sp-3) 0.6rem;
371 color: var(--muted);
372 font-size: var(--fs-2);
373 white-space: nowrap;
374 border-bottom: 2px solid transparent;
375 margin-bottom: -1px;
376}
377nav.tabs a:hover { color: var(--fg); text-decoration: none; }
378/* orange marks position here too */
379nav.tabs a[aria-current] {
380 color: var(--fg);
381 font-weight: 700;
382 border-bottom-color: var(--mark);
383}
384nav.tabs a i {
385 font-style: normal;
386 font-family: var(--mono);
387 font-size: var(--fs-0);
388 background: var(--hover);
389 border-radius: var(--r-sm);
390 padding: 0 0.35rem;
391}
392
393/* ---- mobile: the rail becomes a single strip, not a wall of links ---- */
394@media (max-width: 52rem) {
395 .shell { display: block; }
396 .rail {
397 width: auto;
398 height: auto;
399 position: static;
400 flex-direction: row;
401 align-items: center;
402 gap: var(--sp-2);
403 border-right: 0;
404 border-bottom: 1px solid var(--shell-line);
405 overflow-x: auto;
406 }
407 a.brand { border-bottom: 0; padding-right: var(--sp-2); }
408 .railbody { flex: 1; overflow: visible; padding: 0; display: flex; align-items: center; }
409 /* pinned repos and the review queue both live on the dashboard, so the
410 strip keeps only what has nowhere else to go */
411 .railgroup { display: none; }
412 ul.raillist { display: flex; }
413 ul.raillist a { border-left: 0; border-bottom: 2px solid transparent; padding: var(--sp-2) var(--sp-3); }
414 ul.raillist a[aria-current] { border-left: 0; border-bottom-color: var(--shell-mark); }
415 /* the rail is a horizontal strip here: keep the account cell compact */
416 .railfoot { border-top: 0; padding: var(--sp-2); }
417 .railpinned { border-top: 0; padding: 0; }
418 .content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
419 .repohead { padding: var(--sp-3) var(--sp-4) 0; }
420}
421
422/* tables */
423table { border-collapse: collapse; width: 100%; }
424td {
425 padding: var(--sp-2) var(--sp-4) var(--sp-2) 0;
426 border-bottom: 1px solid var(--faint);
427 vertical-align: top;
428 font-size: var(--fs-2);
429}
430td:last-child { padding-right: 0; }
431td.size, td.mode { color: var(--muted); white-space: nowrap; }
432
433/* path bar on tree and blob pages */
434.pathbar {
435 display: flex;
436 flex-wrap: wrap;
437 align-items: center;
438 gap: var(--sp-2) var(--sp-3);
439 margin: var(--sp-3) 0;
440 font-size: var(--fs-2);
441}
442.pathbar .spacer { flex: 1; }
443.refchip {
444 display: inline-flex;
445 align-items: center;
446 gap: 0.3rem;
447 background: var(--surface);
448 border: 1px solid var(--faint);
449 border-radius: var(--r-md);
450 padding: 0.1rem 0.55rem;
451 font-family: var(--mono);
452 font-size: var(--fs-1);
453 color: var(--fg);
454}
455.pathbar .crumbs strong { color: var(--fg); }
456details.refmenu { position: relative; }
457details.refmenu summary { cursor: pointer; list-style: none; }
458details.refmenu summary::-webkit-details-marker { display: none; }
459details.refmenu summary::after { content: " ▾"; color: var(--muted); }
460details.refmenu .refdrop {
461 position: absolute;
462 z-index: 10;
463 top: calc(100% + 4px);
464 left: 0;
465 min-width: 12rem;
466 max-height: 20rem;
467 overflow-y: auto;
468 background: var(--bg);
469 border: 1px solid var(--line);
470 border-radius: var(--r-md);
471 box-shadow: 0 4px 16px rgba(0,0,0,0.12);
472 padding: var(--sp-1) 0;
473}
474details.refmenu .refdrop a {
475 display: block;
476 padding: var(--sp-1) var(--sp-3);
477 color: var(--fg);
478 font-family: var(--mono);
479 font-size: var(--fs-1);
480}
481details.refmenu .refdrop a:hover { background: var(--hover); text-decoration: none; }
482details.refmenu .refdrop a.allrefs { color: var(--accent); font-family: var(--sans); border-top: 1px solid var(--faint); margin-top: var(--sp-1); }
483
484/* file and refs tables: bordered cards, rows inside */
485/* wide listings scroll inside their own box; the page never does */
486.tablewrap { overflow-x: auto; max-width: 100%; }
487
488table.tree, table.refs {
489 background: var(--surface);
490 border: 1px solid var(--line);
491 border-radius: var(--r-lg);
492 border-collapse: separate;
493 border-spacing: 0;
494 overflow: hidden;
495 margin-bottom: var(--sp-4);
496}
497table.tree td, table.refs td {
498 padding: var(--sp-2) var(--sp-4);
499 border-bottom: 1px solid var(--faint);
500}
501table.tree tr:last-child td, table.refs tr:last-child td { border-bottom: none; }
502table.tree tr:hover td, table.refs tr:hover td { background: var(--hover); }
503tr.cols th {
504 text-align: left;
505 font-weight: 500;
506 font-size: var(--fs-1);
507 color: var(--muted);
508 padding: var(--sp-1) var(--sp-4);
509 border-bottom: 1px solid var(--line);
510 background: var(--bg);
511}
512tr.cols:hover th { background: var(--bg); }
513/* right-aligned columns keep their header with their values; this needs to
514 outrank the tr.cols th rule above, which is why it names both */
515tr.cols th.age, tr.cols th.size { text-align: right; }
516table.tree th.size { text-align: right; }
517table.tree td.name { width: 100%; }
518table.tree td.name a { color: var(--fg); }
519table.tree td.name a:hover { color: var(--accent); }
520table.tree td.size { text-align: right; }
521table.tree td.empty, table.refs td.empty, li.empty, ul.loglist li.empty { color: var(--muted); }
522
523/* refs page */
524table.refs td.name { width: 100%; }
525table.refs td.sha { color: var(--muted); }
526
527/* card header (README) */
528.cardhead {
529 font-family: var(--mono);
530 font-size: var(--fs-1);
531 color: var(--muted);
532 border-bottom: 1px solid var(--faint);
533 margin: calc(-1 * var(--sp-4)) calc(-1 * var(--sp-5)) var(--sp-4);
534 padding: var(--sp-2) var(--sp-5);
535 background: var(--bg);
536 border-radius: var(--r-lg) var(--r-lg) 0 0;
537}
538
539/* log */
540ul.loglist {
541 list-style: none;
542 margin: var(--sp-3) 0;
543 padding: 0;
544 background: var(--surface);
545 border: 1px solid var(--line);
546 border-radius: var(--r-lg);
547 overflow: hidden;
548}
549ul.loglist li {
550 display: flex;
551 align-items: baseline;
552 gap: var(--sp-3);
553 padding: var(--sp-2) var(--sp-4);
554 border-bottom: 1px solid var(--faint);
555}
556ul.loglist li:last-child { border-bottom: none; }
557ul.loglist li:hover { background: var(--hover); }
558ul.loglist .commitmain { flex: 1; min-width: 0; }
559ul.loglist p { margin: 0; }
560ul.loglist .subject a { color: var(--fg); font-weight: 550; }
561ul.loglist .subject a:hover { color: var(--accent); }
562ul.loglist .commitside {
563 display: flex;
564 align-items: baseline;
565 gap: var(--sp-2);
566 white-space: nowrap;
567}
568p.pager { margin-top: var(--sp-4); }
569
570/* commit page */
571.commithead p { margin: var(--sp-1) 0; }
572.commithead h2 { margin-bottom: var(--sp-1); }
573code.fullsha { color: var(--muted); overflow-wrap: anywhere; }
574.empty-note { color: var(--muted); }
575.crumbs { color: var(--muted); font-size: var(--fs-2); }
576.desc, td.desc { color: var(--muted); }
577.error {
578 color: var(--fg);
579 border: 1px solid var(--bad);
580 border-left-width: 3px;
581 border-radius: var(--r-sm);
582 padding: var(--sp-2) var(--sp-3);
583 margin-bottom: var(--sp-4);
584}
585/* settings: one row per control, label then input then its own button */
586form.setform {
587 display: flex;
588 flex-wrap: wrap;
589 align-items: center;
590 gap: var(--sp-3);
591 padding: var(--sp-2) 0;
592 border-bottom: 1px solid var(--faint);
593}
594form.setform label { min-width: 12rem; color: var(--muted); font-size: var(--fs-2); }
595form.setform input[type="text"], form.setform select { flex: 1 1 16rem; }
596form.setform input[type="number"] { width: 5rem; }
597ul.protlist { list-style: none; padding: 0; margin: var(--sp-2) 0; }
598ul.protlist li { padding: var(--sp-1) 0; display: flex; gap: var(--sp-3); align-items: baseline; }
599
600/* branch picker on the new merge request form */
601p.branchpick {
602 display: flex;
603 flex-wrap: wrap;
604 align-items: center;
605 gap: var(--sp-2);
606}
607p.branchpick label { color: var(--muted); font-size: var(--fs-2); }
608p.branchpick select { flex: 1 1 12rem; }
609
610/* merge request actions in the aside: stacked controls, full width */
611.aside form.actions {
612 display: flex;
613 flex-wrap: wrap;
614 gap: var(--sp-2);
615 margin-top: var(--sp-2);
616}
617.aside form.actions button { flex: 1 1 auto; }
618.aside form.actions select { width: 100%; }
619form.threadact { margin: var(--sp-1) 0 0; padding: 0 var(--sp-3) var(--sp-2); }
620
621.meta { color: var(--muted); font-size: var(--fs-1); }
622svg.icon { vertical-align: -0.125em; }
623.lede { font-size: var(--fs-3); margin: var(--sp-2) 0; }
624
625/* repo listings (explore, owner pages, dashboard): one row per repo */
626ul.repolist {
627 list-style: none;
628 margin: var(--sp-3) 0 var(--sp-5);
629 padding: 0;
630 background: var(--surface);
631 border: 1px solid var(--line);
632 border-radius: var(--r-lg);
633 overflow: hidden;
634}
635ul.repolist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
636/* pinned repos: a compact wrap of name pills, no description or meta */
637ul.pinlist {
638 list-style: none;
639 margin: var(--sp-3) 0 var(--sp-5);
640 padding: 0;
641 display: flex;
642 flex-wrap: wrap;
643 gap: var(--sp-2);
644}
645ul.pinlist li {
646 background: var(--surface);
647 border: 1px solid var(--line);
648 border-radius: var(--r-md);
649 padding: var(--sp-1) var(--sp-3);
650}
651ul.pinlist li:hover { background: var(--hover); }
652ul.pinlist li a { color: var(--fg); }
653ul.pinlist li a:hover { color: var(--accent); text-decoration: none; }
654ul.pinlist .sep { color: var(--muted); margin: 0 0.15em; }
655ul.repolist li:last-child { border-bottom: none; }
656ul.repolist li:hover { background: var(--hover); }
657ul.repolist li.empty { color: var(--muted); }
658ul.repolist p { margin: 0; }
659ul.repolist .reponame { font-size: var(--fs-3); }
660ul.repolist .reponame a { color: var(--fg); }
661ul.repolist .reponame a strong { color: var(--accent); font-weight: 600; }
662ul.repolist .reponame .sep { color: var(--muted); margin: 0 0.1em; }
663ul.repolist .desc { margin-top: 0.1rem; }
664ul.repolist .topics { margin-top: var(--sp-1); }
665ul.repolist .meta { margin-top: var(--sp-1); }
666
667/* owner profile header */
668.profilehead {
669 border-bottom: 1px solid var(--faint);
670 padding-bottom: var(--sp-4);
671 margin-bottom: var(--sp-4);
672}
673.profilehead h1 { margin: var(--sp-4) 0 var(--sp-1); }
674.profilehead .lede { margin: 0 0 var(--sp-1); }
675.profilehead .meta { margin: var(--sp-1) 0 0; }
676h2 .count { color: var(--muted); font-weight: 400; font-size: var(--fs-2); }
677
678/* activity graph: 53 week columns x 7 day rows, accent-tinted levels */
679.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
680.actgraph { display: flex; gap: 3px; width: max-content; }
681.actweek { display: flex; flex-direction: column; gap: 3px; }
682.actday {
683 width: 11px;
684 height: 11px;
685 border-radius: 2px;
686 background: var(--faint);
687}
688.actday.pad { background: transparent; }
689.actday.l1 { background: color-mix(in srgb, var(--accent) 25%, var(--bg)); }
690.actday.l2 { background: color-mix(in srgb, var(--accent) 50%, var(--bg)); }
691.actday.l3 { background: color-mix(in srgb, var(--accent) 75%, var(--bg)); }
692.actday.l4 { background: var(--accent); }
693
694/* heading row with actions on the right */
695.headrow {
696 display: flex;
697 align-items: baseline;
698 gap: var(--sp-4);
699 flex-wrap: wrap;
700}
701.headrow .spacer { flex: 1; }
702
703/* member and org chips on owner pages */
704a.memberchip {
705 display: inline-block;
706 border: 1px solid var(--line);
707 border-radius: var(--r-pill);
708 padding: 0.05rem 0.6rem;
709 color: var(--fg);
710 font-size: var(--fs-1);
711 margin: 0 0.15rem 0.15rem 0;
712}
713a.memberchip:hover { text-decoration: none; border-color: var(--accent); color: var(--accent); }
714a.memberchip .role { color: var(--muted); }
715
716/* landing page */
717.landing { max-width: 44rem; padding: var(--sp-6) 0; }
718.landing h1 { font-size: 1.8rem; margin-bottom: var(--sp-3); }
719.landing .lede { font-size: var(--fs-4); color: var(--muted); line-height: 1.7; margin: 0 0 var(--sp-4); }
720pre.quickstart {
721 background: var(--code-bg);
722 border: 1px solid var(--line);
723 border-radius: var(--r-md);
724 padding: var(--sp-3) var(--sp-4);
725 overflow-x: auto;
726 margin: 0 0 var(--sp-4);
727}
728.landing .explorelink { font-weight: 550; }
729
730/* index toolbar */
731p.toolbar { color: var(--muted); font-size: var(--fs-2); margin-top: var(--sp-4); }
732form.inline { display: inline; }
733button.linklike {
734 background: none;
735 border: none;
736 color: var(--accent);
737 padding: 0;
738 font: inherit;
739 font-size: var(--fs-2);
740 cursor: pointer;
741}
742button.linklike:hover { text-decoration: underline; filter: none; }
743
744/* cards: README, comments */
745.readme, .code {
746 background: var(--surface);
747 border: 1px solid var(--line);
748 border-radius: var(--r-lg);
749 padding: var(--sp-4) var(--sp-5);
750 margin-top: var(--sp-4);
751 overflow-x: auto;
752}
753/* Highlighting is class-based with a palette per scheme, so code blocks
754 follow the site's own colors. */
755.code { background: var(--code-bg); color: var(--fg); padding: var(--sp-3) var(--sp-4); border-color: var(--line); }
756.code pre { margin: 0; background: transparent !important; }
757@media (prefers-color-scheme: dark) {
758 .code { border-color: var(--line); }
759}
760
761/* rendered markdown / org / html */
762.rendered { max-width: 100%; overflow-wrap: anywhere; }
763/* line length is a reading constraint, so it applies to prose only —
764 tables, code blocks and images keep the full column */
765.rendered > p,
766.rendered > ul,
767.rendered > ol,
768.rendered > blockquote { max-width: 78ch; }
769.rendered pre {
770 background: var(--code-bg);
771 border: 1px solid var(--line);
772 padding: var(--sp-3) var(--sp-4);
773 border-radius: var(--r-md);
774 overflow-x: auto;
775}
776.rendered code {
777 background: var(--code-bg);
778 border: 1px solid var(--line);
779 padding: 0.05rem 0.3rem;
780 border-radius: var(--r-sm);
781}
782.rendered pre code { background: transparent; border: none; padding: 0; }
783.rendered blockquote {
784 border-left: 3px solid var(--line);
785 margin-left: 0;
786 padding-left: var(--sp-4);
787 color: var(--muted);
788}
789.rendered img { max-width: 100%; }
790.rendered h1, .rendered h2 { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-1); }
791.rendered table {
792 border-collapse: collapse;
793 margin: var(--sp-3) 0;
794 display: block;
795 max-width: 100%;
796 overflow-x: auto;
797}
798.rendered th, .rendered td {
799 border: 1px solid var(--line);
800 padding: var(--sp-1) var(--sp-3);
801 text-align: left;
802 overflow-wrap: normal; /* scroll the table, don't shatter words */
803}
804.rendered th { background: var(--surface); font-weight: 600; }
805.blobimage { text-align: center; }
806.blobimage img {
807 max-width: 100%;
808 border: 1px solid var(--faint);
809 border-radius: var(--r-md);
810 background: var(--surface);
811}
812
813pre.message {
814 background: var(--code-bg);
815 border: 1px solid var(--line);
816 padding: var(--sp-3) var(--sp-4);
817 border-radius: var(--r-md);
818 white-space: pre-wrap;
819 overflow-wrap: anywhere;
820}
821
822/* repo facts: the counts a visitor sizes a project up with */
823.teambody { padding: var(--sp-3); background: var(--bg); }
824.teambody .memberchip { margin-right: var(--sp-2); }
825
826form.logfilter {
827 display: flex; align-items: center; gap: var(--sp-2);
828 margin: 0 0 var(--sp-4); flex-wrap: wrap;
829}
830form.logfilter input { flex: 1; min-width: 12rem; max-width: 28rem; }
831
832/* account settings */
833table.keys td { padding: var(--sp-2) var(--sp-4) var(--sp-2) 0; }
834/* these tables sit flush with the page text, so the header row drops the
835 left padding the card-style listings use */
836table.keys tr.cols th { padding-left: 0; background: transparent; }
837table.keys td.mono, .mono { font-family: var(--mono); font-size: var(--fs-1); overflow-wrap: anywhere; }
838table.keys td.act { text-align: right; }
839ul.plain { list-style: none; margin: 0 0 var(--sp-3); padding: 0; }
840ul.plain li { padding: var(--sp-1) 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
841form.setform.stack { display: block; }
842form.setform.stack textarea, form.setform.stack select { width: 100%; max-width: 48rem; display: block; margin-bottom: var(--sp-2); }
843p.notice {
844 border-left: 3px solid var(--ok);
845 background: var(--hover);
846 padding: var(--sp-2) var(--sp-3);
847 margin: 0 0 var(--sp-4);
848}
849
850.facts { margin: 0 0 var(--sp-4); }
851.facts .counts {
852 display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
853 margin: 0 0 var(--sp-3); font-size: var(--fs-2);
854}
855.facts .counts a { color: var(--fg); text-decoration: none; }
856.facts .counts a:hover { color: var(--accent); text-decoration: underline; }
857.facts .counts .fact { color: var(--muted); }
858.facts .counts strong { font-weight: 600; }
859
860.langbar {
861 display: flex; height: 0.5rem; margin: 0 0 var(--sp-2);
862 border-radius: var(--r-sm); overflow: hidden; background: var(--faint);
863}
864.langbar .lang { display: block; min-width: 2px; }
865.langs {
866 display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
867 margin: 0 0 var(--sp-3); font-size: var(--fs-1);
868}
869.langs .lang-name { display: inline-flex; align-items: center; gap: var(--sp-1); }
870.langs .muted { color: var(--muted); }
871.langs .dot { width: 0.6rem; height: 0.6rem; border-radius: 50%; display: inline-block; }
872/* named where it reads as the language's own color, neutral otherwise */
873.lang { background: var(--neutral); }
874.lang-go { background: #00add8; }
875.lang-rust { background: #dea584; }
876.lang-c, .lang-c- { background: #555555; }
877.lang-python { background: #3572a5; }
878.lang-javascript { background: #f1e05a; }
879.lang-typescript { background: #3178c6; }
880.lang-shell { background: #89e051; }
881.lang-ruby { background: #701516; }
882.lang-java { background: #b07219; }
883.lang-swift { background: #f05138; }
884.lang-html { background: #e34c26; }
885.lang-css { background: #563d7c; }
886.lang-org { background: #77aa99; }
887.lang-markdown { background: #083fa1; }
888.lang-emacs-lisp { background: #c065db; }
889.lang-nix { background: #7e7eff; }
890.lang-sql { background: #e38c00; }
891
892.contribs {
893 display: flex; flex-wrap: wrap; align-items: baseline;
894 gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--fs-1);
895}
896.contribs .label { color: var(--muted); }
897
898/* diffs: one foldable section per file, a table so the line-number
899 gutters stay put while the code scrolls */
900details.difffold {
901 border: 1px solid var(--line);
902 border-radius: var(--r-md);
903 margin: 0 0 var(--sp-3);
904 background: var(--code-bg);
905}
906details.difffold summary {
907 cursor: pointer;
908 display: flex;
909 align-items: baseline;
910 gap: var(--sp-3);
911 padding: var(--sp-2) var(--sp-3);
912 list-style: none;
913 font-size: var(--fs-2);
914}
915details.difffold[open] summary { border-bottom: 1px solid var(--line); }
916details.difffold summary::-webkit-details-marker { display: none; }
917/* flex summaries lose the native disclosure marker; draw our own */
918details.difffold summary::before { content: "\25b8"; color: var(--muted); }
919details.difffold[open] summary::before { content: "\25be"; }
920details.difffold summary:hover { background: var(--fill-subtle); }
921summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; }
922summary .fpath .was { color: var(--muted); }
923summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; }
924details.difffold summary .add { color: var(--ok); }
925details.difffold summary .del { color: var(--bad); }
926details.difffold > .none { padding: var(--sp-3); margin: 0; }
927details.difffold .tablewrap { border-radius: 0 0 var(--r-md) var(--r-md); }
928
929table.difftable {
930 border-collapse: collapse;
931 width: 100%;
932 font-family: var(--mono);
933 font-size: var(--fs-1);
934 line-height: 1.5;
935}
936table.difftable td {
937 border: 0;
938 padding: 0;
939 vertical-align: top;
940 font-size: inherit;
941}
942table.difftable td.ln {
943 width: 1%;
944 min-width: 2.5rem;
945 padding: 0 var(--sp-2);
946 text-align: right;
947 color: var(--muted);
948 user-select: none;
949 border-right: 1px solid var(--line);
950 white-space: nowrap;
951}
952/* not .code: that class is the blob/code-block style and carries its own
953 background, which painted over every row tint */
954table.difftable td.src {
955 padding: 0 var(--sp-3);
956 white-space: pre-wrap;
957 overflow-wrap: anywhere;
958}
959/* the marker is decoration, so it lives in CSS and stays out of a copied
960 selection */
961table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
962table.difftable tr.del td.src::before { content: "\2212"; color: var(--bad); }
963table.difftable tr.ctx td.src::before { content: " "; }
964table.difftable tr.add { background: var(--diff-add); }
965table.difftable tr.del { background: var(--diff-del); }
966table.difftable tr.hunk td, table.difftable tr.dmeta td {
967 color: var(--muted);
968 padding: var(--sp-1) var(--sp-3);
969 background: var(--fill-subtle);
970 border-top: 1px solid var(--line);
971 border-bottom: 1px solid var(--line);
972}
973table.difftable tr.hunk td.src { color: var(--accent); }
974table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--bg); }
975/* a line number is the handle for commenting on that line; it stays a
976 plain number until pointed at, so the gutter does not read as a wall of
977 links */
978table.difftable td.ln a.cmt { color: inherit; text-decoration: none; }
979table.difftable td.ln a.cmt:hover,
980table.difftable td.ln a.cmt:focus { color: var(--accent); text-decoration: underline; }
981
982/* badges: signature and check states. Semantic colors stay distinct:
983 green verified/success, amber pending/stale, red bad/failure, muted
984 unsigned. */
985.badge, .chip {
986 --chip: var(--neutral);
987 display: inline-block;
988 padding: 0.05rem 0.55rem;
989 border-radius: var(--r-pill);
990 font-size: var(--fs-0);
991 font-weight: 500;
992 line-height: 1.5;
993 color: var(--chip);
994 border: 1px solid color-mix(in srgb, var(--chip) 35%, transparent);
995 background: color-mix(in srgb, var(--chip) 7%, transparent);
996 white-space: nowrap;
997 vertical-align: middle;
998}
999.chip-open { --chip: var(--ok); }
1000.chip-closed { --chip: var(--bad); }
1001.chip-merged, .chip-done { --chip: var(--done); }
1002.chip-neutral, .chip-source_gone { --chip: var(--neutral); }
1003.chip-stale { --chip: var(--warn); }
1004.chip.label { font-weight: 500; }
1005.chip.topic { --chip: var(--accent); }
1006.repohead .topics { margin: 0 0 var(--sp-2); }
1007.repohead .mirrorline { margin: 0 0 var(--sp-2); }
1008.mirrorerr { color: var(--bad); }
1009.badge-verified { --chip: var(--ok); }
1010.badge-unsigned { --chip: var(--neutral); }
1011.badge-signed_unknown_key { --chip: var(--warn); }
1012.badge-signed_email_mismatch { --chip: var(--bad); }
1013.badge-signed_key_expired { --chip: var(--warn); }
1014.badge-signed_key_revoked { --chip: var(--bad); }
1015.badge-bad_signature { --chip: var(--bad); }
1016.badge.check-success { --chip: var(--ok); }
1017.badge.check-pending { --chip: var(--warn); }
1018.badge.check-failure, .badge.check-error { --chip: var(--bad); }
1019.badge.check-running, .chip.check-running { --chip: var(--warn); }
1020.chip.check-success { --chip: var(--ok); }
1021.chip.check-pending { --chip: var(--warn); }
1022.chip.check-failure { --chip: var(--bad); }
1023pre.buildlog { max-height: 40rem; overflow: auto; }
1024span.check-success { color: var(--ok); }
1025span.check-pending { color: var(--warn); }
1026span.check-failure, span.check-error { color: var(--bad); }
1027
1028/* issue and MR listings */
1029.listhead {
1030 display: flex;
1031 align-items: baseline;
1032 gap: var(--sp-4);
1033 flex-wrap: wrap;
1034}
1035.listhead h2 { margin-bottom: var(--sp-2); }
1036nav.filters { display: flex; gap: var(--sp-1); }
1037nav.filters a {
1038 color: var(--muted);
1039 font-size: var(--fs-2);
1040 padding: 0.05rem var(--sp-2);
1041 border-radius: var(--r-pill);
1042}
1043nav.filters a:hover { color: var(--fg); background: var(--hover); text-decoration: none; }
1044nav.filters a.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
1045
1046ul.issuelist {
1047 list-style: none;
1048 margin: var(--sp-2) 0;
1049 padding: 0;
1050 background: var(--surface);
1051 border: 1px solid var(--line);
1052 border-radius: var(--r-lg);
1053 overflow: hidden;
1054}
1055ul.issuelist li {
1056 display: flex;
1057 align-items: baseline;
1058 gap: var(--sp-3);
1059 padding: var(--sp-3) var(--sp-4);
1060 border-bottom: 1px solid var(--faint);
1061}
1062ul.issuelist li:last-child { border-bottom: none; }
1063ul.issuelist li:hover { background: var(--hover); }
1064ul.issuelist li.empty { display: block; color: var(--muted); }
1065ul.issuelist .issuemain { flex: 1; min-width: 0; }
1066ul.issuelist p { margin: 0; }
1067ul.issuelist .title a { color: var(--fg); font-weight: 550; }
1068ul.issuelist .title a:hover { color: var(--accent); }
1069
1070/* releases */
1071article.release {
1072 background: var(--surface);
1073 border: 1px solid var(--line);
1074 border-radius: var(--r-lg);
1075 padding: var(--sp-3) var(--sp-4);
1076 margin: var(--sp-4) 0;
1077}
1078.releasehead { background: none; border: 0; padding: 0; }
1079.releasehead h3 { margin: 0 0 var(--sp-1); }
1080.releasehead .meta { margin: 0 0 var(--sp-2); }
1081table.assets { margin-top: var(--sp-2); }
1082table.assets td.size { color: var(--muted); white-space: nowrap; text-align: right; }
1083table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
1084
1085/* milestones */
1086ul.milestonelist {
1087 list-style: none;
1088 margin: var(--sp-2) 0;
1089 padding: 0;
1090 border: 1px solid var(--line);
1091 border-radius: var(--r-lg);
1092 overflow: hidden;
1093}
1094ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1095ul.milestonelist li:last-child { border-bottom: none; }
1096ul.milestonelist li.empty { color: var(--muted); }
1097ul.milestonelist p { margin: 0; }
1098ul.milestonelist .title { font-weight: 550; }
1099.progress {
1100 height: 6px;
1101 background: var(--faint);
1102 border-radius: var(--r-pill);
1103 margin-top: var(--sp-2);
1104 overflow: hidden;
1105 max-width: 24rem;
1106}
1107.progress .bar { height: 100%; background: var(--ok); }
1108.listhead .spacer { flex: 1; }
1109
1110/* issue / MR detail */
1111h2.issuetitle { margin-bottom: var(--sp-1); font-size: var(--fs-5); }
1112.issuenumber { color: var(--muted); font-weight: 400; }
1113.issuemeta { color: var(--muted); font-size: var(--fs-2); margin-top: 0; }
1114.review { font-size: var(--fs-2); }
1115
1116/* comment cards; discussion stays at a readable measure */
1117article.comment, form.commentform {
1118 max-width: 48rem;
1119}
1120article.comment {
1121 border: 1px solid var(--faint);
1122 border-radius: var(--r-lg);
1123 margin: var(--sp-4) 0;
1124}
1125article.comment .commenthead {
1126 background: var(--surface);
1127 border-bottom: 1px solid var(--faint);
1128 border-radius: var(--r-lg) var(--r-lg) 0 0;
1129 padding: var(--sp-2) var(--sp-4);
1130 font-size: var(--fs-2);
1131}
1132article.comment .commenthead .when { color: var(--muted); }
1133article.comment .rendered { padding: 0 var(--sp-4); }
1134article.comment .rendered > :first-child { margin-top: var(--sp-3); }
1135article.comment .rendered > :last-child { margin-bottom: var(--sp-3); }
1136form.commentform { margin: var(--sp-4) 0; }
1137details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
1138details.editbox summary { cursor: pointer; color: var(--muted); font-size: var(--fs-2); }
1139details.editbox summary:hover { color: var(--accent); }
1140details.editbox input[type="text"] { width: 100%; }
1141.syscomment {
1142 max-width: 48rem;
1143 color: var(--muted);
1144 font-size: var(--fs-2);
1145 margin: var(--sp-3) 0;
1146 padding-left: var(--sp-4);
1147 border-left: 3px solid var(--faint);
1148}
1149.syscomment p { display: inline; margin: 0; }
1150
1151/* review threads under diff lines */
1152.thread {
1153 border: 1px solid var(--faint);
1154 border-left: 3px solid var(--accent);
1155 border-radius: var(--r-md);
1156 padding: var(--sp-2) var(--sp-4);
1157 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1158}
1159.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1160.thread.stale { border-left-color: var(--warn); }
1161.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1162.thread .when { color: var(--muted); }
1163.thread .rendered p { margin: var(--sp-1) 0; }
1164.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1165.thread.composing { border-left-color: var(--mark); }
1166.thread details.threadreply { margin: var(--sp-2) 0 0; }
1167.thread details.threadreply > summary { color: var(--accent); font-size: var(--fs-1); cursor: pointer; }
1168.thread textarea { width: 100%; }
1169.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1170
1171/* forms: every control shares one shell, so a select reads as a sibling
1172 of the text inputs beside it rather than as an OS control dropped in */
1173input, textarea, button, select { font: inherit; color: inherit; }
1174input[type="text"], input[type="search"], input[type="email"],
1175input[type="password"], input:not([type]), textarea, select {
1176 background: var(--bg);
1177 color: var(--fg);
1178 border: 1px solid var(--line);
1179 border-radius: var(--r-md);
1180 padding: var(--sp-2) var(--sp-3);
1181 line-height: 1.4;
1182}
1183textarea { width: 100%; resize: vertical; }
1184textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
1185/* the native arrow cannot be restyled, so draw our own and match the
1186 inputs exactly; --chev carries the stroke colour per scheme */
1187select {
1188 appearance: none;
1189 padding-right: 1.9rem;
1190 background-image: var(--chev);
1191 background-repeat: no-repeat;
1192 background-position: right 0.6rem center;
1193 background-size: 0.62rem;
1194 cursor: pointer;
1195}
1196input:hover, textarea:hover, select:hover { border-color: var(--muted); }
1197/* the global :focus-visible ring covers these; only the border moves */
1198input:focus, textarea:focus, select:focus { border-color: var(--accent); }
1199input[type="radio"], input[type="checkbox"] { accent-color: var(--fill); }
1200label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
1201label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
1202
1203/* Shape carries the meaning on these two and nothing else does: a circle
1204 takes one answer, a square takes any number. It survives colour being
1205 removed — greyscale, high contrast, colour blindness — so the native
1206 shapes stay and only the colour joins the system. Drawing them by hand
1207 would align the corners at the cost of the one cue that always works. */
1208input[type="radio"], input[type="checkbox"] { accent-color: var(--fill); }
1209
1210/* a segmented control for a small, mutually exclusive set: real radios
1211 underneath, so arrow keys and screen readers behave as they always did */
1212fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
1213fieldset.segmented legend {
1214 padding: 0;
1215 margin-bottom: var(--sp-2);
1216 color: var(--muted);
1217 font-size: var(--fs-2);
1218}
1219fieldset.segmented .options { display: inline-flex; }
1220fieldset.segmented label { gap: 0; }
1221fieldset.segmented input {
1222 position: absolute;
1223 width: 1px;
1224 height: 1px;
1225 opacity: 0;
1226 pointer-events: none;
1227}
1228fieldset.segmented span {
1229 display: block;
1230 padding: var(--sp-2) var(--sp-4);
1231 border: 1px solid var(--line);
1232 font-size: var(--fs-2);
1233 cursor: pointer;
1234}
1235fieldset.segmented label + label span { border-left: 0; }
1236fieldset.segmented label:first-child span { border-radius: var(--r-sm) 0 0 var(--r-sm); }
1237fieldset.segmented label:last-child span { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
1238fieldset.segmented span:hover { border-color: var(--muted); }
1239fieldset.segmented input:checked + span {
1240 background: var(--fill);
1241 border-color: var(--fill);
1242 color: #ffffff;
1243 font-weight: 600;
1244}
1245fieldset.segmented input:focus-visible + span {
1246 outline: 2px solid var(--accent);
1247 outline-offset: 2px;
1248}
1249
1250/* remaining input states */
1251::placeholder { color: var(--muted); opacity: 1; }
1252::selection { background: var(--fill); color: #ffffff; }
1253/* :user-invalid, not :invalid — a required field is invalid the moment
1254 the page loads, and colouring it red before anyone has typed is a
1255 scolding, not a hint */
1256input:user-invalid, textarea:user-invalid {
1257 border-color: var(--bad);
1258}
1259.hint { display: block; color: var(--muted); font-size: var(--fs-1); margin-top: var(--sp-1); }
1260button {
1261 background: var(--fill);
1262 color: #ffffff;
1263 border: none;
1264 border-radius: var(--r-md);
1265 padding: var(--sp-2) var(--sp-4);
1266 font-weight: 600;
1267 cursor: pointer;
1268}
1269button:hover { filter: brightness(1.15); }
1270
1271/* 404 */
1272.notfound { text-align: center; padding: var(--sp-6) 0; }
1273.notfound .bigcode {
1274 font-family: var(--mono);
1275 font-size: 4rem;
1276 color: var(--faint);
1277 -webkit-text-stroke: 1px var(--line);
1278 margin: 0;
1279 line-height: 1;
1280}
1281.notfound h1 { margin-top: var(--sp-3); }
1282
1283/* footer */
1284footer {
1285 border-top: 1px solid var(--faint);
1286 padding: var(--sp-4) var(--sp-5) var(--sp-5);
1287 width: 100%;
1288 color: var(--muted);
1289 font-size: var(--fs-1);
1290}
1291footer p { margin: 0; }
1292footer a { color: var(--muted); text-decoration: underline; }
1293footer a:hover { color: var(--accent); }
1294
1295/* search */
1296form.searchform {
1297 display: flex;
1298 gap: var(--sp-2);
1299 margin: var(--sp-3) 0 var(--sp-4);
1300}
1301form.searchform input[type="search"] { flex: 1; max-width: 32rem; }
1302form.searchform.compact { margin: 0; }
1303form.searchform.compact input[type="search"] {
1304 padding: var(--sp-1) var(--sp-3);
1305 font-size: var(--fs-2);
1306 min-width: 18rem;
1307}
1308ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1309ul.matchlist li { margin-bottom: var(--sp-3); }
1310ul.matchlist .matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1311pre.matchline {
1312 background: var(--code-bg);
1313 border: 1px solid var(--faint);
1314 border-radius: var(--r-md);
1315 padding: var(--sp-1) var(--sp-3);
1316 margin: var(--sp-1) 0 0;
1317 overflow-x: auto;
1318}
1319pre.matchline mark {
1320 background: color-mix(in srgb, var(--warn) 25%, transparent);
1321 color: inherit;
1322 border-radius: 2px;
1323}
1324
1325/* wiki */
1326.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
1327.wikipage { flex: 1; min-width: 0; }
1328.wikinav { flex: none; width: 13rem; padding-top: var(--sp-4); }
1329.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1330.wikinav li a { display: block; padding: 0.15rem 0; color: var(--fg); }
1331.wikinav li a:hover { color: var(--accent); text-decoration: none; }
1332.wikinav li a.active { color: var(--accent); font-weight: 550; }
1333@media (max-width: 40rem) {
1334 /* Column direction + the desktop align-items:flex-start lets .wikipage
1335 take its content's intrinsic width, overflowing the viewport (and
1336 triggering iOS font inflation). Stretch pins it to the container. */
1337 .wikilayout { flex-direction: column; align-items: stretch; }
1338 .wikinav { width: auto; padding-top: 0; }
1339}
1340
1341/* blame */
1342.blame {
1343 border: 1px solid var(--line);
1344 border-radius: var(--rad-2, 6px);
1345 overflow: hidden;
1346}
1347.blamehunk {
1348 display: flex;
1349 gap: var(--sp-3);
1350 border-top: 1px solid var(--line);
1351 align-items: flex-start;
1352}
1353.blamehunk:first-child { border-top: none; }
1354.blameinfo {
1355 flex: none;
1356 width: 17rem;
1357 padding: var(--sp-2) var(--sp-3);
1358 min-width: 0;
1359}
1360.blameinfo .subject {
1361 margin: 0;
1362 font-size: var(--fs-1);
1363 white-space: nowrap;
1364 overflow: hidden;
1365 text-overflow: ellipsis;
1366}
1367.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1368.blamecode {
1369 flex: 1;
1370 margin: 0;
1371 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1372 overflow-x: auto;
1373 border-left: 1px solid var(--line);
1374 align-self: stretch;
1375}
1376.lineno {
1377 display: inline-block;
1378 min-width: 3.5em;
1379 padding-right: 1em;
1380 text-align: right;
1381 color: var(--muted);
1382 user-select: none;
1383}
1384
1385/* mobile */
1386@media (max-width: 40rem) {
1387 .container { padding-left: var(--sp-4); padding-right: var(--sp-4); }
1388 main.container { padding-top: var(--sp-2); }
1389 .repogrid { grid-template-columns: 1fr; }
1390 .thread { margin-left: var(--sp-3); }
1391 /* the commit subject is the widest thing in the listing and the one
1392 column a phone can do without: the tipbar above already names the
1393 latest commit. */
1394 table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
1395 table.tree td.mode, table.tree th.mode { display: none; }
1396 .clone, .pathbar { overflow-wrap: anywhere; }
1397 .readme, .code { padding: var(--sp-3); }
1398 .blamehunk { flex-direction: column; gap: 0; }
1399 .blameinfo { width: auto; }
1400 .blamecode { border-left: none; padding-left: var(--sp-3); width: 100%; }
1401 .cardhead {
1402 margin: calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) var(--sp-3);
1403 padding: var(--sp-2) var(--sp-3);
1404 }
1405}
1406
1407/* tree listing: the last commit is what a file table is scanned for, so
1408 it leads. The file's own facts moved to the blob page. */
1409.tipbar {
1410 display: flex;
1411 align-items: center;
1412 gap: var(--sp-3);
1413 padding: var(--sp-2) var(--sp-4);
1414 background: var(--hover);
1415 border: 1px solid var(--line);
1416 border-bottom: 0;
1417 border-radius: var(--r-lg) var(--r-lg) 0 0;
1418 font-size: var(--fs-2);
1419}
1420.tipbar .who { font-weight: 600; }
1421.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1422.tipbar .subject:hover { color: var(--accent); }
1423.tipbar .spacer { flex: 1; }
1424.tipbar .age { color: var(--muted); white-space: nowrap; }
1425.tipbar + table.tree { border-radius: 0 0 var(--r-lg) var(--r-lg); }
1426table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
1427table.tree td.lastcommit a { color: var(--muted); display: block; overflow: hidden;
1428 text-overflow: ellipsis; white-space: nowrap; }
1429table.tree td.lastcommit a:hover { color: var(--accent); }
1430table.tree th.age, table.tree td.age {
1431 text-align: right;
1432 white-space: nowrap;
1433 color: var(--muted);
1434 font-variant-numeric: tabular-nums;
1435}
1436table.tree td.name { width: 25%; white-space: nowrap; }
1437table.tree td.name.dir a { color: var(--accent); }
1438p.clone { margin: 0 0 var(--sp-3); }
1439p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1440.pathbar .act { font-size: var(--fs-1); }
1441
1442/* merge request: a two-column split, so state has somewhere to live that
1443 is not a run-on sentence under the title */
1444.withaside {
1445 display: grid;
1446 grid-template-columns: minmax(0, 1fr) 15rem;
1447 gap: var(--sp-5);
1448 align-items: start;
1449}
1450.withaside .mainside { min-width: 0; }
1451@media (max-width: 62rem) { .withaside { grid-template-columns: 1fr; } }
1452
1453.aside { font-size: var(--fs-2); }
1454.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1455.aside .grp:first-child { border-top: 0; padding-top: 0; }
1456.aside h2 {
1457 margin: 0 0 var(--sp-2);
1458 font-family: var(--mono);
1459 font-size: var(--fs-0);
1460 font-weight: 500;
1461 letter-spacing: 0.1em;
1462 text-transform: uppercase;
1463 color: var(--muted);
1464}
1465.aside .row { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1466.aside .row:last-child { margin-bottom: 0; }
1467.aside .none { color: var(--muted); }
1468.aside .dot { width: 0.45rem; height: 0.45rem; flex: none; border-radius: 50%; background: var(--muted); }
1469.aside .dot.ok { background: var(--ok); }
1470.aside .dot.bad { background: var(--bad); }
1471.aside .dot.pend { background: var(--mark); }
1472
1473/* sub-navigation within an item; orange marks position as it does above */
1474nav.subtabs {
1475 display: flex;
1476 gap: var(--sp-4);
1477 border-bottom: 1px solid var(--line);
1478 margin: 0 0 var(--sp-4);
1479}
1480nav.subtabs a {
1481 display: inline-flex;
1482 align-items: center;
1483 gap: var(--sp-2);
1484 padding: 0 0 var(--sp-2);
1485 color: var(--muted);
1486 font-size: var(--fs-2);
1487 border-bottom: 2px solid transparent;
1488 margin-bottom: -1px;
1489}
1490nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1491nav.subtabs a[aria-current] { color: var(--fg); font-weight: 700; border-bottom-color: var(--mark); }
1492nav.subtabs a i {
1493 font-style: normal;
1494 font-family: var(--mono);
1495 font-size: var(--fs-0);
1496 background: var(--hover);
1497 border-radius: var(--r-sm);
1498 padding: 0 0.35rem;
1499}
1500p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1501p.diffstat .add { color: var(--ok); }
1502p.diffstat .del { color: var(--bad); }