/* Episode page v2 - PROTOTYPE, loaded by episode-21 only.
   Lives in its own file on purpose: the shared sheets are linked by all 56
   pages, and touching them means bumping the cache key everywhere. Nothing
   here affects any other episode until this is promoted. */

/* ── Layout ────────────────────────────────────────────────────────────
   Three grid areas, not two. On a phone the old single-column stack put
   the whole sidebar (chapters, download) after the transcript, which is
   why on EP21 the chapters sat 80,000px down the page. Splitting the main
   column into "top" and "rest" lets the sidebar sit between them on
   mobile while staying a true sidebar on desktop. */
.ep-layout--v2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
  grid-template-areas: "top" "side" "rest";
}
.ep-layout--v2 > .ep-main-top  { grid-area: top; min-width: 0; }
.ep-layout--v2 > .ep-sidebar   { grid-area: side; }
.ep-layout--v2 > .ep-main-rest { grid-area: rest; min-width: 0; }

@media (min-width: 900px) {
  .ep-layout--v2 {
    grid-template-columns: minmax(0, 1fr) 300px;
    grid-template-areas: "top side" "rest side";
    column-gap: 40px;
  }
  /* sticky behaviour for the column is defined in the sidebar block
     further down, with the offset it needs. */
}

/* ── About / show notes ─────────────────────────────────────────────── */
.ep-block { margin-top: var(--space-10); }
.ep-block > h2 {
  font-size: 1.35rem;
  font-weight: 800;
  color: var(--ink);
  margin-bottom: var(--space-4);
}
.ep-about p { color: var(--body); line-height: 1.75; margin-bottom: 1rem; font-size: 1.02rem; }
.ep-about p:last-child { margin-bottom: 0; }
.ep-about .ep-about__kicker {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--ink);
}

.notes-group { margin-bottom: var(--space-6); }
.notes-group:last-child { margin-bottom: 0; }
.notes-group h3 {
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: var(--space-3);
}
.notes-list { list-style: none; margin: 0; padding: 0; }
.notes-list li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--hairline);
  line-height: 1.6;
  color: var(--body);
  font-size: 0.95rem;
}
.notes-list li:last-child { border-bottom: 0; }
.notes-list .notes-ts {
  flex: 0 0 auto;
  align-self: flex-start;
  min-width: 52px;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
  background: none;
  border: 0;
  padding: 2px 8px;
  margin-left: -8px;
  text-align: center;
  cursor: pointer;
  font-family: inherit;
}
.notes-list li[data-seek]:hover { background: var(--bg-alt); }
.notes-list li[data-seek]:hover .notes-ts { background: var(--accent); color: #fff; text-decoration: none; }
.notes-list a { color: var(--accent-text); font-weight: 600; }
.notes-list strong { color: var(--ink); }

/* ── Chapters: the "17 minutes" bug ──────────────────────────────────
   components.css clamps .chapter-list to 460px with overflow:auto. On iOS
   no scrollbar is drawn until you touch it, so 8 of 35 chapters read as
   the whole episode. Here the clamp is on a wrapper with a visible fade
   and an explicit button, and the header states the count and runtime. */
.chapters-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 12px;
}
.chapters-head h3 { margin-bottom: 0; }
.chapters-count {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ep-layout--v2 .chapter-list { max-height: none; overflow: visible; }
.chapters-clip { position: relative; max-height: 352px; overflow: hidden; }
.chapters-clip::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 56px;
  background: linear-gradient(to bottom, rgba(255,255,255,0), var(--card, #fff));
  pointer-events: none;
}
.chapters-clip.open { max-height: none; }
.chapters-clip.open::after { display: none; }
/* after the base rule, not inside the layout block above: a media query that
   comes first in the file loses to a later unconditional rule. */
.chapters-more {
  width: 100%;
  margin-top: 10px;
  padding: 10px 12px;
  background: none;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--accent-text);
  cursor: pointer;
}
.chapters-more:hover { background: var(--bg-alt); }

/* ── Transcript: out of the column, collapsed by default ─────────────
   EP19, 20 and 21 shipped without the toggle every earlier episode has.
   307 open entries made the EP21 page 84,193px tall. */
.transcript-section { padding-top: 0; }
.transcript-count { font-size: 0.85rem; font-weight: 600; color: var(--muted); }

@media (max-width: 899px) {
  .ep-block { margin-top: var(--space-8); }
  .chapters-clip { max-height: 308px; }
}

/* ── Mobile: collapse the long blocks ─────────────────────────────────
   Sam's second note. Even with the transcript closed the page ran 15
   screens on a phone. Everything below is mobile-only: on desktop there
   is room, so the clips open to full height and the buttons disappear.

   Two patterns:
     .mclip      a block clipped to a few lines with a fade and a "more"
                 button, used where the first lines still have to be read
                 (about, takeaways, the mentions list)
     .mchip      a block hidden entirely behind a chip, used where the
                 content is reference material (quotes, transcript) */
.mclip { position: relative; overflow: hidden; max-height: var(--mclip-h, 260px); }
.mclip::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 64px;
  background: linear-gradient(to bottom, rgba(255,255,255,0), var(--bg));
  pointer-events: none;
}
.mclip.open { max-height: none; }
.mclip.open::after { display: none; }

