*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;background:#f4f6fb;color:#172033}button,input,textarea,select{font:inherit}button{border:1px solid #d8e0ef;border-radius:10px;background:#fff;padding:9px 14px;color:#334155;cursor:pointer}button.primary{background:#2563eb;color:#fff;border-color:#2563eb;font-weight:700}button.danger{color:#b91c1c;border-color:#fecaca}button:disabled{opacity:.55;cursor:wait}input,textarea,select{border:1px solid #d8e0ef;border-radius:10px;padding:10px 12px;background:#fff;color:#172033}textarea{resize:vertical}:focus-visible{outline:3px solid #93c5fd;outline-offset:2px}.shell{max-width:1040px;margin:auto;padding:0 16px 70px}.top{position:sticky;top:0;z-index:20;background:#f4f6fb;display:flex;gap:9px;align-items:center;padding:12px 0}.top h1{font-size:18px;flex:1;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card{background:#fff;border-radius:17px;padding:18px;box-shadow:0 2px 10px #1e293b0d;margin-bottom:14px}.auth{max-width:420px;margin:70px auto}.auth h1{margin:0 0 8px}.muted{color:#64748b;font-size:13px;line-height:1.65}.field{display:block;margin:12px 0 5px;font-size:13px;font-weight:700;color:#475569}.auth input{width:100%;margin-bottom:7px}.row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}.class-card{display:flex;align-items:center;gap:10px;cursor:pointer}.class-card .grow{flex:1}.class-card b{font-size:16px}.code{font-family:ui-monospace,monospace;letter-spacing:2px;color:#2563eb;font-weight:800}.hero{background:linear-gradient(135deg,#2563eb,#1d4ed8);color:#fff}.hero .code{color:#fff;font-size:20px}.tabs{display:flex;background:#e7edf8;border-radius:12px;padding:4px;gap:4px;margin:13px 0}.tabs button{flex:1;background:transparent;border:0;color:#64748b;font-weight:700}.tabs button.active{background:#fff;color:#2563eb;box-shadow:0 1px 5px #1e293b18}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px}.student-card{padding:13px 8px;border:1px solid #e5eaf3;border-radius:13px;text-align:center;background:#fff;cursor:pointer}.student-card .score{font-size:25px;font-weight:800;color:#2563eb}.names{display:flex;gap:7px;flex-wrap:wrap}.pill{border:1px solid transparent;border-radius:999px;padding:7px 12px;background:#eef2f7;color:#64748b;cursor:pointer}.pill.done,.pill.pass{background:#dcfce7;color:#15803d;border-color:#86efac}.pill.late,.pill.redo{background:#ffedd5;color:#c2410c;border-color:#fdba74}.pill.pending{background:#fee2e2;color:#b91c1c;border-color:#fecaca}.task{border-top:1px solid #edf1f7;padding:14px 0}.task:first-child{border-top:0}.task h3{font-size:15px;margin:0 0 9px}.badge{font-size:12px;border-radius:999px;padding:3px 8px;background:#eef2ff;color:#4338ca;margin-left:5px}.draw-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}.draw-card{border:2px solid transparent;border-radius:15px;padding:18px 10px;text-align:center;background:#f8fafc;cursor:pointer}.draw-card.pass{background:#dcfce7;border-color:#86efac}.draw-card.redo{background:#ffedd5;border-color:#fdba74}.draw-card b{font-size:21px}table{width:100%;border-collapse:collapse;font-size:13px}th,td{padding:9px 6px;border-bottom:1px solid #edf1f7;text-align:left}th{background:#f8fafc;color:#64748b}.num{text-align:center}.toast{position:fixed;left:50%;bottom:25px;transform:translate(-50%,15px);opacity:0;background:#172033eF;color:#fff;padding:10px 17px;border-radius:999px;transition:.2s;z-index:100;max-width:88vw;text-align:center}.toast.show{opacity:1;transform:translate(-50%,0)}dialog{border:0;border-radius:16px;padding:0;width:min(94vw,500px);box-shadow:0 20px 60px #0f172a44}dialog::backdrop{background:#0f172a77}dialog form{padding:20px}dialog textarea,dialog input{width:100%}.empty{text-align:center;padding:45px 10px;color:#94a3b8}.sync-error{color:#b91c1c;font-size:12px;font-weight:700}@media(max-width:560px){.shell{padding:0 11px 50px}.card{padding:14px}.top{flex-wrap:wrap}.tabs button{padding:8px 4px;font-size:12px}th,td{padding:7px 3px;font-size:12px}.desktop-only{display:none}.row>*{max-width:100%}}
.notice{background:#eff6ff;border:1px solid #bfdbfe;border-radius:12px;padding:11px 13px;font-size:13px;line-height:1.6;color:#1e40af;margin:4px 0 8px}
.notice .row{margin:0}
/* 下面这几个是「工具类」，专门替换掉散落在 JS 模板里的内联 style 属性。
   _headers 的 CSP 是 style-src 'self'（不含 'unsafe-inline'），
   内联 style="..." 会被浏览器直接丢弃 —— 表现在界面上就是「班级码输入框没大写没字距」
   「+1/−1 按钮没居中」这种说不清哪里不对的错位。所以一律走类名。 */
.mt8{margin-top:8px}
.mt10{margin-top:10px}
.center{justify-content:center}
.code-input{width:100%;text-transform:uppercase;letter-spacing:3px}

/* ---- 初始化引导页（setup.html）用到的样式 ----
   CSP 是 style-src 'self'，内联 style 会被丢，所以流程页的排版一律走类名。 */
.notice.ok{background:#ecfdf5;border-color:#a7f3d0;color:#065f46}
.notice.warn{background:#fffbeb;border-color:#fde68a;color:#92400e}
.notice a{color:inherit;font-weight:700}
.step{padding:20px}
.step-head{display:flex;gap:11px;align-items:center;margin-bottom:9px}
.step-head h2{font-size:17px;margin:0}
.step-no{flex:none;width:26px;height:26px;border-radius:50%;background:#2563eb;color:#fff;
  font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center}
button.big{padding:13px 20px;font-size:15px}
.ol{margin:6px 0;padding-left:22px;font-size:13px;line-height:1.9;color:#334155}
.ol li{margin-bottom:2px}
.step code{background:#f1f5f9;border:1px solid #e2e8f0;border-radius:5px;
  padding:1px 5px;font-family:ui-monospace,monospace;font-size:12px;color:#0f172a}
.step u{text-decoration-color:#ef4444;text-decoration-thickness:2px;text-underline-offset:3px}
.step a{color:#2563eb}
/* 设口令那一行要能「直接选中复制」：复制按钮失灵时的唯一出路。
   user-select:all 让点一下（iPad 上是双击）就整行选中，不用一点点拖；
   break-all 保证长口令不会把卡片撑破。 */
.stmt{margin:6px 0}
.stmt code{display:block;padding:9px 11px;white-space:pre-wrap;word-break:break-all;
  user-select:all;-webkit-user-select:all;line-height:1.5}
.setup-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}

