/* Narrable — design system extracted from "Narrable Home.dc.html" (artboards 2a, 3a–3g).
   Serif display + amber on near-black. Mono is reserved for System / in-world text,
   labels, and metadata. Mobile-first: the design canvas is 390px wide. */

/* FALLBACKS SHAPED LIKE THE WEB FONTS (2026-10-01). Until Spectral and
   JetBrains Mono arrive the page draws in Georgia and Menlo, and the swap moved
   every line: the widths match (Spectral is 100.5% of Georgia) but the vertical
   metrics do not (ascent 1.059 vs 0.917, descent 0.463 vs 0.219). These faces
   borrow the local fonts' shapes with the web fonts' measurements, read from
   the font files themselves (fontTools; hhea/OS-2 per USE_TYPO_METRICS) over
   a sentence of site text, so the swap changes only the letterforms. */
@font-face {
  font-family: 'Spectral Fallback';
  src: local('Georgia');
  size-adjust: 100.48%; ascent-override: 105.39%; descent-override: 46.08%; line-gap-override: 0%;
}
@font-face {
  font-family: 'Spectral Fallback';
  font-style: italic;
  src: local('Georgia Italic'), local('Georgia-Italic');
  size-adjust: 100.48%; ascent-override: 105.39%; descent-override: 46.08%; line-gap-override: 0%;
}
@font-face {
  font-family: 'JetBrains Mono Fallback';
  src: local('Menlo'), local('Menlo-Regular'), local('Consolas');
  size-adjust: 99.66%; ascent-override: 102.35%; descent-override: 30.10%; line-gap-override: 0%;
}

:root {
  --bg: #161412;
  --panel: #1f1b18;
  --panel-2: #2a2420;
  --ink: #ece4d6;
  --amber: #d29a3c;
  --amber-bright: #e0ad55;

  --ink-85: rgba(236, 228, 214, .85);
  --ink-75: rgba(236, 228, 214, .75);
  --ink-68: rgba(236, 228, 214, .68);
  --ink-65: rgba(236, 228, 214, .65);
  --ink-60: rgba(236, 228, 214, .60);
  --ink-55: rgba(236, 228, 214, .55);
  --ink-50: rgba(236, 228, 214, .50);
  --ink-45: rgba(236, 228, 214, .45);
  --ink-40: rgba(236, 228, 214, .40);
  --ink-32: rgba(236, 228, 214, .32);

  --line: rgba(236, 228, 214, .14);
  --line-soft: rgba(236, 228, 214, .08);
  --line-input: rgba(236, 228, 214, .18);
  --line-btn: rgba(236, 228, 214, .25);

  --serif: 'Spectral', 'Spectral Fallback', Georgia, 'Times New Roman', serif;
  --mono: 'JetBrains Mono', 'JetBrains Mono Fallback', ui-monospace, Menlo, Consolas, monospace;

  --pad: 22px;
  --shell: 430px;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* The canvas artboards are 390px wide. On a phone the shell is the viewport;
   on a desktop it stays a single centred column rather than stretching. */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  min-height: 100vh;
  background: var(--bg);
  position: relative;
}

/* THE FOOTER WAITS BELOW THE FIRST SCREEN (stamped shell, 2026-10-01). The
   header and footer are in the HTML now, so while a page fetches its content
   the footer would sit halfway up the screen and then be shoved away. The page
   area holds at least a screen until its content arrives. */
#page { min-height: calc(100vh - 140px); min-height: calc(100svh - 140px); }

/* Room for the sticky player so the last section is never trapped under it. */
.shell.has-player { padding-bottom: 84px; }

a { color: var(--amber-bright); }

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

.site-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px var(--pad);
}
.site-head.flush { padding-bottom: 0; }

.wordmark {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--ink);
  text-decoration: none;
}

.head-link {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-55);
  text-decoration: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.head-link:hover { color: var(--ink); }

.head-note {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-40);
}

/* ------------------------------------------------------------ typography */

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--amber);
}
.eyebrow.quiet { color: var(--ink-50); }

.display {
  margin: 14px 0 0;
  font-size: 40px;
  line-height: 1.08;
  font-weight: 300;
  letter-spacing: -.01em;
  text-wrap: pretty;
}
.display em { font-style: italic; font-weight: 400; }

.page-title {
  margin: 10px 0 0;
  font-size: 30px;
  line-height: 1.1;
  font-weight: 300;
  text-wrap: pretty;
}

.book-title {
  margin: 22px 0 0;
  font-size: 34px;
  line-height: 1.1;
  font-weight: 300;
  text-wrap: pretty;
}

.lede {
  margin: 18px 0 0;
  font-size: 16.5px;
  line-height: 1.5;
  color: var(--ink-68);
  text-wrap: pretty;
}

.body-copy {
  margin: 12px 0 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-65);
  text-wrap: pretty;
}

.fine {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-45);
}

/* Section rule + mono label, the repeating structural motif of the design. */
.section { padding: 34px var(--pad) 0; }
.section.tight { padding-top: 28px; }

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}
.section-head.center { align-items: center; }

.slabel {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ink-50);
  text-transform: uppercase;
}
.smeta {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-50);
}
.smeta.hot { color: var(--amber-bright); }

/* --------------------------------------------------------------- buttons */

.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 52px;
  border: none;
  border-radius: 6px;
  background: var(--amber);
  color: var(--bg);
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}
.btn:hover { background: var(--amber-bright); }
.btn:disabled { opacity: .45; cursor: default; }
.btn:disabled:hover { background: var(--amber); }
.btn.tall { height: 54px; font-size: 18px; }

.btn-ghost {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  border: 1px solid var(--line-btn);
  border-radius: 6px;
  background: transparent;
  color: var(--ink);
  font-family: var(--serif);
  font-size: 15.5px;
  text-decoration: none;
  cursor: pointer;
}
.btn-ghost:hover { border-color: var(--ink-55); }
.btn-ghost[aria-pressed="true"] {
  border-color: var(--amber);
  color: var(--amber-bright);
}

.btn-quiet {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  font-size: 14.5px;
  color: var(--ink-55);
  text-decoration: none;
}
.btn-quiet:hover { color: var(--ink); }

.btn-row { display: flex; gap: 10px; }
.btn-row > * { flex: 1; }

.cta-block { padding: 36px var(--pad) 30px; }
.cta-note {
  margin: 14px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-45);
  text-align: center;
}

/* ------------------------------------------------------- play affordance */

.play {
  width: 34px;
  height: 34px;
  flex: none;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line-btn);
  background: transparent;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.play:hover { border-color: var(--ink); }

.play .tri {
  width: 0; height: 0;
  border-left: 9px solid currentColor;
  border-top: 5.5px solid transparent;
  border-bottom: 5.5px solid transparent;
  margin-left: 2px;
}
.play .bars { display: none; gap: 3px; }
.play .bars i {
  display: block;
  width: 3px; height: 11px;
  background: currentColor;
}

/* Playing and loading states are driven by the shared audio controller. */
.play[data-state="playing"] {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--bg);
}
.play[data-state="playing"] .tri { display: none; }
.play[data-state="playing"] .bars { display: flex; }

.play[data-state="loading"] {
  border-style: dashed;
  border-color: var(--amber);
  color: var(--amber);
}
.play[data-state="loading"] .tri {
  border: 0;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--amber);
  margin-left: 0;
  animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

.play.lg { width: 40px; height: 40px; }
.play.lg .bars i { height: 12px; }

/* --------------------------------------------------------------- toggles */

.toggle {
  display: flex;
  flex: none;
  border: 1px solid var(--line-input);
  border-radius: 999px;
  padding: 2px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .04em;
  width: fit-content;
}
.toggle button {
  padding: 5px 11px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-50);
  font: inherit;
  cursor: pointer;
}
.toggle button[aria-pressed="true"] {
  background: var(--ink);
  color: var(--bg);
}

/* ----------------------------------------------------------------- forms */

.form { display: flex; flex-direction: column; gap: 12px; }

.field {
  height: 50px;
  width: 100%;
  padding: 0 16px;
  border-radius: 6px;
  border: 1px solid var(--line-input);
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 13px;
  outline: none;
}
.field::placeholder { color: rgba(236, 228, 214, .35); }
.field:focus { border-color: var(--amber); }
.field.on-panel { background: var(--panel); }
.field.serif { font-family: var(--serif); font-size: 15px; }

textarea.field {
  height: 96px;
  padding: 12px 14px;
  font-family: var(--serif);
  font-size: 15px;
  resize: none;
  line-height: 1.5;
}

/* Secondary to the paste box, so it reads as an alternative rather than a
   second required step. */
.dropzone {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 12px 16px;
  border: 1px dashed var(--line-btn);
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-55);
  text-align: center;
  cursor: pointer;
}
.dropzone:hover { border-color: var(--ink-55); color: var(--ink); }
.dropzone.over {
  border-color: var(--amber);
  background: rgba(210, 154, 60, .08);
  color: var(--amber-bright);
}
.dropzone.has-file {
  border-style: solid;
  border-color: var(--amber);
  color: var(--ink);
}

/* The consent tick. It gates the whole pipeline, so it is a real control with
   a 44px target, not fine print with a checkbox glued to it. */
.consent {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  font-size: 15.5px;
  color: var(--ink);
  cursor: pointer;
}
.consent input { position: absolute; opacity: 0; pointer-events: none; }
.consent .box {
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: 4px;
  border: 1px solid rgba(236, 228, 214, .4);
  position: relative;
}
.consent input:checked ~ .box {
  background: var(--amber);
  border-color: var(--amber);
}
.consent input:checked ~ .box::after {
  content: "";
  position: absolute;
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid var(--bg);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.consent input:focus-visible ~ .box { outline: 2px solid var(--amber-bright); outline-offset: 2px; }

.radios { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }

.radio {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  font-size: 15.5px;
  color: var(--ink-75);
  cursor: pointer;
}
.radio input { position: absolute; opacity: 0; pointer-events: none; }
.radio .dot {
  width: 18px; height: 18px;
  flex: none;
  border-radius: 50%;
  border: 1px solid rgba(236, 228, 214, .4);
  background: transparent;
}
.radio .hint { font-size: 13px; color: var(--ink-45); }
.radio input:checked ~ .dot {
  border: 5px solid var(--amber);
  background: var(--ink);
}
.radio input:checked ~ span:not(.hint) { color: var(--ink); }

/* ----------------------------------------------------------------- cards */

.panel {
  background: var(--panel);
  padding: 30px var(--pad) 34px;
}

.card {
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.card.hot {
  border-color: var(--amber);
  background: rgba(210, 154, 60, .08);
  padding: 20px;
}
.card.dashed {
  border: 1px dashed rgba(236, 228, 214, .2);
}

.card-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

.stat-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .06em;
  color: var(--ink-45);
  text-transform: uppercase;
}
.stat-value {
  font-size: 34px;
  font-weight: 300;
  line-height: 1;
  margin-top: 10px;
}
.stat-note { font-size: 13px; color: var(--ink-55); margin-top: 6px; }

/* -------------------------------------------------------------- listings */

/* Play button + speaker name, used for the company and for casting rows. */
.voice-row {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: 14px;
  align-items: center;
  padding: 10px 0;
}
.voice-name { font-size: 16px; }
.voice-note {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-45);
  margin-top: 2px;
}
.inworld {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-40);
}

