
/* Theme tokens.
   Default (when [data-theme] is unset and inline init hasn't run yet,
   or as a safety net) = dark, matching the React app's default state.
   The inline script in blog-template.mjs sets data-theme synchronously
   before paint, so users normally never see this unset state. */
:root {
  --bg-primary: #0a0f1a;
  --bg-secondary: #131a2a;
  --bg-tertiary: #192236;
  --text-primary: #f8fafc;
  --text-secondary: #cbd5e1;
  --text-muted: #94a3b8;
  --accent: #635ee7;
  --accent-hover: #5048db;
  --accent-tint: rgba(99, 94, 231, 0.18);
  --border-light: rgba(255, 255, 255, 0.08);
  --shadow-soft: 0 4px 24px -8px rgba(0, 0, 0, 0.6);
  /* Shared page container width. Nav, footer, magazine index, and the
     article hero overlay all align to this gutter. 1440px fills 1440p
     and 4K monitors far better than the old 1280 cap (which left the
     content stranded in the middle ~33% of a 4K screen) while staying a
     sane editorial measure. Article *reading* width is capped tighter
     (.article-body) for line-length comfort. */
  --blog-max: 1440px;
}

/* Explicit dark — same tokens, kept as named selector so future devs
   can target dark-only styles without duplicating the :root block. */
:root[data-theme="dark"] {
  --bg-primary: #0a0f1a;
  --bg-secondary: #131a2a;
  --bg-tertiary: #192236;
  --text-primary: #f8fafc;
  --text-secondary: #cbd5e1;
  --text-muted: #94a3b8;
  --accent-tint: rgba(99, 94, 231, 0.18);
  --border-light: rgba(255, 255, 255, 0.08);
  --shadow-soft: 0 4px 24px -8px rgba(0, 0, 0, 0.6);
}

/* Light theme override — fires when user toggles OR when OS pref says
   light AND no saved preference exists (inline init handles that). */
:root[data-theme="light"] {
  --bg-primary: #ebeef9;
  --bg-secondary: #ffffff;
  --bg-tertiary: #f3f5fc;
  --text-primary: #0f172a;
  --text-secondary: #334155;
  --text-muted: #64748b;
  --accent-tint: rgba(99, 94, 231, 0.10);
  --border-light: rgba(0, 0, 0, 0.06);
  --shadow-soft: 0 4px 24px -8px rgba(15, 23, 42, 0.08);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
body {
  font-family: 'Poppins', system-ui, -apple-system, sans-serif;
  background: var(--bg-primary);
  color: var(--text-primary);
  line-height: 1.6;
  font-size: 16px;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* Defense against full-bleed elements (article hero, etc.) that use
     negative margins to escape parent padding. Without this, a hero
     wider than the viewport's content area causes a horizontal scrollbar
     and the image visually "leaks" off the right edge. */
  overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; display: block; }

/* ── Top nav (mirrors LandingNavbar.tsx visual structure) ─────────────── */
.nav {
  position: sticky;
  top: 0;
  z-index: 30;
  background: color-mix(in srgb, var(--bg-primary) 92%, transparent);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border-light);
}
.nav-inner {
  max-width: var(--blog-max, 1440px);
  margin: 0 auto;
  padding: 16px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text-primary);
  flex-shrink: 0;
}
.nav-brand img { width: 32px; height: 32px; max-width: 32px; }
.nav-brand-name {
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -0.01em;
}
.nav-links {
  display: flex;
  gap: 4px;
  align-items: center;
  flex: 1;
  justify-content: center;
}
.nav-link {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-secondary);
  padding: 8px 12px;
  border-radius: 8px;
  transition: color 0.2s, background 0.2s;
}
.nav-link:hover { color: var(--text-primary); background: var(--bg-secondary); }
.nav-link-active { color: var(--text-primary); }
.nav-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}
.nav-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 20px;
  background: linear-gradient(135deg, #635ee7, #8b5cf6);
  color: #ffffff;
  border-radius: 9999px;
  font-size: 14px;
  font-weight: 700;
  box-shadow: 0 4px 20px rgba(99, 94, 231, 0.4);
  transition: transform 0.2s;
}
.nav-cta:hover { transform: translateY(-1px); }
.nav-cta svg { width: 14px; height: 14px; }
@media (max-width: 880px) {
  .nav-links { display: none; }
  .nav-inner { justify-content: space-between; }
}