.mclip-more,
.mchip {
  display: block;
  width: 100%;
  margin-top: 12px;
  padding: 12px 16px;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--accent-text);
  cursor: pointer;
  text-align: center;
}
.mclip-more:hover, .mchip:hover { background: var(--bg-alt); }

.mchip { margin-top: 0; display: flex; align-items: center; justify-content: space-between; text-align: left; }
.mchip__count { font-weight: 600; color: var(--muted); font-size: 0.82rem; }
.mchip svg { width: 18px; height: 18px; flex-shrink: 0; transition: transform 0.2s ease; }
.mchip[aria-expanded="true"] svg { transform: rotate(180deg); }
.mchip-body { display: none; }
.mchip-body.open { display: block; padding-top: var(--space-4); }

/* The quotes heading is carried by the chip on mobile, so hide the h2
   there and show it again on desktop where the chip is gone. */
@media (max-width: 899px) {
  .ep-quotes > h2 { display: none; }
}
@media (min-width: 900px) {
  .mclip { max-height: none; }
  .mclip::after { display: none; }
  .mclip-more, .mchip { display: none; }
  .mchip-body { display: block; }
}

/* Collapsed blocks are short, so the section padding that reads as air on
   desktop reads as dead space on a phone. 128px and 112px gaps around the
   transcript chip measured at 375px; halved here. */
@media (max-width: 899px) {
  .transcript-section { padding-bottom: var(--space-8); }
  .ep-layout--v2 { gap: var(--space-6); }
  .ep-block { margin-top: var(--space-6); }
}

/* ── Sam's second pass ───────────────────────────────────────────────── */

/* 1. A real breadcrumb. The old one was a back-arrow link plus an eyebrow
   line repeating the topic and "Recorded in Kyiv, 2026", which the meta
   line under the lead already carries. */
.phero__breadcrumb { gap: 0.4rem; margin-bottom: var(--space-4); }
.phero__breadcrumb a:hover { text-decoration: underline; }
.phero__breadcrumb [aria-current] { color: var(--ink); font-weight: 600; }

/* 4. The "more" buttons sat flush against whatever followed them, which on
   the show notes meant "Show less" touching the next group heading. */
.mclip-more { margin-bottom: var(--space-5); }
.notes-group + .mclip-more { margin-top: var(--space-4); }

/* 6. Dead space at the foot of the column. With the quotes and transcript
   collapsed to single rows, the gaps between them measured 128px and 112px
   at 375px: that is section padding sized for full-height blocks. */
.ep-quotes { margin-bottom: 0; }
.transcript-section { padding-top: 0; }
@media (max-width: 899px) {
  .transcript-section { padding-bottom: var(--space-6); }
  .ep-main-rest > .ep-block:last-child { margin-bottom: 0; }
}

/* 7. .donate-bar-inner is also a .container, and its own
   `padding: var(--space-8) 0` lands later in components.css than
   `.container { padding: 0 24px }`, so it wins and the band loses its
   side padding entirely. Same specificity, later rule. Site-wide bug;
   fixed here for the prototype, noted on the issue for the rollout. */
.donate-bar-inner { padding-left: 24px; padding-right: 24px; }

@media (max-width: 899px) {
  .ep-shell { padding-top: var(--space-6); padding-bottom: var(--space-6); }
}