/* A script line: play button, speaker label, then the line itself. */
.line {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: 14px;
  align-items: start;
  padding: 10px 0;
}
.line-speaker {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  color: var(--ink-50);
  text-transform: uppercase;
}
.line-text {
  margin: 5px 0 0;
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink-85);
}
/* System speaks in mono — the in-world voice is typographically separate. */
.line.system .line-text {
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.55;
}
.line.active .line-speaker { color: var(--amber-bright); }
.line.active .line-text { color: var(--ink); }

.rows { display: flex; flex-direction: column; }

.row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line-soft);
  text-decoration: none;
  color: inherit;
}
.row:last-child { border-bottom: 0; }
.row-title { font-size: 16px; }
.row-num { color: var(--ink-45); }
.row-time {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-50);
  flex: none;
}
.row-latest {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  color: var(--amber-bright);
}

.setting-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 18px 0;
  border-top: 1px solid var(--line);
}
.setting-row:last-of-type { border-bottom: 1px solid var(--line); }
.setting-label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  color: var(--ink-45);
  text-transform: uppercase;
}
.setting-value { font-size: 16px; margin-top: 5px; }
.setting-note { font-size: 13.5px; color: var(--ink-50); margin-top: 3px; }

.dl {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 48px;
  padding: 0 16px;
  border-radius: 6px;
  border: 1px solid rgba(236, 228, 214, .2);
  background: transparent;
  color: var(--ink);
  font-family: var(--serif);
  font-size: 15.5px;
  text-decoration: none;
  cursor: pointer;
}
.dl:hover { border-color: var(--ink-55); }
.dl span {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-50);
}

/* ------------------------------------------------------------------ book */

.cover {
  width: 96px;
  height: 136px;
  border-radius: 4px;
  background: var(--panel-2);
  border: 1px solid rgba(236, 228, 214, .12);
  display: flex;
  align-items: flex-end;
  padding: 10px;
  font-size: 12px;
  line-height: 1.2;
  color: var(--ink-60);
  object-fit: cover;
}

/* The book page holds the opening's room while it loads (book.js). */
.sample-wait { min-height: 196px; }

/* Covers fade in once loaded (app.js, 'fade-covers'); the tile's own
   background holds the space meanwhile, so nothing moves. */
.fade-covers img[src*="/cover/"] { transition: opacity .35s ease; }
.fade-covers img[src*="/cover/"]:not(.is-in) { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .fade-covers img[src*="/cover/"] { transition: none; }
}

.cadence {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-50);
}
.byline { margin-top: 6px; font-size: 15px; color: var(--ink-68); }

/* -------------------------------------------------------------- cast list */

/* One row per character: play, then name over "Voice:" over the line, then the
   line count. The name is set at reading size rather than display size -- these
   rows are a list to work through, not a title sequence. */
.cast-list { display: flex; flex-direction: column; padding: 6px 0 0; }

.cast-row {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: start;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-soft);
}
.cast-row:last-child { border-bottom: 0; }
.cast-row.busy { opacity: .55; }

.cast-name {
  font-size: 22px;
  font-weight: 400;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.cast-row.active .cast-name { color: var(--amber-bright); }

.cast-voice {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  min-width: 0;
}
.cast-voice-label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-45);
  flex: none;
}

/* The trigger looks like a select, because that is the affordance people know:
   a labelled value with a disclosure arrow. What it opens is not a native
   option list -- 461 flat options with no search and no way to hear anything
   before committing is unusable. It opens a picker sheet instead. */
.voice-trigger {
  flex: 1;
  min-width: 0;
  max-width: 260px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 10px;
  border: 1px solid var(--line-input);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 14.5px;
  cursor: pointer;
  text-align: left;
}
.voice-trigger:hover:not(:disabled) { border-color: var(--ink-55); }
.voice-trigger:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }
.voice-trigger:disabled { opacity: .5; cursor: default; }
.voice-trigger .name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.voice-trigger .caret {
  flex: none;
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--ink-55);
}

/* ------------------------------------------------------------ voice sheet */

/* A bottom sheet on a phone, which is where this design lives. Search at the
   top because the library is long, an audition on every row so a voice can be
   heard before it is chosen, and one explicit Use per row so nothing is
   committed by browsing. */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, .55);
}
.sheet[hidden] { display: none; }

.sheet-panel {
  width: 100%;
  max-width: var(--shell);
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border-top: 1px solid var(--line);
  border-radius: 12px 12px 0 0;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.sheet-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 18px var(--pad) 12px;
}
.sheet-title { font-size: 19px; font-weight: 400; }

.sheet-search {
  margin: 0 var(--pad) 12px;
  height: 44px;
  padding: 0 14px;
  border-radius: 6px;
  border: 1px solid var(--line-input);
  background: var(--panel);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 15px;
  outline: none;
}
.sheet-search:focus { border-color: var(--amber); }

.sheet-list {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 var(--pad) 18px;
}

.sheet-group {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-45);
  padding: 14px 0 8px;
}

.voice-row {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  margin-bottom: 6px;
}
.voice-row.chosen { border-color: var(--amber); background: rgba(210, 154, 60, .08); }
.voice-row .vname { font-size: 16px; overflow-wrap: anywhere; }
.voice-row .vnote {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-45);
  margin-top: 2px;
}
.voice-use {
  flex: none;
  height: 32px;
  padding: 0 12px;
  border-radius: 6px;
  border: 1px solid var(--line-btn);
  background: transparent;
  color: var(--ink);
  font-family: var(--serif);
  font-size: 14px;
  cursor: pointer;
}
.voice-use:hover { border-color: var(--amber); color: var(--amber-bright); }
.voice-row.chosen .voice-use {
  border: 0;
  color: var(--amber-bright);
  font-family: var(--mono);
  font-size: 10.5px;
  cursor: default;
}

/* The character's own words, which is what the play button reads out. */
.cast-line {
  margin: 10px 0 0;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--ink-75);
  text-wrap: pretty;
}
.cast-row.active .cast-line { color: var(--ink); }

.cast-lines { white-space: nowrap; padding-top: 4px; }

/* ----------------------------------------------------------- author panel */

/* Sits above the reader view, not instead of it, so an author always sees what
   a reader sees. Panel colour rather than page colour is what separates it. */
.author-panel {
  margin: 0 var(--pad) 8px;
  padding: 16px 18px 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.panel-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line-soft);
}

.panel-state {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-55);
}
.panel-state .dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ink-32);
}
.panel-state .dot.on { background: var(--amber); }

.panel-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 16px;
  align-items: center;
  padding: 14px 0;
}
.panel-stat .stat-label { margin-top: 2px; }

.share-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line-input);
  border-radius: 6px;
  background: var(--bg);
}
.share-url {
  flex: 1;
  min-width: 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-75);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.share-copy {
  flex: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--amber-bright);
}

.clip-out { margin-top: 12px; }
.clip-out[hidden] { display: none; }
.clip-out audio { width: 100%; }
.clip-links {
  display: flex;
  gap: 16px;
  align-items: center;
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 11px;
}
.clip-links a { color: var(--amber-bright); text-decoration: none; }

/* Where the book stands. The countdown is the point: it says what happens if
   nothing is posted, which is the only lever the author has. */
.standing { padding: 12px 0 4px; border-top: 1px solid var(--line-soft); }
.standing-line { display: flex; flex-direction: column; gap: 4px; }
.standing-rank { font-size: 17px; color: var(--amber-bright); }
.standing-rank.off { color: var(--ink-55); font-size: 15px; }
.standing-holds {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-55);
}

/* Completion per chapter: where people stop, not just that they did. */
.completion { padding-bottom: 6px; }
.completion-row {
  display: grid;
  grid-template-columns: 54px 1fr 40px;
  gap: 10px;
  align-items: center;
  padding: 4px 0;
}
.completion-ch { font-family: var(--mono); font-size: 10.5px; color: var(--ink-55); }
.completion-bar {
  height: 4px;
  border-radius: 2px;
  background: rgba(236, 228, 214, .12);
  overflow: hidden;
}
.completion-bar span { display: block; height: 100%; background: var(--amber); }
.completion-pct {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-75);
  text-align: right;
}

/* ---------------------------------------------------------------- player */

/* One persistent player component, per the design notes. It is fixed to the
   bottom of the shell and carries the Single/Cast toggle. */
.player {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: var(--shell);
  background: var(--panel);
  border-top: 1px solid var(--line);
  padding: 12px var(--pad) 14px;
  padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  z-index: 20;
}
.player[hidden] { display: none; }

.player-grid {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  gap: 14px;
  align-items: center;
}
.player-now {
  min-width: 0;
  font-size: 15px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.player-time {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-50);
  margin-top: 2px;
}
.player .play {
  width: 40px;
  height: 40px;
  background: var(--amber);
  border-color: var(--amber);
  color: var(--bg);
}
.player .play .bars i { height: 12px; }

.scrub {
  height: 2px;
  background: rgba(236, 228, 214, .12);
  margin-top: 12px;
  border-radius: 1px;
  cursor: pointer;
}
.scrub-fill {
  width: 0;
  height: 100%;
  background: var(--amber);
  border-radius: 1px;
}

/* The disclosure line appears on every page that plays audio. */
.disclosure {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-40);
  margin-top: 10px;
}
.disclosure.inline {
  font-size: 10.5px;
  padding: 6px 0 0;
  margin: 0;
}

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

.site-foot {
  display: flex;
  justify-content: space-between;
  padding: 20px var(--pad) 26px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-40);
}
.site-foot a { color: inherit; text-decoration: none; }
.site-foot div { display: flex; gap: 16px; }

/* ----------------------------------------------------------- async state */

