/* ==========================================================================
   有声书架 Mini App
   颜色一律优先取 Telegram themeParams 注入的 --tg-theme-* 变量；
   不在 Telegram 内时使用 --fb-* fallback，并按 prefers-color-scheme 切换。
   在 Telegram 内 app.js 会把 tg.colorScheme 写到 html[data-scheme]，
   让阴影、分隔线等非 themeParams 的颜色跟随 Telegram 的明暗。
   ========================================================================== */

:root {
  color-scheme: light dark;

  /* ---- fallback：浅色 ---- */
  --fb-bg: #ffffff;
  --fb-secondary-bg: #f1f2f6;
  --fb-section-bg: #ffffff;
  --fb-text: #16181d;
  --fb-hint: #868b96;
  --fb-link: #2481cc;
  --fb-button: #2481cc;
  --fb-button-text: #ffffff;
  --fb-separator: rgba(20, 24, 33, 0.08);
  --fb-destructive: #e0464b;

  --overlay-weak: rgba(20, 24, 33, 0.05);
  --skeleton: rgba(20, 24, 33, 0.07);
  --skeleton-hi: rgba(255, 255, 255, 0.65);
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.05), 0 1px 3px rgba(16, 24, 40, 0.04);
  --shadow-md: 0 2px 6px rgba(16, 24, 40, 0.05), 0 8px 24px rgba(16, 24, 40, 0.07);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.16);
  --banner-bg: #fff6d6;
  --banner-text: #7a5600;
  --banner-border: rgba(180, 130, 0, 0.18);
  --hero-strength: 0.32;

  /* ---- 语义色：themeParams 优先 ---- */
  --bg: var(--tg-theme-bg-color, var(--fb-bg));
  --secondary-bg: var(--tg-theme-secondary-bg-color, var(--fb-secondary-bg));
  --section-bg: var(--tg-theme-section-bg-color, var(--tg-theme-bg-color, var(--fb-section-bg)));
  --text: var(--tg-theme-text-color, var(--fb-text));
  --hint: var(--tg-theme-hint-color, var(--fb-hint));
  --subtitle: var(--tg-theme-subtitle-text-color, var(--hint));
  --section-header: var(--tg-theme-section-header-text-color, var(--hint));
  --link: var(--tg-theme-link-color, var(--fb-link));
  --accent: var(--tg-theme-button-color, var(--fb-button));
  --accent-text: var(--tg-theme-accent-text-color, var(--link));
  --on-accent: var(--tg-theme-button-text-color, var(--fb-button-text));
  --separator: var(--tg-theme-section-separator-color, var(--fb-separator));
  --destructive: var(--tg-theme-destructive-text-color, var(--fb-destructive));

  /* ---- 间距 ---- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --gutter: 16px;

  /* ---- 圆角 ---- */
  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-pill: 999px;

  /* ---- 字号 ---- */
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-md: 15px;
  --fs-lg: 17px;
  --fs-xl: 22px;
  --fs-2xl: 28px;

  /* ---- 动效 ---- */
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --dur-fast: 0.12s;
  --dur: 0.28s;

  /* ---- 字体：仅系统字体 ---- */
  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "PingFang SC",
    "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
  --font-serif: "Songti SC", "STSongti-SC-Regular", "STSong", "Noto Serif CJK SC", "Source Han Serif SC",
    "Noto Serif SC", "SimSun", serif;

  /* ---- 安全区 ---- */
  --safe-bottom: max(env(safe-area-inset-bottom, 0px), var(--tg-safe-area-inset-bottom, 0px));
}

