/* ==========================================
   燕云十六声 · 战备调律毕业率计算器 v4.2
   玻璃拟态 + 动态炫光
   ========================================== */

/* === CSS Variables（默认 = 白色主题） === */
:root {
  /* 背景基色（整面底色，随主题切换） */
  --bg-app: #f6f8fc;
  --bg-app-grad: linear-gradient(180deg, #fafbfe 0%, #eef1f8 100%);

  /* 炫光主题色（随主题切换） */
  --accent-1: #4f7cff;
  --accent-2: #38bdf8;
  --accent-3: #a78bfa;

  /* 炫光透明度（浅色主题更柔和） */
  --aurora-opacity: 0.6;

  /* 玻璃卡片（全透明玻璃，能透出底部主题色） */
  --glass-bg: rgba(255, 255, 255, 0.12);
  --glass-bg-strong: rgba(255, 255, 255, 0.18);
  --glass-bg-card: rgba(255, 255, 255, 0.18);
  --glass-border: rgba(255, 255, 255, 0.55);
  --glass-border-strong: rgba(255, 255, 255, 0.85);
  --glass-blur: blur(20px) saturate(180%);
  --glass-blur-light: blur(12px) saturate(160%);
  --glass-shadow: 0 8px 32px rgba(30, 42, 74, 0.18);

  /* 兼容别名（玻璃半透明背景） */
  --bg-card: rgba(255, 255, 255, 0.18);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);

  /* 品牌色 */
  --primary: var(--accent-1);
  --primary-hover: #3b68e8;
  --primary-active: #2d56c8;
  --primary-soft: rgba(79, 124, 255, 0.15);
  --primary-tint: rgba(79, 124, 255, 0.1);

  /* 文本（浅色主题用深色文字） */
  --text-1: #1e2a4a;
  --text-2: #5a6584;
  --text-3: #98a1b8;
  --text-inverse: #FFFFFF;

  /* 边框 */
  --border: rgba(30, 42, 74, 0.10);
  --border-strong: rgba(30, 42, 74, 0.18);
  --divider: rgba(30, 42, 74, 0.06);

  /* 状态 */
  --success: #16a34a;
  --success-soft: rgba(22, 163, 74, 0.14);
  --warning: #d97706;
  --warning-soft: rgba(217, 119, 6, 0.14);
  --danger: #dc2626;
  --danger-soft: rgba(220, 38, 38, 0.14);
  --info: #0284c7;
  --info-soft: rgba(2, 132, 199, 0.14);

  /* 阴影（多层柔和阴影，浅色主题用深蓝灰） */
  --shadow-color: rgba(30, 42, 74, 0.14);
  --shadow-xs: 0 1px 2px rgba(30, 42, 74, 0.08), 0 2px 6px rgba(30, 42, 74, 0.06);
  --shadow-sm: 0 1px 3px rgba(30, 42, 74, 0.08), 0 6px 16px rgba(30, 42, 74, 0.12);
  --shadow:    0 2px 6px rgba(30, 42, 74, 0.08), 0 12px 32px rgba(30, 42, 74, 0.14), 0 24px 64px rgba(30, 42, 74, 0.08);
  --shadow-lg: 0 4px 12px rgba(30, 42, 74, 0.10), 0 20px 48px rgba(30, 42, 74, 0.18), 0 32px 96px rgba(30, 42, 74, 0.10);
  --shadow-xl: 0 8px 20px rgba(30, 42, 74, 0.12), 0 28px 64px rgba(30, 42, 74, 0.22), 0 48px 128px rgba(30, 42, 74, 0.12);

  /* 圆角 */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 14px;
  --radius-xl: 20px;

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

  /* 过渡 */
  --t-fast: 0.15s ease;
  --t-base: 0.2s ease;
  --t-slow: 0.3s ease;
}

/* === 主题预设（整面配色随主题切换） === */

/* 天蓝色 */
:root[data-theme="sky"] {
  --bg-app: #e9f4ff;
  --bg-app-grad: linear-gradient(180deg, #f0f8ff 0%, #dceeff 100%);
  --bg-card: rgba(255, 255, 255, 0.20);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.85);
  --glass-border-strong: rgba(255, 255, 255, 1);
  --accent-1: #38bdf8;
  --accent-2: #3b82f6;
  --accent-3: #2dd4bf;
  --primary: #38bdf8;
  --primary-hover: #0ea5e9;
  --primary-active: #0284c7;
  --primary-soft: rgba(56, 189, 248, 0.16);
  --primary-tint: rgba(56, 189, 248, 0.1);
  --text-1: #14324a;
  --text-2: #47667e;
  --text-3: #7e97a8;
}

/* 紫色 */
:root[data-theme="purple"] {
  --bg-app: #f2efff;
  --bg-app-grad: linear-gradient(180deg, #f7f5ff 0%, #e9e2ff 100%);
  --bg-card: rgba(255, 255, 255, 0.20);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.85);
  --glass-border-strong: rgba(255, 255, 255, 1);
  --accent-1: #a78bfa;
  --accent-2: #c4b5fd;
  --accent-3: #818cf8;
  --primary: #8b5cf6;
  --primary-hover: #7c3aed;
  --primary-active: #6d28d9;
  --primary-soft: rgba(139, 92, 246, 0.16);
  --primary-tint: rgba(139, 92, 246, 0.1);
  --text-1: #2d2147;
  --text-2: #5d5278;
  --text-3: #8f86a8;
}

/* 淡粉色 */
:root[data-theme="pink"] {
  --bg-app: #fff0f5;
  --bg-app-grad: linear-gradient(180deg, #fff5f8 0%, #ffe4ee 100%);
  --bg-card: rgba(255, 255, 255, 0.20);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.88);
  --glass-border-strong: rgba(255, 255, 255, 1);
  --accent-1: #f9a8d4;
  --accent-2: #fbcfe8;
  --accent-3: #c4b5fd;
  --primary: #ec4899;
  --primary-hover: #db2777;
  --primary-active: #be185d;
  --primary-soft: rgba(236, 72, 153, 0.16);
  --primary-tint: rgba(236, 72, 153, 0.1);
  --text-1: #4a2233;
  --text-2: #7a5063;
  --text-3: #a88493;
}

/* 薄荷绿 */
:root[data-theme="mint"] {
  --bg-app: #ecfdf5;
  --bg-app-grad: linear-gradient(180deg, #f0fdfa 0%, #dffaf0 100%);
  --bg-card: rgba(255, 255, 255, 0.20);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.85);
  --glass-border-strong: rgba(255, 255, 255, 1);
  --accent-1: #34d399;
  --accent-2: #2dd4bf;
  --accent-3: #60a5fa;
  --primary: #10b981;
  --primary-hover: #059669;
  --primary-active: #047857;
  --primary-soft: rgba(16, 185, 129, 0.16);
  --primary-tint: rgba(16, 185, 129, 0.1);
  --text-1: #143a2e;
  --text-2: #3d6a58;
  --text-3: #749a88;
}

/* 奶油黄 */
:root[data-theme="cream"] {
  --bg-app: #fffaf0;
  --bg-app-grad: linear-gradient(180deg, #fffdf5 0%, #fff3d6 100%);
  --bg-card: rgba(255, 255, 255, 0.20);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.9);
  --glass-border-strong: rgba(255, 255, 255, 1);
  --accent-1: #fbbf24;
  --accent-2: #fb923c;
  --accent-3: #f9a8d4;
  --primary: #f59e0b;
  --primary-hover: #d97706;
  --primary-active: #b45309;
  --primary-soft: rgba(245, 158, 11, 0.16);
  --primary-tint: rgba(245, 158, 11, 0.1);
  --text-1: #4a3a1a;
  --text-2: #7a663d;
  --text-3: #a8926a;
}

/* 薰衣草 */
:root[data-theme="lavender"] {
  --bg-app: #f5f3ff;
  --bg-app-grad: linear-gradient(180deg, #faf8ff 0%, #ede9fe 100%);
  --bg-card: rgba(255, 255, 255, 0.20);
  --bg-modal: rgba(255, 255, 255, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.08);
  --bg-soft-2: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.85);
  --glass-border-strong: rgba(255, 255, 255, 1);
  --accent-1: #a78bfa;
  --accent-2: #ddd6fe;
  --accent-3: #f0abfc;
  --primary: #8b5cf6;
  --primary-hover: #7c3aed;
  --primary-active: #6d28d9;
  --primary-soft: rgba(139, 92, 246, 0.16);
  --primary-tint: rgba(139, 92, 246, 0.1);
  --text-1: #2d2447;
  --text-2: #5d5278;
  --text-3: #8f86a8;
}

/* 夜间模式（柔和深色，不刺眼） */
:root[data-theme="navy"] {
  --bg-app: #12151d;
  --bg-app-grad: linear-gradient(180deg, #161a24 0%, #0f1219 100%);
  --bg-card: rgba(34, 40, 56, 0.42);
  --bg-modal: rgba(20, 26, 40, 0.96);
  --bg-soft: rgba(255, 255, 255, 0.035);
  --bg-soft-2: rgba(255, 255, 255, 0.07);
  --glass-border: rgba(255, 255, 255, 0.10);
  --glass-border-strong: rgba(255, 255, 255, 0.18);
  --glass-bg: rgba(255, 255, 255, 0.05);
  --glass-bg-strong: rgba(255, 255, 255, 0.09);
  /* 柔和低饱和炫光 */
  --accent-1: #4a63c8;
  --accent-2: #6d5a9e;
  --accent-3: #2c7a8f;
  --aurora-opacity: 0.42;
  /* 柔和主色 */
  --primary: #6b8afd;
  --primary-hover: #8198f8;
  --primary-active: #5b74d9;
  --primary-soft: rgba(107, 138, 253, 0.18);
  --primary-tint: rgba(107, 138, 253, 0.12);
  /* 柔和灰白文字（非纯白） */
  --text-1: #d8dce4;
  --text-2: #939cad;
  --text-3: #5f6a7d;
  --border: rgba(255, 255, 255, 0.09);
  --border-strong: rgba(255, 255, 255, 0.16);
  --divider: rgba(255, 255, 255, 0.06);
  /* 柔和状态色 */
  --success: #3fbf6f;
  --success-soft: rgba(63, 191, 111, 0.15);
  --warning: #e0a94f;
  --warning-soft: rgba(224, 169, 79, 0.15);
  --danger: #e57878;
  --danger-soft: rgba(229, 120, 120, 0.15);
  --info: #5eb8dd;
  --info-soft: rgba(94, 184, 221, 0.15);
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.22), 0 2px 6px rgba(0, 0, 0, 0.18);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(0, 0, 0, 0.24);
  --shadow:    0 2px 6px rgba(0, 0, 0, 0.22), 0 12px 32px rgba(0, 0, 0, 0.30), 0 24px 64px rgba(0, 0, 0, 0.18);
  --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.24), 0 20px 48px rgba(0, 0, 0, 0.34), 0 32px 96px rgba(0, 0, 0, 0.20);
  --shadow-xl: 0 8px 20px rgba(0, 0, 0, 0.26), 0 28px 64px rgba(0, 0, 0, 0.38), 0 48px 128px rgba(0, 0, 0, 0.22);
}

/* === Reset === */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
  background: var(--bg-app);
  background-attachment: fixed;
  color: var(--text-1);
  min-height: 100vh;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  font-size: 14px;
  line-height: 1.5;
}

a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-hover); }

/* === SVG Icons === */
.icon, .icon-sm, .brand-icon { flex-shrink: 0; }
.icon { width: 18px; height: 18px; }
.icon-sm { width: 14px; height: 14px; }
.icon-lg { width: 22px; height: 22px; }
.brand-icon { width: 26px; height: 26px; }

/* ==========================================
   动态炫光背景
   ========================================== */
.aurora-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: var(--bg-app-grad);
}

/* ★ v7.17.1（口述5）：自定义背景图层
   层级：与 .aurora-bg 同为 z-index:0，但 DOM 在其之后 → 盖住炫光；
         又被 .app-container（z-index:1，见下方）盖住 → 内容始终在图片之上。
   图片地址由 app.js 的 applyCustomBg() 写入 --custom-bg-image（空值时为 none）。 */
.custom-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;   /* 不挡任何鼠标事件 */
  background-image: var(--custom-bg-image, none);
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  background-attachment: fixed;
}

/* 半透明遮罩：取各主题底色 var(--bg-app) 而**不是**写死白色
   → 白色主题得到浅色蒙版、夜间主题自动压暗，8 套主题都不用单独调。
   opacity 通过过渡平滑（切换/上传时不闪）。

   ★★ v7.17.1 修复（用户报障 2026-09-22）：「加了可上传背景图后，原来默认的主题颜色变的太浅了」
   根因：本 `::after` 原本**无条件** opacity:.55。而 .custom-bg 这一层在**没有背景图时也一直存在**
         （background-image:none 只是不画图，层本身仍在）→ 这块半透明主题底色矩形就无差别地
         盖在 .aurora-bg 上，把整个页面又"洗白"了一遍 55%（实测 ::after opacity=0.55、
         bg=rgb(246,248,252)，而 html 上并没有 has-custom-bg）。
   修法：遮罩**只在确实有自定义背景图时**才启用 —— 默认 opacity:0，
         由 html.has-custom-bg 提上来。无图时完全不加遮罩，主题恢复原本深浅。
   ⚠ 注意：判定条件必须挂在 html.has-custom-bg 上（applyCustomBg() 维护），
     而不是 `.custom-bg` 自身 —— 因为层永远存在，用层做条件等于没条件。 */
.custom-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--bg-app);
  opacity: 0;                       /* 默认不加遮罩：无背景图时不干扰主题 */
  transition: opacity 0.3s ease;
  pointer-events: none;
}

/* 有自定义背景图时才压遮罩，保证前景文字可读 */
html.has-custom-bg .custom-bg::after { opacity: 0.55; }

/* 深色主题需要更厚的蒙版，否则浅色文字会与照片打架 */
html[data-theme="navy"].has-custom-bg .custom-bg::after { opacity: 0.72; }

/* 有自定义背景时把炫光淡出，避免彩色光斑叠在照片上显得脏 */
html.has-custom-bg .aurora-bg { opacity: 0.28; transition: opacity 0.3s ease; }

.aurora-orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: var(--aurora-opacity, 0.4);
  will-change: transform, opacity;
}

.aurora-orb.orb-1 {
  width: 520px; height: 520px;
  top: -10%; left: -8%;
  background: radial-gradient(circle, var(--accent-1), transparent 70%);
}

.aurora-orb.orb-2 {
  width: 460px; height: 460px;
  top: 20%; right: -10%;
  background: radial-gradient(circle, var(--accent-2), transparent 70%);
}

.aurora-orb.orb-3 {
  width: 420px; height: 420px;
  bottom: -12%; left: 25%;
  background: radial-gradient(circle, var(--accent-3), transparent 70%);
}

.aurora-orb.orb-4 {
  width: 300px; height: 300px;
  top: 55%; left: 45%;
  background: radial-gradient(circle, var(--accent-2), transparent 70%);
  opacity: 0.35;
}

/* 动画类型：渐变流动 */
body[data-anim="flow"] .aurora-orb {
  animation: aurora-flow 12s ease-in-out infinite alternate;
}
body[data-anim="flow"] .orb-1 { animation-duration: 13s; }
body[data-anim="flow"] .orb-2 { animation-duration: 15s; animation-delay: -4s; }
body[data-anim="flow"] .orb-3 { animation-duration: 14s; animation-delay: -8s; }
body[data-anim="flow"] .orb-4 { animation-duration: 17s; animation-delay: -3s; }

@keyframes aurora-flow {
  0%   { transform: translate(0, 0) scale(1); }
  25%  { transform: translate(160px, -110px) scale(1.28); }
  50%  { transform: translate(-120px, 90px) scale(0.88); }
  75%  { transform: translate(90px, 140px) scale(1.2); }
  100% { transform: translate(-60px, -80px) scale(1.05); }
}

/* 动画类型：呼吸 */
body[data-anim="breathe"] .aurora-orb {
  animation: aurora-breathe 4.5s ease-in-out infinite alternate;
}
body[data-anim="breathe"] .orb-1 { animation-duration: 5s; }
body[data-anim="breathe"] .orb-2 { animation-duration: 5.5s; animation-delay: -1.5s; }
body[data-anim="breathe"] .orb-3 { animation-duration: 4s; animation-delay: -2.5s; }
body[data-anim="breathe"] .orb-4 { animation-duration: 6s; animation-delay: -2s; }

@keyframes aurora-breathe {
  0%   { opacity: 0.18; transform: scale(0.8); }
  50%  { opacity: 0.85; transform: scale(1.25); }
  100% { opacity: 0.55; transform: scale(1.4); }
}

/* 动画类型：静止 */
body[data-anim="static"] .aurora-orb { animation: none; opacity: var(--aurora-opacity, 0.6); }

/* === App Container === */
.app-container {
  position: relative;
  z-index: 1;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 20px 40px;
}

/* ==========================================
   App Nav (水平白条)
   ========================================== */
.app-nav {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 0 20px;
  height: 60px;
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  position: sticky;
  top: 16px;
  z-index: 100;
  margin-bottom: 24px;
}

.nav-left { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 17px;
  font-weight: 700;
  color: var(--text-1);
  white-space: nowrap;
}

.brand-tag {
  font-size: 12px;
  color: var(--text-3);
  padding: 2px 10px;
  border: 1px solid var(--border);
  border-radius: 100px;
  background: var(--bg-soft);
  white-space: nowrap;
}

.nav-center {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1;
  justify-content: center;
}

.nav-tab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 8px 16px;
  background: transparent;
  border: none;
  color: var(--text-2);
  font-size: 14px;
  font-weight: 500;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: inherit;
  transition: all var(--t-fast);
}
.nav-tab:hover { color: var(--primary); background: var(--primary-tint); }
.nav-tab.active {
  color: var(--primary);
  background: var(--primary-soft);
  font-weight: 600;
}

.nav-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.current-account {
  font-size: 13px;
  color: var(--text-2);
  padding: 6px 12px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.current-account.active { color: var(--success); background: var(--success-soft); border-color: rgba(22, 163, 74, 0.2); }

/* ==========================================
   Buttons
   ========================================== */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  color: var(--text-1);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  transition: all var(--t-fast);
  white-space: nowrap;
  line-height: 1.4;
}
.btn:hover { border-color: var(--primary); color: var(--primary); }

.btn-primary {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--text-inverse);
}
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: var(--text-inverse); }
.btn-primary:active { background: var(--primary-active); }

.btn-outline {
  background: var(--bg-card);
  border-color: var(--primary);
  color: var(--primary);
}
.btn-outline:hover { background: var(--primary-soft); color: var(--primary-hover); }

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text-2);
}
.btn-ghost:hover { background: var(--bg-soft); color: var(--text-1); border-color: transparent; }

.btn-danger {
  color: var(--danger);
  border-color: var(--border);
}
.btn-danger:hover { color: var(--danger); border-color: var(--danger); background: var(--danger-soft); }

.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn-lg { padding: 11px 22px; font-size: 15px; }
.btn-block { width: 100%; justify-content: center; }

/* === Legacy glass-btn aliases (for compat) === */
.glass-btn { display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; background: var(--bg-card); border: 1px solid var(--border-strong); color: var(--text-1); border-radius: var(--radius-sm); font-size: 13px; font-weight: 500; cursor: pointer; transition: all var(--t-fast); white-space: nowrap; font-family: inherit; }
.glass-btn:hover { border-color: var(--primary); color: var(--primary); }
.glass-btn-primary { background: var(--primary); border-color: var(--primary); color: var(--text-inverse); }
.glass-btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: var(--text-inverse); }
.glass-btn-sm { padding: 5px 10px; font-size: 12px; }

/* ==========================================
   Cards（悬浮玻璃卡片）
   ========================================== */
.card {
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  transition: transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base);
  transform: translateZ(0);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--glass-border-strong);
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--divider);
}
.card-header h2 {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-1);
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
}
.card-header h2 .icon { color: var(--primary); }

.card-body { padding: 20px; }

/* === Legacy glass-card alias === */
.glass-card {
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  transition: transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base);
  transform: translateZ(0);
}
.glass-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--glass-border-strong);
}

/* ==========================================
   Overview Hero Cards (4 列)
   ========================================== */
.overview-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}

.overview-card {
  padding: 20px 22px;
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  transition: transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base);
  position: relative;
  overflow: hidden;
  transform: translateZ(0);
  /* ★ v7.17.1（口述2 + 用户报障 2026-09-22）：
     ① 口述2 要求「已装备，词条总数里的文字上下也居中」→ 卡片改为纵向 flex + 居中。
     ② 但单纯 `justify-content:center` 会带来**新的未对齐**（用户报障
        「'已装备''词条总数''当前流派'字样与毕业率字样没有对齐」）：
        每张卡内容行数不同 → 整块内容各自居中 → **标题的垂直位置各不相同**。
        实测：毕业率 top=184 / 当前流派 181 / 已装备 192 / 词条总数 192，最大差 11px。
     ③ 修法：**标题贴顶、其余内容居中**——
        · .overview-card 保持 flex column，但改为 justify-content:flex-start
        · .ov-label 用 `flex:0 0 auto` 固定贴在顶部（四卡 padding-top 相同 → 标题 top 必然一致）
        · 标题之后的所有内容包在 `.ov-body` 里（若存在）或直接由 `:not(.ov-label)` 兜住，
          用 `margin-top:auto` + `margin-bottom:auto` 在剩余空间里垂直居中。
        · 纯 CSS，不加任何 DOM 节点。

     ⚠ 下方 `.overview-card` 与 `.ov-label` 两条规则配合使用，改一条必须同时看另一条。 */
  display: flex;
  flex-direction: column;
  justify-content: flex-start;   /* 标题贴顶；居中交给 .ov-label 之后的兄弟元素 */
}
.overview-card:hover { box-shadow: var(--shadow-lg); transform: translateY(-4px); }

/* ==================== v7.15.13：综合毕业率卡 = 一键自动配装入口（整卡可点） ====================
   需求：删掉卡内的「一键自动配装」按钮，改成直接点卡片的样式。
   实现：整卡 onclick + role/tabindex（键盘可达），卡内保留一行「提示型 CTA」文字（非按钮，
   仅作 affordance，aria-hidden 避免被读屏当成控件重复播报）。 */
