/* ===========================================================
   离线账号站 — 全局样式
   设计规范：黑白体系（核心色 #111 / #fff），无彩色主色，
            图标一律使用线性 SVG（stroke-width 1.8），不使用 emoji。
   =========================================================== */

:root {
  --ink: #111;
  --ink-2: #444;
  --ink-3: #8a8a8a;
  --ink-4: #b5b5b5;
  --line: #e6e6e6;
  --line-2: #f0f0f0;
  --bg: #ffffff;
  --bg-soft: #fafafa;
  --ok: #111;
  --warn: #8a6d00;
  --err: #b00020;
  --radius: 8px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", "PingFang SC", sans-serif;
  font-size: 15px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 20px; }

/* ---------------- 顶部导航 ---------------- */
.topbar {
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  position: sticky;
  top: 0;
  z-index: 50;
}
.topbar .wrap { display: flex; align-items: center; gap: 28px; min-height: 62px; }
.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 17px; letter-spacing: .2px; }
.brand svg { display: block; }
/* ---------------- 顶部导航（数据驱动，见 base.html 与 nav_service） ----------------
   ★ 2026-09-23：导航项改成后台可增删改，所以这里要能扛住「项变多」。
     · `flex-wrap: wrap` —— 项多了换行，而不是把右边那组按钮挤出屏幕；
     · 配套把 `.topbar .wrap` 的 `height` 改成 `min-height`（见上）：
       高度写死 62px 时，换行后的第二行会溢出顶栏。项少时视觉完全一样。
   ★ `min-height: 62px` = 跟顶栏一样高：配合 `.nav-item{ align-self:stretch }`，
     让下拉菜单的 `top:100%` 正好落在**顶栏下沿**（而不是"文字下方 14px"）。
     第一版就是锚在文字上，真浏览器一量：下拉从 y=49 开始、顶栏底在 y=63 ——
     白底下拉把顶栏那条下边线盖掉了一截。 */
.nav { display: flex; flex-wrap: wrap; align-items: stretch; gap: 22px; margin-left: 12px; font-size: 14.5px; min-height: 62px; }
.nav a { color: var(--ink-2); }
.nav a:hover { color: var(--ink); text-decoration: none; }
/* 平铺的一级链接也撑满顶栏高度并垂直居中（与 .nav-item 保持同一基线） */
.nav > a { display: flex; align-items: center; }
/* 一级项容器：撑满顶栏高度（下拉的定位锚点），内容垂直居中。
   ★ `align-items: stretch` 在 .nav 上、这里不再写 align-self ——
     实测 `align-self: stretch` 撑不起来（flex 行高按内容算，只有 24px）。 */
.nav-item { position: relative; display: flex; align-items: center; }
.nav-item > a { color: var(--ink-2); }
.nav-item > a:hover { color: var(--ink); text-decoration: none; }
/* ★ 纯展开器（自己不跳转，只用来挂二级）：不可点，但能聚焦 → 触屏点一下也能展开 */
.nav-label { color: var(--ink-2); cursor: default; outline: none; }
.nav-label:focus { color: var(--ink); }
/* ★ 二级下拉：纯 CSS 展开 —— `:hover` 管鼠标，`:focus-within` 管键盘与触屏，
   两件都写才不会有"手机上点不开"的坑。不写媒体查询（全站一致）。
   ★★ `margin-top: 0` 是**必须**的：一级项已经撑到顶栏下沿，两者相接
     ⇒ 鼠标从文字往下移动到下拉，中途没有"空隙"导致 hover 断掉、菜单闪退。 */
.nav-sub {
  position: absolute; left: 0; top: 100%; min-width: 156px;
  display: none; flex-direction: column; gap: 2px; padding: 8px;
  margin-top: 0; background: #fff; border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 12px 28px rgba(17, 17, 17, .12);
  z-index: 60;
}
.nav-item:hover .nav-sub, .nav-item:focus-within .nav-sub { display: flex; }
.nav-sub a { padding: 7px 12px; border-radius: 6px; white-space: nowrap; }
.nav-sub a:hover { background: var(--bg-soft); color: var(--ink); text-decoration: none; }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 14px; font-size: 14px; }
.topbar-right .who { color: var(--ink-3); }

