/* ============================================================
   食堂用餐登记系统
   蓝紫渐变 / 响应式大卡片 / 移动端优先
   ============================================================ */

:root {
  --grad: linear-gradient(135deg, #5b6ee1 0%, #7c5ce0 52%, #a45cf0 100%);
  --grad-2: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
  --grad-warm: linear-gradient(135deg, #f5a524 0%, #f97316 100%);
  --grad-cool: linear-gradient(135deg, #38bdf8 0%, #6366f1 100%);

  --ink: #221c46;
  --ink-2: #4a4570;
  --muted: #8b88a8;
  --line: #eceaf8;

  --card: #ffffff;
  --radius-xl: 26px;
  --radius-lg: 20px;
  --radius-md: 14px;

  --shadow-lg: 0 18px 44px -18px rgba(91, 110, 225, .38);
  --shadow-sm: 0 8px 24px -14px rgba(91, 110, 225, .40);

  --safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* 必须放在最前：.btn / .sheet-foot 等带 display 的类会盖掉 [hidden] 的默认样式 */
[hidden] { display: none !important; }

html, body { height: 100%; }

/* iOS 的「文字自动放大」（Text Autosizing）会让字号随容器宽度浮动 —— 同一份 CSS
   在 iPhone 上会渲染出跟安卓/电脑不同的尺寸。明确关掉，字号只认我们写死的值。
   （2026-10-14 排查「食堂端日历在 iPhone 上错位」时加的，详见 .cal-grid 处的注释） */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei",
               "Helvetica Neue", "Noto Sans SC", sans-serif;
  color: var(--ink);
  background: #f4f4fd;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ⚠️ 全局只清了 border，**没清 padding** —— `<button>` 的 UA padding 是 1px 6px，
   在 `box-sizing: border-box` 下会把定宽的内容盒挤窄（21px 只剩 9px），
   里面再用 `place-items: center` 居中的文字/符号就会偏到一边。
   凡是「定宽定高 + 居中」的按钮，必须自己补 `padding: 0`（见 .chip-x / .close-btn）。 */
button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
input { font: inherit; }
h1, h2, h3, p { margin: 0; }

/* ---------------- 背景装饰 ---------------- */
.bg-deco { position: fixed; inset: 0; overflow: hidden; z-index: 0; pointer-events: none; }
.bg-deco .blob { position: absolute; border-radius: 50%; filter: blur(58px); opacity: .55; }
.bg-deco .b1 { width: 340px; height: 340px; top: -110px; left: -100px; background: #a5b4fc; }
.bg-deco .b2 { width: 300px; height: 300px; top: 22%; right: -120px; background: #d8b4fe; }
.bg-deco .b3 { width: 360px; height: 360px; bottom: -150px; left: -60px; background: #c7d2fe; }

/* ---------------- 布局 ---------------- */
.app {
  position: relative;
  z-index: 1;
  max-width: 480px;
  margin: 0 auto;
  min-height: 100%;
  padding: 0 16px calc(32px + var(--safe-b));
}

/* ---------------- 顶部校名 ---------------- */
/* 左右 padding 为 0：让图标左边缘和「关于」按钮右边缘都对齐下面卡片的边线
   （原来是 4px，会比卡片往里缩一点）。 */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 22px 0 14px;
}

.school { display: flex; align-items: center; gap: 10px; min-width: 0; }

.school-mark {
  width: 40px; height: 40px; flex: none;
  display: block;
  /* 图标自带圆角（logo.png 四角是透明的），所以这里只做同弧度收边。
     ⚠️ 原来是 border-radius: 50%（那时用的是圆形校徽），
        换成圆角方块图标后必须跟着改，否则会被裁成圆形、筷子尖端贴边。 */
  border-radius: 23%;
  object-fit: contain;
}

.school-name {
  font-size: 17px; font-weight: 700; letter-spacing: .5px;
  color: var(--ink);
  /* 顶栏右边多了「关于」按钮，窄屏（staging 标题还带「（测试）」）可能放不下。
     ⚠️ 这三行是兜底：宁可省略号，也不要撑破顶栏、把按钮挤到下一行。 */
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------------- 顶部「关于」按钮 ---------------- */
/* 只有淡底色、没有图标 —— 是次要入口，不该抢标题的注意力。 */
.about-btn {
  flex: none;
  display: inline-flex; align-items: center;
  padding: 9px 15px;
  border: none; border-radius: 999px;
  background: rgba(109, 91, 208, .09);
  color: #5b4bc4;
  font-size: 14px; font-weight: 600; line-height: 1;
  cursor: pointer;
  transition: background .18s ease, transform .18s ease;
}
.about-btn:active { transform: scale(.95); }
/* ⚠️ 必须显式写：上面的 display:inline-flex 会盖掉 hidden 属性的 UA 样式，
   不加这条，JS 里设 hidden 是没用的（按钮照样显示）。 */
.about-btn[hidden] { display: none; }

/* ---------------- 视图切换 ---------------- */
.stage { position: relative; }

.view { display: none; animation: fadeUp .34s cubic-bezier(.22,.9,.3,1); }
.view.is-active { display: block; }

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

/* ---------------- 主页 · 大卡片 ---------------- */
.hero-card {
  width: 100%;
  display: flex; align-items: center; gap: 16px;
  padding: 26px 22px;
  margin-bottom: 16px;
  border-radius: var(--radius-xl);
  background: var(--grad);
  color: #fff;
  text-align: left;
  box-shadow: var(--shadow-lg);
  transition: transform .18s ease, box-shadow .18s ease;
}
.hero-card:active { transform: scale(.977); }

.hero-badge {
  width: 56px; height: 56px; flex: none;
  display: grid; place-items: center;
  font-size: 28px;
  border-radius: 18px;
  background: rgba(255,255,255,.22);
  backdrop-filter: blur(6px);
}

.hero-text { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.hero-text strong { font-size: 21px; font-weight: 700; letter-spacing: .6px; }
.hero-text em { font-style: normal; font-size: 13px; color: rgba(255,255,255,.82); }

.chev { font-size: 24px; opacity: .7; flex: none; }

.tile-card {
  width: 100%;
  display: flex; align-items: center; gap: 16px;
  padding: 22px;
  margin-bottom: 16px;          /* 与 hero-card 一致；多张入口卡片之间才有间距 */
  border-radius: var(--radius-xl);
  background: var(--card);
  text-align: left;
  box-shadow: var(--shadow-sm);
  border: 1px solid rgba(255,255,255,.9);
  transition: transform .18s ease, box-shadow .18s ease;
}
.tile-card:active { transform: scale(.977); }
.tile-card .chev { color: var(--muted); }

.tile-icon {
  width: 52px; height: 52px; flex: none;
  display: grid; place-items: center;
  font-size: 25px;
  border-radius: 17px;
  background: linear-gradient(135deg, #eef0ff, #f6efff);
}

.tile-text { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.tile-text strong { font-size: 18px; font-weight: 700; color: var(--ink); }
.tile-text em { font-style: normal; font-size: 13px; color: var(--muted); }

/* 原首页底部小字提示（.foot-note）已于 2026-10-17 移入「关于」弹窗的「说明」一节 */

/* 原「加到手机桌面的引导」条（.pwa-tip）已于 2026-10-17 移除：
   首页底部那条提示改成写在「关于」弹窗里（第 2 块「快速访问」）。
   Service Worker 注册保留，离线兜底不受影响。 */

/* ---------------- 面板 / 表单 ---------------- */
.back-btn {
  margin: 0 0 14px -6px; padding: 6px 10px;
  font-size: 14.5px; color: var(--ink-2); font-weight: 500;
  border-radius: 10px;
}
.back-btn:active { background: rgba(124,92,224,.08); }

.panel {
  background: var(--card);
  border-radius: var(--radius-xl);
  padding: 26px 22px 24px;
  box-shadow: var(--shadow-sm);
}
.panel-flat { padding: 20px 18px; }

.panel-title { font-size: 21px; font-weight: 700; letter-spacing: .4px; }
.panel-sub { margin-top: 6px; font-size: 14px; color: var(--muted); }

.field { display: block; margin-top: 20px; }
.field-label {
  display: block; margin-bottom: 8px;
  font-size: 14px; font-weight: 600; color: var(--ink-2); letter-spacing: .3px;
}
.field input {
  width: 100%;
  padding: 15px 16px;
  border-radius: var(--radius-md);
  border: 1.5px solid var(--line);
  background: #fafaff;
  color: var(--ink);
  font-size: 16px;
  outline: none;
  transition: border-color .18s, box-shadow .18s, background .18s;
}
.field input::placeholder { color: #b0adc6; }
.field input:focus {
  border-color: #8b7ce8;
  background: #fff;
  box-shadow: 0 0 0 4px rgba(124,92,224,.13);
}

.form-err {
  min-height: 20px; margin-top: 12px;
  font-size: 14px; color: #e5484d;
}
.form-err:empty { display: none; }

/* ---------------- 按钮 ---------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 6px;
  padding: 15px 22px;
  border-radius: var(--radius-md);
  font-size: 16px; font-weight: 600; letter-spacing: 1px;
  transition: transform .15s ease, opacity .15s ease, box-shadow .15s ease;
}
.btn:active { transform: scale(.975); }
.btn:disabled { opacity: .55; pointer-events: none; }

.btn-primary {
  width: 100%; margin-top: 22px;
  background: var(--grad);
  color: #fff;
  box-shadow: var(--shadow-sm);
}
.btn-block { margin-top: 18px; }

.btn-ghost {
  background: #f3f2fb;
  color: var(--ink-2);
  letter-spacing: 0;
}

.text-btn {
  flex: none; padding: 7px 12px;
  font-size: 15px; color: var(--muted);
  border-radius: 10px;
}
.text-btn:active { background: rgba(124,92,224,.08); }

/* ---------------- 用户条 ---------------- */
.user-bar {
  display: flex; align-items: center; gap: 13px;
  padding: 18px 20px;
  background: var(--card);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
  margin-bottom: 16px;
}

.avatar {
  width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  border-radius: 15px;
  background: var(--grad);
  color: #fff; font-size: 18px; font-weight: 700;
}
.avatar.icon-admin { font-size: 22px; background: linear-gradient(135deg, #eef0ff, #f6efff); }

.user-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.user-info strong { font-size: 17px; font-weight: 700; }
.user-info em { font-style: normal; font-size: 13.5px; color: var(--muted); }

/* ---------------- 早/午 登记卡片 ---------------- */
.meal-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

.meal-card {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
  padding: 24px 18px 22px;
  border-radius: var(--radius-xl);
  color: #fff;
  text-align: left;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transition: transform .18s ease;
}
.meal-card:active { transform: scale(.968); }
.meal-breakfast { background: linear-gradient(135deg, #6d5bd0 0%, #9d6ae8 100%); }
.meal-lunch     { background: linear-gradient(135deg, #4f6fe0 0%, #6d5bd0 100%); }

/* 去掉「去登记」按钮后，把空间让给文字 */
.meal-emoji { font-size: 34px; line-height: 1; margin-bottom: 9px; }
.meal-title { font-size: 21px; font-weight: 700; letter-spacing: .5px; }
.meal-sub { font-style: normal; font-size: 14px; color: rgba(255,255,255,.88); }

/* ---------------- 登记记录 ---------------- */
.records-card {
  margin-top: 18px;
  padding: 20px 18px 18px;
  background: var(--card);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
}

.records-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 14px;
}
.records-head h3 { font-size: 16px; font-weight: 700; }
.records-hint { font-size: 13px; color: var(--muted); }

.rec-group + .rec-group { margin-top: 16px; }
.rec-group-title {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 14.5px; font-weight: 600; color: var(--ink-2);
  margin-bottom: 9px;
}
.rec-edit {
  font-size: 14px; color: #6d5bd0; font-weight: 600;
  padding: 4px 10px; border-radius: 8px; background: #f2f0fe;
}

.chips { display: flex; flex-wrap: wrap; gap: 8px; }

.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 8px 7px 12px;
  border-radius: 999px;
  font-size: 14px; font-weight: 500;
  background: #f2f1fd;
  color: var(--ink-2);
}
.chip.bf { background: #f3efff; color: #6d5bd0; }
.chip.lc { background: #eef2ff; color: #4f6fe0; }

.chip-x {
  width: 21px; height: 21px;
  flex: 0 0 21px;
  /* ⚠️ 2026-10-18 用户反馈：安卓上 × 偏右、iPhone 上还是椭圆。两个独立成因：
     ① **偏右** = 按钮的 UA padding（1px 6px）没清。border-box 下内容盒被挤成 9px，
        `place-items: center` 是在这 9px 里居中 14px 的 ×，视觉上就靠右了。
     ② **椭圆** = flex item 的 `min-width` 默认是 `auto`（= min-content）。
        iOS 字体下 × 的 min-content + UA padding 会超过 21px，把圆横向撑大；
        高度是硬的，于是宽 > 高 → 椭圆。`flex: none` 只管 grow/shrink，管不到 min-width。
     修法：清 padding + 显式 `min-width/min-height: 0`（不能用 max-width 锁死，
     别处的 .close-btn 会被厨房端覆盖成 38px）。 */
  padding: 0;
  appearance: none; -webkit-appearance: none;
  min-width: 0; min-height: 0;
  /* ⚠️ 用 flex 而不是 grid：Safari 对「<button> 当 grid 容器」支持很晚才修好，
     旧机型上 display:grid 会被忽略、place-items 失效 → × 又飘走。
     flex 在 button 上一直可用。 */
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: rgba(109,91,208,.13);
  color: inherit; font-size: 14px; line-height: 1;
}
.chip-x:active { background: rgba(109,91,208,.3); }

/* 已过截止时间：整条记录不可删除 */
.chip.is-locked {
  background: #f4f3f8;
  color: #a7a4bd;
}
.chip.is-locked .chip-x {
  background: #e8e6f0;
  color: #b6b3c9;
  pointer-events: none;
  cursor: not-allowed;
}
.chip-lock {
  font-size: 12.5px;
  color: #b0adc6;
}

/* 加餐标签：和普通登记区分开（加餐不补贴，所以口径必须一眼看出） */
.chip.ex { background: #fff1e9; color: #c2600f; }
/* 午餐加餐用绿色，和首页「午餐加餐」卡片一致 */
.chip.ex.ex-lc { background: #eaf7ef; color: #17693c; }
.chip.ex.is-locked,
.chip.ex.ex-lc.is-locked { background: #f4f3f8; color: #a7a4bd; }
.chip-qty { font-weight: 700; font-size: 13.5px; }

/* 登记记录：月份切换 */
.rec-nav {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 14px;
}
.rec-nav-label {
  flex: 1; text-align: center;
  font-size: 14.5px; font-weight: 700; letter-spacing: .3px;
}
.rec-today {
  flex: none;
  padding: 5px 10px; border-radius: 9px;
  font-size: 13.5px; font-weight: 600;
  color: #6d5bd0; background: #f2f0fe;
}
.rec-today:disabled { opacity: .35; pointer-events: none; }

.empty {
  padding: 20px 6px; text-align: center;
  font-size: 13px; color: var(--muted);
}

/* ---------------- 管理端 · 月份选择 ---------------- */
.year-nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  padding: 9px 14px;
  background: var(--card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.year-label {
  font-size: 16px; font-weight: 700; letter-spacing: .5px;
  font-variant-numeric: tabular-nums;
}

.month-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.month-cell {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  padding: 14px 6px;
  border-radius: 16px;
  background: var(--card);
  border: 1.5px solid var(--line);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.month-cell:active { transform: scale(.95); }
.month-cell b { font-size: 17px; font-weight: 700; line-height: 1.2; }
.month-cell em {
  font-style: normal; font-size: 12.5px; line-height: 1.35;
  text-align: center; word-break: keep-all;
}

/* 有登记数据的月份 */
.month-cell.has-data {
  background: linear-gradient(135deg, #f1eeff, #f8f5ff);
  border-color: #ddd6ff;
}
.month-cell.has-data b { color: #6d5bd0; }
.month-cell.has-data em { color: #8b7ce8; font-weight: 600; }

/* 无数据的月份 */
.month-cell.is-empty b { color: #b8b5cc; }
.month-cell.is-empty em { color: #c9c6da; }

/* 当前月份 */
.month-cell.is-current {
  border-color: #8b7ce8;
  box-shadow: 0 0 0 3px rgba(124, 92, 224, .12);
}

/* ---------------- 管理端 · 导入入口 ---------------- */
.action-card {
  width: 100%;
  display: flex; align-items: center; gap: 15px;
  margin-top: 14px;
  padding: 17px 20px;
  background: var(--card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  text-align: left;
  transition: transform .18s ease;
}
.action-card:active { transform: scale(.98); }
.action-card .chev { color: var(--muted); }
.icon-import { background: linear-gradient(135deg, #eef7ff, #eef0ff); }
.icon-clock { background: linear-gradient(135deg, #fff3e6, #ffeff5); }
.icon-kitchen { background: linear-gradient(135deg, #e9fbf2, #eef7ff); }
.icon-extra { background: linear-gradient(135deg, #fff2e8, #fdeef6); }
.icon-backup { background: linear-gradient(135deg, #e9fbf2, #eef7ff); }
.icon-lock { background: linear-gradient(135deg, #f1f0fa, #eef2ff); }
.icon-range { background: linear-gradient(135deg, #fff2e4, #ffe9f3); }
.icon-key { background: linear-gradient(135deg, #fff7e0, #fdede4); }
.icon-more { background: linear-gradient(135deg, #f0efff, #e9eefc); }

/* 危险操作（放在「更多操作」里的应急功能） */
.action-card.is-danger {
  border: 1px solid #ffd9dd;
  background: linear-gradient(180deg, #fff7f8, #ffffff 62%);
}
.action-card.is-danger .tile-icon { background: linear-gradient(135deg, #ffe4e6, #ffeef1); }
.action-card.is-danger strong { color: #b42318; }
.danger-note {
  margin-top: 14px;
  padding: 0 4px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--muted);
}

/* 职工端：临时加餐入口 —— 早餐 / 午餐 各一张卡片
   （配色区分餐次，进去就不会再点错）
   ⚠️ 整卡高度对齐改造前的单条入口（`.action-card`，实测 86px）—— 用户明确要求「还是这个高度」，
      两卡并排后总高度不能比原来高。改 emoji / 行高 / padding 后务必重量一次高度。 */
.extra-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 14px;
  margin-top: 14px;
}

.extra-card {
  display: flex; align-items: center; gap: 8px;
  /* 与改造前的单条入口等高（同事已经习惯这个高度），内容居中 */
  min-height: 87px;
  padding: 10px 12px;
  border-radius: var(--radius-xl);
  text-align: left;
  box-shadow: var(--shadow-sm);
  transition: transform .18s ease, box-shadow .18s ease;
}
.extra-card:active { transform: scale(.97); }

/* 早餐加餐：暖橙（沿用加餐记录里那套橙色） */
.extra-breakfast { background: linear-gradient(135deg, #fdf1e7, #fbe5d5); }
.extra-breakfast .extra-emoji { background: #fde0c8; }
.extra-breakfast .extra-title { color: #a8540c; }

/* 午餐加餐：浅绿 */
.extra-lunch { background: linear-gradient(135deg, #eaf7ef, #dbf0e4); }
.extra-lunch .extra-emoji { background: #d3efdf; }
.extra-lunch .extra-title { color: #17693c; }

.extra-emoji {
  display: flex; align-items: center; justify-content: center;
  flex: none;
  width: 28px; height: 28px;
  border-radius: 9px;
  font-size: 16px; line-height: 1;
}

/* 文字块：图标右侧，标题在上、份数在下 */
.extra-text {
  display: flex; flex-direction: column; gap: 1px;
  min-width: 0;
}
.extra-title { font-size: 17px; font-weight: 700; letter-spacing: .3px; line-height: 1.25; }
.extra-sub { font-style: normal; font-size: 13px; line-height: 1.3; color: #8b88a8; }

/* ---------------- 管理端 · 导出数据 ---------------- */
.export-card {
  margin-top: 16px;
  padding: 18px 18px 16px;
  background: var(--card);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
}
.export-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 13px;
}
.export-head h3 { font-size: 16px; font-weight: 700; }
.export-hint { font-size: 12.5px; color: var(--muted); }

.export-btns { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.export-btns .btn { width: 100%; margin-top: 0; padding: 13px 10px; font-size: 14.5px; }

.export-tip {
  margin: 13px 0 0; padding: 0 0 0 17px;
  font-size: 12.5px; line-height: 1.9; color: var(--muted);
}
.export-tip b { color: var(--ink-2); }

/* ---------------- 登记时间设置 ---------------- */
/* 覆盖 .sheet-dialog 的默认上限：两栏滚轮需要更多纵向空间 */
.sheet-dialog.sheet-cutoff { max-width: 420px; max-height: min(90vh, 720px); }
.cutoff-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.cutoff-tip {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-radius: 14px;
  background: #f6f4ff;
  font-size: 12.5px; line-height: 1.85; color: var(--ink-2);
}
.cutoff-tip b { color: #6d5bd0; }

.cutoff-field + .cutoff-field { margin-top: 18px; }
.cutoff-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 9px;
}
.cutoff-head .field-label { margin: 0; }
.cutoff-val { font-size: 14px; font-weight: 700; color: #6d5bd0; white-space: nowrap; }

/* 前一天 / 当天 切换 */
.seg-sm { margin-bottom: 10px; padding: 3px; border-radius: 12px; }
.seg-sm button { padding: 7px 0; font-size: 14px; border-radius: 9px; }

/* 滚轮选择器 */
.wheel-box {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  gap: 4px;
  height: 112px;
  border-radius: 16px;
  background: #fafaff;
  overflow: hidden;
  touch-action: pan-y;
}
.wheel-band {
  position: absolute; left: 10px; right: 10px; top: 50%;
  height: 44px; margin-top: -22px;
  border-radius: 12px;
  background: #f1efff;
  pointer-events: none;
}
.wheel-box::before, .wheel-box::after {
  content: ''; position: absolute; left: 0; right: 0; height: 30px;
  z-index: 2; pointer-events: none;
}
.wheel-box::before { top: 0; background: linear-gradient(#fafaff, rgba(250,250,255,0)); }
.wheel-box::after { bottom: 0; background: linear-gradient(rgba(250,250,255,0), #fafaff); }

.wheel {
  position: relative; z-index: 1;
  box-sizing: border-box;
  width: 64px; height: 112px;
  padding: 34px 0;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scroll-behavior: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.wheel::-webkit-scrollbar { display: none; }

.wheel-item {
  width: 100%; height: 44px;
  display: grid; place-items: center;
  scroll-snap-align: center;
  font-size: 16px; font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: #bcb9cd;
  transition: color .16s, font-size .16s;
}
.wheel-item.is-on { color: var(--ink); font-weight: 700; font-size: 19px; }
.wheel-sep {
  position: relative; z-index: 1;
  font-size: 18px; font-weight: 700; color: #c3c0d6;
  padding-bottom: 2px;
}

/* ---------------- 导入弹窗 ---------------- */
.sheet-import { max-width: 480px; }

.file-drop {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 30px 18px;
  border: 2px dashed #cfc9f0;
  border-radius: var(--radius-lg);
  background: #fafaff;
  text-align: center;
  cursor: pointer;
  transition: border-color .18s, background .18s;
}
.file-drop:active, .file-drop.is-over {
  border-color: #8b7ce8;
  background: #f3f1ff;
}
.file-drop-icon { font-size: 32px; line-height: 1; margin-bottom: 2px; }
.file-drop strong { font-size: 15.5px; font-weight: 600; color: var(--ink); }
.file-drop em { font-style: normal; font-size: 13px; color: var(--muted); }

.import-tip {
  margin: 16px 0 0; padding: 0 0 0 18px;
  font-size: 12.5px; line-height: 1.9; color: var(--muted);
}
.import-tip b { color: var(--ink-2); }

/* 导入弹窗：让「主体」成为唯一的滚动区，底部按钮永远钉在卡片里。
   ⚠️ 这里必须写 flex + min-height:0。.sheet-dialog 是
   `display:flex; flex-direction:column; max-height:min(78vh,620px); overflow:hidden`，
   而 .import-body 原先没有任何规则 → 它作为 flex 子项不会缩到内容高度以下，
   内容一高（预览汇总 + 改名警告条 + 长表格）就把 .sheet-foot 顶出卡片外被裁掉，
   表现为「预览出来了，但下面没有『确认导入』按钮」。
   （.details-body / .cutoff-body 早就有这两行，只有 import 漏了。） */
.import-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.sheet-dialog .sheet-foot { flex: none; }

.import-summary {
  font-size: 13.5px; color: var(--ink-2);
  padding: 11px 14px; margin-bottom: 12px;
  background: #f6f5ff; border-radius: var(--radius-md);
}
.import-summary b { color: #6d5bd0; }
.import-summary .bad { color: #e5484d; font-weight: 700; }

/* 导入预览：改名警告（最容易出事的操作，单独拎出来说） */
.import-warn {
  margin: -4px 0 12px;
  padding: 11px 14px;
  border-radius: var(--radius-md);
  background: #fff7ed; border: 1px solid #ffd9b8;
  color: #a8541a; font-size: 13.5px; line-height: 1.9;
}
.import-warn b { color: #b4551a; }
.import-warn span { color: #9c7a5c; }

/* 表格不再自己滚：交给上面的 .import-body 统一滚，
   避免手机端出现「嵌套两层滚动区」（里层滚到底才带动外层，很难操作）。
   thead 的 position:sticky 会挂到 .import-body 上，表头照样吸顶。 */
.import-table-wrap {
  border: 1px solid var(--line); border-radius: var(--radius-md);
}
.data-table-sm th, .data-table-sm td { padding: 9px 10px; font-size: 14px; }
.data-table-sm thead th { position: sticky; top: 0; z-index: 1; }
.data-table-sm td:first-child { color: var(--muted); font-variant-numeric: tabular-nums; width: 42px; }
.row-bad td { background: #fff5f5; color: #c92a2a; }
.row-bad-reason td {
  background: #fff5f5; color: #e5484d;
  font-size: 13px; padding: 0 10px 9px;
}

/* 导入预览：这一行会做什么（重点标出「改名」，避免静默改错人） */
.tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12.5px; line-height: 1.6;
  white-space: nowrap;
}
.tag-new { background: #e7f8ef; color: #12734a; }
.tag-upd { background: #f0eff7; color: #6b6a86; }
.tag-ren { background: #fff1e6; color: #b4551a; }
/* 「改密码」：服务端预检比过密码才知道 —— 只有密码变了，本地预览看不出来 */
.tag-pwd { background: #e8f1fc; color: #1a5fb4; }
/* 「不变」= 服务端已比过密码，确认无变化；「待核对」= 本地还没比过密码。
   两者导入时都会被跳过，区别在于「不变」是结论、「待核对」只是暂时状态。 */
.tag-nochg { background: #f4f3f8; color: #9b99ad; }

/* 导入结果 */
.import-result { text-align: center; padding: 6px 0 2px; }
.import-result-icon { font-size: 40px; line-height: 1; }
.import-result h4 { margin-top: 10px; font-size: 17px; font-weight: 700; }
.import-stats { display: flex; gap: 8px; margin-top: 18px; }
.import-stats .stat {
  flex: 1; min-width: 0; padding: 14px 4px;
  background: #f6f5ff; border-radius: var(--radius-md);
}
.import-stats .stat b { display: block; font-size: 21px; font-weight: 700; color: #6d5bd0; }
.import-stats .stat span { font-size: 12.5px; color: var(--muted); }

/* 导入结果页：本次有账号密码被改 → 他们的设备已被踢下线。
   必须明说，否则过两天会有人来问「我怎么突然要重新登录」。 */
.import-kicked {
  margin-top: 14px;
  font-size: 14px; line-height: 1.7; color: var(--ink-2);
}
.import-kicked b { color: #c2600f; }

.import-failed {
  margin-top: 16px; text-align: left;
  border: 1px solid #ffd9d9; background: #fff8f8;
  border-radius: var(--radius-md); padding: 12px 14px;
}
.import-failed p { font-size: 14px; color: #c92a2a; font-weight: 600; }
.import-failed ul {
  margin: 8px 0 0; padding-left: 18px;
  max-height: 26vh; overflow-y: auto;
  font-size: 13.5px; line-height: 1.85; color: #b03030;
}

/* ---------------- 表格 ---------------- */
.table-card {
  background: var(--card);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  margin-top: 16px;
}

.data-table { width: 100%; border-collapse: collapse; }
.data-table th, .data-table td {
  padding: 13px 12px;
  font-size: 14px;
  text-align: left;
  border-bottom: 1px solid var(--line);
}
.data-table thead th {
  font-size: 13.5px; font-weight: 600; color: var(--muted);
  background: #fafaff;
  letter-spacing: .3px;
}
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table td.num, .data-table th.num { text-align: center; }
.data-table td.num { font-weight: 600; font-variant-numeric: tabular-nums; }
.data-table td.name { font-weight: 600; }
.data-table .col-bf { color: #6d5bd0; }
.data-table .col-lc { color: #4f6fe0; }
/* 加餐两列跟首页卡片、记录区 chip 用同一套配色：早餐=橙、午餐=绿 */
.data-table .col-ex-bf { color: #a8540c; }
.data-table .col-ex-lc { color: #17693c; }

/* 月份统计表（#summary-table）：6 列 —— 编号 · 姓名 · 早餐 · 午餐 · 早加餐 · 午加餐。
   ⚠️ **故意没有「合计」列**（2026-10-13 后勤第二轮反馈）：四项本来就要分开算，
      再给一个「合计」既不是四项之一、又不含加餐，反而容易误读成总数。
   用 table-layout:fixed + colgroup 固定比例，保证窄屏挤得下、姓名不竖排。
   表头用短名「早加餐 / 午加餐」（3 字，能单行显示；全称留给导出表）。
   ⚠️ 改列数 / 列宽 / 内边距后，必须跑 `test-summary-layout.mjs` 复核 320~430px：
      表格不横向溢出、姓名不竖排、表头不裁字、表头单行。 */
.data-table-summary { table-layout: fixed; }
.data-table-summary th, .data-table-summary td { padding: 13px 5px; font-size: 13.5px; }
.data-table-summary thead th { font-size: 11.5px; letter-spacing: 0; }
.data-table-summary .c-id { width: 15%; }
.data-table-summary .c-name { width: 22%; }
.data-table-summary .c-meal { width: 15.5%; }
.data-table-summary .c-extra { width: 16%; }
/* 320px 级极窄屏：再收一档，保证「早加餐」这类 3 字表头仍然单行 */
@media (max-width: 359px) {
  .data-table-summary th, .data-table-summary td { padding: 12px 3px; font-size: 12.5px; }
  .data-table-summary thead th { font-size: 10.5px; }
}

/* ---------------- 弹层 ---------------- */
.overlay {
  position: fixed; inset: 0; z-index: 60;
  display: none;
  align-items: flex-end; justify-content: center;
  background: rgba(34, 28, 70, .42);
  backdrop-filter: blur(3px);
  padding: 0;
}
.overlay.is-open { display: flex; animation: fadeIn .2s ease; }
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }

.sheet {
  width: 100%; max-width: 480px;
  max-height: 88vh; overflow-y: auto;
  background: #fff;
  border-radius: 26px 26px 0 0;
  padding: 20px 18px calc(22px + var(--safe-b));
  animation: slideUp .3s cubic-bezier(.22,.9,.3,1);
  -webkit-overflow-scrolling: touch;
}
@keyframes slideUp { from { transform: translateY(30px); opacity: .6 } to { transform: none; opacity: 1 } }

/* 详情弹窗：居中卡片（内容短时不会飘在底部）
   「关于」也走这里 —— 它是 sheet-dialog（四角全圆角），贴底会把下面两个角切掉。 */
.overlay#details-overlay,
.overlay#cutoff-overlay,
.overlay#about-overlay {
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.sheet-dialog {
  width: 100%;
  max-width: 420px;
  max-height: min(78vh, 620px);
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 24px;
  padding: 20px 20px 18px;
  box-shadow: 0 24px 60px -20px rgba(34, 28, 70, .38);
  animation: popIn .26s cubic-bezier(.22,.9,.3,1);
  overflow: hidden;
}
.sheet-dialog .sheet-head { flex: none; margin-bottom: 14px; }
.sheet-dialog .details-body {
  flex: 1 1 auto;
  min-height: 0;              /* 关键：否则内容会撑破圆角卡片 */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -4px;
  padding: 0 4px;
}

/* 「关于」弹窗：比详情弹窗宽一点，内容靠 .about-body 内部滚动。
   ⚠️ 别把 max-height 写死 —— 里面五条快速访问方式在窄屏会变高。 */
.sheet-about { max-width: 440px; max-height: min(84vh, 700px); }
.about-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -4px;
  /* 底部留 26px：保证滚到底时最后一行落在渐隐区之上，不会被遮住半截 */
  padding: 0 4px 26px;
  /* 底部渐隐：内容进入最下面 26px 时淡出，明确告诉人「下面还有」。
     ⚠️ 2026-10-17 用户反馈：原来内容在第 2 条中间被硬切，看着像「到底了」。
        滚动条解决不了这个问题 —— iOS 的滚动条只在滑动时短暂出现，看不见。
        磨砂也不行：弹窗本来就是白的，白色模糊等于白色渐变，还更脏。
        纯白渐隐是唯一既明显又不干扰阅读的做法。 */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 26px), transparent 100%);
}
/* 桌面端补一条很淡的滚动条（移动端是系统 overlay 滚动条，这条不生效，无副作用） */
.about-body { scrollbar-width: thin; scrollbar-color: rgba(109, 91, 208, .22) transparent; }
.about-body::-webkit-scrollbar { width: 5px; }
.about-body::-webkit-scrollbar-track { background: transparent; }
.about-body::-webkit-scrollbar-thumb {
  background: rgba(109, 91, 208, .22);
  border-radius: 3px;
}
.about-sec + .about-sec {
  margin-top: 20px; padding-top: 18px;
  border-top: 1px solid #efedf9;
}
.about-sec h4 { font-size: 15px; font-weight: 700; color: var(--ink); margin-bottom: 10px; }
.about-sec p { font-size: 14.5px; line-height: 1.75; color: var(--ink-2); }
.about-sec p + p { margin-top: 10px; }
.about-sec strong { color: #6d5bd0; font-weight: 700; }
/* 原「装到桌面后…需要联网」那句（.about-foot）已于 2026-10-17 删除：
   表述容易被读成「之后能离线用」，用户决定整句去掉。 */

.about-list { list-style: none; counter-reset: ab; }
.about-list li {
  position: relative;
  padding-left: 30px;
  font-size: 14.5px; line-height: 1.7; color: var(--ink-2);
}
.about-list li + li { margin-top: 13px; }
.about-list li::before {
  counter-increment: ab; content: counter(ab);
  position: absolute; left: 0; top: 1px;
  width: 21px; height: 21px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: #f1effb; color: #6d5bd0;
  font-size: 12px; font-weight: 700;
}
.about-list b { color: var(--ink); font-weight: 700; }
.about-list span { display: block; color: var(--muted); font-size: 13.5px; margin-top: 2px; }
.about-tag {
  display: inline-block; margin-left: 6px;
  padding: 1px 7px; border-radius: 6px;
  background: #fff1e6; color: #c2410c;
  font-style: normal; font-size: 12px; font-weight: 600;
  vertical-align: 1px;
}

.sheet-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 16px;
}
.sheet-head h3 { font-size: 18px; font-weight: 700; }

.close-btn {
  width: 32px; height: 32px; flex: none;
  /* 同上：清 UA padding + 解掉 min-width:auto，否则 × 偏右 / iOS 上变椭圆。
     这里不能写 max-width —— 厨房端会把它覆盖成 38px（见 #kitchen-day-overlay）。 */
  padding: 0;
  appearance: none; -webkit-appearance: none;
  min-width: 0; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: #f3f2fb; color: var(--muted);
  font-size: 20px; line-height: 1;
}

/* 分段控件 */
.seg {
  display: flex; gap: 4px;
  padding: 4px;
  background: #f3f2fb;
  border-radius: 13px;
  margin-bottom: 16px;
}
.seg button {
  flex: 1; padding: 9px 0;
  border-radius: 10px;
  font-size: 14px; font-weight: 600; color: var(--muted);
  transition: all .18s;
}
.seg button.is-active {
  background: #fff; color: #6d5bd0;
  box-shadow: 0 2px 8px rgba(91,110,225,.16);
}

/* 日历导航 */
.cal-nav {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
}
.cal-arrow {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: 11px;
  background: #f3f2fb; color: var(--ink-2);
  font-size: 20px; line-height: 1;
}
.cal-arrow:active { background: #e8e6f8; }
.cal-arrow:disabled { opacity: .3; pointer-events: none; }
.cal-label { font-size: 15.5px; font-weight: 700; letter-spacing: .3px; }

/* ★★ 2026-10-14 修 iPhone 上「日历对不齐 / 第 7 列溢出面板」（安卓、电脑正常）：
   `1fr` 实际是 `minmax(auto, 1fr)`，那个 auto 的最小值 = grid item 的 min-content。
   iOS Safari 对 `<button class="cal-cell">` 的 min-content 算得比 Chrome 大得多
   （≈ 日期 + 角标并排 + button 的 UA 默认内边距 ≈ 56px），于是 7 列各被撑到 56px，
   总宽超出面板 → 最后一列跑到面板外、且与星期栏错位（两者列宽不一致）。
   修法两条一起上：① 列改成 minmax(0, 1fr) 强制等分；② `.cal-cell` 加 min-width: 0
   并显式 `padding: 0` 抹掉 UA 差异，让 item 也肯收缩。
   ⚠️ 只加 minmax(0,1fr) 不够 —— item 仍会顶着 min-content 溢出列。 */
.cal-weekdays {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  margin-bottom: 6px;
}
.cal-weekdays span {
  text-align: center;
  font-size: 13px; font-weight: 600; color: var(--muted);
}

.cal-grid {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}

.cal-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  display: grid; place-items: center;
  border-radius: 13px;
  font-size: 15px; font-weight: 500;
  color: var(--ink);
  /* ★ iPhone 修复（见上方 .cal-grid 注释）：显式清掉 button 的 UA 内边距，
     并允许收缩到小于内容 min-content，否则 iOS 会把整列撑宽。 */
  padding: 0;
  min-width: 0;
  transition: background .15s, color .15s, transform .12s;
}
.cal-cell:active { transform: scale(.92); }
.cal-cell.is-mute { color: #c9c7dc; pointer-events: none; }
.cal-cell.is-today { box-shadow: inset 0 0 0 1.5px rgba(124,92,224,.45); }
.cal-cell.is-selected {
  background: var(--grad);
  color: #fff; font-weight: 700;
  box-shadow: 0 6px 16px -8px rgba(91,110,225,.9);
}
.cal-cell.is-selected::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 13px;
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.4);
}
/* 已有登记（进入时预选）标记 */
.cal-cell .dot {
  position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%;
  background: #f59e0b;
}

/* 已过截止时间：置灰、不可选 */
.cal-cell.is-locked {
  color: #c4c2d6;
  background: repeating-linear-gradient(
    45deg, #f7f6fb, #f7f6fb 5px, #f1f0f8 5px, #f1f0f8 10px
  );
  pointer-events: none;
  cursor: not-allowed;
}
.cal-cell.is-locked .dot { background: #d6d3e6; }

.sheet-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px;
  margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--line);
}
.sel-count { font-size: 14.5px; color: var(--ink-2); font-weight: 500; }
.sheet-foot .btn { width: auto; margin-top: 0; padding: 13px 30px; }

/* 对话框 */
.dialog {
  width: calc(100% - 40px); max-width: 380px;
  margin: auto;
  background: #fff;
  border-radius: 22px;
  padding: 24px 22px 20px;
  animation: popIn .26s cubic-bezier(.22,.9,.3,1);
}
/* ⚠️ 确认框必须比别的弹窗高一层。
   它可能从别的弹窗**里面**弹出来（如「教职工密码管理」弹窗里的「全校重置」按钮）。
   所有 .overlay 默认同为 z-index: 60，同层级时「DOM 里靠后的盖住靠前的」——
   而 #confirm-overlay 在 index.html 里排在 #pwd-admin-overlay 之前 → 不抬高层级的话
   确认框会被压在密码弹窗底下，表现就是「点了按钮没反应，关掉窗口才冒出确认框」（2026-10-15 实测）。
   70 = 盖住所有 .overlay，又仍在 toast(90) / save-bar(80) 之下。 */
.overlay#confirm-overlay { align-items: center; z-index: 70; }
@keyframes popIn { from { transform: scale(.92); opacity: 0 } to { transform: none; opacity: 1 } }

.dialog h3 { font-size: 17.5px; font-weight: 700; text-align: center; }
.dialog-text {
  margin-top: 12px;
  font-size: 14.5px; line-height: 1.75; color: var(--ink-2);
  text-align: center;
  max-height: 46vh; overflow-y: auto;
}
.dialog-text b { color: #6d5bd0; font-weight: 700; }

/* 「取消 N 天」也是用户这次真要做的动作，不能像补充说明那样灰下去
   （2026-10-17 用户反馈：原来用 #8b88a8 又套一层括号，看着像附注、容易漏看）。
   改法：去掉括号、单独一行、用正文色（近黑），「取消」二字加粗（沿用上面的紫色强调）。 */
.dialog-text .cancel-line { color: var(--ink); }

/* 确认弹窗里的餐次（早餐 / 午餐）单独标红放大：
   有人不看清楚就点「确定」，把餐次选错了。红色比紫色更抓眼。 */
.dialog-text b.meal-hl {
  color: #d93025;
  font-size: 17px;
  font-weight: 800;
  padding: 0 2px;
}

.dialog-btns { display: flex; gap: 11px; margin-top: 22px; }
.dialog-btns .btn { flex: 1; margin-top: 0; padding: 13px 0; letter-spacing: 0; }

/* 详情弹窗内容 */
.details-body { display: flex; flex-direction: column; gap: 14px; }
.detail-person {
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 14px 15px;
}
.detail-person-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 9px;
}
.detail-person-head strong { font-size: 15px; }
.detail-person-head span { font-size: 13.5px; color: var(--muted); }
.detail-line {
  display: flex; gap: 9px; align-items: flex-start;
  font-size: 14px; color: var(--ink-2);
  padding: 3px 0;
}
.detail-line b {
  flex: none; width: 34px;
  font-weight: 600;
}
.detail-line b.bf { color: #6d5bd0; }
.detail-line b.lc { color: #4f6fe0; }
.detail-line b.ex { color: #c2600f; }
.detail-days { word-break: break-all; }

/* ---------------- Toast ---------------- */
.toast {
  position: fixed; left: 50%; bottom: 44px; z-index: 90;
  transform: translate(-50%, 20px);
  max-width: 82vw;
  padding: 12px 20px;
  border-radius: 999px;
  background: rgba(34,28,70,.92);
  color: #fff; font-size: 14px; text-align: center;
  opacity: 0; pointer-events: none;
  transition: opacity .24s, transform .24s;
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }

/* ============================================================
   食堂工作人员端
   ============================================================ */

/* 日历格子要额外放一行「早/午人数」，所以比正方形略高
   （2026-10-13 适老化：日期 14.5→16px、角标 10→12px，格子仍有余量，比例不动） */
.kcal-grid { gap: 4px; }
.kcal-cell {
  aspect-ratio: 1 / 1.18;
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start;
  gap: 2px; padding-top: 4px;
  border-radius: 13px;
  background: #fafaff;
  font-size: 16px; font-weight: 600; line-height: 1;
  color: var(--ink-2);
  transition: background .15s, transform .12s, box-shadow .15s;
}
.kcal-cell:active { transform: scale(.94); }
.kcal-cell.is-mute {
  background: transparent; color: #d4d2e4;
  pointer-events: none;
}
.kcal-cell.is-today {
  background: #f5f2ff;
  color: #5b4bc4;
  box-shadow: inset 0 0 0 1.6px rgba(124,92,224,.5);
}
.kcal-cell.has-data { background: #f7f6ff; }
.kcal-cell.has-data.is-today { background: #f2eeff; }

/* 角标：早/午 人数（适老化：10→12px，「12/15」在 390px 屏仍放得下） */
.kcal-num { display: flex; align-items: center; gap: 1px; line-height: 1; }
.kcal-num b {
  font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* ⚠️ 斜杠原来是 #d3d0e4，在浅紫底上对比度只有 ~1.5:1 —— 食堂端反馈「几乎看不出来」
   （2026-10-16）。改成项目统一的次级文字色 --muted 并加粗，对比度约 3.4:1，一眼能读出「早/午」。 */
.kcal-num i { font-style: normal; font-size: 10px; font-weight: 700; color: var(--muted); }

/* 当天有加餐时的小圆点（食堂看到就知道这几份里有加餐） */
.kcal-ex {
  width: 5px; height: 5px; border-radius: 50%;
  background: #e0862e;
}

/* 320~380px 极窄屏：7 列平分后每格只有 33~38px，
   「12/15」这种两位数角标会顶到格子边 → 回落一档（仍比原来的 10px 大）。
   390px 及以上用上面的 16px / 12px。 */
@media (max-width: 380px) {
  .kcal-cell { font-size: 15px; }
  .kcal-num b { font-size: 11px; }
  .kcal-num i { font-size: 9px; }
}

.kb-bf { color: #6d5bd0; }
.kb-lc { color: #4f6fe0; }

.kcal-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-top: 14px;
}
.kcal-legend { font-size: 14px; color: var(--muted); }
.kcal-legend b { font-weight: 700; }

.kcal-total {
  margin-top: 14px; padding: 16px 18px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow-sm);
}
.kt-item { display: flex; flex-direction: column; gap: 2px; }
.kt-item em { font-style: normal; font-size: 14px; color: var(--muted); }
.kt-item b {
  font-size: 23px; font-weight: 700; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.kt-item b i { font-style: normal; font-size: 14px; font-weight: 500; color: var(--muted); }
.kt-extra { font-size: 13.5px; font-weight: 600; color: #c2600f; }
.kt-bf b { color: #6d5bd0; }
.kt-lc b { color: #4f6fe0; }

/* ---------------- 当天就餐名单弹窗 ---------------- */
.overlay#kitchen-day-overlay {
  align-items: center;
  justify-content: center;
  padding: 20px;
}
/* 适老化：字号整体加大后单屏可视行数变少，弹窗高度放宽一点（86vh→90vh） */
.sheet-dialog.sheet-day { max-width: 440px; max-height: min(90vh, 780px); }

.kd-stats {
  flex: none;
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin-bottom: 16px;
}
.kd-stat {
  display: flex; flex-direction: column; gap: 1px;
  padding: 13px 15px;
  border-radius: 16px;
}
.kd-stat em { font-style: normal; font-size: 14px; }
.kd-stat b {
  font-size: 27px; font-weight: 700; line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.kd-stat-bf { background: #f4f1ff; }
.kd-stat-bf em { color: #7a6cc4; }
.kd-stat-bf b { color: #6d5bd0; }
.kd-stat-lc { background: #eef3ff; }
.kd-stat-lc em { color: #6b81c8; }
.kd-stat-lc b { color: #4f6fe0; }

.kd-body {
  flex: 1 1 auto;
  min-height: 0;                 /* 关键：否则内容会撑破圆角卡片 */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -4px;
  padding: 0 4px;
}
.kd-section + .kd-section { margin-top: 18px; }

.kd-sub { display: flex; align-items: center; gap: 8px; margin-bottom: 9px; }
.kd-tag {
  padding: 4px 13px; border-radius: 999px;
  font-size: 14px; font-weight: 700; color: #fff;
}
.kd-tag-bf { background: linear-gradient(135deg, #6d5bd0, #8f6ce8); }
.kd-tag-lc { background: linear-gradient(135deg, #4f6fe0, #6f9bf0); }
.kd-sub-num { font-size: 14.5px; color: var(--muted); }

.kd-table-wrap {
  border-radius: 14px;
  border: 1px solid var(--line);
  overflow: hidden;
}
.kd-table th, .kd-table td { padding: 12px 16px; font-size: 16px; }
.kd-table td:first-child {
  width: 96px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.kd-table td:last-child { font-weight: 600; }
/* 表头（编号/姓名）单独提一档：`.data-table thead th` 权重更高，
   不写这条会被它按 12.5px 压住（适老化：12.5 → 14px） */
.kd-table thead th { font-size: 14px; }
/* 加餐份数标记：食堂要一眼看出这几份是加餐（不补贴的那部分） */
.kd-extra {
  display: inline-block;
  margin-left: 7px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 13.5px; font-weight: 700;
  background: #fff1e9; color: #c2600f;
}
/* 加餐备注：跟在姓名下面另起一行，不跟份数标记挤在一起（备注最多 30 字，挤一行会截断）。
   左边一条细线做视觉区分，长备注自动换行、不会撑破表格（2026-10-13 新增）。 */
.kd-note {
  display: block;
  margin-top: 3px;
  padding-left: 7px;
  border-left: 2px solid #ded9f0;
  font-size: 14px; font-weight: 500;
  color: var(--muted);
  line-height: 1.4;
  word-break: break-word;
}
/* 空状态：要压过后面的 td:last-child 字重，所以带上 td */
.kd-table td.kd-empty {
  padding: 18px;
  text-align: center;
  font-size: 15px; font-weight: 400;
  color: var(--muted);
}

/* ---------------- 食堂端 · 适老化字号（2026-10-13 加） ----------------
   食堂工作人员年龄偏大，反馈「整体字偏小」。
   上面已把食堂端**专属**类（`.kcal-*` / `.kt-*` / `.kd-*`）整体提了一档；
   这一节再覆盖一批**与管理端 / 教职工端共用**的类。
   ★ 全部用 `[data-view="kitchen-*"]` / `#kitchen-day-overlay` 限定作用域，
     管理端与教职工端的字号一律不动（那边此前已按普通用户调过）。
   ⚠️ 改这里的数值后：跑 `npm run test -- test-kitchen test-pw`，
      并在 320 / 390px 两个宽度下确认日历格子与名单表格不横向溢出。 */

/* 登录页 */
[data-view="kitchen-login"] .panel-title { font-size: 23px; }
[data-view="kitchen-login"] .panel-sub { font-size: 15.5px; }
[data-view="kitchen-login"] .field-label { font-size: 15px; }
[data-view="kitchen-login"] .form-err { font-size: 15px; }
[data-view="kitchen-login"] .btn { font-size: 17px; }

/* 首页 · 顶部用户条（「点击日期查看就餐名单」是唯一的操作引导，必须看得清。
   文案已按 15px 重排过一次：原「点击某一天查看当天就餐名单」14 字在 390px 屏会折行，
   缩成 10 字后单行放下 —— 以后改这句文案要按 15px × 字数 ≤ 188px 估一下） */
[data-view="kitchen-home"] .avatar { font-size: 22px; }
[data-view="kitchen-home"] .user-info strong { font-size: 19px; }
[data-view="kitchen-home"] .user-info em { font-size: 15px; line-height: 1.4; }
[data-view="kitchen-home"] .text-btn { font-size: 15px; padding: 9px 14px; }

/* 首页 · 月份导航 / 星期栏（翻月箭头同时加大到 42px，方便点） */
[data-view="kitchen-home"] .cal-arrow {
  width: 42px; height: 42px;
  font-size: 24px; border-radius: 13px;
}
[data-view="kitchen-home"] .cal-label { font-size: 18px; }
[data-view="kitchen-home"] .cal-weekdays span { font-size: 14px; }

/* 当天名单弹窗 · 头部 */
#kitchen-day-overlay .sheet-head h3 { font-size: 20px; }
#kitchen-day-overlay .close-btn { width: 38px; height: 38px; font-size: 24px; }

/* ---------------- 临时加餐弹窗 ---------------- */
.ex-row {
  display: flex; align-items: center; gap: 10px;
  margin-top: 14px;
}
.ex-row-label {
  flex: none;
  font-size: 14px; font-weight: 600; color: var(--ink-2);
}
.qty-step {
  flex: none;
  display: flex; align-items: center; gap: 2px;
  padding: 3px;
  border-radius: 12px;
  background: #f3f2fb;
}
.qty-btn {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: #fff;
  color: #6d5bd0;
  font-size: 17px; font-weight: 700; line-height: 1;
  box-shadow: 0 1px 3px rgba(34, 28, 70, .1);
}
.qty-btn:active { transform: scale(.93); }
.qty-btn:disabled { opacity: .35; pointer-events: none; }
.qty-val {
  min-width: 30px; text-align: center;
  font-size: 16px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.ex-note {
  flex: 1; min-width: 0;
  padding: 9px 12px;
  border-radius: 12px;
  border: 1.5px solid var(--line);
  background: #fbfaff;
  font-size: 14px;
}
.ex-note:focus { outline: none; border-color: #b9aef0; background: #fff; }
.ex-note::placeholder { color: #b0adc6; }

/* 加餐弹窗的操作提示：只留一句话，字号放大到一眼能看见
   （2026-10-12 反馈：以前两行小字没人耐心看） */
.ex-tip {
  margin-top: 12px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink-2);
}
.ex-tip .tip-hl { color: #d93025; font-weight: 800; }

/* 加餐日历：有加餐的格子标出份数 */
#ex-grid .cal-cell.is-extra {
  background: #fff1e9;
  color: #c2600f;
  box-shadow: inset 0 0 0 1.5px rgba(216, 122, 45, .35);
}
#ex-grid .cal-cell.is-extra.is-selected {
  background: linear-gradient(135deg, #f0813c, #e0662e);
  color: #fff;
  box-shadow: 0 6px 16px -8px rgba(224, 102, 46, .9);
}

/* 加餐弹窗整体跟着餐次走色：早餐=橙、午餐=绿（与首页两张卡片一致） */
#extra-overlay.is-bf .sheet-head h3 { color: #a8540c; }
#extra-overlay.is-lc .sheet-head h3 { color: #17693c; }

#extra-overlay.is-lc #ex-grid .cal-cell.is-extra {
  background: #eaf7ef;
  color: #17693c;
  box-shadow: inset 0 0 0 1.5px rgba(31, 122, 69, .32);
}
#extra-overlay.is-lc #ex-grid .cal-cell.is-extra.is-selected {
  background: linear-gradient(135deg, #3aa96a, #248a52);
  box-shadow: 0 6px 16px -8px rgba(36, 138, 82, .9);
}
/* 只改未选中态的字色，选中态是白字（上面那条规则）不能被盖掉 */
#extra-overlay.is-lc #ex-grid .cal-cell.is-extra:not(.is-selected) .cal-qty { color: #17693c; }

/* 确定按钮也跟着餐次 */
#extra-overlay.is-bf .btn-primary { background: linear-gradient(135deg, #ef8a3f, #e0662e); }
#extra-overlay.is-lc .btn-primary { background: linear-gradient(135deg, #3aa96a, #248a52); }
.cal-qty {
  position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%);
  padding: 1px 5px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; line-height: 1.4;
  background: rgba(255, 255, 255, .88);
  color: #c2600f;
}
.cal-cell.is-selected .cal-qty {
  background: rgba(255, 255, 255, .3);
  color: #fff;
}

/* ============================================================
   按时间段统计导出
   ============================================================ */
.sheet-dialog.sheet-range { max-width: 440px; max-height: min(92vh, 760px); }

/* 同 .import-body：必须自带 flex/min-height，否则内容一高就把 .sheet-foot 顶出卡片 */
.range-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

.range-chips {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-bottom: 14px;
}
.range-chips button {
  padding: 7px 14px;
  border-radius: 999px;
  background: #f3f2fb; color: var(--ink-2);
  font-size: 14px; font-weight: 600;
  transition: background .15s, color .15s;
}
.range-chips button:active { background: #e8e6f8; }
.range-chips button.is-active {
  background: var(--grad); color: #fff;
  box-shadow: 0 6px 16px -9px rgba(91,110,225,.9);
}

.range-fields {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 16px;
}
.range-field {
  flex: 1 1 0; min-width: 0;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  background: #f6f5ff; border: 1px solid #e6e3f8;
  text-align: center;
}
.range-field em {
  display: block; font-style: normal;
  font-size: 12.5px; color: var(--muted); margin-bottom: 3px;
}
.range-field b {
  font-size: 14.5px; font-weight: 700; letter-spacing: .2px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.range-field.is-empty b { color: #c9c7dc; font-weight: 500; }
.range-arrow { color: #b9b6d0; font-size: 15px; flex: none; }

/* 区间高亮：中间是浅紫色块，首尾两个端点是实心胶囊。
   格子之间有 4px 间隙，做不出连续色带，所以端点用实心块区分最清楚。 */
.cal-cell.is-range { background: #efeafd; border-radius: 8px; }
.cal-cell.is-range-end {
  background: var(--grad);
  color: #fff; font-weight: 700;
  border-radius: 13px;
  box-shadow: 0 6px 16px -8px rgba(91,110,225,.9);
}

.range-tip {
  margin: 14px 0 0;
  font-size: 12.5px; line-height: 1.85; color: var(--muted);
}
.range-tip b { color: var(--ink-2); }

/* ============================================================
   电脑端适配
   ============================================================ */
@media (min-width: 720px) {
  .app { max-width: 780px; padding: 0 32px 48px; }

  .topbar { padding: 34px 0 20px; }
  .school-name { font-size: 19px; }
  .school-mark { width: 38px; height: 38px; font-size: 18px; }

  .hero-card { padding: 32px 30px; }
  .hero-text strong { font-size: 24px; }
  .hero-badge { width: 64px; height: 64px; font-size: 32px; }

  .tile-card { padding: 26px 30px; }
  .tile-text strong { font-size: 20px; }

  /* 主页：顶部大卡片通栏，下面两张入口卡片并排 */
  .view[data-view="home"] {
    display: none;
  }
  .view[data-view="home"].is-active {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    align-items: start;
  }
  .view[data-view="home"] .hero-card {
    grid-column: 1 / -1;
    margin-bottom: 0;
    min-height: 0;
    position: relative;
  }
  .view[data-view="home"] .tile-card {
    margin-bottom: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    min-height: 210px;
    padding: 30px 28px;
    position: relative;
  }
  .view[data-view="home"] .chev { position: absolute; right: 26px; bottom: 24px; }

  .meal-grid { gap: 20px; }
  .meal-card { padding: 28px 26px 25px; }
  .meal-emoji { font-size: 40px; }
  .meal-title { font-size: 24px; }
  .meal-sub { font-size: 15px; }
  .extra-grid { gap: 20px; }
  .extra-card { gap: 11px; min-height: 96px; padding: 14px 18px; }
  .extra-emoji { width: 34px; height: 34px; font-size: 19px; border-radius: 11px; }
  .extra-title { font-size: 19px; }
  .extra-sub { font-size: 14px; }

  .panel { padding: 34px 32px 30px; }
  .field input { padding: 16px 18px; }

  .month-grid { grid-template-columns: repeat(4, 1fr); gap: 14px; }
  .month-cell { padding: 18px 8px; border-radius: 18px; }
  .month-cell b { font-size: 18px; }
  .month-cell em { font-size: 13px; }

  /* 电脑端弹窗居中显示 */
  .overlay { align-items: center; padding: 24px; }
  .sheet {
    max-width: 460px;
    border-radius: 26px;
    padding: 26px 26px 24px;
    max-height: 86vh;
  }
  .sheet-dialog { max-width: 480px; max-height: min(80vh, 700px); padding: 24px 24px 22px; }

  .cal-cell { border-radius: 15px; font-size: 16px; }

  .btn-primary { max-width: 100%; }
  .panel .btn-primary { max-width: 100%; }
}

@media (min-width: 1024px) {
  .app { max-width: 900px; }
}

/* 桌面端悬停效果
   ⚠️ **以后新增可点元素，别忘了加进这个块** —— 加餐卡片（`.extra-card`）就漏过一次：
   它只有 `:active`（按下去才缩放），鼠标移上去毫无动静（2026-10-17 用户反馈）。
   `.text-btn`（修改密码 / 退出）也是同样的问题，一起补上。 */
@media (hover: hover) {
  .hero-card:hover, .tile-card:hover, .month-cell:hover, .meal-card:hover,
  .extra-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 22px 48px -20px rgba(91,110,225,.55);
  }
  .text-btn:hover { background: rgba(124,92,224,.08); color: var(--ink-2); }
  .about-btn:hover { background: rgba(109, 91, 208, .18); }
  .chip-x:hover { background: rgba(109,91,208,.3); }
  .cal-cell:not(.is-mute):hover { background: #f2f1fd; }
  .cal-cell.is-selected:hover { background: var(--grad); }
}


/* ---------------- 手机端「保存文件」浮条 ----------------
   为什么需要它：手机浏览器里从「点导出」到「真正保存」之间要加载解析库
   再取一次数据，容易超过浏览器给的 5 秒「用户手势」窗口 —— 那时调分享
   或下载都会被拒（表现就是「有提示、但文件找不到」）。所以这里给一个
   用户主动点的按钮，点下去手势一定有效。桌面端不会出现。 */
.save-bar {
  position: fixed;
  left: 12px; right: 12px;
  bottom: calc(14px + var(--safe-b));
  z-index: 80;
  display: flex; align-items: center; gap: 10px;
  max-width: 456px; margin: 0 auto;
  padding: 10px 10px 10px 14px;
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 14px 34px -12px rgba(60, 45, 130, .42), 0 2px 8px rgba(60, 45, 130, .1);
  animation: fadeUp .26s cubic-bezier(.22,.9,.3,1);
}
.save-bar-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.save-bar-label { font-size: 12.5px; color: var(--muted); }
.save-bar-name {
  font-size: 14px; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.save-bar-hint { font-size: 12.5px; color: #8b88a8; }
.save-bar-btns { flex: none; display: flex; align-items: center; gap: 6px; }
.save-bar-close {
  width: 30px; height: 30px; flex: none;
  /* 同上：清 UA padding + 解掉 min-width:auto；原来是普通 inline-block，
     靠 line-height 对齐，字形的 side bearing 一偏就看得出来 → 改 grid 居中。 */
  padding: 0;
  appearance: none; -webkit-appearance: none;
  min-width: 0; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  font-size: 17px; line-height: 1; color: var(--muted);
  background: #f2f1f8;
}
.save-bar .btn {
  padding: 9px 18px; font-size: 14px;
  /* ⚠️ 必须清掉 .btn-primary 带过来的 margin-top: 22px —— 那是给表单主按钮
     和上方输入框拉开距离用的。浮条里按钮是 flex item，margin 会参与
     `align-items: center` 的对齐计算，把「保存」整体压低 22/2 = **11px**，
     看起来就是「按钮偏下」。2026-10-18 用户反馈，实测 closeOff=0 / okOff=11。
     `width: 100%` 同样还原成 auto（浮条里不该占满整行）。 */
  margin-top: 0;
  width: auto;
}

/* ============================================================
   修改密码 / 教职工密码管理（2026-10-15 加）
   ============================================================ */

/* ---------------- 职工端 · 修改密码 ---------------- */
.pwd-notice {
  margin-top: 18px; padding: 13px 15px;
  border-radius: var(--radius-md);
  background: #f2efff; color: #5b4ba8;
  font-size: 14px; line-height: 1.6;
}
.pwd-hint {
  margin-top: 14px;
  font-size: 13.5px; color: var(--muted);
  text-align: center; line-height: 1.5;
}

/* ---------------- 管理端 · 密码管理弹窗 ---------------- */
.sheet-pwd { max-width: 460px; }
.pwd-admin-body { overflow-y: auto; padding: 0 22px 22px; }

.pwd-block { margin-top: 20px; }
.pwd-block + .pwd-block {
  border-top: 1px solid var(--line);
  padding-top: 20px;
}
.pwd-block-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.pwd-block-head .field-label { margin-bottom: 0; }
.pwd-cur {
  padding: 4px 12px; border-radius: 10px;
  background: #f2efff; color: #5b4ba8;
  font-size: 15px; font-weight: 700; letter-spacing: .6px;
  font-variant-numeric: tabular-nums;
}

.pwd-row { display: flex; gap: 9px; margin-top: 11px; }
.pwd-row input {
  flex: 1 1 auto; min-width: 0;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  border: 1.5px solid var(--line);
  background: #fafaff; color: var(--ink);
  font-size: 15px; outline: none;
  transition: border-color .18s, box-shadow .18s, background .18s;
}
.pwd-row input::placeholder { color: #b0adc6; }
.pwd-row input:focus {
  border-color: #8b7ce8; background: #fff;
  box-shadow: 0 0 0 4px rgba(124,92,224,.13);
}
/* 弹窗里的按钮不要撑满整行（.btn-primary 默认 width:100%） */
.pwd-row .btn { flex: none; width: auto; margin-top: 0; padding: 12px 18px; font-size: 14.5px; }
.pwd-block > .btn { width: 100%; margin-top: 11px; }

.pwd-note {
  margin-top: 9px;
  font-size: 13px; line-height: 1.55; color: var(--muted);
}

/* 导入预览里「密码列留空」的说明（用初始密码 / 不改） */
.pwd-auto { font-size: 13.5px; color: #8b88a8; }

.btn-danger {
  width: 100%;
  background: linear-gradient(135deg, #e2574f 0%, #c0342c 100%);
  color: #fff;
  box-shadow: var(--shadow-sm);
}
