/* =============================================================================
   Cuvinte Vii — letterpress devotional
   Pocket breviary, not magazine masthead. One voice, generous margin.
   ============================================================================= */

/* --- Theme tokens ---------------------------------------------------------- */

:root {
  /* paper / ink — verdigris vellum: pale sage page, copper-gilt marginalia */
  --paper:        #e8ede1;
  --paper-soft:   #dde4d4;
  --paper-edge:   #bcc7b1;
  --paper-deep:   #cfd9c3;

  --ink:          #1d1410;
  --ink-soft:     #3f4a35;
  --ink-faint:    #5a6b51;  /* 4.82:1 vs paper — passes WCAG AA for body text */
  --ink-ghost:    #a3b099;

  /* manuscript accents */
  --vermilion:    #8a2418;
  --gilt:         #ad7e3d;
  --gilt-soft:    #c19a64;
  --sepia:        #6c4a28;

  /* type families */
  --display:      "Fraunces", "EB Garamond", "Iowan Old Style", Georgia, serif;
  --body:         "Newsreader", "Iowan Old Style", "Charter", Georgia, serif;

  /* type tones — variable-font settings as named registers.
     Apply as: font-variation-settings: var(--type-display-quiet);
     The masthead title inlines its own settings since SOFT is scroll-linked. */
  --type-display-quiet: "opsz" 36;
  --type-text-italic:   "opsz" 18;

  /* rhythm */
  --rule:         1px solid color-mix(in oklab, var(--ink) 22%, transparent);
  --rule-faint:   1px solid color-mix(in oklab, var(--ink) 12%, transparent);

  /* layout */
  --player-h:     6.25rem;

  /* Stacking sticky bars: search bar at top, chips below it, then group
     headers below the chips. Offsets are kept in sync via these vars. */
  --sticky-search-h: 2.6rem;
  --sticky-chips-h:  2.55rem;
  --sticky-stack:    calc(var(--sticky-search-h) + var(--sticky-chips-h));

  color-scheme:   light;
}

[data-bs-theme="dark"] {
  /* Chapel at midnight: deep forest paper, the night cousin of verdigris vellum.
     Warm gilt + vermilion marginalia carry across themes; only the page changes. */
  --paper:        #111814;
  --paper-soft:   #18221b;
  --paper-edge:   #253526;
  --paper-deep:   #1c281e;

  --ink:          #d2dac6;
  --ink-soft:     #a8b09c;
  --ink-faint:    #869080;  /* 5.42:1 vs dark paper — passes WCAG AA */
  --ink-ghost:    #475240;

  --vermilion:    #be6451;
  --gilt:         #d3a064;
  --gilt-soft:    #e0bc80;
  --sepia:        #ad8c63;

  color-scheme:   dark;
}

/* --- Reset / base ---------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { height: 100%; }
/* body must use min-height (not height) so its padding-bottom contributes to
   scrollHeight. With height: 100%, the body is clamped to the viewport and
   padding-bottom lives *inside* the viewport-sized box — when main overflows,
   the padding can't push scroll past the player, so the last sections clip
   behind the fixed transport. */
body { min-height: 100%; }
html {
  scroll-padding-top: 4rem;
  scroll-padding-bottom: calc(var(--player-h) + 2rem);
}

body {
  margin: 0;
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.55;
  color: var(--ink);
  background-color: var(--paper);

  background-image:
    radial-gradient(900px 580px at 50% -10%,
      color-mix(in oklab, var(--gilt) 14%, transparent), transparent 60%),
    radial-gradient(900px 540px at 50% 110%,
      color-mix(in oklab, var(--vermilion) 5%, transparent), transparent 60%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.06 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-attachment: fixed, fixed, fixed;
  background-size: auto, auto, 220px 220px;
  background-blend-mode: normal, normal, multiply;

  padding-bottom: calc(var(--player-h) + env(safe-area-inset-bottom) + 1rem);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

[data-bs-theme="dark"] body {
  background-image:
    radial-gradient(900px 580px at 50% -10%,
      color-mix(in oklab, var(--gilt) 10%, transparent), transparent 60%),
    radial-gradient(900px 540px at 50% 110%,
      color-mix(in oklab, var(--vermilion) 6%, transparent), transparent 60%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.04 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-blend-mode: normal, normal, screen;
}

/* --- Helpers --------------------------------------------------------------- */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* app.js toggles `d-none` to swap play/pause icons */
.d-none { display: none !important; }

/* The `hidden` attribute must beat any `display: ...` rule we add — without
   this, elements like `.jump-chip` and `.scroll-top-btn` (which set
   `display: inline-flex`) tie the UA stylesheet on specificity and win by
   source order, leaking those controls onto the page when they should be
   hidden. */
[hidden] { display: none !important; }

.skip-link {
  position: absolute;
  top: 0.5rem; left: 0.5rem;
  padding: 0.5rem 0.9rem;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--body);
  font-size: 0.85rem;
  text-decoration: none;
  border-radius: 2px;
  transform: translateY(-200%);
  transition: transform 120ms ease;
  z-index: 1000;
}
.skip-link:focus-visible { transform: translateY(0); }

.theme-toggle {
  position: fixed;
  top: max(0.9rem, env(safe-area-inset-top));
  right: 0.9rem;
  z-index: 60;
  width: 2.75rem;  /* 44px — meets HIG/MD touch target minimum */
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--ink) 22%, transparent);
  background: color-mix(in oklab, var(--paper) 78%, transparent);
  color: var(--ink-soft);
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: color 160ms ease, border-color 160ms ease, background 160ms ease, transform 160ms ease;
}