/* fallback：深色（Telegram 外按系统设置；Telegram 内按 data-scheme） */
@media (prefers-color-scheme: dark) {
  :root:not([data-scheme="light"]) {
    --fb-bg: #17212b;
    --fb-secondary-bg: #0e1621;
    --fb-section-bg: #17212b;
    --fb-text: #f2f4f7;
    --fb-hint: #7d8b99;
    --fb-link: #6ab3f3;
    --fb-button: #5288c1;
    --fb-button-text: #ffffff;
    --fb-separator: rgba(255, 255, 255, 0.07);
    --fb-destructive: #ff6b6b;

    --overlay-weak: rgba(255, 255, 255, 0.06);
    --skeleton: rgba(255, 255, 255, 0.07);
    --skeleton-hi: rgba(255, 255, 255, 0.1);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.25), 0 8px 24px rgba(0, 0, 0, 0.25);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
    --banner-bg: #3a3016;
    --banner-text: #f3d68a;
    --banner-border: rgba(243, 214, 138, 0.16);
    --hero-strength: 0.42;
  }
}
:root[data-scheme="dark"] {
  --fb-bg: #17212b;
  --fb-secondary-bg: #0e1621;
  --fb-section-bg: #17212b;
  --fb-text: #f2f4f7;
  --fb-hint: #7d8b99;
  --fb-link: #6ab3f3;
  --fb-button: #5288c1;
  --fb-button-text: #ffffff;
  --fb-separator: rgba(255, 255, 255, 0.07);
  --fb-destructive: #ff6b6b;

  --overlay-weak: rgba(255, 255, 255, 0.06);
  --skeleton: rgba(255, 255, 255, 0.07);
  --skeleton-hi: rgba(255, 255, 255, 0.1);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.25), 0 8px 24px rgba(0, 0, 0, 0.25);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
  --banner-bg: #3a3016;
  --banner-text: #f3d68a;
  --banner-border: rgba(243, 214, 138, 0.16);
  --hero-strength: 0.42;
}

/* 柔和强调色：先给 rgba 兜底，支持 color-mix 的环境跟随 themeParams */
:root {
  --accent-soft: rgba(36, 129, 204, 0.12);
  --accent-soft-strong: rgba(36, 129, 204, 0.2);
}
@supports (color: color-mix(in srgb, red 50%, blue)) {
  :root {
    --accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
    --accent-soft-strong: color-mix(in srgb, var(--accent) 22%, transparent);
  }
}

/* ========================================================================== */

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

[hidden] { display: none !important; }

html {
  background: var(--secondary-bg);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--secondary-bg);
  color: var(--text);
  font: var(--fs-md)/1.5 var(--font-sans);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  padding-bottom: calc(var(--sp-6) + var(--safe-bottom));
  overflow-wrap: anywhere;
}
body.has-fallback-main { padding-bottom: calc(88px + var(--safe-bottom)); }

button { font: inherit; color: inherit; }

svg { display: block; }

h1, h2, h3, p { margin: 0; }

.pressable {
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease),
    background-color var(--dur-fast) var(--ease);
}
.pressable:active { transform: scale(0.97); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- 开发预览横幅 ---- */
.dev-banner {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--gutter);
  background: var(--banner-bg);
  color: var(--banner-text);
  border-bottom: 1px solid var(--banner-border);
  font-size: var(--fs-xs);
  line-height: 1.35;
}
.dev-banner svg { flex: none; width: 14px; height: 14px; }

main {
  max-width: 640px;
  margin: 0 auto;
  /* 视图入场的位移动画不能撑出横向滚动 */
  overflow-x: hidden;
  overflow-x: clip;
}

.view { padding: 0 var(--gutter); }
.view-enter { animation: view-in var(--dur) var(--ease) both; }
#view-detail.view-enter { animation-name: view-in-detail; }

@keyframes view-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
@keyframes view-in-detail {
  from { opacity: 0; transform: translateX(16px); }
  to { opacity: 1; transform: none; }
}

/* ---- 通用区块 ---- */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: var(--sp-6) var(--sp-1) var(--sp-2);
}
.section-head h2 {
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--section-header);
}
.section-count { font-size: var(--fs-xs); color: var(--hint); }

.card {
  background: var(--section-bg);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.card-title {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--section-header);
  margin-bottom: var(--sp-2);
}

.icon { flex: none; width: 1em; height: 1em; }

