/* Jamie Brown, portfolio site.
   Two voices: serif for anything written as judgment, mono for anything that is
   an artifact or data. Diff structure appears only where the content has a
   change-of-state shape. Everything else is quiet prose on the same gutter. */

@font-face {
  font-family: 'Source Serif 4';
  src: url(/fonts/source-serif-4-latin-opsz-normal.woff2) format('woff2-variations');
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Source Serif 4';
  src: url(/fonts/source-serif-4-latin-opsz-italic.woff2) format('woff2-variations');
  font-weight: 200 900;
  font-style: italic;
  font-display: swap;
}
@font-face { font-family: 'Commit Mono'; src: url(/fonts/commit-mono-latin-400-normal.woff2) format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Commit Mono'; src: url(/fonts/commit-mono-latin-400-italic.woff2) format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: 'Commit Mono'; src: url(/fonts/commit-mono-latin-500-normal.woff2) format('woff2'); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: 'Commit Mono'; src: url(/fonts/commit-mono-latin-600-normal.woff2) format('woff2'); font-weight: 600; font-style: normal; font-display: swap; }
/* Held in reserve for the type comparison. Not loaded unless data-mono asks for it. */
@font-face { font-family: 'Departure Mono'; src: url(/fonts/DepartureMono-Regular.woff2) format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }

:root {
  --paper: #ffffff;
  --ink: #000000;
  --ink-2: #6b6b6b;
  --rule: #d9d9d9;
  /* Diff hues. Blue and plum by default, which stay apart for colorblind
     readers. The standard palette swaps in red and green, the way the tools
     do it. Markers carry the meaning on their own, so color is never the only
     channel. */
  --rg-add: #177a38; --rg-add-bg: #eaf6ee; --rg-add-ink: #0f5a2a; --rg-del: #b3261e; --rg-del-bg: #fdeeed; --rg-del-ink: #8a1c15;
  --cb-add: #1b4bd1; --cb-add-bg: #eef3ff; --cb-add-ink: #12379e; --cb-del: #8e2c5a; --cb-del-bg: #fbeff5; --cb-del-ink: #6e1f45;
  --add: var(--cb-add); --add-bg: var(--cb-add-bg); --add-ink: var(--cb-add-ink);
  --del: var(--cb-del); --del-bg: var(--cb-del-bg); --del-ink: var(--cb-del-ink);
  /* Receipt hue. Evidence only: dates, counts, repo links. Always mono, never
     inside a tinted block, so it cannot be read as a diff line. It swaps with
     the palette so it stays separable from add and del either way. */
  --rg-cite: #1b4bd1; --cb-cite: #7a5200;
  --cite: var(--cb-cite);
  --serif: 'Source Serif 4', Charter, 'Iowan Old Style', Georgia, serif;
  --mono: 'Commit Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --measure: 38rem;
  --gutter: 3rem;
  --edge: 1.25rem;
  --body: 1.125rem;
  --lh: 1.55;
  --line: calc(var(--body) * var(--lh));
  color-scheme: light;
}
[data-palette="standard"] {
  --add: var(--rg-add); --add-bg: var(--rg-add-bg); --add-ink: var(--rg-add-ink);
  --del: var(--rg-del); --del-bg: var(--rg-del-bg); --del-ink: var(--rg-del-ink);
  --cite: var(--rg-cite);
}
[data-mono="departure"] { --mono: 'Departure Mono', ui-monospace, monospace; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #000000;
    --ink: #f2f2f2;
    --ink-2: #9a9a9a;
    --rule: #333333;
    --rg-add: #6fd18a; --rg-add-bg: #0d2616; --rg-add-ink: #8fe0a5; --rg-del: #f28b82; --rg-del-bg: #2c1210; --rg-del-ink: #f5a09a;
    --cb-add: #8aa6ff; --cb-add-bg: #0b1533; --cb-add-ink: #a3b8ff; --cb-del: #e393bf; --cb-del-bg: #2a0f1d; --cb-del-ink: #eaa6cc;
    --rg-cite: #8fb0ff; --cb-cite: #e0a83c;
    color-scheme: dark;
  }
}
[data-theme="dark"] {
  --paper: #000000;
  --ink: #f2f2f2;
  --ink-2: #9a9a9a;
  --rule: #333333;
  --rg-add: #6fd18a; --rg-add-bg: #0d2616; --rg-add-ink: #8fe0a5; --rg-del: #f28b82; --rg-del-bg: #2c1210; --rg-del-ink: #f5a09a;
  --cb-add: #8aa6ff; --cb-add-bg: #0b1533; --cb-add-ink: #a3b8ff; --cb-del: #e393bf; --cb-del-bg: #2a0f1d; --cb-del-ink: #eaa6cc;
  --rg-cite: #8fb0ff; --cb-cite: #e0a83c;
  color-scheme: dark;
}