/* ── Desktop: sidebar offset and overflow ────────────────────────────
   Two separate problems, both only visible above 900px.

   1. The sticky offset was 80px, set when the header was just the nav.
      With the Why War Matters bar the header is 110px, so the chapters
      card parked 30px underneath it. --umh-sticky-h is measured on load.

   2. The sidebar is 1,164px (chapters 636 + download 504) against 774px
      of usable height at 900px viewport, so pinning the whole column put
      the bottom of the download card permanently out of reach. Only the
      chapters card is pinned now; the download card scrolls normally. */
@media (min-width: 900px) {
  /* The form is stuck to the bottom of the chapters block: the two travel
     as one pinned unit, and the chapter LIST is the only thing that
     scrolls. No outer scroll container around both, no form sliding over
     the chapters, no form scrolling away on its own. */
  .ep-layout--v2 > .ep-sidebar {
    position: sticky;
    top: calc(var(--umh-sticky-h, 110px) + var(--space-4));
    align-self: start;
    max-height: calc(100vh - var(--umh-sticky-h, 110px) - var(--space-8));
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    overflow: visible;
  }
  .ep-layout--v2 .sidebar-card {
    position: static;
    display: flex;
    flex-direction: column;
    min-height: 0;
    flex: 0 1 auto;
  }
  /* whatever height is left after the form, the list takes and scrolls in */
  .ep-layout--v2 .chapters-clip {
    flex: 1 1 auto;
    max-height: none;
    min-height: 140px;
    overflow-y: auto;
  }
  .ep-layout--v2 .chapters-clip.open { max-height: none; overflow: visible; }
  /* With all 35 showing there is nothing to grow into while the column is
     capped to the viewport, so expanding also unpins it: the full list runs
     down the page with the form still attached underneath. */
  .ep-layout--v2 > .ep-sidebar.is-expanded {
    position: static;
    max-height: none;
  }
  .ep-layout--v2 .chapters-head,
  .ep-layout--v2 .chapters-more { flex: 0 0 auto; }
  .ep-layout--v2 .download-card { flex: 0 0 auto; }
}

/* Anchor and seek jumps land under the header for the same reason. */
:root { scroll-padding-top: calc(var(--umh-sticky-h, 110px) + var(--space-4)); }

/* ── Desktop: the quotes ─────────────────────────────────────────────
   Ten cards in one column is 1,140px of scrolling for ten sentences.
   They read better as a pair of columns, and it costs nothing on mobile
   where the whole block is behind a chip. */
@media (min-width: 900px) {
  .mchip-body#quotesBody {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
    align-items: start;
  }
}

/* ── Share row, moved into the hero ──────────────────────────────────
   It used to sit at the very foot of the page, under the transcript,
   where nobody shares anything. The hero meta line has empty space to
   its right on desktop, so it goes there: same row above 900px,
   its own row underneath on a phone. */
.phero__meta .share { gap: 0.5rem; }
@media (min-width: 900px) {
  .phero__meta .share { margin-left: auto; }
}
/* On a phone the row wraps under the meta line and every pixel there
   pushes the video down, so it loses the label and tightens up. */
@media (max-width: 899px) {
  .phero .share__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .phero__meta .share { margin-top: var(--space-3); gap: 0.4rem; }
  .phero .share-link { width: 34px; height: 34px; }
}

/* ── Hero spacing ────────────────────────────────────────────────────
   The share row keeps its own border-top and 24px of padding from when
   it sat alone at the foot of the page. Inside the meta line that rule
   spans only the width of the icons, so it reads as a half-finished
   divider floating in the middle of the hero. */
/* .share carries margin-top:32px, padding-top:24px and a border-top from
   when it sat alone at the foot of the page. Inside the meta line all three
   are wrong: the margin pushed it 16px below the text's centre, so the row
   read as two staggered lines rather than one, and the border drew a
   half-width rule across the middle of the hero. */
.phero__meta .share { margin-top: 0; border-top: 0; padding-top: 0; }

/* The lead ran the full 1,076px of the container: a 150-character measure
   that nobody reads to the end of. The hero sits outside the article grid,
   so the text column is matched to it by hand: total width less the 300px
   sidebar and the 40px gutter. The lead then wraps on the same measure as
   the body copy, and the share row's right edge lands exactly on the right
   edge of the video below it instead of floating out at the page margin. */