.theme-toggle:hover {
  color: var(--gilt);
  border-color: color-mix(in oklab, var(--gilt) 45%, transparent);
}

.theme-toggle:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--gilt) 60%, transparent);
  outline-offset: 2px;
}

.theme-toggle:active { transform: scale(0.96); }

.theme-toggle-icon { display: none; }
[data-bs-theme="light"] .theme-toggle-icon--moon,
[data-bs-theme="dark"]  .theme-toggle-icon--sun  { display: block; }

::selection {
  background: color-mix(in oklab, var(--gilt) 35%, transparent);
  color: var(--ink);
}

/* --- Masthead -------------------------------------------------------------- */
/* Compressed: title + scripture dedication only. No kicker, no separator rule. */

.masthead {
  padding: clamp(0.5rem, 2vw, 1rem) 1.25rem clamp(0.4rem, 1vw, 0.75rem);
  text-align: center;
  position: relative;
}

.masthead-inner {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
}

.masthead-title {
  /* --title-soft is updated by app.js on scroll for a gentle tilt. */
  --title-soft: 80;

  margin: 0;
  font-family: var(--display);
  font-weight: 380;
  font-style: italic;
  font-size: clamp(2rem, 7vw, 5rem);
  line-height: 0.96;
  letter-spacing: -0.025em;
  color: var(--gilt);
  font-variation-settings: "opsz" 144, "SOFT" var(--title-soft);
  transition: font-variation-settings 120ms linear;

  display: flex;
  flex-direction: row;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.22em;
}

.masthead-title-line { display: inline-block; }
.masthead-title-line--accent { color: var(--gilt); }

.dedication {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(0.95rem, 1.8vw, 1.1rem);
  line-height: 1.45;
  color: var(--ink-soft);
  letter-spacing: 0.005em;
}

.dedication em {
  font-style: italic;
  font-weight: 400;
  font-variation-settings: var(--type-text-italic);
}

/* Inline epigraph attribution: same italic hand as the verse,
   smaller and fainter so the hierarchy reads via tone, not family. */
.dedication-cite {
  font-family: var(--display);
  font-style: italic;
  font-variation-settings: var(--type-text-italic);
  font-size: 0.82em;
  color: var(--ink-faint);
  white-space: nowrap;
}

.dedication-cite::before {
  content: "\2009\2014\00A0";
  font-style: normal;
  color: var(--ink-faint);
}

/* --- Search bar ------------------------------------------------------------ */
/* Sticky thin band so the search is reachable from any scroll position. */

.search-bar {
  position: sticky;
  top: 0;
  z-index: 30;
  padding: 0.45rem clamp(1rem, 4vw, 2.5rem);
  background: color-mix(in oklab, var(--paper) 86%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  backdrop-filter: blur(10px) saturate(1.05);
  border-bottom: var(--rule-faint);
}

.search-bar .search {
  max-width: 720px;
  margin: 0 auto;
  position: relative;
  display: flex;
  align-items: center;
}

.search-icon {
  position: absolute;
  left: 0.1rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-faint);
  pointer-events: none;
  display: inline-flex;
}

.search-input {
  width: 100%;
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0.5rem 2.4rem 0.5rem 1.65rem;
  font-family: var(--body);
  font-size: 0.95rem;
  color: var(--ink);
  letter-spacing: 0.005em;
}

.search-input::placeholder {
  color: var(--ink-faint);
  font-style: italic;
}

.search-input:focus { outline: none; }

/* Visible focus ring for keyboard users; mouse focus stays clean. */
.search-input:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--gilt) 55%, transparent);
  outline-offset: 3px;
  border-radius: 2px;
}

.search-input:focus + .search-hint kbd {
  background: color-mix(in oklab, var(--gilt) 18%, transparent);
  border-color: var(--gilt);
  color: var(--gilt);
}

.search-hint {
  position: absolute;
  right: 0.25rem;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
}

