/* Vole's web surface. Token-driven: a light theme is another block of variables,
   and a real identity is a change to the top block only. Everforest is the
   permanent theme in static/everforest.css; this sheet supplies the layout and
   the fallback tokens the theme sheet overrides.

   Sections, in file order. Rules cascade in this order too, so a later section
   can override an earlier one and a section cannot be moved without checking
   what it was quietly overriding:

     tokens                     custom properties, dark and light (:root)
     chrome                     document shell, global bar, account menu,
                                command palette
     repository header          name, visibility, tab row
     panels and tables          the bordered surfaces lists and pages sit on
     controls                   buttons, inputs, selects, form layout
     labels, flashes, empty pages
     auth                       sign-in, registration, invite, account
     repository home            clone button, readme, the home row layout
     diffs and markdown         code/diff tables, hunks, comment cells, .md
     shared responsive rules    the few rules that apply to every surface
     repository overview        summary page: main column and sidebar
     code tab bar and crumbs    the bar above the open file
     code browser and file tree the persistent tree beside the pane
     syntax highlighting        prism token classes
     repository overview sidebar  compact commit and run rows
     run detail                 summary cards, step timing and lazy logs
     issues and changes         list pages, thread, forms, metadata sidebar
     icons                      inline SVG sizing
     activity feed              event rows for one repository and the instance
     accessibility              skip link, focus rings, reduced motion
     light theme                the second token block
     pager                      previous/next between list pages
     code search                per-file result blocks
     blame                      per-line commit column
     landing page               introduction card, repository grid, feed rail
     status page                instance storage, runners, configuration
     language colours           file-icon and language-dot palette

   Note the two pairs that are easy to confuse: "repository home" is the clone
   button and readme on /r/<name>, while "landing page" is the instance home at
   /; "repository overview" is the summary page, while "repository overview
   sidebar" is the small commit and run rows it uses. */

:root {
  color-scheme: dark;

  /* surfaces */
  --bg: #0e0f11;
  --bg-panel: #141517;
  --bg-raised: #191a1e;
  --bg-hover: #1f2024;
  --bg-active: #24262b;
  --border: #26282d;
  --border-strong: #35383f;

  /* text */
  --fg: #e7e8ea;
  --fg-muted: #8b909a;
  --fg-faint: #696e78;

  /* accent and status */
  --accent: #7c86ff;
  --accent-fg: #ffffff;
  --accent-soft: rgba(124, 134, 255, 0.14);
  /* A run that is still going gets its own token rather than --accent: a theme
     whose accent is green (Everforest) would otherwise paint "running" and
     "success" the same colour, and the two must not be confused at a glance. */
  --running: var(--accent);
  --good: #4cb782;
  --good-soft: rgba(76, 183, 130, 0.12);
  --bad: #eb5757;
  --bad-soft: rgba(235, 87, 87, 0.12);
  --warn: #f2c94c;
  --warn-soft: rgba(242, 201, 76, 0.14);
  /* Status buttons are filled, so their label uses the page ground colour. It is
     dark in the dark themes and light in the light ones, which keeps it legible
     against every theme's good/bad/warn hue. */
  --status-fg: var(--bg);
  /* A merged request has landed, which is neither open nor merely closed. It
     gets its own hue so a merged row cannot be read as still being reviewed. */
  --merged: #b083f0;
  --merged-soft: rgba(176, 131, 240, 0.14);

  /* shape and type */
  --radius: 6px;
  --radius-lg: 8px;
  /* One width for every search input: the global bar and a page's filter row
     should not resize the field when the reader moves between them. */
  --search-w: 18rem;
  /* One measure for the page column and the global bar. The bar pads itself out
     to the page's content edges, so the brand and the account menu sit on the
     same vertical line as the content below them. */
  --page-max: 1440px;
  --page-gutter: 24px;
  --font: "Lexend", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "Liberation Sans", Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --fs: 15.4px;
  --lh: 1.55;
  /* Every explicit size is calc(<px> * var(--font-scale)) so the Account page's
     Text size preset reaches labels and code, not just body copy. */
  --font-scale: 1;
}

/* Text-size presets. The account page stores the choice in this browser and
   static/theme.js applies the attribute before the first paint. */
:root[data-font-scale="small"] { --font-scale: 0.9; }
:root[data-font-scale="medium"] { --font-scale: 1; }
:root[data-font-scale="large"] { --font-scale: 1.1; }

/* Self-hosted, OFL fonts. The Latin/Latin-ext subsets keep the binary small;
   anything outside them falls through to the system stack in --font/--mono. */
@font-face {
  font-family: "Lexend";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/lexend-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Lexend";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/lexend-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/static/fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/static/fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: italic;
  font-weight: 100 800;
  font-display: swap;
  src: url("/static/fonts/jetbrains-mono-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: italic;
  font-weight: 100 800;
  font-display: swap;
  src: url("/static/fonts/jetbrains-mono-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

* { box-sizing: border-box; }
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 5px; }
::-webkit-scrollbar-track { background: transparent; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: calc(var(--fs) * var(--font-scale));
  line-height: var(--lh);
  -webkit-font-smoothing: auto;
  font-kerning: normal;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.005em; }
h1 { font-size: calc(19.8px * var(--font-scale)); line-height: 1.35; margin: 2px 0 12px; }
h2 { font-size: calc(14.3px * var(--font-scale)); color: var(--fg-muted); margin: 24px 0 8px; }
h3 { font-size: calc(14.3px * var(--font-scale)); }
p { margin: 0 0 10px; }
ul, ol { margin: 0 0 10px; padding-left: 20px; }
hr { border: 0; border-top: 1px solid var(--border); margin: 20px 0; }
img { max-width: 100%; }

.muted { color: var(--fg-muted); }
.sha { font-family: var(--mono); font-size: calc(13.2px * var(--font-scale)); color: var(--fg-muted); }
.nowrap { white-space: nowrap; }
.adds { color: var(--good); }
.dels { color: var(--bad); }
.conflict, .error { color: var(--bad); }
.bad { color: var(--bad); }

/* ---------- chrome ---------- */

.topbar {
  display: flex;
  align-items: center;
  gap: 20px;
  height: 46px;
  /* The bar spans the window; its items stay inside the page column. */
  padding-block: 0;
  padding-inline: max(var(--page-gutter), calc((100% - var(--page-max)) / 2 + var(--page-gutter)));
  background: color-mix(in srgb, var(--bg-panel) 92%, transparent);
  border-bottom: 1px solid var(--border);
  position: relative;
  z-index: 20;
  backdrop-filter: blur(8px);
}

/* The brand is the emblem alone. The link keeps an accessible name, so a mark with
   no text beside it is still "Vole home" to a screen reader. */
.brand {
  display: inline-flex;
  align-items: center;
  color: var(--fg);
}
.brand:hover { text-decoration: none; }

/* The mark is a mask in the theme's ink. A light theme draws it in the page
   colour with a dark outline instead, because the same muted ink on a pale bar
   reads as a smudge. A custom light theme can opt in by setting these tokens. */
:root {
  --mark-fill: currentColor;
  --mark-outline: transparent;
}
:root[data-theme^="everforest-light"],
:root[data-theme="catppuccin-latte"],
:root[data-theme="solarized-light"],
:root[data-theme="rose-pine-dawn"],
:root[data-theme="ayu-light"] {
  --mark-fill: var(--bg);
  --mark-outline: var(--fg);
}
.brand .mark {
  display: block;
  position: relative;
  flex: none;
  width: 30px;
  height: 30px;
}
.brand .mark::before,
.brand .mark::after {
  content: "";
  position: absolute;
  inset: 0;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-position: center;
  mask-size: contain;
  mask-repeat: no-repeat;
}
/* The outline layer is a slightly expanded solid silhouette behind the light
   head. It draws the outside edge and shows through the eye, mouth, and
   inner-ear holes; the whisker gaps still show the bar. */
.brand .mark::before {
  background-color: var(--mark-outline);
  -webkit-mask-image: url("/static/vole-head-solid.png");
  mask-image: url("/static/vole-head-solid.png");
}
.brand .mark::after {
  background-color: var(--mark-fill);
  -webkit-mask-image: url("/static/vole-head.png");
  mask-image: url("/static/vole-head.png");
}

.topnav { display: flex; gap: 6px; }
.topnav a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--fg);
  font-size: calc(13.75px * var(--font-scale));
  font-weight: 500;
  white-space: nowrap;
}
.topnav a:hover {
  background: var(--bg-hover);
  border-color: var(--border);
  color: var(--fg);
  text-decoration: none;
}
.topnav a.active {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
  color: var(--accent);
}

.topsearch {
  flex: 1 1 auto;
  min-width: 8rem;
  max-width: var(--search-w);
  margin-left: auto;
}
/* The reader is opening the palette, not editing a field, so this is a button
   shaped like the search input it replaces. The label stands in for the
   placeholder, and the last item names the shortcut the browser will hear. */
.topsearch-box {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-width: 0;
  min-height: 30px;
  padding: 5px 8px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--fg-muted);
  font: inherit;
  font-size: calc(13.75px * var(--font-scale));
  text-align: left;
  cursor: pointer;
}
.topsearch-box:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
  color: var(--fg);
}
.topsearch-box .icon { width: 13px; height: 13px; color: var(--fg-faint); }
.topsearch-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topsearch-key {
  flex: 0 0 auto;
  padding: 0 4px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-panel);
  color: var(--fg-faint);
  font-size: calc(11.55px * var(--font-scale));
}

.topright {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: calc(13.75px * var(--font-scale));
  color: var(--fg-muted);
}
.topright > a { display: inline-flex; align-items: center; gap: 5px; color: var(--fg-muted); }
.topright > a:hover { color: var(--fg); text-decoration: none; }

.account-menu { position: relative; }
.account-menu > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border-radius: var(--radius);
  color: var(--fg-muted);
  white-space: nowrap;
  list-style: none;
  cursor: pointer;
}
.account-menu > summary::-webkit-details-marker { display: none; }
.account-menu > summary:hover { background: var(--bg-hover); color: var(--fg); }
.account-menu[open] > summary { background: var(--bg-raised); color: var(--fg); }
.account-name { max-width: 12rem; overflow: hidden; text-overflow: ellipsis; }
.account-caret { display: inline-flex; color: var(--fg-faint); }
.account-caret .icon { width: 12px; height: 12px; transform: rotate(90deg); transition: transform 0.12s ease; }
.account-menu[open] .account-caret .icon { transform: rotate(-90deg); }
.account-pop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  width: 13rem;
  padding: 4px;
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.account-pop a,
.account-pop button {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--fg);
  font: inherit;
  font-size: calc(13.75px * var(--font-scale));
  text-align: left;
  cursor: pointer;
}
.account-pop a:hover,
.account-pop button:hover { background: var(--bg-hover); color: var(--accent); text-decoration: none; }
.account-pop form { margin: 0; }
.account-sep { border-top: 1px solid var(--border); margin: 4px 0; }

