/* main.css — base + homepage. Mobile-first (base at 375px), enhance up.
   All values reference tokens.css. No new colors/fonts here. */

/* ---------- Reset / base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Companion to the full-bleed carousel: the 100vw banner breaks out of the
     centered reading frame via negative margins; this swallows the sub-pixel /
     scrollbar-width overflow so it never spawns a horizontal scrollbar. */
  overflow-x: hidden;
}

h1,
h2,
h3,
p {
  margin: 0;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Clear, consistent keyboard focus everywhere. */
a:focus-visible,
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------- Layout frame ---------- */
.page {
  width: 100%;
  max-width: var(--measure-wide);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ---------- Primary nav ----------
   A thin, restrained editorial top bar on every page. Sits in normal flow at
   the top of the reading frame; on the homepage it rests above the hero and
   never overlaps the particle canvas. Mono links, tokens only. */
.sitenav {
  border-bottom: var(--hairline);
}

.sitenav__inner {
  display: flex;
  flex-wrap: wrap; /* safety: bar never clips; links drop below brand if too tight */
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-4) 0;
}

.sitenav__brand {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.sitenav__brand:hover {
  text-decoration: none;
  color: var(--accent);
}

.sitenav__brand-zh {
  letter-spacing: 0.14em;
  color: var(--accent);
}

.sitenav__links {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.sitenav__link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.sitenav__link:hover {
  text-decoration: none;
  color: var(--ink);
}

.sitenav__link [lang="zh-Hans"] {
  letter-spacing: 0.08em;
}

/* Current page: accent, with a hairline underline that keeps clear of focus. */
.sitenav__brand[aria-current="page"],
.sitenav__link[aria-current="page"] {
  color: var(--accent);
}

.sitenav__link[aria-current="page"] {
  border-bottom: 1px solid var(--accent);
  padding-bottom: 2px;
}

.sitenav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------- Masthead ---------- */
.masthead {
  text-align: center;
  padding: var(--space-6) 0 var(--space-7);
  border-bottom: var(--hairline);
}

.masthead__kicker {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: var(--space-1) 0.6em;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--space-5);
}

/* Keep each language intact; let the two halves wrap as whole units. */
.masthead__kicker > span {
  white-space: nowrap;
}

.masthead__kicker .sep {
  display: none; /* only meaningful when both halves share a line */
  color: var(--rule);
}

.masthead__kicker [lang="zh-Hans"] {
  letter-spacing: 0.12em;
}

@media (min-width: 40rem) {
  .masthead__kicker .sep {
    display: inline;
  }
}

.wordmark {
  font-family: var(--font-serif);
  font-weight: 400;
  line-height: 0.92;
  letter-spacing: 0.04em;
}

.wordmark__en {
  display: block;
  /* Monumental but must stay one line at 375px: 13vw ≈ 48.75px there (inside the
     331px gutter), rising to a commanding 9rem cap on wide screens. */
  font-size: clamp(2.75rem, 13vw, 9rem);
  text-transform: uppercase;
  color: var(--ink);
}

.wordmark__zh {
  display: block;
  margin-top: var(--space-4);
  /* Scaled up proportionally with the EN wordmark (max ~0.44× of it). */
  font-size: clamp(1.75rem, 7vw, 4rem);
  letter-spacing: 0.4em;
  /* balance the trailing letter-spacing so the block stays centered */
  text-indent: 0.4em;
  color: var(--accent);
}

/* ---------- Hero (Phase 5: particle wordmark) ----------
   The .hero wraps the real <h1> (which defines the box height and stays in the
   DOM for AT + search) and an absolutely-positioned decorative canvas. Until
   hero.js activates, the text shows normally — a clean progressive-enhancement
   fallback for the no-canvas tier. */
.hero {
  position: relative;
  /* Immersive: give the wordmark a big stage and center it vertically, so
     opening the page feels like a moment. Held at 64vh (not the full 70–80vh) so
     that, with the kicker above and tagline below, the tagline stays fully
     visible even on a short 375×667 phone — a clear "scroll for more" affordance
     — instead of the episode list being pushed entirely out of reach. */
  min-height: 64vh;
  display: grid;
  place-items: center;
}

.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* pointer events are handled on .hero so this decorative layer never eats
     text selection; JS reads pointer position relative to the canvas box. */
  pointer-events: none;
}

/* When the particle field is live, hide the real text VISUALLY only — it stays
   in the DOM (not display:none) so screen readers and crawlers still get the
   wordmark. The child spans set their OWN color (ink / teal), so we must make
   the spans themselves transparent — targeting only .wordmark leaves the spans
   painting solid text behind the canvas. */
.hero.is-active .wordmark,
.hero.is-active .wordmark__en,
.hero.is-active .wordmark__zh {
  color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

.tagline {
  max-width: 34ch;
  margin: var(--space-6) auto 0;
}

.tagline__en {
  display: block;
  font-family: var(--font-serif);
  font-size: var(--step-2);
  font-style: italic;
  line-height: 1.35;
  color: var(--ink);
}

.tagline__zh {
  display: block;
  margin-top: var(--space-3);
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--muted);
}

/* ---------- Reading column ----------
   Masthead spans the wide page frame; episode content + colophon stay in a
   narrow editorial measure so summaries never run at an unreadable width. */
main,
.colophon {
  max-width: var(--measure);
  margin-left: auto;
  margin-right: auto;
}

/* ---------- Featured card (page anchor, directly under the hero) ----------
   One full-width editorial card foregrounding the flagship/latest episode. It
   reads heavier than a list card: an accent rail, a larger serif title, and a
   filled listen CTA so cold WeChat traffic lands on a clear "start here". */
.featured {
  margin: var(--space-7) 0 0;
}

.featured__link {
  display: block;
  color: inherit;
  background: var(--paper);
  border: var(--hairline);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: var(--space-5) var(--space-5) var(--space-6);
}

.featured__link:hover {
  text-decoration: none;
  border-color: var(--accent);
  box-shadow: var(--shadow);
}

.featured__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: no-preference) {
  .featured__link {
    transition: border-color 160ms ease, box-shadow 160ms ease;
  }
}