.state {
  padding: 30px var(--pad);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-50);
}
.state.error { color: #d98b6a; }

/* A dashed ring standing in for a play button while audio is rendering. */
.pending-ring {
  width: 44px; height: 44px;
  flex: none;
  border-radius: 50%;
  border: 1px dashed rgba(236, 228, 214, .3);
  display: flex;
  align-items: center;
  justify-content: center;
}
.pending-ring i {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--amber);
  animation: pulse 1s ease-in-out infinite;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  max-width: calc(var(--shell) - 44px);
  padding: 12px 16px;
  border-radius: 6px;
  background: var(--ink);
  color: var(--bg);
  font-size: 14px;
  z-index: 60;
}
.toast[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------- discover
   Rails that scroll sideways, as they do in the app. The shell is 430px and a
   rail is meant to overflow it: a row that fits exactly reads as a list and
   gives no reason to swipe. */

.dhero { padding: 18px var(--pad) 6px; }
.dhero-label { font: 400 12px/1.2 var(--mono); letter-spacing: .08em;
               text-transform: uppercase; color: var(--ink-60, rgba(236,228,214,.6)); }
.dhero-track {
  display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
  margin-top: 10px; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.dhero-track::-webkit-scrollbar { display: none; }
.dhero-slide {
  flex: 0 0 100%; display: flex; gap: 14px; align-items: flex-start;
  scroll-snap-align: start;
}
.dhero-dots { display: flex; gap: 6px; justify-content: flex-end; padding-top: 10px; }
.dhero-dot { width: 6px; height: 6px; border-radius: 50%;
             background: rgba(236,228,214,.25); transition: background .2s; }
.dhero-dot.on { background: var(--amber); }
.dhero-text { flex: 1 1 auto; min-width: 0; }
.dhero-title { font: 300 30px/1.1 var(--serif); margin: 0 0 6px; letter-spacing: -.01em; }
.dhero-meta { font: 300 13px/1.4 var(--serif); color: rgba(236,228,214,.6); }
/* .btn is a full-width block everywhere else, which is right for a form and
   wrong beside cover art: it stretched the whole column. */
.dhero-btn { display: inline-flex; width: auto; padding: 0 22px; margin-top: 14px;
             text-decoration: none; }
.dhero-art { width: 108px; height: 158px; border-radius: 8px; object-fit: cover;
             flex: 0 0 auto; }

.drail { padding: 14px 0 6px; }
.drail .section-head { padding: 0 var(--pad); }
.drail-scroll {
  display: flex; gap: 12px; overflow-x: auto; padding: 10px var(--pad) 4px;
  /* Snapping aligns a card to the scroll edge, NOT the padding, unless told:
     the first card sat flush against the screen while its heading had a
     margin (filmed 2026-10-01). */
  scroll-padding-inline: var(--pad);
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.drail-scroll::-webkit-scrollbar { display: none; }
.drail-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 16px 12px; padding: 12px var(--pad);
}

.dcard { flex: 0 0 auto; width: 104px; scroll-snap-align: start;
         text-decoration: none; color: inherit; }
.dcard-art { width: 104px; height: 152px; border-radius: 6px; object-fit: cover;
             display: block; background: var(--panel); }
.dcard-art-blank { display: flex; align-items: flex-end; padding: 8px;
                   border: 1px solid var(--line-soft); }
.dcard-art-title { font: 300 12px/1.25 var(--serif); color: rgba(236,228,214,.55); }
.dcard-title { font: 300 14px/1.25 var(--serif); margin-top: 8px;
               display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
               overflow: hidden; }
.dcard-meta { font: 300 12px/1.3 var(--serif); color: rgba(236,228,214,.45);
              margin-top: 2px; }

.dmood { flex: 0 0 auto; width: 168px; padding: 14px; border-radius: 10px;
         background: var(--panel); border: 1px solid var(--line-soft);
         text-decoration: none; color: inherit; scroll-snap-align: start; }
.dmood-label { font: 300 16px/1.2 var(--serif); }
.dmood-sub { font: 300 12.5px/1.35 var(--serif); color: rgba(236,228,214,.5);
             margin-top: 4px; }
.dmood-count { font: 400 11px/1.2 var(--mono); color: var(--amber);
               margin-top: 10px; letter-spacing: .04em; }
/* A tile with nothing behind it still shows, because the absence is the
   information: these moods are unassigned, not broken. */
.dmood-empty { opacity: .45; }
.dmood-empty .dmood-count { color: rgba(236,228,214,.4); }

/* The drawn cover. The figure fills the card and the title sits over the
   scrim at the bottom-left, the same arrangement the app draws. Type is sized
   in percent of the card so it holds at any width, as ProceduralCoverView
   scales its fonts off the cover's own width. */
.dcard-art-blank { position: relative; overflow: hidden; border: 0; padding: 0;
                   display: block; }
.dcard-art-svg { position: absolute; inset: 0; width: 100%; height: 100%;
                 display: block; }
.dcard-art-text {
  position: absolute; left: 9%; right: 9%; bottom: 5%;
  display: flex; flex-direction: column; gap: 2px;
}
.dcard-art-title {
  font: 300 13px/1.2 var(--serif);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.dcard-art-author { font: 300 8px/1.2 var(--serif); opacity: .6; }
.dhero-art.dcard-art-blank { width: 108px; height: 158px; }
.dhero-art .dcard-art-title { font-size: 13.5px; }

/* ------------------------------------------------------------------- shell */

.site-head {
  display: flex; align-items: center; gap: 18px;
  padding: 18px var(--pad) 10px;
}
.site-nav { display: flex; gap: 16px; margin-left: auto; }
.nav-link {
  font: 400 12px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase;
  color: rgba(236,228,214,.55); text-decoration: none; padding: 4px 0;
  border-bottom: 1px solid transparent;
}
.nav-link:hover { color: var(--ink); }
/* The current page keeps the brass underline, so position is legible without
   reading the label. */
.nav-link.on { color: var(--ink); border-bottom-color: var(--amber); }
.head-slot { margin-left: 4px; }
/* The stamped placeholder holds the slot's width until app.js knows whether
   the visitor is signed in; showing "sign in" to someone who is would flicker. */
.head-pending { visibility: hidden; }

.site-foot {
  margin-top: 40px; padding: 26px var(--pad) 34px;
  border-top: 1px solid var(--line-soft);
}
.foot-cols { display: flex; gap: 32px; flex-wrap: wrap; }
.foot-col { display: flex; flex-direction: column; gap: 7px; }
.foot-title {
  font: 400 11px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase;
  color: rgba(236,228,214,.4); margin-bottom: 2px;
}
.foot-link { font: 300 14px/1.3 var(--serif); color: rgba(236,228,214,.72);
             text-decoration: none; }
.foot-link:hover { color: var(--ink); }
.foot-note { font: 300 12px/1.4 var(--serif); color: rgba(236,228,214,.38);
             margin-top: 22px; }

/* Desktop. The 430px column is right for reading a book page and wrong for
   everything else; from here the shell widens and rails become grids. */
@media (min-width: 900px) {
  .shell { max-width: 1120px; }
  .site-head { padding-inline: 40px; }
  .site-foot { padding-inline: 40px; }
  .drail .section-head, .dhero, .drail-scroll, .drail-grid { padding-inline: 40px; }
  .drail-scroll { scroll-padding-inline: 40px; }
  .dhero-slide { gap: 28px; }
  .dhero-title { font-size: 38px; }
  .dhero-art { width: 150px; height: 220px; }
  .drail-grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .dcard { width: 132px; }
  .dcard-art { width: 132px; height: 194px; }
}

/* THE BOOK PAGE, AT EVERY WIDTH (2026-10-01). On a desktop it was the phone
   layout stretched: a small cover on top and a Play button 1,500px wide. From
   900px the cover sits beside the title and the buttons keep a hand's width;
   the sections below keep a reading width. A phone is unchanged. */
.book-hero { padding: 22px 22px 0; }
.book-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 24px; }
@media (min-width: 900px) {
  .book-hero {
    display: grid; grid-template-columns: 220px minmax(0, 1fr); column-gap: 40px;
    align-items: start; padding: 40px 40px 0;
  }
  .book-hero > * { grid-column: 2; }
  .book-hero > .status-chip, .book-hero > .tag-row { justify-self: start; }
  .book-hero > .cover { grid-column: 1; grid-row: 1 / span 12; width: 220px; height: 322px; padding: 0; }
  .book-hero .book-title { margin-top: 4px; }
  .book-actions { max-width: 440px; }
  .book-page > .section { max-width: 820px; padding-inline: 40px; }
}

/* ------------------------------------------------- page furniture */

.page-title { font: 300 30px/1.15 var(--serif); margin: 6px var(--pad) 4px;
              letter-spacing: -.01em; }

.filters { display: flex; gap: 8px; padding: 10px var(--pad) 4px; flex-wrap: wrap; }
.filter {
  font: 300 14px/1 var(--serif); color: rgba(236,228,214,.62);
  background: none; border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 15px; cursor: pointer;
}
.filter:hover { color: var(--ink); }
.filter.on { color: var(--bg); background: var(--ink); border-color: var(--ink); }

/* An empty state points somewhere. The alternative -- a blank panel -- is the
   screen a new reader meets first, and it tells them nothing. */
.empty { padding: 34px var(--pad) 20px; max-width: 420px; }
.empty-title { font: 300 22px/1.25 var(--serif); }
.empty-body { font: 300 15px/1.5 var(--serif); color: rgba(236,228,214,.6);
              margin: 8px 0 18px; }
.empty .btn { width: auto; display: inline-flex; padding: 0 22px; text-decoration: none; }

/* ------------------------------------------------- prose pages */

.page-lede { font: 300 17px/1.5 var(--serif); color: rgba(236,228,214,.66);
             margin: 0 var(--pad) 10px; max-width: 46ch; }
.prose-section { padding: 18px var(--pad) 4px; max-width: 62ch; }
.prose-h2 { font: 400 11px/1 var(--mono); letter-spacing: .09em;
            text-transform: uppercase; color: rgba(236,228,214,.4);
            margin: 16px 0 14px; }
.prose-item { padding: 0 0 20px; }
.prose-head { font: 300 19px/1.3 var(--serif); display: flex; gap: 10px;
              align-items: baseline; }
.prose-num { font: 400 12px/1 var(--mono); color: var(--amber); flex: 0 0 auto; }
.prose-body { font: 300 15px/1.55 var(--serif); color: rgba(236,228,214,.62);
              margin: 6px 0 0; }
.prose-cta { padding: 8px var(--pad) 10px; }
.prose-cta .btn { width: auto; display: inline-flex; padding: 0 24px;
                  text-decoration: none; }

/* ------------------------------------------------- reader front door */

/* section.lede only: the authors page uses .lede for a paragraph already
   inside padded copy, and this padding indented it twice (2026-10-01). */
section.lede { padding: 28px var(--pad) 10px; }
.lede-title { font: 300 38px/1.08 var(--serif); margin: 0 0 12px;
              letter-spacing: -.015em; }
.lede-title em { font-style: italic; color: var(--amber-bright); }
.lede-body { font: 300 16px/1.5 var(--serif); color: rgba(236,228,214,.66);
             max-width: 44ch; margin: 0; }
.lede-actions { display: flex; gap: 10px; margin-top: 20px; flex-wrap: wrap; }
.lede-btn { width: auto; display: inline-flex; padding: 0 22px;
            text-decoration: none; }
.lede-foot { padding: 30px var(--pad) 8px; border-top: 1px solid var(--line-soft);
             margin-top: 26px; }
.lede-foot .lede-btn { margin-top: 14px; }

@media (min-width: 900px) {
  section.lede { padding: 52px 40px 18px; }
  .lede-title { font-size: 60px; max-width: 16ch; }
  .lede-body { font-size: 18px; }
  .lede-foot { padding-inline: 40px; }
}

/* ---------------------------------------- navigation, by width

   Phone: a bottom bar, where the thumb is and where the app keeps it. The
   header holds only the wordmark and the account, which is all that fits.
   Desktop: the bar disappears and the links sit in the header. */

.site-nav { display: none; }

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; justify-content: space-around; align-items: center;
  gap: 4px; padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: rgba(22,20,18,.92); backdrop-filter: blur(12px);
  border-top: 1px solid var(--line-soft);
}
.tabbar .nav-link { border-bottom: 0; padding: 6px 10px; font-size: 11px; }
.tabbar .nav-link.on { color: var(--amber); }

/* The bar covers the end of the page and the player sits above it. */
body { padding-bottom: 62px; }
.site-foot { margin-bottom: 8px; }

@media (min-width: 900px) {
  .site-nav { display: flex; }
  .tabbar { display: none; }
  body { padding-bottom: 0; }
}

/* ------------------------------------------------- author details form */

.panel-block { margin-top: 18px; border-top: 1px solid var(--line-soft);
               padding-top: 14px; }
.panel-summary {
  font: 400 11px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase;
  color: rgba(236,228,214,.5); cursor: pointer; list-style: none;
}
.panel-summary::-webkit-details-marker { display: none; }
.panel-summary::after { content: ' +'; color: var(--amber); }
.panel-block[open] .panel-summary::after { content: ' −'; }

.field-set { display: flex; flex-direction: column; gap: 14px; padding-top: 14px; }
/* The label-and-input WRAPPER on the book page's author panel. Scoped to the
   wrapper: as a bare .field it also hit every input, select and textarea with
   class "field", and a select laid out as a flex column drew its text at the
   top of the box on iOS ("All rights reserved", 2026-09-30). */
label.field, div.field { display: flex; flex-direction: column; gap: 5px; }
.field-label { font: 400 11px/1 var(--mono); letter-spacing: .06em;
               text-transform: uppercase; color: rgba(236,228,214,.45); }
.field-input {
  font: 300 15px/1.4 var(--serif); color: var(--ink);
  background: rgba(236,228,214,.04); border: 1px solid var(--line-input);
  border-radius: 6px; padding: 10px 12px; width: 100%; resize: vertical;
}
.field-input:focus { outline: none; border-color: var(--amber); }
.field-hint { font: 300 12.5px/1.4 var(--serif); color: rgba(236,228,214,.42); }
.form-status { font: 300 13px/1.4 var(--serif); color: var(--amber); min-height: 18px; }
.field .btn-ghost { width: auto; align-self: flex-start; padding: 0 18px; }

/* ------------------------------------------------- player transport */

.trans {
  font: 400 11px/1 var(--mono); letter-spacing: .04em;
  color: rgba(236,228,214,.72); background: none;
  border: 1px solid var(--line); border-radius: 999px;
  min-width: 44px; height: 32px; padding: 0 10px; cursor: pointer;
}
.trans.wide { min-width: 58px; }
.trans:hover { color: var(--ink); border-color: var(--line-btn); }
/* An armed sleep timer has to be obvious: it is the one control that stops
   playback without the listener touching anything. */
.trans.on { color: var(--bg); background: var(--amber); border-color: var(--amber); }

/* The scrubber is draggable now, so it needs to look it and take a keyboard. */
.scrub { cursor: pointer; }
.scrub:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.player-time { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------ the bar and the sheet
 *
 * The bar carried nine controls across three rows on every page: title, clock,
 * scrubber, back, forward, speed, sleep, Single/Cast and the disclosure line.
 * It is now what its name says -- play/pause, what is playing, and a hairline
 * of progress -- and the rest opens as a sheet when you tap it. */
/* ABOVE THE TAB BAR, not behind it. Both are fixed to bottom:0 and the tab bar
   wins on z-index -- which only went unnoticed while the player was three rows
   tall and most of it cleared the tab bar anyway. A one-row bar sat underneath
   it entirely. It now starts where the tab bar ends, and the tab bar keeps
   paying the safe-area inset for both. */
.player {
  bottom: calc(62px + env(safe-area-inset-bottom, 0px));
  padding: 10px var(--pad) 12px;
}
@media (min-width: 900px) {
  .player { bottom: 0; padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
}
.player-grid { display: flex; align-items: center; gap: 12px; }

/* The title area IS the way in, so it is a button, and says so once. */
.player-meta {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; padding: 0; margin: 0;
  text-align: left; color: inherit; cursor: pointer; font: inherit;
}
.player-meta:hover .player-now { color: var(--ink); }
.player-now { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.player-hint {
  display: block; margin-top: 3px;
  font: 400 10px/1 var(--mono); letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-40);
}

/* Progress, as a hairline along the top edge of the bar. Not draggable: the
   whole bar is a tap target for opening the sheet, and a scrubber inside it
   would turn every mis-aimed tap into a seek. Dragging lives in the sheet. */
.scrub.mini {
  position: absolute; top: 0; left: 0; right: 0;
  height: 2px; margin: 0; border-radius: 0; cursor: default;
}

.sheet {
  /* top/height are set from visualViewport when it opens (app.js fitSheet);
     dvh is the fallback. Either way the sheet ends where the screen the
     reader can see ends, not under Safari's bottom bar. */
  position: fixed; left: 0; right: 0; top: 0; height: 100dvh; z-index: 60;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(12, 10, 9, .66);
}
.sheet[hidden] { display: none; }
body.sheet-open { overflow: hidden; }

.sheet-inner {
  width: 100%; max-width: var(--shell);
  background: var(--panel);
  border-top: 1px solid var(--line);
  border-radius: 14px 14px 0 0;
  padding: 14px var(--pad) calc(24px + env(safe-area-inset-bottom, 0px));
  animation: sheet-rise .2s ease-out;
  /* Taller than a small screen: scroll inside, never off the bottom. */
  max-height: 100%; overflow-y: auto; box-sizing: border-box;
}
@keyframes sheet-rise {
  from { transform: translateY(18px); opacity: .5; }
  to { transform: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .sheet-inner { animation: none; } }

.sheet-head { display: flex; align-items: center; justify-content: space-between; }
.sheet-kicker {
  font: 400 10px/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-40);
}
.sheet-close {
  width: 34px; height: 34px; flex: none; position: relative;
  border: 1px solid var(--line); border-radius: 50%;
  background: none; color: var(--ink-60); cursor: pointer;
}
.sheet-close:hover { color: var(--ink); border-color: var(--line-btn); }
/* A chevron pointing down: the direction the sheet goes. */
.sheet-close::before {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 9px; height: 9px; transform: translateY(-2px) rotate(45deg);
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
}

.sheet-title {
  font: 300 20px/1.35 var(--serif); color: var(--ink);
  margin: 14px 0 20px;
}
.sheet .scrub { height: 4px; margin-top: 0; border-radius: 2px; }
.sheet-times {
  display: flex; justify-content: space-between; margin-top: 9px;
  font: 400 11px/1 var(--mono); color: var(--ink-50);
  font-variant-numeric: tabular-nums;
}
.sheet-transport {
  display: flex; align-items: center; justify-content: center;
  gap: 24px; margin: 24px 0 20px;
}
.play.xl { width: 62px; height: 62px; background: var(--amber); border-color: var(--amber); color: var(--bg); }
.play.xl .tri { border-left-width: 16px; border-top-width: 10px; border-bottom-width: 10px; margin-left: 4px; }
.play.xl .bars { gap: 5px; }
.play.xl .bars i { width: 5px; height: 20px; }
.sheet-options {
  display: flex; align-items: center; justify-content: center;
  gap: 10px; flex-wrap: wrap;
}
.sheet .disclosure { margin-top: 20px; text-align: center; }

/* ------------------------------------------------- header search */

.head-search-wrap { flex: 1 1 auto; min-width: 0; max-width: 340px; }
.head-search {
  width: 100%; font: 300 14px/1 var(--serif); color: var(--ink);
  background: rgba(236,228,214,.05); border: 1px solid var(--line-soft);
  border-radius: 999px; padding: 9px 14px;
}
.head-search::placeholder { color: rgba(236,228,214,.35); }
.head-search:focus { outline: none; border-color: var(--line-btn);
                     background: rgba(236,228,214,.08); }
/* On a phone the wordmark and the account chip already fill the row, so search
   takes the line below rather than squeezing both. */
@media (max-width: 899px) {
  .site-head { flex-wrap: wrap; }
  .head-search-wrap { order: 3; flex-basis: 100%; max-width: none; }
}

/* ------------------------------------------------- resume bar

   Playback cannot survive a page load in a multi-page site, so every other
   page offers back what was interrupted. Sits above the tab bar. */

.resume-bar {
  position: fixed; left: 10px; right: 10px; bottom: calc(66px + env(safe-area-inset-bottom));
  z-index: 45; display: flex; align-items: center; gap: 8px;
  background: rgba(31,27,24,.96); backdrop-filter: blur(12px);
  border: 1px solid var(--line-soft); border-radius: 12px;
  padding: 10px 12px;
}
.resume-main { flex: 1 1 auto; min-width: 0; text-decoration: none; color: inherit;
               display: flex; flex-direction: column; gap: 2px; }
.resume-eyebrow { font: 400 10px/1 var(--mono); letter-spacing: .08em;
                  text-transform: uppercase; color: var(--amber); }
.resume-title { font: 300 14px/1.25 var(--serif); overflow: hidden;
                text-overflow: ellipsis; white-space: nowrap; }
.resume-time { font: 300 12px/1.2 var(--serif); color: rgba(236,228,214,.45); }
.resume-close { background: none; border: 0; color: rgba(236,228,214,.5);
                font-size: 20px; line-height: 1; cursor: pointer; padding: 4px 6px; }
.resume-close:hover { color: var(--ink); }
/* When the real player is on screen it is the source of truth, not this. */
.has-player .resume-bar { display: none; }
/* Room for the bar, as body.has-mini makes for the mini-player: it covered
   the create button at the bottom of the work page. */
body.has-resume { padding-bottom: 140px; }
body.has-resume.has-mini { padding-bottom: 130px; }

@media (min-width: 900px) {
  .resume-bar { left: auto; right: 24px; bottom: 24px; width: 320px; }
  body.has-resume { padding-bottom: 96px; }
  body.has-resume.has-mini { padding-bottom: 62px; }
}

/* ------------------------------------------------- serial status */

.status-chip {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 10px;
  font: 300 13px/1 var(--serif); color: rgba(236,228,214,.7);
  border: 1px solid var(--line-soft); border-radius: 999px; padding: 6px 12px;
}
.status-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
/* Not colour alone: each state also reads as a word, because "is this
   finished" is the question and a green dot does not answer it. */
.status-chip.complete { color: #8fbf7a; }
.status-chip.ongoing { color: var(--amber); }
.status-chip.hiatus { color: rgba(236,228,214,.5); }

/* ------------------------------------------------- filter chips */

.fbar {
  display: flex; gap: 8px; overflow-x: auto;
  /* The page gutter, so the chips line up with the search box above them
     rather than starting at the screen edge. */
  padding: 4px var(--pad) 16px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.fbar::-webkit-scrollbar { display: none; }
.fchip {
  flex: 0 0 auto; padding: 8px 15px; border-radius: 999px;
  border: 1px solid var(--line-soft); color: rgba(236,228,214,.72);
  font: 300 13px/1 var(--serif); text-decoration: none; white-space: nowrap;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.fchip:hover { color: var(--ink); border-color: rgba(210,154,60,.45); }
.fchip.on {
  background: rgba(210,154,60,.14); border-color: var(--amber); color: var(--amber);
}
.fchip:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* ------------------------------------------------- the mini-player

   Present on every page while something is playing, because playback now
   survives navigation. Sits above the tab bar, and gives up the screen to the
   full player on the book page. */

.miniplayer {
  position: fixed; left: 8px; right: 8px; bottom: calc(64px + env(safe-area-inset-bottom));
  z-index: 46; border-radius: 14px; overflow: hidden;
  background: rgba(31,27,24,.97); backdrop-filter: blur(14px);
  border: 1px solid var(--line-soft);
  box-shadow: 0 10px 30px rgba(0,0,0,.45);
}
.mini-track { height: 2px; background: rgba(236,228,214,.1); }
.mini-fill { height: 100%; width: 0; background: var(--amber); transition: width .25s linear; }
.mini-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; }
.mini-meta {
  flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  text-decoration: none; color: inherit; border: 0;
}
.mini-title {
  font: 300 14px/1.25 var(--serif); color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mini-time { font: 400 11px/1 var(--mono); color: rgba(236,228,214,.5); }
.mini-skip { min-width: 40px; height: 30px; }
.mini-close {
  flex: none; width: 30px; height: 30px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--line-soft); background: none;
  color: rgba(236,228,214,.55); font-size: 16px; line-height: 1;
}
.mini-close:hover { color: var(--ink); }

/* The bar must not cover the last row of the page it is sitting on. */
body.has-mini { padding-bottom: 130px; }
.has-mini .resume-bar { display: none; }

@media (min-width: 900px) {
  .miniplayer { left: auto; right: 24px; bottom: 24px; width: 380px; }
  body.has-mini { padding-bottom: 62px; }
}

/* ONE LOOK FOR THE PLAYER (2026-10-03, Azam). The book page's bar used to be a
   full-bleed strip capped at the old 430px phone column, so on a desktop it sat
   alone in the middle of a 1120px page; every other page showed this floating
   card instead. The book page now wears the card too: same surface, same place.
   Only the look changes -- it still opens the full controls sheet on tap. */
.player {
  left: 8px; right: 8px; width: auto; max-width: none; transform: none;
  bottom: calc(64px + env(safe-area-inset-bottom, 0px));
  padding: 0; overflow: hidden;
  border: 1px solid var(--line-soft); border-top: 1px solid var(--line-soft);
  border-radius: 14px;
  background: rgba(31,27,24,.97); backdrop-filter: blur(14px);
  box-shadow: 0 10px 30px rgba(0,0,0,.45);
  z-index: 46;
}
.player .scrub.mini { margin: 0; border-radius: 0; height: 2px; }
.player .player-grid { padding: 9px 12px; gap: 10px; }
.shell.has-player { padding-bottom: 130px; }
/* On a desktop both cards span the page's content column (the 1120px shell,
   inset 24px each side), centred, instead of a 380px corner card. */
@media (min-width: 900px) {
  .player, .miniplayer {
    left: 50%; right: auto; transform: translateX(-50%);
    width: calc(min(1120px, 100vw) - 48px); bottom: 24px;
  }
  .player { padding: 0; }
  .shell.has-player { padding-bottom: 90px; }
  body.has-mini { padding-bottom: 90px; }
}

/* The desktop bar's extra controls (app.js buildMini). A phone keeps the
   compact card: play, title, back 15, close. */
.mini-desk { display: none; }
/* Phone order unchanged: play · title · 15 · close. */
.mini-row > .mini-play { order: 0; }
.mini-row > .mini-meta { order: 1; }
.mini-row > .mini-skip { order: 2; }
.mini-row > .mini-close { order: 9; }
@media (min-width: 900px) {
  /* Desktop: play · 15 · 30 · title · speed · sleep · Single/Cast · close. */
  .mini-row > .mini-skip { order: 1; }
  .mini-row > .mini-meta { order: 2; }
  .mini-row > .mini-desk:not(.mini-skip) { order: 3; }
}
@media (min-width: 900px) {
  .player, .player + .sheet { display: none !important; }   /* the bar below serves */
  .miniplayer .mini-desk { display: inline-flex; }
  .miniplayer button.mini-desk { align-items: center; justify-content: center; height: 30px; }
  .miniplayer .mini-row { gap: 12px; padding: 10px 16px; }
  .miniplayer .mini-meta { flex: 1 1 auto; }
  /* The hairline is the seek bar here: same 2px line, a taller invisible
     target so it can be hit. */
  .miniplayer .mini-track { position: relative; cursor: pointer; }
  .miniplayer .mini-track::after { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 10px; }
  .miniplayer .toggle.mini-desk { flex: none; }
  .miniplayer .mini-close { margin-left: 4px; }
}

/* ------------------------------------------------- author page */

.author-head { padding: 26px var(--pad) 18px; }
.author-mark {
  width: 64px; height: 64px; border-radius: 50%; margin-bottom: 14px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(210,154,60,.14); border: 1px solid rgba(210,154,60,.4);
  color: var(--amber); font: 400 22px/1 var(--serif); letter-spacing: .04em;
}
.author-stats { display: flex; flex-wrap: wrap; gap: 26px; margin-top: 16px; }
.author-stat-n { font: 300 20px/1.1 var(--serif); color: var(--ink); }
.author-stat-l {
  font: 400 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: rgba(236,228,214,.45); margin-top: 6px;
}
.author-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.byline-link { color: inherit; text-decoration: none; border-bottom: 1px solid rgba(210,154,60,.45); }
.byline-link:hover { color: var(--amber); }

/* A section head outside a rail carries the page gutter itself. */
.section-head.padded { margin: 0 var(--pad); }
/* Inside an already-padded header the title must not pay the gutter twice. */
.page-title.flush { margin-left: 0; margin-right: 0; }

/* ------------------------------------------------- sort */

.sort-row { display: flex; align-items: center; gap: 10px; padding: 12px var(--pad) 0; }
.sort-label {
  font: 400 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: rgba(236,228,214,.45);
}
.sort-select {
  font: 300 14px/1 var(--serif); color: var(--ink); cursor: pointer;
  background: transparent; border: 1px solid var(--line-soft); border-radius: 999px;
  padding: 8px 12px;
}
.sort-select:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* ------------------------------------------------- ratings */

.scores { display: grid; gap: 10px; padding: 14px 0 4px; }
.score-line, .rate-line { display: flex; align-items: center; gap: 12px; }
.score-label {
  font: 400 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: rgba(236,228,214,.45); min-width: 92px;
}
.score-n { font: 300 15px/1 var(--serif); color: var(--ink); }
.stars { display: flex; gap: 3px; }
.star {
  font-size: 15px; line-height: 1; color: rgba(236,228,214,.18);
  background: none; border: 0; padding: 0;
}
.star.on { color: var(--amber); }
.stars.pickable .star { cursor: pointer; padding: 3px; font-size: 20px; }
.stars.pickable .star:hover { color: var(--amber); }
.stars.pickable .star:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }

.rate-box {
  margin-top: 18px; padding: 16px; border: 1px solid var(--line-soft);
  border-radius: 12px; display: grid; gap: 10px;
}
.rate-title { font: 300 16px/1.2 var(--serif); color: var(--ink); }
.rate-note { font: 400 11px/1 var(--mono); color: rgba(236,228,214,.45); min-height: 11px; }
.quiet-note { font: 300 14px/1.5 var(--serif); color: rgba(236,228,214,.55); margin: 12px 0 0; }

/* ------------------------------------------------- saved for offline */

.chapter-row {
  display: flex; align-items: center; gap: 8px;
  border-bottom: 1px solid var(--line-soft);
}
.row-main {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: center;
  justify-content: space-between; gap: 12px;
  background: none; border: 0; text-align: left; font: inherit; color: inherit;
  padding: 13px 0; cursor: pointer;
}
.save-btn {
  flex: none; min-width: 34px; height: 30px; padding: 0 8px; cursor: pointer;
  border: 1px solid var(--line-soft); border-radius: 999px; background: none;
  color: rgba(236,228,214,.5); font: 400 11px/1 var(--mono);
}
.save-btn:hover { color: var(--ink); border-color: rgba(210,154,60,.45); }
.save-btn.on { color: var(--amber); border-color: rgba(210,154,60,.5); }
.save-btn:disabled { opacity: .7; cursor: default; }

/* ------------------------------------------------- voice page */

.voice-mark { font-size: 26px; }
.vtraits { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.vtrait {
  font: 400 10px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: rgba(236,228,214,.6); border: 1px solid var(--line-soft);
  border-radius: 999px; padding: 7px 11px;
}
.vnote { margin-top: 16px; font-size: 14px; color: rgba(236,228,214,.5); }
.dcard-role { font: 300 13px/1.3 var(--serif); color: var(--amber); margin-top: 2px; }
.cast-voice { color: rgba(210,154,60,.9); text-decoration: none; border-bottom: 1px solid rgba(210,154,60,.3); }
.cast-voice:hover { color: var(--amber); }
.vtagline { font: 300 15px/1.4 var(--serif); color: rgba(236,228,214,.6); margin-top: 6px; }

/* ------------------------------------------------- series page */

.srows { display: flex; flex-direction: column; padding: 8px var(--pad) 0; }
.srow {
  display: flex; gap: 14px; align-items: center; text-decoration: none;
  color: inherit; padding: 14px 0; border-bottom: 1px solid var(--line-soft);
}
.srow-art { width: 64px; height: 96px; flex: none; border-radius: 4px; object-fit: cover; }
.srow-text { min-width: 0; }
.srow-num {
  font: 400 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--amber);
}
.srow-title { font: 300 18px/1.25 var(--serif); color: var(--ink); margin: 6px 0 4px; }
.field-pair { display: flex; gap: 8px; }
.field-num { max-width: 84px; flex: none; }
.series-line { font: 300 14px/1.4 var(--serif); color: rgba(236,228,214,.7); margin-top: 8px; }

/* ------------------------------------------------- book page detail */

.blurb { margin: 16px 0 0; font: 300 15.5px/1.5 var(--serif); color: var(--ink-75); text-wrap: pretty; }
.blurb.clamped { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.link-btn {
  background: none; border: 0; padding: 4px 0 0; cursor: pointer;
  font: 400 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--amber);
}
.tag-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.row-right { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; flex: none; }
.row-when { font: 400 10px/1 var(--mono); color: rgba(236,228,214,.38); }

/* ------------------------------------------------- studio book list */

.book-list { display: flex; flex-direction: column; margin-top: 10px; }
.book-row {
  display: flex; align-items: center; gap: 12px; width: 100%; cursor: pointer;
  background: none; border: 0; border-bottom: 1px solid var(--line-soft);
  padding: 14px 0; text-align: left; font: inherit; color: inherit;
}
.book-row.on .book-row-title { color: var(--amber); }
.book-row-main { flex: 1 1 auto; min-width: 0; }
.book-row-title { font: 300 16px/1.3 var(--serif); color: var(--ink); }
.book-row-note { font: 400 10px/1 var(--mono); color: rgba(236,228,214,.4); margin-top: 5px; }
.book-state {
  flex: none; font: 400 10px/1 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; padding: 6px 10px; border-radius: 999px;
  border: 1px solid var(--line-soft); color: rgba(236,228,214,.55);
}
.book-state.good { color: #8fbf7a; border-color: rgba(143,191,122,.35); }
.book-state.hot { color: var(--amber); border-color: rgba(210,154,60,.45); }
.book-state.bad { color: #c96a5a; border-color: rgba(201,106,90,.4); }

/* ------------------------------------------------- author intake */

.steps { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 20px; }
.step {
  font: 400 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: rgba(236,228,214,.35); border: 1px solid var(--line-soft);
  border-radius: 999px; padding: 6px 10px;
}
.step.on { color: var(--amber); border-color: rgba(210,154,60,.5); }
.step.done { color: rgba(236,228,214,.6); }

.notes { border-left: 2px solid rgba(210,154,60,.4); padding: 2px 0 2px 14px; margin: 0 0 22px; }
.notes-title { font: 400 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--amber); }
.notes ul { margin: 10px 0 0; padding-left: 18px; }
.notes li { font: 300 14px/1.5 var(--serif); color: rgba(236,228,214,.7); margin-bottom: 7px; }

.consent-strong {
  border: 1px solid rgba(210,154,60,.35); border-radius: 10px;
  padding: 14px; background: rgba(210,154,60,.05);
}
.trust { margin-top: 16px; }
.trust p { margin: 0 0 6px; font: 400 11px/1.5 var(--mono); color: rgba(236,228,214,.45); }

.sec-list { display: flex; flex-direction: column; margin-top: 14px; }
.sec-row { border-bottom: 1px solid var(--line-soft); padding: 12px 0; }
.sec-head { display: flex; align-items: baseline; gap: 10px; cursor: pointer; }
.sec-tick { flex: none; width: 17px; height: 17px; accent-color: #d29a3c; }
.sec-title { flex: 1 1 auto; min-width: 0; font: 300 15px/1.3 var(--serif); color: var(--ink); }
.sec-words { flex: none; font: 400 10px/1 var(--mono); color: rgba(236,228,214,.38); }
.sec-badges { display: flex; gap: 6px; margin: 8px 0 0 27px; }
.sec-badge {
  font: 400 9.5px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: rgba(236,228,214,.5); border: 1px solid var(--line-soft);
  border-radius: 999px; padding: 5px 8px;
}
.sec-badge.warn { color: var(--amber); border-color: rgba(210,154,60,.4); }
.sec-issues { margin: 8px 0 0 27px; padding-left: 16px; }
.sec-issues li { font: 300 13px/1.45 var(--serif); color: rgba(236,228,214,.6); }
.sec-actions { margin: 8px 0 0 27px; }
.sec-text {
  margin: 10px 0 0 27px; padding: 12px; max-height: 260px; overflow: auto;
  background: rgba(0,0,0,.25); border: 1px solid var(--line-soft); border-radius: 8px;
  font: 300 13px/1.6 var(--serif); color: rgba(236,228,214,.78);
  white-space: pre-wrap; word-break: break-word;
}

/* ------------------------------------------------- work page steps */

.step:disabled { cursor: default; }
.step:not(:disabled) { cursor: pointer; }
.step.done:not(:disabled):hover { color: var(--ink); }

.say-list { display: flex; flex-direction: column; margin-top: 8px; }
.say-row { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.say-head { display: flex; align-items: center; gap: 10px; }
.say-name { flex: 0 0 96px; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.say-name .say-tag { font-size: 9px; padding: 3px 7px; }
.say-head .say-input { flex: 1 1 auto; min-width: 0; }
.say-head > :last-child { flex: none; }
.say-word { font: 400 16px/1.2 var(--serif); color: var(--ink); min-width: 96px; }
.say-input { flex: 1 1 160px; height: 38px; padding: 0 12px; }
.say-context { margin-top: 6px; font: 300 13px/1.45 var(--serif); color: rgba(236,228,214,.45); }

/* The pronunciation preview is the only play button on the site whose clip
   does not exist yet -- it is synthesised when pressed -- so it needs a
   waiting state the others never do. */
.play.loading { opacity: .55; cursor: progress; }
.play.loading .tri { animation: say-wait 1s ease-in-out infinite; }
@keyframes say-wait { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }

.render-state { padding: 4px 0 14px; }
.render-title { font: 300 22px/1.25 var(--serif); color: var(--ink); margin-top: 6px; }
.render-state.done .eyebrow { color: #8fbf7a; }
.render-state.bad .eyebrow { color: #c96a5a; }
.cta-block .link-btn { display: block; margin-top: 14px; text-align: center; text-decoration: none; }

/* ------------------------------------------------- title fields */

.title-pair { display: flex; flex-direction: column; gap: 6px; }
.title-pair .field-label {
  font: 400 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: rgba(236,228,214,.45); margin-top: 6px;
}
.title-pair .fine { margin-top: 2px; }

/* The cover picker on the intake form. The preview is a jacket, not a photo:
   fixed to the same 2:3 the server crops to, so what the author sees here is
   what the shelf will show. Without a size an un-styled <img> renders at the
   file's natural width and throws the form down the page. */
.cover-pick {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 6px;
}
.cover-pick #cover-preview {
  width: 56px;
  height: 84px;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--line);
  flex: none;
}

/* Sign-in gate over an input the author cannot use yet.
   Covers the control rather than sitting beside it: the point is that the
   requirement is met before the work is done, not after. */
.gated { position: relative; }
.gate {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 100%;
  border: 1px dashed var(--line);
  border-radius: 4px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(1.5px);
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--amber);
  cursor: pointer;
}
.gate:hover { background: color-mix(in srgb, var(--bg) 78%, transparent); }
/* `display` on a class beats the UA stylesheet's [hidden] { display: none },
   so without this the gate stays on screen after sign-in and locks the author
   out of the form it is guarding. Shipped exactly that way once. */
.gate[hidden] { display: none; }
.gate .gate-sub {
  font-family: var(--serif);
  font-size: 13.5px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-60);
}

/* The mascot's dead-end states. Centred, generous, and quiet: this is a screen
   someone reached by accident or before they had anything, so it should read as
   a pause rather than an error. The owl is dimmed slightly -- at full strength
   on this ground it pulls harder than the sentence it is illustrating. */
.state.state-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 4px;
  padding: 52px var(--pad) 46px;
}
.state-owl {
  width: 72px;
  height: 72px;
  opacity: .72;
  margin-bottom: 10px;
}
.state-empty-line {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-50);
}
.state-empty-detail {
  margin: 2px 0 0;
  max-width: 34ch;
  font-family: var(--serif);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-60);
  letter-spacing: 0;
}

/* The library's own empty state already had a title, a line of copy and a way
   out; it only wanted the bird. Slightly larger than the .state-empty owl
   because this screen is a destination, not a dead end. */
.empty-owl {
  width: 80px;
  height: 80px;
  opacity: .75;
  margin: 0 auto 14px;
  display: block;
}

/* The 404. Centred and quiet: whoever is here followed a link that no longer
   works, and the useful thing is a way onward rather than an apology. Styled in
   this stylesheet rather than inline so it inherits every token the rest of the
   site uses -- the page itself loads no script on purpose. */
.notfound {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 56px var(--pad) 72px;
}
.notfound-mark {
  font-family: var(--serif);
  font-size: 20px;
  color: var(--ink);
  text-decoration: none;
  margin-bottom: 40px;
}
.notfound-owl {
  width: 132px;
  height: 132px;
  opacity: .8;
  margin-bottom: 20px;
}
.notfound-kicker {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--amber);
  margin-bottom: 10px;
}
.notfound-title {
  margin: 0 0 12px;
  font-family: var(--serif);
  font-weight: 300;
  font-size: 28px;
  line-height: 1.22;
  color: var(--ink);
  max-width: 18ch;
}
.notfound-body {
  margin: 0 0 26px;
  max-width: 42ch;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink-65);
}
.notfound-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
}
.notfound-fine {
  margin-top: 40px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-40);
}

