/* Demades — dark editorial layout.

   NO EMOJI ANYWHERE IN THIS FILE — including inside these comments.
   test_no_emoji_ui.py scans the WHOLE stylesheet, not just the declarations:
   unlike a .py `#` comment (stripped before scanning), a CSS comment is served
   verbatim to the browser, so it counts as rendered output. The siren / lock
   markers this repo's Python and Markdown use freely are a submit-gate failure
   here — write "WARNING:" / plain words instead (learned the hard way, CL
   13287 → 13293). */

:root {
  /* demades-tokens:start (generated by design/gen_tokens.py — do not edit) */
  --bg: #0f0f10;
  --bg-elev: #18181b;
  --bg-elev-2: #1f1f24;
  --fg: #ececef;
  --fg-mute: #c8c8d0;
  --fg-dim: #a0a0aa;
  --accent: #f0c27b;
  --accent-hi: #ffd99a;
  --border: #2a2a32;
  --pause: #f2d23a;
  --voice-rainbow-1: #ff5f6d;
  --voice-rainbow-2: #ffb347;
  --voice-rainbow-3: #f9f871;
  --voice-rainbow-4: #5cd68a;
  --voice-rainbow-5: #4fc3f7;
  --voice-rainbow-6: #a77bff;
  /* demades-tokens:end */
  --maxw: 940px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); }
body { font: 17px/1.55 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif; }
h1, h2, h3 { font-family: "Charter", "Iowan Old Style", "Iowan", Georgia, serif; font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: 42px; line-height: 1.1; margin: 0 0 14px; }
h2 { font-size: 28px; line-height: 1.2; margin: 28px 0 12px; }
h3 { font-size: 20px; margin: 18px 0 8px; }
p { margin: 0 0 12px; color: var(--fg); }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hi); text-decoration: underline; }
code { background: var(--bg-elev-2); padding: 1px 6px; border-radius: 4px; font-size: 0.92em; }
hr { border: none; border-top: 1px solid var(--border); margin: 32px 0; }

.topnav {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 12px 24px;
  color: var(--fg-mute);
  font-size: 14px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 16px;
}
.topnav .acct { margin-left: auto; }

main { max-width: var(--maxw); margin: 0 auto; padding: 48px 24px 96px; }

/* ---- Landing ---- */
.landing header { margin-bottom: 64px; }
.landing-logo {
  display: block;
  width: 96px; height: 96px;
  border-radius: 22px;
  margin-bottom: 20px;
  box-shadow: 0 4px 18px rgba(0,0,0,0.45);
}
.landing .tagline { font-size: 19px; color: var(--fg-mute); max-width: 620px; margin-bottom: 28px; }
.cta {
  display: inline-block;
  background: var(--accent);
  color: #1a1a1c;
  padding: 12px 22px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 16px;
}
.cta:hover { background: var(--accent-hi); text-decoration: none; }
.cta-ghost { background: transparent; color: var(--accent); border: 1px solid var(--border); margin-left: 8px; }
.cta-ghost:hover { background: var(--bg-elev); color: var(--accent-hi); }

.tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; margin: 32px 0 56px; }
.tiers article { background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px; padding: 22px; }
.tiers .price { color: var(--accent); font-weight: 600; margin: 0 0 12px; }

.why { margin-top: 64px; }
.why ul { list-style: none; padding: 0; }
.why li { padding: 10px 0; border-bottom: 1px solid var(--border); }
.why li:last-child { border-bottom: none; }

.private { margin-top: 64px; padding: 28px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px; }

/* ---- Collections index ---- */
.collections .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin-top: 24px; }
.cc-cover {
  height: 150px; border-radius: 10px; margin: -4px 0 14px;
  background: #1a1a22; background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center; font-size: 44px;
}
.empty { color: var(--fg-mute); font-style: italic; }

/* ---- Collection detail ---- */
.collection .breadcrumb { color: var(--fg-dim); font-size: 14px; margin: 0 0 12px; }
.collection .breadcrumb a { color: var(--fg-mute); }
.collection header { margin-bottom: 32px; }
.collection .blurb { color: var(--fg-mute); }

.episode {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 22px;
  margin-bottom: 16px;
  display: flex;
  gap: 18px;
  align-items: flex-start;
}
.ep-cover {
  flex: 0 0 132px; width: 132px; height: 132px; border-radius: 10px;
  background: #1a1a22; background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center; font-size: 40px;
}
.ep-body { flex: 1 1 auto; min-width: 0; }
.episode header { margin-bottom: 8px; }
.episode h2 { font-size: 22px; margin: 0 0 4px; }
.episode .meta { color: var(--fg-dim); font-size: 14px; margin: 0 0 8px; }
.episode .blurb { color: var(--fg-mute); margin: 0 0 14px; }
.episode audio { width: 100%; display: block; }
@media (max-width: 560px) {
  .episode { flex-direction: column; }
  .ep-cover { width: 100%; height: 180px; flex-basis: auto; }
}

/* ---- Login / forbidden ---- */
.login { max-width: 540px; }
.login p { color: var(--fg-mute); }
.login .cta { margin: 12px 0 24px; }

/* ======================================================================
   3-tab self-serve app (Marketplace / Studio / Collection)
   ====================================================================== */

body.app-body { --maxw: 1180px; }

#app { padding-bottom: 96px; }  /* room for the fixed player bar */

/* ---- app bar ---- */
.app-bar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 22px;
  padding: 12px 26px;
  background: rgba(15,15,16,0.92);
  backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--border);
}
.app-bar .brand {
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 22px; font-weight: 600; color: var(--fg); letter-spacing: -0.01em;
  display: inline-flex; align-items: center; gap: 10px;
}
.brand-logo { width: 28px; height: 28px; border-radius: 7px; display: block; }
.app-bar .brand:hover { color: var(--accent); text-decoration: none; }
.tabs { display: flex; gap: 6px; }
.tab {
  background: transparent; border: none; color: var(--fg-mute);
  font: inherit; font-size: 15px; font-weight: 500;
  padding: 8px 14px; border-radius: 8px; cursor: pointer;
}
.tab:hover { color: var(--fg); background: var(--bg-elev); }
.tab.active { color: #1a1a1c; background: var(--accent); }
/* Mobile hamburger nav — appearance lives here; the responsive show/hide is in
   the BEGIN-MOBILE block (≤640px), so on desktop both stay display:none and the
   inline .tabs strip is used. The dropdown drives the same switchTab() state. */
.hamburger {
  display: none; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0;
  background: transparent; border: 1px solid var(--border);
  border-radius: 9px; color: var(--fg); cursor: pointer; flex: 0 0 auto;
}
.hamburger:hover { border-color: var(--accent); color: var(--accent-hi); }
.hamburger svg { width: 20px; height: 20px; display: block; }
.nav-menu {
  display: none; position: absolute; top: calc(100% + 6px); left: 14px;
  min-width: 210px; z-index: 40;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 12px; padding: 6px; box-shadow: 0 14px 34px rgba(0,0,0,.5);
}
.nav-menu-item {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; color: var(--fg);
  font: inherit; font-size: 16px; font-weight: 500;
  padding: 12px 14px; border-radius: 8px; cursor: pointer;
}
.nav-menu-item:hover { background: var(--bg); color: var(--accent-hi); }
.nav-menu-item.active { color: #1a1a1c; background: var(--accent); }
.nav-menu-sep { height: 1px; margin: 6px 4px; background: var(--border); }
/* Decorative dead-space fret: the gold meander the wordmark's .dm-key bands
   wore until 2026-07-20 (they're laurel branches now — see the wordmark block);
   kept here as page ornament.
   grows (flex:1) to fill the gap between the tabs/brand and the right controls,
   centered vertically. Pure ornament (the markup is aria-hidden). Its flex-grow
   is what pushes .app-bar-right to the edge, so that rule no longer needs
   margin-left:auto (an auto margin would eat the free space first). */
.app-bar-fret {
  flex: 1 1 0; min-width: 0; align-self: center; height: 14px; opacity: .5;
  background-repeat: repeat-x; background-position: center; background-size: 18px 14px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='36' height='28' viewBox='0 0 36 28'><path d='M0 26H36M2 26V2H26V22H10V10H18V16H14' fill='none' stroke='%23f0c27b' stroke-width='2.4'/></svg>");
}
.app-bar-right { display: flex; align-items: center; gap: 16px; font-size: 14px; }
.credits {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--bg-elev-2); border: 1px solid var(--border);
  padding: 5px 11px; border-radius: 999px; color: var(--accent); font-weight: 600;
}
.credits-icon { font-size: 13px; display: inline-flex; }
.credits-icon .ic-credit { width: 13px; height: 13px; }

/* ---- account chip (Google-style avatar + dropdown) ---- */
.acct { position: relative; }
.acct-trigger {
  display: inline-flex; padding: 0; border: none; background: none;
  cursor: pointer; border-radius: 50%; line-height: 0;
}
.acct-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* the circular avatar — initial centered, optional photo overlaid */
.avatar {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; overflow: hidden; flex: none;
  color: #fff; font-weight: 600; text-transform: uppercase; user-select: none;
  background: hsl(var(--avatar-hue, 210) 42% 42%);
}
.avatar-sm { width: 34px; height: 34px; font-size: 15px; }
.avatar-lg { width: 64px; height: 64px; font-size: 27px; }
.acct-trigger .avatar-sm { box-shadow: 0 0 0 1px var(--border); transition: box-shadow .12s; }
.acct-trigger:hover .avatar-sm { box-shadow: 0 0 0 2px var(--accent); }
.avatar-initial { line-height: 1; }
.avatar-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; background: inherit;
}

/* ---- Settings → Profile picture (capsule demades-custom-avatars) ---- */
.avatar-settings { display: flex; flex-wrap: wrap; align-items: center; gap: .9rem; margin: .4rem 0 1rem; }
.avatar-preview {
  width: 72px; height: 72px; border-radius: 50%; object-fit: cover; flex: none;
  background: rgba(127,127,127,.18); box-shadow: 0 0 0 1px var(--border);
}
.avatar-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.avatar-url-input { min-width: 16rem; max-width: 100%; }
.avatar-actions .cta-secondary { background: none; border: 1px solid var(--border); color: inherit; }

/* the dropdown card */
.acct-menu {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 60;
  min-width: 260px; padding: 8px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 14px; box-shadow: 0 14px 40px rgba(0,0,0,0.5);
}
.acct-menu.hidden { display: none; }
.acct-card {
  display: flex; align-items: center; gap: 13px;
  padding: 12px 12px 14px; border-bottom: 1px solid var(--border); margin-bottom: 6px;
}
.acct-id { min-width: 0; }
.acct-name { color: var(--fg); font-weight: 600; font-size: 15px; }
.acct-email {
  color: var(--fg-mute); font-size: 13px; margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 190px;
}
.acct-actions { display: flex; flex-direction: column; }
.acct-action {
  display: block; padding: 9px 12px; border-radius: 8px;
  color: var(--fg); font-size: 14px;
}
.acct-action:hover { background: var(--bg-elev-2); color: var(--fg); text-decoration: none; }
/* rule above the session actions (Switch account / Sign out) */
.acct-sep { height: 1px; margin: 6px 4px; background: var(--border); }

/* ---- panes ---- */
#tab-panes { max-width: var(--maxw); margin: 0 auto; padding: 30px 26px 40px; }
.pane { display: none; }
.pane.active { display: block; }
.pane-head h1 { font-size: 34px; margin-bottom: 6px; }
.pane-head .sub { color: var(--fg-mute); margin-bottom: 20px; }
.muted { color: var(--fg-mute); }
.small { font-size: 13px; }

/* ---- toolbar (search/sort) ---- */
.toolbar { display: flex; gap: 12px; margin: 6px 0 26px; flex-wrap: wrap; }
.search, .select, .input, .textarea {
  background: var(--bg-elev); border: 1px solid var(--border); color: var(--fg);
  border-radius: 9px; padding: 10px 13px; font: inherit; font-size: 15px;
}
.search { flex: 1; min-width: 220px; }
/* Magnifying-glass affordance inside every search field (inline SVG data-URI,
   no extra request). */
.search {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8a93' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 12px center; background-size: 16px;
  padding-left: 38px;
}
/* The marketplace Search field spans the full width (its own row); the dropdown
   filters wrap onto the line below it. */
.filters .search { flex: 1 1 100%; }
.search:focus, .select:focus, .input:focus, .textarea:focus {
  outline: none; border-color: var(--accent);
}
.select { cursor: pointer; }

