/* ==========================================================================
   1. FONTS
   Cantata One — display serif, weight 400 only (headings, strong).
   Carme      — humanist sans, weight 400 only (body, UI).

   Self-hosted rather than pulled from Google Fonts: one less origin to
   connect to, no third-party request on every page view, and the type can
   never fail to arrive because an external CDN is slow or blocked.
   51 KB total for all three files.
   ========================================================================== */

@font-face {
  font-family: "Cantata One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/cantata-one-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: "Cantata One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/cantata-one-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-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: "Carme";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/carme-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;
}

/* ==========================================================================
   2. DESIGN TOKENS
   ========================================================================== */

:root {
  /* Surfaces */
  --page-bg: #0c0c11;
  --page-bg-secondary: #101016;
  --card-bg: #0f0f14;
  --card-bg-hover: #131319;
  --card-inner: #0b0b10;
  --terminal-bg: #0a0a0e;

  /* Text */
  --text-primary: #f3f1f4;
  --text-secondary: #aaa6b0;
  --text-faint: #77737e;

  /* Lines */
  --border: rgba(255, 255, 255, 0.055);
  --border-hover: rgba(255, 255, 255, 0.1);
  --border-strong: rgba(255, 255, 255, 0.14);

  /* Atmosphere */
  --purple-pearl: rgba(111, 75, 126, 0.16);
  --purple-pearl-soft: rgba(157, 126, 174, 0.08);

  /* Accents — gold for labels/links, purple for buttons */
  --accent: #c5a45b;
  --accent-bright: #d8ba76;
  --accent-dim: rgba(197, 164, 91, 0.14);
  --button-bg: #241c2c;
  --button-bg-hover: #2c2236;
  --button-border: rgba(168, 134, 188, 0.34);
  --button-text: #efe9f3;

  /* Status */
  --ok: #7fc39a;
  --bad: #d98a8a;

  /* Type scale */
  --fs-hero: clamp(2.125rem, 2.6vw + 1.6rem, 4rem);
  --fs-page-title: clamp(2rem, 2.2vw + 1.5rem, 3.25rem);
  --fs-article-title: clamp(1.9375rem, 3.2vw + 1rem, 3.25rem);
  --fs-card-title: clamp(1.6875rem, 1.4vw + 1.35rem, 2rem);
  --fs-section: clamp(1.5rem, 1vw + 1.2rem, 1.75rem);
  --fs-h2: clamp(1.5625rem, 1.2vw + 1.3rem, 1.75rem);
  --fs-h3: 1.25rem;
  --fs-body: 1rem;
  --fs-lead: 1.0625rem;
  --fs-action: 0.875rem;
  --fs-nav: 0.9375rem;
  --fs-meta: 0.8125rem;
  --fs-label: 0.75rem;
  --fs-code: 0.875rem;

  /* Rhythm */
  --lh-body: 1.7;
  --block-gap: 48px;
  --grid-gap: 44px;
  --card-pad: 40px;
  --shell: 1200px;
  --shell-pad: 24px;
  --measure: 65ch;
  --article-col: 800px;

  /* Radii */
  --r-card: 10px;
  --r-inner: 8px;
  --r-button: 8px;
  --r-pill: 999px;

  /* Depth */
  --shadow-card: 0 10px 26px rgba(0, 0, 0, 0.22);
  --shadow-card-hover: 0 14px 32px rgba(0, 0, 0, 0.3);
  --inner-top: inset 0 1px 0 rgba(255, 255, 255, 0.025);

  --fonts-display: "Cantata One", Georgia, "Times New Roman", serif;
  --fonts-body: "Carme", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --fonts-mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}

/* ==========================================================================
   3. RESET / BASE
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--page-bg);
  color: var(--text-primary);
  font-family: var(--fonts-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  /* Cantata One ships weight 400 only — never let the browser fake a bold. */
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}

