@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("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: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/inter-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;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Design system: International Typographic Style (Swiss school), applied to a
   technical blog. Three rules, no exceptions:

   1. ONE COLUMN. Text, code, callouts, tables, figures — every block shares the
      same two edges as the header and footer rules. Nothing breaks out. On phones
      the column loses its padding and every block goes edge to edge together.
   2. ONE SPACE SCALE. Every margin and padding is a multiple of 8px (--s*).
      No hand-picked values anywhere.
   3. ONE TYPE SCALE, ratio 1.2, and TWO rule weights (3px structural, 1px minor).

   Sizes are derived from one number, --cap, the way tonsky.me does it: spacing measured
   in letters rather than pixels, so a larger body size carries the whole rhythm with it.
   The column fits 80-column code; prose lands at ≈88 characters, the wide end of
   Butterick's 45–90. Never size the grid in ch — it resolves against each element's own
   font and silently yields a different width per block. Body sans, mono for the mechanical.
   ───────────────────────────────────────────────────────────────────────────── */
:root {
  /* ── one primitive: the cap height of the body face ──────────────────────
     Everything below is derived from it — type sizes, spacing, column width.
     Change --cap alone and the whole page rescales in proportion. */
  --cap: .7725rem;                        /* ≈12.4px: Inter's cap height at a 17px body */
  --t-body: calc(var(--cap) / .727);      /* .727 is Inter's cap ratio (1490/2048 em) */
  --unit: calc(var(--cap) * 1.3);         /* one rhythm step ≈16px; all spacing is multiples */

  /* space: multiples of the rhythm step, not of a pixel count */
  --s1: calc(var(--unit) / 2); --s2: var(--unit); --s3: calc(var(--unit) * 1.5);
  --s4: calc(var(--unit) * 2); --s6: calc(var(--unit) * 3); --s8: calc(var(--unit) * 4);

  /* type: ratio 1.2 in both directions from the body size */
  --t-micro: calc(var(--t-body) / 1.44); --t-small: calc(var(--t-body) / 1.2);
  --t-h3: calc(var(--t-body) * 1.2); --t-h2: calc(var(--t-body) * 1.44);
  --t-h1: calc(var(--t-body) * 1.728);

  /* rules: exactly two weights */
  --rule-major: 3px; --rule-minor: 1px;

  /* grid: one column, sized so 80-column code never wraps. Mono runs at .875em and
     ~.6em per glyph, so 44 × body size fits ~84 columns — and it now follows the type. */
  --pad: var(--s3);
  --col: calc(var(--t-body) * 44);

  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  /* GitHub Light */
  --bg: #ffffff; --surface: #f6f8fa; --fg: #1f2328; --muted: #59636e;
  --line: #1f2328; --hair: #d1d9e0;
  --accent: #1a7f37; --on-accent: #ffffff; --danger: #cf222e;
  /* the one wide-gamut colour: 0.196 chroma is past the sRGB ceiling for this hue,
     so P3 shows a deeper green and sRGB clamps back to --accent. Small areas only. */
  --vivid: #1a7f37; --vivid: oklch(52% 0.196 148);
}
/* GitHub Dark Dimmed */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #22272e; --surface: #2d333b; --fg: #c9d1d9; --muted: #768390;
    --line: #c9d1d9; --hair: #444c56;
    --accent: #57ab5a; --on-accent: #22272e; --danger: #e5534b;
    --vivid: #57ab5a; --vivid: oklch(67% 0.245 144);
  }
}
:root[data-theme="dark"] {
  --bg: #22272e; --surface: #2d333b; --fg: #c9d1d9; --muted: #768390;
  --line: #c9d1d9; --hair: #444c56;
  --accent: #57ab5a; --on-accent: #22272e; --danger: #e5534b;
  --vivid: #57ab5a; --vivid: oklch(67% 0.245 144);
}