/* ==========================================================================
   书架
   ========================================================================== */

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-1) 0;
}
.brand-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-md);
  background:
    radial-gradient(120% 120% at 20% 0%, rgba(255, 255, 255, 0.35), transparent 60%),
    var(--accent);
  color: var(--on-accent);
  box-shadow: 0 6px 16px -6px var(--accent);
}
.brand-mark svg { width: 24px; height: 24px; }
.brand-text { min-width: 0; }
.brand-text h1 {
  font-size: var(--fs-2xl);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: 0.02em;
}
.brand-text p {
  margin-top: 2px;
  font-size: var(--fs-sm);
  color: var(--hint);
}

/* ---- 继续收听卡片 ---- */
.continue-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  padding: var(--sp-4);
  border-radius: var(--r-lg);
  color: #fff;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(90% 140% at 100% 0%, rgba(255, 255, 255, 0.22), transparent 55%),
    linear-gradient(135deg, var(--c-lo, #1d4f7a), var(--c, var(--accent)));
  box-shadow: 0 12px 28px -12px rgba(var(--c-rgb, 36, 129, 204), 0.75);
  transition: transform var(--dur-fast) var(--ease);
  animation: view-in var(--dur) var(--ease) both;
}
.continue-card:active { transform: scale(0.98); }
.continue-card::after {
  /* 装饰：同心声波圈 */
  content: "";
  position: absolute;
  z-index: -1;
  right: -40px;
  bottom: -60px;
  width: 180px;
  height: 180px;
  border-radius: 50%;
  background: repeating-radial-gradient(circle, rgba(255, 255, 255, 0.07) 0 2px, transparent 2px 16px);
}
.continue-text { flex: 1; min-width: 0; }
.continue-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  opacity: 0.85;
}
.continue-eyebrow .icon { width: 13px; height: 13px; }
.continue-title {
  margin-top: 2px;
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.continue-chapter {
  margin-top: 2px;
  font-size: var(--fs-sm);
  opacity: 0.85;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.play-fab {
  flex: none;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: #fff;
  color: var(--c-lo, #1d4f7a);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}
.play-fab svg { width: 20px; height: 20px; margin-left: 2px; }

/* ---- 书目卡片 ---- */
.book-list,
.chapter-list { list-style: none; margin: 0; padding: 0; }

.book-item {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
  border-radius: var(--r-lg);
  background: var(--section-bg);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.book-item:active { transform: scale(0.98); }
@media (hover: hover) {
  .book-item:hover { box-shadow: var(--shadow-md); }
}

.book-info { flex: 1; min-width: 0; }
.book-title-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.book-info h3 {
  min-width: 0;
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.book-author {
  margin-top: 2px;
  font-size: var(--fs-sm);
  color: var(--subtitle);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.book-desc {
  margin-top: var(--sp-1);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--hint);
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--sp-2); }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 8px;
  border-radius: var(--r-pill);
  background: var(--overlay-weak);
  color: var(--hint);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.chip .icon { width: 12px; height: 12px; }
.chip.tag-listening {
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 600;
}
.chevron { flex: none; width: 18px; height: 18px; color: var(--hint); opacity: 0.6; }

.empty {
  padding: var(--sp-8) var(--sp-4);
  text-align: center;
  color: var(--hint);
  font-size: var(--fs-sm);
}

/* ==========================================================================
   CSS 封面：线装书样式
   ========================================================================== */

.cover {
  --cw: 76px;
  position: relative;
  flex: none;
  width: var(--cw);
  aspect-ratio: 3 / 4;
  border-radius: 2px 6px 6px 2px;
  font-size: calc(var(--cw) * 0.17);
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.035) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.035) 0 1px, transparent 1px 4px),
    radial-gradient(120% 90% at 85% 8%, rgba(255, 255, 255, 0.2), transparent 55%),
    linear-gradient(160deg, var(--c-hi, #5a9ad6), var(--c, #2481cc) 50%, var(--c-lo, #17537f));
  box-shadow:
    1.5px 1px 0 -0.5px #efe8d8,
    3px 2px 0 -1px #d9d0bd,
    0 1px 2px rgba(0, 0, 0, 0.15),
    0 8px 16px -6px rgba(0, 0, 0, 0.4);
}
/* 书脊 + 装订线 */
.cover::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 13%;
  border-radius: 2px 0 0 2px;
  border-right: 1px solid rgba(0, 0, 0, 0.2);
  background:
    radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.55) 0 0.6px, transparent 1.4px) 0 4% / 100% 16% repeat-y,
    linear-gradient(90deg, rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.16) 55%, rgba(0, 0, 0, 0.15));
}
/* 光泽 */
.cover::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 22%, rgba(255, 255, 255, 0.13) 34%, transparent 46%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}
/* 题签 */
.cover-label {
  position: absolute;
  top: 9%;
  right: 13%;
  display: block;
  padding: 0.45em 0.28em;
  max-height: 82%;
  overflow: hidden;
  writing-mode: vertical-rl;
  background: linear-gradient(180deg, #f8f2e3, #efe5cf);
  color: #2a2016;
  font-family: var(--font-serif);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.12em;
  border-radius: 1px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12), inset 0 0 0 2px #f8f2e3, inset 0 0 0 2.6px rgba(120, 80, 40, 0.35);
}
.cover-title { display: block; }
.cover-sub {
  display: block;
  margin-right: 0.25em;
  font-size: 0.6em;
  font-weight: 400;
  opacity: 0.75;
}
.cover-sm { --cw: 46px; }
.cover-sm .cover-sub { display: none; }
.cover-md { --cw: 76px; }
.cover-lg { --cw: 128px; border-radius: 3px 8px 8px 3px; }

