/* ============================================================================
   base.css - structure. Quiet by default: one column, wide margins, hairlines,
   no decoration. Every colour and typeface reads a token from themes.css, so a
   variant swap is a token swap and nothing here changes.
   ============================================================================ */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg-2);
  font-family: var(--font-body);
  font-size: var(--s0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Links: the only place colour appears. Underline sits low and thickens on
   hover - a small, deliberate piece of feedback rather than a colour flash. */
a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--underline);
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  transition: text-decoration-color .18s ease, color .18s ease;
}
a:hover { color: var(--fg); text-decoration-color: var(--accent); text-decoration-thickness: 2px; }

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

h1, h2, h3 {
  margin: 0;
  color: var(--fg);
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.15;
  text-wrap: balance;
}

/* ---------------------------------------------------------------- layout -- */
/* One column. The page is mostly margin; the text column never exceeds a
   comfortable measure regardless of viewport. */
.page {
  width: 100%;
  max-width: var(--col);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.stack-lg > * + * { margin-top: clamp(3.5rem, 9vw, 6rem); }

/* Small uppercase label. Used for section names and meta only. */
.label {
  margin: 0;
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
}

.measure { max-width: var(--measure); }

/* Text for screen readers only, e.g. "(opens in a new tab)". */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Contact / follow links: a plain inline list, styled by where it sits. */
.contact {
  display: flex; flex-wrap: wrap; gap: .35rem 1.25rem;
  margin: 0; padding: 0;
  list-style: none;
}

/* ------------------------------------------------------------------ head -- */
.site-head {
  padding-block: 1.6rem;
  border-bottom: 1px solid var(--rule);
  background: var(--bg);
  transition:
    opacity .42s ease,
    transform .42s cubic-bezier(.22, .61, .36, 1),
    background-color .35s ease,
    border-color .35s ease;
}

/* Pages with no hero: the header holds its own space at the top. */
.site-head--sticky { position: sticky; top: 0; z-index: 80; }

/* The homepage: out of flow, so the hero plate starts at the true viewport
   top. It waits above the fold and drops in once the hero is behind you. */
.site-head--float {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 80;
  border-bottom-color: transparent;
}

.site-head.is-hidden {
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
}

/* Phones: tucked away while reading down the page, back on any scroll up
   (see the header script in templates/layout.php). */
@media (max-width: 40rem) {
  .site-head.is-tucked { transform: translateY(-100%); }
}

/* Elevation is earned: the bar only lifts off once there is content beneath
   it. Translucent + blurred so the page reads as passing underneath. */
.site-head.is-elevated {
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  backdrop-filter: blur(14px) saturate(1.6);
  border-bottom-color: var(--rule-strong);
}

/* Fallback for browsers without backdrop-filter: stay opaque rather than
   letting text collide with whatever scrolls behind. */
@supports not (backdrop-filter: blur(1px)) {
  .site-head.is-elevated { background: var(--bg); }
}
.head-in {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1.25rem; flex-wrap: wrap;
}
.head-name {
  font-family: var(--font-display);
  font-size: var(--s0);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--fg);
  text-decoration: none;
}
.head-name:hover { color: var(--fg); }

.head-nav { display: flex; gap: 1.5rem; }
.head-nav a {
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
}
.head-nav a:hover { color: var(--fg); }
/* The section you are in: full ink plus an accent underline, so it reads as
   "here" without relying on colour alone. */
.head-nav a[aria-current="page"] {
  color: var(--fg);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: .55em;
}

/* ------------------------------------------------------------------ intro -- */
.intro { padding-block: clamp(4rem, 12vw, 8rem) clamp(1rem, 3vw, 2rem); }

.intro h1 {
  font-size: var(--s5);
  line-height: 1.02;
  letter-spacing: var(--name-tracking);
  margin-bottom: 1.75rem;
}

.intro-body {
  max-width: var(--measure);
  font-size: var(--s2);
  line-height: 1.55;
  color: var(--fg-2);
}
.intro-body p { margin: 0; }
.intro-body p + p { margin-top: 1rem; }
.intro-body strong { color: var(--fg); font-weight: var(--strong-weight); }

