/* ============================================================================
   articles.css — /articles and /articles/<category>/<slug>/.

   Generated pages (tools/build_articles.py); this file is hand-written.

   The article brand layer comes from fetch-marketing/BRAND_SYSTEM.md's
   editorial spec: IBM Plex Serif for headlines, IBM Plex Sans for body, and
   the article palette — navy #0C1A2C, teal #3DE0C4, amber #E8AA34, marine
   blue #4AA3E0. The navy/teal/amber/blue literals live here and only here;
   everything structural (surfaces, text, lines, spacing, radii) rides the
   site's tokens so dark theme works without a second palette.

   Category chips: the raw brand hues fail as small-text grounds on white
   (#3DE0C4 measures 1.6:1), so each chip is a TINT of its hue with dark ink —
   the same reasoning css/tokens.css records for splitting --accent from
   --accent-text.
   ========================================================================== */

:root {
  --art-navy:   #0C1A2C;
  --art-teal:   #3DE0C4;
  --art-amber:  #E8AA34;
  --art-blue:   #4AA3E0;

  --art-serif:  'IBM Plex Serif', Georgia, serif;
  --art-sans:   'IBM Plex Sans', var(--font-sans);

  --art-ground: #F7F9FA;
  --art-measure: 68ch;
}
:root[data-theme='dark'] {
  --art-ground: #091322;
}

/* ── page shell ─────────────────────────────────────────────────────────── */

.article-body {
  min-height: 100dvh;
  background: var(--art-ground);
  font-family: var(--art-sans);
  /* footer.js appends to <body>; the column keeps it under the content */
  display: flex;
  flex-direction: column;
}
.article {
  flex: 1 0 auto;
  width: 100%;
}

/* ── head: chip, title, dek, byline row (no hero on the page) ───────────── */

.article__head {
  width: min(var(--art-measure), calc(100% - 2 * var(--sp-5)));
  margin: 0 auto;
  padding-top: clamp(var(--sp-8), 5vw, var(--sp-12));
}
.article__meta { margin-bottom: var(--sp-4); }

.article__title {
  font-family: var(--art-serif);
  font-weight: 700;
  font-size: clamp(2rem, 5vw, 3rem);     /* ~32px → 48px */
  line-height: 1.12;
  letter-spacing: -0.012em;
}
.article__dek {
  margin-top: var(--sp-4);
  color: var(--text-secondary);
  font-size: clamp(1.15rem, 2.4vw, 1.35rem);   /* ~20–22px desktop */
  font-weight: var(--fw-medium);
  line-height: 1.5;
}
.article__byline {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: clamp(var(--sp-5), 3vw, var(--sp-6));
  padding-block: var(--sp-4);
  border-block: 1px solid var(--line);
}
.article__avatar {
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--art-navy);
  display: flex;
  align-items: center;
  justify-content: center;
}
/* a human author: the headshot fills the circle instead of sitting in it */
.article__avatar--photo {
  background: none;
  overflow: hidden;
}
.article__avatar--photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.article__byline-who { display: flex; flex-direction: column; min-width: 0; }
.article__byline-name {
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-label);
}
.article__byline-date {
  color: var(--text-muted);
  font-size: var(--fs-xs);
}
/* the byline's single outbound link: Fetch on Instagram. Fixed-px round hit
   area so it cannot balloon at any viewport; the glyph matches the byline's
   optical size. Muted at rest, brand teal on hover (--accent-text, the
   accessible teal text role in both themes). */
