Commit fa8a9b4260

fa8a9b4260f953d0038e63ec6a1c4886ef43f524

parent: 40993056bc

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-17 06:42 UTC

web: rewrite the stylesheet on measured tokens

Ref #218
internal/httpd/palette_test.go +3 −3
@@ -53,13 +53,13 @@ func TestSyntaxPaletteContrast(t *testing.T) {
5353 }{
5454 {lightStyle, map[string]chroma.Colour{
5555 "page": chroma.NewColour(0xff, 0xff, 0xff),
56 "code": chroma.NewColour(0xf5, 0xf5, 0xf5),
56 "code": chroma.NewColour(0xff, 0xff, 0xff),
5757 "add": chroma.NewColour(0xe4, 0xf6, 0xea),
5858 "del": chroma.NewColour(0xfd, 0xea, 0xea),
5959 }, map[chroma.TokenType]bool{chroma.NameAttribute: true}},
6060 {darkStyle, map[string]chroma.Colour{
61 "page": chroma.NewColour(0x0a, 0x0a, 0x0a),
62 "code": chroma.NewColour(0x05, 0x05, 0x05),
61 "page": chroma.NewColour(0x10, 0x11, 0x14),
62 "code": chroma.NewColour(0x0b, 0x0c, 0x0e),
6363 "add": chroma.NewColour(0x0d, 0x2a, 0x18),
6464 "del": chroma.NewColour(0x2c, 0x11, 0x13),
6565 }, map[chroma.TokenType]bool{
internal/web/static/style.css +1085 −1179
@@ -1,10 +1,11 @@
1/* gitbay stylesheet — Harbor: black and white ground, two accents with
2 separate jobs. Blue is what you can do (links, buttons, focus); orange
3 is where you are and what wants you (active nav, counts, pending state,
4 unverified signatures). Orange is never a button, so the two never
5 compete. One file, light and dark via prefers-color-scheme. Tokens
6 first; components use tokens only. No external requests: Atkinson
7 Hyperlegible is served from this origin. */
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. */
89
910@font-face {
1011 font-family: "Atkinson Hyperlegible Next";
@@ -33,35 +34,40 @@
3334 scrollbars per scheme, and opt out of browser auto-darkening */
3435 color-scheme: light dark;
3536
36 /* ground and ink */
37 --bg: #ffffff;
38 --fg: #0d0d0d;
39 --muted: #595959; /* 7.00:1 on white */
40 --faint: #eaeaea; /* hairlines, row separators */
41 --line: #d4d4d4; /* control borders, table edges */
42 --surface: #ffffff;
43 --hover: #f5f5f5;
44 --code-bg: #f5f5f5;
45 --fill-subtle: #ececec; /* hunk headers, summary hover */
46 --diff-add: #e4f6ea; /* row grounds: tinted enough to scan, light
47 enough that syntax colors stay legible */
48 --diff-del: #fdeaea;
49
50 /* blue: what you can do */
51 --accent: #0000f0; /* links, focus — 9.30:1 on white */
52 --accent-fg: #ffffff;
53 --fill: #0000f0; /* button grounds; white on it is 9.30:1 */
54 --fill-edge: transparent; /* light: the fill is its own boundary */
55
56 /* orange: where you are, what wants you */
57 --mark: #e4572e; /* bars and underlines — non-text, 3.0 bar */
58 --warn: #c2410c; /* the same orange at text size — 5.18:1 */
59
60 /* semantic */
61 --ok: #0a7d3c;
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;
6264 --bad: #c62828;
63 --done: #6b21a8; /* merged */
64 --neutral: #595959;
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;
6571
6672 /* the rail is black in both schemes: the one brand constant */
6773 --shell-bg: #000000;
@@ -69,98 +75,135 @@
6975 --shell-muted: #8f8f8f;
7076 --shell-line: #1c1c1c;
7177 --shell-hover: #141414;
72 --shell-mark: #ff6b3d; /* 7.42:1 on black, both schemes */
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;
7398
74 /* type */
7599 --sans: "Atkinson Hyperlegible Next", -apple-system, BlinkMacSystemFont,
76100 "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
77101 --mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono",
78102 SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
79 --fs-0: 0.78rem;
80 --fs-1: 0.85rem;
81 --fs-2: 0.92rem;
103
104 /* 12, 13, 14, 16, 20, 24, 32 */
105 --fs-0: 0.75rem;
106 --fs-1: 0.8125rem;
107 --fs-2: 0.875rem;
82108 --fs-3: 1rem;
83 --fs-4: 1.2rem;
84 --fs-5: 1.6rem;
85 --fs-6: 1.8rem; /* landing headline */
86 --fs-7: 4rem; /* the 404 code */
87
88 /* spacing */
89 --sp-1: 0.25rem;
90 --sp-2: 0.5rem;
91 --sp-3: 0.75rem;
92 --sp-4: 1rem;
93 --sp-5: 1.5rem;
94 --sp-6: 2.5rem;
95
96 --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23595959' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
97
98 /* radii: 2px everywhere — chart plates, not pills */
99 --r-sm: 2px;
100 --r-md: 2px;
101 --r-lg: 2px;
102 --r-pill: 2px;
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 --r-ctl: 4px; /* controls and chips */
123 --r-card: 6px; /* cards, lists, code blocks */
103124 --shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
125
126 /* the native select arrow cannot be restyled, so draw our own;
127 --chev carries the stroke colour per scheme */
128 --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");
104129}
105130@media (prefers-color-scheme: dark) {
106131 :root {
107 --bg: #0a0a0a;
108 --fg: #f2f2f2;
109 --muted: #a1a1a1; /* 7.66:1 on #0a0a0a */
110 --faint: #1c1c1c;
111 --line: #2e2e2e;
112 --surface: #0f0f0f;
113 --hover: #161616;
114 --code-bg: #050505;
115 --fill-subtle: #161616;
116 --diff-add: #0d2a18;
117 --diff-del: #2c1113;
118 --accent: #6272ff; /* pure #0000f0 is 2.13:1 here. Picked against
119 the lightest ground it lands on, not the page:
120 a link wrapping inline code sits on #161616,
121 where the old #5b6bff was 4.30:1. Now 4.63:1
122 there and 5.06:1 on the page. */
123 --accent-fg: #ffffff;
124 --fill: #0000f0; /* fills stay pure; white on it clears 9:1 */
125 --fill-edge: #7d8cff; /* a button's boundary: #0000f0 on #0a0a0a is 1.3:1 (#120) */
126 --shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
132 --canvas: #101114;
133 --surface: #212429;
134 --inset: #0b0c0e;
135 --hover: #2b2f36;
136 --line: #61666f;
137 --faint: #2f333a;
138
139 --fg: #e9eaec;
140 --muted: #a3a9b3;
141 --neutral: var(--muted);
142
143 --link: #8b9bff;
144 --fill: #4d61f0;
145 --fill-fg: #ffffff;
146 --focus: var(--link);
147
127148 --mark: #ff6b3d;
128 --warn: #ff6b3d;
149 --warn: #ff8a63;
150
129151 --ok: #3fce7a;
130152 --bad: #ff6b6b;
131153 --done: #c084fc;
132 --neutral: #a1a1a1;
133 --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23a1a1a1' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
154
155 --diff-add: #0d2a18;
156 --diff-del: #2c1113;
157
158 --shell-bg: #000000;
159 --shell-fg: #f2f2f2;
160 --shell-muted: #8f8f8f;
161 --shell-line: #1c1c1c;
162 --shell-hover: #141414;
163 --shell-mark: #ff6b3d;
164
165 --shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
166 --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");
134167 }
135168}
136169
170/* ---- base ---- */
137171* { box-sizing: border-box; }
138html { font-size: 15px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
172html { font-size: 16px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
139173body {
140174 margin: 0;
141 background: var(--bg);
175 background: var(--canvas);
142176 color: var(--fg);
143 font: var(--fs-3)/1.6 var(--sans);
177 font: var(--fs-3)/1.5 var(--sans);
144178 min-height: 100vh;
145179}
146
147a { color: var(--accent); text-decoration: none; }
180h1, h2, h3 { line-height: 1.25; font-weight: 600; }
181h1 { font-size: var(--fs-5); margin: 0 0 var(--sp-3); text-wrap: balance; }
182h2 { font-size: var(--fs-4); margin: var(--sp-6) 0 var(--sp-3); }
183h3 { font-size: var(--fs-3); margin: var(--sp-5) 0 var(--sp-2); }
184p { margin: 0 0 var(--sp-3); }
185a { color: var(--link); text-decoration: none; }
148186a:hover { text-decoration: underline; }
187a.xref { color: var(--link); text-decoration: none; }
188
189code, pre, .mono, .code, td.mode, td.size {
190 font-family: var(--mono);
191 font-size: var(--fs-1);
192}
193.mono { overflow-wrap: anywhere; }
149194
150/* one authored focus ring, so keyboard position is never the browser's
151 guess. Blue, because focus is an interactive state. */
195/* ---- focus: one authored ring, so keyboard position is never the
196 browser's guess ---- */
152197:focus-visible {
153 outline: 2px solid var(--accent);
198 outline: 2px solid var(--focus);
154199 outline-offset: 2px;
155200 border-radius: 1px;
156201}
157/* the shell is black in both schemes, and --accent is a dark blue in the
158 light one — a ring nobody could see. The shell's own mark clears 7:1 on
159 black either way. */
202/* the rail is black in both schemes and --focus is a dark blue in the
203 light one — a ring nobody could see there */
160204.rail :focus-visible { outline-color: var(--shell-mark); }
161205
162/* visually hidden, still read aloud: for headings a sighted reader gets
163 from the layout but a screen reader would otherwise miss */
206/* visually hidden, still read aloud */
164207.vh {
165208 position: absolute;
166209 width: 1px; height: 1px;
@@ -169,36 +212,23 @@ a:hover { text-decoration: underline; }
169212 overflow: hidden;
170213 white-space: nowrap;
171214}
172/* the rail runs ahead of the content in source order, so give keyboard
173 and screen-reader users a way past it */
215
216/* ---- skip link: the rail runs ahead of the content in source order ---- */
174217a.skip {
175218 position: absolute;
176219 left: var(--sp-3); top: -3rem;
177220 z-index: 50;
178221 background: var(--fill);
179 color: #ffffff;
222 color: var(--fill-fg);
180223 padding: var(--sp-2) var(--sp-4);
181224 font-weight: 600;
182225}
183226a.skip:focus { top: var(--sp-3); text-decoration: none; }
184227
185h1 { font-size: var(--fs-5); font-weight: 700; line-height: 1.18;
186 margin: 0 0 var(--sp-3); letter-spacing: -0.025em; text-wrap: balance; }
187h2 { font-size: var(--fs-4); font-weight: 700; line-height: 1.3;
188 margin: var(--sp-5) 0 var(--sp-3); letter-spacing: -0.015em; }
189h3 { font-size: var(--fs-3); font-weight: 600; margin: var(--sp-5) 0 var(--sp-2); }
190
191code, pre, .code, td.mode, td.size {
192 font-family: var(--mono);
193 font-size: var(--fs-1);
194}
195
196/* ---- shell: black rail, content pane ---- */
197.shell { display: flex; align-items: stretch; min-height: 100vh; }
198
228/* ---- rail ---- */
199229.rail {
200230 flex: none;
201 width: 13rem;
231 width: 14rem;
202232 background: var(--shell-bg);
203233 color: var(--shell-fg);
204234 border-right: 1px solid var(--shell-line);
@@ -212,170 +242,173 @@ a.brand {
212242 display: flex;
213243 align-items: center;
214244 gap: var(--sp-2);
215 padding: var(--sp-3) var(--sp-4);
245 padding: var(--sp-4) var(--sp-4) var(--sp-3);
216246 color: var(--shell-fg);
217 font-weight: 700;
247 font-weight: 600;
218248 font-size: var(--fs-3);
219 letter-spacing: -0.02em;
220 border-bottom: 1px solid var(--shell-line);
221249}
222a.brand:hover { text-decoration: none; color: #ffffff; }
250a.brand:hover { text-decoration: none; }
223251a.brand svg.mark { display: block; flex: none; }
224252a.brand span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
225253
226.railbody { flex: 1; overflow-y: auto; padding: var(--sp-3) 0; }
254.railbody { flex: 1; overflow-y: auto; padding: 0 var(--sp-3); }
227255/* search is reachable from every page, so it sits above the rail's links
228256 rather than on one page of its own */
229form.railsearch { padding: 0 var(--sp-4) var(--sp-3); }
257form.railsearch { margin-bottom: var(--sp-3); }
230258form.railsearch input[type="search"] {
231259 width: 100%;
232 padding: var(--sp-1) var(--sp-2);
233 font-size: var(--fs-1);
234 color: var(--shell-fg);
235260 background: var(--shell-hover);
236261 border: 1px solid var(--shell-line);
237 border-radius: var(--r-sm);
262 color: var(--shell-fg);
263 border-radius: var(--r-ctl);
264 padding: 6px 10px;
265 height: 32px;
266 font: inherit;
267 font-size: var(--fs-2);
238268}
239269form.railsearch input[type="search"]::placeholder { color: var(--shell-muted); }
240ul.raillist { list-style: none; margin: 0; padding: 0; }
270ul.raillist { list-style: none; margin: 0 0 var(--sp-4); padding: 0; }
241271ul.raillist a {
242 display: block;
243 padding: var(--sp-1) var(--sp-4);
272 display: flex;
273 align-items: center;
274 gap: var(--sp-2);
275 padding: 5px var(--sp-2);
244276 color: var(--shell-fg);
245277 font-size: var(--fs-2);
246 border-left: 3px solid transparent;
278 border-radius: var(--r-ctl);
247279 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
248280}
249281ul.raillist a:hover { background: var(--shell-hover); text-decoration: none; }
250282/* orange marks position — the rail's only accent */
251283ul.raillist a[aria-current] {
252 border-left-color: var(--shell-mark);
253284 background: var(--shell-hover);
285 box-shadow: inset 3px 0 0 var(--shell-mark);
254286 font-weight: 600;
255287}
256288ul.raillist .owner { color: var(--shell-muted); }
257ul.raillist.wide a { white-space: normal; padding-top: var(--sp-1); padding-bottom: var(--sp-1); }
289ul.raillist.wide a { white-space: normal; display: block; }
258290ul.raillist.wide b { display: block; font-weight: 500; font-size: var(--fs-1); }
259ul.raillist.wide .owner { font-size: var(--fs-0); }
291ul.raillist.wide .owner { display: block; font-size: var(--fs-0); }
260292
293.railgroup { margin-bottom: var(--sp-4); }
261294.raillabel {
262295 display: flex;
263296 align-items: center;
264297 gap: var(--sp-2);
265 margin: var(--sp-4) 0 var(--sp-1);
266 padding: 0 var(--sp-4);
267 font-family: var(--mono);
298 margin: 0 var(--sp-2) var(--sp-1);
268299 font-size: var(--fs-0);
269300 font-weight: 500;
270 letter-spacing: 0.1em;
301 letter-spacing: 0.08em;
271302 text-transform: uppercase;
272303 color: var(--shell-muted);
273304}
274.raillabel .count, ul.raillist .count {
275 font-family: var(--sans);
305.count {
276306 font-size: var(--fs-0);
277307 font-weight: 700;
278308 letter-spacing: 0;
279309 background: var(--shell-mark);
280 color: #000000;
281 padding: 0 0.35rem;
282 border-radius: var(--r-sm);
310 color: var(--shell-bg);
311 padding: 0 5px;
312 border-radius: var(--r-ctl);
313 margin-left: auto;
283314}
284315/* pinned above the account cell: always reachable, never scrolled away */
285316.railpinned {
286317 flex: none;
287 padding: var(--sp-2) 0;
318 padding: var(--sp-2) var(--sp-3);
319 margin: 0;
288320 border-top: 1px solid var(--shell-line);
289321}
290322.railfoot {
291323 flex: none;
292324 border-top: 1px solid var(--shell-line);
293 /* same vertical rhythm as the page footer, so the two rules line up
294 when the page is scrolled to the bottom; horizontal padding stays on
295 the rail's own grid so the avatar aligns with the nav items above */
296 padding: var(--sp-4) var(--sp-4) var(--sp-5);
325 padding: var(--sp-3) var(--sp-4);
297326 display: flex;
298327 align-items: center;
328 justify-content: space-between;
299329 gap: var(--sp-3);
300330 font-size: var(--fs-2);
301 line-height: 1.4;
302331}
303332.railfoot a { color: var(--shell-fg); }
304333a.railuser { display: inline-flex; align-items: center; gap: var(--sp-2); }
305334/* a descendant cannot cancel an ancestor's underline, so the link carries
306 none and the name draws its own — the avatar square stays undecorated */
335 none and the name draws its own */
307336a.railuser:hover { text-decoration: none; }
308337a.railuser:hover .uname { text-decoration: underline; }
309338.railfoot form { margin-left: auto; }
310.railfoot .linklike {
311 background: none; border: 0; padding: 0; cursor: pointer;
312 color: var(--shell-muted); font: inherit; text-decoration: underline;
313}
314.railfoot .linklike:hover { color: var(--shell-fg); }
339.railfoot button.linklike { color: var(--shell-muted); text-decoration: underline; }
340.railfoot button.linklike:hover { color: var(--shell-fg); }
315341.avatar {
316 width: 1.4rem; height: 1.4rem; flex: none;
317 display: inline-grid; place-items: center;
342 display: inline-grid;
343 place-items: center;
344 width: 22px; height: 22px;
345 flex: none;
346 border-radius: 50%;
318347 background: var(--fill);
319 color: #ffffff;
348 color: var(--fill-fg);
320349 font-size: var(--fs-0);
321 font-weight: 700;
322 border-radius: var(--r-sm);
350 font-weight: 600;
323351}
324352
353/* ---- shell ---- */
354.shell { display: flex; align-items: stretch; min-height: 100vh; }
325355.pane { flex: 1; min-width: 0; display: flex; flex-direction: column; }
326.content {
356main.content {
327357 flex: 1;
328 padding: var(--sp-5) var(--sp-5) var(--sp-6);
329358 width: 100%;
359 padding: var(--sp-5) var(--sp-6) var(--sp-7);
360}
361main.wide { max-width: none; }
362main.reading { max-width: calc(72rem + 2 * var(--sp-6)); }
363main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); }
364footer {
365 width: 100%;
366 padding: var(--sp-4) var(--sp-6);
367 border-top: 1px solid var(--faint);
368 color: var(--muted);
369 font-size: var(--fs-1);
330370}
371footer p { margin: 0; }
372footer a { color: var(--muted); text-decoration: underline; }
373footer a:hover { color: var(--link); }
331374
332/* ---- repo header: identity and tabs on every page, the rest once ---- */
375/* ---- repository header ---- */
333376.repohead {
334 padding: var(--sp-4) var(--sp-5) 0;
377 padding: var(--sp-4) var(--sp-6) 0;
335378 border-bottom: 1px solid var(--line);
336379}
337.repohead .identity { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
338.repohead .identity .grow { flex: 1; }
380.identity { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
381.grow { flex: 1; }
339382/* h1 on the repo home, p elsewhere so each page keeps its own h1 — but
340 identical in size, because the tabs sit below this and navigation must
341 not move when you use it */
383 identical in size, because the tabs sit below and navigation must not
384 move when you use it */
342385.repotitle {
343386 margin: 0;
344387 font-size: var(--fs-4);
345 font-weight: 700;
346 letter-spacing: -0.02em;
347 line-height: 1.3;
388 font-weight: 600;
389 line-height: 1.25;
348390}
349391.repotitle a { color: var(--fg); }
350392.repotitle a.owner { color: var(--muted); font-weight: 400; }
351.repotitle a:hover { color: var(--accent); text-decoration: none; }
352.repotitle .sep { color: var(--muted); margin: 0 0.12em; font-weight: 400; }
353.repodesc { margin: var(--sp-2) 0 0; color: var(--muted); font-size: var(--fs-2); max-width: 62ch; }
354.repometa { margin: var(--sp-1) 0 0; color: var(--muted); font-size: var(--fs-1); }
355
356button.btn {
357 font: inherit;
358 font-size: var(--fs-1);
359 font-weight: 600;
360 padding: 0.15rem 0.7rem;
361 border: 1px solid var(--line);
362 border-radius: var(--r-sm);
363 background: var(--bg);
393.repotitle a:hover { color: var(--link); text-decoration: none; }
394.repotitle .sep { color: var(--muted); margin: 0 2px; font-weight: 400; }
395.repodesc {
396 margin: var(--sp-2) 0 0;
364397 color: var(--fg);
365 cursor: pointer;
398 font-size: var(--fs-2);
399 display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
366400}
367button.btn:hover { border-color: var(--accent); color: var(--accent); }
368button.btn[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
369form.inline { display: inline; }
370input[name="confirm"] { width: auto; margin-right: var(--sp-2); }
401.repohead .topics { margin: var(--sp-2) 0 0; }
402.repometa { margin: var(--sp-1) 0 0; color: var(--muted); font-size: var(--fs-1); }
403.toggles { margin: var(--sp-2) 0 0; color: var(--muted); font-size: var(--fs-1); }
371404
372405nav.tabs {
373406 display: flex;
374407 gap: var(--sp-1);
375 margin-top: var(--sp-4);
408 margin-top: var(--sp-3);
376409 overflow-x: auto;
377410 /* with overflow-y left visible the browser computes it to auto, which
378 is a vertical drag on touch; the strip scrolls sideways only. */
411 is a vertical drag on touch; the strip scrolls sideways only */
379412 overflow-y: hidden;
380413 scrollbar-width: none;
381414}
@@ -383,8 +416,8 @@ nav.tabs::-webkit-scrollbar { display: none; }
383416nav.tabs a {
384417 display: inline-flex;
385418 align-items: center;
386 gap: var(--sp-2);
387 padding: var(--sp-2) var(--sp-3) 0.6rem;
419 gap: var(--sp-1);
420 padding: var(--sp-2) var(--sp-3) 10px;
388421 color: var(--muted);
389422 font-size: var(--fs-2);
390423 white-space: nowrap;
@@ -392,448 +425,536 @@ nav.tabs a {
392425 margin-bottom: -1px;
393426}
394427nav.tabs a:hover { color: var(--fg); text-decoration: none; }
395/* orange marks position here too */
396nav.tabs a[aria-current] {
397 color: var(--fg);
398 font-weight: 700;
399 border-bottom-color: var(--mark);
400}
401nav.tabs a i {
402 font-style: normal;
403 font-family: var(--mono);
404 font-size: var(--fs-0);
405 background: var(--hover);
406 border-radius: var(--r-sm);
407 padding: 0 0.35rem;
408}
428nav.tabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); }
429/* a count in a tab is plain metadata, not a badge */
430nav.tabs a i { font-style: normal; color: var(--muted); margin-left: 4px; }
409431
410/* ---- mobile: the rail becomes a single strip, not a wall of links ---- */
411@media (max-width: 52rem) {
412 .shell { display: block; }
413 .rail {
414 width: auto;
415 height: auto;
416 position: static;
417 flex-direction: row;
418 align-items: center;
419 gap: var(--sp-2);
420 border-right: 0;
421 border-bottom: 1px solid var(--shell-line);
422 overflow-x: auto;
423 }
424 a.brand { border-bottom: 0; padding-right: var(--sp-2); }
425 .railbody { flex: 1; overflow: visible; padding: 0; display: flex; align-items: center; }
426 form.railsearch { padding: 0 var(--sp-2); }
427 form.railsearch input[type="search"] { min-width: 8rem; }
428 /* pinned repos and the review queue both live on the dashboard, so the
429 strip keeps only what has nowhere else to go */
430 .railgroup { display: none; }
431 ul.raillist { display: flex; }
432 ul.raillist a { border-left: 0; border-bottom: 2px solid transparent; padding: var(--sp-2) var(--sp-3); }
433 ul.raillist a[aria-current] { border-left: 0; border-bottom-color: var(--shell-mark); }
434 /* the rail is a horizontal strip here: keep the account cell compact */
435 .railfoot { border-top: 0; padding: var(--sp-2); }
436 .railpinned { border-top: 0; padding: 0; }
437 .content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
438 .repohead { padding: var(--sp-3) var(--sp-4) 0; }
439 /* seven tabs do not fit a phone in one row; a hidden scrollbar made
440 the ones past the edge look absent. Two rows show all of them. */
441 nav.tabs { flex-wrap: wrap; overflow: visible; }
432/* ---- page heads ---- */
433.pagehead, .listhead, .headrow {
434 display: flex;
435 align-items: center;
436 gap: var(--sp-3);
437 flex-wrap: wrap;
438 margin-bottom: var(--sp-5);
442439}
440.pagehead h1, .listhead h1, .headrow h1, .listhead h2, .headrow h2 { margin: 0; }
441.pagehead .grow, .listhead .spacer, .headrow .spacer { flex: 1; }
442.issuetitle { margin: 0 0 var(--sp-2); font-size: var(--fs-5); }
443.issuenumber { color: var(--muted); font-weight: 400; }
444.issuemeta { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-4); }
445.commithead p { margin: var(--sp-1) 0; }
446.commithead h2 { margin-top: 0; margin-bottom: var(--sp-1); }
443447
444/* tables */
445table { border-collapse: collapse; width: 100%; }
446td {
447 padding: var(--sp-2) var(--sp-4) var(--sp-2) 0;
448 border-bottom: 1px solid var(--faint);
449 vertical-align: top;
448nav.filters { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
449nav.filters a {
450 display: inline-flex;
451 align-items: center;
452 height: 32px;
453 padding: 0 var(--sp-3);
454 background: var(--canvas);
455 border: 1px solid var(--line);
456 border-radius: var(--r-ctl);
457 color: var(--fg);
450458 font-size: var(--fs-2);
459 font-weight: 500;
451460}
452td:last-child { padding-right: 0; }
453td.size, td.mode { color: var(--muted); white-space: nowrap; }
461nav.filters a:hover { background: var(--hover); text-decoration: none; }
462nav.filters a.active { background: var(--surface); border-color: var(--link); color: var(--link); }
454463
455/* path bar on tree and blob pages */
456.pathbar {
464form.searchform, form.logfilter, form.compareform {
457465 display: flex;
458 flex-wrap: wrap;
459466 align-items: center;
460 gap: var(--sp-2) var(--sp-3);
461 margin: var(--sp-3) 0;
462 font-size: var(--fs-2);
467 gap: var(--sp-2);
468 flex-wrap: wrap;
469 margin: 0 0 var(--sp-4);
463470}
464.pathbar .spacer { flex: 1; }
465.refchip {
471form.searchform input[type="search"], form.logfilter input { flex: 1; min-width: 12rem; max-width: 32rem; }
472form.searchform.compact { margin: 0; }
473form.searchform.compact input[type="search"] { min-width: 18rem; }
474form.compareform label { display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; }
475
476/* ---- buttons: one family, 32px tall, so a row of them lines up ---- */
477button, .button {
466478 display: inline-flex;
467479 align-items: center;
468 gap: 0.3rem;
469 background: var(--surface);
470 border: 1px solid var(--faint);
471 border-radius: var(--r-md);
472 padding: 0.1rem 0.55rem;
473 font-family: var(--mono);
474 font-size: var(--fs-1);
480 justify-content: center;
481 gap: 6px;
482 height: 32px;
483 padding: 0 var(--sp-3);
484 font: inherit;
485 font-size: var(--fs-2);
486 font-weight: 500;
487 border: 1px solid transparent;
488 border-radius: var(--r-ctl);
489 cursor: pointer;
490 text-decoration: none;
491 white-space: nowrap;
492 /* a bare <button> is the primary action of its form group */
493 background: var(--fill);
494 color: var(--fill-fg);
495}
496button.primary, .button.primary { background: var(--fill); color: var(--fill-fg); border-color: transparent; }
497button:hover, .button.primary:hover { filter: brightness(1.12); text-decoration: none; }
498button.btn, .button.btn {
499 background: var(--canvas);
475500 color: var(--fg);
501 border-color: var(--line);
502 filter: none;
476503}
477.pathbar .crumbs strong { color: var(--fg); }
478details.refmenu { position: relative; }
479details.refmenu summary { cursor: pointer; list-style: none; }
480details.refmenu summary::-webkit-details-marker { display: none; }
481details.refmenu summary::after { content: " ▾"; color: var(--muted); }
482details.refmenu .refdrop {
483 position: absolute;
484 z-index: 10;
485 top: calc(100% + 4px);
486 left: 0;
487 min-width: 12rem;
488 max-height: 20rem;
489 overflow-y: auto;
490 background: var(--bg);
491 border: 1px solid var(--line);
492 border-radius: var(--r-md);
493 box-shadow: var(--shadow);
494 padding: var(--sp-1) 0;
504button.btn:hover, .button.btn:hover { background: var(--hover); filter: none; text-decoration: none; }
505button.btn[aria-pressed="true"] { background: var(--surface); color: var(--link); border-color: var(--link); }
506button.linklike {
507 background: none;
508 border: 0;
509 padding: 0;
510 height: auto;
511 color: var(--link);
512 font-weight: 400;
513 filter: none;
495514}
496details.refmenu .refdrop a {
497 display: block;
498 padding: var(--sp-1) var(--sp-3);
499 color: var(--fg);
500 font-family: var(--mono);
501 font-size: var(--fs-1);
515button.linklike:hover { text-decoration: underline; filter: none; }
516button.danger, .button.danger {
517 background: var(--canvas);
518 color: var(--bad);
519 border-color: var(--bad);
520 filter: none;
502521}
503details.refmenu .refdrop a:hover { background: var(--hover); text-decoration: none; }
504details.refmenu .refdrop a.allrefs { color: var(--accent); font-family: var(--sans); border-top: 1px solid var(--faint); margin-top: var(--sp-1); }
505
506/* file and refs tables: bordered cards, rows inside */
507/* wide listings scroll inside their own box; the page never does */
508.tablewrap { overflow-x: auto; max-width: 100%; }
522/* --canvas, not --fill-fg: white on the dark scheme's --bad is 2.3:1 */
523button.danger:hover, .button.danger:hover { background: var(--bad); color: var(--canvas); filter: none; }
524button:disabled { opacity: 0.55; cursor: default; filter: none; }
525.btngroup { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
526form.inline { display: inline; }
527.act { text-align: right; }
509528
510table.tree, table.refs {
511 background: var(--surface);
529/* ---- forms ---- */
530/* not button: it sets its own colour above, and this rule comes later at
531 the same specificity */
532input, textarea, select { font: inherit; color: inherit; }
533input[type="text"], input[type="search"], input[type="email"],
534input[type="password"], input[type="number"], input:not([type]), textarea, select {
535 background: var(--inset);
536 color: var(--fg);
512537 border: 1px solid var(--line);
513 border-radius: var(--r-lg);
514 border-collapse: separate;
515 border-spacing: 0;
516 overflow: hidden;
517 margin-bottom: var(--sp-4);
518}
519table.tree td, table.refs td {
520 padding: var(--sp-2) var(--sp-4);
521 border-bottom: 1px solid var(--faint);
538 border-radius: var(--r-ctl);
539 padding: 0 10px;
540 height: 32px;
541 font-size: var(--fs-2);
542 line-height: 1.4;
522543}
523table.tree tr:last-child td, table.refs tr:last-child td { border-bottom: none; }
524table.tree tr:hover td, table.refs tr:hover td { background: var(--hover); }
525tr.cols th {
526 text-align: left;
527 font-weight: 500;
528 font-size: var(--fs-1);
529 color: var(--muted);
530 padding: var(--sp-1) var(--sp-4);
531 border-bottom: 1px solid var(--line);
532 background: var(--bg);
544textarea {
545 width: 100%;
546 height: auto;
547 padding: 8px 10px;
548 resize: vertical;
549 line-height: 1.5;
533550}
534tr.cols:hover th { background: var(--bg); }
535/* right-aligned columns keep their header with their values; this needs to
536 outrank the tr.cols th rule above, which is why it names both */
537tr.cols th.age, tr.cols th.size { text-align: right; }
538table.tree th.size { text-align: right; }
539table.tree td.name { width: 100%; }
540table.tree td.name a { color: var(--fg); }
541table.tree td.name a:hover { color: var(--accent); }
542table.tree td.size { text-align: right; }
543table.tree td.empty, table.refs td.empty, li.empty, ul.loglist li.empty { color: var(--muted); }
544
545/* refs page */
546table.refs th, table.assets th {
547 text-align: left;
548 font-size: var(--fs-0);
549 font-weight: 500;
550 color: var(--muted);
551 padding: var(--sp-1) var(--sp-2);
552 border-bottom: 1px solid var(--line);
551textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
552select {
553 appearance: none;
554 padding-right: 1.9rem;
555 background-image: var(--chev);
556 background-repeat: no-repeat;
557 background-position: right 0.6rem center;
558 background-size: 0.62rem;
559 cursor: pointer;
553560}
554table.refs td.name { width: 100%; }
555table.refs td.sha { color: var(--muted); }
561input:hover, textarea:hover, select:hover { border-color: var(--muted); }
562input[type="radio"] { accent-color: var(--fill); }
563label { display: block; font-weight: 500; font-size: var(--fs-2); margin-bottom: 4px; }
564label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
565label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
566.hint { display: block; color: var(--muted); font-size: var(--fs-1); font-weight: 400; margin: 0 0 6px; }
567.field { margin-bottom: var(--sp-4); }
568.field input[type="text"], .field input[type="email"], .field select { width: 100%; }
569.check { display: flex; align-items: center; gap: var(--sp-2); font-weight: 400; }
570::placeholder { color: var(--muted); opacity: 1; }
571::selection { background: var(--fill); color: var(--fill-fg); }
572/* :user-invalid, not :invalid — a required field is invalid the moment
573 the page loads, and colouring it red before anyone has typed is a
574 scolding, not a hint */
575input:user-invalid, textarea:user-invalid { border-color: var(--bad); }
576input[name="confirm"] { width: auto; margin-right: var(--sp-2); }
556577
557/* card header (README) */
558.cardhead {
559 font-family: var(--mono);
560 font-size: var(--fs-1);
561 color: var(--muted);
562 border-bottom: 1px solid var(--faint);
563 margin: calc(-1 * var(--sp-4)) calc(-1 * var(--sp-5)) var(--sp-4);
564 padding: var(--sp-2) var(--sp-5);
565 background: var(--bg);
566 border-radius: var(--r-lg) var(--r-lg) 0 0;
578/* A radio keeps the native control: a circle takes one answer, a square
579 takes any number, and that shape survives greyscale and colour
580 blindness. The checkbox is drawn so it matches the rest of the family. */
581input[type="checkbox"] {
582 appearance: none;
583 flex: none;
584 width: 16px;
585 height: 16px;
586 margin: 0;
587 /* an empty box has nothing but its border to announce it */
588 border: 1px solid var(--muted);
589 border-radius: var(--r-ctl);
590 background: var(--inset);
591 cursor: pointer;
592}
593input[type="checkbox"]:not(:checked):hover { border-color: var(--fg); }
594input[type="checkbox"]:checked {
595 background: var(--fill);
596 border-color: var(--fill);
597 /* the mark sits on the blue ground, so it is white in both schemes */
598 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");
599 background-repeat: no-repeat;
600 background-position: center;
601 background-size: 11px;
567602}
568603
569/* log */
570ul.loglist {
571 list-style: none;
572 margin: var(--sp-3) 0;
573 padding: 0;
574 background: var(--surface);
604/* a segmented control for a small, mutually exclusive set: real radios
605 underneath, so arrow keys and screen readers behave as they always did */
606fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
607fieldset.segmented legend { padding: 0; margin-bottom: var(--sp-2); color: var(--muted); font-size: var(--fs-2); }
608fieldset.segmented .options { display: inline-flex; }
609fieldset.segmented label { gap: 0; margin: 0; }
610fieldset.segmented input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
611fieldset.segmented span {
612 display: flex;
613 align-items: center;
614 height: 32px;
615 padding: 0 var(--sp-4);
575616 border: 1px solid var(--line);
576 border-radius: var(--r-lg);
577 overflow: hidden;
617 font-size: var(--fs-2);
618 cursor: pointer;
578619}
579ul.loglist li {
580 display: flex;
581 align-items: baseline;
582 gap: var(--sp-3);
583 padding: var(--sp-2) var(--sp-4);
584 border-bottom: 1px solid var(--faint);
585}
586ul.loglist li:last-child { border-bottom: none; }
587ul.loglist li:hover { background: var(--hover); }
588ul.loglist .commitmain { flex: 1; min-width: 0; }
589ul.loglist p { margin: 0; }
590ul.loglist .subject a { color: var(--fg); font-weight: 550; }
591ul.loglist .subject a:hover { color: var(--accent); }
592ul.loglist .commitside {
593 display: flex;
594 align-items: baseline;
595 gap: var(--sp-2);
596 white-space: nowrap;
620fieldset.segmented label + label span { border-left: 0; }
621fieldset.segmented label:first-child span { border-radius: var(--r-ctl) 0 0 var(--r-ctl); }
622fieldset.segmented label:last-child span { border-radius: 0 var(--r-ctl) var(--r-ctl) 0; }
623fieldset.segmented span:hover { border-color: var(--muted); }
624fieldset.segmented input:checked + span {
625 background: var(--fill);
626 border-color: var(--fill);
627 color: var(--fill-fg);
628 font-weight: 600;
597629}
598p.pager { margin-top: var(--sp-4); }
630fieldset.segmented input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }
599631
600/* commit page */
601.commithead p { margin: var(--sp-1) 0; }
602.commithead h2 { margin-bottom: var(--sp-1); }
603code.fullsha { color: var(--muted); overflow-wrap: anywhere; }
604.empty-note { color: var(--muted); }
605.crumbs { color: var(--muted); font-size: var(--fs-2); }
606.desc, td.desc { color: var(--muted); }
607.error {
632p.branchpick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
633p.branchpick label { color: var(--muted); font-size: var(--fs-2); margin: 0; }
634p.branchpick select { flex: 1 1 12rem; }
635
636form.signupform, form.editform { max-width: 40rem; }
637form.signupform label, form.editform label { margin-bottom: 4px; }
638.editform textarea { width: 100%; }
639.editform input[name="message"] { width: 100%; }
640
641form.commentform { margin: var(--sp-4) 0; max-width: 48rem; }
642form.commentform p:last-child { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: 0; }
643
644details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
645details.editbox > summary {
646 display: inline-flex;
647 align-items: center;
648 height: 32px;
649 padding: 0 var(--sp-3);
650 background: var(--canvas);
651 border: 1px solid var(--line);
652 border-radius: var(--r-ctl);
608653 color: var(--fg);
609 border: 1px solid var(--bad);
610 border-left-width: 3px;
611 border-radius: var(--r-sm);
612 padding: var(--sp-2) var(--sp-3);
613 margin-bottom: var(--sp-4);
654 font-size: var(--fs-2);
655 font-weight: 500;
656 cursor: pointer;
657 list-style: none;
614658}
615/* settings: one row per control, label then input then its own button */
659details.editbox > summary::-webkit-details-marker { display: none; }
660details.editbox > summary:hover { background: var(--hover); }
661details.editbox[open] > summary { margin-bottom: var(--sp-2); }
662details.editbox input[type="text"] { width: 100%; }
663
664/* ---- settings: one row per control, label then input then its own
665 button. The name stays setform because the templates carry it. ---- */
616666form.setform {
667 display: grid;
668 grid-template-columns: 14rem minmax(0, 28rem) auto;
669 gap: var(--sp-4);
670 align-items: start;
671 padding: var(--sp-3) 0;
672 border-bottom: 1px solid var(--faint);
673}
674form.setform label { margin-top: 6px; }
675form.setform .hint { margin: 2px 0 0; }
676form.setform input[type="text"], form.setform input[type="number"], form.setform select { width: 100%; }
677/* the third column takes the leftover width; the button keeps its own */
678form.setform > button, form.setform > .btngroup { justify-self: start; }
679form.setform.stack { grid-template-columns: 1fr; }
680form.setform.stack textarea, form.setform.stack select { width: 100%; max-width: 48rem; }
681nav.sections { display: flex; gap: var(--sp-4); flex-wrap: wrap; font-size: var(--fs-2); margin-bottom: var(--sp-5); }
682ul.protlist { list-style: none; margin: var(--sp-2) 0; padding: 0; }
683ul.protlist li {
617684 display: flex;
618 flex-wrap: wrap;
619685 align-items: center;
620686 gap: var(--sp-3);
621687 padding: var(--sp-2) 0;
622688 border-bottom: 1px solid var(--faint);
623689}
624/* the label absorbs the free space, so a row whose control does not
625 stretch — a checkbox, a number — still finishes at the same right edge
626 as the rows whose input fills the line */
627form.setform label { min-width: 12rem; margin-right: auto; color: var(--muted); font-size: var(--fs-2); }
628form.setform input[type="text"], form.setform select { flex: 1 1 16rem; }
629form.setform input[type="number"] { width: 5rem; }
630ul.protlist { list-style: none; padding: 0; margin: var(--sp-2) 0; }
631ul.protlist li { padding: var(--sp-1) 0; display: flex; gap: var(--sp-3); align-items: baseline; }
632
633/* branch picker on the new merge request form */
634p.branchpick {
635 display: flex;
636 flex-wrap: wrap;
637 align-items: center;
638 gap: var(--sp-2);
639}
640p.branchpick label { color: var(--muted); font-size: var(--fs-2); }
641p.branchpick select { flex: 1 1 12rem; }
690ul.protlist li:last-child { border-bottom: 0; }
691ul.protlist form { margin-left: auto; }
692ul.plain { list-style: none; margin: 0 0 var(--sp-3); padding: 0; }
693ul.plain li { padding: var(--sp-1) 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
642694
643/* merge request actions in the aside: stacked controls, full width */
644.aside form.actions {
645 display: flex;
646 flex-wrap: wrap;
647 gap: var(--sp-2);
648 margin-top: var(--sp-2);
695/* ---- messages: .error and .notice are one family. The names stay
696 because e2e tests match class="error". ---- */
697.error, .notice {
698 border-left: 3px solid var(--bad);
699 background: color-mix(in srgb, var(--bad) 6%, transparent);
700 color: var(--fg);
701 border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
702 padding: var(--sp-2) var(--sp-3);
703 margin: 0 0 var(--sp-4);
704 font-size: var(--fs-2);
649705}
650.aside form.actions button { flex: 1 1 auto; }
651.aside form.actions select { width: 100%; }
652form.threadact { margin: var(--sp-1) 0 0; padding: 0 var(--sp-3) var(--sp-2); }
653
654.meta { color: var(--muted); font-size: var(--fs-1); }
655svg.icon { vertical-align: -0.125em; }
656.lede { font-size: var(--fs-3); margin: var(--sp-2) 0; }
706.notice { border-left-color: var(--ok); background: color-mix(in srgb, var(--ok) 6%, transparent); }
707.empty-note, .none, .empty, li.empty, td.empty { color: var(--muted); }
657708
658/* repo listings (explore, owner pages, dashboard): one row per repo */
659ul.repolist {
660 list-style: none;
661 margin: var(--sp-3) 0 var(--sp-5);
662 padding: 0;
709/* ---- containers: one recipe for cards, lists and tables ---- */
710.card, ul.list, ul.loglist, ul.repolist, ul.issuelist,
711ul.milestonelist, .readme, .code, article.release, .blame, .teambody {
663712 background: var(--surface);
664713 border: 1px solid var(--line);
665 border-radius: var(--r-lg);
714 border-radius: var(--r-card);
666715 overflow: hidden;
667716}
668ul.repolist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
669/* pinned repos: a compact wrap of name pills, no description or meta */
670ul.pinlist {
671 list-style: none;
672 margin: var(--sp-3) 0 var(--sp-5);
673 padding: 0;
717.cardhead {
674718 display: flex;
675 flex-wrap: wrap;
676 gap: var(--sp-2);
719 align-items: center;
720 gap: var(--sp-3);
721 padding: var(--sp-2) var(--sp-4);
722 border-bottom: 1px solid var(--line);
723 font-size: var(--fs-1);
724 color: var(--muted);
677725}
678ul.pinlist li {
726.cardhead b { color: var(--fg); font-weight: 500; }
727.cardbody { padding: var(--sp-4) var(--sp-5); }
728ul.list { list-style: none; margin: 0 0 var(--sp-4); padding: 0; }
729ul.list li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
730ul.list li:last-child { border-bottom: 0; }
731ul.list li:hover { background: var(--hover); }
732
733table { border-collapse: collapse; width: 100%; font-size: var(--fs-2); }
734th {
735 text-align: left;
736 font-weight: 500;
737 font-size: var(--fs-1);
738 color: var(--muted);
739 padding: 6px var(--sp-4);
740 border-bottom: 1px solid var(--line);
741}
742td { padding: 7px var(--sp-4); border-bottom: 1px solid var(--faint); vertical-align: top; }
743tr:last-child td { border-bottom: 0; }
744tbody tr:hover td { background: var(--hover); }
745/* every header row a template writes, by the class it or its table
746 carries: TestHeaderRowsAreLeftAligned reads these selectors */
747tr.cols th, table.tree th, table.refs th, table.keys th, table.assets th { text-align: left; }
748tr.cols th { background: var(--canvas); }
749/* right-aligned columns keep their header with their values */
750tr.cols th.age, tr.cols th.size { text-align: right; }
751/* wide listings scroll inside their own box; the page never does. The
752 wrapper is the scroller only — the table inside carries the card. */
753.tablewrap { overflow-x: auto; max-width: 100%; }
754
755table.tree, table.refs {
679756 background: var(--surface);
680757 border: 1px solid var(--line);
681 border-radius: var(--r-md);
682 padding: var(--sp-1) var(--sp-3);
683}
684ul.pinlist li:hover { background: var(--hover); }
685ul.pinlist li a { color: var(--fg); }
686ul.pinlist li a:hover { color: var(--accent); text-decoration: none; }
687ul.pinlist .sep { color: var(--muted); margin: 0 0.15em; }
688ul.repolist li:last-child { border-bottom: none; }
689ul.repolist li:hover { background: var(--hover); }
690ul.repolist li.empty { color: var(--muted); }
691ul.repolist p { margin: 0; }
692ul.repolist .reponame { font-size: var(--fs-3); }
693ul.repolist .reponame a { color: var(--fg); }
694ul.repolist .reponame a strong { color: var(--accent); font-weight: 600; }
695ul.repolist .reponame .sep { color: var(--muted); margin: 0 0.1em; }
696ul.repolist .desc { margin-top: 0.1rem; }
697ul.repolist .topics { margin-top: var(--sp-1); }
698ul.repolist .meta { margin-top: var(--sp-1); }
699
700/* owner profile header */
701.profilehead {
702 border-bottom: 1px solid var(--faint);
703 padding-bottom: var(--sp-4);
758 border-radius: var(--r-card);
759 /* collapsed borders defeat a radius on the table itself */
760 border-collapse: separate;
761 border-spacing: 0;
762 overflow: hidden;
704763 margin-bottom: var(--sp-4);
705764}
706.profilehead h1 { margin: var(--sp-4) 0 var(--sp-1); }
707.profilehead .lede { margin: 0 0 var(--sp-1); }
708.profilehead .meta { margin: var(--sp-1) 0 0; }
709h2 .count { color: var(--muted); font-weight: 400; font-size: var(--fs-2); }
765table.tree tr:last-child td, table.refs tr:last-child td { border-bottom: 0; }
766table.tree tr:hover td, table.refs tr:hover td { background: var(--hover); }
767td.name a { color: var(--fg); }
768td.name a:hover { color: var(--link); }
769table.tree td.name { width: 25%; white-space: nowrap; }
770table.tree td.name.dir a { color: var(--link); }
771table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
772table.tree td.lastcommit a {
773 color: var(--muted);
774 display: block;
775 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
776}
777table.tree td.lastcommit a:hover { color: var(--link); }
778td.age, th.age { text-align: right; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; }
779td.size, td.mode { color: var(--muted); white-space: nowrap; }
780table.tree th.size, table.tree td.size { text-align: right; }
781table.refs td.name { width: 100%; }
782table.refs td.sha, td.sha { color: var(--muted); }
783
784/* these tables sit flush with the page text: no outer border, and the
785 header row drops the ground and the left padding */
786table.keys, table.assets { background: none; border: 0; border-radius: 0; }
787table.keys th, table.assets th, table.keys tr.cols th { background: transparent; padding-left: 0; }
788table.keys td { padding-left: 0; }
789table.keys td.act, table.assets td.size { text-align: right; }
790table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
791table.assets { margin-top: var(--sp-2); }
710792
711/* activity graph: 53 week columns x 7 day rows, accent-tinted levels */
712.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
713.actgraph { display: flex; gap: 3px; width: max-content; }
714.actweek { display: flex; flex-direction: column; gap: 3px; }
715.actday {
716 width: 11px;
717 height: 11px;
718 border-radius: 2px;
719 background: var(--faint);
793/* the tip commit is the first row of the file table */
794.tipbar {
795 display: flex;
796 align-items: center;
797 gap: var(--sp-3);
798 padding: var(--sp-2) var(--sp-4);
799 background: var(--surface);
800 border: 1px solid var(--line);
801 border-bottom: 0;
802 border-radius: var(--r-card) var(--r-card) 0 0;
803 font-size: var(--fs-2);
720804}
721.actday.pad { background: transparent; }
722.actday.l1 { background: color-mix(in srgb, var(--accent) 25%, var(--bg)); }
723.actday.l2 { background: color-mix(in srgb, var(--accent) 50%, var(--bg)); }
724.actday.l3 { background: color-mix(in srgb, var(--accent) 75%, var(--bg)); }
725.actday.l4 { background: var(--accent); }
805.tipbar .who { font-weight: 600; }
806.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
807.tipbar .subject:hover { color: var(--link); }
808.tipbar .spacer { flex: 1; }
809.tipbar .age { color: var(--muted); white-space: nowrap; }
810.tipbar + table.tree,
811.tipbar + .tablewrap table.tree { border-radius: 0 0 var(--r-card) var(--r-card); }
812
813.readme { margin-top: var(--sp-5); }
814.readme .cardbody { max-width: 78ch; }
815/* until every card wraps its body in .cardbody, the rendered block is
816 the body */
817.readme > .rendered { padding: var(--sp-4) var(--sp-5); }
818.code { background: var(--inset); padding: var(--sp-3) var(--sp-4); overflow-x: auto; }
819.code pre { margin: 0; background: transparent !important; border: 0; padding: 0; }
820pre.bigcode, .bigcode {
821 font-family: var(--mono);
822 /* the 404 numeral is a picture of a number, not body type */
823 font-size: 4rem;
824 color: var(--faint);
825 -webkit-text-stroke: 1px var(--line);
826 margin: 0;
827 line-height: 1;
828}
829.notfound { text-align: center; padding: var(--sp-6) 0; }
830.notfound h1 { margin-top: var(--sp-3); }
726831
727/* heading row with actions on the right */
728.headrow {
832ul.loglist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
833ul.loglist li {
729834 display: flex;
730835 align-items: baseline;
731 gap: var(--sp-4);
732 flex-wrap: wrap;
836 gap: var(--sp-3);
837 padding: var(--sp-3) var(--sp-4);
838 border-bottom: 1px solid var(--faint);
733839}
734.headrow .spacer { flex: 1; }
840ul.loglist li:last-child { border-bottom: 0; }
841ul.loglist li:hover { background: var(--hover); }
842ul.loglist p { margin: 0; }
843ul.loglist .commitmain { flex: 1; min-width: 0; }
844ul.loglist .subject a { color: var(--fg); font-weight: 500; }
845ul.loglist .subject a:hover { color: var(--link); }
846ul.loglist .commitside { display: flex; align-items: baseline; gap: var(--sp-2); white-space: nowrap; }
735847
736/* member and org chips on owner pages */
737a.memberchip {
738 display: inline-block;
848ul.repolist { list-style: none; margin: var(--sp-3) 0 var(--sp-5); padding: 0; }
849ul.repolist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
850ul.repolist li:last-child { border-bottom: 0; }
851ul.repolist li:hover { background: var(--hover); }
852ul.repolist p { margin: 0; }
853ul.repolist .reponame { font-size: var(--fs-3); }
854ul.repolist .reponame a { color: var(--fg); }
855ul.repolist .reponame a strong { color: var(--link); font-weight: 600; }
856ul.repolist .reponame .sep { color: var(--muted); margin: 0 2px; }
857ul.repolist .desc { margin-top: 2px; }
858ul.repolist .topics, ul.repolist .meta { margin-top: var(--sp-1); }
859
860/* pinned repos: a compact wrap of names, no description or meta */
861ul.pinlist { list-style: none; margin: var(--sp-3) 0 var(--sp-5); padding: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2); }
862ul.pinlist li {
863 background: var(--surface);
739864 border: 1px solid var(--line);
740 border-radius: var(--r-pill);
741 padding: 0.05rem 0.6rem;
742 color: var(--fg);
743 font-size: var(--fs-1);
744 margin: 0 0.15rem 0.15rem 0;
865 border-radius: var(--r-ctl);
866 padding: var(--sp-1) var(--sp-3);
745867}
746a.memberchip:hover { text-decoration: none; border-color: var(--accent); color: var(--accent); }
747a.memberchip .role { color: var(--muted); }
868ul.pinlist li:hover { background: var(--hover); }
869ul.pinlist li a { color: var(--fg); }
870ul.pinlist li a:hover { color: var(--link); text-decoration: none; }
871ul.pinlist .sep { color: var(--muted); margin: 0 2px; }
748872
749/* landing page */
750.landing { max-width: 44rem; padding: var(--sp-6) 0; }
751.landing h1 { font-size: var(--fs-6); margin-bottom: var(--sp-3); }
752.landing .lede { font-size: var(--fs-4); color: var(--muted); line-height: 1.7; margin: 0 0 var(--sp-4); }
753pre.quickstart {
754 background: var(--code-bg);
755 border: 1px solid var(--line);
756 border-radius: var(--r-md);
873ul.issuelist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
874ul.issuelist li {
875 display: flex;
876 align-items: baseline;
877 gap: var(--sp-3);
757878 padding: var(--sp-3) var(--sp-4);
758 overflow-x: auto;
759 margin: 0 0 var(--sp-4);
879 border-bottom: 1px solid var(--faint);
760880}
761.landing .explorelink { font-weight: 550; }
762.landing .facets { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); margin: var(--sp-5) 0; }
763.landing .facets h2 { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
764.landing .facets p { margin: 0; color: var(--muted); font-size: var(--fs-2); line-height: 1.6; }
765@media (max-width: 40rem) { .landing .facets { grid-template-columns: 1fr; gap: var(--sp-4); } }
881ul.issuelist li:last-child { border-bottom: 0; }
882ul.issuelist li:hover { background: var(--hover); }
883ul.issuelist li.empty { display: block; }
884ul.issuelist p { margin: 0; }
885ul.issuelist .issuemain { flex: 1; min-width: 0; }
886ul.issuelist .title a { color: var(--fg); font-weight: 500; }
887ul.issuelist .title a:hover { color: var(--link); }
766888
767/* index toolbar */
768p.toolbar { color: var(--muted); font-size: var(--fs-2); margin-top: var(--sp-4); }
769button.linklike {
770 background: none;
771 border: none;
772 color: var(--accent);
773 padding: 0;
774 font: inherit;
775 font-size: var(--fs-2);
776 cursor: pointer;
889ul.milestonelist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
890ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
891ul.milestonelist li:last-child { border-bottom: 0; }
892ul.milestonelist li:hover { background: var(--hover); }
893ul.milestonelist p { margin: 0; }
894ul.milestonelist .msmain { min-width: 0; }
895ul.milestonelist .title { font-weight: 500; }
896.progress {
897 height: 6px;
898 max-width: 24rem;
899 margin-top: var(--sp-2);
900 background: var(--faint);
901 border-radius: var(--r-ctl);
902 overflow: hidden;
777903}
778button.linklike:hover { text-decoration: underline; filter: none; }
904.progress .bar { height: 100%; background: var(--ok); }
779905
780/* cards: README, comments */
781.readme, .code {
782 background: var(--surface);
906article.release { padding: var(--sp-4); margin: var(--sp-4) 0; }
907.releasehead { background: none; border: 0; padding: 0; }
908.releasehead h3 { margin: 0 0 var(--sp-1); }
909.releasehead .meta { margin: 0 0 var(--sp-2); }
910
911ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
912ul.matchlist li { margin-bottom: var(--sp-3); }
913.matchpath { font-family: var(--mono); font-size: var(--fs-1); }
914pre.matchline {
915 background: var(--inset);
783916 border: 1px solid var(--line);
784 border-radius: var(--r-lg);
785 padding: var(--sp-4) var(--sp-5);
786 margin-top: var(--sp-4);
917 border-radius: var(--r-card);
918 padding: var(--sp-1) var(--sp-3);
919 margin: var(--sp-1) 0 0;
787920 overflow-x: auto;
788921}
789/* Highlighting is class-based with a palette per scheme, so code blocks
790 follow the site's own colors. */
791.code { background: var(--code-bg); color: var(--fg); padding: var(--sp-3) var(--sp-4); border-color: var(--line); }
792.code pre { margin: 0; background: transparent !important; }
793/* rendered markdown / org / html */
794.rendered { max-width: 100%; overflow-wrap: anywhere; }
795/* A linked line: #f2-n17 on a diff, #L17 on a file (#118). */
796.difftable tr:target td, .code .line:has(a:target) { background: color-mix(in srgb, var(--mark) 18%, transparent); }
797.difftable tr:target td.ln, .code .line:has(a:target) .ln { border-left: 3px solid var(--mark); }
798.thread:target { outline: 2px solid var(--mark); outline-offset: 2px; }
799/* GFM task lists: the box sits in the line, sized to the prose. */
800.rendered li input[type="checkbox"] { width: 0.9em; height: 0.9em; margin: 0 0.35em 0 0; vertical-align: -0.05em; accent-color: var(--accent); }
801.rendered li:has(> input[type="checkbox"]) { list-style: none; margin-left: -1.2em; }
802/* line length is a reading constraint, so it applies to prose only —
803 tables, code blocks and images keep the full column */
804.rendered > p,
805.rendered > ul,
806.rendered > ol,
807.rendered > blockquote { max-width: 78ch; }
808.rendered pre {
809 background: var(--code-bg);
922pre.matchline mark { background: color-mix(in srgb, var(--mark) 25%, transparent); color: inherit; border-radius: 2px; }
923p.pager { margin-top: var(--sp-4); }
924.snippetfile { margin-bottom: var(--sp-5); }
925p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
926pre.buildlog { max-height: 40rem; overflow: auto; }
927
928/* ---- rendered prose ---- */
929pre {
930 background: var(--inset);
810931 border: 1px solid var(--line);
932 border-radius: var(--r-card);
811933 padding: var(--sp-3) var(--sp-4);
812 border-radius: var(--r-md);
934 margin: 0 0 var(--sp-4);
813935 overflow-x: auto;
936 font-size: var(--fs-2);
937 line-height: 1.6;
814938}
815.rendered code {
816 background: var(--code-bg);
817 border: 1px solid var(--line);
818 padding: 0.05rem 0.3rem;
819 border-radius: var(--r-sm);
820}
821.rendered pre code { background: transparent; border: none; padding: 0; }
822.rendered blockquote {
823 border-left: 3px solid var(--line);
824 margin-left: 0;
825 padding-left: var(--sp-4);
826 color: var(--muted);
939code {
940 background: var(--inset);
941 border: 1px solid var(--faint);
942 border-radius: var(--r-ctl);
943 padding: 0 0.3em;
944}
945pre code { background: none; border: 0; padding: 0; font-size: inherit; }
946code.fullsha { color: var(--muted); overflow-wrap: anywhere; }
947pre.message {
948 white-space: pre-wrap;
949 overflow-wrap: anywhere;
827950}
951.rendered { max-width: 100%; overflow-wrap: anywhere; }
952.rendered a { text-decoration: underline; }
953.prose, .rendered > p, .rendered > ul, .rendered > ol, .rendered > blockquote { max-width: 78ch; }
954.rendered blockquote { border-left: 3px solid var(--line); margin-left: 0; padding-left: var(--sp-4); color: var(--muted); }
828955.rendered img { max-width: 100%; }
829956.rendered h1, .rendered h2 { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-1); }
830.rendered table {
831 border-collapse: collapse;
832 margin: var(--sp-3) 0;
833 display: block;
834 max-width: 100%;
835 overflow-x: auto;
836}
957.rendered table { border-collapse: collapse; margin: var(--sp-3) 0; display: block; max-width: 100%; overflow-x: auto; }
837958.rendered th, .rendered td {
838959 border: 1px solid var(--line);
839960 padding: var(--sp-1) var(--sp-3);
@@ -841,129 +962,158 @@ button.linklike:hover { text-decoration: underline; filter: none; }
841962 overflow-wrap: normal; /* scroll the table, don't shatter words */
842963}
843964.rendered th { background: var(--surface); font-weight: 600; }
965/* GFM task lists: the box sits in the line, sized to the prose */
966.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; }
967.rendered li:has(> input[type="checkbox"]) { list-style: none; margin-left: -1.2em; }
844968.blobimage { text-align: center; }
845.blobimage img {
846 max-width: 100%;
847 border: 1px solid var(--faint);
848 border-radius: var(--r-md);
849 background: var(--surface);
850}
969.blobimage img { max-width: 100%; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--surface); }
851970
852pre.message {
853 background: var(--code-bg);
971/* ---- two-column: conversation and aside ---- */
972.withaside { display: grid; grid-template-columns: minmax(0, 1fr) 18rem; gap: var(--sp-6); align-items: start; }
973.withaside .mainside { min-width: 0; }
974aside.aside { font-size: var(--fs-2); }
975.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
976.aside .grp:first-child { border-top: 0; padding-top: 0; }
977.aside h2 {
978 margin: 0 0 var(--sp-2);
979 font-size: var(--fs-0);
980 font-weight: 500;
981 letter-spacing: 0.08em;
982 text-transform: uppercase;
983 color: var(--muted);
984}
985.aside .row { display: flex; align-items: center; gap: 6px; margin: 0 0 var(--sp-1); flex-wrap: wrap; }
986.aside .row:last-child { margin-bottom: 0; }
987/* a row's second line: when it happened, under what it happened to */
988.aside .row .sub { flex-basis: 100%; padding-left: 14px; color: var(--muted); font-size: var(--fs-1); }
989.aside .row:has(.sub) { margin-bottom: var(--sp-2); }
990.aside .none { color: var(--muted); }
991.dot { display: inline-block; width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--neutral); margin-right: 2px; vertical-align: middle; }
992.dot.ok { background: var(--ok); }
993.dot.bad { background: var(--bad); }
994.dot.pend { background: var(--mark); }
995.ok { color: var(--ok); }
996.bad { color: var(--bad); }
997form.actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
998form.actions button { flex: 1 1 auto; }
999form.actions select, form.actions textarea { width: 100%; }
1000.feedline { margin-bottom: var(--sp-2); }
1001
1002/* ---- comments and threads ---- */
1003article.comment {
1004 max-width: 48rem;
8541005 border: 1px solid var(--line);
855 padding: var(--sp-3) var(--sp-4);
856 border-radius: var(--r-md);
857 white-space: pre-wrap;
858 overflow-wrap: anywhere;
1006 border-radius: var(--r-card);
1007 margin: var(--sp-4) 0;
1008 overflow: hidden;
8591009}
860
861/* repo facts: the counts a visitor sizes a project up with */
862.teambody { padding: var(--sp-3); background: var(--bg); }
863.teambody .memberchip { margin-right: var(--sp-2); }
864
865form.logfilter {
866 display: flex; align-items: center; gap: var(--sp-2);
867 margin: 0 0 var(--sp-4); flex-wrap: wrap;
1010article.comment .commenthead {
1011 display: flex;
1012 gap: var(--sp-2);
1013 flex-wrap: wrap;
1014 background: var(--surface);
1015 border-bottom: 1px solid var(--line);
1016 padding: var(--sp-2) var(--sp-4);
1017 margin: 0;
1018 font-size: var(--fs-1);
1019 color: var(--muted);
8681020}
869form.logfilter input { flex: 1; min-width: 12rem; max-width: 28rem; }
1021article.comment .commenthead b { color: var(--fg); font-weight: 500; }
1022article.comment .commenthead .when { color: var(--muted); }
1023article.comment .rendered { padding: var(--sp-3) var(--sp-4); }
1024article.comment .rendered > :first-child { margin-top: 0; }
1025article.comment .rendered > :last-child { margin-bottom: 0; }
1026a.authorlink { color: var(--fg); font-weight: 500; }
1027a.authorlink:hover { color: var(--link); }
8701028
871/* account settings */
872table.keys td { padding: var(--sp-2) var(--sp-4) var(--sp-2) 0; }
873/* these tables sit flush with the page text, so the header row drops the
874 left padding the card-style listings use */
875table.keys tr.cols th { padding-left: 0; background: transparent; }
876table.keys td.mono, .mono { font-family: var(--mono); font-size: var(--fs-1); overflow-wrap: anywhere; }
877table.keys td.act { text-align: right; }
878ul.plain { list-style: none; margin: 0 0 var(--sp-3); padding: 0; }
879ul.plain li { padding: var(--sp-1) 0; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
880form.setform.stack { display: block; }
881form.setform.stack textarea, form.setform.stack select { width: 100%; max-width: 48rem; display: block; margin-bottom: var(--sp-2); }
882p.notice {
883 border-left: 3px solid var(--ok);
884 background: var(--hover);
885 padding: var(--sp-2) var(--sp-3);
886 margin: 0 0 var(--sp-4);
1029.syscomment {
1030 max-width: 48rem;
1031 color: var(--muted);
1032 font-size: var(--fs-1);
1033 margin: 0 0 var(--sp-4) var(--sp-3);
1034 padding: var(--sp-2) 0 var(--sp-2) var(--sp-4);
1035 border-left: 2px solid var(--faint);
8871036}
1037.syscomment p { display: inline; margin: 0; }
8881038
889.facts { margin: 0 0 var(--sp-4); }
890.facts .counts {
891 display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
892 margin: 0 0 var(--sp-3); font-size: var(--fs-2);
1039.thread {
1040 border: 1px solid var(--faint);
1041 border-left: 3px solid var(--link);
1042 border-radius: var(--r-ctl);
1043 padding: var(--sp-2) var(--sp-4);
1044 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
8931045}
894.facts .counts a { color: var(--fg); text-decoration: none; }
895.facts .counts a:hover { color: var(--accent); text-decoration: underline; }
896.facts .counts .fact { color: var(--muted); }
897.facts .counts strong { font-weight: 600; }
1046.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1047/* an unsubmitted comment is the viewer's own note, not the conversation */
1048.thread.pending { border-left-color: var(--neutral); border-left-style: dashed; }
1049.thread.stale { border-left-color: var(--warn); }
1050.thread.composing { border-left-color: var(--mark); }
1051.thread:target { outline: 2px solid var(--mark); outline-offset: 2px; }
1052.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1053.thread .when { color: var(--muted); }
1054.thread .rendered p { margin: var(--sp-1) 0; }
1055.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1056.thread details.threadreply { margin: var(--sp-2) 0 0; }
1057.thread details.threadreply > summary { color: var(--link); font-size: var(--fs-1); cursor: pointer; }
1058.thread textarea { width: 100%; }
1059.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1060form.threadact { margin: var(--sp-1) 0 0; padding: 0 var(--sp-3) var(--sp-2); }
8981061
899.langbar {
900 display: flex; height: 0.5rem; margin: 0 0 var(--sp-2);
901 border-radius: var(--r-sm); overflow: hidden; background: var(--faint);
902}
903.langbar .lang { display: block; min-width: 2px; }
904.langs {
905 display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4);
906 margin: 0 0 var(--sp-3); font-size: var(--fs-1);
1062nav.subtabs {
1063 display: flex;
1064 gap: var(--sp-4);
1065 border-bottom: 1px solid var(--line);
1066 margin: 0 0 var(--sp-4);
9071067}
908.langs .lang-name { display: inline-flex; align-items: center; gap: var(--sp-1); }
909.langs .muted { color: var(--muted); }
910.langs .dot { width: 0.6rem; height: 0.6rem; border-radius: 50%; display: inline-block; }
911/* named where it reads as the language's own color, neutral otherwise */
912.lang { background: var(--neutral); }
913.lang-go { background: #00add8; }
914.lang-rust { background: #dea584; }
915.lang-c, .lang-c- { background: #555555; }
916.lang-python { background: #3572a5; }
917.lang-javascript { background: #f1e05a; }
918.lang-typescript { background: #3178c6; }
919.lang-shell { background: #89e051; }
920.lang-ruby { background: #701516; }
921.lang-java { background: #b07219; }
922.lang-swift { background: #f05138; }
923.lang-html { background: #e34c26; }
924.lang-css { background: #563d7c; }
925.lang-org { background: #77aa99; }
926.lang-markdown { background: #083fa1; }
927.lang-emacs-lisp { background: #c065db; }
928.lang-nix { background: #7e7eff; }
929.lang-sql { background: #e38c00; }
930
931.contribs {
932 display: flex; flex-wrap: wrap; align-items: baseline;
933 gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--fs-1);
1068nav.subtabs a {
1069 display: inline-flex;
1070 align-items: center;
1071 gap: var(--sp-1);
1072 padding: var(--sp-2) 0 10px;
1073 color: var(--muted);
1074 font-size: var(--fs-2);
1075 border-bottom: 2px solid transparent;
1076 margin-bottom: -1px;
9341077}
935.contribs .label { color: var(--muted); }
1078nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1079nav.subtabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); }
1080nav.subtabs a i { font-style: normal; color: var(--muted); margin-left: 4px; }
1081
1082/* ---- diffs and code ---- */
1083p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1084p.diffstat .add { color: var(--ok); }
1085p.diffstat .del { color: var(--bad); }
9361086
937/* diffs: one foldable section per file, a table so the line-number
938 gutters stay put while the code scrolls */
9391087details.difffold {
9401088 border: 1px solid var(--line);
941 border-radius: var(--r-md);
1089 border-radius: var(--r-card);
9421090 margin: 0 0 var(--sp-3);
943 background: var(--code-bg);
1091 background: var(--inset);
1092 overflow: hidden;
9441093}
9451094details.difffold summary {
946 cursor: pointer;
9471095 display: flex;
9481096 align-items: baseline;
9491097 gap: var(--sp-3);
9501098 padding: var(--sp-2) var(--sp-3);
951 list-style: none;
1099 background: var(--surface);
9521100 font-size: var(--fs-2);
1101 cursor: pointer;
1102 list-style: none;
9531103}
9541104details.difffold[open] summary { border-bottom: 1px solid var(--line); }
9551105details.difffold summary::-webkit-details-marker { display: none; }
9561106/* flex summaries lose the native disclosure marker; draw our own */
9571107details.difffold summary::before { content: "\25b8"; color: var(--muted); }
9581108details.difffold[open] summary::before { content: "\25be"; }
959details.difffold summary:hover { background: var(--fill-subtle); }
960summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; }
961summary .fpath .was { color: var(--muted); }
962summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; }
1109details.difffold summary:hover { background: var(--hover); }
1110details.difffold summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; }
1111details.difffold summary .fpath .was { color: var(--muted); }
1112details.difffold summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; }
9631113details.difffold summary .add { color: var(--ok); }
9641114details.difffold summary .del { color: var(--bad); }
9651115details.difffold > .none { padding: var(--sp-3); margin: 0; }
966details.difffold .tablewrap { border-radius: 0 0 var(--r-md) var(--r-md); }
1116details.difffold .tablewrap { background: none; border: 0; border-radius: 0; }
9671117
9681118table.difftable {
9691119 border-collapse: collapse;
@@ -972,12 +1122,8 @@ table.difftable {
9721122 font-size: var(--fs-1);
9731123 line-height: 1.5;
9741124}
975table.difftable td {
976 border: 0;
977 padding: 0;
978 vertical-align: top;
979 font-size: inherit;
980}
1125table.difftable td { border: 0; padding: 0; vertical-align: top; font-size: inherit; }
1126table.difftable tbody tr:hover td { background: none; }
9811127table.difftable td.ln {
9821128 width: 1%;
9831129 min-width: 2.5rem;
@@ -988,13 +1134,9 @@ table.difftable td.ln {
9881134 border-right: 1px solid var(--line);
9891135 white-space: nowrap;
9901136}
991/* not .code: that class is the blob/code-block style and carries its own
992 background, which painted over every row tint */
993table.difftable td.src {
994 padding: 0 var(--sp-3);
995 white-space: pre-wrap;
996 overflow-wrap: anywhere;
997}
1137/* not .code: that class carries its own ground, which painted over the
1138 row tints */
1139table.difftable td.src { padding: 0 var(--sp-3); white-space: pre-wrap; overflow-wrap: anywhere; }
9981140/* the marker is decoration, so it lives in CSS and stays out of a copied
9991141 selection */
10001142table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
@@ -1005,569 +1147,333 @@ table.difftable tr.del { background: var(--diff-del); }
10051147table.difftable tr.hunk td, table.difftable tr.dmeta td {
10061148 color: var(--muted);
10071149 padding: var(--sp-1) var(--sp-3);
1008 background: var(--fill-subtle);
1150 background: var(--surface);
10091151 border-top: 1px solid var(--line);
10101152 border-bottom: 1px solid var(--line);
10111153}
1012table.difftable tr.hunk td.src { color: var(--accent); }
1013table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--bg); }
1154table.difftable tr.hunk td.src { color: var(--link); }
1155table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--canvas); }
10141156/* a line number is the handle for commenting on that line; it stays a
1015 plain number until pointed at, so the gutter does not read as a wall of
1016 links */
1157 plain number until pointed at, so the gutter is not a wall of links */
10171158table.difftable td.ln a.cmt { color: inherit; text-decoration: none; }
10181159table.difftable td.ln a.cmt:hover,
1019table.difftable td.ln a.cmt:focus { color: var(--accent); text-decoration: underline; }
1160table.difftable td.ln a.cmt:focus { color: var(--link); text-decoration: underline; }
1161/* A linked line: f2-n17 on a diff, L17 on a file (see issue 118). */
1162.difftable tr:target td, .code .line:has(a:target) { background: color-mix(in srgb, var(--mark) 18%, transparent); }
1163.difftable tr:target td.ln, .code .line:has(a:target) .ln { border-left: 3px solid var(--mark); }
1164/* chroma writes the highlighted spans; the container only supplies the
1165 ground and the face */
1166.chroma { font-family: var(--mono); background: none; }
1167
1168.blame { border-radius: var(--r-card); }
1169.blamehunk { display: flex; gap: var(--sp-3); border-top: 1px solid var(--line); align-items: flex-start; }
1170.blamehunk:first-child { border-top: 0; }
1171.blameinfo { flex: none; width: 17rem; min-width: 0; padding: var(--sp-2) var(--sp-3); }
1172.blameinfo .subject { margin: 0; font-size: var(--fs-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1173.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1174.blamecode {
1175 flex: 1;
1176 margin: 0;
1177 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1178 background: var(--inset);
1179 border: 0;
1180 border-left: 1px solid var(--line);
1181 border-radius: 0;
1182 overflow-x: auto;
1183 align-self: stretch;
1184}
1185.lineno {
1186 display: inline-block;
1187 min-width: 3.5em;
1188 padding-right: 1em;
1189 text-align: right;
1190 color: var(--muted);
1191 user-select: none;
1192}
10201193
1021/* badges: signature and check states. Semantic colors stay distinct:
1022 green verified/success, amber pending/stale, red bad/failure, muted
1023 unsigned. */
1024.badge, .chip {
1025 --chip: var(--neutral);
1194/* ---- chips and badges ---- */
1195.chip, .badge {
1196 --c: var(--neutral);
10261197 display: inline-block;
1027 padding: 0.05rem 0.55rem;
1028 border-radius: var(--r-pill);
1198 padding: 1px 8px;
1199 border-radius: var(--r-ctl);
10291200 font-size: var(--fs-0);
10301201 font-weight: 500;
10311202 line-height: 1.5;
1032 color: var(--chip);
1033 border: 1px solid color-mix(in srgb, var(--chip) 35%, transparent);
1034 background: color-mix(in srgb, var(--chip) 7%, transparent);
1203 color: var(--c);
1204 border: 1px solid color-mix(in srgb, var(--c) 40%, transparent);
1205 background: color-mix(in srgb, var(--c) 10%, transparent);
10351206 white-space: nowrap;
10361207 vertical-align: middle;
10371208}
1038.chip-open { --chip: var(--ok); }
1039.chip-closed { --chip: var(--bad); }
1040.chip-merged, .chip-done { --chip: var(--done); }
1041.chip-neutral, .chip-source_gone { --chip: var(--neutral); }
1042.chip-stale { --chip: var(--warn); }
1209.chip-open { --c: var(--ok); }
1210.chip-closed { --c: var(--bad); }
1211.chip-merged, .chip-done { --c: var(--done); }
1212.chip-neutral, .chip-source_gone { --c: var(--neutral); }
1213.chip-stale { --c: var(--warn); }
1214.chip.topic { --c: var(--link); }
1215.chip.topic:hover { text-decoration: none; background: color-mix(in srgb, var(--c) 18%, transparent); }
1216/* a label carries its own colour inline, from the label's hex */
10431217.chip.label { font-weight: 500; }
1044.chip.topic { --chip: var(--accent); }
1045.repohead .topics { margin: 0 0 var(--sp-2); }
1046.badge-verified { --chip: var(--ok); }
1047.badge-unsigned { --chip: var(--neutral); }
1048.badge-signed_unknown_key { --chip: var(--warn); }
1049.badge-signed_email_mismatch { --chip: var(--bad); }
1050.badge-signed_key_expired { --chip: var(--warn); }
1051.badge-signed_key_revoked { --chip: var(--bad); }
1052.badge-bad_signature { --chip: var(--bad); }
1053.badge.check-success { --chip: var(--ok); }
1054.badge.check-pending { --chip: var(--warn); }
1055.badge.check-failure, .badge.check-error { --chip: var(--bad); }
1056.badge.check-cancelled, .chip.check-cancelled { --chip: var(--neutral); }
1057.badge.check-skipped, .chip.check-skipped { --chip: var(--neutral); }
1058.badge.check-running, .chip.check-running { --chip: var(--warn); }
1059.chip.check-success { --chip: var(--ok); }
1060.chip.check-pending { --chip: var(--warn); }
1061.chip.check-failure { --chip: var(--bad); }
1062pre.buildlog { max-height: 40rem; overflow: auto; }
1218.badge-verified { --c: var(--ok); }
1219.badge-unsigned { --c: var(--neutral); }
1220.badge-signed_unknown_key, .badge-signed_key_expired { --c: var(--warn); }
1221.badge-signed_email_mismatch, .badge-signed_key_revoked, .badge-bad_signature { --c: var(--bad); }
1222.badge.check-success, .chip.check-success { --c: var(--ok); }
1223.badge.check-pending, .chip.check-pending,
1224.badge.check-running, .chip.check-running { --c: var(--warn); }
1225.badge.check-failure, .chip.check-failure,
1226.badge.check-error, .chip.check-error { --c: var(--bad); }
1227.badge.check-cancelled, .chip.check-cancelled,
1228.badge.check-skipped, .chip.check-skipped { --c: var(--neutral); }
10631229span.check-success { color: var(--ok); }
1064span.check-pending { color: var(--warn); }
1230span.check-pending, span.check-running { color: var(--warn); }
10651231span.check-failure, span.check-error { color: var(--bad); }
10661232
1067/* issue and MR listings */
1068.listhead {
1069 display: flex;
1070 align-items: baseline;
1071 gap: var(--sp-4);
1072 flex-wrap: wrap;
1073}
1074.listhead h2 { margin-bottom: var(--sp-2); }
1075nav.filters { display: flex; gap: var(--sp-1); }
1076nav.filters a {
1077 color: var(--muted);
1078 font-size: var(--fs-2);
1079 padding: 0.05rem var(--sp-2);
1080 border-radius: var(--r-pill);
1081}
1082nav.filters a:hover { color: var(--fg); background: var(--hover); text-decoration: none; }
1083nav.filters a.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
1084
1085ul.issuelist {
1086 list-style: none;
1087 margin: var(--sp-2) 0;
1088 padding: 0;
1089 background: var(--surface);
1090 border: 1px solid var(--line);
1091 border-radius: var(--r-lg);
1092 overflow: hidden;
1093}
1094ul.issuelist li {
1095 display: flex;
1096 align-items: baseline;
1097 gap: var(--sp-3);
1098 padding: var(--sp-3) var(--sp-4);
1099 border-bottom: 1px solid var(--faint);
1100}
1101ul.issuelist li:last-child { border-bottom: none; }
1102ul.issuelist li:hover { background: var(--hover); }
1103ul.issuelist li.empty { display: block; color: var(--muted); }
1104ul.issuelist .issuemain { flex: 1; min-width: 0; }
1105ul.issuelist p { margin: 0; }
1106ul.issuelist .title a { color: var(--fg); font-weight: 550; }
1107ul.issuelist .title a:hover { color: var(--accent); }
1108
1109/* releases */
1110article.release {
1111 background: var(--surface);
1233a.memberchip {
1234 display: inline-block;
11121235 border: 1px solid var(--line);
1113 border-radius: var(--r-lg);
1114 padding: var(--sp-3) var(--sp-4);
1115 margin: var(--sp-4) 0;
1236 border-radius: var(--r-ctl);
1237 padding: 1px 8px;
1238 margin: 0 2px 2px 0;
1239 color: var(--fg);
1240 font-size: var(--fs-1);
11161241}
1117.releasehead { background: none; border: 0; padding: 0; }
1118.releasehead h3 { margin: 0 0 var(--sp-1); }
1119.releasehead .meta { margin: 0 0 var(--sp-2); }
1120table.assets { margin-top: var(--sp-2); }
1121table.assets td.size { color: var(--muted); white-space: nowrap; text-align: right; }
1122table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
1242a.memberchip:hover { text-decoration: none; border-color: var(--link); color: var(--link); }
1243a.memberchip .role { color: var(--muted); }
11231244
1124/* milestones */
1125ul.milestonelist {
1126 list-style: none;
1127 margin: var(--sp-2) 0;
1128 padding: 0;
1245.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); }
1246.pathbar .spacer { flex: 1; }
1247.pathbar .actions { display: flex; gap: var(--sp-2); }
1248.crumbs { color: var(--muted); }
1249.crumbs a { color: var(--link); }
1250.crumbs strong { color: var(--fg); }
1251.refchip {
1252 display: inline-flex;
1253 align-items: center;
1254 gap: 6px;
1255 height: 32px;
1256 padding: 0 10px;
1257 background: var(--canvas);
11291258 border: 1px solid var(--line);
1130 border-radius: var(--r-lg);
1131 overflow: hidden;
1132}
1133ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1134ul.milestonelist li:last-child { border-bottom: none; }
1135ul.milestonelist li.empty { color: var(--muted); }
1136ul.milestonelist p { margin: 0; }
1137ul.milestonelist .title { font-weight: 550; }
1138.progress {
1139 height: 6px;
1140 background: var(--faint);
1141 border-radius: var(--r-pill);
1142 margin-top: var(--sp-2);
1143 overflow: hidden;
1144 max-width: 24rem;
1145}
1146.progress .bar { height: 100%; background: var(--ok); }
1147.listhead .spacer { flex: 1; }
1148
1149/* issue / MR detail */
1150h2.issuetitle { margin-bottom: var(--sp-1); font-size: var(--fs-5); }
1151.issuenumber { color: var(--muted); font-weight: 400; }
1152.issuemeta { color: var(--muted); font-size: var(--fs-2); margin-top: 0; }
1153.review { font-size: var(--fs-2); }
1154
1155/* comment cards; discussion stays at a readable measure */
1156article.comment, form.commentform {
1157 max-width: 48rem;
1158}
1159article.comment {
1160 border: 1px solid var(--faint);
1161 border-radius: var(--r-lg);
1162 margin: var(--sp-4) 0;
1163}
1164article.comment .commenthead {
1165 background: var(--surface);
1166 border-bottom: 1px solid var(--faint);
1167 border-radius: var(--r-lg) var(--r-lg) 0 0;
1168 padding: var(--sp-2) var(--sp-4);
1169 font-size: var(--fs-2);
1170}
1171article.comment .commenthead .when { color: var(--muted); }
1172article.comment .rendered { padding: 0 var(--sp-4); }
1173article.comment .rendered > :first-child { margin-top: var(--sp-3); }
1174article.comment .rendered > :last-child { margin-bottom: var(--sp-3); }
1175form.commentform { margin: var(--sp-4) 0; }
1176details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
1177details.editbox summary { cursor: pointer; color: var(--muted); font-size: var(--fs-2); }
1178details.editbox summary:hover { color: var(--accent); }
1179details.editbox input[type="text"] { width: 100%; }
1180.syscomment {
1181 max-width: 48rem;
1182 color: var(--muted);
1259 border-radius: var(--r-ctl);
1260 font-family: var(--mono);
11831261 font-size: var(--fs-2);
1184 margin: var(--sp-3) 0;
1185 padding-left: var(--sp-4);
1186 border-left: 3px solid var(--faint);
1187}
1188.syscomment p { display: inline; margin: 0; }
1189
1190/* review threads under diff lines */
1191.thread {
1192 border: 1px solid var(--faint);
1193 border-left: 3px solid var(--accent);
1194 border-radius: var(--r-md);
1195 padding: var(--sp-2) var(--sp-4);
1196 margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1197}
1198.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1199/* an unsubmitted comment is the viewer's own note, not the conversation */
1200.thread.pending { border-left-color: var(--neutral); border-left-style: dashed; }
1201.thread.stale { border-left-color: var(--warn); }
1202.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1203.thread .when { color: var(--muted); }
1204.thread .rendered p { margin: var(--sp-1) 0; }
1205.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1206.thread.composing { border-left-color: var(--mark); }
1207.thread details.threadreply { margin: var(--sp-2) 0 0; }
1208.thread details.threadreply > summary { color: var(--accent); font-size: var(--fs-1); cursor: pointer; }
1209.thread textarea { width: 100%; }
1210.thread.composing p, .thread details.threadreply p { margin: var(--sp-2) 0 0; }
1211
1212/* forms: every control shares one shell, so a select reads as a sibling
1213 of the text inputs beside it rather than as an OS control dropped in */
1214input, textarea, button, select { font: inherit; color: inherit; }
1215input[type="text"], input[type="search"], input[type="email"],
1216input[type="password"], input:not([type]), textarea, select {
1217 background: var(--bg);
1262 font-weight: 500;
12181263 color: var(--fg);
1219 border: 1px solid var(--line);
1220 border-radius: var(--r-md);
1221 padding: var(--sp-2) var(--sp-3);
1222 line-height: 1.4;
1223}
1224textarea { width: 100%; resize: vertical; }
1225textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
1226/* the native arrow cannot be restyled, so draw our own and match the
1227 inputs exactly; --chev carries the stroke colour per scheme */
1228select {
1229 appearance: none;
1230 padding-right: 1.9rem;
1231 background-image: var(--chev);
1232 background-repeat: no-repeat;
1233 background-position: right 0.6rem center;
1234 background-size: 0.62rem;
1235 cursor: pointer;
12361264}
1237input:hover, textarea:hover, select:hover { border-color: var(--muted); }
1238/* the global :focus-visible ring covers these; only the border moves */
1239input:focus, textarea:focus, select:focus { border-color: var(--accent); }
1240input[type="radio"] { accent-color: var(--fill); }
1241label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
1242label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
1243
1244/* A radio keeps the native control: a circle takes one answer, a square
1245 takes any number, and that shape is the cue that survives greyscale,
1246 high contrast and colour blindness. The checkbox is drawn instead,
1247 because at the size the OS renders it it reads as an afterthought
1248 beside the button it shares a row with. The square is kept square —
1249 the size changes, the cue does not. */
1250input[type="checkbox"] {
1251 appearance: none;
1252 flex: none;
1253 /* the height of a text input, a select and a button, so a settings row
1254 ends in one column of controls rather than a button and a speck */
1255 width: 2.5rem;
1256 height: 2.5rem;
1257 /* an empty box has nothing but its border to announce it, so the border
1258 is --muted rather than the --line the sized controls can afford */
1259 border: 1px solid var(--muted);
1260 border-radius: var(--r-sm);
1261 background: var(--bg);
1262 cursor: pointer;
1263}
1264input[type="checkbox"]:not(:checked):hover { border-color: var(--fg); }
1265input[type="checkbox"]:checked {
1266 background: var(--fill);
1267 border-color: var(--fill);
1268 /* the mark sits on the blue ground, so it is white in both schemes */
1269 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");
1270 background-repeat: no-repeat;
1271 background-position: center;
1272 background-size: 1.2rem;
1273}
1274
1275/* a segmented control for a small, mutually exclusive set: real radios
1276 underneath, so arrow keys and screen readers behave as they always did */
1277fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
1278fieldset.segmented legend {
1279 padding: 0;
1280 margin-bottom: var(--sp-2);
1281 color: var(--muted);
1282 font-size: var(--fs-2);
1283}
1284fieldset.segmented .options { display: inline-flex; }
1285fieldset.segmented label { gap: 0; }
1286fieldset.segmented input {
1265details.refmenu { position: relative; }
1266details.refmenu summary { cursor: pointer; list-style: none; }
1267details.refmenu summary::-webkit-details-marker { display: none; }
1268details.refmenu summary::after { content: " \25be"; color: var(--muted); }
1269details.refmenu .refdrop {
12871270 position: absolute;
1288 width: 1px;
1289 height: 1px;
1290 opacity: 0;
1291 pointer-events: none;
1292}
1293fieldset.segmented span {
1294 display: block;
1295 padding: var(--sp-2) var(--sp-4);
1271 z-index: 10;
1272 top: calc(100% + 4px);
1273 left: 0;
1274 min-width: 12rem;
1275 max-height: 20rem;
1276 overflow-y: auto;
1277 background: var(--canvas);
12961278 border: 1px solid var(--line);
1297 font-size: var(--fs-2);
1298 cursor: pointer;
1299}
1300fieldset.segmented label + label span { border-left: 0; }
1301fieldset.segmented label:first-child span { border-radius: var(--r-sm) 0 0 var(--r-sm); }
1302fieldset.segmented label:last-child span { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
1303fieldset.segmented span:hover { border-color: var(--muted); }
1304fieldset.segmented input:checked + span {
1305 background: var(--fill);
1306 border-color: var(--fill);
1307 color: #ffffff;
1308 font-weight: 600;
1309}
1310fieldset.segmented input:focus-visible + span {
1311 outline: 2px solid var(--accent);
1312 outline-offset: 2px;
1313}
1314
1315/* remaining input states */
1316::placeholder { color: var(--muted); opacity: 1; }
1317::selection { background: var(--fill); color: #ffffff; }
1318/* :user-invalid, not :invalid — a required field is invalid the moment
1319 the page loads, and colouring it red before anyone has typed is a
1320 scolding, not a hint */
1321input:user-invalid, textarea:user-invalid {
1322 border-color: var(--bad);
1323}
1324.hint { display: block; color: var(--muted); font-size: var(--fs-1); margin-top: var(--sp-1); }
1325button {
1326 background: var(--fill);
1327 color: #ffffff;
1328 border: 1px solid var(--fill-edge);
1329 border-radius: var(--r-md);
1330 padding: var(--sp-2) var(--sp-4);
1331 font-weight: 600;
1332 cursor: pointer;
1279 border-radius: var(--r-card);
1280 box-shadow: var(--shadow);
1281 padding: var(--sp-1) 0;
13331282}
1334button:hover { filter: brightness(1.15); }
1335
1336/* 404 */
1337.notfound { text-align: center; padding: var(--sp-6) 0; }
1338.notfound .bigcode {
1283details.refmenu .refdrop a {
1284 display: block;
1285 padding: var(--sp-1) var(--sp-3);
1286 color: var(--fg);
13391287 font-family: var(--mono);
1340 font-size: var(--fs-7);
1341 color: var(--faint);
1342 -webkit-text-stroke: 1px var(--line);
1343 margin: 0;
1344 line-height: 1;
1288 font-size: var(--fs-1);
13451289}
1346.notfound h1 { margin-top: var(--sp-3); }
1347
1348/* footer */
1349footer {
1290details.refmenu .refdrop a:hover { background: var(--hover); text-decoration: none; }
1291details.refmenu .refdrop a.allrefs {
1292 color: var(--link);
1293 font-family: var(--sans);
13501294 border-top: 1px solid var(--faint);
1351 padding: var(--sp-4) var(--sp-5) var(--sp-5);
1352 width: 100%;
1353 color: var(--muted);
1354 font-size: var(--fs-1);
1295 margin-top: var(--sp-1);
13551296}
1356footer p { margin: 0; }
1357footer a { color: var(--muted); text-decoration: underline; }
1358footer a:hover { color: var(--accent); }
13591297
1360/* search */
1361form.searchform {
1362 display: flex;
1363 gap: var(--sp-2);
1364 margin: var(--sp-3) 0 var(--sp-4);
1365}
1366form.searchform input[type="search"] { flex: 1; max-width: 32rem; }
1367form.searchform.compact { margin: 0; }
1368form.searchform.compact input[type="search"] {
1369 padding: var(--sp-1) var(--sp-3);
1370 font-size: var(--fs-2);
1371 min-width: 18rem;
1372}
1373ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1374ul.matchlist li { margin-bottom: var(--sp-3); }
1375ul.matchlist .matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1376pre.matchline {
1377 background: var(--code-bg);
1378 border: 1px solid var(--faint);
1379 border-radius: var(--r-md);
1380 padding: var(--sp-1) var(--sp-3);
1381 margin: var(--sp-1) 0 0;
1382 overflow-x: auto;
1383}
1384pre.matchline mark {
1385 background: color-mix(in srgb, var(--warn) 25%, transparent);
1386 color: inherit;
1387 border-radius: 2px;
1298/* ---- repository facts ---- */
1299.facts { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); margin: var(--sp-5) 0 var(--sp-4); max-width: 72rem; }
1300.facts h2 {
1301 margin: 0 0 var(--sp-2);
1302 font-size: var(--fs-1);
1303 font-weight: 500;
1304 letter-spacing: 0.08em;
1305 text-transform: uppercase;
1306 color: var(--muted);
13881307}
1308.clone { margin: 0 0 var(--sp-3); }
1309.clone label { font-size: var(--fs-1); color: var(--muted); font-weight: 500; margin-bottom: 2px; }
1310.clone pre { margin-bottom: var(--sp-3); user-select: all; }
1311.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); }
1312.factgrid b { font-weight: 600; }
1313.factgrid a { color: var(--fg); }
1314.factgrid a:hover { color: var(--link); }
1315.counts { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin: 0 0 var(--sp-3); font-size: var(--fs-2); }
1316.counts a { color: var(--fg); }
1317.counts a:hover { color: var(--link); }
1318.counts strong { font-weight: 600; }
1319.fact { color: var(--muted); }
1320.langbar { display: flex; height: 8px; margin: 0 0 var(--sp-2); border-radius: var(--r-ctl); overflow: hidden; gap: 1px; background: var(--faint); }
1321.langbar .lang { display: block; height: 100%; min-width: 2px; }
1322.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); }
1323.langs .lang-name { display: inline-flex; align-items: center; gap: var(--sp-1); }
1324.langs .dot { width: 8px; height: 8px; }
1325/* named where it reads as the language's own colour, neutral otherwise */
1326.lang { background: var(--neutral); }
1327.lang-go { background: var(--lang-go); }
1328.lang-rust { background: var(--lang-rust); }
1329.lang-c, .lang-c- { background: var(--lang-c); }
1330.lang-python { background: var(--lang-python); }
1331.lang-javascript { background: var(--lang-javascript); }
1332.lang-typescript { background: var(--lang-typescript); }
1333.lang-shell { background: var(--lang-shell); }
1334.lang-ruby { background: var(--lang-ruby); }
1335.lang-java { background: var(--lang-java); }
1336.lang-swift { background: var(--lang-swift); }
1337.lang-html { background: var(--lang-html); }
1338.lang-css { background: var(--lang-css); }
1339.lang-org { background: var(--lang-org); }
1340.lang-markdown { background: var(--lang-markdown); }
1341.lang-emacs-lisp { background: var(--lang-emacs-lisp); }
1342.lang-nix { background: var(--lang-nix); }
1343.lang-sql { background: var(--lang-sql); }
1344.contribs { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3); margin: 0; font-size: var(--fs-1); }
1345.contribs .label { color: var(--muted); }
1346.teambody { padding: var(--sp-3); }
1347.teambody .memberchip { margin-right: var(--sp-2); }
13891348
1390/* wiki */
1349/* ---- landing ---- */
1350/* the width class on main carries this too; the cap here keeps the page
1351 readable on the templates that do not set one yet */
1352.landing { max-width: 48rem; padding: var(--sp-6) 0; }
1353.landing h1 { font-size: var(--fs-6); display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
1354.lede { font-size: var(--fs-4); color: var(--muted); line-height: 1.5; max-width: 40rem; margin: 0 0 var(--sp-5); }
1355pre.quickstart { margin: 0 0 var(--sp-4); }
1356.shot { border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; margin: var(--sp-5) 0; box-shadow: var(--shadow); }
1357.shot img { display: block; width: 100%; }
1358.facets { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); margin: var(--sp-5) 0; }
1359.facets h2 { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
1360.facets p { color: var(--muted); font-size: var(--fs-2); margin: 0; }
1361.routes { display: flex; gap: var(--sp-3); align-items: center; margin: var(--sp-5) 0 var(--sp-3); }
1362.explorelink { font-weight: 500; }
1363
1364/* ---- profile ---- */
1365.profilehead { border-bottom: 1px solid var(--faint); padding-bottom: var(--sp-4); margin-bottom: var(--sp-4); }
1366.profilehead h1 { margin: 0 0 var(--sp-1); }
1367.profilehead .lede { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
1368.profilehead .meta { margin: var(--sp-1) 0 0; }
1369.activity { margin-bottom: var(--sp-5); }
1370h2 .count { background: none; color: var(--muted); font-weight: 400; font-size: var(--fs-2); margin-left: var(--sp-2); padding: 0; }
1371/* 53 week columns x 7 day rows, tinted with the link blue */
1372.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
1373.actgraph { display: flex; gap: 3px; width: max-content; }
1374.actweek { display: flex; flex-direction: column; gap: 3px; }
1375.actday { width: 11px; height: 11px; border-radius: 2px; background: var(--faint); }
1376.actday.pad { background: transparent; }
1377.actday.l0 { background: var(--faint); }
1378.actday.l1 { background: color-mix(in srgb, var(--link) 25%, var(--canvas)); }
1379.actday.l2 { background: color-mix(in srgb, var(--link) 50%, var(--canvas)); }
1380.actday.l3 { background: color-mix(in srgb, var(--link) 75%, var(--canvas)); }
1381.actday.l4 { background: var(--link); }
1382
1383/* ---- wiki ---- */
13911384.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
13921385.wikipage { flex: 1; min-width: 0; }
1393.wikinav { flex: none; width: 13rem; padding-top: var(--sp-4); }
1386.wikinav { flex: none; width: 14rem; }
13941387.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1395.wikinav li a { display: block; padding: 0.15rem 0; color: var(--fg); }
1396.wikinav li a:hover { color: var(--accent); text-decoration: none; }
1397.wikinav li a.active { color: var(--accent); font-weight: 550; }
1398@media (max-width: 40rem) {
1399 /* Column direction + the desktop align-items:flex-start lets .wikipage
1400 take its content's intrinsic width, overflowing the viewport (and
1401 triggering iOS font inflation). Stretch pins it to the container. */
1402 .wikilayout { flex-direction: column; align-items: stretch; }
1403 .wikinav { width: auto; padding-top: 0; }
1388.wikinav li a {
1389 display: block;
1390 padding: 5px var(--sp-2);
1391 border-radius: var(--r-ctl);
1392 color: var(--fg);
1393 font-size: var(--fs-2);
14041394}
1395.wikinav li a:hover { background: var(--hover); color: var(--fg); text-decoration: none; }
1396.wikinav li a.active { background: var(--surface); color: var(--link); font-weight: 500; }
14051397
1406/* blame */
1407.blame {
1408 border: 1px solid var(--line);
1409 border-radius: var(--r-md);
1410 overflow: hidden;
1411}
1412.blamehunk {
1413 display: flex;
1414 gap: var(--sp-3);
1415 border-top: 1px solid var(--line);
1416 align-items: flex-start;
1417}
1418.blamehunk:first-child { border-top: none; }
1419.blameinfo {
1420 flex: none;
1421 width: 17rem;
1422 padding: var(--sp-2) var(--sp-3);
1423 min-width: 0;
1424}
1425.blameinfo .subject {
1426 margin: 0;
1427 font-size: var(--fs-1);
1428 white-space: nowrap;
1429 overflow: hidden;
1430 text-overflow: ellipsis;
1431}
1432.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1433.blamecode {
1434 flex: 1;
1435 margin: 0;
1436 padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1437 overflow-x: auto;
1438 border-left: 1px solid var(--line);
1439 align-self: stretch;
1398/* ---- misc ---- */
1399.meta { color: var(--muted); font-size: var(--fs-1); }
1400.muted { color: var(--muted); }
1401.desc, td.desc { color: var(--muted); }
1402.spacer { flex: 1; }
1403.compact { margin: 0; }
1404.name { min-width: 0; }
1405svg.icon { vertical-align: -0.125em; }
1406.sep { color: var(--muted); }
1407.owner { color: var(--muted); }
1408.title { margin: 0; }
1409.subject { min-width: 0; }
1410.sha { font-family: var(--mono); }
1411.when { color: var(--muted); }
1412.who { font-weight: 500; }
1413.was { color: var(--muted); }
1414.role { color: var(--muted); }
1415.age { color: var(--muted); }
1416.size { color: var(--muted); }
1417.review { font-size: var(--fs-2); }
1418
1419/* ---- breakpoints ---- */
1420@media (max-width: 62rem) {
1421 .withaside { grid-template-columns: 1fr; }
1422 .withaside .aside { order: -1; }
14401423}
1441.lineno {
1442 display: inline-block;
1443 min-width: 3.5em;
1444 padding-right: 1em;
1445 text-align: right;
1446 color: var(--muted);
1447 user-select: none;
1424
1425@media (max-width: 52rem) {
1426 /* the rail becomes a single strip, not a wall of links */
1427 .shell { display: block; }
1428 .rail {
1429 width: auto;
1430 height: auto;
1431 position: static;
1432 flex-direction: row;
1433 align-items: center;
1434 gap: var(--sp-2);
1435 border-right: 0;
1436 border-bottom: 1px solid var(--shell-line);
1437 overflow-x: auto;
1438 }
1439 a.brand { padding: var(--sp-2) var(--sp-3); }
1440 .railbody { flex: 1; overflow: visible; padding: 0; display: flex; align-items: center; }
1441 form.railsearch { margin: 0 var(--sp-2); }
1442 form.railsearch input[type="search"] { min-width: 8rem; }
1443 /* pinned repos and the review queue both live on the dashboard, so the
1444 strip keeps only what has nowhere else to go */
1445 .railgroup { display: none; }
1446 ul.raillist { display: flex; margin: 0; }
1447 ul.raillist a { border-radius: 0; border-bottom: 2px solid transparent; padding: var(--sp-2) var(--sp-3); }
1448 ul.raillist a[aria-current] { box-shadow: none; border-bottom-color: var(--shell-mark); }
1449 .railfoot { border-top: 0; padding: var(--sp-2); }
1450 .railpinned { border-top: 0; padding: 0; }
1451 main.content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
1452 footer { padding: var(--sp-4); }
1453 .repohead { padding: var(--sp-3) var(--sp-4) 0; }
1454 /* seven tabs do not fit a phone in one row; a hidden scrollbar made the
1455 ones past the edge look absent. Two rows show all of them. */
1456 nav.tabs { flex-wrap: wrap; overflow: visible; }
1457 .facts { grid-template-columns: 1fr; }
14481458}
14491459
1450/* mobile */
14511460@media (max-width: 40rem) {
1452 .thread { margin-left: var(--sp-3); }
1453 /* the commit subject is the widest thing in the listing and the one
1461 .facets { grid-template-columns: 1fr; gap: var(--sp-4); }
1462 .wikilayout { flex-direction: column; align-items: stretch; }
1463 .wikinav { width: auto; }
1464 form.setform { grid-template-columns: 1fr; gap: var(--sp-2); }
1465 form.setform label { margin-top: 0; }
1466 /* the commit subject is the widest thing in a file table and the one
14541467 column a phone can do without: the tipbar above already names the
1455 latest commit. */
1468 latest commit */
14561469 table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
14571470 table.tree td.mode, table.tree th.mode { display: none; }
1458 .clone, .pathbar { overflow-wrap: anywhere; }
1459 .readme, .code { padding: var(--sp-3); }
1471 .clone pre { white-space: pre-wrap; word-break: break-all; }
1472 .pathbar { overflow-wrap: anywhere; }
1473 .readme .cardbody, .code { padding: var(--sp-3); }
1474 .thread { margin-left: var(--sp-3); }
14601475 .blamehunk { flex-direction: column; gap: 0; }
14611476 .blameinfo { width: auto; }
1462 .blamecode { border-left: none; padding-left: var(--sp-3); width: 100%; }
1463 .cardhead {
1464 margin: calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) var(--sp-3);
1465 padding: var(--sp-2) var(--sp-3);
1466 }
1477 .blamecode { border-left: 0; padding-left: var(--sp-3); width: 100%; }
1478 .factgrid { grid-template-columns: repeat(2, auto); }
14671479}
1468
1469/* tree listing: the last commit is what a file table is scanned for, so
1470 it leads. The file's own facts moved to the blob page. */
1471.tipbar {
1472 display: flex;
1473 align-items: center;
1474 gap: var(--sp-3);
1475 padding: var(--sp-2) var(--sp-4);
1476 background: var(--hover);
1477 border: 1px solid var(--line);
1478 border-bottom: 0;
1479 border-radius: var(--r-lg) var(--r-lg) 0 0;
1480 font-size: var(--fs-2);
1481}
1482.tipbar .who { font-weight: 600; }
1483.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1484.tipbar .subject:hover { color: var(--accent); }
1485.tipbar .spacer { flex: 1; }
1486.tipbar .age { color: var(--muted); white-space: nowrap; }
1487.tipbar + table.tree { border-radius: 0 0 var(--r-lg) var(--r-lg); }
1488table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
1489table.tree td.lastcommit a { color: var(--muted); display: block; overflow: hidden;
1490 text-overflow: ellipsis; white-space: nowrap; }
1491table.tree td.lastcommit a:hover { color: var(--accent); }
1492table.tree th.age, table.tree td.age {
1493 text-align: right;
1494 white-space: nowrap;
1495 color: var(--muted);
1496 font-variant-numeric: tabular-nums;
1497}
1498table.tree td.name { width: 25%; white-space: nowrap; }
1499table.tree td.name.dir a { color: var(--accent); }
1500p.clone { margin: 0 0 var(--sp-3); }
1501p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1502.pathbar .actions { font-size: var(--fs-1); color: var(--muted); }
1503.snippetfile { margin-bottom: var(--sp-5); }
1504
1505/* merge request: a two-column split, so state has somewhere to live that
1506 is not a run-on sentence under the title */
1507.withaside {
1508 display: grid;
1509 grid-template-columns: minmax(0, 1fr) 15rem;
1510 gap: var(--sp-5);
1511 align-items: start;
1512}
1513.withaside .mainside { min-width: 0; }
1514@media (max-width: 62rem) { .withaside { grid-template-columns: 1fr; } }
1515
1516.aside { font-size: var(--fs-2); }
1517.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1518.aside .grp:first-child { border-top: 0; padding-top: 0; }
1519.aside h2 {
1520 margin: 0 0 var(--sp-2);
1521 font-family: var(--mono);
1522 font-size: var(--fs-0);
1523 font-weight: 500;
1524 letter-spacing: 0.1em;
1525 text-transform: uppercase;
1526 color: var(--muted);
1527}
1528.aside .row { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1529.aside .row:last-child { margin-bottom: 0; }
1530.aside .none { color: var(--muted); }
1531/* a row's second line: when it happened, under what it happened to. The
1532 extra gap keeps the pair reading as one entry. */
1533.aside .row .sub { flex-basis: 100%; color: var(--muted); font-size: var(--fs-0); }
1534.aside .row:has(.sub) { margin-bottom: var(--sp-2); }
1535.aside .dot { width: 0.45rem; height: 0.45rem; flex: none; border-radius: 50%; background: var(--muted); }
1536.aside .dot.ok { background: var(--ok); }
1537.aside .dot.bad { background: var(--bad); }
1538.aside .dot.pend { background: var(--mark); }
1539
1540/* sub-navigation within an item; orange marks position as it does above */
1541nav.subtabs {
1542 display: flex;
1543 gap: var(--sp-4);
1544 border-bottom: 1px solid var(--line);
1545 margin: 0 0 var(--sp-4);
1546}
1547nav.subtabs a {
1548 display: inline-flex;
1549 align-items: center;
1550 gap: var(--sp-2);
1551 padding: 0 0 var(--sp-2);
1552 color: var(--muted);
1553 font-size: var(--fs-2);
1554 border-bottom: 2px solid transparent;
1555 margin-bottom: -1px;
1556}
1557nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1558nav.subtabs a[aria-current] { color: var(--fg); font-weight: 700; border-bottom-color: var(--mark); }
1559nav.subtabs a i {
1560 font-style: normal;
1561 font-family: var(--mono);
1562 font-size: var(--fs-0);
1563 background: var(--hover);
1564 border-radius: var(--r-sm);
1565 padding: 0 0.35rem;
1566}
1567p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1568p.diffstat .add { color: var(--ok); }
1569p.diffstat .del { color: var(--bad); }
1570
1571/* file edit form */
1572.editform textarea { width: 100%; }
1573.editform input[name="message"] { width: 60%; }