/* ==================================================================
   base.css — 云上公学·地理实验室 · 公共视觉层 v2
   ------------------------------------------------------------------
   设计原则（对应《前端显示优化方案_20260925.md》§3）：
     1. 唯一视觉来源：本文件在前、static/pages/<page>.css 在后，
        页面层只写布局几何，不再需要 !important 反向覆盖。
     2. 全部颜色/字号/圆角/间距/阴影/时长走 token，页面层不写字面色值。
     3. 响应式断点收在本文件（clamp + @media），页面级断点不再被压死。
     4. 花活分级：html[data-fx="0|1|2"]，见文末 FX 段；默认 1。
     5. 不引外部资源（字体/图片/CDN），底纹用内联 SVG data-URI。
   ================================================================== */

/* ---------- 0. token ---------- */
:root {
  /* 品牌与中性色 */
  --g-primary: #4f46e5;
  --g-primary-2: #2563eb;
  --g-primary-3: #0ea5e9;
  --g-primary-soft: rgba(79, 70, 229, 0.10);
  --g-primary-soft-2: rgba(37, 99, 235, 0.10);
  --g-grad: linear-gradient(135deg, #4f46e5, #2563eb);
  --g-grad-hover: linear-gradient(135deg, #4338ca, #1d4ed8);
  --g-grad-ink: linear-gradient(115deg, #1e1b4b 0%, #4f46e5 42%, #0ea5e9 85%);

  --g-ink: #0f172a;
  --g-ink-2: #334155;
  --g-mute: #64748b;          /* 白底 4.76:1，达 AA */
  --g-mute-2: #94a3b8;        /* 仅用于分隔符/装饰，不作为正文 */
  --g-line: rgba(15, 23, 42, 0.09);
  --g-line-2: rgba(15, 23, 42, 0.055);
  --g-bg: #f5f6fa;
  --g-surface: #ffffff;
  --g-surface-2: #f8fafc;
  --g-surface-3: #f1f5f9;
  --g-on-primary: #ffffff;              /* 主色底上的文字色 */
  --g-scrim: rgba(15, 23, 42, 0.45);    /* 遮罩/抽屉背景 */

  /* 语义色（正文级对比度） */
  --g-ok: #047857;
  --g-ok-bg: #ecfdf5;
  --g-ok-2: #34d399;                    /* 深底上的成功色 */
  --g-warn: #b45309;
  --g-warn-bg: #fffbeb;
  --g-danger: #dc2626;
  --g-danger-bg: #fef2f2;
  --g-danger-2: #f87171;                /* 深底上的危险色 */
  --g-disabled: #94a3b8;                /* 禁用态底色（白字对比度达标） */
  --g-info: #0369a1;
  --g-info-bg: #f0f9ff;

  /* 三线主色（V9.2 拉开色相：紫 / 青绿 / 暖橙，主色白底对比度均 ≥4.5:1） */
  --g-knowledge: #7c3aed;
  --g-knowledge-2: #c084fc;
  --g-knowledge-bg: #f5f3ff;
  --g-tasks: #0f766e;
  --g-tasks-2: #2dd4bf;
  --g-tasks-bg: #f0fdfa;
  --g-exams: #c2410c;
  --g-exams-2: #fb923c;
  --g-exams-bg: #fff7ed;

  /* 浅色渐变（图标底/装饰条用；V9.2 与三线主色同相位：靛蓝英雄位 + 紫 / 青绿 / 暖橙） */
  --g-wash-1: linear-gradient(135deg, #eef2ff, #e0f2fe);
  --g-wash-2: linear-gradient(135deg, #ede9fe, #ddd6fe);
  --g-wash-3: linear-gradient(135deg, #ccfbf1, #99f6e4);
  --g-wash-4: linear-gradient(135deg, #ffedd5, #fed7aa);

  /* 图表调色板（stats / 热点图统一取这里） */
  --g-c1: #4f46e5;
  --g-c2: #0ea5e9;
  --g-c3: #7c3aed;
  --g-c4: #0891b2;
  --g-c5: #f59e0b;
  --g-c6: #10b981;

  /* 科目色板（任务看板时间轴/色点专用；V9.2.1 按评审意见改为色相均布的亮色，
     与图表色解耦——条上无文字可放心用亮色，stats 图表不受影响） */
  --g-subj-1: #3b82f6;   /* 蓝 */
  --g-subj-2: #f97316;   /* 橙 */
  --g-subj-3: #14b8a6;   /* 青 */
  --g-subj-4: #ec4899;   /* 玫红 */
  --g-subj-5: #8b5cf6;   /* 紫 */
  --g-subj-6: #84cc16;   /* 黄绿 */

  /* 字号阶梯（1.2~1.27 模数；V9.1 拉开层级——正文 15px、meta 12px，页面至少出现 xl 档标题锚点）
     xs=meta/时间戳/徽标 · sm=次要说明 · base=正文 · md=卡片标题 · lg=区块题 · xl=页题 · 2xl=展示数字 */
  --g-fs-xs: 12px;
  --g-fs-sm: 13.5px;
  --g-fs-base: 15px;
  --g-fs-md: 17px;
  --g-fs-lg: 21px;
  --g-fs-xl: 26px;
  --g-fs-2xl: 34px;
  --g-fs-hero: clamp(1.7rem, 4.2vw, 2.6rem);

  /* 圆角 / 间距 / 阴影
     间距系统：4px 基数、8 的倍数收口——卡内 16/24，区块间 32/40，页首尾 48/64 */
  --g-r-sm: 8px;
  --g-r-md: 12px;
  --g-r-lg: 16px;
  --g-r-xl: 20px;
  --g-r-pill: 999px;
  --g-sp-1: 4px;
  --g-sp-2: 8px;
  --g-sp-3: 12px;
  --g-sp-4: 16px;
  --g-sp-5: 24px;
  --g-sp-6: 32px;
  --g-sp-7: 40px;
  --g-sp-8: 48px;
  --g-sp-9: 64px;
  --g-sh-sm: 0 1px 2px rgba(16, 24, 40, 0.05), 0 1px 3px rgba(16, 24, 40, 0.06);
  --g-sh-md: 0 2px 4px rgba(16, 24, 40, 0.04), 0 12px 32px -12px rgba(16, 24, 40, 0.16);
  --g-sh-lg: 0 4px 10px rgba(16, 24, 40, 0.05), 0 24px 48px -16px rgba(16, 24, 40, 0.22);
  --g-sh-primary: 0 6px 16px -6px rgba(79, 70, 229, 0.5);
  --g-sh-primary-hover: 0 10px 22px -8px rgba(79, 70, 229, 0.55);

  /* 动效 */
  --g-dur: 0.16s;
  --g-dur-2: 0.24s;
  --g-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* 版心（1440 屏下左右留白 ~120px；双栏应用页用宽版心） */
  --g-page: 1200px;
  --g-page-wide: 1400px;
  --g-nav-h: 56px;

  /* 经纬网底纹（默认 mid，见文件末尾"地理底纹"段） */
  --g-grid-cell: 140px;
  --g-grid-sub: 35px;
  --g-grid-major: rgba(15, 23, 42, 0.105);
  --g-grid-minor: rgba(15, 23, 42, 0.045);
}

/* ---------- 1. reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body, h1, h2, h3, h4, h5, p, figure, blockquote, dl, dd, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
/* reset 只服务于组件列表；Markdown 正文里的列表要恢复符号与缩进 */
.md ul, .md ol, .md-body ul, .md-body ol,
.chat-msg ul, .chat-msg ol, .detail-content ul, .detail-content ol, ul.detail-list {
  padding-left: 1.4em;
  list-style: revert;
}
ul.detail-list { margin: 6px 0; }
img, svg, canvas { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: inherit; }
:root { -webkit-tap-highlight-color: transparent; }

body {
  min-height: 100vh;
  min-height: 100dvh;   /* 移动端地址栏收放时不会把底部输入区顶出视口 */
  background-color: var(--g-bg);
  color: var(--g-ink);
  font-family: "HarmonyOS Sans SC", "MiSans", "PingFang SC", "Microsoft YaHei UI",
    "Microsoft YaHei", -apple-system, "Segoe UI", Roboto, "Noto Sans SC", sans-serif;
  font-size: var(--g-fs-base);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: rgba(79, 70, 229, 0.16); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border: 3px solid transparent; background-clip: content-box; border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: #94a3b8; border: 3px solid transparent; background-clip: content-box; }

/* 统一焦点环：鼠标点击不显示，键盘 Tab 必显示 */
:focus-visible { outline: 2px solid var(--g-primary); outline-offset: 2px; border-radius: 4px; }

h1, h2, h3, h4 { color: var(--g-ink); line-height: 1.3; }
/* 装饰性灰不再承担正文，最小正文 12.5px */
small { font-size: var(--g-fs-xs); }

.g-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- 2. 版心与页头 ---------- */
.page-container, .container {
  width: 100%;
  max-width: var(--g-page);
  margin: 0 auto;
  padding: var(--g-sp-5) var(--g-sp-4) var(--g-sp-6);
}
.page-head { margin-bottom: var(--g-sp-5); }
.page-title {
  font-size: var(--g-fs-xl);
  font-weight: 800;
  letter-spacing: 0.2px;
}
.page-subtitle { margin-top: 4px; font-size: var(--g-fs-base); color: var(--g-mute); }
.section-title {
  display: flex; align-items: center; gap: var(--g-sp-2);
  margin: var(--g-sp-6) 0 var(--g-sp-4);
  font-size: var(--g-fs-md); font-weight: 700; color: var(--g-ink);
}
.section-title::after {
  content: ""; flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--g-line), transparent);
}
.text-mute { color: var(--g-mute); }
.text-xs { font-size: var(--g-fs-xs); }

/* ---------- 3. 导航 ---------- */
.nav-bar {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255, 255, 255, 0.78);
  -webkit-backdrop-filter: blur(18px) saturate(1.7);
  backdrop-filter: blur(18px) saturate(1.7);
  border-bottom: 1px solid var(--g-line);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.6) inset;
}
.nav-inner {
  max-width: var(--g-page); margin: 0 auto; padding: 0 var(--g-sp-4);
  height: var(--g-nav-h);
  display: flex; align-items: center; gap: var(--g-sp-3);
}
.nav-brand {
  font-weight: 800; font-size: var(--g-fs-md); letter-spacing: 0.4px; text-decoration: none;
  white-space: nowrap;
  background: var(--g-grad-ink);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
/* 链接区外层（承载右侧渐隐提示），内层负责横滚 */
.nav-scroll {
  position: relative; display: flex; align-items: center; justify-content: flex-end;
  flex: 1 1 auto; min-width: 0; margin-left: auto;
}
.nav-links { display: flex; align-items: center; gap: 2px; overflow-x: auto; scrollbar-width: none; }
.nav-links::-webkit-scrollbar { display: none; }
.nav-link {
  position: relative;
  padding: 6px 12px; border-radius: var(--g-r-sm); text-decoration: none;
  color: var(--g-mute); font-size: var(--g-fs-base); font-weight: 500; white-space: nowrap;
  transition: background var(--g-dur) var(--g-ease), color var(--g-dur) var(--g-ease);
}
.nav-link:hover { background: var(--g-primary-soft); color: var(--g-primary); }
.nav-link.active {
  color: var(--g-primary); font-weight: 700;
  background: linear-gradient(135deg, var(--g-primary-soft), var(--g-primary-soft-2));
  box-shadow: inset 0 0 0 1px rgba(79, 70, 229, 0.16);
}
.nav-user { display: flex; align-items: center; gap: var(--g-sp-2); font-size: var(--g-fs-sm); color: var(--g-mute); }
.nav-role {
  padding: 2px 9px; border-radius: var(--g-r-pill);
  background: var(--g-surface-3); color: var(--g-mute);
  font-size: var(--g-fs-xs); font-weight: 600;
}
.btn-logout {
  padding: 5px 12px; border: 1px solid var(--g-line); border-radius: var(--g-r-sm);
  background: var(--g-surface); color: var(--g-danger);
  font-size: var(--g-fs-sm); cursor: pointer;
  transition: all var(--g-dur) var(--g-ease);
}
.btn-logout:hover { background: var(--g-danger-bg); border-color: rgba(220, 38, 38, 0.28); }
.btn-login-nav {
  padding: 7px 18px; border-radius: var(--g-r-sm); text-decoration: none;
  background: var(--g-grad); color: #fff; font-size: var(--g-fs-sm); font-weight: 600;
  box-shadow: var(--g-sh-primary);
  transition: all var(--g-dur) var(--g-ease);
}
.btn-login-nav:hover { background: var(--g-grad-hover); transform: translateY(-1px); }

/* 二级导航：宽度与版心一致（修 4-11 错位） */
.subnav {
  position: sticky; top: var(--g-nav-h); z-index: 90;
  background: rgba(248, 250, 252, 0.86);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--g-line);
}
/* 二级入口在窄屏也要能横滚，右缘给同样的渐隐提示（fx.js 挂 has-scroll） */
.subnav.has-scroll::after {
  content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 28px;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(248, 250, 252, 0), rgba(248, 250, 252, 0.95));
}
.subnav-inner {
  max-width: var(--g-page); margin: 0 auto; padding: 0 var(--g-sp-4);
  display: flex; align-items: center; gap: var(--g-sp-4);
  overflow-x: auto; scrollbar-width: none;
}
.subnav-inner::-webkit-scrollbar { display: none; }
.subnav-inner a {
  position: relative; min-height: 36px; display: inline-flex; align-items: center;
  font-size: var(--g-fs-sm); color: var(--g-mute); text-decoration: none; white-space: nowrap;
  transition: color var(--g-dur) var(--g-ease);
}
.subnav-inner a:hover { color: var(--g-primary); }
.subnav-inner a.on { color: var(--g-primary); font-weight: 700; }
.subnav-inner a.on::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  border-radius: 2px; background: var(--g-grad);
}

/* 移动端：品牌+用户一行，链接一行横滚 + 右侧渐隐提示（修 4-6/导航裁切） */
.nav-scroll { position: relative; }
.nav-scroll::after {
  content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 28px;
  pointer-events: none; opacity: 0; transition: opacity var(--g-dur) var(--g-ease);
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.92));
}
/* 桌面端窗口收窄时也亮渐隐（反馈/管理 tab 不再被无声裁掉；fx.js 挂 has-scroll） */
.nav-scroll.has-scroll::after { opacity: 1; }
@media (max-width: 860px) {
  .nav-bar { position: sticky; }
  .nav-inner {
    height: auto; min-height: var(--g-nav-h);
    flex-wrap: wrap; align-items: center;
    padding: 6px var(--g-sp-4) 0;
    row-gap: 2px;
  }
  .nav-brand { flex: 0 1 auto; font-size: var(--g-fs-base); }
  .nav-user { order: 2; margin-left: auto; }
  .nav-links, .nav-scroll {
    order: 3; width: 100%; margin-left: 0;
    justify-content: flex-start; padding-bottom: 4px;
  }
  .nav-scroll { overflow: visible; }
  .nav-scroll.has-scroll::after { opacity: 1; }
  .nav-link { flex: 0 0 auto; }
  .subnav { top: 0; position: relative; }
}

