/* ==========================================================================
   Melograph · 拾音
   设计基调：Apple HIG 的结构与留白 + 纸感暖白 + 宋体标题的文艺气质
   ========================================================================== */

:root {
  --bg: #FBFAF8;
  --surface: #FFFFFF;
  --surface-2: #F4F2ED;
  --text: #1D1D1F;
  --text-2: #6E6E73;
  --text-3: #9C9CA1;
  --line: rgba(0, 0, 0, .07);
  --line-strong: rgba(0, 0, 0, .12);
  --accent: #A1654A;
  --accent-soft: rgba(161, 101, 74, .12);
  /* 影展标（独立放映专用）：暖金，与主色（赭陶）同族但不抢戏 */
  --fest: #8A5A12;
  --fest-bg: rgba(191, 141, 44, .12);
  --fest-line: rgba(191, 141, 44, .3);
  --like: #C05246;
  --like-soft: rgba(192, 82, 70, .12);
  --glass: rgba(251, 250, 248, .72);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 6px 18px rgba(0, 0, 0, .05);
  --shadow-2: 0 10px 34px rgba(0, 0, 0, .10), 0 2px 6px rgba(0, 0, 0, .04);
  --shadow-3: 0 -8px 40px rgba(0, 0, 0, .10);
  --grain-blend: multiply;
  --grain-op: .04;

  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC",
               "Helvetica Neue", "Microsoft YaHei", sans-serif;
  --font-serif: "Songti SC", "STSong", "Noto Serif SC", "Source Han Serif SC",
                Georgia, "Times New Roman", serif;

  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --ease: cubic-bezier(.22, .68, .3, 1);
  --topbar-h: 52px;
  --sidebar-w: 248px;
  --playbar-h: 78px;
}

html[data-theme="dark"] {
  --bg: #0D0D0F;
  --surface: #17171A;
  --surface-2: #1F1F23;
  --text: #F2F2F4;
  --text-2: #9B9BA1;
  --text-3: #6E6E75;
  --line: rgba(255, 255, 255, .08);
  --line-strong: rgba(255, 255, 255, .16);
  --accent: #CE9B7C;
  --accent-soft: rgba(206, 155, 124, .16);
  /* 影展标（独立放映专用）：暗底上换成浅金，保证对比度 */
  --fest: #D9B063;
  --fest-bg: rgba(217, 176, 99, .14);
  --fest-line: rgba(217, 176, 99, .34);
  --like: #E0746A;
  --like-soft: rgba(224, 116, 106, .16);
  --glass: rgba(13, 13, 15, .70);
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .5), 0 6px 18px rgba(0, 0, 0, .35);
  --shadow-2: 0 10px 34px rgba(0, 0, 0, .55);
  --shadow-3: 0 -8px 40px rgba(0, 0, 0, .6);
  --grain-blend: overlay;
  --grain-op: .06;
}

* { box-sizing: border-box; }

/* 组件用 display:grid/flex 会盖掉 UA 的 [hidden]{display:none}，这里统一兜住 */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;
}

/* 纸感噪点 */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9000;
  pointer-events: none;
  opacity: var(--grain-op);
  mix-blend-mode: var(--grain-blend);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

::selection { background: var(--accent-soft); color: var(--text); }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input { font: inherit; color: inherit; }

.ic { width: 18px; height: 18px; flex: none; display: block; }

/* ============================ 布局骨架 ============================ */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr auto;
  grid-template-areas: "top top" "side main" "bar bar";
  height: 100vh;
  height: 100dvh;
}

/* ============================== 顶栏 ============================== */

.topbar {
  grid-area: top;
  position: relative;
  z-index: 40;
  background: var(--glass);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: .5px solid var(--line);
}

.topbar-inner {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 0 20px;
}

.brand { display: flex; align-items: center; gap: 10px; }

.brand-mark {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 18px;
  padding: 0 1px;
}
.brand-mark i {
  width: 2.5px;
  background: var(--text);
  border-radius: 2px;
  animation: eq 2.4s var(--ease) infinite;
}
.brand-mark i:nth-child(1) { height: 40%; animation-delay: 0s; }
.brand-mark i:nth-child(2) { height: 90%; animation-delay: .3s; }
.brand-mark i:nth-child(3) { height: 60%; animation-delay: .6s; }
.brand-mark i:nth-child(4) { height: 100%; animation-delay: .9s; }
.brand-mark.is-large { height: 40px; gap: 4px; }
.brand-mark.is-large i { width: 5px; border-radius: 3px; }

@keyframes eq {
  0%, 100% { transform: scaleY(.45); }
  50%      { transform: scaleY(1); }
}

.brand-text { display: flex; align-items: baseline; gap: 8px; }
.brand-text b {
  font-family: var(--font-serif);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: .06em;
}
.brand-text em {
  font-style: normal;
  font-size: 10.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--text-3);
}

.topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}

.searchbox {
  display: flex;
  align-items: center;
  gap: 8px;
  /* v0.9.47：280 → 340。搜索框在 .topbar-right（margin-left:auto）里，
     变宽即向左长，右边线钉死在账户按钮左侧 —— 这正是「适当变宽（往左一点）」。 */
  width: 340px;
  height: 32px;
  padding: 0 12px;
  border-radius: 10px;
  background: var(--surface-2);
  border: .5px solid transparent;
  transition: border-color .25s, background .25s;
}
.searchbox:focus-within { border-color: var(--line-strong); background: var(--surface); }
.searchbox .ic { width: 15px; height: 15px; color: var(--text-3); }
.searchbox input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: none;
  background: none;
  font-size: 13px;
}
.searchbox input::-webkit-search-cancel-button { display: none; }
.searchbox kbd {
  font-family: var(--font-sans);
  font-size: 10px;
  color: var(--text-3);
  border: .5px solid var(--line-strong);
  border-radius: 4px;
  padding: 0 4px;
  line-height: 15px;
  cursor: pointer; /* 点它 = 聚焦搜索框（v0.9.40：修「点死区没反应」） */
}

/* ── 顶栏搜歌浮层（v0.9.40）─────────────────────────────────────────
   结果在搜索框正下方就地展开，当前页原地不动 —— 不再「边敲字边被甩进放映厅」。
   渲染用卡片族（.card-grid）而不是发现页的 .media-card：搜索的本质是歌曲，
   卡片带播放 / 心动 / 无感，浮层里直接可用。 */
.searchbox { position: relative; }
.search-panel {
  position: absolute;
  top: calc(100% + 8px);
  /* v0.9.47：改**右锚定**。以前 left:0 + width 560 —— 搜索框在顶栏最右侧，
     浮层从左边界向右铺，实测右边缘溢到视口外 54px（1440 视口下 right=1494），
     右边那一列结果等于挂在屏幕外。右锚定后浮层向左生长，永远不越界。 */
  right: 0;
  left: auto;
  width: min(640px, calc(100vw - 260px));
  max-height: min(62vh, 560px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: .5px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-2);
  overflow: hidden;
  z-index: 120;
}
.search-panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px 8px;
  font-size: 12px;
}
.search-panel-title { color: var(--text-3); }
/* v0.9.47：`.search-panel-all`（「在放映厅查看全部」）整块删除 ——
   下拉菜单只负责把结果显示完，不该再塞一个会把人带走的入口。 */
.search-panel-grid {
  flex: 1 1 auto;      /* 面板里唯一能伸缩的滚动区：面板定高，结果在里面上下滑 */
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 2px 12px 12px;
}
/* ⚠️ 必须是 `.card-grid.search-panel-grid`（同元素双类，权重 0-2-0）。
   原先写的是 `.search-panel-grid .card-grid`（后代选择器），可这两个类挂的正是**同一个**
   div（`<div class="card-grid search-panel-grid">`）—— 规则从来就没生效过，是死的；
   浮层于是沿用 .card-grid 默认的 184px，只排 2 列、单卡宽到 257px。
   双类写法权重 0-2-0，同时压过后面定义的 .card-grid（0-1-0），不再受声明顺序牵制。 */
.card-grid.search-panel-grid {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 16px 14px;
}
.search-panel-empty { padding: 22px 0 26px; }
.search-panel-loading { padding: 26px 0 30px; }

.ghost-btn {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--text-2);
  transition: background .2s, color .2s;
}
.ghost-btn:hover { background: var(--surface-2); color: var(--text); }

/* ── 账户（右上角）────────────────────────────────────────────────
   账户与设置是全局的：它们挂在顶栏上，因此每个一级页面都在。
   ──────────────────────────────────────────────────────────────── */
.acct-wrap { position: relative; }

.acct-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 12px 0 5px;
  border-radius: 16px;
  background: var(--surface-2);
  border: .5px solid transparent;
  color: var(--text-2);
  font-size: 12.5px;
  max-width: 168px;
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.acct-btn:hover, .acct-btn.is-open { background: var(--surface); border-color: var(--line-strong); color: var(--text); }
.acct-btn.is-guest { opacity: .8; }

.acct-avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1;
}
.acct-avatar.is-large { width: 34px; height: 34px; font-size: 15px; }
.acct-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.acct-menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 60;
  width: 320px;
  padding: 14px;
  border-radius: 16px;
  border: .5px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow-2, 0 18px 48px rgba(0, 0, 0, .16));
  animation: fadeUp .18s var(--ease) both;
}

.acct-menu-head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding-bottom: 13px;
  border-bottom: .5px solid var(--line);
}
.acct-id { min-width: 0; }
.acct-name {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.acct-phone { margin: 2px 0 0; font-size: 11.5px; color: var(--text-3); }

/* 明文账户 ID：一眼看见「我是哪一份档案」，点一下复制 */
.acct-pubid {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 7px 0 0;
  padding: 3px 9px 3px 8px;
  border: .5px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-2);
  font: inherit;
  cursor: pointer;
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.acct-pubid:hover { background: var(--accent-soft); border-color: transparent; }
.acct-pubid .ic { width: 12px; height: 12px; opacity: .55; flex: none; }
.acct-pubid:hover .ic { opacity: .85; }
.acct-pubid-k { font-size: 9.5px; letter-spacing: .1em; opacity: .7; }
.acct-pubid-v {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .06em;
  color: var(--text);
}
.acct-pubid:hover .acct-pubid-k,
.acct-pubid:hover .acct-pubid-v { color: var(--accent); }

.acct-rows { padding: 5px 0; }
.acct-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 9px 2px;
}
.acct-row + .acct-row { border-top: .5px solid var(--line); }
.acct-row-main { flex: 1; min-width: 0; display: grid; gap: 1px; }
.acct-k { font-size: 11px; letter-spacing: .04em; color: var(--text-3); }
.acct-v { font-size: 13px; font-weight: 500; }
.acct-hint { font-size: 11px; line-height: 1.5; color: var(--text-3); }
.acct-hint.is-error { color: #d0463a; }

/* 就地绑定手机号的小表单 */
.acct-bind { display: grid; gap: 7px; padding: 10px 2px; }
.acct-bind-row { display: flex; align-items: center; gap: 8px; }
.acct-cc {
  flex: none;
  padding-right: 8px;
  border-right: .5px solid var(--line);
  color: var(--text-3);
  font-size: 12.5px;
}
.acct-bind-input {
  flex: 1;
  min-width: 0;
  height: 32px;
  padding: 0 10px;
  border: .5px solid var(--line-strong);
  border-radius: 9px;
  background: var(--bg);
  color: var(--text);
  font-size: 13px;
  letter-spacing: .04em;
}
.acct-bind-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}

.acct-act {
  flex: none;
  align-self: center;
  height: 28px;
  padding: 0 12px;
  border-radius: 999px;
  border: .5px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--text);
  font-size: 12px;
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.acct-act:hover { background: var(--bg); border-color: var(--text-3); }

/* 第二音源：网易云扫码连接（就地展开在账户面板里） */
.acct-net { display: grid; gap: 8px; padding: 10px 2px; }
.acct-qr {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 176px;
  padding: 8px;
  border: .5px solid var(--line);
  border-radius: 12px;
  background: #fff;
}
.acct-qr svg { width: 160px; height: 160px; display: block; }
html[data-theme="dark"] .acct-qr { background: #fff; } /* 二维码保持白底，深色模式也扫得出 */
.acct-qr-wait { font-size: 12px; color: var(--text-3); }
.acct-net-actions { display: flex; align-items: center; gap: 8px; justify-content: flex-end; }
.acct-net-actions .acct-act { min-width: 76px; }

.acct-actions { padding-top: 11px; border-top: .5px solid var(--line); }
.acct-btn-ghost {
  width: 100%;
  height: 34px;
  border-radius: 11px;
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 12.5px;
  transition: background .18s var(--ease), color .18s var(--ease);
}
.acct-btn-ghost:hover { background: var(--bg); color: var(--text); }
.acct-btn-ghost.is-primary { background: var(--text); color: var(--bg); }

/* 设置：顶栏上的胶囊按钮，与主题按钮并排 */
.top-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border-radius: 999px;
  background: var(--surface-2);
  border: .5px solid transparent;
  color: var(--text-2);
  font-size: 12.5px;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.top-pill:hover { background: var(--surface); border-color: var(--line-strong); color: var(--text); }
.top-pill:hover .ic { transform: rotate(60deg); }
.top-pill .ic { width: 14px; height: 14px; transition: transform .5s var(--ease); }

/* ── 移动端导航（窄屏下侧栏整体收起，这三个入口必须另有落点）────── */
.mobilenav { display: none; grid-area: side; }

/* ============================== 侧栏 ============================== */

.sidebar {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 18px 14px;
  border-right: .5px solid var(--line);
  overflow-y: auto;
}

.sidebar nav { display: flex; flex-direction: column; gap: 2px; }

.nav-item {
  display: flex;
  align-items: center;
  gap: 11px;
  height: 38px;
  padding: 0 12px;
  border-radius: 10px;
  color: var(--text-2);
  font-size: 14px;
  transition: background .2s, color .2s;
}
.nav-item .ic { width: 17px; height: 17px; }
.nav-item:hover { background: var(--surface-2); }
.nav-item.is-active { background: var(--surface-2); color: var(--text); font-weight: 500; }

/* 「灵感」下挂的「专辑」子页签：右箭头默认收起，点击展开 */
.nav-group { display: flex; flex-direction: column; gap: 2px; }
.nav-row { display: flex; align-items: center; }
.nav-row .nav-item { flex: 1; }
.nav-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 38px;
  margin-left: 2px;
  border-radius: 10px;
  color: var(--text-3);
  cursor: pointer;
  transition: background .2s, color .2s, transform .2s var(--ease);
}
.nav-arrow:hover { background: var(--surface-2); color: var(--text); }
.nav-arrow .ic { width: 15px; height: 15px; }
.nav-group.is-open .nav-arrow { transform: rotate(90deg); color: var(--text); }
.nav-sub {
  margin-left: 18px;   /* 缩进，表明它是「灵感」的下级 */
  padding-left: 24px;
}
.nav-sub .ic { width: 15px; height: 15px; }
.nav-sub.is-active { background: var(--surface-2); color: var(--text); font-weight: 500; }