/* "About this book" on the upload form. Collapsed by default and deliberately
   quiet: the common case is paste a chapter and hear it, and a wall of selects
   in front of that would cost more uploads than the metadata is worth. */
.about {
  border: 1px solid var(--line);
  border-radius: 5px;
  margin-top: 14px;
  background: rgba(236, 228, 214, .02);
}
.about-summary {
  cursor: pointer;
  padding: 13px 14px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-75);
  list-style: none;
}
.about-summary::-webkit-details-marker { display: none; }
.about-summary::before {
  content: '+ ';
  color: var(--amber);
}
.about[open] .about-summary::before { content: '\2212 '; }
.about-hint {
  text-transform: none;
  letter-spacing: 0;
  font-family: var(--serif);
  font-size: 13px;
  color: var(--ink-45);
}
.about-body {
  padding: 2px 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Two across on a desktop, stacked on a phone -- these are short fields and a
   full-width select for "Language" looks like a mistake. */
.about-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
@media (max-width: 560px) {
  .about-row { grid-template-columns: 1fr; }
}
.check {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-top: 12px;
  font-family: var(--serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-75);
  cursor: pointer;
}
.check input { margin-top: 3px; flex: none; }

/* The tag picker. Chips rather than a text field: the list is closed, so the
   interface should look closed. Grouped headings keep 47 options scannable
   without a scrollbar inside a form. */
.tag-picker { margin-top: 4px; }
.tag-group {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-40);
  margin: 12px 0 6px;
}
.tag-row { display: flex; flex-wrap: wrap; gap: 6px; }
.tag-chip {
  font-family: var(--serif);
  font-size: 13.5px;
  line-height: 1;
  padding: 7px 11px;
  border-radius: 999px;
  border: 1px solid var(--line-btn);
  background: none;
  color: var(--ink-75);
  cursor: pointer;
}
.tag-chip:hover:not(:disabled) { border-color: var(--amber); color: var(--ink); }
.tag-chip.on {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--bg);
}
/* Full: the remaining chips dim rather than vanish, so the cap reads as a
   limit that has been reached and not as options that were never there. */
