/* 小花猫战绩查询 —— 全站样式（唯一真源）
   ⚠⚠⚴⚴ **别把 CSS 再搬回模板**: Jinja 先于 CSS 解析, 注释里的定界符
   会让**整个页面 500**, 而且这种错法离病因很远(报错行指向一句中文)。
   ⚠⚠ 页面级样式**也**在这里 —— 不要图省事塞回各自模板的 js 块:
   那里在 `#tzone` 之外虽能活过换页, 但**职责乱**; 而 head 块里那份
   会被 pjax 连 `#tzone` 一起换掉 ⇒ 换页时旧样式整个消失、新样式整个加进来。
 */

/* ═══════════════════════════════════════════════════════════════
   来自 templates/base.html
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* ⚠⚠⚠ 2026-10-15 主人:「点下去一个矩形阴影」—— 那是**安卓默认的点击高亮**
   (`-webkit-tap-highlight-color` 默认画一个半透明**方块**; 而我们的胶囊是圆的
   ⇒ 看着就是「矩形阴影」)。⇒ **关掉它**, 换成我们自己的按压反馈(缩一点点+变暗)。
   ⚠ 顺带把 `outline` 只留给键盘(`:focus-visible`) —— 点按不再画框, 键盘照样可达。 */
html{-webkit-tap-highlight-color:transparent}
:focus{outline:none}
:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:8px}
/* ── 微交互: 胶囊/按钮统一过渡 + 按下去「压一下」 ── */
.pill,button,a.pill,.unlock,.tsend,.tnk,.tcard,summary{
  transition:background-color .16s ease, border-color .16s ease, color .16s ease,
             transform .12s ease, box-shadow .16s ease, opacity .16s ease}
.pill:active,button:active,a.pill:active,.unlock:active,.tsend:active,.tnk:active{
  transform:scale(.96)}