/* ---------- command palette ---------- */

/* The global bar's search opens this: one field over every issue, change and
   comment the reader can see. A row is a link, so Enter and a click take the
   same route; the stylesheet only has to make the selected row visible. */
.palette {
  width: min(40rem, calc(100vw - 2 * var(--page-gutter)));
  max-height: min(80vh, 44rem);
  margin: 10vh auto auto;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-raised);
  color: var(--fg);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}
.palette::backdrop { background: rgba(0, 0, 0, 0.5); }
.palette-search {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}
.palette-search .icon { width: 16px; height: 16px; color: var(--fg-muted); }
.palette-search input[type="search"] {
  flex: 1 1 auto;
  width: auto;
  max-width: none;
  min-height: 0;
  padding: 2px 0;
  border: 0;
  background: transparent;
  font-size: calc(15.4px * var(--font-scale));
}
/* The field is the dialog's heading, not a control with a box of its own. */
.palette-search input[type="search"]:focus-visible { outline: 0; }
.palette-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--fg-faint);
  cursor: pointer;
}
.palette-close:hover { background: var(--bg-hover); color: var(--fg); }
.palette-results { max-height: min(60vh, 30rem); overflow-y: auto; padding: 6px; }
.palette-row {
  display: block;
  padding: 7px 9px;
  border-radius: var(--radius);
  color: var(--fg);
}
.palette-row:hover { background: var(--bg-hover); text-decoration: none; }
.palette-row.is-selected { background: var(--accent-soft); }
.palette-row-title {
  display: block;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.palette-row-where {
  display: block;
  color: var(--fg-faint);
  font-size: calc(12.65px * var(--font-scale));
}
/* A palette row is one line high per part; the editable page can afford the
   wrapped excerpt, the dialog cannot. */
.palette-row .search-snippet {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.palette-empty {
  margin: 0;
  padding: 16px 12px;
  color: var(--fg-muted);
  font-size: calc(13.75px * var(--font-scale));
}
.palette-foot {
  display: flex;
  gap: 14px;
  padding: 7px 12px;
  border-top: 1px solid var(--border);
  color: var(--fg-faint);
  font-size: calc(12.65px * var(--font-scale));
}
.palette-foot kbd {
  padding: 0 4px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-panel);
  color: var(--fg-muted);
  font-size: calc(11.55px * var(--font-scale));
}

.page {
  width: min(100%, var(--page-max));
  margin: 0 auto;
  padding: 20px var(--page-gutter) 72px;
}

@media (max-width: 720px) {
  .tabs { mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
  :root { --page-gutter: 12px; }
  .topbar {
    height: auto;
    flex-wrap: wrap;
    padding-block: 8px;
    gap: 8px 12px;
  }
  .topsearch { order: 3; flex: 1 1 100%; max-width: none; margin-left: 0; }
  .topsearch-box { width: 100%; }
  /* A keyboard shortcut is not part of a phone's vocabulary. */
  .topsearch-key { display: none; }
  .topright { margin-left: auto; }
  .topnav { gap: 4px; }
  .topnav a { padding: 4px 8px; }
  /* The icon is enough on a phone; the menu keeps the full name. */
  .account-name { display: none; }
  .page { padding: 16px var(--page-gutter) 56px; }
  .palette { margin-top: 6vh; }
}

/* ---------- repository header ---------- */

.repohead {
  margin-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
.repo-title { padding: 26px 0 12px; }
/* The repository actions sit on the title line, at the far right of the header. */
.repo-title-row {
  display: flex;
  align-items: center;
  gap: 16px;
}
.repo-title-row .repo-name { flex: 1 1 auto; min-width: 0; }
.repo-title-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.repo-title-row .clone-pop { left: auto; right: 0; }
.repo-name {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: var(--fg);
  font-size: calc(28.6px * var(--font-scale));
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.025em;
}
.repo-name .repo-vis .icon { width: 16px; height: 16px; }
.repo-desc {
  margin: 6px 0 0;
  color: var(--fg-muted);
  font-size: calc(14.3px * var(--font-scale));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The tab pages are a level below the repository identity: their own headers
   stay small. Top-level pages (Runners, Activity, Accounts, Account, Status) keep
   the home-page header scale. */
.repohead + .page-head {
  align-items: flex-start;
  gap: 16px;
  padding: 0;
  margin-bottom: 12px;
  border-bottom: 0;
}
.repohead + .page-head h1 {
  font-size: calc(19.8px * var(--font-scale));
  line-height: 1.35;
  letter-spacing: -0.005em;
  margin: 0 0 3px;
}
.repohead + .page-head h1:last-child { margin-bottom: 0; }
.repohead + .page-head .page-sub { font-size: calc(13.75px * var(--font-scale)); }

@media (max-width: 720px) {
  .repo-title { padding: 18px 0 10px; }
  .repo-name { font-size: calc(24.2px * var(--font-scale)); }
  .repo-name .repo-vis .icon { width: 14px; height: 14px; }
}

.tabs {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
  margin-left: -10px;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs a {
  color: var(--fg-muted);
  padding: 8px 10px 9px;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  font-size: calc(13.75px * var(--font-scale));
}
.tabs a:hover { color: var(--fg); text-decoration: none; }
.tabs a.active { color: var(--fg); border-bottom-color: var(--accent); }
.tabs .chip-count { margin-left: 0; }
.tabs a.active .chip-count { color: var(--fg-muted); }

/* The rule under a tab row belongs to a wrapper, not to the strip that carries
   the labels: `.tabs` pulls itself 10px left so the first label's text sits on
   the content edge, and a border on that element would hang 10px past it. The
   repository header keeps its rule on `.repohead`; a page's tabs and a change's
   sections wrap the same strip in this class, so every row starts and ends on
   the content edges together. */
.tabrow { margin-bottom: 14px; border-bottom: 1px solid var(--border); }

/* A count that moved while the reader was looking elsewhere keeps one short
   ring, so the change is noticed; the number itself is the answer. app.js adds
   the class when a poll changes a badge and drops it when the animation ends. */
.tabs .chip-count.count-changed {
  border-radius: 999px;
  animation: count-changed 1.8s ease-out;
}
@keyframes count-changed {
  from { color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
  to { box-shadow: 0 0 0 3px transparent; }
}

/* ---------- panels and tables ---------- */

.panel {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin: 12px 0;
  background: var(--bg-panel);
}

.card {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px;
  margin: 12px 0;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: calc(13.75px * var(--font-scale));
}
.panel > table { margin: 0; }
th, td {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
tr:last-child > td { border-bottom: 0; }
th {
  color: var(--fg-faint);
  font-weight: 500;
  font-size: calc(12.1px * var(--font-scale));
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--bg-raised);
  padding-top: 7px;
  padding-bottom: 7px;
}
tbody tr:hover { background: var(--bg-hover); }

table.commits td { padding-top: 7px; padding-bottom: 7px; }
table.commits td:first-child { width: 9ch; }

/* ---------- controls ---------- */

button, .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--accent);
  color: var(--accent-fg);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 5px 11px;
  font-family: var(--font);
  font-size: calc(13.75px * var(--font-scale));
  font-weight: 500;
  line-height: 1.4;
  cursor: pointer;
  white-space: nowrap;
}
button:hover, .button:hover { filter: brightness(1.08); text-decoration: none; }
button:disabled { opacity: 0.5; cursor: default; }

/* A POST form that is still in flight keeps its button in place: it is disabled
   and, after a short delay added by app.js, its icon becomes a spinner. */
button[data-loading] { cursor: progress; }
button.spinning > .icon { display: none; }
.spinner {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(1turn); } }

.button.secondary, button.secondary {
  background: var(--bg-raised);
  color: var(--fg);
  border-color: var(--border-strong);
}
.button.secondary:hover { background: var(--bg-hover); }

/* Action colours use the same filled shape as the primary control: the
   background carries the meaning, and hover brightens it like every other
   button. */
.button.success, button.success {
  background: var(--good);
  color: var(--status-fg);
  border-color: transparent;
}
.button.warn, button.warn {
  background: var(--warn);
  color: var(--status-fg);
  border-color: transparent;
}
.button.danger, button.danger {
  background: var(--bad);
  color: var(--status-fg);
  border-color: transparent;
}

button.link, .link {
  background: none;
  border: 0;
  color: var(--accent);
  padding: 0;
  font: inherit;
  font-weight: 400;
}
button.link:hover, .link:hover { text-decoration: underline; }
form.inline { display: inline; }

select, input[type="text"], input[type="password"], input[type="search"], textarea {
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 5px 8px;
  font: inherit;
  font-size: calc(13.75px * var(--font-scale));
  min-height: 30px;
}
select:focus, input:focus, textarea:focus {
  outline: 2px solid var(--accent-soft);
  outline-offset: 1px;
  border-color: var(--accent);
}
input[type="text"], input[type="password"], input[type="search"], textarea {
  width: 100%;
  max-width: 34rem;
}
textarea { min-height: 7rem; resize: vertical; line-height: 1.5; }
label { display: block; margin: 10px 0; color: var(--fg-muted); font-size: calc(13.75px * var(--font-scale)); }
/* The label text sits above the control. Without this, a max-width input shares
   the line with its label and the form reads as a row of pairs. */
label > input, label > textarea, label > select {
  display: block;
  margin-top: 4px;
  color: var(--fg);
}
label > select { width: 100%; max-width: 34rem; }
label > .field-hint {
  display: block;
  margin-top: 4px;
  color: var(--fg-faint);
  font-size: calc(12.1px * var(--font-scale));
}

/* Every filter/search row is one component: controls in a wrapping row, a
   visible label on every select, selects that apply on change, and a Search
   button for the text field. Search inputs share --search-w on every surface. */
.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 12px;
}
/* The code page needs a form per ref picker (two refs in one form would submit
   twice), so the row can contain forms as well as be one. */
.filters form {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
/* Every row reads left to right: filters, then search. The search group takes
   the leftover space, so it sits against the right edge whether the row is one
   page's chips and two selects or another page's ref pickers. A row with no
   search puts its clear action in the same slot. */
.filters-search {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}
/* Inside the row the chips are one group, not a row with its own margins. */
.filters .chips { margin: 0; }
.filters input[type="text"],
.filters input[type="search"] { width: var(--search-w); max-width: 100%; }
/* A label and its control stay on one line when the filter row wraps. */
.filter-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
}
.filter-field > input,
.filter-field > select {
  width: auto;
  max-width: none;
  margin-top: 0;
}
.chips + .filters { margin-top: 0; }
.page-head + .filters { margin-top: 0; }

@media (max-width: 720px) {
  .filters { flex-direction: column; align-items: stretch; }
  .filters form { flex-direction: column; align-items: stretch; }
  .filters input[type="text"],
  .filters input[type="search"] { width: 100%; }
  .filters-search { margin-left: 0; width: 100%; }
  /* The search stays one line on a phone: a full-width field and its button,
     not the stacked label/control shape the ref pickers need. */
  .filters-search form { flex-direction: row; align-items: center; }
  .filters-search input[type="text"],
  .filters-search input[type="search"] { flex: 1 1 auto; width: auto; }
  /* A phone stacks the label above its control: a label and an 18rem select
     cannot share a 20rem-wide row without the control overflowing it. */
  .filter-field { flex-direction: column; align-items: stretch; gap: 4px; }
  .filters .filter-field > select { width: 100%; }
}

/* ---------- labels, flashes, empty pages ---------- */

.label {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  font-size: calc(12.1px * var(--font-scale));
  line-height: 1.5;
  color: var(--fg-muted);
  vertical-align: 1px;
}
a.label:hover { color: var(--accent); border-color: var(--accent); text-decoration: none; }

.flash {
  border: 1px solid var(--border-strong);
  background: var(--bg-panel);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin-bottom: 14px;
  font-size: calc(13.75px * var(--font-scale));
}
.flash.bad { border-color: color-mix(in srgb, var(--bad) 50%, var(--border)); background: var(--bad-soft); }
.flash.good { border-color: color-mix(in srgb, var(--good) 50%, var(--border)); background: var(--good-soft); }
.flash.warn { border-color: color-mix(in srgb, var(--warn) 50%, var(--border)); background: var(--warn-soft); }

.empty-page {
  max-width: 34rem;
  margin: 12vh auto 0;
  text-align: center;
}
.empty-page .eyebrow {
  color: var(--fg-faint);
  font-family: var(--mono);
  font-size: calc(12.1px * var(--font-scale));
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.empty-page h1 { font-size: calc(26.4px * var(--font-scale)); margin-bottom: 8px; }
.empty-page p { margin-bottom: 18px; }

/* ---------- auth ---------- */

.auth { max-width: 34rem; margin-top: 8vh; }
.auth h1 { margin-bottom: 6px; }

/* ---------- repository home ---------- */

details.clone { position: relative; }
details.clone > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bg-raised);
  color: var(--fg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 5px 11px;
  font-size: calc(13.75px * var(--font-scale));
}
details.clone > summary::-webkit-details-marker { display: none; }
details.clone > summary:hover { background: var(--bg-hover); }
details.clone[open] > summary { border-color: var(--accent); }
.clone-pop {
  position: absolute;
  z-index: 10;
  top: calc(100% + 6px);
  left: 0;
  width: min(32rem, 80vw);
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: 12px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.clone-pop p { margin: 8px 0 2px; }
.clone-pop code { display: block; }
/* Each advertised transport is one row: the command takes the width, the copy
   button stays put at its end. */
.clone-field {
  display: flex;
  align-items: center;
  gap: 6px;
}
.clone-field code {
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
}
.clone-field button { flex: 0 0 auto; padding: 5px 8px; }

.row { display: flex; gap: 16px; flex-wrap: wrap; }
.row > div { flex: 1 1 18rem; min-width: 0; }

.readme { margin: 16px 0; }

/* ---------- diffs and markdown ---------- */

code, pre, kbd {
  font-family: var(--mono);
}
code {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: calc(12.65px * var(--font-scale));
}
pre {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  overflow: auto;
  font-size: calc(13.2px * var(--font-scale));
  line-height: 1.55;
  margin: 10px 0;
}
pre code { background: none; border: 0; padding: 0; font-size: inherit; }

.crumbs { color: var(--fg-muted); font-size: calc(13.75px * var(--font-scale)); margin: -4px 0 12px; }
.crumbs a { color: var(--fg-muted); }
.crumbs a:hover { color: var(--accent); }
.dir { color: var(--accent); }

.md { line-height: 1.65; max-width: 90ch; }
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md h1, .md h2, .md h3, .md h4 {
  color: var(--fg);
  margin: 20px 0 8px;
  letter-spacing: -0.01em;
  text-transform: none;
}
.md h1 { font-size: calc(22px * var(--font-scale)); }
.md h2 { font-size: calc(17.6px * var(--font-scale)); }
.md h3 { font-size: calc(15.4px * var(--font-scale)); }
.md h4 { font-size: calc(14.3px * var(--font-scale)); }
.md p { margin: 9px 0; }
.md ul, .md ol { padding-left: 22px; margin: 9px 0; }
.md blockquote {
  margin: 10px 0;
  padding: 2px 0 2px 12px;
  border-left: 3px solid var(--border-strong);
  color: var(--fg-muted);
}
.md pre { background: var(--bg-panel); }
.md table { width: auto; }
.md img { border-radius: var(--radius); }

.diffsum { font-size: calc(13.2px * var(--font-scale)); margin: 10px 0; }

/* A diff is read with the browser's find bar as much as with the eyes, so the
   card is not a scrolling box: it grows to the full height of the patch and the
   page scrolls instead. `clip` rounds the corners like `hidden` did, without
   making the element a scroll container that find has to scroll separately. */
.diff {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin: 12px 0;
  overflow: clip;
  background: var(--bg-panel);
}
.diff h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 8px 12px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--border);
  font-size: calc(13.2px * var(--font-scale));
  font-weight: 550;
}
/* The name gives way before the counts do: the path can be long enough to cut,
   and two short numbers at the end of the row are the reason the row exists. */
.diff h3 .path {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--mono);
}
/* One file's counts, in the same row as its name and at the other end of it. */
.diffstat {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: calc(12.1px * var(--font-scale));
  font-weight: 400;
}
/* The row's own gap spaces the badges; the label's standalone margin was for
   prose, where nothing else spaced it. */