@media (min-width: 900px) {
  .phero .lead { max-width: calc(100% - 300px - 40px); }
  /* one line, always: nowrap, and the row only keeps the content-column
     cap where there is actually room for both halves side by side */
  .phero__meta {
    align-items: center;
    flex-wrap: nowrap;
    white-space: nowrap;
  }
}
@media (min-width: 900px) {
  /* The row always ends on the video's right edge. Previously it switched
     to the full container below 1200px, so the share jumped sideways as a
     window was resized past that point. The share shrinks instead. */
  .phero__meta { max-width: calc(100% - 300px - 40px); }
}
@media (min-width: 900px) and (max-width: 1279px) {
  .phero .share__label { display: none; }
  .phero .share-link { width: 30px; height: 30px; }
  .phero__meta .share { gap: 0.3rem; }
}
@media (max-width: 899px) {
  .phero .lead { max-width: 60ch; }
}

/* ── FAQ ─────────────────────────────────────────────────────────────
   components.css centres .faq-list in the container (max-width 760,
   margin auto) while its own heading is left-aligned, so the block sits
   158px to the right of everything else on the page and leaves a dead
   gutter down the left. It also carries a border under the last item,
   which draws the bottom of a box that is not there, and then 80px of
   section padding under that. */
.faq-list { margin-left: 0; margin-right: 0; max-width: 736px; }
.faq-item:last-child { border-bottom: 0; }

/* ── Quotes ─────────────────────────────────────────────────────────
   Before: a left rule, body text, and two unstyled spans that ran
   together as "Andriy Zagorodnyuk20:25" because .quote-meta,
   .quote-author and .quote-ts have no rules in any linked stylesheet.
   Laid out as a two-column grid, the cards also stretched to the tallest
   in each row and left ragged holes.

   Now: real cards that pack by height in two columns, with the speaker's
   face and a timestamp that seeks the player. */
@media (min-width: 900px) {
  .mchip-body#quotesBody {
    display: block;
    columns: 2;
    column-gap: var(--space-5);
  }
}
.quote-card {
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  margin: 0 0 var(--space-5);
  padding: var(--space-5) var(--space-5) var(--space-4);
  background: var(--card);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-lg);
  transition: border-color 0.18s, box-shadow 0.18s;
}