.search-hint kbd {
  display: inline-block;
  font-family: var(--body);
  font-size: 0.7rem;
  font-weight: 500;
  padding: 0.12rem 0.42rem;
  color: var(--ink-faint);
  background: color-mix(in oklab, var(--ink) 6%, transparent);
  border: 1px solid color-mix(in oklab, var(--ink) 18%, transparent);
  border-radius: 3px;
  line-height: 1;
  transition: all 180ms ease;
}

/* --- Collection chips ------------------------------------------------------ */
/* Hairline pills, gilt-tinted when selected — closer to manuscript marginalia
   than Material chips. Hybrid overflow strategy:
     - Desktop (>580 px): wraps onto multiple rows so all ~18 collections are
       reachable at-a-glance. Sticky position; downstream group headers track
       its real height via a ResizeObserver-set --sticky-chips-h.
     - Mobile (≤580 px): single-row horizontal scroll with fade-edge mask so
       the chip strip doesn't eat the entire first viewport. Wrapping mobile
       chips means ~13 rows tall, ~70 % of screen, no content visible. */

.chips {
  position: sticky;
  top: var(--sticky-search-h);
  z-index: 25;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.4rem;
  padding: 0.45rem clamp(1rem, 4vw, 2.5rem);
  background: color-mix(in oklab, var(--paper) 86%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  backdrop-filter: blur(10px) saturate(1.05);
  border-bottom: var(--rule-faint);
}

@media (max-width: 580px) {
  .chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    scroll-padding-inline: 1rem;
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 1.25rem, #000 calc(100% - 1.25rem), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 1.25rem, #000 calc(100% - 1.25rem), transparent 100%);
  }
  .chips::-webkit-scrollbar { display: none; }
}

.chip {
  flex-shrink: 0;
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.32rem 0.78rem;
  border: 1px solid color-mix(in oklab, var(--ink) 16%, transparent);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--body);
  font-size: 0.85rem;
  letter-spacing: 0.005em;
  cursor: pointer;
  transition: border-color 180ms ease, color 180ms ease, background-color 180ms ease;
}

.chip-count {
  font-variant-numeric: tabular-nums;
  font-size: 0.74rem;
  color: var(--ink-faint);
  letter-spacing: 0.04em;
}

.chip:hover {
  border-color: color-mix(in oklab, var(--ink) 28%, transparent);
  color: var(--ink);
}

.chip:focus-visible {
  outline: none;
  border-color: var(--gilt);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--gilt) 28%, transparent);
}

.chip.is-active {
  border-color: var(--gilt);
  background: color-mix(in oklab, var(--gilt) 12%, transparent);
  color: var(--ink);
}
.chip.is-active .chip-count { color: var(--gilt); }

/* --- Contents (track list) ------------------------------------------------- */

.contents {
  max-width: 880px;
  margin: 0 auto;
  padding: 0.5rem clamp(0.75rem, 4vw, 2.5rem) 0;
}

/* Single shared reveal — all main regions rise together. */
.masthead-inner,
.search-bar,
.contents {
  animation: rise 700ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.is-hidden { display: none !important; }

/* --- Continue-listening rail ----------------------------------------------- */

.rail {
  margin: 0.4rem 0 1.4rem;
  padding: 0.85rem 0 0.4rem;
  border-top: var(--rule-faint);
  border-bottom: var(--rule-faint);
}

.rail-title {
  margin: 0 0 0.35rem;
  font-family: var(--display);
  font-style: italic;
  font-weight: 420;
  font-size: 0.82rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.rail-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rail-item {
  --pct: 0%;
  display: flex;
  width: 100%;
  margin: 0;
  padding: 0.6rem 0.4rem 0.55rem;
  background: transparent;
  border: 0;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  position: relative;
  border-top: var(--rule-faint);
  transition: background-color 220ms ease, padding-left 280ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.rail-list > li:first-child .rail-item { border-top: 0; }

.rail-item:hover {
  background: color-mix(in oklab, var(--paper-soft) 55%, transparent);
  padding-left: 1rem;
}

.rail-item:focus-visible {
  outline: none;
  background: color-mix(in oklab, var(--paper-soft) 70%, transparent);
  box-shadow: inset 2px 0 0 var(--gilt);
  padding-left: 1rem;
}

/* Active rail item: when the currently-playing track is also in the rail
   (common — user resumed it from here), mirror the gilt tint + italic
   title used in the main list so the visual link is obvious. */
.rail-item.active {
  background: linear-gradient(
    to right,
    color-mix(in oklab, var(--gilt) 12%, transparent),
    color-mix(in oklab, var(--gilt) 3%, transparent) 70%,
    transparent
  );
  padding-left: 1rem;
  box-shadow: inset 2px 0 0 var(--gilt);
}
.rail-item.active .rail-item-title {
  font-style: italic;
  color: var(--gilt);
}

.rail-item-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.16rem;
}

.rail-item-title {
  font-family: var(--display);
  font-weight: 420;
  font-size: 1rem;
  line-height: 1.25;
  color: var(--ink);
  font-variation-settings: var(--type-display-quiet);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rail-item-meta {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  min-width: 0;
  font-family: var(--body);
  font-size: 0.78rem;
  color: var(--ink-faint);
}

.rail-item-sub {
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.rail-item-dot { flex-shrink: 0; opacity: 0.6; }

.rail-item-left {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.03em;
  color: var(--gilt);
}

.rail-item-progress {
  display: block;
  height: 1px;
  margin-top: 0.3rem;
  pointer-events: none;
  background: color-mix(in oklab, var(--ink) 8%, transparent);
}
.rail-item-progress > span {
  display: block;
  height: 100%;
  width: var(--pct, 0%);
  background: linear-gradient(to right, var(--gilt) 0%, var(--gilt-soft) 100%);
}

/* Folded extras: only the most-recent track shows until the rail is expanded,
   so the rail stays a single row regardless of how many tracks are mid-listen. */
.rail:not([data-expanded="true"]) .rail-extra { display: none; }
.rail[data-expanded="true"] .rail-extra { animation: rail-extra-in 240ms ease both; }

@keyframes rail-extra-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.rail-more {
  display: inline-flex;
  align-items: center;
  gap: 0.32rem;
  margin: 0.1rem 0 0;
  padding: 0.35rem 0.4rem;
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: var(--body);
  font-style: italic;
  font-size: 0.8rem;
  color: var(--ink-faint);
  transition: color 180ms ease;
}
.rail-more:hover { color: var(--gilt); }
.rail-more:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--gilt) 60%, transparent);
  outline-offset: 2px;
  border-radius: 3px;
}
.rail-more-chevron { transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1); }
.rail[data-expanded="true"] .rail-more-chevron { transform: rotate(180deg); }

