/* ============================================
   理图 · 设计系统 v2
   浅色玻璃拟态 · 呼吸感 · 卡片错落有层次
   ============================================ */

:root {
  --bg: #eceef6;           /* 极浅冷白紫底 */
  --bg-2: #f3f4fa;
  --glass: rgba(255,255,255,.62);      /* 玻璃卡 */
  --glass-strong: rgba(255,255,255,.86);
  --glass-line: rgba(255,255,255,.75); /* 玻璃高光边 */

  --ink: #2b2e3d;          /* 主文字(近黑不纯黑) */
  --text: #414459;
  --text-dim: #8b8fa6;
  --text-faint: #a9adc2;

  --accent: #6f66e6;       /* 克制雾紫靛 */
  --accent-2: #8a80f0;
  --accent-soft: #eeecfd;  /* 极浅强调底 */
  --accent-ink: #4a42b8;   /* 深紫文字 */

  --line: rgba(110,100,200,.14);
  --shadow-sm: 0 6px 20px -8px rgba(90,84,170,.22);
  --shadow: 0 24px 60px -24px rgba(78,72,150,.32);
  --shadow-lg: 0 40px 90px -30px rgba(70,64,140,.36);
  --radius: 18px;
  --font: "Microsoft YaHei", "微软雅黑", -apple-system, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* ★必须是 min-height 不能是 height(07-27 修)。
   写死 height:100% 时 body 只有一屏高(实测 709px),而首页内容有 2448px。
   顶栏是 position:sticky —— 它只能在【自己的包含块】范围内吸附,包含块就是 body,
   所以滚过第一屏后顶栏就被带走了,导航跟不到底。
   改 min-height 后 body 跟着内容长,吸附范围才是整页。 */
html, body { min-height: 100%; }

body {
  font-family: var(--font);
  color: var(--text);
  background: var(--bg);
  /* 呼吸感:柔光斑 + 极淡网格,浅色不压抑 */
  background-image:
    radial-gradient(900px 620px at 84% -6%, rgba(138,128,240,.16), transparent 62%),
    radial-gradient(760px 540px at 6% 8%, rgba(120,170,240,.14), transparent 58%),
    linear-gradient(180deg, #f4f5fb 0%, var(--bg) 60%);
  background-attachment: fixed;
  min-height: 100vh;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* 细网格纹理层 */
body::before {
  content: "";
  position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background-image:
    linear-gradient(rgba(120,110,200,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(120,110,200,.05) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(ellipse 80% 70% at 50% 30%, #000 40%, transparent 100%);
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 30%, #000 40%, transparent 100%);
}

/* ---------- 顶栏 ---------- */
.topbar {
  /* ★top 不写死 0(08-04 修)。到期横幅也是 sticky top:0 而且 z-index 更高,
     两个都贴 0 的话滚下去横幅会把顶栏整条盖住 —— 实测重叠 57px,
     导航直接点不到(elementFromPoint 取到的是横幅)。
     所以顶栏往下让出一个横幅的高度,由 expire_banner.js 量完写进 --eb-h。
     没有横幅时变量不存在,兜底 0px —— 也就是说这行对没横幅的页面毫无影响。 */
  position: sticky; top: var(--eb-h, 0px); z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 48px;
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  background: rgba(246,247,252,.72);
  border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 12px; }
/* ★07-28 横版字标用【雪碧图 + JS 逐帧】(理图logo短.mp4 抽 21 帧纵向拼)。
   字标【自带"理图"两个字和吉祥物】,所以 .name 必须隐藏,否则字重复出现两遍。
   宽高比 3.40:1,38px 高对应 129px 宽 —— 写死 width 不靠自适应,
   免得图没加载出来时 flex 把右边的 .tag 拽过来跳一下版。

   为什么从动画 WebP 换成雪碧图:用户要"hover 停在小人正面朝前那帧,
   移开再把后半段播完"。动画图的循环次数烧在文件里,CSS 没有任何属性能
   定位帧/暂停/从中间续播 —— 只能改成雪碧图,由 logo_anim.js 挪
   background-position-y。默认停在末帧(100%)= logo 定帧。
   size 100% 2100% 是 21 帧纵向拼的结果,改帧数要同步这里和 JS 里的 SPRITE。 */
.brand .logo {
  width: 129px; height: 38px;
  background: url("/static/img/wordmark_sprite.webp") 0 100%/100% 2100% no-repeat;
  font-size: 0;   /* 兜底:万一某个页面漏删了字,也不会露出来 */
  flex: 0 0 auto;
}
.brand .name { display: none; }
/* .name 隐了之后 .tag 是那个 div 里唯一剩下的东西,原来的 margin-left 是
   用来跟"理图"两个字拉开的,现在没字了要去掉,否则 tag 离字标偏远。 */
.brand .tag { font-size: 12px; color: var(--text-faint); margin-left: 0; }
/* 系统里开了"减少动态效果"的用户(前庭功能敏感、易眩晕)直接给静态末帧。
   无障碍要求,不是可选项。三个用到字标的 CSS 都要有这一段。
   ★这里必须换回整图 wordmark.png 并把 size 改回 contain:雪碧图配 contain
   会把 21 帧压成一条。JS 那边也判了同一个媒体查询,不会再动 position。 */
@media (prefers-reduced-motion: reduce) {
  .brand .logo {
    background: url("/static/img/wordmark.png") left center/contain no-repeat;
  }
}

.nav-right { display: flex; align-items: center; gap: 20px; }
.nav-right a { color: var(--text-dim); text-decoration: none; font-size: 14px; transition: color .2s; }
.nav-right a:hover { color: var(--accent); }
/* 当前所在的那一项(如 /help 页的"怎么用"):加重 + 下划线,让人知道自己在哪 */
.nav-right a.cur {
  color: var(--accent-ink); font-weight: 700;
  border-bottom: 2px solid var(--accent); padding-bottom: 2px;
}
.status-dot {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-dim);
  padding: 6px 12px; border-radius: 20px;
  background: var(--glass); border: 1px solid var(--glass-line);
}
.login-btn {
  font-family: var(--font); font-size: 14px; font-weight: 700; color: #fff; cursor: pointer;
  padding: 9px 22px; border-radius: 20px; border: none;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  box-shadow: 0 10px 22px -8px rgba(111,102,230,.6);
  transition: transform .15s, box-shadow .2s;
}
.login-btn:hover { transform: translateY(-2px); box-shadow: 0 16px 30px -8px rgba(111,102,230,.7); }
.login-btn:active { transform: translateY(0); }
.status-dot i { width: 7px; height: 7px; border-radius: 50%; background: #b7bccf; }
.status-dot.on i { background: #52c17a; box-shadow: 0 0 8px rgba(82,193,122,.7); }
/* ★同一个坑第四次(07-26):类里写了 display,不补这条 hidden 就失效 */
.status-dot[hidden] { display: none; }
/* 出问题才显示,那就得是警示色 —— 灰扑扑的提示等于没提示 */
.status-dot.warn { color: #b8420f; background: rgba(223,83,39,.09); border-color: rgba(223,83,39,.28); }
.status-dot.warn i { background: #df5327; box-shadow: 0 0 8px rgba(223,83,39,.6); }

/* ---------- 主容器 ---------- */
.wrap { position: relative; z-index: 1; max-width: 1180px; margin: 0 auto; padding: 0 48px; }

.hero {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: 60px;
  padding: 78px 0 52px;
  align-items: center;
}

.hero-left .eyebrow {
  display: inline-block; font-size: 13px; color: var(--accent-ink); font-weight: 600;
  border: 1px solid var(--line); border-radius: 20px;
  padding: 6px 15px; margin-bottom: 24px;
  background: var(--glass-strong); box-shadow: var(--shadow-sm);
}
.hero-left h1 {
  font-size: 47px; line-height: 1.16; font-weight: 800;
  letter-spacing: -.5px; margin-bottom: 20px; color: var(--ink);
}
.hero-left h1 .hl { color: var(--accent); position: relative; }
.hero-left h1 .hl::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 5px; height: 11px;
  background: rgba(138,128,240,.22); z-index: -1; border-radius: 3px;
}
.hero-left .sub { font-size: 17px; color: var(--text-dim); max-width: 440px; margin-bottom: 30px; }
.hero-points { list-style: none; display: flex; flex-direction: column; gap: 14px; }
.hero-points li { display: flex; gap: 12px; align-items: center; font-size: 14.5px; color: var(--text); }
.hero-points li .ic {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  background: var(--glass-strong); box-shadow: var(--shadow-sm);
  display: grid; place-items: center; color: var(--accent); font-size: 16px;
}

/* ---------- 上传卡(玻璃,带错落装饰) ---------- */
.upload-card {
  position: relative;
  background: var(--glass-strong);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--glass-line);
  border-radius: 22px;
  box-shadow: var(--shadow-lg);
  overflow: visible;
}
/* 背后错落的两张浅卡,做呼吸层次 */
.upload-card::before,
.upload-card::after {
  content: ""; position: absolute; border-radius: 22px; z-index: -1;
  background: rgba(255,255,255,.5);
  border: 1px solid var(--glass-line);
  box-shadow: var(--shadow);
}
.upload-card::before { inset: 18px -22px -20px 20px; transform: rotate(2.5deg); opacity: .7; }
.upload-card::after  { inset: 30px -10px -34px 34px; transform: rotate(5deg); opacity: .4; }

.mode-tabs { display: flex; border-bottom: 1px solid var(--line); border-radius: 22px 22px 0 0; overflow: hidden; }
.mode-tab {
  flex: 1; padding: 17px 0; text-align: center; cursor: pointer;
  font-size: 15px; color: var(--text-dim); font-weight: 600;
  position: relative; transition: color .2s, background .2s;
}
.mode-tab .mt-sub { display: block; font-size: 11px; font-weight: 400; color: var(--text-faint); margin-top: 3px; }
.mode-tab:hover { color: var(--ink); }
.mode-tab.active { color: var(--accent); background: var(--accent-soft); }
.mode-tab.active::after {
  content: ""; position: absolute; left: 26px; right: 26px; bottom: 0; height: 2.5px;
  background: var(--accent); border-radius: 3px;
}

.upload-body { padding: 26px; }

/* ★.dropzone 那块大虚线拖拽区已删(07-27)。
   删的原因:它和下面 .ref-row 里的"加参考资料"重复 —— 两个都是选文件,
   用户分不清点哪个。现在粘贴框当主入口兼拖拽落点,传文件收进 .ref-row。
   .ref-mini 上还挂着 id="dropzone" 给 JS 用,但样式走 .ref-mini,不再有这套规则。 */

.skip-row { margin-top: 14px; text-align: center; font-size: 13px; color: var(--text-dim); }
.skip-row a { color: var(--accent); text-decoration: none; font-weight: 600; margin-left: 4px; }
.skip-row a:hover { text-decoration: underline; }

.file-list { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; }
.file-item {
  display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--text);
  background: var(--glass); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 12px;
}
.file-item .fi-ic { color: var(--accent); flex-shrink: 0; }
.file-item .fi-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-item .fi-note { flex-shrink: 0; font-size: 12px; color: var(--text-faint); }
/* 删除按钮:08-15 从 <span class="iconify"> 换成 <button>(iconify 会把占位 span
   换成 svg,监听跟着丢 —— 详见 home.js 里的注释)。button 自带边框/背景/padding,
   必须全部清掉才能长回原来那个纯图标的样子。 */
.file-item .fi-del {
  flex-shrink: 0; cursor: pointer; color: var(--text-faint);
  appearance: none; -webkit-appearance: none;
  border: 0; background: none; font: inherit; line-height: 1;
  /* 图标本身只有 13px,太小不好点。给一圈 padding 把可点区域撑到 ~29px,
     再用负 margin 抵掉,保证行高和别的行一样、图标视觉位置不变 */
  padding: 8px; margin: -8px -6px -8px 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px; transition: color .14s, background-color .14s;
}
.file-item .fi-del:hover { color: #e06a6a; background: rgba(224,106,106,0.1); }
.file-item .fi-del:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* 状态:读取中转圈 */
.file-item .fi-ic.spin { animation: fiSpin 0.9s linear infinite; }
@keyframes fiSpin { to { transform: rotate(360deg); } }
/* 状态:读取成功 */
.file-item .fi-ic[data-icon="ph:check-circle-bold"] { color: #3d9e6b; }
/* 状态:读取失败 */
.file-item.err { border-color: rgba(224,106,106,0.4); background: rgba(224,106,106,0.06); }
.file-item.err .fi-ic { color: #e06a6a; }
.file-item.err .fi-note { color: #e06a6a; }

/* ---------- 粘贴框(07-27 起是主入口,也当拖拽落点) ---------- */
.paste-wrap { margin-top: 0; }
.paste-text {
  /* 高度从 92 提到 132:它现在是卡片里第一眼看到的东西,太矮显得不是主入口 */
  width: 100%; min-height: 132px; resize: vertical; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 12px; padding: 13px 14px;
  font-family: var(--font); font-size: 13.5px; line-height: 1.7; color: var(--ink);
  background: var(--glass); transition: border-color .2s, background .2s;
}
.paste-text:focus { outline: none; border-color: var(--accent); background: var(--accent-soft); }
/* 拖着文件悬在框上:虚线提示"松手就行" */
.paste-text.drag {
  border: 1.5px dashed var(--accent); background: rgba(138,128,240,.12);
}
.paste-text::placeholder { color: var(--text-faint); }

/* 三个入口一行,窄屏换行 —— 挤在一行会把字压成两行,高度参差不齐 */
.ref-row { margin-top: 14px; display: flex; gap: 10px; flex-wrap: wrap; }
.ref-mini {
  flex: 1 1 168px; min-width: 0; border: 1px solid var(--line); border-radius: 11px;
  padding: 13px; cursor: pointer; transition: border-color .2s, background .2s;
  display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--text-dim);
  background: var(--glass);
}
.ref-mini:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.ref-mini .rm-ic { color: var(--accent); font-size: 18px; flex: 0 0 auto; }
.ref-mini > span:not(.rm-ic) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 参考图"即将上线"小徽标 */
.ref-mini .rm-soon {
  margin-left: auto; font-size: 11px; font-weight: 600;
  color: var(--accent); background: var(--accent-soft);
  padding: 2px 7px; border-radius: 6px;
}
/* 绘图版参考图提示(非按钮,真实上传在理图流程内) */
/* 纯提示文字,无边框无底,不做成按钮样(避免误以为可点) */
.ref-hint {
  flex: 1; padding: 6px 2px; display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; color: var(--text-dim); cursor: default;
}
.ref-hint .rm-ic { color: var(--accent); font-size: 16px; opacity: .8; }

/* 参考图缩略图:传了图能看见,右上角可移除 */
.ref-thumb {
  position: relative; width: 56px; height: 56px; flex: 0 0 auto;
  border-radius: 10px; overflow: hidden; border: 1px solid var(--line);
  background: #f4f4f6;
}
.ref-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ref-thumb-x {
  position: absolute; top: 2px; right: 2px; width: 18px; height: 18px;
  border: none; border-radius: 50%; cursor: pointer; padding: 0;
  background: rgba(0,0,0,.55); color: #fff; font-size: 11px;
  display: flex; align-items: center; justify-content: center; line-height: 1;
}
.ref-thumb-x:hover { background: #df5327; }

.go-btn {
  width: 100%; margin-top: 22px; padding: 16px; border: none; cursor: pointer;
  border-radius: 13px; font-family: var(--font); font-size: 16px; font-weight: 700;
  color: #fff; background: linear-gradient(135deg, var(--accent-2), var(--accent));
  box-shadow: 0 14px 30px -10px rgba(111,102,230,.6);
  transition: transform .15s, box-shadow .2s;
}
.go-btn:hover { transform: translateY(-2px); box-shadow: 0 20px 40px -10px rgba(111,102,230,.7); }
.go-btn:active { transform: translateY(0); }
.go-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }

/* ---------- 案例画廊 ---------- */
.section-head { display: flex; align-items: flex-end; justify-content: space-between; margin: 44px 0 22px; }
.section-head h2 { font-size: 25px; font-weight: 800; color: var(--ink); }
.section-head .sh-sub { font-size: 13px; color: var(--text-dim); margin-top: 4px; display: block; }

.shuffle-btn {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font); font-size: 14px; font-weight: 600; color: var(--accent-ink);
  padding: 9px 17px; border-radius: 20px; cursor: pointer;
  border: 1px solid var(--line); background: var(--glass-strong);
  box-shadow: var(--shadow-sm); transition: transform .15s, border-color .2s, color .2s;
}
.shuffle-btn:hover { transform: translateY(-2px); border-color: var(--accent); color: var(--accent); }
.shuffle-btn:active { transform: translateY(0) rotate(-2deg); }
.shuffle-btn .iconify { font-size: 16px; }

.gallery {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; padding-bottom: 80px;
  transition: opacity .18s ease;
}
.case {
  border-radius: 16px; overflow: hidden; cursor: pointer; position: relative;
  border: 1px solid var(--glass-line); background: var(--glass-strong);
  box-shadow: var(--shadow-sm);
  transition: transform .22s, box-shadow .22s;
}
.case:hover { transform: translateY(-5px); box-shadow: var(--shadow); }
.case img { width: 100%; height: 132px; object-fit: cover; display: block; }
.case .cap {
  padding: 12px 14px; font-size: 13.5px; font-weight: 600; color: var(--ink);
}
.case .badge {
  position: absolute; top: 10px; left: 10px; font-size: 11px; color: #fff;
  background: rgba(111,102,230,.9); backdrop-filter: blur(6px);
  border-radius: 7px; padding: 3px 9px; font-weight: 600;
}
.case .badge-type {
  position: absolute; top: 10px; right: 10px; font-size: 11px; color: var(--accent-ink);
  background: rgba(255,255,255,.88); backdrop-filter: blur(6px);
  border-radius: 7px; padding: 3px 9px; font-weight: 600;
  box-shadow: 0 2px 8px -3px rgba(78,72,150,.4);
}

/* ---- 案例选中态(07-26 加)----
   老毛病:点案例只弹个提示,画廊里看不出选了哪张,用户去补材料后只能凭记忆再找。
   选中标记做在卡上(描边 + 右下打勾),不铺色块 —— 案例卡本身就是图,盖色会看不清图。 */
.case-tick {
  position: absolute; right: 10px; bottom: 10px;
  width: 24px; height: 24px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: #fff; font-size: 13px;
  opacity: 0; transform: scale(.6); transition: opacity .16s, transform .16s;
  box-shadow: 0 4px 12px -4px rgba(111,102,230,.7);
}
.case.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent) inset, var(--shadow); }
.case.on .case-tick { opacity: 1; transform: scale(1); }

/* 上传卡里的"已选案例"条:选中后在这儿也能看见,不必翻到画廊确认 */
.case-chosen {
  margin-top: 14px; display: flex; align-items: center; gap: 11px;
  padding: 9px 11px; border-radius: 12px;
  border: 1px solid var(--accent); background: var(--accent-soft);
}
/* ★这一条必须有(07-26 修):类选择器写了 display:flex,优先级压过浏览器默认的
   `[hidden]{display:none}` —— 于是 hidden 属性彻底失效。表现是两个症状同一个根:
   ①默认就显示,而 img 没 src、名字是"—",看着像"开裂的空条";
   ②点关闭按钮把 hidden 设上了也关不掉。用户两条都报了。
   ★同一个坑第三次:.pj-lightbox、<label> 没写 display、这里。
   **凡是给带 hidden 的元素写 display,必须同时补 [hidden] 那一条。** */
.case-chosen[hidden] { display: none; }
.case-chosen img {
  width: 58px; height: 38px; object-fit: cover; border-radius: 8px;
  flex: 0 0 auto; background: #f1f1f4;
}
.case-chosen .cc-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.case-chosen .cc-txt b { font-size: 12px; color: var(--accent-ink); font-weight: 700; }
.case-chosen .cc-txt span {
  font-size: 13px; color: var(--ink); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.case-chosen .cc-x {
  flex: 0 0 auto; width: 24px; height: 24px; padding: 0; cursor: pointer;
  border: none; border-radius: 50%; background: rgba(78,72,150,.1);
  color: var(--accent-ink); font-size: 12px;
  display: flex; align-items: center; justify-content: center;
}
.case-chosen .cc-x:hover { background: #df5327; color: #fff; }

/* ---------- 响应式 ---------- */
@media (max-width: 940px) {
  .wrap { padding: 0 24px; }
  .hero { grid-template-columns: 1fr; gap: 40px; padding-top: 44px; }
  .hero-left h1 { font-size: 34px; }
  .gallery { grid-template-columns: repeat(2, 1fr); }
  .topbar { padding: 14px 24px; }
  .upload-card::before, .upload-card::after { display: none; }
}

/* ---------- 产品介绍段(07-26 加) ---------- */
.intro { text-align: center; padding: 80px 0 40px; }
.intro h2 { font-size: 28px; font-weight: 800; color: var(--ink); margin: 0 0 12px; }
.intro-sub { font-size: 15px; color: var(--text-dim); max-width: 540px; margin: 0 auto 42px; line-height: 1.7; }
.intro-features {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px;
  max-width: 820px; margin: 0 auto;
}
.intro-f {
  padding: 28px 22px; border-radius: 18px; text-align: left;
  border: 1px solid var(--glass-line); background: var(--glass-strong);
  display: flex; flex-direction: column; gap: 8px;
}
.intro-f .intro-ic { font-size: 26px; color: var(--accent); margin-bottom: 4px; }
.intro-f b { font-size: 15px; font-weight: 800; color: var(--ink); }
.intro-f span:last-child { font-size: 13.5px; color: var(--text-dim); line-height: 1.6; }

/* ---------- 价格卡(07-26 加) ---------- */
.pricing { text-align: center; padding: 50px 0 80px; }
.pricing h2 { font-size: 26px; font-weight: 800; color: var(--ink); margin: 0 0 10px; }
.pricing-sub { font-size: 14px; color: var(--text-dim); margin: 0 auto 36px; max-width: 480px; }
.pricing-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px;
  max-width: 920px; margin: 0 auto;
}
.price-card {
  position: relative; padding: 30px 22px; border-radius: 18px; text-align: left;
  border: 1px solid var(--glass-line); background: var(--glass-strong);
  display: flex; flex-direction: column; gap: 6px;
}
.price-card.hot { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent) inset, 0 12px 32px -12px rgba(111,102,230,.35); }
.pc-badge {
  position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
  padding: 3px 12px; border-radius: 20px; font-size: 11px; font-weight: 700;
  background: var(--accent); color: #fff; white-space: nowrap;
}
.pc-name { font-size: 14px; font-weight: 700; color: var(--text-dim); margin-bottom: 4px; }
.pc-price { font-size: 13px; color: var(--ink); }
.pc-price b { font-size: 28px; font-weight: 800; }
.pc-price span { color: var(--text-dim); margin-left: 4px; }
.pc-detail { font-size: 12.5px; color: var(--text-faint); margin-bottom: 10px; }
.price-card ul { list-style: none; padding: 0; margin: 0 0 16px; flex: 1; }
.price-card li {
  font-size: 13px; color: var(--text-dim); padding: 5px 0;
  padding-left: 18px; position: relative;
}
.price-card li::before {
  content: "✓"; position: absolute; left: 0; color: var(--accent); font-weight: 700; font-size: 12px;
}
.pc-btn {
  display: block; text-align: center; text-decoration: none; font-weight: 700; font-size: 14px;
  padding: 11px 0; border-radius: 10px; transition: background .16s, transform .12s;
  background: var(--accent); color: #fff;
}
.pc-btn:hover { transform: translateY(-2px); }
.pc-btn.secondary { background: var(--glass); color: var(--accent-ink); border: 1px solid var(--line); }
.pc-btn.secondary:hover { border-color: var(--accent); background: var(--accent-soft); }
.pricing-note { font-size: 13px; color: var(--text-faint); margin-top: 28px; }

@media (max-width: 940px) {
  .intro-features { grid-template-columns: 1fr; }
  .pricing-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 540px) {
  .pricing-grid { grid-template-columns: 1fr; }
}

/* ============================================
   参数确认页
   ============================================ */
.params-wrap { position: relative; z-index: 1; max-width: 940px; margin: 0 auto; padding: 44px 48px 90px; }

.back-link {
  display: inline-flex; align-items: center; gap: 6px; font-size: 14px;
  color: var(--text-dim); text-decoration: none; margin-bottom: 26px; transition: color .2s;
}
.back-link:hover { color: var(--accent); }

.params-head { margin-bottom: 38px; }
.params-head h1 { font-size: 31px; font-weight: 800; margin-bottom: 9px; color: var(--ink); }
.params-head p { color: var(--text-dim); font-size: 15px; }
.params-head .job-chip {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 16px;
  font-size: 13px; color: var(--accent-ink); background: var(--glass-strong);
  border: 1px solid var(--line); border-radius: 11px; padding: 9px 15px; box-shadow: var(--shadow-sm);
}

.field { margin-bottom: 34px; }
.field > label.field-title {
  display: block; font-size: 15.5px; font-weight: 700; margin-bottom: 5px; color: var(--ink);
}
.field .field-hint { font-size: 12.5px; color: var(--text-dim); margin-bottom: 16px; }

.opt-grid { display: grid; gap: 14px; }
.opt-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.opt-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.opt-grid.cols-5 { grid-template-columns: repeat(5, 1fr); }

.opt-card {
  border: 1.5px solid var(--glass-line); border-radius: 14px; padding: 17px 15px;
  cursor: pointer; transition: border-color .18s, box-shadow .18s, transform .12s;
  background: var(--glass-strong); position: relative; box-shadow: var(--shadow-sm);
}
.opt-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.opt-card.sel { border-color: var(--accent); background: var(--accent-soft); }
.opt-card.sel::after {
  content: "✓"; position: absolute; top: 9px; right: 11px; color: var(--accent); font-weight: 800; font-size: 13px;
}
.opt-card .oc-ic { font-size: 23px; color: var(--accent); margin-bottom: 9px; display: block; }
.opt-card .oc-title { font-size: 14px; font-weight: 700; margin-bottom: 4px; color: var(--ink); }
.opt-card .oc-desc { font-size: 11.5px; color: var(--text-dim); line-height: 1.4; }

.page-stepper { display: flex; align-items: center; gap: 18px; }
.page-stepper button {
  width: 44px; height: 44px; border-radius: 12px; border: 1px solid var(--glass-line);
  background: var(--glass-strong); color: var(--accent); font-size: 22px; cursor: pointer;
  box-shadow: var(--shadow-sm); transition: border-color .2s, transform .12s;
}
.page-stepper button:hover { border-color: var(--accent); transform: translateY(-2px); }
.page-stepper .pg-num { font-size: 31px; font-weight: 800; min-width: 46px; text-align: center; color: var(--ink); }
.page-stepper .pg-unit { color: var(--text-dim); font-size: 14px; }

.layout-opt { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.layout-opt .shape { border: 2px solid currentColor; border-radius: 5px; opacity: .8; }
.layout-opt .shape.landscape { width: 56px; height: 34px; }
.layout-opt .shape.portrait { width: 34px; height: 56px; }

/* 配色卡:三色预览条,直接展示这套配色的主色/辅色/点缀,选前就知道出图调性 */
.color-swatch { display: flex; flex-direction: column; align-items: center; gap: 11px; padding: 14px 12px; }
.color-swatch .swatch {
  width: 100%; height: 52px; border-radius: 11px; overflow: hidden;
  display: flex; position: relative;
  box-shadow: 0 3px 10px rgba(43,46,61,.10), inset 0 0 0 1px rgba(255,255,255,.5);
}
/* 三段色块按 3:2:1 分配,主色最宽 */
.color-swatch .swatch i { display: block; height: 100%; }
.color-swatch .swatch i:nth-child(1) { flex: 3; }
.color-swatch .swatch i:nth-child(2) { flex: 2; }
.color-swatch .swatch i:nth-child(3) { flex: 1.2; }
/* 顶部玻璃高光,让色条有光泽而不是死板平涂 */
.color-swatch .swatch::before {
  content: ""; position: absolute; inset: 0 0 55% 0;
  background: linear-gradient(180deg, rgba(255,255,255,.32), rgba(255,255,255,0));
  pointer-events: none;
}
.color-swatch .cs-name { font-size: 12.5px; font-weight: 700; color: var(--ink); letter-spacing: .3px; }
/* 选中时色条放大一点点、点缀描边 */
.color-swatch.sel .swatch { transform: scale(1.03); box-shadow: 0 5px 16px rgba(111,102,230,.24), inset 0 0 0 1.5px var(--accent); }
.color-swatch .swatch { transition: transform .16s, box-shadow .16s; }

.params-actions {
  position: sticky; bottom: 0; z-index: 10;
  display: flex; justify-content: flex-end; gap: 14px;
  margin-top: 50px; padding: 20px 0 10px;
  background: linear-gradient(0deg, var(--bg) 55%, rgba(236,238,246,.85) 85%, transparent);
  backdrop-filter: blur(6px);
}
.btn-ghost {
  padding: 14px 26px; border-radius: 13px; font-family: var(--font); font-size: 15px; font-weight: 600;
  border: 1px solid var(--line); background: var(--glass-strong); color: var(--text-dim); cursor: pointer;
  transition: color .2s, border-color .2s;
}
.btn-ghost:hover { color: var(--ink); border-color: var(--accent); }
.btn-primary {
  padding: 14px 34px; border-radius: 13px; font-family: var(--font); font-size: 16px; font-weight: 700;
  border: none; cursor: pointer; color: #fff;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  box-shadow: 0 14px 30px -10px rgba(111,102,230,.6);
  transition: transform .15s;
}
.btn-primary:hover:not(:disabled) { transform: translateY(-2px); }
/* 出多张时版式没挑齐,"开始出图"要看得出点不动(07-27 加) */
.btn-primary:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; }

textarea {
  background: var(--glass-strong) !important;
  border: 1px solid var(--glass-line) !important;
  color: var(--text) !important;
  box-shadow: var(--shadow-sm);
}
textarea::placeholder { color: var(--text-faint); }

@media (max-width: 940px) {
  .params-wrap { padding: 28px 24px 70px; }
  .opt-grid.cols-4, .opt-grid.cols-5 { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- 价格区:会员卡三档(07-27 加) ---------- */
.pricing-tag {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 0 auto 18px; padding: 6px 15px; border-radius: 20px;
  font-size: 12.5px; font-weight: 700; color: #8a6415;
  background: linear-gradient(120deg, #fff5e2, #fbe6c4);
  border: 1px solid rgba(190,140,40,.26);
}
.pricing-tag .iconify { font-size: 15px; color: #c08a1e; }
/* 加量包那行的小标题:素色,别和金色抢 */
.pricing-tag.plain {
  margin-top: 42px; background: var(--glass); color: var(--text-dim);
  border-color: var(--line); font-weight: 600;
}
/* 会员三档:比加量包宽一点,视觉上是"主推" */
.pricing-grid.mem { grid-template-columns: repeat(3, 1fr); max-width: 760px; }
.price-card.m { border-color: rgba(190,140,40,.22); background: rgba(255,252,245,.9); }
.price-card.m.hot {
  border-color: #c9932a;
  box-shadow: 0 0 0 2px #c9932a inset, 0 14px 34px -14px rgba(170,120,30,.4);
}
.price-card.m.hot .pc-badge { background: linear-gradient(135deg, #c9932a, #e0b455); }
.price-card.m .pc-price b { color: #8a6415; }
.price-card.m li::before { color: #c9932a; }
.pc-btn.gold { background: linear-gradient(135deg, #c9932a, #e0b455); color: #fff; border: none; }
.pc-btn.gold.secondary {
  background: rgba(255,255,255,.8); color: #8a6415; border: 1px solid rgba(190,140,40,.3);
}
.pc-btn.gold.secondary:hover { background: #fff6e6; border-color: #c9932a; }

@media (max-width: 880px) {
  .pricing-grid.mem { grid-template-columns: 1fr; max-width: 380px; }
}


/* ============================================
   移动端基线(720px 以下)—— 全站统一,别在各页 CSS 里重复写
   ============================================
   两条硬规矩,都是实测踩出来的:
   ① 输入框字号 ≥16px。低于 16px 时 iOS Safari 会【自动放大整页】,
      放大后横向就溢出了,用户得手动缩回去才能点按钮 —— 登录页最致命。
   ② 能点的东西高度 ≥44px。这是手指的最小落点,低于这个值在公交车上
      基本点不中(苹果 HIG 给的也是 44)。
*/
@media (max-width: 720px) {
  /* 首页粘贴框:类名是 .paste-text(工作台那个叫 .up-text,两回事) */
  .paste-text { font-size: 16px; }
  input[type="text"], input[type="password"], input[type="number"],
  input[type="email"], textarea, select { font-size: 16px; }

  /* 换一批:桌面上 39px 够了,手机上差 5px 就点不准 */
  .shuffle-btn { min-height: 44px; padding-left: 16px; padding-right: 16px; }

  /* 顶栏在窄屏容易挤成两行,收一下间距 */
  .nav-right { gap: 10px; }
}


/* ============================================
   真机档(560px 以下)—— 08-03 加
   ============================================
   为什么 720 不够、必须再加一档:
   上面那些断点最小到 720px,而真机是 375(iPhone SE)~430(Pro Max)。
   一套按 720 排的版式塞进 375,实测出来的样子:

   ① 顶栏整条【竖排】。.topbar 是 flex nowrap,375px 装不下就把每个
      子项压到最小宽度 —— 中文没有空格,压窄后一个字一行:
      「申报材料 · 一键出架构图」量出来 18×246px,12 个字竖成一列;
      「看案例」16×67、「我的项目」22×90,四个导航全竖着。
      顶栏因此高 285px,吃掉首屏 43% —— 用户一进来先看见一堵竖字墙,
      真正的上传框被顶到屏幕下面。这就是"文字挤在一起 + 重要内容被挤下去"。
   ② 案例画廊两列,标题可用宽只剩 125px,13.5px 字放不下 12 个字的
      案例名(「新质生产力赋能粮食安全」),必然折成三行还压着图。

   改法:让顶栏在窄屏变成【一行只放字标和登录】,标语和导航挪走 ——
   不是缩小,是重新决定窄屏上什么该留在第一屏。
   ★整块都在媒体查询里,PC 端一个像素都不动。
*/
@media (max-width: 560px) {
  /* ---- 顶栏:压成 56px 单行 ---- */
  .topbar {
    padding: 9px 14px;
    /* 允许换行反而更糟(会变成两行 nowrap 各自竖排),明确禁掉 */
    flex-wrap: nowrap; gap: 10px;
  }
  /* 标语在窄屏藏掉:它是"这是什么产品"的补充说明,而首屏 h1 已经把这事
     说清了。留着的代价是整条顶栏竖排 —— 一句补充说明不值这个价。
     ★写 display 必须补 [hidden](本项目第十次踩) */
  .brand .tag { display: none; }
  .brand .tag[hidden] { display: none; }
  .brand { gap: 0; flex: 0 0 auto; min-width: 0; }
  /* 字标按 3.40:1 等比缩,不能只改 width 否则雪碧图会串帧 */
  .brand .logo { width: 102px; height: 30px; }

  /* 导航文字链在窄屏藏掉:四条链接横排要 166px,在 375 屏上必然竖排。
     "看案例""价格"往下滚就到,"我的项目"要登录才有意义 —— 藏掉不丢功能。
     ★但"怎么用"必须留(08-03 用户提):没注册的人进来第一个问题是
       "这东西怎么用",这个入口藏了等于让他自己猜。往下滚能看到的是
       案例和价格,都不回答"怎么用"这个问题。
     顶栏宽度账:字标 102 + 间距 10 + 怎么用 42 + 间距 8 + 登录 90
     + 左右内边距 28 = 280px,375 屏放得下,不会把顶栏顶成两行。 */
  .nav-right > a { display: none; }
  .nav-right > a[hidden] { display: none; }
  /* ★用 id 提优先级压过上面那条(0,1,1 → 0,1,1,1),
     并且必须补 [hidden](本项目第十一次踩这个坑) */
  .nav-right > a#navHelp {
    display: inline-flex; align-items: center;
    min-height: 44px; padding: 0 2px;
    font-size: 14px; font-weight: 600; color: var(--accent-ink);
    white-space: nowrap;
  }
  .nav-right > a#navHelp[hidden] { display: none; }
  .nav-right { gap: 8px; flex: 0 0 auto; }
  .status-dot { display: none; }
  .status-dot[hidden] { display: none; }
  /* 登录按钮:手指落点 ≥44px */
  .login-btn { min-height: 44px; padding: 0 18px; font-size: 15px; }
  /* ★登录后这个按钮的文字会变成用户名(08-04),长度不可控 ——
     实测 9 个汉字的用户名在 375 屏上把顶栏顶出 6px 横向溢出。
     顶栏宽度账(375屏):左右内边距 28 + 字标 102 + 间距 10
     + "怎么用" 46 + 间距 8 = 194,留给按钮 181,给 150 留出余量。
     超了就用省略号截断:顶栏认人只要认得出前几个字,不需要看全。 */
  .login-btn.logged-in {
    max-width: 150px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* ---- 首屏:把主入口提到第一屏 ---- */
  /* 实测原样:粘贴框在 601px、开始按钮在 897px,两个都要滚才看得见 ——
     用户说的"重要的内容被挤下面去了"就是这个。
     账是这么来的:顶栏 63 + 宣传区 427 = 490,上传卡只能从 574 开始。
     宣传区里那三条卖点占 118px,它们该在主入口【下面】——
     用户是来贴材料出图的,不是来读三条卖点的。

     做法:.hero-left 改 display:contents 把自己"溶掉",里面四块
     (小标签/大标题/说明/三条卖点)升级成 .hero 的直接子项,
     再用 order 把三条卖点排到上传卡后面。
     ★为什么不用改 HTML:HTML 一改,PC 端的两栏结构就得跟着重排,
       "PC 端不用动"这条就守不住了。display:contents 只在这个
       媒体查询里生效,PC 端连这行都读不到。 */
  /* ★gap 和上边距是抠出来的,别随手加回去:实测「开始理图」按钮底沿
     落在 599px,而真机可见线约 575(地址栏吃掉一截)—— 按钮露一半
     在屏幕外。从各处间距里挤,不动粘贴框高度(那是 4 行可视区,
     收了就不像主入口了)。 */
  .hero {
    display: flex; flex-direction: column; align-items: stretch;
    gap: 10px; padding: 10px 0 34px;
  }
  .hero-left { display: contents; }
  /* 12.5px 不是随手写的:这行是首屏第一句话(「教学能力 · 创新 ·
     成果奖 · 思政比赛」),告诉用户"这东西是给我用的",12px 偏虚。
     再大就装不下 —— 375 屏上 13px 会折成两行。 */
  .hero-left .eyebrow {
    order: 1; align-self: flex-start;
    font-size: 12.5px; padding: 5px 12px; margin-bottom: 0;
  }
  /* 大标题 34px 时"变成评委记得住的图。"这行 10 个字要 340px,装不下折成
     三行(实测 118px)。降到 26px 后 260px 一行放得下,两行搞定,省 58px。 */
  .hero-left h1 {
    order: 2; font-size: 26px; line-height: 1.26; margin-bottom: 0;
    letter-spacing: -.2px;
  }
  .hero-left h1 .hl::after { bottom: 3px; height: 8px; }
  .hero-left .sub {
    order: 3; font-size: 14.5px; line-height: 1.6; margin-bottom: 0; max-width: none;
  }
  .upload-card { order: 4; }
  /* 三条卖点挪到上传卡后面:看完再往下滚就是"它凭什么行" */
  .hero-points { order: 5; gap: 10px; margin-top: 4px; }
  .hero-points li { font-size: 13.5px; }
  .hero-points li .ic { width: 26px; height: 26px; font-size: 14px; border-radius: 8px; }

  /* 上传卡内边距收窄:26px 两边吃掉 52px,375 屏上是 14% 的宽度 */
  .upload-body { padding: 18px 16px; }
  /* 两个"加材料/加参考图"入口改一行一个。
     并排时每个只有 146px,而 .ref-mini 是 nowrap + 省略号 ——
     「加参考图,照着它的结构理」会被截成「加参考图,照着…」,
     用户根本不知道这个功能是干什么的。 */
  /* ★这里必须改 flex-direction,不能只写 flex:1 1 100%。
     .ref-row 是 flex-wrap:wrap,而 .ref-mini 的 flex-basis 是 168px ——
     只把 basis 改成 100% 时,父容器仍按"能塞就塞"算,实测两个还是
     并排(各 146px),字照旧被截。改成 column 才是真的一行一个。 */
  .ref-row { gap: 8px; flex-direction: column; flex-wrap: nowrap;
             margin-top: 9px; }
  .ref-mini { flex: 0 0 auto; width: 100%; padding: 12px 13px; min-height: 46px; }
  /* 按钮上边距从 22 收到 13:剩下的 9px 就是它进真机可见线的余量 */
  .go-btn { margin-top: 13px; }
  /* 粘贴框 132px 是照桌面定的(要显得像主入口)。手机上这 132px 直接
     决定"开始理图"按钮落在第一屏里还是外面 —— 实测 132 时按钮在 573px,
     正好卡在真机可见线(约 575)上,地址栏一露头就看不见了。
     收到 104px 还能显示 4 行,按钮进到线内。手指往下拉框还能变高
     (resize:vertical 没动)。 */
  .paste-text { min-height: 104px; padding: 12px 13px; line-height: 1.65; }

  /* ---- 案例画廊:改横向滑 ---- */
  /* 08-03 用户提"移动版首页太长了"。之前改成一列是治了"字挤在一起",
     但代价是首页竖着拉得极长:8 张案例一列排下来 1600px+,
     用户要滚 4 屏才能走完一个区,后面的价格根本到不了。
     横滑是拿"划的动作"换"滚的距离":一屏放一张半,张数再多首页也只长一屏。

     ★为什么用 flex 不用 grid:grid 的列宽要预先声明几列,
       画廊张数是 JS 按"换一换"动态给的(6~8 张不定)。flex 只管
       每张多宽、排不下就往右接,张数变了不用改 CSS。 */
  .gallery {
    display: flex; grid-template-columns: none;   /* 清掉桌面的 grid 声明 */
    overflow-x: auto; overflow-y: hidden;
    gap: 12px; padding-bottom: 22px;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;            /* iOS 惯性滑动 */
    scrollbar-width: none;                        /* 手机上滚动条是浮层,藏掉更干净 */
  }
  .gallery::-webkit-scrollbar { display: none; }
  /* 76% 是算出来的:375 屏可用宽 327,76% = 248px ——
     一张主图占大半屏,右边露出 60px 的下一张。
     那截"露出来的边"就是告诉用户"右边还有,划一下"的唯一提示,
     所以不能给 100%(看不出还有)也不能给 50%(两张都太小看不清图)。 */
  .case { flex: 0 0 76%; scroll-snap-align: start; }
  .case img { height: 148px; }
  .case .cap { font-size: 14px; padding: 11px 13px; line-height: 1.5; }
  /* 提示语补一句"左右划":露边是暗示,这行是明说。不改 HTML,只在窄屏加。 */
  #gallery .sh-sub::after { content: " · 左右划"; color: var(--accent-ink); }

  /* ---- 产品介绍三块:改横向滑 ---- */
  /* 原来 940 断点把三块拉成一列,每块 28px 上下内边距 + 三行字 ≈ 150px,
     三块 480px —— 首页白多长一屏半,而这三块是"它凭什么行"的补充说明,
     不是主入口,不值这个高度。横滑一屏看一块,想看下一条划一下。 */
  .intro { padding: 42px 0 26px; }
  .intro h2 { font-size: 21px; line-height: 1.35; }
  .intro-sub { font-size: 13.5px; line-height: 1.65; margin-bottom: 20px; }
  .intro-features {
    display: flex; grid-template-columns: none;
    overflow-x: auto; overflow-y: hidden;
    gap: 12px; max-width: none;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* 满屏出血:.wrap 有 24px 左右内边距,负 margin 顶掉它让滑轨贴到屏幕边,
       再用等量 padding 把第一块推回原来的对齐线上 ——
       这样滑到最后一块时右边不会剩一条 24px 的白边(看着像没滑到底)。 */
    margin-left: -24px; margin-right: -24px;
    padding: 0 24px 18px;
  }
  .intro-features::-webkit-scrollbar { display: none; }
  /* 78%:比案例图那档略宽,因为这里是三行文字,窄了"结构比手画的严谨"要折三行 */
  .intro-f {
    flex: 0 0 78%; scroll-snap-align: start;
    padding: 20px 18px; border-radius: 16px;
  }
  .intro-f .intro-ic { font-size: 23px; margin-bottom: 2px; }
  .intro-f b { font-size: 14.5px; }
  .intro-f span:last-child { font-size: 13px; }

  /* ---- 价格卡:改横向滑 ---- */
  /* 这是首页最长的一段:月卡 3 张 + 加量包 4 张,一列排下来 7 张 × 约 260px
     = 1800px,用户要滚 5 屏才走完价格区。而"比价"这件事天生适合横着看 ——
     竖着排要靠记忆比(往上翻才知道上一档多少钱),横着划是并排比。
     ★两条轨道各自独立滑(会员卡一条、加量包一条),不合成一条:
       这是两种买法(按月订 vs 按张买),混在一条轨里用户会以为是 7 个档。 */
  .pricing { padding: 26px 0 44px; }
  .pricing h2 { font-size: 21px; line-height: 1.35; }
  .pricing-sub { font-size: 13.5px; line-height: 1.65; margin-bottom: 18px; }
  .pricing-grid,
  .pricing-grid.mem {
    display: flex; grid-template-columns: none; max-width: none;
    /* ★别写 overflow-y:visible 想让角标探出去 —— 规范规定一个方向是
       auto/scroll 时,另一个方向的 visible 会被强制提升成 auto,写了等于没写
       (实测计算值就是 auto)。角标靠下面那 15px padding 救,不是靠这里。 */
    overflow-x: auto; overflow-y: hidden;
    gap: 12px;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin-left: -24px; margin-right: -24px;
    /* ★上面这 15px 内边距不是留白,是给 .pc-badge 让位:
       那个"最划算/按张买里最常选"的角标是 position:absolute; top:-11px,
       也就是【探到卡片外面】。而 overflow-x:auto 会把纵向也一起裁掉 ——
       不给这 15px,角标会被削掉半截,只剩下沿露出来。
       ★别用负 margin-top 把这 15px 抵回去:那等于又把角标顶到裁切线外,
         白留。这 15px 就让它占着,上面 .pricing-sub 的下边距已经收过了。 */
    padding: 15px 24px 18px;
  }
  .pricing-grid::-webkit-scrollbar,
  .pricing-grid.mem::-webkit-scrollbar { display: none; }
  /* 82%:价格卡里有 3 条权益清单,再窄"完整出图流程"这类短句也会折行,
     一折行三张卡高度就不齐(横排时高度不齐特别显眼) */
  .price-card {
    flex: 0 0 82%; scroll-snap-align: start;
    padding: 22px 18px;
  }

  /* ---- 价格卡:字号补上来 ---- */
  /* 卡片本身已经是单列全宽(实测 327px、没有溢出、没有夹窄),
     问题只是字太小。而这几行恰恰是【掏钱之前要看清的数字】——
     「开卡到账 20 张 · 比 ¥69 包多 5 张」12.5px 在手机上要凑近看。
     ★首屏那行 eyebrow 不在这儿改 —— 它的选择器是 .hero-left .eyebrow
       (优先级 0,2,0),这里写 .eyebrow(0,1,0) 压不过去,白写。
       已经在上面那条规则里一起改了。 */
  .pc-detail { font-size: 13px; line-height: 1.6; margin-bottom: 11px; }
  /* 「按张买里最常选」原来 11px —— 它是引导选哪一档的,太小等于没写 */
  .pc-badge { font-size: 12px; }
  .pc-name { font-size: 14.5px; }
  .pc-price { font-size: 13.5px; }
  .pricing-tag { font-size: 13px; padding: 7px 15px; }

  /* ---- 返回链接:点击区补到 44px ---- */
  /* .back-link 是全站共用的(「重新开始」在 generate,「已经有账号」在
     login),原来只有 22px 高 —— 手指按不准,得瞄。用内边距撑高,
     再用等量负 margin 抵掉,免得把下面整块往下推。
     ★padding 只往左边不加(padding-left:0),否则文字会离左边界远一截,
       跟下面内容对不齐。 */
  .back-link { padding: 11px 12px 11px 0; margin: -11px 0 15px; }

}


/* ============================================
   页脚(08-03 加)
   ============================================
   为什么加:整站原来没有页脚。用户看完价格就到底了,出了问题不知道找谁 ——
   这个产品的用户是老师,不是开发者,"用不明白"是常态,得给个人工兜底。

   ★这一整块放在 560 媒体查询【后面】是故意的:页脚是新东西,基础样式
     和窄屏调整都在这儿,自成一段。要是把基础样式写到上面去,
     就会被 560 块里的规则按源码顺序压掉,还得反过来提优先级。
*/
.site-foot {
  margin-top: 10px; padding: 30px 0 34px;
  border-top: 1px solid var(--glass-line);
}
.sf-main {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
}
.sf-help { display: flex; flex-direction: column; gap: 5px; }
.sf-k { font-size: 12.5px; color: var(--text-dim); }
/* 电话是页脚唯一真要给的信息,所以做得像个按钮:等宽数字 + 描边 + 可点即拨。
   ★tabular-nums 必须有:雅黑的默认数字宽度不等,11 位号码看着会一跳一跳。 */
.sf-tel {
  display: inline-flex; align-items: center; gap: 7px;
  align-self: flex-start;
  padding: 8px 15px 8px 13px; border-radius: 12px;
  font-size: 19px; font-weight: 800; letter-spacing: .6px;
  font-variant-numeric: tabular-nums;
  color: var(--accent-ink); text-decoration: none;
  background: var(--accent-soft);
  border: 1px solid rgba(111,102,230,.22);
  transition: transform .15s, box-shadow .15s;
}
.sf-tel .iconify { font-size: 17px; }
.sf-tel:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px -8px rgba(111,102,230,.5);
}
.sf-note { font-size: 12.5px; color: var(--text-dim); }
.sf-nav { display: flex; gap: 18px; }
.sf-nav a {
  font-size: 13px; color: var(--text-dim); text-decoration: none;
  transition: color .2s;
}
.sf-nav a:hover { color: var(--accent); }
.sf-copy {
  margin-top: 22px; padding-top: 16px;
  border-top: 1px solid var(--glass-line);
  font-size: 12px; color: var(--text-faint);
}

@media (max-width: 560px) {
  /* 窄屏改上下排:横排时"同微信·工作时间随时接"会和三条链接挤在一行 */
  .site-foot { padding: 24px 0 30px; }
  .sf-main { flex-direction: column; align-items: stretch; gap: 18px; }
  /* 电话拉满一行:手机上这是要用拇指点的,越大越好点 */
  .sf-tel {
    align-self: stretch; justify-content: center;
    min-height: 50px; font-size: 21px;
  }
  .sf-nav { gap: 0; justify-content: space-between; flex-wrap: wrap; }
  /* 每条链接各撑到 44px 高:手机上点击区不够就得瞄。
     wrap 是给"用户协议"留的后路 —— 四项在 375px 上放得下,
     但字号被系统放大时能换行,总比挤成一字一列好 */
  .sf-nav a {
    display: inline-flex; align-items: center;
    min-height: 44px; padding: 0 4px; font-size: 13.5px;
  }
  .sf-copy { margin-top: 14px; padding-top: 14px; }
}

/* ============================================
   会员到期提醒横幅(08-04 加)
   ============================================
   为什么要有它:商户号不支持自动扣费,续费全靠用户自己想起来。
   这条横幅是【唯一】的提醒渠道,漏了用户的张数就静悄悄作废了。

   ★颜色刻意【不用】品牌紫:紫色在本站是"可以点、是功能"的意思,
     满页都是。提醒要的是"停一下看我",所以用琥珀色(warn)和
     赭红色(已过期)——这两个色全站只有这里用,不会和别的东西混。
   ★放在 body 第一个子元素,固定不滚动 —— 往下滚就看不见的提醒等于没提醒。
*/
.expire-banner {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; gap: 12px;
  padding: 11px 20px;
  /* 琥珀色纸感:纯色平铺太像系统弹窗,加一层极淡的斜向纹理 */
  background:
    linear-gradient(135deg, rgba(255,255,255,.5), rgba(255,255,255,0)),
    linear-gradient(90deg, #fdf3dd, #fbeccb);
  border-bottom: 1px solid rgba(176,124,20,.26);
  box-shadow: 0 2px 14px -6px rgba(120,84,10,.3);
  animation: ebIn .32s cubic-bezier(.22,.9,.28,1);
}
/* 已过期用更重的赭红:"要没了"和"已经没了"是两种紧迫程度,颜色得分开 */
.expire-banner.gone {
  background:
    linear-gradient(135deg, rgba(255,255,255,.45), rgba(255,255,255,0)),
    linear-gradient(90deg, #fbe7e0, #f8ded4);
  border-bottom-color: rgba(180,74,38,.3);
}
@keyframes ebIn {
  from { transform: translateY(-100%); opacity: 0; }
  to   { transform: translateY(0);     opacity: 1; }
}
/* 关掉时往上收:直接 remove 是"闪"没的,看着像出了 bug */
.expire-banner.out {
  transform: translateY(-100%); opacity: 0;
  transition: transform .25s ease, opacity .2s ease;
}
.eb-ic { font-size: 21px; color: #9a6a0d; flex: 0 0 auto; }
.expire-banner.gone .eb-ic { color: #b3452a; }
.eb-t { display: flex; align-items: baseline; gap: 8px; flex: 1 1 auto; min-width: 0; }
.eb-t b { font-size: 14px; font-weight: 800; color: #6b4708; white-space: nowrap; }
.expire-banner.gone .eb-t b { color: #8d3116; }
.eb-t span { font-size: 13px; color: #7d5c1f; line-height: 1.5; }
.expire-banner.gone .eb-t span { color: #93513c; }
/* 续期按钮做成实心:这是横幅存在的目的,不能和"关掉"一样轻 */
.eb-go {
  flex: 0 0 auto;
  display: inline-flex; align-items: center;
  min-height: 34px; padding: 0 15px; border-radius: 10px;
  font-size: 13px; font-weight: 700; text-decoration: none;
  color: #fff; background: linear-gradient(135deg, #c08415, #a86c09);
  box-shadow: 0 6px 14px -7px rgba(120,84,10,.75);
  transition: transform .15s, box-shadow .2s;
}
.expire-banner.gone .eb-go {
  background: linear-gradient(135deg, #c4512f, #a63c1f);
  box-shadow: 0 6px 14px -7px rgba(150,50,25,.75);
}
.eb-go:hover { transform: translateY(-1px); box-shadow: 0 10px 20px -8px rgba(120,84,10,.8); }
/* 关闭键做得很淡:它是出口不是选项 */
.eb-x {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  border: none; border-radius: 8px; cursor: pointer;
  background: transparent; color: #9c7a3c; font-size: 13px;
  transition: background .18s, color .18s;
}
.eb-x:hover { background: rgba(150,110,25,.14); color: #6b4708; }

@media (max-width: 760px) {
  /* 窄屏改上下排:横排时那句"卡里还有12张没用完…"会被挤成一字一行
     (中文没有空格,被夹窄了会逐字折行 —— 本项目踩过这个坑)。
     ★标题和正文也改成竖着放,不再 baseline 对齐。 */
  .expire-banner {
    flex-wrap: wrap; gap: 8px 10px; padding: 11px 16px 12px;
    /* ★手机上不吸顶(08-04 改)。竖排之后横幅高 130px 上下,
       667 的屏吸顶就是常驻挡掉五分之一 —— 首屏那句主标题都看不全。
       改成跟着页面滚走:第一眼一定看得见(它在最上面),看完就让位给内容。
       PC 上宽屏横幅只有 57px 一条,继续吸顶不碍事。 */
    position: static;
  }
  .eb-t { flex-direction: column; gap: 3px; flex: 1 1 100%; order: 1; }
  .eb-ic { order: 0; }
  /* 关闭键跟图标同一行的最右边:不占正文的宽度 */
  .eb-x { order: 0; margin-left: auto; }
  .eb-t b { white-space: normal; font-size: 13.5px; }
  .eb-t span { font-size: 12.5px; }
  /* 续期按钮拉满一行:手机上这是要用拇指点的,越大越好点(44px 起) */
  .eb-go {
    order: 2; flex: 1 1 100%; justify-content: center;
    min-height: 44px; font-size: 14px;
  }
}

/* 价格页的额度规则说明(08-04)。
   ★这条必须存在:卡送的张数到期作废、按张买的永不过期 —— 两套规则,
     买之前没说清,到期那天就是纠纷。所以样式上做得比普通脚注显眼一点
     (带底色和图标),但又不能像警告(那会吓退还没买的人)。 */
.pricing-note.rule {
  display: flex; align-items: flex-start; gap: 8px;
  max-width: 620px; margin: 10px auto 0;
  padding: 11px 15px; border-radius: 12px;
  background: var(--accent-soft);
  border: 1px solid rgba(111,102,230,.18);
  color: var(--accent-ink); font-size: 13px; line-height: 1.6;
  text-align: left;
}
.pricing-note.rule .iconify { flex: 0 0 auto; font-size: 16px; margin-top: 2px; }

/* ============================================
   复制反馈 + 手动复制兜底(08-05 加,配 clipboard.js)
   线上是 http,navigator.clipboard 整个不存在,只能用 textarea+execCommand。
   万一连它也失败(浏览器策略更严),弹这个框让用户自己选。
   ============================================ */
.copy-ok { color: #2f8f5b !important; }

.copy-manual {
  position: fixed; inset: 0; z-index: 400;   /* 400:压过项目页最高的 300 */
  background: rgba(30,28,60,.42);
  backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.copy-manual .cm-card {
  width: 100%; max-width: 460px;
  background: var(--glass-strong);
  border: 1px solid var(--glass-line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 18px 18px 14px;
}
.copy-manual .cm-hd {
  font-size: 14px; color: var(--ink); font-weight: 700; margin-bottom: 10px;
}
.copy-manual .cm-ta {
  width: 100%; min-height: 92px; resize: vertical;
  padding: 11px 12px; box-sizing: border-box;
  font: 400 13.5px/1.65 var(--font);
  color: var(--text); background: #fff;
  border: 1px solid var(--line); border-radius: 12px;
}
.copy-manual .cm-ft {
  display: flex; gap: 10px; justify-content: flex-end; margin-top: 12px;
}
.copy-manual .cm-ft button {
  min-height: 40px; padding: 0 16px; cursor: pointer;
  font: 700 13.5px var(--font); border-radius: 11px;
  border: 1px solid var(--line); background: #fff; color: var(--text);
  transition: border-color .18s, color .18s;
}
.copy-manual .cm-ft button:hover { border-color: var(--accent); color: var(--accent-ink); }
.copy-manual .cm-ft .cm-sel {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.copy-manual .cm-ft .cm-sel:hover { background: var(--accent-2); color: #fff; }

@media (max-width: 560px) {
  /* 手机上按钮撑到 44 才点得准 */
  .copy-manual .cm-ft button { min-height: 44px; flex: 1; }
  .copy-manual .cm-ta { min-height: 110px; }
}

