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