/* Nighttime Nathan — static episode pages (/episodes and /episodes/<slug>).
   Layers on styles.css: the night-sky background, fonts and colour tokens all
   come from there, so this file only describes the reading layout.
   Everything here must work with JavaScript off — that's the whole point of
   these pages. No transitions that hide content, no JS-dependent reveals. */

/* Same night sky as the rest of the site, minus the three repeating star
   tiles. On a landing page they're decoration; on a page that is mostly running
   text they kept landing in the gap beside a word — next to "Home", between
   nav links — where a 1.5px dot reads as a stray period. The two big glows and
   the base gradient stay, so the pages still feel like the night sky. */
.ep-page {
  color: var(--ink);
  background-image:
    radial-gradient(1200px 600px at 80% -10%, #16305f66, transparent 60%),
    radial-gradient(900px 500px at 10% 30%, #12294f55, transparent 60%),
    linear-gradient(180deg, var(--navy-900) 0%, var(--navy-800) 45%, var(--navy-900) 100%);
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-size: auto, auto, 100% 100%;
}

/* --- chrome ------------------------------------------------------------- */

/* These pages carry THE site header (.nav, from styles.css), not a lookalike —
   see site_header() in tools/build_pages.py. What's left here is the one thing
   the homepage doesn't need: .ep-head pins directly beneath the header, so it
   needs the header's exact height, and that offset has to hold with JS off,
   which rules out measuring it at runtime.

   So the height is pinned rather than derived from padding: 42px logo + 12px
   above and below + the 1px border. The homepage nav has no height breakpoints,
   so neither does this — one number at every width. If .nav-logo or .nav's
   padding ever changes, this changes with it. */
:root { --ep-nav-h: 67px; }

.ep-page .nav {
  height: var(--ep-nav-h);
  padding-top: 0;
  padding-bottom: 0;
}

/* --- sticky episode header: title, then the player ----------------------- */
/* Title and player pin together, directly beneath the sticky nav. These are
   SIBLINGS of .nav, not nested inside a shared wrapper — a sticky element
   can't travel outside its parent's box, so a wrapper that scrolls away would
   drag the player off-screen with it. */

.ep-head {
  position: sticky;
  top: var(--ep-nav-h);
  z-index: 30;
  /* fully opaque, not a tint: content scrolling underneath showed through at
     92%, and backdrop-filter is off-limits on this site */
  background: var(--navy-900);
  border-bottom: 1px solid rgba(255, 213, 74, 0.3);
  box-shadow: 0 10px 30px rgba(2, 8, 26, 0.45);
  padding: 14px clamp(16px, 4vw, 24px) 12px;
}

.ep-head-inner { max-width: 760px; margin: 0 auto; }

/* Centred to match the full-screen player, which centres its number, title and
   tags — and so the header reads as one player module rather than as the first
   line of the left-aligned article below it.
   Line-clamped on purpose: a three-line title would push the player off-screen. */
/* .ep-page-prefixed to stay ahead of the page-scope .ep-page .ep-title rule
   further down this file. Both were (0,2,0) for a moment, and since that one
   comes later it won the tie and blew this header title up from 28px to 40px
   on a position:sticky header — permanently eating a third of a phone screen. */
.ep-page .ep-head .ep-title {
  font-size: clamp(1.25rem, 3.6vw, 1.75rem);
  line-height: 1.2;
  margin: 0 0 4px;
  text-align: center;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ep-head .ep-meta { margin: 0 0 10px; font-size: 0.88rem; text-align: center; }

/* --- the way out -------------------------------------------------------- */
/* The first row of the sticky header, so it is reachable from any scroll
   position. It used to be a breadcrumb ABOVE the header that scrolled off the
   top, which left the homepage as the only way back once you were reading.

   Deliberately quiet — an arrow and a word, not a button. It shares a small
   sticky header with a title and a full transport, and as a bordered pill with
   the episode number sitting opposite it the row read as a toolbar. The
   episode number went back into the meta line where it had always been. */
.ep-back { display: flex; margin: 0 0 6px; }

.ep-back-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: -3px;              /* optical: the arrow hangs into the gutter */
  padding: 3px 6px 3px 0;
  color: var(--muted);
  font-weight: 800;
  font-size: 0.8rem;
  text-decoration: none;
  transition: color 0.18s;
}

.ep-back-link svg { width: 14px; height: 14px; flex-shrink: 0; }
.ep-back-link:hover { color: var(--gold); }

/* the collection pages use the same link above their <h1>, with room to breathe
   since nothing is sticky there */
.ep-main > .ep-back { margin-bottom: 12px; }

/* .ep-num is the homepage card's gold pill. It's used on the LIST rows, where
   it helps you scan 31 of them; the detail page states the number in the meta
   line like the date and runtime. */
.ep-list .ep-num { margin-right: 5px; }

/* the no-JS fallback: shown until main.js hands the episode to the shared
   player. This is what crawlers read, so it stays in the markup either way. */
.ep-head audio { width: 100%; color-scheme: dark; }

/* --- the header transport ----------------------------------------------- */
/* A real player, not a lone Play button: where you are, how long is left, ±15s
   and a scrub. It drives the ONE shared <audio> in #ntnLayers, so it and the
   mini bar can never disagree about what's playing. */
.epp-ui { display: block; }
.epp-ui[hidden] { display: none; }

.epp-scrub { margin: 2px 0 4px; }
.epp-bar {
  position: relative; height: 7px; border-radius: 99px;
  background: rgba(255, 255, 255, 0.16); cursor: pointer;
}
/* fat touch target without a fat bar */
.epp-bar::before { content: ""; position: absolute; left: 0; right: 0; top: -13px; bottom: -13px; }
.epp-bar:focus-visible { outline: 2px solid var(--gold); outline-offset: 6px; }
.epp-fill {
  position: relative; height: 100%; width: 0%; border-radius: 99px;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold));
}
.epp-knob {
  position: absolute; right: -6px; top: 50%; margin-top: -7px;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--gold); box-shadow: 0 2px 8px rgba(2, 8, 26, 0.65);
}
.epp-times {
  display: flex; justify-content: space-between; margin-top: 7px;
  font-size: 0.72rem; font-weight: 800; color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Nothing but Play works until this page's episode IS the current track —
   scrubbing or skipping would otherwise move a DIFFERENT story, the one still
   playing from the page you came from. main.js adds .is-live when they match. */
   The full-screen handle is disabled with them: openFull() has nothing to show
   without a current track, so leaving it live made it a control that visibly
   did nothing. */
.epp-ui:not(.is-live) .epp-bar { cursor: default; }
.epp-ui:not(.is-live) .epp-bar,
.epp-ui:not(.is-live) .epp-ctl { opacity: 0.35; pointer-events: none; }
.epp-ui:not(.is-live) .epp-knob { display: none; }

/* The play button is centred on the PAGE, not on the row: .epp-more is pulled
   out of the flow so its 40px doesn't shove the transport off-centre to the
   left, which is exactly what a lone right-hand control does in a flex row. */
.epp-transport {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  gap: clamp(10px, 4vw, 22px);
}

.epp-ctl {
  position: relative; flex-shrink: 0;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  background: none; border: 0; padding: 0;
  border-radius: 50%;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  transition: color 0.18s, transform 0.15s, opacity 0.18s;
}
@media (hover: hover) and (pointer: fine) {
  .epp-ctl:hover { color: var(--gold); transform: scale(1.08); }
}
.epp-ctl svg { width: 23px; height: 23px; }
/* the little "15" tucked inside the skip arrows, same as the full player */
.epp-skip span {
  position: absolute; left: 50%; top: 55%; transform: translate(-50%, -50%);
  font-size: 0.5rem; font-weight: 900; letter-spacing: 0;
}
/* the handle up into the full screen player — shuffle, speed and the queue
   live there, and there is no room for them on a sticky header */
.epp-more {
  position: absolute; right: 0; top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
}
@media (hover: hover) and (pointer: fine) {
  .epp-more:hover { transform: translateY(-50%) scale(1.08); }
}

/* Same gold disc as the full screen player's, three quarters the size. */
.epp-play {
  display: grid; place-items: center;
  width: 56px; height: 56px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  color: var(--navy-900);
  box-shadow: 0 8px 22px rgba(255, 213, 74, 0.28), 4px 4px 0 rgba(148, 96, 12, 0.45);
  transition: transform 0.15s;
}
.epp-play svg { width: 26px; height: 26px; }
@media (hover: hover) and (pointer: fine) {
  .epp-play:hover { transform: scale(1.05); }
}
.epp-play:active { transform: scale(0.97); }

/* --- previous / next EPISODE -------------------------------------------- */
/* At the foot of the article, not under the play button. As a ⏮/⏭ pair inside
   the transport they were read as track skips — they are page changes. */
.ep-adjacent {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin: 30px 0 0;
}

.ep-adj {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 14px 16px;
  border-radius: 16px;
  background: var(--card);
  border: 1px solid var(--card-border);
  text-decoration: none;
  color: var(--ink);
  transition: border-color 0.18s, background 0.18s;
}
.ep-adj:hover { border-color: var(--gold); background: rgba(255, 213, 74, 0.08); }
.ep-adj span { font-size: 0.76rem; font-weight: 800; color: var(--muted); letter-spacing: 0.03em; }
.ep-adj strong { font-weight: 800; font-size: 0.94rem; line-height: 1.35; }
/* a first or last episode leaves one cell — the survivor keeps its own side */
.ep-adj-next { text-align: right; grid-column: 2; }

@media (max-width: 560px) {
  .ep-adjacent { grid-template-columns: minmax(0, 1fr); }
  .ep-adj-next { text-align: left; grid-column: 1; }
}

/* A sticky header is space you never get back, so on a phone every gap in it is
   spent deliberately. The transport is worth its 50px; the air around it isn't.
   Trimmed until the header sits close to what the old Play-button-only version
   cost, while now carrying position, runtime, ±15s and a scrub. */
@media (max-width: 700px) {
  .ep-head { padding: 9px 16px 9px; }
  .ep-back { margin-bottom: 6px; }
  .ep-head .ep-meta { margin-bottom: 5px; }
  .epp-scrub { margin: 0 0 2px; }
  .epp-times { margin-top: 5px; }
  .epp-play { width: 50px; height: 50px; }
  .epp-play svg { width: 23px; height: 23px; }
  .epp-ctl { width: 36px; height: 36px; }
  .epp-ctl svg { width: 21px; height: 21px; }
}

/* The header's own rules (.nav, .nav-brand, .nav-name, .nav-links, .nav-burger)
   all live in styles.css and are shared with the homepage. The .ep-brand /
   .ep-navlinks set that used to be here described a second, slightly different
   header and is gone with it. */

.ep-footlinks a {
  color: var(--muted);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
}

.ep-footlinks a:hover,
.ep-crumb a:hover { color: var(--gold); text-decoration: underline; }

.ep-main {
  max-width: 760px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px) clamp(16px, 4vw, 24px) 64px;
}