/* ---------- 4. 按钮：4 型 × 2 档 ---------- */
.btn, .btn-primary, .btn-outline, .btn-ghost, .btn-danger {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 36px; padding: 0 16px; border: 1px solid transparent; border-radius: var(--g-r-sm);
  font-size: var(--g-fs-base); font-weight: 600; line-height: 1.2;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background var(--g-dur) var(--g-ease), color var(--g-dur) var(--g-ease),
    border-color var(--g-dur) var(--g-ease), box-shadow var(--g-dur) var(--g-ease),
    transform var(--g-dur) var(--g-ease);
}
.btn-sm { height: 32px; padding: 0 12px; font-size: var(--g-fs-sm); border-radius: var(--g-r-sm); }
.btn-lg { height: 44px; padding: 0 22px; font-size: var(--g-fs-md); border-radius: var(--g-r-md); }
.btn-block { width: 100%; }

.btn, .btn-primary {
  background: var(--g-grad); color: #fff; box-shadow: var(--g-sh-primary);
}
.btn:hover, .btn-primary:hover:not(:disabled) {
  background: var(--g-grad-hover); transform: translateY(-1px);
  box-shadow: var(--g-sh-primary-hover);
}
.btn-primary:disabled, .btn:disabled {
  background: var(--g-disabled); color: #fff; box-shadow: none; transform: none; cursor: not-allowed;
}
.btn-outline {
  background: var(--g-surface); border-color: var(--g-line); color: var(--g-ink-2);
  box-shadow: none;                      /* 描边类按钮不要继承主按钮的靛蓝光晕 */
}
.btn-outline:hover {
  border-color: rgba(79, 70, 229, 0.45); color: var(--g-primary); background: rgba(79, 70, 229, 0.04);
}
.btn-ghost { background: transparent; color: var(--g-mute); box-shadow: none; }
.btn-ghost:hover { background: var(--g-primary-soft); color: var(--g-primary); }
.btn-danger { background: var(--g-surface); border-color: rgba(220, 38, 38, 0.3); color: var(--g-danger); box-shadow: none; }
.btn-danger:hover { background: var(--g-danger-bg); border-color: rgba(220, 38, 38, 0.5); }

