/* ============================================================================
   工作台外壳 + 通用组件
   ----------------------------------------------------------------------------
   ★ 这个文件里**不写死任何颜色/圆角**，全部走 tokens.css 的变量。
     想换外观请改 tokens.css，不要改这里。
   ============================================================================ */

/* ---------------------------------------------------------------- 基础 */
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden}
body{
  font-family:var(--font); font-size:var(--fs-md); line-height:1.6;
  color:var(--tx); background:var(--bg);
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
}
button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
button{cursor:pointer;border:none;background:none}
a{color:var(--ac);text-decoration:none}
[hidden]{display:none !important}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:var(--r-full);
  border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-track{background:transparent}

/* ---------------------------------------------------------------- 外壳 */
.ws{display:flex;height:100%;overflow:hidden}

/* ---- 侧栏 ---- */
.ws-side{
  width:var(--side-w); flex:none; display:flex; flex-direction:column;
  background:var(--panel); border-right:1px solid var(--line);
  transition:width var(--t-mid) var(--ease); overflow:hidden;
}
.ws.mini .ws-side{width:var(--side-w-mini)}
.ws-side__brand{
  height:var(--top-h); flex:none; display:flex; align-items:center; gap:9px;
  padding:0 16px; border-bottom:1px solid var(--line);
}
.ws-side__logo{
  width:28px;height:28px;flex:none;border-radius:8px;display:grid;place-items:center;
  background:var(--ac);color:#fff;font-size:14px;font-weight:700;
}
.ws-side__name{font-weight:700;font-size:var(--fs-lg);letter-spacing:-.3px;white-space:nowrap}
.ws.mini .ws-side__name{display:none}
/* ★ 「（旧版）」过渡入口（用户 2026-10）：用户要的是**小、低调、不抢眼** ——
   它是过渡用的，不是主功能，所以只是次要文字色的一行小字，没有底色、没有边框。
   ★★ 开关在 core/config.js 的 SHOW_LEGACY_LINK（一处就能整个关掉，
      关掉时这个 <a> 连生成都不会生成）。只在家长端显示（见 shell.js renderLegacy）。
   ★ 窄屏（≤900px）/ 折叠侧栏（.mini）一律藏起来：侧栏那时候只有 64px，
     放不下，硬放会撑破（下面媒体查询里也列了它一次）。 */
.ws-legacy{
  flex:none; margin-left:2px; font-size:var(--fs-xs); line-height:1;
  color:var(--tx-3); text-decoration:none; white-space:nowrap;
  border-radius:var(--r-sm); padding:2px 3px;
}
.ws-legacy:hover{color:var(--tx-2);background:var(--panel-2)}
/* ★ 必须显式写：作者样式表里的其它规则可能盖掉 UA 的 [hidden]{display:none} */
.ws-legacy[hidden]{display:none!important}
.ws.mini .ws-legacy{display:none}

.ws-side__scroll{flex:1;overflow-y:auto;padding:10px 9px 16px}
.ws-grp{
  font-size:10.5px;font-weight:700;color:var(--tx-3);letter-spacing:.8px;
  padding:13px 11px 6px;white-space:nowrap;
}
.ws.mini .ws-grp{opacity:0;height:10px;padding:0}
.ws-nav{
  width:100%;display:flex;align-items:center;gap:10px;padding:8px 11px;
  border-radius:var(--r-sm);font-size:var(--fs-md);color:var(--tx-2);
  font-weight:500;margin-bottom:1px;text-align:left;white-space:nowrap;
  transition:background var(--t-fast) var(--ease),color var(--t-fast) var(--ease);
}
.ws-nav:hover{background:var(--panel-2);color:var(--tx)}
.ws-nav.on{background:var(--ac-soft);color:var(--ac-ink);font-weight:600;
  box-shadow:inset 0 0 0 1px var(--ac-line)}
.ws-nav__ic{width:17px;flex:none;text-align:center;font-size:14px;opacity:.9;
  display:inline-flex;align-items:center;justify-content:center}
