/* ============================
   十一智源移动端 - 主样式表
   设计风格：浅色、简洁、现代（视觉基线见文末「设计基线统一层」）

   适用范围：index.html 外壳 + pages/*.html（首页 / 总览 / 出勤 / 设置）+ 全局控件。
   登录页与注册页自成一套，样式在 css/login.css。

   ⚠️ 已移除页面（环境监测 / 班级监测 / 周工作计划 / 实时数据 / 旧版出勤按钮）的
      样式已**移出本文件**，留档在 css/legacy.css —— **没有任何页面加载它**。
      恢复旧页面时把需要的段落复制回来，且必须先按本文件末尾的「设计基线统一层」
      改造：那些样式仍是旧的蓝色风格（渐变色块、重阴影、旧圆角）。

   ⚠️ --card-line 是**一整条 border 简写**（1px solid var(--border)），不是颜色：
      只能写 border: var(--card-line);。写成 border: 1px solid var(--card-line)
      会展开成无效值 ⇒ 整条声明被丢弃 ⇒ 边框静默变 0px（不报错、不进控制台）。

   ⚠️ 滚动条全局隐藏（见下方同名段落）：只隐藏视觉，滚动能力不受影响。
      ::-webkit-scrollbar 的优先级按**宿主选择器**算，故 .content-area:: 会盖过 *::。

   ⚠️ border: 1.5px 在 Blink 里被向下取整成 1px（DPR 2 实测）⇒ 源码一律写 1px，
      让"写的"与"渲染的"一致。

   增删页面后重跑 node .workbuddy/tools/probes/scan-css-usage.js 重新盘点死代码
   （该脚本**不剥注释**：注释里写 .xxx 也会被算进类名总数，别当成脚本坏了）。
   ============================ */

/* 全局重置 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
}

/* html 级的两件事（2026-09-19 移动端自适应）：
   ① `-webkit-text-size-adjust: 100%` —— 不写的话，iOS Safari 在**横屏**下会给
      正文自动放大字号（"text autosizing"），同一个页面竖屏/横屏两套字号，
      表现是「横过来字突然变大、布局被撑破」。100% 表示"别动我的字号"。
   ② 显式给 html 一个底色 —— `viewport-fit=cover` 之后页面会铺到刘海/圆角外，
      没给底色时那块区域会露出浏览器默认白，与 `.app-container` 的 --bg 对不上。 */
html {
    -webkit-text-size-adjust: 100%;
    /* 归档 049：禁止双击缩放（ pinch 由 viewport user-scalable=no 负责），
       同时消除移动端 300ms 点击延迟，点按钮更跟手 */
    touch-action: manipulation;
    background: var(--bg);
}

:root {
    --primary: #3B82F6;
    --primary-light: #DBEAFE;
    --primary-dark: #1E40AF;
    --primary-bg: #EFF6FF;
    --bg: #F0F4F8;
    --card-bg: #FFFFFF;
    --text-primary: #1E293B;
    --text-secondary: #64748B;
    --text-light: #94A3B8;
    --border: #E2E8F0;
    --shadow: 0 2px 8px rgba(59, 130, 246, 0.08);
    --shadow-hover: 0 4px 16px rgba(59, 130, 246, 0.15);
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-pill: 999px;
    --transition: all 0.3s ease;

    /* ===== 设计基线（与 css/login.css 同源，改这里即全局生效）=====
       2026-09-18 统一风格时新增，用来消灭"同一个东西有多套画法"：

       --brand-glow  品牌光晕。**替代蓝色渐变块**。
                     登录页上轮已确认：logo 自带蓝紫渐变，再垫一层蓝色色块
                     只会把两者糊在一起，还得额外套白底去"托" —— 色块 / 白底 / logo
                     三层叠加正是"丑"的来源。今后品牌区一律用这层极淡光晕。
       --card-line   卡片描边。与登录页输入框同一手法：浅色底上只靠投影的卡片
                     边界发虚，加一条发丝描边"面"才立得住。
                     ⚠️ 取 1px 而不是 1.5px —— 2026-09-18 真机实测（CDP，DPR 2）：
                     Blink 会把小数边框**取整**，`border: 1.5px` 的计算值同样是 1px
                     （登录页 .login-field 一直写 1.5px，量出来也是 1px）。
                     既然渲染结果一样，就按事实写，别让源码骗人。
       --radius-pill 胶囊圆角。分页控件统一用它（旧的"白卡 + 蓝色实心块"已废弃）。 */
    --brand-glow: radial-gradient(58% 76% at 50% 44%, #E4EFFF 0%, rgba(228, 239, 255, 0) 72%);
    --card-line: 1px solid var(--border);
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
    background: var(--bg);
    color: var(--text-primary);
    line-height: 1.6;
    min-height: 100vh;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
}

/* ============================
   滚动条：全局隐藏（所有页面一致）
   ============================
   本页是"移动端 H5"：真机上滚动条是**覆盖式**的，扫过就消失，本来就不占位。
   但在桌面 Chrome / Electron 里会画出实体滚动条（视口约 15px、`.content-area` 4px），
   又宽又始终可见，一眼就露馅。故统一隐藏。

   ⚠️ 只隐藏**视觉**，不影响**滚动能力**：触摸滑动、鼠标滚轮、键盘方向键 / PageUp，
      以及滚动锚定、`scrollIntoView`、`elementscroll` 事件全部照旧。
   ⚠️ 隐藏后桌面端少了"这里还能往下滚"的提示，靠的是移动端本就依赖的
      「底部内容被裁切」这一视觉线索 —— 这是移动端 H5 的通行做法。
   ⚠️ 覆盖范围必须包含 `html` / `body`：登录页、注册页由 `body.login-body{overflow:auto}`
      整页滚动，滚动条挂在视口上；主应用则由 `.content-area` 内部滚动。
      两处都要盖到，才算"所有页面"。

   为什么要用 `html, body, *` 三层而不是只写一个通配：
   `::-webkit-scrollbar` 的优先级按**宿主选择器**算。原先 `.content-area::-webkit-scrollbar`
   是 (0,1,0)，会盖过 `*::-webkit-scrollbar` 的 (0,0,0) —— 只写通配会"隐藏了但没完全隐藏"。
   所以那条 4px 的老规则已**就地删除**（见下方「滚动条美化」段），此处才用通配收口。 */
html,
body,
* {
    scrollbar-width: none;      /* 标准属性：Firefox 64+ / Chromium 121+ */
    -ms-overflow-style: none;   /* 旧 Edge / IE11 */
}

html::-webkit-scrollbar,
body::-webkit-scrollbar,
*::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
}

/* ============================
   应用容器
   ============================ */
.app-container {
    display: flex;
    flex-direction: column;
    /* 🔴 100vh 在移动浏览器里**不可靠**：它恒等于「地址栏收起时」的最大可视高度，
       于是地址栏可见时，底部那一截（正好是固定底栏）会被顶到屏幕外。
       dvh（dynamic viewport height）跟着可视高度实时变化，才是移动端该用的单位。
       写法顺序有意义：先 100vh 给不认 dvh 的老内核兜底，再 100dvh 覆盖它 ——
       解析不了 dvh 的浏览器会整条丢弃第二条，自动留在 100vh。 */
    height: 100vh;
    height: 100dvh;
    max-width: 428px;
    margin: 0 auto;
    background: var(--bg);
    position: relative;
}

/* ============================
   顶部标题栏（固定置顶）
   ============================
   2026-09-18 统一风格：由「蓝色渐变色块 + 白色圆角衬底 logo + 白色大字标题」
   改为「白底 + 一条发丝分割线 + 横版 logo 直接落在浅色上 + 深色标题」，
   与登录 / 注册页的品牌区同一套语言。

   为什么去掉白色衬底：横版 logo（logo-bian.png）自带蓝紫渐变与透明背景，
   压在蓝色色块上会糊在一起，才不得不套一层白底去"托" —— 色块 / 白底 / logo
   三层叠加，正是登录页上轮被判"丑"的那个结构，顶栏这里同样不要。 */
.top-bar {
    background: var(--card-bg);
    color: var(--text-primary);
    padding: 14px 20px;
    /* 刘海屏：顶栏要顶到状态栏 / 挖孔下面，否则 logo 与标题会被摄像头挖孔盖住。
       `viewport-fit=cover` 之后这两个环境变量才有非 0 值（见各页 <meta name="viewport">）；
       非刘海设备上 env() 恒为 0 ⇒ 计算结果回到原来的 14px，既有观感不变。 */
    padding-top: calc(14px + env(safe-area-inset-top, 0px));
    display: flex;
    align-items: center;
    gap: 10px;
    /* 由投影改为发丝线：浅色界面上投影会显脏，且与底部导航同一手法 */
    border-bottom: 1px solid var(--border);
    position: relative;
    z-index: 100;
    flex-shrink: 0;
}

/* 横版 logo —— 与 css/login.css 的 .login-logo 同一套裁切规则：
   图形在方形画布上下留白很大，直接按宽度缩放会保留透明边、显得又小又飘，
   故用 aspect-ratio + object-fit: cover 把透明边裁掉。
   ⚠️ height: auto 不能省 —— <img> 标签上的 height="640" 是"表现性提示"，
      会以 height:640px 参与层叠，把 aspect-ratio 挤掉（实测渲染盒会变成
      44×640，图形被裁成一条）。写 height:auto 才能让 aspect-ratio 生效。 */
.top-bar__logo {
    width: 44px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

.top-bar__logo img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 631 / 412;
    object-fit: cover;
    object-position: center 40%;
}

.top-bar__title {
    font-size: 17px;
    font-weight: 600;
    color: var(--text-primary);
    letter-spacing: 0.12em;
}

/* ============================
   中间内容区（可滚动）
   ============================ */
.content-area {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 20px 16px;
    /* 底部留白 = 固定底栏的实高 + 安全区。
       ⚠️ 底栏（.bottom-nav）是 position:fixed、不参与本区的流式布局，所以这段留白是
       它唯一的「不被压住」保障。底栏实高 ≈ padding 12×2 + 图标 22 + 间隔 4 + 文字 15 ≈ 81px，
       取 96px 留余量；再叠加 iPhone 那条 home indicator（约 34px），
       否则最后一屏内容会被底栏或小白条盖住。 */
    padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
}

.page-content {
    display: none;
}

.page-content:not(.hidden) {
    display: block;
    animation: fadeIn 0.3s ease;
}

@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.hidden {
    display: none !important;
}

/* ============================
   占位页面
   ============================ */
.page-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 80px 20px;
    color: var(--text-light);
}

.page-placeholder i {
    font-size: 64px;
    margin-bottom: 16px;
    opacity: 0.3;
    color: var(--primary);
}

.page-placeholder p {
    font-size: 15px;
    font-weight: 500;
}

/* ============================
   统计图表卡片（总览页：饼图 / 树图 / 矩形树图）
   2026-09-18 新增：接入本地 vendor 的 ECharts。
   容器必须给定高度，否则 ECharts 初始化得到 0 高、图表不显示。
   ============================ */
.chart-card {
    background: var(--card-bg);
    border: var(--card-line);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow);
    padding: 14px 14px 10px;
    margin-bottom: 16px;
}

.chart-card__title {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    margin-bottom: 8px;
    padding-left: 8px;
    border-left: 3px solid var(--primary);
}

