@import url("fonts.css");

/* ---------------------------------------------------------------
   Tokens
   --------------------------------------------------------------- */

/* Palette sampled from assets/img/transcription.png — bone paper,
   indigo ink, slate-teal, warm sand. No pure black anywhere. */
:root {
  --paper:      #f5f0e8;
  --paper-2:    #ece5d9;
  --paper-3:    #e2d9c9;
  --ink:        #253d50;
  --ink-soft:   #4d6374;
  --ink-faint:  #8f9a9d;
  --rule:       #d8d0c1;
  --rule-soft:  #e6ded0;
  --accent:     #40808f;
  --accent-lift:#2f6675;
  --plum:       #7d6394;
  --sand:       #c2a882;

  --serif: "Newsreader", "EB Garamond", "Iowan Old Style", Charter, Georgia, serif;
  --mono:  "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;

  --t-quote: clamp(1.55rem, 3vw, 3rem);
  --t-h1:    clamp(1.9rem, 3.2vw, 3rem);
  --t-h2:    clamp(1.15rem, 0.6vw + 1rem, 1.4rem);
  --t-entry: clamp(1.25rem, 1.3vw + 0.9rem, 1.75rem);
  --t-body:  clamp(1rem, 0.2vw + 0.95rem, 1.09rem);
  --t-label: 0.72rem;

  /* The navigation is set noticeably larger than the small-caps labels it
     used to share a size with — it is the one control on every page. */
  --t-nav:   clamp(0.98rem, 0.35vw + 0.9rem, 1.12rem);
  --t-brand: clamp(1rem, 0.4vw + 0.92rem, 1.18rem);

  /* Minimum comfortable touch target. */
  --tap: 2.75rem;

  --wide:    78rem;   /* page frame */
  --measure: 36rem;   /* reading width for running text */
  --edge:    clamp(1.35rem, 5vw, 4rem);
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:     #141c24;
    --paper-2:   #1c2731;
    --paper-3:   #24313d;
    --ink:       #e6e0d4;
    --ink-soft:  #a9b6bc;
    --ink-faint: #74848c;
    --rule:      #2d3b47;
    --rule-soft: #212d37;
    --accent:    #6fb3bf;
    --accent-lift:#93cdd7;
    --plum:      #a68cbd;
    --sand:      #cfb188;
  }
}
:root[data-theme="dark"] {
  --paper:     #141c24;
  --paper-2:   #1c2731;
  --paper-3:   #24313d;
  --ink:       #e6e0d4;
  --ink-soft:  #a9b6bc;
  --ink-faint: #74848c;
  --rule:      #2d3b47;
  --rule-soft: #212d37;
  --accent:    #6fb3bf;
  --accent-lift:#93cdd7;
  --plum:      #a68cbd;
  --sand:      #cfb188;
}
:root[data-theme="light"] {
  --paper:      #f5f0e8;
  --paper-2:    #ece5d9;
  --paper-3:    #e2d9c9;
  --ink:        #253d50;
  --ink-soft:   #4d6374;
  --ink-faint:  #8f9a9d;
  --rule:       #d8d0c1;
  --rule-soft:  #e6ded0;
  --accent:     #40808f;
  --accent-lift:#2f6675;
  --plum:       #7d6394;
  --sand:       #c2a882;
}

/* ---------------------------------------------------------------
   Base
   --------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t-body);
  font-weight: 390;
  line-height: 1.7;
  font-optical-sizing: auto;
  font-variant-ligatures: common-ligatures contextual;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  transition: background-color .4s ease, color .4s ease;
}

/* Watercolour atmosphere: soft asymmetric washes in teal, sand and plum,
   fixed behind the content so the page feels painted rather than printed. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(60rem 40rem at 12% -6%,
      color-mix(in srgb, var(--sand) 34%, transparent) 0%, transparent 62%),
    radial-gradient(52rem 38rem at 92% 6%,
      color-mix(in srgb, var(--accent) 22%, transparent) 0%, transparent 60%),
    radial-gradient(46rem 36rem at 78% 52%,
      color-mix(in srgb, var(--plum) 15%, transparent) 0%, transparent 58%),
    radial-gradient(50rem 40rem at 8% 78%,
      color-mix(in srgb, var(--accent) 17%, transparent) 0%, transparent 60%);
  opacity: .55;
}

/* fine dotted grid, the way the reference uses halftone fields */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .5;
  background-image: radial-gradient(
    color-mix(in srgb, var(--ink) 22%, transparent) 0.6px, transparent 0.6px);
  background-size: 22px 22px;
  -webkit-mask-image:
    radial-gradient(38rem 30rem at 96% 14%, #000 0%, transparent 68%),
    radial-gradient(34rem 26rem at 2% 62%, #000 0%, transparent 66%);
  mask-image:
    radial-gradient(38rem 30rem at 96% 14%, #000 0%, transparent 68%),
    radial-gradient(34rem 26rem at 2% 62%, #000 0%, transparent 66%);
}

@media (prefers-color-scheme: dark) { body::before { opacity: .4; } }
:root[data-theme="dark"] body::before { opacity: .4; }

img { max-width: 100%; height: auto; display: block; }
::selection { background: var(--accent); color: var(--paper); }

.page {
  width: 100%;
  max-width: var(--wide);
  margin-inline: auto;
  padding-inline: var(--edge);
}

h1, h2, h3 {
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}
p { margin: 0 0 1.15em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }
a { color: inherit; text-decoration: none; }

a.link, .prose a {
  color: var(--accent);
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 100% 1px;
  background-repeat: no-repeat;
  background-position: 0 94%;
  transition: background-size .3s ease, color .3s ease;
}
a.link:hover, .prose a:hover { color: var(--accent-lift); background-size: 100% 2px; }

.label {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .17em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-feature-settings: "tnum" 1;
}

/* ---------------------------------------------------------------
   Masthead
   --------------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid var(--rule);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
@supports not (backdrop-filter: blur(4px)) {
  .masthead { background: var(--paper); }
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding-block: .85rem;
}

.masthead__brand {
  display: flex;
  flex-direction: column;
  gap: .12rem;
  min-width: 0;
}
.masthead__title {
  font-family: var(--mono);
  font-size: var(--t-brand);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  line-height: 1.1;
}
.masthead__by {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  line-height: 1.2;
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2.4vw, 2.1rem);
}
.nav a, .theme-toggle {
  font-family: var(--mono);
  font-size: var(--t-nav);
  letter-spacing: .06em;
  text-transform: none;
  color: var(--ink-soft);
  transition: color .25s ease;
}
.nav a {
  position: relative;
  padding-block: .35rem;
}
/* underline grows from the left on hover and stays put on the current page */
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .3s cubic-bezier(.2,.7,.3,1);
}
.nav a:hover { color: var(--ink); }
.nav a:hover::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: var(--ink); }
.nav a[aria-current="page"]::after { transform: scaleX(1); background: var(--ink); }

.theme-toggle {
  background: none;
  border: 1px solid var(--rule);
  padding: .34rem .8rem;
  cursor: pointer;
  font-size: calc(var(--t-nav) * .82);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color .25s ease, border-color .25s ease;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink-faint); }

