
/* ============================================================
   BÂ·Music ç½‘é¡µç‰ˆ Â· Apple Music é£Žæ ¼ä¸»é¢˜
   æ·±è‰² Â· å¤§åœ†è§’ Â· æ¯›çŽ»ç’ƒ Â· å�•ä¸€çº¢è‰²å¼ºè°ƒè‰²
   ============================================================ */
:root {
  --bg: #0b0b0e;
  --bg2: #121216;
  --panel: rgba(var(--fg-rgb), .055);
  --panel2: rgba(var(--fg-rgb), .09);
  --border: rgba(var(--fg-rgb), .09);
  --text: #f5f5f7;
  --sub: #98989f;
  --accent: #fa2d3c;
  --accent-rgb: 250, 45, 60;
  --fg-rgb: 255, 255, 255;
  --fg-strong: #ffffff;
  --bg3: #16161b;
  --bg-rgb: 11, 11, 14;
  --panel-rgb: 30, 30, 36;
  --accent-2: #ff6b7a;
  --accent-soft: rgba(var(--accent-rgb), .14);
  --accent-grad: linear-gradient(135deg, #fa2d3c, #ff4d5e);
  /* v165: content colour on a solid accent surface. Always white - unlike --fg-strong,
   * which turns dark in the light themes and produced black text on red buttons. */
  --on-accent: #ffffff;
  --radius: 12px;
  --side-w: 238px;
  --bar-h: 76px;
  --player-bg: #101014;   /* player page background (#overlay bg); the bar morph aligns to it */
  --topbar-h: 70px;
  --ease: cubic-bezier(.25, .1, .25, 1);
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scrollbar-width: thin; scrollbar-color: rgba(var(--fg-rgb),.16) transparent; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  user-select: none; -webkit-user-select: none;
}
body.no-scroll { overflow: hidden; }
input, textarea { user-select: text; -webkit-user-select: text; }
.ly-line { user-select: text; -webkit-user-select: text; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: rgba(var(--fg-rgb),.14); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: rgba(var(--fg-rgb),.22); }
::-webkit-scrollbar-track { background: transparent; }
img { display: block; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
svg { fill: currentColor; }
::selection { background: rgba(var(--accent-rgb), .35); }

.hidden { display: none !important; }

/* ============ ä¾§è¾¹æ �ï¼ˆæ‚¬æµ®åœ†è§’çŸ©å½¢ï¼‰ ============ */
#sidebar {
  position: fixed; top: 16px; left: 16px; bottom: 16px; width: var(--side-w);
  background: rgba(var(--panel-rgb), .72);
  backdrop-filter: blur(26px); -webkit-backdrop-filter: blur(26px);
  border: 1px solid var(--border); border-radius: 22px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, .45);
  display: flex; flex-direction: column;
  z-index: 60;
}
.side-logo { display: flex; align-items: center; gap: 11px; padding: 24px 20px 16px; cursor: pointer; }
.logo-badge {
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center;
  background: transparent;
}
.logo-badge svg { width: 26px; height: 26px; fill: var(--accent); }
.logo-text { font-size: 17px; font-weight: 700; letter-spacing: .2px; color: var(--fg-strong); }
.logo-text em { display: block; font-style: normal; font-size: 9.5px; color: var(--sub); font-weight: 600; letter-spacing: 2.4px; text-transform: uppercase; }

.side-nav { padding: 4px 12px; display: flex; flex-direction: column; gap: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 13px; padding: 10px 14px;
  border-radius: 10px; color: var(--sub); font-size: 14px; font-weight: 500;
  transition: all .18s var(--ease);
}
.nav-item svg { width: 19px; height: 19px; flex: none; opacity: .85; }
/* v165: keep a transparent border at rest so the selected border does not shift the row */
.nav-item { border: 1px solid transparent; }
.nav-item:hover { color: var(--text); background: var(--panel); }
.nav-item.active { color: var(--accent); background: var(--accent-soft); font-weight: 600; border-color: rgba(var(--accent-rgb), .38); }

.side-title {
  padding: 20px 22px 8px; font-size: 11px; color: var(--sub);
  letter-spacing: 1.6px; text-transform: uppercase; font-weight: 600;
}
.side-pls { flex: 1; overflow-y: auto; padding: 0 12px 12px; display: flex; flex-direction: column; gap: 2px; }
.side-empty { color: var(--sub); font-size: 12px; padding: 8px 12px; }
.side-pl {
  display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: 9px;
  color: var(--sub); cursor: pointer; transition: background .15s; font-size: 13px;
}
.side-pl:hover { background: var(--panel); color: var(--text); }
.side-pl img { width: 30px; height: 30px; border-radius: 8px; flex: none; object-fit: cover; box-shadow: 0 2px 8px rgba(0,0,0,.3); }
.side-pl span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.side-footer { padding: 12px 14px; border-top: 1px solid var(--border); }
/* ç™»å½•/æ³¨å†Œï¼ˆè®¾ç½®ä¸Šæ–¹ï¼‰ */
.side-account { padding-bottom: 10px; }
.side-auth-btns { display: flex; gap: 8px; }
.side-auth-btn {
  flex: 1; padding: 8px 0; border-radius: 9px; cursor: pointer;
  border: 1px solid var(--border); background: var(--panel);
  color: var(--text); font-size: 12.5px; font-weight: 600; transition: all .18s var(--ease);
}
.side-auth-btn:hover { border-color: rgba(var(--accent-rgb),.45); color: var(--accent); }
.side-auth-btn.primary { background: var(--accent); border-color: transparent; color: var(--on-accent); }
.side-auth-btn.primary:hover { background: var(--accent); color: var(--on-accent); opacity: .88; }
.side-user { display: flex; align-items: center; gap: 8px; }
.side-user-mail {
  flex: 1; min-width: 0; font-size: 12px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.side-user .side-auth-btn { flex: none; padding: 6px 12px; }

/* ç™»å½•/æ³¨å†Œå¼¹çª— */
.auth-panel { width: min(400px, 92vw); }
.auth-tip { font-size: 12px; color: var(--sub); line-height: 1.6; margin-bottom: 14px; }
.auth-input {
  width: 100%; box-sizing: border-box;
  background: rgba(var(--fg-rgb),.05); border: 1px solid var(--border);
  border-radius: 10px; color: var(--fg-strong); font-size: 14px;
  padding: 11px 14px; margin-bottom: 10px; outline: none;
  transition: border-color .18s;
}
.auth-input:focus { border-color: rgba(var(--accent-rgb),.55); }
.auth-err { color: var(--accent-2); font-size: 12.5px; margin-bottom: 10px; line-height: 1.5; }
.auth-submit { width: 100%; justify-content: center; margin-top: 2px; }
.auth-switch { margin-top: 14px; text-align: center; font-size: 13px; color: var(--sub); }
.auth-switch a { color: var(--accent); cursor: pointer; font-weight: 600; }
.auth-sep { margin: 0 6px; opacity: .5; }
/* æ›´æ–°å…¬å‘Š */
.notice-panel { width: min(480px, 92vw); }
.notice-ver { font-size: 12px; color: var(--accent); font-weight: 700; margin-bottom: 12px; letter-spacing: .5px; }
.notice-list { margin: 0 0 18px; padding-left: 4px; list-style: none; }
.notice-list li {
  position: relative; padding: 7px 0 7px 18px; font-size: 13.5px; line-height: 1.65;
  color: rgba(var(--fg-rgb),.85); border-bottom: 1px solid rgba(var(--fg-rgb),.05);
}
.notice-list li:last-child { border-bottom: none; }
.notice-list li::before {
  content: ''; position: absolute; left: 2px; top: 14px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}

/* major release notice: right side split into lettered small-update cards,
 * each with its own 1/2/3 numbered list. */
.notice-list > .notice-sec {
  position: relative;
  padding: 9px 11px;
  margin: 0 0 10px;
  border: 1px solid rgba(var(--fg-rgb),.07);
  border-radius: 10px;
  background: rgba(var(--fg-rgb),.025);
}
.notice-list > .notice-sec::before { display: none; }
.notice-list > .notice-sec:last-child { margin-bottom: 0; }
.notice-sec-ver {
  margin: 0 0 4px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: .02em;
}
.notice-sec-list {
  margin: 0;
  padding-left: 20px;
  list-style: decimal;
}
.notice-sec-list > li {
  position: static;
  padding: 4px 0;
  border-bottom: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: rgba(var(--fg-rgb),.85);
}
.notice-sec-list > li::before { display: none; }
.notice-new {
  display: inline-block; margin-left: 8px; font-size: 10px; font-weight: 700;
  color: var(--on-accent); background: var(--accent); border-radius: 6px; padding: 1px 6px;
  vertical-align: 1px; letter-spacing: .5px;
}
/* æ»‘åŠ¨éªŒè¯� */
.auth-slider { margin-bottom: 12px; }
.auth-slider-track {
  position: relative; height: 44px; border-radius: 12px;
  background: rgba(var(--fg-rgb),.05); border: 1px solid var(--border);
  overflow: hidden; user-select: none; -webkit-user-select: none;
}
.auth-slider-notch {
  position: absolute; top: 6px; width: 30px; height: 30px; border-radius: 7px;
  background: rgba(var(--fg-rgb),.16); border: 1px dashed rgba(var(--fg-rgb),.4);
  transition: left .25s var(--ease);
}
.auth-slider-fill {
  position: absolute; top: 0; left: 0; height: 100%; width: 0;
  background: linear-gradient(90deg, rgba(var(--accent-rgb),.18), rgba(var(--accent-rgb),.34));
  pointer-events: none;
}
.auth-slider-thumb {
  position: absolute; top: 2px; left: 2px; width: 40px; height: 38px;
  border-radius: 10px; background: var(--fg-strong); color: #8a8a93;
  display: grid; place-items: center; cursor: grab;
  box-shadow: 0 3px 10px rgba(0,0,0,.35); z-index: 2;
  transition: background .18s, color .18s;
}
.auth-slider-thumb svg { width: 18px; height: 18px; fill: currentColor; }
.auth-slider-thumb.dragging { cursor: grabbing; background: var(--accent); color: var(--on-accent); }
.auth-slider.ok .auth-slider-thumb { background: #1f9d55; color: var(--fg-strong); }
.auth-slider.ok .auth-slider-fill { background: linear-gradient(90deg, rgba(31,157,85,.2), rgba(31,157,85,.4)); }
.auth-slider.fail .auth-slider-thumb { background: var(--accent); color: var(--on-accent); }
.auth-slider-hint {
  margin-top: 8px; text-align: center; font-size: 12px; color: var(--sub);
}
.auth-slider.ok .auth-slider-hint { color: #3ecf6e; }
.auth-slider.fail .auth-slider-hint { color: var(--accent-2); }
.auth-step { display: block; }
/* å¼€å�‘æ¨¡å¼�æ��ç¤ºï¼ˆæœªé…�ç½® SMTP æ—¶æ˜¾ç¤ºéªŒè¯�ç �ï¼‰ */
.auth-dev {
  font-size: 12px; color: #f0a44a; background: rgba(240,164,74,.1);
  border: 1px solid rgba(240,164,74,.3); border-radius: 8px;
  padding: 8px 12px; margin-bottom: 10px; line-height: 1.5;
}
.side-btn {
  display: flex; align-items: center; gap: 11px; padding: 10px 14px; width: 100%;
  border-radius: 11px; color: var(--sub); font-size: 14px; font-weight: 500;
  transition: all .15s;
}
.side-btn:hover { color: var(--accent); background: var(--accent-soft); }
.side-btn svg { width: 18px; height: 18px; }
.side-ver { padding: 8px 14px 0; color: #5f5f66; font-size: 10.5px; letter-spacing: .4px; text-align: center; }

/* ============ ä¸»åŒºåŸŸ / é¡¶æ � ============ */
:root { --side-offset: calc(var(--side-w) + 32px); }
#main { margin-left: var(--side-offset); min-height: 100vh; padding-top: var(--topbar-h); }
#topbar {
  position: fixed; top: 0; left: var(--side-offset); right: 0; height: var(--topbar-h);
  display: flex; align-items: center; gap: 18px; padding: 0 28px;
  background: rgba(var(--bg-rgb), .78);
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
  border-bottom: 1px solid var(--border); z-index: 50;
}
#btn-menu { display: none; }
.topbar-title {
  font-size: 26px; font-weight: 700; letter-spacing: -.4px; color: var(--fg-strong);
  white-space: nowrap; margin-right: 6px;
}

.icon-btn {
  width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
  color: var(--sub); transition: all .15s; flex: none;
}
.icon-btn:hover { color: var(--accent); background: var(--accent-soft); }
.icon-btn svg { width: 19px; height: 19px; }
.icon-btn.big { width: 44px; height: 44px; }
.icon-btn.big svg { width: 24px; height: 24px; }
.icon-btn.heart.on, .sr-fav.on { color: var(--accent); }
.icon-btn.muted { color: var(--accent); }

#view { padding: 30px 32px 40px; max-width: 1360px; margin: 0 auto; }
#view-bottom-space { height: calc(var(--bar-h) + 44px); }

.view-section { margin-bottom: 38px; }
.sec-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 16px; }
.sec-head h2 { font-size: 22px; font-weight: 700; letter-spacing: -.3px; color: var(--fg-strong); }

.view-loading { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 100px 0; color: var(--sub); }
.view-loading.small { padding: 30px 0; }
.view-loading-text { font-size: 13px; letter-spacing: 2px; }
.spinner {
  width: 30px; height: 30px; border-radius: 50%;
  border: 3px solid rgba(var(--fg-rgb),.12); border-top-color: var(--accent);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.empty { text-align: center; padding: 80px 20px; color: var(--sub); }
.empty-icon { font-size: 42px; margin-bottom: 14px; opacity: .4; }
.empty-text { font-size: 16px; font-weight: 500; }
.empty-sub { font-size: 12.5px; margin-top: 8px; color: var(--sub); }
.empty .mini-btn { margin-top: 18px; }

/* ============ Bannerï¼ˆListen Now é£Žæ ¼ï¼‰ ============ */
.banner-wrap { margin-bottom: 38px; }
.banner { position: relative; height: 260px; border-radius: 16px; overflow: hidden; background: var(--bg3); box-shadow: 0 14px 44px rgba(0,0,0,.4); }
.banner-slide { position: absolute; inset: 0; opacity: 0; transition: opacity .9s var(--ease); cursor: pointer; }
.banner-slide.active { opacity: 1; }
.banner-slide img { width: 100%; height: 100%; object-fit: cover; }
.banner-slide::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(0deg, rgba(0,0,0,.42), transparent 48%);
}
.banner-tag {
  position: absolute; left: 20px; bottom: 18px; z-index: 2;
  background: rgba(var(--panel-rgb), .55); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  padding: 6px 14px; border-radius: 8px; font-size: 12px; font-weight: 600; color: var(--fg-strong);
  letter-spacing: .3px;
}
.banner-dots { display: flex; justify-content: center; gap: 7px; margin-top: 12px; }
.dot { position: relative; width: 6px; height: 6px; border-radius: 50%; background: rgba(var(--fg-rgb),.22); cursor: pointer; transition: all .3s; }
/* i'¹ûí:6px „¹*¹
-	 */
.dot::after { content: ''; position: absolute; inset: -9px -3px; }
.dot:hover { background: rgba(var(--fg-rgb), .45); }
.dot.active { width: 22px; border-radius: 4px; background: var(--accent); }

/* ============ å�¡ç‰‡ç½‘æ ¼ ============ */
.grid { display: grid; gap: 24px 20px; }
.pl-grid { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); }
.pl-grid.featured { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
.pl-card { cursor: pointer; transition: transform .2s var(--ease); }
.pl-card:hover { }
.pl-cover {
  position: relative; aspect-ratio: 1; border-radius: 14px; overflow: hidden;
  background: var(--bg3); box-shadow: 0 8px 26px rgba(0,0,0,.35);
}
.pl-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .45s var(--ease); }
.pl-card:hover .pl-cover img { transform: scale(1.06); }
.pl-count {
  position: absolute; top: 9px; right: 11px; z-index: 2;
  font-size: 11px; color: var(--fg-strong); text-shadow: 0 1px 4px rgba(0,0,0,.7); font-weight: 500;
}
/* æ­Œå�•å�¡æ”¶è—�æŒ‰é’®ï¼ˆå·¦ä¸Šè§’ï¼Œçº¢å¿ƒ=å·²æ”¶è—�ï¼‰ */
.pl-fav {
  position: absolute; top: 8px; left: 8px; z-index: 3;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center; padding: 0; border: none; cursor: pointer;
  background: rgba(var(--bg-rgb), .5); backdrop-filter: blur(6px);
  color: rgba(var(--fg-rgb), .85); transition: all .18s var(--ease);
}
.pl-fav svg { width: 14px; height: 14px; }
.pl-fav.on { color: var(--accent); }
.pl-fav:hover { background: rgba(var(--bg-rgb), .75); }
.pl-hover {
  position: absolute; right: 10px; bottom: 10px; z-index: 2;
  width: 42px; height: 42px; border-radius: 50%;
  background: rgba(var(--accent-rgb), .95); color: var(--on-accent);
  display: grid; place-items: center;
  opacity: 0; transition: opacity .22s var(--ease);
}
.pl-card:hover .pl-hover { opacity: 1; }
.pl-hover svg { width: 20px; height: 20px; margin-left: 2px; }
.pl-name { margin-top: 11px; font-size: 14px; font-weight: 500; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pl-sub { margin-top: 3px; font-size: 12px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.album-grid, .artist-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 24px 20px; }
.album-card, .artist-card { cursor: pointer; transition: transform .2s var(--ease); text-align: left; }
.album-card:hover, .artist-card:hover { }
.artist-avatar { position: relative; aspect-ratio: 1; border-radius: 50%; overflow: hidden; background: var(--bg3); box-shadow: 0 8px 26px rgba(0,0,0,.35); }
.artist-avatar img { width: 100%; height: 100%; object-fit: cover; }

/* ============ ç­›é€‰ / æ ‡ç­¾ ============ */
.filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-bottom: 20px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  padding: 7px 15px; border-radius: 20px; font-size: 12.5px; color: var(--text);
  background: var(--panel); border: 1px solid var(--border); transition: all .18s;
}
.chip:hover { color: var(--text); background: var(--panel2); border-color: rgba(var(--fg-rgb), .16); }
.chip.active {
  color: var(--accent); background: var(--accent-soft);
  border-color: rgba(var(--accent-rgb), .38); font-weight: 600;
}
.hot-chips { display: flex; flex-wrap: wrap; gap: 9px; }
.tag { padding: 3px 10px; border-radius: 10px; font-size: 11px; background: var(--panel2); color: var(--sub); }

/* ============ æ­Œæ›²åˆ—è¡¨ ============ */
.song-list { display: flex; flex-direction: column; }
.song-row {
  display: flex; align-items: center; gap: 14px; padding: 9px 14px;
  border-radius: 10px; transition: background .15s; cursor: pointer;
}
.song-row:hover { background: var(--panel); }
.song-row.active { background: var(--accent-soft); }
.sr-idx { width: 26px; text-align: center; color: var(--sub); font-size: 13px; flex: none; position: relative; font-variant-numeric: tabular-nums; }
.sr-play { width: 17px; height: 17px; display: none; color: var(--accent); margin: 0 auto; }
.song-row:hover .sr-num, .song-row.active .sr-num { display: none; }
.song-row:hover .sr-play, .song-row.active .sr-play { display: block; }
.sr-cover { width: 44px; height: 44px; border-radius: 8px; overflow: hidden; flex: none; background: var(--bg3); box-shadow: 0 3px 10px rgba(0,0,0,.25); }
.sr-cover img { width: 100%; height: 100%; object-fit: cover; }
.sr-main { flex: 1; min-width: 0; }
.sr-name { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.song-row.active .sr-name { color: var(--accent); font-weight: 600; }
.vip-tag { font-style: normal; font-size: 10px; color: #f0a44a; border: 1px solid rgba(240,164,74,.5); border-radius: 4px; padding: 1px 5px; margin-left: 7px; vertical-align: 1px; font-weight: 600; }
.sr-artists { font-size: 12.5px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
.sr-album { width: 24%; min-width: 120px; font-size: 12.5px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-dur { width: 44px; font-size: 12px; color: var(--sub); text-align: right; flex: none; font-variant-numeric: tabular-nums; }
.sr-fav, .sr-dl { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; color: var(--sub); opacity: 0; transition: all .15s; flex: none; }
.song-row:hover .sr-fav, .song-row:hover .sr-dl, .sr-fav.on { opacity: 1; }
.sr-fav:hover, .sr-dl:hover { background: rgba(var(--fg-rgb),.1); color: var(--fg-strong); }
.sr-fav.on { color: var(--accent); }
.sr-fav svg, .sr-dl svg { width: 17px; height: 17px; display: block; }
.sr-dl { margin-right: -6px; }

.more-wrap { text-align: center; padding: 24px 0 6px; }
.mini-btn {
  padding: 8px 22px; border-radius: 20px; font-size: 13px; color: var(--text);
  background: var(--panel2); border: 1px solid var(--border); transition: all .15s;
}
.mini-btn:hover { background: var(--accent-soft); border-color: rgba(var(--accent-rgb), .38); color: var(--accent); }
.mini-btn.danger { color: var(--accent); }
.mini-btn.danger:hover { background: var(--accent-soft); border-color: rgba(var(--accent-rgb),.38); color: var(--accent); }

/* ============ è¯¦æƒ…é¡µå¤´ï¼ˆä¸“è¾‘/æ­Œå�•/æ­Œæ‰‹ï¼‰ ============ */
.detail-head { display: flex; gap: 30px; padding: 12px 0 34px; }
.dt-cover {
  width: 208px; height: 208px; flex: none; border-radius: 16px; overflow: hidden;
  box-shadow: 0 16px 48px rgba(0,0,0,.5); background: var(--bg3);
}
.dt-cover.round { border-radius: 50%; }
.dt-cover img { width: 100%; height: 100%; object-fit: cover; }
.dt-info { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 10px; }
.dt-type { font-size: 11px; letter-spacing: 2.4px; color: var(--accent); font-weight: 700; text-transform: uppercase; }
.dt-name { font-size: 32px; font-weight: 800; letter-spacing: -.6px; line-height: 1.2; overflow-wrap: anywhere; color: var(--fg-strong); }
.dt-meta { font-size: 13px; color: var(--sub); }
.link { cursor: pointer; color: var(--sub); border-bottom: 1px dotted rgba(var(--fg-rgb),.3); }
.link:hover { color: var(--fg-strong); }
.dt-tags { display: flex; gap: 8px; }
.dt-actions { display: flex; gap: 12px; margin-top: 8px; }
.btn {
  display: inline-flex; align-items: center; gap: 8px; padding: 10px 22px; border-radius: 24px;
  font-size: 13.5px; font-weight: 600; color: var(--text); background: var(--panel2);
  border: 1px solid var(--border); transition: all .18s;
}
.btn svg { width: 16px; height: 16px; }
.btn:hover { background: var(--panel); }
.btn.primary {
  background: var(--accent); color: var(--on-accent); border: none;
}
.btn.primary:hover { filter: brightness(1.12); }
.btn.on { color: var(--accent); border-color: rgba(var(--accent-rgb),.45); background: var(--accent-soft); }
.dt-desc { font-size: 12.5px; color: var(--sub); line-height: 1.7; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }

/* ============ æ�œç´¢é¡µ ============ */
.search-box { margin: 8px 0 26px; }
.search-box form { display: flex; }
.search-box input {
  width: 100%; max-width: 560px; padding: 13px 22px; border-radius: 12px; font-size: 15px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text); outline: none;
  transition: border-color .2s, box-shadow .2s;
}
.search-box input:focus { border-color: rgba(var(--accent-rgb),.55); box-shadow: 0 0 0 3px rgba(var(--accent-rgb),.18); }
.fav-tabs { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
#fav-body { min-height: 120px; }

/* ============ è¿›åº¦æ�¡ï¼ˆApple æž�ç®€ï¼šç™½è‰²/çº¢è‰²å¡«å……ï¼Œæ— åœ†ç‚¹ï¼›æ‚¬å�œå�˜é«˜ï¼‰ ============ */
input[type="range"] {
  -webkit-appearance: none; appearance: none; height: 4px; border-radius: 2px;
  background: rgba(var(--fg-rgb), .22); outline: none; flex: 1; cursor: pointer;
  transition: height .18s var(--ease);
}
input[type="range"]:hover { height: 8px; }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 0; height: 0; border: none; background: transparent; opacity: 0;
}
input[type="range"]::-moz-range-thumb {
  width: 0; height: 0; border: none; background: transparent; opacity: 0;
}
input[type="range"]::-moz-range-track { height: 4px; background: transparent; }

/* ============ åº•éƒ¨æ’­æ”¾æ �ï¼ˆæ‚¬æµ®åœ†è§’é•¿æ�¡ï¼‰ ============ */
#playerbar {
  position: fixed; left: var(--side-offset); right: 16px; bottom: 14px; height: var(--bar-h);
  background: rgba(var(--panel-rgb), .78);
  backdrop-filter: blur(26px); -webkit-backdrop-filter: blur(26px);
  border: 1px solid var(--border); border-radius: 30px;
  box-shadow: 0 12px 44px rgba(0, 0, 0, .45);
  z-index: 55;
  display: flex; align-items: center; gap: 18px; padding: 0 20px;
}
.pb-left { display: flex; align-items: center; gap: 12px; min-width: 0; width: 26%; cursor: pointer; }
.pb-cover { position: relative; width: 46px; height: 46px; flex: none; border-radius: 10px; overflow: hidden; box-shadow: 0 4px 14px rgba(0,0,0,.4); }
.pb-cover img { width: 100%; height: 100%; object-fit: cover; }
.pb-playing-dot {
  position: absolute; top: 5px; right: 5px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); opacity: 0; box-shadow: 0 0 8px var(--accent); transition: opacity .2s;
}
.pb-playing-dot.on { opacity: 1; animation: pulse 1.6s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.35); } }
.pb-info { min-width: 0; }
.pb-title { font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg-strong); }
.pb-artist { font-size: 12px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 3px; }

.pb-mid { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
.pb-btns { display: flex; align-items: center; gap: 12px; }
.pb-btns .icon-btn svg { width: 17px; height: 17px; }
/* æ’­æ”¾æŒ‰é’®ï¼šé»˜è®¤ä»…å›¾æ ‡ï¼ˆæ— åœ†åº•ï¼‰ï¼Œæ‚¬å�œæ—¶åœ†åº•æ˜¾çŽ°ï¼›å°ºå¯¸ä¸Žå…¶ä½™å›¾æ ‡æŒ‰é’®ä¸€è‡´ */
.pb-play {
  width: 34px; height: 34px; border-radius: 50%;
  background: transparent; color: var(--fg-strong);
  display: grid; place-items: center; transition: background .2s, box-shadow .2s, filter .2s;
}
.pb-play:hover { background: var(--accent); color: var(--on-accent); }
.pb-play svg { width: 17px; height: 17px; }
.pb-play .ic-play { margin-left: 2px; }
.pb-play .ic-pause { display: none; }
.pb-play.playing .ic-play { display: none; }
.pb-play.playing .ic-pause { display: block; }
/* æ’­æ”¾æŒ‰é’®ä¸�å�šæ—‹è½¬æ•ˆæžœï¼ˆåŠ è½½ä¸­ä»…é™�ä½Žäº®åº¦æ��ç¤ºï¼‰ */
.pb-play.loading { opacity: .7; }

.pb-progress { display: flex; align-items: center; gap: 10px; width: 100%; max-width: 520px; }
.pb-time { font-size: 11px; color: var(--sub); min-width: 34px; text-align: center; font-variant-numeric: tabular-nums; }

.pb-right { display: flex; align-items: center; gap: 8px; width: 26%; justify-content: flex-end; }
.pb-vol { display: flex; align-items: center; gap: 6px; }
.pb-vol input[type="range"] { width: 62px; flex: none; }
.vol-icon {
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  color: var(--sub); flex: none; transition: color .15s;
}
.vol-icon svg { width: 17px; height: 17px; }
button.vol-icon:hover { color: var(--fg-strong); background: var(--panel2); }
.vol-icon .ic-muted { display: none; }
.vol-icon.muted { color: var(--accent); }
.vol-icon.muted .ic-vol { display: none; }
.vol-icon.muted .ic-muted { display: block; }
.vol-icon.static { cursor: default; }
.quality-badge {
  padding: 4px 12px; border-radius: 8px; font-size: 11px; font-weight: 600;
  color: var(--sub); background: var(--panel2); border: 1px solid var(--border);
  user-select: none; flex: none;
}
#ov-quality-btn.quality-badge { cursor: pointer; color: rgba(var(--fg-rgb),.8); }
#ov-quality-btn.quality-badge:hover { color: var(--fg-strong); border-color: rgba(var(--accent-rgb),.5); }

/* éŸ³è´¨ä¸‹æ‹‰è�œå�•ï¼ˆæ’­æ”¾é¡µï¼‰ */
.quality-menu {
  position: absolute; right: 0; top: 44px; width: 228px; z-index: 70;
  background: rgba(var(--panel-rgb), .97); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(var(--fg-rgb),.1); border-radius: 14px; padding: 8px;
  box-shadow: 0 18px 50px rgba(0,0,0,.55);
  animation: menuIn .18s var(--ease);
}
@keyframes menuIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.q-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 9px;
  cursor: pointer; transition: background .13s; width: 100%; text-align: left;
}
.q-item:hover { background: var(--panel2); }
.q-item .q-name { font-size: 13.5px; font-weight: 600; }
.q-item .q-desc { font-size: 11px; color: var(--sub); margin-top: 1px; }
.q-item .q-check { margin-left: auto; color: var(--accent); opacity: 0; font-size: 14px; }
.q-item.active .q-check { opacity: 1; }
.q-item.active .q-name { color: var(--accent); }

/* ============ å…¨å±�æ’­æ”¾é¡µï¼ˆNow Playingï¼‰ ============ */
#overlay {
  position: fixed; inset: 0; z-index: 100; background: transparent; /* the plate paints it */
  display: flex; flex-direction: column; overflow: hidden;
  animation: ovIn .4s var(--ease);
}
@keyframes ovIn { from { opacity: 0; } to { opacity: 1; } }
#ov-bg {
  position: absolute; inset: -60px;
  background-size: cover; background-position: center;
  filter: blur(90px) brightness(.5) saturate(1.25); opacity: .8;
  transition: background-image .6s;
}
#ov-bg::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(var(--bg-rgb),.55), rgba(var(--bg-rgb),.88)); }
/* éš�éŸ³ä¹�èµ·ä¼�çš„åŠ¨æ€�é«˜å…‰ï¼šæ ¹æ�®å°�é�¢äº®éƒ¨åŒºåŸŸå¤šç‚¹å¢žäº®ï¼ˆJS ç”Ÿæˆ� radial èƒŒæ™¯ï¼‰ */
#ov-glow {
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 46%, rgba(var(--fg-rgb), .08), transparent 62%);
  filter: blur(18px);
  opacity: 0; pointer-events: none; z-index: 1;
  transition: opacity .12s linear;
}
.ov-top {
  position: relative; z-index: 2; display: flex; align-items: center; justify-content: space-between;
  padding: 18px 28px;
}
.ov-top-title { display: none; }
.ov-top-right { position: relative; }