/* ---------- 5. 表单 ---------- */
input:not([type]), input[type="text"], input[type="password"], input[type="search"], input[type="number"],
input[type="datetime-local"], input[type="date"], select, textarea,
.form-input, .search-input, .note-input, .subject-select {
  width: 100%; min-height: 38px; padding: 8px 12px;
  background: var(--g-surface); color: var(--g-ink);
  border: 1px solid var(--g-line); border-radius: var(--g-r-sm);
  font-size: var(--g-fs-base);
  transition: border-color var(--g-dur) var(--g-ease), box-shadow var(--g-dur) var(--g-ease);
}
textarea { min-height: 88px; line-height: 1.6; resize: vertical; }
input:focus, select:focus, textarea:focus,
.form-input:focus, .search-input:focus, .note-input:focus, .subject-select:focus {
  outline: none; border-color: var(--g-primary);
  box-shadow: 0 0 0 4px var(--g-primary-soft);
}
input::placeholder, textarea::placeholder { color: var(--g-mute-2); }
input[type="checkbox"], input[type="radio"] { accent-color: var(--g-primary); }
.form-label, label.form-label { display: block; margin-bottom: 6px; font-size: var(--g-fs-sm); font-weight: 600; color: var(--g-ink-2); }
.form-row { margin-bottom: var(--g-sp-3); }
/* 字段说明 / 校验提示：登录、反馈、任务等表单页共用 */
.form-hint { margin-top: 6px; font-size: var(--g-fs-xs); color: var(--g-mute); }
.form-msg {
  margin-top: var(--g-sp-2); padding: 8px 12px;
  border: 1px solid transparent; border-radius: var(--g-r-sm);
  font-size: var(--g-fs-sm); color: var(--g-ink-2); background: var(--g-surface-2);
}
.form-msg.error, .form-msg.is-error { border-color: rgba(220, 38, 38, 0.25); background: var(--g-danger-bg); color: var(--g-danger); }
.form-msg.ok, .form-msg.success { border-color: rgba(4, 120, 87, 0.25); background: var(--g-ok-bg); color: var(--g-ok); }