.tag-chip.is-full { opacity: .3; cursor: default; }
.tag-count {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--amber);
  letter-spacing: .06em;
}

/* One tag chosen: the count turns from a quiet hint into something asking to
   be finished. Amber for "in progress", not red -- nothing is wrong yet. */
.tag-count.is-short { color: var(--amber-bright); }

/* ------------------------------------------------- the studio wall

   Covers, not titles. An author recognises their own book by its jacket, and
   the title is already printed on it -- a list of names is how you read
   someone else's catalogue, not your own shelf. */

.studio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 16px 12px;
  padding: 10px var(--pad) 0;
}
.tile {
  background: none; border: 0; padding: 0; cursor: pointer;
  display: flex; flex-direction: column; gap: 7px; text-align: left;
  color: inherit; font: inherit;
}
/* The frame holds the 2:3 whatever the art is, so one book with no cover does
   not shorten its row. */
.tile-frame {
  aspect-ratio: 2 / 3;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--panel);
}
.tile-frame > * { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A queued book has no cover yet and should not pretend otherwise. */
.tile-frame.waiting { opacity: .45; border-style: dashed; }
.tile:hover .tile-frame { border-color: var(--line-btn); }
.tile:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.tile .book-state { align-self: flex-start; }

.detail-head {
  display: grid;
  grid-template-columns: 108px 1fr;
  gap: 16px;
  align-items: start;
  margin-top: 14px;
}
.detail-title { font: 300 24px/1.2 var(--serif); color: var(--ink); }
.detail-author { font: 300 15px/1.3 var(--serif); color: var(--ink-60); margin-top: 4px; }
.detail-actions { display: flex; gap: 10px; margin-top: 18px; }
.detail-actions > * { flex: 1 1 0; text-align: center; }

/* The "submit a book" tile. Same footprint as a jacket, drawn rather than
   printed, so the way to make a new book sits in the grid of books instead of
   shouting underneath it. */
.tile-add { text-decoration: none; }
.tile-frame.dashed {
  border-style: dashed;
  border-color: var(--line-btn);
  display: flex; align-items: center; justify-content: center;
  background: none;
}
.tile-add-mark { font: 300 30px/1 var(--serif); color: var(--amber); }
.tile-add-label {
  font: 400 10px/1.2 var(--mono); letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-50);
}
.tile-add:hover .tile-frame.dashed { border-color: var(--amber); }
.tile-add:hover .tile-add-label { color: var(--ink); }