.overview-card-clickable { cursor: pointer; }
.overview-card-clickable:hover {
  border-color: var(--accent, rgba(43, 91, 255, 0.55));
  box-shadow: var(--shadow-lg);
  transform: translateY(-4px);
}
.overview-card-clickable:focus-visible {
  outline: 2px solid var(--accent, #2b5bff);
  outline-offset: 2px;
}
.overview-card-clickable:active { transform: translateY(-1px); }
.ov-card-cta {
  margin-top: 8px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent, #2b5bff);
  opacity: 0.85;
  transition: opacity var(--t-base);
  pointer-events: none;   /* 点击穿透到整卡 */
  white-space: nowrap;
}
.overview-card-clickable:hover .ov-card-cta { opacity: 1; }
.ov-card-cta .icon-sm { width: 12px; height: 12px; }

.overview-card.featured {
  background: linear-gradient(135deg, rgba(43, 91, 255, 0.18), rgba(124, 58, 237, 0.14));
  border-color: rgba(43, 91, 255, 0.3);
}

/* ★ v7.17.1（用户报障 2026-09-22）：标题贴顶，四卡严格对齐。
   背景：卡片改 flex column 后，若整块居中，则内容行数不同的卡标题会落在不同高度
        （实测最大差 11px）→ 用户看到「已装备/词条总数/当前流派 与 毕业率 字样没有对齐」。
   修法：标题 `flex:0 0 auto` 固定贴顶（四卡 padding-top 相同 → top 完全一致）；
        标题之后的兄弟元素用上下 `margin:auto` 在剩余空间里居中。
   ⚠ `.ov-label` 必须写在 `.overview-card` 的居中规则之前考虑：
     卡片本身 justify-content:flex-start，居中由这里之后的元素自己吃 auto margin。 */
.ov-label {
  font-size: 13px;
  color: var(--text-2);
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;      /* 固定高度、贴顶，不参与居中 */
}

/* 标题之后的第一个兄弟：吃掉上方剩余空间 → 与下方 auto 一起把正文推到垂直中央 */
.ov-label + * { margin-top: auto; }
/* 卡片里最后一个元素吃掉下方剩余空间 */
.overview-card > *:last-child { margin-bottom: auto; }

/* ★ v7.18.0（用户报障 2026-09-22）：大数字在卡内**上下居中**。
   背景：用户报「已装备 / 词条总数里的数字还是没有上下居中」。
       实测（1440 视口，卡片统一高 131px）：
         已装备   上距 62 / 下距 34  → 偏下 28px
         词条总数 上距 62 / 下距 34  → 偏下 28px
         毕业率   上距 53 / 下距 27  → 偏下 26px
   根因（两条叠加）：
     ① `.ov-value` 自带 `margin-bottom:6px`。它是**固定外边距**，在 `margin:auto`
        平分剩余空间之后又额外占掉 6px，令上下不再相等。
     ② `line-height:1.1` 使行盒略高于字形，数字字形在行盒中落位偏上，
        视觉重心比几何中心略高。
   修法（纯布局，**不用 transform** —— 位移不改变布局盒，量出来会「假性居中」）：
     · 让「标题之后的整块内容」成为一个 flex 列并 `justify-content:center`，
       由它统一吃掉剩余空间 → 固定外边距不再破坏对称；
     · `.ov-value` 自身外边距归零，居中完全交给父容器；
     · `line-height:1` 收紧行盒，让几何中心贴近视觉中心。
   注意：`.ov-label` 仍保持 `flex:0 0 auto` 贴顶 —— 必须保住 v7.17.1 修好的
        「四卡标题严格对齐」，不能为了居中把标题又推到中间。 */

/* 标题之后的整块内容：吃掉卡片剩余空间并垂直居中 */
.ov-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;   /* ← 数字在这里真正居中 */
  align-items: flex-start;   /* 保持左对齐，不因居中而横向漂移 */
  min-height: 0;
}

/* 无 .ov-body 的旧结构（数字直接是 .ov-label 的兄弟）：
   ★ v7.18.0（用户报障 2026-09-22）—— 这里有个**容易被误判的坑**，务必看清：
      仅靠 `margin:auto` 平分，得到的是「标题**下方**那块区域」的居中，
      而不是「整张卡片」的居中。因为标题（含 margin-bottom）占掉了上方 28px
      固定高度，auto 只在剩下的空间里平分 → 数字必然整体偏下。
      实测（卡片高 124，padding 20/20，标题盒 28）：
        auto 各分 11.09px → 数字外边距盒**上下对称**，
        但相对**卡片几何中心**仍偏下 13.8px（用户看到的就是这个）。
  修法：从上方 auto 里**扣掉一半标题高度**补给下方，等价于把数字推向整卡中心。
      标题盒高 28px（20 行高 + 8 下边距）→ 补偿 14px。
      用 `margin-top: calc(50% - 14px)` 不可行（百分比按宽度算），故用固定补偿量，
      并以「不变式断言」守住（见 /tmp/verify_v7180.js 的 C-7）。
   ⚠ 不要用 transform 位移 —— 不改变布局盒，是假居中。 */
.overview-card > .ov-label + * {
  margin-top: auto;
  margin-bottom: auto;
}
/* 只有「标题 + 数字」两张卡（已装备 / 词条总数）需要补偿标题占位；
   含副内容（当前流派 select、毕业率 ADPS 行）的卡由各自布局自然平衡。
   ⚠ 方向别搞反：要让数字**上移**到整卡中心，得让**下方**多占空间，
     所以是 `padding-bottom`（而不是 padding-top —— 那会把数字往下推得更狠）。 */
.overview-card > .ov-label + .ov-value:last-child {
  margin-top: auto;
  margin-bottom: auto;
  padding-bottom: 28px;   /* = 标题盒高（20 行高 + 8 下边距），把数字顶回整卡中心 */
}

/* ★ v7.18.0：毕业率卡（数字 + ADPS/RDPS 副行）同样需要把整块往上顶一点。
   实测偏移 +5.8px（偏下），补偿后应落在 ±1px 内。 */
#ovOverallCard .ov-value { padding-bottom: 12px; }

/* ★ v7.18.0：当前流派卡的数字偏上 5.3px（因下方还有 select 副内容）。
   给它上方加一点补偿，把数字压回中心。 */
#currentFlow { padding-top: 10px; }

.ov-value {
  font-size: 32px;
  font-weight: 700;
  color: var(--text-1);
  /* ★ 用 1 收紧行盒：行盒越贴近字形，「几何中心 ≈ 视觉中心」越成立。
     原先 1.1 会留下约 3px 的下沉感，是这个 bug 的次要成因。 */
  line-height: 1;
  /* ★ 归零：整块由父容器居中，自身若带固定外边距会破坏上下对称
     （这正是「偏下 28px」的主因：auto 平分后又被 margin-bottom 吃掉 6px）。
     ⚠ 不要用 transform 假装居中 —— 位移不改变布局盒，属于自欺欺人。 */
  margin: 0;
}
.ov-value .ov-unit { font-size: 16px; font-weight: 400; color: var(--text-3); margin-left: 2px; }
.ov-value.gradient-text,
.gradient-text {
  background: linear-gradient(135deg, var(--primary) 0%, #4F7AFF 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.ov-flow { font-size: 18px !important; }
.ov-sub { font-size: 12px; color: var(--text-3); }
/* 流派选择下方：武器匹配限制提示 */
.flow-weapon-hint {
  margin-top: 6px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--warning);
  background: var(--warning-soft);
  border: 1px solid var(--warning);
  border-radius: var(--radius-xs);
  padding: 3px 8px;
}

/* ==========================================
   Content Layout
   ========================================== */
.content-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 20px;
  align-items: stretch;   /* 左右两栏等高：面板底边与战备装备底边对齐 */
}

.right-panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
  height: 100%;           /* 撑满战备装备那一行的高度 */
}
/* 满值提醒面板限高，内部滚动，避免把下方装备库挤出视野 */
.suggest-panel { display: flex; flex-direction: column; max-height: 300px; }
.suggest-panel .suggest-list { overflow-y: auto; overscroll-behavior: contain; }
/* 属性面板：与心法面板同处右列。
   v7.4 起右列顺序为「心法装配（上）→ 属性面板（下）」：
   心法按内容高度，属性面板 flex:1 吃掉剩余高度，整列 bottom 仍与左侧战备装备对齐。 */
.attr-panel { display: flex; flex-direction: column; flex: 1 1 0; min-height: 0; }
.attr-panel .attr-grid {
  flex: 1 1 0;
  min-height: 0;
  align-content: start;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* 心法面板按内容高度，不参与拉伸（否则会和属性面板抢空间） */
.xinfa-panel { flex: 0 0 auto; }

/* ==========================================
   Pages
   ========================================== */
.page { display: none; }
.page.active { display: block; }
.page + .page { margin-top: 24px; }

/* ==========================================
   Equipment List (表格行)
   ========================================== */
.equip-panel .card-body { padding: 0; }

.equip-grid {
  display: flex;
  align-items: stretch;
  padding: 0;
}
/* 左右两列：左四件（武器×2+环佩·穿透位）| 右四件（防具·技能位） */
.equip-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.equip-col:first-child { border-right: 1px solid var(--divider); }
/* v7.16.0：分隔线不再用 border-bottom（border 会占盒高，导致偶数槽位比奇数槽位高 1px），
   改用 ::after 伪元素绘制 1px 分隔线 —— 伪元素绝对定位不参与布局，8 个卡片严格等高。
   （此前 #equipGrid 在 1600×1200 @1.5x 视口下两列宽度差 1px 触发子像素舍入，同一个 220px
     内容盒在奇数行为 219.5、偶数行为 218.5，即本回归 29/30 的根因。） */
.equip-col { position: relative; }
.equip-col .equip-slot { border-bottom: none; }
.equip-col .equip-slot:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--divider);
  pointer-events: none;
}
.equip-col .equip-slot:last-child { border-bottom: none; }

.equip-slot {
  background: var(--bg-card);
  padding: 14px 16px;
  cursor: pointer;
  transition: all var(--t-fast);
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 152px;   /* 预留全部 6 条词条空间（1 首 + 4 调律 + 1 定音），保证 8 个装备卡片等高 */
  height: 152px;
  box-sizing: border-box;
  overflow: hidden;
}
.equip-slot:hover { background: var(--bg-soft); }

/* 已装备卡片：右上角「脱下」按钮 */
.slot-unequip-btn {
  position: absolute;
  top: 8px; right: 8px;
  width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-xs);
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-3);
  cursor: pointer;
  opacity: 0;
  transition: all var(--t-fast);
  z-index: 3;
}
.equip-slot:hover .slot-unequip-btn { opacity: 1; }
.slot-unequip-btn:hover { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }

/* 战备装备标题栏按钮组 */
.header-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.danger-btn { color: var(--danger) !important; }
.danger-btn:hover { background: var(--danger-soft) !important; border-color: var(--danger) !important; }

/* 录入装备 · 弹窗内槽位下拉 */
#draftSlotSelect { min-width: 140px; }
.equip-slot.empty {
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  color: var(--text-3);
  font-size: 12px;
  min-height: 152px;
  height: 152px;
  box-sizing: border-box;
  padding: 12px;
}
.equip-slot.empty .icon { color: var(--text-3); margin-bottom: 4px; }

.slot-icon {
  width: 36px; height: 36px;
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
  align-self: flex-start;
  margin-top: 2px;
}

.slot-info { flex: 1; min-width: 0; }

/* 卡片三段式：图标 | 名称区 | 毕业率区 */
.slot-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; height: 100%; justify-content: center; }
.slot-header { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.slot-name {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.equip-name { font-size: 11px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 词条区固定高度（预留全部 6 条词条空间），保证卡片等高 */
.equip-affixes {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  align-content: flex-start;
  align-items: flex-start;
  min-height: 110px;
}
.equip-rate-wrap { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; min-width: 64px; }
.slot-info .equip-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.slot-info .equip-affixes {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
}
.affix-tag {
  font-size: 10px;
  padding: 1px 6px;
  border-radius: var(--radius-xs);
  background: var(--bg-soft);
  color: var(--text-2);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.affix-tag-val { color: var(--primary); font-weight: 700; margin-left: 1px; }

.equip-rate {
  font-size: 18px;
  font-weight: 700;
  text-align: right;
  flex-shrink: 0;
  min-width: 56px;
}
.equip-rate.good { color: var(--success); }
.equip-rate.mid { color: var(--warning); }
.equip-rate.bad { color: var(--danger); }

.equip-progress {
  height: 4px;
  background: var(--bg-soft);
  border-radius: 100px;
  margin-top: 6px;
  overflow: hidden;
}
.equip-progress-bar {
  height: 100%;
  border-radius: 100px;
  transition: width 0.5s ease;
}
.equip-progress-bar.good { background: var(--success); }
.equip-progress-bar.mid { background: var(--warning); }
.equip-progress-bar.bad { background: var(--danger); }

/* 装备库 */
.equip-library-panel { margin-top: 18px; }
.equip-library-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 16px;
  align-items: stretch;
}

/* ── 装备卡片整卡：悬停时整体抬起 + 描边发光 + 顶部光条展开 ── */
/* 装备库卡片专属慢悬浮节奏（独立于全局快速过渡，悬停更从容） */
:root {
  --lib-t: 0.5s cubic-bezier(.22, .68, .3, 1);
  --lib-t-slow: 0.7s cubic-bezier(.22, .68, .3, 1);
  --lib-t-pulse: 3.2s ease-in-out;
}
.equip-lib-item {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  will-change: transform;
  transition: transform var(--lib-t),
              box-shadow var(--lib-t), border-color var(--lib-t), background var(--lib-t);
}
/* 顶部渐隐光条：默认收起，悬停缓慢展开 */
.equip-lib-item::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg, var(--primary), var(--accent-2) 60%, transparent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--lib-t-slow);
}
/* 悬停时整卡浮起 */
.equip-lib-item:hover {
  transform: translateY(-5px);
  border-color: var(--primary);
  background: var(--glass-bg-card, var(--bg-card));
  box-shadow: var(--shadow-lg);
}
.equip-lib-item:hover::before { transform: scaleX(1); }
.equip-lib-item:active { transform: translateY(-2px); }

/* 已装备：左侧高亮描边 + 淡呼吸光 */
.equip-lib-item.is-equipped {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary-tint), var(--shadow-sm);
}
.equip-lib-item.is-equipped::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius-lg);
  pointer-events: none;
  background: var(--primary-tint);
  opacity: .5;
  animation: libEquippedPulse 2.6s ease-in-out infinite;
}
@keyframes libEquippedPulse {
  0%, 100% { opacity: .28; }
  50%      { opacity: .62; }
}

/* 装备卡片本体（点击装备区） */
.equip-lib-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 14px 10px;
  cursor: pointer;
  flex: 1 1 auto;
}

/* 头部：部位徽章 + 部位名 + 装备名 */
.equip-lib-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.lib-slot-badge {
  flex: 0 0 auto;
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  color: var(--primary);
  background: var(--primary-soft);
  border-radius: var(--radius-sm);
  transition: transform var(--lib-t), background var(--lib-t), color var(--lib-t);
}
.equip-lib-item:hover .lib-slot-badge {
  transform: scale(1.12) rotate(-4deg);
  color: var(--text-inverse);
  background: var(--primary);
}
.lib-slot-cat {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--text-3);
}
.lib-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--lib-t);
}
.equip-lib-item:hover .lib-name { color: var(--primary); }
.lib-equipped-flag {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 100px;
  color: var(--success);
  background: var(--success-soft);
  border: 1px solid var(--success);
}

/* 满值状态标签：已满值（绿）/ 未满值（橙） */
.lib-full-tag { font-weight: 700; }
.lib-full-tag.is-full {
  color: var(--success);
  background: var(--success-soft);
  border-color: var(--success);
}
.lib-full-tag.is-notfull {
  color: var(--warning);
  background: var(--warning-soft);
  border-color: var(--warning);
}

/* 元信息行：固定一行高度，避免卡片错位 */
.equip-lib-meta {
  font-size: 11px;
  color: var(--text-3);
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  overflow: hidden;
  height: 18px;
  align-items: center;
}
.equip-lib-meta .tag {
  padding: 1px 7px;
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  border-radius: 100px;
  white-space: nowrap;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 词条位：固定 6 行，行高统一，保证卡片等高、按钮同水平线 */
.equip-lib-affixes {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: 2px;
  padding-top: 6px;
  border-top: 1px dashed var(--divider);
}
.lib-affix-row {
  display: grid;
  grid-template-columns: 20px 1fr auto;
  align-items: center;
  gap: 6px;
  height: 21px;
  padding: 0 4px;
  border-radius: var(--radius-xs);
  font-size: 11px;
  background: transparent;
  transition: background var(--lib-t), transform var(--lib-t);
}
.lib-affix-kind {
  font-size: 9px;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
  border-radius: 3px;
  color: var(--text-3);
  background: var(--bg-soft-2);
}
.lib-affix-row.tiaolv .lib-affix-kind { color: var(--primary); background: var(--primary-soft); }
.lib-affix-row.shou .lib-affix-kind   { color: var(--success); background: var(--success-soft); }
.lib-affix-row.dingyin .lib-affix-kind{ color: var(--warning); background: var(--warning-soft); }
.lib-affix-name {
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lib-affix-val {
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
/* 空词条位：占位但不可交互 */
.lib-affix-row.is-empty { opacity: .45; }
.lib-affix-row.is-empty .lib-affix-name { color: var(--text-3); }
.lib-affix-row.is-empty .lib-affix-kind {
  background: transparent;
  border: 1px dashed var(--border);
  height: 15px;
}
/* 悬停逐行点亮 */
.equip-lib-item:hover .lib-affix-row:not(.is-empty) {
  background: var(--bg-soft);
  transform: translateX(2px);
}

/* 底部操作条：始终贴合卡片底部 */
.equip-lib-actions {
  display: flex;
  gap: 8px;
  padding: 10px 14px 12px;
  border-top: 1px solid var(--divider);
  background: var(--bg-soft);
  transition: background var(--lib-t), border-color var(--lib-t);
}
.equip-lib-item:hover .equip-lib-actions {
  background: var(--bg-soft-2);
  border-top-color: var(--primary);
}
.equip-lib-actions .glass-btn {
  flex: 1;
  justify-content: center;
  padding: 7px 10px;
  font-size: 12px;
  opacity: .78;
  transition: opacity var(--lib-t), transform var(--lib-t), box-shadow var(--lib-t), color var(--lib-t);
}
.equip-lib-item:hover .equip-lib-actions .glass-btn { opacity: 1; }
.equip-lib-actions .glass-btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.equip-lib-actions .lib-del-btn { color: var(--danger); }
.equip-lib-actions .lib-del-btn:hover { background: var(--danger-soft); }

.star-badge {
  font-size: 10px;
  color: var(--warning);
  padding: 1px 5px;
  background: var(--warning-soft);
  border-radius: var(--radius-xs);
}

/* ==========================================
   Attributes Panel (12 列紧凑网格)
   ========================================== */
.attr-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--divider);
  padding: 0;
}

.attr-item {
  background: var(--bg-card);
  padding: 12px 14px;
  transition: all var(--t-fast);
}
.attr-item:hover { background: var(--bg-soft); }
.attr-item .attr-name {
  font-size: 11px;
  color: var(--text-2);
  margin-bottom: 4px;
}
.attr-item .attr-val {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-1);
}
.attr-item.zero .attr-val { color: var(--text-3); font-weight: 600; }
.attr-item.zero .attr-name { color: var(--text-3); }

/* v7.4.7：三率派生行（直接会心率 / 最终会心率）——强调「最终」为推导结果 */
.attr-item.is-derived .attr-name { color: var(--accent, var(--text-2)); }
.attr-item.is-derived .attr-val { font-size: 13px; line-height: 1.45; }
.attr-item.is-derived .attr-val .attr-num { font-weight: 700; }

/* v7.4.9：面板不再输出「黄字」等说明性单位标记，「最终会心率」直接呈现数值。 */
.attr-item.is-derived .attr-val { font-variant-numeric: tabular-nums; }

/* v7.15.10：调律计算页 · 白字（增益类生效值 ÷1.15 / 三率面板原始值）——
   淡化显示，弱于黄字主值：字号略小、颜色降级、透明度 0.8，不换行。 */
.attr-white {
  margin-left: 3px;
  font-size: 0.88em;
  font-weight: 400;
  color: var(--text-3);
  opacity: 0.8;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.attr-item.zero .attr-white { display: none; }

/* ==========================================
   Xinfa Panel（心法装配）
   ========================================== */
.xinfa-panel { display: flex; flex-direction: column; gap: 10px; }

/* 四个心法位横向并排，高度紧凑 */
.xinfa-list {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

.xinfa-item {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 11px 10px 12px;
  /* 全包围式：四边同为主色边框 */
  background: var(--bg-soft);
  border: 1.5px solid var(--primary);
  border-radius: var(--radius-lg);
  min-height: 168px;
  transition: background var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
}
/* 可选位与固定位外观完全一致，仅鼠标手型 + 悬停提示可换 */
.xinfa-item.is-switchable { cursor: pointer; }
.xinfa-item.is-switchable:hover {
  background: var(--bg-card);
  border-color: var(--primary);
  box-shadow: var(--shadow-sm);
  transform: translateY(-2px);
}
.xinfa-item:not(.is-switchable):hover {
  background: var(--bg-card);
  box-shadow: var(--shadow-xs);
}
.xinfa-item.is-empty { opacity: .6; border-style: dashed; }

.xinfa-no {
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--primary-tint);
  border: 1px solid var(--primary);
  color: var(--primary);
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.xinfa-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }

.xinfa-head {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.xinfa-name-txt {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-1);
  line-height: 1.4;
  word-break: break-all;
}

/* 属性纵向排列，窄栏里更好读 */
.xinfa-attrs {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.xinfa-attr {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px;
  font-size: 10.5px;
  line-height: 1.55;
}
.xinfa-attr-name { color: var(--text-3); min-width: 0; }
.xinfa-attr-val { color: var(--success); font-weight: 700; white-space: nowrap; }
/* 区间值（如 40.5~80.9）比单值略窄，避免窄栏里换行 */
.xinfa-attr-val.xinfa-attr-range { font-size: 10px; letter-spacing: -0.2px; }
.xinfa-attr-empty { font-size: 10.5px; color: var(--text-3); }

/* ==========================================
   Xinfa Picker Modal（心法选择弹窗）
   ========================================== */
.picker-modal { max-width: 460px; width: calc(100vw - 48px); }
.picker-modal .modal-body { display: flex; flex-direction: column; gap: 8px; }

.xinfa-pick-item {
  padding: 10px 12px;
  border-radius: var(--radius-lg);
  background: var(--bg-soft);
  border: 1px solid var(--divider);
  border-left: 3px solid transparent;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
}
.xinfa-pick-item:hover {
  background: var(--bg-card);
  border-color: var(--primary);
  transform: translateX(2px);
}
.xinfa-pick-item.is-on {
  border-left-color: var(--primary);
  background: var(--primary-tint);
}
.xinfa-pick-item .xinfa-name-txt {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-1);
  margin-bottom: 6px;
}
.xinfa-pick-cur {
  font-size: 10px;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 999px;
  line-height: 16px;
  background: var(--primary);
  color: #fff;
}

/* ==========================================
   Suggestions List
   ========================================== */
.suggest-list { padding: 16px 20px; display: flex; flex-direction: column; gap: 10px; }

.suggest-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-left: 3px solid var(--info);
  border-radius: var(--radius-sm);
  transition: all var(--t-fast);
}
.suggest-item:hover { border-color: var(--border-strong); background: var(--bg-card); }
.suggest-item.danger { border-left-color: var(--danger); }
.suggest-item.warning { border-left-color: var(--warning); }
.suggest-item.info { border-left-color: var(--primary); }
.suggest-item.success { border-left-color: var(--success); }

.suggest-icon {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--bg-card);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  font-size: 13px;
}
.suggest-item.danger .suggest-icon { color: var(--danger); }
.suggest-item.warning .suggest-icon { color: var(--warning); }
.suggest-item.info .suggest-icon { color: var(--primary); }

.suggest-content { flex: 1; min-width: 0; }
.suggest-title { font-size: 13px; font-weight: 600; color: var(--text-1); margin-bottom: 2px; }
.suggest-desc { font-size: 12px; color: var(--text-2); line-height: 1.5; }

/* ==========================================
   ★ v7.21.1：满值提醒 —— 可点开只读详情 + 右侧关闭提醒
   §为什么全部复用既有 CSS 变量、不新增颜色变量：
     --danger / --warning / --success 只在 :root 与夜间主题两处被定义，浅色各主题一致；
     而 v7.21.0 刚踩过「--primary 当高亮前景色在浅色主题下对比度仅 2.08」的坑。
     复用既有变量 = 继承既有（已逐主题验证过的）表现，零新增风险。
   ========================================== */
