/* 翼起驭风 · 预览样式(从 preview.html 的 <style> 抽出,2026-09-24) */
/* finesse · register=h5-container+product · morph=A-app-shell · 参考:理想汽车 App
 * 素材:真实无人机摄影(本地 assets/)+ Lucide 线性图标 · 版式:白底黑字发丝线 · 克制
 * 执照选择页迭代:机型四封面卡(2×2)+执照类别单选卡+吸底确定栏 · 全页 16px 留白 · CC 图见 assets/covers/CREDITS.md */
/* ==========================================================================================
   设计系统 v2 · 令牌层(2026-09-28「所有界面 UI 都重做」的 P2:学员端外壳)
   三端(学员端 H5 / 小程序 / 后台 PC)共用同一套**语义令牌名**,只是取值不同 ——
   组件只引用令牌,所以换皮是一处改、全局生效。
   铁律三条:① 不出现纯 #fff / #000(中性色一律带一点青);② 线一律半透明;
             ③ 状态色必须配一档淡底(-wash),深色模式下同时改值,不靠各页面打补丁。
   为什么页底要单独一个 --page:原来 --bg 同时当"页底"和"卡面"用(页底也是纯白),
   卡片只能靠描边区分,整屏看过去是一块白板。拆出 --page 之后靠**亮度分层**,
   深色模式下同样成立(页底比卡面更暗)。--bg 仍是卡面值,86 处把它当卡面用的规则不用动。
   ========================================================================================== */