/* ------------------------------------------------- waiting

   The owl, while something loads. It used to be a line of grey text, and the
   bird only ever appeared at dead ends -- so the product had a face for "there
   is nothing here" and none for "this is coming". */

.state-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 44px var(--pad);
  text-align: center;
}
.loading-owl {
  width: 56px;
  height: 56px;
  opacity: .8;
  /* Breathing, not spinning. Most of these waits are a second or two, and a
     spinner turns a short wait into an emergency. */
  animation: owl-breathe 2.4s ease-in-out infinite;
}
@keyframes owl-breathe {
  0%, 100% { transform: scale(1);    opacity: .62; }
  50%      { transform: scale(1.06); opacity: .95; }
}
/* Someone who asked not to see motion still gets the bird, just still. */
@media (prefers-reduced-motion: reduce) {
  .loading-owl { animation: none; opacity: .8; }
}
.loading-line {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-50);
}

/* THE FOOTER. Brand block, link columns, fine-print bar. Every block sets its
   own display because an older rule makes every footer div a flex row. */
.site-foot { display: block; }
.site-foot .foot-main { display: flex; flex-direction: column; gap: 30px; }
.site-foot .foot-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
/* Scoped under .site-foot: an older `.site-foot a { color: inherit }` otherwise
   wins and greys the wordmark out. */
