/* gitbay stylesheet. Tokens first, on :root and again in the dark media query; components use tokens only. Two accents with separate jobs: blue is what you can do (links, primary buttons, focus, pressed toggles), orange is where you are and what wants you (current tab, rail counts, pending state, unverified signatures). Orange is never a button ground. internal/web/tokens_test.go measures every token; internal/web/classes_test.go checks every template class has a rule. No external requests: fonts are served from this origin. */ @font-face { font-family: "Atkinson Hyperlegible Next"; font-style: normal; font-weight: 400 700; font-display: swap; src: url(/static/fonts/atkinson-next-roman.woff2) format("woff2"); } @font-face { font-family: "Atkinson Hyperlegible Next"; font-style: italic; font-weight: 400 700; font-display: swap; src: url(/static/fonts/atkinson-next-italic.woff2) format("woff2"); } @font-face { font-family: "Atkinson Hyperlegible Mono"; font-style: normal; font-weight: 400 600; font-display: swap; src: url(/static/fonts/atkinson-mono-roman.woff2) format("woff2"); } :root { /* declare native light+dark support: correct form controls and scrollbars per scheme, and opt out of browser auto-darkening */ color-scheme: light dark; /* grounds: canvas, surface and inset are three steps, not one */ --canvas: #ffffff; --surface: #ebedf1; --inset: #ffffff; --hover: #e1e4ea; --line: #8d939c; /* 3.09:1 on canvas — a border you can see */ --faint: #d8dce2; /* ink */ --fg: #1c1f24; --muted: #5a6270; --neutral: var(--muted); /* blue: what you can do. --link is text, --fill is a ground; one blue cannot clear 4.5:1 as text and 3:1 as a ground in both schemes. */ --link: #0033d6; --fill: #0000f0; --fill-fg: #ffffff; --focus: var(--link); /* orange: where you are, what wants you. Two cuts because the floor differs by size: --mark for bars, --warn at text size. */ --mark: #e4572e; --warn: #b8400f; /* state */ --ok: #0a7536; --bad: #c62828; --done: #6b21a8; /* diff row tints: enough to scan, light enough that the syntax palette stays legible on them (TestSyntaxPaletteContrast) */ --diff-add: #e4f6ea; --diff-del: #fdeaea; /* the rail is black in both schemes: the one brand constant */ --shell-bg: #000000; --shell-fg: #f2f2f2; --shell-muted: #8f8f8f; --shell-line: #1c1c1c; --shell-hover: #141414; --shell-mark: #ff6b3d; /* the languages' own colours; the same in both schemes */ --lang-go: #00add8; --lang-rust: #dea584; --lang-c: #555555; --lang-python: #3572a5; --lang-javascript: #f1e05a; --lang-typescript: #3178c6; --lang-shell: #89e051; --lang-ruby: #701516; --lang-java: #b07219; --lang-swift: #f05138; --lang-html: #e34c26; --lang-css: #563d7c; --lang-org: #77aa99; --lang-markdown: #083fa1; --lang-emacs-lisp: #c065db; --lang-nix: #7e7eff; --lang-sql: #e38c00; --sans: "Atkinson Hyperlegible Next", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; --mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; /* 12, 13, 14, 16, 20, 24, 32 */ --fs-0: 0.75rem; --fs-1: 0.8125rem; --fs-2: 0.875rem; --fs-3: 1rem; --fs-4: 1.25rem; --fs-5: 1.5rem; --fs-6: 2rem; /* 4, 8, 12, 16, 24, 32, 48 */ --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; /* the rail: a column the width of one hit target, a row one tall */ --rail-hit: 44px; --rail-strip-h: 48px; --rail-mark: 24px; --rail-mark-box: 32px; /* the one page container: header content, main and footer align on it */ --container: 100rem; --r-ctl: 4px; /* controls and chips */ --r-card: 6px; /* cards, lists, code blocks */ --shadow: 0 4px 16px rgba(0, 0, 0, 0.12); /* the native select arrow cannot be restyled, so draw our own; --chev carries the stroke colour per scheme */ --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%235a6270' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); } @media (prefers-color-scheme: dark) { :root { /* the scheme in force, not just the tokens: light-dark() reads it, and themedCSS repeats this block for a page stamped dark */ color-scheme: dark; --canvas: #101114; --surface: #212429; --inset: #0b0c0e; --hover: #2b2f36; --line: #61666f; --faint: #2f333a; --fg: #e9eaec; --muted: #a3a9b3; --neutral: var(--muted); --link: #8b9bff; --fill: #4d61f0; --fill-fg: #ffffff; --focus: var(--link); --mark: #ff6b3d; --warn: #ff8a63; --ok: #3fce7a; --bad: #ff6b6b; --done: #c084fc; --diff-add: #0d2a18; --diff-del: #2c1113; --shell-bg: #000000; --shell-fg: #f2f2f2; --shell-muted: #8f8f8f; --shell-line: #1c1c1c; --shell-hover: #141414; --shell-mark: #ff6b3d; /* the languages' own colours; the same in both schemes */ --lang-go: #00add8; --lang-rust: #dea584; --lang-c: #555555; --lang-python: #3572a5; --lang-javascript: #f1e05a; --lang-typescript: #3178c6; --lang-shell: #89e051; --lang-ruby: #701516; --lang-java: #b07219; --lang-swift: #f05138; --lang-html: #e34c26; --lang-css: #563d7c; --lang-org: #77aa99; --lang-markdown: #083fa1; --lang-emacs-lisp: #c065db; --lang-nix: #7e7eff; --lang-sql: #e38c00; --shadow: 0 4px 16px rgba(0, 0, 0, 0.5); --chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23a3a9b3' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); } } /* a page stamped light keeps the light scheme under a dark OS: the token block above is guarded for it, and this is the other half of that */ :root[data-theme="light"] { color-scheme: light; } /* ---- base ---- */ * { box-sizing: border-box; } html { font-size: 16px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; } body { margin: 0; background: var(--canvas); color: var(--fg); font: var(--fs-3)/1.5 var(--sans); min-height: 100vh; } h1, h2, h3 { line-height: 1.25; font-weight: 600; } h1 { font-size: var(--fs-5); margin: 0 0 var(--sp-3); text-wrap: balance; } h2 { font-size: var(--fs-4); margin: var(--sp-6) 0 var(--sp-3); } h3 { font-size: var(--fs-3); margin: var(--sp-5) 0 var(--sp-2); } p { margin: 0 0 var(--sp-3); } a { color: var(--link); text-decoration: none; } a:hover { text-decoration: underline; } /* a link inside running text is told apart by its underline: link and muted text are 1.07:1 apart in dark, and colour alone is not a cue (#232). Navigation, chips and buttons keep position as their cue. */ p a, .syscomment a { text-decoration: underline; } /* a title or a path is the whole line: position is the cue */ p a.button, p a.btn, p a.chip, .repotitle a, p.title a, .pathbar a, .pager a { text-decoration: none; } /* where a link shares its line with other text the underline is the cue again, path bar or not: a crumb beside the file name, a heading that names an owner, an empty-state note (#226) */ .crumbs a, h1 a, li.empty a { text-decoration: underline; } a.xref { color: var(--link); text-decoration: none; } code, pre, .mono, .code, td.mode, td.size { font-family: var(--mono); font-size: var(--fs-1); } .mono { overflow-wrap: anywhere; } /* ---- focus: one authored ring, so keyboard position is never the browser's guess ---- */ :focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 1px; } /* the rail is black in both schemes and --focus is a dark blue in the light one — a ring nobody could see there */ .rail :focus-visible { outline-color: var(--shell-mark); } /* visually hidden, still read aloud */ .vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; clip-path: inset(50%); overflow: hidden; white-space: nowrap; } /* ---- skip link: the rail runs ahead of the content in source order ---- */ a.skip { position: absolute; left: var(--sp-3); top: -3rem; z-index: 50; display: flex; align-items: center; min-height: var(--rail-hit); background: var(--fill); color: var(--fill-fg); padding: var(--sp-2) var(--sp-4); font-weight: 600; } a.skip:focus { top: var(--sp-3); text-decoration: none; } /* ---- rail: one row of glyphs across the top, no labels ---- One strip the height of a hit target, at every width: fixed squares, no wrapping and no scrolling. Every item is a square link carrying an inline svg, its name in an aria-label and in a visually hidden span, so the nav reads the same to a screen reader as the old text list did. */ .rail { height: var(--rail-strip-h); background: var(--shell-bg); color: var(--shell-fg); border-bottom: 1px solid var(--shell-line); display: flex; flex-direction: row; align-items: center; padding: 0 var(--sp-1); } a.brand { display: flex; align-items: center; justify-content: center; flex: none; width: var(--rail-mark-box); height: var(--rail-strip-h); color: var(--shell-fg); } a.brand:hover { text-decoration: none; } a.brand svg.mark { display: block; flex: none; width: var(--rail-mark); height: var(--rail-mark); } ul.raillist { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; min-width: 0; } /* the spacer that holds settings, admin and the account cell at the far end of the row */ .railgap { flex: 1; } .railicon { position: relative; display: flex; align-items: center; justify-content: center; flex: none; width: var(--rail-hit); height: var(--rail-strip-h); padding: 0; border: 0; background: none; color: var(--shell-fg); cursor: pointer; } .railicon:hover { background: var(--shell-hover); text-decoration: none; } /* orange marks position along the bottom edge — the rail's only accent */ .railicon[aria-current] { background: var(--shell-hover); box-shadow: inset 0 -2px 0 var(--shell-mark); } .count { font-size: var(--fs-0); font-weight: 600; letter-spacing: 0; background: var(--shell-mark); color: var(--shell-bg); padding: 0 5px; border-radius: var(--r-ctl); margin-left: auto; } /* the unread count is a badge on the bell's corner, not a trailing number */ .railicon .count { position: absolute; top: 2px; right: 2px; margin: 0; padding: 0 3px; line-height: 1.35; } .railfoot { flex: none; display: flex; align-items: center; min-width: 0; } .railfoot a { color: var(--shell-fg); } .railfoot form { margin: 0; } a.railuser { display: flex; align-items: center; justify-content: center; flex: none; width: var(--rail-hit); height: var(--rail-strip-h); } a.railuser:hover { text-decoration: none; } /* the phone rail's overflow: every square .railopt hides, and log out, as a labelled list under the rail. Shown only below 34rem. */ .railmore { display: none; position: relative; } .railmore > summary { list-style: none; cursor: pointer; } .railmore > summary::-webkit-details-marker { display: none; } .railmore[open] > summary { background: var(--shell-hover); } .raildrop { position: absolute; top: 100%; right: 0; z-index: 20; min-width: 12rem; padding: var(--sp-1) 0; background: var(--shell-bg); border: 1px solid var(--shell-line); border-radius: var(--r-card); box-shadow: 0 6px 24px rgb(0 0 0 / 0.35); } .raildrop a, .raildrop button { display: flex; align-items: center; /* a button's own default is centred; the rows read as one list */ justify-content: flex-start; gap: var(--sp-3); width: 100%; min-height: var(--rail-hit); padding: 0 var(--sp-4); border: 0; background: none; font: inherit; font-size: var(--fs-2); text-align: left; color: var(--shell-fg); cursor: pointer; } .raildrop a:hover, .raildrop button:hover { background: var(--shell-hover); text-decoration: none; } .raildrop form { margin: 0; } .raildrop svg { flex: none; } a.railuser .avatar { width: var(--rail-mark); height: var(--rail-mark); } .avatar { display: inline-grid; place-items: center; width: 22px; height: 22px; flex: none; border-radius: 50%; background: var(--fill); color: var(--fill-fg); font-size: var(--fs-0); font-weight: 600; } /* ---- shell: the rail above, then the pane, which fills the rest of the viewport so the footer sits at the bottom of a short page ---- */ .shell { display: flex; flex-direction: column; min-height: 100vh; } .pane { flex: 1; min-width: 0; display: flex; flex-direction: column; } main.content { flex: 1; width: 100%; padding: var(--sp-5) var(--sp-6) var(--sp-7); } /* the container is the default width and what `wide` names; reading and bounded follow, so equal specificity gives them the cascade */ main.content, main.wide, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; } main.reading { max-width: calc(72rem + 2 * var(--sp-6)); margin: 0 auto; } main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); margin: 0 auto; } footer { width: 100%; padding: var(--sp-4) var(--sp-6); border-top: 1px solid var(--faint); color: var(--muted); font-size: var(--fs-1); } footer p { margin: 0; } footer a { color: var(--muted); text-decoration: underline; } footer a:hover { color: var(--link); } /* ---- repository header ---- */ .repohead { padding: var(--sp-4) 0 0; border-bottom: 1px solid var(--line); } .repohead .wrap { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; padding: 0 var(--sp-6); } .identity { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; } .grow { flex: 1; } /* h1 on the repo home, p elsewhere so each page keeps its own h1 — but identical in size, because the tabs sit below and navigation must not move when you use it */ .repotitle { margin: 0; font-size: var(--fs-4); font-weight: 600; line-height: 1.25; } .repotitle a { color: var(--fg); } .repotitle a.owner { color: var(--muted); font-weight: 400; } .repotitle a:hover { color: var(--link); text-decoration: none; } .repotitle .sep { color: var(--muted); margin: 0 2px; font-weight: 400; } .repodesc { margin: 0 0 0 var(--sp-2); color: var(--muted); font-size: var(--fs-2); display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; min-width: 0; } .repodesc a.site { color: var(--muted); } .repodesc a.site:hover { color: var(--link); } .repometa { margin: var(--sp-1) 0 0; color: var(--muted); font-size: var(--fs-1); } nav.tabs { display: flex; gap: var(--sp-1); margin-top: var(--sp-3); overflow-x: auto; /* with overflow-y left visible the browser computes it to auto, which is a vertical drag on touch; the strip scrolls sideways only */ overflow-y: hidden; scrollbar-width: none; } nav.tabs::-webkit-scrollbar { display: none; } nav.tabs a { display: inline-flex; align-items: center; gap: var(--sp-1); padding: var(--sp-2) var(--sp-3) 10px; color: var(--muted); font-size: var(--fs-2); white-space: nowrap; border-bottom: 2px solid transparent; margin-bottom: -1px; } nav.tabs a:hover { color: var(--fg); text-decoration: none; } nav.tabs a[aria-current] { color: var(--fg); font-weight: 600; border-bottom-color: var(--mark); } /* a count in a tab is plain metadata, not a badge */ nav.tabs a i { font-style: normal; color: var(--muted); margin-left: 4px; } /* ---- page heads ---- */ .pagehead, .listhead, .headrow { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-5); } .pagehead h1, .listhead h1, .headrow h1, .listhead h2, .headrow h2 { margin: 0; } .pagehead .grow, .listhead .spacer, .headrow .spacer { flex: 1; } .issuetitle { margin: 0 0 var(--sp-2); font-size: var(--fs-5); } .issuenumber { color: var(--muted); font-weight: 400; } .issuemeta { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-4); } .commithead p { margin: var(--sp-1) 0; } .commithead h2 { margin-top: 0; margin-bottom: var(--sp-1); } nav.filters { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; } nav.filters a { display: inline-flex; align-items: center; height: 32px; padding: 0 var(--sp-3); background: var(--canvas); border: 1px solid var(--line); border-radius: var(--r-ctl); color: var(--fg); font-size: var(--fs-2); font-weight: 500; } nav.filters a:hover { background: var(--hover); text-decoration: none; } nav.filters a.active { background: var(--surface); border-color: var(--link); color: var(--link); } form.searchform, form.logfilter, form.compareform { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin: 0 0 var(--sp-4); } form.searchform input[type="search"], form.searchform input[type="text"], form.logfilter input { flex: 1; min-width: 12rem; max-width: 32rem; } form.searchform.compact { margin: 0; } form.searchform.compact input[type="search"], form.searchform.compact input[type="text"] { min-width: 18rem; } form.compareform label { display: inline-flex; align-items: center; gap: var(--sp-2); margin: 0; } /* ---- buttons: one family, 32px tall, so a row of them lines up ---- */ button, .button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 32px; padding: 0 var(--sp-3); font: inherit; font-size: var(--fs-2); font-weight: 500; border: 1px solid transparent; border-radius: var(--r-ctl); cursor: pointer; text-decoration: none; white-space: nowrap; /* a bare