/* 整行可点 → 打开只读装备详情 */
.suggest-item { cursor: pointer; }
.suggest-item:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
/* 关闭提醒按钮：28×28 圆形图标按钮，观感与 .modal-close 一致 */
.suggest-dismiss {
  width: 28px; height: 28px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: all var(--t-fast);
}
.suggest-dismiss:hover { background: var(--bg-card); color: var(--text-1); }
.suggest-dismiss:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

/* ==========================================
   ★ v7.21.1：装备详情（只读）弹窗
   该弹窗内刻意没有任何可编辑控件或会改状态的按钮。
   ========================================== */
.equip-view-info { display: flex; flex-direction: column; gap: 2px; }
.equip-view-note {
  margin: 14px 0 6px;
  padding: 8px 12px;
  font-size: 12px;
  color: var(--text-2);
  background: var(--bg-soft);
  border-left: 3px solid var(--info);
  border-radius: var(--radius-sm);
  line-height: 1.5;
}
.equip-view-group { margin-top: 14px; }
.equip-view-group-title {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: var(--text-2);
  margin-bottom: 6px;
}
.equip-view-group-count {
  font-size: 11px; font-weight: 400; color: var(--text-3);
  background: var(--bg-soft);
  border-radius: 100px;
  padding: 1px 7px;
}
.equip-view-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-soft);
  margin-bottom: 6px;
  font-size: 12.5px;
}
/* 从列表点进来时，目标词条行给一个短暂的高亮，让用户一眼看到点的是哪条 */
.equip-view-row.is-target { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.equip-view-row.is-full { opacity: 0.72; }
.equip-view-kind {
  width: 18px; height: 18px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700;
  border-radius: 4px;
  background: var(--bg-card);
  color: var(--text-2);
}
.equip-view-row.shou .equip-view-kind    { color: var(--primary); }
.equip-view-row.dingyin .equip-view-kind { color: var(--warning); }
.equip-view-name {
  flex: 1; min-width: 0;
  color: var(--text-1); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.equip-view-nums { flex-shrink: 0; color: var(--text-2); font-variant-numeric: tabular-nums; }
.equip-view-nums b { color: var(--text-1); font-weight: 600; }
.equip-view-max { color: var(--text-3); }
.equip-view-gap {
  flex-shrink: 0; min-width: 116px; text-align: right;
  font-size: 12px; font-variant-numeric: tabular-nums;
  color: var(--text-2);
}
/* 缺口分档配色：与列表侧同一套阈值（>10% 红 / >5% 黄 / 其余中性） */
.equip-view-gap.danger  { color: var(--danger); font-weight: 600; }
.equip-view-gap.warning { color: var(--warning); font-weight: 600; }
.equip-view-gap.info    { color: var(--text-2); }
.equip-view-gap.is-full { color: var(--success); font-weight: 600; }
.equip-view-gap.is-dismissed { color: var(--text-3); }
.equip-view-gap.is-none { color: var(--text-3); }
.equip-view-act { flex-shrink: 0; min-width: 76px; text-align: right; }
.equip-view-act-btn {
  border: 1px solid var(--border-strong);
  background: transparent;
  color: var(--text-2);
  font-size: 11.5px;
  padding: 3px 10px;
  border-radius: 100px;
  cursor: pointer;
  transition: all var(--t-fast);
  white-space: nowrap;
}
.equip-view-act-btn:hover { background: var(--bg-card); color: var(--text-1); }
.equip-view-act-btn.is-restore { color: var(--primary); border-color: var(--primary); }

/* 移动端：缺口与按钮换行，避免挤压词条名 */
@media (max-width: 560px) {
  .equip-view-row { flex-wrap: wrap; gap: 6px 8px; }
  .equip-view-name { flex: 1 1 100%; white-space: normal; }
  .equip-view-gap { flex: 1; min-width: 0; text-align: left; }
  .equip-view-act { min-width: 0; }
}

/* ==========================================
   Form Elements
   ========================================== */
.form-group { margin-bottom: 18px; }
.form-group label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-1);
  margin-bottom: 8px;
}

.input, .glass-input {
  width: 100%;
  padding: 10px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  color: var(--text-1);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  transition: all var(--t-fast);
}
.input::placeholder, .glass-input::placeholder { color: var(--text-3); }
.input:focus, .glass-input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(43, 91, 255, 0.12);
}

/* ==========================================================================
   ★ v7.20.13：全部下拉框统一玻璃风
   --------------------------------------------------------------------------
   用户原话：「把所有下拉选择的ui改成一样的玻璃风」。
   改前现状（两处定义完全重复，且都**没有**玻璃质感）：
     `.select` 与 `.glass-select` 各自一份 `background: var(--bg-card)` +
     `border: 1px solid var(--border-strong)` —— 即「不透明白卡 + 深灰硬边框」。
     类名叫 glass，实际观感却是普通白卡，与卡片/导航栏的玻璃语言不一致。
   改法：抽出统一基类，两个类名共用同一份玻璃规则（一处定义全局生效，
         13 个 select 覆盖 index.html / app.js / pzcalc.js 全部来源）。
   玻璃语言对齐既有卡片（见 `.card` / `.app-nav`）：
     · background  : --glass-bg-strong（半透明白）+ --glass-blur 背景模糊
     · border      : --glass-border（白色半透明描边，顶边更亮 --glass-border-strong）
     · box-shadow  : 顶部 1px 高光内阴影，模拟玻璃上沿反光
   ⚠ 注意：`.select-sm` 会覆盖 padding，但**不再重置 background-size**（见下方修复）。
   ========================================================================== */

.select, .glass-select {
  width: 100%;
  padding: 8px 32px 8px 12px;
  /* —— 玻璃底：半透明 + 背景模糊，透出底部炫光/自定义背景图 —— */
  background-color: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);   /* 顶边提亮 = 玻璃上沿反光 */
  color: var(--text-1);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  appearance: none;
  backdrop-filter: var(--glass-blur-light);
  -webkit-backdrop-filter: var(--glass-blur-light);
  /* 自绘箭头（SVG data-uri）。⚠ background-size 在简写外单独声明，
     避免被 .select-sm 等只改 padding 的规则重置成 auto 而压扁箭头。 */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath fill='%2398A1B8' d='M5 7L1 3h8z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 10px 10px;
  /* 玻璃上沿的 1px 高光 + 轻微外阴影，让控件从底面上"浮"起来 */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45),
              0 1px 2px rgba(30, 42, 74, 0.06);
  transition: all var(--t-fast);
}
/* 夜间主题：白色高光在深底上过亮，压到很轻的一层 */
[data-theme="dark"] .select,
[data-theme="dark"] .glass-select {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08),
              0 1px 2px rgba(0, 0, 0, 0.2);
}

.select:hover, .glass-select:hover,
.select:focus, .glass-select:focus {
  border-color: var(--primary);
  border-top-color: var(--primary);
  outline: none;
  /* 展开态：底更实一档 + 主色光圈，与卡片 hover 的提亮同构 */
  background-color: var(--glass-bg-strong);
  box-shadow: 0 0 0 3px rgba(43, 91, 255, 0.12);
}

.form-hint { display: block; font-size: 12px; color: var(--text-3); margin-top: 6px; }

/* ==========================================
   Empty State
   ========================================== */
.empty-hint {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-3);
  font-size: 14px;
}
.empty-hint h3 { font-size: 16px; color: var(--text-2); margin: 8px 0 4px; font-weight: 600; }
.empty-hint p { font-size: 13px; }
/* v7.4.11：心法栏为 4 列 grid，空提示需跨满整行才居中（否则只占第 1 列靠左） */
.xinfa-list .empty-hint.is-full { grid-column: 1 / -1; width: 100%; }

/* ==========================================
   Badge
   ========================================== */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  border-radius: 100px;
  font-size: 11px;
  font-weight: 600;
  background: var(--primary-soft);
  color: var(--primary);
}
.badge.success { background: var(--success-soft); color: var(--success); }
.badge.warning { background: var(--warning-soft); color: var(--warning); }
.badge.danger { background: var(--danger-soft); color: var(--danger); }

/* ==========================================
   Summary (表格式)
   ========================================== */
.summary-section { margin-bottom: 28px; }
.summary-section h3 {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-1);
  margin-bottom: 14px;
  padding-bottom: 8px;
  border-bottom: 2px solid var(--primary);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.summary-section h3 .icon { width: 17px; height: 17px; }
.summary-section h3 .badge { margin-left: 2px; }

.summary-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
}

.summary-stat {
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  text-align: left;
}
.summary-stat .ss-label { font-size: 12px; color: var(--text-2); margin-bottom: 6px; }
.summary-stat .ss-value { font-size: 24px; font-weight: 700; margin-bottom: 4px; color: var(--text-1); }
.summary-stat .ss-value.success { color: var(--success); }
.summary-stat .ss-value.danger { color: var(--danger); }
.summary-stat .ss-sub { font-size: 11px; color: var(--text-3); }

/* 装备排名表格 */
.rank-table {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.rank-row {
  display: grid;
  grid-template-columns: 56px 1fr 80px 80px;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--divider);
  transition: background var(--t-fast);
}
.rank-row:last-child { border-bottom: none; }
.rank-row:hover { background: var(--bg-soft); }
.rank-row.header {
  background: var(--bg-soft);
  font-size: 12px;
  color: var(--text-2);
  font-weight: 600;
}

.rank-slot {
  display: flex;
  align-items: center;
  gap: 8px;
}
.rank-slot-icon {
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px;
  font-weight: 700;
}

/* 各装备满值率排行 */
.equip-rank-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.equip-rank-item {
  display: grid;
  grid-template-columns: 34px 34px 1fr 62px;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base), background var(--t-base);
}
.equip-rank-item:hover {
  transform: translateX(4px);
  background: var(--bg-card);
  border-color: var(--primary);
  box-shadow: var(--shadow-sm);
}
.equip-rank-item .rank-no {
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 800;
  border-radius: var(--radius-sm);
  color: var(--text-2);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  font-variant-numeric: tabular-nums;
}
.equip-rank-item.tone-good .rank-no { color: var(--success); border-color: var(--success); background: var(--success-soft); }
.equip-rank-item.tone-mid  .rank-no { color: var(--warning); border-color: var(--warning); background: var(--warning-soft); }
.equip-rank-item.tone-bad  .rank-no { color: var(--danger);  border-color: var(--danger);  background: var(--danger-soft); }
.equip-rank-item:nth-child(1) .rank-no { box-shadow: 0 0 0 3px var(--primary-tint); }

.equip-rank-item .rank-slot-badge {
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  color: var(--primary);
  background: var(--primary-soft);
  border-radius: 50%;
}
.equip-rank-item .rank-main { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.equip-rank-item .rank-info {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.equip-rank-item .rank-equip-name {
  font-size: 13px; font-weight: 600; color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.equip-rank-item .rank-slot-cat {
  flex: 0 0 auto;
  font-size: 11px; color: var(--text-3);
  padding: 1px 7px;
  border-radius: 100px;
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
}
.equip-rank-item .rank-bar {
  height: 8px;
  background: var(--bg-soft-2);
  border-radius: 100px;
  overflow: hidden;
  box-shadow: inset 0 1px 2px var(--shadow-color);
}
.equip-rank-item .rank-bar-fill {
  height: 100%;
  border-radius: 100px;
  transition: width var(--t-slow);
}
.equip-rank-item .rank-pct {
  font-size: 15px;
  font-weight: 800;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.equip-rank-item .rank-pct.good { color: var(--success); }
.equip-rank-item .rank-pct.mid  { color: var(--warning); }
.equip-rank-item .rank-pct.bad  { color: var(--danger); }

/* 满值提醒（原名「优化建议」，v7.21.1 改名；已移入调律计算页） */
.suggest-section { margin-bottom: 0; }
.suggest-section .suggest-list { max-height: 420px; overflow-y: auto; padding-right: 4px; }

.rank-name { font-size: 13px; color: var(--text-1); font-weight: 500; }
.rank-bar-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}
.rank-bar {
  flex: 1;
  height: 6px;
  background: var(--bg-soft);
  border-radius: 100px;
  overflow: hidden;
}
.rank-bar-fill {
  height: 100%;
  border-radius: 100px;
}
.rank-pct {
  font-size: 13px;
  font-weight: 700;
  min-width: 48px;
  text-align: right;
}
.rank-pct.good { color: var(--success); }
.rank-pct.mid { color: var(--warning); }
.rank-pct.bad { color: var(--danger); }

.rank-status {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 100px;
  text-align: center;
}
.rank-status.good { background: var(--success-soft); color: var(--success); }
.rank-status.mid { background: var(--warning-soft); color: var(--warning); }
.rank-status.bad { background: var(--danger-soft); color: var(--danger); }

/* ==========================================
   Account List
   ========================================== */
.account-list { display: flex; flex-direction: column; gap: 10px; padding: 16px 20px; }

.account-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: all var(--t-fast);
}
.account-item:hover { border-color: var(--primary); background: var(--bg-card); }
.account-item.active { border-color: var(--primary); background: var(--primary-soft); }

.account-avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), #4F7AFF);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700;
  font-size: 16px;
  flex-shrink: 0;
}

.account-info { flex: 1; min-width: 0; }
.account-info .acc-name { font-size: 14px; font-weight: 600; color: var(--text-1); margin-bottom: 2px; }
.account-info .acc-date { font-size: 12px; color: var(--text-3); }

/* ==========================================
   Help
   ========================================== */
.help-content { padding: 20px; }
.help-section { margin-bottom: 28px; }
.help-section h3 {
  font-size: 14px;
  font-weight: 600;
  color: var(--primary);
  margin-bottom: 12px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.help-section ol { padding-left: 22px; line-height: 2; color: var(--text-1); font-size: 13px; }
.help-section ol li { margin-bottom: 4px; }
.help-section p { line-height: 1.8; color: var(--text-1); font-size: 13px; margin-bottom: 8px; }
.help-section strong { color: var(--primary); font-weight: 600; }

/* ---- ★ v7.24.1：帮助页「更新日志」----
   结构（由 app.js 的 renderChangelog 生成）：
     #helpChangelog
       .changelog-item      ← 一个版本
         .changelog-head    ← 版本号 + 日期
           .changelog-ver / .changelog-date
         ul.changelog-list  ← 该版本的条目
   §为什么用「左侧竖线 + 版本号胶囊」而不是表格：
     更新日志是**时间序**的，不是对照关系。表格会诱导人横向比较多列；
     竖排列表天然表达"从上到下越来越新/旧"，与阅读顺序一致。
   §为什么给整块加左细线：这条线把"版本号 + 下面的条目"在视觉上捆成一组，
     否则相邻版本之间只靠间距分隔，条目一多就看不出哪几条属于哪个版本。 */
.help-changelog { position: relative; }
.changelog-item {
  position: relative;
  padding: 0 0 2px 14px;
  margin-bottom: 16px;
  border-left: 2px solid var(--border);
}
/* 最后一个版本不再往下拖尾巴 —— 竖线收在最后一个条目处，避免"下面还有内容"的错觉 */
.changelog-item:last-child { margin-bottom: 4px; }
.changelog-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.changelog-ver {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
}
/* 日期用弱色 —— 它是辅助信息，版本号才是用户扫视时的锚点 */
.changelog-date {
  font-size: 11.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.changelog-list {
  padding-left: 18px;
  margin: 0;
  list-style: disc;
}
.changelog-list li {
  font-size: 13px;
  line-height: 1.75;
  color: var(--text-1);
  margin-bottom: 5px;
}
/* 占位文案：条目为空时显示。§为什么要专门给它样式（而不是复用 .help-section p）：
   它要看起来像"刻意留的位"，不是"忘写的内容" —— 所以用弱色 + 斜体。 */
.changelog-empty {
  font-size: 13px;
  line-height: 1.8;
  color: var(--text-3);
  font-style: italic;
}

/* ==========================================
   Affix Editor (Modal 内)
   ========================================== */
.affix-editor { display: flex; flex-direction: column; gap: 10px; }
.affix-row {
  display: grid;
  /* 固定列宽：序号 | 词条名 | 数值 | 上限提示 | 清空 —— 各行输入框完全对齐 */
  grid-template-columns: 24px minmax(0, 1fr) 92px 118px 32px;
  gap: 8px;
  align-items: center;
}
.affix-order {
  font-size: 12px;
  color: var(--text-3);
  font-weight: 600;
  text-align: center;
}
.affix-order.shou {
  color: var(--primary);
  background: var(--primary-soft);
  border-radius: var(--radius-xs);
  padding: 2px 0;
}
.affix-row.first-affix {
  background: var(--primary-tint);
  border-radius: var(--radius-sm);
}
.affix-row input, .affix-row select {
  padding: 8px 10px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  color: var(--text-1);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-family: inherit;
  width: 100%;
}
.affix-row input:focus { outline: none; border-color: var(--primary); }

/* v7.4.10：三率词条的数值输入框——百分制填写，右侧内嵌「%」 */
.affix-value-wrap {
  position: relative;
  min-width: 0;
}
.affix-value-wrap input[type="number"] {
  padding-right: 24px;   /* 给 % 留位 */
  /* 隐去数字输入框的上下箭头，避免与 % 争空间 */
  -moz-appearance: textfield;
  appearance: textfield;
}
.affix-value-wrap input[type="number"]::-webkit-outer-spin-button,
.affix-value-wrap input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.affix-value-suffix {
  position: absolute;
  right: 9px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12px;
  color: var(--text-3);
  pointer-events: none;
}

/* 词条选择器：点击名称即可更换（替代原来的仅能删除重选） */
.affix-picker { position: relative; min-width: 0; }
/* ★ v7.21.0：按钮玻璃化，与自绘 glassselect 的 trigger 对齐画风。
   改动点（原先用的是 --bg-card + --border-strong 的实心白卡）：
     · 背景换 --glass-bg-strong + backdrop-filter，与 .gs-trigger 一致
     · 边框换 --glass-border / --glass-border-strong（顶部提亮）
     · 加内高光 inset box-shadow
   ⚠ 只改视觉，不动 padding / font-size —— 词条行的高度约束（.affix-row）依赖它。 */
.affix-picker-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  width: 100%;
  padding: 8px 10px;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  color: var(--text-1);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  backdrop-filter: var(--glass-blur-light);
  -webkit-backdrop-filter: var(--glass-blur-light);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45),
              0 1px 2px rgba(30, 42, 74, 0.06);
  transition: all var(--t-fast);
}
:root[data-theme="navy"] .affix-picker-btn {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08),
              0 1px 2px rgba(0, 0, 0, 0.2);
}
.affix-picker-btn:hover {
  border-color: var(--primary);
  background: var(--glass-bg-card);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.affix-picker-btn:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.affix-picker-btn.is-empty .affix-picker-text { color: var(--text-3); }
.affix-picker-text {
  flex: 1 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.affix-picker-caret { flex: 0 0 auto; color: var(--text-3); }
.affix-picker-menu {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  z-index: 60;
  background: var(--bg-modal, var(--bg-card));
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.28);
  overflow: hidden;
}
/* 靠近弹窗底部时向上弹出 */
.affix-picker.drop-up .affix-picker-menu { top: auto; bottom: calc(100% + 4px); }
.affix-picker-search { padding: 6px; border-bottom: 1px solid var(--divider); }
.affix-picker-search input {
  width: 100%; padding: 6px 8px; font-size: 12px;
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: var(--radius-xs); color: var(--text-1);
}
.affix-picker-search input:focus { outline: none; border-color: var(--primary); }
.affix-picker-list { max-height: 168px; overflow-y: auto; overscroll-behavior: contain; padding: 4px; }
.affix-opt {
  padding: 6px 10px; font-size: 12px; border-radius: var(--radius-xs);
  cursor: pointer; color: var(--text-1); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.affix-opt:hover { background: var(--primary-soft); color: var(--primary); }
.affix-opt.active { background: var(--primary-soft); color: var(--primary); font-weight: 600; }
/* 已达上限 / 已被占用 → 打黑不可选 */
.affix-opt.disabled {
  color: var(--text-3);
  background: var(--bg-soft);
  opacity: 0.45;
  cursor: not-allowed;
  text-decoration: line-through;
}
.affix-opt.disabled:hover { background: var(--bg-soft); color: var(--text-3); }
/* 「已满」角标：由 data-locked 驱动，不写入文本，避免影响搜索匹配 */
.affix-opt[data-locked="1"]::after {
  content: "已满";
  display: inline-block;
  margin-left: 6px;
  padding: 0 4px;
  font-size: 10px;
  line-height: 14px;
  font-weight: 700;
  color: var(--danger);
  background: rgba(220, 38, 38, 0.12);
  border: 1px solid rgba(220, 38, 38, 0.35);
  border-radius: 3px;
  vertical-align: middle;
  text-decoration: none;
}
.affix-opt-free { color: var(--primary); font-style: italic; }
.affix-opt-free.disabled { color: var(--text-3); font-style: normal; }

.affix-row input.over-limit {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12);
}

/* 保存时未填写的行高亮提醒 */
.affix-row.row-missing {
  background: rgba(220, 38, 38, 0.10);
  border-radius: var(--radius-xs);
  box-shadow: inset 0 0 0 1px var(--danger);
  animation: rowMissingPulse 0.6s ease-in-out 2;
}
@keyframes rowMissingPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.affix-max-hint {
  font-size: 11px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* v7.4.7：满值缺失类词条（最大气血）——锁定为 0、输入框置灰 */
.affix-max-hint.is-locked { color: var(--warning); }
.affix-row input[type="number"]:disabled {
  background: var(--bg-soft);
  color: var(--text-3);
  cursor: not-allowed;
  opacity: 0.75;
}

.affix-error {
  margin-top: 10px;
  font-size: 12px;
  color: var(--danger);
  min-height: 18px;
}

.affix-remove-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-3);
  width: 32px; height: 32px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all var(--t-fast);
}
.affix-remove-btn:hover { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }

/* OCR 识别区 */
.ocr-box {
  padding: 14px 16px;
  background: var(--primary-tint);
  border: 1px solid rgba(43, 91, 255, 0.15);
  border-radius: var(--radius);
  margin-bottom: 4px;
}
.ocr-box-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--primary);
  margin-bottom: 6px;
}
.ocr-hint {
  font-size: 12px;
  color: var(--text-2);
  margin-bottom: 10px;
  line-height: 1.6;
}
.ocr-hint kbd {
  display: inline-block;
  padding: 1px 6px;
  font-size: 11px;
  font-family: inherit;
  color: var(--text-1);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius-xs);
}
.ocr-box:focus { outline: none; border-color: var(--primary); }
.ocr-status {
  margin-top: 10px;
  font-size: 12px;
  min-height: 18px;
}

/* 定音编辑区：词条下拉与数值输入同一行 */
.dingyin-editor { display: flex; flex-direction: row; align-items: center; gap: 10px; flex-wrap: wrap; }
.dingyin-editor .select { flex: 1 1 160px; min-width: 140px; }
.dingyin-value-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}
.dingyin-value-row .input { width: 110px; }

