/*
  The site's styles, in pieces. Each template says which pieces it uses (its
  `styles` export), and build.js joins them, in the order the templates come
  in, into one stylesheet: one small file, downloaded once and cached for
  every page.

  The idea is a board: a crisp column of typed text for people who came for
  something specific, and handwritten notes in the margin for people who like
  to wander. In light mode it's a whiteboard and the notes are in blue marker;
  in dark mode it's a blackboard and they're in chalk. Visitors can pick up a
  marker and write on it too (src/board/).

  Everything obeys that: text sits in the column, and anything extra (notes,
  pictures) is stuck in the margin. Nothing floats over the page except the
  little marker tray in the corner.

  This piece: fonts, colours, and the base every page starts from.
*/

/* --- Fonts: self-hosted, Latin subset only. Body text uses the system font: zero bytes. */

@font-face {
  font-family: 'Fraunces';
  src: url('/fonts/fraunces.woff2') format('woff2');
  font-weight: 300 800;
  font-display: swap;
}

/* My handwriting, made into a font from a scan. */
@font-face {
  font-family: 'Aidan Hand';
  src: url('/fonts/aidan-hand.woff2') format('woff2');
  font-display: swap;
}

/* --- Colours. Light (whiteboard) by default; dark (blackboard) follows the
   operating system. --paper is the board itself; --note is the handwriting. */

:root {
  --paper: #f9fafa; /* whiteboard: a cool, slightly glossy white */
  --ink: #1b1d20;
  --ink-soft: #40444a;
  --muted: #73787f;
  --rule: rgb(27 29 32 / 0.12);
  --note: #1d4fc4; /* blue whiteboard marker */
  --accent: #1d4fc4;
  --print: #ffffff; /* the white border of a photo print */

  --serif: 'Fraunces', Georgia, serif;
  --soft: 100; /* Fraunces' rounded ends, 0 to 100 (try values in experiments/fraunces.html) */
  --wonk: 0; /* its leaning, wonky letters, 0 or 1 */
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, Consolas, monospace;
  --hand: 'Aidan Hand', 'Segoe Print', cursive;

  --column: 38rem;
  --margin: 13rem; /* width of the margin-note column on wide screens */
  --gutter: 2.5rem;
  --pad: 1.25rem;

  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #232625; /* blackboard: charcoal with a little slate in it */
    --ink: #ecebe6;
    --ink-soft: #c6c7c2;
    --muted: #8e918d;
    --rule: rgb(236 235 230 / 0.14);
    --note: #f3f2ec; /* white chalk */
    --accent: #f2d675; /* yellow chalk, for links and focus */
    --print: #303432;
  }
}

/* --- Base */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 1.0625rem/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Everything set in Fraunces gets its soft, wonky letters (see --soft, --wonk). */
h1,
h2,
h3,
.site-name,
.work-title {
  font-variation-settings: 'SOFT' var(--soft), 'WONK' var(--wonk);
}

h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

a {
  color: inherit;
  text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

a:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

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

::selection {
  background: color-mix(in srgb, var(--accent) 25%, transparent);
}

/* Page-to-page navigation crossfades instead of flashing white. Kept short:
   the site should feel decisive, never like it's waiting on an animation. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.12s;
}

/* --- Layout: one centred column. Margin notes hang outside it, in the empty
   space on the right; below 70rem there isn't room, so they fold away. */

.site-header,
main,
.site-footer {
  max-width: calc(var(--column) + 2 * var(--pad));
  margin-inline: auto;
  padding-inline: var(--pad);
}

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding-block: 1.5rem;
}

.site-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.15rem;
  text-decoration: none;
}

.site-header nav {
  display: flex;
  gap: 1.25rem;
  font-size: 0.95rem;
}

.site-header nav a {
  text-decoration: none;
  color: var(--ink-soft);
}

.site-header nav a:hover {
  color: var(--accent);
}

main {
  padding-block: 1rem 2rem;
}

.site-footer {
  margin-top: 3rem;
  padding-block: 1.5rem 3rem;
  border-top: 1px solid var(--rule);
  font-size: 0.9rem;
  color: var(--muted);
}

.site-footer p {
  margin: 0.25rem 0;
}

/* On the blackboard, handwriting (and the doodles) is chalk: the #chalk filter
   (defined in templates/layout.js) lets it show through a grain of tiny gaps.
   Pictures in the margin stay solid. */