@media (max-width: 40rem) {
  :root { --gutter: 1.75rem; --edge: 1rem; --body: 1.0625rem; }
  .pr { font-size: 0.8125rem; }
  .files { gap: 0.25rem 0.875rem; }
}

/* Base */
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--body);
  line-height: var(--lh);
  font-optical-sizing: auto;
}
.frame {
  max-width: calc(var(--measure) + var(--gutter) + 2 * var(--edge));
  margin: 0 auto;
  padding: 1.5rem var(--edge) 4rem calc(var(--edge) + var(--gutter));
}
main { display: block; }
p { margin: 0 0 1em; }
a { color: inherit; text-decoration: underline; text-underline-offset: 0.15em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
b, strong { font-weight: 600; }
code, kbd, .mono { font-family: var(--mono); font-size: 0.9375em; }
hr { border: 0; border-top: 1px solid var(--rule); margin: 2.5rem 0; }

/* PR header. The site is framed as an open pull request: the name is the
   title, the state marker is availability, the nav is the files-changed list
   with real counts from each page. */
.pr { font-family: var(--mono); margin: 0 0 3rem calc(-1 * var(--gutter)); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.pr-title { font-size: 1.125rem; margin: 0 0 0.35rem; display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.pr-title .name { font-weight: 600; text-decoration: none; }
.pr-title .name:hover { text-decoration: underline; }
.state { font-size: 0.8125rem; font-weight: 600; white-space: nowrap; }
.state::before { content: ''; display: inline-block; width: 0.6em; height: 0.6em; border-radius: 50%; background: currentColor; margin-right: 0.4em; vertical-align: 0.05em; }
.state.open { color: var(--add); }
.state.resolved { color: var(--ink-2); font-weight: 400; font-family: var(--mono); font-size: 0.75rem; margin-left: 0.75em; vertical-align: 0.15em; }
.state.resolved::before { background: var(--ink-2); }
.pr-line { font-size: 0.875rem; color: var(--ink-2); margin: 0 0 1rem; }
.files { display: flex; flex-wrap: wrap; gap: 0.25rem 1.1rem; font-size: 0.8125rem; line-height: 1.6; padding-top: 0.75rem; border-top: 1px solid var(--rule); }
.files a { text-decoration: none; color: var(--ink-2); white-space: nowrap; }
.files a:hover { color: var(--ink); text-decoration: underline; }
.files [aria-current="page"] { color: var(--ink); font-weight: 600; white-space: nowrap; }
.files .stat { font-weight: 400; font-size: 0.8125rem; }
.stat .plus { color: var(--add); }
.stat .minus { color: var(--del); }

/* Headings. Page titles read like a commit subject line. Section heads stay near body size. */
h1 {
  font-family: var(--mono);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.4;
  margin: 0 0 1.5rem;
}
h2 {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.35;
  margin: 3rem 0 1rem;
}
h3 { font-size: 1.0625rem; font-weight: 600; margin: 2rem 0 0.75rem; }

/* Lists in prose */
ol, ul { padding-left: 1.5rem; margin: 0 0 1em; }
li { margin-bottom: 0.5em; }
.model { padding-left: 0; list-style: none; counter-reset: model; }
.model li { counter-increment: model; margin-bottom: 1em; }
.model li::before {
  content: counter(model);
  font-family: var(--mono);
  font-size: 0.875rem;
  color: var(--ink-2);
  position: absolute;
  margin-left: calc(-1 * var(--gutter));
  width: var(--gutter);
  text-align: center;
  line-height: var(--line);
}

/* Diff structure.
   A hunk is a section whose content has before-and-after shape. Blocks inside it
   carry one of four roles: context (unchanged), add, del, or note (a review
   comment, in the margin). Markers live in the gutter and carry the meaning on
   their own. Color is the second channel, never the only one. */
.hunk-head {
  margin: 3.5rem 0 1rem;
}
.hunk-head .range {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.8125rem;
  color: var(--ink-2);
  white-space: nowrap;
  margin-right: 0.75em;
}
.ctx, .add, .del, .mod, .note {
  position: relative;
  margin-left: calc(-1 * (var(--gutter) + var(--edge)));
  padding-left: calc(var(--gutter) + var(--edge));
}
.add, .del { padding-top: 0.5rem; padding-bottom: 0.5rem; padding-right: var(--edge); margin-right: calc(-1 * var(--edge)); margin-bottom: 1em; }
.add > :last-child, .del > :last-child, .note > :last-child { margin-bottom: 0; }
.add { background: var(--add-bg); color: var(--add-ink); }
.del { background: var(--del-bg); color: var(--del-ink); }
.add::before, .del::before, .mod::before {
  position: absolute;
  left: var(--edge);
  top: 0.5rem;
  width: var(--gutter);
  text-align: center;
  font-family: var(--mono);
  font-size: 1rem;
  line-height: var(--line);
  font-weight: 600;
}
.add::before { content: '+'; color: var(--add); }
.del::before { content: '-'; color: var(--del); }

/* A modified line. What changed is a word, not the line, so the marker is ~ and
   the strike lands only on the part that went. This is what a word-level diff
   shows, and it is the honest form when the practice stayed and only the
   restriction on it was dropped. */
.mod::before { content: '~'; color: var(--ink-2); font-weight: 400; }
del {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--del);
  color: var(--del-ink);
  background: var(--del-bg);
}
/* An inline addition: a phrase that entered the working model after it was
   first written. Same hue rule as an added line, no underline, since the
   tint already says what it is. */
ins {
  text-decoration: none;
  color: var(--add-ink);
  background: var(--add-bg);
  padding: 0 0.15em;
}
ins b, .model ins { font-weight: inherit; }

/* A removed line is struck, the way a prose diff marks one. The strike lands on
   the thing that was removed and not on the reasoning for removing it, so the
   audit's why column stays readable while its tool name reads as struck. */
.lines > .del:not(.row), .rows .row.del dt {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--del);
}

/* A note is a review comment: the human layer over the artifact. It reads as
   marginalia, with a rule in the gutter rather than a card. */
.note { margin-top: 1.25em; margin-bottom: 1.25em; }
.note::before {
  content: '';
  position: absolute;
  left: calc(var(--edge) + var(--gutter) / 2 - 1.5px);
  top: 0.15em;
  bottom: 0.15em;
  width: 3px;
  background: var(--cite);
}
.note blockquote {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.9375rem;
  line-height: 1.55;
}
.note .who {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--cite);
  margin: 0.5em 0 0;
}