.intro-contact {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem 1.25rem;
  margin-top: 1.75rem;
}
.contact--intro {
  font-family: var(--font-meta);
  font-size: var(--s-1);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
}
.contact--intro a { color: var(--fg); }

/* Roles line - plain text, no animation. */
.roles {
  margin: 0 0 1.5rem;
  font-family: var(--font-meta);
  font-size: var(--s-1);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
}

/* --------------------------------------------------------------- section -- */
.section { padding-block: clamp(2.5rem, 6vw, 4rem); }
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-bottom: .5rem;
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--fg);
}
.section-head h2 { font-size: var(--s1); letter-spacing: var(--meta-tracking); text-transform: uppercase; font-weight: var(--meta-weight); font-family: var(--font-meta); color: var(--fg); }

/* --------------------------------------------------------------- index --- */
/* The core listing device: title left, meta right, a faint leader between.
   Same component for work and for writing. */
.index { display: grid; }

.irow {
  display: grid;
  grid-template-columns: auto 1fr auto;   /* title | leader | meta */
  gap: .15rem 1rem;
  align-items: baseline;
  padding-block: 1.15rem;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
}
.irow:hover { color: inherit; }
.irow:hover .irow-title { color: var(--accent); }
.irow:hover .irow-leader { border-bottom-color: var(--accent); }

.irow-title {
  font-family: var(--font-display);
  font-size: var(--s2);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.3;            /* long titles wrap; keep the lines together */
  color: var(--fg);
  transition: color .18s ease;
}

/* The dotted leader - a table-of-contents device; it earns its place by
   tying a title to its date across a wide, otherwise empty gap. */
.irow-leader {
  border-bottom: 1px dotted var(--rule-strong);
  transform: translateY(-.28em);
  min-width: 1.5rem;
  transition: border-color .18s ease;
}
@media (max-width: 34rem) {
  .irow { grid-template-columns: 1fr; }
  .irow-leader { display: none; }
  .irow-meta { grid-column: 1 / -1; }
}