.featured__label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.featured__label [lang="zh-Hans"] {
  letter-spacing: 0.12em;
}

.featured__label-sep {
  color: var(--rule);
}

.featured__titles {
  margin-top: var(--space-4);
}

.featured__title-zh {
  font-family: var(--font-serif);
  font-size: var(--step-featured);
  font-weight: 400;
  line-height: 1.15;
  color: var(--ink);
}

.featured__title-en {
  display: block;
  margin-top: var(--space-2);
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--step-2);
  font-weight: 400;
  line-height: 1.25;
  color: var(--muted);
}

.featured__guest {
  margin-top: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.06em;
  color: var(--muted);
}

.featured__guest-name {
  color: var(--accent);
}

.featured__meta {
  margin-top: var(--space-2);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.04em;
  color: var(--muted);
}

.featured__dot {
  color: var(--rule);
}

.featured__summary {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: var(--hairline);
}

.featured__summary-zh {
  display: block;
  font-size: var(--step-1);
  line-height: 1.8;
  color: var(--ink);
}

.featured__summary-en {
  display: block;
  margin-top: var(--space-3);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--muted);
}

.featured__cta {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  margin-top: var(--space-5);
  padding: var(--space-3) var(--space-5);
  background: var(--accent);
  color: var(--bg);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.featured__link:hover .featured__cta {
  background: var(--ink);
}

.featured__cta-arrow {
  font-family: var(--font-sans);
}

/* ---------- Section header ---------- */
.section-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  margin: var(--space-8) 0 var(--space-5);
}

.section-head__label {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.section-head__label [lang="zh-Hans"] {
  color: var(--accent);
  letter-spacing: 0.1em;
}

.section-head__rule {
  flex: 1;
  height: 1px;
  background: var(--rule);
}

/* ---------- Latest teaser (homepage) ----------
   A short, curated "最新单集 · Latest Episodes" block under the featured card:
   the shared refined index list + a CTA into the full archive. */
.latest {
  margin-bottom: var(--space-8);
}

.all-cta {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  margin-top: var(--space-5);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.all-cta:hover {
  text-decoration: none;
}

.all-cta:hover .all-cta__arrow {
  transform: translateX(3px);
}

.all-cta__sep {
  color: var(--rule);
}

.all-cta__arrow {
  font-family: var(--font-sans);
}

@media (prefers-reduced-motion: no-preference) {
  .all-cta__arrow {
    transition: transform 160ms ease;
    will-change: transform;
  }
}

/* ---------- Featured carousel (homepage, below the particle hero) ----------
   A Netflix-style banner carousel. Slides stack absolutely inside a fixed-aspect
   frame and cross-fade. Overlay text is white over a bottom scrim, so it uses
   fixed light values rather than the paper-theme tokens (it always sits on
   imagery). Progressive enhancement: with JS off, the first slide shows (its
   :first-child rule) and the dots stay hidden; carousel.js sets [data-enhanced]
   to switch visibility to the .is-active slide and reveal the dots. */
.pt-carousel {
  position: relative;
  /* Wide banner, capped and centered. Breaks out past the reading frame but not
     all the way to the viewport edges (full-bleed felt overwhelming). Width is
     min(100vw, cap); the margins re-center it in the viewport. On screens
     narrower than the cap it becomes about full width. */
  width: min(100vw, 72rem);
  margin-left: calc(50% - min(50vw, 36rem));
  margin-right: calc(50% - min(50vw, 36rem));
  margin-top: var(--space-7);
  margin-bottom: var(--space-7);
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--ink);
}

.pt-carousel__track {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 0;
  /* Cinematic height instead of a fixed aspect ratio: fill a big part of the
     viewport so it lands as a hero, but clamp so it stays sane on very tall or
     very short screens. Mobile stays shorter so the CTA below is still in view. */
  height: clamp(24rem, 62vh, 34rem);
}

@media (min-width: 40rem) {
  .pt-carousel__track {
    height: clamp(22rem, 52vh, 34rem);
  }
}

.pt-carousel__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
}