.diff h3 .label { margin-left: 0; }
.diff table {
  font-family: var(--mono);
  font-size: calc(12.65px * var(--font-scale));
  border-collapse: collapse;
  table-layout: fixed;
}
.diff col.comment-col { width: 2.25rem; }
.diff col.ln-col { width: 3.5rem; }
.diff td {
  border: 0;
  padding: 1px 10px;
  vertical-align: top;
  line-height: 19px;
}
.diff tbody tr:hover { background: none; }
.diff td.ln {
  text-align: right;
  color: var(--fg-faint);
  user-select: none;
  border-right: 1px solid var(--border);
  padding: 1px 8px;
  white-space: nowrap;
}
/* Only the code column keeps spaces and wraps. The gutter cells hold the
   template's own newlines and indentation; with pre-wrap those became blank
   line boxes and every diff row looked padded. */
.diff td.code { padding-left: 12px; white-space: pre-wrap; word-break: break-word; }
.diff tr.add { background: var(--good-soft); }
.diff tr.add td.ln { color: var(--good); }
.diff tr.del { background: var(--bad-soft); }
.diff tr.del td.ln { color: var(--bad); }
.diff tr.hunk td {
  color: var(--fg-muted);
  background: var(--bg-raised);
  padding: 5px 12px;
  font-size: calc(12.1px * var(--font-scale));
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.diff tr.note td {
  background: var(--bg-panel);
  padding: 8px 12px;
  font-size: calc(13.2px * var(--font-scale));
}
.inline-note {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
  scroll-margin-top: 16px;
}
.inline-note + .inline-note { margin-top: 8px; }
.inline-note:target { border-color: var(--accent); }
.inline-note:target .inline-note-head .comment-author { color: var(--accent); }
.inline-note-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 5px;
  color: var(--fg-muted);
  font-size: calc(12.65px * var(--font-scale));
}
.inline-note-head .comment-author { color: var(--fg); font-size: calc(13.2px * var(--font-scale)); }
.inline-note .comment-body {
  padding: 0;
  max-width: none;
  font-size: calc(13.75px * var(--font-scale));
  line-height: 1.55;
}
.inline-note .comment-body p { margin: 4px 0; }
.diff tr.inline-comment td {
  background: var(--bg-panel);
  padding: 8px 12px;
  border-top: 1px solid var(--border);
}
.inline-comment-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 52rem;
}
.inline-comment-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
}
.inline-comment-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: var(--fg-muted);
  font-size: calc(13.2px * var(--font-scale));
}
.inline-comment-head code { color: var(--fg); }
.inline-comment-form textarea { min-height: 5.5rem; max-width: none; }
.inline-comment-form .form-actions { margin-top: 0; }
.diff .binary { padding: 10px 12px; color: var(--fg-muted); font-size: calc(13.2px * var(--font-scale)); margin: 0; }

/* ---------- shared responsive rules ---------- */

@media (max-width: 720px) {
  h1 { font-size: calc(17.6px * var(--font-scale)); }
  .repohead { gap: 0 10px; }
  th, td { padding: 7px 9px; }
  .nowrap { white-space: normal; }
}

/* ---------- repository overview ---------- */

.overview {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 28px;
  align-items: start;
}
.overview-main { min-width: 0; }
.overview-side section { padding: 12px 0 14px; border-bottom: 1px solid var(--border); }
.overview-side section:first-child { padding-top: 0; }
.overview-side section:last-child { border-bottom: 0; }
.overview-side h2 { margin: 0 0 8px; }

.with-more { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.with-more .more { font-size: calc(13.2px * var(--font-scale)); font-weight: 400; color: var(--fg-muted); }
.with-more .more:hover { color: var(--accent); }

.side-list { display: flex; flex-direction: column; gap: 6px; }
.side-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: calc(13.75px * var(--font-scale)); }
.side-row .muted { font-size: calc(12.65px * var(--font-scale)); white-space: nowrap; }

