/* =========================================================================
   richian — articles.css
   The articles index, the article page, and the style specimen. Everything
   shared — tokens, reset, .btn, the nav, the footer, the reveal system — is
   in site.css, which loads first.

   Both pages open the same way the contact page does: a dark full-bleed band
   carrying the copy, then cream. The band's top padding clears the nav, which
   cancels its own height and therefore takes no layout space.

   NOTE ON PATHS: pages under /articles/ are the first on this site not at the
   root, so every asset reference in their markup is root-relative (/css/…,
   /images/…). This sheet only ever references images by way of the markup, so
   there is nothing path-dependent in here.

   THE 1140 CONTENT CAP. Four horizontal paddings carry it — the two bands,
   the card grid and .article-main — all on var(--page-pad, …) with the
   fallback, as everywhere else. Two things that look like they should have
   been a problem and measurably are not, recorded so nobody re-derives them:

   - The DRAGON does not move. .articles-hero__art is position: absolute with
     width: min(64%, 920px), so its percentage resolves against the section's
     PADDING box — the full viewport — not the content box. Changing the
     section's padding cannot touch it. Same for .article-hero__art, which is
     inset: 0 / width: 100%.
   - The ARTICLE BODY does not move either. It is max-width: 68ch with
     margin-inline: auto, so it centres inside a column that is itself centred
     in the viewport: 794px lands on the same pixel whether the column around
     it is 1672 or 1140. Its 134% bleeds come to 1063, which still fits inside
     1140 with ~38px each side, so they don't clip. Verified at 1920.

   What the cap DOES move here, and the thing to re-check if these headlines
   are ever reworded: the two hero copy wrappers are percentages of the
   CONTENT box — min(58%, 700px) on the index, min(62%, 780px) on an article —
   so above ~1377px they narrow with the column (700 → 661, 780 → 707 at
   1920). That is intended, they should follow the column; but the index
   headline's first sentence has to stay on one line, which is the whole
   reason it is capped at 52px rather than the .section-title scale.
   ========================================================================= */

/* The dragon artwork's field is a flat #1b1811, sampled with getImageData
   rather than guessed — three levels off --seq-bg's #181710, which is enough
   to show as a faint vertical seam where the art stops on a phone. The band
   paints this instead so the image and the band are the same colour and the
   join is invisible. Scoped to the band, exactly as --seq-fill is scoped per
   sequence on the home page: it is the artwork's colour, not the site's.
   Re-sample if dragon-bg.jpg is ever replaced. */