/* Theme toggle — sits between nav links and the primary CTA. Mirrors the
   structure used in the React app's header so the affordance is in the
   same spot across all pages. */
.theme-toggle {
  width: 34px;
  height: 34px;
  border-radius: 9999px;
  background: transparent;
  border: 1px solid var(--border-light);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--text-secondary);
  transition: color 0.2s, background 0.2s, border-color 0.2s;
  padding: 0;
  font: inherit;
}
.theme-toggle:hover {
  color: var(--accent);
  background: var(--accent-tint);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border-light));
}
.theme-toggle:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--accent);
}
.theme-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
/* Default (dark theme): show moon icon — represents current state.
   Sun icon shows on light theme. The init script sets [data-theme]
   before paint, so the right icon is visible from first render. */
.theme-icon-sun { display: none; }
.theme-icon-moon { display: inline-block; }
:root[data-theme="light"] .theme-icon-sun { display: inline-block; }
:root[data-theme="light"] .theme-icon-moon { display: none; }

/* Mobile: nav links already hidden via .nav-links { display: none } at
   880px breakpoint above. No additional rules needed here. Brand + theme
   toggle + Dashboard CTA remain visible. */

main { flex: 1; padding: 56px 24px 80px; }
@media (max-width: 640px) { main { padding: 32px 16px 60px; } }

/* ── Magazine header ───────────────────────────────────────────────── */
.magazine-header {
  max-width: var(--blog-max, 1440px);
  margin: 0 auto 40px;
}
.eyebrow {
  /* Page label, muted. Not a signal — reserve accent for active states
     and primary CTA per the One Beacon Rule. */
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 14px;
}
.magazine-title {
  /* Page label, not Display. The featured post owns the Display slot. */
  font-size: clamp(28px, 4vw, 40px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  max-width: 24ch;
}
.magazine-sub {
  font-size: 16px;
  color: var(--text-secondary);
  margin-top: 14px;
  max-width: 56ch;
  line-height: 1.55;
}

/* ── Editorial list lane ─────────────────────────────────────────────
   Replaces the magazine-grid card stack for the blog index and
   category archives. ONE featured post at the top (with optional
   image), then a quiet typographic list. Hierarchy via space and
   weight, no card chrome. Scales gracefully from 5 to 500 posts.

   The featured-post-title is the ONLY Display-scale element on the
   page; the page header (.magazine-title) is deliberately smaller so
   the content sings, not the chrome.
*/

/* Featured post ----------------------------------------------------- */
.featured-post {
  max-width: var(--blog-max, 1440px);
  margin: 0 auto clamp(56px, 8vw, 96px);
}
.featured-post-link {
  display: block;
  color: inherit;
  text-decoration: none;
}
.featured-post-image {
  width: 100%;
  aspect-ratio: 21 / 9;
  margin-bottom: clamp(24px, 3vw, 36px);
  overflow: hidden;
  border-radius: 12px;
  background: var(--bg-tertiary);
}
.featured-post-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
}
.featured-post-link:hover .featured-post-image img {
  transform: scale(1.02);
}
.featured-post-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 14px;
}
.featured-post-meta .dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.5;
}
.featured-post-title {
  /* Display-scale: the single most important title on this page. */
  font-size: clamp(32px, 5vw, 56px);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.025em;
  margin: 0 0 18px;
  color: var(--text-primary);
  max-width: 22ch;
  transition: color 240ms cubic-bezier(0.16, 1, 0.3, 1);
}
.featured-post-link:hover .featured-post-title {
  color: var(--accent);
}
.featured-post-lede {
  font-size: clamp(16px, 1.6vw, 19px);
  line-height: 1.55;
  color: var(--text-secondary);
  margin: 0 0 24px;
  max-width: 58ch;
}
.featured-post-read {
  /* Quiet at rest: reading affordance, not a primary CTA. Accent
     lights up on hover alongside the arrow slide, so the link still
     signals "click me" without spraying violet at the resting state. */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-muted);
  transition: gap 240ms cubic-bezier(0.16, 1, 0.3, 1),
              color 240ms cubic-bezier(0.16, 1, 0.3, 1);
}
.featured-post-read svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.featured-post-link:hover .featured-post-read,
.featured-post-link:focus-visible .featured-post-read {
  gap: 12px;
  color: var(--accent);
}

