/* web/styles.css · neuo 设计体系（深墨底 + 克制紫标识，三档自适应） */
:root {
  --c-bg: #0B0B0F;            /* 页面深墨底 */
  --c-panel: #14141B;         /* 侧栏 / 卡片 */
  --c-card: #1B1B24;          /* 输入框 / 内控卡片 */
  --c-control: #24242F;       /* 控件底 / hover */
  --c-primary: #6E56F0;       /* 主色：克制紫 */
  --c-primary-d: #5A45D6;
  --c-primary-2: #9C8CFF;     /* 紫（高对比文本用） */
  --c-primary-l: rgba(110, 86, 240, 0.16);
  --c-border: #2C2C38;
  --c-border-d: #3A3A48;
  --c-text: #ECECF2;          /* 主文字 */
  --c-sub: #B6B6C4;           /* 次文字 */
  --c-hint: #9393A1;          /* 弱提示（WCAG AA 4.5+） */
  --c-danger: #FF5A5A;
  --radius: 14px;
  --radius-s: 10px;
  --shadow: 0 10px 34px rgba(0, 0, 0, 0.45);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
  background: var(--c-bg);
  color: var(--c-text);
  font-size: 15px;
  line-height: 1.6;
}
a { color: inherit; text-decoration: none; }

#app { min-height: 100vh; }
.main-wrap { min-height: 100vh; display: flex; flex-direction: column; margin-left: 240px; }

/* ===== 侧边栏（桌面） ===== */
.side {
  position: fixed; top: 0; left: 0; bottom: 0; width: 240px; z-index: 30;
  background: var(--c-panel); border-right: 1px solid var(--c-border);
  display: flex; flex-direction: column; padding: 22px 16px;
}
.side::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--c-primary), var(--c-primary-2));
}
.side-brand { display: flex; align-items: center; gap: 11px; padding: 4px 6px 26px; }
.monogram {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  background: linear-gradient(135deg, var(--c-primary), var(--c-primary-2));
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 13px; box-shadow: 0 4px 14px rgba(110, 86, 240, 0.4);
}
.side-brand-text { display: flex; flex-direction: column; line-height: 1.2; }
/* neuoki 字标：白色粗体 neu + 蓝色圆环 o + 白色 ki（参考品牌图，深墨底） */
.brand-logo {
  display: inline-flex; align-items: center; gap: 0;
  font-size: 21px; font-weight: 800; letter-spacing: .2px;
  color: var(--c-text); line-height: 1; white-space: nowrap;
}
.brand-accent { color: var(--c-primary-2); }
.brand-sub { font-size: 11px; color: var(--c-hint); }
.side-nav { display: flex; flex-direction: column; gap: 4px; }
.side-link {
  position: relative; display: flex; align-items: center; min-height: 44px;
  padding: 0 14px; border-radius: 10px; color: var(--c-sub);
  font-size: 14.5px; transition: background .15s, color .15s;
}
.side-link:hover { color: var(--c-text); background: var(--c-card); }
/* 导演台副标题：桌面侧栏（三端同款小字） */
.side-link-with-sub { flex-direction: column; align-items: flex-start; justify-content: center; gap: 1px; }
.side-link-sub { font-size: 11px; line-height: 1.25; color: var(--c-hint); font-weight: 400; }
.side-link.active .side-link-sub { color: var(--c-primary-2); }
.side-link.active { color: var(--c-text); background: var(--c-primary-l); font-weight: 600; }
.side-link.active::before {
  content: ""; position: absolute; left: -16px; top: 9px; bottom: 9px; width: 3px;
  background: var(--c-primary); border-radius: 0 3px 3px 0;
}
.side-foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--c-border); }
.side-foot .uname { display: block; font-size: 13px; color: var(--c-sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 用户名 + 积分胶囊同一行（之前是块级/行内混排，积分会掉到下一行） */
.side-foot .ub-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.side-foot .ub-row .uname { flex: 1 1 auto; min-width: 0; }
.side-foot .ub-row .ub-points { flex: 0 0 auto; }
/* 受限 webview（微信等）里起不来支付宝 → 给一条能复制带走自己付的链接 */
.pay-guide {
  margin: 12px 0 4px; padding: 14px 16px; border-radius: 12px;
  border: 1px solid var(--c-primary); background: var(--c-primary-l);
}
.pay-guide-title { font-size: 14px; font-weight: 600; color: var(--c-text); margin-bottom: 6px; }
.pay-guide-sub { font-size: 12px; line-height: 1.7; color: var(--c-sub); margin-bottom: 12px; }
.pay-guide .primary-btn { width: 100%; }
.pay-guide-open {
  display: block; text-align: center; text-decoration: none; box-sizing: border-box;
}
.pay-guide-open:hover { color: var(--c-primary); }
/* 支付方式切换（支付宝 / 微信支付）：只有一个渠道时不渲染 */
.pay-channels { display: flex; gap: 8px; margin: 10px 0 2px; }
.pay-chip { flex: 0 0 auto; }
/* 微信 Native 扫码：二维码白底黑块，别跟卡片同色。
   ⚠️ 尺寸不能太小 —— 180px 时手机摄像头扫屏幕上的码基本扫不出来（每格才 4px），
   放大到 280px 才稳。 */
.qr-box {
  width: 280px; max-width: 100%; margin: 0 auto 12px; padding: 12px; box-sizing: border-box;
  background: #fff; border-radius: 10px; line-height: 0;
}
.qr-box svg, .qr-box img { width: 100%; height: auto; display: block; }

.btn-ghost {
  margin-top: 8px; border: 1px solid var(--c-border-d); background: transparent; color: var(--c-sub);
  border-radius: 999px; padding: 7px 14px; font-size: 13px; cursor: pointer; width: 100%;
  transition: border-color .15s, color .15s; font-family: inherit;
}
.btn-ghost:hover { border-color: var(--c-primary); color: var(--c-primary); }

/* ===== 顶部栏（平板 / 手机） ===== */
.topbar { display: none; }
.tabbar { display: none; }

/* ===== 路由出口 =====
   2026-10-31：生成页不再卡 920px 窄条 —— 大屏要铺开才好看，改成自适应放宽。
   其余页面保留一个宽松上限，免得超宽屏上一行字拉得太长。 */
/* ⚠️ 2026-10-31：原来 1180px 太窄 —— 生成页已经放到 1680，会员/充值/任务/FAQ
   却还卡在 1180 里，右侧一大片空白（用户原话"应该也要做成自适应，不是固定宽度"）。 */
.view { flex: 1; padding: 28px; width: 100%; max-width: 1440px; margin: 0 auto; }
.view:has(.submit-card) { max-width: 1680px; }
@media (min-width: 1800px) { .view:has(.submit-card) { max-width: 90vw; } }
.env-hint { margin-left: auto; font-size: 11px; color: var(--c-hint); }

/* ===== 卡片 ===== */
.card {
  background: var(--c-panel); border: 1px solid var(--c-border);
  border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow);
}
.section-title { font-size: 17px; font-weight: 700; margin: 0 0 4px; color: var(--c-text); }
.section-hint { font-size: 12.5px; color: var(--c-hint); margin: 0 0 14px; line-height: 1.5; }
.section-title + .section-hint { margin-top: -4px; }
.ctrl-hint { font-size: 12px; color: var(--c-hint); margin: 6px 0 0; line-height: 1.5; }

/* ===== Hero（生成页标题） ===== */
.hero { margin-bottom: 18px; }
.hero-title { font-size: 30px; font-weight: 800; line-height: 1.25; margin: 0 0 6px; color: var(--c-text); letter-spacing: .4px; }
.hero-title .accent { color: var(--c-primary); }
.hero-sub { font-size: 13.5px; color: var(--c-hint); margin: 0; }

/* ===== 生成页双列布局 ===== */
.submit-grid { display: grid; grid-template-columns: 1fr; gap: 18px; }
@media (min-width: 640px) { .submit-grid { grid-template-columns: 1fr 1fr; gap: 22px; } }
.col-main, .col-params { min-width: 0; }

/* 2026-10-31：本机 / 云端**两档**共用同一套「创作卡」布局（单列 + 隐藏左列），
   切换档位时页面结构不再跳变——这也是用户要的"看起来是一体的"。
   左列的输入框和缩略图会被搬进创作卡（DOM 搬家，不是重建）。 */
.submit-card .submit-grid { grid-template-columns: 1fr; }
.submit-card .col-main { display: none; }
/* 卡里的输入框自带「＋ 参考」，左列那排按钮（＠素材库 / AI 优化）不再出现 */
.submit-card .prompt-footer { display: none; }

/* ===== 云端创作卡（即梦式） ===== */
/* ⚠️ 本站是**深色主题**（--c-text 是浅色），这里一律用主题变量，
   绝不能写死 #fff —— 白底 + 浅色文字 = 控件栏整个看不见（第一版就踩了这个）。 */
.composer {
  margin-top: 12px; padding: 14px; border-radius: var(--radius);
  background: linear-gradient(180deg, rgba(110, 86, 240, .10) 0%, rgba(110, 86, 240, .03) 100%);
  border: 1px solid var(--c-border);
}
.composer-title { font-size: 15px; font-weight: 700; color: var(--c-text); margin: 2px 2px 10px; }
.composer-box { position: relative; }
.composer-box .prompt-editor {
  /* 创作卡里的输入框同样封顶（比通用框略矮，给下面的控件条留空间） */
  min-height: 132px; max-height: 300px; overflow-y: auto; overscroll-behavior: contain;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-s); padding: 14px 14px 52px;
}
.composer-box .prompt-editor:focus { border-color: var(--c-primary); }
/* 占位文案两行（data-placeholder 里的 \n） */
.composer-box .prompt-editor:empty::before { white-space: pre-line; }
.composer-actions {
  position: absolute; left: 12px; bottom: 12px;
  display: flex; align-items: center; gap: clamp(5px, 1.2vw, 8px); flex-wrap: wrap;
}
/* 「✨ AI 优化描述词」是从 prompt-footer 搬来的（.at-btn），跟这排按钮对齐。
   ⚠️ 2026-10-31：通用 .at-btn 自带 `min-height:40px`（比 .ref-add-btn 的 26~30px
   高一截），而 min-height 会压过 height —— 不显式归零就永远比旁边两个高，
   三个按钮不在同一水平线（用户截图）。高度改用跟 .ref-add-btn 同一套 clamp。 */