.ov-body { position: relative; z-index: 2; flex: 1; display: flex; align-items: center; justify-content: center; gap: 6vw; padding: 6px 5vw 24px; min-height: 0; --ov-cover: min(44vh, 460px); transition: gap .35s var(--ease); }
#ov-body.lyrics-hidden { gap: 0; }
.ov-left {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  flex: none; width: min(500px, 48vw);
}
.ov-disc { position: relative; width: var(--ov-cover); aspect-ratio: 1; }
.ov-disc img {
  width: 100%; height: 100%; object-fit: cover; border-radius: 16px;
  box-shadow: 0 24px 80px rgba(0,0,0,.55);
}
.ov-hole { display: none; }
.ov-song { text-align: center; max-width: 100%; margin-top: 2px; }
.ov-title { font-size: 21px; font-weight: 700; letter-spacing: -.3px; color: var(--fg-strong); overflow-wrap: anywhere; }
.ov-artist { font-size: 14px; color: var(--sub); margin-top: 6px; overflow-wrap: anywhere; }

/* è¿›åº¦æ�¡ä¸ŽéŸ³é‡�æ�¡ï¼šä¸Žå°�é�¢å�Œå®½ï¼ˆç•¥çŸ­äºŽå°�é�¢ï¼‰ã€�ç™½è‰²å¡«å……ã€�æž�ç®€æ— åœ†ç‚¹ */
.ov-progress, .ov-vol {
  display: grid; grid-template-columns: 34px 1fr 34px; align-items: center;
  gap: 8px; width: calc(var(--ov-cover) + 84px);
}
.ov-progress .pb-time { text-align: center; font-size: 11px; color: rgba(var(--fg-rgb),.5); min-width: 0; }
.ov-vol .vol-icon { width: 34px; height: 34px; }
.ov-vol .vol-icon svg { width: 17px; height: 17px; }
.ov-vol input[type="range"] { flex: none; }

/* éŸ³è´¨æ��ç¤ºï¼šè¿›åº¦æ�¡ä¸‹æ–¹ï¼Œå°�å�·ã€�ä¸�å�¯ç‚¹å‡» */
.ov-quality {
  font-size: 10.5px; font-weight: 500; letter-spacing: .6px;
  color: rgba(var(--fg-rgb), .32); user-select: none;
  margin-top: -4px;
}

.ov-btns { display: flex; align-items: center; gap: 22px; margin-top: 4px; }
.ov-btns .icon-btn svg { width: 20px; height: 20px; }
.ov-btns .pb-play { width: 34px; height: 34px; }
.ov-btns .pb-play svg { width: 18px; height: 18px; }
.ov-btns .pb-play:hover {
  background: var(--accent);
  color: var(--on-accent);
}
.ov-btns .icon-btn.heart.on { color: var(--accent); }
.ov-btns .icon-btn.heart:not(.on):hover { color: var(--fg-strong); }

/* ============ æ­Œè¯�ï¼ˆæž�ç®€ Â· å·¦å¯¹é½� Â· å¤§å­—å�·ï¼‰ ============ */
.ov-right {
  flex: 1; max-width: 640px; min-width: 0; height: 100%;
  display: flex; flex-direction: column; position: relative; overflow: hidden;
  transition: opacity .35s var(--ease), transform .35s var(--ease),
    max-width .35s var(--ease), visibility .35s;
}
/* æ­Œè¯�éš�è—�ï¼šå�³ä¾§æ·¡å‡ºæ”¶æ‹¢ï¼Œå·¦ä¾§æŽ§ä»¶å¹³æ»‘ç§»å�‘ä¸­å¤®ï¼ˆæ˜¾ç¤ºæ—¶å��å�‘åŠ¨ç”»ï¼‰ */
#ov-body.lyrics-hidden .ov-right {
  opacity: 0; transform: translateX(40px);
  max-width: 0; pointer-events: none; visibility: hidden;
}
.ov-lyrics {
  flex: 1; overflow: hidden; position: relative;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
  scrollbar-width: none;
}
.ov-lyrics::-webkit-scrollbar { display: none; }
/* æ­Œè¯�è½¨é�“ï¼štransform å¹³ç§»æ»šåŠ¨ï¼ˆGPU å�ˆæˆ�ï¼Œé�¿å…�é€�å¸§é‡�ç»˜æ¨¡ç³Šå±‚å¯¼è‡´å�¡é¡¿ï¼‰ */
#ov-lyrics-inner { position: relative; will-change: transform; padding: 48vh 34px 52vh; }

/* æ­Œè¯�é�¢æ�¿å›ºå®šå·¥å…·æ �ï¼šæ’­æ”¾é¡µå�³ä¸‹è§’ï¼Œä¸�éš�æ­Œè¯�éš�è—�/æ»šåŠ¨ */
.ly-toolbar {
  position: absolute; right: 10px; bottom: 20px; z-index: 8;
  display: flex; gap: 10px; padding: 6px;
  background: rgba(var(--panel-rgb), .55); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(var(--fg-rgb), .08); border-radius: 22px;
}
.ly-tool {
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center; color: rgba(var(--fg-rgb), .5);
  transition: all .15s;
}
.ly-tool svg { width: 17px; height: 17px; }
.ly-tool:hover { color: var(--fg-strong); background: rgba(var(--fg-rgb), .1); }
.ly-tool.on { color: var(--accent); }
.ly-tool.on:hover { background: var(--accent-soft); }
.ly-tool.txt { font-size: 12px; font-weight: 700; letter-spacing: .5px; }

/* æ­Œè¯�è¡Œï¼šå·¦å¯¹é½�ï¼Œå­—å�·/ç²—ç»†/è¡Œè·�å�¯ç”±è®¾ç½®è°ƒèŠ‚ï¼›æ”¯æŒ�å¤šè¡Œæ�¢è¡Œã€‚
   æ—  YRC é€�å­—æ•°æ�®ï¼šæ•´æ®µæ˜¾ç¤ºï¼ˆæ´»åŠ¨è¡Œçº¯ç™½ï¼Œå…¶ä½™è¡Œç�°è‰²ï¼‰ï¼Œä¸�å�šå�¡æ‹‰OKå¡«å…… */
.ly-line {
  padding: 12px 0; text-align: left;
  font-size: var(--lyric-size, 22px);
  font-weight: var(--lyric-weight, 600);
  line-height: var(--lyric-lh, 1.75);
  color: rgba(245, 245, 247, .30);
  word-break: break-word; overflow-wrap: anywhere;
  cursor: pointer;
}
/* é�žæ’­æ”¾è¡Œï¼šæ¨¡ç³Šæ•ˆæžœï¼ˆå½“å‰�è¡Œæ¸…æ™°ï¼›è¿œå¤„è¡Œå…³é—­æ¨¡ç³Šï¼Œçœ� GPUï¼‰ */
.ly-line { transition: opacity .3s ease, color .3s ease; }
.ly-line:not(.active):not(.ly-far) { opacity: .55; }
.ly-line.ly-far { opacity: .38; }
/* æ‰‹åŠ¨æ»šåŠ¨é¢„è§ˆæ—¶ï¼šæ­Œè¯�ä¸�æ¨¡ç³Šï¼Œä¾¿äºŽæµ�è§ˆ */
.ov-lyrics.lyrics-previewing .ly-line:not(.active) { opacity: 1; }
/* å½“å‰�è¡Œï¼šæ•´æ®µç™½è‰²æ˜¾ç¤ºï¼Œä¸�æ”¾å¤§å­—å�· */
.ly-line.active .ly-text {
  color: var(--fg-strong);
  text-shadow: 0 0 18px rgba(var(--fg-rgb), .12);
}
.ly-trans {
  font-size: calc(var(--lyric-size, 22px) * .64); color: rgba(var(--fg-rgb), .38); margin-top: 4px; font-weight: 400;
  -webkit-text-fill-color: rgba(var(--fg-rgb), .38); color: rgba(var(--fg-rgb), .38);
}
.ly-trans.hide { display: none; }
.ly-line.active .ly-trans { color: rgba(var(--fg-rgb),.5); -webkit-text-fill-color: rgba(var(--fg-rgb),.5); }
/* å� ä½�æ–‡æ¡ˆï¼ˆçº¯éŸ³ä¹�/åŠ è½½ä¸­/åŠ è½½å¤±è´¥ï¼‰ï¼šå±…ä¸­äºŽå°�é�¢ä¸­å¿ƒï¼Œä¸�å�¯æ»šåŠ¨ã€�ä¸�å�¯é€‰æ‹©ï¼›
   å­—å�·è·Ÿéš�æ­Œè¯�å­—å�·è®¾ç½®ï¼ˆæ›´å¤§æ›´ç²—ï¼‰ */
.ly-placeholder {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  color: var(--sub); font-weight: 600; font-size: calc(var(--lyric-size, 22px) * 1.2);
  pointer-events: none; user-select: none; -webkit-user-select: none;
  text-align: center;
  transform: translateY(-10px);
}
.ly-placeholder[hidden] { display: none; }

/* ============ é˜Ÿåˆ—æŠ½å±‰ ============ */
#queue-mask {
  position: fixed; inset: 0; z-index: 110; background: rgba(0,0,0,.5);
  backdrop-filter: blur(3px); animation: fadeIn .25s;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
#queue-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 352px; z-index: 120;
  background: rgba(var(--panel-rgb), .96); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px);
  border-left: 1px solid var(--border);
  display: flex; flex-direction: column; animation: drawerIn .3s var(--ease);
  box-shadow: -20px 0 60px rgba(0,0,0,.45);
}
@keyframes drawerIn { from { transform: translateX(100%); } to { transform: translateX(0); } }
.qd-head {
  display: flex; align-items: center; justify-content: space-between; padding: 20px 20px 14px;
  font-size: 15px; font-weight: 700; color: var(--fg-strong); border-bottom: 1px solid var(--border);
}
.qd-head em { font-style: normal; font-size: 12px; color: var(--sub); font-weight: 400; margin-left: 8px; }
.qd-list { flex: 1; overflow-y: auto; padding: 10px; }
.qd-empty { text-align: center; color: var(--sub); padding: 70px 0; font-size: 13px; }
.qd-item {
  display: flex; align-items: center; gap: 12px; padding: 9px 11px; border-radius: 11px; cursor: pointer;
  transition: background .13s;
}
.qd-item:hover { background: var(--panel); }
.qd-item.active { background: var(--accent-soft); }
.qd-idx { width: 22px; text-align: center; color: var(--sub); font-size: 12.5px; flex: none; font-variant-numeric: tabular-nums; }
.qd-cover { width: 42px; height: 42px; border-radius: 7px; overflow: hidden; flex: none; background: var(--bg3); box-shadow: 0 2px 8px rgba(0,0,0,.3); }
.qd-cover img { width: 100%; height: 100%; object-fit: cover; }
.qd-main { flex: 1; min-width: 0; }
.qd-name { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qd-item.active .qd-name { color: var(--accent); font-weight: 600; }
.qd-artists { font-size: 11.5px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
.qd-dur { font-size: 11.5px; color: var(--sub); flex: none; font-variant-numeric: tabular-nums; }
.qd-rm { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; color: var(--sub); opacity: 0; flex: none; }
.qd-item:hover .qd-rm { opacity: 1; }
.qd-rm:hover { color: var(--accent-2); background: rgba(var(--accent-rgb),.14); }
.qd-rm svg { width: 16px; height: 16px; }
.qd-eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 14px; }
.qd-eq i { width: 3px; background: var(--accent); border-radius: 2px; animation: eq 1s ease-in-out infinite; }
.qd-eq i:nth-child(1) { height: 6px; animation-delay: 0s; }
.qd-eq i:nth-child(2) { height: 14px; animation-delay: .25s; }
.qd-eq i:nth-child(3) { height: 9px; animation-delay: .5s; }
@keyframes eq { 0%, 100% { transform: scaleY(.5); } 50% { transform: scaleY(1); } }

/* ============ è®¾ç½®å¼¹çª—ï¼ˆSheet é£Žæ ¼ï¼‰ ============ */
.modal { position: fixed; inset: 0; z-index: 130; display: flex; align-items: center; justify-content: center; }
.modal-mask { position: absolute; inset: 0; background: rgba(0,0,0,.55); backdrop-filter: blur(6px); animation: fadeIn .25s; }
.modal-panel {
  position: relative; width: min(500px, 92vw); max-height: 84vh; overflow-y: auto;
  background: rgba(var(--panel-rgb), .97); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px);
  border: 1px solid rgba(var(--fg-rgb),.1); border-radius: 20px;
  padding: 24px 28px; box-shadow: 0 28px 90px rgba(0,0,0,.6); animation: ovIn .3s var(--ease);
}
.modal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.modal-head span { font-size: 18px; font-weight: 700; color: var(--fg-strong); letter-spacing: -.3px; }
.set-group { margin-bottom: 22px; }
.set-label { font-size: 12px; color: var(--sub); margin-bottom: 10px; font-weight: 600; letter-spacing: .4px; }
.set-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.set-row:last-child { margin-bottom: 0; }
.set-sub { font-size: 12px; color: var(--sub); width: 36px; flex: none; }
.set-row .set-quality { margin-bottom: 0; }
.set-quality { display: flex; flex-wrap: wrap; gap: 8px; }
.set-quality .q-item {
  width: auto; padding: 8px 15px; border-radius: 18px;
  border: 1px solid var(--border); background: var(--panel);
}
.set-quality .q-item .q-check { display: none; }
.set-quality .q-item.active { border-color: rgba(var(--accent-rgb),.45); background: var(--accent-soft); }
.set-quality .q-item.active .q-name { color: var(--accent); }
.set-keyrow { display: flex; gap: 10px; }
.set-keyrow input {
  flex: 1; padding: 11px 15px; border-radius: 11px; font-size: 13px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text); outline: none;
}
.set-keyrow input:focus { border-color: rgba(var(--accent-rgb),.55); box-shadow: 0 0 0 3px rgba(var(--accent-rgb),.15); }
.set-hint { font-size: 11.5px; color: var(--sub); margin-top: 8px; line-height: 1.6; }
.set-btns { display: flex; gap: 10px; flex-wrap: wrap; }

/* ============ Toast ============ */
#toast { position: fixed; bottom: calc(var(--bar-h) + 30px); left: 50%; transform: translateX(-50%); z-index: 200; pointer-events: none; }
.toast {
  background: rgba(var(--panel-rgb), .96); color: var(--fg-strong); padding: 10px 22px; border-radius: 24px;
  font-size: 13px; font-weight: 500; box-shadow: 0 10px 36px rgba(0,0,0,.5);
  border: 1px solid rgba(var(--fg-rgb),.1);
  opacity: 0; transform: translateY(14px); transition: all .3s var(--ease);
  white-space: nowrap; max-width: 86vw; overflow: hidden; text-overflow: ellipsis;
}
#toast.show .toast { opacity: 1; transform: translateY(0); }
.toast.warn { border-color: rgba(var(--accent-rgb),.5); background: rgba(60, 24, 30, .96); }

/* ============ ç§»åŠ¨ç«¯ ============ */
@media (max-width: 1100px) {
  .pb-right { width: auto; }
  .pb-left { width: auto; flex: 1; }
  .sr-album { display: none; }
}
@media (max-width: 900px) {
  #sidebar {
    transform: translateX(calc(-100% - 32px)); transition: transform .3s var(--ease);
    box-shadow: 24px 0 70px rgba(0,0,0,.55);
    background: rgba(var(--panel-rgb), .96);
  }
  #sidebar.open { transform: translateX(0); }
  #main, #topbar, #playerbar { left: 0; margin-left: 0; }
  #topbar { left: 0; }
  #btn-menu { display: grid; }
  .topbar-title { font-size: 21px; }
  .ov-body { gap: 4vw; }
  .ov-left { width: min(380px, 46vw); gap: 13px; }
  .ov-body { --ov-cover: min(33vh, 300px); }
  .ov-disc { width: min(33vh, 300px); }
}
@media (max-width: 700px) {
  :root { --bar-h: 70px; }
  #view { padding: 18px 16px 30px; }
  #topbar { padding: 0 14px; gap: 12px; }
  .banner { height: 160px; }
  .pl-grid { grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 16px 12px; }
  .pl-grid.featured { grid-template-columns: repeat(2, 1fr); }
  #playerbar { padding: 0 12px; gap: 10px; right: 10px; bottom: 10px; border-radius: 24px; }
  .pb-cover { width: 40px; height: 40px; }
  .pb-right { display: none; }
  .detail-head { flex-direction: column; align-items: center; text-align: center; gap: 18px; }
  .dt-cover { width: 170px; height: 170px; }
  .dt-name { font-size: 24px; }
  .dt-actions { justify-content: center; }
  .ov-body { flex-direction: column; justify-content: flex-start; padding-top: 14px; overflow-y: auto; }
  .ov-right { width: 100%; max-width: 100%; height: 48vh; display: flex; flex: none; }
  .ov-left { width: 100%; padding: 0 22px; display: flex; }
  #ov-lyrics-inner { padding: 42vh 24px 44vh; }
  .ov-body { --ov-cover: min(34vh, 250px); }
  .ov-disc { width: min(34vh, 250px); }
  .ov-btns { gap: 18px; }
  .ly-toolbar { right: 12px; bottom: 12px; }
  #queue-drawer { width: 88vw; }
  .sr-fav, .sr-dl { opacity: 1; }
  .song-row { gap: 10px; padding: 9px 10px; }
  .sr-dur { display: none; }
}

/* ===== ÏêÇéÒ³·µ»Ø°´Å¥ ===== */
.view-back { display: inline-flex; align-items: center; gap: 8px; width: fit-content; margin: 2px 0 14px; padding: 7px 16px 7px 10px; border-radius: 999px; background: var(--panel); border: 1px solid var(--border); color: var(--text); font-size: 13px; line-height: 1; cursor: pointer; user-select: none; transition: background .18s var(--ease); }
.view-back svg { width: 16px; height: 16px; fill: var(--sub); transition: fill .18s var(--ease); }
.view-back:hover { background: var(--accent-soft); }
.view-back:hover svg { fill: var(--accent); }
@media (max-width: 720px) { .view-back { margin: 0 0 10px; padding: 6px 12px 6px 8px; font-size: 12px; } }

/* ===== ¸è´Ê¶¯»­ GPU »¯ =====
 * ¹ìµÀÖ»×ö translate3d Æ½ÒÆ£¨ºÏ³ÉÆ÷²ãÔËÐÐ£¬²»´¥·¢ÖØÅÅ/ÖØ»æ£©£»
 * will-change ÌáÇ°½¨²ã£¬±ÜÃâ¶¯»­ÖÐÍ¾·´¸´ÌáÉý¡£
 */
.ov-lyrics-inner {
  will-change: transform;
  transform: translate3d(0, 0, 0);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
  .ly-line { transition: none !important; }
}