/* ★ 2026-10 侧栏图标 = 内联 SVG（core/registry.js 的 ICONS）：
   统一 17px、线宽 1.8；`stroke="currentColor"` 所以选中态跟着 .ws-nav.on 的
   color(var(--ac-ink)) 一起变色 —— 零硬编码色值。
   ★★ 2026-10 加固：尺寸**不只靠这条规则** —— 每个 <svg> 自己还带 width/height
   属性（见 registry.js）。万一这条规则没到浏览器（旧缓存 / WebView 丢规则），
   有属性的兜底：实测「没规则又没属性」时图标会变成**跟容器一样大**（200px 的
   容器里就是 200×200）。
   ★★ 另外把 fill / stroke / stroke-* **再用 CSS 说一遍**：presentation attribute
   （fill="none" stroke="currentColor"）和 CSS 属性在引擎里是两条不同的取值路径，
   都写上，老引擎只认其中一条时也不会变成「实心黑块」。
   fill/stroke 都是**继承属性**，写在 <svg> 上就够了（子节点自动继承）。 */
.ws-nav__ic svg{width:17px;height:17px;display:block;flex:none;
  fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
.ws-nav__tx{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.ws-nav__bdg{
  flex:none;font-size:10.5px;font-weight:700;padding:1px 7px;border-radius:var(--r-full);
  background:var(--bad-soft);color:var(--bad);
}
.ws.mini .ws-nav{justify-content:center;padding:9px 0}
.ws.mini .ws-nav__tx,.ws.mini .ws-nav__bdg{display:none}

.ws-side__foot{flex:none;padding:9px;border-top:1px solid var(--line)}
.ws-fold{
  width:100%;display:flex;align-items:center;gap:9px;padding:8px 11px;
  border-radius:var(--r-sm);color:var(--tx-3);font-size:var(--fs-sm);
}
.ws-fold:hover{background:var(--panel-2);color:var(--tx)}
.ws.mini .ws-fold{justify-content:center;padding:9px 0}
.ws.mini .ws-fold span{display:none}
.ws-fold svg{transition:transform var(--t-mid) var(--ease)}
.ws.mini .ws-fold svg{transform:rotate(180deg)}

/* ---- 主区 ---- */
.ws-main{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}
.ws-top{
  height:var(--top-h);flex:none;display:flex;align-items:center;gap:12px;
  padding:0 18px;border-bottom:1px solid var(--line);background:var(--panel);
}
.ws-crumb{font-size:var(--fs-md);color:var(--tx-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ws-crumb b{color:var(--tx);font-weight:600}
.ws-top__sp{flex:1}
.ws-view{flex:1;overflow-y:auto;overflow-x:hidden}
.ws-view__in{
  max-width:var(--content-max);margin:0 auto;
  padding:var(--sp-6) var(--sp-6) var(--sp-10);
}

/* ---- 顶栏小控件 ---- */
.ws-iconbtn{
  width:34px;height:34px;flex:none;border-radius:var(--r-sm);display:grid;place-items:center;
  color:var(--tx-2);transition:background var(--t-fast) var(--ease),color var(--t-fast) var(--ease);
}
.ws-iconbtn:hover{background:var(--panel-2);color:var(--tx)}
.ws-iconbtn.on{background:var(--ac-soft);color:var(--ac-ink)}

/* ---- 身份切换（免密） ---- */
.ws-me{
  display:flex;align-items:center;gap:7px;padding:4px 12px 4px 5px;
  border:1px solid var(--line);border-radius:var(--r-full);background:var(--panel);
  font-size:var(--fs-sm);font-weight:600;box-shadow:var(--sh-1);
  transition:border-color var(--t-fast) var(--ease);
}
.ws-me:hover{border-color:var(--ac-line)}
.ws-me__av{
  width:23px;height:23px;border-radius:50%;background:var(--ac-soft);
  display:grid;place-items:center;font-size:12px;
}
.ws-me__caret{color:var(--tx-3);font-size:10px}

.ws-menu{
  position:absolute;top:calc(var(--top-h) - 6px);right:18px;z-index:60;min-width:200px;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--sh-3);padding:6px;display:none;
}
.ws-menu.open{display:block}
.ws-menu__t{font-size:10.5px;font-weight:700;color:var(--tx-3);padding:8px 10px 5px;letter-spacing:.6px}
.ws-mi{
  width:100%;display:flex;align-items:center;gap:9px;padding:8px 10px;
  border-radius:var(--r-sm);font-size:var(--fs-md);color:var(--tx-2);text-align:left;
}
.ws-mi:hover{background:var(--panel-2);color:var(--tx)}
.ws-mi.on{background:var(--ac-soft);color:var(--ac-ink);font-weight:600}
.ws-mi__av{width:22px;height:22px;border-radius:50%;background:var(--panel-2);
  display:grid;place-items:center;font-size:12px}
.ws-mi__badge{margin-left:auto;font-size:10px;color:var(--tx-3);font-weight:600}

/* ---------------------------------------------------------------- 组件 */
/* 页面头 */
.pg-head{display:flex;align-items:flex-start;gap:14px;margin-bottom:var(--sp-5);flex-wrap:wrap}
.pg-head h1{font-size:var(--fs-3xl);font-weight:700;letter-spacing:-.6px;line-height:1.2}
.pg-head p{color:var(--tx-2);font-size:var(--fs-md);margin-top:3px}
.pg-head__r{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.pg-sub{font-size:var(--fs-xl);font-weight:650;letter-spacing:-.2px;margin:var(--sp-6) 0 var(--sp-3)}

/* 卡片 */
.card{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--sh-1);
}
.card--pad{padding:var(--sp-4)}
.card__hd{display:flex;align-items:center;gap:10px;margin-bottom:var(--sp-3)}
.card__hd h3{font-size:var(--fs-lg);font-weight:650;letter-spacing:-.2px}
.card__hd .hint{margin-left:auto;font-size:var(--fs-xs);color:var(--tx-3)}
.card__hover{transition:box-shadow var(--t-fast) var(--ease),transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.card__hover:hover{box-shadow:var(--sh-2);transform:translateY(-1px);border-color:var(--line-2)}

/* 指标 */
.grid{display:grid;gap:var(--sp-3)}
.grid--4{grid-template-columns:repeat(4,minmax(0,1fr))}
.grid--3{grid-template-columns:repeat(3,minmax(0,1fr))}
.grid--2{grid-template-columns:repeat(2,minmax(0,1fr))}
.grid--auto{grid-template-columns:repeat(auto-fill,minmax(230px,1fr))}
.metric{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  padding:15px 17px;box-shadow:var(--sh-1)}
.metric .v{font-family:var(--mono);font-size:var(--fs-3xl);font-weight:700;letter-spacing:-1px;line-height:1.1}
.metric .v small{font-size:var(--fs-lg);color:var(--tx-3);font-weight:600;letter-spacing:0}
.metric .k{font-size:var(--fs-xs);color:var(--tx-3);margin-top:4px;font-weight:500}
.metric.is-ac .v{color:var(--ac)} .metric.is-ok .v{color:var(--ok)}
.metric.is-warn .v{color:var(--warn)} .metric.is-bad .v{color:var(--bad)}

/* 按钮 */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  padding:8px 15px;border-radius:var(--r-sm);font-size:var(--fs-md);font-weight:600;
  border:1px solid var(--line);background:var(--panel);color:var(--tx-2);
  transition:all var(--t-fast) var(--ease);white-space:nowrap;
}
.btn:hover{border-color:var(--line-2);color:var(--tx);box-shadow:var(--sh-1)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn--pri{background:var(--ac);border-color:var(--ac);color:#fff;box-shadow:0 2px 8px var(--ac-line)}
.btn--pri:hover{background:var(--ac-2);border-color:var(--ac-2);color:#fff}
.btn--danger{color:var(--bad)}
.btn--danger:hover{background:var(--bad-soft);border-color:var(--bad);color:var(--bad)}
.btn--ok{color:var(--ok)}
.btn--ok:hover{background:var(--ok-soft);border-color:var(--ok);color:var(--ok-2)}
.btn--ghost{border-color:transparent;background:transparent}
.btn--ghost:hover{background:var(--panel-2);box-shadow:none}
.btn--lg{padding:11px 20px;font-size:var(--fs-lg);border-radius:var(--r)}
.btn--sm{padding:5px 10px;font-size:var(--fs-sm)}
.btn--block{width:100%}

/* 标签 */
.chip{
  display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-xs);font-weight:600;
  padding:2px 9px;border-radius:var(--r-full);
  background:var(--bg-2);color:var(--tx-2);border:1px solid var(--line);white-space:nowrap;
}
.chip--ac{background:var(--ac-soft);color:var(--ac-ink);border-color:var(--ac-line)}
.chip--ok{background:var(--ok-soft);color:var(--ok-2);border-color:var(--ok-line)}
.chip--warn{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.chip--bad{background:var(--bad-soft);color:var(--bad);border-color:transparent}
.chips{display:flex;gap:6px;flex-wrap:wrap}

/* 词性小标签（共享组件，跨 textbook / mistakes / listen 三个模块）
   ----------------------------------------------------------------------------
   ★ 用户原话：「要把词性加进去」「显示得太小 / 没注意到」。
     原来它是词头后面一个灰 `<small>`，等于没有；现在改成独立小标签（有边框有底色），
     字号比 .chip 大一点、字重高一点 —— **一眼能看见，又不抢词头**。
   ★ 空词性的两种标法见 core/ui.js 的 posChip()：「词组」/「词性待确认」，
     用更淡的虚线款，和真词性在视觉上分得开。
   ★ 类名 .wpos 是这一小块专用前缀；颜色圆角一律走 tokens，零硬编码色值。 */
.wpos{
  display:inline-flex;align-items:center;flex:none;
  font-size:var(--fs-sm);font-weight:700;line-height:1.25;
  font-family:var(--mono);letter-spacing:-.2px;
  padding:1px 7px;border-radius:var(--r-sm);
  background:var(--ac-soft);color:var(--ac-ink);border:1px solid var(--ac-line);
  white-space:nowrap;vertical-align:1px;
}
.wpos--todo{
  font-family:var(--font);font-weight:600;letter-spacing:0;
  background:transparent;color:var(--tx-3);border-style:dashed;border-color:var(--line-2);
}

/* 分段控件 */
.seg{display:inline-flex;gap:3px;background:var(--bg-2);border:1px solid var(--line);
  padding:3px;border-radius:var(--r-sm)}
.seg button{
  padding:6px 14px;border-radius:calc(var(--r-sm) - 1px);font-size:var(--fs-sm);
  font-weight:600;color:var(--tx-2);transition:all var(--t-fast) var(--ease);
}
.seg button:hover{color:var(--tx)}
.seg button.on{background:var(--panel);color:var(--ac-ink);box-shadow:var(--sh-1)}

/* 表单 */
.field{display:flex;flex-direction:column;gap:6px}
.field>label{font-size:var(--fs-sm);font-weight:600;color:var(--tx-2)}
.input,.select,.textarea{
  width:100%;padding:9px 12px;border-radius:var(--r-sm);
  border:1px solid var(--line);background:var(--panel);color:var(--tx);
  transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease);
}
.input:focus,.select:focus,.textarea:focus{
  outline:none;border-color:var(--ac);box-shadow:0 0 0 3px var(--ac-soft)}
.textarea{resize:vertical;line-height:1.7}
.hint{font-size:var(--fs-xs);color:var(--tx-3)}

/* 列表行 */
.rows{display:flex;flex-direction:column}
.row{display:flex;align-items:center;gap:11px;padding:11px 0}
.row+.row{border-top:1px solid var(--line)}
.row__main{flex:1;min-width:0}
.row__t{font-size:var(--fs-md);font-weight:600;color:var(--tx)}
.row__d{font-size:var(--fs-xs);color:var(--tx-3)}
.row__acts{flex:none;display:flex;gap:5px}

/* 进度条 */
.bar{height:5px;border-radius:3px;background:var(--line);overflow:hidden}
.bar i{display:block;height:100%;border-radius:3px;background:var(--ac);
  transition:width var(--t-mid) var(--ease)}
.bar--ok i{background:var(--ok)}

/* 空状态 / 载入 */
.empty{text-align:center;padding:var(--sp-10) var(--sp-4);color:var(--tx-3)}
.empty__ic{font-size:34px;margin-bottom:10px;opacity:.7}
.empty__t{font-size:var(--fs-lg);font-weight:600;color:var(--tx-2);margin-bottom:4px}
.spin{width:17px;height:17px;border:2px solid var(--line);border-top-color:var(--ac);
  border-radius:50%;animation:spin .7s linear infinite;display:inline-block;vertical-align:-3px}
@keyframes spin{to{transform:rotate(360deg)}}
.loading{color:var(--tx-3);font-size:var(--fs-sm);padding:var(--sp-5) 0;text-align:center}

/* 提示条 */
.note{display:flex;gap:9px;padding:11px 14px;border-radius:var(--r-sm);
  font-size:var(--fs-sm);line-height:1.65;background:var(--ac-soft);color:var(--ac-ink);
  border:1px solid var(--ac-line)}
.note--ok{background:var(--ok-soft);color:var(--ok-2);border-color:var(--ok-line)}
.note--warn{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.note--bad{background:var(--bad-soft);color:var(--bad);border-color:transparent}

/* 弹窗 */
.mask{position:fixed;inset:0;z-index:200;background:var(--overlay);
  display:grid;place-items:center;padding:20px;animation:fade var(--t-fast) var(--ease)}
.dlg{width:min(460px,100%);background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--sh-3);padding:var(--sp-5);
  display:flex;flex-direction:column;gap:var(--sp-3);max-height:88vh;overflow:auto}
.dlg h3{font-size:var(--fs-xl);font-weight:700;letter-spacing:-.3px}
.dlg__foot{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}
@keyframes fade{from{opacity:0}to{opacity:1}}

/* Toast */
.toasts{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);z-index:999;
  display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{
  padding:10px 18px;border-radius:var(--r-full);font-size:var(--fs-md);font-weight:600;
  background:var(--tx);color:var(--bg);box-shadow:var(--sh-3);
  animation:up var(--t-mid) var(--ease);max-width:80vw;
}
.toast.ok{background:var(--ok);color:#fff} .toast.bad{background:var(--bad);color:#fff}
@keyframes up{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* 需要密码的板块：内联密码门 */
.gate{max-width:390px;margin:9vh auto;text-align:center}
.gate__ic{width:52px;height:52px;border-radius:var(--r-lg);background:var(--ac-soft);
  color:var(--ac-ink);display:grid;place-items:center;font-size:24px;margin:0 auto 16px}
.gate h2{font-size:var(--fs-2xl);font-weight:700;letter-spacing:-.4px;margin-bottom:6px}
.gate p{color:var(--tx-2);font-size:var(--fs-md);margin-bottom:20px}
.gate form{display:flex;flex-direction:column;gap:11px;text-align:left}

/* ---------------------------------------------------------------------------
   ★★ 入口登录页（只有 AUTH_MODE=password 才出现；open 模式没有这个节点）
   ---------------------------------------------------------------------------
   用户原话：「上线以后我想是这样：输入网址后有一个简单的登录密码，
   进去以后就不再需要后台密码之类的了。」
   用户原话（身份）：「是的，进去以后自己切换身份就可以了。」
   → 一个密码框（今天的 MMDD）+ 一行"用账号密码登录"的后备入口。
   ★ 手机优先：.ws-login 是整屏 flex 居中，输入框高度 ≥44px，
     键盘弹出时整页可滚（overflow:auto），按钮不会被顶出可视区。
   --------------------------------------------------------------------------- */
.ws-login{position:fixed;inset:0;z-index:900;display:flex;align-items:center;
  justify-content:center;padding:24px 18px;background:var(--bg);
  overflow:auto;-webkit-overflow-scrolling:touch}
.ws-login__card{width:100%;max-width:360px;display:flex;flex-direction:column;
  gap:12px;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--sh-2);padding:26px 22px 22px;
  text-align:center;margin:auto}
.ws-login__logo{width:52px;height:52px;margin:0 auto;border-radius:var(--r-lg);
  background:var(--ac-soft);color:var(--ac-ink);display:grid;place-items:center;
  font-size:23px;font-weight:700}
.ws-login__t{font-size:var(--fs-2xl);font-weight:700;letter-spacing:-.4px;margin:0}
.ws-login__d{color:var(--tx-2);font-size:var(--fs-md);margin:0 0 4px}
.ws-login__card .field{text-align:left}
.ws-login__in{height:46px;font-size:var(--fs-lg)}
.ws-login__hint{color:var(--tx-3);font-size:var(--fs-sm);line-height:1.7;
  text-align:left;margin:2px 0 0}
.ws-login__hint b{color:var(--tx-2)}
.ws-login__err{text-align:left}
/* "这台设备是谁"（每台设备第一次进来选一次；进去以后右上角菜单里还能改） */
.ws-device__list{display:flex;flex-direction:column;gap:9px;margin-top:6px}
.ws-device__btn{display:flex;align-items:center;gap:10px;justify-content:flex-start;
  height:48px;font-size:var(--fs-lg)}
.ws-device__btn .ws-mi__badge{margin-left:auto}
@media (max-width:420px){
  .ws-login{padding:16px 14px;align-items:flex-start}
  .ws-login__card{padding:22px 18px 18px;margin-top:6vh}
}

/* 板块卡片（首页用） */
.mod{
  display:flex;flex-direction:column;gap:9px;padding:16px;text-align:left;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--sh-1);transition:all var(--t-fast) var(--ease);
}
.mod:hover{box-shadow:var(--sh-2);transform:translateY(-2px);border-color:var(--ac-line)}
.mod__top{display:flex;align-items:center;gap:10px}
.mod__ic{width:34px;height:34px;flex:none;border-radius:9px;background:var(--ac-soft);
  color:var(--ac-ink);display:grid;place-items:center;font-size:16px}
.mod__n{font-size:var(--fs-lg);font-weight:650;letter-spacing:-.2px}
.mod__d{font-size:var(--fs-xs);color:var(--tx-3);line-height:1.6}
.mod__foot{margin-top:auto;display:flex;align-items:center;gap:6px}
.mod.soon{opacity:.62;box-shadow:none}
.mod.soon:hover{transform:none;box-shadow:none;border-color:var(--line)}

/* 骨架屏 */
.sk{background:linear-gradient(90deg,var(--line) 25%,var(--panel-2) 37%,var(--line) 63%);
  background-size:400% 100%;border-radius:5px;animation:sk 1.3s ease infinite}
@keyframes sk{0%{background-position:100% 50%}100%{background-position:0 50%}}

/* ---------------------------------------------------------------- 响应式 */
@media (max-width:1080px){
  .grid--4{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:900px){
  .ws-side,.ws.mini .ws-side{width:var(--side-w-mini)}
  .ws-side__name,.ws-nav__tx,.ws-nav__bdg,.ws-legacy{display:none}
  .ws-nav{justify-content:center;padding:9px 0}
  .ws-grp{opacity:0;height:10px;padding:0}
  .ws-fold{justify-content:center;padding:9px 0}
  .ws-fold span{display:none}
  .ws-view__in{padding:var(--sp-4) var(--sp-4) var(--sp-8)}
}
@media (max-width:640px){
  .grid--4,.grid--3,.grid--2{grid-template-columns:minmax(0,1fr)}
  .pg-head h1{font-size:var(--fs-2xl)}
  .ws-crumb{display:none}
  .ws-view__in{padding:var(--sp-3) var(--sp-3) var(--sp-8)}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

/* ============================================================================
   单词学习 · 统计看板日历（模块局部样式）
   ----------------------------------------------------------------------------
   ★ 只给 modules/words.js 用，类名统一 cal- 前缀，不动上面任何已有规则。
   ★ 颜色一律走 tokens 变量，热的档位用 color-mix 调主色深浅，换皮自动跟随。
   ============================================================================ */
.cal__hd{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;margin-bottom:var(--sp-4)}
.cal__nav{display:flex;align-items:center;gap:6px}
.cal__title{font-size:var(--fs-lg);font-weight:650;letter-spacing:-.2px;
  min-width:8.5em;text-align:center;font-variant-numeric:tabular-nums}
.cal__legend{margin-left:auto;display:flex;align-items:center;gap:5px;
  font-size:var(--fs-xs);color:var(--tx-3)}
.cal__sw{width:13px;height:13px;border-radius:3px;border:1px solid var(--line);
  background:var(--bg-2);display:inline-block}
.cal__body{display:grid;grid-template-columns:minmax(0,520px) minmax(0,1fr);
  gap:var(--sp-5);align-items:start}
.cal__grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:5px}
.cal__grid>.loading{grid-column:1/-1}
.cal__wd{text-align:center;font-size:var(--fs-xs);color:var(--tx-3);
  font-weight:600;padding-bottom:2px}
.cal__ph{height:52px}
.cal-d{position:relative;height:52px;border-radius:var(--r-sm);border:1px solid transparent;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;
  font-size:var(--fs-sm);font-weight:600;color:var(--tx);background:var(--bg-2);
  transition:box-shadow var(--t-fast) var(--ease),transform var(--t-fast) var(--ease)}
.cal-d__n{line-height:1.1;font-variant-numeric:tabular-nums}
.cal-d__v{font-family:var(--mono);font-size:9.5px;font-weight:700;opacity:.8;line-height:1}
.cal-d:hover{transform:translateY(-1px);box-shadow:var(--sh-2)}
.cal-d.is-future{color:var(--tx-3);opacity:.5}
.cal-d.is-today{box-shadow:inset 0 0 0 2px var(--tx)}
.cal-d.is-sel{outline:2px solid var(--ac-ink);outline-offset:1px}
.cal-d.lv1{background:var(--ac-soft);background:color-mix(in srgb,var(--ac) 15%,var(--panel))}
.cal-d.lv2{background:var(--ac-soft);background:color-mix(in srgb,var(--ac) 45%,var(--panel))}
.cal-d.lv3{background:var(--ac);color:var(--panel)}
.cal__sw.lv1{background:color-mix(in srgb,var(--ac) 15%,var(--panel))}
.cal__sw.lv2{background:color-mix(in srgb,var(--ac) 45%,var(--panel))}
.cal__sw.lv3{background:var(--ac)}
.cal__side{display:flex;flex-direction:column;gap:var(--sp-3);min-width:0}
.cal__sum{display:flex;flex-direction:column;gap:8px}
.cal__sum-t{font-size:var(--fs-sm);font-weight:650;color:var(--tx-2)}
.cal__det{display:flex;flex-direction:column;gap:8px;min-height:62px;
  padding-top:var(--sp-3);border-top:1px solid var(--line)}
.cal__det-t{font-size:var(--fs-lg);font-weight:650;letter-spacing:-.2px}

@media (max-width:900px){
  .cal__body{grid-template-columns:minmax(0,1fr);gap:var(--sp-4)}
  .cal__det{min-height:0}
}
@media (max-width:640px){
  .cal__title{min-width:0;font-size:var(--fs-md)}
  .cal__legend{margin-left:0;width:100%}
  .cal__grid{gap:3px}
  .cal-d,.cal__ph{height:40px}
  .cal-d{font-size:var(--fs-xs);border-radius:5px}
  .cal-d__v{display:none}
}