/* ---- the mobile control -------------------------------------- */

.nav-toggle {
  display: none;
  align-items: center;
  gap: .6rem;
  min-height: var(--tap);
  padding: .4rem .2rem .4rem .6rem;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--t-nav);
  letter-spacing: .1em;
  text-transform: uppercase;
}
.nav-toggle[hidden] { display: none; }
.nav-toggle__bars {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 1.35rem;
  height: .8rem;
}
.nav-toggle__bars i {
  display: block;
  height: 2px;
  background: currentColor;
  transition: transform .3s ease, opacity .2s ease;
}
/* the three bars fold into a cross while the panel is open */
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(1) {
  transform: translateY(.39rem) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(3) {
  transform: translateY(-.39rem) rotate(-45deg);
}

@media (max-width: 46rem) {
  /* The button is revealed by site.js; without it the links stay visible. */
  .nav-toggle:not([hidden]) { display: inline-flex; }

  .js-nav .nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: .5rem var(--edge) 1.4rem;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    box-shadow: 0 18px 30px -22px rgba(0, 0, 0, .5);

    /* collapsed by default; `visibility` keeps the links out of the tab
       order while closed, which `opacity` alone would not do */
    visibility: hidden;
    opacity: 0;
    transform: translateY(-.5rem);
    transition: opacity .25s ease, transform .25s ease, visibility .25s;
  }
  .js-nav .nav[data-open] {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
  }

  .masthead__inner { position: relative; }

  .js-nav .nav a {
    padding-block: .95rem;
    font-size: 1.18rem;
    border-bottom: 1px solid var(--rule-soft);
  }
  .js-nav .nav a::after { display: none; }
  .js-nav .nav a[aria-current="page"] {
    color: var(--accent);
  }
  .js-nav .theme-toggle {
    margin-top: 1.1rem;
    align-self: flex-start;
    min-height: var(--tap);
    padding-inline: 1.1rem;
  }
}

/* ---------------------------------------------------------------
   Home — opening, full-bleed plate, premise, topics
   --------------------------------------------------------------- */

/* The artwork IS the hero — the quote sits inside it, not stacked above a
   cropped strip. Height follows the art's 3:2 ratio, capped so it stays
   a screenful rather than a poster. */
.hero {
  position: relative;
  display: grid;
  align-items: center;
  min-height: min(82vh, 40rem);
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
  overflow: hidden;
}

.hero__art { position: absolute; inset: 0; z-index: 0; }
.hero__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* bias right so the double helix and the RNA strand stay in frame */
  object-position: 62% 50%;
}

/* Scrim: opaque enough on the left for text, clearing by mid-frame so the
   helix reads. Second layer feathers the base into the page. */
.hero__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(100deg,
      var(--paper) 0%,
      color-mix(in srgb, var(--paper) 88%, transparent) 26%,
      color-mix(in srgb, var(--paper) 40%, transparent) 48%,
      transparent 66%),
    linear-gradient(to bottom,
      color-mix(in srgb, var(--paper) 55%, transparent) 0%,
      transparent 18%,
      transparent 74%,
      var(--paper) 100%);
}

/* In dark mode the type is cream, so the picture has to be held down or the
   pale washes in the upper right come up under the end of the quote. */
@media (prefers-color-scheme: dark) {
  .hero__art img { filter: brightness(.58) saturate(.85); }
}
:root[data-theme="dark"] .hero__art img { filter: brightness(.58) saturate(.85); }
:root[data-theme="light"] .hero__art img { filter: none; }

/* Single column: everything stays in the scrimmed left zone where it is
   legible. A right-hand rail would sit on the dark washes. */
.hero__inner {
  position: relative;
  z-index: 1;
  padding-block: clamp(3rem, 7vw, 5rem);
}

@media (max-width: 62rem) {
  .hero__art img { object-position: 70% 50%; }
  .hero__art::after {
    background:
      linear-gradient(100deg,
        var(--paper) 0%,
        color-mix(in srgb, var(--paper) 92%, transparent) 40%,
        color-mix(in srgb, var(--paper) 55%, transparent) 70%,
        color-mix(in srgb, var(--paper) 25%, transparent) 100%),
      linear-gradient(to bottom, transparent 70%, var(--paper) 100%);
  }
}
@media (max-width: 52rem) {
  .hero { min-height: min(74vh, 34rem); }
  .hero__inner { grid-template-columns: 1fr; align-items: start; gap: 2rem; }
}

/* On a phone the text sits over the middle of the picture, not beside it,
   so the wash has to cover the whole frame rather than fade out to the
   right. The art still reads underneath; the words stay legible. */