.articles-hero { --band-dark: #1b1811; }

/* =========================================================================
   INDEX — the dark band
   ========================================================================= */
.articles-hero {
  position: relative;
  z-index: 1;
  overflow: hidden;                     /* the art bleeds off the right */
  background: var(--band-dark);
  color: var(--seq-body);
  padding:
    calc(var(--nav-h) + var(--nav-inset) + clamp(52px, 9vh, 108px))
    var(--page-pad, clamp(22px, 8.6vw, 124px))
    clamp(64px, 10vh, 120px);
  /* The artwork is 2880 × 1292, i.e. 2× a 1440 × 646 band, which is the
     height the mockup draws. min-height rather than a fixed height so long
     copy or a large clamp can still push it taller. */
  min-height: clamp(380px, 45vw, 646px);
  display: flex;
  align-items: center;
}

/* An <img> rather than a background-image, for the same reason the social
   icons are <img>: this section is rasterised by html-to-image for the nav's
   glass, and an inline <img> serialises reliably. Decorative, so alt="" and
   aria-hidden — the headline carries the meaning.

   `cover`, so the artwork fills the band's HEIGHT — it used to be `contain`,
   which letterboxed it to 413px inside a 646px band and made the dragon read
   as smaller than the section it sits in.
   Cover is safe here, and the reason is worth keeping because the obvious
   worry about it is real elsewhere: cover crops on whichever axis overflows,
   and the horns touch row 0 of the file, so a box WIDER than the image's 2.229
   aspect would shave their tips. This box can never be. Its width and the
   band's height are both viewport-linear over the same range — 64% against
   45vw — so the box aspect is a near-constant 1.42, and below 844px the height
   clamps at 380 while the width keeps shrinking, which only makes it narrower
   still. Height therefore always governs the scale, the full 1292px of source
   maps to exactly the band's height, and there is no vertical crop at all.
   The crop is horizontal instead, off the LEFT, where the file is flat field
   (measured: perfectly uniform, sd 0, out to x 1592 where the dragon starts).
   So nothing of the dragon is ever lost, and the crop is invisible.
   The one thing to keep true: the box must stay at least as wide as the band
   is tall, or the crop reaches past x 1592 and starts eating the snout. The
   margin is comfortable — 920 against 646 at 1920, 819 against 576 at 1280. */
.articles-hero__art {
  position: absolute;
  /* Still anchored to the BROWSER edge, not the content column, and that is a
     decision rather than an oversight. The dragon runs to the file's final
     column (x 2879 carries real content, measured — it is not field), so the
     artwork is composed to bleed off the right. Ending it at the column edge
     would cut its neck on a hard vertical line with 390px of flat band colour
     beyond it at 1920: a cut at the screen edge reads as a bleed, the same cut
     inside the screen reads as a mistake. Backgrounds bleed, content caps —
     which is the site-wide rule anyway. */
  inset: 0 0 0 auto;
  /* Width no longer sets the dragon's SIZE — cover ties that to the band's
     height — it only decides how much flat field is clipped off the left.
     Kept at 64% so the box still starts clear of the copy. */
  width: min(64%, 920px);
  height: 100%;
  object-fit: cover;
  object-position: right center;
  pointer-events: none;
  user-select: none;
}

/* Mobile only — see the 860px block, where the artwork goes full bleed and
   ends up directly behind the copy. On desktop the dragon is confined to the
   right of the band and the copy sits on flat field, so a scrim there would
   only mute the artwork for nothing. It is display: none rather than
   opacity: 0 so it costs no paint at all above the breakpoint. */
.articles-hero__scrim { display: none; }

.articles-hero__inner {
  position: relative;                   /* above the art and the scrim */
  z-index: 1;
  /* NOT ch. The wrapper inherits the 16px sans, so a ch-based cap here
     measures against that and not against the 62px serif inside it — 34ch
     came out at 343px, wrapped the headline to six lines and pushed the band
     from 646px to 810px, which then made the artwork zoom. Percentages of the
     band are what this actually wants. */
  max-width: min(58%, 700px);
}

/* --ink-mute would disappear on the dark; --mute-dark is the same job there. */
.articles-hero .eyebrow { color: var(--mute-dark); }

/* Its own scale rather than .section-title's, matching .contact-hero__title:
   this is the page's H1 and the only headline on it. The em treatment is
   shared, over in site.css. */
/* Capped at 52px rather than the .section-title scale. The headline is two
   whole sentences and the break between them is explicit, so the first one has
   to fit on one line — at 62px it wrapped and left "work." orphaned on a line
   of its own, which reads as a mistake rather than a break. */
.articles-hero__title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(31px, 3.7vw, 52px);
  line-height: 1.06;
  letter-spacing: -.006em;
  color: var(--seq-cream);
  margin: 0 0 clamp(20px, 2.8vh, 32px);
}
/* Explicit break so the two sentences land as two blocks — the terracotta is
   the whole second sentence, and letting it wrap naturally would start the
   colour mid-line. Dropped under 860px, as .close__title's and
   .contact-hero__title's are: on a phone there is no room to hold the break
   and the sentences fall where they fall. NB the space before the <br> in the
   markup, or the words render as "work.This". */
@media (max-width: 860px) { .articles-hero__title br { display: none; } }

.articles-hero__lede {
  font-family: var(--sans);
  font-size: clamp(14.5px, 1.15vw, 17px);
  line-height: 1.62;
  color: var(--seq-body);
  margin: 0;
  max-width: 54ch;                      /* two lines, as the mockup has it */
}

/* =========================================================================
   INDEX — the list
   Cream, against the dark band above it: the same hard tonal break .steps
   makes under the sequence on the home page.
   ========================================================================= */
