/* @import 必须先于一切规则；设计字体：Bricolage Grotesque(标题) + Figtree(正文) */
@import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,700;12..96,800&family=Figtree:wght@400;500;600;700&display=swap');

/* ============================================================
   shared.css — D7 VersaHub demo · cross-page styles
   All component styles shared across index, confirm, teacher,
   settings, and tuition pages.
   2026-08 视觉体系「林间明快」(设计定稿见 design canvas)：
   深绿圆角头部 + 米绿底 + 白卡 + 叶绿/单一暖橙强调 + 胶囊导航。
   ============================================================ */

/* ── CSS variables ──────────────────────────────────────── */
/* RT-10453: 引入完整 design token 体系
   - 主色 shade ramp (RI-08): primary-dark / primary-muted
   - shadow scale (RI-10): sm/md/lg/xl
   - transition scale (RI-14): 收窄到 fast/base/slow 三档
   - focus ring token (RI-12)
   - 语义化 tag 色板 (RI-09): info / success / warning / danger / neutral
*/
:root {
  --font-display: 'Bricolage Grotesque', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-body: 'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --primary: #2E5937;          /* 按钮/强调绿 */
  --primary-deep: #24402B;     /* 头部/导航活跃 chip 深绿 */
  --primary-light: #DCEBD9;    /* 叶绿 tint */
  --primary-dark: #21422A;     /* hover/pressed 加深 */
  --primary-muted: #67705F;    /* 次级文本/弱化主色 */
  --accent: #DD8A3E;
  --accent-light: #FBEEDD;
  --accent-deep: #984D16;      /* accent tint 上的文字色 */
  --bg: #F2F5EF;
  --card: #FFFFFF;
  --text: #22301F;
  --text-secondary: #67705F;
  --text-body: #4A5244;         /* UIV-03 §5 新增：正文段落色（UIV-07 也用）—— 比 --text 轻、比 --text-secondary 重 */
  --text-on-accent-tint: #6C6250;   /* UIV-02 §5：紧急卡（#FBEEDD 底）上的描述 —— 5.25，今天 --text-secondary 4.53 贴边 */
  --border: #DFE5DB;
  --hairline: #EEF1EB;         /* 卡内分隔线 */
  --divider: #EDF0EA;           /* UIV-03 §5：列表行与行之间的 1px 线（画板 SchoolList） */
  --icon-muted: #A2A89D;        /* UIV-03 §5：行尾折角 —— 装饰（整行才是按钮），不算非文本 3:1 的对象 */
  --text-disabled: #8B9186;     /* UIV-07 §5：不可点的主键字（发帖未填完）；以前写死 Tailwind 灰 #9CA3AF，不在这套色里 */
  --danger: #B3452F;            /* UIV-07 §5：画板只有这一个红（白字 5.51，以前 4.71）；全站约 60 处跟着变，F4 归壳 */
  --success: #2F6857;
  --radius: 16px;
  /* 按钮的圆角**只在这里定义一次**（T103 / UX-006 ②）。
     实测枚举：主行动按钮 8 颗、**4 种圆角** —— 8 / 10 / 12 / 999。
     四种不是四个人各写各的，是「没有一个可引用的地方」的必然结果。
     取 12：design-spec v2.1 §2.1 刚把 `.btn-post` 立为「一屏 / 一层的主行动」那一族，
     而它的本体就是 12。**要改成 999 的话，改这一行就够了** —— 这正是立 token 的意义。 */
  --radius-btn: 999px;          /* UIV-01 §4：画板上带字的按钮 · 胶囊 · 筛选 · 标签 48 处全是 999（T103 的 12 被这次指令取代） */
  /* UIV-01 §4 全站圆角口径（08-24 画板，按用途归类） */
  --radius-card: 18px;          /* 主内容卡：16px 内边距、带阴影（30 处） */
  --radius-note: 14px;          /* 浅色提示框 · 弹出菜单（5 处） */
  --radius-sm: 12px;            /* 图标块 · 小方块 · 验证码格（22 处） */
  --radius-header: 24px;        /* 头部底角（16 处，全部一致） */
  --radius-bar: 22px;           /* UIV-03 §5：详情底部答题栏的上两角（画板 SchoolItem；不在上面的阶梯里，单列） */
  /* UIV-01 §5：头部（深绿底）里的四种颜色 —— 以前三种浅填充混用、次级字写死 */
  --on-dark-fill: rgba(255, 255, 255, .12);
  --on-dark-icon: #D8E4D6;
  --on-dark-muted: #A9C4AC;
  --on-dark-soft: #E9F1E7;
  /* shadow scale（绿灰底色的柔和投影） */
  --shadow-sm: 0 1px 4px rgba(34,48,31,0.08);   /* UIV-05 §5：画板 .08 */
  --shadow-chip: 0 1px 6px rgba(34,48,31,.05);   /* UIV-02 §5：画板上的小胶囊（快捷入口）都是这一个；不改 --shadow-sm —— 它另有三处、画板各自不同 */
  --shadow-md: 0 2px 10px rgba(34,48,31,0.06);
  --shadow-lg: 0 6px 20px rgba(34,48,31,0.12);
  --shadow-xl: 0 12px 40px rgba(34,48,31,0.22);
  --shadow-up: 0 -4px 20px rgba(34,48,31,.10);   /* UIV-03 §5：吸底答题栏往上的投影 */
  /* PD-0072（用户 Q55 选 A「全照稿」）· S-019 §5：橙底上的白、画板那一枚暖橙字、橙光晕。
     --on-accent 的值就是白 —— 立它是为了让闸 8 豁免表能按「谁在橙上」查到（S-019 §6）。
     --accent-deep 的值**不动**：整体改回画板那一枚会把 PD 范围外 5 处琥珀底上的字一起拖到 4.48（S-019 §3）。 */
  --on-accent: #FFFFFF;
  --accent-text: #A9581B;
  --shadow-primary: 0 6px 18px rgba(46,89,55,.3);   /* UIV-14：主按钮那层绿投影（画板 CTeacher 的 Send；学费 / 注册那几颗主按钮同一档） */
  --shadow-accent: 0 6px 18px rgba(221,138,62,.35);
  --shadow-accent-lg: 0 6px 18px rgba(221,138,62,.45);
  /* PD-0072 v2 · S-019 §5：签字钮选中那一颗的光晕（画板 Sign）、活动视图切换轨道、两处占位字（画板两个值，不并）、
     家长圈头像色板（画板家长 / 老师头像出现过的五色；JS 按序号取，不写色值）。 */
  --shadow-accent-sm: 0 4px 14px rgba(221,138,62,.35);
  --toggle-track: #E7ECE3;
  --text-placeholder: #A2A89D;
  --text-placeholder-field: #9AA394;
  --link-underline: #BFD0BC;   /* UIV-09：文字链接的下划线色（画板 CJoin Resend / Change number；原来在 join.css 里写死两处） */
  --avatar-1: #3E8A78; --avatar-2: #5B6BB0; --avatar-3: #AF5F8C; --avatar-4: #AD7A42; --avatar-5: #2E5937;
  --shadow-pop: 0 10px 28px rgba(34,48,31,.22);  /* UIV-07 §5：弹出菜单（⋯）；--shadow-xl 是 0 12px 40px，差在尺寸，不并 */
  --shadow: var(--shadow-md);  /* 兼容旧引用 */
  /* transition scale (3 tier) */
  --t-fast: 0.15s;
  --t-base: 0.2s;
  --t-slow: 0.3s;
  /* focus ring */
  /* §11：旧值是半透明的一圈 —— 压页面底 **1.77**、压白卡 1.80、
     **压实色 --primary 按钮 1.00（完全隐形）**。而聚焦指示是「辨认状态所需的
     视觉信息」，门槛 3:1。两端每一个可聚焦元素都用这一个 token ——
     **键盘用户按 Tab，看不出焦点落在哪。**
     两圈：里圈一道页面底色当间隙，外圈实色 --primary（压 --bg 7.34 · 压白卡 8.08）
     —— 实色按钮上靠那 2px 间隙分得开。 */
  --focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--primary);
  /* 语义 tag 色 (4 semantic + neutral)——统一收敛为同明度色族 */
  --tag-info-bg: #E1EAF0;     --tag-info-fg: #3E5A6E;
  --tag-success-bg: #DCEBD9;  --tag-success-fg: #21422A;
  --tag-warning-bg: #FBEEDD;  --tag-warning-fg: #984D16;
  --tag-danger-bg: #F6E0DC;   --tag-danger-fg: #9A3B31;
  --tag-neutral-bg: #ECEFE9;  --tag-neutral-fg: #5B6455;
  --nav-height: 74px;   /* 悬浮导航 62px + 底部 12px 间距，供 FAB/toast 计算避让 */
}

/* ── [hidden] 必须真的藏住 ────────────────────────────────
   HTML 规范里 `[hidden]` 只是 UA 样式表的一条 `display:none`，**任何一条自己写的
   `display` 都盖得过它**。这个仓库里已经踩过三次：`.digest-status-actions`（BUG-031）、
   `.cf-actions`（T109）都是 `display:flex`，于是 JS 里 `el.hidden = true` 之后
   **屏幕上那块还在**，而代码读起来完全正确。
   一条全局兜底，比每处各补一条 `[hidden]{display:none}` 可靠。 */
[hidden] { display: none !important; }

/* ── 读取的三态（T143 / T144）────────────────────────────────
   **一套容器，不是七种。** UX-005 已经报过「空态有四种写法」，
   再给错误态长出第四种，就是同一个错误再犯一次。 */
.read-state { padding: 16px; text-align: center; }
.read-state.is-loading {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  color: var(--text-secondary); font-size: 14px;   /* t-215 · D-006 §3：未定义名 → --text-secondary（4.39 → 4.70） */
}
.read-state-spinner {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--border, #e5e7eb); border-top-color: var(--primary, #3b7d4f);
  animation: read-state-spin .7s linear infinite;
}
@keyframes read-state-spin { to { transform: rotate(360deg); } }
/* 动效关掉的人**照样要看得出它在读** —— 所以停转不等于消失 */
@media (prefers-reduced-motion: reduce) {
  .read-state-spinner { animation: none; opacity: .6; }
}
.read-state.is-failed {
  border: 1px solid var(--border, #e5e7eb); border-radius: 12px;
  padding: 20px 16px; margin: 8px 0;
}
.read-state-title { font-weight: 600; margin-bottom: 4px; }
/* S-008 §6：这一句今天在页面底色上只有 4.39。
   **而它之所以是 #6b7280，是因为它引用的那个变量根本没定义** —— 兜底才是真正在
   渲染的那个值（D-006 里会生效的那一类，比 A 类更值得抓：A 类只是死代码，
   这一类是「你以为在用 token，其实在用一个没人复核过的写死值」）。
   换成真的存在的 --text-secondary：压页面底 4.70 ✓，压白卡 5.17。 */
.read-state-text { color: var(--text-secondary); font-size: 14px; line-height: 1.5; }
/* 命中区 ≥44（G30）—— 这颗是她**唯一**的出路，不许比别的按钮小 */
.read-state-retry {
  margin-top: 12px; min-height: 44px; padding: 0 20px;
  border: 1.5px solid var(--primary, #3b7d4f); border-radius: 999px;
  background: transparent; color: var(--primary, #3b7d4f);
  font-size: 15px; font-weight: 600; cursor: pointer;
}


/* ── Global focus ring (RT-10453 RI-12) ──────────────────── */
:focus { outline: none; }
button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: none;
  /* **这里不设 `border-radius`**（design 22:21 更正 §11，采纳）。
     原来这条规则里有 `border-radius: 8px` —— 它改的是**元素形状**，不只是环。
     我第一版照原话做：保留 8px、把圆角大于 8 的四个各自覆盖回去。
     但那只修了一半 —— design 数过四页可聚焦元素，**正好 8px 的只有首页一个**：
         >8 被压扁   .quick-link 999→8 · .header-avatar 999→8 · .fab 50%→8 · .btn-post 12→8
         <8 被磨圆   链接、底栏键（本身 0px）、Skip、老师端 digest 开关
     后一半我自己的探针也量到了（`A 0px → 8px` / `nav-item 0px → 8px`），
     **而我当时把它当成「全局规则的本意」放过去了** —— design 说得对，那也是形变。
     `box-shadow` 本来就沿元素自己的圆角画：这一句删掉，**所有元素聚焦时都不变形**，
     那五条各自覆盖也一并不需要了。 */
  box-shadow: var(--focus-ring);
}

/* ── 像 app（用户 2026-10-01：「从UX层面整体做一次，模仿app操作的巡查和优化」——「都做吧」）──────────
   ① 点按钮不闪灰、连点两下不放大页面、长按按钮不弹浏览器菜单 / 不选中字；
   ② 整页不回弹（头部和导航被一起拽下来）、安卓 Chrome 下拉不整页重载 —— 下拉刷新由 shared.js 自己做；
   ③ 手机上输入框 16px：小于 16px 的输入框，iPhone 一点进去就把整页放大、还不缩回来；
   ④ 加到主屏幕后页面铺到刘海和底部横条底下（viewport-fit=cover + 状态栏透明），
      头部按 --sat 往下让、底部按 --sab 往上让。浏览器里这两个值是 0，什么都不变。 */
:root { --sat: env(safe-area-inset-top, 0px); --sab: env(safe-area-inset-bottom, 0px); }
html { -webkit-tap-highlight-color: transparent; touch-action: manipulation; overscroll-behavior-y: none; }
body { overscroll-behavior-y: none; }
button, .nav-item, .segment-tab, .type-chip, .chip, [role="button"], [role="tab"] {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
@media (hover: none) and (pointer: coarse) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]), textarea, select {
    font-size: 16px !important;
  }
}
@supports (padding-top: env(safe-area-inset-top)) {
  html body .app-header { padding-top: calc(18px + var(--sat)); }
  html body .app-header.home-header { padding-top: calc(20px + var(--sat)); }
  html body .app-header.home-header.on-tab { padding-top: calc(18px + var(--sat)); }
  html body .page-header, html body .tuition-header, html body .teacher-header,
  html body .sd-topbar, html body .post-detail-topbar { padding-top: calc(18px + var(--sat)); }
  html body .audience-page .ap-head { padding-top: calc(16px + var(--sat)); }
  html body .photo-modal-topbar { padding-top: calc(12px + var(--sat)); }
  html body .hp-hero-in { padding-top: calc(8px + var(--sat)); }
  html body .join-wrap { padding-top: calc(24px + var(--sat)); }
  /* 老师端二级纸的顶栏：原来把刘海的高度加在了**下**边距上 */
  html body .cs-topbar { padding: calc(12px + var(--sat)) 16px 12px; }
}

