internal/web/static/style.css
1840 lines · 74186 bytes
1/* gitbay stylesheet. Tokens first, on :root and again in the dark media
2 query; components use tokens only. Two accents with separate jobs:
3 blue is what you can do (links, primary buttons, focus, pressed
4 toggles), orange is where you are and what wants you (current tab,
5 rail counts, pending state, unverified signatures). Orange is never a
6 button ground. internal/web/tokens_test.go measures every token;
7 internal/web/classes_test.go checks every template class has a rule.
8 No external requests: fonts are served from this origin. */
9
10@font-face {
11 font-family: "Atkinson Hyperlegible Next";
12 font-style: normal;
13 font-weight: 400 700;
14 font-display: swap;
15 src: url(/static/fonts/atkinson-next-roman.woff2) format("woff2");
16}
17@font-face {
18 font-family: "Atkinson Hyperlegible Next";
19 font-style: italic;
20 font-weight: 400 700;
21 font-display: swap;
22 src: url(/static/fonts/atkinson-next-italic.woff2) format("woff2");
23}
24@font-face {
25 font-family: "Atkinson Hyperlegible Mono";
26 font-style: normal;
27 font-weight: 400 600;
28 font-display: swap;
29 src: url(/static/fonts/atkinson-mono-roman.woff2) format("woff2");
30}
31
32:root {
33 /* declare native light+dark support: correct form controls and
34 scrollbars per scheme, and opt out of browser auto-darkening */
35 color-scheme: light dark;
36
37 /* grounds: canvas, surface and inset are three steps, not one */
38 --canvas: #ffffff;
39 --surface: #ebedf1;
40 --inset: #ffffff;
41 --hover: #e1e4ea;
42 --line: #8d939c; /* 3.09:1 on canvas — a border you can see */
43 --faint: #d8dce2;
44
45 /* ink */
46 --fg: #1c1f24;
47 --muted: #5a6270;
48 --neutral: var(--muted);
49
50 /* blue: what you can do. --link is text, --fill is a ground; one blue
51 cannot clear 4.5:1 as text and 3:1 as a ground in both schemes. */
52 --link: #0033d6;
53 --fill: #0000f0;
54 --fill-fg: #ffffff;
55 --focus: var(--link);
56
57 /* orange: where you are, what wants you. Two cuts because the floor
58 differs by size: --mark for bars, --warn at text size. */
59 --mark: #e4572e;
60 --warn: #b8400f;
61
62 /* state */
63 --ok: #0a7536;
64 --bad: #c62828;
65 --done: #6b21a8;
66
67 /* diff row tints: enough to scan, light enough that the syntax
68 palette stays legible on them (TestSyntaxPaletteContrast) */
69 --diff-add: #e4f6ea;
70 --diff-del: #fdeaea;
71
72 /* the rail is black in both schemes: the one brand constant */
73 --shell-bg: #000000;
74 --shell-fg: #f2f2f2;
75 --shell-muted: #8f8f8f;
76 --shell-line: #1c1c1c;
77 --shell-hover: #141414;
78 --shell-mark: #ff6b3d;
79
80 /* the languages' own colours; the same in both schemes */
81 --lang-go: #00add8;
82 --lang-rust: #dea584;
83 --lang-c: #555555;
84 --lang-python: #3572a5;
85 --lang-javascript: #f1e05a;
86 --lang-typescript: #3178c6;
87 --lang-shell: #89e051;
88 --lang-ruby: #701516;
89 --lang-java: #b07219;
90 --lang-swift: #f05138;
91 --lang-html: #e34c26;
92 --lang-css: #563d7c;
93 --lang-org: #77aa99;
94 --lang-markdown: #083fa1;
95 --lang-emacs-lisp: #c065db;
96 --lang-nix: #7e7eff;
97 --lang-sql: #e38c00;
98
99 --sans: "Atkinson Hyperlegible Next", -apple-system, BlinkMacSystemFont,
100 "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
101 --mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono",
102 SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
103
104 /* 12, 13, 14, 16, 20, 24, 32 */
105 --fs-0: 0.75rem;
106 --fs-1: 0.8125rem;
107 --fs-2: 0.875rem;
108 --fs-3: 1rem;
109 --fs-4: 1.25rem;
110 --fs-5: 1.5rem;
111 --fs-6: 2rem;
112
113 /* 4, 8, 12, 16, 24, 32, 48 */
114 --sp-1: 4px;
115 --sp-2: 8px;
116 --sp-3: 12px;
117 --sp-4: 16px;
118 --sp-5: 24px;
119 --sp-6: 32px;
120 --sp-7: 48px;
121
122 /* the rail: a column the width of one hit target, a row one tall */
123 --rail-hit: 44px;
124 --rail-strip-h: 48px;
125 --rail-mark: 24px;
126 --rail-mark-box: 32px;
127
128 /* the one page container: header content, main and footer align on it */
129 --container: 100rem;
130
131 --r-ctl: 4px; /* controls and chips */
132 --r-card: 6px; /* cards, lists, code blocks */
133 --shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
134
135 /* the native select arrow cannot be restyled, so draw our own;
136 --chev carries the stroke colour per scheme */
137 --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='%235a6270' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
138}
139@media (prefers-color-scheme: dark) {
140 :root {
141 /* the scheme in force, not just the tokens: light-dark() reads it,
142 and themedCSS repeats this block for a page stamped dark */
143 color-scheme: dark;
144
145 --canvas: #101114;
146 --surface: #212429;
147 --inset: #0b0c0e;
148 --hover: #2b2f36;
149 --line: #61666f;
150 --faint: #2f333a;
151
152 --fg: #e9eaec;
153 --muted: #a3a9b3;
154 --neutral: var(--muted);
155
156 --link: #8b9bff;
157 --fill: #4d61f0;
158 --fill-fg: #ffffff;
159 --focus: var(--link);
160
161 --mark: #ff6b3d;
162 --warn: #ff8a63;
163
164 --ok: #3fce7a;
165 --bad: #ff6b6b;
166 --done: #c084fc;
167
168 --diff-add: #0d2a18;
169 --diff-del: #2c1113;
170
171 --shell-bg: #000000;
172 --shell-fg: #f2f2f2;
173 --shell-muted: #8f8f8f;
174 --shell-line: #1c1c1c;
175 --shell-hover: #141414;
176 --shell-mark: #ff6b3d;
177
178 /* the languages' own colours; the same in both schemes */
179 --lang-go: #00add8;
180 --lang-rust: #dea584;
181 --lang-c: #555555;
182 --lang-python: #3572a5;
183 --lang-javascript: #f1e05a;
184 --lang-typescript: #3178c6;
185 --lang-shell: #89e051;
186 --lang-ruby: #701516;
187 --lang-java: #b07219;
188 --lang-swift: #f05138;
189 --lang-html: #e34c26;
190 --lang-css: #563d7c;
191 --lang-org: #77aa99;
192 --lang-markdown: #083fa1;
193 --lang-emacs-lisp: #c065db;
194 --lang-nix: #7e7eff;
195 --lang-sql: #e38c00;
196
197 --shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
198 --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='%23a3a9b3' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
199 }
200}
201
202/* a page stamped light keeps the light scheme under a dark OS: the token
203 block above is guarded for it, and this is the other half of that */
204:root[data-theme="light"] { color-scheme: light; }
205
206/* ---- base ---- */
207* { box-sizing: border-box; }
208html { font-size: 16px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
209body {
210 margin: 0;
211 background: var(--canvas);
212 color: var(--fg);
213 font: var(--fs-3)/1.5 var(--sans);
214 min-height: 100vh;
215}
216h1, h2, h3 { line-height: 1.25; font-weight: 600; }
217h1 { font-size: var(--fs-5); margin: 0 0 var(--sp-3); text-wrap: balance; }
218h2 { font-size: var(--fs-4); margin: var(--sp-6) 0 var(--sp-3); }
219h3 { font-size: var(--fs-3); margin: var(--sp-5) 0 var(--sp-2); }
220p { margin: 0 0 var(--sp-3); }
221a { color: var(--link); text-decoration: none; }
222a:hover { text-decoration: underline; }
223/* a link inside running text is told apart by its underline: link and
224 muted text are 1.07:1 apart in dark, and colour alone is not a cue
225 (#232). Navigation, chips and buttons keep position as their cue. */
226p a, .syscomment a { text-decoration: underline; }
227/* a title or a path is the whole line: position is the cue */
228p a.button, p a.btn, p a.chip, .repotitle a, p.title a, .pathbar a, .pager a { text-decoration: none; }
229/* where a link shares its line with other text the underline is the cue
230 again, path bar or not: a crumb beside the file name, a heading that
231 names an owner, an empty-state note (#226) */
232.crumbs a, h1 a, li.empty a { text-decoration: underline; }
233a.xref { color: var(--link); text-decoration: none; }
234
235code, pre, .mono, .code, td.mode, td.size {
236 font-family: var(--mono);
237 font-size: var(--fs-1);
238}
239.mono { overflow-wrap: anywhere; }
240
241/* ---- focus: one authored ring, so keyboard position is never the
242 browser's guess ---- */
243:focus-visible {
244 outline: 2px solid var(--focus);
245 outline-offset: 2px;
246 border-radius: 1px;
247}
248/* the rail is black in both schemes and --focus is a dark blue in the
249 light one — a ring nobody could see there */
250.rail :focus-visible { outline-color: var(--shell-mark); }
251
252/* visually hidden, still read aloud */
253.vh {
254 position: absolute;
255 width: 1px; height: 1px;
256 margin: -1px; padding: 0; border: 0;
257 clip-path: inset(50%);
258 overflow: hidden;
259 white-space: nowrap;
260}
261
262/* ---- skip link: the rail runs ahead of the content in source order ---- */
263a.skip {
264 position: absolute;
265 left: var(--sp-3); top: -3rem;
266 z-index: 50;
267 display: flex;
268 align-items: center;
269 min-height: var(--rail-hit);
270 background: var(--fill);
271 color: var(--fill-fg);
272 padding: var(--sp-2) var(--sp-4);
273 font-weight: 600;
274}
275a.skip:focus { top: var(--sp-3); text-decoration: none; }
276
277/* ---- rail: one row of glyphs across the top, no labels ----
278 One strip the height of a hit target, at every width: fixed squares,
279 no wrapping and no scrolling. Every item is a square link carrying an
280 inline svg, its name in an aria-label and in a visually hidden span, so
281 the nav reads the same to a screen reader as the old text list did. */
282.rail {
283 height: var(--rail-strip-h);
284 background: var(--shell-bg);
285 color: var(--shell-fg);
286 border-bottom: 1px solid var(--shell-line);
287 display: flex;
288 flex-direction: row;
289 align-items: center;
290 padding: 0 var(--sp-1);
291}
292a.brand {
293 display: flex;
294 align-items: center;
295 justify-content: center;
296 flex: none;
297 width: var(--rail-mark-box);
298 height: var(--rail-strip-h);
299 color: var(--shell-fg);
300}
301a.brand:hover { text-decoration: none; }
302a.brand svg.mark { display: block; flex: none; width: var(--rail-mark); height: var(--rail-mark); }
303
304ul.raillist {
305 list-style: none;
306 margin: 0;
307 padding: 0;
308 display: flex;
309 align-items: center;
310 min-width: 0;
311}
312/* the spacer that holds settings, admin and the account cell at the far
313 end of the row */
314.railgap { flex: 1; }
315.railicon {
316 position: relative;
317 display: flex;
318 align-items: center;
319 justify-content: center;
320 flex: none;
321 width: var(--rail-hit);
322 height: var(--rail-strip-h);
323 padding: 0;
324 border: 0;
325 background: none;
326 color: var(--shell-fg);
327 cursor: pointer;
328}
329.railicon:hover { background: var(--shell-hover); text-decoration: none; }
330/* orange marks position along the bottom edge — the rail's only accent */
331.railicon[aria-current] {
332 background: var(--shell-hover);
333 box-shadow: inset 0 -2px 0 var(--shell-mark);
334}
335.count {
336 font-size: var(--fs-0);
337 font-weight: 600;
338 letter-spacing: 0;
339 background: var(--shell-mark);
340 color: var(--shell-bg);
341 padding: 0 5px;
342 border-radius: var(--r-ctl);
343 margin-left: auto;
344}
345/* the unread count is a badge on the bell's corner, not a trailing number */
346.railicon .count {
347 position: absolute;
348 top: 2px;
349 right: 2px;
350 margin: 0;
351 padding: 0 3px;
352 line-height: 1.35;
353}
354.railfoot {
355 flex: none;
356 display: flex;
357 align-items: center;
358 min-width: 0;
359}
360.railfoot a { color: var(--shell-fg); }
361.railfoot form { margin: 0; }
362a.railuser {
363 display: flex;
364 align-items: center;
365 justify-content: center;
366 flex: none;
367 width: var(--rail-hit);
368 height: var(--rail-strip-h);
369}
370a.railuser:hover { text-decoration: none; }
371/* the phone rail's overflow: every square .railopt hides, and log out,
372 as a labelled list under the rail. Shown only below 34rem. */
373.railmore { display: none; position: relative; }
374.railmore > summary { list-style: none; cursor: pointer; }
375.railmore > summary::-webkit-details-marker { display: none; }
376.railmore[open] > summary { background: var(--shell-hover); }
377.raildrop {
378 position: absolute;
379 top: 100%;
380 right: 0;
381 z-index: 20;
382 min-width: 12rem;
383 padding: var(--sp-1) 0;
384 background: var(--shell-bg);
385 border: 1px solid var(--shell-line);
386 border-radius: var(--r-card);
387 box-shadow: 0 6px 24px rgb(0 0 0 / 0.35);
388}
389.raildrop a, .raildrop button {
390 display: flex;
391 align-items: center;
392 /* a button's own default is centred; the rows read as one list */
393 justify-content: flex-start;
394 gap: var(--sp-3);
395 width: 100%;
396 min-height: var(--rail-hit);
397 padding: 0 var(--sp-4);
398 border: 0;
399 background: none;
400 font: inherit;
401 font-size: var(--fs-2);
402 text-align: left;
403 color: var(--shell-fg);
404 cursor: pointer;
405}
406.raildrop a:hover, .raildrop button:hover { background: var(--shell-hover); text-decoration: none; }
407.raildrop form { margin: 0; }
408.raildrop svg { flex: none; }
409a.railuser .avatar { width: var(--rail-mark); height: var(--rail-mark); }
410.avatar {
411 display: inline-grid;
412 place-items: center;
413 width: 22px; height: 22px;
414 flex: none;
415 border-radius: 50%;
416 background: var(--fill);
417 color: var(--fill-fg);
418 font-size: var(--fs-0);
419 font-weight: 600;
420}
421
422/* ---- shell: the rail above, then the pane, which fills the rest of the
423 viewport so the footer sits at the bottom of a short page ---- */
424.shell { display: flex; flex-direction: column; min-height: 100vh; }
425.pane { flex: 1; min-width: 0; display: flex; flex-direction: column; }
426main.content {
427 flex: 1;
428 width: 100%;
429 padding: var(--sp-5) var(--sp-6) var(--sp-7);
430}
431/* the container is the default width and what `wide` names; reading and
432 bounded follow, so equal specificity gives them the cascade */
433main.content, main.wide, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }
434main.reading { max-width: calc(72rem + 2 * var(--sp-6)); margin: 0 auto; }
435main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); margin: 0 auto; }
436footer {
437 width: 100%;
438 padding: var(--sp-4) var(--sp-6);
439 border-top: 1px solid var(--faint);
440 color: var(--muted);
441 font-size: var(--fs-1);
442}
443footer p { margin: 0; }
444footer a { color: var(--muted); text-decoration: underline; }
445footer a:hover { color: var(--link); }
446
447/* ---- repository header ---- */
448.repohead {
449 padding: var(--sp-4) 0 0;
450 border-bottom: 1px solid var(--line);
451}
452.repohead .wrap { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; padding: 0 var(--sp-6); }
453.identity { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
454.grow { flex: 1; }
455/* h1 on the repo home, p elsewhere so each page keeps its own h1 — but
456 identical in size, because the tabs sit below and navigation must not
457 move when you use it */
458.repotitle {
459 margin: 0;
460 font-size: var(--fs-4);
461 font-weight: 600;
462 line-height: 1.25;
463}
464.repotitle a { color: var(--fg); }
465.repotitle a.owner { color: var(--muted); font-weight: 400; }
466.repotitle a:hover { color: var(--link); text-decoration: none; }
467.repotitle .sep { color: var(--muted); margin: 0 2px; font-weight: 400; }
468.repodesc {
469 margin: 0 0 0 var(--sp-2);
470 color: var(--muted);
471 font-size: var(--fs-2);
472 display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
473 min-width: 0;
474}
475.repodesc a.site { color: var(--muted); }
476.repodesc a.site:hover { color: var(--link); }
477.repometa { margin: var(--sp-1) 0 0; color: var(--muted); font-size: var(--fs-1); }
478
479nav.tabs {
480 display: flex;
481 gap: var(--sp-1);
482 margin-top: var(--sp-3);
483 margin-bottom: var(--sp-4);
484 overflow-x: auto;
485 /* with overflow-y left visible the browser computes it to auto, which
486 is a vertical drag on touch; the strip scrolls sideways only */
487 overflow-y: hidden;
488 scrollbar-width: none;
489}
490nav.tabs::-webkit-scrollbar { display: none; }
491nav.tabs a {
492 display: inline-flex;
493 align-items: center;
494 gap: var(--sp-1);
495 padding: var(--sp-2) var(--sp-3) 10px;
496 color: var(--muted);
497 font-size: var(--fs-2);
498 white-space: nowrap;
499 border-bottom: 2px solid transparent;
500 margin-bottom: -1px;
501}
502nav.tabs a:hover { color: var(--fg); text-decoration: none; }
503nav.tabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); }
504/* the profile strip draws its unlit tabs, so the underline reads as the
505 control rather than appearing only on the one you are already on.
506 --line, not --faint: the track has to be visible to be a track, and
507 at 2px --faint disappears into the canvas in both schemes. */
508nav.tabs.profiletabs a { border-bottom-color: var(--line); }
509nav.tabs.profiletabs a[aria-current] { border-bottom-color: var(--mark); }
510/* a count in a tab is plain metadata, not a badge */
511nav.tabs a i { font-style: normal; color: var(--muted); margin-left: 4px; }
512
513/* ---- page heads ---- */
514.pagehead, .listhead, .headrow {
515 display: flex;
516 align-items: center;
517 gap: var(--sp-3);
518 flex-wrap: wrap;
519 margin-bottom: var(--sp-5);
520}
521/* every child sheds its block margins, or a p.meta beside an h1 centres
522 its text inside a box the margins made taller than the heading's */
523.pagehead h1, .listhead h1, .headrow h1, .listhead h2, .headrow h2 { margin: 0; }
524.pagehead > p, .listhead > p, .headrow > p { margin: 0; }
525.pagehead .grow, .listhead .spacer, .headrow .spacer { flex: 1; }
526.issuetitle { margin: 0 0 var(--sp-2); font-size: var(--fs-5); }
527.issuenumber { color: var(--muted); font-weight: 400; }
528.issuemeta { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-4); }
529.commithead p { margin: var(--sp-1) 0; }
530.commithead h2 { margin-top: 0; margin-bottom: var(--sp-1); }
531
532nav.filters { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
533nav.filters a {
534 display: inline-flex;
535 align-items: center;
536 height: 32px;
537 padding: 0 var(--sp-3);
538 background: var(--canvas);
539 border: 1px solid var(--line);
540 border-radius: var(--r-ctl);
541 color: var(--fg);
542 font-size: var(--fs-2);
543 font-weight: 500;
544}
545nav.filters a:hover { background: var(--hover); text-decoration: none; }
546nav.filters a.active { background: var(--surface); border-color: var(--link); color: var(--link); }
547
548form.searchform, form.logfilter, form.compareform {
549 display: flex;
550 align-items: center;
551 gap: var(--sp-2);
552 flex-wrap: wrap;
553 margin: 0 0 var(--sp-4);
554}
555form.searchform input[type="search"], form.searchform input[type="text"], form.logfilter input { flex: 1; min-width: 12rem; max-width: 32rem; }
556form.searchform.compact { margin: 0; }
557form.searchform.compact input[type="search"], form.searchform.compact input[type="text"] { min-width: 18rem; }
558form.compareform label { display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; }
559
560/* ---- buttons: one family, 32px tall, so a row of them lines up ---- */
561button, .button {
562 display: inline-flex;
563 align-items: center;
564 justify-content: center;
565 gap: 6px;
566 height: 32px;
567 padding: 0 var(--sp-3);
568 font: inherit;
569 font-size: var(--fs-2);
570 font-weight: 500;
571 border: 1px solid transparent;
572 border-radius: var(--r-ctl);
573 cursor: pointer;
574 text-decoration: none;
575 white-space: nowrap;
576 /* a bare <button> is the primary action of its form group */
577 background: var(--fill);
578 color: var(--fill-fg);
579}
580button:hover, .button.primary:hover { filter: brightness(1.12); text-decoration: none; }
581button.btn, .button.btn {
582 background: var(--canvas);
583 color: var(--fg);
584 border-color: var(--line);
585 filter: none;
586}
587button.btn:hover, .button.btn:hover { background: var(--hover); filter: none; text-decoration: none; }
588button.btn[aria-pressed="true"] { background: var(--surface); color: var(--link); border-color: var(--link); }
589button.linklike {
590 background: none;
591 border: 0;
592 padding: 0;
593 height: auto;
594 color: var(--link);
595 font-weight: 400;
596 filter: none;
597}
598button.linklike:hover { text-decoration: underline; filter: none; }
599button.danger, .button.danger {
600 background: var(--canvas);
601 color: var(--bad);
602 border-color: var(--bad);
603 filter: none;
604}
605/* --canvas, not --fill-fg: white on the dark scheme's --bad is 2.3:1 */
606button.danger:hover, .button.danger:hover { background: var(--bad); color: var(--canvas); filter: none; }
607button:disabled { opacity: 0.55; cursor: default; filter: none; }
608.btngroup { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
609form.inline { display: inline; }
610.act { text-align: right; }
611
612/* ---- forms ---- */
613/* not button: it sets its own colour above, and this rule comes later at
614 the same specificity */
615input, textarea, select { font: inherit; color: inherit; }
616input[type="text"], input[type="search"], input[type="email"],
617input[type="password"], input[type="number"], input:not([type]), textarea, select {
618 background: var(--inset);
619 color: var(--fg);
620 border: 1px solid var(--line);
621 border-radius: var(--r-ctl);
622 padding: 0 10px;
623 height: 32px;
624 font-size: var(--fs-2);
625 line-height: 1.4;
626}
627textarea {
628 width: 100%;
629 height: auto;
630 padding: 8px 10px;
631 resize: vertical;
632 line-height: 1.5;
633}
634textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
635select {
636 appearance: none;
637 padding-right: 1.9rem;
638 background-image: var(--chev);
639 background-repeat: no-repeat;
640 background-position: right 0.6rem center;
641 background-size: 0.62rem;
642 cursor: pointer;
643}
644input:hover, textarea:hover, select:hover { border-color: var(--muted); }
645input[type="radio"] { accent-color: var(--fill); }
646label { display: block; font-weight: 500; font-size: var(--fs-2); margin-bottom: 4px; }
647label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
648label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
649.fieldname { display: block; font-size: var(--fs-2); font-weight: 500; }
650.hint { display: block; color: var(--muted); font-size: var(--fs-1); font-weight: 400; margin: 0 0 6px; }
651.field { margin-bottom: var(--sp-4); }
652.field input[type="text"], .field input[type="email"], .field select { width: 100%; }
653.check { display: flex; align-items: center; gap: var(--sp-2); font-weight: 400; }
654::placeholder { color: var(--muted); opacity: 1; }
655::selection { background: var(--fill); color: var(--fill-fg); }
656/* :user-invalid, not :invalid — a required field is invalid the moment
657 the page loads, and colouring it red before anyone has typed is a
658 scolding, not a hint */
659input:user-invalid, textarea:user-invalid { border-color: var(--bad); }
660input[name="confirm"] { width: auto; margin-right: var(--sp-2); }
661
662/* A radio keeps the native control: a circle takes one answer, a square
663 takes any number, and that shape survives greyscale and colour
664 blindness. The checkbox is drawn so it matches the rest of the family. */
665input[type="checkbox"] {
666 appearance: none;
667 flex: none;
668 width: 16px;
669 height: 16px;
670 margin: 0;
671 /* an empty box has nothing but its border to announce it */
672 border: 1px solid var(--muted);
673 border-radius: var(--r-ctl);
674 background: var(--inset);
675 cursor: pointer;
676}
677input[type="checkbox"]:not(:checked):hover { border-color: var(--fg); }
678input[type="checkbox"]:checked {
679 background: var(--fill);
680 border-color: var(--fill);
681 /* the mark sits on the blue ground, so it is white in both schemes */
682 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");
683 background-repeat: no-repeat;
684 background-position: center;
685 background-size: 11px;
686}
687
688/* a segmented control for a small, mutually exclusive set: real radios
689 underneath, so arrow keys and screen readers behave as they always did */
690fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
691fieldset.segmented legend { padding: 0; margin-bottom: var(--sp-2); color: var(--muted); font-size: var(--fs-2); }
692fieldset.segmented .options { display: inline-flex; }
693fieldset.segmented label { gap: 0; margin: 0; }
694fieldset.segmented input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
695fieldset.segmented span {
696 display: flex;
697 align-items: center;
698 height: 32px;
699 padding: 0 var(--sp-4);
700 border: 1px solid var(--line);
701 font-size: var(--fs-2);
702 cursor: pointer;
703}
704fieldset.segmented label + label span { border-left: 0; }
705fieldset.segmented label:first-child span { border-radius: var(--r-ctl) 0 0 var(--r-ctl); }
706fieldset.segmented label:last-child span { border-radius: 0 var(--r-ctl) var(--r-ctl) 0; }
707fieldset.segmented span:hover { border-color: var(--muted); }
708fieldset.segmented input:checked + span {
709 background: var(--fill);
710 border-color: var(--fill);
711 color: var(--fill-fg);
712 font-weight: 600;
713}
714fieldset.segmented input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
715
716p.branchpick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
717p.branchpick label { color: var(--muted); font-size: var(--fs-2); margin: 0; }
718p.branchpick select { flex: 1 1 12rem; }
719
720form.signupform, form.editform { max-width: 40rem; }
721form.signupform label, form.editform label { margin-bottom: 4px; }
722.editform textarea { width: 100%; }
723.editform input[name="message"] { width: 100%; }
724
725/* A previewed draft, above the textarea it came from. The orange edge is
726 "where you are and what wants you": this is not saved yet. */
727.preview {
728 margin: var(--sp-4) 0;
729 max-width: 48rem;
730 background: var(--surface);
731 border: 1px solid var(--line);
732 border-left: 3px solid var(--mark);
733 border-radius: var(--r-card);
734}
735.preview > .previewmark {
736 margin: 0;
737 padding: var(--sp-2) var(--sp-4);
738 border-bottom: 1px solid var(--line);
739 color: var(--warn);
740 font-size: var(--fs-1);
741}
742.preview > .rendered { padding: var(--sp-3) var(--sp-4); }
743.preview > .rendered > :first-child { margin-top: 0; }
744.preview > .rendered > :last-child { margin-bottom: 0; }
745.preview > .rendered:empty::before { content: "nothing to preview"; color: var(--muted); }
746
747form.commentform { margin: var(--sp-4) 0; max-width: 48rem; }
748form.commentform p:last-child { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: 0; }
749
750details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
751details.editbox > summary {
752 display: inline-flex;
753 align-items: center;
754 height: 32px;
755 padding: 0 var(--sp-3);
756 background: var(--canvas);
757 border: 1px solid var(--line);
758 border-radius: var(--r-ctl);
759 color: var(--fg);
760 font-size: var(--fs-2);
761 font-weight: 500;
762 cursor: pointer;
763 list-style: none;
764}
765details.editbox > summary::-webkit-details-marker { display: none; }
766details.editbox > summary:hover { background: var(--hover); }
767details.editbox[open] > summary { margin-bottom: var(--sp-2); }
768details.editbox input[type="text"] { width: 100%; }
769
770/* ---- settings: one row per control, label then input then its own
771 button. The name stays setform because the templates carry it.
772 The label column takes the slack, so the control and the button ride
773 the right edge: a checkbox, a number and a full-width text input all
774 end on the same rule instead of the narrow ones stranding left. Its
775 14rem floor is what keeps a hint from wrapping a word to a line once
776 the control column claims its 28rem. ---- */
777form.setform {
778 display: grid;
779 grid-template-columns: minmax(14rem, 1fr) minmax(0, 28rem) auto;
780 gap: var(--sp-4);
781 align-items: start;
782 padding: var(--sp-3) 0;
783 border-bottom: 1px solid var(--faint);
784}
785form.setform label { margin-top: 6px; }
786form.setform .hint { margin: 2px 0 0; }
787form.setform input[type="text"], form.setform select { width: 100%; }
788/* a control narrower than its column is pushed to the column's end,
789 which is where a full-width input's own right edge lands */
790form.setform .check { justify-content: flex-end; }
791form.setform .num { text-align: right; }
792form.setform .num input[type="number"] { width: auto; }
793/* the third column takes the leftover width; the button keeps its own */
794form.setform > button, form.setform > .btngroup { justify-self: start; }
795form.setform.stack { grid-template-columns: 1fr; }
796form.setform.stack textarea, form.setform.stack select { width: 100%; max-width: 48rem; }
797ul.protlist { list-style: none; margin: var(--sp-2) 0; padding: 0; }
798ul.protlist li {
799 display: flex;
800 align-items: center;
801 gap: var(--sp-3);
802 padding: var(--sp-2) 0;
803 border-bottom: 1px solid var(--faint);
804}
805ul.protlist li:last-child { border-bottom: 0; }
806ul.protlist form { margin-left: auto; }
807ul.plain { list-style: none; margin: 0 0 var(--sp-3); padding: 0; }
808ul.plain li { padding: var(--sp-1) 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
809/* the email list: address and badges read left, the controls sit right,
810 so the buttons line up down the list however long an address is */
811ul.plain li > form:first-of-type { margin-left: auto; }
812
813/* ---- messages: .error and .notice are one family. The names stay
814 because e2e tests match class="error". ---- */
815.error, .notice {
816 border-left: 3px solid var(--bad);
817 background: color-mix(in srgb, var(--bad) 6%, transparent);
818 color: var(--fg);
819 border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
820 padding: var(--sp-2) var(--sp-3);
821 margin: 0 0 var(--sp-4);
822 font-size: var(--fs-2);
823}
824.notice { border-left-color: var(--ok); background: color-mix(in srgb, var(--ok) 6%, transparent); }
825.empty-note, .none, .empty, li.empty, td.empty { color: var(--muted); }
826
827/* ---- containers: one recipe for cards, lists and tables ---- */
828.card, ul.list, ul.loglist, ul.repolist, ul.issuelist,
829ul.milestonelist, .readme, .code, article.release, .blame, .teambody {
830 background: var(--surface);
831 border: 1px solid var(--line);
832 border-radius: var(--r-card);
833 overflow: hidden;
834}
835.cardhead {
836 display: flex;
837 align-items: center;
838 gap: var(--sp-3);
839 padding: var(--sp-2) var(--sp-4);
840 border-bottom: 1px solid var(--line);
841 font-size: var(--fs-1);
842 color: var(--muted);
843}
844.cardhead b { color: var(--fg); font-weight: 500; }
845.cardbody { padding: var(--sp-4) var(--sp-5); }
846ul.list { list-style: none; margin: 0 0 var(--sp-4); padding: 0; }
847ul.list li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
848ul.list li:last-child { border-bottom: 0; }
849ul.list li:hover { background: var(--hover); }
850
851table { border-collapse: collapse; width: 100%; font-size: var(--fs-2); }
852th {
853 text-align: left;
854 font-weight: 500;
855 font-size: var(--fs-1);
856 color: var(--muted);
857 padding: 6px var(--sp-4);
858 border-bottom: 1px solid var(--line);
859}
860td { padding: 7px var(--sp-4); border-bottom: 1px solid var(--faint); vertical-align: top; }
861tr:last-child td { border-bottom: 0; }
862tbody tr:hover td { background: var(--hover); }
863/* every header row a template writes, by the class it or its table
864 carries: TestHeaderRowsAreLeftAligned reads these selectors */
865tr.cols th, table.tree th, table.refs th, table.keys th, table.assets th { text-align: left; }
866tr.cols th { background: var(--canvas); }
867/* right-aligned columns keep their header with their values */
868tr.cols th.age, tr.cols th.size { text-align: right; }
869/* wide listings scroll inside their own box; the page never does. The
870 wrapper is the scroller only — the table inside carries the card. */
871.tablewrap { overflow-x: auto; max-width: 100%; }
872
873table.tree, table.refs {
874 background: var(--surface);
875 border: 1px solid var(--line);
876 border-radius: var(--r-card);
877 /* collapsed borders defeat a radius on the table itself */
878 border-collapse: separate;
879 border-spacing: 0;
880 overflow: hidden;
881 margin-bottom: var(--sp-4);
882}
883table.tree tr:last-child td, table.refs tr:last-child td { border-bottom: 0; }
884table.tree tr:hover td, table.refs tr:hover td { background: var(--hover); }
885td.name a { color: var(--fg); }
886td.name a:hover { color: var(--link); }
887table.tree td.name { width: 25%; white-space: nowrap; }
888table.tree td.name.dir a { color: var(--link); }
889/* the glyph stays muted in both rows: it is a shape cue, and colour here
890 goes on carrying what it already carries */
891table.tree td.name svg { color: var(--muted); vertical-align: -0.125em; margin-right: var(--sp-2); }
892table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
893table.tree td.lastcommit {
894 max-width: 0;
895 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
896}
897table.tree td.lastcommit a {
898 color: var(--muted);
899 display: block;
900 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
901}
902table.tree td.lastcommit a:hover { color: var(--link); }
903table.tree th.age, table.tree td.age { width: 20%; }
904td.age, th.age { text-align: right; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; }
905td.size, td.mode { color: var(--muted); white-space: nowrap; }
906table.tree th.size, table.tree td.size { text-align: right; }
907table.refs td.name { width: 100%; }
908table.refs td.sha, td.sha { color: var(--muted); }
909
910/* these tables sit flush with the page text: no outer border, and the
911 header row drops the ground and the left padding */
912table.keys, table.assets { background: none; border: 0; border-radius: 0; }
913table.keys th, table.assets th, table.keys tr.cols th { background: transparent; padding-left: 0; }
914table.keys td { padding-left: 0; }
915table.keys td.act, table.assets td.size { text-align: right; }
916/* a fingerprint or an account row is read across, not down: the cells
917 keep one line each and .tablewrap scrolls what does not fit */
918table.keys.nowrap th, table.keys.nowrap td { white-space: nowrap; }
919/* The account list types a username to confirm, which is longer than
920 the key prefixes the confirm field is sized for elsewhere. */
921table.accounts input[name="confirm"] { width: 11rem; }
922table.accounts form.actions { display: inline-flex; gap: var(--sp-2); margin: 0 var(--sp-2) var(--sp-2) 0; }
923table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
924table.assets { margin-top: var(--sp-2); }
925
926/* the tip commit is the first row of the file table */
927tr.tipbar td {
928 background: var(--surface);
929 padding: var(--sp-3) var(--sp-4);
930 border-bottom: 1px solid var(--line);
931 max-width: 0;
932}
933.tipbar .tip {
934 display: flex;
935 align-items: center;
936 gap: var(--sp-2);
937 flex-wrap: wrap;
938 min-width: 0;
939 font-size: var(--fs-2);
940}
941.tipbar .who { font-weight: 600; }
942.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
943.tipbar .subject:hover { color: var(--link); }
944.tipbar .spacer { flex: 1; }
945.tipbar .age { color: var(--muted); white-space: nowrap; }
946
947.readme { margin-top: var(--sp-5); }
948.readme .cardbody { max-width: 78ch; }
949/* the overview README caps as a card, so prose and code share an edge */
950.overview .readme { max-width: 88ch; }
951/* until every card wraps its body in .cardbody, the rendered block is
952 the body */
953.readme > .rendered { padding: var(--sp-4) var(--sp-5); }
954.code { background: var(--inset); padding: var(--sp-3) var(--sp-4); overflow-x: auto; }
955.code pre { margin: 0; background: transparent !important; border: 0; padding: 0; }
956pre.bigcode, .bigcode {
957 font-family: var(--mono);
958 /* the 404 numeral is a picture of a number, not body type */
959 font-size: 4rem;
960 color: var(--faint);
961 -webkit-text-stroke: 1px var(--line);
962 margin: 0;
963 line-height: 1;
964}
965.notfound { text-align: center; padding: var(--sp-6) 0; }
966.notfound h1 { margin-top: var(--sp-3); }
967
968ul.loglist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
969ul.loglist li {
970 display: flex;
971 align-items: baseline;
972 gap: var(--sp-3);
973 padding: var(--sp-3) var(--sp-4);
974 border-bottom: 1px solid var(--faint);
975}
976ul.loglist li:last-child { border-bottom: 0; }
977ul.loglist li:hover { background: var(--hover); }
978ul.loglist p { margin: 0; }
979ul.loglist .commitmain { flex: 1 1 auto; min-width: 0; }
980ul.loglist .subject a { color: var(--fg); font-weight: 500; }
981ul.loglist .subject a:hover { color: var(--link); }
982ul.loglist .commitside { flex: none; display: flex; gap: var(--sp-2); align-items: center; white-space: nowrap; }
983
984ul.loglist.rows li { align-items: center; padding: var(--sp-2) var(--sp-4); }
985ul.loglist.rows .commitmain { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
986ul.loglist.rows .meta { flex: none; color: var(--muted); font-size: var(--fs-1); white-space: nowrap; }
987
988ul.repolist { list-style: none; margin: var(--sp-3) 0 var(--sp-5); padding: 0; }
989ul.repolist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
990ul.repolist li:last-child { border-bottom: 0; }
991ul.repolist li:hover { background: var(--hover); }
992ul.repolist p { margin: 0; }
993ul.repolist .reponame { font-size: var(--fs-3); }
994ul.repolist .reponame a { color: var(--fg); }
995ul.repolist .reponame a strong { color: var(--link); font-weight: 600; }
996ul.repolist .reponame .sep { color: var(--muted); margin: 0 2px; }
997ul.repolist .desc { margin-top: 2px; }
998ul.repolist .topics, ul.repolist .meta { margin-top: var(--sp-1); }
999
1000ul.repolist.rows li { display: flex; align-items: baseline; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4); }
1001ul.repolist.rows .reponame { flex: none; font-size: var(--fs-2); }
1002ul.repolist.rows .desc { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: var(--fs-2); margin: 0; }
1003ul.repolist.rows .topics, ul.repolist.rows .meta { flex: none; margin: 0; white-space: nowrap; }
1004ul.repolist.rows .meta { font-size: var(--fs-1); }
1005
1006/* pinned repos: a compact wrap of names, no description or meta */
1007ul.pinlist { list-style: none; margin: var(--sp-3) 0 var(--sp-5); padding: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2); }
1008ul.pinlist li {
1009 background: var(--surface);
1010 border: 1px solid var(--line);
1011 border-radius: var(--r-ctl);
1012 padding: var(--sp-1) var(--sp-3);
1013}
1014ul.pinlist li:hover { background: var(--hover); }
1015ul.pinlist li a { color: var(--fg); }
1016ul.pinlist li a:hover { color: var(--link); text-decoration: none; }
1017ul.pinlist .sep { color: var(--muted); margin: 0 2px; }
1018
1019ul.issuelist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1020ul.issuelist li {
1021 display: flex;
1022 align-items: baseline;
1023 gap: var(--sp-3);
1024 padding: var(--sp-3) var(--sp-4);
1025 border-bottom: 1px solid var(--faint);
1026}
1027ul.issuelist li:last-child { border-bottom: 0; }
1028ul.issuelist li:hover { background: var(--hover); }
1029ul.issuelist li.empty { display: block; }
1030ul.issuelist p { margin: 0; }
1031ul.issuelist .issuemain { flex: 1 1 auto; min-width: 0; }
1032ul.issuelist .issueside { display: flex; gap: var(--sp-2); align-items: center; flex: none; }
1033ul.issuelist .title a { color: var(--fg); font-weight: 500; }
1034ul.issuelist .title a:hover { color: var(--link); }
1035
1036/* one-line rows: title, labels, then the meta pushed right. Above 64rem
1037 a list is a table, not prose (desktop layout spec). */
1038ul.issuelist.rows li { align-items: center; padding: var(--sp-2) var(--sp-4); }
1039ul.issuelist.rows .issuemain { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
1040ul.issuelist.rows .title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1041ul.issuelist.rows .title .chip { margin-left: var(--sp-1); }
1042ul.issuelist.rows .meta { flex: none; color: var(--muted); font-size: var(--fs-1); white-space: nowrap; }
1043ul.issuelist.rows .meta .repo { color: var(--fg); }
1044
1045ul.milestonelist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1046ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1047ul.milestonelist li:last-child { border-bottom: 0; }
1048ul.milestonelist li:hover { background: var(--hover); }
1049ul.milestonelist p { margin: 0; }
1050ul.milestonelist .msmain { min-width: 0; }
1051ul.milestonelist .title { font-weight: 500; }
1052.progress {
1053 height: 6px;
1054 max-width: 24rem;
1055 margin-top: var(--sp-2);
1056 background: var(--faint);
1057 border-radius: var(--r-ctl);
1058 overflow: hidden;
1059}
1060.progress .bar { height: 100%; background: var(--ok); }
1061
1062article.release { padding: var(--sp-4); margin: var(--sp-4) 0; }
1063.releasehead { background: none; border: 0; padding: 0; }
1064.releasehead h2 { margin: 0 0 var(--sp-1); font-size: var(--fs-3); }
1065.releasehead .meta { margin: 0 0 var(--sp-2); }
1066
1067ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1068ul.matchlist li { margin-bottom: var(--sp-3); }
1069.matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1070pre.matchline {
1071 background: var(--inset);
1072 border: 1px solid var(--line);
1073 border-radius: var(--r-card);
1074 padding: var(--sp-1) var(--sp-3);
1075 margin: var(--sp-1) 0 0;
1076 overflow-x: auto;
1077}
1078pre.matchline mark { background: color-mix(in srgb, var(--mark) 25%, transparent); color: inherit; border-radius: 2px; }
1079p.pager { margin-top: var(--sp-4); }
1080.snippetfile { margin-bottom: var(--sp-5); }
1081p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1082pre.buildlog { max-height: 40rem; overflow: auto; }
1083
1084/* ---- rendered prose ---- */
1085pre {
1086 background: var(--inset);
1087 border: 1px solid var(--line);
1088 border-radius: var(--r-card);
1089 padding: var(--sp-3) var(--sp-4);
1090 margin: 0 0 var(--sp-4);
1091 overflow-x: auto;
1092 font-size: var(--fs-2);
1093 line-height: 1.6;
1094}
1095code {
1096 background: var(--inset);
1097 border: 1px solid var(--faint);
1098 border-radius: var(--r-ctl);
1099 padding: 0 0.3em;
1100}
1101pre code { background: none; border: 0; padding: 0; font-size: inherit; }
1102code.fullsha { color: var(--muted); overflow-wrap: anywhere; }
1103pre.message {
1104 white-space: pre-wrap;
1105 overflow-wrap: anywhere;
1106}
1107.rendered { max-width: 100%; overflow-wrap: anywhere; }
1108.rendered a { text-decoration: underline; }
1109.prose, .rendered > p, .rendered > ul, .rendered > ol, .rendered > blockquote { max-width: 78ch; }
1110.rendered blockquote { border-left: 3px solid var(--line); margin-left: 0; padding-left: var(--sp-4); color: var(--muted); }
1111.rendered img { max-width: 100%; }
1112.rendered h1, .rendered h2 { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-1); }
1113.rendered table { border-collapse: collapse; margin: var(--sp-3) 0; display: block; max-width: 100%; overflow-x: auto; }
1114.rendered th, .rendered td {
1115 border: 1px solid var(--line);
1116 padding: var(--sp-1) var(--sp-3);
1117 text-align: left;
1118 overflow-wrap: normal; /* scroll the table, don't shatter words */
1119}
1120.rendered th { background: var(--surface); font-weight: 600; }
1121.rendered tr:last-child td { border-bottom: 1px solid var(--line); }
1122/* GFM task lists: the box sits in the line, sized to the prose */
1123.rendered li input[type="checkbox"] { width: 0.9em; height: 0.9em; margin: 0 0.35em 0 0; vertical-align: -0.05em; background-size: 0.7em; }
1124.rendered li:has(> input[type="checkbox"]) { list-style: none; margin-left: -1.2em; }
1125.blobimage { text-align: center; }
1126.blobimage img { max-width: 100%; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--surface); }
1127
1128/* ---- dashboard: pinned column, tiles and queues, feed ---- */
1129.dashgrid { display: grid; grid-template-columns: 15rem minmax(0, 1fr) 20rem; gap: var(--sp-6); align-items: start; }
1130.dashgrid h1 { margin-top: 0; }
1131.dashgrid > aside { position: sticky; top: var(--sp-5); }
1132.dashgrid .dashmain h2 { margin-top: var(--sp-5); }
1133.dashgrid .dashmain .tiles + h2 { margin-top: 0; }
1134.colhead {
1135 margin: 0 0 var(--sp-2);
1136 font-size: var(--fs-0);
1137 font-weight: 500;
1138 letter-spacing: 0.08em;
1139 text-transform: uppercase;
1140 color: var(--muted);
1141}
1142.pins { list-style: none; margin: 0; padding: 0; font-size: var(--fs-2); }
1143.pins li { display: flex; align-items: center; gap: var(--sp-2); padding: 6px 0; border-bottom: 1px solid var(--faint); }
1144.pins li:last-child { border-bottom: 0; }
1145.pins a { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1146.pins a:hover { color: var(--link); }
1147.pins .owner { color: var(--muted); }
1148.pins .n { margin-left: auto; flex: none; display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-1); color: var(--muted); font-variant-numeric: tabular-nums; }
1149.pins .n b { font-weight: 600; color: var(--fg); }
1150.pins .n b.wants { color: var(--warn); }
1151.pins .dot { margin: 0; }
1152/* count tiles: the queues' sizes in one strip; a non-zero count is orange,
1153 what wants you */
1154.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); margin: var(--sp-4) 0 var(--sp-5); }
1155.tile {
1156 display: block;
1157 background: var(--surface);
1158 border: 1px solid var(--line);
1159 border-radius: var(--r-card);
1160 padding: var(--sp-3) var(--sp-4);
1161 color: var(--fg);
1162}
1163a.tile:hover { background: var(--hover); text-decoration: none; }
1164.tile b { display: block; font-size: var(--fs-5); font-weight: 600; line-height: 1.2; }
1165.tile.wants b { color: var(--warn); }
1166.tile span { font-size: var(--fs-1); color: var(--muted); }
1167.feedcol .feedline { font-size: var(--fs-2); margin-bottom: var(--sp-2); }
1168.feedcol .feedline .none { font-size: var(--fs-1); }
1169
1170/* ---- two-column: conversation and aside ---- */
1171.withaside { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--sp-6); align-items: start; }
1172.withaside .mainside { min-width: 0; }
1173aside.aside { font-size: var(--fs-2); }
1174.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1175.aside .grp:first-child { border-top: 0; padding-top: 0; }
1176.aside h2 {
1177 margin: 0 0 var(--sp-2);
1178 font-size: var(--fs-0);
1179 font-weight: 500;
1180 letter-spacing: 0.08em;
1181 text-transform: uppercase;
1182 color: var(--muted);
1183}
1184.aside .row { display: flex; align-items: center; gap: 6px; margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1185.aside .row:last-child { margin-bottom: 0; }
1186/* a row's second line: when it happened, under what it happened to */
1187.aside .row .sub { flex-basis: 100%; padding-left: 14px; color: var(--muted); font-size: var(--fs-1); }
1188.aside .row:has(.sub) { margin-bottom: var(--sp-2); }
1189.aside .none { color: var(--muted); }
1190.dot { display: inline-block; width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--neutral); margin-right: 2px; vertical-align: middle; }
1191.dot.ok { background: var(--ok); }
1192.dot.bad { background: var(--bad); }
1193.dot.pend { background: var(--mark); }
1194.ok { color: var(--ok); }
1195.bad { color: var(--bad); }
1196form.actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
1197form.actions button { flex: 1 1 auto; }
1198form.actions select, form.actions textarea { width: 100%; }
1199.feedline { margin-bottom: var(--sp-2); }
1200
1201/* ---- comments and threads ---- */
1202article.comment {
1203 max-width: 48rem;
1204 border: 1px solid var(--line);
1205 border-radius: var(--r-card);
1206 margin: var(--sp-4) 0;
1207 overflow: hidden;
1208}
1209article.comment .commenthead {
1210 display: flex;
1211 gap: var(--sp-2);
1212 flex-wrap: wrap;
1213 background: var(--surface);
1214 border-bottom: 1px solid var(--line);
1215 padding: var(--sp-2) var(--sp-4);
1216 margin: 0;
1217 font-size: var(--fs-1);
1218 color: var(--muted);
1219}
1220article.comment .commenthead b { color: var(--fg); font-weight: 500; }
1221article.comment .commenthead .when { color: var(--muted); }
1222article.comment .rendered { padding: var(--sp-3) var(--sp-4); }
1223article.comment .rendered > :first-child { margin-top: 0; }
1224article.comment .rendered > :last-child { margin-bottom: 0; }
1225a.authorlink { color: var(--fg); font-weight: 500; }
1226a.authorlink:hover { color: var(--link); }
1227
1228.syscomment {
1229 max-width: 48rem;
1230 color: var(--muted);
1231 font-size: var(--fs-1);
1232 margin: 0 0 var(--sp-4) var(--sp-3);
1233 padding: var(--sp-2) 0 var(--sp-2) var(--sp-4);
1234 border-left: 2px solid var(--faint);
1235}
1236.syscomment p { display: inline; margin: 0; }
1237
1238.thread {
1239 border: 1px solid var(--faint);
1240 border-left: 3px solid var(--link);
1241 border-radius: var(--r-ctl);
1242 padding: var(--sp-2) var(--sp-4);
1243 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1244}
1245.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1246/* an unsubmitted comment is the viewer's own note, not the conversation */
1247.thread.pending { border-left-color: var(--neutral); border-left-style: dashed; }
1248.thread.stale { border-left-color: var(--warn); }
1249.thread.composing { border-left-color: var(--mark); }
1250.thread:target { outline: 2px solid var(--mark); outline-offset: 2px; }
1251.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1252.thread .when { color: var(--muted); }
1253.thread .rendered p { margin: var(--sp-1) 0; }
1254.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1255.thread details.threadreply { margin: var(--sp-2) 0 0; }
1256.thread details.threadreply > summary { color: var(--link); font-size: var(--fs-1); cursor: pointer; }
1257.thread textarea { width: 100%; }
1258.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1259form.threadact { margin: var(--sp-1) 0 0; padding: 0 var(--sp-3) var(--sp-2); }
1260
1261nav.subtabs {
1262 display: flex;
1263 gap: var(--sp-4);
1264 border-bottom: 1px solid var(--line);
1265 margin: 0 0 var(--sp-4);
1266}
1267nav.subtabs a {
1268 display: inline-flex;
1269 align-items: center;
1270 gap: var(--sp-1);
1271 padding: var(--sp-2) 0 10px;
1272 color: var(--muted);
1273 font-size: var(--fs-2);
1274 border-bottom: 2px solid transparent;
1275 margin-bottom: -1px;
1276}
1277nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1278nav.subtabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); }
1279nav.subtabs a i { font-style: normal; color: var(--muted); margin-left: 4px; }
1280
1281/* ---- diffs and code ---- */
1282p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1283p.diffstat .add { color: var(--ok); }
1284p.diffstat .del { color: var(--bad); }
1285
1286details.difffold {
1287 border: 1px solid var(--line);
1288 border-radius: var(--r-card);
1289 margin: 0 0 var(--sp-3);
1290 background: var(--inset);
1291 overflow: hidden;
1292}
1293details.difffold summary {
1294 display: flex;
1295 align-items: baseline;
1296 gap: var(--sp-3);
1297 padding: var(--sp-2) var(--sp-3);
1298 background: var(--surface);
1299 font-size: var(--fs-2);
1300 cursor: pointer;
1301 list-style: none;
1302}
1303details.difffold[open] summary { border-bottom: 1px solid var(--line); }
1304details.difffold summary::-webkit-details-marker { display: none; }
1305/* flex summaries lose the native disclosure marker; draw our own */
1306details.difffold summary::before { content: "\25b8"; color: var(--muted); }
1307details.difffold[open] summary::before { content: "\25be"; }
1308details.difffold summary:hover { background: var(--hover); }
1309details.difffold summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; }
1310details.difffold summary .fpath .was { color: var(--muted); }
1311details.difffold summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; }
1312details.difffold summary .add { color: var(--ok); }
1313details.difffold summary .del { color: var(--bad); }
1314details.difffold > .none { padding: var(--sp-3); margin: 0; }
1315details.difffold .tablewrap { background: none; border: 0; border-radius: 0; }
1316
1317table.difftable {
1318 border-collapse: collapse;
1319 width: 100%;
1320 font-family: var(--mono);
1321 font-size: var(--fs-1);
1322 line-height: 1.5;
1323}
1324table.difftable td { border: 0; padding: 0; vertical-align: top; font-size: inherit; }
1325table.difftable tbody tr:hover td { background: none; }
1326table.difftable td.ln {
1327 width: 1%;
1328 min-width: 2.5rem;
1329 padding: 0 var(--sp-2);
1330 text-align: right;
1331 color: var(--muted);
1332 user-select: none;
1333 border-right: 1px solid var(--line);
1334 white-space: nowrap;
1335}
1336/* not .code: that class carries its own ground, which painted over the
1337 row tints */
1338table.difftable td.src { padding: 0 var(--sp-3); white-space: pre-wrap; overflow-wrap: anywhere; }
1339/* the marker is decoration, so it lives in CSS and stays out of a copied
1340 selection */
1341table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
1342table.difftable tr.del td.src::before { content: "\2212"; color: var(--bad); }
1343table.difftable tr.ctx td.src::before { content: " "; }
1344table.difftable tr.add { background: var(--diff-add); }
1345table.difftable tr.del { background: var(--diff-del); }
1346table.difftable tr.hunk td, table.difftable tr.dmeta td {
1347 color: var(--muted);
1348 padding: var(--sp-1) var(--sp-3);
1349 background: var(--surface);
1350 border-top: 1px solid var(--line);
1351 border-bottom: 1px solid var(--line);
1352}
1353table.difftable tr.hunk td.src { color: var(--link); }
1354table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--canvas); }
1355/* a line number is the handle for commenting on that line; it stays a
1356 plain number until pointed at, so the gutter is not a wall of links */
1357table.difftable td.ln a.cmt { color: inherit; text-decoration: none; }
1358table.difftable td.ln a.cmt:hover,
1359table.difftable td.ln a.cmt:focus { color: var(--link); text-decoration: underline; }
1360/* A linked line: f2-n17 on a diff, L17 on a file (see issue 118). */
1361.difftable tr:target td, .code .line:has(a:target) { background: color-mix(in srgb, var(--mark) 18%, transparent); }
1362.difftable tr:target td.ln, .code .line:has(a:target) .ln { border-left: 3px solid var(--mark); }
1363/* chroma writes the highlighted spans; the container only supplies the
1364 ground and the face */
1365.chroma { font-family: var(--mono); background: none; }
1366/* chroma's own LineLink rule is dropped from the served palette: it set
1367 outline: none and hid the focus ring. This is that rule without it, on
1368 a 24px box so a line number is a target and not a glyph (#232) */
1369.chroma .lnlinks { display: inline-block; min-width: 24px; min-height: 24px; line-height: 24px; text-decoration: none; color: inherit; }
1370.chroma .line { line-height: 24px; }
1371
1372.blamehunk { display: flex; gap: var(--sp-3); border-top: 1px solid var(--line); align-items: flex-start; }
1373.blamehunk:first-child { border-top: 0; }
1374.blameinfo { flex: none; width: 17rem; min-width: 0; padding: var(--sp-2) var(--sp-3); }
1375.blameinfo .subject { margin: 0; font-size: var(--fs-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1376.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1377.blamecode {
1378 flex: 1;
1379 margin: 0;
1380 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1381 background: var(--inset);
1382 border: 0;
1383 border-left: 1px solid var(--line);
1384 border-radius: 0;
1385 overflow-x: auto;
1386 align-self: stretch;
1387}
1388.lineno {
1389 display: inline-block;
1390 min-width: 3.5em;
1391 padding-right: 1em;
1392 text-align: right;
1393 color: var(--muted);
1394 user-select: none;
1395}
1396
1397/* ---- chips and badges ---- */
1398.chip, .badge {
1399 --chip: var(--neutral);
1400 display: inline-block;
1401 padding: 1px 8px;
1402 border-radius: var(--r-ctl);
1403 font-size: var(--fs-0);
1404 font-weight: 500;
1405 line-height: 1.5;
1406 color: var(--chip);
1407 border: 1px solid color-mix(in srgb, var(--chip) 40%, transparent);
1408 background: color-mix(in srgb, var(--chip) 10%, var(--canvas));
1409 white-space: nowrap;
1410 vertical-align: middle;
1411}
1412.chip-open { --chip: var(--ok); }
1413.chip-closed { --chip: var(--bad); }
1414.chip-merged, .chip-done { --chip: var(--done); }
1415.chip-neutral, .chip-source_gone { --chip: var(--neutral); }
1416.chip-stale { --chip: var(--warn); }
1417.chip.topic { --chip: var(--link); }
1418.chip.topic:hover { text-decoration: none; background: color-mix(in srgb, var(--chip) 18%, transparent); }
1419/* A label carries its own colour inline, from the label's hex, as one
1420 tone per scheme: chip text is 12px, so it needs 4.5:1 against its own
1421 ground, and no single colour clears that on both canvases (#226). An
1422 old browser without light-dark() drops the declaration and the chip
1423 falls back to the neutral above. */
1424.chip.label {
1425 --chip: light-dark(var(--chip-l, var(--neutral)), var(--chip-d, var(--neutral)));
1426 font-weight: 500;
1427}
1428.badge-verified { --chip: var(--ok); }
1429.badge-unsigned { --chip: var(--neutral); }
1430.badge-signed_unknown_key, .badge-signed_key_expired { --chip: var(--warn); }
1431.badge-signed_email_mismatch, .badge-signed_key_revoked, .badge-bad_signature { --chip: var(--bad); }
1432.badge.check-success, .chip.check-success { --chip: var(--ok); }
1433.badge.check-pending, .chip.check-pending,
1434.badge.check-running, .chip.check-running { --chip: var(--warn); }
1435.badge.check-failure, .chip.check-failure,
1436.badge.check-error, .chip.check-error { --chip: var(--bad); }
1437.badge.check-cancelled, .chip.check-cancelled,
1438.badge.check-skipped, .chip.check-skipped { --chip: var(--neutral); }
1439span.check-success { color: var(--ok); }
1440span.check-pending, span.check-running { color: var(--warn); }
1441span.check-failure, span.check-error { color: var(--bad); }
1442
1443a.memberchip {
1444 display: inline-block;
1445 border: 1px solid var(--line);
1446 border-radius: var(--r-ctl);
1447 padding: 1px 8px;
1448 margin: 0 2px 2px 0;
1449 color: var(--fg);
1450 font-size: var(--fs-1);
1451}
1452a.memberchip:hover { text-decoration: none; border-color: var(--link); color: var(--link); }
1453a.memberchip .role { color: var(--muted); }
1454
1455.pathbar { display: flex; align-items: center; gap: var(--sp-2) var(--sp-3); margin: 0 0 var(--sp-3); flex-wrap: wrap; font-size: var(--fs-2); }
1456.pathbar .spacer { flex: 1; }
1457.pathbar .actions { display: flex; align-items: center; gap: var(--sp-2); }
1458/* history · blame · raw were 21px tall and "raw" 22px wide (#232) */
1459.pathbar .actions a { display: inline-block; padding: 6px 4px; }
1460.pathbar .acts { display: flex; gap: var(--sp-2); }
1461.crumbs { color: var(--muted); }
1462.crumbs a { color: var(--link); }
1463.crumbs strong { color: var(--fg); }
1464
1465/* ---- file navigator: the directory beside a file ---- */
1466.blobgrid { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: var(--sp-6); align-items: start; }
1467.blobmain { min-width: 0; }
1468.filenav { position: sticky; top: var(--sp-4); font-size: var(--fs-2); }
1469.filenav ul { list-style: none; margin: 0; padding: 0; }
1470.filenav li a {
1471 display: block;
1472 padding: 3px var(--sp-2);
1473 border-radius: var(--r-ctl);
1474 color: var(--fg);
1475 font-family: var(--mono);
1476 font-size: var(--fs-1);
1477 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1478}
1479.filenav li a:hover { background: var(--hover); text-decoration: none; }
1480.filenav li a[aria-current] { background: var(--surface); box-shadow: inset 2px 0 0 var(--mark); font-weight: 600; }
1481.filenav li a.dir { color: var(--link); }
1482.filenav li a.up { color: var(--muted); }
1483
1484/* ---- side column: facets or sections beside a list or a form ---- */
1485.withcol { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: var(--sp-6); align-items: start; }
1486.withcol.narrow { grid-template-columns: 15rem minmax(0, 56rem); }
1487.colmain { min-width: 0; }
1488.sidecol { position: sticky; top: var(--sp-4); font-size: var(--fs-2); }
1489.sidecol .grp { margin-bottom: var(--sp-4); }
1490.sidecol ul { list-style: none; margin: 0; padding: 0; }
1491.sidecol li a {
1492 display: flex; align-items: baseline; gap: var(--sp-2);
1493 padding: 4px var(--sp-2);
1494 border-radius: var(--r-ctl);
1495 color: var(--fg);
1496}
1497.sidecol li a:hover { background: var(--hover); text-decoration: none; }
1498.sidecol li a[aria-current] { background: var(--surface); box-shadow: inset 2px 0 0 var(--mark); font-weight: 500; }
1499.sidecol li a i { margin-left: auto; font-style: normal; color: var(--muted); font-size: var(--fs-1); font-variant-numeric: tabular-nums; }
1500.sidecol form.searchform { margin-top: var(--sp-2); }
1501.sidecol form.searchform input[type="text"] { min-width: 0; width: 100%; }
1502
1503/* The column's groups sit in a disclosure. Below 62rem that is all the
1504 reader sees of the column: one closed line before the list, because a
1505 repository with two dozen labels stacked the whole vocabulary under
1506 the content it filters. Above 62rem the summary is hidden and the
1507 content shown whatever the open state, so the column is what it
1508 always was. The @supports guard is the fail-safe: an engine without
1509 ::details-content keeps a working toggle at every width instead of
1510 losing the column (#237). */
1511.sidedrop > summary {
1512 display: inline-flex;
1513 align-items: center;
1514 gap: var(--sp-2);
1515 height: 32px;
1516 padding: 0 var(--sp-3);
1517 background: var(--canvas);
1518 border: 1px solid var(--line);
1519 border-radius: var(--r-ctl);
1520 color: var(--fg);
1521 font-size: var(--fs-2);
1522 cursor: pointer;
1523 list-style: none;
1524}
1525.sidedrop[open] > summary { margin-bottom: var(--sp-3); }
1526.sidedrop > summary::-webkit-details-marker { display: none; }
1527.sidedrop > summary:hover { background: var(--hover); }
1528.sidedrop > summary::after { content: "\25be"; color: var(--muted); }
1529.sidedrop[open] > summary::after { content: "\25b4"; }
1530.sideword { font-weight: 600; }
1531/* the filters in force: where you are */
1532.sideon { color: var(--warn); }
1533/* every group came out empty, so there is nothing to open */
1534.sidedrop:not(:has(.grp)) { display: none; }
1535
1536@media (min-width: 62.01rem) {
1537 @supports selector(::details-content) {
1538 .sidedrop > summary { display: none; }
1539 .sidedrop::details-content { content-visibility: visible; }
1540 }
1541}
1542
1543/* a sticky column taller than the viewport scrolls inside itself, or its
1544 tail is unreachable once the page scrolls. Above 62rem only: below it
1545 .filenav is hidden and the other two are static. .dashpins stops being
1546 a column at 80rem and resets both properties there. */
1547@media (min-width: 62.01rem) {
1548 .filenav, .sidecol, .dashgrid > aside { max-height: calc(100vh - 2 * var(--sp-4)); overflow-y: auto; }
1549}
1550
1551.refchip {
1552 display: inline-flex;
1553 align-items: center;
1554 gap: 6px;
1555 height: 32px;
1556 padding: 0 10px;
1557 background: var(--canvas);
1558 border: 1px solid var(--line);
1559 border-radius: var(--r-ctl);
1560 font-family: var(--mono);
1561 font-size: var(--fs-2);
1562 font-weight: 500;
1563 color: var(--fg);
1564}
1565details.refmenu { position: relative; }
1566details.refmenu summary { cursor: pointer; list-style: none; }
1567details.refmenu summary::-webkit-details-marker { display: none; }
1568details.refmenu summary::after { content: " \25be"; color: var(--muted); }
1569details.refmenu .refdrop {
1570 position: absolute;
1571 z-index: 10;
1572 top: calc(100% + 4px);
1573 left: 0;
1574 min-width: 12rem;
1575 max-height: 20rem;
1576 overflow-y: auto;
1577 background: var(--canvas);
1578 border: 1px solid var(--line);
1579 border-radius: var(--r-card);
1580 box-shadow: var(--shadow);
1581 padding: var(--sp-1) 0;
1582}
1583details.refmenu .refdrop a {
1584 display: block;
1585 padding: var(--sp-1) var(--sp-3);
1586 color: var(--fg);
1587 font-family: var(--mono);
1588 font-size: var(--fs-1);
1589}
1590details.refmenu .refdrop a:hover { background: var(--hover); text-decoration: none; }
1591details.refmenu .refdrop a.allrefs {
1592 color: var(--link);
1593 font-family: var(--sans);
1594 border-top: 1px solid var(--faint);
1595 margin-top: var(--sp-1);
1596}
1597
1598/* ---- repository overview layout ---- */
1599.overview { display: block; }
1600.overviewmain { min-width: 0; }
1601/* the side column exists only above 62rem; below it .facts keeps its
1602 own two-up layout and the 40rem factgrid rule applies untouched */
1603@media (min-width: 62.01rem) {
1604 .overview.withfacts { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--sp-6); align-items: start; }
1605 .overview.withfacts .facts { display: block; margin-top: 0; max-width: none; }
1606 .overview.withfacts .facts .factgrid { grid-template-columns: repeat(2, auto); }
1607 .overview.withfacts .clone pre { white-space: pre-wrap; word-break: break-all; }
1608}
1609
1610/* ---- repository facts ---- */
1611.facts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); margin: var(--sp-5) 0 var(--sp-4); max-width: 72rem; }
1612.facts h2 {
1613 margin: 0 0 var(--sp-2);
1614 font-size: var(--fs-1);
1615 font-weight: 500;
1616 letter-spacing: 0.08em;
1617 text-transform: uppercase;
1618 color: var(--muted);
1619}
1620.clone { margin: 0 0 var(--sp-3); }
1621.facts .about { min-width: 0; margin-bottom: var(--sp-5); }
1622.clone .fieldname { font-size: var(--fs-1); color: var(--muted); font-weight: 500; margin-bottom: 2px; }
1623.clone pre { margin-bottom: var(--sp-3); user-select: all; }
1624.factgrid { display: grid; grid-template-columns: repeat(4, auto); gap: var(--sp-2) var(--sp-4); font-size: var(--fs-2); margin-bottom: var(--sp-3); }
1625.factgrid b { font-weight: 600; }
1626.factgrid a { color: var(--fg); }
1627.factgrid a:hover { color: var(--link); }
1628.counts { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin: 0 0 var(--sp-3); font-size: var(--fs-2); }
1629.counts a { color: var(--fg); }
1630.counts a:hover { color: var(--link); }
1631.counts strong { font-weight: 600; }
1632.fact { color: var(--muted); }
1633.langbar { display: flex; height: 8px; margin: 0 0 var(--sp-2); border-radius: var(--r-ctl); overflow: hidden; gap: 1px; background: var(--faint); }
1634.langbar .lang { display: block; height: 100%; min-width: 2px; }
1635.langs { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin: 0 0 var(--sp-3); font-size: var(--fs-1); color: var(--muted); }
1636.langs .lang-name { display: inline-flex; align-items: center; gap: var(--sp-1); }
1637.langs .dot { width: 8px; height: 8px; }
1638/* named where it reads as the language's own colour, neutral otherwise */
1639.lang { background: var(--neutral); }
1640.lang-go { background: var(--lang-go); }
1641.lang-rust { background: var(--lang-rust); }
1642.lang-c, .lang-c- { background: var(--lang-c); }
1643.lang-python { background: var(--lang-python); }
1644.lang-javascript { background: var(--lang-javascript); }
1645.lang-typescript { background: var(--lang-typescript); }
1646.lang-shell { background: var(--lang-shell); }
1647.lang-ruby { background: var(--lang-ruby); }
1648.lang-java { background: var(--lang-java); }
1649.lang-swift { background: var(--lang-swift); }
1650.lang-html { background: var(--lang-html); }
1651.lang-css { background: var(--lang-css); }
1652.lang-org { background: var(--lang-org); }
1653.lang-markdown { background: var(--lang-markdown); }
1654.lang-emacs-lisp { background: var(--lang-emacs-lisp); }
1655.lang-nix { background: var(--lang-nix); }
1656.lang-sql { background: var(--lang-sql); }
1657.contribs { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--fs-1); }
1658.contribs .label { color: var(--muted); }
1659.teambody { padding: var(--sp-3); }
1660.teambody .memberchip { margin-right: var(--sp-2); }
1661
1662/* ---- landing ---- */
1663/* the width class on main carries this too; the cap here keeps the page
1664 readable on the templates that do not set one yet */
1665.landing { max-width: 48rem; padding: var(--sp-6) 0; }
1666.landing h1 { font-size: var(--fs-6); display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
1667.landing h1 .mark { width: 32px; height: 32px; }
1668.lede { font-size: var(--fs-4); color: var(--muted); line-height: 1.5; max-width: 40rem; margin: 0 0 var(--sp-5); }
1669pre.quickstart { margin: 0 0 var(--sp-4); }
1670.shot { border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; margin: var(--sp-5) 0; }
1671.shot img { display: block; width: 100%; height: auto; max-height: 420px; object-fit: cover; object-position: top; }
1672.shot figcaption {
1673 border-top: 1px solid var(--line);
1674 background: var(--surface);
1675 padding: var(--sp-2) var(--sp-3);
1676 color: var(--muted);
1677 font-size: var(--fs-1);
1678}
1679.facets { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); margin: var(--sp-5) 0; }
1680.facets h2 { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
1681.facets p { color: var(--muted); font-size: var(--fs-2); margin: 0; }
1682.routes { display: flex; gap: var(--sp-3); align-items: center; margin: var(--sp-4) 0 0; }
1683
1684/* ---- profile ---- */
1685.profilehead { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-4); margin-bottom: var(--sp-4); }
1686.profilehead h1 { margin: 0 0 var(--sp-1); }
1687.profilehead .lede { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
1688.profilehead .meta { margin: var(--sp-1) 0 0; }
1689.activity { margin-bottom: var(--sp-5); }
1690h2 .count { background: none; color: var(--muted); font-weight: 400; font-size: var(--fs-2); margin-left: var(--sp-2); padding: 0; }
1691/* 53 week columns x 7 day rows, tinted with the link blue */
1692.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
1693.actgraph { display: flex; gap: 3px; width: max-content; padding-top: 18px; }
1694.actweek { display: flex; flex-direction: column; gap: 3px; position: relative; }
1695.actmonth { position: absolute; top: -16px; left: 0; font-size: var(--fs-0); color: var(--muted); }
1696.actday { width: 11px; height: 11px; border-radius: 2px; background: var(--faint); }
1697.actday.pad { background: transparent; }
1698.actday.l0 { background: var(--faint); }
1699.actday.l1 { background: color-mix(in srgb, var(--link) 25%, var(--canvas)); }
1700.actday.l2 { background: color-mix(in srgb, var(--link) 50%, var(--canvas)); }
1701.actday.l3 { background: color-mix(in srgb, var(--link) 75%, var(--canvas)); }
1702.actday.l4 { background: var(--link); }
1703.actlegend { display: flex; align-items: center; gap: 3px; margin-top: var(--sp-2); font-size: var(--fs-0); color: var(--muted); }
1704.actlegend span:first-child { margin-right: var(--sp-1); }
1705.actlegend span:last-child { margin-left: var(--sp-1); }
1706/* the activity log under the graph: the newest events, not the year */
1707.logsub { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-2); color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
1708.ownerlog .feedline { font-size: var(--fs-2); }
1709.ownerlog .feedline .none { font-size: var(--fs-1); }
1710
1711/* ---- wiki ---- */
1712.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
1713.wikipage { flex: 1; min-width: 0; }
1714.wikinav { flex: none; width: 15rem; }
1715.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1716.wikinav li a {
1717 display: block;
1718 padding: 5px var(--sp-2);
1719 border-radius: var(--r-ctl);
1720 color: var(--fg);
1721 font-size: var(--fs-2);
1722}
1723.wikinav li a:hover { background: var(--hover); color: var(--fg); text-decoration: none; }
1724.wikinav li a.active { background: var(--surface); color: var(--link); font-weight: 500; }
1725
1726/* ---- misc ---- */
1727.meta { color: var(--muted); font-size: var(--fs-1); }
1728.muted { color: var(--muted); }
1729.desc, td.desc { color: var(--muted); }
1730.spacer { flex: 1; }
1731.compact { margin: 0; }
1732.name { min-width: 0; }
1733svg.icon { vertical-align: -0.125em; }
1734.sep { color: var(--muted); }
1735.owner { color: var(--muted); }
1736.title { margin: 0; }
1737.subject { min-width: 0; }
1738.sha { font-family: var(--mono); }
1739.when { color: var(--muted); }
1740.who { font-weight: 500; }
1741.was { color: var(--muted); }
1742.role { color: var(--muted); }
1743.age { color: var(--muted); }
1744.size { color: var(--muted); }
1745.review { font-size: var(--fs-2); }
1746
1747/* ---- breakpoints ---- */
1748@media (max-width: 80rem) {
1749 .dashgrid { grid-template-columns: minmax(0, 1fr) 20rem; }
1750 /* not a column any more, so it neither sticks nor scrolls in itself */
1751 .dashgrid > .dashpins { grid-column: 1 / -1; position: static; max-height: none; overflow: visible; }
1752 /* a pinned block that is not a column is the chip row (spec rule 7) */
1753 .pins { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
1754 /* the shorthand loses to .pins li:last-child, which drops the bottom
1755 border of the last chip -- and so of the second row */
1756 .pins li, .pins li:last-child { border: 1px solid var(--line); border-radius: var(--r-ctl); padding: var(--sp-1) var(--sp-3); }
1757 .pins .n, .dashpins .meta { display: none; }
1758}
1759
1760@media (max-width: 62rem) {
1761 /* one column, the aside after the thread: a phone shows the
1762 description first, checks and reviewers after it (#232) */
1763 .withaside { grid-template-columns: 1fr; }
1764
1765 /* rows go back to two lines where one does not fit */
1766 ul.issuelist.rows .issuemain, ul.repolist.rows li, ul.loglist.rows .commitmain { display: block; }
1767 ul.issuelist.rows .title, ul.repolist.rows .desc { white-space: normal; }
1768 /* a nowrap meta or topic line on one of these rows forces horizontal
1769 page scroll on a phone: a long branch name, a long owner/repo#N */
1770 ul.issuelist.rows .meta, ul.loglist.rows .meta,
1771 ul.repolist.rows .meta, ul.repolist.rows .topics { white-space: normal; }
1772
1773 .dashgrid { grid-template-columns: 1fr; }
1774 .dashgrid > aside { position: static; }
1775 .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1776
1777 /* the tree page is the navigator on a phone */
1778 .blobgrid { grid-template-columns: 1fr; }
1779 .filenav { display: none; }
1780
1781 /* the column is a closed disclosure before the content: a filter you
1782 reach without scrolling the list, and nothing to scroll past when
1783 you do not want it. It leads rather than follows because it is what
1784 the list is narrowed by, not a note on one row (#237) */
1785 .withcol, .withcol.narrow { grid-template-columns: 1fr; }
1786 .sidecol { position: static; margin-bottom: var(--sp-3); }
1787 .sidecol .grp { display: inline-block; vertical-align: top; margin-right: var(--sp-5); }
1788}
1789
1790@media (max-width: 52rem) {
1791 main.content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
1792 footer { padding: var(--sp-4); }
1793 .repohead { padding: var(--sp-3) 0 0; }
1794 .repohead .wrap { padding: 0 var(--sp-4); }
1795 /* seven tabs do not fit a phone in one row; a hidden scrollbar made the
1796 ones past the edge look absent. Two rows show all of them. */
1797 nav.tabs { flex-wrap: wrap; overflow: visible; }
1798 .facts { grid-template-columns: 1fr; }
1799 /* a phone shows the description under the name, not beside it */
1800 .repodesc { flex-basis: 100%; margin-left: 0; }
1801}
1802
1803@media (max-width: 40rem) {
1804 .facets { grid-template-columns: 1fr; gap: var(--sp-4); }
1805 .wikilayout { flex-direction: column; align-items: stretch; }
1806 .wikinav { width: auto; }
1807 form.setform { grid-template-columns: 1fr; gap: var(--sp-2); }
1808 form.setform label { margin-top: 0; }
1809 /* the commit subject is the widest thing in a file table and the one
1810 column a phone can do without: the tipbar above already names the
1811 latest commit */
1812 table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
1813 table.tree td.mode, table.tree th.mode { display: none; }
1814 /* at 320px a nowrap name plus the age column overran the card by the
1815 cell padding and the card clipped the age; a long name wraps (#232) */
1816 table.tree td.name { white-space: normal; overflow-wrap: anywhere; }
1817 .clone pre { white-space: pre-wrap; word-break: break-all; }
1818 .pathbar { overflow-wrap: anywhere; }
1819 .readme .cardbody, .code { padding: var(--sp-3); }
1820 .thread { margin-left: var(--sp-3); }
1821 .blamehunk { flex-direction: column; gap: 0; }
1822 .blameinfo { width: auto; }
1823 .blamecode { border-left: 0; padding-left: var(--sp-3); width: 100%; }
1824 .factgrid { grid-template-columns: repeat(2, auto); }
1825 ul.loglist li { flex-wrap: wrap; }
1826 ul.loglist .commitside { width: 100%; justify-content: flex-start; }
1827}
1828
1829/* Nine 44px squares and the mark are 440px, so below 34rem the rail
1830 keeps five — dashboard, search, notifications, More, your avatar — and
1831 the More menu holds the rest. Shrinking the squares instead is what
1832 this replaces: 32px was under the target every phone guideline asks
1833 for, and the count only grows. */
1834@media (max-width: 34rem) {
1835 .railopt { display: none; }
1836 .railmore { display: block; }
1837 .railicon svg { width: 20px; height: 20px; }
1838 /* the mark is a link home too, so it is a target like the rest */
1839 a.brand { width: var(--rail-hit); }
1840}