/* 三个程序的桌面 GUI 都是 ttkbootstrap 的 cosmo 主题，
   这里按那套控件的观感还原：LabelFrame、toolbutton、Treeview、状态栏。 */

:root {
  --primary: #2780e3;
  --secondary: #7b8a8b;
  --success: #3fb618;
  --info: #9954bb;
  --warning: #ff7518;
  --danger: #ff0039;
  --light: #f8f9fa;
  --dark: #373a3c;

  --bg: #ffffff;
  --panel: #ffffff;
  --ink: #373a3c;
  --ink-2: #6c757d;
  --line: #ced4da;
  --line-soft: #e9ecef;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--light);
  color: var(--ink);
  font: 13px/1.5 "Microsoft YaHei", "PingFang SC", "Segoe UI", system-ui, sans-serif;
}

button, input, select, textarea { font: inherit; color: inherit; }

/* ============ 整体布局 ============ */
.app { display: none; height: 100vh; grid-template-columns: 232px 1fr; }
.app.on { display: grid; }

.side { background: #2f3338; color: #c8cdd2; display: flex; flex-direction: column; overflow-y: auto; }
.side .brand {
  padding: 16px 18px 12px; color: #fff; font-size: 15px; font-weight: 600;
  border-bottom: 1px solid #41464b;
}
.side .brand small { display: block; font-size: 11px; color: #8b949b; font-weight: 400; margin-top: 3px; }
.side .grp { padding: 14px 18px 5px; font-size: 11px; color: #7d858d; letter-spacing: 1px; }
.side button {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  cursor: pointer; padding: 10px 18px; color: #c8cdd2; font-size: 13px;
  border-left: 3px solid transparent; line-height: 1.35;
}
.side button small { display: block; font-size: 11px; color: #858d95; margin-top: 2px; }
.side button:hover { background: #3a3f45; color: #fff; }
.side button.on { background: #3a3f45; color: #fff; border-left-color: var(--primary); }
.side button.on small { color: #a9b3bc; }
.side-foot { margin-top: auto; padding: 12px 18px; font-size: 12px; color: #858d95; border-top: 1px solid #41464b; }
.side-foot a { color: #9aa3ab; cursor: pointer; }
.side-foot a:hover { color: #fff; }

.main { overflow-y: auto; padding: 12px; display: flex; flex-direction: column; }
.page { display: none; flex-direction: column; flex: 1; min-height: 0; }
.page.on { display: flex; }

.win-title { font-size: 15px; font-weight: 600; margin: 2px 4px 10px; }
.win-title span { font-weight: 400; font-size: 12px; color: var(--ink-2); margin-left: 8px; }

/* ============ LabelFrame ============ */
.lf { border: 1px solid var(--line); border-radius: 4px; margin-bottom: 12px; position: relative;
      background: var(--panel); padding: 18px 14px 14px; }
.lf > legend, .lf > .lf-t {
  position: absolute; top: -9px; left: 10px; background: var(--panel);
  padding: 0 6px; font-size: 12px; color: var(--primary); font-weight: 600;
}
.lf.grow { flex: 1; display: flex; flex-direction: column; min-height: 0; }

.row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.row + .row { margin-top: 12px; }
.lf > .toolbar + .row { margin-top: 14px; }
.row.muted { line-height: 1.8; }
.sp { flex: 1; }
.muted { color: var(--ink-2); font-size: 12px; }

/* ============ 控件 ============ */
label.inline { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; white-space: nowrap; }
label.inline input { margin: 0; }

input[type=text], input[type=password], input[type=number], select {
  padding: 5px 8px; border: 1px solid var(--line); border-radius: 4px; background: #fff; outline: none;
}
input:focus, select:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(39,128,227,.15); }
input[readonly] { background: var(--light); color: var(--ink-2); }
input:disabled, select:disabled, button:disabled { opacity: .5; cursor: not-allowed; }

.btn {
  padding: 6px 14px; border-radius: 4px; border: 1px solid var(--line);
  background: #fff; cursor: pointer; white-space: nowrap;
}
.btn:hover:not(:disabled) { background: var(--light); }
.btn.primary  { background: var(--primary);  border-color: var(--primary);  color: #fff; }
.btn.success  { background: var(--success);  border-color: var(--success);  color: #fff; }
.btn.danger   { background: var(--danger);   border-color: var(--danger);   color: #fff; }
.btn.info     { background: var(--info);     border-color: var(--info);     color: #fff; }
.btn.warning  { background: var(--warning);  border-color: var(--warning);  color: #fff; }
.btn.secondary{ background: var(--secondary);border-color: var(--secondary);color: #fff; }
.btn.primary:hover:not(:disabled), .btn.success:hover:not(:disabled),
.btn.danger:hover:not(:disabled), .btn.info:hover:not(:disabled),
.btn.warning:hover:not(:disabled), .btn.secondary:hover:not(:disabled) { filter: brightness(1.1); }
.btn.o-info    { color: var(--info);    border-color: var(--info); }
.btn.o-success { color: var(--success); border-color: var(--success); }
.btn.o-sec     { color: var(--secondary); border-color: var(--secondary); }
.btn.o-danger  { color: var(--danger);  border-color: var(--danger); }
.btn.sm { padding: 3px 9px; font-size: 12px; }

/* toolbutton 样式的单选（华理的功能选择就是这个） */
.toolbar { display: flex; flex-wrap: wrap; gap: 10px; }
.toolbar.fill > label { flex: 1 1 130px; }
.toolbtn {
  display: block; text-align: center; padding: 9px 14px; border-radius: 4px;
  border: 1px solid var(--primary); color: var(--primary); background: #fff;
  cursor: pointer; white-space: nowrap; font-size: 13px; user-select: none;
}
.toolbtn input { display: none; }
.toolbtn:hover { background: rgba(39,128,227,.08); }
.toolbtn.on { background: var(--primary); color: #fff; }

/* 竖排单选（上开大 12 个模式） */
.radios { display: flex; flex-wrap: wrap; gap: 4px 18px; }
.radios label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; padding: 3px 0; white-space: nowrap; }

/* 滑块 */
input[type=range] { flex: 1; min-width: 120px; accent-color: var(--primary); }
.scale-val { font-weight: 700; font-size: 15px; min-width: 28px; text-align: center; }

/* ± 数字框 */
.spin { display: inline-flex; align-items: center; gap: 6px; }
.spin button {
  width: 26px; height: 26px; border: 1px solid var(--line); background: #fff;
  border-radius: 4px; cursor: pointer; color: var(--secondary); line-height: 1;
}
.spin button:hover { background: var(--light); }
.spin .v { min-width: 32px; text-align: center; font-weight: 700; font-size: 14px; }

/* ============ 表格（Treeview） ============ */
.tbl-wrap { border: 1px solid var(--line); border-radius: 3px; overflow: auto; background: #fff; flex: 1; min-height: 90px; }
table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
th, td { padding: 5px 8px; text-align: left; border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
th { background: #eceff1; font-weight: 600; position: sticky; top: 0; z-index: 1; border-bottom: 1px solid var(--line); }
td.c, th.c { text-align: center; }
tbody tr:hover { background: #f1f5f9; }
tr.r-success { background: #C6EFCE; }
tr.r-fail    { background: #FFC7CE; }
tr.r-running { background: #BDD7EE; }
tr.r-waiting { background: #F2F2F2; }
tr.r-success:hover { background: #b6e5be; }
tr.r-fail:hover    { background: #f5b8c0; }
tr.r-running:hover { background: #adc9e4; }
.empty-row td { text-align: center; color: var(--ink-2); padding: 24px; }

/* ============ 进度条 ============ */
.pbar { flex: 1; height: 18px; background: var(--line-soft); border-radius: 3px; overflow: hidden; min-width: 120px; }
.pbar > i {
  display: block; height: 100%; width: 0; background: var(--primary); transition: width .3s;
  background-image: linear-gradient(45deg, rgba(255,255,255,.18) 25%, transparent 25%,
    transparent 50%, rgba(255,255,255,.18) 50%, rgba(255,255,255,.18) 75%, transparent 75%, transparent);
  background-size: 20px 20px; animation: stripe 1s linear infinite;
}
@keyframes stripe { from { background-position: 0 0; } to { background-position: 20px 0; } }
.pbar.idle > i { animation: none; }

/* ============ 日志 ============ */
.logbox {
  flex: 1; min-height: 120px; overflow: auto; padding: 8px 10px; background: #fff;
  border: 1px solid var(--line); border-radius: 3px;
  font: 12px/1.6 Consolas, "Cascadia Mono", monospace; white-space: pre-wrap; word-break: break-all;
}
.logbox.dark { background: #1e1e1e; color: #d4d4d4; border-color: #1e1e1e; }
.logbox .t { color: #9aa0a6; margin-right: 7px; }
.logbox.dark .t { color: #6a737d; }
.l-info {}
.l-success { color: var(--success); }
.l-warn  { color: var(--warning); }
.l-error { color: var(--danger); }
.logbox.dark .l-warn { color: #e3b341; }
.logbox.dark .l-error { color: #f85149; }

/* ============ 状态栏 ============ */
.statusbar {
  display: flex; align-items: center; gap: 18px; margin-top: 6px; padding: 5px 10px;
  background: #eceff1; border: 1px solid var(--line); border-radius: 3px;
  font-size: 12px; color: var(--ink-2);
}
.statusbar .dot-idle { color: var(--secondary); }
.statusbar .dot-run  { color: var(--success); }
.statusbar .dot-err  { color: var(--danger); }

/* ============ 登录页 ============ */
.login { display: flex; min-height: 100vh; align-items: center; justify-content: center; padding: 20px; }
.login .box { background: #fff; border: 1px solid var(--line); border-radius: 6px; padding: 26px; width: 100%; max-width: 330px; }
.login h1 { font-size: 17px; margin: 0 0 4px; text-align: center; }
.login p { text-align: center; color: var(--ink-2); font-size: 12px; margin: 0 0 18px; }
.login label { display: block; margin-bottom: 12px; }
.login label span { display: block; font-size: 12px; color: var(--ink-2); margin-bottom: 4px; }
.login input { width: 100%; }

/* ============ 弹窗 / 提示 ============ */
.mask { position: fixed; inset: 0; background: rgba(0,0,0,.5); display: none;
        align-items: center; justify-content: center; padding: 20px; z-index: 60; }
.mask.on { display: flex; }
.modal { background: #fff; border-radius: 6px; padding: 20px; width: 100%; max-width: 420px; max-height: 88vh; overflow: auto; }
.modal.wide { max-width: 760px; }
.modal h3 { margin: 0 0 6px; font-size: 15px; }
.qr-img { display: block; width: 236px; height: 236px; margin: 14px auto; border: 1px solid var(--line); }

.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%);
  background: #2f3338; color: #fff; padding: 9px 18px; border-radius: 4px;
  font-size: 13px; z-index: 100; opacity: 0; pointer-events: none; transition: opacity .25s; max-width: 90vw;
}
.toast.on { opacity: 1; }
.toast.err { background: var(--danger); }

/* ============ 文才：左右两栏 ============ */
.two-col { display: flex; gap: 10px; align-items: stretch; }
.two-col > .lf.left { width: 268px; flex: none; }
.two-col > .lf.right { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.two-col .lf.left .row { margin-top: 0; margin-bottom: 8px; }
.two-col .lf.left label.f { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.two-col .lf.left label.f > b { width: 40px; font-weight: 400; color: var(--ink); }
.two-col .lf.left label.f > input, .two-col .lf.left label.f > select { flex: 1; min-width: 0; }

@media (max-width: 900px) {
  .app.on { grid-template-columns: 1fr; height: auto; }
  .side { flex-direction: row; overflow-x: auto; align-items: center; }
  .side .brand, .side .grp { display: none; }
  .side button { width: auto; white-space: nowrap; border-left: 0; border-bottom: 3px solid transparent; }
  .side button small { display: none; }
  .side button.on { border-left-color: transparent; border-bottom-color: var(--primary); }
  .side-foot { margin: 0; border: 0; white-space: nowrap; }
  .two-col { flex-direction: column; }
  .two-col > .lf.left { width: auto; }
}

/* ============ 权限勾选弹窗 ============ */
.perm-modal { width: 620px; max-width: 94vw; }
.perm-body { max-height: 52vh; overflow-y: auto; border: 1px solid var(--line);
             border-radius: 4px; padding: 8px 10px; background: var(--panel); }
.perm-grp { margin-bottom: 10px; }
.perm-grp:last-child { margin-bottom: 0; }
.perm-grp > .hd { font-weight: 600; padding: 4px 0; border-bottom: 1px solid var(--line);
                  margin-bottom: 5px; }
.perm-grp > .hd small { font-weight: 400; color: var(--ink-2); margin-left: 6px; }
.perm-items { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px 12px;
              padding-left: 16px; }
.perm-items label { display: flex; align-items: center; gap: 5px; padding: 2px 0;
                    font-size: 13px; cursor: pointer; }
.perm-items label small { color: var(--ink-2); }
@media (max-width: 560px) { .perm-items { grid-template-columns: 1fr; } }
.imp-err { color: var(--danger); font-weight: 500; }

/* 学员账号的状态徽章。颜色只分三档：做完了 / 要留意 / 要人处理，
   别做成一片五颜六色——扫一眼要能看出"该先管谁"。 */
.st-badge {
  display: inline-block;
  margin: 1px 4px 1px 0;
  padding: 1px 7px;
  border-radius: 9px;
  font-size: 11.5px;
  line-height: 17px;
  white-space: nowrap;
  background: #eef1f4;
  color: #4a5761;
}
.st-badge.ok { background: #e4f3ea; color: #1f6b45; }
.st-badge.warn { background: #fdf0da; color: #8a5b00; }
.st-badge.bad { background: #fbe6e4; color: #a8261c; }

/* ===== 上海大学面板：逐账号登录与验证码 =====================================
   这个程序的登录要短信验证码，一次全发出去对不过来，所以操作单位是**一行一个
   账号**：点「登录」才发码，填完那行自己开跑。下面几个类只服务这张表。 */

/* 表头上方的状态统计。数字比文字重要，用等宽对齐，扫一眼就知道有几个在等 */
.chip {
  display: inline-block; padding: 1px 9px; border-radius: 20px;
  border: 1px solid var(--line); background: #fff; color: #555;
  font-size: 12px; line-height: 1.8; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.chip.warn { border-color: #b4700f; background: #fdf1dc; color: #b4700f; font-weight: 700; }
.chip.run  { border-color: #2f6fed; background: #dfeafe; color: #2f6fed; font-weight: 700; }
.chip.ok   { border-color: #1d7a44; background: #e3f4ea; color: #1d7a44; }
.chip.zero { opacity: .55; }

/* 等验证码的行要一眼看见——它是唯一需要人动手的状态 */
tr.r-needcode > td { background: #fdf1dc; }
tr.r-codebad > td  { background: #fce8e5; }

/* 验证码输入框。6 位数字，等宽才对得齐；填错时整框变红并自动全选 */
.codein {
  width: 78px; padding: 1px 5px; text-align: center; letter-spacing: .12em;
  font-family: ui-monospace, Consolas, monospace; font-variant-numeric: tabular-nums;
}
.codein.bad { border-color: #c0392b; background: #fce8e5; color: #c0392b; }
.code-hint { font-family: ui-monospace, Consolas, monospace; font-size: 11px; color: #b4700f; }
.code-done { color: #1d7a44; font-weight: 700; }
.code-none { color: #aab3bf; }

/* 操作列的按钮要挤得下，比通用 .btn.sm 再紧一点 */
.rowbtn { padding: 1px 8px; font-size: 12px; min-width: 62px; }

/* 作业答题助手：待扫码卡片区。每个等扫码的账号一张，几张同时摆着，
   谁扫谁的，不用等一个扫完再出下一个（原来的全屏遮罩一次只能显示一个）。 */
.qrcards { display: flex; flex-wrap: wrap; gap: 12px; }
.qrcard {
  width: 214px; padding: 10px 10px 8px; text-align: center;
  border: 1px solid #b4700f; border-radius: 6px; background: #fffaf0;
  transition: box-shadow .2s;
}
.qrcard.flash { box-shadow: 0 0 0 3px rgba(217, 119, 6, .45); }
.qrhead { font-weight: 700; font-size: 13px; word-break: break-all; }
.qrsub { font-size: 12px; color: #6b7280; margin: 2px 0 6px; word-break: break-all; }
.qrimg { display: block; width: 188px; height: 188px; margin: 0 auto; border: 1px solid var(--line); background: #fff; }
.qrleft { font-size: 12px; color: #b4700f; margin: 5px 0; font-variant-numeric: tabular-nums; }
.qrbtns { display: flex; gap: 6px; justify-content: center; }

/* 侧边栏角标：人在别的页面时，提示上海大学那边有账号在等验证码。
   不挡路（弹窗那套的唯一优点是全局可见，这里用角标补上） */
.nav-badge {
  display: inline-block; margin-left: 6px; min-width: 16px; padding: 0 5px;
  border-radius: 9px; background: #d97706; color: #fff;
  font-size: 11px; font-weight: 700; line-height: 16px; text-align: center;
  font-variant-numeric: tabular-nums;
}
