/* ============================================================
   p1-ui.css — P1 三服务共享前端资产（设计 token + 基础组件）
   ------------------------------------------------------------
   统一基准：attendance「清新简洁」风格（用户已认可，2026-08 审查结论）
   - :root 设计 token 与 attendance/templates/index_new.html
     25-47 行的 CSS 变量完全一致（已验证的一套）
   - 组件部分只提供通用基础类，不绑定任何页面布局
   - 移动端友好：触控目标 >= 44px；刘海/底部横条用 safe-area 变量
   - 使用约定：本文件应先于页面自定义样式加载（页面样式后加载、
     同优先级时后者覆盖前者，保证既有页面布局不被意外改动）
   ============================================================ */

:root{
  /* 本仓只有浅色一套设计（全仓零 `prefers-color-scheme`、零 `light-dark()`）。
     不声明时，桌面浏览器开暗色会由 UA 自行"猜色"强制把整页压暗——写死的近白背景
     （如 .special-meal-row 的 #f8fafc）会变深色、主按钮在暗底上看不见文字。
     声明 light 后 UA 不再改写我们的配色。将来若真做暗色：改这里并补 prefers-color-scheme。 */
  color-scheme: light;
  /* 主色 */
  --primary: #2563eb;
  --primary-deep: #1d4ed8;
  --primary-soft: #eff6ff;
  /* 语义色 */
  --success: #10b981;
  --success-bg: #ecfdf5;
  --success-text: #065f46;
  --error: #ef4444;
  --error-bg: #fef2f2;
  --error-text: #991b1b;
  --warning: #f59e0b;
  --warning-bg: #fffbeb;
  --warning-text: #92400e;
  --info: #2563eb;
  --info-bg: #eff6ff;
  /* 文字 */
  --text: #1e293b;
  --text-2: #64748b;
  --text-3: #94a3b8;
  /* 线条 / 背景 */
  --line: #e2e8f0;
  --bg: #f4f7fe;
  --card: #ffffff;
  /* 表头底色：三套管理端的 th 原来各写一遍 #f8fafc（同值、三处重复），主题 60 收成一个语义 token。
     注意它与 --bg / --card 都不同值，别"顺手合并"成同一个变量——那会改外观。 */
  --table-head-bg: #f8fafc;
  /* 紧凑按钮（表格行内操作等）：原来 meal `.btn-sm`、attendance `.box table .btn`、
     共享 `.btn-small` 三份逐字相同的值，主题 60 收成这一组 token，选择器只引用值。 */
  --btn-compact-min-height: 34px;
  --btn-compact-padding: 6px 14px;
  --btn-compact-font-size: 13px;
  --btn-compact-font-weight: 500;
  --btn-compact-shadow: none;
  /* 圆角 */
  --radius-lg: 20px;
  --radius-md: 14px;
  --radius-sm: 10px;
  /* 阴影 */
  --shadow-card: 0 2px 16px rgba(37,99,235,.06), 0 1px 3px rgba(15,23,42,.04);
  --shadow-btn: 0 8px 20px rgba(37,99,235,.30);
  /* 移动端触控目标最小尺寸（iOS HIG / Material 建议 44px） */
  --tap-min: 44px;
  /* safe-area 使用约定：
     iOS 刘海屏/底部横条区域，页面容器建议
     padding-top:    calc(14px + env(safe-area-inset-top, 0px));
     padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
     浏览器不支持 env() 时自动退化为 0px */
}

/* ============ 管理端版心（主题 62）============
   盒模型写在这条规则自己身上，不依赖页面级 `* { box-sizing }`：三套管理端只有 meal 有那条
   reset，UC 与 attendance 没有——同一个 max-width:1200 在 meal 算出内容宽 1160、在 UC 算出 1200，
   "数字统一"因此是假的。补全局 reset 会把 UC 19／attendance 11／meal 12 条显式宽度声明的算法
   一起改掉（等于同时动 30 个盒子），所以只在这里声明一处。
   内容宽 = 1200 − padding 20×2 = 1160，与 meal 已有的 .admin-container 等价（它不重复套本类）。 */