/* sits between the nav and the sticky header, so it carries its own gutters
   rather than inheriting .ep-main's */
.ep-crumb {
  font-size: 0.88rem;
  color: var(--muted);
  max-width: 760px;
  margin: 0 auto;
  padding: 16px clamp(16px, 4vw, 24px) 14px;
}

.ep-crumb a { color: var(--muted); text-decoration: none; }

/* the index page keeps its breadcrumb inside <main> */
.ep-main .ep-crumb { padding: 0; margin: 0 0 18px; max-width: none; }

/* --- episode header ----------------------------------------------------- */

/* Scoped to .ep-page deliberately. This stylesheet now loads on EVERY page —
   the navigation shell can't inject a <link> mid-swap without a flash on a dark
   background — and styles.css:551 gives .ep-title 1.08rem for the episode cards
   on the homepage. Both rules are (0,1,0) and this file loads second, so left
   unscoped it blew all 31 card titles up to 2.5rem in Brown Beige — except the
   featured one, which .ep-card.featured .ep-title (0,2,0) still pinned at
   1.4rem, leaving the NEWEST episode's title visibly smaller than the rest. */
.ep-page .ep-title,
.ep-main h1 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1.18;
  font-size: clamp(1.7rem, 5vw, 2.5rem);
  margin: 0 0 10px;
}