.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: 12px; }

.agent-card {
  padding: 15px 14px;
  border-radius: var(--r-md);
  background: var(--surface-2);
}
/* ⛔ `.agent-label`（侧栏档案卡那行小标签）随 index.html 里的元素一起删掉了（v0.9.73）——
   最深档位名已改叫「听觉档案」，留着就是同名两行。别再顺手加回来，
   判据在 tests/shot-v0973.cjs：卡片的第一个可见文字必须是档位名。 */
.agent-stage {
  margin: 0 0 3px;
  font-size: 11.5px;
  color: var(--accent);
  font-weight: 500;
}
.agent-headline {
  margin: 0 0 12px;
  font-family: var(--font-serif);
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
}
.agent-stats {
  display: flex;
  gap: 14px;
  font-size: 11.5px;
  color: var(--text-2);
  padding-top: 10px;
  border-top: .5px solid var(--line);
}
.agent-stats b {
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  margin-right: 2px;
}

.provider-note {
  margin: 0;
  font-size: 10.5px;
  line-height: 1.6;
  color: var(--text-3);
  padding: 0 4px;
}

/* 左下角：迭代版本号 + 备案信息（ICP / 公安）。
   备案号是链接（点开落到官方查询页），样式上刻意保持低调的灰、默认无下划线，
   hover 才给一点提示 —— 它是合规信息，不该抢版面。 */
.sidebar-legal {
  margin-top: 2px;
  padding: 10px 4px 2px;
  border-top: .5px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}
.sidebar-legal span,
.sidebar-legal a {
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-3);
  letter-spacing: .02em;
}
.legal-version { font-variant-numeric: tabular-nums; }
.legal-icp {
  color: var(--text-3);
  text-decoration: none;
  border-bottom: .5px solid transparent;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.legal-icp:hover { color: var(--text-2); border-bottom-color: var(--line); }

/* 窄屏备案行：≤900px 侧栏整体 display:none，备案号在主区底部由它接管。
   桌面 display:none，避免与 .sidebar-legal 重复展示同一串号码。 */
.legal-foot {
  display: none;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  max-width: 1000px;
  margin: 28px 0 0;
  padding-top: 14px;
  border-top: .5px solid var(--line);
  font-size: 10.5px;
  color: var(--text-3);
  letter-spacing: .02em;
}
.legal-foot a {
  color: var(--text-3);
  text-decoration: none;
  border-bottom: .5px solid transparent;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.legal-foot a:hover { color: var(--text-2); border-bottom-color: var(--line); }

/* ============================== 主区 ============================== */

.main {
  grid-area: main;
  /* min-width:0 是 grid item 的**自动最小尺寸**开关（与 flex 项出省略号同一招）：
     缺了它时 min-width:auto = 内容的 min-content 宽，主区里任何不可收缩的内容
     都会把整列顶开、让整页横向可滚。这边显式写死更稳（overflow-x:hidden 在
     部分排版路径下并不足以把自动最小尺寸压成 0）。

     ⚠️ 别把它当成「窄屏溢出」的万能药：v0.9.71 顺手查过一个真实案例 ——
     430px 视口下整页横向滚 193px，元凶**不是**主区，而是 .playbar（见 playbar-inner
     那段注释里列的 623px 账）。这里留 min-width:0 是防护，不是那一例的解药。 */
  min-width: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 40px 44px 60px;
  scroll-behavior: smooth;
}

.view { display: none; max-width: 1000px; }
.view.is-active { display: block; animation: viewIn .45s var(--ease); }

@keyframes viewIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* Hero */
.hero { margin-bottom: 30px; }

.hero-eyebrow {
  margin: 0 0 14px;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--accent);
}

.hero-title {
  margin: 0 0 14px;
  font-family: var(--font-serif);
  font-size: 38px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: .01em;
}

.hero-sub {
  margin: 0 0 22px;
  max-width: 46em;
  font-size: 14px;
  line-height: 1.85;
  color: var(--text-2);
}
.hero-sub:empty { display: none; }

.hero-actions { display: flex; gap: 10px; flex-wrap: wrap; }

.pill-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 18px;
  border-radius: 18px;
  background: var(--text);
  color: var(--bg);
  font-size: 13px;
  font-weight: 500;
  transition: transform .2s var(--ease), opacity .2s;
}
.pill-btn .ic { width: 15px; height: 15px; }
.pill-btn:hover { transform: translateY(-1px); }
.pill-btn:active { transform: scale(.98); }
.pill-btn.is-plain {
  background: var(--surface-2);
  color: var(--text);
  border: .5px solid var(--line);
}

.seed-line {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  align-items: center;
  margin-bottom: 22px;
  font-size: 11.5px;
  color: var(--text-3);
}
.seed-line .seed {
  padding: 3px 10px;
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--text-2);
  border: .5px solid var(--line);
}
.seed-line .seed.is-explore { color: var(--accent); border-color: var(--accent-soft); background: var(--accent-soft); }
.seed-line .seed-label { margin-right: 2px; }

/* 卡片网格 */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
  gap: 22px 20px;
}

.card {
  position: relative;
  transition: transform .4s var(--ease);
  animation: cardIn .5s var(--ease) backwards;
}
@keyframes cardIn {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.card:hover { transform: translateY(-4px); }
.card.is-dim { opacity: .42; }

.card-art {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-2);
  box-shadow: var(--shadow-1);
  transition: box-shadow .4s var(--ease);
  cursor: pointer;
}
.card:hover .card-art { box-shadow: var(--shadow-2); }

.card-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .7s var(--ease), filter .4s;
}
.card:hover .card-art img { transform: scale(1.04); }

.card-art .fallback {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-serif);
  font-size: 40px;
  color: var(--text-3);
  background: linear-gradient(145deg, var(--surface-2), var(--bg));
}

.card-play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, .28);
  opacity: 0;
  transition: opacity .3s;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.card:hover .card-play, .card.is-playing .card-play { opacity: 1; }
.card-play span {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .94);
  color: #111;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .25);
  transform: scale(.9);
  transition: transform .3s var(--ease);
}
.card:hover .card-play span { transform: scale(1); }
.card-play .ic { width: 19px; height: 19px; margin-left: 2px; }
.card-play .ic.is-pause { margin-left: 0; }

