/* ============================================================
   EDITORIAL DESIGN SYSTEM — v2
   Warm paper, ink, one international-orange, drawn from the
   Archify editorial reference and the earlier Cabinet Grotesk
   dark build.

   The four web families are loaded via <link> in each page head
   (Fraunces / Space Grotesk / Inter / JetBrains Mono) so nothing
   here shadows or 404s the CDN. The only @font-face is Anurati,
   which has no CDN equivalent and ships in fonts/ — it carries the
   VM logogram and is the one brand asset worth self-hosting.
   ============================================================ */

/* ---------- 1. TOKENS ---------- */
:root {
  --paper:        #eff2f1;
  --paper-raised: #f8faf9;
  --paper-sunk:   #e7ebe9;
  --ink:          #15181b;
  --ink-soft:     #363c41;
  --muted:        #5c6469;
  /* --dim carries real text (dates, labels, meta), so it must clear 4.5:1
     against --paper-sunk — #8b9398 only reached 2.77:1. */
  --dim:          #616a6f;
  --line:         rgba(20,23,26,.13);
  --line-hi:      rgba(20,23,26,.28);
  /* --accent is also used for small text, so it is stepped slightly deeper
     than the pure brand orange; still reads as international orange, and
     clears 4.5:1 on every surface (was 3.74:1 on --paper-sunk). */
  --accent:       #bd3a0c;
  --accent-hi:    #993009;
  --accent-soft:  rgba(189,58,12,.09);
  --accent-fill:  rgba(189,58,12,.06);
  --plate:        #0f1216;
  --on-plate:     #f7f9f9;
  --on-plate-mut: #9aa4aa;
  /* Dark plates need their own accent: the light-theme --accent is stepped
     deep for AA on warm paper and only reached 3.37:1 on --plate. #e2622c
     clears 4.5:1 on both plate colours while still reading as the brand
     orange, so kickers and tags inside a plate stop failing AA. */
  --accent-on-plate: #e2622c;

  /* Venue tags. Only two hues are live: DZone and Medium. The tag paints its
     own fill underneath the text, so the pair that matters is the hue against
     that blend, not against plain paper — #047857 reached only 3.89:1 on
     --paper-sunk; #046a4e clears 4.5:1 against all three light fills.
     The cyan/violet/amber/rose ramps that used to sit here had no consumer and
     were dropped: platform marks take their brand hex from js/research.js,
     because a DZone tile should not shift hue between light and dark. */
  --emerald:  #046a4e;  --emerald-fill:  rgba(4,106,78,.12);
  --orange:     #b83c0b; --orange-fill:    rgba(184,60,11,.12);
  --orange-light: #ea580c;
  /* Text-on-tint variants. --emerald / --orange are also used as SURFACES
     (the .pulse dot, the copy-confirm button) where white sits on top, so they
     cannot simply be lightened for dark mode. These carry the same hues for
     use as foreground, following the --accent-on-plate convention. */
  --emerald-ink: #046a4e;
  --orange-ink:  #993009;
  /* Slate marks the 49 IBM Cloud guides DZone has unpublished. It is the only
     hue here with no live-publication meaning, which is the point: a reader
     should be able to tell at a glance which venue marks open something. */
  --slate:       #55606a;  --slate-fill:  rgba(85,96,106,.13);
  --slate-ink:   #454f58;
  /* Violet marks the Medium publications that carry a piece of this writing --
     Chatbots Life today. A third hue alongside orange and emerald so a row
     showing a publication plus a platform is readable at a glance. */
  --violet-fill: rgba(124,58,237,.12);
  --violet-ink:  #5b21b6;
  /* legacy alias — js/research.js still resolves var(--primary) */
  --primary:    #b83c0b;

  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-grot:    'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
  --font-logo:    'Anurati', var(--font-grot), sans-serif;

  /* Modular type scale — a 1.25 major third off a 15px body, carried over
     from the earlier build's scale discipline so heading levels stay in step
     across all six pages. Sizes that must stay fluid (hero, section headings)
     keep their clamp() and are not expressed here. */
  --t-xs:   .6875rem;  /* 11   mono micro-labels      */
  --t-sm:   .75rem;    /* 12   data labels, meta       */
  --t-base: .875rem;   /* 14   buttons, dense UI       */
  --t-ui:   .9375rem;  /* 15   body, nav               */
  --t-md:   1.0625rem; /* 17   card headings, lede     */
  --t-lg:   1.25rem;   /* 20   subheads                */
  --t-xl:   1.5rem;    /* 24   h3                      */

  /* Display sizes are a separate axis because they are clamps, not steps —
     modelling them as a static ramp would just mean guessing at 32/44/60/80
     when nothing actually renders at those sizes. */
  --d-hero:     clamp(2.75rem, 7.2vw, 5.25rem);   /* h1, homepage   */
  --d-page:     clamp(2.25rem, 5.2vw, 3.5rem);    /* h1, subpages   */
  --d-section:  clamp(1.875rem, 3.6vw, 3rem);     /* h2, sections   */
  --d-sub:      clamp(1.75rem, 3vw, 2.125rem);     /* h3, rail       */
  --d-sub-wide: clamp(1.75rem, 4vw, 2.75rem);      /* h3, wide band  */
  --d-card:     clamp(1.5rem, 2.6vw, 2.125rem);    /* card headline  */
  --d-folio:    clamp(5rem, 11vw, 9.5rem);         /* ghost numeral  */
  --d-folio-sm: clamp(4rem, 20vw, 6rem);           /*  ≤860 override */

  --ls-tight: -.028em;  /* display sizes only */
  --ls-snug:  -.012em;
  --ls-wide:   .08em;   /* uppercase labels   */

  --r-sm: 10px; --r-md: 14px; --r-lg: 20px;
  --nav-h: 62px;
  --drawer-w: 288px;   /* mobile nav slide-in width */
  --gap: 1.5rem;
  --wrap: 1180px;
  --wrap-narrow: 760px;
  --ease-out: cubic-bezier(.22,1,.36,1);

  --shadow-sm: 0 1px 2px rgba(15,18,22,.05), 0 3px 10px rgba(15,18,22,.045);
  --shadow-md: 0 2px 6px rgba(15,18,22,.06), 0 12px 28px rgba(15,18,22,.07);
  --shadow-lg: 0 8px 20px rgba(15,18,22,.10), 0 32px 64px rgba(15,18,22,.14);
  --dur: .55s;
}

/* ---------- 2. DARK THEME ---------- */
html[data-theme="dark"] {
  /* Warm near-black rather than the blue-grey #0d1014 the inversion
     produced — this is the earlier build's #0F0F0F character, warmed
     slightly so the orange accent sits in it rather than on top. */
  --paper:        #0f0e0d;
  --paper-raised:#191715;
  --paper-sunk:   #141210;
  --ink:          #f4f1ee;
  --ink-soft:     #cdc6c0;
  --muted:        #9b938c;
  --dim:          #8a817a;
  --line:         rgba(255,244,236,.10);
  --line-hi:      rgba(255,244,236,.19);
  --accent:       #ff7a3d;
  --accent-hi:    #ff9463;
  --accent-soft:  rgba(255,122,61,.15);
  --accent-fill:  rgba(255,122,61,.09);
  --plate:        #080706;
  --on-plate:     #f2efec;
  --on-plate-mut: #9d958e;
  --accent-on-plate: #ff7a3d;

  --orange:     #f97316; --orange-fill:    rgba(249,115,22,.15);
  --orange-light: #fb923c;
  /* Foreground variants — see the note in :root. --emerald/--orange stay dark
     here because they are surfaces with white text on them; only the *text*
     uses need lifting off a near-black plate. */
  --emerald-fill: rgba(47,163,122,.16);
  --emerald-ink:  #2fa37a;
  --orange-ink:   #f97316;
  --slate-fill: rgba(148,163,184,.18);
  --slate-ink:  #b6c2cf;
  --violet-fill: rgba(167,139,250,.18);
  --violet-ink:  #c4b5fd;
  --primary:    #f97316;

  --shadow-sm: 0 1px 2px rgba(0,0,0,.4), 0 3px 10px rgba(0,0,0,.3);
  --shadow-md: 0 2px 6px rgba(0,0,0,.45), 0 12px 28px rgba(0,0,0,.4);
  --shadow-lg: 0 8px 20px rgba(0,0,0,.5), 0 32px 64px rgba(0,0,0,.55);
}

/* ---------- 3. RESET / BASE ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
/* The UA sheet's [hidden] { display: none } is specificity (0,1,0) — the same
   as any class rule — so an author `display` declaration wins purely by coming
   later. .latest-post-card is `display: grid`, which meant the platform filters
   set `card.hidden = true` on 201 of 260 rows and every one of them stayed on
   screen. The attribute is only load-bearing if it beats class rules. */
[hidden] { display: none !important; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 1.5rem);
}
body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  transition: background-color .3s var(--ease-out), color .3s var(--ease-out);
}
img, svg, canvas, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; padding: 0; }
strong, b { font-weight: 600; color: var(--ink); }
em { font-style: italic; }
code, kbd, pre, samp { font-family: var(--font-mono); font-size: .9em; }
h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
::selection { background: var(--accent); color: #fff; }

/* ---------- 4. ACCESSIBILITY ---------- */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  padding: .7rem 1.15rem; border-radius: 0 0 var(--r-sm) 0;
  background: var(--plate); color: var(--on-plate);
  font-family: var(--font-grot); font-size: .8125rem; font-weight: 600;
}
.skip-link:focus { left: 0; }
.visually-hidden {
  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;
}

/* ---------- 5. LAYOUT PRIMITIVES ---------- */
.container {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(1.125rem, 4vw, 2.5rem);
}
.container.narrow { max-width: var(--wrap-narrow); }
main > section { padding-block: clamp(4rem, 9vw, 7.5rem); }
#contact { padding-block: 2rem 5rem; }

.divider {
  height: 1px; border: 0;
  background: linear-gradient(90deg, transparent, var(--line-hi) 18%, var(--line-hi) 82%, transparent);
}

/* Background texture — a faint drafting grid, like graph paper */
.grid-bg {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 88px 88px;
  -webkit-mask-image: radial-gradient(ellipse 100% 62% at 50% 0%, #000 0%, transparent 78%);
          mask-image: radial-gradient(ellipse 100% 62% at 50% 0%, #000 0%, transparent 78%);
  opacity: .5;
}

/* ---------- 6. REVEAL ANIMATION ---------- */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  filter: blur(5px);
  transition: opacity var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out),
              filter var(--dur) var(--ease-out);
  transition-delay: calc(var(--d, 0) * 80ms);
}
.reveal.d1 { --d: 1 } .reveal.d2 { --d: 2 } .reveal.d3 { --d: 3 }
.reveal.d4 { --d: 4 } .reveal.d5 { --d: 5 }
.reveal.in, .reveal.visible {
  opacity: 1; transform: none; filter: none;
}
/* noscript fallback + JS-less safety net */
.no-js .reveal, .reveal-fallback { opacity: 1; transform: none; filter: none; }

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

