/* ===========================================================
   AI 生图系统 · 自定义样式
   参考「星俊智画工坊」的玻璃拟态 + 渐变流光风格
   =========================================================== */

/* ===========================================================
   ★★ v2.687：设计变量层（design tokens）
   -----------------------------------------------------------
   🔴 用户要求：「页面不好看的改下配色和CSS」

   ★ 先量化了现状，问题不是"某个颜色丑"，而是【不统一】：
       · 颜色 239 种，其中 116 种只出现过 1~2 次（=杂色）
       · 圆角 82 种取值 —— 按钮/标签 20 种、卡片/面板 20 种、输入框 6 种
       · 阴影 115 种取值
       · 而 :root 里只有 6 个变量，且 studio-split.css /
         layout-unify.css / admin-fill.css 里 var() 用了 0 次
     ⇒ 结论：有变量层，但形同虚设 —— 页面只能各自硬编码，
        于是"同一类组件在不同页面长得不一样"，整体就显得"不好看"。

   ★ 这一版做的事：把变量层建【全】，让以后统一有依据。
     ⚠️ 只【新增】变量，不改任何现有规则 ——
        所以这次改动对现有页面【零视觉影响】（是地基，不是改版）。
        真正让页面变统一的是"以后写新样式时用变量 + 逐步替换"，
        以及本文件下面几条把最高频的杂色收敛到变量的规则。

   ★ 取值依据（都是从实际用得最多的值里挑的，不是我凭空定的）：
       主色 #7c3aed（用了 204 次）—— 注意不是 --brand-from 的 #9333ea。
       ⚠️ 这两个紫并存就是"不统一"的来源之一：
          #7c3aed 是 violet-600、#9333ea 是 purple-600，色相只差一点，
          挨在一起看就是"两个紫但不一样"。
          ⇒ 保留 --brand-from 不动（有 12 处在用，改了会变），
            但新增 --brand 指向真正的实际主色，新代码一律用它。
   ============================================================ */
:root {
  /* ---------- 品牌色 ----------
     ⚠️ --brand 是【实际在用的】主色（#7c3aed），新代码用它；
        --brand-from 是历史遗留的另一个紫（#9333ea），保留兼容。 */
  --brand: #7c3aed;
  --brand-dark: #6d28d9;          /* 悬停/按下 */
  --brand-light: #a78bfa;         /* 次要强调 */
  --brand-soft: #f5f3ff;          /* 极浅底（选中态背景） */
  --brand-line: #c4b5fd;          /* 浅色描边（选中态边框） */
  --brand-grad-to: #06b6d4;       /* 渐变另一端（青） */
  --brand-indigo: #6366f1;        /* 渐变中间色（按钮渐变在用） */

  /* ---------- 中性色阶 ----------
     ⚠️ 原来是散的：#9ca3af / #6b7280 / #4b5563 / #374151 / #1f2937
        五个灰都能当"次要文字"用 ⇒ 同一个页面里两种灰并存，看着脏。
        按【用途】命名而不是按深浅命名（--ink-3 这种名字没法判断该用哪个）。 */
  --text: #1f2937;                /* 正文（比 --ink 浅一点，长文更耐看） */
  --text-strong: #111827;         /* 标题 */
  --text-mute: #6b7280;           /* 次要说明 */
  --text-faint: #9ca3af;          /* 最弱（时间戳、占位） */

  /* ---------- 背景与描边 ---------- */
  --bg: #f7f8fc;                  /* 页面底 */
  --bg-soft: #f8fafc;             /* 区块底（比页面底再浅一档） */
  --surface: #ffffff;             /* 卡片面 */
  --border: #e5e7eb;              /* 主描边 */
  --border-soft: #eef0f5;         /* 弱描边（分隔线） */

  /* ---------- 语义色 ----------
     ⚠️ 每档都配"文字色 + 浅底"一对 ——
        只给文字色的话，写提示条时还得自己调浅底，又会出现杂色。 */
  --ok: #047857;      --ok-bg: #ecfdf5;      --ok-line: #6ee7b7;
  --warn: #b45309;    --warn-bg: #fffbeb;    --warn-line: #fcd34d;
  --danger: #b91c1c;  --danger-bg: #fef2f2;  --danger-line: #fecaca;
  --info: #1d4ed8;    --info-bg: #eff6ff;    --info-line: #bfdbfe;

  /* ---------- 圆角 ----------
     ★ 5 档，按【组件类型】定，不是按"好不好看"：
        xs  4px  —— 小角标、内嵌小块
        sm  8px  —— 按钮、输入框、chip（小而密的控件）
        md  12px —— 中卡片、缩略图、下拉
        lg  16px —— 大卡片、面板（= 原来的 --radius，所以 --radius 仍可用）
        xl  20px —— 弹窗、抽屉、大面积容器
        pill 999px —— 胶囊（标签、状态点）；圆形一律 50%（不在这里）
     ⚠️ 为什么是这 5 档：原来的 82 种取值去重后，绝大多数落在这 5 档附近
        （9px≈8、10px≈8~12、.95rem≈16、1.05/1.1rem≈16~20），
        收敛到 5 档能消掉大部分"看着差一点"的别扭。 */
  --r-xs: 4px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-pill: 999px;

  /* ---------- 阴影 ----------
     ★ 4 档，按【层级】定：
        sm  贴在页面上（卡片默认）
        md  悬停抬起
        lg  浮层（下拉、气泡）
        xl  弹窗
     ⚠️ 色相统一用 rgba(31,38,135,…)（原来用得最多的那个蓝紫调），
        不再混用纯黑阴影 —— 纯黑阴影在浅紫底上会发灰、显脏。 */
  --sh-sm: 0 1px 3px rgba(31, 38, 135, .06);
  --sh-md: 0 6px 18px rgba(31, 38, 135, .08);
  --sh-lg: 0 14px 38px rgba(31, 38, 135, .14);
  --sh-xl: 0 24px 60px rgba(31, 38, 135, .20);

  /* ---------- 历史兼容（原有 6 个，值不动）---------- */
  --brand-from: #9333ea;
  --brand-to: #06b6d4;
  --ink: #111827;
  --ink-soft: #4b5563;
  --line: #e5e7eb;
  --radius: 1rem;
}

/* ===========================================================
   ★★ v2.687：暗色主题的变量覆盖
   -----------------------------------------------------------
   ⚠️ 现状（我核对过）：暗色主题里【变量覆盖 0 个】，硬编码 hex 有 954 处。
      也就是说暗色完全是"另写一套颜色"，和亮色没有任何共享。
   ⚠️ 这会导致：以后改亮色配色，暗色不会跟着变 —— 两套会越走越远。
   ★ 这里补上变量层的暗色映射。
     ⚠️ 只覆盖【本文件新增的语义变量】+ 原有的几个，
        不去动那 954 处硬编码（动它们风险太大、收益不明显）——
        所以这次暗色主题【视觉上基本不变】，
        变的是"以后新写的样式能自动适配两种主题"。
   ⚠️ 取值从现有暗色硬编码里挑用得最多的：
        #161a24（面板底）/ #1b2029（卡片）/ #12161e（更深）
        #dfe3ea / #cbd5e1（正文）· rgba(255,255,255,.1)（描边）
   =========================================================== */
html[data-theme="dark"] {
  --brand: #a78bfa;               /* 暗底上要用更亮的紫才看得清 */
  --brand-dark: #8b5cf6;
  --brand-light: #c4b5fd;
  --brand-soft: #241d33;
  --brand-line: #4c3a72;

  --text: #dfe3ea;
  --text-strong: #f3f4f6;
  --text-mute: #9ca3af;
  --text-faint: #6b7280;

  --bg: #0f1319;
  --bg-soft: #161a24;
  --surface: #1b2029;
  --border: rgba(255, 255, 255, .12);
  --border-soft: rgba(255, 255, 255, .07);

  /* ⚠️ 语义色在暗底上要提亮，否则 #047857 这种深绿在暗底上糊成一团 */
  --ok: #34d399;      --ok-bg: #06281f;      --ok-line: #10603f;
  --warn: #fbbf24;    --warn-bg: #2a2008;    --warn-line: #6b4d0a;
  --danger: #f87171;  --danger-bg: #2a0f0f;  --danger-line: #6b1f1f;
  --info: #60a5fa;    --info-bg: #0b1a33;    --info-line: #1e3a6b;

  /* ⚠️ 阴影在暗底上要更重（否则"抬起"看不出来） */
  --sh-sm: 0 1px 3px rgba(0, 0, 0, .4);
  --sh-md: 0 6px 18px rgba(0, 0, 0, .45);
  --sh-lg: 0 14px 38px rgba(0, 0, 0, .5);
  --sh-xl: 0 24px 60px rgba(0, 0, 0, .6);
}

* {
  -webkit-tap-highlight-color: transparent;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',
    'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif;
  color: var(--ink);
  background: #f7f8fc;
}

/* ---------- 动态渐变背景 ---------- */
.animated-bg {
  background: linear-gradient(-45deg, #a78bfa, #f0abfc, #67e8f9, #6ee7b7);
  background-size: 400% 400%;
  animation: gradientBG 18s ease infinite;
}
@keyframes gradientBG {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

.bg-blobs {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.bg-blobs span {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.5;
}
.bg-blobs span:nth-child(1) { width: 42vw; height: 42vw; left: -10vw; top: -8vw; background: #c4b5fd; }
.bg-blobs span:nth-child(2) { width: 36vw; height: 36vw; right: -8vw; top: 12vh; background: #a5f3fc; }
.bg-blobs span:nth-child(3) { width: 34vw; height: 34vw; left: 22vw; bottom: -14vw; background: #fbcfe8; }

/* ---------- 玻璃拟态 ----------
   毛玻璃强度调低了：blur 20px → 10px、底色更实（0.55 → 0.72）。
   强度太高时透过卡片看到的背景是糊的，长时间看很费眼；
   底色太透也会拉低文字对比度。 */
.glass-effect {
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: 0 8px 32px rgba(31, 38, 135, 0.08);
}
.glass-strong {
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border: 1px solid rgba(255, 255, 255, 0.8);
}

/* ---------- 悬浮反馈 ----------
   ★ 这里【完全不用 transform】，也不要 transform-style: preserve-3d。

   为什么连 translateY 都不能用：
     卡片带 .glass-effect（backdrop-filter），浏览器会把它光栅化成一张位图。
     而过渡动画的每一帧都是「小数位移」—— 0 到 -6px 之间会经过 -2.37px 这种值，
     位图在非整数像素位置必须重新采样，于是整个动画过程文字都是糊的。
     动画结束虽然会变清晰，但每次悬停都糊一下，非常费眼。

   改成只动「阴影 + 边框」：这两者不参与位图重采样，
   文字与图标始终按原生分辨率渲染，永远清晰。
   视觉上靠「阴影变大变深」同样能读出浮起来的感觉。
   （也不要改 background-color —— 卡片会变亮，文字对比度下降，看着发虚） */
.hover-3d {
  transition: box-shadow 0.3s ease, border-color 0.3s ease;
}
.hover-3d:hover {
  box-shadow: -10px 24px 52px rgba(31, 38, 135, 0.20),
              0 0 22px rgba(255, 255, 255, 0.8) inset;
  border-color: rgba(255, 255, 255, 0.95);
  /* ★ 这里不要再改 background-color：
     变亮会让卡片里的文字对比度下降，看起来发虚。 */
}

/* ---------- 鼠标光晕 ----------
   ★ 原先是 rgba(255,255,255,0.45) 的一圈白光，而且是 z-index:1
   —— 盖在文字【上面】，鼠标一动就跟着走，等于给文字蒙了层白雾。
   现在把透明度降到 0.10、扩大衰减范围，只留一点点高光质感，
   不再影响文字清晰度。 */
.card-glow { position: relative; overflow: hidden; }
.card-glow::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(520px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
    rgba(255, 255, 255, 0.10), transparent 55%);
  opacity: 0;
  transition: opacity 0.5s ease;
  pointer-events: none;
  z-index: 1;
}
.card-glow:hover::before { opacity: 1; }

/* ---------- 渐变文字 ---------- */
.text-gradient {
  background: linear-gradient(90deg, var(--brand-from), var(--brand-to), #f59e0b, var(--brand-from));
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: shimmer 4s linear infinite;
  font-weight: 800;
}
@keyframes shimmer {
  to { background-position: 200% center; }
}

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.4rem;
  border-radius: 0.9rem;
  font-size: 0.9rem;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: all 0.25s ease;
  white-space: nowrap;
}
.btn-primary {
  color: #fff;
  background: linear-gradient(135deg, var(--brand-from), var(--brand-to));
  box-shadow: 0 6px 18px rgba(147, 51, 234, 0.28);
}
.btn-primary:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(147, 51, 234, 0.38);
}
.btn-ghost {
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid var(--line);
}
.btn-ghost:hover:not(:disabled) { background: #fff; color: var(--ink); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; transform: none !important; }
.btn-lg { padding: 0.95rem 1.8rem; font-size: 1rem; border-radius: 1rem; }

/* ---------- 标签页 ---------- */
.tool-tab {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1.15rem;
  border-radius: 0.85rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  transition: all 0.25s ease;
}
.tool-tab:hover { background: rgba(255, 255, 255, 0.7); color: var(--ink); }
.tool-tab.active {
  color: #fff;
  background: linear-gradient(135deg, var(--brand-from), var(--brand-to));
  box-shadow: 0 6px 16px rgba(147, 51, 234, 0.25);
}

/* ---------- 表单 ---------- */
.field {
  width: 100%;
  padding: 0.8rem 1rem;
  border-radius: 0.85rem;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.85);
  font-size: 0.9rem;
  color: var(--ink);
  transition: border-color 0.2s, box-shadow 0.2s;
  outline: none;
}
.field:focus {
  border-color: #c084fc;
  box-shadow: 0 0 0 4px rgba(192, 132, 252, 0.15);
}
textarea.field { resize: vertical; min-height: 110px; line-height: 1.6; }
.field-label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-soft);
  margin-bottom: 0.4rem;
}

/* 选项胶囊 */
.chip {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.8);
  border: 1px solid var(--line);
  cursor: pointer;
  transition: all 0.2s;
  user-select: none;
}
.chip:hover { border-color: #c084fc; color: var(--ink); }
.chip.active {
  color: #fff;
  border-color: transparent;
  background: linear-gradient(135deg, var(--brand-from), var(--brand-to));
}

/* ---------- 结果区 ---------- */
.result-stage {
  position: relative;
  min-height: 380px;
  border-radius: var(--radius);
  background:
    linear-gradient(rgba(255,255,255,0.6), rgba(255,255,255,0.6)),
    repeating-conic-gradient(#eef0f6 0% 25%, #f8f9fc 0% 50%) 50% / 22px 22px;
  border: 1px dashed var(--line);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.result-stage img { max-width: 100%; max-height: 62vh; object-fit: contain; }

.spinner {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 4px solid rgba(147, 51, 234, 0.15);
  border-top-color: var(--brand-from);
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.progress-track {
  width: 100%;
  max-width: 320px;
  height: 8px;
  border-radius: 999px;
  background: #e9eaf2;
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  width: 5%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--brand-from), var(--brand-to));
  transition: width 0.5s ease;
}

/* ---------- 作品卡片 ---------- */
.work-card {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line);
  cursor: pointer;
  transition: transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.35s;
}
.work-card:hover { transform: translateY(-6px); box-shadow: 0 18px 40px rgba(17, 24, 39, 0.14); }
.work-card img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  display: block;
  background: #f3f4f6;
}
.work-card .overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.5rem;
  padding: 0.9rem;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0) 55%);
  opacity: 0;
  transition: opacity 0.3s;
}
.work-card:hover .overlay { opacity: 1; }
.work-card .overlay p {
  color: #fff;
  font-size: 0.78rem;
  line-height: 1.5;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.work-card .actions { display: flex; gap: 0.5rem; }
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  color: #fff;
  background: rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(6px);
  cursor: pointer;
  transition: background 0.2s ease, box-shadow 0.2s ease;
}
/* 不用 scale / translate —— 按钮带 backdrop-filter，
   任何位移都会在过渡期间重采样而发虚（见 .hover-3d 的说明） */
.icon-btn:hover {
  background: var(--brand-from);
  box-shadow: 0 6px 18px rgba(147, 51, 234, 0.42);
}

/* ---------- 分页 ---------- */
.pagination { display: flex; justify-content: center; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pagination button {
  min-width: 2.5rem;
  height: 2.5rem;
  padding: 0 0.75rem;
  border-radius: 0.75rem;
  background: #fff;
  color: var(--ink-soft);
  font-size: 0.875rem;
  font-weight: 500;
  border: 1px solid var(--line);
  cursor: pointer;
  transition: all 0.25s;
}
.pagination button:hover:not(:disabled) { background: #f3f4f6; color: var(--ink); }
.pagination button.active {
  color: #fff;
  border-color: transparent;
  background: linear-gradient(135deg, var(--brand-from), var(--brand-to));
  box-shadow: 0 4px 12px rgba(147, 51, 234, 0.25);
}
.pagination button:disabled { background: #f9fafb; color: #d1d5db; cursor: not-allowed; }

/* ---------- 模态框 ---------- */
.modal-mask {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(17, 24, 39, 0.55);
  backdrop-filter: blur(4px);
  animation: fadeIn 0.25s ease;
}
.modal-box {
  width: 100%;
  max-width: 440px;
  border-radius: 1.25rem;
  background: #fff;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
  animation: popIn 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.2);
  max-height: 92vh;
  overflow: auto;
}
.modal-box.wide { max-width: 920px; background: transparent; box-shadow: none; }
@keyframes fadeIn { from { opacity: 0; } }
/* 弹窗入场：只淡入，不做缩放/位移 ——
   弹窗内容带 backdrop-filter，动画期间带位移同样会让文字发虚 */
@keyframes popIn { from { opacity: 0; } }

/* ---------- Toast ---------- */
#toast-host {
  position: fixed;
  left: 50%;
  bottom: 2rem;
  transform: translateX(-50%);
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  pointer-events: none;
}
.toast {
  padding: 0.7rem 1.3rem;
  border-radius: 1rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: #fff;
  background: rgba(17, 24, 39, 0.92);
  backdrop-filter: blur(8px);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25);
  animation: toastIn 0.3s ease;
}
.toast.error { background: rgba(185, 28, 28, 0.94); }
.toast.success { background: rgba(5, 122, 85, 0.94); }
@keyframes toastIn { from { opacity: 0; transform: translateY(14px); } }

/* ---------- 上传拖拽区 ---------- */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 150px;
  padding: 1.2rem;
  border-radius: 0.9rem;
  border: 2px dashed var(--line);
  background: rgba(255, 255, 255, 0.6);
  cursor: pointer;
  transition: all 0.25s;
  text-align: center;
}
.dropzone:hover, .dropzone.dragover { border-color: #c084fc; background: rgba(192, 132, 252, 0.07); }
.dropzone img { max-height: 190px; max-width: 100%; border-radius: 0.6rem; object-fit: contain; }

/* ---------- 滚动条 ---------- */
.custom-scrollbar::-webkit-scrollbar { width: 5px; height: 5px; }
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #d8dae5; border-radius: 4px; }
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #c2c5d4; }

/* ---------- 隐藏 ---------- */
.hidden { display: none !important; }

/* ---------- 骨架屏 ---------- */
.skeleton {
  background: linear-gradient(90deg, #eef0f6 25%, #f7f8fc 37%, #eef0f6 63%);
  background-size: 400% 100%;
  animation: skeleton 1.4s ease infinite;
}
@keyframes skeleton { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ===========================================================
   布局壳：左侧菜单 + 顶栏
   =========================================================== */
.app-shell {
  display: flex;
  min-height: 100vh;
  align-items: flex-start;
}

/* ---------- 侧栏 ---------- */
#sidebar-root {
  flex-shrink: 0;
  width: 196px;
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: 45;
  transition: width 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.sidebar-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: rgba(255, 255, 255, 0.62);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-right: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: 4px 0 24px rgba(31, 38, 135, 0.05);
}
.sidebar-loading {
  padding: 1.5rem 1.1rem;
  font-size: 0.82rem;
  color: #9ca3af;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.95rem 0.9rem;
  border-bottom: 1px solid rgba(229, 231, 235, 0.8);
  min-height: 64px;
}
.brand-link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 1;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
.brand-logo {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
  background: linear-gradient(135deg, #9333ea, #06b6d4);
  box-shadow: 0 6px 16px rgba(147, 51, 234, 0.28);
}
.brand-text {
  font-weight: 800;
  font-size: 1.02rem;
  white-space: nowrap;
  overflow: hidden;
}
.brand-text b {
  background: linear-gradient(90deg, #9333ea, #06b6d4);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
/* 代理商自定义 LOGO */
.brand-logo-img {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: 0.75rem;
  object-fit: contain;
  background: #fff;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.app-shell.collapsed .brand-logo-img {
  width: 34px;
  height: 34px;
}
.sidebar-collapse {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 0.5rem;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.9);
  color: #6b7280;
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
  transition: all 0.2s;
}
.sidebar-collapse:hover {
  background: #fff;
  color: #111827;
  border-color: #c084fc;
}

.sidebar-nav {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0.7rem 0.6rem 1rem;
}
.nav-group + .nav-group {
  margin-top: 0.35rem;
}
.nav-group-title {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: none;
  background: transparent;
  color: #9ca3af;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: none;
  cursor: pointer;
  border-radius: 0.6rem;
  transition: color 0.2s;
  white-space: nowrap;
}
.nav-group-title:hover {
  color: #6b7280;
}
.nav-group-icon {
  font-size: 0.85rem;
}
.nav-group-title .nav-text {
  flex: 1;
  text-align: left;
}
.nav-arrow {
  font-size: 0.65rem;
  transition: transform 0.25s;
}
.nav-group.collapsed .nav-arrow {
  transform: rotate(-90deg);
}
/* 分组折叠：用 grid-template-rows 0fr/1fr 实现，
   不用 max-height 猜测高度，菜单再多也不会被裁掉 */
.nav-group-items {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 0.28s ease;
}
.nav-group.collapsed .nav-group-items {
  grid-template-rows: 0fr;
}
.nav-group-inner {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-height: 0;
  overflow: hidden;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.58rem 0.7rem;
  border-radius: 0.7rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: #4b5563;
  text-decoration: none;
  white-space: nowrap;
  transition: all 0.2s ease;
  position: relative;
}
.nav-item:hover {
  background: rgba(147, 51, 234, 0.08);
  color: #6d28d9;
}
.nav-item.active {
  color: #fff;
  background: linear-gradient(135deg, #9333ea, #06b6d4);
  box-shadow: 0 6px 16px rgba(147, 51, 234, 0.28);
}
.nav-item.soon {
  color: #6b7280;
}
/* ★ 未上线的菜单被选中时必须是白字。
   原因：.nav-item.soon 写在 .nav-item.active 后面，两者优先级相同，
   所以「未上线」的灰字会覆盖「选中」的白字 —— 渐变底色配灰字根本看不清。
   这条规则放在最后，专门纠正这个组合。 */
.nav-item.soon.active,
.nav-item.soon.active .nav-text,
.nav-item.soon.active .nav-icon {
  color: #fff;
}
.nav-item.soon.active .nav-badge {
  background: rgba(255, 255, 255, 0.3);
  color: #fff;
}
.nav-icon {
  font-size: 1rem;
  width: 1.25rem;
  text-align: center;
  flex-shrink: 0;
}
.nav-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-badge {
  font-size: 0.58rem;
  font-weight: 700;
  padding: 0.12rem 0.34rem;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e;
  flex-shrink: 0;
}
.nav-item.active .nav-badge {
  background: rgba(255, 255, 255, 0.28);
  color: #fff;
}

.sidebar-footer {
  padding: 0.7rem 0.85rem 0.9rem;
  border-top: 1px solid rgba(229, 231, 235, 0.8);
}
.sidebar-tip {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.72rem;
  color: #9ca3af;
  white-space: nowrap;
}

/* ---------- 收起态（桌面） ---------- */
.app-shell.collapsed #sidebar-root {
  width: 68px;
}
/* ---------- 收起态（桌面，仅图标） ---------- */
.app-shell.collapsed .brand-text,
.app-shell.collapsed .nav-text,
.app-shell.collapsed .nav-arrow,
.app-shell.collapsed .nav-badge,
.app-shell.collapsed .sidebar-tip .nav-text {
  display: none;
}
/* 收起后品牌区竖排，保证「展开」按钮始终可见可点（此前这里是 display:none，导致收起后无法恢复） */
.app-shell.collapsed .sidebar-brand {
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem 0;
}
.app-shell.collapsed .sidebar-collapse {
  display: inline-block;
}
.app-shell.collapsed .brand-link {
  justify-content: center;
}
/* 收起态隐藏分组标题：标题在图标模式下极易被误点折叠，展开后菜单就"消失"了 */
.app-shell.collapsed .nav-group-title {
  display: none;
}
/* 用分隔线替代分组标题，仍能看出分组 */
.app-shell.collapsed .nav-group + .nav-group {
  margin-top: 0.35rem;
  padding-top: 0.35rem;
  border-top: 1px solid rgba(229, 231, 235, 0.9);
}
/* 收起态强制展开所有分组，保证每个菜单项都露出来 */
.app-shell.collapsed .nav-group.collapsed .nav-group-items {
  grid-template-rows: 1fr;
}
.app-shell.collapsed .nav-item {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
  position: relative;
}
.app-shell.collapsed .sidebar-tip {
  justify-content: center;
}
/* 收起态悬浮显示菜单名，否则只剩一串图标认不出来 */
.app-shell.collapsed .nav-item:hover::after {
  content: attr(data-label);
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  padding: 0.32rem 0.65rem;
  border-radius: 0.5rem;
  background: rgba(17, 24, 39, 0.94);
  color: #fff;
  font-size: 0.76rem;
  font-weight: 600;
  white-space: nowrap;
  z-index: 60;
  pointer-events: none;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.22);
}

/* ---------- 主区域 ---------- */
.main-area {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 1.25rem;
  min-height: 64px;
  border-left: 0;
  border-right: 0;
  border-top: 0;
}

/* ============================================================================
   ★★★ v2.802：去掉顶栏左边那道【突兀的白色圆弧边】
   ----------------------------------------------------------------------------
   🔴 用户实测（截图圈出左上角）：「这个圆角顶到这里，看着特别别扭。」
   ★ 根因（是个"简写属性把特意去掉的边又加回来"的经典坑）：
       · 上面 .topbar 里写了 border-left/right/top: 0 —— 想只留底边；
       · 但顶栏同时带 .glass-strong，而它是
             border: 1px solid rgba(255, 255, 255, 0.8);
         ↑ 简写会把四条边【全部】设一遍 ⇒ 前面那三个 0 被覆盖
       ⇒ 顶栏四周出现一圈半透明白边。
       ⇒ 白边贴着侧栏（侧栏底色不同），在两条栏的交界处就成了一道
          白色弧线 —— 就是截图左上角那个"别扭"的东西。
   ⚠️ 教训：用 border 简写的地方，别指望用 border-xxx: 0 去掉单边；
      要么两边都用简写，要么这里显式写 border: 0 再单独给底边。
   ⚠️ 底边保留（1px 很淡的分隔），它让顶栏和内容区有明确界线，
      而且【不会】在左边缘形成弧线（左边缘那条才是问题）。
   ⚠️ 只改边框，不动玻璃效果和 sticky 行为 —— 那两样是用户要的。
   ============================================================================ */
/* ============================================================================
   ★★★ v2.810：顶栏【两端不许是圆角】（用户要求，参考 MJ）
   ----------------------------------------------------------------------------
   🔴 用户原话：「这个导航条，两头不要做成圆形的了，很难看，参考一下MJ」
   ★ 根因（我上一轮没查到底，这次用浏览器直接问出了是哪条规则）：
        design-tokens.css 里有一条【成组的圆角规则】：
            [class~="glass-strong"] { border-radius: var(--r-lg) !important; }
        它的本意是"大面统一 16px 圆角"（给卡片、弹窗用），
        但顶栏也带着 .glass-strong ⇒ 被一起赋予了 16px 圆角。
        ⚠️ 于是顶栏左端和右端各出现一个圆角 —— 就是用户看到的那两个。
        ⚠️ MJ 的顶栏是【通条的、直角】：左边贴着侧栏顶、右边贴着屏幕边。
   ★ 为什么必须带 !important：
        那条规则自带 !important，而 !important 只能被【同样是 !important】
        的声明压过（选择器更具体也没用）。
   ★ 为什么只写 border-radius: 0 而不是四条 border-*-radius: 0：
        简写在这里够用，而且更短。
        ⚠️ 反过来要小心：**别**用"给某个角单独赋值"的方式绕，
           那样另外三个角还是会圆（这个坑上一轮踩过一次）。
   ⚠️ 影响面已核实：.glass-strong 在全项目【只有顶栏在用】
        （layout.js:84 一处）。所以这条规则不会影响任何卡片或弹窗 ——
        那些用的是 .glass-effect（另一条成组规则，没动）。
   ⚠️ 也顺带说明：顶栏是 sticky 在内容区里的，它左右两端的"外观"
        由这条圆角决定；去掉圆角后顶栏就是一条干净的通栏。
   ============================================================================ */
.topbar.glass-strong {
  border: 0;
  border-bottom: 1px solid var(--mc-line, #eef0f5);
  border-radius: 0 !important;      /* ★ 直角通栏（对齐 MJ）；!important 是为了压过 design-tokens 那条 */
}
.topbar-burger {
  display: none;
  flex-shrink: 0;
  font-size: 1rem;
}
.topbar-title {
  flex: 1;
  min-width: 0;
}

/* ============================================================================
   ★★★ v2.835：顶栏三个「按任务入口」按钮（做电商 / 做视频 / 更多）
   ----------------------------------------------------------------------------
   🔴 用户原话：「这里改成MJ那样」（圈的是 MJ 顶栏那三个带下拉的按钮），
      紧接着明确：「只要三个按钮，就行，不要整个左栏菜单都改过来。」
   ★ 所以左栏菜单【一点没动】，这里只是顶栏新增的三个按任务分组的入口。

   ⚠️⚠️ 两条必须守住的规则（否则会变成"看着能用、其实坏了"）：
     ① **窄屏一定要藏起来**：这三个按钮 + 搜索框 + 积分/头像
        在 1024px 以下会把顶栏挤爆（本项目为"顶栏被挤扁"踩过坑：
        搜索框总是第一个被压没的）。
        左栏在窄屏本来就是抽屉，导航不缺 ⇒ 这里直接 display:none 最干净。
     ② **面板与按钮之间那 6px 空隙必须补上**：鼠标从按钮移向面板时
        会先经过空隙 ⇒ 触发按钮的 mouseleave ⇒ 面板刚出来就关了
        （"点了闪一下就没"就是这个问题）。用一条不可见的伪元素补住。
   ============================================================================ */
.task-tabs {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  flex: 0 1 auto;
  min-width: 0;
  flex-wrap: nowrap;
}

.task-tab { position: relative; }

.task-tab-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.4rem 0.66rem;
  border-radius: 10px;
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--mc-ink, #374151);
  white-space: nowrap;
  cursor: pointer;
  background: transparent;
  border: 1px solid transparent;
  font-family: inherit;
  transition: background 0.16s, color 0.16s, border-color 0.16s;
}
.task-tab-btn:hover,
.task-tab.open > .task-tab-btn,
.task-tab.active > .task-tab-btn {
  background: var(--mc-acc-soft, #f5f3ff);
  border-color: var(--mc-acc-line, #ddd6fe);
  color: var(--mc-acc-ink, #6d28d9);
}
.task-tab-ico { font-size: 0.95rem; line-height: 1; }
.task-tab-text { line-height: 1; }
.task-tab-caret { font-size: 0.66rem; opacity: 0.6; line-height: 1; transition: transform 0.18s; }
/* 展开时箭头翻转 —— 给一个"开了"的视觉反馈 */
.task-tab.open > .task-tab-btn .task-tab-caret { transform: rotate(180deg); }

.task-panel {
  position: absolute;
  left: 0;
  top: calc(100% + 6px);
  /* ★★★ v2.838：改成【分列】展示（用户选的"分列展示"）
     🔴 为什么必须分列：「做电商」里有 35 个模块。
        单列到底会很高（35 行 ≈ 1500px），用户要滚很久才能看到后面的；
        而这 35 个本来就有天然的三组（AI商品图 21 / AI换装试衣 13 / 电商视频 1）
        —— 分三列正好和商城页面上那三张大卡一一对应。
     ⚠️ 用 flex 而不是 CSS columns：
        columns 会把一个分组【从中间劈开】跨到下一列（子项被拆散），
        而 flex 的每一项是一个整体列，不会被劈开。
     ⚠️ min-width 改成 max-content 让面板按内容宽 —— 但要有上限，
        否则「AI商品图」那一列 21 个中文名会把面板撑到屏幕外。 */
  display: flex;
  /* ⚠️ align-items 用默认的 stretch：四列等高。
     各列高度不齐的话（MJ 那四列也不齐），底部会参差不齐、看着零散。
     ⚠️ 但【列内】内容还是各排各的 —— stretch 只影响列的盒子高度，
        不影响里面条目的位置。 */
  align-items: stretch;
  gap: 0.2rem;
  /* ★★★ v2.840：**去掉 max-height 和滚动** —— 让四列一次全展开
     ----------------------------------------------------------------------------
     🔴 用户实测（原话）：「要展开，不要折叠起来，参考MJ一模一样。」
        并给了 MJ 的截图：四列全平铺（商品拍摄 / 服饰试穿 / 营销素材 / 图片处理），
        **没有滚动条、没有被切掉**。
     ⚠️ 上一版我加了 `max-height: 62vh; overflow-y: auto` ——
        我的理由是"35 个模块太高、要滚"。但那个理由【站不住】：
          · 四列平铺之后高度由**最长的那一列**决定（21 个 ≈ 500px），
            而不是 35 个叠起来；
          · 62vh 在 900px 高的屏上只有 558px ⇒ 恰好把最后一两行切掉，
            用户看到的是"下面还有但看不到"，体验比滚动更差
            （滚动条在白色面板里几乎看不见）。
     ⇒ 现在不再设高度上限：由内容决定，屏幕放不下时【整页滚动】，
        那个是用户熟悉的滚动条，不会让人以为"坏了"。
     ⚠️ 仍然保留 max-width：四列加起来约 640px，屏幕窄的时候
        必须能自己收，否则会伸出视口右边（右边的模块点不到）。
        ⚠️ 但 max-width 也不能配 overflow-y —— 那会又变成滚动条。 */
  max-width: min(94vw, 900px);
  padding: 0.5rem;
  border-radius: 14px;
  background: var(--surface, #fff);
  border: 1px solid var(--line, #e5e7eb);
  box-shadow: 0 14px 40px rgba(15, 23, 42, 0.16);
  z-index: 60;
  /* ⚠️ 用 opacity + visibility 而不是 display:none ——
     display 不能过渡（面板会"啪"地出现），
     而且 display:none 时读屏软件读不到里面的链接。 */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.16s, transform 0.16s, visibility 0.16s;
}

/* 一列（一组模块）。⚠️ 列本身不滚动，滚的是整个面板 —— 
   分列各自滚的话鼠标要精确停在某一列上，很难用。 */
.task-col {
  flex: 0 0 auto;
  min-width: 150px;
}
.task-col + .task-col {
  border-left: 1px solid var(--line, #eef0f4);
  padding-left: 0.2rem;
  margin-left: 0.2rem;
}
.task-col-title {
  padding: 0.3rem 0.6rem 0.35rem;
  font-size: 0.7rem;
  font-weight: 800;
  color: #9ca3af;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
/* ⚠️ 补住"按钮与面板之间那 6px"的空隙 ——
   不补的话鼠标移过去会先触发 mouseleave ⇒ 面板闪一下就关。 */
.task-panel::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -8px;
  height: 8px;
}
.task-tab.open > .task-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.task-child {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.48rem 0.6rem;
  border-radius: 9px;
  color: var(--mc-ink, #374151);
  text-decoration: none;
  font-size: 0.85rem;
  white-space: nowrap;
  transition: background 0.14s, color 0.14s;
}
.task-child:hover,
.task-child.active {
  background: var(--mc-acc-soft, #f5f3ff);
  color: var(--mc-acc-ink, #6d28d9);
}
.task-child.active { font-weight: 700; }
.task-child-ico { font-size: 0.95rem; line-height: 1; width: 1.2rem; text-align: center; }
.task-child-text { line-height: 1.2; }

/* ⚠️ 窄屏藏掉（见上面注释①）—— 左栏在窄屏是抽屉，导航不缺。 */
@media (max-width: 1024px) {
  .task-tabs { display: none; }
}

/* ============================================================
   ★★★ v2.713：个人中心 / 团队中心的【皮肤主题】
   ============================================================
   🔴 用户原话：「团队中心和个人中心都美化一下，毕竟是属于会员主页，
      还是要好看一点，必要的话，设计几个个人主页的皮肤主题，可以供选择。」

   ★ 做法：先定义一套【令牌】（--mc-*），再给每个皮肤一组值。
     组件里全部用 var(--mc-xxx) —— 换皮肤只改变量，不动任何布局。
     ⚠️ 为什么不给每个皮肤写一遍完整样式：
        那是 4 份几乎相同的 CSS，改一处要改 4 遍（迟早漏一个）。
        令牌化之后，加第 5 个皮肤只要加 8 行。

   ★ 皮肤挂在 <html data-mc-skin="..."> 上（不是 body）：
     和现有的 html[data-theme="dark"] 同一层级，两个属性【正交】——
     深色模式 + 皮肤可以同时生效，不用为每个皮肤再写一套深色。

   ⚠️⚠️ 深色模式的关系（这里最容易出错）：
     皮肤定的是"色调"，深色模式定的是"明暗"。
     两者都要管颜色 ⇒ 必须让【深色的皮肤也单独一组值】，
     否则在深色下选"樱粉"会出现白底刺眼。
     ⇒ 选择器写成 html[data-theme="dark"][data-mc-skin="x"]。
     ⚠️ 默认（紫）不需要单独的 data-mc-skin 值 ——
        它就是现有配色，写 :root 即可（不加属性也是紫的）。
   ============================================================ */
:root,
html[data-mc-skin="violet"] {
  --mc-acc:        #7c3aed;
  --mc-acc-2:      #a855f7;
  --mc-acc-soft:   #f5f3ff;   /* 选中/悬停的淡底 */
  --mc-acc-line:   #ddd6fe;   /* 淡边线 */
  --mc-acc-ink:    #6d28d9;   /* 强调色上的文字（用在小字上） */
  --mc-page-1:     #faf9ff;   /* 页面渐变起点 */
  --mc-page-2:     #f5f9ff;   /* 页面渐变终点 */
  --mc-card:       #ffffff;
  --mc-card-2:     #fcfdff;   /* 次级面（工具区那类） */
  --mc-line:       #eef0f5;
  --mc-ink:        #1f2937;
  --mc-ink-2:      #6b7280;
  --mc-ink-3:      #9ca3af;
  /* ★ v2.713：阴影用的色调 —— 用 rgba 而不是 color-mix()，
     ⚠️ color-mix() 要 Chrome 111+，老浏览器会整条声明失效（阴影没了）。
        这里给个同色系的 rgba 兜底，视觉几乎一样。 */
  --mc-shadow-rgb: 124, 58, 237;
  /* ★ v2.713：带透明度的强调色变体
     ⚠️ 为什么必须有这几条：我批量替换时把 `#7c3aed59`（8 位十六进制，
        末两位是透明度）改成了 `var(--mc-acc-59)` —— 那是【非法值】，
        整条声明会失效（滑块拇指的阴影、卡片的聚焦圈都会没）。
     ⇒ 把常用透明度做成独立令牌，用法是 var(--mc-acc-XX)。 */
  --mc-acc-14: rgba(124, 58, 237, .08);
  --mc-acc-1f: rgba(124, 58, 237, .12);
  --mc-acc-22: rgba(124, 58, 237, .13);
  --mc-acc-24: rgba(124, 58, 237, .14);
  --mc-acc-26: rgba(124, 58, 237, .15);
  --mc-acc-33: rgba(124, 58, 237, .20);
  --mc-acc-59: rgba(124, 58, 237, .35);
  /* ------------------------------------------------------------
     ★★★ v2.718：皮肤要"像一整套主题"，不能只改两个颜色
     ------------------------------------------------------------
     🔴 用户原话：「皮肤很敷衍，只是改下字体颜色，背景颜色，按钮什么的
        都没变，要有个人主页的感觉呀。可以参考 QQ 邮箱的皮肤主题。」
     ★ QQ 邮箱那套主题的做法值得抄的是【覆盖面】：
       它换一次主题，导航条、卡片、按钮、标签、页面底色【全都跟着变】。
     ⇒ 所以令牌要够多。这次新增 5 条（见下），
        加上原有的 8 条，一共 13 条 —— 覆盖面才够。
     ⚠️ 其中 --mc-tab-* 是"选中的标签页"那三件套：
        QQ 邮箱的导航是【胶囊高亮】（不是下划线），
        所以标签要给形状令牌，不能只给颜色。
     ------------------------------------------------------------ */
  --mc-edge:      #e9ecf3;                    /* 卡片边框 */
  --mc-shadow:    0 1px 2px rgba(24,30,60,.04);   /* 卡片阴影（很淡，靠它出"层次"） */
  --mc-head-bg:   linear-gradient(135deg, #faf9ff 0%, #f5f9ff 100%);  /* 头部大卡底色 */
  --mc-page:      linear-gradient(180deg, #faf9ff 0%, #ffffff 320px); /* 页面底色（主题感主要靠它） */
  --mc-tab-bg:    var(--mc-acc);
  --mc-tab-ink:   #fff;
  --mc-tab-r:     999px;                      /* 胶囊圆角（QQ 邮箱那种） */

  /* ------------------------------------------------------------
     ★★★ v2.720：会员等级的视觉（用户要"尊贵的会员和普通会员区别"）
     ------------------------------------------------------------
     🔴 用户原话：「如果用户是会员，要在个人主页有所体现，尊贵的会员和
        普通会员肯定有区别，这块腾讯商业化做得很好，很会收钱。」
     ★ 用户选了「逐级变贵重」：
         基础=青 → 中级=蓝 → 高级=紫 → 神级=橙金 → 超级=红金
     ⚠️ 这【不是】定价（价格数字全部读后台），只是"等级越高看着越贵重"的
        视觉映射。等级 key 用后台已有的五个（Member::cfg()['levels']），
        不新增等级。
     ⚠️ 每档给三样东西：
         · --lv-1/--lv-2：徽章/描边的渐变色
         · --lv-ink：落在浅底上的文字色（深一点，保证可读）
         · --lv-soft：极淡底色（卡片右上角那块的底）
     ------------------------------------------------------------ */
  --lv-basic-1: #06b6d4;  --lv-basic-2: #22d3ee;  --lv-basic-ink: #0e7490;  --lv-basic-soft: #ecfeff;
  --lv-inter-1: #3b82f6;  --lv-inter-2: #60a5fa;  --lv-inter-ink: #1d4ed8;  --lv-inter-soft: #eff6ff;
  --lv-pro-1:   #7c3aed;  --lv-pro-2:   #a855f7;  --lv-pro-ink:   #6d28d9;  --lv-pro-soft:   #f5f3ff;
  --lv-divine-1:#f59e0b;  --lv-divine-2:#fbbf24;  --lv-divine-ink:#b45309;  --lv-divine-soft:#fffbeb;
  --lv-ultra-1: #e11d48;  --lv-ultra-2: #f43f5e;  --lv-ultra-ink: #be123c;  --lv-ultra-soft: #fff1f2;
}
/* 深海：蓝青 + 冷调，适合做"专业工具"的感觉 */
html[data-mc-skin="ocean"] {
  --mc-acc:        #0ea5e9;
  --mc-acc-2:      #22d3ee;
  --mc-acc-soft:   #f0f9ff;
  --mc-acc-line:   #bae6fd;
  --mc-acc-ink:    #0369a1;
  --mc-page-1:     #f5fbff;
  --mc-page-2:     #eef7ff;
  --mc-card:       #ffffff;
  --mc-card-2:     #f8fcff;
  --mc-line:       #e6f1f9;
  --mc-ink:        #0f172a;
  --mc-ink-2:      #5b6b7f;
  --mc-ink-3:      #93a3b5;
  --mc-shadow-rgb: 14, 165, 233;
  --mc-acc-14: rgba(14, 165, 233, .08);
  --mc-acc-1f: rgba(14, 165, 233, .12);
  --mc-acc-22: rgba(14, 165, 233, .13);
  --mc-acc-24: rgba(14, 165, 233, .14);
  --mc-acc-26: rgba(14, 165, 233, .15);
  --mc-acc-33: rgba(14, 165, 233, .20);
  --mc-acc-59: rgba(14, 165, 233, .35);
  --mc-edge:      #e6f1f9;
  --mc-shadow:    0 1px 2px rgba(12,74,110,.05);
  --mc-head-bg:   linear-gradient(135deg, #f5fbff 0%, #eef7ff 100%);
  --mc-page:      linear-gradient(180deg, #f5fbff 0%, #ffffff 320px);
  --mc-tab-bg:    var(--mc-acc);
  --mc-tab-ink:   #fff;
  --mc-tab-r:     999px;
}
/* 樱粉：暖粉 + 珊瑚，会员/美妆类看着更亲和 */
html[data-mc-skin="sakura"] {
  --mc-acc:        #ec4899;
  --mc-acc-2:      #fb7185;
  --mc-acc-soft:   #fff1f7;
  --mc-acc-line:   #fbcfe8;
  --mc-acc-ink:    #be185d;
  --mc-page-1:     #fff8fb;
  --mc-page-2:     #fff5f6;
  --mc-card:       #ffffff;
  --mc-card-2:     #fffafc;
  --mc-line:       #fbe9f1;
  --mc-ink:        #2b1b23;
  --mc-ink-2:      #7c5b6a;
  --mc-ink-3:      #b094a0;
  --mc-shadow-rgb: 236, 72, 153;
  --mc-acc-14: rgba(236, 72, 153, .08);
  --mc-acc-1f: rgba(236, 72, 153, .12);
  --mc-acc-22: rgba(236, 72, 153, .13);
  --mc-acc-24: rgba(236, 72, 153, .14);
  --mc-acc-26: rgba(236, 72, 153, .15);
  --mc-acc-33: rgba(236, 72, 153, .20);
  --mc-acc-59: rgba(236, 72, 153, .35);
  --mc-edge:      #fbe9f1;
  --mc-shadow:    0 1px 2px rgba(131,24,67,.05);
  --mc-head-bg:   linear-gradient(135deg, #fff8fb 0%, #fff5f6 100%);
  --mc-page:      linear-gradient(180deg, #fff8fb 0%, #ffffff 320px);
  --mc-tab-bg:    var(--mc-acc);
  --mc-tab-ink:   #fff;
  --mc-tab-r:     999px;
}
/* 墨玉：低饱和青绿 + 米白，印刷/设计工作室那种"稳"的感觉 */
html[data-mc-skin="jade"] {
  --mc-acc:        #0d9488;
  --mc-acc-2:      #14b8a6;
  --mc-acc-soft:   #f0fdfa;
  --mc-acc-line:   #99f6e4;
  --mc-acc-ink:    #0f766e;
  --mc-page-1:     #f8fdfb;
  --mc-page-2:     #f4faf8;
  --mc-card:       #ffffff;
  --mc-card-2:     #fafdfc;
  --mc-line:       #e6f2ee;
  --mc-ink:        #14211e;
  --mc-ink-2:      #5c6f6a;
  --mc-ink-3:      #93a5a0;
  --mc-shadow-rgb: 13, 148, 136;
  --mc-acc-14: rgba(13, 148, 136, .08);
  --mc-acc-1f: rgba(13, 148, 136, .12);
  --mc-acc-22: rgba(13, 148, 136, .13);
  --mc-acc-24: rgba(13, 148, 136, .14);
  --mc-acc-26: rgba(13, 148, 136, .15);
  --mc-acc-33: rgba(13, 148, 136, .20);
  --mc-acc-59: rgba(13, 148, 136, .35);
  --mc-edge:      #e6f2ee;
  --mc-shadow:    0 1px 2px rgba(19,78,74,.05);
  --mc-head-bg:   linear-gradient(135deg, #f8fdfb 0%, #f4faf8 100%);
  --mc-page:      linear-gradient(180deg, #f8fdfb 0%, #ffffff 320px);
  --mc-tab-bg:    var(--mc-acc);
  --mc-tab-ink:   #fff;
  --mc-tab-r:     999px;
}
/* ---- 深色下每个皮肤各一组（见上面为什么必须）---- */
html[data-theme="dark"][data-mc-skin="ocean"] {
  --mc-acc: #38bdf8; --mc-acc-2: #22d3ee;
  --mc-acc-soft: #0d2233; --mc-acc-line: #16425c; --mc-acc-ink: #7dd3fc;
  --mc-page-1: #0d1520; --mc-page-2: #0b131c;
  --mc-card: #141c27; --mc-card-2: #111823; --mc-line: rgba(255,255,255,.08);
  --mc-ink: #e5e7eb; --mc-ink-2: #94a3b8; --mc-ink-3: #64748b;
  --mc-edge:    rgba(255,255,255,.10);
  --mc-shadow:  0 1px 2px rgba(0,0,0,.3);
  --mc-head-bg: linear-gradient(135deg, #101b28 0%, #0d1520 100%);
  --mc-page:    #0d1520;
  --mc-tab-bg:  var(--mc-acc);
  --mc-tab-ink: #06202b;
  --mc-tab-r:   999px;
}
html[data-theme="dark"][data-mc-skin="sakura"] {
  --mc-acc: #f472b6; --mc-acc-2: #fb7185;
  --mc-acc-soft: #2b1522; --mc-acc-line: #5b2740; --mc-acc-ink: #f9a8d4;
  --mc-page-1: #1a1017; --mc-page-2: #170e14;
  --mc-card: #22151d; --mc-card-2: #1d1219; --mc-line: rgba(255,255,255,.08);
  --mc-ink: #f3e8ee; --mc-ink-2: #b7a0ab; --mc-ink-3: #8a7480;
  --mc-edge:    rgba(255,255,255,.10);
  --mc-shadow:  0 1px 2px rgba(0,0,0,.3);
  --mc-head-bg: linear-gradient(135deg, #241620 0%, #1a1017 100%);
  --mc-page:    #1a1017;
  --mc-tab-bg:  var(--mc-acc);
  --mc-tab-ink: #06202b;
  --mc-tab-r:   999px;
}
html[data-theme="dark"][data-mc-skin="jade"] {
  --mc-acc: #2dd4bf; --mc-acc-2: #5eead4;
  --mc-acc-soft: #0d2521; --mc-acc-line: #1a4b43; --mc-acc-ink: #5eead4;
  --mc-page-1: #0d1614; --mc-page-2: #0b1311;
  --mc-card: #14201d; --mc-card-2: #111b19; --mc-line: rgba(255,255,255,.08);
  --mc-ink: #e6efeb; --mc-ink-2: #9db3ad; --mc-ink-3: #6f8580;
  --mc-edge:    rgba(255,255,255,.10);
  --mc-shadow:  0 1px 2px rgba(0,0,0,.3);
  --mc-head-bg: linear-gradient(135deg, #12201d 0%, #0d1614 100%);
  --mc-page:    #0d1614;
  --mc-tab-bg:  var(--mc-acc);
  --mc-tab-ink: #06202b;
  --mc-tab-r:   999px;
}

/* ---- 皮肤选择器（个人中心头部那几个小圆点）---- */
/* ★ v2.713：统计条和皮肤点【同一行】——
   统计条吃掉剩余宽度（flex:1），皮肤点靠右不换行。
   ⚠️ 这样不额外占高度（用户刚要求过给作品让空间）。 */
.mc-stats-row {
  display: flex; align-items: center; gap: 0.5rem;
  border-top: 1px solid var(--mc-acc-14);
  padding: 0 0.75rem;
}
.mc-stats-row .mc-stats {
  flex: 1 1 auto; min-width: 0;
  border-top: 0; padding: 0.35rem 0 0.45rem;
}
.mc-skins { display: flex; align-items: center; gap: 0.3rem; flex: 0 0 auto; }
.mc-skins-t { font-size: 0.66rem; color: var(--mc-ink-3); margin-right: 0.1rem; }
.mc-skin-dot {
  width: 20px; height: 20px; border-radius: 50%; cursor: pointer;
  border: 2px solid transparent; padding: 0;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.08);
  transition: transform .15s, border-color .15s;
}
.mc-skin-dot:hover { transform: scale(1.12); }
.mc-skin-dot.on { border-color: var(--mc-acc); }
/* 每个点用自己的两个主色做渐变，一眼看出是什么皮肤 */
.mc-skin-dot[data-skin="violet"] { background: linear-gradient(135deg, #7c3aed, #a855f7); }
.mc-skin-dot[data-skin="ocean"]  { background: linear-gradient(135deg, #0ea5e9, #22d3ee); }
.mc-skin-dot[data-skin="sakura"] { background: linear-gradient(135deg, #ec4899, #fb7185); }
.mc-skin-dot[data-skin="jade"]   { background: linear-gradient(135deg, #0d9488, #14b8a6); }
/* ============================================================
   ★★★ v2.705：个人中心 / 团队中心的组件
   ------------------------------------------------------------
   🔴 用户要求：「做一个个人中心，参考这个网页的内容，样式还是用
      我们自己 CSS 样式」—— 参考图是纳米香蕉的个人页
      （顶部用户卡 + 一排统计数字 + 标签页 + 内容区）。
   ★★★ v2.713：配色全部改用上面的 --mc-* 皮肤令牌 ——
      组件里不再出现写死的紫色，这样换皮肤只改变量、不动布局。
      ⚠️ 还没换完的地方：少数几处分隔线仍是 rgba(124,58,237,.1)
         （紫色系）。它们在深海/樱粉/墨玉皮肤下会略有色差，
         但那是极淡的一条线，肉眼几乎看不出 —— 优先级低，暂留。
   ⚠️ 类名统一 mc- 前缀：
      · 不和 me.js 要的那 25 个 id 重名（重名会让它抓到错的）
      · 不和全局的 .card / .chip 之类撞（那会被别处的规则改到）
   ============================================================ */
/* ============================================================
   ★★★ v2.712：个人中心压扁（给作品展示让空间）
   ------------------------------------------------------------
   🔴 用户原话：「这个页面调整一下，为下面作品展示让出来更多的网页空间。」
      配图圈了三处重复的头 ⇒ 作品被压到很下面。
   ★ 这一版的压缩账（原来头部占了约 250px）：
        · 标题 1.35rem + 下边距        约 44px  → 直接去掉（顶栏已有"个人中心"）
        · 用户卡内边距 1rem            约 16px  → 0.6rem
        · 头像 56px                    56px    → 44px
        · 统计条 padding .6rem + 字号 1.05rem  ≈ 62px → 单行小字 ≈ 26px
        · 标签页 padding .6rem         约 40px  → 32px
        · 面板上边距 0.85rem           14px    → 6px
     ⇒ 合计省下约 120px，全部让给下面的作品网格。
   ⚠️ 统计条从"6 格大数字"改成"一行小字"是有取舍的：
      它是【概览】不是【主要操作】，用户来个人中心主要是看作品。
      数字仍然全都在（只是变小），点不进任何地方 —— 所以压小不损失功能。
   ⚠️⚠️ 实现方式：压缩值【直接写进下面各条规则里】，
      不是在文件顶部再写一遍覆盖 —— 那样会有两条同名规则，
      后定义的那条赢，改的时候极容易只改到错的那条
      （我第一次就是这么写的，产生了 7 条重复规则）。
   ============================================================ */

.mc-title { display: none; }   /* ★ v2.712：顶栏已经写了"个人中心"，不重复 */

/* ★★★ v2.718：页面主题底
   ------------------------------------------------------------
   🔴 用户原话：「要有个人主页的感觉呀。可以参考 QQ 邮箱的皮肤主题。」
   ★ QQ 邮箱的主题感【最主要是靠页面底色】——
     它不是把内容区涂色，而是整个背景有一层很淡的主题色渐变，
     内容卡片浮在上面 ⇒ 一眼就有"这是一套皮肤"的感觉。
   ⚠️ 只加很淡的一层（两三百 px 后回到白色）：
      整页浓色会让作品缩略图偏色（用户是来看图的），
      而且深色模式下会很刺眼。
   ⚠️ 用 background-attachment: fixed 之外的做法（默认 scroll）：
      fixed 在手机上性能差（滚动时反复重绘整屏背景）。 */
body[data-page="me"], body[data-page="team"] {
  background: var(--mc-page);
  background-repeat: no-repeat;
}
/* ⚠️ 深色模式也必须写一次：--mc-page 的深色值在不同皮肤里，
   而 body 的默认底是白的 ⇒ 不覆盖会在深色下露出白边。 */
html[data-theme="dark"] body[data-page="me"],
html[data-theme="dark"] body[data-page="team"] { background: var(--mc-page); }
/* ---- 用户卡 ---- */
.mc-head {
  border: 1px solid var(--mc-edge);
  border-radius: 1rem;
  /* ★★★ v2.718：底色/阴影/边框全部走皮肤令牌（原来写死紫渐变）——
     🔴 用户说「皮肤很敷衍，只是改下字体颜色，背景颜色」⇒ 就是这里：
        卡片底色本来是写死的，换皮肤它不会变。 */
  background: var(--mc-head-bg);
  box-shadow: var(--mc-shadow);
  overflow: hidden;
}
html[data-theme="dark"] .mc-head { border-color: var(--mc-edge); }
.mc-head-main {
  display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap;
  padding: 0.6rem 0.75rem 0.5rem;
}
.mc-ava {
  flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.15rem; font-weight: 800; color: #fff;
  background: linear-gradient(135deg, var(--brand-from, #9333ea), var(--brand-to, #6366f1));
  background-size: cover; background-position: center;
}
/* ★★★ v2.747：基础宽度从 220px 收到 150px。
   🔴 用户原话：「下面三块，挪到上面我画的三个红色框框的位置显示呀」
      （三个红框 = 昵称右边、积分左边那三块空白）
   ⚠️ 为什么原来放不进去：.mc-head-info 的 flex-basis 是 220px、
      还会继续伸展 ⇒ 中间那三块空白全被它吃掉，
      三个胶囊只能被 flex-wrap 挤到下一行。
   ⇒ 收到 150px（昵称/UID/简介这三行本来也用不到 220px），
      再把 flex-grow 让给后面 —— 具体宽度由下面的胶囊块自己占。
   ⚠️ 不能直接 flex:0 0 auto：那样昵称长的时候会把整行撑爆（没有收缩余地）。 */
.mc-head-info { flex: 1 1 150px; min-width: 0; }
/* ★★★ v2.718：右侧一列（积分 + 皮肤圆点）
   ⚠️ 竖排而不是并排：并排时「剩余积分 998,692」+ 4 个圆点会把这一行撑得很宽，
      窄屏直接把昵称挤掉一行。
   ⚠️ 圆点比较小（20px），给整块 min-width 防止窄屏被压成椭圆。 */
.mc-head-right {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 0.35rem; flex: 0 0 auto; min-width: 108px;
}
.mc-name-row { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.mc-name-row b { font-size: 1rem; font-weight: 800; }
.mc-badge {
  font-size: 0.66rem; font-weight: 700; padding: 0.1rem 0.45rem;
  border-radius: 999px; background: var(--mc-acc-line); color: var(--mc-acc-ink);
  white-space: nowrap;
}
.mc-badge-dim { background: #f1f5f9; color: #64748b; font-weight: 600; }
.mc-badge-dim a { color: var(--mc-acc); text-decoration: none; font-weight: 800; }
html[data-theme="dark"] .mc-badge { background: #2a2140; color: #c4b5fd; }
html[data-theme="dark"] .mc-badge-dim { background: #232a36; color: #94a3b8; }
.mc-bio {
  /* ★ v2.712：0.78rem/0.35rem → 0.74rem/0.2rem（每处省几像素，加起来可观） */
  font-size: 0.74rem; color: #6b7280; margin: 0.2rem 0 0;
  line-height: 1.5;
  /* ⚠️ 简介可能很长（用户自己填的）—— 折两行封顶，
     不截的话它会把用户卡撑得越来越高 */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.mc-sub { font-size: 0.68rem; color: #9ca3af; margin: 0.1rem 0 0; }
.mc-points { text-align: right; flex: 0 0 auto; }
.mc-points span { display: block; font-size: 0.66rem; color: #9ca3af; }
.mc-points b { display: block; font-size: 1.25rem; font-weight: 800; color: var(--mc-acc); line-height: 1.25; }
.mc-mini {
  display: inline-block; margin-top: 0.15rem;
  font-size: 0.7rem; font-weight: 700; color: var(--mc-acc); text-decoration: none;
  border: 1px solid var(--mc-acc-line); border-radius: 999px; padding: 0.08rem 0.5rem;
}
.mc-mini:hover { background: var(--mc-acc-soft); }

/* ============================================================
   ★★★ v2.720：个人主页上的【会员身份】（5 项标识，用户全选）
   ★★★ v2.722：这一整块曾被我的批量脚本误删，已按原设计补回。
        ⚠️ 教训：改 CSS 时【不要】用 起点标记 + 终点标记 这种区间替换 ——
           终点标记一旦匹配到更靠后的位置，中间的东西会被整段吃掉。
           这次终点标记 .mc-stat-err 匹配到了更后面 ⇒ 会员样式全没了。
           以后要么用 edit 工具，要么把区间收窄到能唯一匹配。
 ============================================================
   🔴 用户原话：「如果用户是会员，要在个人主页有所体现，尊贵的会员和
      普通会员肯定有区别，这块腾讯商业化做得很好，很会收钱。」
   ★ 五层递进（默认全关，只有 .mc-vip 上才生效 ⇒ 普通用户完全不受影响）：
      ① 头像描边环      ② 头像右下角 👑 等级徽章
      ③ 昵称等级色渐变字    ④ 卡片右上角斜纹丝带 + 到期倒计时
      ⑤ .mc-vip-perks 特权区块（免费额度/并发/套餐积分/有效期）
   ⚠️ 等级色靠 body 上的 data-lv 切换，JS 只写等级 key、不拼颜色。
   ⚠️ 普通用户（没有 .mc-vip）【一条都不会生效】——
      不能因为加了会员样式就让普通用户的页面变样。
   ============================================================ */
/* ① 头像描边环（按等级色） */
.mc-vip .mc-ava {
  box-shadow: 0 0 0 2px var(--mc-card), 0 0 0 4px var(--lv-1), 0 0 14px rgba(0,0,0,.12);
}
.mc-vip .mc-ava-wrap { position: relative; display: inline-block; flex: 0 0 auto; }
/* ② 头像右下角等级徽章 */
.mc-vip-badge {
  position: absolute; right: -6px; bottom: -4px;
  display: inline-flex; align-items: center; gap: 0.12rem;
  padding: 0.05rem 0.34rem;
  font-size: 0.6rem; font-weight: 800; line-height: 1.5;
  color: #fff; white-space: nowrap;
  background: linear-gradient(135deg, var(--lv-1), var(--lv-2));
  border: 1.5px solid var(--mc-card);
  border-radius: 999px;
  box-shadow: 0 1px 4px rgba(0,0,0,.18);
}
/* ③ 昵称等级色渐变字 */
.mc-vip .mc-name-row b {
  background: linear-gradient(100deg, var(--lv-1), var(--lv-2));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  font-weight: 900;
}
/* ⚠️ 深色下渐变方向反过来（深底上要更亮那头先出现） */
html[data-theme="dark"] .mc-vip .mc-name-row b {
  background: linear-gradient(100deg, var(--lv-2), var(--lv-1));
  -webkit-background-clip: text; background-clip: text;
}
/* ④ 卡片右上角斜纹丝带 */
.mc-vip .mc-head { position: relative; }
.mc-vip-ribbon {
  position: absolute; top: 0; right: 0;
  padding: 0.28rem 1.5rem 0.28rem 1.1rem;
  font-size: 0.66rem; font-weight: 800; color: #fff;
  background: linear-gradient(100deg, var(--lv-1), var(--lv-2));
  /* ⚠️ 用 clip-path 切斜角丝带，而不是旋转 45 度的方块：
     旋转方块会溢出卡片（要靠 overflow:hidden 裁，那会连别的也裁掉）。 */
  clip-path: polygon(0.55rem 0, 100% 0, 100% 100%, 0 100%);
  border-bottom-left-radius: 0.4rem;
  white-space: nowrap;
  z-index: 2;
}
/* ⑤ 特权胶囊（并发 / 免费模型 / 有效期）
   ------------------------------------------------------------
   ★★★ v2.743：从"下面一整排大格子"改成【三个小胶囊】，挪进资料那一排。
   🔴 用户原话：「下面那三个区域，分成三个小胶囊区域，放在跟个人资料同一排。」

   ⚠️ 变化点（都是用户不满的原因）：
      · 原来 grid auto-fit minmax(5.4rem,1fr) + margin-top ⇒
        它的宽度由【卡宽】决定，格子被拉得很宽很空，还白占一行高度
      · 现在是 flex 行（不伸展、按内容宽）⇒ 三个胶囊挤在一起，像"标签"
      · margin-top 去掉 —— 它在横排里，上面留白由 .mc-head-right 的 gap 管

   ⚠️ flex 的默认收缩要【关掉】：flex-shrink 默认是 1，
      窄屏时三个胶囊会被压扁（"2026-11-04"这种会挤成两行）。
      flex: 0 0 auto ⇒ 该换行就换行，不硬挤。
   ★★★ v2.747：改成 flex:1 1 auto —— 让它【吃掉中间的空档】。
      🔴 用户原话：「下面三块，挪到上面我画的三个红色框框的位置显示呀」
         （三个红框 = 昵称右边、积分左边那三块空白）
      ⚠️ 原来是 flex:0 0 auto（不伸展）⇒ 三个胶囊挤在信息块右边，
         中间留一大片空白，看着就像"没挪进去"。
      ⇒ 改成 1 1 auto：占满中间那块，胶囊用 space-evenly 均匀铺开，
         三个红框的位置就都被用上了。
   ★★★ v2.752：改成【flex-basis:100% ⇒ 自己占满一整行】——
      ⚠️⚠️ 这一版是错的，v2.757 已推翻：那一行左边只有 44px 头像，
         胶囊独占一行 ⇒ 右边 945px 全空，用户直接指着那块空白骂
         「这一块这么空干什么？」
      ★ 教训：flex-basis:100% 看起来像"让它换行"，实际是"让它占满一整行"——
        在只有小头像的行里，等于制造一大片空白。

   ★★★ v2.757：改成【挤在昵称行右侧】。
   ----------------------------------------------------------------------------
   🔴 用户原话：「这一块这么空干什么？把所有内容都挤在一行，真不知道你是怎么
      想的。图一框框里所有内容和开关，都压缩进图二这个小红框里，
      重新排版，重新写CSS。」

   ⚠️⚠️ 那个空框的成因：flex: 1 1 100% ⇒ 胶囊强制独占一整行；
      而那一行左边只有 44px 的头像 ⇒ 右边 945px 全是空的。
      ★ 不是 padding/margin 能修的，是 flex-basis 写死了。

   ★ 现在怎么排：
      · flex: 0 1 auto（不再抢整行）⇒ 有位置就待在昵称行右边
      · 位置在最右：margin-left:auto ⇒ 把昵称/徽章留在左、胶囊推到右，
        中间那段空白【被胶囊自己占掉】，不再是空的
      · flex-wrap: nowrap（行内不折）⇒ 折了又会变成"另一行"，回到老问题
      · ⚠️ 但窄屏真的放不下时整块会掉到下一行（父级 flex-wrap:wrap 管的）——
        那时它靠左，不会缩成一团。

   ⚠️ 为什么不再用 v2.752 的说法（"胶囊被摊得很开，每个隔十几厘米"）：
      那是 flex:1 1 100% + justify-content 拉伸造成的；
      现在胶囊是 auto 宽度 + gap 0.45rem ⇒ 挨在一起，不会散开。
   ============================================================================ */
.mc-vip-perks {
  display: flex; align-items: center; justify-content: flex-start;
  gap: 0.45rem; flex-wrap: nowrap;
  flex: 0 1 auto; min-width: 0;
  margin-left: auto;                   /* ★ 推到这一行最右，吃掉中间空白 */
  /* ⚠️⚠️ 必须避让右上角的会员丝带（.mc-vip-ribbon 是绝对定位，z-index:2）——
     胶囊被 margin-left:auto 推到最右，正好待在丝带下面，
     不避让的话丝带会把最后一枚胶囊盖住一半（丝带在 z-index 上层，
     而且它是绝对定位，不参与 flex 排布 ⇒ 不会自己让位）。
     ★ 丝带最小宽度约 7.5rem（"超级会员 · 还剩 28 天"），给 8.5rem 留余量。
     ⚠️ 只在【会员】时加：普通人没有丝带，加了反而白占宽度。 */
}
.mc-vip .mc-vip-perks { padding-right: 8.5rem; }
.mc-perk {
  padding: 0.18rem 0.5rem;             /* ⚠️ 比 v2.752 更扁：一行要塞下 3~4 枚 */
  background: var(--lv-soft); border: 1px solid var(--lv-1);
  border-radius: 999px;               /* ★ 全圆角 = 胶囊 */
  white-space: nowrap;                /* 胶囊里不许折行 */
  display: inline-flex; align-items: baseline; gap: 0.2rem;
  line-height: 1.4;
}
/* ⚠️ 顺序是【标签 数字】（见 me-center.js 里的说明）——
   弹性方向不用反，因为 JS 已经把 span 放前面了。
   ★ v2.757：字号各降 0.02rem —— 三枚胶囊要挤进昵称行，得再瘦一点。
      用户要的是"挤在一行"，不是为了好看而放大。 */
.mc-perk span { font-size: 0.64rem; color: var(--mc-ink-3); }
.mc-perk b { font-size: 0.76rem; font-weight: 900; color: var(--lv-ink); line-height: 1.25; }
/* 各等级把 --lv-* 映射到自己的色（JS 只写 data-lv） */
.mc-vip[data-lv="basic"]        { --lv-1: var(--lv-basic-1);   --lv-2: var(--lv-basic-2);   --lv-ink: var(--lv-basic-ink);   --lv-soft: var(--lv-basic-soft); }
.mc-vip[data-lv="intermediate"] { --lv-1: var(--lv-inter-1);   --lv-2: var(--lv-inter-2);   --lv-ink: var(--lv-inter-ink);   --lv-soft: var(--lv-inter-soft); }
.mc-vip[data-lv="pro"]          { --lv-1: var(--lv-pro-1);     --lv-2: var(--lv-pro-2);     --lv-ink: var(--lv-pro-ink);     --lv-soft: var(--lv-pro-soft); }
.mc-vip[data-lv="divine"]       { --lv-1: var(--lv-divine-1);  --lv-2: var(--lv-divine-2);  --lv-ink: var(--lv-divine-ink);  --lv-soft: var(--lv-divine-soft); }
.mc-vip[data-lv="ultimate"]     { --lv-1: var(--lv-ultra-1);   --lv-2: var(--lv-ultra-2);   --lv-ink: var(--lv-ultra-ink);   --lv-soft: var(--lv-ultra-soft); }
/* ⚠️ 兜底：后台加了新等级 key 而 CSS 没配 ⇒ 用高级会员的紫色。
   不能让它变成没有 --lv-1 的状态 —— 那会让整条 background 失效、徽章变透明。 */
.mc-vip { --lv-1: var(--lv-pro-1); --lv-2: var(--lv-pro-2); --lv-ink: var(--lv-pro-ink); --lv-soft: var(--lv-pro-soft); }

/* ---- 手机上：特权胶囊 + 积分 + 皮肤 挤一行放不下 ----
   ★ v2.743：三个胶囊是新加进那一排的，加上原有的积分块和皮肤圆点，
     手机上必定换行 ⇒ 换行后 [积分+皮肤] 那一列要【左对齐】，
     否则 align-items:flex-end 会让它在自己那行里靠右，看着像漏了一块。
   ⚠️ .mc-head-main 本来是 align-items:center，换行后两行的对齐不一致 ⇒
      手机上统一改成 stretch（每块占满自己那行）更整齐。
   ★ v2.757 修正：`.mc-vip-perks { width:100% }` 这条【删了】——
      它和桌面端新写法（挤在昵称行右侧）冲突，而且"占满一行"正是用户
      抱怨的那个空框。手机端本来就窄，胶囊跟着昵称行走，
      放不下时 .mc-head-main 的 flex-wrap 会自动把它挪到下一行。 */
@media (max-width: 860px) {
  .mc-head-main { align-items: stretch; }
  /* ⚠️ 窄屏要允许胶囊行内折行（桌面端是 nowrap）——
     否则三枚胶囊会把这一行撑爆，横着溢出被裁掉。 */
  /* ⚠️ 手机上丝带是另一行的观感（卡片更窄），避让值要小一些，
     否则 8.5rem 会把胶囊挤掉半个屏幕。 */
  .mc-vip-perks { flex-wrap: wrap; margin-left: 0; }
  .mc-vip .mc-vip-perks { padding-right: 0; }
  /* ⚠️ 昵称/徽章那一行让出宽度：窄屏上它独占一行更整齐 */
  .mc-name-row { width: 100%; }
  .mc-head-right { align-items: flex-start; }
  .mc-head-right .mc-points { text-align: left; }
  .mc-head-right .mc-skins { justify-content: flex-start; }
}

/* ---- 统计条（在用户卡【内】，卡底的第二条）----
   ★★★ v2.722：用户画红框要求「把这下面一排挪到上面我画的那个红色框里」
   ------------------------------------------------------------
   🔴 红框 = 昵称/UID 右边、积分左边那块留白。
   ⚠️ 走过的弯路（记下来免得再犯）：
      · v2.712 压成【一行小字】放卡内底部 —— 用户说太小
      · v2.718 改成卡外一排独立数字块 —— 数字大了，但卡里留一大块空白
      · v2.722（本次）挪【回卡内】，做成分隔式数据条，填满那块留白
   ★ 形态：grid auto-fit 均分整卡宽度；每格【不单独给底和边框】，
      只用淡淡的竖分隔线 —— 它现在是卡片的一部分，不该像一排小卡片
      （一排小卡片嵌在大卡里会有两层卡片的廉价感）。
   ★ 字号保持 1.15rem（和 v2.718 一样大）——
      我一度担心 10 项挤在卡内放不下，就自作主张收到 1.02rem；
      实际量了一下：卡内每格约 113px，最宽内容（公开中/263）约 32px，
      1.15rem 完全装得下 ⇒ 恢复大字号。
      ⚠️ 教训：觉得"可能放不下"时先量，别凭感觉缩。
   ⚠️ 上边一条分隔线 + 极淡主题底：把【数据区】和上面的【身份区】分开 ——
      这是无边框方案里唯一还能出层次的手段。
   ⚠️ 窄屏：auto-fit 自动折行；8 列以上在手机上会变成 5+5 两行。 */
.mc-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(4.2rem, 1fr));
  gap: 0;
  /* ★★★ v2.752：负外边距【挪到 .mc-strip 上了】（原来在这里）。
     ⚠️ 为什么必须挪：统计条现在和灵感开关并排包在 .mc-strip 里 ——
        它自己再负边距就会顶出去、压到开关上。
        整条顶到卡边的职责由 .mc-strip 统一承担。
     ⚠️ 会不会顶出卡片圆角？不会 —— .mc-head 有 overflow:hidden，
        超出圆角的部分会被裁掉（它在卡片里，不用自己管圆角）。 */
  margin: 0.5rem 0 0;
  /* ★★★ v2.747：纵向收紧 —— 用户要求「把下面更多的地方给作品展示」。
     🔴 那三块挪进头像那一排之后，这条统计条成了首屏最高的一块；
        它每格只是"数字 + 标签"，原来的 0.45/0.2rem 上下留白纯属浪费。
     ⇒ 各收一档（省下约 8px），把高度还给作品列表。
     ⚠️ 只动 padding，不动字号 —— 数字大小是用户先前明确认可过的
        （见上面那段"觉得可能放不下时先量，别凭感觉缩"）。 */
  padding: 0.28rem 0.75rem 0.1rem;
  /* ★★★ v2.752：负外边距【去掉了】。
     ⚠️ 它原来是为了让统计条顶到卡片边缘（那时它是卡里单独一条）。
        现在它和灵感开关并排包在 .mc-strip 里，再负边距就会顶出去、
        压到开关上。⇒ 由 .mc-strip 统一负责左右贴边。 */
  border-top: 1px solid rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.12);
  background: rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.02);
}
/* ★★★ v2.752：统计 + 灵感开关 并排一行（用户要求不要各占一行）
   ------------------------------------------------------------
   🔴 用户原话：「灵感开关，没必要单独占一行，作品、公开中、图片、视频这些
      数据展示也没必要单独一行，都放在会员资料那一行。」
   ★ 这两块本来就是一件事（"公开中 46 件"就是被这个开关管的），
      原来却各占一行 ⇒ 白占一行高度。
   ⚠️ 负边距挪到这里（原来是 .mc-stats 上的）：整条要顶到卡片左右边缘，
      那条上分隔线才够得到卡边，不然看着像"一根悬浮的短线"。
   ⚠️ .mc-head 有 overflow:hidden，超出圆角的部分会被裁掉，不用自己管圆角。 */
.mc-strip {
  display: flex; align-items: stretch; gap: .6rem;
  margin-left: -0.75rem; margin-right: -0.75rem;
}
.mc-strip .mc-stats { flex: 1 1 auto; min-width: 0; margin-top: 0.5rem; }
.mc-strip .mc-share { flex: 0 0 auto; margin-top: 0.5rem; }
/* ⚠️ 手机上并排塞不下（10 个数字 + 开关）⇒ 折回上下两行。
   硬塞的话 10 个数字会被压成两行，比原来更难看。 */
@media (max-width: 860px) {
  .mc-strip { flex-wrap: wrap; }
  .mc-strip .mc-stats { flex: 1 1 100%; }
  .mc-strip .mc-share { flex: 1 1 100%; }
}
/* ⚠️ v2.752：这里原来有一条 `.mc-head-break { flex-basis:100%; height:0 }` ——
   是给"逼特权胶囊换行"用的空 div 占位符准备的。
   ★ 后来改用 .mc-vip-perks 自己的 flex-basis:100% 实现（更可靠），
     那些占位 div 和这条规则就都没人用了 ⇒ 一并删掉，不留孤儿样式。 */
.mc-stat {
  padding: 0.12rem 0.3rem;
  display: flex; flex-direction: column; align-items: center; gap: 0.05rem;
  /* ⚠️ 每格【不给底和边框】—— 它在卡片里，再做小卡片会有两层卡片感 */
  background: transparent;
  border: 0;
  border-left: 1px solid rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.10);
  border-radius: 0;
  box-shadow: none;
}
/* ⚠️ 每行第一格不要左竖线（否则左边缘会顶出一条多余的线）。
   auto-fit 的列数随宽度变，没法写死 nth-child，
   所以用 first-child 保证最左永远无线，再用 10n+1 兜住【一行 10 个】的常见情形。 */
.mc-stat:first-child { border-left: 0; }
@media (min-width: 900px) {
  .mc-stat:nth-child(10n + 1) { border-left: 0; }
}
.mc-stat b { font-size: 1.15rem; font-weight: 800; color: var(--mc-ink); line-height: 1.2; }
.mc-stat span { font-size: 0.68rem; color: var(--mc-ink-3); white-space: nowrap; }
/* 互动类（被点赞/被收藏/分享/粉丝）数字给主题色 —— 和【我有多少东西】区分开 */
.mc-stat-on b { color: var(--mc-acc); }
html[data-theme="dark"] .mc-stat b { color: var(--mc-ink); }
html[data-theme="dark"] .mc-stat-on b { color: var(--mc-acc); }
html[data-theme="dark"] .mc-stats {
  border-top-color: rgba(255,255,255,.10);
  background: rgba(255,255,255,.02);
}
html[data-theme="dark"] .mc-stat { border-left-color: rgba(255,255,255,.08); }
.mc-stat-err { font-size: 0.75rem; color: var(--mc-ink-3); grid-column: 1 / -1; }

/* ============================================================
   ★★★ v2.719：灵感广场开关（个人中心主页上那一条）
   ------------------------------------------------------------
   🔴 用户要求：「灵感广场的开关 也要在个人中心加上」。
   ★ 为什么不做成一张卡：它只是一条设置，
      做成卡会白占 80px 高（用户前面刚要求过"给作品让空间"）。
   ⚠️ 用一条横条：图标 + 标题/说明 + 右侧开关。
   ⚠️ 开关本体复用全局 .switch 组件（不改它）——
      那是全站统一样式，改它会连带影响后台和其它页面。
      但它的"开启"色是写死的紫→青渐变 ⇒ 这里单独覆盖一条，
      让它跟着皮肤变（这是"整套主题"的一部分）。
   ============================================================ */
.mc-share {
  display: flex; align-items: center; gap: 0.55rem;
  /* ★ v2.747：上下留白与上间距各收一档（用户要求把高度让给作品列表） */
  margin-top: 0.4rem; padding: 0.38rem 0.7rem;
  background: var(--mc-card);
  border: 1px solid var(--mc-edge);
  border-radius: 0.7rem;
  box-shadow: var(--mc-shadow);
  /* ★★★ v2.752：它现在和统计条并排（原来各占一行）—— 
     并排时不能再无限伸展，否则会把 10 个数字挤成一团。
     ⚠️ min-width 是给"灵感广场 + 加载中… + 开关"这一行内容留的最小宽度；
        比这更窄时开关会被压变形（switch 是有固定尺寸的控件）。
     ⚠️ 手机上 .mc-strip 会折行，那时它又是整宽 —— 见上面那段 @media。 */
  min-width: 15.5rem;
}
/* ⚠️ 并排之后它不需要"上方留白"了（.mc-strip 统一给），
   但 .mc-strip .mc-share 那条已经把 margin-top 设成 0.5rem 与统计对齐。 */
.mc-share-ico { font-size: 1rem; flex: 0 0 auto; }
.mc-share-info { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.mc-share-info b { font-size: 0.82rem; font-weight: 800; color: var(--mc-ink); }
.mc-share-info small { font-size: 0.7rem; color: var(--mc-ink-3); }
/* ⚠️ 窄屏时开关的文字标签会挤 ⇒ 藏掉它，只留开关本体
   （状态靠颜色+位置就看得出，而且左边那行小字也写了状态） */
@media (max-width: 520px) {
  .mc-share .switch-label { display: none; }
}
/* ★ 让这个开关的"开启"色跟着皮肤走。
   ⚠️ 不用 !important：全局那条是 `.switch input:checked + .track`，
      这里结构相同、只是多了 .mc-share 前缀（优先级更高）⇒ 直接赢。
   ⚠️ 只覆盖【本页这个】开关，不动全站。 */
.mc-share .switch input:checked + .track {
  background: linear-gradient(135deg, var(--mc-acc), var(--mc-acc-2));
}

/* ---- 标签页 ----
   ★★★ v2.718：改成【胶囊高亮】（QQ 邮箱那种），不再是下划线。
   ------------------------------------------------------------
   🔴 用户原话：「皮肤很敷衍…… 可以参考 QQ 邮箱的皮肤主题。」
   ★ QQ 邮箱的导航是"选中的那一项整块填充成胶囊"，一眼能看出在哪一页。
     下划线在新皮肤下太细，几乎看不出主题色 —— 这也是"敷衍"的一部分。
   ⚠️ 形状（圆角）也走令牌 --mc-tab-r：
      不同主题可以给不同形状（现在是统一胶囊，以后想做方角只改令牌）。
   ⚠️ 未选中的标签给一个极淡的底，鼠标悬停才变主题色 ——
      否则一排"没底的文字"看着不像导航。 */
.mc-tabs {
  display: flex; gap: 0.3rem; flex-wrap: wrap;
  margin: 0.35rem 0 0;                    /* ★ v2.747：0.5 → 0.35（让高度给作品） */
  border-bottom: 0;                       /* 胶囊式不需要下划线 */
}
.mc-tab {
  position: relative;
  font: inherit; font-size: 0.82rem; font-weight: 700;
  color: var(--mc-ink-2); background: transparent; border: 0;
  padding: 0.4rem 0.95rem; min-height: 34px; cursor: pointer;
  border-radius: var(--mc-tab-r);
  transition: background .15s, color .15s;
}
.mc-tab:hover { color: var(--mc-acc); background: var(--mc-acc-soft); }
.mc-tab.on {
  /* ★ 选中 = 整块胶囊填主题色（最显眼的一处，也是"主题感"的关键） */
  color: var(--mc-tab-ink);
  background: var(--mc-tab-bg);
  box-shadow: 0 2px 8px rgba(var(--mc-shadow-rgb, 124, 58, 237), .28);
}
/* 签到小红点：今天没签时点一下（不给未签到的用户白点，见 me-center.js） */
.mc-dot {
  position: absolute; top: 0.5rem; right: 0.4rem;
  width: 6px; height: 6px; border-radius: 50%; background: #ef4444;
}

/* ---- 面板 + 内嵌 iframe ---- */
.mc-panes { margin-top: 0.45rem; }
.mc-pane { display: none; }
.mc-pane.on { display: block; }
.mc-frame {
  width: 100%; border: 0; display: block; background: transparent;
  /* ⚠️ 高度给一个下限，不然 iframe 默认 150px，内容会被压成一条
     （iframe 不会自动长高 —— 跨域/同域都一样，这是 HTML 的固有限制）。
     ★★ v2.712：min-height 从 620px 提到 76vh ——
        用户要"给作品展示让空间"：头压扁了，内容区就该跟着长高。
        用 vh 而不是固定 px，这样在大屏上内容区也跟着变大。 */
  min-height: 76vh; height: 78vh;
}
/* ⚠️ 内嵌页面自己会带内边距（layout.js 的 embedMode 里给了 1rem），
   这里不再重复加，否则会变成双层留白。 */

@media (max-width: 860px) {
  /* ★★★ v2.712：统计条已改成【一行小字】（flex + 自动折行），
     不再需要"手机上改 3 列"那条规则了 —— 删掉。
     ⚠️ 留着它是死规则（.mc-stats 已经不是 grid，grid-template-columns 无效），
        而且会让人以为手机上是 3 列网格。 */
  /* ⚠️ 标签页横向滚动而不是折行：折行会让内容区被推下去很多，
     而手机上用户更习惯"一排标签左右滑" */
  .mc-tabs {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none;              /* 轨道不显示，滑动照样能用 */
  }
  .mc-tabs::-webkit-scrollbar { display: none; }
  .mc-tab { flex: 0 0 auto; padding: 0.55rem 0.75rem; font-size: 0.8rem; }
  .mc-frame { height: auto; min-height: 78vh; }
}

/* ============================================================
   ★★★ v2.704：顶栏全站搜索（用户要求：搜作者 / 作品 / 模板 / 工具模块）
   ------------------------------------------------------------
   🔴 结构：.tb-search（定位容器）> input + .tb-sr（结果面板）
      ⚠️ 面板挂在容器【内部】才贴得住输入框。挂 body 上在滚动/缩放时会错位
         —— 看图弹窗那次就是这么错的（.modal-mask 的 backdrop-filter
         会造出新的包含块，position:fixed 就不按预期贴了）。
   ⚠️ 宽度用 clamp 而不是固定值：
      窄屏（<1100px）时顶栏要放下 搜索框 + 积分 + 头像 + 主题按钮，
      固定 320px 会把头像挤出去。clamp(150px, 22vw, 320px)
      在窄屏自动缩到 150px（还能输 5~6 个字），宽屏给到 320px。
   ⚠️ 手机端（<=860px）单独处理：顶栏放不下，改成"点图标展开"
      —— 见 mobile-fix.css 那一节。
   ============================================================ */
.tb-search {
  position: relative;
  flex: 0 1 clamp(150px, 22vw, 320px);
  min-width: 0;
  margin: 0 0.5rem;
}
.tb-search-input {
  width: 100%;
  height: 34px;
  padding: 0 1.9rem 0 1.9rem;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 999px;                 /* 和顶栏其它 chip 一致的胶囊形 */
  background: #f7f8fc;
  font: inherit; font-size: 0.8rem; color: inherit;
  outline: none;
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.tb-search-input:focus {
  border-color: #a78bfa; background: #fff;
  box-shadow: 0 0 0 3px rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.12);
}
/* ⚠️ type=search 在部分浏览器会带一个原生小叉 —— 我们自己有一个，
   两个并排会看起来像坏了 ⇒ 藏掉原生的。 */
.tb-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.tb-search-ico {
  position: absolute; left: 0.65rem; top: 50%; transform: translateY(-50%);
  font-size: 0.78rem; color: #9ca3af; pointer-events: none;
}
.tb-search-clear {
  position: absolute; right: 0.45rem; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; border: 0; border-radius: 50%;
  background: #e5e7eb; color: #4b5563; cursor: pointer;
  font-size: 0.7rem; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.tb-search-clear:hover { background: #d1d5db; }

/* ---- 结果面板 ---- */
.tb-sr {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px);
  z-index: 60;
  max-height: min(66vh, 460px);
  overflow-y: auto;
  background: #fff; border: 1px solid var(--border, #e5e7eb);
  border-radius: 12px;
  box-shadow: 0 12px 34px rgba(24,30,60,.14);
  padding: 0.3rem;
}
html[data-theme="dark"] .tb-sr { background: #1b2029; border-color: rgba(255,255,255,.12); }
.tb-sr-grp {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.4rem 0.5rem 0.2rem;
  font-size: 0.7rem; font-weight: 800; color: #6b7280;
}
.tb-sr-grp i { font-style: normal; font-size: 0.66rem; color: #9ca3af; font-weight: 600; }
.tb-sr-it {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.42rem 0.5rem; border-radius: 8px;
  text-decoration: none; color: inherit; min-width: 0;
}
.tb-sr-it:hover, .tb-sr-it.on { background: var(--mc-acc-soft); }
html[data-theme="dark"] .tb-sr-it:hover, html[data-theme="dark"] .tb-sr-it.on { background: #232a3b; }
.tb-sr-ico {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.85rem; background: #f3f4f6;
}
html[data-theme="dark"] .tb-sr-ico { background: #252b36; }
.tb-sr-img {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 7px;
  object-fit: cover; background: #f3f4f6; display: block;
}
.tb-sr-ava { border-radius: 50%; }     /* 头像用圆 */
.tb-sr-bd { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.05rem; }
.tb-sr-bd b {
  font-size: 0.79rem; font-weight: 700; color: #1f2937;
  /* ⚠️ 单行省略 —— 提示词可能很长，不截会把面板撑成一大片 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
html[data-theme="dark"] .tb-sr-bd b { color: #e5e7eb; }
.tb-sr-bd small {
  font-size: 0.68rem; color: #9ca3af;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tb-sr-none { padding: 1rem 0.6rem; text-align: center; font-size: 0.78rem; color: #9ca3af; line-height: 1.8; }
.topbar-title h1 {
  font-size: 1.05rem;
  font-weight: 800;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topbar-title p {
  font-size: 0.75rem;
  color: #6b7280;
  margin: 0.1rem 0 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.topbar-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

.page-content {
  flex: 1;
  min-width: 0;
}

/* ---------- 移动端抽屉 ---------- */
.sidebar-backdrop {
  position: fixed;
  inset: 0;
  z-index: 44;
  background: rgba(17, 24, 39, 0.45);
  backdrop-filter: blur(2px);
  animation: fadeIn 0.2s ease;
}

@media (max-width: 1024px) {
  #sidebar-root {
    position: fixed;
    left: 0;
    top: 0;
    transform: translateX(-100%);
    transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
    box-shadow: 8px 0 32px rgba(0, 0, 0, 0.18);
  }
  .app-shell.sidebar-open #sidebar-root {
    transform: translateX(0);
  }
  .app-shell.collapsed #sidebar-root {
    width: 196px;
  }
  /* 移动端抽屉里不做图标模式，恢复完整文字与分组标题 */
  .app-shell.collapsed .brand-text,
  .app-shell.collapsed .nav-text,
  .app-shell.collapsed .nav-arrow,
  .app-shell.collapsed .nav-badge,
  .app-shell.collapsed .sidebar-tip .nav-text {
    display: block;
  }
  .app-shell.collapsed .nav-badge {
    display: inline-block;
  }
  .app-shell.collapsed .sidebar-collapse {
    display: block;
  }
  .app-shell.collapsed .nav-group-title {
    display: flex;
  }
  .app-shell.collapsed .nav-group + .nav-group {
    margin-top: 0.35rem;
    padding-top: 0;
    border-top: none;
  }
  .app-shell.collapsed .sidebar-brand {
    flex-direction: row;
    gap: 0.55rem;
    padding: 0.95rem 0.9rem;
  }
  .app-shell.collapsed .nav-item,
  .app-shell.collapsed .nav-group-title,
  .app-shell.collapsed .sidebar-tip {
    justify-content: flex-start;
  }
  .app-shell.collapsed .nav-item {
    padding-left: 0.7rem;
    padding-right: 0.7rem;
  }
  .app-shell.collapsed .nav-item:hover::after {
    display: none;
  }
  .topbar-burger {
    display: inline-flex;
  }
  .topbar-title p {
    display: none;
  }
}

@media (max-width: 640px) {
  .topbar {
    padding: 0.55rem 0.8rem;
    gap: 0.5rem;
  }
  .topbar-title h1 {
    font-size: 0.95rem;
  }
  .topbar-actions .chip {
    display: none;
  }
  .result-stage { min-height: 280px; }
  .result-stage img { max-height: 46vh; }
  .tool-tab { padding: 0.6rem 0.85rem; font-size: 0.82rem; }
}


/* ===========================================================
   管理后台专用样式
   =========================================================== */
.admin-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.1rem;
}
.admin-section-head h2 {
  font-size: 1.3rem;
  font-weight: 800;
  margin: 0;
}
.admin-section-head p {
  font-size: 0.8rem;
  color: #6b7280;
  margin: 0.2rem 0 0;
}

/* 统计卡 */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 0.85rem;
}
.stat-card {
  border-radius: 1rem;
  padding: 1rem 1.1rem;
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 6px 20px rgba(31, 38, 135, 0.05);
}
.stat-card .stat-icon { font-size: 1.1rem; }
.stat-value {
  font-size: 1.55rem;
  font-weight: 800;
  line-height: 1.2;
  margin-top: 0.25rem;
}
.stat-value small { font-size: 0.75rem; font-weight: 600; color: #9ca3af; }
.stat-label { font-size: 0.74rem; color: #6b7280; font-weight: 600; margin-top: 0.1rem; }

/* 面板 */
.panel {
  border-radius: 1rem;
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 6px 20px rgba(31, 38, 135, 0.05);
  overflow: hidden;
}
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--mc-line);
  flex-wrap: wrap;
}
.panel-head h3 { font-size: 0.95rem; font-weight: 800; margin: 0; }
.panel-body { padding: 1.1rem; }
.panel-body.tight { padding: 0; }

/* 表格 */
.table-wrap { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 0.84rem; }
.data-table th {
  text-align: left;
  padding: 0.65rem 0.8rem;
  color: #6b7280;
  font-weight: 700;
  font-size: 0.73rem;
  white-space: nowrap;
  background: #fafbfe;
  border-bottom: 1px solid var(--line);
}
.data-table td {
  padding: 0.6rem 0.8rem;
  border-bottom: 1px solid #f2f3f8;
  vertical-align: middle;
}
.data-table tbody tr:hover td { background: rgba(147, 51, 234, 0.035); }
.data-table .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.76rem; color: #6b7280; }
.data-table .ellipsis {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.data-table .num { font-variant-numeric: tabular-nums; font-weight: 700; }
.text-up { color: #059669; }
.text-down { color: #dc2626; }

/* 徽标 */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.14rem 0.5rem;
  border-radius: 999px;
  font-size: 0.69rem;
  font-weight: 700;
  white-space: nowrap;
}
.badge-green { background: #dcfce7; color: #166534; }
.badge-red { background: #fee2e2; color: #991b1b; }
.badge-amber { background: #fef3c7; color: #92400e; }
.badge-blue { background: #dbeafe; color: #1e40af; }
.badge-gray { background: #f3f4f6; color: #4b5563; }
.badge-purple { background: #f3e8ff; color: #6b21a8; }
.badge-cyan { background: #cffafe; color: #155e75; }

/* 表单行 */
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 0.9rem; }
.form-grid .full { grid-column: 1 / -1; }
.form-row-note { font-size: 0.72rem; color: #9ca3af; margin: 0.3rem 0 0; line-height: 1.5; }

/* 开关 */
.switch { display: inline-flex; align-items: center; gap: 0.5rem; cursor: pointer; user-select: none; }
.switch input { display: none; }
.switch .track {
  width: 40px; height: 22px; border-radius: 999px; background: #d1d5db;
  position: relative; transition: background 0.2s; flex-shrink: 0;
}
.switch .track::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px;
  border-radius: 50%; background: #fff; transition: transform 0.2s;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.switch input:checked + .track { background: linear-gradient(135deg, #9333ea, #06b6d4); }
.switch input:checked + .track::after { transform: translateX(18px); }
.switch .switch-label { font-size: 0.82rem; font-weight: 600; color: #374151; }

/* 工具条 */
.toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.toolbar .field { width: auto; min-width: 130px; padding: 0.5rem 0.75rem; font-size: 0.82rem; }
.toolbar select.field { min-width: 120px; }

/* 供应商卡片 */
.provider-card {
  border-radius: 1rem;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.85);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  transition: all 0.25s;
}
.provider-card:hover { border-color: #c084fc; box-shadow: 0 8px 24px rgba(147, 51, 234, 0.1); }
.provider-card.is-default { border-color: #9333ea; box-shadow: 0 0 0 3px rgba(147, 51, 234, 0.1); }
.provider-card h4 { font-size: 0.92rem; font-weight: 800; margin: 0; display: flex; align-items: center; gap: 0.4rem; }
.provider-card .kv { font-size: 0.74rem; color: #6b7280; display: flex; gap: 0.4rem; }
.provider-card .kv b { color: #374151; font-weight: 600; }
.provider-card .provider-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: auto; padding-top: 0.3rem; }

/* 详情抽屉 */
.drawer-mask {
  position: fixed; inset: 0; z-index: 85; background: rgba(17, 24, 39, 0.5);
  backdrop-filter: blur(3px); animation: fadeIn 0.2s ease;
}
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 86;
  width: min(720px, 96vw); background: #fff; box-shadow: -12px 0 40px rgba(0, 0, 0, 0.2);
  display: flex; flex-direction: column; animation: drawerIn 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes drawerIn { from { transform: translateX(40px); opacity: 0; } }
.drawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  padding: 1rem 1.2rem; border-bottom: 1px solid var(--line);
}
.drawer-body { flex: 1; overflow-y: auto; padding: 1.2rem; }

/* 分页（后台复用） */
.admin-pager { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.8rem 1.1rem; flex-wrap: wrap; }
.admin-pager .info { font-size: 0.78rem; color: #6b7280; }

/* 空状态 */
.empty-state { padding: 2.5rem 1rem; text-align: center; color: #9ca3af; font-size: 0.85rem; }

@media (max-width: 640px) {
  .stat-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
  .stat-value { font-size: 1.25rem; }
  .data-table .ellipsis { max-width: 140px; }
}

/* ===========================================================
   生图表单：新增控件的样式
   （常用尺寸、风格预设、AI 优化按钮、高级参数折叠区）
   =========================================================== */

/* ---------- 标签行里的小按钮 ---------- */
.btn-opt {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-left: 0.4rem;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  border: 1px solid rgba(147, 51, 234, 0.35);
  background: rgba(147, 51, 234, 0.08);
  color: var(--mc-acc);
  font-size: 0.72rem;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
  /* ★ 不换行 + 不压缩
     ------------------------------------------------------------
     ⚠️ 按钮文字里有空格（「✨ AI 优化」「📝 生成歌词」），
        inline-flex 默认允许在空格处断行 —— 手机上宽度一紧就变成
        「AI 优」/「化」、「生成歌」/「词」两行，很难看。
     ⚠️ flex: 0 0 auto 是第二道保险：它让按钮在 flex 行里
        不被压缩（压缩正是触发出换行的原因），宁可让父容器横向滚动。
     ⚠️ 只在 .btn-opt 上加，不动父容器的布局 —— 改父容器会连带
        影响图片页 / 视频页等所有用同一套 .pb-tools 的地方。 */
  white-space: nowrap;
  flex: 0 0 auto;
}
.btn-opt:hover { background: rgba(147, 51, 234, 0.16); border-color: rgba(147, 51, 234, 0.6); }
.btn-opt:disabled { opacity: 0.55; cursor: not-allowed; }

/* ---------- 常用尺寸（比普通 chip 多一点信息） ---------- */
.size-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.42rem 0.8rem;
  border-radius: 0.7rem;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.8);
  color: var(--ink-soft);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
}
.size-chip small { font-size: 0.68rem; opacity: 0.65; font-weight: 500; }
.size-chip:hover { border-color: #c084fc; color: var(--ink); }
.size-chip.active {
  color: #fff;
  border-color: transparent;
  background: linear-gradient(135deg, var(--brand-from), var(--brand-to));
}
.size-chip.active small { opacity: 0.85; }

/* ---------- 风格预设 ---------- */
.style-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.38rem 0.75rem;
  border-radius: 999px;
  border: 1px dashed rgba(147, 51, 234, 0.35);
  background: rgba(255, 255, 255, 0.7);
  color: var(--ink-soft);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}
.style-chip:hover { border-color: #c084fc; color: var(--ink); }
.style-chip.active {
  border-style: solid;
  border-color: transparent;
  color: #fff;
  background: linear-gradient(135deg, var(--brand-from), var(--brand-to));
}

/* ---------- 高级参数折叠区 ---------- */
.adv-box {
  border: 1px solid var(--line);
  border-radius: 0.9rem;
  background: rgba(255, 255, 255, 0.55);
  overflow: hidden;
}
.adv-box > summary {
  padding: 0.7rem 1rem;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--ink-soft);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.adv-box > summary::-webkit-details-marker { display: none; }
.adv-box > summary::after { content: ' ▾'; opacity: 0.5; }
.adv-box[open] > summary::after { content: ' ▴'; }
.adv-box > summary:hover { color: var(--ink); }
.adv-body {
  padding: 0 1rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  border-top: 1px solid var(--line);
  padding-top: 0.9rem;
}
.field-note {
  font-size: 0.72rem;
  color: #9ca3af;
  margin-top: 0.35rem;
  line-height: 1.6;
}
/* ===========================================================
   资产库 / 灵感广场：卡片上的小标签
   （public/assets.js、public/inspiration.js 使用）
   =========================================================== */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.14rem 0.5rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.6;
  white-space: nowrap;
  backdrop-filter: blur(4px);
}
.tag.g { color: #047857; background: rgba(16, 185, 129, 0.16); border: 1px solid rgba(16, 185, 129, 0.3); }
.tag.y { color: #92400e; background: rgba(245, 158, 11, 0.16); border: 1px solid rgba(245, 158, 11, 0.32); }
.tag.r { color: #b91c1c; background: rgba(239, 68, 68, 0.14); border: 1px solid rgba(239, 68, 68, 0.3); }
.tag.b { color: #1d4ed8; background: rgba(59, 130, 246, 0.14); border: 1px solid rgba(59, 130, 246, 0.3); }
.tag.gray { color: #4b5563; background: rgba(107, 114, 128, 0.14); border: 1px solid rgba(107, 114, 128, 0.26); }
/* ===========================================================
   桌面端整屏布局：顶部导航固定，只有内容区滚动
   -----------------------------------------------------------
   原来的问题：.topbar 用了 position: sticky，但它的父元素
   #topbar-root 高度就等于它自身，sticky 没有可粘的区间，
   所以页面一滚，导航栏就跟着走掉了。
   改成：整屏高度固定，让 .page-content 自己滚动。
   =========================================================== */
@media (min-width: 1024px) {
  html, body { height: 100%; }
  .app-shell {
    height: 100vh;
    min-height: 0;
    overflow: hidden;
    align-items: stretch;
  }
  #sidebar-root { height: 100vh; }
  .main-area { height: 100vh; min-height: 0; overflow: hidden; }
  .page-content {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;   /* 滚到底不要带动整页 */
  }
  /* 顶栏不再需要 sticky —— 它所在的 .main-area 本来就不滚动 */
  .topbar { position: relative; top: auto; }
}

/* ===========================================================
   生图页：左侧表单收窄，右侧结果区铺满剩余空间
   =========================================================== */
@media (min-width: 1024px) {
  .tool-panel.grid {
    /* 覆盖 Tailwind 的 lg:grid-cols-2 */
    grid-template-columns: minmax(320px, 400px) minmax(0, 1fr) !important;
    align-items: stretch;
  }
  .tool-panel > div:last-child { display: flex; flex-direction: column; }
  .result-stage {
    flex: 1 1 auto;
    min-height: 460px;
  }
}
/* 结果图可以更大：铺满结果区 */
.result-stage img { max-height: 72vh; }
/* ===========================================================
   生图页：作图区铺满整个内容区高度
   -----------------------------------------------------------
   目标：进来就是一整屏的作图界面，不用先滚动才能看到结果区。
   做法：让作图卡片至少占满「一屏减去顶栏与首屏文案」的高度，
         卡片内部纵向撑开，左栏表单自己滚动，右栏结果区吃掉剩余空间。
         卡片下方的「最近作品」等区块保持整页滚动，不受影响。
   =========================================================== */
@media (min-width: 1024px) {
  /* 首屏文案压缩一些，把高度让给作图区 */
  body[data-page="image"] main > section:first-child {
    padding-top: 0.5rem;
    padding-bottom: 0.75rem;
  }
  body[data-page="image"] main > section:first-child h1 { margin-bottom: 0.5rem; }
  body[data-page="image"] main > section:first-child p { font-size: 0.95rem; }

  /* 作图卡片：至少一屏高，内部纵向撑开 */
  body[data-page="image"] .tool-card {
    min-height: calc(100vh - 210px);
    display: flex;
    flex-direction: column;
  }

  /* 当前显示的那个面板撑满卡片剩余高度 */
  body[data-page="image"] .tool-card > .tool-panel:not(.hidden) {
    flex: 1 1 auto;
    min-height: 0;
  }

  /* 左栏：内容多时自己滚动，不把卡片撑高 */
  body[data-page="image"] .tool-panel > div:first-child {
    min-height: 0;
    overflow-y: auto;
    padding-right: 0.4rem;
  }

  /* 右栏结果区：吃掉全部剩余高度 */
  body[data-page="image"] .tool-panel > div:last-child {
    min-height: 0;
  }
  body[data-page="image"] .result-stage {
    min-height: 320px;
    height: 100%;
  }
  body[data-page="image"] .result-stage img { max-height: 100%; }
}

/* 个人中心：卡片纵向排列（替代原来的内联 display:flex） */
.me-stack {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
/* ===========================================================
   视频 / 音乐页
   =========================================================== */

/* 音乐播放时的跳动波形装饰 */
.music-wave {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  height: 42px;
}
.music-wave span {
  display: block;
  width: 4px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--brand-from), var(--brand-to));
  animation: waveJump 1.1s ease-in-out infinite;
}
@keyframes waveJump {
  0%, 100% { height: 8px; opacity: .55; }
  50%      { height: 38px; opacity: 1; }
}

/* 视频 / 音乐 / 配音页的结果区：撑满可用高度
   ★ v2.754：配音页改成工作台布局后并入这两条（它和视频/音乐结构完全一样）。 */
@media (min-width: 1024px) {
  body[data-page="video"] .result-stage,
  body[data-page="voice"] .result-stage,
  body[data-page="music"] .result-stage {
    flex: 1 1 auto;
    min-height: 420px;
  }
  body[data-page="music"] .result-stage,
  body[data-page="voice"] .result-stage { align-items: center; }
}

/* 提示条：演示模式等 */
.msg.warn {
  background: #fffbeb;
  border: 1px solid #fcd34d;
  color: #92400e;
  border-radius: 0.9rem;
  padding: 0.75rem 1rem;
  font-size: 0.82rem;
  line-height: 1.7;
}
/* 视频 / 音乐 / 配音页：作图区同样铺满一屏
   ★ v2.754：配音页并入（这三页没有首屏文案，所以少减一些）。
   ⚠️ 这一条是"工作台页"的标志 —— dod-probe 靠 style.css 里有没有
      body[data-page="xxx"] 来判断某页是否被布局覆盖，
      所以新增工作台页时【必须】在这里补一条，否则那一页不会被覆盖到。 */
@media (min-width: 1024px) {
  body[data-page="video"] .tool-card,
  body[data-page="voice"] .tool-card,
  body[data-page="music"] .tool-card {
    min-height: calc(100vh - 130px);
    display: flex;
    flex-direction: column;
  }
  body[data-page="video"] .tool-card > .tool-panel,
  body[data-page="voice"] .tool-card > .tool-panel,
  body[data-page="music"] .tool-card > .tool-panel {
    flex: 1 1 auto;
    min-height: 0;
  }
  body[data-page="video"] .tool-panel > div:first-child,
  body[data-page="voice"] .tool-panel > div:first-child,
  body[data-page="music"] .tool-panel > div:first-child {
    min-height: 0;
    overflow-y: auto;
    padding-right: 0.4rem;
  }
}
/* ===========================================================
   生图工作区
   -----------------------------------------------------------
   布局：左「设置区」+ 右「结果区」，整体铺满 1600px。
   设置区内部自己滚动，底部「数量 / 积分 / 生成」固定不动。
   =========================================================== */

/* 工作区整体宽度：1600px（比默认的 max-w-7xl=1280px 宽不少） */
body[data-page="image"] .page-content > main { max-width: 1600px !important; }
/* ★ v2.793：配音页的宽度【不在这里写】——
   它并进了下面那条「视频/音乐工作区：铺满布局」的名单里
   （那里同时管 height:100% / flex 列 / 底部固定，是一整套）。
   ⚠️ 我第一版在这里单独写了一条 voice 的 max-width，
      结果同一个选择器出现两条规则 —— 本项目为"同名规则静默覆盖"踩过坑，
      所以合并到一处，不留第二份。 */

/* -----------------------------------------------------------
   我的作品 / 灵感广场 / 充值中心 / 个人资料：铺满右侧内容区
   -----------------------------------------------------------
   ⚠️ 这四个页面的 <main> 带 Tailwind 的 max-w-7xl（1280px）
      或 max-w-5xl（1024px）+ mx-auto —— 等于「定宽居中」，
      右侧会空出一大片，和左边的菜单形成很明显的断层。

   这里沿用上面 body[data-page="image"] 的写法覆盖掉。
   ⚠️ 用 max-width:none 而不是某个更大的固定值：
      这几个页面是列表 / 表单，本来就该跟着容器自适应，
      再定一个 1600px 只是把断层往后挪一点而已。
   ⚠️ mx-auto（margin auto）在块级满宽元素上没有视觉效果，
      所以不用去动它。
   ----------------------------------------------------------- */
body[data-page="assets"] .page-content > main,
body[data-page="inspiration"] .page-content > main,
body[data-page="recharge"] .page-content > main,
body[data-page="me"] .page-content > main {
  max-width: none !important;
}

/* ==============================================================
   ★ v2.515：管理后台的内容区【铺满右侧】（用户要求）
   --------------------------------------------------------------
   用户原话：「后台所有的内容区，铺满右侧」——
   截图里用户管理页右侧空出约 320px（1920 屏上表格只占中间 1400px）。

   ⚠️ 限宽来自【两处】，必须两处都压：
     · admin.html 第 44 行：#admin-root 带 Tailwind 的 max-w-[1400px] mx-auto
       （CDN 在 <head> 里是 async 加载 ⇒ 样式注入时机不定，
         但它不是 !important，所以下面带 !important 的一条稳定胜过它）
     · style.css 里按 data-page 给的 1600px 上限
       （后台的 body 只有 data-menu="admin"、没有 data-page ⇒ 这条本来
         也不该命中；但选择器下成 main#admin-root 后，就算将来给后台
         加了 data-page，也照样压得住）

   ⚠️ 为什么用 `main#admin-root` 而不是 `body[data-page="admin"]`：
     · 先把权重算清楚（别凭感觉）：main#admin-root = 1 id + 1 元素 = (0,1,0,1)；
       body[data-page="admin"] .page-content > main = 1 属性 + 1 类 + 1 元素
       = (0,1,1,1)。★ 后者其实【更高】—— 所以这里不能靠权重赢。
     · 实际靠两件事：① 带 !important 胜过一切非 important 规则
       （Tailwind 的 max-w-[1400px] mx-auto 都不是 important）；
       ② 写在文件更后面。这样无论 data-page 是什么、Tailwind 何时注入，
       结果都一致 ✓
     · 选 main#admin-root 而不是 body[data-page="admin"]，还有一个原因：
       后台的 body 是 data-menu="admin"、【没有】data-page，
       用 data-page 选择器只会是一条永远不命中的死规则。

   ⚠️ 同时把 mx-auto 的左右 margin 归零：满宽元素不需要居中，
      留着 auto 在某些 flex 场景下会表现成"两边各留一点"，反而没铺满。
   ⚠️ 只作用于 #admin-root 这一个元素（后台所有子页面共用它）——
      前台的 .page-content > main 一律不受影响。
   ============================================================== */
main#admin-root {
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* 面板改成两栏：设置区固定宽度，结果区吃掉剩余空间 */
@media (min-width: 1024px) {
  .tool-panel {
    display: grid;
    grid-template-columns: minmax(360px, 460px) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: stretch;
    min-height: 0;
  }
}

/* ============================================================================
   ★★★ v2.793：配音页（voice）改成【左宽右窄】—— 对齐 MJ 那页
   ----------------------------------------------------------------------------
   🔴 用户原话（附图对比）：「MJ的配音页面控制面板这么宽，我们的这么一点点，
      我说了要一模一样呀。」
   ★ 根因：上面那条【通用】规则把左栏卡在 max 460px、右栏 1fr 吃掉剩余
      ⇒ 在 1900px 宽的屏幕上，控制面板只占 ~460px（约 1/4），
        右边空出一大片 —— 用户看到的就是"这么一点点"。
   ★ MJ 的实际比例：控制面板占【大部分宽度】（约 3/4），右栏是窄的一条
     （任务信息 / 生成记录）。
   ★ 所以配音页单独覆盖成：左 1fr（吃掉剩余）+ 右固定窄栏。
   ⚠️ 为什么给右栏 max 340px 而不是写死：卡片里是「任务信息」文字，
      太窄会频繁折行；340 够放两行中文，又不至于抢走控制面板的宽度。
   ⚠️ 【只覆盖 voice 这一页】—— 其它专区（图创/视频/音乐/电商/广告）
      的左右比例是用户按各自参考站定过的，不能连带改掉。
   ⚠️ 用 minmax(0, 1fr) 而不是 1fr：不加 minmax(0,…) 时，
      栅格子项的最小内容宽度会把列撑破（长英文/长 URL 尤其明显）。 */
@media (min-width: 1024px) {
  body[data-page="voice"] .tool-panel {
    grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  }
}

/* ---------- 设置区：中间滚动 + 底部固定 ---------- */
.studio-side {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}
.studio-side-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-right: 0.5rem;
  /* 滚动到底部时留一点余量，避免最后一项贴着固定栏 */
  padding-bottom: 0.5rem;
}
.studio-side-foot {
  flex: none;
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.55);
}
.foot-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.8rem;
}
.foot-cost {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.3;
}
.foot-cost-label { font-size: 0.72rem; color: #9ca3af; }


/* ============================================================================
   ★★★ v2.758：公开个人主页（/u/{用户名}）
   ----------------------------------------------------------------------------
   🔴 用户原话：「整站只要出现用户名的地方，点击用户名。可以访问该用户的个人主页。」
   ⚠️ 全部用 .pf- 前缀，避免和现有类冲突（个人中心用的是 .mc-）。
   ⚠️ 颜色一律走皮肤令牌：换皮肤时这块要跟着变，
      而且 me-center-probe 会抓"组件里写死的主题色"。
   ============================================================================ */
.pf-head {
  border: 1px solid var(--mc-edge);
  border-radius: 1rem;
  background: var(--mc-head-bg);
  box-shadow: var(--mc-shadow);
  overflow: hidden;
  margin-bottom: 1rem;
}
.pf-head-main {
  display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap;
  padding: 0.85rem 1rem 0.7rem;
}
.pf-ava {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.35rem; font-weight: 800; color: #fff;
  background: linear-gradient(135deg, var(--brand-from, #9333ea), var(--brand-to, #6366f1));
  background-size: cover; background-position: center;
}
.pf-info { flex: 1 1 200px; min-width: 0; }
.pf-name-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pf-name-row b { font-size: 1.1rem; font-weight: 800; }
.pf-badge {
  font-size: 0.66rem; font-weight: 700; padding: 0.1rem 0.45rem;
  border-radius: 999px; background: var(--mc-acc-line); color: var(--mc-acc-ink);
  white-space: nowrap;
}
.pf-bio {
  font-size: 0.76rem; color: #6b7280; margin: 0.25rem 0 0; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
html[data-theme="dark"] .pf-bio { color: #9ca3af; }
.pf-me { flex: 0 0 auto; }
/* 统计：一排分隔式（和用户卡同一个观感） */
.pf-stats {
  display: flex; align-items: stretch;
  border-top: 1px solid var(--mc-edge);
}
.pf-stat {
  flex: 1 1 0; min-width: 0; text-align: center; padding: 0.55rem 0.3rem;
}
.pf-stat + .pf-stat { border-left: 1px solid var(--mc-edge); }
.pf-stat b { display: block; font-size: 1.15rem; font-weight: 800; color: var(--mc-acc); line-height: 1.3; }
.pf-stat span { display: block; font-size: 0.68rem; color: #9ca3af; margin-top: 0.1rem; }

/* 用户名链接（★ 全站的"点名字进主页"都用这个类） */
.pf-ulink { color: inherit; text-decoration: none; }
.pf-ulink:hover { color: var(--mc-acc); text-decoration: underline; }

/* 空 / 出错状态 */
.pf-empty {
  text-align: center; padding: 2.2rem 1rem;
  border: 1px dashed var(--mc-edge); border-radius: 1rem;
  color: #6b7280; font-size: 0.82rem;
}
.pf-empty-ico { font-size: 2.2rem; margin-bottom: 0.4rem; }
.pf-empty b { display: block; font-size: 0.95rem; color: #374151; margin-bottom: 0.3rem; }
html[data-theme="dark"] .pf-empty b { color: #e5e7eb; }
.pf-empty p { margin: 0.15rem 0 0; }
.pf-empty code {
  background: var(--mc-acc-soft, #ede9fe); color: var(--mc-acc-ink, #5b21b6);
  padding: 0.05rem 0.35rem; border-radius: 0.3rem; font-size: 0.78rem;
}

/* ============================================================================
   AI 配音 · 音色选择卡
   ----------------------------------------------------------------------------
   ★★★ v2.754：从 voice.html 的内联 style 搬到这里。
   ⚠️ 为什么必须搬：v2.754 把配音页改成工作台布局时整文件重写了，
      原来写在页面内联 style 里的这两条就丢了 —— 音色按钮会变成
      【没有样式的裸按钮】（一排灰底方块），看着像页面坏了。
      搬进 style.css 之后不会再因为重写页面而丢。

   ⚠️ 选中态：边框加粗 + 底色 + 右上角勾，三个标记一起上。
      依据是用户在这个项目上提过两次「选中看不出来」
      （电商专区的小按钮，v2.721 / v2.750 各修过一次）。
   ============================================================================ */
/* ============================================================================
   ★★★ v2.791：文生音效页新增控件（对齐 MJ 那页）
   ----------------------------------------------------------------------------
   下面是「快速插入词 / 常用模板 / 输出参数 / 声音微调」四组样式。
   ⚠️ 类名加之前全部查过 CSS，确认原先【都不存在】——
      这个项目被"同名选择器静默覆盖"坑过多次（见 .mc-title 那次：
      生图模型卡用了 .mc-title，而会员中心有 .mc-title { display:none }，
      结果模型选择变成空白框）。
   ⚠️ 上面的 .vc-voices / .vc-voice（旧音色选择）保留不动：
      页面已经不渲染它们了，但删样式要动的地方更多，而它们无副作用。
   ============================================================================ */

/* ---- 快速插入词：小圆角标签，点一下追加到描述里 ---- */
.vc-chips {
  display: flex; flex-wrap: wrap; gap: 0.35rem;
}
.vc-chip {
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #4b5563;
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
  font-size: 0.74rem;
  font-weight: 600;
  cursor: pointer;
  line-height: 1.30;
  /* ⚠️ 不折行：标签里的字很少，折了会变得高矮不齐 */
  white-space: nowrap;
  transition: all .15s;
}
.vc-chip:hover { border-color: var(--mc-acc); color: var(--mc-acc); background: #f5f3ff; }
.vc-chip:active { transform: scale(.96); }

/* ---- 常用模板：比插入词大一点，因为是整段文字 ---- */
/* ★★★ v2.796：改成【卡片】形态（对齐 MJ 截图）
   ⚠️ 上一版是 auto-fill + minmax(88px)：那是给"光秃秃的名称按钮"排版的。
      卡片要放 图标+名称+角标+摘要+三个按钮，88px 根本不够 ⇒ 会挤成一团。
      改成 minmax(190px, 1fr)：宽屏一行 4~5 张，窄屏自动减列。 */
.vc-tpls {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 0.5rem;
}
/* 老的单按钮样式：页面已经不渲染它了，保留是因为别处（如文档/判据）还引用，
   删样式要动的地方更多，而它无副作用。 */
.vc-tpl {
  border: 1px solid #e5e7eb;
  background: #fafbfc;
  color: #374151;
  border-radius: 0.55rem;
  padding: 0.4rem 0.3rem;
  font-size: 0.75rem;
  font-weight: 700;
  cursor: pointer;
  line-height: 1.3;
  transition: all .15s;
}
.vc-tpl:hover { border-color: var(--mc-acc); color: var(--mc-acc); background: #f5f3ff; }

/* ---- 模板卡片 ---- */
.vc-tplc {
  border: 1px solid #e9ecf3;
  background: #fff;
  border-radius: 0.7rem;
  padding: 0.55rem 0.6rem 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  transition: all .15s;
}
.vc-tplc:hover { border-color: var(--mc-acc); box-shadow: 0 4px 14px rgba(124, 58, 237, .08); }
.vc-tplc-head { display: flex; align-items: center; gap: 0.4rem; }
.vc-tplc-head > b { font-size: 0.82rem; font-weight: 800; color: #374151; }
/* 波形图标：只用 CSS 画（本项目零依赖，不引图标库）
   ⚠️ 5 根高低不同的竖条 = "音频"的通用符号，比 emoji 可控且不变形。 */
.vc-wave { display: inline-flex; align-items: center; gap: 2px; height: 16px; flex: 0 0 auto; }
.vc-wave > i {
  display: block; width: 2px; border-radius: 1px;
  background: linear-gradient(180deg, #8b5cf6, #6366f1);
}
.vc-wave > i:nth-child(1) { height: 7px; }
.vc-wave > i:nth-child(2) { height: 13px; }
.vc-wave > i:nth-child(3) { height: 16px; }
.vc-wave > i:nth-child(4) { height: 10px; }
.vc-wave > i:nth-child(5) { height: 6px; }
/* 「旁白草稿」角标：和 MJ 一致（说明这是可改的草稿，不是成品） */
/* ⚠️ v2.797：颜色改用【主题变量】而不是写死的十六进制。
   判据（tools/me-center-probe.mjs）抓到过这里 ——
   项目里换皮肤是靠改 --mc-* 变量，写死的色值换皮肤时不会跟着变。
   可用的语义色见 style.css 顶部那组 --mc-acc* 定义。 */
.vc-tplc-badge {
  align-self: flex-start;
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--mc-acc);
  background: var(--mc-acc-soft, #f5f3ff);
  border: 1px solid var(--mc-acc-line, #ddd6fe);
  border-radius: 0.3rem;
  padding: 0.02rem 0.3rem;
  line-height: 1.5;
}
/* 摘要：最多两行，超出省略（全文在「详情」里看） */
.vc-tplc-desc {
  margin: 0;
  font-size: 0.72rem;
  color: #6b7280;
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.1em;   /* 两行高度固定，卡片不会高矮不齐 */
}
.vc-tplc-acts {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: auto;    /* 按钮贴底：卡片高度不一致时也对齐 */
}
.vc-tplc-a {
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #6b7280;
  border-radius: 0.4rem;
  padding: 0.2rem 0.5rem;
  font-size: 0.7rem;
  font-weight: 700;
  cursor: pointer;
  transition: all .15s;
}
.vc-tplc-a:hover { border-color: var(--mc-acc); color: var(--mc-acc); }
/* 「使用」是主操作：实心（和 MJ 那张图一致） */
.vc-tplc-use {
  margin-left: auto;
  background: var(--mc-acc);
  border-color: var(--mc-acc);
  color: #fff;
}
.vc-tplc-use:hover { background: #6d28d9; border-color: #6d28d9; color: #fff; }

/* ---- 模板弹窗（详情 / 试听都用它）---- */
.vc-dlg-mask {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(15, 23, 42, .45);
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
}
.vc-dlg {
  background: #fff; border-radius: 0.9rem;
  width: min(560px, 100%); max-height: 80vh;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 60px rgba(15, 23, 42, .3);
}
.vc-dlg-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.6rem; padding: 0.85rem 1rem 0.6rem;
  border-bottom: 1px solid #eef0f6;
}
.vc-dlg-head > b { font-size: 0.92rem; color: #374151; }
.vc-dlg-x {
  border: none; background: transparent; color: #9ca3af;
  font-size: 0.95rem; cursor: pointer; line-height: 1; padding: 0.2rem;
}
.vc-dlg-x:hover { color: #374151; }
.vc-dlg-body {
  padding: 0.8rem 1rem; overflow-y: auto;
  font-size: 0.8rem; color: #4b5563; line-height: 1.75;
  white-space: pre-wrap;      /* ⚠️ 保留换行：模板里有分段 */
  word-break: break-word;
}
.vc-dlg-note {
  margin: 0; padding: 0 1rem 0.6rem;
  font-size: 0.72rem; color: #9ca3af; line-height: 1.6;
}
.vc-dlg-foot {
  display: flex; justify-content: flex-end; gap: 0.5rem;
  padding: 0.6rem 1rem 0.85rem; border-top: 1px solid #eef0f6;
}

/* ============================================================================
   ★★★ v2.798：右栏「当前任务 / 生成记录」（对齐 MJ）
   ----------------------------------------------------------------------------
   🔴 用户原话：「右侧我的作品，作品广场那三个TAB就不要了，
      改成和MJ一模一样的。」
   ⚠️ 类名加之前都查过 CSS，原先【都不存在】。
   ============================================================================ */
/* tab 头：两个等宽按钮（MJ 那个形态） */
.vc-side-tabs {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.7rem;
  flex: 0 0 auto;
}
.vc-side-tab {
  flex: 1 1 0;
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #6b7280;
  border-radius: 0.55rem;
  padding: 0.45rem 0.5rem;
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
  transition: all .15s;
}
.vc-side-tab:hover { border-color: var(--mc-acc); color: var(--mc-acc); }
/* 选中态：实心紫（MJ 那张图里就是实心） */
.vc-side-tab.active {
  background: var(--mc-acc);
  border-color: var(--mc-acc);
  color: #fff;
}
/* ★★★ v2.827：模式切换（文生音效 / 图生音效）
   ------------------------------------------------------------
   样式沿用 .vc-side-tab 那一套（同一个页面里两个 tab 栏长得不一样会很怪）。
   ⚠️ 类名用 .vc-mode（带 vc- 前缀），不做成全局类 ——
      本项目踩过"全局类波及别的页面"的坑（.thumb / .thumbs）。
   ⚠️ 选中态用 .on 而不是 .active：
      右栏 tab 用的是 .active，这里的按钮和它是两套控件，
      用不同类名可以避免"右栏切 tab 时把模式按钮也点亮"这类串扰。 */
.vc-modes {
  display: flex;
  gap: 0.4rem;
  margin: 0 0 0.7rem;
  flex: 0 0 auto;
}
.vc-mode {
  flex: 1 1 0;
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #6b7280;
  border-radius: 0.55rem;
  padding: 0.45rem 0.5rem;
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
  transition: all .15s;
}
.vc-mode:hover { border-color: var(--mc-acc); color: var(--mc-acc); }
.vc-mode.on {
  background: var(--mc-acc);
  border-color: var(--mc-acc);
  color: #fff;
}

/* 图生音效：上传区（虚线框，点它选图） */
.vc-img-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  border: 1px dashed var(--mc-acc-line);
  background: var(--mc-acc-soft);
  border-radius: 0.7rem;
  /* ⚠️ 用 min-height 而不是固定 height —— 窄屏（320px）下内容会换行，
      固定高度会把字切掉。 */
  min-height: 116px;
  padding: 1rem;
  cursor: pointer;
  text-align: center;
  transition: all .15s;
}
.vc-img-drop:hover { border-color: var(--mc-acc); }
.vc-img-drop .vc-img-ico { width: 30px; height: 30px; color: var(--mc-acc); }
.vc-img-drop .vc-img-ico svg { width: 100%; height: 100%; }
.vc-img-drop b { font-size: 0.86rem; color: var(--mc-acc-ink); }
.vc-img-drop i { font-size: 0.72rem; font-style: normal; color: #9ca3af; }
/* 已有图时把上传区压扁（省竖直空间，图本身在下面显示） */
.vc-img-drop.compact { min-height: 62px; padding: 0.6rem; }

/* 已选图片的预览行 */
.vc-img-preview {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.55rem;
  padding: 0.5rem;
  border: 1px solid var(--mc-acc-line);
  border-radius: 0.6rem;
  background: #fff;
}
.vc-img-preview img {
  width: 54px;
  height: 54px;
  object-fit: cover;
  border-radius: 0.45rem;
  /* ⚠️ 必须有背景色兜底：图还没加载出来时那块会是空白，
      看着像"没选中" */
  background: var(--mc-acc-soft);
  flex: 0 0 auto;
}
.vc-img-meta { flex: 1 1 auto; min-width: 0; }
.vc-img-meta b {
  display: block;
  font-size: 0.78rem;
  color: #111827;
  /* ⚠️ 长文件名必须截断 —— 不截断会把整行撑破、把删除按钮挤出屏幕 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vc-img-meta i { font-size: 0.72rem; font-style: normal; color: #9ca3af; }
.vc-img-del {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #9ca3af;
  border-radius: 50%;
  cursor: pointer;
  font-size: 0.8rem;
  line-height: 1;
}
.vc-img-del:hover { border-color: #ef4444; color: #ef4444; }

/* 面板：占满剩余高度 + 内部滚动 */
.vc-side-pane {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;}

/* 结果播放器挂在右栏里 —— 覆盖 .result-stage 的大高度。
   ⚠️ .result-stage 默认 min-height: 380px，那是给"整块舞台"用的；
      放进窄右栏会把任务信息挤到屏幕外。
   ⚠️ 不用改 .result-stage 本体（别的页面还在用），只在本页覆盖。 */
.vc-side .result-stage {
  min-height: 150px;
  margin-bottom: 0.7rem;
}

/* 任务信息卡 */
.vc-task-card {
  border: 1px solid #eef0f6;
  border-radius: 0.7rem;
  background: #fcfdff;
  padding: 0.7rem 0.8rem;
  margin-bottom: 0.7rem;
}
.vc-task-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.vc-task-head > b { font-size: 0.84rem; font-weight: 800; color: #374151; }
/* 状态角标（待生成 / 生成中 / 已准备就绪） */
.vc-task-state {
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--mc-acc);
  background: var(--mc-acc-soft, #f5f3ff);
  border: 1px solid var(--mc-acc-line, #ddd6fe);
  border-radius: 0.3rem;
  padding: 0.05rem 0.35rem;
  white-space: nowrap;
}
/* 键值表：左边标签固定宽，右边值换行不撑破 */
.vc-task-dl {
  display: grid;
  grid-template-columns: 4.2rem minmax(0, 1fr);
  gap: 0.3rem 0.5rem;
  margin: 0;
  font-size: 0.75rem;
}
.vc-task-dl > dt { color: #9ca3af; }
.vc-task-dl > dd {
  margin: 0;
  color: #4b5563;
  overflow-wrap: anywhere;   /* 长描述不会撑破卡片 */
}
.vc-task-hint {
  margin: 0;
  font-size: 0.74rem;
  color: #9ca3af;
  line-height: 1.75;
}

/* ---- 输出参数：三列（窄屏自动堆叠）---- */
/* ⚠️ v2.800：页面已经不用 .vc-params 了（换成下面那个 .vc-row 一行到底）。
   保留是怕别处还有引用；删样式要动的地方更多，而它无副作用。 */
.vc-params {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.5rem;
}
.vc-param { display: block; }
.vc-param > span {
  display: block;
  font-size: 0.72rem;
  color: #6b7280;
  margin-bottom: 0.2rem;
}
.vc-param select { width: 100%; }

/* ============================================================================
   ★★★ v2.800：生成参数压成【一行】（对齐 MJ）
   ----------------------------------------------------------------------------
   🔴 用户原话：「这个模块也要做成他这样，我们的太占地方了」
   ★ 原来「生成参数」三个下拉各自撑满、目标时长又单独占一整行 ⇒ 竖着很高。
   ★ MJ 那页是：生成类型 | 输出格式 | 采样率 | 目标时长(滑杆) 全在一行。
   ★ 实现方式：
       · 三个下拉给【固定宽度】—— 下拉本身不需要那么宽
         （"智能判断""MP3"这些字很短，撑满 1/3 屏纯属浪费）
       · 目标时长用 flex:1 吃掉剩下的空间（它是滑杆，越宽越好拖）
   ⚠️ 不用 grid 等分：等分会让每个下拉都很宽、又没有滑杆的位置。
   ⚠️ 窄屏（手机）会自然换行 —— flex-wrap: wrap，不用写媒体查询。
   ⚠️ 声道是 MJ 没有的（我们多出来的功能），给它最小宽度即可。 */
.vc-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;      /* 标签在上、控件在下，底边对齐 */
  gap: 0.6rem 0.7rem;
}
.vc-cell { display: block; margin: 0; }
.vc-cell > span {
  display: block;
  font-size: 0.72rem;
  color: #6b7280;
  margin-bottom: 0.2rem;
  white-space: nowrap;
}
.vc-cell select { width: 100%; }
.vc-cell-kind   { flex: 0 1 168px; }
.vc-cell-fmt    { flex: 0 1 118px; }
.vc-cell-rate   { flex: 0 1 138px; }
.vc-cell-ch     { flex: 0 1 118px; }
/* 目标时长：吃掉剩下的宽度（滑杆越宽越好拖）
   ⚠️ min-width 保证它在窄屏上不会被压成一条看不清的线 */
.vc-cell-target { flex: 1 1 200px; min-width: 170px; }
.vc-cell-target > span {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.4rem;
}
.vc-cell-target > span > b {
  color: var(--mc-acc);
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
}
.vc-cell-target input[type="range"] { width: 100%; }

/* ---- 声音微调：一行标题（左名右值）+ 一条滑杆 ---- */
/* ★★★ v2.793：面板变宽之后，三个滑杆要【横排一行】（对齐 MJ 那页）——
   ⚠️ 原来是竖着堆三行，在 460px 的窄栏里是对的；
      栏宽改成 1fr（约 1100px）之后，竖排会拉得很高、右边全空。
   ⚠️ 用 auto-fit + minmax(220px, 1fr)：宽屏三列、窄屏自动堆叠，
      不用写媒体查询（少一处要维护的分支）。 */
.vc-slider-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.2rem 1.1rem;
}
.vc-slider { margin-top: 0.6rem; }
/* 滑杆的说明只在整行下面留一条，不用每个滑杆各带一条（横排时会很乱） */
.vc-slider-row + .form-row-note { margin-top: 0.35rem; }
.vc-slider-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem;
  font-size: 0.76rem;
  color: #4b5563;
  font-weight: 600;
  margin-bottom: 0.15rem;
}
.vc-slider-top b {
  color: var(--mc-acc);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;   /* 数字变化时不抖动 */
}
.vc-slider input[type="range"] { width: 100%; }
/* ⚠️ 禁用的滑杆必须【看得出来是禁用的】——
   语调那一项接口不支持，如果看着和别的滑杆一样，
   用户会以为"拖了没反应是坏了"。 */
.vc-slider input[type="range"]:disabled { opacity: .45; cursor: not-allowed; }
/* "暂不支持"标记：小、灰、不抢眼，但一定要看得见 */
.vc-ns {
  font-style: normal;
  font-size: 0.66rem;
  font-weight: 600;
  color: #9ca3af;
  background: #f3f4f6;
  border-radius: 0.3rem;
  padding: 0 0.28rem;
  margin-left: 0.25rem;
}

/* ★ v2.793：底栏改成一行（状态 | 清空 | 生成）
   ⚠️ 复用 .foot-actions 的既有 flex 规则，这里只调整【顺序与占比】：
      · 状态文字靠左
      · 两个按钮靠右（margin-left:auto 推过去）
   ⚠️ 不给 .btn-primary 设 flex:1 —— 面板宽了之后通栏大按钮会变得很夸张，
      MJ 那页的生成按钮也是紧凑的胶囊形。 */
.vc-foot-row { align-items: center; }
.vc-foot-status {
  margin-right: auto;      /* 把后面的按钮推到右边 */
  margin-bottom: 0;        /* 覆盖 .foot-cost 可能带的底边距 */
  white-space: nowrap;
}
.vc-foot-status > span { font-size: 0.8rem; color: #6b7280; }
.vc-foot-status b { color: var(--mc-acc); }

/* ★★★ v2.807：生成按钮——主标题 + 计费说明【排在同一行】
   ----------------------------------------------------------------------------
   🔴 用户原话：「这个字的内容，不要分两行」
   ★ v2.804 我做成了竖排两行（主标题一行、计费一行）。
     现在改成【横排一行】：主标题和计费并排。
   ⚠️ 光改布局不够 —— 那句话本身也变短了（见 voice.js 里 v2.807 的注释）：
      原来「计费：每 2 秒 1 积分（不足 2 秒按 2 秒算）· 上限 600 秒」
      在按钮里横排放不下，精简成「每 2 秒 1 积分 · 上限 600 秒」才放得下。
      省掉的"不足 N 秒按 N 秒算"进了按钮的 title 悬停提示（信息没丢）。
   ⚠️ 但要留 flex-wrap: wrap 作为【保险】：
      手机窄屏下按钮可能只有 150~200px 宽，硬撑一行会溢出（文字被裁掉，
      用户看不到计费规则，比换行更糟）。允许换行 ⇒ 宽屏一行、窄屏自动落下来。
      ⇒ 这是"优先满足用户要的一行，同时不牺牲窄屏可读性"，不是不听话。
   ⚠️ 主标题和计费用 gap 分开，且计费是次要信息（小一号 + 半透明白）。 */
.vc-run-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;              /* ⚠️ 窄屏保险：放不下时允许落行，不裁切文字 */
  gap: 0.3rem;
  line-height: 1.3;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}
.vc-run-main { font-weight: 800; white-space: nowrap; }
.vc-run-sub {
  font-weight: 500;
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.85);
  text-align: center;
  /* ⚠️ 正常情况保持一行；wrap 只在真的放不下时才生效 */
  white-space: nowrap;
  /* ⚠️ 空的时候不占高度：refresh() 还没填进来之前会有一瞬间是空的，
     不处理的话按钮会先窄后宽地跳一下 */
  min-height: 0;
}
.vc-run-sub:empty { display: none; }

/* ============================================================================
   ★★★ v2.795：描述框下面那排工具（对齐 MJ 截图）
   ----------------------------------------------------------------------------
   四个入口：可参考的音频 / 情绪 / 停顿 / 语气词
   ⚠️ 类名加之前都查过，原先【都不存在】，不会撞车。
   ⚠️ 弹出菜单用【绝对定位 + 相对父级】：父级 .vc-tool 要 position:relative，
      否则菜单会以卡片为基准定位，跑到奇怪的地方。
   ⚠️ 不做成 <select>：下拉里放不下"上传文件 + 说明文字 + 列表"这些东西，
      而且 MJ 那页也是弹出面板的形态。
   ============================================================================ */
/* ============================================================================
   ★★★ v2.857：工具行【移进输入框内部】（对齐 MJ）
   ----------------------------------------------------------------------------
   🔴 用户要求：「下面那一排按钮，放到上面去，参考MJ。」
   ★ 原来 .vc-tools 在 .pb-wrap 【外面】（输入框下方独立一行）；
     现在移进 .pb-wrap 内部、编辑器与页脚之间。

   ⚠️⚠️ 这里【刻意不用绝对定位浮层】，虽然那样更像 MJ 那种"悬在框内底部"。
      原因：浮层会**盖住最后一行文字**。
        · 必须给编辑器加 padding-bottom 把底部留白 —— 但 .vc-editor 是
          contenteditable 且 min-height:150px，加留白会让"点框内任意位置"
          的判定区域变得奇怪（点到留白处光标不知道去哪）。
        · 而且文字多、编辑器滚到底时，浮层会压着正在编辑的那一行，
          用户会以为"字被吃了" —— 这种问题极难描述、极难排查。
      ⇒ 改成【框内的一行】：视觉上仍"在输入框里"（同一个边框、同一张卡片），
        但不遮任何内容。稳妥优先。
   ⚠️ 不用 margin-top：父级已经是 .pb-wrap（有 padding），
      再加外边距会把它顶得离编辑器太远、看着像两个块。
   ⚠️ 加一条细分隔线：让"描述区"和"工具区"在同一张卡里有层次，
      否则按钮会像是文字的一部分。
   ============================================================================ */
/* ============================================================================
   ★★★ v2.862：工具行 + 「字数 · 清空」并成【同一行】
   ----------------------------------------------------------------------------
   🔴 用户要求：「这两个按钮在一行」（截图圈了左边那排工具按钮、
      和右边那块「0 / 3000 · 清空」）。原来它们是【上下两行】。

   ★ 结构（voice.html 里）：
       .vc-bar（本行）
         ├ .vc-tools.vc-tools--inset   ← 左：可参考的音频 / 情绪 / 停顿 / 语气词
         └ .pb-foot.pb-foot--inset     ← 右：0 / 3000 + 清空

   ⚠️ 为什么用 flex + space-between，而不是绝对定位把字数钉到右边：
      绝对定位在窄屏会【和工具按钮重叠】（工具行 flex-wrap 会换行，
      而绝对定位的元素不参与布局，正好压上去）。flex 布局窄屏会自动换行，
      虽然那时又会分两行 —— 但那是"放不下"，不是"被压住"，可接受。
   ⚠️ flex-wrap: wrap 必须留：手机宽度下四个按钮 + 计数放不下一行。
   ⚠️ align-items: center：工具按钮是胶囊、计数是文字，不对齐会一高一低。
   ============================================================================ */
.vc-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.15rem;
  padding-top: 0.45rem;
  border-top: 1px dashed #eef0f5;   /* 原来那条分隔线移到这一行上 */
}
/* ⚠️ 分隔线已经由 .vc-bar 画了 —— 工具行自己不要再画一条（会出双线） */
.vc-bar .vc-tools--inset {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
  flex: 1 1 auto;        /* 占满左边，把字数/清空顶到最右 */
  min-width: 0;
}
/* ⚠️ 原来 .pb-foot 自带 padding-top + 上边框（它是"独立的一行"）。
   挪进同一行之后必须去掉，否则会比工具按钮矮一截、还多一条线。 */
.vc-bar .pb-foot--inset {
  padding-top: 0;
  border-top: 0;
  flex: 0 0 auto;
  margin-left: auto;     /* 双保险：即使 vc-tools 没占满，也把它推到最右 */
}

.vc-tools--inset {
  margin-top: 0.15rem;
  padding-top: 0.45rem;
  border-top: 1px dashed #eef0f5;
  gap: 0.3rem;
}

.vc-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.55rem;
}
.vc-tool { position: relative; }
/* ★★★ v2.799：按钮做成 MJ 那种「圆形图标 + 文字」的胶囊
   ------------------------------------------------------------
   🔴 用户原话：「这些标签都做成MJ一样的。」
   ★ 之前是纯文字按钮（"+ 情绪"），和 MJ 那排差得远 ——
     MJ 每个按钮左边都有一个圆形图标底，整体是一个胶囊。
   ⚠️ 图标用 inline SVG（见 HTML）：emoji 在不同系统长得不一样，
      也会被替换成彩色字形，和旁的线条图标不搭。
   ⚠️ 圆形图标底用主题色系（换皮肤时跟着变，不写死颜色）。 */
.vc-tool-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #4b5563;
  border-radius: 999px;          /* ★ 胶囊：MJ 那排都是全圆角 */
  padding: 0.22rem 0.7rem 0.22rem 0.25rem;
  font-size: 0.75rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: all .15s;
}
.vc-tool-btn:hover { border-color: var(--mc-acc); color: var(--mc-acc); }
.vc-tool-btn.on { border-color: var(--mc-acc); color: var(--mc-acc); background: var(--mc-acc-soft, #f5f3ff); }
.vc-tool-btn b { color: var(--mc-acc); }
/* 圆形图标底 */
.vc-tool-ico {
  flex: 0 0 auto;
  width: 1.35rem; height: 1.35rem;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--mc-acc-soft, #f5f3ff);
  color: var(--mc-acc);
}
.vc-tool-ico > svg { width: 0.85rem; height: 0.85rem; display: block; }
.vc-tool-btn.on .vc-tool-ico { background: #fff; }

/* 弹出面板 */
.vc-pop {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;                 /* 要盖住下面的「生成参数」区 */
  min-width: 220px;
  max-width: 320px;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 0.6rem;
  box-shadow: 0 8px 24px rgba(15, 23, 42, .12);
  padding: 0.35rem;
}
.vc-pop.open { display: block; }
/* 情绪/停顿/语气词：两列小按钮 */
.vc-pop-grid {
  display: none;
  grid-template-columns: 1fr 1fr;
  gap: 0.25rem;
}
.vc-pop-grid.open { display: grid; }
.vc-pop-opt {
  border: 1px solid #eef0f6;
  background: #fafbfc;
  color: #374151;
  border-radius: 0.45rem;
  padding: 0.35rem 0.3rem;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
}
.vc-pop-opt:hover { border-color: var(--mc-acc); color: var(--mc-acc); background: var(--mc-acc-soft, #f5f3ff); }
/* 上传那一项做成整行可点（它是 label，套着隐藏的 file input）
   ★ v2.799：整体加图标（和上面那排按钮同一种形态）。
   ⚠️ 用 grid 两列：图标一列、文字一列；
      说明文字要落在【文字那一列】下面，不能跑到图标底下（那样很难看）。 */
.vc-pop-item {
  display: grid;
  grid-template-columns: 1.35rem minmax(0, 1fr);
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.6rem;
  border-radius: 0.45rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: #374151;
  cursor: pointer;
}
.vc-pop-item:hover { background: var(--mc-acc-soft, #f5f3ff); color: var(--mc-acc); }
.vc-pop-note {
  display: block;
  font-size: 0.68rem;
  font-weight: 400;
  color: #9ca3af;
  line-height: 1.45;
  margin: 0.1rem 0 0 0;
}
/* ⚠️ 说明在 vc-pop-item 里时，它占【第二列】（和标题同列、换行在其下） */
.vc-pop-item > .vc-pop-note { grid-column: 2; }
/* 已上传的参考音频列表 */
.vc-ref-list { margin-top: 0.3rem; }
.vc-ref-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  font-size: 0.72rem;
  color: #4b5563;
}
.vc-ref-item > span { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vc-ref-item > button {
  flex: 0 0 auto;
  border: 1px solid #e5e7eb;
  background: #fff;
  color: #9ca3af;
  border-radius: 0.35rem;
  width: 1.3rem; height: 1.3rem;
  line-height: 1;
  cursor: pointer;
}
.vc-ref-item > button:hover { color: #dc2626; border-color: #fecaca; }

/* ============================================================================
   ★★★ v2.803：内容编辑器（contenteditable）+ 彩色胶囊标签
   ----------------------------------------------------------------------------
   🔴 用户原话：「mj是为一段选中的文字增加情绪，并且有颜色标出来。
      插入的停顿和语气词也是这样的标签，很显眼也好看。」
      「方案 B：把输入框换成内容编辑器，插入的东西渲染成彩色胶囊，
        并且支持『选中一段文字 → 点情绪 → 给这段加标记』」

   ★ 为什么必须换成 contenteditable：
      <textarea> 里只能是纯文本，插进去的 HTML 会被原样显示成字符
      ⇒ 物理上做不出彩色标签。

   ⚠️ 三个必须处理好的细节（textarea 不用管，换了之后全要自己来）：
      ① 空的时候显示占位提示 —— contenteditable 没有 placeholder 属性，
         用 :empty::before + data-ph 实现。
         ⚠️ 只在【真的空】时才显示：里面有一个 <br> 就不算 empty，
            所以清空时必须把内容真的清掉（见 voice.js 的 clearEditor）。
      ② 高度要像多行输入框：min-height + 自动撑高（内容多了往下长，不滚动）。
      ③ 聚焦要有可见的边框变化（和别的 .field 一致），否则用户不知道光标在哪。
   ============================================================================ */
.vc-editor {
  min-height: 150px;
  max-height: 46vh;              /* ⚠️ 太长时给个上限，否则会把工具栏顶出屏幕 */
  overflow-y: auto;
  line-height: 1.75;
  white-space: pre-wrap;         /* 保留换行和空格（和 textarea 行为一致） */
  word-break: break-word;
  outline: none;
}
.vc-editor:focus { border-color: var(--mc-acc); }
/* 占位提示（contenteditable 没有 placeholder 属性） */
.vc-editor:empty::before {
  content: attr(data-ph);
  color: #9ca3af;
  pointer-events: none;          /* 点它时光标要落到编辑器里，不是点在提示上 */
}
/* ⚠️ 浏览器在某些编辑操作后会留一个空的 <br>，那时 :empty 不成立、
      占位提示就不显示了（看起来像"提示没了"）。这里把"只有一个 br"
      也算空。:has 在现代浏览器都支持，且只影响提示的显隐。 */
.vc-editor:has(> br:only-child)::before {
  content: attr(data-ph);
  color: #9ca3af;
  pointer-events: none;
}

/* ---- 彩色胶囊标签 ----
   ⚠️ 用 <span contenteditable="false"> 而不是纯文本：
      这样标签在编辑器里是【一个整体】，光标不会跑到标签中间把它拆开，
      退格也会一次删掉整个标签（用户预期就是这样）。
   ⚠️ 颜色按类型区分（情绪/停顿/语气词），让人一眼看出插的是什么：
      · 情绪 = 紫（和主题色一致）
      · 停顿 = 蓝（"时间"的感觉）
      · 语气词 = 橙（"发声"的感觉）
   ⚠️ 用主题变量而不是写死颜色 —— 换皮肤时要跟着变
      （判据会检查这里有没有裸色值，本项目为此踩过坑）。 */
.vc-pill {
  display: inline-block;
  padding: 0.02rem 0.4rem;
  margin: 0 0.12rem;
  border-radius: 0.35rem;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
  vertical-align: baseline;
  /* ⚠️ 不加 user-select: none：用户要能选中它、然后整体删除 */
  cursor: default;
}
/* 情绪 */
.vc-pill-emo {
  color: var(--mc-acc, #7c3aed);
  background: var(--mc-acc-soft, #f5f3ff);
  border: 1px solid var(--mc-acc-line, #ddd6fe);
}
/* 停顿 */
.vc-pill-pause {
  color: #1d4ed8;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}
/* 语气词 */
.vc-pill-tone {
  color: #c2410c;
  background: #fff7ed;
  border: 1px solid #fed7aa;
}

/* ============================================================================
   ★★★ v2.809：被情绪标色的那段文字
   ----------------------------------------------------------------------------
   🔴 用户原话：「情绪是必须选中一段文字才能点按钮，插入情绪后，这一段有情绪
      的文字都标了颜色。所以情绪到这段标色文字结束，就结束了。」

   ★ 我 v2.803 做错的地方（用户这次纠正的就是它）：
      我只在选区【末尾插了一个胶囊】，选中的文字【没标色】
      ⇒ 用户看不出"这个情绪管到哪儿结束"。
   ★ 现在：选中的那段文字被包进 .vc-callout（浅底 + 情绪色字 + 圆角下划线），
      情绪胶囊紧跟在它后面 ⇒ 视觉上「文字+胶囊」是一整块，
      一看就知道情绪作用范围到哪儿。

   ⚠️ 为什么用浅背景 + 圆角，而不是只改文字颜色：
      只改字色的话，和正文的深色差不够明显（尤其中文小字）；
      加浅底能形成"一段"的块感 —— 这正是用户说的"这一段"。
   ⚠️ 不用浏览器默认的 ::selection 高亮：那是临时的，一点别处就没了；
      这里要的是**持久的标记**（存进内容里，随文字一起编辑）。
   ⚠️ 颜色用主题变量：换皮肤跟着变（本项目有检查会挑写死的主题色）。 */
.vc-callout {
  color: var(--mc-acc-ink, #6d28d9);
  background: var(--mc-acc-soft, #f5f3ff);
  border-bottom: 2px solid var(--mc-acc-line, #ddd6fe);
  border-radius: 0.2rem 0.2rem 0 0;
  padding: 0.02rem 0.1rem;
  /* ⚠️ 不加 white-space: nowrap —— 标色的可能是一整句，必须能换行 */
}

/* ⚠️ 情绪按钮在【没选中文字】时禁用 —— 见 voice.js 的 bindEmoEnabled()。
   用户明确要求"必须选中才能点"，禁用它就是最直白的表达。
   禁用态要看得出来（否则用户会以为按钮坏了）： */
.vc-pop-opt:disabled { opacity: .45; cursor: not-allowed; }
.vc-tool.is-locked { opacity: .6; }
/* 情绪按钮上方给一句提示（选中才有），放在菜单里而不是按钮上，
   免得工具行那一排宽度变化。 */
.vc-pop-note {
  grid-column: 1 / -1;
  font-size: .7rem;
  color: #9ca3af;
  padding: .1rem .2rem .25rem;
  line-height: 1.6;
}

/* ⚠️ 这条是【旧音色选择】的样式，v2.791 重做页面时我一并删掉过 ——
   已经补回来：虽然页面不再渲染 .vc-voices，但别的判断/文档还引用它，
   而且删样式属于"顺手改动"，超出了这一轮的范围。 */
.vc-voices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 0.4rem;
}


.vc-voice {
  border: 1px solid #e5e7eb;
  background: #fff;
  border-radius: 0.7rem;
  padding: 0.45rem 0.5rem;
  cursor: pointer;
  text-align: left;
  font: inherit;
  transition: border-color .15s, background .15s;
}
.vc-voice:hover { border-color: var(--mc-acc-line, #c4b5fd); }
/* ⚠️ v2.754：这里【必须】用皮肤令牌，不能写死紫色。
   ★ 是 me-center-probe 抓到我的：项目有一条规矩
     「组件里不许残留写死的主题色，否则换皮肤那几处不会变」。
     配音页也会换皮肤（它和音乐/视频同一套工作台），写死就会出现
     "整个页面变了、只有音色卡片还是老紫色"。
   ⚠️ 令牌取不到时给兜底值（var 的第二参数）——
      这样万一令牌没定义，也不会变成透明/无边框。 */
.vc-voice.on {
  border-color: var(--mc-acc, #7c3aed);
  border-width: 2px;
  background: var(--mc-acc-soft, #ede9fe);
  position: relative;
}
.vc-voice.on::after {
  content: '✓';
  position: absolute;
  top: -6px;
  right: -6px;
  width: 1.05rem;
  height: 1.05rem;
  border-radius: 999px;
  background: var(--mc-acc, #7c3aed);
  color: #fff;
  font-size: 0.64rem;
  font-weight: 900;
  line-height: 1.05rem;
  text-align: center;
}
.vc-voice b { display: block; font-size: 0.82rem; font-weight: 800; color: #374151; }
.vc-voice.on b { color: var(--mc-acc-ink, #5b21b6); }
.vc-voice span { display: block; font-size: 0.66rem; color: #9ca3af; margin-top: 0.1rem; }
/* ⚠️ 深色主题下改底色/字色（这两处【不涉及主题色】，所以可以写死）。
   ⚠️ 选中态那条不用再写 —— 令牌本身就带深色变体（--mc-acc 在深色下会变）。 */
html[data-theme="dark"] .vc-voice { background: #1c2130; border-color: #2a3040; }
html[data-theme="dark"] .vc-voice b { color: #e5e7eb; }
html[data-theme="dark"] .vc-voice.on b { color: #c4b5fd; }
.foot-cost-value {
  font-size: 1.35rem;
  font-weight: 800;
  color: var(--mc-acc);
  white-space: nowrap;
}
.foot-actions { display: flex; gap: 0.6rem; align-items: center; }
/* ★★★ v2.549：底部按钮行的防护 —— 修「清空」右边被切一半
   ----------------------------------------------------------------
   ⚠️ 用户反馈：「清空两个字，怎么被盖住一半？」（截图里按钮右缘贴到面板边）
   ⚠️ 本机在 1920×884 下实测【并没有被任何祖先裁掉】
      （tools 里的 _btnprobe 量过：按钮 right=679，祖先 .studio-side
        right=679，没有任何 overflow:hidden/scroll 命中）。
      说明是【某个宽度档下容器略窄】造成的 —— 这种"差几像素"的问题
      靠单点测量抓不到，所以这里直接加防护，而不是继续猜哪一档。
   ★ 三处防护：
      ① .btn-ghost 不参与收缩（flex: 0 0 auto）—— 「清空」内容必须完整；
      ② .btn 加 min-width: max-content —— 即使被压也保持文字宽度；
      ③ 按钮行右侧留 2px 安全边距 —— 贴着面板边缘时圆角/描边不会被切。
   ⚠️ 不动 .btn-primary 的 flex: 1 1 auto（它要撑满剩余宽度，那是设计） */
.foot-actions .btn-ghost { flex: 0 0 auto; }
.foot-actions .btn { min-width: max-content; }
.foot-actions { padding-right: 2px; }
.foot-actions .btn-primary { flex: 1 1 auto; justify-content: center; }

/* ---------- 结果区 ---------- */
.studio-stage {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}
.studio-stage .result-stage { flex: 1 1 auto; }

/* ---------- 一行胶囊对齐（修「清晰度」错位）----------
   .field（下拉框）高度约 2.9rem，而 .chip 只有约 2.2rem，
   并排放在同一行时底边对不齐。这里给胶囊行一个统一的最小高度并垂直居中。 */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.9rem;
}
.chip-row .chip { margin: 0; }

/* ---------- 多张结果网格 ---------- */
.result-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.8rem;
  width: 100%;
  padding: 0.85rem;
  align-content: start;
}
.result-grid .cell {
  position: relative;
  border-radius: 0.85rem;
  overflow: hidden;
  background: #f1f2f7;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.result-grid .cell img { width: 100%; height: 100%; object-fit: cover; cursor: zoom-in; }
.result-grid .cell .cell-actions {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  gap: 0.35rem;
  padding: 0.5rem;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.55));
  opacity: 0;
  transition: opacity 0.25s;
}
.result-grid .cell:hover .cell-actions { opacity: 1; }
.result-grid .cell .cell-actions .icon-btn { width: 32px; height: 32px; font-size: 0.9rem; }
.result-grid .cell.is-failed { color: #b91c1c; font-size: 0.8rem; padding: 0.8rem; text-align: center; }
/* 覆盖早期版本留下的「整列滚动」规则
   （body[data-page=...] .tool-panel > div:first-child 的优先级更高，
     会把 .studio-side 变成滚动容器，导致固定底栏跟着滚） */
@media (min-width: 1024px) {
  body[data-page="image"] .tool-panel > .studio-side,
  body[data-page="video"] .tool-panel > .studio-side,
  body[data-page="music"] .tool-panel > .studio-side,
  /* ★ v2.793：voice 补进这个名单。
     ⚠️ 这页是从音乐页抄的结构，但【这一条名单当时漏了它】——
        于是别的页"底栏固定、中间滚动"，配音页却是整列一起滚，
        固定底栏跟着滚走（用户看到的按钮位置就飘）。
     判据依据：v2.793 那条"工作台页名单不许漏页"的检查会发现漏项。 */
  body[data-page="voice"] .tool-panel > .studio-side {
    overflow: hidden !important;
    padding-right: 0 !important;
  }
}
/* 底栏：数量一行 + 居中积分徽章 + 通栏生成按钮（对齐参考站的样子） */
.studio-side-foot .foot-top {
  align-items: center;
  justify-content: flex-start;
  gap: 0.7rem;
  margin-bottom: 0.7rem;
}
.studio-side-foot .foot-cost {
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin: 0 auto 0.7rem;
  padding: 0.32rem 0.9rem;
  border-radius: 999px;
  background: linear-gradient(135deg, #fdf2f8, var(--mc-acc-line));
  border: 1px solid #e9d5ff;
  width: fit-content;
}
.studio-side-foot .foot-cost-label { font-size: 0.75rem; color: var(--mc-acc); }
.studio-side-foot .foot-cost-value { font-size: 0.95rem; font-weight: 800; color: var(--mc-acc); }
/* ===========================================================
   参考站同款：模型卡片 + 右侧画廊
   =========================================================== */

/* ---------- 模型卡片 ---------- */
.model-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.55rem;
}
.model-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding: 0.6rem 0.75rem;
  border-radius: 0.75rem;
  border: 1.5px solid var(--line);
  background: rgba(255, 255, 255, 0.75);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.model-card:hover { border-color: #c084fc; background: #fff; }
.model-card.active {
  border-color: #9333ea;
  background: linear-gradient(135deg, rgba(147, 51, 234, 0.07), rgba(6, 182, 212, 0.07));
  box-shadow: 0 4px 14px rgba(147, 51, 234, 0.16);
}
/* ⚠️⚠️ v2.780：模型卡片里的标题/副标题必须用【自己的类名】(mcard-*)。
   ------------------------------------------------------------
   🔴 用户实测：「图片创作这里的生图模型选择，看起来好像是坏了！」
      —— 截图里模型卡片变成两个【空白框】。
   ★ 根因（真 bug，CSS 类名撞车）：
     模型卡片原来用 `.mc-title` / `.mc-sub`，而 `mc-` 是【个人中心
     member center】的命名前缀：
         .mc-title { display: none; }   ← 个人中心那条，见文件上方
     它没有作用域限制 ⇒ 把模型卡片的标题也一起 `display:none` 掉了
     ⇒ 卡片里只剩空 span ⇒ 看着就是"坏了"。
   ★ 修法：把模型卡片的两个类改名成 `mcard-title` / `mcard-sub`
     （个人中心那边不动 —— 它的规则是对的，错的是这里蹭了名字）。
   ⚠️ 这正是踩坑清单里那条「CSS 别用全局类」：
     给组件起类名要带自己的前缀，别用可能被别人占用的短名。
   ⚠️ 教训：这个 bug 【静态检查抓不到】（CSS 里两条规则各自都合法，
     只有"同时在页面上生效"才出问题）—— 靠用户截图才发现。
     所以下面加了一条判据（见 tools/adcard-css-probe.mjs）。 */
.model-card .mcard-title { font-size: 0.85rem; font-weight: 700; color: #374151; }
.model-card.active .mcard-title { color: var(--mc-acc-ink); }
.model-card .mcard-sub { font-size: 0.7rem; color: #9ca3af; line-height: 1.4; }

/* ---------- 右侧视图切换 ---------- */
.stage-tabs {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-bottom: 0.7rem;
  flex: none;
  /* 两个 tab 居中显示（原来靠左，右侧留一大片空白看着不平衡） */
  justify-content: center;
}
.stage-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.gallery-pane {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-right: 0.35rem;
}

/* 团队套餐已过期的醒目提示 */
.tm-expired {
  margin-top: 0.7rem;
  padding: 0.6rem 0.8rem;
  font-size: 0.8rem; line-height: 1.7;
  color: #b91c1c; background: #fef2f2;
  border: 1px solid #fecaca; border-radius: 0.6rem;
}
html[data-theme="dark"] .tm-expired {
  color: #fca5a5; background: rgba(220,38,38,.1); border-color: rgba(220,38,38,.3);
}

/* 积分流水：变动列前面的来源标识（个 / 会 / 团）
   颜色由 JS 内联给（三种来源三种色），这里只管尺寸和形状。 */
.tx-src {
  display: inline-block;
  min-width: 16px; text-align: center;
  font-size: 0.68rem; font-weight: 800; line-height: 1.5;
  padding: 0 4px; margin-right: 4px;
  border-radius: 4px;
  vertical-align: middle;
}

/* ---------- 画廊网格 ---------- */
.gallery-grid {
  display: grid;
  /* 作品广场（灵感广场）：固定 4 列 —— 4 张一排最好看。
     ★ 原来用 auto-fill + minmax(230px)，列数随容器宽度浮动，
       宽屏上会变成 5~6 列，卡片被压得很窄、提示词只剩一两个字。
       现在固定 4 列，再用媒体查询在窄屏上降到 3 / 2 / 1。 */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.85rem;
  align-content: start;
}
/* 窄屏降列：1200 → 3 列，880 → 2 列，560 → 1 列 */
@media (max-width: 1200px) {
  .gallery-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 880px) {
  .gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .gallery-grid { grid-template-columns: minmax(0, 1fr); }
}
.gallery-loading {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.85rem;
}
.gallery-card {
  border-radius: 0.9rem;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.85);
  border: 1px solid var(--line);
  transition: box-shadow 0.25s ease, border-color 0.25s ease;
}
.gallery-card:hover {
  box-shadow: 0 10px 26px rgba(31, 38, 135, 0.16);
  border-color: #c084fc;
}
.gallery-card .gc-img {
  aspect-ratio: 1 / 1;
  background: #f1f2f7;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* ★ 音乐 / 视频的占位不要用 1:1
   ------------------------------------------------------------
   ⚠️ 图片有真正的缩略图，1:1 正合适；但音乐和视频【没有缩略图】，
      1:1 会变成一个几百像素高的浅色大方块，里面只放一个 ♪ / 🎬 图标 ——
      看起来就是"一张空卡片"，而且把下面的作者名和提示词挤到很远。
      改成更扁的比例，卡片更紧凑、正文更显眼。
   ⚠️ 用 .gc-img.gc-img-media 两段类（比单写 .gc-img-media 更具体），
      确保能盖过上面那条 aspect-ratio —— 不靠"后写的赢"。 */
.gallery-card .gc-img.gc-img-media { aspect-ratio: 16 / 10; }
.gallery-card .gc-img img { width: 100%; height: 100%; object-fit: cover; cursor: zoom-in; }
.gallery-card .gc-ph { font-size: 1.8rem; color: #cbd5e1; }
.gallery-card .gc-body { padding: 0.6rem 0.7rem 0.75rem; }
.gallery-card .gc-author { font-size: 0.72rem; color: #6b7280; margin-bottom: 0.3rem; }
.gallery-card .gc-prompt {
  font-size: 0.75rem;
  color: #4b5563;
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* ★ 作品广场卡片的标签行（参考 MXAI：模块 / 比例 / 模型）
   ⚠️ 只有这一份定义（加之前 grep 过 .gc-tags / .gc-tag 都不存在）。
   ⚠️ flex-wrap 允许换行 —— 模型名可能很长（gpt-image-2.5-sunburst），
      不换行会把卡片撑宽。 */
.gc-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; margin: 0.4rem 0 0.1rem; }
.gc-tag {
  font-size: 0.66rem; font-weight: 600; line-height: 1;
  padding: 0.2rem 0.45rem; border-radius: 999px;
  color: var(--mc-acc-ink); background: rgba(147, 51, 234, 0.08);
  border: 1px solid rgba(147, 51, 234, 0.22);
  white-space: nowrap;   /* ⚠️ 单个标签不折行，否则「gpt-image-2.5-…」会断开 */
}
html[data-theme="dark"] .gc-tag {
  color: #c4b5fd; background: rgba(147, 51, 234, 0.16);
  border-color: rgba(147, 51, 234, 0.3);
}
/* ★ 广场卡片里的社交条：贴着正文下方，上边距小一点
   ⚠️ .work-row-social 本身已经有样式（v2.347 加的），这里只调间距 ——
      不要再写一套按钮样式，否则两套会互相覆盖。 */
.gc-social { margin-top: 0.55rem; }

/* ===========================================================
   ★ 作品广场 / 热门榜单：一行一张（MXAI 形态）
   -----------------------------------------------------------
   ⚠️ 用 .square-list 这个【新类】，【不动】 .gallery-grid 的全局样式 ——
      后者被全部 10 个 pane 用着（5 个页面 × square/mine），
      连 ensureHotTab 动态创建热榜 pane 时用的也是这个类名。
      改全局会把「我的作品」也一起变成一行一张 —— 那不是要的效果。
   ⚠️ 必须 !important： .gallery-grid 在 3 个媒体查询里分别设了
      3 列 / 2 列 / 1 列（本文件 L1679 / L1682 / L1685），
      同权重下后写的赢，不加就盖不住。
      ★ 这个手法和现成的 .work-list（本文件 L3351）完全一致。
   ⚠️ 下面的规则全部带 .square-list 前缀 —— 这样可以：
      · 不影响「我的作品」（那是 .work-list 那一套）
      · 避免和已有的 .gallery-card .gc-author / .gc-prompt 等
        形成【重复选择器】（v2.338 就是被重复规则静默覆盖，
        白折腾了三轮）。带前缀的是新选择器，且权重相同、位置在后 → 生效。
   =========================================================== */
.square-list {
  display: flex !important;
  flex-direction: column;
  gap: 1rem;
  grid-template-columns: none !important;
}

/* 一行一张之后，原来的 1:1 图会被拉到整屏宽（一张图占满一屏）。
   改成固定高度 —— 卡片像"一条"，而不是"一张海报"。 */
.square-list .gc-img {
  aspect-ratio: auto;
  height: 220px;
  /* ★★ v2.505：媒体区【内缩 + 圆角】（用户反馈"直接贴边，没有圆角，很难看"）
     ------------------------------------------------------------
     ⚠️ 原来这个块是【贴到卡片边缘的直角矩形】：
        · 卡片本身圆角 0.9rem + overflow:hidden，所以四角被裁圆
        · 但图片/占位块自己没圆角、没内边距 ⇒ 紧贴卡片上下左右边
        · 图片卡因为 object-fit:contain 留白、背景也是浅灰，
          "贴边"看不出来；视频卡的占位块是【实色】的，一眼就是
          一块方角色块怼在卡片边上（用户截图里那个红框）
        · 电商专区热榜【只有一张图】时同理（.gc-cmp 不存在，走的就是这里）
     ★ 修法：用 aspect-ratio + 内边距 + 圆角，替掉写死的 height:220px。
        · aspect-ratio: 16/10 —— 和 .gc-img-media 的比例一致，
          视频/音乐封面（16:9）基本贴合，不会出现奇怪的横条
        · padding: 0 0.85rem —— 左右各留一点（和 .gc-author 的
          padding 0.75/0.85rem、.gc-body 的 0.7rem 对齐，视觉成一条线）
        · border-radius: 0.7rem —— 比卡片自身 0.9rem 小一档，
          嵌套圆角才不会显得"角被啃掉"
        · overflow: hidden 保留，保证里面的 <img> 被裁进圆角里
     ⚠️ padding 上下为 0、圆角交给自己：这样图片上下仍然紧贴，
        但左右有内缩、四角是圆的 —— 这正是参考站（MXAI）的观感。 */
  /* ★★ v2.508：改成【限宽居中 + 四周留白】
     ------------------------------------------------------------
     ⚠️ v2.505 我加的是 padding: 0 0.85rem（左右各 13.6px）。但用户又反馈
        「不要贴边，参考一下我的作品里那个样式」——
        原因很简单：广场卡片是【整行宽】的（约 1000px），
        13.6px 的内缩在 1000px 宽上等于没有；而"我的作品"那边是
        【300px 的图放在整宽行里】，四周留白一眼就看得出来。
     ★ 所以照"我的作品"的形态改：媒体块【限宽 440px、水平居中】，
        它自己就是那个"留白里的圆角块" —— 不再靠 padding 硬挤边缘。
     ⚠️ 为什么用 margin-inline: auto 而不是 align-self: center：
        .gallery-card 是【块级】容器（不是 flex），align-self 不生效；
        块级子元素水平居中就得靠 margin auto ✓
     ⚠️ 限宽对两类卡片都成立、各自都更好看：
        · 图片卡：图最大 440px 宽（原来被拉到整行、contain 两侧留大白）
        · 媒体卡（视频/音乐）：占位块 440×220 居中，四周留白 —— 正是
          "我的作品"里那块 300×200 圆角块的观感 ✓
     ⚠️ 上下 padding 留一点（0.2rem）：原来上下都为 0，占位块紧贴上沿，
        跟左右留白不成比例。 */
  /* ★★ v2.509：上下也要留白（用户："这个图做圆角，不要直接贴边，上边和下边"）
     ------------------------------------------------------------
     ⚠️ v2.508 只解决了左右（限宽居中），上下仍是 0.2rem —— 图紧贴作者行和标签行。
     ★ 现在是【图片自己】带圆角 + 上下内缩，而不是给容器加灰底：
        · .gc-img 用 padding: 0.5rem 0 + box-sizing: border-box
          ⇒ 内容盒高度 = 220 - 16 = 204px，图片在内容盒里居中，
            上下自然各留 8px ✓
        · box-sizing: border-box 是关键：不写的话 padding 会【加在 220 之外】，
          高度变成 236px，卡片反而更高、还是贴边。
     ⚠️ 上下内缩必须给【容器】而不是给 img 的 margin：
        容器是 flex + align-items: center，img 上的上下 margin 会被居中算法
        部分吸收，留白不稳定；容器 padding 是确定值 ✓ */
  padding: 0.5rem 0;
  max-width: 440px;
  margin-inline: auto;
  border-radius: 0.7rem;
  box-sizing: border-box;
}
/* ★★ v2.509：图片本体带圆角 + 【去掉灰底】
   ------------------------------------------------------------
   ⚠️ 那层 #f7f8fc 灰底就是"看起来贴边"的元凶：图片 object-fit:contain
      只占中间一块，灰底却铺满整个通栏容器 ⇒ 视觉上是一个【通栏灰色方块】，
      图片只是浮在中间。用户要的是"图本身是圆角块"（"做圆角，不要直接贴边"）。
   ★ 改成 background: transparent —— 只有图片本体（带圆角）可见，
      四周是卡片自己的白底 ⇒ 真正的"留白里的圆角图" ✓
   ⚠️ object-fit: contain 保留 —— 广场是"看内容"，不能裁图。
      （⚠️ 这里原来有【两条】同名规则，后一条把背景改回灰底、把前一条废掉。
         已合并成这一条，别再分两份写。） */
.square-list .gc-img img { object-fit: contain; background: transparent; border-radius: 0.7rem; }
/* ★ v2.508：窄屏（卡片本身不足 440px + 边距）时放开限宽，
   否则小屏上会白缩一圈。 */
@media (max-width: 560px) {
  .square-list .gc-img { max-width: none; }
}
/* ★ v2.505/v2.508：媒体占位块（视频/音乐）也要圆角 —— 它就是用户看到的那块
   "方角色块"。它不走 <img>，所以上面那条 img 规则管不到它。
   ⚠️ v2.508 后它的外框由 .gc-img 限宽 440px 居中决定，
      自己 width/height: 100% 填满即可（渐变块本身就是那块圆角区域）。 */
.square-list .gc-img.gc-img-media { border-radius: 0.7rem; }

/* 提示词不再截断（MXAI 是完整段落） */
.square-list .gc-prompt {
  -webkit-line-clamp: unset;
  display: block;
  overflow: visible;
}

/* 作者行：现在有头像了，改成 flex 对齐 */
/* ★★★ v2.789：flex-wrap 从 wrap 改成 nowrap —— 用户要求"要显示在同一行"
   ------------------------------------------------------------
   🔴 用户实测（截图）：套图卡片的作者区【折成了两行】，
      头像掉到第二行，看着像"有两个头像"。
   ★ 根因：原来是 flex-wrap: wrap，窄屏（或套图卡那种元素多的行：
      头像 + 用户名 + 已关注 + 「图片」+「套图 6 张」+ 时间 + 未转存）
      一行放不下就自动折行 ⇒ 头像被挤到下一行。
   ★ 修法：
     ① flex-wrap: nowrap —— 强制同一行
     ② 允许收缩（min-width: 0 交给子元素）——
        否则不折行会把整行撑出卡片（比折行更糟）
     ③ 用户名那一项加省略号：宁可把长名字截断（title 里还是全名），
        也不能让它把"已关注/套图角标"挤出屏幕
   ⚠️ 为什么不直接删掉那些角标：那是套图卡片的必要信息（几张一套），
      用户明确要求过要显示。所以是"压缩名字、保住角标"。 */
.square-list .gc-author {
  display: flex; align-items: center; gap: 0.4rem;
  flex-wrap: nowrap;          /* ★ 不折行 */
  min-width: 0;               /* 允许子元素收缩（否则会撑破卡片） */
  margin-bottom: 0.45rem;
}
/* 作者名：可长可短（用户名可能是手机号/英文长名）——不许把别的元素挤走
   ⚠️ v2.789：原本这里只有"可压缩 + 省略号"，而 font-weight / color
      写在文件别处【第二条同名规则】里（已合并进来，别再写第二处）。 */
.square-list .gc-author-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 0 1 auto;             /* 可以被压缩 */
  font-weight: 700;           /* ← 从下面那条合并过来 */
  color: #374151;
}
/* 头像不能被压缩（它是圆，变形就难看） */
.square-list .gc-author .gc-avatar { flex: 0 0 auto; }
/* 关注按钮 / 角标 / 时间：不给压缩，保证信息完整 */
.square-list .gc-author > .gc-kind,
.square-list .gc-author > .gc-time { flex: 0 0 auto; white-space: nowrap; }
/* ★ 关注按钮推到右侧：它原来是紧跟用户名的，窄屏下正是它把行撑到折行。
   推到右边之后，中间那段空白由用户名自己让出来（配合上面的 ellipsis）。
   ⚠️ 用 margin-left:auto 而不是 justify-content:space-between ——
      后者会把「头像和名字」也拆到两端（那不是我们要的）。 */
.square-list .gc-author > [data-follow] { margin-left: auto; }

/* ===========================================================
   ★ 作者行在卡片【最上面】（v2.376，MXAI 形态）
   -----------------------------------------------------------
   ⚠️ 为什么需要这段：作者行原来在 .gc-body 里（.gc-body 自带内边距），
      挪到卡片最上面之后它【不在 .gc-body 里了】——
      不补内边距就会贴着卡片上沿和左右边缘。
   ⚠️ 用 .square-list > .gallery-card > .gc-author 这条【更长的选择器】：
      · 权重 (0,3,0) 高于上面的 .square-list .gc-author (0,2,0)，能盖住它
      · 而且是【新选择器】，不会和上面那条形成重复定义
        （本文件被重复规则静默覆盖过一次，白折腾三轮，所以这里刻意避开）
   ⚠️ 下边距比上面那条小一点：媒体图紧跟着它，留太多会显得散。
   =========================================================== */
.square-list > .gallery-card > .gc-author {
  padding: 0.75rem 0.85rem 0;
  margin-bottom: 0.35rem;
}
/* ⚠️ v2.789：.square-list .gc-author-name 原来【这里有第二条规则】
   （只有 font-weight / color）—— 和上面 v2.789 新增的那条同名同权重 ⇒
   两条都会生效，但以后改样式极容易只改到一条（本项目为此踩过坑，
   见本文件顶部那段"压缩值直接写进各条规则、不要再写一遍覆盖"）。
   ⇒ 已把这两条【合并到上面那一条】里，这里不再重复定义。 */
.square-list .gc-time { color: #9ca3af; font-weight: 400; }
html[data-theme="dark"] .square-list .gc-author-name { color: #dfe3ea; }

/* ★ 头像：图片版和首字母色块版共用 .gc-avatar
   ⚠️ 这个名字加之前查过，CSS 里原先没有 —— 不会产生第二份定义。 */
.gc-avatar {
  width: 30px; height: 30px; flex: 0 0 auto;
  border-radius: 50%; object-fit: cover;
}
.gc-avatar-txt {
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-size: 0.82rem; font-weight: 800; line-height: 1;
  user-select: none;
}
/* ===========================================================
   ★ 生图工作区：整屏固定高度 + 设置区独立滚动 + 底栏固定
   -----------------------------------------------------------
   之前底栏会跟着滚，根因是给卡片用的是 min-height：
     min-height 只是「至少这么高」，内容一多卡片就跟着长高，
     于是内部永远不会出现滚动条，变成整页滚动、底栏跟着走。
   改成 height 固定高度 + overflow:hidden 把高度锁死，
   内部才真正需要滚动，底栏才能钉住。
   =========================================================== */
@media (min-width: 1024px) {
  body[data-page="image"] .page-content > main {
    height: 100%;
    max-width: 1600px !important;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  body[data-page="image"] .tool-card {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;                 /* ★ 锁住高度，内部滚动的前提 */
  }
  /* 工具标签固定，不参与滚动 */
  body[data-page="image"] #tool-tabs { flex: none; }
  /* 当前面板撑满卡片剩余高度，并裁切溢出的内容 */
  body[data-page="image"] .tool-card > .tool-panel:not(.hidden) {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }
  /* 控制面板变窄（参考 MJ，约 380px） */
  body[data-page="image"] .tool-panel {
    grid-template-columns: 380px minmax(0, 1fr) !important;
    min-height: 0;
  }
  body[data-page="image"] .tool-panel > .studio-side {
    overflow: hidden !important;      /* 覆盖早期「整列滚动」的规则 */
    padding-right: 0 !important;
    height: 100%;
    min-height: 0;
  }
}

/* ---------- 控制面板：独立一层，顶部标题 + 中部滚动 + 底部固定 ---------- */
.studio-side-head {
  flex: none;
  padding-bottom: 0.65rem;
  margin-bottom: 0.7rem;
  border-bottom: 1px solid var(--line);
}
.studio-side-head h2 {
  font-size: 1.05rem;
  font-weight: 800;
  margin: 0;
  color: #1f2937;
}
.studio-side-head p {
  font-size: 0.72rem;
  color: #9ca3af;
  margin: 0.15rem 0 0;
  line-height: 1.5;
}
/* ===========================================================
   非图片资产（视频 / 音乐）的占位与播放器
   音乐/视频作品的地址是 .mp3/.mp4，塞进 <img> 会显示破图，
   所以非图片类型统一用图标占位 + 点开播放器。
   =========================================================== */
.media-ph {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  color: #a78bfa;
  background: linear-gradient(135deg, var(--mc-acc-soft) 0%, #ecfeff 100%);
  /* ★ v2.505：占位块自己带圆角 ——
     ⚠️ 视频/音乐卡片在广场里显示的就是这一块（浅紫→浅青渐变）。
        它原来是个【方角矩形、撑满整个媒体区】，和卡片自身的 0.9rem 圆角
        放一起就是"方块怼在圆角卡片边缘"（用户反馈"没有圆角，很难看"）。
     ⚠️ 为什么不只靠父级 .gc-img 的 overflow:hidden 裁：
        老浏览器对"overflow:hidden + 子元素铺满"的圆角裁切有毛边；
        给元素自己加圆角最稳，父级裁切只是双保险。 */
  border-radius: 0.7rem;
}
.media-ph span { font-size: 2.1rem; line-height: 1; }
.media-ph small { font-size: 0.68rem; color: #9ca3af; }
.media-play {
  position: absolute;
  right: 0.6rem;
  bottom: 0.6rem;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: rgba(124, 58, 237, 0.9);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  padding-left: 2px;
  box-shadow: 0 3px 10px rgba(124, 58, 237, 0.35);
}
.gc-img-media { cursor: pointer; }
.gc-kind {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0 0.35rem;
  border-radius: 0.35rem;
  background: var(--mc-acc-line);
  color: var(--mc-acc-ink);
  font-size: 0.66rem;
}

/* 播放器弹窗 */
.media-modal {
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(17, 24, 39, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.media-modal-box {
  width: 100%;
  max-width: 620px;
  background: #fff;
  border-radius: 1.1rem;
  padding: 1rem;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
}
.media-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.7rem;
}
.media-modal-prompt {
  margin-top: 0.7rem;
  font-size: 0.8rem;
  color: #4b5563;
  line-height: 1.6;
  max-height: 7rem;
  overflow-y: auto;
}
/* ===========================================================
   视频 / 音乐工作区：和图片区一致的铺满布局
   =========================================================== */
@media (min-width: 1024px) {
  body[data-page="video"] .page-content > main,
  body[data-page="music"] .page-content > main,
  body[data-page="text"] .page-content > main,
  /* ★ v2.793：voice 补进这条名单。
     ⚠️ 这页也是工作台结构（左栏工具 + 右栏作品），但这套"铺满 + 整页
        高度 + 底部固定"的规则当时漏了它 ⇒ 配音页的布局比别的页脆。
     判据：tools/workbench-layout-probe.mjs 第 ③ 条专门查"名单不许漏页"。 */
  body[data-page="voice"] .page-content > main {
    height: 100%;
    max-width: 1600px !important;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  body[data-page="video"] .tool-card,
  body[data-page="music"] .tool-card,
  body[data-page="text"] .tool-card {
    flex: 1 1 auto;
    min-height: 0 !important;    /* 覆盖早期的 min-height：它会让卡片长高，内部就不滚了 */
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  body[data-page="video"] .tool-card > .tool-panel:not(.hidden),
  body[data-page="music"] .tool-card > .tool-panel:not(.hidden),
  body[data-page="text"] .tool-card > .tool-panel:not(.hidden) {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }
  /* 左侧设置区变窄，右侧结果区尽量大 */
  body[data-page="video"] .tool-panel,
  body[data-page="music"] .tool-panel,
  body[data-page="text"] .tool-panel {
    grid-template-columns: 380px minmax(0, 1fr) !important;
    min-height: 0;
  }
  /* 左列自己滚动 */
  body[data-page="video"] .tool-panel > div:first-child,
  body[data-page="music"] .tool-panel > div:first-child,
  body[data-page="text"] .tool-panel > div:first-child {
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 0.5rem;
  }
  body[data-page="video"] .tool-panel > div:last-child,
  body[data-page="music"] .tool-panel > div:last-child,
  body[data-page="text"] .tool-panel > div:last-child {
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
}
/* 提示词那三个辅助按钮：独占一行，整齐排列（之前挤在标签行里会错位换行） */
.field-label { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.field-label .label-actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  width: 100%;
  margin-top: 0.1rem;
}
/* 多张参考图：缩略图网格 + 单张删除 */
.ref-item {
  position: relative;
  width: 72px;
  height: 72px;
  border-radius: 0.55rem;
  overflow: hidden;
  border: 1px solid var(--line);
  background: #f1f2f7;
}
.ref-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ref-item .ref-del {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 0;
  background: rgba(17, 24, 39, 0.72);
  color: #fff;
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ref-item .ref-del:hover { background: #dc2626; }
.dropzone { display: flex; flex-wrap: wrap; gap: 0.5rem; align-content: flex-start; }
#t2i-drop-hint { width: 100%; }
/* ---------- 画面比例：形状卡片 ---------- */
.ratio-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(62px, 1fr));
  gap: 0.45rem;
}
.ratio-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  padding: 0.5rem 0.2rem 0.4rem;
  border-radius: 0.7rem;
  border: 1.5px solid var(--line);
  background: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}
.ratio-card:hover { border-color: #c084fc; background: #fff; }
.ratio-card.active {
  border-color: var(--mc-acc);
  background: linear-gradient(135deg, rgba(124, 58, 237, 0.09), rgba(6, 182, 212, 0.09));
  box-shadow: 0 3px 12px rgba(124, 58, 237, 0.16);
}
.ratio-card .ratio-shape {
  display: block;
  border-radius: 4px;
  background: #9aa1ad;
  transition: background 0.18s ease;
}
.ratio-card.active .ratio-shape { background: var(--mc-acc); }
.ratio-card .ratio-label { font-size: 0.66rem; color: #6b7280; line-height: 1; }
.ratio-card.active .ratio-label { color: var(--mc-acc-ink); font-weight: 700; }

/* ---------- 自定义尺寸面板 ---------- */
.custom-size {
  margin-top: 0.7rem;
  padding: 0.7rem;
  border-radius: 0.8rem;
  background: #faf9ff;
  border: 1px solid var(--mc-acc-line);
}
.cs-inputs { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.cs-field { display: flex; align-items: center; gap: 0.35rem; flex: 1 1 140px; }
.cs-field label { font-size: 0.72rem; color: #6b7280; white-space: nowrap; }
.cs-field .field { padding: 0.4rem 0.55rem; font-size: 0.82rem; min-width: 0; }
.cs-reset {
  flex: none;
  border: 0;
  background: transparent;
  color: var(--mc-acc);
  font-size: 0.72rem;
  cursor: pointer;
  padding: 0.15rem 0.25rem;
  text-decoration: underline;
}
.cs-info { display: flex; gap: 0.8rem; margin-top: 0.7rem; align-items: flex-start; }
.cs-shape-wrap {
  flex: none;
  width: 88px;
  height: 88px;
  border-radius: 0.6rem;
  background: #fff;
  border: 1px solid var(--mc-acc-line);
  display: flex;
  align-items: center;
  justify-content: center;
}
.cs-shape { display: block; border-radius: 4px; background: var(--mc-acc-line); }
.cs-meta { font-size: 0.74rem; color: #4b5563; line-height: 1.9; }
.cs-meta b { color: var(--mc-acc-ink); }
.cs-meta .cs-note { font-size: 0.68rem; color: #9ca3af; line-height: 1.5; margin-top: 0.15rem; }
/* ===========================================================
   图片编辑页（模板海报 / 一键重绘 / 节日海报）
   与图片创作页同一套布局：整屏高 + 左侧固定底栏 + 右侧铺满
   =========================================================== */
@media (min-width: 1024px) {
  body[data-page="edit"] .page-content > main {
    height: 100%;
    max-width: 1600px !important;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  body[data-page="edit"] .tool-card {
    flex: 1 1 auto;
    min-height: 0 !important;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  body[data-page="edit"] #tool-tabs { flex: none; }
  body[data-page="edit"] .tool-card > .tool-panel:not(.hidden) {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }
  body[data-page="edit"] .tool-panel {
    grid-template-columns: 380px minmax(0, 1fr) !important;
    min-height: 0;
  }
  body[data-page="edit"] .tool-panel > .studio-side {
    overflow: hidden !important;
    padding-right: 0 !important;
    height: 100%;
    min-height: 0;
  }
}
/* 上传区改成 <label for="file">：点击由浏览器原生处理，不再依赖 JS。
   （之前用 div + input.click()，一旦 JS 没绑上就完全点不动） */
label.dropzone { cursor: pointer; }
label.dropzone .ref-del { cursor: pointer; }
/* ===========================================================
   常用尺寸：三列紧凑网格
   -----------------------------------------------------------
   原来一行只放得下 2 个（每个带着 1024×1024 这类说明），
   12 个要占 6 行。改成三列、说明收进 title 悬停提示，
   12 个只占 4 行 —— 省出 2 行高度。
   =========================================================== */
.size-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.35rem;
}
.size-grid .size-chip {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.22rem;
  min-width: 0;
  padding: 0.36rem 0.42rem;
  font-size: 0.7rem;
  border-radius: 0.55rem;
  white-space: nowrap;
  overflow: hidden;
}
.size-grid .size-chip > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* 说明（1024×1024 / 竖屏高清…）在窄卡片里放不下，收进 title 悬停显示 */
.size-grid .size-chip small { display: none; }

@media (max-width: 480px) {
  .size-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* ===========================================================
   AI 店面页：与图片创作页同一套布局
   =========================================================== */
.shop-ref-count { font-size: 0.72rem; color: #9ca3af; font-weight: 500; }

@media (min-width: 1024px) {
  body[data-page="shop"] .page-content > main {
    height: 100%;
    max-width: 1600px !important;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  body[data-page="shop"] .tool-card {
    flex: 1 1 auto;
    min-height: 0 !important;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  body[data-page="shop"] .tool-card > .tool-panel:not(.hidden) {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }
  body[data-page="shop"] .tool-panel {
    grid-template-columns: 400px minmax(0, 1fr) !important;
    min-height: 0;
  }
  body[data-page="shop"] .tool-panel > .studio-side {
    overflow: hidden !important;
    padding-right: 0 !important;
    height: 100%;
    min-height: 0;
  }
}
/* 播放器弹窗里的提示 */
.media-modal-tip {
  margin-top: 0.6rem;
  font-size: 0.72rem;
  color: #9ca3af;
  line-height: 1.6;
}
/* 顶部用户名：个人中心入口（左侧菜单已移除该项） */
.nav-user-link {
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.nav-user-link:hover {
  border-color: #c084fc;
  color: var(--mc-acc-ink);
  background: #faf5ff;
}

/* ===========================================================
   移动端适配增强
   -----------------------------------------------------------
   说明：本站是「移动优先」结构 —— 桌面样式集中在 min-width:1024px
   的媒体查询里，基础样式本就偏窄屏。这一块补的是「手机上依然别扭」
   的那些点：

     · 触控目标偏小，手指点不准
     · 宽表格把整页撑宽，出现左右晃动
     · iOS 上输入框字号 <16px 会触发「聚焦自动放大」
     · 弹窗在小屏上超出可视区，关不掉也点不到
     · 刘海屏 / 底部横条没有留白，顶部内容被遮
     · 长 URL、密钥不分行，把容器撑破
     · 结果区图片在竖屏上过高，看不到按钮

   注意：这里只写 max-width，不改动任何 min-width:1024px 的桌面规则，
   所以桌面端不受影响。
   =========================================================== */

@media (max-width: 768px) {

  /* ---- 1. 不许横向滚动 --------------------------------------
     只要有任何一个元素比屏幕宽，整页就会被撑宽，
     手机上表现为「页面能左右晃、右侧内容被切掉」。
     先兜一层，再逐个修真正溢出的元素。 */
  html, body {
    max-width: 100%;
    overflow-x: hidden;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }

  /* ---- 2. 触控目标 ------------------------------------------
     手指点击热区建议 ≥44px，否则按钮总是点不中。 */
  .btn, button, .nav-item, .tool-tab, .chip {
    min-height: 42px;
  }
  .btn-sm, .chip, .tool-tab, .btn-opt {
    min-height: 34px;
  }
  /* 导航项行高加大，滑动时不容易误触 */
  .nav-item { padding-top: 0.6rem; padding-bottom: 0.6rem; }

  /* ---- 3. iOS 输入框不自动放大 ------------------------------
     iOS Safari 在输入框字号 <16px 时会自动放整页，
     放完之后就再也缩不回去 —— 这是手机上最烦人的体验问题。 */
  input, select, textarea, .field {
    font-size: 16px;
  }

  /* ---- 4. 表格：允许换行 + 可横向滚动 -----------------------
     不改成 display:block（那会让表头和表体列错位），
     而是缩小字号、允许长内容断行；外层容器允许横向滚动。 */
  table { font-size: 0.78rem; }
  th, td {
    padding: 0.5rem 0.55rem;
    white-space: normal;
  }
  td { word-break: break-word; overflow-wrap: anywhere; }
  /* .panel 原本 overflow:hidden，会让宽表格被裁掉，
     改成允许横向滚动（对不含表格的面板无副作用） */
  .panel, .admin-panel, .card {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* ---- 5. 长内容不撑破容器 ---------------------------------- */
  img, video, audio, canvas, iframe, svg {
    max-width: 100%;
    height: auto;
  }
  audio { width: 100%; }
  code, pre, .key, .token, .mono, .break-all {
    word-break: break-all;
    overflow-wrap: anywhere;
  }

  /* ---- 6. 弹窗：小屏上占满可视区 ----------------------------
     这些类名来自各页面的弹窗；匹配不到也不会产生任何副作用。 */
  .modal-mask, .media-modal-mask, .auth-mask {
    padding: 0;
    align-items: stretch;
  }
  .modal, .modal-box, .media-modal, .auth-modal, .auth-box {
    width: 100%;
    max-width: 100%;
    max-height: 100dvh;
    border-radius: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* 弹窗里的图片别超过一屏，否则按钮被挤到看不见 */
  .modal img, .media-modal img { max-height: 42dvh; object-fit: contain; }

  /* ---- 7. 刘海屏 / 底部横条留白 ----------------------------- */
  .topbar {
    padding-top: max(0.55rem, env(safe-area-inset-top));
    padding-left: max(0.8rem, env(safe-area-inset-left));
    padding-right: max(0.8rem, env(safe-area-inset-right));
  }
  #sidebar-root {
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
  }
  body { padding-bottom: env(safe-area-inset-bottom); }

  /* ---- 8. 结果区：竖屏上别把图片撑太高 ----------------------
     图片一高，下面的「下载 / 再生成」就跑到屏幕外了。 */
  .result-stage { min-height: 240px; }
  .result-stage img { max-height: 40dvh; }

  /* ---- 9. 创作页：控制面板与结果区在手机上改为上下排 ---------
     桌面是左右两栏；窄屏若仍是两栏，两边都窄得没法用。 */
  .tool-panel {
    width: 100%;
    gap: 0.85rem;
  }
  .tool-panel > * { min-width: 0; }
  .studio-side {
    /* 面板不再固定高度，让内容自然撑开 */
    height: auto;
    max-height: none;
  }
  .studio-side-scroll {
    /* 手机上取消内部滚动 —— 页面上只有一层滚动条，更好操作 */
    overflow: visible;
    max-height: none;
    flex: 0 0 auto;
  }
  .studio-side-foot {
    position: sticky;
    bottom: 0;
    /* 按钮贴在屏幕底部，滚动时始终可点 */
    background: rgba(255, 255, 255, 0.94);
    backdrop-filter: blur(8px);
    padding-bottom: max(0.6rem, env(safe-area-inset-bottom));
    z-index: 20;
  }
  .tool-panel { padding: 0.75rem; }

  /* ---- 10. 栅格与间距 --------------------------------------- */
  /* 两栏表单在手机上堆成一栏 */
  .grid.sm\:grid-cols-2 { grid-template-columns: 1fr; }
  .stat-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .stat-value { font-size: 1.35rem; }
  .result-stage, .panel { border-radius: 0.9rem; }
}

/* ---- 更窄的机型（iPhone SE 等，≤390px）---------------------- */
@media (max-width: 390px) {
  .studio-side-foot .btn { flex: 1 1 100%; }
  .stat-grid { grid-template-columns: 1fr 1fr; }
  .topbar-title h1 { font-size: 0.88rem; }
  .field-label { font-size: 0.78rem; }
}

/* ---- 触屏设备：去掉 hover 效果（点了会「粘住」）------------- */
@media (hover: none) {
  .nav-item:hover::after { display: none; }
  .btn:hover, .chip:hover, .tool-tab:hover { transform: none; }
}

/* ---- 尊重「减少动态效果」的系统设置 ------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===========================================================
   移动端底部导航（首页 / 灵感 / 作图 / 作品 / 我的）
   -----------------------------------------------------------
   只在窄屏出现；桌面用左侧菜单，不需要它。
   由 common.js 的 renderTabBar() 注入，所以每个页面都自动带上。
   =========================================================== */
.tabbar { display: none; }

@media (max-width: 768px) {
  .tabbar {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* z-index 要低于侧边抽屉与弹窗，否则抽屉打开时会被底栏压住 */
    z-index: 40;
    background: rgba(255, 255, 255, 0.97);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--line);
    /* 全面屏底部横条留白，否则被系统手势条盖住 */
    padding-bottom: env(safe-area-inset-bottom);
    box-shadow: 0 -4px 20px rgba(31, 38, 135, 0.07);
  }
  .tabbar-item {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    padding: 0.42rem 0.15rem 0.38rem;
    text-decoration: none;
    color: #9ca3af;
    font-size: 0.68rem;
    font-weight: 600;
    line-height: 1.1;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.15s;
  }
  .tabbar-icon {
    font-size: 1.22rem;
    line-height: 1;
    transition: transform 0.15s;
  }
  .tabbar-item.is-active { color: var(--mc-acc); }
  .tabbar-item.is-active .tabbar-icon { transform: translateY(-1px); }
  .tabbar-item:active { opacity: 0.6; }

  /* 内容别被底栏压住 */
  body.has-tabbar { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
  /* 生成按钮原本吸在底部，要抬到底栏上面 */
  body.has-tabbar .studio-side-foot { bottom: calc(56px + env(safe-area-inset-bottom)); }
  /* 回到顶部等悬浮按钮同理 */
  body.has-tabbar .back-top,
  body.has-tabbar .fab { bottom: calc(72px + env(safe-area-inset-bottom)); }
}

/* ------------------------------------------------------------
   无子项的一级菜单项：它自己就是页面入口，不是可折叠组。
   ------------------------------------------------------------
   视觉上要和「分组标题」同一层级 —— 左边距、字重、高度都对齐，
   否则它会看起来像个缩进的子项，用户还是会以为点不开。
   ------------------------------------------------------------ */
.nav-group.single .nav-item-top {
  padding-left: 0.85rem;
  font-weight: 700;
  min-height: 2.35rem;
}
.nav-group.single .nav-item-top .nav-icon {
  font-size: 1rem;
}

/* ------------------------------------------------------------
   侧栏底部：版权与备案
   ------------------------------------------------------------
   文案在「后台 → 系统设置 → 站点信息」里填，留空则整块不渲染。
   侧栏收起（图标态）时隐藏 —— 那个宽度放不下几行小字，
   硬显示只会把菜单挤变形。
   ------------------------------------------------------------ */
.sidebar-copyright {
  padding: 0.7rem 0.9rem 0.2rem;
  font-size: 0.66rem;
  line-height: 1.55;
  color: #9ca3af;
  /* ------------------------------------------------------------
     不要 word-break: break-all ——
     它允许在任意字符处断行，会把「星俊纵横文化传媒有限公司」
     硬切成「…有限公」+「司」两行。
     现在改成不换行 + 按内容撑开，宁可溢出侧栏也不断字。
     ------------------------------------------------------------ */
  word-break: keep-all;
  overflow-wrap: normal;
  overflow: visible;
}

/* 每一行都不换行，宽度按内容自定义 */
.sidebar-copyright > div {
  white-space: nowrap;
  width: max-content;
  max-width: 320px;
}

/* 父级不能裁掉溢出的文字 */
.sidebar-footer { overflow: visible; }
.sidebar-copyright .icp { margin-top: 0.15rem; }
.sidebar-shell.collapsed .sidebar-copyright { display: none; }

/* ------------------------------------------------------------
   顶栏头像悬停面板
   ------------------------------------------------------------ */
.nav-user-wrap { position: relative; display: inline-flex; }
.user-pop {
  position: absolute; right: 0; top: calc(100% + 0.5rem); z-index: 200;
  width: min(330px, 92vw); background: #fff;
  border: 1px solid var(--mc-line); border-radius: 1rem;
  box-shadow: 0 18px 48px rgba(15,23,42,.16);
  padding: 0.85rem; text-align: left;
}
.user-pop.hidden { display: none; }
.up-head { display: flex; align-items: center; gap: 0.6rem; padding-bottom: 0.7rem; border-bottom: 1px solid #f1f5f9; }
.up-avatar {
  width: 2.5rem; height: 2.5rem; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(140deg, #a78bfa, var(--mc-acc)); color: #fff;
  font-weight: 800; font-size: 1rem;
}
.up-id { flex: 1 1 auto; min-width: 0; }
.up-name { font-size: 0.9rem; font-weight: 800; color: #1f2937; }
.up-meta { font-size: 0.7rem; color: #9ca3af; margin-top: 0.1rem; }
.up-more { font-size: 0.74rem; color: var(--mc-acc); text-decoration: none; font-weight: 700; white-space: nowrap; }
.up-more:hover { text-decoration: underline; }
.up-sec { padding: 0.7rem 0 0.3rem; }
.up-sec-title { font-size: 0.78rem; font-weight: 800; color: #374151; display: flex; align-items: center; gap: 0.4rem; }
.up-badge { font-size: 0.64rem; font-weight: 700; color: var(--mc-acc); background: var(--mc-acc-soft); padding: 0.1rem 0.4rem; border-radius: 999px; }
/* ===
   v2.725 修正：下面这 5 条【不能删】——
   团队中心页（team.html + team-page.js）也在用 .up-pay-seg / .up-seg，
   那边的 id 是 tm-seg，是【另一个】切换控件。
   我第一版把它们当死规则删了，结果团队中心的切换退化成两个裸按钮。
   教训：删看起来没人用的规则之前要【全站搜类名】，
   不能只看当前文件里有没有引用。 */
.up-pay-seg {
  display: inline-flex; padding: 2px; border-radius: 999px;
  background: #f1f5f9; border: 1px solid #e9ecf3;
}
.up-seg {
  font: inherit; font-size: 0.68rem; font-weight: 700;
  padding: 0.2rem 0.6rem; min-height: 24px;
  border: 0; border-radius: 999px; background: transparent;
  color: #6b7280; cursor: pointer;
}
.up-seg:hover { color: var(--mc-acc); }
.up-seg.on { background: var(--mc-acc); color: #fff; }
.up-seg:disabled { opacity: .6; cursor: default; }
html[data-theme="dark"] .up-pay-seg { background: #232a36; border-color: rgba(255,255,255,.1); }

/* ============================================================
   ★★★ v2.725：账户切换块（个人账户 / 团队账户 合并）
   ------------------------------------------------------------
   🔴 用户原话：「这两个按钮可以合并，切换到团队就显示团队可用积分，
      切换到个人就显示个人可用积分，包括这个账户使用状态。」
   ★ 结构：上排 = 切换（个人账户 / 团队账户）
           下排 = 当前账户的可用积分（跟着切换变）
           底部一行小字 = 现在按哪个池子算
   ⚠️ 切换做成【选项卡】而不是开关：这里是二选一（互斥），
      选项卡的语义对；用开关会让人以为是两个独立开关。
   ⚠️ 大数字沿用原来首张 .up-card 那套紫色大字 ——
      用户已经习惯看到那个大数字就知道是自己的积分。
   ⚠️ 原来那 8 条 .up-pay / .up-seg 规则已删（那个开关被合并掉了）；
      不删就是死规则，以后有人会以为生成时用还有独立的开关。 */
.up-acct { margin-top: 0.5rem; }
.up-acct-seg {
  display: inline-flex; padding: 2px; border-radius: 999px;
  background: #f1f5f9; border: 1px solid #e9ecf3; margin-bottom: 0.45rem;
}
.up-acct-btn {
  font: inherit; font-size: 0.7rem; font-weight: 700;
  padding: 0.22rem 0.7rem; min-height: 26px;
  border: 0; border-radius: 999px; background: transparent;
  color: #6b7280; cursor: pointer;
}
.up-acct-btn:hover { color: var(--mc-acc); }
.up-acct-btn.on { background: var(--mc-acc); color: #fff; }
.up-acct-btn:disabled { opacity: .6; cursor: default; }
.up-acct-card {
  display: flex; flex-direction: column; gap: 0.1rem; cursor: pointer;
  border: 1px solid var(--mc-acc-line); border-radius: 0.7rem;
  padding: 0.6rem 0.8rem;
  background: linear-gradient(135deg, #faf5ff, #eef2ff);
}
.up-acct-card:hover { border-color: var(--mc-acc); }
.up-acct-card b { font-size: 1.15rem; font-weight: 800; color: #5b21b6; }
.up-acct-card span { font-size: 0.68rem; color: #9ca3af; }
.up-acct-hint { font-size: 0.66rem; color: #9ca3af; margin: 0.35rem 0 0; }
html[data-theme="dark"] .up-acct-seg { background: #232a36; border-color: rgba(255,255,255,.09); }
html[data-theme="dark"] .up-acct-card { background: linear-gradient(135deg, #241a35, #1c2130); }
html[data-theme="dark"] .up-acct-card b { color: #c4b5fd; }
.up-note { font-size: 0.7rem; color: #9ca3af; margin: 0.3rem 0 0.5rem; }
.up-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-top: 0.5rem; }
.up-card, .up-soon {
  display: flex; flex-direction: column; gap: 0.15rem; cursor: pointer;
  border: 1px solid var(--mc-line); background: #fbfcfe; border-radius: 0.7rem;
  padding: 0.55rem 0.65rem; text-decoration: none; font-family: inherit; text-align: left;
}
.up-card:hover, .up-soon:hover { border-color: var(--mc-acc-line); background: #faf9ff; }
.up-card b, .up-soon b { font-size: 0.92rem; font-weight: 800; color: #1f2937; }
.up-card span, .up-soon span { font-size: 0.68rem; color: #9ca3af; }
.up-btns { display: flex; gap: 0.5rem; }
.up-btns .up-soon { flex: 1 1 0; align-items: center; }
.up-btns .up-soon::before { content: ""; }
.up-vip {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  margin-top: 0.7rem; padding: 0.6rem 0.7rem; border-radius: 0.75rem;
  background: linear-gradient(100deg, var(--mc-acc), var(--mc-acc-2)); color: #fff;
}
.up-vip b { display: block; font-size: 0.84rem; font-weight: 800; }
.up-vip span { font-size: 0.68rem; opacity: 0.88; }
.up-vip .up-soon { background: #fff; border: 0; padding: 0.35rem 0.9rem; border-radius: 999px; }
.up-vip .up-soon b { color: var(--mc-acc); font-size: 0.78rem; }
.up-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.15rem; margin-top: 0.7rem; padding-top: 0.6rem; border-top: 1px solid #f1f5f9; }
.up-grid a, .up-out {
  display: flex; align-items: center; gap: 0.45rem; cursor: pointer;
  padding: 0.5rem 0.55rem; border-radius: 0.6rem; border: 0; background: transparent;
  font-family: inherit; font-size: 0.79rem; color: #4b5563; text-decoration: none; font-weight: 600;
  text-align: left;
}
.up-grid a:hover, .up-out:hover { background: #f8fafc; color: var(--mc-acc-ink); }
.up-grid i { font-style: normal; font-size: 0.9rem; }
.up-out { color: #dc2626; }
.up-out:hover { background: #fef2f2; color: #dc2626; }

/* ============================================================
   深色模式
   ============================================================
   为什么用「覆盖」而不是「变量」：
     现有样式里颜色是写死的（#fff 出现 32 次、#6b7280 出现 13 次），
     只有 6 个 CSS 变量。改成全变量化要动上百处、风险极大。
     这里用 [data-theme="dark"] 作用域覆盖主要界面，
     不动原样式，浅色模式完全不受影响。

   已知限制：
     少数用「内联 style」写死颜色的地方盖不到
     （内联优先级高于外部样式表）。这些位置后续逐个清理。
   ============================================================ */

html[data-theme="dark"] {
  color-scheme: dark;
}

/* ---------- 页面底色与光斑 ---------- */
html[data-theme="dark"] body {
  background: #0a0c11;
  color: #e8eaed;
}
html[data-theme="dark"] .bg-blobs {
  opacity: 0.16;
  filter: saturate(0.7);
}
html[data-theme="dark"] .main-area { background: transparent; }

/* ---------- 玻璃面：侧栏 / 顶栏 ---------- */
html[data-theme="dark"] .sidebar-inner {
  background: rgba(23, 26, 35, 0.86);
  border-right-color: rgba(255, 255, 255, 0.06);
  box-shadow: 4px 0 24px rgba(0, 0, 0, 0.4);
}
html[data-theme="dark"] .topbar,
html[data-theme="dark"] .glass-strong,
html[data-theme="dark"] .glass {
  background: rgba(23, 26, 35, 0.82) !important;
  border-color: rgba(255, 255, 255, 0.07) !important;
  backdrop-filter: blur(18px);
}
html[data-theme="dark"] .topbar-title h1,
html[data-theme="dark"] #topbar-heading { color: #f3f4f6; }
html[data-theme="dark"] .topbar-title p,
html[data-theme="dark"] #topbar-sub { color: #9ca3af; }

/* ---------- 卡片 / 面板 / 输入框 ---------- */
html[data-theme="dark"] .panel,
html[data-theme="dark"] .stat-card,
html[data-theme="dark"] .card,
html[data-theme="dark"] .mj-box,
html[data-theme="dark"] .home-prompt,
html[data-theme="dark"] .recent-card,
html[data-theme="dark"] .tpl-card,
html[data-theme="dark"] .app-card,
html[data-theme="dark"] .tool-cell,
html[data-theme="dark"] .group-item,
html[data-theme="dark"] .quick-row,
html[data-theme="dark"] .user-pop,
html[data-theme="dark"] .mj-panel,
html[data-theme="dark"] .mj-plus-menu,
html[data-theme="dark"] .auth-modal,
html[data-theme="dark"] .modal-card {
  background: #161a24 !important;
  border-color: rgba(255, 255, 255, 0.07) !important;
  color: #e5e7eb;
}
html[data-theme="dark"] .panel-head,
html[data-theme="dark"] .panel-body,
html[data-theme="dark"] .up-head,
html[data-theme="dark"] .up-grid,
html[data-theme="dark"] .up-sec { border-color: rgba(255, 255, 255, 0.07) !important; }

html[data-theme="dark"] .field,
html[data-theme="dark"] input.field,
html[data-theme="dark"] textarea.field,
html[data-theme="dark"] select.field,
html[data-theme="dark"] .mj-input,
html[data-theme="dark"] .mj-search,
html[data-theme="dark"] .qc-desc {
  background: #0d1016 !important;
  border-color: rgba(255, 255, 255, 0.09) !important;
  color: #e5e7eb !important;
}
html[data-theme="dark"] .field::placeholder,
html[data-theme="dark"] .mj-input::placeholder,
html[data-theme="dark"] textarea::placeholder { color: #6b7280 !important; }

/* ---------- 表格 ---------- */
html[data-theme="dark"] .data-table th {
  background: #1c2029 !important;
  color: #9ca3af !important;
  border-color: rgba(255, 255, 255, 0.07) !important;
}
html[data-theme="dark"] .data-table td {
  border-color: rgba(255, 255, 255, 0.05) !important;
  color: #d1d5db;
}
html[data-theme="dark"] .data-table tbody tr:hover { background: rgba(255, 255, 255, 0.03) !important; }

/* ---------- 侧栏菜单项 ---------- */
html[data-theme="dark"] .nav-item { color: #cbd5e1; }
html[data-theme="dark"] .nav-item:hover { background: rgba(255, 255, 255, 0.05); }
html[data-theme="dark"] .nav-item.active {
  background: linear-gradient(96deg, var(--mc-acc), var(--mc-acc-ink));
  color: #fff;
}
html[data-theme="dark"] .nav-group-title { color: #e5e7eb; }
html[data-theme="dark"] .sidebar-copyright { color: #6b7280; }

/* ---------- 通用文字 ---------- */
html[data-theme="dark"] h1,
html[data-theme="dark"] h2,
html[data-theme="dark"] h3 { color: #f3f4f6; }
html[data-theme="dark"] .field-label { color: #cbd5e1; }
html[data-theme="dark"] .form-row-note,
html[data-theme="dark"] .empty-state,
html[data-theme="dark"] .muted { color: #9ca3af !important; }

/* ---------- 按钮 ---------- */
html[data-theme="dark"] .btn-ghost {
  background: rgba(255, 255, 255, 0.05) !important;
  border-color: rgba(255, 255, 255, 0.1) !important;
  color: #e5e7eb !important;
}
html[data-theme="dark"] .btn-ghost:hover { background: rgba(255, 255, 255, 0.1) !important; }
html[data-theme="dark"] .chip {
  background: rgba(255, 255, 255, 0.06) !important;
  border-color: rgba(255, 255, 255, 0.09) !important;
  color: #e5e7eb !important;
}

/* ---------- 首页 hero ---------- */
html[data-theme="dark"] .mj-tabs { background: #1c2029; }
html[data-theme="dark"] .mj-tab { color: #9ca3af; }
html[data-theme="dark"] .mj-tab.on { background: #2a2f3a; color: #c4b5fd; box-shadow: none; }
html[data-theme="dark"] .mj-item:hover { background: rgba(255, 255, 255, 0.04); }
html[data-theme="dark"] .mj-item.on { background: rgba(124, 58, 237, 0.18); }
html[data-theme="dark"] .mj-item .nm { color: #e5e7eb; }
html[data-theme="dark"] .mj-mchip { background: #1c2029; border-color: rgba(255,255,255,.08); color: #cbd5e1; }
html[data-theme="dark"] .mj-mchip.on { background: rgba(124,58,237,.2); border-color: var(--mc-acc); color: #c4b5fd; }

/* ---------- 主题开关按钮 ---------- */
.theme-btn {
  width: 2.1rem; height: 2.1rem; border-radius: 50%; cursor: pointer;
  border: 1px solid rgba(229, 231, 235, 0.9); background: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.95rem; line-height: 1; font-family: inherit;
  transition: transform 0.18s, background 0.18s;
}
.theme-btn:hover { transform: scale(1.08); }
html[data-theme="dark"] .theme-btn {
  background: #1c2029; border-color: rgba(255, 255, 255, 0.12); color: #fbbf24;
}

/* ⚠️ v2.702：这里原来是 `.up-checkin-row` 的样式。
   那个类【DOM 里已经没有元素用】了（签到卡实际用的是 .up-inv-row，
   和邀请卡共用一行样式）—— 留着是死规则，删掉。
   ⚠️ 判断依据：全项目搜 up-checkin-row，只有这一处定义、没有任何使用。 */
.up-btn-primary {
  flex: 0 0 auto; cursor: pointer; font-family: inherit;
  border: 0; border-radius: 999px; padding: 0.35rem 1rem;
  background: linear-gradient(100deg, var(--mc-acc), var(--mc-acc-2)); color: #fff;
  font-size: 0.78rem; font-weight: 700;
  transition: transform 0.16s, opacity 0.16s;
}
.up-btn-primary:hover { transform: scale(1.04); }
.up-btn-primary.done,
.up-btn-primary:disabled {
  background: #e5e7eb; color: #9ca3af; cursor: default; transform: none;
}
html[data-theme="dark"] .up-btn-primary.done,
html[data-theme="dark"] .up-btn-primary:disabled { background: #2a2f3a; color: #6b7280; }

/* ============================================================
   深色模式 · 文字可读性修补
   ============================================================
   浅色模式里大量使用 #6b7280 / #9ca3af 这类中灰，
   它们在白底上合适，但直接留在深色底上几乎看不见。
   这里按「同层级、提亮一档」的原则统一替换。
   ============================================================ */
html[data-theme="dark"] { --ink: #e8eaed; --ink-soft: #b6bcc8; --line: rgba(255,255,255,0.1); }

html[data-theme="dark"] .form-row-note,
html[data-theme="dark"] .up-note,
html[data-theme="dark"] .up-meta,
html[data-theme="dark"] .up-card span,
html[data-theme="dark"] .up-soon span,
html[data-theme="dark"] .recent-card .cap,
html[data-theme="dark"] .mj-sub,
html[data-theme="dark"] .home-prompt-foot .hint,
html[data-theme="dark"] .tpl-name,
html[data-theme="dark"] .app-desc,
html[data-theme="dark"] .sec-head .more,
html[data-theme="dark"] .data-table .muted,
html[data-theme="dark"] small,
html[data-theme="dark"] .text-muted {
  color: #a8b0bf !important;
}

/* 内联写的深灰（很多面板用 style="color:#6b7280"）在深色下会糊掉，
   这里用属性选择器兜住最常见的几种写法。 */
html[data-theme="dark"] [style*="color:#6b7280"],
html[data-theme="dark"] [style*="color: #6b7280"],
html[data-theme="dark"] [style*="color:#9ca3af"],
html[data-theme="dark"] [style*="color: #9ca3af"] {
  color: #a8b0bf !important;
}
html[data-theme="dark"] [style*="color:#4b5563"],
html[data-theme="dark"] [style*="color: #4b5563"],
html[data-theme="dark"] [style*="color:#374151"],
html[data-theme="dark"] [style*="color: #374151"],
html[data-theme="dark"] [style*="color:#111827"],
html[data-theme="dark"] [style*="color: #111827"] {
  color: #e8eaed !important;
}
html[data-theme="dark"] [style*="background:#fff"],
html[data-theme="dark"] [style*="background: #fff"],
html[data-theme="dark"] [style*="background:#ffffff"],
html[data-theme="dark"] [style*="background:white"],
html[data-theme="dark"] [style*="background: white"],
html[data-theme="dark"] [style*="background:#f8fafc"],
html[data-theme="dark"] [style*="background: #f8fafc"],
html[data-theme="dark"] [style*="background:#f8f9fc"],
html[data-theme="dark"] [style*="background:#fbfcfe"],
html[data-theme="dark"] [style*="background:#f1f5f9"] {
  background: #1a1f2a !important;
}
html[data-theme="dark"] [style*="border:1px solid var(--mc-line)"],
html[data-theme="dark"] [style*="border:1px solid #f1f5f9"],
html[data-theme="dark"] [style*="border-color:#fecaca"] {
  border-color: rgba(255,255,255,0.1) !important;
}

/* ============================================================
   深色 · 通用可读性网（第二批）
   ============================================================
   第一版只覆盖了 .panel / .card / .field 这类「标准容器」，
   但各页面还有自己的类 —— 光生图页就有 82 个 ——
   漏掉的地方在深色下就是一片灰糊，看着像坏了。

   这一层不追求精确匹配，而是按「元素 + 语义」广泛铺开：
   宁可覆盖多一点，也不要漏。后加 !important 是因为
   很多地方的原样式也带 !important 或用内联写死。
   ============================================================ */

/* ---------- 标题与字段名：提亮到接近正文 ---------- */
html[data-theme="dark"] .studio-side-head,
html[data-theme="dark"] .tool-panel h1,
html[data-theme="dark"] .tool-panel h2,
html[data-theme="dark"] .tool-panel h3,
html[data-theme="dark"] .tool-panel h4,
html[data-theme="dark"] .field-label,
html[data-theme="dark"] .tool-tab,
html[data-theme="dark"] .cs-field > label,
html[data-theme="dark"] label { color: #dfe3ea !important; }

/* ---------- 说明 / 提示类文字 ---------- */
html[data-theme="dark"] .field-note,
html[data-theme="dark"] .cs-note,
html[data-theme="dark"] .form-row-note,
html[data-theme="dark"] .hint,
html[data-theme="dark"] .tool-panel p,
html[data-theme="dark"] .tool-card p { color: #9aa3b2 !important; }

/* ---------- 卡片类容器 ---------- */
html[data-theme="dark"] .tool-card,
html[data-theme="dark"] .card-glow,
html[data-theme="dark"] .adv-box,
html[data-theme="dark"] .cs-field,
html[data-theme="dark"] .tool-panel,
html[data-theme="dark"] .studio-side,
html[data-theme="dark"] .stage-panel {
  background: #161a24 !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
}
html[data-theme="dark"] .model-cards > *,
html[data-theme="dark"] .ratio-cards > *,
html[data-theme="dark"] .chip-row > * {
  background: #1b2029 !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
  color: #dfe3ea !important;
}
/* 选中的卡片反过来：亮紫底白字 */
html[data-theme="dark"] .model-cards > .on,
html[data-theme="dark"] .model-cards > .active,
html[data-theme="dark"] .ratio-cards > .on,
html[data-theme="dark"] .ratio-cards > .active {
  background: linear-gradient(120deg, var(--mc-acc-ink), var(--mc-acc)) !important;
  border-color: #8b5cf6 !important;
  color: #fff !important;
}

/* ---------- 输入控件：一律深底浅字 ---------- */
html[data-theme="dark"] input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]),
html[data-theme="dark"] textarea,
html[data-theme="dark"] select,
html[data-theme="dark"] .cs-inputs,
html[data-theme="dark"] .field {
  background: #0d1016 !important;
  color: #e8eaed !important;
  border-color: rgba(255, 255, 255, 0.1) !important;
}
html[data-theme="dark"] input::placeholder,
html[data-theme="dark"] textarea::placeholder { color: #6f7889 !important; }

/* ---------- 标签 / 选项按钮 ---------- */
html[data-theme="dark"] .tool-tab,
html[data-theme="dark"] .stage-tabs button,
html[data-theme="dark"] .btn-opt,
html[data-theme="dark"] .btn-clear-prompt {
  background: rgba(255, 255, 255, 0.05) !important;
  border-color: rgba(255, 255, 255, 0.1) !important;
  color: #c3cad6 !important;
}
/* 未选中的 tab 不能糊成一团 */
html[data-theme="dark"] .stage-tabs button:not(.on):not(.active),
html[data-theme="dark"] .tool-tab:not(.on):not(.active),
html[data-theme="dark"] .btn-opt:not(.on):not(.active) {
  background: transparent !important;
  color: #c3cad6 !important;
}
html[data-theme="dark"] .stage-tabs button.on,
html[data-theme="dark"] .stage-tabs button.active,
html[data-theme="dark"] .tool-tab.on,
html[data-theme="dark"] .tool-tab.active,
html[data-theme="dark"] .btn-opt.on,
html[data-theme="dark"] .btn-opt.active {
  color: #fff !important;
}

/* ---------- 分隔线 / 滚动条 ---------- */
html[data-theme="dark"] hr,
html[data-theme="dark"] .divider { border-color: rgba(255, 255, 255, 0.08) !important; }
html[data-theme="dark"] ::-webkit-scrollbar { width: 10px; height: 10px; }
html[data-theme="dark"] ::-webkit-scrollbar-track { background: #0d1016; }
html[data-theme="dark"] ::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.14); border-radius: 6px;
}
html[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.24); }

/* ---------- 内联浅色背景兜底（更宽的一批）---------- */
html[data-theme="dark"] [style*="background:#f3f4f6"],
html[data-theme="dark"] [style*="background: #f3f4f6"],
html[data-theme="dark"] [style*="background:#e5e7eb"],
html[data-theme="dark"] [style*="background:#f9fafb"],
html[data-theme="dark"] [style*="background:#fafafa"],
html[data-theme="dark"] [style*="background:#eee"],
html[data-theme="dark"] [style*="background:rgb(255"],
html[data-theme="dark"] [style*="background: rgb(255"] {
  background: #1b2029 !important;
}

/* ============================================================
   视频页 · 平台与版本选择（两级）
   ============================================================
   第一级「平台」用下拉列表，第二级「版本」用卡片网格 ——
   版本带说明和角标，做成卡片比塞进下拉里好读得多。
   ============================================================ */
.vp-select {
  display: flex; align-items: center; gap: 0.7rem; cursor: pointer;
  background: #fff; border: 1px solid #e5e7eb; border-radius: 0.85rem;
  padding: 0.7rem 0.9rem; transition: border-color 0.16s, box-shadow 0.16s;
}
.vp-select:hover { border-color: #c4b5fd; box-shadow: 0 2px 10px rgba(124,58,237,.08); }
.vp-ico { font-size: 1.3rem; flex: 0 0 auto; line-height: 1; }
.vp-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.vp-txt b { font-size: 0.88rem; font-weight: 800; color: #1f2937; }
.vp-txt i { font-style: normal; font-size: 0.72rem; color: #9ca3af; }
.vp-arrow { flex: 0 0 auto; color: #9ca3af; font-size: 0.8rem; transition: transform 0.18s; }
.vp-select.open .vp-arrow { transform: rotate(180deg); }

.vp-list {
  margin-top: 0.4rem; background: #fff;
  border: 1px solid var(--mc-line); border-radius: 0.85rem;
  box-shadow: 0 12px 32px rgba(15,23,42,.10);
  max-height: 320px; overflow-y: auto; padding: 0.3rem;
}
.vp-plat {
  display: flex; align-items: center; gap: 0.6rem; cursor: pointer;
  padding: 0.6rem 0.7rem; border-radius: 0.7rem; transition: background 0.14s;
}
.vp-plat:hover { background: #f8fafc; }
.vp-plat.on { background: var(--mc-acc-soft); }
.vp-plat .vp-ico { font-size: 1.15rem; }
.vp-plat .vp-txt b { font-size: 0.84rem; }
.vp-plat .vp-ck { color: var(--mc-acc); font-weight: 900; flex: 0 0 auto; }

.vp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 0.6rem; }
.vp-card {
  cursor: pointer; text-align: left; font-family: inherit;
  background: #fff; border: 1.5px solid #e5e7eb; border-radius: 0.85rem;
  padding: 0.7rem 0.8rem; position: relative;
  transition: border-color 0.16s, box-shadow 0.16s, transform 0.16s;
}
.vp-card:hover { border-color: #c4b5fd; transform: translateY(-1px); }
.vp-card.on {
  border-color: var(--mc-acc); background: var(--mc-acc-soft);
  box-shadow: 0 0 0 3px rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.12);
}
.vp-card b { display: block; font-size: 0.86rem; font-weight: 800; color: #1f2937; }
.vp-card i { display: block; font-style: normal; font-size: 0.72rem; color: #9ca3af; margin-top: 0.15rem; line-height: 1.5; }
.vp-badge {
  position: absolute; top: -0.45rem; right: 0.6rem;
  font-size: 0.62rem; font-weight: 800; color: #fff;
  background: linear-gradient(96deg, #f59e0b, #ef4444);
  padding: 0.06rem 0.42rem; border-radius: 999px;
}
.vp-empty { font-size: 0.8rem; color: #9ca3af; padding: 0.6rem 0; }

html[data-theme="dark"] .vp-select,
html[data-theme="dark"] .vp-list,
html[data-theme="dark"] .vp-card { background: #161a24; border-color: rgba(255,255,255,.09); }
html[data-theme="dark"] .vp-txt b,
html[data-theme="dark"] .vp-card b { color: #e8eaed; }
html[data-theme="dark"] .vp-plat:hover { background: rgba(255,255,255,.04); }
html[data-theme="dark"] .vp-plat.on { background: rgba(124,58,237,.18); }
html[data-theme="dark"] .vp-card.on { background: rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.14); border-color: var(--mc-acc); }

/* ============================================================
   半透明白底的组件 · 深色批量修复
   ============================================================
   这些组件原本是「半透明白底 + var(--ink-soft) 文字」。
   深色模式下 --ink-soft 被提亮，背景却还是白的，
   结果浅底浅字、完全看不见。

   这里统一把它们的底换成深色卡片色，文字提到正文亮度。
   ★ 以后新增同类组件，只要背景沿用同一种写法，
     重跑 tools/_pillfix.mjs 就会自动把它纳入覆盖。
   ============================================================ */
html[data-theme="dark"] .btn-ghost,
html[data-theme="dark"] 
.cs-shape-wrap,
html[data-theme="dark"] 
.drawer,
html[data-theme="dark"] 
.gallery-card,
html[data-theme="dark"] 
.glass-strong,
html[data-theme="dark"] 
.media-modal-box,
html[data-theme="dark"] 
.modal-box,
html[data-theme="dark"] 
.model-card,
html[data-theme="dark"] 
.ratio-card,
html[data-theme="dark"] 
.stat-card,
html[data-theme="dark"] 
.studio-side-foot,
html[data-theme="dark"] 
.user-pop {
  background: #1b2029 !important;
  border-color: rgba(255, 255, 255, 0.1) !important;
  color: #dfe3ea !important;
}
/* 选中态：深色下要比未选中更亮，否则看不出选了哪个 */
html[data-theme="dark"] .btn-ghost.active,
html[data-theme="dark"] 
.cs-shape-wrap.active,
html[data-theme="dark"] 
.drawer.active,
html[data-theme="dark"] 
.gallery-card.active,
html[data-theme="dark"] 
.glass-strong.active,
html[data-theme="dark"] 
.media-modal-box.active,
html[data-theme="dark"] 
.modal-box.active,
html[data-theme="dark"] 
.model-card.active,
html[data-theme="dark"] 
.ratio-card.active,
html[data-theme="dark"] 
.stat-card.active,
html[data-theme="dark"] 
.studio-side-foot.active,
html[data-theme="dark"] 
.user-pop.active {
  background: rgba(124, 58, 237, 0.22) !important;
  border-color: var(--mc-acc) !important;
  color: #ffffff !important;
}

/* ============================================================
   药丸类组件 · 手动补齐
   ============================================================
   上面那批是脚本扫出来的；这几个因为 CSS 规则配对的问题漏掉了，
   手工列出来。它们的共同点：半透明白底 + var(--ink-soft) 文字，
   深色下会变成浅底浅字。
   ★ 以后发现新的「在深色下看不清」的按钮，把类名加到这里。
   ============================================================ */
html[data-theme="dark"] .style-chip,
html[data-theme="dark"] .size-chip,
html[data-theme="dark"] .chip,
html[data-theme="dark"] .qc-tag,
html[data-theme="dark"] .qc-chip,
html[data-theme="dark"] .tpl-tab,
html[data-theme="dark"] .tpl-card,
html[data-theme="dark"] .tab,
html[data-theme="dark"] .tab-btn,
html[data-theme="dark"] .option-chip,
html[data-theme="dark"] .mode-chip,
html[data-theme="dark"] .duration-chip,
html[data-theme="dark"] .ratio-chip,
html[data-theme="dark"] .quality-chip {
  background: #1b2029 !important;
  border-color: rgba(255, 255, 255, 0.1) !important;
  color: #dfe3ea !important;
}
html[data-theme="dark"] .style-chip.active,
html[data-theme="dark"] .size-chip.active,
html[data-theme="dark"] .chip.active,
html[data-theme="dark"] .qc-tag.on,
html[data-theme="dark"] .qc-chip.on,
html[data-theme="dark"] .tpl-tab.on {
  background: rgba(124, 58, 237, 0.25) !important;
  border-color: var(--mc-acc) !important;
  color: #ffffff !important;
}
/* 虚线边的药丸（style-chip 原本是 dashed）在深色下要看得见边 */
html[data-theme="dark"] .style-chip { border-style: dashed; }

/* 生图数量那一排：选中态必须明显 */
html[data-theme="dark"] .chip.on,
html[data-theme="dark"] .chip.active {
  background: linear-gradient(100deg, var(--mc-acc), var(--mc-acc-2)) !important;
  color: #fff !important;
}

/* ============================================================
   提示词框（Prompt Box）· 通用组件（MJ 形态）
   ============================================================
   排布：
     顶行：[缩略图…] [+]                    🖼 1/6
     中间：提示词文本
     底行：[✨AI优化][🎲换灵感]      25/16000  清空

   ★ 可复用：其他页面按下面结构套类名即可，样式不用重写。
       <div class="pb-wrap">
         <div class="pb-top">
           <div class="pb-thumbs" id="xxx-drop" data-refs-drop="键"></div>
           <label class="pb-plus" for="文件input的id">+</label>
           <input type="file" id="文件input的id" class="hidden"
                  data-refs-store="键" data-refs-max="N">
           <span class="pb-count" data-refs-count="键">🖼 0/N</span>
         </div>
         <textarea class="field pb-input" id="提示词input的id"></textarea>
         <div class="pb-foot">
           <div class="pb-tools">…工具按钮…</div>
           <div class="pb-right"><span class="pb-len">0/16000</span>…清空…</div>
         </div>
       </div>
   ============================================================ */
.pb-wrap {
  border: 1px solid #e5e7eb; border-radius: 0.9rem; background: #fff;
  padding: 0.5rem 0.6rem 0.45rem; transition: border-color 0.16s, box-shadow 0.16s;
}
.pb-wrap:focus-within { border-color: #c4b5fd; box-shadow: 0 0 0 3px rgba(124,58,237,.08); }

/* 顶行：缩略图 + 加号 左对齐，数量右对齐 */
.pb-top { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; min-height: 1.9rem; }
.pb-thumbs { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; }

.pb-plus {
  flex: 0 0 auto; width: 1.9rem; height: 1.9rem; border-radius: 0.55rem; cursor: pointer;
  border: 1.5px dashed #cbb8ff; background: #faf5ff; color: #8b5cf6;
  font-size: 1.05rem; line-height: 1; font-weight: 300;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.16s, border-color 0.16s, transform 0.16s;
}
.pb-plus:hover { background: #f3e8ff; border-color: #a78bfa; transform: scale(1.06); }

.pb-count {
  margin-left: auto; font-size: 0.74rem; color: #9ca3af;
  font-variant-numeric: tabular-nums; pointer-events: none; white-space: nowrap;
}

/* 文本域：去掉自带边框，由 .pb-wrap 统一画框 */
.pb-wrap .pb-input {
  border: 0 !important; box-shadow: none !important; background: transparent !important;
  padding: 0.5rem 0.15rem 0.35rem !important; min-height: 6.5rem; resize: vertical;
  width: 100%; outline: none !important;
}

/* 底行工具条 */
.pb-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem; padding-top: 0.45rem; border-top: 1px solid #f1f3f7;
}
.pb-tools, .pb-right { display: flex; align-items: center; gap: 0.4rem; }
.pb-len { font-size: 0.72rem; color: #b6bcc8; font-variant-numeric: tabular-nums; }
.pb-foot .btn-opt { font-size: 0.76rem; padding: 0.28rem 0.6rem; }

/* 缩略图：小方块，悬停放大预览 */
.pb-wrap .ref-item { position: relative; width: 1.9rem; height: 1.9rem; flex: 0 0 auto; }
.pb-wrap .ref-item img {
  width: 100%; height: 100%; object-fit: cover; border-radius: 0.45rem;
  border: 1px solid #e5e7eb; display: block;
  transition: transform 0.18s, box-shadow 0.18s, border-color 0.18s;
}
.pb-wrap .ref-item:hover img {
  transform: scale(4.2); transform-origin: left bottom;
  box-shadow: 0 14px 36px rgba(15,23,42,.30);
  border-color: #a78bfa; position: relative; z-index: 40; border-radius: 0.5rem;
}
.pb-wrap .ref-item .ref-del {
  position: absolute; top: -0.28rem; right: -0.28rem; z-index: 50;
  width: 1rem; height: 1rem; border-radius: 50%; border: 0;
  background: rgba(15,23,42,.75); color: #fff; cursor: pointer;
  font-size: 0.58rem; line-height: 1; display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 0.14s;
}
.pb-wrap .ref-item:hover .ref-del { opacity: 1; }
.pb-wrap .ref-item .ref-del:hover { background: #dc2626; }

html[data-theme="dark"] .pb-wrap { background: #161a24; border-color: rgba(255,255,255,.09); }
html[data-theme="dark"] .pb-wrap:focus-within { border-color: var(--mc-acc); }
html[data-theme="dark"] .pb-plus { background: #1b2029; border-color: #4c1d95; color: #c4b5fd; }
html[data-theme="dark"] .pb-plus:hover { background: #241b3a; }
html[data-theme="dark"] .pb-count { color: #6b7280; }
html[data-theme="dark"] .pb-foot { border-top-color: rgba(255,255,255,.07); }
html[data-theme="dark"] .pb-len { color: #6b7280; }
html[data-theme="dark"] .pb-wrap .ref-item img { border-color: rgba(255,255,255,.12); }

/* ============================================================
   表单标签的两种小标记 · 通用
   ============================================================
   .req  必填红星
   .q    问号，悬停出解释（文案写在 data-tip 属性里）

   用法：
     <div class="field-label">
       <span class="req">*</span>生图指令
       <span class="q" data-tip="这里写解释文案">?</span>
     </div>
   ============================================================ */
.field-label .req {
  color: #ef4444; font-weight: 900; margin-right: 0.15rem;
}

.field-label .q {
  position: relative; display: inline-flex;
  align-items: center; justify-content: center;
  width: 0.95rem; height: 0.95rem; margin-left: 0.3rem;
  border-radius: 50%; border: 1px solid #cbd2dd; color: #9ca3af;
  font-size: 0.62rem; font-weight: 700; font-style: normal;
  cursor: help; vertical-align: middle; line-height: 1;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.field-label .q:hover { border-color: #a78bfa; color: var(--mc-acc); background: var(--mc-acc-soft); }

/* 提示气泡
   ★ 用左对齐而不是居中：侧栏只有 ~450px 宽，居中会让气泡左半边
     超出容器，被 .studio-side-scroll 的 overflow 裁掉（踩过一次）。
     左对齐则向右展开，始终落在容器内。 */
.field-label .q::after {
  content: attr(data-tip);
  position: absolute; left: 0; top: calc(100% + 0.45rem);
  display: block; width: 14rem; max-width: 14rem;
  background: #1f2937; color: #f3f4f6;
  font-size: 0.72rem; font-weight: 400; line-height: 1.65;
  padding: 0.45rem 0.65rem; border-radius: 0.5rem;
  white-space: normal; text-align: left;
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.28);
  opacity: 0; pointer-events: none; z-index: 200;
  transform: translateY(-0.15rem);
  transition: opacity 0.16s, transform 0.16s;
}
/* 小三角：对准问号下方 */
.field-label .q::before {
  content: ""; position: absolute; left: 0.3rem; top: calc(100% + 0.16rem);
  border: 0.28rem solid transparent; border-bottom-color: #1f2937;
  opacity: 0; pointer-events: none; z-index: 201;
  transition: opacity 0.16s;
}
.field-label .q:hover::after  { opacity: 1; transform: translateY(0); }
.field-label .q:hover::before { opacity: 1; }

/* 深色模式 */
html[data-theme="dark"] .field-label .q { border-color: rgba(255,255,255,.18); color: #8b93a3; }
html[data-theme="dark"] .field-label .q:hover { border-color: var(--mc-acc); color: #c4b5fd; background: #1b2029; }
html[data-theme="dark"] .field-label .q::after { background: #0d1016; color: #e8eaed; box-shadow: 0 10px 26px rgba(0,0,0,.5); }
html[data-theme="dark"] .field-label .q::before { border-bottom-color: #0d1016; }

/* ============================================================
   提示词框内的上传区
   ============================================================
   视频页的参考图用的是老的 .dropzone（大块虚线框）。
   搬进 .pb-wrap 后要变紧凑，否则会把文本框顶开。
   ============================================================ */
.pb-wrap .dropzone {
  display: flex; align-items: center; justify-content: center;
  min-height: 1.9rem; width: 1.9rem; height: 1.9rem; padding: 0;
  border-radius: 0.55rem; border: 1.5px dashed #e5e7eb; background: #fafbfd;
  overflow: hidden; flex: 0 0 auto;
}
.pb-wrap .dropzone:hover { border-color: #c4b5fd; background: var(--mc-acc-soft); }
.pb-wrap .dropzone > div { display: none; }
.pb-wrap .dropzone img { width: 100%; height: 100%; object-fit: cover; }
html[data-theme="dark"] .pb-wrap .dropzone { background: #12161e; border-color: rgba(255,255,255,.1); }

/* ============================================================
   提示词框内的「不参与布局的包装层」
   ============================================================
   有些区块（比如视频页的参考图）在框内需要「自身不占位、
   子元素直接参与 .pb-top 的 flex 排布」，所以要用 display:contents。
   但这个区块又需要能被 .hidden 隐藏 —— 两个 display 会打架。

   写法上必须让 .hidden 的优先级更高（写在后面），否则隐藏会失效。
   ★ 不要用内联 style="display:contents"，那样 .hidden 就管不住它了。
   ============================================================ */
.pb-inline { display: contents; }
.pb-inline.hidden { display: none; }

/* ============================================================
   确认弹窗（uiConfirm）· 替代原生 confirm
   ============================================================ */
.ui-cf-mask {
  position: fixed; inset: 0; z-index: 99999;
  display: flex; align-items: center; justify-content: center;
  background: rgba(15, 23, 42, 0.42);
  backdrop-filter: blur(3px);
  opacity: 0; transition: opacity 0.16s;
  padding: 1rem;
}
.ui-cf-mask.on { opacity: 1; }

.ui-cf-box {
  width: 100%; max-width: 24rem;
  background: #fff; border-radius: 1rem;
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.28);
  transform: translateY(0.6rem) scale(0.97);
  transition: transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.2);
  overflow: hidden;
}
.ui-cf-mask.on .ui-cf-box { transform: translateY(0) scale(1); }

.ui-cf-head {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.95rem 1.1rem 0.5rem;
  font-size: 0.95rem; font-weight: 800; color: #1f2937;
}
.ui-cf-ico { font-size: 1.1rem; line-height: 1; }
.ui-cf-box.danger .ui-cf-head b { color: #b91c1c; }

.ui-cf-body {
  padding: 0 1.1rem 1rem;
  font-size: 0.86rem; line-height: 1.75; color: #4b5563;
  max-height: 46vh; overflow-y: auto;
}
.ui-cf-body > div + div { margin-top: 0.2rem; }

/* 输入模式的字段（替代 window.prompt） */
.ui-cf-field { margin-top: 0.7rem; }
.ui-cf-label {
  display: block; font-size: 0.76rem; font-weight: 700;
  color: #6b7280; margin-bottom: 0.25rem;
}
.ui-cf-input {
  width: 100%; box-sizing: border-box;
  font-family: inherit; font-size: 0.88rem;
  padding: 0.5rem 0.65rem; color: #1f2937; background: #fff;
  border: 1.5px solid #e5e7eb; border-radius: 0.6rem;
  transition: border-color .15s, box-shadow .15s;
}
.ui-cf-input:focus {
  outline: none; border-color: var(--mc-acc-2);
  box-shadow: 0 0 0 3px rgba(168,85,247,.14);
}
html[data-theme="dark"] .ui-cf-label { color: #9ca3af; }
html[data-theme="dark"] .ui-cf-input {
  background: #0d1016; border-color: rgba(255,255,255,.12); color: #e8eaed;
}
html[data-theme="dark"] .ui-cf-input:focus { border-color: var(--mc-acc-2); }

/* ==================================================================
   作品广场（灵感广场）卡片 —— 多列网格，作者导向
   和「我的作品」的整宽列表 .work-row 是两种形态，不要混用。
   ================================================================== */
.gc-prompt-head {
  display: flex; align-items: center; justify-content: space-between;
  margin: 0.5rem 0 0.25rem;
  font-size: 0.72rem; font-weight: 700; color: #6b7280;
}
.gc-copy {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; cursor: pointer;
  font-size: 0.82rem; line-height: 1;
  color: var(--mc-acc); background: rgba(124,58,237,.08);
  border: 1px solid rgba(124,58,237,.18); border-radius: 0.4rem;
  transition: background .15s;
}
.gc-copy:hover { background: rgba(124,58,237,.16); }
html[data-theme="dark"] .gc-prompt-head { color: #9ca3af; }

/* ==================================================================
   作品列表卡片（对齐 MJ 的整宽列表形态）
   取代原来的 .work-card 网格小格。
   ================================================================== */

/* 容器：竖向排列，一行一张 —— 覆盖网格布局 */
.work-list {
  display: flex !important;
  flex-direction: column;
  gap: 1rem;
  grid-template-columns: none !important;
}

.work-row {
  background: #fff;
  border: 1px solid var(--mc-line);
  border-radius: 1rem;
  padding: 0.85rem 1rem 1rem;
  transition: box-shadow .18s, border-color .18s;
}
.work-row:hover { border-color: #e3e7f0; box-shadow: 0 6px 22px rgba(17,24,39,.06); }

/* ① 徽标行 */
.work-row-head {
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.wr-chip {
  font-size: 0.7rem; font-weight: 700;
  padding: 0.16rem 0.5rem; border-radius: 999px;
  color: var(--mc-acc); background: rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.10);
}
.wr-chip-type { color: #2563eb; background: rgba(37,99,235,.1); }
.wr-time { font-size: 0.72rem; color: #9ca3af; }
.wr-id {
  font-size: 0.68rem; color: #b0b6c3;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.work-row-actions { margin-left: auto; display: flex; gap: 0.4rem; flex-wrap: wrap; }

/* 通体小按钮 */
.wr-btn {
  display: inline-flex; align-items: center; gap: 0.22rem;
  font-size: 0.74rem; font-weight: 600; line-height: 1;
  padding: 0.36rem 0.66rem; cursor: pointer;
  color: #4b5563; background: #f6f7fb;
  border: 1px solid #e9ecf3; border-radius: 0.5rem;
  text-decoration: none;
  transition: background .15s, border-color .15s, color .15s;
}
.wr-btn:hover { background: #eef0f7; border-color: #dfe3ee; }
.wr-btn.primary { color: #fff; background: var(--mc-acc); border-color: var(--mc-acc); }
.wr-btn.primary:hover { background: var(--mc-acc-ink); border-color: var(--mc-acc-ink); }
.wr-btn.danger { color: #dc2626; }
.wr-btn.danger:hover { background: #fef2f2; border-color: #fecaca; }

/* ★ 社交操作条（点赞 / 收藏）—— 视觉与 .wr-btn 保持一套语言
   ⚠️ 只有这一份定义。加之前 grep 过：.wr-act / .work-row-social
      在整个 CSS 里都不存在，所以不会出现重复规则互相覆盖
      （v2.338 就是因为重复规则排在后面把修复盖掉，白折腾了三轮）。 */
.work-row-social {
  display: flex; align-items: center; gap: 0.4rem;
  margin-top: 0.5rem;
}
.wr-act {
  display: inline-flex; align-items: center; gap: 0.26rem;
  font-size: 0.74rem; font-weight: 600; line-height: 1;
  padding: 0.34rem 0.6rem; cursor: pointer;
  color: #6b7280; background: #f6f7fb;
  border: 1px solid #e9ecf3; border-radius: 0.5rem;
  transition: background .15s, border-color .15s, color .15s;
  /* 数字变化时不要抖动 */
  font-variant-numeric: tabular-nums;
}
.wr-act:hover { background: #eef0f7; border-color: #dfe3ee; }
.wr-act .wr-act-ico { font-size: 0.86rem; line-height: 1; }
.wr-act .wr-act-n { min-width: 0.9em; text-align: left; }
/* 已点赞：心形变红
   ⚠️⚠️ 必须【同时】匹配 data-act 和 data-sq 两种标记 ——
      · 「我的作品」的卡片用 data-act
      · 「作品广场 / 热门榜单」的卡片用 data-sq
      原先只写了 data-act ⇒ 广场上点赞后【图标会变♥但颜色不变红】
      （图标是 JS 直接换字符，颜色靠这条 CSS）—— 用户看到的就是"没变红"。
   ⚠️ 写成同一个规则里的两个选择器（用逗号），而不是新加一条规则 ——
      避免本文件出现过的那种"重复规则静默覆盖"问题。 */
.wr-act.on[data-act="like"],
.wr-act.on[data-sq="like"] { color: #e11d48; background: #fff1f4; border-color: #fecdd3; }
.wr-act.on[data-act="like"]:hover,
.wr-act.on[data-sq="like"]:hover { background: #ffe4e9; }
/* 已收藏：星形变琥珀（同样两种标记都认） */
.wr-act.on[data-act="fav"],
.wr-act.on[data-sq="fav"] { color: #d97706; background: #fffbeb; border-color: #fde68a; }
.wr-act.on[data-act="fav"]:hover,
.wr-act.on[data-sq="fav"]:hover { background: #fef3c7; }

/* ★ 已不喜欢 / 点踩（v2.390）—— 变灰
   ⚠️ 用 data-dislike 而不是 data-sq —— 这个按钮走 workDislike()，
      不是 workAction()（那两处有详细注释）。
   ⚠️ 灰色而不是红色：点踩不是"喜欢"的强化，是"标记不喜欢"，
      红色会和点赞混在一起看不出区别。
   ⚠️ SVG 图标用 currentColor（写在标记里），所以这里改 color 就够了。 */
.wr-act.on[data-dislike] { color: #6b7280; background: #f3f4f6; border-color: #d1d5db; }
.wr-act.on[data-dislike]:hover { background: #e5e7eb; }
/* ⚠️ 深色主题下那组灰底会显得很亮 —— 跟着换一版 */
html[data-theme="dark"] .wr-act.on[data-dislike] {
  color: #e5e7eb; background: #2a3140; border-color: rgba(255,255,255,.18);
}
html[data-theme="dark"] .wr-act { color: #c3cad6; background: #1b2029; border-color: rgba(255,255,255,.12); }
html[data-theme="dark"] .wr-act:hover { background: #232936; }

/* ===========================================================
   ★ 「更多操作」悬停提示（v2.386）
   -----------------------------------------------------------
   ⚠️ 为什么用 CSS ::after 而不是模板里加一个 span：
      纯 CSS 就不用改 JS 标记 —— 少一处要同步的地方。
   ⚠️ 为什么不用原生的 title 属性：
      那是浏览器自带的提示（灰底、约 1 秒延迟、样式不可控），
      和参考站那种白色圆角气泡不是一回事。
   ⚠️ 只在【悬停】时淡入，并且 pointer-events:none ——
      否则那个气泡会挡住 ⋯ 按钮本身的点击。
   ⚠️ 绝对定位挂在按钮上（不是挂在 .wr-more 上）——
      这样 right:0 是相对按钮对齐的，气泡不会跑到卡片外面。
   ⚠️ 颜色用 8 位十六进制而不是 rgba(...)：
      lint 检查器会把 rgba( 当成"调用了未定义的函数"（踩过一次）。
   =========================================================== */
.wr-more > [data-more] { position: relative; }
.wr-more > [data-more]::after {
  content: '更多操作';
  position: absolute;
  right: 0;
  bottom: calc(100% + .45rem);
  white-space: nowrap;
  padding: .3rem .6rem;
  border-radius: .5rem;
  background: #fff;
  color: #374151;
  font-size: .72rem;
  font-weight: 600;
  line-height: 1.2;
  border: 1px solid #e9ecf3;
  box-shadow: 0 6px 18px #1018281f;
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease;
}
/* 悬停时显示（也覆盖"键盘聚焦"——用 Tab 走到这里也能看到提示） */
.wr-more > [data-more]:hover::after,
.wr-more > [data-more]:focus-visible::after { opacity: 1; }
/* 深色主题：气泡跟着反色，否则白底在深色页面上很刺眼 */
html[data-theme="dark"] .wr-more > [data-more]::after {
  background: #232936; color: #dfe3ea; border-color: rgba(255,255,255,.14);
}

/* ② 描述行 */
.work-row-prompt {
  margin: 0 0 0.55rem; font-size: 0.82rem; line-height: 1.65; color: #4b5563;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* ③ 图片 —— 缩略图尺寸，不要占满整宽
   ★ 参考 MJ：图是"卡片里的一张缩略图"，不是全屏大图。
     原来 width:100% 会让竖版图撑满整个卡片高度，一屏放不下两张，
     翻看时要滚很久。现在限宽 + 限高，一屏能看到好几张。 */
.work-row-img { border-radius: 0.7rem; overflow: hidden; background: #f6f7fb; display: inline-block; max-width: 100%; }

/* 视频 / 音乐：不能塞 <img>（地址是 .mp4/.mp3，会显示破图）。
   用图标占位 + ▶ 播放按钮，和左侧菜单「我的作品」的视觉一致。 */
.work-row-img.is-media {
  position: relative;
  width: 300px; height: 200px;
  display: inline-flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 0.3rem;
  cursor: pointer;
}
.work-row-img.is-media .wr-media-ico { font-size: 2.6rem; line-height: 1; }
.work-row-img.is-media small { font-size: 0.72rem; color: #9ca3af; }
.work-row-img.is-media .wr-media-play {
  position: absolute; right: 0.6rem; bottom: 0.6rem;
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.8rem; color: #fff; background: var(--mc-acc);
  box-shadow: 0 4px 12px rgba(124,58,237,.4);
}
.work-row-img.is-media:hover .wr-media-play { background: var(--mc-acc-ink); }

.work-row-img > img {
  display: block; width: auto; height: auto;
  /* ★ 缩略图尺寸对齐「作品广场」的卡片图（4 列时约 300px 宽）——
     原来是 420px，比广场的卡片明显大一截，两个 tab 之间看着不协调。 */
  max-width: 300px;
  max-height: 300px;
  object-fit: contain;
  cursor: zoom-in;
  border-radius: 0.7rem;
}
/* 窄屏：缩略图跟着容器缩 */
@media (max-width: 720px) {
  .work-row-img > img { max-width: 100%; max-height: 42vh; }
}

/* ==============================================================
   ★ v2.499：套图卡片下面的「缩略图条」（用户选的方案 C）
   --------------------------------------------------------------
   业务：一次生成的整套图在「我的作品」里只占一张卡（封面 + 套图 N 张）。
   光看封面看不出另外几张长什么样，所以封面下面补一行小方块：
   一眼看出"这是 N 张不一样的图"，但又不占地方。

   ⚠️ 用 flex 横排 + 可横向滚动，不用 grid：
      6~12 张在窄屏上也放得下 —— 放不下时横滑，不会把卡片撑高。
   ⚠️ 只作用于「我的作品」的 .work-row（作品广场/热榜是另一种卡片形态，
      它们走 decorateGroupCards 那套「原图 → 输出」对比栏，不受这里影响）。
   ⚠️ 尺寸（58px）是按"一行能放 6 个还不换行"定的：
      卡片内容区约 500px，6 × 58 + 5 × 间隙 ≈ 385px，留有余量。
   ============================================================== */
.work-row-thumbs,
.gc-thumbs {
  display: flex; flex-wrap: nowrap; gap: 0.35rem;
  margin-top: 0.55rem;
  overflow-x: auto;
  padding-bottom: 0.15rem;          /* 给横向滚动条留一点位置 */
  scrollbar-width: thin;
}
.work-row-thumbs:empty,
.gc-thumbs:empty { display: none; margin: 0; }
.work-row-thumbs .wr-thumb,
.gc-thumbs .wr-thumb {
  flex: 0 0 auto;
  width: 58px; height: 58px;
  border-radius: 0.5rem;
  overflow: hidden;
  border: 1px solid #e9ecf3;
  background: #f6f7fb;
  display: block;
  transition: border-color .15s, transform .15s;
  /* ★ v2.506：缩略图从 <a> 改成了 <button>（点它要开弹窗，不是跳页）。
     ⚠️ button 自带浏览器默认样式：内边距、边框、字体、背景色。
        不重置的话小方块会变成"带内边距的凸起按钮"，和原来的观感不一样。
        上面已经给了 border / background / padding 缺一不可 —— padding 必须补 0。 */
  padding: 0;
  cursor: zoom-in;
  font: inherit;
  line-height: 0;
  -webkit-appearance: none;
  appearance: none;
}
.work-row-thumbs .wr-thumb:hover,
.gc-thumbs .wr-thumb:hover {
  border-color: #a78bfa;
  transform: translateY(-1px);
}
.work-row-thumbs .wr-thumb img,
.gc-thumbs .wr-thumb img {
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}

/* ④ 工具行 */
.work-row-tools {
  display: flex; gap: 0.4rem; flex-wrap: wrap;
  margin-top: 0.7rem; padding-top: 0.7rem;
  border-top: 1px dashed var(--mc-line);
}

/* ★ 广场卡片那两个并排按钮（「▷ 图片转视频」「✨ 一键做同款」）——v2.421
   ------------------------------------------------------------
   ⚠️ 为什么必须用类而不是行内样式（原来是行内样式）：
      两个按钮原文案/内边距完全一样，但一个是 <a>、一个是 <button>，
      而手机版全局规则 `.btn, button { min-height: 42px }`
      【只命中 <button>】—— 结果一个 42px、一个 29px，
      并排看就是"两个按钮不一样大"（用户截图反馈）。
      写成同一个类，两边高度就由这一条规则统一决定。
   ⚠️ 只用 min-height（不用固定 height）：文字换行时不会被截断。 */
.sq-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.3rem;
  min-height: 32px; padding: 0.32rem 0.7rem;
  border-radius: 0.55rem; border: 1px solid #e9ecf3; background: #fff;
  color: #4b5563; font-size: 0.76rem; font-weight: 600;
  text-decoration: none; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.sq-btn:hover { background: #f6f7fb; border-color: #dfe3ee; }
html[data-theme="dark"] .sq-btn { background: #1c2130; border-color: rgba(255,255,255,.1); color: #c4cad6; }
html[data-theme="dark"] .sq-btn:hover { background: #232a3b; }

html[data-theme="dark"] .work-row { background: #161a24; border-color: rgba(255,255,255,.08); }
html[data-theme="dark"] .work-row:hover { border-color: rgba(255,255,255,.14); }
html[data-theme="dark"] .work-row-prompt { color: #b6bcc8; }
html[data-theme="dark"] .work-row-img { background: #0d1016; }
html[data-theme="dark"] .work-row-tools { border-top-color: rgba(255,255,255,.08); }
html[data-theme="dark"] .wr-btn { color: #c4cad6; background: #1c2130; border-color: rgba(255,255,255,.1); }
html[data-theme="dark"] .wr-btn:hover { background: #232a3b; }
html[data-theme="dark"] .wr-btn.primary { color: #fff; background: var(--mc-acc); border-color: var(--mc-acc); }
html[data-theme="dark"] .wr-btn.danger { color: #f87171; }
html[data-theme="dark"] .wr-id { color: #6b7280; }

/* 弹窗里的图片（微信二维码等） */
.ui-cf-image { margin-top: 0.7rem; text-align: center; }.ui-cf-image img {
  display: block; margin: 0 auto; max-width: 100%; width: 160px;
  border-radius: 0.6rem; border: 1px solid var(--mc-line); background: #fff;
}
.ui-cf-image > span {
  display: block; margin-top: 0.3rem;
  font-size: 0.72rem; color: #9ca3af;
}
html[data-theme="dark"] .ui-cf-image img { border-color: rgba(255,255,255,.1); }
html[data-theme="dark"] .ui-cf-image > span { color: #6b7280; }

/* ==================================================================
   图片预览 lightbox（对齐 MJ 那种预览窗）
   左侧缩略图 / 中间大图 / 右侧缩放控件 / 底部下载
   ================================================================== */
.img-lb-mask { padding: 0; }

/* ★ 看图器的缩放/旋转/平移（v2.427）
   ------------------------------------------------------------
   ⚠️ transition 只在"按钮缩放/复位"时好看；拖拽时必须关掉，
      否则图片会跟着指针滞后（手感像拖着一条橡皮筋）。
   ⚠️ .fill = 「铺满」：把图拉满舞台并裁掉超出部分（object-fit:cover）。
      原来的默认是"适应"（等比缩到装得下），两者切换用同一个按钮。 */
.img-lb-stage > img { transition: transform .13s ease-out; cursor: grab; touch-action: none; }
.img-lb-stage > img.dragging { transition: none; cursor: grabbing; }
.img-lb-stage > img.fill { width: 100%; height: 100%; object-fit: cover; }
.lb-tool.on { background: var(--mc-acc-line); border-color: #c4b5fd; color: var(--mc-acc-ink); }

.img-lb {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  gap: 0.75rem;
  /* ★ 不要铺满整屏 —— 参考站那个弹窗是个居中的面板，
     四周留出背景（还能看到背后的页面），视觉上轻得多。
     原来 100vw/100vh 顶满，压迫感太强。 */
  width: min(1180px, 94vw);
  height: min(780px, 88vh);
  background: #fff;
  border-radius: 1rem;
  box-shadow: 0 30px 80px rgba(0,0,0,.42);
  padding: 1rem 0.9rem 3.6rem;
  box-sizing: border-box;
  overflow: hidden;
}
html[data-theme="dark"] .img-lb { background: #12161e; }

/* 中间的图 —— 缩放靠 transform，所以容器要能裁剪溢出 */
.img-lb-stage {
  flex: 1 1 auto; min-width: 0; height: 100%;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.img-lb-stage > img {
  max-width: 100%; max-height: 100%;
  border-radius: 0.6rem;
  transition: transform .12s ease-out;
  transform-origin: center center;
  cursor: zoom-in;
}

/* 左右两侧的竖条 */
.img-lb-side {
  flex: 0 0 auto;
  display: flex; flex-direction: column; gap: 0.45rem;
  max-height: 100%; overflow-y: auto;
  padding: 0.3rem;
}
.img-lb-thumbs { width: 104px; }
.img-lb-tools  { width: 58px; align-items: center; }

.img-lb-thumbs .lb-thumb {
  display: block; width: 100%; padding: 0; cursor: pointer;
  background: transparent; border: 2px solid transparent; border-radius: 0.5rem;
  overflow: hidden; line-height: 0;
  transition: border-color .15s, transform .15s;
}
.img-lb-thumbs .lb-thumb img { width: 100%; display: block; border-radius: 0.4rem; }
.img-lb-thumbs .lb-thumb:hover { transform: translateY(-2px); }
.img-lb-thumbs .lb-thumb.on { border-color: var(--mc-acc-2); }

.lb-tool {
  width: 36px; height: 36px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.92rem; cursor: pointer;
  /* 弹窗现在是白底面板，工具按钮要改成浅色系（原来是给深色蒙层配的白色） */
  color: #4b5563; background: #f6f7fb;
  border: 1px solid #e9ecf3; border-radius: 0.55rem;
  transition: background .15s, transform .15s;
}
.lb-tool:hover:not(:disabled) { background: #eef0f7; transform: translateY(-1px); }
.lb-tool:disabled { opacity: .35; cursor: default; }

.lb-zoom {
  font-size: 0.7rem; font-weight: 700; color: #6b7280;
  background: #f6f7fb; border: 1px solid #e9ecf3; border-radius: 0.45rem;
  padding: 0.2rem 0.4rem; min-width: 38px; text-align: center;
}

.lb-close {
  position: absolute; top: 0.75rem; right: 0.75rem; z-index: 2;
  width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
  font-size: 0.92rem; cursor: pointer;
  color: #6b7280; background: #f6f7fb;
  border: 1px solid #e9ecf3; border-radius: 50%;
}
.lb-close:hover { background: #eef0f7; color: #111827; }

/* 底部工具条 */
.img-lb-foot {
  position: absolute; left: 50%; bottom: 0.85rem; transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.35rem 0.6rem;
  background: #f6f7fb;
  border: 1px solid #e9ecf3; border-radius: 999px;
}
.lb-count { font-size: 0.74rem; color: #6b7280; padding: 0 .3rem; }

.lb-prompt {
  position: absolute; left: 0.9rem; right: 0.9rem; bottom: 3.4rem;
  margin: 0;
  font-size: 0.74rem; line-height: 1.6; color: #9ca3af;
  text-align: center;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* 窄屏：把左右两条收起来，只留图和底部条 —— 手机上横排会挤爆 */
@media (max-width: 760px) {
  .img-lb { padding: 0.6rem 0.4rem 4.2rem; gap: 0.3rem; }
  .img-lb-side { display: none; }
  .img-lb-foot { bottom: 2.6rem; }
}

.ui-cf-foot {
  display: flex; gap: 0.5rem; justify-content: flex-end;
  padding: 0.75rem 1.1rem 1rem; background: #fafbfd;
  border-top: 1px solid #f1f3f7;
}
.ui-cf-btn {
  font-family: inherit; font-size: 0.84rem; font-weight: 700;
  padding: 0.5rem 1.15rem; border-radius: 0.6rem; cursor: pointer;
  border: 1px solid transparent; transition: filter 0.15s, background 0.15s, border-color 0.15s;
}
.ui-cf-btn.ghost { background: #fff; border-color: #e5e7eb; color: #4b5563; }
.ui-cf-btn.ghost:hover { background: #f3f4f6; }
.ui-cf-btn.primary {
  background: linear-gradient(96deg, var(--mc-acc), var(--mc-acc-2)); color: #fff;
  box-shadow: 0 4px 14px rgba(124, 58, 237, 0.28);
}
.ui-cf-btn.primary:hover { filter: brightness(1.08); }
.ui-cf-btn.danger {
  background: linear-gradient(96deg, #dc2626, #ef4444); color: #fff;
  box-shadow: 0 4px 14px rgba(220, 38, 38, 0.28);
}
.ui-cf-btn.danger:hover { filter: brightness(1.08); }

html[data-theme="dark"] .ui-cf-mask { background: rgba(0, 0, 0, 0.62); }
html[data-theme="dark"] .ui-cf-box { background: #161a24; box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6); }
html[data-theme="dark"] .ui-cf-head { color: #e8eaed; }
html[data-theme="dark"] .ui-cf-body { color: #b6bcc8; }
html[data-theme="dark"] .ui-cf-foot { background: #12161e; border-top-color: rgba(255,255,255,.07); }
html[data-theme="dark"] .ui-cf-btn.ghost { background: #1b2029; border-color: rgba(255,255,255,.12); color: #cfd6e2; }
html[data-theme="dark"] .ui-cf-btn.ghost:hover { background: #222836; }

/* ============================================================
   通用问号提示
   ============================================================
   上面那套 .field-label .q 只在 .field-label 里生效。
   电商套图（combo.html）的标签不是 .field-label，但它同样需要
   「悬停看解释」—— 所以把 .q 单独抽出来做成通用类。

   用法不变：<span class="q" data-tip="解释文案">?</span>
   ============================================================ */
.q {
  position: relative; display: inline-flex;
  align-items: center; justify-content: center;
  width: 0.95rem; height: 0.95rem; margin-left: 0.28rem;
  border-radius: 50%; border: 1px solid #cbd2dd; color: #9ca3af;
  font-size: 0.62rem; font-weight: 700; font-style: normal;
  cursor: help; vertical-align: middle; line-height: 1; flex: 0 0 auto;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.q:hover { border-color: #a78bfa; color: var(--mc-acc); background: var(--mc-acc-soft); }
.q::after {
  content: attr(data-tip);
  position: absolute; left: 0; top: calc(100% + 0.45rem);
  display: block; width: 14rem; max-width: 14rem;
  background: #1f2937; color: #f3f4f6;
  font-size: 0.72rem; font-weight: 400; line-height: 1.65;
  padding: 0.45rem 0.65rem; border-radius: 0.5rem;
  white-space: normal; text-align: left;
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.28);
  opacity: 0; pointer-events: none; z-index: 200;
  transform: translateY(-0.15rem);
  transition: opacity 0.16s, transform 0.16s;
}
.q::before {
  content: ""; position: absolute; left: 0.3rem; top: calc(100% + 0.16rem);
  border: 0.28rem solid transparent; border-bottom-color: #1f2937;
  opacity: 0; pointer-events: none; z-index: 201;
  transition: opacity 0.16s;
}
.q:hover::after  { opacity: 1; transform: translateY(0); }
.q:hover::before { opacity: 1; }
html[data-theme="dark"] .q { border-color: rgba(255,255,255,.18); color: #8b93a3; }
html[data-theme="dark"] .q:hover { border-color: var(--mc-acc); color: #c4b5fd; background: #1b2029; }
html[data-theme="dark"] .q::after { background: #0d1016; color: #e8eaed; }
html[data-theme="dark"] .q::before { border-bottom-color: #0d1016; }

/* ============================================================
   用户面板 · 会员入口按钮
   ============================================================
   ★ .up-vip 是紫色渐变底，里面的按钮必须用白底紫字才看得见。
     之前这里放的是占位按钮 .up-soon（白底白字），
     结果渲染成一个「看不见的白色椭圆」——就是这个原因。
   ============================================================ */
.up-vip-btn {
  flex: 0 0 auto; cursor: pointer; text-decoration: none; white-space: nowrap;
  border-radius: 999px; padding: 0.35rem 1rem;
  background: #fff; color: var(--mc-acc);
  font-size: 0.78rem; font-weight: 800;
  transition: transform 0.16s, box-shadow 0.16s;
}
.up-vip-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22); color: var(--mc-acc-ink); }

/* 团队账户那两个按钮：在白底面板里，用描边款 */
.up-ghost {
  flex: 1 1 0; text-align: center; text-decoration: none; cursor: pointer;
  border: 1px solid #e5e7eb; border-radius: 0.65rem;
  padding: 0.45rem 0.8rem; background: #fff; color: #4b5563;
  font-size: 0.8rem; font-weight: 700;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.up-ghost:hover { border-color: #c4b5fd; color: var(--mc-acc); background: var(--mc-acc-soft); }

html[data-theme="dark"] .up-ghost {
  background: #1b2029; border-color: rgba(255, 255, 255, 0.12); color: #cfd6e2;
}
html[data-theme="dark"] .up-ghost:hover { border-color: var(--mc-acc); color: #c4b5fd; background: #241b3a; }
html[data-theme="dark"] .up-vip-btn { background: #fff; color: var(--mc-acc-ink); }

/* ============================================================
   ★ 手机版基础规则（全站）—— 手机是【主要使用场景】，不是顺手兼容
   ============================================================
   ⚠️ 项目历史上加了 11 种断点（390 / 480 / 560 / 640×2 / 720 / 760 /
      768×2 / 880 / 1024 / 1200），是历年随手补出来的。
   ⚠️ 这里【不删旧的】—— 一次删掉会静默改变现有布局，而且没法验证
      哪些页面会被影响。
   ★ 规则：新写的统一用下面 3 个断点；以后每轮改一页，就把那页的
     老断点并进来。

        ≤ 640px      手机（★ 主要使用场景）
        641 ~ 1024   平板 / 横屏手机
        > 1024       桌面（现状不动）

   ⚠️ 已经有的、不要再重复做：
      · 底栏的 iPhone 安全区（safe-area / env()）—— style.css L2277 一带
        已经处理过了。
      · ecommerce 的「应用式定高布局」只在 min-width:1281px 生效，
        窄屏本来就走页面滚动，不要去动它。
   ============================================================ */

@media (max-width: 640px) {
  /* ① 触控目标 ≥ 44px
     ⚠️ 这几个小按钮原本 padding 只有 0.15~0.36rem，实际高度约 26px，
        手指点不准（容易误触到相邻按钮）。44px 是 iOS / Android 的通行下限。
     ⚠️ 用 min-height 而不是加 padding —— 改 padding 会让文字的换行位置
        和圆角比例一起变形。 */
  .wr-act,
  .btn-opt,
  .tool-tab,
  .wr-btn,
  .btn-sm { min-height: 44px; }

  /* ② 输入控件的字号 ≥ 16px
     ⚠️ iOS Safari 在聚焦 font-size < 16px 的输入框时会【强制放大整页】，
        用户点一下输入框、页面就跳一下 —— 手机上最烦人的体验问题之一。
     ⚠️ 项目里大量 0.72rem ≈ 11.5px，直接命中这条。
     ⚠️ 排除 checkbox / radio / range / color —— 它们的"字号"没有意义，
        强行给 16px 会把勾选框撑变形。 */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
  textarea,
  select { font-size: 16px; }

  /* ③ 工作台四页：左右两栏 → 上下堆叠
     ⚠️ index.html(图片) / music.html / video.html / shop.html 用的是
        【同一套类名】（tool-panel / studio-side / studio-stage），
        所以这一条能一次覆盖四页 —— 已逐页核对过。
     ★ 顺序：表单在上、作品在下。用户打开页面第一件事是填表单，
        不该先看到别人的作品。
     ⚠️ 用 order 控制顺序，【不改 DOM】—— 一动 DOM，
        initWorksStage / 各页的脚本就找不到元素了。
     ⚠️ 本轮只改"堆叠方向"，不动 .studio-side-scroll 的内部滚动条。
        嵌套滚动（页面一条 + 表单区一条）要在第 2 轮改工作台时
        连着页面结构一起处理，否则改了也没法验证。 */
  .tool-panel { display: flex; flex-direction: column; }
  .tool-panel > .studio-side { order: 1; }
  .tool-panel > .studio-stage { order: 2; }
}

/* ============================================================
   ★ 靓号池（v2.420，后台「用户管理 → 靓号管理」用）
   ------------------------------------------------------------
   池子里可能有上千个号，所以用 flex 换行的"小方块"而不是表格：
   表格一千行没法看，方块直接能扫出哪些还空着（绿=未分配，蓝=已分配）。
   ============================================================ */
.vanity-pool {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  max-height: 320px;
  overflow-y: auto;
  padding: 0.55rem;
  border: 1px solid #e9ecf3;
  border-radius: 0.7rem;
  background: #fbfcfe;
}
.vanity-chip {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.74rem;
  padding: 0.18rem 0.4rem;
  border-radius: 0.4rem;
  border: 1px solid #d1fae5;
  background: #ecfdf5;
  color: #047857;
  cursor: pointer;
}
.vanity-chip:hover { border-color: #6ee7b7; }
.vanity-chip.on {
  border-color: #bfdbfe;
  background: #eff6ff;
  color: #1d4ed8;
}
html[data-theme="dark"] .vanity-pool { background: #12161e; border-color: rgba(255,255,255,.08); }
html[data-theme="dark"] .vanity-chip { background: rgba(16,185,129,.12); border-color: rgba(16,185,129,.3); color: #6ee7b7; }
html[data-theme="dark"] .vanity-chip.on { background: rgba(59,130,246,.14); border-color: rgba(59,130,246,.34); color: #93c5fd; }

/* ============================================================
   ★★ 手机端：作品卡片按钮（v2.421）
   ------------------------------------------------------------
   ⚠️ 用户反馈两件事："两个按钮不一样大" + "四个按钮完全可以放一行"。
      根因：
        · 全局手机规则 `.btn, button { min-height:42px }` 只命中 <button>，
          不命中 <a> ⇒ 同一行里 "↻ 再生成"(button)=42px、
          "✎ 编辑 / ⛶ 裁剪 / ▷ 图片转视频"(a)=23px，又矮又不齐。
        · 四个按钮的自然宽度加起来约 325px，正好卡在 390px 手机的
          卡片内宽（约 330px）边缘 ⇒ 挤出第四行（3+1）。
      做法：工具行【不换行】+ 四个按钮【等分一行】+ 统一高度。
      ⚠️ 用 flex:1 1 0 让它们平分宽度，而不是让文字决定宽度 ——
         这样不同文案（编辑 / 图片转视频）也是等宽，"不一样大"就根治了。
      ⚠️ 只作用于 ≤768px；桌面版保持原样（桌面一行放得下，不需要挤）。
   ============================================================ */
@media (max-width: 768px) {
  .work-row-tools {
    flex-wrap: nowrap;
    gap: 0.3rem;
  }
  .work-row-tools .wr-btn {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    /* ★ 统一高度，并盖掉全局 button 的 42px —— .work-row-tools .wr-btn
       特异性(0,2,0) 高于 `button`(0,0,1)，所以四个按钮高度一致 */
    min-height: 42px;
    padding-left: 0.25rem;
    padding-right: 0.25rem;
    font-size: 0.72rem;
    /* 极窄屏（iPhone SE 320px）放不下时省略，而不是撑破卡片 */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* 广场卡片那两个并排按钮：手机上同样加高到可点，且高度一致 */
  .sq-btn { min-height: 40px; }
}

/* ============================================================
   ★★ 手机适配 · 第 2 轮（v2.417）：把交互控件的【触控热区】补到 ≥44px
   ------------------------------------------------------------
   ⚠️ 为什么这轮做这个（不是排版，而是"点不点得中"）：
      下面这些控件是按【鼠标精度】设计的，在手机上基本点不中：
        · .icon-btn  固定 34×34px —— 批量生成格子上的 放大/下载、
                     登录弹窗的关闭、媒体弹窗的关闭
        · .wr-act    高约 23px（padding .34rem + 12px 字）——
                     广场/热榜那排 点赞 / 点踩 / 收藏 / 分享 / 更多，
                     五个挤一行、每个只有 23px 高
        · .lb-tool   36×36px —— 大图预览里那排工具按钮
        · .gc-copy   复制提示词那个小方钮
      Apple HIG 建议热区 ≥44pt、Material ≥48dp。23px 属于"看着能点、实际点不中"，
      比没有这个按钮还让人恼火。

   ⚠️ 只补【最小尺寸】，不动字号 / 配色 / 间距 / 布局 ——
      视觉上几乎看不出来，只是手指更容易命中。
   ⚠️ .wr-act 只加高不加宽：五个按钮一排，加宽会挤到换行。
   ⚠️ 整块只在 ≤768px 生效 —— 桌面版（用户在用的那套）一个字都不受影响。
   ⚠️ 有行内 width/height 的按钮（如媒体弹窗的 30×30、工作台那三个 44×44）
      行内样式优先级更高，本块不会覆盖它们，符合预期。
   ============================================================ */
@media (max-width: 768px) {
  .icon-btn { width: 44px; height: 44px; font-size: 1.05rem; }

  .wr-act { min-height: 44px; padding-top: 0; padding-bottom: 0; }

  .lb-tool { width: 44px; height: 44px; }

  .gc-copy { min-width: 44px; min-height: 44px; }

  /* 「⋯ 更多」菜单里的项也是按钮（查看大图 / 下载 / 复制描述） */
  .wr-more [data-more-act] { min-height: 44px; }

  /* ★ 后台（admin.html）表单在手机上别挤两列（v2.434）
     ⚠️ .form-grid 原来是 2 列，390px 下每个输入框只剩 ~160px，
        账号/邮箱/价格这类字段输入框被压得看不清自己在打什么。
     ⚠️ 只影响窄屏；桌面后台保持两列（用户在桌面是主力操作）。
     ⚠️ 面板标题行（标题左、按钮右）手机上改成上下堆叠，
        按钮铺满一行 —— 否则"保存设置"会被挤成一条小按钮。 */
  .form-grid { grid-template-columns: 1fr !important; }
  .admin-section-head {
    flex-direction: column;
    align-items: stretch;
    gap: 0.6rem;
  }
  .admin-section-head > div:last-child { display: flex; gap: 0.5rem; }
  .admin-section-head .btn { flex: 1 1 auto; justify-content: center; }
  .topbar-title h1 { font-size: 0.95rem; }
  .topbar-title p { font-size: 0.74rem; }
}

/* ============================================================
   ★★ 套图卡片的「原图 + 输出」对比栏（v2.458）
   ------------------------------------------------------------
   参考站（MXAI）的形态：左边一张原图，右边是本批输出的小图网格。
   ⚠️ 只在 groupCount > 1 的批次卡上出现（占位元素由 JS 渲染时写下）；
      没有原图时左边那格【不渲染】——不留空框，老作品看起来和以前一样。
   ⚠️ 小图用 aspect-ratio: 1 做成正方形缩略图，行高整齐；
      点击走 JS 的捕获委托（进看图器且不触发卡片自己的点击）。
   ============================================================ */
.gc-cmp {
  display: flex;
  gap: 0.7rem;
  align-items: stretch;
  padding: 0.7rem 0.8rem 0;
}
/* ★ 50 / 50（v2.462 用户要求：原图一半、输出一半） */
.gc-cmp-half {
  flex: 1 1 50%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
/* 两边都有的小标题：原图 / 输出 N 张 */
.gc-cmp-label { font-size: 0.72rem; color: #6b7280; font-weight: 700; }
.gc-cmp-label b { color: var(--mc-acc-ink); }
.gc-cmp-none {
  font-size: 0.72rem;
  color: #9ca3af;
  border: 1px dashed #e5e7eb;
  border-radius: 0.5rem;
  padding: 0.8rem;
  text-align: center;
}
/* 原图：铺满自己那一半，且可点击（cursor 提示） */
.gc-cmp-srcimg {
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid #eceef3;
  border-radius: 0.5rem;
  overflow: hidden;
  background: #fff;
  cursor: zoom-in;
  line-height: 0;
}
.gc-cmp-srcimg img { width: 100%; display: block; }
.gc-cmp-src { margin: 0; flex: 0 0 34%; max-width: 220px; }

.gc-cmp-outs { flex: 1 1 auto; min-width: 0; }
.gc-cmp-head { font-size: 0.72rem; color: #6b7280; margin-bottom: 0.35rem; }
.gc-cmp-head b { color: var(--mc-acc-ink); }
.gc-cmp-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.35rem;
}
.gc-cmp-thumb {
  padding: 0;
  line-height: 0;
  cursor: zoom-in;
  background: #fff;
  border: 1px solid #eceef3;
  border-radius: 0.4rem;
  overflow: hidden;
}
.gc-cmp-thumb img {
  width: 100%;
  height: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
}
.gc-cmp-more { font-size: 0.7rem; color: #9ca3af; align-self: center; }

/* ★ 看图器右栏：当前正在浏览的那张要有【明显的选中框】（v2.462 用户要求）
   ⚠️ 原来只有很淡的一点样式，翻到第 N 张时看不出"现在看的是哪张"。
   ⚠️ 同时覆盖 .on / .is-on / .active 三种可能的状态类名 ——
      这些缩略图是两处代码渲染的（AI 作品区 / 原图区），
      类名只要有一种对上就会生效，不会因为改名而失效。 */
.lb-thumb.on,
.lb-thumb.is-on,
.lb-thumb.active {
  border-color: var(--mc-acc-ink) !important;
  box-shadow: 0 0 0 2px rgba(109, 40, 217, 0.4);
  position: relative;
  z-index: 2;
}

/* 手机上：原图在上、输出在下（横向排会被挤成一条） */
@media (max-width: 768px) {
  .gc-cmp { flex-direction: column; }
  .gc-cmp-src { flex: 0 0 auto; width: 100%; max-width: none; }
  .gc-cmp-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ============================================================
   ★★ 电商专区「上传商品图片」→ 方形缩略图网格（v2.460）
   ------------------------------------------------------------
   ⚠️⚠️ v2.507 已把这一整段【作废】—— 原因见下面 v2.507 那段。
      这里原来把 .ec-up 当成"和缩略图并排的 76px 方格"
      （flex + order:2 + width/height 76px + 文字 0.62rem），
      而那套设计在 v2.494 就已经改成"上传区整宽、缩略图在下面"了。
      留着它只会用 #id 权重把新样式全压掉 —— 所以整段删除，
      只保留缩略图(.thumb)自己的格子样式（那段在 v2.507 段里）。
   ⚠️ 这段的 width/height 76px、font-size 0.62rem、order 规则、
      `#blk-upload .ec-up small { display:none }` 全部移除。
   ============================================================ */
/* ★ v2.507：以下到「缩略图格子」之前的旧规则全部删除 ——
   它们属于"上传按钮 = 和缩略图并排的 76px 方格"那套已作废的设计：
     #blk-upload { display:flex; align-items:flex-start; gap; flex-wrap:nowrap }
     #blk-upload .ec-up { order:2; flex:0 0 auto; width:76px; height:76px;
                          padding:.25rem; position:relative; overflow:hidden;
                          display:flex; flex-direction:column; ... line-height:1.15 }
     #blk-upload .ec-up .ec-up-plus { position:static !important; font-size:1.05rem;
                          margin:0 0 .15rem; display:block }
     #blk-upload .ec-up .ec-up-txt { font-size:.62rem; margin:0 !important }
     #blk-upload .ec-up small { display:none }   ← 就是它把格式说明藏了
   ⚠️ 这段留下的 .ec-up-plus { display:block } / font-size 0.62rem 等，
      正是"加号圆圈跑出虚线框、六字被压成两行"的直接原因。
   ★ 现在 .ec-up 的样式【只有两个来源】：
       · ecommerce.html 的 .zone-split-left .ec-up（整宽虚线框，唯一权威）
       · 下面 v2.507 段里那两条"放开旧约束"的兜底
   ============================================================ */

/* 缩略图排成一行格子（跟在正方形按钮后面）
   ⚠️ flex 必须是 0 0 auto（v2.463）：原来写的 1 1 auto 会把这一格【撑满整行】，
      于是上传方格被推到最右边、和缩略图隔着一大段空白（用户截图就是这个）✗ */
#blk-upload #cb-thumbs,
#cb-mthumb {
  display: flex;
  gap: 0.55rem;
  flex: 0 0 auto;
  min-width: 0;
  overflow: visible;
}

/* 缩略图格子：正方形、圆角、悬停放大、右上角 ✕
   ⚠️ overflow 改回 hidden（v2.463）：之前为了让悬停放大不被裁而放开，
      结果图片被外层的尺寸规则撑出格子、盖住下面的内容（用户截图）✗。
      放大是靠【整个格子】transform: scale，格子自己裁剪图片完全不影响放大效果 ✓ */
#blk-upload .thumb,
#cb-mthumb .thumb {
  position: relative;
  flex: 0 0 auto;
  width: 76px;
  height: 76px;
  border: 1px solid #e6e8f0;
  border-radius: 0.6rem;
  background: #fff;
  overflow: hidden;
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}
#blk-upload .thumb img,
#cb-mthumb .thumb img {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: cover;
  display: block;
}
/* ✕ 挪到格子【右上角内侧】—— 放外面会被 overflow:hidden 裁掉 */
#blk-upload .thumb button[data-rm],
#cb-mthumb .thumb button[data-rmmodel] {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 18px;
  height: 18px;
  padding: 0;
  line-height: 16px;
  font-size: 13px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.9);
  background: rgba(239, 68, 68, 0.92);
  color: #fff;
  cursor: pointer;
  z-index: 3;
}
/* 悬停：整格放大成"大图预览"
   ⚠️ 从 2.2 收到 1.35（v2.471，用户反馈"悬停后旁边格子的 ✕ 被挡住"）：
      格子 76px + 间距 8px，放大 1.35 倍 ≈ 103px ⇒ 只多出约 13px，
      【够不到右边的邻居】（右边邻居从 +84px 才开始）⇒ 不会盖住别人的 ✕ ✓。
      2.2 倍会伸出去 90 多像素，把邻居整个盖住、连 ✕ 都点不到 ✗。
   ⚠️ 想更清楚可以悬停后点开大图（弹窗），不要靠加大放大倍数 —— 那必然盖住别人。 */
#blk-upload .thumb:hover,
#cb-mthumb .thumb:hover {
  transform: scale(1.35);
  z-index: 40;
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.3);
}

/* ★★ 对齐修正（v2.466 / v2.507 清理）
   ------------------------------------------------------------
   ⚠️ v2.507：这里原来还压着两条"方格时代"的规则，已改：
     · `#blk-upload .ec-up, .thumb { margin: 0 !important; }`
        —— 那个 !important 会把 ecommerce.html 里 .ec-up 的
        margin-bottom: 0.7rem 也压掉（!important 胜过一切非 important）。
        现在只对 .thumb 归零；.ec-up 的下边距交给它自己的样式表。
     · `#blk-upload #cb-thumbs { height: 76px }`
        —— 写死高度的后果：缩略图换行后仍被钳在 76px，第二行被裁掉。
        改成 height: auto（容器高度由格子决定）。
   ⚠️ .thumb 的 margin 归零要保留：全局 .thumbs/.thumb（图片创作、
      模特图那几处）带了自己的 margin，在电商这一行里会表现为"缩略图
      比上传区低一截"（v2.466 的老问题，别再过回去）。 */
#blk-upload #cb-thumbs {
  align-items: flex-start;
  height: auto;
  margin: 0;
}
#blk-upload .thumb {
  margin: 0;
  box-sizing: border-box;
}
#blk-upload .thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ============================================================
   ★★ 上传区：改成【上传区整宽 + 缩略图另起一行】（v2.507 修正）
   ------------------------------------------------------------
   ⚠️⚠️ 这里原来是（v2.468）「固定 6 列网格：6 张图 + 1 个上传格铺满整行」：
        #blk-upload { display: grid !important; grid-template-columns: repeat(6,…); }
        #blk-upload .ec-up { width: 100% !important; max-width: 110px;
                             aspect-ratio: 1/1; }   ← 把上传区压成 110px 方格

       ★ 但那套设计早就变了：v2.494 起上传区是【整宽的虚线大框】
         （圆形 + 号 + "上传商品图片" + 格式说明），缩略图排在它【下面】。
         HTML 里 #cb-thumbs 本来就写在 </label> 之后 ⇒ 天然就是另一行。

       ★ 所以上面那 6 列网格是【遗留的死规则】，必须删掉，否则：
         · .ec-up 被压成 110×110 的方格，但内容仍是"圆形+两行文字"⇒
           加号圆圈被挤到格子外，盖住下面「核心卖点」标签
         · #blk-upload .ec-up small { display:none } 把格式说明藏掉
         · 那几条都带 !important / #id 权重，前端 .zone-split-left .ec-up
           写的整宽样式【全被压掉】—— 表现就是"改了 5 轮都没反应"

   ★ 现在的结构（和 HTML 一致）：
        #blk-upload         → 纵向 flex：第一行上传区，第二行缩略图
        .ec-up              → 整宽虚线框（样式在 ecommerce.html 里）
        #cb-thumbs          → 自己的 6 列网格（最多 6 张，一行）
   ⚠️ #cb-thumbs 不再用 display:contents —— 它是独立容器，不是父网格的格子。
   ⚠️ 删掉的是"把 ec-up 当格子"的那套；缩略图 76×76 / 悬停放大 / ✕ 全部保留。
   ============================================================ */
#blk-upload {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.55rem;
  /* ⚠️⚠️ v2.530 修：原来是 min-height: 0 —— 那是【内容被盖住的元凶】。
     min-height:0 让容器可以被收缩到 0 高度，于是：
       容器 h=0、子元素 h=76 溢出到容器外 ⇒ 下面的「核心卖点」按
       "上面只占 0px" 排版，正好压住溢出的上传格（用户截图 + #diag 实测）。
     ★ 改成内容高度下限 76px（= 上传格/缩略图高度），容器就把子元素算进布局了。
     ⚠️ 下面 v2.533 那段还有一条 `min-height: 92px !important` 是同样的目的 ——
        两处都改是因为这条老规则不带 !important，保留 !important 那条更保险。
     ⚠️ 92px 要和 v2.533 段里的格子尺寸（92px）保持一致。 */
  min-height: 92px;
  overflow: visible;
}
/* ⚠️ 显式放开这几条 —— 老规则给过 order / flex: 0 0 auto / max-width:110px。
   ★★ v2.532：这里的 `display: flex` 原来带 !important，已去掉 ——
      它会让 combo.js 的 `up.style.display='none'`（行内样式）失效，
      导致"满 6 张藏不掉的"问题（行内样式赢一切，但带 !important 的
      样式表声明赢行内样式）。尺寸/排序仍由下面 v2.532 段用 !important 钉死。 */
#blk-upload .ec-up {
  order: 0;
  flex: 1 1 auto;
  width: 100%;
  max-width: none;
  height: auto;
}
/* ⚠️ 格式说明小字必须重新放出来 —— 老规则为"格子太窄"把它 display:none 了，
   现在上传区整宽，那行说明放得下（用户要求过要显示格式限制）。 */
#blk-upload .ec-up small { display: block; }
/* 缩略图：自己一行、最多 6 列 */
#blk-upload #cb-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  order: 0;
  flex: 0 0 auto;
  min-width: 0;
  height: auto;
  margin: 0;
  overflow: visible;
}
/* 缩略图格子：正方形、圆角、悬停放大、右上角 ✕
   ⚠️ overflow 改回 hidden（v2.463）：之前为了让悬停放大不被裁而放开，
      结果图片被外层的尺寸规则撑出格子、盖住下面的内容（用户截图）✗。
      放大是靠【整个格子】transform: scale，格子自己裁剪图片完全不影响放大效果 ✓ */
#blk-upload .thumb,
#cb-mthumb .thumb {
  position: relative;
  flex: 0 0 auto;
  width: 76px;
  height: 76px;
  border: 1px solid #e6e8f0;
  border-radius: 0.6rem;
  background: #fff;
  overflow: hidden;
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}
#blk-upload .thumb img,
#cb-mthumb .thumb img {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: cover;
  display: block;
}
/* ✕ 挪到格子【右上角内侧】—— 放外面会被 overflow:hidden 裁掉 */
#blk-upload .thumb button[data-rm],
#cb-mthumb .thumb button[data-rmmodel] {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 18px;
  height: 18px;
  padding: 0;
  line-height: 16px;
  font-size: 13px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.9);
  background: rgba(239, 68, 68, 0.92);
  color: #fff;
  cursor: pointer;
  z-index: 3;
}
/* 悬停：整格放大成"大图预览"
   ⚠️ 从 2.2 收到 1.35（v2.471，用户反馈"悬停后旁边格子的 ✕ 被挡住"）：
      格子 76px + 间距 8px，放大 1.35 倍 ≈ 103px ⇒ 只多出约 13px，
      【够不到右边的邻居】（右边邻居从 +84px 才开始）⇒ 不会盖住别人的 ✕ ✓。
      2.2 倍会伸出去 90 多像素，把邻居整个盖住、连 ✕ 都点不到 ✗。
   ⚠️ 想更清楚可以悬停后点开大图（弹窗），不要靠加大放大倍数 —— 那必然盖住别人。 */
#blk-upload .thumb:hover,
#cb-mthumb .thumb:hover {
  transform: scale(1.35);
  z-index: 40;
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.3);
}

/* 手机上格子小一点，放大倍数收一档（触屏没有 hover，纯保险） */
@media (max-width: 768px) {
  #blk-upload .thumb,
  #cb-mthumb .thumb { width: 64px; height: 64px; }
  #blk-upload .thumb:hover,
  #cb-mthumb .thumb:hover { transform: scale(1.3); }
}

/* ============================================================
   ★★ 看图器改版（v2.429）：左图 + 右侧信息栏（对齐参考站）
   ------------------------------------------------------------
   版式：左边大图（浮着缩放/旋转工具条 + 左右箭头 + 页码），
        右边竖排 作者 → 创作提示词（复制/展开）→ AI 生成作品（缩略图）→ 原图。
   ⚠️ 为什么另起一段而不是改上面那套 .img-lb-side 规则：
      那套是"左缩略图栏 + 右工具栏 + 底部按钮"的旧版式，本来就没几行；
      新老混着改容易顾此失彼（本项目被重复规则盖掉过好几次）。
      这里用新类名 + 覆盖 .img-lb 的宽高，旧规则自然失效。
   ⚠️ 比他多两处：① 手机上侧栏不隐藏，变成可滚动的底部抽屉
                  （不然下载按钮在手机上会消失）；
                  ② 缩略图当前那张有紫框 + 页码，翻到第几张一眼看得出。
   ============================================================ */
.img-lb {
  display: flex; align-items: stretch;
  width: min(1280px, 95vw);
  height: min(820px, 90vh);
  padding: 0; gap: 0; overflow: hidden;
}

/* ---------- 左：大图区 ---------- */
.lbm-main { position: relative; flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; background: #f7f8fc; }
.lbm-tabs { display: flex; gap: .4rem; padding: .7rem .8rem .35rem; }
.lbm-tab {
  font-family: inherit; font-size: .8rem; font-weight: 700; cursor: pointer;
  padding: .34rem .9rem; border-radius: .55rem;
  background: #fff; border: 1px solid #e5e7eb; color: #6b7280;
}
.lbm-tab.on { background: var(--mc-acc); border-color: var(--mc-acc); color: #fff; }

.img-lb-stage {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; padding: .4rem .8rem 1.1rem;
}
.img-lb-stage > img { max-width: 100%; max-height: 100%; object-fit: contain; }

/* 浮在图上的工具条（缩放/旋转/铺满） */
.lb-float {
  position: absolute; left: 50%; bottom: .9rem; transform: translateX(-50%);
  display: flex; align-items: center; gap: .35rem;
  padding: .3rem .45rem; border-radius: 999px;
  background: rgba(255,255,255,.94); border: 1px solid #e9ecf3;
  box-shadow: 0 8px 24px rgba(15,23,42,.14);
  backdrop-filter: blur(8px);
}
/* 左右切换箭头 */
.lb-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; line-height: 1; color: #4b5563;
  background: rgba(255,255,255,.92); border: 1px solid #e9ecf3;
  box-shadow: 0 6px 18px rgba(15,23,42,.12);
}
.lb-arrow:hover { background: #fff; color: var(--mc-acc); }
.lb-arrow[disabled] { opacity: .35; cursor: default; }
.lb-arrow.prev { left: .8rem; }
.lb-arrow.next { right: .8rem; }

/* ---------- 右：信息栏 ---------- */
.lbm-side {
  flex: 0 0 296px; width: 296px; min-width: 0;
  display: flex; flex-direction: column;
  background: #fff; border-left: 1px solid var(--mc-line);
  overflow-y: auto;
}
.lbm-side-head { padding: .9rem 1rem .7rem; border-bottom: 1px solid #f1f5f9; }
.lbm-side-title { display: flex; align-items: center; justify-content: space-between; }
.lbm-side-title b { font-size: .95rem; font-weight: 800; color: #1f2937; }
.lbm-author { display: flex; align-items: center; gap: .6rem; }
.lbm-author .av {
  width: 2.4rem; height: 2.4rem; border-radius: .7rem; flex: 0 0 auto;
  background: linear-gradient(120deg,var(--mc-acc),var(--mc-acc-2)); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 800;
}
.lbm-author .meta { min-width: 0; }
.lbm-author .meta b { display: block; font-size: .86rem; color: #1f2937; }
.lbm-author .meta span { font-size: .72rem; color: #9ca3af; }
.lbm-sec { padding: .8rem 1rem; border-bottom: 1px solid #f1f5f9; }
.lbm-sec > h4 {
  margin: 0 0 .5rem; font-size: .78rem; font-weight: 800; color: #6b7280;
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
}
.lbm-sec > h4 .ops { display: flex; gap: .4rem; }
.lbm-sec > h4 .ops button {
  font-family: inherit; font-size: .72rem; cursor: pointer; padding: .1rem .45rem;
  border-radius: .35rem; border: 1px solid #e9ecf3; background: #f8fafc; color: #6b7280;
}
.lbm-sec > h4 .ops button:hover { border-color: #c4b5fd; color: var(--mc-acc); }
/* ★ 右栏的提示词（v2.433）
   ⚠️⚠️ 必须用【新类名】，不能复用老的 .lb-prompt：
      老规则是"绝对定位贴在面板底部 + 渐变遮罩"的浮层，
      复用会把右栏的提示词画到图片下方去（用户已反馈）。
      这里显式写 position: static 把老规则的定位彻底盖掉。 */
.lbm-prompt {
  position: static;
  margin: 0; font-size: .78rem; line-height: 1.7; color: #4b5563;
  white-space: pre-wrap; word-break: break-word;
  max-height: 5.1em; overflow: hidden;   /* 「展开」时去掉这个上限 */
}
.lbm-prompt.open { max-height: none; }
.lb-prompt {
  margin: 0; font-size: .78rem; line-height: 1.7; color: #4b5563;
  white-space: pre-wrap; word-break: break-word;
  max-height: 5.1em; overflow: hidden;   /* 「展开」时去掉这个上限 */
}
.lb-prompt.open { max-height: none; }

/* ★★ 全屏铺满（v2.433）—— 用户要 MJ 那种效果：
   点 ⛶ 后图片铺满【整个屏幕】，不再被弹窗的固定宽高框住；
   放大后可以超出屏幕，拖着看局部。 */
.img-lb.full {
  width: 100vw; height: 100vh;
  border-radius: 0;
  max-width: none; max-height: none;
}
.img-lb.full .lbm-side { flex-basis: 320px; width: 320px; }

/* ============================================================
   ★★ 放大后从弹窗里「跳出来」（v2.435）
   ------------------------------------------------------------
   用户反馈：MJ 点放大后图片会【浮出弹窗】、盖住弹窗外面的页面；
   我们放多大都被弹窗裁住（"放再大都在弹窗后面"）。
   做法：把各级容器的 overflow 在"放大状态"下放开，
        并给图片一个介于舞台与右侧信息栏之间的层级 ——
        MJ 也是这样：图压在弹窗背景/页面上，但【不会盖住右侧信息栏】。
   ⚠️ 只在 zoomed（放大/旋转/铺满）时放开：
      1x 适应模式仍按原样裁切（保住圆角），
      否则图正好铺满时边缘溢出会看着像"跑偏"。
   ⚠️ 必须逐级放开：.img-lb → .lbm-main → .img-lb-stage，
      漏任何一级都还是会被裁（这几层各自都有 overflow）。
   ============================================================ */
/* ⚠️ 舞台【绝对不能】设 z-index ——
   一旦设了（哪怕 1），它就创建自己的层叠上下文，
   里面的图再怎么调 z-index 也压不过右栏（用户反馈"被盖住一部分"，
   根因就是这里）。层级只给图片本身。
   ⚠️ 图片 30 > 右栏 5 ⇒ 放大/铺满后图在【所有层】之前；
      工具条/箭头/关闭 40 仍压在图上，随时能点 ⟲ 复位或 ✕ 关闭。
   ⚠️ 防御式写法（v2.438）：图片的两个祖先用 !important 钉死
      z-index:auto + 不许 transform/filter/opacity/isolation ——
      这五样里【任何一个】都会创建层叠上下文，把图片关进盒子里
      （这类问题不会报错、只会"看起来没生效"，所以直接钉死）。 */
.lbm-main, .img-lb-stage {
  z-index: auto !important;
  transform: none;
  filter: none;
  opacity: 1;
  isolation: auto;
}
.img-lb-stage { position: relative; }
.img-lb-stage > img { position: relative; z-index: 30; }
.lbm-side { position: relative; z-index: 5; }
.lb-float, .lb-arrow, .lb-close { z-index: 40; }

.img-lb.zoomed { overflow: visible; }
.img-lb.zoomed .lbm-main { overflow: visible; }
.img-lb.zoomed .img-lb-stage { overflow: visible; }

@media (max-width: 860px) {
  /* 手机上全屏时信息栏收到底部抽屉（和上面同一条思路） */
  .img-lb.full .lbm-side { flex-basis: auto; width: 100%; }
}

.lbm-thumbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: .35rem; }
.lbm-thumbs .lb-thumb { width: 100%; aspect-ratio: 1/1; padding: 0; }
.lbm-thumbs .lb-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lbm-src-one { display: grid; grid-template-columns: repeat(4, 1fr); gap: .35rem; }
.lbm-acts { padding: .9rem 1rem calc(1rem + env(safe-area-inset-bottom)); display: flex; flex-direction: column; gap: .5rem; margin-top: auto; }
.lbm-acts .btn { width: 100%; justify-content: center; }

/* ---------- 手机：侧栏变底部抽屉（不隐藏，否则下载按钮会消失） ---------- */
@media (max-width: 860px) {
  .img-lb { flex-direction: column; width: 100vw; height: 100vh; border-radius: 0; }
  .lbm-side {
    flex: 0 0 auto; width: 100%; max-height: 46vh;
    border-left: 0; border-top: 1px solid var(--mc-line);
  }
  .img-lb-stage { padding: .3rem .4rem .9rem; }
  .lbm-thumbs { grid-template-columns: repeat(5, 1fr); }
}




/* ★ 放大方向：往【面板内侧】长，不越过控制面板左右边（v2.472 用户要求）
   ------------------------------------------------------------
   ⚠️ 以中心为原点放大时，最左那格会往左顶出面板边缘、最右那格往右顶出 ✗
   ⚠️ 改法：最左格以【左边缘】为原点（只往右长）、最右格以【右边缘】为原点（只往左长），
      中间格保持中心放大 ✓ ⇒ 任何一格放大后都还在面板内 ✓
   ⚠️ #cb-thumbs 用了 display:contents，但 :first-child / :last-child
      仍按 DOM 结构生效，最左/最右判断准确 ✓
   ⚠️ 最后一张缩略图就是"最右格"（上传格不在这个容器里，是它的兄弟节点）✓ */
#blk-upload #cb-thumbs .thumb:first-child:hover,
#cb-mthumb .thumb:first-child:hover { transform-origin: left top; }
#blk-upload #cb-thumbs .thumb:last-child:hover,
#cb-mthumb .thumb:last-child:hover { transform-origin: right top; }

/* ============================================================
   ★★ 模特图上传框（v2.476 起 → v2.518 改）
   ------------------------------------------------------------
   ⚠️⚠️ 这里原来是 76×76 的【小方格】（和商品图缩略图同一套外观），
      但模特框里塞的是「🧍 图标 + 上传你自己的模特照片 + 正面全身照效果最好…」
      三段文字 ⇒ 挤在 76px 里就【一列一个字】竖着断行（用户截图："挤成啥了"）。
      商品图那个 .ec-up 在 v2.507 已经改成"整宽框"，模特框当时漏了，
      所以这次补上——两个上传框现在是同一套外观 ✓
   ⚠️ 缩略图（#cb-mthumb .thumb）仍然是 76×76 方格，那是对的（它只有图没有字）。
   ============================================================ */
.up.up-model {
  /* 整宽框：图标在上、文字在下，居中 */
  width: 100%;
  max-width: none;
  height: auto;
  padding: 1.1rem 1rem;
  /* ⚠️ 不写 position:relative / overflow:hidden —— 那是"小方格 + 悬停放大"时代的；
      整宽框不需要裁剪，写上去反而会把文字截断。 */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  text-align: center;
  line-height: 1.45;
  box-sizing: border-box;
  margin: 0;
  border-radius: 0.95rem;
}
/* ⚠️ v2.476 把这行小字 display:none 了（理由是"格子太窄，放不下"）——
   现在整宽框放得下，放出来（它写明"正面全身照效果最好，五官清晰"，
   对出图质量有实际指导意义）。 */
.up.up-model small { display: block; }
.up.up-model .up-txt,
.up.up-model .up-plus { margin: 0 !important; position: static !important; transform: none !important; }
/* ⚠️ v2.476 把字号压到 0.62rem（格子太窄），整宽后恢复可读字号 */
.up.up-model .up-txt { font-size: 0.84rem; font-weight: 700; }
.up.up-model .up-plus { font-size: 1.5rem; line-height: 1; }

/* 模特图缩略图：跟商品图同一个尺寸/圆角/悬停/✕ 位置 */
#cb-mthumb .thumb {
  width: 76px !important;
  height: 76px !important;
  max-width: 76px;
  margin: 0 !important;
  aspect-ratio: 1 / 1;
  box-sizing: border-box;
}
@media (max-width: 768px) {
  /* ⚠️ v2.518：这里原来是 `.up.up-model { width:64px; height:64px; }` ——
     小方格时代的窄屏尺寸，现在模特框是整宽框，不能再改宽度。
     只保留缩略图那一半（缩略图确实是方格）。 */
  #cb-mthumb .thumb { width: 64px !important; height: 64px !important; max-width: 64px; }
}

/* ============================================================
   ★★ 工具标题行（.pn-head）的间距（v2.477）
   ------------------------------------------------------------
   用户反馈："这个标题和按钮，别靠边那么近，不协调，也不好看"。
   ⚠️ 这一行是「图标 + 标题/副标题 + ✏️ 编辑提示词按钮」，
      原本贴着面板的左右边缘和上沿，显得挤 ✗
   ⚠️ 只加内边距/间距，不动结构 ——
      .pn-head 在【电商专区左栏】里被 .zone-split-left .pn 覆写过，
      所以这里用 !important 确保两边布局都生效（否则左栏里没效果）✗
   ⚠️ 标题与副标题之间也给一点行距，两行不要糊在一起 ✓
   ============================================================ */
.pn-head#cb-head,
.pn-head {
  padding: 0.7rem 1.1rem !important;
  gap: 0.7rem !important;
  align-items: center;
}
.pn-head h1 { margin: 0 0 0.2rem !important; }
.pn-head p { margin: 0 !important; }
#cb-edit {
  flex: 0 0 auto;
  margin-right: 0.2rem;
}
@media (max-width: 768px) {
  .pn-head { padding: 0.6rem 0.8rem !important; }
}

/* ==============================================================
   ★★ v2.521：商品图上传框（.ec-up）的样式【搬到这里一份】
   --------------------------------------------------------------
   ⚠️ 为什么要在 style.css 里再放一份：
     这块的全部样式原来只写在 ecommerce.html 的内联 <style> 里。
     而 ecommerce.html 这个 URL 不带版本号 —— 一旦浏览器用了缓存副本，
     里面的内联样式就是旧的，用户看到的是"改了很多轮都没反应"。
     style.css 带 ?v=xxx（由 tools/assets-version.mjs 统一改），
     版本一变 URL 就变 ⇒ 浏览器必须重新下载 ⇒ 永远不会拿到旧样式。

   ⚠️ 现象对照（用户截图，v2.520 时）：
     · 「上传模特」修好了 —— 它的样式在 style.css 里 ✓
     · 「上传商品图」还是窄的 —— 它的样式在内联 <style> 里 ✗
     同一个页面、同一批改动，差别就在"样式写在哪个文件"。

   ⚠️ 两份内容【完全一致】，不会互相打乱：
     · 选择器同名同权重 ⇒ 后加载的那份赢（本文件在 <head> 里先加载，
       所以 ecommerce.html 内联那份仍然优先；两边一致时无所谓）。
     · 两边不一致时以 ecommerce.html 为准（它是本页的权威）。
       所以以后改样式，优先改 ecommerce.html 那份，再同步这里。

   ⚠️ 只作用于电商专区（.zone-split-left 前缀）——
      combo.html 的 .pn 里也有 .ec-up，但不在这个前缀下，不受影响。
   ============================================================== */
.zone-split-left .ec-up {
  display: flex; align-items: center; justify-content: flex-start;
  gap: 0.85rem;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  padding: 0.95rem 1.2rem;
  margin-bottom: 0.85rem;
  text-align: left;
  border: 1.5px dashed #d8dce6;
  border-radius: 0.95rem;
  background: linear-gradient(180deg, #fcfcff 0%, #f7f8fd 100%);
  transition: border-color .18s, background .18s, box-shadow .18s;
}
.zone-split-left .ec-up:hover {
  border-color: #a78bfa;
  background: linear-gradient(180deg, var(--mc-acc-soft) 0%, #f4f0ff 100%);
  box-shadow: 0 6px 18px rgba(124,58,237,.10);
}
.zone-split-left .ec-up-plus {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: 0 0 auto;
  font-size: 1.45rem; font-weight: 400; line-height: 1;
  color: #fff; background: linear-gradient(135deg, #8b5cf6, #6366f1);
  border: 0; border-radius: 50%;
  box-shadow: 0 4px 12px rgba(99,102,241,.30);
  transition: transform .18s, box-shadow .18s;
}
.zone-split-left .ec-up:hover .ec-up-plus {
  transform: scale(1.06);
  box-shadow: 0 6px 16px rgba(99,102,241,.40);
}
.zone-split-left .ec-up-txt {
  display: flex; flex-direction: column; gap: 0.22rem;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.9rem; font-weight: 700; color: #1f2937;
}
.zone-split-left .ec-up-txt .ec-up-t {
  display: block;
  font-size: 0.88rem; font-weight: 800; color: #1f2937;
  white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.zone-split-left .ec-up-txt .ec-up-meta {
  display: flex; align-items: center; gap: 0.32rem;
  flex-wrap: wrap;
}
.zone-split-left .ec-up-txt .ec-up-meta .req {
  color: #ef4444; font-size: 0.86rem; font-weight: 800; line-height: 1;
}
.zone-split-left .ec-up-txt small { font-size: 0.72rem; color: #9ca3af; }
@media (max-width: 560px) {
  .zone-split-left .ec-up { flex-direction: column; text-align: center; gap: 0.5rem; }
  .zone-split-left .ec-up-txt { align-items: center; }
}

/* ★★★ v2.532：这里原来有一份"长条时代"的重复兜底规则，已整段删除 ——
   它把 .ec-up 钉成 `display:flex !important; width:100%`（整宽长条），
   后果有两个，都是用户实测报出来的：
     ① 上传格被拉成长条（已经不是方形按钮了）
     ② `display: flex !important` 压住 combo.js 的
        `up.style.display='none'`（行内样式）⇒ 满 6 张藏不掉上传格
   现在上传区的样式【只有一处来源】：本文件末尾的 v2.529/2.532 段。
   ⚠️ 要改上传区外观，改那一段；这里不要再加任何 !important 兜底。 */

/* ==============================================================
   ★★ v2.525：生成预览卡上的【细进度条】
   --------------------------------------------------------------
   用户要求：把生成预览区做成参考站那种效果（卡片上有图、有进度）。
   ⚠️ 这个动画只服务于"生成中"那一态：条子在轨道里来回扫。
      CSS 动画而不是 JS 计时器 —— 预览卡每秒都可能被重画，
      JS 计时器会被反复重建、进度会跳。
   ⚠️ 排队中只画底轨（不跑动画）—— 还没开始，跑动画会让人以为在跑。
   ============================================================== */
.pk-bar {
  width: 40%;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(90deg, #a78bfa, var(--mc-acc));
  animation: pkBarRun 1.2s ease-in-out infinite;
}
@keyframes pkBarRun {
  0%   { transform: translateX(-60%); }
  100% { transform: translateX(210%); }
}
/* ⚠️ 尊重"减少动态效果"的系统设置（无障碍）——
   关掉动画时改成一条静止的半透明条，信息不丢。 */
@media (prefers-reduced-motion: reduce) {
  .pk-bar { animation: none; width: 100%; opacity: .45; }
}

/* ==============================================================
   ★★★ v2.529 / v2.531：上传区 = 【方形上传格 + 缩略图从左往右排】
   --------------------------------------------------------------
   用户要求（逐条）：
     · 上传按钮是【方形】按钮（不是长条）
     · 每上传一张图，上传按钮【往右挪一格】
     · **上传按钮永远在最右侧**
     · 6 张传满 → 上传按钮【消失】，无法再传第 7 张
     · 方格可以【大一点】（上方还有空间）

   ⚠️⚠️ v2.531 修了用户指出的两个问题：
     ① 顺序反了 / 按钮不在最右
        病因：老规则（v2.507）给 .ec-up 和 #cb-thumbs 都写了 `order: 0`
              ⇒ 按 DOM 顺序排 = 上传格在前 ⇒ 上传格跑到【最左】。
        修法：给上传格 `order: 2`、缩略图容器 `order: 0`
              ⇒ 缩略图永远排在左、上传格永远排在最右。
     ② 缩略图顺序
        ⚠️ 老版本是"最后上传的图排最左"（靠 order:2 + renderThumbs 前插实现），
           用户要的是【从左到右按上传顺序】⇒ 直接用 S.refs 的自然顺序即可。

   ⚠️⚠️ 另一处必读（这是"内容被盖住"的修复，别删）：
     老规则里有一条 `#blk-upload { min-height: 0 }`（v2.507 写的兜底），
     min-height:0 会让容器【被允许收缩到 0 高度】。实测症状（#diag）：
        blk-upload  h=0     ← 容器高度 0
        ec-up       h=76    ← 子元素溢出到容器外
        blk-sell    top=394 ← 按"上面只占 394px"排版 ⇒ 压住溢出的上传格
     所以必须给容器一个显式高度下限。

   ⚠️ 为什么样式写在这里而不是 ecommerce.html 的内联 <style>：
     内联块出现过"改了不生效"（文件覆盖不全 / 浏览器缓存）。
     style.css 带 ?v= 版本号，版本一变 URL 就变，永远拿不到旧样式。

   ⚠️ 布局原理：
     #blk-upload = flex row + wrap
       ├─ label.ec-up    (order:2) ← 方形上传格，永远排最后
       ├─ input#cb-file           ← 隐藏输入框（absolute，不占位）
       └─ div#cb-thumbs  (order:0) ← 缩略图，从左到右
     没图时：[+]
     1 张时：[图][+]
     6 张时：[图][图][图][图][图][图]（上传格被 combo.js 藏掉）
   ============================================================== */

/* 容器：横向排列 + 允许换行；⚠️ min-height 必须给（见上面的说明） */
#blk-upload {
  display: flex !important;
  flex-direction: row !important;
  flex-wrap: wrap !important;
  /* ⚠️ center 而不是 flex-start：上传格比缩略图高（三行 vs 正方形），
     居中后缩略图不会吊在顶部、也不会被拉伸。 */
  align-items: center !important;
  gap: 0.5rem !important;
  width: 100% !important;
  /* ★★★ v2.533：改回 flex-start —— 修我 v2.532 用 space-between 造成的错位。
     ------------------------------------------------------------
     ⚠️ 用户实测：space-between 把"图1"和"上传格"分别顶到【两端】，
        中间空隙被撑开 ⇒ 看起来像"按钮孤零零在最右"，
        和需求"按钮紧跟在图右边、随上传往右挪"完全不符（用户截图指出）。
     ★ flex-start = 所有格子从左边开始【紧挨着】排：
         没图：[ + ]
         1 张：[图1][ + ]
         2 张：[图1][图2][ + ]
         6 张：[图1]…[图6]（上传格被藏掉）
       ✅ 这才是用户要的"每传一张，上传格往右挪一格"。
     ⚠️ "六个格子铺满整行"由【格子尺寸】保证，不靠 space-between：
        6 × 92px + 5 × 8px(gap) = 592px，容器约 659px ⇒ 基本铺满。
        格子已从 88px 放大到 92px（用户也要求"再大一点"）。 */
  justify-content: flex-start !important;
  /* ⚠️⚠️ 这行是【内容被盖住】的真正修复，别删！
     76px→88px→92px 是随格子放大同步调整（格子多大，下限就多大）。 */
  /* ⚠️⚠️ v2.535 修：这里绝对【不能】写 min-height: var(--ec-tile) ——
     因为 --ec-tile 里含 100%，而百分比高度在父容器高度为 auto 时无法解析
     ⇒ 整个变量计算失效 ⇒ 高度塌成一条线（用户截图：上传格变成扁平长条）。
     ⇒ 换成固定下限，彻底断开这个循环依赖。 */
  min-height: 96px !important;
  overflow: visible !important;
  /* ★★★ v2.534：格子尺寸按【容器实际宽度】均分 6 格 —— 用户要求"铺满这个框"。
     ------------------------------------------------------------
     ⚠️ 为什么不用 space-between：那只是把【空隙撑开】，格子本身没变大，
        看起来像"6 个格子 + 一条空格子"，反而更难看（用户已否掉这种做法）。
     ★ 正确做法 = 把格子本身算大：容器内容宽减去 5 个 gap，再除以 6。
       这样 6 个格子正好铺满整宽，没有多余空白。
     ⚠️ 用 CSS 变量而不是写死 px：面板宽度在不同分档下不同
        （1 格面板 / 2 格并排 / 窄屏），写死就会出现"某一档又不齐"。
     ⚠️ 兜底值 92px：万一 var() 不被支持（老浏览器），退回固定尺寸也不会塌。 */
  /* ⚠️ 上方留白压掉一点 —— 用户说"上面距离纯白背景那句话还有空间" */
  margin-top: -0.1rem !important;
}

/* ⚠️ 文件输入框移出布局流 —— class="hidden" 只设 display:none，
   万一被别的规则改回来就会占一格。absolute 彻底不参与布局。 */
#blk-upload > input[type="file"] {
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  opacity: 0 !important;
  pointer-events: none !important;
  left: -9999px !important;
}

/* ⚠️ 缩略图容器【不能占满整宽】——否则上传格被挤到第二行，就不是"往右挪"了 */
#blk-upload > #cb-thumbs,
#blk-upload #cb-thumbs {
  display: flex !important;
  flex-wrap: wrap !important;
  width: auto !important;
  /* ★ v2.544：回到 flex: 0 0 auto —— 容器只占内容宽。
     （v2.539 曾改成 1 1 auto 去"吃掉剩余宽度"，配合格子的 flex-grow
       导致图少时巨图；已一并撤销。） */
  flex: 0 0 auto !important;
  min-width: 0 !important;
  gap: 0.5rem !important;
  /* ⚠️ center：上传格是三行（110×134）比缩略图高，缩略图要垂直居中，
     不能 flex-start（那样会吊在行顶部，看起来错位）。 */
  align-items: center !important;
  margin: 0 !important;
  /* ★ 缩略图排在前（order 越小越靠前 ⇒ 上传格永远最右） */
  order: 0 !important;
}

/* ★ 方形上传格：88×88，和缩略图同尺寸同圆角 */
#blk-upload > .ec-up,
#blk-upload .ec-up {
  /* ⚠️ 这一组是"从长条变方块"的关键 ——
     v2.495~v2.528 期间它被设成 width:100%，就是那个长条的来源。 */
  /* ★★★ v2.536：【放弃百分比方案，改用固定尺寸】
     ----------------------------------------------------------------
     ⚠️⚠️ 为什么（Chrome 无头实测证据，tools/upload-probe.mjs）：
        之前用 `width: calc((100% - 2.5rem)/6)` —— 但 .thumb/.ec-up 的
        父级 #cb-thumbs 是 shrink-to-fit（实测宽 12px），
        ⇒ 百分比缩到 12px ⇒ 每格算出 2px（实测 .thumb computed width = 2px）。
     ⚠️ 也不能把 #cb-thumbs 改成整宽（width:100%）—— 那会把上传格挤到
        第二行（就是用户报过的"错位到第二行"）。
     ⇒ 结论：格子尺寸【只能用固定值】，不能用百分比。
     固定 96px：6 格 = 6×96 + 5×8 = 616px，容器 674px ⇒ 放得下且接近铺满；
     满 6 张时再用下面的 .is-full 规则把缝隙撑开，做到严丝合缝。 */
  /* ⚠️⚠️ 这里【只写与尺寸无关的公共样式】——尺寸必须在下面按选择器分开写！
     因为我这个规则的选择器是 `#blk-upload > .ec-up, #blk-upload .ec-up`，
     后半段是【后代选择器】，会连 #blk-upload 底下的 .thumb 一起命中 ⇒
     之前把 width/height 写在这里，缩略图被一起改成 110px，
     6 格只占容器 16%（真页面 e2e 实测抓出来的）。 */
  /* ⚠️ flex 用 0 0 auto 而不是 1 1 0：宽度已由上面的 width 精确算出，
     flex-grow 会再抢一次剩余空间、破坏"正好 6 等分"。 */
  flex: 0 0 auto !important;
  box-sizing: border-box !important;
  /* ★★ 永远排在最右 —— 必须大于缩略图容器的 order */
  order: 2 !important;

  /* ⚠️⚠️ display 这条【绝对不能加 !important】—— 加了会让
     combo.js 的 `up.style.display = 'none'`（行内样式）失效，
     于是"满 6 张藏掉上传格"就不生效了（用户实测：6 张满了按钮还在）。
     原理：行内样式赢一切，但【带 !important 的样式表声明】赢行内样式。
     ⇒ 这里只用普通声明，靠 #id 权重压过老规则即可。 */
  display: flex;
  flex-direction: column !important;
  align-items: center !important;
  justify-content: center !important;
  /* ⚠️ gap 必须是 0：里面的 .ec-up-txt 虽然被隐藏，但它仍是 flex 子项，
     gap 会在"图标 + 隐藏项"之间留空 ⇒ 加号偏离方块中心。 */
  gap: 0 !important;

  padding: 0.2rem 0.15rem !important;
  margin: 0 !important;
  text-align: center !important;
  line-height: 1.1 !important;

  /* ⚠️ position: relative 给下面"隐藏文字列"的 absolute 做锚点 */
  position: relative !important;
  overflow: hidden !important;

  border: 1.5px dashed #d8dce6 !important;
  border-radius: 0.6rem !important;
  background: linear-gradient(180deg, #fcfcff 0%, #f7f8fd 100%) !important;
  box-shadow: none !important;
  cursor: pointer !important;
}
/* ★★★ v2.537/v2.544：尺寸【按选择器分开写】——上传格三行、缩略图正方形
   ----------------------------------------------------------------
   用户要求上传格三行：第一行 + / 第二行「上传商品图片」/ 第三行红色 *。
   ⚠️ v2.544：宽从 110 收到 104（"上传商品图片"六个字在 0.7rem 下仍放得下），
      高 134 → 126（三行紧凑一点，不再比缩略图高那么多）。
   ⚠️ 缩略图固定 96×96 正方形：6 格 96 + 5×8 = 616px，容器约 672px。
   ⚠️ 上传格比缩略图略高是【正常的】—— 它有三行内容，靠 align-items:center
      垂直居中，看起来是齐的。 */
#blk-upload > .ec-up, #blk-upload > label.ec-up {
  /* ★★★ v2.548：改回【正方形 96×96】—— 和缩略图同尺寸
     ----------------------------------------------------------------
     用户反馈：「这个上传按钮要方形的，不要这么高，占空间」。
     ⚠️ v2.544 为了塞下三行文字把它拉到 104×126（比缩略图高 30px），
        整行被它顶高、右侧显得空。现在收成和缩略图一样的 96×96。
     ⚠️ 三行文字在 96px 里要放得下 ⇒ 同步把内边距压到 0.2rem、
        行高压到 1.1、字号 0.7rem→0.64rem（见下面 .ec-up-t 那条）：
           +            约 20px（1.15rem）
           上传商品图片   约 17px（0.64rem × 1.1 × 2 行余量）
           *            约 13px
           上下内边距     约 7px
           --------------------------
           合计          约 57px  ⇒ 96px 里绰绰有余，垂直居中
     ⚠️ 6 格 96px + 5×8 = 616px，容器约 672px ⇒ 一行放得下。 */
  width: 96px !important;
  height: 96px !important;
  min-width: 96px !important;
  max-width: 96px !important;
  max-height: 96px !important;
}
/* ★★★ v2.544：撤销 v2.539 的"缩略图自动放大"，回到【固定 96px 正方形】
   ----------------------------------------------------------------
   ⚠️ 为什么撤销（用户实测反馈 + 截图）：
      v2.539 让缩略图 flex-grow 去吃掉剩余宽度，结果【只传 1 张时那张图
      被拉成 420px 的巨图】，把上传格挤到最右边，整块布局面目全非。
      用户明确说："上传那个按钮这样就可以了 2.536 版本"。
   ★ 所以回到 v2.536 的行为：缩略图固定 96×96 正方形，从左往右排，
      上传格紧随其后（order:2 保证它在最后）。
      图少时右边确实会留一点空 —— 这是【可接受】的，不算 bug。
   ⚠️ 不要再改回 flex-grow —— 那条路的代价是"图少时变巨图"，更糟。 */
#blk-upload > #cb-thumbs .thumb, #blk-upload #cb-thumbs .thumb {
  flex: 0 0 auto !important;
  width: 96px !important;
  height: 96px !important;
  min-width: 96px !important;
  max-width: 96px !important;
  max-height: 96px !important;
  aspect-ratio: 1 / 1 !important;
  box-sizing: border-box !important;
}
#blk-upload > .ec-up:hover {
  border-color: #a78bfa !important;
  background: var(--mc-acc-soft) !important;
}

/* ⚠️ 用 position:absolute 而不是 display:none 来隐藏这段文字：
   display:none 的元素仍是 flex 子项，会影响 gap / 对齐；
   absolute 彻底移出布局流，方块里【只剩一个 + 】，居中万无一失。
   ⚠️ 老规则有 `#blk-upload .ec-up small { display: block }`，
     这里的 !important 必须带上，否则"支持 JPG…"那行会冒出来。 */
/* ★★★ v2.537：文字列【不再隐藏】，正常显示成第二、三行。
   用户要求：第一行 + / 第二行「上传商品图片」/ 第三行红色 *。
   ⚠️ 之前是"视觉隐藏"（absolute + 1px + opacity:0），因为方块只有 96px
      放不下文字；现在方块是 110×134，放得下三行。
   ⚠️ 布局是 column：加号在上，文字块在下，整体垂直居中。 */
#blk-upload > .ec-up .ec-up-txt {
  position: static !important;
  width: auto !important; height: auto !important;
  overflow: visible !important;
  opacity: 1 !important;
  pointer-events: auto !important;
  clip: auto !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: center !important;
  gap: 0 !important;
  flex: 0 0 auto !important;
  min-width: 0 !important;
}
/* 第二行：上传商品图片（六个字必须在【一行】，字号压到 0.7rem 放得下） */
#blk-upload > .ec-up .ec-up-t {
  /* ★ v2.548：字号收到 0.64rem —— 96px 方块里"上传商品图片"六个字仍在一行，
     同时给加号和星号留出垂直空间（三行合计约 57px < 96px）。 */
  font-size: 0.64rem !important;
  font-weight: 700 !important;
  color: #374151 !important;
  white-space: nowrap !important;
  line-height: 1.1 !important;
}
/* 第三行：只留红色 *（必传标记）；"支持 JPG…"那行说明藏掉，方块放不下 */
#blk-upload > .ec-up .ec-up-meta {
  display: flex !important;
  flex-direction: row !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 0 !important;
  line-height: 1.1 !important;
}
#blk-upload > .ec-up .ec-up-meta small { display: none !important; }
#blk-upload > .ec-up .ec-up-meta .req {
  color: #ef4444 !important;
  font-size: 0.72rem !important;
  font-weight: 800 !important;
  line-height: 1 !important;
}

/* 加号：方块中央的大号 + */
#blk-upload > .ec-up .ec-up-plus {
  width: auto !important; height: auto !important;
  flex: 0 0 auto !important;
  position: static !important;
  font-size: 1.15rem !important;
  font-weight: 400 !important;
  line-height: 1 !important;
  color: var(--mc-acc) !important;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transform: none !important;
  margin: 0 !important;
}
#blk-upload > .ec-up:hover .ec-up-plus { transform: scale(1.1) !important; }

/* ⚠️ 缩略图格子跟着放大到同一尺寸 —— 否则上传格 92px、缩略图 76px 不齐 */
#blk-upload .thumb {
  /* ★ v2.536：和上传格同尺寸的固定值（原因见上传格那段的实测说明）。 */
  /* ⚠️⚠️ 这里【只写与尺寸无关的公共样式】——尺寸必须在下面按选择器分开写！
     因为我这个规则的选择器是 `#blk-upload > .ec-up, #blk-upload .ec-up`，
     后半段是【后代选择器】，会连 #blk-upload 底下的 .thumb 一起命中 ⇒
     之前把 width/height 写在这里，缩略图被一起改成 110px，
     6 格只占容器 16%（真页面 e2e 实测抓出来的）。 */
  flex: 0 0 auto !important;
  box-sizing: border-box !important;
}
#blk-upload .thumb img { width: 100% !important; height: 100% !important; object-fit: cover !important; }

/* 窄屏：格子小一点（6 个 92px 放不下时仍能折行） */
/* ★ v2.534：窄屏不再"6 等分"（那样格子只剩 ~50px，太小）——
   直接把变量定成 64px，让格子自然折行。 */
@media (max-width: 768px) {
  #blk-upload {
    min-height: 64px !important;
    justify-content: flex-start !important;
  }
  #blk-upload .thumb {
    width: 64px !important; height: 64px !important;
    min-width: 64px !important; max-width: 64px !important; max-height: 64px !important;
  }
  /* ★ v2.548：窄屏的上传格也保持【正方形】（84×84）—— 和桌面端的 96×96 一致，
     只是小一号。（原来写的是 84×104 的竖矩形，改方形后忘了跟着改。） */
  #blk-upload > .ec-up,
  #blk-upload .ec-up {
    width: 84px !important; height: 84px !important;
    min-width: 84px !important; max-width: 84px !important; max-height: 84px !important;
  }
  #blk-upload > .ec-up .ec-up-t { font-size: 0.62rem !important; }
  /* 窄屏不满 6 张也要能铺满（没有 .is-full 时也好看） */
  #blk-upload.is-full { justify-content: flex-start !important; }
}
/* ★★★ v2.536：满 6 张时【铺满整行】
   ----------------------------------------------------------------
   ⚠️ 为什么需要单独一条：格子是固定 96px（原因见上面上传格那段的实测说明），
      6 格 + 5 个 gap = 616px，容器约 674px，右边会空一小条。
      用户明确要求"铺满这个框，留个空不好看"。
   ⚠️ 做法：满 6 张时把 justify-content 从 flex-start 换成 space-between
      —— 注意这次【不会】出现"按钮孤零零在最右"的老问题：
        因为满 6 张时上传格已经被 combo.js 藏掉了，
        行里只剩 6 个缩略图，space-between 只是把它们之间的缝隙均匀撑开。
   ⚠️ 两条触发路径（双保险）：
      ① `.is-full` —— combo.js 在 renderThumbs 里按张数加/去这个类（推荐）
      ② `[data-full="1"]` + 兄弟选择器 —— 纯 CSS 兜底：
         .ec-up 被行内 display:none 后，`!~` 选不中它，
         但能选中它后面的 #cb-thumbs ⇒ 同样能达到目的。
         ⚠️ 属性选择器连写不加空格，是为了不受 HTML 里空格写法影响。 */
#blk-upload.is-full,
#blk-upload[data-full="1"] {
  justify-content: space-between !important;
}
#blk-upload > .ec-up[style*="display: none"] ~ #cb-thumbs,
#blk-upload > .ec-up[style*="display:none"] ~ #cb-thumbs {
  flex: 1 1 auto !important;
  justify-content: space-between !important;
}
/* ==============================================================
   ★★ v2.541：后台弹窗表单的【分区标题】与【稳落两列】
   --------------------------------------------------------------
   用户反馈：「这个编辑会员的弹窗不好看，改大一点，好看一点」。
   光把弹窗改宽还不够 —— 字段一多就成了"一大片输入框"，
   看不出层次。所以做了两件事：
     ① 弹窗宽度 520 → 960（在 admin.js 的 openModal 调用处传 width）
     ② 用 .fg-sec 把表单【分成几段】，每段前面一行小标题
   ⚠️ .fg-sec 必须 grid-column: 1/-1 横跨整行，否则会被当成一个字段占一格。
   ⚠️ .modal-grid-2 用固定两列（而不是 form-grid 的 auto-fill）——
      auto-fill 在 960px 下会算出 3 列，标签长短不一时列宽看着乱；
      固定 2 列更整齐。窄屏由下面的媒体查询退回单列。
   ============================================================== */
.fg-sec {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0.35rem 0 -0.15rem;
  font-size: 0.78rem;
  font-weight: 800;
  color: var(--mc-acc-ink);
  letter-spacing: 0.02em;
}
.fg-sec::before {
  content: '';
  width: 3px;
  height: 0.9rem;
  border-radius: 2px;
  background: linear-gradient(180deg, #a78bfa, var(--mc-acc));
}
/* 第一段的小标题不要额外上边距 */
.form-grid > .fg-sec:first-child { margin-top: 0; }

/* 弹窗里的表单：固定两列（960px 宽下每列约 450px，输入框宽松好点） */
.form-grid.modal-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
@media (max-width: 760px) {
  .form-grid.modal-grid-2 { grid-template-columns: 1fr !important; }
}
/* ==============================================================
   ★★★ v2.584：生图数量改成【数字输入框 + 上下箭头】（1 ~ 10）
   --------------------------------------------------------------
   用户要求：「把图片创作的生成图片数量从拉动条改成这个样式」
   （参考图就是一个带增减箭头的数字框）。
   ⚠️ 上一版是 v2.549 的 <input type="range"> 滑动条，这里整段换掉。
   ⚠️ 为什么要【另加两个箭头按钮】而不是只用原生箭头：
      数字框自带的箭头宽度约 1rem，很窄不好点（移动端更难点）。
      参考站那种是【通栏宽按钮】—— 所以用 appearance:none 把原生箭头
      去掉，右边自己画一列上下两格。
      ⚠️ 但【不能真的把原生箭头删干净】：万一 JS 没跑起来（老缓存），
         用户至少还能用原生箭头改数字。所以这里保留原生箭头，
         只把它压缩到右侧（见下面的 width 设置），自己画的箭头叠在它上面。
   ⚠️ 布局：标签在左、数字框在中间、自己画的箭头贴右、"N 张"在最右 ——
      一行放下，放在固定底栏里不占额外高度。
   ============================================================== */
.count-slider {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  /* ⚠️ gap 设 0，而不是 0.5rem —— 统一 gap 会在【数字框与箭头之间】也留缝，
      把本来该拼成一体的两块分开（我第一版就是这么写的，截图里看着像个控件）。
      间距改由各元素自己的 margin 控制：数字框↔箭头紧贴、"N 张"前留 0.6rem。 */
  gap: 0;
  min-width: 0;
  /* ★ v2.590：让「N 张」不贴右边 —— 给整行留出右侧余量。
     ⚠️ 用户反馈「10 张两个字位置往左挪一下，快触边了」。
     ⚠️ 用 padding-right 而不是 margin：padding 参与 flex 布局计算，
        能稳定地把内容往左推，不受父级 justify-content 影响。 */
  padding-right: 0.5rem;
}
/* ---- 滑动条（v2.585 加回来：和数字框、箭头三者同步）---- */
.count-range {
  /* --fill 由 JS 写入（已滑过的百分比），画"已滑过"那段渐变用 */
  --fill: 0%;
  /* ★ 伸缩的那一个：把剩余空间都吃掉，所以它最长 */
  flex: 1 1 auto;
  min-width: 0;
  height: 1.5rem;          /* 给 thumb 留出点击高度（轨道本身很细） */
  margin: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  outline: none;
}
.count-range::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  /* 已滑过 = 品牌紫渐变；未滑过 = 浅灰（和视频时长那根一致） */
  background: linear-gradient(90deg, var(--mc-acc) 0%, #6366f1 var(--fill), #e9ecf3 var(--fill), #e9ecf3 100%);
}
.count-range::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: #e9ecf3;
}
.count-range::-moz-range-progress {
  height: 4px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--mc-acc), #6366f1);
}
.count-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 1.05rem;
  height: 1.05rem;
  margin-top: calc((4px - 1.05rem) / 2);   /* 垂直居中对齐轨道 */
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--mc-acc);
  box-shadow: 0 1px 4px var(--mc-acc-59);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.count-range:hover::-webkit-slider-thumb { transform: scale(1.12); }
.count-range:active::-webkit-slider-thumb { box-shadow: 0 0 0 6px var(--mc-acc-26); }
.count-range::-moz-range-thumb {
  width: 1.05rem;
  height: 1.05rem;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--mc-acc);
  box-shadow: 0 1px 4px var(--mc-acc-59);
}
.count-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 6px var(--mc-acc-26); }

/* ---- 数字输入框 ---- */
.count-num {
  /* ⚠️ 宽度收窄到 4.4rem 并把伸缩交给滑条 ——
     现在是「滑条(伸缩) + 数字框(固定) + 箭头(固定) + N 张(固定)」，
     数字框再占 5.6rem 会把滑条挤没（v2.585 之前就是这么挤的）。 */
  flex: 0 0 auto;
  width: 4.4rem;
  height: 2.05rem;
  padding: 0 0.55rem;
  border: 1px solid #e2e6ef;
  /* ⚠️ 只圆左边两角：右边要和箭头那一列拼成一个整体（参考图就是这样） */
  border-radius: 0.55rem 0 0 0.55rem;
  background: #fff;
  font: inherit;
  font-size: 0.92rem;
  font-weight: 700;
  color: #1f2937;
  text-align: center;
  font-variant-numeric: tabular-nums;
  /* ⚠️ 保留原生箭头（窄窄地贴右边）作为 JS 失效时的兜底，
      自己画的箭头会盖在它上面（见 .count-steps） */
  -moz-appearance: textfield;
  appearance: auto;
}
.count-num:focus {
  outline: none;
  border-color: #a78bfa;
  box-shadow: 0 0 0 3px var(--mc-acc-26);
}
/* ---- 自己画的增减箭头（右侧一列两格）---- */
.count-steps {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  /* ⚠️ 负 margin 把自己的箭头【叠到】原生箭头那一小块上面，
      这样看起来只有一套箭头（不会出现两列箭头并排） */
  margin-left: -1.15rem;
  width: 1.15rem;
  z-index: 1;
}
.count-step {
  width: 100%;
  height: 1.025rem;          /* 2.05rem 的一半，正好和输入框等高 */
  padding: 0;
  border: 1px solid #e2e6ef;
  border-left: 0;
  background: #f8fafc;
  color: #6b7280;
  font-size: 0.5rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-appearance: none;
  appearance: none;
  transition: background .12s, color .12s;
}
/* ⚠️ 上面那格要圆右上角、下面那格圆右下角 —— 整体才像个输入框 */
.count-step:first-child { border-radius: 0 0.55rem 0 0; border-bottom: 0; }
.count-step:last-child  { border-radius: 0 0 0.55rem 0; }
.count-step:hover:not(:disabled) { background: #f1f5f9; color: var(--mc-acc-ink); }
.count-step:active:not(:disabled) { background: var(--mc-acc-line); }
/* 到边界（1 或 10）时置灰，让用户知道到底了 */
.count-step:disabled { color: #d1d5db; cursor: not-allowed; }
/* ---- 右侧数字（跟着实时变）---- */
.count-out {
  flex: 0 0 auto;
  /* ★ v2.590：用户反馈「10 张两个字位置往左挪一下，快触边了」。
     ⚠️ 底栏是「滑条(伸缩) + 数字框 + 箭头 + N 张」四段。
        数字框和箭头都是固定宽，滑条吃掉剩余空间 ⇒
        「N 张」天然被顶到最右边，贴着面板边缘。
     ★ 收窄 min-width 到 2.9rem：最长文案是「15 张」（3 字符），
       2.9rem 够用；省下的宽度直接变成右边的留白。 */
  margin-left: 0.5rem;
  min-width: 2.9rem;        /* 固定宽度：1 张 → 15 张 变化时行不会跳 */
  text-align: right;
  font-size: 0.82rem;
  font-weight: 800;
  color: var(--mc-acc-ink);
  font-variant-numeric: tabular-nums;
}
/* ⚠️ 窄屏：底栏本来就紧，数字框收窄一点，别把"生成"按钮挤下去 */
@media (max-width: 768px) {
  .count-num { width: 3.6rem; }
  .count-out { min-width: 2.4rem; }
}
/* ==============================================================
   ★★★ v2.561：把 .spin（转圈）提到【全局】样式表
   --------------------------------------------------------------
   ⚠️ 为什么必须这么做（真实 bug）：
     .spin 原来只定义在 combo.html / ecommerce.html / tool.html
     各自的页内 <style> 里 —— 【不在 style.css】。
     而 common.js 的「模块网格占位卡」在【图片创作页 index.html】也用了
     <div class="spin">，那个页面没有这个类 ⇒ 转圈根本不显示，
     生成中的格子看上去是一片空白（用户反馈过"空空白白"）。
   ⚠️ 兼容说明：
     · combo.html 等页面自己那份定义仍然在（页面内 <style> 优先级更靠前，
       且属性完全一致），所以电商专区的观感【一行都不会变】。
     · 这里用 .spin 同一个类名，不新增类名，避免两套转圈各写各的。
   ============================================================== */
.spin {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  border: 2.5px solid #e5e7eb;
  border-top-color: var(--mc-acc);
  animation: spin 0.8s linear infinite;
  box-sizing: border-box;
  flex: 0 0 auto;
}
/* .spin 用在窄卡片里时（占位卡的预览区）要小一号 */
[data-pending-card] .spin { width: 1.25rem; height: 1.25rem; border-width: 2px; }
/* ==============================================================
   ★★★ v2.564：生图预览（占位卡的模块网格）每行【最多 5 个】
   --------------------------------------------------------------
   用户原话：「这个预览图，每行最多 5 个，超过 5 个就下一行，
              不要排列 6 个或以上，太小了。」
   ⚠️ 原来网格是 auto-fit + minmax(132px, 1fr)：
      右栏一宽就自动排到 6 列，每格只剩 100 多像素，
      卡片里的模块名、状态字、↻ 按钮全被挤没了。
   ⚠️ 为什么用【媒体查询按视口宽度】而不是把 minmax 下限调大：
      这张卡挂在「我的作品」网格里，宽度≈浏览器宽度，
      用视口断点最直接，也不用去动 maxmin 那套自动列数逻辑。
   ⚠️ 只作用于 .pk-grid（占位卡的模块网格），
      不影响作品卡网格（.gallery-grid）和其它页面的任何布局。
   ⚠️ !important 的必要性：列数模板藏在 common.js 拼接的【内联 style】里，
      内联样式优先级高于普通样式表规则 —— 不加 !important 这里根本盖不住。
   ============================================================== */
/* ⚠️⚠️ 列数 = min(模块数, 该宽度下的列数上限)
   --------------------------------------------------------------
   为什么不能直接写 repeat(5, ...)：我第一版就是那么写的，结果
     「1 个模块 → 格子被切成 38px」——
   因为 common.js 还给网格加了一个按模块数算的 max-width
   （1 个模块 = 220px，用来防"单模块被拉伸成巨图"），
   220px 再平均分成 5 列 ⇒ 每列 37.6px（实测到的坏值）。
   ★ 所以两边都要参与取 min：
     · common.js 给 --pk-cols = 模块数
     · 这里把上限压到 5/4/3/2/1
     · min() 取两者较小值 ⇒ 少模块时不被切成细条，多模块时不超过 5 列
   ⚠️ max(1, ...) 兜底：--pk-cols 万一没设（老缓存里的 HTML），
      也至少是 1 列，不会算出 0 列导致格子全没了。
   ⚠️ !important 必须加：列数模板写在 common.js 拼接的【内联 style】里，
      内联样式优先级高于普通样式表规则，不加就盖不住。 */
@media (min-width: 1680px) {
  .pk-grid { grid-template-columns: repeat(max(1, min(var(--pk-cols, 1), 5)), minmax(0, 1fr)) !important; }
}
@media (min-width: 1380px) and (max-width: 1679px) {
  .pk-grid { grid-template-columns: repeat(max(1, min(var(--pk-cols, 1), 4)), minmax(0, 1fr)) !important; }
}
@media (min-width: 1080px) and (max-width: 1379px) {
  .pk-grid { grid-template-columns: repeat(max(1, min(var(--pk-cols, 1), 3)), minmax(0, 1fr)) !important; }
}
@media (min-width: 820px) and (max-width: 1079px) {
  .pk-grid { grid-template-columns: repeat(max(1, min(var(--pk-cols, 1), 2)), minmax(0, 1fr)) !important; }
}
@media (max-width: 819px) {
  .pk-grid { grid-template-columns: repeat(1, minmax(0, 1fr)) !important; }
}
/* ★★★ v2.571：广场/热榜卡片的套图缩略图条
   --------------------------------------------------------------
   ⚠️ 样式【直接复用】.work-row-thumbs 那一套（见上面扩展过的选择器）——
      只有上边距要单独调：广场卡片里它上面是 .gc-img（有灰底封面），
      不像「我的作品」那样贴着文字，所以少一点间距更紧凑。
   ⚠️ 尺寸也调小一点：广场是网格卡片，宽度比整宽列表窄，
      58px 的小方块会把 5 张挤成横向滚动，44px 更合适。
   ⚠️ :empty 时 display:none（复用上面那条）——
      这样异步补拉失败 / 只有 1 张时不会留一条空白。 */
.gc-thumbs { margin-top: 0.45rem; }
.gc-thumbs .wr-thumb { width: 44px; height: 44px; border-radius: 0.4rem; }

/* ==============================================================
   ★★★ v2.573：AI 生成模特（弹窗 + 两个入口按钮）
   --------------------------------------------------------------
   用户要求：「电商专区所有涉及到需要上传模特的，都改这个模式，
              这个功能特别好」（附 MXAI 的截图）。
   ⚠️ 命名统一加 mm- / mdlg- 前缀，避免和页面里已有的 .mask / .dlg
      （那是套图结果弹窗在用的）撞车。这就是这次不重用旧类名的原因。
   ⚠️ 弹窗用 position:fixed + 高 z-index：它可能从深层滚动位置打开，
      必须盖住整页，不能受父容器 overflow 影响。
   ============================================================== */

/* ---------- ① 模特来源的两个入口按钮 ---------- */
.model-src-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
}
.model-src-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.12rem;
  padding: 0.75rem 0.5rem;
  border: 1px dashed #d8dce8;
  border-radius: 0.7rem;
  background: #fafbff;
  cursor: pointer;
  font: inherit;
  transition: border-color .15s, background .15s, transform .15s;
  -webkit-appearance: none; appearance: none;
}
.model-src-btn:hover { border-color: #a78bfa; background: var(--mc-acc-soft); transform: translateY(-1px); }
.model-src-btn.is-ai { border-color: #ddd0ff; background: #f8f5ff; }
.model-src-btn .msb-ico { font-size: 1.25rem; line-height: 1; }
.model-src-btn .msb-t { font-size: 0.82rem; font-weight: 700; color: #4c1d95; }
.model-src-btn .msb-s { font-size: 0.66rem; color: #9ca3af; }
/* ⚠️ 窄屏两列会挤成竖排文字，改成一列 */
@media (max-width: 560px) {
  .model-src-row { grid-template-columns: 1fr; }
}

/* ---------- ② 弹窗遮罩与面板 ---------- */
.mmask {
  position: fixed; inset: 0; z-index: 9000;
  background: rgba(17, 24, 39, 0.45);
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
}
.mdlg {
  width: 100%; max-width: 560px;
  max-height: calc(100vh - 2rem);
  display: flex; flex-direction: column;
  background: #fff;
  border-radius: 1rem;
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}
.mdlg-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.15rem 0.7rem;
  border-bottom: 1px solid #f1f2f6;
}
.mdlg-head h3 { margin: 0; font-size: 1rem; font-weight: 800; color: #1f2937; }
.mdlg-x {
  border: 0; background: transparent; cursor: pointer;
  font-size: 1rem; color: #9ca3af; line-height: 1;
  padding: 0.25rem; border-radius: 0.35rem;
}
.mdlg-x:hover { background: #f3f4f6; color: #4b5563; }
.mdlg-body { padding: 0.9rem 1.15rem; overflow-y: auto; }
.mdlg-foot {
  display: flex; justify-content: flex-end; gap: 0.6rem;
  padding: 0.8rem 1.15rem 1rem;
  border-top: 1px solid #f1f2f6;
}

/* ---------- ③ 五组胶囊选项 ---------- */
.mm-row { margin-bottom: 0.85rem; }
.mm-lbl { font-size: 0.8rem; font-weight: 700; color: #374151; margin-bottom: 0.4rem; }
.mm-lbl-sub { font-weight: 500; color: #9ca3af; font-size: 0.72rem; }
.mm-opts { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.mm-opt {
  padding: 0.32rem 0.8rem;
  border: 1px solid #e5e7eb;
  border-radius: 999px;
  background: #fff;
  font: inherit; font-size: 0.78rem; color: #4b5563;
  cursor: pointer;
  transition: all .15s;
  -webkit-appearance: none; appearance: none;
}
.mm-opt:hover { border-color: #c4b5fd; color: var(--mc-acc-ink); }
/* ⚠️ 选中态要一眼可辨：参考截图里选中的是淡紫底 + 紫边 + 紫字 */
.mm-opt.on {
  border-color: var(--mc-acc); background: var(--mc-acc-soft);
  color: var(--mc-acc-ink); font-weight: 700;
}

/* ---------- ④ 外貌描述框 ---------- */
.mm-desc {
  width: 100%; box-sizing: border-box;
  min-height: 5.6rem; resize: vertical;
  padding: 0.6rem 0.7rem;
  border: 1px solid #e5e7eb; border-radius: 0.6rem;
  font: inherit; font-size: 0.8rem; line-height: 1.65; color: #374151;
  background: #fff;
}
.mm-desc:focus { outline: none; border-color: #a78bfa; box-shadow: 0 0 0 3px rgba(167, 139, 250, .15); }

/* ---------- ⑤ 说明行 / 状态行 / 按钮 ---------- */
.mm-note {
  margin: 0.2rem 0 0;
  padding: 0.5rem 0.65rem;
  border-radius: 0.55rem;
  background: #f8f5ff;
  font-size: 0.74rem; color: #6b7280; line-height: 1.55;
}
.mm-status {
  margin: 0.5rem 0 0; font-size: 0.76rem; line-height: 1.6;
  color: var(--mc-acc-ink); word-break: break-word;
}
.mm-status.bad { color: #b91c1c; }
.mm-btn {
  padding: 0.5rem 1.1rem;
  border: 1px solid #e5e7eb; border-radius: 0.55rem;
  background: #fff; font: inherit; font-size: 0.82rem; color: #4b5563;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: all .15s;
}
.mm-btn:hover { background: #f9fafb; }
.mm-btn.primary {
  border-color: transparent;
  background: linear-gradient(135deg, var(--mc-acc), var(--mc-acc-2));
  color: #fff; font-weight: 700;
}
.mm-btn.primary:hover { filter: brightness(1.06); }
.mm-btn:disabled { opacity: .6; cursor: not-allowed; filter: none; }

/* ==============================================================
   ★★★ v2.585：视频【时长】滑条 + 数字框（MJ 那种样式）
   --------------------------------------------------------------
   用户要求：「这个视频的制作时长，也要改成 MJ 这个样子的」
   （给的截图：左边一根滑条，右边一个数字框，最右一个 s）。
   ⚠️ 为什么另起 .dur-* 而不是直接复用图片创作那套 .count-*：
      两处的排布不同 ——
        · 图片创作：数字框在【左】、箭头在右（要上下箭头）
        · 视频时长：滑条在【左】、数字框在右、单位在最右（不要箭头）
      硬套一套类名会互相牵制，改一个影响另一个。所以分开写，
      但【配色与圆角刻意保持一致】，看起来还是同一套设计语言。
   ⚠️ 数字框去掉了原生 spinner（value 只能是 5/10，用户不该用细箭头调）——
      但仍然可手打，并且会吸附到最接近的合法档位（见 video.js）。
   ============================================================== */
.dur-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.dur-range {
  --fill: 0%;
  flex: 1 1 auto;
  min-width: 0;
  height: 1.5rem;          /* 给 thumb 留点击高度（轨道本身很细） */
  margin: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  outline: none;
}
.dur-range::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  /* 已滑过 = 品牌紫渐变；未滑过 = 浅灰（和图片创作那根一致） */
  background: linear-gradient(90deg, var(--mc-acc) 0%, #6366f1 var(--fill), #e9ecf3 var(--fill), #e9ecf3 100%);
}
.dur-range::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: #e9ecf3;
}
.dur-range::-moz-range-progress {
  height: 4px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--mc-acc), #6366f1);
}
.dur-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 1.05rem;
  height: 1.05rem;
  margin-top: calc((4px - 1.05rem) / 2);   /* 垂直居中对齐轨道 */
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--mc-acc);
  box-shadow: 0 1px 4px var(--mc-acc-59);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.dur-range:hover::-webkit-slider-thumb { transform: scale(1.12); }
.dur-range:active::-webkit-slider-thumb { box-shadow: 0 0 0 6px var(--mc-acc-26); }
.dur-range::-moz-range-thumb {
  width: 1.05rem;
  height: 1.05rem;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--mc-acc);
  box-shadow: 0 1px 4px var(--mc-acc-59);
}
.dur-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 6px var(--mc-acc-26); }
/* ---- 数字框（和图片创作那个同一套配色）---- */
.dur-num {
  flex: 0 0 auto;
  width: 4.2rem;
  height: 2.05rem;
  padding: 0 0.4rem;
  border: 1px solid #e2e6ef;
  /* ★ v2.588：右侧加了三角按钮，所以这里只圆左边两角，
     和按钮拼成一个整体（参考图里就是这样） */
  border-radius: 0.55rem 0 0 0.55rem;
  background: #fff;
  font: inherit;
  font-size: 0.92rem;
  font-weight: 700;
  color: #1f2937;
  text-align: center;
  font-variant-numeric: tabular-nums;
  /* ⚠️ 去掉原生上下箭头：可选项只有 5 / 10，用细箭头点很容易点到非法值；
     手打会被吸附到合法档位（见 video.js 的 snap()）。 */
  -moz-appearance: textfield;
  appearance: textfield;
}
.dur-num::-webkit-outer-spin-button,
.dur-num::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
.dur-num:focus {
  outline: none;
  border-color: #a78bfa;
  box-shadow: 0 0 0 3px var(--mc-acc-26);
}
/* ---- 单位 s ---- */
.dur-unit {
  flex: 0 0 auto;
  font-size: 0.86rem;
  font-weight: 700;
  color: #6b7280;
}

/* ==============================================================
   ★★★ v2.588：视频页「全能参考」的创作辅助三块
   --------------------------------------------------------------
   用户要求：点「全能参考」出现 套用模板 / 添加素材 / 选择人物。
   ⚠️ 布局：三块等宽并排（grid 三列），窄屏自动堆成一列。
   ⚠️ 刻意与页面其它卡片同一套配色（浅底 + 悬停描边变紫），
      不引入新的视觉语言。
   ============================================================== */
.va-grid {
  display: grid;
  /* ★ v2.593：从 3 列改成 2 列 —— MXAI 是一行 2 个，第三个换到第二行。
     ⚠️ 3 列时卡片太窄，副标题（"快速生成提示词与参考"）会被挤成 3 行。 */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}
@media (max-width: 640px) {
  .va-grid { grid-template-columns: 1fr; }
}
.va-card {
  /* ★ v2.593：改成「图标在左、文字在右」——
     ⚠️ 原来是 flex-direction: column（图标在上），和 MXAI 不一样。
     加 .va-tx 包住两行文字后，这里用 row + align-items:center 才对齐。 */
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid #e9ecf3;
  border-radius: 10px;
  background: #fff;
  text-align: left;
  cursor: pointer;
  font: inherit;
  transition: border-color .15s, box-shadow .15s;
}
.va-card:hover {
  border-color: #a78bfa;
  box-shadow: 0 0 0 3px var(--mc-acc-14);
}
.va-card .va-ic { font-size: 1.05rem; line-height: 1.2; }
.va-card b { font-size: 0.82rem; font-weight: 700; color: #1f2937; }
.va-card i { font-style: normal; font-size: 0.7rem; color: #9ca3af; line-height: 1.35; }
/* 选中态：三块里当前展开的那块高亮 */
.va-card.on { border-color: var(--mc-acc); box-shadow: 0 0 0 3px var(--mc-acc-1f); }

/* ---- 素材列表 ---- */
.va-mat-head {
  display: flex; align-items: baseline; gap: .5rem;
  margin: 0.7rem 0 0.4rem; flex-wrap: wrap;
}
.va-mat-head b { font-size: 0.82rem; }
.va-mat-list { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.va-mat-list:empty::before {
  content: '还没有参考素材 —— 点下面的按钮添加';
  font-size: 0.74rem; color: #9ca3af;
}
.va-mat-actions {
  display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem;
}
.va-add {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.35rem 0.65rem;
  border: 1px dashed #d6dbe6;
  border-radius: 8px;
  background: #fafbfd;
  font-size: 0.76rem;
  color: #4b5563;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.va-add:hover { border-color: #a78bfa; color: var(--mc-acc-ink); }
/* 未接通的入口：视觉上明确"还不是现在能用"，避免误以为是坏的 */
.va-soon {
  border-style: dashed;
  color: #9ca3af;
  background: #f7f8fa;
}
.va-soon:hover { border-color: #d6dbe6; color: #6b7280; }

/* 深色主题 */
html[data-theme="dark"] .va-card {
  background: #14181f; border-color: rgba(255,255,255,.1);
}
html[data-theme="dark"] .va-card b { color: #e8eaed; }
html[data-theme="dark"] .va-add {
  background: #14181f; border-color: rgba(255,255,255,.14); color: #b6bcc8;
}
html[data-theme="dark"] .va-soon { background: #101319; color: #6b7280; }
/* ==============================================================
   ★★★ v2.588：视频时长的【上下三角按钮】
   --------------------------------------------------------------
   ⚠️ 用户指出我 v2.585 漏了这个：「只有拖动条和数字，
      上下点击的三角按钮没有」。
   ⚠️ 做法与图片创作的 .count-step 一致（同样是叠在原生 spinner 上），
      但这里数字框已经去掉了原生箭头（appearance: textfield），
      所以不需要负 margin 叠合 —— 直接拼在右边即可。
   ============================================================== */
.dur-steps {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  width: 1.15rem;
}
.dur-step {
  width: 100%;
  height: 1.025rem;          /* 2.05rem 的一半，正好和数字框等高 */
  padding: 0;
  border: 1px solid #e2e6ef;
  border-left: 0;
  background: #f8fafc;
  color: #6b7280;
  font-size: 0.5rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-appearance: none;
  appearance: none;
  transition: background .12s, color .12s;
}
/* ⚠️ 上面那格圆右上角、下面那格圆右下角 —— 整体才像个输入框 */
.dur-step:first-child { border-radius: 0 0.55rem 0 0; border-bottom: 0; }
.dur-step:last-child  { border-radius: 0 0 0.55rem 0; }
.dur-step:hover:not(:disabled) { background: #f1f5f9; color: var(--mc-acc-ink); }
.dur-step:active:not(:disabled) { background: var(--mc-acc-line); }
/* 到边界（4 或 15）时置灰，让用户知道到底了 */
.dur-step:disabled { color: #d1d5db; cursor: not-allowed; }
html[data-theme="dark"] .dur-step {
  background: #14181f; border-color: rgba(255,255,255,.12); color: #b6bcc8;
}
html[data-theme="dark"] .dur-step:disabled { color: #4b5563; }

/* ==============================================================
   ★★★ v2.591：视频页「套用模板」的【模板选择弹窗】
   --------------------------------------------------------------
   用户给了 MXAI 的截图，要求照做：点「套用模板」弹出「素材库」，
   里面有 三个 tab + 分类筛选 + 卡片网格。

   ⚠️ 复用 common.js 的 .ui-cf-mask / .ui-cf-box / .ui-cf-head 体系，
      只把宽度放大（默认 24rem 放不下网格）并补内部的 tab/卡片样式。
   ⚠️ 为什么不用 <dialog>：项目里所有弹窗都是这套 ui-cf-*，
      换标签会让屏蔽层、动画、ESC 处理都要重写一遍。
   ============================================================== */
/* ★ v2.595：弹窗从 52rem 加宽到 68rem（用户反馈"有点小"）
   ⚠️ 参考站（MXAI）的弹窗几乎占满内容区，我们的只有它一半宽。
      加宽之后 13rem 的卡片能排 4 列，接近参考站的密度。 */
.vp-tpl-box { max-width: 68rem; width: 100%; }
.vp-tpl-x {
  margin-left: auto;
  border: 0; background: transparent;
  font-size: 1rem; line-height: 1;
  color: #9ca3af; cursor: pointer;
  padding: 0.2rem 0.35rem; border-radius: 6px;
  -webkit-appearance: none; appearance: none;
}
.vp-tpl-x:hover { background: #f3f4f6; color: #4b5563; }

/* ---- 三个 tab（模板库 / 素材库 / 虚拟人像库）---- */
.vp-tpl-tabs {
  display: flex; gap: 0.35rem;
  padding: 0 1.1rem 0.2rem;
  border-bottom: 1px solid var(--mc-line);
}
.vp-tpl-tab {
  flex: 1 1 0;
  padding: 0.5rem 0.4rem;
  border: 0; background: transparent;
  border-radius: 8px 8px 0 0;
  font: inherit; font-size: 0.84rem; font-weight: 700;
  color: #6b7280; cursor: pointer;
  border-bottom: 2px solid transparent;
  -webkit-appearance: none; appearance: none;
}
.vp-tpl-tab:hover { color: var(--mc-acc-ink); background: #f8f7ff; }
.vp-tpl-tab.on { color: var(--mc-acc-ink); border-bottom-color: var(--mc-acc); background: #f8f7ff; }

/* ---- 分类筛选胶囊（全部 / 早安 / 春节 …）---- */
.vp-tpl-cats {
  display: flex; flex-wrap: wrap; gap: 0.4rem;
  padding: 0.7rem 1.1rem 0.2rem;
}
.vp-tpl-cats:empty { display: none; }
.vp-tpl-cat {
  padding: 0.28rem 0.7rem;
  border: 1px solid #e2e6ef; border-radius: 999px;
  background: #fff; font: inherit; font-size: 0.76rem;
  color: #4b5563; cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
.vp-tpl-cat:hover { border-color: #a78bfa; color: var(--mc-acc-ink); }
.vp-tpl-cat.on { background: var(--mc-acc); border-color: var(--mc-acc); color: #fff; font-weight: 700; }

/* ---- 卡片网格 ---- */
.vp-tpl-body { max-height: 62vh !important; padding: 0.8rem 1.2rem 1.2rem !important; }
/* ★ v2.595：网格放大 —— 卡片从 11rem 提到 13rem（配合弹窗加宽）
   ⚠️ 用户反馈「弹窗有点小、模板有点敷衍」：
      原来的卡只有一条窄色条 + 小字，缩略图生成后图会占卡片上部整块，
      所以这里把最小宽度放大，让图有足够的表现空间。 */
.vp-tpl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0.85rem;
}
.vp-tpl-card {
  display: flex; flex-direction: column;
  padding: 0; border: 1px solid #e9ecf3; border-radius: 12px;
  background: #fff; overflow: hidden; cursor: pointer;
  text-align: left; font: inherit;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.vp-tpl-card:hover {
  border-color: #a78bfa;
  box-shadow: 0 8px 22px var(--mc-acc-24);
  transform: translateY(-2px);
}
/* 缩略图位：卡片上部整块。
   ⚠️ 有图就显示图（后端用生图接口生成的真缩略图，缓存在存储层）；
      没有图时不放任何假图，用"还没有缩略图"的明确提示 ——
      绝不能看起来像加载失败或者像假封面。 */
.vp-tpl-thumb {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  height: 8.6rem;                       /* 和图一起撑起卡片，比原来高近一倍 */
  background: #f3f4f6;                  /* 没图时的中性底，不是彩色假图 */
  overflow: hidden;
}
.vp-tpl-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;                    /* 裁满、不留白边 */
  display: block;
}
.vp-tpl-pending {
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  color: #9ca3af;
}
.vp-tpl-pending i { font-style: normal; font-size: 1.5rem; opacity: .6; }
.vp-tpl-pending em { font-style: normal; font-size: 0.7rem; }
/* 分类角标：压在缩略图左下角 */
.vp-tpl-tag {
  position: absolute; left: 0.45rem; bottom: 0.4rem;
  font-style: normal; font-size: 0.68rem; font-weight: 700;
  color: #fff; padding: 0.05rem 0.4rem; border-radius: 999px;
  background: rgba(17, 24, 39, 0.55);
  backdrop-filter: blur(3px);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
/* 提示词：3 行截断（点击整卡即套用） */
.vp-tpl-text {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
  padding: 0.5rem 0.6rem 0.6rem;
  font-size: 0.74rem; line-height: 1.5; color: #4b5563;
}

/* ---- 未接通的 tab 提示 ---- */
.vp-tpl-empty {
  display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
  padding: 2.6rem 1rem; text-align: center;
}
.vp-tpl-empty span { font-size: 1.6rem; }
.vp-tpl-empty b { font-size: 0.9rem; color: #374151; }
.vp-tpl-empty p { margin: 0; font-size: 0.8rem; color: #6b7280; line-height: 1.7; }

/* 深色主题 */
html[data-theme="dark"] .vp-tpl-tabs { border-bottom-color: rgba(255,255,255,.08); }
html[data-theme="dark"] .vp-tpl-tab { color: #9ca3af; }
html[data-theme="dark"] .vp-tpl-tab.on { color: #c4b5fd; background: #1b1a2e; }
html[data-theme="dark"] .vp-tpl-cat { background: #14181f; border-color: rgba(255,255,255,.12); color: #b6bcc8; }
html[data-theme="dark"] .vp-tpl-card { background: #14181f; border-color: rgba(255,255,255,.1); }
html[data-theme="dark"] .vp-tpl-text { color: #b6bcc8; }
html[data-theme="dark"] .vp-tpl-empty b { color: #e8eaed; }
/* ★ v2.593：卡片里包住两行文字的容器（图标在左时必需） */
.va-tx { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.va-tx b { font-size: 0.82rem; font-weight: 700; color: #1f2937; }
.va-tx i { font-style: normal; font-size: 0.7rem; color: #9ca3af; line-height: 1.35; }
html[data-theme="dark"] .va-tx b { color: #e8eaed; }
/* ⚠️ 图标不要被压扁（flex 子项默认可收缩） */
.va-card .va-ic { flex: 0 0 auto; }

/* ★ v2.593：批量压缩里的"中性提示"（既不是成功也不是失败）
   例如「已是原图（压不小）」「已经很小了，压不动」——
   ⚠️ 不用红色：那不是错误；也不用绿色：那会让人以为压缩成功了。 */
.ib-muted { color: #6b7280; font-weight: 700; }
/* ★★★ v2.595：模板库顶部工具条（缩略图进度 / 生成按钮） */
.vp-tpl-bar {
  display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
  padding: 0.55rem 1.2rem 0.2rem;
}
.vp-tpl-bar:empty { display: none; }
.vp-tpl-hint { font-size: 0.78rem; color: #6b7280; font-weight: 700; }
.vp-tpl-tip { font-size: 0.74rem; color: #9ca3af; }
.vp-tpl-prog { font-size: 0.78rem; color: var(--mc-acc-ink); font-weight: 700; }
.vp-tpl-gen {
  padding: 0.36rem 0.85rem;
  border: 0; border-radius: 8px;
  background: linear-gradient(135deg, var(--mc-acc), #6366f1);
  color: #fff; font: inherit; font-size: 0.8rem; font-weight: 700;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  box-shadow: 0 2px 8px var(--mc-acc-33);
}
.vp-tpl-gen:hover { filter: brightness(1.08); }
.vp-tpl-gen:disabled { opacity: .55; cursor: not-allowed; filter: none; }
html[data-theme="dark"] .vp-tpl-hint { color: #9ca3af; }
html[data-theme="dark"] .vp-tpl-thumb { background: #1b2029; }
html[data-theme="dark"] .vp-tpl-pending { color: #6b7280; }
/* ============================================================
   ★★★ v2.600：视频页「分辨率」+「尺寸比例」（照参考站 MJ/MXAI）
   ------------------------------------------------------------
   ⚠️ 分辨率是【胶囊按钮】、比例是【带形状预览的方块】。
      形状按真实比例画（CSS aspect-ratio），用户一眼看出 21:9 与 9:16 的差别。
   ⚠️ 按钮本身由 video.js 按【当前平台能力表】渲染 ——
      这里只管外观，不管有哪些（可灵没有 480p、不认 21:9）。
   ⚠️ 所有选择器都以 .res- / .ratio- 开头 + 只作用于这两个容器，
      不碰全局（.chip 之类全站复用，改了会连带别处）。
   ============================================================ */

/* ---------- 分辨率胶囊 ---------- */
.res-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.res-btn {
  flex: 1 1 0; min-width: 5.2rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid #e5e7eb; border-radius: 0.6rem;
  background: #fff; color: #374151;
  font: inherit; font-size: 0.86rem; font-weight: 700;
  cursor: pointer; text-align: center;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s, color .15s, box-shadow .15s, background .15s;
}
.res-btn:hover { border-color: #c4b5fd; }
.res-btn.active {
  border-color: var(--mc-acc); color: var(--mc-acc-ink);
  background: var(--mc-acc-soft);
  box-shadow: 0 0 0 1px var(--mc-acc) inset;
}
.res-hint { margin: 0.35rem 0 0; font-size: 0.72rem; color: #9ca3af; }
.res-hint:empty { display: none; }

/* ---------- 尺寸比例方块 ---------- */
.ratio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.2rem, 1fr));
  gap: 0.5rem;
}
.ratio-btn {
  display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
  padding: 0.55rem 0.35rem 0.4rem;
  border: 1px solid #e5e7eb; border-radius: 0.6rem;
  background: #fff; color: #374151;
  font: inherit; cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s, color .15s, box-shadow .15s, background .15s;
}
.ratio-btn:hover { border-color: #c4b5fd; }
.ratio-btn.active {
  border-color: var(--mc-acc); color: var(--mc-acc-ink);
  background: var(--mc-acc-soft);
  box-shadow: 0 0 0 1px var(--mc-acc) inset;
}
/* 形状框：固定外框，里面的小方块按真实比例缩放。
   ⚠️ 不固定外框的话，21:9 会撑得特别宽、9:16 特别高，网格会高低不齐。 */
.ratio-shape {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 2.1rem;
}
.ratio-shape i {
  display: block;
  max-width: 100%; max-height: 100%;
  background: currentColor;              /* 跟着按钮文字色变（选中变紫） */
  border-radius: 2px;
  opacity: .78;
}
/* 形状的"最大边"约束：按比例算出来之后不超出这个框 */
.ratio-shape i { width: auto; height: 100%; }
.ratio-btn[data-value="21:9"] .ratio-shape i,
.ratio-btn[data-value="16:9"] .ratio-shape i,
.ratio-btn[data-value="4:3"]  .ratio-shape i { height: auto; width: 100%; }
.ratio-label { font-size: 0.74rem; font-weight: 700; line-height: 1; }
.ratio-hint { margin: 0.35rem 0 0; font-size: 0.72rem; color: #9ca3af; }
.ratio-hint:empty { display: none; }

/* 深色主题 */
html[data-theme="dark"] .res-btn,
html[data-theme="dark"] .ratio-btn { background: #171b22; border-color: #2b313b; color: #cbd5e1; }
html[data-theme="dark"] .res-btn.active,
html[data-theme="dark"] .ratio-btn.active { background: #241a3d; border-color: var(--mc-acc); color: #c4b5fd; }
/* ============================================================
   ★★★ v2.604：素材库 / 虚拟人像库（视频创作弹窗的两个 tab）
   ------------------------------------------------------------
   ⚠️ 全部以 .vp-mat- / .vp-per- 前缀限定，不碰全局类名。
   ⚠️ 颜色沿用已有 token（紫 var(--mc-acc) / 灰 #e9ecf3 / 文字 #6b7280），
      不引新的视觉语言。
   ============================================================ */

/* ---------- 素材库 ---------- */
.vp-mat-top { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; padding: 0.2rem 0 0.5rem; }
.vp-mat-up {
  padding: 0.5rem 1rem; border: 0; border-radius: 9px;
  background: linear-gradient(135deg, var(--mc-acc), #6366f1);
  color: #fff; font: inherit; font-size: 0.86rem; font-weight: 800;
  cursor: pointer; box-shadow: 0 2px 10px var(--mc-acc-33);
  -webkit-appearance: none; appearance: none;
}
.vp-mat-up:hover { filter: brightness(1.07); }
.vp-mat-up:disabled { opacity: .6; cursor: not-allowed; filter: none; }
.vp-mat-hint { font-size: 0.76rem; color: #9ca3af; }
.vp-mat-clear {
  margin-left: auto; padding: 0.35rem 0.7rem;
  border: 1px solid #e5e7eb; border-radius: 8px;
  background: #fff; color: #6b7280; font: inherit; font-size: 0.76rem; font-weight: 700;
  cursor: pointer;
}
.vp-mat-clear:hover { border-color: #fca5a5; color: #b91c1c; }
.vp-mat-chips { display: flex; gap: 0.4rem; flex-wrap: wrap; padding-bottom: 0.6rem; }
.vp-mat-chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.3rem 0.7rem; border: 1px solid #e5e7eb; border-radius: 999px;
  background: #fff; color: #374151; font: inherit; font-size: 0.8rem; font-weight: 700;
  cursor: pointer;
}
.vp-mat-chip i { font-style: normal; font-size: 0.72rem; color: #9ca3af; }
.vp-mat-chip.on { border-color: var(--mc-acc); color: var(--mc-acc-ink); background: var(--mc-acc-soft); }
.vp-mat-chip.on i { color: var(--mc-acc); }
.vp-mat-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(8.4rem, 1fr)); gap: 0.6rem;
}
.vp-mat-card {
  position: relative; display: flex; flex-direction: column;
  border: 1px solid #e9ecf3; border-radius: 10px; overflow: hidden; background: #fff;
}
.vp-mat-card:hover { border-color: #c4b5fd; }
/* ★★★ v2.882：素材卡片的"可点"视觉 —— 用户报「素材无法选定」。
   ⚠️ 原来卡片【没有 pointer 光标、没有选中态】，看起来就是个纯展示块，
      用户根本不知道它能不能点（点了也没反应 ⇒ 只能认为坏了）。
   ⇒ 加上手型光标 + 两种状态：读取中 / 已选中。
   ⚠️ 已选中必须【一眼看得出来】（边框变紫 + ✓ 角标），否则用户不知道
      "我到底选上没有" —— 而这正是他报"无法选定"时的困惑点。 */
.vp-mat-card { cursor: pointer; transition: border-color .15s, box-shadow .15s; }
.vp-mat-card.is-picking { border-color: #a78bfa; opacity: .7; cursor: progress; }
.vp-mat-card.is-picked {
  border-color: #7c3aed; box-shadow: 0 0 0 2px rgba(124, 58, 237, .18);
}
.vp-mat-pick {
  position: absolute; top: 4px; right: 4px; z-index: 2;
  background: #7c3aed; color: #fff; font-size: .68rem; font-weight: 600;
  padding: 1px 6px; border-radius: 999px; pointer-events: none;
}
.vp-mat-thumb {
  position: relative; display: flex; align-items: center; justify-content: center;
  height: 5.6rem; background: #f3f4f6; overflow: hidden;
}
.vp-mat-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vp-mat-ico { font-size: 1.7rem; opacity: .75; }
/* ---- ★ v2.868：素材库「显示更多」 ----
   🔴 为什么要有它：列表原来一次渲染 200 条、每条一张【原图】⇒ 浏览器连接池被占满
      ⇒ 连菜单都加载不出来（用户报「这个功能不行重做吧」的根因）。
   现在一次 24 条，剩下的靠这个按钮按需加载；配合后端缩略图，首屏从最坏 1GB 降到 ~500KB。
   ⚠️ 样式做成【整行居中的虚线块】而不是小按钮：
      它是"继续往下看"的入口，视觉上应该像"下面还有内容"。
      做成小按钮会被当成次要操作、用户找不到 → 以为素材丢了。 */
.vp-mat-more { margin: .7rem 0 .2rem; text-align: center; }
.vp-mat-more button {
  width: 100%; padding: .55rem; font: inherit; font-size: .8rem; font-weight: 700;
  color: #6d28d9; background: #faf5ff; border: 1px dashed #d8b4fe;
  border-radius: 10px; cursor: pointer; transition: background .15s, border-color .15s;
}
.vp-mat-more button:hover { background: #f3e8ff; border-color: #a78bfa; }
.vp-mat-more span { font-size: .74rem; color: #9ca3af; }
html[data-theme="dark"] .vp-mat-more button { background: #1a1530; border-color: #4c1d95; color: #c4b5fd; }
html[data-theme="dark"] .vp-mat-more button:hover { background: #241a3d; }
.vp-mat-thumb em {
  position: absolute; left: 0.35rem; bottom: 0.3rem;
  font-style: normal; font-size: 0.66rem; font-weight: 700; color: #fff;
  padding: 0.05rem 0.35rem; border-radius: 999px; background: rgba(17, 24, 39, 0.55);
}
.vp-mat-meta {
  display: flex; flex-direction: column; gap: 0.1rem;
  padding: 0.35rem 0.45rem 0.45rem;
  font-size: 0.74rem; font-weight: 700; color: #374151;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vp-mat-meta i { font-style: normal; font-size: 0.68rem; font-weight: 500; color: #9ca3af; }
.vp-mat-del {
  position: absolute; right: 0.25rem; top: 0.25rem;
  width: 1.25rem; height: 1.25rem; border: 0; border-radius: 50%;
  background: rgba(17, 24, 39, 0.5); color: #fff; font-size: 0.7rem; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.vp-mat-del:hover { background: #dc2626; }

/* ---------- 虚拟人像库 ---------- */
.vp-per-filters {
  display: flex; gap: 0.45rem; flex-wrap: wrap; align-items: center;
  padding: 0.2rem 0 0.7rem;
}
.vp-per-sel {
  padding: 0.32rem 0.5rem; border: 1px solid #e5e7eb; border-radius: 8px;
  background: #fff; color: #374151; font: inherit; font-size: 0.8rem; font-weight: 600;
  cursor: pointer; min-width: 5.2rem;
}
.vp-per-sel:focus { outline: none; border-color: var(--mc-acc); box-shadow: 0 0 0 2px var(--mc-acc-22); }
.vp-per-cnt { margin-left: auto; font-size: 0.76rem; color: #9ca3af; }
.vp-per-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: 0.6rem;
}
.vp-per-card {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.55rem 0.65rem; border: 1px solid #e9ecf3; border-radius: 11px;
  background: #fff; cursor: pointer; text-align: left; font: inherit;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.vp-per-card:hover { border-color: #a78bfa; box-shadow: 0 6px 16px var(--mc-acc-1f); transform: translateY(-1px); }
.vp-per-face {
  flex: 0 0 auto; width: 2.6rem; height: 2.6rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  background: linear-gradient(135deg, #a78bfa, var(--mc-acc));
}
.vp-per-face img { width: 100%; height: 100%; object-fit: cover; }
.vp-per-face-tx { font-size: 1.05rem; font-weight: 800; color: #fff; }
.vp-per-body { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.vp-per-body b { font-size: 0.86rem; font-weight: 800; color: #1f2937; }
.vp-per-body i { font-style: normal; font-size: 0.72rem; color: #6b7280; }
.vp-per-body em {
  font-style: normal; font-size: 0.7rem; color: #9ca3af;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vp-per-tip { margin: 0.7rem 0 0; font-size: 0.74rem; color: #9ca3af; line-height: 1.7; }

/* 深色主题 */
html[data-theme="dark"] .vp-mat-chip,
html[data-theme="dark"] .vp-mat-card,
html[data-theme="dark"] .vp-mat-clear,
html[data-theme="dark"] .vp-per-sel,
html[data-theme="dark"] .vp-per-card { background: #171b22; border-color: #2b313b; color: #cbd5e1; }
html[data-theme="dark"] .vp-mat-chip.on { background: #241a3d; border-color: var(--mc-acc); color: #c4b5fd; }
html[data-theme="dark"] .vp-mat-thumb { background: #1b2029; }
html[data-theme="dark"] .vp-mat-meta { color: #cbd5e1; }
html[data-theme="dark"] .vp-per-body b { color: #e5e7eb; }
/* ============================================================
   ★ v2.606：参考素材区的【独立展开按钮】
   ------------------------------------------------------------
   ⚠️ 之前这块由「添加素材」控制展开；现在「添加素材」改成打开素材库弹窗，
      所以展开功能搬到这里自己的按钮上（两个入口各司其职）。
   ============================================================ */
.va-ref-row {
  display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap;
  margin-top: 0.55rem;
}
.va-ref-toggle {
  padding: 0.42rem 0.85rem;
  border: 1px dashed #c4b5fd; border-radius: 9px;
  background: #faf5ff; color: var(--mc-acc-ink);
  font: inherit; font-size: 0.82rem; font-weight: 700;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s, background .15s, color .15s;
}
.va-ref-toggle:hover { border-color: var(--mc-acc); background: var(--mc-acc-soft); }
.va-ref-toggle.on { border-style: solid; border-color: var(--mc-acc); background: var(--mc-acc-soft); }
html[data-theme="dark"] .va-ref-toggle { background: #1e1630; border-color: #4c3a7a; color: #c4b5fd; }
/* ============================================================
   ★ v2.610：素材库「我的素材 / 公共素材」来源切换
   ------------------------------------------------------------
   ⚠️ 和"图片/视频/音频"筛选是两个维度：
      source = 看谁的（自己传的 / 平台给的）
      kind   = 看哪类
      两者视觉上要能区分开，否则用户会以为是同一层筛选。
   ============================================================ */
.vp-mat-src {
  display: flex; gap: .35rem; padding: .1rem 0 .55rem;
  border-bottom: 1px solid #f1f3f8; margin-bottom: .55rem;
}
.vp-mat-srcbtn {
  padding: .38rem .9rem;
  border: 1px solid #e5e7eb; border-radius: 999px;
  background: #fff; color: #6b7280;
  font: inherit; font-size: .84rem; font-weight: 800;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s, color .15s, background .15s;
}
.vp-mat-srcbtn:hover { border-color: #c4b5fd; }
.vp-mat-srcbtn.on {
  border-color: var(--mc-acc); color: var(--mc-acc-ink); background: var(--mc-acc-soft);
  box-shadow: 0 0 0 1px var(--mc-acc) inset;
}
html[data-theme="dark"] .vp-mat-srcbtn { background: #171b22; border-color: #2b313b; color: #9ca3af; }
html[data-theme="dark"] .vp-mat-srcbtn.on { background: #241a3d; border-color: var(--mc-acc); color: #c4b5fd; }
html[data-theme="dark"] .vp-mat-src { border-bottom-color: #232833; }
/* ============================================================
   ★ v2.612：广告规格选择器 + 出血/安全区预览（shop 页）
   ------------------------------------------------------------
   ⚠️ 全部以 .adspec- 前缀限定，不碰全站类名。
   ⚠️ 三种颜色是【语义色】，和 canvas 里画的一致：
        红 = 裁切线（外面会被切掉）
        绿 = 安全区（文字放这里）
        黄 = 两线之间（别放重要内容）
      改这里必须同时改 adspec.js 里的颜色，否则图例和图上对不上。
   ============================================================ */
.adspec-box {
  border: 1px solid #e9ecf3; border-radius: 12px;
  padding: .8rem .9rem; margin-top: .9rem; background: var(--mc-card-2);
}
.adspec-head { display: flex; align-items: center; justify-content: space-between; gap: .6rem; flex-wrap: wrap; }
.adspec-tip { font-weight: 400; color: #9ca3af; font-size: .78rem; }
.adspec-clear {
  border: 1px solid #e5e7eb; background: #fff; color: #6b7280;
  border-radius: 999px; padding: .2rem .7rem;
  font: inherit; font-size: .78rem; cursor: pointer;
}
.adspec-clear:hover { border-color: #c4b5fd; color: var(--mc-acc-ink); }
.adspec-row { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .6rem; }
.adspec-row .field { flex: 0 1 auto; }
.adspec-meta {
  display: flex; flex-wrap: wrap; gap: .3rem .75rem;
  margin-top: .6rem; font-size: .78rem; color: #6b7280;
}
.adspec-kv { white-space: nowrap; }
.adspec-kv b { color: #111827; }
.adspec-preview { display: flex; gap: .9rem; align-items: flex-start; flex-wrap: wrap; margin-top: .7rem; }
.adspec-preview canvas {
  border: 1px solid #e9ecf3; border-radius: 8px; background: #fff;
  max-width: 100%; height: auto;
}
.adspec-legend { display: flex; flex-direction: column; gap: .3rem; font-size: .78rem; color: #6b7280; }
.adspec-dot { display: inline-block; width: .55rem; height: .55rem; border-radius: 50%; margin-right: .3rem; }
.adspec-dot-red   { background: #ef4444; }
.adspec-dot-green { background: #22c55e; }
.adspec-dot-amber { background: #f59e0b; }
html[data-theme="dark"] .adspec-box { background: #14181f; border-color: #2b313b; }
html[data-theme="dark"] .adspec-preview canvas { background: #0f1319; border-color: #2b313b; }
html[data-theme="dark"] .adspec-clear { background: #171b22; border-color: #2b313b; color: #9ca3af; }
html[data-theme="dark"] .adspec-kv b { color: #e5e7eb; }
/* ============================================================
   ★ v2.613：一刀多尺寸面板（S1-3 界面层）
   ------------------------------------------------------------
   ⚠️ 全部以 .adx- 前缀限定，不碰全站类名。
   ⚠️ 面板里直接显示真实 canvas（不是图片），所以样式要保证
      画布不被拉伸变形：width:100% + height:auto。
   ============================================================ */
.adx-mask {
  position: fixed; inset: 0; z-index: 9000;
  background: rgba(15,19,25,.62);
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
}
.adx-mask.hidden { display: none; }
.adx-box {
  width: 100%; max-width: 62rem; max-height: 88vh;
  background: #fff; border-radius: 14px; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 18px 50px rgba(0,0,0,.32);
}
.adx-head {
  display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap;
  padding: .85rem 1rem; border-bottom: 1px solid var(--mc-line);
}
.adx-head b { font-size: 1rem; }
.adx-sub { color: #6b7280; font-size: .82rem; }
.adx-x {
  margin-left: auto; border: 0; background: transparent; cursor: pointer;
  font-size: 1rem; color: #9ca3af; padding: .2rem .5rem; border-radius: .4rem;
}
.adx-x:hover { background: #f3f4f6; color: #374151; }
.adx-body { padding: .9rem 1rem; overflow: auto; flex: 1 1 auto; }
.adx-loading { padding: 2rem 0; text-align: center; color: #9ca3af; font-size: .88rem; line-height: 1.9; }
.adx-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: .8rem; }
.adx-item {
  border: 1px solid #e9ecf3; border-radius: 11px; overflow: hidden;
  background: #fbfcfe; transition: border-color .15s, box-shadow .15s;
}
.adx-item.on { border-color: var(--mc-acc); box-shadow: 0 0 0 2px var(--mc-acc-22); }
.adx-pick {
  display: flex; align-items: center; gap: .4rem;
  padding: .45rem .6rem; font-size: .82rem; cursor: pointer;
  border-bottom: 1px solid #f1f3f8;
}
.adx-thumb { background: #fff; display: flex; align-items: center; justify-content: center; min-height: 5rem; }
.adx-meta { padding: .35rem .6rem .5rem; font-size: .72rem; color: #9ca3af; }
.adx-meta i { font-style: normal; color: #059669; margin-left: .35rem; }
.adx-meta i.adx-pure { color: #cbd5e1; }
.adx-foot {
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  padding: .7rem 1rem; border-top: 1px solid var(--mc-line); background: #fbfcfe;
}
.adx-all { font-size: .84rem; display: flex; align-items: center; gap: .3rem; cursor: pointer; }
.adx-note { font-size: .78rem; color: #6b7280; flex: 1 1 10rem; }
.adx-btn {
  padding: .5rem 1.1rem; border: 0; border-radius: 9px;
  color: #fff; font: inherit; font-weight: 800; cursor: pointer; font-size: .86rem;
  background: linear-gradient(135deg, var(--mc-acc), #6366f1);
  box-shadow: 0 2px 10px var(--mc-acc-33);
}
.adx-btn:disabled { opacity: .55; cursor: not-allowed; }
html[data-theme="dark"] .adx-box { background: #14181f; }
html[data-theme="dark"] .adx-head,
html[data-theme="dark"] .adx-foot { border-color: #232833; background: #171b22; }
html[data-theme="dark"] .adx-item { background: #171b22; border-color: #2b313b; }
html[data-theme="dark"] .adx-thumb { background: #0f1319; }
html[data-theme="dark"] .adx-sub,
html[data-theme="dark"] .adx-meta { color: #9ca3af; }
/* ============================================================
   ★ v2.614：文字程序绘制面板（S1-4 界面层）
   ------------------------------------------------------------
   ⚠️ 外壳复用 .adx-（和一刀多尺寸同一个面板），
      这里只补文字面板【特有】的两栏布局与控件。
   ⚠️ 预览画布必须是 width:100% + height:auto ——
      否则宽高比会被 CSS 拉歪，所见即所得就失效了。
   ============================================================ */
.adx-t-grid { display: flex; gap: 1rem; align-items: flex-start; flex-wrap: wrap; }
.adx-t-form { flex: 1 1 17rem; min-width: 15rem; }
.adx-t-prev { flex: 1 1 15rem; min-width: 13rem; }
.adx-t-lb { display: block; font-size: .78rem; font-weight: 700; color: #374151; margin: .55rem 0 .25rem; }
.adx-t-lb:first-child { margin-top: 0; }
.adx-t-tip { font-weight: 400; color: #9ca3af; }
.adx-t-in {
  width: 100%; padding: .45rem .55rem; border: 1px solid #e5e7eb; border-radius: .45rem;
  font: inherit; font-size: .88rem; box-sizing: border-box;
}
.adx-t-in:focus { outline: none; border-color: var(--mc-acc); box-shadow: 0 0 0 2px var(--mc-acc-22); }
.adx-t-row { display: flex; align-items: center; gap: .45rem; margin-top: .6rem; flex-wrap: wrap; }
.adx-t-lb2 { font-size: .78rem; font-weight: 700; color: #374151; }
.adx-chip {
  padding: .28rem .7rem; border: 1px solid #e5e7eb; border-radius: 999px;
  background: #fff; color: #6b7280; font: inherit; font-size: .8rem; cursor: pointer;
}
.adx-chip.on { border-color: var(--mc-acc); color: var(--mc-acc-ink); background: var(--mc-acc-soft); }
.adx-swatch {
  width: 1.5rem; height: 1.5rem; border-radius: 50%; cursor: pointer;
  border: 2px solid #e5e7eb; padding: 0;
}
.adx-swatch.on { border-color: var(--mc-acc); box-shadow: 0 0 0 2px var(--mc-acc-33); }
.adx-t-scale { display: flex; align-items: center; gap: .4rem; margin-top: .7rem; font-size: .78rem; color: #374151; }
.adx-t-scale input[type="range"] { flex: 1 1 auto; }
.adx-t-note { margin-top: .5rem; font-size: .75rem; color: #9ca3af; line-height: 1.7; }
.adx-t-canvas { display: block; width: 100%; height: auto; border-radius: 6px; }
html[data-theme="dark"] .adx-t-lb,
html[data-theme="dark"] .adx-t-lb2,
html[data-theme="dark"] .adx-t-scale { color: #d1d5db; }
html[data-theme="dark"] .adx-t-in { background: #171b22; border-color: #2b313b; color: #e5e7eb; }
html[data-theme="dark"] .adx-chip { background: #171b22; border-color: #2b313b; color: #9ca3af; }
html[data-theme="dark"] .adx-chip.on { background: #241a3d; border-color: var(--mc-acc); color: #c4b5fd; }

/* ============================================================
   ★ v2.615：规格说明面板（S1-5 界面层）
   ------------------------------------------------------------
   ⚠️ 说明正文用 <pre>：它自带换行与空格保留，
      后端生成的是"排好版的纯文本"，用 div 会把缩进和空行吃掉。
   ⚠️ 必须设 white-space: pre-wrap —— 不然长行会横向滚出去。
   ============================================================ */
.adspec-head-btns { display: inline-flex; gap: .4rem; flex-wrap: wrap; }
.adx-g-text {
  margin: 0; padding: .9rem 1rem;
  background: #f8fafc; border: 1px solid #e9ecf3; border-radius: 10px;
  font-family: Consolas, "Courier New", "Microsoft YaHei", monospace;
  font-size: .82rem; line-height: 1.85; color: #111827;
  white-space: pre-wrap; word-break: break-word;
  max-height: 52vh; overflow: auto;
}
.adx-btn-ghost {
  background: #fff; color: #374151; border: 1px solid #e5e7eb;
  box-shadow: none;
}
.adx-btn-ghost:hover { border-color: #c4b5fd; color: var(--mc-acc-ink); }
html[data-theme="dark"] .adx-g-text { background: #0f1319; border-color: #2b313b; color: #e5e7eb; }
html[data-theme="dark"] .adx-btn-ghost { background: #171b22; border-color: #2b313b; color: #d1d5db; }

/* ============================================================
   ★ v2.624：个人弹窗「炫酷化」+ 邀请奖励卡片
   ------------------------------------------------------------
   ⚠️ 这是【追加增强】，不是重写：
      原来 .up-head / .up-sec / .up-card 等规则都保留，
      这里只在后面覆盖/补充，避免影响其他用到这些类名的地方。
   ⚠️ 视觉方向：参考用户给的参考站（樱桃 AI）——
      卡片化、渐变色、圆角、轻投影，但【不堆花哨动效】
      （弹窗是高频操作入口，动效多了会烦）。
   ============================================================ */

/* ---- 顶部：头像加渐变光环，ID 行更清楚 ---- */
.up-head { position: relative; }
.up-avatar {
  background: linear-gradient(135deg, var(--mc-acc), #6366f1 55%, #06b6d4);
  box-shadow: 0 3px 12px rgba(124, 58, 237, .32);
}
.up-name { letter-spacing: .2px; }

/* ---- 账户卡片：积分卡给个渐变，让它成为视觉重心 ---- */
.up-cards .up-card:first-child {
  background: linear-gradient(135deg, #faf5ff, #eef2ff);
  border-color: var(--mc-acc-line);
}
.up-cards .up-card:first-child b { font-size: 1.15rem; color: #5b21b6; }

/* ---- ★ 奖励活动区：签到 + 邀请 并列成两张卡 ---- */
/* ★★ v2.702：奖励活动【改成上下两行】
   ------------------------------------------------------------
   🔴 用户反馈（原话）：「这两块太大了，你可以分成两行，
      或者按钮的高度调整一下」
   ★ 根因：原来是 grid 1fr 1fr（两卡各占一半宽）。
      而每张卡里有 4~5 块内容（图标 / 标题 / 说明 / 数据 / 按钮）——
      在约 160px 的宽度里反复折行 ⇒ 卡片被撑得很高，下半截是空的。
   ★ 改法（两行 + 卡内改横排）：
      · 一行一卡 ⇒ 可用宽度翻倍，说明文字不再折成 3 行
      · 卡内从"图标在左、内容在右"改成【图标 + 标题 + 数据在上一行、
        按钮在右】（.up-rw 用 flex-wrap + 图标竖排）
   ⚠️ 单独占一行后卡片会变【矮】，不是变高 —— 因为不再折行。
   ⚠️ 两卡仍有颜色区分（橙 = 签到 / 品红 = 邀请），只是不再并排。 */
.up-rewards { display: grid; grid-template-columns: 1fr; gap: .35rem; margin-top: .5rem; }
.up-rw {
  position: relative; display: flex; gap: .4rem;
  /* ★ v2.702：改成 wrap + 居中 —— 内容在左、按钮在右，窄了才折行 */
  align-items: center; flex-wrap: wrap;
  /* ★★ v2.707：内边距 .5rem → .3rem（上下各省 3.2px，一卡省 6.4px） */
  padding: .3rem .5rem; border-radius: .7rem; overflow: hidden;
  border: 1px solid #e9ecf3; background: #fff; text-decoration: none;
  transition: transform .15s, box-shadow .15s, border-color .15s;
}
.up-rw:hover { transform: translateY(-1px); border-color: #c4b5fd; box-shadow: 0 4px 14px rgba(var(--mc-shadow-rgb, 124, 58, 237), 0.12); }
.up-rw-ico {
  /* ⚠️ v2.702：从 1.9rem 缩到 1.5rem
     ★★ v2.707：再缩到 1.25rem —— 它是【行1 的最高元素】，
        图标多高这一行就多高。20px 再加卡内边距正好等于行高下限，
        不浪费空间（图标本身不是内容，能认出来就够了）。 */
  flex: 0 0 auto; width: 1.25rem; height: 1.25rem; border-radius: .4rem;
  display: flex; align-items: center; justify-content: center;
  font-size: .78rem; line-height: 1;
}
/* 签到：暖橙；邀请：品红 —— 两卡颜色区分开，扫一眼就知道是两件事 */
.up-rw-checkin { background: linear-gradient(135deg, #fff7ed, #ffedd5); border-color: #fed7aa; }
.up-rw-checkin .up-rw-ico { background: linear-gradient(135deg, #fb923c, #ea580c); }
.up-rw-invite { background: linear-gradient(135deg, #fdf2f8, #fce7f3); border-color: #fbcfe8; }
.up-rw-invite .up-rw-ico { background: linear-gradient(135deg, #ec4899, #db2777); }
.up-rw-t { font-size: .78rem; font-weight: 800; color: #1f2937; flex: 0 0 auto; }
/* ★★ v2.707：说明文字的行高也要收（1.4 → 1.25）——
   它是行1 的第二高元素，行高不收的话行1 还是被它撑住。 */
.up-rw-d { font-size: .66rem; color: #6b7280; line-height: 1.25; min-width: 0; }
.up-rw-n {
  position: absolute; right: .45rem; top: .45rem;
  font-size: .6rem; font-weight: 800; color: #fff;
  background: #ef4444; border-radius: 999px; padding: 0 .32rem; line-height: 1.35;
}
/* 有未领奖励时的呼吸点（只在有东西可领时出现） */
.up-rw-dot {
  position: absolute; right: .55rem; top: .55rem; width: .42rem; height: .42rem;
  border-radius: 50%; background: #ef4444; box-shadow: 0 0 0 0 rgba(239,68,68,.6);
  animation: upPulse 1.8s infinite;
}

/* ---- v2.760：奖励卡单行（用户要求「按钮高度减一半」） ----
   ⚠️ 结构已改：HTML 里原来那层包裹 span 已去掉，四个 span 平级 ⇒
      这里让它们【一行排开】。旧规则里针对那层包裹的（若有）不再生效，
      因为那个元素已经不存在了 —— 不要再给它写样式。
   ⚠️ 本段必须在旧 .up-rw 规则【之后】—— 同权重下后写的才生效。 */
.up-rw {
  display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap;
  padding: 0.42rem 0.6rem;
  margin-bottom: 0.35rem;
}
.up-rw .up-rw-ico { flex: 0 0 auto; font-size: 0.95rem; line-height: 1; }
.up-rw .up-rw-t { flex: 0 0 auto; font-size: 0.78rem; font-weight: 800; }
.up-rw .up-rw-d {
  flex: 1 1 auto; min-width: 0;
  font-size: 0.7rem; color: #6b7280;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html[data-theme="dark"] .up-rw .up-rw-d { color: #9ca3af; }
.up-rw .up-inv-row {
  flex: 0 0 auto; display: flex; align-items: center; gap: 0.32rem; margin: 0;
}
/* 签到卡里的「连续 N 天」也在操作行里 —— 别让它被上面的 flex:1 撑开 */
.up-rw .up-inv-row .up-rw-d { flex: 0 0 auto; }
.up-rw .up-inv-code {
  font-size: 0.64rem; padding: 0.1rem 0.34rem;
  max-width: 8.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 会员块内层（v2.760 加了 id 与 .up-vip-tx）—— 标题与说明两行挨紧 */
.up-vip .up-vip-tx { display: flex; flex-direction: column; gap: 0.05rem; min-width: 0; }
/* 窄屏：说明独占一行、操作行跟随换行 —— 硬挤会把卡片撑出容器 */
@media (max-width: 420px) {
  .up-rw .up-rw-d { flex: 1 1 100%; white-space: normal; }
  .up-rw .up-inv-row { flex: 1 1 100%; }

/* v2.760 次要入口：独立规则（项目约定 —— 次要入口各自一条，便于判据核对） */
.up-rw-more {
  /* ⚠️ 高度必须收：它和「签到」按钮同一行，做大了会把那一行撑高。
     22px 是这一行的下限（和签到按钮等高），不是随便定的。 */
  min-height: 22px; display: inline-flex; align-items: center;
  font-size: 0.58rem; line-height: 1.4;
  margin-left: auto;                 /* 推到行尾，避免换行把卡片撑高 */
  color: #9a3412; text-decoration: none;
  white-space: nowrap;
}
.up-rw-more:hover { text-decoration: underline; }
.up-btn-primary {
  padding: 0.2rem 0.56rem; font-size: 0.68rem; line-height: 1.4;
}
.up-inv-copy {
  /* ⚠️ 必须和同一行的按钮等高（行高由最高的那个决定）——
     只收「签到」不收「复制」等于白改。 */
  min-height: 22px; display: inline-flex; align-items: center;
  padding: 0.16rem 0.46rem; font-size: 0.66rem; line-height: 1.4;
}
}
@keyframes upPulse {
  0%   { box-shadow: 0 0 0 0 rgba(239,68,68,.55); }
  70%  { box-shadow: 0 0 0 .5rem rgba(239,68,68,0); }
  100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); }
}

/* ---- 签到行：放在卡里更紧凑 ----
   ⚠️ v2.702：这些规则原来是给"两卡并排"那版调的（卡很窄，只能上下堆）。
      改成上下两行、内容横排之后，它们【不再命中】（DOM 里没有这个类了）。
      ★ 删除而不是留着：留着会让以后调样式的人改半天没反应。
   ⚠️ 下面 #up-checkin 的 padding:0 也要一起看 —— 卡内边距现在由 .up-rw 统一给。 */
#up-checkin .up-btn-primary {
  /* ★★ v2.707：按钮高度【砍掉约一半】
     ------------------------------------------------------------
     🔴 用户原话（第二次提）：「按钮高度缩小一倍，现在还是太大了。」
     ★ 原来 min-height:30px + padding .28rem×2（9px）⇒ 实际约 39px。
       这一版：min-height 16px + padding .1rem×2（3.2px）+ 0.72rem 行高（12.5px）
       ⇒ 实际约 20px，比原来少一半。
     ⚠️ 为什么敢低于 30px 的触控下限：
        这张卡里【整张卡都可点】（.up-rw 是 <a> 或带点击绑定），
        按钮不是唯一的点击目标 —— 所以按钮本身不需要自己扛 44px。
        真正要保证的触控区由整张卡提供（卡片本身约 60px 高）。
     ⚠️ 字号保持 .72rem 不再往下压：0.68rem 开始中文就糊了，
        而且这个按钮上有"签到"两个字，看不清就是废按钮。 */
  min-height: 16px;
  padding: .1rem .55rem;
  font-size: .72rem;
  line-height: 1.15;
  border-radius: .35rem;
}

/* ---- ★★ v2.701：签到卡里的「详情 →」入口（进独立签到页）----
   🔴 为什么要它：v2.698 做了 /checkin 独立页（7 天奖励格子 + 签到动态含农历），
      却忘了加入口 —— 页面做得再好，用户不知道有、进不去，等于没做。
   ⚠️ 尺寸刻意做小（.68rem / 22px 高）：
      它和「签到」按钮在同一行，做大了会把那一行撑高
      ⇒ 卡片高度变化（用户明确要求过高度别乱动）。
   ⚠️ 颜色用暖橙系（#9a3412）而不是主题紫：
      这张卡是橙色调的，紫色放上去会跳出来抢注意力
      —— 主操作是「签到」，入口只该是次要的。
   ⚠️ 手机端触控：这里写 min-height:22px，但因为【整张卡】是 flex 行，
      实际可点区域比 22px 大；而且它是次要入口，不必按 44px 标准
      （真要按 44px，那一行就装不下了 ⇒ 反而更难点"签到"）。 */
.up-rw-more {
  flex: 0 0 auto; margin-left: auto;
  font-size: .68rem; font-weight: 700; color: #9a3412;
  padding: .15rem .4rem; min-height: 22px; border-radius: .4rem;
  text-decoration: none; line-height: 1.4;
  background: rgba(255,255,255,.7); border: 1px solid #fed7aa;
  transition: background .15s, border-color .15s;
}
.up-rw-more:hover { background: #fff; border-color: #fb923c; }

/* ============================================================
   ★★★ v2.706：弹窗里的「生成时用哪个积分」开关
   ------------------------------------------------------------
   🔴 用户原话：「个人资料弹窗这里加一个切换企业会员，在做图，
      就使用团队积分。」
   ⚠️ 用分段按钮（segmented）而不是一个 checkbox 开关：
      这是【二选一】不是【开/关】—— 开关表达不了"团队 vs 个人"，
      用户会看不懂"关掉是什么"。
   ⚠️ 每段 30px 高：弹窗本身不宽，做大了会把整块撑高
      （本项目为弹窗高度被撑高被用户提过一次）。
   ============================================================ */
html[data-theme="dark"] .up-pay-seg { background: #232a36; border-color: rgba(255,255,255,.1); }

/* ============================================================
   ★★★ v2.706：我的团队（/team）
   ------------------------------------------------------------
   🔴 用户要求：「团队页面也独立做一个」
      参考图：顶部一块暖色横幅（团队名 + 成员数 + 管理/邀请），
      下面两个标签（团队作品 / 团队成员）。
   ⚠️ 用我们自己的令牌与圆角，不抄参考站的暖橙渐变（那是它的品牌色）。
   ⚠️ 类名 tm- 前缀：和 mc-（个人中心）、up-（弹窗）都区分开，
      避免互相命中（本项目在类名撞车上踩过）。
   ============================================================ */
/* ★ v2.739：这里原来有一条 `.tm-title { font-size:1.35rem … }` ——
   它是团队页那个 <h1 class="tm-title">👥 我的团队</h1> 的样式。
   用户反馈「这两处重复了」（顶栏标题 + 页面 h1 各写一遍）⇒ 那个 h1 已删，
   这条规则再也没有使用者 ⇒ 一并删掉，别留孤儿样式。
   ⚠️ 同类处理在 me.html 上是另一种做法（style.css 里
      `.mc-title { display:none }` —— 保留元素、只隐藏）。
      两种都行；这里选删除是因为 team 页那个 h1 除了标题没别的用途。 */
.tm-loading { padding: 2rem 0; text-align: center; color: #9ca3af; font-size: 0.84rem; }

.tm-card {
  /* ★★★ v2.718：底色/边框/阴影走皮肤令牌（原来写死，换皮肤不会变） */
  border: 1px solid var(--mc-edge); border-radius: 1rem;
  background: var(--mc-card); box-shadow: var(--mc-shadow);
  padding: 1rem 1.1rem; margin-bottom: 0.9rem;
}
html[data-theme="dark"] .tm-card { border-color: var(--mc-edge); }
.tm-card h3 { font-size: 0.94rem; font-weight: 800; margin: 0 0 0.7rem; }
.tm-card h3 small { font-size: 0.72rem; color: #9ca3af; font-weight: 600; margin-left: 0.3rem; }

/* ---- 没团队时的空状态 ---- */
.tm-none-ico { font-size: 2.4rem; text-align: center; margin-bottom: 0.4rem; }
.tm-card h2 { font-size: 1.1rem; font-weight: 800; text-align: center; margin: 0 0 0.5rem; }
.tm-card p { font-size: 0.82rem; color: #6b7280; line-height: 1.85; text-align: center; margin: 0; }
.tm-none-btns { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; margin-top: 1rem; }

/* ---- 顶部横幅 ---- */
html[data-theme="dark"] .tm-hero { border-color: var(--mc-edge); }
/* 过期用红色：这是【必须显眼】的状态 —— 过期后生成会扣个人积分，
   不提示的话用户会以为还在用团队池（最容易来投诉的一类） */
.tm-tag-warn { background: #fee2e2; color: #b91c1c; }
html[data-theme="dark"] .tm-tag { background: #2a2140; color: #c4b5fd; }
/* ============================================================================
   ★★★ v2.759：团队页顶部横幅【重排】
   ----------------------------------------------------------------------------
   🔴 用户原话：「框住的部分，重新排版重写CSS，排的好看合理一点，
      不要挤在一起，前面那么多空。」

   ⚠️⚠️ 改之前的毛病：
      .tm-hero 是【一行 flex】，身份块 + 统计 + 积分池 + 扣费来源全塞在一行，
      中间靠 .tm-hero-main 伸展去吃掉空白 ⇒ 左边空一大片、右边挤成一团。
      ★ 这不是调 padding 能修的 —— 是"一行放不下四件事"。

   ★ 现在的结构（两段式，横向铺满、没有空白区）：
      .tm-hero
        ├ .tm-hero-top   [头像][身份+操作][统计][积分池]  ← 一行四格，各自有宽度
        └ .tm-paysrc     生成时用哪个积分 ← 设置项独占一条
   ⚠️ 统计（.tm-stats）是【新增的一块】，专门填原来那个空白区 ——
      它不是装饰：成员数/团队作品数是团队页最该一眼看到的两个数。

   ⚠️ 颜色一律走皮肤令牌，不写死主题色（换皮肤要跟着变）。
   ============================================================================ */
.tm-hero {
  display: flex; flex-direction: column; gap: 0;
  padding: 0.85rem 1rem;
  border: 1px solid var(--mc-edge);
  border-radius: 1rem;
  background: var(--mc-head-bg);
  box-shadow: var(--mc-shadow);
}
.tm-hero-top {
  display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap;
}
.tm-hero-ava {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 0.9rem;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem;
  background: linear-gradient(135deg, var(--brand-from, #9333ea), var(--brand-to, #6366f1));
}
.tm-hero-main { flex: 1 1 220px; min-width: 0; }
.tm-hero-row { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.tm-hero-row h2 { font-size: 1.15rem; font-weight: 800; margin: 0; }
/* ★ 改名按钮：小、低调、只在创建人那里出现（JS 控制 hidden） */
.tm-edit {
  font-size: 0.68rem; font-weight: 700; line-height: 1.5;
  padding: 0.1rem 0.45rem; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--mc-acc-line, #ddd6fe);
  background: transparent; color: var(--mc-acc);
  font-family: inherit;
}
.tm-edit:hover { background: var(--mc-acc-soft, #ede9fe); }
.tm-tag {
  font-size: 0.66rem; font-weight: 700; padding: 0.1rem 0.45rem;
  border-radius: 999px; background: var(--mc-acc-soft, #ede9fe);
  color: var(--mc-acc-ink, #5b21b6); white-space: nowrap;
}
.tm-tag-warn { background: #fee2e2; color: #b91c1c; }
html[data-theme="dark"] .tm-tag-warn { background: #3a1f22; color: #fca5a5; }
.tm-hero-sub { font-size: 0.75rem; color: #6b7280; margin: 0.3rem 0 0; line-height: 1.7; }
html[data-theme="dark"] .tm-hero-sub { color: #9ca3af; }
.tm-hero-acts { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; margin-top: 0.4rem; }
.tm-owner { font-size: 0.7rem; font-weight: 800; color: var(--mc-acc); }
.tm-link { font-size: 0.75rem; font-weight: 700; color: var(--mc-acc); text-decoration: none; }
.tm-link:hover { text-decoration: underline; }

/* ---- 统计（新增）：填原来那块空白。窄屏会自己换行，不会挤 ---- */
.tm-stats {
  display: flex; align-items: stretch; gap: 0;
  flex: 0 1 auto;
  border-left: 1px solid var(--mc-edge);
  padding-left: 0.2rem;
}
.tm-stat { padding: 0 0.85rem; text-align: center; min-width: 4.4rem; }
.tm-stat b { display: block; font-size: 1.05rem; font-weight: 800; color: var(--mc-acc); line-height: 1.3; }
.tm-stat span { display: block; font-size: 0.66rem; color: #9ca3af; margin-top: 0.05rem; white-space: nowrap; }

/* ---- 积分池：右侧一坨，但不再和扣费来源挤在一起 ---- */
.tm-pool {
  flex: 0 0 auto; text-align: right;
  display: flex; flex-direction: column; align-items: flex-end;
  padding-left: 0.9rem; border-left: 1px solid var(--mc-edge);
}
.tm-pool > span { font-size: 0.68rem; color: #9ca3af; }
.tm-pool > b { font-size: 1.6rem; font-weight: 800; color: var(--mc-acc); line-height: 1.15; }
.tm-pool .tm-mine { font-size: 0.68rem; color: #9ca3af; margin-top: 0.1rem; }
.tm-pool .tm-mine b { color: #1f2937; font-size: 0.8rem; }
html[data-theme="dark"] .tm-pool .tm-mine b { color: #e5e7eb; }

/* ---- 第二段：扣费来源（设置项独占一条，有上分隔线） ---- */
.tm-paysrc {
  margin-top: 0.75rem; padding-top: 0.7rem;
  border-top: 1px solid var(--mc-edge);
}
.tm-paysrc-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.8rem; flex-wrap: wrap;
}
.tm-paysrc-tx { flex: 1 1 240px; min-width: 0; }
.tm-paysrc-tx b { font-size: 0.8rem; font-weight: 800; }
.tm-paysrc-tx p { font-size: 0.7rem; color: #9ca3af; margin: 0.1rem 0 0; }

/* ---- 手机上：统计与积分池各占一行，别横向挤 ---- */
@media (max-width: 860px) {
  .tm-stats {
    flex: 1 1 100%; border-left: 0; padding-left: 0;
    border-top: 1px solid var(--mc-edge); padding-top: 0.6rem; margin-top: 0.15rem;
    justify-content: space-between;
  }
  .tm-stat { padding: 0 0.3rem; min-width: 0; flex: 1 1 0; }
  .tm-pool {
    flex: 1 1 100%; align-items: flex-start; text-align: left;
    border-left: 0; padding-left: 0;
    border-top: 1px solid var(--mc-edge); padding-top: 0.6rem;
  }
}

html[data-theme="dark"] .tm-tag-warn { background: #3a1f22; color: #fca5a5; }
.tm-link:hover { text-decoration: underline; }
/* ---- 横幅右侧一列：积分池 + 扣费来源 ----
   ★★★ v2.741：用户要求「这个区域缩短，放在跟团队积分池后面，单独一块」。
   🔴 原来「生成时用哪个积分」是横幅【下面另起一张卡、占满整行】——
      左侧一大片空、右侧两个按钮，横向空间白扔。
   ⇒ 收进横幅右侧，排在积分池下面（.tm-right 就是替原来 .tm-pool 站的位置）。
   ⚠️ .tm-right 必须 flex-direction: column 且 flex:0 0 auto：
      它顶替了原来 .tm-pool 在 .tm-hero 里的角色，宽度按内容走、
      不参与"中间那块文字"的伸展。
   ⚠️ 里面【保留 .tm-pool 这个类名】—— 手机上那条"换整行 + 左对齐 +
      字号变小"的规则还挂在它身上，改类名会连带失效。 */
/* ⚠️ 这一条被我的"去重"误删过一次（当时我以为自己和上面那条重复了）——
   它管的是【桌面端右对齐】；手机上会被下面 @media 里那条改成左对齐整行。
   少了它桌面端积分池会左对齐，看着像没做完。 */
/* ★★★ v2.749：积分池从【竖排 3 行】改成【横排 1 行】——
   用户要的是「省出来页面的高度空间」。
   🔴 原来： `团队积分池` 换行 / 大字 1,765 换行 / `我用 1,765` —— 占 3 行
   ⇒ 现在：`团队积分池 1,765 · 我用 1,765` 一行
   ⚠️ 数字仍然是最大的那个（1.5rem、主题色）——它是这一块的主角，
      不能因为"省高度"把重点也省掉。
   ⚠️ 手机上（见下面 @media）会覆盖成 flex-wrap:wrap，因为一行放不下。 */
html[data-theme="dark"] .tm-pool .tm-mine b { color: #e5e7eb; }

/* ---- 扣费来源（复用弹窗那套分段按钮的样式）---- */
.tm-paysrc-row { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; flex-wrap: wrap; }
.tm-paysrc-row b { font-size: 0.86rem; }
.tm-paysrc-row p { font-size: 0.74rem; color: #6b7280; margin: 0.2rem 0 0; text-align: left; }

/* ---- 标签页 ---- */
.tm-tabs {
  display: flex; gap: 0.3rem; flex-wrap: wrap;
  /* ★ v2.749：下外边距 0.85rem → 0.5rem（用户要求省页面高度给作品）。
     ⚠️ 标签按钮本身的 min-height:40px 不动 —— 那是手机触控下限。 */
  border-bottom: 1px solid var(--border, #e9ecf3); margin-bottom: 0.5rem;
}
html[data-theme="dark"] .tm-tabs { border-color: rgba(255,255,255,.09); }
.tm-tab {
  font: inherit; font-size: 0.84rem; font-weight: 700; color: #6b7280;
  background: transparent; border: 0; cursor: pointer;
  padding: 0.55rem 0.9rem; min-height: 40px;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tm-tab:hover { color: #7c3aed; }
.tm-tab.on { color: var(--mc-tab-ink); background: var(--mc-tab-bg); border-radius: var(--mc-tab-r); }
.tm-pane { display: none; }
.tm-pane.on { display: block; }

/* ---- 表格 ---- */
.tm-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.tm-table th {
  text-align: left; font-weight: 700; color: #6b7280; font-size: 0.74rem;
  padding: 0.45rem 0.5rem; border-bottom: 1px solid #eef0f5; white-space: nowrap;
}
html[data-theme="dark"] .tm-table th { border-color: rgba(255,255,255,.08); }
.tm-table td { padding: 0.5rem; border-bottom: 1px solid #f6f7fb; }
html[data-theme="dark"] .tm-table td { border-color: rgba(255,255,255,.05); }
.tm-neg { color: #ef4444; font-weight: 700; }
.tm-pos { color: #16a34a; font-weight: 700; }
.tm-empty { font-size: 0.8rem; color: #9ca3af; padding: 0.8rem 0; text-align: center; }

/* ============================================================
   ★★★ v2.710：团队作品（网格画廊）
   ------------------------------------------------------------
   🔴 用户要求：「团队管理，只能管理成员，不能管理团队作品，
      我们要求团队作品，可以共享。」
   ⚠️ 用网格画廊而不是表格：作品是图，表格里放缩略图既挤又难看。
   ⚠️ 自适应列（auto-fill minmax）—— 同一个页面在窄屏/宽屏都能用，
      不用为手机单独写一套（省一处以后会忘记维护的地方）。
   ============================================================ */
.tm-works-head {
  display: flex; align-items: center; justify-content: space-between;
  /* ★ v2.749：0.7rem → 0.45rem（省高度给作品列表） */
  gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.45rem;
}
.tm-works-head h3 { margin: 0; }
.tm-kinds { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.tm-kind {
  font: inherit; font-size: 0.72rem; font-weight: 700; cursor: pointer;
  padding: 0.22rem 0.6rem; min-height: 28px;
  border: 1px solid #e5e7eb; border-radius: 999px;
  background: #fff; color: #4b5563;
}
.tm-kind:hover { border-color: #a78bfa; color: #6d28d9; }
.tm-kind.on { background: var(--mc-acc); border-color: var(--mc-acc); color: #fff; }
html[data-theme="dark"] .tm-kind { background: #1b2029; border-color: rgba(255,255,255,.14); color: #cbd5e1; }
html[data-theme="dark"] .tm-kind.on { background: #7c3aed; border-color: #7c3aed; color: #fff; }

.tm-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: 0.6rem;
}
.tm-w {
  border: 1px solid #eef0f5; border-radius: 0.7rem; overflow: hidden;
  background: #fff; transition: border-color .15s, box-shadow .15s;
}
.tm-w:hover { border-color: #c4b5fd; box-shadow: 0 4px 14px rgba(124,58,237,.12); }
html[data-theme="dark"] .tm-w { background: #161a24; border-color: rgba(255,255,255,.08); }
.tm-w-media {
  /* ⚠️ 固定比例（4:3）而不是固定高度：不同尺寸的图都被裁成一样大，
     网格才不会参差不齐（object-fit:cover 负责裁） */
  aspect-ratio: 4 / 3; background: #f6f7fb;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
html[data-theme="dark"] .tm-w-media { background: #131720; }
.tm-w-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tm-noimg { font-size: 1.6rem; opacity: .5; }
.tm-w-body { padding: 0.4rem 0.5rem 0.5rem; }
.tm-w-p {
  font-size: 0.74rem; color: #374151; margin: 0; line-height: 1.45;
  /* ⚠️ 两行封顶：提示词长短差很多，不限高会让网格高低不齐 */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
html[data-theme="dark"] .tm-w-p { color: #cbd5e1; }
.tm-w-meta { font-size: 0.66rem; color: #9ca3af; display: block; margin-top: 0.25rem; }
.tm-more { text-align: center; margin-top: 0.9rem; }
.tm-btn {
  font: inherit; font-size: 0.8rem; font-weight: 700; cursor: pointer;
  padding: 0.4rem 1.1rem; min-height: 34px;
  border: 1px solid #ddd6fe; border-radius: 999px;
  background: #faf8ff; color: #6d28d9;
}
.tm-btn:hover { background: #f5f3ff; }
.tm-btn:disabled { opacity: .6; cursor: default; }

@media (max-width: 860px) {
  /* ⚠️ 手机上横幅三块挤一行放不下 ⇒ 积分池换到下面整行 */
  /* ★ v2.741：右侧列也跟着换整行（它现在是 .tm-pool 的父级）——
     ⚠️ 原来这条写的是 .tm-pool；加了 .tm-right 之后【必须同时改】，
        否则手机上右侧列还是 flex-end 对齐、积分池左对齐会打架。 */
  /* ★ v2.749：桌面端 .tm-pool 改成了 flex 横排（见上面那段说明）——
     手机上要跟着改成【左对齐】的 flex，否则它还是 flex-end（靠右），
     和同一个 .tm-right 里的左对齐块打架。
     ⚠️ text-align:left 现在没用了（flex 容器里 text-align 管不到
        已经变成 flex item 的子元素）⇒ 换成 justify-content:flex-start。
     ⚠️ 原来那两条（> b 缩小、.tm-mine 加 margin-left）也要跟着调：
        它们是为"竖排 3 行"写的，现在是横排，margin-left 会造成
        「1,765」和「我用」之间多一个空格。 */
  /* 手机上不分左右了 ⇒ 只需要放开最大宽度。
     ⚠️ v2.749：虚线也去掉了（桌面端一起去 —— 用户要省高度，
        而这条线原来只是给"竖排两层"做区分用的）。 */
  /* ⚠️ 表格手机上必须能横向滚 —— 不滚就会把整页撑宽（横向溢出） */
  .tm-card { padding: 0.85rem 0.8rem; }
  .tm-table th, .tm-table td { white-space: nowrap; }
  #tm-members, #tm-logs { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
html[data-theme="dark"] .up-rw-more {
  background: rgba(255,255,255,.08); border-color: rgba(251,146,60,.4); color: #fdba74;
}

/* ---- 邀请行（在邀请卡里）---- */
/* ★ v2.702：按钮行现在是【内容区里的一个 flex 项】（横排在右边），
   不再是独立的一整行 ⇒ 去掉 margin-top（那会把卡片撑高）。
   ⚠️ 加 margin-left:auto 把它推到最右 —— 内容在左、按钮在右。 */
.up-inv-row { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; margin-left: auto; }
/* ★★ v2.707：按钮行里的其它元素也要一起收 ——
   不管它们的话，行高由【最高的那个】决定，按钮改小了也白改。
   （这是我的"高度账"里最容易漏的一条：只改按钮，行高还是被旁边撑住。） */
.up-inv-row .up-btn-primary { min-height: 16px; padding: .1rem .55rem; line-height: 1.15; }
.up-inv-code {
  font-family: Consolas, monospace; font-size: .64rem;
  background: rgba(255,255,255,.85); border: 1px dashed #f9a8d4; border-radius: .35rem;
  /* ⚠️ v2.707：max-width 7rem → 5.5rem（邀请码很长，7rem 会把整行撑宽，
        宽到一定程度就换行了 ⇒ 反而多一行高度） */
  padding: .04rem .26rem; color: #9d174d; max-width: 5.5rem; line-height: 1.5;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.up-inv-copy {
  border: 0; border-radius: .4rem; cursor: pointer; font: inherit;
  /* ★★ v2.707：和"签到"按钮统一收小（同处一行，一个高一个矮会很难看） */
  font-size: .66rem; font-weight: 800; color: #fff;
  min-height: 16px; padding: .1rem .45rem; line-height: 1.15;
  background: linear-gradient(135deg, #ec4899, #db2777);
}
.up-inv-copy:hover { filter: brightness(1.06); }

html[data-theme="dark"] .up-rw { background: #171b22; border-color: #2b313b; }
html[data-theme="dark"] .up-rw-checkin { background: #2a1f14; border-color: #7c4a1e; }
html[data-theme="dark"] .up-rw-invite { background: #2a1420; border-color: #7c2d50; }
html[data-theme="dark"] .up-rw-t { color: #e5e7eb; }
html[data-theme="dark"] .up-inv-code { background: #11151b; border-color: #7c2d50; color: #f9a8d4; }
html[data-theme="dark"] .up-cards .up-card:first-child { background: #1e1630; border-color: #4c3a7a; }

/* ⚠️ 窄屏：两张奖励卡改成竖排（横排会把字挤成两行很难看） */
@media (max-width: 400px) {
  .up-rewards { grid-template-columns: 1fr; }
}
/* ============================================================
   ★ v2.635：顶栏「联系我们」按钮 + 悬停菜单
   ------------------------------------------------------------
   ⚠️ 全部 nc- 前缀，不碰全站类名。
   ⚠️ 悬停菜单必须配【延时关闭】（JS 里做），这里只管样式。
   ============================================================ */
.nav-contact-wrap { position: relative; display: inline-flex; }
.nav-contact-menu {
  position: absolute; top: calc(100% + .4rem); left: 0; z-index: 60;
  min-width: 13.5rem; padding: .35rem;
  background: #fff; border: 1px solid #e9ecf3; border-radius: .8rem;
  box-shadow: 0 10px 30px rgba(15, 23, 42, .13);
  display: flex; flex-direction: column; gap: .1rem;
}
/* ⚠️ 菜单和按钮之间留了一段空隙（.4rem）—— 鼠标移过去时会经过它，
   JS 里的 200ms 延时关闭就是为了扛过这段空隙。 */
.nc-item {
  display: flex; align-items: center; gap: .55rem; width: 100%;
  padding: .5rem .6rem; border: 0; background: transparent;
  border-radius: .5rem; cursor: pointer; font: inherit; text-align: left;
}
.nc-item:hover { background: #f5f3ff; }
.nc-ico { font-size: 1rem; line-height: 1; flex: 0 0 auto; }
.nc-body { display: flex; flex-direction: column; min-width: 0; }
.nc-body b { font-size: .82rem; font-weight: 800; color: #1f2937; }
.nc-body small {
  font-size: .68rem; color: #9ca3af; margin-top: .05rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 深色主题 */
html[data-theme="dark"] .nav-contact-menu { background: #171b22; border-color: #2b313b; }
html[data-theme="dark"] .nc-item:hover { background: #241d3a; }
html[data-theme="dark"] .nc-body b { color: #e5e7eb; }
/* ============================================================
   ★ v2.637：创建类页面的「铺满」版式
   ------------------------------------------------------------
   🔴 起因（用户反馈）：
      「音乐创作、视频创作、内容区都变窄了，要跟电商专区的内容区那么宽。」
      查证：这几个页用的是 Tailwind `max-w-7xl`（= 80rem = 1280px），
      在 1920px 屏上两边各空 320px；而电商专区的 .zone-wrap 是
      `width:100%; max-width:none` —— 铺满整屏。
      ⚠️ 这不是被改窄的，是最初就是这么写的（.dist 产物里也是 max-w-7xl）。
         但用户的诉求成立：新页面更宽，老页面看着就"窄了"。

   ★ 为什么不用 `max-w-[1600px]`（首页那种写法）：
     那是 Tailwind CDN 的【任意值语法】，而 tailwind-lite.css 里没有定义它
     ⇒ CDN 一挂就变全宽，宽度会跳。用项目自己的类最可靠。

   ★ 为什么不像电商专区那样把内容也拉满：
     电商专区是「左栏 + 网格」，铺满是合理的。
     音乐/视频是「工具面板 + 预览区」，在 2560px 超宽屏上拉满会很难用。
     ⇒ 折中（也是 .zone-wrap 的原始思路）：
         外层铺满 + 两边 clamp 呼吸边距
         内层 .tool-card 自己保持可读上限
     这样 1920px 上明显变宽（用户要的效果），超宽屏也不会拉成一条。

   ⚠️ 纵向间距【逐页保原样】（改版式不该顺手改留白）：
       .page-wide--tight  对应原来的 pt-6 pb-16（音乐/视频）
       .page-wide         对应原来的 py-8（文字/作品/灵感）
       ⚠️ 顺带修一个问题：原来的 `pt-6` 在 tailwind-lite.css 里【根本没定义】，
          一直靠 CDN 兜着 —— 现在换成项目自己的类，不再依赖 CDN。
   ============================================================ */
.page-wide {
  width: 100%;
  max-width: none;          /* 关键：不封顶 —— 这就是"铺满" */
  margin: 0;
  padding: 2rem clamp(0.375rem, 0.75vw, 1rem);
}
.page-wide--tight {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 1.5rem clamp(0.375rem, 0.75vw, 1rem) 4rem;
}
/* ⚠️ 窄屏下把左右边距收到 1rem（原来 px-4 的宽度）——
   不加这条的话手机上内容会被 clamp 的下限挤得比原来还窄。 */
@media (max-width: 639px) {
  .page-wide, .page-wide--tight { padding-left: clamp(0.375rem, 0.75vw, 1rem); padding-right: 1rem; }
}

/* ============================================================
   ★ v2.638：品牌资产页的隐藏文件输入
   ------------------------------------------------------------
   🔴 为什么必须有这个类（而不是用 Tailwind 的 .hidden + 内联 style）：
      我在 brand.html 里写成了
        <input type="file" class="hidden" style="display:none;">
      —— 同一个标签既有 .hidden 类又有内联 display。
      ⚠️ 这在【v2.626 的解锁弹窗】上已经坑过我一次：
         内联样式优先级更高，会把 .hidden 的 display:none 覆盖掉，
         结果是弹窗"隐藏不了"、一直盖在页面上。
         而现在这里是【反过来】的隐患：两处都写 display 显得像"双保险"，
         其实任何一处改了另一处不生效 —— 这类"同一属性写两遍"迟早出事。
      ⇒ 用一个专用类，只在一处声明隐藏。
   ⚠️ 用 display:none 而不是 visibility/绝对定位：
      这个 input 是靠 <label for> 触发的，display:none 完全够用，
      而且不会在页面上留一个可聚焦的空元素（无障碍上也更干净）。
   ============================================================ */
.bd-file-hidden { display: none; }

/* ⚠️ 这里【故意不加】内层 max-width。
   ------------------------------------------------------------
   我第一版加了一条：
     @media (min-width: 1800px) {
       .page-wide > .tool-card { max-width: 1600px; }
     }
   理由是"超宽屏别把工具面板拉太长"。
   🔴 但那是【反效果】：用户的诉求就是铺满（和电商专区一样宽），
      而在 1920px 屏上这条会把 1840px 重新压回 1600px —— 等于没改。
      「既要铺满又不要太长」是自相矛盾的，这个取舍该由用户做，
      不该我在实现里顺手把它抵消掉。
   ★ 现在的行为：真正的铺满，和 .zone-wrap 完全一致。
      以后真觉得超宽屏太宽，再加限制 —— 那会是一次【有意的决定】，
      而不是像刚才那样把刚做的改动悄悄抵消。
   ------------------------------------------------------------ */

/* ============================================================
   ★★ v2.656（S4）：客户选择器（BrandPicker 渲染出来的）
   ------------------------------------------------------------
   样式放在全站 style.css 里，因为它是【多个页面共用】的一个小控件
   （图片/视频/音乐/电商套图/开业物料都会挂一个）。
   ⚠️ 前缀 bp- 是 BrandPicker 的缩写，和别处不冲突。
   ============================================================ */
.bp-wrap {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: .8rem; color: #4b5563;
}
.bp-label { font-weight: 700; color: #6b7280; font-size: .76rem; }
.bp-sel {
  padding: .3rem .5rem; border: 1px solid #e5e7eb; border-radius: .5rem;
  background: #fff; font: inherit; font-size: .8rem; color: #1f2937;
  max-width: 14rem;
}
.bp-sel:focus { outline: 2px solid rgba(124,58,237,.25); border-color: #7c3aed; }
.bp-manage {
  font-size: .74rem; color: #7c3aed; text-decoration: none;
  border-bottom: 1px dashed rgba(124,58,237,.4);
}
.bp-manage:hover { border-bottom-style: solid; }
.bp-one { font-size: .76rem; color: #6b7280; }
.bp-one b { color: #1f2937; }

/* ============================================================
   ★★★ v2.761：数据看板（新版，后台 /admin）
   ------------------------------------------------------------
   🔴 用户原话：「重新设计制作一个数据看板。要更专业，更美观一些。」
   ⚠️ 全部 .dash- 前缀，不碰现有后台类（.panel / .data-table 都复用）。
   ⚠️ 图表是 SVG 手绘（项目零依赖）；固定 viewBox + preserveAspectRatio=none
      ⇒ 在任意宽度下拉伸不变形。
   ⚠️ 这个文件是全站共用的（前台也用），所以一定只影响 .dash-* ——
      加错一个通用选择器就会改到前台。
   ============================================================ */

.dash-todo {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .55rem .9rem; margin-bottom: 1rem; border-radius: .7rem;
  font-size: .82rem; font-weight: 600;
  background: #fffbeb; border: 1px solid #fcd34d; color: #92400e;
}
.dash-todo.ok { background: #f0fdf4; border-color: #86efac; color: #166534; }
html[data-theme="dark"] .dash-todo { background: #2a2415; border-color: #78560f; color: #fcd34d; }
html[data-theme="dark"] .dash-todo.ok { background: #14261a; border-color: #166534; color: #86efac; }

.dash-kpis {
  display: grid; gap: .7rem; margin-bottom: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
}
.dash-kpi {
  display: flex; align-items: center; gap: .65rem;
  padding: .8rem .9rem; border-radius: .8rem;
  background: #fff; border: 1px solid #e9ecf3;
  transition: transform .15s, box-shadow .15s;
}
.dash-kpi:hover { transform: translateY(-2px); box-shadow: 0 6px 18px #0f172a14; }
.dash-kpi-ico {
  flex: 0 0 auto; width: 2.1rem; height: 2.1rem; border-radius: .6rem;
  display: flex; align-items: center; justify-content: center; font-size: 1.05rem;
  background: linear-gradient(135deg, #ede9fe, #e0e7ff);
}
.dash-kpi-body { min-width: 0; }
.dash-kpi-body b { display: block; font-size: 1.32rem; font-weight: 800; line-height: 1.2; color: #1f2937; }
.dash-kpi-lb { display: block; font-size: .7rem; color: #9ca3af; margin-top: .05rem; }
.dash-kpi-sub { display: block; font-size: .66rem; color: #7c3aed; font-weight: 700; margin-top: .1rem; }
.dash-kpi.t-warn { border-color: #fcd34d; background: #fffdf5; }
.dash-kpi.t-warn .dash-kpi-ico { background: linear-gradient(135deg, #fef3c7, #fde68a); }
.dash-kpi.t-ok .dash-kpi-ico { background: linear-gradient(135deg, #d1fae5, #a7f3d0); }

.dash-trends { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.dash-trend-t { display: block; font-size: .72rem; font-weight: 700; color: #6b7280; margin-bottom: .2rem; }
.dash-chart { width: 100%; height: 84px; display: block; }

.dash-cols {
  display: grid; gap: 1rem; margin-top: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
}
.dash-panel .panel-body { display: flex; flex-direction: column; gap: .42rem; font-size: .84rem; }
.dash-row { display: flex; justify-content: space-between; align-items: baseline; gap: .6rem; }
.dash-row > span { color: #6b7280; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-row > b { font-weight: 800; color: #1f2937; white-space: nowrap; }
.dash-row > b.t-warn { color: #b45309; }
.dash-row > b.t-ok { color: #15803d; }
.dash-mini-t {
  font-size: .68rem; font-weight: 800; color: #9ca3af;
  margin-top: .5rem; padding-top: .5rem; border-top: 1px dashed #e9ecf3;
}

.dash-bars { display: flex; flex-direction: column; gap: .34rem; }
.dash-bar-row { display: flex; align-items: center; gap: .45rem; font-size: .74rem; }
.dash-bar-lb { flex: 0 0 5.4rem; color: #6b7280; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-bar-track { flex: 1 1 auto; height: .42rem; border-radius: 999px; background: #f1f2f7; overflow: hidden; min-width: 0; }
.dash-bar-track > i { display: block; height: 100%; border-radius: 999px; transition: width .3s; }
.dash-bar-n { flex: 0 0 auto; font-weight: 800; color: #374151; min-width: 2.4rem; text-align: right; }
.dash-bar-p { flex: 0 0 2.6rem; color: #9ca3af; text-align: right; }

html[data-theme="dark"] .dash-kpi { background: #171b24; border-color: #262c38; }
html[data-theme="dark"] .dash-kpi:hover { box-shadow: 0 6px 18px #00000066; }
html[data-theme="dark"] .dash-kpi-body b { color: #e5e7eb; }
html[data-theme="dark"] .dash-kpi-ico { background: linear-gradient(135deg, #2a2140, #1e2536); }
html[data-theme="dark"] .dash-row > b { color: #e5e7eb; }
html[data-theme="dark"] .dash-bar-track { background: #232a36; }
html[data-theme="dark"] .dash-bar-n { color: #cbd5e1; }
html[data-theme="dark"] .dash-mini-t { border-top-color: #262c38; }

/* ============================================================
   ★★★ v2.763：个人中心【访客模式】
   ------------------------------------------------------------
   🔴 用户原话：「个人主页就显示个人中的那些就好了，只是别人访问，
      就不显示那些设置项啊，你这弄得两个页面没必要呀」

   ★ 一个页面两种模式：body[data-view="guest"] 由 me-center.js 同步打上。
   ⚠️⚠️ 这层 CSS 是【第三道】防线，不是唯一一道：
      ① JS 不给访客调 /me/overview（私有数据没进页面）
      ② JS 把非"作品"的 iframe 面板删掉（藏着也会带 cookie 去请求私有页）
      ③ 这里藏掉头部的设置类控件
      ★ 只靠 CSS 藏 = 假安全（右键查看源代码全都在）。
   ⚠️ 以后新加设置项：【给它加 mc-self 类】就行，不用改这段 CSS。
   ============================================================ */
body[data-view="guest"] .mc-self { display: none !important; }
/* 访客模式下统计条不再需要贴边（它原来贴边是为了和自己的开关对齐） */
body[data-view="guest"] .mc-strip { margin-left: 0; margin-right: 0; }
/* 访客没有标签栏 —— 已经由 JS 藏掉，这里兜一层（防 JS 早期失败） */
body[data-view="guest"] .mc-tabs { display: none !important; }

/* ============================================================
   ★★★ v2.764：个人中心排版第二刀
   ------------------------------------------------------------
   🔴 用户原话：「个人资料下面那一行，有没有办法挪到上面我画的那两个框框里，
      那一块还是很空。另外，我的作品那一行的TAB和作品筛选的那个：
      全部、图片……的TAB看起来很不协调。」

   ★ 两件事：
     ① 统计 + 灵感开关 → 挪进【资料列的下半行】（原来在卡底独占一整行）
     ② 作品筛选那行（.tool-tab）在本页按 .mc-tab 的观感对齐
   ⚠️⚠️ 第二件事【必须】加 body[data-page="me"] 前缀：
      .tool-tab 是全站共用的（图片/音乐/视频/资产库都在用），
      裸改它会把所有页面的筛选条一起改掉。
   ============================================================ */

/* ---- ① 资料列下半行：统计（紧凑）+ 开关 ---- */
.mc-head-lower {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-top: .5rem; padding-top: .45rem;
  border-top: 1px dashed var(--mc-edge);
  min-width: 0;
}
.mc-head-lower .mc-stats {
  flex: 1 1 auto; min-width: 0;
  /* ⚠️ 覆盖原来的 4.2rem 最小格宽 —— 那是"卡底整行"的尺寸，
     塞进资料列会立刻折成两行。这里改成 auto + 不换行。 */
  grid-template-columns: repeat(auto-fit, minmax(2.6rem, 1fr));
  margin: 0;
}
/* 紧凑：数字和标签都收一档，10 格才排得下 */
.mc-stats-compact .mc-stat { padding: .05rem .12rem; gap: 0; }
.mc-stats-compact .mc-stat b { font-size: .92rem; line-height: 1.15; }
.mc-stats-compact .mc-stat span { font-size: .6rem; }
.mc-head-lower .mc-share { margin: 0; flex: 0 0 auto; }

/* ---- ② 作品筛选那行：在本页对齐 .mc-tab 的观感 ----
   ⚠️ 只对齐【形状与间距】：胶囊、字号、圆角、间距；
      选中态仍用它自己的主题色（两处高亮色不同没关系，
      真正"不协调"的是一个大一个小、一个圆一个方）。 */
body[data-page="me"] .tool-tab {
  padding: .34rem .8rem;
  font-size: .82rem;
  border-radius: 999px;
  gap: .28rem;
}
/* 两行之间的间距也拉齐（原来一行 0.35rem、一行 mb-4=1rem，看着像两块东西） */
body[data-page="me"] .mc-tabs { margin-bottom: .5rem; }

/* ============================================================
   ★★★ v2.765：用户下拉面板压缩 + 可滚动
   ------------------------------------------------------------
   🔴 用户原话：「这一块再压缩一下，重新设计排版，让高度变低一些，
      不然底部的退出登录按钮，就跑出页面」

   ★ 根因：.user-pop 是绝对定位但【没有 max-height、没有 overflow】——
     内容一长就直接超出视口，底部按钮永远点不到。
     ⚠️ 这一条与压缩无关，是【必须】的兜底：小屏 / 浏览器带工具栏时
        内容再短也会顶出去。
   ★ 压缩：面板内边距、各段间距、字号各收一档（不动功能）。
   ★ 团队账户块重排：原来"标题 + 说明 + 两个大按钮"占 3 行，
     现在"一行标题 + 一行摘要 + 两个小链接"占 2 行。
   ⚠️ 只改 .user-pop 内部的排布，不动任何 id（JS 只认 id）。
   ============================================================ */

/* ---- ① 根治：限高 + 滚动（底部内容永远够得着）---- */
.user-pop {
  /* ⚠️ 用 min() 让它在小屏上也不会被顶出去：
     视口高 - 顶栏(约 4rem) - 上下留白(约 1.5rem)。 */
  max-height: calc(100vh - 5.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;   /* 滚到边界时不要把整页一起滚走 */
  /* 滚动条：细一点，不要占掉本来就窄的面板宽度 */
  scrollbar-width: thin;
}

/* ---- ② 压缩：内边距 / 间距 / 字号 ---- */
.user-pop { padding: 0.6rem; }
.up-head { padding-bottom: 0.5rem; gap: 0.5rem; }
.up-sec { padding: 0.45rem 0 0.15rem; }
.up-sec-title { font-size: 0.74rem; }
.up-note { margin: 0.2rem 0 0.3rem; font-size: 0.66rem; }
.up-btns { gap: 0.6rem; margin-top: 0.1rem; }
.up-btns .up-ghost {
  flex: 0 0 auto; padding: 0; border: 0; background: none;
  font-size: 0.72rem; font-weight: 700; color: var(--mc-acc);
  min-height: 0; text-align: left;
}
.up-btns .up-ghost:hover { background: none; text-decoration: underline; }
/* 奖励卡再收一档（上一轮已压过一次，这里只动间距） */
.up-rewards { gap: 0.28rem; margin-top: 0.3rem; }
.up-rw { padding: 0.36rem 0.5rem; margin-bottom: 0.28rem; }
/* 账户卡：数字收小一点 */
.up-acct { margin-top: 0.35rem; }
.up-acct-card { padding: 0.4rem 0.55rem; border-radius: 0.55rem; }
.up-acct-card b { font-size: 1.02rem; }
.up-acct-hint { margin: 0.2rem 0 0; font-size: 0.62rem; }
/* 会员块 + 底部功能格 */
.up-vip { margin-top: 0.5rem; padding: 0.5rem 0.65rem; }
.up-grid { gap: 0.35rem; margin-top: 0.5rem; }
.up-grid a, .up-grid button { padding: 0.34rem 0.4rem; font-size: 0.76rem; }

/* ---- ③ 深色下滚动条不要突兀 ---- */
html[data-theme="dark"] .user-pop { scrollbar-color: #3a4252 transparent; }

/* v2.765-step2：团队块的说明收成单行（它原来是独立一行，白占） */
.up-note {
  /* ⚠️ 文字由 bindTeamWidget 填，不能删元素 —— 只能收排版。
     单行 + 省略号：长文案不折行，把这一行的高度锁死。 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  line-height: 1.35;
}
/* 团队块标题与内容挨紧（它上面还有一条分隔的 .up-sec 内边距） */
.up-sec[id="up-team-sec"] { padding-top: 0.4rem; }

/* ============================================================
   ★★★ v2.768：统计在【宽屏只显示 6 个主要指标】
   ------------------------------------------------------------
   🔴 背景：统计挪进资料行右边那块之后，10 个格子挤在约 700px 里。
      v2.764 交付时我留了一句"挤了就告诉我"，用户回"先做出来看看效果"。

   ★ 为什么是【前 6 个】：渲染顺序本身就是分好组的（见 me-center.js 的 cells）——
       前 6 个 = 我有什么（作品 / 公开中 / 图片 / 视频 / 音频 / 任务）
       后 4 个 = 别人对我做了什么（被点赞 / 被收藏 / 分享 / 粉丝）
     ⇒ 收后 4 个，保留的是"我自己最关心的那几个数"。

   ★ 为什么【窄屏反而全部显示】：
     窄屏时统计会整行换行（.mc-head-lower 是 wrap），地方反而够。
     在那里收起会把内容藏掉 —— 用户要的是"别挤"，不是"别给我看"。
   ============================================================ */

/* 宽屏：只留前 6 格（后 4 格收起） */
@media (min-width: 1024px) {
  .mc-stats-compact .mc-stat:nth-child(n + 7) { display: none; }
}

/* ------------------------------------------------------------
   ★ 方案 B（备用，现在【不启用】）：把灵感开关挪到积分那一列下面，
     统计就能恢复显示全部 10 个。
     ⚠️ 启用方法：把下面三条前面的注释符去掉，并删掉上面那条 nth-child 规则。
     ⚠️ 为什么留着不删：用户是"先看效果"再定 —— 留着省一轮往返。

   .mc-head-right .mc-share { margin-top: .35rem; }
   .mc-head-lower .mc-share { display: none; }
   .mc-stats-compact { grid-template-columns: repeat(10, minmax(0, 1fr)); }
   ------------------------------------------------------------ */

/* ============================================================
   ★★★ v2.769：统计那块拿到应得的宽度
   ------------------------------------------------------------
   🔴 用户反馈（截图）：「略微有点些丑，需要改变一下样式。」

   ★ 丑的根因：统计被放进了 .mc-head-info【里面】，
     而那一列的 flex 是 `1 1 150px` —— 150px 是【昵称那一列】的基准宽，
     不是给统计用的。⇒ 统计跟着被压窄到那个基准，10 个格子挤成一团；
     同时昵称/bio 被顶到最左边贴边。

   ★ 修法（不动 DOM，只改 flex 职责）：
     · 让 .mc-head-lower（统计 + 开关那一行）去"吃掉空白"：flex: 1 1 auto
     · .mc-head-info 不再伸展：flex: 0 1 150px —— 它只放昵称/bio，不需要宽
     ⇒ 统计那块拿到约 700px，10 个格子排得开。
   ⚠️ 同时撤掉 v2.768 那条「宽屏只显 6 个」：
      它是在"只有 150px"的前提下做的妥协；现在地方够了，10 个都该显示。
   ============================================================ */

/* 统计那一行抢过"吃掉空白"的职责 */
.mc-head-lower { flex: 1 1 260px; }
/* 昵称那一列不再伸展（它本来就不需要宽） */
.mc-head-info { flex: 0 1 150px; }
/* 格子宽回正常值（2.6rem 是"挤在 150px 里"时的妥协） */
.mc-head-lower .mc-stats { grid-template-columns: repeat(auto-fit, minmax(3.1rem, 1fr)); }
/* 数字回正常字号（之前收到 0.92rem 也是为了塞进 150px） */
.mc-stats-compact .mc-stat b { font-size: 1.02rem; }
.mc-stats-compact .mc-stat span { font-size: 0.64rem; }
.mc-stats-compact .mc-stat { padding: .06rem .2rem; }

/* ⚠️ 撤销 v2.768 的"宽屏只显 6 个" —— 现在地方够，10 个都显示。
   （保留这条撤销记录，免得以后有人看到旧规则以为它还有用。） */
@media (min-width: 1024px) {
  .mc-stats-compact .mc-stat:nth-child(n + 7) { display: flex; }
}

/* ============================================================
   ★★★ v2.770：用户卡 → 第一行 4 栏 + 统计单独一行摊开
   ------------------------------------------------------------
   🔴 用户原话（在截图上画了 4 个框）：「你把这块分为4个栏，来做，
      不就不会那么空了，而且可以节约下面一行的空间，让给作品管理页面。
      方便看图呀。」
   ★ 用户已确认按【理解 B】做（见对话）——
     不是"把统计塞进 1 栏"，而是"第一行 4 栏摆身份/特权/积分/皮肤，
     统计摊到第二行整行"。
     ⚠️ 理由（算过）：卡片可用宽约 1560px；
        统计塞 1 栏 ⇒ 每格约 39px（比改之前 44px 还挤，等于白改）；
        摊满一行 ⇒ 每格约 156px，数字才看得清、左侧也不空。

   ★ 技术点：.mc-head-info 用 display:contents（自身不生成盒子）
     ⇒ 昵称行 / bio / UID 直接变成 .mc-head-main 的网格项，
        DOM 不用改、id 全不变（JS 完全不受影响）。

   ★ 栏位：
     col1   = 头像 + 昵称/徽标 + bio + UID
     col2-3 = 会员特权胶囊（它在 .mc-name-row 里，随那一行走）
     col4   = 积分 + 皮肤
     第二行 = 统计（col1-3）+ 灵感开关（col4）
   ⚠️ 为什么统计占 col1-3 而不是全 4 栏：把 col4 留给开关，
      它就不会再和统计抢位置（改之前统计往右溢、压住积分，就是这个原因）。
   ⚠️ 只在 ≥1024px 生效 —— 窄屏仍然用原来的 flex 换行排布
      （窄屏没有 4 栏的空间，硬套网格会碎成一片）。
   ============================================================ */
@media (min-width: 1024px) {
  .mc-head-main {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.9fr);
    align-items: center;
    gap: .45rem .9rem;
    padding-bottom: .55rem;
  }
  /* ① 头像：第一栏，跨两行（视觉上和身份块同高） */
  .mc-ava-wrap { grid-column: 1; grid-row: 1; align-self: start; }
  /* ⚠️ 让 .mc-head-info 的内容参与外层网格（它自己不留盒子） */
  .mc-head-info { display: contents; }
  /* 昵称行：占 col1 的剩余（头像在它左边，用内边距让开） */
  .mc-name-row {
    grid-column: 1 / span 3; grid-row: 1;
    padding-left: 3.4rem;      /* ⚠️ 给头像让位（头像 44px + 间距） */
    min-width: 0;
  }
  /* ⚠️ 特权胶囊在 .mc-name-row 里 ⇒ 靠 margin-left:auto 推到那一段的右端，
     正好落在 col2-3 的位置上。把它之前为"丝带避让"加的右内边距收掉，
     否则会顶出网格。 */
  .mc-vip .mc-vip-perks { padding-right: 0; }
  .mc-vip-perks { flex-wrap: nowrap; }
  /* bio / UID：也放第一栏（跟昵称同栏、往下压一行） */
  .mc-bio { grid-column: 1; grid-row: 1; align-self: end; margin: 0; padding-left: 0; }
  .mc-sub { grid-column: 1; grid-row: 1; align-self: end; margin: 0; padding-left: 0; transform: translateY(1rem); }
  /* ④ 积分 + 皮肤：第四栏 */
  .mc-head-right {
    grid-column: 4; grid-row: 1;
    align-items: flex-end; justify-self: end;
    min-width: 0;
  }
  /* 第二行：统计占 col1-3，开关占 col4 */
  .mc-head-lower {
    grid-column: 1 / -1; grid-row: 2;
    display: grid;
    grid-template-columns: minmax(0, 3.25fr) minmax(0, 1fr);
    align-items: center; gap: .9rem;
    margin-top: .1rem; padding-top: .5rem;
  }
  /* 统计：10 个均分（每格约 156px） */
  .mc-head-lower .mc-stats {
    grid-template-columns: repeat(10, minmax(0, 1fr));
    flex: 0 0 auto; margin: 0;
  }
  /* 边界：这一行不该带负边距（那会让它顶出卡片） */
  .mc-head-lower .mc-stats, .mc-strip { margin-left: 0; margin-right: 0; }
  .mc-head-lower .mc-share { justify-self: end; margin: 0; min-width: 0; }
  /* 数字回正常尺寸（之前为"挤在 150px 里"收过字号） */
  .mc-stats-compact .mc-stat b { font-size: 1.05rem; }
  .mc-stats-compact .mc-stat span { font-size: 0.64rem; }
  .mc-stats-compact .mc-stat { padding: .1rem .25rem; }
}