/* ÉèÖÃµ¯´°¼Ó¿í£º³¤ËµÃ÷ÎÄ×Ö¸üÉÙ»»ÐÐ£¬±ãÓÚÔÄ¶Á */
#settings .modal-panel { width: min(94vw, 700px); }
#settings .set-label, #settings .set-sub { font-size: 13px; }
#settings .set-hint { font-size: 12.5px; line-height: 1.8; }
@media (max-width: 560px) { #settings .modal-panel { width: 96vw; padding: 20px 18px; } }

/* ÉèÖÃÐÐÉÏÏÂ¶Ñµþ£ºÎÄ×Ö¶ÀÕ¼Ò»ÐÐ£¬¿Ø¼þÔÚÏÂÒ»ÐÐ */
.set-row.col { flex-direction: column; align-items: stretch; gap: 6px; }
.set-row.col .set-sub { width: auto; }
.set-row.col .set-quality { display: flex; flex-wrap: wrap; gap: 8px; }
.set-row.col .set-quality .q-item { flex: 1 1 auto; justify-content: center; padding: 9px 12px; }
.set-row.col .set-btns { display: flex; flex-wrap: wrap; gap: 10px; }
.set-row.col .set-btns .mini-btn { flex: 1 1 200px; margin-top: 0; justify-content: center; }

/* ===== ¸è´ÊË«²ã GPU äÖÈ¾ =====
 * Ä£ºý²ã£ºÕû²ãÒ»¸ö blur ÂË¾µ + ×ÔÉí translate3d£¨ÎÆÀí»º´æ¸´ÓÃ£¬ºÏ³ÉÆ÷Æ½ÒÆ£¬²»ÖðÐÐÖØ¹âÕ¤»¯£©£»
 * ÇåÎú²ã£º½ö»î¶¯ÐÐ¸ßÁÁ£¬·Ç²¥·ÅÐÐÍ¸Ã÷¶ÈºÜµÍÂ¶³öÄ£ºý²ã¡£
 */
.lyric-blur-wrap { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.lyric-blur-inner {
  filter: blur(5px);
  opacity: .5;
  will-change: transform;
  transform: translate3d(0, 0, 0);
  padding: 48vh 34px 52vh;
  color: rgba(245, 245, 247, .45);
  transition: opacity .3s ease;
}
.lyric-blur-inner .ly-line { color: inherit; }
.lyric-blur-inner .ly-text { color: inherit; }
@media (max-width: 720px) { .lyric-blur-inner { padding: 42vh 24px 44vh; } }

/* ÇåÎú²ã£º»î¶¯ÐÐ 1£¬½ü´¦ÐÐ°ëÍ¸Ã÷Î¢Â¶£¨µþÔÚÄ£ºý²ãÉÏ³ÊÈáºÍ¹âÔÎ£©£¬Ô¶´¦ÐÐÈ«Í¸£¨½»¸øÄ£ºý²ã£© */
.ly-line:not(.active):not(.ly-far) { opacity: .18; }
.ly-line.ly-far { opacity: 0; }
.ly-line.active { opacity: 1; }
/* ÊÖ¶¯ä¯ÀÀ¸è´Ê£º¹ØÄ£ºý²ã£¬È«²¿ÐÐÇåÎú¿É¶Á */
.ov-lyrics.lyrics-previewing .lyric-blur-inner { opacity: 0; }
.ov-lyrics.lyrics-previewing .ly-line:not(.active) { opacity: 1; }

/* Õ­ÆÁµ×²¿²¥·ÅÆ÷£ºÊÕÆð´ÎÒª°´Å¥£¬·À¿Ø¼þÔ½½ç£»ÊÊÅäÁõº£°²È«Çø */
@media (max-width: 700px) {
  #playerbar {
    left: calc(10px + env(safe-area-inset-left));
    right: calc(10px + env(safe-area-inset-right));
    bottom: calc(10px + env(safe-area-inset-bottom));
    width: auto;
  }
  .pb-left { flex: 0 1 auto; max-width: 46vw; min-width: 0; }
  .pb-mid { flex: 1 1 auto; min-width: 0; }
  .pb-btns { gap: 0px; }
  .pb-btns .icon-btn { width: 36px; height: 36px; flex: none; }
  #pb-mode { display: none !important; }
  #pb-fav { display: none !important; }
  .pb-btns .pb-play { width: 46px; height: 46px; flex: none; }
  .pb-progress { width: 100%; min-width: 0; }
  .pb-progress .pb-time { font-size: 10px; }
  .pb-info { min-width: 0; }
  .pb-title, .pb-artist { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ½ø¶ÈÐÐ¿ÉÊÕËõ£º¼«Õ­ÆÁÏÂÊ±¼äÎÄ±¾¹Ì¶¨¡¢½ø¶ÈÌõÎüÊÕÊ£Óà¿í¶È */
@media (max-width: 700px) {
  .pb-progress { gap: 6px; }
  #pb-bar { flex: 1 1 auto; min-width: 40px; }
  .pb-progress .pb-time { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
}

@media (max-width: 700px) { .pb-vol { display: none !important; } }

/* ÏêÇéÒ³¶¥²¿È«¿íÕÚÕÖÌõ£º×óÀàÐÍÎÄ±¾ / ÓÒ·µ»Ø°´Å¥ */
.detail-topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: -30px -32px 24px; padding: 12px 18px 12px 20px;
  background: rgba(var(--fg-rgb), .05);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border);
}
.dtb-type {
  font-size: 14px; font-weight: 700; letter-spacing: 2px; color: var(--text);
  display: inline-flex; align-items: center;
  padding: 7px 18px; border-radius: 999px;
  background: var(--accent-soft); border: 1px solid rgba(var(--accent-rgb), .25);
}
.detail-topbar .view-back { margin: 0; flex: none; }
@media (max-width: 700px) {
  .detail-topbar { margin: -18px -16px 18px; padding: 10px 10px 10px 14px; }
  .dtb-type { font-size: 13px; padding: 6px 14px; }
}

/* ¶¥À¸±êÌâÕÚÕÖ´ø£ººá¹áÕû¸öºáÏò¿í¶È£¬ÎÄ±¾+·µ»ØÍ¬´¦Ò»´ø */
.tb-band {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  height: calc(var(--topbar-h) - 18px); margin: 9px 0;
  padding: 0 8px 0 18px;
  background: rgba(var(--fg-rgb), .05);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border: 1px solid var(--border); border-radius: 14px;
}
.tb-band .topbar-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; margin: 0; }
.topbar-back {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 7px 14px 7px 10px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  font-size: 13px; line-height: 1; cursor: pointer; transition: background .18s var(--ease);
}
.topbar-back svg { width: 15px; height: 15px; fill: var(--sub); }
.topbar-back:hover { background: var(--accent-soft); }
.topbar-back:hover svg { fill: var(--accent); }
.topbar-back.hidden { display: none; }
@media (max-width: 700px) { .tb-band { padding: 0 6px 0 12px; border-radius: 12px; } .topbar-back { padding: 6px 11px 6px 8px; } }

/* ===== ¶¥À¸£¨È«ÆÁ¿í²£Á§±³¾° + ·µ»Ø/±êÌâÔ­Î»»¬Èë¶¯»­£© ===== */
#topbar { left: 0; gap: 16px; }
#topbar .topbar-title { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-back {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 200px; opacity: 1;
  padding: 7px 14px 7px 10px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  font-size: 13px; line-height: 1; cursor: pointer;
  white-space: nowrap; overflow: hidden;
  transition: max-width .28s var(--ease), opacity .22s var(--ease), padding .28s var(--ease), border-color .28s var(--ease), margin .28s var(--ease);
}
.topbar-back svg { width: 15px; height: 15px; fill: var(--sub); flex: none; }
.topbar-back:hover { background: var(--accent-soft); }
.topbar-back:hover svg { fill: var(--accent); }
/* Òþ²ØÌ¬£º¿í¶ÈÊÕËõÎª 0£¨´ø¶¯»­£©£¬±êÌâËæÖ®Æ½»¬×óÒÆÌù±ß */
.topbar-back.hidden {
  max-width: 0; opacity: 0; padding-left: 0; padding-right: 0;
  border-left-width: 0; border-right-width: 0; margin: 0;
  pointer-events: none;
}
@media (max-width: 900px) { #topbar { gap: 10px; } .topbar-back { padding: 6px 11px 6px 8px; } .topbar-back.hidden { padding-left: 0; padding-right: 0; } }

/* ²àÀ¸³éÌëÕÚÕÖ£¨¡Ü900px Ê±ÏÔÊ¾£© */
#side-mask {
  position: fixed; inset: 0; z-index: 38; background: rgba(var(--bg-rgb), .55);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  opacity: 0; pointer-events: none; transition: opacity .25s ease;
}
#side-mask.show { opacity: 1; pointer-events: auto; }
#side-mask.hidden { display: none; }
#sidebar.open + #side-mask, #side-mask.show { display: block; }
@media (min-width: 901px) { #side-mask { display: none !important; } }

/* ÊÖ»ú¶Ë²¥·ÅÆ÷£º½ø¶ÈÌõÉÏÒÆÓë¸èÃûÍ¬Ë®Æ½Ïß£¨°´Å¥»»ÐÐÔÚÏÂ·½£© */
@media (max-width: 700px) {
  .pb-mid { gap: 2px; }
  .pb-btns { order: 2; }
  .pb-progress { order: 1; margin-top: 11px; }
  .pb-btns .icon-btn { width: 34px; height: 34px; }
  .pb-btns .pb-play { width: 42px; height: 42px; }
}

/* ²àÀ¸ÄÚÈÝÕûÌåÈÃ³ö¶¥À¸¸ß¶È£¨È«¿í¶¥À¸ÆÌÂúÆäÉÏ£© */
#sidebar { padding-top: calc(var(--topbar-h) + 4px); }
#sidebar .side-logo { padding-top: 6px; }
@media (max-width: 900px) { #sidebar { padding-top: calc(var(--topbar-h) + 4px); } }

#sidebar { z-index: 60; }

@media (max-width: 700px) { .pb-progress { margin-top: 18px; } }

@media (max-width: 700px) { .pb-progress { margin-top: 19px; } .pb-btns .icon-btn { width: 30px !important; height: 30px !important; } .pb-btns .pb-play { width: 34px !important; height: 34px !important; } }

/* »Ö¸´£º×ÀÃæ¶¥À¸´Ó²àÀ¸ÓÒ²à¿ªÊ¼£¨²£Á§±³¾°¸²¸ÇÄÚÈÝÇøÕû¿í£©£»²àÀ¸»Øµ½¶¥²¿Ô­Î»ÖÃ */
#topbar { left: var(--side-offset); gap: 16px; }
#sidebar { padding-top: 0; }
#sidebar .side-logo { padding-top: 24px; }
@media (max-width: 900px) { #topbar { left: 0; } #sidebar { padding-top: 0; } }

/* ·µ»Ø°´Å¥Î¢µ÷£ºÏÂÒÆ 2px */
.topbar-back { transform: translateY(2px); }

/* ¸èµ¥/×¨¼­/¸èÊÖÏêÇéÎÄ×ÖÍ³Ò»×ó¶ÔÆë£¨º¬ÊÖ»úÕ­ÆÁ£© */
@media (max-width: 700px) {
  .detail-head { text-align: left; }
  .detail-head .dt-info { width: 100%; text-align: left; }
  .detail-head .dt-name { text-align: left; }
  .detail-head .dt-meta { text-align: left; }
  .detail-head .dt-desc { text-align: left; margin-left: 0; }
  .detail-head .dt-actions { justify-content: flex-start; text-align: left; }
}

/* ============ Avatar / Account section (appended) ============ */
/* Circular avatar: 28px in sidebar, 64px (.lg) in settings dialog */
.usr-avatar {
  width: 28px; height: 28px; border-radius: 50%;
  flex: none; position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, rgba(var(--accent-rgb),.34), rgba(var(--accent-rgb),.15));
  border: 1px solid var(--border); color: var(--fg-strong);
  cursor: pointer; user-select: none; -webkit-user-select: none;
  transition: box-shadow .15s var(--ease);
}
.usr-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.usr-avatar b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; border-radius: 50%;
  font-size: 13px; font-weight: 700; color: var(--fg-strong);
  background: linear-gradient(135deg, #fa2d3c, #ff5a6a);
}
.usr-avatar:hover { box-shadow: 0 0 0 3px rgba(var(--accent-rgb),.32); }
.usr-avatar.lg { width: 64px; height: 64px; }
.usr-avatar.lg b { font-size: 26px; }
.usr-avatar .cam {
  position: absolute; inset: auto 0 0 0; height: 34%;
  display: grid; place-items: center;
  background: rgba(0,0,0,.52); opacity: 0;
  transition: opacity .15s var(--ease); pointer-events: none;
}
.usr-avatar:hover .cam { opacity: 1; }
.usr-avatar .cam svg { width: 46%; height: auto; fill: var(--fg-strong); }
#side-user .usr-avatar { width: 28px; height: 28px; }
#side-user .usr-avatar b { font-size: 13px; }

/* Settings dialog: category blocks + group titles */
.set-cat { margin-bottom: 26px; }
.set-cat:last-child { margin-bottom: 0; }
#settings .set-cat .set-group { margin-bottom: 16px; }
#settings .set-cat .set-group:last-child { margin-bottom: 0; }
.set-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 14px; padding-bottom: 8px;
  font-size: 13px; font-weight: 700; color: var(--fg-strong);
  letter-spacing: .6px; border-bottom: 1px solid var(--border);
}
.set-head::before {
  content: ''; width: 3px; height: 14px; border-radius: 2px;
  background: var(--accent); flex: none;
}

/* Account section (login prompt / profile + password form) */
#set-account.set-group { margin-bottom: 0; }
.set-acc-tip { font-size: 13px; color: var(--sub); line-height: 1.7; margin: 2px 0 14px; }
.set-acc-btns { display: flex; gap: 12px; flex-wrap: wrap; }
.set-acc-btns .btn { min-width: 130px; justify-content: center; }
.set-acc-top { display: flex; align-items: center; gap: 18px; margin-bottom: 20px; }
.set-acc-info { min-width: 0; flex: 1; }
.set-acc-mail { font-size: 15px; font-weight: 600; color: var(--text); word-break: break-all; }
.set-acc-sub { font-size: 12px; color: var(--sub); margin-top: 4px; }
.set-acc-pw { border-top: 1px solid var(--border); padding-top: 18px; }
.set-acc-pw .set-label { margin-bottom: 12px; }
.set-acc-pw .auth-input { display: block; max-width: 440px; }
.set-acc-pw .auth-err { max-width: 440px; }
.set-acc-pw-btns { display: flex; margin-top: 4px; }
.set-acc-pw-btns .btn { justify-content: center; min-width: 150px; }
@media (max-width: 560px) {
  .set-acc-top { gap: 14px; }
  .set-acc-mail { font-size: 14px; }
}
/* ============================================================
 * Settings dialog: two-level menu navigation (appended)
 * ------------------------------------------------------------
 * Level 1 (#set-page-main, default when opened): menu list #set-menu
 *   with 3 rows (account/prefs/cache), then the Data / Thanks groups
 *   rendered directly below (not menu items).
 * Level 2 (.set-page panels): Account / Prefs / Cache sections, each
 *   with its own head row holding a back pill (.view-back).
 * Reuses tokens (--panel/--border/--accent/--accent-soft/--text/--sub)
 * and existing .set-group/.set-label/.usr-avatar/.view-back styles.
 * Row hover intent mirrors .side-pl/.song-row.
 * ============================================================ */
#set-page-main { display: flex; flex-direction: column; }
#set-menu { display: flex; flex-direction: column; gap: 10px; margin-bottom: 24px; }
.set-menu-row {
  display: flex; align-items: center; gap: 14px;
  padding: 11px 14px; border-radius: 14px;
  background: var(--panel); border: 1px solid var(--border);
  cursor: pointer; user-select: none; -webkit-user-select: none;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.set-menu-row:hover { background: var(--accent-soft); border-color: rgba(var(--accent-rgb),.3); }
.set-menu-tx { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 6px; }
.set-menu-name { font-size: 15px; font-weight: 600; color: var(--text); line-height: 1.25; }
.set-menu-sub { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 12px; color: var(--sub); line-height: 1.3; }
.set-menu-sub > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.set-menu-row .usr-avatar { pointer-events: none; cursor: default; flex: none; }
.set-menu-row .usr-avatar.off { opacity: .55; }
.set-menu-arrow { width: 13px; height: 13px; flex: none; fill: var(--sub); opacity: .9; }
.set-menu-row:hover .set-menu-arrow { fill: var(--accent); }
/* Second-level pages: head row (back pill) */
.set-page-head { margin-bottom: 16px; }
.set-page-head .view-back { margin: 0; }
@media (max-width: 560px) {
  .set-menu-row { padding: 10px 12px; }
  .set-page-head .view-back { margin: 0; }
}

/* ¸è´Ê¸ßË¹Ä£ºýÐÞÕý£º¸ü´ó°ë¾¶¡¢´¿Ä£ºý³ÊÏÖ£¨È¥µôÇåÎú²ãÈñÀû²ÐÁô£¬Ïû³ý·º¹â¸Ð£© */
.lyric-blur-inner { filter: blur(13px) saturate(1.05); opacity: .75; color: rgba(245, 245, 247, .62); }
.lyric-blur-inner .ly-line { color: inherit; }
.lyric-blur-inner .ly-text { color: inherit; }
.ly-line:not(.active):not(.ly-far) { opacity: 0; }
.ly-line.ly-far { opacity: 0; }
@media (max-width: 720px) { .lyric-blur-inner { filter: blur(11px); } }

/* ¸ßË¹Ä£ºýÆ½ºâ£º°ë¾¶ÊÊÖÐ¡¢ÎÄ×Ö¸üÊµ£¬±£³ÖÄ£ºýÖÊ¸ÐÓÖ¿É±æÈÏ */
.lyric-blur-inner { filter: blur(8px); opacity: 1; color: rgba(245, 245, 247, .8); }
@media (max-width: 720px) { .lyric-blur-inner { filter: blur(7px); } }

/* ÐÞÕý£ºÍ¸Ã÷¶È¹æÔòÖ»×÷ÓÃÓÚÇåÎú²ã£¬Ä£ºý²ã¸è´Êºã¿É¼û */
#ov-lyrics-inner .ly-line:not(.active):not(.ly-far) { opacity: 0; }
#ov-lyrics-inner .ly-line.ly-far { opacity: 0; }
#ov-lyrics-inner .ly-line.active { opacity: 1; }
.lyric-blur-inner .ly-line { opacity: 1 !important; }
.ov-lyrics.lyrics-previewing .lyric-blur-inner .ly-line { opacity: 1; }

/* ×îÖÕ¸ßË¹Ä£ºý²ÎÊý£º4px£¬ÎÞ·º¹â */
.lyric-blur-inner { filter: blur(4px); opacity: 1; color: rgba(245, 245, 247, .75); }
@media (max-width: 720px) { .lyric-blur-inner { filter: blur(4px); } }

/* Ô¤ÀÀ(ä¯ÀÀ)¸è´ÊÊ±£ºÇåÎú²ãÈ«²¿ÐÐ¿É¼û£¬Ä£ºý²ãÒþ²Ø */
#ov-lyrics.lyrics-previewing #ov-lyrics-inner .ly-line:not(.active) { opacity: 1 !important; }
#ov-lyrics.lyrics-previewing #ov-lyrics-inner .ly-line.active { opacity: 1 !important; }

/* ³¹µ×È¥³ý·º¹â/¸ß¹â£ºÄ£ºý²ãÓëÇåÎú²ãÎÄ×Ö¾ùÎÞÒõÓ° */
.lyric-blur-inner, .lyric-blur-inner .ly-text, .lyric-blur-inner .ly-trans, #ov-lyrics-inner .ly-text, #ov-lyrics-inner .ly-trans { text-shadow: none !important; }

/* ×Ô¶¯¹ö¶¯Ä£Ê½£º¹Ø±ÕÄ£ºý²ã£¬·ÇÖ÷¸è´ÊÍ³Ò» 60% ÇåÎúÏÔÊ¾£¨ÎÞ·º¹â£© */
.lyric-blur-inner { opacity: 0 !important; display: none !important; }
#ov-lyrics-inner .ly-line:not(.active) { opacity: .6 !important; }
#ov-lyrics-inner .ly-line.ly-far { opacity: .6 !important; }
#ov-lyrics.lyrics-previewing .lyric-blur-inner { opacity: 0 !important; }

/* ·ÇÖ÷¸è´Ê£º60% Í¸Ã÷¶È + 4px ¸ßË¹Ä£ºý£¬ÆäÓà²»±ä */
#ov-lyrics-inner .ly-line:not(.active):not(.ly-far) { filter: blur(4px) !important; }
/* ============================================================
 * Feature: search history / id & link direct search /
 * custom playlists (new styles appended on 2026-09)
 * ============================================================ */
.mp-count { margin-left: auto; font-size: 13px; color: rgba(var(--fg-rgb),.55); }
.mp-tools { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin: 0 0 16px; }
.mp-tools .mp-input {
  flex: 1 1 220px; min-width: 0; padding: 10px 12px; border-radius: 10px;
  border: 1px solid rgba(var(--fg-rgb),.15); background: rgba(var(--fg-rgb),.06);
  color: var(--fg-strong); outline: none; font-size: 14px;
}
.mp-tools .mp-input:focus { border-color: rgba(var(--accent-rgb),.55); box-shadow: 0 0 0 3px rgba(var(--accent-rgb),.18); }
.mp-import { display: flex; gap: 10px; align-items: flex-start; margin-bottom: 4px; }
.mp-import .search-box { flex: 1; margin: 0; }
.mp-progress { font-size: 12px; color: rgba(var(--fg-rgb),.55); min-height: 16px; margin-bottom: 12px; }
.mp-name { font-size: 14px; font-weight: 600; color: var(--fg-strong); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 8px; }
.mp-acts { display: flex; gap: 6px; margin-top: 8px; }
.mp-acts .mini-btn { padding: 4px 10px; font-size: 12px; }
.mp-edit-input {
  width: 100%; padding: 6px 8px; border-radius: 8px; border: 1px solid rgba(var(--accent-rgb),.5);
  background: rgba(var(--fg-rgb),.08); color: var(--fg-strong); outline: none; font-size: 14px;
}
.mp-del-confirm { font-size: 13px; color: rgba(var(--fg-rgb),.75); display: flex; flex-direction: column; gap: 10px; padding: 14px 10px; }
.mp-del-confirm .mini-btn { align-self: flex-start; }
.mp-pick-mask {
  position: fixed; inset: 0; z-index: 999; background: rgba(0,0,0,.55);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.mp-pick {
  width: min(420px, 92vw); max-height: 76vh; overflow: auto; border-radius: 16px;
  background: var(--bg3); border: 1px solid rgba(var(--fg-rgb),.1); box-shadow: 0 18px 60px rgba(0,0,0,.5);
}
.mp-pick-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; font-size: 15px; font-weight: 700; color: var(--fg-strong);
  border-bottom: 1px solid rgba(var(--fg-rgb),.08); position: sticky; top: 0; background: var(--bg3);
}
.mp-pick-body { padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.mp-pick-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 12px; border-radius: 10px; border: 1px solid rgba(var(--fg-rgb),.08);
  background: rgba(var(--fg-rgb),.04); color: var(--fg-strong); font-size: 14px; text-align: left; cursor: pointer;
}
.mp-pick-item:hover { background: rgba(var(--accent-rgb),.14); border-color: rgba(var(--accent-rgb),.35); }
.mp-pick-item em { font-style: normal; font-size: 12px; color: rgba(var(--fg-rgb),.55); }
.mp-pick-foot { padding: 10px 16px 14px; font-size: 12px; color: rgba(var(--fg-rgb),.5); border-top: 1px solid rgba(var(--fg-rgb),.06); }
.sr-del { color: var(--accent-2) !important; }
/* custom playlist cover (2026-09) */
.mp-head { align-items: center; }
.mp-head-cover {
  width: 52px; height: 52px; border-radius: 12px; object-fit: cover; flex: none;
  border: 1px solid rgba(var(--fg-rgb),.18); background: rgba(var(--fg-rgb),.06);
}
.mp-cover { position: relative; }
.mp-cover-edit {
  position: absolute; right: 6px; bottom: 6px; width: 26px; height: 26px; padding: 5px;
  border-radius: 50%; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.55); color: var(--fg-strong); opacity: 0; transition: opacity .18s;
}
.mp-cover-edit svg { width: 100%; height: 100%; fill: var(--fg-strong); }
.mp-cover:hover .mp-cover-edit, .mp-cover-edit:focus { opacity: 1; }
.mp-cover-edit:hover { background: var(--accent); color: var(--on-accent); }
/* add-to-playlist row button accent */
.sr-pladd { color: #8ab4ff !important; }
/* add-to-playlist button: same muted gray as neighbor actions */
.sr-pladd { color: var(--sub) !important; }
/* add-to-playlist button hover: same as share (white + bg highlight) */
.sr-pladd:hover { color: var(--fg-strong) !important; }
/* notice: history viewer (v1.1) */
.notice-panel .modal-body { padding: 14px 16px 18px; }
.notice-body {
  display: flex; gap: 14px; align-items: stretch;
  max-height: 52vh; min-height: 240px;
}
.notice-side {
  flex: none; width: 130px; display: flex; flex-direction: column; gap: 6px;
  overflow-y: auto; padding-right: 4px;
  border-right: 1px solid rgba(var(--fg-rgb),.08);
}
.notice-ver-item {
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  padding: 9px 10px; border-radius: 10px; text-align: left;
  border: 1px solid rgba(var(--fg-rgb),.08); background: rgba(var(--fg-rgb),.04);
  color: var(--fg-strong); font-size: 13px; cursor: pointer; transition: all .15s;
}
.notice-ver-item b { font-size: 14px; font-weight: 700; }
.notice-ver-item span { font-size: 11px; color: rgba(var(--fg-rgb),.5); }
.notice-ver-item:hover { background: rgba(var(--fg-rgb),.09); }
.notice-ver-item.active { background: rgba(var(--accent-rgb),.16); border-color: rgba(var(--accent-rgb),.45); }
.notice-ver-item.active span { color: rgba(var(--fg-rgb),.75); }
.notice-main { flex: 1; min-width: 0; overflow-y: auto; }
.notice-main .notice-ver { margin-bottom: 10px; }
.notice-panel { width: min(560px, 94vw) !important; }
/* notice v1.1 visual alignment: side list flush with title, accent indicator, polish */
.notice-panel .modal-body { padding: 14px 0 18px; }
.notice-body { padding: 0 0 0 8px; }
.notice-side { width: 128px; }
.notice-ver-item.active { border-left: 3px solid var(--accent); padding-left: 7px; }
.notice-main { padding-right: 16px; }
.notice-main .notice-list li { margin: 0; }
.notice-list li::before { margin-right: 10px; }
/* notice v1.1 final alignment */
.notice-body { padding: 0; }

/* notice: wider reading area + letter-only small-version card headers */
.notice-panel { width: min(720px, 94vw) !important; }
.notice-body { max-height: 58vh; }
.notice-sec-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 6px;
}
.notice-sec-ver {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: .02em;
}
.notice-sec-date {
  font-size: 11px;
  color: rgba(var(--fg-rgb),.45);
  letter-spacing: .02em;
}
@media (max-width: 700px) {
  .notice-panel { width: 94vw !important; }
  .notice-panel .modal-body { padding: 12px 12px 16px; }
  .notice-body { flex-direction: column; gap: 8px; max-height: 64vh; }
  .notice-side {
    width: 100%;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: flex-start;
    overflow-x: auto;
    overflow-y: hidden;
    gap: 6px;
    padding: 0 0 6px;
    border-right: 0;
    border-bottom: 1px solid rgba(var(--fg-rgb),.08);
  }
  .notice-side::-webkit-scrollbar { display: none; }
  .notice-ver-item {
    flex: 0 0 auto;
    flex-direction: row;
    align-items: baseline;
    gap: 5px;
    padding: 6px 11px;
    border-radius: 999px;
  }
  .notice-ver-item b { font-size: 12.5px; }
  .notice-ver-item span { display: none; }
  .notice-ver-item.active { border-left-width: 1px; padding-left: 11px; }
  .notice-main { padding-right: 0; }
  .notice-main .notice-ver { display: none; }
  .notice-list > .notice-sec { padding: 8px 10px; margin-bottom: 8px; }
  .notice-sec-list > li { font-size: 13px; }
}

/* notice: only the content pane scrolls; the panel itself must not scroll */
#notice .modal-panel {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
#notice .modal-head { flex: none; }
#notice .modal-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
#notice .notice-body {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
}
#notice .notice-main {
  min-height: 0;
  overflow-y: auto;
}
#notice .modal-body > .btn { flex: none; }

/* the notice shell never shows its own scrollbar; only .notice-main scrolls */
#notice .modal-panel,
#notice .modal-body,
#notice .notice-body {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
#notice .modal-panel::-webkit-scrollbar,
#notice .modal-body::-webkit-scrollbar,
#notice .notice-body::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}

#notice .notice-main {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
#notice .notice-main::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}
/* lyric blur gradient: per-line --ly-blur set by JS (closer = sharper, 0.5px..4px) */
#ov-lyrics-inner .ly-line:not(.active):not(.ly-far) { filter: blur(var(--ly-blur, 4px)) !important; }
/* lyric translation toggle animation (v1.1) */
.ly-trans { transition: opacity .2s ease, transform .2s ease; }
.ly-trans.in { animation: lyTransIn .24s ease; }
.ly-trans.out { animation: lyTransOut .17s ease forwards; }
@keyframes lyTransIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@keyframes lyTransOut {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-4px); }
}
/* lyric line harmony animation for translation toggle (no-opacity flicker) */
.ly-line { transition: opacity .25s ease, transform .25s ease, filter .25s ease; }
.ly-line.ly-swap { animation: lyLineSwap .28s ease; }
@keyframes lyLineSwap {
  from { transform: translateY(4px); }
  to { transform: none; }
}
/* lyric preview: clear blur on non-active lines while scrolling (readable) */
#ov-lyrics.lyrics-previewing #ov-lyrics-inner .ly-line:not(.active) { filter: none !important; }
/* player toolbar idle fade: dim when unused, back to full on use (hover/touch) */
.ly-toolbar { opacity: .38; transition: opacity .35s ease; }
.ly-toolbar:hover, .ly-toolbar:focus-within, .ly-toolbar:active { opacity: 1; }
@media (max-width: 720px) { .ly-toolbar { opacity: .5; } }
/* YRC word-level karaoke highlight (active line only) */

/* YRC word brightness follows singing progress: start ~30% -> 100% at word end */

/* mobile purple artifacts: kill tap-highlight & default range accent/focus ring in player */
* { -webkit-tap-highlight-color: transparent; }
#overlay input[type="range"] { accent-color: var(--accent); }
#overlay input[type="range"]:focus, #overlay input[type="range"]:focus-visible,
#overlay button:focus, #overlay .ly-line:focus, #overlay .ly-text:focus { outline: none; }
/* kill any stray lines/decoration inside lyrics (mobile purple artifact) */
#ov-lyrics-inner .ly-line,
#ov-lyrics-inner .ly-line * { border: none !important; outline: none !important; text-decoration: none !important; }
#ov-lyrics-inner hr, #ov-lyrics-inner > hr, #ov-lyrics-inner .ly-line hr { display: none !important; }
#ov-lyrics-inner a { color: inherit !important; }
/* mobile lyrics mode: mini cover row on top, controls fixed bottom, max space to lyrics */
@media (max-width: 700px) {
  #ov-body:not(.lyrics-hidden) { justify-content: flex-start; padding-bottom: 210px; }
  #ov-body:not(.lyrics-hidden) .ov-left {
    flex-direction: row; align-items: center; gap: 14px;
    padding: 10px 20px 0; width: 100%;
  }
  #ov-body:not(.lyrics-hidden) .ov-disc { width: 84px; height: 84px; margin: 0; flex: none; }
  #ov-body:not(.lyrics-hidden) .ov-song { text-align: left; flex: 1; min-width: 0; }
  #ov-body:not(.lyrics-hidden) .ov-progress {
    position: fixed; bottom: 196px; left: 50%; transform: translateX(-50%);
    width: min(400px, 88vw); margin: 0;
  }
  #ov-body:not(.lyrics-hidden) .ov-quality {
    position: fixed; bottom: 158px; left: 50%; transform: translateX(-50%); margin: 0;
  }
  #ov-body:not(.lyrics-hidden) .ov-btns {
    position: fixed; bottom: 108px; left: 50%; transform: translateX(-50%); margin: 0;
  }
  #ov-body:not(.lyrics-hidden) .ov-vol {
    position: fixed; bottom: 56px; left: 50%; transform: translateX(-50%);
    width: min(400px, 88vw); margin: 0;
  }
  #ov-body:not(.lyrics-hidden) .ov-right { height: calc(100vh - 118px); }
}
/* mobile lyrics mode v2: bounded lyric viewport (no overflow into controls), no scrollbar */
@media (max-width: 700px) {
  #ov-body:not(.lyrics-hidden) { overflow: hidden; padding-bottom: 0; }
  #ov-body:not(.lyrics-hidden) .ov-right { height: calc(100vh - 380px); min-height: 300px; }
  #ov-lyrics-inner { padding: 30vh 24px 34vh; }
}
/* mobile lyrics v3: clip lyric content above controls (touch/visual), raise controls layer */
@media (max-width: 700px) {
  #ov-body:not(.lyrics-hidden) .ov-right { overflow: hidden; }
  #ov-body:not(.lyrics-hidden) .ov-progress,
  #ov-body:not(.lyrics-hidden) .ov-quality,
  #ov-body:not(.lyrics-hidden) .ov-btns,
  #ov-body:not(.lyrics-hidden) .ov-vol { z-index: 6; }
}
/* cover mode (lyrics hidden): whole group centered, no scrollbar, no page scroll */
@media (max-width: 700px) {
  #ov-body.lyrics-hidden { overflow: hidden; justify-content: center; align-items: center; }
}
/* cover mode hard center: whole group at screen geometric center (blue-box position) */
@media (max-width: 700px) {
  #ov-body.lyrics-hidden { position: relative; display: block; }
  #ov-body.lyrics-hidden .ov-left {
    position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 100%; display: flex; flex-direction: column;
    align-items: center; text-align: center; gap: 6px;
  }
}
/* fav self-built playlist button state */
.mini-btn.mp-faved { color: var(--accent); border-color: rgba(var(--accent-rgb),.45); }
.side-pl-mp { font-style: normal; font-size: 10px; color: var(--accent); border: 1px solid rgba(var(--accent-rgb),.4); border-radius: 4px; padding: 0 4px; margin-left: 6px; vertical-align: 1px; }
/* mp card: operation buttons horizontal, no wrap; heart fav on cover */
.mp-acts { flex-wrap: nowrap; }
.mp-acts .mini-btn { white-space: nowrap; font-size: 11px; padding: 3px 7px; }
.mp-card .pl-fav { position: absolute; top: 8px; right: 8px; opacity: .9; }
/* faved state keeps outlined style on hover (not solid red block) */
.mini-btn.mp-faved, .mini-btn.mp-faved:hover {
  color: var(--accent); border-color: rgba(var(--accent-rgb),.45);
  background: transparent;
}
.mini-btn.mp-faved:hover { background: var(--accent-soft); }
/* share / nickname / uid styles */
.mp-share-owner { margin: 10px 0 4px; color: var(--sub); font-size: 13px; }
.mp-share-tip { margin: 4px 0 14px; color: rgba(var(--fg-rgb),.45); font-size: 12px; }
.set-acc-uid { margin-top: 4px; font-size: 12px; color: rgba(var(--fg-rgb),.5); }
.set-acc-nick { margin-top: 14px; }
.set-acc-nick-row { display: flex; gap: 10px; margin-top: 8px; }
.set-acc-nick-row .auth-input { flex: 1; max-width: 340px; }
.set-acc-nick-row .btn { flex: none; }
/* nickname save button: matched input height, compact, gradient + glow */
.set-acc-nick-row .btn.primary {
  height: 44px; padding: 0 18px; min-width: 0;
  font-size: 13px; font-weight: 600; letter-spacing: .3px;
  border-radius: 12px; line-height: 1;
  background: var(--accent-grad);
  box-shadow: 0 4px 14px rgba(var(--accent-rgb), .28), inset 0 1px 0 rgba(var(--fg-rgb),.12);
  transition: transform .15s ease, box-shadow .2s ease, opacity .2s ease;
}
.set-acc-nick-row .btn.primary:hover { opacity: .94; box-shadow: 0 6px 18px rgba(var(--accent-rgb),.36); }
.set-acc-nick-row .btn.primary:active { }
/* nick save: keep pill shape (999px), shift up 2px to align with input */
.set-acc-nick-row .btn.primary { border-radius: 999px; position: relative; top: -2px; }
/* nick save: shrink ~3px taller fit */
.set-acc-nick-row .btn.primary { height: 41px; padding: 0 13px; font-size: 12.5px; }
/* nick save: font down, button down 1px */
.set-acc-nick-row .btn.primary { font-size: 12px; top: -1px; }
/* nick save row: under the input */
.set-acc-nick-row { margin-top: 10px; }
.set-acc-nick .auth-input { max-width: 340px; width: 100%; }
/* settings account: even spacing between blocks, divider sits between blocks (not on save btn) */
.set-acc-nick { margin-top: 0; margin-bottom: 18px; }
.set-acc-top { margin-bottom: 20px; }
.set-acc-pw { border-top: 1px solid var(--border); padding-top: 18px; }
/* settings page-switch: panel height morph */
#settings .modal-panel { transition: height .36s cubic-bezier(.22,.61,.36,1); }
/* settings panel height morph: reliable transition */
#settings .modal-panel { transition: height .36s cubic-bezier(.22,.61,.36,1); will-change: height; }
/* smaller camera icon on account avatar */
.usr-avatar.lg .cam svg { width: 38%; }
/* settings panel: higher cap so page-switch height morph is visible */
#settings .modal-panel { max-height: 96vh; }
/* secondary set pages: min height ? every switch has visible panel morph */
#set-page-prefs, #set-page-cache, #set-page-account { min-height: 620px; }
/* remove unified secondary-page height: panel follows content again */
#set-page-prefs, #set-page-cache, #set-page-account { min-height: 0; }
/* settings panel: unified width & top-left aligned controls */
#settings .modal-panel { width: min(94vw, 700px) !important; }
#settings .modal-body { text-align: left; }
/* settings panel: FIXED height (content scrolls inside) */
#settings .modal-panel { height: min(560px, 84vh); }
#settings .modal-panel { transition: none; }
/* download progress card */
.dl-card {
  position: fixed; bottom: 88px; left: 50%; transform: translateX(-50%);
  z-index: 99; width: min(360px, 88vw);
  background: rgba(var(--panel-rgb), .94); border: 1px solid var(--border);
  border-radius: 12px; padding: 11px 16px;
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .4);
}
.dl-name {
  font-size: 12px; color: rgba(var(--fg-rgb),.72); margin-bottom: 9px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding-right: 44px;
}
.dl-track { height: 6px; border-radius: 3px; background: rgba(var(--fg-rgb),.12); overflow: hidden; }
.dl-track i {
  display: block; height: 100%; width: 0;
  background: var(--accent-grad); border-radius: 3px;
  transition: width .18s linear;
}
.dl-pct {
  position: absolute; right: 14px; top: 11px;
  font-size: 12px; color: var(--accent); font-weight: 700;
}
/* indeterminate (fetching address) state */
.dl-track i.loading { width: 26%; animation: dlIndet 1.1s ease-in-out infinite; }
@keyframes dlIndet {
  0% { margin-left: -26%; }
  100% { margin-left: 100%; }
}
/* locked quality item */
.q-item.q-locked { opacity: .55; }
.q-item.q-locked .q-lock { font-style: normal; font-size: 10px; color: var(--accent); margin-left: 6px; }
.q-item.q-locked:hover { opacity: .8; }
/* cache capacity slider */
.set-cap-box { margin-top: 12px; }
.set-cap-val { font-size: 15px; font-weight: 700; color: var(--fg-strong); margin-bottom: 8px; }
.set-cap-box input[type="range"] { width: 100%; max-width: 440px; }
.set-cap-skala { display: flex; justify-content: space-between; max-width: 440px; margin-top: 4px; font-size: 11px; color: rgba(var(--fg-rgb),.38); }
.set-cap-tip { margin-top: 8px; font-size: 12px; color: var(--accent); opacity: .85; }
/* cache slider: full width to right edge + red fill paint */
.set-cap-box input[type="range"] { width: 100%; max-width: none; }
.set-cap-box .set-cap-val { margin-bottom: 10px; }
/* cache slider: comfortable width, responsive to panel on narrow screens */
.set-cap-box input[type="range"] { width: 100%; max-width: 520px; }
.set-cap-skala { max-width: 520px; }
/* cache slider: anchor width on container (parent auto-width was collapsing input) */
.set-cap-box { width: 100%; max-width: 520px; }
.set-cap-box input[type="range"] { width: 100%; max-width: none; }
.set-cap-skala { width: 100%; max-width: 520px; }
/* cache slider: right edge aligned with other controls (same width?) */
.set-cap-box { width: 100%; max-width: none; }
.set-cap-box input[type="range"] { width: 100%; max-width: none; }
.set-cap-skala { width: 100%; max-width: none; }
/* account page logout button at footer */
.set-acc-foot { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 16px; }
.set-acc-foot .btn { min-width: 130px; justify-content: center; }
/* page switch: blur fade-in + blocks drop from top */
@keyframes viewBlurIn { from { opacity: 0; filter: blur(10px); } to { opacity: 1; filter: blur(0); } }
#view.view-anim { animation: none; } /* 
Ù #view   filterfilter ú containing block …è fixed 1H */
@keyframes blkDropIn { from { opacity: 0; transform: translateY(-14px); filter: blur(8px); } 99% { filter: blur(.01px); } to { opacity: 1; transform: translateY(0); filter: none; } }
#view.view-anim > * { animation: blkDropIn .34s cubic-bezier(.22, .61, .36, 1) both; }
/* player overlay enter / exit */
@keyframes ovIn { from { opacity: 0; transform: translateY(24px) scale(.99); } to { opacity: 1; transform: none; } }
@keyframes ovOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(20px) scale(.99); } }
#overlay.ov-opening { animation: ovIn .34s cubic-bezier(.22, .61, .36, 1) both; }
#overlay.ov-closing { animation: ovOut .26s ease both; }
/* ============================================================
 * ????html[data-theme]????(??) / ?? / ?? / ?? / ?? / ??
 * ??????? --accent-rgb ? --fg-rgb ? rgba() ???
 * ============================================================ */