.ep-meta { color: var(--muted); font-size: 0.94rem; margin: 0 0 22px; }

.ep-lede { color: var(--muted); margin: 0 0 26px; max-width: 60ch; }

.ep-notes p { margin: 0 0 16px; }

/* --- fact blocks (worlds / themes / pals) -------------------------------- */

/* One panel of labelled rows rather than three side-by-side cards: the cards
   held wildly different amounts of text (three worlds with descriptions next
   to a single pal), so as columns they read as ragged and half-empty. Rows
   let each label line up and the content run the full width. */
.ep-facts {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  padding: 2px 22px;
  margin: 34px 0;
}

/* Without a word of framing, three bare labels read as stray metadata — the
   title alone is enough to say what the panel is. */
.ep-facts-intro {
  padding: 18px 0 14px;
  border-bottom: 1px solid var(--card-border);
}

.ep-facts-intro h2 {
  font-family: var(--font-display);
  font-size: 1.15rem;
  margin: 0;
}

.ep-fact {
  display: grid;
  grid-template-columns: 165px 1fr;
  gap: 4px 20px;
  padding: 16px 0;
  border-bottom: 1px solid var(--card-border);
}

.ep-fact:last-child { border-bottom: 0; }

.ep-fact h3 {
  font-family: var(--font-display);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 3px 0 0;
}

