internal/web/static/style.css

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

1487 lines · 50290 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 summary .add { color: var(--ok); }
 921details.difffold summary .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}
 948/* not .code: that class is the blob/code-block style and carries its own
 949   background, which painted over every row tint */
 950table.difftable td.src {
 951  padding: 0 var(--sp-3);
 952  white-space: pre-wrap;
 953  overflow-wrap: anywhere;
 954}
 955/* the marker is decoration, so it lives in CSS and stays out of a copied
 956   selection */
 957table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
 958table.difftable tr.del td.src::before { content: "\2212"; color: var(--bad); }
 959table.difftable tr.ctx td.src::before { content: " "; }
 960table.difftable tr.add { background: var(--diff-add); }
 961table.difftable tr.del { background: var(--diff-del); }
 962table.difftable tr.hunk td, table.difftable tr.dmeta td {
 963  color: var(--muted);
 964  padding: var(--sp-1) var(--sp-3);
 965  background: var(--fill-subtle);
 966  border-top: 1px solid var(--line);
 967  border-bottom: 1px solid var(--line);
 968}
 969table.difftable tr.hunk td.src { color: var(--accent); }
 970table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--bg); }
 971
 972/* badges: signature and check states. Semantic colors stay distinct:
 973   green verified/success, amber pending/stale, red bad/failure, muted
 974   unsigned. */
 975.badge, .chip {
 976  --chip: var(--neutral);
 977  display: inline-block;
 978  padding: 0.05rem 0.55rem;
 979  border-radius: var(--r-pill);
 980  font-size: var(--fs-0);
 981  font-weight: 500;
 982  line-height: 1.5;
 983  color: var(--chip);
 984  border: 1px solid color-mix(in srgb, var(--chip) 35%, transparent);
 985  background: color-mix(in srgb, var(--chip) 7%, transparent);
 986  white-space: nowrap;
 987  vertical-align: middle;
 988}
 989.chip-open { --chip: var(--ok); }
 990.chip-closed { --chip: var(--bad); }
 991.chip-merged, .chip-done { --chip: var(--done); }
 992.chip-neutral, .chip-source_gone { --chip: var(--neutral); }
 993.chip-stale { --chip: var(--warn); }
 994.chip.label { font-weight: 500; }
 995.chip.topic { --chip: var(--accent); }
 996.repohead .topics { margin: 0 0 var(--sp-2); }
 997.repohead .mirrorline { margin: 0 0 var(--sp-2); }
 998.mirrorerr { color: var(--bad); }
 999.badge-verified { --chip: var(--ok); }