/* ---------- 7. NAVIGATION ---------- */
/* The frosted background lives on ::before, not on .nav itself. backdrop-filter
   (like transform/filter/will-change) makes an element the containing block for
   position:fixed descendants — with it on .nav, the mobile drawer resolved
   `top:0;bottom:0` against the 63px nav box instead of the viewport, giving a
   102px drawer with its links overflowing, and a 62px scrim. Moving the effect
   to a pseudo-element keeps .nav a normal sticky box while looking identical. */
.nav {
  position: sticky; top: 0; z-index: 100;
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease-out);
}
.nav::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
          backdrop-filter: saturate(1.6) blur(14px);
}
.nav.is-stuck { border-bottom-color: var(--line); box-shadow: 0 1px 12px rgba(15,18,22,.04); }
.nav-progress {
  position: absolute; inset: 0 auto auto 0; z-index: 2;
  height: 2px; width: 0;
  background: linear-gradient(90deg, var(--accent), var(--orange-light));
  transition: width .1s linear;
}
.nav-inner {
  width: 100%; max-width: var(--wrap); margin-inline: auto;
  padding-inline: clamp(1.125rem, 4vw, 2.5rem);
  min-height: var(--nav-h);
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
}
.brand { display: inline-flex; align-items: center; gap: .6rem; }
/* The logogram: Anurati, self-hosted from fonts/. No CDN equivalent, and it
   is the one piece of the earlier build worth carrying forward — a real
   brand mark rather than italic display type standing in for one. */
@font-face {
  font-family: 'Anurati';
  src: url('../fonts/Anurati-Regular.otf') format('opentype');
  font-weight: 400; font-style: normal; font-display: swap;
}

.brand-mark {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 8px;
  font-family: var(--font-logo); font-size: .8125rem; font-weight: 400;
  letter-spacing: .06em; line-height: 1;
  background: var(--accent); color: #fff;
  padding-top: 2px; /* Anurati sits slightly high in its em box */
}
.brand-name {
  font-family: var(--font-grot); font-size: var(--t-ui); font-weight: 600;
  letter-spacing: -.015em; color: var(--ink);
}
.nav-links { display: flex; align-items: center; gap: .35rem; }
.nav-link {
  position: relative;
  padding: .4rem .6rem; border-radius: 6px;
  font-family: var(--font-grot); font-size: .8125rem; font-weight: 500;
  color: var(--muted);
  transition: color .2s var(--ease-out), background-color .2s var(--ease-out);
}
.nav-link::after {
  content: ''; position: absolute; left: .6rem; right: .6rem; bottom: .1rem;
  height: 1.5px; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .28s var(--ease-out);
}
.nav-link:hover { color: var(--ink); }
.nav-link:hover::after, .nav-link.is-active::after { transform: scaleX(1); }
.nav-link.is-active { color: var(--ink); }
.nav-tools { display: flex; align-items: center; gap: .35rem; }
.icon-btn {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 8px;
  color: var(--muted);
  transition: color .2s var(--ease-out), background-color .2s var(--ease-out);
}
.icon-btn:hover { color: var(--ink); background: var(--accent-soft); }
.icon-btn i { font-size: var(--t-base); line-height: 1; }
.nav-burger { display: none; }

/* Scrim behind the mobile drawer — carried over from the earlier build, where
   the overlay was the one genuinely better idea than the dropdown that
   replaced it. Without it the menu opens over content that still looks
   tappable, and there is no visual signal that the page is inert. */
.nav-scrim {
  position: fixed; inset: 0; z-index: 99;
  background: color-mix(in srgb, var(--ink) 42%, transparent);
  -webkit-backdrop-filter: blur(2px);
          backdrop-filter: blur(2px);
  opacity: 0; visibility: hidden;
  transition: opacity .28s var(--ease-out), visibility .28s var(--ease-out);
}
.nav-scrim.is-open { opacity: 1; visibility: visible; }
@media (min-width: 861px) { .nav-scrim { display: none; } }

/* ---------- 8. SECTION CHROME ---------- */
.section-label {
  display: flex; align-items: center; gap: .75rem;
  font-family: var(--font-mono); font-size: .625rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--dim); margin-bottom: 1rem;
}
.section-label::before {
  content: ''; width: 1.75rem; height: 1px;
  background: var(--accent); flex: none;
}
.section-heading {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--d-section);
  font-weight: 400; letter-spacing: var(--ls-tight); line-height: 1.08;
  color: var(--ink); margin-bottom: 1.125rem;
  text-wrap: balance;
}
.section-heading em { font-style: italic; color: var(--accent); }
.section-body {
  font-size: var(--t-ui); color: var(--muted); line-height: 1.72;
  max-width: 58ch; text-wrap: pretty;
}
.section-head { margin-bottom: 2.75rem; }
.section-head .section-label { justify-content: flex-start; }
.section-count {
  font-family: var(--font-mono); font-size: var(--t-sm); font-weight: 500;
  color: var(--accent); vertical-align: middle; margin-left: .5rem;
}

/* Ghost folio numeral, top-right of each section */
.folio { position: relative; }
.folio::after {
  content: attr(data-folio);
  position: absolute; top: 2.5rem; right: clamp(1.125rem, 4vw, 2.5rem);
  z-index: 0; pointer-events: none; user-select: none;
  font-family: var(--font-display); font-style: italic; font-optical-sizing: auto;
  font-size: var(--d-folio); line-height: 1;
  color: transparent; -webkit-text-stroke: 1px var(--line-hi);
  opacity: .55;
}
.folio > .container { position: relative; z-index: 1; }

/* ---------- 9. BUTTONS ---------- */
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px; padding: .65rem 1.25rem; border-radius: 9px;
  font-family: var(--font-grot); font-size: var(--t-base); font-weight: 500;
  letter-spacing: -.005em;
  border: 1px solid transparent;
  transition: transform .2s var(--ease-out), background-color .2s var(--ease-out),
              border-color .2s var(--ease-out), color .2s var(--ease-out),
              box-shadow .2s var(--ease-out);
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--ink); color: var(--paper); box-shadow: var(--shadow-sm); }
/* Hover steps to --accent-hi rather than repeating --accent: it gives the
   press state a visible depth cue, and it lifts the button's lowest-contrast
   state (light 4.94 -> 6.70, dark 7.44 -> 8.88) since the label is --paper. */
.btn-primary:hover { background: var(--accent-hi); box-shadow: var(--shadow-md); }
.btn-ghost { border-color: var(--line-hi); color: var(--ink-soft); }
.btn-ghost:hover { border-color: var(--ink); color: var(--ink); background: var(--accent-soft); }

.mono-link {
  display: inline-flex; align-items: center; gap: .4rem;
  /* WCAG 2.2 SC 2.5.8 wants 24x24 minimum for a standalone target. The label
     is 11px mono on a 1px underline and rendered 22px tall, so the hit area is
     padded out to the floor rather than the type being enlarged. */
  min-height: 24px; padding-block: .2rem .3rem;
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft);
  border-bottom: 1px solid var(--line-hi);
  transition: color .2s var(--ease-out), border-color .2s var(--ease-out);
}
.mono-link:hover { color: var(--accent); border-color: var(--accent); }

/* ---------- 10. HERO ---------- */
.hero { padding-top: clamp(3rem, 7vw, 5.5rem) !important; }
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
.hero-eyebrow {
  display: inline-flex; align-items: center; gap: .6rem;
  margin-bottom: 1.75rem;
  font-family: var(--font-mono); font-size: .625rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
}
.pulse {
  position: relative; width: 7px; height: 7px; border-radius: 50%;
  background: var(--emerald); flex: none;
}
.pulse::after {
  content: ''; position: absolute; inset: -4px; border-radius: 50%;
  border: 1px solid var(--emerald);
  animation: pulse 2.4s var(--ease-out) infinite;
}
@keyframes pulse {
  0%   { transform: scale(.6); opacity: .9; }
  100% { transform: scale(1.5); opacity: 0; }
}
.hero-title {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--d-hero);
  font-weight: 400; letter-spacing: -.035em; line-height: .98;
  color: var(--ink); margin-bottom: 1.25rem; text-wrap: balance;
}
.hero-title .last { color: var(--ink-soft); }
.hero-title em {
  font-style: italic; color: var(--accent); font-weight: 400; letter-spacing: -.02em;
}
.hero-role {
  font-family: var(--font-grot); font-size: var(--t-md); font-weight: 500;
  letter-spacing: var(--ls-snug); color: var(--ink-soft); margin-bottom: .625rem;
}
.hero-cred {
  font-family: var(--font-mono); font-size: var(--t-xs); line-height: 1.7;
  letter-spacing: .04em; color: var(--muted); margin-bottom: 1.5rem;
  max-width: 46ch;
}
.hero-lede {
  font-size: 1rem; line-height: 1.75; color: var(--muted);
  max-width: 52ch; margin-bottom: 2rem; text-wrap: pretty;
}
.hero-lede strong { color: var(--ink); font-weight: 600; }
.hero-cta { display: flex; flex-wrap: wrap; gap: .75rem; }
.hero-intro { min-width: 0; }

/* Portrait plate */
.portrait { position: relative; }
.portrait-frame {
  position: relative;
  border-radius: var(--r-lg); overflow: hidden;
  border: 1px solid var(--line-hi);
  background: var(--paper-sunk);
  box-shadow: var(--shadow-md);
  aspect-ratio: 4 / 5;
}
.portrait-frame img { width: 100%; height: 100%; object-fit: cover; }
.portrait-frame::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, transparent 55%, rgba(15,18,22,.28) 100%);
}
.portrait-plate {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-top: -3.25rem; margin-inline: 1.25rem; position: relative; z-index: 2;
  padding: .9rem 1.125rem; border-radius: var(--r-md);
  background: var(--plate); color: var(--on-plate);
  box-shadow: var(--shadow-lg);
}
.portrait-plate span:first-child {
  display: block;
  font-family: var(--font-mono); font-size: .5rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--on-plate-mut); margin-bottom: .25rem;
}
.portrait-plate strong {
  display: block; font-family: var(--font-grot); font-size: var(--t-base);
  font-weight: 600; color: var(--on-plate); letter-spacing: -.01em;
}
.portrait-badge {
  flex: none; display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 50%;
  font-family: var(--font-logo); font-size: 1rem; font-weight: 400;
  letter-spacing: .05em; line-height: 1; padding-top: 2px;
  background: var(--accent); color: #fff;
}