.irow-meta {
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.irow-sub {
  grid-column: 1 / -1;
  margin: .3rem 0 0;
  max-width: var(--measure);
  font-size: var(--s-1);
  color: var(--fg-2);
}

/* Work rows carry a little more: a fact line under the description. */
.irow-facts {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; gap: .35rem 1.1rem;
  margin-top: .6rem;
  font-family: var(--font-meta);
  font-size: var(--s-2);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.irow-facts b { color: var(--fg-2); font-weight: var(--strong-weight); }

/* Work rows are cards with two links. The title link is stretched over the
   whole card (its ::after), so the card still clicks through to the story;
   the site link sits above that layer and goes to the live product. */
.irow--work { position: relative; }
.irow--work .irow-link { color: inherit; text-decoration: none; }
.irow--work .irow-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.irow--work .irow-link:focus-visible { outline: none; }
.irow--work .irow-link:focus-visible::after { outline: 2px solid var(--accent); outline-offset: 2px; }
.irow-visit {
  position: relative; z-index: 2;
  justify-self: end;
  color: var(--fg-2);
  text-decoration: underline;
  text-decoration-color: var(--entry, var(--accent));
  text-decoration-thickness: 1px;
}
.irow-visit:hover { color: var(--fg); text-decoration-thickness: 2px; }
@media (max-width: 40rem) { .irow-visit { justify-self: start; } }

.index-empty {
  margin: 0;
  padding-block: 1.15rem;
  border-bottom: 1px solid var(--rule);
  font-size: var(--s-1);
  color: var(--fg-2);
}

/* -------------------------------------------------------------- article -- */
.article { padding-block: clamp(3rem, 8vw, 5rem); }

.a-head { max-width: var(--measure); margin-bottom: clamp(2.5rem, 6vw, 3.5rem); }
.a-head h1 { font-size: var(--s4); line-height: 1.08; letter-spacing: var(--name-tracking); }
.a-head .dek {
  margin: 1.1rem 0 0;
  font-size: var(--s2);
  line-height: 1.5;
  color: var(--fg-2);
  font-style: var(--dek-style, normal);
}
.byline {
  display: flex; flex-wrap: wrap; gap: .6rem;
  margin-top: 1.75rem; padding-top: .9rem;
  border-top: 1px solid var(--rule);
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.prose { max-width: var(--measure); font-size: var(--s1); line-height: 1.72; color: var(--fg-2); }
.prose > * + * { margin-top: 1.3em; }

/* Section headings read as headings: display face, one step up the scale for
   h2 and a half step for h3, with room above to mark the break. */
.prose h2, .prose h3 {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.25;
  color: var(--fg);
  scroll-margin-top: 6rem;   /* clear the sticky header on #anchor jumps */
}
.prose h2 { font-size: var(--s3); margin-top: 2.2em; }
.prose h3 { font-size: var(--s2); margin-top: 1.8em; }
.prose h2 + *, .prose h3 + * { margin-top: .75em; }

/* Body images: never taller than the screen, so a full-page screenshot does
   not swallow the article. The whole image stays visible (scaled, not
   cropped) and links to the file for the full-size view. */
.prose img { max-height: 80vh; max-height: 80svh; object-fit: contain; }
.prose .img-open { display: block; width: fit-content; max-width: 100%; margin-inline: auto; cursor: zoom-in; text-decoration: none; }
.prose .img-open[style] { width: min(100%, var(--w), 80vh * var(--ar)); width: min(100%, var(--w), 80svh * var(--ar)); }
.prose .img-open[style] img { width: 100%; }
.prose .img-open img {
  display: block;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: var(--bg-2);
}
.prose .img-open:hover img { border-color: var(--rule-strong); }

.prose strong { color: var(--fg); font-weight: var(--strong-weight); }
.prose em { font-style: italic; }

.prose ul { padding-left: 1.1em; margin-top: 1.2em; }
.prose li + li { margin-top: .55em; }
.prose li::marker { color: var(--muted); }

.prose code {
  font-family: var(--font-code);
  font-size: .86em;
  color: var(--fg);
  background: var(--bg-2);
  padding: .08em .3em;
  border-radius: 2px;
}
.prose pre {
  margin: 0;
  overflow-x: auto;            /* wide code scrolls in place, never the page */
  padding: 1rem 1.15rem;
  background: var(--bg-2);
  border-left: 2px solid var(--rule-strong);
  font-family: var(--font-code);
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--fg-2);
}
.prose pre code { background: none; padding: 0; font-size: inherit; }

/* Nothing in a post body may be wider than the column: a pasted 1600px image
   otherwise makes the whole page scroll sideways on a phone. Media shrinks;
   tables scroll inside themselves, as pre does; long URLs wrap. */
.prose { overflow-wrap: break-word; }
.prose img, .prose video, .prose iframe, .prose svg { max-width: 100%; height: auto; }
.prose iframe { width: 100%; }
.prose table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: var(--s-1);
}
.prose th, .prose td { padding: .4rem .8rem .4rem 0; border-bottom: 1px solid var(--rule); text-align: left; vertical-align: top; }
.prose th { color: var(--fg); font-weight: var(--strong-weight); border-bottom-color: var(--rule-strong); }

/* Pull quote: no box, no bar - just larger text and space around it. */
.prose blockquote {
  margin: 2.2em 0;
  padding: 0;
  border: 0;
  font-size: 1.22em;
  line-height: 1.45;
  color: var(--fg);
  text-indent: -.42em;
}
.prose blockquote p { margin: 0; }
.prose blockquote p::before { content: "\201C"; }
.prose blockquote p::after  { content: "\201D"; }

/* End of an article: who wrote it, then where to go next. */
.a-author {
  max-width: var(--measure);
  margin-top: clamp(3rem, 7vw, 4rem);
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}
.a-author-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--fg);
}
.contact--author {
  margin-top: .8rem;
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
}