.ep-fact ul { margin: 0; padding: 0; list-style: none; }
.ep-fact li { margin-bottom: 7px; font-size: 0.95rem; }
.ep-fact li:last-child { margin-bottom: 0; }

/* each world and theme links to its own page — that's what makes those pages
   reachable at all, so they need to read as links */
.ep-fact li a { color: var(--sky-blue); text-decoration: none; }
.ep-fact li a:hover { color: var(--gold); text-decoration: underline; }

@media (max-width: 700px) {
  .ep-facts { padding: 2px 18px; }
  .ep-fact { grid-template-columns: 1fr; gap: 8px; }
}

/* --- related / index list ----------------------------------------------- */

.ep-related h2,
.ep-listen h2,
.ep-cta h2 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  margin: 0 0 14px;
}

.ep-related ul,
.ep-list { list-style: none; margin: 0; padding: 0; }

.ep-related li { margin-bottom: 12px; }
.ep-related a { color: var(--sky-blue); font-weight: 700; text-decoration: none; }
.ep-related a:hover { text-decoration: underline; }
.ep-related span { color: var(--muted); font-size: 0.93rem; }

.ep-list li {
  padding: 18px 0;
  border-bottom: 1px solid var(--card-border);
}

.ep-list li:last-child { border-bottom: 0; }

.ep-list h2 {
  font-family: var(--font-display);
  font-size: 1.15rem;
  line-height: 1.3;
  margin: 0 0 6px;
}

.ep-list h2 a { color: var(--ink); text-decoration: none; }
.ep-list h2 a:hover { color: var(--gold); }
.ep-list p { margin: 0 0 4px; color: var(--muted); font-size: 0.95rem; }

/* Play right here. The button and the little equaliser are the homepage's own
   (.ep-play / .eq in styles.css) — a row just needs somewhere to put them, and
   the is-playing rules the cards get, since .ep-row is what js/player.js marks. */