/* Stats strip */
.stats-strip {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin-top: .5rem;
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  background: var(--paper-raised); overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.stat { padding: 1.5rem 1.5rem 1.25rem; border-left: 1px solid var(--line); }
.stat:first-child { border-left: 0; }
.stat b {
  display: block; margin-bottom: .55rem;
  font-family: var(--font-display); font-style: italic; font-optical-sizing: auto;
  font-size: var(--d-sub); font-weight: 400;
  line-height: 1; letter-spacing: -.02em; color: var(--ink);
}
.stat b sup { font-size: .5em; font-style: normal; color: var(--accent); vertical-align: super; }
/* direct child only — keeps the nested #expYears counter in the display face */
.stat > span {
  display: block;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 500;
  letter-spacing: .13em; text-transform: uppercase; color: var(--dim);
}

/* ---------- 11. ABOUT ---------- */
.about-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
.about-copy p { font-size: var(--t-ui); line-height: 1.78; color: var(--muted); margin-bottom: 1.125rem; text-wrap: pretty; }
.about-copy p:last-child { margin-bottom: 0; }
.about-copy strong { color: var(--ink); font-weight: 600; }

.about-aside { display: flex; flex-direction: column; gap: 1rem; }

/* The two supporting photographs carried over from the old About page. They sit
   below the copy so the section still opens on the argument, not on decoration —
   and they give a long text block somewhere to rest the eye. */
.about-media {
  display: grid; grid-template-columns: 1.35fr 1fr;
  gap: var(--gap); margin-top: clamp(2rem, 4vw, 3rem);
}
.about-media figure {
  overflow: hidden; border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--paper-raised);
}
.about-media img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  transition: transform .7s var(--ease-out);
}
.about-media figure:hover img { transform: scale(1.03); }
.about-media figcaption {
  padding: .75rem 1rem;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase; color: var(--dim);
}
.chip-card, .stack-card {
  padding: 1.375rem 1.375rem 1.5rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.chip-card h3, .stack-card h3 {
  font-family: var(--font-grot); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--dim); margin-bottom: 1rem;
}
/* Inside the single glance card, a second small-caps label introduces the
   community rows, with the chip row's bottom border acting as the divider. */
.glance-sub {
  font-family: var(--font-grot); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--dim);
  margin: 1.25rem 0 .15rem;
}
.about-aside .chip-row {
  padding-bottom: 1.125rem;
  border-bottom: 1px solid var(--line);
}
.chip-row { display: flex; flex-wrap: wrap; gap: .4rem; }
.chip {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .35rem .65rem; border-radius: 999px;
  background: var(--accent-soft); border: 1px solid transparent;
  font-size: var(--t-sm); color: var(--ink-soft);
  transition: border-color .2s var(--ease-out), color .2s var(--ease-out);
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip i { font-size: .3rem; color: var(--accent); }

.stack-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: .6rem 0; border-bottom: 1px solid var(--line);
  font-size: .8125rem;
}
.stack-row:last-child { border-bottom: 0; padding-bottom: 0; }
.stack-row:first-of-type { padding-top: 0; }
.stack-row b { font-family: var(--font-grot); font-weight: 600; color: var(--ink); flex: none; }
.stack-row span {
  font-family: var(--font-mono); font-size: .625rem; color: var(--dim);
  letter-spacing: .04em; text-align: right;
}

/* ---------- 12. EXPERIENCE ---------- */
.exp-grid {
  display: grid;
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.exp-rail { position: relative; }
.exp-rail-inner {
  position: sticky; top: calc(var(--nav-h) + 2.5rem);
}
.exp-rail-inner h3 { margin-bottom: 1rem; }
.exp-rail-inner p { font-size: var(--t-base); color: var(--muted); line-height: 1.72; }

.exp-list { display: flex; flex-direction: column; gap: 1rem; }
.exp-card {
  padding: 1.5rem 1.625rem 1.625rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: border-color .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.exp-card:hover { border-color: var(--line-hi); box-shadow: var(--shadow-md); }
.exp-head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: .5rem 1.25rem;
  padding-bottom: 1.125rem; margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.exp-co {
  font-family: var(--font-display); font-style: italic; font-optical-sizing: auto;
  font-size: 1.375rem; font-weight: 400; letter-spacing: -.018em; color: var(--ink);
}
.exp-when {
  font-family: var(--font-mono); font-size: .625rem; font-weight: 500;
  letter-spacing: .09em; text-transform: uppercase; color: var(--accent);
}
.exp-role-list { display: flex; flex-direction: column; gap: 1.5rem; }
.exp-role-top {
  display: flex; align-items: baseline; gap: .75rem; flex-wrap: wrap;
  margin-bottom: .4rem;
}
.exp-role-name {
  font-family: var(--font-grot); font-size: var(--t-ui); font-weight: 600;
  letter-spacing: var(--ls-snug); color: var(--ink); flex: 1 1 14rem; line-height: 1.4;
}
.exp-role-when {
  flex: none;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 500;
  letter-spacing: .09em; text-transform: uppercase; color: var(--dim);
}
.exp-role-desc {
  font-size: var(--t-base); line-height: 1.72; color: var(--muted);
  max-width: 62ch; text-wrap: pretty;
}

/* ---------- 13. AWARDS ---------- */
.awards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(290px, 100%), 1fr));
  gap: 0 var(--gap);
  border-top: 1px solid var(--line);
}
.award {
  display: flex; align-items: flex-start; gap: 1rem;
  padding: 1.125rem .25rem;
  border-bottom: 1px solid var(--line);
  transition: background-color .25s var(--ease-out);
}
.award:hover { background: var(--accent-fill); }
.award-year {
  flex: none; width: 3.25rem; padding-top: .1rem;
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .06em; color: var(--accent);
}
.award-title {
  font-size: var(--t-base); line-height: 1.5; color: var(--muted);
  display: flex; flex-direction: column; gap: .15rem;
}
.award-title b {
  font-family: var(--font-grot); font-size: var(--t-ui); font-weight: 600;
  letter-spacing: var(--ls-snug); color: var(--ink); line-height: 1.35;
}

/* Curated wall, continued: the disclosure row folds 11 earlier awards and
   internal certificates out of the default view. Native <details>, so it works
   with JavaScript off — and its summary needs the UA marker hiding because it
   already carries its own chevron. */
.awards-more summary {
  display: flex; align-items: center; gap: .625rem;
  width: 100%; min-height: 48px; padding: .375rem .25rem;
  cursor: pointer; list-style: none;
  font-family: var(--font-mono); font-size: .6875rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
  transition: color .2s var(--ease-out);
}
.awards-more summary::-webkit-details-marker { display: none; }
.awards-more summary:hover { color: var(--accent); }
.awards-more .chev {
  font-size: .625rem; color: var(--dim);
  transition: transform .2s var(--ease-out), color .2s var(--ease-out);
}
.awards-more[open] .chev { transform: rotate(180deg); color: var(--accent); }
.awards-more[open] summary { color: var(--accent); }
/* The folded grid's own border-top is the separator; no extra rule needed. */
.awards-more .awards-grid { border-top: 0; border-bottom: 1px solid var(--line); }

/* ---------- 14. WORK ---------- */
.work-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
  gap: var(--gap);
}
.work-card {
  display: flex; flex-direction: column;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  overflow: hidden;
  transition: transform .28s var(--ease-out), border-color .28s var(--ease-out),
              box-shadow .28s var(--ease-out);
}
.work-card:hover { transform: translateY(-3px); border-color: var(--ink); box-shadow: var(--shadow-md); }
/* feature card — spans two columns on wide screens */
.work-card.wide { grid-column: span 2; }
.work-card.wide .work-visual { min-height: 168px; }
.work-visual {
  position: relative;
  display: grid; place-items: center;
  min-height: 132px; padding: 1.25rem;
  background: var(--paper-sunk);
  border-bottom: 1px solid var(--line);
  color: var(--ink-soft);
  overflow: hidden;
}
.work-visual-glyph { display: grid; place-items: center; opacity: .85; transition: transform .4s var(--ease-out); }
.work-visual svg { stroke: currentColor; fill: none; }
.work-card:hover .work-visual-glyph { transform: scale(1.06) rotate(-2deg); }
.work-tag {
  position: absolute; top: .875rem; left: 1rem;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase; color: var(--dim);
}
.work-body { display: flex; flex-direction: column; flex: 1; padding: 1.375rem 1.5rem 1.5rem; }
.work-body h3 {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: 1.125rem; font-weight: 500; letter-spacing: -.016em;
  line-height: 1.3; color: var(--ink); margin-bottom: .5rem;
}
.work-body p {
  font-size: .8125rem; line-height: 1.68; color: var(--muted);
  margin-bottom: auto; text-wrap: pretty;
}
.work-meta {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-top: 1.25rem; padding-top: .875rem; border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 500;
  letter-spacing: .11em; text-transform: uppercase; color: var(--dim);
}
.work-arrow {
  font-family: var(--font-grot); font-size: var(--t-base); letter-spacing: 0;
  color: var(--muted);
  transition: transform .28s var(--ease-out), color .28s var(--ease-out);
}
.work-card:hover .work-arrow { transform: translateX(4px); color: var(--accent); }

/* Dark plate variant (the "browse archive" tile) */
.plate {
  background: var(--plate); border-color: var(--plate);
  justify-content: space-between;
}
.plate .plate-kicker {
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--accent-on-plate);
  margin-bottom: .75rem;
}
.plate .plate-title {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: 1.375rem; font-weight: 400; letter-spacing: -.02em;
  color: var(--on-plate); margin-bottom: .5rem; line-height: 1.2;
}
.plate .plate-sub { font-size: .8125rem; line-height: 1.65; color: var(--on-plate-mut); }
.plate-ring {
  display: grid; place-items: center;
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid rgba(247,249,249,.32); color: var(--on-plate);
  transition: transform .3s var(--ease-out), background-color .3s var(--ease-out),
              border-color .3s var(--ease-out);
}
.plate:hover .plate-ring { background: var(--accent); border-color: var(--accent); transform: rotate(45deg); }

/* ---------- 16. CONTACT PLATE ---------- */
.contact-plate {
  position: relative; overflow: hidden; text-align: center;
  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 5vw, 3.5rem);
  background: var(--plate); border: 1px solid var(--plate);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}