* { box-sizing: border-box; }
html { color-scheme: light dark; }
body {
  hanging-punctuation: first last;   /* quotes hang into the margin where supported */
  max-width: calc(var(--col) + 2 * var(--pad)); margin: 0 auto; padding: 0 var(--pad) var(--s6);
  min-height: 100dvh; display: flex; flex-direction: column;   /* footer holds the bottom on short pages */
  background: var(--bg); color: var(--fg);
  font: var(--t-body)/1.7 var(--sans);
  -webkit-text-size-adjust: 100%;
}
main { flex: 1 0 auto; }
::selection { background: var(--vivid); color: var(--on-accent); }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* ── chrome: asymmetric, left-weighted ────────────────────────────────────── */
header {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s2);
  padding: var(--s4) 0 var(--s1); margin-bottom: var(--s4);
  border-bottom: var(--rule-major) solid var(--line);
}
.brand { font: 700 var(--t-body)/1 var(--mono); text-decoration: none; }
.brand:hover { background: var(--accent); color: var(--on-accent); }
#theme {
  font: var(--t-small)/1 var(--mono); color: var(--muted); background: none;
  border: var(--rule-minor) solid var(--hair); padding: var(--s1) var(--s1); cursor: pointer; line-height: 1;
}
#theme:hover { border-color: var(--line); }
footer {
  display: flex; gap: var(--s2); margin-top: var(--s8); padding-top: var(--s1);
  border-top: var(--rule-major) solid var(--line);
  font: var(--t-micro)/1.6 var(--mono); color: var(--muted);
}
footer a:hover { background: var(--accent); color: var(--on-accent); }

/* ── index ────────────────────────────────────────────────────────────────── */
.tagline {
  font: var(--t-micro)/1.5 var(--mono); text-transform: uppercase; letter-spacing: .1em;
  color: var(--muted); margin: 0 0 var(--s4);
}
.posts { list-style: none; margin: 0; padding: 0; border-top: var(--rule-minor) solid var(--hair); }
.posts li { border-bottom: var(--rule-minor) solid var(--hair); }
.posts a { display: flex; gap: var(--s2); align-items: baseline; padding: var(--s2) var(--s1); text-decoration: none; }
.posts a:hover { background: var(--accent); color: var(--on-accent); }
.posts a:hover time { color: var(--on-accent); }
.posts time { flex: none; }
time, .meta { font: var(--t-micro)/1.6 var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }

/* ── the column ───────────────────────────────────────────────────────────── */
article { max-width: 100%; }
/* full margin reset, not just vertical: blockquote and figure carry margin-inline: 40px
   in the browser's own stylesheet, which is what silently narrowed callouts and images. */
article > * { margin: 0 0 var(--s3); }
article > p, article > li { text-wrap: pretty; }   /* no one-word last line in a paragraph */
h1, h2, h3 {
  font-family: var(--mono); font-weight: 700; letter-spacing: -.015em; line-height: 1.2;
  text-wrap: balance;   /* no one-word orphan line in a heading */
}
h1 { font-size: var(--t-h1); margin-bottom: var(--s1); }
/* the hairline separates sections, so it sits far from the heading it precedes and
   close to the section it ends: 64px above the line, 24px below it. */
h2 { font-size: var(--t-h2); margin-top: var(--s8); padding-top: var(--s3); border-top: var(--rule-minor) solid var(--hair); }
h3 { font-size: var(--t-h3); margin-top: var(--s4); }
article .meta { margin-bottom: var(--s4); }
article > ul, article > ol { padding-left: var(--s3); }
blockquote {
  margin: 0 0 var(--s3); padding-left: var(--s2);
  border-left: var(--rule-major) solid var(--accent); color: var(--muted);
}

/* ── artifacts: same edges as everything else ─────────────────────────────── */
pre {
  font-family: var(--mono);   /* explicit: never inherit a font the grid might read */
  background: var(--surface); border: var(--rule-minor) solid var(--hair);
  padding: var(--s2); overflow-x: auto; line-height: 1.55;
}
code { font: .875em/1.55 var(--mono); }
:not(pre) > code { background: var(--surface); border: var(--rule-minor) solid var(--hair); padding: 0 .25em; }
figure { margin: 0 0 var(--s3); }
figure img { display: block; width: 100%; height: auto; border: var(--rule-minor) solid var(--hair); }
figcaption { font: var(--t-micro)/1.5 var(--mono); color: var(--muted); padding-top: var(--s1); }
img, video { max-width: 100%; height: auto; }
table {
  /* no display:block — that leaves the inner table shrink-to-fit, so the box never
     filled the column. Plain width:100% makes the columns share the grid instead. */
  width: 100%; border-collapse: collapse; font-size: var(--t-small); table-layout: auto;
}
th, td { border: var(--rule-minor) solid var(--hair); padding: var(--s1); text-align: left; vertical-align: top; overflow-wrap: break-word; }
th { font: 700 var(--t-micro)/1.4 var(--mono); text-transform: uppercase; letter-spacing: .06em; }
/* a break inside a section, not between them: short, centred, quiet */
hr { border: none; border-top: var(--rule-minor) solid var(--muted); width: 6em; margin: var(--s6) auto; }