@media (prefers-reduced-motion: reduce) {
  .rail[data-expanded="true"] .rail-extra { animation: none; }
  .rail-more-chevron { transition: none; }
}

/* --- Track groups (chapter divisions) -------------------------------------- */

.track-groups {
  display: block;
}

.track-group {
  border-top: var(--rule-faint);
}
.track-group:first-of-type { border-top: 0; }

.track-group-details {
  margin: 0;
}

.track-group-summary {
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  padding: 0.95rem 0.4rem 0.65rem;
  cursor: pointer;
  user-select: none;

  /* Stick to the bottom of the chips bar so the user always knows which
     collection they're scrolling through. The summary is positioned within
     its `<details>` parent, so when the whole group scrolls past, the next
     group's summary takes over without overlap. */
  position: sticky;
  top: var(--sticky-stack);
  z-index: 20;
  background: color-mix(in oklab, var(--paper) 90%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(1.05);
  backdrop-filter: blur(8px) saturate(1.05);
  border-bottom: var(--rule-faint);
}
.track-group-summary::-webkit-details-marker { display: none; }
.track-group-summary::marker { content: ""; }

.track-group-summary:focus-visible {
  outline: none;
  box-shadow: inset 2px 0 0 var(--gilt);
  background: color-mix(in oklab, var(--paper-soft) 50%, transparent);
}

.track-group-chevron {
  display: inline-flex;
  align-items: center;
  width: 0.85rem;
  flex-shrink: 0;
  color: var(--ink-faint);
  transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.track-group-details[open] > .track-group-summary .track-group-chevron {
  transform: rotate(90deg);
}

.track-group-title {
  flex: 1;
  min-width: 0;
  font-family: var(--display);
  font-style: italic;
  font-weight: 420;
  font-size: 1.05rem;
  line-height: 1.2;
  letter-spacing: -0.005em;
  color: var(--gilt);
  font-variation-settings: var(--type-display-quiet);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.track-group-count {
  flex-shrink: 0;
  font-family: var(--body);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

.track-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.track-list > li {
  border-bottom: var(--rule-faint);
}
.track-list > li:last-child {
  border-bottom: 0;
}

/* Each track is a button rendered by app.js. Structure:
   <button class="track" data-index data-progress style="--pct">
     <span class="track-index">
       <span class="number">1</span>
       <span class="playing-indicator"><span></span><span></span><span></span></span>
     </span>
     <span class="track-body">
       <span class="track-title"></span>
       <span class="track-meta">
         <span class="track-subtitle"></span>
         <span class="track-dot" aria-hidden="true">·</span>
         <span class="track-duration">12:34</span>
       </span>
       <span class="track-progress"><span></span></span>
     </span>
   </button>
*/

.track {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;

  width: 100%;
  margin: 0;
  padding: 1rem 0.5rem 1rem 0.4rem;

  background: transparent;
  border: 0;
  border-radius: 0;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  position: relative;

  transition:
    background-color 240ms ease,
    color 240ms ease,
    padding-left 280ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

.track::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 0;
  height: 1px;
  background: var(--gilt);
  transform: translateY(-50%);
  transition: width 320ms cubic-bezier(0.2, 0.7, 0.2, 1);
  pointer-events: none;
}

.track:hover {
  background: color-mix(in oklab, var(--paper-soft) 55%, transparent);
  padding-left: 1.1rem;
}
.track:hover::before { width: 0.6rem; }

.track:focus-visible {
  outline: none;
  background: color-mix(in oklab, var(--paper-soft) 70%, transparent);
  box-shadow: inset 2px 0 0 var(--gilt);
  padding-left: 1.1rem;
}

/* Active (currently playing) row: italic, gentle gradient tint, gilt rule */
.track.active {
  background: linear-gradient(
    to right,
    color-mix(in oklab, var(--gilt) 12%, transparent),
    color-mix(in oklab, var(--gilt) 3%, transparent) 70%,
    transparent
  );
  padding-left: 1.1rem;
}
.track.active::before {
  width: 0.6rem;
  background: var(--gilt);
}

/* Folio number: hidden by default, only emerges on touch / hover / active. */
.track-index {
  flex-shrink: 0;
  width: 1.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 1.05rem;
  font-variation-settings: var(--type-display-quiet);
  color: var(--ink-faint);
  letter-spacing: -0.01em;
  opacity: 0;
  transition: opacity 220ms ease;
}

.track:hover .track-index,
.track:focus-visible .track-index,
.track.active .track-index { opacity: 1; }

.track.active .track-index .number { display: none; }

.track-index .playing-indicator {
  display: none;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  height: 1.05rem;
  width: 100%;
}

.track.active .track-index .playing-indicator {
  display: inline-flex;
}

.track-index .playing-indicator > span {
  display: block;
  width: 3px;
  height: 35%;
  background: linear-gradient(to top, var(--gilt) 0%, var(--vermilion) 100%);
  border-radius: 2px 2px 1px 1px;
  transform-origin: bottom center;
  animation: wick 1.4s ease-in-out infinite;
}
.track-index .playing-indicator > span:nth-child(1) { animation-delay: -0.6s; }
.track-index .playing-indicator > span:nth-child(2) { animation-delay: -0.3s; }
.track-index .playing-indicator > span:nth-child(3) { animation-delay:  0s; }

#player[data-state="playing"] .track.active .track-index .playing-indicator > span {
  animation-play-state: running;
}
#player:not([data-state="playing"]) .track.active .track-index .playing-indicator > span {
  animation-play-state: paused;
  height: 35%;
}

@keyframes wick {
  0%, 100% { height: 30%; transform: scaleX(1); }
  35%      { height: 80%; transform: scaleX(1.05); }
  60%      { height: 65%; transform: scaleX(0.95); }
}

.track-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
}

.track-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  text-overflow: ellipsis;

  font-family: var(--display);
  font-weight: 420;
  font-size: 1.1rem;
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: var(--ink);
  font-variation-settings: var(--type-display-quiet);
  /* Cap at two lines worth of space so the row height stays predictable
     (line-height 1.25 × 1.1rem × 2 ≈ 2.75rem). */
  max-height: calc(1.25em * 2);
}

