/* ============================================================
   Design system — Claude palette + Apple discipline
   Inter Tight display, warm cream surface ladder, one shadow,
   glass reserved for chrome and cards over a drifting mesh.
   ============================================================ */
:root {
  /* Surface ladder — warm cream */
  --canvas: #faf9f5;
  --surface-soft: #f5f0e8;
  --surface-card: #efe9de;
  --surface-strong: #e8e0d2;
  --surface-dark: #181715;
  --surface-dark-2: #252320;

  /* Ink */
  --ink: #141413;
  --ink-body: #3d3d3a;
  --muted: #6c6a64;
  --on-dark: #faf9f5;
  --on-dark-mute: #a09d96;

  /* Brand */
  --brand: #bc6442;
  --brand-active: #a35233;
  --brand-tint: rgba(188, 100, 66, 0.1);

  /* Hairlines */
  --hairline: #e6dfd8;
  --hairline-soft: #ebe6df;

  /* Glass */
  --glass-chrome: rgba(250, 249, 245, 0.72);
  --glass-card: rgba(255, 253, 250, 0.55);
  --glass-card-hover: rgba(255, 253, 250, 0.72);
  --glass-blur: blur(20px) saturate(180%);
  --glass-edge-top: rgba(255, 255, 255, 0.75);
  --glass-edge-bot: rgba(0, 0, 0, 0.04);

  /* The ONE shadow — imagery only */
  --shadow-media: 0 5px 30px rgba(20, 20, 19, 0.16);

  /* Spacing — 8px base */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;
  --sp-section: 96px;

  /* Radii */
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-pill: 9999px;

  /* Motion */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur-fast: 0.18s;
  --dur: 0.32s;

  --focus-ring: 0 0 0 2px var(--canvas), 0 0 0 4px var(--brand);
  --max-width: 1120px;
  --measure: 68ch;

  --font-display: "Inter Tight", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}


/* Global Reset & Base */
* {
  box-sizing: border-box;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  /* flex column so .site-footer's margin-top:auto pins it to the bottom
     of short pages instead of floating mid-viewport */
  display: flex;
  flex-direction: column;
  min-height: 100%;
  background: var(--canvas);
  color: var(--ink-body);
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

main {
  flex: 1;
}

/* The mesh: this is what the glass refracts. Without it, blur has
   nothing to bend and every glass surface reads as a flat box. */
body::before {
  content: "";
  position: fixed;
  inset: -25%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(38% 42% at 22% 28%, rgba(188, 100, 66, 0.16), transparent 62%),
    radial-gradient(34% 38% at 78% 16%, rgba(232, 165, 90, 0.13), transparent 62%),
    radial-gradient(42% 46% at 60% 84%, rgba(93, 184, 166, 0.08), transparent 62%);
  filter: blur(40px);
  animation: mesh-drift 60s var(--ease) infinite alternate;
}

@keyframes mesh-drift {
  from {
    transform: translate3d(0, 0, 0) scale(1);
  }

  to {
    transform: translate3d(-3%, 2%, 0) scale(1.08);
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  color: var(--ink);
  margin: 0 0 var(--sp-4);
}

h1,
h2 {
  font-family: var(--font-display);
  font-weight: 700;
}

h1 {
  font-size: clamp(2.75rem, 6vw, 4rem);
  line-height: 1.05;
  letter-spacing: -0.035em;
}

h2 {
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
}

h3,
h4,
h5,
h6 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.02em;
}

h3 {
  font-size: clamp(1.15rem, 2vw, 1.375rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
}

h4 {
  font-size: 1.125rem;
  line-height: 1.4;
}

p {
  margin-bottom: var(--sp-5);
}

.muted {
  color: var(--muted);
}

.lead {
  font-size: 1.25rem;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--ink-body);
}

.eyebrow {
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

.caption {
  font-size: 0.875rem;
  line-height: 1.45;
}

a {
  color: var(--brand);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease);
}

a:hover {
  color: var(--brand-active);
}

:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--r-sm);
}

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: var(--sp-4);
  z-index: 300;
  padding: var(--sp-3) var(--sp-5);
  background: var(--canvas);
  color: var(--ink);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-media);
  font-weight: 500;
  transform: translateY(-200%);
  transition: transform var(--dur-fast) var(--ease);
}

.skip-link:focus-visible {
  transform: translateY(0);
  color: var(--ink);
}

.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  background: var(--brand);
  z-index: 200;
  transition: width 0.1s linear;
}

/* Layout Utilities */
.container {
  width: min(100% - 2.5rem, var(--max-width));
  margin-inline: auto;
}

.section {
  padding-block: clamp(var(--sp-8), 9vw, var(--sp-section));
}

/* Surface bands — the colour change is the section divider */
.section--soft {
  background: var(--surface-soft);
}

.section--dark {
  background: var(--surface-dark);
  color: var(--on-dark);
}

.section--dark h1,
.section--dark h2,
.section--dark h3,
.section--dark h4 {
  color: var(--on-dark);
}

.section--dark .muted,
.section--dark .eyebrow {
  color: var(--on-dark-mute);
}

.page-intro {
  max-width: var(--measure);
  margin-inline: auto;
  text-align: center;
}

.grid {
  display: grid;
  gap: var(--sp-5);
}