.contributors { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.contributors li { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 8px; min-width: 0; }
.contributors .cname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: calc(13.75px * var(--font-scale)); }
.contributors .muted { font-size: calc(12.65px * var(--font-scale)); }
.contributors .contributor-stats { display: inline-flex; align-items: center; gap: 8px; color: var(--fg-muted); font-size: calc(12.65px * var(--font-scale)); }
.contributors .contrib-stat { position: relative; display: inline-flex; align-items: center; gap: 3px; cursor: help; }
.contributors .contrib-stat .icon { width: 13px; height: 13px; color: var(--fg-faint); }
.contributors .contrib-stat:hover,
.contributors .contrib-stat:focus-visible { color: var(--fg); outline: none; }
.contributors .contrib-stat:hover .icon,
.contributors .contrib-stat:focus-visible .icon { color: var(--accent); }

.lang { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; margin-bottom: 8px; font-size: calc(13.2px * var(--font-scale)); }
.lang .muted { font-size: calc(12.65px * var(--font-scale)); }
.bar {
  grid-column: 1 / -1;
  appearance: none;
  width: 100%;
  height: 5px;
  border: 0;
  border-radius: 3px;
  background: var(--bg-active);
  overflow: hidden;
}
.bar::-webkit-progress-bar { background: var(--bg-active); border-radius: 3px; }
.bar::-webkit-progress-value { background: var(--accent); border-radius: 3px; }
.bar::-moz-progress-bar { background: var(--accent); border-radius: 3px; }

.filehead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 12px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  font-family: var(--mono);
  font-size: calc(13.2px * var(--font-scale));
}
.filehead .icon { width: 13px; height: 13px; margin-right: 6px; vertical-align: -2px; }
.filehead a { font-family: var(--font); font-size: calc(12.65px * var(--font-scale)); color: var(--fg-muted); }
.filehead a:hover { color: var(--accent); }
.readme {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  padding: 18px 20px;
  margin: 0 0 20px;
  max-width: none;
}
.readme > :first-child { margin-top: 0; }

.latest {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  padding: 7px 12px;
  margin: 0 0 16px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: calc(13.75px * var(--font-scale));
}
.latest .muted { font-size: calc(12.65px * var(--font-scale)); }
.latest a.sha { margin-left: auto; }

.status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: calc(12.1px * var(--font-scale));
  font-weight: 500;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: var(--fg-muted);
}
.status::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.status.success { color: var(--good); }
.status.failed { color: var(--bad); }
.status.running { color: var(--running); }
.status.queued { color: var(--warn); }
.status.canceled { color: var(--fg-faint); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  font-size: calc(12.65px * var(--font-scale));
  color: var(--fg-muted);
  background: var(--bg-panel);
}
.chip .icon { width: 12px; height: 12px; }
.chip:hover { color: var(--fg); border-color: var(--fg-faint); text-decoration: none; }
.chip.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }

td.fit { width: 1%; white-space: nowrap; }

@media (max-width: 1040px) {
  .overview { grid-template-columns: 1fr; }
  .overview-side { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 24px; }
  .overview-side section:first-child { padding-top: 12px; }
}

/* ---------- code tab bar and crumbs ---------- */

/* The tab bar and the tree header share a height so their content starts on the
   same line. The bar is the file's identity, not a separate title block. */
.code-tabbar {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  min-width: 0;
  padding: 0 10px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  color: var(--fg-muted);
  font-family: var(--mono);
  font-size: calc(12.65px * var(--font-scale));
}
.code-tab-icon { display: inline-flex; flex: 0 0 auto; color: var(--fg-faint); }
.code-tab-icon .icon { width: 13px; height: 13px; }
.code-crumbs {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
}
.code-crumbs a { color: var(--fg-muted); }
.code-crumbs a:hover { color: var(--accent); }
.code-crumbs .sep { color: var(--fg-faint); }
.code-crumbs .current { color: var(--fg); overflow: hidden; text-overflow: ellipsis; }
.code-tab-actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  font-family: var(--font);
  font-size: calc(12.65px * var(--font-scale));
}
.code-tab-actions a { color: var(--fg-muted); }
.code-tab-actions a:hover,
.code-tab-actions a.active { color: var(--accent); }
.code-tab-actions .muted { font-size: calc(12.65px * var(--font-scale)); }
.code-tabbar + .panel,
.code-tabbar + .filebody,
.code-tabbar + .card,
.code-tabbar + .readme {
  margin-top: 0;
  border-top: 0;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

/* ---------- code browser and file tree ---------- */

.code-browser {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.code-main { min-width: 0; scroll-margin-top: 16px; }

.file-tree {
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 16px;
  max-height: calc(100vh - 32px);
  overflow: hidden;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.tree-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: 36px;
  padding: 0 10px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--border);
  color: var(--fg-muted);
  font-size: calc(12.1px * var(--font-scale));
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.tree-head .icon { width: 13px; height: 13px; margin-right: 5px; vertical-align: -2px; }
.tree-head .muted { font-size: calc(11.55px * var(--font-scale)); letter-spacing: 0; text-transform: none; }
.tree-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px 4px 8px; }

.tree-list { list-style: none; margin: 0; padding: 0; }
.tree-children { margin-left: 9px; padding-left: 5px; border-left: 1px solid var(--border); }
.tree-row {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 24px;
  padding: 2px 7px;
  border-radius: 4px;
  color: var(--fg-muted);
  font-size: calc(13.2px * var(--font-scale));
  line-height: 1.45;
}
summary.tree-row { list-style: none; cursor: pointer; }
summary.tree-row::-webkit-details-marker { display: none; }
.tree-row:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }
.tree-row.active,
.tree-dir.active > summary.tree-row { background: var(--accent-soft); color: var(--accent); }
.tree-icon { display: inline-flex; flex: 0 0 auto; color: var(--fg-faint); }
.tree-row.active .tree-icon { color: var(--accent); }
.tree-icon .icon { width: 13px; height: 13px; }
.tree-chevron { display: inline-flex; flex: 0 0 auto; color: var(--fg-faint); transition: transform 0.12s ease; }
.tree-chevron .icon { width: 12px; height: 12px; }
details[open] > summary .tree-chevron { transform: rotate(90deg); }
.tree-file { padding-left: 25px; }
.tree-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-note, .tree-empty { margin: 0; padding: 8px 10px; font-size: calc(12.1px * var(--font-scale)); }
.tree-note { border-top: 1px solid var(--border); }

/* Review files: the changed-file tree reuses the code browser's shape, with a
   status mark in place of the file icon. */
.review-tree .tree-file { padding-left: 7px; gap: 7px; }
.review-mark {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  border-radius: 3px;
  background: var(--bg-active);
  color: var(--fg-muted);
  font-family: var(--mono);
  font-size: calc(9.9px * var(--font-scale));
  font-weight: 600;
  line-height: 1;
}
.review-mark[data-status="A"] { color: var(--good); background: var(--good-soft); }
.review-mark[data-status="D"] { color: var(--bad); background: var(--bad-soft); }
.review-mark[data-status="R"] { color: var(--accent); background: var(--accent-soft); }
.review-mark[data-status="M"] { color: var(--warn); background: var(--warn-soft); }
.review-main { min-width: 0; scroll-margin-top: 16px; }
/* A single file is the whole pane, so its header is the pane's top bar: the file
   at one end and its counts at the other, as tall as the tree header so both
   columns start on the same line. The extra pixel is the section's own top
   border, which the height must not add to. */
.review-main .diff { margin-top: 0; }
.review-main .diff h3 { height: 35px; padding: 0 10px; }

.code-main .filebody { max-width: none; }
.code-main .readme > *,
.code-main .filebody > * { max-width: none; }
.empty-code { margin-top: 0; }

.dirlist td { padding: 2px 10px; }
.dirlist a { display: inline-flex; align-items: center; gap: 7px; }
.dirlist .icon { width: 13px; height: 13px; color: var(--fg-faint); }
.dirlist a.dir .icon { color: var(--accent); }
.dirlist a.parent { color: var(--fg-muted); }

@media (max-width: 980px) {
  .code-browser { grid-template-columns: 220px minmax(0, 1fr); }
}
@media (max-width: 760px) {
  .code-browser { grid-template-columns: 1fr; }
  .file-tree { position: static; max-height: 260px; }
}

.readme > *,
.filebody > * { max-width: 84ch; }
.readme > pre,
.readme > table,
.filebody > pre,
.filebody > table { max-width: 100%; }

.filebody {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  margin: 12px 0 20px;
}
.filebody > :first-child { margin-top: 0; }

/* The source card grows to the file's full height for the same reason: find has
   one scroll area, the page. Only a line too wide for the pane scrolls here. */
.blob {
  overflow-x: auto;
}
.blob table.code {
  font-family: var(--mono);
  font-size: calc(12.65px * var(--font-scale));
  border-collapse: collapse;
}
.blob td {
  border: 0;
  padding: 0 12px;
  line-height: 19px;
  white-space: pre;
  vertical-align: top;
}
.blob td.ln {
  width: 3.5rem;
  text-align: right;
  color: var(--fg-faint);
  user-select: none;
  border-right: 1px solid var(--border);
  padding: 0 8px;
}
.blob td.code { padding-left: 12px; }
.blob tr:hover { background: none; }

/* ---------- syntax highlighting ---------- */

/* static/prism-worker.js writes Prism token classes into blob and diff cells
   after the page paints. The palette is the same one the rest of the surface
   uses, so a token is a colour, never a font switch except for comments and
   italics. */