/* Meta text: dates, counts, provenance. Always mono, always quiet. */
.meta { font-family: var(--mono); font-size: 0.8125rem; color: var(--ink-2); }
.meta b, .meta .n { color: var(--cite); font-weight: 600; }

/* Role labels. A case study has diff shape: the context, the human note, the
   result. The label names which one you are about to read, in the machine
   voice, so the paragraph under it can stay plain prose. It replaces the bold
   run-in that made every block open the same way. */
.role {
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.6;
  color: var(--ink-2);
  margin: 1.75rem 0 0.35rem;
}
.role::before { content: '// '; color: var(--ink-2); }
.add > .role { color: var(--add); margin-top: 0; }
.del > .role { color: var(--del); margin-top: 0; }
.add > .role::before, .del > .role::before { content: none; }

/* Receipts. Every number on this site traces to something you can go check, so
   the figures get the cite hue and the words around them stay quiet. Mono, and
   never inside a tinted block, so a receipt cannot be misread as a diff line. */
.receipts {
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.7;
  color: var(--ink-2);
  list-style: none;
  padding: 0;
  margin: 0 0 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.5rem;
}
.receipts li { margin: 0; }
.receipts .n { color: var(--cite); font-weight: 600; white-space: nowrap; }
.receipts.stack { display: block; max-width: 32rem; }
.receipts.stack li { margin-bottom: 0.15em; }
.hunk-head + .receipts { margin-top: -0.5rem; }