@media (max-width: 46rem) {
  .hero {
    min-height: auto;
    padding-block: 1rem 0;
  }
  .hero__art img { object-position: 60% 45%; }
  .hero__art::after {
    background:
      linear-gradient(to bottom,
        color-mix(in srgb, var(--paper) 62%, transparent) 0%,
        color-mix(in srgb, var(--paper) 80%, transparent) 45%,
        color-mix(in srgb, var(--paper) 94%, transparent) 78%,
        var(--paper) 100%);
  }
  .hero__inner { padding-block: 3.5rem 2.5rem; }
}

.hero__quote { max-width: min(100%, 42rem); }
.hero__quote blockquote {
  margin: 0;
  font-size: var(--t-quote);
  /* was 1.13 with a -0.028em track: at quote size that set the lines almost
     touching. Opened up, and the weight raised off 300, the sentence reads
     in one pass instead of being decoded. */
  line-height: 1.28;
  letter-spacing: -0.012em;
  font-style: italic;
  font-weight: 380;
  color: var(--ink);
  text-wrap: balance;
  /* Outlined so the words hold up wherever the artwork happens to be busy.
     Drawn as a ring of hard shadows plus one soft glow behind, rather than
     with -webkit-text-stroke: a stroke is centred on the glyph edge and eats
     into the letterform, which wrecks an italic serif at this size. The ring
     is paper-coloured, so it is white-ish on the light theme and dark on the
     dark one — in both cases it separates the type from the picture. */
  text-shadow: var(--halo);
}

/* The ring is listed first so it paints on top of the soft glow behind it. */
.hero {
  --halo-c: color-mix(in srgb, var(--paper) 88%, transparent);
  --halo:
     1px  1px 0 var(--halo-c), -1px  1px 0 var(--halo-c),
     1px -1px 0 var(--halo-c), -1px -1px 0 var(--halo-c),
     2px  0   0 var(--halo-c), -2px  0   0 var(--halo-c),
     0    2px 0 var(--halo-c),  0   -2px 0 var(--halo-c),
     0 0 .5em color-mix(in srgb, var(--paper) 75%, transparent);
}

/* the attribution and the rail sit on the same picture, so they get it too */
.hero__quote cite,
.hero__meta span { text-shadow: var(--halo); }

/* Quotation marks, set as hanging punctuation: oversized, in the accent,
   and pulled out of the measure so the first word still aligns to the
   left edge of everything below it. */
.hero__quote .mark {
  font-family: var(--serif);
  font-style: normal;
  font-weight: 500;
  font-size: 1.15em;
  line-height: 0;
  color: color-mix(in srgb, var(--accent) 85%, var(--ink));
  vertical-align: -.08em;
}
.hero__quote .mark--open {
  margin-left: -.42em;   /* hang into the gutter */
  margin-right: .04em;
}
.hero__quote .mark--close { margin-left: .04em; }

@media (max-width: 46rem) {
  /* no gutter to hang into on a phone — let it sit inline */
  .hero__quote .mark--open { margin-left: 0; }
}
.hero__quote cite {
  display: block;
  margin-top: clamp(1.2rem, 2.5vw, 1.8rem);
  font-family: var(--mono);
  font-size: var(--t-label);
  font-style: normal;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* horizontal rail beneath the quote, dot-separated */
.hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem 1.5rem;
  max-width: min(100%, 42rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: 1rem;
  border-top: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
}
.hero__meta span {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-soft);
  position: relative;
}
.hero__meta span:first-child { color: var(--ink); }
.hero__meta span + span::before {
  content: "·";
  position: absolute;
  left: -.85rem;
  color: var(--ink-faint);
}

/* ---------------------------------------------------------------
   Page heads — one masthead pattern shared by every subpage
   --------------------------------------------------------------- */

.page-head {
  padding-block: clamp(2.2rem, 5vw, 4rem) clamp(1.4rem, 3vw, 2.2rem);
  border-bottom: 1px solid var(--rule);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.page-head h1 {
  font-size: var(--t-h1);
  font-weight: 350;
  letter-spacing: -0.024em;
  max-width: 20ch;
}
.page-head .label { margin: 0 0 .7rem; }
.page-head__lede {
  margin: 1.1rem 0 0;
  max-width: 42ch;
  font-size: clamp(1.02rem, 0.4vw + 0.95rem, 1.18rem);
  line-height: 1.6;
  color: var(--ink-soft);
}
.page-head__meta {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.3rem;
  margin-top: 1.3rem;
}
.back { transition: color .25s ease; }
.back:hover { color: var(--accent); }

/* Variant carrying an illustration alongside the title.
   `align-items: start` is what keeps Writing, About and Contact agreeing:
   the title sits at the top of its column on all three, so the three
   headings land on the same baseline however tall the picture is or how
   much lede text sits underneath. Centring the grid would push each title
   down by a different amount. */
.page-head--art {
  display: grid;
  /* 12rem, not 15: at 3:4 a wider plate stands a long way taller than the
     two or three lines of text beside it, leaving the heading floating over
     a pool of empty paper. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 12rem);
  gap: clamp(1.5rem, 5vw, 3.5rem);
  align-items: start;
}
.page-head__art {
  overflow: hidden;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}
.page-head__art img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}


@media (max-width: 52rem) {
  /* the plate drops below the title and lies down, so it never eats
     half the screen before a reader reaches a single word */
  .page-head--art { grid-template-columns: 1fr; gap: 1.6rem; }
  .page-head__art { order: 2; }
  .page-head__art img { aspect-ratio: 16 / 9; object-position: center 40%; }
}

/* the topic rail on the writing index */
.tag-rail {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem .55rem;
  margin-bottom: clamp(1.8rem, 4vw, 2.6rem);
}
.tag-rail span {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border: 1px solid var(--rule);
  padding: .34rem .7rem;
}

/* ---------------------------------------------------------------
   Triptych of plates on the home page
   --------------------------------------------------------------- */

.plates {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2.5vw, 1.8rem);
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
}
.plate { margin: 0; }
.plate__frame {
  overflow: hidden;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}