html[data-theme="black-blue"] {
  --accent: #3b82f6; --accent-rgb: 59, 130, 246;
  --accent-2: #60a5fa;
  --accent-soft: rgba(59, 130, 246, .14);
  --accent-grad: linear-gradient(135deg, #3b82f6, #60a5fa);
}
html[data-theme="black-gold"] {
  --accent: #e0b64a; --accent-rgb: 224, 182, 74;
  --accent-2: #f5d27a;
  --accent-soft: rgba(224, 182, 74, .16);
  --accent-grad: linear-gradient(135deg, #e0b64a, #f5d27a);
}
html[data-theme="black-purple"] {
  --accent: #a855f7; --accent-rgb: 168, 85, 247;
  --accent-2: #c084fc;
  --accent-soft: rgba(168, 85, 247, .16);
  --accent-grad: linear-gradient(135deg, #a855f7, #c084fc);
}
html[data-theme="white-blue"] {
  --fg-strong: #14161c; --bg3: #ffffff; --accent-2: #60a5fa;
  --bg-rgb: 243, 245, 249; --panel-rgb: 255, 255, 255;
  --bg: #f3f5f9; --bg2: #ffffff;
  --panel: rgba(0, 0, 0, .04); --panel2: rgba(0, 0, 0, .07);
  --border: rgba(0, 0, 0, .10);
  --text: #14161c; --sub: #626a76; --fg-rgb: 20, 22, 28;
  --accent: #2563eb; --accent-rgb: 37, 99, 235;
  --accent-soft: rgba(37, 99, 235, .12);
  --accent-grad: linear-gradient(135deg, #2563eb, #60a5fa);
}
html[data-theme="white-gold"] {
  --fg-strong: #1a1712; --bg3: #ffffff; --accent-2: #e0b64a;
  --bg-rgb: 247, 245, 240; --panel-rgb: 255, 255, 255;
  --bg: #f7f5f0; --bg2: #ffffff;
  --panel: rgba(0, 0, 0, .04); --panel2: rgba(0, 0, 0, .07);
  --border: rgba(0, 0, 0, .10);
  --text: #1a1712; --sub: #6d6455; --fg-rgb: 26, 23, 18;
  --accent: #b8860b; --accent-rgb: 184, 134, 11;
  --accent-soft: rgba(184, 134, 11, .14);
  --accent-grad: linear-gradient(135deg, #b8860b, #e0b64a);
}
/* ?????????????????????????? */
html[data-theme^="white-"] { color-scheme: light; }
html[data-theme^="white-"] .btn.primary,
html[data-theme^="white-"] .mini-btn.primary,
html[data-theme^="white-"] .set-acc-nick-row .btn.primary { color: var(--on-accent); }
html[data-theme^="white-"] .side { background: #ffffff; }
html[data-theme^="white-"] .modal-panel { background: rgba(255, 255, 255, .98); }
html[data-theme^="white-"] .player-bar { background: rgba(255, 255, 255, .96); }
html[data-theme^="white-"] .card:hover { background: rgba(0, 0, 0, .05); }
/* ?????? */
.set-themes { display: flex; flex-wrap: wrap; gap: 10px; }
.theme-item {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 13px 8px 9px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--panel);
  color: var(--text); font-size: 13px; cursor: pointer;
  transition: border-color .15s ease, background .15s ease, transform .12s ease;
}
.theme-item:hover { background: var(--panel2); }
.theme-item.active { border-color: var(--accent); background: var(--accent-soft); }
.theme-dot { width: 18px; height: 18px; border-radius: 50%; flex: none; border: 1px solid rgba(var(--fg-rgb), .22); }
.theme-dot i { display: block; width: 100%; height: 100%; border-radius: 50%; }
/* ===== ?????????? + ?????? ===== */
.set-themes { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 12px; max-width: 560px; }
.theme-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 8px; border-radius: 13px; cursor: pointer;
  border: 1px solid var(--border); background: var(--panel);
  transition: border-color .2s ease, box-shadow .2s ease, transform .12s ease;
}
.theme-card:hover { }
.theme-card.active { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.theme-prev {
  position: relative; display: block; width: 100%; aspect-ratio: 1 / 1;
  border-radius: 9px; overflow: hidden; border: 1px solid var(--border);
}
.theme-prev .tp-side { position: absolute; left: 0; top: 0; bottom: 0; width: 26%; display: block; }
.theme-prev .tp-line { position: absolute; left: 32%; top: 26%; height: 7px; width: 52%; border-radius: 4px; display: block; }
.theme-prev .tp-line.short { top: 42%; width: 34%; }
.theme-prev .tp-btn { position: absolute; left: 32%; bottom: 20%; width: 40%; height: 15px; border-radius: 8px; display: block; }
.theme-name { font-size: 12.5px; text-align: center; color: var(--text); font-weight: 600; }

/* ===== ??????????????????? ===== */
body, #app, .side, #topbar, #view, .card, .modal-panel, .modal-head, .player-bar,
.mini-btn, .btn, .q-item, .set-group, .set-menu-row, .side-btn, .side-pl,
.auth-input, .theme-card, .theme-prev, .sr-row, .mp-card, .list-row {
  transition: background-color .45s ease, color .45s ease, border-color .45s ease, box-shadow .45s ease;
}

/* ===== ??????????????????? ===== */
html[data-theme^="white-"] #overlay {
  --bg: #0b0b0e; --bg2: #121216; --bg3: #16161b;
  --bg-rgb: 11, 11, 14; --panel-rgb: 30, 30, 36;
  --fg-rgb: 255, 255, 255; --fg-strong: #ffffff;
  --text: #f5f5f7; --sub: #98989f;
  --panel: rgba(255, 255, 255, .055); --panel2: rgba(255, 255, 255, .09);
  --border: rgba(255, 255, 255, .09);
  color-scheme: dark;
}

html[data-theme^="white-"] input[type="range"] { background: rgba(var(--fg-rgb), .34); }
/* ???????? / ?? */
html[data-theme="white-red"] {
  --fg-strong: #1a1416; --bg3: #ffffff; --accent-2: #ff6b7a;
  --bg-rgb: 246, 244, 245; --panel-rgb: 255, 255, 255;
  --bg: #f6f4f5; --bg2: #ffffff;
  --panel: rgba(0, 0, 0, .04); --panel2: rgba(0, 0, 0, .07);
  --border: rgba(0, 0, 0, .10);
  --text: #1a1416; --sub: #6d6165; --fg-rgb: 26, 20, 22;
  --accent: #e0343f; --accent-rgb: 224, 52, 63;
  --accent-soft: rgba(224, 52, 63, .13);
  --accent-grad: linear-gradient(135deg, #e0343f, #ff6b7a);
}
html[data-theme="white-purple"] {
  --fg-strong: #17142a; --bg3: #ffffff; --accent-2: #a855f7;
  --bg-rgb: 246, 244, 250; --panel-rgb: 255, 255, 255;
  --bg: #f6f4fa; --bg2: #ffffff;
  --panel: rgba(0, 0, 0, .04); --panel2: rgba(0, 0, 0, .07);
  --border: rgba(0, 0, 0, .10);
  --text: #17142a; --sub: #645d75; --fg-rgb: 23, 20, 42;
  --accent: #7c3aed; --accent-rgb: 124, 58, 237;
  --accent-soft: rgba(124, 58, 237, .13);
  --accent-grad: linear-gradient(135deg, #7c3aed, #a855f7);
}
/* ============================================================
 * ?????????? / ?? / ?? / ?????
 * ============================================================ */
.rec-wrap { max-width: 720px; margin: 8px auto 40px; text-align: center; }
.rec-title { font-size: 22px; font-weight: 700; margin: 0 0 6px; color: var(--fg-strong); }
.rec-sub { font-size: 13px; color: var(--sub); margin-bottom: 26px; }
.rec-stage { position: relative; width: 190px; height: 190px; margin: 0 auto 18px; display: flex; align-items: center; justify-content: center; }
.rec-mic {
  position: relative; z-index: 2; width: 108px; height: 108px; border-radius: 50%;
  border: none; cursor: pointer; display: flex; align-items: center; justify-content: center;
  background: var(--accent-grad); color: var(--on-accent);
  transition: transform .18s ease, box-shadow .25s ease;
}
.rec-mic:hover { transform: scale(1.05); }
.rec-mic:active { transform: scale(.97); }
.rec-mic svg { width: 46px; height: 46px; fill: #fff; }
.rec-ring {
  position: absolute; inset: 0; border-radius: 50%; border: 2px solid rgba(var(--accent-rgb), .5);
  opacity: 0; pointer-events: none;
}
.rec-stage.recording .rec-ring { animation: recPulse 2.1s ease-out infinite; }
.rec-stage.recording .rec-ring.d2 { animation-delay: .7s; }
.rec-stage.recording .rec-ring.d3 { animation-delay: 1.4s; }
@keyframes recPulse {
  0% { transform: scale(.62); opacity: .85; }
  70% { opacity: .16; }
  100% { transform: scale(1.06); opacity: 0; }
}
.rec-stage.recording .rec-mic { animation: recBeat 1.1s ease-in-out infinite; }
@keyframes recBeat {
  0%, 100% { transform: scale(1); box-shadow: 0 14px 38px rgba(var(--accent-rgb), .38); }
  50% { transform: scale(1.06); box-shadow: 0 18px 52px rgba(var(--accent-rgb), .6); }
}
.rec-stage.scanning .rec-mic { animation: recScan 1.4s linear infinite; }
@keyframes recScan {
  0% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), .55); }
  100% { box-shadow: 0 0 0 26px rgba(var(--accent-rgb), 0); }
}
.rec-timer { font-size: 15px; font-weight: 700; letter-spacing: 1px; color: var(--text); margin-bottom: 6px; font-variant-numeric: tabular-nums; }
.rec-wave { display: flex; align-items: flex-end; justify-content: center; gap: 4px; height: 34px; margin: 6px 0 10px; }
.rec-wave i { display: block; width: 4px; height: 5px; border-radius: 2px; background: var(--accent); opacity: .35; transition: height .2s ease, opacity .2s ease; }
.rec-stage.recording .rec-wave i { opacity: 1; animation: recWave .9s ease-in-out infinite; }
.rec-wave i:nth-child(3n) { animation-duration: 1.15s; }
.rec-wave i:nth-child(4n) { animation-duration: .75s; }
.rec-wave i:nth-child(5n) { animation-duration: 1.35s; }
@keyframes recWave {
  0%, 100% { height: 6px; }
  50% { height: 30px; }
}
.rec-tip { font-size: 13px; color: var(--sub); }
.rec-result { margin-top: 22px; }
.rec-loading { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--sub); }
.rec-loading span { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); animation: recDot 1.1s ease-in-out infinite; }
.rec-loading span:nth-child(2) { animation-delay: .18s; }
.rec-loading span:nth-child(3) { animation-delay: .36s; margin-right: 4px; }
@keyframes recDot {
  0%, 100% { transform: translateY(0); opacity: .45; }
  50% { transform: translateY(-6px); opacity: 1; }
}
.rec-card {
  display: flex; align-items: center; gap: 14px; text-align: left;
  width: min(460px, 94%); margin: 0 auto; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 14px; background: var(--panel);
  animation: blkDropIn .38s cubic-bezier(.22, .61, .36, 1) both;
}
.rec-cover { width: 62px; height: 62px; border-radius: 10px; object-fit: cover; flex: none; background: var(--panel2); }
.rec-info { flex: 1; min-width: 0; }
.rec-name { font-size: 15px; font-weight: 700; color: var(--fg-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rec-artist { font-size: 12.5px; color: var(--sub); margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rec-card .btn { min-width: 86px; justify-content: center; }
.rec-empty { font-size: 13.5px; color: var(--sub); padding: 14px; }
/* ???????????????????????/??/?????? */
.rec-stage { display: block; position: relative; width: 190px; height: 190px; margin: 0 auto 14px; }
.rec-mic { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }
.rec-mic:hover { transform: translate(-50%, -50%) scale(1.05); }
.rec-mic:active { transform: translate(-50%, -50%) scale(.97); }
.rec-ring { position: absolute; left: 50%; top: 50%; width: 190px; height: 190px; margin: -95px 0 0 -95px; }
.rec-timer { margin: 0 0 4px; }
.rec-wave { display: flex; align-items: flex-end; justify-content: center; gap: 4px; height: 34px; margin: 4px auto 10px; }
.rec-tip { min-height: 18px; }
/* ???????????????????????????? */
@keyframes recBeat {
  0%, 100% { transform: translate(-50%, -50%) scale(1); box-shadow: 0 14px 38px rgba(var(--accent-rgb), .38); }
  50% { transform: translate(-50%, -50%) scale(1.06); box-shadow: 0 18px 52px rgba(var(--accent-rgb), .6); }
}
/* ????? JS?AnalyserNode?????????? CSS ???????????? */
.rec-stage.recording .rec-wave i { opacity: 1; animation: none; }
.rec-wave i { transition: height .07s linear, opacity .2s ease; }
/* ?????????????????????????? */
.rec-mic svg { width: 46px !important; height: 46px !important; fill: #ffffff !important; display: block; }
/* ?????????????????????? */
/* ??????????? 20 ???????????? */
/* ============================================================
 * ??????????? ? ???? ? ?????
 *  fade   ??????????????????
 *  scroll ????????????????????????????
 * ============================================================ */
/* ??????????????????????? */
/* ???????????????? */

/* ????????8 ???????? */
.set-themes { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 9px; max-width: 430px; }
.theme-card { padding: 6px; border-radius: 10px; gap: 6px; }
.theme-prev { aspect-ratio: 4 / 3; border-radius: 7px; }
.theme-prev .tp-side { width: 24%; }
.theme-prev .tp-line { left: 30%; top: 28%; height: 5px; width: 50%; }
.theme-prev .tp-line.short { top: 44%; width: 32%; }
.theme-prev .tp-btn { left: 30%; bottom: 18%; width: 38%; height: 12px; border-radius: 6px; }
.theme-name { font-size: 11.5px; }
/* ??????????????????????????? */
/* ????? JS ??????????? _lyricUpdate? */

/* ???????????????????????? JS ?????55% ??????? */

/* ============================================================
 * ????????????
 *  - ?????????(100%)??????(72%)?????? 3px ????
 *  - ???????????????? JS ??????????
 *  - ???????????????????
 * ============================================================ */
.ly-line.active .ly-w { color: var(--fg-strong); opacity: calc(.5 + .5 * var(--wp, 0)); will-change: opacity; }
.ly-line.active .ly-w.on { opacity: 1; }
.ly-line:not(.active) .ly-w { color: inherit; opacity: 1; }
/* ?????????????/??????? transform?????????? */
.ly-line.active .ly-w { transition: transform .18s cubic-bezier(.22, .61, .36, 1); }
/* ??????????????? */
#overlay[data-karaoke="fade"] .ly-w { transform: none !important; }
/* ??????? span ? inline?transform ??? ? ?????? inline-block
 * ?????????????????????????????? */
.ly-line.active .ly-w { display: inline-block; vertical-align: baseline; }
/* ????????????????1px ?????????? */
.ly-line.active .ly-w { will-change: transform, opacity; backface-visibility: hidden; }
/* ????????????????????????????/??? */
.ly-line.active .ly-w.w-cur { transition: none; }
/* ============================================================
 * HiBetter ?? AI ????????? / ?? / ?????
 * ============================================================ */
.hb-entry { margin: 4px 0 16px; }
.hb-entry-btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 11px 20px; border-radius: 12px; cursor: pointer;
  border: 1px solid rgba(var(--accent-rgb), .45);
  background: linear-gradient(135deg, rgba(var(--accent-rgb), .16), rgba(var(--accent-rgb), .04));
  color: var(--fg-strong); font-size: 14px; font-weight: 700;
  transition: transform .15s ease, box-shadow .25s ease, border-color .2s ease;
}
.hb-entry-btn em { font-style: normal; font-size: 11.5px; font-weight: 500; color: var(--sub); }
.hb-entry-btn:hover { border-color: var(--accent); box-shadow: 0 10px 26px rgba(var(--accent-rgb), .28); }
.hb-head { text-align: center; margin-bottom: 16px; }
.hb-title { font-size: 24px; font-weight: 800; color: var(--fg-strong); margin: 0 0 6px; }
.hb-title em { font-style: normal; font-size: 13px; font-weight: 700; color: var(--accent); border: 1px solid rgba(var(--accent-rgb), .5); border-radius: 6px; padding: 1px 6px; vertical-align: 3px; margin-left: 6px; }
.hb-sub { font-size: 12.5px; color: var(--sub); }
.hb-empty { text-align: center; color: var(--sub); font-size: 13px; padding: 40px 0; }
.hb-row { display: flex; gap: 10px; align-items: flex-start; }
.hb-row.me { justify-content: flex-end; }
.hb-ava {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; color: #fff; background: var(--accent-grad);
}
.hb-col { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 8px; }
.hb-bubble {
  max-width: 100%; padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.6;
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  white-space: pre-wrap; animation: blkDropIn .3s cubic-bezier(.22,.61,.36,1) both;
}
.hb-row.me .hb-bubble { background: var(--accent-soft); border-color: rgba(var(--accent-rgb), .35); color: var(--fg-strong); }
.hb-bubble.err { border-color: rgba(224, 52, 63, .5); }
.hb-bubble.typing { display: inline-flex; gap: 5px; align-items: center; }
.hb-bubble.typing span { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: recDot 1.1s ease-in-out infinite; }
.hb-bubble.typing span:nth-child(2) { animation-delay: .18s; }
.hb-bubble.typing span:nth-child(3) { animation-delay: .36s; }
.hb-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 8px; }
.hb-card {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 10px; background: var(--panel);
  transition: background .15s ease, transform .12s ease, border-color .15s ease;
  animation: blkDropIn .32s cubic-bezier(.22,.61,.36,1) both;
}
.hb-card:hover { background: var(--panel2); border-color: rgba(var(--accent-rgb), .45); }
.hb-card img { width: 42px; height: 42px; border-radius: 8px; object-fit: cover; flex: none; background: var(--panel2); }
.hb-card-tx { flex: 1; min-width: 0; }
.hb-card-name { font-size: 13px; font-weight: 600; color: var(--fg-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-card-sub { font-size: 11.5px; color: var(--sub); margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-card-play { flex: none; color: var(--accent); font-size: 12px; }
.hb-ai {
  flex: none; padding: 0 14px; height: 42px; border-radius: 11px; cursor: pointer;
  border: 1px solid rgba(var(--accent-rgb), .45); background: rgba(var(--accent-rgb), .12);
  color: var(--fg-strong); font-size: 13px; font-weight: 700;
  transition: background .18s ease, transform .12s ease;
}
.hb-ai:hover { background: rgba(var(--accent-rgb), .2); }
.hb-input {
  flex: 1; min-width: 0; height: 42px; padding: 0 14px; border-radius: 11px;
  border: 1px solid var(--border); background: var(--panel); color: var(--text); font-size: 14px; outline: none;
}
.hb-input:focus { border-color: rgba(var(--accent-rgb), .55); }
.hb-bar .btn { height: 42px; min-width: 84px; justify-content: center; }
.hb-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.hb-chip {
  padding: 6px 12px; border-radius: 999px; cursor: pointer; font-size: 12px;
  border: 1px solid var(--border); background: var(--panel); color: var(--sub);
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.hb-chip:hover { color: var(--fg-strong); border-color: rgba(var(--accent-rgb), .45); background: var(--panel2); }
/* HiBetter ?????? 2 ????????? */
.hb-cards { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 6px; }
.hb-card { padding: 6px 8px; gap: 8px; border-radius: 9px; }
.hb-card img { width: 34px; height: 34px; border-radius: 6px; }
.hb-card-name { font-size: 12.5px; }
.hb-card-sub { font-size: 11px; margin-top: 2px; }
.hb-card-play { font-size: 11px; }
.hb-bubble { font-size: 13.5px; padding: 9px 13px; }
.hb-chips { gap: 6px; }
.hb-chip { padding: 5px 10px; font-size: 11.5px; }
/* HiBetter Markdown ???? */
.hb-bubble.md { white-space: normal; }
.hb-bubble.md strong { color: var(--fg-strong); font-weight: 700; }
.hb-bubble.md em { font-style: italic; }
.hb-bubble.md code { background: var(--panel2); padding: 1px 5px; border-radius: 4px; font-size: 12.5px; font-family: ui-monospace, Menlo, Consolas, monospace; }
.hb-bubble.md ul { margin: 6px 0 6px 2px; padding-left: 18px; }
.hb-bubble.md li { margin: 2px 0; line-height: 1.55; }
.hb-bubble.md .hb-h { font-weight: 800; color: var(--fg-strong); margin: 8px 0 3px; }
.hb-bubble.md a { color: var(--accent); text-decoration: none; }
.hb-bubble.md a:hover { text-decoration: underline; }
.hb-bubble.md .hb-quote { border-left: 3px solid rgba(var(--accent-rgb), .5); padding-left: 9px; margin: 5px 0; color: var(--sub); }
/* HiBetter????? + ??????????????? */
.hb-icard {
  display: flex; align-items: center; gap: 8px; margin: 7px 0 9px; padding: 6px 9px;
  border: 1px solid var(--border); border-radius: 9px; background: var(--panel); cursor: pointer;
  transition: background .15s ease, transform .12s ease, border-color .15s ease;
  animation: blkDropIn .3s cubic-bezier(.22,.61,.36,1) both;
}
.hb-icard:hover { background: var(--panel2); border-color: rgba(var(--accent-rgb), .45); }
.hb-icard img { width: 34px; height: 34px; border-radius: 6px; object-fit: cover; flex: none; background: var(--panel2); }
.hb-icard-tx { flex: 1; min-width: 0; }
.hb-icard-name { font-size: 12.5px; font-weight: 600; color: var(--fg-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-icard-sub { font-size: 11px; color: var(--sub); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hb-icard-play { flex: none; color: var(--accent); font-size: 11px; }
/* 	­>ö
ûMn! */
/* no divider line */
body:has(.hb-bar) #playerbar { border-top-color: transparent; }
/* concave corners at the junction (inverted radius), matching the top block width */
body:has(.hb-bar) #playerbar::before,
body:has(.hb-bar) #playerbar::after {
  content: ''; position: absolute; top: -20px; width: 20px; height: 20px;
  background: rgba(var(--panel-rgb), .78);
  pointer-events: none;
}
body:has(.hb-bar) #playerbar::before {
  left: calc(50% - 280px);
  -webkit-mask: radial-gradient(circle at 100% 0, transparent 0 20px, #000 20px);
  mask: radial-gradient(circle at 100% 0, transparent 0 20px, #000 20px);
}
body:has(.hb-bar) #playerbar::after {
  right: calc(50% - 280px);
  -webkit-mask: radial-gradient(circle at 0 0, transparent 0 20px, #000 20px);
  mask: radial-gradient(circle at 0 0, transparent 0 20px, #000 20px);
}
/* no divider line between the two blocks */
body:has(.hb-bar) #playerbar { border-top-color: transparent; }
/* hide the player bar's top border on this page so no divider line shows between them */
body:has(.hb-bar) #playerbar { border-top-color: transparent; }
@media (max-width: 900px) {
}
.hb-chips { position: static; padding-bottom: 2px; margin-top: 12px; }
/* •èY}…¹
«úš“enO */

/* HiBetter ???????????????? fixed ????????????? */

/* ?????????????????????? */
.hb-icard { margin: 6px 0 12px; }
.hb-bubble.md ul { margin: 4px 0 6px 2px; }
.hb-bubble.md li { margin: 1px 0; line-height: 1.5; }
/* HiBetter?????????????????????????????????? */
/* HiBetter header: left aligned, greeting style */
.hb-head { text-align: left; margin-bottom: 14px; }
.hb-sub { font-size: 14px; color: var(--text); opacity: .9; }
/* HiBetter???????? + ??/???? */
.hb-think { margin: 0 0 6px; border-left: 2px solid rgba(var(--accent-rgb), .45); padding-left: 10px; }
.hb-think summary { cursor: pointer; font-size: 12px; color: var(--sub); list-style: none; user-select: none; }
.hb-think summary::-webkit-details-marker { display: none; }
.hb-think summary:hover { color: var(--fg-strong); }
.hb-think-body {
  margin-top: 5px; font-size: 12px; line-height: 1.6; color: var(--sub);
  opacity: .92; animation: hbFadeIn .3s ease both;
}
@keyframes hbFadeIn { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
/* ????????? */
.hb-bubble { animation: hbMsgIn .34s cubic-bezier(.22,.61,.36,1) both; }
@keyframes hbMsgIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.hb-icard { animation: hbCardIn .36s cubic-bezier(.22,.61,.36,1) both; }
@keyframes hbCardIn { from { opacity: 0; transform: translateY(10px) scale(.99); } to { opacity: 1; transform: none; } }
/* ??????????????? */
.hb-think-line { margin: 2px 0; font-size: 12px; line-height: 1.65; color: var(--sub); }
.hb-think-line em { font-style: normal; color: rgba(var(--accent-rgb), .95); }
.hb-think summary { font-weight: 600; }
.hb-bubble.md a { color: var(--accent); text-decoration: none; word-break: break-all; }
.hb-bubble.md a:hover { text-decoration: underline; }
/* ???????? + ?? AI ????????? */
.hb-bubble, .hb-bubble.md *, .hb-think-body, .hb-card-name, .hb-card-sub, .hb-icard-name, .hb-icard-sub {
  user-select: text; -webkit-user-select: text; cursor: text;
}
.hb-col { position: relative; }
.hb-copy {
  position: absolute; right: 6px; bottom: 6px; z-index: 2;
  padding: 3px 9px; border-radius: 999px; cursor: pointer;
  font-size: 11px; color: var(--sub);
  border: 1px solid var(--border); background: rgba(var(--panel-rgb), .9);
  opacity: 0; transition: opacity .16s ease, color .16s ease, border-color .16s ease;
}
.hb-row.ai:hover .hb-copy { opacity: 1; }
.hb-copy:hover { color: var(--fg-strong); border-color: rgba(var(--accent-rgb), .5); }
/* ???????????????????????? */
.hb-copy-row { display: flex; justify-content: flex-end; margin-top: 2px; }
.hb-copy {
  position: static; opacity: 1;
  padding: 3px 10px; border-radius: 999px; cursor: pointer;
  font-size: 11px; color: var(--sub);
  border: 1px solid var(--border); background: rgba(var(--panel-rgb), .9);
  transition: color .16s ease, border-color .16s ease;
}
.hb-copy:hover { color: var(--fg-strong); border-color: rgba(var(--accent-rgb), .5); }
/* ???? Pointer????????? */
.hb-card, .hb-card *, .hb-icard, .hb-icard * { cursor: pointer; user-select: none; -webkit-user-select: none; }
.hb-cards-title { font-size: 11.5px; color: var(--sub); margin: 8px 0 2px; }
/* ?????????SVG? */
.hb-ai { display: inline-flex; align-items: center; gap: 6px; }
.hb-ai svg { width: 15px; height: 15px; fill: currentColor; flex: none; }
/* Toast ?????????????? + ?????????????????? */
.toast {
  background: rgba(24, 24, 28, .95) !important;
  color: #fff !important;
  border: 1px solid rgba(255, 255, 255, .14);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
}
.toast.warn {
  background: rgba(126, 26, 34, .96) !important;
  border-color: rgba(255, 130, 140, .55);
  color: #fff !important;
}
.toast.ok, .toast.success {
  background: rgba(20, 84, 52, .96) !important;
  border-color: rgba(90, 220, 150, .5);
  color: #fff !important;
}
/* ?? Beta ?? */
.beta-tag {
  display: inline-block; margin-left: 8px; vertical-align: 4px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-style: normal; font-weight: 700; letter-spacing: .3px;
  color: var(--accent); border: 1px solid rgba(var(--accent-rgb), .55);
  background: rgba(var(--accent-rgb), .12);
}
/* ============================================================
 * Altcha ?????UI ??????? PoW ???
 * ============================================================ */
.auth-captcha { margin: 12px 0 4px; }
.auth-captcha altcha-widget {
  --altcha-border-width: 1px;
  --altcha-border-radius: 12px;
  --altcha-color-base: var(--panel);
  --altcha-color-base-content: var(--text);
  --altcha-color-text: var(--text);
  --altcha-color-border: var(--border);
  --altcha-color-border-focus: rgba(var(--accent-rgb), .65);
  --altcha-color-primary: var(--accent);
  --altcha-color-primary-content: #fff;
  --altcha-color-error-text: #ff8a90;
  --altcha-max-width: 100%;
  display: block;
  font-size: 13px;
}
.auth-captcha altcha-widget::part(main) { background: var(--panel2); }
/* ????????????????????? */
/* Altcha ??????????????? margin-bottom: 10px? */
.auth-captcha { margin: 0 0 10px; }
.auth-captcha altcha-widget { min-height: 44px; }
/* ??????????????? */
.btn.danger { background: rgba(220, 38, 46, .16); border-color: rgba(220, 38, 46, .55); color: #ff8a90; }
.btn.danger:hover { background: rgba(220, 38, 46, .28); border-color: #e0343f; color: #fff; }
.set-acc-foot { display: flex; gap: 10px; flex-wrap: wrap; }
.set-acc-note { margin-top: 8px; font-size: 12px; color: var(--sub); line-height: 1.6; }
/* ?????????? */
.set-del-row { display: flex; gap: 10px; align-items: center; margin-top: 10px; flex-wrap: wrap; }
.set-del-row .auth-input { flex: 1; min-width: 220px; max-width: 320px; margin-bottom: 0; }
/* AI ??????????? */
.set-ai-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 10px; }
.set-ai-card { border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; background: rgba(var(--fg-rgb), .03); }
.set-ai-card.active { border-color: rgba(var(--accent-rgb), .6); background: rgba(var(--accent-rgb), .07); }
.set-ai-head { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.set-ai-name { font-size: 13.5px; font-weight: 600; color: var(--fg-strong); flex: 1; }
.set-ai-tag { font-size: 11px; color: var(--sub); border: 1px solid var(--border); border-radius: 999px; padding: 1px 8px; }
.set-ai-card.active .set-ai-tag { color: var(--accent); border-color: rgba(var(--accent-rgb), .55); }
.set-ai-fields { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.set-ai-fields .auth-input { margin-bottom: 0; }
/* AI ??????????????????????????????????? */
.set-ai-card .set-btns { display: flex; justify-content: flex-end; margin-top: 8px; gap: 8px; }
.set-ai-card .set-btns .mini-btn { padding: 5px 14px; }
.set-ai-fields { gap: 8px; }
/* AI ????????/?? */
.set-ai-head { position: relative; }
.set-ai-sum { font-size: 12px; color: var(--sub); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.set-ai-toggle {
  border: 1px solid var(--border); background: transparent; color: var(--sub);
  font-size: 11.5px; padding: 2px 10px; border-radius: 999px; cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.set-ai-toggle:hover { color: var(--fg-strong); border-color: rgba(var(--accent-rgb), .5); }
.set-ai-card:not(.open) .set-ai-fields,
.set-ai-card:not(.open) .set-btns { display: none; }
.set-ai-card:not(.open) { padding-bottom: 10px; }
.set-ai-card .set-ai-fields { animation: hbFadeIn .22s ease both; }
/* ???????3 ? ? 2 ???? 6 ?????????? */
.hb-cards.hb-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  margin-top: 10px;
}
.hb-grid .hb-icard {
  display: flex; flex-direction: column; align-items: stretch;
  gap: 8px; padding: 10px; border-radius: 12px; margin: 0;
}
.hb-grid .hb-icard img { width: 100%; height: auto; aspect-ratio: 1 / 1; border-radius: 9px; object-fit: cover; }
.hb-grid .hb-icard-tx { min-width: 0; }
.hb-grid .hb-icard-name { font-size: 13px; }
.hb-grid .hb-icard-sub { font-size: 11.5px; }
.hb-grid .hb-icard-play { position: absolute; right: 10px; bottom: 10px; }
.hb-grid .hb-icard { position: relative; }
@media (max-width: 720px) {
  .hb-cards.hb-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* ???????????????????? */
.hb-icard, .hb-icard *, .hb-card, .hb-card *, .hb-cards, .hb-cards * {
  cursor: pointer !important;
  user-select: none !important;
  -webkit-user-select: none !important;
}
/* ???????????? I ??? */
.hb-icard-name, .hb-icard-sub { cursor: pointer !important; }
/* ????????? 2 ????????? */
@media (max-width: 720px) {
  .hb-cards.hb-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}
@media (max-width: 460px) {
  .hb-cards.hb-grid { grid-template-columns: minmax(0, 1fr) !important; }
}
/* ????????????????????????????? */
/* ?????????? JS ????????????? */

/* HiBetter ???????????????? 100vh ???????????? */
body:has(.hb-wrap) #main { min-height: 0 !important; }
body:has(.hb-wrap) #view { min-height: 0 !important; }
body:has(.hb-wrap) { min-height: 0 !important; }
/* ?????????????? */
/* ????????????????????????????????? */

/* ?????????????????????????????????????? */
.hb-chat > * { flex: none; }

/* ===== HiBetter @ È	ùÝFká0“e
¹…¹4• ===== */
.hb-wrap { max-width: 700px; margin: 0 auto; min-height: 0; padding-bottom: 0; display: flex; flex-direction: column; }
.hb-chat {
  display: flex; flex-direction: column; justify-content: flex-end;
  overflow-y: auto; padding: 6px 4px 6px; gap: 12px;
}
.hb-chat > * { flex: none; }
.hb-chat .hb-empty { margin: auto 0; }   /* zE->:
4• */
body:has(.hb-wrap) #main, body:has(.hb-wrap) #view { min-height: 0; }
/* ????????????????????????? */
#hb-msgs.hb-chat {
  display: flex !important;
  flex-direction: column !important;
  justify-content: flex-end !important;
  overflow-y: auto !important;
}
#hb-msgs.hb-chat > * { flex: 0 0 auto !important; }
#hb-msgs.hb-chat > *:first-child { margin-top: auto !important; }
#hb-msgs.hb-chat .hb-empty { margin: auto 0 !important; }
/* ???????????????/??? .hb-wrap ??? */
/* ???????????????? 32px?? #view ? padding ??? */
@media (max-width: 900px) {
}
@media (max-width: 600px) {
}
/* ?? HiBetter ??????? + ??????? */
body:has(.hb-wrap) #view { padding-bottom: 0 !important; }
body:has(.hb-wrap) #main { padding-bottom: 0 !important; }
.hb-chat { margin-top: auto !important; }

/* ===== HiBetter “e ÈÄ/ C	===== */
.hb-bar {
  position: fixed; left: calc(var(--side-offset) + 32px); right: 32px; bottom: 24px;
  z-index: 70; margin: 0 auto; max-width: 700px; padding: 10px 12px;
  border-radius: 14px; border: 1px solid var(--border);
  background: rgba(var(--panel-rgb), .92);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  transition: bottom .25s ease;
  display: flex; gap: 10px; align-items: center;
}
body:has(#playerbar:not(.hidden)) .hb-bar {
  bottom: calc(var(--bar-h) + 13px);
  border-radius: 18px 18px 12px 12px;
  background: rgba(var(--panel-rgb), .78);
}
@media (max-width: 900px) { .hb-bar { left: 16px; right: 16px; } }
@media (max-width: 600px) { .hb-bar { left: 12px; right: 12px; } }
/* ????????????????????????????? */
body:has(.hb-wrap) { overscroll-behavior: contain; }

/* ============================================================
 * ???????????????????????????????
 *   --ease   ?????easeOut??????
 *   --t-fast ???????/??/???
 *   --t-mid  ????/????
 *   --t-slow ??????????
 * ============================================================ */
:root {
  --ease: cubic-bezier(.22, .61, .36, 1);
  --t-fast: .18s;
  --t-mid: .28s;
  --t-slow: .32s;
}

/* 1) ???????????????? transform/opacity/???????? */
button, .btn, .mini-btn, .icon-btn, .nav-item, .set-menu-row, .view-back,
.set-quality button, .set-themes .theme-card, .set-opt, .chip,
.song-row, .list-row, .card, .mp-card, .pl-card, .dt-row,
input, select, textarea, a, .side-item, .search-item {
  transition:
    transform var(--t-fast) var(--ease),
    opacity var(--t-fast) var(--ease),
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    box-shadow var(--t-fast) var(--ease);
}

/* 2) v165c: hover must NOT move the control (no lift). Feedback is colour only
 * (background / text / border). Pressing still scales slightly - see rule 3. */

/* 3) ????????????? 0.98? */
.btn:active, .mini-btn:active, .icon-btn:active, .view-back:active,
.nav-item:active, .set-menu-row:active, .set-quality button:active,
.theme-card:active, .mp-card:active, .song-row:active {
  transform: translateY(0) scale(.98);
}

/* 4) ?? / ??????"????" */
.modal-panel, .set-page:not(.hidden) {
  animation: uni-pop var(--t-mid) var(--ease) both;
}
@keyframes uni-pop {
  from { opacity: 0; transform: translateY(10px) scale(.992); }
  to   { opacity: 1; transform: none; }
}

/* 5) ?????????? */
.song-row, .list-row, .mp-card, .pl-card, .search-item {
  animation: uni-in var(--t-mid) var(--ease) both;
}
@keyframes uni-in {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: none; }
}

/* 6) ???????????????? */
.set-quality button.active, .theme-card.active, .set-opt.active {
  animation: uni-sel var(--t-mid) var(--ease);
}
@keyframes uni-sel {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.045); }
  100% { transform: scale(1); }
}

/* 7) ?????????/????????????????? */
/* ê©¹h§C Z;˜Ç!hy/aG
ÂMLUIC ubb;˜öa */
html, body, #app, #view, .side, #topbar, .modal-panel {
  transition: background-color var(--t-slow) var(--ease), color var(--t-slow) var(--ease),
              border-color var(--t-slow) var(--ease);
}

/* 8) ???????????? svg? */
.btn svg, .mini-btn svg, .icon-btn svg, .nav-item svg {
  transition: transform var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.btn:hover svg, .icon-btn:hover svg { transform: scale(1.06); }

/* ===== ?????????????????????? ===== */
#topbar { position: fixed; }
/* ===== v68: transparent topbar + capsule title + round back button + sticky slide-in ===== */
#topbar {
  left: 0; right: 0; max-width: none; margin: 0;
  height: 70px;
  padding-left: calc(var(--side-offset) + 9px);
  background: transparent !important;
  backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
  border-bottom: none !important;
  overflow: visible;
  z-index: 70 !important;
  pointer-events: none;
}
#topbar > * { pointer-events: auto; }

/* goo layer: sits just under the topbar so the real controls stay crisp on top */
#topbar-goo {
  position: fixed;
  pointer-events: none; z-index: 65;
  filter: url(#goo-filter);
  -webkit-filter: url(#goo-filter);
}
#topbar-goo .goo-blob {
  position: absolute; display: block;
  border-radius: 999px;
  background: rgba(var(--panel-rgb), .92);
  will-change: transform;
  transition: transform .32s cubic-bezier(.3, 1.4, .5, 1), width .32s cubic-bezier(.3, 1.4, .5, 1);
}

/* page title: capsule, 20px type, 4px below the bar centre line */
#page-title {
  font-size: 20px;
  letter-spacing: -.2px;
  padding: 8px 18px;
  border-radius: 999px;
  background: rgba(var(--panel-rgb), .92);
  border: 1px solid var(--border);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
  position: relative;
  top: 4px;
  transition: background-color var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
              color var(--t-mid) var(--ease), box-shadow var(--t-mid) var(--ease),
              transform var(--t-fast) var(--ease);
}

/* back button: big round icon, same fill as the capsule (seamless merge) */
#topbar .topbar-back {
  width: 44px; height: 44px; padding: 0; gap: 0; flex: none;
  border-radius: 50%; justify-content: center;
  background: rgba(var(--panel-rgb), .92);
  position: relative;
  top: 4px;
  transform: none;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
  transition: max-width .28s var(--ease), opacity .22s var(--ease), padding .28s var(--ease),
              margin .28s var(--ease), border-color var(--t-mid) var(--ease),
              background-color var(--t-mid) var(--ease), color var(--t-mid) var(--ease),
              box-shadow var(--t-mid) var(--ease), transform var(--t-fast) var(--ease);
}
#topbar .topbar-back span { display: none; }
#topbar .topbar-back svg { width: 22px; height: 22px; transition: fill var(--t-fast) var(--ease); }

/* hover: pure zoom (no vertical shift), press: shrink back */
#topbar .topbar-back:hover, #page-title:hover {
  transform: scale(1.045);
  box-shadow: 0 10px 24px rgba(0, 0, 0, .22);
}
#topbar .topbar-back:active, #page-title:active {
  transform: scale(.97);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .14);
}

@media (max-width: 900px) {
  #topbar { padding-left: 8px; }
  #page-title { font-size: 17px; padding: 7px 15px; }
  #topbar .topbar-back { width: 40px; height: 40px; }
  #topbar .topbar-back svg { width: 20px; height: 20px; }
}

/* ===== v69: motion blur while the controls travel + lock for the back button ===== */
@keyframes gooMotionBlur {
  /* full blur on the very first frame: the label swaps in the same frame,
     otherwise the new text pops in sharp before the blur ramps up */
  0%, 30% { filter: blur(var(--mb, 6px)); }
  100% { filter: blur(0px); }
}
/* ¨;ô»ÓÔÞ	®ê«„6w¨;Mn1�B# */
#topbar.goo-lock .topbar-back { transition: none !important; }
/* only the LABEL blurs, never the pill itself: a filter on the element would blur its
   background, border and shadow too, which made the whole control look out of focus. */
#topbar.goo-lock #page-title .tb-text {
  display: inline-block;
  --mb: 4px;
  animation: gooMotionBlur .32s var(--ease) both;
}
#topbar.goo-lock .topbar-back svg {
  --mb: 3px;
  animation: gooMotionBlur .32s var(--ease) both;
}
/* ===== v72: modal enter/leave animation (mask + panel, blur assisted) ===== */
.modal-mask { animation: modalMaskIn .3s var(--ease) both; }
.modal-panel { animation: modalPanelIn .38s var(--ease) both; }
.modal.closing { pointer-events: none; }
.modal.closing .modal-mask { animation: modalMaskOut .28s var(--ease) both; }
.modal.closing .modal-panel { animation: modalPanelOut .3s var(--ease) both; }
@keyframes modalMaskIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes modalPanelIn {
  from { opacity: 0; transform: translateY(22px) scale(.955); filter: blur(10px); }
  55%  { filter: blur(0px); }
  to   { opacity: 1; transform: translateY(0) scale(1); filter: blur(0px); }
}
@keyframes modalMaskOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}
@keyframes modalPanelOut {
  from { opacity: 1; transform: translateY(0) scale(1); filter: blur(0px); }
  to   { opacity: 0; transform: translateY(16px) scale(.965); filter: blur(6px); }
}

/* ===== v73: settings level-2 page: sticky round back button + title capsule ===== */
.set-page-head {
  position: sticky; top: -24px; z-index: 6; /* µˆb padding-topÚ¨ö4Ob…v */
  display: flex; align-items: center; gap: 10px;
  margin: 0 -28px 18px; padding: 12px 28px 12px;
  background: rgba(var(--panel-rgb), .97);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
/* {®½…¹Ú
»
l */
.set-page-head::after {
  content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 14px;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(var(--panel-rgb), .92), rgba(var(--panel-rgb), 0));
}
.set-page-head .view-back {
  width: 40px; height: 40px; padding: 0; flex: none;
  border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: rgba(var(--panel-rgb), .92); border: 1px solid var(--border);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
  position: relative; top: 0; transform: none; margin: 0;
  transition: background-color var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
              box-shadow var(--t-mid) var(--ease), transform var(--t-fast) var(--ease);
}
.set-page-head .view-back span { display: none; }
.set-page-head .view-back svg { width: 20px; height: 20px; fill: var(--sub); transition: fill var(--t-fast) var(--ease); }
.set-page-head .view-back:hover { transform: scale(1.045); box-shadow: 0 10px 24px rgba(0, 0, 0, .22); }
.set-page-head .view-back:hover svg { fill: var(--accent); }
.set-page-head .view-back:active { transform: scale(.97); box-shadow: 0 4px 12px rgba(0, 0, 0, .14); }
.set-page-title {
  font-size: 20px; font-weight: 700; letter-spacing: -.2px; color: var(--fg-strong);
  background: rgba(var(--panel-rgb), .92); border: 1px solid var(--border);
  border-radius: 999px; padding: 8px 18px; white-space: nowrap;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
}
/* ˜ònv�Ïc‡Ì„
˜MÍ
 */
.set-page .set-head { display: none; }
@media (max-width: 560px) {
  .set-page-head { margin: 0 -18px 14px; padding: 10px 18px; top: -20px; }
  .set-page-title { font-size: 17px; padding: 7px 15px; }
  .set-page-head .view-back { width: 36px; height: 36px; }
  .set-page-head .view-back svg { width: 18px; height: 18px; }
}

/* ===== v74: modal head = capsule title + round close button, pinned ===== */
.modal-head {
  position: sticky; top: -24px; z-index: 7;
  margin: 0 -28px 18px; padding: 12px 28px;
  background: rgba(var(--panel-rgb), .97);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
.modal-head::after {
  content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 14px;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(var(--panel-rgb), .92), rgba(var(--panel-rgb), 0));
}
/* ˜ ’ öÊv / Œ§u˜ W7	 */
.modal-head > span:first-child {
  font-size: 20px; font-weight: 700; letter-spacing: -.2px;
  background: rgba(var(--panel-rgb), .92); border: 1px solid var(--border);
  border-radius: 999px; padding: 8px 18px; white-space: nowrap;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
}
/* sí	® ’ bþ	®ÔÞ. W7	 */
.modal-head .icon-btn {
  width: 40px; height: 40px; flex: none;
  background: rgba(var(--panel-rgb), .92); border: 1px solid var(--border);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
  transition: background-color var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
              box-shadow var(--t-mid) var(--ease), transform var(--t-fast) var(--ease), color var(--t-mid) var(--ease);
}
.modal-head .icon-btn svg { width: 18px; height: 18px; }
.modal-head .icon-btn:hover { transform: scale(1.045); box-shadow: 0 10px 24px rgba(0, 0, 0, .22); color: var(--fg-strong); }
.modal-head .icon-btn:active { transform: scale(.97); box-shadow: 0 4px 12px rgba(0, 0, 0, .14); }
/* Œ§uövè˜©MŒ§uêñ	˜öÊ	MÍ
 */
#settings:has(.set-page:not(.hidden)) .modal-head > span:first-child { visibility: hidden; }
/* Œ§u„ÔÞ'4(vè˜b */
#settings { --modal-head-h: 70px; }
#settings .set-page-head { top: calc(var(--modal-head-h, 70px) - 24px); }
@media (max-width: 560px) {
  .modal-head { margin: 0 -18px 16px; padding: 10px 18px; }
  .modal-head > span:first-child { font-size: 17px; padding: 7px 15px; }
  .modal-head .icon-btn { width: 36px; height: 36px; }
  #settings { --modal-head-h: 56px; }
  #settings .set-page-head { top: calc(var(--modal-head-h, 56px) - 20px); }
}

/* ===== v75: settings modal  fixed head row, only the body scrolls ===== */
#settings .modal-panel {
  display: flex; flex-direction: column;
  overflow: hidden !important;
  padding: 0 !important;
}
#settings .modal-head {
  position: static; top: auto;
  flex: none;
  margin: 0;
  padding: 18px 28px 14px;
  background: rgba(var(--panel-rgb), .97);
  border-bottom: 1px solid var(--border);
}
#settings .modal-head::after { display: none; }
#settings .modal-body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 16px 28px 24px;
}
#set-page-main { padding-top: 0; }
/* Œ§uövè˜
`MÙ L
�YzÒP */
#settings:has(.set-page:not(.hidden)) .modal-head > span:first-child { display: none; }
/* ˜�Ïsí.ÍY(ó§ */
#settings:has(.set-page:not(.hidden)) .modal-head { justify-content: flex-end; }
/* Œ§uÔÞ8(…¹:vè8Ü
«Úp */
#settings .set-page-head { top: 0; }
@media (max-width: 560px) {
  #settings .modal-head { padding: 14px 18px 12px; }
  #settings .modal-body { padding: 14px 18px 20px; }
}

/* ===== v76: settings head  back + title + close in ONE row ===== */
#settings .modal-head { justify-content: flex-start; gap: 10px; }
#settings .modal-head .modal-title {
  font-size: 20px; font-weight: 700; letter-spacing: -.2px; color: var(--fg-strong);
  background: rgba(var(--panel-rgb), .92); border: 1px solid var(--border);
  border-radius: 999px; padding: 8px 18px; white-space: nowrap;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
  overflow: hidden;
}
/* sí.úš¨0  */
#settings .modal-head .icon-btn[data-close] { margin-left: auto; }
#settings .modal-head .set-back.hidden { display: none !important; }
/* ç„Œ§uìË˜
� � */
.set-page .set-page-head { display: none !important; }
/* Œ§uvè
� �Y}e */
#settings .set-page-head { top: 0; }
@media (max-width: 560px) {
  #settings .modal-head .modal-title { font-size: 17px; padding: 7px 15px; }
}

/* ===== v77: settings modal reuses the goo slide (layer inside the panel) ===== */
/* 4è‹(�BK
b¶ÎbÑÇ‡WÝp */
#settings .modal-head { position: relative; z-index: 2; }
#set-goo {
  pointer-events: none;
  z-index: 1;
  filter: url(#goo-filter);
  -webkit-filter: url(#goo-filter);
}
#set-goo .goo-blob {
  position: absolute; display: block;
  border-radius: 999px;
  background: rgba(var(--panel-rgb), .92);
  will-change: transform;
  transition: transform .32s cubic-bezier(.3, 1.4, .5, 1), width .32s cubic-bezier(.3, 1.4, .5, 1);
}
/* Ð¨ô„Ø¯!Ê˜öÊ + ÔÞ. */
#settings .modal-head.goo-lock .modal-title .mt-text {
  display: inline-block;
  --mb: 4px;
  animation: gooMotionBlur .32s var(--ease) both;
}
#settings .modal-head.goo-lock .set-back svg {
  --mb: 3px;
  animation: gooMotionBlur .32s var(--ease) both;
}
/* ===== v87: only the page canvas fades (150ms); all surfaces switch in one frame ===== */
/* fading the modal panel too made its content look washed out mid-fade (the content
   had already switched while its background was still travelling). So: the canvas
   (page background + inherited text colour) crossfades, every surface - panel, sidebar,
   topbar, cards, buttons - lands in the same frame. */