.card-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  display: flex;
  gap: 4px;
}
.card-badge span {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 22px;
  padding: 0 8px;
  border-radius: 11px;
  font-size: 11px;
  font-weight: 500;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.card-badge .is-like { background: rgba(192, 82, 70, .92); color: #fff; }
.card-badge .is-dislike { background: rgba(30, 30, 32, .78); color: #fff; }
.card-badge .ic { width: 12px; height: 12px; }

.card-info { padding: 11px 2px 0; }
.card-title {
  margin: 0;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.card-artist {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 3px 0 0;
  font-size: 12px;
  color: var(--text-2);
}
.ca-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 卡片上的播放方式标签：和播放器上那枚一样，只标识、不可点。
   完整曲目＝朴素灰（常态不必抢眼），试听 30 秒＝暖色（需要被看见）。 */
.card-mode {
  flex: none;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
  color: #93601F;
  background: rgba(196, 128, 58, .13);
  border: .5px solid rgba(196, 128, 58, .24);
}
.card-mode.is-full,
.card-mode.is-none {
  color: var(--text-3);
  background: var(--surface-2);
  border-color: var(--line);
}
html[data-theme="dark"] .card-mode { color: #E2AC69; background: rgba(226, 172, 105, .14); border-color: rgba(226, 172, 105, .26); }
html[data-theme="dark"] .card-mode.is-full,
html[data-theme="dark"] .card-mode.is-none { color: var(--text-3); background: var(--surface-2); border-color: var(--line); }
.card-why {
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--text-3);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-actions {
  display: flex;
  gap: 6px;
  margin-top: 9px;
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity .25s, transform .25s;
}
.card:hover .card-actions, .card.is-judged .card-actions { opacity: 1; transform: none; }

.mini-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 27px;
  padding: 0 11px;
  border-radius: 14px;
  border: .5px solid var(--line-strong);
  font-size: 11.5px;
  color: var(--text-2);
  transition: background .2s, color .2s, border-color .2s;
}
.mini-btn .ic { width: 13px; height: 13px; }
.mini-btn:hover { background: var(--surface-2); color: var(--text); }
.mini-btn.is-on-like { background: var(--like-soft); border-color: transparent; color: var(--like); }
.mini-btn.is-on-dislike { background: var(--surface-2); border-color: transparent; color: var(--text); }

/* 分区标题 */
.section-head { margin-bottom: 28px; }
.section-head h2 {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-size: 27px;
  font-weight: 500;
}
.section-head p { margin: 0; color: var(--text-2); font-size: 13.5px; }

/* 档案页标题行：左边标题说明，右边一颗「设置」 */
.section-head.is-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
}
.section-head-main { min-width: 0; }
.section-head-main p { max-width: 72ch; }

.settings-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 15px;
  border: .5px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.settings-btn:hover { background: var(--surface-2); color: var(--text); border-color: var(--text-3); }
.settings-btn .ic { width: 14px; height: 14px; }
.settings-btn svg { transition: transform .5s var(--ease); }
.settings-btn:hover svg { transform: rotate(60deg); }

.discover-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 18px;
}
.discover-tab {
  appearance: none;
  border: .5px solid var(--line);
  background: var(--surface);
  color: var(--text-2);
  font-size: 14px;
  padding: 8px 20px;
  border-radius: 999px;
  cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.discover-tab:hover { border-color: var(--text-3); color: var(--text); }
.discover-tab.is-active { background: var(--text); border-color: var(--text); color: #fff; }

.discover-theme {
  margin: -8px 0 18px;
  font-size: 13.5px;
  color: var(--text-2);
  padding: 10px 14px;
  border-radius: 12px;
  background: var(--surface-2);
  border: .5px solid var(--line);
}

/* 一级页面双区块：电影 / 图书 同时展示 */
.discover-block { margin-top: 26px; }
.discover-block-title {
  margin: 0 0 14px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: .2px;
}
.discover-block-theme {
  margin-left: 10px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-2);
}

/* 来源徽章：豆瓣绿 / 微信读书蓝 */
.media-badge.badge-douban {
  background: rgba(0, 150, 56, .1);
  color: #008c3a;
}
.media-badge.badge-weread {
  background: rgba(37, 119, 227, .1);
  color: #2577e3;
}

/* 图书卡 like / dislike */
.media-actions {
  display: flex;
  flex-wrap: wrap; /* 窄卡里宁可整体换行，也别把按钮内的文字挤成两行 */
  gap: 8px;
  margin-top: 8px;
}
.media-act {
  appearance: none;
  border: .5px solid var(--line);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 12px;
  white-space: nowrap;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
  transition: all .15s ease;
}
.media-act:hover { border-color: var(--accent); color: var(--accent); }
.media-act:disabled { opacity: .5; cursor: default; }
.media-act.act-dislike:hover { border-color: #d24b4b; color: #d24b4b; }
.media-card.is-liked .act-like {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(37, 119, 227, .08);
}
.media-card.is-liked { border-color: var(--accent-soft); }

/* 阅读模式：设置里的 Key 输入（阅读统计条已下线，见 2026-09-15） */
.wr-key {
  flex: 1;
  min-width: 160px;
  padding: 7px 12px;
  font-size: 13.5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text-1);
  outline: none;
}
.wr-key:focus { border-color: var(--accent); }

/* 媒体卡（电影 / 图书）—— 复用 .card-grid 的网格 */
.media-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  border-radius: 16px;
  background: var(--surface);
  border: .5px solid var(--line);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.media-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
  border-color: var(--text-3);
}
.media-cover {
  position: relative;
  aspect-ratio: 2 / 3;
  background: var(--surface-2);
  overflow: hidden;
}
.media-cover-link { display: block; width: 100%; height: 100%; }
.media-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* 封面左下：豆瓣评分。压在封面上，不占信息区的行 —— 卡片因此矮一截。
   v0.9.34 起电影用它承载**整个豆瓣身份**：豆瓣 logo + ★评分合成一枚药丸，
   卡片下方标签行不再重复挂「豆瓣」标（见 app.js badgeRow）。 */
.cover-rating {
  position: absolute;
  left: 8px;
  bottom: 8px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: rgba(20,20,22,.78);
  color: #ffd66b;
  font-size: 11.5px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 8px;
  font-variant-numeric: tabular-nums;
  pointer-events: none; /* 纯展示：别挡住封面的点击区 */
}
.cover-rating b { font-size: 9.5px; color: #ffc94d; }
/* 豆瓣身份那一枚：logo 与评分之间留一点气口，左内边距收一点免得药丸变胖 */
.cover-rating.is-douban { padding: 2px 8px 2px 5px; gap: 4px; }
.cover-rating.is-douban .tag-logo { width: 14px; height: 14px; border-radius: 3px; }
/* ── 封面左上角那一列标签（v0.9.48）──────────────────────────────────
   「✓ 看过」在上、「待看」在下，竖排。原先一个在左上、一个在右上，
   摊在两角反而显乱；现在两枚都归左上，右上整个让给隐藏式 ×（.media-card-x）。
   ⚠️ 容器自己不吃指针（pointer-events:none）—— 两枚之间的空隙必须让点击**穿到**
   底下的 .media-cover-link（点标签之间的空白照样能打开详情页）；
   两枚按钮各自再把 pointer-events 打开。 */
.cover-tags {
  position: absolute;
  top: 8px;
  left: 8px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  z-index: 1;
  pointer-events: none;
}
.cover-tags > * { pointer-events: auto; }
/* 「待看」（v0.9.48 从右上角挪到这一列）。点一下 → 书签点亮 → 整卡退场（时序见 app.js judgeMedia） */
.cover-plan {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px 3px 7px;
  border: 0;
  border-radius: 999px;
  background: rgba(20,20,22,.58);
  color: #fff;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: background .18s ease, transform .18s ease, opacity .26s ease;
}
.cover-plan:hover { background: rgba(20,20,22,.8); }
.cover-plan:disabled { cursor: default; }
.cover-plan .ic { width: 12px; height: 12px; }
.cover-plan.is-done { background: var(--accent); transform: scale(1.1); }

/* 「看过」（v0.9.37；v0.9.48 挪进左上那一列，图标从眼睛换成打钩 —— 它是「已经办完」的状态，
   不是「去看」的入口）。点一下点亮 → 与「喜欢」同款停留窗口（再留 2 次操作）后退场，之后不再推回。 */
.cover-seen {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px 3px 7px;
  border: 0;
  border-radius: 999px;
  background: rgba(20,20,22,.58);
  color: #fff;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: background .18s ease, color .18s ease, transform .18s ease, opacity .26s ease;
}
.cover-seen:hover { background: rgba(20,20,22,.8); }
.cover-seen .ic { width: 12px; height: 12px; }
/* 已看过：实心强调（它是「已经办了」的状态，不是待办） */
.cover-seen.is-on { background: var(--accent); }
.cover-seen.is-on:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }

/* 封面右上角的**隐藏式 ×**（参考专辑卡片的 .album-card-x）。平时淡出，卡片 hover 才显形；
   触屏没有 hover，所以 @media (hover:none) 里常显。
   v0.9.48 起内容区（放映厅 / 电影 / 图书位）也用这一枚：同一颗按钮、同一个位置、同一套样式，
   语义由 data-act 决定 —— `dismiss` = 内容区「直接把这张摘掉」，`plan` = 计划页「移出清单」。 */
.media-card-x {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  padding: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: opacity .2s, color .2s, background .2s;
}
.media-card:hover .media-card-x { opacity: 1; }
.media-card-x:hover { color: var(--accent); background: color-mix(in srgb, var(--bg) 90%, transparent); }
.media-card-x .ic { width: 13px; height: 13px; }
@media (hover: none) {
  .media-card-x { opacity: 1; }
}
.media-meta {
  padding: 11px 13px 13px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.media-badge {
  align-self: flex-start;
  font-size: 11px;
  color: var(--text-3);
  border: .5px solid var(--line);
  border-radius: 6px;
  padding: 1px 7px;
  margin-bottom: 2px;
}
.media-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  align-items: center;
  margin-top: 3px;
}
/* 标签 = 「去哪找得到」的入口标识：左侧一枚小 logo + 文字 */
.media-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  border-radius: 6px;
  padding: 2px 8px 2px 5px;
  align-self: flex-start;
}
.tag-logo {
  width: 13px;
  height: 13px;
  border-radius: 3px;
  display: block;
  flex: none;
}
.tag-douban {
  color: #0b7a37;
  background: rgba(0, 150, 56, .08);
  border: .5px solid rgba(0, 150, 56, .22);
}
.tag-weread {
  color: #1f63c4;
  background: rgba(37, 119, 227, .08);
  border: .5px solid rgba(37, 119, 227, .22);
}
/* 能直达微信读书时这个标签是链接：保持标签外观，只加悬停反馈 */
a.media-tag {
  text-decoration: none;
  transition: background .15s ease, border-color .15s ease;
}
a.media-tag:hover {
  background: #d7e8fa;
  border-color: #a9cdee;
}
.media-title {
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.35;
  margin: 0;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* 标题本身也是「点开去看详情页」的入口（封面之外再给一个更好点的靶子）。
   视觉上刻意不做出链接的样子 —— 卡片里到处都是链接会吵；hover 时才浮出下划线。 */
.media-title-link { color: inherit; text-decoration: none; }
.media-title-link:hover { text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 2px; }
.media-title-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
/* 副标题（作者 / 副题）与年份合并成一行，长了省略 —— 卡片因此少一行 */
.media-sub {
  margin: 0;
  font-size: 12px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.media-year {
  font-size: 12px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.media-why {
  margin: 5px 0 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-2);
  background: var(--surface-2);
  border-left: 2px solid var(--accent);
  padding: 4px 8px;
  border-radius: 0 8px 8px 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.empty-state {
  padding: 60px 0;
  text-align: center;
  color: var(--text-3);
  font-size: 13.5px;
}

/* ---- 专辑 · 唱片架 ---- */
.album-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
  gap: 22px 20px;
}
.album-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 9px;
  cursor: pointer;
  animation: cardIn .5s var(--ease) backwards;
}
.album-card .cover { transition: transform .25s var(--ease), box-shadow .25s var(--ease); }
.album-card:hover .cover { transform: translateY(-3px); box-shadow: var(--shadow-2); }
.album-card .cover {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface-2);
  box-shadow: var(--shadow-1);
}
.album-card .cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.album-card .cover-ph {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
}
.album-card .cover-ph svg { width: 30px; height: 30px; }
.album-card-title {
  font-size: 13.5px;
  color: var(--text);
  font-weight: 500;
  line-height: 1.3;
  padding-right: 26px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.album-card-artist {
  font-size: 12px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.album-card-x {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
  transition: opacity .2s, color .2s, background .2s;
}
.album-card:hover .album-card-x { opacity: 1; }
.album-card-x:hover { color: var(--accent); background: color-mix(in srgb, var(--bg) 90%, transparent); }
.album-card-x .ic { width: 13px; height: 13px; }
.album-card.is-off { opacity: .35; }

@media (hover: none) {
  .album-card-x { opacity: 1; }
}

/* ── 专辑二级页（完整专辑信息 + 曲目列表，排版参考 Apple Music）── */
.album-detail { padding-bottom: 40px; }
.back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 18px;
  padding: 7px 12px;
  border-radius: 999px;
  color: var(--text-2);
  font-size: 13px;
  cursor: pointer;
  background: var(--surface-2);
  transition: color .2s, background .2s;
}
.back-btn:hover { color: var(--text); background: var(--surface); }
.back-btn .ic { width: 15px; height: 15px; transform: rotate(180deg); }

.album-detail-hero {
  display: flex;
  gap: 30px;
  /* ★ 顶对齐（v0.9.59）：原来写的是 flex-end —— 封面跟「元信息块」的底边对齐，
     可描述一展开元信息块就变高，封面被推着往下滑（看着就是封面在飘）。
     锚在顶部后，封面与文字块从同一条基线起排：描述展开只让容器往下长，
     封面的位置一动不动。（窄屏那条 media query 是 column，封面在上，同样不受影响。） */
  align-items: flex-start;
  padding: 28px;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  margin-bottom: 26px;
}
.album-detail-cover {
  flex: none;
  width: 220px;
  aspect-ratio: 1;
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow: var(--shadow-2);
  background: var(--surface-2);
}
.album-detail-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.album-detail-cover .cover-ph {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
}
.album-detail-cover .cover-ph svg { width: 56px; height: 56px; }
.album-detail-meta { min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.album-detail-type {
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--text-3);
  font-weight: 600;
}
.album-detail-title {
  font-size: 30px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.15;
  margin: 0;
  letter-spacing: -.01em;
}
.album-detail-artist { font-size: 15px; color: var(--text-2); font-weight: 500; }
.album-detail-facts { font-size: 12.5px; color: var(--text-3); }

.album-detail-loading, .album-detail-error {
  padding: 20px 0;
  color: var(--text-3);
  font-size: 13px;
}
.album-detail-error { color: var(--like); }

.album-tracklist { list-style: none; margin: 0; padding: 0; }
.album-track {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background .15s;
}
.album-track:hover { background: var(--surface-2); }
.album-track-no {
  flex: none;
  width: 26px;
  text-align: right;
  font-size: 13px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.album-track-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.album-track-title {
  font-size: 14px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.album-track-title .explicit-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 0 4px;
  border: 1px solid var(--line);
  border-radius: 3px;
  font-size: 9px;
  color: var(--text-3);
  vertical-align: 1px;
}
.album-track-artist {
  font-size: 12px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.album-track-dur {
  flex: none;
  font-size: 13px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .album-detail-hero { flex-direction: column; align-items: center; text-align: center; gap: 20px; }
  .album-detail-cover { width: 180px; }
  .album-detail-title { font-size: 24px; }
}

.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 50px 0;
  color: var(--text-3);
  font-size: 13px;
}
.bars { display: flex; align-items: flex-end; gap: 3px; height: 16px; }
.bars i {
  width: 3px;
  background: var(--accent);
  border-radius: 2px;
  animation: eq 1.1s var(--ease) infinite;
}
.bars i:nth-child(1) { height: 40%; animation-delay: 0s; }
.bars i:nth-child(2) { height: 90%; animation-delay: .15s; }
.bars i:nth-child(3) { height: 60%; animation-delay: .3s; }
.bars i:nth-child(4) { height: 100%; animation-delay: .45s; }

/* ============================= 档案页 ============================= */

.narrative-card {
  padding: 34px 36px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: .5px solid var(--line);
  box-shadow: var(--shadow-1);
  margin-bottom: 34px;
}
.narrative-stage {
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
}
.narrative-headline {
  margin: 0 0 18px;
  font-family: var(--font-serif);
  font-size: 30px;
  font-weight: 500;
  line-height: 1.35;
}
.narrative-lines p {
  margin: 0 0 10px;
  font-size: 14px;
  line-height: 1.9;
  color: var(--text-2);
}
.narrative-tags { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 18px; }
.narrative-tags span {
  padding: 4px 12px;
  border-radius: 13px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 12px;
}
.narrative-next {
  margin-top: 22px;
  padding-top: 18px;
  border-top: .5px solid var(--line);
  font-size: 12px;
  color: var(--text-3);
}
.narrative-next b { color: var(--text-2); font-weight: 500; }

.dim-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
  margin-bottom: 40px;
}
.dim-card {
  padding: 20px 22px 22px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: .5px solid var(--line);
}
.dim-card h4 {
  /* 卡头做成两端对齐的一行：左边是维度名，右边挂这把尺子的量程（v0.9.74）。
     数字改成 ±100% 的偏差之后，得**就地**说明 100% 是什么口径 ——
     否则又变成一个没来由的百分数。 */
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 16px;
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-3);
  font-weight: 500;
}
/* 量程标：刻意比标题更轻（去到字距、降对比）—— 它是注解，不是第二个标题 */
.dim-card h4 em {
  flex: 0 0 auto;
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0;
  opacity: .75;
  font-variant-numeric: tabular-nums;
}
.dim-row { margin-bottom: 12px; }
.dim-row:last-child { margin-bottom: 0; }
.dim-row-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
  margin-bottom: 5px;
}
.dim-row-head span:first-child {
  /* flex:1 + min-width:0 是省略号能生效的前提（v0.9.71 补上）：
     只写 overflow/text-overflow 而缺 min-width:0 时，flex 项的 min-width:auto
     会把它顶在内容宽度上 —— 省略号永远不出现，长名字把右侧分数直接挤出卡片。
     加上删除按钮之后这一列更挤，所以顺手补齐。 */
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dim-row-head em {
  font-style: normal;
  font-size: 11px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
/* 分数 + 删除按钮（v0.9.71）：同占右侧一小列且不参与收缩，
   名称那一列才能吃到剩余宽度、该省略时才省略。 */
.dim-side {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}
/* 删除按钮：18×18。刻意与 .dim-row-head 的文字高度（约 18.75px）齐平，
   目的是**不把行高撑大** —— 除了确认条的出现/消失，这一行的几何不该有任何变化。 */
.dim-del {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text-3);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: color .2s var(--ease), background .2s var(--ease);
}
.dim-del:hover { color: var(--like); background: var(--like-soft); }
.dim-del:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* 行内二次确认条（v0.9.71）：长在被删的那一行**下面**（.dim-row 的最后一个孩子），
   只会把这张卡往下撑一行，不动上面的名称 / 分数 / 条形 —— 位置即指认，
   用户不会怀疑「它问的是哪一条」。 */
.dim-ask {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
  font-size: 11.5px;
  color: var(--text-2);
}
.dim-ask > span:first-child { flex: 1; min-width: 0; }
.dim-ask button {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: 999px;
  border: .5px solid var(--line-strong);
  background: none;
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 11.5px;
  line-height: 1.4;
  cursor: pointer;
  transition: background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}
.dim-ask button:hover { background: var(--surface-2); color: var(--text); }
.dim-ask button.dim-ask-yes {
  border-color: transparent;
  background: var(--like-soft);
  color: var(--like);
}
.dim-ask button.dim-ask-yes:hover { background: var(--like); color: #fff; }
.dim-ask button:disabled { opacity: .55; cursor: default; }
.dim-bar {
  position: relative;
  height: 5px;
  border-radius: 3px;
  background: var(--surface-2);
  overflow: hidden;
}
.dim-bar i {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 3px;
  background: var(--accent);
  transition: width .6s var(--ease), left .6s var(--ease);
}
.dim-bar i.is-neg { background: var(--text-3); }
.dim-axis {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line-strong);
}
.dim-empty { font-size: 12.5px; color: var(--text-3); }

.history { margin-bottom: 20px; }
.history-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.history-head h3 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 20px;
  font-weight: 500;
}
.text-btn {
  font-size: 12.5px;
  color: var(--text-3);
  padding: 4px 0;
  border-bottom: .5px solid transparent;
  transition: color .2s, border-color .2s;
}
.text-btn:hover { color: var(--like); border-color: var(--like); }