/* ---------- 6. 卡片家族 ---------- */
.card, .track-card, .stat-card, .task-card, .tree-card, .detail-card, .mm-card,
.hot-card, .bank-card, .search-result-card, .wrong-list-card, .s-card, .chart-card,
.q-card, .link-card, .fb-card, .quiz-panel, .filter-card, .preview-card {
  background: var(--g-surface);
  border: 1px solid var(--g-line);
  border-radius: var(--g-r-lg);
  box-shadow: var(--g-sh-sm);
}
.card { padding: var(--g-sp-5); text-decoration: none; display: block; }
/* 悬停抬升只给真正可点的元素（修 4-13：装饰行不再乱抖） */
a.card:hover, a.track-card:hover, a.stat-card-link:hover,
.card[role="button"]:hover, .card.is-clickable:hover {
  transform: translateY(-3px); box-shadow: var(--g-sh-lg); border-color: rgba(79, 70, 229, 0.28);
}
a.card, a.track-card { transition: transform var(--g-dur-2) var(--g-ease), box-shadow var(--g-dur-2) var(--g-ease), border-color var(--g-dur-2) var(--g-ease); }
.card-title { font-size: var(--g-fs-md); font-weight: 700; color: var(--g-ink); }
.card-desc { font-size: var(--g-fs-sm); color: var(--g-mute); }
.card-icon {
  width: 40px; height: 40px; border-radius: var(--g-r-md); flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center; font-size: 1.25rem;
  background: var(--g-surface-3);
}
.card-icon.blue { background: #dbeafe; }
.card-icon.green { background: #dcfce7; }
.card-icon.purple { background: #f3e8ff; }
.card-icon.orange { background: #ffedd5; }
.card-icon.teal { background: #ccfbf1; }
.card-icon.red { background: #fee2e2; }

/* ---------- 7. 徽标 / chip ---------- */
.chip, .tag-chip, .node-tag, .q-type, .q-subject, .track-badge, .nav-role, .cat-tag, .tag-opt {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 10px; border-radius: var(--g-r-pill);
  background: var(--g-surface-3); color: var(--g-ink-2);
  font-size: var(--g-fs-xs); font-weight: 600; line-height: 1.6;
}
.tag-opt { cursor: pointer; border: 1px solid transparent; }
.tag-opt:hover { background: var(--g-primary-soft); color: var(--g-primary); }
.tag-opt.on {
  background: linear-gradient(135deg, var(--g-primary-soft), var(--g-primary-soft-2));
  color: var(--g-primary);
  box-shadow: inset 0 0 0 1px rgba(79, 70, 229, 0.16);
}
/* 题目信息徽标要有语义区分：题型=中性，学科=信息蓝（否则一枚同色 chip 分不清） */
.q-type { background: var(--g-surface-3); color: var(--g-mute); }
.q-subject { background: var(--g-exams-bg); color: var(--g-exams); }
.tag-chip, .node-tag { background: #f3e8ff; color: #6b21a8; cursor: pointer; }
.tag-chip:hover, .node-tag:hover { box-shadow: 0 4px 10px -4px rgba(107, 33, 168, 0.4); }
.track-badge { background: linear-gradient(135deg, var(--g-primary-soft), var(--g-primary-soft-2)); color: var(--g-primary); box-shadow: inset 0 0 0 1px rgba(79, 70, 229, 0.16); }

/* ---------- 7b. SVG 图标系统（icons.js 把 UI 里的装饰 emoji 替换为线性图标；
   24 网格 / 1.5 描边 / currentColor，随文字颜色与字号缩放。
   正文容器（.md-body/.chat-msg/.detail-content 等）不替换，用户内容不受影响） ---------- */
.g-ic-wrap { display: inline-flex; align-items: center; justify-content: center; }
.g-ic { width: 1.15em; height: 1.15em; flex: 0 0 auto; vertical-align: -0.18em; }
.card-icon .g-ic, .quick-icon .g-ic, .g-empty-icon .g-ic { width: 1.4em; height: 1.4em; }

/* 标签页式横滚（admin / practice / stats / library 等页签行）：窄屏不逐字断行。
   注意：`.tabs` 自身就是滚动容器，不能用绝对定位的 ::after 做渐隐（会随内容滚走），
   改用 mask 直接淡出右缘 —— mask 作用于元素盒而非滚动内容，滚动时位置稳定。 */
.tabs { position: relative; }
.tabs.has-scroll {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent 100%);
  mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent 100%);
}

/* ---------- 7c. 统计卡 anatomy（全站统一：数字 2xl 在上、标签 xs 在下；
   各页原有类名 .stat-card .v/.l、.kb-num/.kb-lab、.ov-item 全部归一到同一形态，
   语义强调色只允许出现在数字上） ---------- */
.stat-card .v, .kb-num, .ov-item .ov-value {
  font-size: var(--g-fs-2xl); font-weight: 800; line-height: 1.1;
  color: var(--g-ink); font-variant-numeric: tabular-nums;
}
.stat-card .l, .kb-lab, .ov-item .ov-label {
  font-size: var(--g-fs-xs); color: var(--g-mute); font-weight: 600;
}

/* ---------- 7d. 原生 select 收编：去掉系统箭头，统一成与 input 一致的观感 ---------- */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 15px;
}
select::-ms-expand { display: none; }

/* ---------- 8. 表格（窄屏容器内横滚，修 4-4） ---------- */
.g-table-wrap { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.data-table { width: 100%; min-width: 640px; border-collapse: collapse; font-size: var(--g-fs-sm); }
table.data-table th, table.data-table td { padding: 9px 10px; text-align: left; border-bottom: 1px solid var(--g-line-2); white-space: nowrap; }
table.data-table th { color: var(--g-mute); font-weight: 600; background: var(--g-surface-2); }

/* ---------- 9. 空态 / 骨架 / 错误（统一三件套，修 4-17/4-19/4-21） ---------- */
.g-empty, .empty-state, .empty-hint {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; min-height: 132px; padding: var(--g-sp-5) var(--g-sp-4);
  text-align: center; color: var(--g-mute);
}
.g-empty-icon { font-size: 1.9rem; line-height: 1; opacity: 0.9; }
.g-empty-title { font-size: var(--g-fs-base); font-weight: 600; color: var(--g-ink-2); }
.g-empty-desc { font-size: var(--g-fs-sm); color: var(--g-mute); max-width: 42ch; }
.g-error {
  border: 1px solid rgba(220, 38, 38, 0.25);
  background: var(--g-danger-bg); color: var(--g-danger);
}
/* 重试按钮：stats / links / exam / feedback 都在用，收到公共层避免各页各写一份 */
.btn-retry {
  display: inline-flex; align-items: center; justify-content: center;
  height: 32px; padding: 0 14px; margin-top: 4px;
  border: 1px solid rgba(79, 70, 229, 0.35); border-radius: var(--g-r-sm);
  background: var(--g-surface); color: var(--g-primary);
  font-size: var(--g-fs-sm); font-weight: 600; cursor: pointer;
  transition: background var(--g-dur) var(--g-ease), border-color var(--g-dur) var(--g-ease);
}
.btn-retry:hover { background: var(--g-primary-soft); border-color: var(--g-primary); }

.g-skeleton {
  position: relative; overflow: hidden; border-radius: var(--g-r-sm);
  background: var(--g-surface-3); min-height: 14px;
}
.g-skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.65), transparent);
  transform: translateX(-100%); animation: g-shimmer 1.4s infinite;
}
.g-skeleton-card { height: 96px; border-radius: var(--g-r-lg); }
@keyframes g-shimmer { to { transform: translateX(100%); } }

/* ---------- 10. toast / modal ---------- */
.toast {
  position: fixed; left: 50%; bottom: 24px; z-index: 999;
  padding: 10px 22px; max-width: min(90vw, 520px);
  transform: translateX(-50%) translateY(8px);
  background: rgba(15, 23, 42, 0.94); color: #fff;
  border-radius: var(--g-r-md); font-size: var(--g-fs-sm); text-align: center;
  box-shadow: var(--g-sh-lg);
  opacity: 0; pointer-events: none;
  transition: opacity var(--g-dur-2) var(--g-ease), transform var(--g-dur-2) var(--g-ease);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.error { border-left: 3px solid var(--g-danger-2); }
.toast.success { border-left: 3px solid var(--g-ok-2); }

.modal-overlay {
  position: fixed; inset: 0; z-index: 200;
  display: none; align-items: center; justify-content: center;
  padding: var(--g-sp-4);
  background: rgba(15, 23, 42, 0.42);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.modal-overlay.show, .modal-overlay.open { display: flex; }
.modal-box {
  width: 100%; max-width: 560px; max-height: 86vh; overflow-y: auto;
  background: var(--g-surface); border: 1px solid var(--g-line);
  border-radius: var(--g-r-xl); box-shadow: var(--g-sh-lg);
  padding: var(--g-sp-5);
}
/* 图片放大弹窗（答卷照片等）：容器只负责遮罩，尺寸规则收在这里 */
.modal-box img, .modal-img {
  max-width: 92vw; max-height: 92vh; width: auto; height: auto;
  object-fit: contain; border-radius: var(--g-r-md); margin: 0 auto;
}
/* 弹窗标题规格（反馈/组卷/任务等弹窗共用，避免各页各写一份 h3） */
.modal-box h3, .modal-box h2 {
  font-size: var(--g-fs-md); font-weight: 700; color: var(--g-ink);
  margin-bottom: var(--g-sp-3);
}
/* 统一确认弹窗（fx.js 的 gConfirm：替代原生 confirm，样式全站一致） */
.g-confirm-box { max-width: 400px; }
.g-confirm-box h3 {
  font-size: var(--g-fs-base); font-weight: 600; line-height: 1.7;
  margin-bottom: var(--g-sp-4); white-space: pre-line;   /* 支持多行文案（如 admin 清空密码） */
}
.g-confirm-actions { display: flex; justify-content: flex-end; gap: var(--g-sp-2); }

/* ---------- 11. 页脚 ---------- */
.footer {
  margin-top: auto; padding: var(--g-sp-5) var(--g-sp-4);
  border-top: 1px solid var(--g-line-2);
  text-align: center; color: var(--g-mute); font-size: var(--g-fs-xs);
}
.footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--g-sp-4); margin-bottom: 6px; }
.footer-links a { color: var(--g-mute); text-decoration: none; }
.footer-links a:hover { color: var(--g-primary); }
.footer .beian { margin-top: 4px; }
.footer .beian a { color: var(--g-mute); text-decoration: none; }
.footer .beian a:hover { color: var(--g-primary); }

/* ---------- 12. 上传区 ---------- */
.upload-zone {
  border: 2px dashed var(--g-line); border-radius: var(--g-r-lg);
  padding: var(--g-sp-6) var(--g-sp-4); text-align: center; color: var(--g-mute);
  cursor: pointer; transition: all var(--g-dur-2) var(--g-ease);
}
.upload-zone:hover, .upload-zone.dragover {
  border-color: var(--g-primary); background: rgba(79, 70, 229, 0.04);
  box-shadow: 0 0 0 4px var(--g-primary-soft);
}

/* ---------- 13. 进入动效（可关） ---------- */
.g-rise { animation: g-rise var(--g-dur-2) var(--g-ease) both; animation-delay: calc(var(--i, 0) * 60ms); }
@keyframes g-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ==================================================================
   FX 分级：[data-fx="0"] 纯净 · ["1"] 静态质感（默认）· ["2"] 微动态
   ================================================================== */

/* --- 地理底纹：经纬网（CSS 渐变绘制，无外部请求、透明度可调） ---
   主网格 --g-grid-cell（粗线）每格再分 4 份为 --g-grid-sub（细线），
   强度三档由 html[data-grid] 切换，默认 mid（用户 2026-09-25 反馈"可以更明显"）。 */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right, var(--g-grid-major) 1px, transparent 1px),
    linear-gradient(to bottom, var(--g-grid-major) 1px, transparent 1px),
    linear-gradient(to right, var(--g-grid-minor) 1px, transparent 1px),
    linear-gradient(to bottom, var(--g-grid-minor) 1px, transparent 1px);
  background-size:
    var(--g-grid-cell) var(--g-grid-cell), var(--g-grid-cell) var(--g-grid-cell),
    var(--g-grid-sub) var(--g-grid-sub), var(--g-grid-sub) var(--g-grid-sub);
}
html[data-grid="soft"] { --g-grid-major: rgba(15, 23, 42, 0.06); --g-grid-minor: rgba(15, 23, 42, 0.025); }
html[data-grid="mid"], html:not([data-grid]) {
  --g-grid-major: rgba(15, 23, 42, 0.105); --g-grid-minor: rgba(15, 23, 42, 0.045);
}
html[data-grid="strong"] { --g-grid-major: rgba(15, 23, 42, 0.15); --g-grid-minor: rgba(15, 23, 42, 0.065); }
/* --- 极光渐变：三团柔光（默认静止） --- */
body::after {
  content: ""; position: fixed; inset: -12% -8%; z-index: -2; pointer-events: none;
  background:
    radial-gradient(46rem 30rem at 14% -6%, rgba(99, 102, 241, 0.16), transparent 62%),
    radial-gradient(42rem 28rem at 88% -8%, rgba(14, 165, 233, 0.14), transparent 62%),
    radial-gradient(34rem 26rem at 52% 4%, rgba(168, 85, 247, 0.08), transparent 66%);
}

