/* 考勤工作台 · 设计系统
 *
 * 一套样式供所有页面用。改一次，全站生效——不做每个页面各写一份。
 *
 * 尺寸、颜色的依据见 docs/DESIGN.md。三条原则：
 * 1. 结构靠留白和层级，不靠边框和分割线堆砌。
 * 2. 每个可点的东西都有可见的反馈（hover / focus / active）。
 * 3. 数字一律等宽右对齐——对账时眼睛要能竖着扫。
 */

:root {
  /* 品牌色。比默认蓝更沉一点：这是每天要开八小时的工具，不是营销页。 */
  --brand: #1a63d8;
  --brand-hover: #1550b3;
  --brand-weak: #eaf1fd;
  --brand-ring: rgba(26, 99, 216, .16);

  /* 中性色。冷灰，六级足够表达所有层级。 */
  --fg: #171b23;
  --fg-2: #48505e;
  --fg-3: #77808f;
  --fg-4: #a8b0bd;

  --line: #e8eaef;
  --line-strong: #d6dae2;
  --bg: #f5f6f9;
  --surface: #fff;
  --hover: #f4f6f9;
  --sunken: #f0f2f6;

  /* 状态色。都配一档浅底，用于标签和提示条。 */
  --danger: #c8283c;
  --danger-weak: #fdeef0;
  --warn: #b5590a;
  --warn-weak: #fdf1e0;
  --ok: #0a7f43;
  --ok-weak: #e9f7ef;

  /* 阴影。克制地用：卡片靠边框，浮层才用阴影。 */
  --shadow-sm: 0 1px 2px rgba(23, 27, 35, .05);
  --shadow-md: 0 4px 14px rgba(23, 27, 35, .09);
  --shadow-lg: 0 12px 32px rgba(23, 27, 35, .14);

  --topbar-h: 56px;
  --sidebar-w: 208px;
  --toolbar-h: 50px;
  --row-h: 38px;

  --radius: 10px;
  --radius-sm: 6px;
  --radius-xs: 4px;

  --ease: cubic-bezier(.4, 0, .2, 1);
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 13.5px/1.55 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei",
        "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: var(--brand); text-decoration: none; transition: color .15s var(--ease); }
a:hover { color: var(--brand-hover); }

/* ---------- 顶栏 ---------- */

.topbar {
  height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 14px;
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 20;
}

.topbar .brand {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--fg);
  letter-spacing: -.005em;
}
.topbar .brand .sep { color: var(--fg-4); font-weight: 400; margin: 0 7px; }
.topbar .brand .sub { color: var(--fg-2); font-weight: 400; }

.topbar .spacer { flex: 1; }

.topbar .user {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--fg-2);
  font-size: 13px;
}
.topbar .user .avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--brand-weak); color: var(--brand);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600;
}

/* ---------- 侧栏 ---------- */

.sidebar {
  position: fixed;
  top: var(--topbar-h);
  bottom: 0;
  left: 0;
  width: var(--sidebar-w);
  background: var(--surface);
  border-right: 1px solid var(--line);
  padding: 12px 0;
  overflow-y: auto;
}

.sidebar .group {
  padding: 14px 18px 7px;
  font-size: 11px;
  color: var(--fg-4);
  letter-spacing: .06em;
  font-weight: 500;
}