.a-pager {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
  max-width: var(--measure);
  margin-top: 2.5rem;
}
.a-pager a {
  display: grid; gap: .3rem; align-content: start;
  padding: .9rem 1rem;
  border: 1px solid var(--rule);
  border-radius: 3px;
  text-decoration: none;
}
.a-pager a:hover { border-color: var(--entry, var(--accent)); }
.a-pager a:hover .a-pager-title { color: var(--entry, var(--accent)); }
.a-pager-next { grid-column: 2; text-align: right; }
.a-pager-title {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.3;
  color: var(--fg);
  transition: color .18s ease;
}
@media (max-width: 34rem) {
  .a-pager { grid-template-columns: 1fr; }
  .a-pager-next { grid-column: 1; }
}

.a-foot {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  max-width: var(--measure);
  margin-top: clamp(3rem, 7vw, 4rem);
  padding-top: 1rem;
  border-top: 1px solid var(--fg);
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
}

/* --------------------------------------------------------------- footer -- */
.site-foot {
  margin-top: clamp(4rem, 10vw, 7rem);
  padding-block: 1.6rem 3rem;
  border-top: 1px solid var(--rule);
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--muted);
}
.foot-in { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.contact--foot a { color: var(--fg-2); }
.contact--foot a:hover { color: var(--fg); }

/* ----------------------------------------------- variant picker (local) -- */
/* Dev-only affordance for comparing the three variants. Delete the component
   once a variant is chosen - nothing else references it. */
.picker {
  position: fixed; left: 1rem; bottom: 1rem; z-index: 200;
  display: flex; align-items: center; gap: .2rem;
  max-width: calc(100vw - 2rem);
  overflow-x: auto;
  padding: .3rem;
  background: var(--bg);
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  font-family: var(--font-code);
}
.picker button {
  font: inherit;
  font-size: .625rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); background: transparent; border: 0;
  border-radius: 999px; padding: .38rem .7rem; cursor: pointer;
  white-space: nowrap;
}

@media (max-width: 26rem) {
  .picker { left: .5rem; right: .5rem; max-width: none; justify-content: center; }
  .picker button { padding: .34rem .5rem; font-size: .5625rem; }
}
.picker button:hover { color: var(--fg); }
.picker button[aria-pressed="true"] { background: var(--fg); color: var(--bg); }
.picker .picker-sep { width: 1px; align-self: stretch; background: var(--rule); margin-inline: .2rem; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- /admin ---- */
/* Deliberately plain: this page is a set of links, not a product. */
.admin-new { display: grid; gap: 1rem; justify-items: start; max-width: var(--measure); }

.admin-field { display: grid; gap: .5rem; width: 100%; }
.admin-field input {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--s2);
  color: var(--fg);
  background: var(--bg);
  border: 0;
  border-bottom: 2px solid var(--rule-strong);
  padding: .5rem 0;
  transition: border-color .18s ease;
}
.admin-field input::placeholder { color: var(--muted); opacity: .7; }
.admin-field input:focus { outline: none; border-bottom-color: var(--accent); }

.admin-hint { margin: 0; font-size: var(--s-1); color: var(--muted); }
.admin-hint code { font-family: var(--font-code); font-size: .9em; color: var(--fg-2); }

.admin-btn {
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--bg);
  background: var(--fg);
  border: 1px solid var(--fg);
  padding: .8rem 1.5rem;
  cursor: pointer;
  transition: background .2s ease, color .2s ease, opacity .2s ease;
}
.admin-btn:hover:not(:disabled) { background: transparent; color: var(--fg); }
.admin-btn:disabled { opacity: .35; cursor: not-allowed; }

.admin-badge {
  display: inline-block;
  margin-left: .5rem;
  vertical-align: .12em;
  font-family: var(--font-meta);
  font-size: .5625rem;
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--bg);
  background: var(--muted);
  border-radius: 999px;
  padding: .18rem .5rem;
}

.admin-links {
  display: flex; flex-wrap: wrap; gap: .75rem 2rem;
  font-family: var(--font-meta);
  font-size: var(--s-1);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
}

/* --------------------------------------------------- /admin editor ------- */
.admin-editor { display: grid; gap: 1.4rem; max-width: 44rem; }

.admin-field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--s0);
  line-height: 1.62;
  color: var(--fg);
  background: var(--bg-2);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .85rem 1rem;
  resize: vertical;
  transition: border-color .18s ease;
}
.admin-field textarea:focus { outline: none; border-color: var(--accent); }
.admin-field textarea.admin-mono {
  font-family: var(--font-code);
  font-size: .8125rem;
  line-height: 1.75;
}