html[data-fx="0"] body::before,
html[data-fx="0"] body::after { display: none; }
html[data-fx="0"] { --g-sh-sm: none; --g-sh-md: 0 1px 3px rgba(16, 24, 40, 0.08); }

/* fx=2：极光缓慢漂移 + 卡片聚光（光标位置由 fx.js 写入 --mx/--my） */
html[data-fx="2"] body::after { animation: g-aurora 64s var(--g-ease) infinite alternate; }
html[data-fx="2"] .g-rise { animation-duration: 0.4s; }
html[data-fx="2"] a.card, html[data-fx="2"] a.track-card { position: relative; overflow: hidden; }
html[data-fx="2"] a.card::after, html[data-fx="2"] a.track-card::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  transition: opacity var(--g-dur-2) var(--g-ease);
  background: radial-gradient(180px circle at var(--mx, 50%) var(--my, 0%), rgba(79, 70, 229, 0.10), transparent 70%);
}
html[data-fx="2"] a.card:hover::after, html[data-fx="2"] a.track-card:hover::after { opacity: 1; }
@keyframes g-aurora {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(1.6%, 1.2%, 0) scale(1.05); }
  100% { transform: translate3d(-1.4%, -1%, 0) scale(1.02); }
}

/* 尊重系统偏好：动效一律关闭 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- 14. 最窄屏收口 ----------
   必须放在所有组件定义之后：同优先级(0,1,0)时"后出现的规则"胜，
   本段要覆盖第 7 段的 .nav-role（徽标家族里的 display:inline-flex）。 */