/* Highlight a search match in the track title. <mark> is injected by
   applyFilter() when state.query is non-empty; on clear, the title is
   restored to plain textContent. Background tint is gilt; foreground
   stays inherited so the typography reads as one phrase. */
.track-title mark {
  background: color-mix(in oklab, var(--gilt) 26%, transparent);
  color: inherit;
  padding: 0 0.08em;
  border-radius: 2px;
}

.track.active .track-title {
  font-style: italic;
  font-weight: 460;
  font-variation-settings: "opsz" 36, "SOFT" 60;
}

/* Subtitle + duration on a single line, mid-dot separator. */
.track-meta {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  min-width: 0;

  font-family: var(--body);
  font-size: 0.85rem;
  color: var(--ink-faint);
  letter-spacing: 0.005em;
}

.track-subtitle {
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.track-dot {
  flex-shrink: 0;
  opacity: 0.6;
}

.track-duration {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

.track.active .track-duration { color: var(--gilt); }

/* Resume-position rule: thin gilt under the title block (inside track-body),
   so the bookmark mirrors the read-passage, not the whole row. */
.track-progress {
  display: block;
  height: 1px;
  margin-top: 0.35rem;
  pointer-events: none;
}
.track-progress > span {
  display: block;
  height: 100%;
  width: var(--pct, 0%);
  background: linear-gradient(to right, var(--gilt) 0%, var(--gilt-soft) 100%);
  opacity: 0.6;
}
.track:not([data-progress]) .track-progress { display: none; }

/* --- Search status (aggregate match count) -------------------------------- */

.search-status {
  max-width: 880px;
  margin: 0 auto;
  padding: 0.35rem clamp(1rem, 4vw, 2.5rem) 0;
  font-family: var(--display);
  font-style: italic;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

/* --- Loading skeleton ------------------------------------------------------ */

.skeleton-row {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1rem 0.4rem;
  border-bottom: var(--rule-faint);
}

.skeleton-bar {
  display: block;
  height: 0.85rem;
  width: 78%;
  border-radius: 2px;
  background: linear-gradient(
    90deg,
    color-mix(in oklab, var(--ink) 8%, transparent) 0%,
    color-mix(in oklab, var(--ink) 14%, transparent) 50%,
    color-mix(in oklab, var(--ink) 8%, transparent) 100%
  );
  background-size: 220% 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
.skeleton-bar--short { width: 32%; height: 0.7rem; opacity: 0.7; }

@keyframes skeleton-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* --- Jump-to-current chip -------------------------------------------------- */
/* Floats above the player while the active track is off screen. */

.jump-chip {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--player-h) + env(safe-area-inset-bottom) + 0.6rem);
  z-index: 55;

  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  max-width: min(85vw, 26rem);
  padding: 0.42rem 0.85rem;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--gilt) 55%, transparent);
  background: color-mix(in oklab, var(--paper) 92%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  backdrop-filter: blur(10px) saturate(1.05);
  color: var(--ink);
  font-family: var(--body);
  font-size: 0.85rem;
  letter-spacing: 0.005em;
  cursor: pointer;
  box-shadow: 0 6px 18px -10px color-mix(in oklab, var(--gilt) 60%, transparent);
  animation: jump-chip-rise 220ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.jump-chip-mark {
  color: var(--gilt);
  font-size: 0.95rem;
  line-height: 1;
}

.jump-chip-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

#jump-chip-title { font-style: italic; }

.jump-chip:hover { border-color: var(--gilt); color: var(--ink); }
.jump-chip:focus-visible {
  outline: none;
  box-shadow:
    0 6px 18px -10px color-mix(in oklab, var(--gilt) 60%, transparent),
    0 0 0 3px color-mix(in oklab, var(--gilt) 30%, transparent);
}

@keyframes jump-chip-rise {
  from { opacity: 0; transform: translate(-50%, 0.4rem); }
  to   { opacity: 1; transform: translate(-50%, 0);       }
}

/* --- Scroll-to-top floating button ---------------------------------------- */

.scroll-top-btn {
  position: fixed;
  right: max(1rem, env(safe-area-inset-right));
  bottom: calc(var(--player-h) + env(safe-area-inset-bottom) + 0.6rem);
  z-index: 55;

  width: 2.5rem;
  height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--ink) 18%, transparent);
  background: color-mix(in oklab, var(--paper) 90%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  backdrop-filter: blur(10px) saturate(1.05);
  color: var(--ink-soft);
  cursor: pointer;
  box-shadow: 0 4px 14px -8px rgba(0, 0, 0, 0.25);
  animation: jump-chip-rise 220ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.scroll-top-btn:hover {
  color: var(--gilt);
  border-color: color-mix(in oklab, var(--gilt) 45%, transparent);
}

.scroll-top-btn:focus-visible {
  outline: none;
  border-color: var(--gilt);
  box-shadow:
    0 4px 14px -8px rgba(0, 0, 0, 0.25),
    0 0 0 3px color-mix(in oklab, var(--gilt) 28%, transparent);
}

/* On desktop+ the chip and FAB sit slightly higher relative to the slimmer player. */
@media (min-width: 720px) {
  .jump-chip,
  .scroll-top-btn {
    bottom: calc(var(--player-h) + env(safe-area-inset-bottom) + 0.85rem);
  }
}

/* --- Empty state ----------------------------------------------------------- */

.empty-state {
  margin: 4rem auto;
  max-width: 460px;
  text-align: center;
  font-family: var(--display);
  font-size: 1.05rem;
  color: var(--ink-soft);
  line-height: 1.6;
}

.empty-state-mark {
  display: block;
  font-size: 1.6rem;
  color: var(--gilt);
  margin-bottom: 0.85rem;
}

.empty-state code {
  font-family: ui-monospace, "SF Mono", "JetBrains Mono", monospace;
  font-size: 0.84em;
  background: color-mix(in oklab, var(--ink) 8%, transparent);
  padding: 1px 6px;
  border-radius: 2px;
}

/* --- Player (ribbon) ------------------------------------------------------- */
/* Slim. Top edge IS the seek bar — full-bleed 2px progress rule. */

.player {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 50;

  background-color: color-mix(in oklab, var(--paper) 92%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  backdrop-filter: blur(14px) saturate(1.1);

  padding-bottom: env(safe-area-inset-bottom);
}

[data-bs-theme="dark"] .player {
  background-color: color-mix(in oklab, var(--paper) 78%, #000 22%);
  box-shadow: 0 -16px 32px -28px rgba(0, 0, 0, 0.6);
}

/* The seek input IS the top edge of the player. Full-bleed 2px gilt rule. */
.seek {
  --pct: 0%;
  appearance: none;
  -webkit-appearance: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 14px; /* enlarged tap target — visible track is 2px at top */
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  z-index: 2;
}

/* WebKit: track + thumb */
.seek::-webkit-slider-runnable-track {
  height: 2px;
  border-radius: 0;
  background:
    linear-gradient(to right,
      var(--gilt) 0%, var(--gilt) var(--pct),
      color-mix(in oklab, var(--ink) 14%, transparent) var(--pct),
      color-mix(in oklab, var(--ink) 14%, transparent) 100%);
}
.seek::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px; height: 12px;
  margin-top: -5px;
  border-radius: 50%;
  background: var(--gilt);
  border: 2px solid var(--paper);
  box-shadow: 0 1px 2px rgba(0,0,0,0.18);
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 180ms ease, transform 180ms ease;
}
.seek:hover::-webkit-slider-thumb,
.seek:focus-visible::-webkit-slider-thumb,
.seek:active::-webkit-slider-thumb {
  opacity: 1;
  transform: scale(1);
}
.seek:focus-visible::-webkit-slider-thumb {
  box-shadow:
    0 0 0 4px color-mix(in oklab, var(--gilt) 30%, transparent),
    0 1px 2px rgba(0,0,0,0.18);
}

/* Firefox */
.seek::-moz-range-track {
  height: 2px;
  border-radius: 0;
  background: color-mix(in oklab, var(--ink) 14%, transparent);
}
.seek::-moz-range-progress {
  height: 2px;
  border-radius: 0;
  background: var(--gilt);
}
.seek::-moz-range-thumb {
  width: 12px; height: 12px;
  border: 2px solid var(--paper);
  border-radius: 50%;
  background: var(--gilt);
  box-shadow: 0 1px 2px rgba(0,0,0,0.18);
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 180ms ease, transform 180ms ease;
}
.seek:hover::-moz-range-thumb,
.seek:focus-visible::-moz-range-thumb,
.seek:active::-moz-range-thumb {
  opacity: 1;
  transform: scale(1);
}

.seek:focus-visible { outline: none; }

/* Inner ribbon row: meta | transport | speed */
.player-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0.85rem clamp(0.85rem, 3vw, 1.75rem) 0.7rem;

  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto auto;
  grid-template-areas:
    "meta speed"
    "transport transport";
  column-gap: 0.85rem;
  row-gap: 0.55rem;
  align-items: center;
}

@media (min-width: 720px) {
  .player-inner {
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-rows: auto;
    grid-template-areas: "meta transport speed";
    column-gap: clamp(1rem, 3vw, 2rem);
    row-gap: 0;
    padding: 0.7rem clamp(1rem, 3vw, 2rem);
  }
}

.player-meta {
  grid-area: meta;
  min-width: 0;
}

.player-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 440;
  font-size: clamp(0.98rem, 1.7vw, 1.12rem);
  line-height: 1.2;
  letter-spacing: -0.005em;
  color: var(--ink);
  font-variation-settings: var(--type-display-quiet);

  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.player-sub {
  margin: 0.12rem 0 0;
  font-family: var(--body);
  font-size: 0.82rem;
  color: var(--ink-faint);
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  min-width: 0;
}

.player-subtitle {
  font-style: italic;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.player-times {
  flex-shrink: 0;
  margin-left: auto;
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--ink-ghost);
}

.player[data-state="playing"] .player-times,
.player[data-state="paused"]  .player-times {
  color: var(--ink-faint);
}

/* Current-time mirrors the seek bar's gilt fill: same datum (how far you've
   read), now visually tied so the eye links the leading edge of the bar
   above with the numeric value below. Total stays in --ink-faint as a
   reference, not a focal value. */
.player[data-state="playing"] .time--current,
.player[data-state="paused"]  .time--current {
  color: var(--gilt);
}

.time-sep {
  color: var(--ink-ghost);
  opacity: 0.6;
}

.time { font-variant-numeric: tabular-nums; }

/* --- Transport ------------------------------------------------------------- */

.player-transport {
  grid-area: transport;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;  /* 8px — meets MD touch-spacing minimum between adjacent targets */
}

@media (min-width: 720px) {
  .player-transport { justify-self: center; }
}

.ctrl {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  width: 2.75rem;  /* 44px — meets HIG/MD touch target minimum */
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  cursor: pointer;
  position: relative;
  transition: color 180ms ease, background-color 200ms ease, transform 120ms ease;
}

.ctrl:hover {
  color: var(--ink);
  background: color-mix(in oklab, var(--ink) 7%, transparent);
}

.ctrl:focus-visible {
  outline: none;
  color: var(--ink);
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--gilt) 55%, transparent);
}