.article__ig {
  margin-left: auto;
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  border-radius: 50%;
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.article__ig svg { width: 22px; height: 22px; }
.article__ig:hover {
  color: var(--accent-text);
  background: var(--accent-tint);
}

/* ── body ───────────────────────────────────────────────────────────────── */

.article__body {
  width: min(var(--art-measure), calc(100% - 2 * var(--sp-5)));
  margin: 0 auto;
  padding: clamp(var(--sp-6), 4vw, var(--sp-8)) 0 clamp(var(--sp-10), 6vw, var(--sp-16));
  color: var(--text-secondary);
  font-size: 1.0625rem;                  /* 17px mobile */
  line-height: 1.7;
}
@media (min-width: 720px) {
  .article__body { font-size: 1.1875rem; }   /* 19px desktop */
}
/* generous, uniform flow spacing; headings/figures override below */
.article__body > * + * { margin-top: var(--sp-6); }

.article__body h2 {
  font-family: var(--art-serif);
  font-weight: 700;
  font-size: clamp(1.4rem, 3.4vw, 1.8rem);
  line-height: 1.22;
  text-align: center;
  margin: clamp(var(--sp-10), 7vw, var(--sp-16)) 0 var(--sp-5);
}
.article__body h2:first-child { margin-top: 0; }

.article__body h3 {
  font-family: var(--art-serif);
  font-weight: 600;
  font-size: 1.3rem;
  line-height: 1.25;
  text-align: left;
  letter-spacing: 0;
  margin: clamp(var(--sp-8), 5vw, var(--sp-10)) 0 var(--sp-4);
}

/* the ### stat run — a plain bold bullet list, one line per bullet */
.article__stats {
  margin-top: var(--sp-5);
  padding-left: 1.3em;
}
.article__stats li {
  list-style: disc;
  margin-top: var(--sp-2);
}
.article__stats li::marker { color: var(--accent); }

.article__body strong { color: var(--text); }
.article__body a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.article__list {
  margin: var(--sp-5) 0;
  padding-left: 1.2em;
}
.article__list li {
  list-style: disc;
  margin-top: var(--sp-3);
}
ol.article__list li { list-style: decimal; }
.article__list li::marker { color: var(--accent); }

.article__body blockquote {
  margin: var(--sp-6) 0;
  padding: var(--sp-2) var(--sp-5);
  border-left: 3px solid var(--art-teal);
  font-family: var(--art-serif);
  font-size: 1.15em;
  color: var(--text);
}

/* ── pipe tables (`| a | b |` blocks in article.md) ──────────────────────
   A plain bordered table at the reading measure. The wrapper is the only
   thing that may scroll sideways: on a phone the table keeps its natural
   width inside the box instead of squeezing the columns or widening the
   page. Header rule in teal, alternating rows a hair off the ground. */
.article__table-wrap {
  margin: var(--sp-6) 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.article__table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--line);
  font-size: 0.95em;
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
}
.article__table th,
.article__table td {
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
  white-space: nowrap;                   /* the box scrolls; cells don't wrap */
}
.article__table th {
  font-family: var(--art-sans);
  font-weight: 600;
  font-size: var(--fs-sm);
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  background: rgba(12, 26, 44, 0.04);
  border-bottom: 2px solid var(--art-teal);
}
.article__table tbody tr:nth-child(even) td { background: rgba(12, 26, 44, 0.025); }
:root[data-theme='dark'] .article__table th { background: rgba(255, 255, 255, 0.07); }
:root[data-theme='dark'] .article__table tbody tr:nth-child(even) td { background: rgba(255, 255, 255, 0.035); }

/* not a full-width line — a quiet centered glyph row */
.article__rule {
  margin: clamp(var(--sp-10), 6vw, var(--sp-16)) 0;
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  letter-spacing: 0.35em;
  user-select: none;
}

/* ── inline figures: break out of the text column ───────────────────────── */

.article__figure {
  /* ~1.5× the reading column, capped; full-bleed minus a small gutter on
     phones. Centered on the column with margin math, no transforms. */
  --fig-w: min(1100px, 100vw - 2 * var(--sp-4));
  width: var(--fig-w);
  margin: clamp(var(--sp-8), 5vw, var(--sp-12)) 0
          clamp(var(--sp-8), 5vw, var(--sp-12)) calc(50% - var(--fig-w) / 2);
}
.article__figure img,
.article__figure video {
  display: block;
  width: 100%;
  /* natural aspect from the width/height attributes — never a fixed height,
     object-fit, border, radius, or shadow on inline figures */
  height: auto;
}
/* A portrait figure sits at the reading measure instead of breaking out:
   the wide box would upscale a phone photo (900px wide) to 1100 and hand the
   page a full-screen slab. Capped below its own intrinsic width so it never
   enlarges, and centred on the column. */
.article__figure--portrait {
  --fig-w: min(620px, 100vw - 2 * var(--sp-4));
}
/* A near-square landscape figure (4:3 or squarer, tagged by the build)
   sits at the reading column too — the wide box would make it a slab. */
.article__figure--column {
  --fig-w: 100%;
}

.article__figure figcaption {
  max-width: 42rem;                      /* back to the reading column */
  margin: var(--sp-3) auto 0;
  padding: 0 var(--sp-4);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-sm);               /* 15px */
  line-height: 1.5;
}

/* ── category chips ─────────────────────────────────────────────────────── */

.art-chip {
  display: inline-block;
  padding: 3px 12px;
  border-radius: var(--r-pill);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-label);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}
