/* ===========================================================
   行知书法云 · V1「练字可视化」原型样式
   配色：米白底 #F7F5F0 / 深灰字 #333333 / 暖橙强调 #E8A33D
   版式：单列窄容器（560px），移动端友好，桌面端居中留白
   =========================================================== */

/* ---------- 1. 设计变量 ---------- */
:root {
  --bg: #F7F5F0;              /* 页面底色：米白 */
  --card: #FFFFFF;            /* 卡片底 */

  --ink: #333333;             /* 主文字：深灰 */
  --ink-2: #6E6963;           /* 次要文字 */
  --ink-3: #A5A099;           /* 弱提示 */

  --line: #E6E0D5;            /* 边框 */
  --line-soft: #EFEAE1;       /* 更浅的分割线 */

  --orange: #E8A33D;          /* 强调色：暖橙 */
  --orange-deep: #D18F22;     /* 按下 / 深一档 */
  --orange-soft: #FBF1E0;     /* 浅橙底 */
  --orange-soft-2: #F4E7CE;   /* 浅橙底 · 悬停 */
  --orange-soft-3: #EDDCB6;   /* 浅橙底 · 按下 */

  --radius-sm: 10px;
  --radius: 16px;
  --radius-lg: 22px;

  --shadow: 0 2px 10px rgba(51, 51, 51, .05);
  --shadow-orange: 0 8px 22px rgba(232, 163, 61, .26);

  --app-width: 560px;
  --topbar-h: 56px;

  --font: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
          "Source Han Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
  /* 单个汉字用楷体，和作业图的田字格呼应 */
  --font-kai: "Kaiti SC", "STKaiti", "KaiTi", "PingFang SC", sans-serif;

  /* 图表：掌握 = 暖橙，要加强 = 暖灰
     这两个值是跑 dataviz 校验器定下来的：
     常视觉 ΔE 19.5、色盲 ΔE 16.5（protan），都过了 15 / 8 的线。
     橙色对底色对比度 2.1:1 不到 3:1，所以每根条必须带文字标签，
     不能只靠颜色区分——见 .row__label。 */
  --chart-good: #E8A33D;
  --chart-warn: #8A8378;
  --chart-track: #EFEAE1;

  /* 进步 / 退步（班级页每行右侧那个箭头）。
     红绿这一对儿色觉障碍的人本来就分不开，所以方向必须由
     ↑ → ↓ 和正负号自己带，颜色只是帮忙——见 .roster__delta。
     取了偏灰的暖绿暖红，和米白暖橙这套底子放一起不打架。
     白卡上的对比度：绿 5.23:1、红 5.45:1，过正文 4.5:1 的线。 */
  --up: #2F7A4F;
  --down: #B4453A;
  --down-soft: #FAEDEA;       /* 退步色的浅底，⚠ 徽标用（红色在它上面 4.77:1） */
}

/* ---------- 2. 基础 ---------- */
* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, figure { margin: 0; }

img { max-width: 100%; }

/* 本原型靠 hidden 属性控制显隐，统一压过组件自身的 display */
[hidden] { display: none !important; }

/* ---------- 3. 页面骨架 ---------- */
.app {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--app-width);
  min-height: 100vh;
  margin: 0 auto;
}

/* 首页这类无顶栏的页面，整屏居中 */
.app--center { justify-content: center; max-width: 760px; }

/* 框选评级页要左右分栏，比手机版容器宽 */
.app--wide { max-width: 1000px; }

/* 机构后台是老师坐在电脑前看的，比手机上那几页略宽，
   但仍保持单列 + 卡片，和前台不是一套版式 */
.app--admin { max-width: 720px; }

.main {
  flex: 1;
  padding: 22px 20px 34px;
}

/* ---------- 4. 顶栏 ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  height: var(--topbar-h);
  padding: 0 20px;
  background: rgba(247, 245, 240, .88);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line-soft);
}

.topbar__back,
.topbar__spacer {
  width: 36px;
  height: 36px;
  flex: none;
}

.topbar__back {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: -8px;
  border-radius: 50%;
  color: var(--ink);
  font-size: 19px;
  line-height: 1;
  text-decoration: none;
  transition: background .18s ease;
}

.topbar__back:hover { background: rgba(51, 51, 51, .06); }
.topbar__back:active { background: rgba(51, 51, 51, .1); }
.topbar__spacer { margin-right: -8px; }

.topbar__title {
  flex: 1;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .04em;
  text-align: center;
}

/* 机构后台的顶栏是「品牌 + 入口名」而不是页面标题，
   所以靠左跟在返回箭头后面，字比标题小一档 */