.site-foot .foot-mark { display: inline-flex; align-items: center; gap: 9px;
             font: 400 19px/1 var(--serif); color: var(--ink); }
.foot-mark img { display: block; width: 26px; height: 26px; }
.foot-tag { margin: -2px 0 4px; font: 300 14px/1.4 var(--serif); color: rgba(236,228,214,.6); }
.foot-badge { display: inline-block; line-height: 0; margin: 2px 0; }
.foot-badge img { display: block; width: 120px; height: 40px; }
.site-foot .foot-socials { display: flex; gap: 10px; }
.site-foot .foot-brand { display: grid; grid-template-columns: 1fr auto;
                         grid-template-areas: "mark socials" "tag badge";
                         align-items: center; column-gap: 16px; row-gap: 14px; }
.site-foot .foot-brand .foot-mark { grid-area: mark; }
.site-foot .foot-brand .foot-socials { grid-area: socials; justify-self: end; }
.site-foot .foot-brand .foot-tag { grid-area: tag; margin: 0; }
.site-foot .foot-brand .foot-badge { grid-area: badge; justify-self: end; }
.foot-social { display: inline-flex; align-items: center; justify-content: center;
               width: 36px; height: 36px; border-radius: 50%;
               background: rgba(236,228,214,.08); transition: background .15s; }
.foot-social:hover { background: rgba(236,228,214,.16); }
.foot-social img { display: block; width: 18px; height: 18px; }
/* Two columns of links on a phone, three across on a desktop. */
.site-foot .foot-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 32px; }
.site-foot .foot-col { display: flex; flex-direction: column; gap: 7px; }
.site-foot .foot-bar { display: flex; flex-direction: column; gap: 6px; margin-top: 30px;
                       padding-top: 16px; border-top: 1px solid var(--line-soft);
                       font: 300 12px/1.4 var(--serif); color: rgba(236,228,214,.38); }
@media (min-width: 900px) {
  .site-foot .foot-main { flex-direction: row; justify-content: space-between; gap: 48px; }
  .site-foot .foot-brand { flex: 0 0 360px; }
  .site-foot .foot-cols { grid-template-columns: repeat(3, minmax(120px, auto)); }
  .site-foot .foot-bar { flex-direction: row; justify-content: space-between; }
}

/* ------------------------------------------------------- the intake wizard
 *
 * Three panels in one card rather than one long form. The card holds a floor
 * height so stepping from a five-field panel to a two-field one does not
 * collapse the page under the reader's cursor.
 */
.wiz-head { display: flex; justify-content: space-between; align-items: baseline;
            gap: 12px; margin: 0 0 16px; font: 500 11.5px/1 var(--mono);
            letter-spacing: .09em; text-transform: uppercase; }
#wiz-count { color: var(--amber); }
#wiz-name { color: rgba(236,228,214,.42); }
.wiz { min-height: 260px; animation: wiz-in .22s ease both; }
.wiz[hidden] { display: none; }
/* `hidden` is display:none from the UA sheet, which a class that sets
   display:flex outranks. Both of these need saying explicitly. */
.steps[hidden] { display: none; }
@keyframes wiz-in { from { opacity: 0; transform: translateX(10px); }
                    to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .wiz { animation: none; } }
.wiz-nav { margin-top: 20px; display: flex; gap: 10px; align-items: center; }
.wiz-nav .btn, .wiz-nav .btn-ghost { flex: 0 0 auto; width: auto; padding: 0 26px; }
.wiz-lede { margin: 0 0 18px; font: 300 15.5px/1.5 var(--serif);
            color: rgba(236,228,214,.72); }

/* ------------------------------------------------------- the author's page
 *
 * A bio and a set of links, both absent until the author writes them. The
 * page reads as a stock-take without these: counts of books and chapters and
 * nothing about the person who wrote them.
 */
.author-bio { margin: 10px 0 0; max-width: 56ch;
              font: 300 15.5px/1.6 var(--serif); color: rgba(236,228,214,.74); }
.author-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.author-link { font: 500 11.5px/1 var(--mono); letter-spacing: .06em;
               text-transform: uppercase; text-decoration: none;
               color: var(--amber); border: 1px solid rgba(210,154,60,.34);
               border-radius: 999px; padding: 7px 13px; }
.author-link:hover { border-color: var(--amber); background: rgba(210,154,60,.09); }