.admin-actions { display: flex; flex-wrap: wrap; gap: .75rem 1rem; align-items: center; }
.admin-btn--ghost { color: var(--fg); background: transparent; }
.admin-btn--ghost:hover:not(:disabled) { background: var(--fg); color: var(--bg); }

.admin-status { margin: 0; font-family: var(--font-meta); font-size: var(--s-2); color: var(--muted); }

.admin-row { align-items: baseline; }
.admin-linkish {
  font: inherit;
  font-family: var(--font-display);
  font-size: var(--s2);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--fg);
  background: none; border: 0; padding: 0;
  text-align: left; cursor: pointer;
}
.admin-linkish:hover { color: var(--accent); }

.admin-del {
  font: inherit; font-size: 1rem; line-height: 1;
  color: var(--muted); background: none; border: 0;
  padding: 0 0 0 .6rem; cursor: pointer;
}
.admin-del:hover { color: #C8322B; }

.admin-links a { cursor: pointer; }

/* ------------------------------------------------------ a11y: focus ------ */
/* The global :focus-visible ring above covers links and buttons. The hero
   plate is dark in both themes and sits over a photo, where the light-mode
   teal accent reads weakly (3.7:1 at best), so its ring uses the hero accent. */
.hero :focus-visible { outline-color: var(--hero-accent); }

/* Checkboxes, file pickers and disclosure toggles keep a ring even where a
   field rule removes outlines on :focus for the underlined text inputs. */
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible,
input[type="file"]:focus-visible,
summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ------------------------------------------------ a11y: touch targets ---- */
/* Small uppercase links are ~20px tall. On touch screens, pad them to a
   ~44px tap area; the matching negative margin keeps the layout unchanged. */
@media (pointer: coarse), (max-width: 40rem) {
  .head-name,
  .head-nav a,
  .hero-nav a,
  .section-head a,
  .byline a,
  .a-foot a {
    display: inline-block;
    padding-block: .75rem;
    margin-block: -.75rem;
  }
}

/* ------------------------------------------------------------------ 404 --- */
/* One screen, one message, two ways out. The big numeral is decoration in
   the rule colour, so the sentence under it carries the meaning. */
.nf {
  min-height: calc(100vh - 12rem);
  min-height: calc(100svh - 12rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 3rem;
}
.nf-code {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(6rem, 22vw, 11rem);
  line-height: .9;
  letter-spacing: -.04em;
  color: var(--rule-strong);
  font-variant-numeric: tabular-nums;
}
.nf-title {
  margin: 1.25rem 0 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  font-size: var(--s4);
  line-height: 1.15;
  color: var(--fg);
}
.nf-body { margin: .75rem 0 0; font-size: var(--s1); line-height: 1.55; color: var(--fg-2); }
.nf-path { font-family: var(--font-code); font-size: .9em; color: var(--fg); overflow-wrap: anywhere; }
.nf-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.75rem; margin: 2rem 0 0; }
.nf-btn {
  display: inline-block;
  padding: .8rem 1.4rem;
  font-family: var(--font-meta);
  font-size: var(--s-2);
  font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--bg);
  background: var(--fg);
  border: 1px solid var(--fg);
}
.nf-btn:hover { color: var(--fg); background: transparent; }
.nf-link { font-size: var(--s0); color: var(--accent); }

/* ---------------------------------------------------------------- phones -- */
/* Tap areas of at least ~44px for small links, grown with padding and pulled
   back with a matching negative margin so the layout does not move. */
@media (pointer: coarse), (max-width: 40rem) {
  .contact a,
  .irow-visit { display: inline-block; padding-block: .95rem; margin-block: -.95rem; }
}

/* Short pages (Writing with a few posts, 404) keep the footer at the bottom
   of the window instead of floating mid-screen; long pages are unchanged. */
body:has(> .site-foot) { display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh; }
body:has(> .site-foot) > main { flex: 1 0 auto; }
/* The 404 no longer needs its own viewport maths: main now fills the space. */
.nf { min-height: 0; }
main:has(> .nf) { display: flex; flex-direction: column; justify-content: center; }