/* Soft purple pearlescence: upper-right glow, fainter lower-left counterweight. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60rem 40rem at 82% -6%, var(--purple-pearl), transparent 62%),
    radial-gradient(48rem 36rem at 8% 88%, var(--purple-pearl-soft), transparent 66%);
}

main {
  flex: 1 0 auto;
}

a {
  color: inherit;
  text-decoration: none;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

img,
svg {
  display: block;
  max-width: 100%;
}

hr {
  height: 1px;
  margin: 40px 0;
  border: 0;
  background: var(--border);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: var(--r-button);
  background: var(--button-bg);
  border: 1px solid var(--button-border);
  color: var(--button-text);
  transition: top 0.18s ease;
}

.skip-link:focus {
  top: 12px;
}

/* ==========================================================================
   4. TYPOGRAPHY
   Every heading and every bold word uses Cantata One at its real weight 400.
   Emphasis comes from scale, spacing and colour — never synthetic bolding.
   ========================================================================== */

h1,
h2,
h3,
h4,
strong,
b {
  font-family: var(--fonts-display);
  font-weight: 400;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  color: var(--text-primary);
  letter-spacing: -0.01em;
  line-height: 1.18;
}

/* Long unbreakable tokens (ERR_HTTP2_PROTOCOL_ERROR, cmdlet names) must wrap
   rather than push the page wider than the viewport on small screens.
   Code inside terminals is excluded — those scroll horizontally instead. */
h1,
h2,
h3,
h4,
p,
li,
td,
th,
.card-action,
.text-link {
  overflow-wrap: break-word;
}

h1 {
  font-size: var(--fs-hero);
  line-height: 1.08;
}

h2 {
  font-size: var(--fs-h2);
}

h3 {
  font-size: var(--fs-h3);
}

p {
  margin: 0 0 1.1em;
}

p:last-child {
  margin-bottom: 0;
}

strong,
b {
  color: var(--text-primary);
  letter-spacing: 0.005em;
}

code,
kbd,
samp {
  font-family: var(--fonts-mono);
  font-size: 0.9em;
}

.label {
  margin: 0;
  color: var(--accent);
  font-family: var(--fonts-body);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.lead {
  max-width: var(--measure);
  color: var(--text-secondary);
  font-size: var(--fs-lead);
}

.meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--text-faint);
  font-size: var(--fs-meta);
  list-style: none;
  padding: 0;
}

.meta li + li::before {
  content: "·";
  margin-right: 10px;
  color: var(--text-faint);
}

/* ==========================================================================
   5. LAYOUT
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--shell-pad);
}

.page-main {
  padding-block: 64px 88px;
}

/* Label sits OUTSIDE and 2px above its card. */
.block {
  display: block;
}

.block + .block {
  margin-top: var(--block-gap);
}

.block-label {
  margin: 0 0 2px 4px;
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--grid-gap);
}

/* Each column wraps a label + card; stretch so both cards end level. */
.grid-2 > * {
  display: flex;
  flex-direction: column;
}

.grid-2 > * > .card {
  flex: 1;
}

/* ==========================================================================
   6. HEADER / NAVIGATION
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid var(--border);
  background: rgba(12, 12, 17, 0.78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.site-header .shell {
  min-height: 70px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-family: var(--fonts-display);
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 26px;
  font-size: var(--fs-nav);
}

.site-nav a {
  position: relative;
  padding: 4px 0;
  color: var(--text-secondary);
  transition: color 0.18s ease;
}

.site-nav a:hover {
  color: var(--text-primary);
}

.site-nav a[aria-current="page"] {
  color: var(--text-primary);
}

.site-nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: var(--accent);
}

/* ==========================================================================
   7. CARDS
   ========================================================================== */

.card {
  position: relative;
  display: block;
  padding: var(--card-pad);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  background: var(--card-bg);
  box-shadow: var(--shadow-card), var(--inner-top);
}

a.card {
  transition: transform 0.2s ease, background-color 0.2s ease,
    border-color 0.2s ease, box-shadow 0.2s ease;
}