@media (min-width: 640px) {
  .grid-2 {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 992px) {
  .grid-3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Frosted chrome */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--glass-chrome);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--glass-edge-bot);
  padding: var(--sp-4) 0;
  transition: padding var(--dur) var(--ease);
}

.site-header.scrolled {
  padding: var(--sp-3) 0;
}

.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand {
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.03em;
}

.brand:hover {
  color: var(--ink);
}

.nav-links {
  display: flex;
  gap: var(--sp-1);
}

.nav-links a {
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
  color: var(--muted);
  font-size: 0.9375rem;
  font-weight: 500;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}

.nav-links a:hover {
  color: var(--ink);
}

.nav-links a[aria-current="page"] {
  background: var(--brand-tint);
  color: var(--brand);
}

.menu-toggle {
  display: none;
}

/* Mobile nav — two hairlines that fold into an ×, opening a full-height
   sheet of large links (the apple.com pattern). */
@media (max-width: 768px) {
  .menu-toggle {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 44px;
    height: 44px;
    margin-right: calc(var(--sp-3) * -1);
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: var(--r-pill);
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .menu-toggle__bar {
    display: block;
    width: 18px;
    height: 1.5px;
    border-radius: 1px;
    background: currentColor;
    transition: transform var(--dur) var(--ease);
  }

  .menu-toggle[aria-expanded="true"] .menu-toggle__bar:first-child {
    transform: translateY(3.75px) rotate(45deg);
  }

  .menu-toggle[aria-expanded="true"] .menu-toggle__bar:last-child {
    transform: translateY(-3.75px) rotate(-45deg);
  }

  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: calc(100dvh - 100%);
    flex-direction: column;
    gap: 0;
    padding: var(--sp-4) var(--sp-6) var(--sp-7);
    /* Solid: a backdrop-filter nested inside the blurred header does not
       render, so a translucent sheet would let the page bleed through */
    background: var(--canvas);
    overflow-y: auto;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--dur) var(--ease), visibility var(--dur);
  }

  .nav-links a {
    display: flex;
    align-items: center;
    min-height: 56px;
    padding: 0;
    border-radius: 0;
    border-bottom: 1px solid var(--hairline-soft);
    font-family: var(--font-display);
    font-size: 1.75rem;
    font-weight: 600;
    letter-spacing: -0.025em;
    color: var(--ink);
    transform: translateY(-8px);
    transition: transform var(--dur) var(--ease), color var(--dur-fast) var(--ease);
  }

  .nav-links a[aria-current="page"] {
    background: none;
    color: var(--brand);
  }

  .nav-links.is-open {
    opacity: 1;
    visibility: visible;
  }

  .nav-links.is-open a {
    transform: none;
  }

  .nav-links.is-open a:nth-child(2) { transition-delay: 30ms; }
  .nav-links.is-open a:nth-child(3) { transition-delay: 60ms; }
  .nav-links.is-open a:nth-child(4) { transition-delay: 90ms; }
  .nav-links.is-open a:nth-child(5) { transition-delay: 120ms; }

  /* Page behind the open sheet stays put */
  body.nav-open {
    overflow: hidden;
  }
}

/* Hero Section */
.hero {
  text-align: center;
  padding-block: clamp(var(--sp-7), 8vw, var(--sp-section));
}

.hero .lead {
  margin: var(--sp-5) auto 0;
  max-width: 58ch;
}

/* ------------------------------------------------------------
   .media-plate — for images with a baked light background that
   composite via mix-blend-mode: multiply.

   glassy_design.png and timeline_journey.png are fully opaque.
   Their flat near-white field multiplies away to nothing and
   their grey vignette becomes a real shadow. That only works if
   the backdrop is known and static — so the board below is
   opaque white (multiply against white is a no-op) and carries
   `isolation: isolate` to pin the blend to itself. Without the
   isolation the drifting mesh becomes the backdrop and the
   image visibly breathes colour.

   The glass mat around it is what refracts the mesh.
   ------------------------------------------------------------ */
.media-plate {
  width: 100%;
  max-width: 600px;
  margin-inline: auto;
  background: var(--glass-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-edge-top);
  border-bottom: 1px solid var(--glass-edge-bot);
  border-radius: var(--r-xl);
  padding: var(--sp-3);
}

.media-plate__board {
  isolation: isolate;
  background: #fff;
  border-radius: calc(var(--r-xl) - var(--sp-3));
  overflow: hidden;
}

.media-plate__board>img {
  display: block;
  width: 100%;
  height: auto;
  mix-blend-mode: multiply;
  filter: contrast(1.05) brightness(1.02);
}

.media-plate--wide {
  max-width: 100%;
}

/* Glassy Cards */
.card {
  background: var(--glass-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-edge-top);
  border-bottom: 1px solid var(--glass-edge-bot);
  border-radius: var(--r-xl);
  padding: var(--sp-6);
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.card:hover {
  transform: translateY(-2px);
  background: var(--glass-card-hover);
}

/* On dark bands the lit-top-edge reads inverted; soften it */
.section--dark .card {
  background: var(--surface-dark-2);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-top-color: rgba(255, 255, 255, 0.08);
  border-bottom-color: rgba(0, 0, 0, 0.3);
}

/* Media Card (Blog Preview) */
.media-card {
  display: grid;
  gap: var(--sp-6);
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .media-card {
    grid-template-columns: 300px 1fr;
  }
}

.media-card img {
  width: 100%;
  height: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-media);
}

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-4) 0;
}

