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