/* JS-off fallback: the first slide is a valid static featured card. */
.pt-carousel__slide:first-child {
  opacity: 1;
  visibility: visible;
}

/* Enhanced: visibility is driven by .is-active instead of source order. */
.pt-carousel[data-enhanced] .pt-carousel__slide {
  opacity: 0;
  visibility: hidden;
}

.pt-carousel[data-enhanced] .pt-carousel__slide.is-active {
  opacity: 1;
  visibility: visible;
}

@media (prefers-reduced-motion: no-preference) {
  .pt-carousel[data-enhanced] .pt-carousel__slide {
    transition: opacity 600ms ease, visibility 600ms ease;
  }
}

.pt-slide__link {
  position: absolute;
  inset: 0;
  display: block;
  color: #fff;
}

.pt-slide__link:hover {
  text-decoration: none;
}

.pt-slide__link:focus-visible {
  outline: 3px solid #fff;
  outline-offset: -3px;
  border-radius: var(--radius);
}

.pt-slide__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Per-slide crop bias (meta image_focus) so a subject stays in frame when the
   cover is cropped to the banner aspect. */
.pt-slide[data-focus='left'] .pt-slide__img {
  object-position: left center;
}
.pt-slide[data-focus='right'] .pt-slide__img {
  object-position: right center;
}

/* Bottom-anchored scrim: keeps overlay text legible while leaving the top of
   the image (where cover art / baked-in text usually lives) uncovered. */
/* Two stacked washes: a tall bottom gradient (title/guest/CTA legibility) plus a
   softer left-to-right gradient so the left-aligned overlay stays readable over
   a busy or bright subject sitting behind it (e.g. Jan's dusk seascape). Tuned
   taller than before because the banner is now much bigger and the title larger. */
.pt-slide__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      to top,
      rgba(8, 8, 10, 0.92) 0%,
      rgba(8, 8, 10, 0.72) 20%,
      rgba(8, 8, 10, 0.42) 40%,
      rgba(8, 8, 10, 0.12) 62%,
      rgba(8, 8, 10, 0) 80%
    ),
    linear-gradient(
      to right,
      rgba(8, 8, 10, 0.5) 0%,
      rgba(8, 8, 10, 0.16) 34%,
      rgba(8, 8, 10, 0) 60%
    );
}

/* Light covers (dark baked-in text on a pale field, e.g. the gumi Cryptos
   thumbnail, whose guest sits at bottom-left right under the overlay): a heavier,
   taller bottom wash + a stronger left wash so white overlay text stays legible,
   while the top of the frame — where the baked art lives — stays clear. */
.pt-slide[data-tone='light'] .pt-slide__scrim {
  background:
    linear-gradient(
      to top,
      rgba(8, 8, 10, 0.95) 0%,
      rgba(8, 8, 10, 0.82) 24%,
      rgba(8, 8, 10, 0.55) 46%,
      rgba(8, 8, 10, 0.22) 68%,
      rgba(8, 8, 10, 0) 86%
    ),
    linear-gradient(
      to right,
      rgba(8, 8, 10, 0.58) 0%,
      rgba(8, 8, 10, 0.22) 36%,
      rgba(8, 8, 10, 0) 62%
    );
}