.contact-plate::before {
  content: ''; position: absolute; top: -180px; left: 50%;
  width: 620px; height: 340px; transform: translateX(-50%);
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(214,67,16,.20), transparent);
}
.contact-h {
  position: relative;
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--d-sub-wide); font-weight: 400;
  letter-spacing: var(--ls-tight); line-height: 1.1;
  color: var(--on-plate); margin-bottom: 1rem; text-wrap: balance;
}
.contact-h em { font-style: italic; color: var(--accent); }
.contact-sub {
  position: relative;
  max-width: 46ch; margin: 0 auto 2.25rem;
  font-size: var(--t-ui); line-height: 1.72; color: var(--on-plate-mut);
}
.contact-links {
  position: relative;
  display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem;
}
.contact-link {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 42px; padding: .5rem 1rem; border-radius: 999px;
  border: 1px solid rgba(247,249,249,.2);
  font-family: var(--font-grot); font-size: .8125rem; font-weight: 500;
  color: var(--on-plate);
  transition: background-color .22s var(--ease-out), border-color .22s var(--ease-out),
              transform .22s var(--ease-out);
}
.contact-link:hover {
  background: var(--accent); border-color: var(--accent);
  color: #fff; transform: translateY(-2px);
}
.contact-link i { font-size: .8125rem; }

/* ---------- 17. FOOTER ---------- */
.footer { border-top: 1px solid var(--line); background: var(--paper-sunk); }
.footer-inner {
  width: 100%; max-width: var(--wrap); margin-inline: auto;
  padding: 2.5rem clamp(1.125rem, 4vw, 2.5rem);
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 1.5rem;
}
.footer-left { display: flex; align-items: center; gap: .875rem; }
.footer-mark {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 10px; flex: none;
  font-family: var(--font-logo); font-size: 1rem; font-weight: 400;
  letter-spacing: .05em; line-height: 1; padding-top: 2px;
  background: var(--ink); color: var(--paper);
}
.footer-meta { font-size: var(--t-sm); line-height: 1.55; color: var(--muted); }
.footer-links { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.footer-links a {
  /* Same 24px floor as .mono-link — these measured 18px tall. */
  display: inline-flex; align-items: center; min-height: 24px;
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
  transition: color .2s var(--ease-out);
}
.footer-links a:hover { color: var(--accent); }

/* ---------- 18. SUBPAGE CHROME ---------- */
.page-top { padding-top: calc(var(--nav-h) + clamp(2.5rem, 6vw, 4.5rem)) !important; }
.page-head { text-align: center; margin-bottom: 3rem; }
.page-head .section-label { justify-content: center; }
.page-head .section-label::before { display: none; }
.page-title {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--d-page);
  font-weight: 400; letter-spacing: -.032em; line-height: 1.05;
  color: var(--ink); margin-bottom: 1.125rem; text-wrap: balance;
}
.page-title em { font-style: italic; color: var(--accent); font-weight: 400; }
.page-lede {
  font-size: var(--t-ui); line-height: 1.74; color: var(--muted);
  max-width: 62ch; margin: 0 auto 1.875rem; text-wrap: pretty;
}
.page-lede strong { color: var(--ink); font-weight: 600; }
.meta-strip { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; }
.meta-pill {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .45rem .875rem; border-radius: 999px;
  background: var(--paper-raised); border: 1px solid var(--line);
  font-family: var(--font-mono); font-size: .625rem; font-weight: 500;
  letter-spacing: .09em; text-transform: uppercase; color: var(--muted);
}
.meta-pill i { font-size: var(--t-xs); color: var(--accent); }

/* In-page jump links in a subpage hero. The writing archive is ~24,000px tall,
   so the two destinations a reader actually wants need to be reachable without
   scrolling past the whole index. */
.page-jump {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: .5rem; margin-top: 1.5rem;
}
.page-jump a {
  display: inline-flex; align-items: center;
  min-height: 34px; padding: .35rem .875rem;
  border: 1px solid var(--line-hi); border-radius: 999px;
  font-family: var(--font-mono); font-size: .625rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
  transition: border-color .2s var(--ease-out), color .2s var(--ease-out),
              background-color .2s var(--ease-out);
}
.page-jump a:hover {
  border-color: var(--accent); color: var(--accent);
  background: var(--accent-fill);
}

.back-link {
  display: inline-flex; align-items: center; gap: .5rem;
  margin-bottom: 1.5rem; min-height: 24px;   /* measured 17px — see .mono-link */
  font-family: var(--font-mono); font-size: .625rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--dim);
  transition: color .2s var(--ease-out);
}
.back-link:hover { color: var(--accent); }
.last-updated {
  margin-top: 2.5rem; text-align: center;
  font-family: var(--font-mono); font-size: .625rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
}

/* ---------- 19. SEARCH ---------- */
.search-container { width: 100%; max-width: 46rem; margin-inline: auto; }
.search-box { position: relative; display: flex; align-items: center; }
.search-icon {
  position: absolute; left: 1.125rem; pointer-events: none;
  font-size: .8125rem; color: var(--dim);
}
.search-box input {
  width: 100%; min-height: 56px;
  padding: 0 5rem 0 3rem;
  background: var(--paper-raised); color: var(--ink);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  font-size: var(--t-ui);
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.search-box input::placeholder { color: var(--dim); }
.search-box input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.search-shortcut {
  position: absolute; right: 1rem;
  padding: .25rem .5rem; border: 1px solid var(--line-hi); border-radius: 5px;
  font-family: var(--font-mono); font-size: .5625rem; color: var(--dim);
}
.search-results {
  display: none; margin-top: 8px;
  max-height: 60vh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
}
.search-results.open { display: block; }
.search-result-item {
  display: flex; align-items: center; gap: 1rem;
  padding: .875rem 1.125rem;
  border-bottom: 1px solid var(--line); cursor: pointer;
  transition: background-color .15s var(--ease-out);
}
.search-result-item:last-child { border-bottom: 0; }
.search-result-item:hover { background: var(--accent-fill); }
.sr-icon {
  flex: none; display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 8px;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 700; color: #fff;
}
.sr-info { min-width: 0; flex: 1; }
.sr-title {
  font-size: var(--t-base); font-weight: 500; color: var(--ink);
  line-height: 1.4; margin-bottom: .2rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sr-meta { display: flex; gap: .75rem; font-family: var(--font-mono); font-size: .5625rem; color: var(--dim); }
.sr-tags { display: flex; gap: .3rem; flex: none; }
.sr-tag {
  padding: .18rem .45rem; border-radius: 4px; border: 1px solid var(--line);
  font-family: var(--font-mono); font-size: .5rem; color: var(--muted);
}
.search-empty { padding: 2.5rem 1.125rem; text-align: center; color: var(--muted); font-size: var(--t-base); }
.search-empty i { display: block; margin-bottom: .75rem; font-size: var(--t-xl); color: var(--dim); }

/* ---------- 20. FILTER CHIPS ---------- */
.filter-controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: .375rem;
  margin-bottom: 1rem;
}
/* JS hook — platform filter bar on latest-posts.html */
.platform-filters { margin-bottom: 1.5rem; }
.filter-group-label {
  margin-right: .375rem;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
}
.filter-btn, .topic-filter-btn {
  padding: .4rem .8rem; border-radius: 999px;
  background: transparent; border: 1px solid var(--line);
  font-size: var(--t-sm); font-weight: 500; color: var(--muted);
  transition: color .18s var(--ease-out), border-color .18s var(--ease-out),
              background-color .18s var(--ease-out);
}
.filter-btn:hover, .topic-filter-btn:hover { border-color: var(--ink); color: var(--ink); }
.filter-btn.active, .topic-filter-btn.active {
  background: var(--ink); border-color: var(--ink); color: var(--paper);
}
.topic-filters { display: flex; flex-wrap: wrap; gap: .375rem; }
.tf-count { margin-left: .25rem; font-family: var(--font-mono); font-size: .625rem; opacity: .65; }
.results-bar { margin: 1.5rem 0 1rem; }
.results-count {
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
}

/* ---------- 21. STAT / METRIC CARDS ---------- */
.citation-stats, .metrics-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(212px, 100%), 1fr)); gap: var(--gap);
}
.citation-stat, .metrics-card {
  position: relative;
  padding: 1.625rem 1.5rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: transform .24s var(--ease-out), border-color .24s var(--ease-out),
              box-shadow .24s var(--ease-out);
}
.citation-stat:hover, .metrics-card:hover {
  transform: translateY(-2px); border-color: var(--ink); box-shadow: var(--shadow-md);
}
.stat-icon, .metrics-icon {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 9px; margin-bottom: 1.125rem;
  background: var(--accent-soft); color: var(--accent); font-size: var(--t-base);
}
.stat-number, .metrics-value {
  margin-bottom: .5rem;
  font-family: var(--font-display); font-style: italic; font-optical-sizing: auto;
  font-size: 2.25rem; font-weight: 400; line-height: 1; letter-spacing: -.02em;
  color: var(--ink);
}
.stat-label, .metrics-label {
  margin-bottom: .3rem;
  font-family: var(--font-grot); font-size: .8125rem; font-weight: 600;
  letter-spacing: -.01em; color: var(--ink-soft);
}
.stat-sub, .metrics-sub { font-size: var(--t-sm); line-height: 1.5; color: var(--dim); }
.stat-trend {
  position: absolute; top: 1.25rem; right: 1.25rem;
  font-family: var(--font-mono); font-size: .625rem; color: var(--emerald-ink);
}
.metrics-cta { margin-top: 1.75rem; font-size: var(--t-base); color: var(--muted); }
.metrics-cta a { color: var(--accent); border-bottom: 1px solid var(--accent-soft); }
.metrics-cta a:hover { border-bottom-color: var(--accent); }

/* ---------- 22. PUBLICATION CARDS ---------- */
.publications-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); gap: var(--gap);
}
/* Reveal control under the publications grid. The grid pages itself, so this is
   centred and rules-off rather than another card. */
