internal/web/static/style.css

1533 lines · 58231 bytes

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