.detail-row {
  display: flex;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--divider);
  font-size: 13px;
}
.detail-row:last-child { border-bottom: none; }
/* 标签列固定宽度左对齐，值列对齐成一条线 */
.detail-label { color: var(--text-2); flex: 0 0 76px; text-align: left; }
.detail-value { font-weight: 600; color: var(--text-1); flex: 1 1 auto; min-width: 0; text-align: right; }
.detail-row-inline { align-items: center; gap: 16px; }
/* 弹窗内输入/下拉与文字对齐 */
.detail-value-input { display: flex; justify-content: flex-end; }
.detail-value-input .input-sm,
.detail-value-input .select-sm { width: 220px; max-width: 60%; text-align: left; }
.input-sm, .select-sm { padding: 7px 10px; font-size: 13px; }
/* ★ v7.20.13 修复：`.select-sm` 的 padding 简写会把 `.select` 上单独声明的
   `background-size` 一并重置为 auto，导致弹窗内 4 个下拉（装备品质 / 草稿槽位 /
   武器种类 / 定音）的自绘箭头被横向拉伸压扁，与页面其它下拉框观感不一致。
   此处重新声明尺寸与位置，并按小尺寸把右侧留白收窄到 26px。 */
.select-sm {
  padding-right: 26px;
  background-size: 10px 10px;
  background-position: right 9px center;
}
/* 弹窗内联提示：武器种类 / 装备品质的说明文字 */
.weapon-kind-hint {
  font-size: 11px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--text-3);
  text-align: right;
  max-width: 260px;
}

