internal/web/static/style.css
1529 lines · 52486 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-running, .chip.check-running { --chip: var(--warn); }
1023.chip.check-success { --chip: var(--ok); }
1024.chip.check-pending { --chip: var(--warn); }
1025.chip.check-failure { --chip: var(--bad); }
1026pre.buildlog { max-height: 40rem; overflow: auto; }
1027span.check-success { color: var(--ok); }
1028span.check-pending { color: var(--warn); }
1029span.check-failure, span.check-error { color: var(--bad); }
1030
1031/* issue and MR listings */
1032.listhead {
1033 display: flex;
1034 align-items: baseline;
1035 gap: var(--sp-4);
1036 flex-wrap: wrap;
1037}
1038.listhead h2 { margin-bottom: var(--sp-2); }
1039nav.filters { display: flex; gap: var(--sp-1); }
1040nav.filters a {
1041 color: var(--muted);
1042 font-size: var(--fs-2);
1043 padding: 0.05rem var(--sp-2);
1044 border-radius: var(--r-pill);
1045}
1046nav.filters a:hover { color: var(--fg); background: var(--hover); text-decoration: none; }
1047nav.filters a.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
1048
1049ul.issuelist {
1050 list-style: none;
1051 margin: var(--sp-2) 0;
1052 padding: 0;
1053 background: var(--surface);
1054 border: 1px solid var(--line);
1055 border-radius: var(--r-lg);
1056 overflow: hidden;
1057}
1058ul.issuelist li {
1059 display: flex;
1060 align-items: baseline;
1061 gap: var(--sp-3);
1062 padding: var(--sp-3) var(--sp-4);
1063 border-bottom: 1px solid var(--faint);
1064}
1065ul.issuelist li:last-child { border-bottom: none; }
1066ul.issuelist li:hover { background: var(--hover); }
1067ul.issuelist li.empty { display: block; color: var(--muted); }
1068ul.issuelist .issuemain { flex: 1; min-width: 0; }
1069ul.issuelist p { margin: 0; }
1070ul.issuelist .title a { color: var(--fg); font-weight: 550; }
1071ul.issuelist .title a:hover { color: var(--accent); }
1072
1073/* releases */
1074article.release {
1075 background: var(--surface);
1076 border: 1px solid var(--line);
1077 border-radius: var(--r-lg);
1078 padding: var(--sp-3) var(--sp-4);
1079 margin: var(--sp-4) 0;
1080}
1081.releasehead { background: none; border: 0; padding: 0; }
1082.releasehead h3 { margin: 0 0 var(--sp-1); }
1083.releasehead .meta { margin: 0 0 var(--sp-2); }
1084table.assets { margin-top: var(--sp-2); }
1085table.assets td.size { color: var(--muted); white-space: nowrap; text-align: right; }
1086table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
1087
1088/* milestones */
1089ul.milestonelist {
1090 list-style: none;
1091 margin: var(--sp-2) 0;
1092 padding: 0;
1093 border: 1px solid var(--line);
1094 border-radius: var(--r-lg);
1095 overflow: hidden;
1096}
1097ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1098ul.milestonelist li:last-child { border-bottom: none; }
1099ul.milestonelist li.empty { color: var(--muted); }
1100ul.milestonelist p { margin: 0; }
1101ul.milestonelist .title { font-weight: 550; }
1102.progress {
1103 height: 6px;
1104 background: var(--faint);
1105 border-radius: var(--r-pill);
1106 margin-top: var(--sp-2);
1107 overflow: hidden;
1108 max-width: 24rem;
1109}
1110.progress .bar { height: 100%; background: var(--ok); }
1111.listhead .spacer { flex: 1; }
1112
1113/* issue / MR detail */
1114h2.issuetitle { margin-bottom: var(--sp-1); font-size: var(--fs-5); }
1115.issuenumber { color: var(--muted); font-weight: 400; }
1116.issuemeta { color: var(--muted); font-size: var(--fs-2); margin-top: 0; }
1117.review { font-size: var(--fs-2); }
1118
1119/* comment cards; discussion stays at a readable measure */
1120article.comment, form.commentform {
1121 max-width: 48rem;
1122}
1123article.comment {
1124 border: 1px solid var(--faint);
1125 border-radius: var(--r-lg);
1126 margin: var(--sp-4) 0;
1127}
1128article.comment .commenthead {
1129 background: var(--surface);
1130 border-bottom: 1px solid var(--faint);
1131 border-radius: var(--r-lg) var(--r-lg) 0 0;
1132 padding: var(--sp-2) var(--sp-4);
1133 font-size: var(--fs-2);
1134}
1135article.comment .commenthead .when { color: var(--muted); }
1136article.comment .rendered { padding: 0 var(--sp-4); }
1137article.comment .rendered > :first-child { margin-top: var(--sp-3); }
1138article.comment .rendered > :last-child { margin-bottom: var(--sp-3); }
1139form.commentform { margin: var(--sp-4) 0; }
1140details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
1141details.editbox summary { cursor: pointer; color: var(--muted); font-size: var(--fs-2); }
1142details.editbox summary:hover { color: var(--accent); }
1143details.editbox input[type="text"] { width: 100%; }
1144.syscomment {
1145 max-width: 48rem;
1146 color: var(--muted);
1147 font-size: var(--fs-2);
1148 margin: var(--sp-3) 0;
1149 padding-left: var(--sp-4);
1150 border-left: 3px solid var(--faint);
1151}
1152.syscomment p { display: inline; margin: 0; }
1153
1154/* review threads under diff lines */
1155.thread {
1156 border: 1px solid var(--faint);
1157 border-left: 3px solid var(--accent);
1158 border-radius: var(--r-md);
1159 padding: var(--sp-2) var(--sp-4);
1160 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1161}
1162.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1163.thread.stale { border-left-color: var(--warn); }
1164.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1165.thread .when { color: var(--muted); }
1166.thread .rendered p { margin: var(--sp-1) 0; }
1167.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1168.thread.composing { border-left-color: var(--mark); }
1169.thread details.threadreply { margin: var(--sp-2) 0 0; }
1170.thread details.threadreply > summary { color: var(--accent); font-size: var(--fs-1); cursor: pointer; }
1171.thread textarea { width: 100%; }
1172.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1173
1174/* forms: every control shares one shell, so a select reads as a sibling
1175 of the text inputs beside it rather than as an OS control dropped in */
1176input, textarea, button, select { font: inherit; color: inherit; }
1177input[type="text"], input[type="search"], input[type="email"],
1178input[type="password"], input:not([type]), textarea, select {
1179 background: var(--bg);
1180 color: var(--fg);
1181 border: 1px solid var(--line);
1182 border-radius: var(--r-md);
1183 padding: var(--sp-2) var(--sp-3);
1184 line-height: 1.4;
1185}
1186textarea { width: 100%; resize: vertical; }
1187textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
1188/* the native arrow cannot be restyled, so draw our own and match the
1189 inputs exactly; --chev carries the stroke colour per scheme */
1190select {
1191 appearance: none;
1192 padding-right: 1.9rem;
1193 background-image: var(--chev);
1194 background-repeat: no-repeat;
1195 background-position: right 0.6rem center;
1196 background-size: 0.62rem;
1197 cursor: pointer;
1198}
1199input:hover, textarea:hover, select:hover { border-color: var(--muted); }
1200/* the global :focus-visible ring covers these; only the border moves */
1201input:focus, textarea:focus, select:focus { border-color: var(--accent); }
1202input[type="radio"] { accent-color: var(--fill); }
1203label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
1204label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
1205
1206/* A radio keeps the native control: a circle takes one answer, a square
1207 takes any number, and that shape is the cue that survives greyscale,
1208 high contrast and colour blindness. The checkbox is drawn instead,
1209 because at the size the OS renders it it reads as an afterthought
1210 beside the button it shares a row with. The square is kept square —
1211 the size changes, the cue does not. */
1212input[type="checkbox"] {
1213 appearance: none;
1214 flex: none;
1215 /* the height of a text input, a select and a button, so a settings row
1216 ends in one column of controls rather than a button and a speck */
1217 width: 2.5rem;
1218 height: 2.5rem;
1219 /* an empty box has nothing but its border to announce it, so the border
1220 is --muted rather than the --line the sized controls can afford */
1221 border: 1px solid var(--muted);
1222 border-radius: var(--r-sm);
1223 background: var(--bg);
1224 cursor: pointer;
1225}
1226input[type="checkbox"]:not(:checked):hover { border-color: var(--fg); }
1227input[type="checkbox"]:checked {
1228 background: var(--fill);
1229 border-color: var(--fill);
1230 /* the mark sits on the blue ground, so it is white in both schemes */
1231 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");
1232 background-repeat: no-repeat;
1233 background-position: center;
1234 background-size: 1.2rem;
1235}
1236
1237/* a segmented control for a small, mutually exclusive set: real radios
1238 underneath, so arrow keys and screen readers behave as they always did */
1239fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
1240fieldset.segmented legend {
1241 padding: 0;
1242 margin-bottom: var(--sp-2);
1243 color: var(--muted);
1244 font-size: var(--fs-2);
1245}
1246fieldset.segmented .options { display: inline-flex; }
1247fieldset.segmented label { gap: 0; }
1248fieldset.segmented input {
1249 position: absolute;
1250 width: 1px;
1251 height: 1px;
1252 opacity: 0;
1253 pointer-events: none;
1254}
1255fieldset.segmented span {
1256 display: block;
1257 padding: var(--sp-2) var(--sp-4);
1258 border: 1px solid var(--line);
1259 font-size: var(--fs-2);
1260 cursor: pointer;
1261}
1262fieldset.segmented label + label span { border-left: 0; }
1263fieldset.segmented label:first-child span { border-radius: var(--r-sm) 0 0 var(--r-sm); }
1264fieldset.segmented label:last-child span { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
1265fieldset.segmented span:hover { border-color: var(--muted); }
1266fieldset.segmented input:checked + span {
1267 background: var(--fill);
1268 border-color: var(--fill);
1269 color: #ffffff;
1270 font-weight: 600;
1271}
1272fieldset.segmented input:focus-visible + span {
1273 outline: 2px solid var(--accent);
1274 outline-offset: 2px;
1275}
1276
1277/* remaining input states */
1278::placeholder { color: var(--muted); opacity: 1; }
1279::selection { background: var(--fill); color: #ffffff; }
1280/* :user-invalid, not :invalid — a required field is invalid the moment
1281 the page loads, and colouring it red before anyone has typed is a
1282 scolding, not a hint */
1283input:user-invalid, textarea:user-invalid {
1284 border-color: var(--bad);
1285}
1286.hint { display: block; color: var(--muted); font-size: var(--fs-1); margin-top: var(--sp-1); }
1287button {
1288 background: var(--fill);
1289 color: #ffffff;
1290 border: none;
1291 border-radius: var(--r-md);
1292 padding: var(--sp-2) var(--sp-4);
1293 font-weight: 600;
1294 cursor: pointer;
1295}
1296button:hover { filter: brightness(1.15); }
1297
1298/* 404 */
1299.notfound { text-align: center; padding: var(--sp-6) 0; }
1300.notfound .bigcode {
1301 font-family: var(--mono);
1302 font-size: 4rem;
1303 color: var(--faint);
1304 -webkit-text-stroke: 1px var(--line);
1305 margin: 0;
1306 line-height: 1;
1307}
1308.notfound h1 { margin-top: var(--sp-3); }
1309
1310/* footer */
1311footer {
1312 border-top: 1px solid var(--faint);
1313 padding: var(--sp-4) var(--sp-5) var(--sp-5);
1314 width: 100%;
1315 color: var(--muted);
1316 font-size: var(--fs-1);
1317}
1318footer p { margin: 0; }
1319footer a { color: var(--muted); text-decoration: underline; }
1320footer a:hover { color: var(--accent); }
1321
1322/* search */
1323form.searchform {
1324 display: flex;
1325 gap: var(--sp-2);
1326 margin: var(--sp-3) 0 var(--sp-4);
1327}
1328form.searchform input[type="search"] { flex: 1; max-width: 32rem; }
1329form.searchform.compact { margin: 0; }
1330form.searchform.compact input[type="search"] {
1331 padding: var(--sp-1) var(--sp-3);
1332 font-size: var(--fs-2);
1333 min-width: 18rem;
1334}
1335ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1336ul.matchlist li { margin-bottom: var(--sp-3); }
1337ul.matchlist .matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1338pre.matchline {
1339 background: var(--code-bg);
1340 border: 1px solid var(--faint);
1341 border-radius: var(--r-md);
1342 padding: var(--sp-1) var(--sp-3);
1343 margin: var(--sp-1) 0 0;
1344 overflow-x: auto;
1345}
1346pre.matchline mark {
1347 background: color-mix(in srgb, var(--warn) 25%, transparent);
1348 color: inherit;
1349 border-radius: 2px;
1350}
1351
1352/* wiki */
1353.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
1354.wikipage { flex: 1; min-width: 0; }
1355.wikinav { flex: none; width: 13rem; padding-top: var(--sp-4); }
1356.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1357.wikinav li a { display: block; padding: 0.15rem 0; color: var(--fg); }
1358.wikinav li a:hover { color: var(--accent); text-decoration: none; }
1359.wikinav li a.active { color: var(--accent); font-weight: 550; }
1360@media (max-width: 40rem) {
1361 /* Column direction + the desktop align-items:flex-start lets .wikipage
1362 take its content's intrinsic width, overflowing the viewport (and
1363 triggering iOS font inflation). Stretch pins it to the container. */
1364 .wikilayout { flex-direction: column; align-items: stretch; }
1365 .wikinav { width: auto; padding-top: 0; }
1366}
1367
1368/* blame */
1369.blame {
1370 border: 1px solid var(--line);
1371 border-radius: var(--rad-2, 6px);
1372 overflow: hidden;
1373}
1374.blamehunk {
1375 display: flex;
1376 gap: var(--sp-3);
1377 border-top: 1px solid var(--line);
1378 align-items: flex-start;
1379}
1380.blamehunk:first-child { border-top: none; }
1381.blameinfo {
1382 flex: none;
1383 width: 17rem;
1384 padding: var(--sp-2) var(--sp-3);
1385 min-width: 0;
1386}
1387.blameinfo .subject {
1388 margin: 0;
1389 font-size: var(--fs-1);
1390 white-space: nowrap;
1391 overflow: hidden;
1392 text-overflow: ellipsis;
1393}
1394.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1395.blamecode {
1396 flex: 1;
1397 margin: 0;
1398 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1399 overflow-x: auto;
1400 border-left: 1px solid var(--line);
1401 align-self: stretch;
1402}
1403.lineno {
1404 display: inline-block;
1405 min-width: 3.5em;
1406 padding-right: 1em;
1407 text-align: right;
1408 color: var(--muted);
1409 user-select: none;
1410}
1411
1412/* mobile */
1413@media (max-width: 40rem) {
1414 .container { padding-left: var(--sp-4); padding-right: var(--sp-4); }
1415 main.container { padding-top: var(--sp-2); }
1416 .repogrid { grid-template-columns: 1fr; }
1417 .thread { margin-left: var(--sp-3); }
1418 /* the commit subject is the widest thing in the listing and the one
1419 column a phone can do without: the tipbar above already names the
1420 latest commit. */
1421 table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
1422 table.tree td.mode, table.tree th.mode { display: none; }
1423 .clone, .pathbar { overflow-wrap: anywhere; }
1424 .readme, .code { padding: var(--sp-3); }
1425 .blamehunk { flex-direction: column; gap: 0; }
1426 .blameinfo { width: auto; }
1427 .blamecode { border-left: none; padding-left: var(--sp-3); width: 100%; }
1428 .cardhead {
1429 margin: calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) var(--sp-3);
1430 padding: var(--sp-2) var(--sp-3);
1431 }
1432}
1433
1434/* tree listing: the last commit is what a file table is scanned for, so
1435 it leads. The file's own facts moved to the blob page. */
1436.tipbar {
1437 display: flex;
1438 align-items: center;
1439 gap: var(--sp-3);
1440 padding: var(--sp-2) var(--sp-4);
1441 background: var(--hover);
1442 border: 1px solid var(--line);
1443 border-bottom: 0;
1444 border-radius: var(--r-lg) var(--r-lg) 0 0;
1445 font-size: var(--fs-2);
1446}
1447.tipbar .who { font-weight: 600; }
1448.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1449.tipbar .subject:hover { color: var(--accent); }
1450.tipbar .spacer { flex: 1; }
1451.tipbar .age { color: var(--muted); white-space: nowrap; }
1452.tipbar + table.tree { border-radius: 0 0 var(--r-lg) var(--r-lg); }
1453table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
1454table.tree td.lastcommit a { color: var(--muted); display: block; overflow: hidden;
1455 text-overflow: ellipsis; white-space: nowrap; }
1456table.tree td.lastcommit a:hover { color: var(--accent); }
1457table.tree th.age, table.tree td.age {
1458 text-align: right;
1459 white-space: nowrap;
1460 color: var(--muted);
1461 font-variant-numeric: tabular-nums;
1462}
1463table.tree td.name { width: 25%; white-space: nowrap; }
1464table.tree td.name.dir a { color: var(--accent); }
1465p.clone { margin: 0 0 var(--sp-3); }
1466p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1467.pathbar .act { font-size: var(--fs-1); }
1468
1469/* merge request: a two-column split, so state has somewhere to live that
1470 is not a run-on sentence under the title */
1471.withaside {
1472 display: grid;
1473 grid-template-columns: minmax(0, 1fr) 15rem;
1474 gap: var(--sp-5);
1475 align-items: start;
1476}
1477.withaside .mainside { min-width: 0; }
1478@media (max-width: 62rem) { .withaside { grid-template-columns: 1fr; } }
1479
1480.aside { font-size: var(--fs-2); }
1481.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1482.aside .grp:first-child { border-top: 0; padding-top: 0; }
1483.aside h2 {
1484 margin: 0 0 var(--sp-2);
1485 font-family: var(--mono);
1486 font-size: var(--fs-0);
1487 font-weight: 500;
1488 letter-spacing: 0.1em;
1489 text-transform: uppercase;
1490 color: var(--muted);
1491}
1492.aside .row { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1493.aside .row:last-child { margin-bottom: 0; }
1494.aside .none { color: var(--muted); }
1495.aside .dot { width: 0.45rem; height: 0.45rem; flex: none; border-radius: 50%; background: var(--muted); }
1496.aside .dot.ok { background: var(--ok); }
1497.aside .dot.bad { background: var(--bad); }
1498.aside .dot.pend { background: var(--mark); }
1499
1500/* sub-navigation within an item; orange marks position as it does above */
1501nav.subtabs {
1502 display: flex;
1503 gap: var(--sp-4);
1504 border-bottom: 1px solid var(--line);
1505 margin: 0 0 var(--sp-4);
1506}
1507nav.subtabs a {
1508 display: inline-flex;
1509 align-items: center;
1510 gap: var(--sp-2);
1511 padding: 0 0 var(--sp-2);
1512 color: var(--muted);
1513 font-size: var(--fs-2);
1514 border-bottom: 2px solid transparent;
1515 margin-bottom: -1px;
1516}
1517nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1518nav.subtabs a[aria-current] { color: var(--fg); font-weight: 700; border-bottom-color: var(--mark); }
1519nav.subtabs a i {
1520 font-style: normal;
1521 font-family: var(--mono);
1522 font-size: var(--fs-0);
1523 background: var(--hover);
1524 border-radius: var(--r-sm);
1525 padding: 0 0.35rem;
1526}
1527p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1528p.diffstat .add { color: var(--ok); }
1529p.diffstat .del { color: var(--bad); }