.sidebar a {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 36px;
  margin: 1px 8px;
  padding: 0 10px;
  color: var(--fg-2);
  font-size: 13.5px;
  border-radius: var(--radius-sm);
  position: relative;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.sidebar a:hover { background: var(--hover); color: var(--fg); }
.sidebar a.on {
  background: var(--brand-weak);
  color: var(--brand);
  font-weight: 500;
}

/* ---------- 内容区 ---------- */

/* 整页不滚，只有内容区滚。
 *
 * 原来整页滚动 + 工具条 sticky top:0，结果工具条粘在视口顶部，
 * 被 56px 的顶栏盖住一半。而 HR 的用法是「筛完往下翻人」——
 * 筛选条件必须一直在眼前，翻的时候不能跑掉。
 */
.main {
  margin-left: var(--sidebar-w);
  margin-top: var(--topbar-h);
  height: calc(100vh - var(--topbar-h));
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.toolbar {
  /* 工具条里的控件比过去多了（白名单开关、完整列开关、核对、导出），
     1280 宽的笔记本上会挤到右边看不见。允许横向滚动，
     比换行好——换行会把 48px 的工具条撑成两行，内容区下移。 */
  height: var(--toolbar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  z-index: 10;
}
.toolbar::-webkit-scrollbar { display: none; }
.toolbar .spacer { flex: 1 0 8px; }

.content {
  padding: 12px 14px 14px;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: auto;
}

/* 有数据表的页面：内容区自己不滚，让表格滚。
 * 否则会出现「页面一条滚动条 + 表格一条滚动条」，工具条跟着页面滚走。
 * 文档类页面（规则说明、系统状态）没有表格，保持 content 自己滚。 */
.content:has(> .table-wrap) {
  overflow: hidden;
}

.page-title {
  font-size: 19px;
  font-weight: 600;
  margin: 0 0 5px;
  letter-spacing: -.01em;
}
.page-desc {
  color: var(--fg-3);
  font-size: 13px;
  margin: 0 0 18px;
  max-width: 760px;
  line-height: 1.6;
}

/* ---------- 控件 ---------- */

input, select, button, textarea {
  font: inherit;
  font-size: 13.5px;
  color: var(--fg);
}

input[type="text"], input[type="search"], input[type="date"], select, textarea {
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  outline: none;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
input[type="text"]:focus, input[type="search"]:focus,
input[type="date"]:focus, select:focus, textarea:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-ring);
}
input::placeholder { color: var(--fg-4); }
input:disabled, select:disabled { background: var(--sunken); color: var(--fg-3); }

select { padding-right: 24px; cursor: pointer; }

button, .btn {
  height: 34px;
  padding: 0 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  transition: border-color .15s var(--ease), color .15s var(--ease),
              background .15s var(--ease), box-shadow .15s var(--ease);
}
button:hover, .btn:hover { border-color: var(--brand); color: var(--brand); }
button:active, .btn:active { transform: translateY(.5px); }
button:focus-visible, .btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--brand-ring);
}
button:disabled { color: var(--fg-4); border-color: var(--line); cursor: not-allowed; background: var(--sunken); }
button:disabled:hover { color: var(--fg-4); border-color: var(--line); }

button.primary, .btn.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  box-shadow: var(--shadow-sm);
}
button.primary:hover, .btn.primary:hover {
  background: var(--brand-hover);
  border-color: var(--brand-hover);
  color: #fff;
}

button.text {
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand);
}
button.text:hover { color: var(--brand-hover); }

button.danger-text { color: var(--fg-3); }
button.danger-text:hover { color: var(--danger); border-color: transparent; }

/* ---------- 数据表 ---------- */

.table-wrap {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: auto;
  /* 高度交给 flex 分配，不再用 calc 猜——猜错就会多出一条滚动条 */
  flex: 1;
  min-height: 0;
  box-shadow: var(--shadow-sm);
}

table.data {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13.5px;
}

table.data thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--sunken);
  color: var(--fg-2);
  font-weight: 500;
  font-size: 12.5px;
  height: 36px;
  padding: 0 12px;
  text-align: left;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  user-select: none;
}

table.data thead th.sortable { cursor: pointer; transition: color .15s var(--ease); }
table.data thead th.sortable:hover { color: var(--brand); }
table.data thead th .arrow { color: var(--fg-4); margin-left: 3px; font-size: 10px; display: inline-block; width: 8px; }
table.data thead th.sorted { color: var(--brand); }
table.data thead th.sorted .arrow { color: var(--brand); }

table.data tbody td {
  height: var(--row-h);
  /* 12px 两侧在 16 列的报表里太奢侈：每列少 10px，八列才省得下 80px，
     而 16 列一起省就是 160px。数字列本来就不需要那么宽的呼吸空间。 */
  padding: 0 7px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

table.data tbody tr { transition: background .1s var(--ease); }
table.data tbody tr:hover td { background: var(--hover); }
table.data tbody tr.clickable { cursor: pointer; }
table.data tbody tr.selected td { background: var(--brand-weak); }
table.data tbody tr:last-child td { border-bottom: 0; }

table.data .num { text-align: right; font-variant-numeric: tabular-nums; }
table.data .name { font-weight: 500; }
table.data .muted { color: var(--fg-3); }
table.data .faint { color: var(--fg-4); }
table.data .money { color: var(--danger); font-variant-numeric: tabular-nums; font-weight: 500; }
table.data .warn { color: var(--warn); }

.col-check { width: 36px; }
.col-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--fg-3); }

