/* ============================================================
   英语学习中心 · 公共样式（common.css）
   ------------------------------------------------------------
   2026-10-17 · 视觉重构「清爽学习 App 风」：
   · 本文件是**唯一**的设计 token 正本（颜色阶 / 圆角 / 阴影 / 间距 /
     字阶 / 动效时长与缓动）。各页 css 只消费 token，不再写 :root 副本。
   · 画布：浅灰白底 + 顶部极淡的品牌色晕染；顶栏为 sticky 毛玻璃。
   · 零外部资源：无字体文件 / CDN / 图标库 / 外部图片，图标只用
     内联 SVG（data URI）、CSS 图形或系统 emoji。
   · class/id 契约不变：.es-topbar 等由 common.js 注入；各页既有选择器
     （.btn / .card / .chip / .cv-* / .lib-* / .ch-* / .stat-*）全部保留，
     只做「增补 + 覆盖」，不动 JS 依赖的 DOM 结构。
   · .wrap 仍只在本文件定义，各页只覆盖 --page-wrap。
   · 响应式契约保留：≤760px 表格卡片化、env(safe-area-inset-*)/dvh、
     触控目标 ≥ --tap(44px)、手机正文 ≥13.5px。
   ============================================================ */

:root{
  /* ---------- 品牌色阶（绿 → 青，克制的一层品牌色） ---------- */
  --brand-50:#eefaf3;
  --brand-100:#d6f3e3;
  --brand-200:#b2e7cc;
  --brand-500:#0f9d63;
  --brand-600:#0a7a4e;
  --brand-700:#076b45;
  --brand-800:#065336;

  /* ---------- 中性色阶 ---------- */
  --neutral-0:#ffffff;
  --neutral-50:#f6f8fb;
  --neutral-100:#eef2f7;
  --neutral-200:#e2e8f0;
  --neutral-300:#cbd5e1;
  --neutral-500:#5b6b80;
  --neutral-700:#334155;
  --neutral-900:#0f172a;

  /* ---------- 语义色 ---------- */
  --success:#0a7048;
  --success-soft:#e9f9f1;
  --warn:#b45309;
  --warn-soft:#fff6e8;
  --danger:#b42318;
  --danger-soft:#fdecea;
  --info:#1d4ed8;
  --info-soft:#eaf1ff;

  /* ---------- 旧变量别名（页面 css / 既有组件仍在用，值全部收敛到上面） ---------- */
  --green:var(--brand-600);
  --green-dark:var(--brand-700);
  --green-soft:var(--brand-50);
  --orange:var(--warn);
  --orange-dark:#9a4708;
  --orange-soft:var(--warn-soft);
  --gray:var(--neutral-500);
  --gray-dark:var(--neutral-700);
  --gray-soft:#f2f5f9;
  --blue:var(--info);
  --blue-dark:#1e40af;
  --blue-soft:var(--info-soft);
  --red:var(--danger);
  --red-soft:var(--danger-soft);
  --ink:var(--neutral-900);
  --ink-2:#526071;
  --line:var(--neutral-200);
  --bg:var(--neutral-50);
  --zh:#12507e;
  /* HYA 徽标紫（family app.css 无此色，保留） */
  --purple:#7c3aed;
  --purple-soft:#f3ecff;

  /* ---------- 圆角 ---------- */
  --r-sm:10px;
  --r-md:14px;
  --r-lg:18px;
  --r-pill:999px;
  --radius-sm:var(--r-sm);
  --radius:var(--r-md);
  --radius-lg:var(--r-lg);

  /* ---------- 阴影（两级 + 弹层一级） ---------- */
  --sh-1:0 1px 2px rgba(15,23,42,.05);
  --sh-2:0 10px 30px -12px rgba(15,23,42,.18);
  --sh-3:0 24px 60px -28px rgba(15,23,42,.32);

  /* ---------- 间距阶 ---------- */
  --sp-1:4px;
  --sp-2:8px;
  --sp-3:12px;
  --sp-4:16px;
  --sp-5:20px;
  --sp-6:24px;
  --sp-8:32px;

  /* ---------- 字阶 ---------- */
  --fs-3xl:30px;
  --fs-2xl:24px;
  --fs-xl:20px;
  --fs-lg:17px;
  --fs-base:16px;
  --fs-md:15px;
  --fs-sm:14px;
  --fs-xs:13px;

  /* ---------- 动效 ---------- */
  --dur-1:160ms;
  --dur-2:200ms;
  --ease:cubic-bezier(.2,.7,.3,1);

  /* ---------- 响应式 token（2026-10-17） ---------- */
  --tap:44px;                          /* 触控最小可点尺寸 */
  --pad-x:clamp(14px,3.2vw,40px);      /* 页面左右内边距（流式） */
  --wrap:1400px;                       /* 全站容器上限：桌面/超宽不无限拉伸 */
  --wrap-study:960px;                  /* 学习页：单卡阅读宽度，全站最窄 */
  --measure:72ch;                      /* 最长文本块可读宽度（≈72 字符） */
  --page-wrap:var(--wrap);             /* 每页可覆盖：.wrap{--page-wrap:…} */
  --pad-t:clamp(12px,2vw,22px);
  --pad-b:max(56px,calc(env(safe-area-inset-bottom,0px) + 32px));
}