.ctrl:active { transform: translateY(1px); }

.ctrl--ghost svg { display: block; }

.ctrl--skip { position: relative; }
.ctrl-skip-label {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -45%);
  font-family: var(--body);
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  pointer-events: none;
  color: currentColor;
}

/* Primary play button: gilded coin, slightly slimmer than before. */
.ctrl--primary {
  width: 3rem;
  height: 3rem;
  margin: 0 0.2rem;
  background: radial-gradient(
    circle at 30% 25%,
    color-mix(in oklab, var(--gilt-soft) 90%, white) 0%,
    var(--gilt) 55%,
    color-mix(in oklab, var(--gilt) 70%, var(--sepia)) 100%
  );
  color: var(--paper);
  box-shadow:
    inset 0 0 0 1px color-mix(in oklab, var(--sepia) 70%, transparent),
    inset 0 1px 0 color-mix(in oklab, white 35%, transparent),
    0 4px 14px -6px color-mix(in oklab, var(--gilt) 70%, transparent);
  transition: transform 140ms ease, box-shadow 240ms ease;
}

.ctrl--primary:hover {
  transform: translateY(-1px);
  /* Re-assert the gradient: .ctrl:hover sets a translucent ink background
     that, with its higher specificity, would otherwise dissolve the coin —
     fatally so against the dark-mode player surface. */
  background: radial-gradient(
    circle at 30% 25%,
    color-mix(in oklab, var(--gilt-soft) 100%, white) 0%,
    var(--gilt) 55%,
    color-mix(in oklab, var(--gilt) 65%, var(--sepia)) 100%
  );
  box-shadow:
    inset 0 0 0 1px color-mix(in oklab, var(--sepia) 80%, transparent),
    inset 0 1px 0 color-mix(in oklab, white 45%, transparent),
    0 8px 20px -6px color-mix(in oklab, var(--gilt) 80%, transparent);
}

