internal/web/static/style.css

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

1539 lines · 53306 bytes

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