*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
html{background:var(--neutral-50);}
body{
  background:
    radial-gradient(1100px 520px at 86% -10%,rgba(15,157,99,.075),transparent 62%),
    radial-gradient(900px 460px at 2% -8%,rgba(29,78,216,.05),transparent 60%),
    var(--bg);
  background-repeat:no-repeat;
  color:var(--ink);
  font-family:"Microsoft YaHei","PingFang SC","Hiragino Sans GB","Source Han Sans SC","Noto Sans CJK SC","Segoe UI",system-ui,-apple-system,sans-serif;
  font-size:var(--fs-base);
  line-height:1.65;
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
  overflow-wrap:break-word;
  -webkit-tap-highlight-color:rgba(15,157,99,.12);
}
::selection{background:var(--brand-100);color:var(--brand-800);}
.hidden{display:none !important;}

/* 键盘 focus 必须可见；鼠标点击不出现外圈 */
:focus-visible{
  outline:2px solid var(--brand-500);
  outline-offset:2px;
  border-radius:4px;
}

/* ---------- 统一容器（唯一的 .wrap 定义） ---------- */
.wrap{
  max-width:var(--page-wrap);
  margin:0 auto;
  padding:18px 16px 64px;              /* 老浏览器兜底 */
  padding:
    var(--pad-t)
    max(var(--pad-x),env(safe-area-inset-right,0px))
    var(--pad-b)
    max(var(--pad-x),env(safe-area-inset-left,0px));
}
/* 说明/提示类长文本不拉成超宽横条（桌面 >1400 时仍易读） */
.hint,.cv-note,.sub,.modal-text,.dim,.legend-tip,.ch-empty-tip{max-width:var(--measure);}

/* ============================================================
   顶栏（common.js 注入；class 名固定）
   DOM 顺序：.es-back → .es-brand → .es-nav → .es-user
   视觉顺序：品牌 → 导航 → 用户；工具箱链接收在左侧当小返回
   sticky 放在 #topbar 外层（它的包含块是 .wrap 整页高度）：
   若直接给 .es-topbar 设 sticky，会被高度=自身高度的父元素 #topbar 限制住，滚不走。
   ============================================================ */
#topbar{position:sticky;top:0;z-index:40;}
.es-topbar{
  display:flex;flex-wrap:wrap;align-items:center;
  gap:6px 18px;
  background:rgba(255,255,255,.82);
  -webkit-backdrop-filter:saturate(1.4) blur(10px);
  backdrop-filter:saturate(1.4) blur(10px);
  border:1px solid var(--line);
  border-radius:var(--r-md);
  box-shadow:var(--sh-1);
  padding:8px 14px;
  margin-bottom:18px;
}
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .es-topbar{background:rgba(255,255,255,.96);}
}