/* The author profile form in the studio. */
.profile-form { margin-top: 26px; padding-top: 4px; }
.profile-byline { font: 300 20px/1.2 var(--serif); color: var(--ink); margin: 2px 0 16px; }
.links-list { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.links-row { display: flex; gap: 8px; align-items: center; }
.links-row .link-kind { flex: 0 0 132px; }
.links-row .link-url { flex: 1 1 auto; min-width: 0; }
.link-drop { flex: none; width: 34px; height: 34px; border-radius: 8px;
             background: none; border: 1px solid var(--line); color: var(--ink-60);
             font-size: 17px; line-height: 1; cursor: pointer; }
.link-drop:hover { border-color: #c96a5a; color: #c96a5a; }

/* The rights question sits on the confirm step, beside the tick it belongs
   to, rather than collapsed inside "About this book" where nobody saw it. */
.rights-pick { margin: 4px 0 16px; max-width: 320px; }

/* Editing the author page happens on the author page. */
.author-edit-slot:not(:empty) { margin-top: 16px; }
.author-edit { width: auto; padding: 0 18px; }
.author-editor { margin-top: 6px; max-width: 520px; }

/* ---------------------------------------------- who tells this chapter
   Studio cast step (work.js toldBy). A closed menu of this chapter's cast,
   never a text box; plus the two-step Add Narrator popup. */
.told-by { position: relative; margin: 6px 0 4px; }
.told-chapter { margin-top: 10px; }
.told-field {
  margin-top: 8px; display: inline-flex; align-items: center; gap: 12px;
  min-width: 240px; max-width: 100%; padding: 11px 14px;
  border: 1px solid var(--amber); border-radius: 6px; background: var(--panel);
  color: var(--ink); font: inherit; cursor: pointer; text-align: left;
}
.told-name { font-family: var(--serif); font-size: 18px; flex: 1; }
.told-voice { font-family: var(--mono); font-size: 11px; color: var(--ink-55); }
.told-field .caret { border-top-color: var(--ink-55); }
.told-status { margin: 10px 0 0; font-size: 14.5px; color: var(--ink-65); line-height: 1.5; }
.told-status .link-btn { color: var(--amber); font-family: var(--mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: .06em; }
.told-menu {
  position: absolute; z-index: 30; margin-top: 6px; min-width: 260px; max-width: calc(100vw - 44px);
  background: var(--panel-2); border: 1px solid var(--line-btn); border-radius: 6px;
  padding: 6px 0; box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
}
.told-group { padding: 6px 14px 4px; font-family: var(--mono); font-size: 10px;
  text-transform: uppercase; letter-spacing: .08em; color: var(--ink-45); }
.told-item {
  display: grid; grid-template-columns: 16px 1fr auto; align-items: center; gap: 8px;
  width: 100%; padding: 9px 14px; background: none; border: 0; color: var(--ink-85);
  font: inherit; font-size: 15px; text-align: left; cursor: pointer;
}
.told-item:hover { background: var(--panel); }
.told-item.on { color: var(--ink); }
.told-check { color: var(--amber); font-size: 13px; }
.told-item.add { display: block; color: var(--ink-75); font-size: 14px; }
.told-divider { height: 1px; background: var(--line); margin: 6px 0; }
.cast-line.narration-line { font-style: italic; color: var(--ink-60); }

.narr-panel { padding: 0 var(--pad) 18px; overflow-y: auto; }
.narr-panel .sheet-head { padding-left: 0; padding-right: 0; }
.narr-panel .sheet-list { padding: 0; }
.narr-panel .sheet-title { font-size: 22px; margin-top: 4px; }
.narr-progress { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 12px 0 4px; }
.narr-progress i { height: 3px; border-radius: 2px; background: var(--line); }
.narr-progress i.on { background: var(--amber); }
.narr-trait { display: grid; grid-template-columns: 80px 1fr; gap: 10px; align-items: start; margin: 10px 0; }
.narr-trait .eyebrow { margin-top: 8px; }
.narr-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.narr-pill { height: auto; padding: 6px 12px; font-size: 13px; }
.narr-foot { display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line); }
.narr-foot .smeta { margin-right: auto; }
.narr-foot .btn { width: auto; padding: 0 18px; }
.play.busy { opacity: .5; }
@media (max-width: 520px) {
  .narr-trait { grid-template-columns: 1fr; gap: 4px; }
  .told-field { min-width: 0; width: 100%; }
}

/* ------------------------------------------------- studio: ready to render */

.pending-list { display: flex; flex-direction: column; margin-top: 10px; }
.pending-row {
  display: flex; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--line-soft); padding: 14px 0;
}
.pending-row .book-row-main { flex: 1 1 auto; min-width: 0; }
.pending-chapter { font: 400 13.5px/1.35 var(--serif); color: var(--ink-60); margin-top: 3px; }
.pending-row .book-row-note { margin-top: 7px; line-height: 1.3; }
.pending-row .book-row-note.bad { color: #c96a5a; }
.pending-row .btn-ghost { flex: none; width: auto; height: 38px; padding: 0 16px; font-size: 14.5px; }
.pending-row .btn-ghost.go { border-color: rgba(210,154,60,.55); color: var(--amber-bright); }

/* ------------------------------------------------- required fields */

.field-error { font: 300 13.5px/1.4 var(--serif); color: #d98b6a; margin: 6px 0 0; }
.field.invalid { border-color: #c96a5a; }
.book-flags { display: flex; flex-direction: column; gap: 6px; margin: 18px 0 6px; }
.written-by { font: 300 15px/1.5 var(--serif); color: var(--ink-75); margin: 16px 0 0; }
.written-by span { color: var(--ink); }

/* A stage that is being worked on breathes, so a row that has said
   "Sampling" for two minutes reads as busy rather than stuck. */
@keyframes stage-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.book-row-note.pulsing { animation: stage-pulse 1.8s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .book-row-note.pulsing { animation: none; } }

.told-field.switching { cursor: default; }
.told-field.switching .told-name { animation: stage-pulse 1.8s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .told-field.switching .told-name { animation: none; } }

/* ------------------------------------------------------------- pricing
   Redesigned 2026-10-02 from the Claude Design handoff (pricing-handoff).
   Prices reserve their room (min-height) and show bars until the API answers,
   so nothing moves when they arrive. */
.pr { padding: 36px var(--pad) 64px; display: flex; flex-direction: column; gap: 56px; }
.pr-hero { display: flex; flex-direction: column; gap: 16px; max-width: 680px; }
.pr-h1 { margin: 0; font: 300 40px/1.08 var(--serif); letter-spacing: -.01em; text-wrap: balance; }
.pr-h1 em { color: var(--amber-bright); }
.pr-lede { margin: 0; font-size: 17px; line-height: 1.5; color: var(--ink-75); text-wrap: pretty; }
.pr-cta { width: auto; align-self: flex-start; display: inline-flex; align-items: center; padding: 0 24px;
          text-decoration: none; margin-top: 6px; }
.pr-plans-section { display: flex; flex-direction: column; gap: 18px; scroll-margin-top: 16px; }
.pr-founding { border: 1px solid var(--amber); background: rgba(210,154,60,.08); border-radius: 10px;
               padding: 20px 22px; display: flex; flex-direction: column; gap: 6px; }
.pr-founding .eyebrow { color: var(--amber-bright); }
.pr-founding-title { font-size: 22px; line-height: 1.25; }
.pr-plans-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; }
.pr-h2 { margin: 0; font: 400 28px/1.2 var(--serif); }
.pr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px; }
.pr-card { border: 1px solid var(--line); border-radius: 10px; background: var(--panel); padding: 24px;
           display: flex; flex-direction: column; gap: 18px; }
.pr-who { font-size: 24px; margin-top: 4px; }
.pr-price { display: flex; flex-direction: column; gap: 8px; min-height: 92px; }
.pr-bar { border-radius: 4px; background: var(--panel-2); }
.pr-was-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pr-was { font-size: 18px; color: var(--ink-55); text-decoration: line-through; }
.pr-save { font: 500 11px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--bg);
           background: var(--amber); border-radius: 4px; padding: 4px 7px; }
.pr-now { display: flex; align-items: baseline; gap: 6px; }
.pr-now > span:first-child { font-size: 48px; font-weight: 300; line-height: 1; }
.pr-per { font-size: 17px; color: var(--ink-65); }
.pr-sub { font-size: 15px; line-height: 1.5; color: var(--ink-68); }
.pr-ticks { list-style: none; margin: 0; padding: 16px 0 0; border-top: 1px solid var(--line-soft);
            display: flex; flex-direction: column; gap: 8px; font-size: 16px; line-height: 1.4; }
.pr-ticks li::before { content: '\2713'; color: var(--amber); margin-right: 10px; }
.pr-fine { margin: 0; font-size: 15px; line-height: 1.5; color: var(--ink-65); }
.pr-section { display: flex; flex-direction: column; gap: 22px; border-top: 1px solid var(--line); padding-top: 40px; }
.pr-features { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 26px 32px; }
.pr-f-title { font-size: 18px; }
.pr-f-body { font-size: 15px; line-height: 1.5; color: var(--ink-65); margin-top: 6px; text-wrap: pretty; }
.pr-faq { gap: 6px; max-width: 760px; }
.pr-faq .pr-h2 { margin-bottom: 10px; }
.pr-q { padding: 14px 0; border-bottom: 1px solid var(--line-soft); }
.pr-close { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; background: var(--panel);
            border-radius: 10px; padding: 32px 26px; }
.pr-close-title { margin: 0; font: 300 30px/1.15 var(--serif); text-wrap: balance; }
@media (min-width: 900px) { .pr { padding-inline: 40px; } }

/* ------------------------------------------------------------- paywall sheet
   paywall.js: a bottom sheet on a phone, a centred panel from 900px. */
.pw { position: fixed; inset: 0; z-index: 70; }
.pw-scrim { position: absolute; inset: 0; background: rgba(10, 9, 8, .7); opacity: 0; transition: opacity .2s ease; }
.pw-panel { position: absolute; left: 0; right: 0; bottom: 0; max-height: 92vh; overflow-y: auto;
            background: var(--panel); border-top: 1px solid var(--line); border-radius: 16px 16px 0 0;
            padding: 10px 22px calc(26px + env(safe-area-inset-bottom)); display: flex; flex-direction: column; gap: 16px;
            transform: translateY(24px); opacity: 0; transition: transform .22s ease, opacity .22s ease; }
.pw.in .pw-scrim { opacity: 1; }
.pw.in .pw-panel { transform: none; opacity: 1; }
.pw-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--ink-32); align-self: center; }
.pw-head { display: flex; flex-direction: column; gap: 6px; }
.pw-title { font-size: 24px; line-height: 1.2; text-wrap: balance; }
.pw-body { margin: 0; font-size: 15px; line-height: 1.45; color: var(--ink-75); }
.pw-founding { font: 11px/1.4 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--amber-bright); }
.pw .toggle { align-self: flex-start; }
.pw-plans { display: flex; flex-direction: column; gap: 8px; }
.pw-wait { min-height: 68px; border-radius: 8px; background: var(--panel-2); }
.pw-plan { min-height: 68px; padding: 12px 14px; border-radius: 8px; border: 1px solid var(--line);
           background: transparent; color: var(--ink); display: grid; grid-template-columns: 20px minmax(0, 1fr) auto;
           gap: 12px; align-items: center; text-align: left; cursor: pointer; font: inherit; }
.pw-plan.on { border-color: var(--amber); background: rgba(210,154,60,.1); }
.pw-dot { width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--ink-40); }
.pw-plan.on .pw-dot { border: 5px solid var(--amber); }
.pw-plan-name { display: flex; flex-direction: column; gap: 2px; font-size: 17px; }
.pw-plan-sub { font-size: 13px; color: var(--ink-65); }
.pw-plan-price { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.pw-was { font-size: 13px; color: var(--ink-55); text-decoration: line-through; }
.pw-now { font-size: 20px; }
.pw-per { font-size: 13px; color: var(--ink-65); }
.pw-act { display: flex; flex-direction: column; gap: 8px; }
.pw-ticks { display: flex; flex-direction: column; gap: 10px; }
.pw-act .btn-ghost { width: 100%; }
.pw-note { margin: 0; font-size: 13px; line-height: 1.45; color: var(--ink-60); text-align: center; }
.pw-link { border-top: 1px solid var(--line-soft); padding-top: 12px; text-align: center; font-size: 14px;
           color: var(--ink-65); text-decoration: none; }
body.pw-open { overflow: hidden; }
@media (min-width: 900px) {
  .pw-panel { left: 50%; right: auto; bottom: auto; top: 50%; width: 430px; border-radius: 16px;
              border: 1px solid var(--line); transform: translate(-50%, calc(-50% + 16px)); }
  .pw.in .pw-panel { transform: translate(-50%, -50%); }
  .pw-handle { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pw-scrim, .pw-panel { transition: none; }
}


/* ONE PLAYER (2026-10-03, Azam). The Continue bar is the player paused: on a
   desktop it is the same wide card, and either one minimises to the small
   corner card (.bar-size, body.player-mini). Phones keep their compact cards. */
.bar-size, .resume-play { display: none; }
@media (min-width: 900px) {
  .resume-bar {
    left: 50%; right: auto; transform: translateX(-50%);
    width: calc(min(1120px, 100vw) - 48px); bottom: 24px;
    border-radius: 14px; padding: 10px 16px; gap: 12px;
    background: rgba(31,27,24,.97); backdrop-filter: blur(14px);
    box-shadow: 0 10px 30px rgba(0,0,0,.45);
  }
  .resume-bar .resume-play { display: inline-flex; flex: none; text-decoration: none; }
  .bar-size {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    width: 30px; height: 30px; border-radius: 50%; cursor: pointer;
    border: 1px solid var(--line-soft); background: none;
    color: rgba(236,228,214,.55); font-size: 15px; line-height: 1;
  }
  .bar-size:hover { color: var(--ink); }
  .miniplayer .bar-size { order: 8; }

  /* Minimised: the small card in the corner, play · title · size · close. */
  body.player-mini .miniplayer, body.player-mini .resume-bar {
    left: auto; right: 24px; transform: none; width: 380px;
  }
  body.player-mini .miniplayer .mini-desk,
  body.player-mini .miniplayer .mini-skip { display: none; }
  body.player-mini .miniplayer .mini-time { display: block; }
}