a.card:hover {
  transform: translateY(-2px);
  background: var(--card-bg-hover);
  border-color: var(--border-hover);
  box-shadow: var(--shadow-card-hover), var(--inner-top);
}

.card h2,
.card h3 {
  margin-bottom: 14px;
  font-size: var(--fs-card-title);
  line-height: 1.2;
}

.card p {
  color: var(--text-secondary);
  max-width: var(--measure);
}

.card-action {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 22px;
  color: var(--accent);
  font-size: var(--fs-action);
  letter-spacing: 0.01em;
}

a.card:hover .card-action {
  color: var(--accent-bright);
}

.card-action span {
  transition: transform 0.2s ease;
}

a.card:hover .card-action span {
  transform: translateX(3px);
}

.pill {
  display: inline-block;
  margin-top: 22px;
  padding: 6px 12px;
  border: 1px solid var(--border-hover);
  border-radius: var(--r-pill);
  background: var(--card-inner);
  color: var(--text-secondary);
  font-size: var(--fs-meta);
  letter-spacing: 0.04em;
}

/* Buttons — inverted from the page: purple surface with a black pearl sheen. */
.button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border: 1px solid var(--button-border);
  border-radius: var(--r-button);
  background:
    radial-gradient(120% 140% at 20% 110%, rgba(0, 0, 0, 0.5), transparent 60%),
    linear-gradient(160deg, var(--button-bg), #1b1522);
  box-shadow: var(--inner-top);
  color: var(--button-text);
  font-family: var(--fonts-body);
  font-size: var(--fs-action);
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease,
    transform 0.18s ease;
}

.button:hover {
  background:
    radial-gradient(120% 140% at 20% 110%, rgba(0, 0, 0, 0.44), transparent 60%),
    linear-gradient(160deg, var(--button-bg-hover), #221a2a);
  border-color: var(--border-strong);
  transform: translateY(-1px);
}

.button--ghost {
  background: transparent;
  border-color: var(--border);
  box-shadow: none;
  color: var(--text-secondary);
}

.button--ghost:hover {
  background: var(--card-inner);
  border-color: var(--border-hover);
  color: var(--text-primary);
}

.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* Inline text links that should read as links */
.text-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent);
  font-size: var(--fs-action);
}