.ep-row-actions { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.ep-row .ep-play { padding: 7px 16px; font-size: 0.85rem; }
.ep-row.is-playing .ep-play { background: var(--gold); border-color: var(--gold); color: var(--navy-900); }
.ep-row.is-playing .eq { display: inline-flex; }

/* --- calls to action ----------------------------------------------------- */

/* every block on the page is a panel — related was the odd one out as bare
   text between two cards */
.ep-related,
.ep-cta,
/* --- browse sideways ----------------------------------------------------- */
/* The other pals / places / feelings, at the foot of a collection page. Without
   it a collection page is a filter you can't change: from one world the only
   ways on were a single episode or the homepage. Pills, because that is what
   the homepage finder uses for exactly this choice. */
.ep-browse {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  padding: 22px;
  margin: 30px 0 0;
}
.ep-browse h2 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  margin: 0 0 14px;
}
.ep-browse-rows { display: flex; flex-wrap: wrap; gap: 8px; }
/* desktop: the two courses melt into one wrapping row, exactly as the
   homepage's filter pills do */
.ep-browse .pill-row { display: contents; }
.ep-browse a {
  display: inline-block;
  padding: 7px 13px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--card-border);
  color: var(--ink);
  font-weight: 800;
  font-size: 0.82rem;
  text-decoration: none;
  transition: border-color 0.18s, background 0.18s, color 0.18s;
}
.ep-browse a:hover {
  background: rgba(255, 213, 74, 0.12);
  border-color: var(--gold);
  color: var(--gold);
}

/* On a phone a long list becomes a two-row swipe rail, the same shape the
   homepage's filter pills take — because 37 pals stacked vertically was
   1,550px of page, more than half the character page, for a control that
   belongs at the bottom. Two rows rather than one halves the swiping.

   The two rows are REAL ROWS in the markup, not a two-row CSS grid. Grid sizes
   every column to its widest pill, so "Fridge City" sitting under "The
   Breakfast Kingdom" was followed by a gap the width of the difference and the
   whole block looked mis-set. Flex courses let each pill keep its own width.
   build_pages.browse_strip() splits them by total WIDTH, not by count, so the
   two rows end together.

   Every pill is in the HTML either way — this only decides how much screen they
   cost a reader, never which links exist for a crawler.

   .is-few (under 8 pills, i.e. the themes) keeps wrapping: four pills laid out
   as two short courses looks like a mistake. */
@media (max-width: 720px) {
  .ep-browse:not(.is-few) { padding: 20px 0; }
  .ep-browse:not(.is-few) h2 { padding: 0 18px; }
  .ep-browse:not(.is-few) .ep-browse-rows {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: flex-start;
    overflow-x: auto;
    padding: 3px 18px 6px;
    scroll-snap-type: x proximity;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
            mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
  }
  .ep-browse-rows::-webkit-scrollbar { display: none; }
  .ep-browse:not(.is-few) .pill-row {
    display: flex; gap: 8px; width: max-content;
  }
  .ep-browse:not(.is-few) a { white-space: nowrap; scroll-snap-align: start; }
}

.ep-listen {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  padding: 22px;
  margin: 30px 0 0;
}

.ep-cta p { margin: 0 0 14px; color: var(--muted); }
.ep-cta p:last-child { margin-bottom: 0; }

.ep-btn {
  display: inline-block;
  background: var(--gold);
  color: var(--navy-900);
  font-weight: 800;
  text-decoration: none;
  padding: 11px 22px;
  border-radius: 999px;
  box-shadow: var(--shadow-pop);
}

.ep-btn:hover { background: var(--gold-deep); }

.ep-listen-links { display: flex; flex-wrap: wrap; gap: 10px 20px; margin: 0; }
.ep-listen-links a { color: var(--sky-blue); font-weight: 700; text-decoration: none; }
.ep-listen-links a:hover { text-decoration: underline; }

/* --- footer -------------------------------------------------------------- */

.ep-foot {
  border-top: 1px solid var(--card-border);
  /* Room for the docked mini player. It reaches every page now that the shared
     player is site-wide, and at 40px it sat straight over the footer links and
     the copyright. Same reserve .footer uses on the homepage. */
  padding: 26px clamp(16px, 4vw, 40px) calc(130px + env(safe-area-inset-bottom, 0px));
  text-align: center;
}

.ep-footlinks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 20px;
  margin-bottom: 14px;
}

.ep-copy { color: var(--muted); font-size: 0.85rem; margin: 0; }