.pill:hover{border-color:#3a4356}
/* 悬停: 只在**真有指针**的设备上做(手机上 `:hover` 会粘住) */
@media (hover:hover){
  #main .tcard:hover{transform:translateY(-1px);box-shadow:0 6px 20px rgba(0,0,0,.3)}
  .unlock:hover,button:hover{filter:brightness(1.08)}
  /* ⚠ 只给**默认色**胶囊加悬停底色; `.warn/.ok/.dim/.copy` 有各自语义色, 别覆盖 */
  .pill:not(.warn):not(.ok):not(.dim):not(.copy):not(.nav):hover{background:#232833}
}
@media (prefers-reduced-motion: no-preference){
  /* ═══ 入场动效(用 animate.css 的 keyframes, 延迟/时长我们自己控) ═══ */
  #tzone{animation:fadeInDown .3s cubic-bezier(.2,.8,.3,1) both}
  #main .bats,#main .scroll,#main .msg,#main .prose,#main .bat{
    animation:fadeIn .26s cubic-bezier(.2,.8,.3,1) both}
  #main .pager{animation:fadeIn .3s cubic-bezier(.2,.8,.3,1) .08s both}
  /* 卡片逐张进场(落地页/名单卡片; 数量有限, 值得交错) */
  #main .tcard{animation:fadeInUp .3s cubic-bezier(.2,.8,.3,1) both}
  #main .tcard:nth-child(2){animation-delay:.03s}
  #main .tcard:nth-child(3){animation-delay:.06s}
  #main .tcard:nth-child(4){animation-delay:.09s}
  #main .tcard:nth-child(n+5){animation-delay:.12s}
}
/* ⚠ 目标: **一屏显示全** —— 手机上不出现整页滚动条。
   做法: 100dvh 弹性布局 + 表格区自己滚(flex:1) + 行高压到 ~26px。
   ⚠ 用 dvh 不是 vh: 手机浏览器地址栏收放时 vh 会跳, dvh 才跟可视高度同步。 */
/* ⚠⚠⚠ 局部换页的两条「体感」配套(2026-10-09 主人: 「不丝滑」)
   ──────────────────────────────────────────────────────────────
   ① `touch-action:manipulation` —— 去掉移动端浏览器**双击缩放的 300ms
      等待**。⚠ 这是「点下去顿一下」的最大来源之一, 而它和服务器快慢**无关**,
      ⚠ 光优化后端根本消不掉。
   ② `#main[aria-busy]` —— 局部换页时给一点**极淡**的反馈。
      ⚠⚠⚠ **刻意不做「加载中」转圈/骨架屏**: 旧内容**留在原地不动**
      (页面上还有东西可看), 只加一点点透明度 ⇒ 感知延迟几乎为 0。
      ⚠ 反面做法(先清空再加载)会让屏幕**闪一下白**, 那比慢更让人烦躁。 */
html{-webkit-text-size-adjust:100%}
#main[aria-busy="true"]{opacity:.72;transition:opacity .12s ease-out}
html.pjax-busy #main{opacity:.82}
html.pjax-busy #main[aria-busy="true"]{opacity:.6}
/* ═══ 换页「入场」动效(2026-10-11 主人: 「页面间的跳转还是太硬」)
     ⚠⚠⚠ 原先**只有淡出、没有入场** —— 新内容 `replaceChild` 瞬间落位,
       视觉上是「啪」地一下换掉 ⇒ 这就是「硬」的主因。
     ⚠⚠⚠ **`animationend` 不是可选项**: 动效结束后若不摘掉 `enter` 类,
       下次换页**同一元素不会重放**(animation 只在类**首次**应用时跑一次)
       ⇒ 第二次开始又变回瞬切。⚠ 这正是「动效只第一次有效」的成因。
     ⚠ 动画 22s 时长写错会让内容**长时间半透明**(看着像卡住) —— 见下方 @keyframes。
     ⚠ 位移只有 6px: 再大就会觉得「页面在飘」, 且和骨架屏高度对不上。 */
@keyframes mainIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
#main.enter{animation:mainIn .22s ease-out both}
/* ⚠⚠ **新页面的入场优先于淡出**: aria-busy 的淡出是「旧页变灰」,
   入场是「新页浮现」。⚠ `both` 保证首帧就是 opacity:0(否则会先闪一下全亮再淡入)。 */
@media (prefers-reduced-motion:reduce){
  #main[aria-busy="true"]{transition:none}
  #main.enter{animation:none}
}

/* ── 骨架屏(2026-10-09 主人要)────────────────────────────────────────
   ⚠⚠⚠ **延迟 180ms 才出现**(见 static/pjax.js 里那段说明): 局域网
   70~210ms 的页面**根本不会看到它**, 只有公网(colo=LAX, TTFB 1~4 秒)
   那种才会显示。⇒ 快的页面不闪、慢的页面有交代。
   ⚠ 形状跟当前页走: 表格页出行条、卡片页出块条(JS 按有没有 `table` 判)。 */
.sk-wrap{padding:4px 0}
.sk{display:block;background:linear-gradient(90deg,#1b1f27 25%,#232833 37%,#1b1f27 63%);
  background-size:400% 100%;animation:sk 1.1s ease-in-out infinite;
  border-radius:6px}
.sk-line{height:14px}
.sk-card{margin:0 0 8px;padding:10px;border:1px solid var(--line);border-radius:9px;
  background:#171a21}
.sk-card .sk-line{height:12px}
.sk-card .sk-line+.sk-line{margin-top:8px;width:62%}
.sk-card .sk-line+.sk-line+.sk-line{width:38%}
@keyframes sk{0%{background-position:100% 50%}100%{background-position:0 50%}}
@media (prefers-reduced-motion:reduce){
  .sk{animation:none;background:#1b1f27}
}

:root{--bg:#12141a;--fg:#e6e6e6;--dim:#8f96a3;--line:#242832;--acc:#7c5cff;
      --ok:#3ecf8e;--bad:#ff6b6b;--row:26px;--fs:13px;--pad:8px}
*{box-sizing:border-box;margin:0;padding:0}
/* ── ★ 表单控件**自绘**（2026-10-15 主人:「原生太丑」；试过 Pico.css 后主人说
   「撤回吧我们自己改样式」⇒ 由我们自己画, 不引库）。
   ⚠ 原生 `select` 的箭头、`checkbox` 的方框**各系统长得都不一样且丑** ⇒
   一律 `appearance:none` + 自绘；配色跟着 `:root` 变量走, 与站内其它组件一套。 */
select{flex:0 1 auto;padding:8px 32px 8px 10px;border-radius:8px;
  border:1px solid var(--line);background-color:#0e1015;color:var(--fg);
  -webkit-appearance:none;appearance:none;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%238f96a3' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;background-size:11px}
select:focus{border-color:var(--acc);outline:none}
input[type=checkbox],input[type=radio]{-webkit-appearance:none;appearance:none;
  width:1.05rem;height:1.05rem;flex:0 0 auto;padding:0;margin:0;
  border:1px solid var(--line);background:#0e1015;cursor:pointer;
  transition:background-color .15s ease, border-color .15s ease}
input[type=checkbox]{border-radius:5px}
input[type=radio]{border-radius:50%}
input[type=checkbox]:checked{background-color:var(--acc);border-color:var(--acc);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 10'%3E%3Cpath d='M1 5l3.5 3.5L11 1.5' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:center;background-size:9px}
input[type=radio]:checked{border-color:var(--acc);
  background:radial-gradient(circle, var(--acc) 0 42%, transparent 47%)}
input[type=checkbox]:focus-visible,input[type=radio]:focus-visible{
  outline:2px solid var(--acc);outline-offset:2px}
/* ── ★ **自绘下拉**（2026-10-15 主人:「选择器不要用系统的」）──
   ⚠⚠ 原生 `<select>` 的**下拉列表由系统绘制** —— `appearance:none` 只管**收起来**那个框,
   展开后的面板样式管不到、各系统还不一样 ⇒ 换成 `<details>` + radio **全自绘**。
   ⚠ 用 radio 而不是纯 div: **表单提交天然带 `name=value`**, 不用 JS 兜值。 */
.dd{position:relative;flex:0 1 auto}
.dd>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;
  padding:8px 32px 8px 10px;border:1px solid var(--line);border-radius:8px;
  background-color:#0e1015;color:var(--fg);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%238f96a3' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 10px center;background-size:11px;
  transition:border-color .16s ease}
.dd>summary::-webkit-details-marker{display:none}
.dd[open]>summary{border-color:var(--acc)}
.dd .opts{position:absolute;z-index:40;top:calc(100% + 4px);left:0;min-width:100%;
  background:#161a22;border:1px solid var(--line);border-radius:10px;padding:4px;
  box-shadow:0 12px 32px rgba(0,0,0,.5);display:flex;flex-direction:column;gap:2px}
.dd .opts label{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:7px;
  cursor:pointer;white-space:nowrap;font-size:13px}
.dd .opts label:hover{background:#1e222b}
html,body{height:100%}
body{background:var(--bg);color:var(--fg);
  font:14px/1.45 -apple-system,"PingFang SC","Microsoft Yahei",sans-serif;
  -webkit-text-size-adjust:100%;
  /* ⚠⚠⚠ 去掉移动端**双击缩放的 300ms 等待** —— 「点下去顿一下」的最大来源,
     ⚠ 与服务器快慢**无关**, 光优化后端消不掉(见上面那条说明)。 */
  touch-action:manipulation}
a{color:var(--acc);text-decoration:none}
code{font-size:12px;color:var(--dim)}

/* ── 外壳: 一屏 ── */
/* ⚠⚠ 兜底(flex/grid 子项默认 `min-width:auto` ⇒ 内容多宽就多宽, **不肯缩**):
   给所有 flex/grid 子项 `min-width:0`, 这样「过长主动换行」才真的生效,
   否则里面写了 `overflow-wrap:anywhere` 也照样横向溢出。 */
.page>*{min-width:0}
/* ⚠⚠ `height:100dvh` + 不设 `overflow` ⇒ 默认 `visible`, 内容装不下会**溢出**。
   ⚠ 主人的要求是「**不要滚动隐藏**」—— 关键是**不许 `overflow:hidden` 把内容
   裁掉看不见**。⇒ 显式写 `overflow-y:auto`: 装得下就一屏, 装不下就**能滚**,
   两种情况**都看得见**(而不是「看不见」)。
   ⚠ 各 `.scroll` 已是 `overflow:auto`, 平时不触发。 */
.page{display:flex;flex-direction:column;height:100dvh;max-width:1180px;
  margin:0 auto;overflow-y:auto;overflow-x:hidden;
  padding:8px 10px calc(8px + env(safe-area-inset-bottom))}
/* ── 顶栏: 2026-10-08 重排(主人: 「看着杂乱无章」)
   ⚠ 原来导航 / 数据 / 状态 / 主人开关 / 隧道链接**全是同一种胶囊**, 挤在
     一个 flex 里 ⇒ 没有层级, 眼睛找不到重点; 「← 列表」还夹在数据中间。
   ⇒ 定成一条**从左到右按视觉权重递减**的顺序, 越靠右越退到背景:
     ① `h1` 标题(唯一的粗体大字)
     ② 导航 `← 列表`  —— 纯文字, **无边框无底色**(ghost), accent 色
     ③ 数据 `共 N 局` / 时间 / 地图 / seq —— 普通胶囊
     ④ 状态 `扣次提示` / `已看过` / `剩余 N 次` / 监听状态 —— **纯文字小标**
     ⑤ 隧道链接 —— 等宽小字、最退后(它最不需要被看到)
        ⚠ 2026-10-11 主人「主人模式去掉」⇒ 原来这层的 `🔑 主人模式` 开关
           **已删**(收回 owner 身份走 `/out`, 见那一段注释)。
   ⚠ 右侧簇前加一条竖分隔线, 让「页面信息」与「账号/环境」分属两块。 */
.top{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding-bottom:6px;border-bottom:1px solid var(--line);flex:0 0 auto}
.top h1{font-size:15px;font-weight:600;flex:0 0 auto}
.top .sp{flex:1 1 auto;min-width:8px}
.tzone{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.tzone.tright{padding-left:8px;border-left:1px solid var(--line)}
/* ② 导航: ghost —— 不占视觉重量, 但一眼可点 */
.pill.nav{background:none;border-color:transparent;color:var(--acc);
  padding:2px 4px;font-weight:600}
/* ⚠ `.pill.nav` 也会用在 `<button>` 上(导出图片) ⇒ 按钮默认有底色/边框,
   会盖掉 ghost 样式。⇒ 显式压掉。 */
button.pill.nav{background:none;border:1px solid transparent;color:var(--acc);
  padding:2px 4px;font-weight:600;cursor:pointer}
button.pill.nav:disabled{opacity:.5;cursor:default}
button.pill.nav:hover{color:#ffd08a}
/* ④ 状态: 顶栏里一律用纯文字(.meta), 不占胶囊 */
/* ⚠⚠ 2026-10-08 主人: 「如果过长**主动换行**」。
   ⚠ 原来 `white-space:nowrap` ⇒ 长文案(比如「☆ 疑似·指纹认出」「12 小时内
   不重复扣」)顶破布局。⇒ 放开折行, 但限宽免得无限长。
   ⚠ 徽章折行会变成两行小标签, 比被裁/顶破好; `line-height:1.3` 让两行贴紧。 */
.pill{background:#1e222b;border:1px solid var(--line);border-radius:20px;
  padding:2px 9px;font-size:12px;color:var(--dim);
  white-space:normal;overflow-wrap:anywhere;max-width:100%;
  line-height:1.3;text-align:center}
.pill b{color:var(--acc)}
/* ⚠⚠ 这几个变体**模板一直在用, 样式却从没定义** ⇒ 全渲染成一样的灰胶囊
   (`.pill.warn` 只有 `b` 的颜色规则, 盒子本身没样式)。⇒ 补齐。 */
.pill.warn{color:#ffb454;border-color:#5a4520;background:#241a08}
.pill.warn b{color:#ffb454}
.pill.ok{color:var(--ok);border-color:#2c5a41;background:#152219}
.pill.dim{color:var(--dim);border-color:var(--line);background:#191d25}
/* ⚠⚠ 2026-10-15 软删除按钮用的**红色胶囊**。⚠ 颜色照 `.delbtn`/`.ban .bnote`
   那套已有的红(不新造色值) ⇒ 主人一眼认得「这个是删/恢复」。 */
.pill.danger{color:#ff8f7a;border-color:#5a2a24;background:#241110}
.pill.danger:hover{color:#fff;background:#c0392b;border-color:#c0392b}
/* ⚠⚠ 软删那两个控件的**表单样式故意不放这里** —— 它们是页面专用的
   (放全局 = 每个页面都带一份, 连客户页的 HTML 里都会出现那些类名, 测试会抓到;
   而且表单默认 `display:block`, 放全局还会影响别的页面里同名的 form)。
   ⇒ 软删的表单挂 `tblform`, 不需要额外样式。 */
/* ⑥ 隧道链接: 等宽小字、最退后。⚠ 原来是 `max-width:72vw` 的大胶囊,
   视觉上比「🔑 主人模式」还抢眼 —— 权重完全反了。 */
.pill.copy{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11px;color:var(--dim);border-color:#2a2f3a;background:#171a21;
  padding:2px 7px}
.pill.copy:hover{color:var(--fg);border-color:#3a4152}
/* ⚠ 胜/负徽章: 模板一直在写 `class="pill win|lose"`, 但**样式从来没定义过**
   ⇒ 一直是灰胶囊, 空值时还渲染成**空胶囊**。⇒ 补上配色。 */
.pill.win{color:var(--ok);border-color:#2c5a41;background:#152219}
.pill.lose{color:var(--bad);border-color:#5a2c31;background:#221518}
/* ⚠⚠ 状态类**不占胶囊**(主人 2026-10-08: 「状态类不占胶囊」)
   —— 「☆疑似」「已解锁」「12h 内不重复扣」这类是**注解**, 不是数据。
   做成胶囊会把摘要带撑成三四行, 看着乱(主人原话「太乱了」),
   而且挤得数据项被迫换行 ⇒ 违背「一屏显示全」。
   ⇒ 纯文字小标, 无边框无底色, 靠 `·` 分隔。 */
.meta{font-size:calc(var(--fs) - 1.5px);color:var(--dim);
  white-space:normal;overflow-wrap:anywhere;line-height:1.3}
.meta.warn{color:#ffb454}
.meta.ok{color:var(--ok)}
/* ⚠⚠ 主人模式(2026-10-11 主人要求「去掉」⇒ 顶栏那个 `🔑 主人模式` pill **已删**)。
   这条 `.pill.own` 样式**留着备用**(通用 class, 删了万一别处要用又得重写);
   收回 owner 身份走 `/out`(路由仍在)。 */
.pill.own{background:#3a2a10;border-color:#ffb454;color:#ffd08a;
  font-weight:600;cursor:pointer}
.pill.own:hover{background:#4a3512;border-color:#ffc14d}
/* 隧道地址: 像个可点的按钮, 点了有反馈 */

.pill.copy:hover{border-color:var(--acc);color:var(--fg)}
.pill.copy.ok{color:var(--ok);border-color:var(--ok)}
.pill.copy.bad{color:var(--bad);border-color:var(--bad)}
.mid{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:6px;
  padding-top:6px}
/* ⚠⚠ 改成 flex 列, 好让下面的表**把剩余高度分掉**(主人 2026-10-08:
   「整个内容区域被内容撑开就行, **不要留空**」)。
   ⚠ 原来 `.scroll` 是普通块 + 表按内容高度 ⇒ 侧框比表高时**底部一条空白**,
     手机上尤其明显(两侧框一样高, 表只有 10 行)。
   ⇒ `.scroll` 变 flex 列, `>table` 吃满剩余高度 ⇒ 浏览器把多出来的高度
     **按比例分给各行**, 10 行一起长高, 底边对齐 ban 行 ⇒ 没有空白带。
   ⚠ 内容**超**一屏时 `overflow:auto` 照旧滚(那是「装不下」, 不是「留空」)。 */
.scroll{overflow:auto;-webkit-overflow-scrolling:touch;min-height:0;
  display:flex;flex-direction:column;
  border:1px solid var(--line);border-radius:9px;background:#171a21}
/* ⚠⚠⚠⚠⚠ 2026-10-09 主人: 「战绩列表页不要一行占一半, **面板居上**就行」
   ⚠⚠⚠⚠⚠ 这条**全局**的 `flex:1 1 auto` 会让**任何** `.scroll` 里的表格**撑满**,
   ⚠⚠⚠⚠⚠ 行数少时多余高度就**摊给每一行** ⇒ 主人后台 `/m/` 里「共 1 局」那一条
   ⚠⚠⚠⚠⚠ 被拉成**五百多 px**, 占满整个面板(现象: 「一行占一半」)。
   ⚠⚠⚠⚠⚠ 而它本来是为**详情页的 10 人表**加的(2026-10-08: 10 行一起长高,
   ⚠⚠⚠⚠⚠ 底边对齐 ban 行 ⇒ 侧框底部不留空带) ⇒ **限定在 `.cols` 里**,
   ⚠⚠⚠⚠⚠ 别的表格(你的 `/m/` 列表)保持**自然高度** ⇒ 内容**顶格**, 不摊开。
   ⚠⚠⚠⚠⚠ 嵌入列表那一份已由 `.cols.embed .scroll>table{flex:none}` 覆盖
   ⚠⚠⚠⚠⚠ (它更特异: `.cols.embed .scroll>table` 比 `.cols .scroll>table` 多一类)。
   ⚠⚠⚠⚠⚠ ⚠ **别退回全局写法** —— 那正是主人报的东西, 且它看起来「很合理」
   ⚠⚠⚠⚠ ⚠ (详情页确实需要), 所以极易被「顺手统一」回去。 */
.cols .scroll>table{flex:1 1 auto;height:auto}
.scroll>table{flex:0 1 auto;height:auto}
.scroll::-webkit-scrollbar{width:6px;height:6px}
.scroll::-webkit-scrollbar-thumb{background:#2c313d;border-radius:3px}

/* ── 表单 ── */
.frow{display:flex;gap:6px}
input,button{font:inherit}
input{flex:1;min-width:0;padding:8px 10px;border-radius:8px;
  border:1px solid var(--line);background:#0e1015;color:var(--fg);outline:none}
input:focus{border-color:var(--acc)}
/* ⚠ 同上: 按钮文案过长时**主动换行**, 不横向溢出。 */
button{padding:8px 16px;border-radius:8px;border:0;background:var(--acc);
  color:#fff;font-weight:600;cursor:pointer;
  white-space:normal;overflow-wrap:anywhere;max-width:100%;line-height:1.3}
button.ghost{background:#242832;font-weight:400}
/* ⚠ 表单里带一个输入框的**整行**(自定义到期/改备注/任意次加减共用这一条)。
   ⚠ 摆在这里而不是页面段: 三个页面都在用, 放页面段就是「三份一样的样式」。
   ⚠ 宽度照 `.frow` 的兄弟行; ⚠⚠⚴⚴ **不许**给它写死宽度 ——
   ⚠⚠⚴⚴ 窄屏(360px)放不下, 而这项目规矩是「宁可换行也不许横向溢出」。 */
.trow{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-top:6px}
.trow input{max-width:180px}
/* ⚠ 数字输入框: 手机上直接出数字键盘, 但**别用 type=number 的上下箭头**
   ⚠⚠⚴⚴ (它会挤占宽度、且在桌面端是没人用的东西) ⇒ 用 inputmode=native 给数字键盘。 */
.trow input[type=number]{-moz-appearance:textfield;appearance:textfield}
.trow input[type=number]::-webkit-outer-spin-button,
.trow input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}

/* ── 表 ── */
table{width:100%;border-collapse:collapse;font-size:var(--fs);table-layout:auto}
/* ⚠⚠ 2026-10-08 主人: 「默认「…」的改成换行显示, **宁愿缩小不要隐藏**」。
   ⚠ 基线原来全局 `white-space:nowrap` —— 于是「段位」那种窄列(9% 宽)在
   400px 屏上装不下「至尊星耀Ⅳ」就**横向溢出**。
   ⇒ 表格默认**可折行**; 要「不折」的只有 `.pill`(徽章, 折了会散)。
   ⇒ 行高别再用 `height:var(--row)` 钉死(会把折行的第二个行盒挤出内容盒) */
/* ⚠⚠⚠ 三个要求要同时满足(主人 2026-10-08 一条条加的):
 *   ① **一屏显示全**(手机)      ② **不要滚动隐藏**  ③ **不隐藏内容 + 有美感**
 * ⚠ 折行会让格子**变高** ⇒ 变高就触发 `.scroll` 滚动 ⇒ 违背 ①②。
 * ⇒ 优先级定成: **先缩(字号/内边距/行高) → 再折行 → 永不隐藏**。
 *   折行因此只是**兜底**, 正常情况下一行放得下。
 * ⇒ 内边距收窄到 2px(原来 4px 是我上一轮加的, 那会直接撑出一屏 ⇒ 撤回)。 */
th,td{padding:2px var(--pad);height:auto;
  line-height:1.25;vertical-align:middle;text-align:left;
  white-space:normal;overflow-wrap:anywhere;
  border-bottom:1px solid var(--line)}
/* ⚠ 「字体可以小, 不能不全」(主人 2026-10-06): 需要放长内容的格子用
   `.wrap` —— **允许折行 + 行高可变**, 于是长名字/长 id 自动换行,
   绝不用 text-overflow 截断。行高用 min-height 就是给折行留余地。 */
/* ⚠ 同上: `min-height` 在表格单元格里被忽略, 而 `height:var(--row)` 会把折行
   后的第二个行盒挤出内容盒 ⇒ 「上面一半下面一半」。
   ⇒ 高度交给 padding, 行高按字号倍数, 垂直居中。 */
td.wrap{white-space:normal;height:auto;
  line-height:1.25;vertical-align:middle;
  padding:2px var(--pad);overflow-wrap:anywhere}
td.wrap small{display:block;font-size:calc(var(--fs) - 2px);color:var(--dim);
  line-height:1.25}
th{position:sticky;top:0;z-index:2;background:#1c2029;color:var(--dim);
  font-weight:500;font-size:12px}
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums}
tbody tr:hover{background:#1e232c}
tr.me{background:#241f3d}
tr.me td:first-child{box-shadow:inset 3px 0 0 var(--acc)}

/* 「正在打」那一行: 醒目(绿边), 但一眼看得出不是已完成的对局 */
tr.now{background:#16261a}
tr.now td:first-child{box-shadow:inset 3px 0 0 var(--ok)}
tr.now:hover{background:#1d3122}

/* 定宽 + **折行**(主人 2026-10-08: 「默认…省略的改成换行显示, 宁愿缩小不要隐藏」)
   ⚠⚠ 原来这里是 `overflow:hidden;text-overflow:ellipsis` —— `/m/` 那张表
     (person_old.html) 用的就是 `table.fixed`, 于是**每格超出宽度就显示「…」**,
     昵称/营地 id/段位被截掉。⚠ 那句注释还写着「宁可裁也不横滚」的取舍,
     已被主人明确推翻 ⇒ 现在**一个字都不裁**。
   ⇒ 定宽仍要(`table-layout:fixed`, 列宽才可控), 但**允许折行**:
     `overflow-wrap:anywhere` 让超长 id 也能断, 行高用 min-height 可长。 */
table.fixed{table-layout:fixed}
/* ⚠⚠⚠⚠⚠ 2026-10-11 主人: 「表头颜色没生效」→「**问题是卡片不是灰的,
   表头是灰的**」⇒ 要「表头**融进**所在底色, 不要浮成一个灰块」。
 *
 *   ⚠⚠⚠⚠⚠ **我连着改错了两次, 真因是「没先量色」**:
 *     ① 第一版只改 `.aitbl th` —— 而查号结果表是 `table.fixed` ⇒ 没生效。
 *     ② 第二版把 `table.fixed th` 也设成 `#171a21`(卡片色) —— **更糟**:
 *        ⚠⚠ 查号结果表**不在 `.scroll`/`.tcard` 里**, 它直接挂在 `#pres`
 *          ⇒ 它周围的底色是**页面底色 `--bg:#12141a`**, 不是 `#171a21`。
 *        ⇒ 给表头一个比周围**亮一档**的颜色 = **正是「一个灰块」的效果**,
 *          主人说的「表头是灰的」就来自这里。
 *     ⚠ 实测(canvas 量饱和度) 那一族深色彼此只差 1~4 个色阶,
 *       **肉眼可见的割裂感主要来自「有没有边框/边界」, 不是色相本身**。
 *
 *   ⇒ 正确做法: **表头背景 = transparent**(继承所在容器的底色, 天然「融」),
 *     边界只靠**一条底线** + 字重来表达。
 *   ⚠⚠ 但 `.scroll` 里的表(详情页 10 人表)是**有底色**的(`#171a21`),
 *     那里 `transparent` 会让表头与行**混成一片** ⇒ 分两种情况给:
 *     · `.scroll` 内 ⇒ 给 `#171a21`(与容器同色, 一样是「融」)
 *     · 裸挂在页面上的(查号结果) ⇒ `transparent`(与页面底色同)
 *   ⚠ 这是「同一份代码、两种上下文」的典型 ⇒ 用祖先选择器分开, **不写两份值**。 */
table.fixed th{line-height:1.25;vertical-align:middle;padding:3px var(--pad);
  font-weight:600;color:var(--dim);
  background:transparent;                 /* ← 默认: 融进所在底色 */
  border:0;border-bottom:1px solid var(--line);   /* ← 只留一条底线 */
  box-shadow:none}
/* ⚠ `.scroll` 里的表自带底色 `#171a21` ⇒ 表头给同色(否则表头比行浅, 反而成块) */
.scroll table.fixed th{background:#171a21}
/* ⚠⚠⚠ 折行要**好看**(主人 2026-10-08): 「不要上面一半下面一半」。
   ⚠ 病根: 基线 `th,td` 用的是 `height:var(--row)` **和**
     `line-height:var(--row)` —— 两者**都等于一个行高**, 于是
     ① 格子高度被钉死, 第二个行盒**溢出内容盒**、压到 `border-bottom` 上;
     ② `line-height` 等于固定 px 而非倍数 ⇒ 两行之间被拉开, 一行在上、
        一行在下, 看着就是「上面一半、下面一半」。
   ⇒ 修法三件套:
     · `height:auto`      —— 高度**不参与**折行, 让它自己长
     · 最小高度改用 `padding` —— `min-height` 在表格单元格里本来就被忽略
     · `line-height:1.35` —— 按**字号**的倍数, 两行贴在一起
     · `vertical-align:middle` —— 折行后居中, 同行里短格与长格**底子对齐**
   ⚠ 绝不退回 `overflow:hidden` + `ellipsis`(那是另一头: 截断)。 */
table.fixed td,table.fixed th{
  white-space:normal;overflow:visible;text-overflow:clip;
  overflow-wrap:anywhere;word-break:break-word;
  height:auto;line-height:1.25;vertical-align:middle;
  padding:2px var(--pad)}
.dim{color:var(--dim)}
.win{color:var(--ok)}.lose{color:var(--bad)}
.tom{font-weight:700;color:var(--acc)}
.tag{display:inline-block;background:#242832;border-radius:4px;padding:0 5px;
  font-size:11px;line-height:16px;color:var(--dim)}
.tag.fr{background:#3a3018;color:#ffcf7a}
.tag.g{background:#17301f;color:#7fd8a4}

/* ── 落地页: 号卡片网格 ── */
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(178px,1fr));
  gap:6px;overflow:auto;-webkit-overflow-scrolling:touch;flex:1 1 auto;
  min-height:0;align-content:start;padding-right:2px}
.cards::-webkit-scrollbar{width:6px}
.cards::-webkit-scrollbar-thumb{background:#2c313d;border-radius:3px}
.tcard{display:block;background:#171a21;border:1px solid var(--line);
  border-radius:9px;padding:7px 9px;color:var(--fg)}
.tcard:hover{background:#1e232c;border-color:#333a48}
/* ⚠ 卡片是 <div> 包着两个 <a>(自己查 / 发给老板) —— `<a>` 套 `<a>` 是非法
   HTML, 浏览器会把外层链接吃掉, 点「发给老板」会变成跳去 /m/。 */
.tcard .tnk{display:block;color:var(--fg)}
/* ⚠⚠⚴⁴ 卡片底栏(2026-10-15 主人「优化按钮样式和布局」后重排)。
   ⚠⚠⚴⁴ **动之前的实测**(真浏览器 `getBoundingClientRect`, 414px 档):
   ⚠   卡片 193px / 底栏 173px / 底栏高 54.1px:
   ⚠     发给老板→      58.1×15.9 · 11px · 无 padding 无圆角
   ⚠     🔗复制带卡链接 77.3×15.9 · 11px · 无 padding 无圆角
   ⚠     ⏸不盯了       49.1×26.1 · 11px · **有红框**
   ⚠     ✈️飞书        64.5×26.1 · **12.5px** · **有 padding**
   ⚠   ⇒ **一张卡里三种按钮语言 + 两套高度 + 两套字号**。
   ⚠⚠⚴⁴ `gap` 8→4: 170px 的底栏里 8px 间隙太奢侈。
   ⚠⚠⚴⁴ **仍然必须 `flex-wrap:wrap`** —— 四个动作自然宽度合计 ~249px ≫ 173px。
   ⚠⚠⚴⁴ ⚠ 但**不许把字挤成竖条**: 本项目铁律「绝不隐藏数据」⇒ 挤扁与换行之间
   ⚠     只准选换行(2026-10-15 就钉过这条, 别退回)。 */
.tfoot{display:flex;gap:4px;margin-top:5px;padding-top:4px;
  border-top:1px solid var(--line);flex-wrap:wrap}
.tsend{font-size:11px;color:var(--acc)}
.tsend:hover{text-decoration:underline}
/* ⚠⚠⚴⁴ 卡片底栏上的动作按钮: **四个必须长得一样**, 只靠颜色分层。
   ⚠⚠⚴⁴ 统一后的宽度预算(底栏 173px / 间隙 4px):
   ⚠   行1 = 发给老板(68) + 复制带卡链接(89) + 4 = **161 ≤ 173** ✓
   ⚠   行2 = ⏸不盯了(61) + 条件(80)       + 4 = **145 ≤ 173** ✓
   ⚠ ⇒ **仍然两行, 而四个按钮终于齐平**(原来 15.9 与 26.1 两套高度)。
   ⚠⚠⚴⁴ `min-height` 是为了: 「处理中…」/「▶ 恢复轮询」这种**文案会变长变短**
   ⚠   的回填不会让底栏忽高忽低(点一下卡片跳一下, 很廉价)。
   ⚠⚠⚴⁴ ⚠ `overflow` 一律不设 —— 绝不许 `hidden`/`ellipsis`(铁律: 宁可折行不藏字)。
   ⚠⚠⚴⚴ ⚠ 作用域只到 `.tfoot .tsend`: `.tsend` 还有别的用法, 别全局改。 */
.tfoot .tsend{display:flex;align-items:center;justify-content:center;
  min-height:23px;padding:3px 4px;border:1px solid var(--line);
  border-radius:7px;background:#1e232c;color:var(--acc);
  font-size:11.5px;line-height:1.2;text-align:center;text-decoration:none;
  white-space:nowrap}
.tfoot .tsend:hover{background:#262c38;border-color:#3a4356;text-decoration:none}
/* ⚠⚠ 主人密钥**默认收起**。它明文摆在页面中间的话, 截图 / 转发就泄漏,
   而它是 `/m/`(旧版全明白) 和 `/battle` 全文的唯一钥匙。 */
.keybox{margin-top:4px}
/* ★ 实时状态条(2026-10-07): 落地页顶部一行 pill + 可展开的在局表。
   ⚠⚠⚠ 2026-10-11 主人「改成一行能显示的」⇒ 这里从**一排独立胶囊**改成
     **一条紧凑单行**:
     · `flex-wrap:nowrap` —— 宁可压字号也不折行(折行会让首页顶部占两三行)
     · 逐项**去掉边框/圆角/左右 padding**(省 5×(2边框+18px padding) ≈ 90px),
       改用**分隔点**分隔 ⇒ 这是「一行装得下」的真正来源
     · ⚠⚠ **绝不用 `overflow:hidden` / `text-overflow:ellipsis` 兜底** ——
       那是「隐藏字」, 本项目铁律明令禁止(宁可折行也不藏字)。
     ⚠ 告警(`.lv.warn`)仍带红字 + 🚫, 不因为紧凑化而降级。 */
/* ⚠⚠⚠ 2026-10-11 主人「一行放不下了」⇒ **两行**。
   ⚠ 结构: 外层 `.livebar` 是 **column**(不再 flex) ⇒ 每个 `.lvrow`
     **独占一行**。⚠⚠ 行内是 `nowrap` ⇒ **行内绝不再折** ——
     折行只发生在「行与行之间」这个语义边界上, 而不是随机位置。 */
.livebar{display:flex;flex-direction:column;gap:1px;margin-top:4px;flex:0 0 auto}
/* ⚠ 每一行: 单行不折 + 左右微留白(与 `.msg` 的视觉节奏一致) */
.livebar .lvrow{display:flex;flex-wrap:nowrap;gap:0;align-items:baseline;
  overflow:visible;white-space:nowrap;padding:0 2px}
/* ⚠ 逐项: 无边框(省 5×(2边框+18pxpadding) ≈ 90px), 用 · 分隔 */
.livebar .lv{font-size:11px;color:var(--dim);line-height:1.5;letter-spacing:0}
.livebar .lv b{color:var(--acc);font-weight:600}
/* ⚠⚠ 分隔点用 `::before` 生成, **不写进模板** ——
   写在模板里每处都要空格, 改文案时极易多一个少一个。
   ⚠ 相邻兄弟选择器 ⇒ 首项前面**没有** ·(否则行首多个点)。 */
.livebar .lv + .lv::before{content:'·';color:#4a5462;margin:0 5px}
/* ⚠ 告警项: 红字压过一切, 一眼要能看见(AGENTS.md: 涨了就要看) */
.livebar .lv.warn{color:#ff9a8f;font-weight:600}
.livebar .lv.warn b{color:#ff9a8f}
@media (max-width:400px){ .livebar .lv{font-size:10.5px} }
/* 在局表: 允许折行(跟 10 人详情表一样「不砍列不截字」) */
.livebox table td{font-size:12px;line-height:1.45}
.livebox summary{cursor:pointer}
.keybox>summary{cursor:pointer;color:var(--acc);font-size:12px;list-style:none;
  /* ⚠⚠ 2026-10-11 主人: 「内容溢出到框外面」⇒ 给 summary 自己的**内边距**。
   *   ⚠⚠⚠ 真测量结论(360px, getBoundingClientRect + scrollWidth):
   *     `scrollWidth == clientWidth`(340)== 容器宽) ⇒ **文字本身没超出盒子**。
   *     ⚠ 看着「溢出」是因为 `.keybox[open]` 有 `padding:5px 8px`, 而
   *       **summary 没有任何 padding** ⇒ 字贴着 details 的边框走,
   *       视觉上像「顶出去了」。⇒ 补内边距(左 8 右 8, 与 details 的 8 对齐)。
   *   ⚠ `padding` 会让 summary 的盒模型变宽 ⇒ 用 `box-sizing` 已由全局
   *     `*{box-sizing:border-box}` 保证不会把 details 撑宽(AGENTS.md 记过
   *     这类「padding 撑破容器」的坑)。 */
  padding:5px 8px;line-height:1.45;
  /* ⚠ 长文案允许折行, **不许 overflow:hidden 截字**(本项目铁律) */
  white-space:normal;overflow-wrap:anywhere}
.keybox>summary::-webkit-details-marker{display:none}
.keybox>summary::before{content:'▸ '}
.keybox[open]>summary::before{content:'▾ '}
.keybox[open]{background:#2a1e0c;border:1px solid #7d5a20;border-radius:7px;
  padding:5px 8px}
/* ⚠ 原来 `text-overflow:ellipsis;white-space:nowrap` ⇒ 长昵称显示「…」。
   ⚠ 主人 2026-10-08: 宁愿缩小不要隐藏 ⇒ 折行, 行高自己长。 */
.tname{font-size:14px;font-weight:600;line-height:1.3;
  white-space:normal;overflow-wrap:anywhere;word-break:break-word}
.tmeta{display:flex;gap:6px;align-items:baseline;margin-top:2px}
.tn{color:var(--ok);font-size:12px;font-weight:600}
.td{color:var(--dim);font-size:11.5px}
.tid{color:#6d7480;font-size:10.5px;margin-top:1px;
  white-space:normal;overflow-wrap:anywhere;word-break:break-all}

/* ── 侧栏(红在上 · 蓝在下, 上下堆叠) ── */
.side{border:1px solid var(--line);border-radius:9px;background:#171a21;
  min-height:0;display:flex;flex-direction:column;overflow:hidden;
  flex:1 1 0}                      /* ★ 两边平分高度 ⇒ 一屏塞得下 */
.side>h2{font-size:12.5px;padding:4px 9px;margin:0;font-weight:600;
  border-bottom:1px solid var(--line);display:flex;gap:8px;align-items:baseline;
  flex:0 0 auto}
.side>h2 .dim{font-weight:400;font-size:11.5px}
/* ⚠ 上下堆叠(不是左右两栏 —— 手机上要左右扫)。顺序 = 胜方在上、败方在下,
   跟 store.battle_detail 的输出顺序一致(也跟营地数据原样一致)。 */
.cols{display:flex;flex-direction:column;gap:6px;flex:1 1 auto;min-height:0}
/* ⚠⚠⚠ 2026-10-08 修: 原来这里是 `.cols>.scroll{height:100%}` ——
   **死选择器**: 真实嵌套是 `.cols > .side > .scroll > table`,
   `.scroll` 是**孙子**不是儿子 ⇒ 这条**匹配不到任何元素**(早就在那儿了)。
   ⚠ 真正的病根: `.scroll` 是 `.side`(列向 flex)的 flex item, 用**默认
   `flex:0 1 auto`** ⇒ 高度 = **内容高度** ⇒ 侧框比表高出来的空间
   **全堆在框底部** ⇒ 手机上就是那条空白(主人: 「不要留空」)。
   ⚠ 而我上一轮只加了 `.scroll>table{flex:1 1 auto}` —— 那是在 `.scroll`
   **内部**分配空间, 而 `.scroll` 自己没有多余空间 ⇒ **分配了个空气**,
     页面看起来毫无变化(主人: 「详情没变」)。
   ⇒ 现在两环都补上:
     ① `.side>.scroll{flex:1 1 auto}` —— 先吸收侧框的剩余高度
     ② `.scroll>table{flex:1 1 auto}` —— 再把高度分给各行(上一轮已加)
   ⚠ `min-height:0` 不能少: flex item 默认 `min-height:auto` ⇒
     内容比框高时**不肯缩**, `overflow:auto` 就不会滚。 */
.side>.scroll{flex:1 1 auto;min-height:0}
/* ── ★ 10 人详情表: 紧凑模式(主人 2026-10-08「一屏显示全 + 不滚动 + 不隐藏」)
   这张表是「一屏显示全」的**主角**: 10 行 + 表头 + ban + 摘要, 手机竖屏最紧。
   ⇒ 三手一起缩, 让**每行保持一行**:
     · 行高 `--row` 26 → 21px
     · 字号 比全局再小 1px(窄屏再小 1px)
     · 内边距 2 → 1px(竖向), 列间距靠 `col` 宽度控制
   ⇒ `overflow-wrap:anywhere` 仍留着: 万一真塞不下就**换行**,
     绝不 `ellipsis`、绝不 `overflow:hidden`(那才是「隐藏」)。 */
.scroll table{--row:21px}
.scroll table th,.scroll table td{
  padding:1px 4px;line-height:1.2;
  font-size:calc(var(--fs) - 1px)}
.scroll table th{color:var(--dim);font-weight:600}
.scroll table td.n{font-variant-numeric:tabular-nums}   /* 数字等宽, 上下对齐好看 */
/* ⚠ 美感: 隔行淡底 + 目标行高亮(不占额外高度) */
.scroll table tbody tr:nth-child(even){background:#191d25}
.scroll table tbody tr.me{background:#241f3d}
.scroll table tbody tr.me:hover{background:#2b2449}
@media (max-width:400px){
  .scroll table th,.scroll table td{font-size:calc(var(--fs) - 2px);padding:1px 3px}
}

/* ban 位: 塞在每块表格**下方的空余高度**里(不额外占屏幕) */
.ban{flex:0 0 auto;display:flex;gap:5px;align-items:center;flex-wrap:wrap;
  padding:5px 9px;border-top:1px solid var(--line);
  font-size:calc(var(--fs) - 1px);line-height:1.4}
.ban span{background:#242832;border-radius:4px;padding:1px 6px;color:var(--dim)}
/* ⚠⚠⚠ 2026-10-09 「这一局本来就没有 ban」时的**原因行** —— 必须占着
   ban 那个位置, 否则「本来就没有」与「页面坏了」看着一模一样(主人报过)。 */
.ban.none{border-top-style:dashed}
.ban .bnote{background:none;padding:0;color:var(--dim);
  font-size:calc(var(--fs) - 2px);line-height:1.4}
.ban .dim{background:none;padding:0;font-size:calc(var(--fs) - 2px)}
.ban .both{background:#3a3018;color:#ffcf7a}   /* 双方都 ban */
.side.blue .ban{border-top-color:#2b4a7d}
.side.red .ban{border-top-color:#7d2b34}
/* 红蓝底色条: 一眼分得清哪边是哪边 */
.side.red>h2{background:#3a1e22;color:#ff9d9d;border-bottom-color:#7d2b34}
.side.blue>h2{background:#16283a;color:#8fc4ff;border-bottom-color:#2b4a7d}

.msg{padding:8px 11px;border-radius:8px;font-size:13px;flex:0 0 auto}
.err{background:#3a1e22;border:1px solid #7d2b34;color:#ffb3b3}
.ok{color:var(--ok)}
.big{font-size:28px;font-weight:700;line-height:1.1}

/* ── 弹窗: 卡密输入(2026-10-07 主人定的: **不许跳页面**) ────────────────
   ⚠ 原来解锁失败会 `location.href='/card?u=…'` 跳到独立买卡页, 主人打回:
     列表是滚动的, 跳走再跳回来位置全丢, 而且手机上白闪一下。
   ⚠⚠ 弹窗**贴着顶部**而不是垂直居中: `align-items:center` 遇到手机软键盘
     弹起, `position:fixed;inset:0` 拿到的是**布局视口**不变 ⇒ 居中的弹窗
     会被键盘顶到屏幕外, 输入框看不见。上边缘 + padding 最稳。 */
.mask{position:fixed;inset:0;z-index:50;background:rgba(6,8,12,.74);
  display:flex;align-items:flex-start;justify-content:center;
  padding:calc(9vh + env(safe-area-inset-top)) 16px 16px}
.mask[hidden]{display:none}
.modal{width:100%;max-width:360px;background:#171a21;border:1px solid #2c313d;
  border-radius:12px;padding:12px;display:flex;flex-direction:column;gap:8px;
  box-shadow:0 12px 40px rgba(0,0,0,.5)}
.modal h3{font-size:15px;font-weight:600;display:flex;align-items:center;gap:8px}
.modal h3 .x{margin-left:auto;cursor:pointer;color:var(--dim);font-size:13px;
  background:none;border:0;padding:2px 6px;font-weight:400}
.modal h3 .x:hover{color:var(--fg)}
/* ── ★ 弹窗进出动画 + 统一控制器(2026-10-13 主人:「弹窗打开关闭加动画」)──
   ⚠⚠ `hidden` 是 `display:none` ⇒ **不能过渡**。所以进/出都用**keyframes**
     (与 `#main.enter` 同一套思路), 关闭时先挂 `.closing` 跑完动画**再**设 hidden
     —— 由 `ModalCtrl.hide()` 负责, 别处别再自己 `mask.hidden = true`。
   ⚠ `.closing` 必须在动画结束/兜底定时器里摘掉, 否则同一次打开不会重放。 */
@keyframes maskIn{from{opacity:0}to{opacity:1}}
@keyframes maskOut{from{opacity:1}to{opacity:0}}
@keyframes modalIn{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}
@keyframes modalOut{from{opacity:1;transform:none}to{opacity:0;transform:translateY(6px) scale(.99)}}
.mask:not([hidden]){animation:maskIn .18s ease-out both}
.mask:not([hidden]) .modal{animation:modalIn .2s cubic-bezier(.2,.8,.3,1) both}
.mask.closing{animation:maskOut .16s ease-in both}
.mask.closing .modal{animation:modalOut .16s ease-in both}
/* ⚠ 高亮「滚过去的那张卡」—— 不然滚动了主人也不知道该看哪 */
@keyframes cardFlash{0%,100%{box-shadow:none}
  15%,60%{box-shadow:0 0 0 3px rgba(124,92,255,.55)}}
.tcard.flash{animation:cardFlash 1.1s ease-out 2}
@media (prefers-reduced-motion:reduce){
  .mask, .mask .modal, .tcard.flash{animation:none !important}
}
.modal .row{display:flex;gap:6px}
.modal .row form{display:flex;gap:6px;flex:1;min-width:0}
.modal .dim{font-size:12px;line-height:1.7}

/* ── 对局列表: **一局一块**, 未解锁整行全锁(2026-10-07) ─────────────
   ⚠⚠ 原来是 `<table>`(每局一行)。改成块状是因为「解锁后要在**列表页里
      就地展开成 10 人详情表**」—— 数据格里塞不下 flex 的双方表(.cols/.side)。
      (⚠ 这段注释里刻意不写原样的「数据格标签」: 自测要断言「锁着的列表页
        一格数据都没有」, 注释里混进一个同名字面量会把断言带偏。)
   ⚠ 「一屏显示全」的约定仍然成立: 外层还是 .scroll 自己滚, 不整页横滚。 */
.bats{display:flex;flex-direction:column;gap:6px;padding:6px}
.bat{background:#171a21;border:1px solid var(--line);border-radius:9px}
.bat.open{background:#151822;border-color:#2c313d}
/* ⚠⚠⚠ 「一局一行」(2026-10-08 主人: 「战绩列表改成一行布局」)
   ⚠⚠ **这推翻了上一档的折行方案**(上面原来是 `.lockbar{flex-wrap:wrap}`):
     旧的优先级是「**先缩 → 再折行 → 永不隐藏**」;
     主人现在要的是**永不折行** ⇒ 新优先级:
     「**先缩到一行 → 绝不换行 → 也绝不隐藏**」。
   ⚠⚠ 代价: 一行要塞 `第N局 + 时间 + 胜负 + 英雄/KDA + 表现 + 疑似 + 按钮`,
     手机 360px 装不下全字 ⇒ 只能**把词缩短**(按钮「详情1分」、
     表现分省掉「表现」二字但保留 `title`)。⚠ **缩的是词, 不是数据。**
   ⚠⚠⚠ **绝不许**拿 `overflow:hidden` / `text-overflow:ellipsis` 兜底 ——
     那就是「隐藏」, 这个项目明确不许做(`:root` 顶上那条约定)。
     装不下就**再降一档字号**, 降到底也宁可让最长的英雄名换行, 不藏字。 */
.lockbar{display:flex;align-items:center;gap:6px;flex-wrap:nowrap;
  padding:5px 7px;min-height:30px}
/* ⚠ 一行的关键: 胶囊**内部**不许折(折了就等于两行)。
   `.dim` / `.lkmsg` 仍可折 —— 它们只在「这行连数据都没有」和报错时出现,
   那种情况下宁可折行也要把话说全。 */
.lockbar .pill{white-space:nowrap;max-width:none}
.lockbar .sp{flex:1 1 auto;min-width:4px}
/* 「第 N 局」本身很短; `max-width:100%`+`overflow-wrap` 是**万一来不及**的兜底,
   正常情况下 nowrap 走不到那里。 */
.lockbar .idx{font-size:13px;font-weight:600;color:var(--fg);
  white-space:nowrap;flex:0 0 auto}
.lockbar .dim{font-size:12px;white-space:normal;overflow-wrap:anywhere}
.lockbar .lkmsg{font-size:12px;white-space:normal}
/* ⚠ 锁条带摘要胶囊(2026-10-08 改的口径)+ 一行布局: 胶囊压到 11px、
   内边距收到 5px, 全靠这三个数挤出一行。 */
/* ⚠ 锁条带摘要胶囊(2026-10-08 改的口径)+ 一行布局: 胶囊压到 11px、
   内边距收到 5px, 全靠这三个数挤出一行。
   ⚠⚠⚠ 2026-10-09: gap 5→4 / 胶囊内边距 6→5 —— 给解锁按钮并进
     「含几排」腾宽度。实测(字宽模型, 按 AGENTS.md 记的 358.6 反标定):
     最宽那行 420.0px > 预算 383.3px ⇒ **414px 手机上也会横向滚动**。
   ⚠⚠⚠ **只动间距, 不动字号也不藏字**(符合「宁可缩小不要隐藏」)。 */
.lockbar.free{gap:4px}
.lockbar.free .pill{padding:1px 5px;font-size:11px;line-height:1.35}
/* ⚠ 按钮是**最容易被长文案顶爆**的那个 ⇒ 同样压一档, 且不许折 */
/* ⚠⚠ `button` 基样式是 `padding:8px 16px` 且**没写 font-size**
   ⇒ 解锁按钮光换 padding 还不够, 一个 6 字按钮自己就顶掉 60px 宽
   ⇒ 一行布局下必须连 `font-size` 一起压, 跟胶囊同档。 */
.lockbar .unlock{flex:0 0 auto;white-space:nowrap;padding:3px 8px;font-size:11px}
/* ⚠⚠ 一行布局的**第三道**: 真到极窄屏(≤400px)再降一档字号。
   这是「宁可缩小不要隐藏」的收尾 —— 只缩字号, **一个字都不藏**。
   ⚠⚠⚠ 2026-10-09: gap 4→3 / 内边距各收 1px —— 给「详情含几排·1分」
     腾出 23px。⚠⚠⚠ **只动间距, 不动字号也不藏字** ⇒ 符合
     「宁可缩小不要隐藏」。⚠ 收这一步是因为实测: 按钮并进那句广告后
     最宽那行 380.6px > 预算 358.6px ⇒ 360px 手机上会**横向滚动**,
     老板得往右滑才看得到解锁按钮。
     ⚠⚠⚠ 收完是 **357.6px**, 只剩 **1px** 余量 ⇒ 以后再往这一行加东西
     **必须重算**(自检里有一条宽度预算断言, 见 web/AGENTS.md)。 */
/* ⚠⚠⚴⚴ 订阅卡行(2026-10-15 加「结束时间」后): 又多 6 个字(` →12:58`) ⇒
   >400px 档超预算 18.0px ⇒ **只缩不藏**: 字号与内边距各收一档。
   ⚠⚠⚴⚴ **这一对规则必须写在下面的 @media 之前** —— 同权重时**后写的赢且静默赢**
   (本项目 CSS 头号坑) ⇒ 放后面会把窄屏那档悄悄顶掉, 而窄屏才是最容易横滚的那档。
   ⚠ 这条**只作用于 .sub**, 点卡那一行的数字一个字都没动
   (它的断言照旧读 `.lockbar.free .pill`)。 */
.lockbar.free.sub{gap:3px}
.lockbar.free.sub .pill{padding:1px 4px;font-size:10.5px}
@media (max-width:400px){
  .lockbar{gap:3px;padding:4px 5px}
  .lockbar .idx{font-size:11.5px}
  .lockbar.free{gap:3px}
  .lockbar.free .pill{padding:1px 4px;font-size:10.5px}
  .lockbar .unlock{padding:2px 5px;font-size:10.5px}
  /* ⚠ 订阅卡行窄屏再收一档(它比点卡多 6 个字 ⇒ ≤400px 档超 8.6px) */
  .lockbar.free.sub{gap:2px}
  .lockbar.free.sub .pill{padding:1px 3px;font-size:10px}
}
/* 解锁后的摘要带: **同一套一行规则**(它和锁条是同一个「一行摘要」的两种状态) */
.uband{display:flex;align-items:center;gap:5px;flex-wrap:nowrap;
  padding:0 3px 6px}
.uband .pill{white-space:nowrap;max-width:none;padding:1px 6px;font-size:11px}
/* ⚠ 摘要带里那几个 `.meta` 状态注解**允许折**(它们是解释性长句,
   title 里本来就有全文); 但默认给它们 nowrap 保住一行, 折了也不难看。 */
.uband .meta{white-space:nowrap}
.lockbar .lkmsg.err{color:var(--bad)}
.lockbar .lkmsg.ok{color:var(--ok)}
/* 买完卡回来: 那一行高亮一下(⚠ 不自动扣钱, 只提示) */
.bat.want{border-color:var(--acc);box-shadow:0 0 0 1px var(--acc) inset}
.bat.now{background:#16261a;border-color:#2b4a3a}
/* 解锁后的内容: 摘要带 + 10 人详情 */
.ubody{padding:6px}
/* ⚠⚠⚠ 原来这儿有一条**旧的** `.uband{flex-wrap:wrap}`。⚠⚠⚠ 它在**下面** ——
   CSS 是**后写的赢**, 而且**静默**赢(不报错、不告警) ⇒ 我在上面写的
   `flex-wrap:nowrap` 被它整条覆盖 ⇒ 摘要带照样折成两行, 一看就说「没改成」。
   ⚠ 这是 CSS 里最容易自己骗自己的一处: **同一个选择器写两遍, 旧的留在原地
   等于没改**。改布局前先 `grep -n '<选择器>{'` 数一遍有几条。已删。 */
/* ⚠ 嵌在列表里时**不要抢高度**: .side 是 flex:1 1 0, 在块里得给自然高度,
   否则外层 .scroll 会算出一堆 0 高度的坑。 */
.cols.embed{flex:0 0 auto}
.cols.embed>.side{flex:0 0 auto}
/* ⚠ 嵌在列表里的那一份**不拉伸** —— 列表里每块按内容自然高度才紧凑。
   ⇒ 显式关掉上一条的 flex 拉伸。 */
.cols.embed .scroll{overflow:visible;display:block}
/* ⚠ 嵌在列表里的那一份**不撑**: 列表里按内容自然高度才紧凑 */
.cols.embed .side>.scroll{flex:none}
.cols.embed .scroll>table{flex:none;height:auto}

/* ⚠⚠ 窄屏**只缩字号, 一列都不砍**(主人 2026-10-06: 「字体可以小, 不能不全」)。
   之前那套 `@media{display:none}` 把营地 id/段位/队藏掉, 被打回;
   现在空间全靠「合并列 + 折行」腾, 窄屏再把字号/行高/内边距压一档。 */
@media (max-width:720px){
  :root{--row:24px;--fs:12px;--pad:5px}
}
@media (max-width:400px){
  :root{--row:23px;--fs:11px;--pad:4px}
}
/* ⚠⚠ 折行之后格子会长高, 一屏就放不下了 ⇒ 窄屏**再压一档字号**换行数。
   ⚠ 这是「**宁愿缩小不要隐藏**」的第二半: 先折行, 还嫌挤就缩字号,
   **绝不**退回 ellipsis / display:none。 */
@media (max-width:720px){
  table.fixed td,table.fixed th{font-size:calc(var(--fs) - 0.5px)}
  .tname{font-size:13px}
}
@media (max-width:400px){
  table.fixed td,table.fixed th{font-size:calc(var(--fs) - 1px);padding:3px 2px}
  .tname{font-size:12.5px}
}
/* ⚠ 窄屏把两侧从「左右并排」改成「上下堆叠」: 每侧要放 7 列,
   并排时每侧只剩 ~190px 必然横滚; 堆叠后每侧拿满宽, 而两队各 5 人
   高约 180px ⇒ 合计 360px, 手机竖屏一屏放得下。 */
@media (max-width:600px){
  .cols{flex-direction:column}
}

/* ── ★★★ 「一屏显示全」的高度降档(主人 2026-10-08)
   ⚠ 前面几个 media 都按**宽度**分档, 但「一屏放得下吗」是**高度**问题 ——
     窄而高的手机(iPhone SE 320×568)宽度过档了, 高度却装不下 10 行 + ban。
   ⇒ 这里按 `max-height` 再降两档, 每档都只缩「行高 + 字号 + 内边距」,
     **一个字都不藏、不截**。
   ⚠ 这是「**先缩 → 再折行 → 永不隐藏**」里的「先缩」那一半。 */
@media (max-height:720px){
  :root{--row:22px}
  .scroll table{--row:20px}
  .scroll table th,.scroll table td{font-size:calc(var(--fs) - 1.5px);padding:1px 3px}
  .ban{padding:3px 9px;font-size:calc(var(--fs) - 2px)}   /* ban 行也收 */
  .uband{gap:4px}                                        /* 摘要带收紧 */
  .side>h2{padding:3px 9px;font-size:12px}
}
/* ⚠ 「撑满」是为**手机一屏**服务的。宽屏(`.page` 是 `100dvh`)剩余高度很大
   ⇒ 10 行平分下来每行能到 60px+, 反而难看。
   ⇒ ≥601px 时侧框**贴着内容**, 余量留给页面底部(页面本身能滚)。 */
@media (min-width:601px){
  .side{flex:0 1 auto}
  .side>.scroll{flex:none}
  .scroll>table{flex:none;height:auto}
}
@media (max-height:600px){
  :root{--row:20px;--fs:11px;--pad:3px}
  .scroll table{--row:18px}
  .scroll table th,.scroll table td{font-size:calc(var(--fs) - 1.5px);padding:0 3px;
    line-height:1.15}
  .ban{padding:2px 9px;font-size:calc(var(--fs) - 3px)}
  .side>h2{padding:2px 9px;font-size:11.5px}
}

/* ═══════════════════════════════════════════════════════════════
   来自 templates/admin_cards.html
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* ⚠⚠⚠ **禁掉浏览器的默认选中/长按菜单**（2026-10-15 主人:「屏蔽浏览器的默认选中」）。
   ⚠⚠ 长按卡片出「删除」与**长按选字弹菜单**在手机上**同一个手势** ⇒ 不禁掉就是
   两边一起弹，主人要的是删除。⇒ `user-select:none` + `-webkit-touch-callout:none`
   （后者才是安卓/iOS 长按那个「复制/分享」浮层）。
   ⚠⚠ **代价**：卡号/营地 id 没法再长按选字抄 ⇒ 那两处改成**点一下复制**
   （`.tapcode` / `.tapuid`，模板里挂 `data-copy`，复用 `window.copyText`）。
   ⚠ **输入框必须放开** —— 禁掉选中就等于没法编辑/改写框里的字（搜索框、
     「设到期」那两个都要能选中改）。 */
#main{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
#main input,#main textarea,#main select{
  -webkit-user-select:text;user-select:text;-webkit-touch-callout:default}
#main .tapcode,#main .tapuid{cursor:pointer;color:var(--acc)}
#main .tapuid{font-weight:600;border-bottom:1px dotted var(--acc)}

/* ⚠⚠ 删除按钮：默认**藏起来**，**长按卡片**才在右侧露出来（2026-10-15 主人:
   「发卡管理页的支持长按右边出现红色的删除按钮」）。
   ⚠ `position:relative` 必须加在 `.tcard` 上 —— 不加的话 `.delform` 的
   `position:absolute` 会去找**更外层**的定位祖先，删除按钮直接跑到页面别处去
   （这种错看着像「按钮乱飞」，很难一眼想到是定位祖先的问题）。
   ⚠ 作用域收在 `#main` 里 —— 这套只属于卡密面板，别让 `.tcard` 全站带上定位。 */
#main .tcard{position:relative}
#main .delform{position:absolute;right:7px;top:7px;margin:0;
  opacity:0;transform:translateX(10px);pointer-events:none}
#main .tcard.press{border-color:#6d2731}
#main .tcard.press .delform{opacity:1;transform:none;pointer-events:auto}
#main .delform .pill{background:#2a1114;color:#ff8a80;border-color:#5a2028}
@media (hover:hover){ #main .delform .pill:hover{background:#3b1519;border-color:#7d2a35} }
/* ⚠ 动效（滑出/边框变色）只在这里面 —— 系统关动效时要能**瞬时**切换，
   而「藏/显」本身（`opacity`+`pointer-events`）**不受**影响，仍由上面几条管。 */
@media (prefers-reduced-motion: no-preference){
  #main .delform{transition:opacity .16s ease-out,transform .16s cubic-bezier(.2,.8,.3,1)}
  #main .tcard{transition:border-color .16s ease-out}
}

/* ═══════════════════════════════════════════════════════════════
   来自 templates/landing.html
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* ⚠⚠ 飞书条件(2026-10-15)。⚠ **卡片上只留一个摘要按钮**, 勾选框在共用弹窗里
   —— 64 张卡各挂一行会把面板撑爆, 而条件是**少数人才配**的设置。
   ⚠ 作用域只到 `#nmask` / `.condbox`, **不给 .tcard 加样式** ——
     与 admin_cards 那条「作用域收在 #main」同一理由: 别让这套变成全站默认。 */
/* ⚠ checkbox 自绘(2026-10-15 主人「原生太丑」), 与 admin_cards 的自绘规则一致 */
.condbox{display:inline-flex;align-items:center;gap:4px;font-size:12.5px;
  padding:4px 9px;border:1px solid var(--line);border-radius:999px;
  cursor:pointer;user-select:none;-webkit-user-select:none;
  transition:background .15s,border-color .15s}
.condbox input{appearance:none;-webkit-appearance:none;width:13px;height:13px;
  margin:0;border:1px solid var(--dim);border-radius:4px;flex:0 0 auto;
  background:transparent;position:relative;cursor:pointer}
.condbox input:checked{background:var(--acc);border-color:var(--acc)}
.condbox input:checked::after{content:"";position:absolute;left:3.5px;top:.5px;
  width:3.5px;height:7px;border:solid #0f1115;border-width:0 1.8px 1.8px 0;
  transform:rotate(42deg)}
.condbox input:focus-visible{outline:2px solid var(--acc);outline-offset:1px}
.condbox:has(input:checked){border-color:var(--acc);background:rgba(255,255,255,.04)}
/* ⚠⚠⚴⁴ 条件按钮: 原来**单独立了一套字号(12.5px)与 padding(4px 12px)** ⇒ 在一排
   ⚠ 11px 的按钮里像另一个控件。⚠⚠⚴⁴ ⚠ 但它的文字是**主人配的条件**(数据!)
   ⚠ ⇒ **不许缩、不许藏** ⇒ 只把盒子统一, 文字照旧。 */
.tfoot .tsend.condbtn{padding:3px 4px;font-size:11.5px;white-space:nowrap}
.condwarn{font-size:11.5px;color:#d8a13a}
/* ⚠ 手机上点 label 别触发选中区(长按是「复制」的姿势) */
.condbox{-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}
/* ⚠ 弹窗内的排版。⚠ **复用 `.modal`/`.pill`**(主人认可的观感), 只加内容区。
   ⚠ 不用 `position:fixed;inset:0` 居中 —— 软键盘会把它顶出屏幕
     (见 base.html ModalCtrl 注释: 弹窗一律 `padding-top:9vh`)。 */
#nmask .modal{max-width:520px}
.nsub{margin:2px 0 10px;font-size:13px;color:var(--dim)}
.nrow{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 10px}
.condbox{font-size:13.5px;padding:6px 12px}
.nhint{margin:0 0 10px;font-size:12.5px;color:var(--dim);line-height:1.6}
.nhint b{color:var(--fg);font-weight:600}
.nfoot{display:flex;gap:8px;align-items:center}

/* ⚠ 搜索行: 输入框占满, 「查」按钮贴右边 —— 主人是站在手机上一手打一手点 */
.probe{display:flex;gap:6px;flex:0 0 auto;margin:8px 0 0}
.probe .pinput{flex:1;min-width:0;padding:9px 10px;border-radius:8px;
  border:1px solid var(--line);background:#12151b;color:var(--fg);font-size:14px}
.probe .pinput:focus{outline:none;border-color:var(--acc)}
/* ⚠⚠⚠⚠⚠ 2026-10-11 主人: 「输入框和搜索按钮太别扭了, **按钮比例太小了**」
   *   ⚠⚠⚠ **前两版我把方向做反了**: 为解决 loading 的「显示不全」, 把按钮
   *     锁成 `34×34` 的**小方块** ⇒ 跟 36px 高的输入框并排, 像「大输入框旁
   *     贴了个小方块」, **比例失衡** ⇒ 主人说「别扭」。
   *   ⇒ 回退成**正常按钮比例**: 高度跟输入框一致(`align-items:stretch`),
   *     宽度 `min-width:76px`、**带文字「搜索」** —— 横长的按钮才配横长的输入框。
   *   ⚠⚠ **带文字就不怕「显示不全」**: 常态有字撑宽度, loading 时
   *     `color:transparent` 把字隐掉换转圈 ⇒ **盒子尺寸恒定**, 不再有
   *     「换字形变窄」那种塌陷(那才是当初 34px 的由来)。
   *   ⚠ 高度用 stretch + `min-height` 而**不写死 px** —— 字号/缩放/字体栈
   *     一变就又不对齐。⚠ 横向锁 `min-width` 是给 loading 用的, 与纵向对齐是两件事。 */
.probe .pbtn{flex:0 0 auto;font-size:14px;cursor:pointer;text-align:center;
  min-width:76px;padding:0 14px;min-height:36px;
  display:flex;align-items:center;justify-content:center;box-sizing:border-box;
  white-space:nowrap}
/* ⚠⚠⚠ loading 态: **CSS 转圈**, 不换文字(`…`/换字都会改渲染宽度 ⇒ 又是「显示不全」;
   *   转圈是**纯图形**, 配合上面的 min-width ⇒ 盒子尺寸**恒定**)。
   *   ⚠⚠⚠ `color:transparent` + `font-size:0`: 按钮里是**裸文本节点**(不是元素),
   *     `.busy > *{visibility:hidden}` **选不中它**(我第一版就写错过 ⇒ 转圈与
   *     文字同时显示, 挤在窄盒子里 = 还是显示不全)。
   *   ⚠⚠⚠ **`font-size:0` 不会让盒子塌陷**: 宽度由 `min-width:76px` 撑着,
   *     高度由 stretch/min-height 撑着 ⇒ 两个字都不占, 盒子纹丝不动。
   *   ⚠ `prefers-reduced-motion` 下转圈停转但**仍显示**静态环 —— 按钮不能什么都没有。 */
.probe .pbtn.busy{pointer-events:none;opacity:.75;
  color:transparent;font-size:0;position:relative}
.probe .pbtn.busy::after{
  content:'';position:absolute;top:50%;left:50%;margin:-7.5px 0 0 -7.5px;
  width:15px;height:15px;border-radius:50%;
  border:2px solid rgba(255,255,255,.28);border-top-color:var(--acc);
  animation:pbtnspin .7s linear infinite}
@keyframes pbtnspin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .probe .pbtn.busy::after{animation:none}
}
/* ⚠ battleId 那行(最后一行): 用一条上边框把它和上面那些属性**视觉分开** ——
   它不是「又一个属性」, 是「这人在干什么」的一句话答案。 */
table.fixed tr.sep th,table.fixed tr.sep td{border-top:1px solid var(--line)}
table.fixed tr.sep code{font-size:11px;word-break:break-all}
table.fixed td.bad code{color:#ff9a8f}
/* ⚠ 区服角色列表: 每个角色**两列**(区服 / 昵称), 昵称占大头。
   ⚠ 「营地昵称 + roleId」用小字灰字 —— 它是次要信息, 但必须**在**:
   主人得靠 roleId 认「这个号我盯过」(那才是真锚点)。 */
table.fixed tr.rhead th,table.fixed tr.rhead td{border-top:1px solid var(--line)}
table.fixed tr.rhead td{font-size:11px;line-height:1.5}
table.fixed tr.rhead b{font-size:14px}
/* ⚠⚠ 折叠区现在是**表外独立块**(`.rolemore`), 不再是表格里的 `tr.rmore` ——
   `tr.rmore` 那条样式已随 foster parenting 修复一起删掉, 留着就是死代码。
   ⚠ `.rolemore` 的 summary 沿用 base.html 的 `.keybox>summary`(▸/▾ + 琥珀色),
   这里只补外边距, 让它和上面的角色表之间有呼吸。 */
.rolemore{margin:2px 0 6px}
/* ⚠ 「(无游戏内名)」不该和真名字一样粗 —— 它是**没查到**, 不是「名字叫这个」 */

/* ═══════════════════════════════════════════════════════════════
   来自 templates/landing.html (第 2 段)
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* 搜索弹窗: **复用 `base.html` 的 `.mask`/`.modal`**(与买卡弹窗同观感),
   这里只加宽 + 给结果区滚动。
   ⚠ 别自造配色 —— `.modal` 是深色 `#171a21`, 自造容易回退成浅色(很丑)。
   ⚠ `.modal` 自己的 `padding:12px` 在这里清零, 由内部分段各自给 padding。 */
.mask .modal.swide{max-width:640px;padding:0;gap:0;max-height:88vh;overflow:hidden}
.swide h3{padding:10px 12px;border-bottom:1px solid var(--line);font-size:14px}
.swide .probe{padding:10px 12px;margin:0;border-bottom:1px solid var(--line)}
/* ⚠ 结果区自己滚(`.modal` 限了高度), 不然长表格会被裁掉又没滚动条 */
.swide .sbody{overflow:auto;-webkit-overflow-scrolling:touch;padding:0 12px 12px}

/* ⚠ 「复制带卡链接」: 与「发给老板 →」并排, 但**弱一档**(它不是主路) */
.tfoot .tsend.linkbtn{opacity:.78}
.tfoot .tsend.linkbtn:hover{opacity:1}

/* ⚠⚠⚴⁴⚠⚠ 「⏸ 不盯了」**不是不可逆操作** —— 有「▶ 恢复轮询」, 随时能加回去。
   ⚠⚠⚴⁴⚠⚠ 2026-10-12 那条注释写着「它是**唯一不可逆**的操作(删除撤不回来)」
   ⚠ ⇒ **与事实不符**。⚠⚠⚴⁴⚠⚠ 而「红框 + 红块」这套语言在本项目里是留给
   ⚠   **卡密面板的真删除**(`.delform`, 长按才出现)的; 把可撤销的操作也画成
   ⚠   「危险」⇒ 看卡片会以为点一下这个人就没了 ⇒ **误导, 而且是那种
   ⚠   「功能全正常、页面也不报错」的误导**(本项目最贵的一类)。
   ⚠⇒ 改成**红字 + 极淡的边**: 仍然一眼看得出「它会改变状态」, 但不再像删除。
   ⚠  ⚠ 口味想改回来告诉玲依 —— 那是**语义**问题, 不是样式问题。 */
.tfoot .tsend.delbtn{color:#e0836f;border-color:rgba(224,131,111,.22)}
.tfoot .tsend.delbtn:hover{color:#fff;background:#8e2f22;border-color:#8e2f22}

/* ═══ 账号信息表(2026-10-10) ═══ */
.aicard{margin:10px 0 6px;line-height:1.7}
.aicard b{font-size:15px}
/* ⚠ 表格**: 字号压到能塞进手机一行**, 但**不许藏字** ——
   时间是「2026-10-08 13:14」这种绝对串, 一行放不下就让它换行。 */
.aitbl{width:100%;border-collapse:collapse;font-size:12.5px}
/* ⚠⚠⚠ 2026-10-11 主人: 「表头背景色也不对, 和卡片背景不搭」
   *   ⚠⚠ **根因是继承了全局 `th` 规则**(base.html: `th{position:sticky;
   *     top:0;background:#1c2029;…}`) —— `.aitbl th` 原来只覆盖了
   *     **字号和颜色**, **背景色没覆盖** ⇒ 沿用 `#1c2029`。
   *   ⚠ 色板里三个相近但不同的深灰: 卡片 `#171a21` / 正文行 `#1b1f27` /
   *     表头 `#1c2029` ⇒ 肉眼就是「不搭」(不是错, 是**没对齐**)。
   *   ⇒ 显式给 `#171a21`(同卡片)。⚠ `position:sticky` 也一并去掉 ——
   *     这张表**不滚动**(`.aitbl{max-height:none}`), sticky 纯属副作用。
   *   ⚠⚠ **不许用 `overflow:hidden` 截字**(本项目铁律: 宁可折行也不藏字)。 */
.aitbl th,.aitbl td{padding:5px 6px;border-bottom:1px solid var(--line);
    text-align:left}
.aitbl th{font-size:11.5px;color:var(--dim);font-weight:600;
    /* ⚠⚠ 2026-10-11: 与 `table.fixed th` **同一个道理** ——
       这张表也**裸挂在 `#pres`** 里(不在 `.scroll`/`.tcard`),
       ⇒ 周围底色是页面 `--bg`, 给 `#171a21` 会比周围**亮一档**
       = 主人说的「表头是灰的」那个灰块。
       ⇒ `transparent` 融进去, 边界只靠底线。 */
    background:transparent;position:static;
    border-bottom:1px solid var(--line)}
/* ⚠⚠ 同源问题: 原来这里有 `white-space:nowrap` ⇒ **长内容(绝对时间/长 id)
   *   会把列撑爆、溢出到框外**(主人 10-11 报的「显示不全」是同一个病根)。
   *   ⇒ 允许换行; 真要单行的列用 `.mono` 那一档单独控制。 */
.aitbl td{white-space:normal;overflow-wrap:anywhere}
/* ⚠ 等宽字体给时间与 id: 数字对齐才好读(省略「绝对时间」会不会认错列) */
.aitbl td.mono{font-variant-numeric:tabular-nums;letter-spacing:.2px}
.aitbl .scroll,.scroll .aitbl{max-height:none}
/* ⚠ 「位置」可能很窄(2字省名) ⇒ 给个最小宽, 别让列被挤没 */
.aisum{margin-top:8px;line-height:1.9}
.aifoot{margin:8px 0 2px;font-size:11.5px;line-height:1.6}
.pill.warn{color:#ffb84d;border-color:#6b4a12}
@media (max-width:420px){
  .aitbl{font-size:11.5px}
  .aitbl th,.aitbl td{padding:4px 4px}
}

/* ═══════════════════════════════════════════════════════════════
   来自 templates/person.html
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* ★ 顶栏「补全本页待补的局」(2026-10-14 主人)：订阅卡老板也能补脱敏行。
   ⚠ 放在页首说明块里，**不占行宽** —— 老板页是「一局一行」的胶囊布局，
     行内再加按钮会挤爆宽度预算（最长行 358.6px @ ≤400px 档）。 */
button.bdbatch{background:transparent;border:1px solid #3a4356;border-radius:6px;
  color:#c8d2e0;font:inherit;font-size:12px;line-height:1.6;padding:2px 8px;
  margin-top:6px;cursor:pointer;white-space:nowrap}
button.bdbatch:hover:enabled{border-color:#d8a24a;color:#f0d9a8}
button.bdbatch:disabled{opacity:.5;cursor:default}
button.bdbatch.ok{border-color:#3f7d52;color:#8fd6a4}
button.bdbatch.no{border-color:#7d3f3f;color:#d68f8f}

/* ═══════════════════════════════════════════════════════════════
   来自 templates/person_old.html
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* 补全按钮: 要**一眼像能点的**, 又不能抢「详情」链接的视觉重量 */
button.bdfix{background:transparent;border:1px solid #3a4356;border-radius:6px;
  color:#c8d2e0;font:inherit;font-size:11px;line-height:1.5;padding:0 5px;cursor:pointer;
  white-space:nowrap}
button.bdfix:hover{border-color:#d8a24a;color:#f0d9a8}
button.bdfix[disabled]{opacity:.5;cursor:default}
button.bdfix.ok{border-color:#3f7d52;color:#8fd6a4}
button.bdfix.no{border-color:#7d3f3f;color:#d68f8f}
/* ⚠ 2026-10-15 主人:「导出按钮也很乱, 信息和操作胶囊很乱」
   ⇒ 导出收进一个折叠; 信息独占一行、纯文字(不占胶囊)。 */
details.exp{display:inline-flex;flex-direction:column;align-items:flex-start;gap:4px}
details.exp>summary{list-style:none;cursor:pointer}
details.exp>summary::-webkit-details-marker{display:none}
details.exp[open]>summary{color:#ffd08a}
.topinfo{flex:1 1 100%;line-height:1.6}
.topinfo b{color:var(--acc)}
/* ⚠ 软删除横幅(2026-10-15)。⚠ **只加在 /m/(主人自己看)**,
   客户页 `/p/` 不出现任何「已删除」字样(主人: 「客户不需要知道被删除了」)。 */
.msg.delshow{border-color:#5a2a24;background:#241110;color:#ffb9a8}
.msg.delshow a{color:var(--acc)}

/* ═══════════════════════════════════════════════════════════════
   来自 templates/person_old.html (第 2 段)
   ⚠⚠ 2026-10-15 从模板搬出来。**顺序有意义**: base 必须在最前,
   否则页面样式会被外壳样式盖住(同权重时后者赢)。
   ⚠ 这里放的都是**无 Jinja** 的纯 CSS —— 之前 CSS 住在 Jinja 里, 注释里
   敲一个定界符就会**整站 500**(项目踩过两次)。搬出来那颗雷就没了。
   ⚠ 页面之间无所谓(同一时刻只渲染一个), 只有 base↔页面的次序要紧。
   ═══════════════════════════════════════════════════════════════ */

/* 补全按钮: 要**一眼像能点的**, 又不能抢「详情」链接的视觉重量 */
button.bdfix{background:transparent;border:1px solid #3a4356;border-radius:6px;
  color:#c8d2e0;font:inherit;font-size:11px;line-height:1.5;padding:0 5px;cursor:pointer;
  white-space:nowrap}
button.bdfix:hover{border-color:#d8a24a;color:#f0d9a8}
button.bdfix[disabled]{opacity:.5;cursor:default}
button.bdfix.ok{border-color:#3f7d52;color:#8fd6a4}
button.bdfix.no{border-color:#7d3f3f;color:#d68f8f}