/* 左：← 工具箱（小号、低干扰） */
.es-topbar .es-back{
  order:0;
  color:var(--neutral-500);font-size:var(--fs-xs);font-weight:500;
  text-decoration:none;display:inline-flex;align-items:center;gap:4px;
  min-height:32px;padding:2px 2px;border-radius:8px;
  transition:color var(--dur-1) var(--ease);
}
.es-topbar .es-back:hover{color:var(--brand-700);}

/* 品牌：渐变圆角方块 + 名称 */
.es-topbar .es-brand{
  order:1;
  display:inline-flex;align-items:center;gap:10px;
  font-size:var(--fs-md);font-weight:700;letter-spacing:.01em;
  color:var(--neutral-900);line-height:1.25;white-space:nowrap;
}
.es-topbar .es-brand::before{
  content:"E";
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;flex:none;
  border-radius:9px;
  background:linear-gradient(140deg,var(--brand-500) 0%,var(--brand-700) 78%);
  color:#fff;font-family:Georgia,"Times New Roman",serif;
  font-size:17px;font-weight:700;line-height:1;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35),0 4px 10px -6px rgba(6,95,70,.8);
}

/* 导航 pill：默认灰字，hover 浅底，当前页浅绿实底 */
.es-topbar .es-nav{
  order:2;display:flex;flex-wrap:wrap;align-items:center;gap:2px;
  font-size:var(--fs-sm);min-width:0;
}
.es-topbar .es-nav a{
  color:var(--neutral-500);text-decoration:none;font-weight:500;
  display:inline-flex;align-items:center;justify-content:center;
  padding:6px 12px;border-radius:var(--r-pill);
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease);
}
.es-topbar .es-nav a:hover{background:var(--neutral-100);color:var(--neutral-900);}
.es-topbar .es-nav a.active{
  background:var(--brand-100);color:var(--brand-700);font-weight:600;
  box-shadow:inset 0 0 0 1px rgba(11,138,87,.12);
}

/* 右侧用户区：徽标 + 幽灵登出（未登录时只有「登录」链接） */
.es-user{order:3;display:inline-flex;align-items:center;gap:8px;margin-left:auto;}
.es-login{
  color:var(--brand-700);font-size:var(--fs-sm);font-weight:600;
  text-decoration:none;display:inline-flex;align-items:center;
  min-height:36px;padding:0 12px;border-radius:var(--r-pill);
  background:var(--brand-50);border:1px solid var(--brand-100);
  transition:background var(--dur-1) var(--ease);
}
.es-login:hover{background:var(--brand-100);}

.es-badge{
  display:inline-flex;align-items:center;gap:4px;
  border:1px solid transparent;border-radius:var(--r-pill);
  font-size:var(--fs-xs);font-weight:600;line-height:1.3;
  padding:5px 11px;white-space:nowrap;background:var(--neutral-100);
  color:var(--neutral-700);
}
.es-badge.owner{background:var(--purple-soft);color:var(--purple);border-color:#ddd0ff;}
.es-badge.guest{background:var(--neutral-100);color:var(--neutral-700);border-color:var(--neutral-200);}

.es-logout{
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--neutral-200);background:transparent;color:var(--neutral-500);
  border-radius:var(--r-pill);padding:6px 13px;
  font-family:inherit;font-size:var(--fs-xs);font-weight:500;line-height:1.3;
  cursor:pointer;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease);
}
.es-logout:hover{background:var(--neutral-100);color:var(--neutral-900);border-color:var(--neutral-300);}

/* ============================================================
   通用按钮（.btn 与 .es-btn 同源；各页不再重复定义基础样式）
   primary 实心绿 / navy 浅绿次要 / ghost 描边 / danger 红
   ============================================================ */