/* ---------------- 按钮 ---------------- */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 16px; border: 1px solid var(--ink);
  background: var(--ink); color: #fff; border-radius: var(--radius);
  font-size: 14px; cursor: pointer; font-family: inherit;
  transition: opacity .15s ease;
}
.btn:hover { opacity: .82; text-decoration: none; }
.btn-ghost { background: #fff; color: var(--ink); }
.btn-ghost:hover { background: var(--bg-soft); }
.btn-sm { padding: 5px 11px; font-size: 13px; }
.btn-block { width: 100%; justify-content: center; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-danger { border-color: var(--err); color: var(--err); background: #fff; }
.btn-danger:hover { background: #fff5f5; }

/* ---------------- 卡片 / 区块 ---------------- */
.card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  padding: 20px;
}
.page-head { display: flex; align-items: center; margin: 26px 0 18px; gap: 14px; }
.page-head h1 { font-size: 20px; margin: 0; font-weight: 700; letter-spacing: .2px; }
.page-head .sub { color: var(--ink-3); font-size: 13.5px; }
.spacer { margin-left: auto; }

/* ---------------- 表单 ---------------- */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 13.5px; color: var(--ink-2); margin-bottom: 6px; }
.field .hint { font-size: 12.5px; color: var(--ink-3); margin-top: 5px; }
input[type=text], input[type=password], input[type=email], input[type=number],
input[type=search], select, textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--line);
  border-radius: var(--radius); font-size: 14px; font-family: inherit;
  background: #fff; color: var(--ink);
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--ink); }
textarea { min-height: 120px; resize: vertical; }
.form-row { display: flex; gap: 14px; }
.form-row > .field { flex: 1; }
.checkline { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.checkline input { width: auto; }

/* ---------------- 紧凑表单（后台编辑页专用）----------------
   ★ 2026-09-21 站长反馈「布局太分散、太多空白区域」后加。
   问题来源：每张 card 内边距 20px + 卡片间距 16px + 字段间距 16px，
   而表单又限宽 860px —— 宽屏上右侧一大片空、纵向也全是空气。
   这里把三者一起收：更大可用宽度、更小内边距、更小字段间距。
   ★ 只加类，不改全局 .card / .field 默认值，避免影响前台。 */
/* ★ 2026-09-21 二次反馈：「那些文本框根本就是多余的过长的。账号长度有那么长吗？」
   病根：行内字段一律 `flex:1` 平分整行 → 只有 11 个字符的 Steam 账号
   也被撑到 400px 宽，纯属虚假占位。
   改法：给字段分「宽度档位」，按**内容实际长度**收；短字段一行塞 3~4 个，
   行尾用 .f-fill 吸收剩余空间，既不虚长也不留大片空白。
   限宽同步 1160 → 960（字段都短了，再宽又是空白）。 */
.form-compact { max-width: 960px; }
.form-compact .card { padding: 14px 16px; }
.form-compact .card + .card { margin-top: 10px; }
.form-compact .field { margin-bottom: 10px; }
.form-compact .field:last-child { margin-bottom: 0; }
.form-compact .field label { font-size: 13px; margin-bottom: 4px; }
.form-compact .field .hint { font-size: 12px; margin-top: 3px; }
.form-compact input[type=text], .form-compact input[type=password],
.form-compact input[type=email], .form-compact input[type=number],
.form-compact select, .form-compact textarea { padding: 7px 10px; font-size: 13.5px; }
.form-compact textarea { min-height: 62px; }
.form-compact .form-row { gap: 10px 12px; flex-wrap: wrap; }
/* 两行及以上字段的行，与上一行保持同样的紧凑间距 */
.form-compact .form-row + .form-row { margin-top: 10px; }

/* ---------------- 字段宽度档位（按内容长度收，不再平分整行）----------------
   用之前先看一眼目标列宽 / 实际内容长度：
     f-xs   180px  Steam 账号(~11) / 账号密码 / 排序 / 取码上限
     f-sm   220px  取码渠道 / 状态 / 分类
     f-md   320px  绑定邮箱(~19) / POP3 / URL 标识 / AppID
     f-lg   440px  shared_secret(32) / identity_secret / device_id / 路径
     f-xl   640px  封面 URL / 视频地址 / 视频封面（长 URL，但不必通栏）
     f-fill 弹性   放行尾，吸收本行剩余空间（一行填满，不留空档）
     f-full 整行   简介 textarea 这类需要通栏的
   ★ 选择器写 `.form-compact .field.f-xx`（0,3,0），确保盖过全局 `.form-row > .field`(0,1,1)。 */
/* ★ flex-basis 只管 flex 子项；单独成行的 .field 不在 .form-row 里，
   靠它约束不住（会被 width:100% 撑满），所以 max-width 必须一起写。 */
.form-compact .field.f-xs { flex: 0 1 180px; max-width: 180px; }
.form-compact .field.f-sm { flex: 0 1 220px; max-width: 220px; }
.form-compact .field.f-md { flex: 0 1 320px; max-width: 320px; }
.form-compact .field.f-lg { flex: 0 1 440px; max-width: 440px; }
.form-compact .field.f-xl { flex: 0 1 640px; max-width: 640px; }
.form-compact .field.f-fill { flex: 1 1 200px; }
.form-compact .field.f-full { flex: 1 1 100%; max-width: 100%; }
/* 区块小标题：紧贴内容，不要大段留白 */
.form-compact .sec-h {
  font-weight: 600; font-size: 13.5px; color: var(--ink);
  padding-bottom: 8px; margin-bottom: 10px; border-bottom: 1px solid var(--line);
}
.form-compact .sec-h .muted { font-weight: 400; }
/* ★ 只读「取码方式」下拉（账号表单第 3 行右列）：
   显示账号**实际**走的取码通道（桌面令牌 / 微软 / 自建），人不可改。
   select 加 disabled 后浏览器默认会把文字变成灰色甚至半透明，看起来像"坏掉了"，
   这里显式还原成正常前景色 + 浅底，让它一眼看出是「值是显示出来的，不是让你选的」。 */
.form-compact select.ro-select:disabled {
  color: var(--ink); opacity: 1; background: var(--bg-soft);
  border-style: dashed; cursor: default;
}
/* 一键填充的提示位：空着就不占高度（原 min-height:18px 会凭空留一行空白），
   有内容时才与上方字段拉开间距。JS 会改 className，所以这里用 id 选择器。 */
.form-compact #fetch-msg:not(:empty) { margin-top: 8px; }
/* 提交按钮行：紧跟最后一张卡片 */
.form-actions { margin-top: 12px; display: flex; gap: 10px; align-items: center; }
/* 顶栏收紧（后台编辑页用，替代原来的内联 margin-top:0） */
.page-head-tight { margin: 0 0 14px; }

/* ---------------- 表格 ---------------- */
table.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
table.tbl th, table.tbl td {
  padding: 10px 12px; border-bottom: 1px solid var(--line-2); text-align: left; vertical-align: middle;
}
table.tbl th { color: var(--ink-3); font-weight: 500; font-size: 13px; background: var(--bg-soft); }
table.tbl tr:hover td { background: var(--bg-soft); }

/* ---------------- 标签 ---------------- */
.tag {
  display: inline-block; padding: 2px 9px; border: 1px solid var(--line);
  border-radius: 999px; font-size: 12px; color: var(--ink-2); background: #fff;
}
.tag-ink { background: var(--ink); color: #fff; border-color: var(--ink); }
.tag-mute { color: var(--ink-3); }

/* ---------------- 提示条 ---------------- */
.flash { padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 10px; font-size: 14px; background: var(--bg-soft); }
.flash-error { border-color: #f0c4cb; background: #fff6f7; color: var(--err); }
.flash-success { border-color: var(--line); background: var(--bg-soft); }
.flash-warning { border-color: #ece0bf; background: #fdfaf0; color: var(--warn); }

/* ---------------- 游戏卡片（首页三块小卡：只有主图 + 游戏名） ----------------
   ★★★ 2026-09-23 首页改成「三块小卡」（热门 / 必玩大作 / 全部游戏）。
     卡片尺寸不是拍的，是**量旧站量出来的**：
       旧站首页卡片实测 **6 列 / 175 × 82 / 列距 10**，175÷82 = **2.13** ——
       正好是 Steam header 图（460×215 = 2.1395）的比例，旧站卡片用的就是它。
       本站内容宽 1080（`.wrap` 1120 − 左右各 20）⇒ 6 列每张 **171.7 × 80.2**。

   ★★ 卡里只有两样东西（爹定：只保留**主图 + 游戏名**），且**两种形态名字都要出**：
     · 有封面 → 图铺满 + **底部渐变压字**（`.nm` 绝对定位贴底、白字 + 黑→透明渐变垫底）
       ★ 2026-09-23 爹定的「方案 B」，起因：Steam 资料补全后**中文名不见了**
       （header 图上只有英文 logo）——爹：「那这就成了有资料的，就没有游戏名了啊」。
     · 没封面 → 浅灰渐变块 + 名字**居中**（线上绝大多数游戏还没采到封面，
                空格子必须自带信息、自己能站住）
   ★ 类名由模板的 Jinja 分支给（`{% if not game.cover %} noimg{% endif %}`），
     **不用 CSS `:has()`** —— 老浏览器同样正确。

   ★ 已删：旧大卡规则 `.gcard` / `.gcard .cover` / `.gcard .cover img` /
     `.gcard .scrim` / `.gcard .nm` / `.gcard .rule` / `.gcard .cover.has-img .nm` /
     `.gcard:hover .cover` / `.gcard:hover .cover img` 共 10 行 ——
     首页换成 `.gcard2` 之后全项目零引用（已 grep 确认），
     留着只会误导后来人（与 2026-09-22 删 `.body/.title/.desc` 同一理由）。
   ★ `.grid` **保留**：`pay/index.html` 还在用它。 */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 22px; }

/* ============ 公告栏（首页顶部，单条全文） ============
   ★ 2026-09-23 爹：「然后现在网站没有公告栏。做个公告，前台公告栏，后台要有对应的编辑栏。」
     两处产品决策（爹选的）：位置 = **首页顶部**（页头下方、搜索上方）、
     形态 = **单条全文**（后台只维护一条，前台把全文展开显示）。

   ★ 配色走**黑白体系**（爹 2026-09-04 定：核心是黑与白，不以彩色元素为核心）——
     视觉重量靠「左侧一道粗黑边 + 黑底白字的小标签」撑，
     **不引入任何色相**（不跟风用蓝/紫提示条）。
   ★ `.notice-body` 用 `white-space: pre-wrap` 还原换行：正文是**纯文本**
     （服务层已把 `\r\n` 归一成 `\n`），换行靠 CSS 还、不靠 `<br>`。
   ★ 结构在 `templates/_notice.html` —— **前台首页与后台「公告管理」的预览共用同一份**，
     从结构上杜绝"后台预览与前台不一致"。 */
.notice {
  border: 1px solid var(--line);
  border-left: 4px solid var(--ink);   /* ★ 黑白体系里最"重"的强调 */
  border-radius: var(--radius);
  background: var(--bg-soft);
  padding: 14px 18px 16px;
  margin: 0 0 26px;
}
.notice-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 9px; flex-wrap: wrap; }
.notice-tag {
  flex: none; background: var(--ink); color: #fff;
  font-size: 11.5px; font-weight: 600; letter-spacing: .06em; line-height: 1.5;
  padding: 2px 8px; border-radius: 999px;
}
/* ★ `min-width:0` + `overflow-wrap`：长标题必须能收缩换行，不能把卡片撑破 */
.notice-title {
  margin: 0; min-width: 0; font-size: 15.5px; font-weight: 700;
  color: var(--ink); line-height: 1.4; overflow-wrap: anywhere;
}
.notice-date {
  margin-left: auto; flex: none; white-space: nowrap;
  font-size: 12.5px; color: var(--ink-3);
}
.notice-body {
  font-size: 13.5px; line-height: 1.75; color: var(--ink-2);
  white-space: pre-wrap;                 /* ★ 换行原样保留（纯文本，回车即换行） */
  word-break: break-word; overflow-wrap: anywhere;   /* 长串不撑破卡片 */
}

/* ---- 三块的块头 ---- */
.hblk { margin-bottom: 34px; }
.hblk-head { display: flex; align-items: baseline; gap: 11px; margin-bottom: 11px; }
.hblk-head h2 { font-size: 16px; margin: 0; font-weight: 700; letter-spacing: .3px; }
/* ★ 2026-09-23 爹定「不要显示数量」→ `.hblk-head .cnt` 已删除（页头的 `.sub` 同批去掉）。
   `.sub` 本身留着 —— 会员中心 / 后台等 8 处还在用。 */
.hblk-head .note { font-size: 12px; color: var(--ink-4); margin-left: auto; }

/* ---- 小卡网格：桌面 6 列（1080 内容宽 → 每张 171.7），窄屏自动减列 ---- */
.grid-sm { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px 10px; }
.gcard2 {
  position: relative; display: block; aspect-ratio: 460 / 215;
  border-radius: 6px; overflow: hidden;
  background: linear-gradient(160deg, #f4f4f6 0%, #e9e9ee 100%);
  border: 1px solid var(--line);
  transition: box-shadow .18s ease, border-color .18s ease, opacity .3s ease;
}
.gcard2 img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- 卡片上的游戏名：两种形态都渲染（2026-09-23 爹定「方案 B · 底部渐变压字」）----
   ★ 为什么有封面也要压名字：Steam header 图上只有**英文 logo**，
     Steam 资料补全后中文名就没了（爹：「那这就成了有资料的，就没有游戏名了啊」）。
   ★ 渐变垫底（黑 → 透明）保证**任何图**上白字都读得清 —— 比"整块半透明蒙版"
     保留更多图片观感，比"纯阴影"更稳（浅色图上不掉）。 */
.gcard2 .nm {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 16px 6px 4px;
  background: linear-gradient(to top,
              rgba(0, 0, 0, .82) 0%, rgba(0, 0, 0, .55) 45%, rgba(0, 0, 0, 0) 100%);
  color: #fff; font-size: 12px; font-weight: 600; line-height: 1.25;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 没封面：名字**居中**在浅灰块里（深字、静态定位、去掉渐变与阴影）——
   线上绝大多数游戏还没采到封面，空格子必须自带信息、自己能站住。 */
.gcard2.noimg {
  display: flex; align-items: center; justify-content: center;
  padding: 0 10px; text-align: center;
}
.gcard2.noimg .nm {
  position: static; padding: 0; background: none; text-shadow: none;
  color: var(--ink-2); font-size: 12.5px; line-height: 1.35;
  white-space: normal; text-overflow: clip;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.gcard2:hover { border-color: var(--ink-4); box-shadow: 0 8px 20px rgba(17, 17, 17, .18); }
/* ★★ 轮播池的「收起」必须用**自定义 class**：
   浏览器给 `[hidden]` 的 `display:none` 属于 UA 样式，会被上面
   `.gcard2{display:block}` 直接盖掉 → 整池几十张**全部渲染**出来
   （真机实测踩过，页面当场高 11 行）。`.off{display:none}` 优先级明确。 */
.gcard2.off { display: none; }
/* 换批时的整块淡入淡出（`.fading` 由 home/index.html 的脚本加/去） */
.grid-sm.fading .gcard2 { opacity: 0; }

/* ---------------- 账号展示 ---------------- */
.cred { border: 1px dashed var(--ink-4); border-radius: var(--radius); padding: 16px; background: var(--bg-soft); }
.cred-row { display: flex; align-items: center; gap: 12px; padding: 7px 0; font-size: 14.5px; }
.cred-row .k { width: 78px; color: var(--ink-3); flex: none; }
.cred-row .v { font-family: ui-monospace, Consolas, monospace; font-size: 15px; letter-spacing: .4px; word-break: break-all; }

/* ★★ 2026-09-25 爹定：「账号密码展开后，账号和密码后边需要单独放一个复制按钮」
   —— 参考样式里爹选了**方案 D**（真浏览器实测过）：
   · 值 `flex:1` 把按钮**推到行末** ⇒ 两行按钮**竖着对齐**（实测差 0px；方案 A 差 78px）
   · 按钮 `min-width:64px` + 文字居中 ⇒ 点「复制」变「已复制」时（50→63px）
     **按钮宽度与位置一个像素都不动**（实测 64→64、x 不变）
   ★ 用**独立类名 `cred-row--copy`** 限定，不改上面既有的 `.cred-row` / `.v` ⇒ 零外溢：
     将来别处若复用 `.cred-row` 而不带这个类，布局与现在完全一样。
   ★ `min-width:64px` 是按实测「已复制」= 63px 定的（够兜住 + 只多 1px）。 */
.cred-row--copy .v { flex: 1 1 auto; min-width: 0; }
.cred-row--copy .js-copy { flex: none; min-width: 64px; justify-content: center; }
.codepanel { margin-top: 14px; padding: 16px; border: 1px solid var(--ink); border-radius: var(--radius); text-align: center; }
.codepanel .code { font-family: ui-monospace, Consolas, monospace; font-size: 30px; letter-spacing: 7px; font-weight: 700; margin: 8px 0; }

/* ---------------- 账号领取：一个游戏可能有多个账号（★ 2026-09-22）----------------
   后台录入 N 个账号，前台就铺 N 个 .acc-item，每块**各自独立**地「查看账号密码 /
   获取登录验证码」（块内按钮用 .js-* 类名由脚本绑定，不再用全局 id）。
   块标题只写「账号 N」—— 真实账号名/密码/邮箱一律不写进 HTML（防看源码盗号）。 */
.acc-item { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; margin-bottom: 12px; }
.acc-item:last-child { margin-bottom: 0; }
.acc-item-h { font-size: 13px; color: var(--ink-3); letter-spacing: .5px; margin-bottom: 10px; }
.acc-item .cred { padding: 12px; }
.acc-item .cred-row .k { width: 56px; }
.mono { font-family: ui-monospace, Consolas, monospace; }

/* ---------------- 分页 ---------------- */
.pager { display: flex; gap: 8px; justify-content: center; margin: 26px 0; font-size: 14px; }
.pager a, .pager span { padding: 6px 12px; border: 1px solid var(--line); border-radius: 6px; }
.pager .cur { background: var(--ink); color: #fff; border-color: var(--ink); }

/* ---------------- 后台布局（独立于前台骨架） ---------------- */
/* 后台由 admin/_shell.html 提供裸骨架：无前台 topbar / nav / footer */

.admin-body { background: var(--bg); }
.admin-root { min-height: 100vh; }

.admin-flash-wrap { padding: 16px 26px 0; }

.admin-shell { display: flex; min-height: 100vh; }
.admin-side { width: 190px; flex: none; border-right: 1px solid var(--line); padding: 18px 0; }
.admin-side a { display: block; padding: 9px 20px; color: var(--ink-2); font-size: 14px; }
.admin-side a:hover { background: var(--bg-soft); text-decoration: none; color: var(--ink); }
.admin-side a.on { color: var(--ink); font-weight: 600; border-left: 2px solid var(--ink); padding-left: 18px; }
.admin-side-brand { padding: 0 20px 14px; margin-bottom: 10px; border-bottom: 1px solid var(--line); }
.admin-side-brand-t { display: block; font-size: 15px; font-weight: 700; letter-spacing: -.2px; }
.admin-side-brand-s { display: block; color: var(--ink-3); font-size: 12.5px; margin-top: 2px; }
.admin-side-foot { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.admin-side-foot a { color: var(--ink-3); font-size: 13px; }
.admin-side-foot a:hover { color: var(--ink); }
.admin-main { flex: 1; padding: 24px 26px; min-width: 0; }

/* ================= 后台视觉层次 =================
   ★ 2026-09-21 爹反馈：「颜色不怎么喜欢，列表不清晰，白茫茫一片」
     「太长了没用，建议居中显示」「所有东西都是白底，按钮也是白底黑圈」
   病根：页底白 + 卡片白 + 表格白 + 标签白 + 次要按钮白底黑边 → 全白，没有层次。

   处方（**全部限定后台作用域，前台一点不受影响**）：
     黑侧栏  +  浅灰页底  +  白卡片 / 白表格  =  三层分明
   仍然是纯黑白体系（#111 / #f4f4f5 / #fff），不引入任何彩色。
   ⚠ 本块必须放在上面基础样式之后 —— 同特异性靠后生效。 */

/* 1) 页底改浅灰，白卡片才有"浮起来"的对比 */
.admin-body { background: #f4f4f5; }

/* 2) 内容列居中：不再「有多宽铺多宽」 */
.admin-wrap { max-width: 1240px; margin: 0 auto; }

/* 3) 侧栏黑底反白，激活项白底黑字 —— 导航一眼看清在哪一页 */
.admin-side {
  width: 190px; flex: none; padding: 18px 0;
  background: #111; border-right: none;
}
.admin-side-brand { border-bottom: 1px solid #2b2b2b; }
.admin-side-brand-t { color: #fff; }
.admin-side-brand-s { color: #8c8c8c; }
.admin-side a { display: block; padding: 9px 20px; color: #b3b3b3; font-size: 14px; }
.admin-side a:hover { background: #1f1f1f; color: #fff; text-decoration: none; }
.admin-side a.on {
  background: #fff; color: #111; font-weight: 600;
  border-left: none; padding-left: 20px;
}
.admin-side-foot { margin-top: 18px; padding-top: 14px; border-top: 1px solid #2b2b2b; }
.admin-side-foot a { color: #8c8c8c; }
.admin-side-foot a:hover { color: #fff; }

/* 4) 卡片 / 统计块：白底 + 细边 + 极轻投影 */
.admin-wrap .card { background: #fff; border: 1px solid #e8e8ec; box-shadow: 0 1px 2px rgba(17, 17, 17, .05); }
.admin-wrap .stat { background: #fff; border: 1px solid #e8e8ec; }

/* 5) 次要按钮：不再是「白底黑圈」，改浅灰底 + 淡边 */
.admin-wrap .btn-ghost { background: #f1f1f3; border-color: #e2e2e6; color: #111; }
.admin-wrap .btn-ghost:hover { background: #e4e4e8; opacity: 1; }
.admin-wrap .btn-danger { background: #fff; }

/* 6) 列表：白底 + 黑色顶线 + 实心表头 + 斑马纹 + 悬停高亮 */
.admin-wrap table.tbl {
  background: #fff; border: 1px solid #e8e8ec; border-top: 2px solid #111; font-size: 13.5px;
}
.admin-wrap table.tbl th {
  background: #f4f4f5; color: #111; font-weight: 600; font-size: 12.5px;
  letter-spacing: .2px; border-bottom: 1px solid #e0e0e5;
}
.admin-wrap table.tbl td { border-bottom: 1px solid #f0f0f3; }
.admin-wrap table.tbl tbody tr:nth-child(even) td { background: #fafafb; }
.admin-wrap table.tbl tbody tr:hover td { background: #f0f0f4; }
.admin-wrap table.tbl tbody tr:last-child td { border-bottom: none; }

/* 7) 标签：白底在白表格上看不清 → 统一浅灰底 */
.admin-wrap .tag { background: #f1f1f3; border-color: #e2e2e6; color: #444; }
.admin-wrap .tag-ink { background: #111; border-color: #111; color: #fff; }
.admin-wrap .tag-mute { background: #fff; color: #8a8a8a; }

/* 8) 分页 */
.admin-wrap .pager a, .admin-wrap .pager span { background: #fff; border-color: #e2e2e6; }
.admin-wrap .pager a:hover { border-color: #111; text-decoration: none; }
.admin-wrap .pager .cur { background: #111; color: #fff; border-color: #111; }

/* 9) 搜索框：在灰底页面上保持清晰白底 */
.admin-wrap input[type=search] { background: #fff; border-color: #e2e2e6; }

/* 10) 内容区顶栏内联 margin-top:0 已被 page-head-tight 取代，这里兜底 */
.admin-wrap .page-head { margin-top: 0; }

/* ================= 游戏编辑页：左资料 / 右账号 =================
   ★ 2026-09-21 爹定：「添加账号页面直接就纳入到文章编辑里。编辑游戏左边是资料右边是账号。
     账号紧凑一些布局就行了。不要弄两个入口。」
   两栏用 Grid；窄屏自动堆成上下 —— **不用 JS，功能不依赖 JS**。 */
.edit-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 470px);
  gap: 16px;
  align-items: start;
}
/* 侧栏里不需要 .form-compact 的 960px 限宽（那是给整页宽的编辑页用的） */
.edit-side .form-compact { max-width: 100%; }
.edit-side .card + .card { margin-top: 10px; }

/* ---------------- 右栏账号块（每个账号一张表单，进来就能改） ----------------
   ★ 2026-09-21 爹定：去掉「账号列表 + 点『编辑』才出表单」的两段式 ——
     N 个账号 = N 张表单平铺，最下面一个「＋ 添加新账号」。
     实现见 templates/admin/game_edit.html 右栏注释。
   ★ 旧的 .acclist-wrap / .acclist-sub / table.tbl.tbl-compact / tr.on 已随列表一起删除。 */
.acc-block { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-2); }
/* 紧跟卡片大标题的第一块：不要再画线，否则和标题的下边框连成双线 */
.sec-h + .acc-block { margin-top: 0; padding-top: 0; border-top: none; }
/* 注：原来的 .acc-head（账号名 + 取码标签那一行）已删 —— 账号名在表单第 1 行输入框里
   已有，取码通道由第 3 行「取码方式」只读显示，头部纯属重复（2026-09-21 爹定）。 */

/* 「＋ 添加新账号」：原生 <details>，收起不占地方、零 JS 依赖 */
details.acc-add { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-2); }
.sec-h + details.acc-add { margin-top: 0; padding-top: 0; border-top: none; }
details.acc-add > summary {
  cursor: pointer; font-weight: 600; font-size: 12.5px; color: var(--ink-3);
  list-style: none; user-select: none;
}
details.acc-add > summary::-webkit-details-marker { display: none; }
details.acc-add > summary::marker { content: ""; }
details.acc-add[open] > summary { margin-bottom: 11px; }

/* 右栏表单的小标题（账号表单分三段：取码 / 令牌 / 限制与状态） */
.form-compact .form-sub-h {
  font-weight: 600; font-size: 12.5px; color: var(--ink-3); letter-spacing: .2px;
  padding: 13px 0 7px; margin: 0 0 9px; border-top: 1px solid var(--line-2);
}
.form-compact .form-sub-h .muted { font-weight: 400; }
/* 紧跟卡片大标题后的第一个小标题：不要再画线，否则和标题的下边框连成双线 */
.form-compact .sec-h + .form-sub-h { border-top: none; padding-top: 0; }

/* 右栏放不下时落成单列（470px 侧栏撑不住两栏了） */
@media (max-width: 1100px) {
  .edit-split { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------- 统计块 ---------------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; }
.stat { border: 1px solid var(--line); border-radius: var(--radius); padding: 15px 16px; }
.stat .n { font-size: 25px; font-weight: 700; letter-spacing: -.5px; }
.stat .l { color: var(--ink-3); font-size: 13px; margin-top: 3px; }

/* ---------------- 其他 ---------------- */
.empty { text-align: center; color: var(--ink-3); padding: 46px 0; font-size: 14px; }
.muted { color: var(--ink-3); }
.small { font-size: 13px; }
hr.sep { border: none; border-top: 1px solid var(--line); margin: 20px 0; }
footer.site { border-top: 1px solid var(--line); margin-top: 50px; padding: 22px 0; color: var(--ink-3); font-size: 13px; }
/* ★ 2026-09-26 备案号悬挂（爹：「避免服务器被封」）。
   页脚**只留备案号**（站长名 / slogan /「演示环境」文案一律不要）⇒ 这里负责**水平居中**。
   刻意**不改链接颜色** —— 全局 a 是 --ink(#111)，比页脚灰字(--ink-3)醒目，
   正合"底部显著位置"的合规要求（要调只改这一处，不用动模板）。 */
.site-icp { text-align: center; }
.loading { color: var(--ink-3); font-size: 13.5px; }

/* ---------------- 详情页两栏 ---------------- */
.detail-cols { display: grid; grid-template-columns: 1fr 340px; gap: 24px; align-items: start; }

/* ---------------- 游戏详情：封面 / 一句话简介 / 自动播放视频 ---------------- */
/* ★ 2026-09-21 站长收敛：详情页只留这三样。
   已删掉 .game-meta（资料条）与 .game-content（详细介绍正文）的样式 —— 无人再引用。
   将来若要把资料条加回来，从这里恢复即可。 */
.game-hero { width: 100%; border-radius: var(--radius); margin-bottom: 14px; display: block; }

.game-summary { font-size: 15.5px; margin: 0 0 14px; }

/* 视频 */
.video-wrap { position: relative; background: #000; border-radius: var(--radius); overflow: hidden; }
.video-wrap video { width: 100%; display: block; max-height: 480px; background: #000; }
.video-fallback { padding: 16px; color: #ddd; font-size: 13.5px; text-align: center; background: #111; }
.video-fallback a { color: #fff; text-decoration: underline; }

/* ---------------- 后台独立登录页 ---------------- */
/* 与前台登录视觉区分：深色卡片 + 居中，让人一眼知道这是管理入口 */
.admin-login {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 52px 20px;
  background: var(--bg-soft);
}
.admin-login-card {
  width: 100%; max-width: 400px;
  background: var(--ink); color: #fff;
  border-radius: 12px;
  padding: 34px 32px 26px;
}
.admin-login-brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 700; font-size: 15px; letter-spacing: .2px;
  color: #fff; margin-bottom: 22px;
}
.admin-login-card h1 { font-size: 22px; margin: 0 0 6px; letter-spacing: -.2px; color: #fff; }
.admin-login-tip { color: #9a9a9a; font-size: 13.5px; margin: 0 0 24px; }

/* 深色卡片内的表单控件反转配色 */
.admin-login-card .field label { color: #c8c8c8; }
.admin-login-card .field input {
  background: #1c1c1c; border-color: #333; color: #fff;
}
.admin-login-card .field input:focus {
  border-color: #666; outline: none; background: #222;
}
.admin-login-card .field input::placeholder { color: #666; }
.admin-login-card .checkline label { color: #c8c8c8; }
.admin-login-card .btn {
  background: #fff; color: var(--ink); border-color: #fff;
}
.admin-login-card .btn:hover { background: #e8e8e8; border-color: #e8e8e8; }

@media (max-width: 860px) {
  .detail-cols { grid-template-columns: 1fr; }
  .admin-shell { flex-direction: column; }
  .admin-side { width: 100%; border-right: none; border-bottom: 1px solid var(--line); display: flex; align-items: center; overflow-x: auto; padding: 0; }
  .admin-side a { padding: 12px 14px; white-space: nowrap; }
  .admin-side a.on { border-left: none; border-bottom: 2px solid var(--ink); padding-left: 14px; }
  .admin-side-brand { flex: none; padding: 0 14px; margin: 0; border-bottom: none; }
  .admin-side-brand-t { font-size: 13.5px; }
  .admin-side-brand-s { display: none; }
  .admin-side-foot { margin: 0; padding: 0; border-top: none; }
  .admin-main { padding: 18px 16px; }
  .admin-flash-wrap { padding: 14px 16px 0; }
  .admin-login { padding: 32px 16px; }
  .admin-login-card { padding: 28px 22px 20px; }

  /* ========================================================================
     ★★★ 2026-09-26 移动端修复：顶栏 + 页头在窄屏必须「换行 + 不许被压缩」
     ------------------------------------------------------------------------
     爹报：「手机尺寸下，同步按钮不显示，或者被挡住。」

     根因（已实测确认，不是推测）：`.topbar .wrap` 与 `.page-head` 都是 `display: flex`
     却**都没写 `flex-wrap`** ⇒ 默认 `nowrap`。窄屏总宽远超视口时，flex 只能**压缩**子项
     （`flex-shrink` 默认 1）：
       · `.brand` 文字被压成**竖排**（"离线账号站" 一个字一行）；
       · `.page-head` 的 3 个按钮被压到 **37px** 宽（`.btn-sm` 左右 padding 就占 22px）
         ⇒ 按钮文字**溢出按钮外** —— 看起来就是"不显示 / 被挡住"；
       · `.topbar-right` 的「退出」被顶出视口（390px 实测 `scrollWidth=436`）。
     ⇒ 修法三件套，**缺一不可**：允许换行 + 禁止压缩 + 长文本省略号。
       （只加 `flex-wrap` 不够 —— 子项仍会被压；只加 `flex:0 0 auto` 也不够 —— 会直接溢出。）
     ======================================================================== */

  /* ---- 顶栏：品牌 + 右侧入口占第一行，导航整行换到第二行 ---- */
  .topbar .wrap { flex-wrap: wrap; gap: 8px 14px; padding-top: 8px; padding-bottom: 8px; }
  .brand { flex: 0 0 auto; white-space: nowrap; }
  .nav {
    flex: 1 1 100%; order: 3;            /* 独占一行，排在最后 */
    flex-wrap: wrap; gap: 10px 18px;
    margin-left: 0; min-height: 0;
  }
  .nav > a, .nav-item > a, .nav-label { white-space: nowrap; }
  .topbar-right { flex: 0 1 auto; margin-left: auto; gap: 8px; flex-wrap: nowrap; }
  /* ★ 用户名可能是长邮箱 ⇒ 必须能收缩 + 省略号，否则它会把整行撑破 */
  .topbar-right .who {
    min-width: 0; max-width: 110px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* ---- 页头：标题+副标题一行，按钮整组换到下一行，且按钮不许被压缩 ---- */
  .page-head { flex-wrap: wrap; row-gap: 10px; }
  .page-head .sub {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* `.spacer` 占满整行 ⇒ 后面那组按钮被**强制**换到第二行（不靠猜剩余宽度） */
  .page-head .spacer { flex: 0 0 100%; height: 0; margin: 0; }
  .page-head .btn { flex: 0 0 auto; white-space: nowrap; }
}

/* ============================================================================
   滑动拼图验证码（2026-09-23）
   ★ 与 templates/_captcha.html + static/js/captcha.js 配套，三件一套。
   ★★ 几何约束（别凭直觉改）：
      .cap-stage 与 .cap-track 目标是**同宽**，但**不要求像素级等宽** ——
      .cap-track 有 1px 边框，它的 clientWidth 天然比 stage 小 2px，这是无害的。
      真正的不变量是：「stage 内容宽 / scale == 320」+「t=0/1 两端拼图与滑块都对齐」。
      ★ 所以：**不要给 .cap-track 或 .cap-thumb 加 margin / padding**，
        那会改变滑块可移动距离与视觉位置的关系；加边框是安全的。
      详见 captcha.js 顶部「坐标换算」长注释。
   ★ 配色沿用全站黑白体系；后台深色卡片下用 .admin-login-card 的覆盖规则反转。
   ============================================================================ */
.cap {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-soft);
  padding: 12px;
  margin-bottom: 16px;
}
.cap-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.cap-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.cap-tip { font-size: 12.5px; color: var(--ink-3); }
.cap-refresh {
  margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; font-size: 12.5px; color: var(--ink-2);
  background: #fff; border: 1px solid var(--line); border-radius: 6px;
  cursor: pointer; font-family: inherit;
}
.cap-refresh:hover { border-color: var(--ink-4); }

.cap-stage {
  position: relative; width: 100%; min-height: 84px;
  border-radius: 6px; background: #ececec; overflow: hidden; line-height: 0;
}
.cap-bg, .cap-piece { position: absolute; left: 0; top: 0; display: none; }
.cap-bg.on, .cap-piece.on { display: block; }
.cap-piece { pointer-events: none; }
.cap-loading {
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: var(--ink-3); line-height: 1.6;
}

.cap-track {
  position: relative; width: 100%; height: 40px; margin-top: 10px;
  background: #fff; border: 1px solid var(--line); border-radius: 6px; overflow: hidden;
}
.cap-fill { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: var(--line-2); }
.cap-thumb {
  position: absolute; left: 0; top: 0; width: 44px; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: var(--ink); color: #fff; border-radius: 5px;
  cursor: grab; touch-action: none; user-select: none; outline: none;
}
.cap-thumb:focus-visible { box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--ink-4); }
.cap.dragging .cap-thumb { cursor: grabbing; }
.cap-hint {
  position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%);
  text-align: center; font-size: 12.5px; color: var(--ink-4);
  pointer-events: none; line-height: 1.2;
}
.cap-msg { font-size: 12.5px; color: var(--ink-3); margin-top: 8px; min-height: 18px; }
.cap-msg.err { color: var(--err); }

.cap-blocked {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 13px; margin-bottom: 16px;
  border: 1px solid #f0d0d5; background: #fff5f6; color: var(--err);
  border-radius: var(--radius); font-size: 13.5px; line-height: 1.5;
}
.cap-blocked svg { flex: none; margin-top: 3px; }
.cap-blocked strong { display: block; font-weight: 600; }
.cap-blocked span { display: block; color: var(--ink-2); font-size: 12.5px; }

/* ---- 后台深色登录卡片下的反转 ---- */
.admin-login-card .cap { background: #161616; border-color: #2a2a2a; }
.admin-login-card .cap-title { color: #eaeaea; }
.admin-login-card .cap-tip,
.admin-login-card .cap-hint,
.admin-login-card .cap-msg { color: #8f8f8f; }
.admin-login-card .cap-msg.err { color: #ff8f8f; }
.admin-login-card .cap-stage { background: #1c1c1c; }
.admin-login-card .cap-track { background: #1c1c1c; border-color: #333; }
.admin-login-card .cap-fill { background: #2b2b2b; }
.admin-login-card .cap-thumb { background: #fff; color: var(--ink); }
.admin-login-card .cap-refresh { background: #1c1c1c; border-color: #333; color: #c8c8c8; }
.admin-login-card .cap-refresh:hover { border-color: #666; }
.admin-login-card .cap-blocked {
  background: #2a1518; border-color: #4a2226; color: #ff9a9a;
}
.admin-login-card .cap-blocked span { color: #c0c0c0; }