html.theme-switching,
html.theme-switching body,
html.theme-switching #app,
html.theme-switching #app *,
html.theme-switching #view,
html.theme-switching .side,
html.theme-switching #topbar {
  transition: none !important;
}
/* canvas fade: background + the text colour inherited from it */
html.theme-switching,
html.theme-switching body {
  transition: background-color .15s linear, color .15s linear !important;
}
/* modal panel: same frame, but keep its height morph */
html.theme-switching #app .modal-panel,
html.theme-switching .modal-panel {
  transition-property: height !important;
  transition-duration: .36s !important;
}

/* ===== v88: notice panel layout -- content up, button down, radii aligned ===== */
/* less gap under the head row so the version list starts higher */
/* drop the panel top padding and let the head row carry it, so the top inset
   equals the side inset (28px) - every corner then reads as concentric */
.notice-panel { padding-top: 0; }
.notice-panel .modal-head { margin-bottom: 10px; padding-top: 28px; }
/* no extra top padding, more room at the bottom */
.notice-panel .modal-body { padding: 0 0 4px; }
/* gap above the confirm button pushes it to the bottom of the panel */
.notice-panel .modal-body > .btn { margin-top: 18px; }
/* radii follow the panel (20px) - inner boxes one step in, button keeps the
   same language as every other button in the app */
.notice-panel .notice-ver-item { border-radius: 12px; }
.notice-panel .notice-side { border-right: none; padding-right: 0; }
.notice-panel .notice-main { padding-right: 8px; }

/* ===== v91: feathered clip on the notice text column ===== */
/* the scroll box fades its own edges; the fade only appears on a side that can
   actually still scroll (classes toggled from JS), so the first line stays crisp
   while the panel sits at the top */
.notice-panel .notice-main {
  --nf-top: 0px;
  --nf-bottom: 0px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--nf-top), #000 calc(100% - var(--nf-bottom)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--nf-top), #000 calc(100% - var(--nf-bottom)), transparent 100%);
}
.notice-panel .notice-main.fade-top { --nf-top: 18px; }
.notice-panel .notice-main.fade-bottom { --nf-bottom: 26px; }

/* ===== v98: auth email verification code row ===== */
.auth-code-row { display: flex; gap: 8px; align-items: stretch; }
.auth-code-row .auth-input { flex: 1; min-width: 0; margin-bottom: 10px; }
.auth-code-btn {
  flex: none; white-space: nowrap; padding: 0 16px; margin-bottom: 10px;
  font-size: 13px; font-weight: 600; border-radius: 12px;
  background: var(--panel2); color: var(--text); border: 1px solid var(--border);
}
.auth-code-btn:hover:not(:disabled) { background: var(--panel); border-color: rgba(var(--accent-rgb), .45); }
.auth-code-btn:disabled { opacity: .55; cursor: default; }
@media (max-width: 420px) {
  .auth-code-row { flex-direction: column; }
  .auth-code-btn { width: 100%; margin-bottom: 10px; }
}

/* ===== v99: narrow-screen (mobile) polish =====
 * 1) drawer open: sidebar floats above everything, topbar fades out (it used to
 *    overlap the sidebar brand row and the page-title capsule)
 * 2) drawer geometry: tighter insets, mobile close button, safe-area aware
 * 3) general phone polish: paddings, card sizes, tap targets, bottom spacing
 */
@media (max-width: 900px) {
  #topbar { transition: opacity .22s ease, transform .22s ease; }
  #sidebar {
    top: 12px; left: 12px; bottom: 12px;
    width: min(280px, 78vw);
    border-radius: 20px;
    z-index: 80;
    padding-top: 6px;
    padding-bottom: max(10px, env(safe-area-inset-bottom));
  }
  #sidebar .side-logo { padding: 16px 54px 12px 18px; position: relative; }
  #side-close {
    display: grid; position: absolute; top: 14px; right: 12px;
    width: 34px; height: 34px; border-radius: 50%;
    place-items: center; cursor: pointer;
    background: rgba(var(--fg-rgb), .06); border: 1px solid var(--border);
    color: var(--sub); transition: background .2s ease, color .2s ease, transform .2s ease;
  }
  #side-close:hover { background: rgba(var(--fg-rgb), .12); color: var(--fg-strong); }
  #side-close:active { transform: scale(.94); }
  #side-close svg { width: 16px; height: 16px; fill: currentColor; }
  #sidebar .side-user, #sidebar .side-foot { padding-left: 16px; padding-right: 16px; }
  #sidebar .side-ver { padding-bottom: 6px; }
  #side-mask { z-index: 70; }
}
@media (min-width: 901px) { #side-close { display: none !important; } }

@media (max-width: 700px) {
  /* vöÊ˜ÔÞ.(„Oô'ÑE-ùP */
  #topbar { padding: 0 12px; gap: 10px; }
  #page-title { font-size: 19px; padding: 7px 16px; }
  .topbar-back { height: 40px; padding: 0 14px 0 10px; font-size: 13px; }
  .topbar-back svg { width: 18px; height: 18px; }
  #btn-menu { width: 40px; height: 40px; }
  /* …¹:•èÙ­>Y³zôM  L«ÖO */
  #view { padding: 16px 14px 26px; }
  #view-bottom-space { height: 116px; }
  /* æÅub˜„„OÔ‹ */
  .dt-cover { width: 152px; height: 152px; border-radius: 16px; }
  .dt-name { font-size: 20px; }
  .dt-actions { gap: 8px; }
  .dt-actions .btn { padding: 9px 16px; font-size: 13px; }
  /* LU/‘aGK:
) ¹ Oý0ô */
  .pl-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 12px; }
  .pl-card .pl-name { font-size: 13.5px; }
  .pl-card .pl-sub { font-size: 11.5px; }
  /* hLæ§Ø¦þ:ø */
  .song-row { padding: 8px 10px; }
  .song-row .sr-index { width: 26px; }
  /* ­>4•Ò‰h: */
  #playerbar { left: 8px; right: 8px; bottom: max(8px, env(safe-area-inset-bottom)); padding: 0 10px; border-radius: 20px; }
  .pb-title { font-size: 13.5px; }
  .pb-artist { font-size: 11.5px; }
}

@media (max-width: 420px) {
  #page-title { font-size: 18px; padding: 6px 14px; }
  #view { padding: 14px 12px 24px; }
  .pl-grid { gap: 12px 10px; }
  .banner { height: 148px; }
}

/* ===== v100: auth code row -> input with inline send button =====
 * ÑŒÁ	®9:…L(ŒÁ“eFó§`MôB§ôZ	
 * ¡ö¶ê¨Ø„Sp6
�ú°tL'	®
 */
.auth-code-row { position: relative; margin-bottom: 10px; }
.auth-code-row .auth-input { margin-bottom: 0; padding-right: 118px; }
.auth-code-btn {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: auto; height: 34px; padding: 0 13px; margin: 0;
  border-radius: 10px; font-size: 12.5px; font-weight: 700; letter-spacing: .2px;
  white-space: nowrap; cursor: pointer;
  border: 1px solid rgba(var(--accent-rgb), .5);
  background: rgba(var(--accent-rgb), .16);
  color: var(--accent);
  transition: background .18s ease, color .18s ease, box-shadow .18s ease, opacity .18s ease;
}
.auth-code-btn:hover:not(:disabled) {
  background: rgba(var(--accent-rgb), .3); color: #fff;
  box-shadow: 0 4px 14px rgba(var(--accent-rgb), .3);
}
.auth-code-btn:active:not(:disabled) { transform: translateY(-50%) scale(.96); }
.auth-code-btn:disabled {
  opacity: .6; cursor: default;
  border-color: var(--border); background: var(--panel2); color: var(--sub);
  box-shadow: none;
}
@media (max-width: 460px) {
  .auth-code-row .auth-input { padding-right: 108px; font-size: 13.5px; }
  .auth-code-btn { height: 32px; padding: 0 11px; font-size: 12px; border-radius: 9px; }
}
@media (max-width: 360px) {
  .auth-code-row .auth-input { padding-right: 96px; }
  .auth-code-btn { padding: 0 9px; font-size: 11.5px; }
}

/* ===== v101: auth code button centering (fix sticky-hover on touch) =====
 * ( .btn:hover Š transform 9 translateY(-1px)CÍ 0,2,0	
 * †Ö‰,	®„ translateY(-50%)K:¹ Y˜Þ hover 	®1‰»
 * ÙÌ(CÍFô`„ÄŠƒ‰OveP hover/active/focus 
 */
.auth-code-row .auth-code-btn,
.auth-code-row .auth-code-btn:hover,
.auth-code-row .auth-code-btn:focus,
.auth-code-row .auth-code-btn:focus-visible,
.auth-code-row .auth-code-btn:disabled {
  transform: translateY(-50%);
}
.auth-code-row .auth-code-btn:active:not(:disabled) {
  transform: translateY(-50%) scale(.96);
}
@media (hover: none) {
  .auth-code-row .auth-code-btn:hover:not(:disabled) {
    background: rgba(var(--accent-rgb), .16);
    color: var(--accent);
    box-shadow: none;
  }
}

/* ===== v102: drawer shadow only when open =====
 * K:ï§6wö/ translateX(-100% - 32px)F box-shadow ß@C  w
 * ;úe+24px Oû +70px !Ê	Ž/OU æ§‹Y a—rØ
 * 4q9ê( .open öú°vß@Ñ¨ wÇ!
 */
@media (max-width: 900px) {
  #sidebar {
    box-shadow: none;
    transition: transform .3s var(--ease), box-shadow .3s var(--ease);
  }
  #sidebar.open { box-shadow: 24px 0 70px rgba(0, 0, 0, .55); }
}

/* ===== v103: mobile sidebar as centered popup =====
 * K:ï
�Îæ§Ñú½I9E-„nBÙ…9—Î< ô	
 * )> + áeÛúÒ/•qPØ…èÚ¨ni¹ûsí
 */
@media (max-width: 900px) {
  #sidebar {
    top: 50%; left: 50%; right: auto; bottom: auto;
    width: min(340px, 88vw);
    max-height: min(78vh, 640px);
    border-radius: 22px;
    z-index: 80;
    padding: 0 0 max(10px, env(safe-area-inset-bottom));
    transform: translate(-50%, -50%) scale(.94);
    opacity: 0; visibility: hidden; pointer-events: none;
    box-shadow: none;
    transition: transform .26s var(--ease), opacity .2s ease, visibility .2s ease, box-shadow .26s var(--ease);
  }
  #sidebar.open {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1; visibility: visible; pointer-events: auto;
    box-shadow: 0 24px 70px rgba(0, 0, 0, .55);
  }
  /* 9—…:WÚ¨¤Ù6ÏhvYúš */
  #sidebar .side-logo { padding: 16px 54px 12px 20px; }
  #sidebar .side-nav { flex: none; }
  #sidebar .side-favs { flex: 1 1 auto; min-height: 60px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  /* nBS öOubÚ¨MÌ„…¹ß@¨ */
  body.drawer-open { overflow: hidden; }
}

/* ===== v104: bigger menu button (mobile) =====
 * v 0 /K:ï/ „ü*eãŸe 40px O>'0 48pxþ 22px
 * vtSû 3px öÊ˜„ÆÉ-¿ùP( position: relative + top
 * MŒ hover „ transform S¶	
 */
@media (max-width: 900px) {
  #btn-menu {
    width: 48px; height: 48px;
    position: relative; top: 3px;
    border-radius: 15px;
  }
  #btn-menu svg { width: 24px; height: 24px; }
}
@media (max-width: 700px) {
  #btn-menu { width: 46px; height: 46px; top: 3px; }
  #btn-menu svg { width: 23px; height: 23px; }
}

/* ===== v105: menu button keeps still =====
 * (Ä .icon-btn:hover/.icon-btn:active  translateY(-1.5px) 
n
 * v 0 /úšeãn¨>—–¨ÙÌŠƒ‰O3px „Oû( top ž°
×qÍ	
 */