.admin-shell{
  box-sizing:border-box;
  max-width:1200px;
  margin:0 auto;
  padding:20px;
}

/* ============ 管理端表单底线（主题 65）============
   同样只写在版心里（`.admin-shell`／`.admin-container` 两个作用域，理由见主题 62/63 那两段注释）：
   员工端的表单仍走它自己的 `.form-input` 一族，一个像素都不动。
   - 字号 16px：iOS 上输入框字号 < 16px 会在聚焦时自动放大页面，这是"以 meal 的 16px 为基准"的原因
     （meal 管理端 `.form-group input` 本来就是 1rem=16px；UC 原来 13px、attendance 原来 14px）。
   - 内边距/边框/圆角：三套原来各抄一份且值不同（meal 表单 10px 12px、meal 筛选条 8px 12px、
     UC 与 attendance 8px 10px），这里统一成 meal 表单那份。
   - 排除 checkbox/radio：给它们加 padding/border 会把勾选框撑成方块。
   - 选择器带两个 :not() 之后特异性是 (0,3,1)，比各页原来的 `.input-group input`(0,1,1) 高，
     所以页内**只该留布局属性**（flex/min-width/margin/width），别再留 padding 或字号。 */
/* ⚠️ 作用域为什么还要 `.admin-form`：管理端的**弹窗内容盒不在版心里**（UC 的三个 `.modal-box`
   是 `.admin-shell` 的兄弟节点），只按版心罩就会让弹窗里的控件掉回 UA 样式——比改前更糟。
   `.admin-form` 是给这类"管理端表单区"opt-in 的第三个作用域（员工端没人用这个类名）。 */
.admin-shell input:not([type="checkbox"]):not([type="radio"]),
.admin-shell select,
.admin-shell textarea,
.admin-container input:not([type="checkbox"]):not([type="radio"]),
.admin-container select,
.admin-container textarea,
.admin-form input:not([type="checkbox"]):not([type="radio"]),
.admin-form select,
.admin-form textarea{
  box-sizing:border-box;
  padding:10px 12px;
  border:1.5px solid var(--line);
  border-radius:var(--radius-sm);
  font-size:16px;
}
.admin-shell input:focus:not([type="checkbox"]):not([type="radio"]),
.admin-shell select:focus,
.admin-shell textarea:focus,
.admin-container input:focus:not([type="checkbox"]):not([type="radio"]),
.admin-container select:focus,
.admin-container textarea:focus,
.admin-form input:focus:not([type="checkbox"]):not([type="radio"]),
.admin-form select:focus,
.admin-form textarea:focus{
  outline:none;
  border-color:var(--primary);
  box-shadow:0 0 0 3px rgba(37,99,235,.12);
}
/* 字段标签：meal 本来就是 13px/500（共享 `.form-group label` 供的），UC 原来没有 label 规则
   （16px/400 UA 默认）、attendance 只给了 min-width —— 这轮把三套拉到同一档 */
.admin-shell label,
.admin-container label,
.admin-form label{
  font-size:13px;
  font-weight:500;
  color:var(--text-2);
}