.text-link:hover {
  color: var(--accent-bright);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ==========================================================================
   8. HOME PAGE
   ========================================================================== */

.hero {
  --hero-logo-w: min(420px, 74vw);

  /* Every line under the logo sits this far from the one above it, measured
     ink to ink — the wordmark included. 11px is the leading already running
     between the two lines of the lead, so the whole stack shares one rhythm. */
  --hero-gap: 11px;

  padding-block: 72px 56px;
  text-align: center;
}

/* The logo artwork carries the wordmark, so the h1 is present for search
   engines and screen readers but not shown twice on screen.

   --hero-gap is measured lettering to lettering, so both rules below subtract
   what sits between a line box and the ink inside it: the PNG ends 118px below
   the last letter of JOHN'S TECH NOTES (11.7% of its own width, so it grows
   with the logo), and a line of text carries half its leading above the
   letterforms. Without that correction the wordmark drifts further from the
   text the larger the logo gets — which is exactly what it used to do. */
.hero-logo {
  width: var(--hero-logo-w);
  height: auto;
  margin: 0 auto calc(var(--hero-gap) - 11.4px - 0.117 * var(--hero-logo-w));
}

.hero h1 {
  max-width: 16ch;
  margin-inline: auto;
}

.hero-lead {
  max-width: 62ch;
  margin: 0 auto;
  color: var(--text-secondary);
  font-size: var(--fs-lead);
}

.hero-sub {
  max-width: 62ch;
  margin: calc(var(--hero-gap) - 7.9px) auto 0;
  color: var(--text-faint);
  font-size: var(--fs-action);
}

.home-sections {
  padding-bottom: 96px;
  text-align: center;
}

.home-sections .block-label {
  margin-left: 0;
}

.home-sections .card p,
.home-sections .card h2 {
  margin-inline: auto;
}

.home-sections .card-action,
.home-sections .pill {
  margin-inline: auto;
}

/* Latest fix card — stacked and centred rather than split into columns. */
.latest {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.latest .protocol {
  width: min(340px, 100%);
  margin: 4px auto 24px;
  text-align: left;
}

/* The protocol block is sized so the headline clears 775px and stays on one
   line at desktop; below that the single <wbr> in ERR_HTTP2_PROTOCOL_ERROR
   makes it break at an underscore instead of mid-word. */

/* Restrained editorial visual: an HTTP/2 protocol status block. */
.protocol {
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: var(--r-inner);
  background: var(--card-inner);
  font-family: var(--fonts-mono);
  font-size: var(--fs-meta);
  line-height: 1.9;
}

.protocol-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  color: var(--text-faint);
}

.protocol-row span:last-child {
  color: var(--text-secondary);
}

.protocol-state {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  color: var(--text-faint);
}

.protocol-state b {
  font-family: var(--fonts-mono);
  color: var(--bad);
  letter-spacing: 0.04em;
}

/* About card on the home page — no nested anchors, explicit links instead. */
.about-card h2,
.about-card p {
  max-width: var(--measure);
}

/* Links sit at the foot of the card in a centred column:
   RSS feed, then GitHub, then Read more. */
.about-card .about-links {
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin-top: 30px;
  padding-top: 26px;
  border-top: 1px solid var(--border);
}

/* Cantata One has one weight, so emphasis is carried by colour, not by a
   heavier cut. Same treatment wherever this passage appears. */
.about-card strong,
.about-body strong {
  color: var(--accent);
}

.about-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 24px;
  margin-top: 26px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}

/* ==========================================================================
   9. ARTICLES PAGE
   ========================================================================== */

.page-header {
  max-width: 46ch;
  padding-bottom: 36px;
}

.page-header h1 {
  margin: 6px 0 16px;
  font-size: var(--fs-page-title);
}

.page-header .lead {
  color: var(--text-secondary);
  font-size: var(--fs-lead);
}

.category-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 16px 0 8px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  margin-bottom: 56px;
  padding-bottom: 16px;
}

.category-nav a {
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  color: var(--text-secondary);
  font-size: var(--fs-action);
  transition: color 0.18s ease, border-color 0.18s ease,
    background-color 0.18s ease;
}

.category-nav a:hover {
  background: var(--card-inner);
  border-color: var(--border-hover);
  color: var(--text-primary);
}

.category-nav a[aria-current="page"] {
  border-color: var(--accent-dim);
  background: var(--accent-dim);
  color: var(--accent);
}

.section + .section {
  margin-top: 64px;
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 20px;
  margin-bottom: 24px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.section-head h2 {
  font-size: var(--fs-section);
}

.section-head p {
  max-width: 48ch;
  margin: 0;
  color: var(--text-faint);
  font-size: var(--fs-action);
}

.section-count {
  color: var(--text-faint);
  font-size: var(--fs-meta);
  font-family: var(--fonts-mono);
}

/* Article card */
.entry {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 32px;
  align-items: start;
}

.entry-visual {
  min-height: 108px;
  display: grid;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r-inner);
  background: var(--card-inner);
  color: var(--accent);
  font-family: var(--fonts-mono);
  font-size: 0.9375rem;
  letter-spacing: 0.04em;
}

.entry h2,
.entry h3 {
  margin-bottom: 12px;
  font-size: 1.375rem;
  line-height: 1.28;
}

.entry p {
  margin-bottom: 16px;
  color: var(--text-secondary);
}

.empty-state {
  padding: 34px 40px;
  border: 1px dashed var(--border-hover);
  border-radius: var(--r-card);
  background: rgba(255, 255, 255, 0.012);
  color: var(--text-faint);
}