.pub-more {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: center;
  gap: .625rem; margin-top: var(--gap);
  padding-top: var(--gap);
  border-top: 1px solid var(--line);
}
.pub-more-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .625rem 1.375rem;
  background: transparent; color: var(--ink);
  border: 1px solid var(--line-hi); border-radius: var(--r-sm);
  font-family: var(--font-grot); font-size: var(--t-sm); font-weight: 600;
  letter-spacing: .04em; cursor: pointer;
  transition: background-color .2s var(--ease-out), border-color .2s var(--ease-out);
}
.pub-more-btn:hover { background: var(--accent-fill); border-color: var(--accent); }
.pub-more-btn i { font-size: .625rem; }
.pub-more-note {
  margin: 0; color: var(--dim);
  font-family: var(--font-mono); font-size: var(--t-xs); letter-spacing: .04em;
  text-align: center;
}
.pub-more-note a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.pub-more-note a:hover { color: var(--ink); }
.pub-card {
  display: flex; flex-direction: column;
  padding: 1.5rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: transform .24s var(--ease-out), border-color .24s var(--ease-out),
              box-shadow .24s var(--ease-out);
}
.pub-card:hover { transform: translateY(-2px); border-color: var(--ink); box-shadow: var(--shadow-md); }
.pub-top { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .875rem; }
.pub-year-badge {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .25rem .55rem; border-radius: 5px; border: 1px solid var(--line);
  font-family: var(--font-mono); font-size: .5625rem; color: var(--muted);
}
.pub-platform-badge {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .25rem .55rem; border-radius: 5px;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600; letter-spacing: .06em;
}
.pub-card h4 {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-md); font-weight: 500; letter-spacing: -.014em;
  line-height: 1.34; color: var(--ink); margin-bottom: .5rem; text-wrap: pretty;
  overflow-wrap: anywhere; /* same platform identifiers as .lpc-title */
}
.pub-authors { font-size: var(--t-sm); color: var(--muted); margin-bottom: .5rem; }
.pub-authors strong { color: var(--ink-soft); font-weight: 500; }
.pub-meta {
  display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: .625rem;
  font-family: var(--font-mono); font-size: .5625rem; color: var(--dim); letter-spacing: .04em;
}
.pub-meta span { display: inline-flex; align-items: center; gap: .3rem; }
.cite-badge { color: var(--accent) !important; }
.pub-abstract {
  flex: 1; margin-bottom: .875rem;
  font-size: .8125rem; line-height: 1.65; color: var(--muted); text-wrap: pretty;
}
.pub-tags { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .25rem; }
.pub-tag-topic, .pub-tag-type {
  padding: .2rem .5rem; border-radius: 4px;
  background: var(--paper-sunk);
  font-family: var(--font-mono); font-size: .5rem;
  letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--muted);
}
.pub-link, .cite-btn {
  display: inline-flex; align-items: center; gap: .4rem; align-self: flex-start;
  min-height: 36px; padding: .45rem .8rem; border-radius: 7px;
  border: 1px solid var(--line-hi); background: transparent;
  font-size: var(--t-sm); font-weight: 500; color: var(--ink-soft);
  transition: color .18s var(--ease-out), border-color .18s var(--ease-out);
}
.pub-link:hover, .cite-btn:hover { border-color: var(--ink); color: var(--ink); }

/* The other publications of a cross-posted article. Set apart from the card's
   action row because these are references, not calls to action -- the card
   already has a primary "Read Publication" link above. */
.pub-also {
  display: flex; flex-wrap: wrap; gap: .375rem;
  margin-top: .75rem; padding-top: .75rem;
  border-top: 1px dashed var(--line-hi);
}
.pub-also-link {
  display: inline-flex; align-items: baseline; gap: .375rem;
  padding: .25rem .5rem; border-radius: 5px;
  border: 1px solid var(--line-hi);
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
  text-decoration: none;
  transition: border-color .2s var(--ease-out), color .2s var(--ease-out);
}
.pub-also-link:hover { border-color: var(--ink); color: var(--ink); }
.pub-also-link i { font-size: .625rem; }
.pub-also-date { color: var(--dim); font-weight: 400; letter-spacing: .06em; }
/* An extra publication whose copy survives nowhere. Shown, because it happened,
   but not styled as something you can open: dashed edge, no hover change. */
.pub-also-link.is-gone { border-style: dashed; cursor: default; }
.pub-also-link.is-gone:hover { border-color: var(--line-hi); color: var(--muted); }

/* Journal articles that cite my work. Their authors own them, so the card
   leads with provenance rather than a byline of mine, and the "not my
   publication" cue is not decoration -- it is the point of the card. */
.jr-card { border-left: 4px solid #0f4c81; }
.jr-card .jr-owner { color: var(--accent); font-weight: 600; }
.jr-cites-label {
  margin: .25rem 0 .4rem;
  font-family: var(--font-mono); font-size: .5625rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--dim);
}
.jr-cites { margin: 0 0 .75rem; padding-left: 1.1rem; }
.jr-cites li { font-size: .8125rem; line-height: 1.55; color: var(--ink-soft); }
.jr-cites a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--line-hi); text-underline-offset: 2px; }
.jr-cites a:hover { text-decoration-color: var(--ink); }
.jr-where { color: var(--dim); font-family: var(--font-mono); font-size: .5625rem; }
/* The kind chip answers "what is this?" before the title is read. */
.jr-kind {
  align-self: center; margin-left: auto;
  padding: .18rem .4rem; border: 1px dashed var(--line-hi); border-radius: 4px;
  font-family: var(--font-mono); font-size: .5rem; letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--dim);
}
/* A patent family is several documents, so the card lists each one with its
   own link. The list is prose-sized because it is a reference, not a headline. */
.jr-docs { margin: 0 0 .75rem; padding-left: 1.1rem; }
.jr-docs li { font-size: .8125rem; line-height: 1.55; color: var(--ink-soft); }
.jr-docs a {
  color: var(--ink); font-family: var(--font-mono); font-size: .75rem;
  text-decoration: underline; text-decoration-color: var(--line-hi); text-underline-offset: 2px;
}
.jr-docs a:hover { text-decoration-color: var(--ink); }
.jr-note {
  margin: 0 0 .875rem; padding: .5rem .65rem;
  border-radius: 5px; background: var(--paper-sunk);
  font-size: .75rem; line-height: 1.55; color: var(--muted);
}
.jr-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: auto; }

/* A card for one of the DZone guides that were unpublished. It is not a button
   and does not pretend to be one — it replaces the "Read Publication" link so
   the card's action row does not read as broken. The explanation lives in the
   hover title, not in sight of every reader. */
.pub-gone-note {
  display: inline-flex; align-items: center; gap: .4rem; align-self: flex-start;
  min-height: 36px; padding: .45rem .8rem; border-radius: 7px;
  border: 1px dashed var(--line-hi);
  font-size: var(--t-sm); color: var(--dim);
}

/* ---------- 23. PLATFORM REACH ---------- */
.platform-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr)); gap: var(--gap); }
.platform-card {
  display: flex; align-items: center; gap: .875rem;
  padding: 1.125rem 1.25rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-sm);
  box-shadow: var(--shadow-sm);
  transition: transform .24s var(--ease-out), border-color .24s var(--ease-out),
              box-shadow .24s var(--ease-out);
}
.platform-card:hover { transform: translateY(-2px); border-color: var(--ink); box-shadow: var(--shadow-md); }
.p-icon {
  flex: none; display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: 9px;
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 700; color: #fff;
}
.p-body { min-width: 0; }
.p-body h4 {
  font-family: var(--font-grot); font-size: var(--t-base); font-weight: 600;
  color: var(--ink); margin-bottom: .2rem;
}
.p-stat {
  font-family: var(--font-display); font-style: italic; font-optical-sizing: auto;
  font-size: 1.125rem; color: var(--accent); line-height: 1.2;
}
.p-label {
  font-family: var(--font-mono); font-size: .5625rem;
  color: var(--dim); letter-spacing: .05em;
}

/* ---------- 24. TOPIC EXPLORER ---------- */
.topic-explorer { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: var(--gap); }
.topic-explorer-item {
  padding: 1.25rem; text-align: center;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-sm);
  cursor: pointer;
  transition: transform .24s var(--ease-out), border-color .24s var(--ease-out),
              box-shadow .24s var(--ease-out);
}
.topic-explorer-item:hover { transform: translateY(-2px); border-color: var(--accent); box-shadow: var(--shadow-md); }
.te-icon { margin-bottom: .625rem; font-size: 1.125rem; color: var(--accent); }
.topic-explorer-item h5 {
  font-size: .8125rem; font-weight: 600; color: var(--ink); margin-bottom: .25rem;
}
.te-count {
  font-family: var(--font-mono); font-size: .5625rem;
  color: var(--dim); letter-spacing: .06em;
}

/* ---------- 25. READING PATHS ---------- */
.reading-paths { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); gap: var(--gap); }
.reading-path-card {
  padding: 1.625rem 1.5rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: transform .24s var(--ease-out), border-color .24s var(--ease-out),
              box-shadow .24s var(--ease-out);
}
.reading-path-card:hover { transform: translateY(-2px); border-color: var(--ink); box-shadow: var(--shadow-md); }
.reading-path-card h4 {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-lg); font-weight: 500; letter-spacing: -.016em;
  color: var(--ink); margin-bottom: .625rem;
}
.reading-path-card p { font-size: .8125rem; line-height: 1.65; color: var(--muted); margin-bottom: 1rem; }
.rp-count {
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--accent);
}

/* ---------- 26. TRENDING ---------- */
.trending-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: var(--gap); }
.trending-item {
  display: flex; align-items: center; gap: 1rem;
  padding: 1.125rem 1.25rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-sm);
  box-shadow: var(--shadow-sm);
  transition: transform .24s var(--ease-out), border-color .24s var(--ease-out),
              box-shadow .24s var(--ease-out);
}
.trending-item:hover { transform: translateY(-2px); border-color: var(--ink); box-shadow: var(--shadow-md); }
.ti-rank {
  flex: none; display: grid; place-items: center;
  width: 36px; height: 36px; border-radius: 8px;
  font-family: var(--font-display); font-style: italic; font-size: 1rem;
  background: var(--accent-soft); color: var(--accent);
}
.ti-info { min-width: 0; flex: 1; }
.ti-title {
  margin-bottom: .25rem;
  font-size: .8125rem; font-weight: 500; color: var(--ink); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ti-meta { display: flex; gap: .625rem; font-family: var(--font-mono); font-size: .5625rem; color: var(--dim); letter-spacing: .06em; }
.ti-views {
  flex: none; display: flex; align-items: center; gap: .35rem;
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--muted);
}

