/* ==========================================================================
   志愿者管理系统 · 全局样式
   纯自研 CSS，无任何外部依赖 / 无构建步骤
   设计基调：专业救援蓝 + 干净留白，桌面端侧边栏，移动端抽屉 + 底部导航
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. 设计令牌
   --------------------------------------------------------------------------
   皮肤系统（需求 #66）的全部秘密就在这里：页面里所有颜色都从这里取值，
   换皮肤 = 换这一堆变量的值，一行布局代码都不用动。

   分三层：
     ① 调色板（--c-*）：字面颜色，只在本节出现，别处不许直接写 hex
     ② 语义变量：按用途命名（surface / text / border …），组件只认语义
     ③ 皮肤覆盖：[data-skin="xxx"] 只改语义变量，不改语义变量名

   为什么强调「别处不许直接写 hex」：10 套皮肤必须保证每套都好看，
   只要有一个组件偷偷写死了 #fff，深色皮肤下就会冒出一块刺眼的白。
   -------------------------------------------------------------------------- */

/* 恒量：与皮肤无关的颜色。放在最前面，皮肤覆盖段不许动它们。 */
:root {
  /* 纯白 / 纯黑在需要「绝对对错」的地方使用：
     彩色按钮上的白字、头像白边、遮罩。这些在深色皮肤下也必须保持原样，
     否则按钮上的文字会跟着变深，直接看不清。 */
  --fixed-white: #FFFFFF;
  --mask:        rgba(15, 23, 42, .48);
  --mask-soft:   rgba(15, 23, 42, .28);
}

:root,
[data-skin="blue"] {
  /* 品牌主色（默认：救援蓝） */
  --brand:          #1D5FD0;
  --brand-dark:     #123C86;
  --brand-darker:   #0C2A61;
  --brand-light:    #E8F0FE;
  --brand-lighter:  #F3F7FE;
  --brand-mid:      #5CA0FF;   /* 品牌色阶的浅端：进度条、柱状图渐变 */
  --brand-border:   #CFE0FA;   /* 品牌色系描边（选中态、浅色容器） */
  --brand-ink:      #0C2A61;   /* 品牌色系深字（浅底容器上） */
  /* 品牌渐变：侧栏顶部、登录页背景、海报底图共用 */
  --brand-grad:      linear-gradient(140deg, #3D8BFF, #1D5FD0 60%, #123C86);
  --brand-grad-deep: linear-gradient(158deg, #0A2550 0%, #123C86 48%, #1D5FD0 100%);

  /* 点缀色：用于强调、进行中、需注意 */
  --accent:         #FF6A2B;
  --accent-light:   #FFF1EA;
  --accent-ink:     #C24A12;

  /* 语义色：成功 / 警告 / 危险 / 信息 */
  --ok:             #12A150;
  --ok-light:       #E6F6EC;
  --ok-ink:         #0B7A3B;
  --ok-border:      #B6E2C6;

  --warn:           #E08A00;
  --warn-light:     #FEF4E0;
  --warn-ink:       #A96700;
  --warn-border:    #F0D9A8;

  --danger:         #D93A3A;
  --danger-dark:    #C22F2F;   /* 危险色 hover */
  --danger-light:   #FDECEC;
  --danger-ink:     #B32B2B;
  --danger-border:  #F1BCBC;
  --danger-lite:    #FFFBFB;   /* 危险行的极浅底 */

  --info:           #0E8FA8;
  --info-light:     #E5F6FA;
  --info-ink:       #0A6C7E;

  /* 页面与容器 */
  --bg:             #F4F6FB;
  --surface:        #FFFFFF;   /* 卡片、弹窗、输入框 */
  --surface-2:      #FAFBFE;   /* 次级容器（表头、代码块） */
  --surface-3:      #F2F2F7;   /* 三级容器（灰色药丸、只读区） */
  --surface-hover:  #F7F9FD;
  --border:         #E4E9F2;
  --border-strong:  #D2DAE8;

  --text:           #16233A;
  --text-2:         #47536B;
  --text-3:         #7A879E;

  /* 侧边栏（后台左侧导航）：默认是深色块。
     单独一组变量而不是复用 --brand，因为有的皮肤品牌色很浅（素纸白），
     浅色侧边栏配浅色文字会完全看不见。 */
  --side-bg:        #0E2A5C;
  --side-bg-2:      #0A1F45;
  --side-text:      #DCE6F7;
  --side-text-dim:  #8FAEDC;
  --side-text-3:    #7B9BD0;
  --side-hover:     rgba(255, 255, 255, .07);
  --side-active-bg: rgba(255, 255, 255, .14);

  /* 前台深色头部（与侧边栏同源，但透明度不同） */
  --head-bg:        #123C86;
  --head-text:      #FFFFFF;
  --head-text-dim:  #C3D5EE;

  --radius:         14px;
  --radius-sm:      10px;
  --radius-xs:      8px;
  --radius-pill:    999px;

  --shadow-sm:  0 1px 2px rgba(22, 35, 58, .06);
  --shadow:     0 4px 16px rgba(22, 35, 58, .07);
  --shadow-lg:  0 12px 40px rgba(22, 35, 58, .12);

  --sidebar-w:  248px;
  --topbar-h:   62px;

  --font: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
          "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* 浏览器自绘控件的配色（滚动条、日期选择器、表单默认样式）。
     不声明这个，深色皮肤下日历弹层仍是白底黑字，很跳。 */
  color-scheme: light;
}


/* --------------------------------------------------------------------------
   2. 重置
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* [hidden] 必须真的隐藏 —— 这条不加会踩一个很隐蔽的坑。
   浏览器自带的 [hidden]{display:none} 属于 UA 样式表，优先级**低于**任何
   作者样式；只要组件写了 `.xxx { display: flex }`，`<div class="xxx" hidden>`
   就依然会显示出来。实测踩过：状态打卡卡片里「休假截止」那一行本来靠
   hidden 默认收起（只有点了「休假」才由 JS 展开），结果因为 `.sq-vac`
   写了 display:flex，**每次打开工作台都白占一行**，还带一个空的日期框 ——
   正是"一行就能填完的信息被撑得要滚动"的那类毛病。
   站点里所有显隐切换都是用 `el.hidden = true/false` 这个属性做的
   （没有一处用 style.display），所以 !important 不会和 JS 打架：
   属性一去掉，规则自然失效。 */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: 700; line-height: 1.35; color: var(--text); }
h1 { font-size: 24px; }
h2 { font-size: 19px; }
h3 { font-size: 16px; }
p  { margin: 0 0 10px; }

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-dark); }

img { max-width: 100%; display: block; }
ul, ol { margin: 0; padding-left: 20px; }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }

table { border-collapse: collapse; width: 100%; }

::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-thumb { background: #C6D0E0; border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: #A9B6CC; }
::-webkit-scrollbar-track { background: transparent; }

/* --------------------------------------------------------------------------
   3. 应用外壳
   -------------------------------------------------------------------------- */
.app { display: flex; min-height: 100vh; }

/* --- 侧边栏（桌面端） --- */
.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: linear-gradient(178deg, var(--brand-darker) 0%, #123566 55%, #143A72 100%);
  color: #D3E0F5;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: 60;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 18px 18px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, .09);
}

.sidebar-logo {
  width: 38px; height: 38px;
  flex: 0 0 38px;
  border-radius: 11px;
  background: var(--brand-grad);
  display: grid; place-items: center;
  box-shadow: 0 4px 12px rgba(29, 95, 208, .45);
}

.sidebar-logo svg { width: 22px; height: 22px; }

.sidebar-brand-txt { min-width: 0; }
.sidebar-brand-txt strong {
  display: block;
  color: #fff;
  font-size: 15px;
  letter-spacing: .3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-brand-txt span {
  display: block;
  font-size: 11px;
  color: var(--side-text-dim);
  letter-spacing: 1.4px;
  text-transform: uppercase;
}

.sidebar-nav { flex: 1; overflow-y: auto; padding: 12px 10px 20px; }
.sidebar-nav::-webkit-scrollbar { width: 5px; }
.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.14); }

.nav-group { margin-bottom: 6px; }
.nav-group-title {
  font-size: 11px;
  letter-spacing: 1.2px;
  color: var(--side-text-3);
  padding: 12px 12px 6px;
  font-weight: 600;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9.5px 12px;
  border-radius: var(--radius-sm);
  color: var(--head-text-dim);
  font-size: 13.5px;
  margin-bottom: 2px;
  transition: background .16s, color .16s;
  position: relative;
}
.nav-item:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.nav-item.active {
  background: linear-gradient(90deg, rgba(63, 139, 255, .32), rgba(63, 139, 255, .12));
  color: #fff;
  font-weight: 600;
}
.nav-item.active::before {
  content: "";
  position: absolute; left: 0; top: 50%;
  transform: translateY(-50%);
  width: 3px; height: 18px;
  border-radius: 0 3px 3px 0;
  background: #5B9CFF;
}
.nav-item svg { width: 17px; height: 17px; flex: 0 0 17px; opacity: .9; }
.nav-item .nav-badge {
  margin-left: auto;
  background: var(--accent);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  line-height: 1.6;
}

/* 一级菜单（点击展开二级） */
.nav-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm);
  color: #D8E4F5;
  font-size: 13.5px;
  font-weight: 600;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: background .16s, color .16s;
  margin-bottom: 2px;
  text-decoration: none;
}
.nav-head:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.nav-head.active { background: rgba(63, 139, 255, .28); color: #fff; }
.nav-head .nav-head-ico { display: inline-flex; flex: 0 0 17px; opacity: .92; }
.nav-head .nav-head-txt { flex: 1; }
.nav-head .nav-caret { display: inline-flex; opacity: .55; transition: transform .2s; }
.nav-group.is-open > .nav-head .nav-caret { transform: rotate(180deg); }
.nav-head .nav-badge {
  background: var(--accent);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  line-height: 1.6;
}

/* 二级菜单：默认收起，一级展开时才显示 */
.nav-sub {
  display: none;
  margin: 0 0 6px 20px;
  padding-left: 8px;
  border-left: 1px solid rgba(255, 255, 255, .14);
}
.nav-group.is-open > .nav-sub { display: block; }
.nav-sub .nav-item {
  padding: 8px 10px;
  font-size: 13px;
  margin-bottom: 1px;
}
.nav-sub .nav-item.active::before { display: none; }
.nav-sub .nav-item.active {
  background: linear-gradient(90deg, rgba(63, 139, 255, .36), rgba(63, 139, 255, .10));
}

.sidebar-foot {
  padding: 12px 16px;
  border-top: 1px solid rgba(255, 255, 255, .09);
  font-size: 11.5px;
  color: var(--side-text-3);
}

/* --- 主区域 --- */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  height: var(--topbar-h);
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 20px;
  position: sticky;
  top: 0;
  z-index: 40;
}

/* overflow: hidden —— 标题被挤到 0 宽时**必须裁掉**，不能让它溢出去。
   实测（1440 视口，admin/member_import.php，需求 #13 加了两个模板按钮之后）：
     .topbar-title  clientW=0  scrollW=24   ← 盒子被挤成 0 宽，内容却还占 24px
     .crumb         overflow-x: visible     ← 里面的面包屑没有任何裁切
   min-width:0 只保证"盒子可以被压小"，压小之后内容仍然会溢出（overflow 默认 visible），
   于是这 24px 直接算进 .topbar 的 scrollWidth，一路把 .main / .app 撑宽 ——
   整页横向滚动条就是这么来的。h1 自己有省略号，crumb 没有，所以漏点在 crumb 上；
   给容器加 overflow:hidden 比给每个子元素加更稳（将来再加子元素也不会漏）。 */
/* flex-shrink: 999 —— 空间不够时**先压标题**，再去压右边的动作条。
   这是原有设计已经定下的取舍，别顺手改掉：改前实测 1280 视口，
   标题本来就是 0 宽、页面横向溢出 2px。v2.5.0 补修只是把"溢出 2px"
   换成"页面级按钮条自己横滑"，优先级不动。
   为什么必须显式写：收缩量按 flex-shrink × 基准尺寸 分摊，两边都是默认的 1 时，
   标题和按钮条会各让一半 —— 实测 1280 下按钮条只剩 148px、三个按钮看不到两个。
   给标题 999 之后它一路缩到 0（min-width:0 + 省略号），缺额才轮到按钮条，
   实测 1280 下按钮条保住 278/299，只切掉最右 20px。 */
.topbar-title { min-width: 0; overflow: hidden; flex-shrink: 999; }
.topbar-title h1 {
  font-size: 17px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* 面包屑同样要走省略号，不能靠容器 overflow:hidden 硬切。
   容器裁切只保证"不溢出"，切在半个汉字上时渲染出来是残缺笔画，看着像页面坏了。
   nowrap + ellipsis 之后显示成「先预览，确认无误后…」，一眼就懂是"位置不够"。
   实测 1440 视口、admin/member_import.php：标题区只剩 146px，
   这一行原来正好被切在字中间。 */
.topbar-title .crumb {
  font-size: 12px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* flex: 0 1 auto + 全局控件逐个 0 0 auto —— 动作区只在"只剩页面级按钮条可压"时收缩。
   两段历史都记在这里，免得后人改回去：
     · v2.4 之前写的是 flex: 0 0 auto（完全不收缩）。当时的理由是：默认 flex-shrink:1
       时它会被左边那截标题压扁，而里面的图标、头像、下拉箭头都不能再变窄，
       压缩的结果不是"变紧凑"而是**内容溢出**。实测（390 宽、需求 #12 加了头像区
       下拉箭头之后）：.topbar-actions 盒子 190px、内容 215px；.user-menu 盒子 46px、
       内容 71px；span.uc-caret right=403 > 390 —— 整页横向滚动条就是它撑出来的，
       连带 position:fixed 的底部导航与抽屉遮罩按溢出后的宽度重排，看着像"整页错位"。
     · 但"永不收缩"在宽屏上会撑宽整页（v2.5.0 实测 admin/member_import.php）：
       侧栏 ≥1025 固定 248px，全局控件最小 701px，页面级按钮条 299px
       → 整条顶栏的最小宽度就是 1280px。于是视口 1101 溢出 179px、
       1150 溢出 130px、1200 溢出 80px、1280 恰好卡死（通知角标多一位数字就 2px）。
   两难的解法在 .ta-page：只有它挂 .is-scrollable 时可收缩（min-width:0 +
   overflow-x:auto，自己横滑），于是被压的永远是这段页面级按钮条，
   右侧全局控件的位置与尺寸一个都不动。 */
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: 0 1 auto; min-width: var(--ta-floor, auto); }
/* min-width 取 --ta-floor（由 app.js 的 syncTopbarBars() 实测后写到 .topbar 上，
   ≤640 那格用的是同一个变量名、同一个语义），取不到时回落 auto。
   这一格值不值得这么绕，是踩了两次才定的：
     ① flex: 0 0 auto（完全不收缩）—— 宽屏会撑宽整页：侧栏 ≥1025 固定 248px，
        全局控件最小 701px，页面级按钮条 299px，顶栏最小宽度就是 1280px。
        实测视口 1101 溢出 179px、1200 溢出 80px、1280 恰好卡死。
     ② min-width: 0（让盒子随便缩）—— 窄一点的宽屏上盒子被压得比全局控件还窄。
        子项是 flex:0 0 auto 不再缩，就从盒子右边溢出去：实测视口 900，
        .topbar-actions 盒子 511.52px、子项合计 565.52px，最后那个 .user-menu
        被挤出视口 54px，整页照样出现横向滚动条。
     ③ 现在这版：下限 = "全局控件之和 + 间距"，由 JS 量出来。于是被压的永远是
        页面级按钮条（挂 .is-scrollable 时自己横滑），全局控件的位置与尺寸
        一个都不动，也不必为每个断点手算一个魔法数。
   另外要记住：.ta-page 的**最小内容**（三个按钮各自最长不可断词之和，实测 210px）
   会算进盒子默认 min-width:auto 的"自动最小尺寸"里 —— 这正是 ② 之前动作区卡在
   911.41px 再也下不去的原因，所以下限必须显式写，不能指望默认值。 */
/* 全局控件永不压缩。默认的 min-width:auto 其实也拦得住，但那是"内容不肯变小"，
   不是"盒子不许变小"—— 哪天某个控件自己加了 min-width:0 就会漏，显式写死更稳。 */
.topbar-actions > .sound-wrap,
.topbar-actions > .skin-wrap,
.topbar-actions > .topbar-new-mission,
.topbar-actions > .top-quick,
.topbar-actions > .user-menu { flex: 0 0 auto; }

.hamburger {
  display: none;
  width: 38px; height: 38px;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--radius-sm);
  align-items: center;
  justify-content: center;
  flex: 0 0 38px;
}
.hamburger span {
  display: block; width: 16px; height: 2px;
  background: var(--text-2); border-radius: 2px; position: relative;
}
.hamburger span::before, .hamburger span::after {
  content: ""; position: absolute; left: 0;
  width: 16px; height: 2px; background: var(--text-2); border-radius: 2px;
}
.hamburger span::before { top: -5px; }
.hamburger span::after  { top: 5px; }

.content { padding: 20px; flex: 1; }
.content-narrow { max-width: 900px; }

/* --- 用户头像菜单 --- */
.user-chip {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 10px 5px 5px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  transition: box-shadow .16s, border-color .16s;
}
.user-chip:hover { box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.user-chip img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; }
.user-chip .uc-name { font-size: 13px; font-weight: 600; line-height: 1.2; }
.user-chip .uc-role { font-size: 11px; color: var(--text-3); line-height: 1.2; }
.user-chip .uc-caret { display: inline-flex; color: var(--text-3); transition: transform .16s; }

/* --- 头像下拉菜单（需求 #12）：鼠标悬停展开，触屏点按展开 --- */
/* flex: 0 0 auto 同上：头像 + 姓名 + 角标 + 下拉箭头是一组不可再压缩的控件，
   被压扁只会把箭头挤到视口外（实测 390 宽下溢出 14px）。 */
.user-menu { position: relative; flex: 0 0 auto; }
.user-menu .uc-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--danger); flex: 0 0 7px; margin-left: -3px;
}
.um-panel {
  position: absolute; top: calc(100% + 10px); right: 0;
  width: 268px; max-width: calc(100vw - 24px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 6px;
  z-index: 60;
  /* 默认藏起来：用 opacity + visibility 而不是 display，
     这样展开/收起能有一段短过渡；直接 display 切换会「啪」地闪一下。 */
  opacity: 0; visibility: hidden;
  transform: translateY(-6px);
  transition: opacity .16s, transform .16s, visibility .16s;
}
/* 面板顶到视口右边时不留 8px 空地，看着像贴边断了 */
.um-panel::before {
  content: ''; position: absolute; top: -6px; right: 22px;
  width: 10px; height: 10px;
  background: var(--surface);
  border-left: 1px solid var(--border); border-top: 1px solid var(--border);
  transform: rotate(45deg);
}
.user-menu.is-open .um-panel,
.user-menu:hover .um-panel { opacity: 1; visibility: visible; transform: translateY(0); }
.user-menu.is-open .uc-caret,
.user-menu:hover .uc-caret { transform: rotate(180deg); }

.um-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 10px 11px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 5px;
}
.um-head img { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex: 0 0 38px; }
.um-head div { min-width: 0; }
.um-head b { display: block; font-size: 14px; color: var(--text); line-height: 1.3; }
.um-head small { display: block; font-size: 11.5px; color: var(--text-3); margin-top: 2px; }

.um-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--radius-sm);
  color: var(--text-2); text-decoration: none;
  transition: background .14s, color .14s;
}
.um-item:hover { background: var(--surface-hover); color: var(--text); }
.um-item.is-danger:hover { background: var(--danger-light); color: var(--danger-ink); }
.um-ico { display: inline-flex; flex: 0 0 16px; color: var(--text-3); }
.um-item:hover .um-ico { color: var(--brand); }
.um-item.is-danger:hover .um-ico { color: var(--danger); }
.um-txt { min-width: 0; flex: 1; }
.um-txt b { display: block; font-size: 13px; font-weight: 600; line-height: 1.35; }
.um-txt small { display: block; font-size: 11px; color: var(--text-3); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.um-badge {
  flex: 0 0 auto; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--danger); color: var(--fixed-white);
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}
.um-sep { height: 1px; background: var(--border); margin: 5px 6px; }

/* --- 底部导航（仅移动端） --- */
.bottom-nav {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: 58px;
  padding-bottom: env(safe-area-inset-bottom, 0);
  background: rgba(255, 255, 255, .96);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  z-index: 55;
}
.bottom-nav a {
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 3px;
  color: var(--text-3);
  font-size: 10.5px;
}
.bottom-nav a svg { width: 19px; height: 19px; }
.bottom-nav a.active { color: var(--brand); font-weight: 600; }

/* --- 移动端抽屉 --- */
.drawer-mask {
  display: none;
  position: fixed; inset: 0;
  background: rgba(12, 28, 56, .48);
  z-index: 58;
  opacity: 0;
  transition: opacity .22s;
}
.drawer-mask.show { opacity: 1; }

/* --------------------------------------------------------------------------
   4. 卡片
   -------------------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: 12px;
  overflow: hidden;
}

.card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-wrap: wrap;
}
.card-head h2, .card-head h3 { font-size: 15px; }
.card-head .card-sub { font-size: 12px; color: var(--text-3); }
.card-head .head-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* 卡片内边距与卡片间距一起收紧（需求 #6）。
   为什么连 .card 的 margin-bottom 也动：后台页面普遍是「一张卡一件事」，
   卡片之间的 16px 空隙在十张卡的页面上就是 160px 的纯空白。 */
.card-body { padding: 14px; }
.card-body.tight { padding: 0; }

.card-foot {
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   5. 统计卡
   -------------------------------------------------------------------------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  margin-bottom: 16px;
}

/* 五张卡同排（党团妇工概览加了「退伍军人」之后，需求 5）。
   默认的 minmax(190px,1fr) 在约 1000px 的内容区里放不下 5 列
   （5×190 + 4×14 = 1006 > 1000），第 5 张会单独掉到第二行占一整行宽，
   看起来像"多出来的一张"。收紧到 168px 即可 5 列同排 ——
   这些卡片是「小标题 + 一个大数字 + 一行脚注」，
   168px 放得下最长的「共青团员 50 人」，不必为了凑整数把某张卡拆走。 */
.stat-grid.cols-5 { grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); }

.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
}
.stat::after {
  content: "";
  position: absolute; right: -22px; top: -22px;
  width: 78px; height: 78px; border-radius: 50%;
  background: var(--brand-lighter);
}
.stat > * { position: relative; z-index: 1; }
.stat .stat-label { font-size: 12.5px; color: var(--text-3); display: flex; align-items: center; gap: 6px; }
.stat .stat-value {
  font-size: 27px; font-weight: 800; letter-spacing: -.5px;
  color: var(--text); line-height: 1.25; margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.stat .stat-value small { font-size: 13px; font-weight: 600; color: var(--text-3); margin-left: 3px; }
.stat .stat-foot { font-size: 12px; color: var(--text-3); margin-top: 4px; }
.stat.is-ok::after    { background: var(--ok-light); }
.stat.is-warn::after  { background: var(--warn-light); }
.stat.is-danger::after{ background: var(--danger-light); }
.stat.is-brand::after { background: var(--brand-light); }
.stat.is-muted::after { background: var(--border); }
/* info（青蓝）是需求 5 给「退伍军人」定的色，与 badge-info /
   tone-info 同源。加这一行是为了让第 5 张概览卡右上角那圈淡色底
   也走同一色系 —— 少了它，卡片其它地方是青蓝、水印却是默认的蓝。 */
.stat.is-info::after  { background: var(--info-light); }

/* 统计卡也当筛选入口用（任务管理页：点「已归档」直接跳到该状态的列表）。
   锚点版 .stat 必须显式抹掉下划线与链接色，否则整张卡会变蓝字带下划线。 */
a.stat {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
a.stat:hover {
  border-color: var(--brand);
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}
a.stat:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  a.stat, a.stat:hover { transition: none; transform: none; }
}

.stat-icon {
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center; margin-bottom: 10px;
  background: var(--brand-light); color: var(--brand);
}
.stat-icon svg { width: 18px; height: 18px; }
.stat.is-ok .stat-icon    { background: var(--ok-light); color: var(--ok); }
.stat.is-warn .stat-icon  { background: var(--warn-light); color: var(--warn); }
.stat.is-danger .stat-icon{ background: var(--danger-light); color: var(--danger); }
.stat.is-info .stat-icon  { background: var(--info-light);   color: var(--info); }

/* --------------------------------------------------------------------------
   6. 按钮
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: var(--brand);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.2;
  transition: filter .16s, background .16s, box-shadow .16s, border-color .16s;
  white-space: nowrap;
  text-decoration: none;
}
.btn:hover { filter: brightness(1.07); color: #fff; }
.btn:active { transform: translateY(1px); }
.btn svg { width: 15px; height: 15px; }

.btn-ghost { background: var(--surface); color: var(--text-2); border-color: var(--border-strong); }
.btn-ghost:hover { background: var(--brand-lighter); border-color: var(--brand); color: var(--brand); filter: none; }

.btn-soft { background: var(--brand-light); color: var(--brand-dark); }
.btn-soft:hover { background: #DCE8FD; color: var(--brand-dark); filter: none; }

.btn-accent { background: var(--accent); }
.btn-danger { background: var(--danger); }
.btn-ok { background: var(--ok); }
.btn-warn { background: var(--warn); }

.btn-outline-danger { background: transparent; color: var(--danger); border-color: var(--danger-border); }
.btn-outline-danger:hover { background: var(--danger-light); color: var(--danger); filter: none; }
.btn-outline-ok { background: transparent; color: var(--ok); border-color: var(--ok-border); }
.btn-outline-ok:hover { background: var(--ok-light); color: var(--ok); filter: none; }

.btn-sm { padding: 6px 11px; font-size: 12.5px; border-radius: var(--radius-xs); }
.btn-sm svg { width: 13px; height: 13px; }
.btn-xs { padding: 3px 9px; font-size: 11.5px; border-radius: var(--radius-xs); font-weight: 500; }
.btn-xs svg { width: 12px; height: 12px; }
.btn-lg { padding: 12px 24px; font-size: 15px; }
.btn-block { width: 100%; }
.btn[disabled], .btn.disabled { opacity: .5; pointer-events: none; }

.btn-group { display: inline-flex; gap: 6px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   7. 徽章 / 标签
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.7;
  white-space: nowrap;
  background: var(--surface-3);
  color: var(--text-2);
}
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 6px; }
/* 行内小徽章（需求 #8：技能格子里标记「审 / 驳」）。
   技能格子本身只有 ~118px 宽、里面还有一个复选框和技能名，
   用 12px 的 .badge 会把名字挤成两行、整片格子参差不齐，所以单独给一档 10px。 */
.badge-xs {
  padding: 0 5px;
  font-size: 10px;
  line-height: 16px;
  border-radius: 4px;
  font-weight: 700;
  flex: 0 0 auto;
}
.badge-ok      { background: var(--ok-light);     color: var(--ok-ink); }
.badge-warn    { background: var(--warn-light);   color: var(--warn-ink); }
.badge-danger  { background: var(--danger-light); color: var(--danger-ink); }
.badge-brand   { background: var(--brand-light);  color: var(--brand-dark); }
.badge-info    { background: var(--info-light);   color: var(--info-ink); }
.badge-muted   { background: var(--surface-3);             color: var(--text-3); }
.badge-accent  { background: var(--accent-light); color: var(--accent-ink); }

/* 描边徽标：用于「模板预设了什么」这类信息标签。
   实心徽标成排出现会盖过标题，描边的更轻，适合当注释用。 */
.badge-line {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  font-weight: 500;
}

.badge-on      { background: var(--ok-light);     color: var(--ok-ink); }
.badge-standby { background: var(--brand-light);  color: var(--brand-dark); }
.badge-busy    { background: var(--accent-light); color: var(--accent-ink); }
.badge-off     { background: var(--surface-3);             color: var(--text-3); }

.badge .sub { font-weight: 500; opacity: .8; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: var(--radius-xs);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-2);
}
.chip-brand { background: var(--brand-lighter); border-color: var(--brand-border); color: var(--brand-dark); }

.tag-list { display: flex; flex-wrap: wrap; gap: 6px; }

/* --------------------------------------------------------------------------
   8. 表单

   ★ 紧凑化（需求 #6，全站默认值）
   用户原话：「后台几乎所有页面的编辑框、上传图片、都占用太大空间了，
   都要缩小下，尽量让用户少滑动鼠标」。
   所以这里统一把"一个字段占的高度"降下来，而不是逐个页面改 ——
   逐个改的代价是几十个页面各写一套，迟早又不一致：
     · 输入框 42px → 36px（padding 9.5/12 → 7/10）
     · 文本域 88px → 68px
     · 栅格列宽 230px → 200px、行距 14/16 → 10/12（同样宽度能多放一列）
     · 字段内 label 与控件的间隙 6px → 4px
   一条纪律：**窄屏要还回去**。36px 在手机上低于可点尺寸，
   所以下面的 700px 媒体查询把输入框恢复到 40px，
   桌面省下的空间不能再拿手机的可点性去换。
   -------------------------------------------------------------------------- */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px 12px;
}
.form-grid .span-2 { grid-column: span 2; }
.form-grid .span-3 { grid-column: span 3; }

.field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.field > label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
}
.field > label .req { color: var(--danger); margin-left: 2px; }
.field .hint { font-size: 11.5px; color: var(--text-3); }
/* 警示型提示（如任务指挥下拉里「暂停职务中，不可任命：×××」）。
   必须写成 .field .hint.hint-danger 才能压过上面那条 —— 只写 .hint-danger
   （单个类选择器）优先级更低，颜色会被 .field .hint 吃掉，静默失效。 */
.field .hint.hint-danger { color: var(--danger); font-weight: 600; }

.input, .select, .textarea {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 13.5px;
  transition: border-color .16s, box-shadow .16s;
  min-height: 36px;
}
.textarea { min-height: 68px; resize: vertical; line-height: 1.6; }
.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%237A879E' stroke-width='1.8' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 34px;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(29, 95, 208, .12);
}
.input[readonly], .input[disabled], .select[disabled] {
  background: #F5F7FA;
  color: var(--text-3);
}

.form-section-title {
  /* ★ 需求 6（本轮，手机版设置页错位的根因）：这一行必须**自成一个 BFC**。
     标题右侧的 .fst-note 是 float:right。标题自己是普通块级盒子时不收浮动，
     浮动就溢到标题外面；而它的下一个兄弟通常是 .form-grid（display:grid，
     按规范**会新建 BFC**），BFC 盒子的 border box 必须避开同一格式化上下文里的
     浮动 —— 于是它的宽度被按浮动宽度扣掉。
     说明文字长到换行时会占满整行宽度（例：系统设置「审批与财务」页的
     「通用审批」，标题 336px、浮动也 336px），扣完就是 **0**：
     表单在手机上塌成一条竖线、文字逐字换行，整块高到几千像素。
     实测：把标题改成 flow-root（收纳自己的浮动）后宽度立刻回到 336px。
     display:flow-root 不改变盒子的外观与尺寸（只加"包住浮动"这一条），
     所以桌面端一行排得下的说明文字，版式与改动前逐像素一致。 */
  display: flow-root;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--brand-dark);
  padding: 2px 0 0;
  border-bottom: 1px dashed var(--border-strong);
  margin: 4px 0 0;
  grid-column: 1 / -1;
}

/* 窄屏把可点高度还回去。
   桌面 36px 的输入框在手机上偏矮，手指点不准会误触到相邻字段 ——
   而手机上"滑动"本来就不像鼠标那么费劲，用户抱怨的是 PC 端一屏放不下几个字段。
   所以这一条是「桌面省空间、手机保可点性」，不是两边一起缩。 */
@media (max-width: 700px) {
  .input, .select, .textarea { min-height: 40px; padding: 8px 11px; font-size: 14px; }
  .textarea { min-height: 82px; }
  .form-grid { gap: 12px; }
  .check-grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 8px; }
  .check-item { padding: 9px 11px; font-size: 13px; }
}

/* 多选技能（需求 #6：一屏多放几项，减少滚动） */
.check-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 6px;
}
.check-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--surface-2);
  font-size: 12.5px;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.check-item:hover { border-color: var(--brand); }
.check-item input { width: 15px; height: 15px; accent-color: var(--brand); flex: 0 0 15px; }
.check-item.checked { background: var(--brand-light); border-color: var(--brand); color: var(--brand-dark); font-weight: 600; }
/* 名额已满时被灰掉的选项（需求 #78-7：求救推送队员上限 10 人）。
   用虚线边框 + 去饱和告诉人「不是坏了，是选满了」，不要用 display:none ——
   选项凭空消失会让人以为名单里没有这个人。 */
.check-item.is-dim {
  opacity: .45;
  cursor: not-allowed;
  border-style: dashed;
  background: var(--surface-2);
  color: var(--text-3);
}
.check-item.is-dim:hover { border-color: var(--border); }

/* --------------------------------------------------------------------------
   分段单选（需求 #12 个人装备的三态：未填写 / 有 / 没有）
   --------------------------------------------------------------------------
   为什么不用 .radio-cards：那是卡片式单选，一屏放得下 3~4 张卡，适合
   「选择出勤状态」这种一次只选一组的场景；个人装备页一屏有十几条、
   每条三个选项，卡片会占满整屏。这里做成一条紧凑的胶囊分段。

   选中态用 :has() 而不是靠 JS 加 class：
   原生 radio 一进 DOM 就是可用状态，不必等 app.js 执行完才有高亮 ——
   首屏闪一下无色、或者 JS 报错就永远不高亮，都是很难看出来的坏法。
   键盘可达性由原生 radio 保证（视觉上用 opacity 藏起来但仍在 DOM 里）。 */
.seg-group {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  overflow: hidden;
  align-self: flex-start;
}
.seg-group > label {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 60px;
  padding: 6px 12px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-3);
  cursor: pointer;
  user-select: none;
  transition: background .15s, color .15s;
}
.seg-group > label + label { border-left: 1px solid var(--border); }
.seg-group > label:hover { background: var(--surface-hover); color: var(--text-2); }
.seg-group input {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
  margin: 0;
}
.seg-group > label:has(input:checked) {
  background: var(--brand-light);
  color: var(--brand-dark);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--brand-border);
}
.seg-group > label:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: -2px; }
@media (max-width: 640px) {
  .seg-group { width: 100%; }
  /* 三态分段是「有 / 没有」这种一步就能点错的选择，窄屏上必须够大够好按。
     实测原来的 8px 上下留白只有约 35px 高，手指很容易点偏到隔壁 ——
     这里把纵向留白加到 10px、字号提到 13px，实际高度约 40px。 */
  .seg-group > label { flex: 1 1 0; min-width: 0; padding: 10px 6px; font-size: 13px; }
}

/* 权限勾选面板（角色与权限页） */
.cap-groups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(255px, 1fr));
  gap: 12px;
  margin-top: 12px;
  transition: opacity .2s;
}
.cap-group {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface);
}
.cap-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 11px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.cap-group-head strong { font-size: 13px; }
.cap-group-head .btn { margin-left: auto; }
.cap-group-body { display: flex; flex-direction: column; gap: 5px; padding: 9px; }
.cap-item { font-size: 12.5px; padding: 6px 9px; align-items: flex-start; }
.cap-item > span { display: flex; flex-direction: column; gap: 1px; line-height: 1.35; }
.cap-item .cap-key {
  font-style: normal;
  font-size: 10.5px;
  color: var(--text-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 400;
}
.cap-item.checked .cap-key { color: var(--brand); opacity: .8; }
@media (max-width: 560px) {
  .cap-groups { grid-template-columns: 1fr; }
}

/* 卡片式单选（状态打卡等） */
.radio-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
}
.radio-card {
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px 12px;
  text-align: center;
  cursor: pointer;
  background: var(--surface);
  transition: border-color .15s, background .15s, transform .15s;
}
.radio-card:hover { border-color: var(--brand); transform: translateY(-1px); }
.radio-card input { display: none; }
.radio-card .rc-title { font-weight: 700; font-size: 14px; }
.radio-card .rc-desc { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.radio-card.checked { border-color: var(--brand); background: var(--brand-lighter); box-shadow: 0 0 0 3px rgba(29, 95, 208, .1); }

.form-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  padding-top: 16px;
  margin-top: 16px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.form-actions .right { margin-left: auto; display: flex; gap: 10px; }

/* --------------------------------------------------------------------------
   9. 表格
   -------------------------------------------------------------------------- */
.table-wrap { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }

.table { width: 100%; min-width: 640px; font-size: 13.5px; }
.table thead th {
  background: var(--surface-2);
  color: var(--text-2);
  font-weight: 700;
  font-size: 12.5px;
  text-align: left;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}
.table tbody td {
  padding: 11px 14px;
  border-bottom: 1px solid #EFF2F7;
  vertical-align: middle;
  color: var(--text-2);
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover { background: var(--brand-lighter); }
.table .nowrap { white-space: nowrap; }
.table .col-actions { white-space: nowrap; text-align: right; }
.table .strong { color: var(--text); font-weight: 600; }
.table .num { font-variant-numeric: tabular-nums; }
.table-mini { min-width: 0; font-size: 13px; }

.person-cell { display: flex; align-items: center; gap: 9px; }
.person-cell img { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; flex: 0 0 32px; }
.person-cell .pc-name { font-weight: 600; color: var(--text); line-height: 1.25; }
.person-cell .pc-sub { font-size: 11.5px; color: var(--text-3); line-height: 1.25; }

/* --------------------------------------------------------------------------
   10. 筛选栏
   -------------------------------------------------------------------------- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 10px;
  align-items: flex-end;
}
.filter-bar .field { flex: 1 1 160px; min-width: 140px; }
.filter-bar .field.wide { flex: 1 1 240px; }
.filter-bar .fb-actions { display: flex; gap: 8px; flex: 0 0 auto; }
/* 多选项占满整行时更易点选 */
.filter-bar .field.full { flex: 1 1 100%; }
/* 芯片式多选需要更宽的横向空间，宽屏下允许两列并排 */
.filter-bar .field.chips { flex: 1 1 320px; }

/* 芯片字段比下拉框高，底部对齐会让各字段标签错行；
   报表页筛选区改为顶部对齐，并把操作按钮单独放一行右对齐 */
.filter-bar-tall { align-items: flex-start; }
.filter-bar-tall .fb-actions {
  flex: 1 1 100%;
  justify-content: flex-end;
  margin-top: 4px;
}

/* --------------------------------------------------------------------------
   10.1 芯片式多选（替代 <select multiple>）
   原生多选下拉在移动端与桌面 Chrome 下会渲染成高度重叠的列表框，
   这里改为「隐藏 checkbox + 胶囊标签」，点选直观、触控友好，且保留 name="xx[]" 的提交格式。
   -------------------------------------------------------------------------- */
.msel {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  max-height: 168px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.msel .msel-label {
  flex: 0 0 100%;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: .02em;
  margin-top: 2px;
}
.msel .msel-label:first-child { margin-top: 0; }
.msel-item { position: relative; display: inline-flex; }
.msel-item input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.msel-item > span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  cursor: pointer;
  user-select: none;
  /* 移动端点击目标不小于 32px，符合触控规范 */
  min-height: 32px;
  transition: border-color .15s, background .15s, color .15s;
}
.msel-item > span:hover { border-color: var(--brand); color: var(--brand); }
/* 芯片右上角的分布计数（"红十字救护员证 9"）。
   纯展示，不参与筛选 —— 所以做成弱化的小字，别让人误以为是筛选条件。 */
.msel-item > span .msel-cnt {
  font-style: normal;
  font-weight: 500;
  font-size: 11px;
  opacity: .6;
  min-width: 10px;
  text-align: right;
}
.msel-item input:checked + span .msel-cnt { opacity: .8; }
.msel-item input:focus-visible + span { box-shadow: 0 0 0 3px rgba(29, 95, 208, .16); }
.msel-item input:checked + span {
  border-color: var(--brand);
  background: var(--brand-light);
  color: var(--brand-dark);
}
.msel-item input:checked + span::before {
  content: "✓";
  font-size: 11px;
  font-weight: 700;
}
.msel-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--text-3);
}
.link-mini {
  background: none;
  border: none;
  padding: 0;
  color: var(--brand);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
}
.link-mini:hover { text-decoration: underline; }

/* --------------------------------------------------------------------------
   11. 提示条
   -------------------------------------------------------------------------- */
.alert {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 15px;
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  margin-bottom: 14px;
  border: 1px solid transparent;
  line-height: 1.6;
}
.alert svg { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 2px; }
/* 需求 #11：工作台上的新人必修提醒。整条就是一个链接，所以要压掉下划线、
   让文字继承提示条的颜色（否则会变成默认的蓝色链接色，跟警示底色打架），
   末位再放一个右箭头示意"可点"。 */
a.alert.train-tip {
  text-decoration: none;
  align-items: center;
  padding: 9px 13px;
  margin-bottom: 12px;
  color: inherit;
  transition: filter .15s;
}
a.alert.train-tip:hover { filter: brightness(.97); }
a.alert.train-tip > svg:last-child { flex: 0 0 15px; margin: 0 0 0 auto; opacity: .65; }
a.alert.train-tip div { margin: 0; }
.alert-ok     { background: var(--ok-light);     border-color: var(--ok-border); color: #0B6B35; }
.alert-warn   { background: var(--warn-light);   border-color: var(--warn-border); color: var(--warn-ink); }
.alert-danger { background: var(--danger-light); border-color: var(--danger-border); color: var(--danger-ink); }
.alert-info   { background: var(--brand-light);  border-color: #C9DCFB; color: var(--brand-dark); }
.alert .alert-close { margin-left: auto; background: none; border: none; font-size: 17px; color: inherit; opacity: .5; padding: 0 2px; }
.alert .alert-close:hover { opacity: 1; }

/* --------------------------------------------------------------------------
   12. 空状态
   -------------------------------------------------------------------------- */
.empty { text-align: center; padding: 46px 20px; color: var(--text-3); }
.empty svg { width: 46px; height: 46px; opacity: .35; margin: 0 auto 12px; }
.empty p { font-size: 13.5px; margin: 0; }

/* --------------------------------------------------------------------------
   13. 分页
   -------------------------------------------------------------------------- */
.pager {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 18px;
  border-top: 1px solid var(--border);
}
.pager-info { font-size: 12.5px; color: var(--text-3); }
.pager-btns { margin-left: auto; display: flex; gap: 5px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   14. 时间线
   -------------------------------------------------------------------------- */
.timeline { position: relative; padding-left: 22px; }
.timeline::before {
  content: "";
  position: absolute; left: 5px; top: 6px; bottom: 6px;
  width: 2px; background: var(--border);
}
.tl-item { position: relative; padding-bottom: 16px; }
.tl-item:last-child { padding-bottom: 0; }
.tl-item::before {
  content: "";
  position: absolute; left: -21px; top: 5px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface); border: 2.5px solid var(--brand);
}
.tl-item.is-ok::before   { border-color: var(--ok); }
.tl-item.is-warn::before { border-color: var(--warn); }
.tl-item.is-danger::before { border-color: var(--danger); }
.tl-title { font-size: 13.5px; font-weight: 600; color: var(--text); }
.tl-meta  { font-size: 11.5px; color: var(--text-3); }
.tl-desc  { font-size: 13px; color: var(--text-2); margin-top: 2px; }

/* --------------------------------------------------------------------------
   15. 进度条
   -------------------------------------------------------------------------- */
.bar { height: 7px; border-radius: 4px; background: var(--surface-3); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: 4px; background: var(--brand); transition: width .5s; }
.bar.is-ok > i    { background: var(--ok); }
.bar.is-warn > i  { background: var(--warn); }
.bar.is-danger > i{ background: var(--danger); }

.bar-row { display: flex; align-items: center; gap: 10px; }
.bar-row .bar { flex: 1; }
.bar-row .bar-val { font-size: 12.5px; color: var(--text-2); font-variant-numeric: tabular-nums; min-width: 54px; text-align: right; }

/* --------------------------------------------------------------------------
   15b. 专业组分布条形图（需求 #10：个人中心「任务覆盖哪些专业组」）
   --------------------------------------------------------------------------
   纯 CSS 横条，不引图表库。填充条内再叠一层「培训类」段：
   同一根条上，深色是任务、浅色是其中属于培训的部分，一眼看出比例。 */
.gbar-chart { display: flex; flex-direction: column; gap: 7px; }
.gbar-row {
  display: flex; align-items: center; gap: 9px;
  padding: 4px 6px; border-radius: var(--radius-xs);
  transition: background .14s, box-shadow .14s;
}
/* 需求 #9：把鼠标停在哪一行说清楚 —— 一眼看出"这一条"与总量、与最长条的关系。
   只做底色高亮，不做位移/缩放：横条一动，长度就没法比了。 */
.gbar-row:hover { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--brand); }
.gbar-rank {
  flex: 0 0 20px; width: 20px; text-align: right;
  font-size: 11px; font-weight: 700; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.gbar-row:hover .gbar-rank { color: var(--brand); }
.gbar-name {
  flex: 0 0 96px; width: 96px; font-size: 12.5px; color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gbar-track {
  flex: 1; height: 16px; border-radius: 5px; background: var(--surface-3);
  overflow: hidden; min-width: 40px;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, .05);
}
.gbar-fill {
  height: 100%; border-radius: 5px;
  background: var(--brand-grad, var(--brand));
  position: relative; transition: width .5s;
  display: flex; align-items: center; justify-content: flex-end;
}
/* 条内百分比：太短的条（<22%）不标 —— 塞进去只会溢出成半截字 */
.gbar-in {
  padding-right: 6px; font-size: 10px; font-weight: 700; color: #fff;
  letter-spacing: .3px; font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 1px rgba(0, 0, 0, .18);
}
/* 培训类那一段：叠在填充条上，用半透明白 + 斜纹，深色底下也能看清 */
.gbar-train {
  position: absolute; top: 0; right: 0; height: 100%;
  background: repeating-linear-gradient(135deg, rgba(255,255,255,.72) 0 4px, rgba(255,255,255,.34) 4px 8px);
}
.gbar-val {
  flex: 0 0 96px; width: 96px; font-size: 12.5px; color: var(--text-2);
  font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap;
}
.gbar-val small { display: block; font-size: 10.5px; color: var(--text-3); }
.gbar-legend {
  display: flex; flex-wrap: wrap; gap: 14px; margin-top: 9px;
  font-size: 11.5px; color: var(--text-3);
}
.gbar-legend span { display: inline-flex; align-items: center; gap: 5px; }
.gbar-legend .lg { width: 12px; height: 8px; border-radius: 2px; display: inline-block; }
.gbar-legend .lg-task  { background: var(--brand-grad, var(--brand)); }
.gbar-legend .lg-train { background: var(--brand); opacity: .42; }
.gbar-legend .gbar-tip { margin-left: auto; opacity: .75; }

@media (max-width: 700px) {
  /* 手机上把名字列压窄、数值列改到第二行，避免横条被挤成几像素长 */
  .gbar-row  { gap: 7px; padding: 3px 4px; }
  .gbar-rank { flex: 0 0 16px; width: 16px; font-size: 10px; }
  .gbar-name { flex: 0 0 66px; width: 66px; font-size: 12px; }
  .gbar-val  { flex: 0 0 82px; width: 82px; font-size: 12px; }
  .gbar-track { height: 14px; }
  .gbar-in   { display: none; }
  .gbar-legend .gbar-tip { display: none; }
}

/* --------------------------------------------------------------------------
   16. 标签页
   -------------------------------------------------------------------------- */
.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  padding: 0 18px;
  background: var(--surface);
}
.tabs a {
  padding: 12px 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-3);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  margin-bottom: -1px;
}
.tabs a:hover { color: var(--brand); }
.tabs a.active { color: var(--brand); border-bottom-color: var(--brand); }

/* --------------------------------------------------------------------------
   17. 详情列表
   -------------------------------------------------------------------------- */
.dl {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 0;
}
.dl-item {
  padding: 10px 0;
  border-bottom: 1px dashed var(--border);
  display: flex;
  gap: 10px;
  font-size: 13.5px;
  align-items: baseline;
}
.dl-item dt { color: var(--text-3); flex: 0 0 96px; font-size: 12.5px; }
.dl-item dd { margin: 0; color: var(--text); font-weight: 500; word-break: break-all; }

/* 履历统计（队员档案 · 贡献概览） */
.contrib-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px;
  margin-top: 14px;
}
.cm-item {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cm-label { font-size: 12px; color: var(--text-3); }
.cm-val {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
.cm-val small { font-size: 11.5px; font-weight: 500; color: var(--text-3); }

/* --------------------------------------------------------------------------
   17.2 装备详情头部
   -------------------------------------------------------------------------- */
.eq-head { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.eq-head-main { flex: 1 1 auto; min-width: 0; }
.eq-head-name {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
}
.eq-head-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 7px;
  font-size: 13px;
  color: var(--text-3);
}
.eq-head-warn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 15px;
  border-radius: var(--radius-pill);
  background: var(--warn-light);
  color: var(--warn-ink);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.eq-head-warn b { font-size: 15px; }
.eq-head-warn svg { width: 15px; height: 15px; }
.eq-head-warn.is-overdue { background: var(--danger-light); color: var(--danger-ink); }

/* 按操作类型动态显示 / 隐藏的表单字段（无脚本时全部显示，不影响提交） */
.op-field.is-off { display: none; }

/* --------------------------------------------------------------------------
   17.1 维护 / 到期预警列表（装备、证书等共用）
   -------------------------------------------------------------------------- */
.warn-list { display: flex; flex-direction: column; gap: 8px; }
.warn-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm);
  background: var(--surface);
  text-decoration: none;
  color: var(--text);
  transition: background .15s, border-color .15s;
}
.warn-item:hover { background: var(--bg); border-color: var(--warn); }
.warn-item.is-overdue {
  border-left-color: var(--danger);
  background: var(--danger-light);
}
.warn-item.is-overdue:hover { border-color: var(--danger); }
.wi-name { font-weight: 600; font-size: 13.5px; }
.wi-meta { font-size: 12px; color: var(--text-3); }
.wi-days {
  margin-left: auto;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--warn-ink);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.warn-item.is-overdue .wi-days { color: var(--danger-ink); }

@media (max-width: 640px) {
  .warn-item { flex-wrap: wrap; gap: 4px 10px; padding: 11px 12px; }
  .wi-name { flex: 1 1 auto; }
  .wi-meta { flex: 0 0 100%; order: 3; }
  .wi-days { margin-left: 0; flex: 0 0 auto; }
  .contrib-meta { grid-template-columns: repeat(2, 1fr); }

  /* 装备详情头部：窄屏改为上下两段，避免名称与倒计时挤在一行 */
  .eq-head { gap: 10px; }
  .eq-head-name { font-size: 17px; gap: 8px; }
  .eq-head-warn { width: 100%; justify-content: center; }
}

/* --------------------------------------------------------------------------
   18. 档案头部
   -------------------------------------------------------------------------- */
.profile-head {
  display: flex;
  gap: 20px;
  /* 需求 #11：原来是 align-items:center —— 右侧三个操作按钮跟着内容高度
     垂直居中，内容一多就"飘"在中间，视觉上把整块挤成一坨。
     改成顶对齐后，按钮贴着第一行站住，正文拿到完整行宽。 */
  align-items: flex-start;
  padding: 22px 22px 18px;
  background: linear-gradient(122deg, var(--brand-darker) 0%, #1B4E9E 52%, #1D5FD0 100%);
  color: #fff;
  border-radius: var(--radius);
  margin-bottom: 16px;
  position: relative;
  overflow: hidden;
  flex-wrap: wrap;
}
/* 装饰层①：右上角一团柔光（原有的，稍微收一点，别糊住名字） */
.profile-head::after {
  content: "";
  position: absolute;
  right: -70px; top: -80px;
  width: 240px; height: 240px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(93, 156, 255, .40), transparent 68%);
  pointer-events: none;
}
/* 装饰层②：左下角一团更暗的光，让渐变有"两个光源"的立体感，
   否则整块只有右上亮、左下死平，看起来像一张纯色底图。 */
.profile-head::before {
  content: "";
  position: absolute;
  left: -90px; bottom: -110px;
  width: 260px; height: 260px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(29, 95, 208, .55), transparent 70%);
  pointer-events: none;
}
/* 装饰层③：一道极淡的斜向发丝线网 —— 纯色大块最容易显得"单调"，
   加一层低到几乎看不见的纹理，屏幕上立刻有质感；比塞一张 PNG 好在
   不占体积、跟着皮肤走、也不会在 Retina 上糊。 */
.profile-head {
  background-image:
    repeating-linear-gradient(115deg, rgba(255, 255, 255, .045) 0 1px, transparent 1px 12px),
    linear-gradient(122deg, var(--brand-darker) 0%, #1B4E9E 52%, #1D5FD0 100%);
}
/* 顶部一道高光细线：把卡片与页面底色"压"开，边界更利落 */
.profile-head > .ph-avatar,
.profile-head > .ph-main,
.profile-head > .ph-actions { position: relative; z-index: 1; }
.profile-head .ph-avatar {
  width: 82px; height: 82px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, .5);
  box-shadow: 0 0 0 7px rgba(255, 255, 255, .10), 0 10px 24px rgba(6, 20, 45, .34);
  object-fit: cover;
  flex: 0 0 82px;
  position: relative; z-index: 1;
  background: var(--brand-dark);
}
.profile-head .ph-main { position: relative; z-index: 1; min-width: 0; flex: 1; }
.profile-head h1 { color: #fff; font-size: 21px; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }

/* ── 职务区（需求 #5：一人多职务） ─────────────────────────────────
   以前是「职务」+「兼任 A / B / C」两行纯文本，同一条职务被列两遍，
   手机上能占到 60px 以上；改成一颗颗徽标后：职务名加粗、组织名弱化，
   扫读时先看"做什么"再看"在哪个组织"，折行由 flex-wrap 接管。 */
.profile-head .ph-posts {
  position: relative; z-index: 1;
  margin-top: 9px;
  display: flex; flex-wrap: wrap; gap: 6px;
}
.profile-head .ph-post {
  display: inline-flex; align-items: baseline; gap: 5px;
  max-width: 100%;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .13);
  border: 1px solid rgba(255, 255, 255, .2);
  font-size: 12.5px; line-height: 1.6;
  color: #EAF2FE;
}
.profile-head .ph-post b { font-weight: 600; color: #fff; }
.profile-head .ph-post i { font-style: normal; color: #A9C3E8; }
/* 权限最高的那条职务反白高亮，一眼能看出"主要身份" */
.profile-head .ph-post.is-main { background: rgba(255, 255, 255, .95); border-color: #fff; }
.profile-head .ph-post.is-main b { color: var(--brand-darker); }
.profile-head .ph-post.is-main i { color: #3A5A8C; }

/* 第 5 条起默认收起：常规的两三个职务一眼看全，只有真正身兼多职才需要展开 */
.profile-head .ph-posts:not(.is-open) .ph-post.is-extra { display: none; }
.profile-head .ph-post-more {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px; border-radius: 999px;
  background: transparent;
  border: 1px dashed rgba(255, 255, 255, .42);
  color: #CFE0F8;
  font-size: 12.5px; line-height: 1.6;
  font-family: inherit; cursor: pointer;
}
.profile-head .ph-post-more:hover { background: rgba(255, 255, 255, .14); color: #fff; }
.profile-head .ph-post-more svg { transition: transform .2s; }
.profile-head .ph-posts.is-open .ph-post-more svg { transform: rotate(180deg); }

/* 基础信息改网格：原来是 flex 一行铺开，手机上按内容宽度断行、长短不齐；
   auto-fit 网格让手机稳定两列、桌面一行排完，行数可预期。 */
/* 需求 #11：档案信息区重新排版。
   原来是「标签 值」横排、每项最小 124px 的 auto-fit 网格 —— 六项信息
   在宽屏排成一行、在窄屏碎成好几行，标签和值的字重又接近，
   一眼扫过去分不清哪是标签哪是值，这就是用户说的"内容太拥挤"。

   现在改成**标签在上、值在下**的小格子，格子之间用一根 1px 的发丝线分开
   （做法：容器铺一层半透明白当"线色"，格子里再铺一层深蓝当"底色"，
    1px 的 gap 露出来的就是线）。好处是：
     · 标签与值的层级一眼分明，不用加粗也读得出来；
     · 标签都短（"入队""昵称"），列宽可以收到 108px，同样宽度能多放一项；
     · 六项在宽屏排成 3~6 格、窄屏自动折行，每一格都是完整可读的单元，
       不会出现"标签留在上一行、值掉到下一行"的割裂。

   注意：这里**没有改任何 HTML** —— 靠 flex-direction: column 让标签
   （匿名文本节点）和 <b> 各占一行。三个使用了 .profile-head 的页面
   （个人中心 / 公开档案 / 后台档案）自动一起受益。 */
.profile-head .ph-meta {
  position: relative; z-index: 1;
  margin-top: 13px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(108px, 1fr));
  gap: 1px;
  padding: 1px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .16);   /* 露出来的就是分隔线 */
  overflow: hidden;
  font-size: 11.5px;
  color: #A9C3E8;
  letter-spacing: .2px;
}
.profile-head .ph-meta > span {
  display: flex;
  flex-direction: column;   /* 标签一行、值一行 */
  align-items: flex-start;
  gap: 1px;
  min-width: 0;
  padding: 8px 11px;
  background: rgba(9, 31, 68, .46);   /* 深蓝底，压住渐变的亮部 */
}
.profile-head .ph-meta > span > b {
  font-size: 14px;
  line-height: 1.35;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.profile-head .ph-meta b { color: #fff; font-weight: 600; }
.profile-head .ph-meta-note { grid-column: 1 / -1; font-size: 11.5px; opacity: .8; padding: 7px 11px; }

/* 只在某个组织里当组员、没有职务的组织名；
   原先靠下方分组 chip 承载，一个人加六个组就是六个 chip，那是手机端最长的一行。 */
.profile-head .ph-orgs {
  position: relative; z-index: 1;
  margin-top: 7px; line-height: 1.75;
  font-size: 12.5px; color: #C6DAF5;
}
.profile-head .ph-orgs-t {
  display: inline-block; margin-right: 8px; padding: 1px 7px;
  border-radius: 4px; background: rgba(255, 255, 255, .12);
  color: #A9C3E8; font-size: 11.5px;
}

.profile-head .ph-tags { margin-top: 10px; display: flex; gap: 6px; flex-wrap: wrap; }
.profile-head .ph-tags .chip {
  background: rgba(255, 255, 255, .16);
  border-color: rgba(255, 255, 255, .22);
  color: #EAF2FE;
}
.profile-head .ph-actions { position: relative; z-index: 1; display: flex; gap: 8px; flex-wrap: wrap; }
.profile-head .ph-actions .btn-ghost {
  background: rgba(255, 255, 255, .14);
  border-color: rgba(255, 255, 255, .26);
  color: #fff;
}
.profile-head .ph-actions .btn-ghost:hover { background: rgba(255, 255, 255, .24); color: #fff; }

/* 需求 #78-11：公开主页的「主页短链」区块已整块移除。
   原先这里有一整套 .ph-shortlink / .psl-tag / .psl-url 规则（桌面 9 条 +
   手机端 5 条），现在全站已无任何元素带这些类名 —— 留着只会让后来人
   以为"页面上还有个短链框被藏起来了"，所以一并删掉。
   短链能力本身没删：member_url() / member_share_url() 照旧可用，
   后台「人员档案」详情页与人员列表里仍能看到并复制短链。 */

@media (max-width: 760px) {
  /* 头像改为顶部对齐：main 内容多时（多职务）它会掉到卡片中腰，
     看着像"另起一块"，与右侧文字失去关联。 */
  .profile-head { align-items: flex-start; padding: 16px; gap: 13px; }
  .profile-head .ph-avatar { margin-top: 1px; }
  .profile-head .ph-meta { grid-template-columns: repeat(auto-fit, minmax(108px, 1fr)); gap: 4px 12px; }
  .profile-head .ph-post,
  .profile-head .ph-post-more { font-size: 12px; padding: 4px 10px; }
}
/* 触屏设备：职务折叠按钮的视觉高度只有 20 多像素，
   手指点不准。这里垫一层 44px 高的透明命中区，外观不变、
   命中面积达到可点标准（走查脚本会 elementFromPoint 实测）。 */
@media (hover: none) {
  .profile-head .ph-post-more { position: relative; }
  .profile-head .ph-post-more::after {
    content: ""; position: absolute; left: 0; right: 0; top: 50%;
    transform: translateY(-50%); height: 44px;
  }
}

/* --------------------------------------------------------------------------
   19. 前台（对外站点）
   -------------------------------------------------------------------------- */
.public-body { background: var(--surface); }

.site-head {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
.site-head-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.site-logo { display: flex; align-items: center; gap: 10px; }
.site-logo .logo-badge {
  width: 40px; height: 40px; border-radius: 12px;
  background: var(--brand-grad);
  display: grid; place-items: center;
  box-shadow: 0 4px 14px rgba(29, 95, 208, .35);
  flex: 0 0 40px;
}
.site-logo .logo-badge svg { width: 24px; height: 24px; }
.site-logo strong { display: block; font-size: 16px; letter-spacing: .4px; line-height: 1.25; }
.site-logo span { display: block; font-size: 11px; color: var(--text-3); letter-spacing: 1.6px; }

.site-nav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.site-nav a {
  padding: 8px 13px;
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-size: 14px;
  font-weight: 500;
}
.site-nav a:hover { background: var(--brand-lighter); color: var(--brand); }

/* 首屏 */
.hero {
  position: relative;
  background:
    radial-gradient(1100px 460px at 82% -12%, rgba(93, 156, 255, .34), transparent 62%),
    radial-gradient(720px 380px at 8% 108%, rgba(255, 106, 43, .18), transparent 66%),
    var(--brand-grad-deep);
  color: #fff;
  overflow: hidden;
}
.hero::after {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.045) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(ellipse at 50% 0%, #000 20%, transparent 76%);
  pointer-events: none;
}
.hero-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 62px 20px 74px;
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.15fr .85fr;
  gap: 44px;
  align-items: center;
}
.hero-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 13px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .2);
  font-size: 12.5px;
  letter-spacing: .6px;
  margin-bottom: 18px;
}
.hero-eyebrow i { width: 7px; height: 7px; border-radius: 50%; background: #6BE39A; box-shadow: 0 0 0 3px rgba(107, 227, 154, .25); }
.hero h1 {
  font-size: 42px;
  line-height: 1.2;
  color: #fff;
  letter-spacing: -.5px;
  margin-bottom: 16px;
}
.hero h1 em { font-style: normal; color: #7FB6FF; }
.hero-lead { font-size: 15.5px; color: #C6DAF7; line-height: 1.85; max-width: 560px; margin-bottom: 26px; }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.hero-actions .btn { padding: 12px 24px; font-size: 15px; border-radius: var(--radius-sm); }
.btn-glass {
  background: rgba(255, 255, 255, .13);
  border: 1px solid rgba(255, 255, 255, .28);
  color: #fff;
}
.btn-glass:hover { background: rgba(255, 255, 255, .22); color: #fff; filter: none; }
.btn-white { background: var(--surface); color: var(--brand-dark); }
.btn-white:hover { background: #F0F5FF; color: var(--brand-dark); filter: none; }

.hero-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}
.hero-stat {
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .17);
  border-radius: var(--radius);
  padding: 16px 18px;
  backdrop-filter: blur(6px);
}
.hero-stat .hs-val { font-size: 28px; font-weight: 800; color: #fff; line-height: 1.2; font-variant-numeric: tabular-nums; }
.hero-stat .hs-val small { font-size: 13px; font-weight: 600; color: var(--side-text-dim); margin-left: 3px; }
.hero-stat .hs-label { font-size: 12.5px; color: var(--side-text-dim); margin-top: 2px; }

/* 区块 */
.section { max-width: 1180px; margin: 0 auto; padding: 58px 20px; }
.section-head { text-align: center; margin-bottom: 34px; }
.section-head .kicker {
  display: inline-block;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 1.6px;
  color: var(--brand);
  text-transform: uppercase;
  margin-bottom: 8px;
}
.section-head h2 { font-size: 27px; margin-bottom: 10px; }
.section-head p { color: var(--text-3); font-size: 14.5px; max-width: 620px; margin: 0 auto; }

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  gap: 16px;
}
.feature {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
  transition: transform .2s, box-shadow .2s, border-color .2s;
}
.feature:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--brand-border); }
.feature .f-icon {
  width: 44px; height: 44px; border-radius: 13px;
  display: grid; place-items: center;
  background: var(--brand-light); color: var(--brand);
  margin-bottom: 14px;
}
.feature .f-icon svg { width: 22px; height: 22px; }
.feature h3 { font-size: 15.5px; margin-bottom: 7px; }
.feature p { font-size: 13.5px; color: var(--text-3); margin: 0; line-height: 1.75; }

.section-alt { background: var(--surface-2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }

/* 公开查询面板 */
.query-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 22px;
}
.query-row { display: flex; gap: 10px; flex-wrap: wrap; }
.query-row .input { flex: 1 1 240px; }
.query-row .btn { flex: 0 0 auto; padding: 9.5px 26px; }

.result-card {
  display: flex;
  gap: 16px;
  align-items: center;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  margin-bottom: 10px;
  transition: border-color .16s, box-shadow .16s;
  flex-wrap: wrap;
}
.result-card:hover { border-color: var(--brand); box-shadow: var(--shadow); }
.result-card .rc-avatar { width: 58px; height: 58px; border-radius: 50%; object-fit: cover; flex: 0 0 58px; }
.result-card .rc-body { flex: 1; min-width: 180px; }
.result-card .rc-name { font-size: 16px; font-weight: 700; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.result-card .rc-sub { font-size: 12.5px; color: var(--text-3); margin-top: 3px; }
.result-card .rc-tags { margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap; }

.site-foot {
  background: #0C2A61;
  color: #93ADD6;
  padding: 26px 20px 22px;
  font-size: 13px;
}
.site-foot-inner { max-width: 1180px; margin: 0 auto; display: flex; gap: 14px 22px; flex-wrap: wrap; align-items: baseline; }
.site-foot a { color: var(--head-text-dim); }
.site-foot .foot-right { margin-left: auto; }

/* --------------------------------------------------------------------------
   19b. 页脚重排（需求 #77）
   --------------------------------------------------------------------------
   两行：品牌行（队伍名称 + 系统名称）／法务行（Copyright · 备案号 · 隐私政策 ·
   技术支持）。法务行用 flex + 中点分隔，不写成一条 <div> 拼字符串 ——
   备案号与隐私政策都可能是"没有"，拼字符串就得在 PHP 里到处判空。
   窄屏由下面的媒体查询折成两行，不靠换行符。 */
.site-foot .sf-brand { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.site-foot .sf-brand strong { color: #fff; font-size: 15px; letter-spacing: .3px; }
.site-foot .sf-sys { font-size: 12px; color: #7B9BD0; }
.site-foot .sf-legal { margin-left: auto; display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap; font-size: 12.5px; }
.site-foot .sf-legal > * { position: relative; }
/* 分隔点用 ::before 画，而不是往文案里塞「·」——
   塞进去的话，最后一项后面会跟着一个孤零零的点（因为每一项都带）。 */
.site-foot .sf-legal > * + *::before {
  content: '·';
  position: absolute;
  left: -9px;
  color: #4E6F9E;
}
.site-foot .sf-tech a { display: inline-flex; align-items: center; gap: 3px; }
.site-foot .sf-tech svg { opacity: .75; }

/* 备案号链接（需求 3）：页脚底色是深蓝，默认的链接色在上面偏暗，
   这里提亮到与品牌行相近的亮度，否则「能点」这件事看不出来。
   下划线只在悬停时出现 —— 页脚是法务信息行，常驻下划线会显得脏。 */
.site-foot .sf-icp { display: inline-flex; align-items: center; gap: 3px; color: #B9CEEB; }
.site-foot .sf-icp:hover { color: #fff; text-decoration: underline; }
.site-foot .sf-icp svg { opacity: .7; }

/* 页脚底部导航（需求 4）：与版权 / 备案号 / 隐私政策同一行的一条平铺链接组。
   为什么自己是一层 inline-flex 而不是直接把 <a> 散在 .sf-legal 里：
   .sf-legal 用 `> * + *::before` 给**每个相邻元素**画分隔点，
   散着放的话「底部导航第一项」和「版权」之间、以及组内每一项之间
   都会出现分隔点，读起来像法务条款而不是导航。
   成组之后整组只与前后各有一个分隔点，组内用自己的 gap 拉开。 */
.site-foot .sf-nav { display: inline-flex; align-items: center; gap: 4px 14px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   20. 登录 / 注册
   -------------------------------------------------------------------------- */
.auth-wrap {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  background: var(--surface);
}
.auth-side {
  background:
    radial-gradient(760px 420px at 78% 8%, rgba(93, 156, 255, .32), transparent 62%),
    linear-gradient(158deg, #0A2550 0%, #123C86 52%, #1D5FD0 100%);
  color: #fff;
  padding: 48px 44px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  overflow: hidden;
}
.auth-side::after {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.05) 1px, transparent 1px);
  background-size: 42px 42px;
  mask-image: radial-gradient(ellipse at 60% 20%, #000 15%, transparent 72%);
}
.auth-side > * { position: relative; z-index: 1; }
.auth-side h2 { color: #fff; font-size: 30px; line-height: 1.35; margin-bottom: 14px; }
.auth-side p { color: #C1D8F7; font-size: 14.5px; line-height: 1.85; }
.auth-side .auth-points { margin-top: 30px; display: flex; flex-direction: column; gap: 13px; }
.auth-point { display: flex; gap: 11px; align-items: flex-start; font-size: 14px; color: #DCEAFB; }
.auth-point .ap-ico {
  width: 26px; height: 26px; border-radius: 8px; flex: 0 0 26px;
  background: rgba(255, 255, 255, .16);
  display: grid; place-items: center;
}
.auth-point .ap-ico svg { width: 15px; height: 15px; }

.auth-form-side { display: flex; align-items: center; justify-content: center; padding: 40px 20px; }
.auth-card { width: 100%; max-width: 396px; }
.auth-card h1 { font-size: 25px; margin-bottom: 6px; }
.auth-card .auth-sub { color: var(--text-3); font-size: 13.5px; margin-bottom: 26px; }
.auth-card .field { margin-bottom: 15px; }
.auth-tip {
  margin-top: 18px;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  background: var(--brand-lighter);
  border: 1px dashed #C9DCFB;
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.75;
}
.auth-tip code {
  background: var(--surface);
  padding: 1px 6px;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--brand-dark);
  border: 1px solid var(--border);
}

/* --------------------------------------------------------------------------
   42.8 登录页 · 演示账号清单（需求 #19）
   --------------------------------------------------------------------------
   原先是一行「管理员：admin　管理层：manager　正式队员：zhaomin」的纯文字，
   六个账号挤成两行、中英文混排、"哪个是人名哪个是账号"要读两遍。
   现在改成一张小表：身份 / 手机号 / 姓名各占一列，手机号可点即填。
   一列一列对齐之后，扫一眼就知道该用哪个号进哪个权限。
   -------------------------------------------------------------------------- */
.auth-tip .demo-rows {
  display: grid;
  gap: 4px;
  margin: 8px 0 7px;
}
.auth-tip .demo-row {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.auth-tip .dr-role { color: var(--text-3); }
.auth-tip .dr-phone {
  cursor: pointer;
  font-weight: 600;
  letter-spacing: .4px;
  text-align: left;
  transition: background .14s, border-color .14s, color .14s;
}
.auth-tip .dr-phone:hover {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.auth-tip .dr-name { color: var(--text-3); white-space: nowrap; }
.auth-tip .dr-note { font-size: 11.5px; line-height: 1.75; color: var(--text-3); }
@media (max-width: 420px) {
  .auth-tip .demo-row { grid-template-columns: 76px minmax(0, 1fr); }
  .auth-tip .dr-name { display: none; }
}
.auth-foot { text-align: center; margin-top: 24px; font-size: 13.5px; color: var(--text-3); }

/* 需求 #62：30 天免登录的勾选框与说明。
   说明用浅底小字块而不是弹窗 —— 登录页弹「是否同意协议」会平白多一次点击。 */
.remember-row {
  display: flex; align-items: center; gap: 8px;
  margin: 2px 0 8px; font-size: 13.5px; color: var(--text-2);
  cursor: pointer; user-select: none;
}
.remember-row input[type="checkbox"] {
  width: 15px; height: 15px; flex: none;
  accent-color: var(--brand); cursor: pointer;
}
.remember-row strong { color: var(--brand-dark); }
.remember-tip {
  display: flex; gap: 7px; align-items: flex-start;
  margin: 0 0 4px; padding: 9px 11px;
  border-radius: var(--radius-sm);
  background: var(--brand-lighter);
  border: 1px solid var(--border);
  font-size: 12px; line-height: 1.7; color: var(--text-3);
}
.remember-tip svg { flex: none; margin-top: 2px; color: var(--brand); }

/* --------------------------------------------------------------------------
   21. 工具类
   -------------------------------------------------------------------------- */
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; align-items: start; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.justify-between { justify-content: space-between; }
.gap-4 { gap: 4px; } .gap-6 { gap: 6px; } .gap-8 { gap: 8px; }
.gap-10 { gap: 10px; } .gap-12 { gap: 12px; } .gap-16 { gap: 16px; }
.ml-auto { margin-left: auto; }
.mt-0 { margin-top: 0; } .mt-8 { margin-top: 8px; } .mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; } .mt-24 { margin-top: 24px; } .mt-8 { margin-top: 8px; }
/* mt-10 / mt-14 在页面里已多处使用，之前漏了定义，补上以免间距失效 */
.mt-10 { margin-top: 10px; } .mt-14 { margin-top: 14px; }
.mb-0 { margin-bottom: 0; } .mb-8 { margin-bottom: 8px; } .mb-12 { margin-bottom: 12px; }
.mb-16 { margin-bottom: 16px; }
.text-2 { color: var(--text-2); } .text-3 { color: var(--text-3); }
.text-sm { font-size: 12.5px; } .text-xs { font-size: 11.5px; }
.text-ok { color: var(--ok); } .text-warn { color: var(--warn); } .text-danger { color: var(--danger); }
.text-brand { color: var(--brand); }
.fw-600 { font-weight: 600; } .fw-700 { font-weight: 700; }
.nowrap { white-space: nowrap; }
.mono { font-family: var(--mono); }
.hidden { display: none !important; }
.divider { height: 1px; background: var(--border); margin: 16px 0; }
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.hide-mobile { display: initial; }
.show-mobile { display: none; }

/* --------------------------------------------------------------------------
   22. 响应式 —— 手机端适配
   -------------------------------------------------------------------------- */

/* 平板 */
@media (max-width: 1024px) {
  .hero-inner { grid-template-columns: 1fr; gap: 34px; padding: 48px 20px 56px; }
  .hero h1 { font-size: 34px; }
  .auth-wrap { grid-template-columns: 1fr; }
  .auth-side { display: none; }
  .form-grid .span-3 { grid-column: span 2; }
}

/* 手机 / 窄屏 */
@media (max-width: 860px) {
  /* 侧边栏转为抽屉 */
  .sidebar {
    position: fixed;
    left: 0; top: 0; bottom: 0;
    height: 100%;
    transform: translateX(-102%);
    transition: transform .26s cubic-bezier(.4, 0, .2, 1);
    box-shadow: var(--shadow-lg);
    width: 264px;
    flex-basis: 264px;
  }
  .sidebar.open { transform: translateX(0); }
  .drawer-mask { display: block; pointer-events: none; }
  .drawer-mask.show { pointer-events: auto; }

  .hamburger { display: inline-flex; }

  /* 顶部栏紧凑 */
  .topbar { padding: 0 12px; gap: 9px; }
  .topbar-title h1 { font-size: 15.5px; }
  .topbar-title .crumb { display: none; }
  .user-chip .uc-text { display: none; }
  .user-chip { padding: 4px; }
  .topbar-actions .hide-mobile { display: none; }

  .content { padding: 14px 12px 78px; }

  /* 底部导航 */
  .bottom-nav { display: flex; }

  /* 统计卡两列 */
  .stat-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .stat { padding: 13px 14px; }
  .stat .stat-value { font-size: 22px; }
  .stat .stat-label { font-size: 11.5px; }
  .stat-icon { width: 28px; height: 28px; border-radius: 8px; margin-bottom: 7px; }
  .stat-icon svg { width: 15px; height: 15px; }

  .card-head { padding: 12px 14px; }
  .card-body { padding: 14px; }
  .card-foot { padding: 10px 14px; }
  .pager { padding: 12px 14px; }
  /* 标签栏：移动端换行铺开，避免横向滚动把后面的分类藏起来 */
  .tabs {
    padding: 0 10px;
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: 0;
  }
  .tabs a { padding: 10px 10px; font-size: 12.5px; }

  /* 筛选栏：多选芯片整行铺开，按钮铺满 */
  .filter-bar { gap: 12px 8px; }
  .filter-bar .field,
  .filter-bar .field.wide { flex: 1 1 100%; min-width: 0; }
  .filter-bar .fb-actions { flex: 1 1 100%; }
  .filter-bar .fb-actions .btn { flex: 1; justify-content: center; }
  .msel { max-height: 148px; }
  .msel-item > span { padding: 7px 13px; min-height: 34px; font-size: 13px; }

  /* 表单：单列 */
  .form-grid { grid-template-columns: 1fr; gap: 12px; }
  .form-grid .span-2, .form-grid .span-3 { grid-column: span 1; }
  .field > label { font-size: 12.5px; }
  .input, .select, .textarea { font-size: 16px; } /* ≥16px 避免 iOS 自动放大 */

  /* 筛选栏整行 */
  .filter-bar { gap: 8px; }
  .filter-bar .field { flex: 1 1 100%; }
  .filter-bar .field.half { flex: 1 1 calc(50% - 4px); min-width: 0; }
  .filter-bar .fb-actions { flex: 1 1 100%; }
  .filter-bar .fb-actions .btn { flex: 1 1 auto; }

  /* 表格：横向滚动 + 更小内边距 */
  .table { font-size: 13px; min-width: 560px; }
  .table thead th { padding: 9px 11px; font-size: 12px; }
  .table tbody td { padding: 9px 11px; }

  /* 卡片化表格（用于关键列表） */
  .table-stack { min-width: 0; }
  .table-stack thead { display: none; }
  .table-stack tbody tr {
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    margin-bottom: 10px;
    padding: 6px 4px;
    background: var(--surface);
  }
  .table-stack tbody tr:hover { background: var(--surface); }
  .table-stack tbody td {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 7px 10px;
    border-bottom: 1px dashed #EEF2F8;
    text-align: left !important;
  }
  .table-stack tbody tr td:last-child { border-bottom: none; }
  .table-stack tbody td::before {
    content: attr(data-label);
    flex: 0 0 82px;
    color: var(--text-3);
    font-size: 12px;
    font-weight: 600;
  }
  .table-stack tbody td.col-actions { justify-content: flex-start; }
  .table-stack tbody td.col-actions::before { content: attr(data-label); }

  /* 档案头部 */
  .profile-head { padding: 16px; gap: 14px; }
  .profile-head .ph-avatar { width: 62px; height: 62px; flex-basis: 62px; }
  .profile-head h1 { font-size: 18px; }
  .profile-head .ph-actions { width: 100%; }
  .profile-head .ph-actions .btn { flex: 1 1 auto; }

  .dl { grid-template-columns: 1fr; }
  .dl-item { flex-direction: column; gap: 2px; }
  .dl-item dt { flex: none; }

  /* 前台 */
  .site-head-inner { padding: 10px 14px; }
  .site-logo strong { font-size: 14.5px; }
  .site-nav { display: none; }
  .site-nav.open {
    display: flex;
    position: absolute;
    /* 相对 .site-head 底部展开（此前误用了后台顶栏变量 --topbar-h，
       前台并未定义该变量，导致 top 失效、菜单在页头内部错位展开） */
    top: 100%;
    left: 0; right: 0;
    flex-direction: column;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow);
    padding: 8px 12px 14px;
    gap: 2px;
    z-index: 60;
    max-height: calc(100vh - 64px);
    overflow-y: auto;
  }
  .site-nav.open a { padding: 11px 12px; }
  .site-head .hamburger { display: inline-flex; margin-left: auto; }

  .hero-inner { padding: 38px 16px 44px; gap: 26px; }
  .hero h1 { font-size: 26px; line-height: 1.3; }
  .hero-lead { font-size: 14px; line-height: 1.8; }
  .hero-actions .btn { flex: 1 1 100%; }
  .hero-stats { grid-template-columns: repeat(2, 1fr); gap: 9px; }
  .hero-stat { padding: 13px 14px; }
  .hero-stat .hs-val { font-size: 22px; }

  .section { padding: 40px 16px; }
  .section-head h2 { font-size: 21px; }
  .section-head p { font-size: 13.5px; }
  .feature-grid { grid-template-columns: 1fr; gap: 12px; }
  .feature { padding: 18px; }

  .query-panel { padding: 16px; }
  .query-row .btn { flex: 1 1 100%; }

  .result-card { padding: 14px; gap: 12px; }
  .result-card .rc-avatar { width: 48px; height: 48px; flex-basis: 48px; }

  .site-foot { padding: 22px 16px 18px; }
  .site-foot-inner { flex-direction: column; align-items: flex-start; gap: 8px; }
  .site-foot .foot-right { margin-left: 0; }
  /* 需求 #77：窄屏下法务行也要左对齐，并且**不再画分隔点** ——
     折行后点会掉到行首或行尾，看着像排版坏了。改成每项一行。 */
  .site-foot .sf-legal { margin-left: 0; flex-direction: column; align-items: flex-start; gap: 4px; }
  .site-foot .sf-legal > * + *::before { content: none; }

  .auth-form-side { padding: 26px 18px; }
  .auth-card h1 { font-size: 22px; }

  .hide-mobile { display: none !important; }
  .show-mobile { display: initial; }

  .modal-box { width: calc(100% - 28px); margin: 0 auto; }
}

@media (max-width: 420px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .stat .stat-value { font-size: 20px; }
  .hero h1 { font-size: 23px; }
  h1 { font-size: 20px; }
  .btn-group .btn { flex: 1 1 auto; }
}

/* --------------------------------------------------------------------------
   23. 弹窗
   -------------------------------------------------------------------------- */
.modal-mask {
  position: fixed; inset: 0;
  background: rgba(12, 28, 56, .5);
  z-index: 90;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  opacity: 0; pointer-events: none;
  transition: opacity .2s;
}
.modal-mask.show { opacity: 1; pointer-events: auto; }
.modal-box {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 560px;
  max-height: 88vh;
  overflow-y: auto;
  transform: translateY(10px) scale(.98);
  transition: transform .2s;
}
.modal-mask.show .modal-box { transform: none; }
.modal-head {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 18px;
  border-bottom: 1px solid var(--border);
}
.modal-head h3 { font-size: 16px; }
.modal-head .modal-close {
  margin-left: auto; background: none; border: none;
  font-size: 22px; line-height: 1; color: var(--text-3); padding: 0 4px;
}
.modal-body { padding: 18px; }
.modal-foot {
  display: flex; gap: 10px; justify-content: flex-end;
  padding: 13px 18px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}

/* --------------------------------------------------------------------------
   24. 上传控件
   -------------------------------------------------------------------------- */
/* 上传区也一并收紧（需求 #6：「上传图片占用太大空间」）：
   虚线框内边距 18 → 12、图标 26 → 20、预览图 74 → 60。
   上传区在页面上往往成对出现（头像 + 证书 + 附件），
   每处省 20px 就是一屏的差别。 */
.upload-zone {
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 12px;
  text-align: center;
  background: var(--surface-2);
  transition: border-color .16s, background .16s;
  cursor: pointer;
}
.upload-zone:hover { border-color: var(--brand); background: var(--brand-lighter); }
.upload-zone svg { width: 20px; height: 20px; color: var(--brand); margin: 0 auto 5px; }
.upload-zone .uz-txt { font-size: 12.5px; color: var(--text-2); }
.upload-zone .uz-hint { font-size: 11px; color: var(--text-3); margin-top: 2px; }
.upload-zone input[type=file] { display: none; }
.upload-preview { display: flex; gap: 10px; align-items: center; margin-top: 10px; }
.upload-preview img { width: 60px; height: 60px; border-radius: var(--radius-xs); object-fit: cover; border: 1px solid var(--border); }
/* 证书缩略图：点击即开灯箱放大（PC 悬停有反馈，手机点按全屏） */
.cert-thumb {
  width: 44px; height: 44px; border-radius: 7px; object-fit: cover;
  border: 1px solid var(--border); cursor: zoom-in; background: var(--surface-2);
  transition: border-color .15s, transform .15s;
}
.cert-thumb:hover { border-color: var(--brand); transform: scale(1.04); }

/* --------------------------------------------------------------------------
   25. 新增模块组件
   覆盖：通知公告 / 任务发布报名 / 专业分组通讯录 / 荣誉审核 / 内容与捐赠
   -------------------------------------------------------------------------- */

/* --- 25.1 通用小工具 --- */
.grid-main { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.items-start { align-items: flex-start; }
/* 表格里的主标题链接：保持正文字重与颜色，悬停才出现品牌色，避免整列变蓝 */
a.strong { color: var(--text); text-decoration: none; }
a.strong:hover { color: var(--brand); }
.input-sm { padding: 7px 10px; font-size: 13px; border-radius: var(--radius-xs); }
.inline-form { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* --- 需求 #64：人员列表里就地切换在岗状态 ---
   表格单元格很窄，下拉压到最小尺寸；休假日期只在选了「休假」时才出现，
   平时 hidden，避免每行都多一个输入框把表格撑开。 */
.inline-online { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.inline-online .select-xs {
  padding: 4px 8px; font-size: 12.5px; border-radius: var(--radius-xs);
  min-width: 78px; height: auto; line-height: 1.5;
}
.inline-online .vac-pick { width: 138px; max-width: 100%; }
.inline-online .input-sm { padding: 4px 8px; font-size: 12.5px; }
.form-grid-1 { grid-template-columns: 1fr; }
.thumb-link { display: inline-block; margin-top: 6px; }
.thumb-link img { width: 88px; height: 88px; border-radius: var(--radius-xs); object-fit: cover; border: 1px solid var(--border); }

/* --- 25.2 图片缩略图组 + 点击放大 --- */
.thumb-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.thumb-item { position: relative; width: 96px; }
.thumb-item img {
  width: 96px;
  height: 72px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  border: 1px solid var(--border);
  background: var(--bg);
  display: block;
  cursor: zoom-in;
  transition: border-color .15s, transform .15s;
}
.thumb-item img:hover { border-color: var(--brand); transform: translateY(-1px); }
.thumb-cap {
  margin-top: 3px;
  font-size: 11px;
  color: var(--text-3);
  text-align: center;
}
/* 空位提示，避免「四格缺一格」时版式塌陷 */
.thumb-empty {
  width: 96px;
  height: 72px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-xs);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: var(--text-3);
  background: var(--surface-2);
}

/* 图片放大层 */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(12, 20, 36, .82);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 24px;
  cursor: zoom-out;
}
.lightbox img {
  max-width: min(92vw, 1100px);
  max-height: 82vh;
  border-radius: var(--radius-sm);
  background: var(--fixed-white);
  box-shadow: 0 20px 60px rgba(0, 0, 0, .45);
}
.lightbox-cap { color: #EAF0FA; font-size: 13px; }
.lightbox-close {
  position: absolute;
  top: 18px;
  right: 20px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, .16);
  color: #fff;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.lightbox-close:hover { background: rgba(255, 255, 255, .28); }

/* 车辆四视图上传格 */
.photo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 12px; }
.photo-cell {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px;
  background: var(--surface-2);
}
.photo-cell > img {
  width: 100%;
  height: 96px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  border: 1px solid var(--border);
  background: var(--bg);
  display: block;
  cursor: zoom-in;
}
.photo-cell .thumb-empty { width: 100%; height: 96px; }
.photo-cell .input-sm { margin-top: 8px; font-size: 11.5px; padding: 5px 7px; }
.photo-del {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 7px;
  font-size: 12px;
  color: var(--text-3);
  cursor: pointer;
}

/* 列表内的照片小图条 */
.mini-thumbs { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.mini-thumbs img {
  width: 38px;
  height: 30px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
  background: var(--bg);
  cursor: zoom-in;
  display: block;
}
.mini-thumbs img:hover { border-color: var(--brand); }
.mt-4 { margin-top: 4px; }
.mb-4 { margin-bottom: 4px; }
.ml-4 { margin-left: 4px; }

/* 通用文本/数值（表格外同样可用） */
.strong { font-weight: 600; color: var(--text); }
.num { font-variant-numeric: tabular-nums; }
.kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 9px 14px; margin: 0; font-size: 13.5px; }
.kv dt { color: var(--text-3); white-space: nowrap; }
.kv dd { margin: 0; color: var(--text); word-break: break-word; }

/* 步骤说明列表 */
.step-list { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; font-size: 13.5px; color: var(--text-2); line-height: 1.7; }
.step-list li::marker { color: var(--brand); font-weight: 700; }
.step-list li b { color: var(--text); }

/* --- 25.17 救援贡献量化（履历） --- */
.contrib-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(126px, 1fr)); gap: 12px; }
.contrib-item {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 16px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); text-align: center;
}
.contrib-item b { font-size: 30px; font-weight: 700; line-height: 1.05; color: var(--brand); font-variant-numeric: tabular-nums; }
.contrib-item span { font-size: 12.5px; color: var(--text-2); }
.contrib-item small { font-size: 11px; color: var(--text-3); }
.contrib-item.is-total { background: var(--brand-light); border-color: var(--brand-border); }
.contrib-item.is-total b { color: var(--brand-dark); }
.contrib-item.is-total span { color: var(--brand-dark); }

.honor-list { display: flex; flex-direction: column; gap: 10px; }
.honor-item { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--surface-2); }
.honor-item img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; flex: 0 0 34px; border: 1px solid var(--border); }

/* --- 25.18 前台单页 / 快捷入口 / 捐赠公示 --- */
.btn-primary { background: var(--brand); color: #fff; }
.btn-primary:hover { background: var(--brand-dark); }

.page-body { font-size: 14.5px; }
.page-body h1, .page-body h2 { font-size: 19px; }
.page-body h3 { font-size: 16px; }

.quick-links { display: grid; grid-template-columns: repeat(auto-fit, minmax(206px, 1fr)); gap: 12px; }
.quick-link {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); text-decoration: none; color: inherit;
  transition: border-color .16s, box-shadow .16s, transform .16s;
}
.quick-link:hover { border-color: var(--brand); box-shadow: var(--shadow); transform: translateY(-1px); }
.quick-link svg { color: var(--brand); flex: 0 0 auto; }
.quick-link span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.quick-link b { font-size: 14px; }
.quick-link small { font-size: 11.5px; color: var(--text-3); }

.donor-mark { width: 38px; height: 38px; border-radius: 50%; flex: 0 0 38px; display: flex; align-items: center; justify-content: center; background: var(--danger-light); color: var(--danger); }
.donor-mark svg { width: 18px; height: 18px; }

/* 富文本（任务说明 / 通知正文）——后台录入，无需防注入处理 */
.rich-text { font-size: 14px; line-height: 1.78; color: var(--text-2); word-break: break-word; }
.rich-text p { margin: 0 0 10px; }
.rich-text p:last-child { margin-bottom: 0; }
.rich-text img { max-width: 100%; border-radius: var(--radius-sm); margin: 6px 0; }
.rich-text ul, .rich-text ol { padding-left: 20px; margin: 0 0 10px; }
.rich-text li { margin-bottom: 4px; }
.rich-text h1, .rich-text h2, .rich-text h3 { color: var(--text); font-size: 15px; margin: 14px 0 8px; }
.rich-text a { color: var(--brand); text-decoration: underline; }
.rich-text table { width: 100%; border-collapse: collapse; margin: 8px 0; }
.rich-text th, .rich-text td { border: 1px solid var(--border); padding: 6px 9px; font-size: 13px; }
.rich-text blockquote { margin: 8px 0; padding: 8px 12px; background: var(--surface-2); border-left: 3px solid var(--brand); border-radius: 0 var(--radius-xs) var(--radius-xs) 0; color: var(--text-2); }

/* --- 25.2 头像 --- */
.avatar { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex: 0 0 38px; border: 1px solid var(--border); background: var(--brand-lighter); }
.avatar-sm { width: 34px; height: 34px; flex-basis: 34px; }
.avatar-lg { width: 56px; height: 56px; flex-basis: 56px; }

/* --- 25.3 可点击统计卡 --- */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr)); gap: 12px; margin-bottom: 16px; }
.stat-link { display: block; text-decoration: none; color: inherit; transition: border-color .16s, box-shadow .16s; }
.stat-link:hover { border-color: var(--border-strong); box-shadow: var(--shadow); }
.stat.is-active { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-light); }
.stat.is-active::after { background: var(--brand-light); }
.stat.is-active .stat-value { color: var(--brand); }

/* --- 25.4 列表栈（通知 / 荣誉 / 通用条目） --- */
.list-stack { display: flex; flex-direction: column; }
.list-row { display: flex; align-items: flex-start; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.list-row:last-child { border-bottom: none; }
.list-row:hover { background: var(--surface-2); }
.list-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.list-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 14px; }
.list-title a { color: var(--brand); }
.list-sub { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13.5px; }
.list-meta { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap; font-size: 12px; color: var(--text-3); }
.list-note { font-size: 12.5px; color: var(--text-2); background: var(--surface-2); border-left: 3px solid var(--border-strong); border-radius: 0 var(--radius-xs) var(--radius-xs) 0; padding: 7px 10px; }
.list-actions { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; align-items: stretch; min-width: 132px; }
.list-actions .btn { white-space: nowrap; }

/* --- 25.5 荣誉勋章 --- */
.honor-cell { display: flex; align-items: center; gap: 10px; }
.honor-cell img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; border: 1px solid var(--border); flex: 0 0 34px; }
.honor-mark { width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--warn-light); color: var(--warn); flex: 0 0 34px; }
.honor-mark svg { width: 17px; height: 17px; }

/* --- 25.6 专业分组 --- */
.group-list { display: flex; flex-direction: column; gap: 10px; }
.group-item { display: flex; align-items: flex-start; gap: 12px; padding: 13px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); transition: border-color .16s, background .16s; }
.group-item:hover { border-color: var(--border-strong); background: var(--surface-2); }
.group-item.is-off { opacity: .62; }
.g-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.g-name { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 14px; font-weight: 600; }
.g-desc { font-size: 12.5px; color: var(--text-2); }
.g-actions { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

/* --- 25.7 成员胶囊（通讯录 / 任务名单） --- */
.member-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.member-chip { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); min-width: 210px; text-decoration: none; color: inherit; transition: border-color .16s, box-shadow .16s; }
a.member-chip:hover { border-color: var(--brand); box-shadow: var(--shadow-sm); }
.member-chip.is-static { background: var(--surface-2); }
.member-chip img { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex: 0 0 38px; border: 1px solid var(--border); }
.member-chip > span { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.mc-name { font-size: 13.5px; font-weight: 600; }
.mc-sub { font-size: 11.5px; color: var(--text-3); }
.org-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: 0 0 9px; }

/* --- 25.8 通知列表（详情折叠） --- */
.notice-list { display: flex; flex-direction: column; }
.notice-item { border-bottom: 1px solid var(--border); }
.notice-item:last-child { border-bottom: none; }
.notice-item > summary { display: flex; align-items: center; gap: 11px; padding: 14px 18px; cursor: pointer; list-style: none; transition: background .16s; }
.notice-item > summary::-webkit-details-marker { display: none; }
.notice-item > summary:hover { background: var(--surface-2); }
.notice-item.is-unread > summary { background: var(--brand-lighter); }
.notice-item[open] > summary { background: var(--surface-2); }
.ni-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; background: var(--border-strong); }
.notice-item.is-unread .ni-dot { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-light); }
.ni-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.ni-title { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 14.5px; font-weight: 600; }
.ni-meta { font-size: 12px; color: var(--text-3); }
.ni-caret { flex: 0 0 auto; color: var(--text-3); transition: transform .18s; }
.ni-caret svg { width: 16px; height: 16px; display: block; }
.notice-item[open] .ni-caret { transform: rotate(180deg); }
.ni-body { padding: 0 18px 18px 37px; display: flex; flex-direction: column; gap: 12px; }
.ni-content { font-size: 13.5px; line-height: 1.75; color: var(--text-2); }
.ni-content p { margin: 0 0 8px; }
.ni-content img { max-width: 100%; border-radius: var(--radius-sm); }
.ni-img { max-width: 100%; border-radius: var(--radius-sm); border: 1px solid var(--border); }
.ni-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.must-title { font-size: 15.5px; }
.must-badge { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: var(--radius-pill); background: var(--danger-light); color: var(--danger); font-size: 12.5px; font-weight: 600; }
.must-badge svg { width: 15px; height: 15px; }

/* --- 25.9 通知阅读统计 --- */
.read-bar { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 14px 18px; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.read-bar-num { display: flex; flex-direction: column; gap: 2px; }
.read-bar-num b { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; }
.read-bar-num span { font-size: 11.5px; color: var(--text-3); }
.read-bar-num.is-ok b { color: var(--ok); }
.read-bar-num.is-warn b { color: var(--warn); }
.read-bar-track { flex: 1 1 160px; height: 8px; border-radius: var(--radius-pill); background: var(--border); overflow: hidden; min-width: 120px; }
.read-bar-track i { display: block; height: 100%; border-radius: var(--radius-pill); background: linear-gradient(90deg, var(--brand), var(--info)); transition: width .3s; }
.read-bar-pct { font-size: 14px; font-weight: 700; color: var(--brand); font-variant-numeric: tabular-nums; }
.read-mini { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-3); }
.read-mini b { font-variant-numeric: tabular-nums; color: var(--text-2); }

/* --- 25.10 任务卡片（前台任务大厅） --- */
.mission-list { display: flex; flex-direction: column; gap: 12px; }
.mission-item { display: flex; align-items: flex-start; gap: 14px; padding: 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); transition: border-color .16s, box-shadow .16s; }
.mission-item:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.mission-item.is-mine { border-color: var(--brand); background: var(--brand-lighter); }
/* 已完成的任务：整体压暗一档，让它不与"正在进行"抢注意力。
   不要用 opacity —— 那会把里面的徽标颜色一起洗淡，看起来像被禁用了。 */
.mission-item.is-done { background: var(--surface-2); }
.mission-item.is-done .mi-title { color: var(--text-2); font-weight: 500; }

/* 任务大厅的分组分隔线：上面「可报名」，下面「已出发、报名已截止」。
   做成一条带小图标的中缝标题（右侧余量走一条细线），而不是加粗大字 ——
   它是分区提示，不该和任务标题抢视觉层级。 */
.mission-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 2px 0 -2px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-3);
}
.mission-divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}
.mission-divider svg { flex: 0 0 auto; opacity: .72; }
.mi-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.mi-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 15px; font-weight: 600; }
.mi-meta { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap; font-size: 12.5px; color: var(--text-3); }
.mi-note { font-size: 12.5px; color: var(--warn); background: var(--warn-light); border-radius: var(--radius-xs); padding: 7px 10px; }
.mi-thumb { flex: 0 0 92px; width: 92px; height: 68px; border-radius: var(--radius-xs); overflow: hidden; border: 1px solid var(--border); }
.mi-thumb img { width: 100%; height: 100%; object-fit: cover; }
.mi-actions { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; align-items: stretch; min-width: 118px; }
.mi-actions .btn { white-space: nowrap; }
.mission-cover { width: 100%; max-height: 300px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border); }

/* --- 25.11 任务素材 --- */
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
.media-item { position: relative; margin: 0; border-radius: var(--radius-xs); overflow: hidden; border: 1px solid var(--border); background: var(--surface-2); }
.media-item img { display: block; width: 100%; height: 104px; object-fit: cover; }
.media-del { position: absolute; top: 6px; right: 6px; }

/* --- 25.12 任务模板 --- */
.tpl-list { display: flex; flex-direction: column; gap: 10px; }
.tpl-item { display: flex; align-items: flex-start; gap: 12px; padding: 13px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); }
.tpl-item.is-off { opacity: .62; }
.tpl-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.tpl-name { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 14px; font-weight: 600; }
.tpl-desc { font-size: 12.5px; color: var(--text-2); max-height: 44px; overflow: hidden; }
.tpl-actions { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

/* --- 25.13 操作栏 / 表单行 --- */
.action-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; padding: 12px 18px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.attend-row td { vertical-align: middle; }
.attend-row .select, .attend-row .input { min-width: 150px; }

/* --- 25.14 登录方式切换 / 前台导航按钮 --- */
.tabs-inline { justify-content: center; }
.site-nav-cta { background: var(--brand) !important; color: #fff !important; padding: 7px 14px !important; border-radius: var(--radius-pill); font-weight: 600; }
.site-nav-cta:hover { background: var(--brand-dark) !important; }
/* 紧急求助入口：前台导航里用红色突出，遇险时能一眼找到 */
.site-nav-emergency {
  background: var(--danger) !important; color: #fff !important;
  padding: 7px 14px !important; border-radius: var(--radius-pill); font-weight: 700;
}
.site-nav-emergency:hover { background: var(--danger-dark) !important; }

/* --- 25.15 通用弹窗（mustReadModal 等直接使用 .modal） --- */
.modal { background: var(--surface); border-radius: var(--radius); width: 100%; max-width: 560px; max-height: calc(100vh - 60px); overflow: auto; box-shadow: var(--shadow-lg); }

/* --- 25.16 数据大盘 --- */
.todo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 10px; }
.todo-item {
  display: flex; flex-direction: column; gap: 3px; align-items: center;
  padding: 14px 10px; text-align: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); text-decoration: none; color: inherit;
  transition: border-color .16s, box-shadow .16s, background .16s;
}
.todo-item:hover { border-color: var(--brand); box-shadow: var(--shadow-sm); background: var(--surface); }
.todo-item b { font-size: 24px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--text-3); }
.todo-item span { font-size: 12px; color: var(--text-3); }
.todo-item.is-active { border-color: var(--warn-border); background: var(--warn-light); }
.todo-item.is-active b { color: var(--warn); }
.todo-item.is-active span { color: var(--warn-ink); }

/* --- 需求 6：据点信息（队内信息大盘） ---
   一行一处的紧凑清单，刻意不做成卡片网格：据点通常只有个位数，
   网格会把 3 处据点铺成一屏，而这一页已经有二十多张卡了，
   能省一屏就省一屏。地址 / 电话 / 容纳人数都是弱化的灰字，
   一眼先看到的是「哪个据点、什么类型、还没停用」。 */
.fac-list { display: flex; flex-direction: column; gap: 8px; }
.fac-row {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px;
  padding: 8px 10px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface-2);
}
.fac-row.is-off { opacity: .6; }
.fac-row .fac-name { font-weight: 600; font-size: 13px; color: var(--text); }
.fac-row .fac-meta { display: inline-flex; align-items: center; gap: 3px; font-size: 12px; color: var(--text-3); }
.fac-row .fac-meta svg { opacity: .7; }

.chart-list { display: flex; flex-direction: column; gap: 11px; }
.chart-line { display: flex; align-items: center; gap: 10px; }
.cl-label { flex: 0 0 108px; font-size: 12.5px; color: var(--text-2); display: flex; align-items: center; gap: 6px; min-width: 0; }
.cl-label > span:not(.tone-dot):not(.rank-no) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chart-line .bar { flex: 1 1 auto; }
.cl-val { flex: 0 0 auto; font-size: 12.5px; color: var(--text-2); font-variant-numeric: tabular-nums; text-align: right; min-width: 76px; }

/* --- 需求 #64：状态分布行整行可点，点进去看该状态的人员名单 ---
   行本身是 <a>（工作台用块级、看板用 chart-line），统一样式并给悬停反馈。 */
.status-row {
  display: block; text-decoration: none; color: inherit;
  padding: 6px 8px; margin: -6px -8px;
  border-radius: var(--radius-xs);
  transition: background .15s ease;
}
a.status-row:hover { background: var(--brand-lighter); }
a.status-row:hover .sr-go { opacity: 1; transform: translateX(0); }
.sr-go {
  display: inline-flex; align-items: center; color: var(--brand);
  opacity: 0; transform: translateX(-3px); transition: opacity .15s ease, transform .15s ease;
}
/* chart-line 版的 .status-row 仍要保持横向排列 */
.chart-line.status-row { display: flex; align-items: center; gap: 10px; }
/* 触屏设备没有 hover，箭头常显，否则看不出这一行可以点 */
@media (hover: none) {
  .sr-go { opacity: .5; transform: none; }
}

.tone-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; background: var(--border-strong); }
.tone-dot.tone-brand  { background: var(--brand); }
.tone-dot.tone-ok     { background: var(--ok); }
.tone-dot.tone-warn   { background: var(--warn); }
.tone-dot.tone-danger { background: var(--danger); }
.tone-dot.tone-info   { background: var(--info); }
.tone-dot.tone-muted  { background: var(--border-strong); }

.rank-no { width: 17px; height: 17px; border-radius: 50%; flex: 0 0 17px; display: inline-flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 700; background: var(--surface-3); color: var(--text-3); }
.rank-no.is-top { background: var(--warn-light); color: var(--warn); }

.col-chart { display: flex; align-items: flex-end; gap: 12px; height: 168px; padding: 6px 2px 0; }
.col-col { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; justify-content: flex-end; }
.col-bars { display: flex; align-items: flex-end; justify-content: center; gap: 5px; width: 100%; height: 100%; }
.col-bar { display: block; width: 40%; max-width: 26px; min-height: 3px; border-radius: 5px 5px 2px 2px; background: linear-gradient(180deg, var(--brand), var(--brand-dark)); transition: height .5s; }
.col-bar.is-alt { background: linear-gradient(180deg, var(--brand-mid), var(--brand)); }
.col-val { font-size: 11.5px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.col-label { font-size: 11.5px; color: var(--text-3); }

.legend { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 12px; }
.legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-3); }
.legend-dot { width: 10px; height: 10px; border-radius: 3px; background: linear-gradient(180deg, var(--brand), var(--brand-dark)); }
.legend-dot.is-alt { background: linear-gradient(180deg, var(--brand-mid), var(--brand)); }

.mini-list { display: flex; flex-direction: column; gap: 8px; }
.mini-item { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--radius-xs); text-decoration: none; color: inherit; transition: border-color .16s, background .16s; }
.mini-item:hover { border-color: var(--brand); background: var(--brand-lighter); }
.mini-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mini-main .strong { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 900px) {
  .todo-grid { grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); }
  .cl-label { flex-basis: 88px; }
  .cl-val { min-width: 62px; }
  .col-chart { height: 140px; gap: 6px; }
}

@media (max-width: 900px) {
  .grid-main { grid-template-columns: 1fr; }
  .list-row { flex-wrap: wrap; }
  .list-actions { flex-direction: row; flex-wrap: wrap; min-width: 0; width: 100%; }
  .g-actions { width: 100%; }
  /* ★ 需求 #2：上面这一条单独写，恰好踩中下面「任务卡片」那段注释描述的坑 ——
     `.g-actions` 被设成 width:100% 之后，`.group-item` 若不换行，
     flex 会把 `.g-main`（flex:1 1 auto + min-width:0）一路压到 **0 宽**：
     实测 user/groups.php（390 视口）「联勤中心」整段逐字换行成竖排
     （组名 4 行 + 「现 0 人」3 行 + 简介 31 行），卡片被拉到 876px 高，
     只有「申请加入」按钮正常。修法照抄下面那三行 —— 同一族问题，
     同一个文件里早就写过解法，只是漏了这一处。 */
  .group-item { flex-wrap: wrap; gap: 10px; }
  .g-main { flex: 1 1 150px; }
  .g-actions { flex: 1 1 100%; width: 100%; min-width: 0; }

  .tpl-actions { width: 100%; }
  /* ★ 需求 #2：`.tpl-item / .tpl-main / .tpl-actions`（2772/2774/2777 行）与上面
     分组卡片（2666/2669/2672 行）是逐条对应的同一套结构，也同样漏了"容器换行"。
     实测 admin/task_templates.php（390 视口）：10 个模板的 `.tpl-main` 全是 **0 宽**，
     模板名 + 标签（应急预案 / 水域救援 / 紧急出动…）逐字换行成竖排，
     卡片被拉到 552 / 714 / 742px 高，只有右侧「一键发起 / 编辑 / 删除」正常 ——
     这正是用户报的「任务模板底部的一键发起页面错位」。 */
  .tpl-item { flex-wrap: wrap; gap: 10px; }
  .tpl-main { flex: 1 1 150px; }
  .tpl-actions { flex: 1 1 100%; width: 100%; min-width: 0; }
  .member-chip { min-width: 100%; }
  .ni-body { padding-left: 18px; }

  /* ------------------------------------------------------------------
     任务卡片（任务大厅 / 我参与中的任务）
     行内 `.mi-actions` 被设成 width:100% 后，容器若不换行，flex 会把
     `.mi-main`（flex:1 1 auto 且 min-width:0）压缩到 0 宽，
     中文就会逐字换行——看起来像竖排、整张卡片被拉得很长。
     修法：容器允许换行 + 正文给一个最小基准宽，操作区独占一行。
     ------------------------------------------------------------------ */
  .mission-item { flex-wrap: wrap; gap: 12px; }
  .mi-main { flex: 1 1 150px; }
  .mi-thumb { flex: 0 0 76px; width: 76px; height: 56px; }
  .mi-actions { flex: 1 1 100%; width: 100%; min-width: 0; flex-direction: row; flex-wrap: wrap; }
  .mi-actions > form { flex: 1 1 auto; }
  .mi-actions .btn { flex: 1 1 auto; justify-content: center; }

  /* 指标卡里的长数值/长文案不再顶破栅格 */
  .stat { min-width: 0; }
  .stat .stat-label,
  .stat .stat-foot { overflow-wrap: anywhere; }

  /* 手机端把过小的按钮抬到可点面积（≥36px） */
  .btn-sm, .btn.btn-sm { min-height: 36px; }
}

/* --------------------------------------------------------------------------
   26. 打印样式（迎检报表 A4 输出）
   -------------------------------------------------------------------------- */
@media print {
  .sidebar, .topbar, .bottom-nav, .drawer-mask, .no-print,
  .site-head, .site-foot, .hero { display: none !important; }
  body { background: var(--fixed-white); font-size: 12px; }
  .content { padding: 0; }
  .card { border: none; box-shadow: none; margin: 0; }
  .card-head { border-bottom: 2px solid #000; padding: 0 0 8px; }
  .table { min-width: 0; font-size: 11px; }
  .table thead th { background: #F2F2F2 !important; position: static; }
  .print-header { display: block !important; margin-bottom: 14px; }
  .print-header h1 { font-size: 18px; text-align: center; }
  .print-header .print-meta { text-align: center; font-size: 11px; color: #444; }
  table, tr, td, th { page-break-inside: avoid; }
  @page { size: A4; margin: 14mm 12mm; }
}
.print-header { display: none; }
.print-only { display: none; }
@media print { .print-only { display: block; } }

/* --------------------------------------------------------------------------
   26. 下拉菜单（导出格式选择等）
   -------------------------------------------------------------------------- */
.dd { position: relative; display: inline-block; }
.dd > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; gap: 6px;
}
.dd > summary::-webkit-details-marker { display: none; }
.dd > summary::marker { content: ''; }
.dd-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 70;
  min-width: 178px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 2px;
}
.dd-menu a, .dd-menu button {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 10px; border: 0; background: none; border-radius: var(--radius-xs);
  font-size: 13px; color: var(--text); text-align: left; cursor: pointer; font-family: inherit;
}
.dd-menu a:hover, .dd-menu button:hover { background: var(--surface-2); color: var(--brand); }
.dd-menu .dd-tip { padding: 3px 10px 5px; font-size: 11.5px; color: var(--text-3); }
/* 「这条筛选导出时不生效」的提醒。放在菜单最下方，用分隔线跟三个格式按钮分开 ——
   它说的是「别点」而不是「点这个」，混在按钮里容易被顺手点掉。 */
.dd-menu .dd-warn {
  margin-top: 4px; padding: 7px 10px;
  border-top: 1px solid var(--border);
  font-size: 11.5px; line-height: 1.6;
  color: var(--warn-ink, var(--text-2));
  background: var(--warn-light);
  border-radius: var(--radius-xs);
}
.dd-menu hr { border: 0; border-top: 1px solid var(--border); margin: 5px 2px; }

/* 卡片里如果有下拉菜单（「导出为」这类），卡片**不能裁剪**。
   .card 的 overflow:hidden 是为了让内容贴合圆角，但它同样会裁掉绝对定位的
   .dd-menu —— 菜单只露出「导出为」一行，真正要点的三个按钮被整段吃掉，
   界面上就是「导出为」下面一大片空白、按钮点不到。
   只放开含下拉的卡片，其余卡片照旧裁剪，圆角不受影响。
   现代浏览器走 :has()，老浏览器由 app.js 补 has-dd 类兜底。 */
.card:has(.dd),
.card.has-dd { overflow: visible; }

/* 下方空间不够时向上展开（由 app.js 判断后加类） */
.dd-menu.dd-up { top: auto; bottom: calc(100% + 6px); }

/* 移动端：操作按钮区可横向滚动，避免挤压换行 */
@media (max-width: 640px) {
  .topbar-actions { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .topbar-actions::-webkit-scrollbar { display: none; }
}

/* --------------------------------------------------------------------------
   27. 组织通讯录（四级分组树 + 成员资料卡）
   企业微信式体验：分组可逐级展开，成员默认只露姓名，点开才是联系方式
   -------------------------------------------------------------------------- */
.org-toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 2px 0 10px;
}
.org-tree, .org-extra {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  margin-bottom: 16px;
}
.org-extra { margin-top: -6px; }

.org-node > .org-row { border-top: 1px solid var(--border); }
.org-tree > .org-node:first-child > .org-row,
.org-extra > .org-node:first-child > .org-row { border-top: 0; }

.org-row {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 11px 14px; min-height: 46px;
  border: 0; background: none; text-align: left; cursor: pointer;
  font-family: inherit; font-size: 14px; font-weight: 600; color: var(--text);
  transition: background .15s;
}
.org-row:hover { background: var(--surface-2); }
.org-caret {
  display: inline-grid; place-items: center;
  width: 18px; height: 18px; flex: 0 0 18px;
  color: var(--text-3); transition: transform .18s ease;
}
.org-node:not(.is-open) > .org-row .org-caret { transform: rotate(-90deg); }
.org-dot { width: 9px; height: 9px; flex: 0 0 9px; border-radius: 50%; }
.org-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.org-cat { font-weight: 500; flex: 0 0 auto; }
.org-count {
  margin-left: auto; flex: 0 0 auto;
  font-size: 12px; font-weight: 500; color: var(--text-3);
}

.org-body { display: none; padding-bottom: 12px; }
.org-node.is-open > .org-body { display: block; }
.org-desc { padding: 0 14px 8px 41px; font-size: 12px; color: var(--text-3); }
.org-nobody { padding: 0 14px 8px 41px; font-size: 12px; color: var(--text-3); }

/* 下级分组：左侧虚线导轨 + 缩进，层级一目了然 */
.org-kids { margin: 0 12px 8px 27px; border-left: 1px dashed var(--border-strong); }
.org-kids .org-row { padding: 9px 12px; min-height: 42px; font-size: 13.5px; }
.org-kids .org-body { padding-bottom: 8px; }
.org-kids .org-desc, .org-kids .org-nobody { padding-left: 39px; }
.org-kids .org-people { padding-left: 39px; }

.org-people { display: flex; flex-wrap: wrap; gap: 8px; padding: 4px 14px 2px 41px; }
/* 搜索结果等非树形场景：不要左侧缩进 */
.org-people.is-plain { padding-left: 0; padding-right: 0; padding-top: 0; }

/* ---------- 三大中心 / 预备申请组（v2.0 组织架构） ---------- */
.org-node.is-center > .org-row {
  background: linear-gradient(90deg, var(--brand-lighter), transparent 62%);
}
.org-node.is-center > .org-row .org-name { font-size: 14.5px; letter-spacing: .2px; }
.org-node.is-reserve > .org-row { background: var(--warn-light); }
.org-node.is-reserve > .org-row .org-name { color: var(--warn); }
.org-node.is-reserve .org-count { color: var(--warn); font-weight: 600; }

.org-applicants {
  margin: 2px 14px 6px 41px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--warn-light);
  padding: 8px 10px 10px;
}
.org-kids .org-applicants { margin-left: 39px; }
.oa-head {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: var(--warn);
  margin-bottom: 7px;
}
.oa-head svg { flex: 0 0 auto; }
.oa-head .btn { margin-left: auto; }
.oa-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 0;
}
.oa-row + .oa-row { border-top: 1px dashed var(--border); }
.oa-row img {
  width: 24px; height: 24px; flex: 0 0 24px;
  border-radius: 50%; object-fit: cover; border: 1px solid var(--border);
}
.oa-name { font-size: 13px; font-weight: 600; color: var(--text); }
.oa-time { font-size: 11.5px; color: var(--text-3); }
.oa-count {
  font-size: 11.5px; font-weight: 600; color: var(--brand);
  padding: 1px 7px; border-radius: var(--radius-pill);
  background: var(--brand-light);
}
.oa-note {
  flex: 1 1 100%; font-size: 11.5px; color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- 迷你指标条（后台概况卡） ---------- */
.mini-stat { display: flex; flex-wrap: wrap; gap: 10px; }
.ms-item {
  flex: 1 1 110px; min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  text-align: center;
}
.ms-item.is-warn { border-color: var(--warn); background: var(--warn-light); }
.ms-item.is-warn .ms-num { color: var(--warn); }
.ms-num { display: block; font-size: 19px; font-weight: 700; color: var(--text); line-height: 1.2; }
.ms-label { display: block; margin-top: 3px; font-size: 11.5px; color: var(--text-3); }

/* ---------- 时长系数示例 ---------- */
.coef-demo { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; }
.cd-item {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.cd-label { display: block; font-size: 12px; font-weight: 600; color: var(--text-3); }
.cd-formula { display: block; margin: 6px 0 4px; font-size: 14px; color: var(--text-2); }
.cd-formula b { color: var(--text); }
.cd-out { color: var(--brand) !important; font-size: 16px; }
.cd-note { display: block; font-size: 11.5px; color: var(--text-3); }

/* 系数页：主系数 / 非一线角色系数 分组小标题 */
.coef-divider {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin: 16px 0 12px;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
}
.coef-divider > span { font-size: 13px; font-weight: 600; color: var(--text); }
.coef-divider > em { font-size: 11.5px; font-style: normal; color: var(--text-3); }
.tag-mini {
  display: inline-block; margin-left: 2px;
  padding: 0 5px;
  font-size: 10.5px; font-weight: 500;
  line-height: 15px;
  color: var(--text-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  vertical-align: 1px;
}

/* ---------- 表头 / 表尾强调（年度合计行等） ---------- */
.table tfoot td {
  background: var(--surface-2);
  font-weight: 600;
  border-top: 2px solid var(--border-strong);
}

/* ---------- 行内审核表单 ---------- */
.inline-review { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.inline-review .input-sm { max-width: 150px; }

/* ---------- 折叠的原始数据（删除快照等） ---------- */
.raw-details { display: inline-block; text-align: left; }
.raw-details > summary {
  cursor: pointer; font-size: 12px; font-weight: 600; color: var(--brand);
  padding: 3px 8px; border: 1px solid var(--border); border-radius: var(--radius-xs);
  background: var(--surface); list-style: none;
}
.raw-details > summary::-webkit-details-marker { display: none; }
.raw-details[open] > summary { background: var(--brand-light); border-color: var(--brand); }
.raw-details > pre {
  margin: 6px 0 0; max-width: 460px; max-height: 260px; overflow: auto;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-xs);
  background: var(--surface-2); color: var(--text-2);
  font-family: var(--mono); font-size: 11.5px; line-height: 1.55;
  white-space: pre-wrap; word-break: break-all;
}
.org-person {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 12px 5px 5px; min-height: 38px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--text);
  font-family: inherit; font-size: 13px; cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s, transform .15s;
}
.org-person:hover {
  border-color: var(--brand); background: var(--brand-lighter);
  box-shadow: var(--shadow-sm); transform: translateY(-1px);
}
.org-person img {
  width: 26px; height: 26px; flex: 0 0 26px;
  border-radius: 50%; object-fit: cover; border: 1px solid var(--border);
}
.op-name { font-weight: 600; white-space: nowrap; }
.op-tag { font-size: 11px; color: var(--text-3); white-space: nowrap; }

/* --- 成员资料卡（桌面右侧抽屉 / 手机底部半屏） --- */
.sheet-mask {
  position: fixed; inset: 0; z-index: 120;
  background: rgba(12, 42, 97, .42);
  -webkit-backdrop-filter: blur(1px);
  backdrop-filter: blur(1px);
}
.sheet-mask[hidden] { display: none; }

.contact-sheet {
  position: fixed; top: 0; right: 0; z-index: 130;
  width: min(404px, 94vw); height: 100%;
  display: flex; flex-direction: column;
  background: var(--surface); box-shadow: var(--shadow-lg);
  transform: translateX(103%);
  transition: transform .24s ease;
}
.contact-sheet.is-open { transform: translateX(0); }

.cs-head {
  position: relative; padding: 26px 20px 18px;
  background: linear-gradient(158deg, var(--brand-darker), var(--brand-dark) 55%, var(--brand));
  color: #fff;
}
.cs-avatar {
  width: 64px; height: 64px; border-radius: 50%; object-fit: cover;
  border: 2px solid rgba(255, 255, 255, .72); background: rgba(255, 255, 255, .2);
}
.cs-name { margin-top: 10px; font-size: 19px; font-weight: 700; color: #fff; }
.cs-sub { font-size: 12.5px; color: #CFE0F8; }
.cs-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.cs-tag {
  padding: 2px 9px; border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .18); font-size: 11.5px; color: #fff;
}
.cs-close {
  position: absolute; top: 10px; right: 12px;
  width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .16); color: #fff;
  font-size: 20px; line-height: 1;
}
.cs-close:hover { background: rgba(255, 255, 255, .3); }

.cs-body { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch; padding-bottom: 12px; }
.cs-row {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 18px; border-bottom: 1px solid var(--border);
}
.cs-k { flex: 0 0 72px; font-size: 12.5px; color: var(--text-3); }
.cs-v { flex: 1 1 auto; min-width: 0; font-size: 13.5px; word-break: break-word; }
.cs-v a { color: var(--brand); font-weight: 600; }
.cs-v .cs-blank { color: var(--text-3); font-size: 12.5px; }
.cs-act { flex: 0 0 auto; }
.cs-sec {
  display: flex; align-items: center; gap: 8px;
  padding: 14px 18px 6px; font-size: 12px; color: var(--text-3);
}
.cs-group { display: flex; align-items: flex-start; gap: 9px; padding: 9px 18px; }
.cs-group .cg-dot { width: 8px; height: 8px; margin-top: 7px; flex: 0 0 8px; border-radius: 50%; background: var(--brand); }
.cs-group .cg-txt { min-width: 0; display: block; }
.cs-group .cg-name { display: block; font-size: 13.5px; font-weight: 600; }
.cs-group .cg-path { display: block; font-size: 11.5px; color: var(--text-3); }
.cs-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; margin: 6px 18px 0; background: var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.cs-stat { padding: 10px 6px; background: var(--surface); text-align: center; }
.cs-stat b { display: block; font-size: 17px; color: var(--brand-dark); }
.cs-stat span { font-size: 11.5px; color: var(--text-3); }
.cs-foot { flex: 0 0 auto; display: flex; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--border); }
.cs-foot .btn { flex: 1 1 auto; justify-content: center; }

/* --------------------------------------------------------------------------
   28. 任务简报 / 现场进展 / 指挥大盘
   -------------------------------------------------------------------------- */

/* 两列信息网格（沿用 .kv 的 dt/dd 结构） */
.kv.kv-2 { grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr); }

/* 复选框行：整行可点，触控区域足够大 */
.switch-line {
  display: flex; align-items: center; gap: 9px;
  font-size: 13.5px; color: var(--text); cursor: pointer;
  min-height: 34px;
}
.switch-line input[type=checkbox] { width: 17px; height: 17px; flex: 0 0 17px; accent-color: var(--brand); margin: 0; cursor: pointer; }
.switch-line span { line-height: 1.5; }
/* 把勾选行做成按钮外观，用在表单页脚 */
.switch-line.btn-like {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0 12px; background: var(--surface); color: var(--text-2);
}
.switch-line.btn-like:hover { border-color: var(--brand); color: var(--brand); }

.is-hidden { display: none !important; }

/* 内联折叠（details 包裹正文，不用浮层，手机端也稳） */
.dd-inline > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 5px; }
.dd-inline > summary::-webkit-details-marker { display: none; }
.dd-inline[open] > summary { margin-bottom: 4px; }

/* 现场进展时间线：竖线 + 圆点，最新在最上 */
.log-timeline { position: relative; padding-left: 4px; }
.log-item { display: flex; gap: 12px; padding-bottom: 16px; position: relative; }
.log-item:last-child { padding-bottom: 0; }
.log-item::before {
  content: ''; position: absolute; left: 5px; top: 16px; bottom: 0;
  width: 2px; background: var(--border);
}
.log-item:last-child::before { display: none; }
.log-item .li-dot {
  flex: 0 0 12px; width: 12px; height: 12px; margin-top: 4px;
  border-radius: 50%; background: var(--brand); border: 2px solid var(--surface);
  box-shadow: 0 0 0 2px var(--brand-lighter); position: relative; z-index: 1;
}
.log-item.is-notice .li-dot { background: var(--warn, #D97706); box-shadow: 0 0 0 2px #FEF3C7; }
.log-item .li-body { min-width: 0; flex: 1 1 auto; }
.log-item .li-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.log-item .li-txt { font-size: 13.5px; color: var(--text); line-height: 1.65; margin-top: 5px; word-break: break-word; }
.log-item .li-shot { margin-top: 8px; }
.log-item .li-shot img {
  max-width: 100%; width: auto; max-height: 240px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); cursor: zoom-in; display: block;
}

/* 指挥大盘：左侧任务轨 + 右侧信息栏 */
.cmd-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: start; }
.cmd-side { display: flex; flex-direction: column; gap: 16px; position: sticky; top: calc(var(--topbar-h, 60px) + 14px); }
.cmd-pick { display: flex; gap: 8px; overflow-x: auto; padding: 2px 0 6px; }
.cmd-pick a {
  flex: 0 0 auto; border: 1px solid var(--border); border-radius: 20px;
  padding: 5px 13px; font-size: 13px; color: var(--text-2); background: var(--surface); white-space: nowrap;
}
.cmd-pick a.active { border-color: var(--brand); background: var(--brand); color: #fff; font-weight: 600; }
/* 需求 #78-12h：进行中任务默认只列 3 个，余下的由这个"展开"按钮放出来。
   做成和任务胶囊同高同形的样子，展开后整条读起来还是一排任务，
   而不是"一排任务 + 一个突兀的按钮"。 */
.cmd-pick .cmd-pick-more {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px;
  border: 1px dashed var(--border); border-radius: 20px;
  padding: 5px 12px; font-size: 12.5px; color: var(--text-3);
  background: transparent; cursor: pointer; white-space: nowrap;
}
.cmd-pick .cmd-pick-more:hover { border-color: var(--brand); color: var(--brand); }
.cmd-pick .cmd-pick-more[data-open="1"] svg { transform: rotate(180deg); }
.cmd-live { font-size: 12.5px; color: var(--text-3); }
.cmd-live .dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--ok, #16A34A); margin-right: 5px; }

/* 任务操作条 */
.cmd-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 10px; }
.cmd-actions form { margin: 0; }

/* 迷你指标卡（人力分布） */
.stat-mini-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.stat-mini {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 9px 4px; text-align: center; background: var(--surface-2);
}
.stat-mini b { display: block; font-size: 19px; font-weight: 700; color: var(--text); line-height: 1.2; }
.stat-mini span { font-size: 11.5px; color: var(--text-3); }
.stat-mini.is-ok b { color: var(--ok); }
.stat-mini.is-brand b { color: var(--brand); }
.stat-mini.is-warn b { color: var(--warn); }

/* 人员小标签：可叫应名单 / 报名名单 */
.mini-people { display: flex; flex-wrap: wrap; gap: 6px; }
.mini-person {
  display: inline-flex; align-items: baseline; gap: 5px;
  border: 1px solid var(--border); border-radius: 20px;
  padding: 4px 11px; font-size: 13px; color: var(--text); background: var(--surface);
  text-decoration: none; min-height: 30px; line-height: 22px;
}
.mini-person span { font-size: 11px; color: var(--text-3); }
a.mini-person:hover { border-color: var(--brand); color: var(--brand); }
.mini-person.is-cmd { border-color: var(--brand); background: var(--brand-lighter); font-weight: 600; }

/* 垂直按钮组（侧栏快捷操作） */
.btn-stack { display: flex; flex-direction: column; gap: 8px; }
.btn-stack .btn { justify-content: center; }

/* 带按钮的提示条 */
.alert-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }

@media (max-width: 1100px) {
  .cmd-layout { grid-template-columns: minmax(0, 1fr); }
  .cmd-side { position: static; }
}

@media (max-width: 640px) {
  .kv.kv-2 { grid-template-columns: auto minmax(0, 1fr); }
  .log-item { gap: 9px; }
  .log-item .li-shot img { max-height: 200px; }
  /* 任务胶囊条：手机上换行铺开，避免横向滚动把后面的任务藏起来 */
  .cmd-pick { flex-wrap: wrap; overflow-x: visible; }
  .cmd-pick a { flex: 1 1 auto; text-align: center; white-space: normal; min-width: 0; }
  .cmd-pick .cmd-pick-more { flex: 1 1 auto; justify-content: center; }
}

/* --------------------------------------------------------------------------
   29. 对外公告与声明（前台公开页）
   -------------------------------------------------------------------------- */

/* 窄栏容器：公告正文阅读宽度更舒适 */
.wrap-narrow { max-width: 880px; margin: 0 auto; padding: 0 16px; }

.crumb-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--text-3); padding: 18px 0 14px;
}
.crumb-bar a { color: var(--text-3); }
.crumb-bar a:hover { color: var(--brand); }

.announce-detail .card-body { padding: 28px clamp(18px, 4vw, 40px) 24px; }
.an-head { display: flex; gap: 8px; flex-wrap: wrap; }
.an-title {
  font-size: clamp(20px, 2.6vw, 27px); line-height: 1.4; margin: 12px 0 10px;
  color: var(--text); letter-spacing: .3px;
}
.an-meta {
  display: flex; flex-wrap: wrap; gap: 6px 20px;
  font-size: 12.5px; color: var(--text-3);
  padding-bottom: 16px; border-bottom: 1px dashed var(--border);
}
.an-meta span { display: inline-flex; align-items: center; gap: 5px; }
.an-meta svg { width: 14px; height: 14px; }
.an-cover { margin: 20px 0 4px; }
.an-cover img { width: 100%; border-radius: var(--radius-sm); border: 1px solid var(--border); display: block; }
.an-body { margin-top: 18px; font-size: 15px; line-height: 2; color: var(--text-2); }
.an-body p { margin: 0 0 1em; }
.an-body img { max-width: 100%; border-radius: var(--radius-sm); }
.an-body strong { color: var(--text); }
.an-link { margin-top: 22px; }
.an-foot { margin-top: 26px; padding-top: 14px; border-top: 1px dashed var(--border); }

.an-others { list-style: none; margin: 0; padding: 0; }
.an-others li {
  display: flex; align-items: baseline; gap: 12px; justify-content: space-between;
  padding: 9px 0; border-bottom: 1px dashed var(--border);
}
.an-others li:last-child { border-bottom: none; }
.an-others a { color: var(--text); font-size: 14px; }
.an-others a:hover { color: var(--brand); }
.an-back { padding: 18px 0 40px; }

/* 列表页 */
.an-filters { display: flex; flex-wrap: wrap; gap: 8px; }
.an-top { border-left: 4px solid var(--brand); }
.an-top-title { font-size: clamp(17px, 2vw, 21px); margin: 10px 0 8px; line-height: 1.45; }
.an-top-title a { color: var(--text); }
.an-top-title a:hover { color: var(--brand); }
.an-top-sum { font-size: 14px; line-height: 1.8; color: var(--text-2); margin: 0 0 12px; }

.an-list { list-style: none; margin: 0; padding: 0; }
.an-list > li { border-bottom: 1px solid var(--border); }
.an-list > li:last-child { border-bottom: none; }
.an-item {
  display: flex; align-items: center; gap: 14px; padding: 16px 18px;
  text-decoration: none; color: inherit; transition: background .15s;
}
.an-item:hover { background: var(--surface-2); }
.an-thumb { flex: 0 0 82px; }
.an-thumb img { width: 82px; height: 60px; object-fit: cover; border-radius: var(--radius-xs); border: 1px solid var(--border); display: block; }
.an-main { flex: 1 1 auto; min-width: 0; display: block; }
.an-item-title { display: block; font-size: 15px; font-weight: 600; color: var(--text); line-height: 1.5; }
.an-item-sum {
  font-size: 13px; color: var(--text-3); margin-top: 4px; line-height: 1.6;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.an-item-meta { display: block; font-size: 12px; color: var(--text-3); margin-top: 6px; }
.an-go { flex: 0 0 auto; color: var(--text-3); }
.an-item:hover .an-go { color: var(--brand); }

@media (max-width: 640px) {
  .an-thumb { display: none; }
  .an-item { padding: 14px; gap: 10px; }
  .an-item-title { font-size: 14.5px; }
  .an-body { font-size: 14.5px; line-height: 1.9; }
}


@media (max-width: 640px) {
  .org-people { padding-left: 20px; }
  .org-kids .org-people { padding-left: 22px; }
  .org-kids { margin-left: 14px; }
  .org-desc, .org-nobody { padding-left: 30px; }
  .contact-sheet {
    top: auto; bottom: 0; right: 0; left: 0;
    width: 100%; height: min(86vh, 620px);
    border-radius: var(--radius) var(--radius) 0 0;
    transform: translateY(103%);
  }
  .contact-sheet.is-open { transform: translateY(0); }
}

/* --------------------------------------------------------------------------
   31. 移动端触控可用性兜底
   手机上 .btn-sm / .btn-xs 原始高度约 26~29px，低于「可点区域 ≥32px」的通行下限，
   在列表行里密集排列时容易点错。这里统一抬到 32px（只影响触屏宽度，桌面保持紧凑）。
   注意：用 min-height 而不是加大 padding，避免把已有布局撑变形。
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .btn-sm, .btn-xs { min-height: 32px; padding-top: 5px; padding-bottom: 5px; }
  .btn-xs { font-size: 12px; }
  /* 表内操作按钮组：允许换行，避免挤压成极窄的竖条 */
  .btn-group { flex-wrap: wrap; }
  /* 纯文字链接做成可点区域（通讯录、公告列表里的 a） */
  .an-others li { padding: 11px 0; }
  /* 筛选胶囊：默认 28px，抬到 32px */
  .chip { min-height: 32px; padding-top: 5px; padding-bottom: 5px; }
  /* 电话链接（求救记录、通讯录里可直接拨号的号码）：16px 高的行内文字太难点中 */
  .kv dd > a[href^="tel:"], .sai-txt a[href^="tel:"] {
    display: inline-flex; align-items: center; min-height: 32px; padding: 0 2px;
  }
  /* 弹窗关闭按钮 */
  .sa-close, .alert-close { min-width: 34px; min-height: 34px; display: inline-flex; align-items: center; justify-content: center; }
}

/* --------------------------------------------------------------------------
   32. 队员工作台（志愿者登录后的首页 · 需求 #6）
   -------------------------------------------------------------------------- */

/* ── 工作台任务区 ──────────────────────────────────────────────────────
   摆在页面最顶部：志愿者登录后第一眼要看到"现在有什么事要我处理"。
   配色刻意与下面的白色卡片区分开（浅品牌底 + 品牌边框），
   让它在手机上"一眼就是另一块"，不用读标题也知道这里是重点。 */
.workbench {
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  background: var(--brand-lighter);
  padding: 12px;
  margin-bottom: 16px;
}
.wb-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 10px; padding: 0 2px;
}
.wb-title {
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 700; font-size: 14.5px; color: var(--brand-dark);
}
.wb-more {
  margin-left: auto; font-size: 12.5px; color: var(--brand-dark);
  text-decoration: none; display: inline-flex; align-items: center; gap: 2px;
}
.wb-more:hover { text-decoration: underline; }

/* 分组小标题：把「我参与中的任务」和「可以报名的任务」两摞卡片分开。
   原先只靠卡片左侧色条区分，新人看不出这两摞到底差在哪，所以补一行明确文字。
   `.wb-card + .wb-sec` 给"上一摞的最后一张卡"与下一组标题之间留出呼吸。 */
.wb-sec { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin: 0 2px 7px; }
.wb-card + .wb-sec { margin-top: 12px; }
.wb-sec-t { font-size: 13px; font-weight: 600; color: var(--brand-dark); }
.wb-sec-h { font-size: 11.5px; color: var(--text-3); }

.wb-card {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 11px 12px; margin-bottom: 9px;
}
.wb-card:last-child { margin-bottom: 0; }
/* 我参与中的任务用左侧色条标出来 —— 这类有"我的责任"在里面，优先看 */
.wb-card.is-mine { border-left: 3px solid var(--brand); }
.wb-card.is-open { border-left: 3px solid var(--border); }
a.wb-card:hover { border-color: var(--brand); box-shadow: var(--shadow-sm); }
.wb-card.is-empty {
  display: flex; align-items: flex-start; gap: 10px;
  color: var(--text-3); font-size: 13px;
}
.wb-card.is-empty b { display: block; color: var(--text-2); font-size: 13.5px; margin-bottom: 3px; }
.wb-card.is-empty span { line-height: 1.6; }
.wb-empty-ico {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ok-light); color: var(--ok);
}
.wb-card.is-warn { border-left: 3px solid var(--warn); }

.wb-row1 { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.wb-name { font-weight: 600; font-size: 14.5px; }
.wb-meta {
  display: flex; flex-wrap: wrap; gap: 4px 14px;
  margin-top: 6px; font-size: 12px; color: var(--text-3);
}
.wb-meta > span { display: inline-flex; align-items: center; gap: 4px; }

/* 最新一条现场进展：工作台要能"看到任务在动"，而不只是一个标题 */
.wb-progress {
  margin-top: 9px; padding: 7px 9px;
  background: var(--surface-3); border-radius: var(--radius-xs);
  font-size: 12.5px; line-height: 1.6;
}
.wb-progress.is-none { color: var(--text-3); font-size: 12px; }
.wb-log { display: block; color: var(--text-2); }
.wb-log i {
  font-style: normal; margin-right: 6px; padding: 0 5px;
  border-radius: 3px; background: var(--brand-lighter);
  color: var(--brand-dark); font-size: 11.5px;
}
.wb-log em { font-style: normal; color: var(--text-3); }
.wb-log time { color: var(--text-3); margin-left: 6px; font-size: 11.5px; }
.wb-log-more { display: inline-block; margin-top: 3px; font-size: 11.5px; color: var(--text-3); }
.wb-acts { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.wb-warn {
  display: flex; align-items: flex-start; gap: 9px;
  color: var(--warn-ink); font-size: 13px; line-height: 1.6;
}

@media (max-width: 760px) {
  .workbench { padding: 10px; margin-bottom: 13px; }
  .wb-card { padding: 10px 11px; }
  /* 触屏：报名/详情按钮的视觉高度只有 32px 左右，手指点不准。
     垫一层 44px 高的透明命中区（外观不变、命中达标）。 */
  .wb-acts .btn { position: relative; }
  .wb-acts .btn::after {
    content: ""; position: absolute; left: 0; right: 0; top: 50%;
    transform: translateY(-50%); height: 44px;
  }
  .wb-more { min-height: 32px; display: inline-flex; align-items: center; }
}

.panel-hero {
  background: linear-gradient(135deg, var(--brand-darker), var(--brand));
  color: #fff; border-radius: var(--radius); padding: 20px;
  margin-bottom: 16px; box-shadow: var(--shadow);
}
.pnl-top { display: flex; align-items: center; gap: 13px; }
.pnl-avatar {
  width: 56px; height: 56px; border-radius: 50%; object-fit: cover;
  border: 2px solid rgba(255,255,255,.45); flex: 0 0 56px; background: var(--fixed-white);
}
.pnl-me { min-width: 0; flex: 1 1 auto; }
.pnl-name { font-size: 19px; font-weight: 700; }
.pnl-sub { font-size: 12.5px; opacity: .85; margin-top: 3px; }
.pnl-status { flex: 0 0 auto; }
.pnl-status.badge { background: rgba(255,255,255,.2); color: #fff; }

.pnl-meta {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
  margin-top: 16px; padding-top: 15px; border-top: 1px solid rgba(255,255,255,.2);
}
.pnl-meta-item { text-align: center; }
.pnl-meta-item b { display: block; font-size: 20px; font-weight: 800; font-variant-numeric: tabular-nums; }
.pnl-meta-item span { font-size: 11.5px; opacity: .82; }
.pnl-vac {
  margin-top: 13px; padding: 8px 12px; border-radius: var(--radius-sm);
  background: rgba(255,255,255,.16); font-size: 12.5px;
}

/* 状态切换按钮（.status-picker / .status-btn）的样式已删除 ——
   需求 #1 / #20c 把打卡改成「点一下就提交」的一键式之后，
   个人工作台不再输出这套「先选、再点确认」的两步式控件，
   相关 HTML 与 JS 一并移除，样式留着就是死代码。
   新组件（.sq-*）的样式见本文件末尾「快捷在岗打卡」一节。 */

/* 出勤预览 */
.attend-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.attend-cell {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 16px 8px; text-align: center; background: var(--surface-2);
}
.attend-cell .ac-val { font-size: 27px; font-weight: 800; color: var(--brand-dark); line-height: 1.15; font-variant-numeric: tabular-nums; }
.attend-cell .ac-val small { font-size: 13px; font-weight: 600; margin-left: 2px; }
.attend-cell .ac-lbl { font-size: 13px; color: var(--text-2); margin-top: 4px; }
.attend-cell .ac-hours { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }

/* 待办列表（工作台专属）
   为什么用 wb-todo-* 而不是沿用 .todo-item：
   `.todo-item` 在第 25 节「数据大盘」里已被用作**竖排数字卡**
   （flex-direction: column; align-items: center; background: var(--surface-2)）。
   两处语义完全不同，共用类名会让 column / 居中 / 灰底全部继承过来 ——
   待办行被撑成 140px 高、箭头掉到右下角、文字居中。
   与其在每一条新规则里逐个显式覆盖，不如换成专属类名：以后谁改数据大盘都不会误伤这里。 */
.wb-todo { display: flex; flex-direction: column; gap: 10px; }
.wb-todo-item {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface);
  text-decoration: none; color: inherit; text-align: left;
  min-height: 56px; transition: all .15s;
}
.wb-todo-item:hover { border-color: var(--brand); background: var(--brand-lighter); }
.wb-todo-item > svg:last-child { flex: 0 0 auto; color: var(--text-3); }
.wb-td-ico {
  flex: 0 0 36px; width: 36px; height: 36px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--brand);
}
.wb-td-ico.is-ok { background: var(--ok-light); color: var(--ok); }
.wb-td-ico.is-warn { background: var(--warn-light); color: var(--warn); }
.wb-td-ico.is-brand { background: var(--brand-light); color: var(--brand); }
.wb-td-txt { flex: 1 1 auto; min-width: 0; }
.wb-td-txt b { display: block; font-size: 14.5px; }
.wb-td-txt span { display: block; font-size: 12px; color: var(--text-3); margin-top: 2px; }

/* 功能宫格 */
.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
.tile {
  display: flex; flex-direction: column; gap: 3px; padding: 15px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); text-decoration: none; color: inherit;
  min-height: 96px; transition: all .15s;
}
.tile:hover { border-color: var(--brand); background: var(--brand-lighter); transform: translateY(-1px); }
.tile-ico {
  width: 38px; height: 38px; border-radius: 11px; margin-bottom: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-light); color: var(--brand);
}
.tile-lbl { font-size: 14.5px; font-weight: 600; }
.tile-desc { font-size: 11.5px; color: var(--text-3); }

@media (max-width: 640px) {
  .panel-hero { padding: 17px 15px; }
  .pnl-meta { grid-template-columns: repeat(2, 1fr); gap: 12px 8px; }
  .attend-grid { gap: 9px; }
  .attend-cell { padding: 13px 5px; }
  .attend-cell .ac-val { font-size: 23px; }
  .tile-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .tile { min-height: 92px; padding: 13px 12px; }
}

/* 被禁用的单选卡（如「任务中」由系统自动标记，不允许手动切换） */
.radio-card.is-locked { opacity: .6; cursor: not-allowed; }
.radio-card.is-locked:hover { border-color: var(--border); transform: none; }

/* 个人主页头像：点一下原地放大，再点恢复 */
.ph-avatar.ph-zoomable { cursor: zoom-in; transition: transform .25s ease, box-shadow .25s ease; }
.ph-avatar.ph-zoomable:hover { box-shadow: 0 0 0 3px rgba(29,95,208,.18); }
.ph-avatar.ph-zoomable.is-zoomed {
  transform: scale(2.35); cursor: zoom-out; z-index: 60; position: relative;
  box-shadow: 0 14px 40px rgba(12,20,34,.35);
}
@media (max-width: 640px) {
  .ph-avatar.ph-zoomable.is-zoomed { transform: scale(1.9); }
}

/* --------------------------------------------------------------------------
   34. 前台数据看板（榜单 / 分布条）
   -------------------------------------------------------------------------- */

.board-overview {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-bottom: 16px;
}
.bo-item {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 18px 10px; text-align: center;
}
.bo-item b {
  display: block; font-size: 26px; font-weight: 800; color: var(--brand-dark);
  line-height: 1.15; font-variant-numeric: tabular-nums;
}
.bo-item span { font-size: 12.5px; color: var(--text-3); }

.board-2col { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-bottom: 16px; align-items: start; }

/* 活跃度对比 */
.active-cmp { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.ac-col {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 16px 8px; text-align: center; background: var(--surface-2);
}
.ac-col .acv { font-size: 26px; font-weight: 800; color: var(--brand-dark); line-height: 1.15; font-variant-numeric: tabular-nums; }
.ac-col .acv small { font-size: 12px; font-weight: 600; margin-left: 3px; }
.ac-col .acv.up { color: var(--ok); }
.ac-col .acv.down { color: var(--danger); }
.ac-col .acl { font-size: 13px; color: var(--text-2); margin-top: 4px; }
.ac-col .ach { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }

/* 排行榜 */
.rank-list { display: flex; flex-direction: column; }
.rank-row {
  display: flex; align-items: center; gap: 11px; padding: 10px 16px;
  text-decoration: none; color: inherit; border-bottom: 1px solid var(--border);
  min-height: 54px; transition: background .15s;
}
.rank-row:last-child { border-bottom: none; }
.rank-row:hover { background: var(--brand-lighter); }
.rk-no {
  flex: 0 0 24px; width: 24px; height: 24px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700; color: var(--text-3);
  background: var(--surface-2); border: 1px solid var(--border);
}
.rk-no.is-top1 { background: #FFD34D; color: #6B4A00; border-color: #F0C33C; }
.rk-no.is-top2 { background: #D8E0EC; color: #46536B; border-color: #C6D0DE; }
.rk-no.is-top3 { background: #F0C79B; color: #6E4416; border-color: #E2B784; }
.rk-avatar { flex: 0 0 34px; width: 34px; height: 34px; border-radius: 50%; object-fit: cover; background: var(--surface-2); }
.rk-main { flex: 1 1 auto; min-width: 0; }
.rk-name { display: flex; align-items: baseline; gap: 7px; font-size: 14px; font-weight: 600; }
.rk-role { font-size: 11.5px; color: var(--text-3); font-weight: 400; }
.rk-bar { display: block; height: 5px; border-radius: 4px; background: var(--border); margin-top: 6px; overflow: hidden; }
.rk-bar i { display: block; height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--brand), var(--brand-mid)); }
.rk-val { flex: 0 0 auto; font-size: 16px; font-weight: 800; color: var(--brand-dark); font-variant-numeric: tabular-nums; }
.rk-val small { font-size: 11px; font-weight: 600; color: var(--text-3); margin-left: 2px; }

/* 分布条 */
.bar-list { display: flex; flex-direction: column; gap: 12px; }
.bar-row { display: flex; align-items: center; gap: 11px; font-size: 13px; }
.br-lbl { flex: 0 0 88px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.br-track { flex: 1 1 auto; height: 9px; border-radius: 5px; background: var(--border); overflow: hidden; }
.br-track i { display: block; height: 100%; border-radius: 5px; background: linear-gradient(90deg, var(--brand), var(--brand-mid)); }
.br-track.is-ok i { background: linear-gradient(90deg, var(--ok), #4ED08A); }
.br-val { flex: 0 0 54px; text-align: right; color: var(--text-3); font-variant-numeric: tabular-nums; }

.board-foot { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; padding: 8px 0 10px; }

/* 看板筛选条（年份 / TOP 人数） */
.board-filter {
  display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: center;
  padding: 12px 16px; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.bf-group { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.bf-label { font-size: 12.5px; color: var(--text-3); margin-right: 2px; }
.bf-chip {
  display: inline-flex; align-items: center; height: 30px; padding: 0 13px;
  border-radius: 15px; border: 1px solid var(--border); background: var(--surface-2);
  font-size: 13px; color: var(--text-2); text-decoration: none; white-space: nowrap;
  transition: all .15s;
}
.bf-chip:hover { border-color: var(--brand); color: var(--brand); }
.bf-chip.is-on {
  background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600;
  box-shadow: 0 3px 10px rgba(29,95,208,.28);
}
/* 原先按年度查看时的「N 年任务数 / N 年任务时长(h)」两张卡额外套了一层品牌色
   强调（.bo-item.is-brand：蓝边框 + 淡蓝底，数字用 --brand-dark）。用户在看板上
   一眼数出 7 张卡里只有这两张颜色不一样，问「为啥加了蓝色边框，用不到就删掉」——
   于是去掉：7 项指标口径不同但地位相同，人为挑两项高亮反而让人误以为
   只有这两项是重点。数字本身的字号与颜色（.bo-item b）已经足够醒目。
   HTML 里的 is-brand 类名也一并删了，避免留一个没有样式的死类。 */

.board-note {
  display: flex; gap: 8px; align-items: flex-start;
  font-size: 12.5px; line-height: 1.7; color: var(--text-3);
  background: var(--brand-lighter); border: 1px solid var(--brand-light, var(--border));
  border-radius: var(--radius-sm); padding: 11px 14px; margin: 0 0 14px;
}
.board-note svg { flex: 0 0 auto; margin-top: 3px; color: var(--brand); }

/* 任务类型标记 */
.tt-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 6px; vertical-align: middle;
}
.tt-tag {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 8px;
  font-size: 10.5px; font-style: normal; font-weight: 700; vertical-align: middle;
}
.tt-tag.is-rescue { background: rgba(214,60,60,.12); color: var(--danger); }
.br-track.is-danger i { background: linear-gradient(90deg, var(--danger), #F07A7A); }
/* TOP100 长榜：压紧行高，避免页面过长 */
.rank-list.is-long .rank-row { padding: 7px 16px; min-height: 44px; }
.rank-list.is-long .rk-avatar { flex-basis: 28px; width: 28px; height: 28px; }
.rank-list.is-long .rk-name { font-size: 13px; }
.rank-list.is-long .rk-val { font-size: 14px; }
.rank-list.is-long .rk-bar { height: 4px; }

/* 核验页提示数据 */
.verify-hint {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 18px;
}
.vh-item {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 15px 8px; text-align: center; background: var(--surface-2);
}
.vh-item b { display: block; font-size: 23px; font-weight: 800; color: var(--brand-dark); font-variant-numeric: tabular-nums; }
.vh-item span { font-size: 12.5px; color: var(--text-3); }

@media (max-width: 900px) {
  .board-2col { grid-template-columns: minmax(0, 1fr); }
  .board-overview { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .board-overview { grid-template-columns: repeat(2, 1fr); gap: 9px; }
  .bo-item { padding: 14px 8px; }
  .bo-item b { font-size: 21px; }
  .active-cmp { gap: 9px; }
  .ac-col { padding: 13px 5px; }
  .ac-col .acv { font-size: 21px; }
  .rank-row { padding: 9px 13px; gap: 9px; min-height: 50px; }
  .rk-avatar { flex-basis: 30px; width: 30px; height: 30px; }
  .rk-role { display: none; }
  .br-lbl { flex-basis: 70px; font-size: 12.5px; }
  .br-val { flex-basis: 50px; font-size: 12px; }
  .verify-hint { gap: 9px; }
  .vh-item { padding: 12px 6px; }
  .vh-item b { font-size: 20px; }
}

/* --------------------------------------------------------------------------
   35. 顶栏快捷区 / 返回首页 / Logo 原样展示 / 前官网入口
   -------------------------------------------------------------------------- */

/* 顶栏回到后台首页的按钮 */
.topbar-home {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-2); background: var(--surface-2); border: 1px solid var(--border);
  transition: all .15s;
}
.topbar-home:hover { color: var(--brand); border-color: var(--brand); background: var(--brand-lighter); }
.topbar-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.tt-txt { min-width: 0; }

/* 右上角快捷区：任务 / 通知 / 求救 一步直达 */
.top-quick { display: flex; align-items: center; gap: 6px; }
.tq-item {
  position: relative;
  display: inline-flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 11px; border-radius: 9px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-2); font-size: 13px; text-decoration: none;
  transition: all .15s; white-space: nowrap;
}
.tq-item:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-lighter); }
.tq-item.is-active { border-color: var(--brand); background: var(--brand-lighter); color: var(--brand-dark); font-weight: 600; }
.tq-item.is-danger { color: var(--danger); border-color: var(--danger-border); background: var(--danger-light); }
.tq-item.is-danger:hover { background: #FBDDDD; color: var(--danger); }
.tq-badge {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 9px;
  background: var(--danger); color: #fff; font-size: 10.5px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; line-height: 1;
}
.tq-item.is-danger .tq-badge { background: var(--fixed-white); color: var(--danger); }

/* 自定义 Logo：原样展示，不加蓝色圆角底（需求⑤） */
.sidebar-logo.is-custom,
.logo-badge.is-custom {
  background: none !important;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}
.logo-badge { width: 40px; height: 40px; flex: 0 0 40px; border-radius: 11px; display: grid; place-items: center; }

/* 需求 #78-3：前台导航的「蓝天官网」外链项已换成站内的「对外公告」，
   原来那两条 .site-nav-out 规则一并删掉 —— 留着就是"样式类没有对应元素"，
   下次有人搜到它还会以为那个入口只是被藏起来了。 */

/* --------------------------------------------------------------------------
   35.1 提示音：铃铛按钮 + 设置气泡（需求 #65）
   -------------------------------------------------------------------------- */
.sound-wrap { position: relative; display: inline-flex; }

.sound-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface); color: var(--text-2);
  cursor: pointer; transition: all .15s;
}
.sound-btn:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-lighter); }
.sound-btn.is-muted { color: var(--text-3); background: var(--surface-2); }
.sound-btn .sb-icon,
.sound-btn .sb-off { display: grid; place-items: center; }
/* [hidden] 的默认 display:none 会被上面的 grid 覆盖，必须显式压回去 */
.sound-btn [hidden] { display: none !important; }

/* 前台深色头部里的变体：不抢视觉重心，但要能看清 */
.sound-btn.is-dark {
  width: 32px; height: 32px;
  border-color: rgba(255, 255, 255, .24);
  background: rgba(255, 255, 255, .08);
  color: rgba(255, 255, 255, .92);
}
.sound-btn.is-dark:hover {
  border-color: rgba(255, 255, 255, .45);
  background: rgba(255, 255, 255, .18);
  color: #fff;
}

.sound-pop {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 70;
  width: 284px; padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  color: var(--text); text-align: left;
}
.sound-pop[hidden] { display: none; }

.sp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.sp-head b { font-size: 13.5px; }
.sp-close {
  border: 0; background: none; padding: 0 2px; cursor: pointer;
  font-size: 20px; line-height: 1; color: var(--text-3);
}
.sp-close:hover { color: var(--text); }

.sp-switch { display: flex; align-items: center; gap: 8px; padding: 7px 0; font-size: 13px; cursor: pointer; }

.sp-vol {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 0 10px; font-size: 12.5px; color: var(--text-2);
  border-bottom: 1px solid var(--border);
}
.sp-vol input[type="range"] { flex: 1; min-width: 0; accent-color: var(--brand); }
.sp-vol b { width: 26px; text-align: right; font-family: var(--mono); font-size: 12px; color: var(--text); }

.sp-demo { padding: 10px 0 2px; }
.sp-demo-label { font-size: 12.5px; color: var(--text-2); }
.sp-demo-btns { display: flex; gap: 6px; margin-top: 7px; }
.sp-demo-btn {
  flex: 1; height: 30px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2);
  font-size: 12.5px; font-family: inherit; transition: all .15s;
}
.sp-demo-btn:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); background: var(--brand-lighter); }
.sp-demo-btn:disabled { opacity: .45; cursor: not-allowed; }

.sp-tip {
  display: flex; align-items: flex-start; gap: 6px;
  margin: 9px 0 0; font-size: 11.5px; line-height: 1.55; color: var(--text-3);
}
.sp-tip svg { flex: 0 0 auto; margin-top: 2px; }

/* 35.1.1 未处理时的重复提醒（需求 #1）
   还在重复鸣响时：① 气泡里出现「停止提醒」；② 顶栏铃铛加呼吸光晕，
   让"声音还在响"这件事在视觉上也成立 —— 静音环境下不至于完全没线索。 */
.sp-stop {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; margin: 10px 0 2px; height: 34px;
  border: 0; border-radius: 9px; cursor: pointer; font-family: inherit;
  background: var(--danger); color: #fff; font-size: 13px; font-weight: 600;
}
.sp-stop:hover { background: var(--danger-dark); }
.sp-stop[hidden] { display: none !important; }

.sound-wrap.is-ringing .sound-btn {
  color: var(--danger);
  border-color: var(--danger);
  animation: sb-pulse 1.1s ease-in-out infinite;
}
@keyframes sb-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(217, 58, 58, .45); }
  50%      { box-shadow: 0 0 0 7px rgba(217, 58, 58, 0); }
}
/* 关闭系统动效时只保留变色，不做脉冲 */
@media (prefers-reduced-motion: reduce) {
  .sound-wrap.is-ringing .sound-btn { animation: none; }
}

/* --------------------------------------------------------------------------
   35.2 皮肤选择面板（需求 #66）
   -------------------------------------------------------------------------- */
.skin-wrap { position: relative; display: inline-flex; }

.skin-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface); color: var(--text-2);
  cursor: pointer; transition: all .15s;
}
.skin-btn:hover { border-color: var(--brand); color: var(--brand); background: var(--brand-lighter); }
.skin-btn.is-dark {
  width: 32px; height: 32px;
  border-color: rgba(255, 255, 255, .24);
  background: rgba(255, 255, 255, .08);
  color: rgba(255, 255, 255, .92);
}
.skin-btn.is-dark:hover {
  border-color: rgba(255, 255, 255, .45);
  background: rgba(255, 255, 255, .18);
  color: #fff;
}

.skin-pop {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 70;
  width: 288px; padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  color: var(--text); text-align: left;
}
.skin-pop[hidden] { display: none; }

.skp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.skp-head b { font-size: 13.5px; }
.skp-close {
  border: 0; background: none; padding: 0 2px; cursor: pointer;
  font-size: 20px; line-height: 1; color: var(--text-3);
}
.skp-close:hover { color: var(--text); }
.skp-tip { margin: 0 0 10px; font-size: 11.5px; line-height: 1.55; color: var(--text-3); }

.skp-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }

.skp-item {
  position: relative;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px; cursor: pointer; text-align: left;
  border: 1px solid var(--border); border-radius: var(--radius-xs);
  background: var(--surface-2); color: var(--text-2);
  font-family: inherit; font-size: 12.5px; transition: all .15s;
}
.skp-item:hover { border-color: var(--brand); background: var(--brand-lighter); color: var(--text); }
.skp-item.is-cur {
  border-color: var(--brand); background: var(--brand-lighter); color: var(--text);
  font-weight: 600; box-shadow: inset 0 0 0 1px var(--brand);
}
.skp-item.is-cur::after {
  content: '✓'; position: absolute; top: 2px; right: 5px;
  font-size: 11px; color: var(--brand); font-weight: 700;
}

.skp-chip { flex: 0 0 22px; height: 22px; border-radius: 6px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06); }
.skp-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.skp-def {
  flex: 0 0 auto; font-size: 10px; font-weight: 500;
  padding: 0 5px; border-radius: 20px; line-height: 15px;
  background: var(--brand-light); color: var(--brand-ink);
}

.skp-reset { width: 100%; margin-top: 11px; justify-content: center; }

/* 色卡：直接展示每套皮肤的品牌渐变，点之前就能看出气质。
   这里的色值刻意写死 —— 它是「色卡」，本来就该恒等于那套皮肤的颜色，
   跟着当前皮肤变就没有意义了。 */
[data-skin-chip="blue"]     { background: linear-gradient(135deg, #3D8BFF, #1D5FD0 60%, #123C86); }
[data-skin-chip="dark"]     { background: linear-gradient(135deg, #2C4E86, #1B3A66 60%, #101C33); }
[data-skin-chip="orange"]   { background: linear-gradient(135deg, #F5943F, #E2650F 60%, #B84C08); }
[data-skin-chip="green"]    { background: linear-gradient(135deg, #4FAE7E, #1B7F53 60%, #12603D); }
[data-skin-chip="teal"]     { background: linear-gradient(135deg, #3FA9B8, #0B7C8C 60%, #075D6A); }
[data-skin-chip="red"]      { background: linear-gradient(135deg, #E05F5B, #C0302C 60%, #982220); }
[data-skin-chip="paper"]    { background: linear-gradient(135deg, #FFFFFF, #EEF0F4 55%, #3F4A5A); }
[data-skin-chip="gold"]     { background: linear-gradient(135deg, #D3A83F, #A87C1A 60%, #84600F); }
[data-skin-chip="purple"]   { background: linear-gradient(135deg, #9273DE, #6B45C8 60%, #5232A0); }
[data-skin-chip="graphite"] { background: linear-gradient(135deg, #718096, #4A5568 60%, #374151); }

/* 后台「外观皮肤」页的皮肤卡片：两列大卡，卡片本身就是一张色卡 */
.skin-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }

.skin-card {
  position: relative; display: flex; align-items: stretch; gap: 12px;
  padding: 12px; cursor: pointer;
  border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); transition: all .15s;
}
.skin-card:hover { border-color: var(--brand); background: var(--surface-hover); }
.skin-card.is-cur { border-color: var(--brand); background: var(--brand-lighter); }
.skin-card.is-cur::after {
  content: '当前默认'; position: absolute; top: -9px; right: 10px;
  font-size: 10.5px; font-weight: 600; line-height: 18px; padding: 0 8px;
  border-radius: 20px; background: var(--brand); color: #fff;
}
/* 原生 radio 保留在 DOM 里（键盘可达、表单可提交），视觉上藏起来 */
.skin-card input[type="radio"] {
  position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
}
.skin-card input[type="radio"]:focus-visible ~ .sc-chip { outline: 2px solid var(--brand); outline-offset: 2px; }

.sc-chip {
  flex: 0 0 46px; height: 46px; border-radius: 10px;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .06);
}
.sc-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sc-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.sc-name em {
  font-style: normal; font-weight: 400; font-size: 11px;
  margin-left: 6px; color: var(--text-3); letter-spacing: .3px;
}
.sc-desc { font-size: 11.5px; line-height: 1.55; color: var(--text-3); }

/* --------------------------------------------------------------------------
   36. 装备管理 · 板块化与批量操作（需求 #67）
   -------------------------------------------------------------------------- */

/* 板块导航：比默认 tabs 大一点，因为这一页的板块是「换一个工作场景」，
   不是同一批数据的小切换 */
.tabs-lg a { padding: 10px 16px; font-size: 13.5px; }
.tabs-lg a svg { margin-right: 5px; vertical-align: -2px; }
.tab-n {
  display: inline-block; margin-left: 6px; padding: 0 6px;
  font-size: 11px; line-height: 17px; border-radius: 20px;
  background: var(--brand-light); color: var(--brand-ink);
}
.tabs a.active .tab-n { background: var(--brand); color: #fff; }

/* 勾选列：窄，且不参与移动端的堆叠展示 */
.eq-tabs { margin-bottom: 0; }
.th-check, .td-check { width: 34px; text-align: center; }
.th-check input, .td-check input { width: 15px; height: 15px; accent-color: var(--brand); cursor: pointer; }
.td-check input:disabled { cursor: not-allowed; opacity: .4; }

/* 批量维护条：横向排布，窄屏自动折行 */
.eq-batch-bar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  padding: 12px 14px; margin-bottom: 16px;
  border: 1px solid var(--brand-border); border-radius: var(--radius-sm);
  background: var(--brand-lighter);
}
.ebb-title { display: inline-flex; align-items: center; gap: 5px; font-size: 13.5px; font-weight: 600; color: var(--brand-ink); }
.ebb-hint { font-size: 12px; color: var(--text-3); }
.ebb-field { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-2); }
.ebb-field.grow { flex: 1; min-width: 180px; }
.ebb-field.grow .input { flex: 1; min-width: 0; }
.ebb-count {
  margin-left: auto; font-size: 12.5px; font-weight: 600;
  color: var(--brand-ink); white-space: nowrap;
}

/* 一键完成检修条 */
.eq-fix-bar {
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
  background: var(--warn-light);
}
.efb-title { display: inline-flex; align-items: center; gap: 5px; font-size: 13.5px; font-weight: 600; color: var(--warn-ink); }
.eq-fix-item { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.efi-name { display: inline-flex; align-items: baseline; gap: 8px; min-width: 190px; }
.efi-name b { font-size: 13px; }

/* 装备照片：入库/编辑时最多 5 张 */
.eq-photos { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
.eq-photo {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 104px; height: 104px; overflow: hidden;
  border: 1.5px dashed var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface-2); cursor: pointer; transition: all .15s;
}
.eq-photo.is-existing { border-style: solid; border-color: var(--border); background: var(--surface); }
.eq-photo img { width: 100%; height: 100%; object-fit: cover; }
.eq-photo.is-add:hover { border-color: var(--brand); background: var(--brand-lighter); }
.eq-photo.is-add input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.epa-ico { color: var(--text-3); }
.epa-txt {
  position: absolute; left: 0; right: 0; bottom: 8px;
  text-align: center; font-size: 11.5px; line-height: 1.4; color: var(--text-3);
}
.eq-photo.is-add { flex-direction: column; }
.ep-del {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; justify-content: center; gap: 4px;
  padding: 3px 0; font-size: 11.5px; cursor: pointer;
  background: rgba(15, 23, 42, .68); color: #fff;
}
.ep-del input { width: 13px; height: 13px; accent-color: var(--danger); }
/* 勾了「删除」的照片立刻变灰划掉，保存前就能看出将失去哪张 */
.eq-photo:has(.ep-del input:checked) img { opacity: .35; filter: grayscale(1); }
.eq-photo:has(.ep-del input:checked) .ep-del { background: var(--danger); }

/* 台账里的照片缩略图 */
.eq-thumb-row { display: inline-flex; gap: 3px; margin-top: 4px; }
.eq-thumb-row img {
  width: 26px; height: 26px; object-fit: cover;
  border-radius: 5px; border: 1px solid var(--border);
}
.eq-thumb-more {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 5px;
  background: var(--surface-3); color: var(--text-3); font-size: 10.5px;
}

@media (max-width: 1100px) {
  /* 空间不够时快捷区只留图标 */
  .tq-txt { display: none; }
  .tq-item { padding: 0 9px; }
}
@media (max-width: 640px) {
  .top-quick { gap: 5px; }
  .tq-item { height: 32px; }
  .topbar-home { width: 32px; height: 32px; }
  /* 气泡在窄屏上贴右边会被切掉，改成按屏宽收窄并往左让一点 */
  .sound-pop { right: -6px; width: calc(100vw - 32px); max-width: 300px; }
  .skin-pop  { right: -6px; width: calc(100vw - 32px); max-width: 300px; }
}

/* --------------------------------------------------------------------------
   36. 任务信息大盘（实时播报）
   -------------------------------------------------------------------------- */

.live-board { border-top: 3px solid var(--brand); }
.live-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.live-card {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 13px 15px; background: var(--surface);
  border-left: 3px solid var(--border-strong); transition: all .15s;
}
.live-card:hover { border-color: var(--brand); background: var(--brand-lighter); }
.live-card.is-ongoing { border-left-color: var(--warn); }
.lc-top { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.lc-title { font-size: 15px; font-weight: 700; line-height: 1.45; }
.lc-meta { font-size: 12px; color: var(--text-3); margin-top: 4px; }
.lc-nums { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 9px; font-size: 12.5px; color: var(--text-2); }
.lc-nums b { color: var(--brand-dark); font-size: 15px; font-weight: 800; }
.lc-foot { font-size: 11.5px; color: var(--text-3); margin-top: 8px; padding-top: 7px; border-top: 1px dashed var(--border); }

/* 现场进展滚动播报 */
.live-feed { margin-top: 16px; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.lf-head {
  display: flex; align-items: center; gap: 7px;
  padding: 9px 14px; background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: 13px; font-weight: 700; color: var(--text-2);
}
.lf-tip { margin-left: auto; font-size: 11.5px; font-weight: 400; color: var(--text-3); }
.lf-track { max-height: 240px; overflow: hidden; }
.lf-inner { padding: 6px 0; }
.lf-item {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 9px;
  padding: 8px 14px; font-size: 13px; border-bottom: 1px dashed var(--border);
}
.lf-item:last-child { border-bottom: none; }
.lf-item.is-notice { background: var(--warn-light); }
.lf-time { flex: 0 0 auto; font-size: 12px; color: var(--text-3); }
.lf-task { flex: 0 0 auto; font-weight: 600; color: var(--brand-dark); }
.lf-txt { flex: 1 1 200px; color: var(--text-2); }
.lf-who { flex: 0 0 auto; font-size: 12px; color: var(--text-3); }

/* 小型排行榜（序号 + 姓名 + 次数） */
.mini-rank { list-style: none; margin: 0; padding: 0; counter-reset: mr; }
.mini-rank li {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  padding: 7px 0; border-bottom: 1px dashed var(--border); font-size: 13.5px;
  counter-increment: mr;
}
.mini-rank li:last-child { border-bottom: none; }
.mini-rank li::before {
  content: counter(mr); flex: 0 0 20px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-3);
  font-size: 11.5px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center;
}
.mini-rank li a { flex: 1 1 auto; color: var(--text); }
.mini-rank li a:hover { color: var(--brand); }
.mini-rank li b { color: var(--brand-dark); font-weight: 700; }

@media (max-width: 640px) {
  .live-grid { grid-template-columns: minmax(0, 1fr); }
  .lf-track { max-height: 200px; }
  .lf-item { gap: 6px; padding: 7px 12px; }
  .lf-txt { flex-basis: 100%; }
}

/* 手机端顶栏：底部导航已覆盖任务/消息/我的，这里只留最紧急的「求救」，
   避免顶栏变成横向滚动条（滚动内容不易被发现，等于把入口藏起来）。
   注意这里必须保持 overflow-x: visible —— 顶栏的「导出」是个 <details> 下拉，
   父层一旦 overflow:auto/hidden，弹出的菜单就会被裁掉。 */
@media (max-width: 640px) {
  .top-quick .tq-item:not(.is-danger) { display: none; }
  .topbar-actions { overflow-x: visible; }

  /* 顶栏按钮的文字在窄屏收起，只留图标（含义由 title / aria-label 兜底）。
     不这么做的话，窄屏上只要有「导出下拉 + 发起任务 + 快捷区 + 头像」凑齐，
     .topbar-actions 就会被顶出视口：整页出现横向滚动条，
     而 position:fixed 的底部导航、抽屉遮罩会按溢出后的宽度重排，看起来像"整页错位"。
     一个 87px 的「导出」下拉就足以越过 390px 的视口，所以这里连同内边距一起收紧。 */
  .topbar .dd > summary .dd-lb { display: none; }
  .topbar .dd > summary { padding-left: 9px; padding-right: 9px; gap: 4px; }
  .topbar .dd > summary svg:last-child { display: none; }
}

/* （原「状态切换按钮内的文字 .status-btn .sb-txt」样式已随该控件一并删除） */

/* 看板环比变化的第 3 列用分隔色区分 */
.ac-col.is-delta { background: var(--surface); border-style: dashed; }

/* 短信通道状态与测试条 */
.sms-probe {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 16px; padding: 13px 15px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.sp-left { display: flex; align-items: center; gap: 9px; flex: 1 1 260px; flex-wrap: wrap; }
.sp-left code {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; font-size: 11.5px;
}
.sp-right { display: flex; align-items: center; gap: 8px; }
@media (max-width: 640px) {
  .sp-right { width: 100%; }
  .sp-right .input { max-width: none !important; flex: 1 1 auto; }
}

/* 省 / 市 / 区 三级联动选择：一行三列，小屏自动堆叠 */
.region-select { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.region-select .select { min-width: 0; }
@media (max-width: 640px) {
  .region-select { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   37. 志愿者服务承诺弹窗（注册页）
   ========================================================================== */
.link-btn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--brand); font: inherit; font-weight: 600;
  text-decoration: underline; text-underline-offset: 2px;
}
.link-btn:hover { color: var(--brand-dark); }

.pledge-mask {
  position: fixed; inset: 0; z-index: 2200;
  background: rgba(12, 42, 97, .48);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center; padding: 18px;
}
.pledge-mask[hidden] { display: none !important; }

.pledge {
  width: 100%; max-width: 620px; max-height: 88vh;
  background: var(--surface); border-radius: var(--radius-lg, 16px);
  box-shadow: 0 24px 60px rgba(12, 20, 34, .28);
  display: flex; flex-direction: column; overflow: hidden;
}
.pledge-head {
  display: flex; align-items: center; gap: 10px;
  padding: 17px 20px; border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.pledge-head h3 { margin: 0; font-size: 16px; }
.pledge-x {
  margin-left: auto; background: none; border: 0; cursor: pointer;
  font-size: 24px; line-height: 1; color: var(--text-3); padding: 0 2px;
}
.pledge-x:hover { color: var(--text-1); }
.pledge-body { padding: 18px 20px; overflow-y: auto; }
.pledge-list { margin: 0; padding-left: 20px; }
.pledge-list li { margin-bottom: 10px; font-size: 13.5px; line-height: 1.72; color: var(--text-2); }
.pledge-list li b { color: var(--text-1); }
.pledge-note {
  margin: 16px 0 0; padding: 12px 14px; font-size: 12.5px; line-height: 1.7;
  color: var(--text-2); background: var(--surface-2);
  border-left: 3px solid var(--brand); border-radius: 0 8px 8px 0;
}
.pledge-foot {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 20px; border-top: 1px solid var(--border);
  background: var(--surface-2);
}
@media (max-width: 640px) {
  .pledge-mask { padding: 0; align-items: flex-end; }
  .pledge { max-width: none; max-height: 92vh; border-radius: 16px 16px 0 0; }
  .pledge-list li { font-size: 13px; }
}

/* ==========================================================================
   38. 首页「任务态势」三段时段卡片
   ========================================================================== */
.period-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px;
}
.period-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 18px 18px 14px;
  display: flex; flex-direction: column; gap: 12px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
  transition: box-shadow .2s ease, transform .2s ease;
}
.period-card:hover { box-shadow: 0 10px 26px rgba(16, 24, 40, .08); transform: translateY(-2px); }
.period-card.is-feature { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-lighter); }

.pc-head { display: flex; flex-direction: column; gap: 2px; }
.pc-head h3 { margin: 0; font-size: 15.5px; }
.pc-range { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }

.pc-main {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
  padding: 12px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.pcm { display: flex; flex-direction: column; align-items: center; gap: 3px; text-align: center; }
.pcm b { font-size: 21px; line-height: 1.15; font-weight: 700; color: var(--text-1); font-variant-numeric: tabular-nums; }
.pcm b small { font-size: 12px; font-weight: 500; color: var(--text-3); margin-left: 1px; }
.pcm span { font-size: 11.5px; color: var(--text-3); }

.pc-foot { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--text-2); }
.pc-foot span { display: inline-flex; align-items: center; gap: 4px; }
.pc-foot b { color: var(--text-1); font-variant-numeric: tabular-nums; }

.pc-split { display: flex; flex-direction: column; gap: 6px; }
.pcs-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 9px; font-size: 12px;
}
.pcs-row.is-rescue { background: rgba(217, 45, 32, .07); }
.pcs-row.is-train  { background: rgba(29, 95, 208, .07); }

/* ★ 类名是 .pcs-label，**不是** .pcs-tag —— 这层改名是本节的防腐层，别改回去。
   事故经过：这里原本叫 .pcs-tag，而 user/apply.php 的「申请条件流程」组件
   也用同名 .pcs-tag（见本文件下方 .pcs-flow 那一段，那里要的是**实心品牌色药丸**）。
   两份 .pcs-tag 定义特异性相同（都是 0,1,0），后者在文件里更靠后，
   于是它的 `background: var(--brand)` 覆盖到了首页这两个标签上：
   本该是「深红字 / 深蓝字压在极浅底行上」的朴素标签，变成了两块刺眼的实心蓝；
   而文字色因为 `.pcs-row.is-rescue .pcs-tag` 特异性更高（0,3,0）**没有**跟着变，
   结果就是深红字压在饱和蓝底上 —— 对比度低到快读不出来。
   注意「一个类名被两个组件共用、靠源码先后决定长相」这种耦合：
   它不会报错、不会崩，只会默默让 A 组件长得像 B 组件，改 B 的时候 A 跟着变。
   现在这组规则只认自己（.pcs-label），底与字全部走语义变量，
   十套皮肤下都自动跟着变，且不再依赖规则先后。 */
.pcs-label {
  flex: 0 0 auto; font-weight: 600; font-size: 11.5px;
  padding: 2px 8px; border-radius: 7px; line-height: 1.6;
  /* 用「白底 + 同色系细描边」而不是「同色系浅底」：
     下面那行 .pcs-row 的底本来就是同类色的极浅底（rgba .07），
     再叠一块 --danger-light / --brand-light 上去，实测两者亮度几乎相同
     （标签订在行底上的对比只有 1.03），pill 就"消失"在行里了。
     改成白底（--surface，深色皮肤下自动变深）靠描边立轮廓，
     文字用同色系深色 —— 浅、干净，且十套皮肤下都成立。
     box-sizing 全局是 border-box，所以这 1px 描边不会把 pill 撑大。 */
  background: var(--surface);
}
.pcs-row.is-rescue .pcs-label { border: 1px solid var(--danger-border); color: var(--danger-ink); }
/* 文字用 --brand-ink 而**不是** --brand-dark：
   两者在浅色皮肤下看着差不多（#0C2A61 vs #123C86），但十套皮肤扫下来，
   深色皮肤里 --brand-dark 仍是深蓝 #3B76D6，压在深色卡底上对比度只有 3.82，
   低于 WCAG AA 的 4.5 —— 也就是说这个标签在夜间皮肤下会"发闷"。
   --brand-ink 的语义就是「品牌色系的文字色」，深色皮肤下会自动翻成浅蓝 #A9C9FF，
   实测十套皮肤最低对比度 8.4 以上。救援那侧同理用 --danger-ink（它在深色皮肤下
   也会翻成浅红 #FF9C9C），所以两侧都不需要在组件里写皮肤判断。 */
.pcs-row.is-train  .pcs-label { border: 1px solid var(--brand-border);  color: var(--brand-ink); }
.pcs-vals { margin-left: auto; color: var(--text-2); font-variant-numeric: tabular-nums; }
.pcs-vals b { color: var(--text-1); }

.period-note {
  display: flex; align-items: flex-start; gap: 7px;
  margin: 16px 0 0; font-size: 12.5px; line-height: 1.7; color: var(--text-3);
}
.period-note svg { flex: 0 0 auto; margin-top: 2px; }

@media (max-width: 900px) {
  .period-grid { grid-template-columns: minmax(0, 1fr); }
  .period-card.is-feature { order: -1; }
}

/* 能力栅格：8 个板块时桌面 4 列两行更整齐 */
@media (min-width: 1024px) {
  .feature-grid-8 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* 首页公告卡 */
.notice-card { text-decoration: none; color: inherit; transition: box-shadow .2s ease, transform .2s ease; }
.notice-card:hover { box-shadow: 0 10px 26px rgba(16, 24, 40, .08); transform: translateY(-2px); }
.notice-card h3 { font-size: 15px; line-height: 1.45; }

/* 前台导航当前页高亮 */
.site-nav a.is-cur { background: var(--brand-lighter); color: var(--brand); font-weight: 600; }

/* ==========================================================================
   39. 车辆查询结果卡片（前台 · 与核验页 result-card 同基调）
   设计意图：一台车一张卡。车牌是主角（大字号等宽），
   型号/核载/车主做成一条浅底数据带，实拍四角度图另起一条。
   描边一律 1px #ECECEF，圆角 20px，不用阴影强调层级，只在 hover 时抬 1px。
   ========================================================================== */
.vq-item {
  border: 1px solid var(--border); border-radius: 20px; background: var(--surface);
  box-shadow: 0 1px 2px rgba(22, 35, 58, .04);
  overflow: hidden; margin-bottom: 14px;
  transition: box-shadow .2s, border-color .2s, transform .2s;
}
.vq-item:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 28px rgba(22, 35, 58, .09);
  transform: translateY(-1px);
}

/* ---------- 车牌行 ---------- */
.vq-head {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 20px 24px 18px;
}
.vq-plate-no {
  font-size: 23px; font-weight: 700; letter-spacing: .04em;
  color: var(--text); font-variant-numeric: tabular-nums;
  background: var(--surface-3); border: 0; border-radius: 12px;
  padding: 8px 16px;
}
.vq-tags { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-left: auto; }
.vq-tags .badge { border: 0; }

/* ---------- 数据带（值大标签小，苹果式读数顺序） ---------- */
.vq-meta {
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin: 0; padding: 0;
  border-top: 1px solid var(--border); background: var(--surface-2);
}
.vq-meta > div { padding: 15px 24px 16px; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.vq-meta > div + div { border-left: 1px solid var(--border); }
.vq-meta b {
  font-size: 15.5px; font-weight: 600; color: var(--text);
  letter-spacing: -.2px; overflow-wrap: anywhere;
}
.vq-meta span { font-size: 12px; color: var(--text-3); }

/* ---------- 实拍四角度 ---------- */
.vq-shots {
  display: flex; gap: 10px; flex-wrap: wrap;
  padding: 16px 24px 20px; border-top: 1px solid var(--border);
}
.vq-shot { margin: 0; width: 168px; }
.vq-shot img {
  width: 168px; height: 116px; object-fit: cover; display: block;
  border-radius: 12px; border: 1px solid var(--border); background: var(--surface-3);
  cursor: zoom-in;
}
.vq-shot figcaption { font-size: 11.5px; color: var(--text-3); text-align: center; margin-top: 5px; }

@media (max-width: 760px) {
  .vq-head { padding: 16px 18px 14px; gap: 10px; }
  .vq-plate-no { font-size: 20px; padding: 7px 13px; }
  .vq-tags { margin-left: 0; flex: 1 1 100%; }
  .vq-meta { grid-template-columns: 1fr; }
  .vq-meta > div { padding: 12px 18px 13px; }
  .vq-meta > div + div { border-left: 0; border-top: 1px solid var(--border); }
  .vq-shots { padding: 14px 18px 18px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .vq-shot, .vq-shot img { width: 100%; }
  .vq-shot img { height: 84px; }
}

/* ==========================================================================
   40. 图片放大灯箱（沿用既有 .lightbox，此处做苹果风格收敛）
   ========================================================================== */
.lightbox {
  background: rgba(10, 14, 22, .9);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  padding: 40px 24px 28px;
  animation: lb-in .18s ease;
}
@keyframes lb-in { from { opacity: 0 } to { opacity: 1 } }
.lightbox img {
  max-width: min(94vw, 1180px); max-height: 84vh;
  border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, .55);
}
.lightbox-cap { color: #D7E1F2; font-size: 13px; letter-spacing: .01em; }
.lightbox-close {
  top: 14px; right: 16px; width: 36px; height: 36px;
  background: rgba(255, 255, 255, .14);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: background .16s ease;
}
.lightbox-close:hover { background: rgba(255, 255, 255, .26); }

/* 图片画廊的前后翻页（需求 #3）
   同一图组有多张图时才由 JS 插进来，所以这里的样式对单图场景没有影响。
   触摸目标 44px（苹果 HIG 的最小舒适尺寸），键盘聚焦时描边可见。 */
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 46px; height: 46px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  border: none; cursor: pointer;
  background: rgba(255, 255, 255, .16); color: #fff;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: background .16s ease, transform .16s ease;
  opacity: .82;
}
.lightbox-nav:hover { background: rgba(255, 255, 255, .3); opacity: 1; }
.lightbox-nav:active { transform: translateY(-50%) scale(.94); }
.lightbox-nav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; opacity: 1; }
/* 位置用「离边缘固定距离」而不是「贴住图片」：
   图片最大宽度 1180px 居中显示，宽屏两侧留白本就有几百像素，
   箭头贴在留白里既不会压住图片，也不用写 calc()/min() 这类
   一旦浏览器不支持就整条声明失效的复杂表达式。 */
.lightbox-nav.is-prev { left: clamp(10px, 2vw, 28px); }
.lightbox-nav.is-next { right: clamp(10px, 2vw, 28px); }
/* 竖屏窄手机：图几乎占满宽度，箭头改成贴边半透明浮层。
   尺寸给到 44px —— 苹果 HIG 的最小舒适触摸目标，40px 实测偏小、
   手指容易点在边缘上而滑走（现场戴手套时更明显）。 */
@media (max-width: 760px) {
  .lightbox-nav { width: 44px; height: 44px; background: rgba(20, 26, 40, .62); opacity: .9; }
  .lightbox-nav.is-prev { left: 6px; }
  .lightbox-nav.is-next { right: 6px; }
}
.lightbox-count {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 14px;
  padding: 3px 12px; border-radius: 999px;
  background: rgba(255, 255, 255, .16); color: #fff;
  font-size: 12.5px; letter-spacing: .04em; font-variant-numeric: tabular-nums;
}
@media (max-width: 640px) {
  .lightbox { padding: 56px 12px 20px; }
  .lightbox img { max-height: 76vh; border-radius: 12px; }
}

/* --------------------------------------------------------------------------
   41. 移动端收尾：触控目标尺寸
   放在样式表最后是有意的——顶栏相关选择器在 35 节才定义，
   媒体查询必须晚于它们的普通规则，否则同优先级下会被覆盖。
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  /* 顶栏「返回后台首页」与右上角快捷入口是高频点击目标，抬到 40px */
  .topbar-home { width: 40px; height: 40px; }
  .tq-item { height: 40px; padding: 0 12px; }
  /* 手机上顶栏只留图标，避免图标 + 文字把标题挤掉；紧急求助保留文字以免误触 */
  .topbar-quick .tq-item .tq-txt,
  .top-quick .tq-item .tq-txt { display: none; }
  .top-quick .tq-item.is-danger .tq-txt { display: inline; }
  .sa-close { width: 40px; height: 40px; }
}

/* ==========================================================================
   42. 核验结果卡（苹果基调重做）
   设计意图：把原来「一团小标签」改成有呼吸感的三段式——
     ① 身份行：头像 / 姓名 / 徽章 / 关键标识，右侧一个主行动按钮
     ② 数据条：四个最该被看到的数字，用大字号直接给结论
     ③ 明细行：分组 / 技能 / 持证，每行左侧一个灰色小节标签
   取色与字号参考 Apple HIG：正文 #1D1D1F、次级 #86868B、浅底 #F2F2F7，
   分隔线一律 1px #ECECEF 的极浅灰，不用描边强调层级。
   ========================================================================== */
.result-card {
  display: block;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 20px;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(22, 35, 58, .04);
  overflow: hidden;
  margin-bottom: 14px;
  transition: box-shadow .2s, border-color .2s, transform .2s;
}
.result-card:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 28px rgba(22, 35, 58, .09);
  transform: translateY(-1px);
}

/* ---------- ① 身份行 ---------- */
.result-card .rc-head {
  display: flex; align-items: center; gap: 18px;
  padding: 22px 24px 20px;
}
.result-card .rc-avatar {
  flex: 0 0 68px; width: 68px; height: 68px;
  border-radius: 50%; object-fit: cover;
  box-shadow: 0 0 0 4px var(--surface-3);
}
.result-card .rc-id { flex: 1 1 auto; min-width: 0; }
.result-card .rc-name {
  font-size: 21px; font-weight: 700; letter-spacing: -.4px; line-height: 1.25;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.result-card .rc-nick { font-size: 13.5px; font-weight: 500; color: var(--text-3); letter-spacing: 0; }
.result-card .rc-badges { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-top: 9px; }
.result-card .rc-meta {
  display: flex; flex-wrap: wrap; gap: 4px 18px;
  margin-top: 10px; font-size: 12.5px; color: var(--text-3);
}
.result-card .rc-meta b { font-weight: 600; color: var(--text); }
.result-card .rc-go {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 4px;
  height: 40px; padding: 0 18px; border-radius: 999px;
  background: var(--brand); color: #fff;
  font-size: 13.5px; font-weight: 600; white-space: nowrap;
  transition: background .16s, transform .16s;
}
.result-card .rc-go:hover { background: var(--brand-dark); color: #fff; transform: translateX(2px); }

/* ---------- ② 数据条 ---------- */
.result-card .rc-stats {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--border); background: var(--surface-2);
}
.result-card .rc-stat { padding: 16px 20px 17px; text-align: left; }
.result-card .rc-stat + .rc-stat { border-left: 1px solid var(--border); }
.result-card .rc-stat b {
  display: block; font-size: 26px; font-weight: 700; letter-spacing: -.8px;
  line-height: 1.15; color: var(--text); font-variant-numeric: tabular-nums;
}
.result-card .rc-stat span { display: block; margin-top: 3px; font-size: 12px; color: var(--text-3); }

/* ---------- ③ 明细行 ---------- */
.result-card .rc-sec {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 13px 24px; border-top: 1px solid var(--border);
}
.result-card .rc-sec-t {
  flex: 0 0 60px; padding-top: 4px;
  font-size: 12.5px; color: var(--text-3); white-space: nowrap;
}
.result-card .rc-chips { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; gap: 7px; }

/* 卡片内标签：浅底胶囊，不用描边（描边在密集标签里会显得很吵） */
.result-card .chip {
  border: 0; border-radius: 999px;
  background: var(--surface-3); color: #3A3A3C;
  padding: 4px 11px; font-size: 12.5px; gap: 6px;
}
.result-card .chip i {
  font-style: normal; font-size: 11.5px; font-weight: 600;
  color: var(--text-3); letter-spacing: 0;
}
.result-card .chip-brand { background: var(--brand-light); color: var(--brand-dark); }
.result-card .chip-quiet { background: transparent; color: var(--text-3); padding-left: 2px; }
.result-card .chip--ok     { background: var(--ok-light);     color: #0B7A3C; }
.result-card .chip--warn   { background: var(--warn-light);   color: #A06300; }
.result-card .chip--danger { background: var(--danger-light); color: var(--danger-ink); }
.result-card .chip--ok i, .result-card .chip--warn i, .result-card .chip--danger i { color: inherit; opacity: .72; }

/* ---------- 核验页整体呼吸感（苹果式大留白） ---------- */
.query-panel {
  border: 1px solid var(--border); border-radius: 20px;
  box-shadow: 0 1px 2px rgba(22, 35, 58, .04);
  padding: 24px;
}
.query-panel .query-row .input { height: 44px; border-radius: 12px; }
.query-panel .query-row .btn { height: 44px; border-radius: 12px; }
.query-panel .query-row .select { height: 44px; border-radius: 12px; }

/* 主查询行下方的次级筛选行（车辆查询用：类型 / 状态 / 重置）
   为什么单独一行：主行已经占了「查询方式 + 关键词 + 查询」，
   次级条件塞进同一行会把关键词输入框压扁，标签也会跟输入框错位。 */
.query-sub {
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border);
}
.query-sub .qs-field { display: flex; flex-direction: column; gap: 6px; flex: 0 1 188px; min-width: 150px; }
.query-sub .qs-field > label { font-size: 12.5px; color: var(--text-3); }
.query-sub .qs-field .select { height: 40px; border-radius: 12px; }
.query-sub .qs-reset { height: 40px; border-radius: 12px; padding: 0 18px; }

/* 查询口径提示：单行小字，跟随控件宽度自然换行，不占位挤压输入框 */
.query-note {
  margin: 12px 0 0; font-size: 12px; line-height: 1.6; color: var(--text-3);
}

.verify-hint { gap: 14px; margin-top: 20px; }
/* 四格版本（爱心公示页：金额 / 笔数 / 物资 / 历年合计） */
.verify-hint.is-4 { grid-template-columns: repeat(4, 1fr); }
.verify-hint.is-4 .vh-item b { font-size: 22px; }
.vh-item {
  border: 0; border-radius: 16px; background: var(--surface-3);
  padding: 18px 8px;
}
.vh-item b { font-size: 26px; letter-spacing: -.8px; color: var(--text); }
.vh-item span { font-size: 12.5px; color: var(--text-3); }

@media (max-width: 760px) {
  .query-panel { padding: 18px; }
  .query-panel .query-row .select { flex: 1 1 100% !important; }
  .query-sub { gap: 10px; }
  .query-sub .qs-field { flex: 1 1 calc(50% - 5px); min-width: 0; }
  .query-sub .qs-reset { flex: 1 1 100%; justify-content: center; }
  .verify-hint.is-4 { grid-template-columns: repeat(2, 1fr); }
  .verify-hint.is-4 .vh-item b { font-size: 19px; }
  .result-card .rc-head { flex-wrap: wrap; gap: 14px; padding: 18px 18px 16px; }
  .result-card .rc-avatar { flex: 0 0 56px; width: 56px; height: 56px; box-shadow: 0 0 0 3px var(--surface-3); }
  .result-card .rc-name { font-size: 18.5px; }
  .result-card .rc-go { flex: 1 1 100%; justify-content: center; }
  .result-card .rc-stats { grid-template-columns: repeat(2, 1fr); }
  .result-card .rc-stat { padding: 14px 16px; }
  .result-card .rc-stat:nth-child(3) { border-left: 0; }
  .result-card .rc-stat:nth-child(n+3) { border-top: 1px solid var(--border); }
  .result-card .rc-stat b { font-size: 23px; }
  .result-card .rc-sec { flex-direction: column; gap: 8px; padding: 13px 18px; }
  .result-card .rc-sec-t { flex: 0 0 auto; padding-top: 0; }
}

/* 核验结果小节标题行：手机上允许换行，避免「核验结果」被挤成两行 */
.verify-result-bar { display: flex; align-items: center; gap: 9px; margin-bottom: 13px; flex-wrap: wrap; }
.verify-result-bar > strong { font-size: 15px; white-space: nowrap; }
.verify-result-bar .vrb-hint { margin-left: auto; font-size: 12px; color: var(--text-3); }
@media (max-width: 640px) {
  .verify-result-bar .vrb-hint { margin-left: 0; flex: 1 1 100%; }
}

/* ==========================================================================
   43. 「保存档案到本地」打印文档（Apple / 小米 基调的公文版式）
   屏幕上完全不出现，只在打印 / 另存为 PDF 时接管整页。
   为什么另起一版：屏幕档案头是深蓝底、表格是手机卡化样式，
   A4 宽度（≈720px）会落进 860px 断点，打印出来表格被压成一列一列的长条，
   一本证书占掉半页纸。这里按公文口径重排，并把证书照片带进表格。
   ========================================================================== */
.archive-doc { display: none; }

@media print {
  /* 打印时整页换成档案文档，屏幕版一律不输出 */
  .archive-screen { display: none !important; }
  .archive-doc { display: block !important; }

  .archive-doc {
    font-family: var(--font);
    color: #111; font-size: 10.5pt; line-height: 1.62;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }

  /* ---------- 抬头 ---------- */
  .archive-doc .ad-head { text-align: center; border-bottom: 1.4pt solid #111; padding-bottom: 8pt; margin-bottom: 12pt; }
  .archive-doc .ad-team { font-size: 10pt; letter-spacing: 4px; color: #333; }
  .archive-doc .ad-head h1 { font-size: 19pt; font-weight: 700; letter-spacing: 6px; margin: 5pt 0 4pt; }
  .archive-doc .ad-sub { font-size: 8.5pt; color: #555; }

  /* ---------- 分节 ---------- */
  .archive-doc .ad-sec { margin-bottom: 11pt; break-inside: avoid; page-break-inside: avoid; }
  .archive-doc .ad-sec-last { break-inside: auto; }
  .archive-doc .ad-h2 {
    font-size: 11pt; font-weight: 700; letter-spacing: 1px;
    display: flex; align-items: center; gap: 6pt;
    border-bottom: .6pt solid #C9C9CE; padding-bottom: 4pt; margin-bottom: 7pt;
  }
  .archive-doc .ad-h2 i {
    font-style: normal; font-size: 9pt; font-weight: 700;
    width: 13pt; height: 13pt; line-height: 13pt; text-align: center;
    background: #111; color: #fff; border-radius: 50%;
  }

  /* ---------- 身份卡 ---------- */
  .archive-doc .ad-idcard {
    display: flex; align-items: center; gap: 12pt;
    border: .6pt solid var(--border); border-radius: 6pt;
    padding: 9pt 11pt; margin-bottom: 7pt; background: var(--surface-2);
  }
  .archive-doc .ad-avatar { width: 20mm; height: 20mm; border-radius: 50%; object-fit: cover; }
  .archive-doc .ad-name { font-size: 15pt; font-weight: 700; letter-spacing: 2px; }
  .archive-doc .ad-nick { font-size: 9.5pt; font-weight: 400; color: #666; letter-spacing: 0; margin-left: 6pt; }
  .archive-doc .ad-idmeta { font-size: 9pt; color: #555; margin-top: 3pt; }
  .archive-doc .ad-idmeta-more { font-size: 8.5pt; color: #666; }

  /* ---------- 键值表 ---------- */
  .archive-doc .ad-kv { width: 100%; border-collapse: collapse; }
  .archive-doc .ad-kv th,
  .archive-doc .ad-kv td { border: .6pt solid var(--border); padding: 4.5pt 7pt; font-size: 9.5pt; text-align: left; }
  .archive-doc .ad-kv th { width: 15%; background: var(--surface-3); color: #444; font-weight: 600; white-space: nowrap; }
  .archive-doc .ad-kv td { width: 18.33%; }
  .archive-doc .ad-kv b { font-weight: 700; }
  .archive-doc .ad-kv-skill th { width: 18%; }

  /* ---------- 数据四宫格 ---------- */
  .archive-doc .ad-figures { display: flex; border: .6pt solid var(--border); border-radius: 6pt; overflow: hidden; }
  .archive-doc .ad-fig { flex: 1 1 25%; padding: 8pt 10pt; background: var(--surface-2); }
  .archive-doc .ad-fig + .ad-fig { border-left: .6pt solid #E1E1E6; }
  .archive-doc .ad-fig b { display: block; font-size: 16pt; font-weight: 700; letter-spacing: -.5pt; font-variant-numeric: tabular-nums; }
  .archive-doc .ad-fig span { display: block; font-size: 8.5pt; color: #666; margin-top: 1pt; }

  .archive-doc .ad-lines { margin-top: 6pt; font-size: 9.5pt; display: flex; gap: 10pt; }
  .archive-doc .ad-lines-t { flex: 0 0 auto; color: #666; }

  /* ---------- 数据表 ---------- */
  .archive-doc .ad-table { width: 100%; border-collapse: collapse; }
  .archive-doc .ad-table th,
  .archive-doc .ad-table td { border: .6pt solid var(--border); padding: 4.5pt 7pt; font-size: 9.5pt; text-align: left; vertical-align: middle; }
  .archive-doc .ad-table thead th { background: var(--surface-3); color: #333; font-weight: 700; }
  .archive-doc .ad-table tbody tr { break-inside: avoid; page-break-inside: avoid; }
  .archive-doc .ad-table .strong { font-weight: 700; }
  .archive-doc .ad-table-cert td { height: 20mm; }

  /* 证书照片：A4 表格里按固定高度收敛，避免长图把行撑爆 */
  .archive-doc .ad-photo-cell { text-align: center !important; padding: 4pt !important; }
  .archive-doc .ad-photo-cell img { max-width: 68px; max-height: 68px; width: auto; height: auto; margin: 0 auto; border-radius: 3pt; }
  .archive-doc .ad-nophoto { font-size: 8pt; color: #999; }

  /* 状态角标：只用极浅底色，省墨且黑白打印也能分辨字重 */
  .archive-doc .ad-state { display: inline-block; padding: 1pt 6pt; border-radius: 999px; font-size: 8.5pt; font-weight: 600; }
  .archive-doc .ad-state--ok     { background: #E8F5EC; color: #0B6B36; }
  .archive-doc .ad-state--warn   { background: #FDF3E0; color: #8A5600; }
  .archive-doc .ad-state--danger { background: #FBEAEA; color: #9B2828; }

  .archive-doc .ad-empty { font-size: 9.5pt; color: #888; margin: 0; }

  /* ---------- 说明与签章 ---------- */
  .archive-doc .ad-notes { margin: 0; padding-left: 16pt; font-size: 9pt; color: #444; }
  .archive-doc .ad-notes li { margin-bottom: 2pt; }
  .archive-doc .ad-sign { display: flex; gap: 24pt; margin-top: 16pt; }
  .archive-doc .ad-sign-box {
    flex: 1 1 50%; border-bottom: .6pt solid #111;
    height: 34pt; display: flex; align-items: flex-end; padding-bottom: 3pt;
  }
  .archive-doc .ad-sign-box span { font-size: 9pt; color: #666; }

  .archive-doc .ad-foot {
    margin-top: 14pt; padding-top: 6pt; border-top: .6pt solid #C9C9CE;
    font-size: 8pt; color: #777; text-align: center;
  }
}

@media print {
  /* 列宽按百分比给，必须 fixed 才会严格生效，否则浏览器按内容重算，
     长中文列（发证机构）会被挤成一字一列 */
  .archive-doc .ad-table-cert { table-layout: fixed; }
  .archive-doc .ad-table-cert th,
  .archive-doc .ad-table-cert td { overflow-wrap: break-word; word-break: normal; }
  .archive-doc .ad-kv { table-layout: fixed; }
}
@media print {
  /* 状态角标不允许断行，「已过期」被折成两行会很难读 */
  .archive-doc .ad-state { white-space: nowrap; }
  /* 打印时隐藏交互态留下的焦点描边与悬浮位移 */
  .archive-doc .ad-table tbody tr:hover { background: transparent; }
}
@media print {
  /* 状态角标不允许断行，「已过期」被折成两行会很难读 */
  .archive-doc .ad-state { white-space: nowrap; }
  /* 打印时隐藏交互态留下的焦点描边与悬浮位移 */
  .archive-doc .ad-table tbody tr:hover { background: transparent; }
}

/* ==========================================================================
   44. 前台整体基调收口（苹果优先、小米其次）
   为什么要单独收一遍：前 43 节是逐需求叠加出来的，各页的留白、字号、
   分隔方式不一致。这一节只做「统一的排版逻辑」，不引入新组件：
     · 层级靠字号 + 留白，不靠描边和阴影堆叠（苹果）
     · 数字一律 tabular-nums，右对齐不跳动（小米的参数表习惯）
     · 分隔线只用 1px 极浅灰，避免多层描边互相打架
   所有规则都放在样式表最末，确保能压过前面的同名规则；
   各断点的覆写紧跟其后，避免被前面的媒体查询反向覆盖。
   ========================================================================== */

/* ---------- 区块节奏：更大的上下留白 ---------- */
.public-body .section { padding: 68px 20px; }
.public-body .section-head { margin-bottom: 40px; }
.public-body .section-head h2 {
  font-size: 31px; font-weight: 750; letter-spacing: -.7px; line-height: 1.25;
}
.public-body .section-head p { font-size: 15px; line-height: 1.75; max-width: 660px; }
.public-body .section-head .kicker { letter-spacing: 1.8px; margin-bottom: 10px; }

/* ---------- 首屏：字号拉大、统计区改成极浅分隔线网格 ---------- */
.hero-inner { padding: 76px 20px 84px; gap: 52px; }
.hero h1 {
  font-size: 46px; font-weight: 750; letter-spacing: -1.2px; line-height: 1.14;
  margin-bottom: 20px;
}
.hero-lead { font-size: 16px; line-height: 1.8; margin-bottom: 30px; }
.hero-actions .btn { padding: 13px 26px; font-size: 15px; border-radius: 999px; }

/* 统计区：去掉半透明方块，改用 1px 极浅分隔线做网格。
   方块叠方块会显廉价，细线网格更接近苹果的「参数区」做法。 */
.hero-stats {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 0;
  border-top: 1px solid rgba(255, 255, 255, .16);
}
.hero-stat {
  background: transparent; border: 0; border-radius: 0; backdrop-filter: none;
  padding: 20px 24px 22px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .16);
}
.hero-stat:nth-child(odd) {
  padding-right: 24px; border-right: 1px solid rgba(255, 255, 255, .16);
}
.hero-stat:nth-child(even) { padding-left: 24px; }
/* 奇数个统计项时，最后一个独占整行，不留半格空洞 */
.hero-stat:last-child:nth-child(odd) {
  grid-column: 1 / -1; border-right: 0; padding-right: 0;
}
.hero-stat .hs-val {
  font-size: 40px; font-weight: 700; letter-spacing: -1.6px; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.hero-stat .hs-val small {
  font-size: 14px; font-weight: 600; color: var(--side-text-dim); margin-left: 5px; letter-spacing: 0;
}
.hero-stat .hs-label { font-size: 13px; color: var(--side-text-dim); margin-top: 5px; }

/* ---------- 系统核心能力：8 张卡改两列，卡片内留白加倍 ---------- */
.feature-grid-8 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.feature-grid-8 .feature { padding: 28px 30px 30px; border-radius: 20px; }
.feature-grid-8 .feature .f-icon {
  width: 42px; height: 42px; border-radius: 13px; margin-bottom: 16px;
}
.feature-grid-8 .feature .f-icon svg { width: 23px; height: 23px; }
.feature-grid-8 .feature h3 {
  font-size: 17.5px; font-weight: 700; letter-spacing: -.3px; margin-bottom: 9px;
}
.feature-grid-8 .feature p { font-size: 14px; line-height: 1.85; color: #6B7280; }

/* ---------- 台账统计卡：取消色条与图标底块，只留数字说话 ---------- */
#stats .stat {
  border-radius: 20px; box-shadow: none; background: var(--surface-2);
  border-color: var(--border); padding: 26px 26px 24px;
}
#stats .stat::after { display: none; }
#stats .stat .stat-icon {
  width: 34px; height: 34px; border-radius: 11px; margin-bottom: 14px;
}
#stats .stat .stat-label { font-size: 13px; color: var(--text-3); }
#stats .stat .stat-value {
  font-size: 38px; font-weight: 700; letter-spacing: -1.4px; line-height: 1.12;
  font-variant-numeric: tabular-nums; margin: 6px 0 0; color: var(--text);
}
#stats .stat .stat-value small {
  font-size: 14px; font-weight: 600; color: var(--text-3); letter-spacing: 0; margin-left: 4px;
}
#stats .stat .stat-foot { font-size: 12.5px; color: var(--text-3); margin-top: 6px; }
#stats .stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }

/* 台账内的卡片：统一 20px 圆角 + 极浅描边，取消默认阴影 */
#stats .card { border-radius: 20px; border-color: var(--border); box-shadow: none; }
#stats .card .card-head { padding: 20px 24px 16px; }
#stats .card .card-body { padding: 18px 24px 22px; }
/* 进度条改成更细的胶囊，颜色收敛为单一品牌色 */
#stats .bar { height: 7px; border-radius: 999px; background: var(--surface-3); }
#stats .bar > i { border-radius: 999px; }

/* ---------- 任务态势卡：圆角与描边统一到同一套 ---------- */
.period-card { border-radius: 20px; box-shadow: none; border-color: var(--border); }
.period-card.is-feature { box-shadow: none; border-color: var(--brand); }
.period-card .pcm b { font-size: 24px; letter-spacing: -.6px; }
.period-note { font-size: 12.5px; color: var(--text-3); }

/* ---------- 公告卡：统一圆角 ---------- */
.notice-card { border-radius: 20px; border-color: var(--border); }

@media (max-width: 1100px) {
  .feature-grid-8 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #stats .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .public-body .section { padding: 48px 18px; }
  .public-body .section-head { margin-bottom: 28px; }
  .public-body .section-head h2 { font-size: 24px; letter-spacing: -.4px; }
  .public-body .section-head p { font-size: 14px; }
  .hero-inner { padding: 46px 18px 52px; gap: 32px; }
  .hero h1 { font-size: 32px; letter-spacing: -.8px; }
  .hero-lead { font-size: 14.5px; margin-bottom: 24px; }
  .hero-actions .btn { flex: 1 1 100%; justify-content: center; }
  .hero-stat { padding: 16px 18px 18px 0; }
  .hero-stat:nth-child(odd) { padding-right: 18px; }
  .hero-stat:nth-child(even) { padding-left: 18px; }
  .hero-stat .hs-val { font-size: 28px; letter-spacing: -1px; }
  .hero-stat .hs-label { font-size: 12px; }
  .feature-grid-8 { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .feature-grid-8 .feature { padding: 20px 20px 22px; }
  .feature-grid-8 .feature h3 { font-size: 16px; }
  .feature-grid-8 .feature p { font-size: 13.5px; line-height: 1.8; }
  #stats .stat { padding: 18px 18px 16px; }
  #stats .stat .stat-value { font-size: 28px; letter-spacing: -.8px; }
  #stats .card .card-head { padding: 16px 18px 12px; }
  #stats .card .card-body { padding: 14px 18px 18px; }
}

/* --------------------------------------------------------------------------
   40. 网站功能介绍页（features.php）
   -------------------------------------------------------------------------- */

/* 首屏：左侧文案 + 右侧目录 */
.hero-inner-only .hero-inner { align-items: start; }
.feat-toc {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  align-content: start;
}
.toc-item {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 12px; border-radius: 10px;
  background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.12);
  color: #E4EEFF; text-decoration: none; font-size: 13px;
  transition: all .15s;
}
.toc-item:hover { background: rgba(255,255,255,.15); border-color: rgba(255,255,255,.28); transform: translateY(-1px); }
.toc-no {
  flex: 0 0 auto; font-size: 11px; font-weight: 800; color: #9FC0EA;
  font-variant-numeric: tabular-nums;
}
.toc-t { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.toc-n { flex: 0 0 auto; font-size: 11px; color: var(--side-text-dim); }

/* 模块块 */
.feat-block {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
}
.fb-head {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 22px 24px 18px; border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, var(--brand-lighter), transparent);
}
.fb-icon {
  flex: 0 0 48px; width: 48px; height: 48px; border-radius: 13px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand); color: #fff; box-shadow: 0 6px 16px rgba(29,95,208,.28);
}
.fb-title { flex: 1 1 auto; min-width: 0; }
.fb-kicker {
  font-size: 11px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--brand); margin-bottom: 4px;
}
.fb-title h2 { font-size: 21px; margin-bottom: 6px; }
.fb-title p { font-size: 13.5px; color: var(--text-3); line-height: 1.75; margin: 0; }
.fb-count {
  flex: 0 0 auto; font-size: 12px; color: var(--text-3);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; padding: 4px 11px; white-space: nowrap;
}

/* 功能点栅格 */
.feat-items {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 1px; background: var(--border);
}
.feat-item {
  background: var(--surface); padding: 17px 20px 18px;
  transition: background .15s;
}
.feat-item:hover { background: var(--brand-lighter); }
.fi-t {
  font-size: 14.5px; font-weight: 700; color: var(--text); margin-bottom: 7px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
}
.fi-tag {
  font-size: 10.5px; font-style: normal; font-weight: 700;
  background: var(--brand-lighter); color: var(--brand);
  border: 1px solid var(--brand-light, var(--border));
  border-radius: 9px; padding: 1px 8px;
}
.fi-d { font-size: 13px; line-height: 1.8; color: var(--text-3); }

.feat-cta {
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: center;
}

@media (max-width: 900px) {
  .feat-toc { grid-template-columns: minmax(0, 1fr); }
  .feat-items { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .fb-head { padding: 17px 16px 14px; gap: 11px; }
  .fb-icon { flex-basis: 40px; width: 40px; height: 40px; border-radius: 11px; }
  .fb-title h2 { font-size: 17.5px; }
  .fb-count { display: none; }
  .feat-item { padding: 14px 16px 15px; }
  .fi-t { font-size: 13.5px; }
  .fi-d { font-size: 12.5px; }
}

/* --------------------------------------------------------------------------
   41. 人员内部备注（admin/member_view.php）
   -------------------------------------------------------------------------- */

.note-list { display: flex; flex-direction: column; gap: 10px; }
.note-item {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 12px 14px; background: var(--surface-2);
}
.note-item.is-pinned { border-color: var(--warn, #E8A33D); background: rgba(232,163,61,.06); }
.ni-head {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--text-3); margin-bottom: 7px;
}
.ni-who { font-weight: 700; color: var(--text-2); }
.ni-time { font-variant-numeric: tabular-nums; }
.ni-head .btn-group .btn { padding: 3px 9px; font-size: 12px; }
.ni-body { font-size: 13.5px; line-height: 1.85; color: var(--text); word-break: break-word; }
.ni-imgs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.ni-imgs a { display: block; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); line-height: 0; }
.ni-imgs img { width: 96px; height: 96px; object-fit: cover; display: block; }
@media (max-width: 640px) {
  .ni-imgs img { width: 74px; height: 74px; }
}

/* --------------------------------------------------------------------------
   42. 晋级条件自查与链路（user/apply.php · admin/promote.php）
   -------------------------------------------------------------------------- */

/* 逐项核对行 */
.cond-row {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 8px 11px; border-radius: 9px; font-size: 13px;
  border: 1px solid var(--border); background: var(--surface-2); margin-bottom: 7px;
}
.cond-row.is-ok { border-color: var(--ok-border); background: var(--ok-light); }
.cond-row.is-no { border-color: var(--warn-border); background: var(--warn-light, #FFF7E8); }
.cr-mark {
  flex: 0 0 18px; width: 18px; height: 18px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; color: #fff; background: var(--danger);
}
.cond-row.is-ok .cr-mark { background: var(--ok); }
.cr-label { font-weight: 600; }
.cr-need { color: var(--text-3); font-size: 12.5px; }
.cr-have { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
.cond-row.is-no .cr-have { color: var(--danger); }
.cond-row.is-ok .cr-have { color: var(--ok); }

/* 晋级链路 */
.promo-chain { display: flex; flex-direction: column; gap: 9px; }
.pc-step {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 11px 14px; background: var(--surface-2);
}
.pc-step.is-now { border-color: var(--brand); background: var(--brand-lighter); }
.pc-step.is-off { opacity: .62; }
.pcs-flow {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 14px; font-weight: 700;
}
.pcs-arrow { color: var(--text-3); font-weight: 400; }
.pcs-tag {
  font-size: 10.5px; font-style: normal; font-weight: 700;
  background: var(--brand); color: #fff; border-radius: 9px; padding: 1px 8px;
}
.pcs-tag.is-off { background: var(--text-3); }
.pcs-cond { font-size: 12.5px; color: var(--text-3); line-height: 1.7; margin-top: 5px; }

@media (max-width: 640px) {
  .cr-need { display: none; }
  .cond-row { font-size: 12.5px; padding: 7px 10px; }
}

/* --------------------------------------------------------------------------
   43. 多选勾选栅格（任务报名资质限定等）
   -------------------------------------------------------------------------- */
.pick-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 7px; padding: 10px 12px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface-2);
  max-height: 220px; overflow-y: auto;
}
.pick-grid .check-item { padding: 6px 9px; font-size: 13px; }
@media (max-width: 640px) {
  .pick-grid { grid-template-columns: minmax(0, 1fr); max-height: 260px; }
}

/* --------------------------------------------------------------------------
   44. 顶栏「发起任务」主行动按钮（需求 #26）
   -------------------------------------------------------------------------- */
.topbar-new-mission {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 14px; border-radius: 9px;
  background: linear-gradient(135deg, var(--brand), #2E7BEA);
  color: #fff; text-decoration: none; font-size: 13.5px; font-weight: 600;
  box-shadow: 0 3px 10px rgba(29,95,208,.3); white-space: nowrap;
  transition: transform .15s, box-shadow .15s;
}
.topbar-new-mission:hover { transform: translateY(-1px); box-shadow: 0 5px 14px rgba(29,95,208,.38); color: #fff; }
@media (max-width: 640px) {
  .topbar-new-mission { padding: 0 10px; }
  .topbar-new-mission span { display: none; }
}

/* 照片选中后的预览态 */
.eq-photo.is-preview { border-style: solid; border-color: var(--brand); }
.eq-photo.is-preview img { width: 100%; height: 100%; object-fit: cover; }
.epa-count {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 2px 4px; font-size: 10.5px; line-height: 1.4; text-align: center;
  background: rgba(15, 23, 42, .72); color: #fff;
}

/* --------------------------------------------------------------------------
   39. 地图大数据双大盘（需求 #69）
   -------------------------------------------------------------------------- */
.map-layout { display: grid; grid-template-columns: 264px 1fr; gap: 16px; align-items: start; }
@media (max-width: 980px) { .map-layout { grid-template-columns: 1fr; } }

.map-side { display: flex; flex-direction: column; gap: 16px; position: sticky; top: calc(var(--topbar-h) + 12px); }
@media (max-width: 980px) { .map-side { position: static; } }
.map-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.map-filter { display: flex; flex-direction: column; gap: 11px; }
.map-filter .field { margin: 0; }
.map-filter .field label { font-size: 12.5px; }
.map-filter-acts { display: flex; gap: 6px; margin-top: 4px; }

/* 图例：点一下开关一类，比勾选框更符合「看地图时随手调」的习惯 */
.map-legend { display: flex; flex-wrap: wrap; gap: 6px; }
.ml-item {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; cursor: pointer; font-family: inherit;
  font-size: 12px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-3);
  transition: all .15s;
}
.ml-item i { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; filter: grayscale(1); opacity: .45; }
.ml-item.is-on { border-color: var(--border-strong); background: var(--surface); color: var(--text); font-weight: 500; }
.ml-item.is-on i { filter: none; opacity: 1; }
.ml-item:hover { border-color: var(--brand); }
.ml-item.is-off { text-decoration: line-through; }
.map-legend-acts { display: flex; gap: 6px; margin-top: 9px; }

.map-points { display: flex; flex-direction: column; gap: 7px; }
.mp-item { display: flex; align-items: center; gap: 7px; font-size: 12.5px; }
.mp-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; }
.mp-facility { background: var(--brand); }
.mp-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.mp-kind { flex: 0 0 auto; font-size: 11px; color: var(--text-3); }

/* 行政区分布条 */
.area-list { display: flex; flex-direction: column; gap: 12px; }
.area-row { display: flex; flex-direction: column; gap: 5px; }
.area-row.is-unknown { opacity: .68; }
.ar-head { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.ar-name { font-weight: 600; color: var(--text); }
.ar-prov { font-size: 11.5px; color: var(--text-3); }
.ar-n { margin-left: auto; font-weight: 600; color: var(--text-2); font-variant-numeric: tabular-nums; }
.ar-bar {
  display: flex; height: 10px; border-radius: 5px; overflow: hidden;
  background: var(--surface-3); min-width: 2%;
}
.ar-seg { display: block; height: 100%; transition: width .2s; }
.ar-meta { display: flex; flex-wrap: wrap; gap: 12px; font-size: 11.5px; color: var(--text-3); }

.unknown-samples { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.us-item {
  padding: 2px 8px; font-size: 11.5px; border-radius: var(--radius-pill);
  background: var(--surface-3); color: var(--text-2); max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 真实地图容器 */
.amap-box { width: 100%; height: 560px; border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
.amap-box:fullscreen { height: 100vh !important; border-radius: 0; }
.amap-box:-webkit-full-screen { height: 100vh !important; }

.map-main .table tr.is-off { opacity: .6; }

/* 全屏按钮：贴在板块导航行右侧 */
.map-full-btn { margin-left: auto; align-self: center; }
/* 需求 #72：地图页的标签条与「全屏」按钮同一行。
   标签条能横向滚动（标签多时不换行），全屏按钮固定在右侧不参与滚动。 */
.map-tabs { display: flex; align-items: stretch; gap: 8px; }
.map-tabs .tabs { flex: 1 1 auto; min-width: 0; }

/* --------------------------------------------------------------------------
   40. 首页：时长榜、任务构成、累计口径说明（需求 #70）
   -------------------------------------------------------------------------- */

/* 年份切换条贴在榜单区顶部 */
.home-year-tabs { margin-bottom: 16px; }

/* 救援类任务的 chip：与「常规」在视觉上必须一眼可分，
   因为两者的时长系数不同（×1.5 vs ×1） */
.chip-danger { background: var(--danger-light); border-color: var(--danger-border); color: var(--danger-ink); }
.chip svg { margin-right: 4px; vertical-align: -1px; }

/* 累计口径：平台 + 历史 = 合计，用一个加号一个等号把关系摆明白 */
.ledger-split {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 4px 0 2px;
}
.ls-item {
  flex: 1 1 130px; min-width: 118px;
  padding: 12px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface-2);
}
.ls-item.is-total {
  border-color: var(--brand-border); background: var(--brand-lighter);
}
.ls-label { font-size: 12px; color: var(--text-3); }
.ls-value {
  margin-top: 3px; font-size: 22px; font-weight: 800; letter-spacing: -.5px;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.ls-item.is-total .ls-value { color: var(--brand-dark); }
.ls-value small { font-size: 11.5px; font-weight: 600; color: var(--text-3); margin-left: 3px; }
.ls-sub { margin-top: 2px; font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.ls-plus, .ls-eq {
  flex: 0 0 auto; font-size: 18px; font-weight: 700; color: var(--text-3);
}
@media (max-width: 560px) {
  .ls-plus, .ls-eq { display: none; }
  .ls-item { flex: 1 1 100%; }
}

/* 指挥大盘：出勤人员构成 + 现场照片（需求 #70） */
.demo-bars { display: flex; flex-direction: column; gap: 11px; }
.db-row { display: flex; flex-direction: column; gap: 5px; }
.db-top {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12.5px; color: var(--text-2);
}
.db-top b { color: var(--text); font-variant-numeric: tabular-nums; }
.db-bar { height: 8px; border-radius: 4px; background: var(--surface-3); overflow: hidden; }
.db-bar i { display: block; height: 100%; border-radius: 4px; transition: width .4s; }

.role-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.rc-item {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 11px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface-2);
  font-size: 12.5px; color: var(--text-2);
}
.rc-item b { color: var(--brand-dark); font-variant-numeric: tabular-nums; }

.shot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 9px; }
.shot-item {
  display: block; position: relative; overflow: hidden;
  border-radius: var(--radius-xs); border: 1px solid var(--border);
  aspect-ratio: 4 / 3; background: var(--surface-3);
}
.shot-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shot-item .si-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 4px 7px; font-size: 11px; line-height: 1.4;
  background: rgba(15, 23, 42, .66); color: #fff;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.shot-item:hover img { transform: scale(1.04); transition: transform .2s; }

/* ==========================================================================
   41. 入队指引（join_us.php）与新人引导入口（需求 #71 / #25）

   这一页是「招募落地页」，来访者多半是第一次接触队伍，
   所以视觉上比站内其它页更重（深色首屏 + 大字号），但**一个组件都没有新造**：
   首屏沿用首页 hero 的渐变与玻璃拟态按钮，内容区沿用 section / card，
   加群区沿用卡片风格。新皮肤上线时这一页会自动跟着变，不需要单独适配。
   ========================================================================== */

/* ---- 首屏 ---- */
.join-hero {
  background: var(--brand-grad-deep);
  color: var(--head-text);
  padding: 56px 20px 50px;
  position: relative;
  overflow: hidden;
}
.join-hero::after {
  /* 右上角一团柔光，避免大面积深色显得死板 */
  content: '';
  position: absolute; top: -160px; right: -120px;
  width: 460px; height: 460px; border-radius: 50%;
  background: radial-gradient(circle, rgba(92, 160, 255, .38), transparent 68%);
  pointer-events: none;
}
.join-hero-inner {
  max-width: 1180px; margin: 0 auto;
  display: grid; grid-template-columns: 1.15fr .85fr;
  gap: 44px; align-items: center;
  position: relative; z-index: 1;
}
.join-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 13px; border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .2);
  font-size: 12.5px; letter-spacing: .6px; margin-bottom: 18px;
}
.join-eyebrow i {
  width: 7px; height: 7px; border-radius: 50%;
  background: #6BE39A; box-shadow: 0 0 0 3px rgba(107, 227, 154, .25);
}
.join-hero h1 {
  font-size: 42px; line-height: 1.2; letter-spacing: -.5px;
  color: var(--fixed-white); margin-bottom: 16px;
}
.join-hero h1 em { font-style: normal; color: #7FB6FF; }
.join-lead {
  font-size: 15.5px; color: #C6DAF7; line-height: 1.85;
  max-width: 560px; margin-bottom: 26px;
}
.join-hero-acts { display: flex; gap: 12px; flex-wrap: wrap; }
.join-hero-acts .btn { padding: 12px 24px; font-size: 15px; border-radius: var(--radius-sm); }

.jh-facts { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.jh-facts .jf {
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .17);
  border-radius: var(--radius);
  padding: 16px 18px;
  backdrop-filter: blur(6px);
}
.jh-facts .jf-val {
  font-size: 28px; font-weight: 800; color: var(--fixed-white);
  line-height: 1.2; font-variant-numeric: tabular-nums;
}
.jh-facts .jf-val small { font-size: 13px; font-weight: 600; color: var(--side-text-dim); margin-left: 3px; }
.jh-facts .jf-label { font-size: 12.5px; color: var(--side-text-dim); margin-top: 2px; }
.jh-note {
  margin-top: 12px; padding: 11px 14px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .2);
  font-size: 12.5px; line-height: 1.7; color: #DCE9FB;
  display: flex; gap: 8px; align-items: flex-start;
}
.jh-note svg { flex: 0 0 auto; margin-top: 2px; }

/* 首页引导条与其它 section 之间不需要额外留白，靠 section 自带 padding */
.section-tight { padding-top: 34px; padding-bottom: 34px; }

/* ---- 新人进度卡（仅未认证志愿者可见） ---- */
.join-progress .jp-title { font-size: 16px; margin-bottom: 14px; }
.jp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }
.jp-item {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  text-decoration: none; color: inherit;
  transition: border-color .18s, background .18s, transform .18s;
}
.jp-item:hover { border-color: var(--brand-border); background: var(--brand-lighter); transform: translateY(-2px); }
.jp-item .jp-no {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand); color: var(--fixed-white);
  font-size: 13.5px; font-weight: 700;
}
.jp-item b { display: block; font-size: 14.5px; margin-bottom: 3px; }
.jp-item span { font-size: 12.5px; color: var(--text-3); line-height: 1.65; }
.jp-item > svg { margin-left: auto; color: var(--text-3); flex: 0 0 auto; }

/* ---- 入队流程（编号步骤） ---- */
.jsteps {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px;
  counter-reset: jstep;
}
.jstep {
  display: flex; gap: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 20px 20px 18px;
  position: relative;
  transition: transform .2s, box-shadow .2s, border-color .2s;
}
.jstep:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--brand-border); }
.jstep-no {
  flex: 0 0 auto;
  width: 34px; height: 34px; border-radius: 11px;
  display: grid; place-items: center;
  background: var(--brand-light); color: var(--brand-ink);
  font-size: 15px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.jstep-body h3 { font-size: 15.5px; margin-bottom: 6px; }
.jstep-body p { font-size: 13.5px; color: var(--text-3); line-height: 1.75; margin: 0; }

/* ---- 需要准备的资料 ---- */
.jdocs { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }
.jdoc {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 15px 17px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.jdoc .jdoc-ico { color: var(--ok); flex: 0 0 auto; margin-top: 1px; }
.jdoc b { display: block; font-size: 14px; margin-bottom: 3px; }
.jdoc span { font-size: 12.5px; color: var(--text-3); line-height: 1.7; }

.jtip {
  margin-top: 18px;
  display: flex; gap: 8px; align-items: flex-start;
  padding: 12px 15px;
  border-radius: var(--radius-sm);
  background: var(--brand-lighter);
  border: 1px solid var(--brand-border);
  color: var(--text-2);
  font-size: 12.5px; line-height: 1.75;
}
.jtip svg { flex: 0 0 auto; margin-top: 2px; color: var(--brand); }
.jtip-center { justify-content: center; max-width: 720px; margin-left: auto; margin-right: auto; }

/* ---- 培训与认证 ---- */
.jtrains { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; }
.jtrain {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--brand);
  border-radius: var(--radius-sm);
  padding: 17px 19px;
}
.jtrain h3 { font-size: 15px; margin-bottom: 7px; }
.jtrain p { font-size: 13.5px; color: var(--text-3); line-height: 1.75; margin: 0; }

/* ---- 常见问题（原生 details，零 JS 也能用） ---- */
.jfaq { max-width: 860px; margin: 0 auto; display: flex; flex-direction: column; gap: 10px; }
.jfaq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.jfaq-item[open] { border-color: var(--brand-border); box-shadow: var(--shadow-sm); }
.jfaq-item summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  padding: 15px 18px;
  font-size: 14.5px; font-weight: 600; color: var(--text);
}
.jfaq-item summary::-webkit-details-marker { display: none; }
.jfaq-q { flex: 1 1 auto; }
.jfaq-arrow { flex: 0 0 auto; color: var(--text-3); transition: transform .2s; display: flex; }
.jfaq-item[open] .jfaq-arrow { transform: rotate(180deg); color: var(--brand); }
.jfaq-a {
  padding: 0 18px 16px 18px;
  font-size: 13.5px; color: var(--text-2); line-height: 1.85;
  border-top: 1px dashed var(--border);
  padding-top: 13px;
}

/* ---- 加群与咨询 ---- */
.jqr { display: grid; grid-template-columns: 340px 1fr; gap: 22px; align-items: start; }
.jqr-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
  text-align: center;
  box-shadow: var(--shadow-sm);
}
.jqr-img {
  width: 100%; max-width: 260px; aspect-ratio: 1 / 1;
  object-fit: contain; display: block; margin: 0 auto;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--fixed-white); cursor: zoom-in;
}
.jqr-hint { font-size: 12.5px; color: var(--text-3); margin-top: 10px; }
.jqr-empty {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 28px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text-3);
  background: var(--surface-2);
}
.jqr-empty svg { color: var(--border-strong); }
.jqr-empty b { font-size: 14px; color: var(--text-2); }
.jqr-empty span { font-size: 12px; line-height: 1.7; }
.jqr-acts { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 16px; }

.jqr-side h3 { font-size: 17px; margin-bottom: 14px; }
.jqr-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.jqr-list li { display: flex; gap: 9px; align-items: flex-start; font-size: 14px; color: var(--text-2); line-height: 1.75; }
.jqr-list li svg { flex: 0 0 auto; margin-top: 4px; color: var(--ok); }
.jqr-list b { color: var(--text); }
.jqr-foot {
  margin-top: 18px; padding-top: 14px;
  border-top: 1px dashed var(--border);
  font-size: 12.5px; color: var(--text-3); line-height: 1.8;
  display: flex; gap: 8px; align-items: flex-start;
}
.jqr-foot svg { flex: 0 0 auto; margin-top: 2px; color: var(--brand); }

/* ---- 新人引导入口（首页 / 个人中心，需求 #71） ---- */
.join-guide-wrap { max-width: 1180px; margin: 0 auto; padding: 26px 20px 0; }
.join-guide {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  background: var(--brand-lighter);
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  padding: 18px 20px;
}
.join-guide-me { background: var(--brand-lighter); border-color: var(--brand-border); }
.join-guide .jg-main { display: flex; gap: 13px; align-items: flex-start; flex: 1 1 460px; min-width: 0; }
.join-guide .jg-ico {
  flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: 13px;
  display: grid; place-items: center;
  background: var(--brand); color: var(--fixed-white);
}
.join-guide .jg-title { font-size: 15.5px; margin-bottom: 5px; color: var(--brand-ink); }
.join-guide .jg-desc { font-size: 13px; color: var(--text-2); line-height: 1.75; margin: 0; }
.join-guide .jg-acts { display: flex; gap: 9px; flex-wrap: wrap; margin-left: auto; }

/* ---- 移动端 ---- */
@media (max-width: 900px) {
  .join-hero-inner { grid-template-columns: 1fr; gap: 28px; }
  .jqr { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .join-hero { padding: 36px 16px 32px; }
  .join-hero h1 { font-size: 30px; }
  .join-lead { font-size: 14.5px; }
  .join-hero-acts .btn { flex: 1 1 auto; justify-content: center; }
  .section { padding: 40px 16px; }
  .section-head h2 { font-size: 22px; }
  .jsteps, .jdocs, .jtrains { grid-template-columns: 1fr; }
  .join-guide { flex-direction: column; align-items: stretch; }
  .join-guide .jg-acts { margin-left: 0; }
  .join-guide .jg-acts .btn { flex: 1 1 auto; justify-content: center; }
  .jqr-card { padding: 18px; }
}

/* 深色皮肤下首屏的柔光略收，避免过曝 */
[data-skin="dark"] .join-hero::after,
[data-skin="graphite"] .join-hero::after { opacity: .45; }

/* ---- 后台「入队指引」设置：二维码编辑区 ---- */
.qr-edit { display: grid; grid-template-columns: 200px 1fr; gap: 20px; align-items: start; }
.qr-edit-view {
  text-align: center;
  padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.qr-edit-view img {
  width: 100%; max-width: 170px; aspect-ratio: 1 / 1;
  object-fit: contain; display: block; margin: 0 auto;
  border-radius: var(--radius-xs); border: 1px solid var(--border);
  background: var(--fixed-white); cursor: zoom-in;
}
.qr-edit-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7px;
  aspect-ratio: 1 / 1; max-width: 170px; margin: 0 auto;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-xs);
  color: var(--text-3); font-size: 12.5px;
  background: var(--surface);
}
.qr-edit-empty svg { color: var(--border-strong); }
.qr-edit-form { min-width: 0; }
@media (max-width: 640px) {
  .qr-edit { grid-template-columns: 1fr; }
  .qr-edit-view img, .qr-edit-empty { max-width: 200px; }
}

/* ==========================================================================
   42. 后台二级标签栏（需求 #72 / #18 #37）

   位置：顶栏之下、内容之上，**吸顶**。
   需求原文是「一级/二级菜单点进去后，右侧顶部也能继续基于内容做菜单管理」，
   所以它必须紧跟顶栏、并且在长页面滚动时一直看得见——
   否则滚到一半想换标签还得先滚回顶部。

   吸顶的 top 用 --topbar-h（62px）：顶栏本身 sticky top:0 且 z-index:40，
   标签条取 39 压在它下面。两个都给 40 会让标签条盖住顶栏的毛玻璃。
   ========================================================================== */
.page-tabs {
  position: sticky;
  top: var(--topbar-h);
  z-index: 39;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  /* 横向滚动而不是换行：换行会让吸顶高度随标签数量变化，
     滚动时下面的内容会跟着跳动，阅读体验很差。 */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.page-tabs::-webkit-scrollbar { display: none; }
/* 标签条自己带边框，去掉 .tabs 原本的重复下边框 */
.page-tabs .tabs { border-bottom: none; background: transparent; flex-wrap: nowrap; }
/* 每个标签必须保持「一整块、单行文字」：
   默认 flex 项会被压缩，文字一换行这条吸顶栏就长高（390 宽下 7 个标签能顶到 134px），
   sticky 元素高度一变，下面内容会跟着跳 —— 所以宁可横向滚动，不许换行。 */
.page-tabs .tabs a { padding: 12px 15px; white-space: nowrap; flex: 0 0 auto; }
.page-tabs .tabs a svg { margin-right: 5px; vertical-align: -2px; }

@media (max-width: 640px) {
  .page-tabs .tabs { padding: 0 12px; }
  .page-tabs .tabs a { padding: 11px 12px; font-size: 13px; }
}

/* 打印时标签栏是交互控件，不进正式文档 */
@media print {
  .page-tabs { display: none !important; }
}

/* --------------------------------------------------------------------------
   42.1 表单内分组标签（admin_panes()）

   与上面「换 URL」的标签不同：这里是**同一个表单**里的字段分组，
   所有分组始终在表单里，只是同一时间显示一块。

   `.has-panes` 由 JS 在初始化时加到 <form>（或 <html>）上。没有 JS 就没有这个类，
   所有分组全展开 —— 宁可页面长，也不能出现"点不开、看不到内容"的白屏。
   -------------------------------------------------------------------------- */
.has-panes [data-pane] { display: none; }
.has-panes [data-pane].is-on { display: block; }

.pane-tabs {
  /* 表单里的标签条不需要吸顶（它本来就在表单最上方，且下方紧跟内容） */
  position: relative;
  margin-bottom: 14px;
  /* 右侧挂的「保存」不参与横向滚动，别被标签挤走 */
  align-items: center;
}
.pane-tabs .pane-save {
  margin-left: auto;
  padding: 0 14px 0 12px;
  display: flex;
  align-items: center;
  /* 标签多到要横向滚时，保存按钮要一直看得见 */
  position: sticky;
  right: 0;
  background: var(--surface);
}
.pane-tabs .pane-save .btn { white-space: nowrap; }

@media (max-width: 640px) {
  .pane-tabs .pane-save { padding: 0 12px 0 8px; }
  .pane-tabs .pane-save .btn { padding: 6px 10px; }
}

/* --------------------------------------------------------------------------
   45. 任务页 · 快速填写任务信息 + 任务协作（需求 #7）
   --------------------------------------------------------------------------
   只在有权限的人打开任务页时渲染，所以样式不必考虑"志愿者也看到"的情况，
   但**手机端优先**：现场指挥基本都在手机上操作。
   -------------------------------------------------------------------------- */

/* ── 快速填写：默认收起，展开后是一组两列表单 ────────────────────────── */
.mq-toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 11px 13px; min-height: 46px;
  border: 1px dashed var(--brand-border); border-radius: var(--radius-sm);
  background: var(--brand-lighter); color: var(--brand-dark);
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  cursor: pointer; text-align: left;
}
.mq-toggle:hover { border-style: solid; background: var(--brand-light); }
.mq-toggle svg { flex: 0 0 auto; transition: transform .18s; }
.mq-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

.mq-form { margin-top: 14px; }
.mq-form .form-grid { gap: 12px 16px; }
/* 任务说明独占整行 —— 它是唯一会长到多行的字段，挤在半列里很难写 */
.mq-form .mq-full { grid-column: 1 / -1; }
.mq-clear {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--text-3); font-weight: 400; cursor: pointer;
}
.mq-clear input { margin: 0; }
.mq-foot {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--border);
}
.mq-foot .hint { font-size: 12px; }

/* ── 任务协作：协作者列表 + 添加表单 ──────────────────────────────────── */
.ms-list { display: flex; flex-direction: column; gap: 9px; margin-bottom: 4px; }
.ms-row {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface-2);
}
.ms-row img {
  width: 38px; height: 38px; border-radius: 50%; object-fit: cover;
  flex: 0 0 38px; background: var(--surface-3);
}
.ms-info { flex: 1 1 auto; min-width: 0; }
.ms-name { display: flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 600; flex-wrap: wrap; }
.ms-sub { display: block; font-size: 12px; color: var(--text-3); margin-top: 2px; }
.ms-del { flex: 0 0 auto; }

.ms-add { max-width: 460px; }
.ms-add .field { margin-bottom: 13px; }
/* 候选人选择器：多行列表比原生下拉更适合"翻一翻再挑"，
   配合上方过滤框，找人不靠滚动靠打字。 */
.ms-add select[multiple], .ms-add select[size] {
  height: auto; min-height: 132px; padding: 4px;
  line-height: 1.5;
}
.ms-add select option { padding: 5px 7px; border-radius: 4px; }

@media (max-width: 760px) {
  .mq-form .form-grid { grid-template-columns: 1fr; }
  /* 触屏：展开/收起按钮垫 44px 命中区 */
  .mq-toggle { position: relative; min-height: 46px; }
  .ms-add { max-width: none; }
  .ms-row { padding: 9px 10px; }
  .ms-del .btn { position: relative; }
  .ms-del .btn::after {
    content: ""; position: absolute; left: 0; right: 0; top: 50%;
    transform: translateY(-50%); height: 44px;
  }
  .mq-foot .btn { flex: 1 1 auto; justify-content: center; }
}

/* --------------------------------------------------------------------------
   27. 数据导出中心（需求 #10：全站数据导出 + 多条件筛选导出）
   -------------------------------------------------------------------------- */
.xc-jump { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.xc-jump .chip { text-decoration: none; }

/* 一个数据集 = 一行摘要 + 一条可展开的筛选带。
   筛选带做成 <details>，不点不占地方：41 个数据集排在一页上仍然扫得动。 */
.xc-item { border-bottom: 1px solid var(--border); }
.xc-item:last-child { border-bottom: none; }
.xc-item > .list-row { border-bottom: none; }

.xc-more > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 6px;
  padding: 9px 18px; font-size: 12.5px; font-weight: 600;
  color: var(--brand); background: var(--surface-2);
  border-top: 1px dashed var(--border);
}
.xc-more > summary::-webkit-details-marker { display: none; }
.xc-more > summary::marker { content: ''; }
.xc-more[open] > summary {
  background: var(--brand-lighter);
  border-top-color: var(--brand-border);
}
.xc-more .xc-form {
  padding: 14px 18px 16px;
  background: var(--surface-2);
  border-top: 1px dashed var(--border);
}
/* 没有可筛字段时的说明条，与筛选带同款底色，视觉上仍是「这一数据集的一条附注」 */
.xc-more-flat {
  padding: 9px 18px; font-size: 12.5px; color: var(--text-3);
  background: var(--surface-2); border-top: 1px dashed var(--border);
}

/* 「当前筛选」提示条：把「筛后 N 条 / 全部 M 条」摆出来，
   用户按下导出前就知道自己会拿到多少行。 */
.xc-cur { border-color: var(--brand-border); }
.xc-cur .honor-mark { background: var(--brand-lighter); color: var(--brand); }

@media (max-width: 760px) {
  /* 触屏：展开条垫足命中高度 */
  .xc-more > summary { min-height: 46px; padding: 12px 14px; }
  .xc-more .xc-form { padding: 12px 14px 14px; }
  .xc-item > .list-row { flex-wrap: wrap; }
  .xc-item > .list-row .btn-group { width: 100%; }
  .xc-item > .list-row .btn-group .btn { flex: 1 1 auto; justify-content: center; }
  .xc-cur .list-row { flex-wrap: wrap; }
  .xc-cur .list-row .btn-group { width: 100%; }
  .xc-cur .list-row .btn-group .btn { flex: 1 1 auto; justify-content: center; }
}

/* ==========================================================================
   发起任务页 · 紧凑表单（需求 #2 修订）
   --------------------------------------------------------------------------
   需求原文：「1.要做什么 / 2.什么时候去哪里集合 / 3.谁来指挥、怎么联系
   这几个标题可以删掉」「套用任务模板板块删掉，需要套用模板直接进入
   任务模版页面」「页面简化一点（内容不能少）」。

   所以这里把原来的「三张带编号的卡 + 右侧 296px 模板栏」换成：

     · .me-bar  —— 顶部一条细引导条 + 一个「从模板发起」按钮；
     · .me-grid —— 显式三列栅格，8 个字段压成四行；
     · .me-tip  —— 原「发布须知」卡片压成一行脚注。

   为什么不用 .form-grid（auto-fit）：auto-fit 的列数随容器宽度浮动，
   span-2 / span-3 在窄屏会撑出**隐式列**，直接把卡片顶出横向滚动条。
   显式列数 + 两级媒体查询可控得多。
   ========================================================================== */
.me-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 12px;
  margin-bottom: 12px;
  background: var(--brand-lighter);
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-sm);
}
.me-bar-txt {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  flex: 1 1 320px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-2);
}
.me-bar-txt svg { flex: 0 0 auto; color: var(--brand); }
.me-bar-code { color: var(--text-3); white-space: nowrap; }
.me-bar-btn { flex: 0 0 auto; }

/* 发起 / 编辑任务页：三列紧凑栅格（8 个字段 → 四行） */
.me-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px 14px;
}
.me-grid > .span-2 { grid-column: span 2; }
.me-grid > .span-3 { grid-column: span 3; }
@media (max-width: 900px) {
  .me-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .me-grid > .span-3 { grid-column: span 2; }
}
@media (max-width: 620px) {
  .me-grid { grid-template-columns: 1fr; }
  .me-grid > .span-2,
  .me-grid > .span-3 { grid-column: span 1; }
}

/* 原「发布须知」侧栏卡片 → 一行脚注（少占地方，内容一条不减） */
.me-tip {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 12px 0 0;
  font-size: 11.5px;
  line-height: 1.75;
  color: var(--text-3);
}
.me-tip svg { flex: 0 0 auto; margin-top: 3px; }

/* 折叠区：原生 details，零 JS 也能展开（无 JS 时它就是一块可见的说明条） */
.me-adv {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}
.me-adv > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
  background: var(--surface-2);
}
.me-adv > summary::-webkit-details-marker { display: none; }
.me-adv > summary::marker { content: ''; }
.me-adv > summary:hover { color: var(--brand); }
.me-adv[open] > summary {
  color: var(--brand);
  border-bottom: 1px solid var(--border);
}
.me-adv-body { padding: 14px 16px 4px; }

/* 模板列表里的「预设了什么」标签 */
.tpl-preset { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }

/* ── 模板列表分段：应急预案 / 日常（需求 #2 修订）──────────────────────
   需求原文：「模版页面要新增几个应急预案管理模板……主要用于一旦发生重大
   事件，一键发起针对特殊救援的任务」。

   所以列表不能再是一锅粥：应急预案单独一段置顶，段头加图标与说明，
   条目上带红色「应急预案」徽章。紧急时刻管理员是"照着名字找"的，
   分段比排序更可靠。 */
.tpl-sec + .tpl-sec { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--border); }
.tpl-sec-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.tpl-sec-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-1);
}
.tpl-sec-title svg { color: var(--brand); }
.tpl-sec-note { font-size: 11.5px; color: var(--text-3); }
.tpl-sec-empty {
  margin: 0;
  padding: 10px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--text-3);
}

@media (max-width: 640px) {
  /* 触屏：折叠摘要垫到 46px 才好点 */
  .me-adv > summary { min-height: 46px; padding: 12px 14px; }
  .me-adv-body { padding: 12px 12px 2px; }
  /* 触屏上引导条与按钮各占一行，按钮撑满更好点 */
  .me-bar { padding: 9px 11px; }
  .me-bar-btn { width: 100%; justify-content: center; }
  /* 折叠区摘要右侧那串"报名截止 · 人数上限 · …"在 390px 下会换行，
     把摘要从 46px 撑到 89px —— 白白多占一行。窄屏直接隐掉，
     点开折叠区照样能看到完整字段名。 */
  .me-adv > summary .badge { display: none; }
}

/* ── 编号 / ID 规则 · 实时示例（需求 #16）──────────────────────────
   设置页里四个输入框下面给一条"签发出的第一个编号长什么样"。
   用 accent 底色 + 等宽字体，一眼能和说明文字区分开。 */
.ltid-preview {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 14px;
  margin-top: 4px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.ltid-preview-label { font-size: 12.5px; color: var(--text-3); }
.ltid-preview-code {
  font-family: var(--mono);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .3px;
  color: var(--accent-ink);
}

@media (max-width: 640px) {
  .ltid-preview { gap: 6px; }
  .ltid-preview-code { font-size: 16px; }
}

/* --------------------------------------------------------------------------
   快捷在岗打卡（需求 #1 / #20c）
   --------------------------------------------------------------------------
   设计目标就一个字：矮。

   需求原文（#6）：「不要明明一个很小的按钮、编辑框就可以解决的，非要把 ui 画很大，
   这样会造成填写基础的信息都要大幅度滑动页面，浪费时间」。
   打卡是**每天要点好几次**的东西，却只需要在 4 个状态里点一个 ——
   所以这里刻意不用 card-body 的常规留白：

     · 状态按钮做成 30px 高的小圆角条，一行排开，点一下就提交
     · 备注输入框与按钮同高（30px）并排，不再单独占一行 + 一段 label
     · 「休假截止」默认 hidden，只有真的点「休假」才展开（平时零高度）

   整块卡片在桌面端不到 100px 高、手机端两行，点完不用滚动。

   配色沿用全局语义变量（badge-on / brand / accent / text-3 那套），
   所以 10 套皮肤下都会自动跟着变，不会出现某一套皮肤里按钮看不清的情况。
   -------------------------------------------------------------------------- */
.sq-card .sq-body {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 9px 14px;
}
.sq-opts {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
}

/* 需求 #10：「在岗 / 待命 / 任务中 / 休假」四个按钮原先是一排各自带边框的
   灰药丸，选中态只是把边框染个色 —— 看着松松垮垮、也没有"这四个是一组
   单选"的语义。改成分段控件（segmented control）：
     · 外圈一个浅灰胶囊把所有选项圈起来，一眼看出"只能选一个"；
     · 每个选项自带一个状态圆点，颜色随状态走，不读文字也知道是哪种；
     · 选中项用该状态的浅底 + 同色描边 + 圆点加深外扩，落在灰底上很稳。
   尺寸一律不动（30px / 28px）—— 只是换画法，不占更多版面。 */
.sq-opt {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 13px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  transition: background .16s, color .16s, box-shadow .16s;
}
.sq-opt > .sq-dot {
  flex: 0 0 7px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--sq-tone, var(--text-3));
  opacity: .42;
  transition: opacity .16s, box-shadow .16s;
}
/* 每个状态一套色调，供圆点 / 选中态共用 */
.sq-opt.is-on      { --sq-tone: var(--ok);      --sq-bg: var(--ok-light);      --sq-bd: var(--ok-border);      --sq-ink: var(--ok-ink); }
.sq-opt.is-standby { --sq-tone: var(--brand);   --sq-bg: var(--brand-light);   --sq-bd: var(--brand-border);   --sq-ink: var(--brand-ink); }
.sq-opt.is-busy    { --sq-tone: var(--accent);  --sq-bg: var(--accent-light);  --sq-bd: var(--accent);         --sq-ink: var(--accent-ink); }
.sq-opt.is-off     { --sq-tone: var(--text-3);  --sq-bg: var(--surface-3);     --sq-bd: var(--border-strong);  --sq-ink: var(--text-2); }

.sq-opt:hover:not(:disabled) { color: var(--sq-ink, var(--brand-ink)); background: var(--surface); }
.sq-opt:hover:not(:disabled) > .sq-dot { opacity: .8; }
.sq-opt:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.sq-opt:disabled { opacity: .5; cursor: not-allowed; }
.sq-opt:disabled > .sq-dot { opacity: .25; }

/* 选中项：浅底 + 同色描边 + 圆点点亮并向外扩一圈同色光晕 */
.sq-opt.is-cur {
  color: var(--sq-ink);
  background: var(--sq-bg);
  box-shadow: inset 0 0 0 1px var(--sq-bd);
}
.sq-opt.is-cur > .sq-dot {
  opacity: 1;
  box-shadow: 0 0 0 3px var(--sq-bg);
}
/* 当前「在岗」加一圈缓慢呼吸的光晕 —— 只有一个状态值得被强调：
   调度员扫一眼后台就知道这个人现在能不能派。 */
.sq-opt.is-on.is-cur > .sq-dot { animation: sqPulse 2.4s ease-in-out infinite; }
@keyframes sqPulse {
  0%, 100% { box-shadow: 0 0 0 3px var(--ok-light); }
  50%      { box-shadow: 0 0 0 5px var(--ok-light); }
}
@media (prefers-reduced-motion: reduce) {
  .sq-opt.is-on.is-cur > .sq-dot { animation: none; }
}

.sq-note { flex: 1 1 170px; min-width: 130px; height: 30px; font-size: 13px; }
.sq-vac { display: flex; flex: 1 1 100%; align-items: center; gap: 8px; flex-wrap: wrap; }
.sq-vac-label { font-size: 12.5px; color: var(--text-3); white-space: nowrap; }
.sq-vac .input { height: 30px; max-width: 190px; font-size: 13px; }
/* 「点了「休假」但没填日期」时的就地提示。做成 flex:1 1 100% 自己占一行，
   而不是挤在日期框右边 —— 窄屏上那点宽度会让日期框被压变形。
   只在真缺日期时才出现，平时不占高度。 */
.sq-vac-msg { flex: 1 1 100%; font-size: 12px; color: var(--danger); }
.sq-hint { flex: 1 1 100%; font-size: 12px; color: var(--text-3); }

/* 更矮的一档：后台首页用。按钮缩到 28px，不留备注框 */
.sq-card.is-compact .sq-body { padding: 8px 12px; gap: 6px; }
.sq-card.is-compact .sq-opt  { height: 28px; padding: 0 11px; font-size: 12.5px; }
.sq-card.is-compact .sq-opt > .sq-dot { flex-basis: 6px; width: 6px; height: 6px; }

@media (max-width: 640px) {
  .sq-card .sq-body { padding: 8px 10px; }
  .sq-opts { width: 100%; justify-content: space-between; }
  .sq-opt { height: 28px; padding: 0 10px; font-size: 12.5px; gap: 5px; }
  .sq-opt > .sq-dot { flex-basis: 6px; width: 6px; height: 6px; }

  .sq-note { flex: 1 1 100%; }
}

/* ==========================================================================
   系统设置 · 首页版式选择（需求 #2 追加项）
   --------------------------------------------------------------------------
   五套风格改的是**版面**（首屏骨架 + 数据列数 + 留白），不是配色 ——
   光看名字（"聚焦大屏""数据网格"）管理员分不出差别，所以要给一张版面示意图。

   示意图用纯 CSS 画：一个 10×5 的网格，四个 <i> 按各自的 grid-area 摆位。
   数据区那条用 repeating-linear-gradient 画出竖条纹，表示"这里是一排指标"，
   2 条 vs 5 条一眼可辨 —— 比塞一张 PNG 好在：跟着皮肤换色、不占体积、
   也不会在 Retina 屏上糊。

   这套样式只服务后台设置页，所以与首页的 .home-root 无关，
   是 app.css 的正当内容，不需要挂 [data-home] 前缀。
   ========================================================================== */
.hs-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
}
.hs-card {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 13px 14px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  transition: border-color .16s, background .16s, box-shadow .16s;
}
.hs-card:hover { border-color: var(--brand-border); background: var(--brand-lighter); }
.hs-card.is-cur { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-glow, rgba(29,95,208,.14)); }
.hs-card input { position: absolute; opacity: 0; pointer-events: none; }

.hs-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.hs-name { font-size: 13.5px; font-weight: 700; color: var(--text-1); }
.hs-name em { font-style: normal; font-weight: 500; font-size: 11.5px; color: var(--text-3); margin-left: 4px; }
.hs-desc { font-size: 11.5px; line-height: 1.7; color: var(--text-3); }

/* 版面示意图：10 列 × 5 行的小网格 */
.hs-bone {
  flex: 0 0 auto;
  display: grid;
  width: 112px;
  height: 68px;
  padding: 7px;
  gap: 4px;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(5, 1fr);
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--brand);
}
.hs-bone i { display: block; border-radius: 2.5px; background: currentColor; opacity: .26; }

/* 条纹：把一条指标区画成"一排若干列"，列数即 data-bone 想表达的密度 */
.hs-bone i:nth-child(3) {
  background-image: repeating-linear-gradient(90deg, currentColor 0 46%, transparent 46% 100%);
}

/* ① classic · 左文右数（默认版式） */
.hs-bone[data-bone="split"] i:nth-child(1) { grid-area: 1 / 1 / 3 / 6; opacity: .42; }
.hs-bone[data-bone="split"] i:nth-child(2) { grid-area: 3 / 1 / 4 / 6; opacity: .20; }
.hs-bone[data-bone="split"] i:nth-child(3) { grid-area: 1 / 7 / 4 / 11; opacity: .30; }
.hs-bone[data-bone="split"] i:nth-child(4) { grid-area: 4 / 1 / 6 / 11; opacity: .15; }

/* ② spotlight · 居中聚焦：标题与数据都居中，指标横排一整条 */
.hs-bone[data-bone="centered"] i:nth-child(1) { grid-area: 1 / 3 / 2 / 9; opacity: .45; }
.hs-bone[data-bone="centered"] i:nth-child(2) { grid-area: 2 / 4 / 3 / 8; opacity: .20; }
.hs-bone[data-bone="centered"] i:nth-child(3) {
  grid-area: 3 / 1 / 4 / 11;
  background-image: repeating-linear-gradient(90deg, currentColor 0 17%, transparent 17% 20%);
  opacity: .38;
}
.hs-bone[data-bone="centered"] i:nth-child(4) { grid-area: 4 / 1 / 6 / 11; opacity: .15; }

/* ③ grid · 数据网格：首屏压成一条信息带，指标一行铺开，留白压缩 */
.hs-bone[data-bone="band"] { grid-template-rows: repeat(4, 1fr); }
.hs-bone[data-bone="band"] i:nth-child(1) { grid-area: 1 / 1 / 2 / 4; opacity: .42; }
.hs-bone[data-bone="band"] i:nth-child(2) { grid-area: 1 / 4 / 2 / 11; opacity: .20; }
.hs-bone[data-bone="band"] i:nth-child(3) {
  grid-area: 2 / 1 / 3 / 11;
  background-image: repeating-linear-gradient(90deg, currentColor 0 17%, transparent 17% 20%);
  opacity: .38;
}
.hs-bone[data-bone="band"] i:nth-child(4) { grid-area: 3 / 1 / 5 / 11; opacity: .16; }

/* ④ split · 左右分栏：左边一条窄的速览栏，右边大字 */
.hs-bone[data-bone="rail"] i:nth-child(1) { grid-area: 1 / 4 / 4 / 11; opacity: .42; }
.hs-bone[data-bone="rail"] i:nth-child(2) { grid-area: 4 / 4 / 5 / 11; opacity: .20; }
.hs-bone[data-bone="rail"] i:nth-child(3) {
  grid-area: 1 / 1 / 5 / 3;
  background-image: repeating-linear-gradient(180deg, currentColor 0 20%, transparent 20% 25%);
  opacity: .30;
}
.hs-bone[data-bone="rail"] i:nth-child(4) { grid-area: 5 / 1 / 6 / 11; opacity: .15; }

/* ⑤ editorial · 画报留白：大标题、窄栏、上下留白最多 */
.hs-bone[data-bone="airy"] i:nth-child(1) { grid-area: 2 / 2 / 3 / 10; opacity: .45; }
.hs-bone[data-bone="airy"] i:nth-child(2) { grid-area: 3 / 4 / 4 / 8; opacity: .20; }
.hs-bone[data-bone="airy"] i:nth-child(3) {
  grid-area: 4 / 1 / 5 / 11;
  background-image: repeating-linear-gradient(90deg, currentColor 0 17%, transparent 17% 20%);
  opacity: .34;
}
.hs-bone[data-bone="airy"] i:nth-child(4) { display: none; }

/* ==========================================================================
   39. 档案材料与身体信息（需求 #14 / #15 / #18）
   ========================================================================== */

/* --- 39.1 flex 间距工具类 ---
   .flex / .items-center 早就有了，但一直没有配套的 gap ——
   于是页面里写 class="flex items-center gap-4" 时，gap-4 是个不存在的类，
   实际间距为 0，按钮和输入框贴着长在一起。这种"少块角"靠读代码看不出来
   （class 名字看着很合理），所以补齐这三个最常用的档位。 */
.gap-4 { gap: 4px; }
.gap-6 { gap: 6px; }
.gap-8 { gap: 8px; }

/* --- 39.2 锁定后的只读展示 ---
   身体信息填过之后不再渲染输入框，改用这个块展示值。
   高度刻意跟 .input 对齐（38px），这样"填写前 / 填写后"切换时页面不会跳。 */
.readonly-val {
  min-height: 38px;
  display: flex;
  align-items: center;
  padding: 7px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 13.5px;
  line-height: 1.5;
  word-break: break-word;
}
.readonly-val.strong { color: var(--text); font-weight: 600; }

/* --- 39.3 材料附件展示 --- */
.doc-file { display: flex; align-items: center; gap: 10px; }
.doc-thumb {
  width: 56px; height: 56px;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--surface-2);
}
.doc-pdf {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: 12.5px;
  text-decoration: none;
  max-width: 100%;
}
.doc-pdf:hover { border-color: var(--brand); color: var(--brand); }
.doc-pdf span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- 39.4 「申请变更」折叠入口 ---
   默认收起。理由：绝大多数人一辈子不需要改身体信息，
   把一整套变更表单常驻在页面上，只会把真正要看的信息挤下去。 */
.doc-more > summary {
  cursor: pointer;
  font-size: 12.5px;
  color: var(--brand);
  padding: 6px 0;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.doc-more > summary::-webkit-details-marker { display: none; }
.doc-more > summary::before { content: '▸'; font-size: 10px; transition: transform .15s; }
.doc-more[open] > summary::before { transform: rotate(90deg); }
.doc-more > summary:hover { text-decoration: underline; }

/* --- 39.5 迷你进度条（齐备度矩阵用） --- */
.mini-bar {
  height: 6px;
  border-radius: 3px;
  background: var(--surface-3, var(--surface-2));
  overflow: hidden;
  margin-bottom: 4px;
}
.mini-bar > span {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--brand);
  transition: width .2s;
}
.mini-bar > span.is-ok   { background: var(--ok); }
.mini-bar > span.is-warn { background: var(--warn); }

/* --- 39.6 分段切换（待审队列 / 齐备度 / 全部记录） ---
   用链接实现而不是 JS：这三个视图各自是一次独立的服务端查询，
   做成前端切换就得把三份数据都渲染出来（材料记录可能上千条），
   而且刷新后会跳回第一个标签，用户分享链接也带不上视图。 */
.tabs-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 14px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0;
}
.tab {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  font-size: 13px;
  color: var(--text-2);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab:hover { color: var(--text); }
.tab.is-active { color: var(--brand); border-bottom-color: var(--brand); font-weight: 600; }

@media (max-width: 700px) {
  .doc-thumb { width: 46px; height: 46px; }
  .tab { padding: 7px 10px; font-size: 12.5px; }
  .readonly-val { font-size: 13px; }
}

/* ==========================================================================
   40. 任务时长结算表（需求 #5）
   --------------------------------------------------------------------------
   用户对管理页的要求是「不要明明一个很小的按钮、编辑框就可以解决的，
   非要把 UI 画很大，这样会造成填写基础的信息都要大幅度滑动页面」。
   所以这一节只做两件事：
     ① 把列宽压到刚好够用，让 8 列能塞进内容区而不出横向滚动条；
     ② 「修正」的展开表单单独占一整行（colspan），并且用 4 列窄栅格 ——
        每个输入框一行一个的话，改一个人的时长要往下翻 4 屏。
   ========================================================================== */

/* --- 40.1 结算表列宽 --- */
.table-mini th.col-grp, .table-mini td.col-grp { width: 132px; }
.table-mini th.col-st,  .table-mini td.col-st  { width: 74px; }
.table-mini th.col-h,   .table-mini td.col-h   { width: 76px; }
.table-mini th.col-k,   .table-mini td.col-k   { width: 56px; }
/* 需求 #79-5：新增「签到 / 签退」两列。
   92px 是「09-29 08:30」单行放下的最小宽度；
   不给这两列定宽的话，它们会去抢「队员」列的宽度，
   长姓名被挤成两行，整张表的行高跟着被撑高。 */
.table-mini th.col-t,   .table-mini td.col-t   { width: 92px; }
/* 操作列从 60px 放宽到 138px：现在要同时站下「代签到/代签退」与「修正」两个按钮，
   60px 会把它们压成上下两行、把行高拉高一倍。 */
.table-mini th.col-act, .table-mini td.col-act { width: 138px; text-align: right; }

/* --- 40.2 卡片头里并排的小表单（重新结算按钮） --- */
.inline-form { display: inline-flex; align-items: center; margin: 0; }

/* --- 40.3 展开行 --- */
tr.row-detail > td {
  background: var(--surface-2, #f7f9fc);
  padding: 10px 12px;
}
.adjust-form { margin: 0; }
.adjust-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px 10px;
}
/* 展开行里的输入框一律压到 32px —— 这里是"补个数字"的场景，不是主表单 */
.adjust-grid .input,
.adjust-grid .select { height: 32px; font-size: 13px; padding: 0 8px; }
.adjust-grid .field { margin: 0; }
.adjust-grid .field > label {
  font-size: 12px;
  color: var(--text-3, #7a8699);
  margin-bottom: 3px;
  display: block;
}
.adjust-grid .hint { font-size: 11.5px; }
.adjust-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
}
.adjust-foot > .btn, .adjust-foot > button { margin-left: auto; }

/* 展开按钮的"已展开"态：给一点视觉反馈，否则第二次点不知道是收起还是又展开 */
.btn.is-on { background: var(--brand-soft, rgba(29, 95, 208, .1)); color: var(--brand); }

@media (max-width: 900px) {
  .adjust-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* 手机上列宽固定会直接撑出横向滚动条，这里放开让内容自己决定 ——
   结算表在手机上本来也看不全，横向能滑比被压成乱码强。 */
@media (max-width: 700px) {
  .table-mini th.col-grp, .table-mini td.col-grp,
  .table-mini th.col-st,  .table-mini td.col-st,
  .table-mini th.col-h,   .table-mini td.col-h,
  .table-mini th.col-k,   .table-mini td.col-k { width: auto; }
  .adjust-grid { grid-template-columns: minmax(0, 1fr); }
  .adjust-foot { flex-wrap: wrap; }
  .adjust-foot > .btn, .adjust-foot > button { margin-left: 0; width: 100%; }
}

/* ==========================================================================
   41. 简报模板条 / 占位符按钮（需求 #5）
   --------------------------------------------------------------------------
   用户反复强调的一条：「不要明明一个小按钮、编辑框就可以解决的，非要把 ui 画很大，
   这样会造成填写基础的信息都要大幅度滑动页面」。所以这里全部按"一行放得下"来做：
     · 模板条是一排可换行的小胶囊，不占卡片高度，不做成 6 张卡片；
     · 占位符按钮 22px 高，一行能放十来个；
     · 提示只占一行小字，不弹窗、不占块。
   ========================================================================== */

/* --- 41.1 模板条（填写简报页） --- */
.brief-tpl-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 10px;
  margin-bottom: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2, #f7f9fc);
}
.brief-tpl-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-3, #7a8699);
  white-space: nowrap;
}
.brief-tpl-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 26px;
  padding: 0 10px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1;
  border: 1px solid var(--border-strong, #cfd8e3);
  border-radius: 999px;
  background: var(--surface, #fff);
  color: var(--text-1);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s, background .15s, color .15s;
}
.brief-tpl-chip:hover { border-color: var(--brand); color: var(--brand); }
.brief-tpl-chip .btc-hit {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--brand);
  background: var(--brand-soft, rgba(29, 95, 208, .1));
  border-radius: 999px;
  padding: 1px 5px;
}
.brief-tpl-chip.is-on {
  border-color: var(--brand);
  background: var(--brand-soft, rgba(29, 95, 208, .1));
  color: var(--brand);
}
.brief-tpl-tip {
  margin-top: 8px;
  padding: 6px 10px;
  font-size: 12px;
  line-height: 1.55;
  border-radius: var(--radius-sm);
  background: var(--brand-soft, rgba(29, 95, 208, .08));
  color: var(--brand-dark, #17499f);
}
.brief-tpl-tip.is-hidden { display: none; }

/* --- 41.2 占位符按钮（后台简报模板页） --- */
.form-section-title .fst-note {
  float: right;
  font-weight: 500;
  font-size: 11.5px;
  color: var(--text-3, #7a8699);
}
/* ★ 需求 6（本轮）：窄屏上说明文字**不浮动**。
   390px 宽的卡片里，一行 30 多字的说明浮动后就占满整行并折成两三行，
   标题被挤得只剩一条缝（"通用审批"四个字竖着排）。
   改成块级独占一行后，顺序变成「标题 → 说明」，
   既不用再跟标题抢宽度，读起来也是先结论后解释。 */
@media (max-width: 860px) {
  .form-section-title .fst-note { float: none; display: block; }
}
.ph-bar {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
  margin: 6px 0 8px;
}
.ph-chip {
  height: 22px;
  padding: 0 7px;
  font-size: 11px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  line-height: 1;
  color: var(--brand);
  background: var(--brand-soft, rgba(29, 95, 208, .08));
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
}
.ph-chip:hover { border-color: var(--brand); }
.ph-chip:active { background: var(--brand); color: #fff; }

/* 正文模板用等宽字体看结构更清楚（读一、二、三的层级和占位符都更省眼） */
.textarea.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; line-height: 1.7; }

/* 手机端：模板条横向可滚，避免 6 个胶囊换 4 行把正文推下去 */
@media (max-width: 700px) {
  .brief-tpl-bar { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .brief-tpl-chip { flex: 0 0 auto; height: 30px; }
}

/* --- 41.3 保险附件列表（需求 #18）---
   一行一个附件：类型徽章 + 名称 + 预览/查看 + 删除。
   不做成大卡片 —— 一支队一年也就几十张保单，但一屏能看全比"滚着找"重要。 */
.ins-list { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.ins-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.ins-badge {
  flex: 0 0 auto;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
  padding: 4px 6px;
  border-radius: 4px;
  background: var(--brand-soft, rgba(29, 95, 208, .1));
  color: var(--brand);
}
.ins-name {
  font-size: 13px;
  color: var(--text-1);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ins-name:hover { color: var(--brand); text-decoration: underline; }
.ins-thumb {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
  cursor: zoom-in;
}
@media (max-width: 700px) {
  .ins-item { flex-wrap: wrap; }
  .ins-thumb { width: 48px; height: 48px; }
}

/* --- 41.4 工作台快捷入口的「有待办」态（需求 #13 / #15 / #18）---
   只改文字与底色，**不动尺寸** —— 后台首页的快捷操作是一排小按钮，
   为了提示"有 N 件待审"把按钮撑大，反而把下面真正要看的卡片挤出去。
   待办清空后这个类会被去掉，按钮自动回到普通态。 */
.btn-soft.is-warn {
  background: var(--warn-light);
  color: var(--warn-ink);
}
.btn-soft.is-warn:hover {
  background: #F7E7C6;
  color: var(--warn-ink);
}

/* --- 41.5 可输入下拉选择（smart-select）---
   人员等长列表的选择控件：「输入框 + 就地过滤的候选列表」，替代原生 <select>。
   为什么另起一套而不是复用 .select：
     · 原生下拉在几百号人时只能靠眼睛扫，用户明确反馈"很难选择"；
     · 选中项与候选列表要能同时显示（多选时还要能逐个撤），
       .select 的结构撑不起这两件事。
   视觉上沿用 .input 的描边与圆角，因此在表单里看不出是"另一种控件"。
   原生 <select> 由 .smart-native 藏起来 —— 只在有 JS 时隐藏，
   没 JS 时它就是普通下拉，功能不丢。 */
.smart-native { display: none; }

.smart { position: relative; }

.smart-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  min-height: 36px;
  padding: 4px 9px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  transition: border-color .15s, box-shadow .15s;
}
.smart.is-open .smart-box {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-light);
}
.smart.is-invalid .smart-box { border-color: var(--danger); }

.smart-input {
  flex: 1 1 90px;
  min-width: 80px;
  height: 26px;
  padding: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
}
.smart-input::placeholder { color: var(--text-3); }

/* 多选的胶囊区：空的时候只有一行灰字，不占高度 */
.smart-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.smart-multi .smart-chips { flex: 1 1 100%; }
.smart-chips:empty { display: none; }
.smart-chips-ph { color: var(--text-3); font-size: 12.5px; }
.smart-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 100%;
  padding: 3px 5px 3px 9px;
  border: 1px solid var(--brand-border);
  border-radius: 999px;
  background: var(--brand-light);
  color: var(--brand-dark);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.5;
}
.smart-chip-x {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: rgba(29, 95, 208, .14);
  color: var(--brand-dark);
  font-size: 12px;
  font-style: normal;
  line-height: 15px;
  text-align: center;
  cursor: pointer;
}
.smart-chip-x:hover { background: var(--danger); color: #fff; }

/* 候选列表：绝对定位浮层，最多 260px 高后内部滚动 */
.smart-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 3px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: 0 10px 26px rgba(15, 23, 42, .16);
}
.smart-item {
  display: block;
  width: 100%;
  padding: 7px 9px;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.smart-item:hover,
.smart-item.is-hi { background: var(--brand-lighter); }
.smart-item.is-picked { color: var(--brand); font-weight: 700; }
.smart-item.is-picked::after { content: " ✓"; }
.smart-empty {
  padding: 12px 9px;
  color: var(--text-3);
  font-size: 12.5px;
  text-align: center;
}
.smart-warn {
  margin-top: 5px;
  color: var(--danger);
  font-size: 12px;
}

/* 手机端：候选行加大触控目标，胶囊换行更紧凑 */
@media (max-width: 700px) {
  .smart-item { padding: 10px 10px; font-size: 14px; }
  .smart-menu { max-height: 220px; }
  .smart-box { min-height: 40px; }
}

/* ---------- 41.6 任务人员指派（需求 #4 / #12） ---------- */

/* 经纬度：一格两个小输入框。做成两格会把「经纬度」这件事拆到两个标签上，
   填表的人得自己判断哪个是纬度；并排放在一起、各自带 placeholder 更省一次思考。 */
.coord-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

/* 非一线岗位指派：表头 + 可增删的行。
   列宽用 fixed 第一列（人员）拿自适应、后三列定宽 —— 岗位名最长 4 个字、
   系数最多 4 字符，「移除」按钮也不需要宽，给它们定宽能把空间让给人员那一格。 */
.rp-wrap { display: block; }
.rp-head,
.rp-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 120px 96px 62px;
  gap: 8px;
  align-items: center;
}
.rp-head {
  padding: 0 2px 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.rp-head > span {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
}
.rp-row { margin-bottom: 8px; }
.rp-cell { min-width: 0; }
.rp-cell .select,
.rp-cell .input { width: 100%; }
.rp-cell .btn { width: 100%; }
.rp-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 4px;
}
@media (max-width: 760px) {
  /* 窄屏：岗位与系数并排一行，「移除」独占一行右侧，避免英文按钮文字被压断 */
  .rp-head { display: none; }
  .rp-row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
  }
  .rp-cell:nth-child(4) { grid-column: span 2; }
  .rp-cell:nth-child(4) .btn { width: auto; }
}

/* 结算表展开区里的第二张表单（岗位与系数）—— 用一条虚线把它与"修正时间/奖励"分清楚，
   两张表单叠在一起时如果不分隔，会让人以为下面那组字段属于上面那个保存按钮。 */
.rp-adjust {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
}

/* ---------- 41.7 任务列表的状态筛选按钮（需求 #6） ----------
   五个状态一行摆开、可多选。做成胶囊按钮而不是标签页（tabs），
   是因为它允许**叠加**：标签页是"单选"的语义，用它表达多选会让用户
   以为点了新的就取消了旧的。 */
.mf-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  align-items: center;
}
.mf-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  text-decoration: none;
  white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s;
}
.mf-btn:hover { border-color: var(--border-strong); color: var(--text); background: var(--surface-2); }
.mf-btn.is-on {
  border-color: var(--brand);
  background: var(--brand-lighter);
  color: var(--brand);
  font-weight: 600;
}
.mf-n {
  display: inline-block;
  min-width: 18px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-3);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.mf-btn.is-on .mf-n { background: var(--brand); color: #fff; }
/* 选中时按状态色调走，和列表里的状态徽标一眼对得上 */
.mf-btn.is-on.tone-warn   { border-color: var(--warn);   background: var(--warn-light);   color: var(--warn-ink); }
.mf-btn.is-on.tone-warn .mf-n   { background: var(--warn); }
.mf-btn.is-on.tone-danger { border-color: var(--danger); background: var(--danger-light); color: var(--danger-ink); }
.mf-btn.is-on.tone-danger .mf-n { background: var(--danger); }
.mf-btn.is-on.tone-ok     { border-color: var(--ok);     background: var(--ok-light);     color: var(--ok-ink); }
.mf-btn.is-on.tone-ok .mf-n     { background: var(--ok); }
.mf-clear { color: var(--text-3); border-style: dashed; }
@media (max-width: 620px) {
  .mf-btn { padding: 7px 10px; font-size: 12px; }
}

/* ==========================================================================
   42. 样式补漏（需求 #9 · 自检产物）
   --------------------------------------------------------------------------
   怎么来的：写了一个「把 PHP 里所有 class="…" 抽出来，逐个回 CSS 里找规则」
   的审计脚本，把只在标记里出现、CSS 里查无此类的挑出来。
   剩下的都是**真正的漏网之鱼** —— 它们在页面上表现为"这段没有样式"，
   而因为周围元素是好的，肉眼很容易以为是浏览器缓存问题。

   这一类 bug 的共同点是：**加的时候忘了同步写规则**，
   所以每次加完新页面/新组件都要把这个审计再跑一遍。
   脚本：.dev-tools/maintain/css_audit.js（随包发布，运维可自查）。
   ========================================================================== */

/* --- 42.1 缺的间距 / 对齐工具类 --------------------------------------------
   .mb-12 / .mt-12 / .gap-12 这些早就有，但 .mb-10 / .mb-14 / .mt-6 没补，
   于是 <div class="field mb-10"> 之类写上去完全没有效果 —— 表单挤在一起。 */
.mb-10 { margin-bottom: 10px; }
.mb-14 { margin-bottom: 14px; }
.mt-6  { margin-top: 6px; }
.text-center { text-align: center; }
.text-right, .ta-r { text-align: right; }

/* 段落里的行内跳转链接：不带下划线、hover 才出现，避免正文花 */
.link {
  color: var(--brand);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color .14s;
}
.link:hover { border-bottom-color: var(--brand); }

/* --- 42.2 档案打印件（member_public.php）身份卡主体 -----------------------
   .ad-idcard 是 display:flex（头像 + 主体）。少了 .ad-idmain 的 flex:1 /
   min-width:0，长名字 + 多个职务时主体不会收缩，会把头像挤到卡片外。
   注意：这些规则原本只在 .archive-doc 打印作用域里，屏幕上也该成立。 */
.archive-doc .ad-idmain,
.ad-idmain {
  flex: 1 1 auto;
  min-width: 0;
}

/* --- 42.3 入队指引首屏两栏（join_us.php）--------------------------------
   .join-hero-inner 是 1.15fr / .85fr 的两列 grid，两个孩子本身不需要规则；
   但缺 min-width:0 时，右栏的四格数据卡在窄屏会把整行撑出横向滚动条。 */
.jh-left,
.jh-right { min-width: 0; }

/* --- 42.4 对外公告页首屏（announcements_public.php）---------------------
   这一页直接用了 .page-hero，但这个类从来没被定义过 ——
   标题与说明以默认字号贴在一起，与站内其他对外页完全不像一套。 */
.page-hero {
  padding: 34px 0 22px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 18px;
}
.page-hero h1 {
  margin: 0 0 8px;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: .5px;
  color: var(--text);
}
.page-hero p {
  margin: 0;
  max-width: 660px;
  font-size: 13.5px;
  line-height: 1.8;
  color: var(--text-3);
}
/* 宽屏时给一条左侧品牌竖线，视觉上把"页头"和"列表"分开 */
@media (min-width: 860px) {
  .page-hero { padding-left: 16px; border-left: 3px solid var(--brand); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
}

/* --- 42.5 后台页头（admin/review_flows.php 等）--------------------------
   后台的 .page-head 是老写法：标题在左、操作按钮在右。
   .table-tool / .card-head 用得多，页级标题一直没有对应类。 */
.page-head {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0 0 14px;
}
.page-head > h2,
.page-head > h1 { margin: 0; font-size: 17px; font-weight: 700; color: var(--text); }
.page-head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-left: auto;
}
.page-desc {
  flex: 1 1 100%;
  margin: 0;
  font-size: 12.5px;
  line-height: 1.75;
  color: var(--text-3);
}


/* --- 42.7 状态快切表单（includes/status_quick.php）---------------------
   表单本身靠内层 .sq-* 组件撑起来，外层不需要边框；
   显式写出来是为了让"审计脚本"不再把它报成漏网之鱼。 */
.sq-form { display: block; }

/* --- 42.8 档案打印件的个人介绍 / 屏幕公开主页的个人介绍（需求 #79-8）------
   .ad-intro 是打印件里那一段自述（member_public.php 的 .archive-doc）。
   .ph-bio 是屏幕上公开主页档案卡下面那一段。
   两者语义一样（都是本人自述），但一个要走打印墨色、一个要走屏幕主题色，
   所以不合并成一个类 —— 合并之后改打印样式会连带把屏幕配色改掉。 */
.ad-intro {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.9;
  color: #333;
  text-align: justify;
  word-break: break-word;
}
.ad-intro .ad-none { color: #999; }
/* 打印时给自述加一条左侧细线，与上下的表格区分开 —— 纯文字段落夹在两张
   表格中间，容易被当成表格的脚注。 */
@media print {
  .ad-intro { padding-left: 10px; border-left: 2px solid #ddd; }
}
.ph-bio {
  margin: 0 0 16px;
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border-left: 3px solid var(--brand);
  font-size: 13.5px;
  line-height: 1.85;
  color: var(--text);
  white-space: pre-line;
  word-break: break-word;
}
@media (max-width: 560px) {
  .ph-bio { font-size: 13px; padding: 11px 12px; }
}


/* ==========================================================================
   43. 紧凑行内字段（.field-sm / .input-sm）

   为什么单独一档，而不是继续用 .field ——
   需求 #15 的党团妇工页里，一个类别要在**一行**里放 6 个字段
   （组织名称 / 组织关系所在地 / 职务 / 加入时间 / 状态 / 备注）。
   用默认的 .field + .form-grid（minmax 200px + 每个 label 独占一行）
   会把这 6 个字段排成 6 行，四个类别下来就是 24 行，
   光是看完自己的资料就要滚三屏。用户的纪律是：
   「不要明明一个很小的按钮、编辑框就可以解决的，非要把 ui 画很大，
     这样会造成填写基础的信息都要大幅度滑动页面」。

   所以给「字段多、但每个都很短」的场景单独一档：
     · 控件高 36px → 30px、字号 13.5 → 12.5px
     · label 字号 12.5 → 11.5px、与控件的间隙 4 → 3px
   它不是 .input 的替代品：姓名、地址这类要完整输入的仍用默认尺寸。
   窄屏 700px 以下自动退回默认高度（见文末媒体查询），
   桌面省下的空间不拿手机的可点性去换。
   ========================================================================== */
.field-sm { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.field-sm > span { font-size: 11.5px; font-weight: 600; color: var(--text-3); }
.input-sm {
  min-height: 30px;
  padding: 4px 9px;
  font-size: 12.5px;
  border-radius: var(--radius-xs);
}
select.input-sm { padding-right: 26px; background-position: right 8px center; }
textarea.input-sm { min-height: 54px; }

@media (max-width: 700px) {
  /* 手机上 30px 低于可点尺寸，手指点不准会误触相邻字段 —— 还回默认高度 */
  .input-sm { min-height: 40px; padding: 8px 11px; font-size: 14px; }
  .field-sm > span { font-size: 12.5px; }
}

/* ==========================================================================
   44. 党团妇工（user/politics.php · admin/politics.php · 需求 #15）

   前台：四个类别各一块并列表单（一个人同一类别只有一条记录，
         所以没有"新增条目"这一步，见 user/politics.php 顶部注释）。
   后台：全队统计 + 比例条 + 领导班子名单（admin/politics.php）。
   ========================================================================== */

/* --- 44.1 前台：一个类别一块 ------------------------------------------- */
.pol-block {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  padding: 10px 12px 11px;
  margin-top: 10px;
}
/* 已填写的那一块给一条品牌色左描边：四个块长得一样，
   扫一眼要能立刻分出"哪几个我填过了"，而不是逐个读徽标。 */
.pol-block.is-filled { border-left: 3px solid var(--brand); padding-left: 10px; }

.pol-head {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  margin-bottom: 8px;
  color: var(--text-2);
}
.pol-head svg { flex: 0 0 auto; color: var(--brand); }
.pol-title { font-size: 13px; font-weight: 700; color: var(--text); }
/* 加入时间推到最右边：它是"注释"，不该和上面的状态徽标挤在一串 */
.pol-since { margin-left: auto; }

/* 6 个短字段一行排开。auto-fit + 148px 的下限：
   内容区约 900px 时正好 6 列；窄到 600px 时退成 3~4 列；
   再窄由 700px 媒体查询接管成单列（那时输入框已恢复 40px）。 */
.pol-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 8px 10px;
  align-items: end;
}
/* 按钮作为栅格里的普通一格，跟在最后一个字段后面 —— 不另起一行，
   否则 6 个字段 + 一条只有两个小按钮的空行，白占 40px 高度。 */
.pol-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* --- 44.2 后台：比例条 ------------------------------------------------- */
.pol-ratio {
  display: flex;
  height: 14px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  /* 轨道用最浅的一档（surface-2 #FAFBFE）而不是 surface-3（#F2F2F7）：
     「群众」那一段是 border-strong（#D2DAE8），和 surface-3 只差一点点，
     两条灰叠在一起时看不出分界，整条比例尺会像"只填了 56%"。
     轨道压到近白之后，四段的分界才清楚。 */
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.pol-ratio > span { display: block; min-width: 0; transition: flex-basis .3s ease; }
.pol-ratio .is-party  { background: var(--danger); }
.pol-ratio .is-league { background: var(--brand); }
.pol-ratio .is-other  { background: var(--warn); }
.pol-ratio .is-masses { background: var(--border-strong); }
@media (prefers-reduced-motion: reduce) {
  .pol-ratio > span { transition: none; }
}

.pol-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 9px;
  font-size: 12px;
  color: var(--text-2);
}
.pol-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.pol-legend .swatch {
  width: 10px; height: 10px; border-radius: 3px;
  flex: 0 0 10px;
  background: var(--surface-3);
}
.pol-legend .swatch.is-party  { background: var(--danger); }
.pol-legend .swatch.is-league { background: var(--brand); }
.pol-legend .swatch.is-other  { background: var(--warn); }
.pol-legend .swatch.is-masses { background: var(--border-strong); }
.pol-legend b { color: var(--text); }

/* --- 44.3 后台：领导班子名单 ------------------------------------------ */
.pol-leads {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 10px;
}
.pol-lead {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: 10px 12px;
}
.pol-lead-head {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.pol-lead-head .pol-ava {
  width: 36px; height: 36px;
  border-radius: 50%;
  flex: 0 0 36px;
  object-fit: cover;
  background: var(--surface-3);
  display: grid;
  place-items: center;
  color: var(--text-3);
  font-size: 13px;
  font-weight: 700;
  overflow: hidden;
}
.pol-lead-name {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.pol-lead-role { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
/* 这个人身上挂的党团妇工徽标（可能一个都没有 —— 那是正常的，
   不是所有队干部都必须是党员，空着就不显示这一行）。 */
.pol-badges { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.pol-badges .badge { font-size: 11px; padding: 1px 8px; }
.pol-lead-empty { font-size: 12px; color: var(--text-3); }

/* ==========================================================================
   富文本编辑器（需求 #78-5）
   --------------------------------------------------------------------------
   工具栏刻意做小：字号 12px、按钮高 26px —— 与项目里其它 inline 控件同级。
   用户反复强调过「小按钮 / 编辑框能解决的不要画大」，一个正文输入框
   顶上一排 40px 的大按钮，是把录入区变成"仪表盘"，不是排版。
   编辑区用 max-height + 内滚，而不是让它随内容无限长高：
   否则在手机上发布一条长公告，保存按钮会被推到屏幕外好几屏。
   ========================================================================== */
.rt {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
  transition: border-color .16s, box-shadow .16s;
}
.rt:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(29, 95, 208, .12);
}
.rt-bar {
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
  padding: 4px 6px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.rt-btn {
  height: 26px;
  min-width: 26px;
  padding: 0 7px;
  font-size: 12px;
  line-height: 1;
  color: var(--text-2);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: background .14s, color .14s, border-color .14s;
}
.rt-btn:hover { background: var(--surface-hover); color: var(--text); border-color: var(--border); }
.rt-btn:active { background: var(--brand-light); color: var(--brand-dark); border-color: var(--brand-border); }
.rt-tip { margin-left: auto; padding-left: 8px; font-size: 11.5px; color: var(--text-3); }
.rt-area {
  padding: 9px 11px;
  font-size: 13.5px;
  line-height: 1.72;
  color: var(--text);
  outline: none;
  overflow-y: auto;
  max-height: 46vh;
}
/* 占位提示：contenteditable 不能用 placeholder 属性，只能用 :empty 伪元素 */
.rt-area:empty:before { content: attr(data-placeholder); color: var(--text-3); }
.rt-area p { margin: 0 0 9px; }
.rt-area p:last-child { margin-bottom: 0; }
.rt-area h3 { margin: 12px 0 7px; font-size: 15px; font-weight: 700; color: var(--text); }
.rt-area h3:first-child { margin-top: 0; }
.rt-area ul, .rt-area ol { padding-left: 22px; margin: 0 0 9px; }
.rt-area li { margin-bottom: 3px; }
.rt-area blockquote {
  margin: 0 0 9px;
  padding: 6px 11px;
  border-left: 3px solid var(--brand-border);
  background: var(--surface-2);
  color: var(--text-2);
}
.rt-area a { color: var(--brand); text-decoration: underline; }
.rt-area img { max-width: 100%; border-radius: var(--radius-sm); }
@media (max-width: 700px) {
  /* 手机上工具栏横滑而不是换行：8 个按钮换行会占掉 3 行高度，
     正文区被压到只剩两行，发布一条通知要先滚工具栏。 */
  .rt-bar { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .rt-btn { flex: 0 0 auto; }
  .rt-tip { display: none; }
  .rt-area { max-height: 40vh; }
}

/* 前台 / 详情展示：引用段落与首元素收口
   （.rich-text 原有规则里没有 blockquote，加了排版功能后不补上，
     引用段会变成一段没有任何缩进标记的普通文字，等于白点那个按钮） */
.rich-text blockquote {
  margin: 0 0 10px;
  padding: 7px 12px;
  border-left: 3px solid var(--brand-border);
  background: var(--brand-lighter);
  color: var(--text-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.rich-text > :first-child { margin-top: 0; }
.rich-text h3 { font-weight: 700; }

/* 老内容的 <div> 段落（需求 #78-5 补）
   升级前用 textarea 写正文的人，有人是用 <div> 分段的（旧 placeholder
   只举了 <p> 的例子，但没有禁止 div）。净化器保留 div（拆掉它会把
   段落语义一起丢掉、两段合成一段），所以这里必须补上段间距 ——
   否则"老公告的段落依旧挤在一起"，正是这条需求要修的现象。 */
.rich-text div, .rt-area div { margin: 0 0 10px; }
.rt-area div { margin-bottom: 9px; }
.rich-text div:last-child, .rt-area div:last-child { margin-bottom: 0; }

/* 说明：寻人启事（需求 #79-3）与红头文件通告（需求 #79-4）两个模块已整体删除，
   本文件里它们用过的 `.mp-*`（四种启事风格 + 列表卡）与 `.rh-*`（发布页风格卡 /
   前台版式 / 具名页 @page 打印）样式已一并移除（需求 #15「删掉寻人启事、
   删掉红头文件」）。
   为什么样式也要删、不能只删 HTML：留着不用的类名，下一个人翻样式表时
   会以为这两块 UI 还在，改版时还会去"修"它们。 */

/* ==========================================================================
   个人主页 · 培训履历（需求 #79-7）与档案头呼号（需求 #79-1）
   ========================================================================== */

/* 必修完成度条。
   为什么不用 .stat 那一套：这是卡片**内部**的一行读数，
   不是并列的统计格；用统计格会在卡片里再嵌一层格子，层级变吵。 */
.tch-req { margin-bottom: 14px; }
.tch-req-h {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 7px;
}
.tch-req-h .text-xs { flex: 1; min-width: 0; }
.tch-req-pct {
  font-size: 17px; font-weight: 700; color: var(--brand);
  font-variant-numeric: tabular-nums; letter-spacing: .3px;
}
/* 手机端：百分比换到下一行右对齐，避免把「已完成 3/5 门 · 课时 12/20 h」挤成两行碎字 */
@media (max-width: 560px) {
  .tch-req-h .text-xs { flex: 1 1 100%; order: 3; }
  .tch-req-pct { margin-left: auto; }
}

/* ==========================================================================
   后台 · 个人介绍与我的材料（需求 #79-8）
   ========================================================================== */

/* 个人介绍正文。
   用 pre-line 保留换行：介绍是本人手写的自述，分段是内容的一部分，
   压成一行读起来像流水账。 */
.mi-text {
  white-space: pre-line;
  line-height: 1.75;
  font-size: 13px;
  color: var(--text);
  word-break: break-word;
}

/* 表格里的折叠态：最多 3 行，超出打省略号。
   为什么用行数截断而不是按字数截：中英混排、有没有换行都会让"50 字"
   忽长忽短，行数截断才能保证每一行高度一致 —— 表格才不会被一条长介绍
   撑出 400px 的空白。展开走服务端（?open=ID 在原行渲染全文），
   不依赖 JS，也不会像弹窗那样盖住旁边的对照行。 */
.mi-text.is-clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

/* 材料文件的文件名：与图标同行、超长截断，避免一行文件名把「大小 / 时间」
   两列挤到看不见。完整名字在 title 上，鼠标停一下能看到。 */
.mf-name {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  font-size: 12px;
  line-height: 1.5;
}
.mf-name svg { flex: 0 0 auto; margin-top: 2px; }
.mf-name > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================================================
   需求 #1 · 手机端「错位」修复
   ==========================================================================
   用户报「手机版分类搜索错位 / 发布任务·报名指派页错位 / 任务模板底部一键发起
   错位 / 人员处罚错位 / 档案材料审核错位 / 简报模板错位 / 审批与财务错位」。

   这些页面看着各不相同，实际只有**两个**根因，都发生在窄屏：

   ① 顶栏动作区溢出 → 整页视口被撑宽
      实测（390 宽，admin/flows.php 与 admin/finance.php）：
        .topbar       盒子 390px、内容 416px   ← 26px 溢出
        .topbar-actions 里的页面级按钮 118px（「审批类型设置」「爱心公示」）
      顶栏一溢出，`position: fixed` 的底部导航与抽屉遮罩会按**溢出后的宽度**重排，
      于是整页看着像错位 —— 明明只有顶栏超出 26px。
      注意：`.topbar-actions` 在这之前被显式写成 `flex: 0 0 auto`（见文件上方 393 行
      的注释），是"动作区不参与压缩、由标题让位"的设计。该设计对图标类按钮成立，
      但页面级**纯文字链接**能到 118px，标题退到 0 之后仍然放不下。

   ② 裸表格的 560px 最小宽度 → 整页视口被撑宽
      实测（390 宽，admin/penalties.php）：
        table.table.table-mini  min-width: 560px  →  .app 被撑到 615px
      这张表**没有** `.table-wrap` 包着、也不是 `.table-stack`，
      于是 `@media (max-width:860px)` 里那条 `.table{min-width:560px}`
      直接作用在裸表上，把布局视口一路顶到 615px（是 390 的 1.58 倍）。
      手机端浏览器遇到"内容比视口宽"会把**布局视口**放大，
      所以用户看到的不是"只有表格能横向滑"，而是"整个页面被缩小、位置全偏"。

   另外补一条 `.table-stack` 的：卡片化之后桌面态的 `white-space: nowrap`
   仍然生效，单元格里的长文本不肯折行，卡片被撑到 462px
   （实测 admin/doc_review.php，溢出 85px）。
   ========================================================================== */

@media (max-width: 860px) {
  /* ② 窄屏表格：自己变成横向滚动容器，不再用 560px 最小宽度去撑整页。
     `display: block` 之后 thead/tbody 仍保持各自的 table-* 显示值，
     浏览器会用匿名 table 盒包住它们，列宽照常计算 —— 外观不变，只是能横滑。 */
  .table:not(.table-stack) {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    min-width: 0;
    max-width: 100%;
  }
  /* 已经在 .table-wrap 里的表不用再滚一层，交给外层容器 */
  .table-wrap > .table:not(.table-stack) {
    display: table;
    overflow: visible;
  }

  /* 卡片化表格（.table-stack）：卡片是上下排布的，
     桌面态留给表格的 nowrap 在这里只会让卡片撑破，一律还原成可折行。 */
  .table-stack tbody td {
    white-space: normal;
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* 但 ::before 那个「标签」是短词，保持不折行才对齐 */
  .table-stack tbody td::before {
    white-space: nowrap;
  }
}

@media (max-width: 640px) {
  /* ① 顶栏：收紧留白，并让**页面级动作条**可横滑，而不是把整页视口撑宽。

     这里踩过一个坑，记下来免得后人重犯：
     上一版的做法是「压缩按钮」—— 给 .topbar-actions 写 flex:0 1 auto + min-width:0。
     实测（390 宽，admin/missions.php）证明那是**反效果**：
        .topbar-actions 盒子被压成 122px、内容却有 204px（scrollWidth=204）
     盒子一窄，overflow:visible 的内容就直接画到视口外面 ——
     按钮既点不到、也看不见，比"页面被缩小"更糟。

     正确做法是给动作区一个**真正的滚动容器**（.ta-page），
     滚动容器的 min-content 尺寸为 0，于是 .topbar-actions 收缩时
     被压的是这一条，右侧全局控件（提示音/皮肤/发起任务/头像）位置不动。
     唯一要绕开的坑：条内的「导出」是 <details class="dd">，
     父层一旦 overflow:auto 就会把弹出的菜单裁掉 —— 菜单在 app.js
     initDropdowns() 里展开时临时改成 position:fixed 摆位。 */
  .topbar { padding: 0 10px; gap: 8px; }
  /* ★ 动作区的收缩下限 = 全局控件不可再压的宽度（v2.5.0 · 需求 #1 补修）。
     提示音 34 + 皮肤 34 + 发起任务 36 + 快捷区 0 + 头像 76 = 180，
     再加 5 个 6px 间距 = 210。
     为什么不能用 min-width:0 / min-width:auto 两个"默认写法"，实测都说清了：
       · min-width: 0（原来的写法）
         容器可以被一路压扁，而里面的全局控件是 flex:0 0 auto 不会再小，
         于是它们直接画到视口外 —— 390 宽、admin/mission_report.php?id=255
         实测 .user-menu right=465，**布局视口被撑到 465**，
         position:fixed 的底部导航与抽屉遮罩按 465 重排，整页看着被缩小、
         位置全偏。这正是用户说的「错位」，不是"按钮挤一挤"那么简单。
       · min-width: auto（改了一版，也不行，两个方向都错）
         空页面级按钮条时算小：Chrome 不计 gap，最小值只算 180 而不是 210，
         那 30px 间隙照样把 .user-menu 顶到 right=410；
         满页面级按钮条时又算大：把 .ta-page 的内容全算进去（admin/member_import.php
         是 467px），容器干脆不收缩，顶栏整条溢出，视口被撑到 531 —— 反而更糟。
     显式写下限只表达一个含义：全局控件不许被挤出去；
     页面级按钮条（.ta-page 有 overflow-x:auto）自己横滑，位置不动。 */
  .topbar { --ta-floor: 210px; }
  .topbar-actions {
    gap: 6px;
    flex: 0 1 auto;
    min-width: var(--ta-floor);
  }
  /* 全局控件永不压缩，否则头像会被挤出屏幕 */
  .topbar-actions > .sound-wrap,
  .topbar-actions > .skin-wrap,
  .topbar-actions > .topbar-new-mission,
  .topbar-actions > .top-quick,
  .topbar-actions > .user-menu { flex: 0 0 auto; }

  .ta-page {
    min-width: 0;
    flex: 0 1 auto;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .ta-page::-webkit-scrollbar { display: none; }
  .ta-page > * { flex: 0 0 auto; }
  /* 条内按钮收得更紧一点，少滚几屏 */
  .ta-page > a.btn,
  .ta-page .dd > summary { padding-left: 9px; padding-right: 9px; }
}

/* 页面级动作条：默认就是一段普通的横排按钮（不裁剪，条内 <details> 下拉照常弹出） */
.ta-page { display: flex; align-items: center; gap: 10px; }

/* ★ 顶栏放不下时（app.js 的 syncTopbarBars() 挂上这个类），动作条自己横滑。
   它是整条顶栏里**唯一**可收缩的部分 —— 这样 1101~1280 这类"刚好不够"的宽度下，
   被压的是它，右侧全局控件（提示音/皮肤/发起任务/快捷区/头像）位置不动。
   为什么必须"按需挂类"而不是无条件写：
     overflow: auto/hidden 一律是裁剪容器，无条件挂上就会把条内 <details class="dd">
     的弹出菜单裁掉 —— 菜单还在，但一个选项都点不到。
   挂上这个类之后 initDropdowns() 会改用它判断，把菜单换成 position:fixed 摆位。 */
.ta-page.is-scrollable {
  min-width: 0;
  flex: 0 1 auto;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.ta-page.is-scrollable::-webkit-scrollbar { display: none; }
.ta-page.is-scrollable > * { flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   44. 人员批量导入 · 模板下载条（需求 #11）

   放在上传区**上方**而不是只留在顶栏：用户的动作顺序是"先拿模板填表、
   再回来上传"，入口跟着动作走。顶栏那两个按钮仍然保留（老习惯），
   但新用户第一眼看到的是这里 —— 顶栏按钮在窄屏会横向滚动，不一定被看见。
   -------------------------------------------------------------------------- */
.import-tpl-bar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--brand-lighter); border: 1px solid var(--brand-light);
  border-radius: var(--radius-sm);
}
.import-tpl-bar .itb-txt { font-size: 12.5px; font-weight: 600; color: var(--brand-ink); }
.import-tpl-bar .btn { background: var(--surface); }
.import-tpl-bar .text-xs a { color: var(--brand); text-decoration: underline; }

/* --------------------------------------------------------------------------
   45. 发起任务页 · 顶部模板快捷区 + 可折叠任务地点（需求 #2 / #3 / #13）

   需求原话：
    「2. 发布任务页面经纬度、所在城市移动到进阶信息里；把集结地点下拉改成
        仓库、现场、仓库和现场、等通知……如果集结地点是仓库或者等通知，
        下方的任务地点新折叠一下，除非用户点击展开再填写，免得输入框太多
        影响观看」；
    「3. 发布任务时顶部，支持一键展开任务模板，快速选择任务模板」；
    「13. 发起任务页面顶部的从模板发起页面，打开后默认展示的就是最近使用的
         模板，支持一键发起，新增模板在底部」。

   两块都遵循同一条原则：**平时不占地方，要用时一下就到**。
   所以都用原生 <details>：无 JS 也能开合（渐进增强），
   JS 只做「按钮 → 展开并滚到可见」和「集结地点 → 任务地点收放」这两件事。
   -------------------------------------------------------------------------- */

/* ── 45.1 顶部模板快捷区 ─────────────────────────────────────────────── */
.me-tpl {
  border: 1px solid var(--brand-light);
  border-radius: var(--radius-sm);
  background: var(--surface);
  margin-bottom: 12px;
  overflow: hidden;
}
.me-tpl > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--brand-ink);
  background: var(--brand-lighter);
}
.me-tpl > summary::-webkit-details-marker { display: none; }
.me-tpl > summary::marker { content: ''; }
.me-tpl > summary:hover { color: var(--brand); }
.me-tpl[open] > summary { border-bottom: 1px solid var(--brand-light); }
.me-tpl > summary svg { flex: 0 0 auto; color: var(--brand); }
.me-tpl-note {
  margin-left: auto;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--text-3);
}
.me-tpl-body { padding: 12px 14px 10px; }

/* 卡片栅格：宽屏 3 列、中屏 2 列、窄屏 1 列。
   auto-fit 在这里是安全的 —— 卡片没有跨列需求，不会被撑出隐式列。 */
.me-tpl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
}
.me-tpl-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  min-width: 0;
}
.me-tpl-card:hover { border-color: var(--brand-light); background: var(--brand-lighter); }
.me-tpl-name {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
  line-height: 1.45;
}
.me-tpl-meta { font-size: 11.5px; color: var(--text-3); }
.me-tpl-loc {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  color: var(--text-3);
  min-width: 0;
}
.me-tpl-loc svg { flex: 0 0 auto; }
.me-tpl-act {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}
.me-tpl-used { font-size: 11px; color: var(--text-3); }
.me-tpl-act .btn { margin-left: auto; }
.me-tpl-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.me-tpl-foot .link-btn { margin-left: auto; font-size: 12.5px; }

/* ── 45.2 可折叠的任务地点（跟随集结地点收放）────────────────────────── */
.me-loc {
  grid-column: 1 / -1;      /* 跨满整行：任务地点本来就是个 span-3 的宽框 */
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}
.me-loc > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  padding: 9px 12px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
}
.me-loc > summary::-webkit-details-marker { display: none; }
.me-loc > summary::marker { content: ''; }
.me-loc > summary:hover { color: var(--brand); }
.me-loc > summary svg { flex: 0 0 auto; color: var(--brand); }
.me-loc-hint { font-weight: 400; font-size: 11.5px; color: var(--text-3); }
.me-loc-now {
  font-weight: 400;
  font-size: 11.5px;
  color: var(--text-3);
  max-width: 46%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 展开时摘要是多余的 —— 输入框就在下面，答案已经在那儿了 */
.me-loc[open] .me-loc-hint,
.me-loc[open] .me-loc-now { display: none; }
/* 收起时只显示"有内容的那个"：有地点显示地点，没地点才解释为什么不用填 */
.me-loc:not([open]) .me-loc-hint:empty,
.me-loc:not([open]) .me-loc-now:empty { display: none; }
/* 右侧的展开指示箭头：纯 CSS 三角，不额外引图标字体 */
.me-loc-toggle {
  margin-left: auto;
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: .55;
  transition: transform .15s ease;
}
.me-loc[open] .me-loc-toggle { transform: rotate(180deg); }
.me-loc-body { padding: 12px 12px 2px; }
/* 折起来时下方不留空隙：空 body 仍会带 padding，这里一并清掉 */
.me-loc:not([open]) .me-loc-body { display: none; }

/* ---------- 46. 板块一句话说明（装备拆分后的 eq-hint） ----------
   拆成「总库存 / 入库 / 出库 / 台账」四个入口后，用户点的第一个问题
   往往不是"怎么操作"，而是"这一页到底管什么"。所以每个板块给一行说明。
   刻意做小做淡：它是路标不是一个板块，不能把标签栏挤下去。 */
.eq-hint {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: -2px 0 12px;
  padding: 0 2px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-3);
}
.eq-hint svg { flex: 0 0 auto; margin-top: 2px; color: var(--brand); opacity: .8; }
.eq-hint > span { min-width: 0; }

/* ---------- 47. 任务类别页的两段分组（救援类 / 常规类） ----------
   需求 #14：两种类别都是正式任务，只是系数不同，所以要一眼看出
   "这是两组并列的类别"，而不是"一组类别 + 一组别的什么东西"。
   做法尽量轻：一条细分隔线 + 一个小标题，不再给每组套一层卡片
   （套卡片会让本就不宽的分类表再窄一圈，还会多出一圈边框噪音）。 */
.tt-sec + .tt-sec { border-top: 1px solid var(--border); }
.tt-sec-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 10px;
  padding: 12px 16px 0;
}
.tt-sec-head h4 {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
/* 系数是本页最该被记住的数字，单独给它一点存在感 */
.tt-sec-coef {
  font-size: 12px;
  font-weight: 600;
  color: var(--brand);
  background: var(--brand-light);
  border-radius: 999px;
  padding: 1px 8px;
}
.tt-sec-sub { font-size: 12px; color: var(--text-3); }
.tt-sec-note {
  margin: 4px 16px 0;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-3);
}
.tt-sec .table-wrap { margin-top: 8px; }

/* ---------- 48. 通知列表的排序说明（notice-order-hint） ----------
   需求 #15b：前台通知改成「未读优先 → 必读优先 → 时间倒序」后，
   这个顺序**不再是时间序**。用户滑到一条三天前的必读通知、而昨天发的
   普通通知在它下面时，第一反应是"系统把我刚发的弄丢了"。
   所以列表上方必须常驻一行说明 —— 但它是一句注解，不是内容，
   跟 46 的 eq-hint 同样处理：小字、弱色、单行，不占高度。 */
.notice-order-hint {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 12px;
  padding: 7px 10px;
  border-radius: 8px;
  background: var(--surface-2);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-3);
}
.notice-order-hint svg { flex: 0 0 auto; margin-top: 2px; color: var(--brand); opacity: .8; }
.notice-order-hint > span { min-width: 0; }
.notice-order-hint b { color: var(--text-2); font-weight: 600; }
.notice-order-hint + * { margin-top: 12px; }

@media (max-width: 640px) {
  .me-tpl-note { margin-left: 0; flex: 1 1 100%; }
  .me-tpl-grid { grid-template-columns: 1fr; }
  .me-loc-now { max-width: 100%; flex: 1 1 100%; }
}


/* ==========================================================================
   需求 #2 · 手机端「表格 / 容器被压成竖条」修复
   ==========================================================================
   用户报「手机版分类搜索错位 / 发布任务·报名指派错位 / 任务模板一键发起错位 /
   人员处罚错位 ……」。在 390 视口逐页真实渲染量下来是三类根因：

   ① 栅格轨道的"最小宽度"被卡片内容顶住 —— admin/map_facility.php
      窄屏下 `.grid-main` 是单列 `1fr`，而 `1fr` = `minmax(auto, 1fr)`，
      那个 `auto` 取的是栅格项的**最小内容宽度**。卡片里 7 列的据点表
      最小内容宽 501px，于是轨道被顶到 531px，整页布局视口撑到 556px
      （390 的 1.43 倍），用户看到的是"整页被缩小、位置全偏"。
      实测（390）：`.grid-main` 轨道 531.109px、`nav.bottom-nav@556`、OVERX=166。
      解法：把栅格项的最小宽度从轨道下限里摘出去，表格回到"自己横向滚动"。

   ② `.table-wrap` 里的表被压到容器宽度以下 —— flow_types / skill_review …
      上方"需求 #1"为了让**裸表**不撑宽整页，给 `.table:not(.table-stack)`
      统一写了 `min-width: 0`；连已经包在 `.table-wrap` 里（外层本身就是
      横向滚动容器、根本不会撑宽整页）的表也一起改小了，列宽被压到容器宽度
      以下，日期 / 数字列变成"一个字一行"的竖条。
      实测（390）：flow_types 的 `table-mini` = 384px 宽、`td.num` 内容宽 24px
      排 11 行；skill_review 的 `td` 内容宽 36px 排 6 行。
      解法：`.table-wrap` 里的表按内容宽度排，横滑交给外层滚动容器。

   ③ 窄屏下 flex 容器的宽度被算成 0 —— admin/search.php 的分类芯片、
      admin/mission_edit.php「报名与人员指派」页的人员选择框
      实测（390）：父级块盒内容宽 336px，而 `.sr-chips` / `.field` 的
      used width = 0（同一个元素改成 `display: block` 立刻是 336，
      改回 `display: flex` 又是 0；桌面 1440 下则是正常的 922px）。
      容器宽 0 → 子项被压到最小内容宽 → 「队员档案」竖成一列、
      人员选择框的占位文案排成 10 行。
      解法：显式给宽度，不再依赖 `auto`。
   ========================================================================== */

@media (max-width: 900px) {
  /* ① 栅格轨道不再被卡片的最小内容宽顶住（表格改为自身横滑） */
  .grid-main > * { min-width: 0; }
}

@media (max-width: 860px) {
  /* ② 已在 .table-wrap 里的表：按内容宽度排，外层负责横滑 */
  .table-wrap > .table:not(.table-stack) { min-width: max-content; }

  /* ②b 但横滑壳自己必须**能被压窄**。`.table-wrap` 一旦成为 flex/grid 子项
        （例如 admin/penalties.php 的档位表挂在 `.alert` 这个 flex 容器里），
        它的 `min-width: auto` 会取表的最小内容宽（520px），于是外壳跟着撑到 520，
        整页被顶到 575 视口、185px 溢出 —— 比修之前的"竖条"更糟。
        `min-width: 0` 把下限摘掉，溢出交回给 overflow-x:auto 自己滚动。 */
  .table-wrap { min-width: 0; }

  /* ②c `.table-wrap` 修好了还不够 —— 挡住它的往往是**外面那一层**。
       实测 admin/penalties.php：结构是
         .alert(display:flex) > div ── 这个 div 才是 flex 子项，
       它的 `min-width: auto` 同样取"里面那张 520px 的表"的最小内容宽，
       于是 div 撑到 520、`.alert` 跟着 520、整页视口 575。
         （`.table-wrap` 自己也写了 min-width:0，但它在外层 div 里面，
           外层不松口，里面再松也没用 —— 这就是第一次只改 .table-wrap
           却"毫无效果"的原因，记下来免得下次再试一遍。）
       所以凡是**提示条 / 看板注记**这类 flex 容器，直接子项一律允许被压窄。 */
  .alert > *:not(svg), .board-note > *:not(svg) { min-width: 0; }

  /* ③ 窄屏下某些 flex/grid 子项会被压到 0 宽（父级过约束 + 子项 min-width:0 时，
        浏览器**真的**会把宽度算成 0，不是取近似），显式把宽度给回去。
        实测：admin/search.php 的 `.sr-chips`、admin/mission_edit.php
        报名指派页的 `.card-body > .field`。 */
  .card-body > .field { width: 100%; }

  /* ④ 卡片化表格（.table-stack）的单元格：把「标签 + 内容」从 flex 行
        改成「块流 + 浮动标签」。
        卡片模式原本是 `td{display:flex}` + `::before{flex:0 0 82px}` 的**一行两列**：
        左 82px 标签、右内容。问题是内容里的**每个子节点都会变成独立的 flex 列**
        并排铺开 —— 裸文字 + 若干 <div> 就成了并排的多列，每列被挤到 3.2 字宽以下，
        形成「一字一行」的竖条。实测（390 视口，修前）：
          · admin/roles.php      td.strong（宽 334）里「副队长」最宽 13px / 3 行
          · admin/trainings.php  td.strong（宽 334）里「救援安全与自我防护」最宽 39px
          · admin/doc_review.php 「过敏史：无」最宽 23px / 3 行
          · admin/search.php?q=  「孙磊 · LT000005」最宽 40px / 3 行
        改成块流后：文字恢复整行宽度；多个 <div> 上下堆叠（本来就该这样）；
        而 `.btn` 是 `display:inline-flex`，同一格里多个按钮照旧并排。
        标签摆回原处（左边距 10px、宽 82px），内容左边界仍是 102px = 10 + 82 + 10，
        与原来的 flex 布局**像素级一致**。

        标签必须**参与单元格的高度计算**，不能用绝对定位。
        绝对定位的第一次尝试（left:10px / top:7px）视觉上一样，但标签脱离文档流、
        不再撑高单元格，于是**值为空的格子**会被它溢出到下一条：
        空格子只有上下内边距，实测高 15px（7 + 1 边框 + 7）；标签本身 19.8px，
        从 7px 起画，底部落在 26.8px —— 越出格子 11.8px，压到下一条的标签上。
        实测 admin/reports.php?type=roster：850 个格子里 1 个（标签「ID」）溢出 18.8px。

        顺便把"标签会不会折行"量清楚了，免得下次再猜：
        · 全站静态 `data-label` 去重 30 个，最宽的是 `身份 / 职务`（admin/members.php），
          11 个半角宽 → 12px 字号下 66px；
        · 报表列标签（includes/reports.php，`<td data-label="<?= e($c['label']) ?>"`）
          去重 74 个，最宽的是「个人出勤时长」等 6 个汉字 → 72px。
        82px 的标签位都装得下，**不会折行**，所以只需要处理空格子这一种情形。
        （`includes/export_registry.php` 里还有 14 字的标签，但那是导出用的列名，
          不参与这张表，别混进来。）

        改法：标签用 `float`（仍在左侧，且会撑高单元格），
        再用 `::after { display: table; clear: both }` 这个 clearfix 把浮动收进高度里。
        clearfix 只用 `display:table` + `clear`，所有浏览器都认 —— 不依赖
        `display:flow-root`（那要 Chrome 58+，X5 / 老 WebView 上不保险），
        也不像 `overflow:hidden` 那样会裁掉格子里的下拉菜单 / 提示。
        浮动标签用 `margin-left:-92px` 落进左侧内边距区：
        内容盒左边界 102px − 92px = 10px 起，margin-right:10px 再把内容顶回 102px；
        浮动的 margin 盒正好填满左侧内边距（10 + 82 + 10 = 102），
        内容盒整体在浮动右侧，块级子元素也不会和标签重叠。 */
  .table-stack tbody td {
    display: block;
    padding-left: 102px;
    min-width: 0;
  }
  .table-stack tbody td::before {
    float: left;
    width: 82px;
    margin-left: -92px;
    margin-right: 10px;
    flex: none;
  }
  /* clearfix：把浮动标签的高度收进单元格，空格子（高 15px）也不会再溢到下一条 */
  .table-stack tbody td::after {
    content: '';
    display: table;
    clear: both;
  }
}

/* --------------------------------------------------------------------------
   46. 前台顶部导航的二级下拉（需求 3：后台可自定义一级 / 二级菜单）
   --------------------------------------------------------------------------
   需求原话「支持发布到一级菜单，也要支持二级菜单，下拉选择，包括支持
   自定义第三方链接，支持在新页面打开」。

   为什么用纯 CSS 而不是 JS：
     · :hover 管鼠标，:focus-within 管键盘 —— Tab 到父项就能展开，
       这是纯 hover 做不到的（键盘用户会完全打不开下拉）；
     · app.js 里那条 data-site-nav-toggle 只管**手机端整条导航的展开**，
       两套逻辑互不干扰，少一处会失效的地方。

   手机端（≤860px）没有 hover，导航本身已是竖排展开，所以子项直接静态
   列出来（缩进 + 左侧竖线），不做下拉 —— 竖屏下点出来的浮层会盖住内容，
   而且悬停下拉在触屏上根本没有触发时机。 */
.site-drop { position: relative; }
.site-drop > a { display: inline-flex; align-items: center; gap: 4px; }
.site-drop-caret { transition: transform .16s; opacity: .62; }
.site-drop:hover .site-drop-caret,
.site-drop:focus-within .site-drop-caret { transform: rotate(180deg); }
.site-drop-menu {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 172px;
  display: none; flex-direction: column; gap: 2px;
  padding: 6px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg); z-index: 70;
}
.site-drop:hover > .site-drop-menu,
.site-drop:focus-within > .site-drop-menu { display: flex; }
.site-drop-menu a {
  padding: 8px 11px; font-size: 13.5px; font-weight: 500;
  white-space: nowrap; border-radius: var(--radius-sm);
}
/* 父项自身也命中（例如点进 board.php）时的统一观感 */
.site-nav a.is-cur-parent { background: var(--brand-lighter); color: var(--brand); font-weight: 600; }

@media (max-width: 860px) {
  .site-drop { position: static; }
  .site-drop-caret { display: none; }
  .site-drop-menu {
    position: static; display: flex; box-shadow: none; border: none;
    background: transparent; padding: 0 0 0 13px; margin: 2px 0 5px;
    border-left: 2px solid var(--border); min-width: 0;
  }
  .site-drop-menu a { padding: 9px 11px; }
}