/* ==========================================================================
   详情
   ========================================================================== */

.hero {
  position: relative;
  margin: 0 calc(var(--gutter) * -1);
  padding: var(--sp-4) var(--gutter) var(--sp-6);
  text-align: center;
  background:
    radial-gradient(110% 70% at 50% 0%, rgba(var(--c-rgb, 36, 129, 204), var(--hero-strength)), transparent 72%),
    linear-gradient(180deg, rgba(var(--c-rgb, 36, 129, 204), calc(var(--hero-strength) * 0.5)), transparent 85%);
}
.back-pill {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  position: absolute;
  top: var(--sp-3);
  left: var(--gutter);
  height: 32px;
  padding: 0 12px 0 6px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--section-bg);
  color: var(--link);
  font-size: var(--fs-sm);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
}
.back-pill svg { width: 18px; height: 18px; }

.hero-cover {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-8);
}
.hero-cover .cover {
  box-shadow:
    2px 1.5px 0 -0.5px #efe8d8,
    4px 3px 0 -1px #d9d0bd,
    0 2px 4px rgba(0, 0, 0, 0.15),
    0 20px 36px -12px rgba(var(--c-rgb, 0, 0, 0), 0.7);
}
.hero-title {
  margin-top: var(--sp-5);
  font-family: var(--font-serif);
  font-size: var(--fs-xl);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.02em;
}
.hero-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px var(--sp-3);
  margin-top: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--subtitle);
}
.hero-meta span:empty { display: none; }
.hero-meta b { font-weight: 500; color: var(--hint); margin-right: 4px; }
.hero-stats {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-top: var(--sp-3);
}
.hero-stats .chip { background: var(--section-bg); box-shadow: var(--shadow-sm); }

.desc-card { padding: var(--sp-4); }
.desc {
  font-size: var(--fs-md);
  line-height: 1.8;
  color: var(--text);
  text-align: justify;
}

/* ---- 章节 ---- */
.chapter-list {
  background: var(--section-bg);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.chapter-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  transition: background-color var(--dur) var(--ease);
}
.chapter-item + .chapter-item::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 64px;
  border-top: 1px solid var(--separator);
}
.chapter-item.current { background: var(--accent-soft); }
.chapter-item.current::after {
  content: "";
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: 0;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
}
.chapter-item.current + .chapter-item::before,
.chapter-item.current::before { border-top-color: transparent; }