.plate__frame img {
  width: 100%;
  aspect-ratio: 1 / 2;
  object-fit: cover;
  transition: transform .6s cubic-bezier(.2,.7,.3,1);
}
.plate:hover .plate__frame img { transform: scale(1.03); }
.plate figcaption { margin-top: .8rem; }
.plate .label { display: block; margin-bottom: .3rem; color: var(--ink-soft); }
.plate__note {
  display: block;
  font-size: .93rem;
  line-height: 1.55;
  color: var(--ink-faint);
}

@media (max-width: 52rem) {
  /* three tall plates side by side become slivers — go two up, then one */
  .plates { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .plate__frame img { aspect-ratio: 3 / 4; }
}
@media (max-width: 34rem) {
  .plates { grid-template-columns: 1fr; gap: 1.8rem; }
  .plate__frame img { aspect-ratio: 16 / 10; object-position: center 40%; }
}

/* premise */
.intro { padding-bottom: clamp(3rem, 6vw, 4.5rem); }
/* the closing paragraphs match the premise above them */
.prose.intro__tail {
  margin-top: clamp(2rem, 4vw, 2.8rem);
  max-width: none;
  line-height: 1.78;
}

/* The premise runs the full width of the page and the topic list sits
   directly beneath it, sharing the same left edge — the paragraph ends on
   "topics on:" and the list is what it introduces, so nothing may come
   between them. Not split into snake columns for the same reason: that
   would send you down one column and back up another before reaching the
   list the colon points at.

   The line is long at this width. It is held together by the raised
   line-height: the longer the measure, the more leading a reader needs in
   order to find the start of the next line.

   Both selectors are doubled up (`.prose.intro__text`) so they outrank the
   plain `.prose { max-width: var(--measure) }` further down the file, which
   would otherwise win on source order and pen the text back in. */
.prose.intro__text {
  max-width: none;
  line-height: 1.78;
  margin-bottom: clamp(2rem, 4vw, 2.8rem);
}

/* the topic list, set as a numbered two-column index */
.topics {
  list-style: none;
  /* no top margin: it sits beside the premise and the two align at the top */
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: 0 clamp(1.5rem, 4vw, 3.5rem);
  border-top: 1px solid var(--rule);
}
.topics li {
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  gap: .5rem;
  align-items: baseline;
  padding-block: .72rem;
  border-bottom: 1px solid var(--rule);
}
.topics .n {
  font-family: var(--mono);
  font-size: var(--t-label);
  color: var(--ink-faint);
  font-feature-settings: "tnum" 1;
}

/* "Let's begin!" — the way into the writing */
.begin {
  display: inline-flex;
  align-items: baseline;
  gap: .7rem;
  margin-top: 2.4rem;
  font-size: clamp(1.35rem, 2vw, 1.85rem);
  font-style: italic;
  font-weight: 340;
  color: var(--ink);
  transition: color .3s ease;
}
.begin .arrow {
  font-family: var(--mono);
  font-style: normal;
  display: inline-block;
  transition: transform .35s cubic-bezier(.2,.7,.3,1);
}
.begin:hover { color: var(--accent); }
.begin:hover .arrow { transform: translateX(6px); }

/* latest notes strip */
.latest {
  padding-block: clamp(2rem, 4vw, 3rem) clamp(3rem, 6vw, 4.5rem);
  border-top: 1px solid var(--rule);
}
.latest__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1.5rem;
  margin-bottom: 1.4rem;
}
.latest__head h2 { font-weight: 400; }
.latest__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 1px;
  background: var(--rule);
  border-block: 1px solid var(--rule);
}
.latest__item {
  background: var(--paper);
  padding: 1.4rem 1.3rem 1.6rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  transition: background-color .35s ease;
}
.latest__item:hover { background: var(--paper-2); }
.latest__year {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .15em;
  color: var(--ink-faint);
}
.latest__title {
  font-size: 1.15rem;
  line-height: 1.25;
  transition: color .3s ease;
}
.latest__item:hover .latest__title { color: var(--accent); }

/* ---------------------------------------------------------------
   Landing page — a title page, meant to fill the screen
   --------------------------------------------------------------- */

.landing {
  min-height: calc(100svh - 4rem);
  display: grid;
  grid-template-rows: 1fr auto;
  gap: clamp(2.5rem, 6vw, 5rem);
  padding-block: clamp(2.5rem, 7vw, 5.5rem) clamp(1.8rem, 4vw, 3rem);
}

/* max-width in rem, not ch — ch here resolves against this element's own
   (body-sized) font, not the large font on the blockquote inside it. */
