internal/web/static/style.css
1803 lines · 72046 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 overflow-x: auto;
484 /* with overflow-y left visible the browser computes it to auto, which
485 is a vertical drag on touch; the strip scrolls sideways only */
486 overflow-y: hidden;
487 scrollbar-width: none;
488}
489nav.tabs::-webkit-scrollbar { display: none; }
490nav.tabs a {
491 display: inline-flex;
492 align-items: center;
493 gap: var(--sp-1);
494 padding: var(--sp-2) var(--sp-3) 10px;
495 color: var(--muted);
496 font-size: var(--fs-2);
497 white-space: nowrap;
498 border-bottom: 2px solid transparent;
499 margin-bottom: -1px;
500}
501nav.tabs a:hover { color: var(--fg); text-decoration: none; }
502nav.tabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); }
503/* a count in a tab is plain metadata, not a badge */
504nav.tabs a i { font-style: normal; color: var(--muted); margin-left: 4px; }
505
506/* ---- page heads ---- */
507.pagehead, .listhead, .headrow {
508 display: flex;
509 align-items: center;
510 gap: var(--sp-3);
511 flex-wrap: wrap;
512 margin-bottom: var(--sp-5);
513}
514.pagehead h1, .listhead h1, .headrow h1, .listhead h2, .headrow h2 { margin: 0; }
515.pagehead .grow, .listhead .spacer, .headrow .spacer { flex: 1; }
516.issuetitle { margin: 0 0 var(--sp-2); font-size: var(--fs-5); }
517.issuenumber { color: var(--muted); font-weight: 400; }
518.issuemeta { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-4); }
519.commithead p { margin: var(--sp-1) 0; }
520.commithead h2 { margin-top: 0; margin-bottom: var(--sp-1); }
521
522nav.filters { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
523nav.filters a {
524 display: inline-flex;
525 align-items: center;
526 height: 32px;
527 padding: 0 var(--sp-3);
528 background: var(--canvas);
529 border: 1px solid var(--line);
530 border-radius: var(--r-ctl);
531 color: var(--fg);
532 font-size: var(--fs-2);
533 font-weight: 500;
534}
535nav.filters a:hover { background: var(--hover); text-decoration: none; }
536nav.filters a.active { background: var(--surface); border-color: var(--link); color: var(--link); }
537
538form.searchform, form.logfilter, form.compareform {
539 display: flex;
540 align-items: center;
541 gap: var(--sp-2);
542 flex-wrap: wrap;
543 margin: 0 0 var(--sp-4);
544}
545form.searchform input[type="search"], form.searchform input[type="text"], form.logfilter input { flex: 1; min-width: 12rem; max-width: 32rem; }
546form.searchform.compact { margin: 0; }
547form.searchform.compact input[type="search"], form.searchform.compact input[type="text"] { min-width: 18rem; }
548form.compareform label { display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; }
549
550/* ---- buttons: one family, 32px tall, so a row of them lines up ---- */
551button, .button {
552 display: inline-flex;
553 align-items: center;
554 justify-content: center;
555 gap: 6px;
556 height: 32px;
557 padding: 0 var(--sp-3);
558 font: inherit;
559 font-size: var(--fs-2);
560 font-weight: 500;
561 border: 1px solid transparent;
562 border-radius: var(--r-ctl);
563 cursor: pointer;
564 text-decoration: none;
565 white-space: nowrap;
566 /* a bare <button> is the primary action of its form group */
567 background: var(--fill);
568 color: var(--fill-fg);
569}
570button:hover, .button.primary:hover { filter: brightness(1.12); text-decoration: none; }
571button.btn, .button.btn {
572 background: var(--canvas);
573 color: var(--fg);
574 border-color: var(--line);
575 filter: none;
576}
577button.btn:hover, .button.btn:hover { background: var(--hover); filter: none; text-decoration: none; }
578button.btn[aria-pressed="true"] { background: var(--surface); color: var(--link); border-color: var(--link); }
579button.linklike {
580 background: none;
581 border: 0;
582 padding: 0;
583 height: auto;
584 color: var(--link);
585 font-weight: 400;
586 filter: none;
587}
588button.linklike:hover { text-decoration: underline; filter: none; }
589button.danger, .button.danger {
590 background: var(--canvas);
591 color: var(--bad);
592 border-color: var(--bad);
593 filter: none;
594}
595/* --canvas, not --fill-fg: white on the dark scheme's --bad is 2.3:1 */
596button.danger:hover, .button.danger:hover { background: var(--bad); color: var(--canvas); filter: none; }
597button:disabled { opacity: 0.55; cursor: default; filter: none; }
598.btngroup { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
599form.inline { display: inline; }
600.act { text-align: right; }
601
602/* ---- forms ---- */
603/* not button: it sets its own colour above, and this rule comes later at
604 the same specificity */
605input, textarea, select { font: inherit; color: inherit; }
606input[type="text"], input[type="search"], input[type="email"],
607input[type="password"], input[type="number"], input:not([type]), textarea, select {
608 background: var(--inset);
609 color: var(--fg);
610 border: 1px solid var(--line);
611 border-radius: var(--r-ctl);
612 padding: 0 10px;
613 height: 32px;
614 font-size: var(--fs-2);
615 line-height: 1.4;
616}
617textarea {
618 width: 100%;
619 height: auto;
620 padding: 8px 10px;
621 resize: vertical;
622 line-height: 1.5;
623}
624textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
625select {
626 appearance: none;
627 padding-right: 1.9rem;
628 background-image: var(--chev);
629 background-repeat: no-repeat;
630 background-position: right 0.6rem center;
631 background-size: 0.62rem;
632 cursor: pointer;
633}
634input:hover, textarea:hover, select:hover { border-color: var(--muted); }
635input[type="radio"] { accent-color: var(--fill); }
636label { display: block; font-weight: 500; font-size: var(--fs-2); margin-bottom: 4px; }
637label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
638label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
639.fieldname { display: block; font-size: var(--fs-2); font-weight: 500; }
640.hint { display: block; color: var(--muted); font-size: var(--fs-1); font-weight: 400; margin: 0 0 6px; }
641.field { margin-bottom: var(--sp-4); }
642.field input[type="text"], .field input[type="email"], .field select { width: 100%; }
643.check { display: flex; align-items: center; gap: var(--sp-2); font-weight: 400; }
644::placeholder { color: var(--muted); opacity: 1; }
645::selection { background: var(--fill); color: var(--fill-fg); }
646/* :user-invalid, not :invalid — a required field is invalid the moment
647 the page loads, and colouring it red before anyone has typed is a
648 scolding, not a hint */
649input:user-invalid, textarea:user-invalid { border-color: var(--bad); }
650input[name="confirm"] { width: auto; margin-right: var(--sp-2); }
651
652/* A radio keeps the native control: a circle takes one answer, a square
653 takes any number, and that shape survives greyscale and colour
654 blindness. The checkbox is drawn so it matches the rest of the family. */
655input[type="checkbox"] {
656 appearance: none;
657 flex: none;
658 width: 16px;
659 height: 16px;
660 margin: 0;
661 /* an empty box has nothing but its border to announce it */
662 border: 1px solid var(--muted);
663 border-radius: var(--r-ctl);
664 background: var(--inset);
665 cursor: pointer;
666}
667input[type="checkbox"]:not(:checked):hover { border-color: var(--fg); }
668input[type="checkbox"]:checked {
669 background: var(--fill);
670 border-color: var(--fill);
671 /* the mark sits on the blue ground, so it is white in both schemes */
672 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");
673 background-repeat: no-repeat;
674 background-position: center;
675 background-size: 11px;
676}
677
678/* a segmented control for a small, mutually exclusive set: real radios
679 underneath, so arrow keys and screen readers behave as they always did */
680fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
681fieldset.segmented legend { padding: 0; margin-bottom: var(--sp-2); color: var(--muted); font-size: var(--fs-2); }
682fieldset.segmented .options { display: inline-flex; }
683fieldset.segmented label { gap: 0; margin: 0; }
684fieldset.segmented input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
685fieldset.segmented span {
686 display: flex;
687 align-items: center;
688 height: 32px;
689 padding: 0 var(--sp-4);
690 border: 1px solid var(--line);
691 font-size: var(--fs-2);
692 cursor: pointer;
693}
694fieldset.segmented label + label span { border-left: 0; }
695fieldset.segmented label:first-child span { border-radius: var(--r-ctl) 0 0 var(--r-ctl); }
696fieldset.segmented label:last-child span { border-radius: 0 var(--r-ctl) var(--r-ctl) 0; }
697fieldset.segmented span:hover { border-color: var(--muted); }
698fieldset.segmented input:checked + span {
699 background: var(--fill);
700 border-color: var(--fill);
701 color: var(--fill-fg);
702 font-weight: 600;
703}
704fieldset.segmented input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
705
706p.branchpick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
707p.branchpick label { color: var(--muted); font-size: var(--fs-2); margin: 0; }
708p.branchpick select { flex: 1 1 12rem; }
709
710form.signupform, form.editform { max-width: 40rem; }
711form.signupform label, form.editform label { margin-bottom: 4px; }
712.editform textarea { width: 100%; }
713.editform input[name="message"] { width: 100%; }
714
715/* A previewed draft, above the textarea it came from. The orange edge is
716 "where you are and what wants you": this is not saved yet. */
717.preview {
718 margin: var(--sp-4) 0;
719 max-width: 48rem;
720 background: var(--surface);
721 border: 1px solid var(--line);
722 border-left: 3px solid var(--mark);
723 border-radius: var(--r-card);
724}
725.preview > .previewmark {
726 margin: 0;
727 padding: var(--sp-2) var(--sp-4);
728 border-bottom: 1px solid var(--line);
729 color: var(--warn);
730 font-size: var(--fs-1);
731}
732.preview > .rendered { padding: var(--sp-3) var(--sp-4); }
733.preview > .rendered > :first-child { margin-top: 0; }
734.preview > .rendered > :last-child { margin-bottom: 0; }
735.preview > .rendered:empty::before { content: "nothing to preview"; color: var(--muted); }
736
737form.commentform { margin: var(--sp-4) 0; max-width: 48rem; }
738form.commentform p:last-child { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: 0; }
739
740details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
741details.editbox > summary {
742 display: inline-flex;
743 align-items: center;
744 height: 32px;
745 padding: 0 var(--sp-3);
746 background: var(--canvas);
747 border: 1px solid var(--line);
748 border-radius: var(--r-ctl);
749 color: var(--fg);
750 font-size: var(--fs-2);
751 font-weight: 500;
752 cursor: pointer;
753 list-style: none;
754}
755details.editbox > summary::-webkit-details-marker { display: none; }
756details.editbox > summary:hover { background: var(--hover); }
757details.editbox[open] > summary { margin-bottom: var(--sp-2); }
758details.editbox input[type="text"] { width: 100%; }
759
760/* ---- settings: one row per control, label then input then its own
761 button. The name stays setform because the templates carry it. ---- */
762form.setform {
763 display: grid;
764 grid-template-columns: 14rem minmax(0, 28rem) auto;
765 gap: var(--sp-4);
766 align-items: start;
767 padding: var(--sp-3) 0;
768 border-bottom: 1px solid var(--faint);
769}
770form.setform label { margin-top: 6px; }
771form.setform .hint { margin: 2px 0 0; }
772form.setform input[type="text"], form.setform input[type="number"], form.setform select { width: 100%; }
773/* the third column takes the leftover width; the button keeps its own */
774form.setform > button, form.setform > .btngroup { justify-self: start; }
775form.setform.stack { grid-template-columns: 1fr; }
776form.setform.stack textarea, form.setform.stack select { width: 100%; max-width: 48rem; }
777ul.protlist { list-style: none; margin: var(--sp-2) 0; padding: 0; }
778ul.protlist li {
779 display: flex;
780 align-items: center;
781 gap: var(--sp-3);
782 padding: var(--sp-2) 0;
783 border-bottom: 1px solid var(--faint);
784}
785ul.protlist li:last-child { border-bottom: 0; }
786ul.protlist form { margin-left: auto; }
787ul.plain { list-style: none; margin: 0 0 var(--sp-3); padding: 0; }
788ul.plain li { padding: var(--sp-1) 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
789
790/* ---- messages: .error and .notice are one family. The names stay
791 because e2e tests match class="error". ---- */
792.error, .notice {
793 border-left: 3px solid var(--bad);
794 background: color-mix(in srgb, var(--bad) 6%, transparent);
795 color: var(--fg);
796 border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
797 padding: var(--sp-2) var(--sp-3);
798 margin: 0 0 var(--sp-4);
799 font-size: var(--fs-2);
800}
801.notice { border-left-color: var(--ok); background: color-mix(in srgb, var(--ok) 6%, transparent); }
802.empty-note, .none, .empty, li.empty, td.empty { color: var(--muted); }
803
804/* ---- containers: one recipe for cards, lists and tables ---- */
805.card, ul.list, ul.loglist, ul.repolist, ul.issuelist,
806ul.milestonelist, .readme, .code, article.release, .blame, .teambody {
807 background: var(--surface);
808 border: 1px solid var(--line);
809 border-radius: var(--r-card);
810 overflow: hidden;
811}
812.cardhead {
813 display: flex;
814 align-items: center;
815 gap: var(--sp-3);
816 padding: var(--sp-2) var(--sp-4);
817 border-bottom: 1px solid var(--line);
818 font-size: var(--fs-1);
819 color: var(--muted);
820}
821.cardhead b { color: var(--fg); font-weight: 500; }
822.cardbody { padding: var(--sp-4) var(--sp-5); }
823ul.list { list-style: none; margin: 0 0 var(--sp-4); padding: 0; }
824ul.list li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
825ul.list li:last-child { border-bottom: 0; }
826ul.list li:hover { background: var(--hover); }
827
828table { border-collapse: collapse; width: 100%; font-size: var(--fs-2); }
829th {
830 text-align: left;
831 font-weight: 500;
832 font-size: var(--fs-1);
833 color: var(--muted);
834 padding: 6px var(--sp-4);
835 border-bottom: 1px solid var(--line);
836}
837td { padding: 7px var(--sp-4); border-bottom: 1px solid var(--faint); vertical-align: top; }
838tr:last-child td { border-bottom: 0; }
839tbody tr:hover td { background: var(--hover); }
840/* every header row a template writes, by the class it or its table
841 carries: TestHeaderRowsAreLeftAligned reads these selectors */
842tr.cols th, table.tree th, table.refs th, table.keys th, table.assets th { text-align: left; }
843tr.cols th { background: var(--canvas); }
844/* right-aligned columns keep their header with their values */
845tr.cols th.age, tr.cols th.size { text-align: right; }
846/* wide listings scroll inside their own box; the page never does. The
847 wrapper is the scroller only — the table inside carries the card. */
848.tablewrap { overflow-x: auto; max-width: 100%; }
849
850table.tree, table.refs {
851 background: var(--surface);
852 border: 1px solid var(--line);
853 border-radius: var(--r-card);
854 /* collapsed borders defeat a radius on the table itself */
855 border-collapse: separate;
856 border-spacing: 0;
857 overflow: hidden;
858 margin-bottom: var(--sp-4);
859}
860table.tree tr:last-child td, table.refs tr:last-child td { border-bottom: 0; }
861table.tree tr:hover td, table.refs tr:hover td { background: var(--hover); }
862td.name a { color: var(--fg); }
863td.name a:hover { color: var(--link); }
864table.tree td.name { width: 25%; white-space: nowrap; }
865table.tree td.name.dir a { color: var(--link); }
866table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
867table.tree td.lastcommit {
868 max-width: 0;
869 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
870}
871table.tree td.lastcommit a {
872 color: var(--muted);
873 display: block;
874 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
875}
876table.tree td.lastcommit a:hover { color: var(--link); }
877table.tree th.age, table.tree td.age { width: 20%; }
878td.age, th.age { text-align: right; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; }
879td.size, td.mode { color: var(--muted); white-space: nowrap; }
880table.tree th.size, table.tree td.size { text-align: right; }
881table.refs td.name { width: 100%; }
882table.refs td.sha, td.sha { color: var(--muted); }
883
884/* these tables sit flush with the page text: no outer border, and the
885 header row drops the ground and the left padding */
886table.keys, table.assets { background: none; border: 0; border-radius: 0; }
887table.keys th, table.assets th, table.keys tr.cols th { background: transparent; padding-left: 0; }
888table.keys td { padding-left: 0; }
889table.keys td.act, table.assets td.size { text-align: right; }
890/* a fingerprint or an account row is read across, not down: the cells
891 keep one line each and .tablewrap scrolls what does not fit */
892table.keys.nowrap th, table.keys.nowrap td { white-space: nowrap; }
893/* The account list types a username to confirm, which is longer than
894 the key prefixes the confirm field is sized for elsewhere. */
895table.accounts input[name="confirm"] { width: 11rem; }
896table.accounts form.actions { display: inline-flex; gap: var(--sp-2); margin: 0 var(--sp-2) var(--sp-2) 0; }
897table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
898table.assets { margin-top: var(--sp-2); }
899
900/* the tip commit is the first row of the file table */
901tr.tipbar td {
902 background: var(--surface);
903 padding: var(--sp-3) var(--sp-4);
904 border-bottom: 1px solid var(--line);
905 max-width: 0;
906}
907.tipbar .tip {
908 display: flex;
909 align-items: center;
910 gap: var(--sp-2);
911 flex-wrap: wrap;
912 min-width: 0;
913 font-size: var(--fs-2);
914}
915.tipbar .who { font-weight: 600; }
916.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
917.tipbar .subject:hover { color: var(--link); }
918.tipbar .spacer { flex: 1; }
919.tipbar .age { color: var(--muted); white-space: nowrap; }
920
921.readme { margin-top: var(--sp-5); }
922.readme .cardbody { max-width: 78ch; }
923/* the overview README caps as a card, so prose and code share an edge */
924.overview .readme { max-width: 88ch; }
925/* until every card wraps its body in .cardbody, the rendered block is
926 the body */
927.readme > .rendered { padding: var(--sp-4) var(--sp-5); }
928.code { background: var(--inset); padding: var(--sp-3) var(--sp-4); overflow-x: auto; }
929.code pre { margin: 0; background: transparent !important; border: 0; padding: 0; }
930pre.bigcode, .bigcode {
931 font-family: var(--mono);
932 /* the 404 numeral is a picture of a number, not body type */
933 font-size: 4rem;
934 color: var(--faint);
935 -webkit-text-stroke: 1px var(--line);
936 margin: 0;
937 line-height: 1;
938}
939.notfound { text-align: center; padding: var(--sp-6) 0; }
940.notfound h1 { margin-top: var(--sp-3); }
941
942ul.loglist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
943ul.loglist li {
944 display: flex;
945 align-items: baseline;
946 gap: var(--sp-3);
947 padding: var(--sp-3) var(--sp-4);
948 border-bottom: 1px solid var(--faint);
949}
950ul.loglist li:last-child { border-bottom: 0; }
951ul.loglist li:hover { background: var(--hover); }
952ul.loglist p { margin: 0; }
953ul.loglist .commitmain { flex: 1 1 auto; min-width: 0; }
954ul.loglist .subject a { color: var(--fg); font-weight: 500; }
955ul.loglist .subject a:hover { color: var(--link); }
956ul.loglist .commitside { flex: none; display: flex; gap: var(--sp-2); align-items: center; white-space: nowrap; }
957
958ul.loglist.rows li { align-items: center; padding: var(--sp-2) var(--sp-4); }
959ul.loglist.rows .commitmain { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
960ul.loglist.rows .meta { flex: none; color: var(--muted); font-size: var(--fs-1); white-space: nowrap; }
961
962ul.repolist { list-style: none; margin: var(--sp-3) 0 var(--sp-5); padding: 0; }
963ul.repolist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
964ul.repolist li:last-child { border-bottom: 0; }
965ul.repolist li:hover { background: var(--hover); }
966ul.repolist p { margin: 0; }
967ul.repolist .reponame { font-size: var(--fs-3); }
968ul.repolist .reponame a { color: var(--fg); }
969ul.repolist .reponame a strong { color: var(--link); font-weight: 600; }
970ul.repolist .reponame .sep { color: var(--muted); margin: 0 2px; }
971ul.repolist .desc { margin-top: 2px; }
972ul.repolist .topics, ul.repolist .meta { margin-top: var(--sp-1); }
973
974ul.repolist.rows li { display: flex; align-items: baseline; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4); }
975ul.repolist.rows .reponame { flex: none; font-size: var(--fs-2); }
976ul.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; }
977ul.repolist.rows .topics, ul.repolist.rows .meta { flex: none; margin: 0; white-space: nowrap; }
978ul.repolist.rows .meta { font-size: var(--fs-1); }
979
980/* pinned repos: a compact wrap of names, no description or meta */
981ul.pinlist { list-style: none; margin: var(--sp-3) 0 var(--sp-5); padding: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2); }
982ul.pinlist li {
983 background: var(--surface);
984 border: 1px solid var(--line);
985 border-radius: var(--r-ctl);
986 padding: var(--sp-1) var(--sp-3);
987}
988ul.pinlist li:hover { background: var(--hover); }
989ul.pinlist li a { color: var(--fg); }
990ul.pinlist li a:hover { color: var(--link); text-decoration: none; }
991ul.pinlist .sep { color: var(--muted); margin: 0 2px; }
992
993ul.issuelist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
994ul.issuelist li {
995 display: flex;
996 align-items: baseline;
997 gap: var(--sp-3);
998 padding: var(--sp-3) var(--sp-4);
999 border-bottom: 1px solid var(--faint);
1000}
1001ul.issuelist li:last-child { border-bottom: 0; }
1002ul.issuelist li:hover { background: var(--hover); }
1003ul.issuelist li.empty { display: block; }
1004ul.issuelist p { margin: 0; }
1005ul.issuelist .issuemain { flex: 1 1 auto; min-width: 0; }
1006ul.issuelist .issueside { display: flex; gap: var(--sp-2); align-items: center; flex: none; }
1007ul.issuelist .title a { color: var(--fg); font-weight: 500; }
1008ul.issuelist .title a:hover { color: var(--link); }
1009
1010/* one-line rows: title, labels, then the meta pushed right. Above 64rem
1011 a list is a table, not prose (desktop layout spec). */
1012ul.issuelist.rows li { align-items: center; padding: var(--sp-2) var(--sp-4); }
1013ul.issuelist.rows .issuemain { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
1014ul.issuelist.rows .title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1015ul.issuelist.rows .title .chip { margin-left: var(--sp-1); }
1016ul.issuelist.rows .meta { flex: none; color: var(--muted); font-size: var(--fs-1); white-space: nowrap; }
1017ul.issuelist.rows .meta .repo { color: var(--fg); }
1018
1019ul.milestonelist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1020ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1021ul.milestonelist li:last-child { border-bottom: 0; }
1022ul.milestonelist li:hover { background: var(--hover); }
1023ul.milestonelist p { margin: 0; }
1024ul.milestonelist .msmain { min-width: 0; }
1025ul.milestonelist .title { font-weight: 500; }
1026.progress {
1027 height: 6px;
1028 max-width: 24rem;
1029 margin-top: var(--sp-2);
1030 background: var(--faint);
1031 border-radius: var(--r-ctl);
1032 overflow: hidden;
1033}
1034.progress .bar { height: 100%; background: var(--ok); }
1035
1036article.release { padding: var(--sp-4); margin: var(--sp-4) 0; }
1037.releasehead { background: none; border: 0; padding: 0; }
1038.releasehead h2 { margin: 0 0 var(--sp-1); font-size: var(--fs-3); }
1039.releasehead .meta { margin: 0 0 var(--sp-2); }
1040
1041ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1042ul.matchlist li { margin-bottom: var(--sp-3); }
1043.matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1044pre.matchline {
1045 background: var(--inset);
1046 border: 1px solid var(--line);
1047 border-radius: var(--r-card);
1048 padding: var(--sp-1) var(--sp-3);
1049 margin: var(--sp-1) 0 0;
1050 overflow-x: auto;
1051}
1052pre.matchline mark { background: color-mix(in srgb, var(--mark) 25%, transparent); color: inherit; border-radius: 2px; }
1053p.pager { margin-top: var(--sp-4); }
1054.snippetfile { margin-bottom: var(--sp-5); }
1055p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1056pre.buildlog { max-height: 40rem; overflow: auto; }
1057
1058/* ---- rendered prose ---- */
1059pre {
1060 background: var(--inset);
1061 border: 1px solid var(--line);
1062 border-radius: var(--r-card);
1063 padding: var(--sp-3) var(--sp-4);
1064 margin: 0 0 var(--sp-4);
1065 overflow-x: auto;
1066 font-size: var(--fs-2);
1067 line-height: 1.6;
1068}
1069code {
1070 background: var(--inset);
1071 border: 1px solid var(--faint);
1072 border-radius: var(--r-ctl);
1073 padding: 0 0.3em;
1074}
1075pre code { background: none; border: 0; padding: 0; font-size: inherit; }
1076code.fullsha { color: var(--muted); overflow-wrap: anywhere; }
1077pre.message {
1078 white-space: pre-wrap;
1079 overflow-wrap: anywhere;
1080}
1081.rendered { max-width: 100%; overflow-wrap: anywhere; }
1082.rendered a { text-decoration: underline; }
1083.prose, .rendered > p, .rendered > ul, .rendered > ol, .rendered > blockquote { max-width: 78ch; }
1084.rendered blockquote { border-left: 3px solid var(--line); margin-left: 0; padding-left: var(--sp-4); color: var(--muted); }
1085.rendered img { max-width: 100%; }
1086.rendered h1, .rendered h2 { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-1); }
1087.rendered table { border-collapse: collapse; margin: var(--sp-3) 0; display: block; max-width: 100%; overflow-x: auto; }
1088.rendered th, .rendered td {
1089 border: 1px solid var(--line);
1090 padding: var(--sp-1) var(--sp-3);
1091 text-align: left;
1092 overflow-wrap: normal; /* scroll the table, don't shatter words */
1093}
1094.rendered th { background: var(--surface); font-weight: 600; }
1095.rendered tr:last-child td { border-bottom: 1px solid var(--line); }
1096/* GFM task lists: the box sits in the line, sized to the prose */
1097.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; }
1098.rendered li:has(> input[type="checkbox"]) { list-style: none; margin-left: -1.2em; }
1099.blobimage { text-align: center; }
1100.blobimage img { max-width: 100%; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--surface); }
1101
1102/* ---- dashboard: pinned column, tiles and queues, feed ---- */
1103.dashgrid { display: grid; grid-template-columns: 15rem minmax(0, 1fr) 20rem; gap: var(--sp-6); align-items: start; }
1104.dashgrid h1 { margin-top: 0; }
1105.dashgrid > aside { position: sticky; top: var(--sp-5); }
1106.dashgrid .dashmain h2 { margin-top: var(--sp-5); }
1107.dashgrid .dashmain .tiles + h2 { margin-top: 0; }
1108.colhead {
1109 margin: 0 0 var(--sp-2);
1110 font-size: var(--fs-0);
1111 font-weight: 500;
1112 letter-spacing: 0.08em;
1113 text-transform: uppercase;
1114 color: var(--muted);
1115}
1116.pins { list-style: none; margin: 0; padding: 0; font-size: var(--fs-2); }
1117.pins li { display: flex; align-items: center; gap: var(--sp-2); padding: 6px 0; border-bottom: 1px solid var(--faint); }
1118.pins li:last-child { border-bottom: 0; }
1119.pins a { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1120.pins a:hover { color: var(--link); }
1121.pins .owner { color: var(--muted); }
1122.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; }
1123.pins .n b { font-weight: 600; color: var(--fg); }
1124.pins .n b.wants { color: var(--warn); }
1125.pins .dot { margin: 0; }
1126/* count tiles: the queues' sizes in one strip; a non-zero count is orange,
1127 what wants you */
1128.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); margin: var(--sp-4) 0 var(--sp-5); }
1129.tile {
1130 display: block;
1131 background: var(--surface);
1132 border: 1px solid var(--line);
1133 border-radius: var(--r-card);
1134 padding: var(--sp-3) var(--sp-4);
1135 color: var(--fg);
1136}
1137a.tile:hover { background: var(--hover); text-decoration: none; }
1138.tile b { display: block; font-size: var(--fs-5); font-weight: 600; line-height: 1.2; }
1139.tile.wants b { color: var(--warn); }
1140.tile span { font-size: var(--fs-1); color: var(--muted); }
1141.feedcol .feedline { font-size: var(--fs-2); margin-bottom: var(--sp-2); }
1142.feedcol .feedline .none { font-size: var(--fs-1); }
1143
1144/* ---- two-column: conversation and aside ---- */
1145.withaside { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--sp-6); align-items: start; }
1146.withaside .mainside { min-width: 0; }
1147aside.aside { font-size: var(--fs-2); }
1148.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1149.aside .grp:first-child { border-top: 0; padding-top: 0; }
1150.aside h2 {
1151 margin: 0 0 var(--sp-2);
1152 font-size: var(--fs-0);
1153 font-weight: 500;
1154 letter-spacing: 0.08em;
1155 text-transform: uppercase;
1156 color: var(--muted);
1157}
1158.aside .row { display: flex; align-items: center; gap: 6px; margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1159.aside .row:last-child { margin-bottom: 0; }
1160/* a row's second line: when it happened, under what it happened to */
1161.aside .row .sub { flex-basis: 100%; padding-left: 14px; color: var(--muted); font-size: var(--fs-1); }
1162.aside .row:has(.sub) { margin-bottom: var(--sp-2); }
1163.aside .none { color: var(--muted); }
1164.dot { display: inline-block; width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--neutral); margin-right: 2px; vertical-align: middle; }
1165.dot.ok { background: var(--ok); }
1166.dot.bad { background: var(--bad); }
1167.dot.pend { background: var(--mark); }
1168.ok { color: var(--ok); }
1169.bad { color: var(--bad); }
1170form.actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
1171form.actions button { flex: 1 1 auto; }
1172form.actions select, form.actions textarea { width: 100%; }
1173.feedline { margin-bottom: var(--sp-2); }
1174
1175/* ---- comments and threads ---- */
1176article.comment {
1177 max-width: 48rem;
1178 border: 1px solid var(--line);
1179 border-radius: var(--r-card);
1180 margin: var(--sp-4) 0;
1181 overflow: hidden;
1182}
1183article.comment .commenthead {
1184 display: flex;
1185 gap: var(--sp-2);
1186 flex-wrap: wrap;
1187 background: var(--surface);
1188 border-bottom: 1px solid var(--line);
1189 padding: var(--sp-2) var(--sp-4);
1190 margin: 0;
1191 font-size: var(--fs-1);
1192 color: var(--muted);
1193}
1194article.comment .commenthead b { color: var(--fg); font-weight: 500; }
1195article.comment .commenthead .when { color: var(--muted); }
1196article.comment .rendered { padding: var(--sp-3) var(--sp-4); }
1197article.comment .rendered > :first-child { margin-top: 0; }
1198article.comment .rendered > :last-child { margin-bottom: 0; }
1199a.authorlink { color: var(--fg); font-weight: 500; }
1200a.authorlink:hover { color: var(--link); }
1201
1202.syscomment {
1203 max-width: 48rem;
1204 color: var(--muted);
1205 font-size: var(--fs-1);
1206 margin: 0 0 var(--sp-4) var(--sp-3);
1207 padding: var(--sp-2) 0 var(--sp-2) var(--sp-4);
1208 border-left: 2px solid var(--faint);
1209}
1210.syscomment p { display: inline; margin: 0; }
1211
1212.thread {
1213 border: 1px solid var(--faint);
1214 border-left: 3px solid var(--link);
1215 border-radius: var(--r-ctl);
1216 padding: var(--sp-2) var(--sp-4);
1217 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1218}
1219.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1220/* an unsubmitted comment is the viewer's own note, not the conversation */
1221.thread.pending { border-left-color: var(--neutral); border-left-style: dashed; }
1222.thread.stale { border-left-color: var(--warn); }
1223.thread.composing { border-left-color: var(--mark); }
1224.thread:target { outline: 2px solid var(--mark); outline-offset: 2px; }
1225.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1226.thread .when { color: var(--muted); }
1227.thread .rendered p { margin: var(--sp-1) 0; }
1228.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1229.thread details.threadreply { margin: var(--sp-2) 0 0; }
1230.thread details.threadreply > summary { color: var(--link); font-size: var(--fs-1); cursor: pointer; }
1231.thread textarea { width: 100%; }
1232.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1233form.threadact { margin: var(--sp-1) 0 0; padding: 0 var(--sp-3) var(--sp-2); }
1234
1235nav.subtabs {
1236 display: flex;
1237 gap: var(--sp-4);
1238 border-bottom: 1px solid var(--line);
1239 margin: 0 0 var(--sp-4);
1240}
1241nav.subtabs a {
1242 display: inline-flex;
1243 align-items: center;
1244 gap: var(--sp-1);
1245 padding: var(--sp-2) 0 10px;
1246 color: var(--muted);
1247 font-size: var(--fs-2);
1248 border-bottom: 2px solid transparent;
1249 margin-bottom: -1px;
1250}
1251nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1252nav.subtabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); }
1253nav.subtabs a i { font-style: normal; color: var(--muted); margin-left: 4px; }
1254
1255/* ---- diffs and code ---- */
1256p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1257p.diffstat .add { color: var(--ok); }
1258p.diffstat .del { color: var(--bad); }
1259
1260details.difffold {
1261 border: 1px solid var(--line);
1262 border-radius: var(--r-card);
1263 margin: 0 0 var(--sp-3);
1264 background: var(--inset);
1265 overflow: hidden;
1266}
1267details.difffold summary {
1268 display: flex;
1269 align-items: baseline;
1270 gap: var(--sp-3);
1271 padding: var(--sp-2) var(--sp-3);
1272 background: var(--surface);
1273 font-size: var(--fs-2);
1274 cursor: pointer;
1275 list-style: none;
1276}
1277details.difffold[open] summary { border-bottom: 1px solid var(--line); }
1278details.difffold summary::-webkit-details-marker { display: none; }
1279/* flex summaries lose the native disclosure marker; draw our own */
1280details.difffold summary::before { content: "\25b8"; color: var(--muted); }
1281details.difffold[open] summary::before { content: "\25be"; }
1282details.difffold summary:hover { background: var(--hover); }
1283details.difffold summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; }
1284details.difffold summary .fpath .was { color: var(--muted); }
1285details.difffold summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; }
1286details.difffold summary .add { color: var(--ok); }
1287details.difffold summary .del { color: var(--bad); }
1288details.difffold > .none { padding: var(--sp-3); margin: 0; }
1289details.difffold .tablewrap { background: none; border: 0; border-radius: 0; }
1290
1291table.difftable {
1292 border-collapse: collapse;
1293 width: 100%;
1294 font-family: var(--mono);
1295 font-size: var(--fs-1);
1296 line-height: 1.5;
1297}
1298table.difftable td { border: 0; padding: 0; vertical-align: top; font-size: inherit; }
1299table.difftable tbody tr:hover td { background: none; }
1300table.difftable td.ln {
1301 width: 1%;
1302 min-width: 2.5rem;
1303 padding: 0 var(--sp-2);
1304 text-align: right;
1305 color: var(--muted);
1306 user-select: none;
1307 border-right: 1px solid var(--line);
1308 white-space: nowrap;
1309}
1310/* not .code: that class carries its own ground, which painted over the
1311 row tints */
1312table.difftable td.src { padding: 0 var(--sp-3); white-space: pre-wrap; overflow-wrap: anywhere; }
1313/* the marker is decoration, so it lives in CSS and stays out of a copied
1314 selection */
1315table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
1316table.difftable tr.del td.src::before { content: "\2212"; color: var(--bad); }
1317table.difftable tr.ctx td.src::before { content: " "; }
1318table.difftable tr.add { background: var(--diff-add); }
1319table.difftable tr.del { background: var(--diff-del); }
1320table.difftable tr.hunk td, table.difftable tr.dmeta td {
1321 color: var(--muted);
1322 padding: var(--sp-1) var(--sp-3);
1323 background: var(--surface);
1324 border-top: 1px solid var(--line);
1325 border-bottom: 1px solid var(--line);
1326}
1327table.difftable tr.hunk td.src { color: var(--link); }
1328table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--canvas); }
1329/* a line number is the handle for commenting on that line; it stays a
1330 plain number until pointed at, so the gutter is not a wall of links */
1331table.difftable td.ln a.cmt { color: inherit; text-decoration: none; }
1332table.difftable td.ln a.cmt:hover,
1333table.difftable td.ln a.cmt:focus { color: var(--link); text-decoration: underline; }
1334/* A linked line: f2-n17 on a diff, L17 on a file (see issue 118). */
1335.difftable tr:target td, .code .line:has(a:target) { background: color-mix(in srgb, var(--mark) 18%, transparent); }
1336.difftable tr:target td.ln, .code .line:has(a:target) .ln { border-left: 3px solid var(--mark); }
1337/* chroma writes the highlighted spans; the container only supplies the
1338 ground and the face */
1339.chroma { font-family: var(--mono); background: none; }
1340/* chroma's own LineLink rule is dropped from the served palette: it set
1341 outline: none and hid the focus ring. This is that rule without it, on
1342 a 24px box so a line number is a target and not a glyph (#232) */
1343.chroma .lnlinks { display: inline-block; min-width: 24px; min-height: 24px; line-height: 24px; text-decoration: none; color: inherit; }
1344.chroma .line { line-height: 24px; }
1345
1346.blamehunk { display: flex; gap: var(--sp-3); border-top: 1px solid var(--line); align-items: flex-start; }
1347.blamehunk:first-child { border-top: 0; }
1348.blameinfo { flex: none; width: 17rem; min-width: 0; padding: var(--sp-2) var(--sp-3); }
1349.blameinfo .subject { margin: 0; font-size: var(--fs-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1350.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1351.blamecode {
1352 flex: 1;
1353 margin: 0;
1354 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1355 background: var(--inset);
1356 border: 0;
1357 border-left: 1px solid var(--line);
1358 border-radius: 0;
1359 overflow-x: auto;
1360 align-self: stretch;
1361}
1362.lineno {
1363 display: inline-block;
1364 min-width: 3.5em;
1365 padding-right: 1em;
1366 text-align: right;
1367 color: var(--muted);
1368 user-select: none;
1369}
1370
1371/* ---- chips and badges ---- */
1372.chip, .badge {
1373 --chip: var(--neutral);
1374 display: inline-block;
1375 padding: 1px 8px;
1376 border-radius: var(--r-ctl);
1377 font-size: var(--fs-0);
1378 font-weight: 500;
1379 line-height: 1.5;
1380 color: var(--chip);
1381 border: 1px solid color-mix(in srgb, var(--chip) 40%, transparent);
1382 background: color-mix(in srgb, var(--chip) 10%, var(--canvas));
1383 white-space: nowrap;
1384 vertical-align: middle;
1385}
1386.chip-open { --chip: var(--ok); }
1387.chip-closed { --chip: var(--bad); }
1388.chip-merged, .chip-done { --chip: var(--done); }
1389.chip-neutral, .chip-source_gone { --chip: var(--neutral); }
1390.chip-stale { --chip: var(--warn); }
1391.chip.topic { --chip: var(--link); }
1392.chip.topic:hover { text-decoration: none; background: color-mix(in srgb, var(--chip) 18%, transparent); }
1393/* A label carries its own colour inline, from the label's hex, as one
1394 tone per scheme: chip text is 12px, so it needs 4.5:1 against its own
1395 ground, and no single colour clears that on both canvases (#226). An
1396 old browser without light-dark() drops the declaration and the chip
1397 falls back to the neutral above. */
1398.chip.label {
1399 --chip: light-dark(var(--chip-l, var(--neutral)), var(--chip-d, var(--neutral)));
1400 font-weight: 500;
1401}
1402.badge-verified { --chip: var(--ok); }
1403.badge-unsigned { --chip: var(--neutral); }
1404.badge-signed_unknown_key, .badge-signed_key_expired { --chip: var(--warn); }
1405.badge-signed_email_mismatch, .badge-signed_key_revoked, .badge-bad_signature { --chip: var(--bad); }
1406.badge.check-success, .chip.check-success { --chip: var(--ok); }
1407.badge.check-pending, .chip.check-pending,
1408.badge.check-running, .chip.check-running { --chip: var(--warn); }
1409.badge.check-failure, .chip.check-failure,
1410.badge.check-error, .chip.check-error { --chip: var(--bad); }
1411.badge.check-cancelled, .chip.check-cancelled,
1412.badge.check-skipped, .chip.check-skipped { --chip: var(--neutral); }
1413span.check-success { color: var(--ok); }
1414span.check-pending, span.check-running { color: var(--warn); }
1415span.check-failure, span.check-error { color: var(--bad); }
1416
1417a.memberchip {
1418 display: inline-block;
1419 border: 1px solid var(--line);
1420 border-radius: var(--r-ctl);
1421 padding: 1px 8px;
1422 margin: 0 2px 2px 0;
1423 color: var(--fg);
1424 font-size: var(--fs-1);
1425}
1426a.memberchip:hover { text-decoration: none; border-color: var(--link); color: var(--link); }
1427a.memberchip .role { color: var(--muted); }
1428
1429.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); }
1430.pathbar .spacer { flex: 1; }
1431.pathbar .actions { display: flex; align-items: center; gap: var(--sp-2); }
1432/* history · blame · raw were 21px tall and "raw" 22px wide (#232) */
1433.pathbar .actions a { display: inline-block; padding: 6px 4px; }
1434.pathbar .acts { display: flex; gap: var(--sp-2); }
1435.crumbs { color: var(--muted); }
1436.crumbs a { color: var(--link); }
1437.crumbs strong { color: var(--fg); }
1438
1439/* ---- file navigator: the directory beside a file ---- */
1440.blobgrid { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: var(--sp-6); align-items: start; }
1441.blobmain { min-width: 0; }
1442.filenav { position: sticky; top: var(--sp-4); font-size: var(--fs-2); }
1443.filenav ul { list-style: none; margin: 0; padding: 0; }
1444.filenav li a {
1445 display: block;
1446 padding: 3px var(--sp-2);
1447 border-radius: var(--r-ctl);
1448 color: var(--fg);
1449 font-family: var(--mono);
1450 font-size: var(--fs-1);
1451 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1452}
1453.filenav li a:hover { background: var(--hover); text-decoration: none; }
1454.filenav li a[aria-current] { background: var(--surface); box-shadow: inset 2px 0 0 var(--mark); font-weight: 600; }
1455.filenav li a.dir { color: var(--link); }
1456.filenav li a.up { color: var(--muted); }
1457
1458/* ---- side column: facets or sections beside a list or a form ---- */
1459.withcol { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: var(--sp-6); align-items: start; }
1460.withcol.narrow { grid-template-columns: 15rem minmax(0, 56rem); }
1461.colmain { min-width: 0; }
1462.sidecol { position: sticky; top: var(--sp-4); font-size: var(--fs-2); }
1463.sidecol .grp { margin-bottom: var(--sp-4); }
1464.sidecol ul { list-style: none; margin: 0; padding: 0; }
1465.sidecol li a {
1466 display: flex; align-items: baseline; gap: var(--sp-2);
1467 padding: 4px var(--sp-2);
1468 border-radius: var(--r-ctl);
1469 color: var(--fg);
1470}
1471.sidecol li a:hover { background: var(--hover); text-decoration: none; }
1472.sidecol li a[aria-current] { background: var(--surface); box-shadow: inset 2px 0 0 var(--mark); font-weight: 500; }
1473.sidecol li a i { margin-left: auto; font-style: normal; color: var(--muted); font-size: var(--fs-1); font-variant-numeric: tabular-nums; }
1474.sidecol form.searchform { margin-top: var(--sp-2); }
1475.sidecol form.searchform input[type="text"] { min-width: 0; width: 100%; }
1476
1477/* The column's groups sit in a disclosure. Below 62rem that is all the
1478 reader sees of the column: one closed line before the list, because a
1479 repository with two dozen labels stacked the whole vocabulary under
1480 the content it filters. Above 62rem the summary is hidden and the
1481 content shown whatever the open state, so the column is what it
1482 always was. The @supports guard is the fail-safe: an engine without
1483 ::details-content keeps a working toggle at every width instead of
1484 losing the column (#237). */
1485.sidedrop > summary {
1486 display: inline-flex;
1487 align-items: center;
1488 gap: var(--sp-2);
1489 height: 32px;
1490 padding: 0 var(--sp-3);
1491 background: var(--canvas);
1492 border: 1px solid var(--line);
1493 border-radius: var(--r-ctl);
1494 color: var(--fg);
1495 font-size: var(--fs-2);
1496 cursor: pointer;
1497 list-style: none;
1498}
1499.sidedrop[open] > summary { margin-bottom: var(--sp-3); }
1500.sidedrop > summary::-webkit-details-marker { display: none; }
1501.sidedrop > summary:hover { background: var(--hover); }
1502.sidedrop > summary::after { content: "\25be"; color: var(--muted); }
1503.sidedrop[open] > summary::after { content: "\25b4"; }
1504.sideword { font-weight: 600; }
1505/* the filters in force: where you are */
1506.sideon { color: var(--warn); }
1507/* every group came out empty, so there is nothing to open */
1508.sidedrop:not(:has(.grp)) { display: none; }
1509
1510@media (min-width: 62.01rem) {
1511 @supports selector(::details-content) {
1512 .sidedrop > summary { display: none; }
1513 .sidedrop::details-content { content-visibility: visible; }
1514 }
1515}
1516
1517/* a sticky column taller than the viewport scrolls inside itself, or its
1518 tail is unreachable once the page scrolls. Above 62rem only: below it
1519 .filenav is hidden and the other two are static. .dashpins stops being
1520 a column at 80rem and resets both properties there. */
1521@media (min-width: 62.01rem) {
1522 .filenav, .sidecol, .dashgrid > aside { max-height: calc(100vh - 2 * var(--sp-4)); overflow-y: auto; }
1523}
1524
1525.refchip {
1526 display: inline-flex;
1527 align-items: center;
1528 gap: 6px;
1529 height: 32px;
1530 padding: 0 10px;
1531 background: var(--canvas);
1532 border: 1px solid var(--line);
1533 border-radius: var(--r-ctl);
1534 font-family: var(--mono);
1535 font-size: var(--fs-2);
1536 font-weight: 500;
1537 color: var(--fg);
1538}
1539details.refmenu { position: relative; }
1540details.refmenu summary { cursor: pointer; list-style: none; }
1541details.refmenu summary::-webkit-details-marker { display: none; }
1542details.refmenu summary::after { content: " \25be"; color: var(--muted); }
1543details.refmenu .refdrop {
1544 position: absolute;
1545 z-index: 10;
1546 top: calc(100% + 4px);
1547 left: 0;
1548 min-width: 12rem;
1549 max-height: 20rem;
1550 overflow-y: auto;
1551 background: var(--canvas);
1552 border: 1px solid var(--line);
1553 border-radius: var(--r-card);
1554 box-shadow: var(--shadow);
1555 padding: var(--sp-1) 0;
1556}
1557details.refmenu .refdrop a {
1558 display: block;
1559 padding: var(--sp-1) var(--sp-3);
1560 color: var(--fg);
1561 font-family: var(--mono);
1562 font-size: var(--fs-1);
1563}
1564details.refmenu .refdrop a:hover { background: var(--hover); text-decoration: none; }
1565details.refmenu .refdrop a.allrefs {
1566 color: var(--link);
1567 font-family: var(--sans);
1568 border-top: 1px solid var(--faint);
1569 margin-top: var(--sp-1);
1570}
1571
1572/* ---- repository overview layout ---- */
1573.overview { display: block; }
1574.overviewmain { min-width: 0; }
1575/* the side column exists only above 62rem; below it .facts keeps its
1576 own two-up layout and the 40rem factgrid rule applies untouched */
1577@media (min-width: 62.01rem) {
1578 .overview.withfacts { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--sp-6); align-items: start; }
1579 .overview.withfacts .facts { display: block; margin-top: 0; max-width: none; }
1580 .overview.withfacts .facts .factgrid { grid-template-columns: repeat(2, auto); }
1581 .overview.withfacts .clone pre { white-space: pre-wrap; word-break: break-all; }
1582}
1583
1584/* ---- repository facts ---- */
1585.facts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); margin: var(--sp-5) 0 var(--sp-4); max-width: 72rem; }
1586.facts h2 {
1587 margin: 0 0 var(--sp-2);
1588 font-size: var(--fs-1);
1589 font-weight: 500;
1590 letter-spacing: 0.08em;
1591 text-transform: uppercase;
1592 color: var(--muted);
1593}
1594.clone { margin: 0 0 var(--sp-3); }
1595.facts .about { min-width: 0; margin-bottom: var(--sp-5); }
1596.clone .fieldname { font-size: var(--fs-1); color: var(--muted); font-weight: 500; margin-bottom: 2px; }
1597.clone pre { margin-bottom: var(--sp-3); user-select: all; }
1598.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); }
1599.factgrid b { font-weight: 600; }
1600.factgrid a { color: var(--fg); }
1601.factgrid a:hover { color: var(--link); }
1602.counts { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin: 0 0 var(--sp-3); font-size: var(--fs-2); }
1603.counts a { color: var(--fg); }
1604.counts a:hover { color: var(--link); }
1605.counts strong { font-weight: 600; }
1606.fact { color: var(--muted); }
1607.langbar { display: flex; height: 8px; margin: 0 0 var(--sp-2); border-radius: var(--r-ctl); overflow: hidden; gap: 1px; background: var(--faint); }
1608.langbar .lang { display: block; height: 100%; min-width: 2px; }
1609.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); }
1610.langs .lang-name { display: inline-flex; align-items: center; gap: var(--sp-1); }
1611.langs .dot { width: 8px; height: 8px; }
1612/* named where it reads as the language's own colour, neutral otherwise */
1613.lang { background: var(--neutral); }
1614.lang-go { background: var(--lang-go); }
1615.lang-rust { background: var(--lang-rust); }
1616.lang-c, .lang-c- { background: var(--lang-c); }
1617.lang-python { background: var(--lang-python); }
1618.lang-javascript { background: var(--lang-javascript); }
1619.lang-typescript { background: var(--lang-typescript); }
1620.lang-shell { background: var(--lang-shell); }
1621.lang-ruby { background: var(--lang-ruby); }
1622.lang-java { background: var(--lang-java); }
1623.lang-swift { background: var(--lang-swift); }
1624.lang-html { background: var(--lang-html); }
1625.lang-css { background: var(--lang-css); }
1626.lang-org { background: var(--lang-org); }
1627.lang-markdown { background: var(--lang-markdown); }
1628.lang-emacs-lisp { background: var(--lang-emacs-lisp); }
1629.lang-nix { background: var(--lang-nix); }
1630.lang-sql { background: var(--lang-sql); }
1631.contribs { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--fs-1); }
1632.contribs .label { color: var(--muted); }
1633.teambody { padding: var(--sp-3); }
1634.teambody .memberchip { margin-right: var(--sp-2); }
1635
1636/* ---- landing ---- */
1637/* the width class on main carries this too; the cap here keeps the page
1638 readable on the templates that do not set one yet */
1639.landing { max-width: 48rem; padding: var(--sp-6) 0; }
1640.landing h1 { font-size: var(--fs-6); display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
1641.landing h1 .mark { width: 32px; height: 32px; }
1642.lede { font-size: var(--fs-4); color: var(--muted); line-height: 1.5; max-width: 40rem; margin: 0 0 var(--sp-5); }
1643pre.quickstart { margin: 0 0 var(--sp-4); }
1644.shot { border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; margin: var(--sp-5) 0; }
1645.shot img { display: block; width: 100%; height: auto; max-height: 420px; object-fit: cover; object-position: top; }
1646.facets { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); margin: var(--sp-5) 0; }
1647.facets h2 { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
1648.facets p { color: var(--muted); font-size: var(--fs-2); margin: 0; }
1649.routes { display: flex; gap: var(--sp-3); align-items: center; margin: var(--sp-4) 0 0; }
1650
1651/* ---- profile ---- */
1652.profilehead { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-4); margin-bottom: var(--sp-4); }
1653.profilehead h1 { margin: 0 0 var(--sp-1); }
1654.profilehead .lede { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
1655.profilehead .meta { margin: var(--sp-1) 0 0; }
1656.activity { margin-bottom: var(--sp-5); }
1657h2 .count { background: none; color: var(--muted); font-weight: 400; font-size: var(--fs-2); margin-left: var(--sp-2); padding: 0; }
1658/* 53 week columns x 7 day rows, tinted with the link blue */
1659.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
1660.actgraph { display: flex; gap: 3px; width: max-content; padding-top: 18px; }
1661.actweek { display: flex; flex-direction: column; gap: 3px; position: relative; }
1662.actmonth { position: absolute; top: -16px; left: 0; font-size: var(--fs-0); color: var(--muted); }
1663.actday { width: 11px; height: 11px; border-radius: 2px; background: var(--faint); }
1664.actday.pad { background: transparent; }
1665.actday.l0 { background: var(--faint); }
1666.actday.l1 { background: color-mix(in srgb, var(--link) 25%, var(--canvas)); }
1667.actday.l2 { background: color-mix(in srgb, var(--link) 50%, var(--canvas)); }
1668.actday.l3 { background: color-mix(in srgb, var(--link) 75%, var(--canvas)); }
1669.actday.l4 { background: var(--link); }
1670.actlegend { display: flex; align-items: center; gap: 3px; margin-top: var(--sp-2); font-size: var(--fs-0); color: var(--muted); }
1671.actlegend span:first-child { margin-right: var(--sp-1); }
1672.actlegend span:last-child { margin-left: var(--sp-1); }
1673
1674/* ---- wiki ---- */
1675.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
1676.wikipage { flex: 1; min-width: 0; }
1677.wikinav { flex: none; width: 15rem; }
1678.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1679.wikinav li a {
1680 display: block;
1681 padding: 5px var(--sp-2);
1682 border-radius: var(--r-ctl);
1683 color: var(--fg);
1684 font-size: var(--fs-2);
1685}
1686.wikinav li a:hover { background: var(--hover); color: var(--fg); text-decoration: none; }
1687.wikinav li a.active { background: var(--surface); color: var(--link); font-weight: 500; }
1688
1689/* ---- misc ---- */
1690.meta { color: var(--muted); font-size: var(--fs-1); }
1691.muted { color: var(--muted); }
1692.desc, td.desc { color: var(--muted); }
1693.spacer { flex: 1; }
1694.compact { margin: 0; }
1695.name { min-width: 0; }
1696svg.icon { vertical-align: -0.125em; }
1697.sep { color: var(--muted); }
1698.owner { color: var(--muted); }
1699.title { margin: 0; }
1700.subject { min-width: 0; }
1701.sha { font-family: var(--mono); }
1702.when { color: var(--muted); }
1703.who { font-weight: 500; }
1704.was { color: var(--muted); }
1705.role { color: var(--muted); }
1706.age { color: var(--muted); }
1707.size { color: var(--muted); }
1708.review { font-size: var(--fs-2); }
1709
1710/* ---- breakpoints ---- */
1711@media (max-width: 80rem) {
1712 .dashgrid { grid-template-columns: minmax(0, 1fr) 20rem; }
1713 /* not a column any more, so it neither sticks nor scrolls in itself */
1714 .dashgrid > .dashpins { grid-column: 1 / -1; position: static; max-height: none; overflow: visible; }
1715 /* a pinned block that is not a column is the chip row (spec rule 7) */
1716 .pins { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
1717 /* the shorthand loses to .pins li:last-child, which drops the bottom
1718 border of the last chip -- and so of the second row */
1719 .pins li, .pins li:last-child { border: 1px solid var(--line); border-radius: var(--r-ctl); padding: var(--sp-1) var(--sp-3); }
1720 .pins .n, .dashpins .meta { display: none; }
1721}
1722
1723@media (max-width: 62rem) {
1724 /* one column, the aside after the thread: a phone shows the
1725 description first, checks and reviewers after it (#232) */
1726 .withaside { grid-template-columns: 1fr; }
1727
1728 /* rows go back to two lines where one does not fit */
1729 ul.issuelist.rows .issuemain, ul.repolist.rows li, ul.loglist.rows .commitmain { display: block; }
1730 ul.issuelist.rows .title, ul.repolist.rows .desc { white-space: normal; }
1731 /* a nowrap meta or topic line on one of these rows forces horizontal
1732 page scroll on a phone: a long branch name, a long owner/repo#N */
1733 ul.issuelist.rows .meta, ul.loglist.rows .meta,
1734 ul.repolist.rows .meta, ul.repolist.rows .topics { white-space: normal; }
1735
1736 .dashgrid { grid-template-columns: 1fr; }
1737 .dashgrid > aside { position: static; }
1738 .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1739
1740 /* the tree page is the navigator on a phone */
1741 .blobgrid { grid-template-columns: 1fr; }
1742 .filenav { display: none; }
1743
1744 /* the column is a closed disclosure before the content: a filter you
1745 reach without scrolling the list, and nothing to scroll past when
1746 you do not want it. It leads rather than follows because it is what
1747 the list is narrowed by, not a note on one row (#237) */
1748 .withcol, .withcol.narrow { grid-template-columns: 1fr; }
1749 .sidecol { position: static; margin-bottom: var(--sp-3); }
1750 .sidecol .grp { display: inline-block; vertical-align: top; margin-right: var(--sp-5); }
1751}
1752
1753@media (max-width: 52rem) {
1754 main.content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
1755 footer { padding: var(--sp-4); }
1756 .repohead { padding: var(--sp-3) 0 0; }
1757 .repohead .wrap { padding: 0 var(--sp-4); }
1758 /* seven tabs do not fit a phone in one row; a hidden scrollbar made the
1759 ones past the edge look absent. Two rows show all of them. */
1760 nav.tabs { flex-wrap: wrap; overflow: visible; }
1761 .facts { grid-template-columns: 1fr; }
1762 /* a phone shows the description under the name, not beside it */
1763 .repodesc { flex-basis: 100%; margin-left: 0; }
1764}
1765
1766@media (max-width: 40rem) {
1767 .facets { grid-template-columns: 1fr; gap: var(--sp-4); }
1768 .wikilayout { flex-direction: column; align-items: stretch; }
1769 .wikinav { width: auto; }
1770 form.setform { grid-template-columns: 1fr; gap: var(--sp-2); }
1771 form.setform label { margin-top: 0; }
1772 /* the commit subject is the widest thing in a file table and the one
1773 column a phone can do without: the tipbar above already names the
1774 latest commit */
1775 table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
1776 table.tree td.mode, table.tree th.mode { display: none; }
1777 /* at 320px a nowrap name plus the age column overran the card by the
1778 cell padding and the card clipped the age; a long name wraps (#232) */
1779 table.tree td.name { white-space: normal; overflow-wrap: anywhere; }
1780 .clone pre { white-space: pre-wrap; word-break: break-all; }
1781 .pathbar { overflow-wrap: anywhere; }
1782 .readme .cardbody, .code { padding: var(--sp-3); }
1783 .thread { margin-left: var(--sp-3); }
1784 .blamehunk { flex-direction: column; gap: 0; }
1785 .blameinfo { width: auto; }
1786 .blamecode { border-left: 0; padding-left: var(--sp-3); width: 100%; }
1787 .factgrid { grid-template-columns: repeat(2, auto); }
1788 ul.loglist li { flex-wrap: wrap; }
1789 ul.loglist .commitside { width: 100%; justify-content: flex-start; }
1790}
1791
1792/* Eleven 44px squares and the mark are 524px, so below 34rem the rail
1793 keeps five — dashboard, search, notifications, More, your avatar — and
1794 the More menu holds the rest. Shrinking the squares instead is what
1795 this replaces: 32px was under the target every phone guideline asks
1796 for, and the count only grows. */
1797@media (max-width: 34rem) {
1798 .railopt { display: none; }
1799 .railmore { display: block; }
1800 .railicon svg { width: 20px; height: 20px; }
1801 /* the mark is a link home too, so it is a target like the rest */
1802 a.brand { width: var(--rail-hit); }
1803}