/* 「连接 Apple Music」的两段式状态：正在准备 / 可以点了。
   MusicKit 那 600 KB 在后台下，下好之前按钮是灰的，下好了才亮起来请用户点。 */
.text-btn.is-busy {
  color: var(--text-3);
  opacity: .65;
  cursor: progress;
}
.text-btn.is-cta {
  color: var(--like);
  border-color: var(--like);
  font-weight: 500;
}
.text-btn.is-cta::after {
  content: '';
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-left: 6px;
  border-radius: 50%;
  background: currentColor;
  vertical-align: middle;
  animation: mkPulse 1.4s ease-in-out infinite;
}
@keyframes mkPulse {
  0%, 100% { opacity: .25; transform: scale(.8); }
  50%      { opacity: 1;   transform: scale(1.15); }
}
@media (prefers-reduced-motion: reduce) {
  .text-btn.is-cta::after { animation: none; }
}

.history-list { display: flex; flex-direction: column; }
.history-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 4px;
  border-bottom: .5px solid var(--line);
}
.history-item img {
  width: 38px;
  height: 38px;
  border-radius: 7px;
  object-fit: cover;
  background: var(--surface-2);
}
.history-item .hi-main { flex: 1; min-width: 0; }
.history-item .hi-title {
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.history-item .hi-sub {
  font-size: 11.5px;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.history-item .hi-tag {
  font-size: 11.5px;
  padding: 2px 9px;
  border-radius: 10px;
}
.hi-tag.is-like { background: var(--like-soft); color: var(--like); }
.hi-tag.is-dislike { background: var(--surface-2); color: var(--text-2); }
.hi-tag.is-implicit { background: transparent; color: var(--text-2); border: 1px dashed var(--line); }
.history-item button {
  font-size: 11.5px;
  color: var(--text-3);
  opacity: 0;
  transition: opacity .2s;
}
.history-item:hover button { opacity: 1; }
.history-item button:hover { color: var(--like); }

/* ============================= 播放条 ============================= */

.playbar {
  grid-area: bar;
  position: relative;
  z-index: 50;
  background: var(--glass);
  backdrop-filter: saturate(180%) blur(24px);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  border-top: .5px solid var(--line);
  box-shadow: var(--shadow-3);
}

.playbar-progress {
  height: 3px;
  background: var(--line);
  cursor: pointer;
  transition: height .2s;
}
.playbar-progress:hover { height: 5px; }
.playbar-progress-fill {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width .12s linear;
}

.playbar-inner {
  height: calc(var(--playbar-h) - 3px);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 20px;
  /* ⚠️ 已知问题（v0.9.71 量到、未修，留给下一轮）：窄屏（≤900px）下这一排是
     **不可收缩**的 —— 封面 50 + meta 120 + 徽章 + 控制排 114 + 右侧（时间 + 三个小按钮）172
     + 四个 gap 64 + 内边距 40 ≈ **623px**，而它是 .app 的 grid item，
     min-width:auto 会把整列顶到 608px → 430px 视口下整页横向可滚 **193px**
     （线上实测 doc=623 / vw=430；390 与 1440 同样受 623 这条下限影响，只是 1440 装得下）。
     它只在「有歌在播、playbar 显示」时出现，与被登录态掩盖着，
     所以躲过了 v0.9.66 那一轮窄屏验收（那边量的是设置面板内部，不是整页）。
     修它要给窄屏定一套取舍：隐藏封面 / 徽章 / 时间，或让 meta 参与收缩 ——
     那是产品决策，不顺手做。 */
}

.pb-cover {
  position: relative;
  width: 50px;
  height: 50px;
  border-radius: 9px;
  overflow: hidden;
  flex: none;
  background: var(--surface-2);
  box-shadow: var(--shadow-1);
}
.pb-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pb-cover-hint {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, .3);
  color: #fff;
  opacity: 0;
  transition: opacity .25s;
}
.pb-cover:hover .pb-cover-hint { opacity: 1; }

.pb-meta { min-width: 0; width: 190px; flex: none; }
.pb-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pb-artist {
  margin: 1px 0 0;
  font-size: 11.5px;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pb-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 auto;
}

.ctl {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--text-2);
  transition: background .2s, color .2s, transform .15s;
}
.ctl:hover { background: var(--surface-2); color: var(--text); }
.ctl:active { transform: scale(.93); }
.ctl.is-primary { color: var(--text); }
.ctl.is-primary .ic { width: 21px; height: 21px; }
.ctl.is-small { width: 30px; height: 30px; }
.ctl.is-small .ic { width: 16px; height: 16px; }
.ctl.is-on { color: var(--like); background: var(--like-soft); }
.ctl.is-big { width: 60px; height: 60px; }
.ctl.is-big .ic { width: 26px; height: 26px; }

.pb-right {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  flex: none;
}
.pb-time {
  font-size: 11.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  margin-right: 6px;
}

/* ========================== 正在播放全屏 ========================== */

.nowplaying {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  animation: npIn .5s var(--ease);
}
@keyframes npIn {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: none; }
}

.np-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: blur(60px) saturate(150%);
  opacity: .35;
  transform: scale(1.2);
}
.nowplaying::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: .84;
}
html[data-theme="dark"] .nowplaying::before { opacity: .88; }

.np-inner {
  position: relative;
  width: min(460px, 88vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-height: 92vh;
  overflow-y: auto;
}

.np-close {
  position: absolute;
  top: -8px;
  right: 0;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--text-2);
}
.np-close:hover { background: var(--surface-2); }

.np-art {
  position: relative;
  width: min(320px, 74vw);
  aspect-ratio: 1;
  margin-bottom: 34px;
}
.np-art img {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .28);
  background: var(--surface-2);
}
.np-vinyl {
  position: absolute;
  z-index: 1;
  top: 6%;
  left: 12%;
  width: 82%;
  height: 88%;
  border-radius: 50%;
  background:
    repeating-radial-gradient(circle at 50% 50%,
      rgba(255, 255, 255, .05) 0 2px,
      rgba(0, 0, 0, .05) 2px 4px);
  box-shadow: inset 0 0 40px rgba(0, 0, 0, .3);
  transition: transform .8s var(--ease);
}
.np-art.is-spinning .np-vinyl { transform: translateX(26%) rotate(180deg); }
.np-art.is-spinning img { animation: artFloat 6s ease-in-out infinite; }
@keyframes artFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-8px) rotate(1deg); }
}

.np-eyebrow {
  margin: 0 0 10px;
  font-size: 10.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent);
}
/* 全屏页眉：网易云出声时转绿 —— 与播放器徽章同一套口径（文案不点渠道名，渠道交给颜色） */
.np-eyebrow.is-net { color: #2C7A55; }
html[data-theme="dark"] .np-eyebrow.is-net { color: #7FC9A2; }
.np-title {
  margin: 0 0 6px;
  font-family: var(--font-serif);
  font-size: 26px;
  font-weight: 500;
  line-height: 1.35;
}
.np-artist { margin: 0 0 14px; font-size: 14px; color: var(--text-2); }
.np-reason {
  margin: 0 0 26px;
  font-size: 12px;
  color: var(--text-3);
  line-height: 1.7;
  max-width: 30em;
}
.np-reason:empty { display: none; }

.np-progress { width: 100%; margin-bottom: 22px; }
.np-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--line-strong);
  cursor: pointer;
  overflow: hidden;
  margin-bottom: 8px;
}
.np-fill { height: 100%; width: 0; background: var(--accent); transition: width .12s linear; }
.np-time {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.np-controls {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-bottom: 30px;
}
.np-controls .ctl { width: 44px; height: 44px; }
.np-controls .ctl .ic { width: 20px; height: 20px; }
.np-controls .ctl.is-primary {
  background: var(--text);
  color: var(--bg);
}
.np-controls .ctl.is-primary:hover { opacity: .88; background: var(--text); }

.np-verdict { display: flex; gap: 12px; }
.verdict-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 40px;
  padding: 0 24px;
  border-radius: 20px;
  border: .5px solid var(--line-strong);
  font-size: 13.5px;
  color: var(--text-2);
  transition: all .22s var(--ease);
}
.verdict-btn .ic { width: 16px; height: 16px; }
.verdict-btn.is-like:hover, .verdict-btn.is-like.is-on {
  background: var(--like-soft);
  border-color: transparent;
  color: var(--like);
}
.verdict-btn.is-dislike:hover, .verdict-btn.is-dislike.is-on {
  background: var(--surface-2);
  border-color: transparent;
  color: var(--text);
}
/* 分享：中性档，介于 like/dislike 之间，hover 反显 */
.verdict-btn.is-share {
  background: var(--surface-2);
  color: var(--text-2);
  border-color: transparent;
  min-width: 40px;
  padding: 0 14px;
}
.verdict-btn.is-share:hover {
  background: var(--text);
  color: var(--bg);
  transform: translateY(-1px);
}
.verdict-btn.is-share .ic { width: 15px; height: 15px; }

/* ============================== 登录 ============================== */

.onboarding {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  background: var(--glass);
  backdrop-filter: saturate(180%) blur(30px);
  -webkit-backdrop-filter: saturate(180%) blur(30px);
  animation: viewIn .5s var(--ease);
}
.onboarding.is-hidden { display: none; }

.ob-card {
  width: min(420px, 88vw);
  padding: 52px 44px 40px;
  text-align: center;
  background: var(--surface);
  border: .5px solid var(--line);
  border-radius: 26px;
  box-shadow: var(--shadow-2);
}
.ob-card .brand-mark { justify-content: center; margin-bottom: 22px; }
.ob-card h1 {
  margin: 0 0 14px;
  font-family: var(--font-serif);
  font-size: 34px;
  font-weight: 500;
  letter-spacing: .14em;
}
.ob-sub {
  margin: 0 0 32px;
  font-size: 13.5px;
  line-height: 1.9;
  color: var(--text-2);
}
.apple-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  height: 46px;
  border-radius: 14px;
  background: var(--text);
  color: var(--bg);
  font-size: 14.5px;
  font-weight: 500;
  transition: transform .2s var(--ease), opacity .2s;
}
.apple-btn:hover { transform: translateY(-1px); }
.apple-btn:active { transform: scale(.99); }
.apple-btn .ic { width: 19px; height: 19px; }
.apple-btn[disabled] { opacity: .45; cursor: default; transform: none; }

/* 手机号表单与 Apple 按钮之间的「或」分隔 */
.ob-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 22px 0 18px;
  color: var(--text-3);
  font-size: 11px;
}
.ob-divider::before,
.ob-divider::after {
  content: '';
  flex: 1;
  height: .5px;
  background: var(--line);
}