.pt-slide__overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--space-5) var(--gutter) var(--space-6);
  /* Wide enough that the ZH title has room for a full line (no orphan char),
     but still a hero measure, not the full banner width. */
  max-width: min(42rem, 92%);
}

@media (min-width: 40rem) {
  .pt-slide__overlay {
    /* Align the text to the site's content frame (the same left edge as the
       masthead/nav) rather than the raw viewport edge, so the full-bleed banner
       still feels anchored to the page. */
    padding: var(--space-6) var(--space-6) var(--space-8)
      max(var(--space-7), calc((100vw - var(--measure-wide)) / 2 + var(--gutter)));
    max-width: min(56rem, 66%);
  }
}

.pt-slide__ep {
  font-family: var(--font-mono);
  font-size: clamp(0.75rem, 1vw, 0.875rem);
  letter-spacing: 0.28em;
  color: rgba(255, 255, 255, 0.88);
}

.pt-slide__title-zh {
  margin-top: var(--space-3);
  font-family: var(--font-serif);
  /* Scaled up to read as a true hero on the big banner. */
  font-size: clamp(2rem, 5.2vw, 3.5rem);
  font-weight: 400;
  line-height: 1.12;
  color: #fff;
  text-shadow: 0 1px 18px rgba(0, 0, 0, 0.5);
  /* Balance the two lines so a short CJK title never drops a lone orphan
     character (…投资 / 人) onto its own line. */
  text-wrap: balance;
}

.pt-slide__title-en {
  display: block;
  margin-top: var(--space-2);
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(1.125rem, 2.2vw, 1.75rem);
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
  text-wrap: balance;
}

.pt-slide__guest {
  margin-top: var(--space-4);
  font-family: var(--font-mono);
  font-size: clamp(0.75rem, 1.05vw, 0.9375rem);
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.82);
}

.pt-slide__guest-name {
  color: #fff;
}

.pt-slide__dot {
  margin: 0 0.5em;
  color: rgba(255, 255, 255, 0.5);
}

.pt-slide__cta {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  margin-top: var(--space-5);
  padding: var(--space-3) var(--space-5);
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: clamp(0.75rem, 0.95vw, 0.875rem);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #fff;
}

.pt-slide__cta-sep {
  color: rgba(255, 255, 255, 0.55);
}

.pt-slide__cta-arrow {
  font-family: var(--font-sans);
}

.pt-slide__link:hover .pt-slide__cta {
  background: var(--accent);
  border-color: var(--accent);
}

@media (prefers-reduced-motion: no-preference) {
  .pt-slide__cta {
    transition: background 160ms ease, border-color 160ms ease;
  }
}

/* Dot indicators — hidden until JS enhances the carousel (they'd do nothing
   otherwise). Centered along the bottom; the overlay's bottom padding clears
   them. */
.pt-carousel__dots {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--space-4);
  justify-content: center;
  gap: var(--space-3);
  padding: 0 var(--gutter);
}

.pt-carousel[data-enhanced] .pt-carousel__dots {
  display: flex;
}

.pt-carousel__dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.9);
  background: transparent;
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

.pt-carousel__dot[aria-selected='true'] {
  background: #fff;
}

.pt-carousel__dot:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

@media (prefers-reduced-motion: no-preference) {
  .pt-carousel__dot {
    transition: background 160ms ease;
  }
}

/* Standalone All-Episodes CTA under the carousel. */
.home-cta {
  margin-bottom: var(--space-8);
}

/* ---------- Refined index list (Latest teaser + Episodes archive) ----------
   ONE list primitive shared by the homepage teaser and the full archive. Each
   row: EP number + bilingual title + guest·company on the left, duration (or a
   SOON marker) on the right, hairline divider between rows. Mobile-first: the
   right-hand meta drops below the body at 375px and rises beside it on wider
   screens. */
.ep-index {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--hairline);
}

.ep-row {
  border-bottom: var(--hairline);
}

.ep-row__link {
  display: grid;
  /* minmax(0, 1fr): let the flexible track shrink below its content's min-width
     so long titles wrap instead of forcing horizontal overflow at 375px. */
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  column-gap: var(--space-4);
  row-gap: var(--space-2);
  padding: var(--space-5) 0;
  color: inherit;
}

a.ep-row__link:hover {
  text-decoration: none;
}

a.ep-row__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

.ep-row__no {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.16em;
  color: var(--accent);
  /* nudge onto the title baseline */
  align-self: baseline;
}

.ep-row__body {
  min-width: 0; /* allow long titles to wrap instead of overflowing the grid */
}

