/*
Theme Name: Longhand
Theme URI: https://oluwatobisoyombo.com
Update URI: false
Author: Oluwatobi Soyombo
Description: A reading-first theme for a writer with a long back catalogue. An even timeline rather than a front page of headlines, with every post one keystroke away.
Version: 2.10.0
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: longhand
Tags: blog, one-column, custom-colors, custom-logo, editor-style, translation-ready, featured-images
*/

/* ==========================================================================
   1. Tokens
   ========================================================================== */

:root {
  color-scheme: light;

  --paper:        #fbfaf8;
  --raised:       #ffffff;
  --sunk:         #efece5;
  --ink:          #101013;
  --ink-2:        #5b5b64;
  --ink-3:        #6e6e76;
  --hair:         #e9e6df;
  --hair-strong:  #d3cfc5;
  --field-line:   #767680;
  --error-line:   #b3261e;
  --accent:       #2f3577;
  --accent-soft:  rgba(47, 53, 119, .055);
  --accent-line:  rgba(47, 53, 119, .3);
  --selection:    rgba(47, 53, 119, .15);

  --display: "Instrument Serif", "Iowan Old Style", Georgia, serif;
  --body:    "Newsreader", "Iowan Old Style", Georgia, serif;
  --meta:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --measure: 36rem;
  --gutter:  clamp(1.25rem, 4vw, 2rem);
  --dur: 220ms;
  --ease: cubic-bezier(.2, .6, .3, 1);

  /* The sticky bar: its own height, and how far down the viewport it starts
     once WordPress puts its admin bar above it. */
  --bar-h:      3.25rem;
  --sticky-top: 0px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --paper:       #0e0e11;
    --raised:      #15151a;
    --sunk:        #191920;
    --ink:         #eeece6;
    --ink-2:       #a5a4ad;
    --ink-3:       #8b8b95;
    --hair:        #24242b;
    --hair-strong: #383840;
    --field-line:  #7c7c88;
    --error-line:  #f2b8b5;
    --accent:      #a9aef2;
    --accent-soft: rgba(169, 174, 242, .075);
    --accent-line: rgba(169, 174, 242, .35);
    --selection:   rgba(169, 174, 242, .22);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --paper:       #0e0e11;
  --raised:      #15151a;
  --sunk:        #191920;
  --ink:         #eeece6;
  --ink-2:       #a5a4ad;
  --ink-3:       #8b8b95;
  --hair:        #24242b;
  --hair-strong: #383840;
  --field-line:  #7c7c88;
  --error-line:  #f2b8b5;
  --accent:      #a9aef2;
  --accent-soft: rgba(169, 174, 242, .075);
  --accent-line: rgba(169, 174, 242, .35);
  --selection:   rgba(169, 174, 242, .22);
}

/* ==========================================================================
   2. Base
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--bar-h) + 1.25rem);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-optical-sizing: auto;
  font-size: 19px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--selection); }

a { color: inherit; text-decoration: none; }
img, svg, video { max-width: 100%; height: auto; display: block; }

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

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

.skip-link {
  position: absolute; top: -100px; left: var(--gutter); z-index: 100;
  padding: .6rem 1rem; background: var(--ink); color: var(--paper);
  font-family: var(--meta); font-size: .8rem; text-decoration: none;
}
.skip-link:focus { top: .75rem; }

.shell { width: min(100% - (var(--gutter) * 2), 58rem); margin-inline: auto; }

.meta, .entry__meta, .post-head__meta, .year__c, .topbar__nav, .site-foot,
.post-nav__label, .comments__title, .page-kicker {
  font-family: var(--meta);
  letter-spacing: .02em;
}

/* ==========================================================================
   3. Masthead
   ========================================================================== */

/* .has-ident marks the front page, where the bar has a full masthead above it. */

/* --------------------------------------------------------------------------
   3a. Who this is — the front page only.

   Replaying an introduction above every one of two hundred entries is a
   sentence written for somebody arriving, said to somebody who already chose.
   It cost 176px above a desktop entry and pushed the first paragraph of an
   essay clean off a 375x812 phone screen.
   -------------------------------------------------------------------------- */

.ident-block { padding: 2.8rem 0 1.8rem; }

/* Text left, portrait opposite, one margin — the same rule the listing follows
   when it puts thumbnails on the right so that every title starts square. The
   masthead used to run in a shell 6rem wider than the reading column purely to
   seat a portrait beside the name, which centred the name on an axis nothing
   else on the page shared. */
.ident {
  display: flex; align-items: center; gap: 1.8rem;
  text-align: left;
}

.ident__text { flex: 1 1 auto; min-width: 0; }

.ident__portrait { flex: none; order: 2; }
body[data-thumb-side="left"] .ident__portrait { order: 0; }

.ident__portrait img,
.ident__img,
.ident__portrait .custom-logo {
  width: 84px; height: 84px; border-radius: 50%; object-fit: cover;
  filter: grayscale(1) contrast(1.04);
  transition: filter .35s var(--ease);
}
.ident:hover .ident__portrait img { filter: grayscale(0); }

.ident__name {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.5rem, 5.5vw, 3.9rem);
  letter-spacing: -.022em;
  line-height: 1;
}

.ident__line {
  margin: .55rem 0 0;
  font-size: 1.02rem;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 48ch;
  text-wrap: pretty;
}
.ident__more { color: var(--accent); border-bottom: 1px solid var(--accent-line); white-space: nowrap; }
.ident__more:hover { border-color: currentColor; }

/* --------------------------------------------------------------------------
   3b. What you can do — every view, and it stays.

   These entries run to several thousand pixels. Once the old masthead had
   scrolled away there was no way home, no search, no colour control and no
   statement of what you were reading: a two-pixel progress line and nothing
   else.
   -------------------------------------------------------------------------- */