/* 手机号输入：+86 前缀与号码在同一个框里，视觉上就是一个整体 */
.ob-form { display: grid; gap: 10px; }
.ob-input {
  display: flex;
  align-items: center;
  height: 44px;
  padding-left: 15px;
  border: .5px solid var(--line);
  border-radius: 13px;
  background: var(--bg);
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.ob-input:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
.ob-cc {
  flex: none;
  padding-right: 11px;
  margin-right: 11px;
  border-right: .5px solid var(--line);
  color: var(--text-3);
  font-size: 13.5px;
  letter-spacing: .02em;
}
.ob-input .ob-field { border: 0; background: none; padding: 0 15px 0 0; height: 42px; }
.ob-input .ob-field:focus { box-shadow: none; }

.ob-field {
  width: 100%;
  height: 44px;
  padding: 0 15px;
  border: .5px solid var(--line);
  border-radius: 13px;
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.ob-field::placeholder { color: var(--text-3); }
.ob-field:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
/* 手机号是主入口，按钮跟着做主角；Apple 按钮降为同级备选 */
.ob-submit {
  height: 46px;
  border-radius: 14px;
  border: .5px solid var(--line);
  background: var(--text);
  color: var(--bg);
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 500;
  transition: transform .2s var(--ease), opacity .2s;
}
.ob-submit:hover { transform: translateY(-1px); }
.ob-submit:active { transform: scale(.99); }
.ob-submit[disabled] { opacity: .5; cursor: default; transform: none; }
.ob-form-msg {
  margin: 2px 0 0;
  min-height: 14px;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--text-3);
}
.ob-form-msg.is-error { color: #d0463a; }

.ob-card .text-btn { margin-top: 18px; }

/* Apple 弹窗报错时的备用通道：做成低调的一行小字，不抢主按钮 */
.ob-card .text-btn.ob-alt {
  margin-top: 10px;
  font-size: 12.5px;
  padding: 4px 10px;
  color: var(--muted);
  border-color: transparent;
}
.ob-hint {
  margin: 20px 0 0;
  font-size: 11px;
  line-height: 1.7;
  color: var(--text-3);
}

/* ============================== Toast ============================== */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--playbar-h) + 22px);
  transform: translateX(-50%);
  z-index: 400;
  padding: 10px 20px;
  border-radius: 20px;
  background: var(--text);
  color: var(--bg);
  font-size: 13px;
  box-shadow: var(--shadow-2);
  animation: toastIn .35s var(--ease);
}
@keyframes toastIn {
  from { opacity: 0; transform: translate(-50%, 10px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
/* 之前 .stage-read 就写着 animation: fadeUp，但关键帧一直没定义 —— 顺手补上 */
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================== 响应式 ============================== */

@media (max-width: 900px) {
  .app {
    grid-template-columns: 1fr;
    /* 窄屏下侧栏整体收起，导航改用一行横向的 .mobilenav 落在这里 */
    grid-template-rows: var(--topbar-h) auto 1fr auto;
    grid-template-areas: "top" "side" "main" "bar";
  }
  .sidebar { display: none; }
  /* 侧栏一没，备案号就得在主区底部露出来（合规信息不能只在桌面可见） */
  .legal-foot { display: flex; }
  .mobilenav {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 8px 14px;
    background: var(--glass);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    border-bottom: .5px solid var(--line);
  }
  .mnav-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border-radius: 999px;
    color: var(--text-2);
    font-size: 12.5px;
    transition: background .18s var(--ease), color .18s var(--ease);
  }
  .mnav-item .ic { width: 15px; height: 15px; }
  .mnav-item.is-active { background: var(--surface-2); color: var(--text); font-weight: 500; }
  .main { padding: 28px 24px 48px; }
  .hero-title { font-size: 30px; }
  /* 搜索框 160 → 200（同上，往左长；浮层宽度基础规则已按 100vw 自适应，无需覆盖） */
  .searchbox { width: 200px; }
  .pb-meta { width: 120px; }
  .brand-text em { display: none; }
}

/* ========================== 今日 · 播放器 ========================== */

.stage {
  display: grid;
  grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
  gap: 44px;
  align-items: start;
  max-width: 940px;
  margin: 0 auto;
  padding: 20px 4px 8px;
  animation: fadeUp .55s var(--ease) both;
}

/* ---- 封面 ---- */
.stage-art {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
}
.stage-halo {
  position: absolute;
  inset: 10% 6% -4% 6%;
  border-radius: 34%;
  background-size: cover;
  background-position: center;
  filter: blur(34px) saturate(1.5);
  opacity: .42;
  transition: background-image .6s var(--ease), opacity .4s var(--ease);
  pointer-events: none;
}
.stage-art.is-playing .stage-halo { opacity: .62; }
.stage-spin {
  position: absolute;
  inset: 0;
  border-radius: 26px;
  box-shadow: 0 0 0 0 var(--accent-soft);
  transition: box-shadow .6s var(--ease);
  pointer-events: none;
}
/* .stage-art.is-playing .stage-spin { box-shadow: 0 0 0 7px var(--accent-soft); } */
.stage-art img {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 22px;
  background: var(--surface-2);
  box-shadow: var(--shadow-2);
}
.stage-art img[src=""] { visibility: hidden; }

/* ---- 文字区 ---- */
.stage-body { min-width: 0; }
.stage-tags { display: flex; align-items: center; flex-wrap: wrap; gap: 9px; margin-bottom: 14px; }

/* —— 三枚 tag 等高对齐（音源 / 完整 / 音质）——
   它们的实测高度原来是各靠上下 padding 撑出来的：.q-menu-trigger 上下 3px、.mode-badge 上下 4px，
   内容里又有 15px 的图标、6px 的圆点、9px 的三角箭头和各不相同的行盒，并排渲染能差 2px 上下，
   看上去就是「三枚胶囊歪着」。这里统一给固定高度 + flex 居中，行盒的细微差别再也传不到外观；
   左右内距也统一成 11px，三枚胶囊的圆角端才对得齐。
   只作用于主页这一排 —— 底部迷你条那枚 .mode-badge.is-mini 不在 .stage-tags 里，不受影响。 */
.stage-tags > .mode-badge,
.stage-tags .q-menu-trigger {
  height: 24px;
  padding: 0 11px;
  box-sizing: border-box;
  align-items: center;
  line-height: 1;
}

/* 标签分组分隔符：把「播放方式」与「音质」两组信息在视觉上切开。
   高度跟着三枚 tag 的视觉重量收一档（15 → 13px），免得比胶囊还抢眼。 */
.tag-sep { width: 1px; height: 13px; background: var(--line); flex: none; }

/* 播放方式徽章：只标识，不切换 —— 光标、指针事件都别暗示能点 */
.mode-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .02em;
  background: rgba(196, 128, 58, .13);
  color: #93601F;
  border: .5px solid rgba(196, 128, 58, .26);
  white-space: nowrap;
  cursor: default;
  user-select: none;
}
/* 小圆点：试听＝空心，完整＝实心 —— 不靠颜色也能一眼分辨 */
.mode-badge::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.mode-badge.is-preview::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px currentColor;
}
.mode-badge.is-wait::before,
.mode-badge.is-none::before { display: none; }
.mode-badge.is-full {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: rgba(161, 101, 74, .28);
}
/* 网易云出声：绿色系，一眼区别于 Apple 那套棕色调 —— 意味着「这一首不走授权那条路」 */
.mode-badge.is-net {
  background: rgba(52, 130, 94, .13);
  color: #2C7A55;
  border-color: rgba(52, 130, 94, .30);
}
.mode-badge.is-net::before { background: currentColor; }
html[data-theme="dark"] .mode-badge.is-net { color: #7FC9A2; background: rgba(84, 178, 128, .16); border-color: rgba(84, 178, 128, .34); }
.mode-badge.is-mini { padding: 2px 8px; font-size: 10.5px; gap: 5px; }
.mode-badge.is-mini::before { width: 5px; height: 5px; }
.mode-badge.is-wait,
.mode-badge.is-none {
  background: var(--surface-2);
  color: var(--text-3);
  border-color: var(--line);
}
html[data-theme="dark"] .mode-badge { color: #E2AC69; background: rgba(226, 172, 105, .14); border-color: rgba(226, 172, 105, .26); }
html[data-theme="dark"] .mode-badge.is-full { color: #D3A08A; background: rgba(211, 160, 138, .14); border-color: rgba(211, 160, 138, .26); }
html[data-theme="dark"] .mode-badge.is-wait,
html[data-theme="dark"] .mode-badge.is-none { color: var(--text-3); background: var(--surface-2); border-color: var(--line); }

/* 「本次第 n 首」（v0.9.57 从音源标签行挪进 .stage-foot 的计数行，紧跟其后的是
   「后面还有 x 首没听…」）。 */
.pos-badge {
  font-size: 11.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
/* 还没开始播放时这一格是空的 —— 整格消失，否则计数行前面会留一个空档。
   ⚠️ 写成 `<span id="posBadge"></span>`（标签之间不能有空白），否则 :empty 不匹配。 */
.pos-badge:empty { display: none; }
/* 与后面的队列计数之间补一个分隔点：两句同色同号的灰字挨着，没点就读不断句。
   元素本身 display:none 时伪元素跟着不渲染，所以不必再加 :not(:empty) 条件。 */
.pos-badge::after {
  content: '·';
  margin-left: 6px;
  opacity: .7;
}

/* —— 主页音质档位：胶囊分段控件，选中项点亮 ——
   管的是「完整曲目用多少 kbps」，不是「试听 / 完整」的选择；
   当前这首走 30 秒试听时档位不生效，用 .is-na 如实置灰。 */
/* —— 主页音质档位：下拉菜单（折叠态只显示「音质 · {当前档位} ▾」）——
   管的是「完整曲目用多少 kbps」，不是「试听 / 完整」的选择；
   当前这首走 30 秒试听时档位不生效，用 .is-na 如实置灰。 */
.q-menu { position: relative; display: inline-block; }
.q-menu-trigger {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 11px;
  border-radius: 999px;
  background: var(--surface-2);
  border: .5px solid var(--line);
  color: var(--text-3);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .02em;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity .2s var(--ease), color .15s ease, border-color .15s ease;
}
.q-menu-trigger:hover { color: var(--text); border-color: var(--line-strong, var(--text-3)); }
.q-menu-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.q-menu.is-open .q-menu-trigger {
  color: var(--accent);
  background: var(--surface);
  border-color: var(--line-strong, var(--text-3));
}
.q-menu-prefix { color: var(--text-3); font-weight: 500; }
.q-menu-trigger:hover .q-menu-prefix,
.q-menu.is-open .q-menu-prefix { color: var(--accent); }
.q-menu-current { color: inherit; font-weight: 600; }
.q-menu-caret {
  display: inline-block;
  font-size: 9px;
  line-height: 1;
  transition: transform .18s var(--ease);
}
.q-menu.is-open .q-menu-caret { transform: rotate(180deg); }
.q-menu.is-na { opacity: .45; }
.q-menu.is-na .q-menu-trigger { cursor: default; }
.q-menu.is-na .q-menu-trigger:hover { color: var(--text-3); }

.q-menu-list {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 100%;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--surface);
  border: .5px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 32px -10px rgba(0,0,0,.18), 0 2px 8px -4px rgba(0,0,0,.08);
  z-index: 40;
  animation: q-menu-in .14s var(--ease) both;
}
@keyframes q-menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.q-menu-list[hidden] { display: none; }
.q-menu-opt {
  display: block;
  width: 100%;
  appearance: none;
  border: 0;
  background: transparent;
  text-align: left;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  padding: 6px 12px;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s ease, color .12s ease;
}
.q-menu-opt:hover { background: var(--surface-2); color: var(--text); }
.q-menu-opt.is-on {
  background: rgba(var(--accent-rgb, 211,160,138), .12);
  color: var(--accent);
}
.q-menu-opt.is-on::after { content: ' · 当前'; font-weight: 500; color: var(--accent); opacity: .75; font-size: 10.5px; }

/* 网易云账号音质等级徽章（v0.9.43）：音质菜单里的一行只读说明。
   展示「当前账号」能到哪一档；选档超出等级时 app.js 据它提示（绝不报错）。 */
.q-menu-net-chip {
  display: block;
  padding: 7px 12px 5px;
  margin-bottom: 4px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-3);
  border-bottom: 1px dashed var(--line, rgba(128,128,128,.25));
}
.q-menu-net-chip b { color: var(--accent); font-weight: 700; }
.q-menu-net-chip[hidden] { display: none; }

/* —— 音源模式选择器（智能 / Apple Music / 网易云）——
   与音质菜单共用 q-menu 骨架；这里只补图标与选项排版。 */
.src-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  color: var(--accent);
}
/* 宽 248px 是按**最长那句副标题**倒推的：12 个汉字 × 10.5px ≈ 126px，
   再留出图标 26 + 两道 10 的间隙 + 右侧「· 当前」（选中态才有，约 30px）
   与左右内距 24 —— 刚好装下且不挤。副标题据此才能稳稳压在一行里。 */
.src-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  white-space: normal;
  min-width: 248px;
  padding: 8px 12px;
}
.src-opt-ic {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  object-fit: cover;
  display: inline-block;
}
.src-opt-ic-svg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  color: var(--accent);
}
.src-opt-main {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1;
  min-width: 0;
}
.src-opt-main b {
  font-size: 12.5px;
  font-weight: 700;
  color: inherit;
  white-space: nowrap;
}
/* 副标题恒一行。三条文案都按「一行装得下」写短（见 index.html），
   这里再用 nowrap 把住底线 —— 万一以后有人写长了，也只会省略号收尾，
   不会把菜单项撑成两行、把三条选项的高低拉歪。 */
.src-opt-main i {
  font-style: normal;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text-3);
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* 选中态的「· 当前」是 flex 里的第三个兄弟，别让它被压窄换行 */
.src-opt.is-on::after { flex: none; }
.q-menu-opt.is-on .src-opt-main i { color: var(--accent); opacity: .8; }
/* Apple 模式需要授权，未授权时整项置灰不可点 */
.src-opt.is-na { pointer-events: none; opacity: .45; }