.landing__quote {
  align-self: center;
  max-width: min(100%, 44rem);
  margin-inline-start: clamp(0rem, 5vw, 5rem);
}
.landing__quote blockquote {
  margin: 0;
  font-size: var(--t-quote);
  line-height: 1.14;
  letter-spacing: -0.028em;
  font-style: italic;
  font-weight: 300;
  text-wrap: balance;
}
.landing__quote cite {
  display: block;
  margin-top: clamp(1.4rem, 3vw, 2.2rem);
  font-family: var(--mono);
  font-size: var(--t-label);
  font-style: normal;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* foot of the title page: identity rail + premise + the way in */
.landing__foot {
  display: grid;
  grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: start;
  padding-top: clamp(1.6rem, 3vw, 2.4rem);
  border-top: 1px solid var(--rule);
}
@media (max-width: 46rem) {
  .landing__foot { grid-template-columns: 1fr; gap: 1.8rem; }
}

.landing__meta {
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.landing__meta span {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.landing__meta span:first-child { color: var(--ink); }

.landing__premise { max-width: 32rem; }
.landing__premise p {
  font-size: clamp(1.02rem, 0.4vw + 0.95rem, 1.16rem);
  line-height: 1.62;
  color: var(--ink-soft);
}

.landing__enter {
  display: inline-flex;
  align-items: baseline;
  gap: .6rem;
  margin-top: 1.4rem;
  font-size: 1.12rem;
  color: var(--ink);
}
.landing__enter span.arrow {
  font-family: var(--mono);
  transition: transform .35s cubic-bezier(.2,.7,.3,1);
  display: inline-block;
}
.landing__enter:hover { color: var(--accent); }
.landing__enter:hover span.arrow { transform: translateX(5px); }

/* ---------------------------------------------------------------
   Writing index — year and tags in a rail, content alongside
   --------------------------------------------------------------- */

.index { list-style: none; margin: 0; padding: 0; }
/* no top border on the first row — the section heading above already
   supplies a rule, and two of them read as an empty table row */
.index li { border-bottom: 1px solid var(--rule); }

.index a {
  display: grid;
  grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr) minmax(0, 11rem);
  gap: clamp(1rem, 3vw, 2.4rem);
  padding-block: clamp(1.5rem, 3vw, 2.2rem);
  align-items: start;
  position: relative;
  isolation: isolate;
}

/* hover wash bleeds into the page gutter */
.index a::before {
  content: "";
  position: absolute;
  inset: 0 calc(var(--edge) * -0.45);
  background: var(--paper-2);
  opacity: 0;
  z-index: -1;
  transition: opacity .4s ease;
}
.index a:hover::before { opacity: 1; }

.index__rail {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding-top: .35rem;
}
.index__rail span {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-feature-settings: "tnum" 1;
}
.index__rail span.year { color: var(--ink-soft); }

.index__title {
  display: block;
  font-size: var(--t-entry);
  font-weight: 380;
  line-height: 1.16;
  letter-spacing: -0.018em;
  transition: color .3s ease;
}
.index a:hover .index__title { color: var(--accent); }

.index__blurb {
  margin: .6rem 0 0;
  font-size: .97em;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 42rem;
}

/* Narrow: the year/tag rail lies down above the entry and the picture keeps
   its place as a small thumbnail. Dropping the image entirely, as this did
   before, left a wall of undifferentiated text on exactly the screens where
   an entry is hardest to scan. */
@media (max-width: 58rem) {
  .index a {
    grid-template-columns: minmax(0, 1fr) minmax(0, 7.5rem);
    grid-template-areas:
      "rail  thumb"
      "body  thumb";
    gap: .6rem 1.2rem;
    align-content: start;
  }
  .index__rail {
    grid-area: rail;
    flex-direction: row;
    flex-wrap: wrap;
    gap: .3rem .9rem;
    padding-top: 0;
  }
  .index__body { grid-area: body; }
  .index .slot {
    grid-area: thumb;
    align-self: start;
    aspect-ratio: 1 / 1;
  }
}
@media (max-width: 30rem) {
  .index a { grid-template-columns: minmax(0, 1fr) minmax(0, 5.25rem); gap: .5rem .9rem; }
  .index__blurb { font-size: .92em; }
}

/* ---------------------------------------------------------------
   Publications — a compact citation list. Title first, then authors,
   then the journal line ending in the year, the way a citation reads.
   No date rail: sixteen entries in a column of years is a table of
   numbers with the papers pushed off to one side.
   --------------------------------------------------------------- */

.pub__legend {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1.6rem;
  margin: 1.6rem 0 .8rem;
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* No reading-width cap here. A citation is scanned, not read in sequence,
   and the full column keeps long author lists to two lines instead of
   three, which is what actually makes an entry hard to take in. */
.pubs { list-style: none; margin: 0; padding: 0; }

/* The three lines of a citation are set almost solid so the entry reads as
   one block; the space that separates entries is carried by the padding
   here, not by the gaps inside them. */
.pub {
  padding-block: clamp(2rem, 3.4vw, 2.9rem);
  border-top: 1px solid var(--rule);
}

.pub__title {
  margin: 0;
  font-size: 1.03em;
  line-height: 1.25;
  letter-spacing: -0.008em;
  text-wrap: pretty;
}
.pub__link { text-decoration: none; border-bottom: 1px solid var(--rule); }
.pub__link:hover { color: var(--accent); border-bottom-color: currentColor; }

/* Preprint / Chapter, set beside the title rather than above it */
.pub__note {
  margin-left: .5rem;
  padding: .1rem .4rem;
  border: 1px solid var(--rule);
  border-radius: 2px;
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  vertical-align: .18em;
  white-space: nowrap;
}

.pub__authors {
  margin: 0;
  font-size: .88em;
  line-height: 1.35;
  color: var(--ink-faint);
}
/* the author's own name, so a reader can find their place in a list of ten */
.pub__authors strong { color: var(--ink-soft); font-weight: 560; }

.pub__where {
  margin: 0;
  font-size: .88em;
  line-height: 1.35;
  color: var(--ink-soft);
}
.pub__year { font-feature-settings: "tnum" 1; color: var(--ink-faint); }

/* ---------------------------------------------------------------
   Image slots — a real photo, or a visible marker of where one goes
   --------------------------------------------------------------- */

.slot {
  position: relative;
  overflow: hidden;
  background: var(--paper-2);
}
.slot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.slot--hero     { aspect-ratio: 16 / 9; }
.slot--wide     { aspect-ratio: 16 / 9; }
.slot--thumb    { aspect-ratio: 4 / 3; }
.slot--portrait { aspect-ratio: 3 / 4; }
.slot--tall     { aspect-ratio: 3 / 4; }
@media (max-width: 34rem) {
  /* a tall plate at phone width is nearly a full screen on its own */
  .slot--tall { aspect-ratio: 16 / 10; }
  .slot--tall img { object-position: center 40%; }
}

/* empty slot: hairline frame with a quiet label, never a loud "no image" */
.slot--empty {
  display: grid;
  place-items: center;
  border: 1px dashed var(--rule);
  background: transparent;
}
.slot--empty::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    -45deg, transparent 0 9px, var(--rule-soft) 9px 10px);
  opacity: .5;
}
.slot--empty span {
  position: relative;
  z-index: 1;
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--paper);
  padding: .3rem .6rem;
}