.badge {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--r-pill);
  font-size: 0.875rem;
  color: var(--muted);
}

.section--dark .badge {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.14);
  color: var(--on-dark-mute);
}

/* Grouped list — one inset list, iOS Settings style. Used by the
   contact page and the About credentials/toolkit. Rows are 64px+
   tap targets; hairlines are inset past the icon. */
.contact {
  max-width: 640px;
}

.group-list {
  --row-pad: var(--sp-5);
  --hairline-inset: calc(var(--row-pad) + 36px + var(--sp-4));
  list-style: none;
  margin: var(--sp-7) 0 0;
  padding: 0;
  background: var(--glass-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-edge-top);
  border-bottom: 1px solid var(--glass-edge-bot);
  border-radius: var(--r-xl);
  overflow: hidden;
}

.about-narrow .group-list {
  margin-top: 0;
}

dl.group-list {
  --hairline-inset: var(--row-pad);
}

.group-list > * + * {
  background-image: linear-gradient(var(--hairline-soft), var(--hairline-soft));
  background-size: calc(100% - var(--hairline-inset)) 1px;
  background-position: right top;
  background-repeat: no-repeat;
}

.group-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: 72px;
  padding: var(--sp-4) var(--row-pad);
  color: var(--ink);
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur-fast) var(--ease);
}

.group-row--stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  min-height: 0;
}

.group-row--stacked dd {
  margin: 0;
  line-height: 1.5;
}

a.group-row:hover,
a.group-row:active {
  color: var(--ink);
  background-color: var(--glass-card-hover);
}

.group-row:focus-visible {
  border-radius: 0;
  box-shadow: inset 0 0 0 2px var(--brand);
}

.group-row__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--brand-tint);
  color: var(--brand);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.group-row__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}

.group-row__label {
  font-weight: 500;
  font-size: 1.0625rem;
  line-height: 1.3;
}

.group-row__detail {
  font-size: 0.875rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.group-row__meta {
  margin-top: 2px;
  font-size: 0.75rem;
  color: var(--muted);
  opacity: 0.8;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  overflow-wrap: anywhere;
}

.group-row--stacked dd.group-row__label {
  font-size: 0.9375rem;
  font-weight: 400;
  color: var(--ink-body);
}

.group-row__chev {
  flex: none;
  color: var(--muted);
  opacity: 0.6;
  transition: transform var(--dur-fast) var(--ease);
}

.group-row:hover .group-row__chev {
  transform: translateX(2px);
}

.cta-button {
  display: inline-block;
  margin-top: auto;
  padding: var(--sp-3) var(--sp-5);
  background: var(--brand);
  color: #fff;
  border-radius: var(--r-pill);
  font-size: 0.9375rem;
  font-weight: 500;
  text-align: center;
  transition: background-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.cta-button:hover {
  background: var(--brand-active);
  color: #fff;
}

.cta-button:active {
  transform: scale(0.95);
}

.cta-section {
  text-align: center;
}

/* Footer */
.site-footer {
  margin-top: auto;
  padding: var(--sp-7) 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.875rem;
  border-top: 1px solid var(--hairline);
  background: var(--surface-soft);
}

/* Card Images (for grids) */
.card img {
  width: 100%;
  height: 220px;
  object-fit: cover;
  border-radius: var(--r-lg);
  margin-bottom: var(--sp-5);
  box-shadow: var(--shadow-media);
}

/* Yale Badge — institutional mark, keeps its own colour */
.yale-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  font-size: 0.875rem;
  background: #00356b;
  color: white;
  border-radius: var(--r-pill);
  font-weight: 500;
}

/* ============================================================
   Scroll reveal
   .reveal starts hidden; main.js adds .is-visible via
   IntersectionObserver. --reveal-i staggers siblings.
   Everything degrades to "always visible" if JS never runs
   (html.no-js) or the user prefers reduced motion.
   ============================================================ */
/* Content is NEVER hidden by the reveal.
   An earlier version faded in from opacity 0, which meant anything the
   scroll handler missed stayed invisible — it read as broken images
   rather than as an animation. Only transform is animated now, so the
   worst case if JS never runs is content sitting 14px low, still fully
   readable. Scoped to html.js so a no-JS page has no offset at all. */
.js .reveal {
  transform: translateY(14px);
  transition: transform 0.5s var(--ease);
  /* capped so a long grid never leaves late cards visibly lagging */
  transition-delay: calc(min(var(--reveal-i, 0), 4) * 60ms);
}

.js .reveal.is-visible {
  transform: none;
}

/* ============================================================
   About — chapter carousel. Mobile-first: one card fills most of
   the screen and the next one peeks in, Instagram style. Native
   scroll-snap does the physics; JS only feeds --p (each card's
   offset from the snap line, in card widths) for the depth effect.
   ============================================================ */
.about-head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto var(--sp-7);
}

.about-head h2 {
  margin: 0 0 var(--sp-3);
}

.about-head .lead {
  margin: 0;
}