/* ---------- 状态 ---------- */

.state {
  padding: 56px 20px;
  text-align: center;
  color: var(--fg-3);
  font-size: 13.5px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.state .title { color: var(--fg-2); font-size: 14px; font-weight: 500; margin-bottom: 6px; }
.state .hint { font-size: 12.5px; color: var(--fg-3); }
.state.error { border-color: var(--danger-weak); background: var(--danger-weak); color: var(--danger); }

.skeleton-row td { padding: 0 12px; height: var(--row-h); }
.skeleton {
  height: 10px;
  border-radius: 3px;
  background: linear-gradient(90deg, #eef0f4 25%, #f7f8fa 37%, #eef0f4 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
}
@keyframes shimmer {
  from { background-position: 100% 50%; }
  to { background-position: 0 50%; }
}

/* ---------- 分页 ---------- */

.pager {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 2px 0;
  color: var(--fg-3);
  font-size: 12.5px;
}
.pager .spacer { flex: 1; }
.pager button { height: 28px; padding: 0 10px; font-size: 12.5px; }
.pager .pages { display: flex; gap: 4px; }
.pager .pages button.on {
  background: var(--brand); border-color: var(--brand); color: #fff;
}

/* ---------- 抽屉 ---------- */

.drawer-mask {
  position: fixed;
  inset: 0;
  background: rgba(23, 27, 35, .38);
  backdrop-filter: blur(1px);
  z-index: 40;
  animation: fade .18s var(--ease);
}
.drawer-mask[hidden] { display: none; }

@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes slide-in { from { transform: translateX(24px); opacity: .6; } to { transform: none; opacity: 1; } }

.drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 760px;
  max-width: 94vw;
  background: var(--surface);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  z-index: 41;
  display: flex;
  flex-direction: column;
  animation: slide-in .2s var(--ease);
}
.drawer[hidden] { display: none; }

.drawer-head {
  padding: 16px 22px;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: flex-start;
  gap: 14px;
}
.drawer-head .spacer { flex: 1; }
.drawer-head h2 { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: -.01em; }
.drawer-head .sub { color: var(--fg-3); font-size: 12.5px; margin-top: 4px; }
.drawer-body { padding: 0; overflow: auto; flex: 1; }

.kv {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border-bottom: 1px solid var(--line);
}
.kv > div { background: var(--surface); padding: 13px 18px; }
.kv .k { color: var(--fg-3); font-size: 12px; }
.kv .v { font-size: 17px; font-weight: 500; font-variant-numeric: tabular-nums; margin-top: 3px; }
.kv .v.danger { color: var(--danger); }

/* ---------- 通用零件 ---------- */

.tag {
  display: inline-block;
  padding: 0 8px;
  height: 21px;
  line-height: 21px;
  border-radius: var(--radius-xs);
  font-size: 12px;
}
.tag.off { background: var(--warn-weak); color: var(--warn); }
.tag.work { background: var(--brand-weak); color: var(--brand); }
.tag.ok { background: var(--ok-weak); color: var(--ok); }
.tag.bad { background: var(--danger-weak); color: var(--danger); }
.tag.plain { background: var(--hover); color: var(--fg-2); }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 30px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 99px;
  background: var(--surface);
  font-size: 12.5px;
  cursor: pointer;
  transition: border-color .15s var(--ease), color .15s var(--ease);
}
.chip:hover { border-color: var(--brand); color: var(--brand); }
.chip .n { color: var(--fg-3); font-variant-numeric: tabular-nums; }

.section { margin-bottom: 28px; }
.section-title {
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 5px;
}
.section-desc {
  color: var(--fg-3);
  font-size: 12.5px;
  margin: 0 0 13px;
  max-width: 720px;
}