.slot-caption {
  margin: .75rem 0 0;
  font-family: var(--mono);
  font-size: var(--t-label);
  line-height: 1.7;
  color: var(--ink-faint);
}


/* ---------------------------------------------------------------
   About — portrait anchored in its own column beside the text
   --------------------------------------------------------------- */

.about {
  display: grid;
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
  gap: clamp(1.8rem, 5vw, 4rem);
  align-items: start;
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
/* The biography is the page, so it runs wider than the default measure —
   but not the full column. Past roughly 46rem a line of this size carries
   more than about 90 characters and the eye loses the return sweep. */
.about__body .prose { max-width: 46rem; }
/* sticky under the sticky masthead, hence the extra offset */
.about__side { position: sticky; top: 5.5rem; }

@media (max-width: 46rem) {
  .about { grid-template-columns: 1fr; gap: 2rem; }
  /* the print sits alongside its caption rather than stacking, which keeps
     the whole introduction inside the first screen */
  .about__side { position: static; }
  .about__portrait {
    display: grid;
    grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
    gap: 1.2rem;
    align-items: center;
  }
  .about__portrait figcaption {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }
}
@media (max-width: 24rem) {
  .about__portrait { grid-template-columns: 1fr; gap: .9rem; }
  .about__side { max-width: 12rem; }
}

.about__portrait { margin: 0; }

/* The photograph is presented as a mounted print: a wide paper mat, a
   hairline rule, a soft drop. The image is never asked to fill a fixed
   ratio, so a small source file is shown at a size it can actually carry
   instead of being stretched until it goes soft. Replace the file with a
   larger one and the frame grows with it, up to the column width. */
/* No mat, no border, no drop shadow — the photograph sits on the paper as
   itself. The width is capped close to the file's own 150px so it is never
   enlarged past the point where it goes soft. That was the actual problem:
   the picture looked poor because it was being scaled up, and putting a
   frame around it only drew attention to the box. Replace the file with a
   larger one and raise this cap. */
.portrait-frame { max-width: 12rem; }
.portrait-frame img {
  width: 100%;
  height: auto;
  display: block;
  /* Toned rather than left at full colour: the greens and skin tones in the
     original fight the bone-and-indigo palette everywhere else. Pulled most
     of the way to grey, then warmed with a little sepia so it reads as an
     old print on the same paper instead of a snapshot dropped onto it. */
  filter: grayscale(1) sepia(.42) saturate(1.3) contrast(.96) brightness(1.04);
}
/* On dark paper the same picture needs holding down a little, or it glows. */
@media (prefers-color-scheme: dark) {
  .portrait-frame img {
    filter: grayscale(1) sepia(.38) saturate(1.2) contrast(.94) brightness(.9);
  }
}
:root[data-theme="dark"] .portrait-frame img {
  filter: grayscale(1) sepia(.38) saturate(1.2) contrast(.94) brightness(.9);
}
:root[data-theme="light"] .portrait-frame img {
  filter: grayscale(1) sepia(.42) saturate(1.3) contrast(.96) brightness(1.04);
}

.about__portrait figcaption {
  margin-top: .9rem;
  padding-top: .7rem;
  border-top: 1px solid var(--rule);
}
.about__name {
  display: block;
  font-family: var(--mono);
  font-size: .82rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink);
}
.about__roles {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  margin-top: .45rem;
}
.about__roles span {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .1em;
  color: var(--ink-faint);
}

.about__gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: clamp(1.2rem, 3vw, 2rem);
  padding-block: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--rule);
}
.about__gal { margin: 0; }
.about__gal figcaption {
  margin-top: .7rem;
  font-family: var(--mono);
  font-size: var(--t-label);
  line-height: 1.7;
  color: var(--ink-faint);
}

/* ---------------------------------------------------------------
   Contact — form and location side by side
   --------------------------------------------------------------- */

.contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
@media (max-width: 52rem) {
  .contact { grid-template-columns: 1fr; }
}
.contact .map-wrap { margin-top: 0; padding-top: 0; border-top: 0; }
.contact .form { max-width: none; }

/* ---------------------------------------------------------------
   Article + prose
   --------------------------------------------------------------- */

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

/* ---------------------------------------------------------------
   Article body — rail beside the text rather than a narrow strip
   --------------------------------------------------------------- */

.post {
  display: grid;
  grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
  gap: clamp(1.8rem, 5vw, 3.5rem);
  align-items: start;
}
/* A grid child defaults to min-width:auto, which lets a wide code block push
   its own track — and the page — sideways instead of scrolling inside its
   own box. This is what keeps `pre { overflow-x: auto }` actually working. */
.post > * { min-width: 0; }

/* The rail holds the date, the tags and the artwork, so the width the page
   used to leave blank now carries the things you would otherwise have to
   scroll back to the top to find. Sticky, offset to clear the masthead. */
.post-rail {
  position: sticky;
  top: 5.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}
.post-rail__meta {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--rule);
}
/* No forced ratio: post artwork ranges from 1:2 to 3:2, and cropping them all
   to one shape would slice the wide ones in half. In a rail this narrow a
   wide picture is simply short, which is fine. */
.post-rail__art {
  overflow: hidden;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}
.post-rail__art img { width: 100%; height: auto; }
.post-rail .slot-caption { margin-top: 0; }

/* the text may now run a little wider, since it is no longer alone */
.post-body { min-width: 0; max-width: 40rem; }
.post-body .article { max-width: none; }