/* ECharts 挂载点：必须显式高度（移动端窄屏统一 260px）。
   ⚠️ 树状图(orient:LR) 在极窄屏可能横向拥挤，真机验证后再调 initialTreeDepth。 */
.chart-box {
    width: 100%;
    height: 260px;
}

/* ============================
   监测页面 - 标签页
   ============================ */

/* ✅ 本段原属**已移除的「监测」页面的分页控件**（2026-09-18 盘点：无任何 HTML 引用）；
   现被 **「总览」页（pages/overview.html）复用**，已不再是遗留样式。
   下面的旧值（白卡片 + 蓝色实心选中块）仍被文末「设计基线统一层」④ 覆盖成胶囊 ——
   旧值保留原样不改：一个属性只应有一处定义，要调外观请去统一层。 */
.tab-bar {
    display: flex;
    background: var(--card-bg);
    border-radius: var(--radius-md);
    padding: 4px;
    margin-bottom: 20px;
    box-shadow: var(--shadow);
}

.tab-btn {
    flex: 1;
    border: none;
    background: none;
    padding: 12px 16px;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: var(--transition);
}

.tab-btn--active {
    background: var(--primary);
    color: #fff;
    box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
}

.tab-btn:active {
    transform: scale(0.97);
}

/* 面板显隐：靠 **.hidden 类**切换 —— 总览页（pages/overview.html + js/overview.js）用的就是这条。
   ⚠️ 不能用 hidden 属性：作者样式优先级恒高于浏览器默认样式表，
   带 hidden 属性的面板仍会被下面这条 `:not(.hidden)` 命中而显示出来。
   注意文件下方「实时页面」段还有一条**一模一样的 .tab-content{display:none}**（历史重复），
   那段的 .tab-content.active 已无调用点 —— 要改显隐规则，改这里。 */
.tab-content {
    display: none;
}

.tab-content:not(.hidden) {
    display: block;
    animation: fadeIn 0.3s ease;
}

/* ============================
   底部功能栏（固定置底）
   ============================ */
.bottom-nav {
    position: fixed;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
    max-width: 428px;
    background: var(--card-bg);
    display: flex;
    justify-content: space-around;
    padding: 12px 0;
    /* 🔴 这里的 second 参数**不是**「安全区为 0 时的默认值」。
       `env(name, fallback)` 的 fallback 只在浏览器**压根不认识 env()** 时生效；
       而任何支持 env() 的浏览器（含所有在用的安卓机、桌面 Chrome）都会把
       `safe-area-inset-bottom` 解析成 **0px** ⇒ 原来的 `env(…, 12px)` 实际算出 0px，
       底栏的文字直接贴着屏幕下边缘（非刘海机上的实际观感）。
       正确写法是把基准值放进 calc，环境变量只当增量。 */
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    /* 与顶栏对称：发丝线分区，不再用投影 */
    border-top: 1px solid var(--border);
    z-index: 100;
    flex-shrink: 0;
}

.nav-btn {
    flex: 1;
    border: none;
    background: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 8px 0;
    cursor: pointer;
    color: var(--text-light);
    font-size: 11px;
    transition: var(--transition);
    position: relative;
}

.nav-btn i {
    font-size: 22px;
    transition: var(--transition);
}

.nav-btn--active {
    color: var(--primary);
}

.nav-btn--active i {
    transform: translateY(-2px);
}

.nav-btn--active::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 24px;
    height: 3px;
    background: var(--primary);
    border-radius: 0 0 4px 4px;
}

.nav-btn:active {
    transform: scale(0.92);
}

/* ============================
   响应式适配
   ============================ */
/* 小屏手机（< 375px） */
@media (max-width: 374px) {
    .top-bar {
        padding: 12px 16px;
    }
    
    /* ⚠️ 只给宽度：高度由 .top-bar__logo img 的 aspect-ratio 推出来。
       同时写 width + height 会顶掉 aspect-ratio → logo 被压成方形。 */
    .top-bar__logo {
        width: 38px;
    }

    .top-bar__title {
        font-size: 16px;
    }
}

/* 大屏手机/平板（> 428px） */
@media (min-width: 429px) {
    .app-container {
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.1);
    }
    
    .bottom-nav {
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    }
}

/* 横屏适配 */
@media (max-height: 500px) {
    .top-bar {
        padding: 10px 16px;
    }
    
    /* 横屏：同样只给宽度（理由见上面 374px 那段） */
    .top-bar__logo {
        width: 34px;
    }

    .top-bar__title {
        font-size: 15px;
    }
    
    .content-area {
        padding: 12px 16px;
        padding-bottom: 70px;
    }
}

/* ============================
   滚动条美化 —— 已废弃（2026-09-18）
   ============================
   原先这里给 `.content-area` 做了一条 4px 的细滚动条（track 透明 + thumb 用 --border）。
   现按需求**所有页面一律不显示滚动条**，本段已整体移除 —— 保留这段说明是因为：
   ① `.content-area::-webkit-scrollbar` 的优先级是 (0,1,0)，**会盖过文件上方全局段里
      `*::-webkit-scrollbar` 的 (0,0,0)**。留一个 `width: 4px` 在这儿，全局隐藏就失效。
   ② 若日后想改回"细滚动条"，改全局段一处即可，不要在 .content-area 上另起一套 ——
      否则同一个东西又是两套画法（本项目的老毛病）。
   全局规则见文件上方「滚动条：全局隐藏（所有页面一致）」。 */

/* ============================
   出勤上报页面
   ============================ */

/* ⚠️ 遗留言：本段属于**已移除的「出勤上报」页面（旧版：纵向班级按钮 + 学生网格，已被 .att-* 取代）**（2026-09-18 盘点：无任何 HTML 引用）。
   保留以备恢复，但视觉仍是旧的蓝色风格 —— 恢复前请先按文末「设计基线统一层」改造，
   否则会把老风格带回来。 */
.page-attendance {
    padding: 0;
}


.section-title {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0 0 8px 0;
}



/* ============================
   设置页面
   ------------------------------------
   本节样式来自重置前的旧设置页；旧页面删除后一度无人引用。
   设置页（pages/settings.html）**直接复用本节**，并做三处适配：
     ① .settings-header 做成通栏：抵消 .content-area 的 20px / 16px 内边距
     ② .settings-content 不再自带左右内边距（否则与 .content-area 叠加成双倍缩进）
     ③ 新增「待开发项」与「禁用开关」两处样式 —— 本页除退出登录外不实现功能，
        开关一律 disabled，避免「能拨动但不生效」的误导性交互

   2026-09-18 统一风格：头部由「蓝色渐变色块 + 白色圆形衬底 logo + 白色 22px 标题」
   改为「浅色底 + 品牌光晕 + 横版 logo + 深色标题」。
   原来的三层叠加（蓝块 / 白圆 / logo）与登录页上轮被判"丑"的结构完全同款 ——
   logo 自带蓝紫渐变，压在蓝块上会糊在一起，只好再套白圆去"托"。
   ============================ */
.page-settings {
    padding: 0;
}

/* ============================================================
   ICP 备案号页脚（登录页 .login-footer 与设置页 .settings-footer 共用）
   ------------------------------------------------------------
   按《互联网信息服务管理办法》要求：备案号须在页面底部展示，
   且通常链接到工信部备案系统（beian.miit.gov.cn）。
   两页共用 .icp-beian 以保证字号 / 颜色 / 间距一致。 */
.settings-footer {
    padding: 18px 20px calc(18px + env(safe-area-inset-bottom, 0px));
    text-align: center;
    font-size: 12px;
    color: var(--text-light);
}

.icp-beian {
    margin: 4px 0 0 0;
    font-size: 12px;
    line-height: 1.6;
}

.icp-beian a {
    color: var(--text-light);
    text-decoration: none;
}

.icp-beian a:active {
    color: var(--text-secondary);
}

/* 园所控制页（pages/school.html）：整页是若干分组列表，没有通栏品牌区，
   故左右内边距沿用 .content-area 的、只补一个底部留白（与 .settings-content 同一处理）。
   ⚠️ 显式写出来是**故意**的：本项目踩过「类名在用、CSS 却没有任何规则」的坑
   （.identity-actions —— 两个按钮几乎贴在一起），这里不留那种空档。 */
.page-school {
    padding-bottom: 20px;
}

/* ============================================================
   园所控制页 · 身份绑定审核（pages/school.html，2026-09-20）
   ------------------------------------------------------------
   一条待审申请一张卡。为什么**不复用** .identity-teacher 那套：
   那套是「列表项 + 右侧一颗小按钮」的两列布局，而这里要靠底部
   两颗等宽按钮做「通过 / 驳回」—— 两个不可逆动作挤在右侧，误触代价太高。 */
.school-bind__item {
    display: block;
    border: var(--card-line);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow);
    background: var(--card-bg);
    padding: 12px 14px;
    margin-bottom: 10px;
}

.school-bind__who {
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
}

.school-bind__meta {
    display: block;
    margin-top: 3px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-secondary);
}

.school-bind__actions {
    display: flex;
    gap: 10px;
    margin-top: 12px;
}

/* 两颗按钮**等宽**：对称性不是审美偏好，是在告诉用户这是同一级别的两个决定 */
.school-bind__actions .identity-btn {
    flex: 1;
    width: auto;
    margin-top: 0;
}

.settings-header {
    text-align: center;
    padding: 34px 20px 26px;
    /* 与登录 / 注册页品牌区同一套：极淡品牌光晕，不用色块 */
    background: var(--brand-glow);
    /* ① 通栏：抵消 .content-area 的内边距，让品牌区横跨整个内容区。
       负值必须与 .content-area 的 padding 保持一致（当前 20px 16px）。 */
    margin: -20px -16px 22px;
}

/* 横版 logo —— 与 .login-logo / .top-bar__logo 同一套裁切规则。
   ⚠️ height: auto 不能省（标签上的 height 属性会顶掉 aspect-ratio）。 */
.settings-logo {
    width: 96px;
    margin: 0 auto 14px;
}

.settings-logo img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 631 / 412;
    object-fit: cover;
    object-position: center 40%;
}

.school-name {
    font-size: 19px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 6px 0;
    letter-spacing: 0.06em;
}

.app-version {
    font-size: 12px;
    color: var(--text-light);
    margin: 0;
}

.settings-content {
    /* ② 左右内边距由 .content-area 统一提供，此处不再叠加 */
    padding: 0;
    padding-bottom: 20px;
}

.settings-section {
    margin-bottom: 20px;
}

/* 字号 / 字重 / 颜色已由文末「设计基线统一层」② 统一
   （与首页区块标题一致：15px / 700 / 深色 + 左侧品牌色条），这里只保留本页特有的外边距。
   原先这里是 16px / 600 / 灰色 —— 同一个"区块标题"项目里有三套画法，本轮已合并。 */
.settings-section .section-title {
    margin: 0 0 12px 0;
}


.settings-list {
    background: var(--card-bg);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.setting-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
    transition: var(--transition);
}

.setting-item:last-child {
    border-bottom: none;
}

.setting-item:active {
    background: var(--bg);
}

.setting-info {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1;
}

.setting-info i {
    font-size: 18px;
    color: var(--primary);
    width: 24px;
    text-align: center;
    flex-shrink: 0;
}

.setting-info span {
    font-size: 15px;
    color: var(--text-primary);
    font-weight: 500;
}

