/* ============================================================
   Nighttime Nathan — night-sky design system
   Display face: Brown Beige (official brand font)
   ============================================================ */

@font-face {
  font-family: "Brown Beige";
  src: url("../assets/fonts/BrownBeige.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

:root {
  --navy-950: #050d20;
  --navy-900: #071229;
  --navy-800: #0a1a3a;
  --navy-700: #10254e;
  --navy-600: #17315f;
  --ink: #eef3ff;
  --muted: #aebcdd;
  --gold: #ffd54a;
  --gold-deep: #f5b52e;
  --gold-soft: #ffe9a3;
  --cream: #fff3c4;
  --sky-blue: #8fd0ff;
  --card: rgba(255, 255, 255, 0.055);
  --card-border: rgba(255, 255, 255, 0.11);
  --shadow-pop: 0 10px 30px rgba(2, 8, 26, 0.55);
  --r-lg: 22px;
  --r-xl: 30px;
  --font-display: "Brown Beige", "Nunito", system-ui, sans-serif;
  --font-body: "Nunito", system-ui, sans-serif;
  /* Yoto's brand orange, sampled from the approved lockup in assets/yoto/.
     A partner's colour, not one of ours — don't tint it to match the palette. */
  --yoto-orange: #f85e42;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; overflow-x: clip; } /* clip (not hidden!) — blocks sideways scroll without breaking the sticky nav */

body {
  font-family: var(--font-body);
  /* the sky the "rooms" float on: three mismatched star tiles (160/190/210 so
     no visible grid) over the original soft glows. Static — never animate. */
  background-image:
    radial-gradient(1.6px 1.6px at 22px 28px, rgba(238, 243, 255, 0.5) 50%, transparent 52%),
    radial-gradient(1.2px 1.2px at 96px 82px, rgba(255, 233, 163, 0.38) 50%, transparent 52%),
    radial-gradient(1.3px 1.3px at 60px 128px, rgba(143, 208, 255, 0.32) 50%, transparent 52%),
    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: repeat, repeat, repeat, no-repeat, no-repeat, no-repeat;
  background-size: 160px 160px, 190px 190px, 210px 210px, auto, auto, 100% 100%;
  background-color: var(--navy-900);
  color: var(--ink);
  line-height: 1.6;
  /* clip, not hidden: the tilted marquee is 1% oversize, but overflow-x:hidden
     creates a scroll container that silently breaks the sticky nav */
  overflow-x: clip;
}

img { max-width: 100%; display: block; }
/* The page behind the full screen player must not scroll under it. The class
   goes on <html> AS WELL: body's overflow only propagates to the viewport when
   the root's own overflow is visible, and this site sets html{overflow-x:clip},
   so locking the body alone was a no-op and the sheet's swipe-to-close scrolled
   the page at the same time. */
html.modal-open, body.modal-open { overflow: hidden; }
/* …and the header has to be told, because THE LOCK BREAKS position:sticky.

   NTNScrollLock doesn't only hide overflow — it pins the body with
   `position:fixed; top:-<scrollY>px` so the scroll offset survives (that part
   is for iOS, where overflow:hidden alone doesn't hold). A fixed body has no
   scrolling ancestor, and a sticky element without one simply renders at its
   natural place in the document: the top of the page. Open a dialog 1500px
   down and the nav goes to -1500px — measured — so it vanishes.

   Nobody saw it until now because the creator and the full-screen player are
   opaque and cover the whole viewport anyway. The Yoto dialog is a small card
   over a 78%-opaque backdrop, so the page behind it is visible and the header
   disappearing from behind the dim is obvious.

   Fixed-with-inset while locked reproduces exactly where sticky had it. It sits
   at z-index 50, under the creator overlay (200) and under any <dialog>, which
   the top layer puts above every z-index — so it stays correctly dimmed behind
   whatever opened, rather than punching through it. */
html.modal-open .nav { position: fixed; top: 0; left: 0; right: 0; }
a { color: inherit; }
::selection { background: var(--gold); color: var(--navy-900); }

/* Display type: Brown Beige is chunky — give it air */
h1, h2, h3, .btn, .nav-name {
  font-family: var(--font-display);
  font-weight: normal;
  letter-spacing: 0.04em;
}

/* ---------- Nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px clamp(16px, 4vw, 44px);
  background: var(--navy-900); /* solid — translucent nav ghosts content through it */
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.nav-brand { display: flex; align-items: center; gap: 11px; text-decoration: none; flex-shrink: 0; }
.nav-logo {
  width: 42px; height: 42px; border-radius: 12px;
  background: radial-gradient(circle at 50% 40%, #14295a, #0a1a3a);
  padding: 4px;
  box-shadow: 0 0 14px rgba(255, 213, 74, 0.25);
}
.nav-name { font-size: 1.15rem; color: var(--gold); letter-spacing: 0.06em; }
.nav-links { display: flex; gap: clamp(12px, 2.5vw, 30px); }
.nav-links a {
  text-decoration: none; font-weight: 800; font-size: 0.98rem;
  color: var(--muted); padding: 6px 2px; transition: color 0.2s;
}
.nav-links a:hover { color: var(--gold); }
.nav-cta { display: flex; align-items: center; gap: 12px; }

.nav-burger { display: none; flex-direction: column; gap: 5px; background: none; border: 0; cursor: pointer; padding: 8px; }
.nav-burger span { width: 24px; height: 3px; border-radius: 3px; background: var(--ink); transition: transform 0.25s, opacity 0.25s; }
.nav-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.nav-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-size: 1rem;
  padding: 13px 26px; border-radius: 999px;
  text-decoration: none; border: 0; cursor: pointer;
  white-space: nowrap;
  transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s;
}
.btn { max-width: 100%; } /* a long label must never outgrow its container */
/* Hover lift ONLY where there is a real hover. On a touch screen a tap applies
   :hover and it STICKS until you tap somewhere else — so every button you'd
   already pressed stayed lit at brightness(1.07), and an untouched one (the
   Create CTA) read as "darker than the other buttons". Touch gets :active for
   press feedback instead, which is what it's for.

   THIS GUARD IS NOT OPTIONAL AND IT IS NOT JUST FOR .btn. Until 2026-08-16 it
   was the only place that had it, and every other hover affordance on the site
   — .chip, .ep-card, .ep-play, .platform, .song-plat, the player controls —
   fired on tap and latched. Two of them were doing real damage on phones:
   .ep-card lifted 5px and stayed lifted, and `.review-row:hover .review-track`
   PAUSED the reviews marquee permanently, so one stray tap stopped a scrolling
   row from ever scrolling again. They are all wrapped now.

   So: any new :hover rule that moves, scales, animates or pauses something goes
   inside a `@media (hover: hover) and (pointer: fine)` block. :focus-visible
   stays OUTSIDE it — that's the keyboard path and it belongs on every device,
   which is why a couple of rules below are split into two. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover { transform: translateY(-2px) scale(1.02); filter: brightness(1.07); }
}
.btn:active { transform: translateY(0) scale(0.99); }
.btn svg { width: 20px; height: 20px; flex-shrink: 0; }
.btn-sm { padding: 9px 16px; font-size: 0.88rem; }

.btn-spotify { background: linear-gradient(180deg, #23d364, #169c47); color: #fff; box-shadow: 0 6px 22px rgba(30, 215, 96, 0.35); }
.btn-apple { background: linear-gradient(135deg, #b150e2, #e850a8); color: #fff; box-shadow: 0 6px 22px rgba(216, 81, 197, 0.35); }
.btn-insta {
  background: linear-gradient(45deg, #f09433, #dc2743 55%, #bc1888);
  color: #fff; box-shadow: 0 6px 22px rgba(220, 39, 67, 0.35);
}
/* Glow, like every other button above — NOT the 5px 5px 0 rgba(148, 96, 12, .55)
   hard shadow this used to carry. Offset by 5px with no blur and only 55% alpha,
   that brown slab sat half-off the pill's rounded ends and read as a smudge of
   dirt under the button rather than a shadow: the big gold CTAs (Submit my
   character most of all) looked shaded, like they were disabled. */
.btn-gold { background: linear-gradient(180deg, var(--gold), var(--gold-deep)); color: var(--navy-900); box-shadow: 0 6px 22px rgba(255, 213, 74, 0.35); }
.btn-youtube { background: linear-gradient(180deg, #ff4b4b, #cc0000); color: #fff; box-shadow: 0 6px 22px rgba(255, 0, 0, 0.32); }
/* The one hero pill that stays on the site: it scrolls to #listen.
   OUTLINED, NOT QUIET. It started dashed and near-transparent to keep it from
   competing with the three logos above it — but at 5% white on a navy sky it
   read as disabled rather than as restrained, which is the wrong kind of
   different for a button carrying a quarter of the hero's traffic. A solid gold
   border, a fill you can actually see and the same glow the filled pills wear
   put it back at their weight; staying outlined rather than filled is enough to
   say "this one doesn't leave the site". */
.btn-more {
  background: rgba(255, 213, 74, 0.16);
  border: 2px solid var(--gold);
  color: var(--gold);
  box-shadow: 0 6px 22px rgba(255, 213, 74, 0.22);
  /* .btn's 13px 26px MINUS the 2px border this one alone carries. Every other
     pill is border-0, so matching padding would make this the only 56px cell
     in a 52px grid — and the row centres rather than stretches, so it sat 2px
     proud of YouTube beside it. */
  padding: 11px 24px;
}
@media (hover: hover) and (pointer: fine) {
  .btn-more:hover { background: rgba(255, 213, 74, 0.26); }
}
/* Yoto's own orange, sampled from their lockup — see the co-sign note below. */
.btn-yoto { background: var(--yoto-orange); color: #fff; box-shadow: 0 6px 22px rgba(248, 94, 66, 0.34); }
/* .btn-ghost and its .tb-icon / .tb-dur parts went with the hero's "Play the
   Trailer" button (2026-08-05) — it was the only thing on the site wearing
   them. The creator's own ghost buttons are .cc-btn-ghost in css/creator.css
   and are unrelated. */

/* ---------- Hero (matches the key art: textured royal blue, hill, silhouettes) ---------- */
.hero {
  position: relative;
  text-align: center;
  padding: clamp(44px, 7vw, 84px) clamp(20px, 6vw, 80px) 0;
  min-height: 82vh;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  overflow: hidden;
  background:
    radial-gradient(520px 250px at 50% 84%, rgba(64, 118, 194, 0.45), transparent 72%),
    radial-gradient(130% 95% at 50% 28%, #1d4b8e 0%, #16407e 35%, #0e2c5d 70%, #0a1f47 100%);
}
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='0.055'/%3E%3C/svg%3E");
}
.sky { position: absolute; inset: 0; pointer-events: none; }

/* chunky cartoon stars, like the cover art */
.cstar {
  position: absolute; fill: var(--gold);
  filter: drop-shadow(0 3px 8px rgba(0, 0, 0, 0.35));
  animation: twinkle 4s ease-in-out infinite;
}
.c1 { width: 54px; top: 12%; right: 8%;  transform: rotate(14deg); }
.c2 { width: 26px; top: 7%;  right: 22%; transform: rotate(-12deg); animation-delay: 1.1s; }
.c3 { width: 34px; top: 26%; left: 6%;   transform: rotate(-18deg); animation-delay: 0.4s; }
.c4 { width: 20px; top: 44%; left: 13%;  transform: rotate(22deg);  animation-delay: 2s; }
.c5 { width: 42px; top: 55%; right: 9%;  transform: rotate(-8deg);  animation-delay: 1.6s; }
.c6 { width: 22px; top: 66%; left: 7%;   transform: rotate(10deg);  animation-delay: 2.6s; }
.c7 { width: 28px; top: 72%; right: 20%; transform: rotate(24deg);  animation-delay: 0.8s; }
.c8 { width: 18px; top: 30%; right: 4%; transform: rotate(-20deg); animation-delay: 3.1s; }
.stars { position: absolute; inset: -40px 0 0 0; background-repeat: repeat; }
.stars-a {
  background-image:
    radial-gradient(1.6px 1.6px at 25px 35px, #fff 60%, transparent),
    radial-gradient(1.4px 1.4px at 155px 95px, var(--gold-soft) 60%, transparent),
    radial-gradient(1.2px 1.2px at 80px 160px, #cfe2ff 60%, transparent),
    radial-gradient(1.8px 1.8px at 210px 200px, #fff 60%, transparent);
  background-size: 260px 260px;
  animation: twinkle 4.5s ease-in-out infinite;
}
.stars-b {
  background-image:
    radial-gradient(1.3px 1.3px at 60px 20px, var(--gold-soft) 60%, transparent),
    radial-gradient(1.1px 1.1px at 190px 60px, #fff 60%, transparent),
    radial-gradient(1.7px 1.7px at 120px 130px, #bcd7ff 60%, transparent),
    radial-gradient(1.2px 1.2px at 30px 210px, #fff 60%, transparent);
  background-size: 300px 300px;
  animation: twinkle 6s ease-in-out 1.2s infinite;
}
.stars-c {
  background-image:
    radial-gradient(2.2px 2.2px at 140px 40px, #fff 55%, transparent),
    radial-gradient(1.5px 1.5px at 40px 110px, var(--gold) 60%, transparent),
    radial-gradient(1.3px 1.3px at 230px 170px, #dbe9ff 60%, transparent);
  background-size: 340px 340px;
  animation: twinkle 5.2s ease-in-out 2.3s infinite;
}
@keyframes twinkle { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }

.shooting-star {
  position: absolute; width: 130px; height: 2px;
  background: linear-gradient(90deg, transparent, #fff, transparent);
  border-radius: 2px; opacity: 0; transform: rotate(-24deg);
}
.ss-1 { top: 16%; left: 64%; animation: shoot 8s ease-in 2s infinite; }
.ss-2 { top: 42%; left: 16%; animation: shoot 11s ease-in 6.5s infinite; }
@keyframes shoot {
  0% { opacity: 0; transform: rotate(-24deg) translateX(0); }
  3% { opacity: 1; }
  9% { opacity: 0; transform: rotate(-24deg) translateX(-240px); }
  100% { opacity: 0; transform: rotate(-24deg) translateX(-240px); }
}

/* padding-bottom keeps sky between the buttons and the characters' heads —
   the silhouette is bottom-pinned, so without it they collide when the hero
   is content-driven rather than stretched */
.hero-inner {
  position: relative; z-index: 3; max-width: 760px;
  padding-top: clamp(8px, 2vw, 26px);
  padding-bottom: clamp(34px, 6vh, 76px);
}
.hero-logo {
  /* the wordmark PNG carries its own transparent padding — pull the sub up
     tight against it rather than stacking margin on top of that */
  width: min(620px, 88vw); height: auto; margin: 0 auto -2px;
  filter: drop-shadow(0 8px 30px rgba(255, 213, 74, 0.25));
  animation: floaty 7s ease-in-out infinite;
}
.hero-sub { color: var(--gold-soft); font-weight: 700; font-style: italic; font-size: clamp(1rem, 2vw, 1.15rem); margin: 0 auto 16px; }
.hero-tag { font-size: clamp(1.02rem, 2vw, 1.22rem); font-weight: 700; max-width: 44ch; margin: 0 auto 4px; }
/* desktop: the hero composes like a storybook cover — logo and silhouette
   scale with viewport HEIGHT so the whole scene (sky, logo, buttons,
   characters on the hill) fits the first screen instead of cutting the
   characters at the fold */
@media (min-width: 721px) {
  .hero { padding-top: clamp(18px, 3vh, 48px); }
  .hero-inner { padding-top: 6px; }
  .hero-logo { width: auto; max-height: min(322px, 20.5vh); }
  /* .hero prefix: must outrank the base width clamp further down the file,
     or the forced width + capped height squash the characters */
  .hero .hero-silhouette { width: auto; height: auto; max-height: min(310px, 19vh); }
}

/* the pills are a compact block everywhere — three places to listen and one
   door to the rest — part of keeping the whole hero scene above the fold.
   No `order` overrides any more: the grid fills in DOM order, so index.html is
   the only place the arrangement is written down. */
.hero-btns { display: flex; flex-direction: column; align-items: center; gap: 13px; margin-top: 14px; }
.hero-btns .btn { width: min(320px, 100%); }
/* Four cells, so the desktop grid is a plain 2×2 again — Spotify + Apple on
   top, YouTube + "everywhere else" underneath — and none of the odd-one-out
   spanning rules the three-button set needed are here any more. The gold
   Create pill they existed for left the hero on 2026-08-16. */
@media (min-width: 721px) {
  .hero-btns { display: grid; grid-template-columns: repeat(2, 262px); justify-content: center; }
  .hero-btns .btn { width: 100%; }
}
/* phones: same storybook-cover discipline — one column of pills and
   height-scaled art so Nathan & PBJ make the first screen here too */
@media (max-width: 720px) {
  .hero { padding-top: clamp(20px, 3svh, 40px); padding-left: 14px; padding-right: 14px; }
  /* logo and the sky under the buttons both give up a little so the stacked
     pills + the co-sign fit without pushing the characters through the fold.
     The silhouette's own margin-bottom is NOT where to take it from: that
     number is what lands their feet on the hill crest, so trimming it sinks
     them into the ground instead of moving them up. */
  .hero-logo { width: auto; max-height: min(45vw, 20.5svh); }
  .hero-inner { padding-bottom: clamp(20px, 3.2vh, 44px); }
  /* One column, full-width pills. They used to sit 2-up, which forced every
     label down to ~0.7rem to clear "APPLE PODCASTS" in half a phone. Stacked,
     they're all the same width and the type can breathe. Do NOT go back to a
     2×2 here to save the height a fourth pill costs — that's the same trade
     that produced the leaking labels, and "Yoto, Amazon & more" is longer than
     anything that failed before. The height comes back from the two lines
     above and from the shorter ghost pill below. */
  .hero-btns {
    display: grid; grid-template-columns: minmax(0, 1fr);
    gap: 8px; width: 100%; max-width: 330px; margin: 12px auto 0;
  }
  .hero-btns .btn {
    width: 100%; padding: 11px 14px;
    font-size: clamp(0.78rem, 3.6vw, 0.9rem);
  }
  /* the door to the rest of the list, not a fourth platform — so it's the one
     that gives up a few pixels to keep the characters above the fold */
  .hero-btns .btn-more { padding: 8px 14px; font-size: clamp(0.72rem, 3.3vw, 0.84rem); }
  .hero-btns .btn svg { width: 17px; height: 17px; }
  .hero .hero-silhouette { width: auto; height: auto; max-height: min(170px, 19svh); margin-bottom: 96px; }
}
/* Short phones — SE-class hardware, and any tall phone once the browser chrome
   eats into the viewport. Measured at 375×667: the hero used to clear the fold
   by 16px, and stacking the pills + adding the co-sign pushed it 114px past.
   Everything gives up a little rather than one thing giving up a lot, so it
   still reads as the same storybook cover — just tighter. The silhouette's
   margin-bottom stays put on purpose: that's what lands their feet on the hill
   crest, so it's a position, not slack.

   TIGHTENED AGAIN 2026-08-16, when the fourth pill (YouTube joined the set and
   Create left it) added 93px here and put both the scroll cue and the bottom of
   the hill under the fold at 375×667. Same method as before — logo, type,
   padding and the co-sign each give a few pixels rather than any one of them
   collapsing. What was NOT done, twice considered: putting YouTube and
   "Yoto, Amazon & more" 2-up to save a whole row. At half of a 375px phone that
   label has ~3px of slack in Brown Beige and none at all in the Nunito
   fallback, which is precisely the leak the one-column layout above exists to
   fix. A row is not worth reopening that. */
@media (max-width: 720px) and (max-height: 740px) {
  .hero { padding-top: clamp(6px, 1.2svh, 16px); }
  .hero-logo { max-width: 60vw; }
  .hero-sub { font-size: 0.88rem; margin-bottom: 5px; }
  .hero-tag { font-size: 0.92rem; }
  .hero-inner { padding-bottom: 4px; }
  .hero-btns { gap: 5px; margin-top: 7px; }
  .hero-btns .btn { padding: 7px 14px; }
  .hero-btns .btn-more { padding: 5px 14px; font-size: clamp(0.68rem, 3vw, 0.78rem); }
  .cosign { margin-top: 7px; gap: 8px; }
  .cosign-laurel { width: 17px; height: 37px; }
  .cosign-eyebrow { font-size: 0.53rem; }
  .cosign-name { font-size: 0.86rem; }
  .cosign-name .yoto-mark { width: 15px; height: 15px; }
  .cosign-sub { font-size: 0.62rem; }
  .hero .hero-silhouette { max-height: min(140px, 17svh); }
}
/* ---------- The Yoto co-sign ----------
   This used to be .yoto-badge: a fourth pill in the hero button grid, filled
   in Yoto's orange with the same chunky shadow the buttons carry. Weighted
   like a button it behaved like one — a fourth destination competing with
   Spotify, Apple and Create, pointing off our own hero into a partner's news
   post. The thing it carries is evidence, not an offer, so from 2026-08-10 it
   is styled as a credential: laurels, small caps, no fill, no border, no
   shadow, no hover lift. Everything a button does to say "press me" is
   deliberately absent — the only affordance left is the pointer, because it is
   still a link to the source.
   Nothing here is in Yoto's orange either. On the orange fill the badge read
   as Yoto's own furniture parked in our hero; in our gold and cream it reads
   as our page reporting what Yoto did, which is what a co-sign is. Yoto's
   colour still belongs to Yoto's chip in the Stream row below. */
.cosign {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  margin: 15px auto 0; padding: 2px 4px;
  text-decoration: none; text-align: center;
}
.cosign-laurel {
  width: 23px; height: 49px; flex-shrink: 0;
  color: var(--gold); opacity: 0.78;
  transition: opacity 0.2s ease;
}
/* one drawing, mirrored — the two halves of a wreath are the same branch */
.cosign-laurel-r { transform: scaleX(-1); }
.cosign-body { display: grid; gap: 2px; justify-items: center; }
/* gold, like the laurels: the eyebrow is the half of the sentence that makes
   this a citation rather than a boast, so it has to survive being small */
.cosign-eyebrow {
  font-size: 0.62rem; font-weight: 800; letter-spacing: 0.17em; text-transform: uppercase;
  color: var(--gold-soft);
}
/* Yoto takes the big line, in the display face (which is all-caps by design).
   The endorser IS the credential — an award reads as a boast until you can see
   whose award it is, so the name outranks the award below it. */
.cosign-name {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-display); font-size: 1.02rem; letter-spacing: 0.03em;
  color: var(--ink);
}
/* the mark is a filled disc with the face knocked out, so the sky behind it
   becomes the eyes and the smile — no fill of its own to fight the palette */
.cosign-name .yoto-mark { width: 19px; height: 19px; flex-shrink: 0; }
/* Kept to one line: the laurels frame a three-line block, and a wrap here
   makes it four and outgrows them. Worth re-checking if the sheet lengthens
   the wording. */
.cosign-sub { font-size: 0.72rem; font-weight: 700; color: var(--muted); white-space: nowrap; }
/* It warms under the pointer and stops there. No lift, no scale: those are the
   buttons' tell that they are the thing to press, and this isn't. */
@media (hover: hover) and (pointer: fine) {
  .cosign:hover .cosign-laurel { opacity: 1; }
  .cosign:hover .cosign-eyebrow, .cosign:hover .cosign-sub { color: var(--gold-soft); }
}
@media (max-width: 720px) {
  .cosign { gap: 9px; margin-top: 13px; }
  .cosign-laurel { width: 19px; height: 41px; }
  .cosign-eyebrow { font-size: 0.56rem; }
  .cosign-name { font-size: 0.94rem; }
  .cosign-name .yoto-mark { width: 17px; height: 17px; }
  .cosign-sub { font-size: 0.67rem; }
}

.hero-ground {
  position: absolute; bottom: -70px; left: -20%; right: -20%; height: 190px; z-index: 1;
  background: #071331;
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  box-shadow: 0 -32px 70px rgba(76, 126, 197, 0.35); /* moonlit rim above the hill crest */
}
.hero-silhouette {
  position: relative; z-index: 2;
  width: clamp(180px, 23vw, 310px); height: auto;
  /* margin-top auto pins the figures to the bottom of the hero on every screen;
     feet land ~16px into the hill crest (crest sits 120px above the hero's edge) */
  margin: auto auto 104px;
  filter: drop-shadow(0 0 24px rgba(122, 170, 235, 0.35));
}
@keyframes floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }

/* a gentle nudge to scroll — bobs on the hill, retires once you've scrolled */
.scroll-cue {
  position: absolute; left: 50%; bottom: clamp(22px, 4.5vh, 46px); z-index: 4;
  display: grid; place-items: center;
  width: 46px; height: 46px; border-radius: 50%;
  color: var(--gold);
  background: rgba(7, 19, 49, 0.5);
  border: 2px solid rgba(255, 213, 74, 0.45);
  box-shadow: 0 0 22px rgba(255, 213, 74, 0.18);
  animation: cue-bob 2.4s ease-in-out infinite;
  transition: opacity 0.35s ease, visibility 0.35s ease, border-color 0.2s, color 0.2s;
}
.scroll-cue svg { width: 22px; height: 22px; }
.scroll-cue:hover { color: var(--cream); border-color: var(--gold); }
.scroll-cue.gone { opacity: 0; visibility: hidden; }
@keyframes cue-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50% { transform: translate(-50%, 8px); }
}

/* ---------- Marquee ---------- */
.marquee {
  overflow: hidden; white-space: nowrap; padding: 12px 0;
  font-family: var(--font-display); font-size: clamp(1rem, 2vw, 1.2rem);
  letter-spacing: 0.08em;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold) 50%, var(--gold-deep));
  color: var(--navy-900);
  transform: rotate(-0.6deg) scale(1.01);
  box-shadow: 0 8px 30px rgba(255, 213, 74, 0.18);
}
.marquee-track { display: inline-flex; animation: scroll-x 70s linear infinite; }
@keyframes scroll-x { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ---------- Sections ---------- */
.section {
  max-width: 1140px; margin: 0 auto;
  padding: clamp(60px, 8vw, 100px) clamp(20px, 5vw, 40px) 0;
  scroll-margin-top: 78px; /* clear the sticky nav when jumping to anchors */
}
.section[hidden] { display: none; } /* a section JS switches off must actually go */
.section-wide { max-width: none; padding-left: 0; padding-right: 0; }
.section-wide .section-title, .section-wide .section-sub { padding: 0 20px; }
.section-title {
  font-size: clamp(1.9rem, 4.4vw, 2.9rem);
  text-align: center; line-height: 1.12; margin-bottom: 12px;
  color: var(--gold);
  text-shadow: 0 3px 0 rgba(148, 96, 12, 0.4), 0 0 34px rgba(255, 213, 74, 0.18);
}
/* 90s squiggle divider above every section title */
.section-title::before {
  content: ""; display: block; width: 118px; height: 14px; margin: 0 auto 12px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 14'%3E%3Cpath d='M2 7 q 7 -9 14 0 t 14 0 t 14 0 t 14 0 t 14 0 t 14 0 t 14 0 t 14 0' fill='none' stroke='%238fd0ff' stroke-width='3.5' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat;
}
.section-sub { text-align: center; color: var(--muted); font-weight: 600; max-width: 58ch; margin: 0 auto 26px; }
.nowrap { white-space: nowrap; }

/* ---------- Starlit rooms: sections as floating panels ----------
   #adventures, #songs and #listen become opaque navy "rooms" floating on the
   body star field (the same recipe as .create-card / .follow-card, so the page
   reads as one family). #create and #follow already ARE panels; the hero and
   the reviews marquee stay full-bleed sky. NOTE: these id selectors outrank
   the generic .section shell — future .section tweaks won't reach the three
   panels unless repeated here. */
#adventures, #songs, #listen {
  position: relative;
  max-width: min(1180px, calc(100% - 24px)); /* ≥12px of sky each side at 375px */
  margin: clamp(44px, 6vw, 80px) auto 0;     /* the sky gap between rooms */
  padding: clamp(34px, 5vw, 56px) clamp(18px, 4vw, 44px) clamp(40px, 5.5vw, 60px);
  border-radius: var(--r-xl);
  background:
    radial-gradient(90% 55% at 50% 0%, var(--panel-glow, rgba(143, 208, 255, 0.08)), transparent 70%),
    linear-gradient(180deg, var(--navy-700), var(--navy-800));
  border: 1px solid rgba(255, 213, 74, 0.18);
  box-shadow: 0 0 0 3px rgba(5, 13, 32, 0.65), 0 18px 44px rgba(2, 8, 26, 0.55);
}
#adventures { --panel-glow: rgba(143, 208, 255, 0.09); }
#songs  { --panel-glow: rgba(255, 213, 74, 0.08); max-width: min(860px, calc(100% - 24px)); }
#listen { --panel-glow: rgba(255, 233, 163, 0.06); max-width: min(860px, calc(100% - 24px)); }

/* one chunky gold star straddling each room's top edge, like a sticker.
   pointer-events:none is load-bearing — without it the star eats taps. */
#adventures::after, #songs::after, #listen::after {
  content: ""; position: absolute; top: -13px; width: 28px; height: 28px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 0c.7 6.2 5.8 11.3 12 12-6.2.7-11.3 5.8-12 12-.7-6.2-5.8-11.3-12-12C6.2 11.3 11.3 6.2 12 0z' fill='%23ffd54a'/%3E%3C/svg%3E") center/contain no-repeat;
  pointer-events: none; filter: drop-shadow(0 3px 6px rgba(2, 8, 26, 0.6));
}
#adventures::after { right: 34px; transform: rotate(10deg); }
#songs::after  { left: 34px;  transform: rotate(-12deg); width: 23px; height: 23px; }
#listen::after { right: 58px; transform: rotate(6deg);  width: 21px; height: 21px; }

/* no lonely words on their own line: headings/titles balance their lines,
   prose avoids single-word last lines (both degrade gracefully) */
h1, h2, h3, .section-sub, .results-title, .results-blurb,
.hero-tag, .hero-sub, .ep-title, .empty-line, .empty-sub, .fp-title { text-wrap: balance; }
.ep-summary, .follow-copy p { text-wrap: pretty; }

/* ---------- Adventure finder ---------- */
.finder { max-width: 720px; margin: 0 auto; }

/* the search-by switch: pals / places / feelings */
.finder-modes {
  display: flex; justify-content: center; gap: 4px;
  width: max-content; max-width: 100%; margin: 0 auto 14px;
  padding: 4px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  border: 2px solid rgba(255, 255, 255, 0.14);
}
.mode-btn {
  font-family: var(--font-body); font-weight: 800; font-size: 0.92rem;
  padding: 8px 17px; border-radius: 999px; cursor: pointer;
  background: transparent; border: 0; color: var(--muted);
  white-space: nowrap;
  transition: background 0.18s, color 0.18s;
}
.mode-btn:hover { color: var(--ink); }
.mode-btn.on {
  background: var(--sky-blue); color: var(--navy-900);
  box-shadow: 0 0 16px rgba(143, 208, 255, 0.35);
}

/* the pills live on a little star chart */
.map-frame {
  position: relative;
  margin-top: 6px;
  border: 2.5px dashed rgba(255, 213, 74, 0.38);
  border-radius: 20px;
  padding: 16px 16px 12px;
  background: radial-gradient(340px 130px at 10% 0%, rgba(143, 208, 255, 0.07), transparent 70%);
}
#filterPills { min-height: 44px; }
#filterPills[data-mode="worlds"] .chip.on::after { content: " 📍"; }
/* the roster-overflow drawer pill — an invitation, not a filter */
.chip-more {
  border-style: dashed; border-color: rgba(255, 213, 74, 0.45);
  background: rgba(255, 213, 74, 0.06); color: var(--gold);
}
.chip-more:hover { color: var(--gold); }

.chips { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; }
.pill-row { display: contents; } /* desktop: the two courses melt into one wrapping row */
.chip {
  font-family: var(--font-body); font-weight: 800; font-size: 0.88rem;
  padding: 8px 16px; border-radius: 999px; cursor: pointer;
  background: rgba(255, 255, 255, 0.06);
  border: 2px solid rgba(255, 255, 255, 0.16);
  color: var(--muted);
  box-shadow: 3px 3px 0 rgba(2, 8, 26, 0.45);
  transition: all 0.18s;
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover { border-color: var(--gold); color: var(--ink); transform: translate(-1px, -3px); box-shadow: 4px 5px 0 rgba(2, 8, 26, 0.45); }
}
.chip.on { background: var(--gold); border-color: var(--gold-deep); color: var(--navy-900); box-shadow: 3px 3px 0 rgba(148, 96, 12, 0.55); }

/* signposts inside the finder console */
.zone-label {
  font-weight: 800; font-size: 0.72rem; letter-spacing: 1.6px; text-transform: uppercase;
  color: var(--sky-blue); opacity: 0.9;
  text-align: center;
  margin: 0 4px 10px;
}

/* the results header always names what the grid is showing — centered like the
   section titles, with the clear pill floated off to the right */
.results-head {
  position: relative;
  max-width: 720px; /* aligned with the finder console — keeps ✕ clear near the title */
  margin: 26px auto 12px; padding: 4px 84px;
  border-radius: 12px;
}
.results-title {
  font-family: var(--font-display); font-weight: normal;
  font-size: 1.14rem; letter-spacing: 0.06em; line-height: 1.3;
  color: var(--gold-soft);
  text-align: center;
}
/* the picked pal's/place's little blurb, captioning the title */
.results-blurb {
  text-align: center; font-style: italic;
  color: var(--muted); font-weight: 600; font-size: 0.9rem;
  margin-top: 3px;
}
.results-clear {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font-family: var(--font-body); font-weight: 800; font-size: 0.82rem;
  background: rgba(255, 213, 74, 0.12); color: var(--gold);
  border: 1.5px solid rgba(255, 213, 74, 0.45);
  border-radius: 999px; padding: 6px 14px; cursor: pointer;
  transition: background 0.18s;
}
.results-clear:hover { background: rgba(255, 213, 74, 0.22); }
/* author display values (the mobile display:table) must not defeat [hidden] */
.results-clear[hidden] { display: none; }

/* 90s click sparkles */
.spark {
  position: fixed; width: 13px; height: 13px; z-index: 999; pointer-events: none;
  clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
  animation: spark-pop 0.65s ease-out forwards;
}
@keyframes spark-pop {
  from { transform: translate(-50%, -50%) scale(0.5) rotate(0deg); opacity: 1; }
  to { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0) rotate(120deg); opacity: 0; }
}

/* ---------- Episode grid ---------- */
.ep-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.ep-card {
  display: flex; flex-direction: column;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  padding: 16px 16px 15px;
  transition: transform 0.2s ease, border-color 0.2s, box-shadow 0.2s;
}
@media (hover: hover) and (pointer: fine) {
  .ep-card:hover { transform: translateY(-5px); border-color: rgba(255, 213, 74, 0.4); box-shadow: 0 14px 34px rgba(2, 8, 26, 0.5); }
}
.ep-card.is-playing { border-color: var(--gold); box-shadow: 0 0 0 3px rgba(255, 213, 74, 0.22), 0 14px 34px rgba(2, 8, 26, 0.5); }
.ep-card[hidden] { display: none; }
.ep-card.featured { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: 26px;
  background: radial-gradient(600px 260px at 105% -30%, rgba(255, 213, 74, 0.1), transparent 60%), var(--card); }
.ep-card.featured .ep-body { flex: 1; }
.ep-card.featured img { width: clamp(120px, 18vw, 200px); border-radius: 16px; transform: rotate(-2deg);
  box-shadow: 0 14px 34px rgba(2, 8, 26, 0.55); }

.ep-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; gap: 8px; }
.ep-num {
  font-family: var(--font-display); font-size: 0.8rem; letter-spacing: 0.08em;
  background: rgba(255, 213, 74, 0.14); color: var(--gold);
  border: 1px solid rgba(255, 213, 74, 0.35);
  padding: 3px 12px; border-radius: 999px;
}
/* 90s starburst badge */
.ep-new {
  min-width: 56px; height: 56px; flex-shrink: 0;
  padding: 0 15px; white-space: nowrap;  /* the burst stretches to fit any badge text */
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: 0.68rem; letter-spacing: 0.05em;
  background: var(--gold); color: var(--navy-900);
  clip-path: polygon(100% 50%, 84.8% 59.3%, 93.3% 75%, 75.5% 75.5%, 75% 93.3%, 59.3% 84.8%, 50% 100%, 40.7% 84.8%, 25% 93.3%, 24.5% 75.5%, 6.7% 75%, 15.2% 59.3%, 0% 50%, 15.2% 40.7%, 6.7% 25%, 24.5% 24.5%, 25% 6.7%, 40.7% 15.2%, 50% 0%, 59.3% 15.2%, 75% 6.7%, 75.5% 24.5%, 93.3% 25%, 84.8% 40.7%);
  animation: burst-wobble 5s ease-in-out infinite;
}
@keyframes burst-wobble {
  0%, 100% { transform: rotate(-8deg) scale(1); }
  50% { transform: rotate(5deg) scale(1.07); }
}
.ep-dur { font-size: 0.8rem; font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; margin-left: auto; }
.ep-title { font-family: var(--font-body); font-weight: 800; font-size: 1.08rem; line-height: 1.3; margin-bottom: 6px; }
.ep-card.featured .ep-title { font-size: 1.4rem; }
.ep-date { font-size: 0.8rem; color: var(--muted); font-weight: 700; margin-bottom: 9px; }
/* teaser is a complete sentence generated at build time — no clamping, no cut-off thoughts */
.ep-summary {
  color: var(--muted); font-size: 0.9rem; line-height: 1.5;
  margin-bottom: 12px;
}
.ep-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.ep-tag { font-size: 0.72rem; font-weight: 800; color: var(--sky-blue); background: rgba(143, 208, 255, 0.1); border-radius: 999px; padding: 2px 9px; }
.ep-actions { margin-top: auto; display: flex; align-items: center; gap: 12px; }
.ep-play {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-display); font-size: 0.92rem; letter-spacing: 0.05em;
  background: rgba(255, 255, 255, 0.08);
  border: 2px solid rgba(255, 255, 255, 0.18);
  color: var(--ink);
  padding: 9px 18px; border-radius: 999px; cursor: pointer;
  box-shadow: 3px 3px 0 rgba(2, 8, 26, 0.4);
  transition: background 0.2s, border-color 0.2s, transform 0.15s, box-shadow 0.15s;
}
@media (hover: hover) and (pointer: fine) {
  .ep-play:hover { background: rgba(255, 213, 74, 0.15); border-color: var(--gold); transform: translate(-1px, -1px); box-shadow: 4px 4px 0 rgba(2, 8, 26, 0.4); }
}
.ep-play svg { width: 14px; height: 14px; }
.ep-card.is-playing .ep-play { background: var(--gold); border-color: var(--gold); color: var(--navy-900); }

.eq { display: none; align-items: flex-end; gap: 3px; height: 18px; }
.ep-card.is-playing .eq { display: inline-flex; }
.eq i { width: 4px; border-radius: 2px; background: var(--gold); animation: eq-bounce 0.9s ease-in-out infinite; }
.eq i:nth-child(1) { height: 40%; }
.eq i:nth-child(2) { height: 90%; animation-delay: 0.15s; }
.eq i:nth-child(3) { height: 60%; animation-delay: 0.3s; }
@keyframes eq-bounce { 0%, 100% { transform: scaleY(0.5); } 50% { transform: scaleY(1); } }

.ep-empty { text-align: center; padding: 26px 0 30px; }
.empty-jim {
  width: 62px; margin: 0 auto 12px; opacity: 0.85;
  transform: rotate(-8deg);
  animation: floaty 5s ease-in-out infinite;
}
.empty-line { color: var(--gold-soft); font-weight: 800; font-size: 1.05rem; max-width: 40ch; margin: 0 auto 6px; }
.empty-sub { color: var(--muted); font-weight: 700; font-size: 0.9rem; }
.ep-more-wrap { text-align: center; margin-top: 30px; }

/* play/pause icon swap */
.i-pause { display: none; }
.is-playing .i-play { display: none; }
.is-playing .i-pause { display: block; }

/* ---------- Reviews ---------- */
.reviews .review-row {
  overflow: hidden; margin-top: 10px;
  /* dashed-gold "ticket edges" frame the full-bleed marquee band */
  padding: 14px 0;
  border-top: 1px dashed rgba(255, 213, 74, 0.2);
}
/* The bottom "ticket edge" moves down to sit under the For-parents link, so
   the link reads as part of this section rather than as loose text after it.
   It can't go INSIDE .review-row — that clips to overflow:hidden for the
   scrolling marquee. */
.reviews .ep-all-link {
  margin: 0;
  padding: 12px 0 14px;
  border-bottom: 1px dashed rgba(255, 213, 74, 0.2);
}
.review-track { display: flex; gap: 18px; width: max-content; animation: scroll-x 55s linear infinite; padding: 6px 0; }
@media (hover: hover) and (pointer: fine) {
  .review-row:hover .review-track { animation-play-state: paused; }
}
.review-card {
  width: 320px; flex-shrink: 0;
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: var(--r-lg); padding: 18px 22px;
}
.review-stars { color: var(--gold); letter-spacing: 2px; font-size: 0.82rem; margin-bottom: 7px; }
.review-quote { font-size: 0.94rem; }
.review-name { margin-top: 9px; color: var(--muted); font-weight: 800; font-size: 0.82rem; }

/* ---------- Follow / platforms ---------- */
/* Like .create-invite: #follow jumps straight to the card with no heading above
   it, so its top spacing is a MARGIN (outside the scroll-anchor box) instead of
   padding. A menu jump then lands on the card rather than below an empty band. */
#follow { margin-top: clamp(60px, 8vw, 100px); padding-top: 0; }
.follow-card {
  position: relative; /* anchors the corner star */
  display: flex; align-items: center; gap: clamp(20px, 4vw, 50px);
  background:
    radial-gradient(500px 240px at 0% -40%, rgba(220, 39, 67, 0.12), transparent 70%),
    linear-gradient(180deg, var(--navy-700), var(--navy-800));
  border: 1px solid rgba(255, 213, 74, 0.22);
  border-radius: var(--r-xl);
  padding: clamp(26px, 4.5vw, 48px);
  box-shadow: 0 0 0 3px rgba(5, 13, 32, 0.65), var(--shadow-pop); /* keyline: joins the panel family */
}
/* this room wears the same corner-star charm as the panels */
.follow-card::after {
  content: ""; position: absolute; top: -13px; right: 44px; width: 24px; height: 24px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 0c.7 6.2 5.8 11.3 12 12-6.2.7-11.3 5.8-12 12-.7-6.2-5.8-11.3-12-12C6.2 11.3 11.3 6.2 12 0z' fill='%23ffd54a'/%3E%3C/svg%3E") center/contain no-repeat;
  pointer-events: none; filter: drop-shadow(0 3px 6px rgba(2, 8, 26, 0.6));
  transform: rotate(-8deg);
}
/* every room heading wears the squiggle — same mark as the panel titles */
.follow-card h2::before {
  content: ""; display: block; width: 118px; height: 14px; margin: 0 0 12px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 14'%3E%3Cpath d='M2 7 q 7 -9 14 0 t 14 0 t 14 0 t 14 0 t 14 0 t 14 0 t 14 0 t 14 0' fill='none' stroke='%238fd0ff' stroke-width='3.5' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat;
}
.follow-copy { flex: 1; }
/* the module header — "Get in touch" — sits over both methods */
.follow-card h2 { font-size: clamp(1.5rem, 3.2vw, 2.2rem); color: var(--gold); margin-bottom: 20px; }
.follow-card p { color: var(--muted); max-width: 52ch; margin-bottom: 22px; }
/* one reach-us method (Instagram, mailing list): a subhead over its controls */
.connect-subhead {
  font-family: var(--font-display); font-weight: normal;
  font-size: 1.14rem; letter-spacing: 0.04em;
  color: var(--gold-soft); margin-bottom: 12px; text-wrap: balance;
}
.follow-art { width: clamp(140px, 20vw, 240px); border-radius: 20px; transform: rotate(3deg);
  box-shadow: 0 18px 44px rgba(2, 8, 26, 0.6); }
/* the handle is one long unbreakable word — let the button wrap and shrink
   instead of bursting out of the card on narrow screens. Sized down: it's one
   of three reach-us methods, not a hero CTA. */
.btn-insta {
  white-space: normal; text-align: center;
  font-size: clamp(0.78rem, 2.9vw, 0.9rem);
  padding: 10px 18px;
}
.btn-insta svg { width: 17px; height: 17px; }

/* ---------- Kit email signup (the "mailing list" method) ---------- */
.kit-form[hidden] { display: none; }
/* the dashed line divides this method from the Instagram one above it */
.kit-form {
  margin-top: 26px; padding-top: 22px;
  border-top: 1px dashed rgba(255, 213, 74, 0.28);
}
.kit-fields { display: flex; flex-wrap: wrap; gap: 9px; }
.kit-input {
  flex: 1 1 190px; min-width: 0;
  /* 16px min so iOS Safari doesn't zoom the page in on focus */
  font-family: var(--font-body); font-weight: 700; font-size: 16px;
  color: var(--ink);
  background: rgba(5, 13, 32, 0.55);
  border: 2px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px; padding: 13px 20px;
  transition: border-color 0.18s, background 0.18s;
}
.kit-input::placeholder { color: rgba(174, 188, 221, 0.75); font-weight: 600; }
.kit-input:hover { border-color: rgba(255, 255, 255, 0.3); }
.kit-input:focus {
  outline: none; border-color: var(--gold);
  background: rgba(5, 13, 32, 0.75);
  box-shadow: 0 0 0 3px rgba(255, 213, 74, 0.18);
}
.kit-input:user-invalid { border-color: rgba(255, 120, 120, 0.7); }
.kit-submit { flex: 1 1 100%; }
.kit-submit[disabled] { opacity: 0.6; cursor: default; }
.kit-submit[disabled]:hover { transform: none; filter: none; }
/* the grown-ups line — this is a kids' brand, so who we're emailing matters */
.kit-fine { color: var(--muted); font-size: 0.76rem; font-weight: 700; margin-top: 11px; line-height: 1.5; }
.kit-status[hidden] { display: none; }
.kit-status {
  margin-top: 12px; font-weight: 800; font-size: 0.9rem;
  color: var(--gold); text-wrap: balance;
}
.kit-status.bad { color: #ffb4b4; }
/* offscreen rather than display:none — some bots skip hidden inputs */
.kit-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
/* Submit ALWAYS sits full-width on its own row (never inline with the input):
   an inline button is sized to its label, so the flexible input would grow and
   shrink with the button's text — including the jump to "Sending…" on submit.
   Stacking keeps the email field a stable, full-width size at every breakpoint. */

.platforms { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.platform {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: 999px; padding: 9px 18px;
  text-decoration: none; font-weight: 800; font-size: 0.9rem; color: var(--ink);
  transition: transform 0.18s, border-color 0.2s;
}
@media (hover: hover) and (pointer: fine) {
  .platform:hover { transform: translateY(-3px); border-color: rgba(255, 213, 74, 0.45); }
}
.platform .dot { width: 10px; height: 10px; border-radius: 50%; }
/* The Yoto chip is a <button> — it opens the how-to dialog rather than leaving
   the site — and a button inherits none of the font the <a> chips beside it
   get for free. These four lines are what make the two look identical. */
button.platform { font: inherit; font-weight: 800; font-size: 0.9rem; cursor: pointer; }
/* Yoto: the same filled orange as the hero badge, so the announcement reads
   the same way in both places. It lifts on hover like every other chip in the
   row now that it does something — only the gold border is held back, because
   gold on the orange fill is the one hover state in here that doesn't read. */
.platform-yoto {
  background: var(--yoto-orange);
  border-color: rgba(255, 255, 255, 0.28);
  color: #fff;
  box-shadow: 0 4px 16px rgba(248, 94, 66, 0.32);
}
.platform-yoto:hover { border-color: rgba(255, 255, 255, 0.5); }
.platform .yoto-mark { width: 18px; height: 18px; flex-shrink: 0; }

/* ---------- The Yoto how-to dialog ----------
   A <dialog>, so the browser owns the top layer, the inertness of the page
   behind, the Tab trap and Escape. What's left for CSS is the night-sky card
   and undoing the UA's white box. */
.yoto-modal {
  width: min(420px, calc(100vw - 32px));
  max-height: calc(100svh - 40px);
  overflow-y: auto;
  margin: auto;                       /* centred by the UA's inset:0 + auto */
  padding: 30px 26px 26px;
  border: 2px solid rgba(255, 213, 74, 0.3);
  border-radius: 22px;
  background: linear-gradient(180deg, #14295a, var(--navy-900));
  color: var(--ink);
  box-shadow: 0 26px 70px rgba(2, 8, 26, 0.7);
  text-align: center;
  overscroll-behavior: contain;
}
.yoto-modal::backdrop { background: rgba(4, 11, 32, 0.78); }
/* the UA sets display:block on an open dialog and display:none otherwise —
   both are author-level here, so [open] has to drive it explicitly */
.yoto-modal:not([open]) { display: none; }
.yoto-modal[open] { animation: ym-in 0.24s ease both; }
@keyframes ym-in { from { opacity: 0; transform: translateY(14px) scale(0.97); } }

.ym-close {
  position: absolute; top: 10px; right: 10px;
  width: 38px; height: 38px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.08); border: 0; cursor: pointer;
  color: var(--ink);
}
.ym-close svg { width: 15px; height: 15px; }
.ym-close:hover { background: rgba(255, 255, 255, 0.16); }

.ym-mark { width: 46px; height: 46px; display: block; margin: 0 auto 12px; }
.ym-title { font-size: 1.2rem; color: var(--gold); text-wrap: balance; margin-bottom: 6px; }
/* focused programmatically when the dialog opens, so it must not draw a ring */
.ym-title:focus { outline: none; }
.ym-sub { color: var(--muted); font-size: 0.9rem; font-weight: 700; text-wrap: balance; }

/* Numbered because the order is the instruction — you can't add it to the
   Library before you've found it. Counters rather than list-style so the
   number can be a gold coin that lines up with the text baseline. */
.ym-steps { list-style: none; counter-reset: ym; margin: 18px 0 22px; text-align: left; }
.ym-steps li {
  counter-increment: ym;
  position: relative; padding-left: 40px; min-height: 28px;
  margin-bottom: 12px; font-size: 0.94rem; line-height: 1.5;
  text-wrap: pretty;
}
.ym-steps li::before {
  content: counter(ym);
  position: absolute; left: 0; top: -1px;
  width: 27px; height: 27px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  color: var(--navy-900); font-weight: 900; font-size: 0.85rem;
}
.ym-steps li b { color: var(--gold); }
.ym-steps li:last-child { margin-bottom: 0; }

.yoto-modal .btn-yoto { width: 100%; }
.ym-fine { color: var(--muted); font-size: 0.74rem; font-weight: 700; margin-top: 10px; }
.ym-link {
  display: inline-block; margin-top: 16px;
  color: var(--muted); font-size: 0.82rem; font-weight: 800;
  text-decoration: underline; text-underline-offset: 3px;
}
.ym-link:hover { color: var(--gold); }

/* ---------- Songs ----------
   Spotify's embed is the only one that lists songs to everyone (Apple's shows
   just a Play button when signed out), so it's the on-page player; the buttons
   below open the whole catalogue on whichever app the visitor prefers. */
.song-box { max-width: 640px; margin: 0 auto; }
.song-embed {
  border-radius: 16px; overflow: hidden;
  border: 2px solid rgba(255, 213, 74, 0.22);
  box-shadow: var(--shadow-pop);
  background: rgba(7, 19, 49, 0.6);
  min-height: 152px;
}
.song-embed iframe { display: block; width: 100%; border: 0; }

.song-elsewhere-label {
  text-align: center; margin: 22px 0 12px;
  color: var(--muted); font-weight: 800; font-size: 0.86rem;
}
.song-platforms { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.song-plat {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 18px; border-radius: 999px;
  text-decoration: none; font-weight: 800; font-size: 0.9rem;
  color: var(--ink);
  background: var(--card); border: 2px solid var(--card-border);
  box-shadow: 3px 3px 0 rgba(2, 8, 26, 0.45);
  transition: transform 0.16s ease, border-color 0.2s, color 0.2s;
}
/* focus-visible is the keyboard path and belongs to every device; only the
   hover half is mouse-only. Splitting them is why this isn't one selector. */
.song-plat:focus-visible {
  transform: translate(-1px, -2px); border-color: var(--gold); color: var(--gold);
  box-shadow: 4px 5px 0 rgba(2, 8, 26, 0.45);
}
@media (hover: hover) and (pointer: fine) {
  .song-plat:hover {
    transform: translate(-1px, -2px); border-color: var(--gold); color: var(--gold);
    box-shadow: 4px 5px 0 rgba(2, 8, 26, 0.45);
  }
}
.song-plat .dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }

/* ---------- Business inquiries (third method inside the connect card) ---------- */
.contact-method {
  margin-top: 26px; padding-top: 22px;
  border-top: 1px dashed rgba(255, 213, 74, 0.28); /* same divider as the kit form */
  scroll-margin-top: 90px; /* nav "Business" + footer "Contact" anchor here */
}
/* the address is one long unbreakable word — let it wrap and shrink, never burst the card */
.contact-btn { white-space: normal; font-size: clamp(0.82rem, 3.4vw, 1rem); padding-left: 22px; padding-right: 22px; }

/* ---------- Footer: rowboat painting ---------- */
.footer {
  margin-top: clamp(60px, 8vw, 100px);
  /* moonrise: a faint warm glow above the rowboat, on the dark-hill ground */
  background:
    radial-gradient(560px 300px at 50% 0%, rgba(255, 233, 163, 0.07), transparent 70%),
    var(--navy-950);
  /* the footer rises out of the star field like a dark hill — mirrors
     .hero-ground's curve, with a moonlit rim to match */
  border-radius: clamp(28px, 6vw, 60px) clamp(28px, 6vw, 60px) 0 0;
  border-top: 1px solid rgba(255, 233, 163, 0.12);
  box-shadow: 0 -14px 40px rgba(2, 8, 26, 0.45);
  /* enough room that the docked mini player never covers the last line */
  padding: 60px 20px calc(130px + env(safe-area-inset-bottom, 0px));
  text-align: center;
}
.rowboat-frame {
  position: relative;
  width: min(460px, 84vw); height: 240px; /* 84vw cap guarantees sky on both sides */
  margin: 0 auto 26px;
  border: 10px solid #8a6a3b;
  border-radius: 6px;
  background: linear-gradient(180deg, #0b1d3f 0%, #10254e 55%, #0d2145 100%);
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6), inset 0 0 40px rgba(0, 0, 0, 0.5);
}
.rb-moon {
  position: absolute; top: 22px; right: 44px; width: 44px; height: 44px;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 38%, #fff5cf, var(--gold-soft) 65%, #e8c25f);
  box-shadow: 0 0 34px rgba(255, 233, 163, 0.55);
}
.rb-hill {
  position: absolute; bottom: 84px; left: -20%; right: -20%; height: 70px;
  background: #081530; border-radius: 100% 100% 0 0;
}
.rb-water {
  position: absolute; bottom: 0; left: 0; right: 0; height: 92px;
  background: linear-gradient(180deg, #123061, #0a1a3a);
}
.rb-water::after {
  content: ""; position: absolute; inset: 0;
  background-image: radial-gradient(60px 5px at 30% 30%, rgba(255, 233, 163, 0.25), transparent 70%),
    radial-gradient(80px 5px at 70% 60%, rgba(255, 255, 255, 0.12), transparent 70%),
    radial-gradient(50px 4px at 45% 80%, rgba(255, 233, 163, 0.18), transparent 70%);
}
.rb-boat {
  position: absolute; bottom: 58px; left: -140px; width: 110px;
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.5));
}
.rb-hull { position: relative; animation: boat-rock 3.4s ease-in-out infinite; transform-origin: 55% 88%; }
@keyframes boat-rock {
  0%, 100% { transform: rotate(-2.4deg); }
  50% { transform: rotate(2.6deg); }
}
.rb-hull svg { position: relative; } /* hull paints over Jim's feet */
.rb-riders { position: absolute; bottom: 26px; left: 50%; transform: translateX(-50%); width: 30px; }
/* negative delay: first loop starts ~27% in, so Jim is already on screen when the frame reveals */
.rowboat-frame.in .rb-boat { animation: row-away 26s linear -7s infinite; }
@keyframes row-away {
  0% { transform: translateX(0) rotate(0.5deg); }
  50% { transform: translateX(calc(50vw - 60px)) rotate(-1deg); }
  100% { transform: translateX(calc(100vw)) rotate(0.5deg); }
}
/* clamp boat travel to the frame width */
.rowboat-frame { --frame-w: min(460px, 84vw); }
@keyframes row-away {
  0% { transform: translateX(0); }
  100% { transform: translateX(calc(var(--frame-w) + 280px)); }
}

.footer-lyric { color: var(--gold-soft); font-style: italic; font-weight: 700; font-size: 1.05rem; max-width: 46ch; margin: 0 auto 6px; }
.footer-signoff { color: var(--muted); font-weight: 700; margin-bottom: 26px; }
.footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 26px; margin-bottom: 14px; }
.footer-links a { text-decoration: none; color: var(--muted); font-weight: 800; font-size: 0.92rem; cursor: pointer; }
.footer-links a:hover { color: var(--gold); }
.footer-copy { color: rgba(174, 188, 221, 0.55); font-size: 0.85rem; }

/* ---------- Mini player ---------- */
.mini-player[hidden] { display: none; }
/* Docked, not floating. A fully-rounded pill hovering above the edge reads as
   a notification — something finished, to be dismissed. Welding it to the
   bottom with a rounded top lip reads as a drawer pulled part-way up, which is
   what actually makes "there's more above this" legible at a glance. */
.mini-player {
  position: fixed; left: 50%; bottom: 0; transform: translateX(-50%);
  z-index: 80;
  display: flex; align-items: center; gap: 14px;
  width: min(560px, 100%);
  background: rgba(10, 22, 48, 0.97);
  border: 1px solid rgba(255, 213, 74, 0.35);
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding: 24px 14px 10px;
  padding-bottom: max(10px, env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -14px 44px rgba(2, 8, 26, 0.7);
  touch-action: none; /* the bar owns its vertical drag (swipe up to open) */
  animation: mp-in 0.35s ease;
}
@keyframes mp-in { from { transform: translate(-50%, 100%); opacity: 0; } to { transform: translate(-50%, 0); opacity: 1; } }

/* the grabber: capsule + a word, in its own band across the top */
.mp-grip {
  position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  height: 24px; padding: 0 12px;
  display: flex; align-items: center; gap: 8px;
  background: none; border: 0; cursor: pointer;
}
/* an arrow, not a capsule — it points at what the gesture does */
.mp-grip-arrow {
  width: 13px; height: 13px; flex-shrink: 0;
  color: var(--gold); opacity: 0.8;
  transition: transform 0.18s ease, opacity 0.18s ease;
}
.mp-grip-label {
  font-family: var(--font-body); font-weight: 800;
  font-size: 0.67rem; letter-spacing: 0.04em;
  color: var(--gold-soft); opacity: 0.8; white-space: nowrap;
}
/* the arrow lifts on hover (mouse only); focus-visible is the keyboard path
   and must stay outside the guard */
.mp-grip:focus-visible .mp-grip-arrow { transform: translateY(-2px); opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .mini-player:hover .mp-grip-arrow { opacity: 1; }
  .mp-grip:hover .mp-grip-arrow { transform: translateY(-2px); opacity: 1; }
}
.mp-grip:hover .mp-grip-label { opacity: 1; }

/* skip ahead without opening the player — the one control auto-advance makes
   worth having down here; everything else stays in the full screen view */
.mp-next {
  flex-shrink: 0; display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: none; border: 0; cursor: pointer; color: var(--muted);
  transition: color 0.18s, transform 0.15s;
}
.mp-next svg { width: 18px; height: 18px; }
@media (hover: hover) and (pointer: fine) {
  .mp-next:hover { color: var(--ink); transform: scale(1.08); }
}
.mp-next:disabled { opacity: 0.3; cursor: default; transform: none; }
.mp-grip:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: 99px; }

.mp-art { display: block; flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%; object-fit: cover; }
.mp-info { flex: 1; min-width: 0; }
.mp-title { display: block; font-weight: 800; font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.mp-bar { position: relative; height: 6px; border-radius: 99px; background: rgba(255, 255, 255, 0.14); cursor: pointer; margin: 5px 0 3px; }
/* bigger touch target for seeking — but kept to ±7px, because this pad is
   excluded from the swipe-up and a fatter one carves a dead band across the
   middle of the bar where the gesture silently stops working */
.mp-bar::before { content: ""; position: absolute; left: 0; right: 0; top: -7px; bottom: -7px; }
.mp-fill { height: 100%; width: 0%; border-radius: 99px; background: linear-gradient(90deg, var(--gold-deep), var(--gold)); }
.mp-time { font-size: 0.7rem; color: var(--muted); font-weight: 800; font-variant-numeric: tabular-nums; }
.mp-btn {
  flex-shrink: 0; width: 46px; height: 46px; border-radius: 50%;
  border: 0; cursor: pointer; display: grid; place-items: center;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  color: var(--navy-900);
}
.mp-btn svg { width: 22px; height: 22px; }
.mp-close { flex-shrink: 0; background: none; border: 0; color: var(--muted); font-size: 0.95rem; cursor: pointer; padding: 6px; }
.mp-close:hover { color: var(--ink); }

/* ---------- Full screen player ----------
   The mini bar blown up into the same night sky as the hero. Sized in vh so
   the whole thing — art, title, scrubber, controls — fits one screen without
   scrolling, on a phone or a laptop. */
.full-player[hidden] { display: none; }
.full-player {
  position: fixed; inset: 0; z-index: 120;
  display: flex; justify-content: center;
  overflow: hidden;
  background:
    radial-gradient(560px 280px at 50% 6%, rgba(64, 118, 194, 0.42), transparent 72%),
    radial-gradient(130% 95% at 50% 30%, #1d4b8e 0%, #16407e 34%, #0e2c5d 68%, #0a1f47 100%);
  animation: fp-in 0.34s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes fp-in { from { opacity: 0; transform: translateY(46px); } to { opacity: 1; transform: none; } }
.full-player.closing { animation: fp-out 0.24s ease forwards; }
@keyframes fp-out { to { opacity: 0; transform: translateY(46px); } }
.fp-sky { position: absolute; inset: 0; pointer-events: none; }

.fp-sheet {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  width: min(460px, 100%); height: 100%;
  padding: clamp(12px, 2.2vh, 22px) 24px clamp(14px, 3.4vh, 30px);
  gap: clamp(6px, 1.5vh, 16px);
  touch-action: pan-y; /* the sheet reads vertical drags itself (swipe to close) */
}
/* just the centred eyebrow now. min-height holds the 40px the close button used
   to give this row, so dropping it out of the flow doesn't shift the art up. */
.fp-head { display: flex; align-items: center; justify-content: center; width: 100%; min-height: 40px; flex-shrink: 0; }
.fp-close {
  display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  border: 2px solid rgba(255, 255, 255, 0.2);
  color: var(--ink); cursor: pointer;
  transition: color 0.18s, border-color 0.18s;
}
.fp-close svg { width: 20px; height: 20px; }
.fp-close:hover { color: var(--gold); border-color: var(--gold); }
.fp-eyebrow {
  font-weight: 800; font-size: 0.68rem; letter-spacing: 1.6px; text-transform: uppercase;
  color: var(--sky-blue); opacity: 0.9;
}
/* Pinned to the OVERLAY's top-right corner rather than the sheet's. The sheet
   is only min(460px, 100%) wide, so on a desktop its right edge lands a couple
   of hundred px right of centre — the ✕ read as a stray button floating next to
   the "NOW PLAYING" label instead of a corner control. Anchoring it to
   .full-player puts it in the corner every modal keeps its close button in.
   The offsets match the sheet's own padding, so on a phone (sheet = 100% wide)
   the button doesn't move at all. */
.fp-close-top {
  position: absolute; z-index: 4;
  top: clamp(12px, 2.2vh, 22px); right: 24px;
}

/* the art soaks up all the spare height and stays centred in it, so a tall
   screen spreads the slack around the artwork instead of tearing a hole
   between the title and the scrubber */
.fp-art-wrap {
  position: relative; display: grid; place-items: center;
  flex: 1 1 auto; min-height: 0;
  /* width:100% is load-bearing. Both children are absolutely positioned, so the
     wrapper has no in-flow content, and .fp-sheet's align-items:center made it
     shrink-to-fit to ZERO px. The art's inset:0 + margin:auto then resolved
     against a 0-wide box: CSS 2.1 §10.3.7 says when auto margins would come out
     negative, set margin-left to 0 and solve the right one — so the art was
     left-aligned on the sheet's centre line and hung off its right side
     (clipped at the viewport edge on a phone). The .fp-eq badge used the
     wrapper's centre and so stayed put, which is why only the art looked off. */
  width: 100%;
  margin: clamp(6px, 2vh, 20px) 0 clamp(10px, 2.4vh, 24px);
}
.fp-art {
  /* Absolutely positioned inside the (already relative) wrapper so that
     max-height:100% resolves against a DEFINITE box. As an in-flow grid item
     that percentage silently did not resolve — the art kept its full size when
     the wrapper was squeezed on a short phone and painted straight over the EP
     badge. (Proof it wasn't clamping: `max-height:100%` on its own let a 320px
     image sit in a 121px wrapper.) inset+margin:auto keeps it centred exactly
     where place-items:center had it, and it now shrinks into whatever room is
     left instead of overflowing. The wrapper's own size is unchanged, so the
     .fp-eq badge pinned to its bottom edge doesn't move. */
  position: absolute; inset: 0; margin: auto;
  width: auto; height: auto;
  max-width: min(340px, 72vw);
  max-height: min(340px, 36vh, 100%);
  object-fit: contain;
  border-radius: 22px;
  box-shadow: 0 26px 60px rgba(2, 8, 26, 0.7), 0 0 0 1px rgba(255, 213, 74, 0.22);
}
.fp-eq {
  position: absolute; left: 50%; bottom: -13px; transform: translateX(-50%);
  height: 26px; padding: 0 13px 6px; border-radius: 999px;
  background: rgba(7, 19, 49, 0.92); border: 1px solid rgba(255, 213, 74, 0.4);
}
.full-player.is-playing .fp-eq { display: inline-flex; }

.fp-meta { text-align: center; width: 100%; flex-shrink: 0; }
.fp-num {
  display: inline-block;
  font-family: var(--font-display); font-size: 0.72rem; letter-spacing: 0.08em;
  background: rgba(255, 213, 74, 0.14); color: var(--gold);
  border: 1px solid rgba(255, 213, 74, 0.35);
  padding: 3px 12px; border-radius: 999px;
}
/* an authored display: would otherwise beat the [hidden] attribute */
.fp-num[hidden] { display: none; }
.fp-title { font-family: var(--font-body); font-weight: 800; font-size: clamp(1.02rem, 4.2vw, 1.28rem); line-height: 1.32; margin: 9px 0 3px; }
.fp-tags { color: var(--sky-blue); font-weight: 800; font-size: 0.78rem; min-height: 1.2em; }

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

.fp-controls {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(8px, 3.5vw, 20px);
  width: 100%; margin: clamp(6px, 2vh, 16px) 0; flex-shrink: 0;
}
.fp-ctl {
  position: relative; display: grid; place-items: center;
  width: 48px; height: 48px; border-radius: 50%;
  background: none; border: 0; color: var(--ink); cursor: pointer;
  transition: color 0.18s, transform 0.15s, opacity 0.18s;
}
.fp-ctl svg { width: 26px; height: 26px; }
@media (hover: hover) and (pointer: fine) {
  .fp-ctl:hover { color: var(--gold); transform: scale(1.09); }
}
.fp-ctl:disabled { opacity: 0.28; cursor: default; transform: none; color: var(--ink); }
/* the little "15" tucked inside the skip arrows */
.fp-skip span {
  position: absolute; left: 50%; top: 55%; transform: translate(-50%, -50%);
  font-size: 0.53rem; font-weight: 900; letter-spacing: 0;
}
.fp-play {
  display: grid; place-items: center;
  width: 74px; height: 74px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  color: var(--navy-900);
  box-shadow: 0 10px 28px rgba(255, 213, 74, 0.3), 5px 5px 0 rgba(148, 96, 12, 0.45);
  transition: transform 0.15s;
}
.fp-play svg { width: 32px; height: 32px; }
@media (hover: hover) and (pointer: fine) {
  .fp-play:hover { transform: scale(1.05); }
}
.fp-play:active { transform: scale(0.97); }
.fp-hint { color: var(--muted); font-size: 0.72rem; font-weight: 700; opacity: 0.6; flex-shrink: 0; }
/* mouse users get Esc / the ✕ instead — there's nothing to swipe */
@media (hover: hover) and (pointer: fine) { .fp-hint { display: none; } }

/* shuffle · speed · queue — the quieter row under the transport */
.fp-extra { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; flex-shrink: 0; }
.fp-x-btn {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-body); font-weight: 800; font-size: 0.76rem;
  padding: 7px 13px; border-radius: 999px; cursor: pointer;
  background: rgba(255, 255, 255, 0.07);
  border: 1.5px solid rgba(255, 255, 255, 0.16);
  color: var(--muted);
  transition: color 0.18s, border-color 0.18s, background 0.18s;
}
.fp-x-btn svg { width: 15px; height: 15px; }
.fp-x-btn:hover { color: var(--ink); border-color: rgba(255, 255, 255, 0.34); }
/* shuffle on / queue open both light up gold */
.fp-x-btn[aria-pressed="true"], .fp-x-btn[aria-expanded="true"] {
  background: rgba(255, 213, 74, 0.16); border-color: var(--gold); color: var(--gold);
}
.fp-speed-val { font-variant-numeric: tabular-nums; min-width: 26px; text-align: center; }
/* a speed other than 1× is a state worth seeing at a glance */
#fpSpeed.off-normal { background: rgba(143, 208, 255, 0.16); border-color: var(--sky-blue); color: var(--sky-blue); }

/* the queue slides up over the player */
.fp-queue[hidden] { display: none; }
.fp-queue {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  display: flex; flex-direction: column;
  max-height: 72%;
  background: rgba(7, 19, 49, 0.98);
  border-top: 2px solid rgba(255, 213, 74, 0.35);
  border-radius: 22px 22px 0 0;
  box-shadow: 0 -18px 50px rgba(2, 8, 26, 0.6);
  animation: q-up 0.26s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes q-up { from { transform: translateY(100%); } to { transform: none; } }
.fp-queue-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px 10px; flex-shrink: 0;
}
/* the title wraps; the controls do not get squashed to do it */
.fp-queue-head h3 { font-size: 1rem; color: var(--gold); letter-spacing: 0.06em; min-width: 0; }
.fp-queue-close { width: 34px; height: 34px; flex-shrink: 0; }
.fp-queue-close svg { width: 15px; height: 15px; }
/* overscroll containment: over-scrolling the queue must not chain into the
   page underneath (which body.modal-open alone doesn't stop on iOS) */
.fp-queue-list {
  list-style: none; overflow-y: auto; padding: 0 10px 16px;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}
.fp-q-item {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 9px 10px; border-radius: 12px;
  background: none; border: 0; cursor: pointer; text-align: left;
  color: var(--ink); font-family: var(--font-body);
  transition: background 0.15s;
}
.fp-q-item:hover { background: rgba(255, 255, 255, 0.07); }
.fp-q-num {
  flex-shrink: 0; width: 46px;
  font-family: var(--font-display); font-size: 0.66rem; letter-spacing: 0.06em;
  color: var(--gold); opacity: 0.85;
}
.fp-q-title { flex: 1; min-width: 0; font-size: 0.84rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-q-dur { flex-shrink: 0; font-size: 0.72rem; font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; }
.fp-q-item.now { background: rgba(255, 213, 74, 0.12); }
.fp-q-item.now .fp-q-title { color: var(--gold); }
.fp-q-empty { color: var(--muted); font-weight: 700; font-size: 0.85rem; text-align: center; padding: 20px 10px 26px; }

/* screen-reader-only announcements for the keyboard reorder path */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ---- Drag to re-order ----
   The grip is the ONLY draggable surface, so which gesture you meant is
   decided by what you touched — no timers, no thresholds, no long-press
   racing the list's own scrolling. */
.fp-q-row { position: relative; display: flex; align-items: center; transition: transform 0.16s ease; }
.fp-q-row .fp-q-item { flex: 1; min-width: 0; }
.fp-q-grip {
  flex-shrink: 0; display: grid; place-items: center;
  width: 44px; align-self: stretch; min-height: 44px;
  background: none; border: 0; cursor: grab;
  border-radius: 12px; color: var(--gold);
  touch-action: none;                 /* the load-bearing line: claims the gesture */
  -webkit-touch-callout: none; user-select: none; -webkit-user-select: none;
}
.fp-q-grip:active { cursor: grabbing; }
.fp-q-grip:hover { background: rgba(255, 255, 255, 0.07); }
.fp-q-grip:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
/* three little moonbeams */
.fp-q-grip-glyph, .fp-q-grip-glyph::before, .fp-q-grip-glyph::after {
  display: block; width: 18px; height: 2.5px; border-radius: 99px;
  background: currentColor; opacity: 0.7;
}
.fp-q-grip-glyph { position: relative; }
.fp-q-grip-glyph::before, .fp-q-grip-glyph::after { content: ""; position: absolute; left: 0; }
.fp-q-grip-glyph::before { top: -6px; }
.fp-q-grip-glyph::after { top: 6px; }
.fp-q-item { touch-action: pan-y; }   /* stated as intent so nobody tidies it away */
.fp-q-row.is-lifted { z-index: 4; transition: none; }
.fp-q-row.is-lifted .fp-q-item, .fp-q-row.is-lifted .fp-q-grip {
  background: rgba(255, 213, 74, 0.16);
  box-shadow: 0 10px 26px rgba(2, 8, 26, 0.55);
}
.fp-q-row.is-lifted .fp-q-item { transform: scale(1.02); border-radius: 12px; }
.fp-q-row.is-grabbed .fp-q-item { background: rgba(143, 208, 255, 0.16); }
.fp-q-row.is-grabbed .fp-q-grip { color: var(--sky-blue); }
.fp-queue-list.is-dragging { user-select: none; -webkit-user-select: none; }

/* "Keep playing" — the opt-out for auto-advance, parked in the queue header */
.fp-auto {
  display: inline-flex; align-items: center; gap: 7px; margin-left: auto; margin-right: 8px;
  flex-shrink: 0; white-space: nowrap;
  font-family: var(--font-body); font-weight: 800; font-size: 0.72rem;
  padding: 6px 12px; border-radius: 999px; cursor: pointer;
  background: rgba(255, 255, 255, 0.07);
  border: 1.5px solid rgba(255, 255, 255, 0.16);
  color: var(--muted);
  transition: color 0.18s, border-color 0.18s, background 0.18s;
}
.fp-auto-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; opacity: 0.5; }
.fp-auto[aria-checked="true"] {
  background: rgba(255, 213, 74, 0.16); border-color: var(--gold); color: var(--gold);
}
.fp-auto[aria-checked="true"] .fp-auto-dot { opacity: 1; }

/* ---- Speed picker ---- */
.fp-speed-wrap { position: relative; display: inline-flex; }
.fp-speed-menu[hidden] { display: none; }
.fp-speed-menu {
  position: absolute; z-index: 5;
  bottom: calc(100% + 10px); left: 50%; transform: translateX(-50%);
  min-width: 186px; max-width: min(240px, calc(100vw - 40px));
  max-height: min(236px, 46vh); overflow-y: auto;
  overscroll-behavior: contain;       /* must not chain into the sheet swipe */
  padding: 6px;
  background: rgba(7, 19, 49, 0.98);
  border: 1.5px solid rgba(255, 213, 74, 0.35);
  border-radius: 16px;
  box-shadow: 0 14px 40px rgba(2, 8, 26, 0.62);
  /* its own keyframes, NOT the queue's q-up: that one animates `transform`
     from translateY(100%) and would wipe out the translateX(-50%) centering,
     so the menu flew in ~93px off to one side and snapped */
  animation: speed-up 0.18s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes speed-up {
  from { transform: translate(-50%, 10px); opacity: 0; }
  to { transform: translateX(-50%); opacity: 1; }
}
.fp-speed-opt {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 11px; border-radius: 11px;
  background: none; border: 0; cursor: pointer; text-align: left;
  color: var(--ink); font-family: var(--font-body); font-size: 0.8rem; font-weight: 700;
}
.fp-speed-opt:hover { background: rgba(255, 255, 255, 0.07); }
.fp-speed-opt-rate {
  flex-shrink: 0; width: 46px;
  font-variant-numeric: tabular-nums; font-weight: 800; color: var(--gold); opacity: 0.85;
}
.fp-speed-opt-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-speed-opt[aria-checked="true"] { background: rgba(255, 213, 74, 0.14); }
.fp-speed-opt[aria-checked="true"] .fp-speed-opt-label { color: var(--gold); }

/* the auto-advance / end-of-queue line, in both players */
.fp-note[hidden], .mp-note[hidden] { display: none; }
.fp-note {
  margin-top: 6px; font-family: var(--font-body); font-weight: 800;
  font-size: 0.8rem; color: var(--gold); text-align: center; text-wrap: balance;
}
/* one line only — a wrapping note grew the docked bar past the footer's
   reserved space and covered the copyright line */
.mp-note {
  display: block; font-size: 0.68rem; font-weight: 800; color: var(--gold);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---------- Reveal on scroll ---------- */
.reveal { opacity: 0; transform: translateY(20px); }
.reveal.in { opacity: 1; transform: none; transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.16, 1, 0.3, 1); }

/* ---------- Responsive ---------- */
/* FOUR nav links plus the three labelled listen buttons need ~1102px, measured.
   (The history: ~1040px for five links and two buttons, ~1140px once YouTube
   joined them on 2026-08-16, then back down when "Listen" left the menu on
   2026-08-17 — the threshold has to move with the contents or it hides labels
   that would have fitted.) Past that they slide off the right edge. Between the
   burger breakpoint and there, shed the wordmark and the button labels instead
   — the links themselves stay visible, so Songs and Contact don't get buried in
   a menu.
   Leave headroom past the measured need: this query matches the viewport width
   INCLUDING the scrollbar, so a threshold set to the exact number leaves a dead
   zone ~15px wide where the layout has already broken. */

/* THE LISTEN BUTTONS ARE ICON-ONLY EVERYWHERE BELOW THE FULL-WIDTH LAYOUT, and
   that is ONE rule on purpose.

   It used to be two — the same pair of declarations copied into the 721-1200px
   block below and into the 520px block further down — which left 521-720px with
   no rule at all and three fully labelled pills in it. That band is exactly
   where the burger appears, so the burger was pushed clean off the right edge:
   141px past it at 600px wide. Nothing showed a scrollbar either, because
   html{overflow-x:clip} silently swallows the overflow instead — the menu was
   simply gone, with no symptom pointing at the nav.

   It was already broken there with two buttons (~37px over at 600px); the third
   made it unmissable. If a third state is ever needed here, widen or narrow
   THIS query — don't add a second copy of these declarations somewhere else. */
/* ---------- centre the nav links on their own axis ----------
   .nav is `display:flex; justify-content:space-between` over three children —
   brand, links, buttons — and space-between only centres the MIDDLE child when
   the two outer ones happen to be the same width. They are not: the wordmark is
   narrower than three platform buttons, so the links sat noticeably left of the
   bar's true centre (measured ~73px off at 1895px wide).

   Fixed by giving the two outer groups an equal share of the leftover space
   (`flex: 1 1 0` — equal basis, equal growth) and letting the links keep their
   natural width in the middle. Everything stays IN FLOW, which is why this is
   preferred over the usual absolute-centre trick: an absolutely positioned
   middle item can silently overlap the brand or the buttons at widths where the
   bar gets tight, whereas this just stops centring and starts crowding, which
   is visible and safe. Flex items keep min-width:auto, so neither side can be
   squashed below its content.

   ABOVE 720px ONLY. At 720px and below .nav-links becomes the burger drawer —
   position:absolute, full width, top:100% — and is out of flow entirely, so
   these rules would be meaningless there and the `flex: 1 1 0` on the outer two
   would leave the brand and the buttons splitting the bar down the middle.

   .nav's HEIGHT must not move: css/episode.css pins .ep-head at
   top: var(--ep-nav-h) and that offset has to hold with JS off, so it cannot be
   measured at runtime. Verified 67px before and after. */
@media (min-width: 721px) {
  .nav-brand, .nav-cta { flex: 1 1 0; }
  .nav-cta { justify-content: flex-end; }
  .nav-links { flex: 0 0 auto; }
}

@media (max-width: 1160px) {
  .nav-cta .btn { padding: 9px 11px; }
  .nav-cta .btn .btn-label { display: none; }
}
/* Between the burger breakpoint and the full layout, the wordmark goes too, so
   the five links can stay inline rather than getting buried in a menu. Below
   721px the burger owns the links and .nav-name has its own rules further down. */
@media (max-width: 1160px) and (min-width: 721px) {
  .nav-name { display: none; }
  .nav-links { gap: 16px; }
}
@media (max-width: 960px) {
  .ep-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .follow-card { flex-direction: column; text-align: center; }
  .follow-card p { margin-left: auto; margin-right: auto; }
  .follow-card h2::before { margin: 0 auto 12px; } /* squiggle centers with the stacked layout */
}
@media (max-width: 720px) {
  .nav-links {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; gap: 0;
    background: rgba(7, 18, 41, 0.98);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    display: none;
  }
  .nav-links.open { display: flex; }
  .nav-links a { padding: 15px 24px; border-top: 1px solid rgba(255, 255, 255, 0.06); }
  .nav-burger { display: flex; }
  /* the wordmark carries its own stars — the big decorative ones collide with it on small screens */
  .cstar { display: none; }
  /* starlit rooms: tighter radius/shadow on small screens */
  #adventures, #songs, #listen {
    border-radius: 24px;
    margin-top: 40px;
    box-shadow: 0 0 0 2px rgba(5, 13, 32, 0.6), 0 12px 30px rgba(2, 8, 26, 0.5);
  }
  #adventures::after { right: 22px; }
  #songs::after { left: 22px; }
  .ep-grid { grid-template-columns: 1fr; }
  .ep-card.featured { flex-direction: column; text-align: left; align-items: flex-start; }
  .chip { padding: 12px 19px; font-size: 0.95rem; } /* rail chips are primary tap targets */
  .mp-time { display: none; }

  /* Filter pills: swipeable lines instead of a wall between the switch and results */
  .map-frame { padding: 14px 12px 10px; border-radius: 18px; }
  .zone-label { font-size: 0.68rem; margin: 0 2px 8px; }
  .mode-btn { padding: 8px 13px; font-size: 0.84rem; }
  /* narrow screens stack the results card — a floated ✕ crowds wrapped titles */
  .results-head { padding: 4px 12px; }
  .results-clear { position: static; transform: none; display: table; margin: 8px auto 0; padding: 5px 12px; }
  .results-title { font-size: 1.02rem; }
  .chips {
    flex-wrap: nowrap; justify-content: flex-start;
    overflow-x: auto; margin: 0 -12px; padding: 4px 14px 10px;
    scroll-snap-type: x proximity; overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 14px, #000 calc(100% - 14px), transparent);
            mask-image: linear-gradient(90deg, transparent, #000 14px, #000 calc(100% - 14px), transparent);
  }
  .chips::-webkit-scrollbar { display: none; }
  .chip { flex-shrink: 0; scroll-snap-align: start; white-space: nowrap; }
  /* every pill set doubles into a two-row swipe rail — half the swiping.
     Flex courses (not grid columns) so every pill keeps its natural width
     and the gaps stay uniform. */
  #filterPills { flex-direction: column; align-items: flex-start; }
  #filterPills .pill-row { display: flex; gap: 9px; width: max-content; }

  /* Reviews: the same gentle auto-marquee as desktop, a touch slower */
  .review-track { animation-duration: 80s; padding: 6px 0 16px; gap: 12px; }
  .review-card { width: min(300px, 80vw); }
}
/* THE WORDMARK GOES BEFORE THE MENU DOES.
   This threshold used to be 384px, which is narrower than every phone sold in
   the last decade — so from 385px up the wordmark stayed, and once the header
   grew a third listen button it was the thing pushing the burger off the right
   edge (64px off at 390px, measured on the live site). The menu is a control;
   the wordmark is decoration sitting next to a logo tile that already says the
   same thing. Decoration yields first.

   WHY 640 AND NOT 520, WHERE IT ACTUALLY STOPS OVERFLOWING. At 521 the header
   fit with 18px to spare, and 18px is not a margin — it is a coincidence. The
   wordmark is set in Brown Beige, which is a chunky display face: measured at
   641px it renders 206px wide against 165px for the Nunito fallback, so the
   font that ships is the WIDE one and a threshold tuned to it has no give left
   for a longer wordmark, a bigger default text size, or a fourth button. At 640
   the first width that shows the wordmark has ~129px of slack. Same lesson as
   the 1200px query above: leave headroom past the measured need. */
@media (max-width: 640px) {
  .nav-name { display: none; }
}
@media (max-width: 520px) {
  /* the icon-only rule lives in the 1200px block above — this is only the
     tighter spacing a phone needs on top of it */
  .nav-cta { gap: 8px; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .stars, .shooting-star, .hero-moon, .hero-logo, .marquee-track,
  .review-track, .eq i, .rowboat-frame.in .rb-boat, .rb-hull, .ep-new, .scroll-cue,
  .empty-jim, .full-player, .full-player.closing, .fp-queue,
  .mini-player, .fp-speed-menu, .yoto-modal[open] { animation: none !important; }
  .fp-q-row { transition: none !important; }
  .fp-q-row.is-lifted .fp-q-item { transform: none !important; } /* keep the lift, drop the scale */
  .spark { display: none; }
  .reveal { opacity: 1; transform: none; }
  .btn:hover, .ep-card:hover, .song-plat:hover, .song-plat:focus-visible,
  .fp-ctl:hover, .fp-play:hover { transform: none; }
  /* frozen marquee would trap the reviews — make them scrollable instead */
  .reviews .review-row { overflow-x: auto; }
  .review-card.dup { display: none; }
}

/* Link out to /episodes — the plain, indexable full list. The grid above it is
   the filterable browser; this is the page Google and the AI crawlers read. */
.ep-all-link { text-align: center; margin: 18px 0 0; }
.ep-all-link a {
  color: var(--sky-blue); font-weight: 800; font-size: 0.95rem; text-decoration: none;
}
.ep-all-link a:hover { color: var(--gold); text-decoration: underline; }

/* ---------- the navigation shell (js/shell.js) --------------------------
   #ntnView holds whatever page you're on; #ntnLayers holds the player and the
   creator and is never replaced, which is how a story keeps playing while you
   move around the site.

   These two wrappers must stay layout-transparent. NEVER give either one a
   transform, filter, will-change, contain, overflow or backdrop-filter: any of
   those creates a containing block that breaks position:fixed on the mini bar,
   or a scroll container that breaks position:sticky on the nav and the episode
   header. */
#ntnView { display: block; }
#ntnLayers { display: contents; }

/* Scroll anchoring keeps your visual position when content above you resizes —
   exactly the wrong instinct when the whole page has just been replaced. It beat
   the shell's "a new page starts at the top" every time, landing you partway
   down an episode you had only just opened.

   It has to be suppressed on the SCROLL CONTAINER, which for this site is the
   document. Putting it on #ntnView does nothing: that only excludes #ntnView
   itself from being chosen as the anchor, while the document scroller carries on
   anchoring to whatever is inside it. */
html, body { overflow-anchor: none; }

/* A slow fetch, and only a slow one: the shell waits 400ms before adding this,
   because a same-origin page lands in well under 100ms and a bar that flashes
   on every tap reads as jank. */
.ntn-loading::after {
  content: "";
  position: fixed; inset: 0 auto auto 0; z-index: 200;
  height: 3px; width: 100%;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold), var(--sky-blue));
  transform-origin: 0 50%;
  animation: ntn-load 1.4s ease-in-out infinite;
}
@keyframes ntn-load {
  0%   { transform: scaleX(0);   opacity: 1; }
  70%  { transform: scaleX(0.8); opacity: 1; }
  100% { transform: scaleX(1);   opacity: 0.3; }
}

/* ============================================================
   THE AD GATE — the interstitial, as a layer over the homepage
   ------------------------------------------------------------
   Ad traffic lands on / (the ads point there and are not being edited), and this
   covers the homepage with the one question that traffic was bought to answer:
   which app do you listen in. Dismiss it and the full homepage is underneath,
   untouched — which is the reason it is a layer rather than a redirect to
   /listen: nobody who was going to explore the site loses the chance to.

   ONLY EVER SHOWN WHEN THE URL SAYS "THIS IS AN AD CLICK". The gate is opened by
   a class the inline script in index.html's <head> puts on <html> — before the
   first paint, so the homepage never flashes behind it — and that script only
   fires on Meta's own parameters. Organic, direct and search traffic never see
   it, and neither does Googlebot (crawlers carry no utm), so this is not the
   "intrusive interstitial" pattern search penalises.

   WHAT IT COSTS, on the record: this paints only after the three stylesheets in
   <head> have downloaded — 161KB uncompressed, because the server sends no
   content-encoding. /listen carries its own inline CSS and needs none of them.
   Enabling mod_deflate is what closes most of that gap and is worth doing.
   ============================================================ */
.ad-gate { display: none; }
html.ntn-gate .ad-gate {
  display: flex;
  position: fixed; inset: 0; z-index: 150;
  flex-direction: column; align-items: center; justify-content: flex-start;
  /* Safe areas. index.html does NOT currently set viewport-fit=cover, so every
     env() here resolves to 0 and this is exactly the padding it always was —
     written this way so the gate stays correct if that meta ever changes, and
     because the gate is position:fixed inset:0, which IS laid out under the
     notch and home indicator the moment cover is enabled. */
  padding-top: max(22px, env(safe-area-inset-top, 0px));
  padding-right: max(clamp(16px, 5vw, 28px), env(safe-area-inset-right, 0px));
  padding-bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  padding-left: max(clamp(16px, 5vw, 28px), env(safe-area-inset-left, 0px));
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  text-align: center;
  /* Opaque, not a scrim. A translucent gate over a busy homepage reads as an
     accident and the page behind competes with the three buttons. */
  background:
    radial-gradient(1.6px 1.6px at 22px 28px, rgba(238, 243, 255, 0.5) 50%, transparent 52%),
    radial-gradient(1.3px 1.3px at 60px 128px, rgba(143, 208, 255, 0.32) 50%, transparent 52%),
    radial-gradient(1200px 600px at 80% -10%, #16305f66, transparent 60%),
    linear-gradient(180deg, var(--navy-900) 0%, var(--navy-800) 45%, var(--navy-900) 100%);
  background-repeat: repeat, repeat, no-repeat, no-repeat;
  background-size: 160px 160px, 210px 210px, auto, 100% 100%;
  background-color: var(--navy-900);
}
.ag-inner { width: 100%; max-width: 620px; margin: auto; }
.ag-cover {
  width: min(200px, 42vw);
  /* height:auto is NOT optional — <img>'s width/height ATTRIBUTES map to the
     width/height CSS PROPERTIES as presentational hints, so setting only width
     here leaves height:800px in force and the art renders as a tall smear. */
  height: auto;
  margin: 0 auto 18px;
  border-radius: 20px;
  box-shadow: 0 14px 38px rgba(2, 8, 26, 0.6);
}
.ag-eyebrow {
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--gold-soft); margin-bottom: 10px;
}
.ag-title {
  font-family: var(--font-display); font-weight: normal;
  font-size: clamp(1.12rem, 4.3vw, 1.55rem); line-height: 1.26;
  letter-spacing: 0.03em; max-width: 26ch; margin: 0 auto 22px;
  text-wrap: balance;
}
/* The buttons are the site's own .btn / .btn-spotify / .btn-apple / .btn-youtube
   — same fills, same shape as the hero, so the gate is recognisably this site
   and not a third-party splash. Only the layout is overridden. */
.ag-picks { display: grid; gap: 12px; }
.ag-picks .btn { width: 100%; min-height: 56px; }
.ag-fine { font-size: 0.78rem; font-weight: 600; color: var(--muted); opacity: 0.75; margin-top: 14px; }
/* The way out. Deliberately quiet — a link, not a button, well below the three
   that matter — but never absent: a gate with no exit is a trap, and someone who
   already subscribes still has a homepage to get to. */
.ag-dismiss {
  display: inline-block; margin-top: 20px;
  background: none; border: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 0.84rem; font-weight: 800;
  color: var(--muted); text-decoration: underline; text-underline-offset: 3px;
}
.ag-dismiss:hover { color: var(--gold); }
html.ntn-gate, html.ntn-gate body { overflow: hidden; }

@media (min-width: 600px) {
  .ag-picks { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ag-picks .btn { font-size: 0.95rem; padding: 14px 10px; white-space: nowrap; }
}
/* iOS puts Apple Podcasts first — pre-installed and already signed in, so it is
   the shortest path from this tap to a playing story. `order` only: the markup
   never moves, so GA4 compares like with like across devices. The media query is
   what narrows -webkit-touch-callout to a touch device; desktop Safari has
   matched that @supports test since 14 and would otherwise get the phone order. */
@media (hover: none) and (pointer: coarse) {
  @supports (-webkit-touch-callout: none) {
    .ag-picks .btn-apple { order: -1; }
  }
}