/* Editorial list (chronological rows) ------------------------------- */
.editorial-list {
  max-width: var(--blog-max, 1440px);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--border-light);
}
.editorial-row {
  display: grid;
  grid-template-columns: minmax(0, 16ch) 1fr;
  gap: clamp(20px, 3vw, 48px);
  padding: clamp(24px, 3.5vw, 40px) 0;
  border-bottom: 1px solid var(--border-light);
  color: inherit;
  text-decoration: none;
}
.editorial-row-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-self: start;
  padding-top: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.editorial-row-meta time,
.editorial-row-meta span {
  display: block;
}
.editorial-row-body {
  min-width: 0;
}
.editorial-row-title {
  font-size: clamp(20px, 2.4vw, 26px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0 0 8px;
  color: var(--text-primary);
  transition: color 240ms cubic-bezier(0.16, 1, 0.3, 1);
}
.editorial-row-lede {
  font-size: 15px;
  line-height: 1.55;
  color: var(--text-secondary);
  margin: 0;
  max-width: 64ch;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.editorial-row:hover .editorial-row-title,
.editorial-row:focus-visible .editorial-row-title {
  color: var(--accent);
}
.editorial-row:focus-visible,
.featured-post-link:focus-visible {
  outline: none;
}
.editorial-row:focus-visible .editorial-row-body,
.featured-post-link:focus-visible {
  /* Soft ring offset from the title block, not a hard outline rectangle
     around the entire huge row. Keyboard users see clear focus state
     without the harsh browser-default outline. */
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--accent);
  border-radius: 6px;
}
.featured-post-link:focus-visible {
  border-radius: 12px;
}

/* Pagination footer (auto-appears when index pages > 1) -------------
   Editorial register: 3-column flex (prev · current · next) with
   hairline above, no card chrome. Empty slots render as spacers so
   the centered "Page N of M" stays put on first/last page.
*/
.pagination {
  max-width: var(--blog-max, 1440px);
  margin: clamp(56px, 8vw, 88px) auto 0;
  padding: 28px 0 4px;
  border-top: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.pagination-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-secondary);
  text-decoration: none;
  transition: gap 240ms cubic-bezier(0.16, 1, 0.3, 1),
              color 200ms ease-out;
}
.pagination-link svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.pagination-link:hover,
.pagination-link:focus-visible {
  color: var(--accent);
  outline: none;
  gap: 12px;
}
.pagination-current {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pagination-spacer {
  /* Reserves equivalent visual weight so the center label doesn't
     shift on first or last page. Empty by design. */
  display: inline-block;
  min-width: 1px;
}

@media (max-width: 560px) {
  .pagination {
    flex-direction: column;
    gap: 16px;
    text-align: center;
  }
  .pagination-spacer { display: none; }
}

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

/* Mobile: collapse to single column, eyebrow above title ------------ */
@media (max-width: 720px) {
  .editorial-row {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 24px 0;
  }
  .editorial-row-meta {
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding-top: 0;
  }
  .editorial-row-meta time::after {
    content: " ·";
    margin-left: 4px;
    opacity: 0.5;
  }
  .featured-post-image {
    aspect-ratio: 16 / 10;
  }
}

@media (prefers-reduced-motion: reduce) {
  .featured-post-image img,
  .featured-post-title,
  .featured-post-read,
  .editorial-row-title {
    transition: none;
  }
}

/* ── Category chip row ─────────────────────────────────────────────── */
.category-row {
  max-width: var(--blog-max, 1440px);
  margin: 0 auto 40px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.chip {
  display: inline-flex;
  align-items: center;
  padding: 7px 14px;
  border-radius: 9999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border: 1px solid var(--border-light);
  transition: all 0.2s;
}
.chip:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.chip.chip-filled,
.chip.active {
  background: var(--accent);
  color: #ffffff;
  border-color: var(--accent);
}
.chip.chip-filled:hover,
.chip.active:hover { background: var(--accent-hover); color: #ffffff; border-color: var(--accent-hover); }
.chip-eyebrow {
  display: inline-flex;
  padding: 5px 11px;
  border-radius: 9999px;
  background: var(--accent);
  color: #ffffff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

/* ── Author byline ──────────────────────────────────────────────────── */
.byline {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--text-muted);
}
.byline .dot { width: 3px; height: 3px; background: var(--text-muted); border-radius: 50%; flex-shrink: 0; }
.author-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.author-avatar.placeholder {
  /* Flat neutral, not a violet gradient. Missing avatar is "no data",
     not a brand moment. */
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-tertiary);
  color: var(--text-muted);
  font-weight: 700;
  font-size: 12px;
}
.byline-author {
  font-weight: 600;
  color: var(--text-secondary);
}

/* ── Small card grid ───────────────────────────────────────────────────
   Used by article-page extras (More from author, Related). NOT used
   by the blog index anymore (replaced by editorial-list lane). Keep
   the styles scoped to article-extras context.
*/
.small-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 24px;
}
.small-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: transform 0.3s ease;
}
.small-card:hover { transform: translateY(-2px); }
.small-card-image {
  aspect-ratio: 16/10;
  border-radius: 14px;
  overflow: hidden;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  transition: border-color 0.3s;
}
.small-card:hover .small-card-image { border-color: color-mix(in srgb, var(--accent) 35%, var(--border-light)); }
.small-card-image img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.6s ease; }
.small-card:hover .small-card-image img { transform: scale(1.03); }
.small-card-image.placeholder {
  /* Flat neutral; missing image is "no data", not a brand moment. */
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-tertiary);
}
.small-card-image.placeholder span {
  font-size: 44px;
  font-weight: 900;
  color: var(--text-muted);
  letter-spacing: -0.02em;
}
.small-card-title {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── ARTICLE page ──────────────────────────────────────────────────── */
.article-fullbleed-hero {
  position: relative;
  /* Full-bleed: width is AUTO (not 100%) so the negative left+right
     margins both stretch the box past <main>'s 24px horizontal padding
     to the viewport edges. With width:100% the box was pinned to the
     content-box width and the right negative margin couldn't extend it,
     leaving a ~48px gap on the right (the reported "image cut off on the
     right" bug). margin-top -56px pulls it up under the sticky nav. */
  margin-top: -56px;
  margin-left: -24px;
  margin-right: -24px;
  height: clamp(380px, 56vh, 560px);
  overflow: hidden;
  background: var(--bg-tertiary);
}
@media (max-width: 640px) {
  .article-fullbleed-hero {
    margin-left: -16px;
    margin-right: -16px;
    margin-top: -32px;
    height: clamp(300px, 50vh, 420px);
  }
}
/* Direct child only: this is the featured image that fills the hero.
   Without ">", the descendant selector would also catch nested imgs
   like .author-avatar inside the byline overlay and stretch them to
   100% of the hero (rendering the gravatar as a screen-sized blob).
   object-position center 50% (default) explicitly stated so future
   browser/spec changes can't shift the crop origin; both edges crop
   equally so the subject stays centered on every viewport size. */
.article-fullbleed-hero > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
  display: block;
}
.article-fullbleed-hero.placeholder {
  /* Flat neutral. The 200px violet initials read as a logo wall, not
     as missing content. Mute it. */
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-tertiary);
}
.article-fullbleed-hero.placeholder span {
  font-size: clamp(96px, 16vw, 200px);
  font-weight: 900;
  color: var(--text-muted);
  letter-spacing: -0.04em;
  opacity: 0.4;
}
.article-overlay {
  position: absolute;
  inset: auto 0 0 0;
  padding: 48px 24px 36px;
  background: linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0.35) 60%, transparent 100%);
  color: #ffffff;
}
.article-overlay-inner {
  max-width: 1280px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.article-overlay .chip-eyebrow {
  align-self: flex-start;
  background: var(--accent);
  color: #ffffff;
}
.article-overlay h1 {
  font-size: clamp(28px, 4.5vw, 48px);
  font-weight: 900;
  line-height: 1.08;
  letter-spacing: -0.025em;
  color: #ffffff;
  text-shadow: 0 2px 16px rgba(0,0,0,0.3);
  max-width: 28ch;
}
.article-overlay .byline { color: rgba(255,255,255,0.85); }
.article-overlay .byline-author { color: #ffffff; }
.article-overlay .author-avatar { border: 2px solid rgba(255,255,255,0.4); }

.article-layout {
  max-width: 1280px;
  margin: 56px auto 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  position: relative;
}
@media (min-width: 1024px) {
  .article-layout {
    grid-template-columns: 64px 1fr;
    gap: 48px;
  }
}

.share-rail {
  display: none;
}
@media (min-width: 1024px) {
  .share-rail {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: center;
    position: sticky;
    top: 100px;
    align-self: start;
  }
}
.share-btn {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  transition: all 0.2s;
}
.share-btn:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border-light));
  transform: translateY(-1px);
}
.share-btn svg { width: 18px; height: 18px; }
.share-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  writing-mode: vertical-rl;
  margin-bottom: 8px;
}

