/* 扫码生成卡片页 —— index.php 的样式 */

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:#fff;color:#1f2329;
  font:14px/1.5 -apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  -webkit-font-smoothing:antialiased;
  padding:32px 16px 48px;
}
.page{max-width:560px;margin:0 auto}

/* ---------- 主面板 ---------- */
.panel{display:flex;background:#f6f7f9;border-radius:14px;padding:20px}
.side{flex:0 0 200px;min-width:0}
.side+.side{flex:1 1 auto;margin-left:20px;padding-left:20px;border-left:1px solid #e6e8eb}
.cap{font-size:13px;color:#8a919e;margin-bottom:12px}

.qrbox{position:relative;background:#fff;border-radius:10px;padding:12px}
.qrbox svg{display:block;width:100%;height:auto}
/* 空态（还没提交识别码）：占位块做得跟真码一样是白底方块，1:1 撑高 ——
   出码后码填进去，左列宽度不跳。注意：空态下边那排小卡和三步说明
   都不渲染（见 index.php），有码才有它们。 */
.qrbox.is-empty{display:flex;align-items:center;justify-content:center;
                aspect-ratio:1;color:#b3b8c1;font-size:12px;line-height:2;text-align:center}
/* 原先到期时左列那行「续费后重新打开本页即可」的小字（.hint）已改成弹窗，
   这条样式跟着删了 —— 别再当它还在。 */

/* 「在哪打开 / 去哪下载」两行小卡（原先把这行文字提示占的位置）
   版式：浅紫底圆角块 + 20px 图标 + 12px 文字，第二行右侧一个 CSS 画的箭头
   —— 箭头不用图，少一个文件也不会因为没传到就变空白方块 */
.dsbox{margin-top:12px;background:#f2f4fb;border-radius:10px;padding:2px 0}
.dsrow{display:flex;align-items:center;gap:8px;padding:8px 10px;
       font-size:12px;line-height:1.4;color:#2b3040;text-decoration:none}
a.dsrow{-webkit-tap-highlight-color:transparent}
a.dsrow:active{background:#e9ecf8;border-radius:10px}
.dsrow img{flex:0 0 20px;width:20px;height:20px;display:block}
.dsrow span{flex:1 1 auto;min-width:0}
.dsrow .chev{flex:0 0 auto;width:6px;height:6px;margin:0 2px 0 0;
             border-right:1.5px solid #97a0b3;border-bottom:1.5px solid #97a0b3;
             transform:rotate(-45deg)}

/* ---------- 卡片到期：这张码扫了也发不了卡，遮起来 + 引导续费 ---------- */
.qrbox.is-dead svg{filter:blur(5px);opacity:.32}
.dead{
  position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;padding:14px;text-align:center;
}
.dead-t{font-size:16px;font-weight:600;color:#1f2329;letter-spacing:.3px}
.dead-s{margin-top:6px;font-size:12px;line-height:1.65;color:#7c8593}
.dead .btn{margin-top:14px}

/* 客服二维码面板：整块盖住码，点任意处收起（index.js 管开关） */
.kefu-panel{
  position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;padding:12px;text-align:center;
  background:rgba(255,255,255,.98);border-radius:10px;cursor:pointer;
}
.kefu-panel[hidden]{display:none}   /* 必须写在 display:flex 后面，否则盖不住 */
.kefu-cap{font-size:13px;font-weight:500;color:#1f2329}
/* 白边：二维码要一圈静区（quiet zone）才扫得稳，jpg 自带的不一定够，
   靠 padding 补；底色跟面板几乎一样白，但加一条淡边框才看得出是张图。 */
.kefu-qr{
  display:block;width:70%;max-width:140px;height:auto;margin-top:8px;
  padding:9px;background:#fff;border:1px solid #e8ebef;border-radius:10px;
}
.kefu-ph{
  margin-top:10px;width:72%;padding:16px 10px;border-radius:8px;
  background:#f6f7f9;font-size:12px;line-height:1.6;color:#8a919e;
}
.kefu-tip{margin-top:8px;font-size:11px;color:#b3b8c1}

.pv{display:flex;gap:10px;background:#fff;border-radius:10px;padding:10px;align-items:center}
.pv .thumb{flex:0 0 56px;width:56px;height:56px;border-radius:8px;background:#eef0f2;object-fit:cover;display:block}
.pv .txt{min-width:0;flex:1 1 auto}
.pv .ttl{font-size:15px;font-weight:500;color:#1f2329;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pv .ttl.is-empty{color:#b3b8c1;font-weight:400}   /* 空态占位标题，别抢眼 */
.pv .sub{margin-top:4px;font-size:12px;color:#8a919e;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.acts{display:flex;gap:10px;margin-top:16px}
.acts .btn{flex:1 1 0}
/* 「下载二维码」是个 hidden 表单（地址栏不能带参数），要跟旁边那颗按钮等宽 */
.acts form.dl{display:flex;flex:1 1 0;margin:0}
.acts form.dl .btn{flex:1 1 0}
.btn{
  display:inline-flex;align-items:center;justify-content:center;
  height:36px;padding:0 18px;border-radius:6px;
  font:inherit;font-size:14px;line-height:1;cursor:pointer;text-decoration:none;
  border:1px solid #e6e8eb;background:#fff;color:#1f2329;
  transition:background .15s,border-color .15s;
  white-space:nowrap;
}
.btn:hover{border-color:#d5d8dd}
.btn.primary{background:#3370ff;border-color:#3370ff;color:#fff}
.btn.primary:hover{background:#2966f0;border-color:#2966f0}

/* ---------- 右列那个识别码表单 ----------
   **永远在「卡片预览」上面**，空态和出码态同一个位置：先能换码，再谈预览。
   下面是「卡片预览」的 .cap，所以只给底边距，不留顶边距、不画分割线
   （它已经是右列第一个块了）。手机断点下跟着右列堆叠，不用另写规则
   （.swap-row 是 flex，宽度不够时输入框自己缩）。 */
.swap{margin-bottom:16px}
.swap .cap{display:block;margin-bottom:8px}   /* label 默认是 inline，不改成块级 margin 不生效 */
.swap-row{display:flex;gap:8px}
.swap input{
  flex:1 1 auto;min-width:0;height:36px;padding:0 10px;
  border:1px solid #e6e8eb;border-radius:6px;background:#fff;color:#1f2329;
  font:inherit;font-size:14px;
  transition:border-color .15s,box-shadow .15s;
}
.swap input::placeholder{color:#b3b8c1}
.swap input:focus{outline:none;border-color:#3370ff;box-shadow:0 0 0 3px rgba(51,112,255,.12)}
.swap .btn{flex:0 0 auto}

/* ---------- 提交中（无刷新那次请求还没回来的几百毫秒） ----------
   盖在二维码上转一圈：那块地方马上要被新码换掉，先给一个「在算」的信号。
   预览区不叠遮罩，只压暗 —— 两块都盖动效反而乱。 */
.spin{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;
      background:#fff;border-radius:inherit}
.spin i{width:22px;height:22px;border:2px solid #dfe3e9;border-top-color:#3370ff;border-radius:50%;
        animation:spin .7s linear infinite}
.pv.is-busy{opacity:.45}
/* 按钮里那颗小圈：主按钮是蓝底白字，圈也得是白的 */
.btn .ld{width:14px;height:14px;margin-right:7px;border:2px solid rgba(255,255,255,.4);
         border-top-color:#fff;border-radius:50%;animation:spin .7s linear infinite}
/* 提交期间按钮禁用：鼠标不变手型、不要让 hover 把蓝色改回去 */
.btn[disabled]{cursor:default;opacity:.72}
.btn.primary[disabled]:hover{background:#3370ff;border-color:#3370ff}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- 识别码出错的弹窗 ----------
   盖住整页。脚本现造的那份，按钮是 <button>；整页降级那条路上服务端输出的是
   <a href="./">，没 JS 也能点（那一下就是普通 GET，回空表单）。 */
.modal{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;
       padding:24px;background:rgba(17,20,24,.45)}
.modal-box{width:100%;max-width:340px;background:#fff;border-radius:14px;padding:22px 20px 18px;
           text-align:center;box-shadow:0 14px 36px rgba(0,0,0,.18)}
.modal-t{font-size:16px;font-weight:600;color:#1f2329}
.modal-m{margin-top:8px;padding:0 2px;font-size:13px;line-height:1.65;color:#8a919e}
.modal-box .btn{margin-top:18px;width:100%}

/* ---------- 三步说明 ---------- */
.steps{display:flex;gap:12px;margin-top:20px}
.step{flex:1 1 0;min-width:0;background:#f6f7f9;border-radius:12px;padding:16px 12px 14px;text-align:center}
.step .num{
  width:26px;height:26px;line-height:26px;margin:0 auto 8px;
  border-radius:50%;background:#3370ff;color:#fff;font-size:14px;font-weight:600;
}
.step .st{font-size:13px;color:#8a919e;margin-bottom:12px;min-height:20px}
.step .simg svg{display:block;width:100%;height:auto;border-radius:8px;background:#fff}
.step .simg img{display:block;width:100%;height:auto;border-radius:8px}
/* 空态占位（.ph）与「已到期」叠字（.simg.is-dead）已随「有码才出三步说明」
   一起下线：三步说明只在 $hasCard && !$expired 时渲染，这两态走不到。 */

@media (max-width:520px){
  body{padding:16px 12px 32px}
  .panel{flex-direction:column;padding:16px}
  .side{flex:none}
  .side+.side{margin:16px 0 0;padding:16px 0 0;border-left:0;border-top:1px solid #e6e8eb}
  .steps{flex-direction:column}
  .step .simg img,.step .simg svg{max-width:172px;margin:0 auto}
}