.articles-list {
  position: relative;
  z-index: 1;
  background: var(--cream-bg);
  color: var(--ink);
  padding: clamp(56px, 9vh, 108px) var(--page-pad, clamp(22px, 8.6vw, 124px)) clamp(72px, 12vh, 140px);
}

/* One grid holds the featured card and all the others, so a short final row
   simply ends rather than needing its own rule. The featured card spans every
   column; the rest take one each and fill left to right. Add a card and there
   is nothing to recalculate. */
.articles-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(34px, 4vw, 58px) clamp(22px, 2.6vw, 38px);
  align-items: start;
}

/* ---- A card ------------------------------------------------------------- */
/* Rules separate rows here, they never enclose — the same language .work and
   .steps are built on, which is why there is no border, no fill and no radius
   on a card.

   One link per card, on the title, stretched over the whole card by the
   pseudo-element below. That way the entire card is clickable but there is
   only ONE tab stop and one thing for a screen reader to announce; a second
   link around the image would double both for no gain. */
.card {
  position: relative;
  display: block;
  border-top: 1px solid var(--rule);
  padding-top: clamp(18px, 2.2vh, 26px);
}
.card__title a {
  color: inherit;
  text-decoration: none;
}
.card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
}
/* Keep the focus ring on the card rather than on the stretched box, which has
   no visible bounds of its own. */
.card:focus-within { outline: 2px solid var(--brand); outline-offset: 6px; }
.card__title a:focus-visible { outline: none; }

.card__media {
  display: block;
  width: 100%;
  aspect-ratio: 0.9;                    /* the grid card's shape */
  overflow: hidden;
  background: var(--band-dark, #1b1811);
  margin-bottom: clamp(16px, 2.2vh, 24px);
}
/* One image per article and it can be any shape — a wide still or a tall
   poster — so every slot crops with object-fit and each article aims its own
   crop with --focus. That is the same lever focusX is for the unicorn
   sequence, and it exists because a 4:1 hero and a 0.9:1 card cannot both
   show the whole of one image. Default is dead centre. */
.card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focus, 50% 50%);
  transition: transform .5s cubic-bezier(.22,.7,.3,1);
}
.card:hover .card__media img,
.card:focus-visible .card__media img { transform: scale(1.035); }

.card__title {
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(21px, 1.75vw, 25px);
  line-height: 1.18;
  color: var(--brand);
  margin: 0 0 clamp(10px, 1.4vh, 15px);
  transition: color .25s ease;
}
.card:hover .card__title,
.card:focus-visible .card__title { color: #b03a18; }

/* Justified, as drawn — with hyphens: auto, which is what stops a 40-character
   column stretching its word spaces into rivers. lang="en" is on <html>, and
   without it the browser has no dictionary and silently does nothing. */
.card__excerpt {
  font-family: var(--sans);
  font-size: clamp(13.5px, 1.05vw, 15px);
  line-height: 1.62;
  color: var(--ink-body);
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
  margin: 0 0 clamp(16px, 2.2vh, 24px);
}

/* Date left, author right, on one baseline. */
.card__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  font-family: var(--sans);
  font-size: clamp(10.5px, .85vw, 12px);
  letter-spacing: .11em;
  text-transform: uppercase;
}
.card__date   { color: var(--ink-mute); }
.card__author { color: var(--ink); font-weight: 600; text-align: right; }

/* ---- The featured card -------------------------------------------------- */
/* Spans the grid and turns side-on: image left, copy right. It is promoted by
   scale and position alone — no container, no fill, no outline. Three of those
   were tried and rejected on .work's flagship row for the same reason: the
   container itself fights a layout whose rules separate and never enclose. */
.card--featured {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
  column-gap: clamp(26px, 3.4vw, 54px);
  align-items: start;
}
.card--featured .card__media {
  aspect-ratio: 1.9;                    /* the wide shape the mockup draws */
  margin-bottom: 0;
}
.card--featured .card__body { max-width: 46ch; }
.card--featured .card__title { font-size: clamp(23px, 2.1vw, 30px); }

