/**
 * EdenAbacus V2 Theme - Playful Sunny Edition
 * 视觉风格：奶油黄背景 + 糖果色 3D 按钮 + 绘本风粗边框
 * 目标人群：儿童与学生，强调亲和力与快乐感。
 */

/* ══════════════════════════════════════════════
   V2 DYNAMIC THEME SYSTEM
   ═══════════════════════════════════════════════ */

:root {
    /* ── COLOUR ──────────────────────────────── */
    --v2-bg-main:       #FFF9E6;   /* page background */
    --v2-surface:       #FFFFFF;   /* card surface */
    --v2-primary:       #FF8A00;   /* orange — main accent */
    --v2-primary-dark:  #E67E00;
    --v2-secondary:     #4CAF50;   /* green — success */
    --v2-secondary-dark:#388E3C;
    --v2-accent:        #2196F3;   /* blue */
    --v2-danger:        #FF5252;   /* red */
    --v2-danger-dark:   #C62828;
    --v2-text:          #4A4A4A;   /* body text */
    --v2-text-dark:     #333333;   /* strong text */
    --v2-muted:         #9A9A9A;   /* secondary / hint text */
    --v2-green:         #4CAF50;
    --v2-green-dark:    #2E7D32;
    --v2-red:           #FF5252;
    --v2-red-dark:      #C62828;
    /* 输入类控件（步进器数值框等）专用色，深色主题需单独覆盖，
       不能直接复用 --v2-text/--v2-muted（那两个在深色主题会变成近白色，
       但输入框底色若仍是浅灰就会看不清） */
    --v2-input-bg:      #F0F2F5;
    --v2-input-text:    var(--v2-text);
    --v2-input-label:   var(--v2-muted);

    /* ── BORDER ──────────────────────────────── */
    --v2-border-main:   #E0D0B0;
    --v2-border-width:  3px;
    --v2-card-border:   var(--v2-border-width) solid var(--v2-border-main);

    /* ── SHADOW ──────────────────────────────── */
    --v2-shadow-depth:  4px;
    --v2-shadow-soft:   0 var(--v2-shadow-depth) 0 var(--v2-border-main);
    --v2-shadow-inner:  inset 0 2px 5px rgba(0, 0, 0, 0.08);
    --v2-shadow-flat:   none;

    /* ── RADIUS ──────────────────────────────── */
    --v2-radius-card:   24px;   /* large cards */
    --v2-radius-chip:   12px;   /* chips, small cards, setting cards */
    --v2-radius-btn:    20px;   /* buttons */
    --v2-radius-icon:   20px;   /* icon containers */

    /* ── TYPOGRAPHY ──────────────────────────── */
    --v2-font-main:     'Outfit', sans-serif;
    --v2-font-num:      'Outfit', sans-serif;
    --v2-size-xs:       10px;
    --v2-size-sm:       12px;
    --v2-size-md:       14px;
    --v2-size-body:     16px;
    --v2-size-lg:       18px;
    --v2-size-xl:       20px;
    --v2-size-title:    24px;
    --v2-weight-normal: 600;
    --v2-weight-bold:   800;
    --v2-weight-heavy:  900;

    /* ── INTERACTION ─────────────────────────── */
    --v2-transition:    all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    --v2-transition-fast: all 0.1s ease;
    --v2-transition-pop:  all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);

    /* ── BUTTON ──────────────────────────────── */
    --v2-btn-height:    52px;
    --v2-btn-font-size: var(--v2-size-lg);
    --v2-btn-radius:    var(--v2-radius-btn);
    --v2-btn-shadow:    0 8px 0 var(--v2-primary-dark);

    /* ── LAYOUT ──────────────────────────────── */
    --v2-gap-screen:    20px;   /* gap between cards on screen */
    --v2-gap-card:       8px;   /* gap inside a card */
    --v2-pad-card:      20px 15px;
    --v2-pad-screen:    10px 6px;
    --v2-header-height: 90px;

    /* ── LEGACY ALIASES (keep for backwards compat) ── */
    --v2-text-main:     var(--v2-text);
    --v2-card-bg:       var(--v2-surface);
    --v2-bg:            var(--v2-bg-main);
    --v2-shadow-raised: var(--v2-shadow-soft);
    --v2-glass:         none;

    /* ── MODE ICON TOKENS (sunny defaults) ──────────
       Each training mode has a bg + accent color, used by
       [data-mode=X] .v2-neu-icon rules below. Themes override
       these in their own .v2-theme-X block. */
    --v2-mode-flash-bg:     #FDF2F8;
    --v2-mode-flash-accent: #DB2777;
    --v2-mode-look-bg:      #FFF7ED;
    --v2-mode-look-accent:  #F97316;
    --v2-mode-listen-bg:    #E0F2FE;
    --v2-mode-listen-accent:#0EA5E9;
    --v2-mode-speed-bg:     #F0FDF4;
    --v2-mode-speed-accent: #16A34A;
    --v2-mode-challenge-bg:     #FEF9C3;
    --v2-mode-challenge-accent: #CA8A04;
    --v2-mode-ranking-bg:       #FEE2E2;
    --v2-mode-ranking-accent:   #DC2626;
}

/* Teacher Centre · Guided Abacus — follows the existing settings visual language. */
.tgab-shell { width:100%; max-width:1000px; }
.tgab-caption { margin-top:3px; color:var(--v2-muted); font-size:12px; font-weight:700; }
.tgab-config input { width:100%; box-sizing:border-box; padding:13px 15px; border:var(--v2-card-border); border-radius:var(--v2-radius-chip); outline:none; background:var(--v2-surface); color:var(--v2-text); box-shadow:var(--v2-shadow-inner); text-align:center; font:900 22px var(--v2-font-num); }
.tgab-config input:focus { border-color:var(--v2-primary); }
.tgab-help { color:var(--v2-muted); font-size:11px; line-height:1.55; text-align:center; }
.tgab-config .v2-start-btn,.tgab-actions .v2-start-btn { min-height:48px; margin:4px 0 var(--v2-shadow-depth); border:0; border-radius:var(--v2-radius-btn); font-weight:900; }
.tgab-practice[hidden],.tgab-config[hidden] { display:none !important; }
.tgab-practice { padding:16px 14px; }
.tgab-status-row { display:grid; grid-template-columns:1fr auto; align-items:center; gap:10px; }
.tgab-step-label { display:block; color:var(--v2-muted); font-size:10px; font-weight:800; }
.tgab-status-row strong { color:var(--v2-text); font-size:16px; }
.tgab-target { grid-column:1/-1; padding:10px 16px; border:1.5px solid color-mix(in srgb,var(--v2-primary) 28%,transparent); border-radius:var(--v2-radius-chip); background:color-mix(in srgb,var(--v2-primary) 8%,var(--v2-surface)); color:var(--v2-primary); text-align:center; font-size:22px; font-weight:900; }
.tgab-reset { justify-self:end; padding:7px 10px; border:0; background:transparent; color:var(--v2-muted); font:800 11px var(--v2-font-main); cursor:pointer; }
.tgab-progress { height:5px; margin:10px 0 14px; overflow:hidden; border-radius:99px; background:color-mix(in srgb,var(--v2-text) 9%,transparent); }
.tgab-progress i { display:block; width:0; height:100%; border-radius:inherit; background:var(--v2-primary); transition:width .3s ease; }
.tgab-board-wrap { width:min(100%,520px); margin:0 auto; }
.tgab-live-value { margin-bottom:9px; text-align:center; color:var(--v2-muted); font-size:11px; font-weight:800; }
.tgab-live-value strong { display:inline-block; margin-left:5px; min-width:36px; color:var(--v2-text); font-size:18px; }
#tgab-board { width:min(100%,480px); margin:0 auto; }
.tgab-feedback { width:min(100%,520px); box-sizing:border-box; margin:12px auto 0; padding:9px 12px; border-radius:var(--v2-radius-chip); text-align:center; font-size:12px; font-weight:800; color:var(--v2-muted); }
.tgab-feedback[data-state="success"] { color:var(--v2-secondary-dark); background:color-mix(in srgb,var(--v2-secondary) 11%,var(--v2-surface)); }
.tgab-feedback[data-state="error"] { color:var(--v2-danger-dark); background:color-mix(in srgb,var(--v2-danger) 9%,var(--v2-surface)); }
.tgab-actions { width:min(100%,520px); margin:10px auto 0; display:grid; grid-template-columns:1fr 2fr; gap:10px; align-items:start; }
.tgab-clear { min-height:48px; padding:10px; border:var(--v2-card-border); border-radius:var(--v2-radius-btn); background:var(--v2-surface); color:var(--v2-text); box-shadow:var(--v2-shadow-soft); font:900 13px var(--v2-font-main); cursor:pointer; }

/* 点名的「全部出席/全部缺席」：不加这条会掉进 .v2-content button 的全局主按钮样式，
   变成两块和「保存点名」一样醒目的大橙块，喧宾夺主(实测截图确认)。 */
.tatt-bulk { flex:1; min-height:38px; padding:8px 10px; border:var(--v2-card-border); border-radius:var(--v2-radius-chip); background:var(--v2-surface); color:var(--v2-muted); box-shadow:none; font:800 12px var(--v2-font-main); cursor:pointer; }
.tatt-bulk:active { transform:translateY(1px); }
.guided-step-chip { padding:8px 14px; border:1.5px solid color-mix(in srgb,var(--v2-primary) 35%,transparent); border-radius:var(--v2-radius-chip); background:color-mix(in srgb,var(--v2-primary) 8%,var(--v2-surface)); color:var(--v2-primary); text-align:center; font-size:14px; font-weight:900; }
.guided-step-feedback { min-height:20px; color:var(--v2-muted); text-align:center; font-size:11px; font-weight:800; }
/* 无内容时彻底不占位 —— min-height:20px 会让空元素照样吃掉一行，
   而这一屏不滚动，省下的每一 px 都直接给算盘/题目。
   (静态提示已去掉，只在拨错/判断中才有文字，见 GuidedAbacusEngineV2) */
.guided-step-feedback:empty { min-height:0; display:none; }
.guided-step-feedback[data-state="error"] { color:var(--v2-danger-dark); }
.guided-step-feedback[data-state="success"] { color:var(--v2-secondary-dark); }
.guided-current-line { color:var(--v2-primary) !important; filter:drop-shadow(0 3px 0 color-mix(in srgb,var(--v2-primary) 15%,transparent)); }

/* ── 指法示范：高亮「接下来该拨哪颗珠」 ──────────────────────────
   ⚠️ 不可用 transform 做效果：珠子的靠梁/离梁位移本身就走 transform
   (.abv2-on)，在这里再写一次会把珠子挪回原位、看起来像没拨动。
   故只用 outline + box-shadow 光环 —— 两者都不参与布局也不覆盖 transform。

   圈一律用亮黄：珠子本身是主色(蓝紫)，黄色是它的对比色，在深浅两种珠面上
   都跳得出来；绿/红试过——绿圈贴着蓝珠不够醒目，且红色在这里像「错了」，
   而这只是提示该拨哪颗，不带对错含义。
   方向不靠颜色区分，改用箭头(▲靠梁 / ▼离梁)标在圈上，色盲也读得出。 */
.guided-fingering-hint { text-align:center; font-size:12px; font-weight:900; color:var(--v2-primary); padding:2px 0 4px; }
/* [hidden] 在 flex 容器里会被 display:flex 覆盖而照样显示 —— 必须显式收掉，
   否则「只在拨错时显示」的逻辑等于没做，padding 也继续占高度。 */
.guided-fingering-hint[hidden], .guided-fingering-hint:empty { display:none; padding:0; }

/* 拨错提示改成「浮在算盘上方」而不是插进竖排里。
   ⚠️ 它们是临时状态(拨错才出现)，若参与布局就必须常驻预算 42px；
   可这一屏不滚动，常驻等于永久牺牲算盘/题目 —— 而真出现时又会把按钮
   顶出屏幕(实测 5 个尺寸出线 9~27px)。浮层两头兼顾：常态零占位，
   出现时也不推动任何东西。 */
.guided-abacus-wrap .abv2-answer-area { position: relative; }
.guided-abacus-wrap .guided-fingering-hint:not([hidden]),
.guided-abacus-wrap .guided-step-feedback:not(:empty) {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    padding: 3px 10px;
    border-radius: var(--v2-radius-chip, 12px);
    background: color-mix(in srgb, var(--v2-surface) 92%, transparent);
    box-shadow: 0 1px 6px rgba(0,0,0,0.12);
    white-space: nowrap;
    pointer-events: none;
}
/* 指法提示贴 chip 下方，判断/纠错反馈贴按钮上方，互不遮挡 */
.guided-abacus-wrap .guided-fingering-hint:not([hidden]) { top: 40px; }
.guided-abacus-wrap .guided-step-feedback:not(:empty) { bottom: 46px; }
/* 拨错后的「拨回来」提示：换暖色，跟正常口诀区分开 —— 学生要能看出
   这不是原来那句口诀，而是纠错的走法 */