@media (prefers-color-scheme: dark) {
  .mn:not(:has(.print)),
  .doodle {
    filter: url(#chalk);
  }
}

/* --- Utilities */

.skip-link {
  position: absolute;
  left: 1rem;
  top: -3rem;
  padding: 0.5rem 1rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 4px;
}

.skip-link:focus {
  top: 1rem;
}

/* The SVG that only holds filter definitions takes up no space. */
.filters {
  position: absolute;
  width: 0;
  height: 0;
}

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

/* --- Margin notes. Beside the text on wide screens; behind a ✎ toggle on
   narrow ones (a checkbox does the toggling, so no JavaScript). */

.mn {
  display: block;
  float: right;
  clear: right;
  width: var(--margin);
  margin-right: calc(-1 * (var(--margin) + var(--gutter)));
  font: 400 1.9rem/1.1 var(--hand);
  letter-spacing: 0;
  color: var(--note);
  rotate: -1.5deg;
  text-wrap: pretty;
}

.mn a {
  text-decoration-color: currentColor;
}

/* A note can hang in the left margin instead, tilted the other way. */
.mn--left {
  float: left;
  clear: left;
  margin-right: 0;
  margin-left: calc(-1 * (var(--margin) + var(--gutter)));
  rotate: 1.5deg;
}

/* A picture in the margin is a print taped into the notebook: a white border,
   a hair of shadow, and the note's own slight tilt. */
.print {
  display: block;
  width: 10rem; /* small enough to stay level with its row */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  margin-bottom: 0.3rem;
  padding: 0.3rem;
  background: var(--print);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.12);
}

/* Prints hang in the left margin (templates/work.js), so they sit by the
   text, not out at the margin's far edge: the note is only as wide as the
   print. */
.mn--left:has(.print) {
  width: 10rem;
  margin-left: calc(-1 * (10rem + var(--gutter)));
}

/* Alternate the tilt, so a column of prints looks pasted in by hand. */
.work-item:nth-child(even) > .mn:has(.print) {
  rotate: -1.25deg;
}

.mn-toggle,
.mn-toggle-input {
  display: none;
}

@media (max-width: 69.99rem) {
  .mn {
    display: none;
  }

  .mn-toggle {
    display: inline;
    margin-left: 0.2em;
    /* Fonts with a plain ✎, so it doesn't turn into a colour emoji. */
    font: 400 1rem 'Segoe UI Symbol', 'Apple Symbols', 'DejaVu Sans', var(--sans);
    color: var(--note);
    cursor: pointer;
    user-select: none;
  }

  /* Visually hidden but still focusable, so keyboard users can open notes. */
  .mn-toggle-input {
    display: inline;
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
  }

  .mn-toggle-input:focus-visible + .mn,
  .work-item > .mn-toggle-input:focus-visible ~ .mn,
  .mn-toggle:has(+ .mn-toggle-input:focus-visible) {
    outline: 2px solid var(--accent);
  }

  /* (A work item's picture and note share its one toggle.) */
  .mn-toggle-input:checked + .mn,
  .work-item > .mn-toggle-input:checked ~ .mn {
    display: block;
    float: none;
    width: auto;
    margin: 0.5rem 0 0.75rem;
    rotate: none;
  }

  .work-item > .mn-toggle-input:checked ~ .mn .print,
  .mn-toggle-input:checked + .mn .print {
    max-width: 16rem;
  }
}

/* --- The board: the drawing layer and the tray of markers in the corner
   (src/board/). Without JavaScript, neither appears.

   The tray, closed, shows the tool in hand. Hovered or focused, it opens into
   a row of markers or chalks, an eraser, and the plain cursor. */

.tray {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 20;
  display: flex;
  flex-direction: row-reverse;
  align-items: flex-end;
  gap: 0.1rem;
  padding: 0 0.5rem;
  border-radius: 0.9rem;
  background: color-mix(in srgb, var(--paper) 86%, var(--ink));
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.2);
}

/* Each tool is a stick poking up out of the tray; its bottom half is hidden
   inside. The one in hand stands a little taller, like in Apple Notes. */
.tray button {
  display: block;
  width: 1.75rem;
  height: 2.5rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  overflow: hidden;
  cursor: pointer;
}

.tray svg {
  display: block;
  width: 100%;
  height: 100%;
  transition: translate 0.12s ease-out;
}

.tray button[aria-pressed='true'] svg {
  translate: 0 -0.35rem;
}

/* Bigger for fingers. */
@media (pointer: coarse) {
  .tray button {
    width: 2.75rem;
    height: 3.25rem;
  }
}

.tray button:not(.tray-current) {
  display: none;
}

/* Open, every tool is in the row already; the one in hand just stands taller.
   (Keyboard users keep the first button, since it may be the one focused.) */
/* :has(:focus-visible), not :focus-within, so a mouse click on a tool closes the tray. */
.tray:has(:focus-visible) button,
.tray.is-open button {
  display: block;
}