.empty-state p {
  margin: 0;
}

/* ==========================================================================
   10. ABOUT PAGE
   ========================================================================== */

.about-body {
  max-width: 68ch;
}

.about-body p {
  margin-bottom: 1.35em;
  color: var(--text-secondary);
  font-size: var(--fs-lead);
}

.about-body p:first-of-type {
  color: var(--text-primary);
}

.about-body strong {
  color: var(--accent);
}

/* ==========================================================================
   11. ARTICLE PAGE
   ========================================================================== */

.article-layout {
  display: grid;
  grid-template-columns: minmax(0, var(--article-col)) 216px;
  gap: 56px;
  align-items: start;
  padding-block: 40px 96px;
}

/* Pages without a table of contents (the TL;DR) drop the rail entirely
   rather than leaving an empty column. */
.article-layout--single {
  grid-template-columns: minmax(0, var(--article-col));
}

/* The column, not the viewport, is what article type has to fit into. */
.article-layout > article {
  container-type: inline-size;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 26px;
  color: var(--text-secondary);
  font-size: var(--fs-action);
}

.back-link:hover {
  color: var(--accent);
}

.article-header {
  padding-bottom: 34px;
  margin-bottom: 40px;
  border-bottom: 1px solid var(--border);
}

.article-header h1 {
  margin: 10px 0 18px;
  font-size: var(--fs-article-title);
  line-height: 1.12;
}

/* A headline built around a long error code. ERR_HTTP2_PROTOCOL_ERROR stays
   whole rather than breaking at an underscore, so this title is sized from the
   token instead of the shared title scale. In Cantata One those 24 characters
   measure ~17.6x the font size, so 5.5% of the column keeps them on one line
   with a little room to spare — 44px in the full 800px column, scaling down
   with the column on narrower screens. Sized against the column rather than
   the viewport because the desktop table of contents takes 272px out of it. */
.article-header h1.title-code {
  font-size: min(2.75rem, 5vw);
  font-size: min(2.75rem, 5.5cqi);
}

.title-code__token {
  white-space: nowrap;
}

.article-deck {
  max-width: var(--measure);
  color: var(--text-secondary);
  font-size: var(--fs-lead);
}

.article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  color: var(--text-faint);
  font-size: var(--fs-meta);
}

.article-meta li + li::before {
  content: "·";
  margin-right: 10px;
}

.article-actions {
  margin-top: 26px;
}

.article-body > *:first-child {
  margin-top: 0;
}

.article-body p,
.article-body li {
  color: var(--text-secondary);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.article-body p,
.article-body ul,
.article-body ol {
  max-width: var(--measure);
}

.article-body h2 {
  margin: 56px 0 18px;
  padding-top: 8px;
  scroll-margin-top: 92px;
}

.article-body h3 {
  margin: 36px 0 12px;
  scroll-margin-top: 92px;
}

.article-body ul,
.article-body ol {
  margin: 0 0 1.1em;
  padding-left: 1.3rem;
}

.article-body li + li {
  margin-top: 8px;
}

.article-body a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.article-body a:hover {
  color: var(--accent-bright);
}

.article-body :not(pre) > code {
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--card-inner);
  color: var(--accent-bright);
}

.article-body strong {
  color: var(--text-primary);
}

/* Results table */
.table-wrap {
  margin: 26px 0;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-inner);
}

.article-body table {
  width: 100%;
  min-width: 380px;
  border-collapse: collapse;
  font-size: var(--fs-action);
}