.setting-value {
    font-size: 14px;
    color: var(--text-secondary);
}

/* 「切换身份」这类**可点的**条目：沿用 .setting-value 的字号/位置，
   但去掉 <button> 的默认外观，并改成品牌色 + 右箭头语义（在此只做颜色与手感）。
   刻意不新造一套 .setting-action —— 同一个位置出现两种字型就是"不统一"的开始。 */
.setting-value--link {
    border: none;
    background: none;
    padding: 0;
    font-family: inherit;
    color: var(--primary);
    font-weight: 600;
    cursor: pointer;
}

.setting-value--link:active { opacity: 0.6; }

.setting-item > i {
    font-size: 14px;
    color: var(--text-light);
}

/* 开关按钮样式 */
.switch {
    position: relative;
    display: inline-block;
    width: 48px;
    height: 28px;
    flex-shrink: 0;
}

.switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #CBD5E1;
    transition: var(--transition);
    border-radius: 28px;
}

.slider::before {
    position: absolute;
    content: "";
    height: 22px;
    width: 22px;
    left: 3px;
    bottom: 3px;
    background-color: white;
    transition: var(--transition);
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.switch input:checked + .slider {
    background-color: var(--primary);
}

.switch input:checked + .slider::before {
    transform: translateX(20px);
}

/* ③-a 待开发项：**整行灰显**，不响应点击（本页除退出登录外不实现功能）。
   2026-09-20 起消息通知 / 深色模式也走这一套 ——
   只在 JS 里 disabled 是不够的：用户看不见「禁用」，只会以为开关坏了。 */
.setting-item--pending {
    cursor: default;
}

.setting-item--pending:active {
    background: transparent;
}

.setting-item--pending .setting-value {
    color: var(--text-light);
}

/* 图标与标题一并压灰：只灰开关的话，视觉重心还在左边那一行字上，
   「这项不可用」的第一眼印象就没了。 */
.setting-item--pending .setting-info i,
.setting-item--pending .setting-info span {
    color: var(--text-light);
}

/* 「暂不可用」四个字：贴在开关左侧，给灰显一个**文字解释**。 */
.setting-value--muted {
    font-size: 13px;
    margin-right: 10px;
    flex-shrink: 0;
}

/* ③-b 开关暂不可用：灰显 + 不可点击，避免「能拨动但不生效」的误导性交互 */
.switch input:disabled + .slider {
    opacity: 0.45;
    cursor: default;
}

/* 退出登录按钮 */
.logout-btn {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 15px 20px;
    border: none;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    color: #DC2626;
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: var(--transition);
}

.logout-btn i {
    font-size: 17px;
}

.logout-btn:active {
    transform: scale(0.98);
    background: #FEF2F2;
}

/* 捐助条目：稍稍强调（主色图标 + 主色链接），但不做成实心主按钮 ——
   它不是设置页的主操作，抢走注意力反而显得像在催钱 */
.setting-item--donate .setting-info i {
    color: var(--primary);
}

.setting-item--donate .setting-value--link {
    color: var(--primary);
}

/* ============================
   设置页 - 通用底部弹层（修改密码 / 关于 / 捐助 共用）

   与 .reason-modal 同一套观感（底部升起 + 半透明遮罩 + 圆角面板），
   刻意不复用后者：那是「原因采集」专用（字典选项 + 具体情况），
   这里是「表单 / 图文展示」，硬套只会把两边都改歪。
   ============================ */
.settings-sheet {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

.settings-sheet__mask {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
}

.settings-sheet__panel {
    position: relative;
    width: 100%;
    max-width: 520px;
    max-height: 86vh;
    display: flex;
    flex-direction: column;
    padding: 18px 18px calc(18px + env(safe-area-inset-bottom));
    background: var(--card-bg);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.12);
    animation: settings-sheet-up 0.22s ease;
}

@keyframes settings-sheet-up {
    from { transform: translateY(12px); opacity: 0.6; }
    to   { transform: translateY(0);    opacity: 1; }
}

.settings-sheet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 14px;
}

.settings-sheet__title {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
}

.settings-sheet__close {
    padding: 4px 6px;
    border: none;
    background: transparent;
    color: var(--text-light);
    font-size: 16px;
    cursor: pointer;
}

.settings-sheet__body {
    overflow-y: auto;
}

.settings-sheet__msg {
    margin: 10px 0 0;
    font-size: 13px;
    color: #DC2626;
}

.settings-sheet__actions {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}

.settings-sheet__btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 13px 10px;
    border: var(--card-line);
    border-radius: var(--radius-md);
    background: var(--card-bg);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
}

/* 主按钮沿用全站基线：渐变蓝 + 白字 600（已在 verify-theme-consistency.js 的
   GRADIENT_OK 白名单里登记 —— 蓝色渐变只许出现在主按钮上） */
.settings-sheet__btn--primary {
    border: none;
    color: #fff;
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
}

.settings-sheet__btn:active {
    transform: scale(0.98);
}

.settings-sheet__btn--primary:disabled {
    opacity: 0.5;
    cursor: default;
}

.settings-sheet [hidden] {
    display: none;
}

/* 弹层内的表单字段（修改密码） */
.settings-field {
    display: block;
    margin-bottom: 14px;
}

.settings-field__label {
    display: block;
    margin-bottom: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.settings-field__input {
    width: 100%;
    padding: 12px 14px;
    border: var(--card-line);
    border-radius: var(--radius-md);
    background: var(--card-bg);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 15px;
}

.settings-field__input:focus {
    outline: none;
    border-color: var(--primary);
}

/* 关于十一智源 */
.settings-about__lead {
    margin: 0 0 12px;
    font-size: 16px;
    font-weight: 700;
    color: var(--primary);
}

.settings-about__list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 14px;
    margin: 0;
    font-size: 14px;
}

.settings-about__list dt {
    color: var(--text-secondary);
}

.settings-about__list dd {
    margin: 0;
    color: var(--text-primary);
    word-break: break-all;
}

.settings-about__note {
    margin: 14px 0 0;
    font-size: 12px;
    color: var(--text-light);
}

/* 捐助开发 */
.settings-donate__text {
    margin: 0 0 14px;
    font-size: 14px;
    line-height: 1.7;
    color: var(--text-secondary);
}

.settings-donate__tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 14px;
}