/* ---------- 27. CHART ---------- */
.chart-section {
  padding: 2.25rem 1.75rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.chart-bars {
  display: flex; align-items: flex-end; justify-content: center; gap: 2rem;
  min-height: 200px; padding-bottom: 1rem;
  border-bottom: 1px solid var(--line);
}
.chart-bar-group { display: flex; flex-direction: column; align-items: center; gap: .625rem; }
.bar-value {
  font-family: var(--font-display); font-style: italic;
  font-size: 1.375rem; color: var(--accent);
}
.bar { width: 56px; border-radius: 6px 6px 0 0; background: linear-gradient(180deg, var(--orange-light), var(--orange)); }
.bar-label {
  font-family: var(--font-mono); font-size: .625rem;
  color: var(--dim); letter-spacing: .1em;
}
.chart-legend {
  display: flex; gap: 1.5rem; justify-content: center; margin-top: 1.125rem;
  font-family: var(--font-mono); font-size: .625rem; color: var(--muted); letter-spacing: .06em;
}
.chart-legend span { display: inline-flex; align-items: center; gap: .45rem; }
.legend-dot { width: 9px; height: 9px; border-radius: 2px; }

/* ---------- 28. KNOWLEDGE GRAPH ---------- */
.knowledge-graph-container {
  position: relative; padding: 1.5rem;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.kg-overlay {
  position: absolute; top: 1.25rem; left: 1.5rem;
  display: flex; flex-direction: column; gap: .5rem; pointer-events: none;
}
.kg-label {
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase; color: var(--dim);
}
.kg-legend { display: flex; flex-wrap: wrap; gap: .75rem; max-width: 60%; }
.kg-legend-item {
  display: inline-flex; align-items: center; gap: .35rem;
  font-family: var(--font-mono); font-size: .5rem; color: var(--muted);
}
.kg-dot { width: 7px; height: 7px; border-radius: 50%; }

/* ---------- 29. INTEREST TAGS ---------- */
.research-interests { display: flex; flex-wrap: wrap; gap: .5rem; }
.interest-tag {
  padding: .5rem .875rem; border-radius: 999px;
  background: var(--paper-raised); border: 1px solid var(--line-hi);
  font-size: .8125rem; color: var(--ink-soft);
  transition: color .2s var(--ease-out), border-color .2s var(--ease-out),
              transform .2s var(--ease-out);
}
.interest-tag:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }

/* ---------- 30. CITATION MODAL ---------- */
.citation-modal {
  position: fixed; inset: 0; z-index: 1000;
  display: none; place-items: center; padding: 1.5rem;
  background: rgba(8,10,13,.66);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.citation-modal.active { display: grid; }
.citation-modal-content {
  width: min(620px, 100%); max-height: 88vh; overflow-y: auto;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}
.citation-modal-header {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--line);
}
.citation-modal-header h3 {
  display: flex; align-items: center; gap: .5rem;
  font-family: var(--font-grot); font-size: 1rem; font-weight: 600; color: var(--ink);
}
.citation-modal-close {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 7px;
  border: 1px solid var(--line); color: var(--muted);
  transition: color .18s var(--ease-out), border-color .18s var(--ease-out);
}
.citation-modal-close:hover { border-color: var(--ink); color: var(--ink); }
.citation-modal-body { padding: 1.5rem; }
.cite-title {
  margin-bottom: .375rem;
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-lg); font-weight: 500; letter-spacing: -.016em;
  color: var(--ink); line-height: 1.3;
}
.cite-authors { font-size: .8125rem; color: var(--muted); margin-bottom: 1.25rem; }
.citation-format-tabs { display: flex; flex-wrap: wrap; gap: .375rem; margin-bottom: 1rem; }
.citation-format-tab {
  padding: .375rem .7rem; border-radius: 6px;
  background: transparent; border: 1px solid var(--line);
  font-family: var(--font-mono); font-size: .625rem; color: var(--muted);
  transition: color .18s var(--ease-out), border-color .18s var(--ease-out),
              background-color .18s var(--ease-out);
}
.citation-format-tab:hover { border-color: var(--ink); color: var(--ink); }
.citation-format-tab.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.citation-text {
  width: 100%; min-height: 150px; padding: .875rem 1rem; resize: vertical;
  background: var(--paper); color: var(--ink-soft);
  border: 1px solid var(--line-hi); border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: var(--t-sm); line-height: 1.7;
}
.citation-text:focus { outline: none; border-color: var(--accent); }
.citation-actions { display: flex; gap: .5rem; margin-top: 1rem; }
.cite-copy-btn, .cite-download-btn {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 40px; padding: .5rem 1rem; border-radius: 7px;
  font-size: .8125rem; font-weight: 500;
  transition: background-color .18s var(--ease-out), border-color .18s var(--ease-out),
              color .18s var(--ease-out);
}
.cite-copy-btn { background: var(--ink); border: 1px solid var(--ink); color: var(--paper); }
.cite-copy-btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.cite-copy-btn.copied { background: var(--emerald); border-color: var(--emerald); color: #fff; }
.cite-download-btn { background: transparent; border: 1px solid var(--line-hi); color: var(--ink-soft); }
.cite-download-btn:hover { border-color: var(--ink); color: var(--ink); }

/* ---------- 31. ARTICLE INDEX ----------
   The earlier build listed writing as a dated index row — date | title |
   platform, separated by hairlines — and that was the better idea, so it is
   what came forward. A uniform card grid turns 83 publications into a wall;
   an index reads like a journal's contents and lets a reader scan titles and
   dates at a glance. The rows also carry the summaries the cards had, so
   nothing was traded away to get the density back. */

/* One toolbar for the three ways of navigating the index. Grouping them means
   the reader learns the controls once, and on desktop the bar stays pinned
   below the nav while the 283 rows scroll past. */
.archive-toolbar {
  margin: 0 0 1.75rem; padding: 1rem 1.125rem;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--paper-raised);
}
.archive-toolbar-top {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem 1.5rem; flex-wrap: wrap;
}
.archive-toolbar .filter-controls { margin: 0; flex: 1 1 32rem; }
.archive-toolbar .filter-result { margin-left: auto; padding-left: 0; }
.archive-toolbar .year-rail { margin: 1rem 0 0; }
.archive-toolbar .density-toggle { margin: 0; flex: none; }

@media (min-width: 861px) {
  .archive-toolbar {
    position: sticky; top: var(--nav-h); z-index: 20;
    box-shadow: var(--shadow-sm);
    background: color-mix(in srgb, var(--paper-raised) 94%, transparent);
    -webkit-backdrop-filter: blur(10px);
            backdrop-filter: blur(10px);
  }
  /* The sticky toolbar sits over the top of the index, so a year link needs
     enough run-up that its heading lands below both the nav and the toolbar
     instead of underneath them. */
  .year-group, .era-band { scroll-margin-top: calc(var(--nav-h) + 9rem); }
}

.archive-top { margin-top: 2rem; text-align: right; }
.archive-top a {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 32px;
  font-family: var(--font-mono); font-size: .625rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
  transition: color .2s var(--ease-out);
}
.archive-top a:hover { color: var(--accent); }

.article-index { display: block; }
.year-group + .year-group { margin-top: clamp(2.25rem, 5vw, 3.5rem); }
.year-head {
  display: flex; align-items: baseline; gap: 1rem;
  margin: 0 0 .25rem; padding-bottom: .75rem;
  border-bottom: 1px solid var(--line-hi);
}
.year-num {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-xl); font-weight: 400; letter-spacing: -.02em;
  color: var(--accent); font-variant-numeric: lining-nums;
}
.year-rule { flex: 1; }
.year-count {
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: .14em; text-transform: uppercase; color: var(--dim);
}

/* One row: fixed date rail, fluid title+abstract, fixed platform rail.
   `minmax(0,1fr)` on the middle so a long title shrinks instead of pushing
   the platform column past the viewport. */
.latest-post-card {
  display: grid;
  grid-template-columns: 5.75rem minmax(0, 1fr) 6.5rem;
  gap: 0 1.5rem; align-items: start;
  padding: 1.375rem .75rem 1.375rem .25rem;
  border-bottom: 1px solid var(--line);
  transition: background-color .2s var(--ease-out);
}
.latest-post-card:last-child { border-bottom: 0; }
.latest-post-card:hover { background: var(--accent-fill); }

/* ---- Era bands ----
   Years are grouped into three bands where the character of the work changes.
   The band is the page's primary structure: it is what tells a reader looking
   at 300 rows that the 2010s and the 2020s are not the same body of writing.
   The button resets the UA appearance because it wraps display text and must not
   carry a border or background of its own. */
.era-band + .era-band { margin-top: clamp(2.5rem, 5vw, 4rem); }
.era-head {
  display: flex; align-items: center; gap: 1rem; width: 100%;
  margin: 0 0 1.25rem; padding: 0 0 .875rem;
  border: 0; border-bottom: 2px solid var(--ink);
  background: none; color: inherit; text-align: left; cursor: pointer;
  font: inherit;
}
.era-head:hover .era-label { color: var(--accent); }
.era-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.era-chevron {
  flex: none; display: grid; place-items: center;
  width: 1.75rem; height: 1.75rem; border-radius: 50%;
  border: 1px solid var(--line-hi); color: var(--dim);
  font-size: .6875rem;
  transition: transform .2s var(--ease-out), border-color .2s var(--ease-out),
              color .2s var(--ease-out);
}
.era-head:hover .era-chevron { border-color: var(--accent); color: var(--accent); }
.era-band.is-collapsed .era-chevron { transform: rotate(-90deg); }
/* A word beside the count so the band reads as a control, not a heading. */
.era-toggle-label {
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent);
}
.era-text { display: block; min-width: 0; flex: 1; }
.era-label {
  display: block;
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-lg); font-weight: 400; letter-spacing: -.018em;
  line-height: 1.2; color: var(--ink);
  transition: color .2s var(--ease-out);
}
.era-blurb {
  display: block; margin-top: .1875rem;
  font-size: var(--t-sm); line-height: 1.5; color: var(--muted);
}
/* The span is data, the count is chrome, so they get separate treatments and
   wrap as a unit rather than as two loose words. */
.era-meta {
  flex: none; display: flex; align-items: baseline; gap: .75rem;
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: .12em; text-transform: uppercase; color: var(--dim);
}
.era-span { color: var(--ink); }
.era-count { white-space: nowrap; }
/* Collapsed, the band keeps its heading and drops its years. */
.era-band.is-collapsed .era-body { display: none; }

/* ---- Year rail ----
   Seventeen year headings and 300+ rows leaves scrolling as the only way to
   move between them. This is the fix: every year in one horizontal strip. It
   scrolls itself horizontally on overflow, so the counts stay reachable at
   320px without wrapping into a second row of chrome. */