.article-body th,
.article-body td {
  padding: 13px 18px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.article-body thead th {
  background: var(--card-inner);
  color: var(--text-primary);
  font-family: var(--fonts-display);
  font-weight: 400;
}

.article-body tbody tr:last-child td {
  border-bottom: 0;
}

.article-body td {
  color: var(--text-secondary);
}

.result-good {
  color: var(--ok);
}

.result-bad {
  color: var(--bad);
}

/* Desktop table of contents */
.toc {
  position: sticky;
  top: 96px;
  align-self: start;
  padding-left: 22px;
  border-left: 1px solid var(--border);
}

.toc h2 {
  margin-bottom: 14px;
  color: var(--text-faint);
  font-family: var(--fonts-body);
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.toc ol {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 10px;
}

.toc a {
  display: block;
  color: var(--text-faint);
  font-size: var(--fs-meta);
  line-height: 1.45;
  transition: color 0.18s ease;
}

.toc a:hover {
  color: var(--accent);
}

.article-footer {
  max-width: var(--article-col);
  margin-top: 56px;
  padding-top: 30px;
  border-top: 1px solid var(--border);
}

.article-footer p {
  color: var(--text-faint);
  font-size: var(--fs-action);
}

/* ==========================================================================
   12. CODE: OUTPUT AND TERMINAL
   ========================================================================== */

/* Program output, errors and service states are not commands: they get a
   plain black highlight, no terminal chrome and no copy button. Only real
   commands become terminals. */
.output {
  margin: 22px 0 26px;
  padding: 16px 18px;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-left: 2px solid var(--border-strong);
  border-radius: var(--r-inner);
  background: #08080b;
  color: #c9c6d0;
  font-family: var(--fonts-mono);
  font-size: var(--fs-code);
  line-height: 1.62;
  tab-size: 4;
}

.output code {
  font-size: inherit;
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
}

.terminal {
  position: relative;
  margin: 24px 0 28px;
  border: 1px solid var(--border);
  border-radius: var(--r-inner);
  background: var(--terminal-bg);
  overflow: hidden;
}

.terminal__bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.018);
}

.terminal__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--border-strong);
}

.terminal__label {
  margin-left: 8px;
  color: var(--text-faint);
  font-family: var(--fonts-body);
  font-size: var(--fs-meta);
  letter-spacing: 0.06em;
}

.terminal pre {
  /* Bottom padding reserves the copy button's gutter so code is never hidden. */
  margin: 0;
  padding: 18px 18px 46px;
  overflow-x: auto;
  color: #dcd9e0;
  font-family: var(--fonts-mono);
  font-size: var(--fs-code);
  line-height: 1.62;
  tab-size: 4;
}

.terminal pre code {
  font-size: inherit;
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
}