/* 承音装备勾选 */
.chengyin-toggle {
  display: flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  user-select: none;
  font-size: 13px;
  color: var(--text-1);
  font-weight: 600;
}
.chengyin-toggle input { accent-color: var(--primary); width: 15px; height: 15px; cursor: pointer; }
.chengyin-tag {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-2);
  padding: 2px 8px;
  border-radius: 100px;
  background: var(--primary-soft);
}
.level-lock {
  font-size: 11px;
  font-weight: 500;
  color: var(--success);
  padding: 2px 8px;
  border-radius: 100px;
  background: var(--success-soft, var(--primary-soft));
  margin-left: 6px;
}
.chengyin-badge {
  font-size: 10px;
  font-weight: 600;
  color: var(--primary);
  padding: 1px 6px;
  border-radius: 100px;
  background: var(--primary-soft);
  line-height: 1.4;
}
.weapon-kind-badge {
  font-size: 10px;
  font-weight: 600;
  color: #fff;
  padding: 1px 6px;
  border-radius: 100px;
  background: linear-gradient(135deg, #6f4cff 0%, #4f7aff 100%);
  line-height: 1.4;
  letter-spacing: 0.5px;
}

/* 响应式 - 词条编辑 */
@media (max-width: 640px) {
  .affix-row { grid-template-columns: 20px 1fr 70px 32px; }
  .affix-max-hint { display: none; }
}

/* ==========================================
   Modal
   ========================================== */
.modal-overlay {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(5, 8, 18, 0.55);
  backdrop-filter: blur(6px);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  animation: fadeIn 0.2s ease;
  overscroll-behavior: contain;
}
/* 用 class 控制显隐（旧弹窗走 inline style，这里统一起来） */
.modal-overlay.active { display: flex; }

.modal {
  background: var(--bg-card);
  border: 1px solid var(--glass-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  max-width: 520px;
  width: 92%;
  max-height: 86vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: slideUp 0.25s ease;
}
.modal-lg { max-width: 680px; }

.modal-header {
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
}
.modal-header h3 {
  font-size: 16px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
}

.modal-close {
  background: transparent;
  border: none;
  color: var(--text-3);
  width: 28px; height: 28px;
  border-radius: 50%;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all var(--t-fast);
}
.modal-close:hover { background: var(--bg-soft); color: var(--text-1); }

.modal-body { padding: 22px; overflow-y: auto; flex: 1; min-height: 0; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.modal-footer {
  padding: 14px 22px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  flex-shrink: 0;
}

/* 玻璃弹窗（装备/Token 通用）；必须为 flex 列容器，否则内部 .modal-body 无法撑起独立滚动区 */
/* 背景使用 --bg-modal（高不透明度）保证文字清晰可读；不再用 backdrop-filter 以免与炫光背景叠加导致文字模糊 */
.glass-modal {
  background: var(--bg-modal);
  border: 1px solid var(--glass-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  max-width: 520px;
  width: 92%;
  max-height: 86vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: slideUp 0.25s ease;
}
.glass-modal-lg { max-width: 680px; }

/* ==========================================
   Toast
   ========================================== */
#toastContainer {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
}

.toast {
  padding: 12px 18px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 500;
  background: var(--bg-card);
  color: var(--text-1);
  border: 1px solid var(--border);
  border-left: 4px solid var(--info);
  box-shadow: var(--shadow-lg);
  animation: slideIn 0.3s ease;
  pointer-events: auto;
  min-width: 240px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.toast.success { border-left-color: var(--success); color: var(--success); }
.toast.error { border-left-color: var(--danger); color: var(--danger); }
.toast.info { border-left-color: var(--primary); color: var(--primary); }
.toast.warning { border-left-color: var(--warning); color: var(--warning); }

/* ==========================================
   Loading Spinner
   ========================================== */
.spinner {
  display: inline-block;
  width: 16px; height: 16px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  vertical-align: middle;
}

/* ==========================================
   Animations
   ========================================== */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes slideIn { from { transform: translateX(20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }

/* ==========================================
   Responsive
   ========================================== */
@media (max-width: 1024px) {
  .content-grid { grid-template-columns: 1fr; }
  /* 单列布局下不再跟随左栏等高，给固定高度保证属性可见 */
  .right-panel { height: auto; }
  .attr-panel { min-height: 320px; }
  .attr-panel .attr-grid { max-height: 420px; }
  .overview-row { grid-template-columns: repeat(2, 1fr); }
  .equip-grid { flex-direction: column; }
  .equip-col:first-child { border-right: none; }
  .equip-col .equip-slot:last-child { border-bottom: 1px solid var(--divider); }
  .attr-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 768px) {
  .app-nav { padding: 0 14px; gap: 10px; height: auto; flex-wrap: wrap; padding-top: 10px; padding-bottom: 10px; }
  .nav-center { order: 3; width: 100%; justify-content: flex-start; overflow-x: auto; padding-bottom: 4px; }
  .nav-tab { padding: 6px 10px; font-size: 13px; }
  .brand-tag { display: none; }
  .current-account { display: none; }

  .overview-row { grid-template-columns: 1fr 1fr; gap: 10px; }
  .ov-value { font-size: 24px; }
}

@media (max-width: 480px) {
  .overview-row { grid-template-columns: 1fr 1fr; }
  .attr-grid { grid-template-columns: 1fr 1fr; }

  /* v7.5.0：窄屏导航项不得换行成竖排文字条 */
  .nav-tab { white-space: nowrap; flex-shrink: 0; }
  /* v7.5.0：榜单分布条在手机上改为两行（标签独占一行），避免挤压 */
  .rank-bar-row { grid-template-columns: 1fr; gap: 4px; }
  .rank-bar-label { white-space: normal; }
  .rank-bar-val { text-align: left; }
  .rank-periods { gap: 6px; }
  .rank-pill { padding: 6px 12px; font-size: 12px; }
  .rank-toolbar { padding: 10px 14px; gap: 8px; }
  .rank-search { flex: 1 1 100%; }
  .rank-updated { margin-left: 0; width: 100%; }
  .rank-side-card .card-body { padding: 14px; }
}

/* ==========================================
   Theme Panel (主题设置面板)
   ========================================== */
.theme-btn {
  width: 34px; height: 34px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

.theme-panel {
  position: absolute;
  top: 60px;
  right: 20px;
  z-index: 500;
  width: 280px;
  padding: 16px;
  background: var(--bg-card);
  border: 1px solid var(--glass-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  animation: slideUp 0.2s ease;
}

.theme-panel-header {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.theme-section { margin-bottom: 16px; }
.theme-section:last-child { margin-bottom: 0; }
.theme-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  margin-bottom: 8px;
}

.theme-swatches {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.theme-swatch {
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  transition: all var(--t-fast);
  position: relative;
}
.theme-swatch:hover { transform: scale(1.12); }
.theme-swatch.active {
  border-color: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
}

.theme-swatch[data-theme="white"]    { background: linear-gradient(135deg, #ffffff, #e8edf5); border: 2px solid #d5dbe8; }
.theme-swatch[data-theme="sky"]      { background: linear-gradient(135deg, #bae6fd, #7dd3fc); }
.theme-swatch[data-theme="purple"]   { background: linear-gradient(135deg, #c4b5fd, #a78bfa); }
.theme-swatch[data-theme="pink"]     { background: linear-gradient(135deg, #fbcfe8, #f9a8d4); }
.theme-swatch[data-theme="mint"]     { background: linear-gradient(135deg, #a7f3d0, #6ee7b7); }
.theme-swatch[data-theme="cream"]    { background: linear-gradient(135deg, #fde68a, #fcd34d); }
.theme-swatch[data-theme="lavender"] { background: linear-gradient(135deg, #ddd6fe, #c4b5fd); }
.theme-swatch[data-theme="navy"]     { background: linear-gradient(135deg, #2a3142, #12151d); }

.theme-anim {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

.theme-anim-btn {
  padding: 8px 6px;
  background: var(--bg-soft);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: 12px;
  cursor: pointer;
  transition: all var(--t-fast);
  font-family: inherit;
  text-align: center;
}
.theme-anim-btn:hover { border-color: var(--glass-border-strong); color: var(--text-1); }
.theme-anim-btn.active {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
  font-weight: 600;
}

/* ---------- ★ v7.17.1（口述5）：自定义背景 ---------- */
/* 「上传图片 / 恢复默认」两个按钮并排（复用 .theme-anim-btn 外观） */
.theme-bg-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
/* 禁用态（未上传时「恢复默认」不可点） */
.theme-anim-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.theme-anim-btn:disabled:hover {
  border-color: var(--glass-border);   /* 禁用时不给 hover 反馈 */
  color: var(--text-2);
}
.theme-bg-hint {
  margin-top: 8px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-3);
}

/* ==========================================
   文字对齐统一
   ========================================== */
.card-header h2,
.card-header h2 .icon { vertical-align: middle; }

.nav-tab,
.btn, .glass-btn,
.theme-anim-btn,
.baiye-filter-btn { text-align: center; }

.detail-row { align-items: center; }

.affix-row { text-align: left; }

.ov-label, .ov-value, .ov-sub { text-align: center; }

.attr-item { text-align: center; }

.account-item .account-info { text-align: left; }

.equip-slot .slot-info { text-align: left; }

.suggest-item { text-align: left; }

/* ==========================================
   Scrollbar
   ========================================== */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 100px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-3); }
/* ==========================================
   竞速榜单（v7.5.0）
   复用大鹅家现有 CSS 变量，自动适配 8 套主题
   ========================================== */

/* ---------- 期数选择 pill ---------- */
.rank-periods {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.rank-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: 100px;
  color: var(--text-2);
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  backdrop-filter: var(--glass-blur-light);
  -webkit-backdrop-filter: var(--glass-blur-light);
  transition: all var(--t-fast);
}
.rank-pill:hover { border-color: var(--primary); color: var(--primary); }
.rank-pill.active {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--text-inverse);
  font-weight: 600;
  box-shadow: var(--shadow-xs);
}
.rank-pill .rank-pill-tag { font-size: 11px; opacity: 0.75; }
.rank-pill.active .rank-pill-tag { opacity: 0.9; }

/* ---------- 统计卡 ---------- */
.rank-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.rank-cards:empty { display: none; }

.rank-card {
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-xs);
  backdrop-filter: var(--glass-blur-light);
  -webkit-backdrop-filter: var(--glass-blur-light);
  padding: 14px 16px;
  text-align: center;
  transition: transform var(--t-base), box-shadow var(--t-base);
}
.rank-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-sm); }
.rank-card .rk-k { font-size: 12px; color: var(--text-3); margin-bottom: 6px; }
.rank-card .rk-v {
  font-size: 19px;
  font-weight: 700;
  color: var(--text-1);
  line-height: 1.3;
  word-break: break-all;
}
.rank-card .rk-v small {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-3);
  margin-top: 3px;
}

/* ---------- 主布局：左榜右况 ---------- */
.rank-grid { align-items: start; }
.rank-main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.rank-side { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.rank-side-card .card-body { padding: 16px 18px; }

/* ---------- 成绩分段分布 ---------- */
.rank-bars { display: flex; flex-direction: column; gap: 9px; }
.rank-bar-row {
  display: grid;
  grid-template-columns: 150px 1fr 110px;
  align-items: center;
  gap: 12px;
  font-size: 12.5px;
}
.rank-bar-label {
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
.rank-bar-track {
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: 5px;
  height: 18px;
  overflow: hidden;
}
.rank-bar-fill {
  height: 100%;
  border-radius: 4px 0 0 4px;
  background: linear-gradient(90deg, var(--accent-2), var(--primary));
  transition: width 0.4s var(--t-slow);
}
.rank-bar-val { text-align: right; color: var(--text-3); white-space: nowrap; }
.rank-bar-val b { color: var(--text-1); font-weight: 700; }

/* ---------- 榜单工具条 ---------- */
.rank-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 18px;
  border-bottom: 1px solid var(--divider);
  background: var(--bg-soft);
}
.rank-search { width: auto; flex: 0 1 220px; min-width: 150px; padding: 7px 12px; font-size: 13px; }
.rank-chk {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-2);
  cursor: pointer;
  user-select: none;
}
.rank-chk input { accent-color: var(--primary); cursor: pointer; }
.rank-updated { margin-left: auto; font-size: 12px; color: var(--text-3); }

/* ---------- 榜单表格 ---------- */
.rank-table-card .card-header { border-bottom: none; }
.rank-table-wrap { max-height: 620px; overflow: auto; }

.rank-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.rank-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  padding: 10px 18px;
  background: var(--bg-card);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--divider);
  white-space: nowrap;
}
.rank-table tbody td {
  padding: 9px 18px;
  border-bottom: 1px solid var(--divider);
  color: var(--text-1);
  white-space: nowrap;
}
.rank-table tbody tr { transition: background var(--t-fast); }
.rank-table tbody tr:hover { background: var(--bg-soft); }
.rank-table tbody tr.star { background: var(--primary-tint); }

.rank-rk { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--text-2); }
.rank-rk.top1 { color: #c8971f; }
.rank-rk.top2 { color: #8a919b; }
.rank-rk.top3 { color: #b07a4b; }

.rank-delta { font-size: 11px; font-weight: 600; margin-left: 5px; }
.rank-delta.up { color: var(--danger); }
.rank-delta.down { color: var(--success); }
.rank-delta.same { color: var(--text-3); }

.rank-team { max-width: 340px; overflow: hidden; text-overflow: ellipsis; }
.rank-dur { font-variant-numeric: tabular-nums; color: var(--text-2); }

.rank-star-btn {
  border: none;
  background: none;
  padding: 0 4px;
  font-size: 15px;
  line-height: 1;
  color: var(--text-3);
  cursor: pointer;
  opacity: 0.35;
  transition: opacity var(--t-fast), color var(--t-fast);
}
.rank-star-btn:hover { opacity: 0.9; color: var(--warning); }
tr.star .rank-star-btn { opacity: 1; color: var(--warning); }

/* ---------- 概况侧栏 ---------- */
.rank-meta { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.rank-meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
}
.rank-meta-row > span { color: var(--text-3); flex-shrink: 0; }
.rank-meta-row > b {
  color: var(--text-1);
  font-weight: 600;
  text-align: right;
  word-break: break-all;
}
.rank-meta-row > b small {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-3);
  margin-top: 2px;
}
.rank-warn { color: var(--danger); font-size: 11px; font-weight: 500; }

.rank-live {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--text-3);
  padding: 8px 12px;
  background: var(--bg-soft);
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
}
.rank-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--success);
  flex-shrink: 0;
}
.rank-dot.off { background: var(--text-3); }

.rank-refresh { width: 100%; justify-content: center; }

.rank-note p {
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.75;
  margin: 0 0 10px;
}
.rank-note p:last-child { margin-bottom: 0; }
.rank-note strong { color: var(--text-1); }

/* ---------- 响应式 ---------- */
@media (max-width: 900px) {
  .rank-bar-row { grid-template-columns: 108px 1fr 86px; }
  .rank-team { max-width: 180px; }
}

/* ==========================================
   竞速榜单 · 分布图三种形态（v7.5.1）
   ========================================== */

/* ---------- 形态切换器 ---------- */
.rank-chart-switch {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  margin-left: auto;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.rank-chart-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  border: none;
  background: transparent;
  color: var(--text-2);
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  border-radius: var(--radius-xs);
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--t-fast);
}
.rank-chart-btn:hover { color: var(--primary); background: var(--primary-tint); }
.rank-chart-btn.active {
  background: var(--bg-modal);
  color: var(--primary);
  font-weight: 600;
  box-shadow: var(--shadow-xs);
}
.rank-chart-btn .icon-sm { width: 13px; height: 13px; }
.rank-chart-switch + .badge { margin-left: 10px; }

/* ---------- A. 竖向柱状图 ---------- */
.rank-columns {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  padding: 22px 4px 0;
}
.rank-col {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.rank-col-plot {
  position: relative;
  width: 100%;
  height: 190px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
/* 基线 */
.rank-col-plot::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--border-strong);
}
.rank-col-bar {
  position: relative;
  width: 100%;
  max-width: 54px;
  border-radius: 5px 5px 0 0;
  background: linear-gradient(180deg, var(--accent-2), var(--primary));
  transition: height 0.45s var(--t-slow), filter var(--t-fast);
  box-shadow: 0 2px 10px rgba(79, 124, 255, 0.22);
}
.rank-col:hover .rank-col-bar { filter: brightness(1.12); }
.rank-col-num {
  position: absolute;
  top: -19px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
/* 收藏队伍所在段的柱：描边强调 */
.rank-col.is-star .rank-col-bar {
  background: linear-gradient(180deg, #fbbf24, #d97706);
  box-shadow: 0 2px 12px rgba(217, 119, 6, 0.32);
}
.rank-col-x {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  margin-top: 9px;
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  text-align: center;
  width: 100%;
}
.rank-col-x1 { color: var(--text-2); font-weight: 600; }
.rank-col-x2 { opacity: 0.75; }

/* ---------- 悬停 tooltip（柱 / 条共用） ---------- */
.rank-col-tip {
  position: absolute;
  bottom: calc(100% - 148px);
  left: 50%;
  transform: translate(-50%, -6px);
  z-index: 20;
  min-width: 150px;
  padding: 9px 12px;
  background: var(--bg-modal);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--t-fast), transform var(--t-fast), visibility var(--t-fast);
}
.rank-col:hover .rank-col-tip {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, -10px);
}
.rank-dt-range {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-1);
  margin-bottom: 6px;
  white-space: nowrap;
}
.rank-dt-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  font-size: 12px;
  color: var(--text-3);
  line-height: 1.7;
}
.rank-dt-row b { color: var(--text-1); font-weight: 600; font-variant-numeric: tabular-nums; }
.rank-dt-star {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--divider);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--warning);
}

/* 横向条形态下的收藏标记 */
.rank-bar-row { position: relative; }
.rank-bar-row.is-star .rank-bar-fill {
  background: linear-gradient(90deg, #fbbf24, #d97706);
}
.rank-bar-row.is-star .rank-bar-label { color: var(--text-1); font-weight: 600; }
.rank-star-mark { color: var(--warning); font-weight: 600; }

/* ---------- C. 环形图 ---------- */
.rank-charts.mode-donut {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 24px;
}
.rank-donut-wrap { position: relative; width: 176px; height: 176px; flex-shrink: 0; }
.rank-donut { width: 100%; height: 100%; display: block; }
.rank-donut-seg { transition: stroke-width var(--t-fast), opacity var(--t-fast); cursor: pointer; }
.rank-donut-seg:hover { opacity: 0.8; }
.rank-donut-seg.is-star { filter: drop-shadow(0 0 5px rgba(217, 119, 6, 0.55)); }
.rank-donut-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.rank-donut-center .rdc-k { font-size: 11px; color: var(--text-3); margin-bottom: 3px; }
.rank-donut-center .rdc-v {
  font-size: 17px;
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}

.rank-legend { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.rank-legend-item {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
  color: var(--text-2);
  padding: 4px 8px;
  border-radius: var(--radius-xs);
  transition: background var(--t-fast);
}
.rank-legend-item:hover { background: var(--bg-soft); }
.rank-legend-item.is-star { background: var(--warning-soft); }
.rank-legend-dot { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.rank-legend-lb {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
.rank-legend-v {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.rank-legend-item.is-star .rank-legend-v { color: var(--text-1); font-weight: 600; }

/* ---------- 响应式 ---------- */
@media (max-width: 900px) {
  .rank-columns { gap: 7px; padding-top: 20px; }
  .rank-col-plot { height: 150px; }
  .rank-col-x { font-size: 10px; }
  .rank-charts.mode-donut { grid-template-columns: 1fr; justify-items: center; gap: 16px; }
  .rank-legend { width: 100%; }
  /* v7.5.1：窄屏下 tooltip 固定 150px 宽会让首尾柱的提示框越出视口，
     触发横向滚动。改为跟随柱宽并左对齐，同时不再撑破容器。 */
  .rank-col-tip { left: 0; right: auto; transform: translate(0, -6px); min-width: 0; width: max-content; max-width: 132px; }
  .rank-col:hover .rank-col-tip { transform: translate(0, -10px); }
  .rank-col:last-child .rank-col-tip { left: auto; right: 0; }
  .rank-columns { overflow: visible; }
  .rank-dist-card { overflow: hidden; }
}

@media (max-width: 480px) {
  .rank-chart-btn { padding: 5px 8px; }
  .rank-col-num { font-size: 11px; top: -17px; }
  .rank-col-x { font-size: 9.5px; }
  .rank-col-plot { height: 130px; }
  .rank-donut-wrap { width: 150px; height: 150px; }

  /* v7.5.1：窄屏下分布卡头部改为两行（标题一行、切换器+徽章一行），
     否则标题会被切换器挤成竖排文字条并撑出横向溢出 */
  .rank-dist-card .card-header { flex-wrap: wrap; row-gap: 8px; }
  .rank-dist-card .card-header h2 { flex: 1 1 100%; white-space: nowrap; }
  .rank-chart-switch { margin-left: 0; }
  .rank-chart-switch + .badge { margin-left: auto; }
  /* 切换器按钮只留图标，省空间 */
  .rank-chart-btn .btn-txt { display: none; }
  .rank-chart-btn { padding: 6px 10px; }
  .rank-chart-btn .icon-sm { width: 15px; height: 15px; }
}

/* ==========================================
   竞速榜单 · 「只看收藏」气泡开关（v7.5.2）
   ========================================== */
.rank-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px 5px 6px;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: 100px;
  color: var(--text-2);
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: all var(--t-fast);
}
.rank-toggle:hover { border-color: var(--primary); color: var(--primary); }

/* 滑块 */
.rank-toggle-knob {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--bg-soft);
  color: var(--text-3);
  transition: all var(--t-fast);
  flex-shrink: 0;
}
.rank-toggle-knob .icon-sm { width: 13px; height: 13px; }

/* 收藏数角标 */
.rank-toggle-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 6px;
  border-radius: 100px;
  background: var(--primary-soft);
  color: var(--primary);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* 选中态：整颗变主色，滑块亮起 */
.rank-toggle.active {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
  font-weight: 600;
}
.rank-toggle.active .rank-toggle-knob {
  background: var(--primary);
  color: var(--text-inverse);
  box-shadow: 0 1px 6px rgba(79, 124, 255, 0.4);
}
.rank-toggle.active .rank-toggle-n {
  background: var(--primary);
  color: var(--text-inverse);
}

/* 深色主题下角标在选中态同样反白 */

/* ==================== 破竹尘计算器 (v7.5.4) ==================== */
.pz-grid { grid-template-columns: 1.2fr 1fr; align-items: start; }
@media (max-width: 980px) { .pz-grid { grid-template-columns: 1fr; } }

.pz-card-wide { margin-top: 14px; }
.pz-form { display: flex; flex-direction: column; gap: 8px; }

.pz-subtitle {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: 0.04em;
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.pz-subtitle::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border-soft, rgba(128, 128, 128, 0.18));
}

.pz-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
.pz-row-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 720px) {
  .pz-row, .pz-row-3 { grid-template-columns: repeat(2, 1fr); }
}
.pz-row label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--text-2);
  min-width: 0;
}
.pz-row .glass-input, .pz-row .glass-select {
  width: 100%;
  height: 34px;
  padding: 0 10px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.pz-row-sys { grid-template-columns: 52px repeat(4, 1fr); align-items: end; }
@media (max-width: 720px) { .pz-row-sys { grid-template-columns: 52px repeat(2, 1fr); } }
.pz-sys-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--primary);
  display: flex;
  align-items: center;
  height: 34px;
}
.pz-span2 { grid-column: span 2; }

/* 衍生只读格（原表公式位） */
.pz-locked .glass-input {
  color: var(--text-3);
  background: var(--surface-dim, rgba(128, 128, 128, 0.08));
  cursor: not-allowed;
}

/* √ / × 分段开关 */
.pz-seg {
  display: inline-flex;
  height: 34px;
  border: 1px solid var(--border-soft, rgba(128, 128, 128, 0.25));
  border-radius: 9px;
  overflow: hidden;
  background: var(--surface-dim, rgba(128, 128, 128, 0.06));
}
.pz-seg-btn {
  flex: 1;
  min-width: 44px;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.pz-seg-btn + .pz-seg-btn { border-left: 1px solid var(--border-soft, rgba(128, 128, 128, 0.25)); }
.pz-seg-btn.active {
  background: var(--primary);
  color: var(--text-inverse, #fff);
}

/* 毕业率卡 */
.pz-rate-card .ov-value { font-size: 34px; }
.pz-rate-good { color: #16a34a; }
.pz-rate-mid { color: #d97706; }
.pz-rate-low { color: #dc2626; }
.pz-delta {
  font-size: 11px;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
.pz-delta.is-up { color: #16a34a; }
.pz-delta.is-down { color: #dc2626; }

/* 高级折叠 */
.pz-adv { margin-top: 6px; }
.pz-adv-toggle {
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 0;
  display: flex;
  align-items: center;
  gap: 4px;
}
.pz-adv-toggle:hover { color: var(--primary); }
.pz-adv-arrow { display: inline-block; width: 12px; }
.pz-adv-body { padding-top: 6px; }

/* 助手带出徽标 + 锁定控件（v7.5.4） */
.pz-auto-badge {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px;
  border-radius: 100px;
  background: var(--primary-soft, rgba(79, 124, 255, 0.12));
  color: var(--primary);
  font-size: 10px;
  font-weight: 700;
  vertical-align: middle;
  white-space: nowrap;
}
.pz-locked-input {
  opacity: 0.75;
  cursor: not-allowed !important;
}

/* 流派选择行（v7.6.0） */
.pz-school-card { margin-bottom: 14px; }
.pz-school-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.pz-school-label {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary, inherit);
  white-space: nowrap;
}
.pz-school-sel {
  min-width: 260px;
  max-width: 100%;
}
.pz-school-hint {
  font-size: 11px;
  color: var(--text-secondary, rgba(128, 128, 128, 0.8));
}
@media (max-width: 640px) {
  .pz-school-row { gap: 8px; }
  .pz-school-sel { min-width: 0; flex: 1; }
}

/* ==================== 流派天赋（v7.8.0） ==================== */
.talent-panel .talent-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: pointer; user-select: none; font-size: 12px; color: var(--text-secondary, #5a7395);
}
.talent-panel .talent-toggle input { accent-color: var(--primary, #2B5BFF); width: 15px; height: 15px; cursor: pointer; }
.talent-list { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.talent-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 14px; border-radius: 10px;
  background: var(--bg-secondary, rgba(120, 160, 255, 0.06));
  border: 1px solid var(--border-color, rgba(120, 160, 255, 0.14));
}
.talent-item.is-off { opacity: 0.45; }
.talent-name { font-size: 13px; font-weight: 600; color: var(--text-primary, #22334d); }
.talent-desc { font-size: 11px; color: var(--text-secondary, #5a7395); margin-top: 2px; }
.talent-val { font-size: 13px; font-weight: 700; color: var(--primary, #2B5BFF); white-space: nowrap; }
.talent-full { font-style: normal; font-size: 10px; color: #fff; background: var(--success, #2fa86a);
  border-radius: 6px; padding: 1px 5px; margin-left: 5px; vertical-align: 1px; }
@media (max-width: 900px) { .talent-list { grid-template-columns: 1fr; } }

/* ==================== 套装选择 + 流派天赋二级弹层（v7.9.0） ==================== */
.attr-header-ctrls { display: flex; align-items: center; gap: 8px; min-width: 0; }
.set-select {
  max-width: 150px; height: 30px; padding: 0 26px 0 10px; font-size: 12px;
  border-radius: 8px; cursor: pointer;
}
.set-select:disabled { opacity: 0.5; cursor: not-allowed; }
.talent-link {
  height: 30px; padding: 0 10px; font-size: 12px; font-weight: 600; white-space: nowrap;
  color: var(--primary, #2B5BFF); background: transparent;
  border: 1px solid var(--border, rgba(43,91,255,0.28)); border-radius: 8px; cursor: pointer;
  transition: background 0.15s ease;
}
.talent-link:hover { background: rgba(43, 91, 255, 0.08); }
.talent-modal { max-width: 560px; width: calc(100vw - 48px); }
.talent-modal .modal-header { display: flex; align-items: center; justify-content: space-between; }
.talent-modal-head-right { display: flex; align-items: center; gap: 10px; }
.talent-modal-head-right .talent-toggle { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-secondary, #5a7395); cursor: pointer; }
.talent-modal-head-right .talent-toggle input { accent-color: var(--primary, #2B5BFF); width: 15px; height: 15px; cursor: pointer; }
.talent-modal-body { max-height: 62vh; }
@media (max-width: 900px) {
  .set-select { max-width: 120px; }
  .attr-header-ctrls { flex-wrap: wrap; }
}
.bow-select { max-width: 110px; }
@media (max-width: 900px) { .bow-select { max-width: 96px; } }

/* ==================== 武器槽位选择弹层（v7.11.0） ==================== */
.ws-slot-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 16px; text-align: left; cursor: pointer;
}
.ws-slot-btn .ws-slot-name { font-size: 14px; font-weight: 700; color: var(--text-1, #1d2b45); }
.ws-slot-btn .ws-slot-state { font-size: 12px; color: var(--text-secondary, #5a7395); }
.ws-slot-btn.is-occupied .ws-slot-state { color: var(--warning, #d4881f); }
.ws-slot-btn:hover { background: rgba(43, 91, 255, 0.08); }

/* ==================== 配装分享弹窗（v7.12.0） ==================== */
.transfer-textarea {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--border-1, rgba(148, 163, 184, 0.35));
  border-radius: 10px;
  background: var(--bg-2, rgba(248, 250, 252, 0.85));
  color: var(--text-2, #334155);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px;
  line-height: 1.5;
  padding: 8px 10px;
  resize: vertical;
  outline: none;
}
.transfer-textarea:focus { border-color: var(--primary, #0ea5e9); }
.transfer-textarea[readonly] { background: var(--bg-1, rgba(241, 245, 249, 0.6)); color: var(--text-3, #64748b); }

/* ==========================================
   v7.13.0 · 角色工具条（调律计算页右上角）
   ========================================== */
.calc-account-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 16px;
  margin-bottom: 14px;
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.calc-acc-left { display: flex; align-items: center; gap: 12px; min-width: 0; }

.calc-acc-avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), #4F7AFF);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px;
  flex-shrink: 0;
}
.calc-acc-avatar.is-empty { background: var(--bg-soft); color: var(--text-3); border: 1px dashed var(--border); }

.calc-acc-info { min-width: 0; }
.calc-acc-name {
  font-size: 14px; font-weight: 600; color: var(--text-1);
  display: flex; align-items: center; gap: 6px;
}
.calc-acc-name .calc-acc-tag {
  font-size: 10px; font-weight: 500; color: var(--primary);
  background: var(--primary-soft); border-radius: 4px; padding: 1px 5px;
}
.calc-acc-sub {
  font-size: 11.5px; color: var(--text-3); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.calc-acc-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.calc-acc-switcher { display: none; }
.calc-acc-switcher.is-shown { display: block; }
.calc-acc-switcher .glass-select { min-width: 150px; max-width: 220px; padding: 5px 10px; font-size: 12px; }

/* 角色管理弹窗内：新建行 + 列表标题 + 行内重命名 */
.acc-create-row { display: flex; gap: 8px; }
.acc-create-row .glass-input { flex: 1; min-width: 0; }
.acc-create-row .glass-btn { flex-shrink: 0; white-space: nowrap; }

/* ---- ★ v7.24.1：新建角色时的名称辨识建议 ----
   §为什么是"建议"样式（左细边 + 弱底）而不是"警告"样式（黄/红）：
     这是一条**不影响能否创建**的提示。用警告色会让用户以为"名字不合格"，
     继而在一个没有正确答案的问题上反复纠结（什么才算"够辨识"？）。
   §为什么不做成可关闭：它在创建角色这一屏只占一行半，且这是用户
     唯一会因为这句话而改名的时机；可关闭等于默认被关掉。 */
.acc-name-tip {
  margin-top: 8px;
  padding: 8px 10px;
  font-size: 11.5px;
  line-height: 1.75;
  color: var(--text-3);
  background: var(--bg-soft);
  border-left: 2px solid var(--accent-2);
  border-radius: 0 6px 6px 0;
}
.acc-name-tip b { color: var(--text-2); }

.acc-list-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 600; color: var(--text-2);
  margin: 18px 0 6px;
}
.acc-list-title .badge { font-size: 11px; }

#modalAccount .account-list { padding: 0; max-height: 42vh; overflow: auto; }
#modalAccount .account-item { padding: 10px 12px; gap: 10px; }
#modalAccount .account-avatar { width: 32px; height: 32px; font-size: 14px; }
#modalAccount .account-info .acc-date { font-size: 11px; }

.acc-name-input {
  width: 100%;
  font-size: 14px; font-weight: 600; color: var(--text-1);
  background: var(--bg-card);
  border: 1px solid var(--primary);
  border-radius: var(--radius-sm);
  padding: 3px 7px;
  outline: none;
}

.acc-row-actions { display: flex; gap: 6px; flex-shrink: 0; }
.acc-row-actions .glass-btn { padding: 4px 8px; font-size: 11.5px; }
.acc-row-actions .acc-del-btn { color: var(--danger); }
.acc-row-actions .acc-del-btn:hover { background: var(--danger-soft); }

/* 通用确认弹窗（v7.13.0） */
.glass-modal-sm { max-width: 420px; }
.confirm-msg {
  font-size: 13.5px; line-height: 1.7; color: var(--text-2);
  margin: 0; white-space: pre-wrap; word-break: break-word;
}

@media (max-width: 720px) {
  .calc-account-bar { padding: 8px 12px; }
  .calc-acc-actions { width: 100%; justify-content: flex-end; }
}

/* ==========================================================================
   自动配装弹窗（v7.15.0）
   全部颜色走 CSS 变量，兼容 8 套主题（white/sky/purple/navy/mint/cream/lavender/pink）
   ========================================================================== */

/* 概览卡上的入口按钮（v7.15.1：入口在「调律计算」页的「综合毕业率」卡） */
.pz-autoplan-btn {
  margin-top: 10px;
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
/* 概览卡比毕业率卡窄，按钮字号与内边距要收一档才不会换行 */
.overview-card .pz-autoplan-btn {
  margin-top: 8px;
  font-size: 11px;
  padding: 5px 8px;
  white-space: nowrap;
}
.overview-card .pz-autoplan-btn .icon-sm {
  width: 12px;
  height: 12px;
}

/* 弹窗外壳：比常规 picker 宽，容纳 10 张配装卡 */
.autoplan-modal {
  max-width: 760px;
  width: 94%;
}
.autoplan-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: 76vh;
  overflow: auto;
}

/* —— 前置条件不满足时的空态 —— */
.autoplan-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 28px 12px;
  text-align: center;
  color: var(--text-1);
}
.autoplan-empty p { margin: 0; line-height: 1.7; }
.autoplan-missing {
  font-weight: 700;
  color: var(--warning);
  font-size: 15px;
}

/* —— 初始态 —— */
.autoplan-intro { display: flex; flex-direction: column; gap: 16px; }
.autoplan-lead { margin: 0; line-height: 1.75; color: var(--text-1); }

/* ★ v7.21.2：候选规模指标块 —— 「理论组合数 / 装备库候选」并排，重点数字放大。
   原设计只是一行 .form-hint，组合数还说成「约 15.4 万」，不如直接给精确值和分项。 */
.autoplan-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.autoplan-metric {
  padding: 12px 14px;
  border-radius: var(--radius);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  min-width: 0;
}
.autoplan-metric.is-primary {
  background: linear-gradient(135deg, var(--primary-soft), transparent 70%), var(--glass-bg-strong);
  border-color: var(--primary);
}
.autoplan-metric-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-3);
  margin-bottom: 6px;
}
.autoplan-metric-value {
  font-size: 24px;
  font-weight: 800;
  line-height: 1.15;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
  word-break: break-all;
}
.autoplan-metric.is-primary .autoplan-metric-value { color: var(--primary); }
.autoplan-metric-unit {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  margin-left: 4px;
}
.autoplan-metric-sub {
  margin-top: 5px;
  font-size: 11.5px;
  color: var(--text-2);
  line-height: 1.5;
}

/* 区块标题（各槽位候选 / 配装明细 等） */
.autoplan-section { display: flex; flex-direction: column; gap: 8px; }
.autoplan-section-title {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-3);
}

.autoplan-slots {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.autoplan-slot-chip {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.autoplan-slot-chip.is-worn {
  color: var(--text-2);
  border-style: dashed;
}
.autoplan-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  padding-top: 2px;
}
/* 主按钮在弹窗里独占一行更醒目 */
.autoplan-run-btn { flex: 1 1 200px; }

/* ==================== v7.18.0：自动求解「考虑弓箭套装」勾选项 ====================
   需求原文：「调律计算页面自动求解最佳装备需要勾选是否考虑弓箭套装。」
   ★ v7.21.2 起：候选收敛为 BOWS 三把弓（会心 / 精准 / 会意），不再含「无弓」。
   视觉上做成一条可点整行的选项条：勾选框 + 标题 + 说明（说明里写明会挑哪几把弓）。
   勾选时整条高亮（.is-on），让"求解维度已扩展"这件事一眼可见。 */
.autoplan-opt-line {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius);
  background: var(--divider); border: 1px solid var(--glass-border);
  cursor: pointer; font-size: 13px; color: var(--text-1);
  transition: border-color .2s ease, background .2s ease;
}
.autoplan-opt-line:hover { border-color: var(--primary); }
.autoplan-opt-line.is-on {
  border-color: var(--primary);
  background: linear-gradient(135deg, var(--primary-soft), transparent 70%), var(--divider);
}
.autoplan-opt-line input {
  width: 16px; height: 16px; margin-top: 2px;
  accent-color: var(--accent, #6b8afd); cursor: pointer; flex: 0 0 auto;
}
.autoplan-opt-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 auto; }
.autoplan-opt-title { font-weight: 600; }
.autoplan-opt-desc { font-size: 12px; color: var(--text-2); line-height: 1.6; }
.autoplan-opt-desc b { color: var(--text-1); }

/* 结果卡上的「弓箭」标签（勾选求解时才出现） */
.ap-bow-tag {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--text-2);
  background: var(--divider); padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--glass-border);
}
.ap-bow-tag .icon-sm { width: 11px; height: 11px; }

/* —— 进度条 —— ★ v7.21.2：加标题行（状态点 + 文案 + 百分比） */
.autoplan-progress { display: flex; flex-direction: column; gap: 8px; }
.autoplan-progress-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--text-2);
}
.autoplan-progress-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  background: var(--accent-1, var(--primary));
  box-shadow: 0 0 0 0 var(--primary-soft);
  animation: autoplan-pulse 1.4s ease-out infinite;
}
@keyframes autoplan-pulse {
  0%   { box-shadow: 0 0 0 0 var(--primary-soft); }
  70%  { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.autoplan-progress-text { flex: 1; min-width: 0; }
.autoplan-progress-pct {
  flex: 0 0 auto; font-variant-numeric: tabular-nums;
  font-weight: 700; color: var(--text-1);
}
.autoplan-bar {
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
}
.autoplan-bar-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-1), var(--accent-2));
  transition: width 0.25s ease;
}

/* —— 结果态 —— */
/* ★ v7.21.3：结果头做「粘性」处理 —— 长列表滚到第 8 张卡时，
   「N 套候选配装 / 耗时 / 精算次数」这些信息就看不到了，用户会忘记自己在看第几套。
   吸顶后始终可见，同时给它一层毛玻璃底避免与下方卡片文字叠色。 */
.autoplan-result-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 0 0 10px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--divider);
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--glass-bg-strong, var(--glass-bg));
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.autoplan-result-title {
  display: flex; align-items: baseline; gap: 5px; flex: 0 0 auto;
}
.autoplan-result-count {
  font-size: 21px; font-weight: 800; line-height: 1;
  color: var(--primary);
  font-variant-numeric: tabular-nums;
}
.autoplan-result-count-unit { font-size: 12.5px; color: var(--text-2); }
.autoplan-result-stats { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; }
.ap-stat-chip {
  font-size: 11px; color: var(--text-2);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  padding: 2px 9px; border-radius: 999px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ap-stat-chip b { color: var(--text-1); font-weight: 700; }
.ap-budget-note {
  font-size: 11px; color: var(--warning);
  background: var(--warning-soft, rgba(240, 173, 78, .14));
  padding: 2px 9px; border-radius: 999px; flex: 0 0 auto;
}
.autoplan-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.ap-card {
  border-radius: 12px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  padding: 11px 14px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.ap-card:hover { border-color: var(--primary); }
/* ★ v7.21.3：最优卡改用「左上角渐变光晕」而非整块渐变底 ——
   整块渐变在长列表里会让第一张卡和其余卡的底色断层，观感割裂。 */
.ap-card.is-best {
  border-color: var(--success);
  background:
    radial-gradient(120% 90% at 0% 0%, var(--success-soft, rgba(76, 175, 80, .16)), transparent 55%),
    var(--glass-bg);
  box-shadow: 0 0 0 1px var(--success-soft), 0 6px 18px -8px var(--success);
}
/* ★ v7.21.3：非最优卡的左侧色条原来 3px 实色，在长列表里非常抢眼、像警告。
   改为 2px 半透明，保留「一眼分辨档位」的作用但不喧宾夺主。
   最优卡不参与着色（它已有绿色边框 + 光晕 + ★ 三重标识）。 */
.ap-card.tone-mid { border-left: 2px solid color-mix(in srgb, var(--warning) 55%, transparent); }
.ap-card.tone-bad { border-left: 2px solid color-mix(in srgb, var(--danger) 55%, transparent); }
.ap-card.tone-good.is-best { border-left: 1px solid var(--success); }

.ap-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.ap-rank {
  display: flex; align-items: center; gap: 2px;
  font-weight: 800;
  font-size: 15px;
  color: var(--text-2);
  min-width: 40px;
  font-variant-numeric: tabular-nums;
}
.ap-rank-crown { color: var(--success); font-size: 12px; }
.ap-rate-wrap { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ap-rate-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ap-rate { font-weight: 800; font-size: 21px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.ap-tone-chip {
  font-size: 10.5px; font-weight: 600; padding: 1px 7px; border-radius: 999px;
  border: 1px solid currentColor; opacity: .85;
}
.ap-tone-chip.tone-good { color: var(--success); }
.ap-tone-chip.tone-mid { color: var(--warning); }
.ap-tone-chip.tone-bad { color: var(--danger); }
.ap-rate-sub { font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; }
/* ★ v7.21.2：差值从「灰色小字」升级为可辨识的徽章 */
.ap-delta-under {
  font-size: 11.5px; color: var(--warning);
  background: var(--warning-soft, rgba(240, 173, 78, .14));
  padding: 1px 8px; border-radius: 999px; font-variant-numeric: tabular-nums;
}
.ap-delta-best {
  font-size: 11.5px; color: var(--success);
  background: var(--success-soft, rgba(76, 175, 80, .14));
  padding: 1px 8px; border-radius: 999px;
}
.ap-apply { flex-shrink: 0; }

.ap-items {
  margin-top: 2px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 14px;
}
/* v7.15.0：每件装备 = 主行（槽 · 名称 · 满值率）+ 其下词条列表 */
.ap-item {
  display: block;
  font-size: 11.5px;
  min-width: 0;
}
.ap-item-main {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
/* 词条列表：缩进对齐在槽位徽章右侧
   ★ v7.21.3：行距 1.5 → 1.34、gap 1px → 0，单件装备省下约 6px，
   8 件累计约 48px —— 这是把整卡从 ~500px 压到 ~430px 的主要来源。 */
.ap-item-affixes {
  margin: 2px 0 0 38px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.ap-affix-row {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  line-height: 1.34;
  min-width: 0;
  color: var(--text-2);
}
.ap-affix-kind {
  flex-shrink: 0;
  width: 14px;
  text-align: center;
  font-size: 10px;
  border-radius: 3px;
  background: var(--glass-bg-strong);
  color: var(--text-3);
}
.ap-affix-row.shou .ap-affix-kind { color: var(--warning); }
.ap-affix-row.dingyin .ap-affix-kind { color: var(--primary); }
.ap-affix-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ap-affix-val { flex-shrink: 0; color: var(--text-1); font-variant-numeric: tabular-nums; }

/* 结果卡两栏：左「配装明细」/ 右「面板属性」
   ★ v7.21.3：左列明显更高（8 件 × 4 词条）会把整卡撑到 500px，一屏只能看 2 张。
   这里把栏宽改成 1.35 : 1 —— 左列吃宽、词条行更宽松，右栏面板属性本身是
   双列短行，不需要那么宽，收回来的宽度正好给左列。 */
.ap-body {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 16px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--divider);
}
.ap-left, .ap-right { min-width: 0; }
.ap-sec-title {
  display: flex; align-items: center; gap: 5px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: .06em;
  margin-bottom: 5px;
}
/* 小标题前的竖条，让「配装明细 / 面板属性」两块有明确的分区感 */
.ap-sec-title::before {
  content: '';
  width: 2px; height: 10px; border-radius: 1px;
  background: currentColor; opacity: .45;
}
/* 面板属性列：★ v7.21.3 起改为「只列有值项 + 全平铺」，不再滚动。
   数据侧已在 renderApPanel 过滤零值行，这里同步去掉 max-height / overflow，
   让整列跟随卡片自然增高，用户不必下拉即可看全。 */
/* ★ v7.21.3：自适应双列 —— 短名（三率 / 四维）双列并排，长名（攻击 / 区间）独占整行。
   §为什么不是纯双列也不是纯单列：
     · 纯双列：每列仅 ~159px，而「外功攻击 2478.6~4290.0」的数值就 ~95px，
       名称被压成「外…」「无相攻…」——实测信息直接丢失。
     · 纯单列：每行 ~330px，20 行撑到 480px，比左列高出一大截，卡片反而胖了 155px。
   §做法：用 grid 的 span 2 让「名字 + 数值」估算宽度超标的行跨两列。
     判定交给 JS（见 renderApPanel 的 attr-item.is-wide），CSS 只负责布局 ——
     CSS 拿不到文本宽度，用 :has()/ch 猜都不稳。 */
/* ★ v7.21.3：中缝加一条极淡的竖分隔线。
   §为什么需要：双列各 156.7px、列间距 12px，两个「名 值」对贴太近时
     （如「外功攻击 2478.6~4296.0」紧邻「鸣金攻击 539~1468.4」），
     眼睛会跨列连读。一条 1px 淡线把两列物理隔开，成本远低于加宽间距。
   用 background 画在列间空档，不占布局宽度、不影响 is-wide 行的跨列。 */
.ap-panel {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 18px;
  background-image: linear-gradient(var(--divider), var(--divider));
  background-size: 1px 100%;
  background-position: calc(50% - 9px) 0;
  background-repeat: no-repeat;
}
.ap-panel .attr-item.is-wide { grid-column: 1 / -1; }
/* ★ v7.21.3：19~20 行双列排下来，「名 ……… 值」容易串行看错。
   加一条极淡的点状引导线把名称和数值连起来，视觉上锁死配对关系。 */
.ap-panel .attr-item {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 6px;
  font-size: 11px;
  line-height: 1.42;
  min-width: 0;
  padding: 0 3px;
  border-radius: 4px;
  transition: background 0.15s ease;
}
.ap-panel .attr-item:not(.zero):hover { background: var(--glass-bg-strong); }
/* ★ v7.21.3：attr-name 不再收缩（flex: 0 0 auto）。
   §为什么：原来 flex: 0 1 auto + overflow:hidden，在 flex 收缩时**最先被砍**，
     于是「外功攻击」变「外…」——信息直接丢失且没有任何提示。
     ⚠ 改法不是简单去掉 overflow —— 名称宁可撑破也不能静默截断（截断是不可逆的信息损失）。
       真正兜底交给 renderApPanel 的 is-wide：宽度不够的行整行跨两列。
       这里去掉 overflow/ellipsis，让「万一没被判定为 wide」的行**溢出可见**，
       而不是伪装成正常行 —— 视觉上难看但能被测试发现，比静默丢字安全。
   ⚠ 保留 white-space: nowrap：名称本身不允许折行，折行会让行高不一致。 */
.ap-panel .attr-name {
  color: var(--text-3);
  flex: 0 0 auto;
  white-space: nowrap;
}
/* ★ v7.21.3：名称与数值之间的点状引导线。
   §为什么用 flex:1 的独立元素而不是 ::after 撑宽 —— 上一版把引导线做成
     attr-name 的 ::after 并给 width:100%，它会把有限宽度全部吃掉，
     于是「外功攻击」被压成「外…」「无相攻…」——信息全丢了。
     改成兄弟节点后，引导线只吃「名称与数值之间的富余空间」，名称按内容占位。 */
/* ★ v7.21.3：点线是「装饰」，绝不能参与抢宽。
   flex: 1 1 4px → flex: 1 1 0 + min-width: 0：
   basis 归零后它只吃「名称与数值排完后的富余空间」，排满就缩到 0 自然消失，
   而不是把名称挤到截断。 */
.ap-panel .attr-dots {
  flex: 1 1 0;
  min-width: 0;
  height: 1px;
  margin: 0 3px;
  align-self: center;
  overflow: hidden;
  background-image: linear-gradient(90deg, var(--divider) 0 2px, transparent 2px 5px);
  background-size: 5px 1px;
  background-repeat: repeat-x;
  opacity: .75;
}
.ap-panel .attr-val {
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
  text-align: right;
  font-weight: 600;
}
/* 名称 + 数值都不收缩、点线 flex-basis:0 只吃余量 ——
   于是「放不下」这件事会以**整行溢出**的形式暴露出来（而不是静默截断），
   由 renderApPanel 的 is-wide 判定提前把这类行改成跨两列。 */
.ap-panel .attr-item.is-wide { grid-column: 1 / -1; }
.ap-panel .attr-item.zero .attr-val { color: var(--text-3); }
.ap-panel-empty { font-size: 11px; color: var(--text-3); }
.ap-item-slot {
  flex-shrink: 0;
  width: 30px;
  text-align: center;
  padding: 1px 0;
  border-radius: 5px;
  background: var(--glass-bg-strong);
  color: var(--text-2);
  font-size: 11px;
}
.ap-item-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-1);
}
.ap-item-rate {
  flex-shrink: 0; color: var(--text-2);
  font-variant-numeric: tabular-nums;
  font-size: 11px; padding: 0 5px; border-radius: 4px;
  background: var(--glass-bg-strong);
}
/* ★ v7.21.2：单件满值率按高低着色，扫一眼就知道哪件拖后腿 */
.ap-item-rate.is-full { color: var(--success); background: var(--success-soft, rgba(76, 175, 80, .14)); }
.ap-item-rate.is-mid { color: var(--text-1); }
.ap-item-rate.is-low { color: var(--warning); background: var(--warning-soft, rgba(240, 173, 78, .14)); }

@media (max-width: 720px) {
  /* v7.15.0：窄屏把「配装明细 / 面板属性」两栏改成上下堆叠 */
  .ap-body { grid-template-columns: 1fr; }
  .ap-items { grid-template-columns: 1fr; }
  /* ★ v7.21.2：指标块与结果统计在窄屏改为单列 / 整行换行 */
  .autoplan-metrics { grid-template-columns: 1fr; }
  .autoplan-result-head { flex-direction: column; align-items: stretch; }
  .autoplan-result-head > .glass-btn { align-self: flex-start; }
  .autoplan-run-btn { flex: 1 1 100%; }
}
@media (max-width: 560px) {
  .ap-items { grid-template-columns: 1fr; }
  .ap-rate { font-size: 18px; }
  /* ★ v7.21.3：窄屏改单列，同样不设高度上限，靠过滤后的行数自然收口 */
  .ap-panel { grid-template-columns: 1fr; }
  .autoplan-modal { max-width: 96%; }
  .autoplan-metric-value { font-size: 20px; }
  .ap-card-head { flex-wrap: wrap; }
  .ap-apply { margin-left: auto; }
  /* ★ v7.21.2：窄屏原来把 rank / 毕业率 / 分档 / 差值 / 弓标签 / 应用挤在一行，
     导致 .ap-rate-row 折行，毕业率孤零零飘在上一行（截图可见「49.95%」单独一行）。
     改为：第一行 = 排名 + 毕业率（占满），第二行 = 分档 + 差值 + 弓标签 + 应用。 */
  .ap-rank { min-width: 34px; }
  .ap-rate-wrap { order: 2; flex: 1 1 auto; }
  .ap-rate-row { flex-wrap: wrap; }
  .ap-bow-tag { order: 3; }
  .ap-apply { order: 4; }
  .ap-card-head { row-gap: 6px; }
}

/* ==================== v7.15.12：装备槽卡片套用装备库样式 ==================== */
/* 装备槽改用 .equip-lib-affixes / .lib-affix-* 后，做几处适配：
   · 槽位卡内部空间比库卡窄，词条名字段给足但限制最小宽度，避免把数值挤出去；
   · 槽位卡高度由内容撑开（原来固定 152px + .equip-affixes min-height:110px 是为词条堆叠预留的）；
   · 保持 8 个槽位卡片等高：数值列 tabular-nums 对齐。 */
.equip-slot .slot-affixes {
  width: 100%;
  margin-top: 4px;
  padding-top: 5px;
}
.equip-slot .slot-affixes .lib-affix-row {
  grid-template-columns: 18px minmax(0, 1fr) auto;
  gap: 5px;
  height: 20px;
  padding: 0 3px;
}
.equip-slot .slot-affixes .lib-affix-val {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 装备槽卡片高度改由内容决定（6 行词条位 + 标题），不再写死 152px */
.equip-slot { min-height: 0; height: auto; align-items: center; }
/* ★ v7.17.0（docx#23）：空槽**也必须**由内容撑开 —— 旧版把空槽钉死在 152px，
   而换用 6 行词条位后已装备槽的实际高度是 ~219px，两者不再等高，左右列立刻错位。
   现在保持 height:auto，让空槽的 6 行占位与已装备槽完全同高（同骨架、同内容量 → 同高）。 */
.equip-slot.empty { min-height: 0; height: auto; }

/* ==================== v7.16.0（用户需求1）：竞速榜快照对比 ==================== */
.rank-snap-card { margin: 0 0 14px; }
.rank-snap-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 16px;
}
.rank-snap-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
  font-size: 13px;
  color: var(--text-1);
  margin-right: 2px;
}
.rank-snap-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-3);
}
.rank-snap-field > span { white-space: nowrap; }
.rank-snap-sel { min-width: 150px; font-size: 12px; padding: 6px 8px; }
.rank-snap-vs { font-size: 12px; color: var(--text-3); font-weight: 700; }
.rank-snap-hint { font-size: 11px; color: var(--text-3); margin-left: auto; }
.rank-snap-summary {
  border-top: 1px solid var(--divider);
  padding: 10px 16px 14px;
  font-size: 12px;
  color: var(--text-2);
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
}
.rank-snap-summary b { color: var(--text-1); }
.rank-snap-summary .up-txt { color: var(--success); }
.rank-snap-summary .down-txt { color: var(--danger); }

/* 对比模式下的名次列：双列并排 */
.rank-table.cmp-mode th.cmp-base,
.rank-table.cmp-mode td.cmp-base { background: var(--bg-soft); }
.rank-table.cmp-mode td.cmp-base { color: var(--text-2); }
.rank-table.cmp-mode th.cmp-cmp { border-left: 1px dashed var(--divider); }
.rank-table.cmp-mode td.cmp-cmp { border-left: 1px dashed var(--divider); }
.rk-cell { display: inline-flex; align-items: center; gap: 5px; }
/* 差异高亮：名次上升绿、下降红，新进/掉榜用中性色
   ★ v7.17.0（docx#28）：「上升为绿，下降为红」，且标注紧跟在**名次数字右侧**（见 rank.js）。
     口径与 rank.js 的 deltaHtml / rankDeltaCls 完全一致：
       `.rk-diff-up`   = 名次数值**变小**（名次上升）→ **绿**，渲染 ▲
       `.rk-diff-down` = 名次数值**变大**（名次下降）→ **红**，渲染 ▼
     两处必须同口径改动，否则会出现「颜色绿、箭头 ▼」的自相矛盾。 */
.rk-diff-up   { color: var(--success); font-weight: 700; }
.rk-diff-down { color: var(--danger); font-weight: 700; }
.rk-diff-new  { color: var(--primary); font-weight: 700; }
/* ★ v7.19.2 修复③：掉榜的删除线**必须限定在名次数字上**，不能让它向外传染。
   §踩坑现场（用户截图）：双列并排时给 `.rk-cell` 挂了 `rk-diff-gone`，
     `text-decoration` 是会**继承到后代**的 —— 于是同一行右侧的「时长」格
     也划上了一条横线，看起来像成绩被划掉了。
   §为什么 .rank-dur 会中招：`.rk-cell` 只包住名次数字，本是独立元素，
     但在双列并排布局里它与 `.rank-dur` 处于**同一行**；
     实测该行的删除线视觉上横穿了时长列，用户原话「新上榜的队伍成绩那里划了一条横线」。
   §修法：用 `text-decoration-skip-ink: none` 挡不住跨元素传染，
     改为把删除线**只画在数字本身的文本节点上** —— 即限定选择器深度，
     并显式给所有可能继承的兄弟元素复位 `text-decoration: none`。 */
.rk-diff-gone { color: var(--text-3); text-decoration: line-through; text-decoration-thickness: 1px; }
/* 复位：名次格以外的单元格不许继承删除线（时长 / 队名 / 收藏） */
.rank-table.cmp-mode td.cmp-base,
.rank-table.cmp-mode td.cmp-cmp,
.rank-table td.rank-dur,
.rank-table td.rank-team,
.rank-table td.rank-rk > .rk-cell { text-decoration: none; }
/* 名次数字自身仍要保留删除线（掉榜标记），故单独再提一级特异性 */
.rank-table td .rk-cell.rk-diff-gone { text-decoration: line-through; }
.rk-diff-same { color: var(--text-3); }
/* 紧跟名次数字的 ▲/▼ 标记：字号略小、与数字同基线 */
.rk-cell .rk-diff-up, .rk-cell .rk-diff-down { font-size: 11.5px; margin-left: 1px; }
/* 差异模式下名次列：数字右对齐，▲/▼ 紧贴其右，读数顺序与用户截图一致（「48 ▼2」） */
.rank-table:not(.cmp-mode) .rank-rk .rk-cell { flex-direction: row; justify-content: flex-start; }

/* ==================== ★ v7.19.0：历史掉榜队伍 ====================
   用户原文：「竞速榜单页面显示所有历史已经掉榜的人，可勾选是否显示」。
   视觉目标：一眼能看出「这行不是当前榜内的」，但又不能太花把主榜压下去。
   做法：整行降透明度 + 队名后挂灰色胶囊标签 + 名次列显示「—」。 */
.rank-gone-row {
  color: var(--text-3);
  background: color-mix(in srgb, var(--text-3) 5%, transparent);
}
.rank-gone-row:hover { background: color-mix(in srgb, var(--text-3) 9%, transparent); }
.rank-gone-row .rank-team {
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--text-3) 60%, transparent);
  text-decoration-thickness: 1px;
}
/* 名次列的「—」：给个可见的虚线框，提示"这里本来有排名，但它已经没有当前名次了" */
.rk-gone-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 6px;
  border: 1px dashed color-mix(in srgb, var(--text-3) 55%, transparent);
  color: var(--text-3); font-size: 12px; cursor: help;
}
.rank-gone-tag {
  display: inline-block; margin-left: 6px; padding: 0 7px;
  border-radius: 999px; font-size: 11px; line-height: 17px;
  border: 1px solid color-mix(in srgb, var(--text-3) 40%, transparent);
  color: var(--text-3); text-decoration: none;
  vertical-align: middle;
}
/* 说明段里的 ▲/▼ 也必须与表格同口径（上升绿、下降红）。
   ⚠ 只给符号上色，不给整句上色 —— 整段染色的观感像报错提示。 */
.rank-note .rk-diff-up, .rank-note .rk-diff-down { font-weight: 700; }

@media (max-width: 900px) {
  .rank-snap-hint { margin-left: 0; width: 100%; }
  .rank-snap-sel { min-width: 130px; }
}

/* ==================== v7.16.0（用户需求4）：账号 / 好友 / 查看面板 ==================== */

/* 顶栏账号入口（取代原「角色」字样） */
.account-entry-btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-1, rgba(255,255,255,0.6));
  color: var(--text-2); font-size: 13px; font-weight: 500;
  cursor: pointer; transition: all .18s ease; white-space: nowrap;
}
.account-entry-btn:hover { color: var(--text-1); border-color: var(--border-strong); transform: translateY(-1px); }
.account-entry-btn.is-logged-in { color: var(--success); border-color: var(--success-soft); background: var(--success-soft); }
.account-entry-btn .icon-sm { width: 15px; height: 15px; }

/* 登录 / 注册弹窗 */
.auth-tabs { display: flex; gap: 6px; margin-bottom: 14px; border-bottom: 1px solid var(--divider); }
.auth-tab {
  flex: 1; padding: 8px 0; border: none; background: none; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--text-3);
  border-bottom: 2px solid transparent; transition: all .16s ease;
}
.auth-tab:hover { color: var(--text-2); }
.auth-tab.active { color: var(--primary-1, var(--accent-1)); border-bottom-color: var(--primary-1, var(--accent-1)); }
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-field { display: flex; flex-direction: column; gap: 5px; }
.auth-field > span { font-size: 12.5px; color: var(--text-2); font-weight: 500; }
.auth-field .req { color: var(--danger); font-style: normal; font-size: 11px; margin-left: 4px; }
.auth-field .opt { color: var(--text-3); font-style: normal; font-size: 11px; margin-left: 4px; }
.auth-submit { margin-top: 4px; }
.auth-error { min-height: 18px; margin-top: 10px; font-size: 12.5px; color: var(--danger); }
.auth-account-block {
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--divider);
  display: flex; flex-direction: column; gap: 8px;
}
.auth-me-line { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-2); flex-wrap: wrap; }
.auth-me-line b { color: var(--text-1); }
.auth-me-id { font-size: 11.5px; color: var(--text-3); background: var(--divider); padding: 1px 7px; border-radius: 999px; }
.auth-logout { margin-left: auto; }
.auth-bind-title { font-size: 12.5px; font-weight: 600; color: var(--text-2); margin-top: 4px; }
.auth-bind-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 0; }
.auth-bind-name { font-size: 13px; color: var(--text-1); }
.glass-btn.is-on { color: var(--success); border-color: var(--success-soft); background: var(--success-soft); }

/* 好友弹窗 */
.friend-visibility {
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px; margin-bottom: 14px;
  background: var(--divider); border-radius: var(--radius);
}
.switch-line { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-1); cursor: pointer; }
.switch-line input { width: 16px; height: 16px; accent-color: var(--success); cursor: pointer; }
.friend-sync-line { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.friend-search-result { margin: 10px 0 4px; display: flex; flex-direction: column; gap: 6px; }
.friend-list { display: flex; flex-direction: column; gap: 6px; }
.friend-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1, rgba(255,255,255,0.4));
}
.friend-main { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.friend-name { font-size: 13.5px; font-weight: 600; color: var(--text-1); }
.friend-id { font-size: 11px; color: var(--text-3); background: var(--divider); padding: 1px 7px; border-radius: 999px; }
.friend-flag { font-size: 11px; color: var(--text-3); }
.friend-flag.is-public { color: var(--success); }
.friend-ops { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.friend-hint { font-size: 11.5px; color: var(--text-3); }
.form-hint.err { color: var(--danger); }

/* ==================== v7.18.0（#23-b）：我的主页（独立放大页） ====================
   需求原文：「独立放大的『我的主页』」。此前账号身份只挤在登录弹窗末尾一行，
   故这里做成独立大弹窗（glass-modal-lg）+ 独立版式，视觉上与「好友」功能分层。 */
.friend-home-entry {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px; margin-bottom: 14px;
  background: var(--divider); border-radius: var(--radius);
}
.friend-home-btn { flex: 0 0 auto; }

.my-home-body { max-height: 70vh; overflow-y: auto; }
/* 头部：圆形首字头像 + 名称/标识 */
.myhome-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.myhome-avatar {
  flex: 0 0 auto; width: 56px; height: 56px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 24px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--accent, #6b8afd), var(--accent-2, #a06bfd));
  box-shadow: 0 4px 14px rgba(0,0,0,0.14);
}
.myhome-idbox { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.myhome-name { font-size: 19px; font-weight: 700; color: var(--text-1); line-height: 1.25; word-break: break-all; }
.myhome-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.myhome-chip {
  font-size: 11.5px; color: var(--text-3); background: var(--divider);
  padding: 2px 9px; border-radius: 999px;
}
.myhome-chip.is-public { color: var(--success); }
.myhome-chip.is-empty { opacity: .7; }

/* 统计三格 */
.myhome-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  padding: 12px 0; margin-bottom: 16px;
  border-top: 1px solid var(--divider); border-bottom: 1px solid var(--divider);
}
.myhome-stat { text-align: center; min-width: 0; }
.ms-label { font-size: 11.5px; color: var(--text-3); margin-bottom: 3px; }
.ms-value { font-size: 17px; font-weight: 700; color: var(--text-1); }
.ms-value.ms-sm { font-size: 12px; font-weight: 600; color: var(--text-2); line-height: 1.4; word-break: break-all; }

/* 修改资料表单 */
.myhome-form { display: flex; flex-direction: column; gap: 10px; }
.myhome-form-title { font-size: 12.5px; font-weight: 700; color: var(--text-2); }
.myhome-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.myhome-actions .form-hint { flex: 1 1 200px; min-width: 0; }

@media (max-width: 560px) {
  .myhome-stats { grid-template-columns: 1fr; gap: 6px; }
  .myhome-avatar { width: 46px; height: 46px; font-size: 20px; }
  .myhome-name { font-size: 17px; }
}

/* 查看面板（只读）弹窗 */
.view-panel-body { max-height: 68vh; overflow-y: auto; }
.view-panel-head { padding-bottom: 10px; margin-bottom: 12px; border-bottom: 1px solid var(--divider); }
.view-panel-owner { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; color: var(--text-1); }
.view-panel-meta { font-size: 12px; color: var(--text-3); margin-top: 3px; }
.view-panel-flow { font-size: 13px; color: var(--text-2); margin-bottom: 12px; }
.view-panel-flow b { color: var(--text-1); }
.view-panel-section-title { font-size: 12.5px; font-weight: 700; color: var(--text-2); margin: 14px 0 8px; }
.view-panel-attrs { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
.view-panel-equips { display: flex; flex-direction: column; gap: 5px; }
.view-equip-item {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 7px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.view-equip-slot { font-size: 11.5px; color: var(--text-3); flex-shrink: 0; min-width: 40px; }
.view-equip-name { font-size: 13px; font-weight: 600; color: var(--text-1); }
.view-equip-affixes { font-size: 11.5px; color: var(--text-2); display: flex; flex-wrap: wrap; gap: 6px; }
.view-affix { background: var(--divider); padding: 1px 6px; border-radius: var(--radius-xs); }

/* ==========================================================================
   v7.17.0（docx 需求批次）· 新增与调整样式
   --------------------------------------------------------------------------
   覆盖范围：
     ① 概览卡：「毕业率」标题右侧的可点击箭头 / ADPS·RDPS 一行 / 删掉 CTA 后的留白
     ② 装备库：分类 tab、金装·紫装·承音分色标签
     ③ 装备槽：空槽与已装备槽同构对齐
     ④ 新二级页：词条数量统计、建议与反馈
     ⑤ 流派署名小字
   注意：新样式一律使用 CSS 变量，保证亮/暗两套主题都不崩。
   ========================================================================== */

/* ---------- ① 概览卡 ---------- */

/* docx#12：「综合毕业率」字样后加 > 符号，表示这里可以点击。
   原来卡片底部那行「一键自动配装」（.ov-card-cta）已删除，故此处不再需要
   它的 hover 提升效果；箭头用轻微的位移动画代替，点击感更明确。 */
.ov-label-arrow {
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  color: var(--primary);
  opacity: 0.75;
  transition: transform var(--t-fast), opacity var(--t-fast);
  transform: translateX(0);
}
.overview-card-clickable:hover .ov-label-arrow {
  opacity: 1;
  transform: translateX(3px);
}

/* 口述1：毕业率下方「ADPS xxx · RDPS xxx」拍成一行 */
.ov-adpsline {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px;
  margin: 2px 0 6px;
  font-size: 12.5px;
  color: var(--text-3);
  letter-spacing: 0.02em;
}
.ov-adpsline b {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.ov-adpsline-sep { color: var(--divider); margin: 0 2px; }

/* ---------- ⑤ 流派署名（docx#4） ----------
   ★ v7.17.1（口述4 + 口述9）：整块已删除。
   原「内置游戏当前 11 个流派毕业率计算表 + 作者：BiliBili@片雲 · 鸣金影：豆沙包包包」
   随 index.html 的 .flow-author-credit 一起移除；署名已迁到帮助页「来源说明」
   （见 index.html #helpSourceSection），本选择器不再有任何引用，故一并删掉。 */

/* ---------- ★ v7.17.1（口述1）：毕业率卡空白区装饰刻度线 ----------
   档位文案（完全毕业 / 基本毕业 …）删除后，「毕业率」卡片下半部分会空出一块。
   这里用**纯 CSS 伪元素**补一条渐隐刻度线来平衡视觉 ——
   ⚠ 刻意不新增任何 DOM 节点，避免又被当成用户要删的「字样」。
   线用主题主色向两端渐隐，长度固定 64px 且水平居中（.ov-* 已有 text-align:center）。 */
#ovOverallCard .ov-value::after {
  content: '';
  display: block;
  width: 64px;
  height: 2px;
  margin: 12px auto 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--primary), transparent);
  opacity: 0.7;
}

/* ---------- ② 装备库分类 tab（docx#17） ---------- */
.lib-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 12px;
}
.lib-tab {
  appearance: none;
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 6px 11px;
  border-radius: 100px;
  cursor: pointer;
  color: var(--text-2);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  transition: all var(--t-fast);
  white-space: nowrap;
}
.lib-tab:hover {
  color: var(--text-1);
  border-color: var(--primary);
  background: var(--primary-soft);
}
.lib-tab.is-active {
  color: #fff;
  background: var(--primary);
  border-color: var(--primary);
  font-weight: 700;
  box-shadow: 0 2px 8px rgba(43, 91, 255, 0.28);
}

/* ---------- ② 品质 / 承音 分色标签（docx#18） ----------
   用户口径：「金装字样底色为金色，紫装底色为紫色，承音装字样底色为金色」。
   金/紫沿用游戏内的品质色（金 #C9A227 系、紫 #8B5CF6 系），
   承音用金色系但要与「金装」区分开 —— 承音是**金色描边 + 淡金底**（偏琥珀），
   金装是**实心金底**，两者放在一起仍能一眼分开。 */
.equip-lib-meta .tag.tag-gold {
  color: #7a5a00;
  background: linear-gradient(135deg, #f7e08a 0%, #e0b93f 100%);
  border-color: #c9a227;
  font-weight: 700;
}
.equip-lib-meta .tag.tag-purple {
  color: #fff;
  background: linear-gradient(135deg, #a78bfa 0%, #7c3aed 100%);
  border-color: #6d28d9;
  font-weight: 700;
}
.equip-lib-meta .tag.tag-chengyin {
  color: #8a6100;
  background: rgba(224, 185, 63, 0.18);
  border-color: #d9a521;
  font-weight: 700;
}
.equip-lib-meta .tag.tag-kind {
  color: var(--text-2);
  background: var(--bg-soft-2);
  border-color: var(--divider);
}
/* 暗色主题下压深文字色，避免浅底浅字看不清 */
[data-theme="dark"] .equip-lib-meta .tag.tag-gold,
[data-theme="dark"] .equip-lib-meta .tag.tag-chengyin {
  color: #2a1f00;
}

/* ---------- ③ 装备槽空槽对齐（docx#23） ----------
   旧空槽是「居中的矮方块」，高度 152px 但内部是纵向居中的图标 + 文字，
   与已装备槽（顶部对齐的 6 行词条）视觉基线完全错位。
   现在空槽复用了已装备槽的骨架（.slot-icon / .slot-main / .equip-lib-affixes），
   故只需覆盖掉旧的 column + center 布局，并弱化视觉。 */
.equip-slot.empty {
  display: flex;
  align-items: center;      /* 覆盖旧值 flex-direction: column 的居中 */
  flex-direction: row;
  justify-content: flex-start;
  color: var(--text-3);
  padding: 14px 16px;
}
.equip-slot.empty .slot-icon {
  background: var(--bg-soft-2);
  color: var(--text-3);
}
.equip-slot.empty:hover .slot-icon {
  background: var(--primary-soft);
  color: var(--primary);
}
.slot-empty-name { color: var(--text-3); font-weight: 500; }
.equip-slot.empty .equip-name { color: var(--text-3); }
.equip-slot.empty .lib-affix-row.is-empty { opacity: 0.45; }
/* 空槽右侧：一个淡淡的 + 号，位置与已装备槽的 % 数字同格 */
.equip-rate.empty-plus {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 30px;
  border-radius: var(--radius-sm);
  border: 1px dashed var(--divider);
  color: var(--text-3);
  background: transparent;
}
.equip-slot.empty:hover .equip-rate.empty-plus {
  border-color: var(--primary);
  color: var(--primary);
}

/* ---------- ④ 词条数量统计二级页（docx#22） ---------- */
.affix-stats-modal { max-width: 620px; width: 92vw; }
.affix-stats-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  font-size: 12.5px;
  color: var(--text-2);
}
.affix-stats-summary b { color: var(--primary); font-size: 15px; }
.affix-stat-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 52vh;
  overflow-y: auto;
  padding-right: 4px;
}
.affix-stat-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border-radius: var(--radius-xs);
  transition: background var(--t-fast);
}
.affix-stat-row:hover { background: var(--bg-soft-2); }
.affix-stat-name {
  flex: 0 0 128px;
  font-size: 12.5px;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.affix-stat-bar {
  flex: 1 1 auto;
  height: 8px;
  border-radius: 100px;
  background: var(--divider);
  overflow: hidden;
  min-width: 40px;
}
.affix-stat-bar i {
  display: block;
  height: 100%;
  border-radius: 100px;
  background: linear-gradient(90deg, var(--primary) 0%, #4F7AFF 100%);
}
.affix-stat-count {
  flex: 0 0 40px;
  text-align: right;
  font-weight: 700;
  font-size: 13px;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.affix-stat-equips {
  flex: 0 0 52px;
  text-align: right;
  font-size: 11.5px;
  color: var(--text-3);
}

/* ---------- ④ 建议与反馈二级页（docx#20） ---------- */
.feedback-modal { max-width: 560px; width: 92vw; }
.fb-kind-row { display: flex; gap: 8px; margin-bottom: 14px; }
.fb-kind-btn {
  flex: 1 1 0;
  appearance: none;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-2);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  transition: all var(--t-fast);
}
.fb-kind-btn:hover { border-color: var(--primary); color: var(--text-1); }
.fb-kind-btn.is-active {
  color: #fff;
  background: var(--primary);
  border-color: var(--primary);
  box-shadow: 0 2px 10px rgba(43, 91, 255, 0.3);
}
.fb-label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
  margin: 0 0 6px;
}
.fb-optional { font-weight: 400; color: var(--text-3); }
.fb-textarea {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  min-height: 110px;
  font: inherit;
  font-size: 13px;
  line-height: 1.6;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  color: var(--text-1);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  margin-bottom: 14px;
  transition: border-color var(--t-fast);
}
.fb-textarea:focus { outline: none; border-color: var(--primary); }
.fb-drop {
  border: 2px dashed var(--divider);
  border-radius: var(--radius-sm);
  padding: 22px 14px;
  text-align: center;
  cursor: pointer;
  transition: all var(--t-fast);
  background: var(--bg-soft-2);
  color: var(--text-3);
  font-size: 12.5px;
  margin-bottom: 10px;
}
.fb-drop:hover, .fb-drop.is-drag {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--text-1);
}
.fb-drop strong { color: var(--primary); }
.fb-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}
.fb-thumb {
  position: relative;
  width: 76px;
  height: 76px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--divider);
}
.fb-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fb-thumb-del {
  position: absolute;
  top: 2px; right: 2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  line-height: 1;
  font-size: 13px;
  color: #fff;
  background: rgba(0, 0, 0, 0.62);
}
.fb-thumb-del:hover { background: var(--danger); }

/* ★ v7.23.0：反馈页新增元素（登录提示 / 必填标记 / 字数计数） */
.fb-required { font-weight: 400; color: var(--danger); }
.fb-counter {
  text-align: right;
  font-size: 11.5px;
  color: var(--text-3);
  margin: -8px 0 12px;
  font-variant-numeric: tabular-nums;
}
/* 接近上限时变色提醒（1800 / 2000）—— 比等超限被拦下来更友好 */
.fb-counter.is-near { color: var(--danger); font-weight: 600; }
/* v7.24.0：.fb-login-hint 已无使用者（反馈不再需要登录），本类暂留 ——
   它是一套「左侧主色竖条 + 浅底 + 可内嵌按钮」的提示条样式，
   后续若再出现需要用户操作的阻断式提示可直接复用。
   注意：不要把它当作通用提示条无脑套用，它的主色竖条语义是「这里需要你做点什么」。 */
.fb-login-hint {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-2);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin: 0 0 14px;
}
/* v7.24.0：反馈改为匿名提交，提示条从「请先登录」变成「无需登录」声明。
   沿用 fb-login-hint 的视觉（左侧主色竖条 + 浅底），但换成中性配色 ——
   它现在是一条**常显**的说明，不再是需要吸引注意的阻断式提示。 */
.fb-anon-hint {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-3);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  border-left: 3px solid var(--text-3);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  margin: 0 0 14px;
}
.fb-login-btn {
  flex: 0 0 auto;
  padding: 5px 14px !important;
  font-size: 12.5px !important;
  min-height: 0 !important;
}
/* 未登录时提交按钮置灰 —— 但保持可见，让用户知道"这里本来有个提交" */
.glass-btn:disabled,
.glass-btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  filter: grayscale(0.4);
}

/* ==========================================================================
   v7.17.0（docx#3）· 下拉控件风格统一
   --------------------------------------------------------------------------
   用户原话：「毕业率计算页面表格选择下拉也需要做相应风格 ui，包括心法选择也是。
             流派字样改为"表格"，左侧距离卡片边缘适当远一些。」
             「调律计算页面角色选择/流派选择/套装选择/弓选择下拉应也为相应风格 ui，
               而不是白色的古董选择 ui。」
   现状：`.glass-select` 早就做了 appearance:none + 自绘箭头，但**展开后的选项列表**
         仍是浏览器原生白底（Windows/部分 Chromium 下尤其明显），这就是"白色的古董 UI"的来源。
   对策：① 给 <option> 显式上色（Chromium/Edge 生效，Firefox 部分生效）；
         ② 用 color-scheme 让原生控件跟随亮/暗主题；
         ③ 统一箭头与高度，让所有下拉观感一致。
   ========================================================================== */

/* 让原生控件（下拉箭头、滚动条、选项面板）跟随主题明暗 */
:root { color-scheme: light; }
[data-theme="dark"] { color-scheme: dark; }

.select option, .glass-select option {
  background-color: var(--bg-card);
  color: var(--text-1);
  font-family: inherit;
  font-size: 13px;
}
[data-theme="dark"] .select option,
[data-theme="dark"] .glass-select option {
  background-color: #1b2130;
  color: #e6eaf5;
}
/* 选中项与 hover 项的高亮（Chromium 会尊重这两个伪类） */
.select option:checked, .glass-select option:checked,
.select option:hover, .glass-select option:hover {
  background: var(--primary);
  color: #fff;
}

/* 统一箭头位置与点击区，避免各下拉因 font-size 不同导致箭头错位
   ★ v7.20.13：`background-size` 已并入上方 `.select, .glass-select` 主规则，
     此处只保留行高（位置放在这里是因为它必须晚于 `.select-sm` 之类只改尺寸的规则）。
     ⚠ 别再往这里加 `background-size` —— 重复声明会覆盖 `.select-sm` 的收窄版留白。 */
.select, .glass-select {
  line-height: 1.4;
}

/* 毕业率计算页：流派行改为「表格」标签 + 与卡片边缘留出距离（docx#3） */
.pz-school-row {
  padding-left: 6px;       /* 原为紧贴卡片内边距，用户要求"左侧距离卡片边缘适当远一些" */
  gap: 14px;
}
.pz-school-label { min-width: 44px; }
.pz-school-sel { max-width: 420px; }

/* 高级预设里合并后的「食物加成」一格（docx#1） */
.pz-food-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pz-food-title { font-size: 12.5px; color: var(--text-2); }
.pz-food-pair {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  /* 整体占原来一个填写位的长度：两个短输入 + 中间的连接符 */
  max-width: 100%;
}
.pz-food-input {
  width: 0;                 /* 由 flex 分配，避免撑破栅格 */
  flex: 1 1 0;
  min-width: 48px;
  padding-left: 8px;
  padding-right: 8px;
  text-align: center;
}
.pz-food-sep {
  flex: 0 0 auto;
  color: var(--text-3);
  font-weight: 700;
  line-height: 1;
}

/* ==========================================================================
   v7.17.0（docx#2）· 心法装配移入属性面板
   ========================================================================== */
.xinfa-section {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--divider);
}
.xinfa-section-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.xinfa-section-head h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-2);
  display: flex;
  align-items: center;
  gap: 6px;
}
.xinfa-section-head h3 .icon-sm { color: var(--primary); }
/* 旧独立卡片的样式在移入面板后需要收敛：去掉自身边距，避免双层 padding 造成空洞 */
.xinfa-section .xinfa-list { margin: 0; }

/* ==========================================================================
   v7.17.0（docx#13）· 配装方案
   ========================================================================== */
.plan-bar { display: flex; align-items: center; }
.plan-bar-btn {
  appearance: none;
  font: inherit;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-2);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  transition: all var(--t-fast);
  max-width: 190px;
}
.plan-bar-btn:hover { border-color: var(--primary); color: var(--primary); background: var(--primary-soft); }
.plan-bar-btn span:not(.plan-bar-count) {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plan-bar-count {
  flex: 0 0 auto;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 100px;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  color: #fff;
  background: var(--primary);
}

.plan-modal { max-width: 640px; width: 92vw; }
.plan-save-row {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}
.plan-save-row .glass-input { flex: 1 1 auto; }
.plan-save-row .glass-btn { flex: 0 0 auto; gap: 6px; }
.plan-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 50vh;
  overflow-y: auto;
}
.plan-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--bg-soft-2);
  border: 1px solid var(--divider);
  transition: all var(--t-fast);
}
.plan-item:hover { border-color: var(--primary); }
.plan-item.is-active {
  border-color: var(--primary);
  background: var(--primary-soft);
}
.plan-main { flex: 1 1 auto; min-width: 0; }
.plan-name-row { display: flex; align-items: center; gap: 6px; min-width: 0; }
.plan-name {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plan-cur-flag {
  flex: 0 0 auto;
  font-size: 10px; font-weight: 700;
  padding: 1px 7px;
  border-radius: 100px;
  color: var(--success);
  background: var(--success-soft);
  border: 1px solid var(--success);
}
.plan-meta { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.plan-actions { display: flex; gap: 6px; flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; }

/* ==========================================================================
   v7.17.0（docx#2）· 团队增益卡改版
   用户原话：「"团队增益"做的有点丑，你看着优化。」
   改动纯视觉：分区标题 + 计数徽标 + 紧凑开关网格 + 长文案省略号。
   ⚠ .pz-seg 仍是行为锚点（collect/fillDefaults/bindAll 依赖它 + el.value），
     下面的 .pz-switch* 只叠加外观，不改变任何取值路径。
   ========================================================================== */

/* 卡片头右侧的说明小字（新增 .card-note：原只有 card-header 的 h2） */
.card-note {
  font-size: 11.5px;
  color: var(--text-3);
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 720px) { .card-note { display: none; } }

/* 分区容器 */
.pz-block + .pz-block { margin-top: 12px; }
.pz-block-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}
.pz-block-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-2);
  letter-spacing: 0.03em;
}
.pz-block-title::before {
  content: '';
  display: inline-block;
  width: 3px;
  height: 11px;
  margin-right: 6px;
  border-radius: 2px;
  background: var(--primary);
  vertical-align: -1px;
}
.pz-block-count {
  font-size: 11px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  padding: 1px 7px;
  border-radius: 100px;
  background: var(--bg-soft-2, rgba(128, 128, 128, 0.08));
  border: 1px solid var(--divider);
}