#btn-menu,
#btn-menu:hover,
#btn-menu:active,
#btn-menu:focus,
#btn-menu:focus-visible { transform: none; }
#btn-menu svg, #btn-menu:hover svg { transform: none; }

/* ===== v106: side-close matches modal close =====
 * K:ïnBÌ„  Ÿe/êñ Wp•7ßÙ…9—ó
Ò„sí	®
 ô
 * ÙÌô¥ùP .modal-head .icon-btn „Ä<40px bpanel •Ï¹ + •q
 * hover >' 1.045 / 	 0.97	„O 560px å: 36px
 */
#side-close {
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  position: absolute; top: 14px; right: 12px;
  background: rgba(var(--panel-rgb), .92);
  border: 1px solid var(--border);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
  color: var(--sub);
  transition: background-color var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
              box-shadow var(--t-mid) var(--ease), transform var(--t-fast) var(--ease), color var(--t-mid) var(--ease);
}
#side-close svg { width: 18px; height: 18px; fill: currentColor; }
#side-close:hover { transform: scale(1.045); box-shadow: 0 10px 24px rgba(0, 0, 0, .22); color: var(--fg-strong); }
#side-close:active { transform: scale(.97); box-shadow: 0 4px 12px rgba(0, 0, 0, .14); }
@media (max-width: 560px) { #side-close { width: 36px; height: 36px; } }

/* ===== v107: close button same interaction + menu 2px lower ===== */
#side-close:hover { background: var(--panel2); }
#side-close:hover, #side-close:focus { transform: scale(1.045); }
#side-close:active { transform: scale(.97); }
#side-close:hover svg, #side-close:active svg { transform: none; }
@media (max-width: 900px) { #btn-menu { top: 5px; } }
@media (max-width: 700px) { #btn-menu { top: 5px; } }

/* ===== v108: menu button capsule background ===== */
@media (max-width: 900px) {
  #btn-menu {
    background: rgba(var(--panel-rgb), .92);
    border: 1px solid var(--border);
    border-radius: 999px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .16);
    transition: background-color var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
                color var(--t-mid) var(--ease), box-shadow var(--t-mid) var(--ease);
  }
  /* keep the fill identical on hover/press, only the shadow reacts (no movement) */
  #btn-menu:hover {
    background: rgba(var(--panel-rgb), .92);
    box-shadow: 0 10px 24px rgba(0, 0, 0, .22);
    color: var(--fg-strong);
  }
  #btn-menu:active {
    background: rgba(var(--panel-rgb), .92);
    box-shadow: 0 4px 12px rgba(0, 0, 0, .14);
    color: var(--fg-strong);
  }
}

/* ===== v109: bigger mobile sidebar card + card nav ===== */
@media (max-width: 900px) {
  #sidebar {
    width: min(424px, 92vw);
    max-height: min(88vh, 820px);
    border-radius: 26px;
  }
  #sidebar .side-logo { padding: 18px 60px 14px 20px; }

  /* nav items become 2-column cards: bigger tap targets, less vertical space */
  #sidebar .side-nav {
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
    padding: 4px 16px 2px;
  }
  #sidebar .side-nav .nav-item {
    display: flex; align-items: center; gap: 10px;
    padding: 14px 14px; border-radius: 14px;
    font-size: 14.5px; font-weight: 600;
    background: rgba(var(--fg-rgb), .045);
    border: 1px solid var(--border);
  }
  #sidebar .side-nav .nav-item svg { width: 20px; height: 20px; }
  #sidebar .side-nav .nav-item.active {
    background: var(--accent-soft);
    border-color: rgba(var(--accent-rgb), .45);
    color: var(--accent);
  }

  /* saved playlists: rows untouched, only a taller visible area */
  #sidebar .side-title { padding: 16px 20px 6px; }
  #sidebar .side-pls { flex: 1 1 auto; min-height: 208px; padding: 0 12px 10px; }

  /* footer buttons: card-sized too */
  #sidebar .side-footer { padding: 12px 16px 4px; }
  #sidebar .side-auth-btn { padding: 12px 0; border-radius: 14px; font-size: 14px; }
  #sidebar .side-btn { padding: 13px 14px; border-radius: 14px; font-size: 14.5px; }
}

/* ===== v110: bottom tab bar (mobile) ===== */
#tabbar { display: none; }
@media (max-width: 900px) {
  #tabbar {
    display: flex; position: fixed; z-index: 58;
    left: 8px; right: 8px; bottom: max(8px, env(safe-area-inset-bottom));
    height: 58px; padding: 4px; gap: 2px;
    background: rgba(var(--panel-rgb), .92);
    backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px);
    border: 1px solid var(--border); border-radius: 18px;
    box-shadow: 0 12px 34px rgba(0, 0, 0, .38);
  }
  .tab-item {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
    border-radius: 14px; color: var(--sub); text-decoration: none;
    font-size: 10.5px; font-weight: 600; letter-spacing: .2px;
    transition: color .18s var(--ease), background-color .18s var(--ease);
  }
  .tab-item svg { width: 21px; height: 21px; fill: currentColor; opacity: .9; }
  .tab-item em { font-style: normal; line-height: 1.1; }
  .tab-item.active { color: var(--accent); background: var(--accent-soft); }
  .tab-item.active svg { opacity: 1; }

  /* ­>
û0ÜUK
 */
  #playerbar { bottom: calc(max(8px, env(safe-area-inset-bottom)) + 66px); }
  /* …¹•èöÙ­> + ÜUYzô */
  #view-bottom-space { height: 150px; }

  /* ÜUòÅü*nBÌ
�Í
ü*_
>:6Ï„LU */
  #sidebar .side-nav,
  #sidebar .side-title,
  #sidebar #side-playlists { display: none; }
}

/* ===== v111: sliding tab indicator ===== */
@media (max-width: 900px) {
  #tabbar { position: fixed; }
  .tab-ind {
    position: absolute; top: 4px; bottom: 4px; left: 0; width: 0;
    border-radius: 14px; background: var(--accent-soft);
    transition: transform .3s cubic-bezier(.32, 1.28, .48, 1), width .3s cubic-bezier(.32, 1.28, .48, 1);
    pointer-events: none; z-index: 0;
  }
  .tab-ind.instant { transition: none; }
  .tab-item { position: relative; z-index: 1; background: transparent; }
  .tab-item.active { background: transparent; }
}

/* ===== v112: hide page scrollbar (scrolling still works) =====
 * Only the page-level scrollbar is hidden; inner scroll areas such as the saved
 * playlist list, modal bodies and lyrics keep their own thin scrollbar.
 */
html, body { scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar,
body::-webkit-scrollbar { width: 0 !important; height: 0 !important; display: none !important; }

/* ===== v113: no sidebar flash on breakpoint change =====
 * Applied for a couple of frames from JS while the viewport crosses 900px.
 */
#sidebar.side-noanim, #sidebar.side-noanim.open { transition: none !important; }

/* ===== v114: popup entrance animation (no transition on the base state) =====
 * KM #sidebar „ opacity/visibility /"Ç!"q¨„Î½O0„Oö
 * ’Såâ ûl1 Ë 0.2s áúŽ/0§ê �ˆ1
 * °(�Ï
ZûUÇ!¬ö	e:9( keyframes ¨;  ê	  .open M­
 */
@media (max-width: 900px) {
  #sidebar, #sidebar.open {
    transition: none;
    animation: none;
  }
  #sidebar.open { animation: sidePopupIn .24s var(--ease) both; }
}
@keyframes sidePopupIn {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.94); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* ===== v115: menu button on the right + entrance / exit animations =====
 * 1) mobile: hamburger moves to the far right of the topbar (title stays left)
 * 2) tab bar + hamburger animate in on load; opening the menu sheet plays
 *    the tab bar out and gives the hamburger a small pulse.
 */
@media (max-width: 900px) {
  #btn-menu { order: 20; margin-left: auto; }
  #tabbar { animation: tabbarIn .36s var(--ease); }
  #btn-menu { animation: menuIn .32s var(--ease); }
}
@keyframes tabbarIn {
  from { opacity: 0; transform: translateY(130%); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes menuIn {
  from { opacity: 0; transform: translateX(12px) scale(.86); }
  to { opacity: 1; transform: translateX(0) scale(1); }
}

/* ===== v115b: align menu button with tabbar ===== */
@media (max-width: 900px) { #topbar { padding-right: 8px; } }

/* ===== v120: share sheet (in-app first) ===== */
#share .share-panel { width: min(420px, 92vw); }
.share-card {
  display: flex; align-items: center; gap: 14px;
  padding: 14px; border-radius: 16px;
  background: var(--panel2); border: 1px solid var(--border);
}
.share-cover { width: 62px; height: 62px; border-radius: 12px; flex: none; object-fit: cover; box-shadow: 0 6px 18px rgba(0,0,0,.28); }
.share-meta { min-width: 0; flex: 1; }
.share-name {
  font-size: 14.5px; font-weight: 700; color: var(--fg-strong); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.share-url {
  margin-top: 5px; font-size: 12px; color: var(--sub);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  user-select: text; -webkit-user-select: text;
}
.share-acts { display: flex; gap: 10px; margin-top: 16px; }
.share-act {
  flex: 1; padding: 12px 10px; border-radius: 14px; cursor: pointer;
  border: 1px solid var(--border); background: var(--panel2); color: var(--text);
  font-size: 13.5px; font-weight: 600; transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.share-act:hover { border-color: rgba(var(--accent-rgb), .45); color: var(--accent); }
.share-act.primary { background: var(--accent); border-color: transparent; color: var(--fg-strong); }
.share-act.primary:hover { color: var(--fg-strong); opacity: .9; }
@media (max-width: 460px) {
  /* Å«9—;	®b0 
¹vtLúá w,b
×qÍ	 */
  .share-panel .share-acts { flex-wrap: wrap; }
  .share-panel .share-acts .share-act { flex: 1 1 100%; }
  .share-panel .share-acts .share-act.primary { order: -1; }
}

/* ===== v121: share panel insets =====
 * Align the four sides: same 28px inset for the head, the card and the bottom.
 * The head no longer adds its own vertical padding, so the whole block sits higher.
 */
#share .modal-panel { padding: 26px 28px 28px; }
#share .modal-head {
  margin: 0 -28px 14px;
  padding: 0 28px;
  min-height: 44px;
  align-items: center;
}
#share .modal-body { padding: 0; }
#share .modal-head > span { font-size: 18px; padding: 8px 18px; }
#share .share-card { padding: 13px; }

/* ===== v122: share head without band =====
 * .modal-head is a sticky bar with a solid background, a bottom border and a
 * fading ::after strip (built for the scrolling settings modal). On the share
 * sheet that band cut straight through the capsule / close-button shadows.
 * The share panel does not scroll, so drop the band entirely.
 */
#share .modal-panel { overflow: visible; }
#share .modal-head {
  position: static; top: auto; z-index: auto;
  background: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  border-bottom: 0;
}
#share .modal-head::after { display: none; }

/* ===== v123: logout pill in the mobile sheet =====
 * v109 gave every .side-auth-btn a horizontal padding of 0 (fine for the
 * full-width login/register pair), which squashed the standalone logout
 * button into an oval with the label sticking out. Give it a proper pill.
 */
@media (max-width: 900px) {
  #sidebar .side-user { gap: 10px; }
  #sidebar .side-user .side-auth-btn {
    flex: none; padding: 9px 16px; border-radius: 999px;
    font-size: 13px; font-weight: 600; line-height: 1.2;
    color: var(--accent); border-color: rgba(var(--accent-rgb), .45);
  }
  #sidebar .side-user .side-auth-btn:hover {
    background: var(--accent-soft); color: var(--accent);
  }
}

/* ===== v128: listen together + developer welcome ===== */
#listen .lt-panel { width: min(460px, 94vw); }
#listen .modal-body { padding: 0; }
.lt-tip { margin: 0 0 14px; font-size: 13px; color: var(--sub); line-height: 1.6; }
.lt-btn { width: 100%; }
.lt-or {
  display: flex; align-items: center; gap: 10px; margin: 16px 0 12px;
  color: var(--sub); font-size: 12px;
}
.lt-or::before, .lt-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.lt-join-row { display: flex; gap: 10px; align-items: center; }
.lt-code-input {
  flex: 1; text-align: center; letter-spacing: 6px; font-weight: 700;
  font-size: 18px; text-transform: uppercase;
}
.lt-invite {
  padding: 16px; border-radius: 16px; text-align: center;
  background: var(--panel2); border: 1px solid var(--border);
}
.lt-invite-label { font-size: 12px; color: var(--sub); margin-bottom: 8px; }
.lt-code {
  font-size: 30px; font-weight: 800; letter-spacing: 8px;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.lt-link {
  margin-top: 8px; font-size: 12px; color: var(--sub);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: text;
}
.lt-acts { display: flex; gap: 10px; margin-top: 14px; }
.lt-acts .share-act { flex: 1; }
.lt-status { margin-top: 16px; }
.lt-song { font-size: 14.5px; font-weight: 700; color: var(--fg-strong); line-height: 1.45; }
.lt-meta { margin-top: 5px; font-size: 12px; color: var(--sub); }
.lt-members { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.lt-member {
  padding: 5px 11px; border-radius: 999px; font-size: 12px;
  background: var(--panel2); border: 1px solid var(--border); color: var(--sub);
}
.lt-member.host { color: var(--accent); border-color: rgba(var(--accent-rgb), .45); }
.lt-chat {
  margin-top: 16px; padding: 12px; height: 190px; overflow-y: auto;
  border-radius: 14px; background: var(--panel2); border: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 10px;
}
.lt-chat-empty { color: var(--sub); font-size: 12.5px; text-align: center; margin: auto; }
.lt-msg { max-width: 86%; }
.lt-msg.mine { align-self: flex-end; text-align: right; }
.lt-msg-head { display: flex; gap: 8px; align-items: baseline; font-size: 11.5px; color: var(--sub); }
.lt-msg.mine .lt-msg-head { justify-content: flex-end; }
.lt-msg-name { font-weight: 600; }
.lt-msg-text {
  margin-top: 3px; padding: 8px 12px; border-radius: 12px; font-size: 13.5px; line-height: 1.5;
  background: var(--panel); color: var(--text); word-break: break-word; text-align: left;
}
.lt-msg.mine .lt-msg-text { background: var(--accent-soft); color: var(--fg-strong); }
.lt-input { display: flex; gap: 10px; margin-top: 12px; align-items: center; }
.lt-input .auth-input { flex: 1; }
.lt-input .share-act { flex: none; padding: 11px 18px; }
.lt-leave { margin-top: 12px; width: 100%; color: var(--accent); }
.share-act.lt-entry { width: 100%; margin-top: 10px; }

#devwelcome .dev-panel { width: min(400px, 92vw); text-align: center; }
.dev-hi { margin: 6px 0 4px; font-size: 17px; font-weight: 700; color: var(--fg-strong); }
.dev-uid { margin: 10px 0 6px; font-size: 13.5px; color: var(--sub); }
.dev-uid b { color: var(--accent); font-size: 16px; letter-spacing: .5px; }
.dev-tip { margin: 10px 0 16px; font-size: 12.5px; color: var(--sub); line-height: 1.6; }

@media (max-width: 560px) {
  .lt-code { font-size: 26px; letter-spacing: 6px; }
  .lt-chat { height: 160px; }
}

/* ===== v129: listen panel fits its contents =====
 * The chat box was a fixed 190px and the body did not scroll, so the "leave"
 * button was pushed ~41px below the panel. The panel is now a flex column
 * with a scrolling body and a height-aware chat box.
 */
#listen .lt-panel {
  width: min(460px, 94vw);
  max-height: min(88vh, 700px);
  display: flex; flex-direction: column;
}
#listen .modal-head { flex: none; }
#listen .modal-body { padding: 0; overflow-y: auto; min-height: 0; }
.lt-chat { height: 150px; flex: none; }
.lt-leave { margin-bottom: 2px; }
@media (max-height: 760px) { .lt-chat { height: 118px; } }
@media (max-height: 680px) { .lt-chat { height: 92px; } }

/* ===== v130: scope share-act mobile rules to the share panel =====
 * The v120 narrow-screen block applied "order:-1" to every .share-act.primary,
 * which also reordered the listen-together chat send button to the left of its
 * input. Those rules are only meant for the share sheet, so scope them there.
 */
@media (max-width: 460px) {
  #listen .share-acts { flex-wrap: nowrap; }
  #listen .share-act,
  #listen .share-act.primary { order: 0; flex: 1 1 0; }
  #listen .lt-input .share-act { flex: none; }
}

/* ===== v131: local account button (local deployment only) ===== */
.auth-local { margin-top: 10px; width: 100%; }
.auth-local-tip {
  margin: 8px 0 0; font-size: 12px; line-height: 1.6; color: var(--sub);
  text-align: center;
}

/* ===== v132: listen panel tidy + player entry =====
 * 1) every control in the sheet is one height (44px) and one rhythm
 * 2) chat / input / leave only exist inside a room
 * 3) listen-together entry in the full-screen player top bar
 */
#listen .lt-panel { padding: 24px 24px 24px; }
#listen .modal-head { margin: 0 -24px 14px; padding: 0 24px; }
#listen .modal-body { padding: 0; }
#listen .lt-panel { --lt-h: 44px; }

/* ß „§öØ¦Ò */
#listen .auth-input,
#listen .lt-btn,
#listen .lt-input .share-act,
#listen .lt-join-row .share-act,
#listen .lt-leave {
  height: var(--lt-h); border-radius: 12px; font-size: 13.5px;
  box-sizing: border-box; margin: 0;
}
#listen .auth-input { padding: 0 14px; line-height: 1; }
#listen .lt-code-input { letter-spacing: 5px; font-size: 16px; font-weight: 700; }
#listen .lt-btn { width: 100%; display: flex; align-items: center; justify-content: center; }
#listen .lt-join-row { display: flex; gap: 10px; align-items: center; }
#listen .lt-join-row .auth-input { flex: 1; min-width: 0; }
#listen .lt-join-row .share-act { flex: none; width: 96px; padding: 0; display: flex; align-items: center; justify-content: center; }

/* ‚O@	WKôß  12px */
#listen .lt-tip { margin: 0 0 12px; font-size: 12.5px; line-height: 1.65; }
#listen .lt-or { margin: 12px 0; }
#listen .lt-invite { padding: 16px; }
#listen .lt-invite-label { margin-bottom: 6px; }
#listen .lt-code { font-size: 28px; letter-spacing: 7px; line-height: 1.25; }
#listen .lt-link { margin-top: 6px; }
#listen .lt-acts { margin-top: 12px; gap: 10px; }
#listen .lt-acts .share-act { height: var(--lt-h); border-radius: 12px; padding: 0; display: flex; align-items: center; justify-content: center; }
#listen .lt-status { margin-top: 12px; }
#listen .lt-song { font-size: 14px; }
#listen .lt-meta { margin-top: 4px; }
#listen .lt-members { margin-top: 10px; gap: 6px; }

/* J):	®½…¹Ý6' */
#listen .lt-room-only { margin-top: 12px; }
#listen .lt-chat {
  margin-top: 0; padding: 10px 12px; height: 148px; border-radius: 12px; gap: 8px;
}
#listen .lt-msg-text { padding: 7px 11px; border-radius: 10px; font-size: 13px; }
#listen .lt-input { margin-top: 10px; gap: 10px; }
#listen .lt-input .auth-input { flex: 1; min-width: 0; }
#listen .lt-input .share-act { flex: none; width: 72px; padding: 0; display: flex; align-items: center; justify-content: center; }
#listen .lt-leave {
  margin-top: 10px; width: 100%; background: transparent; border: 1px solid var(--border);
  color: var(--accent); font-weight: 600; display: flex; align-items: center; justify-content: center;
}
#listen .lt-leave:hover { background: var(--accent-soft); border-color: rgba(var(--accent-rgb), .45); }

/* ­>uv w,eãsí. ’`óv’	 */
.ov-top { justify-content: flex-end; gap: 12px; }
.ov-listen { position: relative; }
.ov-listen svg { width: 20px; height: 20px; }
.ov-listen-badge {
  position: absolute; top: -4px; right: -4px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: var(--accent); color: var(--fg-strong);
  font-size: 10.5px; font-weight: 700; line-height: 17px; text-align: center;
}

/* ===== v133: player top bar alignment + badge inside =====
 * The count badge stuck 4px outside the round button and could be clipped on
 * short viewports; both top-bar buttons now share one icon size and baseline.
 */
.ov-top { align-items: center; }
.ov-top .icon-btn,
.ov-listen,
.ov-close { width: 34px; height: 34px; flex: none; }
.ov-top .icon-btn svg,
.ov-listen svg,
.ov-close svg { width: 20px; height: 20px; }
.ov-listen-badge {
  top: 0; right: 0; min-width: 15px; height: 15px; padding: 0 3px;
  font-size: 10px; line-height: 15px; border: 1.5px solid var(--bg);
}

/* ===== v134: listen sheet - head band, avatars, bubbles, collapsible invite =====
 * 1) drop the sticky head band (it cut through the capsule / close-button shadows)
 * 2) avatars in the member chips and chat
 * 3) own messages right, others left
 * 4) invite block collapses from its header
 */
#listen .modal-panel { overflow: visible; }
#listen .modal-head {
  position: static; top: auto; z-index: auto;
  background: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  border-bottom: 0;
}
#listen .modal-head::after { display: none; }

/* ãäW˜à4 */
.lt-invite { padding: 0; overflow: hidden; }
.lt-invite-head {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 12px 16px; background: none; border: 0; cursor: pointer;
  color: var(--sub); font-size: 12.5px; font-weight: 600;
}
.lt-invite-head:hover { color: var(--text); }
.lt-chev { width: 15px; height: 15px; fill: currentColor; transition: transform .22s var(--ease); }
.lt-invite.collapsed .lt-chev { transform: rotate(-90deg); }
.lt-invite-body { padding: 0 16px 16px; }
.lt-invite.collapsed .lt-invite-body { display: none; }
.lt-invite-label { display: none; }

/* X~&4Ï */
.lt-member { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px 4px 4px; }
.lt-m-av,
.lt-av {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  background: var(--bg3) center/cover no-repeat; color: var(--sub);
  font-size: 11px; font-style: normal; font-weight: 700; line-height: 22px; text-align: center;
  overflow: hidden;
}
.lt-member.host .lt-m-av { box-shadow: 0 0 0 1.5px rgba(var(--accent-rgb), .55); }

/* J)á+ºæ(óG&4Ï */
.lt-msg { display: flex; align-items: flex-start; gap: 8px; max-width: 100%; }
.lt-msg .lt-av { width: 26px; height: 26px; line-height: 26px; font-size: 12px; margin-top: 2px; }
.lt-msg-body { min-width: 0; max-width: 82%; }
.lt-msg.other { align-self: flex-start; }
.lt-msg.mine { align-self: flex-end; flex-direction: row-reverse; }
.lt-msg.mine .lt-msg-body { text-align: right; }
.lt-msg.mine .lt-msg-head { justify-content: flex-end; }
.lt-msg-text { display: inline-block; max-width: 100%; }

/* ===== v135: listen room view - live info, progress bar, tabs ===== */
#listen .lt-room { display: block; }
.lt-now {
  padding: 12px 14px; border-radius: 14px;
  background: var(--panel2); border: 1px solid var(--border);
}
.lt-now-line { display: flex; align-items: baseline; gap: 10px; }
.lt-now-line .lt-song { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lt-count {
  flex: none; font-size: 11.5px; font-weight: 700; color: var(--accent);
  padding: 2px 8px; border-radius: 999px; background: var(--accent-soft);
}
.lt-progress { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.lt-time { font-size: 11px; color: var(--sub); font-variant-numeric: tabular-nums; flex: none; min-width: 34px; }
.lt-progress input[type="range"] {
  flex: 1; min-width: 0; height: 4px; appearance: none; -webkit-appearance: none;
  border-radius: 999px; background: rgba(var(--fg-rgb), .16); outline: none; cursor: pointer;
}
.lt-progress input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 12px; height: 12px; border-radius: 50%;
  background: var(--accent); border: 0; box-shadow: 0 2px 6px rgba(0,0,0,.35);
}
.lt-progress input[type="range"]::-moz-range-thumb {
  width: 12px; height: 12px; border: 0; border-radius: 50%; background: var(--accent);
}
.lt-now .lt-members { margin-top: 10px; }

/* €÷ / J) $*buÂlJ„H,h7	 */
.lt-tabs {
  display: flex; gap: 6px; margin: 12px 0 10px; padding: 4px;
  background: var(--panel2); border: 1px solid var(--border); border-radius: 12px;
}
.lt-tab {
  flex: 1; height: 34px; border: 0; border-radius: 9px; cursor: pointer;
  background: none; color: var(--sub); font-size: 13px; font-weight: 600;
  transition: background .18s var(--ease), color .18s var(--ease);
}
.lt-tab:hover { color: var(--text); }
.lt-tab.active { background: var(--accent); color: var(--fg-strong); }
.lt-pane { min-height: 0; }
.lt-invite-tip { margin: 12px 0 0; font-size: 12px; line-height: 1.6; color: var(--sub); text-align: center; }
.lt-invite { padding: 14px 16px; }

/* ­>uX0„ ú w,?ô
	® */
.ov-leave-room {
  height: 34px; padding: 0 14px; border-radius: 999px; cursor: pointer; flex: none;
  background: var(--accent-soft); border: 1px solid rgba(var(--accent-rgb), .45);
  color: var(--accent); font-size: 13px; font-weight: 700;
}
.ov-leave-room:hover { background: var(--accent); color: var(--fg-strong); }

/* ===== v136: listen - left side tabs (like the notice dialog) ===== */
.lt-main { display: flex; gap: 12px; align-items: stretch; }
.lt-side {
  flex: none; width: 104px; display: flex; flex-direction: column; gap: 6px;
}
.lt-side .lt-tab {
  height: 44px; border: 1px solid var(--border); border-radius: 12px; cursor: pointer;
  background: var(--panel2); color: var(--sub);
  font-size: 13px; font-weight: 600; letter-spacing: .2px;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.lt-side .lt-tab:hover { color: var(--text); background: var(--panel); }
.lt-side .lt-tab.active {
  background: var(--accent); border-color: transparent; color: var(--fg-strong);
}
.lt-content { flex: 1; min-width: 0; }
.lt-content .lt-invite { height: 100%; }
.lt-content .lt-chat { height: 176px; }

@media (max-width: 520px) {
  .lt-side { width: 82px; }
  .lt-side .lt-tab { height: 40px; font-size: 12.5px; }
  .lt-content .lt-chat { height: 138px; }
}

/* ç„*u~7\ŸÝY{
|¹	 */
.lt-tabs { all: unset; }

/* ===== v137: listen - three compact left tabs, even spacing, fixed panel =====
 * panel: fixed 480x500 while in a room (was auto 460x485)
 * tabs: compact 34px pills, 88px column, uniform 10px gaps
 */
#listen .lt-panel.in-room { width: min(480px, 94vw); height: min(500px, 88vh); }
#listen .modal-body { display: flex; flex-direction: column; }
#listen .lt-room { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#listen .lt-main { flex: 1; min-height: 0; display: flex; gap: 10px; align-items: stretch; }
#listen .lt-side { all: unset; display: flex; flex-direction: column; gap: 8px; flex: none; width: 88px; }
#listen .lt-side .lt-tab {
  height: 34px; padding: 0 4px; border: 1px solid var(--border); border-radius: 10px; cursor: pointer;
  background: var(--panel2); color: var(--sub); font-size: 12.5px; font-weight: 600;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
#listen .lt-side .lt-tab:hover { color: var(--text); background: var(--panel); }
#listen .lt-side .lt-tab.active { background: var(--accent); border-color: transparent; color: var(--fg-strong); }
#listen .lt-content { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
#listen .lt-pane { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#listen .lt-pane .lt-invite { flex: 1; display: flex; flex-direction: column; justify-content: center; }
#listen .lt-pane .lt-chat { flex: 1; min-height: 0; height: auto; }
#listen .lt-now { flex: 1; display: flex; flex-direction: column; justify-content: center; }
#listen .lt-now .lt-members { margin-top: 10px; }

/* IÝáoW / ;: / •è	® ß  10px */
#listen .lt-room { gap: 10px; }
#listen .lt-invite { padding: 14px; }
#listen .lt-leave { margin-top: 0; }
#listen .lt-input { margin-top: 10px; }

@media (max-width: 520px) {
  #listen .lt-side { width: 74px; }
  #listen .lt-side .lt-tab { height: 32px; font-size: 12px; }
}

/* ===== v137b: body fills the fixed panel height ===== */
#listen .lt-panel.in-room .modal-body { flex: 1; min-height: 0; }
#listen .lt-panel.in-room .lt-room { height: 100%; }

/* ===== v137c: left tabs must not grow (v135 left flex:1 on them) ===== */
#listen .lt-side .lt-tab { flex: none; width: 100%; }

/* ===== v137d: room pane content top aligned ===== */
#listen .lt-now { justify-content: flex-start; }
#listen .lt-pane .lt-invite { justify-content: flex-start; }

/* ===== v138 / v144: keep spaces in karaoke words, but never block wrapping =====
 * v138: a word span holding a single space collapsed to zero width, so spaces inside
 *       the line vanished while playing; white-space: pre preserved them.
 * v144: pre also forbids breaking INSIDE that span, so when a lyric source hands us a
 *       whole phrase as one word (or the column is narrow), the row cannot wrap: it is
 *       clipped by the lyrics box, and breaks only land on span edges (e.g. "Hey" alone
 *       on a row). pre-wrap keeps the spaces AND lets the browser wrap normally.
 */
.ly-line.active .ly-w,
#overlay[data-karaoke] .ly-w { white-space: pre-wrap; }

/* ===== v139: bottom bar dissolves into the player =====
 * Entering the player: the bar content (cover / title / buttons) blurs out while the
 * bar background cross-fades into the player background, so the expanding window
 * reveals a player whose backdrop already matches. Leaving plays it backwards.
 */
#playerbar {
  transition: background-color .5s var(--ease), border-color .5s var(--ease),
    border-radius .5s var(--ease), box-shadow .5s var(--ease);
}
#playerbar > * {
  transition: filter .42s var(--ease), opacity .42s var(--ease);
}
#playerbar.morph-out {
  background-color: #101014;
  border-color: transparent;
  /* v163: keep the real radius while morphing (it is invisible then, but the
     morph animations read it to land with matching corners) */
  box-shadow: none;
}
#playerbar.morph-out > * { filter: blur(9px); opacity: 0; }

/* ===== v140: bar controls dissolve into the player (final) =====
 * Enter: every control inside the bar blurs and scales UP until it disappears,
 *        while the bar background fades away so the player background shows through.
 *        The bar is lifted above the player during the morph so it can dissolve on top.
 * Leave: background fades back in, controls come down from blurred/large to sharp.
 */