.topbar__brand {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  margin-left: 2px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- 5. 品牌标识 ---------- */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--ink);
}

/* ---------- 6. 按钮 ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 30px;
  border: 0;
  border-radius: 999px;
  background: var(--orange);
  color: #fff;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: .06em;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .18s ease, transform .18s ease, box-shadow .18s ease;
}

.btn:hover { background: var(--orange-deep); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: 3px; }

.btn--lg {
  padding: 17px 46px;
  font-size: 17px;
  box-shadow: var(--shadow-orange);
}

.btn--block {
  display: flex;
  width: 100%;
}

.btn--sm {
  padding: 9px 18px;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: .04em;
}

.btn--ghost {
  background: transparent;
  color: var(--ink-2);
  border: 1px solid var(--line);
  font-weight: 500;
  box-shadow: none;
}

.btn--ghost:hover { background: rgba(51, 51, 51, .04); color: var(--ink); }

/* 未满足条件时（如一个字都没选）压灰并挡住点击 */
.btn.is-disabled {
  background: #DCD6CB;
  color: rgba(255, 255, 255, .92);
  box-shadow: none;
  pointer-events: none;
}

/* ---------- 7. 上传虚线框 ---------- */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 300px;
  padding: 40px 24px;
  background: var(--card);
  border: 2px dashed var(--line);
  border-radius: var(--radius-lg);
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .2s ease, background .2s ease, transform .2s ease;
}

.dropzone:hover,
.dropzone:focus-visible {
  border-color: var(--orange);
  background: var(--orange-soft);
  outline: none;
}

.dropzone:active { transform: scale(.99); }

.dropzone__plus {
  color: var(--orange);
  font-size: 36px;
  font-weight: 300;
  line-height: 1;
}

.dropzone__title {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .04em;
}

.dropzone__hint {
  color: var(--ink-3);
  font-size: 13px;
}

/* ---------- 8. 作业图预览 ---------- */
.preview {
  padding: 12px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.preview img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

.tip {
  margin-top: 12px;
  color: var(--ink-3);
  font-size: 13px;
  text-align: center;
}

/* ---------- 9. 按钮组 ---------- */
.actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 26px;
}

/* 两个并排（报告页底部） */
.actions--row { flex-direction: row; }
.actions--row .btn { flex: 1; }

/* 主按钮上方的一句说明（机构后台「查看全部 N 个孩子」） */
.actions__hint {
  color: var(--ink-3);
  font-size: 13px;
  letter-spacing: .04em;
  text-align: center;
}

/* ---------- 9.5 挑选字 ---------- */
.select-tip {
  margin-bottom: 16px;
  color: var(--ink-2);
  font-size: 14px;
  letter-spacing: .02em;
  text-align: center;
}

.select-tip b {
  color: var(--orange);
  font-weight: 600;
}

/* 作业图 + 可点字框的叠放容器 */
.work { position: relative; }

.work__img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

/* 覆盖层与图等大，字框按百分比定位，所以缩放窗口不会错位 */
.work__overlay {
  position: absolute;
  inset: 0;
}

.char {
  position: absolute;
  padding: 0;
  background: transparent;
  border: 2px solid transparent;
  border-radius: 9px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .16s ease, background .16s ease;
}

.char:hover,
.char:focus-visible {
  border-color: rgba(232, 163, 61, .55);
  background: rgba(232, 163, 61, .1);
  outline: none;
}

.char.is-selected {
  border-color: var(--orange);
  background: rgba(232, 163, 61, .16);
}

.char:focus-visible { border-color: var(--orange); }

/* 右上角的橙色勾 */
.char__check {
  position: absolute;
  top: -10px;
  right: -10px;
  display: none;
  width: 23px;
  height: 23px;
  border-radius: 50%;
  background: var(--orange);
  color: #fff;
  font-size: 13px;
  line-height: 23px;
  text-align: center;
  box-shadow: 0 1px 5px rgba(51, 51, 51, .2);
}

.char.is-selected .char__check {
  display: block;
  animation: pop .2s ease both;
}

@keyframes pop {
  from { opacity: 0; transform: scale(.4); }
  to   { opacity: 1; transform: scale(1); }
}