.tray.is-open .tray-current {
  display: none;
}

/* Only where there's a real hover: a phone keeps :hover on whatever was last
   tapped, which would hold the tray open after picking a tool. There, tapping
   the tool in hand opens it. */
@media (hover: hover) {
  .tray button:hover svg {
    translate: 0 -0.35rem;
  }

  .tray:hover button {
    display: block;
  }

  .tray:hover:not(:has(:focus-visible)) .tray-current {
    display: none;
  }
}

.tray button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .tray svg {
    transition: none;
  }
}

/* The drawing covers the whole page and scrolls with it, on top of
   everything (typed text, pictures, margin notes) except the tray. It lets the
   pointer through, so links and text underneath still work. */
.board {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  pointer-events: none;
}

/* With a marker in hand, the whole page is the board: nothing under the
   pointer reacts (no link hovers, no clicks, no text selection) except the tray.
   Touch doesn't scroll either; src/board/main.js scrolls for two fingers. */
html.is-drawing {
  cursor: var(--pen);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

html.is-drawing body > * {
  pointer-events: none;
}

html.is-drawing .tray {
  pointer-events: auto;
}

@media print {
  .tray,
  .board {
    display: none;
  }
}

/* --- Homepage */

.intro {
  padding-top: clamp(2rem, 8vh, 5rem);
}

.portrait {
  display: block;
  width: 7rem;
  height: 7rem;
  object-fit: cover;
  border-radius: 50%;
  margin-bottom: 1.25rem;
}

.intro h1 {
  margin: 0 0 0.75rem;
  font-size: clamp(2.5rem, 7vw, 3.25rem);
}

.lede {
  margin: 0 0 1rem;
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* The speaker for "Hello there" (src/say.js). It hangs in the margin left of
   the greeting, hidden until you hover over it: then it slides in from the
   left, and back out after. */
.greeting {
  position: relative;
}
.say {
  position: absolute;
  top: 0;
  right: 100%;
  bottom: 0;
  display: flex;
  align-items: center;
  padding: 0 0.3em 0 0; /* also bridges the gap, so moving onto it keeps it open */
  border: 0;
  background: none;
  font: inherit;
  color: var(--muted);
  cursor: pointer;
  opacity: 0;
  translate: -0.5em 0;
  pointer-events: none;
  transition: opacity 0.2s ease, translate 0.25s ease;
}
.say svg {
  width: 0.9em;
  height: 0.9em;
}
.greeting:hover .say,
.say:focus-visible,
.say.is-playing {
  opacity: 1;
  translate: 0 0;
  pointer-events: auto;
}
.say:hover,
.say.is-playing {
  color: var(--accent);
}
/* Touch screens: no hover, and no room in the margin, so it sits in the line. */
@media (hover: none) {
  .say {
    position: static;
    display: inline-flex;
    vertical-align: -0.1em;
    opacity: 1;
    translate: none;
    pointer-events: auto;
  }
}
@media (prefers-reduced-motion: reduce) {
  .say {
    transition: none;
  }
}

.contact {
  margin: 0;
}

.label {
  margin: 2.5rem 0 0.75rem;
  font: 500 0.75rem/1.4 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* "Now" and "Previously": small headings in the serif, one step below
   "Selected work" and "Writing". */
.subhead {
  margin: 2.25rem 0 0.5rem;
  font-size: 1.15rem;
}

.now .subhead:first-child {
  margin-top: 3rem;
}

.entries {
  list-style: none;
  margin: 0;
  padding: 0;
}

.entries li {
  margin-bottom: 0.35rem;
}

.entries strong {
  font-weight: 500;
}

.entries span {
  color: var(--ink-soft);
}

/* Links in these lists stay quiet, so the rows read as one calm list; the
   underline comes back on hover (and keyboard focus gets the usual outline). */
.entries a {
  text-decoration: none;
}

.entries a:hover {
  text-decoration: underline;
}

.work h2,
.writing h2,
.group-heading {
  margin: 3.5rem 0 0.5rem;
  font-size: 1.6rem;
}

.more {
  margin-top: 1.25rem;
  font-size: 0.95rem;
}

/* --- Doodles (templates/doodles.js): three one-stroke stars in the homepage
   margins that draw themselves once scrolled into view, and an arrow from
   each note beside a post in "Writing" to that post. They're handwriting on the board, like
   the margin notes: same colour, same chalk grain. Once someone
   picks up a marker, src/board/ turns them into strokes on its canvas (so
   they can be erased) and hides these. Only on screens wide enough to have
   margins. */

.doodle {
  display: none;
  overflow: visible; /* a stroke can overshoot its box */
  fill: none;
  stroke: var(--note);
  stroke-width: 2.75; /* about as thick as the margin notes' handwriting */
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.doodle path {
  vector-effect: non-scaling-stroke;
}

.doodle.on-board {
  visibility: hidden;
}

@media (min-width: 70rem) {
  .doodle {
    display: block;
  }

  .intro,
  .work,
  .writing {
    position: relative;
  }

  .star {
    position: absolute;
    width: 4.5rem;
    height: 4.5rem;
  }

  /* Top right, beside the name. */
  .star-1 {
    top: 2.5rem;
    right: calc(-1 * var(--margin));
    rotate: 8deg;
  }

  /* Left, beside "Selected work". */
  .star-2 {
    top: -1.25rem;
    left: calc(-1 * (var(--gutter) + 6rem));
    rotate: -12deg;
  }

  /* Right, above the note beside the posts in "Writing". */
  .star-3 {
    top: -1.5rem;
    right: calc(-1 * var(--margin) + 10rem);
    rotate: 16deg;
  }

  /* From a post's note, back across to the end of its title: it fills the
     rest of the line and the gutter, stopping just short of the note. */
  .post-list li > span:has(.post-arrow) {
    display: flex;
    align-items: flex-start;
  }

  /* One line tall, so it runs level with the title's first line and the
     note's (which line up: see .post-list .mn). */
  .post-arrow {
    display: block;
    position: relative;
    flex: 1;
    min-width: 2rem;
    height: 1lh;
    margin: 0 calc(-1 * var(--gutter) + 0.5rem) 0 0.6rem;
  }

  .post-arrow-shaft {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }

  .post-arrow-head {
    position: absolute;
    left: 0;
    top: 0;
    width: 0.875rem;
    height: 100%;
  }
}

/* Drawn in: the line is a dash as long as the whole star, slid into place.
   The first star is already in view when the page opens, so it draws itself
   just after you arrive; src/stars.js draws the others once you scroll to them. With
   reduced motion (or no JavaScript), they're simply already there. */
@media (prefers-reduced-motion: no-preference) {
  .doodle.star-1 path {
    stroke-dasharray: 1;
    animation: draw-star 0.9s 0.4s ease-in-out both;
  }

  /* Undrawn from the start, so they don't show for a moment before
     src/stars.js (a deferred module) gets going. Only with JavaScript: the
     `js` class comes from an inline script in the head. */
  .js .doodle.star-2 path,
  .js .doodle.star-3 path {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
  }
}

@keyframes draw-star {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

/* --- Lists of work and posts */

.work-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.work-item {
  border-top: 1px solid var(--rule);
}

/* On wide screens, a work item's margin notes (a picture on the left,
   handwriting on the right) are centred on the row, not hung from its top.
   They're short, so they never reach past it. */
@media (min-width: 70rem) {
  .work-item {
    position: relative;
  }

  .work-item > .mn {
    position: absolute;
    top: 50%;
    right: calc(-1 * (var(--margin) + var(--gutter)));
    margin: 0;
    translate: 0 -50%;
  }

  .work-item > .mn--left {
    right: auto;
    left: calc(-1 * (var(--margin) + var(--gutter)));
  }

  .work-item > .mn--left:has(.print) {
    left: calc(-1 * (10rem + var(--gutter)));
  }
}

/* On phones, a work item's margin note (which comes first in the markup, so
   it can float level with the title on wide screens) moves below the summary. */
@media (max-width: 69.99rem) {
  .work-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  .work-item > .work-row {
    order: 1;
    align-self: stretch;
  }

  .work-item > .mn-toggle {
    order: 2;
    margin: -0.75rem 0 0.75rem;
  }

  .work-item > .mn {
    order: 3;
  }
}

.work-row {
  display: grid;
  gap: 0.15rem;
  padding: 1rem 0;
  text-decoration: none;
}

.work-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.3rem;
  line-height: 1.2;
}

a.work-row:hover .work-title {
  color: var(--accent);
}

a.work-row:hover .work-title::after {
  content: ' →';
}

.work-meta {
  font: 0.75rem/1.5 var(--mono);
  color: var(--muted);
}

.work-summary {
  color: var(--ink-soft);
}

/* The two smaller entries share a row: notable, but a step below the three above. */
.work-list--pair {
  border-top: 1px solid var(--rule);
}

.work-list--pair .work-item {
  border-top: 0;
}

.work-list--pair .work-title {
  font-size: 1.1rem;
}

.work-list--pair .work-summary {
  font-size: 0.95rem;
}

@media (min-width: 40rem) {
  .work-list--pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 2rem;
  }
}

.post-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.post-list li {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: 0 1rem;
  padding: 0.45rem 0;
}

/* A note beside a post hangs in the margin from that row, without making the
   row taller (a float would stretch it, since a grid cell contains its floats). */
@media (min-width: 70rem) {
  .post-list li {
    position: relative;
  }

  .post-list .mn {
    position: absolute;
    top: calc(0.45rem - 0.16em); /* the row's padding, less a little: the handwriting sits low in its line, and this puts its first line's middle level with the arrow */
    right: calc(-1 * (var(--margin) + var(--gutter)));
    margin: 0;
  }

  .post-list .mn--left {
    right: auto;
    left: calc(-1 * (var(--margin) + var(--gutter)));
  }
}

/* The date sits on the same baseline as the title's first line. (Centring
   their boxes looks off: the eye centres a title on its lowercase letters,
   and an all-digit date sharing its baseline lands right in their middle.) */
.post-list time {
  align-self: first baseline;
  font: 0.8rem/1.6 var(--mono);
  color: var(--muted);
}

.post-list li > :nth-child(2) {
  align-self: first baseline;
}

.post-list--long li {
  padding: 0.75rem 0;
}

.post-list--long p {
  grid-column: 2;
  margin: 0.2rem 0 0;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

@media (max-width: 30rem) {
  .post-list li {
    grid-template-columns: 1fr;
  }

  .post-list--long p {
    grid-column: 1;
  }
}

.listing h1 {
  margin: 1rem 0 0.5rem;
  font-size: 2.25rem;
}

.listing .lede {
  margin-bottom: 1.5rem;
}

.archive {
  list-style: none;
  margin: 0;
  padding: 0;
}

.archive li {
  padding: 0.4rem 0;
}

.quiet {
  color: var(--muted);
}

/* --- Project pages */

.project-asset {
  margin: 1rem 0 0;
}

.project-asset img,
.project-asset video {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  background: var(--rule);
}

/* Tall media (phone recordings, square demos) shouldn't take over the screen. */
.project-asset video {
  width: auto;
  max-width: 100%;
  max-height: min(32rem, 70vh);
  margin-inline: auto;
}

.project-asset figcaption {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--muted);
}

.project-header h1 {
  margin: 0 0 0.5rem;
  font-size: 2.25rem;
}

.project-header .label {
  margin-top: 2rem;
  margin-bottom: 0.5rem;
}

.summary {
  margin: 0;
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.facts {
  display: grid;
  gap: 0.5rem;
  margin: 1.5rem 0 0;
  padding: 1rem 0;
  border-block: 1px solid var(--rule);
}

.facts div {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 1rem;
}

/* Each label sits on the same baseline as the first line of its value, like
   the dates beside post titles. */
.facts dt,
.facts dd {
  align-self: first baseline;
}

.facts dt {
  font: 500 0.75rem/1.6 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.facts dd {
  margin: 0;
}

.project-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  list-style: none;
  margin: 2rem 0 0;
  padding: 1rem 0 0;
  border-top: 1px solid var(--rule);
}

/* --- Long-form writing */

.post-header h1 {
  margin: 0.25rem 0 0;
  font-size: clamp(2rem, 5vw, 2.5rem);
}

.post-header .label {
  margin-top: 2rem;
}

.prose {
  margin-top: 1.5rem;
  text-wrap: pretty;
}

.prose h2 {
  margin: 2.5rem 0 0.75rem;
  font-size: 1.5rem;
}

.prose h3 {
  margin: 2rem 0 0.5rem;
  font-size: 1.2rem;
}

.prose img {
  display: block;
  max-width: 100%;
  width: auto;
  height: auto;
  max-height: 34rem;
  margin: 1.5rem auto;
}

.prose blockquote {
  margin: 1.5rem 0;
  padding-left: 1rem;
  border-left: 2px solid var(--rule);
  color: var(--ink-soft);
}

.prose code {
  font: 0.9em var(--mono);
  padding: 0.1em 0.3em;
  border-radius: 4px;
  background: var(--rule);
}

.prose pre {
  overflow-x: auto;
  padding: 1rem;
  border-radius: 6px;
  background: var(--rule);
}

.prose pre code {
  padding: 0;
  background: none;
}

.prose .katex-display {
  overflow-x: auto;
  overflow-y: hidden;
  padding-block: 0.25rem;
}

/* Footnotes, generated by marked-footnote. */
.prose sup a {
  text-decoration: none;
  color: var(--accent);
}

.footnotes {
  margin-top: 3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  font-size: 0.9rem;
  color: var(--ink-soft);
}