.article-body {
  max-width: 960px;
  font-size: 18px;
  line-height: 1.75;
  color: var(--text-secondary);
}
.article-body h2 {
  font-size: 30px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.015em;
  color: var(--text-primary);
  margin-top: 56px;
  margin-bottom: 18px;
}
.article-body h3 {
  font-size: 22px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text-primary);
  margin-top: 40px;
  margin-bottom: 12px;
}
.article-body h4 {
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
  margin-top: 32px;
  margin-bottom: 8px;
}
.article-body p { margin-bottom: 24px; }
.article-body p:last-child { margin-bottom: 0; }
.article-body a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.article-body a:hover { color: var(--accent-hover); }
.article-body strong { color: var(--text-primary); font-weight: 700; }
.article-body em { font-style: italic; }
.article-body code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 0.92em;
  padding: 2px 6px;
  background: var(--bg-tertiary);
  border-radius: 4px;
  color: var(--text-primary);
}
.article-body pre {
  background: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  border-radius: 14px;
  padding: 20px;
  overflow-x: auto;
  margin-bottom: 28px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 14px;
  line-height: 1.6;
}
.article-body pre code { background: transparent; padding: 0; font-size: inherit; }
.article-body blockquote {
  margin: 36px 0;
  padding: 8px 0 8px 28px;
  border-left: 3px solid var(--accent);
  font-style: italic;
  color: var(--text-primary);
  font-size: 20px;
  line-height: 1.5;
}
.article-body ul, .article-body ol { margin: 0 0 24px 24px; padding: 0; }
.article-body li { margin-bottom: 8px; }
.article-body img { border-radius: 14px; margin: 36px 0; }
.article-body hr { border: none; border-top: 1px solid var(--border-light); margin: 48px 0; }