/* ============ 按钮 ============ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:var(--tap-min);
  padding:10px 20px;
  border:none;border-radius:999px;
  background:var(--primary);color:#fff;
  font-size:15px;font-weight:600;letter-spacing:.5px;
  line-height:1.2;
  cursor:pointer;
  box-shadow:var(--shadow-btn);
  -webkit-tap-highlight-color:transparent;
  user-select:none;
  transition:transform .15s, opacity .15s, background .15s;
}
.btn:hover{background:var(--primary-deep)}
.btn:active{transform:scale(.96)}
.btn:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}
/* 幽灵按钮（次要操作） */
.btn-ghost{
  background:var(--primary-soft);color:var(--primary);
  box-shadow:none;
}
.btn-ghost:hover{background:#dbeafe}
/* 危险按钮 */
.btn-danger{
  background:var(--error);color:#fff;
  box-shadow:0 8px 20px rgba(239,68,68,.25);
}
.btn-danger:hover{background:#dc2626}
/* 成功/警示色修饰类（主题 65）：只改底色，不带布局与字号——那些归 .btn 基类与紧凑档。
   命名对齐 meal 管理端**已经在用**的 `.btn.btn-success`（原来那份定义只写在 meal 页内，
   attendance 用的是另一套裸色名 `.success`/`.warning`，两边各一份迟早分叉）。
   ⚠️ 不要把它们放到 `.btn-small` 之后再看：它们不设 box-shadow，与紧凑档那条 `box-shadow:none` 无冲突。
   ⚠️ 也别误当成"整行主按钮"——那是 `.btn-primary`（width:100%＋渐变＋17px，员工端提交/打卡用），
   管理端的纯色小按钮基类是 `.btn`。 */
.btn-success{background:var(--success);color:#fff}
.btn-success:hover{background:#0d9f6e}
.btn-warning{background:var(--warning);color:#fff}
.btn-warning:hover{background:#d97706}
/* 整行主按钮（申请/提交/打卡等页面主操作；区别于上方胶囊 .btn）。
   两系统用户端申请界面统一使用；样式源自 meal/attendance 页面级同名类现状 */
.btn-primary{
  display:flex;align-items:center;justify-content:center;gap:8px;
  width:100%;
  min-height:var(--tap-min);
  padding:14px 16px;
  border:none;border-radius:16px;
  background:linear-gradient(135deg,#3b82f6,#2563eb);
  color:#fff;
  font-size:17px;font-weight:600;letter-spacing:2px;
  box-shadow:var(--shadow-btn);
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  user-select:none;
  transition:transform .15s, opacity .2s, box-shadow .2s;
}
.btn-primary:hover{background:linear-gradient(135deg,#3b82f6,#2563eb)}
.btn-primary:active{transform:scale(.97)}
.btn-primary:disabled{opacity:.6;box-shadow:none;cursor:not-allowed}
/* 小尺寸紧凑按钮（表格行内操作等）。值只在 :root 的 --btn-compact-* 里有一份。
   **必须排在 .btn-primary 之后**：`.btn.btn-sm.btn-primary` 这类组合现在靠的就是"后写的赢"，
   把它挪到 .btn-primary 前面会让 padding/字号被 .btn-primary 的整行值覆盖（主题 60 实测过）。
   `.btn-sm` 是 meal 管理端在用的类名（19 处），一并留在这里，不动 markup。 */
.btn-small,.btn-sm{
  min-height:var(--btn-compact-min-height);padding:var(--btn-compact-padding);
  font-size:var(--btn-compact-font-size);font-weight:var(--btn-compact-font-weight);
  box-shadow:var(--btn-compact-shadow);
}
/* 整行次要按钮（撤销/取消等） */
.btn-secondary{
  display:flex;align-items:center;justify-content:center;gap:8px;
  width:100%;
  min-height:var(--tap-min);
  padding:12px 16px;
  border:none;border-radius:16px;
  background:var(--primary-soft);color:var(--primary);
  box-shadow:none;
  font-size:15px;font-weight:500;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  transition:transform .15s, background .15s;
}
.btn-secondary:hover{background:#dbeafe}
.btn-secondary:active{transform:scale(.97)}

/* ============ 表单 ============ */
.form-group{margin-bottom:14px}
.form-group:last-child{margin-bottom:0}
.form-group label{
  display:block;font-size:13px;color:var(--text-2);
  margin-bottom:6px;font-weight:500;
}
.form-input,.form-select,.form-textarea{
  width:100%;
  min-height:var(--tap-min);
  padding:10px 14px;
  border:1.5px solid var(--line);
  border-radius:var(--radius-sm);
  background:#fff;color:var(--text);
  font-size:15px;
  box-sizing:border-box;
  -webkit-appearance:none;
  transition:border-color .15s, box-shadow .15s;
}
.form-input::placeholder,.form-textarea::placeholder{color:var(--text-3)}
.form-input:focus,.form-select:focus,.form-textarea:focus{
  outline:none;
  border-color:var(--primary);
  box-shadow:0 0 0 3px rgba(37,99,235,.12);
}
.form-input:disabled,.form-select:disabled,.form-textarea:disabled{background:#f1f5f9;color:var(--text-3)}
/* 文本域（申请理由/备注等；与 .form-input 同族，text 特有属性在此补充） */
.form-textarea{
  resize:none;overflow:hidden;line-height:1.5;
  font-family:inherit;
}
/* 下拉箭头容器：配合 .form-select 使用（两系统申请界面共用） */
.select-wrapper{position:relative}
.select-wrapper .form-select{padding-right:40px}
.select-wrapper::after{
  content:'';position:absolute;right:16px;top:50%;
  transform:translateY(-70%) rotate(45deg);
  width:8px;height:8px;
  border-right:2px solid var(--text-3);border-bottom:2px solid var(--text-3);
  pointer-events:none;
}

/* ============ 卡片 ============ */
.card{
  background:var(--card);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);
  padding:18px;
}
/* 窄屏统一 16px（原来这条写在 meal/base.html 的 media 段里，两边因此一个 16 一个 18；
   断点沿用 meal 原有的 600px，不另起一个）。
   页面自己后面再定义 .card 的（如 user-center 的 20px/32px）按级联仍然胜出，不受影响。 */
@media (max-width: 600px) {
  .card{padding:16px}
}

/* ============ 管理端面板的唯一定义（主题 63）============
   只给"在版心里面的卡"这套值，上面那条 `.card` 本体一个字不动——它被全仓 27 处 .card 元素在用
   （meal 员工端首页 8、attendance 员工端 8），给它加 margin-bottom 会牵动每天在用的界面。
   选择器列表带 `.admin-container`：主题 62 定了 meal 不重复套 `.admin-shell`，只写 `.admin-shell` 罩不住它。
   meal 自己的 `overflow:hidden` 留在页内——它不在这五个面板值里（管卡片底部圆角处悬停行的裁切）。 */
.admin-shell .card,
.admin-container .card{
  background:var(--card);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);
  padding:18px;
  margin-bottom:20px;
}

/* ============ 整页状态容器（这一屏只有这一张状态卡）——主题 52 第三步 ============
   主题 93（用户 2026-10-05 裁定 C）把这一族的几何从"卡片撑满整屏"换成
   **“卡片贴内容高度 ＋ 卡片自己在容器里垂直居中”**：容器仍是整屏高的 flex 列（状态屏要有
   "这一屏只有这一张卡"的骨架），但卡不再 `flex:1`；居中靠卡片自己的 `margin:auto 0`。
   ⚠️ 为什么不用 `justify-content:center` 居中容器：内容比容器高（矮视口 ＋ 长表单）时 center 会把
      **顶部裁掉且滚不回去**；`margin:auto` 在这种情况下自动退化成 0，顶部永远可达（主题 67 那一族的教训）。
   ⚠️ 只给"只显示一张状态卡"的界面用；操作页（报餐表单、打卡列表、多卡文档流）
      绝对不要加这个类——那类页面要贴顶（主题 49 已定）。
   ⚠️ 不复用也不改 .order-page：那是 meal 报餐操作页专用容器，两件事。 */
.state-screen{
  display:flex;
  flex-direction:column;
  min-height:100vh;          /* 兜底在前，dvh 在后（同主题 48 的顺序口径） */
  min-height:100dvh;
  box-sizing:border-box;
}
.state-screen > .card{
  /* 主题 93：原先这里是 `flex:1`（卡撑满整屏）——90% 屏高、中间一个圈、四周全白，
     用户的真实读感是"页面坏了"。改成贴内容高＋auto 边距垂直居中；
     卡内不再需要"首尾孩子 margin-top/bottom:auto"那套（主题 90 的两条已随之删除）。 */
  margin:auto 0;
  min-height:0;
  display:flex;
  flex-direction:column;
}

/* ============ 模态框 ============ */
.modal-mask{
  position:fixed;top:0;left:0;right:0;bottom:0;
  z-index:999;
  background:rgba(15,23,42,.5);
  display:flex;justify-content:center;align-items:center;
  padding:0 20px;
}
.modal{
  background:var(--card);
  border-radius:var(--radius-lg);
  padding:24px;
  width:100%;max-width:380px;
  box-shadow:var(--shadow-card);
}
.modal-title{font-size:16px;font-weight:600;color:var(--text);margin:0 0 12px}
.modal-msg{font-size:14px;color:var(--text-2);line-height:1.6;margin:0 0 20px;word-break:break-all}
.modal-btns{display:flex;gap:10px}
.modal-btns .btn{flex:1;min-height:var(--tap-min)}

/* ============ 顶部浮动提示（toast） ============
   配合 p1-ui.js 的 toast() 使用：JS 创建单元素并每次重置 class，
   MutationObserver 监听 class 变化自动展示/延时隐藏；
   展示/隐藏由内联 style 控制（opacity/transform），
   本处 transition 负责过渡动画（与 attendance #status 同机制） */
.toast{
  position:fixed;
  left:50%;
  top:calc(14px + env(safe-area-inset-top,0px));
  transform:translate(-50%,-12px);
  z-index:1100;
  max-width:calc(100vw - 40px);
  padding:10px 18px;
  border-radius:999px;
  font-size:14px;line-height:1.4;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  opacity:0;
  pointer-events:none;
  transition:opacity .25s, transform .25s;
}
.toast-info{background:rgba(15,23,42,.85);color:#fff}
.toast-success{background:var(--success);color:#fff}
.toast-error{background:var(--error);color:#fff}

/* ============ 底部弹层（sheet） ============
   移动端底部操作面板：页面需配 .sheet-mask 遮罩（或复用 .modal-mask） */
.sheet{
  position:fixed;
  left:0;right:0;bottom:0;
  z-index:1000;
  background:var(--card);
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  padding:18px 18px calc(18px + env(safe-area-inset-bottom,0px));
  box-shadow:0 -4px 24px rgba(15,23,42,.12);
}
.sheet-title{font-size:16px;font-weight:600;color:var(--text);margin-bottom:10px}
.sheet-hint{font-size:13px;color:var(--text-2);margin-bottom:12px}
.sheet-cancel{
  width:100%;
  min-height:var(--tap-min);
  margin-top:12px;
  border:none;border-radius:999px;
  background:var(--primary-soft);color:var(--primary);
  font-size:15px;font-weight:500;
  cursor:pointer;
}

/* ============ 徽标 ============ */
.badge{
  display:inline-block;
  padding:2px 10px;
  border-radius:999px;
  font-size:12px;font-weight:500;
  line-height:1.6;
  background:#f1f5f9;color:var(--text-2);
}
.badge-success{background:var(--success-bg);color:var(--success-text)}
.badge-error{background:var(--error-bg);color:var(--error-text)}
.badge-warning{background:var(--warning-bg);color:var(--warning-text)}
.badge-info{background:var(--info-bg);color:var(--primary)}

/* ============ 申请授权界面组件（两系统用户端申请界面共用） ============ */
/* 申请页底部说明 / 输入框下方提示（如"授权后才能进行报餐操作"） */
.apply-note{
  margin-top:12px;color:var(--text-3);
  font-size:12px;text-align:center;line-height:1.6;
}
/* 上次申请被驳回：驳回原因提示块 */
.reject-box{
  background:var(--error-bg);border:1px solid #fecaca;
  border-radius:var(--radius-md);padding:12px 14px;margin-bottom:14px;
}
.reject-title{font-size:13px;font-weight:600;color:var(--error-text);margin-bottom:4px}
.reject-text{font-size:13px;color:var(--error-text);line-height:1.5;word-break:break-all}

/* ============ 表格基础样式 ============ */
.table{
  width:100%;
  border-collapse:collapse;
  font-size:14px;
}
.table th,.table td{
  text-align:left;
  padding:10px 12px;
  border-bottom:1px solid var(--line);
}
.table th{
  background:var(--table-head-bg);
  color:var(--text-2);
  font-weight:600;
  white-space:nowrap;
}
.table tbody tr:last-child td{border-bottom:none}
/* 主题 68：表格的横向可达性容器。窄屏里表比屏幕宽时**由这一层来滚**，而不是把整页顶出去——
   实测 attendance 六张表在 390 宽下右缘都到 638、整页 scrollWidth 638，而它们外层 `.card` 的
   `overflow-x` 是 visible：scrollWidth 虽然大于 clientWidth，但**根本滚不动**（不是可滚容器）。
   值与属性顺序与 user-center 页内原那条逐字一致（原先只有 UC 有这层容器），空白按本文件风格归一；
   UC 页内那条已删，这份是唯一定义。
   它是 **opt-in 类**：markup 不挂就不生效，员工端模板一处都没挂（有用例钉）。
   ⚠️ 别把 overflow-x 塞进共享 `.card` 或 `.admin-shell`——那会连带改变其它面板的裁切行为。 */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* ============ 状态卡组件（未登录 / 身份被拒 / 异常提示）——主题 52 从 meal/base.html 整段搬来，
   同名同值，两边共用一份定义（meal 的 #bannedCard 与 attendance 的身份被拒卡都引这组类）。
   口径与文案见 docs/09 §5.4。搬动本身不改视觉：meal 侧只是定义换了文件位置。 ============ */
.text-center { text-align: center; }

.state-icon {
    width: 56px; height: 56px; margin: 4px auto 14px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
}
.state-icon.soft { background: var(--primary-soft); color: var(--primary); }
.state-icon.warn { background: #fff7ed; color: #f59e0b; }

/* 未登录 / 待审批 / 身份被拒等居中提示卡片 */
.auth-required { margin: auto 0; padding: 8px 4px; }
.auth-required h2 { font-size: 17px; font-weight: 600; color: var(--text); margin-bottom: 10px; }
.auth-required p { color: var(--text-2); font-size: 14px; line-height: 1.6; margin: 0 0 14px; }
.auth-required .btn-primary,
.auth-required .btn-secondary { margin-top: 10px; }
.auth-required .nick { color: var(--primary); font-weight: 600; margin-bottom: 14px; }
/* 主题 90：只读姓名行（「真实姓名：X（如需修改请联系管理员）」）两侧共用的一份强调样式。
   meal 那侧靠上面 `.auth-required .nick` 的后代选择器赢过 `.auth-required p` 的灰色正文；
   attendance 的申请卡不在 `.auth-required` 容器下，挂不到那条选择器，主题 89 只能临时借 `.apply-note`
   ——同一句话一页像强调（14px/600/主色）、一页像脚注（12px/400/灰）。
   上面那条是 `p1_common/tests/test_shared_state_card_component.py` 的"搬动前后值一个不许改"契约对象，
   所以这里**另起一条独立语义类**而不是并进那条；两者的等值由
   `attendance/tests/test_theme90_apply_card_geometry.py` 逐条属性比着，防止今后各自被改走。
   `font-size:14px` 是显式写的：meal 那 14px 来自 `.auth-required p`，考勤这边没有那层后代关系。 */
.name-fixed { color: var(--primary); font-weight: 600; font-size: 14px; margin-bottom: 14px; }

/* ============ 中性加载态（主题 74 从 meal/templates/base.html 整段上收，这份是唯一定义）
   值与属性顺序与 meal 页内那 5 行逐字一致，空白按本文件风格归一；meal 页内已删（同主题 68 上收
   `.table-wrap` 的口径）。meal 的 `#loadingCard` 与 attendance 新加的 `#loadingCard` 引的是同一组类，
   两边"身份判定出来之前"都显示它——不再拿登录卡当加载屏。
   ⚠️ `@keyframes spin` 一并上收：meal 页内两处（`.loading-spinner` 与它自己的按钮 spinner）与
   attendance 的 `.btn-spinner` 都引用这个名字，谁删页内副本都要实测"还在转"（主题 60：同值≠可删）。 */
.loading-spinner { border: 3px solid #e2e8f0; border-top: 3px solid var(--primary); border-radius: 50%; width: 20px; height: 20px; animation: spin 1s linear infinite; display: inline-block; }
.loading-big { width: 40px; height: 40px; margin-bottom: 16px; }
.loading-text { color: var(--text-2); font-size: 14px; }
.card-center { margin: auto 0; text-align: center; padding: 40px 0; }
@keyframes spin { to { transform: rotate(360deg); } }

/* 诊断行（code=… msg=…）：保留但默认折叠，排查时点「查看诊断」展开 */
.diag-text { color: var(--text-3); font-size: 12px; word-break: break-all; }
.diag-details { margin: 6px 0 0; text-align: center; }
.diag-details summary { color: var(--text-3); font-size: 12px; cursor: pointer; list-style: none; }
.diag-details summary::-webkit-details-marker { display: none; }
.diag-details .diag-text { margin-top: 4px; }


/* ============ 管理端页眉（主题 132）＝三套唯一出处 ============
   值取自报餐管理端那套（用户裁定“以报餐系统的UI设计为准”）。改前是三条各写一份：
   报餐写在页内样式里、用户中心用通栏壳（纯色、无圆角无投影）、考勤**根本没有容器**
   （只有一个裸标题标签，所以那页是白底）。两处定义等于没有出处——下一次改只会改到其中一处。
   判据：`p1_common/tests/test_theme132_admin_header_parity.py`（"页内不许再留一份"与"三套同形"两条）。
   ⚠️ 本文件是三套共享副本的源（各自 `static/shared/` 下那份），改完必须跑 sync_shared_assets.py。 */
.admin-header{
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  color: white;
  padding: 20px 30px;
  border-radius: var(--radius-lg);
  margin-bottom: 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 8px 24px rgba(37,99,235,.25);
}
.admin-header h1 { font-size: 1.5rem; margin: 0; }
/* 左侧第二行「当前范围」：字号与透明度沿用页眉右侧那一档小字
   ——右侧写"我是谁"、左侧写"我在管哪个范围"，两行同层级（主题 128 定）。 */
.admin-header .scope-line { font-size: 0.85rem; opacity: 0.85; margin-top: 4px; }
/* ============ 页眉右上"账户块"（主题 133）＝三套同形 ============
   改前三形各一套：报餐两行纯文字（第二行是 `.role` 里一枚下划线链接）、用户中心只有两枚链接
   （连"欢迎／是谁"都没有）、考勤是「欢迎：＋一个等接口回填的空 span」再加一枚**红色按钮**，
   首帧那一格还是空的。现在统一成两行：姓名行（头像圆＋欢迎：＋加粗用户名，服务端渲染）
   ＋动作行（胶囊 `.header-action`）。
   ⚠️ 行为不动：用户中心的「修改密码」是**真功能**（另两套没有，不许为统一而删）；
   考勤的退出仍走它自己的 `logout()`（先打 /api/admin/logout 再回登录页），只是外观从红按钮换成胶囊。
   ⚠️ 旧的两条一起删：`.user-info .role`（角色名按主题 132 已不再显示）与 `.admin-header a`
   （下划线白链接——现在页眉里所有动作都是胶囊，留着只会让下一个加链接的人又拿回那枚下划线）。 */
.admin-header .user-info {
  display: flex; flex-direction: column; align-items: flex-end; gap: 6px; text-align: right;
}
.admin-header .user-name { display: flex; align-items: center; gap: 8px; font-size: .9rem; line-height: 1.2; }
.admin-header .user-avatar {
  width: 30px; height: 30px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.18); border: 1px solid rgba(255,255,255,.28); font-weight: 600;
  /* ⚠️ 这枚 `box-sizing` 不是装饰：报餐页内有 `*{box-sizing:border-box}`，考勤与用户中心没有，
     同一份共享规则在两套上会连边框一起加进尺寸（实测头像圆 30 vs 32）。"三套同形"要么自己算清，
     要么就带着这枚，让这三套的量与版心有没有全局 reset 无关。 */
  box-sizing: border-box;
}
.admin-header .user-greet { opacity: .75; font-size: .8rem; }
.admin-header .user-actions { display: flex; align-items: center; gap: 8px; }
.admin-header .header-action {
  padding: 3px 10px; border-radius: 999px;
  background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.18);
  color: #fff; font-size: .8rem; line-height: 1.6; text-decoration: none;
  cursor: pointer; font-family: inherit;
  transition: background .2s, border-color .2s;
  box-sizing: border-box;   /* 同上一条：胶囊尺寸不随各页有没有全局 reset 而变 */
}
.admin-header .header-action:hover { background: rgba(255,255,255,.26); border-color: rgba(255,255,255,.32); }
@media (max-width: 768px) {
  .admin-header { flex-direction: column; text-align: center; gap: 12px; }
  /* 整块已经竖排居中了，账户块自己也得跟着居中——留着 `align-items:flex-end` 会在居中列里
     又靠右甩出去一截（窄屏上看着像"名字贴到屏幕边"）。 */
  .admin-header .user-info { align-items: center; text-align: center; }
}
.admin-header h1 { letter-spacing: .02em; }   /* 主题 133：只加字距，字号与颜色一字未动 */

/* ============ 管理端「一卡页签」（主题 133）＝三套唯一出处 ============
   母版是报餐那一套（用户裁定：「报餐界面……在同一块，点哪个展示哪个的 UI 很好。另外两个管理界面
   也统一成这样」）。改前三套是三套实现：报餐＝`.tabs`/`.tab-btn`/`.tab-content`；
   用户中心＝`.tabs`/裸 `button[data-tab]`/`.tab-panel`（还带四张独立面板卡、每卡一个 `<h2>`）；
   考勤＝压根没有外层页签（七个版块从上到下堆着，只有「打卡设置」里内层一组 `.tab-container`/`.tab`/`.tab-pane`）。
   值**逐字照搬报餐那份**（上收只许搬、不许顺手改外观），报餐页内那几条同时删掉——两处定义等于没有出处。
   ⚠️ `.tab-content{display:none}` 一进共享，任何挂着这个类名的 div 都会隐形：考勤从前那个
   `.tab-content` 是**面板的内边距层**（与报餐的反义同名，`docs/09` §5.5「三个陷阱」第 1 条写的就是它），
   所以本单必须同时把考勤那层改名，否则「打卡设置」整块会看不见——这条由
   `p1_common/tests/test_theme133_admin_tabs.py` 的内层配对判据钉住。
   ⚠️ `.tabs` 的 `flex-wrap:wrap` 是主题 68 实测补的（第三枚标签会把 390 的页面顶出去），搬过来时一条不放宽。 */
.tabs { display: flex; flex-wrap: wrap; border-bottom: 1px solid var(--line); }
.tab-btn {
  padding: 14px 24px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 1rem;
  color: var(--text-2);
  border-bottom: 2px solid transparent;
  transition: color .3s, background .2s;
}
.tab-btn.active { color: var(--primary); border-bottom-color: var(--primary); }
/* 报餐原本只有 `color: var(--primary)`；这里加一枚极浅的底（rgba(37,99,235,.04)）当悬停反馈——
   卡片说的"轻度视觉整理"里唯一一处新增美术，不引新色值、走主色的 alpha。 */
.tab-btn:hover { color: var(--primary); background: rgba(37,99,235,.04); }
.tab-content { display: none; }
.tab-content.active { display: block; }
/* 卡片解剖两块：报餐页内那两条的原值。它们与「面板五值」那条 `.card` 是三件事——
   五值（背景/圆角/阴影/padding/margin-bottom）仍由主题 63 那条唯一提供，本单一个字不动。 */
.card-header {
  padding: 16px 20px;
  border-bottom: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.card-header h3 { margin: 0; font-size: 1.1rem; color: var(--text); }
.card-body { padding: 20px; }
/* 表格行悬停底色（主题 133 统一）：从前只有报餐页内有这条，另两套悬停没反馈。
   作用域仍限定在两个管理端版心里——员工端（报餐 `view.html` 等）不在这两个容器内，
   一像素都不动（这条由实测承担，写在 `docs/14` §8 主题 133 块⑤）。值用现成的 #f8fafc，
   不新增 token：它与 `--table-head-bg` 同值但语义不同（一个是表头、一个是悬停），并进一枚反而出错。 */
.admin-shell .table tbody tr:hover,
.admin-container .table tbody tr:hover { background: #f8fafc; }
/* 窄屏（≤600px，沿用共享 `.card` 那条的断点，不另起一档）标签尺寸收一点：
   实测 390 下报餐 5／8 枚与另两套 4 枚都折成 ≤2 行，靠的就是这一档（数在 docs/14 §8 块⑤）。 */
@media (max-width: 600px) {
  .tab-btn { padding: 12px 14px; font-size: .95rem; }
}