internal/web/static/style.css

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

1840 lines · 74186 bytes

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