.ch-index {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--overlay-weak);
  color: var(--hint);
  font-size: var(--fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.ch-index svg { width: 14px; height: 14px; margin-left: 2px; }
.chapter-item.current .ch-index {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 4px 10px -4px var(--accent);
}

.ch-text { flex: 1; min-width: 0; }
.ch-title {
  font-size: var(--fs-md);
  font-weight: 500;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chapter-item.current .ch-title { color: var(--accent-text); font-weight: 600; }
.ch-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px 8px;
  margin-top: 3px;
  font-size: var(--fs-xs);
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}
.ch-meta .dur { display: inline-flex; align-items: center; gap: 3px; }
.ch-meta .icon { width: 12px; height: 12px; }
.badge-last {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 0 7px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 11px;
  font-weight: 600;
  line-height: 18px;
}

.send-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 32px;
  padding: 0 12px 0 10px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.send-btn .icon { width: 15px; height: 15px; }
.send-btn:active:not(:disabled) { background: var(--accent-soft-strong); }
.send-btn:disabled { cursor: default; opacity: 0.45; }
.send-btn.is-loading { opacity: 1; }
.send-btn.is-sent { background: transparent; color: var(--hint); opacity: 1; }
.chapter-item.current .send-btn:not(.is-sent) { background: var(--section-bg); box-shadow: var(--shadow-sm); }

.spinner {
  flex: none;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- 状态 / 错误 ---- */
.status {
  margin: var(--sp-6) var(--gutter) 0;
  padding: var(--sp-5) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--section-bg);
  color: var(--hint);
  text-align: center;
  font-size: var(--fs-sm);
}
.status.error { color: var(--destructive); }
.status .retry {
  margin-top: var(--sp-3);
  height: 32px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 600;
  cursor: pointer;
}

/* ==========================================================================
   骨架屏
   ========================================================================== */

.sk {
  position: relative;
  overflow: hidden;
  background: var(--skeleton);
  border-radius: var(--r-xs);
}
.sk::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--skeleton-hi), transparent);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
.sk-line { height: 12px; }
.sk-cover { width: 76px; aspect-ratio: 3 / 4; border-radius: 2px 6px 6px 2px; flex: none; }
.sk-dot { width: 34px; height: 34px; border-radius: 50%; flex: none; }
.sk-pill { width: 84px; height: 32px; border-radius: var(--r-pill); flex: none; }
.book-item.skeleton,
.chapter-item.skeleton { cursor: default; }
.book-item.skeleton .book-info > * + *,
.chapter-item.skeleton .ch-text > * + * { margin-top: 10px; }

/* ==========================================================================
   底部替身按钮 & toast
   ========================================================================== */

.fallback-main {
  position: fixed;
  z-index: 15;
  left: var(--gutter);
  right: var(--gutter);
  bottom: calc(var(--sp-3) + var(--safe-bottom));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  max-width: calc(640px - var(--gutter) * 2);
  height: 52px;
  margin: 0 auto;
  padding: 0 var(--sp-4);
  border: 0;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--fs-md);
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  cursor: pointer;
}
.fallback-main .icon { width: 18px; height: 18px; }
.fallback-main:disabled { opacity: 0.7; cursor: default; }

.toast {
  position: fixed;
  z-index: 30;
  left: 50%;
  bottom: calc(var(--sp-4) + var(--safe-bottom));
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: max-content;
  max-width: calc(100% - var(--gutter) * 2);
  padding: 10px 16px 10px 12px;
  border-radius: var(--r-md);
  background: rgba(28, 30, 36, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.1); /* 深色背景上也能看出边界 */
  color: #fff;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
  backdrop-filter: saturate(160%) blur(12px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(-50%, 12px) scale(0.98);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility 0s linear var(--dur);
}
body.has-fallback-main .toast { bottom: calc(76px + var(--safe-bottom)); }
.toast.show {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility 0s;
}
.toast-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #34c759;
  color: #fff;
}
.toast-icon svg { width: 15px; height: 15px; }
.toast.error .toast-icon { background: #ff453a; }
.toast-body { min-width: 0; }
.toast-title { font-size: var(--fs-md); font-weight: 600; line-height: 1.35; }
.toast-sub { margin-top: 1px; font-size: var(--fs-xs); line-height: 1.4; color: rgba(255, 255, 255, 0.7); }

/* ==========================================================================
   减少动效
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