@media (max-width: 58rem) {
  /* rail lies down above the text: meta first, artwork as a band */
  .post { grid-template-columns: minmax(0, 1fr); gap: 1.6rem; }
  .post-rail { position: static; }
  .post-rail__meta { flex-direction: row; flex-wrap: wrap; gap: .4rem 1.2rem; }
  .post-rail__art { max-width: 22rem; }
  .post-body { max-width: var(--measure); }
}
.prose h2 { font-size: var(--t-h2); margin: 2.3em 0 .7em; font-weight: 420; }
.prose h3 { font-size: 1.05em; margin: 2em 0 .5em; font-weight: 460; }
.prose > *:first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 1.15em; margin: 0 0 1.25em; }
.prose li { margin-bottom: .34em; }
.prose li::marker { color: var(--ink-faint); }
.prose blockquote {
  margin: 1.9em 0;
  padding-left: 1.2rem;
  border-left: 1px solid var(--rule);
  font-style: italic;
  color: var(--ink-soft);
}
.prose img { margin-block: 2rem; }

/* figures may break the reading measure */
.prose img[src*="/img/"] { max-width: min(52rem, 100%); }

.article { padding-bottom: clamp(3rem, 7vw, 5rem); }

/* ---------------------------------------------------------------
   Downloads — the script, and data to run it against
   --------------------------------------------------------------- */

.dl {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: clamp(1.4rem, 3vw, 2rem);
  border-top: 1px solid var(--rule);
}
.dl__head {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .17em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 400;
  margin: 0 0 .9rem;
}
.dl__run {
  margin: 0 0 1.1rem;
  font-size: .9rem;
}
.dl__run code {
  background: var(--paper-2);
  padding: .35rem .6rem;
  display: inline-block;
}

.dl__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule-soft);
}
.dl__list li { border-bottom: 1px solid var(--rule-soft); }
/* These are file rows, not running-text links, so the underline gradient
   `.prose a` paints is cancelled explicitly — it drew a coloured rule across
   the full width of every row. */
.dl__list a {
  background-image: none;
  color: inherit;
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr) auto;
  gap: .3rem 1.2rem;
  align-items: baseline;
  padding: .8rem .4rem .8rem 1.6rem;
  position: relative;
  transition: background-color .3s ease;
}
.dl__list a:hover { background: var(--paper-2); }

/* downward arrow standing in for a file icon */
.dl__list a::before {
  content: "↓";
  position: absolute;
  left: .25rem;
  font-family: var(--mono);
  color: var(--ink-faint);
  transition: transform .3s cubic-bezier(.2,.7,.3,1), color .3s ease;
}
.dl__list a:hover::before { transform: translateY(3px); color: var(--accent); }

/* an outward arrow, since this one leaves the site rather than saving */
.dl__list a.dl--ext::before { content: "↗"; }
.dl__list a.dl--ext:hover::before { transform: translate(2px, -2px); }

.dl__name {
  font-family: var(--mono);
  font-size: .88rem;
  color: var(--ink);
  word-break: break-all;
}
.dl__list a:hover .dl__name { color: var(--accent); }
.dl__note {
  font-size: .9rem;
  color: var(--ink-soft);
  line-height: 1.5;
}
.dl__size {
  font-family: var(--mono);
  font-size: var(--t-label);
  color: var(--ink-faint);
  text-align: right;
  font-feature-settings: "tnum" 1;
  white-space: nowrap;
}

@media (max-width: 46rem) {
  /* name and size share the top line, the note runs underneath */
  .dl__list a {
    grid-template-columns: minmax(0, 1fr) auto;
    padding-left: 1.5rem;
  }
  .dl__note { grid-column: 1 / -1; }
}

/* ---------------------------------------------------------------
   Code
   --------------------------------------------------------------- */

pre {
  margin: 1.8rem 0;
  padding: 1.1rem 1.2rem;
  background: var(--paper-2);
  border-left: 2px solid var(--rule);
  overflow-x: auto;
  font-family: var(--mono);
  font-size: .8rem;
  line-height: 1.75;
  tab-size: 4;
  max-width: min(52rem, 100%);
}
pre code { font: inherit; background: none; padding: 0; }
code {
  font-family: var(--mono);
  font-size: .86em;
  background: var(--paper-2);
  padding: .1em .35em;
  color: var(--ink);
}

.highlight .c, .highlight .c1, .highlight .cm, .highlight .sd { color: var(--ink-faint); font-style: italic; }
.highlight .k, .highlight .kn, .highlight .kd, .highlight .kc,
.highlight .ow, .highlight .nb { color: var(--accent); }
.highlight .s, .highlight .s1, .highlight .s2, .highlight .se,
.highlight .mi, .highlight .mf, .highlight .m { color: #4a6b45; }
.highlight .nf, .highlight .nc { color: var(--ink); font-weight: 500; }
@media (prefers-color-scheme: dark) {
  .highlight .s, .highlight .s1, .highlight .s2, .highlight .se,
  .highlight .mi, .highlight .mf, .highlight .m { color: #9cbf94; }
}
:root[data-theme="dark"] .highlight .s,
:root[data-theme="dark"] .highlight .s1,
:root[data-theme="dark"] .highlight .s2,
:root[data-theme="dark"] .highlight .mi,
:root[data-theme="dark"] .highlight .mf { color: #9cbf94; }

/* ---------------------------------------------------------------
   Post navigation + footer
   --------------------------------------------------------------- */

.post-nav {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  flex-wrap: wrap;
}
.post-nav a { max-width: 16rem; }
.post-nav .label { display: block; margin-bottom: .35rem; }
.post-nav span.t { font-size: 1rem; line-height: 1.3; display: block; transition: color .25s ease; }
.post-nav a:hover span.t { color: var(--accent); }
.post-nav .next { text-align: right; margin-left: auto; }

.foot { border-top: 1px solid var(--rule); padding-block: 2rem 2.6rem; }
.foot p {
  font-family: var(--mono);
  font-size: var(--t-label);
  line-height: 1.9;
  color: var(--ink-faint);
  margin: 0;
}

/* ---------------------------------------------------------------
   Contact form
   --------------------------------------------------------------- */

.form { margin-top: 2.2rem; max-width: 38rem; }
.field { margin-bottom: 1.3rem; }
.field label {
  display: block;
  margin-bottom: .4rem;
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.field input, .field textarea {
  width: 100%;
  padding: .65rem .8rem;
  font-family: var(--serif);
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 0;
  transition: border-color .25s ease, background-color .25s ease;
}
.field textarea { resize: vertical; min-height: 8rem; }
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--paper);
}

/* honeypot — off-screen rather than display:none, which some bots detect */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form__foot { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; margin-top: 1.6rem; }
.form button[type="submit"] {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  padding: .7rem 1.4rem;
  cursor: pointer;
  transition: background-color .25s ease, border-color .25s ease, opacity .25s ease;
}
.form button[type="submit"]:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); }
.form button[type="submit"]:disabled { opacity: .5; cursor: default; }