.ep-row__title-zh {
  display: block;
  font-family: var(--font-serif);
  font-size: var(--step-3);
  line-height: 1.2;
  color: var(--ink);
}

a.ep-row__link:hover .ep-row__title-zh {
  color: var(--accent);
}

.ep-row__title-en {
  display: block;
  margin-top: var(--space-1);
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--step-1);
  line-height: 1.3;
  color: var(--muted);
}

.ep-row__guest {
  display: block;
  margin-top: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.04em;
  color: var(--muted);
}

.ep-row__dot {
  margin: 0 0.5em;
  color: var(--rule);
}

/* Row blurb: ZH primary, EN secondary/muted. Clamped to ~2 lines each so the
   list stays scannable; the full summary lives on the episode page. */
.ep-row__summary {
  display: block;
  margin-top: var(--space-3);
  max-width: 60ch;
}

.ep-row__summary-zh,
.ep-row__summary-en {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.ep-row__summary-zh {
  font-size: var(--step-0);
  line-height: 1.7;
  color: var(--muted);
}

.ep-row__summary-en {
  margin-top: var(--space-2);
  font-size: var(--step-mono);
  line-height: 1.6;
  color: var(--muted);
  opacity: 0.85;
}

/* Right-hand meta: on 375px it sits in the second column under the body (its
   own row); at 40rem+ it moves to a dedicated trailing column. */
.ep-row__dur,
.ep-row__soon {
  grid-column: 2;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.08em;
  white-space: nowrap;
}

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

a.ep-row__link:hover .ep-row__dur {
  color: var(--accent);
}

.ep-row__soon {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  justify-self: start;
  padding: 0.15em 0.7em;
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  text-transform: uppercase;
}

.ep-row__soon-sep {
  color: var(--rule);
}

/* Coming-soon rows are non-interactive; de-emphasise the number. */
.ep-row--soon .ep-row__link {
  cursor: default;
}

.ep-row--soon .ep-row__no {
  color: var(--muted);
}

@media (min-width: 40rem) {
  .sitenav__links {
    gap: var(--space-5);
  }

  .sitenav__brand {
    letter-spacing: 0.22em;
  }

  .sitenav__link {
    letter-spacing: 0.14em;
  }

  .ep-row__link {
    grid-template-columns: auto minmax(0, 1fr) auto;
    column-gap: var(--space-5);
  }

  .ep-row__dur,
  .ep-row__soon {
    grid-column: 3;
    grid-row: 1;
    align-self: baseline;
    justify-self: end;
    text-align: right;
  }
}

/* ---------- Interior page header (Episodes / About) ----------
   A quieter counterpart to the homepage masthead: mono kicker, serif bilingual
   title, a short lead. Constrained to the reading measure. */
.page-head {
  max-width: var(--measure);
  margin: 0 auto;
  padding: var(--space-7) 0 var(--space-6);
  border-bottom: var(--hairline);
}

.page-head__kicker {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}

.page-head__kicker [lang="zh-Hans"] {
  letter-spacing: 0.12em;
  color: var(--accent);
}

.page-head__kicker-sep {
  color: var(--rule);
}

.page-head__title {
  margin-top: var(--space-4);
  font-family: var(--font-serif);
  font-weight: 400;
  line-height: 1.1;
}

.page-head__title-zh {
  display: block;
  font-size: var(--step-3);
  color: var(--ink);
}

.page-head__title-en {
  display: block;
  margin-top: var(--space-2);
  font-style: italic;
  font-size: var(--step-2);
  color: var(--muted);
}

.page-head__lead {
  margin-top: var(--space-5);
  max-width: 60ch;
}

.page-head__lead-zh {
  display: block;
  font-size: var(--step-1);
  line-height: 1.8;
  color: var(--ink);
}

.page-head__lead-en {
  display: block;
  margin-top: var(--space-3);
  line-height: 1.65;
  color: var(--muted);
}

/* ==========================================================================
   About page — a two-column editorial grid. Each section is one row: a mono
   label rail on the left (关于 · ABOUT, 使命 · MISSION, 主持人 · THE HOST) and the
   content column on the right (ZH serif lead prominent, EN muted below). Every
   row shares the SAME grid template, so all labels sit on one left edge and all
   content on another — the whole page lines up vertically. Mobile stacks to one
   column (label above its content, one consistent left edge). Sections gently
   fade + slide up on scroll via reveal.js; see the reduced-motion / no-JS guard.
   ========================================================================== */

.about {
  padding: var(--space-7) 0 var(--space-9);
}

/* Shared bilingual mono label idiom: page kicker + section labels + contact. */
.about__label,
.about__contact-label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}