.btn,.es-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:40px;padding:9px 16px;
  border:1px solid transparent;border-radius:11px;
  font-family:inherit;font-size:var(--fs-md);font-weight:600;line-height:1.3;
  text-decoration:none;text-align:center;cursor:pointer;
  background:var(--brand-700);color:#fff;
  transition:background var(--dur-1) var(--ease),
             border-color var(--dur-1) var(--ease),
             box-shadow var(--dur-1) var(--ease),
             transform var(--dur-1) var(--ease),
             opacity var(--dur-1) var(--ease);
}
.btn:hover,.es-btn:hover{background:var(--brand-600);}
.btn:active,.es-btn:active{transform:translateY(1px);}
.btn:disabled,.es-btn:disabled{opacity:.55;cursor:not-allowed;}
.btn:disabled:active,.es-btn:disabled:active{transform:none;}

.btn.primary,.btn-green,.es-btn.primary{background:var(--brand-700);color:#fff;box-shadow:0 10px 22px -16px rgba(6,95,70,.9);}
.btn.primary:hover,.btn-green:hover,.es-btn.primary:hover{background:var(--brand-600);}
.btn-blue{background:var(--brand-700);color:#fff;box-shadow:0 10px 22px -16px rgba(6,95,70,.9);}
.btn-blue:hover{background:var(--brand-600);}
.btn-orange{background:var(--warn);color:#fff;}
.btn-orange:hover{background:var(--orange-dark);}

/* 浅绿次要按钮 */
.btn-navy{background:var(--brand-50);border-color:var(--brand-100);color:var(--brand-700);}
.btn-navy:hover{background:var(--brand-100);color:var(--brand-800);}

/* 描边幽灵按钮 */
.btn.ghost,.es-btn.ghost,.btn-nav{background:transparent;border-color:var(--neutral-200);color:var(--neutral-700);}
.btn.ghost:hover,.es-btn.ghost:hover,.btn-nav:hover{background:var(--neutral-100);border-color:var(--neutral-300);color:var(--neutral-900);}

/* 危险操作 */
.btn-danger{background:transparent;border-color:#eccbc7;color:var(--danger);}
.btn-danger:hover{background:var(--danger-soft);border-color:#e3b3ad;color:#8f1c13;}

.btn-big{font-size:var(--fs-md);padding:12px 22px;border-radius:var(--r-md);min-height:48px;white-space:nowrap;}
.btn-tool{font-size:var(--fs-sm);padding:10px 15px;}

/* ============================================================
   通用卡片 / 区块
   ============================================================ */
.es-card{
  background:var(--neutral-0);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  padding:var(--sp-5);
  box-shadow:var(--sh-1);
}
.card{
  background:var(--neutral-0);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-1);
}

/* 统一 section header：左侧 3px 品牌竖条 + 标题
   竖条与标题固定 10px 间距；竖条顶部对齐首行文字（标题换行时不居中到整块高度） */
.sec,.cv-title,.lib-head h1,.ch-head h1{position:relative;}
.sec,.cv-title{
  display:flex;flex-wrap:wrap;align-items:flex-start;
  column-gap:0;row-gap:4px;
  font-size:var(--fs-xl);font-weight:700;line-height:1.35;color:var(--ink);
  margin:0 0 14px;
}
.sec::before,.cv-title::before{
  content:"";flex:none;width:3px;height:1.05em;border-radius:2px;
  margin:.15em 10px 0 0;
  background:linear-gradient(180deg,var(--brand-500),var(--brand-700));
}
.cv-title{column-gap:8px;}
.cv-title::before{margin-right:2px;}
.lib-head h1,.ch-head h1{display:flex;align-items:center;column-gap:0;}
.lib-head h1::before,.ch-head h1::before{
  content:"";flex:none;width:3px;height:.8em;border-radius:2px;
  margin-right:10px;align-self:center;
  background:linear-gradient(180deg,var(--brand-500),var(--brand-700));
}

/* ============================================================
   响应式公共层（各页共用，勿在页面 css 里重复定义）
   ============================================================ */

/* ---------- 触控：粗指针（手机/平板/折叠屏触屏）或窄屏 ---------- */
@media (pointer:coarse),(max-width:700px){
  /* 所有可点控件 ≥ --tap(44px)；input/select ≥16px 避免 iOS 聚焦自动放大 */
  button,.es-btn,.es-logout,.chip,.lib-chip,.lib-row,.cv-tab,summary,
  select,.cv-select,.cv-input,input[type="search"],input[type="text"],
  input[type="password"],input[type="file"]{
    min-height:var(--tap);
  }
  input[type="search"],input[type="text"],input[type="password"],
  select,.cv-select,.cv-input{font-size:16px;}
  /* 独立的图标按钮同时保证宽高（🔊 之类）——带类名提高优先级，压过页面里 36/40px 的自定义值 */
  button.say,button.ch-say,button.cv-tab,button.mode-btn,
  button[class*="say"],.es-btn.ghost.cv-mini{min-width:var(--tap);min-height:var(--tap);}
  /* 头部/导航链接保持足够行高（行内元素需 inline-flex 才吃 min-height） */
  .es-topbar .es-nav a,.es-topbar .es-back,.es-login,.back,.lib-row .go{display:inline-flex;align-items:center;min-height:var(--tap);}
  /* 安全区：顶栏在 .wrap 之内，左右安全区已由 .wrap 的 max(--pad-x, env(...)) 兜住，
     这里不再重复加，避免刘海屏上出现双倍内边距。 */
}

/* ---------- 手机竖屏（≤700px）：顶栏两行、导航横滑 ---------- */
@media (max-width:700px){
  .es-topbar{gap:2px 8px;padding:7px 10px;border-radius:var(--r-md);}
  #topbar{position:sticky;top:0;}
  .es-topbar .es-back{order:0;font-size:13.5px;min-height:var(--tap);}
  .es-topbar .es-brand{order:1;font-size:var(--fs-sm);gap:8px;}
  .es-topbar .es-brand::before{width:26px;height:26px;border-radius:8px;font-size:15px;}
  .es-user{order:2;gap:6px;}
  .es-badge{font-size:13.5px;padding:4px 9px;}
  .es-logout{font-size:13.5px;padding:5px 10px;min-height:var(--tap);}
  .es-topbar .es-nav{
    order:3;flex:1 1 100%;width:100%;
    flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;
    gap:2px;padding:1px 1px 2px;
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
  }
  .es-topbar .es-nav::-webkit-scrollbar{display:none;}
  .es-topbar .es-nav a{padding:6px 13px;font-size:var(--fs-sm);white-space:nowrap;}
  .es-badge,.es-logout,.es-back,.es-login{font-size:13.5px;}
}

/* ---------- 双折叠方屏（≈0.8~0.9 宽高比，700–1000px） ---------- */
@media (min-width:701px) and (max-width:1000px){
  .es-topbar{gap:6px 14px;}
}

/* ---------- 超宽屏（≥1600px）：容器已封顶，只调纵向留白 ---------- */
@media (min-width:1600px){
  :root{--pad-t:clamp(16px,1.6vw,26px);}
}

/* ---------- 折叠/平板宽度（701–1180）：不依赖 pointer 的触控兜底 ----------
   有些折叠屏/平板/带触屏的轻薄本会把 pointer 报成 fine（尤其接了鼠标或笔），
   那样上面的 (pointer:coarse) 触控层不生效，导航只剩 32px。
   这一层只把常点控件抬到 40px（不追求 44，避免桌面观感变臃肿），
   ≥1201 的纯桌面仍按鼠标密度排。 */
@media (min-width:701px) and (max-width:1180px){
  .es-topbar .es-nav a,.es-topbar .es-back,.es-login,.es-logout,
  /* 用 button.xxx 提权：页面内联 <style> 里的 .ch-say{min-height:36px} 同权重且更晚，
     只有加一级元素选择器才压得住。 */
  button.ch-say,button.cv-tab,button.cv-mini,.cv-mini,.say{display:inline-flex;align-items:center;justify-content:center;min-height:40px;}
  button.ch-say,button.cv-mini,.cv-mini,.say{min-width:40px;}
}

/* ---------- 动效降级（系统开了「减少动态效果」就全关） ---------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}

/* 超窄屏（必须放在 .es-* 基础规则之后，同权重后者生效）
   超窄屏（≤400，如 360 宽的老机型）：把「← 工具箱」收成箭头、品牌降一档、导航收窄，
   让顶栏从 3 行回到 2 行（品牌+用户一行，导航一行），首屏不多占 40px。 */
@media (max-width:400px){
  .es-topbar{gap:6px 10px;padding:8px 12px;}
  .es-topbar .es-back{font-size:0;gap:0;min-width:26px;justify-content:center;}
  .es-topbar .es-back::before{content:"←";font-size:16px;line-height:1;}
  .es-topbar .es-brand{font-size:15px;gap:8px;}
  .es-topbar .es-brand::before{width:26px;height:26px;border-radius:8px;}
  .es-topbar .es-nav a{padding:6px 9px;}
}

/* ============================================================
   折叠屏横持 / 小平板宽度（701–1180）两处定点修正
   （2026-10-19 用无头浏览器在真实设备 CSS 视口下实测后补；两块都必须放在文件末尾，
     因为要压过上面同权重、更早定义的规则）
   ============================================================ */

/* ① 顶栏「先压窄导航，再考虑换行」——修 Mate X2 内屏横持（763×676）的孤行
   现象：763 这一档加了用户徽标后整行放不下（back 58 + 品牌≈140 + 导航≈490 + 用户≈111
   + 间隙≈36 ≈ 835 > 763），默认 flex-wrap 就把 .es-user（order:3 + margin-left:auto）
   甩到第二行、孤零零右对齐 → 顶栏 104px，白吃 46px 竖向空间（676 高的 6.8%）。
   做法：让导航变成可收缩项（min-width:0 才允许压到内容宽度以下）+ 横向可滑，
   浏览器会**先压窄导航**而不是换行；真压到极限还放不下时才回退换行（不会横向溢出）。
   代价：763 下最后一个导航项会被截掉一点，需要横滑——这与 ≤700 手机档的导航横滑是同一套交互，一致。 */
@media (min-width:701px) and (max-width:1180px){
  /* 🔴 必须同时给 .es-topbar 加 nowrap：flex 的**换行判定用的是「假设主尺寸」**
     （hypothetical main size），`min-width:0` 只在**同一行内**分配剩余空间时才生效。
     只给 .es-nav 设 min-width:0 是没用的——实测那样做顶栏仍换行（763 档 104 → 112px）。
     加了 nowrap 之后，所有项先排进一行，再由 flex-shrink 把导航压窄。 */
  .es-topbar{flex-wrap:nowrap;}
  .es-topbar .es-back,.es-topbar .es-brand,.es-user{flex-shrink:0;}
  .es-topbar .es-nav{
    min-width:0;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
  }
  .es-topbar .es-nav::-webkit-scrollbar{display:none;}
  .es-topbar .es-nav a{white-space:nowrap;}
}

/* ② 真触控设备在 701–1180 也必须是 44px —— 修级联被压掉的问题
   🔴 级联顺序坑：上面 `(min-width:701px) and (max-width:1180px)` 那条 40px 兜底规则
   （本意是「有些折叠屏/平板/触屏本会把 pointer 报成 fine，给它们兜到 40px」）
   写在 `(pointer:coarse)` 层**之后**且**同权重** → 它会把触控层的 44px 压回 40px。
   实测证据：Mate X2 内屏横持(763)、S21 Ultra 横持(854) 上顶栏链接实测就是 40px，
   而这两台都是纯触控设备、`(pointer:coarse)` 为真。
   这里把粗指针设备抬回 44px；只有真报了 fine 的设备才继续用 40px 兜底。 */
@media (pointer:coarse) and (min-width:701px){
  .es-topbar .es-nav a,.es-topbar .es-back,.es-login,.es-logout,
  button.ch-say,button.cv-tab,button.cv-mini,.cv-mini,.say{min-height:var(--tap);}
}