.ctrl--primary:focus-visible {
  box-shadow:
    inset 0 0 0 1px color-mix(in oklab, var(--sepia) 80%, transparent),
    inset 0 1px 0 color-mix(in oklab, white 35%, transparent),
    0 0 0 4px color-mix(in oklab, var(--gilt) 35%, transparent);
}

.ctrl--primary svg { display: block; color: #1d1410; }

[data-bs-theme="dark"] .ctrl--primary svg { color: #0a0e0c; }

/* Coin breath: subtle scale on the coin itself while playing.
   Paused on hover/active so it doesn't fight the lift transform. */
@keyframes coin-breath {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.025); }
}

#player[data-state="playing"] .ctrl--primary:not(:hover):not(:active) {
  animation: coin-breath 3.4s ease-in-out infinite;
}

/* --- Speed selector -------------------------------------------------------- */

.player-speed {
  grid-area: speed;
  justify-self: end;
}

.speed {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid color-mix(in oklab, var(--ink) 16%, transparent);
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--body);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  padding: 0.22rem 1.4rem 0.22rem 0.55rem;
  border-radius: 999px;
  cursor: pointer;
  letter-spacing: 0.02em;
  /* Chevron stroke is hand-pinned to the light-mode `--ink-faint`; keep in
     sync with the token (the dark-mode override below mirrors it). */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%235a6b51' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.5rem center;
  transition: border-color 180ms ease, color 180ms ease;
}

.speed:hover {
  border-color: color-mix(in oklab, var(--ink) 32%, transparent);
  color: var(--ink);
}

.speed:focus-visible {
  outline: none;
  border-color: var(--gilt);
  color: var(--ink);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--gilt) 28%, transparent);
}

[data-bs-theme="dark"] .speed {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23869080' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

/* --- Animations ------------------------------------------------------------ */

@keyframes rise {
  from { opacity: 0; transform: translateY(0.45rem); }
  to   { opacity: 1; transform: translateY(0);       }
}

/* --- Responsive tightening ------------------------------------------------- */

@media (max-width: 580px) {
  .masthead { padding-top: 0.85rem; padding-bottom: 0.4rem; }
  .track { gap: 0.7rem; padding: 0.9rem 0.4rem; }
  .track-title { font-size: 1rem; }
  .track-meta { font-size: 0.8rem; }
  /* Keep ≥44px on mobile — don't shrink below the touch target minimum. */
  .ctrl { width: 2.75rem; height: 2.75rem; }
  .ctrl--primary { width: 3rem; height: 3rem; }
  :root { --player-h: 8rem; }
}

/* --- Reduced motion -------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .skip-link { transition: none; }
}