/* 按钮按下去：稍微淡一下（触屏上没有 hover，原来按下去什么反应都没有） */
@media (hover: none) {
  .btn-post:active, .btn-cancel:active, .nav-item:active, .chip:active, .type-chip:active, .segment-tab:active {
    opacity: 0.72;
  }
}
@media (prefers-reduced-motion: reduce) {
  html body #school-detail-modal .modal-sheet, html body #hw-detail-modal .modal-sheet, html body .post-detail-sheet,
  html body .class-sheet, html body .audience-page { transition: none !important; animation: none !important; }
}

/* ── 下拉刷新（shared.js D7Pull）── */
.ptr {
  position: fixed; left: 50%; top: calc(8px + var(--sat)); z-index: 600;
  width: 40px; height: 40px; margin-left: -20px; border-radius: 50%;
  background: var(--card); color: var(--primary-deep); box-shadow: var(--shadow-md);
  display: flex; align-items: center; justify-content: center;
  transform: translateY(-60px); opacity: 0; pointer-events: none;
}
.ptr svg { width: 20px; height: 20px; transition: transform 0.15s; }
.ptr.ready svg { transform: rotate(180deg); }
.ptr.spinning svg { animation: ptr-spin 0.8s linear infinite; }
@keyframes ptr-spin { to { transform: rotate(360deg); } }

/* ── Reset ──────────────────────────────────────────────── */
* { margin: 0; padding: 0; box-sizing: border-box; }
/* 表单控件默认不继承字体（否则全站按钮/输入框渲染成 Arial） */
button, input, select, textarea { font-family: inherit; }

/* ── Base body ──────────────────────────────────────────── */
body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text);
  max-width: 480px;
  margin: 0 auto;
  -webkit-font-smoothing: antialiased;
}
/* CJK fonts injected by shared.js when lang=zh */
body.lang-zh {
  font-family: 'Figtree', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB',
               'Microsoft YaHei', 'Segoe UI', Roboto, sans-serif;
}

/* ── Responsive breakpoints ─────────────────────────────── */
/* ≤360dp: full-width + narrower padding */
@media (max-width: 360px) {
  body { max-width: 100%; }
  .tab-page { padding-left: 12px; padding-right: 12px; }
  .content { padding-left: 12px; padding-right: 12px; }
}
/* 768dp+: 600px container */
@media (min-width: 768px) {
  body { max-width: 600px; border-left: 1px solid var(--border); border-right: 1px solid var(--border); }
  .photo-grid { grid-template-columns: repeat(4, 1fr); }
}
/* 1024dp+: 720px container */
@media (min-width: 1024px) { body { max-width: 720px; } }

/* Foldable hinge safe area */
@supports (padding: env(safe-area-inset-left)) {
  body {
    padding-left: env(safe-area-inset-left, 0);
    padding-right: env(safe-area-inset-right, 0);
  }
}