.stage-title {
  font-family: var(--font-serif);
  font-size: clamp(26px, 3vw, 38px);
  line-height: 1.22;
  letter-spacing: -.01em;
  margin: 0 0 8px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* 「歌手 · 专辑 · 年份」+ 生效平台同一排（v0.9.55）：
   图标紧跟文字右侧。文字用 `flex: 0 1 auto` + `min-width: 0` 才肯让出省略号，
   图标 `flex: none` 保证永远不被压扁 —— 宁可歌名被截，也不能让平台标变形。 */
.stage-sub {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  min-width: 0;
}
.stage-artist {
  margin: 0;
  flex: 0 1 auto;
  min-width: 0;
  font-size: 14px;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 次要操作排：收藏专辑 + 分享同排（v0.9.45；分享原本夹在无感/心动中间）
   左对齐 = 跟随标题/艺人那一条左边线 —— 原本单枚 inline-flex 就是左对齐的，
   这里若用 center 会把这一排整体推到中间，看着就是「往右偏」（v0.9.46 修）。 */
/* 次要操作排：收藏专辑 / 分享单曲（v0.9.58 起**两枚等宽**）。
   做法 = 「收缩到内容的网格 + 等分列」：
     · `grid-auto-columns: 1fr` → 两列取同一个宽度（取较宽的那个）；
     · `width: max-content` → 容器只占内容那么宽，两枚胶囊不会被拉成半屏宽。
   为什么不能只靠文字长度：收藏那枚的文案会在「收藏专辑 / 已收藏」之间变（3↔4 字），
   纯靠内容宽度就会一会儿胖一会儿瘦，两枚并排看着就是歪的。
   为什么不用 `flex: 1`：那是按容器宽均分，容器撑满整行 → 两枚胶囊巨大。
   左对齐怎么来：容器缩到内容宽后本身就贴着左沿起排，不再需要 `justify-content`
   （v0.9.46 那条「必须 flex-start、否则右偏」的坑，在这里由 max-content 天然满足）。
   只剩一枚可见时（专辑信息缺失会藏掉收藏那枚）：只有一列，它回到自己的自然宽度，
   不会孤零零撑一大条。 */
.stage-meta {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: max-content;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  min-height: 28px;
}

/* 专辑收藏：把正在播这张唱片收进唱片架 */
.album-collect {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin: 0;
  padding: 6px 13px;
  border: .5px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-2);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: border-color .2s, color .2s, background .2s;
}
.album-collect .ic { width: 14px; height: 14px; }
.album-collect:hover { border-color: var(--accent); color: var(--accent); }
.album-collect.is-on {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
/* 版权不满足（v0.9.50）：置灰 + 明确「不可点」，但**不要**用 opacity 压到看不见 ——
   用户需要读得出「这里有个按钮，只是现在不能用」，工具提示里写着原因。 */
.album-collect.is-locked,
.album-collect.is-locked:hover {
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--text-3);
  opacity: .55;
  cursor: not-allowed;
}

/* ── 生效平台那一排小图标（v0.9.50；v0.9.55 移到「歌手 · 专辑 · 年份」右侧）────
   同一个组件用在两处：首页播放器单曲的歌手行（#stagePlatforms）、专辑详情页（#albumDetailPlatforms）。
   生效 = 原色；不生效 = 灰度 + 压暗（`.is-off`）。用灰度而不是直接降 opacity，
   是为了让「哪个平台」仍然一眼认得出 —— 灰掉的网易云还是网易云那个图标。 */
.stage-plats { display: inline-flex; align-items: center; gap: 9px; flex: none; }
.plat-row { display: inline-flex; align-items: center; gap: 6px; }
.plat-label { font-size: 11.5px; color: var(--text-3); }
.plat-ico {
  width: 15px;
  height: 15px;
  border-radius: 4px;
  display: block;
  filter: none;
  transition: filter .2s, opacity .2s;
}
.plat-ico.is-off { filter: grayscale(1); opacity: .32; }
.album-detail-plats {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}

/* ---- 专辑详情页 · 编辑描述（v0.9.51）----
   默认三行截断（-webkit-line-clamp），点「更多」展开；没有描述整块 hidden */
.album-detail-desc { margin-top: 4px; }
.album-detail-desc-text {
  margin: 0;
  font-size: 13px;
  line-height: 1.65;
  color: var(--text-2);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  cursor: default;
}
.album-detail-desc.is-open .album-detail-desc-text {
  -webkit-line-clamp: unset;
  overflow: visible;
}
.album-detail-desc-toggle {
  margin-top: 4px;
  padding: 0;
  border: none;
  background: none;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
}
.album-detail-desc-toggle:hover { text-decoration: underline; }

/* ---- 专辑详情页 · 「你喜欢过的歌」汇总行（v0.9.51）---- */
.album-liked-note {
  margin: 14px 0 2px;
  padding: 8px 14px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: 12.5px;
  color: var(--text-2);
}
.album-liked-note b { color: var(--like); font-weight: 600; }
.album-liked-note-ico { display: inline-flex; vertical-align: -2px; margin-left: 2px; }
.album-liked-note-ico .ic { width: 13px; height: 13px; color: var(--like); }

/* 曲目行上的红心：你 like 过的歌（v0.9.51） */
.album-track-like {
  flex: none;
  display: inline-flex;
  color: var(--like);
}
.album-track-like .ic { width: 14px; height: 14px; }

/* ---- 专辑详情页 · 版权落款（v0.9.51）----
   对齐 Apple Music 专辑页脚：发行日期 / 曲目数与总时长 / ℗© 行 / 唱片公司 */
.album-detail-copy {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.album-detail-copy p {
  margin: 0 0 4px;
  font-size: 12px;
  color: var(--text-3);
  line-height: 1.5;
}
.stage-why { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
.stage-why span {
  font-size: 11.5px;
  color: var(--text-3);
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--surface-2);
}

/* ---- 描述区块：一个槽位，三种状态（v0.9.64）----
   v0.9.61：这一块从播放器中部搬到了**最末尾**（见 index.html 的 #stageNote）。
   它是临时反馈，出现 / 消失都不该推动上面的进度条与控制按钮，所以：
   - 上边距只跟「它上面那行」（.stage-foot 里的连接提示 / 计数行）拉开一点距离即可，
     不再是从 .stage-why 往下让位的 16px；
   - **下边距留 0** —— 它下面没有东西了，留白交给 .stage 自己的 padding-bottom，
     否则会凭空多出一条空隙，看起来像被截断。
   v0.9.64：原来的两块（「推荐理由」/「我这样理解你」）合成这一个槽位。
   三种状态**共用同一条卡片样式**（一样的外观，只换抬头与正文）—— 读起来才是
   「同一个声音在说话」，而不是两块不同的东西轮流抢位置。 */
.stage-read {
  margin: 14px 0 0;
  padding: 12px 16px;
  border-left: 2px solid var(--accent);
  background: linear-gradient(90deg, var(--accent-soft), transparent 78%);
  border-radius: 0 12px 12px 0;
  animation: fadeUp .4s var(--ease) both;
}
/* 槽位**换内容**时补一次淡入。
   上面那条 fadeUp 只在 hidden → 显示那一次跑（display:none 会重启动画），
   可这一块更多是在**已经可见**的时候从「推荐理由」换成「我这样理解你」——
   不补一下就是硬切，像文字闪了一下。app.js 的 renderStageNote 在状态变化时
   remove → 强制 reflow → add，让这条动画重新开始。 */
.stage-read.is-swap { animation: fadeUp .28s var(--ease) both; }
.read-label {
  display: block;
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 5px;
}
/* 正文**按内容长短自适应 1~2 行**（v0.9.69，替掉 v0.9.62 的「一律压成一行」）。
   为什么要放开：这句话是「我懂你」的正面陈述，而它被压成一行 + 省略号时，
   被吃掉的那半截恰恰是**洞察** —— 用户永远只看得到前半句的复述。
   现在短的占一行、长的自然占两行，气口出来了，句子才像在说话。

   上界仍是硬的：两行封顶、溢出省略号，全文挂 title（app.js 里设置）。
   所以这块高度最多浮动**一行**（≈22px），不会失控。
   为什么敢浮动：它是 .stage-body 的**最后一个孩子** —— 长高只让容器往下长，
   上面的进度条 / 控制排 / 页脚一个像素都不动（tests/shot-v0961 的零漂移断言钉着）。
   clamp 用 -webkit- 前缀写法（与 .card-why / .media-title / 专辑详情描述同一套，
   Chrome / Safari / Firefox 都认这条别名）。 */
.read-line {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.62;
  color: var(--text);
  font-family: var(--font-serif);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.read-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.read-tags span {
  font-size: 11px;
  padding: 2.5px 8px;
  border-radius: 999px;
  background: var(--surface);
  border: .5px solid var(--line-strong);
  color: var(--text-2);
}

/* ---- 进度 ---- */
.stage-progress { margin: 22px 0 4px; }
.stage-bar {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: var(--surface-2);
  cursor: pointer;
}
.stage-bar:hover { background: var(--line-strong); }
.stage-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--text);
}
.stage-bar.is-preview .stage-fill { background: linear-gradient(90deg, #C4803A, #E0A75E); }
.stage-knob {
  position: absolute;
  top: 50%;
  left: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--text);
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity .18s var(--ease);
  pointer-events: none;
}
.stage-bar:hover .stage-knob { opacity: 1; }
.stage-time {
  display: flex;
  justify-content: space-between;
  margin-top: 7px;
  font-size: 11.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.stage-dur.is-preview { color: #A5712C; }

/* ---- 控制（v0.9.54）：一排四个等大按钮，两端与进度条对齐 ---- */
.stage-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 14px 0 0;
}
.stage-ctl-group { display: flex; align-items: center; gap: 10px; }
.round-btn {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: .5px solid var(--line-strong);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: transform .18s var(--ease), background .18s var(--ease), opacity .18s var(--ease);
}
.round-btn:hover { transform: translateY(-1px); }
.round-btn:active { transform: translateY(0) scale(.96); }
.round-btn .ic { width: 19px; height: 19px; }
/* 心动 / 无感：纯图标靠底色与描边颜色表达状态（实心/空心由 JS 换 symbol） */
.round-btn.is-like:hover, .round-btn.is-like.is-on {
  background: var(--like-soft);
  border-color: transparent;
  color: var(--like);
}
.round-btn.is-dislike:hover, .round-btn.is-dislike.is-on {
  background: var(--surface-2);
  border-color: transparent;
  color: var(--text);
}
/* 播放/暂停：同尺寸，只换成实心主色 —— 视觉锚点，不是「更大的按钮」 */
.round-btn.is-primary {
  background: var(--text);
  color: var(--bg);
  border-color: transparent;
  box-shadow: var(--shadow-2);
}
.round-btn.is-primary .ic { width: 21px; height: 21px; }

/* 播放器页脚（v0.9.57）：**两行**，不是一排 ——
   第一行是「这一轮听到哪儿了」（本次第 n 首 · 后面还有 x 首没听 · 已备 y 首），
   第二行是 Apple Music 连接状态/操作。以前两者挤在同一排，连接状态那句很长，
   会把计数顶到换行、又看着像同一句话的续写；改成纵向堆叠后各占一行、都在左沿起排。 */
.stage-foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  margin-top: 12px;
  font-size: 11.5px;
  color: var(--text-3);
  min-height: 18px;
}
.stage-foot-count {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
}
.stage-foot .text-btn { font-size: 11.5px; color: var(--accent); }

#stageLoading, .stage-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 60px 0;
  color: var(--text-3);
  font-size: 13px;
}

@media (max-width: 860px) {
  .stage {
    grid-template-columns: 1fr;
    gap: 26px;
    max-width: 460px;
    padding-top: 8px;
  }
  .stage-art { max-width: 300px; margin: 0 auto; }
  .stage-title { font-size: 27px; }
}

/* ========================== 档案页 · 双层结构 ========================== */
/* 上层是用户亲自写定的（可增删），下层是 Agent 推断的（只读）。
   两层视觉上必须有明确分野，否则用户会误以为自己能改 Agent 的判断。 */

.layer { margin-bottom: 42px; }

.layer-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 18px;
}

.layer-title h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 7px;
  font-family: var(--font-serif);
  font-size: 19px;
  font-weight: 500;
}

.layer-title h3 .ic { width: 15px; height: 15px; color: var(--accent); }

.layer-title p {
  margin: 0;
  max-width: 60ch;
  font-size: 12.5px;
  line-height: 1.75;
  color: var(--text-2);
}

.layer-count {
  flex: none;
  padding: 4px 12px;
  border-radius: 13px;
  background: var(--surface-2);
  border: .5px solid var(--line);
  font-size: 12px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  transition: background .2s, color .2s, border-color .2s;
}

.layer-count.is-full {
  background: var(--accent-soft);
  border-color: transparent;
  color: var(--accent);
}

.layer-lock {
  flex: none;
  padding: 4px 12px;
  border-radius: 13px;
  border: .5px dashed var(--line-strong);
  font-size: 11.5px;
  color: var(--text-3);
  letter-spacing: .02em;
}

/* ------------------------------ 点名区 ------------------------------ */

.pin-tabs { display: flex; gap: 6px; margin-bottom: 16px; }

.pin-tab {
  padding: 6px 15px;
  border-radius: 15px;
  border: .5px solid var(--line);
  background: var(--surface);
  font-size: 13px;
  color: var(--text-2);
  transition: background .18s, color .18s, border-color .18s;
}

.pin-tab:hover { color: var(--text); border-color: var(--line-strong); }
.pin-tab.is-active { background: var(--text); border-color: var(--text); color: #fff; }

.pin-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 10px;
}

.pin-chip {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 12px 9px 9px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: .5px solid var(--line);
  box-shadow: var(--shadow-1);
  transition: border-color .18s, transform .18s;
}

.pin-chip img,
.pin-chip .pin-glyph {
  width: 40px;
  height: 40px;
  border-radius: 9px;
  flex: none;
  object-fit: cover;
  background: var(--surface-2);
}

.pin-glyph {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--accent);
  border: .5px solid var(--line);
}

.pin-chip-main { flex: 1; min-width: 0; }

.pin-chip-main b {
  display: block;
  font-size: 13.5px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pin-chip-main span {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pin-chip > button {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--text-3);
  transition: background .18s, color .18s;
}

.pin-chip > button:hover { background: var(--like-soft); color: var(--like); }
.pin-chip > button .ic { width: 12px; height: 12px; }

/* 替换态：名额已满，整条 chip 变成「点我换掉」的目标 */
.pin-list.is-replacing .pin-chip {
  cursor: pointer;
  border-style: dashed;
  border-color: var(--accent);
  animation: pinPulse 1.7s var(--ease) infinite;
}

.pin-list.is-replacing .pin-chip:hover { transform: translateY(-1px); }
.pin-list.is-replacing .pin-chip > button { display: none; }

@keyframes pinPulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent-soft); }
  50% { box-shadow: 0 0 0 5px var(--accent-soft); }
}

.pin-empty {
  grid-column: 1 / -1;
  padding: 20px 2px;
  font-size: 12.5px;
  color: var(--text-3);
}

.pin-adder { margin-top: 14px; }

.pin-search {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 14px;
  max-width: 420px;
  border-radius: 18px;
  background: var(--surface);
  border: .5px solid var(--line);
  transition: border-color .18s, box-shadow .18s;
}

.pin-search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.pin-search .ic { width: 14px; height: 14px; flex: none; color: var(--text-3); }

