internal/web/static/style.css

f327db6192d9a0877606a40385b24c0cda29fd2d
gitbay/internal/web/static/style.css history · blame · raw

1803 lines · 72046 bytes

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