internal/web/static/style.css

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

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