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