#playerbar {
  transition: background-color .55s var(--ease), border-color .55s var(--ease),
    border-radius .45s var(--ease), box-shadow .5s var(--ease), backdrop-filter .55s var(--ease),
    -webkit-backdrop-filter .55s var(--ease);
}
#playerbar > * {
  transition: filter .46s var(--ease), opacity .46s var(--ease), transform .46s var(--ease);
  transform-origin: 50% 50%;
}
#playerbar.morph-out {
  z-index: 120;               /* Ç!ôn(­>uK
Mý"¶ã"‰ */
  background-color: transparent;
  backdrop-filter: blur(0); -webkit-backdrop-filter: blur(0);
  border-color: transparent;
  /* v163: keep the real radius while morphing (it is invisible then, but the
     morph animations read it to land with matching corners) */
  box-shadow: none;
}
#playerbar.morph-out > * {
  filter: blur(10px);
  opacity: 0;
  transform: scale(1.55);     /* >'ó�Ï */
}

/* ===== v141: reverse dissolve runs WITH the collapse =====
 * The z-index lift lives in its own class (.morph-top) so the bar can stay above the
 * player page while the collapse animation plays. On close the bar drops .morph-out
 * immediately: its background fades back in and its controls shrink from blurred back
 * to sharp in parallel with the shrinking window (a true mirror of the enter).
 */
#playerbar.morph-top { z-index: 120; }
#playerbar.morph-out { pointer-events: none; }

/* ===== v142: the bar paints NO background while the player page is on screen =====
 * The player page grows out of the bar rect and later shrinks back into it, so the
 * bar own background is always exactly covered by the player display range: while the
 * page is up the bar shows the player background itself. Previously the panel colour
 * faded out over .55s (slower than the controls .46s), so in light themes a lighter
 * white strip lingered on top of the dark player page. Now background / backdrop /
 * border switch off instantly in the morph states, and fade back in only after the
 * player page is gone (the class is dropped when the collapse finishes).
 */
/* v143: the plate fills the WHOLE bar box and cross-fades with the player background.
 * Enter: panel colour -> player colour (so the plate melts into the player page instead of
 *        lingering as a lighter strip), still eased, never snapped.
 * Open : plate colour == player background, so the box reads as part of the player page.
 * Leave: .morph-top only keeps the stacking order, so dropping .morph-out on close lets the
 *        plate ease back to the panel colour WHILE the page retracts (gradual show).
 */
#playerbar.morph-out {
  background-color: var(--player-bg, #101014);
  background-image: none;
  backdrop-filter: blur(0); -webkit-backdrop-filter: blur(0);
  border-color: transparent;
  /* v163: keep the real radius while morphing (it is invisible then, but the
     morph animations read it to land with matching corners) */
  box-shadow: none;
  transition: background-color .5s var(--ease), border-color .5s var(--ease),
    border-radius .45s var(--ease), box-shadow .5s var(--ease),
    backdrop-filter .5s var(--ease), -webkit-backdrop-filter .5s var(--ease);
}
#playerbar.morph-top { z-index: 120; }

/* ===== v142b: the bar concave-corner pseudo elements stay light too =====
 * They are painted by body:has(.hb-bar) #playerbar::before / ::after and are not
 * children, so the dissolve rules above never touched them. Hide them while the
 * player page is on screen (same reason as v142).
 */
#playerbar.morph-out::before,
#playerbar.morph-out::after,
#playerbar.morph-top::before,
#playerbar.morph-top::after { opacity: 0; }

/* ===== v145: the bar background becomes the growing player plate =====
 * While morphing, the BAR paints no background at all. The plate look comes from the
 * player page itself: its background starts as the bar panel colour (same rgba + radius
 * footprint comes from the clip window, which starts exactly on the bar box), then
 * cross-fades into the player background as the window grows to the full screen.
 * So the background really does fill the screen and fade away, and nothing is left
 * sitting at the bottom as a darker strip. Closing plays the same thing backwards.
 */
/* v149: BOTH directions keep a single object: the bar paints no plate of its own while
 * morphing (enter AND exit), so what you see is only the one growing/shrinking plate.
 * The plate carries the live shadow and picks up the frosted backdrop near the end of the
 * exit, so handing over to the real bar plate at landing is seamless. */
#playerbar.morph-out,
#playerbar.morph-top {
  background-color: transparent;
  background-image: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  border-color: transparent;
  /* v162: border-radius is deliberately NOT reset here. The plate is transparent while
   * morphing, so the radius is invisible anyway, but keeping the real value lets the
   * morph animations read the bar true radius (30 / 24 / 20px by breakpoint) and land
   * with matching corners on every screen size. */
  box-shadow: none;
  transition: none;      /* do not fade the plate itself, or a colour band appears */
}

/* ===== v146: morph on composited properties instead of clip-path =====
 * clip-path repaints the whole screen (blurred backdrop included) every frame, so the
 * animation stalled at the start and then snapped - the harsh exit. Now the player page
 * is scaled/translated from the bar rect (composited) while its background cross-fades
 * and its content fades in late, which keeps the whole move smooth.
 */
#overlay { transform-origin: 50% 50%; }
#ov-bg { transition: background-image .6s, opacity .28s var(--ease); }
#overlay .ov-fill { transition: opacity .28s var(--ease); }
#overlay.ov-morph-hidden .ov-fill { opacity: 0; }
#overlay.ov-morph-instant .ov-fill { transition: none; }
/* while morphing the container is full-screen but the plate is not: keep clicks reaching
 * whatever is visible (the content layer keeps its own pointer-events) */
#overlay.ov-morphing { pointer-events: none; }
#overlay.ov-morphing .ov-fill { pointer-events: auto; }

/* v146b: hint the compositor while the morph runs (dropped again on settle) */
/* v148: the plate animates its real box + radius + colours (no scaling), so the corner
 * radius is never stretched by a non-uniform transform. */
/* v164: the morph animates THIS childless plate instead of #overlay.
 * #overlay is the ancestor of the whole player page (#ov-fill holds every lyric node) and of
 * #ov-bg (a 90px blurred cover that rescales when its box changes). Animating the container made
 * every frame invalidate that whole subtree: style recalc + a full layout + image re-decode.
 * The plate is an empty box on purpose - one element to restyle, no subtree to touch. */
#ov-plate {
  position: absolute; inset: 0; background: var(--player-bg, #101014);
  pointer-events: none; z-index: 0;
  overflow: hidden; /* clips the content layer to the growing plate (was #overlay) */
}
/* v164b: no will-change here. The animated properties (top/left/width/height/border-radius/
 * background-color) cannot be composited, so hinting only made the compositor re-run layerization
 * on every frame (measured ~4ms per frame in Layerize). The plate is cheap to repaint on its own. */

/* v152: the player content lives in .ov-fill, whose size is pinned to the viewport, so
 * animating the plate box never re-lays it out. The old visibility / content-visibility
 * tricks are gone: the content is hidden only by opacity (driven by the morph timeline
 * itself), which keeps it a composited change and lets it appear early enough that the
 * screen is never a blank dark plate ("black flash"). */
#overlay.ov-morph-hidden #ov-fill { opacity: 0; }

/* ===== v151: pin the player content to the viewport =====
 * .ov-fill is the single child of #overlay and is laid out at 100vw x 100vh, so animating
 * the overlay plate box (top/left/width/height) no longer re-lays-out the player page at
 * all - that per-frame re-layout was what stuttered at the end of the enter. The content
 * just fades in/out on the compositor (opacity), and because its layout never changes,
 * the reveal costs nothing either.
 */
#ov-fill {
  position: absolute; top: 0; left: 0;
  width: 100vw; height: 100vh;
  /* v164d: the plate above is pointer-events:none (it is only the background). The content
   * layer must re-enable events, otherwise every control on the player page inherits none. */
  pointer-events: auto;
  /* v164c: layout/paint containment. The plate (its parent, the animated box) changes size every
   * frame; without this the whole player subtree was re-laid-out and re-matched on every frame.
   * The fill own size is viewport-based, so containment changes nothing visually. */
  contain: layout paint;
  display: flex; flex-direction: column;
  transition: opacity .2s var(--ease);
}
#overlay.ov-morph-hidden #ov-fill { opacity: 0; }
#overlay.ov-fade-out #ov-fill { opacity: 0; }

/* ===== v154: top grabber instead of the X button, listen button in the toolbar =====
 * The grabber sits centred at the top: tap closes the player page, press-and-drag drives
 * the exit animation with the finger (the timeline is seeked, not restarted).
 */
.ov-grab {
  position: absolute; left: 50%; top: 3px; transform: translateX(-50%);
  width: 132px; height: 34px; padding: 0; border: 0; background: transparent;
  display: flex; align-items: center; justify-content: center;
  cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none;
}
.ov-grab i {
  display: block; width: 52px; height: 5px; border-radius: 3px;
  background: rgba(var(--fg-rgb), .42);
  transition: background .18s var(--ease), width .18s var(--ease);
}
.ov-grab:hover i { background: rgba(var(--fg-rgb), .72); width: 62px; }
.ov-grab.on i { background: rgba(var(--fg-rgb), .85); width: 66px; }
.ov-grab:active { cursor: grabbing; }
.ly-toolbar .ov-listen { width: 32px; height: 32px; flex: none; }
.ly-toolbar .ov-listen svg { width: 17px; height: 17px; }

/* ===== v157: the bar controls come back LATE during the exit =====
 * When closing, .morph-top only carries the stacking order; the children used to start
 * un-blurring immediately, so the mini player looked restored while the plate was still
 * large. Now they start restoring at ~40% of the 520ms collapse and finish with it.
 * (While dragging with the grabber the same values are driven directly by the finger.)
 */
#playerbar.morph-top > * {
  transition-duration: .26s;
  transition-delay: .22s;
}

/* ===== v160: the player bar paints IN FRONT OF the sidebar =====
 * The bar was z-index 55 while the sidebar is 60, so the sidebar covered the bar
 * wherever they overlapped. The bar is now 65: above the sidebar (60), still below the
 * player page (100) and every modal / drawer, so nothing else about the morph changes.
 */
#playerbar { z-index: 65; }

/* ===== v161: on narrow screens the listen tabs move BELOW the content =====
 * The room panel used to keep the 88px tab column on the left, which squeezes the room
 * pane on phones. Below 560px the layout stacks: content first, the three tabs become a
 * full-width row at the bottom.
 */
@media (max-width: 560px) {
  #listen .lt-main { flex-direction: column; gap: 8px; }
  #listen .lt-content { order: 1; flex: 1 1 auto; min-height: 0; }
  #listen .lt-side { order: 2; flex-direction: row; width: 100%; gap: 8px; }
  #listen .lt-side .lt-tab { flex: 1 1 0; width: auto; height: 34px; padding: 0 6px; }
  #listen .lt-pane .lt-chat { height: auto; }
}

/* ===== v164: on narrow screens the bottom nav paints IN FRONT OF the player bar =====
 * The bar is 65 on wide screens (above the sidebar at 60). Below 900px the tab bar (58)
 * is the bottom-most chrome, so the bar drops to 57 there: the nav now covers the bar and
 * its shadow instead of the other way round. During the player page morph the bar still
 * jumps to 120 (#playerbar.morph-out / .morph-top is more specific), so the plate keeps
 * covering the nav while the page opens and closes.
 */
@media (max-width: 900px) {
  #playerbar { z-index: 57; }
}

/* ===== v165: the two bottom controls stop shading EACH OTHER =====
 * The bar sits 8px above the nav, so its 44px shadow reached 26px into the nav and the
 * nav 34px shadow reached ~5px up onto the bar: measured on a 631px viewport that made
 * the nav top ~1.8 levels darker and the bar bottom ~4.6 levels darker than they are
 * without the other shadow. Both shadows are now clipped so they only fall on what is
 * NOT one of the two controls: the bar keeps a bottom shadow inside the 8px gap, the nav
 * keeps its shadow below itself (which still darkens the page behind, as before).
 * --bar-shadow is the single source of truth, also read by _barShadow() in app.js so the
 * morph animation lands with exactly the resting shadow.
 */
#playerbar {
  --bar-shadow: 0 12px 44px rgba(0, 0, 0, .45);
  box-shadow: var(--bar-shadow);
}
@media (max-width: 900px) {
  #playerbar { --bar-shadow: 0 8px 12px -8px rgba(0, 0, 0, .55); }
  #tabbar { box-shadow: 0 26px 36px -20px rgba(0, 0, 0, .42); }
}

/* ===== v166: on narrow screens both bottom controls cast the SAME shadow =====
 * v165 clipped them but left two different values (bar 8/12/-8 .55, nav 26/36/-20 .42),
 * so the bar showed a tight dark band in the 8px gap while the nav, sitting 8px above the
 * bottom edge, had almost all of its wide shadow fall off screen: the two looked nothing
 * alike. They now share one shadow, so the band under the bar and the band under the nav
 * have the same depth; both stay inside their own 8px strip and never reach the other
 * control.
 */
@media (max-width: 900px) {
  #tabbar { box-shadow: 0 8px 12px -8px rgba(0, 0, 0, .55); }
}

/* ===== v168: BetterMusic curated page (sidebar entry, hash #/curated) =====
 * Two cards per row that always fill the content width, so they grow and shrink with the
 * viewport instead of sitting in a fixed 620px column with empty space next to them.
 * Each card: a small 56px square SVG cover with the playlist name (and track count) to its
 * right, then the plain song list (name + artist, click a row to play). The list is clipped
 * at a fixed height, so all cards are the same height and the page keeps scrolling on touch.
 * The whole card opens #/curated/<key>, which has the topbar back button to return here.
 */
.bm-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
.bm-card {
  display: flex; flex-direction: column;
  min-width: 0; overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--panel);
  cursor: pointer;
  transition: border-color .2s var(--ease);
}
.bm-card:hover { border-color: rgba(var(--fg-rgb), .22); }
.bm-top { display: flex; align-items: center; gap: 10px; padding: 10px; border-bottom: 1px solid var(--border); }
.bm-cover { flex: 0 0 auto; width: 56px; height: 56px; border-radius: 12px; overflow: hidden; background: transparent; }
.bm-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
.bm-info { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.bm-name { font-size: 15px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bm-count { font-size: 11.5px; color: var(--sub); }
.bm-tri {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
  background: rgba(var(--accent-rgb), .92); color: #fff;
  opacity: 0; transform: scale(.86);
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}
.bm-tri svg { width: 14px; height: 14px; fill: currentColor; }
.bm-card:hover .bm-tri { opacity: 1; transform: scale(1); }
.bm-songs { flex: 1 1 auto; min-height: 0; max-height: 300px; overflow: hidden; padding: 6px 8px 8px; }
.bm-song {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  height: 24px; padding: 0 6px; border-radius: 6px;
  transition: background-color .16s var(--ease);
}
.bm-song:hover { background: rgba(var(--accent-rgb), .16); }
.bm-song-name { min-width: 0; font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bm-song-artist { flex: 0 0 auto; max-width: 48%; font-size: 11px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 420px) {
  .bm-song-artist { display: none; }
}
/* ===== v169: keep the curated card title readable on phones =====
 * At 176px per card the 56px cover plus the hover play badge left only ~70px for the name,
 * so a four-character name was clipped to two characters. On narrow cards the badge is hidden (there is no
 * hover on touch anyway) and the cover shrinks to 48px, which gives the name room.
 */
@media (max-width: 520px) {
  .bm-top { gap: 8px; padding: 8px; }
  .bm-cover { width: 48px; height: 48px; border-radius: 10px; }
  .bm-name { font-size: 13.5px; }
  .bm-tri { display: none; }
}

/* ===== v170: no white plate behind the curated covers =====
 * The light theme gives .dt-cover a plain white background; the curated SVGs are square
 * with a ~1% transparent margin, so a thin white ring showed around the artwork (and the
 * card cover had the same problem at 56px). Both cover boxes are transparent now: what you
 * see is only the SVG itself on top of the card/page background.
 */
.bm-dt-cover { background: transparent !important; }

/* ===== v171: no white plate behind the covers (kills the white fringe on the corners) =====
 * In the light themes --bg3 is #ffffff and it sits behind every cover box. The image is
 * clipped to the rounded corners, so the anti-aliased corner pixels blended with that
 * white plate and every cover looked like it had a white edge on all four corners.
 * The plates are transparent now, so the corners blend into the page instead.
 *   .sr-cover  song rows (playlist pages, search, queue ...)
 *   .dt-cover  big cover on playlist / album / curated detail pages
 */
.sr-cover,
.dt-cover { background: transparent; }

/* ===== v172: cover shadows via drop-shadow, so the rounded corners have no light fringe =====
 * box-shadow is clipped to OUTSIDE the border box, so the little pocket between the
 * rounded corner and the square box never receives any shadow. With a transparent cover
 * background that pocket shows the plain page while everything around it is darkened by
 * the shadow - measured on the detail cover: 243,245,249 inside the pocket against
 * 223,227,231 just outside, i.e. a bright edge on all four corners.
 * filter: drop-shadow() is generated from what the element actually paints (the rounded,
 * clipped artwork), so it covers that pocket too and the corner blends smoothly.
 */
.sr-cover,
.dt-cover {
  box-shadow: none;
  filter: drop-shadow(0 3px 9px rgba(0, 0, 0, .30));
}
.dt-cover { filter: drop-shadow(0 14px 24px rgba(0, 0, 0, .42)); }

/* ===== v173: on narrow screens the playlist cover sits at the LEFT edge too =====
 * The <=700px block stacks .detail-head and centers it. The text and the action buttons
 * were later moved back to the left, but the cover kept align-items: center and floated in
 * the middle of the page. Now the whole head is left aligned on narrow screens, so the
 * cover lines up with the title / meta / buttons below it.
 */
@media (max-width: 700px) {
  .detail-head { align-items: flex-start; }
  .detail-head .dt-info { text-align: left; }
}

/* ===== v174: curated cards / playlist page take a tint from their cover =====
 * JS samples each cover and writes --bm-rgb (e.g. "214, 78, 62"). The tint is mixed with
 * the PAGE background (var(--bg)) instead of a fixed colour, so the same cover gives a
 * dark, muted tone on the dark themes and a pale pastel on the light themes: a bright
 * cover colour can never glare on a dark page, and a dark one can never muddy a light
 * page. The plain --panel colour stays in front of the color-mix line as a fallback for
 * browsers without color-mix().
 */
.bm-card {
  --bm-rgb: 128, 128, 128;
  background: var(--panel);
  background: color-mix(in srgb, rgb(var(--bm-rgb)) 16%, var(--bg));
  border-color: color-mix(in srgb, rgb(var(--bm-rgb)) 22%, var(--border));
}
.bm-card:hover {
  border-color: color-mix(in srgb, rgb(var(--bm-rgb)) 55%, var(--border));
}
.bm-card .bm-top {
  border-bottom-color: color-mix(in srgb, rgb(var(--bm-rgb)) 22%, var(--border));
}
.bm-detail { position: relative; }
.bm-detail { position: relative; }

/* ===== v175: the cover tint covers the WHOLE screen on a curated playlist page =====
 * The first version only washed the top 420px of the content column. Now the page
 * background itself is a fixed gradient mixed from the cover colour and var(--bg), so the
 * tint fills the whole window (sidebar / topbar keep their own surfaces on top of it) and
 * fades back to the plain page background lower down. Same colour-mix rule as the cards,
 * so it stays dark on dark themes and pale on light themes.
 */
html.bm-tint-page body {
  background: linear-gradient(180deg,
    color-mix(in srgb, rgb(var(--bm-rgb, 128 128 128)) 26%, var(--bg)) 0%,
    color-mix(in srgb, rgb(var(--bm-rgb, 128 128 128)) 12%, var(--bg)) 38%,
    var(--bg) 78%,
    var(--bg) 100%) fixed no-repeat;
}

/* ===== v176: iOS viewport / safe area + GPU compositing hints =====
 * iOS Safari reports 100vh as the LARGE viewport (the part hidden behind its bottom bar),
 * so the player page bottom controls (volume row, lyric toolbar) ended up underneath the
 * Safari toolbar. dvh follows the visible viewport, and the safe-area insets keep the
 * controls clear of the home indicator. Browsers without dvh keep the 100vh fallback.
 */
#ov-fill {
  height: 100vh;
  height: 100dvh;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
@media (max-width: 700px) {
  /* same values as the 118px / 380px rules above, dvh unit only (the later one still wins) */
  #ov-body:not(.lyrics-hidden) .ov-right {
    height: calc(100dvh - 118px);
    height: calc(100dvh - 380px);
    min-height: 300px;
  }
  #ov-body:not(.lyrics-hidden) .ov-btns { bottom: calc(108px + env(safe-area-inset-bottom, 0px)); }
  #ov-body:not(.lyrics-hidden) .ov-vol { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
}

/* mobile: idle auto-hide for the bottom controls (progress / quality / buttons / volume +
 * the bottom-right toolbar). app.js adds .ov-idle on #overlay when the finger has been quiet
 * for a few seconds, and takes it off on any touch/scroll/key. While idle the lyric viewport
 * grows into the freed space, so the lyric player re-fits and re-aligns (see _ovIdleRelayout).
 * Only opacity/filter are transitioned for the controls; the lyric height transition is
 * tracked frame by frame by the player fit. */
@media (max-width: 700px) {
  #overlay .ov-progress,
  #overlay .ov-quality,
  #overlay .ov-btns,
  #overlay .ov-vol,
  #overlay .ly-toolbar {
    transition: opacity .38s var(--ease), filter .38s var(--ease);
  }
  #overlay.ov-idle #ov-body:not(.lyrics-hidden) .ov-progress,
  #overlay.ov-idle #ov-body:not(.lyrics-hidden) .ov-quality,
  #overlay.ov-idle #ov-body:not(.lyrics-hidden) .ov-btns,
  #overlay.ov-idle #ov-body:not(.lyrics-hidden) .ov-vol,
  #overlay.ov-idle .ly-toolbar {
    opacity: 0;
    filter: blur(7px);
    pointer-events: none;
  }
  #ov-body:not(.lyrics-hidden) .ov-right { transition: height .38s var(--ease); }
  /* mobile lyric mode: kill the flex gap between the cover row and the lyric column, so the
   * current line sits right under the cover instead of leaving a blank strip above it. */
  #ov-body:not(.lyrics-hidden) { gap: 0; }
  #overlay.ov-idle #ov-body:not(.lyrics-hidden) .ov-right {
    height: calc(100vh - 118px);
    height: calc(100dvh - 118px);
  }
}
.ly-toolbar { bottom: calc(20px + env(safe-area-inset-bottom, 0px)); }
@media (max-width: 900px) {
  .ly-toolbar { bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
}

/* ---- GPU: keep animated things on their own composited layer ----
 * The morph animates the plate box (top/left/width/height), which cannot be composited,
 * but hinting it while .ov-morphing is present lets the browser prepare the layer and
 * keeps the shadow / radius repaint from walking up the tree. The hints are transient:
 * the classes are removed on settle, so no element keeps a permanent layer. */
#overlay.ov-morphing {
  will-change: top, left, width, height, border-radius, background-color, box-shadow;
  transform: translateZ(0);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
#playerbar.morph-out,
#playerbar.morph-top { will-change: opacity, background-color, box-shadow, filter; }
#view.view-anim > * {
  will-change: opacity, transform;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
#playerbar, #tabbar { backface-visibility: hidden; -webkit-backface-visibility: hidden; }

/* ===== v177: dynamic song covers (mp4) =====
 * A muted looping video sits exactly on top of the static cover and is only revealed once
 * it actually reports "playing", so there is never a black flash in between; songs without
 * a dynamic cover (or a failed load) simply keep showing the static image underneath.
 */
.dyn-cover {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
  transition: opacity .28s var(--ease);
}
.dyn-cover.on { opacity: 1; }
.pb-cover { position: relative; }
/* the player page cover is a 16px-radius square (see .ov-disc img), so the video layer
   must use the same radius to line up exactly (it used to be 50%, which made it a circle) */
.ov-disc .dyn-cover { border-radius: 16px; }

/* ===== v178: hover highlight for lyric lines =====
 * ONE rounded block holding the whole line (original + translation): 5px outside the text on
 * all four sides.
 *
 * Width: a block child is as wide as the track, which is what made the box run hundreds of
 * pixels past a short line, so the line itself shrinks to its text with width: fit-content.
 * Wrapping is untouched: fit-content = min(max-content, available), so a line that already
 * fills the track keeps exactly the same line breaks (verified over all 84 lines: 0 height
 * changes).
 *
 * Height: an absolutely positioned box is laid out against the PADDING box of .ly-line,
 * and .ly-line has padding: 12px 0 (line 639, no media query overrides it), so the 12px has
 * to be added back into the insets. Inside a row, with line-height 1.75 the half-leading is
 * (1.75 - font content height) / 2 = .193em and the glyph ink starts another .182em below the
 * font box top, so ink begins .375em below the row top. The inset is therefore
 * 12px + .375em - 3px = .375em + 9px: a 3px gap above the glyphs and, symmetrically, 3px
 * below the last row. The 7px is the 12px line padding minus the 5px gap; left and right use
 * -5px (the 3px of the first version plus 2px), and
 * because the line box ends exactly at the text, -5px is 5px outside the glyphs.
 * The bottom row is the translation (font size .64em), so its inset is
 * .24em + 9px; lines without a translation (no .ly-trans element, or it is .hide) fall back
 * to .375em + 9px. Wrapped rows need no extra term: one more row adds exactly one line
 * height to both the row box and the ink position.
 *
 * Painting: the pseudo is z-index: -1 inside a z-index: 0 line, so it sits under the text
 * and its karaoke words while staying above the panel behind it.
 *
 * Motion: a plain fade (opacity only). No box in the lyric flow changes size, so the layout
 * and the cached scroll offsets stay exactly as they were.
 *
 * Text rows also get line-height 1.2 with .275em of vertical padding. The padding equals the
 * leading that 1.75 gave up, so the row box, the glyph positions and the cached offsets are
 * all unchanged, but the native ::selection band is painted at max(line box, font box): it
 * drops from 1.75em (39px at 22px text) to the font box (30px), i.e. from 8.25px above the
 * glyphs to 4px, so the red selection band (the glyphs plus 4px) sits inside the grey hover
 * card (the glyphs plus 5px) instead of spilling over it.
 */
.ly-line { position: relative; z-index: 0; width: fit-content; }
.ly-line > .ly-text, .ly-line > .ly-trans { line-height: 1.2; padding: .275em 0; }
.ly-line::before {
  content: ''; position: absolute; z-index: -1;
  top: calc(.375em + 7px); bottom: calc(.24em + 7px); left: -5px; right: -5px;
  background: var(--panel2); border-radius: 8px;
  opacity: 0; transition: opacity .2s ease; pointer-events: none;
}
.ly-line:not(:has(.ly-trans:not(.hide)))::before { bottom: calc(.375em + 7px); }
.ly-line:hover::before { opacity: 1; }

/* ===== v179: returning from a hidden tab must not fade the lyrics =====
 * While the tab is hidden requestAnimationFrame stops, so the active lyric line can jump
 * many lines at once when it comes back. Every line would then run its .25s opacity/filter
 * transition from the grey non-active state, which reads as "the lyrics went pale". The
 * jump path adds .ly-noanim for two frames so the new state lands instantly, exactly like
 * the scroll position already does for long jumps.
 */
#ov-lyrics-inner.ly-noanim .ly-line,
#ov-lyrics-inner.ly-noanim .ly-line::before { transition: none !important; }


/* ===== v180: selecting lyric text =====
 * The selection keeps the theme accent (the red of the cover), which is what the global
 * ::selection paints. Only its height changed: the short line-height above makes Chrome paint
 * a 30px band instead of 39px, so it stays inside the hover card instead of covering the row.
 */

/* ===== v181: splash screen =====
 * #F3DBDD background, #AB4949 logo mark above the label (column layout, both the same colour),
 * no dots, no "web version" suffix.
 * Loading sheen: the mark is filled pure white and a diagonal mask sweeps across it from the
 * top-left to the bottom-right: the mask is fully opaque at rest (so the on-screen colour is
 * exactly #AB4949) and the moving band is held back to 42%, which lets the pale background
 * show through - i.e. the band reads as a light sheen travelling across the mark.
 * Removed once the first view has rendered (min 420ms, hard cap 4s, see app.js). */
#splash {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  background: #F3DBDD;
  transition: opacity .32s ease, visibility .32s ease;
}
#splash.gone { opacity: 0; visibility: hidden; pointer-events: none; }
#splash .splash-inner { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; }
#splash .splash-badge { display: flex; align-items: center; justify-content: center; background: none; }
#splash .splash-badge svg {
  width: 88px; height: 88px; fill: #AB4949;
  -webkit-mask-image: linear-gradient(135deg, #000 34%, rgba(0, 0, 0, .42) 50%, #000 66%);
  mask-image: linear-gradient(135deg, #000 34%, rgba(0, 0, 0, .42) 50%, #000 66%);
  -webkit-mask-size: 200% 200%; mask-size: 200% 200%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: 100% 100%; mask-position: 100% 100%;
  animation: splashSheen 1.7s linear infinite;
}
#splash .splash-text { font-size: 27px; font-weight: 700; letter-spacing: -.2px; color: #AB4949; }
/* 100% -> 0%: the window walks BACK through the gradient, so the band travels from the
   top-left corner to the bottom-right corner. It used to animate 0% -> 100%, which moved
   the band the opposite way (bottom-right to top-left) - that is why it looked stuck. */
@keyframes splashSheen {
  0% { -webkit-mask-position: 100% 100%; mask-position: 100% 100%; }
  100% { -webkit-mask-position: 0% 0%; mask-position: 0% 0%; }
}
@media (prefers-reduced-motion: reduce) {
  #splash .splash-badge svg { animation: none; -webkit-mask-image: none; mask-image: none; }
}

/* ===== v182: developer welcome modal =====
 * The panel head sits 4px higher than the shared .modal-head default; the close (x) button was
 * removed, so the capsule title is the only thing in the head and "Start" is the single action.
 * (The real bug was that nothing had ever bound [data-close] inside #devwelcome, so both the x
 * and the Start button were dead - see app.js.) */
/* The panel centres its content (flex), so a negative margin on the head only moves it half as
   far - a 4px relative offset on the title itself is exact and does not disturb the layout. */
#devwelcome .modal-head > span:first-child { position: relative; top: -4px; }
#devwelcome .modal-body { text-align: center; }
#devwelcome .modal-body .auth-submit { margin-top: 18px; }

/* ===== v183: no hairline seam around cover art =====
 * Cover boxes regularly land on fractional sizes: the player disc is min(44vh, 460px), which is
 * 455.391px at a 1035px viewport. A composited image/video layer is rasterised to whole device
 * pixels, so a sub-pixel strip along the right and bottom edge stays unpainted and the page
 * background shows through as a hairline (white on light themes, black on dark ones). Anything that
 * forces a repaint re-rasterises the layer correctly - which is why taking a screenshot "fixes" it.
 *
 * Fix: let the media overscan its box by 1px; the wrapper already clips (border-radius + overflow),
 * so the extra pixel can never be seen but always covers the unpainted strip. For the player disc
 * the drop shadow moves from the <img> onto the container, otherwise overflow: hidden would clip
 * the shadow away.
 */
.pl-cover img,
.sr-cover img,
.dt-cover img,
.qd-cover img,
.bm-cover img,
.usr-avatar img,
.ov-disc img,
.ov-disc .dyn-cover {
  width: calc(100% + 1px);
  height: calc(100% + 1px);
}
.ov-disc {
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 24px 80px rgba(0, 0, 0, .55);
}
.ov-disc img { box-shadow: none; }

/* ===== v184 / v186: karaoke words must be allowed to paint their overhangs =====
 * A karaoke word is an inline-block whose box is only one line tall (line-height 1.2, set in
 * v178), while the ink of a y/g/q/p descender reaches about .03em past that box bottom and the
 * left hook of a j (or y) reaches about .07em past the box left. In scroll style JS gives the
 * word being sung a mask-image, and a masked element is painted into a group bounded by its own
 * box, so those overhangs were cut off the moment the progress reached such a letter (measured:
 * 1.67px of tail, 2.08px of j hook). The same rule promotes a compositing layer, which clips
 * the same overflow - so a forced repaint, i.e. any screenshot, hides the bug.
 * Fix: grow the PAINTED box on all four sides so the ink sits inside it. The equal negative
 * margin keeps the margin box - and with it the line box, every glyph position, the cached
 * lyric offsets and the hover card insets - exactly as before. The amount is .12em: the hook
 * measured 2.25px at 30px text over every font that resolves here (Segoe UI / YaHei / the
 * default stack = .075em), so an earlier .08em left only .15px of headroom - too tight.
 *
 * Do NOT add mask-origin here. mask-origin: content-box made Chromium drop the whole sweep mask
 * (measured: an injected gradient then changed 0 pixels instead of ~41k), so the sweep position
 * is compensated in JS instead: _lyricUpdate writes the gradient stops in px, measured from the
 * border box, so the sweep still lines up with the TEXT inside the padding.
 */
.ly-line.active .ly-w {
  padding: .25em;
  margin: -.25em;
}

/* ===== v190: per-character lift inside a word =====
 * English lyrics arrive as whole words, so the karaoke wave could only lift a word. Each
 * grapheme now gets its own inline-block (JS wraps it in .ly-c) and can be moved on its own.
 * display MUST be inline-block: transform does not apply to a plain inline box. That drops
 * font kerning inside the word (a fraction of a pixel) - the inline-block keeps its own width,
 * so line breaking, the line box and the sweep geometry are unchanged.
 * The transition smooths the fall-back when the word changes.
 */
.ly-line .ly-c {
  display: inline-block;
  /* Default (released) transition = the SLOW one. It is what runs when a character lets go:
     at the end of its word, and when the whole line stops being the active one. While a
     character is actually tracking the sweep it carries .c-up, which swaps in a short
     transition so it still follows the motion closely. */
  transition: transform .55s cubic-bezier(.25, .12, .25, 1);
}

/* v192: low-end auto degrade. JS measures the real frame rate and adds .ly-lite when the
 * device cannot keep up; the per-character lift/glow is switched off entirely then (the
 * word-level karaoke wave stays), so nothing keeps animating. */
.ov-lyrics.ly-lite .ly-line .ly-c { transition: none !important; }
.ly-line .ly-c.c-up {
  transition: transform .16s cubic-bezier(.4, 0, .3, 1);
}
/* v194: keep the chars that are actually moving on a stable composited layer. Without this
 * the browser keeps promoting/demoting them every frame (they sit inside the masked word),
 * which shows up as a one-frame flicker on desktop. Only the current word carries .c-up, so
 * this is a handful of layers, not the whole column. */
.ly-line.active .ly-c.c-up { will-change: transform; }
/* ===== v185 / v191: the karaoke glow, now per character =====
 * The character being sung right now gets a soft halo that grows the longer the voice stays on
 * it. JS writes two values on that .ly-c element every frame:
 *   --glow    halo radius in px: (time spent on this word) / 4, capped, times 10px  ->  0..10px
 *   --glow-o  fade envelope, also per character (each one fades in and out on its own)
 *
 * Painted by a pseudo copy of THAT ONE character (content: attr(data-c); its own glyphs stay
 * transparent and only the text-shadow shows), so the halo sits on the character itself and
 * travels with it - including the per-character lift, which a whole-word copy could not follow
 * (that left a second, lower layer of text under the lifted letters).
 *
 * The layer is 14px larger on every side, enough for the full 10px blur. The .ly-w padding is
 * what gives it room: a masked element (the sweep) clips its own painting to its box, so the
 * halo can never shine further than the padding of the word it lives in.
 */
.ly-line.active .ly-c.c-glow { position: relative; }
.ly-line.active .ly-c.c-glow::after {
  content: attr(data-c);
  position: absolute; left: -11px; top: -11px;
  width: calc(100% + 22px); padding: 11px;
  color: transparent; opacity: var(--glow-o, 0);
  text-shadow: 0 0 var(--glow, 0px) var(--fg-strong);
  pointer-events: none;
}

/* ===== v193: iOS (WebKit) lyric hardening =====
 * On iPhone thin purple lines showed up across the lyrics while playing. Both usual causes
 * are in this stylesheet:
 *   - filter: blur() on the non-active lines, inside a container that is translated every
 *     frame. WebKit keeps re-rasterising that filter and leaks coloured seams.
 *   - backface-visibility / will-change promoting every karaoke word to its own layer.
 * On iOS the non-active lines are therefore dimmed with opacity only (no filter), the word
 * layers are left to WebKit, and the two scrolling layers get an explicit identity transform
 * so their texture is stable.
 * @supports (-webkit-touch-callout: none) matches iOS Safari only.
 */
@supports (-webkit-touch-callout: none) {
  #ov-lyrics-inner .ly-line:not(.active):not(.ly-far) { filter: none !important; }
  #ov-lyrics-inner .ly-line:not(.active) { opacity: .55 !important; }
  .ly-line.active .ly-w { will-change: auto; backface-visibility: visible; -webkit-backface-visibility: visible; }
  .ly-line.active .ly-c { will-change: auto; backface-visibility: visible; -webkit-backface-visibility: visible; }
  .ly-line.active .ly-c.c-up { will-change: auto; }
  #ov-lyrics-inner, #ov-lyric-blur-inner { -webkit-transform: translateZ(0); }
}

/* v195: mobile player background is ONE continuous plate. The lyric scroller used to read
 * as its own filled panel while the cover block above and the controls below sat on the
 * plain plate, so a horizontal seam showed where they met. On narrow screens nothing
 * inside the player paints its own background and the blurred cover backdrop is pinned
 * to the whole overlay. The lyric fade mask stays (that is the lines melting at edges). */
@media (max-width: 720px) {
  #ov-lyrics, .ov-lyrics, #ov-lyrics-inner, .ov-lyric-wrap { background: transparent !important; }
  .lyric-blur-inner { background: transparent !important; }
  #ov-bg { inset: 0 !important; top: 0 !important; bottom: 0 !important; height: auto !important; }
}


/* v197: the playlists / leaderboard switch - two separate buttons styled exactly like the
 * topbar pill (see the design reference), sitting as a SIBLING of the title pill so the
 * metaball merge/split animation never touches them. JS owns their lifetime (id lookup). */
.pl-switch { display: inline-flex; align-items: center; gap: 10px; margin-left: 12px; flex: none; }
.pl-switch-btn {
  font: inherit; font-weight: 700; line-height: 1;
  padding: 10px 18px !important; border-radius: 999px !important; cursor: pointer !important;
  color: var(--text, #1a1a1a); background: rgba(var(--panel-rgb, 255, 255, 255), .96);
  border: 1px solid var(--border, rgba(0, 0, 0, .12));
  /* v165b: top-of-page large controls keep their original shadow (see UI-SPEC.md) */
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
  transition: color .18s ease, background .18s ease, border-color .18s ease;
}
.pl-switch-btn:hover { border-color: rgba(var(--accent-rgb, 229, 72, 77), .5); }
.pl-switch-btn.on { color: var(--on-accent); background: var(--accent, #e5484d); border-color: var(--accent, #e5484d); }
@media (max-width: 720px) {
  .pl-switch { gap: 8px; margin-left: 8px; }
  .pl-switch-btn { padding: 8px 13px; font-size: .82rem; }
}

/* v198: bottom bars get a soft upward shadow so they read as a layer above the content.
 * Same value for the desktop player bar and the mobile bottom menu. */
/* ?????????(0 12px 44px),????????,??? */
/* v198b: the mobile bottom menu shadow pointed UP (negative y offset), which reads as an
 * upside-down shadow - it looked like the bar was pressed into the content above it.
 * It now falls downward and shares the player bar value, same as the rule above. */
#tabbar { box-shadow: 0 8px 12px -8px rgba(0, 0, 0, .55) !important; }

/* v199: playlist card tweaks
 *  - the play-count keeps a WHITE shadow under it (???????) so it stays readable
 *    on light covers;
 *  - the round play button in the bottom-right corner is gone (removed by request).
 * !important is needed: index.html carries an inline stylesheet that loads after this file. */
.pl-count {
  color: #fff !important;
  text-shadow: 0 2px 6px rgba(255, 255, 255, .85), 0 1px 2px rgba(255, 255, 255, .6) !important;
}
.pl-hover { display: none !important; }
/* ===== Performance HUD: draggable window, sparkline chart, simple / detail modes ===== */
#perf-hud {
  position: fixed; top: 74px; right: 16px; z-index: 2147483000; /* always on top (above splash 9999 / tip 99999) */
  width: 226px; padding: 9px 11px 8px;
  display: flex; flex-direction: column; gap: 7px;
  font: 500 11.5px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: rgba(var(--fg-rgb), .86);
  background: rgba(var(--panel-rgb), .78);
  border: 1px solid var(--border); border-radius: 12px;
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
  user-select: none; -webkit-user-select: none;
}
#perf-hud.pf-simple { width: 188px; }
#perf-hud.pf-dragging { box-shadow: 0 16px 44px rgba(0, 0, 0, .5); border-color: rgba(var(--accent-rgb, 250, 45, 60), .45); }
#perf-hud .pf-head {
  display: flex; align-items: center; gap: 6px;
  margin: -2px -3px 0; padding: 2px 3px 4px;
  cursor: grab; touch-action: none;
  border-bottom: 1px solid rgba(var(--fg-rgb), .08);
}
#perf-hud.pf-dragging .pf-head { cursor: grabbing; }
#perf-hud .pf-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
#perf-hud .pf-title { flex: 1; color: rgba(var(--fg-rgb), .58); letter-spacing: .5px; }
#perf-hud .pf-chip {
  font: inherit; line-height: 1; color: rgba(var(--fg-rgb), .72);
  background: rgba(var(--fg-rgb), .08); border: 1px solid rgba(var(--fg-rgb), .14);
  border-radius: 999px; padding: 3px 8px; cursor: pointer; transition: all .15s ease;
}
#perf-hud .pf-chip:hover { color: #fff; background: var(--accent); border-color: transparent; }
#perf-hud .pf-x {
  display: grid; place-items: center; width: 18px; height: 18px; padding: 0; flex: none;
  color: rgba(var(--fg-rgb), .5); background: transparent; border: 0; border-radius: 50%; cursor: pointer;
}
#perf-hud .pf-x svg { width: 11px; height: 11px; fill: currentColor; }
#perf-hud .pf-x:hover { color: #fff; background: rgba(var(--fg-rgb), .16); }
#perf-hud .pf-rows { display: flex; flex-direction: column; gap: 5px; }
#perf-hud .pf-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
#perf-hud .pf-k { color: rgba(var(--fg-rgb), .5); flex: none; }
#perf-hud .pf-v { font-variant-numeric: tabular-nums; white-space: nowrap; margin-left: auto; }
#perf-hud .pf-vwrap { display: flex; align-items: baseline; gap: 5px; margin-left: auto; }
#perf-hud .pf-vwrap .pf-v { margin-left: 0; }
#perf-hud .pf-detail-only { display: none; }
#perf-hud.pf-detail .pf-row.pf-detail-only { display: flex; }
#perf-hud.pf-detail span.pf-detail-only { display: inline; }
#perf-hud.pf-detail .pf-chart-cap.pf-detail-only { display: block; }
#perf-hud .pf-chart-wrap { position: relative; }
#perf-hud .pf-chart { display: block; width: 100%; height: 46px; border-radius: 7px; background: rgba(0, 0, 0, .22); }
#perf-hud .pf-chart-cap { margin-top: 3px; font-size: 10px; color: rgba(var(--fg-rgb), .4); }
@media (max-width: 900px) { #perf-hud { right: 10px; } }
@media (max-width: 560px) {
  #perf-hud { top: 66px; right: 8px; width: 190px; padding: 8px 10px 7px; font-size: 10.5px; gap: 6px; }
  #perf-hud.pf-simple { width: 168px; }
  #perf-hud .pf-chart { height: 40px; }
}

/* ===== v170: AMLL lyric host (per package README) =====
 * README: append player.getElement() and let the package stylesheet do the rest.
 * Requirement: a container with a DEFINITE height - keep it in normal flow. */
/* v177: weight + sub-line rules for the AMLL player (CSS Modules need !important) */
#ov-lyrics-inner .FmKaba_lyricMainLine { font-weight: var(--amll-main-weight, 400) !important; }
#ov-lyrics-inner .FmKaba_lyricSubLine { font-weight: var(--amll-sub-weight, 300) !important; line-height: 1.25em; transition: opacity .12s ease !important; }
#ov-lyrics-inner.amll-host {
  position: relative;
  height: 100%;
  min-height: 0;
  padding: 0 !important;
}