@media (max-width: 480px) {
  .nav-inner { padding: 4px var(--g-sp-3) 0; gap: var(--g-sp-2); }
  .nav-brand { font-size: var(--g-fs-sm); }
  .nav-user { gap: 6px; font-size: var(--g-fs-xs); }
  .nav-role { display: none; }
  .btn-logout { padding: 4px 10px; font-size: var(--g-fs-xs); }
}

/* ---------- 15. 并档第二批（原各页自建，2026-09-26 收编，见《前端重构阶段总结》待办#1） ----------
   页签结构基线：admin=文件夹式皮肤、library=分段式皮肤，皮肤差异留在各页 pages/<page>.css；
   .btn-xs/.btn-warn/快捷卡/文件行/文献行/行内加载为通用组件，全站可复用。 */
.tabs { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab-btn {
  flex: 0 0 auto; min-height: 34px; white-space: nowrap;
  padding: 6px var(--g-sp-3); border: none; border-radius: var(--g-r-sm);
  background: none; color: var(--g-mute);
  font-size: var(--g-fs-sm); font-weight: 600; cursor: pointer;
  transition: background var(--g-dur) var(--g-ease), color var(--g-dur) var(--g-ease);
}
.tab-btn:hover { background: var(--g-surface-3); color: var(--g-ink-2); }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* 行内紧凑按钮（表格"升/降/停用/删"列）与警示档；box-shadow 复位原因同 .btn-outline */
.btn-xs { height: 32px; padding: 0 10px; border-radius: var(--g-r-sm); font-size: var(--g-fs-xs); }
.btn-warn { background: var(--g-warn-bg); border-color: currentColor; color: var(--g-warn); box-shadow: none; }
.btn-warn:hover { background: var(--g-warn); color: var(--g-surface); }

/* 快捷动作卡（exams 门户四入口等） */
.quick-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(212px, 1fr)); gap: var(--g-sp-3); }
a.quick-card {
  display: flex; align-items: center; gap: var(--g-sp-3);
  padding: var(--g-sp-3) var(--g-sp-4);
  background: var(--g-surface); border: 1px solid var(--g-line);
  border-radius: var(--g-r-md); box-shadow: var(--g-sh-sm);
  text-decoration: none;
  transition: transform var(--g-dur-2) var(--g-ease), box-shadow var(--g-dur-2) var(--g-ease),
    border-color var(--g-dur-2) var(--g-ease);
}
a.quick-card:hover { transform: translateY(-2px); box-shadow: var(--g-sh-md); }
.quick-icon {
  width: 40px; height: 40px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.3rem; line-height: 1;
  border-radius: var(--g-r-md); background: var(--g-wash-4);
}
a.quick-card .t { font-size: var(--g-fs-base); font-weight: 700; color: var(--g-ink-2); }
a.quick-card .d { font-size: var(--g-fs-xs); color: var(--g-mute); }

