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