/* =========================================================================
   ARTICLE — the dark hero
   Same band as the index, but carrying the piece's own image behind a scrim.
   ========================================================================= */
.article-hero {
  --band-dark: #1b1811;
  position: relative;
  z-index: 1;
  overflow: hidden;
  background: var(--band-dark);
  color: var(--seq-body);
  padding:
    calc(var(--nav-h) + var(--nav-inset) + clamp(52px, 9vh, 108px))
    var(--page-pad, clamp(22px, 8.6vw, 124px))
    clamp(48px, 7vh, 84px);
  min-height: clamp(380px, 45vw, 646px);
  display: flex;
  align-items: flex-end;                /* copy sits low in the band */
}
.article-hero__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focus, 50% 50%);
  pointer-events: none;
  user-select: none;
}
/* A legibility fix, not a mood one — the same job .seq__scrim--top does over
   SF/TO's sunset. The article image is arbitrary and may be bright anywhere,
   so this is unconditional rather than tuned per piece: dark at the bottom
   and along the left, where the copy is, clearing towards the top right. */
.article-hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to top,   rgba(27,24,17,.94) 0%, rgba(27,24,17,.74) 34%, rgba(27,24,17,.28) 68%, rgba(27,24,17,.12) 100%),
    linear-gradient(to right, rgba(27,24,17,.80) 0%, rgba(27,24,17,.34) 46%, rgba(27,24,17,0) 78%);
}
/* Same trap as the index's: a ch cap here measures against the inherited
   16px sans, not the 58px serif inside it. Percentages of the band. */
.article-hero__inner {
  position: relative;
  z-index: 1;
  max-width: min(62%, 780px);
}
.article-hero__meta {
  font-family: var(--sans);
  font-size: clamp(11px, .9vw, 12.5px);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--mute-dark);
  margin: 0 0 clamp(16px, 2.2vh, 26px);
}
.article-hero__title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(32px, 4.1vw, 58px);
  line-height: 1.06;
  letter-spacing: -.006em;
  color: var(--seq-cream);
  margin: 0 0 clamp(18px, 2.4vh, 28px);
}
.article-hero__deck {
  font-family: var(--sans);
  font-size: clamp(14px, 1.1vw, 16.5px);
  line-height: 1.6;
  color: var(--seq-body);
  margin: 0;
  max-width: 60ch;
}

/* =========================================================================
   ARTICLE — the reading column
   ========================================================================= */
/* The font-size and the three bleed values live HERE, on the shared parent,
   rather than on .article-body — and both of those matter.

   The font-size, because the measure is stated in `ch` and `ch` resolves
   against whatever font the element itself has. The author block is a SIBLING
   of .article-body, so with the size set on the body it was measuring 68ch of
   the 16px default (920px) while the body measured 68ch of 18.5px (794px),
   and the author's top rule missed the edge of every figure above it.

   The bleed values, because the mobile breakpoint switches them off and a
   custom property only inherits DOWNWARD. Set on .article-body they never
   reached the author block or anything else outside it. */
.article-main {
  position: relative;
  z-index: 1;
  background: var(--cream-bg);
  color: var(--ink);
  padding: clamp(52px, 8vh, 96px) var(--page-pad, clamp(22px, 8.6vw, 124px)) clamp(64px, 10vh, 120px);
  font-size: clamp(16px, 1.3vw, 18.5px);
  --measure: 68ch;
  --bleed-w: 134%;
  --bleed-x: -17%;
  --bleed-f: 1.34;
}

/* ~68 characters, which is the measure the mockup sets and the range running
   text is comfortable at. Stated in ch rather than px deliberately: the line
   length then holds at every step of the font-size clamp instead of drifting
   with the viewport. */
.article-body {
  max-width: var(--measure);
  margin-inline: auto;
  font-family: var(--sans);
  font-size: inherit;                   /* from .article-main — see above */
  line-height: 1.72;
  color: var(--ink-body);
}
.article-body > * { margin-inline: auto; }
.article-body p { margin: 0 0 1.5em; }
.article-body > :first-child { margin-top: 0; }
.article-body > :last-child { margin-bottom: 0; }