/* 开关网格：自适应列宽，窄屏自动降列 */
.pz-switch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 8px;
}
@media (max-width: 720px) {
  .pz-switch-grid { grid-template-columns: 1fr; }
}

/* 单个开关：左侧文字 + 右侧 √/× 分段按钮 */
.pz-switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  padding: 0 0 0 10px;
  height: 36px;
  border: 1px solid var(--divider);
  border-radius: 10px;
  background: var(--bg-soft-2, rgba(128, 128, 128, 0.04));
  transition: border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.pz-switch-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12.5px;
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 已开启态：主色描边 + 浅底 + 文字提亮，一眼扫出开了哪几项 */
.pz-switch.is-on {
  border-color: var(--primary);
  background: var(--primary-soft, rgba(59, 130, 246, 0.08));
  box-shadow: inset 0 0 0 1px var(--primary-soft, transparent);
}
.pz-switch.is-on .pz-switch-label {
  color: var(--text-1);
  font-weight: 600;
}
/* 开关内部的√/×按钮组：复用 .pz-seg-btn 配色，但不再需要外框（外框交给 .pz-switch） */
.pz-switch.pz-seg {
  border: 1px solid var(--divider);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-soft-2, rgba(128, 128, 128, 0.04));
  padding-right: 0;
}
.pz-switch-btns {
  flex: 0 0 auto;
  display: inline-flex;
  align-self: stretch;
  height: 100%;
  /* 按钮组自带一层浅底，与开关外框拉开层次，避免"√/× 糊在一起看不清" */
  background: var(--surface-dim, rgba(128, 128, 128, 0.08));
  border-left: 1px solid var(--divider);
}
.pz-switch .pz-seg-btn {
  flex: 0 0 auto;
  min-width: 34px;
  height: 100%;
  font-size: 13px;
  /* 未选中态也要有可辨识的字色 —— 原全局值是 var(--text-3)，在浅底上对比度过低 */
  color: var(--text-2);
  background: transparent;
}
.pz-switch .pz-seg-btn:hover { background: var(--bg-soft-2, rgba(128, 128, 128, 0.12)); }
.pz-switch .pz-seg-btn.active { background: var(--primary); color: var(--text-inverse, #fff); }
/* 已开启项：√ 主色实心、× 保持低调但可读 */
.pz-switch.is-on .pz-switch-btns { background: transparent; }
.pz-switch.is-on .pz-seg-btn[data-v="×"] { color: var(--text-3); }

/* 下拉 label 的长文案截断（原来会长到撑破三列栅格） */
.pz-row label .pz-label-text {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==================== v7.20.0（用户需求）：角色合并弹窗 + 账号级自动同步开关 ====================
   需求原文：「我需要当前注册账号下所有角色及角色的配装，装备库都跟着账号走，换电脑登录也可以看到
             所有角色及配装。配装页面可以勾选是否自动同步配装。勾选后立刻同步。」

   本段只负责**外观**，交互逻辑在 auth.js（renderMergeModal / onMergeChange / applyMerge）。
   ★ 弹窗内容由 JS 整体 innerHTML 重绘，故这里所有规则必须是"结构无关"的 ——
     只靠 class 命中，不依赖 nth-child 之类的位置关系，否则重绘后样式会错位。 */

/* 账号级自动同步开关那块，与「允许好友查看面板」视觉上分开，
   提示用户这是两件独立的事（详见 index.html 的注释）。 */
.friend-autosync { margin-top: -6px; }
.autosync-note { font-size: 11.5px; line-height: 1.5; }
.autosync-note strong { color: var(--text-2); }

/* ---- 合并弹窗 ---- */
.merge-body { display: flex; flex-direction: column; gap: 12px; }

.merge-intro {
  font-size: 12.5px; line-height: 1.65; color: var(--text-2);
  padding: 11px 13px; border-radius: var(--radius);
  background: var(--divider);
}
.merge-intro b { color: var(--text-1); }

/* ★ 本地时钟警示：两端 updatedAt 是各自电脑的时钟，不能直接比大小。
   用警示色是为了让用户看见"时间不准"这句提醒，而不是当成普通小字跳过。 */
.merge-warn { display: inline-block; margin-top: 6px; color: var(--warning, #d99a2b); font-size: 12px; }

.merge-group { display: flex; flex-direction: column; gap: 6px; }
.merge-group-title {
  font-size: 12px; font-weight: 600; color: var(--text-2);
  padding-bottom: 4px; border-bottom: 1px solid var(--border);
}

/* 一行一个角色。用 label 包住复选框 → 点整行都能勾，比只点小方块好按得多 */
.merge-row {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 11px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1, rgba(255,255,255,0.4));
  font-size: 13px; cursor: pointer;
}
.merge-row:hover { border-color: var(--accent, var(--success)); }
.merge-row input { width: 15px; height: 15px; accent-color: var(--success); cursor: pointer; flex-shrink: 0; }
.merge-name { font-weight: 600; color: var(--text-1); }
.merge-meta { font-size: 11.5px; color: var(--text-3); margin-left: auto; text-align: right; }

/* 冲突项：不用复选框而用单选，因为必须二选一、没有"都不选"这个选项 */
.merge-conflict {
  display: flex; flex-direction: column; gap: 5px;
  padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1, rgba(255,255,255,0.4));
}
.merge-conflict .merge-name { font-size: 13px; margin-bottom: 2px; }
.merge-radio {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; border-radius: calc(var(--radius) - 2px);
  font-size: 12.5px; color: var(--text-2); cursor: pointer;
}
.merge-radio:hover { background: var(--divider); }
.merge-radio input { width: 14px; height: 14px; accent-color: var(--success); cursor: pointer; flex-shrink: 0; }

/* 窄屏：摘要行换行到角色名下方，避免横向挤成一团 */
@media (max-width: 560px) {
  .merge-row, .merge-radio { flex-wrap: wrap; }
  .merge-meta { margin-left: 24px; text-align: left; width: 100%; }
}

/* ==========================================================
   玻璃风下拉组件（v7.21.0）
   ----------------------------------------------------------
   §背景
     原生 <select> 的展开面板由浏览器/OS 合成层独立绘制，不参与页面样式树，
     border-radius / padding / backdrop-filter / box-shadow 全部被忽略。
     因此本组件改为：原生 select 保留为**隐藏数据层**，外观全部自绘。

   §结构
     .gs-wrap           ← 挂上原 select 的全部 class，只继承宽度约束，清掉装饰
       select.gs-native ← 数据层，opacity:0 + pointer-events:none
       .gs-trigger      ← 视觉层（按钮）
     body > .gs-panel   ← 浮层面板（position:fixed）

   §玻璃强度
     取「中等透」：--gs-menu-bg 浅色 0.72 / 夜间 0.58。
     ⚠ 不能复用 --glass-bg-strong（它只有 0.18 / 夜间 0.09）——
       那个量级是给「浮在炫光背景上的卡片」用的，面板必须能压住底下的
       表格与文字，透到 0.18 会完全看不清选项。
   ========================================================== */

:root {
  --gs-menu-bg: rgba(255, 255, 255, 0.72);
  --gs-menu-bg-hover: rgba(255, 255, 255, 0.88);
  --gs-menu-border: rgba(255, 255, 255, 0.85);
  --gs-menu-shadow: 0 4px 12px rgba(30, 42, 74, 0.10),
                    0 16px 40px rgba(30, 42, 74, 0.18),
                    0 32px 72px rgba(30, 42, 74, 0.10);
  --gs-menu-text: var(--text-1);
  --gs-menu-label: var(--text-3);
  --gs-menu-divider: rgba(30, 42, 74, 0.07);
  /* 高亮/选中态的文字色。
     §为什么不直接用 --primary：
       面板底色是半透白（0.72 白 + 0.28 主题底 ≈ #FCFDFE），而浅色系主题的
       --primary 偏亮，压上去对比度不够（sky #38bdf8 ≈ 2.1、cream #f59e0b ≈ 2.1、
       mint #10b981 ≈ 2.5），选项文字会糊。
     §为什么不直接用 --primary-active：
       那个够深（sky #0284c7 ≈ 4.0、cream #b45309 ≈ 5.0），但它在别的组件里
       承担「按下态」语义，借来当常驻文字色会让主题语汇错乱。
     所以这里新造一个只服务于面板的变量，取「--primary 在面板底色上 ≥ 4.5」的值
     （WCAG AA 正文线）。默认 white 主题用 #2d56c8（6.29）。 */
  --gs-menu-accent: #2d56c8;
}
/* --- 逐主题校正 --gs-menu-accent ---
   下面每条都是按「0.72 白 + 0.28 该主题 --bg-app」的合成底色实算的对比度，
   括号里是实测值，全部 ≥ 4.4。改了主题配色请回头复核这几个数。 */
:root[data-theme="sky"]      { --gs-menu-accent: #0369a1; }  /* 5.12 */
:root[data-theme="purple"]   { --gs-menu-accent: #6d28d9; }  /* 5.68 */
:root[data-theme="pink"]     { --gs-menu-accent: #be185d; }  /* 4.83 */
:root[data-theme="mint"]     { --gs-menu-accent: #047857; }  /* 4.63 */
:root[data-theme="cream"]    { --gs-menu-accent: #a94f08; }  /* 4.85 */
:root[data-theme="lavender"] { --gs-menu-accent: #6d28d9; }  /* 5.69 */

:root[data-theme="navy"] {
  --gs-menu-bg: rgba(30, 36, 52, 0.58);
  --gs-menu-bg-hover: rgba(46, 54, 74, 0.72);
  --gs-menu-border: rgba(255, 255, 255, 0.14);
  --gs-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.30),
                    0 16px 40px rgba(0, 0, 0, 0.42),
                    0 32px 72px rgba(0, 0, 0, 0.26);
  --gs-menu-text: #d8dce4;
  --gs-menu-label: #7d8798;
  --gs-menu-divider: rgba(255, 255, 255, 0.08);
  /* 夜间底色本身就深，用亮色文字即可：面板合成色 ≈ #191E2A，#a8b4ff 对比度 6.47 */
  --gs-menu-accent: #a8b4ff;
}

/* ---------- 外层：只继承宽度约束，装饰一律清掉 ---------- */
/* 原 select 的 class（.glass-select / .select-sm / .set-select / .rank-snap-sel …）
   被原样搬到 wrapper 上，所以这里必须显式复位它们带来的外观属性，
   否则会额外画出一个「看不见的方框 + 内联 SVG 箭头」，把 trigger 挤歪。 */
.gs-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  max-width: 100%;
  background: none;
  background-image: none;
  border: none;
  box-shadow: none;
  padding: 0;
  min-height: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: inherit;
  font: inherit;
  cursor: default;
}
/* 允许被弹性/网格父容器正确压缩（否则长文案会把布局撑破） */
.gs-wrap { min-width: 0; }
.gs-wrap > .gs-trigger { min-width: 0; }

/* ---------- 数据层：视觉隐藏，但保留完整 DOM 语义 ---------- */
/* ⚠ 用 opacity:0 而不是 display:none / visibility:hidden：
     · display:none 会让元素脱离布局，某些浏览器下 selectedIndex 读取异常，
       且它祖先的 :nth-child 选择器会错位；
     · visibility:hidden 仍占位但没有 2×2 的 rect，也不便调试。
   opacity:0 + pointer-events:none 让元素**仍在布局中、仍可被程序读写**，
   只是点不到、看不见。它绝对定位是为了不占 wrapper 的尺寸 —— 尺寸由 trigger 决定。 */
.gs-native {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  pointer-events: none;
  z-index: -1;
  /* 保持原生控件的可访问性树存在，不影响程序化读写 */
}

/* ---------- 视觉层 ---------- */
.gs-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  width: 100%;
  min-width: 0;
  /* 尺寸兜底：wrapper 上的业务 class 若没给 padding/font-size，用这套默认值 */
  padding: 8px 30px 8px 12px;
  font-size: 13px;
  font-family: inherit;
  line-height: 1.4;
  text-align: left;
  color: var(--text-1);
  background-color: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-top-color: var(--glass-border-strong);
  border-radius: var(--radius-sm);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45),
              0 1px 2px rgba(30, 42, 74, 0.06);
  backdrop-filter: var(--glass-blur-light);
  -webkit-backdrop-filter: var(--glass-blur-light);
  cursor: pointer;
  transition: all var(--t-fast);
  overflow: hidden;
}
:root[data-theme="navy"] .gs-trigger {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08),
              0 1px 2px rgba(0, 0, 0, 0.2);
}
.gs-trigger:hover:not(:disabled) {
  border-color: var(--primary);
  background-color: var(--glass-bg-card);
}
.gs-trigger:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.gs-wrap.is-open > .gs-trigger {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* 关闭态文案 */
.gs-text {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.gs-text.is-placeholder { color: var(--text-3); }

/* 箭头 */
.gs-caret {
  position: absolute;
  right: 10px;
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  color: var(--text-3);
  pointer-events: none;
  transition: transform var(--t-fast);
}
.gs-wrap.is-open > .gs-trigger .gs-caret { transform: rotate(180deg); }

/* 禁用态：视觉降级 + 去掉手型（原生 select 的 disabled 已在 JS 里同步） */
.gs-wrap.is-disabled > .gs-trigger {
  opacity: 0.55;
  cursor: not-allowed;
  background-color: var(--bg-soft);
  border-color: var(--border);
  box-shadow: none;
}
.gs-wrap.is-disabled > .gs-trigger:hover { border-color: var(--border); background-color: var(--bg-soft); }

/* 尺寸继承：把 wrapper 上业务 class 的 padding/font-size 转译到 trigger 上。
   ⚠ 这几条必须放在 .gs-trigger 主规则**之后**，否则被主规则覆盖。
   §为什么用「父级 class 前缀」而不是给 trigger 也挂同样的 class：
     若 trigger 也带 .glass-select，它就会同时命中 `.select, .glass-select` 那条
     既有规则，两套 background-image / padding 打架，难以预期。 */
.gs-wrap.rank-snap-sel > .gs-trigger { padding: 6px 28px 6px 8px; font-size: 12px; }
.gs-wrap.select-sm > .gs-trigger { padding: 7px 26px 7px 10px; font-size: 13px; }
.gs-wrap.set-select > .gs-trigger,
.gs-wrap.bow-select > .gs-trigger { padding: 6px 28px 6px 10px; font-size: 12.5px; }
.gs-wrap.pz-school-sel > .gs-trigger { padding: 8px 30px 8px 12px; font-size: 13px; }
.calc-acc-switcher .gs-wrap > .gs-trigger { padding: 5px 26px 5px 10px; font-size: 12px; }
.calc-acc-switcher .gs-wrap { min-width: 150px; max-width: 220px; }

/* ---------- 浮层面板 ---------- */
/* ⚠ position:fixed 且挂 body 是唯一能逃出弹窗裁切的做法：
     .modal / .glass-modal 是 overflow:hidden + max-height:86vh，
     .modal-body 是滚动容器，absolute 浮层必被裁。
   ⚠ 祖先中若有 transform / filter / will-change 会创建包含块，使 fixed 退化为
     absolute —— 故本元素**必须**直接挂在 body 下（body 上无 transform）。 */
.gs-panel {
  position: fixed;
  z-index: 1500;   /* 高于 .modal-overlay(1000)，低于 #toastContainer(2000) */
  min-width: 120px;
  max-height: 264px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 5px;
  background: var(--gs-menu-bg);
  border: 1px solid var(--gs-menu-border);
  border-radius: var(--radius);
  box-shadow: var(--gs-menu-shadow);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  animation: gsPop 0.14s ease;
  transform-origin: top center;
}
.gs-panel.is-drop-up { transform-origin: bottom center; }

@keyframes gsPop {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.gs-panel.is-drop-up { animation: gsPopUp 0.14s ease; }
@keyframes gsPopUp {
  from { opacity: 0; transform: translateY(4px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* 分组标题（对应原生 optgroup 的 label） */
.gs-group-label {
  padding: 7px 11px 3px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--gs-menu-label);
  user-select: none;
}
.gs-group-label + .gs-opt { margin-top: 0; }
.gs-group-label:not(:first-child) {
  margin-top: 4px;
  border-top: 1px solid var(--gs-menu-divider);
  padding-top: 8px;
}

/* 选项 */
.gs-opt {
  padding: 8px 11px;
  font-size: 13px;
  line-height: 1.35;
  color: var(--gs-menu-text);
  border-radius: calc(var(--radius) - 4px);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background var(--t-fast), color var(--t-fast);
}
/* 高亮/选中态用 --gs-menu-accent（逐主题校正过的可读深色，见变量区注释）。
   §别改回 var(--primary)：浅色系主题的 --primary 压在半透白面板上对比度只有 2.1~2.5。 */
.gs-opt.is-active,
.gs-opt:hover {
  background: var(--primary-soft);
  color: var(--gs-menu-accent);
}
.gs-opt.is-active { font-weight: 600; }
/* 当前选中项：左侧竖条标记，与 .is-active 的高亮区分开 */
.gs-opt[aria-selected="true"] { color: var(--gs-menu-accent); font-weight: 600; }
.gs-opt[aria-selected="true"]::before {
  content: '';
  display: inline-block;
  width: 3px;
  height: 12px;
  margin-right: 7px;
  vertical-align: -1px;
  border-radius: 2px;
  background: var(--primary);
}
/* 不可选项（原生 <option disabled>） */
.gs-opt.is-disabled {
  color: var(--gs-menu-label);
  opacity: 0.5;
  cursor: not-allowed;
  text-decoration: line-through;
}
.gs-opt.is-disabled:hover { background: none; color: var(--gs-menu-label); }

/* 空态 */
.gs-empty {
  padding: 12px 11px;
  font-size: 12.5px;
  color: var(--gs-menu-label);
  text-align: center;
  user-select: none;
}

/* 滚动条跟随玻璃风，避免默认滚动条把圆角切掉 */
.gs-panel::-webkit-scrollbar { width: 8px; }
.gs-panel::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
}
.gs-panel::-webkit-scrollbar-track { background: transparent; }

/* 窄屏：面板本身由 JS 夹进视口，这里只收敛内边距 */
@media (max-width: 560px) {
  .gs-panel { max-height: 220px; padding: 4px; }
  .gs-opt { padding: 9px 10px; }
}

/* ==========================================================================
   v7.24.0（用户需求 D-1/D-2）· 角色同步 / 快捷导入
   --------------------------------------------------------------------------
   替代了 v7.13.0~v7.23.0 的账号体系（登录 / 注册 / 好友 / 查看面板）。
   两件事在这里被表达：
     ① 上传本机角色到服务器 → 每个角色拿到一个 4-10 位纯数字校验码；
     ② 角色名搜索 + 输入校验码 → 把别人电脑上的角色导入本机。

   §命名与复用：
     弹窗外壳（.modal-overlay / .glass-modal / .modal-header / .auth-tabs …）沿用旧样式，
     .auth-tab 就是那两个 Tab 的按钮 —— 不另起一套，避免同一弹窗里出现两种 Tab 观感。
     本段只补 sync-* 专属部分。

   §两条视觉原则（与项目其余部分一致）：
     · 校验码是"要念给人听"的东西 → 用等宽 + 加大字距 + 大字号，方便逐个数字核对；
     · 搜索结果是"要核对自己找对了没有"的东西 → 角色名最大最重，其余元信息降级为灰字。
   ========================================================================== */

/* ---- 引导文案 ---- */
.sync-lead {
  margin: 0 0 14px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--text-2);
}
.sync-lead strong { color: var(--text-1); }

/* ---- ★ v7.24.0：上传时的「逐角色填码」列表 ----
   结构（由 auth.js 的 renderUploadHint 生成）：
     .sync-code-rows
       .sync-code-rows-title
       .sync-code-rows-list
         .sync-code-row-input
           .sync-code-role   ← 角色名
           input.sync-code-field
       .sync-code-rows-tips
   §为什么用 flex 横排「角色名 + 输入框」而不是每个角色一张卡片：
     本机角色数常见是 1~3 个，行式排布一屏就能看全，且"名 → 码"的对应关系
     在水平方向上一目了然（卡片式会把对应关系变成上下结构，多角色时反而不好扫）。
   §窄屏（见文件末尾的 @media）会改成纵向堆叠：输入框固定宽度在手机上会挤压角色名。 */
.sync-code-rows { margin: 0 0 4px; }
.sync-code-rows-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  margin: 0 0 8px;
}
.sync-code-rows-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* 角色多时（上限 50 个）限制高度并允许滚动，避免把提交按钮顶出视口 */
  max-height: 260px;
  overflow-y: auto;
  padding-right: 2px;
}
.sync-code-row-input {
  display: flex;
  align-items: center;
  gap: 10px;
}
.sync-code-role {
  flex: 0 0 40%;
  min-width: 0;
  font-size: 13px;
  color: var(--text-1);
  /* 角色名过长时省略号，不撑破布局 —— title 属性里存了全名 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sync-code-field {
  flex: 1 1 auto;
  min-width: 0;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 15px;
  letter-spacing: 3px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding: 9px 10px !important;
}
.sync-code-rows-tips {
  margin: 10px 0 0;
  font-size: 11.5px;
  line-height: 1.85;
  color: var(--text-3);
}
.sync-code-rows-tips b { color: var(--text-2); }

/* ---- ★ v7.24.1：名称辨识引导（上传时）----
   结构：<details class="sync-name-tip"><summary>…</summary><div class="sync-name-tip-body">…</div></details>
   §为什么折叠：这段是"值得知道但不影响操作"的补充说明，而填码才是本页主任务。
     默认展开会把填码列表挤下去；折叠后既可见又不抢注意力。
   §为什么 <summary> 要带一句"点开看看"：纯标题的 summary 用户会当成
     又一个说明标签而略过。加上动作提示，点击率会明显不同。 */
.sync-name-tip {
  margin: 10px 0 0;
  font-size: 11.5px;
  line-height: 1.8;
  color: var(--text-3);
  border-top: 1px dashed var(--line-2, rgba(255, 255, 255, 0.08));
  padding-top: 8px;
}
.sync-name-tip > summary {
  cursor: pointer;
  color: var(--text-2);
  font-weight: 600;
  /* §去掉默认三角再自绘，是为了让不同浏览器（尤其 Safari）的 summary 观感一致 */
  list-style: none;
  outline: none;
}
.sync-name-tip > summary::-webkit-details-marker { display: none; }
.sync-name-tip > summary::before {
  content: '▸ ';
  display: inline-block;
  transition: transform 0.15s ease;
}
.sync-name-tip[open] > summary::before { content: '▾ '; }
.sync-name-tip > summary:hover { color: var(--text-1); }
.sync-name-tip-body {
  margin: 6px 0 0;
  padding-left: 2px;
  color: var(--text-3);
}
.sync-name-tip-body b { color: var(--text-2); }
/* §"同名不会影响功能"这句用 success 色单独标出来：
   用户最初的顾虑就是"同名会不会坏"，这是这段话里**唯一需要被记住**的一句，
   其余都是建议。视觉上把它从"一排建议"里拎出来。
   §用 --success 而不是新的 --ok：本文件已有该变量（亮/暗两套主题各自定义），
     自造变量会在暗色主题下失效 —— 这类"变量名写错导致某主题下没颜色"的 bug 极难发现。 */
.sync-name-tip-calm { color: var(--success); }

/* ---- 校验码输入 ---- */
.sync-code-input {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 17px;
  letter-spacing: 6px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding: 11px 10px !important;
}
/* 未选中角色时把输入框压成明显的"还不能用"状态（比单纯 disabled 更易读） */
.sync-code-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--bg-soft-2);
}

/* ---- 已选中的导入目标 ---- */
.sync-import-target {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 12px;
  margin: 2px 0 4px;
  font-size: 13px;
  color: var(--text-1);
  background: var(--primary-soft, var(--bg-soft-2));
  border: 1px solid var(--primary);
  border-radius: var(--radius-sm);
}
/* ★ v7.24.1：重名时在确认区补显这条记录的概况，让用户输码前有一次"有没有点错"的自查机会。
   §为什么它要占满一整行而不是跟在名字后面：
     概况本身较长（"鸣金 · 穿戴 6 件 · 装备库 12 件 · 更新于 2026-09-26 15:20"），
     跟在名字后会被挤成省略号，而它存在的**唯一目的**就是被读全。 */
.sync-import-detail {
  flex: 1 1 100%;
  font-size: 11.5px;
  color: var(--text-3);
  line-height: 1.6;
}
/* ★ v7.24.1：重名时的「点错人」兜底说明。
   §为什么这句话必须存在：服务端对"码不对"和"角色不存在"**故意**回同一句话
     （防 id 枚举）。这个安全性设计带来一个副作用 —— 用户点错条目后，
     看到的提示完全指向"你的码有问题"。若不在此处提前说明另一种可能，
     他会去反复重输同一串正确的码，永远找不到真正的原因。 */
.sync-import-warn {
  flex: 1 1 100%;
  margin-top: 4px;
  padding: 7px 9px;
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--text-2);
  background: var(--warning-soft);
  border-left: 2px solid var(--warning);
  border-radius: 0 5px 5px 0;
}
.sync-import-warn b { color: var(--text-1); }

/* ---- 上传结果：校验码清单 ---- */
.sync-code-result { margin-top: 14px; }
/* 标题条：成功用 success 主色，避免让人以为出了问题 */
.sync-code-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--success);
  margin-bottom: 8px;
}
.sync-code-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 240px;
  overflow-y: auto;      /* 一次传 50 个角色时会很长，必须能滚 */
}
.sync-code-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-1, rgba(255, 255, 255, 0.4));
}
.sync-code-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 校验码本体：等宽 + 字距 + 选中态便于双击全选复制 */
.sync-code-val {
  flex: 0 0 auto;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 15px;
  letter-spacing: 3px;
  font-variant-numeric: tabular-nums;
  color: var(--primary);
  background: var(--bg-soft-2);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-xs);
  padding: 3px 9px;
  user-select: all;
}
.sync-code-actions { display: flex; gap: 6px; flex-shrink: 0; }
/* 校验码丢失警告 —— 这是本功能唯一"不可挽回"的后果，必须显眼但不吓人 */
.sync-code-warn {
  margin-top: 10px;
  padding: 9px 12px;
  font-size: 12px;
  line-height: 1.65;
  color: var(--text-2);
  background: var(--danger-soft, var(--bg-soft-2));
  border-left: 3px solid var(--danger);
  border-radius: var(--radius-sm);
}