.notice {
  border-left: 3px solid var(--warn);
  background: var(--warn-weak);
  padding: 11px 15px;
  font-size: 12.5px;
  color: var(--fg-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin-top: 12px;
  line-height: 1.6;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  transform: translate(-50%, 8px);
  background: #1b2029;
  color: #fff;
  padding: 10px 20px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  z-index: 60;
  opacity: 0;
  transition: opacity .2s var(--ease), transform .2s var(--ease);
  pointer-events: none;
  box-shadow: var(--shadow-md);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.error { background: var(--danger); }

.faint { color: var(--fg-3); }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }

/* 抽屉底部操作区：快捷操作放在能看见数字的地方，而不是让人回设置页找 */
.drawer-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line);
  background: var(--sunken);
}
.drawer-actions .hint { font-size: 12.5px; color: var(--fg-3); }
.drawer-actions .spacer { flex: 1; }
.btn-exempt {
  white-space: nowrap;
  min-width: 108px;
}
.btn-exempt[data-on="1"] {
  border-color: var(--warn);
  color: var(--warn);
  background: var(--warn-weak);
}

/* 白名单标记：一行的扣款是 0 时，要能一眼看出是「不该算」而不是「算漏了」 */
.badge-exempt {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 6px;
  border-radius: var(--radius-xs);
  font-size: 11px;
  line-height: 16px;
  color: var(--fg-3);
  background: var(--sunken);
  vertical-align: 1px;
}

/* ---------- 汇总条 ---------- */