/* ---- Headings ----------------------------------------------------------- */
/* Serif, like every other headline on the site. H2 opens a part of the piece,
   H3 is a beat inside one — so H3 drops to the sans, which keeps the two from
   competing at similar sizes. */
.article-body h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(25px, 2.3vw, 33px);
  line-height: 1.14;
  letter-spacing: -.004em;
  color: var(--ink);
  margin: 2.1em 0 .62em;
}
.article-body h3 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: clamp(16.5px, 1.32vw, 19px);
  line-height: 1.35;
  color: var(--ink);
  margin: 2em 0 .55em;
}
.article-body h2 + h3 { margin-top: 1.1em; }

/* ---- Inline ------------------------------------------------------------- */
.article-body a {
  color: var(--brand);
  text-decoration: none;
  border-bottom: 1px solid rgba(200,68,30,.35);
  transition: border-color .25s ease, color .25s ease;
}
.article-body a:hover { border-bottom-color: var(--brand); color: #b03a18; }
.article-body strong { font-weight: 600; color: var(--ink); }
.article-body em { font-style: italic; }
.article-body small { font-size: .84em; color: var(--ink-mute); }

/* ---- Lists -------------------------------------------------------------- */
/* Markers in terracotta, which is the one place the brand colour appears in
   running text. The list sits at the text measure, not indented past it. */
.article-body ul,
.article-body ol {
  margin: 0 0 1.5em;
  padding-left: 1.35em;
}
.article-body li { margin-bottom: .55em; }
.article-body li::marker { color: var(--brand); }
.article-body ol { list-style: decimal; }
.article-body ul { list-style: disc; }
.article-body li > ul,
.article-body li > ol { margin: .55em 0 0; }

/* ---- Blockquote --------------------------------------------------------- */
/* A quotation from a source: at the measure, marked by a terracotta rule down
   its left edge. Distinct from the pull quote below, which is the author's own
   line set large — two different jobs that are easy to conflate. */
.article-body blockquote {
  margin: 2em 0;
  padding: .15em 0 .15em clamp(18px, 2vw, 28px);
  border-left: 2px solid var(--brand);
  font-size: 1.02em;
  line-height: 1.66;
  color: var(--ink-body);
}
.article-body blockquote p:last-child { margin-bottom: 0; }
.article-body blockquote cite {
  display: block;
  margin-top: .9em;
  font-style: normal;
  font-size: .82em;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* ---- Pull quote --------------------------------------------------------- */
/* Serif, large, and allowed past the measure like the images are — it is a
   pause in the reading rather than part of it. No quote marks: the scale is
   what marks it, and glyphs at this size read as decoration. */
.article-body .pullquote {
  width: var(--bleed-w, 134%);
  margin: 2.4em 0 2.4em var(--bleed-x, -17%);
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(24px, 2.4vw, 34px);
  line-height: 1.2;
  letter-spacing: -.004em;
  color: var(--ink);
  text-align: center;
}
.article-body .pullquote em { font-style: normal; color: var(--brand); }

/* ---- Figures ------------------------------------------------------------ */
/* Images break out wider than the text, as the mockup draws them — the one
   thing on the page allowed past the measure, which is what gives the column
   its rhythm. Both numbers come from one pair of custom properties so the
   pull quote and the section rule stay in step with it. */
.article-body figure {
  width: var(--bleed-w, 134%);
  margin: 2.4em 0 2.4em var(--bleed-x, -17%);
}
.article-body figure img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--band-dark, #1b1811);
}
/* An inset figure stays at the text measure — for a portrait image, or a
   screenshot that would be absurd at full bleed. */
.article-body figure.figure--inset { width: 100%; margin-inline: 0; }
.article-body figcaption {
  font-family: var(--sans);
  font-size: .78em;
  line-height: 1.5;
  color: var(--ink-mute);
  margin-top: .85em;
  text-align: left;
}

/* ---- Callout ------------------------------------------------------------ */
/* The one boxed element, and it is boxed on purpose: an aside has to read as
   lifted out of the flow, which a rule alone cannot do. Sand-tinted rather
   than outlined, so it is still a tonal shift rather than a container. */
.article-body .callout {
  margin: 2em 0;
  padding: clamp(20px, 2.4vw, 30px);
  background: var(--cream-panel);
  border-left: 2px solid var(--brand);
  font-size: .96em;
}
.article-body .callout > :last-child { margin-bottom: 0; }
.article-body .callout__head {
  font-family: var(--sans);
  font-weight: 600;
  font-size: .8em;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--brand);
  margin: 0 0 .7em;
}