:is(.blob, .diff) .token.comment,
:is(.blob, .diff) .token.prolog,
:is(.blob, .diff) .token.doctype,
:is(.blob, .diff) .token.cdata { color: #6f7682; font-style: italic; }
:is(.blob, .diff) .token.punctuation { color: #a6accd; }
:is(.blob, .diff) .token.namespace { color: #a6accd; }
:is(.blob, .diff) .token.operator,
:is(.blob, .diff) .token.entity,
:is(.blob, .diff) .token.url { color: #7fd3e8; }
:is(.blob, .diff) .token.boolean,
:is(.blob, .diff) .token.number,
:is(.blob, .diff) .token.constant,
:is(.blob, .diff) .token.symbol { color: #f2a06b; }
:is(.blob, .diff) .token.string,
:is(.blob, .diff) .token.char,
:is(.blob, .diff) .token.attr-value,
:is(.blob, .diff) .token.regex { color: #a8d98a; }
:is(.blob, .diff) .token.atrule,
:is(.blob, .diff) .token.keyword,
:is(.blob, .diff) .token.tag,
:is(.blob, .diff) .token.selector { color: #c792ea; }
:is(.blob, .diff) .token.function,
:is(.blob, .diff) .token.function-name,
:is(.blob, .diff) .token.method { color: #83aaff; }
:is(.blob, .diff) .token.class-name,
:is(.blob, .diff) .token.builtin,
:is(.blob, .diff) .token.attr-name,
:is(.blob, .diff) .token.property,
:is(.blob, .diff) .token.title { color: #f0c674; }
:is(.blob, .diff) .token.variable { color: #e7e8ea; }
:is(.blob, .diff) .token.deleted { color: var(--bad); }
:is(.blob, .diff) .token.inserted { color: var(--good); }
:is(.blob, .diff) .token.important,
:is(.blob, .diff) .token.bold { font-weight: 600; }
:is(.blob, .diff) .token.italic { font-style: italic; }

/* ---------- repository overview sidebar ---------- */

/* Compact commit and run rows beside the overview. */

.side-commit,
.side-run,
.side-issue,
.side-change {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 4px 0;
  color: var(--fg);
  min-width: 0;
}
.side-commit:hover,
.side-run:hover,
.side-issue:hover,
.side-change:hover { color: var(--accent); text-decoration: none; }
.side-subject {
  font-size: calc(13.75px * var(--font-scale));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.side-num { color: var(--fg-faint); font-variant-numeric: tabular-nums; margin-right: 4px; }
.side-meta {
  display: flex;
  gap: 8px;
  font-size: calc(12.1px * var(--font-scale));
  color: var(--fg-faint);
  white-space: nowrap;
}
.side-run-top { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.side-run-top .status { flex: 0 0 auto; }

/* The Issues section of a change lists its linked issues in the overview's compact
   shape, with the remove control beside the row and the add field beneath. */
.request-issue { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.request-issue .side-issue { flex: 1; min-width: 0; }
.thread-side .request-issue form { flex: 0 0 auto; margin: 0; }
.request-issue form button { color: var(--fg-faint); }
.request-issue form button:hover { color: var(--bad); }
.request-unlink { display: inline-grid; place-items: center; width: 22px; min-height: 22px; border-radius: var(--radius); }
.request-unlink:hover { background: var(--bg-hover); text-decoration: none; }
#request-combined[hidden], #request-merge-note[hidden] { display: none; }
.request-issue-picker { position: relative; margin-top: 8px; }
.thread-side .request-issue-picker form { margin: 0; }
.request-issue-search input { width: 100%; font-size: calc(12.65px * var(--font-scale)); }
.request-issue-results { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 40; }
.request-issue-popover {
  max-height: 18rem;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-raised);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.request-issue-popover p { margin: 0; padding: 5px 6px; font-size: calc(12.65px * var(--font-scale)); }
.request-issue-matches { display: flex; flex-direction: column; gap: 2px; }
.thread-side .request-issue-match { margin: 0; }
.request-issue-match button {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 1px;
  width: 100%;
  min-height: 0;
  padding: 4px 6px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--fg);
  font-weight: 400;
  text-align: left;
  white-space: normal;
}
.request-issue-match button:hover { background: var(--bg-hover); color: var(--accent); }

/* ---------- run detail ---------- */

/* A run's summary is a row of facts, not a paragraph: how long it took, how
   long it waited, what it ran on, which commit it tested, and the workflow
   definition it ran. */
.run-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 10px;
  margin: 16px 0;
}
.run-summary .card {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.run-summary-label {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--fg-faint);
  font-size: calc(11.55px * var(--font-scale));
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.run-summary-label .icon { width: 12px; height: 12px; }
.run-summary strong {
  font-size: calc(17.6px * var(--font-scale));
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.run-summary .status-note { margin: 0; }
.run-summary code { font-size: calc(11.55px * var(--font-scale)); overflow-wrap: anywhere; }

/* Step logs are loaded on demand. The details element is the trigger; the pre is
   the target, and htmx uses textContent so a log can never become markup. */
.run-log {
  margin: 4px 0;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.run-log > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  color: var(--fg-muted);
  font-size: calc(13.2px * var(--font-scale));
  cursor: pointer;
  list-style: none;
}
.run-log > summary::-webkit-details-marker { display: none; }
.run-log > summary:hover { color: var(--fg); background: var(--bg-hover); }
.run-log > summary .icon { width: 12px; height: 12px; color: var(--fg-faint); }
.run-log[open] > summary {
  color: var(--fg);
  border-bottom: 1px solid var(--border);
}
.run-log-card {
  padding: 0;
  overflow: hidden;
}
.run-log-card > .run-log {
  margin: 0;
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
}
.run-log-card > .run-log:last-child { border-bottom: 0; }
.run-log-title { flex: 1; color: var(--fg); font-weight: 500; }
.run-log-meta {
  margin-left: auto;
  color: var(--fg-faint);
  font-size: calc(12.1px * var(--font-scale));
  font-variant-numeric: tabular-nums;
}
.run-step-num {
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
  min-width: 2.5ch;
}
.run-step-name {
  flex: 1;
  color: var(--fg);
  overflow-wrap: anywhere;
}
.run-step-meta {
  margin-left: 8px;
  color: var(--fg-faint);
  font-size: calc(12.1px * var(--font-scale));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.run-log-empty {
  margin: 0;
  padding: 10px 12px;
  color: var(--fg-muted);
  font-size: calc(13.2px * var(--font-scale));
}
.run-log-text {
  margin: 0;
  padding: 10px 12px;
  border: 0;
  border-radius: 0;
  background: var(--bg);
  color: var(--fg);
  font-size: calc(13.2px * var(--font-scale));
  line-height: 1.5;
  max-height: 34rem;
  min-height: 2.5rem;
  overflow: auto;
  white-space: pre;
}
.run-logbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 8px 0;
  font-size: calc(13.2px * var(--font-scale));
}

/* ---------- issues and changes ---------- */

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding: 26px 0 20px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
.page-head h1 {
  font-size: calc(28.6px * var(--font-scale));
  line-height: 1.2;
  letter-spacing: -0.025em;
  margin: 0 0 4px;
}
.page-head-main { min-width: 0; }
/* The `#42` alias leads a page heading, the way it leads a row in a list: the
   number is what a reader quotes, and the title is what they are looking for. */
.page-num {
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
  margin-right: 7px;
}
.page-head-actions {
  display: flex;
  flex-wrap: wrap;
  flex: 0 0 auto;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-left: auto;
}
/* Search and branch pickers are filters, not inline prose: a row layout keeps the
   input, its icon button, and the select on the same baseline. */
.page-head-actions form.inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.page-sub { color: var(--fg-muted); font-size: calc(14.3px * var(--font-scale)); margin: 0; max-width: 80ch; }

@media (max-width: 720px) {
  .page-head { padding: 18px 0 16px; }
  .page-head h1 { font-size: calc(24.2px * var(--font-scale)); }
}

/* Secondary navigation inside a change: conversation and the review files. It is
   the same `.tabrow` and `.tabs` as every other row, pulled up against the
   request header. */
.subtabs { margin-top: -2px; }

.state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 7px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  font-size: calc(11.55px * var(--font-scale));
  line-height: 1.6;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
  white-space: nowrap;
}
.state::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.state.open {
  color: var(--good);
  border-color: color-mix(in srgb, var(--good) 45%, var(--border));
  background: var(--good-soft);
}
.state.closed { color: var(--fg-faint); }
.state.merged {
  color: var(--merged);
  border-color: color-mix(in srgb, var(--merged) 45%, var(--border));
  background: var(--merged-soft);
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
.chip-count { margin-left: 5px; color: var(--fg-faint); font-variant-numeric: tabular-nums; }
.chip.active .chip-count { color: var(--accent); }
.filter-label {
  color: var(--fg-faint);
  font-size: calc(12.1px * var(--font-scale));
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.row-title { font-weight: 550; color: var(--fg); }
.row-title:hover { color: var(--accent); text-decoration: none; }
.row-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  margin-top: 2px;
  font-size: calc(12.65px * var(--font-scale));
  color: var(--fg-faint);
}

/* The one word a list says about where a row is: a change's waiting state, or an
   issue's open/closed. The icon carries the colour, the label the meaning, and,
   where there is one, the title attribute the reason. */
.row-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: calc(12.65px * var(--font-scale));
  color: var(--fg-muted);
  white-space: nowrap;
}
.row-status .icon { width: 13px; height: 13px; flex: 0 0 auto; }
.row-status.open,
.row-status.ready { color: var(--good); }
.row-status.merged { color: var(--merged); }
.row-status.failed,
.row-status.conflict { color: var(--bad); }
.row-status.waiting,
.row-status.review { color: var(--warn); }
.row-status.closed { color: var(--fg-faint); }

/* A search snippet is the sentence the query matched, with the matched words
   marked. It sits under the row title, quieter than the title and smaller than
   the body it came from. */
.search-snippet {
  margin: 3px 0 0;
  font-size: calc(12.65px * var(--font-scale));
  color: var(--fg-faint);
}
.search-snippet mark {
  background: var(--accent-soft);
  color: var(--fg);
  border-radius: 2px;
  padding: 0 1px;
}

/* An empty state stands in for a list or a pane of content that has nothing to
   show. Use it for a whole region, not for one quiet line inside a card, a
   sidebar, a tree, or a table cell: those stay .muted so a page does not fill
   with dashed boxes. */
.empty-state {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin: 14px 0;
  color: var(--fg-muted);
}
.empty-state p { margin: 0 0 8px; }
.empty-state p:last-child { margin-bottom: 0; }
.empty-state pre { margin: 8px 0; }

/* Thread layout: conversation in the main column, action and metadata beside it. */
.thread {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 24px;
  align-items: start;
}
.thread-main { min-width: 0; }
.thread-side section { padding: 12px 0 14px; border-bottom: 1px solid var(--border); }
.thread-side #request-sidebar > #request-review { padding-top: 0; }
.thread-side > section:last-child,
.thread-side #request-sidebar > section:last-child { border-bottom: 0; }
.thread-side h2 { margin: 0 0 8px; }
.thread-side form { margin: 8px 0 0; }
.thread-side .meta-list { margin-bottom: 0; }

/* The run rows beside a change use the same compact shape as the recent runs
   on the overview: status and job, then the context under them. */
.thread-side .side-meta { flex-wrap: wrap; white-space: normal; }
.thread-side .side-meta > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* A `?` next to a section heading: the explanation is a tooltip rather than a
   paragraph, so the panel keeps only the state it is about. The tooltip opens
   to the left because the sidebar sits at the right edge of the page. */
.help {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 15px;
  height: 15px;
  margin-left: 6px;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  color: var(--fg-faint);
  font-family: var(--font);
  font-size: calc(10px * var(--font-scale));
  font-weight: 600;
  line-height: 1;
  vertical-align: 1px;
  cursor: help;
  user-select: none;
}
.help:hover,
.help:focus-visible { color: var(--accent); border-color: var(--accent); outline: none; }
.help::after,
.contributors .contrib-stat::after {
  content: attr(data-tip);
  position: absolute;
  top: 50%;
  right: calc(100% + 8px);
  z-index: 20;
  width: max-content;
  max-width: 210px;
  padding: 7px 9px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-raised);
  color: var(--fg);
  font-size: calc(12.1px * var(--font-scale));
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: normal;
  text-align: left;
  white-space: normal;
  transform: translateY(-50%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
}
.help:hover::after,
.help:focus::after,
.help:focus-visible::after,
.contributors .contrib-stat:hover::after,
.contributors .contrib-stat:focus::after,
.contributors .contrib-stat:focus-visible::after { opacity: 1; visibility: visible; }
@media (prefers-reduced-motion: no-preference) {
  .help::after { transition: opacity 120ms ease; }
}

/* Scope the card to the article that renders it. Prism calls a syntax token
   "comment" too, and an unscoped .comment rule put a rounded panel behind every
   comment-coloured line in a blob or diff. */
article.comment {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin: 10px 0;
  overflow: visible;
  scroll-margin-top: 16px;
}
article.comment:target {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}
article.comment:target .comment-head { background: var(--accent-soft); }
.comment-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  padding: 7px 12px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--border);
  border-top-left-radius: calc(var(--radius-lg) - 1px);
  border-top-right-radius: calc(var(--radius-lg) - 1px);
  font-size: calc(13.2px * var(--font-scale));
}
.comment-author { font-weight: 550; }
.comment-head .muted { font-size: calc(12.65px * var(--font-scale)); }
.reply-context { color: var(--fg-muted); font-size: calc(12.65px * var(--font-scale)); }
.reply-context a { color: var(--fg-muted); }
.reply-context a:hover { color: var(--accent); }
.comment-body { padding: 12px 14px; }
.comment-body > :first-child { margin-top: 0; }
.comment-body > :last-child { margin-bottom: 0; }

article.comment.deleted {
  border-style: dashed;
  background: transparent;
}
.comment-deleted {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  color: var(--fg-faint);
  font-size: calc(13.2px * var(--font-scale));
  font-style: italic;
}
.comment-deleted .icon { width: 13px; height: 13px; }

/* Replies are displayed one level deep: a root comment leads, all its
   descendants sit in an indented rail, and the reply composer joins the thread. */
.comment-replies {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0 0 12px 26px;
  padding-left: 12px;
  border-left: 2px solid var(--border);
}
.comment-replies article.comment {
  margin: 0;
  background: var(--bg-raised);
}
.comment-menu { position: relative; margin-left: auto; }
.comment-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--fg-muted);
  font-family: var(--font);
  font-size: calc(17.6px * var(--font-scale));
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}
.comment-menu-toggle:hover { background: var(--bg-hover); color: var(--fg); }
.comment-menu-list {
  position: absolute;
  z-index: 60;
  top: calc(100% + 4px);
  right: 0;
  min-width: 10rem;
  padding: 4px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-raised);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.comment-menu-list[hidden] { display: none; }
.comment-menu-list button {
  display: block;
  width: 100%;
  min-height: 0;
  padding: 6px 9px;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--fg);
  text-align: left;
  font-family: var(--font);
  font-size: calc(13.2px * var(--font-scale));
  font-weight: 400;
  line-height: 1.4;
  cursor: pointer;
}
.comment-menu-list button:hover { background: var(--bg-hover); }
.comment-menu-list form { margin: 0; }
.comment-menu-list .menu-danger { color: var(--bad); }
.comment-menu-list .menu-danger:hover { background: var(--bad-soft); }
.comment-edit-form, .details-edit-form { padding: 10px 14px 12px; }
.comment-edit-form[hidden], .details-edit-form[hidden] { display: none; }
.comment-edit-form textarea, .details-edit-form textarea { min-height: 7rem; max-width: none; }
.comment-edit-form .form-actions, .details-edit-form .form-actions { margin-top: 8px; }
article.comment.editing > .comment-body,
article.comment.editing > .comment-snippet { display: none; }

/* The heading is one row: the number stays put, the title sits beside it, and
   the pencil opens a title-only form that takes the title's place. */
.details-title { display: flex; align-items: baseline; flex-wrap: wrap; gap: 7px; margin: 0 0 4px; }
.details-title .page-num { flex: 0 0 auto; margin-right: 0; }
.details-title-view { min-width: 0; margin: 0; }
.details-title-view[hidden], .title-edit-form[hidden], .title-edit-toggle[hidden] { display: none; }
.title-edit-toggle {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: var(--radius);
  color: var(--fg-faint);
}
.title-edit-toggle:hover { background: var(--bg-hover); color: var(--accent); text-decoration: none; }
.title-edit-toggle .icon { width: 14px; height: 14px; }
.title-edit-form { display: flex; align-items: center; flex: 1 1 18rem; gap: 6px; min-width: 0; }
.title-edit-form .details-title-input { flex: 1 1 auto; min-width: 8rem; }
.title-edit-form button { flex: 0 0 auto; }
.details-title-input {
  width: 100%;
  max-width: none;
  font-family: var(--font);
  font-size: calc(19.8px * var(--font-scale));
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.005em;
}

/* A thread keeps its root visible and lets the replies fold away. */
.thread-replies { margin: 0 0 10px 26px; }
.thread-replies > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: max-content;
  padding: 2px 0;
  color: var(--fg-muted);
  font-size: calc(12.65px * var(--font-scale));
  cursor: pointer;
  list-style: none;
}
.thread-replies > summary::-webkit-details-marker { display: none; }
.thread-replies > summary:hover { color: var(--accent); }
.thread-replies[open] > summary { margin-bottom: 6px; }
.thread-chevron { display: inline-flex; color: var(--fg-faint); transition: transform 0.12s ease; }
.thread-chevron .icon { width: 12px; height: 12px; }
.thread-replies[open] .thread-chevron { transform: rotate(90deg); }
.thread-replies .comment-replies { margin: 6px 0 0; }

.discussion-composer { margin: 16px 0 0; }
.discussion-composer textarea {
  width: 100%;
  max-width: none;
  min-height: 7rem;
  padding: 12px 14px;
  background: var(--bg-panel);
  border-color: var(--border);
  border-radius: var(--radius-lg);
  line-height: 1.55;
}
.discussion-composer .form-actions { margin-top: 8px; }
.reply-target {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0 0 8px;
  padding: 5px 8px;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--fg-muted);
  font-size: calc(12.65px * var(--font-scale));
}
.reply-target[hidden] { display: none; }
.reply-target strong { color: var(--fg); }

/* An anchored comment can show the lines it was written about. The details
   element keeps the conversation compact. */
.comment-snippet {
  margin: 0 14px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
  overflow: hidden;
}
.comment-snippet > summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 7px 10px;
  color: var(--fg-muted);
  font-size: calc(12.65px * var(--font-scale));
  cursor: pointer;
  list-style: none;
}
.comment-snippet > summary::-webkit-details-marker { display: none; }
.comment-snippet > summary:hover { background: var(--bg-hover); }
.comment-snippet code { color: var(--fg); font-family: var(--mono); }
.comment-snippet[open] > summary { border-bottom: 1px solid var(--border); }
.snippet-chevron { display: inline-flex; color: var(--fg-faint); transition: transform 0.12s ease; }
.snippet-chevron .icon { width: 12px; height: 12px; }
.comment-snippet[open] .snippet-chevron { transform: rotate(90deg); }
.snippet-code {
  overflow-x: auto;
  background: var(--bg-panel);
  font-family: var(--mono);
  font-size: calc(12.65px * var(--font-scale));
  line-height: 1.55;
}
.snippet-line { display: flex; min-width: max-content; }
.snippet-line.anchor { background: var(--accent-soft); }
.snippet-no {
  flex: 0 0 3.2rem;
  padding-right: 8px;
  text-align: right;
  color: var(--fg-faint);
  user-select: none;
  border-right: 1px solid var(--border);
}
.snippet-text { padding: 0 10px; white-space: pre; color: var(--fg); }
.snippet-actions {
  padding: 6px 10px;
  border-top: 1px solid var(--border);
  font-size: calc(12.65px * var(--font-scale));
}

.meta-list {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 4px 10px;
  margin: 0;
  font-size: calc(13.2px * var(--font-scale));
}
.meta-list dt { color: var(--fg-faint); }
.meta-list dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

/* The request target is two stacked fields, not one crowded row: the sidebar is
   narrow, so each branch name gets the full width and a visible label. */
.request-target { margin: 2px 0 0; }
.target-fields { display: grid; gap: 4px; }
.target-field { display: grid; gap: 3px; min-width: 0; margin: 0; }
.target-label { color: var(--fg-muted); font-size: calc(12.1px * var(--font-scale)); }
.request-target select {
  min-width: 0;
  width: 100%;
  min-height: 30px;
  padding: 4px 7px;
  font-size: calc(13.2px * var(--font-scale));
}
.target-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin-top: 6px;
}
.target-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  margin-left: auto;
  padding: 3px 9px;
}
.request-target p { margin: 0; font-size: calc(12.65px * var(--font-scale)); }
.target-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  margin: 0;
  font-size: calc(13.2px * var(--font-scale));
}
.label-row { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.label-row .label { margin-left: 0; }

.approval-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: calc(13.2px * var(--font-scale));
}
.approval-list li { display: flex; align-items: center; gap: 7px; min-width: 0; }
.approval-list .cname {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.approval-list .muted { font-size: calc(12.1px * var(--font-scale)); }

@media (max-width: 900px) {
  .thread { grid-template-columns: 1fr; }
  .thread-side { display: block; }
  .thread-side #request-aside { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 24px; }
  .thread-side #request-sidebar { display: contents; }
  .thread-side section:first-child { padding-top: 12px; }
  .help::after,
  .contributors .contrib-stat::after { top: calc(100% + 7px); right: auto; left: 0; transform: none; }
  .page-head { flex-wrap: wrap; }
  .page-head-actions { width: 100%; justify-content: flex-start; }
}

/* Form cards: fields live on a card, actions sit below it and align right.
   Every primary action uses the same height and horizontal padding. */
.form-block { margin: 12px 0; }
.danger-form + .danger-form { margin-top: 28px; }
.acl-check { display: flex; align-items: center; gap: 6px; }
.acl-check input[type="checkbox"] { width: auto; margin: 0; }
table.acl select { min-width: 9rem; }
.role-options { border: 0; padding: 0; margin: 0; min-width: 0; }
.role-options legend {
  padding: 0;
  margin: 0 0 8px;
  color: var(--fg);
  font-size: calc(14.3px * var(--font-scale));
  font-weight: 600;
}
.role-options > p { margin: 0 0 10px; }
.role-option {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 5px 0;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--fg);
  font-size: calc(14.3px * var(--font-scale));
  cursor: pointer;
}
.role-option:hover { border-color: var(--border-strong); background: var(--bg-raised); }
.role-option:has(input[type="radio"]:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.role-option input[type="radio"] {
  display: block;
  flex: 0 0 auto;
  width: auto;
  margin: 0;
  accent-color: var(--accent);
}
.role-option .role-name { font-weight: 600; }
.role-option .role-desc { color: var(--fg-muted); font-size: calc(13.2px * var(--font-scale)); line-height: 1.45; }
.role-options.compact { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.role-options.compact legend { display: none; }
.role-options.compact .role-option {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-size: calc(13.2px * var(--font-scale));
}
.role-options.compact .role-option:hover { background: none; }
.role-options.compact .role-option:has(input[type="radio"]:checked) {
  border: 0;
  background: none;
}
.role-options.compact .role-option:has(input[type="radio"]:checked) .role-name { color: var(--accent); }
.role-options.compact .role-desc { display: none; }
.role-options.compact input[type="radio"] { margin: 0; }
.form-card { margin: 0; }
.form-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
.auth > .card { margin: 0; }
.auth > .form-actions { margin-top: 8px; }
.form-card input[type="text"],
.form-card input[type="password"],
.form-card input[type="search"],
.form-card textarea,
.form-card select {
  width: 100%;
  max-width: none;
}

/* The public-key card is the field: the label sits above it and the textarea
   fills the card edge to edge. The focus ring draws inside the card so the
   rounded frame does not clip it. */
.key-card { padding: 0; overflow: hidden; }
.key-card textarea {
  display: block;
  min-height: 8rem;
  margin: 0;
  padding: 12px 14px;
  border: 0;
  border-radius: 0;
  background: transparent;
  resize: vertical;
}
.key-card textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-color: transparent;
}

button, .button {
  min-height: 30px;
  padding-top: 0;
  padding-bottom: 0;
}
button.link, .link { min-height: 0; }

/* Label token input: the bordered box is the control, the text input inside it
   adds labels, and selected labels are removable chips. */
.label-input { position: relative; }
.label-tokens {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  min-height: 32px;
  padding: 3px 8px;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
}
.label-tokens:focus-within {
  border-color: var(--accent);
  outline: 2px solid var(--accent-soft);
  outline-offset: 1px;
}
.label-token {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 1px 3px 1px 8px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: calc(12.65px * var(--font-scale));
  line-height: 1.6;
}
.label-remove {
  min-height: 0;
  padding: 0 3px;
  background: none;
  border: 0;
  color: inherit;
  font-size: calc(15.4px * var(--font-scale));
  line-height: 1;
  cursor: pointer;
}
.label-remove:hover { color: var(--fg); }
.label-tokens .label-entry {
  flex: 1 1 9rem;
  width: auto;
  max-width: none;
  min-width: 8rem;
  margin: 0;
  padding: 2px 0;
  background: none;
  border: 0;
  border-radius: 0;
  font-size: calc(13.75px * var(--font-scale));
  color: var(--fg);
}
.label-tokens .label-entry:focus { outline: none; }
.label-entry::placeholder { color: var(--fg-faint); }
.label-suggest {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 12rem;
  overflow: auto;
  padding: 4px;
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.label-suggest[hidden], .label-option[hidden] { display: none; }
.label-option {
  display: block;
  width: 100%;
  min-height: 0;
  padding: 5px 8px;
  background: none;
  border: 0;
  border-radius: 4px;
  color: var(--fg);
  text-align: left;
  font-size: calc(13.2px * var(--font-scale));
  font-weight: 400;
}
.label-option:hover, .label-option:focus { background: var(--bg-hover); filter: none; }

/* ---------- icons ---------- */

/* Inline SVG from Lucide. Icons inherit currentColor and size with the text
   around them. */
.icon { width: 14px; height: 14px; flex: 0 0 auto; }
.tabs a { display: inline-flex; align-items: center; gap: 5px; }
h2 .icon { width: 13px; height: 13px; margin-right: 4px; vertical-align: -2px; color: var(--fg-faint); }

/* A token save is triggered by the token input, not a button. Dim the field
   while its request is in flight. */
form.htmx-request .label-tokens { opacity: 0.6; }

/* HTMX's indicator rules live here rather than in the <style> element it would
   inject, because the CSP allows style-src 'self' only. Keep them in step with
   the config in chrome.html that turns that injection off. */
.htmx-indicator { opacity: 0; visibility: hidden; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator {
  opacity: 1;
  visibility: visible;
  transition: opacity 200ms ease-in;
}

/* Line-anchored review comments: a small button on each line opens the composer. */
.diff td.comment-cell {
  padding: 0 3px;
  text-align: center;
  white-space: nowrap;
}
.diff td.comment-cell a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 0;
  background: none;
  color: var(--fg-muted);
  opacity: 0.55;
  transition: opacity 0.12s ease, color 0.12s ease;
}
.diff tr:hover td.comment-cell a { opacity: 1; color: var(--accent); }
.diff td.comment-cell a:focus-visible {
  opacity: 1;
  color: var(--accent);
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: 3px;
}
.diff td.comment-cell .icon { width: 12px; height: 12px; }
.anchor-note { margin: 0 0 8px; font-size: calc(13.2px * var(--font-scale)); }
@media (max-width: 720px) { .diff td.comment-cell a { opacity: 0.8; } }

/* ---------- activity feed ---------- */
.activity-list {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-panel);
  overflow: hidden;
}
.activity-event {
  display: flex;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  align-items: flex-start;
}
.activity-event:last-child { border-bottom: 0; }
.activity-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: var(--bg-raised);
  color: var(--fg-muted);
}
.activity-icon .icon { width: 13px; height: 13px; }
.activity-icon.issue { color: var(--good); }
.activity-icon.change { color: #c792ea; }
.activity-icon.release { color: var(--warn); }
.activity-body { min-width: 0; flex: 1; }
.activity-title {
  display: block;
  color: var(--fg);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.activity-title:hover { color: var(--accent); text-decoration: none; }
.activity-meta { color: var(--fg-faint); font-size: calc(12.65px * var(--font-scale)); margin-top: 2px; }
@media (max-width: 720px) {
  .activity-title { white-space: normal; }
}
.danger-zone { border-color: color-mix(in srgb, var(--bad) 40%, var(--border)); }
.danger-zone h3 { margin: 14px 0 4px; color: var(--fg-muted); }
.state.active { color: var(--good); }
.state.retired { color: var(--fg-faint); }

/* ---------- accessibility ---------- */

/* Keyboard users get out of the chrome before the tabs. */
.skip-link {
  position: absolute;
  left: -999px;
  top: 8px;
  z-index: 100;
  padding: 6px 10px;
  background: var(--bg-raised);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
}
.skip-link:focus { left: 12px; }

a:focus-visible,
button:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
  /* The ring still marks the waiting button, but it does not turn. */
  .spinner { animation: none; }
}

@media (max-width: 720px) {
  .panel { overflow-x: auto; }
  .panel > table { min-width: 34rem; }
}

/* ---------- light theme ---------- */

/* A light theme is the same layout with a second set of tokens. It follows the
   operating system until a real theme switch exists. */
@media (prefers-color-scheme: light) {
  :root {
    color-scheme: light;
    --bg: #f7f7f8;
    --bg-panel: #ffffff;
    --bg-raised: #f1f2f4;
    --bg-hover: #eceef2;
    --bg-active: #e4e7ec;
    --border: #dfe2e7;
    --border-strong: #c7ccd5;
    --fg: #1b1e23;
    --fg-muted: #5d646e;
    --fg-faint: #858c96;
    --accent: #4f5bd5;
    --accent-fg: #ffffff;
    --accent-soft: rgba(79, 91, 213, 0.12);
    --good: #247f55;
    --good-soft: rgba(36, 127, 85, 0.12);
    --bad: #bd3b3b;
    --bad-soft: rgba(189, 59, 59, 0.10);
    --warn: #946200;
    --warn-soft: rgba(148, 98, 0, 0.12);
    --merged: #7b3fb5;
    --merged-soft: rgba(123, 63, 181, 0.12);
  }
}
/* ---------- pager ---------- */

.pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 12px 0; }
.pager .button { font-size: calc(13.2px * var(--font-scale)); }

/* ---------- code search ---------- */

/* One block per file, with line numbers linked to blob anchors. */
.search-group { margin: 14px 0; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg-panel); overflow: hidden; }
.search-group h3 { margin: 0; padding: 7px 10px; background: var(--bg-raised); border-bottom: 1px solid var(--border); font-size: calc(13.2px * var(--font-scale)); }
.search-group h3 a { color: var(--fg); }
.search-lines td.code { font-family: var(--mono); font-size: calc(13.2px * var(--font-scale)); white-space: pre-wrap; word-break: break-word; }
.search-lines td.ln { width: 5ch; text-align: right; color: var(--fg-faint); font-family: var(--mono); font-size: calc(12.1px * var(--font-scale)); }
.search-lines td.ln a { color: var(--fg-faint); }
.search-lines tr:hover td.ln a { color: var(--accent); }
.code-main tr:target { background: var(--accent-soft); }