.about-narrow {
  max-width: 720px;
}

.ch-carousel {
  /* Aligns the first card with the page container while letting the
     track itself run edge to edge */
  --gutter: max(1.25rem, (100% - var(--max-width)) / 2);
  --card-w: min(80vw, 360px);
  margin-top: var(--sp-7);
}

.ch-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-4);
}

.ch-count {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.ch-count__now {
  color: var(--ink);
}

.ch-nav {
  display: none;
  gap: var(--sp-2);
}

.ch-nav__btn {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: 50%;
  background: var(--glass-card);
  color: var(--ink);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.ch-nav__btn:hover:not(:disabled) {
  background: var(--glass-card-hover);
}

.ch-nav__btn:active:not(:disabled) {
  transform: scale(0.92);
}

.ch-nav__btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.ch-track {
  display: flex;
  gap: var(--sp-3);
  list-style: none;
  margin: 0;
  padding: var(--sp-3) var(--gutter) var(--sp-5);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
  perspective: 1200px;
  -webkit-overflow-scrolling: touch;
}

.ch-track::-webkit-scrollbar {
  display: none;
}

.ch-track:focus-visible {
  box-shadow: none;
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}

.ch {
  flex: 0 0 var(--card-w);
  display: flex;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

/* Depth: cards leaving the snap line shrink and turn slightly away.
   Transform only, so content is never hidden if JS never runs
   (--p then stays 0, which is the resting state). */
.ch-card {
  --d: min(1, max(var(--p, 0), var(--p, 0) * -1));
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 460px;
  padding: var(--sp-6) var(--sp-5) var(--sp-5);
  overflow: hidden;
  border-radius: 28px;
  background: var(--glass-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-edge-top);
  border-bottom: 1px solid var(--glass-edge-bot);
  transform: scale(calc(1 - var(--d) * var(--shrink, 0.06))) rotateY(calc(var(--p, 0) * var(--tilt, -7deg)));
  transform-origin: center;
  will-change: transform;
}

.ch--current .ch-card {
  background:
    radial-gradient(120% 60% at 100% 0%, var(--brand-tint), transparent 60%),
    var(--glass-card);
}

/* Oversized year, drifting against the swipe — the parallax layer */
.ch-year {
  position: absolute;
  top: var(--sp-3);
  right: calc(var(--sp-3) * -1);
  font-family: var(--font-display);
  font-size: 6.5rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.06em;
  color: var(--node, var(--brand));
  opacity: 0.1;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  transform: translateX(calc(var(--p, 0) * 70px));
}

.ch--study { --node: #4f6b5c; --kind-bg: rgba(108, 138, 122, 0.14); }
.ch--research { --node: #5a5490; --kind-bg: rgba(122, 116, 168, 0.14); }

.ch-kind {
  position: relative;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--kind-bg, var(--brand-tint));
  color: var(--node, var(--brand));
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ch--current .ch-kind::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  animation: ch-live 2s var(--ease) infinite;
}

@keyframes ch-live {
  0%, 100% { box-shadow: 0 0 0 0 rgba(188, 100, 66, 0.45); }
  50% { box-shadow: 0 0 0 5px rgba(188, 100, 66, 0); }
}

.ch-head {
  position: relative;
  margin-top: var(--sp-7);
}

.ch-period,
.ch-org {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
}

.ch-period {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.ch-role {
  margin: var(--sp-1) 0 2px;
  color: var(--ink);
  font-size: 1.5rem;
  line-height: 1.2;
  letter-spacing: -0.025em;
}

.ch-lede {
  margin: var(--sp-4) 0 0;
  font-size: 1rem;
  line-height: 1.5;
}

.ch-metrics {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  list-style: none;
  margin: var(--sp-4) 0 0;
  padding: 0;
}

.ch-metrics li {
  padding: var(--sp-1) 10px;
  border-radius: var(--r-pill);
  background: var(--surface-soft);
  border: 1px solid var(--hairline-soft);
  color: var(--ink);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
}

.ch-open {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  margin-top: auto;
  padding: 0 var(--sp-4) 0 var(--sp-5);
  border: 0;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--canvas);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}

.ch-open:hover {
  background: #2c2b28;
}

.ch-open:active {
  transform: scale(0.96);
}

/* Button sits on the card floor, always clear of the metrics */
.ch-metrics:has(+ .ch-open) {
  margin-bottom: var(--sp-6);
}

.js .ch-card:has(.ch-open) {
  cursor: pointer;
}

/* Story lives in the card for no-JS; with JS it opens in the sheet */
.js .ch-body {
  display: none;
}

html:not(.js) .ch-open {
  display: none;
}

/* Page control — the active dot stretches into a pill */
.ch-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-top: var(--sp-2);
}

.ch-dot {
  width: 6px;
  height: 6px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--hairline);
  cursor: pointer;
  transition: width var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.ch-dot[aria-current="true"] {
  width: 22px;
  background: var(--ink);
}

/* ---- Story sheet: bottom sheet on phones, centred card on desktop ---- */
html:has(.ch-sheet[open]) {
  overflow: hidden;
}

.ch-sheet {
  width: 100%;
  max-width: 100%;
  max-height: 90dvh;
  margin: auto 0 0;
  padding: 0;
  border: 0;
  border-radius: 28px 28px 0 0;
  background: var(--canvas);
  color: var(--ink-body);
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateY(0);
  transition: transform 0.45s cubic-bezier(0.32, 0.72, 0, 1), overlay 0.45s allow-discrete, display 0.45s allow-discrete;
}

.ch-sheet:not([open]) {
  transform: translateY(100%);
}

@starting-style {
  .ch-sheet[open] {
    transform: translateY(100%);
  }
}

.ch-sheet::backdrop {
  background: rgba(20, 20, 19, 0.32);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background-color 0.45s, overlay 0.45s allow-discrete, display 0.45s allow-discrete;
}

@starting-style {
  .ch-sheet[open]::backdrop {
    background: rgba(20, 20, 19, 0);
  }
}

.ch-sheet__top {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  justify-content: flex-end;
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
  background: linear-gradient(var(--canvas) 75%, transparent);
}

.ch-sheet__grabber {
  position: absolute;
  top: 8px;
  left: 50%;
  width: 36px;
  height: 5px;
  margin-left: -18px;
  border-radius: var(--r-pill);
  background: var(--hairline);
}

.ch-sheet__close {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--surface-card);
  color: var(--ink);
  cursor: pointer;
}

.ch-sheet__content {
  padding: 0 var(--sp-5) calc(var(--sp-7) + env(safe-area-inset-bottom));
}

.ch-sheet .ch-head {
  margin: 0 0 var(--sp-5);
  padding-right: 40px;
}

.ch-sheet .ch-role {
  font-size: 1.75rem;
}

.ch-sheet .ch-body {
  display: block;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--hairline-soft);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.ch-project + .ch-project {
  margin-top: var(--sp-7);
}

.ch-project h4 {
  margin: 0;
  font-size: 1.125rem;
}

.ch-body .ch-label {
  margin: var(--sp-5) 0 var(--sp-1);
  color: var(--muted);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ch-body h4 + .ch-label {
  margin-top: var(--sp-3);
}

.ch-body p {
  margin: 0;
}

.ch-body ul {
  margin: 0;
  padding-left: 1.1em;
}

.ch-body li + li {
  margin-top: 6px;
}

.ch-body li::marker {
  color: var(--muted);
}

.ch-body .ch-stack {
  margin-top: var(--sp-6);
  color: var(--muted);
  font-size: 0.8125rem;
}

@media (min-width: 768px) {
  /* Several cards share the screen here, so the depth is gentler */
  .ch-carousel {
    --card-w: 380px;
    --shrink: 0.03;
    --tilt: -3deg;
  }

  .ch-nav {
    display: flex;
  }

  .ch-track {
    gap: var(--sp-5);
  }

  .ch-card {
    padding: var(--sp-7) var(--sp-6) var(--sp-6);
  }

  .ch-sheet {
    width: min(640px, 100% - 48px);
    max-height: 84dvh;
    margin: auto;
    border-radius: 28px;
    transform: none;
    opacity: 1;
    transition: transform 0.35s var(--ease), opacity 0.35s var(--ease), overlay 0.35s allow-discrete, display 0.35s allow-discrete;
  }

  .ch-sheet:not([open]) {
    transform: scale(0.96);
    opacity: 0;
  }

  @starting-style {
    .ch-sheet[open] {
      transform: scale(0.96);
      opacity: 0;
    }
  }

  .ch-sheet__grabber {
    display: none;
  }

  .ch-sheet__content {
    padding: 0 var(--sp-7) var(--sp-7);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ch-card,
  .ch-year {
    transform: none;
  }

  .ch-track {
    scroll-snap-stop: normal;
  }
}

.error-section {
  text-align: center;
  padding-block: clamp(var(--sp-8), 12vw, 10rem);
}

body.is-error main {
  display: flex;
  align-items: center;
  justify-content: center;
}

.error-code {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(5rem, 18vw, 10rem);
  line-height: 1;
  letter-spacing: -0.05em;
  color: var(--brand);
  opacity: 0.18;
  margin: 0;
}

.error-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  justify-content: center;
  margin-top: var(--sp-6);
}

.error-links a {
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
  color: var(--muted);
  font-weight: 500;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}

.error-links a:hover {
  background: var(--brand-tint);
  color: var(--brand);
}

/* ============================================================
   Post cards — articles index and blog index
   The whole card is the link; the media frame crops and the
   image scales inside it on hover.
   ============================================================ */
.post-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--sp-6);
  margin-top: var(--sp-6);
}

.post-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--ink-body);
  background: var(--glass-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-edge-top);
  border-bottom: 1px solid var(--glass-edge-bot);
  border-radius: var(--r-xl);
  transition:
    transform var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