/* Feather the box that actually clips (the lyric column). */
#ov-lyrics.amll-parent {
  -webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, .5) 0, rgba(0, 0, 0, .82) 4%, #000 12%, #000 88%, rgba(0, 0, 0, .82) 96%, rgba(0, 0, 0, .5) 100%);
  mask-image: linear-gradient(to bottom, rgba(0, 0, 0, .5) 0, rgba(0, 0, 0, .82) 4%, #000 12%, #000 88%, rgba(0, 0, 0, .82) 96%, rgba(0, 0, 0, .5) 100%);
}

/* mobile: the current line is pinned to the TOP (alignAnchor=top, alignPosition~.07), so the
 * top feathering has to stay shallow - otherwise the current line sits inside the gradient
 * and looks grey. Previous lines above it fade out within the first few percent. */
@media (max-width: 700px) {
  #ov-lyrics.amll-parent {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 1%, #000 95%, rgba(0, 0, 0, .55) 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 1%, #000 95%, rgba(0, 0, 0, .55) 100%);
  }
}

/* v178: lyric line spacing, translation offset and the trans/orig toggle (AMLL player).
 * The component exposes no line-spacing API, so the app writes its lyric line-height
 * setting into --amll-lh-pad (in em) and the rule below spends it as the gap BETWEEN
 * lyric lines. Deliberately padding and not line-height: line-height would also spread
 * the wrapped rows *inside* a single lyric line, which looks far too airy.
 * The translation line is pushed down from the original lyric: the row is a nested block,
 * so a top margin on it is the offset. The unit is the sub line own em (= half of the
 * original lyric size), so .7em is about .35x the original size and the distance grows
 * with the font size setting instead of hugging the descenders.
 * Translation and romanization lines share the .FmKaba_lyricSubLine class; hiding those
 * two sub lines is exactly what "orig only" means for this player. */
#ov-lyrics-inner.amll-host .FmKaba_lyricLineWrapper {
  padding-top: var(--amll-lh-pad, .4em);
  padding-bottom: var(--amll-lh-pad, .4em);
}
#ov-lyrics-inner.amll-host .FmKaba_lyricSubLine { margin-top: .7em; }
#ov-lyrics-inner.amll-host .amll-lyric-player.amll-hide-trans .FmKaba_lyricSubLine { display: none !important; }

/* v200b: player-page settle-in - lyrics start as a flat faint block (no blur, no active-line
 * scale, one dim colour) and then grow into the normal look when the page finishes opening.
 * setWarmup() toggles .amll-warmup on the lyric host and on the player element; every rule
 * here is a composited transition so the morph animation itself stays cheap. */
#ov-lyrics-inner.amll-host .FmKaba_lyricLine { transition: filter .45s ease; }
#ov-lyrics-inner.amll-host .FmKaba_lyricMainLine { transition: color .45s ease; }
#ov-lyrics-inner.amll-warmup .FmKaba_lyricLine { filter: none !important; }
#ov-lyrics-inner.amll-warmup .amll-lyric-player { --amll-lp-color: rgba(255, 255, 255, .52) !important; }
/* v421: defer the lyric column on player-page open. While .ov-lyric-wait is set
 * the lyrics are hidden and do not take part in the morph; the app rebuilds and
 * snaps them once the page has settled, then removes the class and this
 * composited transition fades/rises the finished column into place. */
#ov-lyrics-inner .amll-lyric-player {
  transition: opacity .42s var(--ease), transform .42s var(--ease);
  transform-origin: 50% 60%;
}
#overlay.ov-lyric-wait .amll-lyric-player {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: none;
  pointer-events: none;
}

/* duet: lines sung by both are centered (AMLL itself only has left/right sides). */
#ov-lyrics-inner .FmKaba_lyricLineWrapper.amll-duet-both {
  align-items: center !important;
}
#ov-lyrics-inner .amll-duet-both .FmKaba_lyricLine {
  text-align: center !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  transform-origin: center !important;
}
#ov-lyrics-inner .amll-duet-both .FmKaba_bgWrapper {
  transform-origin: center top !important;
}

/* ===== v165b: control shadow policy (see UI-SPEC.md) =====
 * SMALL controls never cast a shadow. The big controls at the top of a page KEEP theirs:
 *   .pl-switch-btn (page switch), #page-title / .topbar-title, .topbar-back, .view-back,
 *   .set-page-title, .set-page-head .view-back, .modal-head .icon-btn (#set-back)
 * So the list below is small-control classes only - deliberately NOT `button`,
 * `.icon-btn` or `.view-back`, which would kill the back button and the title pills. */
.btn, .mini-btn, .chip, .q-item, .nav-item, .set-opt, .theme-card,
.pl-hover, .ly-tool, .side-btn, .set-quality button {
  box-shadow: none !important;
}


/* v165: a solid accent surface always takes --on-accent; theme overrides must not darken it */
html[data-theme^="white-"] .btn.primary,
html[data-theme^="white-"] .mini-btn.primary,
html[data-theme^="white-"] .side-auth-btn.primary,
html[data-theme^="white-"] .pl-switch-btn.on,
html[data-theme^="white-"] .pl-hover {
  color: var(--on-accent) !important;
}

/* home: horizontally scrollable playlist rows (8 per row) */
.home-section { margin-bottom: 32px; }
.home-sec-head { justify-content: space-between; }
.home-sub { font-size: 12px; color: var(--sub); letter-spacing: .02em; }
.home-row {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 2px 2px 8px;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}
.home-row > .pl-card {
  flex: 0 0 158px;
  width: 158px;
  scroll-snap-align: start;
}
.home-row-big > .pl-card {
  flex-basis: 232px;
  width: 232px;
}
.home-row-big .pl-name { font-size: 15px; }
.home-row::-webkit-scrollbar { height: 6px; }
.home-row::-webkit-scrollbar-thumb { background: rgba(var(--fg-rgb),.16); border-radius: 6px; }
.home-row::-webkit-scrollbar-track { background: transparent; }
.pl-card-liked .liked-cover {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, rgba(var(--accent-rgb),.92), rgba(var(--accent-rgb),.42));
}
.liked-heart { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
.liked-heart svg { width: 40%; height: 40%; fill: #fff; }
.home-curated .pl-sub { color: var(--accent); }
@media (max-width: 700px) {
  .home-section { margin-bottom: 26px; }
  .home-row { gap: 12px; }
  .home-row > .pl-card { flex-basis: 132px; width: 132px; }
  .home-row-big > .pl-card { flex-basis: 186px; width: 186px; }
  .home-sub { display: none; }
}
.home-style-loading { padding: 8px 2px 18px; font-size: 12.5px; color: var(--sub); }

/* home: give card shadows room inside the scroll row */
.home-row {
  padding: 18px 18px 24px;
  margin-left: -18px;
  margin-right: -18px;
}
.home-curated .pl-cover { background: var(--bg3); }
.home-curated .pl-cover img {
  transform: scale(1.08);
  transform-origin: center;
}
.home-curated:hover .pl-cover img { transform: scale(1.12); }
@media (max-width: 700px) {
  .home-row { padding: 14px 12px 20px; margin-left: -12px; margin-right: -12px; }
}

/* home: reduce clipped card shadows and crop curated cover frames */
.home-row .pl-cover { box-shadow: 0 5px 14px rgba(0,0,0,.26); }
.home-row .home-curated .pl-cover,
.home-row .home-curated .pl-cover img { border: 0 !important; outline: 0 !important; }
.home-row .home-curated .pl-cover img { transform: scale(1.16); }
.home-row .home-curated:hover .pl-cover img { transform: scale(1.2); }

/* curated covers: let the transparent outer frame show the page, not a white card */
.home-row .home-curated .pl-cover { background: transparent !important; }
.home-row .home-curated .pl-cover img { transform: scale(1.08) !important; }

/* curated covers: only crop the two assets that carry an outer white frame */
.home-row .home-curated .pl-cover img {
  transform: none !important;
  clip-path: none !important;
}
.home-row .home-curated[data-curated="western-pop"] .pl-cover img,
.home-row .home-curated[data-curated="for-you"] .pl-cover img {
  transform: scale(1.16) !important;
}

/* home rows: no snap, no visible scrollbar; desktop wheel drives the row */
.home-row {
  scroll-snap-type: none;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.home-row > .pl-card { scroll-snap-align: none; }
.home-row::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* curated covers: fill the transparent rim with the cover edge colour (no white frame) */
.home-row .home-curated[data-curated="spatial"] .pl-cover { background: #ef5a5a !important; }
.home-row .home-curated[data-curated="western-pop"] .pl-cover { background: #8fa3b5 !important; }
.home-row .home-curated[data-curated="for-you"] .pl-cover { background: #e15c58 !important; }
.home-row .home-curated[data-curated="mandarin"] .pl-cover { background: #7a0c10 !important; }
.home-row .home-curated[data-curated="western-pop"] .pl-cover img,
.home-row .home-curated[data-curated="for-you"] .pl-cover img { transform: none !important; }

/* one custom horizontal scrollbar per home section */
.home-row-scrollbar {
  position: relative;
  width: min(360px, 46vw);
  height: 12px;
  margin: -8px auto 4px;
  cursor: pointer;
  touch-action: none;
  user-select: none;
}
.home-row-scrollbar.is-off { display: none; }
.home-row-scrollbar::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 4px;
  height: 4px;
  border-radius: 4px;
  background: rgba(var(--fg-rgb),.1);
}
.home-row-scrollbar-thumb {
  position: absolute;
  top: 3px;
  height: 6px;
  border-radius: 6px;
  background: rgba(var(--fg-rgb),.34);
  transition: background .15s, height .15s, top .15s;
}
.home-row-scrollbar:hover .home-row-scrollbar-thumb,
.home-row-scrollbar.dragging .home-row-scrollbar-thumb {
  top: 2px;
  height: 8px;
  background: rgba(var(--fg-rgb),.52);
}
@media (max-width: 900px) { .home-row-scrollbar { display: none !important; } }

/* home rows: feather the clipped card edges */
.home-row[data-scroll="start"] {
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), transparent 100%);
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), transparent 100%);
}
.home-row[data-scroll="end"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 100%);
}
.home-row[data-scroll="middle"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
}
@media (max-width: 700px) {
  .home-row[data-scroll="start"] { -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 18px), transparent 100%); mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 18px), transparent 100%); }
  .home-row[data-scroll="end"] { -webkit-mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 100%); mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 100%); }
  .home-row[data-scroll="middle"] { -webkit-mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%); mask-image: linear-gradient(to right, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%); }
}

/* smoother, longer feather at the clipped row edges */
.home-row[data-scroll="start"] {
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 64px), rgba(0,0,0,.86) calc(100% - 50px), rgba(0,0,0,.55) calc(100% - 34px), rgba(0,0,0,.24) calc(100% - 17px), transparent 100%);
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 64px), rgba(0,0,0,.86) calc(100% - 50px), rgba(0,0,0,.55) calc(100% - 34px), rgba(0,0,0,.24) calc(100% - 17px), transparent 100%);
}
.home-row[data-scroll="end"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.24) 17px, rgba(0,0,0,.55) 34px, rgba(0,0,0,.86) 50px, #000 64px, #000 100%);
  mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.24) 17px, rgba(0,0,0,.55) 34px, rgba(0,0,0,.86) 50px, #000 64px, #000 100%);
}
.home-row[data-scroll="middle"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.24) 17px, rgba(0,0,0,.55) 34px, rgba(0,0,0,.86) 50px, #000 64px, #000 calc(100% - 64px), rgba(0,0,0,.86) calc(100% - 50px), rgba(0,0,0,.55) calc(100% - 34px), rgba(0,0,0,.24) calc(100% - 17px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.24) 17px, rgba(0,0,0,.55) 34px, rgba(0,0,0,.86) 50px, #000 64px, #000 calc(100% - 64px), rgba(0,0,0,.86) calc(100% - 50px), rgba(0,0,0,.55) calc(100% - 34px), rgba(0,0,0,.24) calc(100% - 17px), transparent 100%);
}
@media (max-width: 700px) {
  .home-row[data-scroll="start"] { -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 36px), rgba(0,0,0,.55) calc(100% - 20px), transparent 100%); mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 36px), rgba(0,0,0,.55) calc(100% - 20px), transparent 100%); }
  .home-row[data-scroll="end"] { -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 20px, #000 36px, #000 100%); mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 20px, #000 36px, #000 100%); }
  .home-row[data-scroll="middle"] { -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 20px, #000 36px, #000 calc(100% - 36px), rgba(0,0,0,.55) calc(100% - 20px), transparent 100%); mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 20px, #000 36px, #000 calc(100% - 36px), rgba(0,0,0,.55) calc(100% - 20px), transparent 100%); }
}

/* tighter but smoother feather */
.home-row[data-scroll="start"] {
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 40px), rgba(0,0,0,.82) calc(100% - 31px), rgba(0,0,0,.52) calc(100% - 21px), rgba(0,0,0,.22) calc(100% - 10px), transparent 100%);
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 40px), rgba(0,0,0,.82) calc(100% - 31px), rgba(0,0,0,.52) calc(100% - 21px), rgba(0,0,0,.22) calc(100% - 10px), transparent 100%);
}
.home-row[data-scroll="end"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.22) 10px, rgba(0,0,0,.52) 21px, rgba(0,0,0,.82) 31px, #000 40px, #000 100%);
  mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.22) 10px, rgba(0,0,0,.52) 21px, rgba(0,0,0,.82) 31px, #000 40px, #000 100%);
}
.home-row[data-scroll="middle"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.22) 10px, rgba(0,0,0,.52) 21px, rgba(0,0,0,.82) 31px, #000 40px, #000 calc(100% - 40px), rgba(0,0,0,.82) calc(100% - 31px), rgba(0,0,0,.52) calc(100% - 21px), rgba(0,0,0,.22) calc(100% - 10px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.22) 10px, rgba(0,0,0,.52) 21px, rgba(0,0,0,.82) 31px, #000 40px, #000 calc(100% - 40px), rgba(0,0,0,.82) calc(100% - 31px), rgba(0,0,0,.52) calc(100% - 21px), rgba(0,0,0,.22) calc(100% - 10px), transparent 100%);
}
@media (max-width: 700px) {
  .home-row[data-scroll="start"] { -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), rgba(0,0,0,.55) calc(100% - 14px), transparent 100%); mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), rgba(0,0,0,.55) calc(100% - 14px), transparent 100%); }
  .home-row[data-scroll="end"] { -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 14px, #000 24px, #000 100%); mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 14px, #000 24px, #000 100%); }
  .home-row[data-scroll="middle"] { -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 14px, #000 24px, #000 calc(100% - 24px), rgba(0,0,0,.55) calc(100% - 14px), transparent 100%); mask-image: linear-gradient(to right, transparent 0, rgba(0,0,0,.55) 14px, #000 24px, #000 calc(100% - 24px), rgba(0,0,0,.55) calc(100% - 14px), transparent 100%); }
}

/* notice: small AI disclaimer */
.notice-note {
  margin: 10px 0 0;
  text-align: center;
  font-size: 10px;
  line-height: 1.4;
  letter-spacing: .2px;
  color: rgba(var(--fg-rgb),.38);
  user-select: none;
}

/* AMLL: hide background vocal lines while paused */
.amll-lyric-player:not(.FmKaba_playing) .FmKaba_bgWrapper {
  display: none !important;
}

/* fluent play glyphs in cards / counts */
.pl-play-ic, .hb-card-play svg, .hb-icard-play svg {
  width: 10px; height: 10px; vertical-align: -1px; fill: currentColor;
}

/* row edge feather is desktop-only */
@media (max-width: 900px) {
  .home-row[data-scroll="start"],
  .home-row[data-scroll="end"],
  .home-row[data-scroll="middle"] {
    -webkit-mask-image: none !important;
    mask-image: none !important;
  }
}

/* player lyrics: feather the top and bottom clipped edges */
#ov-lyrics,
#ov-lyrics.amll-parent {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, rgba(0,0,0,.18) 3%, rgba(0,0,0,.55) 7%, #000 14%, #000 86%, rgba(0,0,0,.55) 93%, rgba(0,0,0,.18) 97%, transparent 100%) !important;
  mask-image: linear-gradient(to bottom, transparent 0, rgba(0,0,0,.18) 3%, rgba(0,0,0,.55) 7%, #000 14%, #000 86%, rgba(0,0,0,.55) 93%, rgba(0,0,0,.18) 97%, transparent 100%) !important;
}
@media (max-width: 700px) {
  #ov-lyrics,
  #ov-lyrics.amll-parent {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 1.5%, #000 94%, rgba(0,0,0,.35) 97%, transparent 100%) !important;
    mask-image: linear-gradient(to bottom, transparent 0, #000 1.5%, #000 94%, rgba(0,0,0,.35) 97%, transparent 100%) !important;
  }
}

/* player control optical alignment after Fluent icons */
.ov-btns .icon-btn,
.ov-btns .pb-play,
.pb-btns .icon-btn,
.pb-btns .pb-play {
  display: grid;
  place-items: center;
  line-height: 0;
  flex: none;
}
.ov-btns .icon-btn,
.ov-btns .pb-play {
  width: 36px;
  height: 36px;
}
.ov-btns .icon-btn svg,
.ov-btns .pb-play svg {
  width: 20px;
  height: 20px;
  display: block;
}
.pb-btns .icon-btn svg,
.pb-btns .pb-play svg {
  display: block;
}
.pb-play .ic-play,
.pb-play .ic-pause { margin: 0; }

/* play/pause state must win over the generic display:block alignment rule */
.pb-play .ic-play { display: block; }
.pb-play .ic-pause { display: none; }
.pb-play.playing .ic-play { display: none; }
.pb-play.playing .ic-pause { display: block; }