/* ── callouts: native GitHub alerts, sentences, so text column ────────────── */
[class^="markdown-alert-"] {
  padding: var(--s2); background: var(--surface);
  border: var(--rule-minor) solid var(--hair); border-left: var(--rule-major) solid var(--muted);
}
[class^="markdown-alert-"] > * { margin: 0 0 var(--s2); }
[class^="markdown-alert-"] > :last-child { margin-bottom: 0; }
[class^="markdown-alert-"]::before {
  display: block; margin-bottom: var(--s1);
  font: 700 var(--t-micro)/1.4 var(--mono); text-transform: uppercase; letter-spacing: .09em;
  color: var(--muted);
}
.markdown-alert-caution { border-left-color: var(--danger); }
.markdown-alert-caution::before { content: "Bad idea"; color: var(--danger); }
.markdown-alert-tip { border-left-color: var(--accent); }
.markdown-alert-tip::before { content: "Do this instead"; color: var(--accent); }
.markdown-alert-warning { border-left-color: var(--danger); }
.markdown-alert-warning::before { content: "Watch out"; color: var(--danger); }
.markdown-alert-note::before { content: "Note"; }
.markdown-alert-important { border-left-color: var(--accent); }
.markdown-alert-important::before { content: "Important"; color: var(--accent); }
[class^="markdown-alert-"] pre { background: var(--bg); }

/* footnotes: config sets bottom_footnotes, so Zola emits a numbered list with a ↩ back
   to the exact reference. Both ends are visible and both are links. */
/* superscript out of the line box, so a footnote marker never nudges line spacing */
sup, sub { vertical-align: baseline; position: relative; font-size: .7em; line-height: 1; }
sup { top: -.45em; }
sub { bottom: -.2em; }
.footnote-reference a {
  text-decoration: none; color: var(--accent);
  font: 700 1em/1 var(--mono); padding-left: .15em;
}
.footnote-reference a:hover { text-decoration: underline; }
.footnotes {
  margin-top: var(--s6); padding-top: var(--s3);
  border-top: var(--rule-minor) solid var(--hair);
  font-size: var(--t-small); color: var(--muted);
}
.footnotes-list { margin: 0; padding-left: var(--s3); }
.footnotes-list li { margin-bottom: var(--s1); }
.footnotes-list li::marker { font-family: var(--mono); }
.footnotes-list p { margin: 0; }
.footnotes a[href*="#fr-"] { text-decoration: none; color: var(--accent); padding-left: .25em; }
/* jumping to either end marks where you landed */
.footnotes-list li:target, sup.footnote-reference:target { outline: 2px solid var(--vivid); outline-offset: 3px; }
.term { color: var(--muted); }
.cursor { background: var(--vivid); color: var(--vivid); animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .cursor { animation: none; } }
.back { font: var(--t-micro)/1.6 var(--mono); margin-top: var(--s6); }

/* ── phone: the grid collapses to one column, artifacts go edge to edge ───── */
@media (max-width: 40rem) {
  /* bigger on a phone, not smaller — it is read at arm's length, not 60cm.
     One number moves type, spacing and column together. */
  :root { --cap: .818rem; --pad: var(--s1); }
  body { line-height: 1.6; }
  header { padding-top: var(--s3); margin-bottom: var(--s3); }
  .tagline { margin-bottom: var(--s3); }
  h2 { margin-top: var(--s4); }
  article > pre, article > figure, article > table, article > .wide,
  article > [class^="markdown-alert-"] {
    margin-left: calc(-1 * var(--pad)); margin-right: calc(-1 * var(--pad));
    width: calc(100% + 2 * var(--pad));
  }
  article > pre { border-left: none; border-right: none; }
  figure img { border-left: none; border-right: none; }
  figcaption { padding-left: var(--pad); padding-right: var(--pad); }
  [class^="markdown-alert-"] { border-right: none; }
  .posts a { flex-direction: column; gap: 0; padding: var(--s1) 0; }
  footer { margin-top: var(--s4); }
}