.quote-card blockquote {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.55;
  font-weight: 500;
  color: var(--ink);
}
.quote-meta {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--hairline);
}
.quote-meta img { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.quote-author { font-size: 0.85rem; font-weight: 600; color: var(--muted); }
.quote-ts {
  margin-left: auto;
  padding: 3px 9px;
  background: var(--accent-soft);
  border: 0;
  border-radius: var(--radius-full);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
  transition: background 0.18s, color 0.18s;
}

/* ── One hover language for everything that seeks the player ─────────
   Three controls did the same job and said so three different ways: a
   chapter row went grey, a quote card drew an accent border and a drop
   shadow, a reference timestamp underlined itself. Same action, so the
   same signal: an accent tint on the row and the timestamp filling in.
   Shapes still differ, which is correct, because a card is not a row. */
.chapter-item,
.quote-card,
.notes-list li[data-seek] {
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
@media (hover: hover) and (pointer: fine) {
  .chapter-item:hover,
  .quote-card:hover,
  .notes-list li[data-seek]:hover { background: var(--accent-soft); }
  .quote-card:hover { border-color: var(--accent); }
  /* the timestamp is the shared tell: it fills in wherever it lives */
  .chapter-item:hover .chapter-time,
  .notes-list li[data-seek]:hover .notes-ts,
  .quote-card:hover .quote-ts { background: var(--accent); color: #fff; }
}

/* keyboard focus gets the same treatment on every device */
.chapter-item:focus-visible,
.quote-card:focus-visible,
.notes-list li[data-seek]:focus-visible { background: var(--accent-soft); }
.quote-card:focus-visible { border-color: var(--accent); }
.chapter-item:focus-visible .chapter-time,
.notes-list li[data-seek]:focus-visible .notes-ts,
.quote-card:focus-visible .quote-ts { background: var(--accent); color: #fff; }

/* touch: a brief press state instead of a hover that stays painted on */
.chapter-item:active,
.quote-card:active,
.notes-list li[data-seek]:active { background: var(--accent-soft); }
.chapter-time,
.notes-ts {
  border-radius: var(--radius-full);
  padding: 2px 8px;
  transition: background 0.15s, color 0.15s;
}
.notes-list li[data-seek] { border-radius: var(--radius-md); padding-left: 8px; padding-right: 8px; }

:where(.chapter-item, .quote-card, .notes-list li[data-seek]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── Pre-existing: the RSS toast forces a horizontal scrollbar ───────
   .rss-toast is an invisible tooltip under the RSS button, inline-styled
   white-space:nowrap and centred on its button. Near the right edge of a
   narrow window it extends past the viewport and the page gains 48px of
   horizontal scroll even though nothing is visible out there. Reproduced
   on the live episode-20 page at 768px, so it is not from this work;
   fixed here because it is on the page being shipped. */
.rss-toast {
  white-space: normal !important;
  max-width: min(70vw, 240px) !important;
  text-align: center;
}

/* ── One column width below the grid ────────────────────────────────
   The transcript section and the subscribe bar were full-container
   (1,140px) while the FAQ and the article column are 736px, so the page
   changed measure three times on the way down. */
.transcript-section > .transcript-container,
.subscribe-bar { max-width: 736px; margin-left: 0; margin-right: 0; }

/* ── Empty status line in the download card ─────────────────────────
   .form-msg reserves `min-height: 1.2em` plus a 12px margin for a message
   that is only written after a submit, so every card carries a blank
   band between the button and "100% free". It keeps its role="status"
   and aria-live, so screen readers still get the message when it appears;
   :empty simply stops it taking space until then. */
.form-msg:empty { min-height: 0; margin-top: 0; }

/* ── Radius scale ───────────────────────────────────────────────────
   Audited every rounded element on the page. Three tiers were already in
   use and only three exceptions sat outside them:

     9px  (--radius-lg)   cards and containers
     6px  (--radius-md)   controls: buttons, inputs, tinted rows
     999  (--radius-full) pills and chips: timestamps, speaker, platform
     50%                  circular avatars and icon badges

   1. The Spotify embed carries an inline border-radius:12px, the only 12
      on the page, sitting directly under a 9px video frame. */
.audio-player iframe { border-radius: var(--radius-lg) !important; }

/* 2. Chapter rows had square corners while the reference rows they now
      share a hover language with were 6px. Both are tinted seekable rows. */
.ep-layout--v2 .chapter-item { border-radius: var(--radius-md); }

/* ── Scrollable lists stop at whole rows ────────────────────────────
   Both scrolling lists came to rest mid-row, so the top of the card
   showed half a chapter and read as broken rather than as scrolled. */
.chapters-clip, .mclip { scroll-snap-type: y proximity; }
.chapter-item, .notes-list li { scroll-snap-align: start; scroll-margin-top: 2px; }

/* The fade said "more below" but nothing said "more above" once the list
   had been scrolled. */
.chapters-clip { position: relative; }
.chapters-clip::before {
  content: "";
  position: sticky;
  top: 0;
  display: block;
  height: 18px;
  margin-bottom: -18px;
  background: linear-gradient(to bottom, var(--card), rgba(255,255,255,0));
  pointer-events: none;
  z-index: 1;
}

/* ── Rhythm between the stacked blocks at the foot of the page ──────
   Measured at 1341px: 72px between the last quote and the transcript
   chip, 88px between that chip and the subscribe bar, 112px before the
   FAQ. Those are margins sized for full-height blocks; the chips are
   single rows, so the page read as a column of orphaned bars. 40px
   between all three instead.

   72 = .ep-shell padding-bottom 24 + .transcript-container margin-top 48 */
.transcript-section .transcript-container { margin-top: 0; }
/* 88 = .transcript-section padding-bottom 24 + .subscribe-bar margin-top 64 */
.subscribe-bar { margin-top: var(--space-4); }
/* 112 = the FAQ section's own 80px top padding */
section.container.section:has(.faq-list) { padding-top: var(--space-2); }

@media (min-width: 900px) {
  .ep-shell { padding-bottom: var(--space-10); }
  .transcript-section { padding-top: var(--space-4); padding-bottom: 0; }
}