.art-chip--surf    { background: rgba(61, 224, 196, 0.18);  color: #0A5A4C; }
.art-chip--fishing { background: rgba(232, 170, 52, 0.20);  color: #7A5210; }
.art-chip--marine  { background: rgba(74, 163, 224, 0.18);  color: #1F5A85; }
.art-chip--weather { background: rgba(12, 26, 44, 0.10);    color: var(--art-navy); }
:root[data-theme='dark'] .art-chip--surf    { color: var(--art-teal); }
:root[data-theme='dark'] .art-chip--fishing { color: var(--art-amber); }
:root[data-theme='dark'] .art-chip--marine  { color: var(--art-blue); }
:root[data-theme='dark'] .art-chip--weather { background: rgba(255,255,255,0.10); color: var(--text-secondary); }

/* ── produced-by footer (named authors only) ────────────────────────────── */

.article__producer {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-top: clamp(var(--sp-8), 5vw, var(--sp-12));
  padding-top: clamp(var(--sp-6), 4vw, var(--sp-8));
  border-top: 1px solid var(--line);
}
.article__producer-avatar {
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  border-radius: 50%;
  object-fit: cover;
}
.article__producer-eyebrow {
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-label);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}
.article__producer-name {
  margin-top: var(--sp-1);
  font-family: var(--art-serif);
  font-weight: 600;
  font-size: 1.15rem;
  color: var(--text);
}
.article__producer-role {
  margin-top: 2px;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* ── listing rows: index + "More articles" ──────────────────────────────── */

.art-list {
  display: block;
}
.art-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  width: 100%;
  padding: var(--sp-4) var(--sp-2);
  border-radius: var(--r-md);
  transition: background var(--dur-fast) var(--ease);
}
/* separator between rows, not around the list */
.art-row + .art-row { border-top: 1px solid var(--line); }
.art-row:hover,
.art-row:active { background: var(--surface); }
/* a row gaining hover-radius must not double the hairline into the fill */
.art-row:hover + .art-row,
.art-row:active + .art-row { border-top-color: transparent; }

.art-row__thumb {
  width: 72px;
  height: 72px;
  flex: 0 0 auto;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--art-navy);
}
.art-row__text { min-width: 0; }
.art-row__title {
  font-family: var(--art-serif);
  font-weight: 600;
  font-size: 1.15rem;
  line-height: 1.3;
  letter-spacing: 0;
}
.art-row__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
}