.summary {
  flex: none;
  display: flex;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 10px;
}
.summary > div {
  flex: 1;
  background: var(--surface);
  padding: 13px 18px;
}
.summary .k {
  font-size: 12px;
  color: var(--fg-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.summary .v {
  font-size: 20px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
  letter-spacing: -.01em;
}
.summary .v small { font-size: 12px; font-weight: 400; color: var(--fg-3); margin-left: 2px; }

/* 紧凑模式：窄屏时汇总条两列 */
@media (max-width: 1100px) {
  .summary { flex-wrap: wrap; }
  .summary > div { flex: 1 0 calc(33.33% - 1px); }
}

/* ---------- 搜索选人（共用） ----------
 *
 * 白名单页和例外页都要「按名字找人」，两处各写一份的结果是同一件事
 * 有两种长相。这里定义一次，页面只负责数据。
 */

.picker { position: relative; }
.picker input { width: 100%; }
.picker .results {
  position: absolute;
  z-index: 40;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 280px;
  overflow: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  animation: fade .12s var(--ease);
}
.picker .results:empty { display: none; }
.picker .opt {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 9px 12px;
  cursor: pointer;
  border-bottom: 1px solid var(--line);
  transition: background .1s var(--ease);
}
.picker .opt:last-child { border-bottom: none; }
.picker .opt:hover, .picker .opt.active { background: var(--hover); }
.picker .opt .nm { font-size: 13.5px; }
.picker .opt .meta {
  font-size: 12px;
  color: var(--fg-3);
  margin-left: auto;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* 整月 0 天出勤：多数是外勤岗，用警示色提醒 HR 别误当旷工 */
.picker .opt .meta.idle { color: var(--warn); }

/* 人员列表（白名单页）：一行一个人，带本月实况 */
.people-list {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.people-list .row {
  display: grid;
  grid-template-columns: 1fr 180px 200px auto;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 6px 16px;
  border-bottom: 1px solid var(--line);
  transition: background .1s var(--ease);
}
.people-list .row:last-child { border-bottom: 0; }
.people-list .row:hover { background: var(--hover); }
.people-list .who { font-weight: 500; }
.people-list .where { color: var(--fg-3); font-size: 12.5px; }
.people-list .stat {
  color: var(--fg-3);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* 整月 0 天出勤：多半是外勤岗连不上 Wi-Fi，不是旷工。用到橙色提醒别误判。 */
.people-list .stat .idle { color: var(--warn); font-weight: 500; }

/* ---------- 卡片容器 ----------
 *
 * 状态页和例外页都用到。原来各写一份，圆角和内边距不一致——
 * 同一类东西在不同页面长得不一样，是最容易被察觉的粗糙。
 */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  /* 父级 .content 是 flex 列，而 panel 的 flex-shrink 默认是 1，
     内容一多就被压扁，再被 overflow:hidden 直接裁掉——例外列表最后几条
     就是这样消失的（容器 410px，内容 463px，没有滚动条也没报错）。
     卡片的高度应当由内容决定，不该被父容器压缩。 */
  flex-shrink: 0;
}
.panel > h3 {
  margin: 0;
  padding: 13px 16px;
  font-size: 13.5px;
  font-weight: 600;
  border-bottom: 1px solid var(--line);
  background: var(--sunken);
}
.panel dl { margin: 0; padding: 4px 16px 16px; }
.panel dt { color: var(--fg-3); font-size: 12px; margin-top: 14px; }
.panel dd { margin: 4px 0 0; font-size: 13.5px; }

.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 1000px) { .cols { grid-template-columns: 1fr; } }

/* 休息日打卡标记：这天本来不用来，来了要能一眼看出是在休息日的班 */
.badge-rest {
  display: inline-block;
  margin-left: 3px;
  padding: 0 4px;
  border-radius: 3px;
  font-size: 10.5px;
  line-height: 15px;
  color: var(--warn);
  background: var(--warn-weak);
  vertical-align: 1px;
}

/* ---------- 分类标签 ----------
 *
 * 白名单、有审批、正常参与，三类人性质不同。混在一张表里会互相干扰：
 * 白名单的人缺卡不罚（看着像漏算），有审批的人缺卡有据（看着像问题）。
 * 分开摆，每张表里的人才是同一类。
 */
.tabs {
  flex: none;
  display: flex;
  gap: 4px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.tabs button {
  height: 34px;
  padding: 0 14px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: none;
  color: var(--fg-3);
  font-size: 13.5px;
  gap: 6px;
}
.tabs button:hover { color: var(--fg); background: var(--hover); }
.tabs button.on {
  color: var(--brand);
  border-bottom-color: var(--brand);
  font-weight: 500;
}
.tabs button .c {
  font-size: 12px;
  color: var(--fg-4);
  font-variant-numeric: tabular-nums;
}
.tabs button.on .c { color: var(--brand); }

/* 整月未到岗的人用警示色：这类人不是「考勤差」，是根本不打卡，
 * 混在缺卡次数里会让人以为大家在集体违纪 */
.summary .v.warn-num { color: var(--warn); }

/* 账号异常标记：已退出企业的人还在报表里被罚钱，是明显的错 */
.badge-gone {
  display: inline-block;
  margin-right: 5px;
  padding: 0 5px;
  border-radius: var(--radius-xs);
  font-size: 10.5px;
  line-height: 16px;
  color: var(--danger);
  background: var(--danger-weak);
  vertical-align: 1px;
}

/* ---------- 拉取任务 ----------
 *
 * 拉一次要 2-5 分钟。给了进度就要真的在动——三步各显示状态，
 * 让人能判断是卡住了还是在跑。
 */
.refresh-box {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.refresh-box .input { width: 150px; }
.refresh-box .hint { font-size: 12.5px; color: var(--fg-4); }

.rf-steps {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  flex-wrap: wrap;
}
.rf-step {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 13px;
  color: var(--fg-3);
}
.rf-step .m { font-size: 12px; color: var(--fg-4); }
.rf-step.running {
  border-color: var(--brand);
  color: var(--brand);
  background: var(--brand-weak);
}
.rf-step.running .m { color: var(--brand); animation: rf-spin 1s linear infinite; }
.rf-step.done { color: var(--fg); }
.rf-step.done .m { color: var(--ok); }
.rf-step.failed { border-color: var(--danger); color: var(--danger); }
.rf-step.failed .m { color: var(--danger); }

@keyframes rf-spin { to { transform: rotate(360deg); } }

.rf-done { margin-top: 10px; font-size: 13px; color: var(--ok); }
.rf-warn {
  margin-top: 10px;
  padding: 8px 12px;
  border-radius: var(--radius);
  background: var(--warn-weak);
  color: var(--warn-fg);
  font-size: 13px;
}
.rf-fail {
  margin-top: 12px;
  padding: 10px 14px;
  border-radius: var(--radius);
  background: var(--danger-weak);
  color: var(--danger);
  font-size: 13px;
}

/* 主按钮：一个页面上只该有一个，所以用实心。
 * 次按钮直接用默认 button 样式，不用额外加类。 */
.btn-primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}
.btn-primary:hover {
  background: var(--brand-hover, var(--brand));
  border-color: var(--brand-hover, var(--brand));
  color: #fff;
  filter: brightness(1.06);
}
.btn-primary:disabled {
  opacity: .55;
  cursor: progress;
  filter: none;
}

/* 表格行内的按钮：比常规按钮矮一档，否则行高被撑开 */
.btn-sm { height: 26px; padding: 0 10px; font-size: 12.5px; }

/* ---------- 规则页与节假日页的语义类 ----------
 *
 * 这些类名在页面上写了，但一直没定义样式——靠默认元素样式和相邻规则
 * 凑合着能看。凑合的结果是版面松、层次平，写的人却以为已经指定过了。
 */
.page-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.page-head .lead {
  margin: 0;
  font-size: 13px;
  color: var(--fg-3);
}
.page-head .actions { display: flex; gap: 8px; }

.field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.field > label,
.field .lab {
  font-size: 12.5px;
  color: var(--fg-3);
}
.field .scope { font-size: 12px; color: var(--fg-4); }

.composer {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  padding: 16px 16px 18px;
  margin-bottom: 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* .panel 的 overflow:hidden 是为表格圆角裁切准备的。
     这个容器里放的是表单，按钮贴着底边，一裁就只剩上半截。 */
  overflow: visible;
}
.composer .row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  width: 100%;
}
.composer .actions {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-top: 2px;
}

.rule-table { width: 100%; border-collapse: collapse; }
.rule-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.rule-list .more { font-size: 12.5px; color: var(--fg-4); }
.rule-list .formula {
  font-size: 12.5px;
  color: var(--fg-3);
}
.rule-list .aka {
  font-size: 12.5px;
  color: var(--fg-4);
  font-style: italic;
}

.shift,
.slot {
  display: inline-block;
  padding: 1px 7px;
  border-radius: var(--radius-xs);
  background: var(--hover);
  font-size: 12px;
  color: var(--fg-2);
  font-variant-numeric: tabular-nums;
}
.shift + .slot,
.slot + .slot { margin-left: 4px; }

.flag {
  display: inline-block;
  padding: 0 6px;
  border-radius: var(--radius-xs);
  font-size: 11.5px;
  line-height: 17px;
  background: var(--warn-weak);
  color: var(--warn-fg);
}

.empty-inline {
  padding: 10px 0;
  font-size: 13px;
  color: var(--fg-4);
}

/* 值班与外出：两种「来了但性质不同」的情况，用不同色区分于正常出勤 */
.duty { color: var(--brand); }
.outing { color: var(--warn); }

/* 明细里的标记：一行一个词说清这天怎么了 */
.mk {
  display: inline-block;
  margin: 0 3px 3px 0;
  padding: 0 6px;
  border-radius: var(--radius-xs);
  font-size: 11.5px;
  line-height: 17px;
  white-space: nowrap;
}
.mk-duty   { background: var(--brand-weak); color: var(--brand); }
.mk-outing { background: var(--warn-weak); color: var(--warn-fg); }
.mk-miss   { background: var(--danger-weak); color: var(--danger); }
.mk-late   { background: var(--danger-weak); color: var(--danger); }
.mk-excuse { background: var(--ok-weak); color: var(--ok); }
.mk-exempt { background: var(--hover); color: var(--fg-3); }

/* 标记贴着星期显示：扫一列就能看出这个月哪些天有情况，
   不用看到最右边才知道。 */
.mk-row { margin-top: 3px; line-height: 1; }
.mk-row .mk { font-size: 11px; padding: 0 4px; line-height: 16px; margin: 0 2px 2px 0; }

/* 加班：和值班一样是「额外」，但性质不同——值班是休息日到岗，加班是延长时间 */
.ot { color: var(--ok); font-variant-numeric: tabular-nums; }
.mk-ot { background: var(--ok-weak); color: var(--ok); }

/* 已选人员的小标签：× 是移除按钮 */
.chip .x {
  margin-left: 6px;
  opacity: .55;
  font-size: 13px;
  line-height: 1;
}
.chip:hover .x { opacity: 1; }

/* 旷工：比缺卡更重，单独一个色，不和缺卡混在一起 */
.absent { color: var(--danger); font-weight: 600; }

/* 表单里的输入框要撑满所在的列。
   不收这一条，input 只有浏览器默认宽度（约 170px），
   放在整行的容器里就只有左边一小截能打字。 */
.field input,
.field select {
  width: 100%;
  box-sizing: border-box;
}

/* 一行里并排几个日期框时，各自按内容撑开，不撑满父级。
   原来 .field input 设了 100%，一行放两个就会互相挤出去——
   实测「结束日期」跑到「怎么算」下拉框底下，两个控件叠在一起。 */
.field > div input[type="date"] {
  width: auto;
  min-width: 0;
  flex: 0 0 auto;
}

/* 日期范围那一格按内容宽度占住，不参与压缩。
   它里面是两个日期框 + 一个箭头，压窄了就会互相挤；
   父级 .row 有 flex-wrap，宽度不够时整格换行，比挤在一起好。 */
#dateField {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* 工具条里的开关：做成一行可点的标签，不是裸 checkbox */
.switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 10px;
  font-size: 13px;
  color: var(--fg-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.switch:hover { border-color: var(--line-focus, var(--accent)); }
.switch input { margin: 0; cursor: pointer; }

/* 报表列多，横向滚动时姓名要钉在左边。
   16 列加起来 1614px，内容区只有 1042px——不钉住的话，
   滚到右边看「扣款」就不知道这一行是谁了。 */
table.data thead th:first-child,
table.data tbody td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
}
table.data thead th:first-child {
  z-index: 3;               /* 表头本身是 sticky top，要压在首列之上 */
  background: var(--sunken);
}
/* 滚动时首列右边加一道阴影，让人看得出左边还有内容被压住了 */
table.data tbody td:first-child {
  box-shadow: 1px 0 0 var(--line);
}

/* 报表这张表（#tbl）的列宽控制。
   16 列按内容撑开是 1614px，内容区只有 1042px——右侧的「扣款」「备注」
   被裁掉，恰恰是最想看的两列。量下来是三列在撑：
   姓名 263px、考勤组 159px、备注 280px，吃掉 43% 的宽度。

   注意都限定在 #tbl 里：白名单页也用 .name 和 td.muted，
   那边每行一个名字，收窄只会让同名的老师分辨不出来。 */
#tbl .name {
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#tbl td.muted {
  max-width: 95px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#tbl td:last-child {
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 三列「看得少但偶尔要看」的列默认收起，需要时勾「完整列」。 */
table.data .extra { display: none; }
body.show-extra table.data .extra { display: table-cell; }

/* 补卡天数：人来了、卡没打上，后来补的。
   用中性色而不是警示色——这不是错误，是正常的管理流程。 */
table.data .cardfix {
  color: var(--fg-2);
  font-variant-numeric: tabular-nums;
}

/* ---------- 确认框 ----------
   替代 window.confirm：原生弹窗顶着「hr.xxx.com says」和英文 Cancel/OK，
   在一套中文企业界面里像外来物，也没法把「删除」这种危险动作标红。
   用原生 <dialog> 而不是自己搭遮罩：自带 ESC 关闭、焦点陷阱和 ::backdrop。 */
dialog.confirm {
  border: none;
  padding: 0;
  border-radius: 14px;
  max-width: 420px;
  width: calc(100vw - 48px);
  background: var(--surface);
  color: var(--fg-1);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .22);
}
dialog.confirm::backdrop {
  background: rgba(17, 20, 24, .42);
  backdrop-filter: blur(1.5px);
}
dialog.confirm .body { padding: 22px 24px 6px; }
dialog.confirm h2 {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 600;
}
dialog.confirm p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--fg-3);
}
dialog.confirm .actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 16px 24px 20px;
}
dialog.confirm .btn,
dialog.confirm .btn-primary { min-width: 76px; }
dialog.confirm .btn-danger {
  background: var(--bad, #d92d20);
  border-color: var(--bad, #d92d20);
  color: #fff;
}
dialog.confirm .btn-danger:hover { filter: brightness(.94); }