/* Key clause. One phrase a paragraph at most, and only the load-bearing one.
   It is the same ink, heavier, so a reader skimming the page still lands on
   the sentence that carries the point. */
.prose-key { font-weight: 600; }

/* Colophon: the last receipt on every page */
.colophon {
  margin-top: 5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--ink-2);
}
.colophon p { margin: 0 0 0.5em; max-width: 34rem; }
.colophon .checks { color: var(--ink); }

/* Display controls. Fixed in the corner so they are reachable from anywhere
   on a long page. Text labels say what pressing does. */
.controls {
  position: fixed;
  right: max(0.75rem, env(safe-area-inset-right));
  bottom: max(0.75rem, env(safe-area-inset-bottom));
  display: flex;
  gap: 0.5rem;
  z-index: 10;
}
.controls button {
  font-family: var(--mono);
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--ink-2);
  background: var(--paper);
  border: 1px solid var(--rule);
  padding: 0.4em 0.75em;
  cursor: pointer;
}
.controls button:hover { color: var(--ink); border-color: var(--ink); }
.controls button[aria-pressed="true"] { color: var(--paper); background: var(--ink); border-color: var(--ink); }
@media (max-width: 40rem) { .controls .more { display: none; } }

/* Consecutive lines of a hunk form one block, each changed line with its own marker. */
.lines > .add, .lines > .del, .lines > .ctx, .lines > .mod { margin-bottom: 0; padding-top: 0.3rem; padding-bottom: 0.3rem; }
.lines > :first-child { padding-top: 0.6rem; }
.lines > :last-child { padding-bottom: 0.6rem; margin-bottom: 1.5rem; }
.lines > .add::before, .lines > .del::before, .lines > .mod::before { top: 0.3rem; }
.lines > .add:first-child::before, .lines > .del:first-child::before, .lines > .mod:first-child::before { top: 0.6rem; }

@media print {
  :root { --paper: #fff; --ink: #000; --ink-2: #444; --rule: #999; --add-bg: #eef; --del-bg: #fee; --cite: #14349b; }
  .files, .controls { display: none; }
  .frame { padding: 0 0 0 var(--gutter); max-width: none; }
  a { text-decoration: none; }
  * { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}

/* Home: the five-line hunk */
.hero .hunk-head { margin: 0 0 0.5rem; }
.links { font-family: var(--mono); font-size: 0.875rem; line-height: 1.8; margin: 0 0 3rem; }
.links a { margin-right: 1.25rem; white-space: nowrap; }
.catalog { max-width: 30rem; }

/* Audit rows. Each row is one line of the diff. */
.rows { margin: 0 0 2rem; }
.rows .row { padding-top: 0.75rem; padding-bottom: 0.75rem; }
.rows .row::before { top: 0.75rem; }
.rows .row.ctx { position: relative; margin-left: calc(-1 * (var(--gutter) + var(--edge))); padding-left: calc(var(--gutter) + var(--edge)); }
.rows .row.ctx + .row.ctx { border-top: 1px solid var(--rule); }
.rows dt { font-family: var(--mono); font-size: 0.9375rem; font-weight: 600; margin: 0 0 0.25rem; }
.rows dd { margin: 0; }
.rows .when { display: block; font-family: var(--mono); font-size: 0.8125rem; color: var(--ink-2); margin-bottom: 0.25rem; }

/* An unresolved thread: a question the record has not closed. */
.unresolved { position: relative; margin-left: calc(-1 * (var(--gutter) + var(--edge))); padding-left: calc(var(--gutter) + var(--edge)); margin-top: 1.5em; }
.unresolved::before {
  content: 'open';
  position: absolute;
  left: var(--edge);
  top: 0.2em;
  width: var(--gutter);
  text-align: center;
  font-family: var(--mono);
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--ink-2);
}
.unresolved::after {
  content: '';
  position: absolute;
  left: calc(var(--edge) + var(--gutter) / 2 - 1px);
  top: 1.7em;
  bottom: 0.2em;
  border-left: 2px dotted var(--ink-2);
}

/* Projects: each repo is a file in the change set, with a diff-style file header. */
.file { margin: 0 0 3rem; }
.file-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 1rem; border-top: 1px solid var(--rule); padding-top: 0.75rem; margin: 0 0 0.25rem; }
.file-head h2 { font-family: var(--mono); font-size: 1.125rem; margin: 0; }
.file-head h2.serif { font-family: var(--serif); font-size: 1.25rem; }
.file-head .stat { font-family: var(--mono); font-size: 0.8125rem; color: var(--ink-2); }
.file .meta { margin-bottom: 0.75rem; }
.file .meta a { margin-right: 1rem; }