@media (max-width: 560px) {
  .art-row__thumb { width: 56px; height: 56px; }
  .art-row__title {
    font-size: 1.05rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

.article__more {
  /* the list reads at the article's own measure, not the site shell's */
  width: min(var(--art-measure), calc(100% - 2 * var(--sp-5)));
  margin: 0 auto;
  padding-bottom: clamp(var(--sp-10), 6vw, var(--sp-16));
}
.article__more-title {
  font-family: var(--art-serif);
  font-weight: 700;
  font-size: 1.5rem;
  margin-bottom: var(--sp-6);
}

/* ── the index page: mode panels, category tabs, sectioned card grids ───── */

/* The brandfield, injected by js/articles.js on the INDEX only — the HOME
   arrangement (Grant's screenshot): the isobars are the PAGE GROUND, running
   behind the title, subtitle, mode selector, tabs, and faintly under the
   section headings; the cards float on it as opaque surfaces the way home's
   forecast cards do. Home's exact radial + fade, ended on the articles
   ground. About's lesson still applies:
   ⚠ THE NAV IS NOT IN ANY RULE HERE. Pulling it into the content's z-index:1
   once flattened its own 60 and put the hover menus BEHIND the page. The nav
   keeps css/nav.css's stacking with no help from this file. */
.articles-index { position: relative; }
.articles-index .brandfield {
  position: absolute;
  inset: 0 0 auto;
  height: min(760px, 90vh);
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(120% 100% at 12% 0%, rgba(61, 224, 196, 0.16), rgba(61, 224, 196, 0) 58%),
    linear-gradient(180deg, var(--bf-top) 0%, var(--art-ground) 88%);
}
.articles-index .brandfield__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.articles-index .article { position: relative; z-index: 1; }

/* Local line knockout, MEASURED (2026-09-05): at the stroke's authored 0.2
   opacity a contour crossing the muted 12px time reads 3.57–3.70:1 against
   its ink (needs 4.5) and the light-mode tabs 3.79:1; a globally passing
   stroke would be 0.04 — no field at all. So the LINE dims behind the text
   only, per Grant's ruling (no card surface): a ground-colored halo knocks
   the stroke to ~0 exactly around glyphs, restoring the clean-ground ratios
   (4.86:1 light / 5.54:1 dark on the muted ink). Large heavy text (titles,
   section headings) measures ≥10.5:1 over the line and needs no halo. */
.articles-index .articles-head__sub,
.articles-index .art-tab,
.articles-index .art-card__dek,
.articles-index .art-card__meta {
  text-shadow: 0 0 1px var(--art-ground), 0 0 3px var(--art-ground),
               0 0 6px var(--art-ground);
}

.articles-head,
.art-mode-panel {
  width: min(var(--maxw), calc(100% - 2 * var(--sp-5)));
  margin: 0 auto;
}
.articles-head {
  padding: clamp(var(--sp-8), 5vw, var(--sp-12)) 0 0;
}
.articles-head__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
/* ⚠ THE INDEX IS SANS, DELIBERATELY (Grant, 2026-09-05): one geometric face,
   heavy and tight — the voice base.css h1-h2, home.css section titles and
   forecast.css's page bar already speak (Inter, --fw-display 800,
   --tracking-tight). The serif stays the ARTICLE PAGES' voice; these
   index-only classes drop their overrides so base.css's heading rules apply
   unfought. */
.articles-head__title {
  font-size: clamp(2rem, 5vw, 2.8rem);   /* Inter 800, tight — from base h1 */
}
/* the segmented pill itself comes from base.css — the home page's control */
.articles-head__sub {
  margin-top: var(--sp-3);
  color: var(--text-secondary);
  font-size: var(--fs-body-lg);
  max-width: 52ch;
}

.art-mode-panel { padding-bottom: clamp(var(--sp-12), 7vw, var(--sp-20)); }

.art-tabs {
  display: flex;
  gap: clamp(var(--sp-4), 3vw, var(--sp-8));
  margin-top: clamp(var(--sp-6), 4vw, var(--sp-8));
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}
.art-tab {
  padding: var(--sp-3) 2px;
  /* inactive tabs carry the accent; the active one earns the ink + underline */
  color: var(--accent-text);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;                    /* the underline sits ON the rule */
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.art-tab:hover { color: var(--text); }
.art-tab.is-active {
  color: var(--text);
  border-bottom-color: var(--accent);
}

.art-section { margin-top: clamp(var(--sp-8), 5vw, var(--sp-10)); }
.art-section__title {
  font-size: 1.25rem;                    /* Inter 800, tight — from base h2 */
  margin-bottom: var(--sp-5);
}

.art-grid3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6) var(--sp-6);
}
@media (min-width: 700px)  { .art-grid3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .art-grid3 { grid-template-columns: repeat(3, 1fr); } }

/* ── index card: image, title, dek, category + relative time ────────────── */

/* ⚠ ONLY THE IMAGE SITS IN A BOX (Grant's call, 2026-09-05): the title, dek
   and metadata stay loose on the page ground with the isobars running behind
   them. The media box is the one opaque rectangle; contrast of a contour
   hairline under the text was MEASURED before accepting this — see the note
   at the brandfield rule above. */
.art-card { display: block; min-width: 0; }
.art-card__media {
  /* square corners, 16:9 — and the image itself is CUT at 16:9 by the build
     (…-card.webp), so this box displays it whole rather than cropping it a
     second time */
  overflow: hidden;
  aspect-ratio: 16 / 9;
  background: var(--surface-sunken);
}
.art-card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur) var(--ease);
}
.art-card:hover .art-card__img { transform: scale(1.02); }
/* no hero: a brandfield-toned block with the category's icon — intentional,
   where a broken image would not be */
.art-card__field {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  background:
    radial-gradient(120% 100% at 12% 0%, rgba(61, 224, 196, 0.16), rgba(61, 224, 196, 0) 60%),
    linear-gradient(180deg, var(--bf-top) 0%, var(--surface) 85%);
}
.art-card__field svg { width: 42px; height: 42px; }
.art-card__title {
  margin-top: var(--sp-4);
  font-weight: 700;                      /* forecast.css card-title weight */
  font-size: 1.08rem;
  line-height: 1.3;
  letter-spacing: -0.015em;
}
.art-card__dek {
  margin-top: var(--sp-2);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.art-card__meta {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-muted);
}
.art-card__cat {
  color: var(--accent-text);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-label);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* ══ web redesign Stage 5b §1 — the Articles index ═════════════════════════
   One newest-first card grid under a category chip row. Cards: 16:9 hero,
   category (accent), title, summary, date · byline. 3 → 2 → 1 columns. */
