internal/web/static/style.css
1534 lines · 52824 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}
594/* the label absorbs the free space, so a row whose control does not
595 stretch — a checkbox, a number — still finishes at the same right edge
596 as the rows whose input fills the line */
597form.setform label { min-width: 12rem; margin-right: auto; color: var(--muted); font-size: var(--fs-2); }
598form.setform input[type="text"], form.setform select { flex: 1 1 16rem; }
599form.setform input[type="number"] { width: 5rem; }
600ul.protlist { list-style: none; padding: 0; margin: var(--sp-2) 0; }
601ul.protlist li { padding: var(--sp-1) 0; display: flex; gap: var(--sp-3); align-items: baseline; }
602
603/* branch picker on the new merge request form */
604p.branchpick {
605 display: flex;
606 flex-wrap: wrap;
607 align-items: center;
608 gap: var(--sp-2);
609}
610p.branchpick label { color: var(--muted); font-size: var(--fs-2); }
611p.branchpick select { flex: 1 1 12rem; }
612
613/* merge request actions in the aside: stacked controls, full width */
614.aside form.actions {
615 display: flex;
616 flex-wrap: wrap;
617 gap: var(--sp-2);
618 margin-top: var(--sp-2);
619}
620.aside form.actions button { flex: 1 1 auto; }
621.aside form.actions select { width: 100%; }
622form.threadact { margin: var(--sp-1) 0 0; padding: 0 var(--sp-3) var(--sp-2); }
623
624.meta { color: var(--muted); font-size: var(--fs-1); }
625svg.icon { vertical-align: -0.125em; }
626.lede { font-size: var(--fs-3); margin: var(--sp-2) 0; }
627
628/* repo listings (explore, owner pages, dashboard): one row per repo */
629ul.repolist {
630 list-style: none;
631 margin: var(--sp-3) 0 var(--sp-5);
632 padding: 0;
633 background: var(--surface);
634 border: 1px solid var(--line);
635 border-radius: var(--r-lg);
636 overflow: hidden;
637}
638ul.repolist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
639/* pinned repos: a compact wrap of name pills, no description or meta */
640ul.pinlist {
641 list-style: none;
642 margin: var(--sp-3) 0 var(--sp-5);
643 padding: 0;
644 display: flex;
645 flex-wrap: wrap;
646 gap: var(--sp-2);
647}
648ul.pinlist li {
649 background: var(--surface);
650 border: 1px solid var(--line);
651 border-radius: var(--r-md);
652 padding: var(--sp-1) var(--sp-3);
653}
654ul.pinlist li:hover { background: var(--hover); }
655ul.pinlist li a { color: var(--fg); }
656ul.pinlist li a:hover { color: var(--accent); text-decoration: none; }
657ul.pinlist .sep { color: var(--muted); margin: 0 0.15em; }
658ul.repolist li:last-child { border-bottom: none; }
659ul.repolist li:hover { background: var(--hover); }
660ul.repolist li.empty { color: var(--muted); }
661ul.repolist p { margin: 0; }
662ul.repolist .reponame { font-size: var(--fs-3); }
663ul.repolist .reponame a { color: var(--fg); }
664ul.repolist .reponame a strong { color: var(--accent); font-weight: 600; }
665ul.repolist .reponame .sep { color: var(--muted); margin: 0 0.1em; }
666ul.repolist .desc { margin-top: 0.1rem; }
667ul.repolist .topics { margin-top: var(--sp-1); }
668ul.repolist .meta { margin-top: var(--sp-1); }
669
670/* owner profile header */
671.profilehead {
672 border-bottom: 1px solid var(--faint);
673 padding-bottom: var(--sp-4);
674 margin-bottom: var(--sp-4);
675}
676.profilehead h1 { margin: var(--sp-4) 0 var(--sp-1); }
677.profilehead .lede { margin: 0 0 var(--sp-1); }
678.profilehead .meta { margin: var(--sp-1) 0 0; }
679h2 .count { color: var(--muted); font-weight: 400; font-size: var(--fs-2); }
680
681/* activity graph: 53 week columns x 7 day rows, accent-tinted levels */
682.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
683.actgraph { display: flex; gap: 3px; width: max-content; }
684.actweek { display: flex; flex-direction: column; gap: 3px; }
685.actday {
686 width: 11px;
687 height: 11px;
688 border-radius: 2px;
689 background: var(--faint);
690}
691.actday.pad { background: transparent; }
692.actday.l1 { background: color-mix(in srgb, var(--accent) 25%, var(--bg)); }
693.actday.l2 { background: color-mix(in srgb, var(--accent) 50%, var(--bg)); }
694.actday.l3 { background: color-mix(in srgb, var(--accent) 75%, var(--bg)); }
695.actday.l4 { background: var(--accent); }
696
697/* heading row with actions on the right */
698.headrow {
699 display: flex;
700 align-items: baseline;
701 gap: var(--sp-4);
702 flex-wrap: wrap;
703}
704.headrow .spacer { flex: 1; }
705
706/* member and org chips on owner pages */
707a.memberchip {
708 display: inline-block;
709 border: 1px solid var(--line);
710 border-radius: var(--r-pill);
711 padding: 0.05rem 0.6rem;
712 color: var(--fg);
713 font-size: var(--fs-1);
714 margin: 0 0.15rem 0.15rem 0;
715}
716a.memberchip:hover { text-decoration: none; border-color: var(--accent); color: var(--accent); }
717a.memberchip .role { color: var(--muted); }
718
719/* landing page */
720.landing { max-width: 44rem; padding: var(--sp-6) 0; }
721.landing h1 { font-size: 1.8rem; margin-bottom: var(--sp-3); }
722.landing .lede { font-size: var(--fs-4); color: var(--muted); line-height: 1.7; margin: 0 0 var(--sp-4); }
723pre.quickstart {
724 background: var(--code-bg);
725 border: 1px solid var(--line);
726 border-radius: var(--r-md);
727 padding: var(--sp-3) var(--sp-4);
728 overflow-x: auto;
729 margin: 0 0 var(--sp-4);
730}
731.landing .explorelink { font-weight: 550; }
732
733/* index toolbar */
734p.toolbar { color: var(--muted); font-size: var(--fs-2); margin-top: var(--sp-4); }
735form.inline { display: inline; }
736button.linklike {
737 background: none;
738 border: none;
739 color: var(--accent);
740 padding: 0;
741 font: inherit;
742 font-size: var(--fs-2);
743 cursor: pointer;
744}
745button.linklike:hover { text-decoration: underline; filter: none; }
746
747/* cards: README, comments */
748.readme, .code {
749 background: var(--surface);
750 border: 1px solid var(--line);
751 border-radius: var(--r-lg);
752 padding: var(--sp-4) var(--sp-5);
753 margin-top: var(--sp-4);
754 overflow-x: auto;
755}
756/* Highlighting is class-based with a palette per scheme, so code blocks
757 follow the site's own colors. */
758.code { background: var(--code-bg); color: var(--fg); padding: var(--sp-3) var(--sp-4); border-color: var(--line); }
759.code pre { margin: 0; background: transparent !important; }
760@media (prefers-color-scheme: dark) {
761 .code { border-color: var(--line); }
762}
763
764/* rendered markdown / org / html */
765.rendered { max-width: 100%; overflow-wrap: anywhere; }
766/* line length is a reading constraint, so it applies to prose only —
767 tables, code blocks and images keep the full column */
768.rendered > p,
769.rendered > ul,
770.rendered > ol,
771.rendered > blockquote { max-width: 78ch; }
772.rendered pre {
773 background: var(--code-bg);
774 border: 1px solid var(--line);
775 padding: var(--sp-3) var(--sp-4);
776 border-radius: var(--r-md);
777 overflow-x: auto;
778}
779.rendered code {
780 background: var(--code-bg);
781 border: 1px solid var(--line);
782 padding: 0.05rem 0.3rem;
783 border-radius: var(--r-sm);
784}
785.rendered pre code { background: transparent; border: none; padding: 0; }
786.rendered blockquote {
787 border-left: 3px solid var(--line);
788 margin-left: 0;
789 padding-left: var(--sp-4);
790 color: var(--muted);
791}
792.rendered img { max-width: 100%; }
793.rendered h1, .rendered h2 { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-1); }
794.rendered table {
795 border-collapse: collapse;
796 margin: var(--sp-3) 0;
797 display: block;
798 max-width: 100%;
799 overflow-x: auto;
800}
801.rendered th, .rendered td {
802 border: 1px solid var(--line);
803 padding: var(--sp-1) var(--sp-3);
804 text-align: left;
805 overflow-wrap: normal; /* scroll the table, don't shatter words */
806}
807.rendered th { background: var(--surface); font-weight: 600; }
808.blobimage { text-align: center; }
809.blobimage img {
810 max-width: 100%;
811 border: 1px solid var(--faint);
812 border-radius: var(--r-md);
813 background: var(--surface);
814}
815
816pre.message {
817 background: var(--code-bg);
818 border: 1px solid var(--line);
819 padding: var(--sp-3) var(--sp-4);
820 border-radius: var(--r-md);
821 white-space: pre-wrap;
822 overflow-wrap: anywhere;
823}
824
825/* repo facts: the counts a visitor sizes a project up with */
826.teambody { padding: var(--sp-3); background: var(--bg); }
827.teambody .memberchip { margin-right: var(--sp-2); }
828
829form.logfilter {
830 display: flex; align-items: center; gap: var(--sp-2);
831 margin: 0 0 var(--sp-4); flex-wrap: wrap;
832}
833form.logfilter input { flex: 1; min-width: 12rem; max-width: 28rem; }
834
835/* account settings */
836table.keys td { padding: var(--sp-2) var(--sp-4) var(--sp-2) 0; }
837/* these tables sit flush with the page text, so the header row drops the
838 left padding the card-style listings use */
839table.keys tr.cols th { padding-left: 0; background: transparent; }
840table.keys td.mono, .mono { font-family: var(--mono); font-size: var(--fs-1); overflow-wrap: anywhere; }
841table.keys td.act { text-align: right; }
842ul.plain { list-style: none; margin: 0 0 var(--sp-3); padding: 0; }
843ul.plain li { padding: var(--sp-1) 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
844form.setform.stack { display: block; }
845form.setform.stack textarea, form.setform.stack select { width: 100%; max-width: 48rem; display: block; margin-bottom: var(--sp-2); }
846p.notice {
847 border-left: 3px solid var(--ok);
848 background: var(--hover);
849 padding: var(--sp-2) var(--sp-3);
850 margin: 0 0 var(--sp-4);
851}
852
853.facts { margin: 0 0 var(--sp-4); }
854.facts .counts {
855 display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
856 margin: 0 0 var(--sp-3); font-size: var(--fs-2);
857}
858.facts .counts a { color: var(--fg); text-decoration: none; }
859.facts .counts a:hover { color: var(--accent); text-decoration: underline; }
860.facts .counts .fact { color: var(--muted); }
861.facts .counts strong { font-weight: 600; }
862
863.langbar {
864 display: flex; height: 0.5rem; margin: 0 0 var(--sp-2);
865 border-radius: var(--r-sm); overflow: hidden; background: var(--faint);
866}
867.langbar .lang { display: block; min-width: 2px; }
868.langs {
869 display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
870 margin: 0 0 var(--sp-3); font-size: var(--fs-1);
871}
872.langs .lang-name { display: inline-flex; align-items: center; gap: var(--sp-1); }
873.langs .muted { color: var(--muted); }
874.langs .dot { width: 0.6rem; height: 0.6rem; border-radius: 50%; display: inline-block; }
875/* named where it reads as the language's own color, neutral otherwise */
876.lang { background: var(--neutral); }
877.lang-go { background: #00add8; }
878.lang-rust { background: #dea584; }
879.lang-c, .lang-c- { background: #555555; }
880.lang-python { background: #3572a5; }
881.lang-javascript { background: #f1e05a; }
882.lang-typescript { background: #3178c6; }
883.lang-shell { background: #89e051; }
884.lang-ruby { background: #701516; }
885.lang-java { background: #b07219; }
886.lang-swift { background: #f05138; }
887.lang-html { background: #e34c26; }
888.lang-css { background: #563d7c; }
889.lang-org { background: #77aa99; }
890.lang-markdown { background: #083fa1; }
891.lang-emacs-lisp { background: #c065db; }
892.lang-nix { background: #7e7eff; }
893.lang-sql { background: #e38c00; }
894
895.contribs {
896 display: flex; flex-wrap: wrap; align-items: baseline;
897 gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--fs-1);
898}
899.contribs .label { color: var(--muted); }
900
901/* diffs: one foldable section per file, a table so the line-number
902 gutters stay put while the code scrolls */
903details.difffold {
904 border: 1px solid var(--line);
905 border-radius: var(--r-md);
906 margin: 0 0 var(--sp-3);
907 background: var(--code-bg);
908}
909details.difffold summary {
910 cursor: pointer;
911 display: flex;
912 align-items: baseline;
913 gap: var(--sp-3);
914 padding: var(--sp-2) var(--sp-3);
915 list-style: none;
916 font-size: var(--fs-2);
917}
918details.difffold[open] summary { border-bottom: 1px solid var(--line); }
919details.difffold summary::-webkit-details-marker { display: none; }
920/* flex summaries lose the native disclosure marker; draw our own */
921details.difffold summary::before { content: "\25b8"; color: var(--muted); }
922details.difffold[open] summary::before { content: "\25be"; }
923details.difffold summary:hover { background: var(--fill-subtle); }
924summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; }
925summary .fpath .was { color: var(--muted); }
926summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; }
927details.difffold summary .add { color: var(--ok); }
928details.difffold summary .del { color: var(--bad); }
929details.difffold > .none { padding: var(--sp-3); margin: 0; }
930details.difffold .tablewrap { border-radius: 0 0 var(--r-md) var(--r-md); }
931
932table.difftable {
933 border-collapse: collapse;
934 width: 100%;
935 font-family: var(--mono);
936 font-size: var(--fs-1);
937 line-height: 1.5;
938}
939table.difftable td {
940 border: 0;
941 padding: 0;
942 vertical-align: top;
943 font-size: inherit;
944}
945table.difftable td.ln {
946 width: 1%;
947 min-width: 2.5rem;
948 padding: 0 var(--sp-2);
949 text-align: right;
950 color: var(--muted);
951 user-select: none;
952 border-right: 1px solid var(--line);
953 white-space: nowrap;
954}
955/* not .code: that class is the blob/code-block style and carries its own
956 background, which painted over every row tint */
957table.difftable td.src {
958 padding: 0 var(--sp-3);
959 white-space: pre-wrap;
960 overflow-wrap: anywhere;
961}
962/* the marker is decoration, so it lives in CSS and stays out of a copied
963 selection */
964table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
965table.difftable tr.del td.src::before { content: "\2212"; color: var(--bad); }
966table.difftable tr.ctx td.src::before { content: " "; }
967table.difftable tr.add { background: var(--diff-add); }
968table.difftable tr.del { background: var(--diff-del); }
969table.difftable tr.hunk td, table.difftable tr.dmeta td {
970 color: var(--muted);
971 padding: var(--sp-1) var(--sp-3);
972 background: var(--fill-subtle);
973 border-top: 1px solid var(--line);
974 border-bottom: 1px solid var(--line);
975}
976table.difftable tr.hunk td.src { color: var(--accent); }
977table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--bg); }
978/* a line number is the handle for commenting on that line; it stays a
979 plain number until pointed at, so the gutter does not read as a wall of
980 links */
981table.difftable td.ln a.cmt { color: inherit; text-decoration: none; }
982table.difftable td.ln a.cmt:hover,
983table.difftable td.ln a.cmt:focus { color: var(--accent); text-decoration: underline; }
984
985/* badges: signature and check states. Semantic colors stay distinct:
986 green verified/success, amber pending/stale, red bad/failure, muted
987 unsigned. */
988.badge, .chip {
989 --chip: var(--neutral);
990 display: inline-block;
991 padding: 0.05rem 0.55rem;
992 border-radius: var(--r-pill);
993 font-size: var(--fs-0);
994 font-weight: 500;
995 line-height: 1.5;
996 color: var(--chip);
997 border: 1px solid color-mix(in srgb, var(--chip) 35%, transparent);
998 background: color-mix(in srgb, var(--chip) 7%, transparent);
999 white-space: nowrap;
1000 vertical-align: middle;
1001}
1002.chip-open { --chip: var(--ok); }
1003.chip-closed { --chip: var(--bad); }
1004.chip-merged, .chip-done { --chip: var(--done); }
1005.chip-neutral, .chip-source_gone { --chip: var(--neutral); }
1006.chip-stale { --chip: var(--warn); }
1007.chip.label { font-weight: 500; }
1008.chip.topic { --chip: var(--accent); }
1009.repohead .topics { margin: 0 0 var(--sp-2); }
1010.repohead .mirrorline { margin: 0 0 var(--sp-2); }
1011.mirrorerr { color: var(--bad); }
1012.badge-verified { --chip: var(--ok); }
1013.badge-unsigned { --chip: var(--neutral); }
1014.badge-signed_unknown_key { --chip: var(--warn); }
1015.badge-signed_email_mismatch { --chip: var(--bad); }
1016.badge-signed_key_expired { --chip: var(--warn); }
1017.badge-signed_key_revoked { --chip: var(--bad); }
1018.badge-bad_signature { --chip: var(--bad); }
1019.badge.check-success { --chip: var(--ok); }
1020.badge.check-pending { --chip: var(--warn); }
1021.badge.check-failure, .badge.check-error { --chip: var(--bad); }
1022.badge.check-cancelled, .chip.check-cancelled { --chip: var(--neutral); }
1023.badge.check-running, .chip.check-running { --chip: var(--warn); }
1024.chip.check-success { --chip: var(--ok); }
1025.chip.check-pending { --chip: var(--warn); }
1026.chip.check-failure { --chip: var(--bad); }
1027pre.buildlog { max-height: 40rem; overflow: auto; }
1028span.check-success { color: var(--ok); }
1029span.check-pending { color: var(--warn); }
1030span.check-failure, span.check-error { color: var(--bad); }
1031
1032/* issue and MR listings */
1033.listhead {
1034 display: flex;
1035 align-items: baseline;
1036 gap: var(--sp-4);
1037 flex-wrap: wrap;
1038}
1039.listhead h2 { margin-bottom: var(--sp-2); }
1040nav.filters { display: flex; gap: var(--sp-1); }
1041nav.filters a {
1042 color: var(--muted);
1043 font-size: var(--fs-2);
1044 padding: 0.05rem var(--sp-2);
1045 border-radius: var(--r-pill);
1046}
1047nav.filters a:hover { color: var(--fg); background: var(--hover); text-decoration: none; }
1048nav.filters a.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
1049
1050ul.issuelist {
1051 list-style: none;
1052 margin: var(--sp-2) 0;
1053 padding: 0;
1054 background: var(--surface);
1055 border: 1px solid var(--line);
1056 border-radius: var(--r-lg);
1057 overflow: hidden;
1058}
1059ul.issuelist li {
1060 display: flex;
1061 align-items: baseline;
1062 gap: var(--sp-3);
1063 padding: var(--sp-3) var(--sp-4);
1064 border-bottom: 1px solid var(--faint);
1065}
1066ul.issuelist li:last-child { border-bottom: none; }
1067ul.issuelist li:hover { background: var(--hover); }
1068ul.issuelist li.empty { display: block; color: var(--muted); }
1069ul.issuelist .issuemain { flex: 1; min-width: 0; }
1070ul.issuelist p { margin: 0; }
1071ul.issuelist .title a { color: var(--fg); font-weight: 550; }
1072ul.issuelist .title a:hover { color: var(--accent); }
1073
1074/* releases */
1075article.release {
1076 background: var(--surface);
1077 border: 1px solid var(--line);
1078 border-radius: var(--r-lg);
1079 padding: var(--sp-3) var(--sp-4);
1080 margin: var(--sp-4) 0;
1081}
1082.releasehead { background: none; border: 0; padding: 0; }
1083.releasehead h3 { margin: 0 0 var(--sp-1); }
1084.releasehead .meta { margin: 0 0 var(--sp-2); }
1085table.assets { margin-top: var(--sp-2); }
1086table.assets td.size { color: var(--muted); white-space: nowrap; text-align: right; }
1087table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
1088
1089/* milestones */
1090ul.milestonelist {
1091 list-style: none;
1092 margin: var(--sp-2) 0;
1093 padding: 0;
1094 border: 1px solid var(--line);
1095 border-radius: var(--r-lg);
1096 overflow: hidden;
1097}
1098ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1099ul.milestonelist li:last-child { border-bottom: none; }
1100ul.milestonelist li.empty { color: var(--muted); }
1101ul.milestonelist p { margin: 0; }
1102ul.milestonelist .title { font-weight: 550; }
1103.progress {
1104 height: 6px;
1105 background: var(--faint);
1106 border-radius: var(--r-pill);
1107 margin-top: var(--sp-2);
1108 overflow: hidden;
1109 max-width: 24rem;
1110}
1111.progress .bar { height: 100%; background: var(--ok); }
1112.listhead .spacer { flex: 1; }
1113
1114/* issue / MR detail */
1115h2.issuetitle { margin-bottom: var(--sp-1); font-size: var(--fs-5); }
1116.issuenumber { color: var(--muted); font-weight: 400; }
1117.issuemeta { color: var(--muted); font-size: var(--fs-2); margin-top: 0; }
1118.review { font-size: var(--fs-2); }
1119
1120/* comment cards; discussion stays at a readable measure */
1121article.comment, form.commentform {
1122 max-width: 48rem;
1123}
1124article.comment {
1125 border: 1px solid var(--faint);
1126 border-radius: var(--r-lg);
1127 margin: var(--sp-4) 0;
1128}
1129article.comment .commenthead {
1130 background: var(--surface);
1131 border-bottom: 1px solid var(--faint);
1132 border-radius: var(--r-lg) var(--r-lg) 0 0;
1133 padding: var(--sp-2) var(--sp-4);
1134 font-size: var(--fs-2);
1135}
1136article.comment .commenthead .when { color: var(--muted); }
1137article.comment .rendered { padding: 0 var(--sp-4); }
1138article.comment .rendered > :first-child { margin-top: var(--sp-3); }
1139article.comment .rendered > :last-child { margin-bottom: var(--sp-3); }
1140form.commentform { margin: var(--sp-4) 0; }
1141details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
1142details.editbox summary { cursor: pointer; color: var(--muted); font-size: var(--fs-2); }
1143details.editbox summary:hover { color: var(--accent); }
1144details.editbox input[type="text"] { width: 100%; }
1145.syscomment {
1146 max-width: 48rem;
1147 color: var(--muted);
1148 font-size: var(--fs-2);
1149 margin: var(--sp-3) 0;
1150 padding-left: var(--sp-4);
1151 border-left: 3px solid var(--faint);
1152}
1153.syscomment p { display: inline; margin: 0; }
1154
1155/* review threads under diff lines */
1156.thread {
1157 border: 1px solid var(--faint);
1158 border-left: 3px solid var(--accent);
1159 border-radius: var(--r-md);
1160 padding: var(--sp-2) var(--sp-4);
1161 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1162}
1163.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1164.thread.stale { border-left-color: var(--warn); }
1165.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1166.thread .when { color: var(--muted); }
1167.thread .rendered p { margin: var(--sp-1) 0; }
1168.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1169.thread.composing { border-left-color: var(--mark); }
1170.thread details.threadreply { margin: var(--sp-2) 0 0; }
1171.thread details.threadreply > summary { color: var(--accent); font-size: var(--fs-1); cursor: pointer; }
1172.thread textarea { width: 100%; }
1173.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1174
1175/* forms: every control shares one shell, so a select reads as a sibling
1176 of the text inputs beside it rather than as an OS control dropped in */
1177input, textarea, button, select { font: inherit; color: inherit; }
1178input[type="text"], input[type="search"], input[type="email"],
1179input[type="password"], input:not([type]), textarea, select {
1180 background: var(--bg);
1181 color: var(--fg);
1182 border: 1px solid var(--line);
1183 border-radius: var(--r-md);
1184 padding: var(--sp-2) var(--sp-3);
1185 line-height: 1.4;
1186}
1187textarea { width: 100%; resize: vertical; }
1188textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
1189/* the native arrow cannot be restyled, so draw our own and match the
1190 inputs exactly; --chev carries the stroke colour per scheme */
1191select {
1192 appearance: none;
1193 padding-right: 1.9rem;
1194 background-image: var(--chev);
1195 background-repeat: no-repeat;
1196 background-position: right 0.6rem center;
1197 background-size: 0.62rem;
1198 cursor: pointer;
1199}
1200input:hover, textarea:hover, select:hover { border-color: var(--muted); }
1201/* the global :focus-visible ring covers these; only the border moves */
1202input:focus, textarea:focus, select:focus { border-color: var(--accent); }
1203input[type="radio"] { accent-color: var(--fill); }
1204label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
1205label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
1206
1207/* A radio keeps the native control: a circle takes one answer, a square
1208 takes any number, and that shape is the cue that survives greyscale,
1209 high contrast and colour blindness. The checkbox is drawn instead,
1210 because at the size the OS renders it it reads as an afterthought
1211 beside the button it shares a row with. The square is kept square —
1212 the size changes, the cue does not. */
1213input[type="checkbox"] {
1214 appearance: none;
1215 flex: none;
1216 /* the height of a text input, a select and a button, so a settings row
1217 ends in one column of controls rather than a button and a speck */
1218 width: 2.5rem;
1219 height: 2.5rem;
1220 /* an empty box has nothing but its border to announce it, so the border
1221 is --muted rather than the --line the sized controls can afford */
1222 border: 1px solid var(--muted);
1223 border-radius: var(--r-sm);
1224 background: var(--bg);
1225 cursor: pointer;
1226}
1227input[type="checkbox"]:not(:checked):hover { border-color: var(--fg); }
1228input[type="checkbox"]:checked {
1229 background: var(--fill);
1230 border-color: var(--fill);
1231 /* the mark sits on the blue ground, so it is white in both schemes */
1232 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 10'%3E%3Cpath d='M1 5l3.4 3.4L11 1.4' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
1233 background-repeat: no-repeat;
1234 background-position: center;
1235 background-size: 1.2rem;
1236}
1237
1238/* a segmented control for a small, mutually exclusive set: real radios
1239 underneath, so arrow keys and screen readers behave as they always did */
1240fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
1241fieldset.segmented legend {
1242 padding: 0;
1243 margin-bottom: var(--sp-2);
1244 color: var(--muted);
1245 font-size: var(--fs-2);
1246}
1247fieldset.segmented .options { display: inline-flex; }
1248fieldset.segmented label { gap: 0; }
1249fieldset.segmented input {
1250 position: absolute;
1251 width: 1px;
1252 height: 1px;
1253 opacity: 0;
1254 pointer-events: none;
1255}
1256fieldset.segmented span {
1257 display: block;
1258 padding: var(--sp-2) var(--sp-4);
1259 border: 1px solid var(--line);
1260 font-size: var(--fs-2);
1261 cursor: pointer;
1262}
1263fieldset.segmented label + label span { border-left: 0; }
1264fieldset.segmented label:first-child span { border-radius: var(--r-sm) 0 0 var(--r-sm); }
1265fieldset.segmented label:last-child span { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
1266fieldset.segmented span:hover { border-color: var(--muted); }
1267fieldset.segmented input:checked + span {
1268 background: var(--fill);
1269 border-color: var(--fill);
1270 color: #ffffff;
1271 font-weight: 600;
1272}
1273fieldset.segmented input:focus-visible + span {
1274 outline: 2px solid var(--accent);
1275 outline-offset: 2px;
1276}
1277
1278/* remaining input states */
1279::placeholder { color: var(--muted); opacity: 1; }
1280::selection { background: var(--fill); color: #ffffff; }
1281/* :user-invalid, not :invalid — a required field is invalid the moment
1282 the page loads, and colouring it red before anyone has typed is a
1283 scolding, not a hint */
1284input:user-invalid, textarea:user-invalid {
1285 border-color: var(--bad);
1286}
1287.hint { display: block; color: var(--muted); font-size: var(--fs-1); margin-top: var(--sp-1); }
1288button {
1289 background: var(--fill);
1290 color: #ffffff;
1291 border: none;
1292 border-radius: var(--r-md);
1293 padding: var(--sp-2) var(--sp-4);
1294 font-weight: 600;
1295 cursor: pointer;
1296}
1297button:hover { filter: brightness(1.15); }
1298
1299/* 404 */
1300.notfound { text-align: center; padding: var(--sp-6) 0; }
1301.notfound .bigcode {
1302 font-family: var(--mono);
1303 font-size: 4rem;
1304 color: var(--faint);
1305 -webkit-text-stroke: 1px var(--line);
1306 margin: 0;
1307 line-height: 1;
1308}
1309.notfound h1 { margin-top: var(--sp-3); }
1310
1311/* footer */
1312footer {
1313 border-top: 1px solid var(--faint);
1314 padding: var(--sp-4) var(--sp-5) var(--sp-5);
1315 width: 100%;
1316 color: var(--muted);
1317 font-size: var(--fs-1);
1318}
1319footer p { margin: 0; }
1320footer a { color: var(--muted); text-decoration: underline; }
1321footer a:hover { color: var(--accent); }
1322
1323/* search */
1324form.searchform {
1325 display: flex;
1326 gap: var(--sp-2);
1327 margin: var(--sp-3) 0 var(--sp-4);
1328}
1329form.searchform input[type="search"] { flex: 1; max-width: 32rem; }
1330form.searchform.compact { margin: 0; }
1331form.searchform.compact input[type="search"] {
1332 padding: var(--sp-1) var(--sp-3);
1333 font-size: var(--fs-2);
1334 min-width: 18rem;
1335}
1336ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1337ul.matchlist li { margin-bottom: var(--sp-3); }
1338ul.matchlist .matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1339pre.matchline {
1340 background: var(--code-bg);
1341 border: 1px solid var(--faint);
1342 border-radius: var(--r-md);
1343 padding: var(--sp-1) var(--sp-3);
1344 margin: var(--sp-1) 0 0;
1345 overflow-x: auto;
1346}
1347pre.matchline mark {
1348 background: color-mix(in srgb, var(--warn) 25%, transparent);
1349 color: inherit;
1350 border-radius: 2px;
1351}
1352
1353/* wiki */
1354.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
1355.wikipage { flex: 1; min-width: 0; }
1356.wikinav { flex: none; width: 13rem; padding-top: var(--sp-4); }
1357.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1358.wikinav li a { display: block; padding: 0.15rem 0; color: var(--fg); }
1359.wikinav li a:hover { color: var(--accent); text-decoration: none; }
1360.wikinav li a.active { color: var(--accent); font-weight: 550; }
1361@media (max-width: 40rem) {
1362 /* Column direction + the desktop align-items:flex-start lets .wikipage
1363 take its content's intrinsic width, overflowing the viewport (and
1364 triggering iOS font inflation). Stretch pins it to the container. */
1365 .wikilayout { flex-direction: column; align-items: stretch; }
1366 .wikinav { width: auto; padding-top: 0; }
1367}
1368
1369/* blame */
1370.blame {
1371 border: 1px solid var(--line);
1372 border-radius: var(--rad-2, 6px);
1373 overflow: hidden;
1374}
1375.blamehunk {
1376 display: flex;
1377 gap: var(--sp-3);
1378 border-top: 1px solid var(--line);
1379 align-items: flex-start;
1380}
1381.blamehunk:first-child { border-top: none; }
1382.blameinfo {
1383 flex: none;
1384 width: 17rem;
1385 padding: var(--sp-2) var(--sp-3);
1386 min-width: 0;
1387}
1388.blameinfo .subject {
1389 margin: 0;
1390 font-size: var(--fs-1);
1391 white-space: nowrap;
1392 overflow: hidden;
1393 text-overflow: ellipsis;
1394}
1395.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1396.blamecode {
1397 flex: 1;
1398 margin: 0;
1399 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1400 overflow-x: auto;
1401 border-left: 1px solid var(--line);
1402 align-self: stretch;
1403}
1404.lineno {
1405 display: inline-block;
1406 min-width: 3.5em;
1407 padding-right: 1em;
1408 text-align: right;
1409 color: var(--muted);
1410 user-select: none;
1411}
1412
1413/* mobile */
1414@media (max-width: 40rem) {
1415 .container { padding-left: var(--sp-4); padding-right: var(--sp-4); }
1416 main.container { padding-top: var(--sp-2); }
1417 .repogrid { grid-template-columns: 1fr; }
1418 .thread { margin-left: var(--sp-3); }
1419 /* the commit subject is the widest thing in the listing and the one
1420 column a phone can do without: the tipbar above already names the
1421 latest commit. */
1422 table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
1423 table.tree td.mode, table.tree th.mode { display: none; }
1424 .clone, .pathbar { overflow-wrap: anywhere; }
1425 .readme, .code { padding: var(--sp-3); }
1426 .blamehunk { flex-direction: column; gap: 0; }
1427 .blameinfo { width: auto; }
1428 .blamecode { border-left: none; padding-left: var(--sp-3); width: 100%; }
1429 .cardhead {
1430 margin: calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) var(--sp-3);
1431 padding: var(--sp-2) var(--sp-3);
1432 }
1433}
1434
1435/* tree listing: the last commit is what a file table is scanned for, so
1436 it leads. The file's own facts moved to the blob page. */
1437.tipbar {
1438 display: flex;
1439 align-items: center;
1440 gap: var(--sp-3);
1441 padding: var(--sp-2) var(--sp-4);
1442 background: var(--hover);
1443 border: 1px solid var(--line);
1444 border-bottom: 0;
1445 border-radius: var(--r-lg) var(--r-lg) 0 0;
1446 font-size: var(--fs-2);
1447}
1448.tipbar .who { font-weight: 600; }
1449.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1450.tipbar .subject:hover { color: var(--accent); }
1451.tipbar .spacer { flex: 1; }
1452.tipbar .age { color: var(--muted); white-space: nowrap; }
1453.tipbar + table.tree { border-radius: 0 0 var(--r-lg) var(--r-lg); }
1454table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
1455table.tree td.lastcommit a { color: var(--muted); display: block; overflow: hidden;
1456 text-overflow: ellipsis; white-space: nowrap; }
1457table.tree td.lastcommit a:hover { color: var(--accent); }
1458table.tree th.age, table.tree td.age {
1459 text-align: right;
1460 white-space: nowrap;
1461 color: var(--muted);
1462 font-variant-numeric: tabular-nums;
1463}
1464table.tree td.name { width: 25%; white-space: nowrap; }
1465table.tree td.name.dir a { color: var(--accent); }
1466p.clone { margin: 0 0 var(--sp-3); }
1467p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1468.pathbar .act { font-size: var(--fs-1); }
1469
1470/* merge request: a two-column split, so state has somewhere to live that
1471 is not a run-on sentence under the title */
1472.withaside {
1473 display: grid;
1474 grid-template-columns: minmax(0, 1fr) 15rem;
1475 gap: var(--sp-5);
1476 align-items: start;
1477}
1478.withaside .mainside { min-width: 0; }
1479@media (max-width: 62rem) { .withaside { grid-template-columns: 1fr; } }
1480
1481.aside { font-size: var(--fs-2); }
1482.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1483.aside .grp:first-child { border-top: 0; padding-top: 0; }
1484.aside h2 {
1485 margin: 0 0 var(--sp-2);
1486 font-family: var(--mono);
1487 font-size: var(--fs-0);
1488 font-weight: 500;
1489 letter-spacing: 0.1em;
1490 text-transform: uppercase;
1491 color: var(--muted);
1492}
1493.aside .row { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1494.aside .row:last-child { margin-bottom: 0; }
1495.aside .none { color: var(--muted); }
1496/* a row's second line: when it happened, under what it happened to. The
1497 extra gap keeps the pair reading as one entry. */
1498.aside .row .sub { flex-basis: 100%; color: var(--muted); font-size: var(--fs-0); }
1499.aside .row:has(.sub) { margin-bottom: var(--sp-2); }
1500.aside .dot { width: 0.45rem; height: 0.45rem; flex: none; border-radius: 50%; background: var(--muted); }
1501.aside .dot.ok { background: var(--ok); }
1502.aside .dot.bad { background: var(--bad); }
1503.aside .dot.pend { background: var(--mark); }
1504
1505/* sub-navigation within an item; orange marks position as it does above */
1506nav.subtabs {
1507 display: flex;
1508 gap: var(--sp-4);
1509 border-bottom: 1px solid var(--line);
1510 margin: 0 0 var(--sp-4);
1511}
1512nav.subtabs a {
1513 display: inline-flex;
1514 align-items: center;
1515 gap: var(--sp-2);
1516 padding: 0 0 var(--sp-2);
1517 color: var(--muted);
1518 font-size: var(--fs-2);
1519 border-bottom: 2px solid transparent;
1520 margin-bottom: -1px;
1521}
1522nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1523nav.subtabs a[aria-current] { color: var(--fg); font-weight: 700; border-bottom-color: var(--mark); }
1524nav.subtabs a i {
1525 font-style: normal;
1526 font-family: var(--mono);
1527 font-size: var(--fs-0);
1528 background: var(--hover);
1529 border-radius: var(--r-sm);
1530 padding: 0 0.35rem;
1531}
1532p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1533p.diffstat .add { color: var(--ok); }
1534p.diffstat .del { color: var(--bad); }