/* 文件行（真题库附件等：名称截断 + 大小 + 下载链接） */
.paper-file {
  display: flex; align-items: center; gap: var(--g-sp-2);
  padding: var(--g-sp-2) var(--g-sp-3); margin-bottom: 6px;
  background: var(--g-surface); border: 1px solid var(--g-line);
  border-radius: var(--g-r-sm); font-size: var(--g-fs-xs);
  transition: border-color var(--g-dur) var(--g-ease), background var(--g-dur) var(--g-ease);
}
.paper-file:hover { border-color: var(--g-primary); background: var(--g-primary-soft); }
.paper-file .name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--g-ink-2); }
.paper-file .size { flex: 0 0 auto; color: var(--g-mute); font-variant-numeric: tabular-nums; }
.paper-file a { flex: 0 0 auto; color: var(--g-primary); font-weight: 600; text-decoration: none; }
.paper-file a:hover { text-decoration: underline; }

/* 可点文献行（library）：左轨 hover 变主色，只动 border-left-color（修 4-13 同款纪律） */
.lit-item {
  margin-bottom: var(--g-sp-3); padding: var(--g-sp-4);
  background: var(--g-surface);
  border: 1px solid var(--g-line);
  border-left: 3px solid transparent;
  border-radius: var(--g-r-lg);
  box-shadow: var(--g-sh-sm);
  cursor: pointer;
  overflow-wrap: anywhere;
  transition: box-shadow var(--g-dur-2) var(--g-ease), border-color var(--g-dur-2) var(--g-ease);
}
.lit-item:hover { border-left-color: var(--g-primary); box-shadow: var(--g-sh-md); }

/* 行内加载占位（表格行/卡片文本位）：轻脉冲，reduced-motion 下静止 */
.g-loading { padding: var(--g-sp-4); text-align: center; color: var(--g-mute); font-size: var(--g-fs-sm); animation: g-pulse 1.4s var(--g-ease) infinite; }
@keyframes g-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

/* ---------- 打印（组卷导出/答卷打印不该带底纹） ---------- */
@media print {
  body::before, body::after { display: none; }
  .nav-bar, .subnav, .footer { display: none; }
}