.articles-page {
  max-width: 1200px; margin: 0 auto; position: relative; z-index: 1;
  padding: calc(var(--nav-h, 68px) + 28px) 24px 64px;
}
@media (max-width: 560px) { .articles-page { padding-inline: 16px; } }
.articles-page .articles-head { margin: 0 0 22px; }
.articles-page .articles-head__title {
  margin: 0; font: 800 clamp(30px, 4vw, 40px)/1.1 var(--font-sans, "Inter", sans-serif);
  letter-spacing: -0.02em; color: var(--text);
}
.articles-page .articles-head__sub { margin: 8px 0 16px; font-size: 16px; color: var(--text-secondary); }
.art-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.art-chipf {
  border: 1px solid var(--line-strong, var(--line)); background: var(--surface-raised, var(--bg)); color: var(--text);
  border-radius: 999px; padding: 7px 14px; cursor: pointer;
  font: 600 13px/1 var(--font-sans, "Inter", sans-serif);
}
.art-chipf:hover { border-color: var(--accent); }
.art-chipf[aria-pressed='true'] { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); }
.art-chipf:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 2px; }
.art-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
@media (max-width: 1000px) { .art-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .art-grid { grid-template-columns: minmax(0, 1fr); } }
.art-grid .art-card[hidden] { display: none; }
.art-grid .art-card, .article__more-grid .art-card {
  display: flex; flex-direction: column; border-radius: 16px; overflow: hidden; text-decoration: none;
  background: var(--surface-raised, var(--bg)); border: 1px solid var(--line); color: var(--text);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.art-grid .art-card:hover, .article__more-grid .art-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.art-grid .art-card:focus-visible, .article__more-grid .art-card:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 2px; }
.art-card .art-card__media { border-radius: 0; }
.art-card__text { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px 16px; }
.art-card__cat { margin: 0; font: 700 11px var(--font-sans, "Inter", sans-serif); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--accent-text); }
.art-card .art-card__title { margin: 0; font: 700 18px/1.3 var(--font-sans, "Inter", sans-serif); color: var(--text); }
.art-card .art-card__dek { margin: 0; font-size: 14px; line-height: 1.5; color: var(--text-secondary);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.art-card .art-card__meta { margin: 4px 0 0; display: flex; flex-wrap: wrap; gap: 6px; font-size: 12px;
  color: var(--text-muted); }
.art-card__by { color: var(--text-secondary); }
.art-empty { margin: 18px 0; color: var(--text-secondary); }

/* ══ web redesign Stage 5b §2 — the article page ═══════════════════════════
   Hero → category · date → title → dek → byline, in a ~700px reading column;
   body typography for headings, lists, quotes, figures (+ captions), tables,
   video and code; "More Articles" as three cards. */
:root { --art-measure: 700px; }
.article__hero {
  width: min(1100px, calc(100% - 2 * var(--sp-5)));
  margin: calc(var(--nav-h, 68px) + 24px) auto 0;
}
.article__hero img {
  display: block; width: 100%; height: auto; max-height: 560px; object-fit: cover;
  border-radius: 18px; background: var(--surface-sunken);
}
.article__hero figcaption {
  width: min(var(--art-measure), 100%); margin: 10px auto 0; font-size: 13px; line-height: 1.5;
  color: var(--text-muted);
}
.article__hero + .article__head { padding-top: clamp(20px, 3vw, 32px); }
.article__kicker {
  margin: 0 0 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font: 600 13px var(--font-sans, "Inter", sans-serif); color: var(--text-muted);
}
.article__cat { font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-text); }
.article__body code {
  font: 0.88em/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  padding: 0.12em 0.36em; border-radius: 6px; background: var(--surface-sunken); color: var(--text);
}
.article__body pre {
  overflow-x: auto; padding: 14px 16px; border-radius: 12px; background: var(--surface-sunken);
  border: 1px solid var(--line); font-size: 0.85em; line-height: 1.5;
}
.article__body pre code { padding: 0; background: none; }
.article__body ul:not([class]), .article__body ol:not([class]) { padding-left: 1.3em; }
.article__body figure video { display: block; width: 100%; height: auto; border-radius: 12px; }
.article__more { width: min(1100px, calc(100% - 2 * var(--sp-5))); }
.article__more-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
@media (max-width: 900px) { .article__more-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .article__more-grid { grid-template-columns: minmax(0, 1fr); } }