/* ---- Table -------------------------------------------------------------- */
/* Allowed the same break-out as a figure, and scrolls inside its own box
   rather than pushing the page sideways. Rules separate rows; nothing is
   enclosed, which is the same call .work's grid makes. */
.article-body .table-wrap {
  width: var(--bleed-w, 134%);
  margin: 2.2em 0 2.2em var(--bleed-x, -17%);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.article-body table {
  width: 100%;
  border-collapse: collapse;
  font-size: .9em;
  line-height: 1.5;
}
.article-body th,
.article-body td {
  text-align: left;
  vertical-align: top;
  padding: .78em 1.1em .78em 0;
  border-bottom: 1px solid var(--rule);
}
.article-body th {
  font-family: var(--sans);
  font-weight: 600;
  font-size: .82em;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.article-body tbody tr:last-child td { border-bottom: 0; }

/* ---- Code --------------------------------------------------------------- */
/* Dark, because a cream code block on a cream page has no edge and reads as
   badly-spaced prose. The site ships no mono webfont, so this is the system
   stack deliberately rather than by omission. */
.article-body code,
.article-body pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}
.article-body :not(pre) > code {
  font-size: .87em;
  padding: .14em .4em;
  border-radius: 4px;
  background: rgba(27,24,19,.07);
  color: var(--ink);
}
.article-body pre {
  width: var(--bleed-w, 134%);
  margin: 2em 0 2em var(--bleed-x, -17%);
  padding: clamp(18px, 2.2vw, 26px);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--seq-bg);
  color: var(--seq-body);
  font-size: .82em;
  line-height: 1.66;
}
.article-body pre code { padding: 0; background: none; color: inherit; font-size: 1em; }

/* ---- Section rule ------------------------------------------------------- */
/* A break between parts of a piece. Deliberately not a full-width line: a
   short centred rule reads as a pause, where an edge-to-edge one reads as the
   end of the article. NB this is a real <hr>, not [data-rule] — that attribute
   is a global hidden state and nothing here would ever reveal it. */
.article-body hr {
  width: 84px;
  height: 1px;
  border: 0;
  background: var(--rule);
  margin: 2.8em auto;
}

/* ---- Footnotes ---------------------------------------------------------- */
.article-body .fn-ref {
  font-size: .72em;
  vertical-align: super;
  line-height: 0;
  border-bottom: 0;
  padding-left: .12em;
}
.article-body .footnotes {
  margin-top: 3em;
  padding-top: 1.6em;
  border-top: 1px solid var(--rule);
  font-size: .86em;
  line-height: 1.6;
  color: var(--ink-mute);
}
.article-body .footnotes ol { padding-left: 1.2em; }
.article-body .footnotes li { margin-bottom: .7em; }
.article-body .footnotes li::marker { color: var(--ink-mute); }

/* =========================================================================
   ARTICLE — the closing CTA and the author
   ========================================================================= */
/* Centred, and it goes full width on a phone like every other CTA on the site
   (.steps, .work, .close all do). */
.article-more {
  display: flex;
  justify-content: center;
  margin-top: clamp(40px, 6vh, 68px);
}

/* Sits on the TEXT MEASURE, so it shares its left and right edge with every
   paragraph above it and its top rule spans exactly the column you have been
   reading. It used to sit at the figures' width instead — measure × --bleed-f,
   1063px against the body's 794 — on the reasoning that its rule should line up
   with the images rather than the text. In practice that read as the block
   being left-shifted out of the article: it is centred either way, but at the
   wider width its left edge starts 135px before the body's at 1440, and the
   eye reads that as a broken margin rather than as alignment with a figure that
   may be thousands of pixels further up. Changed at the author's request.
   This also makes desktop agree with mobile, where --bleed-f is already 1 and
   the block has always sat on the measure.
   Deliberately static — no [data-reveal] anywhere in here. It is the last
   thing before the footer, thousands of pixels below the one trigger this
   page has, so an entrance would fire long before anyone reached it. Same
   call the footer makes, and for the same reason. */