/* ---------- blame ---------- */

/* A commit column spans the consecutive lines it last touched. */
.blame-panel { overflow-x: auto; }
.blame { min-width: 40rem; }
.blame td.blame-meta {
  width: 16rem;
  border-right: 1px solid var(--border);
  background: var(--bg-raised);
  vertical-align: top;
  font-size: calc(12.65px * var(--font-scale));
  line-height: 1.45;
}
.blame td.blame-meta .sha { font-size: calc(12.1px * var(--font-scale)); }
.blame td.ln { width: 6ch; text-align: right; color: var(--fg-faint); font-family: var(--mono); font-size: calc(12.1px * var(--font-scale)); }
.blame td.code { font-family: var(--mono); font-size: calc(13.2px * var(--font-scale)); white-space: pre; }

/* ---------- landing page ---------- */

/* The identity strip, the introduction, the repository grid and the merged feed
   as a rail. The feed has a full page at /activity; here it is a sign the forge
   is alive, not the subject of the page. */
.hero {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding: 26px 0 20px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
}
.hero-main { min-width: 0; }
.hero h1 {
  font-size: calc(28.6px * var(--font-scale));
  line-height: 1.2;
  letter-spacing: -0.025em;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hero-actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: center; gap: 8px; }

/* The introduction sits in the repository column, above the list, so it is as
   wide as the work rather than as wide as the page. */