.post-card:hover {
  transform: translateY(-4px);
  background: var(--glass-card-hover);
  color: var(--ink-body);
}

.post-card__media {
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: var(--surface-card);
  flex-shrink: 0;
}

.post-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}

.post-card:hover .post-card__media img {
  transform: scale(1.05);
}

.post-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--sp-6);
  gap: var(--sp-3);
}

.post-card__source {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.post-card__title {
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0;
}

.post-card__excerpt {
  color: var(--muted);
  font-size: 0.9375rem;
  margin: 0;
}

.post-card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: auto;
  padding-top: var(--sp-3);
  font-size: 0.875rem;
  color: var(--muted);
}

.post-card__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: 500;
  color: var(--brand);
}

.post-card__cta svg {
  width: 15px;
  height: 15px;
  transition: transform var(--dur) var(--ease);
}

.post-card:hover .post-card__cta svg {
  transform: translateX(4px);
}

/* Research variant — no thumbnail. The only Yale image available is
   300x168, so repeating it across three cards read as a blurry tile.
   These carry their weight typographically instead. */
.post-card--research .post-card__body {
  padding-top: var(--sp-7);
}

.post-card--research .post-card__title {
  font-size: 1.375rem;
  line-height: 1.25;
}

.post-card--research::before {
  content: "";
  display: block;
  height: 4px;
  background: linear-gradient(90deg, #00356b, color-mix(in srgb, #00356b 25%, transparent));
}

/* Featured — first card goes full-width and horizontal on wide screens */
@media (min-width: 900px) {
  .post-grid--featured {
    grid-template-columns: repeat(3, 1fr);
  }

  .post-card--wide {
    grid-column: span 3;
    flex-direction: row;
    align-items: stretch;
  }

  .post-card--wide .post-card__media {
    flex: 0 0 44%;
    aspect-ratio: auto;
  }

  .post-card--wide .post-card__body {
    padding: var(--sp-8);
    justify-content: center;
  }

  .post-card--wide .post-card__title {
    font-size: 1.75rem;
    line-height: 1.2;
  }

  .post-card--wide .post-card__excerpt {
    font-size: 1.0625rem;
  }
}

/* ============================================================
   Knowledge graph — the articles canvas.

   Tiles are absolutely positioned from authored coordinates in a
   1200x920 space (see tools/build_graph.py); the SVG connectors use
   the SAME space, so lines and tiles cannot drift apart.

   Transform composition matters here. Four things move a tile —
   authored tilt, scroll parallax, idle float and hover scale — so
   each uses its OWN property rather than fighting over `transform`:
     .graph-node        rotate (tilt)  + translate (parallax)
     .graph-node__media translate (float) + scale (hover)
   All of it is progressive: the page is complete and readable with
   no JS at all, and every animation is transform-only, so nothing
   can end up invisible.
   ============================================================ */
.graph-wrap {
  position: relative;
}

.graph {
  position: relative;
  width: 100%;
  aspect-ratio: 1200 / 920;
  margin-top: var(--sp-6);
}

.graph-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.graph-line {
  /* hairline is too pale to read as a thread on the cream canvas */
  stroke: color-mix(in srgb, var(--muted) 34%, transparent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  transition: stroke var(--dur) var(--ease), stroke-width var(--dur) var(--ease);
}

/* ---- tiles ---- */
.graph-node {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  rotate: var(--r, 0deg);
  translate: 0 var(--par, 0px);
  color: var(--ink-body);
  transition: filter var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

.graph-node__media {
  display: block;
  translate: 0 0;
  scale: 1;
  transition: scale var(--dur) var(--ease), filter var(--dur) var(--ease);
  /* Ambient orbit. Each tile gets its own amplitude, period and phase
     from the generator, so the field never falls into step. Runs on
     `translate` and `rotate` only — `scale` is left free for hover, so
     the two compose instead of overwriting each other. */
  animation: tile-orbit var(--ddur, 27s) ease-in-out var(--ddel, 0s) infinite;
  will-change: translate;
}

.graph-node img {
  width: 100%;
  height: auto;
  border-radius: 3px;
  box-shadow: 0 2px 14px rgba(20, 20, 19, 0.09);
  transition: box-shadow var(--dur) var(--ease);
}

/* A closed four-point loop rather than a straight bob, so tiles
   trace a drifting orbit instead of oscillating on one axis. */
@keyframes tile-orbit {
  0% {
    translate: 0 0;
    rotate: 0deg;
  }

  25% {
    translate: var(--dx, 10px) var(--dy, -10px);
    rotate: var(--spin, 0.6deg);
  }

  50% {
    translate: calc(var(--dx, 10px) * 0.35) calc(var(--dy, -10px) * -1);
    rotate: 0deg;
  }

  75% {
    translate: calc(var(--dx, 10px) * -1) calc(var(--dy, -10px) * 0.45);
    rotate: calc(var(--spin, 0.6deg) * -1);
  }

  100% {
    translate: 0 0;
    rotate: 0deg;
  }
}

.graph-node:hover,
.graph-node:focus {
  z-index: 4;
  color: var(--ink-body);
}

.graph-node:hover .graph-node__media,
.graph-node:focus .graph-node__media {
  scale: 1.08;
  animation-play-state: paused;
}

.graph-node:hover img,
.graph-node:focus img {
  box-shadow: 0 10px 34px rgba(20, 20, 19, 0.2);
}

/* Typographic tile, for pieces with no usable artwork */
.graph-node__plate {
  display: flex;
  align-items: flex-end;
  aspect-ratio: 4 / 3;
  padding: var(--sp-3);
  border-radius: 3px;
  background: #00356b;
  color: #fff;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1.3;
  box-shadow: 0 2px 14px rgba(20, 20, 19, 0.09);
  transition: box-shadow var(--dur) var(--ease);
}

.graph-node:hover .graph-node__plate,
.graph-node:focus .graph-node__plate {
  box-shadow: 0 10px 34px rgba(0, 53, 107, 0.28);
}

/* Caption under the tile. Supplementary — the tile itself is the
   link — so it is revealed on hover/focus to keep the canvas quiet. */
.graph-node__label {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  translate: -50% -3px;
  width: max(112%, 140px);
  font-size: 0.6875rem;
  line-height: 1.35;
  text-align: center;
  color: var(--ink);
  background: color-mix(in srgb, var(--canvas) 92%, transparent);
  border-radius: var(--r-sm);
  padding: var(--sp-2);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease), translate var(--dur-fast) var(--ease);
  pointer-events: none;
}

.graph-node:hover .graph-node__label,
.graph-node:focus .graph-node__label {
  opacity: 1;
  translate: -50% 0;
}

/* ---- focus / dim choreography ----
   Hovering anything on the canvas pushes everything else back, so the
   active thread reads clearly. Pure CSS via :has(); browsers without
   it simply get no dimming. */
.graph:has(.graph-node:hover) .graph-node:not(:hover),
.graph:has(.graph-cluster:hover) .graph-node:not(:hover) {
  opacity: 0.32;
  filter: saturate(0.5);
}

.graph:has(.graph-node:hover) .graph-line,
.graph:has(.graph-cluster:hover) .graph-line {
  stroke: color-mix(in srgb, var(--muted) 10%, transparent);
}

.graph:has(.graph-node[data-cluster="minds"]:hover) .graph-line[data-cluster="minds"],
.graph:has(.graph-node[data-cluster="health"]:hover) .graph-line[data-cluster="health"],
.graph:has(.graph-node[data-cluster="cause"]:hover) .graph-line[data-cluster="cause"],
.graph:has(.graph-node[data-cluster="next"]:hover) .graph-line[data-cluster="next"],
.graph:has(.graph-cluster[data-cluster="minds"]:hover) .graph-line[data-cluster="minds"],
.graph:has(.graph-cluster[data-cluster="health"]:hover) .graph-line[data-cluster="health"],
.graph:has(.graph-cluster[data-cluster="cause"]:hover) .graph-line[data-cluster="cause"],
.graph:has(.graph-cluster[data-cluster="next"]:hover) .graph-line[data-cluster="next"] {
  stroke: var(--brand);
  stroke-width: 1.6;
}

/* Hovering a cluster label brings its own tiles back to full strength */
.graph:has(.graph-cluster[data-cluster="minds"]:hover) .graph-node[data-cluster="minds"],
.graph:has(.graph-cluster[data-cluster="health"]:hover) .graph-node[data-cluster="health"],
.graph:has(.graph-cluster[data-cluster="cause"]:hover) .graph-node[data-cluster="cause"],
.graph:has(.graph-cluster[data-cluster="next"]:hover) .graph-node[data-cluster="next"] {
  opacity: 1;
  filter: none;
}

/* Decorative texture tiles — no content, no links */
.graph-accent {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--s);
  aspect-ratio: 1;
  border-radius: 2px;
  background: var(--c);
  rotate: var(--r, 0deg);
  translate: 0 var(--par, 0px);
  pointer-events: none;
  animation: accent-orbit var(--ddur, 33s) ease-in-out var(--ddel, 0s) infinite;
}

/* Accents drift wider and slower — background depth, not focus */
@keyframes accent-orbit {
  0%   { scale: 1; }
  25%  { scale: 1.12; }
  50%  { scale: 0.94; }
  75%  { scale: 1.06; }
  100% { scale: 1; }
}

/* ---- cluster labels ---- */
.graph-cluster {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w, 230px);
  text-align: center;
  translate: -50% 0;
  cursor: default;
}