.settings-donate__tab {
    flex: 1;
    padding: 10px;
    border: var(--card-line);
    border-radius: var(--radius-pill);
    background: var(--card-bg);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

.settings-donate__tab.is-active {
    border-color: var(--primary);
    background: var(--primary-bg);
    color: var(--primary);
}

.settings-donate__qr {
    display: flex;
    justify-content: center;
    padding: 8px 0 4px;
}

.settings-donate__qr img {
    width: 200px;
    max-width: 70vw;
    border: var(--card-line);
    border-radius: var(--radius-md);
}

.settings-donate__hint {
    margin: 10px 0 0;
    font-size: 13px;
    text-align: center;
    color: var(--text-primary);
}

.settings-donate__note {
    margin: 8px 0 0;
    font-size: 12px;
    text-align: center;
    color: var(--text-light);
}

/* ============================
   首页 - 用户信息区
   ============================ */
.home-profile {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px;
    margin-bottom: 20px;
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}


.home-profile__info {
    flex: 1;
    min-width: 0;
}

.home-profile__greeting {
    margin: 0 0 4px 0;
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 🆕 权限组 · 班级管理范围（归档 `041`）
   如「办公室 · 全部班级」/「教职工 · 待审核」。
   🔴 三段式：组名（主色）· 分隔符（弱）· 范围（次色）—— 让「归属」与「范围」两件事
      在视觉上一眼分开，不用读文字就能分辨哪半边在说什么。 */
.home-profile__scope {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 6px 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.home-profile__scope .scope-dot {
    color: var(--text-light);
    font-weight: 400;
}

.home-profile__scope .scope-range {
    font-weight: 500;
    color: var(--text-secondary);
}

/* 「待审核」是个**状态**而不是范围，配色要区别于正常范围（琥珀色 = 需要留意） */
.home-profile__scope.is-pending .scope-range {
    color: var(--amber, #d97706);
}

/* 🆕 右侧本园 LOGO（归档 `041`）
   🔑 固定 60px 且 `object-fit: contain`：园所 logo 长宽比千差万别，
      `cover` 会把窄长 logo 裁掉，contain + 白色衬底能容下任意比例。
   ⚠️ 衬底用白色而非主色：logo 多为深色图形，落在主色块上容易糊成一片。 */
.home-profile__brand {
    flex: 0 0 60px;
    width: 60px;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    background: #fff;
    box-shadow: 0 1px 4px rgba(15, 23, 42, 0.08);
    overflow: hidden;
}

.home-profile__logo {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

/* 「当前身份（角色 · 姓名 · 编号）」一行已于归档 `046` 按需求从首页移除 ——
   顶部卡里的「权限组 · 班级范围」已表达归属信息；样式一并清掉，避免留死代码。 */

.home-profile__meta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 2px 0;
    font-size: 12px;
    color: var(--text-secondary);
}

.home-profile__meta i {
    font-size: 12px;
    color: var(--primary);
}

.home-profile__date {
    margin: 0;
    font-size: 12px;
    color: var(--text-light);
}

/* 当前登录账号（脱敏手机号），未登录时不渲染文字故不占高度 */
.home-profile__account {
    margin: 2px 0 0 0;
    font-size: 12px;
    color: var(--text-light);
}


/* ============================
   首页 - 区块标题
   ============================ */
.home-section {
    margin-bottom: 20px;
}

.home-section__title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 12px 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.home-section__title::before {
    content: '';
    width: 3px;
    height: 14px;
    border-radius: 2px;
    background: var(--primary);
}

/* ============================
   首页 - 快捷功能
   ============================ */
.home-quick {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}

.home-quick__item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 16px 14px;
    border: none;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    box-shadow: var(--shadow);
    cursor: pointer;
    transition: var(--transition);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: left;
}

.home-quick__item i {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    font-size: 17px;
    background: var(--primary-bg);
    color: var(--primary);
}

.home-quick__item:active {
    transform: scale(0.97);
    box-shadow: var(--shadow-hover);
}

/* 🆕 「开发中」角标（归档 `041`）
   需求：安全上报 / 维修上报**只有按钮、没有页面**，右上角要挂一个「开发中」标签。
   🔑 为什么用角标而不是把整块置灰：置灰 = 「你有这个功能但不能用」，
      而这里的真实语义是「**功能还没做出来**」—— 角标 + 可点击（弹提示）更诚实。
   ⚠️ 角标必须 `position: absolute` 且父级 `position: relative`：
      直接放进 flex 流里会把按钮文字挤变形。 */
.home-quick__item--wip {
    position: relative;
}

.home-quick__item--wip::after {
    content: '开发中';
    position: absolute;
    top: -6px;
    right: -4px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--text-light);
    color: #fff;
    font-size: 10px;
    font-weight: 600;
    line-height: 1.6;
    letter-spacing: 0.2px;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.18);
    pointer-events: none;          /* 角标不吞点击 —— 点了仍然弹「开发中」提示 */
}

/* ============================
   首页 - 入口色板
   按钮的底色由 data-tone 决定，在 QUICK_ACTIONS 里指定 tone 即可，
   新增按钮不需要改 CSS。未指定时回落到默认主题蓝。
   ============================ */
.home-quick__item[data-tone="teal"] i   { background: #E1F5EE; color: #0F6E56; }
.home-quick__item[data-tone="amber"] i  { background: #FAEEDA; color: #854F0B; }
.home-quick__item[data-tone="red"] i    { background: #FCEBEB; color: #A32D2D; }
.home-quick__item[data-tone="blue"] i   { background: #E6F1FB; color: #185FA5; }
.home-quick__item[data-tone="purple"] i { background: #EEEDFE; color: #3C3489; }
.home-quick__item[data-tone="green"] i  { background: #EAF3DE; color: #3B6D11; }
.home-quick__item[data-tone="pink"] i   { background: #FBEAF0; color: #993556; }
.home-quick__item[data-tone="gray"] i   { background: #F1EFE8; color: #5F5E5A; }

/* 按钮多于 4 个时收窄为 3 列，图标上、文字下 */
.home-quick--dense {
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.home-quick--dense .home-quick__item {
    flex-direction: column;
    gap: 8px;
    padding: 14px 6px;
    font-size: 12px;
    text-align: center;
}

.home-quick--dense .home-quick__item i {
    width: 34px;
    height: 34px;
    font-size: 15px;
}

/* ============================
   首页 - 本周工作计划
   ============================ */
.home-plan {
    background: var(--card-bg);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.home-plan__day {
    display: flex;
    gap: 12px;
    padding: 13px 16px;
    border-bottom: 1px solid var(--border);
}

.home-plan__day:last-child {
    border-bottom: none;
}

/* 今天：浅底 + 左侧色条 */
.home-plan__day--today {
    background: var(--primary-bg);
    box-shadow: inset 3px 0 0 var(--primary);
}

.home-plan__date {
    width: 44px;
    flex-shrink: 0;
    text-align: center;
}

.home-plan__weekday {
    display: block;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}

.home-plan__day--today .home-plan__weekday {
    color: var(--primary);
}

.home-plan__md {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    color: var(--text-light);
}

.home-plan__items {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.home-plan__item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-primary);
}

.home-plan__time {
    flex-shrink: 0;
    padding: 1px 7px;
    border-radius: 10px;
    background: var(--primary-bg);
    color: var(--primary);
    font-size: 11px;
    font-weight: 600;
}

.home-plan__day--today .home-plan__time {
    background: #fff;
}

.home-plan__text {
    flex: 1;
    min-width: 0;
}

.home-plan__empty {
    font-size: 13px;
    color: var(--text-light);
}

/* ============================
   全局轻提示
   ============================ */
.app-toast {
    position: fixed;
    left: 50%;
    /* 悬在底部导航**之上**：导航实高 ≈81px，96px 留一线余量；
       再加安全区，否则刘海机上提示条会被 home indicator 压住。 */
    bottom: calc(96px + env(safe-area-inset-bottom, 0px));
    max-width: 80%;
    padding: 10px 18px;
    border-radius: 20px;
    background: rgba(30, 41, 59, 0.9);
    color: #fff;
    font-size: 13px;
    line-height: 1.5;
    text-align: center;
    opacity: 0;
    pointer-events: none;
    transform: translate(-50%, 12px);
    transition: opacity 0.25s ease, transform 0.25s ease;
    z-index: 9999;
}

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

/* ============================
   出勤上报页
   结构见 pages/attendance.html，逻辑见 js/attendance.js
   ============================ */
.att-step__head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

.att-step__title {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.att-step__hint {
    margin-left: auto;
    font-size: 12px;
    color: var(--text-light);
}

/* 返回班级列表 */
.att-back {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px 10px 5px 7px;
    border: none;
    border-radius: 14px;
    background: var(--primary-bg);
    color: var(--primary);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: var(--transition);
}

.att-back i {
    font-size: 11px;
}

.att-back:active {
    transform: scale(0.96);
}

/* 班级列表：自动换行胶囊，非纵向列表 */
.att-list {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* 胶囊宽度由内容决定，因此不设 width: 100% */
.att-class {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 11px 18px;
    border: none;
    border-radius: 999px;
    background: var(--card-bg);
    box-shadow: var(--shadow);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.4;
    cursor: pointer;
    transition: var(--transition);
    -webkit-tap-highlight-color: transparent;
}

.att-class:active {
    transform: scale(0.95);
    background: var(--primary-bg);
    color: var(--primary);
    box-shadow: var(--shadow-hover);
}

/* 继承胶囊的字号与颜色，:active 时才能整体变色 */
.att-class__name {
    font-size: inherit;
    font-weight: inherit;
    color: inherit;
}

.att-class__count {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-light);
}

/* 出勤状态三选一：出勤 / 病假 / 事假
   位置在学生清单**上方** —— 它是「标记模式」选择器：选中哪个，点学生就标哪个状态。
   ⚠️ 本轮只做**互斥选中 + 高亮**，不给学生打标、不做上报（下一步）。

   语义色沿用重置前旧版（`.func-btn--present/sick/leave`）的取值，理由是这三个状态
   靠颜色区分才有意义（与"性别不分色"不同：性别是属性，这里是业务状态）。
   ⚠️ 但蓝色一律写 var(--primary)，**不得出现 #3B82F6 字面量**（全局基线）。

   选中态刻意做成「淡色底 + 同色描边 + 同色字」，而不是旧版的「2px 空心描边」：
   浅色极简基线里 2px 描边太重，且只靠描边在 390px 窄屏上分不出选中与未选中。
   未选中的两个保持白底 + 发丝描边 + 次级灰字，视觉上明显退到后面。 */
.att-status {
    display: flex;
    gap: 10px;
    margin-bottom: 14px;
}

.att-status__btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 38px;
    /* ⚠️ --card-line 本身就是**完整 shorthand**（`1px solid var(--border)`），
       只能整体引用 —— 写成 `border: 1px solid var(--card-line)` 会展开成
       `1px solid 1px solid …`，整条声明无效，边框被 button 重置的 `border:none` 吃掉，
       静默变成 0px（2026-09-18 真机量到 border-top-width=0px 才发现）。 */
    border: var(--card-line);
    border-radius: var(--radius-pill);
    background: var(--card-bg);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}

.att-status__btn i {
    font-size: 13px;
}

/* 选中：字重加重 + 语义色底/边/字。三个状态各一套，不共用（颜色本身就是区分信息） */
.att-status__btn--active {
    font-weight: 600;
}

.att-status__btn--present.att-status__btn--active {
    border-color: #059669;
    background: #ECFDF5;
    color: #047857;
}

.att-status__btn--sick.att-status__btn--active {
    border-color: #D97706;
    background: #FFFBEB;
    color: #B45309;
}

.att-status__btn--leave.att-status__btn--active {
    border-color: var(--primary);
    background: var(--primary-bg);
    color: var(--primary-dark);
}

/* 点名操作提示：多选这件事不写在界面上没人知道能点，更不会知道「再点一次能取消」 */
.att-tip {
    margin: 0 0 10px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-light);
}

/* 学生名单 */
.att-students {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

/* 一格一个幼儿：只放姓名，单行居中（**不再显示性别**）。
   仍用 flex 居中而非 text-align —— 3 列网格单格宽度会随屏宽变化，靠 flex 居中更稳。

   它是**可点的多选开关**（点一下打标、再点一下撤销），所以用 <button> 而不是 <div>：
   键盘可达与读屏语义都由浏览器给，不必自己补 role / tabindex。 */
.att-student {
    position: relative;          /* 右上角「待提交」圆点的定位基准 */
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 14px 6px;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    box-shadow: var(--shadow);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: center;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: var(--transition);
    -webkit-tap-highlight-color: transparent;
}

.att-student:active {
    transform: scale(0.96);
}

/* 当日出勤状态 → 卡片配色（未标记的保持白底 + 深色字，视觉上退到后面）。
   三个状态各一套、不共用 —— 颜色本身就是区分信息。

   ⚠️ 一律写成**复合选择器** `.att-student.att-student--x`：文末「设计基线统一层」里的
      `.att-student { border: … }` 是 shorthand，同权重且顺序在后，会把这里单独写的
      border-color 盖回发丝灰（2026-09-18 踩过：border 与 border-color 的覆盖顺序）。 */
.att-student.att-student--present {
    border-color: #059669;
    background: #ECFDF5;
    color: #047857;
}

.att-student.att-student--sick {
    border-color: #D97706;
    background: #FFFBEB;
    color: #B45309;
}

.att-student.att-student--leave {
    border-color: var(--primary);
    background: var(--primary-bg);
    color: var(--primary-dark);
}

/* 本地已标记、尚未提交：右上角一个小圆点，与「已写库」区分开。
   颜色取 currentColor，跟着上面的状态色走，不必再给三套颜色。 */
.att-student.att-student--pending::after {
    content: '';
    position: absolute;
    top: 6px;
    right: 6px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.7;
}

/* 中途离园附加角标：在正常出勤底色（.att-student--present）之上，右上角叠一个「离」字小标签。
   它是**附加事实**（后端 mid_leave_status=4，att_stt_code 仍是 1 出勤），所以只加角标、不动底色。
   颜色取琥珀，与「中途离园」语义对齐（见 .att-student--leavemid）。 */
.att-student__corner {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    color: #fff;
    background: #D97706;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
    pointer-events: none;
}
/* 同时有「本地待提交」圆点时，把圆点挪到左上角，避免和「离」角标在右上角重叠 */
.att-student.att-student--pending.att-student--midleave::after {
    top: 6px;
    left: 6px;
    right: auto;
}

.att-student__name {
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* ⚠️ 遗留言：性别行（浅灰小字）**已不再渲染**
   —— 需求改为学生格只显示姓名。保留不删：性别字段仍在 fetchStudentList 的映射里，
   恢复展示时把 .att-student 改回 column 排布、并在渲染里补回这一行即可。
   刻意不做蓝 / 粉分色 —— 统一基线的浅色极简里不引入性别色，
   卡片描边与投影已由文末「设计基线统一层」统一给。 */
.att-student__gender {
    max-width: 100%;
    font-size: 11px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--text-light);
}

/* 加载 / 空 / 错误态 */
.att-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 46px 20px;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    box-shadow: var(--shadow);
    font-size: 13px;
    color: var(--text-light);
    text-align: center;
}

.att-state i {
    font-size: 26px;
}

.att-state p {
    margin: 0;
    line-height: 1.6;
}

/* 占位提示的第二行小字说明
   ⚠️ 当前未使用（2026-09-18）：出勤页的学生名单接口已接真实后端，
      「接口未接入」的占位态（.att-state--placeholder + 下面这条 em）失去了唯一调用点。
      保留不删 —— 接口未接入 / 功能未开放这类「不是错误、也没有数据」的场景会反复出现
      （设置页的「待开发」条目即同类），届时直接复用。js/attendance.js 的 renderState 同此。 */
.att-state em {
    font-style: normal;
    font-size: 12px;
    line-height: 1.6;
    color: var(--text-light);
    opacity: 0.85;
}

/* 接口未接入等「暂无数据来源」的占位态，与真正的错误态区分开（当前未使用，见上） */
.att-state--placeholder i {
    color: var(--primary);
}

.att-state--error,
.att-state--error i {
    color: #A32D2D;
}

/* 底部提交
   主按钮视觉与登录页 .login-submit 同一基线（渐变蓝 135° + radius-md + 白字 600 + 阴影），
   高度取 46px 而非登录页的 52px —— 出勤页这一屏还有状态按钮与学生网格，
   52px 会把清单挤得过短，46px 仍满足触控区最小高度（≥44px）。

   ⚠️ 旧版这段叫 .bottom-buttons / .bottom-btn--submit（见「底部按钮」遗留段），
   刻意不复用：它带 2px 描边的重置按钮 + 更重的阴影，且与「重置/提交」成对出现；
   本页只有提交一个动作，且沿用当前基线的字重与圆角。 */
.att-submit {
    margin-top: 16px;
}

.att-submit__btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 46px;
    border: none;
    border-radius: var(--radius-md);
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    color: #fff;
    font-family: inherit;
    font-size: 16px;
    font-weight: 600;
    letter-spacing: 2px;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(59, 130, 246, 0.35);
    transition: var(--transition);
}

.att-submit__btn i {
    font-size: 15px;
}

.att-submit__btn:active {
    transform: scale(0.98);
    box-shadow: 0 2px 8px rgba(59, 130, 246, 0.4);
}

/* 提交中：此时按钮**真的不可点**（防重复提交），与「没有可提交内容」是两回事 ——
   后者按钮仍然可点，点了会提示先标记学生。 */
.att-submit__btn:disabled {
    cursor: default;
    opacity: 0.65;
    transform: none;
    box-shadow: none;
}

/* ============================
   中途离园上报页
   结构见 pages/leave.html，逻辑见 js/leave.js
   复用出勤页的 .att-step / .att-list / .att-class / .att-students / .att-student 组件；
   本段只补：中途离园状态色、状态小字、底部双按钮。
   ============================ */

/* 中途离园状态（code=4）：琥珀色，与出勤（绿）区分。
   ⚠️ 复合选择器 .att-student.att-student--leavemid（同出勤页，避免被统一层 .att-student 覆盖）。 */
.att-student.att-student--leavemid {
    border-color: #D97706;
    background: #FFFBEB;
    color: #B45309;
}

/* 学生格内的「姓名 + 状态小字」纵向居中（不改 .att-student 自身布局，只包一层） */
.att-student__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-width: 0;
}

.att-student__tag {
    max-width: 100%;
    font-size: 11px;
    font-weight: 500;
    line-height: 1.3;
    opacity: 0.9;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* 底部双按钮：提交中途离园（主）/ 取消中途离园（次）。
   主按钮琥珀渐变 —— 已登记进 verify-theme-consistency.js 的 GRADIENT_OK 白名单。 */
.leave-actions {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}

.leave-actions__btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 46px;
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    transition: var(--transition);
    -webkit-tap-highlight-color: transparent;
}

/* 主按钮：提交中途离园（琥珀渐变，与「中途离园」amber 主题一致） */
.leave-actions__btn--primary {
    border: none;
    background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
    color: #fff;
    box-shadow: 0 4px 14px rgba(217, 119, 6, 0.32);
}

/* 次按钮：取消中途离园（描边 + 浅底，退到后面） */
.leave-actions__btn--default {
    border: var(--card-line);
    background: var(--card-bg);
    color: var(--text-secondary);
}

.leave-actions__btn:active {
    transform: scale(0.98);
}

.leave-actions__btn:disabled {
    cursor: default;
    opacity: 0.6;
    transform: none;
    box-shadow: none;
}

/* ============================================================
   原因采集弹层（出勤病假/事假 + 中途离园共用，js/reason-modal.js 渲染）
   移动端底部抽屉式；确认按钮用实色主按钮（非渐变，不进 GRADIENT_OK 白名单）
   ============================================================ */
.reason-modal { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: flex-end; justify-content: center; }
.reason-modal__mask { position: absolute; inset: 0; background: rgba(15, 23, 42, 0.45); }
.reason-modal__panel {
    position: relative; width: 100%; max-width: 520px; box-sizing: border-box;
    background: var(--card-bg); border-radius: 18px 18px 0 0;
    padding: 20px 18px calc(20px + env(safe-area-inset-bottom));
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.18);
    animation: reasonUp .2s ease;
}
@keyframes reasonUp { from { transform: translateY(100%); } to { transform: none; } }
.reason-modal__head { margin-bottom: 14px; }
.reason-modal__title { font-size: 17px; font-weight: 700; color: var(--text); margin: 0; }
.reason-modal__sub { margin: 4px 0 0; font-size: 13px; color: var(--text-secondary); }
/* 幼儿姓名：放到醒目位置（大号 + 主色），进度「第 x / y 位」退为右侧小字 */
.reason-modal__stu { display: flex; align-items: baseline; gap: 8px; margin: 8px 0 0; }
.reason-modal__name { font-size: 20px; font-weight: 700; color: var(--primary); }
.reason-modal__idx { font-size: 12px; color: var(--text-secondary); }
.reason-modal__body { max-height: 60vh; overflow-y: auto; }
.reason-modal__field { margin-bottom: 14px; }
.reason-modal__field:last-child { margin-bottom: 0; }
.reason-modal__label { display: block; font-size: 14px; font-weight: 600; color: var(--text); margin-bottom: 8px; }
.reason-modal__req { color: #DC2626; font-style: normal; margin-left: 2px; }
.reason-modal__options { display: flex; flex-direction: column; gap: 8px; }
.reason-modal__option {
    display: flex; align-items: center; gap: 10px; padding: 12px 14px;
    border: var(--card-line); border-radius: var(--radius-md);
    background: var(--card-bg); cursor: pointer; font-size: 15px; color: var(--text);
}
.reason-modal__option.is-checked { border-color: var(--primary); background: rgba(59, 130, 246, 0.06); }
.reason-modal__option input { accent-color: var(--primary); width: 18px; height: 18px; flex: none; }
/* 具体情况：单行文本框（内容一般不多，比 textarea 省纵向空间） */
.reason-modal__detail {
    width: 100%; box-sizing: border-box; height: 44px; padding: 0 12px;
    border: var(--card-line); border-radius: var(--radius-md);
    font-family: inherit; font-size: 14px; color: var(--text);
    background: var(--card-bg);
}
.reason-modal__hint { display: block; margin-top: 6px; font-size: 12px; color: #DC2626; font-style: normal; }
/* ⚠️ 必须显式写 display:none —— 上面 .reason-modal__hint 的 display:block 会盖掉 [hidden] 的 UA 样式，
   不写的话「选『其他』时必填」红字会在**任何**选中态都一直显示（2026-09-19 真机截图发现；同类坑见 login.css 的 .login-panel[hidden]）。 */
.reason-modal [hidden] { display: none; }
.reason-modal__actions { display: flex; gap: 10px; margin-top: 6px; }
.reason-modal__btn {
    flex: 1; height: 46px; border-radius: var(--radius-md); font-size: 15px; font-weight: 600;
    font-family: inherit; cursor: pointer; transition: transform .1s ease; -webkit-tap-highlight-color: transparent;
}
.reason-modal__btn--cancel { border: var(--card-line); background: var(--card-bg); color: var(--text-secondary); }
.reason-modal__btn--confirm { border: none; background: var(--primary); color: #fff; }
.reason-modal__btn--confirm:disabled { opacity: .5; cursor: default; }
.reason-modal__btn:active { transform: scale(0.98); }

/* ============================================================
   身份页（identity.html，2026-09-19）
   ------------------------------------------------------------
   位置：**登录成功 → 本页 → 主页**。三条分支：唯一身份直通 / 多身份选择 / 无身份绑定。
   它是独立整页（与 login.html / register.html 同类），故整页滚动 + 居中窄栏；
   卡片面（描边 + 投影）交给文末「设计基线统一层」①，本段只管布局与字型 ——
   同一个属性不留两处定义。
   ============================================================ */
.identity-body {
    /* 与登录页同理：整页可滚动（矮屏 / 输入法顶起时都要能滚到底）。
       全局 body 是 overflow:hidden，不覆盖就只能显示首屏。 */
    overflow: auto;
}

.identity-page {
    max-width: 460px;
    margin: 0 auto;
    padding: 26px 20px 36px;
}

/* 品牌区：与登录 / 设置页同一套语言（极淡品牌光晕 + 横版 logo，不用蓝色色块） */
.identity-header {
    text-align: center;
    /* 通栏：抵消 .identity-page 的内边距，让光晕横跨整屏 */
    margin: -26px -20px 18px;
    /* 顶部计入安全区：身份页没有 .top-bar，品牌区就是最顶，刘海屏上 logo 会顶进状态栏 */
    padding: calc(30px + env(safe-area-inset-top, 0px)) 20px 20px;
    background: var(--brand-glow);
}

.identity-logo {
    width: 96px;
    margin: 0 auto 12px;
}

/* 横版 logo —— 与 .login-logo / .top-bar__logo / .settings-logo 同一套裁切规则。
   ⚠️ height: auto 不能省：<img> 上的 height="640" 会以 height:640px 参与层叠，
      把 aspect-ratio 挤掉（实测会被裁成一条）。 */
.identity-logo img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 631 / 412;
    object-fit: cover;
    object-position: center 40%;
}

.identity-title {
    margin: 0 0 4px 0;
    font-size: 19px;
    font-weight: 600;
    color: var(--text-primary);
    letter-spacing: 0.06em;
}

.identity-account {
    margin: 0;
    font-size: 12px;
    color: var(--text-light);
}

/* 阶段卡片：加载 / 自动确认 / 选择 / 绑定 / 错误，同一时刻只显示一张，
   切换靠 HTML 的 hidden 属性（兜底规则见下面的 [hidden]）。 */
.identity-card {
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    padding: 18px;
    margin-bottom: 16px;
}

.identity-card__title {
    margin: 0 0 6px 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.identity-card__hint {
    margin: 0 0 14px 0;
    font-size: 13px;
    color: var(--text-secondary);
}

/* 🔴 hidden 必须显式兜底：作者样式的 display 会盖掉 HTML hidden 属性的 UA 规则
   （与 .reason-modal [hidden]、.login-panel[hidden] 同一类坑 —— 本项目已踩过两次）。
   本页五个阶段块全靠 hidden 切换，漏了会出现「加载中 + 错误态同时出现」。 */
.identity-page [hidden] {
    display: none;
}

/* 进行中 / 加载中的一行提示 */
.identity-state {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin: 6px 0;
    font-size: 14px;
    color: var(--text-secondary);
}

.identity-state i { color: var(--primary); }
.identity-state--muted { font-size: 12px; color: var(--text-light); }

/* 唯一身份自动确认：姓名放大，角色 / 园所退为副行 */
.identity-auto__name {
    margin: 2px 0 4px;
    font-size: 20px;
    font-weight: 700;
    color: var(--primary);
}

.identity-auto__meta {
    margin: 0 0 10px;
    font-size: 13px;
    color: var(--text-secondary);
}

/* 选项列表（多身份选择）与教师列表共用同一套外壳间距 */
.identity-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* 多身份：整行可点 */
.identity-option {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 12px 14px;
    background: var(--card-bg);
    border-radius: var(--radius-md);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.identity-option__main { flex: 1; min-width: 0; }

.identity-option__name {
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
}

.identity-option__meta {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-secondary);
}

.identity-option__arrow { font-size: 13px; color: var(--text-light); }
.identity-option:active { transform: scale(0.995); }

/* 绑定流程：第 1 步（园所）/ 第 2 步（本人档案）共用 */
.identity-step { display: block; }

.identity-field { display: block; margin-bottom: 10px; }

.identity-field__label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    color: var(--text-secondary);
}

.identity-field__input {
    width: 100%;
    height: 44px;                      /* 与登录页输入框同高：同一个控件不出现两种高度 */
    padding: 0 12px;
    border: var(--card-line);
    border-radius: var(--radius-md);
    background: var(--card-bg);
    font-family: inherit;
    font-size: 15px;
    color: var(--text-primary);
}

.identity-field__input:focus {
    outline: none;
    border-color: var(--primary);
}

/* 搜索行：输入框 + 搜索按钮 */
/* 🔴 输入框与「搜索」按钮**强制上下两行**（用户实测反馈「输入框过小、显示不全」）。
   根因：.identity-btn 是 width:100%，而 <input> 默认按一行 20 字符给最小宽度，
   两者在同一 flex 行里互抢宽度 ⇒ 输入框被压到约 146px，18 位身份证号显示不全。
   改 flex-direction:column 后，两者各自整行宽，号码完整可见。 */
.identity-search {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 12px;
}

/* 两行布局下不再需要 flex:1（否则单列里 input 会被拉伸得怪）；
   让 input 按自身 100% 宽度整行显示即可。 */
.identity-search .identity-field__input { width: 100%; }

/* 搜索按钮也整行宽：两行布局里它本就是独占一行，这里显式锁住，
   免得哪天 .identity-btn 的 width 规则被改回 auto 又变回去。 */
.identity-search .identity-btn { width: 100%; }

/* 教师条目：与「多身份选项」的区别在右侧 —— 这里是一个明确动作（绑定），
   不是整行可点，避免"点到哪儿都在选"的误触。 */
.identity-teacher {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    background: var(--card-bg);
    border-radius: var(--radius-md);
}

.identity-teacher__main { flex: 1; min-width: 0; }

.identity-teacher__name {
    display: block;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.identity-teacher__meta {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-secondary);
}

/* 空列表是**正常业务结果**（该园没有教师 / 关键词没匹配上），不是错误态 */
.identity-empty {
    margin: 0;
    padding: 16px 0;
    text-align: center;
    font-size: 13px;
    color: var(--text-light);
}

.identity-tip {
    display: flex;
    gap: 6px;
    margin: 0 0 14px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-secondary);
}

.identity-tip i { color: var(--primary); margin-top: 2px; }

/* 「没查到 → 自主新增」入口：与列表区同宽，给一句话 + 一个出口。
   刻意不并进 .identity-empty —— 那是「结果为空」的陈述，这里要的是一条**出路**。 */
.identity-create-entry { margin-bottom: 12px; }

.identity-create-entry .identity-empty { padding: 12px 0; }

/* 录入表单的消息条：默认中性，`--error` 为失败（本地校验不通过 / 服务端 400·403·404·409）。
   错误用红、而「身份暂不可用」用琥珀 —— 前者是「这次没成」，后者是「你没错」，别混。 */
.identity-msg {
    margin: 0 0 12px;
    padding: 10px 12px;
    border: var(--card-line);
    border-radius: var(--radius-md);
    background: var(--card-bg);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-secondary);
}

.identity-msg--error {
    border-color: #FECACA;
    background: #FEF2F2;
    color: #B91C1C;
}

/* 「身份暂不可用」（profile_code 2001 / 2002）：**告知**而非报错 ——
   用户没做错任何事，是园所档案没建好 / 家长功能还没上线。
   故用琥珀色提示卡（与中途离园角标同一色系），不用错误态的红色。 */
.identity-blocked {
    padding: 12px 14px;
    margin-bottom: 10px;
    border: 1px solid #FDE68A;
    border-radius: var(--radius-md);
    background: #FFFBEB;
}

.identity-blocked__who {
    margin: 0 0 4px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.identity-blocked__reason {
    margin: 0;
    font-size: 12px;
    line-height: 1.5;
    color: #B45309;
}

/* 按钮：主（品牌色实心，与全站主按钮同一画法）/ 次（浅底 + 描边，退到后面） */
.identity-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    height: 46px;
    border: none;
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
}

.identity-btn--primary {
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    color: #fff;
    box-shadow: var(--shadow);
}

.identity-btn--ghost {
    background: var(--primary-bg);
    color: var(--primary);
    border: var(--card-line);
}

.identity-btn--sm {
    width: auto;
    height: 32px;
    padding: 0 14px;
    font-size: 13px;
    flex-shrink: 0;
}

.identity-btn:active { transform: scale(0.99); }

/* 同一步骤里上下叠放的按钮（下一步 / 上一步） */
.identity-step .identity-btn + .identity-btn { margin-top: 12px; }

/* 按钮组（`.identity-actions`）与上方内容、组内按钮之间的间距。
   ⚠️ 这个类此前**完全没有规则** —— 间距只写在 `.identity-step` 上，而自主录入 /
      blocked / error / 身份列表这几块用的是 `.identity-actions`，
      于是「提交并绑定」和「返回」两个 46px 高的按钮几乎贴在一起（2026-09-20 反馈）。
      这里用 flex + gap 统一给，避免以后再漏；`hidden` 的按钮由
      `.identity-page [hidden]{display:none}` 兜底，不会占 gap。 */
.identity-actions {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-top: 18px;
}

/* ============================================================
   设计基线统一层（2026-09-18）
   ------------------------------------------------------------
   为什么集中放在文件末尾：同权重的规则，**顺序在后的覆盖前面的** ——
   改这一处即"全局统一"，不必在上千行里做几十处分散改动（那种改法既无法验证，也极易漏改）。

   基线来自 css/login.css（登录 / 注册页）：
     浅色底、不用渐变色块、卡片带发丝描边、胶囊分页、图标方圆角浅底。

   ⚠️ **签名级改动仍要就地改**，不在本层加覆盖：一个属性只应有一处定义，
      否则读源码时会看到"旧值写在前面、新值藏在文件末尾盖着"这种误导。
      已就地改掉的：.top-bar 蓝色渐变块 → 白底 + 发丝线；
      .settings-header 蓝块 + 白圆衬底 → 品牌光晕 + 横版 logo。
   ============================================================ */

/* ① 卡片面统一：加发丝描边 + 轻投影
   与登录页的 .login-field 同一手法 —— 浅色底上只靠投影的卡片边界发虚，
   加一条 1px 描边后"面"才立得住（为什么不是 1.5px 见 :root 里 --card-line 的说明）。 */
.home-profile,
.home-quick__item,
.home-plan,
.settings-list,
.logout-btn,
.att-class,
.att-student,
.att-state,
.identity-card,
.identity-option,
.identity-teacher {
    border: var(--card-line);
    box-shadow: var(--shadow);
}

/* ② 区块标题统一：15px/700 深色 + 左侧品牌色条
   原先有三套写法（首页 15px/700 带色条、设置页 16px/600 灰字、出勤页 15px/700 无色条），这里三合一。 */
.settings-section .section-title,
.att-step__title {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-left: 0;          /* 设置页原本有 4px 缩进，与首页的色条对齐方式不一致 */
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.settings-section .section-title::before,
.att-step__title::before {
    content: '';
    width: 3px;
    height: 14px;
    border-radius: 2px;
    background: var(--primary);
    flex-shrink: 0;
}

/* 出勤页的标题在 .att-step__head 这个 flex 行里（前面是返回按钮、后面是提示），
   所以色条不能占掉标题该有的伸展空间，下边距也由 .att-step__head 统一给。 */
.att-step__title {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
}

/* ④ 分页控件统一为胶囊（基线是登录页的 .login-tabs：浅灰底 + 白色选中块 + 蓝字）
   ⚠️ 选中类名是 BEM 的 `.tab-btn--active`，与 .nav-btn--active 同风格。
      旧实时页那套 `.tab-btn.active`（非 BEM）已随页面移除，别混用 —— 混了就是"点了没高亮"。 */
.tab-bar {
    display: flex;
    padding: 4px;
    background: rgba(148, 163, 184, 0.16);
    border-radius: var(--radius-pill);
    box-shadow: none;
}

.tab-bar .tab-btn {
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--text-secondary);
    font-weight: 400;
    box-shadow: none;
}

.tab-bar .tab-btn--active {
    background: #fff;
    color: var(--primary);
    font-weight: 600;
    box-shadow: 0 1px 4px rgba(30, 64, 175, 0.14);
}

/* ============================
   小屏适配（≤ 360px：iPhone SE / 小屏安卓）
   2026-09-19 移动端自适应收尾：让最窄的常见机型也能完整放下，杜绝横向滚动。
   只收「内边距 / 字号」这些缩放安全量，不动布局结构；安全区增量照旧保留。
   ============================ */
@media (max-width: 360px) {
    .top-bar {
        padding: calc(14px + env(safe-area-inset-top, 0px)) 14px 14px;
    }
    .content-area {
        padding: 16px 12px calc(96px + env(safe-area-inset-bottom, 0px));
    }
    .identity-page {
        padding: 18px 14px 28px;
    }
    .identity-header {
        padding: calc(24px + env(safe-area-inset-top, 0px)) 14px 16px;
    }
    .identity-card {
        padding: 14px;
    }
    .identity-logo {
        width: 84px;
    }
    .identity-title {
        font-size: 17px;
    }
    .login-header {
        padding-left: 16px;
        padding-right: 16px;
    }
    .login-panel {
        padding: 18px 16px;
    }
    /* 输入框 ≥ 16px：iOS Safari 在聚焦小于 16px 的输入框时会整页缩放，
       小屏上这一下缩放会把布局撑破。 */
    .identity-field__input,
    .identity-search .identity-field__input {
        font-size: 16px;
    }
}

/* ============================
   权限层（2026-09-20）：模块权限隐藏入口、操作权限禁用按钮
   ------------------------------------------------------------
   js/permission.js 只负责**打标记**，视觉落在这里：
     · .perm-hidden      —— 没有模块/操作权限，整个区块不出现（入口级）
     · .is-perm-denied   —— 有模块权限但缺操作权限，控件禁用（按钮级）
     · .perm-note        —— 「只有查看权限」的说明条，避免用户以为页面坏了
   ⚠️ 为什么 .perm-hidden 用 !important：它要盖过页面自己的显隐逻辑
      （如 .att-submit 默认 class="hidden"、由脚本控制显示），
      但不改页面那个 class —— 两边各管各的，互不抢。
   ⚠️ 为什么禁用态另起 .is-perm-denied 而不是只靠 :disabled：
      :disabled 只覆盖 button/input，容器（如 .att-status 状态选择组）需要
      一个能一眼看出「这块不可用」的信号，否则用户会以为按钮坏了。
   ============================ */
.perm-hidden {
    display: none !important;
}

.is-perm-denied {
    opacity: .55;
    cursor: not-allowed;
}

/* 只读说明条：琥珀浅底 —— 是「权限没开」不是「出错了」，别用红色吓人 */
.perm-note {
    margin: 12px 0 0;
    padding: 10px 12px;
    border: 1px solid #FDE68A;
    border-radius: 12px;
    background: #FFFBEB;
    color: #92400E;
    font-size: 13px;
    line-height: 1.55;
}

/* 嵌在设置列表里的那一条：去掉左右留白，与 .setting-item 对齐 */
.perm-note--inline {
    margin: 6px 16px 0;
    font-size: 12px;
    padding: 8px 12px;
}

/* 快捷功能一个都不剩时的兜底文案（不是错误，是「还没给你开」） */
.home-quick__empty {
    margin: 0;
    padding: 14px 0;
    color: var(--text-light, #94A3B8);
    font-size: 13px;
    text-align: center;
}

/* ============================
   应用模块（归档 `041`）
   ============================ */
/* 应用卡片：左图标 + 中标题说明 + 右箭头。
   🔑 用 grid 而不是 flex：说明文字长度不一，flex 下箭头会被长文案推歪。 */
.app-grid {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.app-card {
    display: grid;
    grid-template-columns: 40px 1fr 14px;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 14px 16px;
    border: none;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    box-shadow: var(--shadow);
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    transition: var(--transition);
}

.app-card:active {
    transform: scale(0.98);
    box-shadow: var(--shadow-hover);
}

.app-card__icon {
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    font-size: 17px;
    background: var(--primary-bg);
    color: var(--primary);
}

.app-card__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.app-card__title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.app-card__desc {
    font-size: 12px;
    color: var(--text-light);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-card__arrow {
    font-size: 12px;
    color: var(--text-light);
}

/* 「开发中」的应用：与首页快捷区同款角标（语义见 .home-quick__item--wip 的注释） */
.app-card--wip {
    position: relative;
}

.app-card--wip::after {
    content: '开发中';
    position: absolute;
    top: -6px;
    right: 10px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--text-light);
    color: #fff;
    font-size: 10px;
    font-weight: 600;
    line-height: 1.6;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.18);
    pointer-events: none;
}

.app-card[data-tone="teal"] .app-card__icon   { background: #E1F5EE; color: #0F6E56; }
.app-card[data-tone="amber"] .app-card__icon  { background: #FAEEDA; color: #854F0B; }
.app-card[data-tone="red"] .app-card__icon    { background: #FCEBEB; color: #A32D2D; }
.app-card[data-tone="blue"] .app-card__icon   { background: #E6F1FB; color: #185FA5; }
.app-card[data-tone="purple"] .app-card__icon { background: #EEEDFE; color: #3C3489; }
.app-card[data-tone="green"] .app-card__icon  { background: #EAF3DE; color: #3B6D11; }
.app-card[data-tone="gray"] .app-card__icon   { background: #F1EFE8; color: #5F5E5A; }

/* ============================
   用户审核（归档 `041`）
   ============================ */
.review-tabs {
    display: flex;
    gap: 8px;
    margin: 12px 0;
}

.review-tab {
    flex: 1;
    padding: 8px 0;
    border: var(--card-line);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    font-family: inherit;
    font-size: 13px;
    color: var(--text-secondary);
    cursor: pointer;
    transition: var(--transition);
}

.review-tab.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
    font-weight: 600;
}

/* 列表项里的状态小标签（已通过 / 已驳回的历史条目看得见自己是什么结果） */
.review-status {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 500;
    background: #F1EFE8;
    color: #5F5E5A;
}

.review-status--0 { background: #FAEEDA; color: #854F0B; }
.review-status--1 { background: #EAF3DE; color: #3B6D11; }
.review-status--2 { background: #FCEBEB; color: #A32D2D; }

/* ============================
   添加学生（归档 `041`）
   ============================ */
.sc-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.sc-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.sc-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.sc-required {
    color: #A32D2D;
    font-weight: 700;
}

.sc-input {
    width: 100%;
    padding: 10px 12px;
    border: var(--card-line);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    font-family: inherit;
    font-size: 14px;
    color: var(--text-primary);
}

.sc-input:focus {
    outline: none;
    border-color: var(--primary);
}

.sc-tip {
    font-size: 12px;
    color: var(--text-light);
}

/* ============================
   权限分配（归档 `041`）
   ============================ */
.pa-select {
    width: 100%;
    padding: 10px 12px;
    border: var(--card-line);
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    font-family: inherit;
    font-size: 14px;
    color: var(--text-primary);
}

.pa-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin: 10px 0;
    font-size: 12px;
    color: var(--text-secondary);
}

.pa-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.pa-tree {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 12px 0;
}

.pa-module {
    border: var(--card-line);
    border-radius: var(--radius-md);
    background: var(--card-bg);
    overflow: hidden;
}

.pa-module__head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: var(--primary-bg);
    font-size: 13px;
    font-weight: 700;
    color: var(--primary);
}

.pa-module__code {
    font-size: 11px;
    font-weight: 400;
    color: var(--text-light);
}

.pa-module__body {
    display: flex;
    flex-direction: column;
    padding: 8px 14px 12px;
}

.pa-module__empty {
    font-size: 12px;
    color: var(--text-light);
}

.pa-node {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 0;
    font-size: 13px;
    color: var(--text-primary);
    cursor: pointer;
}

.pa-node__box {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.pa-node__name {
    font-weight: 500;
}

.pa-node__code {
    font-size: 11px;
    color: var(--text-light);
}

/* 🔴 「来自用户组」的点锁死 —— 不锁死的话用户取消勾选一次、保存、刷新发现还在，
      界面就在撒谎（后端直授是纯追加语义，取消不掉组的权限）。 */
.pa-node--locked {
    cursor: not-allowed;
    color: var(--text-secondary);
}

.pa-node__tag {
    padding: 1px 6px;
    border-radius: 999px;
    background: #F1EFE8;
    color: #5F5E5A;
    font-size: 10px;
    font-weight: 600;
}

/* ============================
   总览 · 概况（归档 `042`）
   ============================ */
/* ① 今日出勤概况卡（AI 尚未接入，仅预留位）
   🔑 用一条左侧主色竖线把它与下面的真实统计区分开：
      上面是「系统在推测」，下面是「库里真实的数」，视觉上必须一眼分得清。 */
.ov-ai {
    border-left: 3px solid var(--primary);
}

.ov-ai__head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 8px;
}

.ov-ai__title {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
}

.ov-ai__title i {
    color: var(--primary);
}

/* 徽标：AI / 测试中。
   ⚠️ 这两个标签是**合规要求**不是装饰 —— 只要卡片里的内容还不是模型输出，
      就必须一直挂着，别在「看起来做好了」之后悄悄摘掉。 */
.ov-tag {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 600;
    line-height: 1.7;
}

/* ⚠️ 归档 049（2026-09-21）：本项目第四次踩同一个坑 ——
   .ov-tag 的 display:inline-block、.ov-ai__body 的 display:flex 都是作者样式，
   会盖掉 [hidden] 属性的 UA 样式（同 .reason-modal [hidden]、.identity-page [hidden]、
   .login-panel[hidden]）。不兜底的话，「分析中」徽标与 AI 正文空盒子
   会在任何状态下一直显示（2026-09-21 真机截图发现）。 */
.ov-ai [hidden] {
    display: none;
}

.ov-tag--ai {
    background: #EEEDFE;
    color: #3C3489;
}

.ov-tag--beta {
    background: #FAEEDA;
    color: #854F0B;
}

.ov-ai__text {
    font-size: 13px;
    line-height: 1.7;
    color: var(--text-secondary);
}

.ov-ai__note {
    margin-top: 8px;
    font-size: 11px;
    line-height: 1.6;
    color: var(--text-light);
}

/* ② 关键指标：两格等宽，数字用等宽感更强的字重压住 */
.ov-kpi {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    margin-bottom: 16px;
}

.ov-kpi__item {
    padding: 14px 16px;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    box-shadow: var(--shadow);
}

.ov-kpi__label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-secondary);
}

.ov-kpi__label i {
    color: var(--primary);
}

.ov-kpi__value {
    margin-top: 6px;
    font-size: 26px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text-primary);
}

.ov-kpi__sub {
    margin-top: 4px;
    font-size: 11px;
    color: var(--text-light);
}

/* ③ 柱图容器：班级多达十几个，横轴标签要斜排 ⇒ 必须给足高度，
      否则标签被裁掉一半（ECharts 不会报错，只会静静画歪）。 */
.ov-chart {
    height: 300px;
}

/* ============================
   总览 · 请假（归档 `043`）
   ============================ */
/* 三格 KPI（概况是两格，这里是三格 ⇒ 单独一条规则，不覆盖 .ov-kpi 的两列基线） */
.ov-kpi--three {
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.ov-kpi--three .ov-kpi__value {
    font-size: 22px;
}

.ov-kpi--three .ov-kpi__label {
    font-size: 11px;
}

/* 图表下方的一行口径说明。
   🔑 它**不是**装饰 —— 「分母是什么」不说清楚，同一张图能读出两种意思。 */
.ov-note {
    margin-top: 8px;
    font-size: 11px;
    line-height: 1.6;
    color: var(--text-light);
}

/* ============================
   总览 · 出勤热点图（🆕 归档 `051`）
   每天一个方块，按月分组；颜色越深 = 当日出勤率越高，灰块 = 无上报数据。
   ============================ */
.ov-heatmap {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}

.ov-heatmap__month {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.ov-heatmap__monthName {
    flex: 0 0 28px;
    font-size: 11px;
    color: var(--text-light);
    line-height: 14px;
    padding-top: 1px;
}

.ov-heatmap__cells {
    flex: 1 1 auto;
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
}

.ov-heatmap__cell {
    width: 14px;
    height: 14px;
    padding: 0;
    border: 1px solid rgba(0, 0, 0, 0.04);
    border-radius: 3px;
    background: #e5e7eb;            /* 默认 = 无数据灰 */
    cursor: pointer;
    transition: transform .08s ease;
}

.ov-heatmap__cell:active {
    transform: scale(0.9);
}

/* 四档颜色：出勤率越高颜色越深（90-100% 最深，<70% 最淡） */
.ov-heatmap__cell--4 { background: #065f46; }
.ov-heatmap__cell--3 { background: #10b981; }
.ov-heatmap__cell--2 { background: #6ee7b7; }
.ov-heatmap__cell--1 { background: #d1fae5; }
.ov-heatmap__cell--empty { background: #e5e7eb; }

.ov-heatmap__detail {
    margin-top: 8px;
    font-size: 12px;
    color: var(--text-primary);
    background: var(--primary-bg);
    border-radius: var(--radius-sm);
    padding: 6px 10px;
}
/* 🔴 hidden 属性兜底（049 同款坑）：作者样式会盖掉浏览器默认 [hidden]{display:none} */
.ov-heatmap__detail[hidden] { display: none; }

.ov-heatmap__legend {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 4px;
    font-size: 11px;
    color: var(--text-light);
}

.ov-heatmap__legendItem {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.ov-heatmap__swatch {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.04);
    background: #e5e7eb;
}

/* 原因明细表：十几列必然超出屏宽 ⇒ 横向滚动 + 首列冻结。
   ⚠️ 冻结列必须给背景色，否则滚动时下面的数字会透上来。 */
.ov-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin-top: 10px;
    border-radius: var(--radius-sm);
    border: var(--card-line);
}

.ov-table {
    border-collapse: collapse;
    width: max-content;
    min-width: 100%;
    font-size: 12px;
}

.ov-th {
    padding: 7px 10px;
    border: var(--card-line);
    background: var(--primary-bg);
    color: var(--text-secondary);
    font-weight: 600;
    white-space: nowrap;
    text-align: center;
}

.ov-th--sub {
    font-weight: 500;
    font-size: 11px;
}

/* 冻结列：班级名与合计都要能一直看见，否则横滚之后不知道在看哪个班 */
.ov-th--sticky {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--primary-bg);
    text-align: left;
}

.ov-th--row {
    font-weight: 600;
    color: var(--text-primary);
}

.ov-td {
    padding: 7px 10px;
    border: var(--card-line);
    color: var(--text-light);
    text-align: center;
    white-space: nowrap;
}

/* 只有「真有人」的格子才上色 —— 十来列全是 0 时，
   把有数的那几格点亮，一眼就能定位到哪个班、哪个原因。 */
.ov-td--hit {
    color: var(--text-primary);
    font-weight: 600;
    background: #FFF7ED;
}

.ov-td--total {
    color: var(--text-primary);
    font-weight: 700;
    background: #F8FAFC;
}

.ov-empty {
    padding: 14px 0;
    font-size: 12px;
    color: var(--text-light);
    text-align: center;
}

/* ============================
   总览 · 厨房（归档 `044`）
   ============================ */
/* 「后续实现」徽标。
   ⚠️ 与「测试中 / AI」同族但语义不同：**那两个是「有东西但不可全信」，
   这个是「还没有东西」**。颜色刻意做成中性灰，别让人误以为已经在跑。 */
.ov-tag--todo {
    background: #F1EFE8;
    color: #5F5E5A;
}

/* 各班来校人数：三列网格，一个班一格。
   🔑 十几个班排成一列会很长，用网格让厨房一眼扫完；数字压到 24px 是这一页的主角。 */
.ov-class-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    margin-top: 10px;
}

.ov-class {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 12px 6px;
    border-radius: var(--radius-md);
    background: var(--primary-bg);
    border: var(--card-line);
    text-align: center;
}

.ov-class__name {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.ov-class__num {
    font-size: 24px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--primary);
}

.ov-class__unit {
    font-size: 10px;
    color: var(--text-light);
}

/* 🔴 「0 人」的班刻意压暗 —— 今天大部分班还没上报时，
   把「有数的那几格」凸显出来，比满屏一样的数字更有用。
   注意：这是**数字真的是 0**（已上报且没人来），与过敏区的「—」（无数据）不同。 */
.ov-class[data-zero="1"] {
    background: var(--card-bg);
}

.ov-class[data-zero="1"] .ov-class__num {
    color: var(--text-light);
}

/* ============================
   总览 · 请假明细（归档 `046`）
   ============================ */
/* 拆分后的两张子表（病假明细 / 事假明细）各占一个 section */
.lv-split {
    margin-top: 14px;
}

/* 🆕 归档 `046`：包两张明细子表（病假 / 事假）的容器（改名自 ov-table-wrap）。
   本身不渲染边框，仅做纵向间距；内部布局交给 .lv-split / .ov-table-wrap。 */
.lv-tables {
    display: block;
}
.lv-tables .lv-split + .lv-split {
    margin-top: 18px;
}

.lv-split__title {
    margin: 0 0 8px 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    padding-left: 8px;
    border-left: 3px solid var(--primary);
}

/* 可点的数字格：沿用 --hit 的橙色底，再加「能点」的手势与按压反馈 */
.ov-td--link {
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.ov-td--link:active {
    background: #FFEDD5;
}

/* 明细弹层：点击数字后展示该班该原因的具体幼儿名单。
   挂 document.body（position:fixed 覆盖视口），关闭即移除 —— 与 reason-modal 同套路。 */
.lv-detail {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

.lv-detail__mask {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
}

.lv-detail__panel {
    position: relative;
    width: 100%;
    max-width: 480px;
    max-height: 72vh;
    display: flex;
    flex-direction: column;
    background: var(--card-bg, #fff);
    border-radius: 16px 16px 0 0;
    overflow: hidden;
}

.lv-detail__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px 10px;
    border-bottom: var(--card-line);
}

.lv-detail__title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.lv-detail__close {
    border: none;
    background: transparent;
    padding: 4px 8px;
    font-size: 16px;
    color: var(--text-secondary);
    cursor: pointer;
}

.lv-detail__body {
    padding: 6px 16px 20px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}


/* ==========================================================================
   归档 `048` 维护类页面样式（.mg-* 名单型 / .cs-* 配置型）
   --------------------------------------------------------------------------
   覆盖页面：创建教职工 / 班级范围 / 过敏学生 / 学生信息维护 / 教师信息维护。

   🔴 语义色一律成"底 + 字"成对给（与 .app-card[data-tone] 同一套色板）：
      只给 color 不给 background，在浅色底上会读不清；只给 background 不给 color，
      文字会继承 --text-primary（深色）而在深底上发灰。

   ⚠️ --card-line 是**一整条 border 简写**，只能写 `border: var(--card-line);`。
   ========================================================================== */

/* ---- .mg-* 名单型：过滤条 / 名单 / 行 ---- */

.mg-filter {
    display: flex;
    gap: 8px;
    margin-bottom: 10px;
}

.mg-filter > .pa-select {
    flex: 1;
    min-width: 0;
}

.mg-count {
    font-size: 12px;
    font-weight: 400;
    color: var(--text-secondary);
}

.mg-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* 一行 = 一条档案。左侧主信息可换行收缩，右侧操作区**不压缩**
   （`flex-shrink: 0`）：否则「停用」两个字会被挤成竖排，误触率飙升。 */
.mg-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--card-bg);
    border: var(--card-line);
    border-radius: var(--radius-md);
}

.mg-row--off {
    opacity: 0.62;
}

.mg-row__main {
    flex: 1;
    min-width: 0;
}

.mg-row__title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.mg-row__meta {
    margin-top: 3px;
    font-size: 12px;
    color: var(--text-secondary);
    word-break: break-all;
}

.mg-row__ops {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* 「不可修改」比「按钮置灰」更诚实：置灰会让人以为"过会儿就能点"，
   而无权就是无权 —— 这里连按钮都不给。 */
.mg-row__locked {
    font-size: 12px;
    color: var(--text-secondary);
}

.mg-btn {
    border: var(--card-line);
    background: var(--card-bg);
    color: var(--text-primary);
    border-radius: var(--radius-pill);
    padding: 5px 12px;
    font-size: 13px;
    cursor: pointer;
    transition: var(--transition);
}

.mg-btn:active {
    background: var(--primary-bg);
}

.mg-btn--danger {
    color: #A32D2D;
    border-color: #F5C6C6;
    background: #FCEBEB;
}

.mg-btn[disabled] {
    opacity: 0.5;
    cursor: default;
}

/* ---- .mg-badge 徽标：底 + 字成对 ---- */

.mg-badge {
    display: inline-block;
    padding: 1px 7px;
    border-radius: var(--radius-sm);
    font-size: 11px;
    font-weight: 500;
    line-height: 1.6;
    background: #F1EFE8;
    color: #5F5E5A;
}

.mg-badge--gender { background: #E6F1FB; color: #185FA5; }   /* 性别 · 中性信息 */
.mg-badge--self   { background: #E1F5EE; color: #0F6E56; }   /* 本人 */
.mg-badge--on     { background: #EAF3DE; color: #3B6D11; }   /* 在岗 / 在册 */
.mg-badge--off    { background: #F1EFE8; color: #5F5E5A; }   /* 已离园 / 已解除 / 离职 */

/* 过敏严重度：1 轻度 / 2 中度 / 3 重度 —— 数字即语义，按数字命名，不另起别名 */
.mg-badge--sev1 { background: #FAEEDA; color: #854F0B; }
.mg-badge--sev2 { background: #FAEEDA; color: #854F0B; }
.mg-badge--sev3 { background: #FCEBEB; color: #A32D2D; }

/* ---- .mg-result 结果回显（建号成功后的账号 / 初始密码）---- */

.mg-result {
    margin-top: 12px;
    padding: 12px;
    background: var(--primary-bg);
    border: var(--card-line);
    border-radius: var(--radius-md);
}

.mg-result__row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 4px 0;
    font-size: 13px;
    color: var(--text-primary);
}

.mg-result__row + .mg-result__row {
    border-top: var(--card-line);
}

/* ---- .cs-* 配置型：MODE 单选 + 班级勾选 ---- */

.cs-mode {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 0 10px;
}

.cs-mode__item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    background: var(--card-bg);
    border: var(--card-line);
    border-radius: var(--radius-md);
    font-size: 14px;
    color: var(--text-primary);
    cursor: pointer;
}

.cs-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.cs-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--card-bg);
    border: var(--card-line);
    border-radius: var(--radius-md);
    cursor: pointer;
}

.cs-item__box {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
}

.cs-item__name {
    font-size: 14px;
    color: var(--text-primary);
}

/* ---- 应用卡新增两个 tone（归档 048 用了 indigo / cyan）----
   🔴 与 .app-card[data-tone] 既有七色同一色板，避免"新增功能自己发明颜色"。 */
.app-card[data-tone="indigo"] .app-card__icon { background: #EEEDFE; color: #3C3489; }
.app-card[data-tone="cyan"] .app-card__icon   { background: #E1F5EE; color: #0F6E56; }


/* ==========================================================================
   归档 `047` 概况 AI 卡 + 厨房过敏区（补 048 回归发现的 9 个"用了没定义"的类）
   --------------------------------------------------------------------------
   🔴 归档 046 教训：类名用了而 CSS 没定义 ⇒ 页面渲染成裸 HTML，**不报错、不进控制台**，
      只能靠 verify-overview.js 的「C 用到的类名在 style.css 里都有定义」这条断言兜住。
   ========================================================================== */

.ov-ai__refresh {
    border: var(--card-line);
    background: var(--card-bg);
    color: var(--text-secondary);
    border-radius: var(--radius-pill);
    padding: 3px 10px;
    font-size: 12px;
    cursor: pointer;
    transition: var(--transition);
}

.ov-ai__refresh:active {
    background: var(--primary-bg);
}

.ov-ai__body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 8px;
}

.ov-ai__block {
    padding: 8px 10px;
    background: var(--primary-bg);
    border-radius: var(--radius-sm);
}

.ov-ai__label {
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.ov-ai__para {
    font-size: 13px;
    line-height: 1.7;
    color: var(--text-secondary);
    white-space: pre-wrap;
}

/* 预警 / 建议两条列表：色带在左侧（不靠颜色单独表意，前面还有标题文字） */
.ov-alert,
.ov-suggest {
    margin: 0;
    padding-left: 18px;
    font-size: 13px;
    line-height: 1.8;
    color: var(--text-secondary);
}

.ov-alert {
    color: #A32D2D;
}

.ov-ai__meta {
    margin-top: 4px;
    font-size: 11px;
    color: var(--text-secondary);
}

/* ---- 厨房过敏区 ---- */

.ov-allergy {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 8px;
}

.ov-allergy__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 7px 10px;
    background: var(--card-bg);
    border: var(--card-line);
    border-radius: var(--radius-sm);
}

.ov-allergy__name {
    font-size: 14px;
    color: var(--text-primary);
}

.ov-allergy__num {
    font-size: 14px;
    font-weight: 600;
    color: #A32D2D;
}

.ov-allergy__src {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
}

.ov-allergy__srcTitle {
    font-size: 12px;
    color: var(--text-secondary);
}

.ov-allergy__tag {
    padding: 2px 8px;
    background: #FCEBEB;
    color: #A32D2D;
    border-radius: var(--radius-pill);
    font-size: 12px;
}