.readme-card { margin: 0 0 20px; }
.readme-body { padding: 18px 20px; }
.readme-empty {
  margin: 0 0 20px;
  color: var(--fg-muted);
  font-size: calc(13.75px * var(--font-scale));
}

/* Repositories beside the rail. */
.home-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  gap: 28px;
  align-items: start;
}
.home-main { min-width: 0; }
.home-rail { position: sticky; top: 16px; }

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 9px;
}
.section-head h2 { margin: 0; }
.section-head .more { font-size: calc(12.65px * var(--font-scale)); color: var(--fg-muted); }
.section-head .more:hover { color: var(--accent); }
.section-head .muted { font-size: calc(12.65px * var(--font-scale)); }

.repo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(23rem, 1fr));
  gap: 12px;
}
.repo-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  padding: 14px 16px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.repo-card:hover { border-color: var(--border-strong); background: var(--bg-raised); }
.repo-card-top { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.repo-card h3 { font-size: calc(14.85px * var(--font-scale)); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.repo-card h3 a { color: var(--fg); font-weight: 600; }
.repo-card h3 a:hover { color: var(--accent); text-decoration: none; }
.repo-vis { display: inline-flex; flex: 0 0 auto; color: var(--fg-faint); }
.repo-vis .icon { width: 12px; height: 12px; }
.repo-lang { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; font-size: calc(11.55px * var(--font-scale)); color: var(--fg-faint); }
.lang-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--fg-faint); }
.repo-updated { margin-left: auto; flex: 0 0 auto; color: var(--fg-faint); font-size: calc(12.1px * var(--font-scale)); }
.repo-desc {
  color: var(--fg-muted);
  font-size: calc(13.2px * var(--font-scale));
  margin: 0;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.repo-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; }