.pin-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  outline: none;
  font-size: 13.5px;
}

.pin-results {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 10px;
  max-width: 520px;
  /* 风格档会一次列出三十多个官方流派，给个滚动区免得把页面撑太长 */
  max-height: 330px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 4px;
}

.pin-option {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 8px 10px;
  border-radius: 11px;
  text-align: left;
  transition: background .16s;
}

.pin-option:hover { background: var(--surface-2); }

.pin-option img,
.pin-option .pin-glyph { width: 36px; height: 36px; border-radius: 8px; flex: none; object-fit: cover; }

.pin-option-main { flex: 1; min-width: 0; }
.pin-option-main b { display: block; font-size: 13px; font-weight: 500; }
.pin-option-main span { display: block; margin-top: 1px; font-size: 11.5px; color: var(--text-3); }

.pin-option-state { flex: none; font-size: 11.5px; color: var(--text-3); }
.pin-option-state.is-on { color: var(--accent); }

.pin-hint {
  margin: 10px 0 0;
  min-height: 17px;
  font-size: 12px;
  color: var(--text-3);
}

.pin-hint.is-warn { color: var(--like); }
.pin-hint.is-ok { color: var(--accent); }

/* ── Apple Music 连接态 ─────────────────────────────────────────────
   .note-warn  侧栏底部把 MusicKit 的真实失败原因摆出来
   ──────────────────────────────────────────────────────────────── */
.note-warn { color: var(--like); }

/* ── Agent 控制台 ────────────────────────────────────────────────────
   说话而不是填表。模型档位、对话流、图片上传都收在这一块里，
   视觉上沿用「纸面 + 赭石」的克制调子，不引入新的色系。
   ──────────────────────────────────────────────────────────────── */
.agent-console .layer-title p { max-width: 62ch; }

.agent-log {
  max-height: 320px;
  overflow-y: auto;
  margin-bottom: 12px;
  padding-right: 4px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.agent-msg { max-width: 82%; font-size: 13.5px; line-height: 1.62; }
.agent-msg.is-user {
  align-self: flex-end;
  padding: 9px 13px;
  border-radius: var(--r-md) var(--r-md) 4px var(--r-md);
  background: var(--accent-soft);
  color: var(--text);
}
.agent-msg.is-agent {
  align-self: flex-start;
  padding: 9px 13px;
  border-radius: var(--r-md) var(--r-md) var(--r-md) 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-family: var(--font-serif);
}
.agent-msg.is-error { color: var(--like); border-color: var(--like-soft); }
.agent-msg.is-pending { color: var(--text-3); font-style: italic; }

.agent-acts { margin-top: 8px; display: flex; flex-direction: column; gap: 4px; }
.agent-act { position: relative; padding-left: 12px; font-size: 11.5px; color: var(--text-3); }
.agent-act::before { content: '·'; position: absolute; left: 3px; }
.agent-act.is-ok { color: var(--accent); }

.agent-cands { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.agent-cand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.agent-cand img { flex: none; width: 38px; height: 38px; border-radius: 7px; object-fit: cover; }
.agent-cand-main { flex: 1; min-width: 0; }
.agent-cand-main b { display: block; font-size: 13px; font-weight: 500; }
.agent-cand-main span { display: block; margin-top: 1px; font-size: 11.5px; color: var(--text-3); }
.agent-cand button {
  flex: none;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: transparent;
  color: var(--accent);
  font-size: 12px;
  cursor: pointer;
}
.agent-cand button:disabled { opacity: .5; cursor: default; }

.agent-form {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 6px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  transition: border-color .18s var(--ease);
}
.agent-form:focus-within { border-color: var(--accent); }

.agent-attach {
  flex: none;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-3);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.agent-attach:hover { color: var(--accent); background: var(--accent-soft); }
.agent-attach .ic { width: 17px; height: 17px; }

#agentMessage {
  flex: 1;
  min-width: 0;
  padding: 6px 0;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 13.5px;
  outline: none;
}

.agent-thumb { position: relative; flex: none; width: 34px; height: 34px; }
.agent-thumb img { width: 100%; height: 100%; border-radius: 8px; object-fit: cover; }
.agent-thumb button {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  background: var(--text);
  color: var(--bg);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.agent-send {
  flex: none;
  padding: 7px 16px;
  border: none;
  border-radius: 999px;
  background: var(--accent);
  color: var(--bg);
  font-size: 13px;
  cursor: pointer;
  transition: opacity .18s var(--ease);
}
.agent-send:hover { opacity: .88; }
.agent-send:disabled { opacity: .5; cursor: default; }

.agent-hint { margin: 9px 0 0; font-size: 11.5px; color: var(--text-3); }
.agent-hint.is-warn { color: var(--like); }

/* ==========================================================================
   设置弹窗
   —— 独立呼出的一层，遮罩是黑色半透明（用户点名要的）。
      面板本身仍然跟随主题（浅底深字 / 深底浅字），只有遮罩恒定压暗。
   ========================================================================== */

.settings {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: grid;
  place-items: center;
  padding: 24px;
}
.settings[hidden] { display: none; }

.settings-mask {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .52);
  backdrop-filter: blur(6px) saturate(120%);
  -webkit-backdrop-filter: blur(6px) saturate(120%);
  animation: maskIn .22s var(--ease);
}
@keyframes maskIn { from { opacity: 0; } to { opacity: 1; } }

.settings-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(720px, 100%);
  max-height: min(760px, calc(100vh - 48px));
  background: var(--surface);
  border: .5px solid var(--line-strong);
  border-radius: 22px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, .38);
  overflow: hidden;
  animation: panelIn .3s var(--ease);
}
@keyframes panelIn {
  from { opacity: 0; transform: translateY(12px) scale(.985); }
  to { opacity: 1; transform: none; }
}

.settings-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 26px 16px;
  border-bottom: .5px solid var(--line);
}
.settings-head h2 {
  margin: 0 0 4px;
  font-family: var(--font-serif);
  font-size: 21px;
  font-weight: 500;
  letter-spacing: .04em;
}
.settings-head p { margin: 0; font-size: 12px; color: var(--text-3); }
.settings-close {
  flex: none;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-2);
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.settings-close:hover { background: var(--line-strong); color: var(--text); }
.settings-close .ic { width: 14px; height: 14px; }

.settings-tabs {
  display: flex;
  gap: 6px;
  padding: 12px 26px;
  border-bottom: .5px solid var(--line);
  background: var(--surface-2);
}
.settings-tab {
  height: 30px;
  padding: 0 15px;
  border: .5px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--text-2);
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.settings-tab:hover { color: var(--text); }
.settings-tab.is-active {
  background: var(--surface);
  border-color: var(--line-strong);
  color: var(--text);
  box-shadow: var(--shadow-1);
}

.settings-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 22px 26px 28px;
  -webkit-overflow-scrolling: touch;
}
.settings-pane[hidden] { display: none; }
.settings-loading { margin: 40px 0; text-align: center; font-size: 13px; color: var(--text-3); }

/* —— 弹窗里的分组（沿用「分组灰底 + 卡片」那套语言）—— */
.set-block { margin-bottom: 22px; }
.set-block:last-child { margin-bottom: 0; }
.set-block-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 10px;
}
.set-block-head h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .02em;
}
.set-block-head p { margin: 3px 0 0; font-size: 11.5px; color: var(--text-3); }

.set-rows {
  border: .5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
}
.set-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 15px;
  border-bottom: .5px solid var(--line);
}
.set-row:last-child { border-bottom: none; }
.set-row-key { font-size: 12.5px; color: var(--text-2); }
.set-row-val {
  font-size: 12.5px;
  color: var(--text);
  text-align: right;
  word-break: break-all;
}
.set-row-val.is-mono {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 11.5px;
}

.set-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 21px;
  padding: 0 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
}
.set-pill.is-on { color: var(--accent); background: var(--accent-soft); }
.set-pill.is-off { color: var(--like); background: var(--like-soft); }
.set-pill.is-mute { color: var(--text-3); background: var(--line); }
/* 账号编号这类纯标识：等宽，别让它跟着正文比例跳字宽 */
.set-pill.is-mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; letter-spacing: .04em; }

/* —— LLM 页签：模型行 ——
 * 只展示、不给选（v0.9.56）：整行没有任何可点元素，右边两个 pill 是如实说明，
 * 不是开关。左边那颗点是「活着」的信号，跟顶栏的状态灯同一套语言。 */
.set-llm-model {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  padding: 13px 15px;
  border: .5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.set-llm-dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 0 3.5px var(--accent-soft);
}
.set-llm-model > b {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -.01em;
}
.set-llm-mode { font-size: 12px; color: var(--text-2); }
/* 两个 pill 推到行尾；窄屏换行时也保持成组，不会一个贴左一个贴右 */
.set-llm-flags { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }

/* —— 用量三卡：累计调用 / 累计 tokens / 今天 —— */
.set-usage-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 10px;
}
.set-usage-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  padding: 13px 14px;
  border: .5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.set-usage-card b {
  font-size: 19px;
  font-weight: 650;
  letter-spacing: -.015em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.set-usage-card span { font-size: 11px; color: var(--text-3); }

/* —— 用途明细行：左边「它插在哪些环节」，右边次数 + 占比 —— */
.set-task {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 15px;
  border-bottom: .5px solid var(--line);
  /* 还没被触发过的环节压暗：一眼分出「接上了」和「还没轮到它」 */
  opacity: .58;
}
.set-task:last-child { border-bottom: none; }
.set-task.is-used { opacity: 1; }
.set-task-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.set-task-main > b { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; }
.set-task-main > span { font-size: 11px; line-height: 1.55; color: var(--text-3); }
.set-task-bad {
  flex: 0 0 auto;
  padding: 1px 6px;
  border-radius: 999px;
  font-size: 10.5px;
  font-style: normal;
  font-weight: 500;
  color: var(--like);
  background: var(--like-soft);
}
.set-task-num { display: flex; align-items: baseline; gap: 3px; flex: 0 0 auto; }
.set-task-num > b { font-size: 14px; font-weight: 650; font-variant-numeric: tabular-nums; }
.set-task-num > span { font-size: 11px; color: var(--text-3); }
.set-task-num > em { min-width: 34px; font-size: 11px; font-style: normal; color: var(--text-3); text-align: right; }

/* 分段选择：设置里的小档位（队列重排频率）。选中态用主题强调色，一眼看得出当前是哪个 */
.set-seg { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px; }
.set-seg-btn {
  height: 24px;
  padding: 0 10px;
  border: .5px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 11.5px;
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease), border-color .16s var(--ease);
}
.set-seg-btn:hover { border-color: var(--text-3); color: var(--text); }
.set-seg-btn.is-on { color: var(--accent); background: var(--accent-soft); border-color: var(--accent); }

/* 档位卡片：和档案页控制台里的 chip 是同一套视觉，只是在这里排得更开 */
.set-modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.set-mode {
  padding: 12px 13px;
  border: .5px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition: border-color .16s var(--ease), background .16s var(--ease), transform .16s var(--ease);
}
.set-mode:hover { border-color: var(--text-3); transform: translateY(-1px); }
.set-mode.is-active { border-color: var(--accent); background: var(--accent-soft); }
.set-mode.is-active b { color: var(--accent); }
.set-mode:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.set-mode b { display: block; font-size: 13px; font-weight: 600; }
.set-mode span { display: block; margin-top: 3px; font-size: 11px; color: var(--text-3); line-height: 1.5; }
.set-mode i {
  display: inline-block;
  margin-top: 7px;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--line);
  color: var(--text-2);
  font-size: 10px;
  font-style: normal;
}

/* 开关 */
.set-toggle {
  position: relative;
  flex: none;
  width: 40px;
  height: 23px;
  border: none;
  border-radius: 999px;
  background: var(--line-strong);
  cursor: pointer;
  transition: background .2s var(--ease);
}
.set-toggle::after {
  content: '';
  position: absolute;
  top: 2.5px;
  left: 2.5px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
  transition: transform .2s var(--ease);
}
.set-toggle.is-on { background: var(--accent); }
.set-toggle.is-on::after { transform: translateX(17px); }

.set-pref {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  padding: 13px 15px;
  border-bottom: .5px solid var(--line);
}
.set-pref:last-child { border-bottom: none; }
.set-pref-main b { display: block; font-size: 13px; font-weight: 600; }
.set-pref-main span { display: block; margin-top: 3px; font-size: 11.5px; color: var(--text-3); line-height: 1.6; }

/* 工具 / 技能清单 */
.set-tool {
  display: flex;
  gap: 12px;
  padding: 12px 15px;
  border-bottom: .5px solid var(--line);
}
.set-tool:last-child { border-bottom: none; }
.set-tool-name {
  flex: none;
  min-width: 132px;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 11.5px;
  color: var(--accent);
  word-break: break-all;
}
.set-tool-desc { font-size: 12px; color: var(--text-2); line-height: 1.65; }
.set-tool-params { display: block; margin-top: 4px; font-size: 10.5px; color: var(--text-3); }
.set-tool-params code {
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--line);
  font-size: 10.5px;
}

.set-code {
  position: relative;
  margin: 0;
  padding: 14px 15px;
  border: .5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 11.5px;
  line-height: 1.75;
  color: var(--text-2);
  overflow-x: auto;
  white-space: pre;
}
.set-copy { margin-top: 9px; }

.set-note {
  margin: 10px 0 0;
  font-size: 11.5px;
  color: var(--text-3);
  line-height: 1.7;
}

.set-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 10px; }

/* 耳机页行内小注 + 可收缩性（v0.9.66）：
   这几行右侧常是「长设备名 + 一句为什么拿不到」，而设置面板一旦出现滚动条，
   可用宽度会再少 5.6px —— 而 .set-row-val 作为 flex 项的默认 min-width:auto
   不许收缩到内容最小宽度以下，窄屏就会被顶出横向滚动条（实测 376 vs 370.4）。
   注意这里**只作用 #paneEar**：其它页签的几何被好几条回归钉着，不动它们。 */