/* ── Article tags ──────────────────────────────────────────────────── */
/* Rendered at the bottom of the article body, after the post content.
   Quiet visual register: small chips, low contrast, hashtag prefix in
   the content (not as a separate element) so they read as text first,
   navigation second. */
.article-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 48px;
  padding-top: 24px;
  border-top: 1px solid var(--border-light);
}
.tag-chip {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 9999px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.01em;
}

/* ── Article extras: more from author, related ─────────────────────── */
.article-extras {
  max-width: 1100px;
  margin: 80px auto 0;
  padding: 56px 0 0;
  border-top: 1px solid var(--border-light);
  display: flex;
  flex-direction: column;
  gap: 56px;
}
.extras-block { display: flex; flex-direction: column; gap: 20px; }
.extras-title {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.015em;
  color: var(--text-primary);
}

.article-back {
  max-width: 1100px;
  margin: 56px auto 0;
  text-align: center;
}
.article-back a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 20px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-secondary);
  border: 1px solid var(--border-light);
  background: var(--bg-secondary);
  transition: all 0.2s;
}
.article-back a:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border-light));
}

/* ── Footer (mirrors Footer.tsx visual structure) ──────────────────── */
.footer {
  position: relative;
  margin-top: 80px;
  padding: 80px 24px 48px;
  background: var(--bg-primary);
  overflow: hidden;
}
/* Top glowing hairline border */
.footer-border-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(
    to right,
    transparent,
    color-mix(in srgb, var(--accent) 50%, transparent),
    transparent
  );
}
/* Background indigo glow */
.footer-glow {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 800px;
  height: 400px;
  background: color-mix(in srgb, var(--accent) 5%, transparent);
  filter: blur(120px);
  border-radius: 9999px;
  pointer-events: none;
}
.footer-inner {
  max-width: var(--blog-max, 1440px);
  margin: 0 auto;
  position: relative;
  z-index: 1;
}