1000.badge-unsigned { --chip: var(--neutral); }
1001.badge-signed_unknown_key { --chip: var(--warn); }
1002.badge-signed_email_mismatch { --chip: var(--bad); }
1003.badge-signed_key_expired { --chip: var(--warn); }
1004.badge-signed_key_revoked { --chip: var(--bad); }
1005.badge-bad_signature { --chip: var(--bad); }
1006.badge.check-success { --chip: var(--ok); }
1007.badge.check-pending { --chip: var(--warn); }
1008.badge.check-failure, .badge.check-error { --chip: var(--bad); }
1009.badge.check-running, .chip.check-running { --chip: var(--warn); }
1010.chip.check-success { --chip: var(--ok); }
1011.chip.check-pending { --chip: var(--warn); }
1012.chip.check-failure { --chip: var(--bad); }
1013pre.buildlog { max-height: 40rem; overflow: auto; }
1014span.check-success { color: var(--ok); }
1015span.check-pending { color: var(--warn); }
1016span.check-failure, span.check-error { color: var(--bad); }
1017
1018/* issue and MR listings */
1019.listhead {
1020  display: flex;
1021  align-items: baseline;
1022  gap: var(--sp-4);
1023  flex-wrap: wrap;
1024}
1025.listhead h2 { margin-bottom: var(--sp-2); }
1026nav.filters { display: flex; gap: var(--sp-1); }
1027nav.filters a {
1028  color: var(--muted);
1029  font-size: var(--fs-2);
1030  padding: 0.05rem var(--sp-2);
1031  border-radius: var(--r-pill);
1032}
1033nav.filters a:hover { color: var(--fg); background: var(--hover); text-decoration: none; }
1034nav.filters a.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
1035
1036ul.issuelist {
1037  list-style: none;
1038  margin: var(--sp-2) 0;
1039  padding: 0;
1040  background: var(--surface);
1041  border: 1px solid var(--line);
1042  border-radius: var(--r-lg);
1043  overflow: hidden;
1044}
1045ul.issuelist li {
1046  display: flex;
1047  align-items: baseline;
1048  gap: var(--sp-3);
1049  padding: var(--sp-3) var(--sp-4);
1050  border-bottom: 1px solid var(--faint);
1051}
1052ul.issuelist li:last-child { border-bottom: none; }
1053ul.issuelist li:hover { background: var(--hover); }
1054ul.issuelist li.empty { display: block; color: var(--muted); }
1055ul.issuelist .issuemain { flex: 1; min-width: 0; }
1056ul.issuelist p { margin: 0; }
1057ul.issuelist .title a { color: var(--fg); font-weight: 550; }
1058ul.issuelist .title a:hover { color: var(--accent); }
1059
1060/* releases */
1061article.release {
1062  background: var(--surface);
1063  border: 1px solid var(--line);
1064  border-radius: var(--r-lg);
1065  padding: var(--sp-3) var(--sp-4);
1066  margin: var(--sp-4) 0;
1067}
1068.releasehead { background: none; border: 0; padding: 0; }
1069.releasehead h3 { margin: 0 0 var(--sp-1); }
1070.releasehead .meta { margin: 0 0 var(--sp-2); }
1071table.assets { margin-top: var(--sp-2); }
1072table.assets td.size { color: var(--muted); white-space: nowrap; text-align: right; }
1073table.assets td.name { width: 100%; font-family: var(--mono); font-size: var(--fs-1); }
1074
1075/* milestones */
1076ul.milestonelist {
1077  list-style: none;
1078  margin: var(--sp-2) 0;
1079  padding: 0;
1080  border: 1px solid var(--line);
1081  border-radius: var(--r-lg);
1082  overflow: hidden;
1083}
1084ul.milestonelist li { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--faint); }
1085ul.milestonelist li:last-child { border-bottom: none; }
1086ul.milestonelist li.empty { color: var(--muted); }
1087ul.milestonelist p { margin: 0; }
1088ul.milestonelist .title { font-weight: 550; }
1089.progress {
1090  height: 6px;
1091  background: var(--faint);
1092  border-radius: var(--r-pill);
1093  margin-top: var(--sp-2);
1094  overflow: hidden;
1095  max-width: 24rem;
1096}
1097.progress .bar { height: 100%; background: var(--ok); }
1098.listhead .spacer { flex: 1; }
1099
1100/* issue / MR detail */
1101h2.issuetitle { margin-bottom: var(--sp-1); font-size: var(--fs-5); }
1102.issuenumber { color: var(--muted); font-weight: 400; }
1103.issuemeta { color: var(--muted); font-size: var(--fs-2); margin-top: 0; }
1104.review { font-size: var(--fs-2); }
1105
1106/* comment cards; discussion stays at a readable measure */
1107article.comment, form.commentform {
1108  max-width: 48rem;
1109}
1110article.comment {
1111  border: 1px solid var(--faint);
1112  border-radius: var(--r-lg);
1113  margin: var(--sp-4) 0;
1114}
1115article.comment .commenthead {
1116  background: var(--surface);
1117  border-bottom: 1px solid var(--faint);
1118  border-radius: var(--r-lg) var(--r-lg) 0 0;
1119  padding: var(--sp-2) var(--sp-4);
1120  font-size: var(--fs-2);
1121}
1122article.comment .commenthead .when { color: var(--muted); }
1123article.comment .rendered { padding: 0 var(--sp-4); }
1124article.comment .rendered > :first-child { margin-top: var(--sp-3); }
1125article.comment .rendered > :last-child { margin-bottom: var(--sp-3); }
1126form.commentform { margin: var(--sp-4) 0; }
1127details.editbox { margin: var(--sp-2) 0; max-width: 48rem; }
1128details.editbox summary { cursor: pointer; color: var(--muted); font-size: var(--fs-2); }
1129details.editbox summary:hover { color: var(--accent); }
1130details.editbox input[type="text"] { width: 100%; }
1131.syscomment {
1132  max-width: 48rem;
1133  color: var(--muted);
1134  font-size: var(--fs-2);
1135  margin: var(--sp-3) 0;
1136  padding-left: var(--sp-4);
1137  border-left: 3px solid var(--faint);
1138}
1139.syscomment p { display: inline; margin: 0; }
1140
1141/* review threads under diff lines */
1142.thread {
1143  border: 1px solid var(--faint);
1144  border-left: 3px solid var(--accent);
1145  border-radius: var(--r-md);
1146  padding: var(--sp-2) var(--sp-4);
1147  margin: var(--sp-2) 0 var(--sp-2) var(--sp-6);
1148}
1149.thread.resolved { border-left-color: var(--ok); opacity: 0.75; }
1150.thread.stale { border-left-color: var(--warn); }
1151.thread p.commenthead { font-size: var(--fs-2); margin: var(--sp-2) 0 0; }
1152.thread .when { color: var(--muted); }
1153.thread .rendered p { margin: var(--sp-1) 0; }
1154.thread .threadstate { color: var(--muted); font-size: var(--fs-1); margin: var(--sp-1) 0 0; }
1155
1156/* forms: every control shares one shell, so a select reads as a sibling
1157   of the text inputs beside it rather than as an OS control dropped in */
1158input, textarea, button, select { font: inherit; color: inherit; }
1159input[type="text"], input[type="search"], input[type="email"],
1160input[type="password"], input:not([type]), textarea, select {
1161  background: var(--bg);
1162  color: var(--fg);
1163  border: 1px solid var(--line);
1164  border-radius: var(--r-md);
1165  padding: var(--sp-2) var(--sp-3);
1166  line-height: 1.4;
1167}
1168textarea { width: 100%; resize: vertical; }
1169textarea[name="content"] { font-family: var(--mono); font-size: var(--fs-1); }
1170/* the native arrow cannot be restyled, so draw our own and match the
1171   inputs exactly; --chev carries the stroke colour per scheme */
1172select {
1173  appearance: none;
1174  padding-right: 1.9rem;
1175  background-image: var(--chev);
1176  background-repeat: no-repeat;
1177  background-position: right 0.6rem center;
1178  background-size: 0.62rem;
1179  cursor: pointer;
1180}
1181input:hover, textarea:hover, select:hover { border-color: var(--muted); }
1182/* the global :focus-visible ring covers these; only the border moves */
1183input:focus, textarea:focus, select:focus { border-color: var(--accent); }
1184input[type="radio"], input[type="checkbox"] { accent-color: var(--fill); }
1185label:has(> input[type="radio"]), label:has(> input[type="checkbox"]),
1186label:has(> select) { display: inline-flex; align-items: center; gap: var(--sp-2); }
1187
1188/* Shape carries the meaning on these two and nothing else does: a circle
1189   takes one answer, a square takes any number. It survives colour being
1190   removed — greyscale, high contrast, colour blindness — so the native
1191   shapes stay and only the colour joins the system. Drawing them by hand
1192   would align the corners at the cost of the one cue that always works. */
1193input[type="radio"], input[type="checkbox"] { accent-color: var(--fill); }
1194
1195/* a segmented control for a small, mutually exclusive set: real radios
1196   underneath, so arrow keys and screen readers behave as they always did */
1197fieldset.segmented { border: 0; margin: 0 0 var(--sp-4); padding: 0; }
1198fieldset.segmented legend {
1199  padding: 0;
1200  margin-bottom: var(--sp-2);
1201  color: var(--muted);
1202  font-size: var(--fs-2);
1203}
1204fieldset.segmented .options { display: inline-flex; }
1205fieldset.segmented label { gap: 0; }
1206fieldset.segmented input {
1207  position: absolute;
1208  width: 1px;
1209  height: 1px;
1210  opacity: 0;
1211  pointer-events: none;
1212}
1213fieldset.segmented span {
1214  display: block;
1215  padding: var(--sp-2) var(--sp-4);
1216  border: 1px solid var(--line);
1217  font-size: var(--fs-2);
1218  cursor: pointer;
1219}
1220fieldset.segmented label + label span { border-left: 0; }
1221fieldset.segmented label:first-child span { border-radius: var(--r-sm) 0 0 var(--r-sm); }
1222fieldset.segmented label:last-child span { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
1223fieldset.segmented span:hover { border-color: var(--muted); }
1224fieldset.segmented input:checked + span {
1225  background: var(--fill);
1226  border-color: var(--fill);
1227  color: #ffffff;
1228  font-weight: 600;
1229}
1230fieldset.segmented input:focus-visible + span {
1231  outline: 2px solid var(--accent);
1232  outline-offset: 2px;
1233}
1234
1235/* remaining input states */
1236::placeholder { color: var(--muted); opacity: 1; }
1237::selection { background: var(--fill); color: #ffffff; }
1238/* :user-invalid, not :invalid — a required field is invalid the moment
1239   the page loads, and colouring it red before anyone has typed is a
1240   scolding, not a hint */
1241input:user-invalid, textarea:user-invalid {
1242  border-color: var(--bad);
1243}
1244.hint { display: block; color: var(--muted); font-size: var(--fs-1); margin-top: var(--sp-1); }
1245button {
1246  background: var(--fill);
1247  color: #ffffff;
1248  border: none;
1249  border-radius: var(--r-md);
1250  padding: var(--sp-2) var(--sp-4);
1251  font-weight: 600;
1252  cursor: pointer;
1253}
1254button:hover { filter: brightness(1.15); }
1255
1256/* 404 */
1257.notfound { text-align: center; padding: var(--sp-6) 0; }
1258.notfound .bigcode {
1259  font-family: var(--mono);
1260  font-size: 4rem;
1261  color: var(--faint);
1262  -webkit-text-stroke: 1px var(--line);
1263  margin: 0;
1264  line-height: 1;
1265}
1266.notfound h1 { margin-top: var(--sp-3); }
1267
1268/* footer */
1269footer {
1270  border-top: 1px solid var(--faint);
1271  padding: var(--sp-4) var(--sp-5) var(--sp-5);
1272  width: 100%;
1273  color: var(--muted);
1274  font-size: var(--fs-1);
1275}
1276footer p { margin: 0; }
1277footer a { color: var(--muted); text-decoration: underline; }
1278footer a:hover { color: var(--accent); }
1279
1280/* search */
1281form.searchform {
1282  display: flex;
1283  gap: var(--sp-2);
1284  margin: var(--sp-3) 0 var(--sp-4);
1285}
1286form.searchform input[type="search"] { flex: 1; max-width: 32rem; }
1287form.searchform.compact { margin: 0; }
1288form.searchform.compact input[type="search"] {
1289  padding: var(--sp-1) var(--sp-3);
1290  font-size: var(--fs-2);
1291  min-width: 18rem;
1292}
1293ul.matchlist { list-style: none; margin: var(--sp-3) 0; padding: 0; }
1294ul.matchlist li { margin-bottom: var(--sp-3); }
1295ul.matchlist .matchpath { font-family: var(--mono); font-size: var(--fs-1); }
1296pre.matchline {
1297  background: var(--code-bg);
1298  border: 1px solid var(--faint);
1299  border-radius: var(--r-md);
1300  padding: var(--sp-1) var(--sp-3);
1301  margin: var(--sp-1) 0 0;
1302  overflow-x: auto;
1303}
1304pre.matchline mark {
1305  background: color-mix(in srgb, var(--warn) 25%, transparent);
1306  color: inherit;
1307  border-radius: 2px;
1308}
1309
1310/* wiki */
1311.wikilayout { display: flex; gap: var(--sp-5); align-items: flex-start; }
1312.wikipage { flex: 1; min-width: 0; }
1313.wikinav { flex: none; width: 13rem; padding-top: var(--sp-4); }
1314.wikinav ul { list-style: none; margin: var(--sp-1) 0 var(--sp-4); padding: 0; }
1315.wikinav li a { display: block; padding: 0.15rem 0; color: var(--fg); }
1316.wikinav li a:hover { color: var(--accent); text-decoration: none; }
1317.wikinav li a.active { color: var(--accent); font-weight: 550; }
1318@media (max-width: 40rem) {
1319  /* Column direction + the desktop align-items:flex-start lets .wikipage
1320     take its content's intrinsic width, overflowing the viewport (and
1321     triggering iOS font inflation). Stretch pins it to the container. */
1322  .wikilayout { flex-direction: column; align-items: stretch; }
1323  .wikinav { width: auto; padding-top: 0; }
1324}
1325
1326/* blame */
1327.blame {
1328  border: 1px solid var(--line);
1329  border-radius: var(--rad-2, 6px);
1330  overflow: hidden;
1331}
1332.blamehunk {
1333  display: flex;
1334  gap: var(--sp-3);
1335  border-top: 1px solid var(--line);
1336  align-items: flex-start;
1337}
1338.blamehunk:first-child { border-top: none; }
1339.blameinfo {
1340  flex: none;
1341  width: 17rem;
1342  padding: var(--sp-2) var(--sp-3);
1343  min-width: 0;
1344}
1345.blameinfo .subject {
1346  margin: 0;
1347  font-size: var(--fs-1);
1348  white-space: nowrap;
1349  overflow: hidden;
1350  text-overflow: ellipsis;
1351}
1352.blameinfo .meta { margin: 0; font-size: var(--fs-1); color: var(--muted); }
1353.blamecode {
1354  flex: 1;
1355  margin: 0;
1356  padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
1357  overflow-x: auto;
1358  border-left: 1px solid var(--line);
1359  align-self: stretch;
1360}
1361.lineno {
1362  display: inline-block;
1363  min-width: 3.5em;
1364  padding-right: 1em;
1365  text-align: right;
1366  color: var(--muted);
1367  user-select: none;
1368}
1369
1370/* mobile */
1371@media (max-width: 40rem) {
1372  .container { padding-left: var(--sp-4); padding-right: var(--sp-4); }
1373  main.container { padding-top: var(--sp-2); }
1374  .repogrid { grid-template-columns: 1fr; }
1375  .thread { margin-left: var(--sp-3); }
1376  /* the commit subject is the widest thing in the listing and the one
1377     column a phone can do without: the tipbar above already names the
1378     latest commit. */
1379  table.tree td.lastcommit, table.tree th.lastcommit { display: none; }
1380  table.tree td.mode, table.tree th.mode { display: none; }
1381  .clone, .pathbar { overflow-wrap: anywhere; }
1382  .readme, .code { padding: var(--sp-3); }
1383  .blamehunk { flex-direction: column; gap: 0; }
1384  .blameinfo { width: auto; }
1385  .blamecode { border-left: none; padding-left: var(--sp-3); width: 100%; }
1386  .cardhead {
1387    margin: calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) var(--sp-3);
1388    padding: var(--sp-2) var(--sp-3);
1389  }
1390}
1391
1392/* tree listing: the last commit is what a file table is scanned for, so
1393   it leads. The file's own facts moved to the blob page. */
1394.tipbar {
1395  display: flex;
1396  align-items: center;
1397  gap: var(--sp-3);
1398  padding: var(--sp-2) var(--sp-4);
1399  background: var(--hover);
1400  border: 1px solid var(--line);
1401  border-bottom: 0;
1402  border-radius: var(--r-lg) var(--r-lg) 0 0;
1403  font-size: var(--fs-2);
1404}
1405.tipbar .who { font-weight: 600; }
1406.tipbar .subject { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1407.tipbar .subject:hover { color: var(--accent); }
1408.tipbar .spacer { flex: 1; }
1409.tipbar .age { color: var(--muted); white-space: nowrap; }
1410.tipbar + table.tree { border-radius: 0 0 var(--r-lg) var(--r-lg); }
1411table.tree th.lastcommit, table.tree td.lastcommit { width: 55%; }
1412table.tree td.lastcommit a { color: var(--muted); display: block; overflow: hidden;
1413                             text-overflow: ellipsis; white-space: nowrap; }
1414table.tree td.lastcommit a:hover { color: var(--accent); }
1415table.tree th.age, table.tree td.age {
1416  text-align: right;
1417  white-space: nowrap;
1418  color: var(--muted);
1419  font-variant-numeric: tabular-nums;
1420}
1421table.tree td.name { width: 25%; white-space: nowrap; }
1422table.tree td.name.dir a { color: var(--accent); }
1423p.clone { margin: 0 0 var(--sp-3); }
1424p.filefacts { color: var(--muted); font-size: var(--fs-1); margin: 0 0 var(--sp-3); }
1425.pathbar .act { font-size: var(--fs-1); }
1426
1427/* merge request: a two-column split, so state has somewhere to live that
1428   is not a run-on sentence under the title */
1429.withaside {
1430  display: grid;
1431  grid-template-columns: minmax(0, 1fr) 15rem;
1432  gap: var(--sp-5);
1433  align-items: start;
1434}
1435.withaside .mainside { min-width: 0; }
1436@media (max-width: 62rem) { .withaside { grid-template-columns: 1fr; } }
1437
1438.aside { font-size: var(--fs-2); }
1439.aside .grp { border-top: 1px solid var(--line); padding: var(--sp-3) 0; }
1440.aside .grp:first-child { border-top: 0; padding-top: 0; }
1441.aside h2 {
1442  margin: 0 0 var(--sp-2);
1443  font-family: var(--mono);
1444  font-size: var(--fs-0);
1445  font-weight: 500;
1446  letter-spacing: 0.1em;
1447  text-transform: uppercase;
1448  color: var(--muted);
1449}
1450.aside .row { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-1); flex-wrap: wrap; }
1451.aside .row:last-child { margin-bottom: 0; }
1452.aside .none { color: var(--muted); }
1453.aside .dot { width: 0.45rem; height: 0.45rem; flex: none; border-radius: 50%; background: var(--muted); }
1454.aside .dot.ok { background: var(--ok); }
1455.aside .dot.bad { background: var(--bad); }
1456.aside .dot.pend { background: var(--mark); }
1457
1458/* sub-navigation within an item; orange marks position as it does above */
1459nav.subtabs {
1460  display: flex;
1461  gap: var(--sp-4);
1462  border-bottom: 1px solid var(--line);
1463  margin: 0 0 var(--sp-4);
1464}
1465nav.subtabs a {
1466  display: inline-flex;
1467  align-items: center;
1468  gap: var(--sp-2);
1469  padding: 0 0 var(--sp-2);
1470  color: var(--muted);
1471  font-size: var(--fs-2);
1472  border-bottom: 2px solid transparent;
1473  margin-bottom: -1px;
1474}
1475nav.subtabs a:hover { color: var(--fg); text-decoration: none; }
1476nav.subtabs a[aria-current] { color: var(--fg); font-weight: 700; border-bottom-color: var(--mark); }
1477nav.subtabs a i {
1478  font-style: normal;
1479  font-family: var(--mono);
1480  font-size: var(--fs-0);
1481  background: var(--hover);
1482  border-radius: var(--r-sm);
1483  padding: 0 0.35rem;
1484}
1485p.diffstat { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-3); }
1486p.diffstat .add { color: var(--ok); }
1487p.diffstat .del { color: var(--bad); }