:root{
  --bg:#eef1f9;--bg2:#e6eaf6;--card:#fff;--ink:#1b2140;--muted:#6d7595;--line:#e4e8f4;
  --brand:#5b5bf0;--brand-d:#3f3fcf;--mint:#00c2b8;--good:#22c55e;--bad:#ef4444;--warn:#f59e0b;--gold:#fbbf24;
  --radius:18px;--shadow:0 12px 34px -14px rgba(45,55,120,.28);
  --pinkyL:#f87171;--ringL:#fbbf24;--midL:#34d399;--indexL:#60a5fa;
  --indexR:#818cf8;--midR:#22d3ee;--ringR:#f472b6;--pinkyR:#fb923c;--thumb:#cbd5e1;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:-apple-system,"PingFang SC","Microsoft YaHei","Segoe UI",system-ui,sans-serif;
  background:radial-gradient(1200px 600px at 50% -10%,#f4f0ff,transparent),var(--bg);color:var(--ink);line-height:1.6;-webkit-font-smoothing:antialiased;min-height:100vh}
button{font-family:inherit;cursor:pointer;border:0;background:none}
a{color:inherit;text-decoration:none}
.wrap{max-width:940px;margin:0 auto;padding:0 20px}
.btn{display:inline-flex;align-items:center;gap:8px;font-weight:700;font-size:15px;padding:11px 22px;border-radius:13px;transition:.16s}
.btn-fill{background:var(--brand);color:#fff;box-shadow:0 10px 22px -10px var(--brand)}
.btn-fill:hover{transform:translateY(-2px);box-shadow:0 14px 26px -10px var(--brand)}
.btn-ghost{background:#fff;color:var(--ink);border:1px solid var(--line)}
.btn-ghost:hover{border-color:var(--brand);color:var(--brand)}

/* ── header ── */
header{position:sticky;top:0;z-index:30;background:rgba(238,241,249,.82);backdrop-filter:blur(12px);border-bottom:1px solid var(--line)}
nav{display:flex;align-items:center;height:64px;gap:14px}
.logo{font-weight:800;font-size:20px;display:flex;align-items:center;gap:10px}
.logo .m{width:32px;height:32px;border-radius:10px;background:linear-gradient(135deg,var(--brand),var(--mint));display:grid;place-items:center;color:#fff;font-size:18px;box-shadow:0 6px 14px -6px var(--brand)}
.logo span{color:var(--brand)}
nav .spacer{flex:1}
.oprog{display:flex;align-items:center;gap:9px;font-size:13px;color:var(--muted)}
.oprog .track{width:120px;height:8px;border-radius:99px;background:var(--line);overflow:hidden}
.oprog .fill{height:100%;background:linear-gradient(90deg,var(--brand),var(--mint));width:0;transition:width .5s}
.guest{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--muted);background:#fff;border:1px solid var(--line);padding:6px 12px;border-radius:99px}

/* ── views ── */
.view{display:none;padding:26px 0 80px}
.view.on{display:block;animation:fade .3s}
@keyframes fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ── path hero ── */
.phero{text-align:center;padding:8px 0 4px}
.phero h1{font-size:clamp(24px,4vw,34px);font-weight:800;letter-spacing:-.01em}
.phero h1 span{background:linear-gradient(120deg,var(--brand),var(--mint));-webkit-background-clip:text;background-clip:text;color:transparent}
.phero p{color:var(--muted);margin-top:6px;font-size:14.5px}
.review-banner{max-width:600px;margin:16px auto 0;background:#fff7ea;border:1px solid #ffe4b3;color:#a86e12;border-radius:14px;padding:11px 16px;font-size:14px;display:flex;align-items:center;gap:10px;justify-content:center;flex-wrap:wrap}
.review-banner b{color:var(--warn)}
.review-banner button{color:var(--warn);font-weight:700;border-bottom:2px solid var(--warn)}

/* ── units as grid ── */
.unit{margin-top:22px}
.unit-head{display:flex;align-items:center;gap:14px;background:var(--uc);color:#fff;border-radius:16px;padding:14px 18px;box-shadow:var(--shadow);position:relative;overflow:hidden}
.unit-head::after{content:"";position:absolute;right:-30px;top:-40px;width:150px;height:150px;background:rgba(255,255,255,.13);border-radius:50%}
.unit-head .num{font-size:30px;font-weight:800;opacity:.9;line-height:1;z-index:1}
.unit-head .t{z-index:1}
.unit-head .t small{opacity:.85;font-size:12px;letter-spacing:.1em;font-weight:700}
.unit-head .t h3{font-size:19px;font-weight:800;margin:1px 0}
.unit-head .t p{font-size:12.5px;opacity:.9}
.unit-head .u-stars{margin-left:auto;font-size:13px;white-space:nowrap;background:rgba(0,0,0,.16);padding:5px 12px;border-radius:99px;z-index:1}

.unit-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-top:12px;position:relative}
/* 连接箭头 */
.ncard{background:var(--card);border:1px solid var(--line);border-radius:15px;padding:16px 12px;box-shadow:var(--shadow);cursor:pointer;transition:.16s;text-align:center;min-height:132px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;position:relative}
.ncard:not(.locked):hover{transform:translateY(-4px);border-color:var(--brand)}
.ncard .ic{width:48px;height:48px;border-radius:13px;display:grid;place-items:center;font-size:22px;background:var(--bg2);transition:.16s}
.ncard .nt{font-size:14px;font-weight:800;line-height:1.25}
.ncard .ns{font-size:11px;color:var(--muted)}
.ncard .nstars{font-size:12px;letter-spacing:1px;color:#dbe0ee;height:15px}
.ncard .nstars b{color:var(--gold)}
.ncard .badge{position:absolute;top:8px;right:8px;font-size:10px;font-weight:800;padding:2px 8px;border-radius:99px}
.ncard .badge.review{background:#fff4e5;color:var(--warn);border:1px solid #ffe0b2}
/* 类型图标底色 */
.ncard.type-lesson .ic{color:var(--brand)}
.ncard.type-review .ic{color:var(--warn)}
.ncard.type-game .ic{color:var(--mint)}
.ncard.type-test  .ic{color:#e11d48}
.ncard.type-entest .ic{color:#2563eb}
.ncard.type-cntest .ic{color:#dc2626}
.ncard.type-arena .ic{color:#e0952a;background:#fff7e6}
.ncard.type-arena{border-color:#f4c04a}
.ncard.type-entest.done .ic{background:linear-gradient(135deg,#2563eb,#60a5fa);color:#fff}
.ncard.type-cntest.done .ic{background:linear-gradient(135deg,#dc2626,#f87171);color:#fff}
/* 状态 */
.ncard.done .ic{background:linear-gradient(135deg,var(--brand),var(--mint));color:#fff}
.ncard.type-review.done .ic{background:linear-gradient(135deg,var(--warn),#fbbf24)}
.ncard.type-game.done   .ic{background:linear-gradient(135deg,var(--mint),#5eead4)}
.ncard.type-test.done   .ic{background:linear-gradient(135deg,#e11d48,#fb7185)}
.ncard.cur{border-color:var(--brand);box-shadow:0 0 0 3px rgba(91,91,240,.16),var(--shadow)}
.ncard.cur .ic{animation:pulse 1.6s infinite}
.ncard.cur .go{position:absolute;top:-9px;background:var(--brand);color:#fff;font-size:11px;font-weight:800;padding:2px 11px;border-radius:99px;box-shadow:var(--shadow)}
.ncard.review-due{box-shadow:0 0 0 3px #ffe4b3,var(--shadow)}
.ncard.locked{opacity:.6;cursor:not-allowed;background:#f4f6fb}
.ncard.locked .ic{background:#e9edf7;color:#b6bdd4}
.ncard.locked .lk{position:absolute;bottom:10px;right:12px;font-size:13px}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(91,91,240,.5)}50%{box-shadow:0 0 0 10px rgba(91,91,240,0)}}

/* ── lesson player ── */
.topbar{display:flex;align-items:center;gap:12px;margin-bottom:16px}
.topbar h2{font-size:20px;font-weight:800}
.topbar .spacer{flex:1}
.pbar{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:16px}
.stat{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:11px 16px;min-width:90px;text-align:center;box-shadow:var(--shadow)}
.stat b{font-size:24px;font-weight:800;display:block;line-height:1.1}
.stat.wpm b{color:var(--brand)}.stat.acc b{color:var(--good)}.stat.err b{color:var(--bad)}
.stat small{font-size:11px;color:var(--muted)}
.textbox{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:28px 30px;box-shadow:var(--shadow);
  font-size:26px;line-height:1.9;letter-spacing:.5px;user-select:none;min-height:120px;
  font-family:"SF Mono",ui-monospace,Consolas,monospace;white-space:normal;overflow-wrap:break-word;word-break:break-word}
.textbox .word{display:inline-block;white-space:nowrap}
.textbox .ch{color:#bcc3d8;position:relative;border-radius:3px}
.textbox .ch.done{color:var(--ink)}
.textbox .ch.wrong{color:var(--bad);background:#fde8e8}
.textbox .ch.sp{display:inline}
.textbox .ch.sp.wrong{background:#fbb;border-radius:3px}
.textbox .ch.cur::after{content:"";position:absolute;left:-1px;right:-1px;bottom:-3px;height:3px;background:var(--brand);border-radius:2px;animation:blink 1s steps(1) infinite}
@keyframes blink{50%{opacity:.2}}
.hint{text-align:center;color:var(--muted);font-size:13px;margin:12px 0}

/* keyboard */
.kb{margin:12px auto 0;max-width:700px;display:flex;flex-direction:column;gap:7px;align-items:center}
.kb .row{display:flex;gap:7px;justify-content:center}
.key{width:46px;height:46px;border-radius:11px;background:#fff;border:1px solid var(--line);border-bottom:3px solid #d7ddec;display:grid;place-items:center;font-size:15px;font-weight:700;color:var(--muted);text-transform:uppercase;transition:.08s}
.key.wide{width:230px}
.key[data-f]{border-bottom-color:var(--kbf)}
.key.next{color:#fff;background:var(--brand);border-color:var(--brand);border-bottom-color:var(--brand-d);transform:translateY(1px);box-shadow:0 7px 16px -6px var(--brand)}
.key.hit{background:#e9fbef;border-color:var(--good)}
.key.miss{background:#fdecec;border-color:var(--bad);animation:shake .18s}
@keyframes shake{25%{transform:translateX(-3px)}75%{transform:translateX(3px)}}
.legend{display:flex;gap:13px;flex-wrap:wrap;justify-content:center;margin-top:13px;font-size:11.5px;color:var(--muted)}
.legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:5px;vertical-align:middle}

/* ── modal ── */
.overlay{position:fixed;inset:0;background:rgba(18,22,48,.55);display:none;align-items:center;justify-content:center;z-index:50;padding:20px}
.overlay.on{display:flex;animation:fade .2s}
.modal{background:#fff;border-radius:24px;padding:34px;max-width:430px;width:100%;text-align:center;box-shadow:0 40px 90px -30px rgba(0,0,0,.5);animation:pop .3s}
@keyframes pop{from{transform:scale(.9);opacity:0}to{transform:none;opacity:1}}
.modal .big{font-size:50px;letter-spacing:6px;margin-bottom:4px}
.modal h2{font-size:23px;font-weight:800}
.modal .sub{color:var(--muted);font-size:14px;margin-top:4px}
.modal .res{display:flex;gap:12px;justify-content:center;margin:22px 0}
.modal .res .s{flex:1;background:var(--bg);border-radius:14px;padding:12px 8px}
.modal .res b{font-size:26px;font-weight:800;display:block}
.modal .res small{color:var(--muted);font-size:12px}
.modal .save-tip{background:#f1f2ff;border:1px solid #e0e2ff;border-radius:12px;padding:11px;font-size:13px;color:var(--brand);margin-bottom:16px}
.modal .row{display:flex;gap:10px}
.modal .row .btn{flex:1;justify-content:center}

/* ── game ── */
.gamewrap{background:linear-gradient(180deg,#0e1330,#1c1250);border-radius:var(--radius);padding:20px;color:#fff;box-shadow:var(--shadow)}
.gtop{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.gtop .gs b{font-size:22px}.gtop .gs small{opacity:.7;font-size:12px;display:block}
.gcombo{font-weight:800;color:#fde047;font-size:16px;transition:transform .1s}
.gcombo.bump{transform:scale(1.3)}
.timebar{height:8px;border-radius:99px;background:rgba(255,255,255,.15);overflow:hidden;margin-bottom:8px}
.timebar .fill{height:100%;background:linear-gradient(90deg,#22d3ee,#5b5bf0);width:100%;transition:width 1s linear}
.lives{text-align:right;font-size:17px;letter-spacing:2px;margin-bottom:10px;height:22px}
.field{position:relative;height:340px;overflow:hidden;border-radius:14px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1)}
.word-drop{position:absolute;padding:5px 11px;border-radius:9px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.2);font-weight:700;font-size:17px;white-space:nowrap;font-family:"SF Mono",monospace;letter-spacing:1px}
.word-drop.target{border-color:#22d3ee;box-shadow:0 0 14px rgba(34,211,238,.6)}
.word-drop .wc{color:#e5e9f5}
.word-drop .wc.typed{color:#22d3ee;text-shadow:0 0 8px #22d3ee}
.ship{position:absolute;bottom:8px;left:50%;width:0;height:0;border-left:15px solid transparent;border-right:15px solid transparent;border-bottom:26px solid #22d3ee;transform:translateX(-50%);transform-origin:50% 72%;transition:transform .08s;filter:drop-shadow(0 0 8px rgba(34,211,238,.8));z-index:5}
.bullet{position:absolute;width:4px;height:14px;margin:-7px 0 0 -2px;background:#a7f3ff;border-radius:2px;box-shadow:0 0 8px #22d3ee;z-index:4}
.boom{position:absolute;font-size:24px;pointer-events:none;animation:boom .4s forwards;z-index:6}
@keyframes boom{from{transform:scale(.6);opacity:1}to{transform:scale(2.2);opacity:0}}
.bubble{position:absolute;width:56px;height:56px;border-radius:50%;display:grid;place-items:center;font-size:24px;font-weight:800;text-transform:uppercase;background:radial-gradient(circle at 35% 30%,#fff,#c7d2fe);color:var(--brand-d);border:2px solid #a5b4fc;box-shadow:0 8px 18px -6px rgba(0,0,0,.5)}
.bubble.pop{animation:bpop .2s forwards}
@keyframes bpop{to{transform:scale(1.6);opacity:0}}
.ginput{margin-top:12px;display:flex;gap:10px}
.ginput input{flex:1;padding:13px 16px;border-radius:12px;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.06);color:#fff;font-size:16px;outline:none;font-family:"SF Mono",monospace}
.ginput input::placeholder{color:rgba(255,255,255,.5)}
.gtip{opacity:.7;font-size:12.5px;margin-top:8px;text-align:center}
.gover{position:absolute;inset:0;display:grid;place-content:center;text-align:center;padding:30px;background:rgba(10,13,35,.72)}
.gover h2{font-size:26px;font-weight:800;margin-bottom:8px}
.gover p{opacity:.9;margin-bottom:16px}
.gover p b{color:#22d3ee}
.gover .grow{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}

/* ── 中文测速 ── */
.cn-target{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:24px 28px;box-shadow:var(--shadow);font-size:23px;line-height:2;letter-spacing:1px;margin-bottom:14px}
.cn-target .cch{color:#aab1c8;border-radius:3px;padding:0 1px}
.cn-target .cch.ok{color:var(--good)}
.cn-target .cch.bad{color:#fff;background:var(--bad);border-radius:4px}
.cn-target .cch.cur{box-shadow:inset 0 -3px 0 var(--brand)}
.cn-input{width:100%;min-height:110px;resize:vertical;border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;font-size:20px;line-height:1.9;font-family:inherit;outline:none;box-shadow:var(--shadow);color:var(--ink)}
.cn-input:focus{border-color:var(--brand)}

/* ── 竞技场 ── */
.arena-hero{text-align:center;background:linear-gradient(135deg,#e11d48,#7c3aed);color:#fff;border-radius:var(--radius);padding:34px 20px;box-shadow:var(--shadow);position:relative;overflow:hidden}
.arena-hero::after{content:"";position:absolute;right:-40px;top:-50px;width:180px;height:180px;background:rgba(255,255,255,.13);border-radius:50%}
.arena-hero .ah-badge{font-size:44px}
.arena-hero h2{font-size:26px;font-weight:800;margin-top:6px}
.arena-hero p{opacity:.9;margin-top:6px;font-size:14px}
.login-gate{text-align:center;background:var(--card);border:1px dashed var(--brand);border-radius:var(--radius);padding:30px 24px;margin-top:16px;box-shadow:var(--shadow)}
.login-gate .lg-icon{font-size:38px}
.login-gate h3{font-size:20px;font-weight:800;margin:8px 0 6px}
.login-gate p{color:var(--muted);font-size:14.5px;max-width:460px;margin:0 auto 18px}
.login-gate p b{color:var(--brand)}
.login-gate .btn[disabled]{opacity:.55;cursor:not-allowed}
.lb-preview{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;margin-top:16px;box-shadow:var(--shadow)}
.lb-head{display:flex;justify-content:space-between;align-items:center;font-weight:800;font-size:16px;margin-bottom:8px}
.lb-head span{font-size:12px;color:var(--muted);font-weight:600}
.lb-row{display:grid;grid-template-columns:44px 1fr auto;align-items:center;padding:9px 6px;border-top:1px solid var(--line)}
.lb-row.me{background:#fff7ed;border-radius:8px;box-shadow:inset 0 0 0 1px #ffd7a8}
.lb-row.me .nm{color:#d4622a}
.lb-row .rk{font-weight:800;color:var(--muted);text-align:center}
.lb-row .rk.top{color:#fff;background:var(--gold);width:26px;height:26px;line-height:26px;border-radius:50%;margin:0 auto}
.lb-row:nth-child(2) .rk.top{background:#c0c0c0}
.lb-row:nth-child(3) .rk.top{background:#cd7f32}
.lb-row .nm{font-weight:600}
.lb-row .sc{font-weight:800;color:var(--brand)}
.lb-note{text-align:center;color:var(--muted);font-size:12.5px;margin-top:10px}

@media(max-width:640px){
  .unit-grid{grid-template-columns:repeat(auto-fill,minmax(120px,1fr))}
}
@media(max-width:560px){
  .key{width:30px;height:40px;font-size:12px;border-radius:8px}.key.wide{width:150px}
  .textbox{font-size:21px;padding:20px}
  .oprog .track{width:80px}
}