/* ---- 搜索结果 ---- */
.sync-search-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-1, rgba(255, 255, 255, 0.4));
}
/* ★ v7.24.1：重名条目的行样式 —— 左侧一道警示色细边。
   §为什么按"整行"标记而不是只给名字加个图标：
     重名的两个条目在列表里是**上下相邻**的，用户扫视时是按"整行"跳的。
     只在名字上加一个小标记，扫视时几乎注意不到；整行加边才拦得住视线。
   §为什么用左细边而不是整块变色：整块变色会让这两条看起来像"出错的记录"，
     而它们本身完全正常 —— 要传达的是"这两条需要你多看一眼",不是"这两条有问题"。 */
.sync-search-row-dup {
  border-left: 3px solid var(--warning);
  background: var(--warning-soft);
}
/* 重名徽标：明确说出"另有几个" —— "重名"两个字本身不够，
   用户会疑惑"是不是重复上传了"，给出数量才能让他理解这是**多个独立记录**。 */
.sync-search-dup-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  color: var(--warning);
  background: var(--warning-soft);
  border: 1px solid var(--warning);
  padding: 0 6px;
  border-radius: 999px;
  margin-left: 6px;
  vertical-align: 1px;
}
.sync-search-main { flex: 1 1 auto; min-width: 0; }
/* ★ v7.24.1：把 .sync-search-main 改成**两行网格**（原来只是普通块，靠 inline 元素自然换行）。
   §为什么必须改结构，不能只靠 margin：改之前它是普通块，里面全是 inline 元素
     —— [名字][ID][标记][重名徽标][概况][时间] 会**依次排在同一行**，
     靠 .sync-search-meta 的 margin-top 换行。但 margin-top 对 inline 元素**无效**，
     所以只要前面的元素够多，概况就会跟徽标挤在一起（实拍截图里
     「重名 · 另有 1 个」和「鸣金 · 穿戴 6 件」粘成了一串，就是这么来的）。
   §用 grid 而不是给 meta 加 display:block：
     display:block 也会换行，但会把 [名字][ID][标记][徽标] 那一行也变成独立块，
     时间戳就掉到第三行了。grid 明确声明"第一行是身份、第二行是概况"，
     与设计意图一一对应，后续加字段也不会再乱。 */