.graph-cluster h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 var(--sp-1);
  transition: color var(--dur) var(--ease);
}

.graph-cluster:hover h3 {
  color: var(--brand);
}

.graph-cluster p {
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--muted);
  margin: 0;
}

/* Oversized display words anchoring the canvas */
.graph-word {
  position: absolute;
  left: var(--x);
  top: var(--y);
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 6.5vw, 5.5rem);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 0.95;
  color: var(--ink);
  translate: 0 var(--par, 0px);
  pointer-events: none;
  user-select: none;
}

.graph-hint {
  display: none;
}

@media (min-width: 1024px) {
  .graph-hint {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
    border: 1px solid var(--hairline);
    border-radius: var(--r-pill);
    font-size: 0.75rem;
    color: var(--muted);
    background: color-mix(in srgb, var(--canvas) 70%, transparent);
  }
}

/* ------------------------------------------------------------
   Below 1024px the scatter canvas overlaps (measured), so it
   becomes a threaded list: same markup, same graph language,
   laid out for a narrow screen.
   ------------------------------------------------------------ */
@media (max-width: 1023px) {
  .graph {
    aspect-ratio: auto;
    display: block;
    position: relative;
    margin-top: var(--sp-6);
    padding-left: var(--sp-6);
  }

  /* the thread */
  .graph::before {
    content: "";
    position: absolute;
    left: 5px;
    top: 8px;
    bottom: 8px;
    width: 2px;
    background: linear-gradient(180deg, transparent, var(--hairline) 5%, var(--hairline) 95%, transparent);
  }

  .graph-lines,
  .graph-word,
  .graph-accent {
    display: none;
  }

  /* cluster becomes a node on the thread */
  .graph-cluster {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    translate: none;
    text-align: left;
    margin: var(--sp-8) 0 var(--sp-5);
  }

  .graph-cluster:first-of-type {
    margin-top: 0;
  }

  .graph-cluster::before {
    content: "";
    position: absolute;
    left: calc(var(--sp-6) * -1 + 1px);
    top: 8px;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--brand);
    box-shadow: 0 0 0 4px var(--brand-tint);
  }

  .graph-cluster h3 {
    font-size: 1.25rem;
  }

  .graph-cluster p {
    font-size: 0.875rem;
    max-width: 46ch;
  }

  /* tiles flow as cards under their cluster */
  .graph-node {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    rotate: none;
    translate: none;
    display: grid;
    grid-template-columns: 96px 1fr;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-3);
    margin-bottom: var(--sp-3);
    border-radius: var(--r-lg);
    background: var(--glass-card);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border-top: 1px solid var(--glass-edge-top);
    border-bottom: 1px solid var(--glass-edge-bot);
    transition: background-color var(--dur) var(--ease), translate var(--dur) var(--ease);
  }

  .graph-node:active {
    translate: 3px 0;
    background: var(--glass-card-hover);
  }

  /* connector stub back to the thread */
  .graph-node::before {
    content: "";
    position: absolute;
    left: calc(var(--sp-6) * -1 + 6px);
    top: 50%;
    width: 20px;
    height: 1px;
    background: var(--hairline);
  }

  .graph-node__media {
    animation: none;
    scale: 1;
    translate: none;
    rotate: none;
  }

  .graph-node img {
    aspect-ratio: 3 / 2;
    object-fit: cover;
    border-radius: var(--r-sm);
  }

  .graph-node__plate {
    aspect-ratio: 3 / 2;
    font-size: 0.5625rem;
    padding: var(--sp-2);
    border-radius: var(--r-sm);
  }

  /* caption is the card title here — always visible */
  .graph-node__label {
    position: static;
    opacity: 1;
    translate: none;
    width: auto;
    text-align: left;
    background: none;
    padding: 0;
    font-size: 0.875rem;
    line-height: 1.4;
    font-weight: 500;
  }

  /* no dimming choreography on touch */
  .graph:has(.graph-node:hover) .graph-node:not(:hover),
  .graph:has(.graph-cluster:hover) .graph-node:not(:hover) {
    opacity: 1;
    filter: none;
  }
}