.terminal__copy {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  border: 1px solid var(--button-border);
  border-radius: 8px;
  background:
    radial-gradient(120% 140% at 20% 110%, rgba(0, 0, 0, 0.5), transparent 60%),
    linear-gradient(160deg, var(--button-bg), #1b1522);
  color: var(--text-secondary);
  font-family: var(--fonts-body);
  font-size: var(--fs-meta);
  line-height: 1;
  cursor: pointer;
  opacity: 0.72;
  transition: opacity 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

.terminal:hover .terminal__copy,
.terminal__copy:focus-visible {
  opacity: 1;
  color: var(--text-primary);
  border-color: var(--border-strong);
}

.terminal__copy[data-state="done"] {
  opacity: 1;
  color: var(--ok);
  border-color: rgba(127, 195, 154, 0.4);
}

.terminal__copy[data-state="error"] {
  opacity: 1;
  color: var(--bad);
  border-color: rgba(217, 138, 138, 0.4);
}

/* Touch devices have no hover — keep the control permanently visible. */
@media (hover: none) {
  .terminal__copy {
    opacity: 1;
  }
}

/* ==========================================================================
   13. RSS PRESENTATION (feed.xsl)
   ========================================================================== */

.feed-note {
  padding: 26px 30px;
  margin-bottom: 40px;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  background: var(--card-inner);
}

.feed-note h2 {
  margin-bottom: 10px;
  font-size: var(--fs-h3);
}

.feed-note p {
  color: var(--text-secondary);
  font-size: var(--fs-action);
  max-width: var(--measure);
}

.feed-note code {
  display: inline-block;
  max-width: 100%;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--page-bg);
  color: var(--accent-bright);
  /* The feed URL is one unbreakable token; let it wrap rather than push the
     page wider than a phone viewport. */
  overflow-wrap: anywhere;
}

.feed-list {
  display: grid;
  gap: 20px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Grid items default to min-width:auto, so an unbreakable token in a feed
   title stretches the row past the viewport. Let them shrink. */
.feed-list > li {
  min-width: 0;
}

/* Feed titles come from feed.xml as plain text, so they carry no <wbr>
   hints; `anywhere` lets the token break and shrinks its min-content size. */
.feed-item h3 {
  overflow-wrap: anywhere;
}

.feed-item h3 {
  margin-bottom: 10px;
  font-size: 1.25rem;
  line-height: 1.3;
}

.feed-item p {
  color: var(--text-secondary);
  margin-bottom: 14px;
}

.feed-date {
  display: block;
  margin-bottom: 10px;
  color: var(--text-faint);
  font-family: var(--fonts-mono);
  font-size: var(--fs-meta);
}

/* ==========================================================================
   14. 404 PAGE
   ========================================================================== */

.notfound {
  padding-block: 100px 120px;
  text-align: center;
}

.notfound-code {
  margin: 0 0 14px;
  color: var(--accent);
  font-family: var(--fonts-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.2em;
}

.notfound h1 {
  font-size: var(--fs-page-title);
}

.notfound p {
  max-width: 52ch;
  margin: 18px auto 32px;
  color: var(--text-secondary);
}

.notfound .button-row {
  justify-content: center;
}

/* ==========================================================================
   15. FOOTER
   ========================================================================== */

.site-footer {
  flex-shrink: 0;
  margin-top: auto;
  border-top: 1px solid var(--border);
  background: var(--page-bg-secondary);
}

.site-footer .shell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 32px;
  padding-block: 28px;
}

.site-footer p {
  margin: 0;
  color: var(--text-faint);
  font-size: var(--fs-action);
}

.site-footer p + p {
  text-align: right;
}

/* ==========================================================================
   16. RESPONSIVE
   ========================================================================== */

@media (max-width: 1024px) {
  :root {
    --block-gap: 36px;
    --grid-gap: 32px;
    --card-pad: 28px;
    --shell-pad: 18px;
  }

  .article-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .toc {
    display: none;
  }

  .latest {
    grid-template-columns: minmax(0, 1fr);
  }

  .latest .protocol {
    order: -1;
  }
}

@media (max-width: 860px) {
  .grid-2 {
    grid-template-columns: 1fr;
    gap: var(--block-gap);
  }

  .hero {
    padding-block: 62px 48px;
  }

  .entry {
    grid-template-columns: 1fr;
    gap: 22px;
  }

  .entry-visual {
    min-height: 76px;
  }
}

@media (max-width: 640px) {
  :root {
    --block-gap: 28px;
    --grid-gap: 28px;
    --card-pad: 22px;
    --shell-pad: 14px;
  }

  /* The wordmark now carries the header on its own, and it plus four nav links
     will not fit one phone-width row, so the nav drops below it when short. */
  .site-header .shell {
    min-height: 64px;
    flex-wrap: wrap;
    align-content: center;
    gap: 2px 14px;
    padding-block: 10px;
  }

  .site-nav {
    gap: 16px;
    font-size: var(--fs-action);
  }

  .page-main {
    padding-block: 44px 64px;
  }

  .article-layout {
    padding-top: 28px;
  }

  .article-body h2 {
    margin-top: 44px;
  }

  .empty-state {
    padding: 26px 22px;
  }

  .site-footer .shell {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .site-footer p + p {
    text-align: left;
  }
}

/* ==========================================================================
   17. REDUCED MOTION
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  a.card:hover,
  .button:hover {
    transform: none;
  }
}