.sync-search-main {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
}
/* 第一行：名字 + 各种标签（作为一个整体，内部用 inline-flex 允许换行） */
.sync-search-line1 {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 6px;
  min-width: 0;
}
.sync-search-name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sync-search-id {
  font-size: 11px;
  color: var(--text-3);
  margin-left: 6px;
}
/* 来源标记 / 流派标签：胶囊形，与项目其余 pill 保持一致 */
.sync-search-tag {
  display: inline-block;
  font-size: 11px;
  color: var(--text-3);
  background: var(--divider);
  padding: 1px 7px;
  border-radius: 999px;
  margin-right: 6px;
}
.sync-search-meta {
  font-size: 11.5px;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 时间戳单独一行 —— 它是同名时三条辨别依据中最可靠的一条（件数可能碰巧一样，
   但更新时间几乎不可能相同），所以不跟概况挤在一起，给它独立的一行。 */
.sync-search-time {
  color: var(--text-3);
  font-size: 11.5px;
}
.sync-search-ops { flex: 0 0 auto; }
.sync-search-foot {
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--text-3);
  line-height: 1.6;
}

/* ---- 通用降级 / 警告文本 ---- */
.sync-dim { font-size: 11.5px; color: var(--text-3); }
.sync-warn { color: var(--danger); font-size: 12.5px; }

/* 窄屏：校验码行改为纵向堆叠 —— 横排时角色名会被挤到只剩两三个字 */
@media (max-width: 560px) {
  .sync-code-row { flex-wrap: wrap; }
  .sync-code-name { flex: 1 1 100%; }
  .sync-code-input { letter-spacing: 4px; font-size: 16px; }
  .sync-search-row { flex-wrap: wrap; }
  .sync-search-ops { flex: 1 1 100%; }
  .sync-search-ops .glass-btn { width: 100%; }
  /* ★ v7.24.0：窄屏下「角色名 + 码输入框」改为纵向堆叠。
     §为什么必须堆叠：横排时角色名占 40%、输入框占 60%，
       在 320px 宽的屏上输入框只剩不到 180px，而码最长 10 位 + 字距 3px，
       会顶到边界甚至溢出。堆叠后输入框能占满宽度，"名 → 码"的对应关系
       靠上下相邻仍然清晰（本机角色通常只有 1~3 个）。 */
  .sync-code-row-input { flex-wrap: wrap; gap: 6px; }
  .sync-code-role { flex: 1 1 100%; }
  .sync-code-field { flex: 1 1 100%; }
  .sync-code-rows-list { max-height: 300px; }
}