.form__status { margin: 0; font-size: .93rem; color: var(--ink-faint); }
.form__status[data-state="ok"]    { color: #3f6b3a; }
.form__status[data-state="error"] { color: var(--accent); }
@media (prefers-color-scheme: dark) { .form__status[data-state="ok"] { color: #93c088; } }
:root[data-theme="dark"] .form__status[data-state="ok"] { color: #93c088; }

.form__alt { margin-top: 1.6rem; font-size: .95rem; color: var(--ink-soft); }

/* ---------------------------------------------------------------
   Map
   --------------------------------------------------------------- */

.map-wrap {
  margin-top: clamp(2.5rem, 6vw, 3.5rem);
  padding-top: clamp(2rem, 5vw, 2.8rem);
  border-top: 1px solid var(--rule);
}
.map {
  width: 100%;
  height: clamp(240px, 34vw, 360px);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  z-index: 0;
}
.map .leaflet-container { font-family: var(--mono); background: var(--paper-2); }

/* CARTO's dark tiles put near-black buildings on a near-black ground, which
   on this page reads as an empty rectangle. Lifting the whole tile pane
   separates the roads and labels again without swapping basemaps. */
@media (prefers-color-scheme: dark) {
  .map .leaflet-tile-pane { filter: brightness(1.75) contrast(.88) saturate(.85); }
}
:root[data-theme="dark"] .map .leaflet-tile-pane {
  filter: brightness(1.75) contrast(.88) saturate(.85);
}
:root[data-theme="light"] .map .leaflet-tile-pane { filter: none; }

/* Sat on its own bright band across the foot of the map before. */
.map .leaflet-control-attribution {
  font-family: var(--mono);
  font-size: 9px;
  line-height: 1.6;
  padding: .2rem .45rem;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  color: var(--ink-faint);
  border-top-left-radius: 2px;
}
.map .leaflet-control-attribution a {
  color: var(--ink-soft);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.map .leaflet-control-attribution a:hover { color: var(--accent); }
.map .leaflet-control-zoom a {
  font-family: var(--mono);
  color: var(--ink);
  background: var(--paper);
  border-color: var(--rule);
}
.map .leaflet-control-zoom a:hover { background: var(--paper-2); }
.map .leaflet-popup-content-wrapper, .map .leaflet-popup-tip {
  background: var(--paper);
  color: var(--ink);
  border-radius: 0;
  box-shadow: 0 1px 8px rgba(0,0,0,.14);
}
.map .leaflet-popup-content {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .08em;
  text-transform: uppercase;
  margin: .7rem .9rem;
}
.map-caption {
  margin: .9rem 0 0;
  font-family: var(--mono);
  font-size: var(--t-label);
  line-height: 1.85;
  letter-spacing: .05em;
  color: var(--ink-faint);
}
.map-caption strong { color: var(--ink-soft); font-weight: 400; }

/* ---------------------------------------------------------------
   A11y
   --------------------------------------------------------------- */

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

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: var(--paper);
  padding: .7rem 1.1rem; z-index: 100;
  font-family: var(--mono); font-size: var(--t-label);
  letter-spacing: .12em; text-transform: uppercase;
}
.skip:focus { left: 1rem; top: .5rem; }

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

/* ---------------------------------------------------------------
   Small screens — the rules that apply across every page
   --------------------------------------------------------------- */

/* Nothing should be able to push the page sideways. Long URLs in prose,
   wide tables and code blocks are the usual culprits; each is handled
   below rather than by hiding the overflow on the body, which would also
   kill position:sticky on the masthead. */
.prose { overflow-wrap: break-word; }
.prose a { word-break: break-word; }

/* tables scroll inside their own box instead of widening the page */
.prose table {
  display: block;
  width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  margin: 1.8rem 0;
  font-size: .95em;
  -webkit-overflow-scrolling: touch;
}
.prose th, .prose td {
  padding: .5rem .8rem;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  white-space: nowrap;
}
.prose th {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 400;
}

@media (max-width: 46rem) {
  /* every link and control in a list reaches a comfortable tap size */
  .latest__item { padding: 1.2rem 1.1rem 1.35rem; }
  .index a { padding-block: 1.35rem; }

  .topics li { grid-template-columns: 2rem 1fr; padding-block: .82rem; }

  .contact { gap: 2.5rem; }
  .form__foot { gap: .9rem; }
  .form button[type="submit"] {
    width: 100%;
    min-height: var(--tap);
    font-size: .8rem;
  }
  .form__status { width: 100%; }

  .map { height: clamp(220px, 52vw, 300px); }

  /* previous/next stop sitting shoulder to shoulder in two cramped columns */
  .post-nav { flex-direction: column; gap: 1.3rem; }
  .post-nav a { max-width: none; }
  .post-nav .next { text-align: left; margin-left: 0; }

  pre { font-size: .74rem; padding: .9rem 1rem; }
}

@media (max-width: 34rem) {
  .latest__grid { grid-template-columns: 1fr; }
  .about__gallery { grid-template-columns: 1fr; }

  /* The rail cannot fit on one line here, and a wrapped line was starting
     with an orphaned separator dot. Stack the items and drop the dots. */
  .hero__meta { flex-direction: column; align-items: flex-start; gap: .28rem; }
  .hero__meta span + span::before { content: none; }
}