/* ---- card grid ---- */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; }
.card {
  display: flex; flex-direction: column;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(0,0,0,0.3);
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.card:hover {
  border-color: #3a3a44;
  transform: translateY(-3px);
  box-shadow: 0 12px 30px rgba(0,0,0,0.45);
}
.card-cover {
  font-size: 52px; aspect-ratio: 3 / 2; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #26262f, #17171b);
  border-bottom: 1px solid var(--border);
  position: relative; overflow: hidden;
}
/* Emoji-free cover placeholder: an inline-SVG mic/lock (.cover-ic) and a
   first-letter monogram (.pt-mono) replace the old cover emoji. Both size off
   the container's existing font-size (1em), so they inherit the per-surface
   sizing the emoji used to get. (Sam 2026-06-15: no emoji.) */
.cover-ic { width: 1em; height: 1em; color: var(--fg-mute); opacity: 0.9; }
.pt-mono { font-weight: 600; color: var(--fg-mute); }
/* Inline glyph icons (replace the literal ★ / ▶ / ◈ text marks). Each sizes off
   the surrounding font (1em-ish) so it inherits per-surface sizing. */
.star-ic { width: 1em; height: 1em; color: var(--accent); flex: none; }
.ic-play { width: 0.85em; height: 0.85em; }
.ic-credit { width: 0.92em; height: 0.92em; }
.btn .ic-play, .btn .ic-credit { vertical-align: -0.1em; }
.upload-row .u-icon .ic { width: 1em; height: 1em; vertical-align: middle; color: var(--fg-mute); }
.card-body { padding: 16px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.card-title { font-size: 19px; margin: 0; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.card-rating { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.stars { color: var(--accent); display: inline-flex; align-items: center; gap: 3px; }
.rcount { color: var(--fg-dim); font-size: 13px; }
.card-desc { color: var(--fg-mute); font-size: 14px; margin: 0; flex: 1; }
.card-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip-mini {
  font-size: 12px; color: var(--fg-mute);
  background: var(--bg-elev-2); border: 1px solid var(--border);
  padding: 3px 8px; border-radius: 999px;
}
.card-actions { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
.link-card { color: var(--fg); }
.link-card:hover { text-decoration: none; }
.card-meta-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.card-by { margin-left: auto; }
.cat-tag {
  display: inline-block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--accent); background: var(--bg-elev-2); border: 1px solid var(--border);
  padding: 2px 8px; border-radius: 999px;
}

/* ---- marketplace subtabs ---- */
/* margin-bottom gives the content below the capsule row (Founder's picks shelf,
   the search "Search in" chips) room to breathe — was cramped right under it. */
.subtabs { display: flex; gap: 6px; margin: 14px 0 18px; flex-wrap: wrap; }
.subtab {
  background: var(--bg-elev); border: 1px solid var(--border); color: var(--fg-mute);
  font: inherit; font-size: 14px; font-weight: 500;
  padding: 7px 16px; border-radius: 999px; cursor: pointer;
}
.subtab:hover { color: var(--fg); border-color: #3a3a44; }
.subtab.active { background: var(--accent); color: #1a1a1c; border-color: var(--accent); }
/* Studio's building-block sub-row sits just under the "Create" top tab — pull it
   up so the two levels read as a nested group, not two equal-weight rows. */
.subtabs.studio-subtabs { margin-top: -8px; }
/* Discover is two-level (CL6 entity-first): the OUTER entity strip
   (Episodes | Creators | Shows) sits above the INNER mode strip
   (Recommended | Trending | Categories | Advanced Search). Both reuse
   .subtabs/.subtab; the outer one is heavier and the mode strip pulls up under
   it so the hierarchy reads as a nested group, not two equal rows. */
.subtabs.discover-entities { margin-bottom: 4px; }
.subtabs.discover-entities .subtab { font-weight: 600; }
.subtabs.discover-modes { margin-top: 0; }
.subtabs.discover-modes .subtab { font-size: 13px; padding: 6px 13px; }
.grid-hint { margin: 0 0 14px; }

/* ---- popularity-sized tile grid (categories / creators) ----
   flex-grow lets a bigger flex-basis claim more of the row, so the
   popularity-ordered tiles read big→small top-to-bottom. */
.pop-grid { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; }
.pop-tile {
  display: flex; flex-direction: column; justify-content: center; gap: 6px;
  text-align: left; cursor: pointer;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 16px;
  color: var(--fg); padding: 18px 20px;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.pop-tile:hover { border-color: var(--accent); transform: translateY(-2px); }
.pop-tile .pt-emoji { font-size: 30px; line-height: 1; }
.pop-tile .pt-name { font-family: "Charter", "Iowan Old Style", Georgia, serif; font-weight: 600; letter-spacing: -0.01em; }
.pop-tile .pt-count { color: var(--fg-mute); font-size: 13px; }
.pop-tile .pt-rating { font-size: 13px; }
.pop-tile.xl { flex: 1 1 360px; min-height: 200px; }
.pop-tile.xl .pt-emoji { font-size: 46px; }
.pop-tile.xl .pt-name { font-size: 30px; }
.pop-tile.lg { flex: 1 1 280px; min-height: 162px; }
.pop-tile.lg .pt-emoji { font-size: 38px; }
.pop-tile.lg .pt-name { font-size: 24px; }
.pop-tile.md { flex: 1 1 200px; min-height: 132px; }
.pop-tile.md .pt-name { font-size: 19px; }
.pop-tile.sm { flex: 1 1 150px; min-height: 108px; }
.pop-tile.sm .pt-emoji { font-size: 26px; }
.pop-tile.sm .pt-name { font-size: 16px; }

/* ---- category DAG explorer ---- */
.cat-crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin: 2px 0 12px; font-size: 14px; }
.cat-crumbs .crumb {
  background: transparent; border: none; color: var(--accent); cursor: pointer;
  font: inherit; font-size: 14px; padding: 2px 4px; border-radius: 6px;
}
.cat-crumbs .crumb:hover { color: var(--accent-hi); background: var(--bg-elev); }
.cat-crumbs .crumb:last-of-type { color: var(--fg); font-weight: 600; cursor: default; }
.cat-crumbs .crumb-sep { color: var(--fg-dim); }
.cat-tile { outline: none; justify-content: flex-start; }
.cat-tile:focus-visible { border-color: var(--accent); }
.cat-tile .pt-actions {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: auto; padding-top: 8px;
}
.cat-tile .pt-explore { color: var(--fg-dim); font-size: 13px; white-space: nowrap; }

/* ---- searchable multiselect (studio categories) ---- */
.multiselect { position: relative; }
.ms-control {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px;
  padding: 7px 9px; min-height: 42px;
}
.multiselect:focus-within .ms-control { border-color: var(--accent); }
.ms-chips { display: contents; }
.ms-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-elev-2); border: 1px solid var(--border); border-radius: 999px;
  padding: 3px 6px 3px 10px; font-size: 13px; color: var(--fg);
}
.ms-chip-x {
  background: transparent; border: none; color: var(--fg-mute); cursor: pointer;
  font-size: 16px; line-height: 1; padding: 0 2px;
}
.ms-chip-x:hover { color: var(--accent-hi); }
.ms-input {
  flex: 1; min-width: 140px; background: transparent; border: none; outline: none;
  color: var(--fg); font: inherit; font-size: 15px; padding: 4px 2px;
}
.ms-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 50;
  max-height: 280px; overflow-y: auto;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.45);
}
.ms-option { padding: 9px 13px; cursor: pointer; font-size: 14px; }
.ms-option:hover, .ms-option.active { background: var(--bg-elev-2); color: var(--accent-hi); }
.ms-empty { padding: 10px 13px; }

/* ---- search filter bar ---- */
.filters { display: flex; gap: 10px; margin: 6px 0 24px; flex-wrap: wrap; align-items: center; }
.filters .search { flex: 2 1 240px; }
.filters .select { flex: 1 1 150px; }
/* The length window holds two longer placeholders now ("Minimum length
   (minutes)"); give it more room so the labels are legible. */
.filters .len-range { flex: 1 1 320px; }

/* Advanced-Search category drill-down picker (replaces the flat datalist). */
.cat-picker { position: relative; flex: 1 1 190px; min-width: 0; }
.cat-picker-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 8px; text-align: left;
}
.cat-picker-btn .cat-picker-label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cat-picker-btn .cat-picker-caret { color: var(--fg-dim); flex: 0 0 auto; }
.cat-picker-btn[aria-expanded="true"] { border-color: var(--accent); }
.cat-picker-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 50;
  min-width: 240px; max-height: 320px; overflow-y: auto;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 9px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.45); padding: 6px;
}
.cat-pick-crumbs {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  padding: 4px 6px 8px; font-size: 13px; border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.cat-pick-crumb {
  background: transparent; border: none; color: var(--accent); cursor: pointer;
  font: inherit; font-size: 13px; padding: 2px 5px; border-radius: 6px;
}
.cat-pick-crumb:hover { color: var(--accent-hi); background: var(--bg-elev-2); }
.cat-pick-crumb:last-of-type { color: var(--fg); font-weight: 600; }
.cat-pick-list { display: flex; flex-direction: column; }
.cat-pick-opt {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  background: transparent; border: none; color: var(--fg); cursor: pointer;
  font: inherit; font-size: 14px; padding: 9px 11px; border-radius: 7px;
}
.cat-pick-opt:hover { background: var(--bg-elev-2); color: var(--accent-hi); }
.cat-pick-use { color: var(--fg-mute); font-size: 13px; }
.cat-pick-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-pick-count { flex: 0 0 auto; color: var(--fg-dim); font-size: 12px; font-variant-numeric: tabular-nums; }
.cat-pick-explore { flex: 0 0 auto; color: var(--fg-dim); }
.cat-pick-empty { padding: 10px 11px; }

/* Sort control: a visible "Sort By" label paired with the select. */
.f-sort-wrap { display: inline-flex; align-items: center; gap: 8px; flex: 0 1 240px; min-width: 0; }
.f-sort-label { color: var(--fg-mute); font-size: 14px; white-space: nowrap; flex: 0 0 auto; }
.f-sort-wrap .select { flex: 1 1 auto; }

/* ---- buttons ---- */
.btn {
  background: var(--bg-elev-2); border: 1px solid var(--border); color: var(--fg);
  font: inherit; font-size: 14px; font-weight: 500;
  padding: 9px 14px; border-radius: 9px; cursor: pointer;
}
.btn:hover { border-color: var(--accent); color: var(--accent-hi); }
.btn.primary, .btn.buy { background: var(--accent); color: #1a1a1c; border-color: var(--accent); }
.btn.primary:hover, .btn.buy:hover { background: var(--accent-hi); color: #1a1a1c; }
.btn.play { background: #2b3a2b; border-color: #3c5a3c; color: #d6f5d6; }
.btn.play:hover { background: #34472f; color: #eaffea; }
.btn.ghost { background: transparent; }
.btn.small { padding: 6px 11px; font-size: 13px; }
.btn:disabled { opacity: 0.55; cursor: default; }
/* Sign-in affordances (open lazy-auth): <a> elements styled as buttons. */
a.btn.sign-in { text-decoration: none; display: inline-block; }
.anon-pane { max-width: 460px; margin: 64px auto; text-align: center; display: grid; gap: 14px; justify-items: center; }
.anon-pane .sub { margin: 0; }
/* No-JS / crawler fallback hero in #tab-panes (the SPA owns the panes when JS runs). */
.noscript-hero { max-width: 560px; margin: 64px auto; text-align: center; display: grid; gap: 14px; justify-items: center; padding: 0 16px; }
.noscript-hero h1 { margin: 0; }
.noscript-hero p { margin: 0; }
/* Anonymous conversion hero on the Marketplace home (demades funnel fix
   2026-06-13): leads the signed-out landing with the create-your-own action. */
.anon-hero {
  background: linear-gradient(135deg, var(--bg-elev-2), var(--bg-elev));
  border: 1px solid var(--border); border-radius: 14px;
  padding: 26px 30px; margin: 4px 0 28px;
}
.anon-hero h1 { font-size: 30px; margin: 0 0 8px; }
.anon-hero p { color: var(--fg-mute); max-width: 640px; margin: 0 0 18px; }
.anon-hero p strong { color: var(--accent); }
.anon-hero-cta { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
.anon-hero-note { color: var(--fg-dim); font-size: 14px; }
@media (max-width: 560px) {
  .anon-hero { padding: 22px 20px; }
  .anon-hero h1 { font-size: 25px; }
}
/* When the anon conversion hero owns the page's single H1, the Marketplace block
   below it demotes to a secondary section — a thin divider + smaller heading —
   so the signed-out front door has ONE focal point, not two competing H1s. */
.pane-head.mkt-secondary { border-top: 1px solid var(--border); padding-top: 24px; margin-top: 8px; }
.pane-head.mkt-secondary h2 { font-size: 24px; margin: 0 0 4px; }
.badge { font-size: 13px; color: var(--fg-dim); padding: 6px 10px; }
.badge.proc { color: var(--accent); }
.badge.err { color: #f0a0a0; }
.badge.free { color: var(--accent); font-weight: 600; padding: 0; } /* Free-to-play shelf cards */

/* ---- studio ---- */
.studio-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 26px; align-items: start; }
.studio-form { display: flex; flex-direction: column; gap: 16px; }
.field { display: flex; flex-direction: column; gap: 7px; }
.field > span { font-size: 14px; color: var(--fg-mute); font-weight: 500; }
.field small { color: var(--fg-dim); font-weight: 400; }
.emoji {
  font-size: 22px; width: 44px; height: 44px; border-radius: 10px;
  background: var(--bg-elev); border: 1px solid var(--border); cursor: pointer;
}
.emoji.on { border-color: var(--accent); background: var(--bg-elev-2); }
.persona {
  text-align: left; display: flex; flex-direction: column; gap: 2px;
  background: var(--bg-elev); border: 1px solid var(--border); color: var(--fg);
  border-radius: 11px; padding: 11px 13px; cursor: pointer;
}
.persona:hover { border-color: #3a3a44; }
.persona.on { border-color: var(--accent); background: var(--bg-elev-2); }
.persona .p-emoji { font-size: 20px; }
.persona .p-name { font-weight: 600; font-size: 14px; }
.persona .p-role { font-size: 12px; color: var(--fg-dim); }

/* checkboxes (research toggles) */
.check { display: flex; align-items: center; gap: 9px; cursor: pointer; color: var(--fg); font-size: 14px; }
.check input[type="checkbox"], .check input[type="radio"] { width: 17px; height: 17px; accent-color: var(--accent); cursor: pointer; }

/* progressive-disclosure "Research sources" control (Studio Create form) */
.research-disclosure > summary {
  font-size: 14px; color: var(--fg-mute); font-weight: 500; cursor: pointer;
  list-style-position: inside; user-select: none;
}
.research-disclosure > summary:hover { color: var(--fg); }
.research-disclosure > summary small { color: var(--fg-dim); font-weight: 400; }
.research-disclosure[open] > summary { margin-bottom: 9px; }
/* Setting `display` on a direct <details> child overrides the UA's
   closed-content hiding, so hide the body explicitly while collapsed —
   otherwise the tiers render even though the disclosure reads closed. */
.research-disclosure:not([open]) .research-body { display: none; }
.research-body { display: flex; flex-direction: column; gap: 9px; }
.research-tiers { display: flex; flex-direction: column; gap: 7px; }

/* configurable hosts editor */
.hosts-editor { display: flex; flex-direction: column; gap: 12px; }
.host-row {
  display: flex; flex-direction: column; gap: 7px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 11px; padding: 11px 12px;
}
.host-line { display: flex; gap: 8px; align-items: center; }
.host-line .h-name { flex: 1; min-width: 0; }
.host-line .h-del { flex: none; }
/* Three orthogonal voice dropdowns (tone / nationality / gender). */
.host-voice { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.host-voice .select { flex: 1 1 110px; min-width: 0; }
/* ▶ voice-sample preview button: fixed width so it never stretches like a select. */
.host-voice .h-play { flex: 0 0 auto; }
.host-voice .h-play.playing { color: var(--accent, #1f6feb); border-color: var(--accent, #1f6feb); }
.host-row .h-bio { width: 100%; }

/* Studio "Saved hosts" subtab — saved hosts + cast presets. */
.presets h3 { font-size: 16px; margin: 0 0 8px; }
.preset-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.preset-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.preset-meta strong { font-size: 15px; }
.preset-meta .small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.preset-actions { display: flex; gap: 6px; flex: 0 0 auto; }
#s-add-host { align-self: flex-start; }

/* reference-file uploads */
.uploads { display: flex; flex-direction: column; gap: 8px; margin-bottom: 4px; }
.upload-row {
  display: flex; align-items: center; gap: 9px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 10px; padding: 7px 11px;
}
.upload-row .u-icon { font-size: 16px; }
.upload-row .u-name { flex: 1; min-width: 0; padding: 6px 10px; font-size: 14px; }
.upload-row .u-size { flex: none; white-space: nowrap; }
.upload-btn { align-self: flex-start; display: inline-block; }

.recent-list { display: flex; flex-direction: column; gap: 8px; }

/* ---- collection ---- */
.col-list { display: flex; flex-direction: column; gap: 10px; }
.col-section { margin-top: 40px; }

/* ---- player bar ---- */
.player {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: grid;
  /* minmax(0, …) lets the flexible columns shrink below their content's
     intrinsic width so a long title ellipsizes instead of overflowing into
     (colliding with) the playback controls on narrow-desktop widths. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 2fr) auto;
  align-items: center; gap: 18px;
  padding: 12px 26px;
  background: rgba(24,24,27,0.97);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--border);
}
.player.hidden { display: none; }
.player-meta { display: flex; align-items: center; gap: 12px; min-width: 0; }
.player-cover { font-size: 30px; }
.player-titles { min-width: 0; }
/* Title: clips with an ellipsis at rest; on hover, if it overflows, the inner
   span marquees the full text into view (and a native tooltip carries the whole
   title). The grid's minmax(0,1fr) guarantees it never collides with controls. */
.player-title { font-weight: 600; white-space: nowrap; overflow: hidden; display: block; }
.player-title .pt-inner {
  display: inline-block; max-width: 100%; vertical-align: bottom;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.player-title.marquee:hover .pt-inner {
  max-width: none; overflow: visible; text-overflow: clip;
  animation: pt-marquee var(--pt-dur, 8s) ease-in-out infinite alternate;
}
@keyframes pt-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(var(--pt-shift, 0)); }
}
.player-sub { font-size: 13px; color: var(--fg-dim); }
.player-controls { display: flex; align-items: center; gap: 6px; }
.player-extra { display: flex; align-items: center; gap: 6px; }
/* Thin vertical rule separating the podcast-specific controls (speed / rate /
   share / comments / download / sleep-timer / transcript) from the far-right
   "Now Playing view" toggle (Sam 2026-06-18). Neutral --border tone.
   `order: 2` + the rail toggle's `order: 3` force this pair to the FAR RIGHT
   regardless of DOM insertion order — other player_*.js feature modules
   (player_utilities sleep-timer, player_transcript) appendChild to .player-extra
   AFTER the rail module runs, so without an explicit order they'd land to the
   right of the toggle. `margin-left: auto` pushes the whole group to the edge. */
.player-extra-divider {
  width: 1px; align-self: stretch; min-height: 22px;
  margin: 0 6px 0 auto; background: var(--border); flex: 0 0 auto;
  order: 2;
}
#rail-toggle.pbtn-rail { order: 3; }
.pbtn {
  background: transparent; border: none; color: var(--fg);
  font-size: 18px; cursor: pointer; width: 38px; height: 38px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
.pbtn:hover { background: var(--bg-elev-2); color: var(--accent); text-decoration: none; }
/* The headline control: the original golden button — a solid gold accent fill
   with a dark glyph at the same 38px as the flanking back-15 / fwd-30 .pbtn
   twins (Sam 2026-07-05, reverting the 2026-07-04 bigger+blue changes). Kept
   in sync with the Expo player-bar `pbtnMain` (tokens.accent, dark icon) —
   both surfaces are intentional twins. */
.pbtn-main { background: var(--accent); color: #1a1a1c; font-size: 16px; }
.pbtn-main:hover { background: var(--accent-hi); color: #1a1a1c; }
.pbtn-rate { width: auto; padding: 0 10px; font-size: 13px; font-weight: 600; border: 1px solid var(--border); border-radius: 8px; }
.player-seek { display: flex; align-items: center; gap: 10px; }
.ptime { font-size: 12px; color: var(--fg-dim); font-variant-numeric: tabular-nums; min-width: 36px; text-align: center; }
.seek { flex: 1; accent-color: var(--accent); cursor: pointer; }

/* Crisp SVG glyphs replace the old emoji controls (snappier, theme-aware). */
.pbtn .ic { width: 20px; height: 20px; display: block; }
.pbtn-main .ic { width: 22px; height: 22px; }

/* Clickable episode title in the player bar → its public /e/<slug> page. */
a.player-title { color: inherit; text-decoration: none; }
.player-title.is-link { cursor: pointer; }
.player-title.is-link:hover { color: var(--accent); text-decoration: underline; }

/* Per-episode rating: ★ button in the player bar + its star-pick popover. */
.pbtn-star { font-size: 19px; line-height: 1; }
.pbtn-star.rated { color: var(--accent); }
.ep-star-pick { display: flex; gap: 2px; padding: 4px 6px; }
.ep-star {
  background: transparent; border: none; cursor: pointer; padding: 0 2px;
  font-size: 22px; line-height: 1; color: var(--fg-dim);
}
.ep-star.on { color: var(--accent); }
.ep-star:hover { color: var(--accent-hi); }

/* Episode-title deep-links inside cards / shelves / rows. Stay visually a
   heading; reveal link affordance on hover. */
.ep-link { color: inherit; text-decoration: none; cursor: pointer; }
.ep-link:hover { color: var(--accent); text-decoration: underline; }

/* ---- playback-speed popover (presets + free-form slider) ---- */
.rate-wrap { position: relative; display: inline-flex; }
.rate-pop {
  position: absolute; bottom: calc(100% + 10px); right: 0; z-index: 50;
  width: 220px; padding: 12px;
  background: var(--bg-elev-2, #2a2a2e);
  border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
}
.rate-pop.hidden { display: none; }
.rate-presets { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.rate-preset {
  flex: 1 0 28%; padding: 6px 0; font-size: 13px; font-weight: 600;
  background: transparent; color: var(--fg);
  border: 1px solid var(--border); border-radius: 8px; cursor: pointer;
}
.rate-preset:hover { border-color: var(--accent); color: var(--accent); }
.rate-preset.on { background: var(--accent); color: #1a1a1c; border-color: var(--accent); }
.rate-slider-row { display: flex; align-items: center; gap: 10px; }
.rate-slider { flex: 1; accent-color: var(--accent); cursor: pointer; }
.rate-val { font-size: 12px; font-weight: 600; color: var(--fg-dim); font-variant-numeric: tabular-nums; min-width: 44px; text-align: right; }

/* ---- player utilities: sleep timer + smart speed (capsule demades-player-ux-upgrade) ---- */
.pbtn-util { position: relative; font-size: 16px; }
.pbtn-util.on { color: var(--accent); }
.util-badge {
  position: absolute; bottom: -1px; right: -1px;
  background: var(--accent); color: #1a1a1c;
  font-size: 9px; font-weight: 700; line-height: 1;
  min-width: 13px; padding: 1px 2px; border-radius: 7px; text-align: center;
}
.util-badge.hidden { display: none; }
.util-pop { width: 168px; }
.util-pop-title { font-size: 12px; font-weight: 600; color: var(--fg-dim); margin-bottom: 8px; }
.util-opts { display: flex; flex-direction: column; gap: 4px; }
.util-opt {
  text-align: left; padding: 6px 8px; font-size: 13px;
  background: transparent; color: var(--fg);
  border: 1px solid transparent; border-radius: 8px; cursor: pointer;
}
.util-opt:hover { border-color: var(--accent); color: var(--accent); }
.util-opt.on { background: var(--accent); color: #1a1a1c; border-color: var(--accent); }

/* ---- in-player synced transcript panel (capsule demades-player-ux-upgrade) ---- */
.tx-panel {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 88px; z-index: 45;
  width: min(760px, calc(100vw - 32px)); max-height: 48vh;
  display: flex; flex-direction: column;
  background: var(--bg-elev-2, #1f1f24); border: 1px solid var(--border);
  border-radius: 14px; box-shadow: 0 14px 40px rgba(0,0,0,0.5); overflow: hidden;
}
.tx-panel.hidden { display: none; }
.tx-head {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border-bottom: 1px solid var(--border); flex: 0 0 auto;
}
.tx-title { font-weight: 600; font-size: 14px; white-space: nowrap; }
.tx-chapters { display: flex; gap: 6px; overflow-x: auto; flex: 1; padding-bottom: 2px; }
.tx-chip {
  flex: 0 0 auto; max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 4px 9px; font-size: 12px; background: transparent; color: var(--fg-mute);
  border: 1px solid var(--border); border-radius: 999px; cursor: pointer;
}
.tx-chip:hover { border-color: var(--accent); color: var(--accent); }
.tx-lang {
  flex: 0 0 auto; max-width: 170px; padding: 4px 8px; font-size: 12px; cursor: pointer;
  background: var(--bg-elev); color: var(--fg); border: 1px solid var(--border); border-radius: 8px;
}
.tx-lang:hover { border-color: var(--accent); }
.tx-close { background: transparent; border: none; color: var(--fg-mute); font-size: 22px; line-height: 1; cursor: pointer; flex: 0 0 auto; }
.tx-close:hover { color: var(--fg); }
.tx-xlate { color: var(--accent); background: rgba(240,194,123,0.06); }
.tx-note { padding: 8px 14px; font-size: 12px; color: var(--accent-hi); background: rgba(240,194,123,0.08); }
.tx-note.hidden { display: none; }
.tx-body { overflow-y: auto; padding: 8px 6px; flex: 1 1 auto; }
.tx-line {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: none; border-radius: 8px;
  padding: 7px 10px; margin: 1px 0; color: var(--fg-mute); font-size: 14px; line-height: 1.5;
}
.tx-line:hover { background: var(--bg-elev); color: var(--fg); }
.tx-line.active { background: rgba(240,194,123,0.14); color: var(--fg); }
.tx-speaker { font-weight: 700; color: var(--accent); margin-right: 7px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
.tx-empty { color: var(--fg-dim); font-size: 14px; padding: 16px; text-align: center; }

/* ---- fact footnotes (capsule demades-fact-footnotes) ---- */
.tx-fn { margin-left: 3px; line-height: 0; }
.tx-fn-mark {
  background: transparent; border: none; cursor: pointer; padding: 0 1px;
  color: var(--accent); font-size: 10px; font-weight: 700; vertical-align: super;
}
.tx-fn-mark:hover { color: var(--accent-hi); text-decoration: underline; }
.tx-sources { border-top: 1px solid var(--border); margin-top: 12px; padding: 10px 10px 4px; }
.tx-sources-title {
  font-weight: 700; color: var(--accent); font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 6px;
}
.tx-source { display: flex; gap: 7px; padding: 3px 0; font-size: 12.5px; color: var(--fg-mute); line-height: 1.5; }
.tx-source-num { flex: 0 0 auto; font-weight: 700; color: var(--accent); }
.tx-source-body em { color: var(--fg-dim); font-style: italic; }
.tx-source-body a { color: var(--accent); text-decoration: none; }
.tx-source-body a:hover { text-decoration: underline; }

/* ---- bookmarks popover (capsule demades-player-ux-upgrade) ---- */
.bm-pop { width: 260px; }
.bm-add { display: flex; gap: 6px; margin-bottom: 8px; }
.bm-note {
  flex: 1; min-width: 0; padding: 6px 8px; font-size: 12px;
  background: var(--bg-elev); color: var(--fg);
  border: 1px solid var(--border); border-radius: 8px;
}
.bm-add-btn {
  flex: 0 0 auto; white-space: nowrap; padding: 6px 9px; font-size: 12px; font-weight: 600;
  background: var(--accent); color: #1a1a1c; border: none; border-radius: 8px; cursor: pointer;
}
.bm-add-btn:disabled { opacity: 0.5; cursor: default; }
.bm-list { display: flex; flex-direction: column; gap: 3px; max-height: 220px; overflow-y: auto; }
.bm-empty { color: var(--fg-dim); font-size: 12px; padding: 8px 2px; margin: 0; }
.bm-row { display: flex; align-items: center; gap: 4px; }
.bm-jump {
  flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px; text-align: left;
  background: transparent; color: var(--fg); border: none; border-radius: 6px;
  padding: 5px 7px; cursor: pointer; font-size: 13px;
}
.bm-jump:hover { background: var(--bg-elev); }
.bm-time { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.bm-label { color: var(--fg-mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bm-share, .bm-del {
  flex: 0 0 auto; background: transparent; border: none; color: var(--fg-dim);
  cursor: pointer; font-size: 14px; line-height: 1; padding: 4px 5px; border-radius: 6px;
}
.bm-share:hover, .bm-del:hover { color: var(--accent); background: var(--bg-elev); }
.bm-share:disabled { opacity: 0.35; cursor: default; }
.bm-share .ic { width: 15px; height: 15px; display: block; }
.bm-del { font-size: 18px; }

/* ---- waveform scrubber (capsule demades-player-ux-upgrade) ---- */
/* The canvas sits behind the existing range input (the interaction layer stays
   the input); when present, the input's own track goes transparent so the
   waveform shows through while the thumb stays visible. Cosmetic + optional. */
.wave-wrap { position: relative; flex: 1; display: flex; align-items: center; min-width: 0; }
.wave-wrap .seek { width: 100%; flex: 1; }
.wave-canvas { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); pointer-events: none; z-index: 1; }
.wave-canvas.hidden { display: none; }
.seek.has-wave { position: relative; z-index: 2; background: transparent; }
.seek.has-wave::-webkit-slider-runnable-track { background: transparent; }
.seek.has-wave::-moz-range-track { background: transparent; }
/* The playhead is now the NEUTRAL vertical bar drawn on the waveform canvas
   (player_waveform.js), perfectly synced to the played/unplayed boundary. Hide
   ALL native range chrome so only the synced bar shows. `appearance: none` is
   load-bearing: without it Chrome keeps rendering the native slider (the round
   thumb — the "black dot" — and the accent-filled track portion — the "filled
   line") on top of the canvas at z-index 2, and `accent-color: transparent` is
   NOT reliably honored to hide them (Sam 2026-06-19). The input stays the
   interaction layer — full-height/transparent thumb keeps click+drag seeking
   working across the whole track. */
.seek.has-wave { -webkit-appearance: none; appearance: none; accent-color: transparent; height: 28px; }
.seek.has-wave::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 1px; height: 28px; background: transparent; border: none; cursor: pointer;
}
.seek.has-wave::-moz-range-thumb {
  width: 1px; height: 28px; background: transparent; border: none; cursor: pointer;
}

/* ---- modal ---- */
.modal-overlay {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(0,0,0,0.6); display: none; align-items: center; justify-content: center;
  padding: 24px;
}
.modal-overlay.open { display: flex; }
/* Consent confirm dialog — stacks ABOVE the settings/credits modal. */
.confirm-overlay { z-index: 65; }
.confirm-modal { max-width: 420px; }
.confirm-modal h3 { margin: 0 0 6px; }
.confirm-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
.modal {
  position: relative; background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 16px; max-width: 560px; width: 100%; max-height: 86vh; overflow-y: auto;
  padding: 26px;
}
.modal-close {
  position: absolute; top: 14px; right: 16px; background: transparent; border: none;
  color: var(--fg-mute); font-size: 26px; cursor: pointer; line-height: 1;
}
.modal-close:hover { color: var(--fg); }
.modal-head { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.modal-cover { font-size: 44px; }
.modal-head h2 { margin: 0 0 4px; }
.modal-actions { margin: 18px 0; display: flex; gap: 10px; }
.rate-box { border-top: 1px solid var(--border); padding-top: 16px; margin-top: 10px; }
.rate-box .textarea { width: 100%; margin: 8px 0; }
.star-pick button {
  background: transparent; border: none; font-size: 26px; color: var(--fg-dim); cursor: pointer;
}
.star-pick button.on { color: var(--accent); }
.reviews { list-style: none; padding: 0; }
.reviews li { padding: 10px 0; border-bottom: 1px solid var(--border); }
.reviews li:last-child { border-bottom: none; }
.reviews .rv-who { color: var(--fg-dim); font-size: 13px; margin-left: 8px; }
.reviews p { margin: 4px 0 0; color: var(--fg-mute); font-size: 14px; }

/* ---- feedback modal ---- */
.feedback-modal h2 { margin: 0 0 6px; }
.fb-stars { display: flex; align-items: center; gap: 4px; margin: 12px 0 6px; }
.fb-star {
  background: transparent; border: none; font-size: 28px; color: var(--fg-dim);
  cursor: pointer; line-height: 1; padding: 0 2px;
}
.fb-star:hover, .fb-star.on { color: var(--accent); }
.fb-stars-hint { margin-left: 8px; }
.fb-message { width: 100%; margin: 8px 0 4px; resize: vertical; min-height: 96px; }
.fb-actions { margin: 14px 0 8px; display: flex; gap: 10px; }
/* Header "Feedback" button — quiet ghost. Stays a text label at every width
   (short enough not to crowd the chip); no emoji fallback. */
.feedback-btn { white-space: nowrap; }
@media (max-width: 560px) {
  .feedback-btn { padding: 8px 10px; }
  .help-btn { padding: 8px 10px; }
}

/* ---- help / "what is Demades?" modal ---- */
.help-btn { white-space: nowrap; }
.help-modal .modal-title { margin: 0 0 6px; }
.help-areas { margin-top: 18px; display: flex; flex-direction: column; gap: 14px; }
.help-area {
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-elev-2);
}
.help-area h3 { margin: 0 0 4px; font-size: 15px; color: var(--accent); }
.help-area p { margin: 0; color: var(--fg-mute); font-size: 14px; line-height: 1.5; }

/* ---- episode comments modal ---- */
.comments-modal h2 { margin: 0 0 6px; }
.comments-modal #cmt-body { width: 100%; margin: 8px 0 4px; resize: vertical; }
#cmt-list { margin-top: 10px; max-height: 50vh; overflow-y: auto; }
.cmt-item { padding: 8px 0; border-top: 1px solid var(--line, rgba(127,127,127,.25)); }
.cmt-who { font-weight: 600; }
.cmt-when { margin-left: 8px; }
.cmt-del {
  background: transparent; border: none; cursor: pointer;
  margin-left: 8px; color: var(--fg-dim);
}
.cmt-del:hover { color: var(--accent); }
.cmt-body { margin: 4px 0 0; color: var(--fg-mute); font-size: 14px; white-space: pre-wrap; }

/* ---- toast ---- */
.toast {
  position: fixed; bottom: 110px; left: 50%; transform: translateX(-50%);
  z-index: 70; background: var(--bg-elev-2); border: 1px solid var(--border);
  color: var(--fg); padding: 12px 20px; border-radius: 10px; font-size: 14px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.4);
}
.toast.hidden { display: none; }
.toast.ok { border-color: #3c5a3c; }
.toast.err { border-color: #6a3a3a; color: #f4caca; }

/* ---- credits modal (badge button, sparkline, packs, ledger timeline) ---- */
button.credits { cursor: pointer; font: inherit; transition: border-color .12s, background .12s; }
button.credits:hover { border-color: var(--accent); background: var(--bg-elev); }
.credits.low { color: #e8b04b; border-color: #6a5a2a; }   /* low-balance amber nudge */
.credits-hero { text-align: center; margin: 4px 0 18px; }
.credits-hero-num { font-size: 36px; font-weight: 700; color: var(--accent); letter-spacing: -0.01em; }
.spark { display: block; width: 100%; height: 56px; margin-top: 12px; color: var(--accent); opacity: 0.85; }
.packs-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(108px, 1fr)); gap: 10px; margin: 10px 0 18px; }
.pack {
  display: flex; flex-direction: column; gap: 4px; align-items: center;
  padding: 12px 8px; background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: 12px; color: var(--fg); cursor: pointer; font: inherit;
}
.pack:hover:not(:disabled) { border-color: var(--accent); }
.pack:disabled { opacity: 0.5; cursor: not-allowed; }
.pack-credits { font-weight: 700; color: var(--accent); }
.pack-price { font-size: 15px; }
.pack-bonus { font-size: 11px; color: #7fc97f; font-weight: 600; }
.pack-bonus.base { color: var(--fg-dim); font-weight: 400; }
.gift-row { display: flex; gap: 8px; margin: 10px 0 18px; }
.gift-row #gift-email { flex: 2; min-width: 0; }
.gift-row #gift-amount { flex: 1; min-width: 0; }
.ledger { list-style: none; padding: 0; margin: 8px 0 0; }
.ledger-row {
  display: grid; grid-template-columns: minmax(0,1fr) auto auto auto;
  gap: 10px; align-items: center; padding: 9px 0;
  border-bottom: 1px solid var(--border); font-size: 14px;
}
.ledger-when { white-space: nowrap; }
.ledger-row:last-child { border-bottom: none; }
.ledger-what { display: flex; flex-direction: column; min-width: 0; }
.ledger-what small { color: var(--fg-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ledger-when { color: var(--fg-dim); font-size: 12px; }
.ledger-delta { font-variant-numeric: tabular-nums; }
.ledger-delta.pos { color: #7fc97f; font-weight: 600; }
.ledger-delta.neg { color: #e08585; font-weight: 600; }
.ledger-bal { color: var(--fg-dim); font-variant-numeric: tabular-nums; font-size: 12px; }

@media (max-width: 760px) {
  .studio-grid { grid-template-columns: 1fr; }
  .player { grid-template-columns: 1fr auto; gap: 10px; }
  .player-seek, .player-extra { display: none; }
  .app-bar-right .who { display: none; }
}

/* ---- Public episode page (un-gated /e/<slug>, /discover, /topic) -------- */
/* Server-rendered standalone pages — no app shell. Match the dark editorial
   look; readable measure for the transcript (the SEO body text). */
.public-episode { background: var(--bg); }
.public-ep { max-width: 760px; margin: 0 auto; padding: 56px 24px 96px; }
.public-ep .kicker {
  text-transform: uppercase; letter-spacing: 0.12em; font-size: 13px;
  color: var(--accent); font-weight: 600; margin: 0 0 10px;
}
.public-ep h1 { font-size: 38px; line-height: 1.15; margin: 0 0 12px; }
.public-ep .ep-meta { color: var(--fg-dim); font-size: 14px; margin: 0 0 14px; }
.public-ep .ep-cover {
  display: block; width: 100%; height: auto; max-height: 420px;
  object-fit: cover; border-radius: 14px; margin: 6px 0 18px;
}
/* WARNING: the bare `.ep-desc` below is the APP's clamped card summary
   (`-webkit-line-clamp: 2`) and a bare class selector doesn't care that this
   one is the public page's full description — the same app/public class
   collision as `.ep-more` (see docs/public-pages.md). Un-box it here so the
   whole description shows (Sam, 2026-08-01: summaries were cut off with an
   ellipsis). */
.public-ep .ep-desc {
  font-size: 18px; color: var(--fg-mute); margin: 0 0 22px;
  display: block; -webkit-line-clamp: unset; overflow: visible;
}
/* #ep-audio is a <video> for the mp4-bearing media (animation / video), so the
   player rule covers both tags — otherwise a Seedance episode renders an
   unstyled, intrinsically-sized video box. */
.public-ep audio, .public-ep video { width: 100%; margin: 8px 0 20px; }
.public-ep video { background: #000; border-radius: 14px; }
.public-ep h2 { font-size: 22px; margin: 40px 0 16px; }

/* Cross-topic internal-linking rail on /topic/<slug> hubs (de-islanding).
   A subtle top divider sets it apart from the episode grid above; the heading
   inherits `.public-ep h2` and the chips reuse `.topic-chips`/`.topic-chip`. */
.explore-topics { margin: 40px 0 8px; padding-top: 24px; border-top: 1px solid var(--border); }
.explore-topics h2 { margin-top: 0; }
.topic-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }
.topic-chip {
  display: inline-block; padding: 4px 12px; border-radius: 999px;
  background: var(--bg-elev); border: 1px solid var(--border);
  color: var(--fg-mute); font-size: 13px;
}
.topic-chip:hover { border-color: var(--accent); color: var(--accent-hi); text-decoration: none; }

.share-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 8px; }
.share-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0; border-radius: 50%;
  background: var(--bg-elev); border: 1px solid var(--border);
  color: var(--fg-mute); cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s, transform 0.15s;
}
.share-btn svg { width: 18px; height: 18px; display: block; }
.share-btn:hover { text-decoration: none; transform: translateY(-2px); color: #fff; }
.share-x:hover { background: #000; border-color: #444; }
.share-linkedin:hover { background: #0a66c2; border-color: #0a66c2; }
.share-reddit:hover { background: #ff4500; border-color: #ff4500; }
.share-copy:hover { background: var(--accent); border-color: var(--accent); }
.share-native:hover { background: var(--accent); border-color: var(--accent); }
/* Copy-link feedback: swap the chain icon for a checkmark while .copied. The
   native-share button reuses the same swap for its copy fallback. */
.share-copy .ic-check, .share-native .ic-check { display: none; }
.share-copy.copied .ic-link, .share-native.copied .ic-share { display: none; }
.share-copy.copied .ic-check, .share-native.copied .ic-check { display: block; color: #4ade80; }
.share-copy.copied, .share-native.copied { border-color: #4ade80; }

.transcript .turn { margin: 0 0 18px; }
.transcript .who {
  display: block; font-weight: 600; color: var(--accent);
  font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 3px;
}
.transcript .turn p { margin: 0; color: var(--fg); line-height: 1.6; }
.transcript-empty .muted { color: var(--fg-dim); font-style: italic; }
/* Paid public-preview surfaces (capsule demades-distribution-model). */
.public-ep .preview-note { color: var(--fg-dim); font-size: 13px; margin: -12px 0 18px; }
.public-ep .transcript-cut { margin: 22px 0 0; font-style: italic; text-align: center; }
.buy-cta {
  margin: 8px 0 26px; padding: 20px 22px; border-radius: 14px;
  background: var(--surface, rgba(255,255,255,0.04)); border: 1px solid var(--border, rgba(255,255,255,0.1));
}
.buy-cta p { margin: 0 0 12px; color: var(--fg); }
.buy-cta .buy-btn {
  display: inline-block; padding: 10px 18px; border-radius: 999px;
  background: var(--accent); color: #fff; font-weight: 600; text-decoration: none;
}
/* Distribution modal (capsule demades-distribution-model). */
.dist-opts { display: flex; flex-direction: column; gap: 10px; margin: 14px 0; }
.dist-opt { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.dist-opt input { margin-top: 4px; }
.dist-paid { margin: 6px 0 4px; padding-left: 26px; }
.dist-paid.hidden { display: none; }
.dist-preview { display: flex; gap: 8px; align-items: center; font-size: 14px; margin-top: 8px; }

.related .rel-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}
.rel-card {
  display: flex; flex-direction: column; gap: 6px; padding: 16px;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px;
  color: var(--fg);
}
.rel-card:hover { border-color: var(--accent); text-decoration: none; }
/* Square cover thumbnail: the real episode art (.rel-cover-img) overlays the
   inline mic SVG fallback (.cover-ic), which shows through when the img 404s
   and removes itself (onerror). font-size sizes the fallback glyph. */
.rel-cover {
  position: relative; width: 100%; aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px; overflow: hidden; background: var(--bg); font-size: 28px;
}
.rel-cover-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.rel-title { font-weight: 600; line-height: 1.25; }
.rel-sub { font-size: 13px; }
/* Listen-count social proof on an episode card (capsule
   demades-public-listen-counts). Rendered only past the badge threshold, and
   `margin-top:auto` pins it to the bottom of the flex card so a two-line title
   in one card can't shove its neighbour's count out of alignment. Smaller than
   .rel-sub: it's supporting evidence, not the pitch. */
.rel-listens { font-size: 12px; margin-top: auto; letter-spacing: 0.01em; }

.made-with { margin-top: 56px; padding-top: 24px; border-top: 1px solid var(--border); color: var(--fg-mute); }
.public-index .rel-grid { margin-top: 8px; }

/* Play-next continuation card, revealed at the /e player on `ended`: a one-tap
   continuation at the player — the "More from Demades" rail sits far below the
   fold. Hidden until `ended` via the native [hidden] attribute (no CSS needed
   for that). */
.play-next { margin: 14px 0 4px; }
.play-next .pn-label { display: block; font-size: 13px; color: var(--fg-mute); margin-bottom: 6px; text-transform: uppercase; letter-spacing: .04em; }
.pn-card {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px; color: var(--fg);
}
.pn-card:hover { border-color: var(--accent); text-decoration: none; }
.pn-title { font-weight: 600; flex: 1; line-height: 1.3; }
.pn-go { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 50%; background: var(--accent); color: var(--bg); flex: none; }

/* De-islanding header on every public page (brand → home, Discover, app CTA). */
.pub-nav {
  position: sticky; top: 0; z-index: 20;
  background: var(--bg); border-bottom: 1px solid var(--border);
}
.pub-nav-inner {
  max-width: 760px; margin: 0 auto; padding: 12px 24px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.pub-brand {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 700; color: var(--fg);
}
.pub-brand img { border-radius: 6px; display: block; }
.pub-brand:hover { color: var(--accent-hi); text-decoration: none; }
.pub-nav-links { display: inline-flex; align-items: center; gap: 16px; }
.pub-nav-links a { color: var(--fg-mute); font-size: 14px; }
.pub-nav-links a:hover { color: var(--fg); text-decoration: none; }
.pub-nav-cta {
  padding: 7px 14px; border-radius: 999px;
  /* Black label on the gold pill (Sam, 2026-07-02 — "/try 'Go to main site'
     should be black text"); matches the app's primary-button fg #1a1a1c. */
  background: var(--accent); color: #1a1a1c !important; font-weight: 600;
}
.pub-nav-cta:hover { filter: brightness(1.1); }
.public-ep .kicker a { color: inherit; }

/* Mid-page "make your own" conversion band on free public episodes. */
.make-own {
  margin: 18px 0 26px; padding: 18px 22px; border-radius: 14px;
  background: var(--bg-elev); border: 1px solid var(--border);
}
.make-own p { margin: 0 0 12px; color: var(--fg); }
.make-own .make-own-actions {
  margin: 0; display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
}
.make-own .buy-btn {
  display: inline-block; padding: 10px 18px; border-radius: 999px;
  background: var(--accent); color: #fff; font-weight: 600; text-decoration: none;
}
.make-own-browse { color: var(--fg-mute); font-size: 14px; }

/* Metrics consent settings page (SCALING §6.9) */
.settings { max-width: 640px; margin: 48px auto; padding: 0 20px; }
.settings h1 { margin-bottom: 8px; }
.settings-lede { color: var(--text-dim); line-height: 1.5; margin-bottom: 24px; }
.consent { display: flex; flex-direction: column; gap: 14px; }
.consent-row { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.consent-row input { margin-top: 3px; }
.consent-required { color: var(--text-dim); cursor: not-allowed; }
.consent-required em { font-style: normal; opacity: 0.8; }
.consent .cta { align-self: flex-start; margin-top: 8px; }
.consent-status { color: var(--text-dim); font-size: 0.9em; margin-left: 10px; }
/* Point-of-sale terms-assent gate (credits modal, plan settings, landing). */
.buy-consent { font-size: 13px; color: var(--fg-mute); margin: 4px 0 12px; }
.tier-consent { max-width: 640px; margin: 0 auto 28px; font-size: 13px; }
.tier-fineprint { color: var(--fg-mute); font-size: 12px; margin: 8px 0 0; }
.consent-error { color: var(--danger, #d9534f); font-weight: 600; }
.settings-note { color: var(--text-dim); font-size: 0.9em; margin-top: 24px; line-height: 1.5; }

/* ── Invite-a-friend referral card (capsule demades-referral-program) ──────── */
.referral-card { margin-top: 8px; }
.referral-linkrow { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.referral-link {
  flex: 1 1 240px; min-width: 0; padding: 9px 12px;
  background: var(--bg-elev); color: var(--fg); border: 1px solid var(--border);
  border-radius: 8px; font-size: 0.95em; font-family: inherit;
}
.referral-stats { margin-top: 12px; }

/* ── Affiliate program dashboard (GTM affiliate-program lane) ──────────────────
   The CASH sibling of the credits card above; it reuses .referral-linkrow /
   .referral-link for the copy-link row so the two surfaces look like one family. */
.affiliate-terms-table, .affiliate-payouts { border-collapse: collapse; width: 100%; margin: 12px 0; }
.affiliate-terms-table th, .affiliate-terms-table td,
.affiliate-payouts th, .affiliate-payouts td {
  text-align: left; padding: 8px 14px 8px 0;
  border-bottom: 1px solid var(--border); vertical-align: baseline;
}
.affiliate-terms-table th, .affiliate-payouts th { font-weight: 600; white-space: nowrap; }
.affiliate-terms-table td.muted { color: var(--text-dim); font-size: 0.9em; }

/* The FTC compensated-endorser duty, rendered AT the copy button rather than
   only in the terms. Deliberately the loudest block on the page. */
.affiliate-disclose {
  margin-top: 16px; padding: 14px 16px; border-radius: 10px;
  border: 1px solid var(--danger, #d9534f);
  background: color-mix(in srgb, var(--danger, #d9534f) 8%, transparent);
}
.affiliate-disclose p { margin: 0 0 8px; line-height: 1.5; font-size: 0.95em; }
.affiliate-disclose p:last-child { margin-bottom: 0; }

.affiliate-funnel { display: flex; gap: 28px; flex-wrap: wrap; margin: 12px 0 4px; }
.affiliate-stat { display: flex; flex-direction: column; min-width: 110px; }
.affiliate-stat-n { font-size: 1.6em; font-weight: 700; line-height: 1.2; }
.affiliate-stat-l { color: var(--text-dim); font-size: 0.9em; }

.affiliate-bar {
  height: 10px; max-width: 420px; margin-top: 8px; overflow: hidden;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 999px;
}
.affiliate-bar > span { display: block; height: 100%; width: 0; background: var(--accent, #6ea8fe); }

/* ── Cover / hero images (capsule demades-ai-images) ─────────────────────────
   A deterministic per-entity cover renders as a CSS background; `.has-img` hides
   the emoji fallback and (for tiles) lays a scrim so the label stays legible. */
.card-cover.has-img {
  background-size: cover; background-position: center; background-repeat: no-repeat;
  font-size: 0;
}
.cr-cover.has-img,
.player-cover.has-img {
  display: inline-block; width: 46px; height: 46px; flex: 0 0 46px;
  border-radius: 10px; font-size: 0; vertical-align: middle;
  background-size: cover; background-position: center; background-repeat: no-repeat;
  border: 1px solid var(--border);
}
.modal-cover.has-img {
  display: inline-block; width: 72px; height: 72px; border-radius: 14px; font-size: 0;
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.pop-tile.cat-tile.has-img {
  position: relative; overflow: hidden;
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.pop-tile.cat-tile.has-img::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(180deg, rgba(8,9,12,0.18) 0%, rgba(8,9,12,0.82) 100%);
}
.pop-tile.cat-tile.has-img > * { position: relative; z-index: 1; }
.pop-tile.cat-tile.has-img .pt-emoji { display: none; }
.pop-tile.cat-tile.has-img .pt-name { color: #fff; }
.pop-tile.cat-tile.has-img .pt-count,
.pop-tile.cat-tile.has-img .pt-rating { color: rgba(255,255,255,0.88); }

/* ── Baseline dark theme (capsule demades-frontend-dark-mode) ────────────────
   Demades is dark-editorial by default, so under an OS dark preference this
   block (1) pins the dark palette explicitly on the :root variables — dark-pref
   users keep a dark background + light text even if the default palette is ever
   lightened — and (2) sets color-scheme: dark so native UI (form controls,
   scrollbars, <audio> players) renders dark instead of light-themed chrome.
   Light mode (no dark preference) is untouched. */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --bg: #0f0f10;
    --bg-elev: #18181b;
    --bg-elev-2: #1f1f24;
    --fg: #ececef;
    --fg-mute: #c8c8d0;
    --fg-dim: #a0a0aa;
    --accent: #f0c27b;
    --accent-hi: #ffd99a;
    --border: #2a2a32;
  }

  html, body { background: var(--bg); color: var(--fg); }
}

/* ── Script-debug modal (capsule demades-script-debug-ui) ──────────────────── */
.seg-summary { margin: 8px 0; }
.seg-label { display: block; font-weight: 600; margin: 12px 0 4px; font-size: 13px; }
.seg-edit {
  width: 100%; min-height: 160px; box-sizing: border-box; resize: vertical;
  font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--bg-elev); color: var(--fg); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px;
}
.seg-actions { display: flex; align-items: center; gap: 12px; margin: 10px 0; }
.seg-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.seg-table th, .seg-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
.seg-table th { color: var(--fg-mute); font-weight: 600; }
.seg-table .seg-text { color: var(--fg-mute); }
.seg-table code { font-size: 12px; color: var(--accent); }
.seg-badge { font-size: 12px; padding: 1px 8px; border-radius: 999px; white-space: nowrap; border: 1px solid var(--border); }
.seg-badge.ok { color: #7adcb4; border-color: rgba(122,220,180,.4); }
.seg-badge.warn { color: #ffc86e; border-color: rgba(255,200,110,.4); }
.seg-badge.new { color: #ff8a65; border-color: rgba(255,138,101,.5); }

/* Settings modal (account chip → Settings) */
.modal.modal-wide { max-width: 760px; width: calc(100% - 32px); }
.settings-modal h2 { margin: 0 0 14px; }
.set-section { margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--border); }
.set-section h3 { margin: 0 0 10px; font-size: 15px; color: var(--fg); }
.set-account { display: flex; align-items: center; gap: 14px; color: var(--fg-mute); flex-wrap: wrap; }
.set-credits { color: var(--accent); font-weight: 600; }
.set-note { color: var(--fg-dim); font-size: 13px; line-height: 1.5; margin: 10px 0 0; }
.plan-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
@media (max-width: 640px) { .plan-grid { grid-template-columns: 1fr; } }
.plan-card {
  text-align: left; background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: 12px; padding: 14px; cursor: pointer; color: var(--fg);
  display: flex; flex-direction: column; gap: 6px; font: inherit;
}
.plan-card:hover { border-color: var(--accent); }
.plan-card.current { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); cursor: default; }
.plan-name { font-weight: 700; font-size: 15px; }
.plan-price { font-size: 22px; font-weight: 700; color: var(--accent); }
.plan-per { font-size: 13px; font-weight: 400; color: var(--fg-mute); }
.plan-blurb { color: var(--fg-mute); font-size: 13px; }
.plan-perks { margin: 0; padding-left: 18px; color: var(--fg-mute); font-size: 13px; line-height: 1.6; }
.plan-cta {
  margin-top: auto; padding-top: 8px; font-size: 13px; font-weight: 600; color: var(--accent);
}
.plan-card.current .plan-cta { color: var(--fg-dim); }
.settings-modal .consent { margin-top: 8px; }

/* ── Created Episodes — per-episode creator analytics cards ──────────── */
.ce-intro { color: var(--fg-mute); margin: 0 0 14px; font-size: 14px; }
.ce-card { background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px;
  padding: 14px 16px; margin-bottom: 12px; }
.ce-analytics { margin-top: 12px; }
.ce-muted { color: var(--fg-dim); font-size: 13px; margin: 6px 0 2px; }
.ce-tiles { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; }
.ce-tile { background: var(--bg-elev-2); border: 1px solid var(--border); border-radius: 8px;
  padding: 8px 6px; text-align: center; }
.ce-val { font-size: 20px; font-weight: 700; color: var(--fg); line-height: 1.1; }
.ce-lbl { font-size: 10px; color: var(--fg-mute); margin-top: 3px; white-space: nowrap; }
.ce-funnel { margin-top: 14px; }
.ce-ftitle { font-size: 12px; color: var(--fg-mute); margin-bottom: 8px; }
.ce-frow { display: flex; align-items: center; gap: 10px; margin: 5px 0; }
.ce-fk { width: 34px; font-size: 12px; color: var(--fg-dim); text-align: right; flex: 0 0 auto; }
.ce-fbar { flex: 1 1 auto; height: 12px; background: var(--bg-elev-2); border-radius: 6px; overflow: hidden; }
.ce-ffill { display: block; height: 100%; border-radius: 6px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hi)); transition: width .3s ease; }
.ce-fv { width: 74px; font-size: 12px; color: var(--fg-mute); flex: 0 0 auto; }
@media (max-width: 640px) {
  .ce-tiles { grid-template-columns: repeat(3, 1fr); }
}

/* ══ CL1 cosmetic quick wins (capsule demades-app-cl1-cosmetic-quick-wins) ══
   Skeleton shimmer loaders, hover-play overlay, Search sort tabs, credits
   chip extras + the "Listen now" toast action. Sibling CLs touch the player
   styles concurrently — keep additions inside this bounded section. */

/* skeleton loaders — gray blocks matching card/tile/row geometry, with a
   left-to-right shimmer sweep. */
.skeleton {
  position: relative; overflow: hidden;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px;
}
.skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent 0%, rgba(255,255,255,0.04) 40%,
    rgba(255,255,255,0.09) 50%, rgba(255,255,255,0.04) 60%, transparent 100%);
  transform: translateX(-100%);
  animation: skel-shimmer 1.3s ease-in-out infinite;
}
@keyframes skel-shimmer { to { transform: translateX(100%); } }
.skel-card { height: 280px; border-radius: 14px; }
.skel-tile { flex: 1 1 200px; min-height: 132px; border-radius: 16px; }
.skel-row { height: 66px; border-radius: 12px; margin-bottom: 10px; }
.skel-row.skel-recent { height: 44px; border-radius: 10px; margin-bottom: 0; }

/* hover-play overlay — circular ▶ centered on playable artwork, shown on
   hover (or keyboard focus) of the cover. */
.cr-cover, .r-cover {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.cr-cover { width: 46px; height: 46px; }
.r-cover { width: 34px; height: 34px; }
.hover-play {
  position: absolute; inset: 0; margin: auto;
  width: 46px; height: 46px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(15,15,16,0.78); color: var(--accent);
  border: 1px solid var(--accent); font-size: 17px; cursor: pointer;
  opacity: 0; transform: scale(0.92);
  transition: opacity 0.12s ease, transform 0.12s ease, background 0.12s ease;
}
.cr-cover .hover-play { width: 36px; height: 36px; font-size: 14px; }
.r-cover .hover-play { width: 28px; height: 28px; font-size: 11px; }
/* the play triangle reads centered when nudged a hair right of true-center */
.hover-play .ic-play { width: 1em; height: 1em; margin-left: 2px; }
.card-cover:hover .hover-play,
.cr-cover:hover .hover-play,
.r-cover:hover .hover-play,
.hover-play:focus-visible { opacity: 1; transform: scale(1); }
.hover-play:hover { background: var(--accent); color: #1a1a1c; }

/* Search sort tabs (Trending / Best Sellers / Hot & New) — reuse the .subtab
   pill look; this row sits between the filter bar and the results grid. */
.sort-tabs { display: flex; gap: 6px; margin: -10px 0 18px; flex-wrap: wrap; }

/* credits chip extras — "credits" label + zero-balance state + the top-up
   affordance (real since the credits-wallet CL: clicking it bubbles to the
   badge button, which opens the wallet modal at the packs). */
#credit-word { font-weight: 500; color: var(--fg-mute); }
.credits.zero { color: #f4caca; border-color: #6a3a3a; }
.credits.zero #credit-word { color: #f4caca; }
.credit-topup {
  margin-left: 4px; padding-left: 9px; border-left: 1px solid var(--border);
  font-size: 12px; color: var(--accent); cursor: pointer;
}
.credit-topup:hover { color: var(--fg); text-decoration: none; }

/* toast action button ("▶ Listen now" after a purchase) */
.toast-action {
  margin-left: 10px; background: var(--accent); color: #1a1a1c;
  border: none; border-radius: 7px; padding: 5px 11px;
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.toast-action:hover { background: var(--accent-hi); }
/* ══ END CL1 cosmetic quick wins ════════════════════════════════════════════ */

/* ── Marketplace shelves (capsule demades-app-cl5-marketplace-shelves) ──
   BEGIN-SHELVES — bounded section; keep all shelf styles between markers. */
.shelves { margin: 0 0 26px; }
.shelf { margin: 0 0 22px; }
.shelf-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; padding: 0 44px; }
.shelf-title { font-size: 22px; margin: 0; }
.shelf-showall { margin-left: auto; background: none; border: none; cursor: pointer;
  color: var(--accent); font-size: 14px; padding: 2px 4px; }
.shelf-showall:hover { color: var(--accent-hi); text-decoration: underline; }
/* Side gutters hold the scroll arrows BESIDE the cards (not over them); the
   head is inset by the same 44px so the title lines up with the first card. */
.shelf-wrap { position: relative; padding: 0 44px; }
.shelf-row { display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-padding-left: 2px; padding: 2px 2px 10px;
  scrollbar-width: none; -ms-overflow-style: none; }
/* No scrollbar — the side arrows ARE the scroll affordance (Sam, 2026-06-16). */
.shelf-row::-webkit-scrollbar { display: none; }
.shelf-card { scroll-snap-align: start; flex: 0 0 188px; width: 188px; cursor: pointer;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px;
  overflow: hidden; display: flex; flex-direction: column; }
.shelf-card:hover { border-color: #3a3a44; }
.shelf-cover { height: 104px; display: flex; align-items: center; justify-content: center;
  font-size: 40px; background: var(--bg-elev-2); flex: 0 0 auto; }
.shelf-cover.has-img { background-size: cover; background-position: center; }
.shelf-body { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 5px; flex: 1; }
.shelf-name { font-size: 15px; margin: 0; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.shelf-by { color: var(--fg-mute); font-size: 12px; }
.shelf-meta { font-size: 12px; display: flex; align-items: center; gap: 6px; }
.shelf-meta .rcount { font-size: 11px; }
.shelf-actions { margin-top: auto; display: flex; gap: 6px; }
/* Hero card — the eyebrow-labeled Founder's-pick lead (Apple style). */
.shelf-card.shelf-hero { flex: 0 0 340px; width: 340px; border-color: var(--accent);
  background: linear-gradient(160deg, var(--bg-elev-2), var(--bg-elev)); }
.shelf-card.shelf-hero .shelf-cover { height: 140px; font-size: 56px; }
.shelf-card.shelf-hero .shelf-name { font-size: 21px; -webkit-line-clamp: 3; }
.shelf-eyebrow { color: var(--accent); font-size: 11px; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; }
.shelf-blurb { color: var(--fg-mute); font-size: 13px; margin: 0; }
/* Resume cards — progress bar + "N min left". */
.shelf-progress { height: 5px; background: var(--bg-elev-2); border-radius: 3px; overflow: hidden; }
.shelf-progress-fill { display: block; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hi)); }
.shelf-left { color: var(--fg-mute); font-size: 12px; }
/* Hover arrows — appear over the row ends on a pointer device. */
.shelf-arrow { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--border);
  background: rgba(24, 24, 27, 0.92); color: var(--fg); font-size: 19px; line-height: 1;
  cursor: pointer; opacity: 0; transition: opacity .15s ease; }
.shelf-arrow.prev { left: 4px; }
.shelf-arrow.next { right: 4px; }
.shelf-wrap:hover .shelf-arrow { opacity: 1; }
.shelf-arrow:hover { border-color: var(--accent); color: var(--accent-hi); }
@media (hover: none) { .shelf-arrow { display: none; } }
/* Don't float phantom scroll arrows over a row that already fits (nothing to
   scroll) — JS adds .scrollable only when the row overflows. */
.shelf-wrap:not(.scrollable) .shelf-arrow { display: none; }
/* Dim/hide the arrow at the end of its travel so it never sits over a card
   pointlessly: .at-start hides prev, .at-end hides next. */
.shelf-wrap.at-start .shelf-arrow.prev,
.shelf-wrap.at-end .shelf-arrow.next { opacity: 0; pointer-events: none; }
/* END-SHELVES */

/* Studio defaults (Settings → Studio defaults + "Save as my defaults") */
.studio-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* Voice-quality / TTS cost control sitting directly next to "Generate episode".
   Changing it re-prices the episode live (cost = ceil(credits_per_min × min)). */
.tts-cost-control {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 10px 4px 12px;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 10px;
}
.tts-cost-control .select { min-width: 120px; }

/* ── Studio redesign (Create Hosts/Cast/Template + Being-created) ──────────── */
/* BEGIN-STUDIO-REDESIGN */
.cast-editor-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.preset-id { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; margin-left: 4px; }
.preset-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
/* Saved/temp binding clarity (entity-semantics.md "UI binding must be
   unambiguous"): a "SAVED" chip on library rows, and the Create-form banner
   that names the live-reference cast + offers the tweakable-copy fork. */
.binding-tag { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .04em;
  color: var(--accent, #2d6cdf); background: color-mix(in srgb, var(--accent, #2d6cdf) 14%, transparent);
  border-radius: 4px; padding: 1px 6px; margin-right: 6px; vertical-align: middle; }
.cast-binding { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 8px 12px; border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--accent, #2d6cdf) 35%, transparent);
  background: color-mix(in srgb, var(--accent, #2d6cdf) 7%, transparent); font-size: 13px; }
.cast-binding .binding-text { flex: 1; min-width: 200px; color: var(--text); }
.cast-binding[hidden] { display: none; }
/* Entity-aware cast editor: one card per member with reference/private clarity +
   the per-membership "tweak for this cast" overlay editor. */
.cast-member { border: 1px solid var(--border, #e3e3e3); border-radius: 8px;
  padding: 10px 12px; margin: 8px 0; }
.cast-member .cm-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 6px; }
.cast-member .cm-tweak { margin: 0; }
.cast-member .cm-tweak textarea { width: 100%; }
.cast-member .cm-actions { display: flex; gap: 8px; margin-top: 6px; }
/* "Being created" phase cards */
.building-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.bc-h { margin: 0 0 4px; font-size: 14px; }
.bc-card { border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; background: var(--card, #16161a); }
.bc-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.bc-title { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bc-phase { color: var(--accent); font-size: 12px; flex: 0 0 auto; }
.bc-bar { height: 6px; border-radius: 4px; background: #2a2a31; overflow: hidden; margin: 9px 0 6px; }
.bc-fill { display: block; height: 100%; background: var(--accent); border-radius: 4px; transition: width 0.4s ease; }
.bc-foot { display: flex; gap: 10px; align-items: center; }
.bc-pub { color: var(--accent); }
/* Transcript-review gate (capsule demades-review-transcript-before-tts): the
   "Awaiting your review" card stands out from the in-progress ones. */
.bc-review { border-color: var(--accent); }
.bc-actions { margin-top: 10px; display: flex; gap: 8px; }
/* END-STUDIO-REDESIGN */

/* ── Queue drawer ("Playing Next" — capsule demades-app-cl3-queue-ui) ────────
   Right-side drawer over a backdrop, full scrollable queue. Sits BELOW the
   player bar in z-order so the bar's controls (incl. the Playing Next toggle)
   stay clickable while the drawer is open; the list pads its bottom so the
   last row clears the bar. */
.queue-backdrop {
  position: fixed; inset: 0; z-index: 38;
  background: rgba(0,0,0,0.45);
  opacity: 0; pointer-events: none; transition: opacity .18s ease;
}
.queue-backdrop.open { opacity: 1; pointer-events: auto; }
.queue-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 39;
  width: min(380px, 92vw);
  background: var(--bg-elev); border-left: 1px solid var(--border);
  box-shadow: -12px 0 32px rgba(0,0,0,0.45);
  transform: translateX(102%); transition: transform .2s ease;
  display: flex; flex-direction: column;
}
.queue-drawer.open { transform: translateX(0); }
.queue-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 18px; border-bottom: 1px solid var(--border);
}
.queue-head h3 { margin: 0; font-size: 17px; }
.queue-close {
  background: transparent; border: none; color: var(--fg-mute);
  font-size: 24px; cursor: pointer; line-height: 1;
}
.queue-close:hover { color: var(--fg); }
.queue-list {
  flex: 1; overflow-y: auto;
  padding: 10px 12px 110px; /* bottom clears the fixed player bar */
  display: flex; flex-direction: column; gap: 8px;
}
.q-empty { padding: 18px 8px; }
.q-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: 10px; padding: 8px 10px;
}
.q-cover { font-size: 24px; flex: 0 0 auto; }
.q-cover.has-img {
  display: inline-block; width: 38px; height: 38px; flex: 0 0 38px;
  border-radius: 8px; font-size: 0;
  background-size: cover; background-position: center; background-repeat: no-repeat;
  border: 1px solid var(--border);
}
.q-meta { flex: 1; min-width: 0; }
.q-title { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.q-sub { font-size: 12px; }
.q-actions { display: flex; gap: 2px; flex: 0 0 auto; }
.q-actions button {
  background: transparent; border: none; color: var(--fg-dim); cursor: pointer;
  font-size: 13px; width: 26px; height: 26px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
}
.q-actions button:hover:not(:disabled) { background: var(--bg-elev); color: var(--accent); }
.q-actions button:disabled { opacity: 0.3; cursor: default; }
.q-actions .q-remove { font-size: 16px; }
/* "Playing Next" toggle on the player bar (injected by app.js) + count badge */
.pbtn-queue {
  position: relative; width: auto; padding: 0 10px;
  font-size: 13px; font-weight: 600;
  border: 1px solid var(--border); border-radius: 8px;
}
.q-count {
  position: absolute; top: -6px; right: -6px;
  background: var(--accent); color: #1a1a1c;
  font-size: 10px; font-weight: 700;
  min-width: 16px; height: 16px; border-radius: 8px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
}
.q-count.hidden { display: none; }

/* Settings → Account: public creator name editor */
.set-profile { margin-top: 12px; }
.set-profile-row { display: flex; gap: 10px; align-items: center; }
.set-profile-row .input { flex: 1; }

/* ══ CL6 search upgrades (capsule demades-app-cl6-search-upgrades) ══════════
   Entity chips (All / Episodes / Creators) and the result-count / clear-all
   line. The All-segment section headers, see-all links and Top-result card
   that this section also carried were retired with the segmented All view;
   their rules were unreachable and are gone.
   Keep this section self-contained and append within it. */

/* Segmented control — a connected bordered group with square-ish inner segments
   and a label prefix, deliberately distinct from the rounded-pill Discover
   subtabs. Used by the Collection "Show" filter (.col-chips). (CL6 retired the
   Discover in-search "Search in" entity chips — entity is now the OUTER strip.) */
.entity-chips {
  display: inline-flex; margin: 2px 0 14px;
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  background: var(--bg-elev);
}
.entity-chips::before {
  content: "Search in"; align-self: center;
  padding: 0 10px; font-size: 12px; color: var(--fg-mute);
  border-right: 1px solid var(--border);
}
.entity-chip {
  background: transparent; border: none; color: var(--fg-mute);
  font: inherit; font-size: 13px; font-weight: 500;
  padding: 6px 14px; cursor: pointer;
}
.entity-chip + .entity-chip { border-left: 1px solid var(--border); }
.entity-chip:hover { color: var(--fg); background: rgba(255, 255, 255, 0.04); }
.entity-chip.active {
  background: var(--accent); color: #1a1a1c; font-weight: 600;
}
/* Collection reuses the segmented control with its own label. */
.col-chips::before { content: "Show"; }
/* .col-controls is a column flexbox; without this the inline-flex chip strip gets
   stretched to full container width by the default align-items:stretch. Pin it to
   its content width. */
.col-chips { align-self: flex-start; }
.col-controls { display: flex; flex-direction: column; gap: 2px; margin: 4px 0 8px; }
.col-controls .mkt-search-bar { margin: 0; max-width: 420px; }
.col-group { margin: 0; }
.col-group .col-section { margin-top: 28px; }
.col-group:first-of-type .col-section { margin-top: 8px; }
.col-count {
  font-size: 13px; font-weight: 500; color: var(--fg-mute);
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 999px; padding: 1px 9px; margin-left: 6px; vertical-align: middle;
}

/* Episode-only Advanced-Search controls hide for the creator / show entities
   (CL6 entity-first): the length window, the min-rating field, and the
   episode-centric sort tabs (Trending / Best Sellers / Hot & New). The search
   bar, the category drill-down, the creator filter, and the per-entity Sort By
   select all still apply, so they stay. */
#mp-view.ent-creator .len-range, #mp-view.ent-show .len-range,
#mp-view.ent-creator #f-rating, #mp-view.ent-show #f-rating,
#mp-view.ent-creator .sort-tabs, #mp-view.ent-show .sort-tabs { display: none; }
.filters .f-num { flex: 1 1 130px; }
/* Length window: two minute inputs with a dash between them. */
.filters .len-range { display: inline-flex; align-items: center; gap: 6px; flex: 1 1 190px; }
.filters .len-range .f-num { flex: 1 1 70px; min-width: 0; }
.len-dash { color: var(--fg-dim); }

/* Convenience "search everything" bar — sits below the Marketplace capsules. */
.mkt-quicksearch { margin: 0 0 4px; }
.mkt-quicksearch .search { width: 100%; box-sizing: border-box; }

/* The Advanced Search view's own scope-aware search bar (top of the view,
   above the All/Episodes/Creators chips). */
.mkt-search-bar { margin: 0 0 14px; }
.mkt-search-bar .search { width: 100%; box-sizing: border-box; }

/* result-count line — "17 results · ✕ clear filters" above the grid */
.result-line { margin: -8px 0 14px; font-size: 13px; color: var(--fg-mute); min-height: 16px; }
.link-btn {
  background: transparent; border: none; color: var(--accent); cursor: pointer;
  font: inherit; font-size: 13px; padding: 0;
}
.link-btn:hover { color: var(--accent-hi); text-decoration: underline; }

/* ══ END CL6 search upgrades ════════════════════════════════════════════════ */

/* Settings → Data & account (export + delete) */
.btn.danger { color: #ff8a80; border-color: rgba(255, 138, 128, 0.45); }
.btn.danger:hover { background: rgba(255, 138, 128, 0.12); }
.set-delete-confirm { margin-top: 12px; }

/* ── Right rail ("Now Playing" view — capsule demades-app-cl4-right-rail) ────
   BEGIN-RIGHT-RAIL — bounded section; keep all rail styles between markers.
   A persistent side panel (Spotify's Now Playing View shape), NOT an overlay:
   below the queue drawer (z 39/38) and the player bar (z 40), beside the
   sticky app-bar (z 30 — the rail starts under it via top offset). When open,
   #tab-panes gains right padding so the main content flexes narrower instead
   of sliding under the rail. Hidden entirely <1100px (the JS auto-collapses;
   the CSS is the backstop).
   NOTE: z-index must stay BELOW the app bar's 30: the sticky app bar is a
   stacking context, so the account-chip dropdown (z 60 *inside* it) paints at
   the app bar's level — a rail above 30 covered the open menu and made
   Settings/Sign out unclickable whenever audio was playing (rail auto-opens
   on playback; QA sweep 2026-06-07, probe: tools/rail_overlap_check.py). */
.now-rail {
  position: fixed; top: 60px; right: 0; bottom: 0; z-index: 29;
  width: 300px;
  background: var(--bg-elev); border-left: 1px solid var(--border);
  transform: translateX(102%); transition: transform .2s ease;
  overflow-y: auto;
  padding: 18px 18px 96px; /* bottom clears the fixed player bar */
}
.now-rail.open { transform: translateX(0); }
body.rail-open #tab-panes {
  /* content column stays ≤ --maxw; the extra width is consumed by the rail */
  max-width: calc(var(--maxw) + 300px);
  padding-right: 326px;
}
.rail-now.hidden, .rail-block.hidden { display: none; }
.rail-art {
  width: 100%; aspect-ratio: 1; border-radius: 12px;
  background: var(--bg-elev-2); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 72px; margin-bottom: 12px;
}
.rail-art.has-img {
  font-size: 0;
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.rail-title { margin: 0 0 2px; font-size: 18px; line-height: 1.25; }
.rail-sub { font-size: 12px; color: var(--fg-dim); }
.rail-desc { font-size: 13px; color: var(--fg-mute); margin: 10px 0 0; }
.rail-desc.clamped {
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}
.rail-more, .rail-link {
  background: transparent; border: none; color: var(--accent);
  font-size: 12px; font-weight: 600; cursor: pointer; padding: 0;
}
.rail-more:hover, .rail-link:hover { color: var(--accent-hi); }
.rail-more { margin-top: 2px; }
.rail-block { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--border); }
.rail-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px;
}
.rail-head h4 { margin: 0; font-size: 14px; }
.rail-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px; margin: 0 -6px; border-radius: 10px; cursor: pointer;
}
.rail-row:hover { background: var(--bg-elev-2); }
.rail-thumb {
  position: relative; font-size: 22px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
}
.rail-thumb.has-img {
  border-radius: 8px; font-size: 0;
  background-size: cover; background-position: center; background-repeat: no-repeat;
  border: 1px solid var(--border);
}
.rail-row-meta { flex: 1; min-width: 0; }
.rail-row-title { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-row-sub { font-size: 12px; }
/* hover-play ▶ overlay on recommended thumbs (the row opens the detail modal) */
.rail-hoverplay {
  position: absolute; inset: 0; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.55); color: var(--accent);
  font-size: 15px; opacity: 0; transition: opacity .12s ease;
}
.rail-row:hover .rail-hoverplay { opacity: 1; }
.rail-more-count { display: block; margin-top: 6px; }
/* "Now Playing view" toggle on the player bar (injected by app.js) */
.pbtn-rail.on { color: var(--accent); background: var(--bg-elev-2); }
@media (max-width: 1099px) {
  /* auto-collapse backstop: no rail, no toggle, no divider, no reserved padding */
  .now-rail, .pbtn-rail, .player-extra-divider { display: none !important; }
  body.rail-open #tab-panes { max-width: var(--maxw); padding-right: 26px; }
}
/* END-RIGHT-RAIL */

/* ══ B2B tier buy CTAs (the /welcome pricing cards → Stripe Checkout) ═══════ */
.tiers .tier-cta { display: inline-block; margin-top: 14px; }
button.buy-tier { font: inherit; border: none; cursor: pointer; }
button.buy-tier:disabled { opacity: 0.6; cursor: wait; }
.thanks .why ul { margin-top: 18px; }
/* ══ END B2B tier buy CTAs ══════════════════════════════════════════════════ */

/* ══ CL7 Collection upgrades (capsule demades-app-cl7-collection-upgrades) ══
   Bounded section — continue-listening shelf, unified episode rows (Apple
   show-page anatomy), ⋯ overflow menu, listening-stats corner card. Sibling
   /app CLs are landing concurrently; keep all CL7 styles inside this block. */

/* -- Collection header: stats card floats right of the title -- */
.cl-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; }
.cl-stats {
  display: flex; gap: 18px; flex-shrink: 0;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 12px; padding: 12px 18px; margin-top: 6px;
}
.cls-cell { display: flex; flex-direction: column; align-items: center; min-width: 56px; }
.cls-v { font-size: 18px; font-weight: 700; color: var(--accent); white-space: nowrap; }
.cls-k { font-size: 11px; color: var(--fg-mute); white-space: nowrap; }
@media (max-width: 640px) {
  .cl-head { flex-direction: column; }
  .cl-stats { margin-top: 0; }
}

/* -- continue-listening shelf (first row of the tab) -- */
.cl-shelf { margin-bottom: 28px; }
.cl-shelf-title { font-size: 22px; margin: 0 0 12px; }
.cl-shelf-row {
  display: flex; gap: 14px; overflow-x: auto; padding-bottom: 6px;
  scrollbar-width: thin;
}
.cl-resume {
  flex: 0 0 150px; cursor: pointer; border-radius: 12px; padding: 8px;
  background: var(--bg-elev); border: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 6px;
}
.cl-resume:hover { border-color: var(--accent); }
.cl-resume:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cl-art {
  width: 100%; aspect-ratio: 1; border-radius: 8px;
  background: var(--bg-elev-2) center/cover no-repeat;
  display: flex; align-items: center; justify-content: center; font-size: 42px;
}
.cl-resume-title {
  font-size: 13px; font-weight: 600; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* -- unified episode row (Apple show-page anatomy) -- */
.ep-row {
  display: flex; align-items: flex-start; gap: 14px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 12px; padding: 14px 16px;
}
.ep-thumb.cr-cover { width: 56px; height: 56px; font-size: 32px; border-radius: 10px; flex-shrink: 0; }
.ep-main { flex: 1; min-width: 0; }
.ep-date { font-size: 12px; display: flex; align-items: center; gap: 8px; }
.ep-badge {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; color: var(--fg-mute);
}
.ep-badge.created { color: var(--accent); border-color: var(--accent); }
.ep-title { font-size: 16px; font-weight: 600; margin-top: 2px; }
.ep-desc {
  font-size: 13px; line-height: 1.45; margin-top: 2px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ep-foot { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.ep-dur { font-size: 13px; }

/* -- ⋯ overflow menu -- */
.ep-overflow { position: relative; margin-left: auto; }
.ep-more {
  background: none; border: 1px solid transparent; color: var(--fg-mute);
  font-size: 18px; line-height: 1; cursor: pointer;
  width: 30px; height: 30px; border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
}
.ep-more:hover { background: var(--bg-elev-2); color: var(--fg); border-color: var(--border); }
.ep-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 40;
  min-width: 190px; display: none; flex-direction: column;
  background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: 10px; padding: 6px; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
}
.ep-menu.open { display: flex; }
.ep-menu button, .ep-menu a {
  background: none; border: none; cursor: pointer; text-align: left;
  font-size: 13px; color: var(--fg); padding: 7px 10px; border-radius: 6px;
  text-decoration: none; display: block; white-space: nowrap;
}
.ep-menu button:hover, .ep-menu a:hover { background: var(--bg-elev); color: var(--accent); text-decoration: none; }
/* hover-play sizing on the bigger episode-row thumb */
.ep-thumb.cr-cover .hover-play { width: 40px; height: 40px; font-size: 15px; }
/* ══ END CL7 Collection upgrades ════════════════════════════════════════════ */

/* ══ CL8 Studio polish + creator stats (capsule demades-app-cl8-studio-stats) ══
   Bounded section — epRow nested inside the Created-Episodes analytics cards,
   plus the "Your episodes" creator-stats block in the Recent right column.
   Sibling /app CLs are landing concurrently; keep CL8 styles in this block. */

/* The ce-card already provides the card chrome — strip the nested epRow's. */
.ce-card .ep-row { background: none; border: 0; border-radius: 0; padding: 0; }
.ce-card .ce-analytics { border-top: 1px solid var(--border); padding-top: 12px; }

/* "Your episodes" creator-stats block (right column of Studio → Recent). */
.cstats {
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 12px; padding: 16px 18px;
}
.cstats h2 { margin: 0 0 12px; font-size: 16px; }
.cstats-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.cstats-tile {
  background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 8px; text-align: center;
}
.cstats-v { font-size: 20px; font-weight: 700; color: var(--accent); line-height: 1.2; }
.cstats-k { font-size: 11px; color: var(--fg-mute); margin-top: 3px; white-space: nowrap; }
.cstats-top { font-size: 13px; color: var(--fg-mute); margin: 12px 0 0; }
.cstats-top b { color: var(--fg); }
.skeleton.skel-cstats { height: 190px; border-radius: 12px; }
/* ══ END CL8 Studio polish + creator stats ══════════════════════════════════ */

/* (The Marketplace "All" view + its Recommended rail were retired when the
   All subtab split into the Recommended / Trending shelf tabs.) */

/* ---- Legal pages + sitewide footer (demades-terms-of-service CL) ---- */
.site-foot{margin:4rem auto 2rem;padding:1.25rem 1.5rem 0;max-width:72rem;
  border-top:1px solid rgba(255,255,255,.08);font-size:.8rem;line-height:1.6;
  color:rgba(235,235,235,.45);text-align:center}
.site-foot a{color:rgba(235,235,235,.65)}
.site-foot p{margin:.25rem 0}
.ai-disclaimer{font-size:.78rem;color:rgba(235,235,235,.45);margin:.6rem 0 1rem}
.ai-disclaimer a{color:rgba(235,235,235,.6)}
/* Bias/non-factuality warning (Sam, 2026-06-19): a deliberately opinionated or
   counterfactual episode. NOT muted — a visible amber warning so listeners
   can't miss that the content may be biased and may not be factual. */
.bias-disclaimer{font-size:.92rem;font-weight:600;color:#3a2a00;background:#ffd86b;border:1px solid #e0b200;border-radius:8px;padding:.6rem .8rem;margin:.8rem 0}
.legal-doc{max-width:46rem;margin:3rem auto;padding:0 1.25rem;line-height:1.7}
.legal-doc h1{font-size:1.6rem;margin-bottom:.25rem}
.legal-doc h2{font-size:1.05rem;margin-top:2rem}
.legal-doc table{border-collapse:collapse;margin:1rem 0;font-size:.9rem}
.legal-doc th,.legal-doc td{border:1px solid rgba(255,255,255,.12);
  padding:.4rem .7rem;text-align:left}

/* ══ Mobile / phone responsive pass (capsule demades-mobile-responsive) ══════
   BEGIN-MOBILE — one consolidated phone-width section, appended so it overrides
   the scattered tablet breakpoints above without editing their bounded blocks.
   Goal: nothing on demades.ai gets cut off or overflows on a phone. Covers the
   landing, the 3-tab /app shell, the public episode/discover pages, the admin
   + legal tables, and 16px form inputs (so iOS Safari stops auto-zooming on
   focus). The app's primary nav is a HAMBURGER menu on phones (Sam found the
   old scrollable tab strip too cramped, 2026-06-13); the inline strip returns
   above 640px. See docs/design-notes.md → "Mobile app nav". */

/* ---- ≤640px: the main phone breakpoint ---- */
@media (max-width: 640px) {
  /* Typography — large editorial headings overflow narrow screens; scale them
     down and let long words break instead of forcing horizontal scroll. */
  h1 { font-size: 30px; }
  h2 { font-size: 23px; }
  h3 { font-size: 18px; }
  h1, h2, h3 { overflow-wrap: anywhere; }
  /* `clip` (not `hidden`) so it doesn't become a scroll container and break the
     sticky .app-bar — a phone-scoped safety net so the off-canvas panels
     (queue drawer / now-rail, positioned off the right edge via
     transform: translateX(102%)) can't create phantom horizontal scroll that
     makes mobile browsers zoom-to-fit. The app-bar itself no longer overflows
     because the inline .tabs strip is hidden behind the hamburger below. */
  body { font-size: 16px; overflow-x: clip; }

  main { padding: 32px 18px 80px; }

  /* Landing hero + pricing tiers */
  .landing header { margin-bottom: 40px; }
  .landing .tagline { font-size: 16px; }
  .landing-logo { width: 76px; height: 76px; }
  .cta, .cta-ghost { display: block; text-align: center; margin: 8px 0 0; }
  .tiers { grid-template-columns: 1fr; gap: 14px; margin: 24px 0 40px; }
  .why, .private { margin-top: 40px; }
  .private { padding: 20px; }

  /* Collection index / detail */
  .collections .grid { grid-template-columns: 1fr; }
  .episode { flex-direction: column; gap: 14px; padding: 18px; }
  .ep-cover { width: 100%; height: 170px; flex-basis: auto; }

  /* ---- /app shell: app bar — HAMBURGER nav (replaces the old scrollable tab
     strip; Sam found the strip too cramped, 2026-06-13). The inline .tabs strip
     is hidden; the .hamburger toggles the .nav-menu dropdown, whose items call
     the same switchTab() (app.js). The "Demades" wordmark stays visible now
     that the strip no longer competes for the row. ---- */
  .app-bar { gap: 10px; padding: 10px 14px; }
  .brand-logo { width: 30px; height: 30px; }
  .tabs { display: none; }                 /* inline strip hidden on phones */
  .hamburger { display: inline-flex; order: -1; } /* …replaced by the hamburger; sits LEFT of the Demades wordmark (Sam, 2026-06-13) */
  .nav-menu { display: block; }            /* shown unless .hidden (JS toggles) */
  .nav-menu.hidden { display: none; }
  .app-bar .feedback-btn { display: none; }/* Feedback moves into the menu */
  .app-bar-right { gap: 8px; }

  /* account dropdown: never wider than the screen */
  .acct-menu { max-width: calc(100vw - 20px); }

  /* panes */
  #tab-panes { padding: 22px 16px 36px; }
  .pane-head h1 { font-size: 26px; }

  /* ---- player bar: keep the SEEK bar on phones (the tablet rule at 760px
     hides it). 2-row grid: meta + transport on top, full-width scrubber below;
     the secondary controls (rate/share/comments/download) fold away. ---- */
  #app { padding-bottom: 118px; }
  .player {
    grid-template-columns: 1fr auto;
    grid-template-areas: "meta controls" "seek seek";
    gap: 6px 12px; padding: 9px 14px;
  }
  .player-meta { grid-area: meta; }
  .player-controls { grid-area: controls; }
  .player-seek { grid-area: seek; display: flex; }
  .player-extra { display: none; }

  /* tables (admin metrics, legal docs, script-debug) — let them scroll
     horizontally instead of forcing the page wider than the viewport. */
  .mx-table, .legal-doc table, .seg-table {
    display: block; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch;
  }

  /* modals get tighter padding + a hair more height on small screens */
  .modal { padding: 20px; max-height: 90vh; }
  .modal-overlay { padding: 14px; }

  /* public episode / discover pages */
  .public-ep { padding: 36px 18px 72px; }
  .public-ep h1 { font-size: 28px; }
  .public-ep .ep-desc { font-size: 16px; }
  .pub-nav-inner { padding: 10px 16px; gap: 10px; }
  .pub-nav-links { gap: 12px; }

  /* 16px form fields → iOS Safari no longer zooms in on focus */
  .search, .select, .input, .textarea, .ms-input { font-size: 16px; }
}

/* ---- ≤400px: the tightest phones — squeeze transport + chips a touch more ---- */
@media (max-width: 400px) {
  .app-bar { gap: 8px; padding: 9px 11px; }
  .tab { padding: 8px 10px; font-size: 14px; }
  .player { padding: 8px 11px; }
  .player-controls { gap: 2px; }
  .credits { padding: 5px 9px; }
  main { padding: 28px 14px 72px; }
}

/* ---- touch devices: ensure comfortable (~40px) tap targets on the small,
   dense controls that are otherwise sized for a mouse pointer. ---- */
@media (hover: none) and (pointer: coarse) {
  .tab, .subtab, .btn.small, .entity-chip, .rate-preset { min-height: 40px; }
  .ms-chip-x, .cmt-del, .q-actions button { min-width: 34px; min-height: 34px; }
}
/* END-MOBILE */

/* ── Keyboard-shortcuts UI — dark-theme overrides (Sam 2026-06-18) ──────────
   The shared keyboard_shortcuts/vanilla.js library ships LIGHT-theme inline
   styles (white card, #f0f0f0 key chips, a faint #888 corner hint) built for
   hub's light UIs. On Demades' dark /app those bright-white chips clashed hard,
   and the "⌨ Press ? for shortcuts" hint sat tucked into the player's podcast
   icons. We DON'T edit the shared lib (it's monorepo-wide) — instead scope dark
   overrides to Demades' app shell (`body.app-body`, where the kbsc nodes are
   appended to <body>). The lib sets these via inline cssText, so `!important`
   is required to win. */

/* (a) Key chips: theme surface + border + readable contrast, not bright white. */
body.app-body .kbsc-list kbd {
  background: var(--bg-elev-2) !important;
  border: 1px solid var(--border) !important;
  color: var(--fg) !important;
  border-radius: 5px !important;
  padding: 2px 8px !important;
}

/* (b) Corner hint: clear padding + lift it ABOVE the fixed player bar so it's no
   longer crowded by the podcast/player icons; theme-toned, still unobtrusive. */
body.app-body .kbsc-hint {
  bottom: 84px !important;       /* clear the ~64px player bar + breathing room */
  right: 16px !important;
  padding: 6px 12px !important;
  color: var(--fg-mute) !important;
  background: var(--bg-elev) !important;
  border: 1px solid var(--border) !important;
  border-radius: 8px !important;
  font-size: 12px !important;
}

/* The modal card + close button also default to the light palette — tone them
   to the dark theme so the shortcuts modal matches the rest of /app. The card
   is the lib's only un-classed node, so reach it as the .kbsc-modal's child. */
body.app-body .kbsc-modal > div {
  background: var(--bg-elev) !important;
  color: var(--fg) !important;
  border: 1px solid var(--border) !important;
  box-shadow: 0 12px 40px rgba(0,0,0,0.6) !important;
}
body.app-body .kbsc-modal .kbsc-close {
  background: var(--bg-elev-2) !important;
  color: var(--fg) !important;
  border: 1px solid var(--border) !important;
  border-radius: 8px !important;
}

/* Public creator profile page (/creator/<account_id>): display name + bio +
   episodes, with the owner's inline bio editor. */
.creator-profile .creator-head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 8px;
}
.creator-profile .creator-head h1 { margin: 0; }
.creator-profile .bio { margin: 12px 0 18px; }
.creator-profile .bio-text {
  font-size: 17px;
  line-height: 1.6;
  color: var(--fg-mute);
  margin: 0 0 12px;
  white-space: normal;
}
.creator-profile .bio-form { margin: 0 0 24px; }
.creator-profile .bio-form.hidden { display: none; }
.creator-profile #bio-edit-btn.hidden { display: none; }
.creator-profile .bio-form textarea {
  width: 100%;
  box-sizing: border-box;
  min-height: 120px;
  padding: 12px;
  font: inherit;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
  resize: vertical;
}
.creator-profile .bio-form-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
}

/* ════ Demades wordmark lockup — the Sam-composed laurel vector ════
   The wordmark is static/wordmark.svg (templates.py _wordmark_inner): the
   Sam-approved lockup — "Demades" with the temple-m glyph and ONE gold laurel
   branch running fully BEHIND the word — composed in the Laurel Composer as a
   CLEAN VECTOR (Cormorant Garamond 600 glyph outlines + geometric temple-m +
   potraced gold laurel), transparent onto the dark chrome (v3 2026-07-22;
   superseded the v2 two-branch halo lockup, the short-lived raster
   wordmark.png, and the earlier traced two-path SVG). Crisp at any size. v3
   has NO halo/padding around the word (Sam's direction), so the SVG carries no
   <mask>/<filter> at all — trivially react-native-svg safe. Em-scalable: set
   font-size on the .dm-wordmark container; the img height follows (1.73em, tuned
   so the WORD ≈ the container font-size for the v3.1 lifted-laurel crop) and width
   tracks the viewBox aspect (932:274). Provenance: docs/brand-assets.md.

   IMPORTANT: 1.37em → 1.73em is NOT a size change — it is the v3.1 crop rescale. v3.1
   lifted the laurel 55 user units clear of the glyph band (the branch used to
   cross the letters at ~45% of cap-height and collapsed into a visible
   STRIKETHROUGH at the 18–21px header sizes, though it looked fine at the 56px
   hero) and grew the viewBox's top edge to match, 217 → 274. Scaling the em by
   the same 274/217 = 1.263 keeps the WORD rendering at exactly its former size;
   the extra 0.36em is transparent headroom above it. Move this number, the
   viewBox in web/static/wordmark.svg, and LOCKUP_EM/LOCKUP_VB_H in
   clients/app/src/components/chrome/wordmark.tsx together — never one alone. */
.dm-wordmark {
  display: inline-flex; flex-direction: column; align-items: stretch;
  vertical-align: middle; line-height: 1;
}
img.dm-lockup { display: block; height: 1.73em; width: auto; }


/* Plain text wordmark for alternate brand SKINS (web/skins.py wordmark='text',
   e.g. the Tempo weightlifting skin) — the cheap lockup a new skin starts on
   before it earns a bespoke glyph. Bold, slightly tight; sits in the same
   .dm-wordmark slot as the temple lockup so the app-bar geometry is unchanged. */
.dm-wordmark--text {
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-weight: 800; letter-spacing: .005em; color: #ece5d5;
  white-space: nowrap; align-self: center; line-height: 1; font-size: 20px;
}
.app-bar .brand .dm-wordmark--text { font-size: 20px; }

/* Raster wordmark lockup for image-skins (web/skins.py wordmark='image', e.g.
   the four vertical variants' Imagen-designed lockups, 2026-07-22). A
   transparent-bg PNG served from the skin's `wordmark_image`; sits in the same
   .dm-wordmark slot as the temple lockup, em-scalable off the container
   font-size (height ≈ 1.5em so the WORD ≈ the container size), width auto. */
img.dm-wordmark-img { display: block; height: 1.5em; width: auto; align-self: center; }

/* The alternate-skin lockup is the plain .dm-wordmark--text above (the old
   'pod' glyph-in-the-'o' lockup retired 2026-07-05 with the FooPod→real-name
   variant rename; each vertical's glyph lives on as the skin `logo`). */

/* contextual sizes — size the container; temple + fret follow via em */
.app-bar .brand .dm-wordmark { font-size: 21px; }
.pub-brand .dm-wordmark { font-size: 18px; }
.dm-wordmark--hero { font-size: 56px; }
@media (max-width: 520px) { .dm-wordmark--hero { font-size: 40px; } }

/* Creator attribution byline (public episode page) + the in-app/byline links
   to a creator's /creator/<account_id> profile. */
.public-ep .ep-byline { color: var(--fg-mute); font-size: 15px; margin: 0 0 6px; }
.creator-link { color: var(--accent); text-decoration: none; }
.creator-link:hover { text-decoration: underline; }

/* "Part of <Show>" series line on the public episode page — the crawlable link
   UP from an episode to its /show/<slug> hub. Sits with the byline in the
   masthead run, so it wears the byline's muted type. */
.public-ep .ep-series { color: var(--fg-mute); font-size: 15px; margin: 0 0 6px; }
.public-ep .ep-series .series-link { color: var(--accent); text-decoration: none; }
.public-ep .ep-series .series-link:hover { text-decoration: underline; }

/* Studio "Shows" subtab (capsule demades-series-cl3-studio-ui) — recurring
   show cards + the "Make it a show" create form. Reuses .ce-card / .studio-grid
   / .presets; these only lay out the show head, meta row and episode drawer. */
.show-card .show-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
.show-card .show-sub { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 4px; }
.show-card .show-actions { display: flex; gap: 8px; flex-wrap: wrap; flex-shrink: 0; }
.show-card .show-links { margin-top: 8px; }
.show-card .show-links a { color: var(--accent); text-decoration: none; }
.show-card .show-links a:hover { text-decoration: underline; }
.show-card .show-eps { margin-top: 12px; display: flex; flex-direction: column; gap: 12px; }
.show-card .show-eps[hidden] { display: none; }
.show-create .studio-form { margin-top: 12px; }
/* Plan usage line above the create form (capsule demades-series-cl5-billing-gating). */
.show-create .show-quota { margin: 4px 0 0; }
.show-create .show-quota a { color: var(--accent); text-decoration: none; }
.show-create .show-quota a:hover { text-decoration: underline; }
/* Low-credit auto-pause hint on a show card (capsule demades-series-cl5-billing-gating). */
.show-card .show-lowcredits { margin-top: 8px; color: var(--warn, #b54708); }
.show-card .show-lowcredits a { color: var(--accent); text-decoration: none; }
.show-card .show-lowcredits a:hover { text-decoration: underline; }

/* Public /business B2B funnel — the Bespoke contact-sales form (b2b_landing.py).
   Reuses the landing tokens; this only lays out the form + its status line. */
.contact-sales { max-width: 640px; margin: 8px auto 56px; }
.contact-sales h2 { margin-bottom: 8px; }
.contact-form { display: flex; flex-direction: column; gap: 14px; margin-top: 18px; }
.contact-form label { display: flex; flex-direction: column; gap: 6px; font-size: 14px; color: var(--fg-mute); }
.contact-form input, .contact-form select, .contact-form textarea {
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; color: var(--fg); font: inherit; }
.contact-form input:focus, .contact-form select:focus, .contact-form textarea:focus {
  outline: none; border-color: var(--accent); }
.contact-form textarea { resize: vertical; min-height: 88px; }
.contact-form button[type=submit] { align-self: flex-start; }
/* The "we can't take a card here" note + the "you're asking about: <tier>"
   line the tier CTAs stamp onto the /business contact-sales form. */
.contact-note { margin: 8px 0 0; font-size: 14px; color: var(--fg-mute); }
.contact-tier { margin: 12px 0 0; font-size: 14px; font-weight: 600; }
.contact-tier[hidden] { display: none; }
.contact-status { margin: 4px 0 0; font-size: 14px; }
.contact-status.ok { color: var(--accent); }
.contact-status.err { color: var(--warn, #b54708); }

/* ══ Legal / info pages — standard Demades skin (capsule demades-legal-skin) ══
   The About / Support / Terms / Privacy / Editorial / DMCA pages (+ clip-terms,
   b2b-terms, creator-agreement — every legal_pages.py + about_page.py slug)
   shipped as flat dark text on --bg. This brings them into the same look as the
   /discover|/studio app: the daily-rotating AI Greek scene behind a scrim, with
   the content + footer floated in blurred glass capsules. Those pages carry
   `body class="legal-skin"`; the backdrop image is set client-side into
   --dm-backdrop / --dm-backdrop-mobile by templates._LEGAL_SKIN_JS (GET
   /api/backdrops/active). Until it loads — or if the scene master isn't
   generated / JS is off — the gradient fallback below stands in, so the page is
   never bare. Capsule values MIRROR the app's data-dm-capsule frost
   (clients/app/src/global.css): rgba(12,14,18,.68) · blur(18px) saturate(120%) ·
   1px rgba(255,255,255,.12) · radius 22 · shadow 0 18px 50px rgba(0,0,0,.35). */
body.legal-skin { background: #0b0d12; }
/* The backdrop layer must be a NON-negative z-index sibling: at z-index:-2 the
   capsules' backdrop-filter can't sample it (it blurred the opaque body
   background instead — the full-height "black band" behind the capsule, Sam
   2026-07-23). z-index:0 + content lifted to z-index:1 keeps the image behind
   everything AND inside the capsules' backdrop. Verified live via injected
   override before shipping. */
/* `:not(.dm-mini)` — the persistent cross-page AUDIOBAR (templates.py
   _PERSISTENT_MINIPLAYER) is `position:fixed;bottom:0`, and this rule
   out-specifies a bare `.dm-mini` class selector: on EVERY legal/about page the
   bar lost its fixed positioning and fell to the bottom of the document flow
   (measured live on prod 2026-07-26: y=2115 in a 900px viewport — i.e. the bar
   was simply GONE). Sam, 2026-07-26: "the proper demades audiobar should be
   maintained under about/support/terms/privacy/etc". The bar already carries
   z-index 60, well clear of the ::before backdrop this rule lifts content above,
   so excluding it costs the skin nothing. (Belt-and-braces: the injected rule is
   `body .dm-mini`, so neither side alone can un-fix the bar again.) */
body.legal-skin > *:not(.dm-mini) { position: relative; z-index: 1; }
body.legal-skin::before {
  content: ""; position: fixed; inset: 0; z-index: 0;
  background:
    linear-gradient(180deg, rgba(11,13,18,.42) 0%, rgba(11,13,18,.55) 100%),
    var(--dm-backdrop, radial-gradient(120% 80% at 50% -10%, #24304a 0%, #141a28 45%, #0b0d12 100%));
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
@media (max-width: 640px) {
  body.legal-skin::before {
    background:
      linear-gradient(180deg, rgba(11,13,18,.44) 0%, rgba(11,13,18,.58) 100%),
      var(--dm-backdrop-mobile, var(--dm-backdrop, radial-gradient(120% 80% at 50% -10%, #24304a 0%, #141a28 45%, #0b0d12 100%)));
    background-size: cover; background-position: center; background-repeat: no-repeat;
  }
}
/* The frost values live ONCE, in the `--dm-glass-*` tokens at the bottom of this
   file (the shared Demades glass skin), so this capsule and the episode page's
   can't drift apart. Same rendered values as before the extraction. */
body.legal-skin .legal-doc {
  margin: clamp(1.5rem, 5vw, 3.5rem) auto;
  padding: clamp(1.4rem, 4vw, 2.4rem) clamp(1.25rem, 4vw, 2.2rem);
  background: var(--dm-glass-bg);
  -webkit-backdrop-filter: var(--dm-glass-blur); backdrop-filter: var(--dm-glass-blur);
  border: 1px solid var(--dm-glass-border-color); border-radius: var(--dm-glass-radius);
  box-shadow: var(--dm-glass-shadow);
}
body.legal-skin .legal-doc a { color: var(--accent-hi); }
body.legal-skin .legal-doc th, body.legal-skin .legal-doc td { border-color: rgba(255, 255, 255, .14); }
body.legal-skin .site-foot {
  max-width: 46rem; margin: 1.5rem auto 2.5rem; padding: 1rem 1.5rem 1.1rem;
  border: 1px solid rgba(255, 255, 255, .10); border-radius: 18px;
  background: rgba(12, 14, 18, .55);
  -webkit-backdrop-filter: blur(14px) saturate(120%); backdrop-filter: blur(14px) saturate(120%);
}
/* Accessibility: users who ask for reduced transparency get solid capsules. */
@media (prefers-reduced-transparency: reduce) {
  body.legal-skin .legal-doc { background: rgba(12, 14, 18, .96); -webkit-backdrop-filter: none; backdrop-filter: none; }
  body.legal-skin .site-foot { background: rgba(12, 14, 18, .92); -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* ---- Dyslexia-friendly reading mode (capsule demades-accessibility-reading-mode) ----
 * A user-toggleable reading mode for episode transcripts: a warm off-white
 * (cream) background, dark-grey (not pure black) text, increased letter / word /
 * line spacing, a wider reading measure, and an optional OpenDyslexic face
 * (self-hosted, SIL OFL 1.1 — see AI_DISCLOSURE_LICENSING.md). State is
 * server-side (prefer-server-side-state); static/reading_mode.js sets the class
 * + data-attrs these rules key off. Everything is SCOPED to
 * [data-reading-surface] so nothing outside a reading surface is affected. */
@font-face {
  font-family: "OpenDyslexic";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/opendyslexic-400.woff2") format("woff2");
}
@font-face {
  font-family: "OpenDyslexic";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/fonts/opendyslexic-700.woff2") format("woff2");
}

/* Spacing scale — three steps set the CSS vars the text rules consume. */
[data-reading-surface].reading-mode { --rm-letter: 0.035em; --rm-word: 0.10em; --rm-line: 1.8; }
[data-reading-surface].reading-mode[data-rm-spacing="normal"] { --rm-letter: 0.01em; --rm-word: 0.04em; --rm-line: 1.55; }
[data-reading-surface].reading-mode[data-rm-spacing="relaxed"] { --rm-letter: 0.035em; --rm-word: 0.10em; --rm-line: 1.8; }
[data-reading-surface].reading-mode[data-rm-spacing="loose"] { --rm-letter: 0.06em; --rm-word: 0.16em; --rm-line: 2.05; }

/* Container — cream background, dark-grey ink, a comfortable reading measure. */
[data-reading-surface].reading-mode {
  background: #faf3e3;
  color: #3a3730;
  border-radius: 12px;
  padding: 14px 20px;
  max-width: 68ch;
  margin-left: auto;
  margin-right: auto;
}
[data-reading-surface].reading-mode[data-rm-font="dyslexic"] {
  font-family: "OpenDyslexic", Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Text — dark-grey ink + the chosen spacing on every readable line, overriding
   the dark-theme muted greys the base transcript uses. */
[data-reading-surface].reading-mode .tx-line,
[data-reading-surface].reading-mode .tx-text,
[data-reading-surface].reading-mode .turn p,
[data-reading-surface].reading-mode p {
  color: #3a3730;
  letter-spacing: var(--rm-letter);
  word-spacing: var(--rm-word);
  line-height: var(--rm-line);
}
[data-reading-surface].reading-mode h2,
[data-reading-surface].reading-mode summary,
[data-reading-surface].reading-mode summary h2 { color: #2b2822; }
[data-reading-surface].reading-mode .tx-speaker,
[data-reading-surface].reading-mode .who { color: #8a5a10; }
/* Active-line + hover highlights recolored for the cream surface (the base
   dark-elev backgrounds would be near-black smudges on cream). */
[data-reading-surface].reading-mode .tx-line:hover { background: rgba(120, 90, 40, 0.10); color: #2b2822; }
[data-reading-surface].reading-mode .tx-line.active { background: rgba(120, 90, 40, 0.16); color: #2b2822; }

/* Settings → Accessibility section chrome. */
.acc-granular { margin: 2px 0 4px 26px; display: flex; flex-direction: column; gap: 6px; }
.acc-field { display: flex; align-items: center; gap: 10px; font-size: 14px; }
.acc-select {
  background: var(--bg-elev, #1f1f24); color: var(--fg, #e8e8ea);
  border: 1px solid var(--border, #333); border-radius: 8px; padding: 5px 9px; font-size: 14px;
}
.acc-preview { margin-top: 10px; }
.acc-preview-label { margin: 0 0 6px; }
.acc-preview-surface { font-size: 15px; }
.acc-preview-surface .turn .who { font-weight: 700; margin-right: 8px; }
/* When reading mode is OFF the preview shows the plain (dark-theme) transcript
   styling so the toggle's effect is obvious. */
.acc-preview-surface:not(.reading-mode) { color: var(--fg-mute, #b6b6bb); }

/* ══ Shared Demades glass skin — backdrop + frosted capsules ═════════════════
   The "classic demades" look, factored out of the legal/info-page skin (capsule
   demades-legal-skin) so any server-rendered public surface can wear it without
   re-typing the frost values. Sam, 2026-07-26: "we should make episode slug
   pages use the classic demades style: ai-generated backdrop + frosted glass
   capsules."

   Two pieces:

     * `--dm-glass-*` — ONE definition of the capsule frost. `body.legal-skin`
       above and `body.ep-skin` below both consume these, so the look can only
       drift in one place. Values MIRROR the app's `data-dm-capsule` frost
       (clients/app/src/global.css) — keep them in sync with it, not with a copy.
     * `body.ep-skin` — the backdrop layer for the public EPISODE page
       (`/e/<slug>`). Same fixed full-bleed backdrop + scrim as
       `body.legal-skin`, but the image is THIS episode's own AI (Imagen) cover,
       set server-side into `--dm-backdrop` by `templates.public_episode_page`
       (no fetch, no new image path, no new spend — it is the same asset the
       hero <img> and the OG card already serve off `/e/<slug>/cover.png`).

   Backdrop fallback ladder, so the page is never bare and nothing can enqueue a
   render from a page view:
     1. the episode's own cover (server-rendered inline `--dm-backdrop`);
     2. no cover yet → the daily-rotating Greek scene the app paints
        (`templates._BACKDROP_SKIN_JS` → GET /api/backdrops/active);
     3. that fetch failing / JS off → the gradient below. */
:root {
  --dm-glass-bg: rgba(12, 14, 18, .55);
  /* prefers-reduced-transparency + the no-backdrop-filter fallback both need a
     near-opaque twin; naming it here keeps the two in step. */
  --dm-glass-bg-solid: rgba(12, 14, 18, .96);
  --dm-glass-blur: blur(18px) saturate(120%);
  --dm-glass-border-color: rgba(255, 255, 255, .12);
  --dm-glass-radius: 22px;
  --dm-glass-shadow: 0 18px 50px rgba(0, 0, 0, .35);
}

/* ---- The public episode page's backdrop layer ---- */
body.ep-skin { background: #0b0d12; }
/* `:not(.dm-mini)` — the persistent cross-page AUDIOBAR is
   `position:fixed;bottom:0` and a bare `.dm-mini` class selector loses to this
   one; on the legal pages that exact rule un-fixed the bar and dropped it to the
   bottom of the document flow (measured on prod 2026-07-26, fixed same day).
   Carried forward here so the episode skin cannot reintroduce the same bug. */
body.ep-skin > *:not(.dm-mini) { position: relative; z-index: 1; }
/* The CLASSIC DEMADES WALLPAPER (Sam, 2026-07-26): the same daily-rotating AI
   Greek scene `body.legal-skin` paints, from the same `--dm-backdrop` /
   `--dm-backdrop-mobile` custom properties `templates._BACKDROP_SKIN_JS` sets.
   The first cut of this skin used the EPISODE'S OWN cover, which meant a heavy
   `filter: blur()` + `transform: scale()` layer (a 1024² square blown up to fill
   a wide viewport is upscaling mush without it) and a separate unfiltered scrim
   element on top. A real landscape wallpaper needs neither — so this is now
   byte-for-byte the legal skin's treatment: scrim stacked over image in ONE
   `background`, no filter, no `::after`.
   z-index 0 (never negative): at a negative z-index the capsules'
   backdrop-filter cannot sample this layer and blurs the opaque body background
   instead — the "black band behind the capsule" bug the legal skin hit. */
body.ep-skin::before {
  content: ""; position: fixed; inset: 0; z-index: 0;
  background:
    linear-gradient(180deg, rgba(11, 13, 18, .42) 0%, rgba(11, 13, 18, .55) 100%),
    var(--dm-backdrop, radial-gradient(120% 80% at 50% -10%, #24304a 0%, #141a28 45%, #0b0d12 100%));
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
@media (max-width: 640px) {
  body.ep-skin::before {
    background:
      linear-gradient(180deg, rgba(11, 13, 18, .44) 0%, rgba(11, 13, 18, .58) 100%),
      var(--dm-backdrop-mobile, var(--dm-backdrop, radial-gradient(120% 80% at 50% -10%, #24304a 0%, #141a28 45%, #0b0d12 100%)));
    background-size: cover; background-position: center; background-repeat: no-repeat;
  }
}

/* ---- The capsules themselves ----
   The simplified page (Sam, 2026-07-26) is four top-level blocks, each its own
   frosted capsule: the hero (`<header class="ep-hero">`), any `<section>` still
   rendered directly on the page (today only the paid buy-CTA — hosts /
   transcript / rating / comments / related all moved INSIDE the episode modal),
   the share row, and the two-button action row. */
body.ep-skin .public-ep > .ep-hero,
body.ep-skin .public-ep > section,
body.ep-skin .public-ep > .share-row,
body.ep-skin .public-ep > .ep-actions {
  background: var(--dm-glass-bg);
  -webkit-backdrop-filter: var(--dm-glass-blur); backdrop-filter: var(--dm-glass-blur);
  border: 1px solid var(--dm-glass-border-color);
  border-radius: var(--dm-glass-radius);
  box-shadow: var(--dm-glass-shadow);
  padding: clamp(1.1rem, 3.2vw, 1.8rem) clamp(1rem, 3.2vw, 1.6rem);
  margin: 0 0 18px;
}
@media (prefers-reduced-transparency: reduce) {
  body.ep-skin .public-ep > .ep-hero,
  body.ep-skin .public-ep > section,
  body.ep-skin .public-ep > .share-row,
  body.ep-skin .public-ep > .ep-actions,
  body.ep-skin .ep-modal-panel {
    background: var(--dm-glass-bg-solid);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  body.ep-skin .public-ep > .ep-hero,
  body.ep-skin .public-ep > section,
  body.ep-skin .public-ep > .share-row,
  body.ep-skin .public-ep > .ep-actions,
  body.ep-skin .ep-modal-panel { background: var(--dm-glass-bg-solid); }
}
/* The hero's first child is the kicker; its own top margin plus the capsule
   padding double up. Same at the tail of every capsule. */
body.ep-skin .public-ep > .ep-hero > :first-child,
body.ep-skin .public-ep > section > :first-child { margin-top: 0; }
body.ep-skin .public-ep > .ep-hero > :last-child,
body.ep-skin .public-ep > section > :last-child { margin-bottom: 0; }
/* `.public-ep h2` ships a 40px top margin for the flat layout; inside a capsule
   the padding already provides the separation. */
body.ep-skin .public-ep > section > h2 { margin-top: 0; }
/* Loose text that stays OUT of a capsule — the AI disclaimer and the bias
   banner. They read as fine print and would look over-weighted boxed, but they
   are the only text with the wallpaper (however scrimmed) directly behind it,
   so each gets a shadow that guarantees a dark edge whatever today's scene is.
   This is what lets the scrim above stay light enough for the backdrop to
   actually show. */
body.ep-skin .public-ep > .ai-disclaimer,
body.ep-skin .public-ep > .bias-disclaimer {
  text-shadow: 0 1px 3px rgba(0, 0, 0, .85), 0 0 12px rgba(0, 0, 0, .6);
}
/* The AI disclaimer is a REQUIRED editorial disclosure (EDITORIAL_POLICY.md), so
   it doesn't get to be the one thing the restyle made hard to read: `.muted` was
   tuned against the flat --bg this page used to have and goes marginal over a
   light scene. Lifted a step — still fine print, no longer squint-grey. */
body.ep-skin .public-ep > .ai-disclaimer { color: var(--fg-mute, #b6b6bb); text-align: center; }
/* Album art, not a page-width slab: at full width the cover pushed the summary
   and everything below it off the fold (measured 1440×1000: the description
   landed at y≈891). Still the crawlable hero <img>. */
body.ep-skin .public-ep .ep-cover {
  width: min(300px, 62%); max-height: none; aspect-ratio: 1 / 1;
  /* Centred (Sam, 2026-08-01) — the <img> is inline by default, so block +
     auto margins, not text-align on the hero (which would recentre siblings). */
  display: block; margin: 10px auto 18px;
}
/* ---- The cover IS the play control (2026-08-12) ----
   Sam's 2026-08-01 cover-first order pushed the native transport below the
   fold on phone AND laptop viewports (measured live: audio y=642 in a 664px
   viewport, y=746 in 720px; 7d likely-human view→play 1.8%), so the centred
   art gains the play affordance instead of the page being re-ordered. The
   button takes over the img's centring/sizing; the img fills it. Same
   markup-ships-both-glyphs pattern as `.ep-mact-primary` (see below). */
body.ep-skin .public-ep .ep-cover-btn {
  position: relative; display: block; margin: 10px auto 18px;
  width: min(300px, 62%);
  background: none; border: 0; padding: 0; cursor: pointer;
}
body.ep-skin .public-ep .ep-cover-btn .ep-cover { width: 100%; margin: 0; }
.public-ep .ep-cover-glyph {
  position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center;
}
.public-ep .ep-cover-glyph::before {
  /* The circular scrim behind the glyph. */
  content: ""; position: absolute; width: 64px; height: 64px;
  border-radius: 50%; background: rgba(0, 0, 0, .55);
  transition: background .15s ease, transform .15s ease;
}
.public-ep .ep-cover-btn:hover .ep-cover-glyph::before,
.public-ep .ep-cover-btn:focus-visible .ep-cover-glyph::before {
  background: rgba(0, 0, 0, .75); transform: scale(1.06);
}
.public-ep .ep-cover-glyph svg {
  position: relative; width: 30px; height: 30px; fill: #fff;
}
.public-ep .ep-cover-glyph .ic-pause,
.public-ep .ep-cover-btn.playing .ep-cover-glyph .ic-play { display: none; }
.public-ep .ep-cover-btn.playing .ep-cover-glyph .ic-pause { display: block; }
/* While playing, the scrim gets out of the art's way; it returns on
   hover/keyboard focus (the whole button still pauses on tap regardless). */
.public-ep .ep-cover-btn.playing .ep-cover-glyph { opacity: 0; transition: opacity .15s ease; }
.public-ep .ep-cover-btn.playing:hover .ep-cover-glyph,
.public-ep .ep-cover-btn.playing:focus-visible .ep-cover-glyph { opacity: 1; }
/* Slightly lift the body copy: --fg-mute over a scrimmed photo reads dimmer than
   it does over the flat --bg this page used to have. */
body.ep-skin .public-ep .ep-desc { color: var(--fg, #e8e8ea); }

/* ══ The simplified episode page (Sam, 2026-07-26) ═══════════════════════════
   "let's also simplify the UI. should essentially just have: buttons to share,
    embed the player … should be able to click an episode title and bring up the
    episode modal view … should be buttons side by side: Go to Demades, Try it
    myself."
   Three new pieces: the title-as-a-control, the two-button action row, and the
   `<dialog>` modals (episode details + embed) those controls open. */

/* ---- The title is the door into the episode modal ---- */
.public-ep .ep-title { margin-bottom: 6px; }
.public-ep .ep-title-btn {
  /* An <h1>-sized button must inherit every type property or it renders as a
     14px form control — `font: inherit` alone misses color/letter-spacing. */
  font: inherit; color: inherit; letter-spacing: inherit; text-align: left;
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  display: inline; /* so a long title still wraps as prose, not as a block */
}
.public-ep .ep-title-btn:hover { text-decoration: underline; text-underline-offset: 4px; }
/* "Hosts, transcript & more" — a proper gold/black button, centered (Sam,
   2026-07-27). It was a bare gold text link, which read as fine print next to
   the real controls. Gold fill + black label is the app's primary button
   (`--accent` on `#1a1a1c`, the same pair `.pub-nav-cta` uses).

   WARNING: the wrapper is `.ep-more-row`, NOT `.ep-more`, and must stay so:
   `.ep-more` is the app's ⋯ overflow-menu BUTTON above in this file
   (`width: 30px; height: 30px; display: inline-flex`) and a bare class selector
   doesn't care that this one is a <p>. Sam reported the button as uncentred
   TWICE while this rule already said `text-align: center` — because the <p> was
   a 30px square inline-flex box hugging the capsule's left edge, so it centred
   the button on a 30px axis (measured on prod: button centre x=326, hero centre
   x=640). Adding `display: block; width: auto` here would have papered over it;
   the name collision is the actual defect. */
/* ---- The primary actions: Go to Demades · Try it myself · Episode Details
   (Sam, 2026-08-01 — "Episode Details" folded in from the retired
   `.ep-more-row`; the three share one button style, gold only on primary).
   `.ep-action` must dress a <button> as well as an <a>: buttons don't inherit
   font and ship a UA background/border, so reset them here. ---- */
.public-ep .ep-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.public-ep .ep-action {
  flex: 1 1 0; min-width: 11rem; text-align: center; text-decoration: none;
  padding: .8rem 1.1rem; border-radius: 12px; font-weight: 600;
  border: 1px solid rgba(255, 255, 255, .18);
  font: inherit; font-weight: 600; cursor: pointer;
}
.public-ep .ep-action-primary {
  background: var(--accent-hi, #f0c27b); border-color: transparent; color: #16130d;
}
.public-ep .ep-action-ghost { background: rgba(255, 255, 255, .06); color: inherit; }
.public-ep .ep-action:hover { filter: brightness(1.08); }
/* "Side by side" is the ask, so keep it side by side on a phone too: at 390px
   the capsule's inner width is ~320px, and the desktop `min-width: 11rem` +
   `gap: 12px` needs 364px — so the row wrapped and the two actions stacked.
   Measured at 390×844: both fit on one line each at these values. */
@media (max-width: 480px) {
  .public-ep .ep-actions { gap: 8px; }
  .public-ep .ep-action { min-width: 0; padding: .8rem .5rem; font-size: .95rem; }
}

/* ---- The modals — the REAL Demades modal (Sam, 2026-07-27) ----------------
   Sam: *"clicking the title should bring up a real demades episode modal view"*
   / *"a real demades creator modal view"*. The first cut styled these as another
   frosted capsule, which read as a page block, not as the app's modal.

   These values are the app's `components/ui/modal.tsx` card, transcribed 1:1 so
   the web modal and the in-app NavModal (the browsable episode/creator/show
   overlay) are the same object:
       backdrop  rgba(0,0,0,0.6)      card bg   tokens.bgElev  (--bg-elev)
       border    1px tokens.border    radius    16
       maxWidth  560 (wide 760)       padding   26  (CARD_PADDING)
       close     top 14 / right 16    title     serif 28/600, paddingRight 28
   Keep them in step with that file — not with a copy. */
.public-ep .ep-modal {
  border: 0; padding: 0; background: none; color: inherit;
  width: min(760px, calc(100vw - 2rem)); max-height: min(84vh, 56rem);
  overflow: visible;
}
.public-ep .ep-modal::backdrop { background: rgba(0, 0, 0, .6); }
.public-ep .ep-modal-panel {
  position: relative;
  display: flex; flex-direction: column; max-height: min(84vh, 56rem);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 16px;
  overflow: hidden;
}
/* The app has no header RULE — the title is just the first thing in the padded
   card, with the ✕ floating over the top-right corner. */
.public-ep .ep-modal-head {
  display: block;
  padding: 26px 26px 0;
}
.public-ep .ep-modal-head h2 {
  margin: 0 28px 12px 0;
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 28px; font-weight: 600; line-height: 1.15; color: var(--fg);
}
.public-ep .ep-modal-x {
  position: absolute; top: 14px; right: 16px; z-index: 2;
  font-size: 1.6rem; line-height: 1; cursor: pointer; padding: 0 .2rem;
  background: none; border: 0; color: inherit; opacity: .7;
}
.public-ep .ep-modal-x:hover { opacity: 1; }
.public-ep .ep-modal-body {
  overflow-y: auto; overscroll-behavior: contain;
  padding: 0 26px 26px;
  /* The app's modal body is a flex column with a 24px gap between top-level
     blocks (`episode-detail.tsx` `styles.content`, Spacing.four) sitting inside
     the card's own 12px body gap. Reproducing the GAP — instead of leaning on
     each section's own page margins — is most of what makes the stack read as
     one designed view rather than a pile of page blocks. */
  display: flex; flex-direction: column; gap: 24px;
}
/* A CONTENT modal has no title band, so the body owns the card's full padding
   (the ✕ floats over it, exactly as in `ui/modal.tsx`). */
.public-ep .ep-modal-body-top { padding-top: 26px; }
/* Inside the modal the sections are already boxed by the card — drop the
   40px `h2` lead-in the flat page layout wants, and the trailing margins the
   flex gap now supplies. */
.public-ep .ep-modal-body > section:first-child > :first-child,
.public-ep .ep-modal-body > section > h2:first-child { margin-top: 0; }
.public-ep .ep-modal-body > section { margin: 0; }
.public-ep .ep-modal-body > section > :last-child { margin-bottom: 0; }
/* Section headings inside the modal are the app's `sectionTitle` (18px serif
   600), NOT the page's larger flat-layout h2. */
.public-ep .ep-modal-body section h2 {
  margin: 0 0 8px;
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 18px; font-weight: 600; line-height: 1.3; color: var(--fg);
}

/* ---- The episode modal's HERO ROW ----
   `episode-detail.tsx`'s masthead, measured live off the app's own NavModal
   (2026-07-27): heroRow gap 16 / cover 120 radius 16 / text column gap 4 /
   title 22px·28px weight 600 serif / meta + hosts 14px·20px weight 500
   `--fg-mute` / byline a pill with a 1px `--border` at radius 999. */
.public-ep .ep-mhero { display: flex; flex-direction: row; gap: 16px; align-items: center; }
.public-ep .ep-mhero-cover {
  width: 120px; height: 120px; flex: 0 0 auto;
  border-radius: 16px; object-fit: cover; display: block;
}
.public-ep .ep-mhero-text {
  display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 auto;
}
.public-ep .ep-mhero-title {
  margin: 0;
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 22px; line-height: 28px; font-weight: 600; color: var(--fg);
}
.public-ep .ep-mhero-meta {
  margin: 0; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--fg-mute);
}
.public-ep .ep-mhero-by {
  align-self: flex-start; margin-top: 4px;
  padding: 4px 8px; border: 1px solid var(--border); border-radius: 999px;
  font-size: 14px; line-height: 20px; text-decoration: none; color: var(--accent);
}
.public-ep .ep-mhero-by:hover { border-color: var(--accent); }

/* ---- The episode modal's ACTION ROW ----
   `episode-detail.tsx` `styles.actions`: a wrapping row of `flex:1 1 96px`
   chips at radius 10 with a 14/20 bold label, one accent-filled primary. */
.public-ep .ep-mactions { display: flex; flex-flow: row wrap; gap: 8px; }
.public-ep .ep-mact {
  flex: 1 1 96px;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  padding: 8px; border: 1px solid var(--border); border-radius: 10px;
  background: none; color: var(--fg); text-decoration: none; cursor: pointer;
  font-size: 14px; line-height: 20px; font-weight: 700;
  font-family: inherit;
}
.public-ep .ep-mact:hover { border-color: var(--accent); }
.public-ep .ep-mact svg { width: 16px; height: 16px; flex: 0 0 auto; }
.public-ep .ep-mact-primary {
  background: var(--accent); border-color: transparent; color: #0f0f10;
}
.public-ep .ep-mact-primary:hover { border-color: transparent; opacity: .9; }
/* One markup, two states: the chip ships both glyphs and paints the one that
   matches `#ep-audio` — no icon-building JS on a page that carries no app.js. */
.public-ep .ep-mact .ic-pause,
.public-ep .ep-mact.playing .ic-play { display: none; }
.public-ep .ep-mact.playing .ic-pause { display: inline-block; }
/* The copy-link chip's confirmation, mirroring `.share-btn.copied`. */
.public-ep .ep-mact.copied { border-color: var(--accent); color: var(--accent); }
/* The modal's summary — the app's `styles.desc` (16/22). */
.public-ep .ep-mdesc { margin: 0; font-size: 16px; line-height: 22px; color: var(--fg); }

/* No-<dialog> fallback (`_EP_MODAL_JS` sets the `open` attribute instead of
   calling showModal): render it inline rather than leaving a dead control. */
.public-ep .ep-modal:not([open]) { display: none; }
@media (max-width: 640px) {
  .public-ep .ep-modal { width: 100vw; max-width: 100vw; margin: auto 0 0; }
  .public-ep .ep-modal-panel { border-radius: 18px 18px 0 0; }
  .public-ep .ep-modal-head { padding: 20px 20px 0; }
  .public-ep .ep-modal-head h2 { font-size: 23px; }
  .public-ep .ep-modal-body { padding: 0 20px 20px; }
  .public-ep .ep-modal-body-top { padding-top: 20px; }
  /* The hero stacks on a phone — a 120px cover beside a 2-line title leaves the
     title ~120px wide and it shatters into one word per line. */
  .public-ep .ep-mhero { flex-direction: column; align-items: flex-start; gap: 12px; }
  .public-ep .ep-mhero-cover { width: 96px; height: 96px; }
}

/* ---- Creator modal body (fetched by `_EP_CREATOR_JS`) ----
   The app's `CreatorDetail`, measured live off its own modal (2026-07-27): a
   WIDER card (maxWidth 980) that holds a fixed 820px height so the content
   doesn't resize the overlay, a 104px circular avatar beside the name (24/30
   serif) / @handle / meta column, then the bio, then their episodes as a GRID
   OF COVER CARDS — the same shape the app's marketplace chips use. */
.public-ep .ep-modal.ep-modal-creator { width: min(980px, calc(100vw - 2rem)); }
.public-ep .ep-modal-creator .ep-modal-panel { height: min(820px, 84vh); }
/* With a definite card height the body must own the leftover space (and be
   allowed to shrink below its content) or it overflows the rounded card. */
.public-ep .ep-modal-creator .ep-modal-body { flex: 1 1 auto; min-height: 0; gap: 16px; }
.public-ep .dm-creator-head { display: flex; gap: 16px; align-items: center; }
.public-ep .dm-creator-avatar {
  width: 104px; height: 104px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
  background: var(--bg-elev-2);
}
.public-ep .dm-creator-mono {
  display: flex; align-items: center; justify-content: center;
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 46px; font-weight: 600; color: var(--fg-mute);
}
.public-ep .dm-creator-id { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.public-ep .dm-creator-name {
  margin: 0;
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 24px; line-height: 30px; font-weight: 600; color: var(--fg);
}
.public-ep .dm-creator-handle,
.public-ep .dm-creator-meta {
  margin: 0; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--fg-mute);
}
.public-ep .dm-creator-bio { margin: 0; font-size: 16px; line-height: 22px; color: var(--fg); }
.public-ep .dm-creator-sub {
  margin: 0;
  font-family: "Charter", "Iowan Old Style", Georgia, serif;
  font-size: 18px; line-height: 1.3; font-weight: 600; color: var(--fg);
}
/* The episodes grid. `auto-fill` + a 160px floor keeps the app's ~3-up desktop
   rhythm while collapsing to 2-up on a phone without a second breakpoint. */
.public-ep .dm-creator-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.public-ep .dm-creator-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; border: 1px solid var(--border); border-radius: 16px;
  background: rgba(255, 255, 255, .04);
  text-decoration: none; color: var(--fg);
}
.public-ep .dm-creator-card:hover { border-color: var(--accent); }
.public-ep .dm-creator-cover {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: 10px; display: block;
}
.public-ep .dm-creator-card-title {
  font-size: 14px; line-height: 20px; font-weight: 600;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.public-ep .dm-creator-card-meta { font-size: 13px; line-height: 18px; color: var(--fg-mute); }
@media (max-width: 640px) {
  /* The creator card is more specific than `.public-ep .ep-modal`, so it does
     NOT inherit the phone bottom-sheet shape — restate it, or the two modals
     open as visibly different objects on the same phone. */
  .public-ep .ep-modal.ep-modal-creator { width: 100vw; max-width: 100vw; margin: auto 0 0; }
  .public-ep .dm-creator-avatar { width: 76px; height: 76px; }
  .public-ep .dm-creator-mono { font-size: 34px; }
  .public-ep .dm-creator-name { font-size: 21px; line-height: 27px; }
  .public-ep .ep-modal-creator .ep-modal-panel { height: auto; max-height: min(84vh, 56rem); }
  .public-ep .dm-creator-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 12px; }
}

/* ---- The brand lockup on the wallpaper (Sam, 2026-07-27) ----
   First `.pub-nav`'s sticky `--bg` fill + bottom border came off ("make no
   black bar in the top"), leaving the bare wordmark. Then: *"the demades text
   logo should be in a black rounded rectangle and lets actually put the demades
   logo to its left (demades logo gets same vertical height as the text logo)."*
   So a CONTAINED black plate — `.ep-brand` (the header) still has no background
   and no border, so nothing spans the art; only `.ep-brand-link` is filled, and
   it is inline-flex so it is exactly as wide as logo + wordmark.

   CENTRED (Sam, 2026-07-27: *"can you center the demades logo + logo text?"*).
   It first sat top-LEFT to match the app's own chrome over the same wallpaper
   (measured on /discover: brand mark at x=30, y=16), but on this page every
   other element — the hero capsule, the "Hosts, transcript & more" button, the
   share row, the action pair — is centred on the column axis, so a left-hugging
   plate was the one thing off that axis. `text-align: center` on the header is
   what does it: `.ep-brand-link` is inline-flex, so it stays exactly as wide as
   its contents and the plate does NOT become a band.

   MATCHED HEIGHTS ARE STRUCTURAL. The one `font-size` below is the em BOTH
   marks size off, and `.ep-brand-logo`'s 1.37em is deliberately the em the
   lockup's INK occupies (20px × 1.37 = 27.4px), so the plate's two marks read
   the same height and a later font-size change moves them together. Don't give
   either a px height.
   IMPORTANT: it is no longer literally `img.dm-lockup`'s number. v3.1 (2026-08-02)
   lifted the laurel clear of the letters and grew the lockup's box to 1.73em to
   hold it — but the added 0.36em is TRANSPARENT HEADROOM, not ink, so matching
   the box would inflate this icon 26% against an unchanged word. Track the
   lockup's INK height (still ≈1.37em), not its box. */
.ep-brand { padding: 16px 24px 0; text-align: center; }
.ep-brand-link {
  display: inline-flex; align-items: center; gap: 10px; color: var(--fg);
  font-size: 20px;
  background: #000; border: 1px solid rgba(255, 255, 255, .10);
  border-radius: 14px; padding: 8px 14px;
}
/* Rounded like an app icon — logo.jpg is an opaque 512² square (a sky
   background), so square corners would read as a photo pasted on the plate.
   Same treatment the app bar's `.brand-logo` gives the identical asset. */
.ep-brand-logo { height: 1.37em; width: auto; border-radius: 6px; display: block; }
.ep-brand-link:hover { color: var(--accent-hi); text-decoration: none; }
/* White-label delivery mode (white_label.py): the partner's NAME stands in for
   the Demades wordmark image on the same plate. It sizes off `.ep-brand-link`'s
   one font-size, exactly as `img.dm-lockup` and `.ep-brand-logo` do, so the
   plate's geometry is identical whoever's mark it wears. `nowrap` because a
   two-word agency name breaking mid-plate would read as a layout bug. */
.ep-brand-name { font-weight: 600; letter-spacing: .01em; white-space: nowrap; }
@media (max-width: 640px) { .ep-brand { padding: 12px 16px 0; } }

/* ---- Centered share row (Sam, 2026-07-27) ----
   Scoped to the episode page so the clip share page's row is untouched. */
body.ep-skin .public-ep > .share-row { justify-content: center; }

/* ---- SHOW-level source + licence notice (`/show/<slug>`) ----
   Each EPISODE page carries a full TASL attribution inside its description; the
   SHOW page carried none, so a listener who subscribes to the show's feed and
   never opens an episode saw no licence at all — the half of CC BY-NC-SA
   §3(a)(1) that attaches the notice to every public presentation of the adapted
   material (`show_license.py`). Fine print by design: it sits under the summary
   inside the hero capsule, one <p> per distinct source. Lifted off `--fg-mute`
   over the wallpaper for the same reason `.ai-disclaimer` is — a REQUIRED
   notice does not get to be the one thing the skin made unreadable. */
.public-ep .show-source {
  font-size: 14px; line-height: 1.5; margin: -10px 0 18px;
}
body.ep-skin .public-ep .show-source { color: var(--fg-mute, #b6b6bb); }

/* ══ Landing / marketing pages — the classic Demades skin ════════════════════
   Sam, 2026-08-08, on /affiliates: *"it doesn't use the classic demades style
   (frosted glass capsules + wallpaper). all demades pages, now and moving
   forward, should use this style."*

   Every server-rendered `<main class="landing">` page (/affiliates, /partners,
   /pricing, /business, the signed-out landing, the thanks + episode-unavailable
   pages) shipped as flat dark text on `--bg` — the same defect the legal/info
   pages had before `body.legal-skin`. This is the third consumer of the shared
   `--dm-glass-*` tokens above, so the frost cannot drift from the app's
   `data-dm-capsule` or from the legal/episode skins.

   Backdrop image: the daily-rotating AI Greek scene, set client-side into
   `--dm-backdrop` / `--dm-backdrop-mobile` by `templates._BACKDROP_SKIN_JS`
   (GET /api/backdrops/active — an ALREADY-GENERATED rotation, so no page view
   can spend image money). Until it resolves — or with JS off — the gradient
   fallback below stands in, so the page is never bare.

   Guarded by `test_landing_skin.py`: a new `.landing` page that forgets the
   body class or the backdrop script fails the gate rather than shipping flat. */
body.landing-skin { background: #0b0d12; }
/* `:not(.dm-mini)` — the persistent cross-page AUDIOBAR is `position:fixed`, and
   an unqualified `body.<skin> > *` rule out-specifies a bare `.dm-mini` class
   selector and drops the bar to the bottom of the document flow. That shipped
   live once already (the legal skin, measured at y=2115 on prod 2026-07-26);
   both other skins carry the exclusion and so does this one.
   z-index 0 on the backdrop (never negative): at a negative z-index the
   capsules' backdrop-filter cannot sample the image and blurs the opaque body
   background instead — the "black band behind the capsule" bug. */
body.landing-skin > *:not(.dm-mini) { position: relative; z-index: 1; }
body.landing-skin::before {
  content: ""; position: fixed; inset: 0; z-index: 0;
  background:
    linear-gradient(180deg, rgba(11, 13, 18, .42) 0%, rgba(11, 13, 18, .55) 100%),
    var(--dm-backdrop, radial-gradient(120% 80% at 50% -10%, #24304a 0%, #141a28 45%, #0b0d12 100%));
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
@media (max-width: 640px) {
  body.landing-skin::before {
    background:
      linear-gradient(180deg, rgba(11, 13, 18, .44) 0%, rgba(11, 13, 18, .58) 100%),
      var(--dm-backdrop-mobile, var(--dm-backdrop, radial-gradient(120% 80% at 50% -10%, #24304a 0%, #141a28 45%, #0b0d12 100%)));
    background-size: cover; background-position: center; background-repeat: no-repeat;
  }
}

/* ---- The capsules ----
   One capsule per top-level block: the hero header, each `<section class="why">`
   (and the affiliate FTC-disclosure note, which is a `<div>`), and the footer.
   `.tiers` is excluded because it is a GRID of cards — frosting the grid would
   put flat `--bg-elev` boxes on top of a capsule; its `article`s are frosted
   individually below, which is what makes the pricing rows read as capsules. */
body.landing-skin .landing > header,
body.landing-skin .landing > section:not(.tiers),
body.landing-skin .landing > .affiliate-disclose,
body.landing-skin .landing > .private,
body.landing-skin .tiers > article {
  background: var(--dm-glass-bg);
  -webkit-backdrop-filter: var(--dm-glass-blur); backdrop-filter: var(--dm-glass-blur);
  border: 1px solid var(--dm-glass-border-color);
  border-radius: var(--dm-glass-radius);
  box-shadow: var(--dm-glass-shadow);
  padding: clamp(1.2rem, 3.4vw, 2rem) clamp(1.1rem, 3.4vw, 1.8rem);
}
/* Flat-page rhythm was 64px gaps between bare text blocks; capsules carry their
   own edges, so one uniform gap reads better and the `.why`/`header` margins
   from the base sheet are overridden here rather than in the shared rules. */
body.landing-skin .landing > header,
body.landing-skin .landing > section,
body.landing-skin .landing > .affiliate-disclose,
body.landing-skin .landing > .private { margin: 0 0 20px; }
body.landing-skin .landing > header > :first-child,
body.landing-skin .landing > section > :first-child,
body.landing-skin .tiers > article > :first-child { margin-top: 0; }
body.landing-skin .landing > header > :last-child,
body.landing-skin .landing > section > :last-child,
body.landing-skin .tiers > article > :last-child { margin-bottom: 0; }
/* The footer capsule, matching the legal skin's. */
body.landing-skin .site-foot {
  max-width: 46rem; margin: 1.5rem auto 2.5rem; padding: 1rem 1.5rem 1.1rem;
  border: 1px solid rgba(255, 255, 255, .10); border-radius: 18px;
  background: rgba(12, 14, 18, .55);
  -webkit-backdrop-filter: blur(14px) saturate(120%); backdrop-filter: blur(14px) saturate(120%);
}
/* Body copy over a scrimmed photo reads dimmer than over the flat `--bg` these
   pages used to have — the same one-step lift `body.ep-skin .ep-desc` takes. */
body.landing-skin .landing .tagline { color: var(--fg, #e8e8ea); }
body.landing-skin .landing a:not(.cta) { color: var(--accent-hi); }
body.landing-skin .affiliate-terms-table th,
body.landing-skin .affiliate-terms-table td { border-color: rgba(255, 255, 255, .14); }
/* Accessibility + the no-backdrop-filter fallback: solid capsules, never a
   transparent panel with unreadable text behind it. */
@media (prefers-reduced-transparency: reduce) {
  body.landing-skin .landing > header,
  body.landing-skin .landing > section:not(.tiers),
  body.landing-skin .landing > .affiliate-disclose,
  body.landing-skin .landing > .private,
  body.landing-skin .tiers > article,
  body.landing-skin .site-foot {
    background: var(--dm-glass-bg-solid);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  body.landing-skin .landing > header,
  body.landing-skin .landing > section:not(.tiers),
  body.landing-skin .landing > .affiliate-disclose,
  body.landing-skin .landing > .private,
  body.landing-skin .tiers > article,
  body.landing-skin .site-foot { background: var(--dm-glass-bg-solid); }
}

/* ---- The hero lockup: mark and wordmark SIDE BY SIDE ----
   Sam, 2026-08-08: *"pls put the logo and text logo side by side. rn we have
   logo above text logo and they're both massive. pls borrow from how we do it
   on the main demades.ai page."* The main site's lockup (`.pub-brand`, and the
   app bar's `.brand`) is a horizontal inline-flex of a small rounded mark plus
   the wordmark — this is that lockup at hero scale: 56px mark, 40px wordmark
   (was a 96px stacked mark over a 56px wordmark). `templates.landing_lockup()`
   emits it, so the geometry lives in one place for every landing page. */
.landing-lockup {
  display: flex; align-items: center; gap: 16px;
  margin: 0 0 22px; flex-wrap: wrap;
}
/* Overrides the stacked `.landing-logo` block above (display:block + 96px +
   margin-bottom) for the horizontal lockup only. */
.landing-lockup .landing-logo { width: 56px; height: 56px; margin: 0; border-radius: 14px; }
/* `h1` carries the accessible name; the wordmark inside it is aria-hidden art. */
.landing-lockup h1 { margin: 0; line-height: 1; }
.landing-lockup .dm-wordmark--hero { font-size: 40px; }
@media (max-width: 520px) {
  .landing-lockup { gap: 12px; }
  .landing-lockup .landing-logo { width: 44px; height: 44px; border-radius: 11px; }
  .landing-lockup .dm-wordmark--hero { font-size: 30px; }
}