:root{
  --page:#EEF3F3;      /* 页底:带青的浅灰(卡片浮在上面才有层次) */
  --bg:#FCFEFE;        /* 卡面 / 顶栏 / TabBar:近白但带一点青,替掉纯 #FFFFFF */
  --panel:#F2F7F7;     /* 次级面:卡内嵌格 / 图标砖底 / 分段控件底 / 进度条槽 */
  --gap:#F2F7F7;
  --line:rgba(15,22,24,.09);    /* 发丝线:半透明(原来 #EEEFF1 是硬色,深色/长辈版得各写一遍) */
  --line-2:rgba(15,22,24,.16);  /* 重一档的线:输入框 / 分段控件 / 开关 */
  --ink:#0F1618; --ink2:#4E5A5D; --ink3:#616D6F;  /* ink3 两度压深(#9AA0AA→#87938F→#616D6F):
                                                   * 它是全 App 的"提示文字"色,而 #9AA0AA 在近白底上只有
                                                   * 2.6:1、#87938F 也只有 3.1:1 —— 小灰字读不清,
                                                   * 正是"看着像廉价模板"的第一来源。现在 ≥4.78:1(过 WCAG AA),
                                                   * 层级改由字号与字重承担(见 docs/UI-重做计划.md §1) */
  --t:0; /* 长辈版过渡进度(0 常规 → 1 长辈版):过渡时由 JS 逐帧写在实际可见的那几块上 */
  --f:1; /* 基础字号系数;.phone 与各可见块上会重写成 calc(1 + .18*var(--t)) 以便逐帧插值 */
  --accent:#1C5CE4; --accent-ink:#1746B8; --accent-soft:rgba(28,92,228,.09);
  --accent-wash:rgba(28,92,228,.05);   /* 更淡一档:大面积底色 / 页头渐变,不抢内容 */
  --green:#52B8A4; --amber:#B7791F; --red:#E5484D;
  --r:16px; --r-lg:20px;               /* 圆角抬一档:14/18 → 16/20,和后台(9/13/18)拉开手机端与 PC 端的密度差 */
  /* 投影一律带色:两层(贴地 1px + 散开 24px),不用纯黑 */
  --shadow:0 1px 2px rgba(15,34,36,.05),0 10px 24px -16px rgba(15,34,36,.14);
  /* 浮在内容之上的提示卡用半透明玻璃底:压住下面的面板时还能看见底下,而不是糊成一块白 */
  --glass:rgba(252,254,254,.76); --glass-line:rgba(15,22,24,.07);
  /* ---- Ant Design 式设计令牌:统一阴影层次 / 缓动 / 语义色,减少各处手调造成的参差 ---- */
  --sd-1:var(--shadow);
  --sd-2:0 3px 6px -4px rgba(17,19,24,.12),0 6px 16px rgba(17,19,24,.08),0 9px 28px 8px rgba(17,19,24,.05);
  --sd-3:0 12px 32px -12px rgba(17,19,24,.22);
  --ease:cubic-bezier(.645,.045,.355,1);
  --ease-spring:cubic-bezier(.34,1.56,.64,1);
  --ok-bg:rgba(82,184,164,.12);   --ok-fg:#1B6B57;   /* 绿/红都按"字压在自己的淡底上也要 ≥4.5:1"取值:
                                                     * 原来 #D74448 压 10% 红底只有 3.8:1,chip 上的小字是虚的 */
  --warn-bg:rgba(183,121,31,.12); --warn-fg:#8A5A0E;
  --err-bg:rgba(229,72,77,.10);   --err-fg:#B8232B;   /* 实色填充仍用 --red(#E5484D);两者分工:实底 / 浅底上的字 */
  --info-bg:rgba(28,92,228,.10);  --info-fg:#1C5CE4;
  /* 压在高饱和实色(状态色 / 品牌色)上的文字。为什么单独一个令牌:浅色下它是近白,深色下
     也不能跟着 --bg 一起变暗 —— 红色/琥珀色两套主题下都是同一块实色,字必须一直是浅的。 */
  --on-solid:#FBFDFD;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
/* 可点击组件禁止文字选中(避免双击/长按出现蓝色"复制"高亮);输入框仍可选中编辑 */
.gs-btn,.shape-seg span,.btn-black,.pb,.kpi-chip,.chip,.seg span,.filter span,.bank-head,.m-card,.lv-card,
.func,.mode,.row,.q .q-btn,.btn,.fab,.b-btn,.gs-shape,.subject-row,.cell,.stepper,.step-row,.lic-sum,
.btn-ghost-s,.btn-solid-s,.c-btns div,.pd-actions .btn,.pair-btns .pb,.ht-count,.race-tabs span,.top-pill,.bk-btn{-webkit-user-select:none;user-select:none}
html,body{height:100%;overflow-x:clip}
body{overflow:hidden;background:#0b0c0e;display:flex;align-items:center;justify-content:center;
     font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","MiSans","Microsoft YaHei",sans-serif;color:var(--ink)}
.phone{position:relative;width:100%;height:100%;overflow:hidden;background:var(--page);display:flex;flex-direction:column}
/* 页内状态栏的样式:随那条 DOM 一起删了(真机上会和系统状态栏叠两层)。留注释免得有人照着旧截图又加回来。 */
.view{display:none;flex:1;min-height:0}
.view.active{display:flex;flex-direction:column}
.app{flex:1;overflow-y:auto;overflow-x:clip;scrollbar-width:none;padding-bottom:calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 64px)}
.app::-webkit-scrollbar{display:none}
/* 通用 */
.sec-h{font-size:calc(15px*var(--f));font-weight:700;color:var(--ink);padding:14px 20px 8px}
.row{display:flex;align-items:center;gap:12px;padding:14px 20px;background:var(--bg);border-bottom:1px solid var(--line)}
.row:last-child{border-bottom:none}
.row .r-ic{width:32px;height:32px;border-radius:10px;background:var(--panel);border:1px solid rgba(17,19,24,.04);
            display:flex;align-items:center;justify-content:center;color:var(--ink);flex:none}
.row .r-t{flex:1;min-width:0}
.row .r-t b{font-size:calc(14px*var(--f));font-weight:600;display:block;color:var(--ink)}
.row .r-t span{font-size:calc(11.5px*var(--f));color:var(--ink3);display:block;margin-top:2px}
.row .r-v{font-size:calc(12.5px*var(--f));color:var(--ink2);font-weight:600;white-space:nowrap}
.row .chev{color:#C6C9CE}
.chip{display:inline-flex;align-items:center;padding:3px 8px;border-radius:6px;font-size:calc(11px*var(--f));font-weight:600;line-height:1.5}
.chip-green{background:rgba(82,184,164,.14);color:#217A63}
.chip-amber{background:rgba(183,121,31,.14);color:#8a5a0e}
.chip-gray{background:var(--panel);color:var(--ink2)}
.chip-teal{background:var(--accent-soft);color:var(--accent)}
/* 通用小按钮(自定义弹层等,此前缺失定义) */
.btn-solid-s{height:46px;border-radius:13px;background:var(--ink);color:var(--bg);display:flex;align-items:center;
             justify-content:center;font-size:calc(14px*var(--f));font-weight:700;cursor:pointer}
.btn-ghost-s{height:46px;border-radius:13px;background:var(--panel);color:var(--ink);display:flex;align-items:center;
             justify-content:center;font-size:calc(14px*var(--f));font-weight:600;cursor:pointer}
.btn-solid-s:active,.btn-ghost-s:active{transform:scale(.97)}
/* 深色模式开关 */
.switch{width:46px;height:28px;border-radius:999px;background:var(--panel);border:1px solid var(--line);
        position:relative;flex:none;transition:background .2s ease;cursor:pointer}
.switch i{position:absolute;top:2px;left:2px;width:22px;height:22px;border-radius:50%;background:#fff;
          box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .25s cubic-bezier(.34,1.56,.64,1)}
.switch.on{background:var(--accent)}
.switch.on i{transform:translateX(18px)}
/* ---------- 深色模式 ----------
 * 深色下也是"亮度分层":页底比卡面更暗一层(--page < --bg < --panel),
 * 而不是靠投影 —— 深色背景上的黑色投影根本看不见,只会把界面糊脏。 */
body.dark{
  --page:#0B1113; --bg:#151C1F; --panel:#1C2528; --gap:#1C2528;
  --line:rgba(255,255,255,.09); --line-2:rgba(255,255,255,.17);
  --ink:#E9EFF0; --ink2:#A9B4B7; --ink3:#8B979A; /* 弱文字保持 ≥4.5:1(见 §26 的对比度审计) */
  --accent:#5B8DFF; --accent-ink:#8FB0FF; --accent-soft:rgba(91,141,255,.16);
  --accent-wash:rgba(91,141,255,.07);
  /* 状态色在深色下整体提亮(原来这些值散在各处的 body.dark 补丁里,一条一条写;
     收进令牌之后,凡是引用 --ok-fg/--err-fg 的组件自动就是对的) */
  --ok-bg:rgba(95,208,176,.15);   --ok-fg:#5FD0B0;
  --warn-bg:rgba(229,181,102,.15); --warn-fg:#E5B566;
  --err-bg:rgba(240,138,142,.15);  --err-fg:#F08A8E;
  --info-bg:rgba(91,141,255,.15);  --info-fg:#8FB0FF;
  --shadow:0 1px 2px rgba(0,0,0,.4),0 12px 28px -18px rgba(0,0,0,.7);
  --glass:rgba(21,28,31,.78); --glass-line:rgba(255,255,255,.10);
}
body.dark .m3d{background:linear-gradient(180deg,#1B1E23 0%,#22262C 100%)}
body.dark .trip-map{background:linear-gradient(180deg,#1B1E23 0%,#21252B 100%)}
body.dark .cc-head{background:linear-gradient(135deg,#1C1F24,#22262C)}
body.dark .drone-stage{background:linear-gradient(180deg,#1C1F24 0%,#22262C 100%);border-color:var(--line)}
body.dark .stage-photo{background:linear-gradient(180deg,#1C1F24,#22262C)}
body.dark .model-switch{background:rgba(242,244,246,.12)}
body.dark .model-switch span.on{background:#F2F4F6;color:#14161A}
body.dark .chip-green{color:#5FD0B0}
body.dark .chip-amber{color:#E5B566}
body.dark .chip-red{color:#F08A8E}
body.dark .ms-clear{background:rgba(255,255,255,.22)}
body.dark .lv-radio{border-color:#3A4048}
body.dark .score-chip{background:rgba(82,184,164,.16);color:#5FD0B0}
body.dark .searchbar input::placeholder,body.dark .ms-input input::placeholder{color:var(--ink3)}
body.dark .exam-bar .back{background:var(--panel)}
body.dark .switch i{background:#F2F4F6}
/* 深色修补:柱状图/按压态/箭头/加载圈/视角标签/绿色角标 */
body.dark .bars .b i{background:#3A4048}
body.dark .q .q-btn:active,body.dark .q .q-btn:hover{background:#262B32}
body.dark .row .chev,body.dark .joined-empty .ic,body.dark .ms-empty .ic{color:var(--ink3)}
body.dark .stage-photo .spinner,body.dark .m-card .m3d-loading{border-color:rgba(242,244,246,.18);border-top-color:var(--accent)}
body.dark .lv-card.on .lv-cam{background:rgba(242,244,246,.16)}
body.dark .me-head .m-name .lv,body.dark .g-ic.green{color:#5FD0B0}
body.dark .f-ic.f-teal{color:#247DFF}
body.dark .f-ic.f-blue{color:#7DA2F5}
body.dark .f-ic.f-amber{color:#E5B566}
body.dark .f-ic.f-red{color:#F08A8E}
body.dark .f-ic.f-green{color:#5FD0B0}
body.dark .f-ic.f-purple{color:#A78BFA}
body.dark .analysis .ok,body.dark .analysis .an-score,body.dark .analysis .an-ic{color:#5FD0B0}
/* 航线图名称标注深色提亮 */
body.dark .gs-n-home{fill:#F08A8E}
body.dark .gs-n-apex{fill:#7DA2F5}
body.dark .gs-n-seat{fill:#5FD0B0}
body.dark .m-card:hover,body.dark .bank-card:hover,body.dark .race-card:hover,body.dark .proj-card:hover,
body.dark .class-card:hover,body.dark .signup-row:hover,body.dark .race-item:hover{border-color:#3A4048}
/* ---------- 长辈版(大字号 · 高对比 · 大触控) ----------
 * --t = 过渡进度(0 常规 → 1 长辈版):字号由 --f:calc(1 + .18*var(--t)) 统一缩放,
 * 控件尺寸写成 calc(基准 + 增量*var(--t)),对比度色随类一起切换。
 * 类挂在 .phone 上(最终态),过渡时再给「当前可见的几块」逐帧写内联 --t —— 选择器用 .elder X,
 * 两种挂法都生效。这样每帧只重排可见的那 ~200 个节点(实测 0.1ms),才敢做真正的字号渐变;
 * 若把变量挂在 html 上逐帧改,每帧要重排 1900 个节点(实测 98ms),那就是之前卡顿的根源。 */
/* 可见块自己算 --f(而不是只挂在 html/.phone 上):这样过渡时给它们写内联 --t 就能逐帧插值字号。 */
.phone,.view,.layer,.sheet,.tabbar{--f:calc(1 + .18*var(--t))}
.elder{--t:1;--ink2:#3D434C;--ink3:#565D68;--line:#D9DCE1;--page:#EAF0F0;--line-2:rgba(15,22,24,.24)}
body.dark .elder,body.dark.elder{--ink2:#BEC5CD;--ink3:#929AA4;--line:#353B43;--page:#080D0F;--line-2:rgba(255,255,255,.24)}
.elder .row{padding-top:calc(14px + 3px*var(--t));padding-bottom:calc(14px + 3px*var(--t))}
.elder .btn-black,.elder .btn-solid-s,.elder .btn-ghost-s,.elder .btn-ghost-big{height:calc(46px + 6px*var(--t))}
.elder .bk-btn,.elder .ri-actions .btn-ghost-s,.elder .ri-actions .btn-solid-s,
.elder .race-card .ri-actions .btn-ghost-s,.elder .race-card .ri-actions .btn-solid-s{height:calc(34px + 6px*var(--t))}
.elder .cc-btns div{height:calc(36px + 6px*var(--t))}
.elder .pj-body .pj-actions div{height:calc(32px + 6px*var(--t))}
.elder .opt{padding:calc(14px + 2px*var(--t)) 14px}
.elder .opt .badge{width:calc(26px + 4px*var(--t));height:calc(26px + 4px*var(--t))}
.elder .exam-foot .side{width:calc(52px + 6px*var(--t))}
.elder .q .q-btn{width:calc(52px + 6px*var(--t));height:calc(52px + 6px*var(--t))}
.elder .func .f-ic,.elder .grid4 .g .g-ic{width:calc(46px + 6px*var(--t));height:calc(46px + 6px*var(--t))}
.elder .searchbar{height:calc(40px + 6px*var(--t))}
.elder .ms-input{height:calc(42px + 6px*var(--t))}
.elder .f-input{height:calc(44px + 6px*var(--t))}
.elder .f-area{height:calc(120px + 20px*var(--t))}
.elder .gs-field input{height:calc(42px + 6px*var(--t))}
.elder .code-btn{height:calc(44px + 6px*var(--t))}
.elder .comment-bar input,.elder .comment-bar .send{height:calc(42px + 6px*var(--t))}
.elder .tabbar button{height:calc(52px + 6px*var(--t))}
.elder .stepper .st-btn{width:calc(28px + 6px*var(--t));height:calc(28px + 6px*var(--t))}
.elder .switch{width:calc(46px + 4px*var(--t));height:calc(28px + 3px*var(--t))}
.elder .switch i{width:calc(22px + 3px*var(--t));height:calc(22px + 3px*var(--t))}
.elder .switch.on i{transform:translateX(calc(18px + 3px*var(--t)))}
.elder .chip{padding:calc(3px + 1px*var(--t)) calc(9px + 1px*var(--t))}
.elder .seg span{padding:calc(8px + 3px*var(--t)) 0}
.elder .race-tabs span,.elder .dt-tabs span{padding:calc(9px + 2px*var(--t)) 0}
.elder .today-bar .h-btn{padding:calc(10px + 2px*var(--t)) calc(18px + 2px*var(--t))}
.elder .exam-bar .back{width:calc(38px + 6px*var(--t));height:calc(38px + 6px*var(--t))}
.elder .gs-btn{height:calc(48px + 6px*var(--t))}
.elder .pair-btns .pb{height:calc(46px + 6px*var(--t))}
.elder .lic-foot .btn-black{height:calc(48px + 6px*var(--t))}
.elder .faq-q{padding:calc(14px + 2px*var(--t)) 0}
.elder .avatar-opt{padding:calc(14px + 2px*var(--t)) 4px}
.elder .ms-empty-btn{width:calc(120px + 12px*var(--t));height:calc(38px + 6px*var(--t))}
.elder .mode{padding:calc(12px + 2px*var(--t))}
.elder .kpi-chip{padding:calc(10px + 2px*var(--t)) 6px}
.elder .badge{padding:calc(14px + 2px*var(--t)) 6px calc(12px + 2px*var(--t))}
.elder .lv-radio{width:calc(22px + 2px*var(--t));height:calc(22px + 2px*var(--t))}
.elder .mode-pill{padding:calc(8px + 2px*var(--t)) calc(12px + 2px*var(--t))}
.elder .bars{height:calc(40px + 8px*var(--t))}
.elder .sec-btn{padding:calc(6px + 2px*var(--t)) calc(12px + 2px*var(--t))}
.elder .create-cta{padding:calc(14px + 3px*var(--t))}
.elder .pick-chips span{padding:calc(6px + 2px*var(--t)) calc(12px + 2px*var(--t))}
/* ---------- 地面站:6 分钟考试倒计时(最后 2 分钟边框加速变红) ---------- */
.gs-timer{flex:none;display:flex;align-items:center;gap:5px;padding:6px 11px;border-radius:999px;cursor:pointer;
          background:var(--panel);color:var(--ink);font-size:calc(12.5px*var(--f));font-weight:700;
          border:1.5px solid transparent;white-space:nowrap;font-variant-numeric:tabular-nums;
          transition:color .3s linear,background .3s linear,border-color .3s linear,opacity .2s ease}
.gs-timer .ic{width:14px;height:14px}
.gs-timer b{font-variant-numeric:tabular-nums;letter-spacing:.02em}
.gs-timer.warn{color:var(--gs-tone,#B7791F);border-color:var(--gs-tone,#B7791F);background:rgba(183,121,31,.12)}
.gs-timer.danger b{animation:gsTickPop var(--gs-beat,.4s) ease-out infinite}
.gs-timer.over{color:var(--err-fg);border-color:var(--red);background:rgba(229,72,77,.12)}
.gs-timer.idle{border-style:dashed;border-color:var(--line);color:var(--ink3);background:var(--bg)}
.gs-timer.idle b{color:var(--ink2)}
.gs-timer.paused{opacity:.55}
.gs-timer.paused b{animation:none}
@keyframes gsTickPop{0%{transform:scale(1)}14%{transform:scale(1.14)}100%{transform:scale(1)}}
/* 整屏边框渐晕(高德超速那种):四周内侧红色柔光,和计时同步呼吸,越接近 0 越红越快 —— 全场只有这一处在闪 */
#gsEdge{position:absolute;inset:0;z-index:9;pointer-events:none;border-radius:inherit;opacity:0;
        transition:opacity .3s linear}
#gsEdge.warn{opacity:1;animation:gsEdgeFlash var(--gs-beat,1.6s) ease-in-out infinite;
             box-shadow:inset 0 0 0 3px var(--gs-tone,#B7791F),inset 0 0 22px 2px var(--gs-glow,rgba(183,121,31,.5))}
#gsEdge.warn.danger{box-shadow:inset 0 0 0 5px var(--gs-tone,#E5484D),inset 0 0 36px 6px var(--gs-glow,rgba(229,72,77,.55))}
#gsEdge.paused{animation-play-state:paused}
@keyframes gsEdgeFlash{0%,100%{opacity:.2}50%{opacity:1}}
/* 航线卡:只跟着变色,不参与闪烁(避免到处都在闪、看不出重点) */
#gsMapCard.warn{border-color:var(--gs-tone,#B7791F)}
/* 时间到:整屏红光闪三下后常亮,图形与参数锁定 */
#layer-ground.gs-timeup #gsEdge{opacity:1;box-shadow:inset 0 0 0 4px var(--red),inset 0 0 34px 5px rgba(229,72,77,.5);
                                animation:gsFlash .42s ease-out 3}
#layer-ground.gs-timeup .shape-seg,#layer-ground.gs-timeup .gs-field input,
#layer-ground.gs-timeup .pair-btns{pointer-events:none;opacity:.5}
@keyframes gsFlash{0%,100%{opacity:.3}50%{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .gs-timer.danger b,#gsEdge.warn,#layer-ground.gs-timeup #gsEdge{animation:none}
  #gsEdge.warn{opacity:1}
}
/* 区块标题右侧的小胶囊(创建班级等主动作,取代原来 12px 灰字看不见的问题):
   用实心墨底=主按钮(与 .top-pill 的浅青次要入口形成层级),文字对比度 18:1 而不是灰字的 2.6:1 */
.sec-btn{flex:none;display:flex;align-items:center;gap:4px;background:var(--ink);color:var(--bg);
         font-size:calc(12px*var(--f));font-weight:700;padding:6px 12px;border-radius:999px;cursor:pointer;
         transition:transform .3s cubic-bezier(.34,1.56,.64,1),opacity .15s ease}
.sec-btn:active{transform:scale(.94);opacity:.85}
/* 创建班级:列表里的虚线卡,最显眼的入口 */
.create-cta{display:flex;align-items:center;gap:12px;margin:10px 16px 0;padding:14px;cursor:pointer;
            border:1.5px dashed var(--line);border-radius:16px;background:var(--bg);
            transition:transform .3s cubic-bezier(.34,1.56,.64,1),border-color .2s ease,background .2s ease}
.create-cta:active{transform:scale(.98);background:var(--gap)}
.create-cta .cta-plus{width:38px;height:38px;border-radius:12px;background:var(--accent-soft);color:var(--accent);
                      display:flex;align-items:center;justify-content:center;font-size:calc(19px*var(--f));font-weight:700;flex:none}
.create-cta .cta-txt{flex:1;min-width:0}
.create-cta .cta-txt b{display:block;font-size:calc(14px*var(--f));font-weight:700;color:var(--ink)}
.create-cta .cta-txt span{display:block;font-size:calc(11.5px*var(--f));color:var(--ink3);margin-top:3px}
.create-cta .chev{color:var(--ink3);flex:none}
@media (hover:hover) and (pointer:fine){.create-cta:hover{border-color:var(--accent);background:var(--accent-soft)}}
/* 新建班级卡片的入场:滑入 + 一圈高亮淡出 */
.class-card.is-new{animation:cardIn .44s cubic-bezier(.34,1.56,.64,1),cardGlow 1.5s ease-out .1s}
@keyframes cardIn{from{opacity:0;transform:translateY(-10px) scale(.97)}to{opacity:1;transform:none}}
@keyframes cardGlow{0%{box-shadow:0 0 0 2px var(--accent)}100%{box-shadow:0 0 0 7px rgba(28,92,228,0)}}
/* 弹层表单:内联报错 + 输入框抖动 + 建议词 */
.f-err{display:none;font-size:calc(11.5px*var(--f));color:var(--err-fg);font-weight:600;margin-top:6px}
.f-err.on{display:block}
.f-input.err{border-color:var(--red);animation:shakeX .38s ease}
@keyframes shakeX{0%,100%{transform:translateX(0)}20%{transform:translateX(-5px)}40%{transform:translateX(5px)}60%{transform:translateX(-3px)}80%{transform:translateX(3px)}}
.pick-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.pick-chips span{font-size:calc(12px*var(--f));color:var(--ink2);background:var(--panel);border-radius:999px;padding:6px 12px;
                 font-weight:600;cursor:pointer;transition:transform .3s cubic-bezier(.34,1.56,.64,1),background .15s ease,color .15s ease}
.pick-chips span:active{transform:scale(.94)}
.pick-chips span.on{background:var(--accent-soft);color:var(--accent)}
.btn-black.busy{opacity:.6;pointer-events:none}
@media (prefers-reduced-motion:reduce){
  .class-card.is-new,.f-input.err{animation:none}
}
/* ================= Ant Design 式组件层(统一提示/警告/空状态/结果页与状态语言) ================= */
/* ① 全局提示 Message:顶部居中磨砂玻璃卡 + 语义图标 + 层次阴影(底色半透明,压住内容也不糊) */
#toast{position:absolute;top:calc(env(safe-area-inset-top) + 56px);left:50%;z-index:200;pointer-events:none;
       display:flex;align-items:center;gap:8px;max-width:calc(100% - 40px);padding:10px 15px;
       background:var(--glass);color:var(--ink);border:1px solid var(--glass-line);border-radius:12px;
       -webkit-backdrop-filter:blur(16px) saturate(180%);backdrop-filter:blur(16px) saturate(180%);
       box-shadow:var(--sd-2);font-size:calc(13px*var(--f));font-weight:600;line-height:1.5;
       opacity:0;transform:translate(-50%,-14px);transition:opacity .22s var(--ease),transform .22s var(--ease)}
/* 不支持毛玻璃的浏览器退回实心卡(宁可实心,也不能让文字压字) */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  #toast{background:var(--bg)}
}
#toast.on{opacity:1;transform:translate(-50%,0)}
#toast .tm-ic{width:16px;height:16px;flex:none;display:flex}
#toast .tm-act{flex:none;margin-left:4px;color:#fff;font-weight:700;pointer-events:auto;cursor:pointer;
               padding:3px 10px;border-radius:8px;background:var(--accent)}
/* 压一下就行,不再缩放:提示卡本身很窄,缩放会让旁边的字跟着抖 */
#toast .tm-act:active{opacity:.75}
/* 深色底上的动作按钮用亮一档的蓝(与深色主题的 --accent 一致,保证对比度) */
body.dark #toast .tm-act{background:var(--accent);color:#08131F}
#toast.success .tm-ic{color:var(--ok-fg)}
#toast.warning .tm-ic{color:var(--warn-fg)}
#toast.error .tm-ic{color:var(--err-fg)}
#toast.info .tm-ic{color:var(--info-fg)}
body.dark #toast.success .tm-ic{color:#5FD0B0}
body.dark #toast.warning .tm-ic{color:#E5B566}
body.dark #toast.error .tm-ic{color:#F08A8E}
body.dark #toast.info .tm-ic{color:#247DFF}
/* ② 警告提示 Alert:柔和底色 + 左侧语义图标,可带标题 */
.ant-alert{position:relative;display:flex;gap:10px;align-items:flex-start;padding:11px 13px;border-radius:12px;margin-top:10px;
           border:1px solid transparent;font-size:calc(12.5px*var(--f));line-height:1.7;color:var(--ink2)}
.ant-alert .aa-close{position:absolute;top:7px;right:7px;width:22px;height:22px;padding:0;border:none;background:none;
                     display:flex;align-items:center;justify-content:center;color:var(--ink3);cursor:pointer;border-radius:7px;
                     transition:background .15s ease,color .15s ease}
.ant-alert .aa-close:active{background:var(--panel);color:var(--ink)}
.ant-alert[data-closable] .aa-body{padding-right:20px}
.ant-alert .aa-ic{width:16px;height:16px;flex:none;margin-top:3px;display:flex}
.ant-alert .aa-body{flex:1;min-width:0}
.ant-alert .aa-body b{display:block;color:var(--ink);font-weight:700;font-size:calc(13px*var(--f));margin-bottom:2px}
.ant-alert.info{background:var(--info-bg);border-color:rgba(28,92,228,.20)}    .ant-alert.info .aa-ic{color:var(--info-fg)}
.ant-alert.success{background:var(--ok-bg);border-color:rgba(82,184,164,.22)}  .ant-alert.success .aa-ic{color:var(--ok-fg)}
.ant-alert.warning{background:var(--warn-bg);border-color:rgba(183,121,31,.22)} .ant-alert.warning .aa-ic{color:var(--warn-fg)}
.ant-alert.error{background:var(--err-bg);border-color:rgba(229,72,77,.20)}    .ant-alert.error .aa-ic{color:var(--err-fg)}
body.dark .ant-alert.info .aa-ic{color:#247DFF}
body.dark .ant-alert.success .aa-ic{color:#5FD0B0}
body.dark .ant-alert.warning .aa-ic{color:#E5B566}
body.dark .ant-alert.error .aa-ic{color:#F08A8E}
/* ③ 空状态 Empty:本 App 的空状态就是这套组件(班级/报名/购课用 .joined-empty,搜索无结果用 .ms-empty,
   两者共用同一套「圆形图标底座 + 说明 + 可选按钮」样式,故不再单列 .ant-empty 类) */
/* ④ 结果页 Result:状态图标 + 标题 + 副文案 */
.ant-result{display:flex;flex-direction:column;align-items:center;text-align:center;padding:2px 0 6px}
.ant-result .ar-ic{width:54px;height:54px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin-bottom:12px}
.ant-result .ar-ic .ic{width:27px;height:27px}
.ant-result.success .ar-ic{background:var(--ok-bg);color:var(--ok-fg)}
.ant-result.warning .ar-ic{background:var(--warn-bg);color:var(--warn-fg)}
.ant-result.error .ar-ic{background:var(--err-bg);color:var(--err-fg)}
body.dark .ant-result.success .ar-ic{color:#5FD0B0}
body.dark .ant-result.warning .ar-ic{color:#E5B566}
body.dark .ant-result.error .ar-ic{color:#F08A8E}
.ant-result b{font-size:calc(16px*var(--f));font-weight:700;color:var(--ink)}
.ant-result span{font-size:calc(12px*var(--f));color:var(--ink3);margin-top:6px;line-height:1.7}
/* ⑤ 统一状态:焦点环 + 输入聚焦光晕 + 禁用(AntD 的状态语言) */
.btn-black:focus-visible,.btn-solid-s:focus-visible,.btn-ghost-s:focus-visible,.btn-ghost-big:focus-visible,
.sec-btn:focus-visible,.mode-pill:focus-visible,.top-pill:focus-visible,.create-cta:focus-visible,.bk-btn:focus-visible,
.gs-btn:focus-visible,.pb:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.f-input:focus,.f-area:focus,.gs-field input:focus{border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}
.f-input:disabled,.f-area:disabled{background:var(--panel);color:var(--ink3);cursor:not-allowed}
/* ⑥ 页面标题 PageHeader:全站 22 处顶栏标题统一样式(原来各页重复写内联样式) */
.exam-bar .ptitle{font-size:calc(15.5px*var(--f));font-weight:700;color:var(--ink);letter-spacing:.01em;
                  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.exam-bar .ptitle .sub{color:var(--ink3);font-weight:500;font-size:calc(12px*var(--f))}
.exam-bar .ptitle.act{color:var(--accent);cursor:pointer;flex:none}
/* ⑦ 描述列表 Descriptions:标签-值两列(替代各处手写的 label/value 行) */
.ant-desc{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;margin:12px 16px 0}
.ant-desc .dd{display:flex;justify-content:space-between;gap:14px;padding:12px 14px;border-bottom:1px solid var(--line);
              font-size:calc(13px*var(--f));line-height:1.6}
.ant-desc .dd:last-child{border-bottom:none}
.ant-desc .dd .k{color:var(--ink3);flex:none}
.ant-desc .dd .v{color:var(--ink);font-weight:600;text-align:right;min-width:0;overflow:hidden;text-overflow:ellipsis}
/* ⑧ 统计数值 Statistic:大数字 + 小标签 */
.ant-stat{display:flex;flex-direction:column;gap:3px}
.ant-stat .as-v{font-size:calc(22px*var(--f));font-weight:700;letter-spacing:-.01em;
                font-variant-numeric:tabular-nums;color:var(--ink);line-height:1.15}
.ant-stat .as-v small{font-size:calc(12px*var(--f));font-weight:500;color:var(--ink3);margin-left:3px}
.ant-stat .as-l{font-size:calc(11px*var(--f));color:var(--ink3)}
.ant-stat.ok .as-v{color:var(--accent)}
/* ⑨ 分割线 Divider(可带文字) */
.ant-divider{display:flex;align-items:center;gap:10px;color:var(--ink3);font-size:calc(11.5px*var(--f));
             font-weight:500;margin:16px 0}
.ant-divider::before,.ant-divider::after{content:'';flex:1;height:1px;background:var(--line)}
.badge-num{background:var(--red);color:#fff;border-radius:9px;font-size:calc(10px*var(--f));font-weight:700;padding:1px 6px;margin-left:6px}
.btn-black{background:var(--ink);color:var(--bg);border-radius:13px;height:46px;display:flex;align-items:center;
           justify-content:center;font-size:calc(15px*var(--f));font-weight:600}
.btn-black:active{opacity:.85}
.ic{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none}
/* ---------- 点击交互(下沉 + 弹簧回弹) ---------- */
/* 统一缓动:交互反馈用 AntD 默认曲线(cubic-bezier(.645,.045,.355,1)),回弹仍保留轻微弹性 */
.func,.row,.m-row,.chapter,.mode,.race,.post-card,.ht-count,.model-switch span,.q .q-btn,.btn-black,.opt{
  transition:transform .3s cubic-bezier(.34,1.56,.64,1), box-shadow .18s ease,
             background .15s ease, opacity .18s ease, filter .18s ease}
.card,.race-card,.proj-card,.class-card,.bank-card,.signup-row,.race-item,.msg-card,.ai-card,.sec-x,.attach,.badge,.kpi-chip,.spec-card{
  transition:box-shadow .24s var(--ease),border-color .24s var(--ease),transform .24s var(--ease)}
.func{box-shadow:var(--shadow)}
/* 按下:卡片向页面内沉,阴影塌陷 */
.func:active{transform:scale(.95);background:var(--gap);box-shadow:0 1px 4px rgba(17,19,24,.05)}
.func:active .f-ic{transform:scale(.86)}
.f-ic{transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
/* 行:整行微缩,文字向右轻推 */
.row:active,.m-row:active,.chapter:active,.mode:active,.post-card:active{background:var(--gap);transform:scale(.988)}
.row:active .r-t{transform:translateX(3px)}
.r-t{transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
/* 大图卡:压下 + 变暗 */
.race:active{transform:scale(.975);filter:brightness(.94)}
/* 圆钮:明显下沉 */
.q .q-btn:active{transform:scale(.86)}
.ht-count:active,.model-switch span:active{opacity:.6}
.btn-black:active{transform:scale(.97)}
.opt:active{transform:scale(.985);background:var(--gap)}
.fav-on{background:var(--accent)!important;color:#fff!important}
.view.active{animation:viewIn .22s ease}
@keyframes viewIn{from{opacity:.55;transform:translateY(4px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .view.active{animation:none}
  *{animation-duration:.01ms!important;transition-duration:.01ms!important}
}
/* ---------- 悬停交互(桌面指针) ---------- */
@media (hover:hover) and (pointer:fine){
  .func:hover{transform:translateY(-2px);box-shadow:0 8px 18px rgba(17,19,24,.08)}
  .func:hover .f-ic{transform:scale(1.06)}
  .row:hover,.m-row:hover,.chapter:hover,.mode:hover{background:var(--gap)}
  .race:hover{transform:scale(1.015)}
  .q .q-btn:hover{background:#E9EAEC}
  .ht-count:hover,.model-switch span:hover{opacity:.85}
  .btn-black:hover{opacity:.9}
}
/* 状态条 */
.state-strip{display:flex;align-items:center;gap:13px;padding:4px 20px 10px;font-size:calc(12.5px*var(--f));font-weight:600}
.state-strip .sep{width:1px;height:11px;background:var(--line)}
.state-strip .d{color:var(--ink3);font-weight:500}
/* 英雄图(真实照片) */
.hero{margin:0 16px;border-radius:var(--r-lg);overflow:hidden;position:relative;height:196px;box-shadow:var(--shadow)}
/* 交互 3D 无人机舞台(理想车控式,位于「我的」页) */
.drone-stage{margin:0 0 4px;height:236px;border-radius:var(--r-lg);position:relative;overflow:hidden;
             background:linear-gradient(180deg,#FBFCFE 0%,#EFF2F5 100%);border:1px solid var(--line);box-shadow:var(--shadow)}
.drone-stage canvas{position:absolute;inset:0;width:100%;height:100%;touch-action:pan-y;cursor:grab}
.drone-stage canvas:active{cursor:grabbing}
.drone-stage .drag-hint{position:absolute;right:12px;bottom:10px;font-size:calc(10.5px*var(--f));color:var(--ink3);font-weight:500;
                        pointer-events:none}
/* 模型切换器 */
.model-switch{position:absolute;left:12px;bottom:10px;display:flex;background:rgba(17,19,24,.45);border-radius:999px;
              padding:3px;z-index:5}
.model-switch span{color:rgba(255,255,255,.75);font-size:calc(10.5px*var(--f));font-weight:600;padding:3px 11px;border-radius:999px;
                   cursor:pointer;transition:all .15s}
.model-switch span.on{background:#fff;color:var(--ink)}
/* 加载态(照片 + 转圈,不再露玩具) */
.stage-photo{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;z-index:4;
             background:linear-gradient(180deg,#FBFCFE,#EFF2F5)}
.stage-photo img{width:100%;height:100%;object-fit:cover;display:block}
.stage-photo .spinner{position:absolute;width:26px;height:26px;border:2.5px solid rgba(17,19,24,.12);
                      border-top-color:var(--accent);border-radius:50%;animation:spin 0.9s linear infinite}
.stage-photo .st-label{position:absolute;bottom:12px;left:0;right:0;text-align:center;font-size:calc(10.5px*var(--f));
                       color:var(--ink3);font-weight:500}
@keyframes spin{to{transform:rotate(360deg)}}
.today-bar{display:flex;align-items:center;gap:12px;margin:10px 16px 0;background:var(--bg);border:1px solid var(--line);
           border-radius:var(--r-lg);padding:11px 14px;box-shadow:var(--shadow)}
.today-bar .t-l{flex:1;min-width:0}
.today-bar .t-l .label{font-size:calc(10.5px*var(--f));color:var(--ink3);font-weight:500;display:block;letter-spacing:.02em}
.today-bar .t-l .num{font-size:calc(19px*var(--f));font-weight:700;letter-spacing:-.01em;font-variant-numeric:tabular-nums;display:block;margin-top:2px}
.today-bar .t-l .num small{font-size:calc(11.5px*var(--f));font-weight:500;color:var(--ink3);margin-left:2px}
.today-bar .h-btn{background:var(--ink);color:var(--bg);border-radius:999px;font-size:calc(12.5px*var(--f));font-weight:700;padding:10px 18px;flex:none}
/* 考试倒计时卡(独立,仪表样式) */
.exam-count{margin:10px 16px 0;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);
            box-shadow:var(--shadow);padding:16px 16px 0;cursor:pointer;overflow:hidden}
.exam-count:active{opacity:.85}
.exam-count .ec-body{display:flex;align-items:center;gap:14px}
.exam-count .ec-label{font-size:calc(11px*var(--f));color:var(--ink3);font-weight:500;display:block}
.exam-count .ec-num-wrap{display:flex;align-items:baseline;gap:4px;margin-top:2px}
.exam-count .ec-num{font-size:calc(40px*var(--f));font-weight:800;color:var(--accent);letter-spacing:-.02em;
                     font-variant-numeric:tabular-nums;line-height:1}
.exam-count .ec-unit{font-size:calc(13px*var(--f));color:var(--ink2);font-weight:600}
.exam-count .ec-ring{width:62px;height:62px;border-radius:50%;margin-left:auto;flex:none;position:relative;
                      display:flex;align-items:center;justify-content:center;
                      background:conic-gradient(var(--accent) 0 66%, var(--panel) 66% 100%)}
.exam-count .ec-ring::before{content:"";position:absolute;inset:6px;border-radius:50%;background:var(--bg)}
.exam-count .ec-ring b{position:relative;font-size:calc(13px*var(--f));font-weight:800;color:var(--accent);
                        font-variant-numeric:tabular-nums}
.exam-count .ec-foot{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--line);
                      margin:14px -16px 0;padding:10px 16px;font-size:calc(11px*var(--f));color:var(--ink2)}
.exam-count .ec-foot .ec-edit{color:var(--accent);font-weight:700}
/* 圆钮 */
.quick{display:flex;justify-content:space-between;padding:16px 30px 2px}
.quick .q{display:flex;flex-direction:column;align-items:center;gap:7px;font-size:calc(10.5px*var(--f));color:var(--ink2);font-weight:500}
.quick .q .q-btn{width:52px;height:52px;border-radius:50%;background:var(--panel);border:1px solid rgba(17,19,24,.04);
                 display:flex;align-items:center;justify-content:center;color:var(--ink)}
.quick .q .q-btn:active{background:#EAEBED}
/* 功能宫格(原首页 6 入口,完整保留) */
.home-top{padding:12px 20px 2px;display:flex;align-items:flex-start;justify-content:space-between}
.home-top .ht-title{font-size:calc(23px*var(--f));font-weight:800;letter-spacing:.01em;color:var(--ink);
                    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ⚠ 副标题不许再用 nowrap + text-overflow:ellipsis:这一行的可用宽度 = 430 减去右侧三枚控件
   (铃铛 38 + 深色 73 + 倒计时 82.8 + 两个 8px 间隙 + 左右内边距 18)= **184px**,
   而「从没练过」那条句子实测 225.9px —— 省略号切掉的正好是「从顺序练习开始」这半句,
   学员看到的是「早上好,飞手 · 今天第一题…」,"去哪儿练"没了。改成最多两行
   (与 .post-card .p-body / .rc-cover .rc-title 同一个写法),只有两行都放不下才截。
   实测见 _work/20261009-变更记录.md 第八轮。 */
.home-top .ht-sub{font-size:calc(12.5px*var(--f));color:var(--ink3);font-weight:500;margin-top:5px;
                  line-height:1.45;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* 顶部右侧:迷你倒计时 */
.ht-count{text-align:right;cursor:pointer;padding-top:2px}
.ht-count:active{opacity:.7}
.ht-count .hc-num{font-size:calc(21px*var(--f));font-weight:800;color:var(--accent);letter-spacing:-.02em;
                  font-variant-numeric:tabular-nums}
.ht-count .hc-unit{font-size:calc(11px*var(--f));color:var(--ink2);font-weight:600;margin-left:2px}
.ht-count .hc-label{display:block;font-size:calc(10px*var(--f));color:var(--ink3);font-weight:500;margin-top:2px}
.func-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;padding:12px 16px 0}
.func{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px 8px 12px;
      text-align:center;box-shadow:var(--shadow)}
.func .f-ic{width:46px;height:46px;border-radius:15px;background:var(--panel);border:1px solid rgba(17,19,24,.04);
            margin:0 auto 9px;display:flex;align-items:center;justify-content:center;color:var(--ink);
            box-shadow:inset 0 -6px 10px rgba(0,0,0,.03)}
/* 六色图标砖 */
.f-ic.f-teal{background:rgba(28,92,228,.12);color:#009494}
.f-ic.f-blue{background:rgba(61,123,253,.12);color:#2F66E6}
.f-ic.f-amber{background:rgba(183,121,31,.14);color:#B06D10}
.f-ic.f-red{background:rgba(229,72,77,.12);color:#D74448}
.f-ic.f-green{background:rgba(46,139,119,.12);color:#217A63}
.f-ic.f-purple{background:rgba(139,92,246,.12);color:#7C5CD6}
.func b{font-size:calc(12.5px*var(--f));font-weight:600;display:block;color:var(--ink)}
.func span{font-size:calc(10px*var(--f));color:var(--ink3);display:block;margin-top:2px}
/* 学习数据(统计下移后的落位) */
.stat-card{display:flex;margin:14px 16px 0;background:var(--bg);border:1px solid var(--line);
           border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow)}
.stat-card .s{flex:1;padding:13px 6px;text-align:center;border-right:1px solid var(--line)}
.stat-card .s:last-child{border-right:none}
.stat-card .s b{font-size:calc(17px*var(--f));font-weight:700;display:block;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.stat-card .s b.teal{color:var(--accent)}
.stat-card .s span{font-size:calc(10px*var(--f));color:var(--ink3)}
/* 刷题页:模式卡 */
.mode-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:4px 16px 0}
.mode{display:flex;align-items:center;gap:10px;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);
      padding:12px;box-shadow:var(--shadow)}
.mode .m-ic{width:38px;height:38px;border-radius:12px;background:var(--panel);border:1px solid rgba(17,19,24,.04);
            display:flex;align-items:center;justify-content:center;color:var(--ink);flex:none}
.mode b{font-size:calc(13px*var(--f));font-weight:600;display:block;color:var(--ink)}
.mode span{font-size:calc(10.5px*var(--f));color:var(--ink3);display:block;margin-top:1px}
/* 班级页 */
.seg{display:flex;margin:4px 16px 0;background:var(--panel);border-radius:12px;padding:3px}
.seg span{flex:1;text-align:center;padding:9px 0;border-radius:10px;font-size:calc(13.5px*var(--f));font-weight:600;color:var(--ink2)}
.seg span.on{background:var(--bg);color:var(--ink);box-shadow:var(--shadow)}
/* 班级模块:卡片 / 详情 / 学员 */
.class-card{margin:10px 16px 0;background:var(--bg);border:1px solid var(--line);border-radius:16px;
            overflow:hidden;box-shadow:var(--shadow);cursor:pointer}
.cc-head{display:flex;align-items:center;gap:12px;padding:13px 14px;background:linear-gradient(135deg,#F7F9FA,#EFF2F5)}
.cc-avatar{width:42px;height:42px;border-radius:12px;background:var(--ink);color:var(--bg);display:flex;align-items:center;
           justify-content:center;font-size:calc(16px*var(--f));font-weight:700;flex:none}
.cc-title{flex:1;min-width:0}
.cc-title b{font-size:calc(14.5px*var(--f));font-weight:700;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cc-title span{font-size:calc(11px*var(--f));color:var(--ink3);display:block;margin-top:2px}
.cc-badge{flex:none;font-size:calc(10.5px*var(--f));font-weight:600;color:var(--accent);background:var(--accent-soft);
          padding:3px 8px;border-radius:999px}
/* 班级卡上的「作业 n」标记:有待完成作业时才出现 */
.cc-assign{flex:none;font-size:calc(10.5px*var(--f));font-weight:700;color:var(--warn-fg,#8A5A0E);
           background:var(--warn-bg,rgba(183,121,31,.12));padding:3px 8px;border-radius:999px}
.cc-meta{display:flex;gap:18px;padding:11px 14px;font-size:calc(11.5px*var(--f));color:var(--ink2);border-top:1px solid var(--line)}
.cc-meta b{font-weight:700}
.cc-code{color:var(--accent);font-weight:700;letter-spacing:.05em}
.cc-btns{display:flex;gap:8px;padding:0 14px 13px}
.cc-btns div{flex:1;height:36px;border-radius:11px;display:flex;align-items:center;justify-content:center;
             font-size:calc(12.5px*var(--f));font-weight:600;cursor:pointer;transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.cc-btns div:active{transform:scale(.96)}
.cc-btns .ghost{background:var(--panel);color:var(--ink)}
.cc-btns .solid{background:var(--ink);color:var(--bg);font-weight:700}
.joined-empty{display:flex;flex-direction:column;align-items:center;text-align:center;padding:24px 20px 22px;
              color:var(--ink2);font-size:calc(13.5px*var(--f));font-weight:600;margin:10px 16px 0;
              border:1px dashed var(--line);border-radius:16px;background:var(--bg)}
.joined-empty .ic{width:25px;height:25px;color:var(--ink3);display:block;margin:0 auto 12px;
                  padding:14px;box-sizing:content-box;background:var(--panel);border-radius:50%}
.joined-empty span{display:block;font-size:calc(11.5px*var(--f));color:var(--ink3);font-weight:400;margin-top:5px;line-height:1.7;max-width:250px}
.joined-empty .ae-btn{margin-top:14px;height:36px;padding:0 18px;border-radius:999px;background:var(--panel);color:var(--ink);font-size:calc(12.5px*var(--f));font-weight:600;display:inline-flex;align-items:center;cursor:pointer;transition:transform .3s var(--ease-spring)}
.joined-empty .ae-btn:active{transform:scale(.96)}
.stu-avatar{width:34px;height:34px;border-radius:50%;background:var(--panel);color:var(--ink);display:flex;
            align-items:center;justify-content:center;font-size:calc(14px*var(--f));font-weight:700;flex:none}
.cd-hero{display:flex;align-items:center;gap:14px;margin:12px 16px 0;padding:15px 16px;background:var(--bg);
         border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow)}
.cd-hero b{font-size:calc(16px*var(--f));font-weight:800;display:block}
.cd-hero span{font-size:calc(11.5px*var(--f));color:var(--ink3);display:block;margin-top:3px}
.cd-hero .cd-code{font-size:calc(11.5px*var(--f));color:var(--accent);font-weight:600;margin-top:5px}
/* 徽章墙 */
.badge-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:12px 16px 0}
.badge{background:var(--bg);border:1px solid var(--line);border-radius:14px;padding:14px 6px 12px;text-align:center;box-shadow:var(--shadow)}
.badge .bd-ic{width:44px;height:44px;border-radius:14px;background:var(--panel);color:#B9BEC5;display:flex;
              align-items:center;justify-content:center;margin:0 auto 8px}
.badge.on .bd-ic{color:#fff}
.badge b{font-size:calc(12px*var(--f));font-weight:700;display:block;color:var(--ink)}
.badge span{font-size:calc(10px*var(--f));color:var(--ink3);display:block;margin-top:3px}
.badge:not(.on) b{color:var(--ink3)}
/* 帮助中心 FAQ */
.faq{border-bottom:1px solid var(--line);padding:0 14px}
.faq:last-child{border-bottom:none}
.faq-q{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 0;cursor:pointer}
.faq-q span{font-size:calc(13.5px*var(--f));font-weight:600;color:var(--ink);flex:1}
.faq-q .ic{transition:transform .25s ease;color:var(--ink3)}
.faq.open .faq-q .ic{transform:rotate(90deg)}
.faq-a{display:none;font-size:calc(12.5px*var(--f));color:var(--ink2);line-height:1.7;padding:0 0 14px}
.faq.open .faq-a{display:block}
/* 购买确认行 / 收藏删除 */
.buy-row{display:flex;align-items:center;justify-content:space-between;background:var(--panel);border-radius:12px;
         padding:12px 14px;margin-top:10px;font-size:calc(14px*var(--f));font-weight:700}
.col-del{flex:none;font-size:calc(11px*var(--f));color:var(--ink3);background:var(--panel);border-radius:999px;padding:5px 11px;
         font-weight:600;cursor:pointer}
.col-del:active{opacity:.7}
.signup-row{display:flex;align-items:center;gap:12px;background:var(--bg);border:1px solid var(--line);
            border-radius:16px;margin:12px 16px 0;padding:13px 14px;box-shadow:var(--shadow)}
.signup-row .sr-ic{width:40px;height:40px;border-radius:12px;display:flex;align-items:center;justify-content:center;color:#fff;flex:none}
.signup-row b{font-size:calc(13.5px*var(--f));font-weight:700;display:block}
.signup-row span{font-size:calc(11px*var(--f));color:var(--ink3);display:block;margin-top:3px}
/* 大数字 */
.bigblock{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-top:1px solid var(--line);margin-top:14px}
.bigblock .l b{font-size:calc(32px*var(--f));font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums;display:block}
.bigblock .l span{font-size:calc(12px*var(--f));color:var(--ink3)}
.bigblock .r{text-align:right}
.bigblock .r b{font-size:calc(15px*var(--f));font-weight:600;display:block}
.bigblock .r span{font-size:calc(11px*var(--f));color:var(--ink3)}
/* 月度 */
.month{padding:14px 24px 16px;border-top:1px solid var(--line)}
.month .m-top{display:flex;align-items:baseline;justify-content:space-between}
.month .m-top b{font-size:calc(22px*var(--f));font-weight:700;font-variant-numeric:tabular-nums}
.month .m-top b small{font-size:calc(11.5px*var(--f));font-weight:500;color:var(--ink3);margin-left:3px}
.month .m-top span{font-size:calc(12px*var(--f));color:var(--ink3)}
.bars{display:flex;align-items:flex-end;gap:10px;height:40px;margin-top:12px}
.bars .b{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px}
.bars .b i{display:block;width:100%;max-width:16px;border-radius:4px 4px 2px 2px;background:#E1E3E7;min-height:4px}
.bars .b.on i{background:var(--ink)}
.bars .b span{font-size:calc(9.5px*var(--f));color:var(--ink3)}
/* 进度行 */
.gauge-row{display:flex;align-items:center;gap:13px;padding:14px 24px;border-top:1px solid var(--line)}
.gauge-row .g-t{font-size:calc(14px*var(--f));font-weight:600;flex:none}
.gauge-row .g-bar{flex:1;height:7px;border-radius:99px;background:var(--panel);overflow:hidden}
.gauge-row .g-bar i{display:block;height:100%;border-radius:99px;background:var(--accent)}
.gauge-row .g-v{font-size:calc(13.5px*var(--f));font-weight:700;font-variant-numeric:tabular-nums}
/* 列表块 */
.listblock{background:var(--bg);margin-top:10px;border-top:1px solid var(--line)}
/* 通知缩略 */
.thumb{width:56px;height:50px;border-radius:10px;flex:none;overflow:hidden;position:relative}
.thumb img{width:100%;height:100%;object-fit:cover;display:block}
/* 比赛照片卡 */
.race{margin:8px 16px 0;border-radius:var(--r-lg);overflow:hidden;position:relative;height:120px;box-shadow:var(--shadow)}
.race img{width:100%;height:100%;object-fit:cover;display:block}
.race .mask{position:absolute;inset:0;background:linear-gradient(180deg,rgba(17,19,24,0) 25%,rgba(17,19,24,.7) 100%)}
.race .r-info{position:absolute;left:14px;right:14px;bottom:11px;color:#fff}
.race .r-info b{font-size:calc(14px*var(--f));display:block;font-weight:700}
.race .r-info span{font-size:calc(10.5px*var(--f));font-weight:600;margin-right:8px;opacity:.9}
/* 题库 */
.page-title{font-size:calc(23px*var(--f));font-weight:700;padding:14px 20px 4px}
.searchbar{display:flex;align-items:center;gap:8px;margin:10px 16px 0;height:40px;padding:0 13px;background:var(--panel);
           border-radius:12px;color:var(--ink3);font-size:calc(13px*var(--f))}
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:20px 8px;padding:18px 20px}
.grid4 .g{display:flex;flex-direction:column;align-items:center;gap:7px;font-size:calc(11px*var(--f));color:var(--ink2);font-weight:500}
.grid4 .g .g-ic{width:46px;height:46px;border-radius:15px;background:var(--panel);border:1px solid rgba(17,19,24,.04);
                 display:flex;align-items:center;justify-content:center;color:var(--ink)}
.grid4 .g .g-ic.green{background:rgba(82,184,164,.12);color:#217A63}
/* 我的 */
.me-head{display:flex;gap:14px;padding:16px 20px 18px;background:var(--bg)}
.me-head .avatar{width:62px;height:62px;border-radius:50%;background:var(--ink);color:var(--bg);display:flex;align-items:center;
                 justify-content:center;font-size:calc(24px*var(--f));font-weight:700;flex:none;position:relative;cursor:pointer;overflow:hidden}
.me-head .avatar::after{content:'';position:absolute;right:0;bottom:0;width:21px;height:21px;border-radius:50%;
  background-color:var(--bg);border:1px solid var(--line);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B6069' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z'/%3E%3Ccircle cx='12' cy='13' r='3'/%3E%3C/svg%3E");
  background-size:11px;background-repeat:no-repeat;background-position:center}
.me-head .avatar.photo{color:transparent}
.me-head .avatar.photo::after{display:none}
.avatar-opts{margin:2px 0 4px}
.avatar-opt{display:flex;align-items:center;gap:12px;padding:14px 4px;border-bottom:1px solid var(--line);
            cursor:pointer;font-size:calc(14.5px*var(--f));font-weight:600;color:var(--ink);
            transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.avatar-opt:last-child{border-bottom:none}
.avatar-opt:active{transform:scale(.98)}
.avatar-opt .ao-ic{width:38px;height:38px;border-radius:12px;background:var(--panel);display:flex;align-items:center;
                    justify-content:center;color:var(--ink);flex:none}
.btn-ghost-big{margin-top:12px;height:46px;border-radius:13px;background:var(--panel);color:var(--ink);
               display:flex;align-items:center;justify-content:center;font-size:calc(14px*var(--f));font-weight:600;cursor:pointer}
.btn-ghost-big:active{opacity:.8}
/* 练习结果弹层 */
.result-row{display:flex;gap:8px;margin:14px 0 16px}
/* 结算弹层的收尾动作:最多两个按钮并排(再来一轮 / 只练错题),或一个整宽「继续答题」 */
.result-acts{display:flex;gap:10px;flex-wrap:wrap}
.result-acts .btn-black{flex:1 1 0;min-width:0}
.result-row div{flex:1;text-align:center;background:var(--panel);border-radius:12px;padding:15px 4px}
.result-row i{font-style:normal;font-size:calc(22px*var(--f));font-weight:800;display:block;font-variant-numeric:tabular-nums;color:var(--ink)}
.result-row span{font-size:calc(11px*var(--f));color:var(--ink3);display:block;margin-top:3px}
/* 登录验证码按钮 */
.code-btn{flex:none;height:44px;padding:0 16px;border-radius:12px;background:var(--accent-soft);color:var(--accent);
          font-size:calc(13px*var(--f));font-weight:700;display:flex;align-items:center;cursor:pointer;
          transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.code-btn:active{transform:scale(.96)}
.code-btn.disabled{color:var(--ink3);background:var(--panel);pointer-events:none}
.me-head .m-name{font-size:calc(17px*var(--f));font-weight:700;display:flex;align-items:center}
.me-head .m-name .lv{background:rgba(82,184,164,.14);color:#217A63;border-radius:6px;font-size:calc(10px*var(--f));font-weight:700;padding:2px 7px;margin-left:8px}
.me-head .m-desc{font-size:calc(12px*var(--f));color:var(--ink3);margin-top:7px}
.mstats{display:flex;background:var(--bg);border-bottom:1px solid var(--line)}
.mstats .m{flex:1;text-align:center;padding:13px 0}
.mstats .m b{font-size:calc(16px*var(--f));font-weight:700;display:block;font-variant-numeric:tabular-nums}
.mstats .m span{font-size:calc(10.5px*var(--f));color:var(--ink3)}
.msg-card{margin:12px 16px;border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;background:var(--bg)}
.msg-card .msg-h{display:flex;align-items:center;justify-content:space-between;padding:11px 14px;
                 border-bottom:1px solid var(--line);font-size:calc(13.5px*var(--f));font-weight:600}
.msg-card .msg{padding:10px 14px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center}
.msg-card .msg:last-child{border-bottom:none}
.msg-card .msg b{font-size:calc(12.5px*var(--f));font-weight:500;flex:1;margin-right:10px}
.msg-card .msg span{font-size:calc(10.5px*var(--f));color:var(--ink3)}
.invite{margin:12px 16px;border-radius:var(--r-lg);overflow:hidden;position:relative;height:100px;box-shadow:var(--shadow)}
.invite img{width:100%;height:100%;object-fit:cover;display:block}
.invite .mask{position:absolute;inset:0;background:linear-gradient(90deg,rgba(17,19,24,.72) 20%,rgba(17,19,24,.15))}
.invite .i-info{position:absolute;left:15px;top:50%;transform:translateY(-50%);color:#fff}
.invite .i-info b{font-size:calc(15px*var(--f));display:block}
.invite .i-info span{font-size:calc(11px*var(--f));opacity:.85;display:block;margin-top:4px}
.invite .go{position:absolute;right:13px;top:50%;transform:translateY(-50%);background:var(--bg);color:var(--ink);
            border-radius:999px;font-size:calc(12px*var(--f));font-weight:700;padding:7px 14px}
/* 答题 */
.exam-bar{flex:none;display:flex;align-items:center;gap:12px;padding:calc(env(safe-area-inset-top) + 8px) 16px 10px;
          background:var(--bg);border-bottom:1px solid var(--line)}
/* ⚠ 顶栏里的元素**默认不许被压缩**(flex-shrink:0),要占满剩余宽度的那个自己写 flex:1。
   为什么必须写死这一条:flex 的默认 shrink 是 1,于是当中间那个标题很长时,
   右侧的动作钮(如发帖页的「发布」)会被**挤窄** —— 它的内边距被压掉,
   看起来就"贴着屏幕右边、太靠边缘了"(实测:学员反馈的正是这一条)。
   这类挤压**不报错、不换行**,只是内边距凭空少了一截,光看代码很难往这上面想。 */
.exam-bar > *{flex:none}
.exam-bar .back{width:38px;height:38px;border-radius:12px;background:var(--panel);display:flex;align-items:center;justify-content:center;color:var(--ink)}
.exam-bar .prog{flex:1;min-width:0;height:5px;border-radius:99px;background:var(--panel);overflow:hidden}
.exam-bar .prog i{display:block;height:100%;width:34%;border-radius:99px;background:var(--ink)}
.exam-bar .count{font-size:calc(12.5px*var(--f));font-weight:600;color:var(--ink2);white-space:nowrap}
/* 顶栏右侧的文字动作(章节列表的「全章顺序刷」/ 章节详情的「只练本章」):
   原来只有文字和图标,实测热区不到 40px,被控件体检判为「热区过小」—— 这里给它 34×34 的最小面积 */
.exam-bar .bar-act{display:flex;align-items:center;gap:5px;min-width:40px;min-height:40px;padding:0 10px;
                   background:var(--panel);border-radius:12px;color:var(--accent);
                   font-size:calc(12.5px*var(--f));font-weight:600;white-space:nowrap}
#examTitle{flex:none;max-width:130px;overflow:hidden;text-overflow:ellipsis}
.exam-bar .timer{display:flex;align-items:center;gap:5px;background:var(--panel);color:var(--ink);font-size:calc(12.5px*var(--f));font-weight:600;
                 padding:6px 11px;border-radius:999px;white-space:nowrap}
.q-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);margin:12px 16px 0;padding:16px;box-shadow:var(--shadow)}
.q-tags{display:flex;gap:8px;margin-bottom:12px}
.q-text{font-size:calc(16px*var(--f));font-weight:600;line-height:1.6}
.q-text .num{color:var(--accent);margin-right:3px}
/* 题干配图(2026-10-07 加):空域图/装订图/仪表图这类题的文字底下摆一张图。
   为什么用 contain 而不是 cover:这些图是**要看清内容**的(航线、标注、刻度),
   cover 会把边缘裁掉 —— 学员看不全就会照着错的形状答题;宁可有留白。
   上限 42vh:图再高也不能把选项挤出屏幕(手机上一屏必须能看到选项)。 */
.q-img{margin-top:10px}
.q-img img{display:block;width:100%;max-height:42vh;object-fit:contain;background:var(--panel);border:1px solid var(--line);border-radius:12px}
.opts{margin:12px 16px 0}
/* 答题页常驻的左右滑提示(线上同款:选项下方一行小灰字) */
.q-swipe{margin:14px 16px 0;text-align:center;font-size:calc(11.5px*var(--f));font-weight:600;color:var(--ink3);letter-spacing:.2px}
.q-swipe i{font-style:normal;color:var(--accent);font-weight:800;margin:0 5px}
/* 多选题的确认按钮:主按钮样式 + 右侧「已选 n 项」小字;没选任何项时置灰 */
.q-confirm{margin:2px 16px 0;display:flex;align-items:center;justify-content:center;gap:10px}
.q-confirm .qc-n{font-size:calc(11.5px*var(--f));font-weight:600;opacity:.72}
.q-confirm.is-disabled{opacity:.45;pointer-events:none}
.opt{display:flex;align-items:center;gap:12px;background:var(--bg);border:1.5px solid var(--line);border-radius:13px;padding:14px;margin-bottom:9px;
     transition:border-color .18s ease,background .18s ease,transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .2s ease}
.opt:active{background:var(--gap);transform:scale(.985)}
.opt .badge{width:26px;height:26px;border-radius:50%;background:var(--panel);color:var(--ink);font-size:calc(12.5px*var(--f));font-weight:700;
            display:flex;align-items:center;justify-content:center;flex:none;
            transition:transform .35s cubic-bezier(.34,1.56,.64,1),background .18s ease,color .18s ease}
.opt p{font-size:calc(14px*var(--f));font-weight:500;flex:1}
.opt .mark{width:22px;height:22px;border-radius:50%;flex:none;display:none;align-items:center;justify-content:center;
           color:#fff;font-size:calc(13px*var(--f));font-weight:800;margin-left:auto}
.opt.right .mark,.opt.wrong .mark{display:flex;animation:markPop .35s cubic-bezier(.34,1.56,.64,1)}
.opt.right .mark{background:#2E8B77}
.opt.right .mark::after{content:'✓'}
.opt.wrong .mark{background:var(--red)}
.opt.wrong .mark::after{content:'✕'}
@keyframes markPop{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
.opt.picked{border-color:var(--ink)}
.opt.picked .badge{background:var(--ink);color:var(--bg)}
/* 多选题「选漏了」:漏选的正确项给虚线框,和「选错」区分开 */
.opt.miss{border-style:dashed;border-color:var(--ink3);background:var(--gap)}
.opt.right{border-color:#2E8B77;background:rgba(82,184,164,.08);box-shadow:0 0 0 3px rgba(82,184,164,.14)}
.opt.right .badge{background:#2E8B77;color:#fff;transform:scale(1.15)}
.opt.right.reveal{animation:optPop .55s cubic-bezier(.34,1.56,.64,1)}
.opt.wrong{border-color:var(--red);background:rgba(229,72,77,.05)}
.opt.wrong .badge{background:var(--red);color:#fff}
.opt.wrong.pick{animation:optShake .42s ease}
@keyframes optPop{0%{transform:scale(1)}45%{transform:scale(1.04)}100%{transform:scale(1)}}
@keyframes optShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-6px)}40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(4px)}}
@media (prefers-reduced-motion:reduce){
  .opt.right.reveal,.opt.wrong.pick{animation:none}
}
.analysis{margin:12px 16px 0;border:1px solid var(--line);border-radius:var(--r-lg);padding:14px;border-left:3px solid #2E8B77}
.analysis.show{animation:anIn .35s ease}
.analysis .an-head{display:flex;align-items:center;gap:9px}
.analysis .an-ic{width:24px;height:24px;border-radius:50%;background:rgba(82,184,164,.16);color:#2E8B77;
                  display:flex;align-items:center;justify-content:center;flex:none}
.analysis .an-ic .ic{width:13px;height:13px}
.analysis .ok{font-weight:800;font-size:calc(13.5px*var(--f));color:#2E8B77}
.analysis .an-score{margin-left:auto;font-size:calc(13px*var(--f));font-weight:800;color:#2E8B77;font-variant-numeric:tabular-nums}
.analysis.err{border-left-color:var(--red)}
.analysis.err .an-ic{background:rgba(229,72,77,.12);color:var(--red)}
.analysis.err .ok{color:var(--red)}
.analysis.err .an-score{color:var(--ink3);font-weight:600}
.analysis p{font-size:calc(12.5px*var(--f));color:var(--ink2);line-height:1.7;margin-top:8px}
/* 解析正文支持换行(2026-10-07,「超级详细解析」落地时补):正文由 app.js 的 setAnalysis 用
   textContent 整段塞进这个 <p>,里面是「考点/逐项/易错」分行的几百字。浏览器默认把 \n 当空格折叠,
   不分行就糊成一整坨、几百字挤在一起根本读不下去。只给这一个节点开 pre-line,
   不动 .analysis p 的其它用法(那段是通用段落样式)。 */
.analysis p#analysisText{white-space:pre-line}
/* 追问入口(2026-10-05 补):这个类是 app.js 动态摆出来的(preview.html 的 #analysisAsk),
   全仓库此前**一条样式都没有** —— 渲染出来是一段裸文本,和旁边的「+1 分」挤在一起、也看不出能点。
   写法照抄邻居 .bc-link(次级色小字 + 可点反馈);**刻意不写 min-height**:这个头部行只有 24px 高,
   给个 36px 的触控高度会把整块解析撑高 —— 负外边距 + 内边距只是把可点区域向四周外扩,排版纹丝不动。
   颜色只用既有令牌(--ink2 / --accent),不留硬编码色值。

   ⚠ 2026-10-07 改档(`--ink3` → `--ink2`):原来用的是第三档灰,而这一行压在 `.analysis` 的
   **彩色淡底**上(`var(--ok-bg)`;答错时 `var(--err-bg)`)—— 浅色下实测 **4.38:1**(要求 4.5:1,12px),
   是全站体检「藏块」那一遍(把 `display:none` 的块摆出来量)抓出来的:这块解析默认是收着的,
   不主动摆出来永远量不到。换 `--ink2` 后复量 ≈6.4:1。
   教训与登录页那条 `#netWarn` 完全一样:**底是彩色淡底时,里面的灰字要升一档** ——
   页面背景上的第三档灰(脚注档)搬到淡色底上就不够了。 */
.analysis .an-ask{flex:none;display:inline-flex;align-items:center;padding:4px;margin:-4px;
                  font-size:calc(12px*var(--f));font-weight:600;color:var(--ink2);cursor:pointer;
                  transition:color .15s ease,opacity .15s ease}
.analysis .an-ask:active{opacity:.6}
@media (hover:hover) and (pointer:fine){.analysis .an-ask:hover{color:var(--accent)}}
@keyframes anIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.score-chip{transition:transform .35s cubic-bezier(.34,1.56,.64,1)}
.score-chip.bump{animation:scoreBump .5s cubic-bezier(.34,1.56,.64,1)}
@keyframes scoreBump{0%{transform:scale(1)}45%{transform:scale(1.35)}100%{transform:scale(1)}}
.exam-foot{flex:none;display:flex;gap:12px;padding:12px 16px calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 12px);background:var(--bg);border-top:1px solid var(--line)}
.exam-foot .side{width:52px;border-radius:13px;background:var(--panel);color:var(--ink2);display:flex;flex-direction:column;
                 align-items:center;justify-content:center;gap:2px;font-size:calc(10px*var(--f));font-weight:600}
.exam-foot .btn-black{flex:1}
/* 详情 */
.dt-head{padding:calc(env(safe-area-inset-top) + 10px) 20px 14px;background:var(--bg);border-bottom:1px solid var(--line)}
.dt-head h1{font-size:calc(16.5px*var(--f));font-weight:700;line-height:1.5;margin-top:12px}
.dt-head .meta{display:flex;gap:12px;font-size:calc(11.5px*var(--f));color:var(--ink3);margin-top:10px}
.ai-card{margin:12px 16px 0;border:1px solid var(--line);border-radius:var(--r-lg);padding:14px;box-shadow:var(--shadow)}
.ai-badge{display:inline-flex;align-items:center;background:var(--accent);color:#fff;padding:2px 9px;border-radius:999px;font-size:calc(10.5px*var(--f));font-weight:700}
.ai-card h2{font-size:calc(14px*var(--f));font-weight:700;margin:9px 0 5px}
.ai-card p{font-size:calc(12.5px*var(--f));line-height:1.7;color:var(--ink2)}
.dt-tabs{display:flex;gap:8px;margin:14px 16px 0}
.dt-tabs span{flex:1;text-align:center;padding:9px 0;border-radius:999px;font-size:calc(13px*var(--f));font-weight:600;color:var(--ink2);background:var(--panel)}
.dt-tabs span.on{background:var(--ink);color:var(--bg)}
.sec-x{margin:12px 16px 0;border:1px solid var(--line);border-radius:var(--r-lg);padding:14px}
.sec-x h4{font-size:calc(13.5px*var(--f));font-weight:700;margin-bottom:7px;display:flex;align-items:center;gap:7px}
.sec-x p{font-size:calc(12.5px*var(--f));line-height:1.75;color:var(--ink2)}
.attach{margin:12px 16px 0;border:1px solid var(--line);border-radius:var(--r-lg);padding:13px;display:flex;align-items:center;gap:10px}
.attach .a-ic{width:34px;height:34px;border-radius:10px;background:var(--panel);display:flex;align-items:center;justify-content:center;color:var(--ink)}
.attach b{font-size:calc(13px*var(--f));font-weight:600;display:block}
.attach span{font-size:calc(11px*var(--f));color:var(--ink3);display:block;margin-top:2px}
/* 通用卡片(地面站/帖子详情/题库选择页等处使用,此前 .card 无定义导致内容贴边) */
.card{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px;
      margin:12px 16px 0;box-shadow:var(--shadow)}
/* 「登录与安全」这一行要整行可点(2026-10-05)。
   原来它是 .card 里一行 flex,右边那个 .chev **自己带 onclick** —— 也就是说
   "设置密保问题"的全部热区就是那个箭头:实测 15×21px,低于全站体检的下限 36px
   (.workbench/cdp-full-audit.mjs 的 r.height < 36),而且它是纯图标 div:
   没有可访问名称、Tab 也到不了。密保问题是"忘记密码"唯一能自助走通的路,
   把它的入口藏在一个 15px 的箭头后面,等于半藏起来。
   改法:整张卡片变成一个真的 <button> —— 原生就能 Tab 到、能按 Enter/Space、
   aria-label 一句话说清它是干什么的;箭头退回纯装饰(aria-hidden)。
   为什么用 button 而不是给 div 加 role=button + 手写 keydown:
   后者要自己补键盘分支,而全站体检只验"有没有 tabindex",补漏了它也不会报。 */
.pq-card{padding:0}
.pq-row{display:flex;width:100%;align-items:center;justify-content:space-between;gap:12px;
        padding:14px;background:none;border:0;font:inherit;color:inherit;text-align:left;
        border-radius:inherit;cursor:pointer;transition:background .16s var(--ease-out)}
.pq-row:active{background:var(--accent-soft)}
.pq-row:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.pq-row .pq-t{display:block;flex:1;min-width:0}   /* flex:1 必写:状态文案可能很长,不给宽度会被箭头挤出去 */
.pq-row .pq-t b{font-size:calc(13.5px*var(--f))}
.pq-row .pq-t span{display:block;font-size:calc(11px*var(--f));color:var(--ink3);margin-top:5px;line-height:1.65}
.pq-row .chev{flex:none;display:flex;align-items:center;color:#C6C9CE}
body.dark .pq-row .chev{color:var(--ink3)}
/* 首页「今天该练什么」卡片的主按钮。
   它原来是 .bk-btn.solid —— 而 .bk-btn(见「.bk-actions」那条)是给「并排两个、各自 flex:1」
   设计的:宽度全交给 flex 分配,所以**它没有任何左右内边距**。在卡片里被内联 flex:none 一收,
   按钮就缩成内容宽:实测 24×38px(两个 12px 的汉字正好 24px),字贴着 10px 圆角边 —— 一块挤扁的黑条。
   主按钮该是整行的、有内边距和图标,所以按 .btn-black 那一档的形状另立一个类,
   沿用同一套配色(--ink 底 / --bg 字)与 46px / 圆角 13px;
   不直接复用 .btn-black 是因为它在 20 多处出现,改它的盒子会牵动别的页面。 */
.rec-cta{display:flex;align-items:center;justify-content:center;gap:7px;
         margin-top:12px;height:46px;border-radius:13px;padding:0 16px;
         background:var(--ink);color:var(--bg);
         font-size:calc(15px*var(--f));font-weight:700;cursor:pointer;
         -webkit-user-select:none;user-select:none;white-space:nowrap;
         transition:transform .3s var(--ease-spring),background .15s ease,opacity .15s ease}
.rec-cta .ic{width:19px;height:19px}
.rec-cta:active,.rec-cta.pressing{transform:scale(.97);opacity:.9}
.rec-cta:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.elder .rec-cta{height:calc(46px + 6px*var(--t))}
/* ---------- 二级页:地面站/比赛/论坛/无人机+ ---------- */
.trip-map{position:relative;height:160px;background:linear-gradient(180deg,#F7F9FA 0%,#F1F3F5 100%);
          border-radius:14px;margin-top:10px;overflow:hidden;padding:14px}
.trip-map svg{width:100%;height:100%;display:block}
/* 航线图三类名称标注(用类控制颜色,深色下自动提亮) */
.gs-n-home{fill:#D74448}
.gs-n-apex{fill:#2F66E6}
.gs-n-seat{fill:#009494}
/* 航线图底纹(网格 + 等高线):用 CSS 给色,深色下换成浅色描边 —— 原先写死 rgba(17,19,24,.04/.05),深色下等于看不见 */
.gs-grid{stroke:rgba(17,19,24,.04)}
.gs-terrain{stroke:rgba(17,19,24,.05)}
body.dark .gs-grid{stroke:rgba(242,244,246,.055)}
body.dark .gs-terrain{stroke:rgba(242,244,246,.075)}
/* 航线图形切换(7 种考试图形,图标+名称卡片网格) */
.shape-seg{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:12px}
.shape-seg span{display:flex;flex-direction:column;align-items:center;gap:5px;padding:9px 2px 8px;
                border:1px solid var(--line);border-radius:12px;background:var(--bg);cursor:pointer;
                transition:border-color .15s ease,background .15s ease,transform .3s cubic-bezier(.34,1.56,.64,1)}
.shape-seg span em{font-style:normal;font-size:calc(10.5px*var(--f));font-weight:600;color:var(--ink2);
                  white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.shape-seg span .ic{width:21px;height:14px;color:var(--ink3);transition:color .15s ease}
.shape-seg span.on{border-color:var(--accent);background:var(--accent-soft)}
.shape-seg span.on em{color:var(--ink)}
.shape-seg span.on .ic{color:var(--accent)}
.shape-seg span:active{transform:scale(.95)}
/* 区块标题:标题 + 全部链接 */
.sec-h{display:flex;align-items:center;justify-content:space-between;padding:14px 20px 8px}
.sec-h .st{font-size:calc(15px*var(--f));font-weight:700;color:var(--ink)}
.sec-h .more{font-size:calc(12px*var(--f));color:var(--ink3);font-weight:600;display:flex;align-items:center;gap:2px;
             cursor:pointer;transition:opacity .15s}
.sec-h .more:active{opacity:.6}
/* 地面站底栏 */
.gs-foot{flex:none;display:flex;gap:10px;padding:12px 16px calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 12px);
         background:var(--bg);border-top:1px solid var(--line)}
.gs-lock{display:none;align-items:center;justify-content:center;gap:7px;font-size:calc(13px*var(--f));font-weight:600;
         color:var(--ink2);background:var(--panel)}
.gs-btn{flex:1;height:48px;border-radius:14px;display:flex;align-items:center;justify-content:center;gap:7px;
        font-size:calc(14px*var(--f));font-weight:700;transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.gs-btn.ghost{background:var(--panel);color:var(--ink)}
.gs-btn.solid{background:var(--ink);color:var(--bg)}
.gs-btn:active{transform:scale(.96)}
/* 考试模式:锁定图形选择,隐藏操作按钮,徽标变红 */
.gs-exam .shape-seg{pointer-events:none;opacity:.55}
.gs-exam #gsFoot{display:none}
.gs-exam .gs-lock{display:flex}
.chip-red{background:rgba(229,72,77,.14);color:#D74448}
/* 收藏侧按钮 */
.fav-side{width:58px;height:50px;border-radius:14px;background:var(--bg);border:1px solid var(--line);
          display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
          font-size:calc(10px*var(--f));font-weight:600;color:var(--ink2);flex:none;transition:all .2s}
.fav-side.on{background:var(--accent-soft);color:var(--accent);border-color:rgba(28,92,228,.4)}
.fav-side:active{transform:scale(.94)}
.gs-field{display:flex;flex-direction:column;gap:4px;font-size:calc(11px*var(--f));color:var(--ink3);font-weight:600}
.gs-field input{height:42px;border:1px solid var(--line);border-radius:10px;padding:0 10px;font-size:calc(14px*var(--f));
                background:var(--bg);color:var(--ink);font-variant-numeric:tabular-nums;box-sizing:border-box}
/* 表单页(设置/发帖) */
.f-label{font-size:calc(12px*var(--f));color:var(--ink3);font-weight:600;margin:14px 0 6px}
.f-input{width:100%;height:44px;border:1px solid var(--line);border-radius:12px;padding:0 12px;font-size:calc(14px*var(--f));
         background:var(--bg);color:var(--ink);box-sizing:border-box}
.f-area{width:100%;height:120px;border:1px solid var(--line);border-radius:12px;padding:12px;font-size:calc(14px*var(--f));
        background:var(--bg);color:var(--ink);box-sizing:border-box;resize:none;line-height:1.6}
/* 发帖页底部那一句"按哪个键发"。
   为什么需要它:发帖的全页入口收到右上角之后,学员滚到最底下会**找不到按钮** ——
   而"找不到按钮"和"这页坏了"在他眼里是同一件事。所以底部留一句说明,把位置说清楚。
   不是按钮,所以不做成按钮的样子(灰字、无边框、不可点)。 */
.post-hint{margin:18px 0 8px;font-size:calc(12px*var(--f));color:var(--ink3);line-height:1.7}
/* 意见反馈弹层(2026-10-05 从"复制到剪贴板"改成真提交之后新增的三块)。
   为什么分类 chip 要 38px 高(而不是复用全局 `.chip` 的 3px 8px):
   全局 `.chip` 是"标签"的样子,只在后台表格里当色块用;这里是**要点的**,
   而体检脚本的判据是高度 <36px 就算热区过小(见 .workbench/cdp-full-audit.mjs:72)。
   手指点偏了会提交到别的分类,学员根本不会发现。 */
.fb-kinds{display:flex;gap:10px;margin-top:12px}
.fb-kinds .chip{height:38px;padding:0 14px;border:1px solid var(--line);border-radius:10px;background:var(--bg);
               color:var(--ink2);font-size:calc(13px*var(--f));cursor:pointer;justify-content:center}
.fb-kinds .chip.on{background:var(--accent-soft);border-color:var(--accent);color:var(--accent);font-weight:700}
.fb-kinds .chip:active{opacity:.7}
/* 「我提过的」。为什么要摆这个列表(而不是只靠铃铛里的通知):
   通知会沉底、会被"全部已读"清掉,而"我提过什么、平台是怎么答的"应该随时查得到 ——
   学员回来问"我上次说的那个改了吗",他需要的是能翻到原话的那一页。 */
.fb-mine{margin-top:16px}
.fb-mine .fm-head{display:flex;align-items:center;gap:8px;font-size:calc(12px*var(--f));color:var(--ink3);font-weight:600;margin-bottom:8px}
.fb-mine .fm-card{border:1px solid var(--line);border-radius:12px;padding:12px;margin-bottom:10px;background:var(--bg)}
.fb-mine .fm-top{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.fb-mine .fm-top .fb-time{margin-left:auto;font-size:calc(11px*var(--f));color:var(--ink3)}
.fb-mine .fm-body{font-size:calc(13px*var(--f));color:var(--ink);line-height:1.7;white-space:pre-wrap;word-break:break-word}
/* 平台回复与学员原话**必须分得开**:同色同底的话,学员会以为那段是他自己写的,
   或者反过来以为整条都是客服说的。左侧一道强调色竖线是这套 UI 里"这是引用/回应"的既有语言。 */
.fb-mine .fm-reply{margin-top:10px;padding:10px 12px;border-left:3px solid var(--accent);background:var(--accent-soft);border-radius:0 10px 10px 0}
.fb-mine .fm-reply .fm-who{font-size:calc(11px*var(--f));color:var(--accent);font-weight:700;margin-bottom:4px}
.fb-mine .fm-reply .fm-body{font-size:calc(12.5px*var(--f))}
.fb-mine .fm-wait{margin-top:10px;font-size:calc(11.5px*var(--f));color:var(--ink3)}
.fb-mine .fm-empty{font-size:calc(12px*var(--f));color:var(--ink3);line-height:1.75;padding:14px 2px}
.fb-mine .fm-retry{display:inline-flex;align-items:center;min-height:36px;margin-top:6px;color:var(--accent);font-weight:700;font-size:calc(12.5px*var(--f))}
.step-row{display:flex;align-items:center;justify-content:space-between;padding:13px 0;border-bottom:1px solid var(--line)}
.step-row:last-child{border-bottom:none}
.step-row .k{font-size:calc(13px*var(--f));color:var(--ink)}
.stepper{display:flex;align-items:center;gap:12px}
.stepper .st-btn{width:28px;height:28px;border-radius:9px;background:var(--panel);display:flex;align-items:center;
                 justify-content:center;font-size:calc(16px*var(--f));font-weight:700;color:var(--ink)}
.stepper .st-v{font-size:calc(15px*var(--f));font-weight:700;font-variant-numeric:tabular-nums;min-width:36px;text-align:center}
/* 项目详情 */
.detail-hero{height:150px;border-radius:var(--r-lg);overflow:hidden;position:relative;margin-top:12px}
.detail-hero img{width:100%;height:100%;object-fit:cover;display:block}
.detail-hero .mask{position:absolute;inset:0;background:linear-gradient(180deg,rgba(17,19,24,0) 40%,rgba(17,19,24,.55) 100%)}
.detail-hero .dh-tag{position:absolute;left:12px;top:12px}
.detail-hero .dh-title{position:absolute;left:14px;right:14px;bottom:12px;color:#fff;font-size:calc(16px*var(--f));font-weight:700}
.param{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border:1px solid var(--line);
       border-radius:12px;overflow:hidden;margin-top:10px}
.param .p{background:var(--bg);padding:9px 12px}
.param .p b{font-weight:600;color:var(--ink3);display:block;font-size:calc(11px*var(--f))}
.param .p span{color:var(--ink);font-size:calc(12.5px*var(--f));font-weight:600}
.pair-btns{display:flex;gap:10px;margin:10px 16px 0}
.pair-btns .pb{flex:1;height:46px;border-radius:12px;display:flex;align-items:center;justify-content:center;
               font-size:calc(13.5px*var(--f));font-weight:700}
.pair-btns .pb.on{outline:2px solid var(--accent);outline-offset:1px}
.pb-green{background:var(--ink);color:var(--bg)}
.pb-blue{background:var(--accent-soft);color:var(--accent)}
.rule-text{font-size:calc(12px*var(--f));color:var(--ink2);line-height:1.8}
.rule-text b{color:var(--ink)}
.cur-param{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}
.cur-param .cp{background:var(--panel);border-radius:10px;padding:9px 11px}
.cur-param .cp b{color:var(--ink3);font-weight:600;display:block;font-size:calc(10.5px*var(--f))}
.cur-param .cp span{color:var(--ink);font-weight:600;font-size:calc(12px*var(--f))}
.post-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);padding:12px 14px;
           margin-top:10px;box-shadow:var(--shadow);cursor:pointer}
.post-card .p-top{display:flex;justify-content:space-between;font-size:calc(11px*var(--f));color:var(--ink3)}
.post-card .p-top .p-author{color:var(--ink2);font-weight:600}
.post-card .p-title{font-size:calc(14.5px*var(--f));font-weight:700;margin-top:6px;line-height:1.45}
.post-card .p-body{font-size:calc(12px*var(--f));color:var(--ink2);margin-top:4px;line-height:1.6;
                   display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.post-card .p-foot{display:flex;gap:16px;margin-top:8px;font-size:calc(11px*var(--f));color:var(--ink3)}
.post-card .p-foot .more{margin-left:auto;color:var(--accent);font-weight:600}
/* 「删除」文字按钮(自己发的帖子 / 自己的评论、以及帖子作者删自己帖子下的评论)。
   颜色用 --err-fg(#B8232B)而不是 --red(#E5484D):后者是"实底 + 白字"那一档,
   当浅色卡片上的小字用对比度不够 —— 口径见本文件"浅底上的小字"那一段。 */
.p-del{color:var(--err-fg);font-weight:600;margin-left:12px;white-space:nowrap}
.post-card .p-foot .p-del{margin-left:14px}
/* 评论行里的那个:靠右贴边,字号再小一档(评论正文是 12.5px) */
.p-del.sm{font-size:calc(10.5px*var(--f));margin-left:auto;padding-left:10px}
.pd-manage{display:flex;justify-content:flex-end;margin-top:10px;font-size:calc(12px*var(--f))}
/* 帖子详情 + 评论栏 */
.pd-actions{display:flex;gap:8px;margin-top:12px}
.pd-actions .btn{flex:1;height:42px;border-radius:12px;background:var(--panel);color:var(--ink);
                 display:flex;align-items:center;justify-content:center;gap:6px;font-size:calc(13px*var(--f));font-weight:600}
.pd-actions .btn.on{background:var(--accent-soft);color:var(--accent)}
.comment-bar{flex:none;display:flex;gap:10px;padding:12px 16px calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 12px);
             background:var(--bg);border-top:1px solid var(--line)}
.comment-bar input{flex:1;height:42px;border:1px solid var(--line);border-radius:999px;padding:0 16px;
                   font-size:calc(13px*var(--f));background:var(--bg);color:var(--ink);box-sizing:border-box}
.comment-bar .send{height:42px;padding:0 18px;border-radius:999px;background:var(--ink);color:var(--bg);
                   font-size:calc(13px*var(--f));font-weight:700;display:flex;align-items:center}

/* ============ 评论回复(楼中楼)+「回复」入口(2026-10-05 加)============
   服务端 post_comments 补了 parent_id,详情接口已经把 rootId / replyTo 算好下发,
   这一段是端上的显示。**只做两层**:回复的回复也挂在同一个顶层评论下 ——
   再深就要缩进到屏幕外了,而学员要的只是"知道在跟谁说话"。 */
#pdCommentList .row.rep{margin-left:30px;padding-left:10px;border-left:2px solid var(--line)}
#pdCommentList .row.rep .stu-avatar{width:24px;height:24px;font-size:calc(11px*var(--f))}
/* 「回复 @谁」:只有回复才有的前缀,与正文同一行 */
.r-at{color:var(--accent);font-weight:700;margin-right:4px}
/* 评论下面那一行小动作(回复 / 删除)。
   为什么放进正文那个 div 里而不是再加一个 .row 的孩子:.row 是 flex 行,
   多一个孩子就会把正文挤窄;放进正文里则自然换到第二行。 */
.c-foot{display:flex;align-items:center;gap:16px;margin-top:5px}
.c-foot .p-del.sm{margin-left:0;padding-left:0}
/* 「回复」文字按钮。为什么不复用 .p-del:那个是破坏性操作的红字(--err-fg),
   回复是中性动作 —— 混用会让"删除"和"回复"长得一样,而这两件事的后果差得远。 */
.p-rep{color:var(--accent);font-weight:600;font-size:calc(10.5px*var(--f));white-space:nowrap}
.p-rep:active,.p-del:active{opacity:.55}
/* 回复提示行:点了评论上的「回复」才出现,说清"你现在在回谁",并给一个明确的取消。
   为什么不塞进 .comment-bar:那是一条 flex 行(输入框 flex:1 + 发送),
   硬加第三个孩子会把输入框挤窄;单独一行更稳,也更容易看清在回复谁。 */
.reply-hint{flex:none;display:flex;align-items:center;gap:8px;padding:2px 16px;min-height:40px;
            font-size:calc(11.5px*var(--f));color:var(--ink2);background:var(--bg);
            border-top:1px solid var(--line)}
.reply-hint b{color:var(--accent)}
/* 取消回复的 ✕:热区必须 ≥36px —— 全站体检的判据就是这么写的
   (`.workbench/cdp-full-audit.mjs` 里 `r.height < 36` 记一条「热区过小」),
   而它旁边就是一个"点了会发出去"的输入框,点偏了的代价是发错地方,不能靠 15px 的小叉子。 */
.reply-hint .rh-x{margin-left:auto;color:var(--ink3);font-weight:700;
                  min-width:36px;height:36px;display:flex;align-items:center;justify-content:center;
                  border-radius:8px}
.reply-hint .rh-x:active{opacity:.55;background:var(--line)}
/* 提示行就在评论栏上面,两条 border-top 会叠成一条粗线 —— 去掉下面那条 */
.reply-hint + .comment-bar{border-top:none}

/* ============ 消息(站内通知,2026-10-05 加)============
   为什么在首页顶栏放一枚铃铛而不是往宫格里加一格:宫格每一格都是"去练点什么",
   而消息是"别人对你做过什么",性质不同;铃铛是这件事的通用位置。 */
.mode-pill.msg-bell{position:relative;width:38px;height:38px;padding:0;justify-content:center}
.msg-bell .ic{width:17px;height:17px}
/* 未读角标:实底 + 白字用 --red(#E5484D);浅底上的红字才用 --err-fg(#B8232B)。
   两者分工见本文件第 46 行那条注释。 */
.msg-dot{position:absolute;top:-2px;right:-2px;min-width:17px;height:17px;padding:0 4px;border-radius:999px;
         background:var(--red);color:#fff;font-size:calc(10px*var(--f));font-weight:800;line-height:17px;
         text-align:center;box-sizing:border-box;box-shadow:0 0 0 2px var(--bg)}
/* 「全部已读」同样是热区 ≥36px 的规矩(见上面 .rh-x 那条):
   它是个"一按下去几十条就全变已读"的动作,点偏了没有第二次确认的机会。 */
.msg-allread{margin-left:auto;color:var(--accent);font-weight:700;font-size:calc(12px*var(--f));
             min-height:36px;display:flex;align-items:center;padding:0 12px;border-radius:999px;
             white-space:nowrap}
.msg-allread:active{opacity:.6;background:var(--line)}
.msg-allread[hidden]{display:none}
/* 未读那一条:标题前面一枚红点。
   为什么两个状态都用 ::before 占位、只换颜色:否则标成已读的瞬间整行文字会右移一下。 */
.msg-row .r-t b::before{content:'';display:inline-block;width:6px;height:6px;border-radius:50%;
                        background:transparent;margin-right:6px;vertical-align:1px}
.msg-row.unread .r-t b::before{background:var(--red)}
.msg-row.unread .r-t b{font-weight:800}
/* 分段控件里那个未读数(「未读 3」)。空着的时候不占位,所以不用 :empty 之类的技巧。 */
.seg .seg-n{font-weight:800;margin-left:4px}
/* 消息行右边那个「✕」(删掉这一条)。
   为什么给它 34px 高:小于 36px 的点击热区会被 cdp-full-audit.mjs 记成「热区过小」
   (那条判据在 .workbench/cdp-full-audit.mjs:72),而这枚 ✕ 在手机上本来就不好点。 */
.msg-row .msg-x{flex:none;width:34px;height:34px;display:flex;align-items:center;justify-content:center;
                color:var(--ink3);font-size:calc(14px*var(--f));font-weight:700}
.msg-row .msg-x:active{opacity:.5}
/* 刷题页:当前题库卡(选择完成后的入口态) */
.bank-head{display:flex;align-items:center;gap:13px;margin:10px 16px 0;background:var(--bg);
           border:1px solid var(--line);border-radius:var(--r-lg);padding:13px 14px;cursor:pointer;
           box-shadow:var(--shadow);transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .18s ease}
.bank-head:active{transform:scale(.985)}
.bh-media{position:relative;width:56px;height:56px;flex:none;border-radius:14px;overflow:hidden;
          background:linear-gradient(180deg,#39404A 0%,#23272D 100%)}
.bh-media img{width:100%;height:100%;object-fit:cover;display:block;border-radius:14px;
              border:1px solid rgba(17,19,24,.06)}
.bh-media.live img{display:none}
.bh-media canvas{position:absolute;inset:0;width:100%;height:100%;border-radius:14px}
.bh-txt{flex:1;min-width:0}
.bh-txt b{font-size:calc(15.5px*var(--f));font-weight:700;color:var(--ink);display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bh-txt .bh-sub{display:flex;align-items:baseline;gap:7px;margin-top:4px;font-size:calc(12px*var(--f));color:var(--ink2);font-weight:500}
.bh-txt .bh-sub em{font-style:normal}
.bh-txt .bh-sub i{font-style:normal;color:var(--ink3)}
.bh-switch{flex:none;display:flex;align-items:center;gap:4px;background:var(--accent-soft);color:var(--accent);
           font-size:calc(12px*var(--f));font-weight:700;padding:8px 13px;border-radius:999px}
@media (hover:hover) and (pointer:fine){
  .bank-head:hover{box-shadow:0 8px 18px rgba(17,19,24,.08)}
}
/* 题库与执照选择:机型区 = 可搬移 3D 机库舞台 + 紧凑选择卡 */
.lic-app{padding:6px 16px 28px}
.lic-sec{margin-top:22px}
.lic-sec:first-child{margin-top:16px}
.lic-sec-h{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:12px}
.lic-sec-h b{font-size:calc(15px*var(--f));font-weight:700;color:var(--ink)}
.lic-sec-h span{font-size:calc(11px*var(--f));color:var(--ink3);font-weight:500}
/* 机型区:四张卡片各带一个迷你 3D 机库(可拖拽旋转,轻点选中) */
.m-grid3d{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.m3d-hint{margin-top:10px;font-size:calc(11px*var(--f));color:var(--ink3);font-weight:500}
.m-card{position:relative;display:flex;flex-direction:column;border:1.5px solid var(--line);border-radius:16px;
        background:var(--bg);overflow:hidden;cursor:pointer;box-shadow:var(--shadow);
        transition:border-color .15s ease,box-shadow .18s ease}
.m-card .m3d{position:relative;height:112px;background:linear-gradient(180deg,#F6F8FA 0%,#E1E6EB 100%);overflow:hidden}
.m-card .m3d canvas{position:absolute;inset:0;width:100%;height:100%;touch-action:pan-y;cursor:grab}
.m-card .m3d canvas:active{cursor:grabbing}
.m-card .m3d-fb{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:none}
.m-card .m3d.fail .m3d-fb{display:block}
.m-card .m3d.fail canvas{display:none}
.m-card .m3d-loading{position:absolute;top:50%;left:50%;width:22px;height:22px;margin:-11px 0 0 -11px;
                     border:2.5px solid rgba(17,19,24,.12);border-top-color:var(--accent);border-radius:50%;
                     animation:spin .9s linear infinite}
.m-card .m3d.ok .m3d-loading{display:none}
.m-card .m-txt{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:10px 11px}
.m-card .m-txt b{font-size:calc(13px*var(--f));font-weight:700;color:var(--ink);padding-right:4px;white-space:nowrap;overflow:hidden;
                 text-overflow:ellipsis;min-width:0}
.m-card .m-num{flex:none;font-size:calc(11px*var(--f));font-weight:600;color:var(--ink2);font-variant-numeric:tabular-nums;white-space:nowrap}
.m-card .m-num.off{color:var(--ink3);font-weight:500}
.m-card .m-check{position:absolute;top:10px;right:10px;width:18px;height:18px;border-radius:50%;
                 background:var(--accent);color:#fff;display:none;align-items:center;justify-content:center;
                 box-shadow:0 2px 6px rgba(28,92,228,.45)}
.m-card.on{border-color:var(--accent);box-shadow:0 1px 2px rgba(17,19,24,.05),0 6px 16px rgba(28,92,228,.10)}
.m-card.on .m-check{display:flex}
.m-card.on .m-txt{background:var(--accent-soft)}
@media (hover:hover) and (pointer:fine){
  .m-card:hover{border-color:#D9DBE0}
}
/* 执照类别卡的视角标签 */
.lv-cam{flex:none;font-size:calc(10px*var(--f));font-weight:600;color:var(--ink3);background:var(--panel);border-radius:8px;
        padding:3px 8px;white-space:nowrap}
.lv-card.on .lv-cam{color:var(--accent);background:rgba(255,255,255,.75)}
/* 执照类别卡 */
.lv-list{display:flex;flex-direction:column;gap:10px}
.lv-card{display:flex;align-items:center;gap:12px;border:1.5px solid var(--line);border-radius:16px;padding:13px 14px;
         background:var(--bg);cursor:pointer;box-shadow:var(--shadow);
         transition:transform .3s cubic-bezier(.34,1.56,.64,1),border-color .15s ease,background .15s ease}
.lv-card .lv-ic{width:40px;height:40px;border-radius:12px;background:var(--panel);display:flex;align-items:center;
                justify-content:center;color:var(--ink);flex:none;transition:background .15s ease,color .15s ease}
.lv-txt{flex:1;min-width:0}
.lv-txt b{font-size:calc(14px*var(--f));font-weight:700;color:var(--ink);display:flex;align-items:center;gap:7px}
.lv-txt b .lv-tag{display:none;font-style:normal;font-size:calc(10px*var(--f));font-weight:600;color:var(--accent);
                  background:var(--accent-soft);border-radius:999px;padding:2px 7px}
.lv-card.on .lv-txt b .lv-tag{display:inline-flex}
.lv-txt span{font-size:calc(11.5px*var(--f));color:var(--ink3);display:block;margin-top:3px;line-height:1.45}
.lv-radio{width:22px;height:22px;border-radius:50%;border:1.5px solid #D9DBE0;flex:none;display:flex;align-items:center;
          justify-content:center;color:transparent;transition:border-color .15s ease,background .15s ease,color .15s ease}
.lv-card.on{border-color:var(--accent);background:var(--accent-soft)}
.lv-card.on .lv-ic{background:var(--accent);color:#fff}
.lv-card.on .lv-radio{border-color:var(--accent);background:var(--accent);color:#fff}
.lv-card:active{transform:scale(.98)}
/* 确定栏(吸底) */
.lic-foot{flex:none;padding:10px 16px calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 12px);background:var(--bg);
          border-top:1px solid var(--line)}
.lic-foot .btn-black{/* 高度/圆角统一走 L 档(原来单独写成 48/14,和别的页面主按钮不一样) */}
.lic-sum{display:flex;align-items:baseline;gap:7px;padding:0 2px 10px;font-size:calc(12.5px*var(--f));color:var(--ink)}
.lic-sum span{font-size:calc(11px*var(--f));font-weight:600;color:var(--ink3)}
.lic-sum b{font-weight:700}
.lic-sum i{font-style:normal;color:var(--ink3)}
/* 比赛卡:紧凑型(小图标块,无长图) */
.ri-ic{width:46px;height:46px;border-radius:14px;display:flex;align-items:center;justify-content:center;
       color:#fff;flex:none}
.ic-a{background:linear-gradient(135deg,#1c2a3a,#3a4a5c)}
.ic-b{background:linear-gradient(135deg,#7a5410,#B7791F)}
.ic-c{background:linear-gradient(135deg,#155e5e,#0E7F7F)}
.race-item{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);padding:12px;
           margin-top:10px;box-shadow:var(--shadow)}
.race-item .ri-top{display:flex;align-items:center;gap:8px}
.race-item .ri-title{font-size:calc(13.5px*var(--f));font-weight:700;margin-top:6px;line-height:1.5}
.race-item .ri-meta{display:flex;gap:12px;margin-top:6px;font-size:calc(11px*var(--f));color:var(--ink3)}
/* ---------- 题库选择页:状态化题库卡(第三版) ----------
   每张卡按「已开通 / 未开通」给不同的右侧大数字与主按钮,不再是一串价格加两个长得一样的按钮 */
.bank-card{display:block;background:var(--bg);border:1px solid var(--line);border-radius:16px;
           padding:13px 14px 12px;margin:10px 16px 0;box-shadow:var(--shadow);cursor:pointer}
.bk-head{display:flex;align-items:center;gap:11px}
.bk-ic{width:44px;height:44px;border-radius:13px;display:flex;align-items:center;justify-content:center;
       font-size:calc(16px*var(--f));font-weight:800;flex:none}
.bk-ic.cat-fire{background:rgba(229,72,77,.12);color:#D74448}
.bk-ic.cat-guard{background:rgba(61,123,253,.12);color:#2F66E6}
.bk-ic.cat-build{background:rgba(183,121,31,.14);color:#B06D10}
.bk-ic.cat-uav{background:var(--accent-soft);color:var(--accent)}
.bk-title{flex:1;min-width:0}
.bk-name{display:block;font-size:calc(14px*var(--f));font-weight:700;line-height:1.35;
         white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bk-sub{display:flex;align-items:center;gap:6px;margin-top:5px;font-size:calc(11px*var(--f));color:var(--ink3);
        white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bk-sub .chip{flex:none;padding:2px 7px}
.bk-right{flex:none;text-align:right}
.bk-big{display:block;font-size:calc(17px*var(--f));font-weight:800;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.bk-big.price{color:#E5484D}
.bk-big.ok{color:var(--accent)}
.bk-small{display:block;font-size:calc(10.5px*var(--f));color:var(--ink3);margin-top:3px}
.bk-prog{height:5px;border-radius:3px;background:var(--panel);margin-top:11px;overflow:hidden}
.bk-prog i{display:block;height:100%;border-radius:3px;background:var(--accent);transition:width .45s var(--ease)}
.bk-actions{display:flex;gap:8px;margin-top:11px;padding-top:11px;border-top:1px solid var(--line)}
.bk-btn{flex:1;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;
        font-size:calc(12.5px*var(--f));font-weight:600;
        transition:transform .3s cubic-bezier(.34,1.56,.64,1),background .15s ease,opacity .15s ease}
.bk-btn.solid{background:var(--ink);color:var(--bg);font-weight:700}
.bk-btn.ghost{background:var(--panel);color:var(--ink)}
.bk-btn:active{transform:scale(.96)}
.bk-btn.busy::before{width:12px;height:12px;margin-right:6px}
/* 购买弹层里的价格沿用同一套红色数字 */
.bk-price{color:#E5484D;font-weight:800;font-variant-numeric:tabular-nums}
/* 全局卡片交互:按压下沉 + 桌面悬停抬升(比赛卡/项目卡/题库卡/班级卡/报名行/首页活动卡) */
.bank-card,.race-card,.proj-card,.class-card,.signup-row,.race-item{
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .18s ease,border-color .15s ease}
.bank-card:active,.race-card:active,.proj-card:active,.class-card:active,.signup-row:active,.race-item:active{transform:scale(.98)}
@media (hover:hover) and (pointer:fine){
  .bank-card:hover,.race-card:hover,.proj-card:hover,.class-card:hover,.signup-row:hover,.race-item:hover{
    box-shadow:0 8px 18px rgba(17,19,24,.08);border-color:#D9DBE0}
}
/* 分段控件与 FAQ 的按压反馈 */
.seg span,.filter span{transition:background .2s ease,color .2s ease,transform .3s cubic-bezier(.34,1.56,.64,1)}
.seg span:active,.filter span:active{transform:scale(.97)}
.faq-q:active{opacity:.65}
.cd-code:active{opacity:.6}
.attach:active{background:var(--gap)}
/* 无人机+ 横幅:流光扫过 */
.banner{position:relative;overflow:hidden}
.banner::after{content:'';position:absolute;top:0;bottom:0;left:-60%;width:40%;
               background:linear-gradient(105deg,transparent,rgba(255,255,255,.16),transparent);
               transform:skewX(-18deg);animation:bannerSweep 4.5s ease-in-out infinite;pointer-events:none}
@keyframes bannerSweep{0%{left:-60%}55%,100%{left:130%}}
@media (prefers-reduced-motion:reduce){.banner::after{animation:none}}
/* 顶栏胶囊按钮(我的报名等) */
.top-pill{flex:none;display:flex;align-items:center;gap:5px;background:var(--accent-soft);color:var(--accent);
          padding:7px 12px;border-radius:999px;font-size:calc(12px*var(--f));font-weight:600;cursor:pointer;
          transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.top-pill:active{transform:scale(.94)}
/* 主题/模式胶囊按钮(首页深色模式 · 刷题页长辈版;开启=实心反色) */
.mode-pill{flex:none;display:flex;align-items:center;gap:6px;background:var(--panel);color:var(--ink2);
           border:1px solid rgba(17,19,24,.05);padding:7px 12px;border-radius:999px;font-size:calc(12px*var(--f));
           font-weight:700;cursor:pointer;
           transition:transform .3s cubic-bezier(.34,1.56,.64,1),background .2s ease,color .2s ease,border-color .2s ease}
.mode-pill .ic{width:15px;height:15px}
.mode-pill.on{background:var(--ink);color:var(--bg);border-color:transparent}
.mode-pill:active{transform:scale(.94)}
body.dark .mode-pill{border-color:rgba(242,244,246,.08)}
/* 切换瞬间的图标动作:深色=绕一圈,长辈版=放大回弹 */
.mode-pill.spin .ic{animation:pillSpin .58s cubic-bezier(.34,1.56,.64,1)}
@keyframes pillSpin{0%{transform:rotate(0) scale(1)}55%{transform:rotate(-200deg) scale(1.15)}100%{transform:rotate(-360deg) scale(1)}}
.mode-pill.grow .ic{animation:pillGrow .55s cubic-bezier(.34,1.56,.64,1)}
@keyframes pillGrow{0%{transform:scale(1)}45%{transform:scale(1.4)}100%{transform:scale(1)}}
/* 全页颜色渐变:切换瞬间临时挂载 body.theme-anim,结束后移除(深↔浅、常规↔长辈的底色/文字/描边一起渐变) */
body.theme-anim,body.theme-anim *,body.theme-anim *::before,body.theme-anim *::after{
  transition:background-color .46s cubic-bezier(.4,0,.2,1),color .46s cubic-bezier(.4,0,.2,1),
             border-color .46s cubic-bezier(.4,0,.2,1),fill .46s cubic-bezier(.4,0,.2,1),
             stroke .46s cubic-bezier(.4,0,.2,1),box-shadow .46s cubic-bezier(.4,0,.2,1)!important}
/* 从被点的按钮位置扩散一圈光晕(青绿/白,按切换方向取色) */
.theme-glow{position:absolute;width:200px;height:200px;margin:-100px 0 0 -100px;border-radius:50%;
            pointer-events:none;z-index:190;opacity:0;
            background:radial-gradient(circle,var(--glow,rgba(28,92,228,.3)) 0%,transparent 68%)}
.theme-glow.run{animation:glowPop .68s cubic-bezier(.22,.61,.36,1)}
@keyframes glowPop{0%{opacity:.85;transform:scale(.25)}60%{opacity:.38}100%{opacity:0;transform:scale(2.9)}}
@media (prefers-reduced-motion:reduce){
  body.theme-anim,body.theme-anim *,body.theme-anim *::before,body.theme-anim *::after{transition:none!important}
  .theme-glow.run,.mode-pill.spin .ic,.mode-pill.grow .ic{animation:none}
}
/* 比赛/项目分段控件(iOS 风:选中项浮起成白卡) */
.race-tabs{display:flex;margin:12px 16px 0;background:var(--panel);border-radius:12px;padding:3px}
.race-tabs span{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:9px 0;
                border-radius:10px;font-size:calc(13.5px*var(--f));font-weight:600;color:var(--ink2);cursor:pointer;
                transition:background .2s ease,color .2s ease,box-shadow .2s ease,transform .3s cubic-bezier(.34,1.56,.64,1)}
.race-tabs span.on{background:var(--bg);color:var(--ink);box-shadow:0 1px 4px rgba(17,19,24,.10)}
.race-tabs span:active{transform:scale(.96)}
/* 搜索行:常驻可见(不再用「假输入框 → 展开搜索态」两套状态),计数就在下面一行 */
.ms-input{margin:10px 16px 0;display:flex;align-items:center;gap:8px;height:44px;padding:0 13px;background:var(--panel);
          border-radius:12px;border:1.5px solid transparent;transition:border-color .15s ease,background .15s ease}
.ms-input:focus-within{border-color:var(--accent);background:var(--bg)}
.ms-input input{flex:1;border:none;outline:none;background:transparent;font-size:calc(13.5px*var(--f));color:var(--ink);min-width:0}
.ms-input input::placeholder{color:var(--ink3)}
.ms-clear{width:24px;height:24px;border-radius:50%;background:rgba(17,19,24,.14);color:#fff;display:none;
          align-items:center;justify-content:center;font-size:calc(12px*var(--f));cursor:pointer;flex:none}
.ms-input.has .ms-clear{display:flex}
.ms-count{margin:8px 16px 0;font-size:calc(11px*var(--f));color:var(--ink3)}
.ms-empty{display:none;text-align:center;padding:30px 20px 14px;color:var(--ink2);font-size:calc(13.5px*var(--f));font-weight:600}
.ms-empty .ic{width:25px;height:25px;color:var(--ink3);margin:0 auto 12px;display:block;
              padding:14px;box-sizing:content-box;background:var(--panel);border-radius:50%}
.ms-empty span{display:block;font-size:calc(11.5px*var(--f));color:var(--ink3);font-weight:400;margin-top:5px;line-height:1.7}
.ms-empty-btn{margin:16px auto 0;height:36px;padding:0 18px;border-radius:999px;background:var(--panel);color:var(--ink);
              font-size:calc(12.5px*var(--f));font-weight:600;display:flex;align-items:center;justify-content:center;cursor:pointer}
/* ---------- 题库选择页:品牌卡(白底发丝线,替掉原来的青绿大横幅)+ 分类筛选 chip ---------- */
.brand-card{margin:12px 16px 0;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);
            padding:14px;box-shadow:var(--shadow)}
.bc-top{display:flex;align-items:center;gap:12px}
.bc-ic{width:46px;height:46px;border-radius:14px;background:var(--accent-soft);color:var(--accent);
       display:flex;align-items:center;justify-content:center;flex:none}
.bc-txt{flex:1;min-width:0}
.bc-txt b{display:block;font-size:calc(15px*var(--f));font-weight:700;line-height:1.35}
.bc-txt span{display:block;font-size:calc(11.5px*var(--f));color:var(--ink3);margin-top:3px}
.bc-link{flex:none;font-size:calc(12px*var(--f));font-weight:600;color:var(--accent);cursor:pointer;
         display:inline-flex;align-items:center;min-height:36px;padding:0 2px;margin:0 -2px;transition:opacity .15s ease}
.bc-link:active{opacity:.6}
.bc-stats{display:flex;margin-top:13px;padding-top:12px;border-top:1px solid var(--line)}
.bc-stats .bs{flex:1;padding:0 12px;border-right:1px solid var(--line)}
.bc-stats .bs:first-child{padding-left:0}
.bc-stats .bs:last-child{border-right:none;padding-right:0}
.bc-stats .bs b{display:block;font-size:calc(19px*var(--f));font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.bc-stats .bs span{display:block;font-size:calc(11px*var(--f));color:var(--ink3);margin-top:2px}
/* 类目条:内容宽度、可横向滚动 —— 类目从 4 个涨到 12 个也不会挤(等宽分段控件放不下,
   所以这里不复用 .seg);右缘渐隐只在「右边还有没露出来的类目」时出现 */
.bank-cats-wrap{position:relative;margin:12px 16px 0}
.bank-cats-wrap::after{content:'';position:absolute;top:0;right:0;bottom:0;width:30px;pointer-events:none;
  background:linear-gradient(90deg,rgba(255,255,255,0),var(--bg) 78%);opacity:0;
  transition:opacity var(--dur-2) linear}
.bank-cats-wrap.more::after{opacity:1}
body.dark .bank-cats-wrap::after{background:linear-gradient(90deg,rgba(20,22,26,0),var(--bg) 78%)}
.bank-cats{display:flex;gap:8px;overflow-x:auto;padding:2px 0;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
.bank-cats::-webkit-scrollbar{display:none}
.bank-cats span{flex:none;display:inline-flex;align-items:center;gap:5px;min-height:36px;padding:0 14px;
  border-radius:999px;background:var(--bg);border:1px solid var(--line);color:var(--ink2);
  font-size:calc(12.5px*var(--f));font-weight:600;cursor:pointer;white-space:nowrap;
  transition:transform var(--dur-3) var(--ease-spring),background var(--dur-1) linear,
             border-color var(--dur-1) linear,color var(--dur-1) linear}
.bank-cats span i{font-style:normal;font-size:calc(10.5px*var(--f));font-weight:700;color:var(--ink3);
  font-variant-numeric:tabular-nums;transition:color var(--dur-1) linear}
.bank-cats span.on{background:var(--ink);color:var(--bg);border-color:transparent}
.bank-cats span.on i{color:#7FE3E3}
.top-pill.on{background:var(--ink);color:var(--bg);border-color:transparent}
.top-pill.on .ic{color:var(--bg)}
/* 地面站:参数行/规则块/KPI 芯片 */
.gs-row{display:flex;align-items:center;justify-content:space-between;padding:11px 0;border-bottom:1px solid var(--line)}
.gs-row:last-child{border-bottom:none}
.gs-row .k{font-size:calc(12px*var(--f));color:var(--ink3)}
.gs-row .v{font-weight:600;font-size:calc(13px*var(--f));font-variant-numeric:tabular-nums;white-space:nowrap}
/* ---------- 地面站「附加要求」:参数格 ----------
   一行行的「标签-值」在手机上要扫 6 遍;改成「小灰标签 + 大数字」的格子:
   1 个通栏(飞行距离)+ 4 个并排(参照距离/高度/两个朝向)+ 1 个通栏(经纬度),
   数值 15px 加粗、标签 10.5px 灰,考试那 6 分钟里一眼能读到。朝向还带一个按方位旋转的箭头。 */
.req-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.req-head b{font-size:calc(14px*var(--f))}
.req-head .req-note{font-size:calc(10.5px*var(--f));color:var(--ink3);white-space:nowrap}
.req-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:11px}
.req-cell{display:flex;flex-direction:column;justify-content:space-between;background:var(--panel);
          border-radius:12px;padding:9px 12px 10px;min-width:0}
.req-cell.wide{grid-column:1 / -1}
.req-cell .rc-k{display:flex;align-items:center;gap:5px;font-size:calc(10.5px*var(--f));line-height:1.45;color:var(--ink3)}
.req-cell .rc-tag{font-style:normal;flex:none;font-size:calc(9.5px*var(--f));font-weight:700;line-height:1.6;
                  color:var(--accent);background:var(--accent-soft);border-radius:5px;padding:0 5px}
.req-cell .rc-k .rc-far{margin-left:auto;font-style:normal;flex:none;font-size:calc(9.5px*var(--f));opacity:.9}
.req-cell .rc-v{display:flex;align-items:center;gap:6px;margin-top:4px;font-size:calc(15px*var(--f));font-weight:800;
                letter-spacing:-.01em;color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden}
.req-cell .rc-v.coord{font-size:calc(13.5px*var(--f));font-weight:700;letter-spacing:0}
.req-cell .rc-v .rc-dir{display:flex;flex:none;color:#FF6A2D;transition:transform var(--dur-3) var(--ease-spring)}
.req-cell .rc-v .rc-dir .ic{width:11px;height:11px;fill:currentColor;stroke:none}
.rule-block{background:var(--info-bg);border:1px solid rgba(28,92,228,.18);border-radius:12px;padding:11px 13px;margin-top:10px}
.rule-block.amber{background:var(--warn-bg);border-color:rgba(183,121,31,.20)}
.kpi-chips{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.kpi-chip{background:var(--bg);border:1px solid var(--line);border-radius:12px;padding:10px 6px;text-align:center}
.kpi-chip b{display:block;font-size:calc(14px*var(--f));font-weight:700;color:var(--ink)}
.kpi-chip span{font-size:calc(10.5px*var(--f));color:var(--ink3)}
/* 比赛卡:海报式封面(发布者可传 16:9 实拍图;未传则按分类渐变+图标+标题压字自动生成) */
.rc-cover{position:relative;height:118px;border-radius:0;color:#fff;padding:14px;display:flex;
          flex-direction:column;justify-content:flex-end;overflow:hidden}
.rc-cover .rc-ic{position:absolute;top:12px;left:12px;width:34px;height:34px;border-radius:10px;
                 background:rgba(255,255,255,.16);display:flex;align-items:center;justify-content:center}
.rc-cover .rc-badge{position:absolute;top:12px;right:12px;background:rgba(255,255,255,.92);color:#D74448;
                    font-size:calc(10.5px*var(--f));font-weight:700;padding:3px 9px;border-radius:999px}
.rc-cover .rc-badge.soon{color:#B7791F}
.rc-cover .rc-title{font-size:calc(14.5px*var(--f));font-weight:700;line-height:1.4;
                     display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.rc-cover .rc-sub{font-size:calc(10.5px*var(--f));opacity:.88;margin-top:4px}
.race-card{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);margin:12px 16px 0;
           overflow:hidden;box-shadow:var(--shadow);cursor:pointer}
.race-card .rc-foot{display:flex;align-items:center;justify-content:space-between;padding:9px 12px;
                     border-top:1px solid var(--line)}
.race-card .rc-meta{font-size:calc(11px*var(--f));color:var(--ink3)}
.race-card .ri-actions{margin-top:0;width:auto;flex:none}
.race-card .ri-actions .btn-ghost-s,.race-card .ri-actions .btn-solid-s{width:76px;flex:none}
.cover-a{background:linear-gradient(135deg,#1c2a3a,#3a4a5c)}
.cover-b{background:linear-gradient(135deg,#7a5410,#B7791F)}
.cover-c{background:linear-gradient(135deg,#155e5e,#0E7F7F)}
/* 项目卡:信息优先,封面退为类型图标块(发布者可传小图替换) */
.proj-card{display:flex;gap:12px;background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);
           margin:12px 16px 0;padding:13px 14px;box-shadow:var(--shadow);cursor:pointer}
.pj-ic{width:52px;height:52px;border-radius:14px;color:#fff;display:flex;align-items:center;justify-content:center;flex:none}
.pj-body{flex:1;min-width:0}
.pj-body b{font-size:calc(14px*var(--f));font-weight:700;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pj-body span{display:block;font-size:calc(11.5px*var(--f));color:var(--ink2);margin-top:3px;line-height:1.5;
              white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pj-body .pj-actions{display:flex;gap:8px;margin-top:9px}
.pj-body .pj-actions div{flex:1;height:32px;border-radius:10px;display:flex;align-items:center;justify-content:center;
                         font-size:calc(12px*var(--f));font-weight:600}
.pj-body .pj-ghost{background:var(--panel);color:var(--ink)}
.pj-body .pj-solid{background:var(--ink);color:var(--bg);font-weight:700}
.ri-actions{display:flex;gap:8px;margin-top:10px}
.ri-actions .btn-ghost-s{flex:1;height:34px;border-radius:10px;background:var(--panel);color:var(--ink);
                          display:flex;align-items:center;justify-content:center;font-size:calc(12px*var(--f));font-weight:600}
.ri-actions .btn-solid-s{flex:1;height:34px;border-radius:10px;background:var(--ink);color:var(--bg);
                         display:flex;align-items:center;justify-content:center;font-size:calc(12px*var(--f));font-weight:700}
/* 论坛:头像 + 发帖 FAB */
.p-avatar{width:34px;height:34px;border-radius:50%;background:var(--ink);color:var(--bg);display:flex;align-items:center;
          justify-content:center;font-size:calc(14px*var(--f));font-weight:700;flex:none}
.p-avatar.c2{background:#2E8B77}
.p-avatar.c3{background:#7C5CD6}
.post-head{display:flex;gap:10px;align-items:center}
.fab-post{position:absolute;right:16px;bottom:calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 20px);height:44px;padding:0 18px;
          border-radius:999px;background:var(--ink);color:#fff;display:flex;align-items:center;gap:6px;
          font-size:calc(13px*var(--f));font-weight:700;box-shadow:0 8px 20px rgba(17,19,24,.3);z-index:65}
/* 商城:彩色封面块 */
.bank-cover{width:54px;height:54px;border-radius:16px;color:#fff;display:flex;align-items:center;justify-content:center;
            font-weight:800;font-size:calc(22px*var(--f));flex:none}
.cov-a{background:linear-gradient(135deg,#FF7A3D,#E5484D)}
.cov-b{background:linear-gradient(135deg,#2F66E6,#3D7BFD)}
.cov-c{background:linear-gradient(135deg,#2E8B77,#0E9F6E)}
.cov-d{background:linear-gradient(135deg,#7C5CD6,#A78BFA)}
/* 转场/弹层 */
.layer{position:absolute;inset:0;z-index:60;background:var(--bg);display:flex;flex-direction:column;transform:translateX(100%);
       transition:transform .3s cubic-bezier(.4,0,.2,1)}
.layer.on{transform:none}
.scrim{position:absolute;inset:0;z-index:70;background:rgba(17,18,20,.4);opacity:0;pointer-events:none;transition:opacity .25s}
.scrim.on{opacity:1;pointer-events:auto}
.sheet{position:absolute;left:0;right:0;bottom:0;z-index:75;background:var(--bg);border-radius:20px 20px 0 0;
       padding:10px 20px calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 18px);transform:translateY(102%);transition:transform .32s cubic-bezier(.4,0,.2,1);
       max-height:82%;overflow-y:auto}
.sheet.on{transform:none}
.grab{width:40px;height:4px;border-radius:99px;background:var(--ink);opacity:.15;margin:4px auto 12px}
.sheet h3{font-size:calc(15px*var(--f));font-weight:700;margin-bottom:12px}
.sheet-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}
.sheet-grid .cell{aspect-ratio:1;border-radius:9px;background:var(--panel);display:flex;align-items:center;justify-content:center;
                  font-size:calc(12px*var(--f));font-weight:600;color:var(--ink2)}
.sheet-grid .cell.done{background:var(--ink);color:var(--bg)}
.sheet-grid .cell.wrong{background:var(--red);color:#fff}
.sheet-grid .cell.cur{outline:2px solid var(--accent);outline-offset:1px}
.sheet-grid .cell.on{outline:2px solid var(--accent);outline-offset:1px;color:var(--accent);font-weight:700;background:var(--accent-soft)}
/* TabBar */
/* ⚠ 底部内边距(2026-09-28:4px → 7px)。
   学员第三次指着底部问"为什么这种样子"时,我把电脑宽窗口下的底部放大三倍看了一下:
   选中项那颗淡蓝药丸与「首页/刷题/班级/我的」这几个字**紧贴底边** ——
   在手机外框(圆角 46px + overflow:hidden)里,贴底的那一条会被圆角切掉一点,
   看起来就是"底栏被裁了/贴在边上"。多给 3px 之后文字与底边之间有明确的呼吸位。
   (真机上还要再叠系统栏占位 --safe-b,见 app-shell.js 的 measureInsets。) */
.tabbar{flex:none;display:flex;background:var(--bg);padding-bottom:calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 7px)}
.tabbar button{flex:1;height:52px;background:none;border:none;display:flex;flex-direction:column;align-items:center;
               justify-content:center;gap:2px;color:var(--ink3);font-size:calc(10px*var(--f));font-weight:500;position:relative}
.tabbar button.on{color:var(--ink);font-weight:700}
.tabbar button .ic{width:22px;height:22px}
@media (min-width:560px){
  /* 电脑宽窗口下的"手机外壳"。三条**实测**结论,别再照旧截图猜:
     ① `body{background:radial-gradient(...#0b0c0e)}` 这条**实际上没生效** —— preview.html 里的
        首帧内联样式(html,body{background:#EEF3F3})在文档里更靠后,同特异性下它赢。
        所以电脑上这个手机壳一直坐在**浅灰底 #EEF3F3** 上,不是坐在深色舞台上。
     ② 真正压在底栏上、被学员连着两次圈红的那一层,是第一层**大面积黑色投影**
        `0 46px 120px -30px rgba(0,0,0,.9)`:偏移 46px + 模糊 120px 会让它在浅底上铺开约 60px 的灰雾,
        实测底栏正下方 6px 是 (8,8,9) 里混出的灰、12px 后 (125,128,128)、再往外一路 (142,145,145)
        —— 那是"晕影",不是外壳。
     ③ 第二层 `0 0 0 10px #101113` 是**实体边框**(spread 10px、无模糊、无偏移),它只在自己那 10px 里
        是黑的,不会往外晕。这一层按用户要求**保留**:手机壳要有那个黑边才像一台设备。
     所以:只去掉第一层,保留第二层。改完的现象是——底栏下方 10px 干净的实体黑边,
     再往外立刻回到页面底色,中间没有渐变灰带。 */
  body{background:radial-gradient(120% 90% at 50% 0%,#23262b 0%,#0b0c0e 62%)}
  .phone{width:406px;height:min(880px,94vh);border-radius:46px;border:1px solid rgba(255,255,255,.1);
         box-shadow:0 0 0 10px #101113}
}
/* ================= 交互触感补足(触控目标 / 按压反馈 / 整卡可点) ================= */
/* 1 触控目标:视觉尺寸可以小,热区一律补到 ≥34px(审计出 37 个过小的) */
.sec-h .more{padding:10px 6px;margin:-10px -6px}          /* 「全部 / 查看更多」原来只有 16px 高 */
.exam-bar .back,.dt-head .back{min-width:40px;min-height:40px}
.dt-head .back{width:40px !important;height:40px !important}
.mode-pill{padding:9px 13px}
.top-pill{padding:9px 13px}
.gs-timer{padding:8px 12px}
.bk-btn{height:38px}
.ri-actions .btn-ghost-s,.ri-actions .btn-solid-s,
.race-card .ri-actions .btn-ghost-s,.race-card .ri-actions .btn-solid-s{height:38px}
.stepper .st-btn{width:34px;height:34px}
#gsMode{padding:9px 12px;min-height:34px;display:inline-flex;align-items:center}
/* 2 按压反馈:补齐审计出的 93 处「能点但没反馈」 */
.dt-head .back,.exam-bar .back,.grid4 .g,.exam-bar .side,.cd-code,.me-head .avatar,.sec-h .more,
.seg,.faq-q,.attach,.invite .go,.avatar-opt,.banner{
  transition:transform .3s var(--ease-spring),background .15s ease,opacity .15s ease,color .15s ease}
.dt-head .back:active,.exam-bar .back:active,.me-head .avatar:active{transform:scale(.92)}
.grid4 .g:active{transform:scale(.93)}
.grid4 .g .g-ic{transition:transform .3s var(--ease-spring)}
.grid4 .g:active .g-ic{transform:scale(.88)}
.exam-bar .side:active{transform:scale(.95)}
.sec-h .more:active{opacity:.55}
.avatar-opt:active{background:var(--gap)}
.invite:active{transform:scale(.99)}
/* 3 班级码:做成可点的复制 chip(原来只有 15px 高的一行字) */
.cd-hero .cd-code{display:inline-flex;align-items:center;gap:5px;padding:8px 12px;border-radius:10px;
                  background:var(--accent-soft);margin-top:8px;font-size:calc(12px*var(--f));font-weight:700}
.cd-hero .cd-code:active{transform:scale(.95)}
.class-card .cc-btns div{cursor:pointer}
/* 顶栏右侧的动作文字(分享等)也补足热区 */
.exam-bar .count[onclick]{padding:10px 5px;margin:-10px -5px}
.exam-bar .count[onclick]:active{opacity:.55}
/* 5 第二批:设置行的可点值 / 取消收藏 / 建议词的热区,以及漏掉的按压反馈 */
#qRange,#qMode{padding:11px 6px;margin:-11px -6px}
.col-del{padding:8px 12px}
.pick-chips span{padding:9px 13px}
.me-head{transition:background .15s ease}
.me-head:active{background:var(--gap)}
.exam-foot .side{transition:transform .3s var(--ease-spring),background .15s ease}
.exam-foot .side:active{transform:scale(.94)}
.btn-ghost-big{transition:transform .3s var(--ease-spring),opacity .15s ease}
.btn-ghost-big:active{transform:scale(.98);opacity:.82}
#gsMode{transition:transform .3s var(--ease-spring),background .15s ease}
#gsMode:active{transform:scale(.95)}
.pair-btns .pb{transition:transform .3s var(--ease-spring),background .15s ease,color .15s ease}
.pair-btns .pb:active{transform:scale(.97)}
.shape-seg span,.filter span{transition:transform .3s var(--ease-spring),border-color .15s ease,background .15s ease}
.btn-solid-s,.btn-ghost-s,.btn-black,.bk-btn,.gs-btn{transition:transform .3s var(--ease-spring),opacity .15s ease,background .15s ease}
/* 题目收藏按钮 */
.fav-btn{margin-left:auto;display:flex;align-items:center;gap:5px;padding:8px 12px;min-height:31px;border-radius:999px;flex:none;
         background:var(--panel);color:var(--ink2);font-size:calc(11.5px*var(--f));font-weight:700;cursor:pointer;
         transition:transform .3s var(--ease-spring),background .18s ease,color .18s ease}
.fav-btn .ic{width:15px;height:15px}
.fav-btn:active{transform:scale(.94)}
.fav-btn.on{background:rgba(229,72,77,.10);color:var(--red)}
.fav-btn.on .ic{fill:currentColor}/* 0 手势引导:首次进入提示一次(隐藏手势不提示等于没有);「我的」页可手动重看 */
.gesture-coach{position:absolute;left:16px;right:16px;bottom:calc(max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)) + 84px);z-index:180;
               display:flex;gap:12px;align-items:flex-start;padding:14px;border-radius:16px;background:var(--bg);
               border:1px solid var(--line);box-shadow:var(--sd-2);opacity:0;transform:translateY(14px);
               transition:opacity .28s var(--ease),transform .28s var(--ease);pointer-events:none}
.gesture-coach.on{opacity:1;transform:none;pointer-events:auto}
.gesture-coach .gc-ic{width:38px;height:38px;border-radius:12px;background:var(--accent-soft);color:var(--accent);
                      display:flex;align-items:center;justify-content:center;flex:none}
.gesture-coach .gc-body{flex:1;min-width:0}
.gesture-coach .gc-body b{display:block;font-size:calc(13.5px*var(--f));font-weight:700;color:var(--ink);margin-bottom:5px}
.gesture-coach .gc-body span{display:block;font-size:calc(11.5px*var(--f));color:var(--ink2);line-height:1.75}
.gesture-coach .gc-body span i{font-style:normal;color:var(--accent);font-weight:700;margin-right:3px}
.gesture-coach .gc-btn{flex:none;align-self:center;height:34px;padding:0 14px;border-radius:999px;background:var(--panel);
                       color:var(--ink);font-size:calc(12px*var(--f));font-weight:700;display:flex;align-items:center;cursor:pointer;
                       transition:transform .3s var(--ease-spring)}
.gesture-coach .gc-btn:active{transform:scale(.95)}/* ================= 手势与加载态(下拉关弹层 / 答题页翻题 / 骨架屏) ================= */
/* 1 骨架屏:列表首次进入的加载态 + 题库卡 3D 缩略图加载 */
.sk-list{padding:10px 16px 0}
.sk-row{display:flex;gap:12px;align-items:center;padding:12px 0;border-bottom:1px solid var(--line)}
.sk-row:last-child{border-bottom:none}
.sk-row i{display:block;border-radius:7px;
          background:linear-gradient(90deg,var(--panel) 25%,rgba(17,19,24,.05) 37%,var(--panel) 63%);
          background-size:400% 100%;animation:skeletonShine 1.3s ease infinite}
.sk-av{width:34px;height:34px;border-radius:50%;flex:none}
.sk-lines{flex:1;display:flex;flex-direction:column;gap:8px}
.sk-lines i{height:10px}
body.dark .sk-row i{background:linear-gradient(90deg,#1C1F24 25%,#2A2F36 37%,#1C1F24 63%);background-size:400% 100%}
@keyframes skeletonShine{0%{background-position:100% 50%}100%{background-position:0 50%}}
/* 题库卡的 3D 缩略图加载:转圈改成扫光(更像 AntD 骨架屏) */
.m-card .m3d-loading{position:absolute;inset:0;width:auto;height:auto;margin:0;top:0;left:0;border:none;border-radius:0;
                     background:linear-gradient(100deg,rgba(255,255,255,0) 20%,rgba(255,255,255,.55) 50%,rgba(255,255,255,0) 80%);
                     background-size:200% 100%;animation:skeletonSweep 1.25s ease-in-out infinite}
@keyframes skeletonSweep{0%{background-position:140% 0}100%{background-position:-40% 0}}
@media (prefers-reduced-motion:reduce){.sk-row i,.m-card .m3d-loading{animation:none}}
/* 2 可下拉关闭的弹层:拖动时禁止过渡,松手后回归/关闭 */
.sheet.dragging{transition:none}
.sheet-grip{cursor:grab}
/* 3 长按复制的目标:稍加提示(可复制的地方给一点文字选中抑制,避免和系统菜单打架) */
[data-copy],.dd .v,.gs-row .v,.req-cell .rc-v,.row .r-v{-webkit-user-select:none;user-select:none}/* 6 登录页协议链接:内联小字也要有足够热区 */
#layer-login span[onclick]{display:inline-block;padding:10px 3px;margin:-10px -3px;color:var(--accent);font-weight:600;
                            transition:opacity .15s ease,transform .3s var(--ease-spring)}
#layer-login span[onclick]:active{opacity:.6;transform:scale(.97)}
/* ================= 第三批交互补足:热区 ≥36px / 53 处漏掉的按压反馈 / 状态与键盘 ================= */
/* A1 触控目标:上一批补到 34–35px 的这轮全部拉到 ≥36(视觉尺寸不变,靠 padding + 负 margin 撑热区) */
.ant-alert .aa-close{width:38px;height:38px;top:2px;right:2px;display:flex;align-items:center;justify-content:center}
.stepper .st-btn{width:36px;height:36px}
.pick-chips span{display:inline-flex;align-items:center;padding:10px 14px;min-height:36px}
.col-del{padding:9px 13px;min-height:36px;display:inline-flex;align-items:center}
.top-pill{padding:10px 14px}
.sec-btn{padding:10px 15px}
.cd-hero .cd-code{padding:9px 12px;min-height:36px}
.fav-btn{min-height:36px;padding:9px 13px}
.gs-timer{padding:9px 12px}
#gsMode{padding:10px 13px;min-height:36px}
#layer-login span[onclick]{padding:10px 3px;margin:-10px -3px}
/* A2 按压反馈:补齐审计出的 53 处「能点但按下没反应」 */
.quick .q,.st-btn,.cell.tap,.exam-bar .count,.race-tabs,.fab-post,.pd-actions .btn,.comment-bar .send,
.searchbar[onclick],#qRange,#qMode,.fav-side,.avatar[onclick],.ms-clear,.ms-cancel,.ms-empty-btn{
  transition:transform .3s var(--ease-spring),background .15s ease,opacity .15s ease,color .15s ease}
.quick .q:active{transform:scale(.96)}
.quick .q:active .q-btn{transform:scale(.88)}
.st-btn:active{transform:scale(.9);background:var(--line)}
.cell.tap:active{transform:scale(.94);background:var(--accent-soft);color:var(--accent)}
.exam-bar .count:active{opacity:.6}
.race-tabs:active{transform:scale(.995)}
.fab-post:active{transform:scale(.94)}
.pd-actions .btn:active{transform:scale(.96);background:var(--gap)}
.comment-bar .send:active{transform:scale(.95);opacity:.85}
.searchbar[onclick]:active{background:var(--line)}
#qRange:active,#qMode:active{opacity:.6}
.fav-side:active{transform:scale(.94)}
.avatar[onclick]:active{transform:scale(.94)}
.col-del,.shape-seg,.searchbar[onclick],#qRange,#qMode{transition:transform .3s var(--ease-spring),background .15s ease,opacity .15s ease,color .15s ease}
.ms-clear:active{transform:scale(.9);background:rgba(17,19,24,.26)}
.ms-cancel:active{opacity:.6}
.ms-empty-btn:active{transform:scale(.95)}
/* A3 状态语言:焦点环覆盖所有自定义控件(鼠标点击不出现) */
[role=button]:focus-visible,.cell:focus-visible,.faq-q:focus-visible,.attach:focus-visible,
.quick .q:focus-visible,.grid4 .g:focus-visible,.row[onclick]:focus-visible,.seg span:focus-visible,
.pick-chips span:focus-visible,.race-tabs span:focus-visible,.st-btn:focus-visible,.fav-btn:focus-visible,
.fav-side:focus-visible,.ms-clear:focus-visible,.fab-post:focus-visible,.filter span:focus-visible,
.dt-tabs span:focus-visible,.shape-seg span:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px}
:focus:not(:focus-visible){outline:none}
/* A4 禁用态 + 忙碌态(统一:置灰不可点 / 转圈防重复提交) */
.is-disabled,.is-disabled:active{opacity:.45;pointer-events:none;transform:none!important;filter:grayscale(.2)}
.busy{opacity:.72;pointer-events:none;position:relative}
.busy::before{content:'';width:14px;height:14px;border-radius:50%;flex:none;margin-right:8px;
  border:2px solid currentColor;border-top-color:transparent;animation:busySpin .7s linear infinite}
@keyframes busySpin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.busy::before{animation:none}}
/* ================= 按键体系:四个档位一次定死(原来同一档高度/圆角/字号各自为政) =================
   L 主操作(页面级 CTA)46 · 圆角 13 · 15px   |  M 区块内操作 42 · 圆角 12 · 13px
   S 卡片内动作 38 · 圆角 10 · 12px           |  胶囊/小控件 ≥36 · 圆角 999 · 11.5–12px
   四档共用同一套按压回弹、焦点环、禁用与忙碌态(见 A3/A4)                                    */
.btn-black,.gs-btn,.btn-ghost-big,.pb{height:46px;border-radius:13px;font-size:calc(15px*var(--f))}
.btn-solid-s,.btn-ghost-s,.bk-btn,.pj-solid,.pj-ghost{height:38px;border-radius:10px;font-size:calc(12px*var(--f))}
.btn,.code-btn,.send,.fab-post{height:42px;border-radius:12px;font-size:calc(13px*var(--f))}
.send,.fab-post{border-radius:999px}
.btn-black,.btn-solid-s,.btn-ghost-s,.bk-btn,.gs-btn,.pj-solid,.pj-ghost,.pb,.btn,.send,.code-btn,.btn-ghost-big{
  transition:transform .3s var(--ease-spring),background .15s ease,opacity .15s ease,box-shadow .15s ease}
.btn-black:active,.gs-btn:active,.pb:active{transform:scale(.97);opacity:.9}
.btn-solid-s:active,.btn-ghost-s:active,.bk-btn:active,.pj-solid:active,.pj-ghost:active{transform:scale(.96)}
.btn:active,.send:active,.code-btn:active,.fab-post:active{transform:scale(.96)}
/* 四档按钮统一:图标与文字基线对齐、内容不换行、忙碌时宽度不跳 */
.btn-black,.btn-solid-s,.btn-ghost-s,.bk-btn,.gs-btn,.pj-solid,.pj-ghost,.pb,.btn,.send,.code-btn,.btn-ghost-big{
  white-space:nowrap;justify-content:center;align-items:center;gap:6px}
/* A5 分段 / 标签控件(视距内超视距教员、班级学员、男女保密、全部帖子、AI 解读、3D 机型…)
   它们现在带 role=radio 也是触控目标,热区统一 ≥36(原来 20–35px) */
.seg span,.filter span,.dt-tabs span,.model-switch span{
  min-height:36px;display:inline-flex;align-items:center;justify-content:center}
.seg span,.filter span,.dt-tabs span,.model-switch span{
  transition:transform .3s var(--ease-spring),background .15s ease,color .15s ease,border-color .15s ease}
.model-switch span{padding:6px 12px}
.pick-chips span{min-height:37px}
.seg span:active,.filter span:active,.dt-tabs span:active,.model-switch span:active{transform:scale(.96)}
/* ================= 第四批:动效精修(时长三档 + 三条曲线,全站只用这一套) =================
   原来 93 处 transition 的时长写成了 .15/.18/.2/.22/.24/.25/.28/.3/.32/.35 十种,曲线也各不相同 ——
   统一成三档时长 + 三条曲线:颜色/悬停 dur-1,开关/状态 dur-2,进场/弹层 dur-3。                        */
:root{
  --dur-1:120ms;      /* 颜色、悬停、淡入淡出 */
  --dur-2:200ms;      /* 开关、chip、状态切换 */
  --dur-3:300ms;      /* 进场、弹层、翻页 */
  --dur-press:90ms;   /* 按下那一瞬:要比松手快得多,手感才"跟手" */
  --ease-out:cubic-bezier(.22,.61,.36,1);       /* 进场:快出慢停 */
  --ease-in-fast:cubic-bezier(.55,.06,.68,.19); /* 按下:立刻有反应 */
  --ease-emphasized:cubic-bezier(.2,.8,.2,1);   /* 大面板位移 */
}
/* 1 按压手感:按下 90ms 直线沉下去 → 松手 300ms 弹回来(原来两边一样长,按起来"肉") */
.pressing{transition-duration:var(--dur-press)!important;transition-timing-function:var(--ease-in-fast)!important}
.func:is(:active,.pressing){transform:scale(.95);background:var(--gap);box-shadow:0 1px 4px rgba(17,19,24,.05)}
.func:is(:active,.pressing) .f-ic{transform:scale(.86)}
.row:is(:active,.pressing),.m-row:is(:active,.pressing),.chapter:is(:active,.pressing),
.mode:is(:active,.pressing),.post-card:is(:active,.pressing){background:var(--gap);transform:scale(.988)}
.row:is(:active,.pressing) .r-t{transform:translateX(3px)}
.race:is(:active,.pressing){transform:scale(.975);filter:brightness(.94)}
.q .q-btn:is(:active,.pressing){transform:scale(.86)}
.opt:is(:active,.pressing){transform:scale(.985);background:var(--gap)}
.btn-black:is(:active,.pressing){transform:scale(.97);opacity:.9}
.bank-card:is(:active,.pressing),.race-card:is(:active,.pressing),.proj-card:is(:active,.pressing),
.class-card:is(:active,.pressing),.signup-row:is(:active,.pressing),.race-item:is(:active,.pressing),
.spec-card:is(:active,.pressing){transform:scale(.985)}
.spec-card:is(:active,.pressing){background:var(--gap)}
.grid4 .g:is(:active,.pressing){transform:scale(.93)}
.grid4 .g:is(:active,.pressing) .g-ic{transform:scale(.88)}
.exam-bar .back:is(:active,.pressing),.dt-head .back:is(:active,.pressing),.me-head .avatar:is(:active,.pressing){transform:scale(.9)}
.exam-foot .side:is(:active,.pressing){transform:scale(.94)}
.btn-solid-s:is(:active,.pressing),.btn-ghost-s:is(:active,.pressing),.bk-btn:is(:active,.pressing),
.gs-btn:is(:active,.pressing),.pj-solid:is(:active,.pressing),.pj-ghost:is(:active,.pressing),.pb:is(:active,.pressing),
.btn:is(:active,.pressing),.send:is(:active,.pressing),.code-btn:is(:active,.pressing){transform:scale(.96)}
.top-pill:is(:active,.pressing),.mode-pill:is(:active,.pressing),.sec-btn:is(:active,.pressing),
.fav-btn:is(:active,.pressing),.fav-side:is(:active,.pressing),.st-btn:is(:active,.pressing),
.col-del:is(:active,.pressing),.bc-link:is(:active,.pressing),.dt-tabs span:is(:active,.pressing),
.seg span:is(:active,.pressing),.filter span:is(:active,.pressing),.model-switch span:is(:active,.pressing){transform:scale(.94)}
.cell.tap:is(:active,.pressing){transform:scale(.94)}
/* 2 进场节奏:整页一起浮入太"平",改成前 5 块各错 24ms —— 读起来像内容依次落位 */
.view.active .app > *{animation:blockIn var(--dur-3) var(--ease-out) both}
.view.active .app > *:nth-child(2){animation-delay:24ms}
.view.active .app > *:nth-child(3){animation-delay:48ms}
.view.active .app > *:nth-child(4){animation-delay:72ms}
.view.active .app > *:nth-child(5){animation-delay:96ms}
.view.active .app > *:nth-child(n+6){animation-delay:120ms}
@keyframes blockIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.card-in{animation:blockIn var(--dur-3) var(--ease-out) both}
/* 3 图层位移:换成"快出慢停",遮罩与弹层时长对齐(原来 .25 / .32 各走各的) */
.layer{transition:transform var(--dur-3) var(--ease-emphasized)}
.scrim{transition:opacity var(--dur-2) linear}
.sheet{transition:transform var(--dur-3) var(--ease-emphasized)}
/* 4 触摸与滚动手感:点按延迟消掉、滚动不串到后面那层 */
button,.btn-black,.btn-solid-s,.btn-ghost-s,.bk-btn,.gs-btn,.top-pill,.mode-pill,.sec-btn,.fav-btn,
.st-btn,.col-del,.bc-link,.cell.tap,[role=button],[role=radio]{touch-action:manipulation}
.app,.sheet{overscroll-behavior:contain}
/* 5 状态变化的连续性:数字滚动、星标弹一下、卡片被点亮、进度条补齐 */
.num-tick{display:inline-block;animation:numTick var(--dur-2) var(--ease-out)}
@keyframes numTick{from{opacity:.35;transform:translateY(-5px)}to{opacity:1;transform:none}}
.fav-btn.on .ic{animation:starPop .42s var(--ease-spring)}
@keyframes starPop{0%{transform:scale(1)}42%{transform:scale(1.34)}100%{transform:scale(1)}}
.bank-card.is-updated{animation:cardUpdated 560ms var(--ease-out)}
@keyframes cardUpdated{0%{box-shadow:0 0 0 2px var(--accent-soft),var(--shadow);transform:scale(.985)}
                       55%{box-shadow:0 0 0 4px var(--accent-soft),var(--shadow)}
                       100%{box-shadow:var(--shadow);transform:none}}
.bk-prog i{transition:width 480ms var(--ease-out)}
@media (prefers-reduced-motion:reduce){
  .view.active .app > *,.card-in,.num-tick,.fav-btn.on .ic,.bank-card.is-updated{animation:none}
  .pressing{transition-duration:.01ms!important}
  .layer,.sheet,.scrim{transition-duration:.01ms}
}
/* 6 导航与选择态的小动作:TabBar 图标随选中微微上浮,分段/chip 选中时弹一下 */
.tabbar button .ic{transition:transform var(--dur-2) var(--ease-spring)}
.tabbar button.on .ic{transform:translateY(-1px) scale(1.06)}
.tabbar button:is(:active,.pressing) .ic{transform:scale(.9)}
.seg span.on,.filter span.on,.race-tabs span.on,.dt-tabs span.on,.shape-seg span.on{animation:chipPop var(--dur-2) var(--ease-spring)}
@keyframes chipPop{0%{transform:scale(1)}45%{transform:scale(1.045)}100%{transform:scale(1)}}
@media (prefers-reduced-motion:reduce){
  .tabbar button .ic{transition:none}
  .seg span.on,.filter span.on,.race-tabs span.on,.dt-tabs span.on,.shape-seg span.on{animation:none}
}

/* ============ 题库选择页 · 排版精修(第五轮) ============
   ① 分组标题:吸顶时用「毛玻璃 + 渐隐 + 发丝线」垫底,卡片不会硬生生切在字上
   ② 去掉与外层重复的「题库列表」标题行(分组标题已经承担结构)
   ③ 侧边锚点:手柄更小更安静(隐藏式的关键),展开的列表更像通讯录索引         */
.bk-sec-h{position:sticky;top:0;z-index:3;display:flex;align-items:baseline;justify-content:space-between;gap:10px;
          margin:0 16px;padding:13px 0 9px;background:var(--bg);
          background:linear-gradient(var(--bg) 64%,rgba(255,255,255,0));
          border-bottom:1px solid var(--line);
          font-size:calc(13px*var(--f));font-weight:700;color:var(--ink);letter-spacing:.01em}
body.dark .bk-sec-h{background:linear-gradient(var(--bg) 64%,rgba(20,22,26,0))}
.bk-sec-h .cnt{font-size:calc(11px*var(--f));font-weight:500;color:var(--ink3);font-variant-numeric:tabular-nums}
.bk-sec{padding-top:0}
.bk-sec:first-child .bk-sec-h{padding-top:6px}
.bk-sec .bank-card:first-of-type{margin-top:10px}
/* ============ 侧边锚点导航 v2:可拖动的悬浮球 ============
   ① 手柄能拖到任意顺手的位置,松手吸附到最近的左右边缘,位置记进 localStorage(下次进来还在原地)
   ② 展开的索引贴着悬浮球出现(球在右半屏就开在左边,反之亦然),并上下夹紧,不再固定压屏幕中间
   ③ 平时半透明;按住拖动/展开/滚动时提亮                                              */
.bank-rail{position:absolute;left:0;top:0;right:auto;transform:none;z-index:40;
           display:flex;align-items:center;gap:6px;pointer-events:none}
.bank-rail > *{pointer-events:auto}
.rail-handle{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;
             background:rgba(255,255,255,.9);border:1px solid var(--line);box-shadow:var(--sd-2);
             color:var(--ink2);opacity:.5;cursor:grab;padding:0;touch-action:none;
             transition:opacity var(--dur-2) linear,transform var(--dur-3) var(--ease-spring),box-shadow var(--dur-2) var(--ease)}
.rail-handle .ic{width:16px;height:16px}
.bank-rail.show .rail-handle,
.bank-rail.open .rail-handle,
.bank-rail.dragging .rail-handle{opacity:1}
.bank-rail.dragging .rail-handle{cursor:grabbing;transform:scale(1.08);box-shadow:var(--sd-3)}
body.dark .rail-handle{background:rgba(28,31,36,.9)}
/* 索引:绝对定位,左右与上下由 JS 算,永远贴着球 */
.rail-list{position:absolute;top:0;left:0;display:flex;flex-direction:column;gap:1px;padding:5px;border-radius:15px;
           background:var(--bg);border:1px solid var(--line);box-shadow:var(--sd-3);
           max-height:62vh;overflow-y:auto;scrollbar-width:none;
           opacity:0;transform:translateY(6px);pointer-events:none;
           transition:opacity var(--dur-2) var(--ease-out),transform var(--dur-3) var(--ease-spring)}
.rail-list::-webkit-scrollbar{display:none}
.bank-rail.open .rail-list{opacity:1;transform:none;pointer-events:auto}
.rail-item{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:36px;padding:0 11px;
           border-radius:11px;font-size:calc(12.5px*var(--f));font-weight:600;color:var(--ink2);white-space:nowrap;
           transition:background var(--dur-1) linear,color var(--dur-1) linear,transform var(--dur-3) var(--ease-spring)}
.rail-item i{font-style:normal;font-size:calc(10.5px*var(--f));font-weight:700;color:var(--ink3);font-variant-numeric:tabular-nums}
.rail-item.on{background:var(--accent-soft);color:var(--accent);font-weight:700}
.rail-item.on i{color:var(--accent)}
.rail-item:active{transform:scale(.96)}
/* 当前类目气泡:跟在球的另一侧 */
.rail-tip{position:absolute;top:0;left:0;padding:6px 10px;border-radius:9px;background:var(--ink);color:var(--bg);
          font-size:calc(11.5px*var(--f));font-weight:600;white-space:nowrap;box-shadow:var(--sd-2);
          opacity:0;pointer-events:none;transition:opacity var(--dur-1) linear}
.bank-rail:not(.open).show .rail-tip{opacity:.92}
.bank-rail.open .rail-tip,
.bank-rail.dragging .rail-tip{opacity:0}
@media (prefers-reduced-motion:reduce){
  .rail-list,.rail-tip,.rail-handle,.rail-item{transition-duration:.01ms}
}
/* 口试页的样式(沿用答题页的分析卡语言) */
/* 口述提示:一条说明,不抢视线 */
.oral-hint{margin-top:11px;padding:9px 11px;border-radius:11px;background:var(--accent-soft);
           font-size:calc(11.5px*var(--f));line-height:1.7;color:var(--ink2)}
/* 参考答案与评分要点 */
.oral-points{margin:9px 0 0;padding-left:18px;display:flex;flex-direction:column;gap:6px}
.oral-points li{font-size:calc(12.5px*var(--f));line-height:1.7;color:var(--ink2)}
.oral-points li::marker{color:var(--accent);font-weight:700}
.oral-miss{margin-top:10px;padding-top:9px;border-top:1px solid var(--line);
           font-size:calc(11.5px*var(--f));line-height:1.7;color:var(--ink3)}
.oral-miss b{display:block;color:var(--warn-fg,#B7791F);font-size:calc(11.5px*var(--f));margin-bottom:3px}
/* 三个动作:看答案 / 没答全 / 答上来了 */
.oral-actions{display:flex;gap:8px;margin:12px 16px 0}
.oral-actions .bk-btn{flex:1}
.oral-self{margin:10px 16px 0;font-size:calc(11.5px*var(--f));color:var(--ink3);font-weight:600}
.oral-self.ok{color:var(--ok-fg,#217A63)}
.oral-self.warn{color:var(--warn-fg,#B7791F)}
/* 刷题页顶部的小提示:说明当前类别考什么 */
#bankModeTip{font-size:calc(11px*var(--f));color:var(--ink3);font-weight:500}
/* 区块标题右侧的说明「本类别考什么」 */
.sec-h .mode-tip{font-size:calc(11px*var(--f));color:var(--ink3);font-weight:500;flex:1;text-align:right;min-width:0}
/* ---------- 专项科目:按类别显示 1–2 项,不留半格也不留洞 ----------
   只有一项 → 整行一张大卡:图标 + 名称 + 身份 chip + 一句「怎么练」+ 进度条 + 已练 n/N;
   有两项 → 并排两张紧凑卡:去掉 chip 与「怎么练」,补一行 11px 的小字(.sc-meta)顶上,
             两张卡等高、各占一半,看起来是一行,而不是半格加半格。 */
.spec-row{display:flex;gap:10px;margin:4px 16px 0}
.spec-card{flex:1 1 0;min-width:0;padding:13px 15px 12px;background:var(--bg);border:1px solid var(--line);
           border-radius:var(--r-lg);box-shadow:var(--shadow);cursor:pointer}
.spec-card .sc-head{display:flex;align-items:center;gap:10px;min-width:0}
.spec-card .sc-ic{width:36px;height:36px;border-radius:12px;display:flex;align-items:center;justify-content:center;flex:none}
.spec-card .sc-ic .ic{width:18px;height:18px}
.spec-card .sc-ic.ic-amber{background:rgba(183,121,31,.14);color:#B06D10}
.spec-card .sc-ic.ic-teal{background:var(--accent-soft);color:var(--accent)}
.spec-card .sc-ic.ic-blue{background:rgba(61,123,253,.12);color:#2F66E6}
.spec-card .sc-head b{font-size:calc(14.5px*var(--f));font-weight:800;color:var(--ink);letter-spacing:-.01em}
.spec-card .sc-head .chev{margin-left:auto;display:flex;align-items:center;color:#C6C9CE;flex:none}
.spec-card .sc-sub{margin-top:8px;font-size:calc(11.5px*var(--f));line-height:1.65;color:var(--ink2)}
/* 卡片第二行:一行之内放得下「小字」和「进度条」——所以一张卡有进度、另一张没有时,也不会空出一行 */
.spec-card .sc-foot{display:flex;align-items:center;gap:10px;margin-top:10px}
.spec-card .sc-bar{flex:1 1 auto;min-width:24px;height:6px;border-radius:99px;background:var(--panel);overflow:hidden}
.spec-card .sc-bar i{display:block;height:100%;width:0;border-radius:99px;background:var(--accent);
                     transition:width .48s var(--ease-out)}
.spec-card .sc-num{font-size:calc(11px*var(--f));font-weight:600;color:var(--ink3);white-space:nowrap;font-variant-numeric:tabular-nums}
.spec-card .sc-meta{display:none}
/* 两项并排:chip 与说明句收起,第二行 = 小字 + 进度条(同一行,两卡等高) */
.spec-row.duo .spec-card{padding:12px 13px}
.spec-row.duo .spec-card .sc-head b{font-size:calc(13.5px*var(--f))}
.spec-row.duo .spec-card .sc-head .chip,
.spec-row.duo .spec-card .sc-sub{display:none}
.spec-row.duo .spec-card .sc-foot{margin-top:9px;gap:9px}
.spec-row.duo .spec-card .sc-meta{display:block;flex:0 1 auto;min-width:0;font-size:calc(11px*var(--f));line-height:1.5;
                                  color:var(--ink3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.spec-row.duo .spec-card .sc-meta em{font-style:normal;color:var(--ink2);font-weight:700;font-variant-numeric:tabular-nums}
.spec-row.duo .spec-card .sc-num{display:none}
body.dark .spec-card .sc-ic.ic-amber{color:#E5B566}
body.dark .spec-card .sc-ic.ic-blue{color:#7DA2F5}
body.dark .spec-card .sc-head .chev{color:var(--ink3)}
/* ---------- 口述类页面(综合问答 / 口试)顶部的题库概览条:这一页是自己一个题库 ---------- */
.qa-ov{margin:12px 16px 0;padding:12px 14px;border-radius:var(--r-lg);background:var(--panel)}
.qa-ov .qo-top{display:flex;align-items:center;gap:8px;min-width:0}
.qa-ov .qo-sub{font-size:calc(11px*var(--f));color:var(--ink3);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.qa-ov .qo-n{margin-left:auto;font-size:calc(11.5px*var(--f));font-weight:700;color:var(--ink2);white-space:nowrap;font-variant-numeric:tabular-nums}
.qa-ov .qo-bar{height:6px;border-radius:99px;background:var(--bg);overflow:hidden;margin-top:10px}
.qa-ov .qo-bar i{display:block;height:100%;width:0;border-radius:99px;background:var(--accent);transition:width .48s var(--ease-out)}
.qa-ov .qo-meta{margin-top:8px;font-size:calc(11px*var(--f));color:var(--ink3);font-variant-numeric:tabular-nums}

/* ==========================================================================================
   设计系统 v2 · 学员端外壳组件层(P2,2026-09-28)

   这一节为什么放在文件**末尾**:
     学员端 app.css 有 1122 条规则、191 处写死的十六进制色,而且是原型期一路长出来的;
     手工去 1000 行里逐条改值,改错一处要找半天,回滚更麻烦。同名选择器写在末尾按 CSS 顺序
     覆盖旧写法,等于"整套新皮叠在旧皮上"——改坏了整段删掉就回到原样。
   三条纪律:
     ① 只换皮:不改类名、不改 DOM 层级(学员端有大量选择器被用例断言:.view/.tile/.card/
        .btn-black/#layer-*/.q-table…,重命名会红一批用例);
     ② 字号一律 calc(Npx*var(--f)):长辈版靠 --f 逐帧插值,写死 px 会让长辈版失灵;
     ③ 深色/长辈版的旧补丁(选择器带 body.dark / .elder)优先级更高,继续生效,不用重写。

   这一轮改掉的三件"看得见"的事:
     A 分层:页底从纯白改成带青的浅灰(新令牌 --page),卡片/顶栏/TabBar 是更亮一档的"纸"
       —— 原来页底和卡面都是纯白,整个界面靠描边分块,像一块白板;现在靠亮度分层,深色下同理(页底更暗)。
     B 卡组:全宽白条(.listblock / .month / .gauge-row)收成圆角卡片组 —— 这是手机端最标准的
       "设置分组的形状",也是这次从"网页感"变"App 感"最主要的一处。
     C 触感:选中/按下的语言统一到品牌蓝(TabBar 选中态、分段控件、图标砖),并按下的都是弹簧回弹。
   ========================================================================================== */

/* ---------- 1 分层:页底(青灰)→ 卡面(近白)→ 次级面 ---------- */
.phone{background:var(--page)}
/* 顶栏与 TabBar 用玻璃底:滚动时下面的内容透出来一点,而不是硬切一条白 */
/* ⚠ 底栏改成**实色、无分隔线**(2026-09-28,学员第三次报障的答案):
   他的原话是「底部这一块又阴影啊,一道痕啊」——
   量出来的两个来源正好对上:
     · 「一道痕」= 这条规则里的 `border-top:1px solid var(--line)`(一条 1px 的分隔线);
     · 「阴影」  = `background:var(--glass)`(76% 半透明)+ `backdrop-filter:blur(18px)` ——
                  毛玻璃会把下面的内容糊成一团暗影,看着像"底栏下面压着一层灰"。
   现在的做法:**去掉分隔线,底色改成实色**,靠"更深的底 + 更浅的卡面"来分层:
     --page #EEF3F3(页底,浅青灰) vs --bg #FCFEFE(卡面/底栏,近白)
   两者有明确色差,不需要再画一条线。学员要的就是"干净、没有那道痕"。
   ⚠ 深色模式下同理:body.dark 里 --page/--bg 也有一对色差,所以这条规则在两个主题下都成立。 */
.tabbar{background:var(--bg);border-top:none;
        -webkit-backdrop-filter:none;backdrop-filter:none}

/* ---------- 2 首页头:一块极淡的品牌光晕(不抢内容,只把"这一页是首页"说出来)---------- */
.home-top{padding:14px 18px 6px;align-items:center;
          background:radial-gradient(120% 160% at 4% 0%,var(--accent-wash) 0%,transparent 62%)}
.home-top .ht-title{font-size:calc(24px*var(--f));letter-spacing:-.02em}   /* 大字标题收紧字距才显精致 */
.home-top .ht-sub{font-size:calc(12.5px*var(--f));color:var(--ink2);margin-top:4px}
.home-top .mode-pill,.home-top .ht-count{flex:none}
/* ---------- 2b 窄屏:顶部那行放不下就让它换行(320 是设计底线)---------- */
/* 这一行放不下是**算得出来**的:右侧三枚控件(铃铛 38 + 深色 73 + 倒计时 82.8 + 两个 8px 间隙)
   + 左右内边距 36 = 246.8px,而标题「翼起驭风」在 24px 下要 94px ——
   视口窄于 340.8px 时标题被省略号切掉(320 实测:标题盒 74px、需要 94px),副标题也被压成 3 行。
   所以 ≤340px 时把右侧那一组放到第二行,标题与副标题各占整行。
   ⚠ 不用 flex-wrap + min-width 的隐式换行:那个阈值会随 --f(长辈模式)漂移,说不清什么时候换行。 */
@media (max-width:340px){
  .home-top{flex-wrap:wrap;row-gap:8px}
  .home-top>div:first-child{width:100%}
  .home-top>div:last-child{margin-left:auto}
}
/* 倒计时从"两行小字"变成一枚真的统计胶囊:数字是这一块的主角,点击进考试设置 */
.ht-count{padding:7px 13px;border-radius:14px;background:var(--bg);border:1px solid var(--line);
          box-shadow:var(--shadow);text-align:left}
.ht-count .hc-num{font-size:calc(20px*var(--f));line-height:1.15;letter-spacing:-.03em}
.ht-count .hc-label{margin-top:1px;font-size:calc(9.5px*var(--f))}

/* ---------- 3 TabBar:选中态说人话(品牌蓝 + 图标底一枚淡蓝胶囊)---------- */
.tabbar button{color:var(--ink3);gap:3px;transition:color .18s ease}
.tabbar button .ic{position:relative;z-index:1;transition:transform .3s var(--ease-spring)}
.tabbar button::before{content:'';position:absolute;top:5px;left:50%;width:42px;height:26px;margin-left:-21px;
                       border-radius:999px;background:transparent;transform:scale(.82);
                       transition:background .2s ease,transform .3s var(--ease-spring)}
.tabbar button.on{color:var(--accent);font-weight:700}
.tabbar button.on::before{background:var(--accent-soft);transform:scale(1)}
.tabbar button.on .ic{transform:translateY(-1px)}
.tabbar button:active .ic{transform:scale(.9)}
/* 选中项上方那条 2px 指示条:大屏/深色下颜色不够时也能一眼看出在哪一栏 */
.tabbar button.on::after{content:'';position:absolute;top:0;left:50%;width:20px;height:2.5px;margin-left:-10px;
                         border-radius:0 0 3px 3px;background:var(--accent)}
@media (prefers-reduced-motion:reduce){.tabbar button,.tabbar button::before,.tabbar button .ic{transition:none}}

/* ---------- 4 卡片:一层发丝线 + 一层带色柔光(替掉原来 3 层 1px 的黑影)---------- */
.func,.mode,.stat-card,.race-item,.card,.class-card,.bank-card,.race-card,.proj-card,.spec-card,
.signup-row,.msg-card,.ai-card,.today-bar,.exam-count,.create-cta{box-shadow:var(--shadow)}
.func,.mode{transition:transform .3s var(--ease-spring),box-shadow .24s var(--ease),border-color .24s var(--ease)}
@media (hover:hover){
  .func:hover,.mode:hover{border-color:var(--line-2);box-shadow:0 2px 4px rgba(15,34,36,.06),0 14px 30px -18px rgba(15,34,36,.2)}
}
.func:active,.mode:active{transform:scale(.97)}

/* ---------- 5 卡组:全宽白条 → 圆角卡片组(.listblock 17 处全是"设置分组",形状统一)---------- */
.listblock{margin:12px 16px 0;border-top:none;border:1px solid var(--line);border-radius:var(--r-lg);
           overflow:hidden;box-shadow:var(--shadow)}
/* 卡片组里的行:左右内缩与卡片对齐(原来 20px 是按全宽白条定的,套进卡片就成了两重缩进) */
.listblock .row{padding:13px 16px}
.listblock .row .r-t b{font-size:calc(14.5px*var(--f));font-weight:600}
.listblock .row .r-t span{margin-top:3px;font-size:calc(11.5px*var(--f))}
.row .chev{color:var(--ink3)}
/* 月度柱状图 / 备考进度:原来是"全宽白条 + 顶部一条线",现在同样收成卡片 */
.month{margin:12px 16px 0;padding:16px;border-top:none;border-radius:var(--r-lg);background:var(--bg);
       border:1px solid var(--line);box-shadow:var(--shadow)}
.bars .b i{background:var(--line-2);border-radius:5px 5px 3px 3px}
.bars .b.on i{background:var(--accent)}
.gauge-row{margin:12px 16px 0;padding:15px 16px;border-top:none;border-radius:var(--r-lg);background:var(--bg);
           border:1px solid var(--line);box-shadow:var(--shadow)}

/* ---------- 6 功能宫格 + 快捷圆钮:图标砖扁平化,六色各归其位 ---------- */
.func-grid{gap:10px;padding:14px 16px 0}
.func{padding:15px 8px 13px}
.func .f-ic,.grid4 .g .g-ic,.mode .m-ic{border:none;box-shadow:none}
/* 原来 f-teal 是"蓝底 + 青绿字"(底色取自品牌蓝、字色取自青绿),两个色系打架;这里按色系配平 */
.f-ic.f-teal{background:rgba(13,148,136,.13);color:#0F766E}
.f-ic.f-blue{background:var(--accent-soft);color:var(--accent)}
.f-ic.f-amber{background:rgba(183,121,31,.14);color:#A05F0C}
.f-ic.f-red{background:rgba(229,72,77,.12);color:#C93A3F}
.f-ic.f-green{background:rgba(16,150,120,.13);color:#0F7A63}
.f-ic.f-purple{background:rgba(124,92,214,.13);color:#6D4DC4}
.func b{font-size:calc(12.5px*var(--f));font-weight:600}
.func span{margin-top:3px}
.quick{padding:16px 24px 2px}
.quick .q{gap:8px;font-weight:500}
.quick .q .q-btn{width:52px;height:52px;background:var(--bg);border:1px solid var(--line);box-shadow:var(--shadow);
                 color:var(--accent)}
.quick .q .q-btn:active{background:var(--accent-soft)}
.grid4{gap:18px 8px;padding:14px 18px 4px}
.grid4 .g{gap:8px}
.grid4 .g .g-ic{background:var(--bg);border:1px solid var(--line);box-shadow:var(--shadow);color:var(--accent)}
.grid4 .g .g-ic.green{background:rgba(16,150,120,.12);color:#0F7A63}
.grid4 .g:active .g-ic{background:var(--accent-soft)}

/* ---------- 7 统计:数字用等宽数位并收紧字距(一屏里几个数字对齐才不"跳")---------- */
.stat-card,.mstats .m b,.stat-card .s b{font-variant-numeric:tabular-nums}
.stat-card{margin:16px 16px 0;border-radius:var(--r-lg)}
.stat-card .s{padding:14px 6px 13px}
.stat-card .s b{font-size:calc(19px*var(--f));font-weight:800;letter-spacing:-.02em}
.stat-card .s b.teal{color:var(--accent)}
.stat-card .s span{margin-top:3px}
.mstats{background:var(--bg);border-bottom:none;border-top:1px solid var(--line)}
.mstats .m b{font-size:calc(17px*var(--f));font-weight:800;letter-spacing:-.02em}

/* ---------- 8 段落标题:与卡片外沿对齐(16px),右侧"全部/查看更多"给品牌蓝 ---------- */
.sec-h{padding:18px 16px 8px}
.sec-h .st{font-size:calc(15.5px*var(--f));letter-spacing:-.01em}
.sec-h .more{color:var(--accent);font-weight:600}
.page-title{font-size:calc(24px*var(--f));font-weight:800;letter-spacing:-.02em;padding:14px 18px 4px}

/* ---------- 9 分段控件 / 标签:线改半透明,选中块给一层柔光 ---------- */
.seg{background:var(--panel);border:1px solid var(--line);border-radius:13px;padding:3px}
.seg span{border-radius:10px;color:var(--ink2);transition:color .18s ease,background .18s ease}
.seg span.on{background:var(--bg);color:var(--ink);font-weight:700;box-shadow:0 1px 2px rgba(15,34,36,.08),0 6px 14px -10px rgba(15,34,36,.2)}
.chip{border-radius:7px;letter-spacing:.01em}
.chip-teal{background:var(--accent-soft);color:var(--accent)}

/* ---------- 10 输入:聚焦时用品牌蓝描边(原来只有浏览器默认的轮廓)---------- */
.f-input,.f-area,.searchbar,.ms-input{border-color:var(--line-2);background:var(--bg)}
.f-input:focus,.f-area:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.searchbar:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}

/* ---------- 11 空状态:统一形状(图标 → 一句话 → 一个出口按钮)---------- */
.joined-empty,.ms-empty{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);
                        box-shadow:var(--shadow);margin:12px 16px 0;padding:28px 20px 24px}
.joined-empty .ic,.ms-empty .ic{color:var(--accent);opacity:.55}
.ms-empty{display:block}
/* ⚠ 嵌在 .listblock 里的空态**不要再画自己的卡片**。
   为什么(2026-09-28 学员截图反馈「最新通知这里为什么会出现两个框」):
   第 1714 行把 .listblock 改成了「白卡片」——`margin:12px 16px 0` + `border:1px` + `radius:18` + 阴影;
   而这一行又给 .joined-empty 加了**一模一样的**一整套。空态是**放在 .listblock 里面**的,
   于是同一个位置上画了两个同心圆角框(间距还一样,看着就是"一道痕 + 一个框"),
   学员看到的就是"多了一个框"。
   修法:套在 listblock 里时,空态退回"只有内容"(背景/边框/阴影/外边距全部交给外层卡片)。
   这样 ① 通知层 ② 首页通知块 这两处共用空态的地方都不再重框;
   而独立使用的 .joined-empty(班级/报名/购课那些直接挂在 .app 下的)保持不变。 */
.listblock .joined-empty,.listblock .ms-empty{
  background:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:26px 20px 24px;
}

/* ---------- 12 无障碍兜底:新增的过渡一律尊重"减少动态效果" ---------- */
@media (prefers-reduced-motion:reduce){
  .func,.mode,.seg span,.quick .q .q-btn,.grid4 .g .g-ic{transition:none}
  .func:active,.mode:active{transform:none}
}

/* ==========================================================================================
   设计系统 v2 · 学员端答题链路(P3,2026-09-28)

   这一段的取舍和"外壳好看"不一样:外壳只要第一眼有质感,而答题页是学员**一天要待 20 分钟以上**
   的地方,所以这里的预算全花在"读得清"和"状态一眼可判读"上,装饰性的一律不做。

   三件具体的事:
     ① 题干字号提一档(16→17px,行高 1.6→1.65):全 App 读得最多的那 20 行字,值得这一档。
     ② 选项三态在**颜色 + 描边 + 阴影**三个通道上同时变化。只靠颜色区分,对色觉障碍的人
        等于没区分 —— 这不是审美问题(§无障碍),所以已选给了描边+光晕,正确给了实色标记,
        错误给了淡红底 + 红边,"漏选"给了虚线边。
     ③ 对/错/已选三处原来各写各的绿:选项用写死的 #2E8B77、解析条也用 #2E8B77、
        而设计系统里的 --ok-fg 是 #217A63,chip-green 又是 #217A63 —— 同一个"对"有三种绿。
        这一节全部改走 --ok-fg / --err-fg / --accent 令牌,深色下由令牌自动提亮。
   ========================================================================================== */

/* ---------- 13.0 二级页(push)也用页底色:卡片才会浮起来 ----------
   原来 .layer 的底是 --bg(卡面色),而页面里的卡片也是 --bg —— 实测答题页 **82% 的像素
   是同一个颜色**,也就是"一整块白板 + 看不见的卡片"。整屏页面统一用 --page 之后,
   页底/卡片/弹层三档亮度关系在主 Tab、二级页、弹层里完全一致(深色下同理)。 */
.layer{background:var(--page)}

/* ---------- 13.1 顶栏与进度:同一个"进度"原来有两套颜色(答题页墨黑 / 首页品牌蓝)---------- */
.exam-bar{background:var(--bg);border-bottom:1px solid var(--line)}
.exam-bar .back,.exam-bar .side,.exam-bar .bar-act{background:var(--panel);border:1px solid var(--line)}
.exam-bar .prog{height:6px;background:var(--panel);border:1px solid var(--line)}
.exam-bar .prog i{background:var(--accent)}
.exam-bar .count,.exam-bar .timer{font-variant-numeric:tabular-nums}
.exam-bar .timer{background:var(--panel);border:1px solid var(--line)}
.progress{background:var(--panel);border:1px solid var(--line);border-radius:999px;overflow:hidden}
.progress>i{background:var(--accent)}

/* ---------- 13.2 题干卡:全 App 读得最多的一块字 ---------- */
.q-card{padding:18px 16px;box-shadow:var(--shadow)}
.q-text{font-size:calc(17px*var(--f));line-height:1.65;letter-spacing:-.005em}
.q-tags{gap:6px;margin-bottom:13px}

/* ---------- 13.3 选项:三态(未选 / 已选 / 对错)三通道可辨 ---------- */
.opt{padding:14px;border-radius:14px;box-shadow:0 1px 2px rgba(15,34,36,.03)}
.opt p{font-size:calc(15px*var(--f));line-height:1.6}
.opt .badge{width:28px;height:28px;font-weight:700}
.opt.picked{border-color:var(--accent);background:var(--accent-wash);box-shadow:0 0 0 3px var(--accent-soft)}
.opt.picked .badge{background:var(--accent);color:var(--bg)}
.opt.right,.opt.right.picked{border-color:var(--ok-fg);background:var(--ok-bg);box-shadow:0 0 0 3px var(--ok-bg)}
.opt.right .badge{background:var(--ok-fg);color:var(--bg)}
.opt.wrong{border-color:var(--err-fg);background:var(--err-bg)}
.opt.wrong .badge{background:var(--red);color:var(--on-solid)}
.opt.miss{border-style:dashed;border-color:var(--line-2);background:var(--panel)}

/* ---------- 13.4 解析块:绿/红都走语义令牌,不再各自写死一个绿 ---------- */
.analysis{background:var(--ok-bg);border-color:transparent;border-left:3px solid var(--ok-fg);padding:14px 15px}
.analysis .ok,.analysis .an-score{color:var(--ok-fg)}
.analysis .an-ic{background:var(--bg);color:var(--ok-fg)}
.analysis p{line-height:1.75}
.analysis.err{background:var(--err-bg);border-left-color:var(--err-fg)}
.analysis.err .ok,.analysis.err .an-ic{color:var(--err-fg)}
/* 深色下把这一组钉死:上面那些 body.dark 老补丁的优先级比 .analysis.err 高,
   不写这几行的话"答错"的解析在深色模式里会显示成绿色(实测过这一类覆盖坑)。 */
body.dark .analysis .an-ic{color:var(--ok-fg)}
body.dark .analysis.err .ok,body.dark .analysis.err .an-ic{color:var(--err-fg)}

/* ---------- 13.5 多选确认键:未选够时不是"变灰不可点",而是说清还差什么 ---------- */
.q-confirm{border-radius:14px}
.q-confirm .qc-n{opacity:.8}

/* ---------- 13.6 答题卡弹层 ---------- */
/* ⚠ 投影**只许挂在 `.sheet.on` 上**(2026-09-28 学员第三次指着底栏说"有黑色阴影"之后实测确认):
   弹层是靠 `transform:translateY(102%)` 藏起来的(见 §13.1 的 `.sheet`),**本体推到屏幕外,自己还在画**。
   而这一层的 `box-shadow:0 -14px 44px -14px` 是**向上**投的 —— 页面上有 6 个这样的弹层同时蹲在屏幕下方
   (矩形 top 在 935~942,视口底是 932),6 × rgba(15,34,36,.26) 叠起来 = 约 84% 的黑,
   全糊在底栏最下面那 30px 上:实测底栏底部一行是 (74,90,90),往上到 y=900 才慢慢回到 (214,217,217)。
   这正是学员说的"底部导航栏**向上扩散**的黑色阴影"——不是底栏自己的样式(底栏是实色、无投影、无毛玻璃)。
   判据(注入对照,可复跑):`.workbench/_diag-bottom-strip.mjs` 把 `.sheet` 的投影去掉后,
   底栏底部每一行**精确回到 (252,254,254)**;而把底栏底色改成纯红时那层黑会跟着变红(说明它画在底栏之上)。
   改成挂 `.on` 之后:关着的弹层不投影(看不见的层不该有影子),打开时投影照旧(它那时盖住底栏,
   影子落在上方内容上,正是想要的效果)。 */
.sheet{border-radius:22px 22px 0 0}
.sheet.on{box-shadow:0 -14px 44px -14px rgba(15,34,36,.26)}
.grab{width:44px;height:5px;background:var(--ink);opacity:.18}
.sheet h3{font-size:calc(16px*var(--f));letter-spacing:-.01em}
.sheet-grid{gap:9px}
.sheet-grid .cell{border-radius:11px;background:var(--panel);border:1px solid var(--line);
                  font-size:calc(13px*var(--f));font-weight:600;color:var(--ink2)}
.sheet-grid .cell.done{background:var(--accent);border-color:var(--accent);color:var(--bg)}
.sheet-grid .cell.wrong{background:var(--err-bg);border-color:var(--err-fg);color:var(--err-fg)}
.sheet-grid .cell.cur,.sheet-grid .cell.on{outline:2px solid var(--accent);outline-offset:1px}
.sheet-grid .cell.on{background:var(--accent-soft);color:var(--accent);font-weight:800}

/* ---------- 13.7 交卷报告单 ---------- */
.ant-result .ar-ic{width:56px;height:56px;box-shadow:var(--shadow)}
.result-row div{background:var(--panel);border:1px solid var(--line);border-radius:14px}
.result-row i{letter-spacing:-.02em}

/* ---------- 13.8 错题本 / 收藏 / 章节页共用的小件 ---------- */
.ant-stat .as-v{font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.fav-btn{border:1px solid var(--line);background:var(--bg);color:var(--ink2)}
.fav-btn.on{border-color:var(--err-fg);background:var(--err-bg);color:var(--err-fg)}
.fav-side{border-radius:14px}
.fav-side.on{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-ink)}
.sec-h .mode-tip{font-variant-numeric:tabular-nums}
/* 浅底上的小字用"文字档"的状态色(--ok-fg/--warn-fg/--err-fg),不用填充档(--green/--amber/--red):
   填充档是为了"实底 + 白字"选的,拿来当浅底文字只有 2.4~3.9:1,全站在 4.5:1 底下(见令牌层注释)。 */
.opt.right .mark{background:var(--ok-fg)}
.bk-big.price{color:var(--err-fg)}
.bk-big.ok{color:var(--accent-ink)}
.lv-tag,.lv-card.on .lv-cam{color:var(--accent-ink)}
.pb-blue,.top-pill,.sec-btn.ghost{color:var(--accent-ink)}

/* ---------- 13.9 底部操作条:和 TabBar 一样用玻璃底,内容从下面穿过时看得见一点 ---------- */
.exam-foot{background:var(--glass);border-top:1px solid var(--line);
           -webkit-backdrop-filter:saturate(180%) blur(18px);backdrop-filter:saturate(180%) blur(18px)}
.exam-foot .side{background:var(--panel);border:1px solid var(--line);color:var(--ink2)}

/* ---------- 13.10 状态色标签:改用 -wash 淡底令牌(深色下自动换) ---------- */
.chip-green{background:var(--ok-bg);color:var(--ok-fg)}
.chip-amber{background:var(--warn-bg);color:var(--warn-fg)}
.chip-red{background:var(--err-bg);color:var(--err-fg)}

@media (prefers-reduced-motion:reduce){
  .opt,.sheet-grid .cell{transition:none}
}

/* ==========================================================================================
   设计系统 v2 · 学员端其余浮层(P4,2026-09-28)

   P4 的施工方式与 P2/P3 不同:**先用审计脚本量,再动手**。
     `node .workbench/audit-layer-conformance.mjs` 把 29 个浮层逐层量四件事:
     对比度(小字 ≥4.5:1、大字 ≥3:1)/ 字号是否在阶梯上 / 圆角是否在集合里 / 哪些文字压在图片上(跳过,算不出)。
     为什么非要先量:换皮到第 20 屏走形是重做 UI 最典型的失败方式,而"这屏的灰字太浅"
     靠眼睛是看不出来的 —— 第一轮量出来 **24 层有小字对比度不达标**(同一个原因)。
   量出来的主因只有一个,但它影响 24 屏:**状态色被当成文字色用**。
     --green(#52B8A4)/--amber(#B7791F)/--red(#E5484D) 是为"实底 + 白字"选的填充色,
     压在浅底上当文字只有 2.4~3.9:1;--ink3 作为全站提示文字色,原来是 #9AA0AA(2.6:1)。
     修法不是在 24 屏里各改一遍,而是在令牌层把"填充档"和"文字档"分开(#616D6F / #1B6B57 / #C62A2F),
     再把 15 处内联样式与十来条规则收进文字档 —— 一处改、24 屏一起过。
   ========================================================================================== */

/* ---------- 14.1 文字档状态色(小字与图标的对比度) ---------- */
.lv-txt b .lv-tag{color:var(--accent-ink)}
.lv-card.on .lv-txt span{color:var(--ink2)}   /* 选中卡是淡蓝底,底上再用 ink3 只有 4.2:1 */
.pb-blue{color:var(--accent-ink)}
.bk-big.price{color:var(--err-fg)}
.f-err{color:var(--err-fg)}

/* ---------- 14.2 圆角与进度条:5px 高的进度条用 3px 圆角看着是"缺角",全站统一成胶囊 ---------- */
.bk-prog,.bk-prog i{border-radius:99px}

/* ---------- 14.4 淡蓝底上的文字/图标一律用 --accent-ink(比 --accent 深一档)----------
   深色模式下 --accent(#5B8DFF)压在 16% 蓝底上只有 4.37:1,就差这一点点不达标 ——
   而"差一点点"在手机户外光下就是看不看得清的区别。浅色下同理(#1C5CE4 → #1746B8)。
   --accent 继续用于描边、进度条填充、实底(那些不是"文字压在淡底上")。 */
.chip-teal,.top-pill,.cc-badge,.code-btn,.pick-chips span.on,.create-cta .cta-plus,
.bk-ic.cat-uav,.bc-ic,.bh-switch,.pd-actions .btn.on,.rail-item.on,.rail-item.on i,
.sheet-grid .cell.on,.spec-card .sc-ic.ic-teal,.f-ic.f-blue,.req-cell .rc-tag,
.cd-hero .cd-code,.cd-code{color:var(--accent-ink)}
/* 2026-10-08 补:`.fb-kinds .chip.on`(意见反馈/举报的「故障 / 报错」这类选中的分类 chip,
   assets/app.css:930)原来不在上面这份名单里 —— 名单是**手抄的**。它是同一个毛病:
   --accent 压在 16% 淡蓝底上,深色下 13px 只有 4.37:1(要 4.5)。
   怎么抓到的:设计系统体检原来只量 `.layer`,**15 个弹层一个都没量过**;补上弹层那一遍,
   第一次跑就把它报出来了(其余 9 个弹层的同类 chip 都由这条一起修好)。 */
.fb-kinds .chip.on{color:var(--accent-ink)}

/* ---------- 14.3 前景跟着填充反相:深色模式下 --accent/--ink 会变亮,写死 #fff 的字会看不见 ----------
   判据很简单:填充用的是会因为主题变亮的令牌(--accent / --ink),前景就必须用 --bg(近白↔深),
   两者一起翻转;填充用的是两套主题都一样的实色(--red / --amber),前景才用 --on-solid(一直浅)。
   压在照片/渐变上的白字不在此列(那是标准做法,照片上白字最稳)。 */
.m-card .m-check,.ai-badge,.lv-card.on .lv-ic,.lv-card.on .lv-radio{color:var(--bg)}
.fab-post{color:var(--bg)}
.fav-on{color:var(--bg)!important}
.model-switch span.on{background:var(--bg)}
.switch i{background:var(--on-solid)}
.badge-num{color:var(--on-solid)}

/* ---------- 邀请奖励层(我的 → 邀请奖励,2026-10-07)----------
   为什么要有这一小块:邀请码要**大而醒目**(学员会照着念给别人),而设计系统的字号阶梯里
   大号只有 22/24/26/28/30 几档 —— 用 inline style 随手写 25px 就会掉出阶梯
   (.workbench/audit-layer-conformance.mjs 第 ② 条量这个)。
   圆角/颜色一律走已有令牌,不新造:这一层是新页,新页最容易被写成"自己一套。 */
.iv-code{display:flex;align-items:center;gap:12px;margin-top:8px}
.iv-code b{font-size:calc(26px*var(--f));font-weight:800;letter-spacing:.12em;color:var(--ink);
  font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none}
.iv-code .code-btn{margin-left:auto}
.iv-acts{display:flex;gap:10px;margin-top:12px}
.iv-acts .btn-solid-s,.iv-acts .btn-ghost-s{flex:1 1 0;min-width:0}
.iv-form{margin-top:10px;display:none}
.iv-form.on{display:block}
.iv-form .f-input{margin-top:8px}
.iv-form .seg{margin-top:8px}

/* ==========================================================================================
   学情诊断(我的 → 学情诊断,2026-10-09 加)

   为什么要有这一屏:全端到处都在说「练了多少」(首页统计、章节进度 3%、周报),
   **没有一处说「错在哪一类题上」**。学员最想要的那句话只有四个字:「我差在哪」。

   这一小块样式只做三件现有类做不到的事,其余(卡片/行/章节标题/chip/空状态)一律复用:
     ① 大号预估分 —— 字号走阶梯里的 26px(与 .iv-code 同档),不随手写 25px;
     ② 短板行右边的正确率用**文字档状态色**(--ok-fg/--warn-fg/--err-fg,见上文 14.1),
        不用填充档(--green/--red 是给实底白字用的,压在卡面上只有 2.4~3.9:1);
     ③ 「考场节奏」里的对比刻度(两条 1px 发丝线 + 一根 2px 的当前值),不新画一个图。
   圆角/字号/颜色全部取自现有令牌,不新造 —— 新页最容易写成"自己一套"。 */
.dg-hero{display:flex;align-items:flex-start;gap:14px}
.dg-score{font-size:calc(26px*var(--f));font-weight:800;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1.15;display:block}
.dg-score small{font-size:calc(12px*var(--f));font-weight:600;color:var(--ink3);margin-left:2px}
.dg-verdict{display:flex;flex-direction:column;gap:6px;align-items:flex-start;padding-top:4px;margin-left:auto;text-align:right}
.dg-verdict .chip,.dg-verdict .dg-basis{align-self:flex-end}
.dg-basis{font-size:calc(11.5px*var(--f));color:var(--ink3);line-height:1.6}
.dg-note{font-size:calc(11.5px*var(--f));color:var(--ink3);line-height:1.6;margin:10px 0 0}
.dg-v{font-variant-numeric:tabular-nums}
.dg-v.ok{color:var(--ok-fg)}
.dg-v.warn{color:var(--warn-fg)}
.dg-v.err{color:var(--err-fg)}
.dg-pace{margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}
.dg-foot{margin:14px 16px 24px;font-size:calc(11px*var(--f));color:var(--ink3);line-height:1.7}
.dg-foot b{color:var(--ink2);font-weight:600}
#diagBody .joined-empty b{font-size:calc(13px*var(--f));color:var(--ink2);font-weight:600;display:block}
#diagBody .joined-empty span{font-size:calc(11.5px*var(--f));color:var(--ink3);display:block;margin-top:4px;line-height:1.6}

/* ============ ㉗ 演示数据(2026-10-09) ============
   未登录(且学员没主动清过)时,页面上多出三处「含示例数据」徽标 + 一条首页横幅 +
   「我的 → 演示数据说明」一行入口;都由 syncDemoMarks() 按同一个判据 demoBaseboardOn() 显隐。
   这层只管外观,一句文案都不写在这里 —— 清单与说明的文字只有 renderDemo / DEMO_ITEMS 一份来源。 */
/* flex 元素会盖掉浏览器默认的 [hidden]{display:none}(先例:.msg-allread[hidden],见上方),必须自己写 */
.demo-note[hidden],.demo-mark[hidden],[data-demo-only][hidden],.demo-wipe-hint[hidden],.cl-hint2[hidden]{display:none}
/* 首页横幅:沿用 .ant-alert.warning 的盒子,只加"可点"的反馈 —— 它是进 #layer-demo 的入口 */
.demo-note{cursor:pointer;transition:transform var(--dur-press) var(--ease)}
.demo-note:active{transform:scale(.99)}
/* 统计块旁的小徽标:紧凑药丸,重心在"含示例数据"这四个字上 */
.demo-mark{display:inline-flex;align-items:center;gap:6px;margin:10px 16px 0;padding:7px 12px;border-radius:999px;
  background:var(--warn-bg);color:var(--warn-fg);border:1px solid rgba(183,121,31,.3);cursor:pointer;
  font-size:calc(12px*var(--f));font-weight:600;line-height:1;transition:transform var(--dur-press) var(--ease)}
.demo-mark:active{transform:scale(.97)}
.demo-mark .aa-ic{display:inline-flex;width:14px;height:14px;flex:0 0 auto}
.demo-mark .aa-ic svg{width:14px;height:14px;display:block}
.demo-mark .aa-body{display:inline;font-size:inherit;color:inherit;line-height:1}
body.dark .demo-mark{border-color:rgba(255,255,255,.16)}
/* 清空按钮:破坏性动作,底色用 --err-bg 而不是实心红 —— 常态下它只是一句"要清就点这里",
   等学员点了第一次(二次确认)才换成实心红,颜色本身就是"现在真的会清"的信号。 */
.demo-wipe{width:100%;height:46px;margin-top:12px;border-radius:13px;border:1px solid rgba(229,72,77,.34);
  /* ㉔ 的清空是 div 复用这个类(㉗ 是真 button)—— UA 只替 button 居中,不写这几行文字会贴左上角。 */
  display:flex;align-items:center;justify-content:center;text-align:center;padding:0 14px;
  background:var(--err-bg);color:var(--err-fg);font-size:calc(15px*var(--f));font-weight:700;font-family:inherit;
  cursor:pointer;transition:background var(--dur-2) var(--ease),color var(--dur-2) var(--ease),transform var(--dur-press) var(--ease)}
.demo-wipe:active{transform:scale(.98)}
.demo-wipe.arm{background:var(--red);color:var(--on-solid);border-color:var(--red)}
.demo-wipe-hint{margin-top:8px;font-size:calc(12px*var(--f));color:var(--err-fg);line-height:1.6}
.elder .demo-wipe{height:calc(46px + 6px*var(--t))}
/* ⚠ 2026-10-09 实测抓到的真缺陷:层内滚到底时这颗按钮停在 714-760,而 PWA 安装条(#pwaBar,
   悬在 TabBar 上方,preview.html 里生成、挂在 body 上,z-index 9000)当时占 707-763 ——
   elementFromPoint 在按钮整段高度上返回的全是那条提示条,真实点击一下都打不到按钮
   (程序化 .click() 却是好的,所以只看「函数有没有被调用」会漏掉这类「点不着」)。
   修法:给这一层的滚动区留出比「底部 76px + 提示条自身高度」更宽的余量,滚到底时按钮停在它上方。
   独立安装(App/小程序壳)里没有这条提示条,效果只是底部多一段空白。 */
#layer-demo .app{padding-bottom:calc(150px + max(env(safe-area-inset-bottom, 0px), var(--safe-b, 0px)))}

/* ===== ⑫ 不确定标记(2026-10-09 加) =====
   一颗 chip 摆在选项区与「确认答案」之间 —— 位置本身就说明规矩:判分**之前**才谈得上标。
   设计系统那三条照旧:不用纯白纯黑、描边一律半透明发丝线、状态色自带同色淡底。
   未标 = 中性(--panel / --ink2);已标 = 琥珀(--warn-bg / --warn-fg),深色模式跟着换。
   高度 38px:学员端的热区口径是 ≥36px(见 check.mjs 那条 36px 判据),不做 34px 的小籽。 */
.unsure-row{margin:12px 16px 0;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.unsure-chip{display:inline-flex;align-items:center;gap:6px;height:calc(38px + 6px*var(--t));padding:0 14px;
  border-radius:999px;border:1px solid var(--line);background:var(--panel);color:var(--ink2);cursor:pointer;
  font-size:calc(12.5px*var(--f));font-weight:600;line-height:1;
  transition:background var(--dur-2) var(--ease),color var(--dur-2) var(--ease),border-color var(--dur-2) var(--ease),transform var(--dur-press) var(--ease)}
.unsure-chip:active{transform:scale(.97)}
.unsure-chip .uc-ic{display:inline-flex;align-items:center;margin-left:-3px;color:var(--ink3)}
.unsure-chip .uc-ic svg{display:block}
.unsure-chip.on{background:var(--warn-bg);color:var(--warn-fg);border-color:rgba(183,121,31,.3)}
.unsure-chip.on .uc-ic{color:var(--warn-fg)}
body.dark .unsure-chip.on{border-color:rgba(229,181,102,.34)}
.unsure-chip.locked{cursor:default;opacity:.9}
.unsure-chip.locked:active{transform:none}
.unsure-hint{flex:1;min-width:110px;font-size:calc(11.5px*var(--f));color:var(--ink3);line-height:1.5}
@media (hover:hover) and (pointer:fine){.unsure-chip:not(.locked):hover{border-color:var(--accent)}}
/* 判分后那颗「蒙对」徽标(挂在解析抬头里,判语与得分之间) */
.analysis .an-unsure{flex:none;display:inline-flex;align-items:center;height:calc(20px*var(--f));padding:0 8px;
  border-radius:999px;background:var(--warn-bg);color:var(--warn-fg);border:1px solid rgba(183,121,31,.3);
  font-size:calc(11px*var(--f));font-weight:700;line-height:1}
body.dark .analysis .an-unsure{border-color:rgba(229,181,102,.34)}
/* 学情诊断里那句「N 题是蒙对的」:同色淡底,别跟正文抢注意力 */
.dg-note.dg-unsure{margin-top:8px;padding:8px 10px;border-radius:12px;background:var(--warn-bg);color:var(--warn-fg)}

/* ===== ⑲ 题库正文搜索(2026-10-09 加) =====
   搜索行本身复用现成的 .searchbar(与班级/学员/比赛/论坛/通知那 5 个同一个组件):
   40px 高(+长辈模式)、--panel 底、聚焦时品牌蓝描边,分别见 app.css:621 / 170 / 1974,这里不重写一份。
   新的只有三件事:
     ① 清空键:.ms-clear 默认 display:none,要靠父级 .has 才显形 —— 输入框有内容时由 qSearchNow 加上;
     ② 结果卡片:发丝线分隔(不用硬色描边),每行 ≥52px 热区,远超 36px 的口径;
     ③ 关键词高亮:品牌蓝淡底 + --accent-ink 文字 —— 状态色之外的强调色只有它,而且自带同色淡底(设计系统第 ③ 条)。 */
.searchbar.has .ms-clear{display:flex}
#qSearchBox[hidden]{display:none}
.qs-head{margin:10px 16px 0;font-size:calc(11.5px*var(--f));color:var(--ink3);line-height:1.7}
.qs-head b{color:var(--accent);font-weight:700}
.qs-head-2{margin-top:4px}
.qs-chap{margin:10px 16px 0;display:flex;flex-wrap:wrap;gap:8px}
.qs-chap-btn{display:inline-flex;align-items:center;height:34px;padding:0 14px;border-radius:999px;
  background:var(--accent-soft);color:var(--accent-ink);font-size:calc(12.5px*var(--f));font-weight:600;cursor:pointer;
  transition:transform var(--dur-press) var(--ease)}
.qs-chap-btn:active{transform:scale(.97)}
.qs-list{margin:8px 16px 0;border:1px solid var(--line);border-radius:var(--r);background:var(--bg);overflow:hidden}
.qs-row{padding:calc(12px + 2px*var(--t)) 14px;border-bottom:1px solid var(--line);cursor:pointer}
.qs-row:last-child{border-bottom:none}
.qs-row:active{background:var(--panel)}
.qs-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:7px}
.qs-stem{font-size:calc(13.5px*var(--f));color:var(--ink);line-height:1.65}
.qs-exp{margin-top:6px;font-size:calc(11.5px*var(--f));color:var(--ink3);line-height:1.7}
.qs-stem mark,.qs-exp mark{background:var(--accent-soft);color:var(--accent-ink);border-radius:4px;padding:0 2px;font-weight:700}
.qs-empty{padding:26px 20px 14px;text-align:center;color:var(--ink2);font-size:calc(13.5px*var(--f));font-weight:600}
.qs-empty span{display:block;margin-top:6px;font-size:calc(11.5px*var(--f));color:var(--ink3);font-weight:400;line-height:1.7}
.elder .qs-row{padding-top:calc(12px + 4px*var(--t));padding-bottom:calc(12px + 4px*var(--t))}


/* ===== ⑳ 术语 · 单位速查(2026-10-09 加)===== */

/* 解析里的可点词:虚线底线 —— 一眼看出能点,又不像链接那样抢走正文的注意力 */
#analysisText .gl-t{color:var(--ink);border-bottom:1px dashed var(--accent-ink);cursor:pointer;-webkit-tap-highlight-color:transparent}
#analysisText .gl-t:active{background:var(--accent-soft);border-radius:3px}
.gl-head{margin:12px 16px 0;font-size:calc(12.5px*var(--f));line-height:1.72;color:var(--ink2)}
.gl-head b{color:var(--ink);font-weight:600}
.gl-meta{margin:6px 16px 0;font-size:calc(11.5px*var(--f));color:var(--ink3);line-height:1.6}
.gl-count{font-size:calc(12px*var(--f));color:var(--ink3);font-weight:500}
.gl-list{margin:0 16px;border:1px solid var(--line);border-radius:var(--r);background:var(--bg);overflow:hidden}
.gl-item{padding:calc(12px + 2px*var(--t)) 14px;border-bottom:1px solid var(--line)}
.gl-item:last-child{border-bottom:0}
.gl-it-h{display:flex;align-items:baseline;gap:8px}
.gl-tm{font-size:calc(14.5px*var(--f));font-weight:600;color:var(--ink);letter-spacing:-.01em}
.gl-n{font-size:calc(11px*var(--f));color:var(--ink3);font-variant-numeric:tabular-nums}
.gl-df{margin-top:4px;font-size:calc(13px*var(--f));line-height:1.72;color:var(--ink2)}
.gl-df mark,.gl-tm mark{background:var(--accent-soft);color:var(--accent-ink);border-radius:4px;padding:0 2px}
.gl-empty{margin:14px 16px;padding:24px 16px;text-align:center;color:var(--ink2);font-size:calc(13.5px*var(--f));font-weight:600;border:1px solid var(--line);border-radius:var(--r);background:var(--bg)}
.gl-empty span{display:block;margin-top:6px;font-size:calc(11.5px*var(--f));color:var(--ink3);font-weight:400;line-height:1.7}
.gl-card{margin:12px 16px 0;padding:14px;border:1px solid var(--line);border-radius:var(--r);background:var(--bg)}
.gl-ch{font-size:calc(13px*var(--f));font-weight:600;color:var(--ink)}
.gl-row{display:flex;align-items:center;gap:8px;margin-top:12px}
.gl-in{flex:1;min-width:0;height:calc(40px + 4px*var(--t));padding:0 12px;border:1px solid var(--line);border-radius:12px;background:var(--panel);color:var(--ink);font-size:calc(14px*var(--f));font-family:inherit;outline:none;-moz-appearance:textfield}
.gl-in:focus{border-color:var(--accent-ink)}
.gl-in::-webkit-outer-spin-button,.gl-in::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.gl-eq{font-size:calc(13px*var(--f));color:var(--ink3);flex:none}
.gl-out{flex:1;min-width:0;font-size:calc(13px*var(--f));color:var(--ink);font-variant-numeric:tabular-nums}
.gl-note{margin-top:9px;font-size:calc(11.5px*var(--f));line-height:1.68;color:var(--ink3)}
.gl-note-foot{margin:14px 16px calc(20px + max(env(safe-area-inset-bottom,0px),var(--safe-b,0px)))}
#layer-gloss .app{padding-bottom:calc(20px + max(env(safe-area-inset-bottom,0px),var(--safe-b,0px)))}

/* 底部术语小卡:在解析里点词就地出释义 */
.gl-tip{position:absolute;left:12px;right:12px;bottom:calc(12px + max(env(safe-area-inset-bottom,0px),var(--safe-b,0px)));z-index:210;padding:14px 14px 8px;border:1px solid var(--glass-line);border-radius:var(--r-lg);background:var(--bg);box-shadow:var(--sd-3);animation:glTipIn var(--dur-2) var(--ease-emphasized)}
.gl-tip[hidden]{display:none}
.gl-tip-h{display:flex;align-items:baseline;gap:8px}
.gl-tip-c{font-size:calc(11px*var(--f));color:var(--accent-ink);background:var(--accent-soft);border-radius:999px;padding:2px 8px;font-weight:600}
.gl-tip-n{font-size:calc(11px*var(--f));color:var(--ink3);font-variant-numeric:tabular-nums}
.gl-tip-t{margin-top:8px;font-size:calc(15.5px*var(--f));font-weight:700;color:var(--ink);letter-spacing:-.01em}
.gl-tip-b{margin-top:5px;font-size:calc(13px*var(--f));line-height:1.72;color:var(--ink2)}
.gl-tip-f{display:flex;align-items:center;justify-content:space-between;margin-top:6px}
.gl-tip-x{padding:10px 4px;font-size:calc(13px*var(--f));color:var(--ink3);cursor:pointer}
.gl-tip-m{padding:10px 4px;font-size:calc(13px*var(--f));color:var(--accent-ink);font-weight:600;cursor:pointer}
.gl-tip-x:active,.gl-tip-m:active{opacity:.55}
@keyframes glTipIn{from{transform:translateY(14px);opacity:0}to{transform:translateY(0);opacity:1}}
@media (prefers-reduced-motion:reduce){.gl-tip{animation:none}}
.elder .gl-item{padding-top:calc(12px + 4px*var(--t));padding-bottom:calc(12px + 4px*var(--t))}
.elder .gl-df,.elder .gl-tip-b{font-size:calc(14.5px*var(--f))}
/* ===== ㉑ 分享这题 / ㉔ 报考与考场清单(2026-10-09 加) =====
   ㉑ 只多了一个 chip —— 直接复用 ⑳「查术语」那套 .an-ask(解析抬头的现成组件),不另起一套样式。
   ㉔ 的清单行与「我的」页那些 .row 长得很像,但不能直接用 .row:一行里要塞「勾选框 + 标题 + 说明 + 出处标签」,
      而且整行是勾选热区。所以另起 .cl-row,排版口径与 .row 对齐(13px 内边距、发丝线分隔)。
   设计系统三条照办:① 底色一律 --bg / --page;② 分隔一律 1px solid var(--line);③ 勾上的方框用品牌蓝实底
      + --on-solid 对勾(与 .switch.on 同一个色),出处标签用同色淡底 + 同色字(不是实心色块)。 */
.cl-head{padding:14px 16px 4px}
.cl-prog{display:flex;align-items:baseline;gap:8px}
.cl-prog b{font-size:calc(24px*var(--f));font-weight:800;color:var(--accent);letter-spacing:-.02em}
.cl-prog span{font-size:calc(12.5px*var(--f));color:var(--ink3)}
.cl-bar{height:6px;border-radius:999px;background:var(--panel);margin:10px 0 8px;overflow:hidden}
.cl-bar i{display:block;height:100%;border-radius:999px;background:var(--accent);transition:width var(--dur-2) var(--ease-emphasized)}
.cl-days{font-size:calc(12.5px*var(--f));color:var(--ink2)}
.cl-days b{font-weight:800;color:var(--ink)}
.cl-link{color:var(--accent);font-weight:600;cursor:pointer}
.cl-link:active{opacity:.6}
.cl-note{margin:10px 0 0;font-size:calc(11.5px*var(--f));line-height:1.7;color:var(--ink3)}
/* 清单行:整行都是勾选热区(实测 ≥52px),左边方框、中间两行字、右边出处标签 */
.listblock.cl-lb .cl-row{display:flex;align-items:flex-start;gap:12px;padding:13px 16px;background:var(--bg);
  border-bottom:1px solid var(--line);cursor:pointer;transition:background var(--dur-1) ease}
.listblock.cl-lb .cl-row:last-child{border-bottom:0}
.cl-row:active{background:var(--panel)}
.cl-box{flex:none;width:22px;height:22px;margin-top:1px;border-radius:7px;border:1.5px solid var(--line-2);
  background:var(--bg);position:relative;box-sizing:border-box;
  transition:background var(--dur-1) ease,border-color var(--dur-1) ease}
.cl-row.on .cl-box{background:var(--accent);border-color:var(--accent)}
.cl-row.on .cl-box::after{content:'';position:absolute;left:6px;top:2.5px;width:5px;height:10px;
  border:2px solid var(--on-solid);border-top:0;border-left:0;transform:rotate(45deg);box-sizing:border-box}
.cl-tx{flex:1;min-width:0}
.cl-tx b{display:block;font-size:calc(13.5px*var(--f));font-weight:600;color:var(--ink);line-height:1.5}
.cl-row.on .cl-tx b{color:var(--ink2)}
.cl-tx span{display:block;margin-top:4px;font-size:calc(11.5px*var(--f));line-height:1.65;color:var(--ink3)}
.cl-src{flex:none;height:calc(19px*var(--f));padding:0 7px;border-radius:999px;display:inline-flex;align-items:center;
  margin-top:1px;font-size:calc(10.5px*var(--f));font-weight:700;line-height:1;white-space:nowrap;
  background:var(--accent-soft);color:var(--accent);border:1px solid rgba(28,92,228,.18)}
/* 「应用」这一档借 .chip-green 那套绿(出处标签不是状态,所以只借色、不借语义) */
.cl-src-a{background:rgba(82,184,164,.14);color:#217A63;border-color:rgba(82,184,164,.28)}
body.dark .cl-src{background:var(--accent-soft);border-color:rgba(91,141,255,.3)}
body.dark .cl-src-a{background:var(--ok-bg);color:var(--ok-fg);border-color:rgba(95,208,176,.3)}
/* ④ 末尾那个直接入口:就在这一屏里把考试日期设了 */
.cl-quick{display:flex;align-items:center;justify-content:center;gap:6px;margin:10px 16px 0;
  height:calc(42px + 4px*var(--t));border-radius:14px;border:1px solid var(--line-2);background:var(--bg);
  color:var(--accent);font-size:calc(13px*var(--f));font-weight:600;cursor:pointer}
.cl-quick:active{background:var(--accent-soft)}
/* ⑤ 自己填:label + 输入框;落盘时机是「停顿 400ms 或失焦」,不是每敲一个字 */
.cl-own .cl-field{display:block;padding:12px 16px;border-bottom:1px solid var(--line);background:var(--bg)}
.cl-own .cl-field:last-child{border-bottom:0}
.cl-fl{display:block;font-size:calc(12px*var(--f));font-weight:600;color:var(--ink2);margin-bottom:7px}
.cl-in{width:100%;height:calc(40px + 4px*var(--t));padding:0 12px;border-radius:12px;border:1px solid var(--line-2);
  background:var(--panel);color:var(--ink);font-size:calc(13px*var(--f));font-family:inherit;outline:none;box-sizing:border-box}
.cl-in:focus{border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-soft);background:var(--bg)}
.cl-in::placeholder{color:var(--ink3)}
.cl-foot{padding:16px 16px 0}
.cl-hint2{margin-top:8px;font-size:calc(12px*var(--f));color:var(--err-fg);line-height:1.6}
.elder .listblock.cl-lb .cl-row{padding-top:calc(13px + 3px*var(--t));padding-bottom:calc(13px + 3px*var(--t))}
.elder .cl-tx span{font-size:calc(11.5px*var(--f) + 1px)}
.elder .cl-fl{font-size:calc(12px*var(--f) + 1px)}