/* 风格库「看效果」按钮：放在副控件条里，要和胶囊等高，别把整行撑高 */
/* 风格下拉面板里的「看效果」小按钮：右对齐，别和选项名抢位置 */
.picker-option .picker-peek {
  float: right;
  margin-left: 10px;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  color: var(--c-primary-2);
  background: var(--c-primary-l);
  white-space: nowrap;
}
.picker-option .picker-peek:hover { background: var(--c-primary); color: #fff; }
.ctrl-bar-sub .style-peek {
  height: clamp(26px, 4vw, 30px); min-height: 0;
  padding: 0 clamp(8px, 2vw, 12px); border-radius: 999px;
  font-size: clamp(11.5px, 2.05vw, 13px); font-weight: 400;
  background: var(--c-control); border: 1px solid var(--c-border); color: var(--c-sub);
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  white-space: nowrap; cursor: pointer; font-family: inherit;
}
.ctrl-bar-sub .style-peek:hover { border-color: var(--c-primary); color: var(--c-primary-2); }
.ctrl-bar-sub .style-peek[hidden] { display: none; }
.composer-actions .at-btn {
  height: clamp(26px, 4vw, 30px); min-height: 0;
  padding: 0 clamp(8px, 2vw, 12px); border-radius: 999px;
  font-size: clamp(11.5px, 2.05vw, 13px);
  background: var(--c-control); border: 1px solid var(--c-border); color: var(--c-sub);
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  white-space: nowrap;
}
.composer-actions .at-btn:hover { border-color: var(--c-primary); color: var(--c-primary-2); }
.composer-actions .at-btn:disabled { opacity: .45; cursor: not-allowed; }
.ref-add-btn {
  height: clamp(26px, 4vw, 30px); padding: 0 clamp(8px, 2vw, 12px);
  border-radius: 999px; border: 1px solid var(--c-border);
  background: var(--c-control); color: var(--c-sub); font-size: clamp(11.5px, 2.05vw, 13px); cursor: pointer;
}
.ref-add-btn:hover { border-color: var(--c-primary); color: var(--c-primary-2); }
.dir-enhance-btn { background: var(--c-primary); color: #fff; border-color: var(--c-primary); font-weight: 600; }
.dir-enhance-btn:hover { background: var(--c-primary-2); color: #fff; }
.composer .thumbs { margin: 10px 0 0; }

/* 控件栏 + 积分 + 发送（同一行，按设计图） */
.ctrl-row { display: flex; align-items: center; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
/* 7 个格子要挤进一行（设计图就是一行），所以这里比通用 .ctrl-bar 更紧一点 */
.composer .ctrl-bar { flex: 1 1 auto; margin: 0; justify-content: flex-start; gap: clamp(4px, .7vw, 6px); }
.composer .ctrl-bar .picker { flex: 0 1 auto; min-width: 0; }
/* ⚠️ 2026-10-31：这三个尺寸原来写死 36px / 6px 12px / 13px，手机上显得又大又占行，
   一行只塞得下 2~3 个胶囊（用户原话"是否可以根据自适应去调节这些按钮的大小"）。
   改用 clamp() 按视口宽度**无级缩放**：360px 屏收到 26px 高 / 11.5px 字，
   ≥818px 的桌面仍是原来的 36px / 13px —— 桌面观感一点不变。
   （不用 @media 是因为跳档式断点在中间尺寸会突变，clamp 是连续的。） */
.composer .ctrl-bar .picker-trigger {
  /* 与右端「生成」按钮同一套胶囊语言：控件底 + 全圆角，展开时主色描边 */
  background: var(--c-control); border: 1px solid var(--c-border); border-radius: 999px;
  min-height: clamp(26px, 4.4vw, 36px);
  padding: clamp(3px, .8vw, 6px) clamp(8px, 2.2vw, 12px);
  font-size: clamp(11.5px, 2.05vw, 13px);
  gap: clamp(3px, .7vw, 5px);
}
/* 模型名太长会把整行挤爆 → 截断（hover 有 title 看全称）；上限也跟着收窄 */
.composer .ctrl-bar .picker-trigger .pv {
  max-width: clamp(64px, 24vw, 132px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ctrl-right { display: flex; align-items: center; gap: 10px; flex: none; margin-left: auto; }
.ctrl-pts { font-size: 12px; color: var(--c-hint); white-space: nowrap; }
/* 副控件条（本机档的还原度 / 生成链路 / 提示词遵循 / 风格库 / 闪电）：
   与主控件条同款 picker，只是略矮一号，视觉上是一体的副行。
   ⚠️ 2026-10-31：它已从 .ctrl-row 的**兄弟节点**搬进 .ctrl-row **内部**
   （排在 .ctrl-right 之前）—— 兄弟节点时手机上「积分+生成」会被挤到主行和
   副行中间（用户截图：生成按钮跑中间去了）。
   ⚠️ 必须 `flex: 0 0 100%` 强制独占一行，才能把 .ctrl-right 顶到最后一行。
   选择器要带 .composer 前缀，否则压不过 `.composer .ctrl-bar { flex:1 1 auto }`。 */
.composer .ctrl-bar-sub {
  flex: 0 0 100%; margin: 2px 0 0;
  justify-content: flex-start; gap: clamp(4px, .7vw, 6px);
}
.composer .ctrl-bar-sub .picker { flex: 0 1 auto; min-width: 0; }
/* 副行整体比主行矮一号（32px vs 36px），clamp 的上限/下限同步各降一档 */
.composer .ctrl-bar-sub .picker-trigger {
  background: var(--c-control); border: 1px solid var(--c-border); border-radius: 999px;
  min-height: clamp(24px, 4vw, 32px);
  padding: clamp(2px, .7vw, 5px) clamp(7px, 2vw, 11px);
  font-size: clamp(11px, 1.95vw, 12.5px);
  gap: clamp(3px, .7vw, 5px);
}
/* ===== 生成按钮（控件栏右端，两档共用） =====
   2026-10-31 重做：原来是 40px 纯色圆 + 箭头图标，禁用态还刷成 --c-control 死灰，
   跟深色背景糊在一起（用户原话"好丑"），而且用户明确不要箭头 → 改成**「生成」文字按钮**。
   胶囊造型（全圆角）与左侧一排参数胶囊呼应；主色渐变 + 光晕 + 顶部内高光。
   ⚠️ 禁用态**不再用死灰**：保留紫色调（降饱和 + 半透明），仍一眼看出是主按钮，只是明确不可点。
   ⚠️ 宽度在同设备上仍是定值（只是按视口 clamp）：提交中把文字换成转圈时按钮不会抽动。 */
.send-btn {
  position: relative;
  /* ⚠️ 2026-10-31：手机上 96×42 太大，clamp 收到 72×34（「生成」两个字放得下）。
     border-radius 从写死的 21px（= 42/2）改成 999px，高度变了也不用跟着改圆角。 */
  width: clamp(72px, 12vw, 96px); height: clamp(34px, 5.2vw, 42px);
  flex: none; border-radius: 999px; border: none; cursor: pointer;
  background: linear-gradient(135deg, var(--c-primary-2), var(--c-primary));
  color: #fff; font-size: clamp(13.5px, 2.4vw, 15px); font-weight: 600; letter-spacing: 2px; line-height: 1;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  box-shadow: 0 3px 12px rgba(110, 86, 240, .45), inset 0 1px 0 rgba(255, 255, 255, .22);
  transition: transform .16s ease, box-shadow .16s ease, filter .16s ease;
}
.send-btn:hover:not(:disabled) {
  transform: translateY(-1px); filter: brightness(1.07);
  box-shadow: 0 6px 18px rgba(110, 86, 240, .58), inset 0 1px 0 rgba(255, 255, 255, .24);
}
.send-btn:active:not(:disabled) { transform: translateY(0) scale(.95); }
.send-btn:focus-visible { outline: 2px solid var(--c-primary-2); outline-offset: 2px; }
.send-btn:disabled {
  background: linear-gradient(135deg, rgba(156, 140, 255, .40), rgba(110, 86, 240, .36));
  color: rgba(255, 255, 255, .58);
  box-shadow: none; cursor: not-allowed;
}
/* 提交中（doSubmit 会加 .loading）：文字换成转圈，宽度不变所以按钮不抽动 */
.send-btn.loading { pointer-events: none; }
.send-btn.loading .send-label { display: none; }
.send-btn.loading::before {
  content: ''; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .38); border-top-color: #fff;
  animation: send-spin .7s linear infinite;
}
@keyframes send-spin { to { transform: rotate(360deg); } }
.send-btn:hover { opacity: .88; }
.send-btn:disabled { background: var(--c-control); color: var(--c-hint); cursor: not-allowed; }

/* ===== 文本框 ===== */
.prompt-box { position: relative; }
textarea.prompt, .prompt-editor {
  display: block; width: 100%; min-height: 150px;
  /* 2026-10-31：以前只有 min-height，内容一多整张卡被无限撑高、下面的控件条被推走。
     现在封顶 320px，超出就在框内滚动。 */
  max-height: 320px; overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-s); padding: 14px; font-size: 15px;
  font-family: inherit; color: var(--c-text); background: var(--c-card);
  box-sizing: border-box; line-height: 1.7; transition: border-color .15s;
}
textarea.prompt { resize: vertical; }
textarea.prompt:focus, .prompt-editor:focus { outline: none; border-color: var(--c-primary); }
.prompt-editor { white-space: pre-wrap; word-break: break-word; cursor: text; }
.prompt-editor:empty::before { content: attr(data-placeholder); color: var(--c-hint); pointer-events: none; }
.at-embed {
  display: inline-block; height: 28px; width: 40px; object-fit: cover;
  border-radius: 6px; vertical-align: -9px; margin: 0 2px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12); background: var(--c-control); user-select: none;
}
.at-embed.aud {
  width: 28px; text-align: center; line-height: 28px; font-size: 15px;
  background: var(--c-primary-l); color: var(--c-primary-2); font-weight: 700; box-shadow: none;
}
.prompt-footer { margin-top: 10px; display: flex; align-items: center; gap: 10px; }
.at-btn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 40px;
  background: var(--c-primary-l); color: var(--c-primary-2);
  border-radius: 999px; padding: 0 18px; font-size: 13px; font-weight: 500; cursor: pointer;
  border: none; transition: background .15s; font-family: inherit;
}
.at-btn:hover { background: rgba(110, 86, 240, 0.26); }
.at-btn:disabled { opacity: .35; pointer-events: none; }

/* ===== 上传区 ===== */
.upload-row { display: flex; gap: 12px; margin: 16px 0 4px; flex-wrap: wrap; }
.upload-card {
  flex: 1; min-width: 130px; min-height: 84px; border: 1px dashed var(--c-border-d);
  border-radius: var(--radius-s); padding: 14px; text-align: center; cursor: pointer;
  background: var(--c-card); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  transition: border-color .15s, background .15s;
}
.upload-card:hover { border-color: var(--c-primary); background: var(--c-primary-l); }
.upload-card .uc-icon { font-size: 20px; color: var(--c-primary); }
.upload-card .uc-title { font-size: 14px; color: var(--c-text); }
.upload-card .uc-count { font-size: 12px; color: var(--c-hint); }
.upload-card.disabled { opacity: .32; pointer-events: none; }
input[type=file] { display: none; }

.thumbs { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.thumb {
  position: relative; width: 64px; height: 64px; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--c-border); background: var(--c-card);
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb.audio { display: flex; align-items: center; justify-content: center; font-size: 22px; color: var(--c-primary); }
.thumb .rm {
  position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: rgba(0, 0, 0, .6); color: #fff; font-size: 12px; line-height: 18px; text-align: center; cursor: pointer;
}

/* ===== 参数区 ===== */
.param-block { margin-top: 6px; }
.param-divider { display: flex; align-items: center; gap: 12px; margin: 4px 0 14px; }
.param-divider::before, .param-divider::after { content: ""; flex: 1; height: 1px; background: var(--c-border); }
.param-divider span { font-size: 12px; color: var(--c-hint); letter-spacing: .06em; }
.param-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 12px 0; }
.param-row .param-label { font-size: 14px; color: var(--c-sub); flex: none; }
.param-row .picker { flex: 1; max-width: 64%; }

.seg { display: flex; gap: 8px; flex-wrap: wrap; }
.seg-item {
  padding: 8px 16px; border: 1px solid var(--c-border); border-radius: 999px;
  font-size: 13px; color: var(--c-sub); cursor: pointer; background: var(--c-card);
}
.seg-item.active { background: var(--c-primary); color: #fff; border-color: var(--c-primary); }
.seg-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.seg-grid-item { text-align: center; padding: 10px 0; }

/* ===== 开关 ===== */
.switch-row { display: flex; align-items: center; justify-content: space-between; margin: 16px 0 4px; padding: 0; }
.switch-row .param-label { color: var(--c-text); }
.switch-row .ctrl-hint { margin-top: 2px; }
.switch {
  position: relative; width: 46px; height: 26px; border-radius: 999px; background: var(--c-border-d);
  cursor: pointer; transition: background .2s; flex: none;
}
.switch.on { background: var(--c-primary); }
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: 50%; background: #fff; transition: transform .2s;
}
.switch.on::after { transform: translateX(20px); }

/* ===== 下拉（picker）：统一胶囊控件 =====
   ⚠️ 2026-10-31 重做：原来是「方角 + 卡片底 + ▾ 字形」的原生感方块，跟本站
      的胶囊按钮（.btn-ghost / .at-btn / .ref-add-btn / 发送按钮）不是一个体系，
      放在控件栏里像贴上去的补丁。现在统一成：胶囊圆角 + 控件底 + 主色描边，
      展开时描边变主色、箭头用 CSS 画的 V 形（字形 ▾ 在不同字体下粗细差别很大）。 */
.picker { position: relative; }
.picker-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 7px; min-height: 44px;
  border: 1px solid var(--c-border); border-radius: 999px; padding: 10px 14px;
  cursor: pointer; background: var(--c-card); font-size: 14px; color: var(--c-text);
  user-select: none;
  transition: border-color .15s, background .15s, color .15s, box-shadow .15s;
}
.picker-trigger:hover { border-color: var(--c-border-d); background: var(--c-control); }
.picker.open .picker-trigger, .picker-trigger:active {
  /* 展开态：主色描边 + 主色微光，跟「已选中」的 seg-item.active 一个语言 */
  border-color: var(--c-primary-2);
  background: var(--c-primary-l);
  box-shadow: 0 0 0 3px rgba(110, 86, 240, .14);
}
.picker-trigger .pv { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 箭头：藏掉原来的 ▾ 字形，改用 CSS 画的 V 形（锐利、不挑字体、能跟着主色变） */
.picker-trigger .arrow {
  position: relative; width: 11px; height: 11px; flex: none;
  font-size: 0; color: var(--c-hint);
  transition: transform .18s ease, color .15s;
}
.picker-trigger .arrow::after {
  content: ''; position: absolute; left: 1px; top: 1px;
  width: 6px; height: 6px;
  border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  transform: rotate(45deg);
}
.picker-trigger:hover .arrow { color: var(--c-sub); }
.picker.open .picker-trigger .arrow { color: var(--c-primary-2); transform: rotate(180deg); }
/* 「开」态（闪电等）：主色描边 + 主色文字，一眼看出这个功能是激活的 */
.picker.on .picker-trigger { border-color: var(--c-primary); color: var(--c-primary-2); }
.picker.on .picker-trigger .arrow { color: var(--c-primary-2); }
/* 高价档（1080P / 2K / 4K，企业定制）：红色描边 + 「高价」角标。
   2026-10-31：这几档单条几千积分，必须让用户在选择时第一眼就看到，
   不能等到提交后才发现被扣了多少 —— 视觉上和「开」态（主色）明显区分开。 */
.picker.is-premium .picker-trigger { border-color: #e5484d; color: #e5484d; }
.picker.is-premium .picker-trigger .arrow { color: #e5484d; }
.premium-tag {
  display: inline-block; margin-left: 5px; padding: 0 4px;
  font-size: 10px; font-style: normal; line-height: 15px;
  color: #fff; background: #e5484d; border-radius: 3px; vertical-align: 1px;
}
.hint-premium { color: #e5484d; }
.hint-premium b { font-weight: 600; }
/* 审核严格提示（Seedance 全系）：橙色，和高价档的红色区分开 ——
   一个是「贵」，一个是「素材会被拒」，用户要采取的行动完全不同。 */
.hint-audit { color: #b45309; background: rgba(180, 83, 9, .08); padding: 5px 8px; border-radius: 6px; }
.picker-panel {
  position: absolute; left: 0; right: 0; top: calc(100% + 8px); z-index: 30;
  background: var(--c-panel); border: 1px solid var(--c-border); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden; max-height: 320px; overflow-y: auto;
  animation: pkIn .14s ease;
}
@keyframes pkIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
/* ⚠️ 2026-10-31：面板位置校正（class 由 bindPicker 按视口实测后加）
   —— 默认左对齐向下展开，空间不够时贴右 / 向上翻，否则手机上会展开到屏幕外。 */
.picker-panel.to-left { left: auto; right: 0; }
.picker-panel.to-up { top: auto; bottom: calc(100% + 8px); }
/* 上下都放不下（小屏 + 长列表，如 18 个风格）→ 退化成贴底弹层，保证一定看得见 */
@media (max-width: 639px) {
  .picker-panel.as-sheet {
    position: fixed; left: 12px; right: 12px; bottom: 12px; top: auto;
    max-height: 52vh; z-index: 60;
  }
}
.picker-group { padding: 10px 14px 5px; font-size: 12px; color: var(--c-hint); font-weight: 600; letter-spacing: .03em; }
.picker-option {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 44px;
  padding: 8px 14px; cursor: pointer; font-size: 14px; color: var(--c-text);
  transition: background .12s;
}
.picker-option:hover { background: var(--c-primary-l); }
.picker-option.active { color: var(--c-primary-2); font-weight: 600; }
.picker-option.active::before { content: "✓"; margin-right: 6px; color: var(--c-primary-2); font-weight: 700; }
.picker-option.active { padding-left: 8px; }
.picker-option.disabled { color: var(--c-hint); opacity: .4; pointer-events: none; }
.picker-hint { font-size: 11.5px; color: var(--c-hint); margin-left: auto; padding-left: 10px; }

/* ===== 档位切换：MiniMaxH3 限时特价 / 云端模型 ===== */
/* 两个档位的参数集完全不同，所以用分段器分开，而不是塞进同一个面板里折叠 */
.tier-switch {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-s); padding: 4px; margin: 0 0 16px;
}
/* ⚠️ 2026-10-31：改成两行结构 —— <b>主文案</b> + <i>一行小字说明</i>。
   flex column + align-items:center 让两行居中对齐；小字用 opacity 弱化，
   选中态（.on）稍微提亮，免得主色底上小字看不清。 */
.tier-btn {
  border: 0; background: transparent; color: var(--c-sub); font: inherit;
  font-size: 13.5px; padding: 6px 4px; border-radius: 8px; cursor: pointer;
  transition: background .15s, color .15s;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; min-width: 0;
}
.tier-btn b {
  font-weight: 600; font-size: 13.5px; line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.tier-btn i {
  font-style: normal; font-size: 11px; line-height: 1.35; opacity: .7; font-weight: 400;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.tier-btn.on i { opacity: .88; }
.tier-btn:hover { color: var(--c-text); }
.tier-btn.on { background: var(--c-primary); color: #fff; font-weight: 600; }
/* ⭐ 2026-11-05：后台「参数配置」停用 H3特价 → 物理拦截，不可点、不弹说明。
   同时挂 disabled 属性 + 这个 class：disabled 挡键盘/脚本，pointer-events 挡鼠标。 */
.tier-btn.tier-off, .tier-btn:disabled {
  opacity: .32; pointer-events: none; cursor: not-allowed;
  background: transparent; color: var(--c-sub); font-weight: 400;
}
.tier-btn.tier-off:hover { color: var(--c-sub); }

/* ===== 云端档位：即梦式控件栏（一行胶囊，放不下自动换行） ===== */
.ctrl-bar { display: flex; flex-wrap: wrap; gap: 8px; }
.ctrl-bar .picker { flex: 1 1 auto; min-width: 92px; }
.ctrl-bar .picker-trigger { min-height: 40px; padding: 8px 12px; font-size: 13.5px; }
.ctrl-bar .picker-trigger .ck { font-size: 11.5px; color: var(--c-hint); flex: none; }
.ctrl-bar .picker-panel { min-width: 170px; }
/* 未实装的格子：压暗 + 物理拦截，不弹解释弹窗 */
.ctrl-bar .picker.is-off { opacity: .42; }
.ctrl-bar .picker.is-off .picker-trigger { cursor: not-allowed; }
.cost-note { color: var(--c-hint); font-size: 12px; }

/* ===== 主按钮 ===== */
.primary-btn {
  width: 100%; margin-top: 18px; padding: 15px; border: none; border-radius: var(--radius-s);
  background: var(--c-primary); color: #fff; font-size: 16px; font-weight: 600; cursor: pointer;
  transition: background .15s, transform .05s; font-family: inherit;
}
.primary-btn:hover { background: var(--c-primary-d); }
.primary-btn:active { transform: scale(0.99); }
.primary-btn:disabled { background: var(--c-border-d); color: var(--c-hint); cursor: not-allowed; }
.primary-btn.loading { opacity: .7; }

/* ===== @ 素材弹层 ===== */
.at-panel-mask { position: fixed; inset: 0; background: rgba(0, 0, 0, .5); z-index: 40; display: flex; align-items: flex-end; }
.at-panel {
  width: 100%; background: var(--c-panel); border-radius: 24px 24px 0 0; padding: 22px 18px 34px;
  max-width: 920px; margin: 0 auto; box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.4);
}
.at-panel h3 { margin: 0 0 4px; font-size: 16px; color: var(--c-text); }
.at-panel .sub { font-size: 12px; color: var(--c-hint); margin-bottom: 14px; }
.at-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.at-chip {
  background: var(--c-primary-l); color: var(--c-primary-2); border-radius: 12px;
  padding: 12px 16px; font-size: 14px; cursor: pointer; transition: background .12s;
}
.at-chip:hover { background: rgba(110, 86, 240, 0.26); }
.at-chip .hint { font-size: 11px; color: var(--c-sub); display: block; margin-top: 2px; }
.at-thumb {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: 76px; padding: 8px 6px; border-radius: 12px; cursor: pointer;
  background: var(--c-card); border: 2px solid transparent; box-sizing: border-box;
}
.at-thumb:hover { border-color: var(--c-primary); }
.at-thumb img { width: 60px; height: 60px; object-fit: cover; border-radius: 8px; display: block; background: var(--c-control); }
.at-thumb .a-icon {
  width: 60px; height: 60px; border-radius: 8px; background: var(--c-primary-l);
  display: flex; align-items: center; justify-content: center; font-size: 24px; color: var(--c-primary-2);
}
.at-thumb .lbl { font-size: 12px; color: var(--c-sub); font-weight: 500; }
.at-cancel { text-align: center; margin-top: 16px; color: var(--c-sub); font-size: 14px; cursor: pointer; }

/* ===== 列表 ===== */
/* ⚠️ 2026-10-31：原来是单列竖排，宽屏上每行都空着一半 → 改成自适应多列。
   min(100%, 380px) 是关键：窄屏（<380px）时列宽自动退回 100%，不会横向溢出。 */
.task-list {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr));
  align-items: start;
}
.task-card {
  display: flex; gap: 12px; align-items: center; background: var(--c-panel); border: 1px solid var(--c-border);
  border-radius: var(--radius); padding: 12px; cursor: pointer; box-shadow: var(--shadow);
  transition: border-color .15s;
}
.task-card:hover { border-color: var(--c-primary); }
.task-thumb { width: 88px; height: 88px; border-radius: 10px; background: #000; flex: none; overflow: hidden; }
.task-thumb video, .task-thumb img { width: 100%; height: 100%; object-fit: cover; }
.task-info { flex: 1; min-width: 0; }
.task-prompt { font-size: 14px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; color: var(--c-text); }
.task-meta { font-size: 12px; color: var(--c-hint); margin-top: 4px; }
.badge { display: inline-block; font-size: 11px; padding: 2px 9px; border-radius: 999px; margin-top: 6px; }
.badge.pending, .badge.submitted { background: var(--c-control); color: var(--c-sub); }
.badge.running { background: var(--c-primary-l); color: var(--c-primary-2); }
.badge.completed { background: rgba(86, 200, 122, 0.16); color: #5fd07f; }
.badge.failed, .badge.cancelled { background: rgba(255, 90, 90, 0.16); color: var(--c-danger); }
.task-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.task-head .badge { margin-top: 0; }
.task-time { font-size: 12px; color: var(--c-hint); }
/* 任务编号：等宽字体方便比对，点一下复制给后台查单用 */
.task-id, .row-ref-id {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px; color: var(--c-sub); background: var(--c-control);
  border: 1px solid var(--c-border); border-radius: 5px;
  padding: 1px 6px; cursor: pointer; user-select: all; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.task-id:hover, .row-ref-id:hover { color: var(--c-primary-2); border-color: var(--c-primary); }
.task-id.copied, .row-ref-id.copied { color: #5fd07f; border-color: #5fd07f; }
.row-ref-id { align-self: flex-start; }
.param-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.param-chip {
  font-size: 11px; color: var(--c-sub); background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: 6px; padding: 2px 7px; line-height: 1.5; white-space: nowrap;
}
.param-chip b { color: var(--c-hint); font-weight: 500; margin-right: 4px; }
.param-chip i { font-style: normal; color: var(--c-hint); margin-left: 4px; }
.task-prog { font-size: 12px; color: var(--c-primary-2); margin-top: -4px; }
.task-error { font-size: 12px; color: var(--c-danger); margin-top: 6px; }
.task-actions { display: flex; gap: 14px; margin-top: 8px; }
.task-actions .link-btn { font-size: 13px; text-decoration: none; }
/* 「重新编辑」是 <button>，需抹掉浏览器默认样式才能和旁边的 <a> 长得一样 */
button.link-btn { background: none; border: none; padding: 0; margin: 0; font: inherit; }

/* ===== 详情 =====
   ⚠️ 2026-10-31 重排（用户截图指定）：原来是「视频缩在左上 280px + 信息挤在右列」，
   宽屏上右侧大片空白、视频又小得看不清。改成与手机端一致的纵向排版：
   ① 视频居中 + 按任务自身 aspect_ratio 自适应（比例写在 video 的 style 上）；
   ② 8 项参数搬到视频下方，排成 2 列小卡片。 */
.detail-video-wrap { display: flex; justify-content: center; margin-bottom: 16px; }
.detail-video {
  display: block; width: 100%;
  /* ⚠️ 2026-10-31：420 → 640（用户原话"宽度还是不够"）。高度上限同步放宽到 70vh：
     16:9 的片子先撞的是高度，只放宽宽度、不放高度等于没改。 */
  max-width: 640px; max-height: 70vh;
  height: auto; object-fit: contain;      /* 竖屏片也不会被拉变形，留黑边 */
  border-radius: 12px; background: #000;
}
/* 元信息条：编号 / 状态 / 创建时间。
   ⚠️ 2026-10-31：这三项是系统给的，跟下方"用户自己选过的参数"分开一行小字，
   混在卡片里会让人分不清哪些是自己选的（用户原话"记录还是旧的"）。 */
.detail-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  font-size: 12px; color: var(--c-hint); margin-bottom: 10px;
}
.detail-meta .badge { margin-top: 0; }    /* .badge 自带 6px 上边距，在这一行里会顶歪 */
.detail-grid {
  display: grid;
  /* 自适应列数：宽屏 3~4 列、窄屏自动塌 1 列 —— 不用写死断点，
     参数项数量随模型档位变化（云端 / 本机各一套），写死列数必然有时空半行。 */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: 10px; margin-bottom: 14px;
}
.dg-item {
  /* ⚠️ 2026-10-31：标签和值**同一行**（左标签、右值）。原来是两个 block 上下叠，
     8 项参数占 16 行太散，用户明确要求"不要分行，直接一行显示完"。 */
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  min-width: 0; background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: 10px; padding: 8px 12px;
}
.dg-item.wide { grid-column: 1 / -1; }    /* 「排队 第 N 位 / 共 M 个在等」太长，独占一行 */
.dg-k { flex: none; font-size: 12px; color: var(--c-hint); }
.dg-v {
  /* 值超长自动省略号（不折行），完整值挂在 title 上悬浮可见 */
  flex: 1 1 auto; min-width: 0; text-align: right;
  font-size: 13.5px; color: var(--c-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dg-v i { font-style: normal; font-size: 11.5px; color: var(--c-hint); margin-left: 5px; }
.dp-wrap { margin-top: 10px; }
.detail-prompt { font-size: 14px; line-height: 1.6; color: var(--c-text); white-space: pre-wrap; word-break: break-word; }
/* ⚠️ 2026-10-31：AI 改写后的分镜稿动辄上千字，整段铺开会把视频顶出屏幕
   （用户原话"应该要折叠起来"）→ 默认折到 3 行 + 底部渐隐，点「展开全文」才全显。 */
.detail-prompt.is-clamp {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 58%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 58%, transparent 100%);
}
.dp-toggle {
  margin-top: 4px; padding: 0; border: 0; background: none; font-family: inherit;
  color: var(--c-primary-2); font-size: 12.5px; cursor: pointer;
}
.dp-toggle:hover { text-decoration: underline; }

/* ===== 常见问题（折叠列表） ===== */
.faq-card { padding: 6px 22px; }
.faq-item { border-bottom: 1px solid var(--c-border); padding: 16px 0; }
.faq-item:last-of-type { border-bottom: none; }
.faq-q {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 15px; font-weight: 500; color: var(--c-text); cursor: pointer; list-style: none;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-arrow { color: var(--c-hint); font-size: 12px; transition: transform .2s; }
.faq-item[open] .faq-arrow { transform: rotate(180deg); }
.faq-a { font-size: 13.5px; line-height: 1.8; color: var(--c-sub); margin-top: 10px; }
.faq-a p { margin: 0 0 8px; }
.faq-a p:last-child { margin-bottom: 0; }
.kv { font-size: 13px; color: var(--c-sub); margin: 4px 0; }
.kv b { color: var(--c-text); font-weight: 500; }
.link-btn { color: var(--c-primary-2); cursor: pointer; font-size: 14px; }
.progress-bar { height: 6px; background: var(--c-border); border-radius: 999px; overflow: hidden; margin: 10px 0; }
.progress-bar > i { display: block; height: 100%; background: var(--c-primary); width: 0; transition: width .4s; }

/* ===== 登录 ===== */
.login-wrap { max-width: 360px; margin: 6vh auto; }
.login-wrap input {
  width: 100%; padding: 12px 14px; border: 1px solid var(--c-border); border-radius: var(--radius-s);
  font-size: 15px; margin: 10px 0; background: var(--c-card); color: var(--c-text); font-family: inherit;
}
.login-wrap input:focus { outline: none; border-color: var(--c-primary); }
.login-tip { font-size: 12px; color: var(--c-hint); margin-top: 10px; text-align: center; }
/* 登录卡底部改用站点广告语（原来是"后端：xxx"这种调试信息，不该给用户看） */
.login-slogan { margin-top: 18px; font-size: 13px; line-height: 1.7; }

/* ===== toast ===== */
.toast {
  position: fixed; left: 50%; bottom: 80px; transform: translateX(-50%) translateY(20px);
  background: rgba(20, 20, 26, 0.94); color: #fff; padding: 10px 18px; border-radius: 999px;
  font-size: 13px; opacity: 0; pointer-events: none; transition: all .25s; z-index: 120; max-width: 90%;
  border: 1px solid var(--c-border);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ===== modal ===== */
/* ⭐ 遮罩必须高于手机端下拉面板 / tabbar / 侧栏（它们分别是 z-index 60 / 25 / 30）；
   toast 再高一层（120），弹窗里点「保存」的提示才不会被遮罩挡住。
   overscroll-behavior：弹窗滚到边界时不要把滑动甩给 body（安卓 Chrome 有效）。 */
.modal-mask {
  position: fixed; inset: 0; background: rgba(0, 0, 0, .5); z-index: 100;
  display: flex; align-items: center; justify-content: center;
  overscroll-behavior: contain;
}
.modal-mask[hidden] { display: none; }
.modal {
  /* ⭐ 2026-11-03：给右上角关闭按钮当定位参照（position 只加不减，不影响别的弹窗） */
  position: relative;
  background: var(--c-panel); border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 20px; max-width: 90%; width: 420px; box-shadow: var(--shadow);
}
/* 右上角关闭（×）：弹窗以前只能点遮罩关，手机端尤其难关 */
.modal-close {
  position: absolute; top: 10px; right: 12px;
  width: 30px; height: 30px; padding: 0; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; font-family: inherit; color: var(--c-sub);
  background: transparent; border: 1px solid var(--c-border); border-radius: 50%;
  cursor: pointer; transition: color .15s, border-color .15s, background .15s;
}
.modal-close:hover { color: var(--c-text); border-color: var(--c-primary); background: var(--c-control); }
.modal h3 { margin: 0 0 10px; color: var(--c-text); }
.modal .modal-actions { margin-top: 16px; text-align: right; }
.modal .modal-actions button { margin-left: 8px; }

/* ===== 到账成功弹窗（大字，一眼看到）===== */
.paid-modal { text-align: center; padding: 6px 0 2px; }
.paid-icon {
  width: 62px; height: 62px; margin: 0 auto 14px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; line-height: 1; color: #fff;
  background: linear-gradient(135deg, #2ecc71, #27ae60);
  box-shadow: 0 6px 18px rgba(46, 204, 113, .35);
}
.paid-modal .modal-title { font-size: 20px; margin-bottom: 10px; }
.paid-points { font-size: 34px; font-weight: 800; color: var(--c-primary); line-height: 1.2; margin-bottom: 6px; }
.paid-modal .modal-sub { margin-bottom: 18px; font-size: 13px; }
.paid-modal .modal-actions { text-align: center; }
.paid-modal .modal-actions button { margin: 0; min-width: 160px; }

/* ===== 支付方式选择弹窗（点「立即充值」后弹出）===== */
.pay-pick-list { display: flex; flex-direction: column; gap: 10px; }
.pay-pick-item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 16px 18px; box-sizing: border-box;
  border-radius: var(--radius-s); cursor: pointer;
  border: 1px solid var(--c-border); background: var(--c-card);
  transition: border-color .15s, background .15s;
}
.pay-pick-item:hover { border-color: var(--c-primary); }
.pay-pick-item.active { border-color: var(--c-primary); background: rgba(124, 92, 255, .12); }
/* 微信内置浏览器里支付宝起不来 → 物理拦截（半透明 + 不可点），不弹解释 */
.pay-pick-item.blocked { opacity: .32; pointer-events: none; }
.pay-pick-name { font-size: 17px; font-weight: 700; color: var(--c-text); display: flex; align-items: center; gap: 8px; }
.pay-pick-rec {
  font-style: normal; font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 999px;
  background: var(--c-primary); color: #fff;
}
.pay-pick-icon {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 700; color: #fff; background: var(--c-primary);
}
.pay-pick-item[data-ch="wxpay"] .pay-pick-icon { background: #22c55e; }
.pay-pick-item[data-ch="alipay"] .pay-pick-icon { background: #1677ff; }
.pay-pick .modal-actions { text-align: center; }
.pay-pick .modal-actions button { margin: 0; }

/* ===== 高清处理弹窗（档位选择）===== */
.modal-title { font-size: 16px; font-weight: 700; color: var(--c-text); margin-bottom: 4px; }
.modal-sub { font-size: 12px; color: var(--c-hint); margin-bottom: 14px; line-height: 1.5; }
.hd-opts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.hd-opt {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
  padding: 12px 14px; border-radius: var(--radius-s); cursor: pointer;
  border: 1px solid var(--c-border); background: var(--c-card);
  transition: border-color .15s, background .15s;
}
.hd-opt:hover { border-color: var(--c-primary); }
.hd-opt b { font-size: 15px; color: var(--c-text); }
.hd-opt span { font-size: 12px; color: var(--c-hint); }
.hd-opt.active { border-color: var(--c-primary); background: rgba(110, 86, 240, .12); }
.hd-opt.active b { color: var(--c-primary); }

/* ===== 画面质感弹窗：分组下拉 + 卡片网格（2026-11-02）=====
   取代原来的窄下拉（会把风格名挤成竖排、还带内部滚动条）。
   视频 muted、不 autoplay，点 ▶ 才播；卡片不显示固定描述词。 */
.modal.style-modal { width: min(760px, 94vw); max-height: 88vh; overflow-y: auto; padding: 18px; }
.style-modal-head { position: relative; margin-bottom: 14px; }
.style-modal-x {
  position: absolute; right: 0; top: -4px; width: 28px; height: 28px; border-radius: 50%;
  background: var(--c-control); border: 1px solid var(--c-border); color: var(--c-sub);
  font-size: 18px; line-height: 1; cursor: pointer; font-family: inherit;
}
.style-group-wrap { position: relative; display: flex; justify-content: center; margin-bottom: 14px; }
.style-group-trigger {
  position: relative; z-index: 2; display: flex; align-items: center; gap: 8px;
  margin: 0 auto; width: fit-content; background: var(--c-control);
  border: 1px solid var(--c-border-d); color: var(--c-text); border-radius: 999px;
  padding: 7px 16px; font-size: 13px; font-family: inherit; cursor: pointer;
}
.style-group-trigger:hover { border-color: var(--c-primary); }
.style-group-arrow { color: var(--c-primary-2); transition: transform .18s; }
.style-group-trigger.open .style-group-arrow { transform: rotate(180deg); }
.style-group-mask { position: absolute; inset: 0; z-index: 1; }
.style-group-mask[hidden] { display: none; }
.style-group-panel {
  position: absolute; z-index: 2; top: calc(100% + 8px); left: 50%; transform: translateX(-50%);
  min-width: 180px; max-width: 300px; padding: 6px; max-height: 240px; overflow-y: auto;
  background: var(--c-panel); border: 1px solid var(--c-border-d);
  border-radius: var(--radius-s); box-shadow: var(--shadow);
}
.style-group-panel[hidden] { display: none; }
.style-group-opt {
  padding: 8px 12px; border-radius: 8px; font-size: 13px;
  color: var(--c-sub); cursor: pointer; white-space: nowrap;
}
.style-group-opt:hover { background: var(--c-primary-l); color: var(--c-text); }
.style-group-opt.active { color: var(--c-primary-2); }
.style-card-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
@media (max-width: 639px) {
  .style-card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .modal.style-modal { width: 94vw; padding: 14px; }
}
.style-card {
  position: relative; display: block; width: 100%; text-align: left; padding: 0;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-s); overflow: hidden; cursor: pointer;
  font-family: inherit; color: var(--c-text);
}
.style-card:hover { border-color: var(--c-border-d); }
.style-card.active { border: 2px solid var(--c-primary); }
.style-card:focus-visible { outline: 2px solid var(--c-primary-2); outline-offset: 2px; }
.style-card-media {
  position: relative; width: 100%; aspect-ratio: 16 / 10;
  background: #0C0C12; overflow: hidden;
}
.style-card-video, .style-card-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.style-card-empty { width: 100%; height: 100%; background: #101017; position: relative; }
.style-card-empty::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 22px; height: 22px;
  margin: -11px 0 0 -11px; border: 1px dashed #3A3A48; border-radius: 50%;
}
.style-card-play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 38px; height: 38px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255, 255, 255, .92); display: flex; align-items: center; justify-content: center;
}
.style-card-play::before {
  content: ""; width: 0; height: 0; margin-left: 3px;
  border-left: 11px solid #14141B; border-top: 6px solid transparent; border-bottom: 6px solid transparent;
}
.style-card-play.playing { opacity: 0; }
.style-card-media:hover .style-card-play.playing { opacity: .85; }
.style-card-muted {
  position: absolute; right: 6px; bottom: 5px; font-size: 11px; color: #ECECF2;
  background: rgba(0, 0, 0, .55); padding: 1px 5px; border-radius: 4px;
}
.style-card-info { padding: 8px 9px 9px; }
.style-card-name { font-size: 13px; color: var(--c-text); line-height: 1.3; }
.style-card-tag { font-size: 11px; color: var(--c-hint); margin-top: 2px; line-height: 1.3; }
.style-card-check {
  position: absolute; top: 6px; right: 6px; width: 19px; height: 19px; border-radius: 50%;
  background: var(--c-primary); color: #fff; font-size: 12px; line-height: 19px; text-align: center;
}
.style-modal-foot { text-align: center; color: var(--c-hint); font-size: 11.5px; margin-top: 14px; }

/* ===== 响应式：平板 / 手机 ===== */
@media (max-width: 1023px) {
  .side { display: none; }
  .main-wrap { margin-left: 0; }
  .topbar {
    display: flex; align-items: center; gap: 10px; padding: 12px 16px;
    background: rgba(11, 11, 15, 0.9); backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--c-border); position: sticky; top: 0; z-index: 20;
  }
  .topbar .monogram { width: 30px; height: 30px; border-radius: 9px; font-size: 12px; }
  .topbar .brand-logo { font-size: 17px; }
  .view { padding: 20px; }
}
@media (max-width: 639px) {
  .view { padding: 14px 14px 84px; }
  .hero-title { font-size: 24px; }
  .card { padding: 18px; }
  .faq-card { padding: 4px 18px; }
  .faq-item { padding: 14px 0; }
  .faq-q { font-size: 14.5px; }
  /* ⚠️ 2026-10-31：手机上「✨ AI 优化 · 5 积分」文字最长，跟「＋参考 / ＋音频」
     挤不进同一行 → flex-wrap 把它换到第二行，三个按钮就不在同一水平线了
     （用户截图）。处理：整排不换行 + AI 优化按钮单独再缩一档（字号/padding）。 */
  .composer-actions { flex-wrap: nowrap; gap: 6px; }
  .composer-actions .at-btn.ai-btn {
    height: 26px; padding: 0 7px; font-size: 11px; gap: 3px;
    overflow: hidden; text-overflow: ellipsis;
  }
  /* ⚠️ 2026-10-31：手机端占位文案两行 + 已输入内容全挤在 132px 里，视觉很乱
     （用户截图）。两件事一起做：输入框加高 + 占位文案字号降一档。 */
  .composer-box .prompt-editor {
    min-height: 168px; padding: 12px 12px 56px; font-size: 14px;
  }
  .composer-box .prompt-editor:empty::before { font-size: 13px; line-height: 1.75; }
  /* 详情页：2026-10-31 起本身就是纵向排版（视频居中 → 参数卡片），
     窄屏只需把视频上限放开、高度别顶满屏 —— 不再需要 .detail-head 那套竖排覆盖。 */
  .detail-video { max-width: 100%; max-height: 56vh; }
  .tabbar {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 25;
    background: rgba(11, 11, 15, 0.92); backdrop-filter: blur(10px);
    border-top: 1px solid var(--c-border); padding: 6px 0 calc(6px + env(safe-area-inset-bottom));
  }
  .tab-link {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 52px; color: var(--c-hint); font-size: 11px;
  }
  .tab-link .tab-ic { font-size: 17px; line-height: 1; }
  .tab-link.active { color: var(--c-primary-2); }
  /* 导演台副标题：手机底栏（5 项各 75px，字号再收一档） */
  .tab-sub { font-size: 9px; line-height: 1.15; color: var(--c-hint); white-space: nowrap; }
  .tab-link.active .tab-sub { color: var(--c-primary-2); }
}

/* ===== 会员 / 积分 / 充值 ===== */
.ub-points {
  font-size: 12px; color: var(--c-primary-2); background: var(--c-primary-l);
  padding: 2px 8px; border-radius: 999px; white-space: nowrap;
}
.cost-preview {
  margin-top: 10px; font-size: 13px; color: var(--c-sub); text-align: center;
}
.cost-preview.cost-warn { color: var(--c-danger); font-weight: 600; }

/* ⚠️ 2026-10-31：这两个页面原来写死 720px 居中窄条，宽屏上右侧一大片空着，
   跟已经铺开的生成页完全不是一个观感 → 改成铺满容器 + 内部自适应分栏。 */
.member-page, .recharge-page { width: 100%; padding: 8px 4px 32px; }
/* 会员中心：左列「积分卡」固定宽，右列「账号安全 + 积分明细」自适应吃掉剩余宽度。
   窄屏（<900px）自动塌成单列，不需要额外的移动端分支。 */
/* ⭐ 2026-11-04 修「手机端会员页整页向右拉伸」：
   grid item 默认 min-width:auto，会被绑定表单里几个 min-width:140px 的 input
   顶到比视口还宽；以前只在 ≥900px 给 .member-col-right 设了 min-width:0，
   窄屏没设 → 所有卡片跟着一起溢出。这里窄屏也强制能收缩。 */
.member-grid {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 18px; align-items: start; width: 100%; max-width: 100%;
}
.member-col-left, .member-col-right { min-width: 0; max-width: 100%; }
.member-page .card { max-width: 100%; box-sizing: border-box; }
@media (min-width: 900px) {
  .member-grid { grid-template-columns: 320px minmax(0, 1fr); }
  .member-page .bind-card, .member-page .ledger { min-width: 0; }
  .member-col-right { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
}
.section-title { font-size: 20px; font-weight: 700; margin: 4px 0 16px; }
.section-subtitle { font-size: 14px; font-weight: 600; color: var(--c-sub); }
.section-hint { font-size: 13px; color: var(--c-hint); margin: -8px 0 16px; line-height: 1.6; }

.points-card { padding: 22px; text-align: center; margin-bottom: 18px; }
.pc-label { font-size: 13px; color: var(--c-sub); }
.pc-value { font-size: 44px; font-weight: 800; color: var(--c-primary-2); line-height: 1.2; margin: 6px 0; }
.pc-sub { font-size: 12px; color: var(--c-hint); margin-bottom: 14px; }

.ledger-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.ledger-filters { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  font-size: 12px; color: var(--c-sub); background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: 999px; padding: 4px 12px; cursor: pointer;
}
.chip.active { color: #fff; background: var(--c-primary); border-color: var(--c-primary); }

.ledger-list, .order-list { list-style: none; margin: 0; padding: 0; }
.ledger-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 4px; min-height: 56px; border-bottom: 1px solid var(--c-border);
  cursor: pointer;
}
.ledger-row:focus-visible { outline: 2px solid var(--c-primary); outline-offset: -2px; }
.row-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.row-type { font-weight: 600; display: flex; align-items: center; gap: 6px; }
.row-ref, .row-time { font-size: 12px; color: var(--c-hint); }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot-in { background: #1AAD19; } .dot-out { background: var(--c-danger); }
.row-amount { font-size: 16px; font-weight: 700; white-space: nowrap; }
.amount-in { color: #1AAD19; } .amount-out { color: var(--c-danger); } .amount-gray { color: var(--c-sub); }
.ledger-empty, .order-empty { color: var(--c-hint); font-size: 13px; padding: 18px 4px; text-align: center; }

/* 档位卡片：容器变宽后 180px 会排出 7 列又碎又挤 → 抬到 230px */
.pkg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; margin: 8px 0 26px; }
.pkg-card { padding: 18px; text-align: center; display: flex; flex-direction: column; gap: 6px; align-items: center; }
.pkg-name { font-weight: 700; font-size: 15px; }
.pkg-price { font-size: 26px; font-weight: 800; color: var(--c-primary-2); }
.pkg-points { font-size: 13px; color: var(--c-sub); }
.pkg-bonus { font-size: 12px; color: #1AAD19; }
.pkg-buy { margin-top: 8px; width: 100%; }
.recharge-history { margin-top: 8px; }
.order-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 4px; border-bottom: 1px solid var(--c-border); font-size: 13px; }
.order-pkg { color: var(--c-text); font-weight: 600; }
.order-amt { color: var(--c-sub); }
.order-status { font-size: 12px; padding: 2px 8px; border-radius: 999px; }
.order-status.paid { color: #1AAD19; background: rgba(26,173,25,0.14); }
.order-status.created { color: var(--c-hint); background: var(--c-card); }
/* 订单行里的「查单入账」：紧凑小按钮。
   ⚠️ .btn-ghost 自带 width:100%（给表单整行按钮用的），在 flex 行里会被拉满整行，
   这里必须显式收成 fit-content。 */
.order-sync {
  flex: 0 0 auto; width: fit-content; margin-top: 0;
  padding: 3px 10px; font-size: 12px; line-height: 1.4;
  white-space: nowrap;
}
.order-sync:hover { border-color: var(--c-primary); color: var(--c-primary); }

/* ---------- 登录 / 注册（多方式） ---------- */
.hidden { display: none !important; }

.auth-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 14px; }
.auth-tabs .chip { font-size: 13px; padding: 6px 14px; }
.auth-pane { display: flex; flex-direction: column; }
.auth-pane .primary-btn { margin-top: 10px; }
/* ⚠️ .primary-btn / .btn-ghost 全局都是 width:100%（原用于整行按钮），
   放进 flex 行内必须显式改回 width:auto，否则会把兄弟元素顶出容器。 */
.otp-row { display: flex; gap: 8px; align-items: center; }
.otp-row input { flex: 1 1 0; width: auto; min-width: 0; margin: 10px 0; }
.otp-row .btn-ghost {
  flex: 0 0 auto; width: auto; margin-top: 0;
  white-space: nowrap; padding: 12px 14px;
}
/* 两个按钮并排（登录 / 注册） */
.btn-row { display: flex; gap: 8px; align-items: stretch; margin-top: 10px; }
.btn-row .primary-btn, .btn-row .btn-ghost {
  flex: 1 1 0; width: auto; margin-top: 0;
  white-space: nowrap; padding: 12px 10px; font-size: 15px;
}

/* ---------- 账号与安全（绑定手机/邮箱/密码） ---------- */
.bind-card { margin-bottom: 20px; }
.bind-card .section-subtitle { margin-bottom: 12px; }
.bind-list {
  list-style: none; margin: 0 0 16px; padding: 0;
  border: 1px solid var(--c-border); border-radius: var(--radius-s); overflow: hidden;
}
.bind-item {
  display: flex; justify-content: space-between; align-items: center;
  padding: 11px 14px; font-size: 14px;
  border-bottom: 1px solid var(--c-border);
}
.bind-item:last-child { border-bottom: none; }
.bind-k { color: var(--c-hint); }
.bind-v { font-weight: 500; flex: 1; text-align: right; }
.bind-v.ok { color: #1AAD19; }
.bind-v.off { color: var(--c-hint); }
/* 区域2：注册渠道右侧的「修改」入口 */
.bind-edit {
  margin-left: 10px; padding: 3px 10px; font-size: 12px;
  color: var(--c-primary); background: transparent;
  border: 1px solid var(--c-border-d); border-radius: 999px; cursor: pointer;
}
.bind-edit:hover { background: var(--c-primary-l); }
/* 区域1：注册渠道默认锁定时整行灰度（不可编辑，需先点上方「修改」） */
.bind-row.row-locked { opacity: 0.45; }
.bind-row.row-locked input,
.bind-row.row-locked button { pointer-events: none; }
.bind-forms { display: flex; flex-direction: column; gap: 10px; }
.bind-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.bind-row input {
  flex: 1 1 140px; min-width: 140px; padding: 10px 12px;
  border: 1px solid var(--c-border); border-radius: var(--radius-s);
  background: var(--c-card); color: var(--c-text); font-size: 14px; font-family: inherit;
}
.bind-row input:focus { outline: none; border-color: var(--c-primary); }
.bind-row .primary-btn, .bind-row .btn-ghost {
  flex: 0 0 auto; width: auto; margin-top: 0; white-space: nowrap;
}
.bind-card .login-tip { text-align: left; margin-top: 2px; }

/* 充值页：「我已完成支付」手动同步按钮（回调丢失兜底） */
.sync-wrap { margin-top: 12px; text-align: center; }
.sync-wrap .btn-ghost {
  /* ⚠️ .btn-ghost 全局 width:100%，这里要收成自适应宽度 */
  width: auto; display: inline-block; padding: 10px 18px;
}

/* AI 优化描述词按钮：和 @素材库 同款胶囊，只改描边区分主次 */
.ai-btn {
  background: transparent; border: 1px solid var(--c-border-d); color: var(--c-primary-2);
}
.ai-btn:hover { background: var(--c-primary-l); }
.ai-btn:disabled { opacity: .45; pointer-events: none; }

/* ===================== 导演台（2026-11-03，方案 §26）=====================
   布局顺序按用户拍板：预览窗口在最上面（21:9 全宽）→ 时间轴 → 描述词在底部。
   ======================================================================= */
.dir-wrap { display: flex; flex-direction: column; gap: 14px; }
.dir-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dir-head-acts { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* ⭐ 自适应按钮（2026-11-03）：不写死宽度，内容多宽就多宽；
   手机端（≤640px）整行铺开、三个等分，再也不会被挤成"开始/生成"两行竖排。 */
.dir-btn {
  flex: 0 0 auto; white-space: nowrap;
  min-height: 34px; padding: 8px 16px; border-radius: var(--radius-s);
  font-size: 13px; font-weight: 500; cursor: pointer; font-family: inherit;
  background: var(--c-card); border: 1px solid var(--c-border); color: var(--c-text);
  transition: background .15s, border-color .15s, color .15s;
}
.dir-btn:hover { border-color: var(--c-primary); color: var(--c-primary); }
.dir-btn.primary {
  background: var(--c-primary); border-color: var(--c-primary); color: #fff; font-weight: 600;
}
.dir-btn.primary:hover { background: var(--c-primary-d); color: #fff; }
/* 删除要有区分度：不然和「新建」长得一样，容易误点 */
.dir-btn.danger { color: var(--c-danger); border-color: rgba(255, 90, 90, .38); }
.dir-btn.danger:hover { background: rgba(255, 90, 90, .12); border-color: var(--c-danger); color: var(--c-danger); }
.dir-btn.dl { text-decoration: none; display: inline-flex; align-items: center; justify-content: center; }
.dir-btn:disabled { opacity: .45; pointer-events: none; }

/* 按钮行 / 居中小字（描述词面板：小字不再和按钮并排） */
.dir-btn-row { display: flex; justify-content: center; margin-top: 12px; }
/* ⚠️ 按钮文案带积分后会变长（§36）→ 允许换行居中，别被 max-width 裁掉 */
.dir-btn-row .dir-btn { min-width: 168px; max-width: 100%; white-space: normal; text-align: center; }
.dir-hint {
  margin-top: 8px; text-align: center; color: var(--c-hint);
  font-size: 12px; line-height: 1.5;
}

/* 公用参数：自适应网格，电脑端一行铺开、手机端两列 —— 高度压到最低 */
.dir-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
}
.dir-grid label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 11.5px; color: var(--c-hint); min-width: 0;
}
.dir-sel, .dir-inp {
  width: 100%; min-width: 0; height: 32px; padding: 0 8px; border-radius: var(--radius-s);
  background: var(--c-card); border: 1px solid var(--c-border); color: var(--c-text); font-size: 13px;
}
/* 风格触发器：和公用参数其他控件同高，点它开风格库大弹窗 */
.dir-style-trigger {
  width: 100%; height: 32px; padding: 0 8px; border-radius: var(--radius-s);
  background: var(--c-card); border: 1px solid var(--c-border); color: var(--c-text);
  font-size: 13px; font-family: inherit; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
}
.dir-style-trigger:hover { border-color: var(--c-primary); }
.dir-style-trigger .pv {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dir-style-trigger .arrow { flex: 0 0 auto; color: var(--c-hint); font-size: 11px; }
.dir-style-trigger.on { border-color: var(--c-primary); color: var(--c-primary); }

/* 参考素材入口：嵌在输入框左下角，和首页 composer 同一套（§34） */
.dir-composer { position: relative; display: flex; flex-direction: column; gap: 10px; }
/* ⭐ 2026-11-04：按钮不再绝对定位压在 textarea 上（手机端会和描述词重叠），
   改成输入框下方独立一行；textarea 不用再为它留 padding-bottom。 */
.dir-composer .composer-actions {
  position: static; left: auto; bottom: auto;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0;
}
.dir-refs-hint { color: var(--c-hint); font-size: 11.5px; line-height: 1.4; margin-top: 8px; }
/* 没传参考素材时缩略图容器是空的，别白留 12px */
.dir-panel .thumbs:empty { margin-top: 0; }
.dir-pick {
  max-width: 240px; height: 34px; padding: 0 8px; border-radius: var(--radius-s);
  background: var(--c-card); border: 1px solid var(--c-border); color: var(--c-text); font-size: 13px;
}

/* 预览窗口：21:9 全宽。21/9 ≈ 2.333 */
.dir-stage {
  position: relative; width: 100%; aspect-ratio: 21 / 9;
  background: #000; border: 1px solid var(--c-border); border-radius: var(--radius);
  overflow: hidden;
}
.dir-stage video { width: 100%; height: 100%; object-fit: contain; display: block; }
.dir-stage-ph {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--c-hint); font-size: 13px; pointer-events: none;
}
@media (max-width: 640px) { .dir-stage { aspect-ratio: 16 / 9; } }

.dir-prog {
  display: flex; flex-wrap: wrap; gap: 4px 14px;
  color: var(--c-hint); font-size: 12.5px;
}

/* 合成成片进度（§30）：重编码 60 段约 10 分钟，必须给反馈 */
.dir-synth {
  flex: 0 0 100%; margin-bottom: 4px; padding: 10px 12px;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-s);
}
.dir-synth-row { display: flex; align-items: baseline; gap: 10px; }
.dir-synth-t { color: var(--c-text); font-size: 13px; font-weight: 600; }
.dir-synth-p { color: var(--c-primary); font-size: 13px; font-weight: 700; }
.dir-synth-e { color: var(--c-hint); font-size: 12px; }
.dir-synth-bar {
  margin: 8px 0 6px; height: 5px; border-radius: 3px;
  background: var(--c-border); overflow: hidden;
}
.dir-synth-bar > i {
  display: block; height: 100%; background: var(--c-primary);
  transition: width .4s ease;
}
.dir-synth-sub { color: var(--c-hint); font-size: 11.5px; line-height: 1.5; }

/* 横条时间轴：横向滚动，每段一块 */
.dir-timeline {
  display: flex; gap: 8px; overflow-x: auto; padding: 4px 2px 8px;
  scrollbar-width: thin;
}
.dir-seg {
  flex: 0 0 auto; width: 132px; padding: 8px 10px; cursor: pointer;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-left-width: 3px; border-radius: var(--radius-s);
  transition: background .15s, transform .1s;
}
.dir-seg:hover { background: var(--c-control); }
.dir-seg:active { transform: scale(.98); }
.dir-seg-top { display: flex; align-items: baseline; justify-content: space-between; }
.dir-seg-no { font-size: 14px; font-weight: 600; color: var(--c-text); }
.dir-seg-dur { font-size: 11px; color: var(--c-hint); }
.dir-seg-st { font-size: 11.5px; margin-top: 2px; }
.dir-seg-p {
  margin-top: 4px; font-size: 11.5px; color: var(--c-sub); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.dir-panel { padding: 14px 16px; }
.dir-panel-title { font-size: 13.5px; font-weight: 600; margin-bottom: 8px; }
/* 公用参数面板：贴紧一点，别占太高 */
.dir-panel-params { padding: 12px 16px; }
.dir-panel-params .dir-panel-title { margin-bottom: 10px; }
.dir-panel-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 10px; gap: 10px; }
.dir-ta {
  width: 100%; background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-s); color: var(--c-text); font-size: 13.5px;
  padding: 10px 12px; resize: vertical; line-height: 1.6; font-family: inherit;
}
.dir-ta:focus { outline: none; border-color: var(--c-primary); }
.dir-grid { display: flex; flex-wrap: wrap; gap: 12px; }
.dir-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 11.5px; color: var(--c-hint); }
.dir-sel, .dir-inp {
  height: 32px; min-width: 120px; padding: 0 8px; border-radius: var(--radius-s);
  background: var(--c-card); border: 1px solid var(--c-border); color: var(--c-text); font-size: 13px;
}
.dir-inp { min-width: 88px; }
.dir-banner {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; border-radius: var(--radius-s); font-size: 13px;
  background: rgba(255, 90, 90, .10); border: 1px solid rgba(255, 90, 90, .35); color: var(--c-text);
}
.dir-final { display: flex; gap: 14px; }
.dir-empty { padding: 48px 24px; text-align: center; }
.dir-empty-title { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
.dir-empty .modal-actions { justify-content: center; margin-top: 18px; }
.dir-modal { min-width: 320px; max-width: 520px; }
.dir-modal .dir-ta { margin-top: 10px; }

/* ⭐⭐ 手机端导演台（§33）
   ⚠️⚠️ 这个 @media **必须放在导演台所有样式之后**：媒体查询不增加优先级，
   写在前面的话会被后面同优先级的 .dir-grid 规则覆盖（之前就踩过，
   手机端一直按桌面栅格排，看着特别占地方）。 */
@media (max-width: 640px) {
  /* 头部按钮独占一行：按 min-width 自然换行，不再挤成一排糊在一起 */
  .dir-head-acts { margin-left: 0; width: 100%; }
  .dir-head-acts .dir-btn { flex: 1 1 84px; min-width: 0; padding: 9px 6px; }
  /* ⭐ 手机端按钮调序（用户要求）：删除提到最前，开始生成 / 终止放最后
     —— 主操作独占一行铺满更好点，删除不再孤零零占一整行。 */
  .dir-head-acts .dir-btn-del { order: 1; }
  .dir-head-acts .dir-btn-dup { order: 2; }
  .dir-head-acts .dir-btn-new { order: 3; }
  .dir-head-acts .dir-btn-dl { order: 4; }
  .dir-head-acts .dir-btn-start { order: 5; }

  /* 输入框初始高度太低（rows=3 在手机上只有 ~80px），加高到能舒服写两三段话 */
  .dir-ta { min-height: 148px; }
  .dir-composer .composer-actions { gap: 6px; flex-wrap: nowrap; }

  /* 公用参数：改成「label 在左、控件在右」的紧凑流式排布 ——
     每个字段只占内容宽度，一行能塞 2~3 个，比栅格（每个都撑满半行）省一半高度。 */
  .dir-grid { display: flex; flex-wrap: wrap; gap: 8px 12px; }
  .dir-grid label {
    flex: 0 0 auto; flex-direction: row; align-items: center; gap: 6px; font-size: 12px;
  }
  .dir-grid .dir-sel, .dir-grid .dir-inp, .dir-grid .dir-style-trigger {
    width: auto; min-width: 96px;
  }
  /* 段数 / 单段秒数只有两三个字符，给窄一点。
     ⚠️ 不用 :has() —— 部分手机浏览器 / 微信 webview 还不支持，显式加 class 更稳。 */
  .dir-inp-sm { min-width: 58px; }

  /* 描述词面板底部一行两个按钮（§36 AI 优化 / §38 查看分镜）：
     各占一半并排，别各占一行把面板撑高 */
  .dir-btn-row { gap: 8px; }
  .dir-btn-row .dir-btn { flex: 1 1 0; width: auto; min-width: 0; }
}

/* ⭐ 分镜模式切换（§39）：轨道**正上方**的一排 chip。
   ⚠️ 放在导演台 @media **之后** —— 媒体查询不增加优先级，写前面会被覆盖。 */
.dir-mode { display: flex; align-items: center; gap: 8px; margin: 2px 0 6px; flex-wrap: wrap; }
.dir-mode-chip {
  padding: 5px 12px; font-size: 12.5px; font-family: inherit; cursor: pointer;
  color: var(--c-sub); background: var(--c-card);
  border: 1px solid var(--c-border); border-radius: 999px;
  transition: background .15s, color .15s, border-color .15s;
}
.dir-mode-chip:hover { color: var(--c-text); border-color: var(--c-primary); }
.dir-mode-chip.on {
  color: #fff; background: var(--c-primary); border-color: var(--c-primary); font-weight: 600;
}
/* 已有片段生成后禁改（换模式会让前后段衔接方式不一致）→ 物理拦截 + 说清原因 */
.dir-mode-chip.locked { opacity: .42; cursor: not-allowed; }
.dir-mode-chip.locked:hover { color: var(--c-sub); border-color: var(--c-border); }
.dir-mode-hint { font-size: 11.5px; color: var(--c-hint); line-height: 1.5; }

/* ⭐ 预览窗口中间的「正在生成 / 正在合成」卡片（2026-11-03 用户反馈：原来那行
   13px 灰字太不显眼，跑十几分钟没人知道在干嘛）。
   ⚠️ 放在导演台 @media **之后** —— 媒体查询不增加优先级，写前面会被覆盖。 */
.dir-stage-busy { background: rgba(0, 0, 0, .35); }
.dir-busy-box {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px 26px; border-radius: 14px;
  background: rgba(0, 0, 0, .62); border: 1px solid rgba(255, 255, 255, .16);
}
.dir-busy-t {
  font-size: 17px; font-weight: 600; color: #fff; line-height: 1.35; text-align: center;
}
.dir-busy-s { font-size: 12px; color: rgba(255, 255, 255, .6); text-align: center; }
.dir-spin {
  width: 26px; height: 26px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, .2); border-top-color: var(--c-primary);
  animation: dir-spin .9s linear infinite;
}
@keyframes dir-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .dir-spin { animation-duration: 2.4s; } }
@media (max-width: 640px) {
  .dir-busy-box { padding: 12px 16px; }
  .dir-busy-t { font-size: 15px; }
}

/* ⭐ 生成中锁灰（2026-11-03）：物理拦截 + 一眼看得出不可改 */
.dir-lock-tag {
  margin-left: 8px; padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 400; color: var(--c-warning, #d9880f);
  background: rgba(217, 136, 15, .12); border: 1px solid rgba(217, 136, 15, .3);
}
.dir-locked .dir-sel:disabled, .dir-locked .dir-inp:disabled {
  opacity: .5; cursor: not-allowed;
}
.dir-locked .dir-style-trigger:disabled { opacity: .5; pointer-events: none; }
.dir-locked .dir-ta[readonly] { opacity: .62; cursor: not-allowed; }
.dir-btn:disabled, .ref-add-btn:disabled {
  opacity: .45; cursor: not-allowed; pointer-events: none;
}

/* ⭐ 段弹窗：三个按钮排成一行、同款按钮（2026-11-03）
   「看这段」以前是个 14px 的 link-btn，用户根本没看见 → 换成和「保存」一样的 btn-ghost。
   ⚠️ btn-ghost / primary-btn 默认 width:100%（那是给充值那种单按钮弹窗用的），
      这里要并排 → 显式改回 auto，否则会各占一整行。 */
.dir-modal .modal-actions {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; margin-top: 16px;
}
.dir-modal .modal-actions > * {
  margin: 0; margin-left: 0; width: auto; min-width: 96px;
  padding: 9px 16px; text-align: center;
}
a.btn-ghost { display: inline-block; text-decoration: none; }
.btn-ghost:disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }
/* ⭐ 只读的描述词要看得出来是灰的（原来只在 .dir-locked 里生效，弹窗里的没变灰） */
.dir-ta[readonly] { opacity: .6; cursor: not-allowed; }
.dir-seg-lock { color: var(--c-warning, #d9880f); }

/* 「查看分镜」弹窗里的分镜原文（§38）：只读，滚动区限高，别把弹窗顶出屏。
   ⚠️ 放在导演台 @media **之后**：媒体查询不增加优先级，写在里面虽然也生效，
      但这套样式是电脑端手机端通用的，放外面更好找。 */
.dir-sb {
  margin-top: 10px; max-height: 52vh; overflow: auto;
  background: var(--c-card); border: 1px solid var(--c-border);
  border-radius: var(--radius-s); padding: 12px 14px;
}
.dir-sb .sb-h {
  font-size: 13px; font-weight: 700; color: var(--c-primary);
  margin: 10px 0 4px;
}
.dir-sb .sb-h:first-child { margin-top: 0; }
.dir-sb .sb-p {
  font-size: 12.5px; line-height: 1.65; color: var(--c-text);
  margin: 0 0 8px;
}

/* ---------------------------------------------------------------------------
   手机端「普通任务」参数胶囊：等宽自适应网格（2026-11-03 §37）
   以前是 flex-wrap 流式 —— 每个胶囊按内容宽度排，最后一行常常只剩 1 个小胶囊、
   右边一大片空白（用户原话"排序太难看了"）。
   改 `repeat(auto-fit, minmax(96px, 1fr))`：**列数按屏宽自适应**（360px 屏 3 列、
   更窄 2 列），且 `1fr` 会把每一行的格子**拉满整行**，每行都齐整。
   ⚠️ 必须放在 .composer .ctrl-bar 那堆规则**之后** —— 媒体查询不增加优先级。
--------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .composer .ctrl-bar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: 6px;
  }
  .composer .ctrl-bar .picker { flex: none; width: 100%; min-width: 0; }
  .composer .ctrl-bar .picker-trigger {
    width: 100%; min-height: 30px;
    justify-content: space-between;   /* 文字靠左、▾ 靠右，格子再宽也不空 */
    padding: 4px 9px;
  }
  .composer .ctrl-bar .picker-trigger .pv {
    max-width: none; flex: 1 1 auto; text-align: left;
  }
  /* 副控件条（风格 / 闪电…）：同样拉成网格，两个就各占一半 */
  .composer .ctrl-bar-sub {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 6px;
  }
  .composer .ctrl-bar-sub .picker { flex: none; width: 100%; min-width: 0; }
  .composer .ctrl-bar-sub .picker-trigger { width: 100%; justify-content: space-between; }
}

/* ---------------------------------------------------------------------------
   段弹窗里的「本段成片」播放器（2026-11-03 用户要求）
   位置：描述词框**正上方** —— 点开片段先看到片子，再往下读/改描述词。
   约束：弹窗高度有限（手机上尤其），用 max-height 40vh + 黑底留边，
        不设 height:100% 免得竖屏被拉成一长条。
--------------------------------------------------------------------------- */
/* ⭐ 弹窗原来没有高度上限（.modal 只给了 width），塞进一个 40vh 的视频后
   在手机上会顶出屏幕且**没法滚动**（遮罩是 flex 居中、overflow 默认 visible）
   → 只给导演台段弹窗加 86vh + overflow:auto，别的弹窗不受影响。 */
.dir-modal { max-height: 86vh; overflow: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.dir-seg-video {
  display: block;
  width: 100%;
  max-height: 40vh;
  margin: 2px 0 12px;
  background: #000;
  border-radius: 8px;
  object-fit: contain;
}

/* ---------------------------------------------------------------------------
   一致性锚点卡输入区（2026-11-03，consistency-design.md §3.1）
   两个短输入框横排 —— 卡本来就只有一句话，用 textarea 太占地方，
   用户会当成"又一个要填的描述词"而直接跳过。
--------------------------------------------------------------------------- */
.dir-anchor { margin-top: 10px; }
.dir-anchor-title {
  font-size: 12px; color: var(--c-sub); margin-bottom: 6px;
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
}
.dir-anchor-hint { font-size: 11px; color: var(--c-hint); }
.dir-anchor-row { display: flex; gap: 8px; flex-wrap: wrap; }
.dir-anchor-row label {
  flex: 1 1 160px; min-width: 0;
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--c-sub);
}
.dir-anchor-inp { flex: 1 1 auto; min-width: 0; }
.dir-anchor-inp[readonly] { opacity: .6; cursor: default; }
/* ---------------------------------------------------------------------------
   手机端「段详情」弹窗收窄（2026-11-03 用户反馈"手机端的片段详情都错位了"）

   ⛔ 根因：弹窗是两层 —— 外壳 .modal（width:420px / max-width:90% / padding:20px）
       里面再套一层 .dir-modal（min-width:320px / max-width:520px）。
       在 360dp 的手机上：外壳 = 90% × 360 = 324px，扣掉左右 padding 各 20
       → 内容区只剩 **284px**，而里层硬要 320px → **右边 36px 直接顶到屏幕外**，
       于是「重跑这一段」被裁掉、按钮行整体右移错位。
       （min-width 是硬下限，flex 压不下去，靠里的元素只能溢出。）

   修法（两步）：
     ① 给外壳加 .dir-modal-box（app.js 里 dirOpenSeg 时才加，和 .style-modal 一个套路），
        手机端把外壳改成「屏宽 − 24px」+ 左右 padding 收到 12px，内容区立刻够用；
     ② .dir-modal 手机端 min-width 归 0 / width 100%，不再跟屏幕宽度较劲。
   ⚠️ 这段 @media 必须放在 .dir-modal / .dir-seg-video / .dir-modal .modal-actions
      **之后**（媒体查询不增加优先级，写前面会被同优先级规则盖掉）。
--------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .dir-modal-box {
    width: calc(100vw - 24px);
    max-width: calc(100vw - 24px);
    padding: 16px 12px;
  }
  .dir-modal {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    /* 86vh 是弹窗自己的高度上限，外壳还有上下 padding + 1px 边框，扣掉免得顶出屏 */
    max-height: calc(86vh - 40px);
  }
  /* 视频矮一点：手机上 40vh 会把描述词和按钮整块顶到折叠线以下 */
  .dir-seg-video { max-height: 30vh; margin: 2px 0 10px; }
  /* 段描述词不需要主输入框那么高（主框 .dir-ta 在手机端是 min-height:148px），
     段里常常就一两句话，撑 148px 底下就是一大片空白。 */
  .dir-modal .dir-ta { min-height: 104px; }
  /* 按钮行：不换行、不溢出，宽度不够时自己缩（min-width 从 96 降到 88） */
  .dir-modal .modal-actions { flex-wrap: nowrap; }
  .dir-modal .modal-actions > * {
    flex: 0 1 auto; min-width: 88px; padding: 10px 10px; white-space: nowrap;
  }
}

/* ---------------------------------------------------------------------------
   ⭐⭐ 弹窗期间锁背景（2026-11-03 §44，用户录屏："片段详情打开后上下滑动
        竟然是后面的页面，而且后面页面的视频一直都在第一层"）

   ① 锁滚动：**只用 overflow:hidden + overscroll-behavior:none**，滚动位置完全不动。
      ⛔ 别改成 `position:fixed + top:-scrollY` —— 手机软键盘弹出时浏览器要把
      输入框滚进可视区，fixed 的 body 不参与滚动，hit-test 会跟视觉位置错位，
      表现就是"拉到某个位置才点得中，拉一点又点不了"（§45 踩过）。
      穿透本身交给遮罩上的 touchmove 守卫（app.js modalTouchGuard）来拦。
   ② 藏背景视频：#view 里带 controls 的 <video>（导演台 #dirVideo 等）在部分
      手机浏览器是**系统原生播放层**，z-index 再高也盖不住，会一直浮在弹窗上，
      还会把触摸事件吃掉 → 弹窗期间直接 display:none，让原生 surface 消失。
      ⚠️ 用 `body.modal-open #view video` 这种后代选择器，而不是给元素加 class：
         导演台生成中会轮询重绘 #view，新造出的 video 必须自动继续被藏住。
      ⚠️ 作用范围只到 #view：弹窗里那段 .dir-seg-video 在 #modal 下，照常播放。
   ③ 手机端遮罩 z-index:100 已高于下拉面板(60)/tabbar(25)/侧栏(30)，此处不再重复。
--------------------------------------------------------------------------- */
body.modal-open { overflow: hidden; overscroll-behavior: none; }
body.modal-open #view video { display: none !important; }

/* ⭐ 手机端会员页：所有 flex 子项都要能收缩，否则长内容会把整页向右拉伸 */
.member-page { max-width: 100%; box-sizing: border-box; }
.member-page .profile-card { max-width: 100%; box-sizing: border-box; }
.member-page .bind-row input { min-width: 0; flex: 1 1 100px; box-sizing: border-box; }
.member-page .ledger-row, .member-page .row-main { min-width: 0; max-width: 100%; }
.profile-modify { width: auto; margin-top: 10px; }
