:root{
  --brand:#1677ff;
  --brand-d:#0f5fd6;
  --brand-l:#e8f1ff;
  --bg:#f4f6fb;
  --card:#ffffff;
  --line:#e6eaf2;
  --txt:#1b2233;
  --txt2:#5b6579;
  --txt3:#98a1b3;
  --ok:#12b76a;
  --warn:#f79009;
  --err:#f04438;
  --r:14px;
  --shadow:0 1px 2px rgba(16,24,40,.04),0 8px 24px rgba(16,24,40,.06);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
html{-webkit-text-size-adjust:100%}   /* 横竖屏切换时 iOS 不要自己放大字号 */
body{
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  background:var(--bg);color:var(--txt);font-size:15px;line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow-wrap:break-word;
}
img{max-width:100%}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}

/* ---------- 布局 ---------- */
.topbar{
  background:var(--card);border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:50;
}
.topbar .inner{
  max-width:980px;margin:0 auto;padding:0 20px;height:60px;
  display:flex;align-items:center;gap:14px;
}
.logo{display:flex;align-items:center;gap:9px;font-weight:700;font-size:17px;color:var(--txt)}
.logo .dot{
  width:26px;height:26px;border-radius:8px;background:linear-gradient(135deg,var(--brand),#5aa2ff);
  display:flex;align-items:center;justify-content:center;color:#fff;font-size:14px;font-weight:800;
}
.topbar nav{margin-left:auto;display:flex;gap:20px;align-items:center;font-size:14px}
.topbar nav a{color:var(--txt2)}
.topbar nav a:hover{color:var(--brand);text-decoration:none}
.wrap{max-width:980px;margin:0 auto;padding:26px 20px 60px}
/* 管理后台用：表格列多，980px 会把表格挤成竖排文字 */
body.is-admin .wrap,
body.is-admin .topbar .inner,
body.is-admin .foot{max-width:1400px}
/* 列多的表格用固定布局，否则一个长 URL 就能把相邻列挤成一字一行 */
table.tbl-fixed{table-layout:fixed}
table.tbl-fixed td{word-break:break-word}
.foot{
  max-width:980px;margin:0 auto;padding:22px 20px 40px;color:var(--txt3);font-size:13px;
  text-align:center;line-height:1.9;
}

/* ---------- 通用组件 ---------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow)}
.pad{padding:22px}
.h1{font-size:22px;font-weight:700;margin:0 0 4px}
.h2{font-size:17px;font-weight:700;margin:0 0 14px}
.sub{color:var(--txt2);font-size:14px}
.muted{color:var(--txt3);font-size:13px}
.mt{margin-top:16px}.mt2{margin-top:26px}
.row{display:flex;gap:14px;flex-wrap:wrap}
.grow{flex:1;min-width:0}
.sep{height:1px;background:var(--line);margin:18px 0}
.center{text-align:center}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  height:42px;padding:0 20px;border-radius:10px;border:1px solid transparent;
  background:var(--brand);color:#fff;font-size:15px;font-weight:600;cursor:pointer;
  transition:.15s;font-family:inherit;white-space:nowrap;
}
.btn:hover{background:var(--brand-d)}
.btn:active{transform:translateY(1px)}
.btn:disabled{opacity:.5;cursor:not-allowed}
.btn.ghost{background:#fff;color:var(--txt);border-color:var(--line)}
.btn.ghost:hover{background:#f7f9fc;color:var(--brand)}
.btn.ok{background:var(--ok)}
.btn.warn{background:var(--warn)}
.btn.err{background:var(--err)}
.btn.sm{height:32px;padding:0 12px;font-size:13px;border-radius:8px}
.btn.block{width:100%}

label.f{display:block;margin:0 0 6px;font-size:13px;font-weight:600;color:var(--txt2)}
input[type=text],input[type=password],input[type=number],input[type=email],select,textarea{
  width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
  font-size:15px;font-family:inherit;background:#fff;color:var(--txt);outline:none;transition:.15s;
}
input:focus,select:focus,textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-l)}
textarea{resize:vertical;min-height:110px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:13px}
.field{margin-bottom:14px}

.tag{
  display:inline-flex;align-items:center;height:22px;padding:0 9px;border-radius:6px;
  font-size:12px;font-weight:600;background:var(--brand-l);color:var(--brand-d);
}
.tag.ok{background:#e7f8f0;color:#0b8f52}
.tag.warn{background:#fff5e6;color:#b96b00}
.tag.err{background:#feebea;color:#c0352b}
.tag.gray{background:#f1f3f7;color:var(--txt2)}
.tag.gray2{background:#eef0f5;color:#6b7488}
a.tag{cursor:pointer}
a.tag:hover{text-decoration:none;background:#d7e6ff;color:var(--brand-d)}

table{width:100%;border-collapse:collapse;font-size:13px}
th,td{padding:9px 10px;text-align:left;border-bottom:1px solid var(--line);vertical-align:middle}
th{background:#fafbfd;color:var(--txt2);font-weight:600;font-size:12px;white-space:nowrap}
tbody tr:hover{background:#fafbfe}
td.mono,th.mono{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px}
.mono{font-family:ui-monospace,Menlo,Consolas,monospace}

.alert{padding:12px 15px;border-radius:10px;font-size:14px;margin-bottom:16px;line-height:1.7}
.alert.info{background:var(--brand-l);color:#0b4bab}
.alert.warn{background:#fff8e8;color:#8a5300}
.alert.err{background:#feebea;color:#a52a1f}
.alert.ok{background:#e7f8f0;color:#0b7a46}

/* ---------- 商品 ---------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}
.prod{display:flex;flex-direction:column;padding:20px}
.prod .name{font-size:16px;font-weight:700;margin-bottom:6px}
.prod .desc{color:var(--txt2);font-size:13.5px;min-height:42px;margin-bottom:10px}
.prod .meta{color:var(--txt3);font-size:13px;line-height:1.85;margin-bottom:10px}
.prod .cardfoot{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.prod .price{font-size:26px;font-weight:800;color:var(--brand);letter-spacing:-.5px}
.prod .price small{font-size:14px;font-weight:600;margin-right:2px}
.prod .foot{margin-top:auto;display:flex;align-items:flex-end;justify-content:space-between;gap:10px}

/* ---------- 分组 ---------- */
.chips{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:18px}
.chip{
  display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 14px;border-radius:999px;
  background:#fff;border:1px solid var(--line);color:var(--txt2);font-size:14px;font-weight:600;
}
.chip:hover{color:var(--brand);border-color:var(--brand);text-decoration:none}
.chip.on{background:var(--brand);border-color:var(--brand);color:#fff}
.chip .n{
  min-width:20px;height:20px;padding:0 6px;border-radius:999px;background:var(--brand-l);
  color:var(--brand-d);font-size:12px;display:inline-flex;align-items:center;justify-content:center;
}
.chip.on .n{background:rgba(255,255,255,.28);color:#fff}

/* 下单页的「同系列其他规格」——同类型换时长的入口 */
.siblist{display:flex;flex-direction:column;gap:8px}
.sib{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 14px;border:1px solid var(--line);border-radius:12px;background:#fbfcfe;
}
.sib:hover{border-color:var(--brand);background:#f6faff;text-decoration:none}
.sib-l{display:flex;flex-direction:column;min-width:0}
.sib-name{font-weight:600;color:var(--txt);font-size:14.5px}
.sib-meta{color:var(--txt3);font-size:12.5px;line-height:1.6}
.sib-r{display:flex;align-items:center;gap:10px;flex:none}
.sib-price{font-weight:800;color:var(--brand);font-size:17px}
.sib-go{font-size:12px;color:var(--txt3)}

/* ---------- 软件下载 ---------- */
/* 卡片撑满整行：介绍可能写好几行，两列排会把文字压成窄条很难读 */
.swlist{display:grid;grid-template-columns:minmax(0,1fr);gap:14px}
.sw .sw-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}
.sw .sw-name{font-size:16.5px;font-weight:700}
.sw .sw-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:7px;color:var(--txt3);font-size:12.5px}
.sw .sw-desc{
  margin:14px 0 0;padding-top:14px;border-top:1px solid var(--line);
  color:var(--txt2);font-size:13.5px;line-height:1.8;
  white-space:pre-line;              /* 后台按多行写的介绍要保留换行，否则挤成一坨 */
}
.sw .btn{flex:none}
/* 一个软件可能给两条下载地址（主用 + 备用），并排放、放不下就换行 */
.sw .sw-btns{display:flex;flex-direction:column;gap:8px}
@media (min-width:641px){ .sw .sw-btns{flex-direction:row;flex-wrap:wrap} }

/* ---------- 支付 ---------- */
.paybox{display:flex;gap:28px;flex-wrap:wrap;align-items:flex-start}
.qrwrap{
  width:230px;height:230px;border:1px solid var(--line);border-radius:12px;
  padding:12px;background:#fff;flex:none;
}
.qrwrap svg{display:block;width:100%;height:100%}
.kv{display:flex;justify-content:space-between;gap:14px;padding:8px 0;font-size:14px;border-bottom:1px dashed var(--line)}
.kv:last-child{border-bottom:0}
.kv .k{color:var(--txt2)}
.kv .v{font-weight:600;text-align:right;word-break:break-all}
.countdown{font-family:ui-monospace,Menlo,Consolas,monospace;color:var(--warn);font-weight:700}

.cards{
  background:#0f1a2e;color:#c9f7d8;border-radius:12px;padding:16px 18px;
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:14px;line-height:2;
  white-space:pre-wrap;word-break:break-all;position:relative;
}
.cards .copy{
  position:absolute;top:10px;right:10px;height:30px;padding:0 12px;font-size:12px;
  background:rgba(255,255,255,.12);color:#fff;border:0;border-radius:7px;cursor:pointer;
}
.cards .copy:hover{background:rgba(255,255,255,.22)}

.steps{display:flex;gap:8px;margin-bottom:22px;flex-wrap:wrap}
.step{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--txt3)}
.step .n{
  width:22px;height:22px;border-radius:50%;background:#eaedf3;color:var(--txt3);
  display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none;
}
.step.on{color:var(--txt);font-weight:600}
.step.on .n{background:var(--brand);color:#fff}
.step.done .n{background:var(--ok);color:#fff}
.step .bar{width:22px;height:1px;background:var(--line)}

/* ---------- 后台 ---------- */
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:20px;flex-wrap:wrap}
.tabs a{
  padding:10px 16px;font-size:14px;font-weight:600;color:var(--txt2);border-bottom:2px solid transparent;
  margin-bottom:-1px;
}
.tabs a.on{color:var(--brand);border-bottom-color:var(--brand)}
.tabs a:hover{text-decoration:none;color:var(--brand)}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-bottom:22px}
.stat{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:15px 16px}
.stat .n{font-size:23px;font-weight:800;letter-spacing:-.5px}
.stat .l{font-size:12.5px;color:var(--txt2);margin-top:2px}
.tablewrap{overflow-x:auto;border:1px solid var(--line);border-radius:12px;background:#fff}
.tablewrap table{min-width:640px}
/* ⚠️ 网格轨道一律写 minmax(0,1fr) 而不是 1fr：
   1fr 的最小值是 auto = 内容的 min-content，而表格有 min-width:640px，
   于是「1fr」的列会被撑到 688px 并溢出容器（`.tablewrap` 的滚动条根本没机会出现）。
   minmax(0,1fr) 才允许轨道缩到容器宽度，把溢出交给 .tablewrap 去滚。 */
.keys{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px}
/* 商品页：编辑表单窄、列表宽（列多，1:1 会把表格挤成竖排文字） */
.keys.wide{grid-template-columns:minmax(300px,360px) minmax(0,1fr);align-items:start}

/* ================================================================
   移动端适配
   断点说明：900px（平板/小笔记本，后台两列改一列）
             640px（手机竖屏，主要战场）
             400px（小屏手机 iPhone SE 之类）
   ================================================================ */

/* 只在窄屏 / 只在宽屏显示的元素。
   .only-phone      段落类（按块显示）
   .only-phone-flex 按钮类（.btn 是 inline-flex，改成块会把按钮拉满一行）
   .only-pc         电脑端专属，窄屏藏掉
   默认状态都是「藏起来」，由窄屏媒体查询放出来。 */
.only-phone,.only-phone-flex{display:none!important}

@media(max-width:980px){
  .keys.wide{grid-template-columns:minmax(0,1fr)}
}

@media(max-width:640px){
  /* 布局 */
  .wrap{padding:16px 13px 44px}
  .topbar .inner{height:54px;padding:0 13px;gap:10px}
  .logo{font-size:16px}
  .topbar nav{gap:14px;font-size:13.5px}
  .topbar-contact{display:none}          /* 窄屏顶栏放不下，联系方式挪到页脚 */
  .pad{padding:16px}
  .card{border-radius:12px}
  .h1{font-size:19px}
  .h2{font-size:16px}
  .foot{padding:18px 13px 34px}
  .sep{margin:14px 0}

  /* 商品卡片：单列、压缩留白 */
  .grid{grid-template-columns:minmax(0,1fr);gap:12px}
  .prod{padding:16px}
  .prod .desc{min-height:0}
  .prod .price{font-size:23px}

  /* 软件下载卡片：下载按钮单独占一行并撑满，手指好点 */
  .swlist{gap:12px}
  .sw .sw-head{gap:10px}
  .sw .btn{width:100%;margin-top:4px}

  /* ⚠️ 表单控件必须 ≥16px：小于 16px 时 iOS Safari 一聚焦就自动放大整页，
     用户得手动缩回去，是手机端最容易被投诉的体验问题。 */
  input[type=text],input[type=password],input[type=number],input[type=email],select,textarea{font-size:16px}
  label.f{font-size:12.5px}

  /* 触控目标：主按钮 44px（苹果/安卓人机指南下限），小按钮 38px 兼顾信息密度 */
  .btn{height:44px;padding:0 18px}
  .btn.sm{height:38px;padding:0 14px;font-size:13.5px}

  .chips{gap:7px;margin-bottom:14px}
  .chip{height:32px;padding:0 12px;font-size:13.5px}

  /* 订单页：手机版优先给「打开支付宝」的跳转按钮（自己扫自己屏幕没意义），
     但二维码**不能藏** —— 手机没装支付宝、或者页面开在微信里，按钮是打不开的，
     那一刻二维码是唯一的出路。所以只把它缩小，不 display:none。 */
  .paybox{gap:16px;flex-direction:column}
  .payqr .qrwrap{width:168px;height:168px}
  .only-phone{display:block!important}
  .only-phone-flex{display:inline-flex!important}
  .only-pc{display:none!important}
  .kv{font-size:13.5px}
  .kv .v{font-size:14px}
  .qrwrap{width:200px;height:200px;margin:0 auto}

  /* 卡密是长串等宽文本，窄屏必须让它自然换行，复制按钮改成整行 */
  .cards{font-size:12.5px;padding:14px;line-height:1.9;border-radius:10px}
  .cards .copy{position:static;display:block;width:100%;margin-top:10px;height:36px}

  .steps{gap:6px;margin-bottom:16px}
  .step{font-size:12.5px}
  .step .bar{width:10px}

  /* 下单页的同系列切换 */
  .sib{padding:11px 12px}
  .sib-price{font-size:16px}

  /* 后台：两列并排的卡片在手机上改成一列 */
  .keys{grid-template-columns:minmax(0,1fr)}

  /* 后台：tab 横向滑动、表格横向滚动（列多的表在手机上没法塞进去） */
  .stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .stat .n{font-size:20px}
  .tabs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .tabs::-webkit-scrollbar{display:none}
  .tabs a{padding:10px 13px;white-space:nowrap}
  .tablewrap{-webkit-overflow-scrolling:touch}
  body.is-admin .wrap{padding:16px 13px 44px}
}

@media(max-width:400px){
  /* 价格和按钮挤一行会互相压，小屏就竖着放 */
  .prod .foot{flex-direction:column;align-items:stretch;gap:10px}
  .prod .foot .btn{width:100%}
}

/* ---------- toast ---------- */
#toast{
  position:fixed;left:50%;top:22px;transform:translate(-50%,-160%);
  background:#1b2233;color:#fff;padding:10px 20px;border-radius:10px;font-size:14px;
  z-index:999;transition:transform .28s cubic-bezier(.2,.9,.3,1.2),opacity .2s;
  max-width:88vw;text-align:center;opacity:0;pointer-events:none;
}
#toast.show{transform:translate(-50%,0);opacity:1}
#toast.err{background:#c0352b}
#toast.ok{background:#0b7a46}