.guided-fingering-hint[data-offtrack="1"] { color:var(--v2-danger-dark, #b4341f); }
.abv2-bead.abv2-hint-on,
.abv2-bead.abv2-hint-off {
    outline:3px solid var(--abv2-hint, #ffc21a);
    outline-offset:2px;
    animation:abv2HintPulse 1.1s ease-in-out infinite;
}
/* 方向箭头：贴在珠子外侧，不占布局(绝对定位)，不挡触控(pointer-events:none)。
   ⚠️ 箭头自己带 translateX(-50%) 居中，做位移动画时必须把它写进每一帧的
   transform 里，否则一动就往右偏半个字宽。故 keyframes 用完整的
   translate(-50%, Npx) 而不是只写 translateY —— 后者会整个覆盖掉居中量。 */
.abv2-bead.abv2-hint-on::before,
.abv2-bead.abv2-hint-off::before {
    content:'▲';
    position:absolute;
    left:50%;
    transform:translateX(-50%);
    font-size:calc(var(--abv2-b) * 0.5);
    line-height:1;
    color:var(--abv2-hint, #ffc21a);
    text-shadow:0 0 3px rgba(0,0,0,0.5);
    pointer-events:none;
    z-index:3;
    animation:abv2ArrowNudgeUp 1.1s ease-in-out infinite;
}
/* 靠梁=往梁的方向走；上珠往下、下珠往上 —— 箭头跟着珠子实际移动方向 */
.abv2-deck-upper .abv2-bead.abv2-hint-on::before  { content:'▼'; bottom:calc(var(--abv2-b) * -0.72); animation-name:abv2ArrowNudgeDown; }
.abv2-deck-lower .abv2-bead.abv2-hint-on::before  { content:'▲'; top:calc(var(--abv2-b) * -0.72); animation-name:abv2ArrowNudgeUp; }
/* 离梁=离开梁；上珠往上、下珠往下 */
.abv2-deck-upper .abv2-bead.abv2-hint-off::before { content:'▲'; top:calc(var(--abv2-b) * -0.72); animation-name:abv2ArrowNudgeUp; }
.abv2-deck-lower .abv2-bead.abv2-hint-off::before { content:'▼'; bottom:calc(var(--abv2-b) * -0.72); animation-name:abv2ArrowNudgeDown; }

/* 箭头轻推：朝该拨的方向来回小幅移动，把「往哪拨」演出来而不只是标出来。
   幅度刻意小(0.28 珠高)——大了会跟珠子本身的靠梁动画抢视线。 */
@keyframes abv2ArrowNudgeUp {
    0%,100% { transform:translate(-50%, 0); opacity:.75; }
    50%     { transform:translate(-50%, calc(var(--abv2-b) * -0.28)); opacity:1; }
}
@keyframes abv2ArrowNudgeDown {
    0%,100% { transform:translate(-50%, 0); opacity:.75; }
    50%     { transform:translate(-50%, calc(var(--abv2-b) * 0.28)); opacity:1; }
}

/* 幽灵珠：在珠子「该去的位置」画一个半透明轮廓，并让它循环走一遍全程。
   这是最接近老师示范的一层 —— 不只说该动哪颗，而是把这颗珠子要走的路演出来。
   ⚠️ 珠子本体的 transform 归 .abv2-on 管(靠梁位移)，绝不能在这里碰；
   幽灵是独立的 ::after 图层，走自己的 transform，两者互不干扰。
   ::after 原本是触控热区(inset:-4px)，这里只在有提示时改写它的外观，
   不改 inset —— 热区照常，点得到。 */
.abv2-bead.abv2-hint-on::after,
.abv2-bead.abv2-hint-off::after {
    border-radius:50%;
    border:2px dashed var(--abv2-hint, #ffc21a);
    opacity:0;
    /* ⚠️ 这里绝不能加 pointer-events:none：::after(inset:-4px) 是珠子在手机上的
       扩大触控热区(珠高才 ~20px)，命中判定靠 e.target.closest('.abv2-bead')，
       伪元素的事件本来就归宿主珠子。设 none 会把热区缩回珠子本体，
       正好在「有提示时」变得更难点 —— 提示越有用的时候越点不中。 */
}
.abv2-deck-lower .abv2-bead.abv2-hint-on::after  { animation:abv2GhostLowerOn  1.6s ease-in-out infinite; }
.abv2-deck-lower .abv2-bead.abv2-hint-off::after { animation:abv2GhostLowerOff 1.6s ease-in-out infinite; }
.abv2-deck-upper .abv2-bead.abv2-hint-on::after  { animation:abv2GhostUpperOn  1.6s ease-in-out infinite; }
.abv2-deck-upper .abv2-bead.abv2-hint-off::after { animation:abv2GhostUpperOff 1.6s ease-in-out infinite; }

/* 下珠靠梁：从当前位往上走一个下珠行程 */
@keyframes abv2GhostLowerOn {
    0%      { transform:translateY(0); opacity:0; }
    15%     { opacity:.85; }
    70%,100%{ transform:translateY(calc(var(--abv2-tl) * -1)); opacity:0; }
}
/* 下珠离梁：往下走 */
@keyframes abv2GhostLowerOff {
    0%      { transform:translateY(0); opacity:0; }
    15%     { opacity:.85; }
    70%,100%{ transform:translateY(var(--abv2-tl)); opacity:0; }
}
/* 上珠靠梁：往下走一个上珠行程 */
@keyframes abv2GhostUpperOn {
    0%      { transform:translateY(0); opacity:0; }
    15%     { opacity:.85; }
    70%,100%{ transform:translateY(var(--abv2-tu)); opacity:0; }
}
/* 上珠离梁：往上走 */
@keyframes abv2GhostUpperOff {
    0%      { transform:translateY(0); opacity:0; }
    15%     { opacity:.85; }
    70%,100%{ transform:translateY(calc(var(--abv2-tu) * -1)); opacity:0; }
}
@keyframes abv2HintPulse {
    0%,100% { box-shadow:inset 0 calc(var(--abv2-b) * -0.22) 0 rgba(0,0,0,0.18),
                         inset 0 calc(var(--abv2-b) * 0.16) 0 rgba(255,255,255,0.35),
                         0 0 0 0 color-mix(in srgb, var(--abv2-hint, #ffc21a) 60%, transparent); }
    50%     { box-shadow:inset 0 calc(var(--abv2-b) * -0.22) 0 rgba(0,0,0,0.18),
                         inset 0 calc(var(--abv2-b) * 0.16) 0 rgba(255,255,255,0.35),
                         0 0 0 6px color-mix(in srgb, var(--abv2-hint, #ffc21a) 0%, transparent); }
}
/* 关掉动效时：全部静止，但提示本身必须还在 ——
   圈和箭头保留(箭头回到静止位、幽灵停在终点淡显)，只是不再动。 */
@media (prefers-reduced-motion:reduce) {
    .abv2-bead.abv2-hint-on, .abv2-bead.abv2-hint-off,
    .abv2-bead.abv2-hint-on::before, .abv2-bead.abv2-hint-off::before,
    .abv2-bead.abv2-hint-on::after, .abv2-bead.abv2-hint-off::after { animation:none; }
    .abv2-bead.abv2-hint-on::before, .abv2-bead.abv2-hint-off::before { opacity:1; }
    .abv2-bead.abv2-hint-on::after, .abv2-bead.abv2-hint-off::after { opacity:.5; }
}
.guided-abacus-wrap .abv2-answer-actions { justify-content:center; flex-wrap:wrap; gap:8px; }
.guided-abacus-wrap .abv2-btn-clear { min-width:110px; }
/* 「示范一次」是这一屏的主动作(不会了就按它)，用主色实底跟两个次要按钮拉开 */
.guided-abacus-wrap .abv2-btn-demo {
    min-width:120px;
    background:var(--v2-primary);
    color:#fff;
    border-color:var(--v2-primary);
}
.guided-abacus-wrap .abv2-btn-demo.is-playing {
    opacity:.6;
    pointer-events:none;   /* 演示中不可重复点，否则两条计时器互相打架 */
}
/* 示范中把珠子滑行放慢：平时 0.12s 是为了跟手(手指拨珠必须即时响应)，
   但那个速度小孩看不清珠子从哪走到哪。只在示范期间加长，
   靠 body 上的 .guided-demoing 开关 —— 学生自己拨珠时依旧是 0.12s 跟手。 */
body.guided-demoing .guided-abacus-wrap .abv2-bead {
    /* [PERF] Hardware optimized bead rendering.
       ⚠️ 不能写 transform:translateZ(0) —— 珠子移动全靠 .abv2-on 那条规则的
       transform:translateY(...)，两条规则 transform 只能留一个值生效，
       而这条 specificity 更高(body+wrap+bead 三层)会把 translateY 吃掉，
       示范时珠子在 Android WebView 上直接钉死不动(手机 APK 实测踩过)。
       改用 will-change 达到同样的建层效果，不占 transform 这个属性。 */
    contain: layout style;
    will-change: transform;
    backface-visibility: hidden;
    transition:transform 0.45s cubic-bezier(0.34, 1.12, 0.64, 1);
}

/* Homework feedback overlay — spacious desktop layout, compact mobile flow */
.v2-feedback-overlay {
  padding: 18px;
  box-sizing: border-box;
  overflow: hidden;
  animation: feedback-fade-in .18s ease-out;
}
.v2-feedback-card {
  width: min(720px, 100%) !important;
  max-width: 720px !important;
  max-height: calc(100dvh - 36px);
  padding: 22px !important;
  gap: 14px !important;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--v2-border-main) transparent;
  box-shadow: 0 24px 70px rgba(15, 23, 42, .3), 0 6px 0 var(--v2-border-main) !important;
  animation: feedback-card-in .22s cubic-bezier(.2,.8,.2,1);
}
.v2-feedback-card::-webkit-scrollbar { width: 7px; }
.v2-feedback-card::-webkit-scrollbar-thumb {
  background: var(--v2-border-main);
  border-radius: 999px;
}
.v2-feedback-head {
  position: sticky;
  top: -22px;
  z-index: 3;
  margin: -22px -22px 0;
  padding: 20px 22px 14px;
  background: linear-gradient(180deg, #fff 80%, rgba(255,255,255,.9));
}
.v2-feedback-head h3 { font-size: 20px !important; }
.v2-feedback-close {
  flex: 0 0 auto;
  padding: 0;
  transition: transform .15s ease, background .15s ease;
}
.v2-feedback-close:hover { background: #fff7ed !important; transform: rotate(6deg); }
.v2-feedback-close:focus-visible,
.feedback-sticker-btn:focus-visible,
.v2-feedback-comment:focus-visible {
  outline: 3px solid rgba(249, 115, 22, .25) !important;
  outline-offset: 2px;
}
.v2-feedback-meta {
  padding: 9px 12px;
  border-radius: var(--v2-radius-chip);
  background: color-mix(in srgb, var(--v2-primary) 8%, var(--v2-surface));
  border: 2px solid var(--v2-border-main);
}
.v2-feedback-stickers {
  grid-template-columns: 1fr !important;
  gap: 12px !important;
}
.feedback-sticker-btn {
  min-height: 66px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  font-family: inherit;
  color: var(--v2-text-dark) !important;
  box-shadow: 0 4px 0 var(--v2-border-main) !important;
  transition: var(--v2-transition-fast) !important;
}
.feedback-sticker-btn:hover {
  transform: translateY(-2px);
  border-color: var(--v2-primary) !important;
}
.feedback-sticker-btn.is-selected {
  background: color-mix(in srgb, var(--v2-primary) 13%, var(--v2-surface)) !important;
  border-color: var(--v2-primary) !important;
  color: var(--v2-primary-dark) !important;
  box-shadow: 0 5px 0 var(--v2-primary-dark) !important;
  transform: translateY(-2px);
}
.feedback-sticker-name { font-size: 13px; }
.v2-feedback-templates {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px !important;
}
.v2-feedback-comment {
  min-height: 92px;
  height: 92px !important;
  line-height: 1.55;
}
/* 底色跟随 --v2-input-bg 变深色主题时，浏览器默认 placeholder 灰字会糊掉，需单独指定 */
.v2-feedback-comment::placeholder {
  color: var(--v2-input-label);
  opacity: 1;
}
.v2-feedback-points-row {
  padding: 12px;
  border: 1px solid var(--v2-border-main);
  border-radius: 14px;
  background: var(--v2-input-bg);
}
.v2-feedback-actions {
  display: grid !important;
  grid-template-columns: 1.35fr 1fr;
  align-items: stretch;
  gap: 12px !important;
  margin-top: 2px !important;
}
.v2-feedback-actions > * {
  min-height: 50px;
  padding-inline: 16px !important;
}
@keyframes feedback-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes feedback-card-in {
  from { opacity: 0; transform: translateY(12px) scale(.985); }
  to { opacity: 1; transform: none; }
}
@media (max-width: 560px) {
  .v2-feedback-overlay {
    align-items: flex-end !important;
    padding: 8px !important;
  }
  .v2-feedback-card {
    width: 100% !important;
    max-height: calc(100dvh - 16px);
    padding: 17px !important;
    gap: 12px !important;
    border-radius: 20px !important;
  }
  .v2-feedback-head {
    top: -17px;
    margin: -17px -17px 0;
    padding: 16px 17px 12px;
  }
  .v2-feedback-head h3 { font-size: 17px !important; }
  .v2-feedback-stickers { grid-template-columns: 1fr !important; gap: 7px !important; }
  .feedback-sticker-btn { min-height: 58px; padding: 8px !important; }
  .v2-feedback-templates { grid-template-columns: 1fr; }
  .v2-feedback-actions { grid-template-columns: 1fr; }
}

/* 批改中心 4 个 tab（待批改/进行中/已批改/全部）右上角数量徽章。
   颜色跟随按钮自身 color（inline style 在 switchGradingTab() 里切换），
   不写死颜色，否则未选中的灰色 tab 上徽章会跟激活态一样显眼。 */
.v2-grading-tab-count {
  font-size: 11px;
  font-weight: 900;
  opacity: 0.75;
}

/* Homework grading filters — compact, horizontally scrollable chips */
.v2-grading-filter-panel {
  width: 100%;
  max-width: 1000px;
  min-width: 0;
  margin: 0 auto 12px;
  padding: 14px;
  border: 2px solid var(--v2-border-main);
  border-radius: 20px;
  background: color-mix(in srgb, var(--v2-primary) 4%, var(--v2-surface));
  box-shadow: 0 4px 0 var(--v2-border-main);
  box-sizing: border-box;
}
.v2-grading-filter-panel > div + div {
  margin-top: 13px;
  padding-top: 13px;
  border-top: 2px dashed var(--v2-border-main);
}
.v2-grading-filter-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.v2-grading-filter-head strong {
  /* ⚠️ .v2-grading-filter-panel 底色固定近白，字色不能用深色主题下
     会变近白的 --v2-text-dark，否则星河等主题下浅底浅字看不见 */
  color: #1F2937;
  font-size: 13px;
  font-weight: 900;
}
.v2-grading-filter-head span {
  color: #6B7280;
  font-size: 10px;
  font-weight: 800;
}
@media (max-width: 560px) {
  .v2-grading-filter-panel {
    margin-inline: -2px;
    padding: 12px;
    border-radius: 17px;
  }
}
@media (max-width: 700px) {
  .v2-grading-filter-panel {
    padding: 12px;
    border-radius: 17px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .v2-feedback-overlay,
  .v2-feedback-card { animation: none; }
}
.v2-feedback-inline {
  width: 100%;
  margin: 0;
  scroll-margin-top: 16px;
  box-sizing: border-box;
  font-family: var(--v2-font-main);
  animation: feedback-card-in .22s cubic-bezier(.2,.8,.2,1);
}
.v2-feedback-mode > :not(.v2-feedback-inline) {
  display: none !important;
}
.v2-feedback-workspace-bar {
  width: 100%;
  max-width: 860px;
  margin: 0 auto 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  box-sizing: border-box;
}
.v2-feedback-workspace-bar button {
  width: auto !important;
  min-width: 0 !important;
  height: auto !important;
  flex: 0 0 auto;
  display: inline-flex !important;
  align-items: center;
  gap: 5px;
  margin: 0 !important;
  padding: 9px 14px !important;
  border: 2px solid var(--v2-border-main) !important;
  border-radius: var(--v2-radius-chip) !important;
  background: var(--v2-surface) !important;
  color: var(--v2-text-dark) !important;
  box-shadow: 0 3px 0 var(--v2-border-main) !important;
  font-family: inherit !important;
  font-size: 12px !important;
  font-weight: 900 !important;
  line-height: 1.2 !important;
  cursor: pointer;
}
.v2-feedback-workspace-bar button:hover {
  border-color: var(--v2-primary);
  color: var(--v2-primary-dark);
}
.v2-feedback-workspace-bar button span {
  color: var(--v2-muted);
  font-size: 10px;
}
.v2-feedback-workspace-bar > div {
  flex: 1 1 auto;
  min-width: 0;
  text-align: right;
}
.v2-feedback-workspace-bar > div span {
  display: block;
  color: var(--v2-primary);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .08em;
}
.v2-feedback-workspace-bar > div strong {
  display: block;
  overflow: hidden;
  color: var(--v2-text-dark);
  font-size: 14px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.v2-feedback-inline .v2-feedback-card {
  width: 100% !important;
  max-width: 860px !important;
  max-height: none;
  margin: 0 auto;
  overflow: visible;
  background: var(--v2-surface) !important;
  box-shadow: 0 6px 0 var(--v2-border-main) !important;
}
.v2-feedback-inline .v2-feedback-head {
  position: static;
  display: block !important;
}
.v2-feedback-inline .v2-feedback-head::before {
  display: none;
}
.v2-feedback-inline .v2-feedback-head h3 {
  min-width: 0;
  text-align: center;
}
@media (max-width: 560px) {
  .v2-feedback-inline {
    margin-top: 2px;
  }
  .v2-feedback-workspace-bar {
    align-items: flex-start;
  }
  .v2-feedback-workspace-bar > div {
    text-align: left;
  }
  .v2-feedback-workspace-bar > div strong {
    max-width: 48vw;
  }
  .v2-feedback-inline .v2-feedback-card {
    max-height: none;
    border-radius: var(--v2-radius-card) !important;
  }
}

/* 1. Playful Sunny (Default) */
.v2-theme-sunny {
    --v2-bg-main: #FFF9E6;
    --v2-primary: #FF8A00;
    --v2-border-main: #E0D0B0;
    --v2-font-num: 'Outfit', sans-serif;
    /* 大数字：橙红实色 + 轻奶油描边，配奶油黄背景 */
    --v2-display-color: #E65100;
    --v2-display-glow: 0 2px 0 rgba(255, 138, 0, 0.18);
    --v2-display-divider: #E67E00;
}

/* 2. Modern Premium (Apple Style) */
.v2-theme-modern {
    --v2-bg-main: #F2F2F7;
    --v2-primary: #007AFF;
    --v2-primary-dark: #0051D5;
    --v2-secondary: #34C759;
    --v2-border-main: rgba(0,0,0,0.1);
    --v2-card-bg: rgba(255, 255, 255, 0.85);
    --v2-text-main: #1C1C1E;
    --v2-card-border: 1px solid rgba(0,0,0,0.1);
    --v2-shadow-soft: 0 10px 30px rgba(0, 0, 0, 0.08);
    --v2-btn-shadow: 0 8px 0 #0051D5;
    --v2-glass: blur(20px);
    --v2-font-num: 'Montserrat', sans-serif; /* 现代感字体 */
    /* Cool/neutral palette: cyan, indigo, magenta, lime, teal, blue */
    --v2-mode-flash-bg:     #E0F7FA; --v2-mode-flash-accent:     #00ACC1;
    --v2-mode-look-bg:      #F3E5F5; --v2-mode-look-accent:      #8E24AA;
    --v2-mode-listen-bg:    #E8EAF6; --v2-mode-listen-accent:    #3949AB;
    --v2-mode-speed-bg:     #F1F8E9; --v2-mode-speed-accent:     #689F38;
    --v2-mode-challenge-bg: #FFF8E1; --v2-mode-challenge-accent: #F57C00;
    --v2-mode-ranking-bg:   #FCE4EC; --v2-mode-ranking-accent:   #D81B60;
    /* 大数字：深石板色 + 极轻阴影，干净 Apple 风 */
    --v2-display-color: #1C1C1E;
    --v2-display-glow: 0 1px 2px rgba(0, 0, 0, 0.12);
    --v2-display-divider: #007AFF;
}

/* 3. Space Adventure (Neon Style) */
.v2-theme-space {
    --v2-bg-main: #0B0E14;
    --v2-primary: #BB86FC;
    --v2-primary-dark: #7C4DFF;
    --v2-secondary: #03DAC6;
    --v2-border-main: #BB86FC;
    --v2-card-bg: #1E1E1E;
    /* ⚠️ .v2-neu-key（数字键盘等）直接读 --v2-surface 当背景，不是 --v2-card-bg。
       漏覆盖就会沿用浅色主题默认的纯白 #FFFFFF，配上下面已改近白的 --v2-text
       就是白底白字（数字键盘看不清）。跟 --v2-card-bg 保持一致。 */
    --v2-surface: #1E1E1E;
    /* ⚠️ 正误反馈提示/笔算输入框文字色也要一起覆盖：默认值是给浅色卡片配的
       暗红/暗绿/宝蓝，配上面已改深的 --v2-surface 卡片背景，对比度会明显
       变差。换成同色系里更亮更饱和的版本，深色底上依旧清晰。 */
    --v2-secondary-dark: #22E5C7;
    --v2-danger: #FF6B6B;
    --v2-danger-dark: #FF8A8A;
    --v2-accent: #64B5F6;
    --v2-text-main: #E0E0E0;
    --v2-text-dark: #F5F0FF; /* 深色底上的标题等通用文字 */
    /* .v2-neu-title 等大量组件直接读 --v2-text（不是 --v2-text-dark），
       深色卡片主题必须一并覆盖，否则标题文字沿用默认深灰糊底看不清
       （同 moonlight 主题踩过的坑，见上方 moonlight 注释） */
    --v2-text: #F5F0FF;
    --v2-muted: #9AA3B8;
    --v2-card-border: 2px solid var(--v2-primary);
    /* 大数字：紫白霓虹 + 紫青双层辉光 */
    --v2-display-color: #F5F0FF;
    --v2-display-glow:
        0 0 12px rgba(187, 134, 252, 0.85),
        0 0 28px rgba(187, 134, 252, 0.55),
        0 0 60px rgba(3, 218, 198, 0.35);
    --v2-display-divider: #03DAC6;
    --v2-display-divider-glow: 0 0 10px rgba(3, 218, 198, 0.7);
    --v2-shadow-soft: 0 0 20px rgba(187, 134, 252, 0.3);
    --v2-btn-shadow: 0 8px 0 #7C4DFF;
    /* 科技感等宽字体。原为 'Space Mono'，但那个字体从未出现在 index.html 的
       Google Fonts 请求里 —— 一直静默回退到系统 monospace，各手机长相不一。
       改用已请求的 JetBrains Mono：同为等宽，零新增下载。 */
    --v2-font-num: 'JetBrains Mono', monospace;
    /* Deep neon panels — dark bg, glowing accents */
    --v2-mode-flash-bg:     #1A1033; --v2-mode-flash-accent:     #BB86FC;
    --v2-mode-look-bg:      #001A1F; --v2-mode-look-accent:      #03DAC6;
    --v2-mode-listen-bg:    #0F1B33; --v2-mode-listen-accent:    #82B1FF;
    --v2-mode-speed-bg:     #0F1F14; --v2-mode-speed-accent:     #69F0AE;
    --v2-mode-challenge-bg: #2A1A0F; --v2-mode-challenge-accent: #FFAB40;
    --v2-mode-ranking-bg:   #2A0F1A; --v2-mode-ranking-accent:   #FF80AB;
    /* 步进器数值框：深色主题不能沿用浅灰底+深灰字，否则文字看不清 */
    --v2-input-bg: #12131C;
    --v2-input-text: #F5F0FF;
    --v2-input-label: #9AA3B8;
}

/* 4. Sakura (Soft Pink) */
.v2-theme-sakura {
    --v2-bg-main: #FFF0F5;
    --v2-primary: #EC4899;
    --v2-primary-dark: #BE185D;
    --v2-secondary: #F472B6;
    --v2-btn-shadow: 0 8px 0 #BE185D;
    --v2-border-main: #F9A8D4;          /* deeper pink so cards have visible outline */
    --v2-card-bg: #FFF7FB;              /* faintly tinted surface */
    --v2-card-border: var(--v2-border-width) solid #F9A8D4;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #F9A8D4;
    --v2-font-num: 'Outfit', sans-serif;
    /* Warm pastel palette tied to sakura/peach */
    --v2-mode-flash-bg:     #FCE7F3; --v2-mode-flash-accent:     #DB2777;
    --v2-mode-look-bg:      #FFE4E6; --v2-mode-look-accent:      #E11D48;
    --v2-mode-listen-bg:    #F5E1FF; --v2-mode-listen-accent:    #9333EA;
    --v2-mode-speed-bg:     #FFE4F1; --v2-mode-speed-accent:     #BE185D;
    --v2-mode-challenge-bg: #FEF3C7; --v2-mode-challenge-accent: #D97706;
    --v2-mode-ranking-bg:   #FFD8E4; --v2-mode-ranking-accent:   #BE123C;
    /* 大数字：深玫红 + 粉色柔光 */
    --v2-display-color: #9D174D;
    --v2-display-glow: 0 2px 0 rgba(244, 114, 182, 0.35), 0 0 18px rgba(236, 72, 153, 0.18);
    --v2-display-divider: #EC4899;
}

/* 5. Ocean (Cool Blue) */
.v2-theme-ocean {
    --v2-bg-main: #E0F2FE;
    --v2-primary: #0EA5E9;
    --v2-primary-dark: #0369A1;
    --v2-secondary: #06B6D4;
    --v2-btn-shadow: 0 8px 0 #0369A1;
    --v2-border-main: #7DD3FC;          /* sky-300 — visible against pale-blue page */
    --v2-card-bg: #F5FBFF;              /* cool-tinted surface */
    --v2-card-border: var(--v2-border-width) solid #7DD3FC;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #7DD3FC;
    --v2-font-num: 'Outfit', sans-serif;
    /* Aqueous palette: cyan, teal, deep blue, with seafoam accents */
    --v2-mode-flash-bg:     #CFFAFE; --v2-mode-flash-accent:     #0891B2;
    --v2-mode-look-bg:      #DBEAFE; --v2-mode-look-accent:      #2563EB;
    --v2-mode-listen-bg:    #E0E7FF; --v2-mode-listen-accent:    #4F46E5;
    --v2-mode-speed-bg:     #CCFBF1; --v2-mode-speed-accent:     #0D9488;
    --v2-mode-challenge-bg: #FEF9C3; --v2-mode-challenge-accent: #0369A1;
    --v2-mode-ranking-bg:   #BAE6FD; --v2-mode-ranking-accent:   #0C4A6E;
    /* 大数字：深海军蓝 + 青色水波柔光 */
    --v2-display-color: #0C4A6E;
    --v2-display-glow: 0 2px 0 rgba(125, 211, 252, 0.45), 0 0 20px rgba(6, 182, 212, 0.22);
    --v2-display-divider: #0EA5E9;
}

/* 6. Forest (Calm Green) */
.v2-theme-forest {
    --v2-bg-main: #ECFDF5;
    --v2-primary: #059669;
    --v2-primary-dark: #047857;
    --v2-secondary: #10B981;
    --v2-btn-shadow: 0 8px 0 #047857;
    --v2-border-main: #6EE7B7;          /* emerald-300 — visible against mint page */
    --v2-card-bg: #FFFFFF;              /* solid white for clear contrast on mint bg */
    --v2-card-border: var(--v2-border-width) solid #6EE7B7;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #6EE7B7;
    --v2-font-num: 'Outfit', sans-serif;
    /* Earthen palette: lime, leaf, moss, bark */
    --v2-mode-flash-bg:     #FEF3C7; --v2-mode-flash-accent:     #CA8A04;
    --v2-mode-look-bg:      #D1FAE5; --v2-mode-look-accent:      #047857;
    --v2-mode-listen-bg:    #DCFCE7; --v2-mode-listen-accent:    #15803D;
    --v2-mode-speed-bg:     #ECFCCB; --v2-mode-speed-accent:     #65A30D;
    --v2-mode-challenge-bg: #FFEDD5; --v2-mode-challenge-accent: #C2410C;
    --v2-mode-ranking-bg:   #FEE2E2; --v2-mode-ranking-accent:   #B91C1C;
    /* 大数字：墨绿森林色 + 嫩芽柔光 */
    --v2-display-color: #064E3B;
    --v2-display-glow: 0 2px 0 rgba(110, 231, 183, 0.5), 0 0 18px rgba(16, 185, 129, 0.2);
    --v2-display-divider: #059669;
}

/* 7. Kaamatan / 丰收节 (Sabah Harvest Festival)
   配色灵感：金黄稻穗 + 沙巴庆典红 + 椰风绿 + 竹木棕。 */
.v2-theme-harvest {
    --v2-bg-main: #FFFBEB;              /* warm rice-paper cream */
    --v2-primary: #D97706;              /* harvest amber */
    --v2-primary-dark: #B45309;
    --v2-secondary: #DC2626;            /* festival red */
    --v2-border-main: #FCD34D;          /* golden rice stalk */
    --v2-card-bg: #FFFEF7;              /* paler cream surface */
    --v2-card-border: var(--v2-border-width) solid #FCD34D;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #FCD34D;
    --v2-btn-shadow: 0 8px 0 #B45309;
    --v2-font-num: 'Outfit', sans-serif;
    /* Mode tints: gold, red, palm-green, bamboo-brown, sunset, hibiscus */
    --v2-mode-flash-bg:     #FEF3C7; --v2-mode-flash-accent:     #D97706;
    --v2-mode-look-bg:      #FEE2E2; --v2-mode-look-accent:      #DC2626;
    --v2-mode-listen-bg:    #DCFCE7; --v2-mode-listen-accent:    #15803D;
    --v2-mode-speed-bg:     #FED7AA; --v2-mode-speed-accent:     #C2410C;
    --v2-mode-challenge-bg: #FCE7F3; --v2-mode-challenge-accent: #BE185D;
    --v2-mode-ranking-bg:   #FEF9C3; --v2-mode-ranking-accent:   #A16207;
    /* 大数字：丰收红 + 金穗柔光 */
    --v2-display-color: #B91C1C;
    --v2-display-glow: 0 2px 0 rgba(252, 211, 77, 0.55), 0 0 18px rgba(217, 119, 6, 0.22);
    --v2-display-divider: #D97706;
}

/* 🎖️ 勋章专属主题 — 只能用老师赏识勋章兑换，不在积分商店出现 */
.v2-theme-galaxy {
    --v2-bg-main: #1E1B4B;              /* deep indigo night sky */
    --v2-primary: #A78BFA;             /* violet star */
    --v2-primary-dark: #7C3AED;
    --v2-secondary: #F472B6;           /* nebula pink */
    --v2-btn-shadow: 0 8px 0 #5B21B6;
    --v2-border-main: #6D5BD0;         /* visible against indigo */
    --v2-card-bg: #2A2560;             /* lighter indigo surface */
    /* ⚠️ .v2-neu-key（数字键盘等）直接读 --v2-surface，不是 --v2-card-bg，
       漏覆盖会沿用浅色主题的纯白，配上下面改深的字色就是白底白字看不清 */
    --v2-surface: #2A2560;
    /* ⚠️ 正误反馈提示/笔算输入框文字色也要一起覆盖：默认值是给浅色卡片配的
       暗红/暗绿/宝蓝，配上面已改深的 --v2-surface 卡片背景，对比度会明显
       变差。换成同色系里更亮更饱和的版本，深色底上依旧清晰。 */
    --v2-secondary-dark: #FF9ECF;
    --v2-danger: #FF6B6B;
    --v2-danger-dark: #FF8A8A;
    --v2-accent: #64B5F6;
    --v2-card-border: var(--v2-border-width) solid #6D5BD0;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #4C1D95;
    --v2-font-num: 'Outfit', sans-serif;
    /* 深色主题字色三件套要一起定义，不能只改 --v2-text：
       --v2-text-dark/--v2-muted 缺覆盖会各自沿用浅色主题的深灰默认值，
       在深色卡片背景上就会出现同一主题里几种字色深浅不一、时隐时现的问题 */
    --v2-text: #EDE9FE;                /* near-white lavender — 正文 */
    --v2-text-dark: #FFFFFF;           /* 最亮 — 大标题/强调文字 */
    --v2-muted: #A5A0C9;               /* 偏暗紫灰 — 次要/提示文字 */
    /* Cosmic palette: violet, magenta, cyan, gold star-shine */
    --v2-mode-flash-bg:     #312E81; --v2-mode-flash-accent:     #C4B5FD;
    --v2-mode-look-bg:      #3B0764; --v2-mode-look-accent:      #E879F9;
    --v2-mode-listen-bg:    #1E3A8A; --v2-mode-listen-accent:    #93C5FD;
    --v2-mode-speed-bg:     #4A044E; --v2-mode-speed-accent:     #F0ABFC;
    --v2-mode-challenge-bg: #422006; --v2-mode-challenge-accent: #FCD34D;
    --v2-mode-ranking-bg:   #083344; --v2-mode-ranking-accent:   #67E8F9;
    /* 大数字：星光紫 + 霓虹柔光 */
    --v2-display-color: #DDD6FE;
    --v2-display-glow: 0 2px 0 rgba(124, 58, 237, 0.6), 0 0 22px rgba(167, 139, 250, 0.45);
    --v2-display-divider: #A78BFA;
    /* 步进器数值框：--v2-text 已改成近白色，若数值框底色仍是浅灰会看不清 */
    --v2-input-bg: #1E1B4B;
    --v2-input-text: #EDE9FE;
    --v2-input-label: #A5A0C9;
}

.v2-theme-candy {
    --v2-bg-main: #FFF1F8;              /* bubblegum cream */
    --v2-primary: #F43F5E;             /* strawberry */
    --v2-primary-dark: #BE123C;
    --v2-secondary: #FB923C;           /* orange-cream */
    --v2-btn-shadow: 0 8px 0 #BE123C;
    --v2-border-main: #FDA4AF;         /* candy pink outline */
    --v2-card-bg: #FFFAFC;             /* faint pink surface */
    --v2-card-border: var(--v2-border-width) solid #FDA4AF;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #FDA4AF;
    --v2-font-num: 'Outfit', sans-serif;
    /* Sweets palette: strawberry, lime, grape, lemon, mint */
    --v2-mode-flash-bg:     #FFE4E6; --v2-mode-flash-accent:     #E11D48;
    --v2-mode-look-bg:      #FCE7F3; --v2-mode-look-accent:      #DB2777;
    --v2-mode-listen-bg:    #EDE9FE; --v2-mode-listen-accent:    #7C3AED;
    --v2-mode-speed-bg:     #DCFCE7; --v2-mode-speed-accent:     #16A34A;
    --v2-mode-challenge-bg: #FEF9C3; --v2-mode-challenge-accent: #CA8A04;
    --v2-mode-ranking-bg:   #FFEDD5; --v2-mode-ranking-accent:   #EA580C;
    /* 大数字：草莓红 + 糖果柔光 */
    --v2-display-color: #E11D48;
    --v2-display-glow: 0 2px 0 rgba(253, 164, 175, 0.6), 0 0 18px rgba(244, 63, 94, 0.25);
    --v2-display-divider: #F43F5E;
}

.v2-theme-moonlight {
    --v2-bg-main: #0B1120;              /* deep night blue */
    --v2-primary: #F59E0B;             /* full moon gold */
    --v2-primary-dark: #B45309;
    --v2-secondary: #38BDF8;           /* starlight cyan */
    --v2-btn-shadow: 0 8px 0 #78350F;
    --v2-border-main: #1E293B;
    --v2-card-bg: #1E293B;             /* dark slate surface */
    /* ⚠️ .v2-neu-key（数字键盘等）直接读 --v2-surface，不是 --v2-card-bg，
       漏覆盖会沿用浅色主题的纯白，配上下面改深的字色就是白底白字看不清 */
    --v2-surface: #1E293B;
    /* ⚠️ 正误反馈提示/笔算输入框文字色也要一起覆盖：默认值是给浅色卡片配的
       暗红/暗绿/宝蓝，配上面已改深的 --v2-surface 卡片背景，对比度会明显
       变差。换成同色系里更亮更饱和的版本，深色底上依旧清晰。 */
    --v2-secondary-dark: #7DD3FC;
    --v2-danger: #FF6B6B;
    --v2-danger-dark: #FF8A8A;
    --v2-accent: #64B5F6;
    --v2-card-border: var(--v2-border-width) solid #334155;
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #020617;
    --v2-font-num: 'Outfit', sans-serif;
    --v2-mode-flash-bg:     #1E1B4B; --v2-mode-flash-accent:     #FBBF24;
    --v2-mode-look-bg:      #172554; --v2-mode-look-accent:      #60A5FA;
    --v2-mode-listen-bg:    #2E1065; --v2-mode-listen-accent:    #C084FC;
    --v2-mode-speed-bg:     #064E3B; --v2-mode-speed-accent:     #34D399;
    --v2-mode-challenge-bg: #451A03; --v2-mode-challenge-accent: #F59E0B;
    --v2-mode-ranking-bg:   #312E81; --v2-mode-ranking-accent:   #818CF8;
    --v2-display-color: #FEF08A;
    --v2-display-glow: 0 2px 0 rgba(180, 83, 9, 0.6), 0 0 22px rgba(253, 224, 71, 0.4);
    --v2-display-divider: #F59E0B;
    /* 步进器数值框：深夜蓝主题不能沿用浅灰底，否则数字发灰糊在一起 */
    --v2-input-bg: #0B1120;
    --v2-input-text: #F1F5F9;
    --v2-input-label: #94A3B8;
    /* ⚠️ 深色卡片背景(--v2-card-bg: #1E293B)必须配套覆盖字色三件套，
       否则各组件各读各的默认深灰色变量，糊在深色底上看不清
       (症状：模式选择格子的"闪算/看算/听算..."标题发暗)。 */
    --v2-text: #F1F5F9;         /* 正文 */
    --v2-text-dark: #FFFFFF;    /* 最亮 — 大标题/强调文字 */
    --v2-muted: #94A3B8;        /* 次要/提示文字 */
}

/* 🎃 11. 经典万圣夜 (Classic Spooky Halloween / Jack-o'-Lantern) */
.v2-theme-halloween {
    --v2-bg-main: #180828;              /* 深夜暗紫黑背景 */
    --v2-surface: #261238;              /* 暗紫卡片表面 */
    --v2-card-bg: #261238;              /* 暗紫卡片底色 */
    --v2-primary: #F97316;              /* 南瓜亮橙主色 */
    --v2-primary-dark: #C2410C;         /* 深南瓜橙 */
    --v2-secondary: #10B981;            /* 幽灵青绿 */
    --v2-secondary-dark: #059669;
    --v2-btn-shadow: 0 8px 0 #7C2D12;   /* 南瓜焦褐厚重立体阴影 */
    --v2-border-main: #EA580C;          /* 亮橙主边框 */
    --v2-card-border: var(--v2-border-width) solid #581C87; /* 幽秘巫师紫卡片边框 */
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #0D0316;   /* 深夜暗影 */
    --v2-font-num: 'Outfit', sans-serif;

    /* 模式格子配色：深色神秘背景 + 万圣霓虹高光 */
    --v2-mode-flash-bg:     #3B0764; --v2-mode-flash-accent:     #F97316;  /* 闪算：幽暗紫 + 亮橙 */
    --v2-mode-look-bg:      #064E3B; --v2-mode-look-accent:      #34D399;  /* 看算：幽灵深绿 + 荧光青绿 */
    --v2-mode-listen-bg:    #2E1065; --v2-mode-listen-accent:    #C084FC;  /* 听算：女巫魔药紫 + 浅紫 */
    --v2-mode-speed-bg:     #431407; --v2-mode-speed-accent:     #FB923C;  /* 速算：赤褐暗夜 + 炽燃橙 */
    --v2-mode-challenge-bg: #451A03; --v2-mode-challenge-accent: #FBBF24;  /* 闯关：古堡金褐 + 烛火金黄 */
    --v2-mode-ranking-bg:   #1F1538; --v2-mode-ranking-accent:   #F43F5E;  /* 榜单：血夜暗紫 + 猩红 */

    /* 大数字与珠算核心：亮黄南瓜烛光 + 橙色双重外发光 */
    --v2-display-color: #FEF08A;
    --v2-display-glow: 0 2px 0 rgba(194, 65, 12, 0.7), 0 0 22px rgba(249, 115, 22, 0.55), 0 0 45px rgba(254, 240, 138, 0.35);
    --v2-display-divider: #F97316;
    --v2-display-divider-glow: 0 0 12px rgba(249, 115, 22, 0.8);

    /* 步进器数值框与输入框 */
    --v2-input-bg: #180828;
    --v2-input-text: #FEF08A;
    --v2-input-label: #C084FC;

    /* 深色卡片字色三件套：确保高对比度清晰易读 */
    --v2-text: #F8FAFC;         /* 正文纯亮白 */
    --v2-text-dark: #FFFFFF;    /* 大标题最亮纯白 */
    --v2-muted: #C084FC;        /* 次要/提示：幽秘荧光紫 */

    /* 背景星火点阵 */
    --v2-dot-color: rgba(249, 115, 22, 0.16);
    --v2-dot-size: 32px;
}

/* 🪔 12. 璀璨万灯 (Deepavali / Festival of Lights) */
.v2-theme-deepavali {
    --v2-bg-main: #1F082E;              /* 皇家暗夜紫罗兰底色 */
    --v2-surface: #331048;              /* 宫廷宝石紫卡片表面 */
    --v2-card-bg: #331048;              /* 宫廷宝石紫卡片底色 */
    --v2-primary: #F59E0B;              /* 璀璨油灯金黄主色 */
    --v2-primary-dark: #B45309;         /* 浓郁古铜金 */
    --v2-secondary: #14B8A6;            /* 孔雀翠羽青绿 */
    --v2-secondary-dark: #2DD4BF;       /* 深色底高对比度亮翠绿 */
    --v2-danger: #FB7185;               /* 深色底高对比度莲华珊瑚红 */
    --v2-danger-dark: #FDA4AF;
    --v2-accent: #F472B6;               /* 兰戈丽莲花粉高光 */
    --v2-btn-shadow: 0 8px 0 #78350F;   /* 金色立体厚重阴影 */
    --v2-border-main: #D97706;          /* 皇家金主边框 */
    --v2-card-border: var(--v2-border-width) solid #701A75; /* 瑰丽紫红宝石卡片边框 */
    --v2-shadow-soft: 0 var(--v2-shadow-depth) 0 #0F0318;   /* 深邃暗影 */
    --v2-font-num: 'Outfit', sans-serif;

    /* 模式格子配色：深邃宫廷背景 + 万灯节璀璨霓虹高光 */
    --v2-mode-flash-bg:     #4A044E; --v2-mode-flash-accent:     #FBBF24;  /* 闪算：皇室紫红 + 烛火亮金 */
    --v2-mode-look-bg:      #064E3B; --v2-mode-look-accent:      #2DD4BF;  /* 看算：孔雀深翠 + 翡翠青绿 */
    --v2-mode-listen-bg:    #3B0764; --v2-mode-listen-accent:    #F472B6;  /* 听算：深邃紫晶 + 莲华亮粉 */
    --v2-mode-speed-bg:     #451A03; --v2-mode-speed-accent:     #FB923C;  /* 速算：古铜琥珀 + 炽盛灯焰 */
    --v2-mode-challenge-bg: #500724; --v2-mode-challenge-accent: #FDE047;  /* 闯关：红宝石宫殿 + 皇冠纯金 */
    --v2-mode-ranking-bg:   #1E1B4B; --v2-mode-ranking-accent:   #38BDF8;  /* 榜单：星空蓝宝石 + 孔雀蓝 */

    /* 大数字与珠算核心：璀璨万灯金辉 + 暖橙流光外发光 */
    --v2-display-color: #FEF08A;
    --v2-display-glow: 0 2px 0 rgba(180, 83, 9, 0.75), 0 0 22px rgba(245, 158, 11, 0.55), 0 0 45px rgba(236, 72, 153, 0.35);
    --v2-display-divider: #F59E0B;
    --v2-display-divider-glow: 0 0 12px rgba(245, 158, 11, 0.85);

    /* 步进器数值框与输入框 */
    --v2-input-bg: #1F082E;
    --v2-input-text: #FEF08A;
    --v2-input-label: #F9A8D4;

    /* 深色卡片字色三件套：确保高对比度清晰易读 */
    --v2-text: #FFFBEB;         /* 正文暖金白 */
    --v2-text-dark: #FFFFFF;    /* 大标题最亮纯白 */
    --v2-muted: #F9A8D4;        /* 次要/提示：柔和莲花粉 */

    /* 背景金粉星火点阵 */
    --v2-dot-color: rgba(251, 191, 36, 0.18);
    --v2-dot-size: 30px;
}

#app {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: var(--v2-bg-main);
    display: flex;
    flex-direction: column;
    color: var(--v2-text);
    font-family: 'Outfit', 'Montserrat', sans-serif;
    overflow: hidden;
    /* 沉浸式全屏后内容会铺到刘海/挖孔/圆角底下 —— 用安全区内边距把内容让开，
       背景仍铺满整屏(padding 不影响 background)。横屏时刘海在左右两侧，
       所以四个方向都要给。需配合 index.html 的 viewport-fit=cover，
       否则 env() 恒为 0、这几行等于没写。 */
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    box-sizing: border-box;
}

/* Dot pattern background — color is themable via --v2-dot-color */
#app::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image: radial-gradient(var(--v2-dot-color, rgba(224, 208, 176, 0.3)) 2px, transparent 2px);
    background-size: var(--v2-dot-size, 30px) var(--v2-dot-size, 30px);
    z-index: -1;
}

/* Harvest theme: warm cream gradient + golden rice-stalk dots */
.v2-theme-harvest #app {
    background:
        radial-gradient(circle at 15% 10%, rgba(252, 211, 77, 0.35) 0%, transparent 45%),
        radial-gradient(circle at 85% 90%, rgba(220, 38, 38, 0.18) 0%, transparent 50%),
        linear-gradient(160deg, #FFFBEB 0%, #FEF3C7 55%, #FFE8D6 100%);
}
.v2-theme-harvest {
    --v2-dot-color: rgba(217, 119, 6, 0.22);   /* golden amber dots */
    --v2-dot-size: 28px;
}

/* Halloween theme: deep eerie violet-black + pumpkin orange & ghost green ambient glow */
.v2-theme-halloween #app {
    background:
        radial-gradient(circle at 82% 12%, rgba(249, 115, 22, 0.22) 0%, transparent 45%),
        radial-gradient(circle at 14% 86%, rgba(16, 185, 129, 0.15) 0%, transparent 42%),
        radial-gradient(circle at 50% 45%, rgba(88, 28, 135, 0.25) 0%, transparent 65%),
        #180828;
}

/* Deepavali theme: royal violet-magenta + warm diya gold & peacock teal ambient glow */
.v2-theme-deepavali #app {
    background:
        radial-gradient(circle at 82% 14%, rgba(251, 191, 36, 0.25) 0%, transparent 46%),
        radial-gradient(circle at 16% 85%, rgba(20, 184, 166, 0.18) 0%, transparent 44%),
        radial-gradient(circle at 50% 45%, rgba(157, 23, 77, 0.28) 0%, transparent 65%),
        #1F082E;
}

/* ══════════════════════════════════════════════
   SCREEN & CONTENT
   ═══════════════════════════════════════════════ */

.v2-screen {
    display: none;
    flex: 1;
    height: 100%;
    flex-direction: column;
    overflow: hidden;
    position: relative;
    animation: v2PopIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    width: 100%;
    max-width: 100%;
}

.v2-screen.active {
    display: flex;
}

@keyframes v2PopIn {
    from { opacity: 0; transform: scale(0.9); }
    to { opacity: 1; transform: scale(1); }
}

.v2-header {
    font-size: var(--v2-size-title);
    font-weight: var(--v2-weight-heavy);
    text-align: center;
    /* 左右各留 64px 给绝对定位的返回/设置按钮，标题永不被压住 */
    padding: 15px 64px;
    line-height: 1.2;
    color: var(--v2-primary);
    text-shadow: 2px 2px 0 var(--v2-surface);
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    /* ⚠️ header 是 width:100% 撑满全屏，但 .v2-content 下面的卡片收窄到 1000px 居中——
       宽屏桌面下标题/返回按钮就会贴着物理屏幕边缘，跟下方居中内容错位。
       这里收拢成同宽(1000px)居中框，绝对定位的按钮(.v2-header-gear)就会跟着相对这个框对齐。 */
    max-width: 1000px;
    margin: 0 auto;
    box-sizing: border-box;
    width: 100%;
}

/* 窄屏：双语长标题缩小一点，尽量一行；放不下则居中换行（已被左右 padding 护住，不会压按钮）*/
@media (max-width: 420px) {
    .v2-header {
        font-size: 20px;
        padding: 13px 60px;
    }
}

.v2-header-gear {
    position: absolute;
    right: 20px;
    font-size: 20px;
    color: var(--v2-primary);
    cursor: pointer;
    transition: transform 0.3s;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: white;
    border-radius: 12px;
    box-shadow: 2px 2px 0 var(--v2-border-main);
}

.v2-header-gear:active {
    transform: scale(0.9) rotate(45deg);
}

/* Home header has three actions on the right; reserve their space on phones.
   max-width/margin 已由 .v2-header 通用规则处理，这里只覆盖对齐方式与内边距。 */
#v2-screen-mode-select > .v2-header {
    justify-content: flex-start !important;
    padding-left: 20px !important;
    padding-right: 164px !important;
    white-space: nowrap;
}

@media (max-width: 420px) {
    #v2-screen-mode-select > .v2-header {
        font-size: 18px;
        padding-left: 14px !important;
        padding-right: 154px !important;
    }

    #v2-screen-mode-select #v2-app-version {
        display: none;
    }
}

.v2-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    padding: 12px 10px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    width: 100%;
    box-sizing: border-box;
}

.v2-footer {
    /* 圆角/内边距贴齐其它卡片(--v2-radius-card)规格，
       原先 40px 圆角 + 大内边距会让按钮周围留白明显比页面上其它卡片宽，
       显得这个容器"边框"特别粗 */
    padding: 14px 15px 18px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    background: white;
    /* 之前只写 border-top，左右/底边完全没描边只靠阴影撑，
       跟上面四边都有边框的卡片放在一起边缘明显更"软"、不齐整。
       改成四边同款描边，底边虽然贴屏幕边缘通常看不见，但宽屏/桌面预览时
       容器没顶到屏幕底就会露出来，四边都描边才不会露馅。 */
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card) var(--v2-radius-card) 0 0;
    box-shadow: 0 -8px 24px rgba(0,0,0,0.04);
    /* ⚠️ 必须跟页面上其它卡片一样限制 max-width + 居中，否则宽屏下这个
       白色容器会一直铺到 .v2-content 右边缘，而里面的按钮却被 1000px
       上限收窄居中，两边就对不齐，看起来像"右边多出一大块白框" */
    width: 100%;
    max-width: 1000px;
    margin: 0 auto;
    box-sizing: border-box;
}

/* ══════════════════════════════════════════════
   UNIFIED BUTTON SYSTEM
   ═══════════════════════════════════════════════ */

/* Base button — all footer / content buttons inherit this
   ⚠️ 这条规则会把 .v2-content 里**所有** <button> 撑成 95% 宽的大橙按钮。
   任何小按钮（图标钮、行内操作钮）都必须加进下面的 :not() 排除列表，
   否则自己写的 width/height 会被这条规则的高特异性盖掉 —— 症状是小按钮
   变成整行大按钮并撑爆容器（.tatt-bulk、.tgc-del、.v2-detail-tab、.tdx-btn、.v2-shop-preview-chip 都先后踩过）。
   ⚠️ 这条选择器特异性是 (0,7,1)，光给自己的组件写个 .my-btn(0,1,0) 是压不过的，
   必须把类名加进下面的 :not() 列表——诊断面板整块「乱」就是这么来的。
   ⚠️ 行内 style 也救不了：这条选择器特异性比 style 属性低，但 width/height 一旦
   在这里定死，行内的 flex:1 / max-width 会跟它打架 —— 学生详情页页签就是被压成
   窄条、动作钮涨成橙色大横幅。加类名到 :not() 才是唯一解。 */
.v2-footer button,
.v2-content button:not(.v2-neu-key):not(.v2-step-btn):not(.tatt-bulk):not(.tgc-btn):not(.tgc-del):not(.v2-detail-tab):not(.v2-detail-action):not(.tdx-btn):not(.v2-roster-button):not(.v2-shop-preview-chip) {
    width: 95%;
    max-width: 1000px;
    height: var(--v2-btn-height);
    padding: 0 24px;
    border-radius: var(--v2-btn-radius);
    border: none;
    outline: none;
    background: var(--v2-primary);
    color: var(--v2-surface);
    font-family: var(--v2-font-main);
    font-size: var(--v2-btn-font-size);
    font-weight: var(--v2-weight-heavy);
    cursor: pointer;
    position: relative;
    box-shadow: var(--v2-btn-shadow);
    transition: var(--v2-transition-fast);
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}

.v2-footer button:active,
.v2-content button:not(.v2-neu-key):not(.v2-step-btn):not(.tatt-bulk):not(.tgc-btn):not(.tgc-del):not(.v2-detail-tab):not(.v2-detail-action):not(.tdx-btn):not(.v2-roster-button):not(.v2-shop-preview-chip):active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

/* Primary action button (Start / Generate) */
.v2-start-btn {
    background: var(--v2-primary);
    color: var(--v2-surface);
    box-shadow: var(--v2-btn-shadow);
    width: 100%;
    max-width: 1000px;
}

.v2-start-btn:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

.v2-start-btn.disabled {
    background: #BDC3C7 !important;
    color: #ECF0F1 !important;
    box-shadow: none !important;
    opacity: 0.6 !important;
    cursor: not-allowed !important;
    pointer-events: none !important;
}

/* Secondary button (last in footer = cancel/back) */
.v2-footer button:last-child:not(.v2-start-btn) {
    background: #F0F0F0;
    color: var(--v2-muted);
    box-shadow: 0 var(--v2-shadow-depth) 0 #D0D0D0;
}

.v2-footer button:last-child:not(.v2-start-btn):active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

/* Result-screen home/back button — keep it clearly clickable (colored),
   even when it becomes the last footer button (retry hidden). */
#v2-result-home-btn,
.v2-footer button:last-child#v2-result-home-btn {
    background: var(--v2-accent);
    color: #fff;
    box-shadow: 0 var(--v2-shadow-depth) 0 #1976D2;
}

#v2-result-home-btn:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

/* Back button (neumorphic style) */
.v2-back-btn {
    background: #EDF1F5;
    color: var(--v2-text);
    box-shadow: 3px 3px 6px #d1d9e6, -3px -3px 6px var(--v2-surface);
}

.v2-back-btn:active {
    box-shadow: var(--v2-shadow-inner);
}

/* ══════════════════════════════════════════════
   PLAYFUL CARDS (MODE SELECT)
   ═══════════════════════════════════════════════ */

.v2-neu-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 12px;
    width: 100%;
    max-width: 1000px; /* 提升至 1000px，兼顾视觉中心与大气感 */
    margin: 0 auto;
    box-sizing: border-box;
    padding: 5px;
}

/* 网格内的卡片应该不受 max-width 限制 */
.v2-neu-grid .v2-neu-card {
    max-width: none;
    margin: 0;
}

.v2-neu-card {
    background: var(--v2-card-bg);
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card);
    padding: 20px 15px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    cursor: pointer;
    box-shadow: var(--v2-shadow-soft);
    transition: var(--v2-transition);
    width: 100%;
    max-width: 1000px;
    margin: 0 auto;
    box-sizing: border-box;
}

.v2-neu-card:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

/* Teacher student roster: compact, searchable rows */
#v2-t-students-list.v2-roster-mode {
    display: block;
    max-width: 1000px;
    padding: 5px;
}

.v2-roster-shell { width: 100%; }
.v2-roster-header,
.v2-roster-overview-header {
    display:flex; align-items:center; gap:12px; padding:12px 14px; margin:2px 0 14px;
    border:2px solid var(--v2-border-main, #E0D0B0); border-radius:18px;
    background:rgba(255,255,255,.94); box-shadow:0 3px 0 var(--v2-border-main, #E0D0B0);
    box-sizing:border-box;
}
.v2-roster-overview-header { grid-column:1 / -1; width:100%; }
/* ⚠️ 底色固定白，字色不能用深色主题下会变近白的 --v2-text-dark，
   否则星河等主题下白底白字，返回箭头/班级名整个看不见 */
.v2-roster-back {
    width:42px; height:42px; flex:0 0 auto; border-radius:13px;
    border:2px solid var(--v2-border-main, #E0D0B0); background:#fff;
    color:#1E293B; box-shadow:0 3px 0 var(--v2-border-main, #E0D0B0);
    font:900 21px/1 var(--v2-font-main); cursor:pointer;
}
.v2-roster-back:active { transform:translateY(3px); box-shadow:none; }
.v2-roster-heading { display:flex; flex-direction:column; min-width:0; }
.v2-roster-heading strong { font-size:18px; color:#1E293B; }
.v2-roster-heading span { margin-top:2px; font-size:11px; font-weight:800; color:var(--v2-muted, #64748B); }
.v2-roster-actions { margin-left:auto; display:flex; align-items:center; gap:8px; }
.v2-roster-action,
.v2-roster-add {
    height:38px; margin:0; border-radius:12px; cursor:pointer; font-family:var(--v2-font-main);
    font-weight:900; transition:transform .16s ease, box-shadow .16s ease;
}
.v2-roster-action { width:38px; padding:0; border:2px solid var(--v2-border-main, #E0D0B0); background:#fff; color:#526074; box-shadow:0 2px 0 var(--v2-border-main, #E0D0B0); font-size:21px; }
.v2-roster-add { width:auto; padding:0 14px; display:flex; align-items:center; gap:5px; border:2px solid #E67E00; background:var(--v2-primary, #FF8A00); color:#fff; box-shadow:0 3px 0 #CC6F00; font-size:12px; }
.v2-roster-action:active,
.v2-roster-add:active { transform:translateY(2px); box-shadow:none; }
.v2-roster-search-wrap { position:relative; margin-bottom:14px; }
.v2-roster-search {
    width:100%; height:48px; box-sizing:border-box; padding:0 46px;
    border:2px solid var(--v2-border-main, #E0D0B0); border-radius:16px;
    outline:none; background:rgba(255,255,255,.94); color:var(--v2-text-dark, #1E293B);
    font:800 14px/1 var(--v2-font-main); box-shadow:0 3px 0 var(--v2-border-main, #E0D0B0);
    transition:border-color .18s ease, box-shadow .18s ease;
}
.v2-roster-search:focus { border-color:var(--v2-primary, #FF8A00); box-shadow:0 3px 0 #F5B45F, 0 0 0 3px rgba(255,138,0,.12); }
.v2-roster-search::placeholder { color:#98A2B3; }
.v2-roster-search::-webkit-search-cancel-button { display:none; }
.v2-roster-search-icon { position:absolute; left:17px; top:50%; transform:translateY(-52%); z-index:1; font-size:23px; color:#7C3AED; font-weight:900; pointer-events:none; }
.v2-roster-search-clear { position:absolute; right:10px; top:50%; transform:translateY(-50%); width:30px; height:30px; border:0; border-radius:10px; background:#F1F5F9; color:#64748B; font-size:20px; line-height:1; cursor:pointer; }
.v2-roster-search-clear[hidden] { display:none; }
.v2-roster-cards { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:12px; }
.v2-roster-card {
    min-width:0; min-height:100px; padding:16px; display:flex; align-items:center; gap:14px;
    border:2px solid var(--v2-border-main, #E0D0B0); border-radius:20px;
    /* ⚠️ 底色固定白，字色不能用深色主题下会变近白的 --v2-text-dark，
       否则星河等主题下白底白字，英文名整行看不见 */
    background:#fff; box-shadow:0 4px 0 var(--v2-border-main, #E0D0B0);
    color:#1E293B; text-align:left; font-family:var(--v2-font-main);
    cursor:pointer; transition:transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.v2-roster-card:hover { transform:translateY(-2px); border-color:#F2C981; box-shadow:0 6px 0 #E7CFA6; }
.v2-roster-card:active { transform:translateY(3px); box-shadow:none; }
.v2-roster-avatar { width:54px; height:54px; flex:0 0 54px; display:grid; place-items:center; border-radius:16px; background:#F5F3FF; font-size:27px; }
.v2-roster-identity { min-width:0; flex:1; display:flex; flex-direction:column; gap:7px; }
.v2-roster-name { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:15px; line-height:1.2; font-weight:900; letter-spacing:-.15px; }
.v2-roster-meta { display:flex; align-items:center; flex-wrap:wrap; gap:4px; color:var(--v2-muted, #64748B); font-size:10.5px; line-height:1.35; font-weight:800; }
.v2-roster-cn { color:#667085; }
.v2-roster-dot { opacity:.55; }
.v2-roster-points { flex:0 0 auto; border:1px solid #FCD34D; border-radius:999px; padding:4px 8px; background:#FFFBEB; color:#B45309; font-size:10.5px; font-weight:900; white-space:nowrap; }
.v2-roster-chevron { flex:0 0 auto; color:#B0A58F; font-size:26px; line-height:1; }
.v2-roster-empty { grid-column:1 / -1; min-height:180px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px; border:2px dashed var(--v2-border-main, #E0D0B0); border-radius:20px; color:var(--v2-muted, #64748B); background:rgba(255,255,255,.55); }
.v2-roster-empty-icon { font-size:35px; color:#7C3AED; }
/* ⚠️ 底色是半透明白，字色不能用深色主题下会变近白的 --v2-text-dark，否则看不清 */
.v2-roster-empty strong { color:#1E293B; font-size:15px; }
.v2-roster-empty span:last-child { font-size:11px; font-weight:700; }

@media (max-width: 700px) {
    .v2-roster-cards { grid-template-columns:1fr; gap:10px; }
    .v2-roster-card { min-height:92px; padding:13px; gap:11px; }
    .v2-roster-avatar { width:48px; height:48px; flex-basis:48px; border-radius:14px; font-size:24px; }
    .v2-roster-points { padding:3px 7px; }
}

@media (max-width: 410px) {
    .v2-roster-header,
    .v2-roster-overview-header { padding:10px; gap:9px; }
    .v2-roster-add { width:38px; padding:0; justify-content:center; font-size:20px; }
    .v2-roster-add span:last-child { display:none; }
    .v2-roster-card { align-items:flex-start; position:relative; padding-right:34px; }
    .v2-roster-points { position:absolute; right:32px; bottom:13px; }
    .v2-roster-chevron { position:absolute; right:12px; top:50%; transform:translateY(-50%); }
    .v2-roster-meta { padding-bottom:25px; }
}

.v2-neu-icon {
    font-size: 36px;
    width: 80px;
    height: 80px;
    background: var(--v2-bg-main);
    border-radius: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 5px;
    background-size: cover;
    background-position: center;
}

.v2-svg-icon {
    display: block;
    pointer-events: none;
    transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.v2-neu-card:hover .v2-svg-icon {
    transform: scale(1.06);
}

/* 各模式图标颜色：由 [data-mode=X] 驱动，主题级 token 控制配色 */
.v2-neu-card[data-mode="flash"]     .v2-neu-icon { background: var(--v2-mode-flash-bg);     color: var(--v2-mode-flash-accent); }
.v2-neu-card[data-mode="look"]      .v2-neu-icon { background: var(--v2-mode-look-bg);      color: var(--v2-mode-look-accent); }
.v2-neu-card[data-mode="listen"]    .v2-neu-icon { background: var(--v2-mode-listen-bg);    color: var(--v2-mode-listen-accent); }
.v2-neu-card[data-mode="speed"]     .v2-neu-icon { background: var(--v2-mode-speed-bg);     color: var(--v2-mode-speed-accent); }
.v2-neu-card[data-mode="challenge"] .v2-neu-icon { background: var(--v2-mode-challenge-bg); color: var(--v2-mode-challenge-accent); }
.v2-neu-card[data-mode="ranking"]   .v2-neu-icon { background: var(--v2-mode-ranking-bg);   color: var(--v2-mode-ranking-accent); }
/* 笔算复用看算配色：两者题目呈现最接近（同款竖排算式），且免去为每套
   主题各补一组 token —— 新增 token 要改 4+ 处主题定义，漏一处就掉色。 */
.v2-neu-card[data-mode="written"]   .v2-neu-icon { background: var(--v2-mode-look-bg);      color: var(--v2-mode-look-accent); }

.v2-neu-title {
    font-weight: 900;
    font-size: 19px;
    color: var(--v2-text);
}

.v2-neu-desc {
    font-size: 11px;
    color: var(--v2-muted);
    font-weight: 700;
    text-align: center;
}

/* ══════════════════════════════════════════════
   SETTINGS UI (PLAYFUL LIST)
   ═══════════════════════════════════════════════ */

.v2-settings-grid {
    width: 100%;
    max-width: 1000px;
}

.v2-setting-item {
    background: white;
    border: 3px solid var(--v2-border-main);
    border-radius: 28px;
    padding: 20px;
    margin-bottom: 16px;
    box-shadow: 0 6px 0 var(--v2-border-main);
}

.v2-setting-item label {
    font-weight: 900;
    font-size: 15px;
    /* ⚠️ .v2-setting-item 底色固定白，字色不能用深色主题下会变浅的
       --v2-muted，否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    display: flex;
    justify-content: space-between;
    margin-bottom: 15px;
}

/* Range Input Chunky */
input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 12px;
    background: #EEE;
    border-radius: 10px;
    outline: none;
}

input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 32px;
    height: 32px;
    background: white;
    border: 4px solid var(--v2-primary);
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 4px 0 rgba(0,0,0,0.1);
}

.v2-range-value {
    background: var(--v2-primary);
    color: white;
    padding: 4px 12px;
    border-radius: 12px;
    font-weight: 900;
    font-family: 'Outfit', sans-serif;
}


/* ══════════════════════════════════════════════
   PLAYER & ENGINE (SUNNY STYLE)
   ═══════════════════════════════════════════════ */

.v2-speed-card {
    background: white;
    border: 5px solid var(--v2-primary);
    border-radius: 50px;
    padding: 50px 30px;
    text-align: center;
    box-shadow: 0 15px 0 rgba(255, 138, 0, 0.2);
    width: 90%;
    max-width: 1000px;
    position: relative;
}

.v2-speed-card::after {
    content: '⭐';
    position: absolute;
    top: -20px;
    right: -20px;
    font-size: 40px;
    transform: rotate(15deg);
}

.v2-num-display {
    /* 响应式：手机不溢出，电子白板/投屏自动放大 */
    font-size: clamp(64px, 26vmin, 220px);
    font-weight: 900;
    font-family: var(--v2-font-num);
    /* ⚠️ .v2-speed-card 底色固定白，字色不能用深色主题下会变近白的
       --v2-text-dark，否则星河等主题下大数字看不见 */
    color: #1F2937;
    margin-bottom: 10px;
    text-align: center;
    width: 100%;
}

.v2-feedback-card {
    background: white;
    border: 6px solid var(--v2-primary);
    border-radius: 40px;
    padding: 30px 20px;
    text-align: center;
    width: 85%;
    max-width: 1000px;
    box-shadow: 0 12px 0 rgba(0,0,0,0.05);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    animation: v2PopIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* 答对场景：SFX + 绿勾已经传达，去掉外框/底色/阴影，更安静 */
.v2-feedback-card.correct {
    background: transparent;
    border: none !important;            /* 覆盖 inline border-color */
    box-shadow: none;
    padding: 10px;
}

.v2-feedback-icon {
    font-size: 64px;
    margin-bottom: 15px;
}

.v2-feedback-msg {
    font-size: 20px;
    font-weight: 900;
    /* ⚠️ .v2-feedback-card 底色固定白，字色不能用深色主题下会变近白的
       --v2-text，否则星河等主题下浅底浅字看不见 */
    color: #1F2937;
    line-height: 1.4;
}

.v2-num-pos { color: #2196F3; } /* 蓝色 */
.v2-num-neg { color: #FF5252; } /* 红色 */

/* ⚠️ REMARK: 乘除法横向显示（闪算 + 看算模式共用） — 样式由 FlashEngineV2.js 和 LookEngineV2.js 引用 */
.v2-num-multi {
    white-space: nowrap;
    letter-spacing: 1px;
    /* 响应式：上限调高让电子白板/投屏放大；超宽时 LookEngine 的横向自动缩小会兜底 */
    font-size: clamp(56px, 16vw, 280px);
    font-weight: 900;
    font-family: var(--v2-font-num);
    width: 100%;
    text-align: center;
    color: var(--v2-display-color, var(--v2-text-dark));
}

.v2-step-info {
    display: inline-block;
    padding: 8px 20px;
    background: #F5F5F5;
    border-radius: 25px;
    font-size: 14px;
    font-weight: 900;
    /* ⚠️ 底色固定浅灰，字色不能用深色主题下会变浅的 --v2-muted，
       否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
}

/* ══════════════════════════════════════════════
   FLASH MODE SPECIFIC
   ═══════════════════════════════════════════════ */

/* ══════════════════════════════════════════════
   FLASH MODE V2 REFINED LAYOUT
   ═══════════════════════════════════════════════ */

.v2-flash-container {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
}

.v2-flash-controls {
    width: 100%;
    display: flex;
    justify-content: space-between;
    padding: 10px 0;
}

.v2-mini-btn {
    background: white !important;
    color: #666 !important;
    padding: 8px 15px !important;
    font-size: 14px !important;
    border-radius: 12px !important;
    box-shadow: 0 4px 0 #DDD !important;
    width: auto !important;
    max-width: none !important;
    margin: 0 !important;
}

.v2-mini-btn:active {
    transform: translateY(2px) !important;
    box-shadow: 0 2px 0 #DDD !important;
}

/* Mouth Progress Bar */
.v2-mouth-progress-wrap {
    width: 100%;
    height: 12px;
    background: rgba(0,0,0,0.05);
    border-radius: 6px;
    overflow: hidden;
    margin: 20px 0;
}

.v2-mouth-progress-bar {
    height: 100%;
    background: var(--v2-secondary);
    border-radius: 6px;
    transition: width 0.2s ease;
}


.v2-mouth-info {
    font-size: 18px;
    font-weight: 900;
    /* ⚠️ 底色固定白，字色不能用深色主题下会变浅的 --v2-muted，
       否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    background: white;
    padding: 5px 20px;
    border-radius: 20px;
    border: 2px solid var(--v2-border-main);
}

@keyframes v2PulseQuick {
    0% { transform: scale(0.8); opacity: 0.5; }
    100% { transform: scale(1); opacity: 1; }
}

/* ══════════════════════════════════════════════
   PLAYER & ENGINE (SUNNY STYLE)
   ═══════════════════════════════════════════════ */

.v2-player-stage {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    position: relative;
    overflow: hidden;
}

.v2-flash-stage {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 30px;
    width: 100%;
    height: 100%;
}

/* ⚠️ REMARK: 题目显示（闪算 + 听算模式） — 样式由 FlashEngineV2.js 和 ListenEngineV2.js 引用
   颜色/辉光由各主题在 token 层定义：--v2-display-color / --v2-display-glow */
.v2-flash-display,
.v2-look-item {
    color: var(--v2-display-color, var(--v2-text-dark));
    text-shadow: var(--v2-display-glow, none);
}

.v2-flash-display {
    font-size: 160px;
    font-weight: 900;
    font-family: var(--v2-font-num);
    animation: v2PulseQuick 0.15s ease-out;
}

/* ⚠️ 乘除算式闪现：必须放在 .v2-flash-display 之后。
   闪算/极速/听算/挑战都把两个类叠在同一个元素上写成
   `class="v2-flash-display v2-num-multi"`，两者特异性相同(0,1,0)，
   于是后定义的 .v2-flash-display 的固定 160px 覆盖掉 .v2-num-multi
   的响应式 clamp()。配上 white-space:nowrap，手机上 "7854 ÷ 26 ="
   实测宽 1023px、容器只有 390px —— 算式右半截(运算符和第二个数)
   直接被裁掉看不见，学生根本没法答题。
   单个数字(加减法)不受影响，因为那条路径不加 .v2-num-multi。

   字号按算式实际长度自适应：引擎在元素上写 --v2-expr-len(字符数)，
   这里用 88vw/字符数 反推每字可用宽度。好处是短算式("12 × 3 =")
   能放到跟看算一样大，长算式才缩小 —— 若按最坏情况一刀切定死 vw，
   短算式会被无谓压小(实测比看算小 1.45 倍，正是「闪算看起来比看算小」
   的原因)。--v2-expr-len 缺省 11 是常见的 4÷2 位长度，
   万一引擎忘了写也不会溢出。 */
.v2-flash-display.v2-num-multi {
    font-size: min(16vw, 200px, calc(88vw / var(--v2-expr-len, 11) * 1.75));
}


.v2-input-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    width: 100%;
    height: 100%;
}

/* ══════════════════════════════════════════════
   NUMPAD V2 (PLAYFUL & RESPONSIVE)
   ═══════════════════════════════════════════════ */

.v2-input-area .v2-input-label {
    font-size: 16px;
    font-weight: 800;
    color: var(--v2-text);
    margin: 0;
    opacity: 1;
}

.v2-neu-input-box {
    width: 90%;
    max-width: 300px;
    height: 80px;
    background: var(--v2-bg);
    border: none;
    border-radius: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
    font-weight: 900;
    color: var(--v2-accent);
    box-shadow: var(--v2-shadow-inner);
    position: relative; /* 为绝对定位光标做准备 */
}

/* 确保数字展示区域可以容纳绝对定位的光标 */
#v2-input-val, #v2-answer-display {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* 确保光标不占位，且不重叠 */
.v2-cursor { 
    display: none !important;
}

.v2-neu-numpad {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    width: 90%;
    max-width: 300px;
    justify-items: center;
}

.v2-neu-key {
    width: 100%;
    max-width: 85px;
    aspect-ratio: 1 / 1;
    height: auto;
    min-height: 60px;
    background: var(--v2-surface);
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card);
    font-size: 26px;
    font-weight: var(--v2-weight-heavy);
    color: var(--v2-text);
    cursor: pointer;
    box-shadow: var(--v2-shadow-soft);
    transition: var(--v2-transition-fast);
    display: flex;
    align-items: center;
    justify-content: center;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.v2-neu-key:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
    background: var(--v2-bg-main);
}

@keyframes v2Blink { 50% { opacity: 0; } }

/* ══════════════════════════════════════════════
   NEU-STICKER CARDS (拟物贴纸风 - 还原版)
   ═══════════════════════════════════════════════ */




.v2-neu-card .v2-neu-title {
    font-size: 18px; /* 调大标题 */
    font-weight: 900;
    color: var(--v2-text);
}

.v2-neu-card .v2-neu-desc {
    font-size: 12px;
    opacity: 0.6;
    font-weight: 600;
    margin-top: 4px;
}


#v2-screen-player .screen-header {
    padding: 0 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--v2-bg-main);
    z-index: 100;
    position: relative;
    border-bottom: 2px solid rgba(0,0,0,0.05);
    height: 90px;
}

.v2-header-side {
    flex: 1;
    display: flex;
    justify-content: flex-start;
}

.v2-global-progress {
    flex: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin: 0;
}

.v2-progress-stats {
    display: flex;
    gap: 8px;
}

.progress-pill {
    background: var(--v2-primary);
    color: white;
    font-size: 11px;
    font-weight: 900;
    padding: 4px 12px;
    border-radius: 50px;
    box-shadow: 0 3px 0 rgba(0,0,0,0.1);
    white-space: nowrap;
}

.v2-progress-bar-wrap {
    width: 100%;
    max-width: 180px;
    height: 8px;
    background: rgba(0,0,0,0.1);
    border-radius: 12px;
    overflow: hidden;
    border: none;
}

.v2-progress-bar {
    height: 100%;
    background: linear-gradient(90deg, var(--v2-secondary), var(--v2-primary));
    width: 0%;
    transition: width 0.1s linear, background-color 0.2s ease;
    border-radius: 12px;
    box-shadow: 0 0 8px rgba(108, 99, 255, 0.4);
}

.v2-header-controls {
    flex: 1;
    display: flex;
    justify-content: flex-end;
    gap: 12px;
}

/* 强力锁定：确保训练界面顶部的三个按钮风格完全一致（白底、粗边、3D投影） */
#v2-screen-player .screen-header button.back-btn,
#v2-screen-player .screen-header button.pause-btn,
#v2-screen-player .screen-header button.skip-btn {
    width: 48px !important;
    height: 48px !important;
    background: white !important;
    border: 3px solid var(--v2-border-main) !important;
    border-radius: 15px !important;
    color: var(--v2-primary) !important;
    box-shadow: 0 4px 0 var(--v2-border-main) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    font-size: 18px !important;
    cursor: pointer !important;
    transition: all 0.1s !important;
    padding: 0 !important;
    margin: 0 !important;
    outline: none !important;
}

#v2-screen-player .screen-header button:active {
    transform: translateY(2px) !important;
    box-shadow: 0 2px 0 var(--v2-border-main) !important;
}

/* ══════════════════════════════════════════════
   RESULT PAGE V2
   ═══════════════════════════════════════════════ */

.v2-result-card {
    background: white;
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card);
    padding: 30px 20px;
    width: 90%;
    max-width: 1000px;
    box-shadow: var(--v2-shadow-soft);
    text-align: center;
    margin: 0 auto;
    animation: v2PopIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    max-height: 80vh;
    display: flex;
    flex-direction: column;
}

.v2-result-details-header {
    margin-top: 25px;
    font-size: 14px;
    font-weight: 900;
    /* ⚠️ .v2-result-card 底色固定白，字色不能用深色主题下会变浅的
       --v2-muted，否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    text-transform: uppercase;
    border-top: 2px dashed #EEE;
    padding-top: 15px;
    margin-bottom: 10px;
}

.v2-result-details-list {
    flex: 1;
    overflow-y: auto;
    padding-right: 5px;
    margin-bottom: 10px;
}

.v2-detail-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 15px;
    background: #F9F9F9;
    border-radius: 15px;
    margin-bottom: 8px;
    border: 2px solid transparent;
}

.v2-detail-item.correct {
    background: rgba(76, 175, 80, 0.05);
    border-color: rgba(76, 175, 80, 0.1);
}

.v2-detail-item.wrong {
    background: rgba(255, 82, 82, 0.05);
    border-color: rgba(255, 82, 82, 0.1);
}

.v2-detail-item .idx {
    font-weight: 900;
    /* ⚠️ 底色固定浅灰 #F9F9F9，字色不能用深色主题下会变浅的
       --v2-muted，否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    width: 30px;
}

.v2-detail-item .detail-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-left: 10px;
}

.v2-detail-item .q-text {
    font-size: 15px;
    font-weight: 900;
    color: #555;
    margin-bottom: 4px;
}

.v2-detail-item .ans-group {
    display: flex;
    gap: 12px;
    font-size: 13px;
    font-weight: 900;
}

.v2-detail-item .correct-ans {
    color: var(--v2-secondary);
}

.v2-detail-item .user-ans {
    color: var(--v2-danger);
    text-decoration: none; /* 移除中划线，改为文字对比更清晰 */
    opacity: 0.8;
}

/* Custom Scrollbar for details */
.v2-result-details-list::-webkit-scrollbar {
    width: 6px;
}
.v2-result-details-list::-webkit-scrollbar-thumb {
    background: #DDD;
    border-radius: 10px;
}

.v2-score-header {
    margin-bottom: 30px;
}

.v2-stars {
    font-size: 40px;
    margin-bottom: 20px;
    filter: drop-shadow(0 4px 0 rgba(0,0,0,0.1));
}

.v2-score-circle {
    width: 140px;
    height: 140px;
    background: var(--v2-bg-main);
    border: 8px solid var(--v2-secondary);
    border-radius: 50%;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-shadow: inset 0 6px 0 rgba(0,0,0,0.05);
}

.v2-score-num {
    font-size: 38px;
    font-weight: 900;
    color: var(--v2-secondary);
}

.v2-score-label {
    font-size: 14px;
    font-weight: 900;
    /* ⚠️ .v2-result-card 底色固定白，字色不能用深色主题下会变浅的
       --v2-muted，否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
}

.v2-stats-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    margin-bottom: 30px;
}

.v2-stat-item {
    background: #FDFDFD;
    padding: 15px 5px;
    border-radius: var(--v2-radius-chip);
    border: var(--v2-card-border);
    box-shadow: var(--v2-shadow-soft);
}

.v2-stat-item .label {
    display: block;
    font-size: 11px;
    /* ⚠️ 底色固定 #FDFDFD，字色不能用深色主题下会变浅的 --v2-muted，
       否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    font-weight: 900;
    margin-bottom: 5px;
}

.v2-stat-item .val {
    display: block;
    font-size: 18px;
    font-weight: 900;
    color: #1F2937;
}

.v2-result-message {
    font-size: 18px;
    font-weight: 900;
    color: var(--v2-primary);
    padding: 0 10px;
}

/* Bento Grid Layout for Homework Results */
.v2-bento-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    margin: 20px 0;
    text-align: left;
    width: 100%;
    box-sizing: border-box;
}

.v2-bento-card {
    background: #F8FAFC;
    border: 3px solid var(--v2-border-main);
    border-radius: 18px;
    padding: 14px 18px;
    box-shadow: 3px 3px 0 var(--v2-border-main);
    transition: all 0.2s ease;
    box-sizing: border-box;
}

.v2-bento-card:hover {
    transform: translateY(-2px);
    box-shadow: 5px 5px 0 var(--v2-border-main);
}

.v2-bento-card .bento-title {
    font-size: 11px;
    font-weight: 900;
    /* ⚠️ 底色固定 #F8FAFC，字色不能用深色主题下会变浅的 --v2-muted，
       否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.v2-bento-card .bento-value {
    font-size: 24px;
    font-weight: 900;
    color: #1F2937;
    margin-top: 6px;
}

/* Ceremony header customisation */
.v2-homework-ceremony {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-bottom: 20px;
}

.v2-score-circle.active-hw {
    border-color: #6366F1;
    background: linear-gradient(135deg, #EEF2FF, white);
}

.mood-item {
    transition: all 0.2s ease;
}

.mood-item:hover {
    transform: scale(1.1);
}

#v2-teacher-sub-content {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
    box-sizing: border-box;
}

/* ══════════════════════════════════════════════
   THEME SELECTOR (SKIN STORE)
   ═══════════════════════════════════════════════ */

.v2-theme-selector-wrap {
    margin-bottom: 20px;
    background: white;
    padding: 20px;
    border-radius: var(--v2-radius-card);
    border: var(--v2-card-border);
    box-shadow: var(--v2-shadow-soft);
    width: 100%;
    max-width: 1000px;
    margin-left: auto;
    margin-right: auto;
    box-sizing: border-box;
}

.v2-section-label {
    display: block;
    font-size: 14px;
    font-weight: 900;
    /* ⚠️ .v2-theme-selector-wrap 底色固定白，字色不能用深色主题下会变
       浅的 --v2-muted，否则切到星河等主题后连"切换主题"都看不清 */
    color: #6B7280;
    margin-bottom: 15px;
    text-transform: uppercase;
    letter-spacing: 1px;
}

.v2-theme-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 15px;
}

.v2-theme-chip {
    background: white;
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-chip);
    padding: 15px 10px;
    text-align: center;
    position: relative;
    cursor: pointer;
    transition: var(--v2-transition);
    box-shadow: var(--v2-shadow-soft);
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.v2-theme-chip.active {
    border-color: var(--v2-primary);
    background: var(--v2-bg-main);
    transform: translateY(-5px);
    box-shadow: 0 8px 0 var(--v2-primary);
}

.v2-theme-chip.locked {
    opacity: 0.6;
    filter: grayscale(0.8);
    background: #F5F5F5;
}

.v2-theme-preview {
    font-size: 32px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
}

.v2-theme-preview svg {
    display: block;
    filter: drop-shadow(0 2px 4px rgba(124, 45, 18, 0.12));
}

.v2-theme-name {
    font-size: 13px;
    font-weight: 900;
    /* ⚠️ 未选中时卡片底色固定白，字色不能用深色主题下会变浅的
       --v2-muted，否则切到星河等主题后看不清、也切不回来 */
    color: #6B7280;
}

/* 选中态卡片底色改用 --v2-bg-main（会随主题变深），字色需跟着换成
   跟随主题走的 --v2-primary，在深浅两种主题背景下都保持清晰对比 */
.v2-theme-chip.active .v2-theme-name {
    color: var(--v2-primary);
}

.v2-theme-lock {
    position: absolute;
    top: -5px;
    right: -5px;
    background: #ef4444;
    color: white;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    font-size: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid white;
}

/* ══════════════════════════════════════════════
   SETTINGS V2 (OPTIMIZED)
   ═══════════════════════════════════════════════ */

.v2-settings-list {
    width: 100%;
    max-width: 1000px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
    transition: all 0.3s ease;
    align-items: center;
    margin: 0 auto;
}

.v2-setting-card {
    background: white;
    border-radius: var(--v2-radius-card);
    padding: 20px 15px;
    border: var(--v2-card-border);
    box-shadow: var(--v2-shadow-soft);
    transition: transform 0.2s, opacity 0.2s;
    box-sizing: border-box;
    width: 100%;
    max-width: 1000px;
    margin: 0 auto;
}

.v2-card-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}

.v2-card-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    color: var(--v2-primary);
    opacity: 0.9;
    flex-shrink: 0;
    line-height: 1;
}

.v2-card-icon svg {
    display: block;
}

.v2-card-label {
    font-size: 17px;
    font-weight: 900;
    /* ⚠️ .v2-setting-card 底色固定白，字色不能用深色主题下会变近白的
       --v2-text-dark，否则星河等主题下浅底浅字看不见（覆盖面极广） */
    color: #1F2937;
    letter-spacing: 0.3px;
    flex: 1;
}

.v2-card-body {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* 高级拟物步进器 (Premium Neumorphic Stepper) */
.v2-stepper {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    background: var(--v2-input-bg);
    padding: 4px;
    border-radius: 14px;
    box-shadow: inset 0 1px 3px rgba(0,0,0,0.08);
    width: 100%;
    max-width: 240px;
    margin: 0 auto;
    box-sizing: border-box;
}

.v2-step-btn {
    width: 32px;
    height: 32px;
    border: none;
    outline: none;
    border-radius: 50%;
    background: var(--v2-primary);
    color: var(--v2-surface);
    box-shadow: none;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: var(--v2-size-body);
    font-weight: var(--v2-weight-heavy);
    transition: var(--v2-transition-fast);
    flex-shrink: 0;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.v2-step-btn:active {
    transform: scale(0.88);
    background: var(--v2-primary-dark);
}

.v2-step-value {
    flex: 1;
    text-align: center;
    font-size: var(--v2-size-lg);
    font-weight: var(--v2-weight-heavy);
    color: var(--v2-input-text);
    padding: 8px 12px;
    min-width: 40px;
    cursor: pointer;
    transition: var(--v2-transition-fast);
    background: transparent;
    border-radius: 14px;
    box-shadow: none;
    display: flex;
    align-items: center;
    justify-content: center;
}

.v2-step-value:hover {
    color: var(--v2-primary);
}

.v2-step-input {
    width: 100%;
    height: 100%;
    background: transparent;
    border: none;
    outline: none;
    text-align: center;
    font-size: var(--v2-size-lg);
    font-weight: var(--v2-weight-heavy);
    color: var(--v2-input-text);
    font-family: inherit;
    -moz-appearance: textfield !important;
    appearance: textfield !important;
    padding: 0 !important;
    margin: 0 !important;
}

.v2-step-input::-webkit-outer-spin-button,
.v2-step-input::-webkit-inner-spin-button {
    display: none !important;
    -webkit-appearance: none !important;
    margin: 0 !important;
}

/* Level Chips (自适应网格版) */
.v2-level-mini-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(75px, 1fr));
    gap: 12px;
    width: 100%;
    box-sizing: border-box;
}

.v2-level-chip {
    background: #FAFAFA;
    border-radius: 14px;
    padding: 10px 4px;
    min-height: 85px;
    /* ⚠️ 排行挑战「竞技方式」只有2个选项时，父级 grid-template-columns 会写死
       repeat(2,1fr)，宽屏下每格被拉到400px+，44px 图标缩在一大片空白里显得
       偏左失衡。锁 max-width 让 chip 本身不再随格子无限变宽，超宽部分居中留白。 */
    max-width: 220px;
    margin: 0 auto;
    width: 100%;
    text-align: center;
    border: var(--v2-card-border);
    box-shadow: var(--v2-shadow-soft);
    transition: var(--v2-transition);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
    overflow: hidden;
    min-width: 0;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.v2-level-chip.active {
    background: white;
    border-color: var(--v2-secondary);
    color: var(--v2-secondary);
    box-shadow: 0 var(--v2-shadow-depth) 0 var(--v2-secondary);
    transform: translateY(-2px);
}
/* .v2-level-chip .name 的 color:#333 特殊性更高，要显式覆盖才能保留选中态的强调色 */
.v2-level-chip.active .name { color: var(--v2-secondary); }

.v2-level-chip:active {
    transform: scale(0.95);
    box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
}

.v2-level-chip .icon {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    margin-bottom: 2px;
    transition: transform 0.2s;
}
.v2-level-chip.active .icon { transform: scale(1.08); }
/* ⚠️ .v2-level-chip 底色固定 #FAFAFA（不跟随主题变色），字色不能用深色
   主题下会变近白的 --v2-text，否则星河等主题下浅底浅字看不见 */
.v2-level-chip .name { font-size: 12px; font-weight: 900; color: #333; }

/* Chip Group Settings (通用) */
.v2-chip-group {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 6px;
    width: 100%;
    padding: 5px 0;
    box-sizing: border-box;
}

.v2-setting-chip {
    flex: 1;
    min-width: 0; /* 允许弹性压缩，彻底防止横向溢出 */
    background: #F5F5F5;
    border-radius: 12px;
    padding: 8px 2px; /* 压缩内边距，释放横向宽度 */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    border: var(--v2-border-width) solid #F5F5F5;
    transition: var(--v2-transition);
    cursor: pointer;
    box-sizing: border-box;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.v2-setting-chip.active {
    background: white;
    border-color: var(--v2-primary);
    box-shadow: 0 var(--v2-shadow-depth) 0 var(--v2-primary);
    transform: translateY(-2px);
}

.v2-setting-chip:active {
    transform: scale(0.95);
    box-shadow: inset 0 2px 5px rgba(0,0,0,0.1);
}

.v2-setting-chip .icon {
    min-height: 38px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.2s;
    font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif;
    text-align: center;
    flex: 0 0 auto;
}
.v2-setting-chip.active .icon { transform: scale(1.15); }
.v2-setting-chip .label {
    font-size: 13px; /* 优化文字字号至 13px，在极窄屏幕上也能完美展示 */
    font-weight: 900;
    /* ⚠️ 底色固定 #F5F5F5/white（不跟随主题变色），字色不能用深色
       主题下会变浅的 --v2-muted，否则星河等主题下浅底浅字看不见 */
    color: #6B7280;
    transition: var(--v2-transition);
    text-align: center;
    line-height: 1.25;
    min-height: 2.5em; /* 锁定两行高度，防止图标随标签行数上下漂移 */
    display: flex;
    align-items: center;
    justify-content: center;
}
.v2-setting-chip.active .label { 
    color: var(--v2-primary);
    transform: scale(1.03); /* 激活时微调放大，保证排版平滑 */
}

/* Multi-Chip Group (数字矩阵全景版 - 分行优化) */
/* 紧凑型三联排卡片 (题数、口数、位数) */
.v2-stepper-group-row {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}

.v2-multi-layout {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}

/* Stepper Group/Pair Styling (Horizontal) */
.v2-stepper-pair-horizontal {
    display: flex;
    justify-content: center;
    align-items: flex-end;
    width: 100%;
    gap: 24px;
    padding: 16px 0;
}

.v2-stepper-row {
    display: flex;
    /* 原为 nowrap：高级模式有 4 个 stepper 时被硬挤在一行，
       相邻的 +/- 几乎贴住，容易点错。改为允许换行。 */
    flex-wrap: wrap;
    justify-content: center;
    align-items: flex-end;
    width: 100%;
    gap: 16px 12px;
    padding: 16px 0;
}

.v2-stepper-mini-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    /* min-width 从 0 提到 132px：不再允许无限压缩，
       放不下就换行(4 个 → 2×2)，而不是继续挤扁。 */
    flex: 1 1 132px;
    min-width: 132px;
}

.v2-mixed-row {
    display: flex;
    flex-wrap: nowrap;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    gap: 12px;
    padding: 16px 0;
}

.v2-mixed-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
}

.v2-mixed-item.stepper-item {
    justify-content: center;
}

.v2-mixed-item.toggle-item {
    justify-content: center;
}

.v2-mixed-item.stepper-item .v2-stepper {
    min-width: 120px;
}

.v2-mixed-item.toggle-item .v2-toggle-inline-container {
    display: flex;
    align-items: center;
    justify-content: center;
}

.v2-stepper-mini {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

.v2-stepper-mini .mini-label,
.v2-stepper-mini-item .mini-label {
    font-size: 12px;
    font-weight: 900;
    color: var(--v2-input-label);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    display: block;
    text-align: center;
    width: 100%;
    line-height: 1.2;
}
.v2-stepper-mini-item .mini-label span {
    display: block;
    width: 100%;
    text-align: center;
}

.v2-stepper-sep {
    font-size: 28px;
    font-weight: 900;
    color: var(--v2-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    height: 40px;
    opacity: 0.8;
}

/* 📱 Mobile Responsive Scale down for Steppers to prevent button overlap on narrow screens */
@media (max-width: 480px) {
    .v2-setting-card {
        padding: 16px 10px;
    }
    .v2-stepper-row {
        gap: 6px;
    }
    .v2-stepper-pair-horizontal {
        gap: 12px;
    }
    .v2-mixed-row {
        gap: 8px;
    }
    .v2-stepper {
        padding: 2px;
        border-radius: 10px;
        max-width: 180px;
    }
    .v2-step-btn {
        width: 26px;
        height: 26px;
        font-size: 13px;
    }
    .v2-step-value {
        padding: 5px 6px;
        font-size: 13px;
        min-width: 32px;
        border-radius: 10px;
    }
    .v2-step-input {
        font-size: 13px;
    }
    .v2-stepper-mini {
        gap: 6px;
    }
    .v2-stepper-mini-item {
        gap: 6px;
    }
    .v2-stepper-mini .mini-label,
    .v2-stepper-mini-item .mini-label {
        font-size: 11px;
    }
    .v2-stepper-sep {
        font-size: 18px;
        height: 36px;
    }
}

/* 📱 Super Narrow Mobile viewports (e.g., screen width <= 360px) */
@media (max-width: 360px) {
    .v2-stepper-row {
        gap: 4px;
    }
    .v2-stepper {
        padding: 1px;
    }
    .v2-step-btn {
        width: 22px;
        height: 22px;
        font-size: 11px;
    }
    .v2-step-value {
        padding: 4px 4px;
        font-size: 11px;
        min-width: 26px;
    }
    .v2-step-input {
        font-size: 11px;
    }
    .v2-stepper-mini .mini-label,
    .v2-stepper-mini-item .mini-label {
        font-size: 10px;
    }
}


.v2-stepper-sample {
    width: 100%;
    text-align: center;
    font-size: 15px;
    font-weight: 900;
    color: #3498DB;
    margin-top: 12px;
    padding: 10px 12px;
    background: rgba(52, 152, 219, 0.06);
    border-radius: 12px;
    border: 1px solid rgba(52, 152, 219, 0.15);
    font-family: var(--v2-font-num);
    letter-spacing: 0.5px;
}

.v2-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    width: 100%;
}

.v2-chip-grid {
    /* 原为 flex + flex-grow：末行不满时会被拉宽，与上面几行宽度对不齐。
       改成 grid 后列宽固定，末行不满也保持同宽。
       每行 5 格：十朋友(含全选共10个) → 5+5；五朋友/混合友(共5个) → 正好一行。
       窄屏由 auto-fit + minmax 自动降列数。 */
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
    gap: 10px;
    width: 100%;
}

/* 桌面/平板上锁定 5 列，避免 auto-fit 在宽容器里排成 6、7 格 */
@media (min-width: 560px) {
    .v2-chip-grid {
        grid-template-columns: repeat(5, 1fr);
    }
}

.v2-desc-mini-title {
    font-size: 11px;
    color: var(--v2-muted);
    margin: 12px 0 8px 0;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* ── 训练目标：加/减 配对两列 ─────────────────────────────
   词形选项(十朋友加/十朋友减…)按系列配对成行，同系列的加与减并排，
   落单的(直接加减)独占整行。取代原本每行 4 格导致的 4+3 断行。 */
.v2-pair-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
}
.v2-pair-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.v2-pair-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    width: 100%;
}
.v2-pair-grid .v2-setting-chip {
    flex: none;
    width: 100%;
    margin: 0;
}
.v2-pair-row.single {
    grid-template-columns: 1fr;
}
.v2-pair-row .v2-setting-chip {
    /* 由 grid 定宽，不再让 flex 拉伸，两行之间宽度才对得齐 */
    flex: none;
    width: 100%;
    margin: 0;
}
/* 「全选」原本是整条通栏灰条，比所有选项都宽、且灰底像被禁用。
   收成与单列同宽的常规 chip，未选时用描边而非实心灰。 */
.v2-chip-row.all-row {
    margin-bottom: 10px;
}
.v2-chip-row.all-row .v2-setting-chip {
    flex: none;
    width: 100%;
    background: transparent;
    border-style: dashed;
}
.v2-chip-row.all-row .v2-setting-chip.active {
    background: #F8F9FA;
    border-style: solid;
}

.v2-chip-row .v2-setting-chip,
.v2-chip-grid .v2-setting-chip {
    flex: 1 1 calc(25% - 10px);
    min-width: 80px;
    height: 48px;
    padding: 4px 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: var(--v2-radius-chip);
    font-size: 13px;
    font-weight: 900;
    background: #F8F9FA;
    border: var(--v2-card-border);
    transition: var(--v2-transition);
    white-space: normal;
    text-align: center;
    line-height: 1.1;
}

/* grid 布局下宽度由列决定：撤掉 flex-basis，否则 25% 的 basis 会与
   grid 列宽打架，末行仍会显得不齐。只覆盖宽度，外观沿用上面的共用块。 */
.v2-chip-grid .v2-setting-chip {
    flex: none;
    width: 100%;
    min-width: 0;
}


.v2-chip-row .v2-setting-chip.active {
    background: white;
    border-color: var(--v2-primary);
    color: var(--v2-primary);
    box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}

/* Description Panel (新面板样式) */
.v2-desc-panel {
    margin-top: 8px;
    padding: 14px 16px;
    background: #F5F7FB;
    border-radius: 14px;
    border-left: 4px solid var(--v2-primary);
    animation: v2-fade-in-up 0.3s ease;
    width: 100%;
    box-sizing: border-box;
}

.v2-desc-title {
    font-size: 11px;
    font-weight: 900;
    color: var(--v2-primary);
    opacity: 0.75;
    margin-bottom: 6px;
    letter-spacing: 1px;
    text-transform: uppercase;
}

.v2-desc-body {
    font-size: 14px;
    font-weight: 700;
    color: #555;
    line-height: 1.5;
}

@keyframes v2-fade-in-up {
    from { opacity: 0; transform: translateY(5px); }
    to { opacity: 1; transform: translateY(0); }
}

.v2-chip-row.all-row {
    width: 100%;
}

.v2-chip-row.all-row .v2-setting-chip {
    background: #E0E0E0;
    height: 36px;
    margin-bottom: 4px;
}

.v2-chip-row .v2-setting-chip.active,
.v2-chip-grid .v2-setting-chip.plus-chip.active {
    background: white;
    border-color: var(--v2-primary);
    color: var(--v2-primary);
    box-shadow: 0 4px 0 rgba(0,0,0,0.05);
    transform: translateY(-2px);
}

.v2-chip-grid .v2-setting-chip.minus-chip.active {
    background: white;
    border-color: var(--v2-secondary);
    color: var(--v2-secondary);
    box-shadow: 0 4px 0 rgba(0,0,0,0.05);
    transform: translateY(-2px);
}

.v2-chip-grid .v2-setting-chip.minus-chip.active .label {
    color: var(--v2-secondary);
}

/* ══════════════════════════════════════════════
   LOOK & LISTEN SIMPLE STYLE (统一中心化)
   ═══════════════════════════════════════════════ */
.v2-look-simple-container, .v2-listen-stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    flex: 1;
}

.v2-look-list {
    display: flex;
    flex-direction: column;
    align-items: center; /* 容器居中 */
    padding: 30px;
    min-width: 200px;
}

/* ⚠️ REMARK: 加减法竖排显示（看算模式）— 样式由 LookEngineV2.js renderQuestion() 引用 */
.v2-look-item {
    /* 响应式：上限调高让大屏放大；行数多时 LookEngine 的纵向自动缩小会兜底 */
    font-size: clamp(45px, 15vw, 200px);
    font-weight: 900;
    font-family: var(--v2-font-num);
    line-height: 1.1;
    /* ⚠️ 符号必须贴着数字走，不能钉在固定的符号列上。
       原本是 grid「符号列 + 数字列」：数字在自己列里右对齐，所以「-7」这种
       一位数行，符号留在列左端、数字跑到列右端，中间空出大半个字宽 ——
       看起来像跟题目无关的孤零零一个减号（用户反馈「减号离题目太远」）。
       改成整行右对齐的 flex：符号与数字自然相邻，个位仍靠右边界对齐，
       竖式的「个位对个位」照旧成立。 */
    display: flex;
    justify-content: flex-end;
    gap: 0.06em;
    align-items: center;
    width: 100%;
    /* 等宽数字：珠心算竖式必须个位对个位，靠它保证各行同位数字等宽 */
    font-variant-numeric: tabular-nums;
}

.v2-look-item .symbol {
    opacity: 0.8;
}

.v2-look-item .val {
    text-align: right;
}

/* ⚠️ REMARK: 看算「滚动显示」模式 — 由 LookEngineV2.js renderQuestion() 加 .v2-look-scrolling，
   动画本身用 Web Animations API 在 startScroll() 里跑（需要 pause/play，CSS animation 不好控）。
   这里只负责把容器变成一个「窗口」：超出部分裁掉，数字才会从下方进、上方出。 */
.v2-look-simple-container.v2-look-scrolling {
    position: relative;
    overflow: hidden;
    /* 纵向改从顶部起算，位置全交给 translateY 控制；
       ⚠️ 只动 justify-content（纵轴），不能动 align-items —— 这是 column 布局里的
       「横向居中」，数字列靠它待在屏幕中间。曾误用 position:absolute+left/right:0
       把列撑成满屏宽，.val 的 text-align:right 就把数字全顶到右边缘去了。 */
    justify-content: flex-start;
}

.v2-look-simple-container.v2-look-scrolling .v2-look-list {
    /* 内容比窗口高时不许被 flex 压扁——滚动模式本来就指望它超出 */
    flex: 0 0 auto;
    /* 提前提升到合成层，长列表滚动才不掉帧 */
    will-change: transform;
}

/* ⚠️ REMARK: 加减法分割线（看算模式）— 样式由 LookEngineV2.js renderQuestion() 引用 */
.v2-look-divider {
    width: 100%;
    height: 4px;
    background: var(--v2-display-divider, #333);
    box-shadow: var(--v2-display-divider-glow, none);
    margin: 15px 0;
    border-radius: 2px;
}


.v2-look-numpad-wrap {
    transform: scale(0.9);
    margin-top: -10px;
}

/* 迷你反馈动画 */
.v2-mini-feedback {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: white;
    border: 4px solid currentColor;
    padding: 20px 40px;
    border-radius: 30px;
    text-align: center;
    z-index: 200;
    box-shadow: 0 10px 30px rgba(0,0,0,0.1);
    animation: v2MiniPop 1.2s forwards;
}

@keyframes v2MiniPop {
    0% { opacity: 0; transform: translate(-50%, -40%) scale(0.8); }
    20% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    80% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -60%) scale(0.9); }
}

/* ══════════════════════════════════════════════
   LISTEN MODE V2 (听算)
   ═══════════════════════════════════════════════ */

.v2-listen-stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 300px;
    height: auto;
}

.v2-listen-visualizer {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 60px;
    margin-bottom: 20px;
}

.v2-wave {
    width: 12px;
    height: 40px;
    background: var(--v2-primary);
    border-radius: 10px;
    animation: v2Wave 1s ease-in-out infinite;
}

.v2-wave:nth-child(2) { animation-delay: 0.2s; height: 60px; }
.v2-wave:nth-child(3) { animation-delay: 0.4s; }

@keyframes v2Wave {
    0%, 100% { transform: scaleY(0.5); opacity: 0.5; }
    50% { transform: scaleY(1.2); opacity: 1; }
}

.v2-listen-msg {
    /* 下限按视宽收，长串(Listen carefully…)换行也居中不贴边 */
    font-size: clamp(34px, 11vw, 80px);
    font-weight: 900;
    color: var(--v2-muted);
    letter-spacing: 2px;
    width: 100%;
    text-align: center;
    padding: 0 16px;
    box-sizing: border-box;
    line-height: 1.15;
    overflow-wrap: break-word;
}

/* ══════════════════════════════════════════════
   READY SCREEN & COUNTDOWN
   ══════════════════════════════════════════════ */

.v2-ready-card {
    background: white;
    padding: 40px 30px;
    border-radius: var(--v2-radius-card);
    border: var(--v2-card-border);
    box-shadow: var(--v2-shadow-soft);
    text-align: center;
    max-width: 1000px;
    width: 90%;
    margin: 40px auto;
    animation: v2-pop-in 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.v2-ready-icon {
    font-size: 60px;
    margin-bottom: 15px;
}

.v2-ready-title {
    font-size: 28px;
    font-weight: 900;
    color: var(--v2-primary);
    margin-bottom: 10px;
}

.v2-ready-detail {
    display: flex;
    justify-content: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 30px;
    font-size: 14px;
    color: var(--v2-muted);
}

.v2-ready-btn {
    background: var(--v2-secondary);
    color: white;
    border: none;
    padding: 18px 40px;
    border-radius: 25px;
    font-size: 20px;
    font-weight: 900;
    box-shadow: 0 8px 0 #388E3C;
    cursor: pointer;
    transition: var(--v2-transition-fast);
    width: 100%;
}

.v2-ready-btn:active {
    transform: translateY(4px);
    box-shadow: 0 4px 0 #388E3C;
}

.v2-countdown-circle {
    font-size: 120px;
    font-weight: 900;
    color: var(--v2-primary);
    text-shadow: 0 10px 0 rgba(0,0,0,0.1);
    animation: v2-pulse 0.8s infinite alternate;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
}

@keyframes v2-pop-in {
    from { transform: scale(0.8); opacity: 0; }
    to { transform: scale(1); opacity: 1; }
}

@keyframes v2-pulse {
    from { transform: scale(0.9); }
    to { transform: scale(1.1); }
}

.v2-round-splash {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    width: 100%;
}

.v2-round-splash .label {
    /* 响应式：大屏放大 */
    font-size: clamp(18px, 4vmin, 44px);
    font-weight: 900;
    color: var(--v2-muted);
    letter-spacing: 4px;
    margin-bottom: 5px;
}

.v2-round-splash .num {
    /* 响应式：手机适中，电子白板/投屏自动放大。
       下限按视宽(vw)收，保证「Question N」这种长英文串单行居中不溢出贴边。 */
    font-size: clamp(44px, 13vw, 260px);
    font-weight: 900;
    color: var(--v2-primary);
    line-height: 1.1;
    width: 100%;
    text-align: center;
    padding: 0 16px;
    box-sizing: border-box;
    word-break: keep-all;
    overflow-wrap: break-word;
}

/* Toggle Switch */
.v2-toggle-container { display: flex; align-items: center; gap: 12px; cursor: pointer; background: #F8F9FA; padding: 8px 16px; border-radius: 20px; border: 2px solid #EEE; transition: var(--v2-transition); touch-action: manipulation; user-select: none; -webkit-user-select: none; }
.v2-toggle-container:active { transform: scale(0.95); }
.v2-toggle-inline-container { display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--v2-transition); touch-action: manipulation; user-select: none; -webkit-user-select: none; }
.v2-toggle-inline-container:active { transform: scale(0.95); }
.v2-toggle { width: 44px; height: 24px; background: #DDD; border-radius: 12px; position: relative; transition: all 0.3s; }
.v2-toggle.active { background: var(--v2-secondary); }
.v2-toggle-thumb { width: 18px; height: 18px; background: white; border-radius: 50%; position: absolute; top: 3px; left: 3px; transition: all 0.3s; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.v2-toggle.active .v2-toggle-thumb { left: 23px; }
/* ⚠️ .v2-toggle-container 底色固定 #F8F9FA，字色不能用深色主题下会变浅的
   --v2-muted，否则星河等主题下浅底浅字看不见 */
.v2-toggle-label-text { font-size: 14px; font-weight: 900; color: #6B7280; }

/* ══════════════════════════════════════════════
   V2 AUTH & PROFILE (Neumorphism & Bento)
   ═══════════════════════════════════════════════ */

/* Profile Bento Card */
.v2-profile-trigger.v2-card-profile {
    background: linear-gradient(135deg, #f5f3ff, #ede9fe) !important;
    border: var(--v2-card-border) !important;
    box-shadow: var(--v2-shadow-soft) !important;
    display: flex !important;
}

.v2-profile-trigger.v2-card-profile .v2-avatar-mini {
    background: linear-gradient(135deg, #8b5cf6, #7c3aed) !important;
    color: white !important;
}

/* Profile Trigger on Main Menu */
.v2-profile-trigger {
    grid-column: span 2;
    display: flex;
    align-items: center;
    gap: 15px;
    padding: 15px 25px;
    background: var(--v2-bg);
    box-shadow: var(--v2-shadow-flat);
    border-radius: 20px;
    cursor: pointer;
    margin-bottom: 10px;
    transition: all 0.2s ease;
}

.v2-profile-trigger:active {
    box-shadow: var(--v2-shadow-inner);
    transform: scale(0.98);
}

.v2-avatar-mini {
    width: 40px;
    height: 40px;
    background: var(--v2-surface);
    box-shadow: var(--v2-shadow-raised);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}

#v2-username-main {
    font-weight: 800;
    font-size: 16px;
    color: var(--v2-text);
}

/* Auth Form & Inputs */
.v2-neu-form {
    padding: 10px;
}

.v2-input-label {
    display: block;
    font-size: 13px;
    font-weight: 800;
    /* ⚠️ 常用于 .v2-setting-card 等固定白底容器内，字色不能用深色
       主题下会变近白的 --v2-text，否则星河等主题下浅底浅字看不见 */
    color: #374151;
    margin-bottom: 10px;
    margin-left: 5px;
}

.v2-neu-input-wrap {
    background: var(--v2-bg);
    box-shadow: var(--v2-shadow-inner);
    border-radius: 18px;
    padding: 5px 15px;
    display: flex;
    align-items: center;
}

.v2-neu-input {
    width: 100%;
    height: 50px;
    background: transparent;
    border: none;
    outline: none;
    font-family: inherit;
    font-size: 16px;
    font-weight: 700;
    color: var(--v2-text-main, var(--v2-text));
}

/* ⚠️ .v2-neu-input 本身透明无边框，是设计给「已有凹陷阴影的容器」用的——
   发书登记的搜索框套在 .v2-neu-card（按钮卡片，没有凹陷效果）里，
   整个框在深色主题下完全隐形，只剩淡灰 placeholder，学生反馈「看不到
   search bar」。补上独立的背景/边框/placeholder 颜色，别改全局
   .v2-neu-input（怕连累其它借用这个 class 的地方）。 */
.bd-search-input {
    background: var(--v2-bg-main, rgba(255,255,255,0.06)) !important;
    border: 2px solid var(--v2-border-main, #E0D0B0) !important;
    border-radius: 12px !important;
    padding: 0 14px !important;
    height: 46px !important;
}
.bd-search-input:focus {
    border-color: var(--v2-primary) !important;
}
.bd-search-input::placeholder {
    color: var(--v2-muted, #94A3B8);
    opacity: 0.85;
    font-weight: 600;
}

.v2-neu-btn-primary {
    background: var(--v2-primary);
    color: white;
    border: none;
    border-radius: 20px;
    padding: 18px;
    font-size: 16px;
    font-weight: 900;
    box-shadow: 6px 6px 12px rgba(108, 99, 255, 0.3);
    cursor: pointer;
    transition: var(--v2-transition);
}

.v2-neu-btn-primary:active {
    transform: scale(0.96);
    filter: brightness(0.9);
}

/* Loading Spinner inside Buttons */
.v2-btn-loading-spinner {
    display: inline-block;
    width: 18px;
    height: 18px;
    border: 3px solid rgba(255, 255, 255, 0.35);
    border-radius: 50%;
    border-top-color: #FFF;
    animation: v2SpinnerRotate 0.8s linear infinite;
    margin-right: 10px;
    vertical-align: middle;
}

@keyframes v2SpinnerRotate {
    to { transform: rotate(360deg); }
}

/* Profile Specific */
.v2-profile-avatar {
    width: 70px;
    height: 70px;
    background: var(--v2-surface);
    box-shadow: var(--v2-shadow-raised);
    border-radius: 25px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 35px;
}

.v2-badge-gold {
    background: linear-gradient(135deg, #f59e0b, #d97706);
    color: white;
    font-size: 10px;
    font-weight: 900;
    padding: 3px 10px;
    border-radius: 8px;
    text-transform: uppercase;
    box-shadow: 0 4px 10px rgba(217, 119, 6, 0.3);
}

.v2-badge-silver {
    background: #E2E8F0;
    color: #475569;
    font-size: 10px;
    font-weight: 900;
    padding: 3px 10px;
    border-radius: 8px;
    text-transform: uppercase;
}

.v2-card-mini-title {
    font-size: 14px;
    font-weight: 800;
    opacity: 0.7;
    width: 100%;
    max-width: 1000px;
    margin: 0 auto;
    box-sizing: border-box;
    padding: 0 15px;
}

.v2-neu-btn-action {
    background: var(--v2-secondary);
    color: white;
    border: none;
    border-radius: 15px;
    padding: 0 20px;
    font-weight: 800;
    box-shadow: var(--v2-shadow-raised);
    cursor: pointer;
}

.v2-neu-btn-action:active {
    box-shadow: var(--v2-shadow-inner);
    transform: translateY(2px);
}

.v2-menu-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 18px 15px;
    border-radius: 15px;
    cursor: pointer;
    transition: var(--v2-transition);
}

.v2-menu-item:hover {
    background: rgba(0,0,0,0.03);
}

.v2-menu-item:active {
    background: rgba(0,0,0,0.06);
    transform: translateX(5px);
}

.v2-menu-item span {
    font-weight: 700;
    font-size: 15px;
}

.v2-menu-item i {
    opacity: 0.4;
    font-size: 12px;
}

/* V2 Teacher Console Specifics */
.v2-neu-select {
    background: var(--v2-bg);
    box-shadow: var(--v2-shadow-inner);
    border: none;
    border-radius: 12px;
    padding: 8px 12px;
    font-family: inherit;
    font-weight: 800;
    color: var(--v2-text);
    outline: none;
    appearance: none;
    cursor: pointer;
}

.v2-neu-btn-mini {
    background: var(--v2-bg);
    box-shadow: var(--v2-shadow-raised);
    border: none;
    border-radius: 12px;
    padding: 8px 15px;
    font-size: 12px;
    font-weight: 900;
    color: var(--v2-text);
    cursor: pointer;
    transition: var(--v2-transition);
}

.v2-neu-btn-mini:active {
    box-shadow: var(--v2-shadow-inner);
    transform: translateY(2px);
}

.v2-stat-num {
    font-family: 'Outfit', sans-serif;
    font-weight: 900;
}

/* Teacher Center Bento Card - Main Menu Version */
.v2-card-teacher {
    background: linear-gradient(135deg, #fffbeb, #fef3c7) !important;
    border: var(--v2-card-border) !important;
    box-shadow: var(--v2-shadow-soft) !important;
    transition: all 0.2s ease;
}

.v2-card-teacher:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none !important;
}

.v2-card-teacher .v2-neu-icon {
    background: #fbbf24 !important;
    color: white !important;
    box-shadow: 0 4px 10px rgba(217, 119, 6, 0.2);
}

/* Profile Bento Card */
.v2-card-profile {
    background: var(--v2-bg) !important;
    border: var(--v2-card-border) !important;
    box-shadow: var(--v2-shadow-soft) !important;
    transition: all 0.2s ease;
}

.v2-card-profile:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none !important;
}

.v2-card-profile .v2-avatar-mini {
    background: linear-gradient(135deg, #3b82f6, #2563eb) !important;
    box-shadow: 0 4px 10px rgba(37, 99, 235, 0.3);
}

/* V2 GRADER & SCORING STATION */
.v2-grader-dashboard {
  background: white;
  border: var(--v2-card-border);
  border-radius: var(--v2-radius-card);
  padding: 16px 20px;
  box-shadow: var(--v2-shadow-soft);
  animation: v2GraderPop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.v2-grader-board-card {
  width: 100%;
}
.v2-board-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;       /* 窄屏时分数与统计换行，避免挤成一团 */
  gap: 10px 16px;
}
.v2-board-score {
  font-size: 42px;
  font-weight: 900;
  color: var(--v2-primary);
  font-family: 'Outfit', sans-serif;
  display: flex;
  align-items: baseline;
  line-height: 1;
}
.v2-score-unit {
  font-size: 14px;
  font-weight: 800;
  /* ⚠️ .v2-grader-dashboard 底色固定白，字色不能用深色主题下会变浅的
     --v2-muted，否则星河等主题下浅底浅字看不见 */
  color: #6B7280;
  margin-left: 4px;
}
.v2-board-divider {
  width: 2px;
  height: 44px;
  background: var(--v2-border-main);
  margin: 0 20px;
  opacity: 0.6;
}
.v2-board-stats {
  display: flex;
  gap: 20px;
  flex: 1 1 220px;   /* 可伸缩，但窄到放不下时整块换到下一行 */
  justify-content: space-around;
}
.v2-board-stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.v2-stat-label {
  font-size: 11px;
  font-weight: 900;
  /* ⚠️ .v2-grader-dashboard 底色固定白，字色不能用深色主题下会变浅的
     --v2-muted，否则星河等主题下浅底浅字看不见 */
  color: #6B7280;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 4px;
}
.v2-stat-val {
  font-size: 18px;
  font-weight: 900;
  color: #1F2937;
}

.v2-grader-grid {
  /* ⚠️ 一题一行，不分列。曾用 auto-fill + minmax(96px) 自动分列，手机上
     排成 3 列、每张卡只有 123px 宽 —— 老师核对答案时要横着扫三格再换行，
     很难跟纸上的题号对齐(用户反馈「每三题一行很不方便」)。
     改成单列后卡片整行铺开，答案字号也能放大，一眼从上往下核到底。 */
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  padding: 10px 0;
  width: 100%;
  box-sizing: border-box;
}
/* 平板/电脑横向空间富余时才分两列，手机永远单列 */
@media (min-width: 820px) {
  .v2-grader-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }
}
@media (max-width: 600px) {
  .v2-grader-grid {
    gap: 6px;
    padding: 6px 0;
  }
}

.v2-grader-card {
  background: #FDFDFD;
  border-radius: var(--v2-radius-chip);
  /* 整行卡片要有足够点击高度：这是老师逐题点对错的主操作区，
     44px 是触控最小尺寸(padding 10 + 内容 26 = 46px) */
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: var(--v2-card-border);
  box-shadow: var(--v2-shadow-soft);
  transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  cursor: pointer;
  user-select: none;
  box-sizing: border-box;
  animation: v2GraderPop 0.4s ease backwards;
}
.v2-grader-card:active {
  transform: scale(0.95);
}
.v2-grader-card.is-correct {
  background: #E8F5E9 !important;
  border-color: #4CAF50 !important;
  box-shadow: 0 4px 0 #388E3C !important;
}
.v2-grader-card.is-correct .v2-grader-val {
  color: #2E7D32 !important;
}
.v2-grader-card.is-correct .v2-grader-idx {
  background: rgba(76, 175, 80, 0.15) !important;
  color: #2E7D32 !important;
}
.v2-grader-card.is-correct .v2-grader-status-icon {
  color: #2E7D32 !important;
}

.v2-grader-card.is-wrong {
  background: #FFEBEE !important;
  border-color: #FF5252 !important;
  box-shadow: 0 4px 0 #C62828 !important;
}
.v2-grader-card.is-wrong .v2-grader-val {
  color: #C62828 !important;
  text-decoration: line-through;
}
.v2-grader-card.is-wrong .v2-grader-idx {
  background: rgba(255, 82, 82, 0.15) !important;
  color: #C62828 !important;
}
.v2-grader-card.is-wrong .v2-grader-status-icon {
  color: #C62828 !important;
}

.v2-grader-card-left {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1;
}
/* 单列后横向空间充裕，题号/答案都放大 —— 老师是拿着手机对纸核分的，
   16px 的答案在 123px 窄卡里还行，整行铺开后就显得小了。 */
.v2-grader-idx {
  width: 26px;
  height: 26px;
  background: rgba(0,0,0,0.05);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 900;
  color: #7A8B99;
  flex-shrink: 0;
  transition: all 0.2s ease;
}
.v2-grader-val {
  font-family: 'Outfit', sans-serif;
  font-size: 22px;
  font-weight: 900;
  /* ⚠️ .v2-grader-card 底色固定 #FDFDFD，字色不能用深色主题下会变近白的
     --v2-text-dark，否则星河等主题下浅底浅字看不见（.is-correct/.is-wrong
     态有自己的!important覆盖，不受影响） */
  color: #1F2937;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: all 0.2s ease;
}
.v2-grader-status-icon {
  font-size: 18px;
  font-weight: 900;
  margin-left: 4px;
  flex-shrink: 0;
  transition: all 0.2s ease;
}

@keyframes v2GraderPop {
  0% { transform: scale(0.9) translateY(10px); opacity: 0; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}

@media (max-width: 600px) {
  /* .v2-grader-grid 现在固定单列(≥820px 才两列)，这里只调评分大盘 */
  .v2-board-score {
    font-size: 34px;
  }
  .v2-board-divider {
    display: none;   /* 窄屏分数与统计会换行，竖分隔线失去意义 */
  }
  .v2-board-stats {
    gap: 10px;
    justify-content: flex-start;
  }
  .v2-stat-val {
    font-size: 15px;
  }
}

/* ══════════════════════════════════════════════
   LEGACY COMPONENTS — migrated & updated to V2 tokens
   ═══════════════════════════════════════════════ */

/* ── TOAST ──────────────────────────────────── */
#toast {
  position: fixed;
  bottom: 32px;
  left: 50%;
  transform: translateX(-50%) translateY(100px);
  background: var(--v2-bg-main);
  border: var(--v2-card-border);
  color: var(--v2-text);
  padding: 12px 20px;
  border-radius: 999px;
  font-size: var(--v2-size-sm);
  font-weight: var(--v2-weight-normal);
  z-index: 200000;
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  white-space: nowrap;
  box-shadow: var(--v2-shadow-soft);
}
#toast.show { transform: translateX(-50%) translateY(0); }

/* ── SCROLLABLE CONTENT ─────────────────────── */
.scroll-content {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
}
.scroll-content::-webkit-scrollbar { width: 4px; }
.scroll-content::-webkit-scrollbar-thumb { background: var(--v2-border-main); border-radius: 2px; }

/* ── STATUS COLOURS ─────────────────────────── */
.correct       { color: var(--v2-green); }
.wrong         { color: var(--v2-red); }
.wrong-user    { background: rgba(239,68,68,0.1);  color: var(--v2-red); }
.correct-user  { background: rgba(34,197,94,0.1);  color: var(--v2-green); }

/* ── ANSWER FEEDBACK POPUP ──────────────────── */
.feedback-overlay {
  position: fixed;
  inset: 0;
  background: rgba(255,249,230,0.7);
  backdrop-filter: blur(6px);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  opacity: 0;
  transition: opacity 0.2s;
}
.feedback-overlay.active { display: flex; opacity: 1; }

.feedback-card {
  /* ⚠️ --v2-surface 在太空/星河/月光深色主题下已改深色，
     但 .feedback-sub 文字是写死的 #6B7280 深灰，不跟主题走，
     深底配深字会看不清，这里固定白底保证对比度 */
  background: #fff;
  border: var(--v2-card-border);
  border-radius: var(--v2-radius-card);
  padding: 40px;
  width: 280px;
  max-width: 90vw;
  text-align: center;
  transform: scale(0.5);
  transition: var(--v2-transition-pop);
  box-shadow: 0 20px 0 var(--v2-border-main);
}
.feedback-overlay.active .feedback-card { transform: scale(1); }
.feedback-icon  { font-size: 80px; line-height: 1; margin-bottom: 20px; display: block; }
.feedback-text  { font-size: 32px; font-weight: var(--v2-weight-heavy); margin-bottom: 8px; }
.feedback-sub   { font-size: var(--v2-size-body); color: #6B7280; font-weight: var(--v2-weight-normal); }

.feedback-card.is-correct { border-color: var(--v2-green);     box-shadow: 0 20px 0 var(--v2-green-dark); }
.feedback-card.is-correct .feedback-text { color: var(--v2-green-dark); }
.feedback-card.is-wrong   { border-color: var(--v2-red);       box-shadow: 0 20px 0 var(--v2-red-dark); }
.feedback-card.is-wrong   .feedback-text { color: var(--v2-red-dark); }

/* ── VIRTUAL ABACUS ─────────────────────────── */
.abacus-container {
  background: #fdf6e3;
  border: 8px solid #8b5e3c;
  border-radius: 20px;
  padding: 20px 30px;
  display: inline-flex;
  gap: 32px;
  box-shadow: 0 10px 0 #5d3a24, inset 0 2px 10px rgba(0,0,0,0.1);
  position: relative;
  margin-top: 20px;
  touch-action: none;
}
.abacus-reset-lever {
  position: absolute;
  top: -18px; left: 25px; right: 25px;
  height: 24px;
  background: var(--v2-primary);
  border: 2px solid var(--v2-primary-dark);
  border-radius: 12px;
  box-shadow: 0 5px 0 var(--v2-primary-dark);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; letter-spacing: 3px;
  font-weight: var(--v2-weight-heavy);
  color: var(--v2-surface);
  text-transform: uppercase;
  z-index: 30;
  transition: var(--v2-transition-fast);
  user-select: none;
}
.abacus-reset-lever:active { transform: translateY(3px); box-shadow: 0 2px 0 var(--v2-primary-dark); }
.abacus-reset-lever::before {
  content: '';
  position: absolute;
  left: 15px; right: 15px; top: 4px;
  height: 3px;
  background: rgba(255,255,255,0.2);
  border-radius: 2px;
}
.abacus-rod {
  width: 64px; height: 300px;
  position: relative;
  display: flex; flex-direction: column; align-items: center;
}
.abacus-rod::before {
  content: '';
  position: absolute; top: 0; bottom: 0;
  width: 4px;
  background: #d4a574;
  border-radius: 2px;
  box-shadow: inset 1px 0 2px rgba(0,0,0,0.2);
}
.abacus-divider-bar {
  position: absolute;
  top: 85px; left: -15px; right: -15px;
  height: 12px;
  background: #8b5e3c;
  z-index: 10;
  border-radius: 6px;
}
.abacus-divider-bar.has-dot::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%,-50%);
  width: 6px; height: 6px;
  background: var(--v2-surface);
  border-radius: 50%;
}
.bead {
  width: 76px; height: 44px;
  border-radius: 22px;
  position: absolute;
  z-index: 5;
  transition: all 0.15s cubic-bezier(0.18, 0.89, 0.32, 1.28);
  cursor: pointer;
  pointer-events: all;
  touch-action: none;
  user-select: none;
}
.bead:active { filter: brightness(1.3); transform: scale(1.05); }
.bead-up  { background: linear-gradient(to bottom,#ffcc33,#e6b800); box-shadow: 0 4px 0 #b38f00, inset 0 2px 4px rgba(255,255,255,0.6); top: 5px; }
.bead-up.active { top: 38px; }
.bead-down { background: linear-gradient(to bottom,#a0522d,#8b4513); box-shadow: 0 4px 0 #5d2e0a, inset 0 2px 4px rgba(255,255,255,0.3); }
.bead-down-1 { bottom:145px; } .bead-down-2 { bottom:98px; }
.bead-down-3 { bottom:51px;  } .bead-down-4 { bottom:4px;  }
.bead-down-1.active { bottom:162px; } .bead-down-2.active { bottom:115px; }
.bead-down-3.active { bottom:68px;  } .bead-down-4.active { bottom:21px;  }
.abacus-label {
  position: absolute; bottom: -22px;
  font-family: var(--v2-font-main);
  font-size: var(--v2-size-sm);
  font-weight: var(--v2-weight-bold);
  color: #8b5e3c;
}
.abacus-tool-controls { padding: 24px 0; display: flex; flex-direction: column; align-items: center; gap: 16px; }

/* ── LOOK ENGINE — number display ───────────── */
.look-list {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  margin: auto;
  padding: 40px 0;
  font-variant-numeric: tabular-nums;
  min-width: 160px;
}
.look-list.dense .look-number       { font-size: 36px; }
.look-list.ultra-dense              { gap: 4px; }
.look-list.ultra-dense .look-number { font-size: 24px; }

.look-number {
  font-family: 'JetBrains Mono', var(--v2-font-num);
  font-size: 64px;
  font-weight: var(--v2-weight-heavy);
  line-height: 1.1;
  color: var(--v2-text);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  width: 100%;
}
.look-number.negative { color: var(--v2-red-dark); }
.look-number.len-4  { font-size: 42px !important; }
.look-number.len-5  { font-size: 38px !important; }
.look-number.len-6  { font-size: 34px !important; }
.look-number.len-7  { font-size: 31px !important; }
.look-number.len-8, .look-number.len-9  { font-size: 28px !important; }
.look-number.len-10,.look-number.len-11 { font-size: 24px !important; }
.look-number.len-12,.look-number.len-13 { font-size: 20px !important; }

.look-divider-double {
  width: 100%;
  height: 80px;
  border-top: 4px solid var(--v2-text);
  border-bottom: 4px solid var(--v2-text);
  margin-top: 10px;
}
.look-mask {
  position: absolute; inset: 0;
  background: rgba(255,249,230,0.9);
  backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center;
  font-size: 64px;
  font-weight: var(--v2-weight-heavy);
  color: var(--v2-primary);
  opacity: 0; visibility: hidden;
  transition: all 0.3s ease;
  z-index: 10;
}
.look-mask.active { opacity: 1; visibility: visible; }

/* ── RESULT ITEMS (rendered by TrainingCore) ─── */
.result-list        { display: flex; flex-direction: column; gap: 10px; padding: 10px 0; }
.result-list-header { font-size: var(--v2-size-md); font-weight: var(--v2-weight-bold); color: var(--v2-muted); margin-bottom: 10px; padding-left: 5px; }
.result-item {
  /* ⚠️ 要「永远白底 + 固定深字」，不能读 --v2-surface：太空冒险/星河/月光
     主题已把它改成深色开关，读它会跟下面 .ri-expr 写死的深字撞成深底深字。 */
  background: #fff;
  border-radius: var(--v2-radius-chip);
  padding: 12px 16px;
  display: flex; align-items: center; gap: 12px;
  border: var(--v2-card-border);
  box-shadow: var(--v2-shadow-soft);
}
.ri-num  { width:24px; height:24px; background:var(--v2-bg-main); border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:var(--v2-weight-bold); color:var(--v2-muted); flex-shrink:0; }
/* ⚠️ .result-item 底色固定 --v2-surface（各主题都是白），字色不能用
   深色主题下会变近白的 --v2-text，否则星河等主题下浅底浅字看不见 */
.ri-expr { flex:1; font-family:var(--v2-font-num); font-size:15px; font-weight:700; color:#1F2937; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ri-ans  { font-family:var(--v2-font-num); font-weight:var(--v2-weight-heavy); font-size:var(--v2-size-body); color:var(--v2-green-dark); }
.ri-user { font-family:var(--v2-font-num); font-weight:var(--v2-weight-heavy); font-size:var(--v2-size-body); min-width:40px; text-align:right; }
.ri-user.correct-user { color: var(--v2-green-dark); }
.ri-user.wrong-user   { color: var(--v2-red); text-decoration: line-through; opacity: 0.6; }
.ri-icon { font-size: var(--v2-size-md); flex-shrink: 0; }

/* ── WORKSHEET PRINT ────────────────────────── */
.ws-print-header { border-bottom: 2px solid black; padding-bottom: 10px; margin-bottom: 30px; display: flex; justify-content: space-between; align-items: flex-end; }
.ws-print-grid   { display: grid; grid-template-columns: repeat(10,1fr); gap: 20px 10px; }
.ws-item         { border: 1px solid #cbd5e1; border-radius: 8px; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,0.02); padding: 10px 5px; display: flex; flex-direction: column; align-items: center; }
.ws-num-list     { font-family: var(--v2-font-main); font-size: var(--v2-size-body); text-align: right; width: 100%; margin-bottom: 10px; line-height: 1.4; }
.ws-ans-box      { width: 100%; height: 30px; border: 1px solid #475569; border-radius: 6px; background: #f8fafc; margin-top: auto; }
.ws-idx          { font-size: var(--v2-size-xs); color: var(--v2-muted); margin-bottom: 5px; }
.ws-select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px;
}

/* ── DEBUG TOOL ─────────────────────────────── */
.debug-question-card { background: var(--v2-surface); border-radius: var(--v2-radius-chip); padding: 16px; margin-bottom: 20px; box-shadow: var(--v2-shadow-soft); border: var(--v2-card-border); }
.debug-item { transition: var(--v2-transition); }
.debug-item:hover { transform: translateY(-2px); }
#debug-results-list { padding-bottom: 40px; }
#persistent-debug-btn { animation: debug-pulse 2s infinite; transition: var(--v2-transition-fast); }
#persistent-debug-btn:active { transform: scale(0.9); }
@keyframes debug-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(245,158,11,0.7); }
  70%  { box-shadow: 0 0 0 15px rgba(245,158,11,0);   }
  100% { box-shadow: 0 0 0 0   rgba(245,158,11,0);   }
}

/* ── PRINT MEDIA ────────────────────────────── */
@media print {
  body { background: white !important; padding: 0 !important; margin: 0 !important; }
  .no-print, .bg-orb, .v2-header, .v2-footer { display: none !important; }
  #app { overflow: visible !important; min-height: auto !important; }
  .v2-screen { display: none !important; }
  #screen-worksheet-print { display: block !important; }
}

/* ── KEYFRAMES ANIMATIONS ─────────────────────── */
@keyframes popUp {
  from { transform: scale(0.8); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}
@keyframes v2BadgeBounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
}
.v2-hw-badge {
  animation: v2BadgeBounce 2s infinite ease-in-out;
}

/* ══════════════════════════════════════════════
   QR SCANNER VIEWPORT (V2 Premium Style)
   ═══════════════════════════════════════════════ */
.v2-scanner-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
    background: rgba(0, 0, 0, 0.45);
    z-index: 10;
    box-sizing: border-box;
    padding: 40px 20px;
}

.v2-scanner-header {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 15px;
    z-index: 20;
    padding: 10px;
}

.v2-scanner-header .v2-round-btn {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    border: 1.5px solid rgba(255, 255, 255, 0.3);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition: var(--v2-transition-fast);
}

.v2-scanner-header .v2-round-btn:active {
    transform: scale(0.9);
    background: rgba(255, 255, 255, 0.3);
}

.v2-scanner-title {
    font-size: 20px;
    font-weight: 900;
    color: white;
    text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.v2-scanner-frame-wrap {
    width: 280px;
    height: 280px;
    position: relative;
    border-radius: 28px;
    overflow: hidden;
    box-shadow: 0 0 0 4000px rgba(0, 0, 0, 0.6); /* Viewport mask */
    border: 2px solid rgba(255, 255, 255, 0.25);
    z-index: 15;
}

/* Viewfinder Corners */
.v2-scanner-corners {
    position: absolute;
    inset: 10px;
    pointer-events: none;
    z-index: 18;
    background: 
        linear-gradient(to right, var(--v2-primary) 4px, transparent 4px) 0 0,
        linear-gradient(to bottom, var(--v2-primary) 4px, transparent 4px) 0 0,
        linear-gradient(to left, var(--v2-primary) 4px, transparent 4px) 100% 0,
        linear-gradient(to bottom, var(--v2-primary) 4px, transparent 4px) 100% 0,
        linear-gradient(to right, var(--v2-primary) 4px, transparent 4px) 0 100%,
        linear-gradient(to top, var(--v2-primary) 4px, transparent 4px) 0 100%,
        linear-gradient(to left, var(--v2-primary) 4px, transparent 4px) 100% 100%,
        linear-gradient(to top, var(--v2-primary) 4px, transparent 4px) 100% 100%;
    background-size: 20px 20px;
    background-repeat: no-repeat;
}

/* Laser scanning horizontal line animation */
.v2-scanner-corners::after {
    content: '';
    position: absolute;
    left: 0;
    width: 100%;
    height: 4px;
    background: linear-gradient(90deg, transparent, var(--v2-primary), transparent);
    box-shadow: 0 0 12px var(--v2-primary), 0 0 4px var(--v2-primary);
    z-index: 17;
    animation: v2ScannerLaser 2.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
    pointer-events: none;
}

@keyframes v2ScannerLaser {
    0% { top: 0%; opacity: 0; }
    5% { opacity: 1; }
    95% { opacity: 1; }
    100% { top: 100%; opacity: 0; }
}

.v2-scanner-footer {
    width: 100%;
    display: flex;
    justify-content: center;
    z-index: 20;
    padding: 10px;
}

.v2-scanner-hint {
    background: rgba(0, 0, 0, 0.65);
    color: #FFF;
    padding: 10px 20px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 800;
    letter-spacing: 0.5px;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.15);
    text-align: center;
    box-shadow: 0 4px 12px rgba(0,0,0,0.25);
    animation: v2ScannerPulse 1.5s ease-in-out infinite alternate;
}

@keyframes v2ScannerPulse {
    from { transform: scale(1); border-color: rgba(255, 255, 255, 0.15); }
    to { transform: scale(1.02); border-color: var(--v2-primary); }
}


/* ══════════════════════════════════════════════
   HALL OF FAME — Achievements & Leaderboard
   ═══════════════════════════════════════════════ */

.hof-badges-grid {
    display: flex;
    flex-direction: column;
    gap: 24px;
    width: 100%;
}

.hof-group {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.hof-group-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 6px 4px 4px;
    border-bottom: 2px dashed rgba(0,0,0,0.08);
}

.hof-group-title {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.hof-group-title-zh {
    font-size: 16px;
    font-weight: 900;
    color: #1f2937;
}

.hof-group-title-en {
    font-size: 11px;
    font-weight: 600;
    color: #6b7280;
    opacity: 0.75;
    letter-spacing: 0.3px;
}

.hof-group-progress {
    font-size: 12px;
    font-weight: 800;
    color: #4b5563;
    background: rgba(255,255,255,0.7);
    padding: 4px 10px;
    border-radius: 999px;
    box-shadow: inset 1px 1px 3px rgba(163,177,198,0.4),
                inset -1px -1px 3px rgba(255,255,255,0.9);
}

.hof-group-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 10px;
}

@media (max-width: 720px) {
    .hof-group-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

.hof-badge {
    background: #E6EAF0;
    border: 1px solid rgba(255,255,255,0.85);
    border-radius: 20px;
    padding: 16px 10px 14px;
    text-align: center;
    box-shadow: 6px 6px 14px rgba(163,177,198,0.5),
                -6px -6px 14px rgba(255,255,255,0.85);
    transition: transform 0.2s ease;
    position: relative;
    overflow: hidden;
}

.hof-badge.unlocked {
    background: linear-gradient(145deg, #FFFFFF, #FFFBEB);
    border-top: 3px solid var(--ach-color, #F59E0B);
}

.hof-badge.unlocked:hover {
    transform: translateY(-2px);
}

.hof-badge.locked {
    opacity: 0.55;
    filter: grayscale(0.7);
}

.hof-badge-icon {
    font-size: 38px;
    line-height: 1;
    margin-bottom: 8px;
    filter: drop-shadow(0 3px 6px rgba(0,0,0,0.12));
}

.hof-badge-title {
    font-weight: 900;
    font-size: 14px;
    color: #1F2937;
}

.hof-badge-title-en {
    font-weight: 600;
    font-size: 10px;
    opacity: 0.65;
    margin-top: 1px;
    letter-spacing: 0.3px;
}

.hof-badge-desc {
    font-size: 10px;
    opacity: 0.75;
    margin-top: 6px;
    line-height: 1.35;
    min-height: 26px;
}

.hof-badge-status {
    font-size: 9px;
    font-weight: 900;
    letter-spacing: 1px;
    margin-top: 8px;
    padding: 3px 8px;
    border-radius: 999px;
    display: inline-block;
    background: var(--ach-color, #F59E0B);
    color: white;
}

.hof-badge-status.locked {
    background: rgba(0,0,0,0.25);
}

/* ─── TABS ────────────────────────────────────── */
.hof-tabs {
    display: flex;
    background: rgba(0,0,0,0.04);
    padding: 5px;
    border-radius: 16px;
    gap: 4px;
    margin-bottom: 10px;
    box-shadow: inset 0 2px 4px rgba(0,0,0,0.06);
}

.hof-tab {
    flex: 1;
    padding: 9px 4px;
    border-radius: 12px;
    border: none;
    font-size: 12px;
    font-weight: 800;
    cursor: pointer;
    transition: all 0.22s;
    background: transparent;
    color: var(--v2-muted, #6B7280);
    margin: 0;
}

.hof-tab.active {
    background: white;
    color: var(--v2-primary, #FF8A00);
    box-shadow: 0 4px 10px rgba(0,0,0,0.06);
}

/* ─── LEADERBOARD ROWS ────────────────────────── */
.hof-leaderboard {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.hof-row {
    display: grid;
    /* 末列固定宽：用 auto 时 2 位数/3 位数会让右边缘逐行漂移 */
    grid-template-columns: 44px 38px 1fr 64px;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: white;
    border-radius: 14px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.04);
    transition: transform 0.15s;
}

.hof-row.top-1 {
    background: linear-gradient(135deg, #FFFBEB, #FEF3C7);
    border-left: 4px solid #F59E0B;
}

.hof-row.top-2 {
    background: linear-gradient(135deg, #F8FAFC, #E2E8F0);
    border-left: 4px solid #94A3B8;
}

.hof-row.top-3 {
    background: linear-gradient(135deg, #FFF7ED, #FED7AA);
    border-left: 4px solid #EA580C;
}

.hof-row.is-me {
    outline: 2px solid var(--v2-primary, #FF8A00);
    outline-offset: -2px;
}

.hof-rank {
    font-weight: 900;
    font-size: 18px;
    text-align: center;
}

.hof-avatar {
    font-size: 24px;
    text-align: center;
}

/* 姓名与称号上下居中对齐：称号比姓名宽，左对齐会显得姓名偏在一边 */
.hof-name {
    font-weight: 800;
    font-size: 14px;
    color: #1F2937;
    text-align: center;
    overflow: hidden;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* 姓名单行截断；称号另起一行，窄屏也不会被姓名挤掉 */
.hof-name-text {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 榜单里称号自成一行：去掉行内用的左边距，太长就自己截断 */
.hof-name .v2-title-badge {
    margin-left: 0;
    margin-top: 3px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 黑底金字 / 冠军称号 (Rank 1 - 金字) */
.v2-title-badge--gold-black {
    color: #FDE047 !important;
    background: linear-gradient(135deg, #1c1917 0%, #0c0a09 100%) !important;
    border: 1.5px solid #000000 !important;
    box-shadow: 0 0 0 1px #EAB308, 0 2px 4px rgba(0,0,0,0.6) !important;
    text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000, 0 0 6px rgba(253,224,71,0.5) !important;
    font-weight: 900 !important;
    letter-spacing: 0.6px !important;
}

/* 黑底银字 / 亚军称号 (Rank 2 - 银字) */
.v2-title-badge--silver-black {
    color: #F1F5F9 !important;
    background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%) !important;
    border: 1.5px solid #000000 !important;
    box-shadow: 0 0 0 1px #94A3B8, 0 2px 4px rgba(0,0,0,0.6) !important;
    text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000, 0 0 6px rgba(241,245,249,0.5) !important;
    font-weight: 900 !important;
    letter-spacing: 0.6px !important;
}

/* 黑底铜字 / 季军称号 (Rank 3 - 铜字) */
.v2-title-badge--bronze-black {
    color: #FDBA74 !important;
    background: linear-gradient(135deg, #291508 0%, #150a04 100%) !important;
    border: 1.5px solid #000000 !important;
    box-shadow: 0 0 0 1px #EA580C, 0 2px 4px rgba(0,0,0,0.6) !important;
    text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000, 0 0 6px rgba(253,186,116,0.5) !important;
    font-weight: 900 !important;
    letter-spacing: 0.6px !important;
}

.hof-me-tag {
    display: inline-block;
    background: var(--v2-primary, #FF8A00);
    color: white;
    font-size: 9px;
    font-weight: 900;
    padding: 2px 6px;
    border-radius: 6px;
    margin-left: 4px;
    vertical-align: middle;
}

.hof-value {
    font-weight: 900;
    font-size: 15px;
    color: var(--v2-primary, #FF8A00);
    font-family: ''Outfit'', sans-serif;
    text-align: right;
}

.hof-empty {
    text-align: center;
    padding: 40px 20px;
    opacity: 0.6;
    font-weight: 700;
}

/* tabular 数字：题数列不跳动 */
.hof-value {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

.hof-myrow-hint {
    margin-top: 8px;
    text-align: center;
    font-size: 12px;
    font-weight: 800;
    color: var(--v2-primary, #FF8A00);
    opacity: 0.9;
    padding: 8px;
}

/* ─── MONTHLY SEASON + PODIUM ─────────────────── */
.hof-season {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 78px;
    gap: 12px 16px;
    margin: 2px auto 12px;
    padding: 18px;
    /* ⚠️ 父级 .v2-content 是 flex column + align-items:center。不写这两条的话：
       横向——本元素按内容收缩成窄条；纵向——内容一多就被 flex 压扁，文字糊成一团看不见。
       同屏其它卡片没事，是因为它们各自写死了宽度。
       ⚠️ max-width 要跟 .v2-setting-card/.hof-board-card 一致(1000px)，否则
       这张卡横向撑满整屏，跟下面「排行榜」卡宽度不一样，看起来错位。 */
    width: 100%;
    max-width: 1000px;
    flex: 0 0 auto;
    box-sizing: border-box;
    overflow: hidden;
    color: #fff;
    border-radius: 24px;
    background:
        radial-gradient(circle at 88% 8%, rgba(255,225,142,.38), transparent 34%),
        linear-gradient(135deg, #3b234f 0%, #6d355f 56%, #a9363e 100%);
    box-shadow: 0 12px 28px rgba(74, 35, 72, .24);
}
.hof-season::after {
    content: "";
    position: absolute;
    width: 150px;
    height: 150px;
    right: -62px;
    bottom: -92px;
    border: 18px solid rgba(255,255,255,.08);
    border-radius: 50%;
}
.hof-season-copy { display: flex; flex-direction: column; min-width: 0; }
.hof-season-kicker {
    margin-bottom: 5px;
    color: #ffd989;
    font: 900 10px/1.2 'Montserrat', sans-serif;
    letter-spacing: 1.1px;
    text-transform: uppercase;
}
.hof-season-copy strong { font-size: 20px; line-height: 1.25; letter-spacing: -.4px; }
.hof-season-rule { margin-top: 7px; font-size: 10px; line-height: 1.45; opacity: .76; font-weight: 700; }
.hof-season-countdown {
    align-self: start;
    display: grid;
    place-items: center;
    padding: 10px 5px;
    border: 1px solid rgba(255,255,255,.18);
    border-radius: 18px;
    background: rgba(255,255,255,.11);
    box-shadow: inset 0 1px rgba(255,255,255,.12);
}
.hof-season-countdown b { color: #ffe29b; font: 900 30px/1 'Outfit', sans-serif; }
.hof-season-countdown span { margin-top: 4px; font-size: 8px; font-weight: 900; letter-spacing: .7px; opacity: .75; }
.hof-season-rewards {
    grid-column: 1 / -1;
    min-width: 0;
}
.hof-season-rewards-label {
    display: block;
    margin-bottom: 7px;
    color: #ffd989;
    font: 900 9px/1.2 'Montserrat', sans-serif;
    letter-spacing: .9px;
    text-transform: uppercase;
}
/* 本月冠军奖品：把「争的是这只」摆出来，比纯文字有拉力。 */
.hof-season-prize {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 9px;
    margin-bottom: 9px;
    padding: 14px 13px 13px;
    border: 1px solid rgba(255,225,142,.32);
    border-radius: 16px;
    background: linear-gradient(170deg, rgba(255,225,142,.20), rgba(255,225,142,.05));
}
/* 居中后整张卡的宽度都归它，图可以再大一圈。 */
.hof-season-prize-art {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 96px;
    height: 96px;
    overflow: hidden;
    border-radius: 20px;
    background: rgba(0,0,0,.18);
    box-shadow: 0 3px 14px rgba(0,0,0,.26), inset 0 0 0 1px rgba(255,225,142,.22);
}
.hof-season-prize-art .v2-avatar-art { width: 100%; height: 100%; object-fit: contain; }
.hof-season-prize-art .v2-avatar-legacy { font-size: 54px; line-height: 1; }
.hof-season-prize-copy {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 0;
    gap: 3px;
}
.hof-season-prize-copy b {
    color: #fff;
    font-size: 10px;
    font-weight: 900;
    letter-spacing: .4px;
    opacity: .82;
}
.hof-season-prize-copy i {
    color: #ffe29b;
    font: 900 17px/1.25 'Outfit', sans-serif;
    font-style: normal;
    overflow-wrap: anywhere;
}
/* 窄屏收一点，但仍要看得清。 */
@media (max-width: 360px) {
    .hof-season-prize { gap: 8px; padding: 12px 11px 11px; }
    .hof-season-prize-art { width: 82px; height: 82px; border-radius: 18px; }
    .hof-season-prize-art .v2-avatar-legacy { font-size: 46px; }
    .hof-season-prize-copy i { font-size: 16px; }
}
/* 榜单：一行一个人，名次奖牌 + 头像 + 名字 + 分数。
   名字用 minmax(0,1fr) 才肯换行；不写 min-width:0 长英文名会把分数挤出卡片。
   前三名（.is-medal）头像放大 + 奖牌色描边发光，呼应下方领奖台的「赢家感」，
   4-10名保持紧凑但留足呼吸空间，不再是挤成一坨的细行。 */
.hof-season-top {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.hof-season-top li {
    display: grid;
    grid-template-columns: 22px 30px minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 6px 10px 6px 6px;
    border-radius: 11px;
    transition: transform 0.15s ease;
}
.hof-season-top li.is-medal {
    padding: 7px 12px 7px 7px;
    background: rgba(255,255,255,.06);
}
.hof-season-top li.is-me {
    background: rgba(255,255,255,.14);
    box-shadow: inset 0 0 0 1px rgba(255,225,142,.4);
}
.hof-season-top-avatar {
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    flex-shrink: 0;
}
.hof-season-top-avatar .v2-avatar-art { width: 30px; height: 30px; }
.hof-season-top-avatar .v2-avatar-legacy { font-size: 20px; }
/* 前三名头像加大一圈 + 奖牌色描边光晕，其余保持原尺寸不抢镜。 */
.hof-season-top li.is-medal .hof-season-top-avatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
}
.hof-season-top li.is-medal .hof-season-top-avatar .v2-avatar-art { width: 38px; height: 38px; }
.hof-season-top li.is-medal .hof-season-top-avatar .v2-avatar-legacy { font-size: 26px; }
.hof-season-top li.gold .hof-season-top-avatar { box-shadow: 0 0 0 2.5px #ffd76e, 0 0 12px rgba(255,215,110,.55); }
.hof-season-top li.silver .hof-season-top-avatar { box-shadow: 0 0 0 2.5px #dce8f2, 0 0 10px rgba(220,232,242,.4); }
.hof-season-top li.bronze .hof-season-top-avatar { box-shadow: 0 0 0 2.5px #e8a16e, 0 0 10px rgba(232,161,110,.4); }
.hof-season-top b {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border: 1px solid rgba(255,255,255,.22);
    border-radius: 7px;
    background: rgba(255,255,255,.1);
    font: 900 10px/1 'Outfit', sans-serif;
}
.hof-season-top .gold { color: #4d3100; background: #ffd76e; border-color: transparent; box-shadow: 0 2px 6px rgba(255,215,110,.35); }
.hof-season-top .silver { color: #3e4d5d; background: #dce8f2; border-color: transparent; }
.hof-season-top .bronze { color: #4d250e; background: #e8a16e; border-color: transparent; }
.hof-season-top span {
    min-width: 0;
    color: #fff;
    font-size: 11.5px;
    font-weight: 800;
    line-height: 1.35;
    overflow-wrap: anywhere;   /* 长英文名折行，不撑破卡片 */
}
.hof-season-top li.is-medal span { font-size: 12.5px; font-weight: 900; }
.hof-season-top span i {
    margin-left: 4px;
    padding: 1px 5px;
    border-radius: 5px;
    background: rgba(255,225,142,.9);
    color: #4d3100;
    font: 900 8px/1.4 'Montserrat', sans-serif;
    font-style: normal;
}
.hof-season-top em {
    color: #ffe29b;
    font: 900 12px/1 'Outfit', sans-serif;
    font-style: normal;
    white-space: nowrap;
}
.hof-season-top li.is-medal em { font-size: 14px; }
.hof-season-empty,
.hof-season-mine {
    margin: 0;
    color: #fff3ca;
    font-size: 10px;
    font-weight: 800;
    line-height: 1.4;
}
.hof-season-mine {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-top: 7px;
    padding-top: 7px;
    border-top: 1px solid rgba(255,255,255,.14);
}
.hof-season-mine b {
    display: grid;
    place-items: center;
    min-width: 20px;
    height: 20px;
    padding: 0 4px;
    border-radius: 7px;
    background: rgba(255,255,255,.16);
    font: 900 9px/1 'Outfit', sans-serif;
}
.hof-season-mine.muted { opacity: .72; }
.hof-board-card { padding: 14px !important; overflow: visible !important; }
.hof-board-header { margin-bottom: 14px !important; }
.hof-live-dot {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-left: auto;
    color: #8f3144;
    font: 900 9px/1 'Montserrat', sans-serif;
    letter-spacing: .8px;
}
.hof-live-dot i { width: 7px; height: 7px; border-radius: 50%; background: #e54a62; box-shadow: 0 0 0 4px rgba(229,74,98,.12); }
.hof-podium {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: end;
    gap: 7px;
    min-height: 190px;
    padding: 12px 4px 0;
}
.hof-podium-place {
    position: relative;
    display: flex;
    min-width: 0;
    flex-direction: column;
    align-items: center;
    padding: 34px 7px 13px;
    border: 1px solid rgba(255,255,255,.85);
    border-radius: 20px 20px 14px 14px;
    background: linear-gradient(155deg, #fff, #f0edf3);
    box-shadow: 5px 7px 15px rgba(101,84,116,.16), -4px -4px 12px rgba(255,255,255,.9);
}
.hof-podium-place.place-1 { min-height: 146px; background: linear-gradient(155deg, #fff9dc, #f8d97c); }
.hof-podium-place.place-1 { grid-column: 2; }
.hof-podium-place.place-2 { min-height: 122px; }
.hof-podium-place.place-3 { min-height: 108px; background: linear-gradient(155deg, #fff5ed, #e9b08a); }
.hof-podium-place.is-me { outline: 3px solid #ff6fb5; outline-offset: 2px; }
.hof-podium-rank {
    position: absolute;
    top: -9px;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border: 3px solid #fff;
    border-radius: 12px;
    color: #fff;
    background: #5d6470;
    box-shadow: 0 5px 10px rgba(40,30,50,.18);
    font: 900 14px/1 'Outfit', sans-serif;
}
.place-1 .hof-podium-rank { color: #5a3600; background: #ffc43e; transform: scale(1.12); }
.place-3 .hof-podium-rank { background: #bd6e3d; }
.hof-podium-avatar { width: 54px; height: 54px; display: grid; place-items: center; font-size: 38px; }
.hof-podium-avatar .v2-avatar-art { width: 100%; height: 100%; }
.hof-podium-name { width: 100%; margin-top: 7px; overflow: hidden; color: #3d3346; font-size: 11px; font-weight: 900; text-align: center; text-overflow: ellipsis; white-space: nowrap; }
.hof-podium-score { margin-top: 4px; color: #8e3548; font: 900 17px/1 'Outfit', sans-serif; }
.hof-podium-score small, .hof-value small { margin-left: 2px; font: 800 8px/1 sans-serif; opacity: .62; }
.hof-rank-list { display: flex; flex-direction: column; gap: 7px; margin-top: 12px; }
.hof-row.reward-zone { border-left: 3px solid #d0a238; background: linear-gradient(90deg, #fffaf0, #fff); }
.hof-row.reward-zone .hof-rank { color: #9a6700; font-size: 10px; letter-spacing: -.2px; }
.hof-value { display: flex; align-items: baseline; justify-content: flex-end; }
.hof-value strong { font: 900 16px/1 'Outfit', sans-serif; }

@media (max-width: 390px) {
    .hof-season { padding: 15px; grid-template-columns: minmax(0, 1fr) 68px; }
    .hof-season-copy strong { font-size: 17px; }
    .hof-season-rule { font-size: 9px; }
    .hof-season-top li { grid-template-columns: 18px 26px minmax(0, 1fr) auto; gap: 6px; padding-right: 6px; }
    .hof-season-top span { font-size: 10px; }
    .hof-season-top li.is-medal .hof-season-top-avatar { width: 32px; height: 32px; }
    .hof-season-top li.is-medal .hof-season-top-avatar .v2-avatar-art { width: 32px; height: 32px; }
    .hof-season-top li.is-medal .hof-season-top-avatar .v2-avatar-legacy { font-size: 22px; }
    .hof-season-top li.is-medal span { font-size: 11px; }
    .hof-podium { gap: 5px; }
    .hof-podium-place { padding-left: 4px; padding-right: 4px; }
    .hof-podium-avatar { width: 46px; height: 46px; }
    .hof-row { grid-template-columns: 38px 34px minmax(0, 1fr) 56px; gap: 7px; padding: 9px 9px; }
}

/* ══════════════════════════════════════════════
   LEADERBOARD · 年龄组主控 (聚焦版)
   ═══════════════════════════════════════════════ */

.hof-age-stepper {
    display: grid;
    grid-template-columns: 48px 1fr 48px;
    align-items: center;
    gap: 8px;
    background: linear-gradient(135deg, #FFFFFF, #FFF4FA);
    border: 1px solid rgba(255,255,255,0.85);
    border-radius: 20px;
    padding: 12px 10px;
    box-shadow: 6px 6px 14px rgba(163,177,198,0.35),
                -6px -6px 14px rgba(255,255,255,0.9);
    margin: 0 auto 10px;
    /* ⚠️ 跟 .hof-season 同理：宽度要锁 1000px，否则整屏撑满，跟下面
       「排行榜」等卡片宽度不一致 */
    width: 100%;
    max-width: 1000px;
    box-sizing: border-box;
}

.hof-age-arrow {
    width: 44px;
    height: 44px;
    border-radius: 14px;
    border: none;
    background: #FFFFFF;
    color: var(--v2-primary, #FF6FB5);
    font-size: 26px;
    font-weight: 900;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px rgba(0,0,0,0.08);
    transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.hof-age-arrow:active { transform: scale(0.92); }
.hof-age-arrow.disabled {
    opacity: 0.3;
    pointer-events: none;
    box-shadow: none;
}

/* 中间这块可点：打开年龄组弹层 */
.hof-age-current {
    text-align: center;
    min-width: 0;
    cursor: pointer;
    border-radius: 14px;
    padding: 4px 6px;
    transition: transform 0.15s, background 0.15s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.hof-age-current:active { transform: scale(0.97); background: rgba(255,255,255,0.75); }
.hof-age-tap { font-weight: 900; opacity: 0.8; }
/* ⚠️ IconSetV2 出的 SVG 都带 .v2-svg-icon（display:block，图标最佳实践），
   父级 text-align:center 对 block 元素完全无效 —— block 默认贴容器左边，
   不受 text-align 影响。改用 flex 居中才能让图标真正居中而不是贴左。 */
.hof-age-emoji { font-size: 30px; line-height: 1; display: flex; justify-content: center; }
.hof-age-label {
    font-size: 16px;
    font-weight: 900;
    color: #1F2937;
    margin-top: 3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.hof-age-me {
    display: inline-block;
    background: var(--v2-primary, #FF6FB5);
    color: #fff;
    font-size: 10px;
    font-weight: 900;
    padding: 2px 7px;
    border-radius: 8px;
    margin-left: 4px;
    vertical-align: middle;
}
.hof-age-sub {
    font-size: 12px;
    font-weight: 700;
    /* ⚠️ 卡片底色固定白色，字色不能只靠opacity继承深色主题下近白的
       --v2-text，否则星河等主题下浅底浅字看不见 */
    color: #4B5563;
    opacity: 0.85;
    margin-top: 2px;
}

/* 项目摘要（收起态） */
.hof-event-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: #FFFFFF;
    border-radius: 16px;
    padding: 11px 14px;
    margin: 0 auto 10px;
    /* ⚠️ 同 .hof-season/.hof-age-stepper：宽度锁 1000px 跟其它卡片对齐 */
    width: 100%;
    max-width: 1000px;
    box-sizing: border-box;
    box-shadow: 0 2px 6px rgba(0,0,0,0.05);
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.hof-event-summary:active { transform: scale(0.99); }
.hof-event-summary-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.hof-event-summary-mode {
    font-size: 13px;
    font-weight: 900;
    color: #1F2937;
}
.hof-event-summary-detail {
    font-size: 12px;
    font-weight: 700;
    /* ⚠️ 底色固定白，没设颜色时会继承深色主题下变白的全局文字色，
       配合 opacity 几乎看不见。固定深灰 + 单独控制透明度。 */
    color: #1F2937;
    opacity: 0.65;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.hof-change-btn {
    flex-shrink: 0;
    background: linear-gradient(135deg, #FFE3F1, #FFD0E6);
    color: var(--v2-primary, #FF6FB5);
    font-size: 12px;
    font-weight: 900;
    padding: 7px 12px;
    border-radius: 12px;
    white-space: nowrap;
}

/* 项目选择弹层 (Neumorphic Bento) */
.hof-picker-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    display: flex;
    align-items: flex-end;
    justify-content: center;
    z-index: 99999;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s;
}
.hof-picker-overlay.show {
    opacity: 1;
    pointer-events: auto;
}
.hof-picker-card {
    background: #E6EAF0;
    border: 1px solid rgba(255,255,255,0.85);
    border-radius: 24px 24px 0 0;
    padding: 20px 18px calc(20px + env(safe-area-inset-bottom));
    width: 100%;
    max-width: 460px;
    max-height: 82vh;
    overflow-y: auto;
    box-shadow: 0 -12px 30px rgba(0,0,0,0.25);
    transform: translateY(100%);
    transition: transform 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.2);
}
.hof-picker-overlay.show .hof-picker-card {
    transform: translateY(0);
}
.hof-picker-title {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 18px;
    font-weight: 900;
    color: #1F2937;
    margin-bottom: 14px;
}
.hof-picker-title-en {
    font-size: 12px;
    font-weight: 600;
    opacity: 0.5;
}
.hof-picker-section { margin-bottom: 14px; }
.hof-picker-label {
    font-size: 12px;
    font-weight: 900;
    letter-spacing: 0.5px;
    opacity: 0.7;
    margin-bottom: 8px;
}
.hof-picker-done {
    width: 100%;
    margin-top: 6px;
    padding: 14px;
    border: none;
    border-radius: 16px;
    background: linear-gradient(135deg, #FF8FC0, #FF6FB5);
    color: #fff;
    font-size: 15px;
    font-weight: 900;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(255,111,181,0.4);
    transition: transform 0.15s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.hof-picker-done:active { transform: scale(0.98); }

@media (prefers-reduced-motion: reduce) {
    .hof-picker-card, .hof-age-arrow, .hof-event-summary, .hof-picker-done { transition: none; }
}

/* ══════════════════════════════════════════════
   ACHIEVEMENT UNLOCK TOAST (Neumorphic Bento)
   ═══════════════════════════════════════════════ */

.ach-unlock-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 99999;
    opacity: 0;
    transition: opacity 0.35s;
    cursor: pointer;
}

.ach-unlock-overlay.show {
    opacity: 1;
}

.ach-unlock-card {
    background: #E6EAF0;
    border: 1px solid rgba(255,255,255,0.85);
    border-radius: 24px;
    padding: 30px 36px 28px;
    text-align: center;
    box-shadow: 12px 12px 24px rgba(163,177,198,0.5),
                -12px -12px 24px rgba(255,255,255,0.8);
    border-top: 5px solid var(--ach-color, #F59E0B);
    transform: scale(0.7);
    transition: transform 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.2);
    max-width: 340px;
    width: 86%;
}

.ach-unlock-overlay.show .ach-unlock-card {
    transform: scale(1);
}

.ach-unlock-tag {
    font-size: 11px;
    font-weight: 900;
    letter-spacing: 2px;
    color: var(--ach-color, #F59E0B);
    margin-bottom: 14px;
}

.ach-unlock-icon {
    font-size: 72px;
    line-height: 1;
    margin-bottom: 10px;
    filter: drop-shadow(0 6px 12px rgba(0,0,0,0.2));
    animation: achIconPulse 1.2s ease-in-out infinite;
}

@keyframes achIconPulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.08); }
}

.ach-unlock-title {
    font-size: 22px;
    font-weight: 900;
    color: #1F2937;
    margin-top: 4px;
}

.ach-unlock-title-en {
    font-size: 13px;
    font-weight: 600;
    opacity: 0.7;
    margin-top: 2px;
    letter-spacing: 0.5px;
}

.ach-unlock-desc {
    font-size: 13px;
    margin-top: 12px;
    color: #4B5563;
    font-weight: 700;
}

.ach-unlock-desc-en {
    font-size: 11px;
    opacity: 0.75;
    margin-top: 3px;
    font-weight: 500;
}

/* --- V2 SVG Badge Integration Styles --- */
.hof-badge-svg-container {
    width: 90px;
    height: 82px;
    margin: 0 auto 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.2s ease;
}
.hof-badge.unlocked:hover .hof-badge-svg-container {
    transform: scale(1.08) translateY(-2px);
}
.ach-unlock-icon svg {
    width: 165px;
    height: 150px;
    margin: 0 auto;
}
.hof-badge.locked .hof-badge-svg-container {
    filter: grayscale(0.85) opacity(0.5);
}

/* ══════════════════════════════════════════════
   FX LAYER — themed visual effects (rice burst, etc.)
   ═══════════════════════════════════════════════ */
.v2-fx-layer {
    position: fixed;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    z-index: 9999;
}

.v2-rice-particle {
    position: absolute;
    font-size: 26px;
    line-height: 1;
    will-change: transform, opacity;
    width: 30px;
    height: 30px;
    margin-left: -15px;
    margin-top: -15px;
    text-align: center;
    user-select: none;
    animation: v2RiceBurst 800ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
    /* 移除了耗费 GPU 资源的 drop-shadow filter 以显著提升移动端流畅度 */
}
.v2-rice-particle--big {
    font-size: 34px;
    width: 40px;
    height: 40px;
    margin-left: -20px;
    margin-top: -20px;
}

@keyframes v2RiceBurst {
    0% {
        transform: translate(0, 0) scale(0.4) rotate(0deg);
        opacity: 0;
    }
    15% {
        transform: translate(0, 0) scale(1.15) rotate(calc(var(--fx-rot) * 0.2));
        opacity: 1;
    }
    100% {
        transform: translate(var(--fx-dx), var(--fx-dy)) scale(0.8) rotate(var(--fx-rot));
        opacity: 0;
    }
}

/* ===========================================================
   Ranking Challenge — subject tabs (复用 v2-level-chip 风格)
   =========================================================== */
.ranking-challenge-content {
    align-items: center;
}

.ranking-challenge-hint,
#ranking-events-container {
    width: 100%;
    max-width: 1000px;
    box-sizing: border-box;
}

.ranking-challenge-hint {
    margin: 4px 4px 8px;
}

#ranking-events-container > .v2-setting-item {
    width: 100%;
    box-sizing: border-box;
}

.ranking-subject-tabs {
    margin: 0;
}

.ranking-events-section .ranking-panel {
    margin-top: 4px;
}

.ranking-panel {
    animation: rankingPanelIn 0.28s cubic-bezier(0.175, 0.885, 0.32, 1.15);
}

@keyframes rankingPanelIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ── Ranking event cards（主题化 + 个人成绩对比）──────────────── */
.ranking-event-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}

/* 宽屏（平板横屏 / 网页版）原本也锁死两列：一张卡摊到 900px 宽，
   里面只有三行居中小字，整块变成空板砖。改成按 180px 自动排列并封顶居中，
   手机端（≤720px）一个字节都不变，还是熟悉的两列方卡。 */
@media (min-width: 721px) {
    .ranking-event-grid {
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
        max-width: 1080px;
        margin: 0 auto;
    }
}

.ranking-event-card {
    padding: 14px 10px;
    cursor: pointer;
    text-align: center;
    border-radius: 18px;
    transition: transform 0.15s, box-shadow 0.15s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.ranking-event-card:active { transform: scale(0.97); }

.ranking-event-card .rec-name {
    font-size: 18px;
    font-weight: 900;
    color: var(--v2-primary, #FF6FB5);
}
.ranking-event-card .rec-desc {
    font-size: 11px;
    opacity: 0.65;
    margin-top: 5px;
    font-weight: 600;
}

.ranking-event-card .rec-stat {
    margin-top: 9px;
    padding-top: 8px;
    border-top: 1px dashed rgba(0,0,0,0.10);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}
.rec-best { color: #B45309; }            /* 金棕：最佳纪录 */
.rec-last { opacity: 0.55; }
.rec-first { color: var(--v2-primary, #FF6FB5); opacity: 0.85; font-weight: 800; }
/* 新赛季提示：比「首次挑战」再弱一档，是参照信息不是成绩 */
.rec-newmonth { color: var(--v2-muted); opacity: 0.9; font-weight: 800; }
.rec-loading { opacity: 0.3; letter-spacing: 2px; }

.rec-trend {
    padding: 1px 8px;
    border-radius: 8px;
    font-size: 11px;
    font-weight: 900;
    white-space: nowrap;
}
/* 名次徽章：跟最佳/上次同排走 flex-wrap，不用绝对定位压在项目名上 */
.rec-rank {
    display: inline-flex;
    align-items: baseline;
    gap: 1px;
    padding: 1px 7px;
    border-radius: 8px;
    background: #F1F5F9;
    color: #475569;
    font-size: 11px;
    font-weight: 900;
    white-space: nowrap;
}
.rec-rank small { font-size: 9px; font-weight: 700; opacity: 0.6; }
.rec-rank.rank-1 { background: #FEF3C7; color: #92400E; }   /* 金 */
.rec-rank.rank-2 { background: #E2E8F0; color: #334155; }   /* 银 */
.rec-rank.rank-3 { background: #FCE7D3; color: #9A3412; }   /* 铜 */

/* 「再对 N 题进前三」：把名次换成够得着的目标 */
.rec-gap {
    margin-top: 5px;
    font-size: 10.5px;
    font-weight: 800;
    color: #0284C7;
}
.rec-gap.is-top { color: #B45309; }

.rec-trend.up   { background: #DCFCE7; color: #16A34A; }   /* 进步 */
.rec-trend.down { background: #FEE2E2; color: #DC2626; }   /* 退步（语义红，配 ▼）*/
.rec-trend.flat { background: #F1F5F9; color: #64748B; }   /* 持平 */

@media (prefers-reduced-motion: reduce) {
    .ranking-event-card { transition: none; }
    .ranking-panel { animation: none; }
}

/* ── Competition Banner (主屏比赛横幅) ───────────────────────────── */
.comp-banner{
    position: relative; overflow: hidden; cursor: pointer;
    display: flex; align-items: center; gap: 14px;
    margin: 0 0 14px; padding: 16px 18px; border-radius: 20px;
    background: linear-gradient(135deg, #FF8A00, #FF5722);
    box-shadow: 0 10px 24px rgba(255,87,34,.35);
    animation: compBannerIn .5s cubic-bezier(.175,.885,.32,1.2);
}
.comp-banner.joined{ background: linear-gradient(135deg, #16a34a, #0d9488);
    box-shadow: 0 10px 24px rgba(13,148,136,.3); }
.comp-banner .cb-glow{ position:absolute; top:-50%; right:-20%; width:200px; height:200px;
    background: radial-gradient(circle, rgba(255,255,255,.35), transparent 70%);
    pointer-events:none; }
.comp-banner .cb-icon{ font-size: 38px; flex-shrink:0; filter: drop-shadow(0 2px 4px rgba(0,0,0,.2)); }
.comp-banner .cb-body{ flex:1; min-width:0; color:#fff; }
.comp-banner .cb-tag{ font-size:11px; font-weight:900; letter-spacing:.5px; opacity:.95;
    background: rgba(255,255,255,.22); display:inline-block; padding:2px 9px; border-radius:999px; margin-bottom:4px; }
.comp-banner .cb-title{ font-size:17px; font-weight:900; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.comp-banner .cb-sub{ font-size:12px; font-weight:600; opacity:.9; }
.comp-banner .cb-arrow{ font-size:30px; font-weight:900; color:#fff; opacity:.85; flex-shrink:0; }

/* 图片横幅（裁判上传的自定义横幅图） */
.comp-banner.img{ display:block; padding:0; min-height:96px; background-size:cover; background-position:center;
    position:relative; box-shadow:0 8px 20px rgba(0,0,0,.2); }
.comp-banner.img .cb-img-tag{ position:absolute; top:10px; left:12px; background:rgba(0,0,0,.55);
    color:#fff; font-weight:800; font-size:12px; padding:4px 12px; border-radius:999px;
    backdrop-filter:blur(4px); }
.comp-banner.img.joined .cb-img-tag{ background:rgba(22,163,74,.85); }
.comp-banner.img .cb-img-arrow{ position:absolute; right:14px; top:50%; transform:translateY(-50%);
    font-size:30px; font-weight:900; color:#fff; opacity:.9; text-shadow:0 2px 6px rgba(0,0,0,.5); }
@keyframes compBannerIn{ from{opacity:0; transform:scale(.94) translateY(-6px);} to{opacity:1; transform:scale(1) translateY(0);} }

/* ── Competition Registration Page (报名页) ─────────────────────── */
.cr-loading,.cr-empty{ padding:40px; text-align:center; color:var(--v2-muted); font-weight:700; }
.cr-empty.err{ color:#dc2626; }
.cr-wrap{ max-width:480px; margin:0 auto; width:100%; }
.cr-hero{ text-align:center; padding:18px 0 22px; }
.cr-hero-icon{ font-size:54px; }
.cr-hero-title{ font-size:22px; font-weight:900; color:var(--v2-text-dark); margin-top:6px; }
.cr-hero-meta{ display:flex; gap:16px; justify-content:center; margin-top:8px; color:var(--v2-muted); font-size:13px; font-weight:700; }
.cr-card{ background:#E6EAF0; border-radius:20px; padding:16px 18px; margin-bottom:14px;
    border:1px solid rgba(255,255,255,.85);
    box-shadow:8px 8px 18px rgba(163,177,198,.5),-8px -8px 18px rgba(255,255,255,.8); }
.cr-card-label{ font-size:13px; font-weight:900; color:var(--v2-text-dark); margin-bottom:12px; }
.cr-card-label .muted{ font-weight:600; color:var(--v2-muted); font-size:12px; }
.cr-field{ display:flex; justify-content:space-between; padding:9px 0; border-bottom:1px solid rgba(163,177,198,.2); }
.cr-field:last-child{ border-bottom:none; }
.cr-field .k{ color:var(--v2-muted); font-weight:700; font-size:13px; }
.cr-field .v{ font-weight:800; color:var(--v2-text-dark); font-size:14px; }
.cr-field .v.hl{ color:var(--v2-primary); }
.cr-warn{ background:#FEF3C7; color:#92400E; border-radius:14px; padding:12px 14px; font-size:13px; font-weight:700; margin-bottom:14px; }
.cr-foot{ display:flex; gap:10px; }
.cr-btn{ flex:1; padding:15px; border:none; border-radius:16px; cursor:pointer; font-size:16px; font-weight:900; }
.cr-btn.primary{ color:#fff; background:var(--v2-primary); box-shadow:0 6px 0 var(--v2-primary-dark); }
.cr-btn.primary:active{ transform:translateY(3px); box-shadow:0 3px 0 var(--v2-primary-dark); }
.cr-btn.primary:disabled{ opacity:.5; cursor:not-allowed; box-shadow:none; }
.cr-btn.joined{ color:#16a34a; background:#dcfce7; width:100%; }
.cr-btn.ghost{ background:transparent; color:var(--v2-muted); flex:1; }

/* 报名截止提示 */
.cr-deadline{ margin-top:8px; font-size:12px; font-weight:800; color:var(--v2-primary-dark); }
.cr-deadline.over{ color:#dc2626; }

/* 报名成功引导卡 */
.cr-success{ text-align:center; background:#dcfce7; border-radius:18px; padding:18px; margin-bottom:14px;
    border:1px solid rgba(22,163,74,.25); }
.cr-success .cs-icon{ font-size:34px; }
.cr-success .cs-title{ font-size:18px; font-weight:900; color:#15803d; margin-top:4px; }
.cr-success .cs-sub{ font-size:13px; font-weight:600; color:#166534; margin-top:6px; line-height:1.5; }
.cr-success .cs-sub b{ color:#15803d; }

/* 弱化的取消链接 */
.cr-cancel-link{ text-align:center; margin-top:14px; font-size:13px; font-weight:600;
    color:var(--v2-muted); text-decoration:underline; cursor:pointer; opacity:.7; }
.cr-cancel-link:hover{ opacity:1; color:#dc2626; }

/* ══ Competition Player (比赛答题全屏层) ══ */
#cp-root{ position:fixed; inset:0; z-index:9000; }
.cp-overlay{ position:fixed; inset:0; background:var(--v2-bg-main,#FFF9E6);
    display:flex; flex-direction:column; align-items:center; padding:16px;
    overflow:auto; }
.cp-center{ margin:auto; font-size:16px; font-weight:700; color:var(--v2-muted); text-align:center; }
.cp-err{ color:#dc2626; font-weight:800; margin-bottom:16px; }

/* 顶栏：进度 / 组别 / 倒计时 */
.cp-top{ width:100%; max-width:480px; display:flex; align-items:center; justify-content:space-between;
    padding:10px 4px; flex-shrink:0; }
.cp-prog{ font-weight:900; font-size:15px; color:var(--v2-text-dark,#2c3140); }
.cp-grp{ font-size:12px; font-weight:800; color:#fff; background:var(--v2-primary,#FF8A00);
    padding:3px 10px; border-radius:999px; }
.cp-timer{ font-weight:900; font-size:20px; color:var(--v2-primary-dark,#E67E00);
    font-variant-numeric:tabular-nums; }
.cp-timer.low{ color:#dc2626; animation:cpPulse .8s infinite; }
@keyframes cpPulse{ 0%,100%{opacity:1} 50%{opacity:.4} }

/* 直式题目舞台（常驻） */
.cp-stage{ flex:1; display:flex; align-items:center; justify-content:center; width:100%; min-height:160px; }
.cp-vstack{ display:flex; flex-direction:column; align-items:stretch; min-width:120px; }
.cp-vrow{ display:grid; grid-template-columns:0.5fr 1.5fr; align-items:center;
    font-size:clamp(34px,11vw,64px); font-weight:900; line-height:1.12;
    font-variant-numeric:tabular-nums; color:var(--v2-text-dark,#2c3140); }
.cp-sym{ text-align:left; opacity:.8; }
.cp-val{ text-align:right; }
.cp-vline{ height:4px; background:#333; border-radius:2px; margin:8px 0; }

/* 乘除横式 a × b = ? */
.cp-hstack{ display:flex; align-items:center; justify-content:center; gap:clamp(8px,2.5vw,18px);
    flex-wrap:wrap; font-size:clamp(34px,10vw,60px); font-weight:900;
    font-variant-numeric:tabular-nums; color:var(--v2-text-dark,#2c3140); }
.cp-hsym{ opacity:.7; }
.cp-hq{ color:var(--v2-primary,#FF8A00); }

/* 输入框 */
.cp-inputbox{ width:100%; max-width:480px; min-height:54px; margin:8px 0; padding:10px 18px;
    background:#fff; border-radius:16px; font-size:30px; font-weight:900; text-align:right;
    color:var(--v2-primary-dark,#E67E00); font-variant-numeric:tabular-nums;
    box-shadow:inset 3px 3px 7px rgba(163,177,198,.5),inset -3px -3px 7px rgba(255,255,255,.9);
    display:flex; align-items:center; justify-content:flex-end; flex-shrink:0; }
/* ⚠️ .cp-inputbox 底色固定白，字色不能用深色主题下会变浅的
   --v2-muted（变量已定义，fallback不会生效），否则星河等主题下浅底浅字看不见 */
.cp-inputbox .cp-ph{ color:#8a93a6; font-size:18px; font-weight:600; }
.cp-inputbox.shake{ animation:cpShake .4s; }
@keyframes cpShake{ 0%,100%{transform:translateX(0)} 25%{transform:translateX(-8px)} 75%{transform:translateX(8px)} }

/* numpad */
.cp-numpad{ width:100%; max-width:480px; display:grid; grid-template-columns:repeat(3,1fr); gap:10px;
    flex-shrink:0; }
/* ⚠️ 底色固定白，字色不能用深色主题下会变近白的 --v2-text-dark
   （变量已定义，fallback不会生效），否则星河等主题下浅底浅字看不见 */
.cp-key{ padding:18px 0; border:none; border-radius:16px; font-size:26px; font-weight:900; cursor:pointer;
    background:#fff; color:#2c3140;
    box-shadow:5px 5px 12px rgba(163,177,198,.5),-5px -5px 12px rgba(255,255,255,.9); }
.cp-key:active{ box-shadow:inset 4px 4px 8px rgba(163,177,198,.6),inset -4px -4px 8px rgba(255,255,255,.9); }
.cp-key.cp-fn{ color:#dc2626; }
.cp-key.cp-ok{ background:var(--v2-primary,#FF8A00); color:#fff; box-shadow:0 5px 0 var(--v2-primary-dark,#E67E00); }
.cp-key.cp-ok:active{ transform:translateY(3px); box-shadow:0 2px 0 var(--v2-primary-dark,#E67E00); }

/* skip */
.cp-skip{ width:100%; max-width:480px; margin:12px 0 4px; padding:13px; border:none; border-radius:14px;
    background:transparent; color:var(--v2-muted,#8a93a6); font-size:14px; font-weight:800; cursor:pointer;
    border:2px dashed rgba(138,147,166,.4); flex-shrink:0; }
.cp-skip:active{ background:rgba(138,147,166,.1); }
.cp-kbhint{ width:100%; max-width:480px; text-align:center; margin-top:8px; font-size:11px;
    color:var(--v2-muted,#8a93a6); font-weight:600; flex-shrink:0; }
@media (hover: none) and (pointer: coarse) { .cp-kbhint{ display:none; } } /* 触屏设备隐藏键盘提示 */

/* 结果页 */
.cp-result{ margin:auto; max-width:420px; text-align:center; background:#E6EAF0; border-radius:24px; padding:32px 26px;
    box-shadow:12px 12px 24px rgba(163,177,198,.5),-12px -12px 24px rgba(255,255,255,.8); }
.cp-res-icon{ font-size:56px; }
.cp-res-title{ font-size:22px; font-weight:900; color:var(--v2-text-dark,#2c3140); margin:6px 0 18px; }
.cp-res-stats{ display:flex; justify-content:center; gap:24px; margin-bottom:18px; }
.cp-res-stats div{ display:flex; flex-direction:column; }
.cp-res-stats b{ font-size:26px; font-weight:900; color:var(--v2-primary,#FF8A00); }
.cp-res-stats span{ font-size:12px; color:var(--v2-muted,#8a93a6); font-weight:700; margin-top:2px; }
.cp-res-note{ font-size:13px; color:var(--v2-muted,#8a93a6); font-weight:600; line-height:1.5; margin-bottom:20px; }
.cp-btn{ padding:14px 40px; border:none; border-radius:16px; font-size:16px; font-weight:900; cursor:pointer;
    color:#fff; background:var(--v2-primary,#FF8A00); box-shadow:0 6px 0 var(--v2-primary-dark,#E67E00); }
.cp-btn:active{ transform:translateY(3px); box-shadow:0 3px 0 var(--v2-primary-dark,#E67E00); }

/* ── Book Dispatch (发书登记) ── */
.bd-slot{ display:flex; align-items:center; gap:10px; padding:14px 14px; border-radius:12px;
    font-size:15px; font-weight:800; min-height:52px; transition:background .2s, color .2s; }
.bd-slot.empty{ background:var(--v2-bg-main,#E6EAF0); color:var(--v2-muted,#94a3b8);
    border:1.5px dashed rgba(148,163,184,.5); }
.bd-slot.filled{ background:linear-gradient(135deg,#065f46,#047857); color:#fff; border:none;
    box-shadow:0 3px 8px rgba(5,150,105,.25); animation:bdPop .25s cubic-bezier(0.175,0.885,0.32,1.275); }
@keyframes bdPop{ 0%{ transform:scale(.96); } 60%{ transform:scale(1.02); } 100%{ transform:scale(1); } }
.bd-slot-ic{ font-size:20px; flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center; }
.bd-slot-txt{ flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bd-slot-x{ flex:0 0 auto; cursor:pointer; opacity:.85; font-size:14px; padding:4px 8px; }
.bd-slot-x:active{ opacity:.5; }
.bd-result{ padding:12px 14px; border-radius:10px; background:var(--v2-bg-main,#E6EAF0);
    margin-top:8px; cursor:pointer; font-weight:700; font-size:14px; color:var(--v2-text,#1e293b); }
.bd-result:active{ background:rgba(148,163,184,.3); }


/* ══════════════════════════════════════════════════════════════════
   AbacusV2 虚拟算盘 (标准珠心算 1上4下)
   珠子位移全靠 .abv2-on + transform，状态由 AbacusV2.js 管理。
   尺寸由 --abv2-b (珠高) 派生，手机竖屏到桌面自适应。
   ══════════════════════════════════════════════════════════════════ */
.abv2-screen {
    width: 100%;
    max-width: 760px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.abv2-value-card {
    /* ⚠️ --v2-surface 在太空/星河/月光深色主题下已改深色，
       但 .abv2-value-label 文字是写死的 #6B7280 深灰，不跟主题走，
       深底配深字会看不清，这里固定白底保证对比度 */
    background: #fff;
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card);
    box-shadow: var(--v2-shadow-soft);
    text-align: center;
    padding: 10px 16px 14px;
}
.abv2-value-label {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1px;
    color: #6B7280;
}
.abv2-value {
    font-family: var(--v2-font-num);
    font-size: clamp(28px, 6vw, 44px);
    font-weight: 900;
    color: var(--v2-accent);
    line-height: 1.15;
    word-break: break-all;
}

/* 顶栏内联数值：竖屏不需要(数值卡已显示)，横屏去掉数值卡后顶栏顺带露出数值 */
.abv2-value-inline {
    display: none;
    font-family: var(--v2-font-num);
    font-weight: 900;
    color: var(--v2-accent);
}

/* 转横屏提示：虚拟算盘最佳操作是横屏(珠大、空间足)。竖屏进来显示这条轻提示，
   横屏(见文件末尾 landscape 区块)自动隐藏。不挡操作——用户坚持竖屏也能拨。 */
.abv2-rotate-hint {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 700;
    color: var(--v2-accent);
    background: color-mix(in srgb, var(--v2-accent) 10%, var(--v2-surface));
    border: 1.5px dashed color-mix(in srgb, var(--v2-accent) 35%, transparent);
    border-radius: var(--v2-radius-chip);
    padding: 8px 14px;
    text-align: center;
}

/* 盘框 */
.abv2-frame {
    --abv2-b: clamp(15px, 4.2vw, 30px);       /* 珠高，一切尺寸的基准(13档竖屏默认) */
    --abv2-tu: calc(var(--abv2-b) * 1.1);      /* 上珠行程 */
    --abv2-tl: calc(var(--abv2-b) * 1.2);      /* 下珠行程 */
    display: flex;
    position: relative;
    gap: 2px;
    background: var(--v2-bg-main);
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card);
    box-shadow: var(--v2-shadow-soft);
    padding: 12px 8px;

    /* ⚠️ 低端机拨珠卡顿的主因。
       珠子拖拽时每帧改 transform，但拖拽期间 transition 被设成 none，
       浏览器不会把珠子提升为独立合成层 —— 于是每动一次就**重绘整个视口**。
       实测(CPU 降频20倍，模拟旧手机)：单颗珠只有 67×57px，
       却触发 420×800 满屏重绘，60 次拖拽产生 43 次 Paint、共 106ms。

       contain:paint 告诉浏览器「这个盒子的绘制不会溢出自己的边界」，
       重绘范围因此被裁在算盘内，Paint 次数 43 → 14、耗时降 36%。
       已验证珠子在 5档/13档 × 全离梁/全贴梁/拖拽极限 六种状态下
       都不超出 frame 边界（溢出量全为 0），不会被裁掉。 */
    contain: paint;
}

/* 通梁桥接条：真算盘的梁是一根横跨全部档的整木，不是每档各一小段。
   各档 .abv2-beam 之间有 frame 的 gap，露出背景就变成断裂的虚线感。
   这条绝对定位的桥接条贴在同一高度、贯穿整个盘面，垫在各档梁下面
   补住缝隙，视觉上拼成一整根连续的梁。 */
.abv2-frame::after {
    content: '';
    position: absolute;
    left: 8px;
    right: 8px;
    top: calc(12px + var(--abv2-b) + var(--abv2-tu));
    height: 9px;
    background: var(--v2-text);
    opacity: 0.75;
    border-radius: 2px;
    z-index: 1;
    pointer-events: none;
}
/* classic-wood 的 frame padding 跟默认不一样(clamp 竖向+横向都不同)，
   桥接条的 top/left/right 要跟着它的 padding 重新对齐，否则会跟各档梁错位。 */
.abv2-frame[data-abacus-skin="classic-wood"]::after {
    left: clamp(12px, 3.2vw, 24px);
    right: clamp(12px, 3.2vw, 24px);
    top: calc(clamp(14px, 3vw, 22px) + var(--abv2-b) + var(--abv2-tu));
    height: 11px;
    background: linear-gradient(180deg, #4d3028 0%, #2f1c18 100%);
    opacity: 1;
    border: 1px solid rgba(31, 15, 11, 0.45);
    border-radius: 4px;
    box-shadow: inset 0 2px 1px rgba(255, 255, 255, 0.14), 0 2px 3px rgba(44, 20, 14, 0.22);
}

/* 竖屏少档：珠子按可用宽度放大(每档更宽了)。以档宽为准算珠高，档少珠大。
   竖屏 app 常态是 5 档——珠子明显变大、好拨。9 档为过渡值。横屏(见文件末尾)
   另按视口高度算，不受这里影响。 */
.abv2-frame[data-rods="5"] { --abv2-b: clamp(30px, 13vw, 58px); }
.abv2-frame[data-rods="7"] { --abv2-b: clamp(24px, 9vw, 46px); }
.abv2-frame[data-rods="9"] { --abv2-b: clamp(20px, 7vw, 38px); }

.abv2-rod {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
    min-width: 0;
}
/* 档杆 */
.abv2-rod::before {
    content: '';
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 50%;
    transform: translateX(-50%);
    width: 3px;
    background: rgba(0, 0, 0, 0.14);
    border-radius: 2px;
}

/* 梁：视觉上的横条由 .abv2-frame::after 通梁桥接条统一画（见上方），
   这里只保留占位高度 + 承载定位点 .abv2-dot，不再自己画条(避免和桥接条重叠)。 */
.abv2-beam {
    height: 9px;
    width: 100%;
    position: relative;
    z-index: 2;
}
.abv2-dot {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--v2-surface);
}

/* 上珠区：珠默认离梁(顶部)，激活时下移靠梁 */
.abv2-deck-upper {
    height: calc(var(--abv2-b) + var(--abv2-tu));
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: flex-start;
}
/* 下珠区：珠默认离梁(底部)，激活时上移靠梁 */
.abv2-deck-lower {
    height: calc(var(--abv2-b) * 4 + var(--abv2-tl));
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
}

.abv2-bead {
    width: 88%;
    max-width: calc(var(--abv2-b) * 2.3);
    height: var(--abv2-b);
    /* ⚠️ 必须 border-box：珠子的高度基准是 --abv2-b，而 deck 的高度、
       贴梁行程(--abv2-tu/--abv2-tl)全都按 --abv2-b 推算。默认 content-box
       会把 skin 的 1px 边框加在 height 之外，每颗珠实际高出约 2.5px ——
       上珠只有 1 颗(溢出 2px 尚可忽略)，下珠 4 颗累加就溢出 8px，
       贴梁时第一颗下珠整个沉到梁底下去，看起来「藏在梁下面」。
       写死 border-box 让边框吃进 --abv2-b 内，上下两层才对称贴合。 */
    box-sizing: border-box;
    border-radius: 50%;
    background: var(--v2-primary);
    box-shadow: inset 0 calc(var(--abv2-b) * -0.22) 0 rgba(0, 0, 0, 0.18),
                inset 0 calc(var(--abv2-b) * 0.16) 0 rgba(255, 255, 255, 0.35);
    cursor: pointer;
    position: relative;
    z-index: 1;
    transition: transform 0.12s ease;
    touch-action: none;   /* 拖拽需要完全接管手势，防止竖直拖珠时触发页面滚动 */
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
}
/* 扩大触控热区（珠子在手机上只有 ~20px 高） */
.abv2-bead::after {
    content: '';
    position: absolute;
    inset: -4px;
}
.abv2-deck-upper .abv2-bead.abv2-on { transform: translateY(var(--abv2-tu)); }
.abv2-deck-lower .abv2-bead.abv2-on { transform: translateY(calc(var(--abv2-tl) * -1)); }

/* 作答算盘：现代木质教具风格。只影响题目里的算盘，不改自由练习算盘。 */
.abv2-frame[data-abacus-skin="classic-wood"] {
    gap: clamp(5px, 1.5vw, 12px);
    padding: clamp(14px, 3vw, 22px) clamp(12px, 3.2vw, 24px);
    background:
        linear-gradient(145deg, rgba(255, 255, 255, 0.2), transparent 42%),
        linear-gradient(135deg, #a6643f 0%, #7b422c 48%, #613022 100%);
    border: 2px solid #54291e;
    border-radius: clamp(18px, 5vw, 28px);
    box-shadow:
        inset 0 0 0 3px rgba(255, 224, 185, 0.34),
        inset 0 -7px 10px rgba(62, 24, 14, 0.18),
        0 7px 0 #d7a27d,
        0 12px 24px rgba(74, 38, 25, 0.16);
}

.abv2-frame[data-abacus-skin="classic-wood"][data-rods="3"] {
    --abv2-b: clamp(30px, 10vw, 44px);
    gap: clamp(10px, 3vw, 20px);
}

.abv2-frame[data-abacus-skin="classic-wood"] .abv2-rod::before {
    width: 4px;
    background: linear-gradient(90deg, #8c735e 0%, #f0d4aa 44%, #9a7b60 100%);
    border: 1px solid rgba(72, 48, 34, 0.28);
    box-shadow: 1px 0 2px rgba(255, 255, 255, 0.35);
}

.abv2-frame[data-abacus-skin="classic-wood"] .abv2-beam {
    height: 11px;
}

.abv2-frame[data-abacus-skin="classic-wood"] .abv2-dot {
    width: 7px;
    height: 7px;
    background: #f8e7ce;
    border: 1px solid rgba(60, 32, 24, 0.28);
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.16);
}

.abv2-frame[data-abacus-skin="classic-wood"] .abv2-bead {
    width: 94%;
    max-width: calc(var(--abv2-b) * 2.45);
    border-radius: 36% 36% 42% 42% / 48% 48% 52% 52%;
    /* ⚠️ 只用单层渐变。这里原本还叠了一层 90deg 的侧面暗边
       （linear-gradient(90deg, rgba(105,31,12,.25), transparent 18%,
       transparent 82%, rgba(105,31,12,.28))），意图是给珠子加左右两侧的
       立体收边。但珠子实际宽度只有 ~60px，那两道暗边各占 18% 且本身
       透明度很低，在真实尺寸下肉眼分辨不出（2 倍图逐像素对比也看不出差别）。
       代价却很实在：拖拽时每颗珠每帧都要多合成一层渐变 ——
       去掉后 Paint 从 78.9ms 降到 64.0ms（快 19%，CPU 降频 20 倍实测）。
       ⚠️ 别再加回来，也别在这里叠新的渐变层：珠子是全场重绘最频繁的元素，
       它的绘制成本会乘以珠子数量(13档=65颗)再乘以帧数。 */
    background: linear-gradient(180deg, #ffb75b 0%, #ff8a28 34%, #e85c12 72%, #bc3d09 100%);
    border: 1px solid rgba(157, 54, 12, 0.65);
    box-shadow:
        inset 0 3px 2px rgba(255, 235, 190, 0.58),
        inset 0 -4px 3px rgba(137, 35, 6, 0.26),
        0 2px 2px rgba(74, 29, 14, 0.22);
}

.abv2-frame[data-abacus-skin="classic-wood"] .abv2-bead:active {
    filter: brightness(1.05);
}

/* 工具条（用 div 避开 .v2-content button 全局样式） */
.abv2-toolbar {
    display: flex;
    justify-content: center;
    gap: 12px;
}
.abv2-btn {
    padding: 12px 30px;
    border-radius: 14px;
    /* ⚠️ 这里要的是「永远白底 + 永远深字」，不能读 --v2-surface：
       该变量现在被数字键盘等组件当成「跟主题一起变深」的开关用，
       太空冒险/星河/月光已把它改成深色——读它就会变成深底配下面
       写死的深字，看不清。改用真正固定的 #fff，不随任何主题变化。 */
    background: #fff;
    border: var(--v2-card-border);
    box-shadow: var(--v2-shadow-soft);
    font-weight: 900;
    font-size: 15px;
    color: #1F2937;
    cursor: pointer;
    text-align: center;
    user-select: none;
    -webkit-user-select: none;
    transition: var(--v2-transition-fast);
}
.abv2-btn:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

/* ── 算盘作答模式：看算式后，用算盘拨答 + 确认/清盘钮 ── */
.abv2-answer-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    width: 100%;
    max-width: 760px;
    margin: 0 auto;
}
.abv2-answer-board {
    width: 100%;
}
.abv2-answer-actions {
    display: flex;
    gap: 14px;
    justify-content: center;
    flex-wrap: wrap;
}
.abv2-btn-confirm {
    background: var(--v2-secondary);
    color: #fff;
    border-color: var(--v2-secondary-dark);
}
.abv2-btn-confirm:active {
    transform: translateY(var(--v2-shadow-depth));
    box-shadow: none;
}

/* ══════════════════════════════════════════════════════════════════
   笔算模式 (WRITTEN MODE)
   题目与输入框同屏。题目区可压缩、键盘区不可压缩 —— 口数多时优先
   让题目自己缩（配合 fitLookList），保证数字键盘永远点得到。
   ══════════════════════════════════════════════════════════════════ */
.v2-written-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    height: 100%;
    gap: 4px;
    min-height: 0;
}
/* 题目区：占据键盘之外的剩余高度。必须给 min-height:0，否则 flex 子项
   默认 min-height:auto 会被内容(超大字号)撑开，把键盘挤出屏幕。 */
/* .v2-look-simple-container 全局有 flex:1（看算下它独占舞台）；这里用
   更高特异性接管尺寸，否则两处 flex 打架。 */
.v2-written-wrap .v2-written-question {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    justify-content: center;
    overflow: hidden;
}
/* ⚠️ .v2-input-area 全局带 height:100%（它原本独占舞台）。嵌进笔算后
   它会索要整屏高度，把题目区压成 0 —— 画面上只剩键盘、题目一片空白。
   必须在这里改回 auto。 */
.v2-written-wrap .v2-input-area {
    flex: 0 0 auto;
    width: min(330px, calc(100% - 24px));
    max-width: 330px;
    height: auto;
    gap: 10px;
    box-sizing: border-box;
}
/* 与键盘同屏，字号必须比看算(clamp 45-200px)小得多，否则一行就吃掉整屏。
   fitLookList 只在溢出时才缩，起点太大会先被裁切。 */
.v2-written-wrap .v2-look-list {
    padding: 6px 15px;
    min-width: 0;
}
.v2-written-wrap .v2-look-item {
    font-size: clamp(22px, 7vw, 46px);
}
.v2-written-wrap .v2-num-multi {
    font-size: clamp(24px, 8vw, 52px);
}

/* 算盘作答的题目是主要视觉信息，竖屏不要沿用笔算的紧凑起始字号。
   ⚠️ 中间项必须同时含 vh：原本只有 vw，字号纯按「宽度」算 —— 高身手机
   (窄但高)命中不了下面 max-height:700px 的小屏规则，于是键盘照常吃掉 4 行
   高度，题目却因为屏窄一直停在 44~46px，上方大片留白没人用（学生反馈
   「题目太小、keypad 太大」即此）。改用 max(vw, vh) 让纵向空间也能把字顶上去；
   溢出仍由 fitLookList 缩回，所以起点放大是安全的。 */
@media (orientation: portrait) {
    .v2-written-wrap .v2-look-item {
        font-size: clamp(44px, max(12vw, 9vh), 96px);
    }
    .v2-written-wrap .v2-num-multi {
        font-size: clamp(42px, max(11vw, 8.5vh), 92px);
    }
    .abv2-written-wrap .v2-look-item {
        font-size: clamp(48px, 14vw, 78px);
    }
    .abv2-written-wrap .v2-num-multi {
        font-size: clamp(44px, 12vw, 72px);
    }

    /* ⚠️ 算盘作答竖屏：算盘必须可压缩，否则「清盘/确认」被顶出屏幕。
       跟横屏(见文件末尾 orientation:landscape 那块)是**同一个坑**，当时只补了横屏。

       症状：题目行数一多(3 口以上)，题目区吃掉高度，算盘却按 data-rods 的
       vw 珠高硬撑住不缩 —— 实测 390x844、答案 166(5 档)：舞台只有 330px，
       算盘自己就 414px，两个按钮被推到视口下方 452px 处，此屏又不滚动 →
       根本按不到，题目做不下去。

       修法照抄横屏那套：算盘是唯一可压缩项(flex:1 1 auto + min-height:0，
       不加 min-height:0 的话 flex 子项默认 min-height:auto 会按珠子总高撑住)，
       标签和按钮固定不动，珠高改用 vh 让它跟着可用高度走。 */
    /* ⚠️ 全局 .v2-written-wrap .v2-input-area 是 flex:0 0 auto(给键盘写的，
       键盘高度固定所以不用缩)。算盘会随档数变高，必须允许收缩，
       否则它按内容高度硬撑，把按钮连同自己一起顶出舞台。 */
    .v2-input-area.abv2-answer-area {
        flex: 1 1 auto;
        max-height: 100%;
        min-height: 0;
        overflow: visible;
    }
    /* 题目与算盘按比例分高度，两边都可压缩(min-height:0)。
       ⚠️ 别用 min-height 给题目保底、也别给算盘设 max-height 百分比：
       min-height 在 CSS 里永远压过 max-height，一旦保底值大于实际可用高度，
       溢出的部分就会把按钮顶出舞台 —— 这正是上面 32vh 那条踩的坑。
       改用 flex 比例：高度紧张时两边一起等比缩，按钮永远留得住。 */
    /* ⚠️ 分高度不能只写 flex 比例：题目区的**内容**（几行大字）撑出很大的
       自然高度，flex-basis:0 也压不住它，实测 360x640 题目吃掉 154/228px，
       算盘容器被挤成 0 —— fitBoard 量到可用高度为 0 直接放弃，盘面于是原样
       溢出、按钮被顶到屏幕外。用 max-height 给题目封顶，剩下的才够算盘用。
       字号那边 fitLookList 会自动把字缩进这个高度，不会被裁。 */
    .abv2-written-wrap .v2-written-question {
        flex: 0 1 auto;
        min-height: 0;
        max-height: 46%;
    }
    .abv2-written-wrap .abv2-answer-area {
        flex: 1 1 auto;
        min-height: 0;
        /* 按钮不要贴死屏幕最底边（含手势条机型），留一点安全边距 */
        padding-bottom: max(8px, env(safe-area-inset-bottom));
    }
    .abv2-answer-area .abv2-answer-board {
        min-height: 0;
        flex: 1 1 auto;
        overflow: hidden;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .abv2-answer-area .v2-input-label,
    .abv2-answer-area .abv2-answer-actions {
        flex: 0 0 auto;
    }
    .abv2-answer-area .abv2-answer-board .abv2-frame {
        max-height: 100%;
        /* ⚠️ 必须写宽度。上面把 board 改成了 display:flex（为了让盘面垂直居中、
           可压缩），frame 就变成 flex 项，默认 flex:0 1 auto 会**按内容收缩**——
           档位只是几根细杆，于是整个盘缩成一条 54px 宽的竖条，珠子 width:88%
           跟着塌成 2px，画面上只剩三根杆子（366x692 实测）。
           横屏那套本来就有 width:100%，竖屏这块当初漏抄了这一行。 */
        width: 100%;
        box-sizing: border-box;
    }
    /* 珠高的「起点」：同时受宽度和高度约束，min() 取较小值。
       ⚠️ 不能加 !important —— AbacusAnswerEngineV2.fitBoard() 会按盘面**实际**
       分到的高度写行内 --abv2-b 收尾（CSS 算不到 flex 分配后的高度）。
       加了 !important 行内值就被这条压过，珠子永远不缩，等于没修。 */
    .abv2-answer-area .abv2-frame,
    .abv2-answer-area .abv2-frame[data-rods] {
        --abv2-b: min(clamp(22px, 11vw, 52px), 6.4vh);
    }
}

/* ── 指法示范竖屏：把高度还给题目 ────────────────────────────────
   问题：这一屏比普通算盘作答多了「口诀 chip + 指法提示 + 判断反馈 +
   三个按钮」，且按钮窄屏会换行成三行。3 档算盘的珠高按 10vw 算
   (classic-wood 皮肤)，390px 机上珠高 39px → 一盘约 300px。
   加起来把题目区压到只剩几十 px，fitLookList 于是把 5 行数字一路缩到
   ~28px —— 题目(这一屏真正要读的东西)比按钮文字还小(实测截图确认)。
   对策两条，缺一不可：
   1) 题目区保底 30vh —— fitLookList 是按容器实测高度缩字的，
      不先把空间留出来，单调字号也会被它缩回去；
   2) 算盘珠高改按视口高度封顶(横屏早就这么做，见文件末尾矮横屏区块)。
      ⚠️ 盘高只能靠 --abv2-b 调，不可用 max-height 压：盘的自然高度是
      死公式 ≈7.3b + 35px，没有可伸缩项，压矮不会让珠子变小。
      珠高 5vh x 7.3 ≈ 37vh + 题目 22vh + chip/提示/反馈/按钮 ≈ 满屏，
      按钮刚好留在屏内(390x844 / 320x568 实测)。 */
@media (orientation: portrait) {
    /* ── 纵向预算（单一来源）────────────────────────────────────────
       这一屏不滚动，所以「题目 + chip + 提示 + 盘 + 反馈 + 按钮」必须
       恰好装进一屏。从前各块各写各的 vh，固定开销只在注释里估成一个
       「≈」值 —— 实测竖屏按钮**换行**后是 88px 而非估的 36px，误差直接
       变成超支：10 个尺寸里 6 个把按钮挤出屏幕(HEAD 实测)。
       现在把固定开销显式声明成变量，珠高从「剩余空间」反推而不是猜 vh。
       改这里之前先跑 test/written-layout/guided-budget 看总账。 */
    .guided-abacus-wrap {
        /* chip 37 + 按钮单行 41 + gap/边距 ≈ 30。
           指法提示与反馈行常态为空(已改成只在拨错/判断中才显示)，
           故不计入固定开销 —— 省下的 42px 全给算盘和题目。 */
        --guided-fixed: 108px;
        /* 题目是这一屏真正要读的东西 —— 22vh 时字号被 fitLookList 压到
           23~28px，比按钮文字还小。但纯 vh 在高身手机上会过头(844px 机
           34vh=287px，加上盘 333px + 固定 150px 远超可用 562px，按钮出屏)。
           用 min() 同时给相对与绝对上限：屏越高越不该无限放大题目。 */
        --guided-q: min(34vh, 220px);         /* 题目区目标高度 */
        /* 一屏总额 = 92vh(扣顶栏/边距)，题目与盘共享同一份：
             盘 = 92vh - 题目(--guided-q) - 固定块(--guided-fixed)
           ⚠️ 题目和盘必须扣同一份总额，各算各的就会打架(题目放大时盘不
           收缩，按钮立刻被顶出屏)。
           ⚠️ 同样重要：珠高上限不能写死 —— 写死 40px 时预算再小也没用，
           盘照样按上限渲染(390x844 实测 预算给 41.7px 却仍渲染 40px 上限，
           盘 333px 撑爆)。上限必须与预算取小，见下方 min()。 */
        --guided-board: calc(92vh - var(--guided-fixed) - var(--guided-q));
        --guided-b: calc((var(--guided-board) - 35px) / 7.3);
    }
    .guided-abacus-wrap .abv2-question {
        min-height: var(--guided-q);
        /* ⚠️ 只给下限会被内容撑开(flex 子项默认 min-height:auto)：5 口题把
           题目区顶到 302px，fitLookList 拿 clientHeight 判断「没溢出」于是
           不缩字，外层 overflow:hidden 再切掉超出部分 —— 画面上第一行只剩
           半截横线(502x947 实测 内容 432 vs 容器 274)。必须给上限 + 收缩权。 */
        /* ⚠️ 上限就是预算值本身，不能再加宽放 —— 曾写 +12vh，390x844 实测
           题目吃到 267px(预算只给 186px)，多出来的 80px 直接把按钮顶出屏幕。
           题目要更大是靠 fitLookList 在这个高度内放大字号，不是靠占更多格。 */
        max-height: var(--guided-q);
        flex: 0 1 auto;
    }
    .guided-abacus-wrap .abv2-answer-area {
        min-height: 0;
    }
    /* ⚠️ 同横屏：不要给盘限宽，会被 gap/padding 吃光导致档杆只剩几 px。
       竖屏珠子长宽比实测 1.4~1.9，本来就正常。 */
    /* !important 压过 data-rods / data-abacus-skin 那几条 vw 基准的高优先级规则 */
    .guided-abacus-wrap .abv2-frame,
    .guided-abacus-wrap .abv2-frame[data-rods],
    .guided-abacus-wrap .abv2-frame[data-abacus-skin][data-rods] {
        /* 珠高由上面的预算反推(--guided-b)，不再猜 vh。
           ⚠️ 上限必须用 min() 与预算取小，不能写死 40px —— 写死时
           390x844 / 320x568 的珠高被顶到上限、预算形同虚设，盘照样撑爆
           (实测这两屏盘高与大屏一模一样，按钮出线 17~61px)。
           16px 是可点下限，宁可盘小也不能让「示范一次」按不到。 */
        --abv2-b: max(16px, min(var(--guided-b), 40px)) !important;
    }
    /* ⚠️ 按钮必须单行 —— 这是 --guided-fixed 只算 40px 的前提。
       三个按钮默认会换行成两行(实测 88px)，白吃 50px 高度，正是竖屏
       「示范一次」被挤出屏幕的主因。等分宽度 + 不换行 + 解除 min-width。 */
    .guided-abacus-wrap .abv2-btn {
        padding: 9px 10px;
        font-size: 13px;
        white-space: nowrap;
        min-width: 0;
        flex: 1 1 0;
    }
    .guided-abacus-wrap .abv2-answer-actions {
        gap: 6px;
        flex-wrap: nowrap;
        width: 100%;
    }
}

/* 矮竖屏(320x568 这类老小屏)：字号/内边距整体再收一档，固定开销随之变小，
   题目也让一点 —— 只改预算变量，珠高会自动跟着重算(见上方 --guided-b)。 */
@media (orientation: portrait) and (max-height: 700px) {
    .guided-abacus-wrap {
        --guided-fixed: 90px;    /* 同上，小屏 chip/按钮更矮 */
        --guided-q: min(26vh, 150px);   /* 小屏也别把题目压成蚂蚁字，见上 */
        --guided-board: calc(94vh - var(--guided-fixed) - var(--guided-q));
    }
    .guided-abacus-wrap .abv2-question {
        min-height: var(--guided-q);
    }
    .guided-abacus-wrap .abv2-frame,
    .guided-abacus-wrap .abv2-frame[data-rods],
    .guided-abacus-wrap .abv2-frame[data-abacus-skin][data-rods] {
        /* 小屏上限收到 26px：32px 时盘仍 269~276px，对 568~640px 高的屏
           太大，按钮出线 17~64px(实测)。宁可盘小也要保住「示范一次」可点。 */
        --abv2-b: max(14px, min(var(--guided-b), 26px)) !important;
    }
    .guided-abacus-wrap .abv2-btn {
        padding: 7px 10px;
        font-size: 12px;
        min-width: 0;
    }
    .guided-abacus-wrap .abv2-answer-actions {
        flex-wrap: nowrap;
        gap: 5px;
    }
    .guided-abacus-wrap .guided-step-feedback {
        min-height: 0;
    }
    /* 收掉最后几 px：竖排各块的间距 + 底部留白，让按钮完整落在屏内 */
    .guided-abacus-wrap .abv2-answer-area {
        gap: 4px;
        padding-bottom: 4px;
    }
    .guided-abacus-wrap .guided-fingering-hint {
        padding: 0;
    }
}

/* ── 小屏竖屏：键盘按视口高度封顶，别把题目区挤没 ──────────────────
   问题：.v2-neu-key 是 aspect-ratio:1/1 + min-height:60px，宽度撑满时
   按键跟着变高，4 行 + 间距 = 294~376px。在 536px 高的小屏上，题目区
   只剩 23~56px，5 口题(内容 244px)被 overflow:hidden 从中间裁断 ——
   用户看到数字只剩上半截、几行糊在一起(266x536 / 320x568 实测)。
   390x844 基线机题目区有 282px，所以一直没暴露。
   仅缩「按键尺寸」不动布局结构：键高改由视口高度算，把省下的高度
   还给题目区；fitLookList 再按实际空间缩字号，两者配合才放得下。
   只命中竖屏且矮(≤700px)的小屏，基线机与平板不受影响。 */
@media (orientation: portrait) and (max-height: 700px) {
    .v2-written-wrap .v2-neu-key {
        /* (视口高 - 顶栏/题目区预留 ~46% - 3 道间隙) / 4 行 */
        --v2-keyh: calc((100vh * 0.46 - 30px) / 4);
        min-height: 0;
        height: var(--v2-keyh);
        max-height: 62px;
        width: var(--v2-keyh);
        max-width: 62px;
        aspect-ratio: auto;
        font-size: clamp(15px, 4.5vh, 24px);
    }
    .v2-written-wrap .v2-neu-numpad {
        gap: clamp(5px, 1.2vh, 10px);
        width: auto;
        justify-content: center;
    }
    .v2-written-wrap .v2-neu-input-box {
        height: clamp(38px, 7vh, 58px);
        font-size: clamp(20px, 4.5vh, 30px);
    }
    /* 题目区拿回主导权：至少占 ~1/4 屏，字才有地方缩。
       同上：排除跟拨，它的题目高度由 --guided-q 单独管。
       ⚠️ 也要排除算盘作答：算盘比数字键盘高得多，这条 24vh 保底会把
       盘面容器压成 0 高，「清盘/确认」跟着掉出屏幕(360x640 实测)。
       min-height 永远压过 max-height，所以只能在这里排除，不能靠后面补 max。 */
    .v2-written-wrap:not(.guided-abacus-wrap):not(.abv2-written-wrap) .v2-written-question {
        min-height: 24vh;
    }

    /* 矮屏的算盘作答：标签和按钮压扁，把省下的高度让给题目和盘面
       （跟横屏那套同理）。不这么做的话 360x640 上珠子会被挤到 13px 拨不动。 */
    .abv2-written-wrap .v2-input-label {
        font-size: 12px;
    }
    .abv2-written-wrap .abv2-btn {
        padding: 8px 22px;
        font-size: 13px;
    }
}

/* ── 高身手机竖屏：别让键盘按视口宽度长胖 ────────────────────────
   .v2-neu-key 基础样式是 width:100% + aspect-ratio:1/1 + max-width:85px，
   完全按「宽度」定尺寸。上面的小屏规则只收 max-height:700px，所以 844px+
   的高身手机两头不沾：键盘按宽度长到满格(4 行接近半屏)，题目却还是小字，
   中间空一大块。这里按视口高度给键盘设上限，把富余高度还给题目区。 */
@media (orientation: portrait) and (min-height: 701px) {
    /* ⚠️ 只压「高度」，绝不动宽度。曾同时写 max-width + numpad{width:auto}，
       结果键盘从 297px(与输入框同宽)缩成 208px 挤作一坨居中 —— 用户一眼
       看出「keypad 变了款」。宽度撑满是这套拟物键盘的原始造型，
       要省的是纵向空间，跟宽度无关。 */
    .v2-written-wrap .v2-neu-key {
        aspect-ratio: auto;          /* 解除 1:1，否则高度会被宽度反向锁死 */
        height: clamp(52px, 7.2vh, 72px);   /* 按钮变扁而不变窄 */
        min-height: 0;               /* 基础样式的 min-height:60px 会顶掉上面的高度 */
    }
    /* 题目区吃下省出来的高度（配合上面的 vh 字号才看得出效果）。
       ⚠️ 必须排除跟拨：跟拨的 wrap 同时带 .v2-written-wrap 和
       .guided-abacus-wrap 两个类，会被这条命中。而 min-height 在 CSS 里
       永远压过 max-height —— 跟拨题目区因此被顶到 270px(它自己的预算只给
       186px)，多出的 84px 直接把「示范一次」挤出屏幕(390x844 实测)。
       跟拨的题目高度由 --guided-q 单独管，见本文件跟拨预算区块。 */
    /* ⚠️ 算盘作答(.abv2-written-wrap)也必须排除，理由跟跟拨一模一样。
       这条是给**数字键盘**布局写的——键盘矮，题目区拿 32vh 绰绰有余。
       算盘盘面比键盘高得多：390x844 实测舞台只有 330px，题目被这条顶到
       270px，只剩 60px 给算盘+标签+按钮，「清盘/确认」直接掉出屏幕按不到。
       算盘作答的题目高度交给 flex 自己分配(上面 portrait 区块已让盘面可压缩)。 */
    .v2-written-wrap:not(.guided-abacus-wrap):not(.abv2-written-wrap) .v2-written-question {
        min-height: 32vh;
    }
}

/* ── 宽屏分栏：题目在左、键盘在右 ────────────────────────────────
   电脑 / 电子白板 / 平板命中；手机竖屏(窄)与手机横屏(矮)都不命中，
   维持上下堆叠。
   ⚠️ 不用纯 min-width 硬切：手机横屏也能宽到 800px+，但高度只有
   ~400px，分栏会把两边都压扁 —— 必须同时要求足够高度。 */
@media (min-width: 820px) and (min-height: 620px) {
    .v2-written-wrap {
        flex-direction: row;
        align-items: stretch;
        gap: 20px;
        padding: 0 12px;
        box-sizing: border-box;
    }
    .v2-written-wrap .v2-written-question {
        flex: 1 1 50%;
        min-width: 0;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .v2-written-wrap .v2-input-area {
        flex: 0 1 46%;
        max-width: 460px;
        align-self: center;
    }
    /* 横向有空间了，题目可以放大回看算的量级 */
    .v2-written-wrap .v2-look-item {
        font-size: clamp(60px, 10vw, 112px);
    }
    .v2-written-wrap .v2-num-multi {
        font-size: clamp(56px, 9vw, 104px);
    }
}

/* 大屏／投影：算盘作答不能停留在手机卡片尺寸。仅放大算盘类布局。 */
@media (min-width: 1400px) and (min-height: 760px) {
    .v2-written-wrap.abv2-written-wrap {
        width: min(1500px, calc(100% - 8vw));
        max-width: 1500px;
        gap: clamp(70px, 8vw, 150px);
        padding: clamp(30px, 5vh, 64px) 30px;
    }
    .v2-written-wrap.abv2-written-wrap .abv2-question {
        flex: 1 1 52%;
        max-width: 760px;
    }
    .v2-written-wrap.abv2-written-wrap .v2-look-item {
        font-size: clamp(96px, 7vw, 150px);
    }
    .v2-written-wrap.abv2-written-wrap .v2-num-multi {
        font-size: clamp(88px, 6.5vw, 138px);
    }
    .v2-written-wrap.abv2-written-wrap .abv2-answer-area {
        flex: 0 0 clamp(480px, 31vw, 620px);
        width: clamp(480px, 31vw, 620px);
        max-width: 620px;
        padding: clamp(20px, 2vw, 32px);
        gap: clamp(14px, 1.5vh, 22px);
    }
    .v2-written-wrap.abv2-written-wrap .abv2-answer-board {
        width: 100%;
    }
    .v2-written-wrap.abv2-written-wrap .abv2-frame[data-rods="3"] {
        --abv2-b: clamp(48px, 5.5vh, 68px);
        gap: clamp(18px, 2vw, 30px);
    }
    .v2-written-wrap.abv2-written-wrap .abv2-frame[data-rods="5"] {
        --abv2-b: clamp(38px, 4.5vh, 56px);
    }
    .v2-written-wrap.abv2-written-wrap .abv2-btn {
        min-width: 150px;
        padding: 15px 32px;
        font-size: 17px;
    }
    .v2-written-wrap.abv2-written-wrap .v2-input-label,
    .v2-written-wrap.abv2-written-wrap .guided-step-chip {
        font-size: 17px;
    }
}

/* 笔算宽屏舞台：限制视觉跨度，避免题目居中而键盘贴住屏幕最右侧 */
@media (min-width: 820px) and (min-height: 620px) {
    .v2-written-wrap {
        width: min(1040px, calc(100% - 64px));
        max-width: 1040px;
        margin: 0 auto;
        padding: clamp(12px, 2vw, 24px) clamp(12px, 2.5vw, 28px);
        gap: clamp(24px, 5vw, 84px);
        align-items: center;
    }
    .v2-written-wrap .v2-written-question {
        flex: 1 1 0;
        max-width: 560px;
        align-self: stretch;
        border-radius: var(--v2-radius-card);
    }
    .v2-written-wrap .v2-input-area {
        flex: 0 0 330px;
        width: min(330px, calc(100% - 24px));
        max-width: 330px;
        padding: clamp(12px, 1.8vw, 18px);
        gap: clamp(10px, 1.4vw, 14px);
        border: 2px solid var(--v2-border-main);
        border-radius: var(--v2-radius-card);
        background: color-mix(in srgb, var(--v2-primary) 5%, var(--v2-surface));
        box-shadow: 0 5px 0 var(--v2-border-main);
        box-sizing: border-box;
    }
    .v2-written-wrap .v2-neu-input-box,
    .v2-written-wrap .v2-neu-numpad {
        width: 100%;
        max-width: none;
    }
    .v2-written-wrap .v2-neu-input-box {
        height: 68px;
        background: var(--v2-surface);
        border: 2px solid var(--v2-border-main);
    }
    .v2-written-wrap .v2-neu-key {
        max-width: 82px;
        border-radius: 18px;
    }
}

/* ── 挑战模式自注入 header (#ch-header) ────────────────────────────
   ChallengeEngineV2._renderHeader() 用 insertBefore(header, stage) 插在
   舞台前面，是**流式**元素；而返回键 .back-btn 是 position:absolute 钉在
   left:14px(宽约 42px)。两者互不知情 —— 只要 header 左内边距不够，
   返回键就压住计时器，「5:00」只剩「:00」(学生横屏截图即此)。
   竖屏返回键同样浮在左上，所以左边距横竖屏都要留。 */
.ch-header {
    padding: 10px 16px;
    padding-left: 68px;   /* 14px(left) + 42px(宽) + 12px 呼吸 */
    box-sizing: border-box;
    flex: 0 0 auto;
}
/* 矮横屏：这条 header 是流式元素，占的高度不算在 .v2-player-stage 里，
   等于把下方内容整体下推 —— 键盘卡片因此被挤出视口下缘(边框出线，
   实测 844x390 出线 3px)。压扁它把高度还给舞台。 */
@media (orientation: landscape) and (max-height: 619px) {
    .ch-header {
        padding-top: 4px;
        padding-bottom: 4px;
        margin-bottom: 4px;
        font-size: 13px;
    }
    .ch-header #ch-time { font-size: 17px; }
}

/* ══════════════════════════════════════════════════════════════════
   横屏矮屏优化 (LANDSCAPE — SHORT VIEWPORT)
   命中「横屏(宽>高) 且 高度 ≤ 619px」的场景。
   - orientation:landscape 保证 宽>高，竖屏(高>宽)永不匹配 → PORTRAIT 零改动
   - 让竖排键盘放不下的真实横屏(手机/平板竖握横屏)都受益，
     iPad 横屏(768px)高度充足，不受影响。
   ⚠️ 上限曾是 600px，与下方分栏规则的 min-height:620px 之间留下
   601~619px 的**夹缝**：两条规则都够不着，横屏却走竖屏堆叠 ——
   88px 白顶栏把计时器推到返回键底下(被盖住)，键盘保持 85px 大尺寸
   撑爆视口(边框出线)。实测 946x605 键盘出线 1px、题目区只剩 42px。
   现改 619 与 620 接上，中间不留空隙。改这里必须连同 WrittenEngineV2
   的两处 matchMedia 一起改，否则 CSS 生效而 JS 判定不生效，又是夹缝。
   此区块只新增覆盖，绝不改动竖屏样式。
   ══════════════════════════════════════════════════════════════════ */
@media (orientation: landscape) and (max-height: 619px) {

  /* 算盘作答不是数字输入 Grid：横屏恢复完整横向算盘，并按实际档数控制宽度。 */
  .v2-input-area.abv2-answer-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    max-width: 760px;
    height: 100%;
    padding: 8px 16px;
    gap: 8px;
    box-sizing: border-box;
  }
  .abv2-answer-area .abv2-answer-board {
    width: min(72vw, 560px);
    max-width: 100%;
  }
  .abv2-answer-area .abv2-answer-board[data-rods="3"] { width: min(48vw, 300px); }
  .abv2-answer-area .abv2-answer-board[data-rods="5"] { width: min(58vw, 400px); }
  .abv2-answer-area .abv2-frame {
    width: 100%;
    box-sizing: border-box;
  }

  /* ⚠️ 横屏关键修正：珠高必须按「视口高度」算，不能按宽度。
     data-rods 的默认尺寸(如 3 档 clamp(30px,10vw,44px))全是 vw 基准 ——
     横屏时屏幕又宽又矮，10vw 直接顶到 44px 上限，算盘被撑到 382px 高，
     而手机横屏可用高度只有 390px，结果上方被裁、下方「清盘/确认」两个
     按钮整个掉出屏幕，而且此屏不滚动 → 根本按不到，题目做不下去。
     #v2-screen-abacus 早就用 vh 修过同一个坑(见本区块末尾)，
     当时只改了独立算盘屏，算盘作答的 player 漏掉了，这里补上。
     !important 用来压过 data-rods / data-abacus-skin 那几条更高优先级的 vw 规则。
     上限取值：一盘自然高度 ≈ 珠高 x 7.6(7 颗珠 + 梁 + 边框)，要塞进
     (视口高 - 顶部题号 - 按钮 - 边距) ≈ 视口高 x 0.72，倒推珠高 ≤ 9.5vh；
     取 7.6vh 留安全余量，保证任何矮横屏都压不到按钮。 */
  .abv2-answer-area .abv2-frame,
  .abv2-answer-area .abv2-frame[data-rods] {
    --abv2-b: clamp(14px, 7.6vh, 40px) !important;
  }

  /* 面板整体不许超出视口：算盘可压缩，标签和按钮固定，
     保证「确认」永远点得到(这才是能不能继续做题的底线)。 */
  .v2-input-area.abv2-answer-area {
    max-height: 100%;
    overflow: visible;
  }
  /* 算盘是唯一可压缩项：min-height:0 + overflow:hidden 才真的会缩。
     不加 min-height:0 的话 flex 子项默认 min-height:auto，
     算盘按内容(珠子总高)撑住不肯让步，就会直接盖到按钮上面去。 */
  .abv2-answer-area .abv2-answer-board {
    min-height: 0;
    flex: 1 1 auto;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .abv2-answer-area .v2-input-label,
  .abv2-answer-area .abv2-answer-actions {
    flex: 0 0 auto;
  }
  /* frame 跟着容器高度走，珠子按 flex 自适应，不再溢出到按钮区 */
  .abv2-answer-area .abv2-answer-board .abv2-frame {
    max-height: 100%;
  }
  /* 矮横屏下按钮压扁一点，把高度还给算盘 */
  .abv2-answer-area .abv2-btn {
    padding: 8px 22px;
    font-size: 13px;
  }
  .abv2-answer-area .v2-input-label {
    font-size: 12px;
  }

  /* 横屏 Header：返回键独立左上，进度只占左侧题目栏；舞台使用完整高度。 */
  #v2-screen-player {
    position: relative;
  }
  #v2-screen-player .screen-header {
    position: absolute;
    inset: 0 auto auto 0;
    width: 100%;
    height: 100%;
    padding: 0;
    background: transparent;
    border-bottom: 0;
    z-index: 120;
    pointer-events: none;
  }
  #v2-screen-player .screen-header .v2-header-side {
    position: absolute;
    top: 12px;
    left: 14px;
    width: auto;
    flex: none;
    pointer-events: auto;
  }
  #v2-screen-player .screen-header .v2-global-progress {
    position: absolute;
    top: auto;
    right: auto;
    /* #app 已统一让开安全区，这里不能再加 env() —— 会重复计算把胶囊顶高一截 */
    bottom: 10px;
    left: 50% !important;
    width: auto;
    transform: translateX(-50%);
    gap: 5px;
    align-items: center;
  }
  /* ⚠️ 笔算横屏：位置由 WrittenEngineV2._alignLandscapeHeader() 按题目框算，
     写的是内联 left。上面那条 `left:50% !important` 会压过内联样式 —— JS 对齐
     等于没生效，进度条永远停在视口正中，正好压在键盘上（学生横屏截图即此）。
     这里把笔算的 left 交还给 JS，仅保留居中位移的抵消。 */
  #v2-screen-player.written-active .screen-header .v2-global-progress {
    left: 0;
    transform: translateX(-50%);
  }
  #v2-screen-player .screen-header .progress-pill {
    padding: 4px 11px;
    font-size: 11px;
    background: color-mix(in srgb, var(--v2-primary) 12%, var(--v2-surface));
    color: var(--v2-primary);
    border: 1.5px solid color-mix(in srgb, var(--v2-primary) 45%, transparent);
    box-shadow: none;
  }
  #v2-screen-player .screen-header .progress-pill > [data-i18n="pill_q"] {
    display: none;
  }
  #v2-screen-player .screen-header .v2-progress-bar-wrap {
    display: none;
  }
  #v2-screen-player .screen-header button.back-btn {
    width: 42px !important;
    height: 42px !important;
    border-radius: 13px !important;
    font-size: 16px !important;
  }
  #v2-screen-player .screen-header .v2-header-controls {
    display: none;
  }
  #v2-screen-player .v2-player-stage {
    flex: 1 1 100%;
    height: 100%;
  }

  /* 笔算在手机横屏时必须改为左右分栏；继续上下排列会让键盘把题目区压成 0。 */
  .v2-written-wrap {
    flex-direction: row;
    align-items: stretch;
    justify-content: center;
    gap: clamp(12px, 2.5vw, 28px);
    padding: 6px clamp(10px, 2vw, 24px);
    box-sizing: border-box;
  }
  .v2-written-wrap .v2-written-question {
    flex: 1 1 42%;
    width: auto;
    min-width: 0;
    align-self: stretch;
    padding-top: 0;
    box-sizing: border-box;
  }
  .v2-written-wrap .v2-input-area {
    flex: 0 1 55%;
    align-self: stretch;
  }
  .v2-written-wrap .v2-look-item {
    font-size: clamp(44px, 12vh, 72px);
  }
  .v2-written-wrap .v2-num-multi {
    font-size: clamp(42px, 11vh, 68px);
  }
  .v2-written-wrap .v2-input-area .v2-neu-input-box {
    grid-row: 1 / 3;
    align-self: center;
  }

  /* ── 1) 做题答题区：竖排 → 「标签+答案框」与「键盘」两组水平居中 ──
     DOM 里 label/input-box/numpad 是三个平级 flex 兄弟。用一个 CSS Grid
     两列布局代替 flex row：左列(label 竖直堆叠在答案框上方)、右列(键盘)，
     两列各自 justify-self:center，整体 grid 再居中，视觉上就是清晰的
     两组，而不会被三个 flex item 拆散成三等分。 */
  .v2-written-wrap .v2-input-area {
    width: min(600px, calc(100% - 24px));
    max-width: 600px;
  }
  .v2-input-area {
    display: grid;
    grid-template-columns: auto auto;
    grid-template-rows: auto auto;
    justify-content: center;
    align-items: center;
    align-content: center;
    column-gap: clamp(28px, 5vw, 48px);
    row-gap: 8px;
    padding: 8px 24px;
    height: 100%;
    box-sizing: border-box;
  }
  /* label 在左列第 1 行，靠底对齐紧贴答案框 */
  .v2-input-area .v2-input-label {
    grid-column: 1;
    grid-row: 1;
    align-self: end;
    justify-self: center;
    font-size: 13px;
    font-weight: 800;
    margin: 0;
    opacity: 0.65;
    white-space: nowrap;
  }
  /* 答案框在左列第 2 行 */
  .v2-input-area .v2-neu-input-box {
    grid-column: 1;
    grid-row: 2;
    width: 30vw;
    min-width: 130px;
    max-width: 220px;
    height: 60px;
    font-size: 34px;
    border-radius: 16px;
    /* 矮屏尺寸缩小后内凹阴影不够醒目，加一圈边框补足视觉重量，
       与右侧 12 颗键盘按钮的视觉密度更平衡，避免"数学居中但视觉偏右" */
    border: 2px solid rgba(0, 0, 0, 0.08);
  }
  /* 键盘占右列，纵跨两行，与左组垂直居中对齐 */
  .v2-input-area .v2-neu-numpad {
    grid-column: 2;
    grid-row: 1 / 3;
  }

  /* 右组：键盘，尺寸按可用高度精确算，保证 4 行 + 间距不溢出也不过紧 */
  .v2-input-area .v2-neu-numpad {
    width: auto;
    max-width: none;
    gap: 7px;
    margin: 0;
  }
  .v2-input-area .v2-neu-key {
    min-height: 0;
    /* (可用高度 - 顶部工具条90px - 3道间隙 - 上下呼吸边距) / 4 行 */
    --abv2-keyh: calc((100vh - 90px - 21px - 16px) / 4);
    width: var(--abv2-keyh);
    height: var(--abv2-keyh);
    max-width: 62px;
    max-height: 62px;
    min-width: 44px;   /* 触控最小尺寸下限 (44pt) */
    min-height: 44px;
    font-size: 20px;
    border-radius: 14px;
    aspect-ratio: auto;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }

  /* 笔算横屏沿用标准竖向键盘卡片；完整高度由横屏 Header 让出。 */
  .v2-written-wrap .v2-input-area {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    align-self: center;
    /* ⚠️ 这条在上面 `flex:0 1 55%` 之后声明、特异性相同 —— width:fit-content
       会压过它，键盘被压成「内容宽」(实测 1021px 宽的横屏下只剩 230px，
       而题目区独占 698px)。改用下限保证卡片有合理宽度，仍不超过分栏份额。 */
    width: clamp(240px, 34vw, 360px);
    max-width: calc(100% - 12px);
    height: auto;
    padding: 10px;
    gap: 8px;
    border: 2px solid var(--v2-border-main);
    border-radius: var(--v2-radius-card);
    background: color-mix(in srgb, var(--v2-primary) 5%, var(--v2-surface));
    box-shadow: 0 5px 0 var(--v2-border-main);
  }
  .v2-written-wrap .v2-input-area .v2-neu-input-box {
    grid-column: auto;
    grid-row: auto;
    align-self: stretch;
    justify-self: stretch;
    width: auto;
    min-width: 0;
    max-width: none;
    height: 52px;
    background: var(--v2-surface);
    border: 2px solid var(--v2-border-main);
  }
  .v2-written-wrap .v2-input-area .v2-neu-numpad {
    grid-column: auto;
    grid-row: auto;
    align-self: stretch;   /* 撑满卡片宽度，否则按钮挤在中间留白 */
    width: 100%;
    max-width: none;       /* 解除基础样式的 300px 上限 */
  }
  .v2-written-wrap .v2-input-area .v2-neu-key {
    --abv2-keyh: clamp(44px, 15vh, 82px);
    /* 宽度交给网格(3 等分卡片)，只锁高度 —— 写死 width 会让按钮挤在
       卡片中间留白，与竖屏「撑满一行」的造型不一致 */
    width: 100%;
    height: var(--abv2-keyh);
    max-width: none;
    max-height: none;
  }

  /* ── 2) 通用顶栏：矮屏时压扁，把竖向空间还给内容 ──
     .v2-header 是所有屏共用的标题栏，首页/设置/个人中心等一并受益。
     字号/内边距按 4pt 节奏收紧，而不是随意砍数字。 */
  .v2-header {
    font-size: 18px;
    padding: 8px 60px;
    min-height: 40px;   /* 保留基本触控高度，不显得局促 */
  }
  .v2-header-gear {
    width: 36px;
    height: 36px;
    top: 50%;
    transform: translateY(-50%);
  }
  .v2-content {
    padding-top: 8px;
    padding-bottom: 12px;
    gap: 12px;
  }

  /* ── 3) 设置页：副标题隐藏省一行，参数卡更早露出 ── */
  #settings-screen-subtitle {
    display: none;
  }

  /* ── 4) 通用弹窗：矮屏缩小内边距，配合 90vh 滚动不溢出 ──
     内边距按比例收紧（而非砍成统一数字），标题/正文的层级间距保留出来，
     视觉重心仍然稳定，不会显得所有文字挤在一起。 */
  #v2-custom-modal .v2-neu-card {
    padding: 20px 24px !important;
    max-width: min(420px, 88vw) !important;
  }
  #v2-custom-modal .v2-neu-card > div:first-child {
    font-size: 19px !important;
    margin-bottom: 10px !important;
  }
  #v2-custom-modal .v2-neu-card > div:nth-child(2) {
    font-size: 14px !important;
    line-height: 1.5 !important;
    margin-bottom: 18px !important;
  }

}

/* ══════════════════════════════════════════════════════════════════
   指法示范 · 横屏分栏修正
   ⚠️ 必须排在「横屏矮屏」区块之后 —— 那个区块把 header 绝对定位、
   把 1/5 进度胶囊钉在 bottom:10px 居中，正好压在本屏的按钮行上
   (普通作答只有两个按钮、位置更高才没暴露)。同选择器同特异性时后写的赢，
   所以这里靠顺序覆盖，不再堆 !important。

   两个坑一起修：
   1) 算盘被裁上下 —— 分栏那层(820/620)只分了宽度，没做高度预算，
      而 3 档珠高在 820~1400px 区间仍是 vw 基准(10vw 顶到 44px → 盘高约
      330px)，超出栏位后被题目区的 overflow:hidden 从上下切掉。
      改成按 vh 定珠高，并让盘成为唯一可压缩项(min-height:0)。
   2) 1/5 胶囊压住「示范一次」—— 本屏按钮行更靠下，把胶囊移到左上角
      返回键旁边，那里是空的。
   命中范围只限 .guided-abacus-wrap，普通算盘作答/笔算零改动。 */
@media (orientation: landscape) {
  /* 横屏是左右分栏：题目独占左栏，不占纵向预算，所以固定开销只有
     chip + 提示 + 反馈 + 按钮单行 + gap。与竖屏用同一套 --guided-b 公式，
     珠高从剩余空间反推 —— 不再用「视口 x 0.62」这种估值(那个估值没算到
     按钮换行，844x390 实测超支 18px、按钮被切)。 */
  .guided-abacus-wrap {
    /* 同竖屏：提示/反馈常态为空不计入；chip 37 + 按钮 36 + gap ≈ 30 */
    --guided-fixed: 103px;
    /* 横屏题目在左栏，不占纵向；基数扣掉顶栏/边距留 92vh */
    --guided-board: calc(92vh - var(--guided-fixed));
    --guided-b: calc((var(--guided-board) - 35px) / 7.3);
  }
  .guided-abacus-wrap .abv2-question {
    /* 分栏下题目自己就是一栏，不需要再裁切；裁切正是算盘被切头切尾的元凶 */
    overflow: visible;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .guided-abacus-wrap .abv2-answer-area {
    justify-content: center;
    min-height: 0;
    gap: 6px;
  }
  /* ⚠️ 盘高只能靠 --abv2-b 调，绝不可加 max-height ——
     盘的自然高度是死公式：上珠区(b + 1.1b) + 下珠区(4b + 1.2b) + 梁 11px
     + padding 24px ≈ 7.3b + 35px，不含任何可伸缩项，max-height 压矮
     只会让盘超出容器被外层切掉，珠子并不会跟着缩小。
     「算盘不完整」那张截图就是盘(350px)高过栏位、下半截被屏幕裁掉。
     珠高改由上面的 --guided-b 反推(可用高度 - 35px)/7.3，clamp 只兜底。 */
  .guided-abacus-wrap .abv2-frame,
  .guided-abacus-wrap .abv2-frame[data-rods],
  .guided-abacus-wrap .abv2-frame[data-abacus-skin][data-rods] {
    --abv2-b: max(14px, min(var(--guided-b), 44px)) !important;
  }
  /* 盘按自然高度占位，不参与 flex 纵向伸缩(它压根不可压缩，见上) */
  .guided-abacus-wrap .abv2-answer-board {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  /* ⚠️ 上面的 display:flex 让盘框变成 flex item，会按内容收缩，
     而档杆是 flex:1 1 0% + min-width:0 —— 没有内在宽度，于是三根一起
     塌成 2px，珠子肉眼消失(1180x820 实测 frameW=46px / rodW=2px)。
     必须显式把框撑满板宽，档杆才有东西可分。
     ⚠️ 也不要改成给盘写死宽度(如 min(100%,260px))：会和大屏区块的
     gap:clamp(18px,2vw,30px) + padding:24px 打架，同样把档杆吃光。
     横屏珠子长宽比实测 1.6~2.4 属正常，不需要额外限宽。 */
  .guided-abacus-wrap .abv2-answer-board .abv2-frame {
    width: 100%;
    box-sizing: border-box;
  }
  .guided-abacus-wrap .guided-step-chip,
  .guided-abacus-wrap .guided-fingering-hint,
  .guided-abacus-wrap .guided-step-feedback,
  .guided-abacus-wrap .abv2-answer-actions {
    flex: 0 0 auto;
  }
  /* 同竖屏：按钮单行是 --guided-fixed 成立的前提 */
  .guided-abacus-wrap .abv2-answer-actions {
    flex-wrap: nowrap;
    width: 100%;
    gap: 6px;
  }
  .guided-abacus-wrap .abv2-btn {
    padding: 7px 10px;
    font-size: 12px;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 0;
  }
}

/* 1/5 胶囊让位：本屏按钮行更靠下，胶囊钉在 bottom 会压住「示范一次」。
   挪到左上返回键右侧(那里是空的)。
   开关是 #v2-screen-player 上的 .guided-active，由 GuidedAbacusEngineV2
   渲染时加、退出时清(见该文件 renderQuestion / handleBack)。
   ⚠️ 不用 :has() 按内容判断，老 webview 会静默失效(见 css_has_webview_pitfall)。 */
@media (orientation: landscape) and (max-height: 619px) {
  #v2-screen-player.guided-active .screen-header .v2-global-progress {
    bottom: auto;
    top: 20px;
    left: 68px !important;
    transform: none;
  }
}

/* ── 虚拟算盘：横屏 100% 全屏（含平板高屏，不限矮屏）──
   横屏是老师上课的展示场，13 档大盘。数值卡去掉，只留顶栏数值 + 算盘 + 清盘。
   曾误放进 max-height:600 矮屏块，导致平板横屏(height>600)拿不到全屏、盘挤成窄条——已移出到这里。
   横屏支持拖拽拨珠(含双指上下珠同拨)——AbacusV2.js 靠「横向漂移超过半档宽即停止跟手」防跨档误触。
   转屏提示在横屏无意义，一并隐藏。 */
@media (orientation: landscape) {
  .abv2-rotate-hint { display: none; }

  #v2-screen-abacus .v2-content {
    overflow-y: hidden;
    height: 100%;
    padding-top: 4px;
    padding-bottom: 6px;
  }
  .abv2-screen {
    max-width: 100%;
    width: 100%;         /* 父级 .v2-content 有 align-items:center，不加宽度会按内容收缩成窄条 */
    align-self: stretch; /* 双保险：拉满交叉轴，13 档大盘才能真正铺开 */
    height: 100%;
    gap: 8px;
    padding: 0 12px;
    box-sizing: border-box;
  }
  .abv2-value-card {
    display: none;   /* 横屏空间优先给算盘，不显示数值卡 */
  }
  /* 数值改到顶栏跟标题同排显示，不占算盘的横屏空间 */
  .abv2-value-inline {
    display: inline-block;
    font-size: 18px;
    margin-left: 10px;
  }
  #v2-abacus-mount {
    flex: 1;
    display: flex;
    width: 100%;      /* mount 是 .v2-content(align-items:center) 的直接子，不给宽会收缩成窄条 */
    min-height: 0;    /* 允许 flex 子项收缩，触发内部 frame 的高度换算 */
  }
  #v2-screen-abacus .abv2-frame {
    flex: 1;
    /* 横屏按视口高度算珠子尺寸(不按宽度)；data-rods 尺寸只作用于竖屏，这里统一覆盖 */
    --abv2-b: clamp(12px, 7vh, 34px) !important;
  }
  #v2-screen-abacus .abv2-toolbar {
    flex-shrink: 0;
    margin: 0;
  }
  #v2-screen-abacus .abv2-btn {
    padding: 6px 22px;
    font-size: 13px;
  }
}

/* ══════════════════════════════════════════════
   功课批改卡片 (Grading Card)
   ⚠️ 用 class 不用内联 style：这张卡片按学生数量成百上千次渲染，
      内联样式会把每行 HTML 撑大好几倍，明显拖慢列表。
   ═══════════════════════════════════════════════ */

.tgc-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 18px;
    /* ⚠️ --v2-surface 在太空/星河/月光深色主题下已改深色，
       但 .tgc-hwtitle / .tgc-prog-head 文字是写死的深灰十六进制值，不跟主题走，
       深底配深字会看不清，这里固定白底保证对比度 */
    background: #fff;
    border: 2px solid var(--v2-border-main);
    border-radius: var(--v2-radius-card);
    box-shadow: var(--v2-shadow-soft);
    width: 100%;
    box-sizing: border-box;
}
.tgc-card.is-done    { border-color: var(--v2-secondary); }
.tgc-card.is-overdue { border-color: var(--v2-danger); }

/* ── 头部：头像 + 姓名 + 操作 ── */
.tgc-head { display: flex; align-items: flex-start; gap: 12px; width: 100%; }

.tgc-avatar {
    flex-shrink: 0;
    width: 46px; height: 46px;
    border-radius: 50%;
    background: linear-gradient(135deg, #EDE9FE, #F5F3FF);
    border: 1.5px solid rgba(255,255,255,0.9);
    box-shadow: 0 2px 6px rgba(109,90,205,0.14);
    display: flex; align-items: center; justify-content: center;
    font-size: 22px;
}

.tgc-headmain { flex: 1; min-width: 0; }

.tgc-name {
    display: flex; align-items: baseline; gap: 7px;
    font-size: 15px; font-weight: 900; color: var(--v2-primary);
    min-width: 0;
}
.tgc-name-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tgc-hwtitle {
    /* ⚠️ .tgc-card 底色固定 --v2-surface（白），字色不能用深色主题下
       会变浅的 --v2-muted，否则星河等主题下浅底浅字看不见 */
    color: #6B7280; font-size: 11px; font-weight: 700;
    flex-shrink: 0;
}

.tgc-tags {
    display: flex; align-items: center; gap: 8px;
    flex-wrap: wrap; margin-top: 7px;
}
.tgc-tag {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 9px; border-radius: 8px;
    font-size: 10px; font-weight: 900; white-space: nowrap;
}
.tgc-tag-class   { background: rgba(99,102,241,0.08); color: #4F46E5; }
.tgc-tag-acct    { color: #6B7280; font-weight: 800; font-size: 10px; }
.tgc-tag-done    { background: #D1FAE5; color: #065F46; border: 1.5px solid #A7F3D0; }
.tgc-tag-doing   { background: #FEF3C7; color: #92400E; border: 1.5px solid #FDE68A; }
.tgc-tag-notyet  { background: #F1F5F9; color: #64748B; border: 1.5px solid #E2E8F0; }

.tgc-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }

.tgc-btn {
    padding: 7px 14px; border-radius: 12px; border: none;
    font-size: 12px; font-weight: 900; white-space: nowrap;
    cursor: pointer; height: 34px;
    display: inline-flex; align-items: center; justify-content: center; gap: 3px;
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: transform 0.12s;
}
.tgc-btn:active { transform: scale(0.96); }
.tgc-btn-grade   { background: linear-gradient(135deg, #FF8A00, #FF5C00); color: #fff; box-shadow: 0 3px 8px rgba(255,92,0,0.28); }
.tgc-btn-overdue { background: linear-gradient(135deg, #EF4444, #B91C1C); color: #fff; box-shadow: 0 3px 8px rgba(185,28,28,0.28); }
.tgc-btn-viewed  { background: rgba(76,175,80,0.10); color: var(--v2-secondary); border: 1.5px solid var(--v2-secondary); }
.tgc-btn-wait    { background: #F1F5F9; color: #94A3B8; border: 1.5px solid #E2E8F0; cursor: default; }
.tgc-btn-wait:active { transform: none; }
.tgc-btn-remind  { background: rgba(59,130,246,0.10); color: #2563EB; border: 1.5px solid #93C5FD; }

.tgc-del {
    width: 34px; height: 34px; border-radius: 50%;
    background: rgba(239,68,68,0.08);
    border: 1.5px solid rgba(239,68,68,0.18);
    color: #ef4444; font-size: 13px; font-weight: 900;
    cursor: pointer; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.15s, transform 0.12s;
}
.tgc-del:hover  { background: rgba(239,68,68,0.16); }
.tgc-del:active { transform: scale(0.92); }

/* ── 信息条：配置 / 布置于 / 进度，竖线分隔 ── */
.tgc-info {
    display: flex; align-items: stretch;
    background: #F7F8FA;
    border-radius: 14px;
    padding: 11px 6px;
    gap: 0;
    flex-wrap: wrap;
}
.tgc-info-item {
    display: flex; align-items: center; gap: 7px;
    padding: 2px 14px;
    font-size: 12px; font-weight: 800;
    /* ⚠️ .tgc-info 底色固定浅灰 #F7F8FA，字色不能用深色主题下会变
       近白的 --v2-text-dark，否则星河等主题下浅底浅字看不见 */
    color: #374151;
    min-width: 0; flex: 1;
}
.tgc-info-item + .tgc-info-item { border-left: 1.5px solid #E6E9EF; }
.tgc-info-icon { font-size: 14px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
.tgc-info-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tgc-info-item.is-overdue .tgc-info-text { color: var(--v2-danger); font-weight: 900; }

/* 窄屏：竖线换成堆叠，避免三项挤成一坨 */
@media (max-width: 560px) {
    .tgc-info { flex-direction: column; gap: 8px; padding: 10px 12px; }
    .tgc-info-item { padding: 0; flex: none; }
    .tgc-info-item + .tgc-info-item { border-left: none; }
}

/* ── 进度条 ── */
.tgc-prog-head {
    display: flex; justify-content: space-between; align-items: baseline;
    font-size: 12px; font-weight: 900;
    /* ⚠️ .tgc-card 底色固定 --v2-surface（白），字色不能用深色主题下
       会变近白的 --v2-text-dark，否则星河等主题下浅底浅字看不见 */
    color: #1F2937;
    margin-bottom: 7px;
}
.tgc-prog-pct { font-size: 13px; color: var(--v2-primary); }
.tgc-prog-track {
    width: 100%; height: 10px;
    background: #E8EBF0; border-radius: 999px; overflow: hidden;
}
.tgc-prog-fill {
    height: 100%; border-radius: 999px;
    background: linear-gradient(90deg, #10B981, #34D399);
    transition: width 0.35s ease;
}
.tgc-card.is-overdue .tgc-prog-fill { background: linear-gradient(90deg, #F87171, #EF4444); }

/* ── 空状态 ── */
.tgc-empty {
    border: 1.5px dashed #C7D2E5;
    border-radius: 14px;
    padding: 18px;
    text-align: center;
    font-size: 12px; font-weight: 800; color: var(--v2-muted);
    background: #FBFCFE;
}

/* 窄屏：姓名优先占满整行，别被右侧按钮和标签挤成「NOT ST...」 */
@media (max-width: 560px) {
    .tgc-head { flex-wrap: wrap; }
    .tgc-avatar { width: 38px; height: 38px; font-size: 18px; }
    .tgc-headmain { flex: 1 1 100%; order: 3; }
    .tgc-name { flex-wrap: wrap; }
    .tgc-actions { margin-left: auto; }
}

/* ══════════════════════════════════════════════════════════════════
   认珠模式 (BEAD READ MODE)
   算盘摆好珠子当题目（只读），下方沿用标准数字键盘。
   布局借笔算那套 .v2-written-wrap：题目区可压缩、键盘区固定高度，
   所以盘面再高也不会把键盘顶出屏幕（见 AbacusV2.fitBoard 的注释）。
   ══════════════════════════════════════════════════════════════════ */
.bead-read-question {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    min-height: 0;
}
.bead-read-label {
    flex: 0 0 auto;
    font-size: 15px;
    font-weight: 900;
    color: var(--v2-muted);
    letter-spacing: 0.5px;
}
/* 盘面是这一屏唯一可压缩的东西。
   ⚠️ min-height:0 不能省：flex 子项默认 min-height:auto，会按珠子总高硬撑住不缩。

   ⚠️ 宽度必须封顶，不能让盘铺满整屏。档杆是 flex:1 平分盘宽，珠子宽度是档宽的
   88%（上限 2.3 倍珠高），所以盘一宽、档就宽、珠子跟着摊成薄饼：550px 屏上实测
   珠子 118x48（宽高比 2.45），而算盘作答那边是 81x52（1.56）—— 同一个算盘看起来
   却是两个东西，用户一眼就看出来了。
   算盘作答之所以好看，是因为它的盘长在 .v2-input-area 里，被那条 max-width:330px
   顺手卡住了（3 档 → 每档 110px）。这里按同一把尺子来：每档 110px，3 档时正好
   330px 与算盘作答完全一致，档多了按比例放宽，屏幕不够就以屏幕为准。 */
.bead-read-board {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    max-width: min(calc(100% - 24px), 330px);
    margin-inline: auto;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.bead-read-board[data-rods="4"] { max-width: min(calc(100% - 24px), 440px); }
.bead-read-board[data-rods="5"] { max-width: min(calc(100% - 24px), 550px); }
.bead-read-board[data-rods="6"] { max-width: min(calc(100% - 24px), 660px); }
/* ⚠️ 位数上限从 5 提到 9 后（档数最高到 10 = 9 位 + 1 空档）必须补齐这几档，
   否则 7~10 档会全部退回默认的 330px(3 档宽度)，珠子按固定公式画却挤在
   窄框里，横向严重重叠溢出（9 位数认珠实测过的坑）。 */
.bead-read-board[data-rods="7"]  { max-width: min(calc(100% - 24px), 770px); }
.bead-read-board[data-rods="8"]  { max-width: min(calc(100% - 24px), 880px); }
.bead-read-board[data-rods="9"]  { max-width: min(calc(100% - 24px), 990px); }
.bead-read-board[data-rods="10"] { max-width: min(calc(100% - 24px), 1100px); }
/* ⚠️ 必须写 width：board 是 flex 容器，frame 作为 flex 项默认按内容收缩，
   档位只是几根细杆 → 整盘会塌成一条竖条（算盘作答竖屏踩过同一个坑）。
   ⚠️ 千万别给 frame 加 max-height:100%：AbacusV2.fitBoard() 靠「盘面自然高度 ÷ 珠高」
   反推比例，max-height 会先把量到的高度截成容器高度 → 比例被低估 → 算出的珠高偏大，
   而收尾那个 while 又因为「量到的高度 == 可用高度」以为已经塞下了，一轮都不缩。
   360x640 实测：珠子撑爆盘框、最后一排被裁掉。让它报真实高度，溢出交给 board 的
   overflow:hidden 挡一帧，fitBoard 收完就正好。 */
.bead-read-board .abv2-frame {
    width: 100%;
    box-sizing: border-box;
}
/* 珠高的「起点」，同时受宽高约束。
   ⚠️ 不能加 !important —— AbacusV2.fitBoard() 会按盘面实际分到的高度写行内
   --abv2-b 收尾，加了就被这条压过，珠子永远不缩，等于没修。 */
.bead-read-board .abv2-frame,
.bead-read-board .abv2-frame[data-rods] {
    --abv2-b: min(clamp(20px, 10vw, 48px), 7vh);
}
/* 只读盘面：明确告诉学生这是题目、不是拨给你玩的（事件本来就没绑，见 AbacusV2.create）。 */
.abv2-frame.abv2-readonly {
    cursor: default;
}
.abv2-frame.abv2-readonly .abv2-bead {
    cursor: default;
}

/* ===========================================================
   学生详情页 — 分段页签 (档案 / 功课 / 摸底与算力)
   复用 v2-level-chip 的选中语汇：白底 + 主题色描边 + 同色投影 + 上浮，
   而不是整块填色 —— 全 App 的「选中」都是这个手势，页签不该自成一派。
   宽屏封顶居中：三个页签摊到 2000px 会变成三条横幅，不像页签。
   =========================================================== */
/* 页签 + 动作（登入码）同一条；动作靠竖分隔线跟页签划清界限 */
.v2-detail-tabbar {
    display: flex;
    align-items: stretch;
    gap: 10px;
    margin: 0 auto 16px;
    max-width: 720px;
    width: 100%;
    box-sizing: border-box;
}

.v2-detail-tabbar > .v2-detail-action {
    padding-left: 12px;
    border-left: 2px dashed var(--v2-border-main);
    margin-left: 2px;
}

.v2-detail-tabs {
    display: flex;
    gap: 10px;
    flex: 1;
    min-width: 0;
    box-sizing: border-box;
}

.v2-detail-tab,
.v2-detail-action {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 11px 10px;
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-chip);
    background: #FAFAFA;
    color: var(--v2-muted);
    box-shadow: var(--v2-shadow-soft);
    font: 900 12.5px var(--v2-font-main);
    line-height: 1.2;
    cursor: pointer;
    transition: var(--v2-transition);
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.v2-detail-tab .vdt-icon,
.v2-detail-action .vdt-icon {
    font-size: 15px;
    flex-shrink: 0;
    transition: transform 0.2s;
}

.v2-detail-tab .vdt-label,
.v2-detail-action .vdt-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 动作按钮：靛蓝身份，跟登入码弹窗同色系；它永远不进「选中」态，
   所以用实心描边 + 常驻主色，一眼跟旁边的页签区分开。 */
.v2-detail-action {
    flex: 0 1 auto;
    background: #EEF2FF;
    border-color: #C7D2FE;
    color: #4338CA;
    box-shadow: 0 var(--v2-shadow-depth) 0 #C7D2FE;
}

.v2-detail-action:hover {
    background: #E0E7FF;
    transform: translateY(-2px);
}

.v2-detail-tab[aria-selected="true"] {
    background: var(--v2-surface);
    border-color: var(--v2-primary);
    color: var(--v2-primary);
    box-shadow: 0 var(--v2-shadow-depth) 0 var(--v2-primary);
    transform: translateY(-2px);
}

.v2-detail-tab[aria-selected="true"] .vdt-icon {
    transform: scale(1.18);
}

.v2-detail-tab:active,
.v2-detail-action:active {
    transform: scale(0.96);
    box-shadow: var(--v2-shadow-inner);
}

/* 窄屏：图标叠在文字上方，避免「摸底与算力」被挤成省略号 */
@media (max-width: 480px) {
    .v2-detail-tabbar { gap: 7px; }
    .v2-detail-tabs { gap: 7px; }
    .v2-detail-tab,
    .v2-detail-action {
        flex-direction: column;
        gap: 3px;
        padding: 9px 4px;
        font-size: 11px;
    }
    .v2-detail-tab .vdt-icon,
    .v2-detail-action .vdt-icon { font-size: 16px; }
    /* 窄屏收起分隔线，四个格子等宽排满，省下的横向空间给文字 */
    .v2-detail-tabbar > .v2-detail-action {
        padding-left: 4px;
        border-left: none;
        margin-left: 0;
    }
}

/* ===========================================================
   学员诊断面板 (摸底与算力) — tdx-*
   ⚠️ 每个 button 都必须带 .tdx-btn，否则会被 line 1144 那条
   「.v2-content button」通吃规则撑成 95% 宽的橙色大按钮
   （标题被压住、按钮宽窄不一就是这么来的）。
   =========================================================== */

/* 卡片：统一用 App 既有的卡片语汇，不再每张卡各写各的行内样式 */
.tdx-card {
    padding: 18px 20px;
    margin-bottom: 14px;
    border: var(--v2-card-border);
    border-radius: var(--v2-radius-card);
    /* ⚠️ --v2-surface 在太空/星河/月光深色主题下已改深色，
       但 .tdx-title / .tdx-sub 文字是写死的深灰十六进制值，不跟主题走，
       深底配深字会看不清，这里固定白底保证对比度 */
    background: #fff;
    box-shadow: var(--v2-shadow-soft);
    box-sizing: border-box;
}
.tdx-card:last-child { margin-bottom: 0; }

/* 卡头：标题在左、动作钮在右，中间用 gap 隔开。
   ⚠️ 标题必须 min-width:0 才能在窄屏收缩，否则会把按钮挤出去/压住。 */
.tdx-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}
.tdx-head-text { min-width: 0; flex: 1; }

.tdx-title {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 15px;
    font-weight: 900;
    /* ⚠️ .tdx-card 底色固定 --v2-surface（各主题都是白），字色不能用
       深色主题下会变近白的 --v2-text-dark，否则星河等主题下浅底浅字看不见 */
    color: #1F2937;
    line-height: 1.3;
}
.tdx-sub {
    margin-top: 3px;
    font-size: 11px;
    font-weight: 800;
    color: #6B7280;
    line-height: 1.4;
}

/* 所有诊断面板里的按钮共用的基线（同时是脱离通吃规则的钩子） */
.tdx-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: auto;
    min-height: 36px;
    margin: 0;
    padding: 8px 14px;
    border: 2px solid transparent;
    border-radius: var(--v2-radius-chip);
    font: 900 11.5px var(--v2-font-main);
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition: var(--v2-transition);
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.tdx-btn:active { transform: scale(0.96); box-shadow: var(--v2-shadow-inner); }

/* 卡头上的动作钮：不换行、不被标题挤扁 */
.tdx-head .tdx-btn { flex: 0 0 auto; }

.tdx-btn-primary {
    background: var(--v2-primary);
    border-color: var(--v2-primary-dark);
    color: #FFFFFF;
    box-shadow: 0 3px 0 var(--v2-primary-dark);
}
.tdx-btn-dark {
    background: #0F172A;
    border-color: #0F172A;
    color: #FFFFFF;
    box-shadow: 0 3px 0 #000000;
}
.tdx-btn-danger {
    background: var(--v2-danger);
    border-color: var(--v2-danger-dark);
    color: #FFFFFF;
    box-shadow: 0 3px 0 var(--v2-danger-dark);
}

/* 三维指标 */
.tdx-metrics {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-bottom: 12px;
}
.tdx-metric {
    padding: 10px 8px;
    border: 1.5px solid var(--v2-border-main);
    border-radius: var(--v2-radius-chip);
    background: #F8FAFC;
    text-align: center;
}
/* ⚠️ .tdx-metric 底色固定 #F8FAFC，字色不能用深色主题下会变浅/近白的
   --v2-muted / --v2-text-dark，否则星河等主题下浅底浅字看不见 */
.tdx-metric-k { font-size: 10.5px; font-weight: 800; color: #6B7280; }
.tdx-metric-v {
    margin-top: 2px;
    font-size: 19px;
    font-weight: 900;
    color: #1F2937;
    font-variant-numeric: tabular-nums;   /* 数字等宽，换值时不抖 */
}

/* 结论条 */
.tdx-verdict {
    padding: 10px 12px;
    border: 1.5px solid;
    border-radius: var(--v2-radius-chip);
    font-size: 11.5px;
    font-weight: 800;
    line-height: 1.45;
}
.tdx-verdict-tip { margin-top: 3px; font-size: 10.5px; font-weight: 600; opacity: 0.85; }

/* 摸底测评：四个等宽等高的选项钮 */
.tdx-bench-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 8px;
}
.tdx-bench {
    min-height: 44px;          /* 触控目标下限 */
    padding: 10px 12px;
    border-width: 1.5px;
    border-style: solid;
    font-size: 11.5px;
    text-align: center;
    white-space: normal;       /* 长标签换行，不撑破格子 */
    box-shadow: none;
}
.tdx-bench:active { transform: scale(0.97); box-shadow: var(--v2-shadow-inner); }

/* 弱项列表 */
.tdx-weak-list { display: flex; flex-direction: column; gap: 8px; }
.tdx-weak {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 14px;
    border: 1.5px solid #FECACA;
    border-radius: var(--v2-radius-chip);
    background: #FEF2F2;
}
.tdx-weak-text { min-width: 0; }
.tdx-weak-name { font-size: 13px; font-weight: 900; color: #991B1B; }
.tdx-weak-why { margin-top: 2px; font-size: 10.5px; font-weight: 700; color: #B91C1C; line-height: 1.4; }

/* 空态 */
.tdx-empty {
    padding: 18px 0;
    text-align: center;
    font-size: 12px;
    font-weight: 800;
    color: #16A34A;
}

/* 窄屏：卡头改上下堆叠，按钮撑满——避免标题和按钮互相挤压 */
@media (max-width: 560px) {
    .tdx-card { padding: 16px 14px; }
    .tdx-head { flex-direction: column; align-items: stretch; gap: 10px; }
    .tdx-head .tdx-btn { width: 100%; }
    .tdx-metrics { gap: 6px; }
    .tdx-metric-v { font-size: 17px; }
}

/* 乘除题面的文字。_fitMultiDiv() 量的就是这个 span 的实际宽度，
   据此决定要不要缩字号（横屏两栏时题目栏只有 42% 宽，长题目会溢出）。
   ⚠️ 别给它加 overflow/width 限制 —— getBoundingClientRect 会量到截断后的
   宽度，缩放判断就永远认为「没溢出」，等于把自动缩放废掉。 */
.v2-md-text {
    white-space: nowrap;
    display: inline-block;
}

/* 低配 Android：榜单屏外的行不排版不绘制（旧 WebView 不认就忽略） */
.hof-row {
    content-visibility: auto;
    contain-intrinsic-size: auto 58px;
}