/* ── App header ─────────────────────────────────────────── */
.app-header {
  background: var(--primary-deep);
  color: white;
  padding: 18px 20px 20px;
  border-radius: 0 0 var(--radius-header) var(--radius-header);
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  gap: 12px;
}
.app-header .header-brand { flex: 1; min-width: 0; }
.app-header .logo { font-family: var(--font-display); font-size: 21px; font-weight: 800; letter-spacing: -0.2px; }
/* 标题整体纯白（logo 两个词都是 span，别只染 span——那会把整个字标染灰绿） */
.app-header .logo span { color: #fff; }
.app-header .subtitle { font-size: 12.5px; font-weight: 500; color: var(--on-dark-muted); margin-top: 2px; letter-spacing: 0.1px; }
/* RT-10451 AC7: 设置按钮降权 — 缩小 + 降低不透明度 */
/* UIV-01：设置键 32 → 34、底 .08 → --on-dark-fill（.12）、图标 16 → 18、描边白 .75 → --on-dark-icon */
.app-header .header-settings-btn {
  background: var(--on-dark-fill);
  border: none;
  color: var(--on-dark-icon);
  width: 34px; height: 34px;
  border-radius: 999px;
  font-size: 15px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  text-decoration: none;
  line-height: 1;
}
.app-header .header-settings-btn svg { width: 18px; height: 18px; }
.app-header .header-settings-btn:hover,
.app-header .header-settings-btn:active {
  background: rgba(255,255,255,0.20);
  color: white;
}

/* gap 8 → 12：两个圆按钮的命中区各扩到 44 之后，8px 的间距会让它们**互相咬掉一角**
   （实测头像的命中宽被隔壁吃成 42）。中心距 = 18 + gap + 16，要 ≥44 就得 gap ≥ 10。 */
.app-header .header-auth { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }

.header-avatar {
  width: 36px; height: 36px;
  border-radius: 999px;
  background: var(--accent);
  /* PD-0072 · S-019 §1 ①：照画板白字压 --accent（2.70，用户明知不过线选 A，进闸 8 豁免表）。
     推翻了 design-spec §12 那一版（字改 --text 5.15，t-170）。 */
  color: var(--on-accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700;
  text-decoration: none;
  flex-shrink: 0;
}
.header-avatar.guest { background: rgba(255,255,255,0.25); font-size: 18px; }
.header-avatar:hover { opacity: 0.88; }

.header-login-btn {
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  background: rgba(255,255,255,0.18);
  border: none;
  border-radius: 999px;
  padding: 8px 16px;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.header-login-btn:hover { background: rgba(255,255,255,0.28); }

/* 切 tab 时头部换成「tab 名 + 功能描述」（首页显示品牌+问候） */
.header-brand .brand-tab .tab-title { font-family: var(--font-display); font-size: 22px; font-weight: 800; letter-spacing: -0.2px; }
.header-brand [hidden] { display: none; }

/* ── Home 页头部（问候语并入深绿头部，2026-08 视觉定稿）──── */
/* UIV-01：首页头部 20 / 20 / 24（画板 OptionC）；tab 页头部 18 / 20 / 20 与其余九块画板一致，不动 */
.app-header.home-header { display: block; position: static; padding: 20px 20px 24px; }
/* 同一个头部切到 tab 页：回到 .app-header 的 18 / 20（UIV-01 §3「只首页」；index.js 切 .on-tab） */
.app-header.home-header.on-tab { padding: 18px 20px 20px; }
.home-header .header-top { display: flex; align-items: center; gap: 12px; }
.home-header .header-greeting {
  margin-top: 18px;
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
}
.home-header .header-greeting[hidden] { display: none; }
.home-header .greeting { font-family: var(--font-display); font-size: 27px; font-weight: 700; color: #fff; letter-spacing: -0.3px; }
.home-header .greeting-date { font-size: 13px; font-weight: 500; color: var(--on-dark-muted); margin-top: 3px; }
.home-header .todo-pill {
  flex-shrink: 0; background: var(--on-dark-fill); color: var(--on-dark-soft);
  border-radius: 999px; padding: 7px 14px; font-size: 12.5px; font-weight: 600;
  white-space: nowrap; margin-bottom: 2px;
}

/* 紧急卡的小标签（Due tomorrow） */
.action-body .action-label {
  display: block;
  font-size: 12px; font-weight: 700; letter-spacing: 0.3px;
  text-transform: uppercase; color: var(--accent-deep); margin-bottom: 2px;
}
/* PD-0072 · S-019 §2：紧急卡（#FBEEDD 底）里那一条照画板的暖橙字 --accent-text（4.48，豁免表）。只这一条 ——
   非紧急卡上的标签不在 PD 范围内，仍是 --accent-deep */
.card.action-card.urgent-alert .action-body .action-label { color: var(--accent-text); }

/* 快捷入口 chip（Notice history / Resources） */
.quick-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 2px; }
.quick-link {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--card); color: var(--primary); border: none;
  border-radius: 999px; padding: 10px 16px; min-height: 44px;
  font-size: 13px; font-weight: 600; cursor: pointer;
  box-shadow: var(--shadow-chip);
  transition: background var(--t-fast), box-shadow var(--t-fast);
}
.quick-link:hover { box-shadow: var(--shadow-md); }
/* 「Tuition」入口上还要付的笔数（2026-09-29）：和底栏角标同一个橙 */
.quick-link-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; margin-left: 6px; border-radius: 9px; background: var(--accent); color: var(--text); font-size: 11px; font-weight: 700; line-height: 1; }  /* 白字压橙只有 2.70：小东西「底不动、字改 --text」（BUG-034 那条） */
.quick-link:active { background: var(--primary-light); }
/* 学费入口是一个 <a>（它去的是另一张页面，不是切 tab）—— 别带下划线 */
a.quick-link { text-decoration: none; }
.empty-state a.empty-cta { text-decoration: none; }

/* ── Language-scoped visibility ──────────────────────────── */
body.lang-zh [data-lang-only="en"] { display: none !important; }
body.lang-en [data-lang-only="zh"] { display: none !important; }

/* ── Section title ───────────────────────────────────────── */
/* RT-10451 AC1/AC8: 字体权重 700→600 与 :first-child 收紧上间距 */
.section-title {
  font-family: var(--font-display);
  font-size: 17px;              /* UIV-01：画板 17 */
  font-weight: 700;
  color: var(--text);
  margin: 20px 0 10px;
}
.section-title:first-child { margin-top: 4px; }

/* ── Cards ───────────────────────────────────────────────── */
.card {
  background: var(--card);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 12px;
  box-shadow: var(--shadow);
}

/* ── Tab pages ──────────────────────────────────────────── */
/* **底部要给悬浮导航让出位置。** 之前 padding-bottom 是 0，于是每一页的最后
   一条内容都压在胶囊导航底下 —— 点不到，也看不全。--nav-height 这个变量本来
   就是为这件事定的（FAB 和 toast 一直在用），页面自己却没用上。 */
.tab-page {
  display: none;
  padding: 16px 16px calc(var(--nav-height) + 24px + env(safe-area-inset-bottom, 0px));
}
.tab-page.active { display: block; }

/* ── Greeting ───────────────────────────────────────────── */
/* RT-10453 RI-05: greeting 视觉降级 — 去掉 gradient, 改为纯色背景 + 更轻的左边条
   保留 26px bold 维持仪式感, 但去掉 4px 主色实心边条与渐变 */
.greeting-card {
  background: var(--card);
  padding: 16px;
}
.greeting { font-family: var(--font-display); font-size: 26px; font-weight: 700; color: var(--primary-deep); letter-spacing: -0.3px; }
.greeting-date { font-size: 13px; color: var(--text-secondary); margin-top: 4px; font-weight: 500; }

/* ── Action cards ───────────────────────────────────────── */
/* 整张卡都点得开：待办卡和「接下来」那几行都是 <button>，不是只有右边那个
   小按钮能点 —— 拇指按在标题上什么都不发生，是这一页此前最主要的观感问题。
   （右边那个 .action-btn 现在是卡里的一个 <span>，只负责说清点了会怎样。） */
button.card.action-card, button.event-mini {
  width: 100%; text-align: left; font: inherit; color: inherit;
  border: none; cursor: pointer;
}
button.card.action-card:active, button.event-mini:active { opacity: 0.9; }
.action-card { display: flex; align-items: center; gap: 12px; }
/* 首页 to-do：左边的勾只管打钩，右边整块是打开详情的按钮（2026-09-28） */
.home-todo-check .action-icon { cursor: pointer; }
.home-todo-open { flex: 1; min-width: 0; background: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.home-todo-chev { flex: none; font-size: 22px; line-height: 1; color: var(--text-secondary); }
/* UIV-01 §4：首页待办卡是「主内容卡」—— 18，不是列表行卡的 16 */
.card.action-card { border-radius: var(--radius-card); }
/* UIV-02：图标块 42 → 44、圆角 12 → --radius-note 14；图标 20 → 22、笔宽 1.75 → 2（两种卡同） */
.action-icon {
  width: 44px; height: 44px;
  border-radius: var(--radius-note);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; flex-shrink: 0;
}
/* PD-0072 · S-019 §1 ④：照画板白笔压 --accent（非文字 2.70，豁免表）；推翻 §12.1 / t-170 的 --text */
.action-icon.urgent { background: var(--accent); color: var(--on-accent); }
/* UIV-02 §4：画板上非紧急的都是叶绿 —— 橙只留给紧急卡，一屏里只有一处在喊 */
.action-icon.pending { background: var(--primary-light); color: var(--primary); }
.action-icon.info { background: var(--primary-light); color: var(--primary); }
.action-body { flex: 1; min-width: 0; display: block; }
.action-body h4, .action-body p { display: block; }
.action-body h4 { font-size: 15px; font-weight: 700; }
.action-body p { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
/* RT-10453 RI-11/RI-13: action-btn 加 hover + min-height 44px 触控达标 */
/* RT-10452 LS-01: 10→8 收敛到 8/16 标准 scale (min-height 44 兜底触控) */
.action-btn {
  background: var(--primary); color: white; border: none;
  border-radius: 999px; padding: 12px 18px;
  font-size: 13.5px; font-weight: 700; cursor: pointer;   /* UIV-01：画板 13.5（qa run 99 指出） */
  white-space: nowrap; min-height: 44px;
  transition: background var(--t-base), opacity var(--t-base);
}
/* 待办卡里的 .action-btn 是个 <span>（整张卡才是按钮）—— 自己居中一下 */
.action-card .action-btn { display: inline-flex; align-items: center; justify-content: center; }

/* T081：老师发的 to-do 直接在首页勾掉。**它是 label 不是 button** ——
   checkbox 套在 button 里是无效 HTML，而这一行的主要动作就是打钩。
   点中任意处都算（label 天然如此），所以命中区是整张卡，不是那个小方框。 */
.home-todo-check { cursor: pointer; }
.home-todo-check .home-todo-box {
  width: 20px; height: 20px; margin: 0; accent-color: var(--primary); cursor: pointer;
}
/* 勾掉之后**不立刻消失**：她要看得见自己刚做了什么（下一次加载它就不在了，
   因为服务端的 checks 里有它了）。划掉 + 变淡，和详情页那一份同一个说法。 */
.home-todo-check.done .action-body h4 { text-decoration: line-through; }
.home-todo-check.done { opacity: .55; }
.home-todo-tag {
  display: inline-block; margin-top: 2px; font-size: 12px; color: var(--primary);
}
.action-btn:hover { background: var(--primary-dark); }
.action-btn:active { opacity: 0.85; }
.action-btn.secondary { background: var(--primary-light); color: var(--primary-dark); }
.action-btn.secondary:hover { background: #CBE0C8; }

/* RT-10390 AC1 / RT-10453 RI-06: urgent-alert P1 专属强化
   - 边框由 1px #FED7AA 升至 1.5px var(--accent)
   - 顶部条 4→6px + 左侧 3px 主色 accent 实心边条 (双轴强调)
   - 增加 shadow-lg + accent 微染色光环, 与普通 action-card 拉开层级 */
/* 2026-08 视觉定稿：紧急卡只保留一个强调轴——accent 底色卡 + accent 按钮。
   旧版的 顶条 + 左边条 + ⚠️ 前缀 + P1 徽章 四重强调全部移除。 */
.card.action-card.urgent-alert {
  background: var(--accent-light);
  box-shadow: var(--shadow-md);
}
.card.action-card.urgent-alert .action-body h4 {
  font-weight: 700;
  margin-top: 2px;              /* UIV-02：到期标签与标题之间 */
}
/* UIV-02：紧急卡描述 --text-secondary 压 #FBEEDD 4.53 贴边 → --text-on-accent-tint 5.25；行高 1.4 */
.card.action-card.urgent-alert .action-body p { color: var(--text-on-accent-tint); line-height: 1.4; }
.card.action-card.urgent-alert .action-btn {
  background: var(--accent);
}
.card.action-card.urgent-alert .action-btn:hover {
  background: #C97C33;
}

/* RT-10390 AC2: time tier headers */
/* RT-10451 AC1: 字体权重 700→600 — 与 section-title 形成梯度 */
.time-tier-header {
  display: flex; align-items: center; gap: 8px;
  margin: 16px 0 8px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.4px;
  color: var(--text-secondary); text-transform: uppercase;
}
.time-tier-header::before, .time-tier-header::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.time-tier-header.tier-today { color: var(--accent-deep); }
.time-tier-header.tier-today::before, .time-tier-header.tier-today::after { background: #EFD9BE; }

/* ── RT-10406: Empty states ──────────────────────────────── */
.empty-state {
  text-align: center; padding: 48px 24px 32px;
  margin: 8px 4px 16px;
  background: var(--card);               /* t-215 · D-006 §3：未定义名 → --card（同值）；下面两条的兜底本来就是死的，一起删 */
  border: 1px dashed var(--border);
  border-radius: 12px; color: var(--text-secondary);
}
/* ── T101 / UX-005：**一处「这里现在没东西」= 一个容器** ───────────
   改之前全站有 26 处空态容器、**9 种画法**：`.cal-list-empty`（13 处，无边框无圆角）·
   `.circle-reported-empty`（圆角 **10px**，不在圆角 token 表里）· `.bill-empty`（16px）·
   `.notice-empty` / `.resource-empty`（36px 内边距）· `.parent-picker-empty`（12px）·
   `.published-empty`（22px）· `.cal-empty-state` · 以及这一条本身。
   **同一页、同一次滚动里两块「空」用两种画法**（UX-005 的原始现象）。
   现在它们全部落到这一条上，各自的类只留作 JS 钩子。

   `.is-compact`：浮出层里的**子列表**（「这个孩子还没挂监护人」这一类）用它。
   同一条边框、同一个圆角、同一套颜色，**只有内边距走小一档** ——
   一个 48px 高的虚线盒子压在一个三行的子列表上，读起来像出了错，而不是像「还没有」。 */
.empty-state.is-compact { padding: 20px 16px; margin: 4px 0 8px; }
/* RT-10452 LS-05: 12→8 sub-item 间距 (icon→title) */
.empty-state .empty-icon { line-height: 1; display: block; margin-bottom: 8px; color: var(--primary-muted); }
.empty-state .empty-icon svg { display: block; margin: 0 auto; }
/* RT-10451 AC1: empty-title 字体权重 600→500 — 让 hint 不与标题抢视觉权重 */
/* t-180：原来引用的变量在哪都没定义，这里一直退到体系外的 #0F172A —— 换成正文字色 --text */
.empty-state .empty-title { font-size: 15px; font-weight: 500; color: var(--text); margin: 0 0 8px; }
.empty-state .empty-hint { font-size: 13px; line-height: 1.5; margin: 0 auto 16px; max-width: 280px; }
/* RT-10453 RI-11/RI-13: empty-cta hover + min-height 44px */
/* RT-10452 LS-02: 11→12 收敛到标准 scale (4/8/12/16/20...) */
.empty-state .empty-cta {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 12px 20px; border-radius: 999px; border: none;
  background: var(--primary, #2F6F8C); color: #fff;
  font-size: 13px; font-weight: 700; font-family: inherit;
  cursor: pointer; min-height: 44px;
  transition: background var(--t-base), opacity var(--t-base);
}
.empty-state .empty-cta:hover { background: var(--primary-dark); }
.empty-state .empty-cta.secondary {
  background: transparent; color: var(--primary, #2F6F8C); border: 1px solid var(--primary, #2F6F8C);
}
.empty-state .empty-cta.secondary:hover { background: var(--primary-light); }
.empty-state .empty-cta:active { opacity: 0.85; }

/* ── Event mini (home tab "coming up") ───────────────────── */
/* 2026-08 视觉定稿：每条一张白卡 + 叶绿日期方块 */
.event-mini {
  display: flex; gap: 12px; align-items: center; padding: 13px 14px;
  background: var(--card); border-radius: var(--radius);
  box-shadow: var(--shadow-md); margin-bottom: 8px;
}
.event-date-block {
  width: 46px; height: 46px; flex-shrink: 0;
  border-radius: 12px; background: var(--primary-light);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.event-date-block .day { display: block; font-family: var(--font-display); font-size: 17px; font-weight: 800; color: var(--primary-dark); line-height: 1; }
.event-date-block .month { display: block; font-size: 9.5px; font-weight: 700; letter-spacing: 0.8px; color: #4E6B50; text-transform: uppercase; margin-top: 2px; }
.event-info { display: block; min-width: 0; }
.event-info h4 { display: block; font-size: 14.5px; font-weight: 700; }
.event-info p { display: block; font-size: 12.5px; color: var(--text-secondary); margin-top: 2px; }

/* ── Homework ────────────────────────────────────────────── */
.hw-card { display: flex; align-items: center; gap: 12px; }
/* S-009 §5：这里原来躺着**被叫停的那两版**的整套视觉词汇 ——
   科目方块 + 五个科目色 · 「不急」的日期变体 · ✓ 与 🔔 两颗按钮 ·
   「我看到了」的划掉态 · 琥珀底的「逾期」折叠组 · 红边过期卡。
   它们在 JS/HTML 里**一处都不渲染**（逐条 grep 过，删前 0 命中）。

   留着它们的代价已经付过一次：S-005 就是对着这些死样式定的色，
   t-147 又是照 S-005 开的单。**样式表里躺着一整套「打勾 + 标红 + 科目色」，
   下一个人读 CSS 会以为那是这一屏的设计。**

   删死样式**不改变任何像素** —— 没有元素带这些类。 */
.hw-body { flex: 1; min-width: 0; }
/* UIV-04：标题 15 → 14.5，说明 13 → 12.5、行高 1.4（画板 CHomework） */
.hw-body h4 { font-size: 14.5px; font-weight: 700; }
.hw-body .hw-desc { font-size: 12.5px; line-height: 1.4; color: var(--text-secondary); margin-top: 2px; }
/* S-009 §3：日期行去掉琥珀色。
   `--accent-deep` 就是 `--tag-warning-fg`（同一个值）—— **这个颜色在这套 token 里
   的意思是「注意」**，而今天**每一个**截止日期都是它：下周的、折起来的上个月的，
   全都是。一个把所有日期都涂成警示色的列表，等于**用颜色催**。
   不用灰（候选 --text-secondary 5.17）：灰 600 的日期会和上面灰 400 的副文案同色，
   扫一眼找不到截止日 —— **而截止日正是她在这一屏上要找的那个信息**。
   深色 600 让它保持好找，只是不再带「注意」的意思。
   D-004 ③：6.16 → 13.90，**不是降**。

   **UIV-04 §3 取代了上面「不用灰」那一半**（design 推翻了自己在 S-009 §3 的判断）：
   画板是灰 #67705F / 600 —— 和说明（灰 400）靠**字重**分开，不靠颜色。压白 5.17 过 AA。
   去琥珀、不标红两条不变。 */
.hw-body .hw-due { font-size: 12px; color: var(--text-secondary); font-weight: 600; margin-top: 4px; }
.hw-overdue-tag {
  display: inline-block; margin-left: 6px;
  padding: 1px 6px; background: var(--danger); color: white;
  font-size: 10px; font-weight: 700; border-radius: 4px; vertical-align: middle;
}

/* ── Calendar ────────────────────────────────────────────── */
.view-toggle {
  /* PD-0072 v2（S-019 §4）：轨道与未选字照画板，成对 4.31，进闸 8 豁免表。S-010 §3.3 那次换成中性 token（5.32）被推翻。 */
  display: flex; background: var(--toggle-track); border-radius: 999px; padding: 4px; margin-bottom: 14px;   /* UIV-05：下距 16 → 14 */
}
/* RT-10453 RI-10/RI-11/RI-13: view-toggle 走 shadow token + hover + min-height */
/* RT-10452 LS-01: 10→8 收敛 (min-height 44 兜底) */
.view-toggle button {
  flex: 1; border: none; background: transparent; padding: 10px 8px; border-radius: 999px;   /* UIV-05：上下 8 → 10、字 14 → 13.5 */
  font-size: 13.5px; font-weight: 600; color: var(--text-secondary); cursor: pointer;
  min-height: 44px;
  transition: background var(--t-fast), color var(--t-fast);
}
.view-toggle button:hover { color: var(--text); }
.view-toggle button.active { background: white; color: var(--text); font-weight: 700; box-shadow: var(--shadow-sm); }
/* RT-10453 RI-09: tag 收窄为 4 语义色 + neutral, 全部走 token */
.event-tag { display: inline-block; padding: 3px 8px; border-radius: 8px; font-size: 11px; font-weight: 500; margin-right: 6px; }
.tag-holiday    { background: var(--tag-info-bg);    color: var(--tag-info-fg); }
.tag-activity   { background: var(--tag-success-bg); color: var(--tag-success-fg); }
.tag-meeting    { background: var(--tag-warning-bg); color: var(--tag-warning-fg); }
.tag-deadline   { background: var(--tag-danger-bg);  color: var(--tag-danger-fg); }
.tag-field-trip { background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
.event-card { padding: 16px; }
.event-card h4 { font-size: 15px; font-weight: 700; margin-top: 8px; }
.event-card .event-time { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
/* RT-10453 RI-11/RI-13/RI-14: event-cal-btn hover + 44px + 标准 timing */
/* RT-10452 LS-01: 10→8 padding 收敛 */
.event-card .event-cal-btn {
  margin-top: 8px; display: inline-flex; align-items: center; padding: 10px 16px;
  border-radius: 999px; background: var(--primary-light); color: var(--primary-dark);
  font-size: 13px; font-weight: 700; border: none; cursor: pointer;
  min-height: 44px;
  transition: background var(--t-base), color var(--t-base);
}
.event-card .event-cal-btn:hover { background: #CBE0C8; }
.event-card .event-cal-btn:active { background: #BDD6BA; }
.event-card .event-cal-btn.added {
  background: var(--success); color: #fff;
  pointer-events: none; opacity: 0.85;
}
.cal-grid { display: none; }
.cal-grid.active { display: block; }
.cal-list.active { display: block; }
.cal-list { display: none; }
.cal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; font-weight: 600; font-size: 16px; }
/* S-010 §3.2：‹ › 以前 22.5 × 30 —— 翻月是这一屏最常按的两颗 */
.cal-header button { background: none; border: none; font-size: 18px; cursor: pointer; padding: 4px 8px; color: var(--primary); min-width: 44px; min-height: 44px; }
.cal-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 12px; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; }
.cal-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-day { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; font-size: 14px; border-radius: 8px; cursor: default; position: relative; }
.cal-day.today { font-weight: 700; background: var(--primary); color: white; }
.cal-day.has-event { cursor: pointer; }
.cal-day.has-event:active { background: rgba(168,191,171,0.3); }
/* S-010 §3.3：圆点是图形，门槛 3:1。--accent 压白 2.70 → --primary 8.08 */
.cal-day.has-event::after { content: ''; position: absolute; bottom: 4px; width: 5px; height: 5px; border-radius: 50%; background: var(--primary); }
.cal-day.today.has-event::after { background: white; }
.cal-day.other-month { color: #ccc; cursor: default; }
.cal-event-detail { display: none; margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); }
.cal-event-detail.active { display: block; }
.cal-detail-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.cal-detail-date { font-size: 14px; font-weight: 600; color: var(--text); }
.cal-detail-close { background: transparent; border: none; font-size: 16px; color: var(--text-secondary); cursor: pointer; padding: 4px 8px; border-radius: 8px; min-width: 44px; min-height: 44px; }
.cal-detail-close:active { background: var(--bg); }
.cal-detail-events { display: flex; flex-direction: column; gap: 8px; }
.cal-detail-event { background: var(--bg); border-radius: 12px; padding: 12px; }
.cal-detail-event h4 { font-size: 14px; font-weight: 700; margin-top: 4px; }
.cal-detail-event .event-time { font-size: 12.5px; color: var(--text-secondary); margin-top: 2px; }

/* ── Notice history ──────────────────────────────────────── */
.notice-search { position: sticky; top: 0; z-index: 8; background: var(--bg); padding: 4px 0 8px; }
.notice-search input {
  width: 100%; padding: 12px 16px; border: 1.5px solid var(--border);
  border-radius: 999px; font-size: 14px; background: white; outline: none;
  -webkit-appearance: none; font-family: inherit; transition: border-color var(--t-fast);
  min-height: 44px; box-sizing: border-box;   /* BUG-055（t-250）：实测 43 —— 闸 1 无容差（S-022 §1.1），差 1 也是不过 */
}
.notice-search input:focus { border-color: var(--primary); }
.notice-filter { display: flex; gap: 8px; overflow-x: auto; padding: 2px 0 12px; scrollbar-width: none; }
.notice-filter::-webkit-scrollbar { display: none; }
.notice-month-section { margin-bottom: 16px; }
/* T099 / UX-009：**这条「空白」是折叠整月的开关。**
   实测：月份头 44px 高、y 210–254，第一张通知卡从 y 254 开始 —— **间距 0px**。
   点 y=251（视觉上就是两者之间的空白）接住的是月份头，**整月一条不剩**，
   而她没看见自己按了任何按钮，屏幕上只是「东西都没了」。
   第一张卡的上边缘正是翻列表时最自然的落点。
   8px 的间隙让那一带谁都不属于 —— 点空了什么也不发生，比折掉一整月好得多。 */
.notice-month-header {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: transparent; border: none; padding: 8px 4px;
  font-family: inherit; cursor: pointer; text-align: left; min-height: 44px;  /* UX-004 */
  margin-bottom: 8px;
}
/* UIV-03 表一：月份标题换成画板的小号大写分组标题（画板的字是手打的大写；月份是数据，只能靠 CSS 大写） */
.notice-month-header .month-label { color: var(--text-secondary); font-size: 11.5px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; }
.notice-month-header .month-meta { flex: 1; font-weight: 500; font-size: 12px; color: var(--text-secondary); }
.notice-month-header .fold-indicator { font-size: 10px; color: var(--text-secondary); transition: transform var(--t-fast); }
.notice-month-section.folded .fold-indicator { transform: rotate(-90deg); }
.notice-month-section.folded .notice-month-body { display: none; }
/* UIV-03 表一：一条一张卡 → **一张白卡里一行一条**，行间 1px 分割线（画板 SchoolList）。
   白底、圆角、阴影交给列表容器；条目本身透明、无圆角、无阴影（hover 也不再加阴影）。
   `overflow: hidden`：必达那条的 3px 红边在第一 / 最后一条时顺着容器的圆角裁掉一角（design 接受）。
   代价是条目的外圈聚焦环会被裁 —— 所以容器里的条目改用**内圈**（见下面 :focus-visible）。 */
.notice-month-body {
  display: flex; flex-direction: column; gap: 0;
  background: var(--card); border-radius: var(--radius-card); box-shadow: var(--shadow-md);
  overflow: hidden;
}
.notice-item {
  position: relative;                    /* 分割线（::before）按条目定位 */
  display: grid; grid-template-columns: 1fr auto auto; column-gap: 12px; row-gap: 4px;
  align-items: start; background: transparent; border: none; border-radius: 0;
  box-shadow: none; padding: 14px 16px; text-align: left;
  font-family: inherit; cursor: pointer; width: 100%;
  transition: transform var(--t-fast);
}
/* 分割线：**前面有看得见的条目才画**。筛选把条目藏成 `style="display: none"`，
   写成 `.notice-item + .notice-item` 的话，被筛掉那条后面的第一条会顶着一根线。 */
.notice-month-body .notice-item:not([style*="none"]) ~ .notice-item::before {
  content: ""; position: absolute; top: 0; left: 16px; right: 16px; height: 1px;
  background: var(--divider);
}
/* 必达那条左边多 3px 红边：绝对定位从边框**里面**量起，不补的话这一根线比别的行往右错 3px。
   补在 margin 上、不改 left —— 每一行的 left 都还是 16（表一那一格按所有条目量）。 */
.notice-month-body .notice-item:not([style*="none"]) ~ .notice-item.is-urgent::before { margin-left: -3px; }
/* 容器 overflow: hidden 会裁掉全局那圈外环（左右两边整条看不见）—— 改成贴着里面画 */
.notice-month-body .notice-item:focus-visible { box-shadow: inset 0 0 0 2px var(--primary); }
.notice-item:active { transform: scale(0.997); }
.notice-item.is-urgent { border-left: 3px solid var(--danger); padding-left: 13px; }
.notice-item .notice-title { grid-column: 1; grid-row: 1; font-size: 14px; font-weight: 700; color: var(--text); line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.notice-item .notice-status { grid-column: 2; grid-row: 1; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; }
.notice-item .status-icon { font-size: 16px; line-height: 1.1; }
/* 状态色点（取代 emoji 状态图标） */
.status-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.status-dot.ok      { background: var(--success); }
.status-dot.pending { background: var(--accent); }
.status-dot.urgent  { background: var(--danger); box-shadow: 0 0 0 3px var(--tag-danger-bg); }
.notice-item .notice-date { font-size: 12px; color: var(--text-secondary); font-weight: 400; white-space: nowrap; }
.notice-item .notice-tag-row { grid-column: 1 / 3; grid-row: 2; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* RT-10453 RI-09: notice-type-tag 走 semantic token */
.notice-type-tag { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 999px; background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
.notice-type-tag.t-homework { background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
.notice-type-tag.t-event    { background: var(--tag-success-bg); color: var(--tag-success-fg); }
.notice-type-tag.t-meeting  { background: var(--tag-warning-bg); color: var(--tag-warning-fg); }
.notice-type-tag.t-system   { background: var(--tag-info-bg);    color: var(--tag-info-fg); }
/* action_type 的五个值（docs/SCHOOL-TAB.md）。要动手的三种给暖色，读和知会给中性。 */
.notice-type-tag.t-sign     { background: var(--tag-warning-bg); color: var(--tag-warning-fg); }
.notice-type-tag.t-respond  { background: var(--tag-warning-bg); color: var(--tag-warning-fg); }
.notice-type-tag.t-attend   { background: var(--tag-warning-bg); color: var(--tag-warning-fg); }   /* PD-0084 ①：与回答同档 —— 要她动手 */
.notice-type-tag.t-prepare  { background: var(--tag-success-bg); color: var(--tag-success-fg); }
.notice-type-tag.t-study    { background: var(--tag-info-bg);    color: var(--tag-info-fg); }
.notice-type-tag.t-inform   { background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
.notice-item .notice-snippet { font-size: 12px; color: var(--text-secondary); font-weight: 400; }
/* UIV-03 表三 · PD-0078 ①（T088 压画板）：行首图标块只给 sign / respond 两类 —— 琥珀那一对（与同一行的类型标签同色语言），
   40 · 圆角 12 · 图 19 · 笔宽 2。其余三类行首不留位（不做幽灵缩进），所以只有 .has-icon 那一行多一列。 */
.notice-item.has-icon { grid-template-columns: 40px 1fr auto auto; }
.notice-item .ni-icon {
  grid-column: 1; grid-row: 1 / 3; align-self: start;
  width: 40px; height: 40px; border-radius: var(--radius-sm);
  background: var(--tag-warning-bg); color: var(--tag-warning-fg);
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.notice-item .ni-icon svg { width: 19px; height: 19px; stroke: var(--tag-warning-fg); stroke-width: 2; fill: none; }
.notice-item.has-icon .notice-title { grid-column: 2; }
.notice-item.has-icon .notice-status { grid-column: 3; }
.notice-item.has-icon .notice-tag-row { grid-column: 2 / 4; }
.notice-item.has-icon .ni-chevron { grid-column: 4; }
/* UIV-03 表三：行尾折角。装饰 —— 整行才是按钮，读屏不念它（aria-hidden） */
.notice-item .ni-chevron {
  grid-column: 3; grid-row: 1 / 3; align-self: center;
  width: 17px; height: 17px; stroke: var(--icon-muted); stroke-width: 2.2; fill: none;
}
#notice-empty .icon { font-size: 32px; display: block; margin-bottom: 8px; }

/* ── Resources (学习资料) ──────────────────────────────── */
.resources-hint { font-size: 13px; color: var(--text-secondary); padding: 0 4px 8px; line-height: 1.5; }
.resources-search { padding: 0 0 8px; }
.resources-search input {
  width: 100%; padding: 8px 12px; border-radius: 8px;
  border: 1.5px solid var(--border); background: white;
  font-size: 14px; font-family: inherit; outline: none;
  min-height: 44px; box-sizing: border-box;   /* BUG-055（t-250）：35 → 44。输入框是替换元素，伪元素撑不了，只能自己长到 44 */
}
.resources-search input:focus { border-color: var(--primary); }
.resources-filter { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 0 12px; }
.resource-list { display: flex; flex-direction: column; gap: 8px; }
.resource-item {
  display: flex; gap: 12px; align-items: flex-start;
  background: white; border-radius: var(--radius); box-shadow: var(--shadow-md);
  padding: 16px; text-decoration: none; color: inherit;
  transition: transform var(--t-fast), box-shadow var(--t-fast);
}
.resource-item:hover { box-shadow: var(--shadow-lg); }
.resource-item:active { transform: scale(0.997); }
.resource-item .resource-icon { line-height: 1.1; flex-shrink: 0; color: var(--primary); display: flex; align-items: center; }
.resource-item .resource-meta { flex: 1; min-width: 0; }
.resource-item .resource-title {
  font-size: 15px; font-weight: 700; color: var(--text); line-height: 1.35;
  margin-bottom: 4px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.resource-item .resource-sub { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 12px; color: var(--text-secondary); }
/* RT-10453 RI-09: resource-kind-tag 走 semantic token */
.resource-kind-tag { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 999px; background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
.resource-kind-tag.t-article { background: var(--tag-info-bg);    color: var(--tag-info-fg); }
.resource-kind-tag.t-video   { background: var(--tag-danger-bg);  color: var(--tag-danger-fg); }
.resource-kind-tag.t-podcast { background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
.resource-kind-tag.t-other   { background: var(--tag-warning-bg); color: var(--tag-warning-fg); }
.resource-item .resource-date { font-size: 11px; font-weight: 500; }
#resource-empty .icon { font-size: 32px; display: block; margin-bottom: 8px; }

/* ── Photos ──────────────────────────────────────────────── */
.photo-privacy-banner {
  display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px;
  background: var(--primary-light); border: none; border-radius: 14px; margin: 0 0 16px;   /* UIV-06：上距 4 → 0 */
}
.photo-privacy-banner .icon { line-height: 1.4; flex-shrink: 0; color: var(--primary-dark); margin-top: 1px; }
.photo-privacy-banner .text { font-size: 12.5px; line-height: 1.5; color: var(--primary-dark); }
.photo-privacy-banner .text strong { color: var(--primary-dark); font-weight: 700; }
/* UIV-06（画板 CPhotos）：白底无边、4 / 10、推到行尾（「+ Add」跟在后面）。
   以前「仅查看」和「可下载」长得一样（都是 --bg 底 + 1px 边 + 灰字）—— 一眼分不出这本能不能存。
   「开着」的那本（.on）换叶绿对；胶囊里一枚 12px 图标（眼睛 / 下载），笔色跟字走。 */
.photo-permission-tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 600; color: var(--text-secondary);
  background: var(--card); border: none;
  border-radius: 999px; padding: 4px 10px; margin-left: auto; vertical-align: middle;
}
.photo-permission-tag.on { color: var(--primary-dark); background: var(--primary-light); }
.photo-permission-tag svg { width: 12px; height: 12px; flex-shrink: 0; }
/* 开相册的人看到的那一枚是开关（2026-09-29）：长得和标签一样，只是点得动 */
button.photo-permission-tag.perm-toggle { border: 1px solid var(--border); font: inherit; font-size: inherit; font-weight: inherit; cursor: pointer; }
button.photo-permission-tag.perm-toggle.on { border-color: transparent; }
.photo-group-label { font-family: var(--font-display); font-size: 15.5px; font-weight: 700; margin: 16px 0 8px; }
.photo-group-label:first-child { margin-top: 0; }
.photo-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.photo-card { aspect-ratio: 1; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 32px; cursor: pointer; transition: transform var(--t-fast), filter var(--t-fast); }
.photo-card:hover { filter: brightness(0.96); }
.photo-card:active { transform: scale(0.95); }

/* RT-10390 AC3: new album red dot */
.photo-card { position: relative; }
.photo-card.is-new::after {
  content: ''; position: absolute; top: 6px; right: 6px;
  width: 10px; height: 10px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 2px white, 0 0 6px rgba(221, 138, 62, 0.6);
  animation: newDotPulse 1.6s ease-in-out infinite;
}
@keyframes newDotPulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%       { transform: scale(1.18); opacity: 0.85; }
}
.photo-group-label .new-flag {
  display: inline-block; margin-left: 6px; font-size: 10px; font-weight: 700;
  color: white; background: var(--accent); padding: 2px 6px; border-radius: 999px;
  vertical-align: middle; letter-spacing: 0.3px;
}

/* Photo modal */
.photo-modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.85); z-index: 200; align-items: center; justify-content: center; padding: 20px; }
.photo-modal.show { display: flex; }
.photo-modal-content {
  width: 100%; max-width: 360px; aspect-ratio: 1; border-radius: 16px;
  display: flex; align-items: center; justify-content: center; font-size: 80px;
  position: relative; touch-action: pan-y;
  transition: transform var(--t-slow) cubic-bezier(.2,.8,.2,1); will-change: transform;
}
.photo-modal-content.dragging { transition: none; }
.photo-modal-counter {
  position: absolute; top: calc(env(safe-area-inset-top, 0px) + 12px); right: 16px;
  background: rgba(0,0,0,0.55); color: white; border-radius: 22px; padding: 6px 12px;
  font-size: 13px; font-weight: 500; z-index: 1; pointer-events: none;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); display: none;
}
.photo-modal-counter.show { display: inline-block; }
.photo-modal-edge-hint {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  background: rgba(0,0,0,0.7); color: white; border-radius: 18px; padding: 8px 16px;
  font-size: 14px; z-index: 2; pointer-events: none; opacity: 0; transition: opacity var(--t-fast);
  white-space: nowrap; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.photo-modal-edge-hint.show { opacity: 1; }
.photo-modal-topbar {
  position: absolute; top: 0; left: 0; right: 0;
  padding: calc(env(safe-area-inset-top, 0px) + 12px) 12px 12px;
  display: flex; align-items: center; z-index: 1; pointer-events: none;
}
.photo-modal-back {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(0,0,0,0.55); color: white; border: none; border-radius: 22px;
  padding: 9px 16px 9px 12px; font-size: 15px; font-weight: 500; cursor: pointer;
  pointer-events: auto; -webkit-tap-highlight-color: transparent;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.photo-modal-back:active { background: rgba(0,0,0,0.75); }
.photo-modal-back-arrow { font-size: 22px; line-height: 1; margin-right: 2px; display: inline-block; transform: translateY(-1px); }
.photo-modal-hint {
  position: absolute; bottom: calc(env(safe-area-inset-bottom, 0px) + 18px);
  left: 0; right: 0; text-align: center; color: rgba(255,255,255,0.7); font-size: 13px; pointer-events: none;
}

/* ── Community ───────────────────────────────────────────── */
/* UIV-07 表一：间距 6、上下内边距 0（横向滚动条早已隐藏，下面那 12 不再需要）、下距 14 */
.community-filter { display: flex; gap: 6px; overflow-x: auto; padding: 0; margin-bottom: 14px; scrollbar-width: none; }
.community-filter::-webkit-scrollbar { display: none; }
/* RT-10453 RI-11/RI-13: filter-chip hover + min-height 44px */
/* RT-10452 LS-01: 10→8 padding 收敛 */
.filter-chip {
  flex-shrink: 0; background: white; border: 1.5px solid var(--border); border-radius: 999px;
  padding: 8px 16px; font-size: 13px; font-weight: 600; color: var(--text-secondary); cursor: pointer; white-space: nowrap;
  min-height: 44px;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.filter-chip:hover { background: var(--bg); border-color: var(--text-secondary); color: var(--text); }
.filter-chip.active { background: var(--primary); border-color: var(--primary); color: white; }
.filter-chip.active:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
/* UIV-07：家长圈的筛选胶囊去边框（未选白底压 --bg 靠底色分开）、12.5 · 9 / 15；选中换头部同色 --primary-deep。
   只改家长圈这一排 —— 校方 / 资料那两排不在这张表里。 */
.community-filter .filter-chip { border: 0; padding: 9px 15px; font-size: 12.5px; }
.community-filter .filter-chip:hover:not(.active) { background: var(--card); color: var(--text); }
.community-filter .filter-chip.active { background: var(--primary-deep); font-weight: 700; }
.community-card { padding: 16px; }
.community-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.avatar { width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-weight: 700; font-size: 15px; flex-shrink: 0; }
.community-meta { flex: 1; }
.community-meta .name { font-weight: 700; font-size: 14px; }
.community-meta .time { font-size: 12px; color: var(--text-secondary); }
/* RT-10453 RI-09: post-type 走 semantic token (4 semantic + neutral) */
/* UIV-07：所有类别胶囊 11 / 700 · 999 · 4 / 10（列表与详情纸同一个类，一起变） */
.post-type { font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 999px; }
/* PD-0072 v2（S-019 §4）：接送 / 礼物的字照画板那一枚暖橙（压底 4.48，进闸 8 豁免表）；底仍是琥珀那一对的底 */
.post-type.pickup   { background: var(--tag-warning-bg); color: var(--accent-text); }
.post-type.playdate { background: var(--tag-success-bg); color: var(--tag-success-fg); }
/* UIV-07：礼物从中性灰改琥珀（画板礼物 = 接送同一对） */
.post-type.gift     { background: var(--tag-warning-bg); color: var(--accent-text); }
.post-type.carpool  { background: var(--tag-info-bg);    color: var(--tag-info-fg); }
.post-type.question { background: var(--tag-info-bg);    color: var(--tag-info-fg); }
.post-type.other    { background: var(--tag-neutral-bg); color: var(--tag-neutral-fg); }
/* RT-10452 LS-05: 12→8 sub-item 间距 (body→actions) */
.community-body { font-size: 14px; line-height: 1.5; margin-bottom: 8px; }
/* T129：列表里只给前两行。**截行不截字** —— 按渲染出来的行断，不挑魔数、不切词。
   整文仍然在 DOM 里，点进详情看到的是同一份 —— 详情那一处**不带这个类**，
   所以不受影响。（T137 把详情从 `.post-detail-card` 那张卡改成了纸上的直排，
   两处仍然共用 `.community-body`，区别始终只是这个类在不在。） */
.community-snippet { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
/* T130：删是破坏性的，颜色要说出来；但**不靠颜色单编码** —— 图标也换了（垃圾桶）。 */
.post-menu-item.is-danger { color: var(--danger); }   /* 兜底色去掉：--danger 早在 :root，旧兜底 #A03528 已不是这套色（UIV-07 §5 改值 #B3452F） */
.community-actions { display: flex; gap: 8px; }
/* RT-10453 RI-11/RI-13: community action buttons hover + min-height */
/* RT-10452 LS-01/LS-02: 11→12, 9→8 收敛到标准 scale */
.community-actions button {
  flex: 1; padding: 12px 8px; border-radius: 999px;
  font-size: 13px; font-weight: 700;
  border: 1.5px solid var(--border); background: white; cursor: pointer;
  min-height: 44px;
  transition: background var(--t-base), border-color var(--t-base), color var(--t-base);
}
.community-actions button:hover { background: var(--bg); border-color: var(--text-secondary); }
.community-actions button:active { background: var(--primary-light); }
.community-actions button.primary-action { background: var(--primary); color: white; border-color: var(--primary); }
.community-actions button.primary-action:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.community-actions button.primary-action:active { opacity: 0.85; }

/* RT-10390 AC4: post title clamp + image preview */
.community-card .post-title { font-size: 15px; font-weight: 700; line-height: 1.4; color: var(--text); margin-bottom: 8px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
.community-card .post-image { width: 100%; aspect-ratio: 16 / 9; border-radius: 12px; margin: 8px 0 12px; background-position: center; background-size: cover; display: flex; align-items: center; justify-content: center; font-size: 42px; position: relative; overflow: hidden; }
.community-card .post-image .img-count { position: absolute; bottom: 6px; right: 8px; background: rgba(0,0,0,0.6); color: white; font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 8px; }

/* RT-10390 AC6: unread posts */
.community-card.unread { position: relative; border-left: 4px solid var(--accent); padding-left: 12px; background: linear-gradient(to right, var(--accent-light) 0%, var(--card) 60px); transition: border-color var(--t-slow) ease, background var(--t-slow) ease; }
/* The unread badge text is injected via JS from i18n — but keep the pseudo CSS here */
.community-card.unread::after {
  position: absolute; top: 12px; right: 12px; font-size: 10px; font-weight: 700;
  color: var(--accent-deep); background: var(--accent-light); padding: 2px 7px; border-radius: 999px;
  letter-spacing: 0.3px; pointer-events: none;
  content: attr(data-unread-label);
}
.community-card.read-fading { border-left-color: transparent; background: var(--card); }

/* ── Circle：真实数据渲染出来的卡片 ───────────────────────── */
.community-card { position: relative; }
/* S-012 §3.1：铺满整张卡的透明按钮 —— 读屏器与键盘从这里进详情；看得见的一个像素都没变 */
.community-card > .post-open {
  position: absolute; inset: 0; z-index: 1; margin: 0; padding: 0; border: 0;
  background: transparent; border-radius: inherit; cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
.community-card .mine-tag {
  margin-left: 6px; font-size: 10.5px; font-weight: 700; letter-spacing: 0.2px;
  padding: 2px 7px; border-radius: 999px;
  background: var(--primary-light); color: var(--primary-dark);
}
/* ⋯ 菜单：举报是家长唯一能把一条帖子送到老师面前的动作 */
/* S-012 §3.2：32 见方（命中 33）→ 44。负边距把多出来的占位抵回去：
   占位仍是 30 × 24、图标中心不动（(346, 241) 修前修后同一点）。
   position/z-index：叠在铺满整张卡的 .post-open（z 1）上面 —— 点 ⋯ 开菜单，不开详情。 */
.post-menu-btn {
  position: relative; z-index: 2;
  flex-shrink: 0; width: 44px; height: 44px; margin: -10px -10px -10px -4px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; border-radius: 50%;
  color: var(--text-secondary); cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.post-menu-btn:hover { background: var(--bg); color: var(--text); }
/* UIV-07 表四：⋯ 底下一枚 28px 的 --bg 圆（画板 CircleList）。画在 ::before 上、居中 ——
   按钮本体仍是 44×44 命中区（UX-004），不缩。z-index -1：落在图标下面、按钮自己的层里。 */
.post-menu-btn::before {
  content: ""; position: absolute; left: 50%; top: 50%; width: 28px; height: 28px;
  margin: -14px 0 0 -14px; border-radius: 50%; background: var(--bg); z-index: -1;
}
.post-menu {
  position: absolute; top: 46px; right: 12px; z-index: 20;
  min-width: 188px; padding: 6px;
  /* UIV-07：无边、14 圆角、更深的弹出投影（画板 CircleList） */
  background: var(--card); border: 0; border-radius: var(--radius-note);
  box-shadow: var(--shadow-pop);
}
.post-menu[hidden] { display: none; }
/* t-213：往下放不下时从 ⋯ 上面展开（bottom 由 tab-community.js 按实时几何写） */
.post-menu.opens-up { top: auto; }
.post-menu-item {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px;
  padding: 10px 10px 10px 11px; border: none; border-radius: 8px; background: none;   /* UIV-07：左 11、13.5；普通项 600 */
  font-size: 13.5px; font-weight: 600; color: var(--text); text-align: left; cursor: pointer;
}
/* UIV-07：画板上「举报」是红的（以前只有「删除」红）；红项 700（design 10:38：Report、Delete）；旗子图标跟着换（§8） */
.post-menu-item[data-action="report"], .post-menu-item.is-danger { font-weight: 700; }
.post-menu-item[data-action="report"] { color: var(--danger); }
.post-menu-item[data-action="report"] svg { color: var(--danger); }
.post-menu-item:hover { background: var(--bg); }
.post-menu-item[disabled] { color: var(--text-secondary); cursor: default; }
.post-menu-item[disabled]:hover { background: none; }
.post-menu-item svg { flex-shrink: 0; color: var(--accent-deep); }
.post-menu-item[disabled] svg { color: var(--text-secondary); }
/* 加载 / 失败 / 未登录 —— 有话直说，不拿假数据顶上 */
.circle-status {
  padding: 16px; margin-bottom: 12px;
  background: var(--card); border: 1px dashed var(--border); border-radius: var(--radius);
  font-size: 13px; line-height: 1.5; color: var(--text-secondary); text-align: center;
}
.circle-status[hidden] { display: none; }
.post-detail-card .post-title { font-size: 16px; font-weight: 700; line-height: 1.4; margin-bottom: 8px; }

/* ── New-post modal ──────────────────────────────────────── */
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: flex-end; justify-content: center; }
.modal-overlay.show { display: flex; }
.modal-sheet { background: white; border-radius: 20px 20px 0 0; padding: 24px 20px; width: 100%; max-width: 480px; max-height: 80dvh; overflow-y: auto; }
@media (min-width: 768px) { .modal-sheet { max-width: 600px; } }
@media (min-width: 1024px) { .modal-sheet { max-width: 720px; } }
.modal-sheet h3 { font-size: 18px; margin-bottom: 4px; }
.modal-sheet .modal-hint { font-size: 12px; color: var(--text-secondary); margin-bottom: 16px; }
.modal-sheet label { display: block; font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; margin-top: 16px; }
.modal-sheet label:first-of-type { margin-top: 0; }
.modal-sheet input[type="text"], .modal-sheet select, .modal-sheet textarea { width: 100%; padding: 8px 12px; border: 1.5px solid var(--border); border-radius: 8px; font-size: 14px; font-family: inherit; resize: vertical; box-sizing: border-box; }
.modal-sheet textarea { min-height: 80px; }
.modal-sheet .segment-tabs { display: flex; background: var(--bg); border: 1.5px solid var(--border); border-radius: 12px; padding: 4px; margin: 4px 0 16px; gap: 2px; }
/* RT-10452 LS-01: 横向 10→8 收敛 */
.modal-sheet .segment-tab { flex: 1; background: transparent; border: none; border-radius: 8px; padding: 12px 8px; font-size: 13.5px; font-weight: 600; color: var(--text-secondary); cursor: pointer; min-height: 44px; transition: background var(--t-fast), color var(--t-fast); }
.modal-sheet .segment-tab:hover { color: var(--text); }
.modal-sheet .segment-tab.active { background: var(--card); color: var(--primary); box-shadow: var(--shadow-sm); }
.modal-sheet .post-more { display: none; }
.modal-sheet .post-more.show { display: block; }
.modal-sheet .template-field { margin-top: 8px; }
.modal-sheet .template-field input[type="text"] { padding: 8px 12px; font-size: 13.5px; }
.modal-sheet .preselect-tag { display: inline-flex; align-items: center; gap: 6px; background: var(--primary-light); color: var(--primary); padding: 4px 12px; border-radius: 999px; font-size: 12px; font-weight: 600; margin-bottom: 8px; }
.modal-sheet .preselect-tag .clear-preselect { background: none; border: none; color: var(--primary); font-size: 14px; cursor: pointer; padding: 0; line-height: 1; }
.modal-sheet .type-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 4px; }
.modal-sheet .type-chip { background: var(--bg); border: 1.5px solid var(--border); border-radius: 999px; padding: 6px 12px; font-size: 12px; font-weight: 600; color: var(--text-secondary); cursor: pointer; }
.modal-sheet .type-chip.active { background: var(--primary-light); border-color: var(--primary); color: var(--primary); }
.modal-sheet .template-collapsed-row { display: none; align-items: center; gap: 8px; padding: 6px 12px; background: var(--primary-light); border: 1px solid var(--primary); border-radius: 999px; font-size: 12px; font-weight: 600; color: var(--primary); cursor: pointer; margin-bottom: 4px; width: fit-content; }
.modal-sheet .template-collapsed-row.show { display: inline-flex; }
/* S-012 §3.3 ①：换成 button 后的外观归零。**不写 width: 100%** —— 它在弹层里是自适应宽度的胶囊 */
.modal-sheet button.template-collapsed-row { font-family: inherit; line-height: inherit; text-align: left; -webkit-appearance: none; appearance: none; }
/* §3.3 ②：「Type」--text-secondary 压 --primary-light 是 4.17 → --primary 6.51 */
.modal-sheet .template-collapsed-row .label { color: var(--primary); font-weight: 500; }
.modal-sheet .template-collapsed-row .current-type { font-weight: 700; }
.modal-sheet .template-collapsed-row .expand-hint { color: var(--primary); font-size: 11px; opacity: 0.85; }
.modal-sheet .image-upload-btn { background: var(--bg); border: 1.5px dashed var(--border); border-radius: 8px; padding: 12px 16px; font-size: 13px; color: var(--text-secondary); cursor: pointer; margin: 8px 0 8px; width: 100%; text-align: center; }
.modal-sheet .image-thumb-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }
.modal-sheet .image-thumb-grid:empty { display: none; }
.modal-sheet .image-thumb { position: relative; width: 64px; height: 64px; border-radius: 8px; background: #E5E7EB; }
.modal-sheet .image-thumb .remove-thumb { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; border-radius: 50%; background: #1F2937; color: white; border: 2px solid white; font-size: 12px; line-height: 1; cursor: pointer; padding: 0; display: flex; align-items: center; justify-content: center; }
/* 「谁能看到」是一行**已经填好的**摘要，点开才有细节。
   一旦做成摆在发帖页上的选择器，失败模式就回来了：忘了改、改错了，
   代价是毁掉的惊喜或者一次泄漏。见 docs/PRODUCT-STRUCTURE.md 约束一。 */
.visibility-summary { margin-top: 16px; }
.visibility-summary .vis-row {
  /* S-012 §3.2：Ask 模式单行时高 39 → 44（Post 模式两行本来 55） */
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px;
  padding: 12px; border: none; border-left: 3px solid var(--accent); border-radius: 8px;
  background: var(--accent-light); color: var(--accent-deep);
  font-size: 12.5px; text-align: left; cursor: pointer;
}
.visibility-summary .vis-icon { display: flex; flex-shrink: 0; }
.visibility-summary .vis-label { font-weight: 700; flex-shrink: 0; }
.visibility-summary .vis-value { flex: 1; font-weight: 600; color: var(--text); }
/* UIV-07 表三：去左边条、12 圆角、间距 10；标签 11 大写 · 0.4 · 画板暖橙字（PD-0072 v2，4.48，豁免表）；值 13 / 700 */
#new-post-modal .visibility-summary .vis-row { border-left: 0; border-radius: var(--radius-sm); gap: 10px; }
#new-post-modal .visibility-summary .vis-label { font-size: 11px; letter-spacing: 0.4px; text-transform: uppercase; color: var(--accent-text); }
#new-post-modal .visibility-summary .vis-value { font-size: 13px; font-weight: 700; }
.visibility-summary .vis-chevron { display: flex; flex-shrink: 0; transition: transform var(--t-fast); }
.visibility-summary .vis-row[aria-expanded="true"] .vis-chevron { transform: rotate(180deg); }
.visibility-summary .vis-details {
  padding: 12px 12px 4px 15px; font-size: 12.5px; line-height: 1.55; color: var(--text-secondary);
}
.visibility-summary .vis-details[hidden] { display: none; }
.visibility-summary .vis-details p { margin-bottom: 8px; }
/* 举报会让老师读到 —— 说在前面，所以要比其余说明显眼一档 */
.visibility-summary .vis-details p.vis-warn { color: var(--accent-deep); font-weight: 600; }
.visibility-summary .vis-details p.vis-warn[hidden] { display: none; }
.visibility-summary .vis-details p[hidden] { display: none; }
.modal-sheet .template-field select {
  width: 100%; padding: 10px 12px; border: 1.5px solid var(--border); border-radius: 8px;
  font-size: 13.5px; font-family: inherit; background: var(--card); color: var(--text);
}
.modal-sheet .template-field select:disabled { color: var(--text-secondary); background: var(--bg); }
.modal-sheet .publish-rules-link { background: none; border: none; color: var(--primary); font-size: 12px; text-decoration: underline; padding: 4px 0; margin: 4px 0 0; cursor: pointer; align-self: flex-start; }
/* S-012 §3.3 ②：「N required field(s) left」以前是 --danger 压写死的粉底 4.30 —— 她刚打开弹层、
   一个字没写就看见一个红框。**还没填完不是填错了**（「Post」灰着已经在说「还不能发」）。
   中性那一对说「还差几格」5.32，填齐了转 token 绿；去边。 */
.modal-sheet .post-required-counter { display: flex; align-items: center; gap: 8px; margin-top: 16px; padding: 8px 12px; border-radius: 8px; background: var(--tag-neutral-bg); border: 0; color: var(--tag-neutral-fg); font-size: 12.5px; font-weight: 600; line-height: 1.4; }
.modal-sheet .post-required-counter.complete { background: var(--tag-success-bg); color: var(--tag-success-fg); }
.modal-sheet label .required-asterisk { color: var(--danger); font-weight: 700; margin-left: 2px; }
.modal-sheet .modal-btns { display: flex; gap: 8px; margin-top: 20px; }
/* RT-10453 RI-11/RI-13: modal buttons hover + min-height 44px */
/* RT-10452 LS-02: 13→12 收敛到标准 scale (min-height 44 兜底) */
/* **同一族的第三份本体**（`.btn-post` / `.btn-cancel` 在弹层里被整体改写）。
   它把圆角改成 999，于是同一颗按钮在弹层里是胶囊、在别处是圆角矩形 ——
   实测「Close」两颗正是被这一条盖住的。圆角并回 token，其余照旧。 */
/* Circle 详情那张纸不是 .modal-sheet —— 套上 UIV-03 的壳之后（T137）它的 Close 也要是同一颗（design 09-11） */
.post-detail-sheet .modal-btns button,
.modal-sheet .modal-btns button {
  flex: 1; padding: 12px; border-radius: var(--radius-btn);
  font-size: 15px; font-weight: 700; cursor: pointer; border: none;
  min-height: 44px;
  transition: background var(--t-base), opacity var(--t-base);
}
.modal-sheet .btn-cancel, .post-detail-sheet .btn-cancel { background: var(--border); color: var(--text); }
.modal-sheet .btn-cancel:hover, .post-detail-sheet .btn-cancel:hover { background: #D1D5DB; }
.modal-sheet .btn-post { background: var(--primary); color: white; }
.modal-sheet .btn-post:hover:not(:disabled) { background: var(--primary-dark); }
/* UIV-07：未填完的「Post」—— 以前写死 Tailwind 灰 #E5E7EB / #9CA3AF，换成这套色（不可点态，不算对比度） */
.modal-sheet .btn-post:disabled { background: var(--border); color: var(--text-disabled); cursor: not-allowed; opacity: 1; }

/* Publishing rules popover */
.publish-rules-popover { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1100; display: none; align-items: center; justify-content: center; padding: 24px; }
.publish-rules-popover.show { display: flex; }
.publish-rules-popover .popover-card { background: var(--card); border-radius: 12px; padding: 20px 20px 16px; max-width: 420px; width: 100%; max-height: 80dvh; overflow-y: auto; }
.publish-rules-popover .popover-card h4 { margin: 0 0 8px; font-size: 15px; color: var(--text); }
.publish-rules-popover .popover-card ul { margin: 0; padding-left: 18px; font-size: 12.5px; line-height: 1.7; }
.publish-rules-popover .popover-card li.ok { color: #166534; }
.publish-rules-popover .popover-card li.no { color: #991B1B; }
.publish-rules-popover .popover-card .timing-note { margin-top: 8px; font-size: 11.5px; color: var(--text-secondary); line-height: 1.5; }
.publish-rules-popover .popover-close { margin-top: 12px; width: 100%; background: var(--primary); color: white; border: none; padding: 12px; border-radius: var(--radius-btn); font-size: 14px; font-weight: 600; cursor: pointer; min-height: 44px; }

/* 深色页眉左上角那颗返回图标。**一份本体，谁用谁挂 class** ——
   /settings 与 /tuition 用的是同一颗（T104 判据 2：不要第三种做法）。
   44×44 是 UX-004 量出来的：spec 要 44，实测只有 38。 */
.back-btn {
  background: transparent;
  border: none;
  color: #D8E4D6;
  width: 44px; height: 44px;
  border-radius: 999px;
  font-size: 18px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

/* ── 摘要卡：家长收到的那份小结的形状 ──────────────────────
   **一份本体，两页共用**：家长端在详情里读它，老师端在 T113 里用同一个形状
   看「家长收到了什么」。老师那一份不带打钩（她不是在完成这些事）。 */
.sd-summary { background: var(--bg); border: 1.5px solid var(--border); border-radius: 14px; padding: 12px 14px; margin: 10px 0 12px; }
.sd-summary[hidden] { display: none; }
.sd-sum-head { font-size: 11.5px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-secondary); margin: 10px 0 4px; }
.sd-for-me { margin: -2px 0 6px; }
.sd-for-child { background: var(--accent-light); border-radius: 10px; padding: 8px 10px; margin-bottom: 6px; }
.sd-for-child .sd-sum-head { color: var(--accent-deep); margin: 0 0 2px; }
.sd-for-text { font-size: 14px; font-weight: 600; line-height: 1.4; }
.sd-summary-text { margin: 0; font-size: 14px; line-height: 1.5; }
.sd-summary ul { list-style: none; margin: 0; padding: 0; }
.sd-optional li, .sd-info li { font-size: 13.5px; line-height: 1.45; padding: 3px 0 3px 14px; position: relative; }
.sd-optional li::before, .sd-info li::before { content: "•"; position: absolute; left: 2px; color: var(--text-secondary); }
/* **元素选择器前面那个 `li` 不是装饰，是这两条能不能生效的全部理由。**
   学校详情整块在 `.modal-sheet` 里，而 index.css（后加载）有两条同特异度的：
     .modal-sheet label { display: block }      ← 把这一行的 flex 打掉
     .modal-sheet input { width: 100% }         ← 把 18px 的勾拉成整行宽
   特异度打平时后加载的赢，于是打钩框掉到自己一行、宽 320px 看着像浮在中间，
   标题和日期贴成「Sign the permission slipSep 12」——**用户报的「样式出问题」就是它**。
   加个 `li` 把特异度抬到 (0,1,2)，**跟文件先后无关地**赢过 (0,1,1)。
   （同一族：T131 是 display/opacity 打架，这一条是同特异度靠顺序决胜 —— 都属
   「两条规则都对，合在一起错」。） */
li.sd-todo label { display: flex; align-items: flex-start; gap: 10px; padding: 6px 0; cursor: pointer; }
li.sd-todo input { width: 18px; height: 18px; margin-top: 2px; flex: none; accent-color: var(--primary); }
.sd-todo-text { flex: 1; font-size: 14px; line-height: 1.4; font-weight: 600; }
.sd-todo.done .sd-todo-text { text-decoration: line-through; color: var(--text-secondary); font-weight: 500; }
.sd-todo-tag { font-size: 11px; font-weight: 700; color: var(--tag-warning-fg); background: var(--tag-warning-bg); border-radius: 999px; padding: 1px 7px; margin-left: 4px; white-space: nowrap; }
.sd-todo-when { font-size: 12px; font-weight: 700; color: var(--primary); white-space: nowrap; margin-top: 2px; margin-left: 8px; }
/* §3.5：实测高 31.8 —— 命中区不足 44。 */
.sd-full-toggle { display: block; width: 100%; min-height: 44px; margin-top: 10px; background: transparent; border: 1.5px solid var(--border); border-radius: 999px; font-family: inherit; font-size: 12.5px; font-weight: 700; color: var(--primary); padding: 7px 10px; cursor: pointer; }
.sd-body.folded { display: none; }

/* Post detail overlay */
.post-detail-overlay { position: fixed; inset: 0; background: var(--bg); z-index: 1200; display: none; flex-direction: column; overflow: hidden; }
.post-detail-overlay.show { display: flex; }
.post-detail-topbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--card); border-bottom: 1px solid var(--border); flex-shrink: 0; }
.post-detail-topbar .back-btn { background: none; border: none; font-size: 26px; line-height: 1; color: var(--text); cursor: pointer; padding: 4px 8px; margin: -4px 0; }
.post-detail-topbar .title { font-size: 15px; font-weight: 700; color: var(--text); }
.post-detail-status-row { display: flex; align-items: center; gap: 8px; padding: 12px 16px; background: var(--card); border-bottom: 1px solid var(--border); font-size: 12px; color: var(--text-secondary); flex-shrink: 0; }
/* RT-10452 LS-01: 横向 10→12 收敛 (pill 需横向呼吸) */
.post-status-pill { display: inline-flex; align-items: center; gap: 4px; padding: 4px 12px; border-radius: 999px; font-size: 12px; font-weight: 700; border: 1px solid transparent; line-height: 1.2; }
.post-status-pill.pending  { background: #FEF3C7; color: #92400E; border-color: #FCD34D; }
.post-status-pill.pending::before  { content: '🟡 '; }
.post-status-pill.rejected { background: #FEE2E2; color: #991B1B; border-color: #FCA5A5; }
.post-status-pill.rejected::before { content: '🔴 '; }
.post-status-pill.published { background: #DCFCE7; color: #166534; border-color: #86EFAC; }
.post-status-pill.published::before { content: '✅ '; }
.post-detail-body { flex: 1; overflow-y: auto; padding: 16px; }
.post-detail-card { background: var(--card); border-radius: 12px; padding: 16px; box-shadow: var(--shadow-sm); }
.post-detail-card .community-body { font-size: 14px; line-height: 1.55; color: var(--text); margin-bottom: 8px; white-space: pre-wrap; word-break: break-word; }
.post-detail-image-row { position: relative; margin-top: 8px; }
.post-detail-image-row .scroll-track { display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; border-radius: 12px; }
.post-detail-image-row .scroll-track::-webkit-scrollbar { display: none; }
.post-detail-image-row .img-cell { flex: 0 0 100%; height: 200px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 36px; scroll-snap-align: start; }
.post-detail-image-row .page-counter { position: absolute; right: 8px; bottom: 8px; background: rgba(0,0,0,0.55); color: white; padding: 4px 8px; border-radius: 999px; font-size: 11.5px; font-weight: 600; letter-spacing: 0.3px; pointer-events: none; }
.first-reply-preview { background: var(--card); border-radius: 12px; padding: 12px 16px; margin-top: 12px; }
.first-reply-preview .reply-label { font-size: 11.5px; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; letter-spacing: 0.3px; }
.first-reply-preview .reply-row { display: flex; gap: 8px; align-items: flex-start; }
.first-reply-preview .reply-row .avatar { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 12px; color: white; font-weight: 600; }
.first-reply-preview .reply-content { flex: 1; font-size: 13px; line-height: 1.5; color: var(--text); }
.first-reply-preview .reply-name { font-weight: 600; color: var(--text); margin-bottom: 2px; }
.first-reply-preview .reply-time { font-weight: 400; color: var(--text-secondary); font-size: 11.5px; margin-left: 6px; }
.first-reply-preview .view-all-btn { display: block; width: 100%; margin-top: 8px; background: none; border: 1px solid var(--border); color: var(--primary); padding: 8px; border-radius: 8px; font-size: 12.5px; font-weight: 600; cursor: pointer; }
.first-reply-preview .empty-reply { font-size: 12.5px; color: var(--text-secondary); text-align: center; padding: 6px 0; }

/* ── FAB ─────────────────────────────────────────────────── */
.fab {
  position: fixed; bottom: calc(var(--nav-height) + 20px + env(safe-area-inset-bottom, 0px));
  right: max(16px, calc(50% - 284px));
  /* PD-0072 · S-019 §1 ⑨：回到画板的橙 FAB（白「+」2.70、橙对页底 2.45，用户选 A，豁免表）——
     撤掉 t-148 / S-006 §1 的绿。4px 页底色那一圈保留：它把按钮和身后的卡 / 导航分开，也给聚焦环让位。 */
  width: 54px; height: 54px; border-radius: 50%; background: var(--accent);
  color: var(--on-accent); border: none; font-size: 28px;
  box-shadow: 0 0 0 4px var(--bg), var(--shadow-accent-lg); cursor: pointer; z-index: 90;
  display: none; align-items: center; justify-content: center;
  transition: transform var(--t-base), background var(--t-base);
}
/* S-006 §6：以前悬停是写死的橙 #C97C33 —— 绿按钮一悬停就跳回橙，而且不过（白字 3.27 · 对外环 2.98）。
   悬停 / 按下 = --primary-dark（design-spec §1.1 本来就写着「hover / pressed 加深」）：11.19 / 10.16。
   **悬停只给有鼠标的设备**：触屏点一下 :hover 会粘住，按钮一直是深色、像卡住了；按下的反馈由缩放给。 */
/* 悬停 / 按下加深：--accent-deep（白字 6.16）—— 画板没画悬停；不回到写死的 #C97C33（S-006 §6 那条理由仍成立） */
@media (hover: hover) { .fab:hover { background: var(--accent-deep); } }
.fab:active { background: var(--accent-deep); transform: scale(0.9); }
/* 全局 :focus-visible 的 box-shadow 会顶掉上面那条（外环 + 投影）。双层环自带一圈 2px 页底色，
   外环由它顶上；**投影要自己加回来**，否则聚焦时按钮是「贴」在页面上的。 */
.fab:focus-visible { box-shadow: var(--focus-ring), var(--shadow-accent-lg); }
.fab.show { display: flex; }

/* ── Bottom nav ──────────────────────────────────────────── */
/* 2026-08 视觉定稿：悬浮胶囊导航 */
/* 胶囊是悬浮的：它下面有 12px 缝、两侧有留白，内容会从这些地方**可见地**滚过去。
   加一层从页面底色渐隐的遮罩，内容在够到缝之前就化掉，而胶囊仍然浮着。
   **挂在 body 上，不能挂在 .bottom-nav 上** —— 导航有 transform，那会让它成为
   position:fixed 后代的包含块，遮罩就只有胶囊那么宽了。 */
body.has-bottom-nav::after {
  content: ''; position: fixed; left: 0; right: 0; bottom: 0;
  height: calc(var(--nav-height) + 28px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, var(--bg) 58%, transparent);
  z-index: 99;              /* 低于导航的 100，高于页面内容 */
  pointer-events: none;
}
.bottom-nav {
  position: fixed; bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  left: 50%; transform: translateX(-50%);
  width: calc(100% - 24px); max-width: 456px; height: 62px;
  background: white; border-radius: 999px; box-shadow: var(--shadow-lg);
  display: flex; align-items: center; justify-content: space-around; z-index: 100;
  padding: 0 8px;
}
@media (min-width: 768px) { .bottom-nav { max-width: 576px; } }
@media (min-width: 1024px) { .bottom-nav { max-width: 696px; } }
/* RT-10453 RI-11/RI-13: nav-item min-height 44px + hover */
/* RT-10452 LS-01: 横向 10→12 收敛 */
.nav-item {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: none; border: none; cursor: pointer;
  color: var(--text-secondary); font-size: 11px; font-weight: 600;
  padding: 8px 12px; min-height: 44px;
  transition: color var(--t-base), background var(--t-base); position: relative;
}
.nav-item:hover { color: var(--text); background: rgba(0,0,0,0.02); }
.nav-item .nav-icon { font-size: 22px; transition: transform var(--t-base); display: flex; align-items: center; justify-content: center; }
.nav-item .nav-icon svg { display: block; }
.action-icon svg { display: block; width: 22px; height: 22px; stroke-width: 2; }
/* RT-10451 AC6: 活跃态增强 — 选中态是一枚药丸 */
/* 导航第 6 格（docs/PRODUCT-STRUCTURE.md 决定 4）。
 *
 * 每格都带文字标签时，六格英文要 376px，而胶囊只有 366px —— 第 6 格会被裁在外面。
 * Option C 定稿本来就是图标式导航：**未选中只有图标，选中才带文字**。
 * 这里补上这处落地偏差，中英文就都装得下，不需要额外缩短标签。 */
/* T155 / BUG-035：**`display: none` 视觉上藏掉文字，也把它从无障碍树里拿掉了。**
   实测无障碍树是 `["Home","","","","",""]` —— 六颗键里五颗**没有名字**。
   design 当初正是引这一行证明「未选中只有图标」已落地：
   **视觉上落地 ≠ 落地**（R-002 §2 A 已更正）。

   改成视觉隐藏：屏上仍然只见图标，名字留在树里。
   **这里是替换那一行，不是在后面追加** —— qa 实测过：追加一段不带 `display`
   的视觉隐藏规则，`display: none` 仍然赢，名字一个都没回来
   （追加后量到 `['Today','','','','2']`，一个没变）。 */
.nav-item > span {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
  display: inline;            /* **不能省** —— 省了就被上一版的 display:none 压回去 */
}
.nav-item.active {
  color: #fff;
  background: var(--primary-deep);
  border-radius: 999px;
  padding: 11px 16px;           /* UIV-01：6 / 14 → 11 / 16，字 11/600 → 12.5/700（Nav6） */
  font-size: 12.5px; font-weight: 700;
  flex-direction: row;
  gap: 6px;
}
/* 选中那颗的图标 19（未选中仍 21）—— SVG 的 width/height 属性是 21，CSS 盖掉它 */
.nav-item.active .nav-icon svg { width: 19px; height: 19px; }
/* 选中那一颗要真的看得见 —— 视觉隐藏的每一条都得解开，只写 display 不够。
   **只解开名字，不解开计数**（design-spec §9.0 · BUG-044）：.nav-count 是同一层的 span、只给读屏器；
   不排除它，这条 (0,2,1) 压过 .nav-count (0,1,0)，选中那颗有待办时屏上多一个「2」。
   （#271 先用一条覆盖把它藏回去，屏上相同，但留了三份一样的视觉隐藏块 —— t-203 收成这一处。） */
.nav-item.active > span:not(.nav-count) {
  position: static; width: auto; height: auto; padding: 0; margin: 0;
  overflow: visible; clip: auto; clip-path: none; white-space: normal;
  display: inline;
}
/* UIV-01 §7（design 08:47Z 补）：选中胶囊里图标 ↔ 字的间距，画板九张全是 7。
   以前放 9 是给挂在图标上的徽章让位；徽章挪到胶囊右上角之后这 2px 没理由了。 */
.nav-item.active { gap: 7px; }
/* UIV-01 §7：画板的徽章挂在**选中胶囊**的右上角（-3 / -3），不挂在图标上。
   选中那颗让图标框不再当定位参照，徽章就以整颗胶囊（.nav-item 是 relative）为参照。 */
.nav-item.active .nav-icon-wrap { position: static; }
.nav-item.active .badge { top: -3px; right: -3px; }
.nav-item.active:hover { color: #fff; background: var(--primary-dark); }
.nav-icon-wrap { position: relative; }
/* §12.1 / **BUG-034**：10px 粗体白字压 --accent 也是 2.70。
   小东西一律「底不动、字改 --text」—— 它们靠橙色被看见，底一深就糊。 */
/* PD-0072 · S-019 §1 ②：徽章字照画板白（2.70，豁免表；BUG-034 由 qa 改判「负责人接受」） */
.nav-item .badge { position: absolute; top: -4px; right: -6px; background: var(--accent); color: var(--on-accent); font-size: 10px; font-weight: 700; width: 21px; height: 21px; border-radius: 50%; border: 2px solid white; display: none; align-items: center; justify-content: center; }
.nav-item .badge:not([hidden]) { display: flex; }
/* 列表里「还没点开过」的那几条 —— 底栏角标数的就是它们。和角标同一个颜色。 */
.unread-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); margin-right: 6px; vertical-align: middle; flex-shrink: 0; }

/* ── 校方 item 详情 ──────────────────────────────────────── */
/* 「改过」这条横幅要排在标题**前面**：七条真实群消息里两条是更正，家长往回翻
   先撞上的永远是错的那条。所以「这条改过」得比标题先进眼睛。 */
.sd-updated {
  background: var(--tag-warning-bg); color: var(--tag-warning-fg);
  font-size: 12px; font-weight: 600; padding: 6px 12px;
  border-radius: 999px; margin-bottom: 10px; display: inline-block;
}
/* 类选择器里的 display 会盖掉 hidden 属性（作者样式优先于 UA 样式）——
   没这一行的话「还没改过」也会挂着一枚「已更新」。 */
.sd-updated[hidden] { display: none; }
.sd-meta { font-size: 12px; color: var(--text-secondary); margin-bottom: 12px; }
.sd-body { font-size: 14px; line-height: 1.6; white-space: pre-wrap; margin-bottom: 14px; color: var(--text-body); }   /* UIV-03：正文比 --text 淡一档 */
.sd-fields { display: grid; gap: 6px; margin-bottom: 12px; }
.sd-field { display: flex; gap: 10px; font-size: 13px; }
.sd-field .k { color: var(--text-secondary); min-width: 76px; font-weight: 600; }
.sd-field .v { color: var(--text); }
.sd-answer { margin: 14px 0; }
.sd-answer[hidden] { display: none; }
/* §3.1（UC-05 原文）：今天 `#sd-answer` 是 static，排在正文和字段后面 ——
   一条 30 句的长通知打开时它在 **y=1634，而视口只有 844**：
   **她要滚到底才知道这条要她签字。**

   **`bottom` 是负的，不是笔误**：详情纸有 `padding-bottom: max(32px, safe-area)`
   （底部横条不压住 Close）。`bottom: 0` 会停在这段内边距的**上沿**，
   正文就从它下面那 32px 里透出来（design 第一版就是这样）。往下盖住这段内边距，
   才真的贴住底边。

   respond 的「要 / 不要」和 sign 是同一个 `#sd-answer`、同一种「这条要你答」——
   一起吸底。逐孩表单（`#sd-form`）会把它藏掉，本条不碰表单。 */
#sd-answer:not([hidden]) {
  position: sticky; bottom: calc(-1 * max(32px, env(safe-area-inset-bottom))); z-index: 1;
  background: var(--card); margin: 0 -16px;          /* 跟着纸的左右内边距（UIV-03：20 → 16） */
  padding: 14px 16px calc(8px + max(32px, env(safe-area-inset-bottom)));
  /* UIV-03 表二：答题栏上两角 22、往上的投影（画板 SchoolItem） */
  border-radius: var(--radius-bar) var(--radius-bar) 0 0;
  box-shadow: var(--shadow-up);
}
#sd-answer-label { font-weight: 700; }
/* UIV-03 §3.3：两颗的**形状**照画板（胶囊 · 700 · 上下 13）。答之前两颗一样重 ——
   画板只画了一颗橙色实心「Sign」；把「同意」涂实、「不同意」留白边就是在推她点其中一颗（UC-05 E2）。
   PD-0072 v2（S-019 §1 ⑥）：**选中的那一颗**（不论哪颗）穿画板 Sign 那一身，另一颗回中性。
   只改答题栏里这两颗 —— 逐孩表单的「要 / 不要」同一个类名，不是签字，选中照旧深绿。 */
#sd-answer .sd-ans-btn { border-radius: var(--radius-btn); font-weight: 700; padding-top: 13px; padding-bottom: 13px; }
.sd-answer label { display: block; font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; }
.sd-answer-btns { display: flex; gap: 8px; }
/* 「要」和「不要」**同等分量** —— 把「不要」做成一个次要的小字链接，就等于
   又一次鼓励留空。两个按钮一样大，选中的才上色。 */
.sd-ans-btn {
  flex: 1; min-height: 44px; padding: 10px 12px;
  border: 1.5px solid var(--border); border-radius: 12px; background: #fff;
  font-size: 14px; font-weight: 600; color: var(--text); cursor: pointer;
  font-family: inherit; transition: background var(--t-fast), border-color var(--t-fast);
}
.sd-ans-btn:hover { border-color: var(--primary); }
.sd-ans-btn.chosen { background: var(--primary-deep); border-color: var(--primary-deep); color: #fff; }
#sd-answer .sd-ans-btn.chosen { background: var(--accent); border-color: var(--accent); color: var(--on-accent); box-shadow: var(--shadow-accent-sm); }
/* 全局 :focus-visible 的 box-shadow 会顶掉光晕 —— 两层一起写（同 .fab） */
#sd-answer .sd-ans-btn.chosen:focus-visible { box-shadow: var(--focus-ring), var(--shadow-accent-sm); }
.sd-answer-hint { font-size: 12px; color: var(--text-secondary); margin-top: 8px; line-height: 1.5; }
/* §3.4：今天是 `--danger` 红 600 —— 读数 4.71 **过**，但**意思不对**：
   她还没答，不是答错了。而**同一个状态在 S-008 那张列表上是琥珀**
   （「Needs your signature」）—— 进了详情变成红，等于同一件事在两个地方
   说两种话。改琥珀：6.16，**比今天还高**。
   「旧版本」（`answer_stale` 用同一个类）也跟着琥珀 ——
   「请看一下改了什么」同样是「要你动一下」，不是「出错了」。
   与 S-012 §3.3（「还没填完」不用红）是同一条理由。 */
.sd-answer-hint.unanswered { color: var(--tag-warning-fg); font-weight: 600; }
.sd-form { margin: 14px 0; }
.sd-form[hidden] { display: none; }
.sd-form > label { display: block; font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; }
.sd-unit { border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; }
.sd-unit-name { font-size: 14px; font-weight: 700; margin-bottom: 8px; }
.sd-frow { display: grid; gap: 6px; padding: 8px 0; border-top: 1px solid var(--border); }
.sd-frow:first-of-type { border-top: none; }
.sd-frow-label { font-size: 13.5px; font-weight: 600; }
.sd-frow-note { font-size: 12px; color: var(--text-secondary); }
/* 逐行也是三态，「不要」同样是等宽的一个按钮 —— 跟整条回应一个道理 */
.sd-frow-btns { display: flex; gap: 6px; }
.sd-frow-btns .sd-ans-btn { font-size: 13px; min-height: 44px; }
.sd-frow-extra { display: flex; gap: 6px; }
.sd-frow-extra select, .sd-frow-extra input {
  flex: 1; padding: 8px 10px; border: 1.5px solid var(--border); border-radius: 10px;
  font-size: 13px; font-family: inherit; background: #fff; color: var(--text);
}
.sd-frow-extra[hidden] { display: none; }
#sd-form-save { width: 100%; margin-top: 4px; }
.sd-revisions ul { margin: 6px 0 0; padding-left: 18px; }
/* 要带的东西：和摘要同一种卡片，行和 to-do 一样能勾 */
.sd-bring { background: var(--bg); border: 1.5px solid var(--border); border-radius: 14px; padding: 2px 14px 8px; margin: 0 0 12px; }
.sd-bring[hidden] { display: none; }
.sd-bring ul { list-style: none; margin: 0; padding: 0; }
.sd-revisions li { font-size: 12.5px; line-height: 1.7; color: var(--text-secondary); }
.sd-revisions .was { text-decoration: line-through; opacity: 0.7; }
.sd-revisions .now { color: var(--text); font-weight: 600; }

/* ── Toast ───────────────────────────────────────────────── */
/* RT-10451 AC3: 对比度合规 — 背景 #333→#1F2937 (gray-800) 提升至 ~14:1 */
.toast {
  position: fixed; bottom: calc(var(--nav-height) + 20px + env(safe-area-inset-bottom, 0px));
  left: 50%; transform: translateX(-50%) translateY(80px);
  background: #1F2937; color: #FFFFFF; padding: 12px 24px; border-radius: 12px;
  font-size: 14px; font-weight: 600; z-index: 300; opacity: 0;
  box-shadow: var(--shadow-xl);
  transition: opacity var(--t-slow) ease, transform var(--t-slow) ease; pointer-events: none;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ── Tab onboarding overlay ──────────────────────────────── */
.tab-onboard-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 250; display: none; }
.tab-onboard-overlay.show { display: block; }
.tab-onboard-tooltip { position: fixed; background: white; color: var(--text); border-radius: 12px; padding: 12px 16px; max-width: 220px; font-size: 13px; line-height: 1.5; box-shadow: var(--shadow-xl); z-index: 251; text-align: left; }
.tab-onboard-tooltip::after { content: ''; position: absolute; bottom: -7px; left: var(--arrow-x, 50%); transform: translateX(-50%) rotate(45deg); width: 12px; height: 12px; background: white; box-shadow: 2px 2px 4px rgba(0,0,0,0.06); }
.tab-onboard-tooltip .tt-title { font-weight: 700; margin-bottom: 4px; color: var(--primary); }
.tab-onboard-tooltip .tt-step { font-size: 11px; color: var(--text-secondary); font-weight: 600; }
.tab-onboard-tooltip .tt-actions { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; gap: 8px; }
.tab-onboard-tooltip .tt-skip { background: none; border: none; color: var(--text-secondary); font-size: 12px; cursor: pointer; padding: 4px 6px; }
.tab-onboard-tooltip .tt-next { background: var(--primary); color: white; border: none; border-radius: 8px; padding: 8px 16px; font-size: 13px; font-weight: 600; cursor: pointer; }
.bottom-nav .nav-item.onboard-spotlight { position: relative; z-index: 251; background: white; border-radius: 12px; box-shadow: 0 0 0 4px rgba(45,74,50,0.15); }

/* ── Lang toggle button ──────────────────────────────────── */
#lang-toggle {
  background: rgba(255,255,255,0.15); color: white; border: none;
  border-radius: 8px; padding: 6px 12px; font-size: 12px; font-weight: 600;
  cursor: pointer; font-family: inherit; letter-spacing: 0.2px;
  transition: background var(--t-fast);
}
#lang-toggle:hover { background: rgba(255,255,255,0.25); }

/* ── 挂在公告下面的筹款 ─────────────────────────────── */
/* 捐款不是回应：**没有「不要」这个按钮**。不给也是一种答案，而且不需要
   按下去表达 —— 这一点和上面的三态回应正好相反。 */
.sd-fund { margin: 14px 0; padding: 14px; background: var(--bg); border-radius: 12px; }
.sd-fund[hidden] { display: none; }
.sd-fund label { display: block; font-size: 14px; font-weight: 700; margin-bottom: 8px; }
.sd-fund .fr-bar {
  height: 8px; border-radius: 999px; background: var(--card);
  margin-top: 4px; overflow: hidden;
}
.sd-fund .fr-bar[hidden] { display: none; }
.sd-fund .fr-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.sd-fund .fr-meta {
  font-size: 12.5px; font-weight: 700; color: var(--text-secondary);
  margin-top: 6px; font-variant-numeric: tabular-nums;
}
.sd-fund-give { margin-top: 12px; }
.sd-fund-give[hidden] { display: none; }
.sd-fund-give .give-row { display: flex; align-items: center; gap: 8px; }
.sd-fund-give .give-cur { font-size: 20px; font-weight: 800; color: var(--text-secondary); }
.sd-fund-give .give-amount {
  flex: 1; min-width: 0; padding: 11px 12px;
  border: 1.5px solid var(--border); border-radius: 10px;
  font-size: 18px; font-weight: 700; font-family: inherit;
  background: var(--card); color: var(--text); outline: none;
}
.sd-fund-give .give-amount:focus { border-color: var(--primary); }
.sd-fund-give .give-anon {
  display: flex; align-items: center; gap: 8px; margin-top: 10px;
  font-size: 13.5px; font-weight: 600;
}
.sd-fund #sd-fund-btn { margin-top: 12px; width: 100%; }
.sd-fund #sd-fund-btn[hidden] { display: none; }


/* ── UX-004：可点目标 ≥44px（design-spec §4.1）──
   **做法照 T066**：能长的就长，不能长的用「内边距撑开 + 负外边距收回」——
   看得见的还是原来那么大，接得住手指的那一块变大。
   量法只认命中测试（`docs/ux/tools/hit-height.py`）：本仓库用过伪元素扩展点击区，
   盒模型两个方向都会给出假结果。 */

.tab-onboard-tooltip .tt-skip,
.tab-onboard-tooltip .tt-next {
  min-height: 44px; display: inline-flex; align-items: center; justify-content: center;
}

/* 顶栏那两个圆按钮：头像 36、设置 32。**它们在 sticky 顶栏里，长大会把顶栏撑高** ——
   所以用 T066 那一招：伪元素把命中区扩到 44×44，看得见的还是原来那么大。
   两个 44 区会互相重叠一点，但**它们指向同一个地址**（都是 /settings），
   重叠区点到哪个都对。 */
.app-header .header-avatar,
.app-header .header-settings-btn { position: relative; }
.app-header .header-avatar::after,
.app-header .header-settings-btn::after {
  content: ""; position: absolute;
  top: 50%; left: 50%; width: 44px; height: 44px;
  transform: translate(-50%, -50%);
}

/* Skip 高够了、宽 36 —— 判据是 44×44，两个方向都要量 */
.tab-onboard-tooltip .tt-skip { min-width: 44px; }

/* ── T095：头像开一个菜单（你是谁 + 退出）──
   用户：「这两个按钮，去的地方是一样的？并且没有地方 log out。」
   齿轮还是直接去设置（**T083 那张图指的就是它**，换掉那张图就说了假话）；
   头像改成菜单。**菜单里不放「设置」** —— 那是旁边那颗按钮的活，一个控件一件事。 */
.header-auth { position: relative; }
.header-menu {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 300;
  min-width: 200px; max-width: 260px;
  background: var(--card, #fff); color: var(--text, #2A2F27);
  border-radius: 14px; box-shadow: 0 12px 32px rgba(0,0,0,0.22);
  padding: 6px; text-align: left;
}
.header-menu[hidden] { display: none; }
/* **她是谁**，写在最上面 —— 共用设备上这才是她打开这个菜单要确认的第一件事 */
.hm-who { padding: 10px 12px 8px; border-bottom: 1px solid var(--border, #E5E7EB); }
.hm-name { display: block; font-size: 14px; font-weight: 700; }
.hm-phone { display: block; margin-top: 2px; font-size: 12px; color: var(--text-secondary, #67705F); }
.hm-item {
  display: block; width: 100%; text-align: left;
  background: none; border: none; font-family: inherit;
  font-size: 14px; font-weight: 600; color: var(--danger, #B42318);
  padding: 0 12px; min-height: 44px;      /* UX-004 */
  cursor: pointer; border-radius: 10px;
}
.hm-item:hover { background: var(--bg, #F6F9F4); }
.hm-item:disabled { opacity: 0.55; cursor: progress; }
.hm-err {
  margin: 4px 8px 8px; padding: 8px 10px; border-radius: 10px;
  background: #FDECEC; color: #8A1F1F; font-size: 12px; line-height: 1.45;
}

/* ── 主/次/处置 三个按钮族的**本体**（design S-002 §8）──
   `.btn-post` / `.btn-cancel` 此前**只定义在 `index.css` 里**，而老师端只加载
   `shared.css` + `teacher.css` —— 于是老师端每一颗 `.btn-post` 都退回浏览器默认：
   实测「Add a student」是 rgb(239,239,239) 的灰方块、0 圆角、黑字。
   **它不报错，CSS 里也看不出毛病** —— 这是 `.btn-secondary` 那次（T052）的同一族，
   而我在 T092 里把它变成了一屏的主动作，等于把这个缺陷推到了最显眼的位置。

   放在 shared.css：两个页面都加载它。`index.css` 里那两条留着（`flex: 1/2` 是
   那个容器的布局），它在后面加载，同名属性照旧由它赢 —— 家长端一像素不变。 */
.btn-post {
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-btn);
  font-family: inherit; font-size: 15px; font-weight: 600;
  padding: 12px; min-height: 48px;      /* spec §4.1：主按钮 ≥48 */
  cursor: pointer;
}
.btn-post:hover:not(:disabled) { background: var(--primary-dark, #1F3A1C); }
.btn-post:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-cancel {
  background: var(--bg);
  color: var(--text);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-btn);
  font-family: inherit; font-size: 15px; font-weight: 600;
  padding: 12px; min-height: 44px;
  cursor: pointer;
}
.btn-cancel:hover { background: var(--card); }

/* 破坏性动作（design-spec §2.1 第三族）。
   **本体从 teacher.css 搬到这里** —— design v2.1 §3 记着这一条：
   家长端不加载 teacher.css，**一旦家长端用到 .btn-danger 就会重演
   「有类名、没本体」那个缺陷**（`.btn-post` 在 #170 之前正是这样）。
   圆角同时并回族里那一个：v2.1 §3 的另一条是「新族内部 12/12/10 不齐」。 */
.btn-danger {
  background: none;
  border: 1px solid var(--danger, #B42318);
  color: var(--danger, #B42318);
  border-radius: var(--radius-btn);
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  padding: 0 14px; min-height: 44px;
  cursor: pointer;
}

/* T155：跟在导航名字后面的那个数。看得见的角标是 aria-hidden 的，
   这一个只进无障碍树 —— **视觉上一个像素都不占**（N2：Nav6 视觉不变）。 */
.nav-count {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}
.nav-count[hidden] { display: none; }

/* ── 「单独一条整行入口」.cal-entry-row（design-spec §2.3）──
   老师端 Class 页「放一份资源」/ 快捷卡（UIV-12 v2）与家长端家长圈页尾的通讯录入口（S-028 §2）同一身。
   S-028 §2：家长端第一次用它时从 teacher.css **搬**过来，不复制第二份（复制出第二份就是 D-008 那个病的下一个实例）；
   老师端只剩 .quick-cards 那三行留在 teacher.css。值一格没动：UIV-12 v2 量过的那一份。 */
.cal-entry-row {
  display: flex; align-items: center; gap: 10px;   /* UIV-12 v2：画板 10 */
  width: 100%; min-height: 69px; padding: 13px 14px; box-sizing: border-box; margin: 8px 0 4px;   /* UIV-12 v2：高 69（原 56 / 上下 13） */
  background: var(--card); border: none; box-shadow: var(--shadow-md); border-radius: 16px;   /* UIV-12：画板 16；v2：画板是白卡 + --shadow-md，没有描边（描边会把 69 撑成 72） */
  text-align: left; cursor: pointer; font-family: inherit; color: var(--text);
}
.cal-entry-row:hover, .cal-entry-row:focus-visible { background: var(--primary-light); }
/* UIV-12 v2：emoji → 36 的圆角块（--radius-sm 12 · --primary-light 底）+ 18 线性 SVG（design-spec §6，与 UIV-03 §8 同族） */
.cal-entry-icon { width: 36px; height: 36px; border-radius: var(--radius-sm); background: var(--primary-light); color: var(--primary); display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.cal-entry-icon svg { width: 18px; height: 18px; }
.cal-entry-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cal-entry-title { font-size: 13.5px; font-weight: 700; color: var(--text); line-height: 16px; }   /* UIV-12：画板 13.5 / --text */
/* UIV-12 v2：副文 11（原 12.5）。pd PD-0087：快捷卡副文 ≤20 字符、一行放得下 —— 放不下就改词，不许 line-clamp（手机上没有 hover，藏进 title 等于没写） */
.cal-entry-sub { font-size: 11px; line-height: 13px; color: var(--text-secondary); }
.cal-entry-chevron { font-size: 24px; line-height: 1; color: var(--primary); flex-shrink: 0; }

/* ── 帖子下面的表情与回复（2026-09-28）── 家长圈 / 老师帖 / 老师端「家长看到的样子」共用 */
.thread-host { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); }
.th { display: flex; flex-direction: column; gap: 12px; }
.th-reacts { display: flex; flex-wrap: wrap; gap: 8px; }
.th-react { display: inline-flex; align-items: center; gap: 4px; min-height: 34px; padding: 4px 10px; border-radius: 999px;
  border: 1.5px solid var(--border); background: var(--card); font: inherit; font-size: 14px; color: var(--text); cursor: pointer; }
.th-react.on { border-color: var(--primary); background: var(--primary-light); }
.th-react:focus-visible, .th-send:focus-visible, .th-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.th-emoji { font-size: 16px; line-height: 1; }
.th-count { font-weight: 700; font-variant-numeric: tabular-nums; }
.th-head { font-size: 12px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--text-secondary); }
.th-empty { margin: 0; font-size: 13.5px; color: var(--text-secondary); }
.th-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.th-reply { display: flex; flex-direction: column; gap: 2px; }
.th-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; font-size: 13px; color: var(--text); }
.th-tag { font-size: 11px; font-weight: 700; color: var(--primary); background: var(--primary-light); border-radius: 999px; padding: 1px 7px; }
.th-when { font-size: 12px; color: var(--text-secondary); }
.th-body { font-size: 14px; line-height: 1.5; color: var(--text-body, var(--text)); white-space: pre-wrap; overflow-wrap: anywhere; }
.th-actions { font-size: 12.5px; color: var(--text-secondary); }
.th-link { background: none; border: 0; padding: 2px 0; font: inherit; font-size: 12.5px; color: var(--text-secondary); text-decoration: underline; cursor: pointer; }
.th-yes { color: var(--primary); font-weight: 700; }
.th-form { display: flex; gap: 8px; align-items: flex-end; }
.th-input { flex: 1; min-width: 0; resize: vertical; font: inherit; font-size: 14px; padding: 8px 10px; border: 1.5px solid var(--border); border-radius: 10px; background: var(--card); color: var(--text); }
.th-send { flex: none; min-height: 38px; padding: 0 14px; border: 0; border-radius: 10px; background: var(--primary); color: #fff; font: inherit; font-weight: 700; cursor: pointer; }
.th-send:disabled { opacity: .6; cursor: progress; }
.th-err { margin: 0; font-size: 13px; color: var(--danger, #b3261e); }
.th-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.thread-sum { display: block; margin-top: 6px; font-size: 12.5px; color: var(--text-secondary); }
