internal/web/static/style.css

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