.topbar {
  position: sticky; top: var(--sticky-top, 0px); z-index: 40;
  background: var(--paper);
  border-bottom: 1px solid transparent;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.topbar.is-stuck { border-bottom-color: var(--hair); }
@supports ((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px))) {
  .topbar.is-stuck {
    background: color-mix(in srgb, var(--paper) 82%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(1.6);
    backdrop-filter: blur(12px) saturate(1.6);
  }
}

/* On the front page the bar sits below the name, so it wants a line above it
   rather than beneath — until it lifts off and becomes the top of the page. */
.has-ident .topbar { border-top: 1px solid var(--hair); }
.has-ident .topbar.is-stuck { border-top-color: transparent; }

.topbar__inner {
  display: flex; align-items: center; gap: 1rem;
  min-height: var(--bar-h);
}

.topbar__id {
  display: inline-flex; align-items: center; gap: .55rem;
  flex: none; color: var(--ink);
  transition: opacity var(--dur) var(--ease);
}
.topbar__mark { flex: none; }
.topbar__img {
  width: 24px; height: 24px; border-radius: 50%; object-fit: cover;
  filter: grayscale(1);
}
.topbar__name {
  font-family: var(--meta); font-size: .74rem; letter-spacing: .02em;
  white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.topbar__id:hover .topbar__name { color: var(--accent); }

/* The same name twice, sixty pixels apart, is once too many: on the front page
   the bar keeps its identity to itself until the real one has scrolled off. */
.has-ident .topbar:not(.is-stuck) .topbar__id { opacity: 0; pointer-events: none; }

/* What you are reading, revealed once the entry's own title is out of sight. */
.topbar__now {
  /* Basis zero, not auto: the title takes the room left over once the name,
     the navigation and the tools have theirs, and ellipsises into it. On auto
     it bid for space at full title width and squeezed the navigation into a
     sideways scroll instead. */
  flex: 1 1 0; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: .92rem; color: var(--ink-2);
  opacity: 0; transform: translateY(3px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.topbar__now::before { content: "/ "; color: var(--hair-strong); }
.topbar__now.is-on { opacity: 1; transform: none; }

/* Below this the room left over is a few characters and an ellipsis, which
   names nothing. The breadcrumb above the entry is still there to say where
   you are, so the bar gives the width to the navigation instead. */
@media (max-width: 60rem) { .topbar__now { display: none; } }

.topbar__nav {
  margin-left: auto; min-width: 0;
  font-size: .68rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-3);
  /* A menu is administrator-editable and can be any length; it scrolls rather
     than wrapping the bar onto a second line or pushing the tools off it.
     Setting overflow on one axis makes the other clip too, and the box is
     exactly as tall as its links — so the focus ring, which is drawn 5px
     outside them, was being cut off top and bottom and a keyboard reader could
     not see where they were. The padding is inside the scrollport, so it gives
     the ring room; the negative margin keeps the bar the height it was. */
  padding-block: .4rem; margin-block: -.4rem;
  overflow-x: auto; scrollbar-width: none;
}
.topbar__nav::-webkit-scrollbar { display: none; }
.topbar__nav-list {
  display: flex; flex-wrap: nowrap; align-items: center; gap: 1.35rem;
  margin: 0; padding: 0; list-style: none;
}
.topbar__nav-list li { display: inline-flex; }
.topbar__nav a { white-space: nowrap; transition: color var(--dur) var(--ease); }
.topbar__nav a:hover,
.topbar__nav .is-current,
.topbar__nav .current-menu-item > a,
.topbar__nav .current_page_item > a { color: var(--ink); }

.topbar__tools { display: flex; align-items: center; gap: .35rem; flex: none; }

/* One control style for both. The search was the only object on the page
   carrying a border, a raised fill and a hover shadow at once, which made it
   heavier than any headline on a theme whose whole argument is the writing. It
   keeps its label — it is on every page now and never scrolls away, so it is
   easier to find than it was — and gives up the weight. */
.topbar__btn {
  display: inline-flex; align-items: center; gap: .5rem;
  height: 2rem; padding: 0 .65rem;
  border: 1px solid transparent; border-radius: 999px;
  background: transparent; color: var(--ink-3);
  font-family: var(--meta); font-size: .7rem; letter-spacing: .02em;
  cursor: pointer; white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.topbar__btn:hover { color: var(--ink); border-color: var(--hair-strong); }
.topbar__btn svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.6; flex: none; }
.topbar__search { border-color: var(--hair); }
.topbar__search kbd {
  font: inherit; font-size: .66rem; color: var(--ink-3);
  border: 1px solid var(--hair); border-radius: 3px; padding: .05rem .3rem;
}
.topbar__toggle { padding: 0 .5rem; }

/* Both controls in the bar are scripted: one opens a dialog JavaScript builds,
   the other stores a preference. With scripting off they are dead buttons, so
   they stand aside and a plain search field takes the space instead. */
html:not(.has-js) .topbar__search,
html:not(.has-js) .topbar__toggle { display: none; }

.topbar__search-fallback input {
  height: 2rem; padding: 0 .7rem; min-width: 0; width: min(14rem, 40vw);
  border: 1px solid var(--hair); border-radius: 999px;
  background: transparent; color: var(--ink);
  font-family: var(--meta); font-size: .7rem; letter-spacing: .02em;
}
.topbar__search-fallback input::placeholder { color: var(--ink-3); }
.topbar__search-fallback input:focus { outline: none; border-color: var(--accent); }

/* The old toggle drew a sun in both schemes, so it named neither the state it
   was in nor the one it was offering. A moon offers dark; a sun offers light. */
.topbar__toggle .i-sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .topbar__toggle .i-moon { display: none; }
  :root:not([data-theme="light"]) .topbar__toggle .i-sun  { display: block; }
}
:root[data-theme="dark"] .topbar__toggle .i-moon { display: none; }
:root[data-theme="dark"] .topbar__toggle .i-sun  { display: block; }
:root[data-theme="light"] .topbar__toggle .i-moon { display: block; }
:root[data-theme="light"] .topbar__toggle .i-sun  { display: none; }

/* Progress belongs to the thing it measures, not to the top edge of the window. */
.topbar__progress {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  transform-origin: 0 50%; transform: scaleX(var(--p, 0));
  background: var(--accent); opacity: .9;
}

/* WordPress's own admin bar owns the top of the viewport while you are signed
   in, and nothing stops a sticky theme header from sliding underneath it.
   These are core's own heights and breakpoints; below 600px core lets the admin
   bar scroll away with the page, so the offset goes back to nothing. */
body.admin-bar { --sticky-top: 32px; }
@media screen and (max-width: 782px) { body.admin-bar { --sticky-top: 46px; } }
@media screen and (max-width: 600px) { body.admin-bar { --sticky-top: 0px; } }

/* ==========================================================================
   4. The listing
   ========================================================================== */

.year { display: flex; align-items: baseline; gap: 1rem; padding: 3.4rem 0 .2rem; }
/* The generous top padding separates a year from the list above it. The first
   marker has only the masthead above it, so it needs none — with it, the first
   post was pushed past half the viewport. */
.year:first-child { padding-top: 1.2rem; }
.year__n {
  font-family: var(--display); font-size: 1.9rem; font-weight: 400;
  letter-spacing: -.02em; line-height: 1; color: var(--ink-2);
}
.year__c { font-size: .66rem; letter-spacing: .15em; text-transform: uppercase; color: var(--ink-3); }
.year__rule { flex: 1; height: 1px; background: var(--hair); }

.entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 11rem;
  gap: 2.4rem;
  align-items: start;
  padding: 2.3rem 0;
  border-bottom: 1px solid var(--hair);
  position: relative;
}
body[data-thumb-side="left"] .entry { grid-template-columns: 11rem minmax(0, 1fr); }
body[data-thumb-side="left"] .entry__text { order: 2; }
body[data-thumb-side="left"] .entry__thumb { order: 1; }
body[data-thumbs="off"] .entry { grid-template-columns: minmax(0, 1fr); }
body[data-thumbs="off"] .entry__thumb { display: none; }
.entry:last-child { border-bottom: 0; }

/* The hover wash fades in from the page rather than ending on a hard edge, so
   the row lights up without a box being drawn around it. Its negative inset
   must stay inside the page gutter or it widens the document. */
.entry::before {
  content: "";
  position: absolute; inset: 0 -1rem;
  border-radius: 4px;
  background: linear-gradient(90deg, transparent, var(--accent-soft) 10%,
              var(--accent-soft) 90%, transparent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.entry:hover::before { opacity: 1; }
.entry > * { position: relative; }

.entry__hit { position: absolute; inset: 0; }

.entry__meta {
  display: flex; flex-wrap: wrap; gap: .85rem; align-items: center;
  margin-bottom: .6rem;
  font-size: .68rem; letter-spacing: .15em; text-transform: uppercase;
  color: var(--ink-3);
}
.entry__cat { color: var(--accent); }

.entry__title {
  margin: 0 0 .5rem;
  font-weight: 500; font-size: 1.52rem; line-height: 1.24; letter-spacing: -.014em;
  text-wrap: balance;
}
.entry:hover .entry__title { color: var(--accent); }

.entry__excerpt { margin: 0; font-size: 1rem; line-height: 1.62; color: var(--ink-2); max-width: 56ch; }

.entry__thumb img, .entry__thumb-empty {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: 3px; background: var(--sunk);
}
.entry__thumb-empty { display: block; }
.entry__thumb img { transition: transform .5s var(--ease); }
.entry:hover .entry__thumb img { transform: scale(1.03); }

/* ==========================================================================
   5. Post and page
   ========================================================================== */

/* A post has no sidebar, so the reading column is centred: the page reads like
   a page of a book rather than a column pinned to the left edge. */
.post-head { padding: 3.6rem 0 0; text-align: center; }

.post-head__meta {
  display: flex; flex-wrap: wrap; gap: 1.1rem; align-items: center; justify-content: center;
  margin-bottom: 1rem;
  font-size: .68rem; letter-spacing: .15em; text-transform: uppercase;
  color: var(--ink-3);
}
.post-head__cat { color: var(--accent); }
.post-head__meta a:hover { color: var(--ink); }

.post-title {
  margin: 0 auto;
  font-family: var(--display); font-weight: 400;
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  line-height: 1.04; letter-spacing: -.024em;
  text-wrap: balance;
  max-width: 18ch;
}

/* a hairline under the title, the way a book separates a chapter opening */
.post-head::after {
  content: ""; display: block;
  width: 3.5rem; height: 1px; margin: 2rem auto 0;
  background: var(--hair-strong);
}

.post-featured { margin: 2.4rem auto 0; max-width: 44rem; }
.post-featured img { width: 100%; border-radius: 3px; }

.prose { max-width: var(--measure); margin: 2.4rem auto 0; }

/* Recovered posts arrive wrapped in the old theme's own container, so the
   paragraphs are grandchildren of .prose, not children. Spacing has to be set
   on the elements themselves — a child combinator here matched nothing and
   collapsed every post into one unbroken block of text. */
.prose p,
.prose ul, .prose ol, .prose dl,
.prose blockquote, .prose figure, .prose pre, .prose table,
.prose .gallery, .prose .wp-caption {
  margin: 0 0 1.35em;
}
.prose p { line-height: 1.8; }
.prose p:last-child, .prose > :last-child { margin-bottom: 0; }

/* an editorial lede: the opening paragraph carries a little more weight */
.prose > :first-child > p:first-child,
.prose > p:first-child {
  font-size: 1.13em;
  line-height: 1.7;
  color: var(--ink);
}

.prose h2, .prose h3, .prose h4 {
  font-weight: 600; line-height: 1.25; letter-spacing: -.012em;
  margin: 2em 0 .55em; text-wrap: balance;
}
.prose h2 { font-size: 1.5rem; }
.prose h3 { font-size: 1.22rem; }
.prose a { color: var(--accent); border-bottom: 1px solid var(--accent-line); }
.prose a:hover { border-color: currentColor; }
.prose ul, .prose ol { margin: 0; padding-left: 1.3em; }
.prose li + li { margin-top: .4em; }
.prose blockquote {
  margin: 2em 0; padding-left: 1.25em;
  border-left: 2px solid var(--hair-strong);
  font-style: italic; color: var(--ink-2);
}
.prose img { border-radius: 3px; margin-inline: auto; }
.prose figure { margin: 2em 0; }
.prose figcaption, .prose .wp-caption-text {
  margin-top: .6rem; font-family: var(--meta); font-size: .72rem; color: var(--ink-3);
}
.prose hr { border: 0; border-top: 1px solid var(--hair); margin: 2.5em 0; }
.prose code {
  font-family: var(--meta); font-size: .85em;
  background: var(--sunk); padding: .1em .35em; border-radius: 2px;
}
.prose pre {
  overflow-x: auto; padding: 1rem 1.15rem;
  background: var(--sunk); border-radius: 3px; font-size: .85rem;
}
.prose pre code { background: none; padding: 0; }
.prose table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.prose th, .prose td { text-align: left; padding: .5rem .6rem; border-bottom: 1px solid var(--hair); }
.prose iframe, .prose embed, .prose object { max-width: 100%; }

/* A handful of very old posts reference an image file that is no longer on the
   server. This is a live blog, not an exhibit about its own history, so the gap
   is simply closed rather than announced to the reader. The markup stays in the
   post, so any image found later can be dropped straight back in. */
.img-gone { display: none; }
.link-gone { color: inherit; text-decoration: none; cursor: default; }

.prose .gallery {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: .6rem; margin: 2em 0;
}
.prose .gallery br { display: none; }
.prose .gallery-item, .prose .gallery dt, .prose .gallery dd { margin: 0; }
.prose .gallery img { width: 100%; aspect-ratio: 1; object-fit: cover; }

/* ==========================================================================
   6. Post footer
   ========================================================================== */

.post-foot {
  margin: 3.5rem auto 0; padding-top: 1.5rem;
  border-top: 1px solid var(--hair); max-width: var(--measure);
}

.post-tags { display: flex; flex-wrap: wrap; gap: .45rem; }
.post-tags a {
  font-family: var(--meta); font-size: .7rem; letter-spacing: .04em;
  color: var(--ink-3); border: 1px solid var(--hair); border-radius: 999px;
  padding: .2rem .65rem;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.post-tags a:hover { border-color: var(--accent); color: var(--accent); }

.post-nav { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-top: 2rem; }
.post-nav__item { min-width: 0; }
.post-nav__item--next { text-align: right; }
.post-nav__label {
  display: block; font-size: .66rem; letter-spacing: .15em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: .3rem;
}
.post-nav__title { line-height: 1.3; display: inline-block; font-size: 1rem; }
.post-nav__title:hover { color: var(--accent); }

/* ==========================================================================
   7. Comments
   ========================================================================== */

.comments { margin: 4rem auto 0; max-width: var(--measure); }

.comments__title {
  display: flex; align-items: center; gap: 1rem;
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 400; margin: 0 0 1.8rem;
}
.comments__title::after {
  content: ""; flex: 1; height: 1px; background: var(--hair);
}

.comment-list { margin: 0; padding: 0; list-style: none; }
.comment-list > li + li { margin-top: 1.6rem; padding-top: 1.6rem; border-top: 1px solid var(--hair); }
.comment-list .children { list-style: none; margin: 1.4rem 0 0 1.6rem; padding-left: 1.4rem; border-left: 1px solid var(--hair); }
.comment-list .children li + li { margin-top: 1.4rem; }

/* A disc with the commenter's initial echoes the portrait in the masthead and
   gives a long thread some rhythm without needing avatars we do not have. */
.comment-card { display: grid; grid-template-columns: 2.5rem minmax(0, 1fr); gap: 1rem; align-items: start; }

.comment__mark {
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--sunk); color: var(--ink-2);
  font-family: var(--meta); font-size: .82rem; line-height: 1;
  user-select: none;
}
.comment__mark--unknown {
  background: transparent; border: 1px dashed var(--hair-strong);
  color: var(--ink-3); font-size: 1rem;
}

.comment__main { min-width: 0; }

.comment__head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: .5rem 1rem;
  margin-bottom: .45rem;
}
.comment__author { font-weight: 500; font-size: 1.05rem; letter-spacing: -.008em; }
.comment__author--unknown { color: var(--ink-3); font-style: italic; font-weight: 400; font-size: 1rem; }
.comment__date {
  font-family: var(--meta); font-size: .66rem; color: var(--ink-3);
  letter-spacing: .08em; text-transform: uppercase; white-space: nowrap;
}
.comment__approx { opacity: .65; }

.comment__body { font-size: 1.02rem; line-height: 1.72; color: var(--ink-2); }
.comment__body p { margin: 0 0 .7em; }
.comment__body p:last-child { margin-bottom: 0; }
.comment__body a { color: var(--accent); border-bottom: 1px solid var(--accent-line); }

.comments__closed {
  font-family: var(--meta); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
  margin-top: 2.2rem; padding-top: 1.2rem; border-top: 1px solid var(--hair);
}

@media (max-width: 34rem) {
  .comment-card { grid-template-columns: 2rem minmax(0, 1fr); gap: .8rem; }
  .comment__mark { width: 2rem; height: 2rem; font-size: .72rem; }
  .comment__head { justify-content: flex-start; }
}

/* --------------------------------------------------------------------------
   The comment form
   -------------------------------------------------------------------------- */

.comment-respond { margin: 3rem auto 0; max-width: var(--measure); }
.comment-reply-title {
  display: flex; align-items: center; gap: 1rem;
  font-family: var(--meta); font-size: .68rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3); font-weight: 400; margin: 0 0 1.4rem;
}
.comment-reply-title::after { content: ""; flex: 1; height: 1px; background: var(--hair); }
.comment-reply-title small { margin-left: auto; text-transform: none; letter-spacing: .04em; }

/* WordPress emits each field as a sibling <p>, so the form is laid out as a
   three-column grid: everything spans the full width except name/email/website,
   which sit side by side. (A column flex with `flex: 1 1 12rem` gave each field
   a 12rem *height* — flex-basis follows the main axis, which is why the form
   was full of empty space.) */
.comment-form {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.1rem;
  align-items: start;
}
.comment-form > * { grid-column: 1 / -1; }
.comment-form p { margin: 0; }
.comment-notes, .comment-form-cookies-consent label, .form-allowed-tags {
  font-family: var(--meta); font-size: .68rem; line-height: 1.6; color: var(--ink-3);
}
.form-allowed-tags { display: none; }

.comment-form label {
  display: block;
  font-family: var(--meta); font-size: .64rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: .35rem;
}
.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form input[type="url"],
.comment-form textarea {
  width: 100%;
  padding: .65rem .8rem;
  border: 1px solid var(--hair); border-radius: 3px;
  background: var(--raised); color: var(--ink);
  font-family: var(--body); font-size: 1rem; line-height: 1.6;
  transition: border-color var(--dur) var(--ease);
}
.comment-form textarea { min-height: 8rem; resize: vertical; }
.comment-form input:focus, .comment-form textarea:focus {
  outline: none; border-color: var(--accent);
}
.comment-form-author { grid-column: 1; }
.comment-form-email  { grid-column: 2; }
.comment-form-url    { grid-column: 3; }

.comment-form-cookies-consent {
  display: flex; align-items: flex-start; gap: .55rem;
}
.comment-form-cookies-consent input { margin: .2rem 0 0; flex: none; }
.comment-form-cookies-consent label {
  margin: 0; text-transform: none; letter-spacing: .02em;
  font-size: .7rem; line-height: 1.5;
}

.comment-form .form-submit { margin-top: .3rem; }
.comment-form .submit {
  appearance: none;
  padding: .7rem 1.4rem;
  border: 1px solid var(--ink); border-radius: 999px;
  background: var(--ink); color: var(--paper);
  font-family: var(--meta); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; cursor: pointer;
  transition: opacity var(--dur) var(--ease);
}
.comment-form .submit:hover { opacity: .82; }

/* the guard: honeypot stays reachable to bots but off-screen for people */
.cg__trap {
  position: absolute !important;
  left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden;
}

.cg__status {
  display: flex; align-items: center; gap: .55rem;
  font-family: var(--meta); font-size: .66rem; letter-spacing: .06em;
  color: var(--ink-3);
}
.cg__dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--hair-strong);
  transition: background var(--dur) var(--ease);
}
.cg__status[data-state="working"] .cg__dot { background: var(--accent); animation: cg-pulse 1.1s ease-in-out infinite; }
.cg__status[data-state="ready"] .cg__dot { background: #2e7d5b; }
.cg__status[data-state="failed"] .cg__dot { background: #a8762a; }
.cg__status[data-state="restored"] .cg__dot { background: var(--accent); }

@keyframes cg-pulse { 50% { opacity: .35; } }

.cg-preview { margin-top: .9rem; }
.cg-preview[hidden] { display: none; }
.cg-preview__label {
  display: block;
  font-family: var(--meta); font-size: .62rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: .6rem;
}
.cg-preview .comment-card {
  padding: .9rem 1rem; border: 1px dashed var(--hair-strong); border-radius: 4px;
  background: var(--sunk);
}

/* ==========================================================================
   8. The Index template
   ========================================================================== */

.index-head { padding: 3.2rem 0 1.5rem; }
.index-head__title {
  margin: 0; font-family: var(--display); font-weight: 400;
  font-size: clamp(2.2rem, 5vw, 3.4rem); letter-spacing: -.024em; line-height: 1.03;
}
.index-head__sub { margin: .6rem 0 0; font-family: var(--meta); font-size: .72rem; color: var(--ink-3); letter-spacing: .04em; }

.index-filter {
  position: sticky; top: calc(var(--sticky-top, 0px) + var(--bar-h)); z-index: 20;
  padding-block: .85rem;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hair);
  margin-bottom: .5rem;
}
.index-filter__row { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.index-search {
  flex: 1 1 14rem; min-width: 0;
  padding: .5rem .7rem; border: 1px solid var(--hair); border-radius: 3px;
  background: var(--raised); color: var(--ink);
  font-family: var(--meta); font-size: .8rem;
}
.index-search::placeholder { color: var(--ink-3); }
.index-search:focus { outline: none; border-color: var(--accent); }

.year-chip {
  font-family: var(--meta); font-size: .68rem; letter-spacing: .04em;
  border: 1px solid var(--hair); border-radius: 3px;
  background: transparent; color: var(--ink-2);
  padding: .35rem .55rem; cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.year-chip:hover { border-color: var(--hair-strong); color: var(--ink); }
.year-chip[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.year-chip small { opacity: .55; margin-left: .3rem; }

.index-count { font-family: var(--meta); font-size: .68rem; color: var(--ink-3); margin-left: auto; }

.index-rows { margin: 0; padding: 0; list-style: none; }
.index-row {
  display: grid; grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  gap: 1rem; align-items: baseline;
  padding: .55rem .35rem; margin-inline: -.35rem;
  border-bottom: 1px solid var(--hair); border-radius: 2px;
}
.index-row:hover { background: var(--accent-soft); }
.index-row[hidden] { display: none; }
.index-row__date { font-family: var(--meta); font-size: .68rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.index-row__title { font-size: 1rem; line-height: 1.35; }
.index-row:hover .index-row__title { color: var(--accent); }
.index-row__cat { font-family: var(--meta); font-size: .66rem; color: var(--ink-3); white-space: nowrap; }

.index-year { display: flex; align-items: baseline; gap: .9rem; margin-top: 2.25rem; padding-bottom: .5rem; }
.index-year[hidden] { display: none; }
.index-year__n { font-family: var(--display); font-size: 1.9rem; font-weight: 400; letter-spacing: -.02em; line-height: 1; }
.index-year__c { font-family: var(--meta); font-size: .66rem; color: var(--ink-3); }
.index-year__rule { flex: 1; height: 1px; background: var(--hair); }

.index-empty { padding: 3rem 0; color: var(--ink-3); font-family: var(--meta); font-size: .85rem; }
.index-empty[hidden] { display: none; }

@media (max-width: 40rem) {
  .index-row { grid-template-columns: 4.5rem minmax(0, 1fr); }
  .index-row__cat { grid-column: 2; }
}

/* ==========================================================================
   9. Command palette
   ========================================================================== */

.palette[hidden] { display: none; }
.palette {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: start center;
  padding: clamp(3rem, 12vh, 8rem) var(--gutter) var(--gutter);
  background: color-mix(in srgb, var(--sunk) 74%, transparent);
  backdrop-filter: blur(6px);
  animation: longhand-fade var(--dur) var(--ease);
}
@keyframes longhand-fade { from { opacity: 0; } }

.palette__box {
  width: min(100%, 34rem);
  background: var(--raised);
  border: 1px solid var(--hair-strong);
  border-radius: 6px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .3), 0 2px 6px rgba(0, 0, 0, .06);
  overflow: hidden;
  animation: longhand-rise var(--dur) var(--ease);
}
@keyframes longhand-rise { from { transform: translateY(-8px); opacity: 0; } }

.palette__input {
  width: 100%; border: 0; border-bottom: 1px solid var(--hair);
  background: transparent; color: var(--ink);
  font-family: var(--body); font-size: 1.25rem; padding: 1rem 1.15rem;
}
.palette__input:focus { outline: none; }
.palette__input::placeholder { color: var(--ink-3); }

/* One quiet row: two menus and a count. Menus rather than chips because eight
   years and ten topics cannot sit in a row without wrapping or scrolling, and a
   scrollbar under a search field hides half the options from the reader. */
.palette__filters {
  display: flex; align-items: center; gap: .25rem;
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--hair);
}
.palette__filters[hidden] { display: none; }

.palette__filter { position: relative; display: inline-flex; }
.palette__filter select {
  appearance: none;
  border: 0; background: transparent; color: var(--ink-2);
  font-family: var(--meta); font-size: .7rem; letter-spacing: .04em;
  padding: .25rem 1.25rem .25rem .5rem;
  border-radius: 3px; cursor: pointer;
  max-width: 12rem; text-overflow: ellipsis;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.palette__filter select:hover { background: var(--sunk); color: var(--ink); }
.palette__filter select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* the chevron, drawn rather than relying on the platform's own control */
.palette__filter::after {
  content: ""; position: absolute; right: .5rem; top: 50%;
  width: 6px; height: 6px; margin-top: -4px;
  border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  transform: rotate(45deg);
  pointer-events: none;
}
/* a menu that is actually filtering should look like it */
.palette__filter select:not([data-empty="true"]) { color: var(--accent); }

.palette__results { max-height: min(22rem, 44vh); overflow-y: auto; margin: 0; padding: .35rem; list-style: none; }
.palette__topic {
  display: block; font-family: var(--meta); font-size: .62rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); margin-top: .15rem;
}
.palette__count { margin-left: auto; }
.palette__item {
  display: grid; grid-template-columns: 1fr auto; gap: .75rem; align-items: baseline;
  padding: .5rem .8rem; border-radius: 4px; color: inherit;
}
.palette__item[aria-selected="true"] { background: var(--accent-soft); }
.palette__item mark { background: none; color: var(--accent); font-weight: 500; }
.palette__title { font-size: 1rem; line-height: 1.35; }
.palette__meta { font-family: var(--meta); font-size: .68rem; color: var(--ink-3); white-space: nowrap; }

.palette__foot {
  display: flex; gap: 1rem; padding: .55rem .95rem; border-top: 1px solid var(--hair);
  font-family: var(--meta); font-size: .66rem; color: var(--ink-3);
}
.palette__foot kbd { font: inherit; border: 1px solid var(--hair); border-radius: 2px; padding: 0 .25rem; }
.palette__empty { padding: 1.5rem .95rem; color: var(--ink-3); font-family: var(--meta); font-size: .85rem; }

/* ==========================================================================
   10. Footer and misc
   ========================================================================== */


/* The same control the bar uses, for the two places outside it that need one:
   the search button on the 404 page and the submit on the search form. It used
   to live in the masthead block that the bar replaced, which left both of them
   rendering as raw browser buttons. */
.chip {
  display: inline-flex; align-items: center; gap: .45rem;
  height: 2rem; padding: 0 .85rem;
  border: 1px solid var(--hair); border-radius: 999px;
  background: transparent; color: var(--ink-2);
  font-family: var(--meta); font-size: .72rem; letter-spacing: .04em;
  cursor: pointer; white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.chip:hover { border-color: var(--hair-strong); color: var(--ink); }

.site-foot {
  margin-top: 6rem; padding: 2rem 0 4rem;
  border-top: 1px solid var(--hair);
  font-size: .66rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3);
}
.site-foot__inner { display: flex; flex-wrap: wrap; gap: .75rem 1.5rem; justify-content: space-between; }
.site-foot a:hover { color: var(--ink); }

.pagination { margin-top: 3rem; display: flex; gap: .5rem; flex-wrap: wrap; font-family: var(--meta); font-size: .72rem; }
.pagination .page-numbers {
  padding: .35rem .65rem; border: 1px solid var(--hair); border-radius: 3px; color: var(--ink-2);
}
.pagination .page-numbers:hover { border-color: var(--hair-strong); color: var(--ink); }
.pagination .page-numbers.current { background: var(--ink); border-color: var(--ink); color: var(--paper); }

.page-head { padding: 3.2rem 0 1rem; }
.page-title {
  margin: 0; font-family: var(--display); font-weight: 400;
  font-size: clamp(2.2rem, 5vw, 3.4rem); line-height: 1.03; letter-spacing: -.024em;
  text-wrap: balance;
}
.page-kicker {
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 .6rem;
}
.notice { font-family: var(--meta); font-size: .85rem; color: var(--ink-2); padding: 1rem 0; }

.alignleft { float: left; margin: .35rem 1.5rem 1rem 0; }
.alignright { float: right; margin: .35rem 0 1rem 1.5rem; }
.aligncenter { display: block; margin-inline: auto; }
.alignwide, .alignfull { max-width: none; }

/* ==========================================================================
   11. Responsive
   ========================================================================== */

@media (max-width: 44rem) {
  body { font-size: 18px; }

  .ident-block { padding: 2.5rem 0 1.7rem; }
  .ident { gap: 1rem; }
  .ident__portrait img, .ident__img { width: 64px; height: 64px; }
  .ident__line { font-size: .98rem; }

  .topbar__inner { gap: .7rem; }

  /* A phone has room for the navigation or for the name, not both — the name
     alone took a third of the row and left three of the four links behind a
     sideways scroll. With a portrait, it stands in and the name goes to screen
     readers only; without one, the link goes altogether, since Writing is the
     same journey by a clearer label. */
  body[data-portrait="on"] .topbar__name {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  body[data-portrait="off"] .topbar__id { display: none; }

  .topbar__nav { font-size: .64rem; letter-spacing: .1em; }
  .topbar__nav-list { gap: .9rem; }
  .topbar__search-label, .topbar__search kbd { display: none; }
  .topbar__search { padding: 0 .5rem; }

  .entry,
  body[data-thumb-side="left"] .entry { grid-template-columns: minmax(0, 1fr); gap: 1.1rem; }
  body[data-thumb-side="left"] .entry__text,
  body[data-thumb-side="left"] .entry__thumb { order: 0; }
  .entry__thumb img, .entry__thumb-empty { aspect-ratio: 16 / 9; }

  .post-nav { grid-template-columns: 1fr; }
  .post-nav__item--next { text-align: left; }
  .post-title { max-width: none; }
}

/* The narrowest phones still in use. Four labels want 215px there and the row
   has 198, so the last of them sat behind a sideways scroll with nothing to say
   so. The scroll stays as the backstop for a menu longer than this one. */
@media (max-width: 22.5rem) {
  .topbar__nav { font-size: .6rem; letter-spacing: .08em; }
  .topbar__nav-list { gap: .75rem; }
  .topbar__tools { gap: .2rem; }
  .topbar__btn { padding: 0 .4rem; }
}

/* ==========================================================================
   12. Motion and print
   ========================================================================== */

@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 260ms; }

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

@media print {
  :root { --paper: #fff; --ink: #000; --ink-2: #333; --ink-3: #666; --hair: #ccc; }
  .topbar, .palette, .post-nav, .site-foot,
  .index-filter, .skip-link, .entry__thumb { display: none !important; }
  body { font-size: 11pt; line-height: 1.5; }
  .post-title { font-size: 22pt; }
  .prose a { border: 0; }
  .prose a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8pt; color: #666; }
  @page { margin: 18mm; }
}


@media (max-width: 40rem) {
  .comment-form { grid-template-columns: minmax(0, 1fr); }
  .comment-form-author,
  .comment-form-email,
  .comment-form-url { grid-column: 1; }
}

/* --------------------------------------------------------------------------
   Reader-supplied text can contain a URL or a run of characters with no space
   in it. Without this, one long token forces its container wider than the page.
   -------------------------------------------------------------------------- */
.comment__body,
.cg-preview .comment__body,
.prose,
.entry__excerpt,
.palette__title,
.index-row__title,
.read-next__link,
.post-nav__title {
  overflow-wrap: anywhere;
}
.prose pre { overflow-wrap: normal; }   /* code should scroll, not break */

.comment__main,
.entry__text,
.comment-card > * { min-width: 0; }

/* ==========================================================================
   10. Breadcrumbs, reading time and what to read next
   ========================================================================== */

/* The trail sits above the title in the same mono metadata voice as the date
   and topic, so it reads as one more fact about the entry rather than as a
   navigation bar bolted to the top of the page. */
.crumbs {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: center; gap: .5rem;
  margin: 2.4rem auto -1.2rem;
  max-width: var(--measure);
  font-family: var(--meta);
  font-size: .66rem; letter-spacing: .15em; text-transform: uppercase;
  color: var(--ink-3);
}
.crumbs a { color: var(--ink-3); text-decoration: none; }
.crumbs a:hover { color: var(--ink); }
.crumbs__sep { color: var(--hair-strong); }

/* The page you are on is stated, not linked — a link to here from here is a
   dead control, and every crumb after the first would otherwise look clickable. */
.crumbs__here {
  color: var(--ink-2);
  max-width: 38ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Sharing.

   A quiet row at the foot of the entry, in the metadata voice the date and the
   reading time already speak in. Marks rather than branded buttons: a row of
   company colours at the end of an essay belongs to the companies, not to the
   writing, and the point here is to be available rather than insistent.
   -------------------------------------------------------------------------- */

.share {
  display: flex; align-items: center; gap: .9rem;
  flex-wrap: wrap;
  padding-bottom: 1.4rem;
}

.share__label {
  font-family: var(--meta);
  font-size: .66rem; letter-spacing: .15em; text-transform: uppercase;
  color: var(--ink-3);
}

.share__list {
  display: flex; align-items: center; gap: .35rem;
  margin: 0; padding: 0; list-style: none;
}

.share__link {
  display: grid; place-items: center;
  width: 2rem; height: 2rem;
  padding: 0;
  color: var(--ink-3);
  background: none; border: 0; border-radius: 50%;
  cursor: pointer;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.share__link:hover { color: var(--accent); background: var(--accent-soft); }

.share__icon { width: 1rem; height: 1rem; fill: currentColor; }

/* The copy button confirms in place. Without a visible change the click reads
   as a dead control, since nothing else on screen moves. */
.share.is-copied .share__link--copy { color: var(--accent); }

@media (max-width: 30rem) {
  .share { gap: .6rem; }
  .share__label { width: 100%; }
}

/* A 32px control is comfortable under a mouse and mean under a thumb. On a
   touch device the hit area grows to 44px without the mark growing with it, so
   the row looks identical and stops being a game of accuracy. */
@media (pointer: coarse) {
  .share__link { width: 44px; height: 44px; }
  .share__list { gap: .1rem; }

  /* The field and its button came out 37px tall on a phone — under a thumb
     that is a miss waiting to happen, and this is the one action on the page
     we are actually asking for. */
  .subscribe__input,
  .subscribe__btn { min-height: 44px; }
}

/* --------------------------------------------------------------------------
   Email capture.

   Sits on the sunk tone rather than behind a border, so it reads as a different
   kind of object from the essay above it without drawing a box around itself.
   It is deliberately the plainest thing on the page: the writing has just ended
   and this is an offer, not an interruption.
   -------------------------------------------------------------------------- */

.subscribe {
  margin: 4rem auto 0;
  max-width: var(--measure);
  padding: 1.8rem 1.6rem 1.5rem;
  background: var(--sunk);
  border-radius: 4px;
}

.subscribe__title {
  margin: 0;
  font-family: var(--body); font-weight: 600;
  font-size: 1.18rem; line-height: 1.3;
  letter-spacing: -.01em;
}

.subscribe__note {
  margin: .5rem 0 0;
  font-size: .92rem; line-height: 1.5;
  color: var(--ink-2);
  text-wrap: pretty;
}

.subscribe__row {
  display: flex; gap: .5rem; margin-top: 1.1rem;
}

/* The border is --field-line, not the --hair-strong used elsewhere. A hairline
   between two blocks is decoration and may be faint; the edge of a text field
   is what tells you where to type, which makes it a user interface component
   under WCAG 1.4.11 and puts a floor of 3:1 under it. Measured on the running
   page, --hair-strong came to 1.32:1 in light and 1.50:1 in dark. */
.subscribe__input {
  flex: 1 1 auto; min-width: 0;
  padding: .62rem .8rem;
  font-family: var(--body); font-size: 1rem;
  color: var(--ink);
  background: var(--raised);
  border: 1px solid var(--field-line);
  border-radius: 3px;
}
.subscribe__input[aria-invalid="true"] { border-color: var(--error-line); border-width: 2px; }
.subscribe__input::placeholder { color: var(--ink-3); }
.subscribe__input:focus-visible { border-color: var(--accent); }

.subscribe__btn {
  flex: none;
  padding: .62rem 1.1rem;
  font-family: var(--meta); font-size: .74rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--paper); background: var(--ink);
  border: 1px solid var(--ink); border-radius: 3px;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.subscribe__btn:hover { background: var(--accent); border-color: var(--accent); }

/* The honeypot. Moved out of the viewport rather than display:none, because a
   robot that reads the stylesheet skips a hidden field but fills a visible one. */
.subscribe__hp {
  position: absolute !important;
  left: -9999px; width: 1px; height: 1px; overflow: hidden;
}

.subscribe__status:empty { display: none; }
.subscribe__status {
  margin: .8rem 0 0;
  font-family: var(--meta); font-size: .74rem;
  letter-spacing: .04em;
  color: var(--ink-2);
}

@media (max-width: 30rem) {
  .subscribe__row { flex-wrap: wrap; }
  .subscribe__btn { width: 100%; }
}

/* Three entries on a related topic. Set as a short list rather than as cards:
   the archive already reads as a list, and a grid of thumbnails here would
   compete with the writing directly above it. */
.read-next { margin: 4rem auto 0; max-width: var(--measure); }

.read-next__title {
  display: flex; align-items: center; gap: 1rem;
  margin: 0 0 1.2rem;
  font-family: var(--meta); font-weight: 400;
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3);
}
.read-next__title::after {
  content: ""; flex: 1; height: 1px; background: var(--hair);
}

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

.read-next__item {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: 0 1.2rem; align-items: baseline;
  padding: .7rem 0;
  border-bottom: 1px solid var(--hair);
}
.read-next__item:last-child { border-bottom: 0; }

.read-next__meta {
  font-family: var(--meta);
  font-size: .66rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

.read-next__link {
  font-size: 1.05rem; line-height: 1.3;
  color: var(--ink); text-decoration: none;
}
.read-next__link:hover { color: var(--accent); }

/* On a narrow screen the date drops above the title rather than squeezing the
   title into a column too narrow to read. */
@media (max-width: 34rem) {
  .read-next__item { grid-template-columns: 1fr; gap: .2rem; }
  .crumbs { margin-bottom: -0.6rem; }
  .crumbs__here { max-width: 20ch; }
}