@media (max-width: 420px) {
  .graph-node {
    grid-template-columns: 74px 1fr;
    gap: var(--sp-3);
  }
}

@media (prefers-reduced-motion: reduce) {

  .graph-node__media,
  .graph-accent {
    animation: none;
  }
}

/* ============================================================
   Long-form article
   Previously duplicated across two per-post <style> blocks.
   ============================================================ */
.blog-article {
  max-width: var(--measure);
  margin: 0 auto;
}

.blog-article p {
  margin-bottom: var(--sp-6);
}

.blog-article h2 {
  font-size: clamp(1.625rem, 3vw, 2.125rem);
  text-align: left;
  margin-top: var(--sp-8);
  margin-bottom: var(--sp-4);
}

.blog-article h3 {
  margin-top: var(--sp-7);
}

.blog-article ul,
.blog-article ol {
  margin: var(--sp-5) 0 var(--sp-6);
  padding-left: var(--sp-5);
}

.blog-article li {
  margin-bottom: var(--sp-3);
  padding-left: var(--sp-2);
  line-height: 1.7;
}

.blog-header {
  text-align: center;
  padding: var(--sp-8) 0 var(--sp-6);
}

.blog-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
  color: var(--muted);
  font-size: 0.9375rem;
}

.author-avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--canvas);
  flex-shrink: 0;
}

.share-bar {
  display: flex;
  justify-content: center;
  gap: var(--sp-3);
  margin: var(--sp-6) auto;
  padding: var(--sp-3);
  background: var(--glass-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-edge-top);
  border-bottom: 1px solid var(--glass-edge-bot);
  border-radius: var(--r-pill);
  width: fit-content;
}

.share-icon {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--canvas);
  color: var(--muted);
  transition: color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}

.share-icon svg {
  width: 18px;
  height: 18px;
}

.share-icon:hover {
  transform: translateY(-2px);
  color: var(--brand);
}

.blog-image {
  width: 100%;
  border-radius: var(--r-xl);
  margin: var(--sp-6) 0;
  box-shadow: var(--shadow-media);
}

.section-break {
  text-align: center;
  margin: var(--sp-7) 0;
  color: var(--muted);
  font-size: 1.5em;
  letter-spacing: 12px;
  opacity: 0.4;
}

.closing-line {
  font-size: 1.05em;
  font-style: italic;
  color: var(--muted);
  margin-top: var(--sp-7);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--hairline);
}

/* Motion preferences — the repo previously had no guard at all */
@media (prefers-reduced-motion: reduce) {

  body::before {
    animation: none;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .card:hover {
    transform: none;
  }
}