.footer-cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: 48px;
  margin-bottom: 64px;
}
@media (min-width: 768px) {
  .footer-cols { grid-template-columns: 1fr 1fr; gap: 48px; }
}
@media (min-width: 1024px) {
  .footer-cols { grid-template-columns: 2fr 1fr 1fr 1fr 1fr; gap: 32px; }
}

.footer-brand-col {
  display: flex;
  flex-direction: column;
  gap: 24px;
  grid-column: 1 / -1;
}
@media (min-width: 1024px) {
  .footer-brand-col { grid-column: span 2; }
}
/* Footer brand mirrors the nav brand exactly (32px mark, 18px extrabold
   wordmark, 10px gap) so the identity reads consistently at the top and
   bottom of every blog page. */
.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  width: fit-content;
  color: var(--text-primary);
}
.footer-brand img { width: 32px; height: 32px; max-width: 32px; transition: transform 0.3s; }
.footer-brand:hover img { transform: translateY(-4px); }
.footer-brand span {
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -0.01em;
}
.footer-tagline {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.6;
  max-width: 24rem;
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.footer-col-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: 0.05em;
  margin: 0;
}
.footer-col ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.footer-col a {
  font-size: 14px;
  color: var(--text-muted);
  transition: color 0.2s;
}
.footer-col a:hover { color: var(--text-primary); }

.footer-bottom {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: 32px;
  border-top: 1px solid var(--border-light);
}
@media (min-width: 768px) {
  .footer-bottom { flex-direction: row; }
}
.footer-bottom-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
@media (min-width: 640px) {
  .footer-bottom-left { flex-direction: row; }
}
.footer-socials { display: flex; align-items: center; gap: 12px; }
.footer-socials a {
  width: 40px;
  height: 40px;
  border-radius: 9999px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  transition: all 0.3s;
  box-shadow: var(--shadow-soft);
}
.footer-socials a:hover {
  color: #ffffff;
  background: var(--accent);
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: 0 4px 20px rgba(99, 94, 231, 0.25);
}
.footer-socials svg { width: 18px; height: 18px; }
.footer-divider {
  display: none;
  width: 1px;
  height: 24px;
  background: var(--border-light);
}
@media (min-width: 640px) {
  .footer-divider { display: inline-block; }
}
.footer-copyright {
  font-size: 13px;
  color: var(--text-muted);
  font-weight: 500;
  text-align: center;
}
@media (min-width: 640px) {
  .footer-copyright { text-align: left; }
}
.footer-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  padding: 8px 16px;
  border-radius: 9999px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
}
.footer-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 9999px;
  background: #22c55e;
  animation: footer-pulse 2s ease-in-out infinite;
}
@keyframes footer-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 24px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid color-mix(in srgb, var(--border-light) 60%, transparent);
}
@media (min-width: 768px) {
  .footer-legal { justify-content: flex-start; }
}
.footer-legal a {
  font-size: 12px;
  color: var(--text-muted);
  transition: color 0.2s;
}
.footer-legal a:hover { color: var(--text-primary); }

/* ── Empty / placeholder / sample-banner ───────────────────────────── */
.empty-state {
  max-width: 600px;
  margin: 80px auto;
  text-align: center;
  color: var(--text-muted);
}
.empty-state-title { font-size: 22px; font-weight: 700; color: var(--text-secondary); margin-bottom: 8px; }

.sample-banner {
  /* Informational, not a brand moment. This banner only appears when
     the WP API is unreachable and we fell back to samples. Neutral
     hairline + muted background keeps it informational without
     spending Beacon Violet authority. */
  max-width: var(--blog-max, 1440px);
  margin: 0 auto 32px;
  padding: 12px 18px;
  border: 1px dashed var(--border-light);
  border-radius: 12px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.sample-banner-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); flex-shrink: 0; }