.about__label [lang="zh-Hans"],
.about__contact-label [lang="zh-Hans"] {
  letter-spacing: 0.12em;
  color: var(--accent);
}

.about__head-sep,
.about__sig-sep {
  color: var(--rule);
}

/* ---------- Row = one section (label + content) ---------- */
/* Mobile: stacked. Label sits above its content on one shared left edge. */
.about__row {
  margin-top: var(--space-7);
  padding-top: var(--space-7);
  border-top: var(--hairline);
}

/* The lead is the first row: no divider above it, tighter top. */
.about__row--lead {
  margin-top: var(--space-6);
  padding-top: 0;
  border-top: 0;
}

.about__content {
  margin-top: var(--space-4);
}

/* ---------- Content typography ---------- */
.about__lead-zh {
  max-width: 34ch;
  font-family: var(--font-serif);
  font-size: clamp(1.375rem, 3.4vw, 1.75rem);
  line-height: 1.7;
  color: var(--ink);
}

.about__lead-en {
  margin-top: var(--space-5);
  max-width: 60ch;
  font-size: var(--step-0);
  line-height: 1.8;
  color: var(--muted);
}

.about__body-zh {
  max-width: 40ch;
  font-size: var(--step-1);
  line-height: 1.9;
  color: var(--ink);
}

.about__body-en {
  margin-top: var(--space-4);
  max-width: 60ch;
  font-size: var(--step-0);
  line-height: 1.8;
  color: var(--muted);
}

/* ---------- Host signature + contact (in the content column) ---------- */
.about__sig {
  margin-top: var(--space-6);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
}

.about__sig-name {
  font-family: var(--font-serif);
  font-size: var(--step-2);
  color: var(--ink);
}

.about__sig-aff {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4em;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.06em;
  color: var(--muted);
}

.about__contact {
  margin-top: var(--space-4);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
}

.about__email {
  font-family: var(--font-mono);
  font-size: var(--step-1);
  letter-spacing: 0.02em;
  color: var(--accent);
}

.about__email:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* ---------- Scroll reveal (progressive enhancement) ----------
   Only hide-then-reveal when JS is on (html.js, set before first paint) AND the
   user allows motion. With JS off, or under reduced motion, the rules below do
   not apply, so every row is fully visible with no animation. reveal.js adds
   .is-visible as each row scrolls into view. */
@media (prefers-reduced-motion: no-preference) {
  html.js .about__row[data-reveal] {
    opacity: 0;
    transform: translateY(1.25rem);
    transition: opacity 640ms ease, transform 640ms ease;
    will-change: opacity, transform;
  }

  html.js .about__row[data-reveal].is-visible {
    opacity: 1;
    transform: none;
  }
}

/* ---------- Desktop: strict two-column aligned grid ---------- */
@media (min-width: 48rem) {
  .about {
    padding: var(--space-8) 0 var(--space-9);
  }

  .about__row {
    display: grid;
    /* Fixed label rail + flexible content column. Identical on every row, so the
       two column edges are shared across all sections. */
    grid-template-columns: minmax(7rem, 10rem) minmax(0, 1fr);
    column-gap: var(--space-6);
    align-items: start;
    margin-top: var(--space-8);
    padding-top: var(--space-8);
  }

  .about__row--lead {
    margin-top: var(--space-6);
    padding-top: 0;
  }

  /* Label rail: top-aligned to its content, on the shared left edge. */
  .about__label {
    align-self: start;
    padding-top: 0.15em; /* optical: sit the mono cap-line near the serif x-height */
  }

  .about__content {
    margin-top: 0;
  }
}

/* ---------- Footer ---------- */
.colophon {
  border-top: var(--hairline);
  padding: var(--space-6) 0 var(--space-8);
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  letter-spacing: 0.06em;
  color: var(--muted);
  line-height: 1.9;
}

.colophon__zh {
  display: block;
  letter-spacing: 0.1em;
}

/* ---------- Enhance up ---------- */
@media (min-width: 40rem) {
  :root {
    --step-2: 1.5rem;
    --step-3: 2rem;
    --step-featured: 2.5rem;
  }

  .featured__link {
    padding: var(--space-7) var(--space-7) var(--space-7);
  }
}

@media (min-width: 64rem) {
  .masthead {
    padding: var(--space-7) 0 var(--space-8);
  }
}