/* ------------------------------------------------------- theme switch ---- */
/* Native controls (scrollbars, date pickers) follow the chosen theme too. */
:root { color-scheme: light; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { color-scheme: dark; } }
:root[data-theme="dark"] { color-scheme: dark; }

.head-tools,
.hero-tools { display: flex; align-items: center; gap: .75rem 1rem; }
.theme-btn {
  display: inline-grid; place-items: center;
  width: 2.75rem; height: 2.75rem; margin: -.7rem -.6rem -.7rem 0;
  padding: 0; border: 0; border-radius: 50%;
  color: var(--fg-2); background: none; cursor: pointer;
}
.hero-tools .theme-btn { color: var(--hero-dim); }
/* Hover only where there is a real pointer; on touch it would stick after a tap. */
@media (hover: hover) {
  .theme-btn:hover { color: var(--fg); background: var(--bg-2); }
  .hero-tools .theme-btn:hover { color: var(--hero-fg); background: rgba(255, 255, 255, .08); }
}
.theme-switching *, .theme-switching *::before, .theme-switching *::after { transition: none !important; }
/* Show the icon for where a click takes you: a moon in light, a sun in dark. */
.theme-icon--sun { display: none; }
.theme-btn[data-showing="dark"] .theme-icon--moon { display: none; }
.theme-btn[data-showing="dark"] .theme-icon--sun { display: block; }


/* ------------------------------------------------------ article axis -- */
/* Everything in an article shares one centre line. Text blocks keep a
   readable measure; pictures, diagrams, code and tables are wider and extend
   equally on both sides, so their edges sit symmetrically around the text
   instead of drifting to one side. 100cqw is the page's content width, so on
   phones the wide blocks simply match the text. */
.page { container-type: inline-size; }
.article { --wide: min(100cqw, 54rem); }
.article > .a-head,
.article > .prose,
.article > .a-author,
.article > .a-pager,
.article > .a-foot { max-width: var(--measure); margin-inline: auto; }
.article > .a-cover,
.prose > .fig,
.prose > .diagram,
.prose > .fig-pair,
.prose > pre,
.prose > .table-scroll,
.prose > table {
  width: var(--wide);
  max-width: none;
  margin-inline: calc((100% - var(--wide)) / 2);
}

/* Phones: the sticky header was ~120px of a 640px screen on every page, and
   index pages opened on a landing-page gap. Tighter chrome, same design. */
@media (max-width: 40rem), (max-height: 32rem) {
  .site-head { padding-block: 1rem; }
  .head-in { gap: .25rem 1rem; }
  .head-nav { gap: 1.25rem; }
  .intro { padding-top: 2.5rem; }
  .intro h1 { margin-bottom: 1rem; }
}
/* A phone on its side: the 404 numeral alone filled the screen, pushing the
   two ways out below the fold. */
@media (max-height: 32rem) {
  .nf { padding-block: 1.5rem; }
  .nf-code { font-size: 4.5rem; }
  .nf-title { margin-top: .75rem; }
  .nf-actions { margin-top: 1.25rem; }
}

/* Phones: name, menu and theme button stay on one line. On a 320-393px
   screen they needed ~346px plus the gutters and wrapped into a two-line,
   120px header. Tighter tracking and gaps rather than hiding anything; the
   theme button keeps its ~44px tap area by overlapping its own margin. */
@media (max-width: 40rem) {
  .head-in { flex-wrap: nowrap; align-items: center; gap: .75rem; }
  .head-name { font-size: .95rem; white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .head-tools { flex: none; gap: .7rem; }
  .head-nav { gap: .9rem; }
  .head-nav a { letter-spacing: .07em; }
  .theme-btn { margin: -.7rem -.7rem -.7rem -.2rem; }
}
@media (max-width: 22rem) {
  .head-in { gap: .6rem; padding-inline: 1rem; }
  .head-name { font-size: .88rem; }
  .head-tools { gap: .55rem; }
  .head-nav { gap: .6rem; }
  .head-nav a { letter-spacing: .03em; }
}