.year-rail {
  display: flex; gap: .25rem; align-items: stretch;
  margin: 0 0 1.5rem; padding: .375rem;
  overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: thin;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--paper-raised);
}
.year-rail:empty { display: none; }
.year-pip {
  flex: none; display: flex; flex-direction: column; align-items: center; gap: .0625rem;
  padding: .3125rem .4375rem; border-radius: 4px;
  text-decoration: none; color: var(--dim);
  transition: background-color .2s var(--ease-out), color .2s var(--ease-out);
}
.year-pip:hover { background: var(--accent-fill); color: var(--ink); }
.year-pip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.year-pip.is-active { background: var(--ink); color: var(--paper); }
.year-pip-num {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .06em; font-variant-numeric: tabular-nums;
}
.year-pip-n {
  font-family: var(--font-mono); font-size: .5rem; letter-spacing: .1em;
  opacity: .62; font-variant-numeric: tabular-nums;
}

/* ---- Density ----
   Comfortable is the default and keeps the abstract. Compact drops it, which is
   what makes the whole 300-row index scannable in one screen of titles when
   someone is looking for one specific piece rather than browsing. */
.density-toggle {
  display: flex; gap: .375rem; align-items: center;
  margin: 0 0 1.25rem;
}
.density-btn {
  padding: .3125rem .75rem; border: 1px solid var(--line-hi); border-radius: 999px;
  background: none; cursor: pointer;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--dim);
  transition: border-color .2s var(--ease-out), color .2s var(--ease-out),
              background-color .2s var(--ease-out);
}
.density-btn:hover { border-color: var(--ink); color: var(--ink); }
.density-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.density-btn.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }

html[data-index-density="compact"] .lpc-summary { display: none; }
html[data-index-density="compact"] .latest-post-card { padding: .625rem .75rem .625rem .25rem; }
html[data-index-density="compact"] .lpc-title { margin-bottom: 0; font-size: var(--t-sm); }
html[data-index-density="compact"] .year-group + .year-group { margin-top: 1.5rem; }

/* Rows whose article is no longer online. Kept in the index and visibly
   distinct: dimmed, no hover fill, and no pointer cursor, so it never reads as
   something that can be opened. `cursor: default` is the honest signal. */
.latest-post-card.is-unlinked { cursor: default; }
.latest-post-card.is-unlinked:hover { background: none; }
.latest-post-card.is-unlinked .lpc-title { color: var(--muted); }
.latest-post-card.is-unlinked .lpc-date { opacity: .8; }
.lpc-gone {
  grid-column: 3; justify-self: end; align-self: start;
  display: inline-flex; align-items: center; gap: .3125rem;
  font-family: var(--font-mono); font-size: .5rem; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase; color: var(--dim);
  white-space: nowrap;
}
.lpc-platforms + .lpc-gone { margin-top: .25rem; }

/* Result count sits at the end of the filter row. aria-live is on the element so
   a screen reader hears the new total when a filter is applied. */
.filter-result {
  margin-left: auto; padding-left: 1rem;
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
  white-space: nowrap;
}
.lpc-date {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
  padding-top: .2rem; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.lpc-main { display: block; min-width: 0; }
.lpc-title {
  display: block; margin-bottom: .4375rem;
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: 1.125rem; font-weight: 500; letter-spacing: -.014em;
  line-height: 1.34; color: var(--ink); text-wrap: pretty;
  /* Titles come verbatim from six publishing platforms, so they carry
     identifiers like RSRC_INSUFFICIENT_REQ_MEMORY that have no break
     opportunity. Without this one 29-char token pushed the whole index 7px
     wider than a 320px viewport, giving the page a horizontal scrollbar. */
  overflow-wrap: anywhere;
  transition: color .2s var(--ease-out);
}
.latest-post-card:hover .lpc-title { color: var(--accent); }
/* Abstract so a row is scannable without opening the article. Two lines is
   enough to judge relevance and keeps the whole index a predictable rhythm. */
.lpc-summary {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; max-width: 68ch;
  font-size: var(--t-base); line-height: 1.62; color: var(--muted); text-wrap: pretty;
}
/* Venue rail. Most rows carry one venue; a cross-posted article stacks two or
   three, so the column stays 6.5rem wide no matter how often an article ran.
   Colour is keyed per-venue off data-venue rather than the row, because a row
   can now hold more than one venue at once. */
.lpc-platforms {
  justify-self: end; display: flex; flex-direction: column;
  align-items: flex-end; gap: .25rem;
}
.lpc-platform-name {
  text-align: right;
  padding: .22rem .55rem; border-radius: 4px;
  font-family: var(--font-mono); font-size: .625rem; font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase; color: var(--dim);
  transition: background-color .2s var(--ease-out), color .2s var(--ease-out);
}
/* Secondary venues step back so the primary one leads the eye. */
.lpc-platform-name[data-more] { opacity: .68; }
.lpc-platform-name[data-venue="DZone"]  { background: var(--orange-fill);  color: var(--orange-ink); }
.lpc-platform-name[data-venue="Medium"] { background: var(--emerald-fill); color: var(--emerald-ink); }
/* The legacy guides get a neutral slate rather than DZone's orange. They were
   published on DZone, so orange would read as "live and clickable", which is
   precisely the wrong signal -- 40 of these 49 rows have nothing to open. The
   selector also has to match the attribute in full: without the surrounding
   quotes a multi-word value like "DZone Legacy" is not a valid identifier and
   the rule would silently never match. */
.lpc-platform-name[data-venue="DZone Legacy"] { background: var(--slate-fill); color: var(--slate-ink); }
.lpc-platform-name[data-venue="Chatbots Life"] { background: var(--violet-fill); color: var(--violet-ink); }
/* A row whose only venue is a legacy guide should not read as a row you can
   open, so its venue pill is the one thing allowed to keep full contrast. */
.lpc-gone-row .lpc-platform-name { opacity: 1; }

/* ---- Talks & panels ----
   A dated, sourced list rather than cards: every row is one engagement with a
   fixed date in a fixed rail, so the list reads as a chronology and stays
   scannable as it grows. The source link is styled as evidence, not as a
   second call to action -- the title already goes to the session itself. */
.talk-list { list-style: none; margin: 0; padding: 0; }
.talk-item {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  gap: .25rem 1.5rem;
  padding: 1.25rem 0;
  border-top: 1px solid var(--line);
}
.talk-item:first-child { border-top: 0; padding-top: 0; }
.talk-rail { display: flex; flex-direction: column; gap: .3125rem; }
.talk-when {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-lg); letter-spacing: -.01em; color: var(--accent);
  font-variant-numeric: lining-nums;
}
/* Kind is the one categorical fact per row, so it carries the only fill on the
   card: a pill makes Talk / Panel / Webinar scannable down the rail. */
.talk-kind {
  align-self: flex-start;
  padding: .1875rem .4375rem; border-radius: 3px;
  border: 1px solid var(--line-hi);
  font-family: var(--font-mono); font-size: .5rem; font-weight: 600;
  letter-spacing: .11em; text-transform: uppercase; color: var(--muted);
}
.talk-item[data-kind="Panel"] .talk-kind { background: var(--accent-fill); color: var(--accent); border-color: transparent; }
.talk-main { min-width: 0; }
.talk-title {
  margin: 0 0 .1875rem; font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-lg); font-weight: 400; letter-spacing: -.015em; line-height: 1.28;
}
.talk-title a { color: var(--ink); text-decoration: none; }
.talk-title a:hover { color: var(--accent); }
.talk-venue {
  margin: 0 0 .125rem;
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: .06em; text-transform: uppercase; color: var(--dim);
}
.talk-role { margin: 0; font-size: var(--t-sm); font-weight: 600; color: var(--ink-soft); }
.talk-detail {
  margin: .4375rem 0 0; max-width: 62ch;
  font-size: var(--t-sm); line-height: 1.6; color: var(--muted); text-wrap: pretty;
}
/* Footer of a row: the link that settles the entry. */
.talk-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem;
  margin: .625rem 0 0;
}
.talk-source {
  display: inline-flex; align-items: center; gap: .3125rem;
  font-family: var(--font-mono); font-size: .5625rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim); text-decoration: none;
  transition: color .2s var(--ease-out);
}
.talk-source:hover { color: var(--accent); }
.talk-source i { font-size: .5rem; }

/* ---------- 33. BLOG VENUES ---------- */
.venue-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap); }
.venue {
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: transform .28s var(--ease-out), border-color .28s var(--ease-out),
              box-shadow .28s var(--ease-out);
}
.venue:hover { transform: translateY(-3px); border-color: var(--ink); box-shadow: var(--shadow-md); }
.venue-head {
  display: flex; align-items: center; gap: .625rem;
  padding: 1.125rem 1.25rem; border-bottom: 1px solid var(--line);
}
.venue-mark {
  flex: none; display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 8px;
  font-family: var(--font-mono); font-size: .625rem; font-weight: 700; color: #fff;
}
.venue-name {
  font-family: var(--font-grot); font-size: var(--t-ui); font-weight: 600;
  color: var(--ink); letter-spacing: var(--ls-snug);
}
.venue-badge {
  flex: none; margin-left: auto;
  font-family: var(--font-mono); font-size: .5rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--dim);
}
.venue-body { display: flex; flex-direction: column; flex: 1; padding: 1.25rem; }
.venue-body h3 {
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--t-md); font-weight: 500; letter-spacing: -.014em;
  line-height: 1.3; color: var(--ink); margin-bottom: .5rem;
}
.venue-body p {
  font-size: .8125rem; line-height: 1.65; color: var(--muted);
  margin-bottom: 1rem; text-wrap: pretty;
}
.venue-body code {
  padding: .1rem .3rem; border-radius: 4px;
  background: var(--paper-sunk); color: var(--ink-soft);
}
.venue-stat {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-top: auto; padding-top: .875rem; border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: .625rem; color: var(--dim); letter-spacing: .06em;
}
.venue-stat b {
  font-family: var(--font-display); font-style: italic;
  font-size: 1.125rem; color: var(--accent); font-weight: 400;
}