/* Documentation inside a file: a data-flow diagram built from the same facts
   as the copy. Nodes are mono boxes, arrows are glyphs, rows wrap on a phone. */
.doc-h { font-family: var(--mono); font-size: 0.8125rem; font-weight: 600; color: var(--ink-2); margin: 1.25rem 0 0.5rem; }
.flow { margin: 0 0 1rem; }
.flow ol { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; align-items: stretch; gap: 0.5rem 0; }
.flow li { display: flex; align-items: stretch; }
.flow li:not(:last-child)::after { content: '\2192'; font-family: var(--mono); font-size: 0.9375rem; color: var(--cite); padding: 0 0.5rem; display: flex; align-items: center; }
.flow .box { display: block; box-sizing: border-box; height: 100%; border: 1px solid var(--rule); border-left: 2px solid var(--ink); padding: 0.35rem 0.6rem; font-family: var(--mono); font-size: 0.8125rem; line-height: 1.4; max-width: 13rem; }
.flow .box b { font-weight: 600; }
.flow .box small { display: block; font-size: 0.75rem; color: var(--ink-2); }
.verification { font-family: var(--mono); font-size: 0.8125rem; line-height: 1.7; color: var(--ink-2); margin: 0 0 1rem; }
.verification .n { color: var(--cite); font-weight: 600; }

/* CV: experience is a commit log on a rail. Dates sit in a wider gutter on
   desktop and above the subject line on a phone. */
body.cv { --rail: 1rem; }
@media (min-width: 40.01rem) { body.cv { --gutter: 12.5rem; } }
@media (max-width: 40rem) { body.cv { --rail: 0.875rem; } }
.cv h2 { margin-top: 3.5rem; }
.cv h3 { font-size: 1.125rem; margin: 2.25rem 0 0.25rem; }
.cv h3 + .meta { margin-bottom: 0.75rem; }
.commits { position: relative; }
.commits::before { content: ''; position: absolute; top: 0.6em; bottom: 0; left: calc(-1 * var(--rail) - 1px); border-left: 2px solid var(--rule); }
.commit { position: relative; margin: 0 0 2.5rem; }
.commit::before { content: ''; position: absolute; left: calc(-1 * var(--rail) - 5px); top: 0.5em; width: 10px; height: 10px; border-radius: 50%; background: var(--ink); }
.commit.head::before { background: var(--add); }
.commit h3 { margin: 0 0 0.15rem; }
.commit .when { font-family: var(--mono); font-size: 0.8125rem; color: var(--cite); margin: 0 0 0.25rem; }
.commit + .commit { border-top: 1px solid var(--rule); padding-top: 1.5rem; }
.commit.head h3 { color: var(--add-ink); }
.commit .meta { margin-bottom: 0.75rem; }
@media (min-width: 40.01rem) {
  .commit .when { position: absolute; left: calc(-1 * var(--gutter)); width: calc(var(--gutter) - var(--rail) - 1rem); text-align: right; top: 0.25em; margin: 0; }
}
.cv ul { padding-left: 1.25rem; }
.cv li { margin-bottom: 0.4em; }
.cv table { border-collapse: collapse; width: 100%; font-size: 0.9375rem; margin: 0 0 1.5rem; }
.cv th, .cv td { text-align: left; vertical-align: top; padding: 0.4rem 0.75rem 0.4rem 0; border-top: 1px solid var(--rule); }
.cv th { font-family: var(--mono); font-weight: 600; font-size: 0.8125rem; border-top: 0; }
.download { font-family: var(--mono); font-size: 0.875rem; margin: 0 0 2.5rem; }
.download a { border: 1px solid var(--ink); padding: 0.35em 0.75em; text-decoration: none; }
.download a:hover { background: var(--ink); color: var(--paper); }
.contact { font-family: var(--mono); font-size: 0.9375rem; line-height: 1.8; margin: 0 0 1.5rem; list-style: none; padding: 0; }