.set-note-inline {
  margin-left: 8px;
  color: var(--text-3);
  font-size: 11px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
#paneEar .set-row-val { min-width: 0; overflow-wrap: anywhere; }
#paneEar .set-btn { max-width: 100%; }
.set-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 31px;
  padding: 0 14px;
  border: .5px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 12.5px;
  cursor: pointer;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.set-btn:hover { background: var(--surface-2); border-color: var(--text-3); }
.set-btn:disabled { opacity: .55; cursor: default; }
.set-btn .ic { width: 13px; height: 13px; }
.set-probe { font-size: 11.5px; color: var(--text-3); }
.set-probe.is-ok { color: var(--accent); }
.set-probe.is-bad { color: var(--like); }
.set-note {
  margin: 12px 0 0;
  padding: 11px 13px;
  border-radius: 11px;
  background: var(--surface-2);
  font-size: 11.5px;
  line-height: 1.8;
  color: var(--text-3);
}

/* 跨平台红心导入（v0.9.63）—— 平台小标 + 「刚读到的几首」清单 */
.imp-mark {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  object-fit: cover;
  vertical-align: -2px;
  margin-right: 6px;
}
.imp-list {
  display: grid;
  gap: 6px;
  margin: 12px 0 0;
}
.imp-item {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.imp-cover {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: var(--line);
  object-fit: cover;
}
/* flex 项要出省略号必须 min-width:0（老规矩），歌名再长也不许把布局撑开 */
.imp-name {
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: 12px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.imp-name > i {
  min-width: 0;
  font-size: 11px;
  font-style: normal;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 620px) {
  /* 顶栏在窄屏上只留必要的：搜索框缩短，账户与设置只留图标 */
  .searchbox { width: 116px; }
  .searchbox kbd { display: none; }
  /* 窄屏下账户按钮已收到 40px 出头，左侧余量变宽 —— 浮层跟着放大到近满屏。
     175 = 搜索框右侧那串图标按钮占位（实测 390 屏下搜索框右边线距屏幕右缘 151px）+ 24px 左边距；
     沿用桌面那条 `100vw - 260px` 会在窄屏上窄成一条（390 屏只剩 130px）。 */
  .search-panel { width: calc(100vw - 175px); }
  /* 手机档卡片最小宽 150 → 132：150 的底线会把 500px 屏挤成 1 列 299px 的巨卡；
     132 的底线在 480px 以上都能排 2 列（620px 屏仍是 2 列 203px，不至于窄成 3×130）。 */
  .card-grid.search-panel-grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .acct-btn { padding: 0 5px; max-width: 40px; }
  .acct-label { display: none; }
  .top-pill { padding: 0 9px; }
  .top-pill span { display: none; }
  .acct-menu { width: min(320px, calc(100vw - 28px)); }
  .mnav-item { flex: 1; justify-content: center; padding: 7px 8px; }

  .settings { padding: 0; }
  .settings-panel { max-height: 100vh; border-radius: 0; }
  .set-modes { grid-template-columns: 1fr; }
  .set-tool { flex-direction: column; gap: 5px; }
}

/* ==========================================================================
   发现页 · 计划清单（v0.9.15）
   Read plan / Film plan 两个子页签 + 待看操作 + 交互说明
   ========================================================================== */

/* 侧栏子页签的角标：待看条数 */
.nav-count {
  margin-left: auto;
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 11px;
  font-weight: 600;
  line-height: 18px;
  text-align: center;
}
.nav-sub.is-active .nav-count { background: var(--accent); color: #fff; }

/* 发现页顶部「三种操作」说明条 */
.discover-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 2px 0 20px;
  padding: 12px 14px;
  border: .5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.5;
}
.discover-legend .legend-title {
  font-weight: 600;
  color: var(--text);
  margin-right: 2px;
}
.discover-legend .legend-item { display: inline-flex; align-items: center; gap: 6px; }
.discover-legend b { color: var(--text); font-weight: 600; }
.discover-legend .legend-plain { color: var(--text-3); }
/* 「审美内核」那一行：选片 Agent 读到的气质 / 母题 —— 给一点点强调，别喧宾夺主 */
#screeningKernelRow { color: var(--text-2); }
#screeningKernel { color: var(--fest, var(--text)); }
.legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex: none;
}
.legend-dot.dot-plan { background: var(--accent); }
.legend-dot.dot-dislike { background: #d24b4b; }
.legend-dot.dot-like { background: var(--like); }

/* 待看按钮：未加入 = 描边，已加入 = 实心（收藏态） */
.media-act.act-plan { display: inline-flex; align-items: center; gap: 4px; }
.media-act.act-plan .ic { width: 12px; height: 12px; }
.media-act.act-plan:hover { border-color: var(--accent); color: var(--accent); }
.media-card.is-planned .act-plan {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}
.media-card.is-planned { border-color: var(--accent-soft); }
/* 已看过（v0.9.37）：与「已喜欢」区分开的第二种「停留中」状态 —— 同样是「已经办了，留一下」 */
.media-card.is-watched { border-color: var(--accent-soft); }
/* 退场：dislike / 待看 的卡片在摘掉前先淡出一下，避免「啪」地跳走。
   时序见 app.js 的 retireCard（190ms 后摘除并立刻补位）。 */
.media-card.is-leaving {
  opacity: 0;
  transform: scale(.96);
  transition: opacity .18s var(--ease), transform .18s var(--ease);
}
/* 已喜欢：给卡片一个更明确的停留标记（它会在若干次操作后退场） */
.media-card.is-liked .act-like {
  border-color: var(--like);
  color: var(--like);
  background: var(--like-soft);
}

/* 计划页网格的**默认档**：与通用 .card-grid 同尺（184px），书清单用它。
   Watch plan 是**电影**清单，刻意不走这一档 —— 它在下面的放映厅区块里与
   #screeningGrid 共用同一套格子，好让「清单里的卡片和放映厅一模一样」。
   （此前 Watch plan 也吃这一档，于是卡片比放映厅小一圈 —— v0.9.39 修。） */
.plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
  gap: 22px 20px;
}
.plan-loading {
  grid-column: 1 / -1;
  padding: 40px 0;
  text-align: center;
  color: var(--text-3);
  font-size: 13.5px;
}

@media (max-width: 640px) {
  .discover-legend { font-size: 12px; }
  .plan-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 18px 14px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ==========================================================================
   放映厅 · 场景（v0.9.32 引入，v0.9.35 两辑：独立放映 / 纪录片）
   --------------------------------------------------------------------------
   场景不是筛选器 —— 它换的是**候选池**（独立放映 = sub 的影展片单；
   纪录片 = doc 从豆瓣「类型 = 纪录片」分类榜取的片）。
   所以视觉上它是「一组带说明的页签」，而不是「几个筛选 chip」：每个页签带一行副标题，
   一眼说清这一辑看什么。页签**顺序即服务端下发的顺序**，第一条为默认选中。
   ========================================================================== */
.scene-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 8px;
  margin: 2px 0 16px;
}
.scene-lead {
  align-self: center;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .4px;
  color: var(--text-3);
  margin-right: 2px;
}
.scene-tab {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  text-align: left;
  padding: 9px 16px;
  border-radius: var(--r-md);
  border: .5px solid var(--line);
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.scene-tab:hover { background: var(--surface-2); }
.scene-tab.is-active {
  background: var(--surface-2);
  border-color: var(--accent);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.scene-tab-name { font-size: 14px; font-weight: 650; letter-spacing: .2px; }
.scene-tab-sub { font-size: 11px; color: var(--text-3); }
.scene-tab.is-active .scene-tab-sub { color: var(--text-2); }
.scene-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* 页签副标题里的 Agent 名（sub）—— 让人知道这一辑是谁选的 */
.scene-agent { color: var(--accent); font-weight: 700; }

/* 区块标题上的 Agent 署名（独立放映） */
.agent-chip {
  margin-left: 8px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .3px;
  color: var(--accent);
  background: var(--surface-2);
  border: .5px solid var(--accent);
  border-radius: 999px;
  padding: 1px 8px 2px;
  vertical-align: 2px;
}

/* 出处标（独立放映）：卡片上的「出处」—— 这部片出现在豆瓣的哪个影展 / 奖项标签下。
   v0.9.34 起分三档，措辞与图标都不许含糊：
     · 影展  .tag-fest          —— 暖金主标 + 胶片图标（入围 / 展映）
     · 奖项  .tag-fest.is-award —— 同样是主标，但虚线描边 + 星芒图标（提名 / 获奖）
     · 流派  .tag-fest.is-art   —— 淡化处理（只是豆瓣的归类，不是影展入围） */
.tag-fest {
  color: var(--fest);
  background: var(--fest-bg);
  border: .5px solid var(--fest-line);
}
.tag-fest .ic { width: 11px; height: 11px; }
/* 奖项：虚线描边 —— 一眼能看出「这不是影展」 */
.tag-fest.is-award { border-style: dashed; }
.tag-fest.is-art {
  color: var(--text-3);
  background: var(--surface-2);
  border-color: var(--line);
}
.legend-dot.dot-fest { background: var(--fest); }

/* 类型 / 地区标（纪录片那一辑）：豆瓣条目自己的结构化字段，
   既不是影展入围、也不是社区标签，所以用**中性灰**，不抢出处标的金色。
   地区再淡一档（它是「哪儿拍的」，比「什么类型」更外围）。 */
.tag-meta {
  color: var(--text-2);
  background: var(--surface-2);
  border: .5px solid var(--line);
}
.tag-meta.is-region { color: var(--text-3); background: transparent; }

/* ── 放映厅：封面是主角 ─────────────────────────────────────────────────────
   两个场景（独立放映 / 纪录片）共用 #screeningGrid，格子比通用 .card-grid 大一档：
   184px → 232px（1000px 内容宽下：5 列 → 4 列，单张封面 184px → 235px，
   面积 +64%）。用户要的「适当放大电影封面面积」就落在这里。

   **v0.9.39：Watch plan（#filmPlanGrid）并入同一个选择器。** 电影清单里的卡片
   必须和放映厅**逐像素一致** —— 此前它跟着 .plan-grid 走 184px / 22×20，
   所以「样式没对齐」。两者现在共用一套格子尺寸，值只有这一处。
   ⚠️ id 选择器会压过媒体查询里的 .plan-grid（媒体查询不加特异性），
   所以下面 640px 那条窄屏规则也必须一并带上 #filmPlanGrid，
   否则手机上它会卡在 232px 掉成单列。
   图书（#bookGrid）与 Read plan 不在此列，仍是 184px。 */
#screeningGrid,
#filmPlanGrid {
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 26px 22px;
}

@media (max-width: 900px) {
  .scene-bar { gap: 6px; }
  .scene-lead { display: none; }
  .scene-tab { flex: 1 1 auto; padding: 8px 12px; }
  .scene-tab-name { font-size: 13px; }
  .scene-tab-sub { font-size: 10.5px; }
}
@media (max-width: 640px) {
  .discover-legend { font-size: 12px; }
  .scene-tab-sub { display: none; }
  .agent-chip { display: none; }
  /* 手机上 232px 会掉到单列（封面铺满屏宽，反而更难扫）—— 收回到两列。
     Watch plan 与放映厅同尺，必须一起收。 */
  #screeningGrid,
  #filmPlanGrid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 18px 14px; }
}

/* ── 迭代日志（点左下角版本号打开） ──────────────────────────────────
   遮罩与设置面板同一套做法：fixed 铺满 + 居中卡片，[hidden] 直接 display:none。
   每条只列**核心**特性与修复 —— 写全了没人看，那是 git log 的活儿。 */
.legal-version.is-clickable {
  cursor: pointer;
  border-bottom: .5px dotted var(--text-3);
  transition: color .18s var(--ease);
}
.legal-version.is-clickable:hover { color: var(--text-2); }

.changelog {
  position: fixed;
  inset: 0;
  z-index: 420;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(0, 0, 0, .38);
}
.changelog[hidden] { display: none; }
.changelog-card {
  width: min(560px, 100%);
  max-height: 76vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  box-shadow: var(--shadow-2);
  overflow: hidden;
}
.changelog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line);
}
.changelog-title { font-size: 13px; font-weight: 600; color: var(--text); }
.changelog-x {
  border: 0;
  background: transparent;
  color: var(--text-3);
  font-size: 14px;
  line-height: 1;
  padding: 4px 7px;
  border-radius: 8px;
  cursor: pointer;
}
.changelog-x:hover { background: var(--surface-2); color: var(--text); }
.changelog-body {
  overflow-y: auto;
  padding: 4px 16px 16px;
  -webkit-overflow-scrolling: touch;
}
.cl-item { padding: 12px 0; border-bottom: 1px solid var(--line); }
.cl-item:last-child { border-bottom: 0; }
.cl-head { display: flex; align-items: baseline; gap: 8px; }
.cl-ver {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.cl-at { font-size: 11px; color: var(--text-3); }
.cl-list { margin: 7px 0 0; padding-left: 15px; }
.cl-list li { font-size: 12px; line-height: 1.65; color: var(--text-2); }
.cl-list li + li { margin-top: 3px; }
.cl-tag {
  font-size: 10.5px;
  padding: 1px 5px;
  border-radius: 5px;
  margin-right: 5px;
}
.cl-tag.is-feature { background: var(--accent-soft); color: var(--accent); }
.cl-tag.is-fix { background: var(--surface-2); color: var(--text-2); }
.cl-empty { font-size: 12px; color: var(--text-3); padding: 18px 0; text-align: center; }