/* ---------- 34. SCHOLAR CTA ---------- */
.scholar-cta {
  position: relative; overflow: hidden; text-align: center;
  padding: clamp(2.5rem, 6vw, 3.25rem) 2.5rem;
  background: var(--plate); border: 1px solid var(--plate);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
}
.scholar-cta::before {
  content: ''; position: absolute; top: -150px; left: 50%;
  width: 560px; height: 320px; transform: translateX(-50%); pointer-events: none;
  background: radial-gradient(closest-side, rgba(214,67,16,.18), transparent);
}
.scholar-cta h3 {
  position: relative;
  font-family: var(--font-display); font-optical-sizing: auto;
  font-size: var(--d-card); font-weight: 400;
  letter-spacing: -.024em; color: var(--on-plate); margin-bottom: .75rem;
}
.scholar-cta p {
  position: relative; max-width: 48ch; margin: 0 auto 1.75rem;
  font-size: var(--t-base); line-height: 1.7; color: var(--on-plate-mut);
}
.cta-btn {
  position: relative;
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px; padding: .65rem 1.5rem; border-radius: 8px;
  background: var(--on-plate); color: var(--plate);
  font-family: var(--font-grot); font-size: var(--t-base); font-weight: 600;
  transition: background-color .2s var(--ease-out), color .2s var(--ease-out);
}
.cta-btn:hover { background: var(--accent); color: #fff; }

/* ---------- 35. PHOTO GALLERY ---------- */
.gallery { columns: 3; column-gap: var(--gap); }
.gallery figure {
  break-inside: avoid; margin: 0 0 var(--gap);
  overflow: hidden;
  background: var(--paper-raised);
  border: 1px solid var(--line-hi); border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  transition: transform .3s var(--ease-out), border-color .3s var(--ease-out),
              box-shadow .3s var(--ease-out);
}
.gallery figure:hover { transform: translateY(-3px); border-color: var(--ink); box-shadow: var(--shadow-md); }
.gallery img { width: 100%; height: auto; display: block; }

/* ============================================================
   36. RESPONSIVE
   ============================================================ */
@media (max-width: 1080px) {
  .hero-grid { grid-template-columns: 1fr; }
  .portrait { max-width: 24rem; }
  .about-grid { grid-template-columns: 1fr; }
  .exp-grid { grid-template-columns: 1fr; }
  .exp-rail-inner { position: static; }
  .venue-grid { grid-template-columns: 1fr 1fr; }
  .gallery { columns: 2; }
}
@media (max-width: 860px) {
  /* The toolbar stops being sticky at this width: the filter row wraps to
     several lines, and a pinned bar would eat half the viewport. */
  .archive-toolbar { padding: .875rem; }
  .archive-toolbar-top { flex-direction: column; align-items: stretch; }
  /* Once the top row is a column, `flex: 1 1 32rem` resolves against height,
     which stretched the two wrapped filter lines 512px apart. */
  .archive-toolbar .filter-controls { flex: 0 1 auto; }
  .archive-toolbar .density-toggle { align-self: flex-start; }
  .archive-toolbar .year-rail { margin-top: .875rem; }

  /* Slide-in drawer from the right, as in the earlier build, rather than a
     full-width dropdown. A drawer keeps the page visible behind it, which
     makes it obvious where you are and where you came back to. */
  .nav-links {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 101;
    width: min(var(--drawer-w), 84vw);
    flex-direction: column; align-items: stretch; gap: .125rem;
    padding: calc(var(--nav-h) + 1rem) 1.25rem 1.5rem;
    background: var(--paper-raised);
    border-left: 1px solid var(--line-hi);
    box-shadow: var(--shadow-lg);
    overflow-y: auto; overscroll-behavior: contain;
    /* The closed drawer is nudged 32px right and faded, NOT pushed a full
       drawer-width off-screen. A transform past the viewport edge still counts
       toward the scrollable area — that gave every mobile page a horizontal
       scrollbar (scrollWidth 678 on a 390px viewport). 32px keeps the travel
       inside the viewport at every width, since the drawer is at most 84vw and
       84vw - 32px stays positive down to 200px. */
    transform: translateX(32px); opacity: 0;
    visibility: hidden; pointer-events: none;
    transition: transform .3s var(--ease-out), opacity .22s var(--ease-out),
                visibility .3s var(--ease-out);
  }
  .nav-links.open, .nav-links.active {
    transform: none; opacity: 1;
    visibility: visible; pointer-events: auto;
  }
  /* Links get a full-width row and a hairline, so the drawer reads as a list
     rather than floating text. The underline indicator from the desktop nav
     becomes a left rail instead. */
  .nav-link {
    padding: .875rem .75rem; font-size: var(--t-base);
    border-radius: 8px; border-bottom: 1px solid var(--line);
  }
  .nav-link:last-child { border-bottom: 0; }
  .nav-link::after {
    left: .75rem; right: auto; top: 50%; bottom: auto;
    width: 2px; height: 1.1rem; border-radius: 2px;
    transform: translateY(-50%) scaleY(0); transform-origin: center;
  }
  .nav-link:hover { background: var(--accent-fill); }
  .nav-link:hover::after, .nav-link.is-active::after { transform: translateY(-50%) scaleY(1); }
  .nav-link.is-active { background: var(--accent-fill); }
  .nav-burger { display: grid; position: relative; z-index: 102; }
  /* Touch targets: the desktop 34px buttons clear WCAG 2.5.8's 24px floor but
     sit under the 44px that touch input actually wants, so grow them where a
     finger is the pointing device. Still inside the 63px nav. */
  .icon-btn { width: 44px; height: 44px; border-radius: 10px; }
  /* Comfortable touch height for the standalone text links too. */
  .mono-link, .back-link, .footer-links a { min-height: 44px; }
  .icon-btn i { font-size: 1rem; }

  /* Article index: stack the rails above the title. The date becomes a small
     mono line and the platform tag moves inline with it, so a row still reads
     date -> title -> venue without a three-column grid at 320px. */
  .latest-post-card {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .375rem .875rem; padding: 1rem .25rem;
  }
  .lpc-date { grid-column: 1; padding-top: 0; }
  .lpc-main { grid-column: 1 / -1; grid-row: 2; }
  /* The wrapper is the grid item now, not the individual venue tags. Laying the
     venues out in a row here (they wrap if there are three) keeps row 1 one
     line tall; stacking them would inflate the header of every cross-posted
     row on the narrowest screens. */
  .lpc-platforms {
    grid-column: 2; grid-row: 1; align-self: center;
    flex-direction: row; flex-wrap: wrap; justify-content: flex-end;
  }
  .year-num { font-size: var(--t-lg); }

  /* The Offline badge is a third grid item once the venue rail has moved into
     row 1, so it needs an explicit cell. Without one the grid auto-places it
     into row 2 column 1, under the title. */
  .lpc-gone {
    grid-column: 1 / -1; grid-row: 3; justify-self: start; margin-top: .125rem;
  }

  /* Era heading stacks: the blurb and the meta line cannot share a row with a
     display heading at this width without the label wrapping to two words per
     line. */
  .era-head { flex-wrap: wrap; row-gap: .5rem; }
  .era-text { flex: 1 1 100%; order: 2; }
  .era-meta { order: 3; margin-left: 0; }
  /* The chevron would sit alone on its own line above the title once the text
     wraps to full width; the Collapse/Expand word is the clearer affordance. */
  .era-chevron { display: none; }

  /* Talks: the fixed date rail has no room at this width, so it folds above
     the title and the list becomes a single column of records. */
  .talk-item { grid-template-columns: minmax(0, 1fr); gap: .5rem; padding: 1rem 0; }
  .talk-rail { flex-direction: row; align-items: baseline; gap: .625rem; }
  .talk-when { font-size: var(--t-md); }
  .talk-detail { max-width: none; }

  /* Two explicit columns for the auto-fill grids. Left to auto-fill they get a
     fixed px minimum, and when the container sits between that minimum and two
     of them Chrome keeps the second track and hands it the leftover — .work-grid
     resolved to "300px 21px" at 375px, collapsing four cards to 21px wide and
     ~1200px tall. Two minmax(0,1fr) tracks can never produce a sliver. */
  .work-grid, .trending-grid, .publications-grid, .reading-paths, .platform-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  :root { --gap: 1.125rem; }
  .stats-strip { grid-template-columns: 1fr 1fr; }
  .stat { border-left: 0; border-top: 1px solid var(--line); padding: 1.125rem 1rem; }
  .stat:nth-child(-n+2) { border-top: 0; }
  .stat:nth-child(even) { border-left: 1px solid var(--line); }
  .venue-grid { grid-template-columns: 1fr; }
  .about-media { grid-template-columns: 1fr; }
  .gallery { columns: 1; }
  .awards-grid { grid-template-columns: 1fr; }
  .work-grid, .trending-grid, .publications-grid, .reading-paths, .platform-grid { grid-template-columns: 1fr; }
  .citation-stats, .metrics-grid, .topic-explorer { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* .work-card.wide spans 2 tracks; with a single-column grid that would create
     an implicit second column and overflow, so drop it back to auto here. */
  .work-card.wide { grid-column: auto; }
  .folio::after { font-size: var(--d-folio-sm); top: 1.25rem; }
  .search-box input { padding-right: 1rem; }
  .search-shortcut { display: none; }
  .sr-tags { display: none; }
  .citation-actions { flex-direction: column; }
  .cite-copy-btn, .cite-download-btn { justify-content: center; width: 100%; }
  /* Stacking the role name above its date also turns the name's flex-basis into
     a *height*: the desktop rule is `flex: 1 1 14rem`, sized so the name and the
     date sit side by side. In a column container that basis became a 224px
     minimum height, so every role name reserved a 14rem-tall box for one or two
     lines of text -- roughly 200px of blank space per role, and about 1,400px
     inside the IBM card alone, which is why the section read as a gap rather
     than as content. `flex: none` hands the height back to the text. */
  .exp-role-top { flex-direction: column; gap: .2rem; }
  .exp-role-name { flex: none; }
  .stack-row { flex-direction: column; gap: .15rem; }
  .stack-row span { text-align: left; }
  .footer-inner { flex-direction: column; text-align: center; }
  .footer-links { justify-content: center; gap: 1rem; }
  .chart-bars { gap: 1rem; }
  .kg-legend { max-width: 100%; }
  .venue-head { flex-wrap: wrap; }
  .venue-badge { margin-left: 0; width: 100%; }
}

@media (max-width: 420px) {
  .stats-strip { grid-template-columns: 1fr; }
  .stat:nth-child(even) { border-left: 0; }
  .stat:nth-child(-n+2) { border-top: 1px solid var(--line); }
  .stat:first-child { border-top: 0; }
  .hero-cta { flex-direction: column; align-items: stretch; }
  .btn { justify-content: center; }
}

@media (max-width: 480px) {
  .citation-stats, .metrics-grid, .topic-explorer { grid-template-columns: 1fr; }
}

/* ---------- 37. PRINT ---------- */
@media print {
  .nav, .grid-bg, .footer, .hero-cta, .folio::after { display: none !important; }
  body { background: #fff; color: #000; }
  .folio, .plate, .contact-plate, .scholar-cta { background: #fff !important; color: #000 !important; border: 1px solid #ccc !important; }
  .reveal { opacity: 1 !important; transform: none !important; filter: none !important; }
  a::after { content: ' (' attr(href) ')'; font-size: .7em; color: #555; }
}