/* Editor-style folds. A summary line with a fold marker, and the lines under
   it hidden until asked for. The build appends the hidden line count. Printing
   opens every fold. */
details.fold { margin: 0.35rem 0 0.9rem; }
details.fold > summary {
  cursor: pointer;
  list-style: none;
  font-size: 1rem;
  line-height: 1.5;
  padding: 0.15rem 0;
}
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::before {
  content: '\25B8';
  font-family: var(--mono);
  color: var(--cite);
  display: inline-block;
  width: 1.1em;
}
details.fold[open] > summary::before { content: '\25BE'; }
details.fold > summary:hover { text-decoration: underline; text-underline-offset: 0.15em; }
details.fold > summary .fold-n { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-2); margin-left: 0.6em; white-space: nowrap; }
details.fold[open] > summary .fold-n { visibility: hidden; }
details.fold > :not(summary) { margin-left: 1.1em; }
details.fold > ul, details.fold > ol { margin-top: 0.4rem; }
details.fold > p:first-of-type { margin-top: 0.4rem; }

/* Skills as tags, grouped by tier. Same box vocabulary as the data-flow
   diagrams, so a skill reads as a node rather than a keyword in a paragraph. */
.tags { margin: 0 0 1.5rem; }
.tags dt { font-family: var(--mono); font-size: 0.75rem; font-weight: 600; color: var(--ink-2); margin: 1rem 0 0.4rem; }
.tags dt::before { content: '// '; }
.tags dd { margin: 0; }
.tags .tier { font-size: 0.9375rem; color: var(--ink-2); margin: 0 0 0.5rem; }
.tag {
  display: inline-block;
  border: 1px solid var(--rule);
  border-left: 2px solid var(--ink);
  padding: 0.12rem 0.5rem;
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.5;
  margin: 0 0.35rem 0.4rem 0;
}
.tag.deep { border-left-color: var(--cite); font-weight: 600; }
.tag small { color: var(--ink-2); font-size: 0.75rem; margin-left: 0.35em; }
.cv .personal h3::after { content: 'personal work'; font-family: var(--mono); font-size: 0.75rem; font-weight: 400; color: var(--cite); margin-left: 0.75em; vertical-align: 0.15em; }

/* Author line under the PR title, and the files-changed summary above the list. */
.pr-author { font-size: 0.8125rem; color: var(--ink-2); margin: 0 0 1rem; }
.pr-author a { text-decoration: none; color: var(--ink-2); margin-right: 1rem; white-space: nowrap; }
.pr-author a:hover { color: var(--ink); text-decoration: underline; }
.files-summary { flex-basis: 100%; color: var(--ink-2); }

/* Blame on the working model: which items changed since the model was
   written, and when. In the right margin on a wide screen, on its own line
   otherwise. */
.model li { position: relative; }
.model li[data-blame]::after { content: attr(data-blame); font-family: var(--mono); font-size: 0.75rem; color: var(--cite); }
@media (min-width: 64rem) { .model li[data-blame]::after { position: absolute; left: calc(100% + 1.5rem); top: 0.35em; white-space: nowrap; } }
@media (max-width: 63.99rem) { .model li[data-blame]::after { display: block; margin-top: 0.25rem; } }