.article-author {
  max-width: var(--measure);
  margin: clamp(44px, 6vh, 72px) auto 0;
  padding-top: clamp(30px, 4vh, 46px);
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(20px, 2.4vw, 32px);
  align-items: start;
}
.article-author__photo {
  width: clamp(64px, 7vw, 92px);
  aspect-ratio: 1;
  border-radius: 50%;                   /* load-bearing: the mugs are square
                                           files with white corners */
  overflow: hidden;
}
.article-author__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.article-author__name {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.6vw, 22px);
  flex-wrap: wrap;
  margin: 0 0 .5em;
  font-family: var(--serif);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(24px, 2.2vw, 31px);
  line-height: 1.1;
  color: var(--ink);                    /* on cream, unlike .person__name */
}
.article-author__name em { font-style: inherit; color: var(--brand); }

/* The icon SVGs carry a baked-in cream fill for the dark .people section, so
   they would all but vanish here. These are the ink variants of the same three
   files. Still <img> rather than CSS-masked, for the reason recorded on
   .person__social: this section is rasterised for the nav's glass, and an
   <img> inlines reliably where an external mask-image is a coin toss. */
.article-author__social {
  display: flex;
  gap: 14px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.article-author__social a {
  display: block;
  opacity: .7;
  transition: opacity .25s ease;
}
.article-author__social a:hover,
.article-author__social a:focus-visible { opacity: 1; }
.article-author__social img { display: block; width: 21px; height: 21px; }

.article-author__bio {
  font-family: var(--sans);
  font-size: clamp(14px, 1.1vw, 16px);
  line-height: 1.6;
  color: var(--ink-body);
  margin: 0;
  max-width: 54ch;
}

/* =========================================================================
   SPECIMEN
   The style reference at /articles/_specimen/. It is noindex'd and absent
   from sitemap.xml, but it is a normal page otherwise — it reuses
   .article-body wholesale, which is the point: what you see here is exactly
   what an article gets, because it is the same CSS and not a copy of it.
   ========================================================================= */
/* The box keeps the inherited font-size so its `ch` matches the body's and the
   two line up; the smaller type is set on the paragraphs inside it instead. */
.spec-note {
  max-width: var(--measure);
  margin: 0 auto clamp(30px, 4vh, 48px);
  padding: clamp(18px, 2.2vw, 26px);
  background: var(--cream-panel);
  border-left: 2px solid var(--brand);
  font-family: var(--sans);
  line-height: 1.6;
  color: var(--ink-body);
}
.spec-note p { margin: 0 0 .8em; font-size: clamp(13.5px, 1.05vw, 15px); }
.spec-note p:last-child { margin-bottom: 0; }
.spec-note code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .88em;
  padding: .12em .38em;
  border-radius: 4px;
  background: rgba(27,24,19,.07);
  color: var(--ink);
}
/* Labels the specimen's own sections. Not part of the article styles — an
   article never carries one. */
.article-body .spec-label {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand);
  margin: 3.2em 0 1.1em;
  padding-bottom: .6em;
  border-bottom: 1px solid var(--rule);
}
.article-body .spec-label:first-child { margin-top: 0; }

/* =========================================================================
   BREAKPOINTS
   ========================================================================= */

/* Two columns before one: three cards at tablet width leaves each too narrow
   to justify cleanly, which is the width the hyphenation is already working
   hardest at. */