.repo-chips .chip { padding: 1px 7px; font-size: calc(11.55px * var(--font-scale)); gap: 4px; }
.repo-chips .chip .icon { width: 11px; height: 11px; }
.repo-chips .status { font-size: calc(10.45px * var(--font-scale)); letter-spacing: 0.03em; }
.repo-chips .status::before { width: 5px; height: 5px; }

.empty-state.first-run {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 44px 20px;
}
.first-run .empty-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 12px;
  border-radius: 50%;
  background: var(--bg-raised);
  color: var(--fg-faint);
}
.first-run .empty-icon .icon { width: 20px; height: 20px; }
.first-run h2 { margin: 0 0 6px; font-size: calc(17.6px * var(--font-scale)); color: var(--fg); }
.first-run p { margin: 0 0 14px; }
.first-run .empty-actions { margin: 0 0 10px; }
.first-run .empty-hint { margin: 0; font-size: calc(12.65px * var(--font-scale)); color: var(--fg-faint); }
.first-run .empty-hint code { font-size: calc(12.1px * var(--font-scale)); }

@media (max-width: 1040px) {
  .home-grid { grid-template-columns: 1fr; }
  .home-rail { position: static; order: 2; }
  .home-main { order: 1; }
}
@media (max-width: 720px) {
  .hero { flex-wrap: wrap; align-items: flex-start; padding-top: 18px; }
  .hero-actions { width: 100%; }
  .hero h1 { font-size: calc(24.2px * var(--font-scale)); }
  .repo-grid { grid-template-columns: 1fr; }
}

/* ---------- status page ---------- */

/* No rule under the header itself; the tab row keeps its rule. */
.status-head { border-bottom: 0; margin-bottom: 8px; }
.status-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 10px; margin: 14px 0; }
.status-grid .card { margin: 0; display: flex; flex-direction: column; gap: 4px; }
.status-grid strong { font-size: calc(22px * var(--font-scale)); font-weight: 600; font-variant-numeric: tabular-nums; }
.status-note { color: var(--fg-muted); font-size: calc(12.65px * var(--font-scale)); }
.status-total td { font-weight: 600; border-top: 1px solid var(--border-strong); }
/* Audit detail is attacker-influenced text: wrap it instead of widening the page. */
.audit-detail { overflow-wrap: anywhere; }
.check-state { font-size: calc(12.1px * var(--font-scale)); text-transform: uppercase; letter-spacing: 0.04em; }
.check-state.ok { color: var(--good); }
.check-state.warn { color: var(--warn); }
.check-state.fail { color: var(--bad); }

/* The admin-only effective-configuration table below the health checks. */
.config-table td:first-child { width: 15rem; }
.config-table td:first-child code { white-space: nowrap; }
.config-table td:last-child { overflow-wrap: anywhere; }
.config-group td {
  background: var(--bg-raised);
  color: var(--fg-muted);
  font-size: calc(12.1px * var(--font-scale));
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-top: 7px;
  padding-bottom: 7px;
}
.config-group:hover td { background: var(--bg-raised); }

/* ---------- language colours ---------- */

/* Language hints for file rows. Active tree rows still win through specificity. */
.tree-icon.lang-go, .dirlist a.file.lang-go .icon { color: #00add8; }
.tree-icon.lang-rust, .dirlist a.file.lang-rust .icon { color: #dea584; }
.tree-icon.lang-js, .dirlist a.file.lang-js .icon { color: #f1e05a; }
.tree-icon.lang-ts, .dirlist a.file.lang-ts .icon { color: #3178c6; }
.tree-icon.lang-py, .dirlist a.file.lang-py .icon { color: #3572a5; }
.tree-icon.lang-rb, .dirlist a.file.lang-rb .icon { color: #cc342d; }
.tree-icon.lang-jvm, .dirlist a.file.lang-jvm .icon { color: #b07219; }
.tree-icon.lang-c, .dirlist a.file.lang-c .icon { color: #a8b9cc; }
.tree-icon.lang-cpp, .dirlist a.file.lang-cpp .icon { color: #f34b7d; }
.tree-icon.lang-cs, .dirlist a.file.lang-cs .icon { color: #178600; }
.tree-icon.lang-php, .dirlist a.file.lang-php .icon { color: #8f9ad8; }
.tree-icon.lang-sh, .dirlist a.file.lang-sh .icon { color: #89e051; }
.tree-icon.lang-html, .dirlist a.file.lang-html .icon { color: #e34c26; }
.tree-icon.lang-css, .dirlist a.file.lang-css .icon { color: #a074c4; }
.tree-icon.lang-config, .dirlist a.file.lang-config .icon { color: #cbcb41; }
.tree-icon.lang-text, .dirlist a.file.lang-text .icon { color: #519aba; }
.tree-icon.lang-sql, .dirlist a.file.lang-sql .icon { color: #e38c00; }
.tree-icon.lang-image, .dirlist a.file.lang-image .icon { color: #a074c4; }
.tree-icon.lang-lock, .dirlist a.file.lang-lock .icon { color: var(--fg-muted); }
.tree-icon.lang-build, .dirlist a.file.lang-build .icon { color: var(--fg-muted); }

/* The same palette marks a repository's top language on the landing page. */
.lang-dot.lang-go { background: #00add8; }
.lang-dot.lang-rust { background: #dea584; }
.lang-dot.lang-js { background: #f1e05a; }
.lang-dot.lang-ts { background: #3178c6; }
.lang-dot.lang-py { background: #3572a5; }
.lang-dot.lang-rb { background: #cc342d; }
.lang-dot.lang-jvm { background: #b07219; }
.lang-dot.lang-c { background: #a8b9cc; }
.lang-dot.lang-cpp { background: #f34b7d; }
.lang-dot.lang-cs { background: #178600; }
.lang-dot.lang-php { background: #8f9ad8; }
.lang-dot.lang-sh { background: #89e051; }
.lang-dot.lang-html { background: #e34c26; }
.lang-dot.lang-css { background: #a074c4; }
.lang-dot.lang-config { background: #cbcb41; }
.lang-dot.lang-text { background: #519aba; }
.lang-dot.lang-sql { background: #e38c00; }
.lang-dot.lang-image { background: #a074c4; }
.lang-dot.lang-lock, .lang-dot.lang-build { background: var(--fg-muted); }

/* ---------- profiles and the account directory ---------- */

.profile-joined { margin: 4px 0 0; font-size: calc(12.65px * var(--font-scale)); }
.profile-scope { margin: 8px 0 0; font-size: calc(12.65px * var(--font-scale)); }


/* The four numbers a profile leads with. Each one is a link to the feed it
   counts, so a number is a door rather than a dead end. */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 10px; margin: 18px 0 0; }
.stat {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 16px;
  color: var(--fg);
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.stat:hover { color: var(--fg); background: var(--bg-raised); border-color: var(--border-strong); text-decoration: none; }
.stat-num { font-size: calc(24px * var(--font-scale)); font-weight: 600; font-variant-numeric: tabular-nums; }
.stat-label { color: var(--fg-muted); font-size: calc(12.65px * var(--font-scale)); }

.profile-repos, .profile-activity { margin-top: 26px; }
.profile-repo { gap: 4px; }
.profile-repo-meta { display: flex; flex-wrap: wrap; gap: 4px 10px; margin: 0; color: var(--fg-muted); font-size: calc(12.65px * var(--font-scale)); }

/* The user directory is a table: one row per account, sortable headers, and
   counts right-aligned so a column can be scanned. */
.people-name { font-weight: 600; }
.user-scope { margin: 0 0 10px; font-size: calc(12.65px * var(--font-scale)); }
.user-list th a { color: inherit; }
.user-list th a:hover { color: var(--accent); text-decoration: none; }
.user-list .sort-mark { margin-left: 4px; color: var(--accent); }
.user-list th.count,
.user-list td.count { text-align: right; font-variant-numeric: tabular-nums; }
.user-list td.count { color: var(--fg-muted); }
.user-list .state { margin-left: 4px; vertical-align: 1px; }

@media (max-width: 720px) {
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