/* ---------- 9.6 底部吸底条 ---------- */
.bottombar {
  position: sticky;
  bottom: 0;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  background: rgba(247, 245, 240, .94);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-top: 1px solid var(--line-soft);
}

.bottombar__count {
  color: var(--ink-2);
  font-size: 14px;
  white-space: nowrap;
}

.bottombar__count b {
  margin: 0 2px;
  color: var(--orange);
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* 一个字都没选时，数字转灰 */
.bottombar__count.is-empty b { color: var(--ink-3); }

/* ---------- 9.7 报告页 ---------- */
.report {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.card {
  padding: 20px 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.card__label {
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .12em;
}

/* 卡片标题行：左边标题、右边一句补充说明（如「对比上周」）。
   说明只是补充，所以不加大字号、不加粗，靠位置和标题分开。 */
.card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.card__hint {
  flex: none;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
}

/* 总结句：数字放大，颜色仍是墨色——图表才负责带颜色 */
.summary__text {
  margin-top: 12px;
  font-size: 17px;
  line-height: 1.9;
  letter-spacing: .01em;
}

/* 大号独立数字用比例数字，不用等宽数字（等宽在大字号下发松） */
.summary__text b {
  font-size: 25px;
  font-weight: 700;
  line-height: 1;
}

/* 窄屏换行时不要把「几个要加强」拦腰拆开 */
.nb { white-space: nowrap; }

/* 横条图 */
.chart {
  display: flex;
  flex-direction: column;
  gap: 11px;
  margin: 18px 0 4px;
  padding: 0;
  list-style: none;
}

.row {
  display: grid;
  grid-template-columns: 1.6em 1fr 3.4em;
  align-items: center;
  gap: 12px;
}

.row__char {
  font-family: var(--font-kai);
  font-size: 17px;
  line-height: 1;
  text-align: center;
}

/* 轨道：和填充条同为「基线端方、数据端圆」，几何才一致 */
.bar {
  display: block;
  height: 10px;
  background: var(--chart-track);
  border-radius: 0 5px 5px 0;
}

.bar__fill {
  display: block;
  height: 100%;
  min-width: 6px;
  border-radius: 0 5px 5px 0;
}

.bar__fill--good { background: var(--chart-good); }
.bar__fill--warn { background: var(--chart-warn); }

.row__label {
  color: var(--ink-2);
  font-size: 12px;
  letter-spacing: .04em;
  text-align: right;
  white-space: nowrap;
}

/* 本次报告：每个字一块（字名 · 总体评级 · 样本数，下面一排样本缩略图） */
.wordline {
  padding: 12px 0;
}

.wordline + .wordline { border-top: 1px solid var(--line-soft); }
.wordline:first-child { padding-top: 2px; }

.wordline__head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.wordline__name {
  flex: none;
  min-width: 1.5em;
  color: var(--ink);
  font-family: var(--font-kai);
  font-size: 20px;
  font-weight: 700;
}

.wordline__grade {
  flex: none;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--line-soft);
  color: var(--ink-2);
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
}

/* 评级配色的三档规则在文件靠后（紧接 .sample__rating），
   因为要同时压过 .wordline__grade 和 .sample__rating 两个基础类，
   同权重下靠后的才生效。 */

.wordline__count {
  margin-left: auto;
  color: var(--ink-3);
  font-size: 13px;
  white-space: nowrap;
}

.wordline__thumbs {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

/* 缩略图：裁哪块由 js 里共用的 paintThumb() 决定，这里只管尺寸 */
.wordline__thumb {
  width: 60px;
  height: 60px;
  border: 1px solid var(--line-soft);   /* 极淡，只是给浅色区域一个边界 */
  border-radius: 8px;
  background-color: #EDE7DC;
  background-repeat: no-repeat;
}

/* 点评段落 */
.note {
  margin-top: 12px;
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.95;
}

/* ---------- 9.75 历史记录列表 ---------- */
.records {
  display: block;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.record {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease;
}

/* 行之间用发丝线分隔，最后一行不加 */
.record + .record { border-top: 1px solid var(--line-soft); }

.record:hover { background: var(--orange-soft); }
.record:active { background: var(--orange-soft-2); }
.record:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: -2px; }

.record__text {
  display: block;
  flex: 1;
  min-width: 0;
}

.record__title {
  display: block;
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .02em;
}

.record__sub {
  display: block;
  margin-top: 3px;
  color: var(--ink-2);
  font-size: 13px;
}

/* 日期是一列要对齐的数字，用等宽数字才不参差 */
.record__sub time { font-variant-numeric: tabular-nums; }

.record__arrow {
  flex: none;
  color: var(--ink-3);
  font-size: 20px;
  line-height: 1;
}

/* ---------- 9.76 框选评级页（select.html） ---------- */
.work-main {
  flex: 1;
  display: grid;
  grid-template-columns: 2fr 1fr;   /* 左边照片约占 2/3 */
  gap: 20px;
  align-items: start;
  padding: 20px;
}

.stage {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}

/* 照片容器：框和评级气泡都相对它定位 */
.photo {
  position: relative;
  width: 100%;
  background: #EDE7DC;
  border-radius: var(--radius);
  overflow: hidden;
  touch-action: none;               /* 触屏拖动时不要跟着滚页面 */
  user-select: none;
  -webkit-user-select: none;
}

.photo__img {
  display: block;
  width: 100%;
  height: auto;
}

/* 框是点按钮直接出现的，不再在照片上拖拽画框，所以照片本身没有特殊光标 */

/* 照片还没放进 images/ 时的占位，别让页面看起来是坏的 */
.photo__missing { display: none; }

.photo.is-missing { min-height: 320px; }
.photo.is-missing .photo__img { display: none; }

.photo.is-missing .photo__missing {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.9;
  text-align: center;
}

.photo.is-missing .photo__missing span {
  color: var(--ink-3);
  font-size: 12px;
}

/* 拖出来的框：尺寸由 main.js 顶部的 BOX_SIZE 决定（内联样式会覆盖这里的值，
   这里只作为 JS 没跑起来时的兜底），只能拖位置、不能缩放 */
.pick {
  position: absolute;
  width: 40px;
  height: 40px;
  border: 2px solid var(--orange);
  border-radius: 4px;
  background: rgba(232, 163, 61, .16);
  /* 框本身要能接指针事件——拖动就是按住它拖；光标提示可拖 */
  cursor: grab;
  touch-action: none;
}

.pick:active { cursor: grabbing; }

/* 松手后出现的评级气泡 */
.rating {
  position: absolute;
  z-index: 3;
  display: flex;
  gap: 2px;
  padding: 4px;
  background: #fff;
  border-radius: 999px;
  box-shadow: 0 4px 16px rgba(51, 51, 51, .2);
}

.rating__btn {
  padding: 6px 11px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease;
}

.rating__btn:hover { background: var(--orange-soft); }
.rating__btn:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: -2px; }

/* 右侧栏 */
.panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.panel__title {
  color: var(--ink);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: .02em;
}

/* ---------- 按字分组的列表 ---------- */
.words {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.word {
  padding: 12px 12px 10px;
  background: #FCFAF6;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  transition: border-color .16s ease, background .16s ease;
}

/* 正在给这个字框选时，整块高亮 */
.word.is-active {
  border-color: var(--orange);
  background: var(--orange-soft);
}

.word__head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.word__name {
  flex: 1;
  min-width: 0;
  color: var(--ink);
  font-family: var(--font-kai);
  font-size: 20px;
  font-weight: 700;
}

/* 字名前的三角标记 */
.word__name::before {
  content: "▸";
  margin-right: 6px;
  color: var(--orange);
  font-family: var(--font);
  font-size: 12px;
  font-weight: 400;
  vertical-align: 3px;
}

.word__add {
  flex: none;
  padding: 4px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink-2);
  font-family: inherit;
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}

.word__add:hover:not(:disabled) {
  border-color: var(--orange);
  background: var(--orange-soft);
  color: var(--ink);
}

.word__add:disabled {
  opacity: .4;
  cursor: not-allowed;
}

/* 高亮块里的按钮变成实心橙，兼作「取消」 */
.word.is-active .word__add {
  border-color: var(--orange);
  background: var(--orange);
  color: #fff;
}

.word__count {
  margin-top: 8px;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .04em;
}

.word .samples { margin-top: 8px; gap: 6px; }

.word__empty {
  margin-top: 8px;
  color: var(--ink-3);
  font-size: 13px;
}

.samples {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sample {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* 缩略图：用 background-position 从原图裁出框选的那块 */
.sample__thumb {
  flex: none;
  width: 48px;
  height: 48px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background-color: #EDE7DC;
  background-repeat: no-repeat;
}

.sample__rating {
  flex: none;
  margin-right: auto;      /* 标签贴着文字，把 × 顶到最右 */
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--line-soft);
  color: var(--ink-2);
  font-size: 12px;
  letter-spacing: .04em;
  white-space: nowrap;
}

/* 评级配色：report 的「各字评级」和 select 的样本标签共用同一套，
   两个类名并列写，颜色值只有这一处。
   ⚠ 必须放在 .wordline__grade 和 .sample__rating 两个基础类之后——
     同权重（都是单类选择器），靠后的才赢；放在前面会被基础样式盖掉。
   对比度实测（WCAG 正文要求 4.5:1）：
     优秀   #E8A33D + #333   5.86:1  ✓
     合格   #EEEEEE + #666   4.95:1  ✓
     需努力 #666666 + 白字   5.74:1  ✓ */
.wordline__grade--good,
.sample__rating--good { background: #E8A33D; color: #333333; }

.wordline__grade--pass,
.sample__rating--pass { background: #EEEEEE; color: #666666; }

.wordline__grade--warn,
.sample__rating--warn { background: #666666; color: #fff; }

.sample__del {
  flex: none;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-3);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  transition: background .16s ease, color .16s ease;
}

.sample__del:hover {
  background: rgba(51, 51, 51, .06);
  color: var(--ink);
}

/* ---------- 9.77 机构后台（admin.html） ---------- */

/* 三个数字的时间口径，标在整排上方 */
.kpis__range {
  margin-bottom: 8px;
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .06em;
}

/* 三个概况数字：始终一行三个（手机上也一行，靠缩字号而不是折行来适配） */
.kpis {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}

.kpi {
  padding: 16px 10px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-align: center;
}

.kpi__label {
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .06em;
  line-height: 1.5;
}

/* 大号独立数字用比例数字，不用等宽（等宽在大字号下发松）；
   单位小一号、浅一档跟在数字后面，数字才是主角。
   数字本身仍是墨色——颜色留给下面的横条带。 */
.kpi__value {
  margin-top: 6px;
  font-size: clamp(22px, 6.5vw, 30px);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -.01em;
}

.kpi__unit {
  margin-left: 1px;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
}

/* 进步榜的第一列放名字，比报告的「字」列宽一些 */
.chart--rank .row { grid-template-columns: 4.6em 1fr 3.6em; }

/* 名字是文字不是字卡，所以不用楷体、可以截断 */
.row__name {
  color: var(--ink);
  font-size: 14px;
  letter-spacing: .02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 进步百分点是一列要对齐的数字，用等宽数字才不参差 */
.chart--rank .row__label { font-variant-numeric: tabular-nums; }

/* 进步榜配色：前三名暖橙突出，其余暖灰退到背景。
   颜色值仍取自报告图表那两个变量，全局只有一处定义。
   注意这跟「掌握 / 要加强」不是一回事，只是同一对颜色值，
   所以另起类名，免得把两处语义混在一起。 */
.bar__fill--lead { background: var(--chart-good); }
.bar__fill--rest { background: var(--chart-warn); }

/* 需要关注：浅橙底的小条，一条一句现成的话。
   每条是个按钮（点进这个孩子的详情），所以底色比卡片深一档，
   悬停和按下再各深一档，让它看得出来是能点的。 */
.alerts {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 14px 0 2px;
}

.alert {
  display: flex;
  gap: 10px;
  width: 100%;
  padding: 11px 13px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--orange-soft);
  color: var(--ink);
  font-family: inherit;
  font-size: 14px;
  line-height: 1.7;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease;
}

.alert:hover { background: var(--orange-soft-2); }
.alert:active { background: var(--orange-soft-3); }
.alert:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: 2px; }

/* 小圆点只是个引子，说的是哪一类事由文字讲清楚，不靠颜色区分 */
.alert__dot {
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: 9px;
  border-radius: 50%;
  background: var(--orange);
}

.alert__text { flex: 1; min-width: 0; }
.alert__text b { font-weight: 600; }

/* ---------- 9.78 班级页（class.html） ---------- */

/* 班级名 + 人数，比卡片标题重一档，是这一页的页标题 */
.class-head {
  margin-bottom: 16px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: .04em;
}

/* 三个筛选标签：胶囊，选中填橙。
   用 aria-pressed 而不是 tab 语义——这是三个并列的开关，不是标签页容器。 */
.filters {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.filter {
  padding: 8px 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink-2);
  font-family: inherit;
  font-size: 14px;
  letter-spacing: .04em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}

.filter:hover {
  border-color: var(--orange);
  background: var(--orange-soft);
  color: var(--ink);
}

.filter.is-on {
  border-color: var(--orange);
  background: var(--orange);
  color: #fff;
  font-weight: 600;
}

.filter:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: 3px; }

/* 名单整块是一张卡片。overflow 裁掉首尾行的方角，跟 .records 一个处理。 */
.roster-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.roster {
  margin: 0;
  padding: 0;
  list-style: none;
}

.roster li + li { border-top: 1px solid var(--line-soft); }

/* 列头 + 每一行共用同一套栅格：⚠（定宽）· 名字（占剩下的）· 份数 · 掌握率 · 较上周。
   后三列定宽右对齐，才能一列对齐一列地竖着扫下来。

   列宽用 rem 不用 em：em 是相对各自字号的，列头是 12px、行是 14px，
   用 em 两边的列宽就对不上了。

   最左边那格是给 ⚠ 留的固定位——不管有没有 ⚠ 都占着，
   这样 32 个名字才对齐在同一条竖线上。 */
.roster__head,
.roster__row {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr) 3.2rem 3.2rem 4rem;
  align-items: center;
  gap: 10px;
}

/* 列头：给右边的数字一个名分。底色比卡片再浅一点的米色，和表体分开 */
.roster__head {
  padding: 11px 18px;
  border-bottom: 1px solid var(--line-soft);
  background: #FCFAF6;
  color: var(--ink-2);
  font-size: 12px;
  letter-spacing: .04em;
}

.roster__head span { text-align: right; }
.roster__head span:first-child { text-align: left; }

.roster__row {
  width: 100%;
  padding: 15px 18px;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.5;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .16s ease;
}

.roster__row:hover { background: var(--orange-soft); }
.roster__row:active { background: var(--orange-soft-2); }
.roster__row:focus-visible { outline: 2px solid var(--orange-deep); outline-offset: -3px; }

.roster__name {
  min-width: 0;
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 份数和掌握率是一列要对齐的数字，用等宽数字才不参差 */
.roster__num {
  color: var(--ink-2);
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.roster__delta {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 持平用深一档的灰，不用 --ink-3——那档在白底上只有 2.6:1，读不清 */
.roster__delta--up   { color: var(--up); }
.roster__delta--flat { color: var(--ink-2); }
.roster__delta--down { color: var(--down); }

/* ⚠ 那一格：不需要关注的孩子留空，但列宽留着，名字才对齐。
   需要关注的孩子给个实心红圆徽标——32 行里只有 3 个，
   一眼扫下去先撞到的就是它。白字对红底 5.45:1。 */
.roster__flag {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  font-size: 12px;
  line-height: 1;
}

.roster__flag--on {
  background: var(--down);
  color: #fff;
}

/* ---------- 9.79 孩子详情页（student.html） ---------- */

.student__name {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: .04em;
  line-height: 1.3;
}

.student__sub {
  margin: 4px 0 18px;
  color: var(--ink-2);
  font-size: 14px;
  letter-spacing: .02em;
}

/* 这一页的三个数字是「数字在上、说明在下」，和总览页那三张正好相反，
   所以用 order 把值提到前面，而不是另写一套卡片 */
.kpi--flip {
  display: flex;
  flex-direction: column;
}

.kpi--flip .kpi__value { order: -1; margin-top: 0; }
.kpi--flip .kpi__label { margin-top: 7px; }

/* 较上周那个格子：颜色跟着 ↑ / → / ↓ 走，和班级页用的是同一组变量 */
.kpi__value--up   { color: var(--up); }
.kpi__value--down { color: var(--down); }
.kpi__value--flat { color: var(--ink-2); }

/* 提醒卡：浅橙底，和总览页「需要关注」那几条是同一套话、同一套底色 */
.card--warn {
  background: var(--orange-soft);
  border-color: var(--orange-soft-2);
}

/* 标题里那个 ⚠ 用退步红，和班级页名单上的徽标呼应 */
.card__label-icon {
  margin-right: 6px;
  color: var(--down);
  font-size: 13px;
}

.alert-text {
  margin-top: 10px;
  font-size: 16px;
  line-height: 1.7;
}

.alert-text b { font-weight: 600; }

/* 近 4 周趋势：四根柱子，共用 0-100 的刻度，所以高矮能直接比 */
.trend {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}

.trend__col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
}

.trend__value {
  color: var(--ink-2);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

/* 轨道和填充同高、同为「底端方、数据端圆」，和报告页的横条几何一致。
   轨道是定高 130px 的 0-100 满格——几个孩子的掌握率都挤在 35-95 之间，
   轨道太矮的话 48% 和 40% 只差几个像素，趋势就看不出来了。
   刻度不从 0 起会夸大面积差异，所以宁可把槽拉高，不截断刻度。 */
.trend__bar {
  display: flex;
  align-items: flex-end;
  width: 100%;
  max-width: 46px;
  height: 130px;
  background: var(--chart-track);
  border-radius: 6px 6px 0 0;
}

.trend__fill {
  width: 100%;
  min-height: 4px;
  background: var(--chart-good);
  border-radius: 6px 6px 0 0;
}

/* 本周那根颜色不变、字加粗——只用颜色区分「哪个是本周」的话，
   色觉障碍的人就看不出来了，所以靠下面的文字加粗来点 */
.trend__col:last-child .trend__value { color: var(--ink); font-weight: 700; }
.trend__col:last-child .trend__label { color: var(--ink); font-weight: 600; }

.trend__label {
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .04em;
}

/* 本周批改记录：缩略图 + 日期 + 评级 */
.homework {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 14px 0 2px;
  padding: 0;
  list-style: none;
}

.hw {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* 裁哪块由 js/admin.js 的 paintCrop() 决定，这里只管尺寸 */
.hw__thumb {
  flex: none;
  width: 46px;
  height: 46px;
  border: 1px solid var(--line-soft);
  border-radius: 9px;
  background-color: #EDE7DC;
  background-repeat: no-repeat;
}

.hw__date {
  color: var(--ink-2);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* 评级标签贴在日期右边，把整条撑满 */
.hw__rating { margin-right: auto; }

/* ---------- 9.8 提示条（分享等暂无功能的按钮） ---------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: 40px;
  z-index: 40;
  padding: 10px 20px;
  border-radius: 999px;
  background: rgba(51, 51, 51, .88);
  color: #fff;
  font-size: 13px;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, 8px);
  pointer-events: none;
  transition: opacity .22s ease, transform .22s ease;
}

.toast.is-on {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---------- 10. 首页 hero ---------- */
.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 28px 40px;
  text-align: center;
}

.hero__title {
  margin: 40px 0 16px;
  font-size: clamp(30px, 7.8vw, 40px);
  font-weight: 700;
  letter-spacing: .04em;
  line-height: 1.35;
}

.hero__sub {
  max-width: 20em;
  margin-bottom: 42px;
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.85;
}

.entry-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  width: 100%;
  max-width: 700px;
}

.entry-card {
  display: flex;
  min-height: 240px;
  flex-direction: column;
  align-items: center;
  padding: 28px 18px 22px;
  border: 1px solid #EBEBEB;
  border-radius: 16px;
  background: #F9F9F9;
  box-shadow: none;
  text-align: center;
}

.entry-card__icon {
  width: 32px;
  height: 32px;
  flex: none;
  margin-bottom: 16px;
  color: var(--orange);
}

.entry-card--coming .entry-card__icon {
  color: #B5ADA1;
}

.entry-card__title {
  margin: 0;
  color: var(--ink);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: .02em;
  line-height: 1.35;
}

.entry-card__copy {
  min-height: 50px;
  margin: 8px 0 0;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.8;
  text-align: center;
}

.entry-card__action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  padding-top: 18px;
}

.entry-btn {
  display: inline-flex;
  width: auto;
  align-items: center;
  justify-content: center;
  padding: 12px 32px;
  border: 0;
  border-radius: 999px;
  background: var(--orange);
  color: #fff;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .04em;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 7px 16px -11px rgba(232, 163, 61, .7);
  -webkit-tap-highlight-color: transparent;
  transition: background .18s ease, transform .18s ease, box-shadow .18s ease;
}

.entry-btn:hover {
  background: var(--orange-deep);
  transform: translateY(-1px);
}

.entry-btn:active {
  transform: translateY(1px);
}

.entry-btn:focus-visible {
  outline: 2px solid var(--orange-deep);
  outline-offset: 3px;
}

.entry-btn--disabled,
.entry-btn--disabled:hover {
  background: #E9E4DB;
  color: #9B9489;
  box-shadow: none;
  cursor: not-allowed;
  transform: none;
}

.entry-card__status {
  color: #A39B8F;
  font-size: 10.5px;
  letter-spacing: .08em;
  line-height: 1.3;
}

@media (orientation: portrait) {
  .entry-grid {
    grid-template-columns: 1fr;
    max-width: 430px;
  }

  .entry-card {
    min-height: 0;
    padding: 22px 20px 18px;
  }

  .entry-card__icon {
    width: 30px;
    height: 30px;
    margin-bottom: 10px;
  }

  .entry-card__copy {
    min-height: 0;
  }

  .entry-card__action {
    padding-top: 14px;
  }
}

/* ---------- 11. 页脚 ---------- */
.footer {
  padding: clamp(56px, 10vh, 96px) 20px calc(32px + env(safe-area-inset-bottom, 0px));
  color: var(--ink-3);
  font-size: 12px;
  letter-spacing: .04em;
  text-align: center;
}

.footer__icp {
  margin-top: 7px;
}

.footer__icp a {
  color: inherit;
  text-decoration: none;
  transition: color .18s ease;
}

.footer__icp a:hover {
  color: var(--orange-deep);
  text-decoration: underline;
}

.footer__icp a:focus-visible {
  outline: 2px solid var(--orange-deep);
  outline-offset: 3px;
}

@media (max-width: 767px) {
  .hero {
    padding-bottom: 24px;
  }

  .hero__title {
    margin-top: 24px;
  }

  .hero__sub {
    margin-bottom: 24px;
  }

  .entry-grid {
    gap: 10px;
    max-width: 100%;
  }

  .entry-card {
    min-height: 0;
    padding: 16px 16px 14px;
  }

  .entry-card__icon {
    width: 26px;
    height: 26px;
    margin-bottom: 7px;
  }

  .entry-card__title {
    font-size: 17px;
  }

  .entry-card__copy {
    margin-top: 2px;
    font-size: 12.5px;
    line-height: 1.55;
  }

  .entry-card__action {
    gap: 5px;
    padding-top: 10px;
  }

  .entry-btn {
    padding: 9px 24px;
    font-size: 13px;
  }

  .entry-card__status {
    font-size: 9.5px;
  }

  .footer {
    padding-top: 32px;
  }
}

/* ---------- 12. 入场动画 ---------- */
@keyframes fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.fade-in { animation: fade-up .35s ease both; }

/* ---------- 13. 小屏微调 ---------- */
@media (max-width: 420px) {
  .main { padding: 18px 16px 30px; }
  .topbar { padding: 0 16px; }
  .dropzone { min-height: 250px; }
  .hero { padding: 0 22px 32px; }
  .hero__title { margin-top: 32px; }
  .bottombar { padding: 12px 16px; padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  .bottombar__count b { font-size: 18px; }

  /* 机构后台：卡片内边距收窄，进步榜的名字列也跟着窄一点 */
  .kpi { padding: 14px 6px; }
  .kpi__label { font-size: 11px; letter-spacing: .02em; }
  .chart--rank .row { grid-template-columns: 4em 1fr 3.2em; gap: 9px; }
  .alert { padding: 10px 11px; font-size: 13px; }

  /* 班级页：窄屏把行内边距和列间距收一收，
     五列都缩一点，宁可紧一点也不折行 */
  .class-head { font-size: 19px; }
  .filter { padding: 7px 15px; font-size: 13px; }
  .roster__head,
  .roster__row { grid-template-columns: 1.3rem minmax(0, 1fr) 2.6rem 3.1rem 3.8rem; gap: 7px; }
  .roster__flag { width: 1.3rem; height: 1.3rem; font-size: 10px; }
  .roster__head { padding: 9px 14px; font-size: 11px; }
  .roster__row { padding: 13px 14px; font-size: 13px; }
  .roster__name { font-size: 14px; }
  .roster__flag { font-size: 13px; }
}

/* 窄屏：左右分栏改成上下堆叠 */
@media (max-width: 760px) {
  .work-main {
    grid-template-columns: 1fr;
    gap: 16px;
    padding: 16px;
  }
}

/* 尊重系统的「减少动态效果」设置 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}