/* A view toggle on a hunk: unified or split. Desktop only. */
.view-toggle { font-family: var(--mono); font-size: 0.75rem; margin-left: 1rem; }
.view-toggle button { font: inherit; color: var(--ink-2); background: none; border: 1px solid var(--rule); padding: 0.1em 0.5em; cursor: pointer; }
.view-toggle button:hover { color: var(--ink); border-color: var(--ink); }
.view-toggle button[aria-pressed="true"] { color: var(--paper); background: var(--ink); border-color: var(--ink); }

/* Split view: old on the left, new on the right, rows aligned. It breaks out
   of the reading column because two columns need the width. */
.lines.split { position: relative; left: 50%; transform: translateX(-50%); width: min(96vw, 64rem); margin: 0 0 1.5rem; font-size: 1rem; }
.lines.split .row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 2px; }
.lines.split .row + .row { margin-top: 2px; }
/* Cells reset the unified line rules (gutter margins, marker box) that the
   shared role classes carry, so each cell stays inside its grid column. */
.lines.split .cell { position: relative; margin: 0; padding: 0.3rem 0.75rem 0.3rem 1.75rem; min-height: 1.5em; min-width: 0; overflow-wrap: anywhere; }
.lines.split .cell::before { position: absolute; left: 0.6rem; top: 0.3rem; width: auto; text-align: left; line-height: inherit; font-family: var(--mono); font-size: 1rem; font-weight: 600; }
.lines.split .cell.add { background: var(--add-bg); color: var(--add-ink); }
.lines.split .cell.add::before { content: '+'; color: var(--add); }
.lines.split .cell.del { background: var(--del-bg); color: var(--del-ink); text-decoration: line-through; text-decoration-thickness: 1px; text-decoration-color: var(--del); }
.lines.split .cell.del::before { content: '-'; color: var(--del); }
.lines.split .cell.del.mod { text-decoration: none; }
.lines.split .cell.empty { background: repeating-linear-gradient(45deg, transparent 0 6px, var(--rule) 6px 7px); }
@media (max-width: 64rem) {
  .view-toggle { display: none; }
  .lines.split { display: none !important; }
  .lines.unified { display: block !important; }
}

/* CV year ruler: one bar per commit, each a link to its entry. Bars are
   positioned by date as a percentage of 2009 to now. */
.ruler { margin: 0 0 2.5rem; font-family: var(--mono); font-size: 0.75rem; }
.ruler ol { list-style: none; margin: 0; padding: 0; }
.ruler-rows li { position: relative; height: 1.45rem; margin: 0; }
.ruler-rows a { position: absolute; left: var(--from); width: calc(var(--to) - var(--from)); min-width: 3px; top: 0.2rem; height: 1rem; background: var(--add-bg); border-left: 2px solid var(--ink); text-decoration: none; color: var(--ink); }
.ruler-rows a span { position: absolute; left: 100%; top: 0; line-height: 1rem; padding-left: 0.4rem; white-space: nowrap; }
.ruler-rows a.late span { left: auto; right: 100%; padding-left: 0; padding-right: 0.4rem; }
.ruler-rows a:hover { background: var(--add); }
.ruler-rows a:hover span { text-decoration: underline; }
.ruler-axis { position: relative; height: 1.5rem; border-top: 1px solid var(--rule); margin-top: 0.35rem; }
.ruler-axis li { position: absolute; left: var(--at); top: 0.3rem; transform: translateX(-50%); color: var(--ink-2); margin: 0; }
.ruler-axis li::before { content: ''; position: absolute; left: 50%; top: -0.55rem; height: 0.4rem; border-left: 1px solid var(--rule); }
.ruler-axis li.now { color: var(--add); transform: translateX(-100%); }
.ruler-axis li.now::before { left: 100%; border-color: var(--add); }
.commit { scroll-margin-top: 1rem; }

/* An artifact: a screenshot of the running thing, captioned in the machine voice. */
.artifact { margin: 1rem 0 1.5rem; }
.artifact img { display: block; max-width: 100%; height: auto; border: 1px solid var(--rule); }
.artifact figcaption { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-2); margin-top: 0.4rem; }