@media (max-width: 1080px) {
  .articles-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  /* The featured card drops its side-on layout and becomes an ordinary card,
     as the mobile mockup draws it — one uniform column, nothing promoted.
     A wide image beside a 30-character text column is unreadable, and the
     composition has nothing to lead at this width anyway. */
  .articles-grid { grid-template-columns: minmax(0, 1fr); }
  .card--featured {
    grid-column: auto;
    display: block;
  }
  .card--featured .card__media {
    aspect-ratio: 0.9;                  /* same shape as every other card */
    margin-bottom: clamp(16px, 2.2vh, 24px);
  }
  .card--featured .card__body { max-width: none; }
  .card--featured .card__title { font-size: clamp(21px, 1.75vw, 25px); }

  /* The dragon goes FULL BLEED here and sits behind the copy, with a scrim
     over it doing the legibility work. It used to be confined to a box in the
     bottom-right corner, on the reasoning that cover against a near-square
     band scales the head up until it fills the width and the copy sits on top
     of it — which is true, and is exactly what happens now. The scrim is what
     changed: at 90% the artwork is a texture rather than a subject, so the
     head filling the band is the point instead of the problem. */
  .articles-hero {
    display: block;
    min-height: 0;
  }
  .articles-hero__art {
    inset: 0;
    width: 100%;
    height: 100%;
    /* Cover here too, but for a different reason than on desktop, and the
       desktop rule's safety argument does NOT carry over — this box is the
       whole band, which on a phone is portrait-ish (roughly 0.8) against the
       image's 2.229, so height governs by a wide margin and the horizontal
       crop is severe. That is fine at 10% visibility, but it does mean the
       snout is cropped away: 70% keeps the head, which is the only feature
       that still reads through the scrim.
       `top`, not `center`, and that is the horns again. The band is portrait
       on a phone so height governs and there is no vertical crop at all — but
       at the top of this range it is not: at exactly 860 × 374 the band is
       2.30, WIDER than the image's 2.229, so width governs and ~12px overflows
       vertically. Centred that would shave the horn tips, which touch row 0 of
       the file. Anchored to the top it all comes off the bottom, which is
       lower neck and costs nothing. Invisible at 90% either way — but it stops
       being invisible the moment anyone lowers the scrim. */
    object-fit: cover;
    object-position: 70% top;
  }
  /* The legibility layer. Flat rather than a gradient, because the copy runs
     the full height of the band here — a bottom-anchored gradient like the
     article page's would leave the eyebrow and the first headline line sitting
     on open artwork.
     90% is the author's number. Note it is pure black, not --band-dark, so the
     band reads a little cooler and darker on a phone than the same band does on
     desktop; if that ever looks like two different colours, this is the one
     value to change. At 90% the dragon is a 10% ghost — if it reads as too
     faint to be worth having, that is the same value. */
  .articles-hero__scrim {
    display: block;
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, .6);
    pointer-events: none;
  }
  .articles-hero__inner { max-width: none; }

  /* The article hero's copy takes the full width once there's no room beside
     the image, and the scrim leans harder on the bottom since the text now
     spans it. */
  .article-hero__inner { max-width: none; }
  .article-hero__scrim {
    background: linear-gradient(to top,
      rgba(27,24,17,.95) 0%, rgba(27,24,17,.82) 42%,
      rgba(27,24,17,.42) 74%, rgba(27,24,17,.16) 100%);
  }

  /* Nothing may break out past the measure any more — the column is already
     the full width of the screen, so a 134% figure would overflow the page.
     One set of properties turns all of it off at once: figures, pull quotes,
     tables, code blocks AND the author block's width, which is why they were
     written against these and why they sit on the shared parent. */
  .article-main {
    --bleed-w: 100%;
    --bleed-x: 0;
    --bleed-f: 1;
  }

  /* Portrait above the name, everything centred, as the mobile mockup draws
     it. The bio stays left-aligned — centred running text is hard to read
     past a line or two. */
  .article-author {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    text-align: center;
  }
  .article-author__photo { width: 96px; margin-bottom: clamp(16px, 2.2vh, 22px); }
  .article-author__name { justify-content: center; flex-direction: column; gap: 14px; }
  .article-author__bio { text-align: left; }

  .article-more .btn--primary { width: 100%; }
}

/* The card hover lift is motion; the reveal system is cut elsewhere. */
@media (prefers-reduced-motion: reduce) {
  .card__media img { transition: none; }
  .card:hover .card__media img,
  .card:focus-visible .card__media img { transform: none; }
}
