/* ============================================================
   绩效任务台账 weilOA · 样式层
   同一套 HTML，两套外壳：
     html[data-layout="mobile"]   手机端（底部标签栏 + 折行列表）
     html[data-layout="desktop"]  电脑端（左侧导航 + 对齐列表）

   设计基调：冷中性灰 + 深品牌蓝。数据型界面，靠「对齐 / 数字等宽 /
   层级用颜色而不是粗细 / 留白有节奏」来获得秩序感，而不是靠装饰。
   ============================================================ */

/* ---------- 1. 设计令牌 ---------- */

:root {
  /* 品牌蓝 */
  --blue: #185FA5;
  --blue-dark: #114A80;
  --blue-fill: #E9F1FA;
  --blue-line: #C3D9EE;

  /* 语义色：每个都配一个浅底 + 一条描边，标签才有形不散。
     ⚠️ 2026-09-22 审计（F2）压深过：原来的 #CF3B3E / #A96A0B 落在自己的浅底上
        只有 4.22 / 3.98，而标签字号是 11.5~12.5px —— 那是「正文级」字号，
        门槛是 4.5。现在 4.87 / 4.71，都过了。 */
  --red: #C03336;
  --red-fill: #FCECEC;
  --red-line: #F2C8C9;

  --amber: #9A5F08;
  --amber-fill: #FCF2E1;
  --amber-line: #EEDAC0;

  --green: #3C7420;
  --green-fill: #EDF5E5;
  --green-line: #CBE1B6;

  --purple: #6A3FBF;
  --purple-fill: #F1EAFB;
  --purple-line: #D8C8F1;

  /* 中性阶：冷灰。原来的暖米色偏「纸」，数据表格用冷灰更清爽、
     和蓝色也同族，不会互相打架 */
  --text: #1A1F26;
  --text-2: #4B5563;
  /* ⚠️ 2026-09-22 审计（F2）：--muted 原来 #8B94A0，白底只有 3.07 —— 而
     .muted / .sub2 / .refresh-at / .chip-sub 全是 11.5~12.5px 的正文级小字，
     门槛 4.5，一直是不达标的（灰底上更差，2.83）。
     现在 #667085：白底 4.97、灰底 4.59、蓝底 4.37，三处都够。
     （按拍板选的 #6B7280 同族再压一档 —— #6B7280 在灰底只有 4.46，差一点点。） */
  --muted: #667085;
  /* --faint 只留给 input::placeholder 这类「提示、不是内容」的地方（每个输入框都有
     自己的 <label>，占位符只是补一句示例）。任何承载信息的数字/文字一律走 --muted。
     仍压深了一档：#AEB6C0（2.05）→ #9AA3AF（2.55），占位符能看清是哪一类值 */
  --faint: #9AA3AF;

  /* ⚠️ 分割线（非文字元素门槛是 3.0）：这里只做到 1.53 / 1.23，是【刻意的取舍】。
     要真到 3.0 得用 #8B94A0 那一档，等于把每条表格线画成一道深灰实线 ——
     整个列表会变成「格子纸」，得不偿失。所以只适度压深（1.25→1.53，+22%），
     在浅色屏/强光下比原来清楚，同时保住极简的观感。这一条在审计报告里记为已知取舍。 */
  --line: #CBD2DA;
  --line-soft: #E3E8EE;
  --bg: #F4F6F8;
  --bg-soft: #F8F9FB;
  --card: #FFFFFF;
  --hover: #F5F8FB;

  /* 形状 */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;

  --sh-1: 0 1px 2px rgba(16, 24, 40, .05);
  --sh-2: 0 1px 2px rgba(16, 24, 40, .04), 0 12px 28px -18px rgba(16, 24, 40, .18);
  --sh-3: 0 28px 64px -24px rgba(16, 24, 40, .30);

  --sidebar: 232px;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

/* ---------- 2. 基础与排版 ---------- */

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

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei",
    "PingFang SC", "Hiragino Sans GB", sans-serif;
  font-size: 14.5px;
  line-height: 1.55;
  /* 数字全部等宽：表格里的 0 / 100% 能一列对齐，扫描时不跳 */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-text-size-adjust: 100%;
}

html[data-layout="mobile"] body { overscroll-behavior-y: contain; }

.hidden { display: none !important; }
.spacer { flex: 1; }
.muted { color: var(--muted); font-size: 13px; }

h1 { font-size: 18px; font-weight: 650; margin: 0 0 3px; letter-spacing: -.01em; }
h2 { font-size: 14.5px; font-weight: 650; margin: 0 0 12px; letter-spacing: -.005em; }
h3 { font-size: 16.5px; font-weight: 650; margin: 0 0 14px; letter-spacing: -.01em; }
.sub { color: var(--muted); font-size: 13px; margin: 0; line-height: 1.5; }

/* 长段落限制每行字数：1440 宽下满行 150+ 字，眼睛会跳行 */
.wrap p, .card > p, .boardctl-tip { max-width: 92ch; }

::selection { background: #CFE2F5; }

/* ---------- 3. 通用组件 ---------- */

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 12px;
}

.field { margin-bottom: 12px; }
.field label { display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 6px; }
.field label .req { color: var(--red); }

input[type=text], input[type=password], input[type=date], input[type=month],
input[type=number], select, textarea {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14.5px;
  font-family: inherit;
  background: #fff;
  color: var(--text);
  min-height: 38px;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
input::placeholder, textarea::placeholder { color: var(--faint); }
input:hover, select:hover, textarea:hover { border-color: #D3D9E0; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(24, 95, 165, .13);
}
textarea { resize: vertical; min-height: 68px; line-height: 1.55; }
input[type=date], input[type=month] { min-height: 38px; }
select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238B94A0' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  padding-right: 32px;
}

.row { display: flex; gap: 10px; }
.row > * { flex: 1; min-width: 0; }

button {
  font-family: inherit;
  font-size: 14.5px;
  border-radius: var(--radius-sm);
  padding: 8px 15px;
  cursor: pointer;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--text);
  min-height: 38px;
  transition: background .14s, border-color .14s, color .14s, box-shadow .14s;
}
button:hover { border-color: #D3D9E0; background: var(--bg-soft); }
button:active { transform: translateY(.5px); }
button:disabled { opacity: .5; cursor: not-allowed; }
button:disabled:hover { background: #fff; border-color: var(--line); }

.btn-primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.btn-primary:hover { background: var(--blue-dark); border-color: var(--blue-dark); }
.btn-danger { background: var(--red); border-color: var(--red); color: #fff; }
.btn-danger:hover { background: #B53438; border-color: #B53438; }

.btn-sm { padding: 5px 11px; font-size: 13px; min-height: 30px; }

/* 「不可自审 / 不可自批」：做成「看得出这里本该有个按钮、但它是死的」的样子，
   免得用户以为是渲染漏了。全站只用在自审、自批这两处 */
.btn-off {
  display: inline-flex; align-items: center;
  padding: 5px 10px; min-height: 30px;
  font-size: 12.5px; white-space: nowrap;
  border-radius: var(--radius-sm);
  color: var(--muted); background: var(--bg-soft);
  border: 1px dashed var(--line);
  cursor: not-allowed; user-select: none;
}

.btn-link {
  border: none; background: none; color: var(--blue);
  padding: 3px 5px; font-size: 13px; min-height: 26px;
  border-radius: var(--radius-sm);
}
.btn-link:hover { background: var(--blue-fill); text-decoration: none; }

/* 「终止任务」是破坏性偏动作，但又不该跟 btn-danger 同级加粗 —— 用红色文字预警即可 */
.btn-link.warn { color: var(--red); }
.btn-link.warn:hover { background: var(--red-fill); color: var(--red); }

.btns { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }

/* 详情/标记完成弹窗底部操作栏：内容长时吸在弹窗下沿，滚到底之前不跑掉。
   ⚠️ 为什么不给 .btns 直接加 sticky：.btns 是全项目共用类（app.js 里 25 处调用），
      多数弹窗只有几行高，粘住纯属多余；给专用类才不会连带改掉那 24 处。
   ⚠️ 为什么是 sticky 不是 fixed：滚动发生在 .modal 自己身上（overflow:auto），
      fixed 会以视口定位 → 底栏横跨整屏、和弹窗对不齐（见 方案-详情底部悬浮操作栏.md §一）。
   被需求 1（详情 @app.js:2400）与需求 3（标记完成 @app.js:4010）两处共用。 */
.btns-bar {
  position: sticky;
  bottom: 0;
  background: var(--card);       /* 挡住底下滚过去的文字：与既存吸顶元素用同一变量，别写死 #fff */
  border-top: 1px solid var(--line-soft);
  padding: 12px 0 2px;
  margin-top: 14px;              /* 与 .btns 原本的 margin-top 一致，避免高度跳变 */
  z-index: 1;                    /* 盖过 .divider 等静态元素 */
}
/* 手机端：抽屉本身有 padding-bottom = 24px + 安全区，底栏要把这段抵消掉，
   否则吸住时按钮下方会露出一条 24px 的空白（像内容没滚完）。 */
[data-layout="mobile"] .btns-bar {
  padding-bottom: calc(2px + env(safe-area-inset-bottom));
  margin-bottom: calc(-24px - env(safe-area-inset-bottom));
}

/* 标签：加一条同色描边。纯色底的胶囊在浅背景上边界发虚，描边后干净很多 */
.tag {
  display: inline-block;
  font-size: 12px;
  line-height: 18px;
  padding: 0 8px;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid transparent;
  font-weight: 500;
}
.tag-late { background: var(--red-fill); color: var(--red); border-color: var(--red-line); }
.tag-soon { background: var(--amber-fill); color: var(--amber); border-color: var(--amber-line); }
.tag-ok { background: var(--blue-fill); color: var(--blue); border-color: var(--blue-line); }
.tag-done { background: var(--green-fill); color: var(--green); border-color: var(--green-line); }
.tag-gray { background: #F2F4F7; color: var(--muted); border-color: #E4E8ED; }
.tag-self { background: var(--purple-fill); color: var(--purple); border-color: var(--purple-line); }
/* 待确认（审核追问挂起）：既不是待审也不是通过，用紫色区别于「待审核」的蓝 */
.tag-ask { background: var(--purple-fill); color: var(--purple); border-color: var(--purple-line); }

/* 追问往返留痕（askLogsHtml）：问句 / 答句给两种底色，一眼分清谁说的 */
.asklog { margin-bottom: 8px; }
.asklog .q { background: var(--amber-fill); color: var(--ink); border-left: 3px solid var(--amber-line);
  padding: 6px 8px; border-radius: 4px; margin: 4px 0; white-space: pre-wrap; word-break: break-word; }
.asklog .a { background: var(--blue-fill); color: var(--ink); border-left: 3px solid var(--blue-line);
  padding: 6px 8px; border-radius: 4px; margin: 4px 0; white-space: pre-wrap; word-break: break-word; }
.asklog .muted { margin: 2px 0; }

/* 员工自治补充的验收标准（方案 A）：详情/提交/审核里都用这块展示来源，与派单标准视觉上明显分开 */
.selfcrit { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.selfcrit-item {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--line); border-radius: 8px;
  padding: 6px 10px; font-size: 13.5px;
}
.selfcrit-item .btn-link { margin-left: auto; padding: 0; }
.selfcrit-add { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 4px; }
.selfcrit-add input[type="text"] {
  flex: 1 1 240px; min-width: 200px;
  border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; font-size: 13.5px;
  background: var(--card); color: var(--text);
}
.selfcrit-add input[type="text"]:focus { outline: none; border-color: var(--blue); }
.selfcrit-add .muted { flex-basis: 100%; }

.kv { font-size: 13.5px; margin-top: 8px; word-break: break-word; line-height: 1.6; }
.kv .k { color: var(--muted); }
.kv a { color: var(--blue); text-decoration: none; }
.kv a:hover { text-decoration: underline; }
.kv code {
  font-family: var(--mono); font-size: 12.5px;
  background: var(--bg-soft); border: 1px solid var(--line-soft);
  border-radius: 5px; padding: 1px 5px;
}
.divider { height: 1px; background: var(--line-soft); margin: 14px 0; }

.empty {
  color: var(--muted); text-align: center; padding: 40px 16px; font-size: 13.5px;
  line-height: 1.7;
}
.empty::before {
  content: ""; display: block; width: 34px; height: 34px; margin: 0 auto 12px;
  border: 1.5px dashed var(--line); border-radius: 50%;
}

.warnbox {
  background: var(--amber-fill); color: var(--amber);
  border: 1px solid var(--amber-line);
  border-radius: var(--radius-sm); padding: 10px 12px; font-size: 13px;
  line-height: 1.65; margin-bottom: 12px;
}
/* 派单页的「复制已有任务」条。刻意做得比 warnbox 淡：
   它是省事的入口，不是要读的警示 —— 抢了警告的注意力就本末倒置了 */
.copybar {
  background: var(--bg-soft); border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm); padding: 11px 12px; margin-bottom: 14px;
}
.copybar-row { display: flex; align-items: center; gap: 8px; }
.copybar-row label { flex: none; font-size: 13px; font-weight: 600; color: var(--text-2); }
/* 组合框：输入框 + 右侧箭头 + 展开的候选层，外面看是【一个】框。
   它取代了原来的「小搜索框 + 大下拉」两个控件 —— 两个框并排，人不知道该往哪个里打字。
   搜索要占满整行，所以这里是 flex: 1（老的那个固定 190px 的搜索框已经删掉） */
.copybar-row .combo { position: relative; flex: 1; min-width: 0; }
.combo-input { width: 100%; padding-right: 30px; }
/* 箭头只是「这里点得开」的提示；点击由它自己接（data-act="combotoggle"） */
.combo-caret {
  position: absolute; right: 9px; top: 50%; margin-top: -9px;
  line-height: 18px; font-size: 12px; color: var(--muted);
  cursor: pointer; user-select: none;
}
.combo-caret:hover { color: var(--text-2); }
/* 候选层：绝对定位贴在框下面，不把下面的表单往下顶 */
.combo-pop {
  position: absolute; left: 0; right: 0; top: calc(100% + 3px); z-index: 40;
  max-height: 252px; overflow: auto;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-sm); box-shadow: var(--sh-2);
}
.combo-pop[hidden] { display: none; }
/* 单号在最前，长标题用省略号 —— 宁可截尾也不要换行把行高撑乱 */
.combo-opt {
  padding: 8px 10px; font-size: 13px; line-height: 1.45;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.combo-opt + .combo-opt { border-top: 1px solid var(--line-soft); }
.combo-opt:hover { background: var(--hover); }
/* 高亮的这条 = 现在选中的那条，「带出内容」认的就是它 */
.combo-opt.on { background: var(--blue-fill); color: var(--blue-dark); font-weight: 600; }
.combo-none { padding: 10px; font-size: 13px; line-height: 1.6; color: var(--muted); }
.copybar-row button { flex: none; }
.copybar #f-copyhint { margin: 8px 0 0; line-height: 1.65; }
.copybar #f-copyhint b { color: var(--text); }
/* 手机上 select 和按钮挤在一行会只剩几十像素，改成竖排三行 */
[data-layout="mobile"] .copybar-row { flex-direction: column; align-items: stretch; gap: 6px; }
/* ⚠️ 手机端必须把 flex 重置掉：column 布局里 flex-basis 作用在【高度】上，
   不重置的话这个框会被撑成一根高柱子（宽度靠上面的 stretch 自然占满） */
[data-layout="mobile"] .copybar-row input[type="text"] { flex: none; }
[data-layout="mobile"] .copybar-row .combo { flex: none; }
[data-layout="mobile"] .copybar-row button { width: 100%; }
.errbox {
  background: var(--red-fill); color: var(--red);
  border: 1px solid var(--red-line);
  border-radius: var(--radius-sm); padding: 10px 12px; font-size: 13px;
  line-height: 1.65; margin-bottom: 12px;
}

/* 变更留痕与跨月提示 */
.changebox {
  margin-top: 10px; padding: 9px 12px;
  border-radius: var(--radius-sm); font-size: 13px; line-height: 1.6;
  background: var(--bg-soft); border: 1px solid var(--line-soft);
}
.changebox.pending {
  background: var(--amber-fill); border-color: var(--amber-line);
}
.changebox.pending b { color: var(--amber); }
.chgline { line-height: 1.45; }
.chgcut {
  color: var(--muted); font-size: 12.5px; line-height: 1.5; margin-top: 1px;
  word-break: break-word;
}
/* 三个类就是「生效没生效」的三态，只能按下面这张表用（2026-09-21 定案）：
     .chgfrom  灰 + 划掉 = 【已作废】（被批准替换掉了），或【明确没通过】的提议值
     .chgto    绿       = 【已生效】—— 只有已批准的变更才配这个绿
     .chgpend  琥珀     = 【还没被决定】的提议值（待审批）—— 不绿也不划
     .chgcur   正常字   = 【现值】，既没作废也没被替换
   ⚠️ 绿 = 已生效，没有例外。待审批的提议值曾经也是绿的，那和「已批准的变更」长得一样，
      审的人扫一眼会以为已经改完了 —— 而它随时可能被驳回。
   ⚠️ 划掉 = 已作废，也不能乱用：把「现值」划掉，看的人会以为现值不作数了。 */
.chgfrom { text-decoration: line-through; opacity: .6; }
.chgto { color: var(--green); }
.chgpend { color: var(--amber); }
.chgcur { color: inherit; }

/* ---------- 逐条对照验收标准写交付内容（2026-09-21） ----------
   提交弹窗里「标准 + 一个输入框」成对出现；审核弹窗里「标准 + 执行人填的内容」成对出现。
   两处共用同一套类，是为了让两边看起来就是同一张表 —— 交的人知道自己写的东西
   会原样出现在审的人那一屏（写的时候就会认真一点）。 */
.evrow { margin-bottom: 12px; }
.evstd {
  font-size: 13.5px; line-height: 1.55; color: var(--text);
  margin-bottom: 5px; word-break: break-word;
}
.evrow input { width: 100%; }
.rvev {
  margin-top: 5px; padding: 7px 9px; font-size: 13px; line-height: 1.55;
  background: var(--bg-soft); border: 0.5px solid var(--line-soft);
  border-radius: 6px; word-break: break-word;
}
.rvev .k { color: var(--muted); }
/* 这条没有逐条内容（老单提交的）—— 说明白，别让人以为是界面漏渲染了 */
.rvev-miss { color: var(--muted); }

/* ---------- 只读「任务详情」弹窗（?v=31）----------
   同一份 .rvev 对照块在审核弹窗里是 <label> + 勾选框，在详情里是纯只读 —— 
   这里的 .evrow-ro 只是「只读那一版」的外层间距，别把两边的样式混在一起改 */
.evrow-ro { padding: 8px 0; font-size: 14.5px; }
/* 审核时逐条勾没勾。只读详情里要有：光看一个总评级，看不出是哪几条算过了 */
.rvmark {
  display: inline-block; width: 16px; margin-right: 3px;
  color: var(--muted); font-weight: 650;
}
.rvmark.on { color: var(--green); }
/* 详情里的交付物是【全文】，不像列表那格夹 3 行 —— 详情存在的意义就是「看全」 */
.delivfull {
  font-size: 14.5px; line-height: 1.6; margin-bottom: 10px;
  white-space: pre-wrap; word-break: break-word;
}
/* 提交之后这条标准被改过：把「当时答应的那一条」一并给审核的人看，
   否则等于拿新标准去评旧交付 */
.rvev-stale { margin-top: 4px; color: var(--amber); font-size: 12.5px; line-height: 1.5; }

/* ---------- 登录页的图形验证码 ---------- */
.caprow { display: flex; align-items: center; gap: 10px; }
.caprow input { flex: 1; min-width: 0; letter-spacing: .12em; }
/* 图本身就是一张 SVG（点是阵图，不是文字）。点它 = 换一张 */
.capbox {
  flex: none; width: 164px; height: 54px; padding: 0;
  border: 1px solid var(--line); border-radius: 8px; background: #F6F8FB;
  cursor: pointer; overflow: hidden; line-height: 0;
  display: flex; align-items: center; justify-content: center;
}
.capbox:hover { border-color: var(--blue); }
.capbox svg { width: 100%; height: 100%; display: block; }
.caphint { margin: 5px 0 0; font-size: 12.5px; line-height: 1.5; }
/* 手机上输入框和验证码图并排会太挤，改成上下两行 */
[data-layout="mobile"] .caprow { flex-direction: column; align-items: stretch; gap: 8px; }
[data-layout="mobile"] .capbox { width: 100%; height: 52px; }
.carrybox {
  margin-top: 10px; padding: 10px 12px;
  border-radius: var(--radius-sm); font-size: 13px; line-height: 1.65;
  background: var(--blue-fill); border: 1px solid var(--blue-line); color: var(--text-2);
}
.carrybox b { color: var(--text); }

/* 任务卡（弹窗/派单页仍在用） */
.task-head { display: flex; align-items: flex-start; gap: 8px; }
.task-head .t { font-weight: 600; flex: 1; }
.owner { color: var(--muted); font-size: 13px; }

/* 验收标准清单：方框 + 文案。打过勾的变绿 */
.accept { margin: 6px 0 0; padding-left: 0; list-style: none; font-size: 13.5px; }
.accept li { padding: 2px 0 2px 18px; position: relative; }
.accept li::before {
  content: ""; position: absolute; left: 2px; top: 8px;
  width: 9px; height: 9px;
  border: 1.5px solid #C6CDD5; border-radius: 3px;
}
.accept li.yes::before { border-color: var(--green); background: var(--green); }

/* 弹窗 / 提示 */
.mask {
  position: fixed; inset: 0; background: rgba(16, 24, 40, .38);
  backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center;
  padding: 16px; z-index: 50;
}
.modal {
  background: #fff; border-radius: var(--radius-lg); padding: 20px;
  width: 100%; max-width: 480px;
  max-height: 88vh; overflow: auto;
  box-shadow: var(--sh-3);
  animation: pop .18s cubic-bezier(.2, .8, .3, 1);
}
@keyframes pop { from { opacity: 0; transform: translateY(10px) scale(.985); } }

.toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
  background: #1A1F26; color: #fff; padding: 10px 18px;
  border-radius: 999px; font-size: 13.5px; z-index: 99; max-width: 90vw;
  box-shadow: 0 10px 30px -8px rgba(0, 0, 0, .4);
  animation: pop .18s cubic-bezier(.2, .8, .3, 1);
}

/* 表格（电脑端看板） */
table {
  width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px;
}
th, td {
  padding: 9px 10px; text-align: right;
  border-bottom: 1px solid var(--line-soft);
  white-space: nowrap;
}
th:first-child, td:first-child { text-align: left; }
thead th {
  color: var(--muted); font-weight: 500; font-size: 12.5px;
  position: sticky; top: 0; background: var(--card); z-index: 2;
  border-bottom: 1px solid var(--line);
  padding-top: 8px; padding-bottom: 8px;
}
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------- 看板大表（18 列）----------
   18 列摊在 1100px 里，默认渲染出来是一片同色的数字墙：
   半数格子是 0，几个关键结论混在中间。这里做三件事 ——
     ① 零值压暗、异常值上色（红色＝超期，琥珀＝延期/返工/补票）
     ② 组与组之间加竖线，把 18 列切成 6 段可读的块
     ③ 姓名列吸附在左侧，横向滚动时始终知道在看谁 */
table.board { font-size: 13px; }
.board td, .board th { border-bottom: 1px solid var(--line-soft); }
.board thead th { background: var(--bg-soft); }
.board th.grp { border-left: 1px solid var(--line); }
.board td.grp { border-left: 1px solid var(--line-soft); }

/* 每行一个不透明底色变量：隔行浅底 / 悬停 / 结论色块都靠它，
   吸附加粗的姓名列才能跟着一起变色 */
.board tbody tr { --row-bg: var(--card); }
.board tbody tr:nth-child(even) { --row-bg: #FBFCFD; }
.board tbody tr:hover { --row-bg: var(--hover); }
.board tbody tr.bad { --row-bg: var(--red-fill); }
.board tbody tr.good { --row-bg: var(--green-fill); }
.board tbody td { background: var(--row-bg); }

.board td.c-name, .board th.c-name {
  position: sticky; left: 0; z-index: 1;
  box-shadow: 1px 0 0 var(--line-soft);
}
.board thead th.c-name { z-index: 3; }

/* 「0」和「—」仍然是信息（它告诉你「这档没人」），不是装饰 —— 2026-09-22 审计后
   从 --faint 改成 --muted：--faint 只留给占位符那种「提示性」文字 */
.board .z { color: var(--muted); }
.board .na { color: var(--muted); }
.board .od:not(.z) { color: var(--red); font-weight: 650; }
.board .am:not(.z) { color: var(--amber); font-weight: 650; }

/* 结论区（按期率 / 一次合格率 / 结论）：数字加大加粗，和左边 14 个计数拉开层级 */
.board td.key { font-weight: 650; font-size: 13.5px; }
.board td.key.na { font-weight: 400; font-size: 13px; }
.board td.key .tag { font-weight: 500; font-size: 12px; }
.board th.key { color: var(--text-2); font-weight: 600; }

/* 登录页 */
.loginform .field { margin-bottom: 14px; }
/* 手机上字号低于 16px 会被 iOS 自动放大整页，登录页尤其明显，这里顶到 16 */
.loginform input { font-size: 16px; }

/* 筛选药丸 */
.pill-row {
  display: flex; gap: 6px; margin-bottom: 4px;
  overflow-x: auto; padding-bottom: 4px;
}
.pill-row button {
  padding: 5px 13px; font-size: 13px; border-radius: 999px;
  white-space: nowrap; min-height: 32px; color: var(--text-2);
  border-color: var(--line);
}
.pill-row button:hover { background: var(--bg-soft); }
.pill-row button.on {
  background: var(--blue); color: #fff; border-color: var(--blue);
  font-weight: 500;
}
.pill-row button.on:hover { background: var(--blue-dark); }

.formgrid { display: block; }
.formgrid .field { margin-bottom: 12px; }

/* 看板控制区 */
.bctl-month { margin-bottom: 0; }
.bctl-btns { margin-bottom: 0; }
.inline-btns { display: flex; gap: 8px; }
.inline-btns button { flex: 1; }
.boardctl-tip {
  margin: 14px 0 0;
  padding: 11px 13px;
  background: var(--bg-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  font-size: 12.5px; line-height: 1.7; color: var(--text-2);
}
.boardctl-tip b { color: var(--text); }

/* ---------- 全员台账：筛选条 ---------- */

.ctlcard { padding: 14px 16px; }
.fbar { display: block; }
.fbar .field:last-child { margin-bottom: 0; }
/* 月份只需要放下「本月」两个字，原来给它 .95fr 会撑出一大片空的 */
[data-layout="desktop"] .fbar {
  display: grid;
  grid-template-columns: minmax(150px, .55fr) 132px minmax(260px, 1.6fr) auto;
  gap: 0 14px;
  align-items: end;
}
[data-layout="desktop"] .fbar .field { margin-bottom: 0; }
.fbar .inline-btns { flex-wrap: wrap; }
.fbar .inline-btns button { flex: 0 1 auto; }
[data-layout="desktop"] .fbar-btn .inline-btns button { flex: 1; white-space: nowrap; }
.fbar select, .fbar input { width: 100%; }
.fbar-month .inline-btns select,
.fbar-month .inline-btns input { flex: 1 1 0; min-width: 0; }

/* 手机端：月份与排序并排，搜索和按钮各占一整行 —— 否则筛选区比数据还高 */
[data-layout="mobile"] .fbar {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
[data-layout="mobile"] .fbar .field { margin-bottom: 0; }
[data-layout="mobile"] .fbar-q,
[data-layout="mobile"] .fbar-btn { grid-column: 1 / -1; }
[data-layout="mobile"] .fbar .inline-btns button { flex: 1; }

/* ⚠️ 2026-09-22 审计（F1）：900~1060px 这一档，筛选条会把【整页】顶出横向滚动
   （实测 900px 时 +51px、899px 时 +52px）。
   原因不是表格（表格有自己的 .scroll-x，容器内滚动是设计），而是这条 .fbar：
   上面那套列宽的最小值是写死的 minmax(150px)/132px/minmax(260px) = 542px，
   再加上「重置 / 导出明细」两个 white-space:nowrap 的按钮（约 129px），
   已经超过「扣掉 232px 侧栏之后」能用的宽度 —— grid 最右边那格只能顶出去。
   做法：只在这一档把三个下限收小（宽屏完全不受影响：那边是 fr 说了算，
   这些数字只在「挤不下」时才生效）。
   ⚠️ 条件写成 max-width 而不是 (min-width:900px and max-width:1060px) ——
   要覆盖的是 899px 这个「桌面外壳 + 手机列表」的夹缝（此时 data-layout 仍是
   desktop，但 min-width:900 的媒体查询不生效，所以必须自己管到）。
   选择器带 [data-layout="desktop"]，手机版那套两列布局不会被误伤。 */
@media (max-width: 1060px) {
  [data-layout="desktop"] .fbar {
    grid-template-columns: minmax(104px, .55fr) 112px minmax(150px, 1.6fr) auto;
    gap: 0 10px;
  }
}

/* ---------- 全员台账：人名条 ---------- */

.chiptip { margin: 12px 0 8px; font-size: 12.5px; line-height: 1.6; }
.chipbar {
  display: flex; gap: 8px; overflow-x: auto;
  padding: 2px 0 6px;
  scrollbar-width: thin;
}
.chip {
  flex: none; display: flex; flex-direction: column; align-items: flex-start;
  justify-content: center; gap: 2px;
  min-height: 52px; padding: 8px 13px;
  border-radius: var(--radius); background: #fff;
  border: 1px solid var(--line);
  text-align: left; line-height: 1.35;
  transition: border-color .14s, background .14s, box-shadow .14s;
}
.chip:hover { border-color: #C9D5E2; background: var(--hover); }
.chip b { font-size: 13.5px; font-weight: 600; }
.chip-sub { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.chip.on {
  border-color: var(--blue); background: var(--blue-fill);
  box-shadow: 0 0 0 2px rgba(24, 95, 165, .1);
}
.chip.on b { color: var(--blue); }
.chip .bad { color: var(--red); font-weight: 600; }

/* 汇总条：每个数一段，数字用深色 + 标签用灰，扫的时候先看到数 */
.allsum {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px; color: var(--muted);
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 2px 0;
}
.allsum b {
  font-size: 14px; color: var(--text); font-weight: 650;
  margin-left: 2px;
}
.allsum b.bad { color: var(--red); }
.allsum .sep { color: #D5DAE1; margin: 0 9px; }
.allsum .st-total b { font-size: 15px; }

/* F11「显示更多」：台账超过 50 条时才出现。做成一张居中的卡片，
   和上面的列表卡视觉上是一组，不抢列表的注意力 */
.morecard {
  margin-top: 10px; padding: 12px;
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.morecard .muted { font-size: 13px; }

.pcard-foot { margin-top: 12px; text-align: right; }
.pcard-name { padding: 0; font-size: 15px; font-weight: 650; color: var(--text); text-align: left; }
.pcard-name:hover { background: none; color: var(--blue); }

/* 看板规则卡：宽屏下两条并排。
   等分 4 列会把「待改进」这类词拆到下一行，2 列让每条独占一行；
   窗口窄了退回单列。 */
.rules-list { display: block; }
[data-layout="desktop"] .rules-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 28px;
}
[data-layout="desktop"] .rules-list .kv { min-width: 0; margin-top: 0; }
@media (max-width: 1200px) {
  [data-layout="desktop"] .rules-list { grid-template-columns: minmax(0, 1fr); }
}

/* 规则条文：左侧一条短竖线，比死板的圆点更贴合数据面板的气质 */
.rules-list .kv {
  position: relative; padding-left: 14px; font-size: 13.5px; line-height: 1.5;
}
.rules-list .kv::before {
  content: ""; position: absolute; left: 0; top: 7px;
  width: 3px; height: 13px; border-radius: 2px; background: var(--line);
}
.rules-list .kv b { color: var(--text); font-weight: 600; }

/* 只在某一端出现的元素 */
[data-layout="mobile"] .hide-mobile { display: none !important; }
[data-layout="desktop"] .hide-desktop { display: none !important; }

/* 界面形态切换 */
.seg {
  display: inline-flex; border: 1px solid var(--line);
  border-radius: var(--radius-sm); overflow: hidden; background: #fff;
}
.seg button {
  border: none; border-radius: 0; background: none;
  padding: 6px 14px; font-size: 13px; color: var(--text-2);
  border-right: 1px solid var(--line); min-height: 34px;
}
.seg button:last-child { border-right: none; }
.seg button:hover { background: var(--bg-soft); }
.seg button.on { background: var(--blue); color: #fff; }
.seg button.on:hover { background: var(--blue-dark); }

/* ============================================================
   4. 电脑端外壳
   ============================================================ */

[data-layout="desktop"] .shell {
  display: flex;
  align-items: stretch;
  min-height: 100vh;
}

[data-layout="desktop"] .sidebar {
  width: var(--sidebar);
  flex: none;
  background: var(--card);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

[data-layout="desktop"] .brand {
  display: flex; align-items: center; gap: 10px;
  padding: 17px 16px 15px;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: 10px;
}
[data-layout="desktop"] .brand-mark {
  width: 28px; height: 28px; flex: none;
  border-radius: 8px; background: linear-gradient(160deg, #2075BE, var(--blue-dark));
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 13.5px; font-weight: 650;
  box-shadow: 0 2px 6px -2px rgba(24, 95, 165, .5);
}
[data-layout="desktop"] .brand-text {
  display: flex; flex-direction: column; min-width: 0;   /* 产品名 + 团队名两行 */
  font-weight: 650; font-size: 14px; letter-spacing: -.01em;
  overflow: hidden;
}
/* 团队名做副标题：产品名固定 weilOA，团队名是「谁的台账」，两者别混 */
[data-layout="desktop"] .brand-org {
  font-weight: 400; font-size: 11.5px; color: var(--muted);
  line-height: 1.35; margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

[data-layout="desktop"] .sidenav {
  flex: 1; padding: 0 10px; display: flex; flex-direction: column; gap: 1px;
  overflow-y: auto;
}
[data-layout="desktop"] .sidenav-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left;
  border: none; background: none;
  padding: 9px 11px; border-radius: 8px;
  font-size: 13.5px; color: var(--text-2);
  min-height: 38px;
  position: relative;
  transition: background .13s, color .13s;
}
[data-layout="desktop"] .sidenav-item:hover { background: var(--bg-soft); }
[data-layout="desktop"] .sidenav-item.on {
  background: var(--blue-fill); color: var(--blue); font-weight: 600;
}
[data-layout="desktop"] .sidenav-item .ico { width: 18px; height: 18px; flex: none; }
[data-layout="desktop"] .sidenav-item .badge {
  margin-left: auto; min-width: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--red); color: #fff;
  font-size: 11px; line-height: 18px; text-align: center; font-weight: 500;
}

[data-layout="desktop"] .side-foot {
  border-top: 1px solid var(--line-soft);
  padding: 13px 16px 16px;
  font-size: 13px;
}
[data-layout="desktop"] .side-foot .me { font-weight: 600; }
[data-layout="desktop"] .side-foot .me-role {
  color: var(--muted); font-weight: 400; font-size: 12px; margin-left: 6px;
}
[data-layout="desktop"] .side-btns { display: flex; gap: 12px; margin-top: 6px; }
[data-layout="desktop"] .side-btns .btn-link { padding: 0; min-height: auto; }
[data-layout="desktop"] .side-btns .btn-link:hover { background: none; text-decoration: underline; }

[data-layout="desktop"] .main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
[data-layout="desktop"] .pagehead {
  padding: 19px 28px 15px;
  border-bottom: 1px solid var(--line);
  background: rgba(244, 246, 248, .88);
  backdrop-filter: blur(8px);
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
[data-layout="desktop"] .pagehead .ph-text { min-width: 0; }
[data-layout="desktop"] .pagehead h1 { font-size: 19px; margin-bottom: 2px; }

/* 顶部的「刷新」：手动拉一次最新数据，不用去按浏览器的 F5 */
.ph-actions { display: flex; align-items: center; gap: 10px; flex: none; }
.refresh-at { color: var(--muted); font-size: 12.5px; white-space: nowrap; }
.ico-btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); background: var(--card); color: var(--text-2);
  border-radius: var(--radius-sm); padding: 6px 11px;
  font-size: 13px; font-family: inherit; line-height: 1; cursor: pointer;
  min-height: 32px;
  transition: border-color .14s, color .14s, background .14s;
}
.ico-btn:hover { border-color: var(--blue-line); color: var(--blue); background: var(--blue-fill); }
.ico-btn .ico { width: 15px; height: 15px; }
.ico-btn .ico-label { white-space: nowrap; }
.ico-btn:disabled { opacity: .6; cursor: default; }
/* 转一圈表示正在拉数据 —— 只在图标上转，文字不动 */
.ico-btn.spin .ico { animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* 内容区撑满可用宽度：窗口越宽，右侧越不该留空 */
[data-layout="desktop"] .wrap { padding: 20px 28px 56px; margin: 0; }

/* 设置页整页都是说明性文字，铺满超宽屏会一行一百多字、读起来跳行 ——
   收成阅读栏宽。数据型的台账 / 看板不受影响，仍然铺满。 */
[data-layout="desktop"] #view.view-settings { max-width: 1000px; }

/* 宽屏下表格加大内边距，18 列摊开后数字不至于挤成一团；
   窗口变窄则逐级收紧 —— 表头是 nowrap 的，内边距不改小会撑出横向滚动条。 */
[data-layout="desktop"] th,
[data-layout="desktop"] td { padding: 9px 12px; }
@media (max-width: 1500px) {
  [data-layout="desktop"] th,
  [data-layout="desktop"] td { padding: 9px 8px; }
}
@media (max-width: 1100px) {
  [data-layout="desktop"] table { font-size: 12px; }
  [data-layout="desktop"] th,
  [data-layout="desktop"] td { padding: 8px 6px; }
}
/* 看板那张 18 列的表，在 1280 这类笔记本宽度上只差几十像素就要横向拖动。
   不给它单独收一档，就得让同事左右拉着看 —— 能不滚就不滚。
   （表头是 nowrap 的，能省的地方只有内边距和字号。） */
@media (min-width: 1101px) and (max-width: 1400px) {
  [data-layout="desktop"] table.board { font-size: 12.5px; }
  [data-layout="desktop"] table.board th,
  [data-layout="desktop"] table.board td { padding: 8px 6px; }
  [data-layout="desktop"] .board td.key { font-size: 13px; }
}

[data-layout="desktop"] .formgrid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0 14px;
}
[data-layout="desktop"] .fg-half { grid-column: span 3; }
[data-layout="desktop"] .fg-third { grid-column: span 2; }
[data-layout="desktop"] .fg-full { grid-column: 1 / -1; }

[data-layout="desktop"] .row.boardctl { align-items: flex-end; }
[data-layout="desktop"] .bctl-month { flex: 0 0 190px; }
[data-layout="desktop"] .bctl-btns { flex: 1; }
[data-layout="desktop"] .inline-btns button { flex: 0 0 auto; }
[data-layout="desktop"] .inline-btns button { min-height: 38px; }

[data-layout="desktop"] .card { box-shadow: var(--sh-1); }
[data-layout="desktop"] .modal { max-width: 520px; }
[data-layout="desktop"] .toast { bottom: 34px; }

/* ============================================================
   5. 手机端外壳
   ============================================================ */

[data-layout="mobile"] .topbar {
  position: sticky; top: 0; z-index: 20;
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  padding: 8px 14px;
  display: flex; align-items: center; gap: 4px;
  padding-top: calc(8px + env(safe-area-inset-top));
}
[data-layout="mobile"] .topbar .org {
  font-weight: 650; font-size: 15px; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
[data-layout="mobile"] .topbar .who {
  color: var(--muted); font-size: 12.5px;
  max-width: 76px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
[data-layout="mobile"] .topbar .ico-btn {
  border: none; background: none; color: var(--blue);
  padding: 4px; display: flex; align-items: center; justify-content: center;
  width: 40px; min-height: 44px;
}
[data-layout="mobile"] .topbar .ico-btn:hover { background: var(--blue-fill); }
[data-layout="mobile"] .topbar .ico-btn .ico { width: 20px; height: 20px; }
/* 顶栏的「退出」是纯文字链接，默认高度只有 32px —— 手机上点不准，撑到 36px */
[data-layout="mobile"] .topbar .btn-link {
  min-height: 36px;
  display: inline-flex; align-items: center;
  padding: 0 6px;
}

[data-layout="mobile"] .wrap {
  max-width: none;
  padding: 12px 12px calc(92px + env(safe-area-inset-bottom));
}

[data-layout="mobile"] .tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  display: flex;
  background: rgba(255, 255, 255, .97);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
[data-layout="mobile"] .tab {
  flex: 1; border: none; background: none;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 2px 7px;
  color: var(--muted); font-size: 11px;
  border-radius: 0;
  min-height: 56px;
}
[data-layout="mobile"] .tab:hover { background: none; }
[data-layout="mobile"] .tab .tab-ico { position: relative; display: flex; }
[data-layout="mobile"] .tab .ico { width: 22px; height: 22px; }
[data-layout="mobile"] .tab.on { color: var(--blue); }
[data-layout="mobile"] .tab.on .tab-label { font-weight: 650; }
[data-layout="mobile"] .tab .badge {
  position: absolute; top: -4px; right: -8px;
  min-width: 16px; padding: 0 4px; border-radius: 8px;
  background: var(--red); color: #fff;
  font-size: 10px; line-height: 16px; text-align: center;
}

/* 手机端：一切单列、加大触控面积 */
[data-layout="mobile"] .row { flex-direction: column; gap: 0; }
[data-layout="mobile"] .row.row-inline { flex-direction: row; gap: 8px; }

[data-layout="mobile"] input[type=text],
[data-layout="mobile"] input[type=password],
[data-layout="mobile"] input[type=date],
[data-layout="mobile"] input[type=month],
[data-layout="mobile"] input[type=number],
[data-layout="mobile"] select,
[data-layout="mobile"] textarea {
  font-size: 16px;          /* iOS 聚焦时不放大页面 */
  padding: 10px 12px;
  min-height: 46px;
}
[data-layout="mobile"] button { min-height: 44px; }
[data-layout="mobile"] .btn-sm { min-height: 38px; }
[data-layout="mobile"] .btn-off { min-height: 34px; }
[data-layout="mobile"] .btn-link { min-height: 36px; }

[data-layout="mobile"] .btns { gap: 8px; }
[data-layout="mobile"] .btns > button { flex: 1; }

[data-layout="mobile"] .card { padding: 14px; border-radius: var(--radius); }
[data-layout="mobile"] .kv { font-size: 14px; }
[data-layout="mobile"] .accept { font-size: 14px; }
[data-layout="mobile"] h1 { font-size: 17px; }
[data-layout="mobile"] h2 { font-size: 14px; }

[data-layout="mobile"] .loginform input { min-height: 46px; }

[data-layout="mobile"] .mask { padding: 0; align-items: flex-end; }
[data-layout="mobile"] .modal {
  max-width: none;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  max-height: 92vh;
  padding: 20px 16px calc(24px + env(safe-area-inset-bottom));
  animation: sheet .22s cubic-bezier(.2, .8, .3, 1);
}
@keyframes sheet { from { transform: translateY(30px); opacity: .6; } }
[data-layout="mobile"] .modal::before {
  content: ""; display: block;
  width: 38px; height: 4px; border-radius: 2px;
  background: #D8DDE4; margin: -8px auto 16px;
}

[data-layout="mobile"] .toast { bottom: calc(88px + env(safe-area-inset-bottom)); }

/* ============================================================
   6. 看板：手机端人物卡
   ============================================================ */

.pcard { padding: 15px; }
.pcard.bad { border-color: var(--red-line); background: #FFFCFC; }
.pcard.good { border-color: var(--green-line); background: #FCFEF9; }

.pcard-head { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
.pcard-name { font-weight: 650; flex: 1; }

/* 两个比率是这张卡的主角：给它们一个比周围略深的底，视线先落在这里 */
.rate-row { display: flex; gap: 10px; margin-top: 13px; }
.rate {
  flex: 1; background: var(--bg-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm); padding: 9px 12px;
  display: flex; flex-direction: column; gap: 1px;
}
.rate b {
  font-size: 21px; font-weight: 650; line-height: 1.15; letter-spacing: -.02em;
}
.rate span { color: var(--muted); font-size: 11.5px; }

/* 14 个明细指标：3 列，靠底色交替分组，零值自动变浅 */
.metrics {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 1px; margin-top: 13px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.metric { text-align: center; padding: 8px 4px; background: var(--card); }
.metric b {
  display: block; font-size: 15px; font-weight: 650; line-height: 1.3;
  letter-spacing: -.01em;
}
/* 同上：指标里的「0」是信息，走 --muted 不走 --faint */
.metric b.z { color: var(--muted); font-weight: 500; }
.metric span { color: var(--muted); font-size: 11px; }

/* ============================================================
   7. 任务横向列表（核心版式）
   ------------------------------------------------------------
   一条任务占一行。宽屏列与列对齐、内容多的单元格自己撑高；
   窄屏同一行折行、每个单元格自带标签 —— 仍比卡片省一半以上高度。

   这一次的调整重点：把「宽了也没用的列」让给「写得长的列」，
   并给每个单元格的内容设上限 —— 行高由最长的格子决定，
   不设上限的话，4 条验收标准就能把一行撑到 200px。
   ============================================================ */

.card.listcard { padding: 0; overflow: hidden; }
.tlist { font-size: 13.5px; }
/* 操作记录的「详情」列：像「修改配置」那种是整段 JSON，原样铺开能把这行撑到几百像素。
   列表里只给两行，全文挂在 title 上（悬停可看）—— 与「验收标准每条只占一行」同一个道理。 */
.tc-audit-det { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.trow {
  display: flex; flex-wrap: wrap;
  gap: 3px 16px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-soft);
  align-items: flex-start;
}
.trow:last-child { border-bottom: none; }
.trow.th { display: none; }

.tc { min-width: 0; word-break: break-word; line-height: 1.5; }
.tc.nw { white-space: nowrap; }
.tname { font-weight: 600; }
/* 任务名最多两行：标题再长也不该把整行撑开 */
.tc-t .tname {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* 交付物：最多三行，超出省略；完整内容鼠标悬停可看，或打开「修改」 */
.deliv {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.sub2 { display: block; color: var(--muted); font-size: 12.5px; line-height: 1.5; margin-top: 2px; }

/* 验收标准：每条压成一行。8 条标准铺开能撑到 170px，这是行高失控的主因；
   每条一行 + 悬停看全文，行高立刻可控 */
.tc .accept { margin: 0; font-size: 13px; }
.tc .accept li {
  padding: 2px 0 2px 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tc .accept li::before { top: 8px; width: 8px; height: 8px; border-radius: 2px; }
.tc .changebox { margin-top: 0; padding: 7px 10px; }
.lk { word-break: break-all; }
.lk a { color: var(--blue); text-decoration: none; }
.lk a:hover { text-decoration: underline; }
.rvline { display: flex; gap: 8px; flex-wrap: wrap; align-items: baseline; }
.rvline b { font-weight: 650; }
/* 审核意见只给一行：这一格是「提交与审核」的摘要，不是正文。
   必须写 display:-webkit-box，否则 -webkit-line-clamp 完全不生效 ——
   少那一行的话，一条 20 字的意见就能把这格从 20px 撑到 147px */
.rvcomment {
  display: -webkit-box;
  -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  overflow: hidden; flex: 1 1 100%; min-width: 0;
}

/* 操作列：按钮两两并排。
   原来列只有 92px，4 个按钮只能一竖溜排下来 —— 光按钮就 110px 高，
   成了整行的地板。给到 136px 后两个一行，降到 ~53px。 */
.tc-act {
  display: flex; flex-wrap: wrap; gap: 3px 5px;
  align-items: center; align-content: flex-start;
}
.tc-act button { flex: 0 0 auto; }
.tc-act .btn-sm { padding: 3px 7px; font-size: 12px; min-height: 25px; }
.tc-act .btn-link { padding: 3px 5px; font-size: 12px; min-height: 25px; }

/* 单号（MM-NNN）：等宽字体 + 低饱和品牌蓝。它是用来「引用」的编号，
   要一眼认得出来，但不能抢过任务名的注意力 —— 在「层级用颜色不用粗细」的
   规矩下，用色相区分而不是加粗 */
.tno {
  font-family: var(--mono); font-size: 12px; letter-spacing: -.3px;
  color: var(--blue); white-space: nowrap;
}

/* --- 窄屏（手机）：折行 + 单元格自带标签 --- */
@media (max-width: 899px) {
  .trow .tc::before {
    content: attr(data-k) '：';
    color: var(--muted); font-size: 12px; margin-right: 2px;
  }
  .trow .tc-t::before, .trow .tc-act::before { content: none; }
  /* 「状态：」和紧随其后的标签要在同一行 —— 单元格里的标签是块级元素，
     直接放的话标签会另起一行，只剩一个孤零零的「状态：」 */
  .trow .tc.nw { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 6px; }
  .trow .tc.nw::before { flex: none; }
  .trow .tc.nw .tagrow { display: flex; flex-wrap: wrap; gap: 4px 5px; margin-bottom: 0; }
  .trow .tc.nw .sub2 { flex: 1 0 100%; margin-top: 1px; }
  /* 长内容独占一行；短值（.nw）并排，省高度 */
  .trow .tc:not(.nw):not(.tc-t):not(.tc-act) { flex: 1 1 100%; }
  /* 需求1：手机上按钮横排、自动换行，指头好点。
     之前是竖排压满整行 —— 现在 todo 任务只留「开始做+申请变更」两颗按钮，
     竖排纯属浪费高度，横排一层放得下 */
  .tc-act { flex-direction: row; align-items: center; justify-content: flex-start; gap: 3px 5px; }
  .tc-act button { width: auto; }
  /* 手机上不必截断：整页本来就能滚，看全比看齐更重要 */
  .tc-t .tname, .deliv, .tc .accept li { -webkit-line-clamp: none; overflow: visible; white-space: normal; }
  .tc-t .tname { display: block; }
  .deliv { display: block; }
  .trow { gap: 4px 12px; padding: 13px 14px; }
  /* 手机上「单号」排在任务名【之后】：这一屏是拿来扫「我有哪些活」的，
     任务名必须还是第一行，单号退成紧随其后的一行元信息。
     ⚠️ order 在 grid 容器里同样生效，所以这几条只能写在窄屏（flex）这一段里，
        不能提到外面去 —— 否则电脑端整张表的列序会被打乱 */
  .trow .tc-t { order: 1; }
  .trow .tc-no { order: 2; }
  .trow .tc:not(.tc-t):not(.tc-no) { order: 3; }
}

/* --- 宽屏（电脑）：列对齐成表格 --- */
@media (min-width: 900px) {
  .trow {
    display: grid; gap: 0 14px;
    padding: 12px 16px; align-items: start;
  }
  /* 隔行浅底 + 悬停高亮：列多的时候靠底色跟住行 */
  /* ⚠️ 手型光标必须和「可点」成对出现，而且要和下面那条 hover 一起看：
     2026-09-22 之前只有 hover 高亮、没有光标、也没有点击处理 —— 
     那是全项目最误导人的一处「看着能点，点下去什么都不发生」。
     ?v=31 起整行可点开只读详情，所以光标补上；将来若把点击去掉，这里也要一起删。 */
  .tlist .trow:not(.th) { background: var(--card); cursor: pointer; }
  .tlist .trow:nth-child(odd):not(.th) { background: #FBFCFD; }
  .tlist .trow:hover:not(.th) { background: var(--hover); }
  .trow .tc::before { content: none; }

  /* 表头 */
  .trow.th {
    display: grid; align-items: center;
    padding: 9px 16px;
    color: var(--muted); font-size: 12.5px; font-weight: 500;
    border-bottom: 1px solid var(--line);
    background: var(--bg-soft);
  }

  /* 列宽：短列给固定值（够放下就够），长列给 fr（窗口越宽长得越多）。
     两个坑：① 原来「变更」拿最大的 1.25fr、「交付物」只有 .85fr，正好给反了；
     ② 「操作」给得太窄，4 个按钮只能一竖溜排下来，成了整行的地板。 */
  .tlist.v-mine .trow {
    grid-template-columns:
      66px                        /* 单号：MM-NNN，等宽字体，够放下 6 个字符 */
      minmax(118px, 1.15fr)       /* 任务 */
      90px                        /* 状态 */
      minmax(92px, .95fr)         /* 交付物 */
      minmax(98px, 1.3fr)         /* 验收标准 */
      minmax(92px, .95fr)         /* 进展 */
      minmax(84px, .85fr)         /* 提交与审核 */
      minmax(76px, .75fr)         /* 变更 */
      136px;                      /* 操作：够两个按钮一行 */
  }
  .tlist.v-all .trow {
    grid-template-columns:
      66px                        /* 单号 */
      minmax(106px, 1.05fr)       /* 任务 */
      66px                        /* 责任人 */
      90px                        /* 状态 */
      minmax(86px, .92fr)         /* 交付物 */
      minmax(94px, 1.25fr)        /* 验收标准：最长的列，给最大的权重 */
      minmax(86px, .92fr)         /* 进展 */
      minmax(78px, .8fr)          /* 提交与审核 */
      minmax(74px, .74fr)         /* 变更 */
      136px;                      /* 操作 */
  }
  .tlist.v-change .trow {
    grid-template-columns: 66px minmax(140px, 1.3fr) 80px 82px 86px minmax(170px, 1.5fr)
      minmax(140px, 1.3fr) 96px;
  }
  .tlist.v-brief .trow {
    grid-template-columns: 66px minmax(220px, 1.8fr) 92px 104px 100px 116px;
  }
  .tlist.v-trash .trow {
    grid-template-columns: 66px minmax(180px, 1.6fr) 84px 84px 84px 132px 104px 140px;
  }
  /* 操作记录：4 列，详情给最大权重（它可能很长） */
  .tlist.v-audit .trow {
    grid-template-columns: 108px 92px 104px minmax(240px, 3fr);
  }

  /* 窗口窄到摊不开时表格内部会横向滚动 —— 「操作」列吸附在右侧，
     滚动过程中按钮始终看得见、点得到 */
  .tlist .trow .tc-act {
    position: sticky; right: 0; background: inherit; z-index: 1;
  }
  .tlist .trow.th .tc-act { background: var(--bg-soft); }
  /* 单元格里的变更信息不再做成色块：窄列里色块会挤成一条细长条 */
  .tc .changebox {
    padding: 0; background: none; border: none; border-radius: 0; font-size: 12.5px;
  }
  .tc .changebox b { color: var(--text); }
  .tc .changebox.pending b { color: var(--amber); }
  /* 变更信息逐行截断：理由随手动辄二三十个字，不截断单这一格就能撑到 200px */
  .tc .chgline {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .tc .chgcut { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* 变更审核列表：「原值 → 新值」两行各自最长能到 160 字，原样铺开会单格撑到 190px；
     列表里只看摘要（悬停有全文），完整内容在「处理申请」弹窗里。
     ⚠️ 待审批那两行现在是 .chgcur（现值，不划）+ .chgpend（提议值，琥珀），
        这两个类也必须挂进这条规则 —— 漏了它们就没有「不换行 + 省略号」，
        一格 160 字会把整行撑高（这个 bug 不报错，只让表格变形）。 */
  .tc .chgfrom, .tc .chgto, .tc .chgpend, .tc .chgcur {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 12.5px;
  }
  .tc .chgreason {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 12.5px;
  }
  .trow .lk { font-size: 12.5px; }
  .trow .accept { font-size: 12.5px; }
}

/* 笔记本宽度（≤1180）再收一档：列宽、字号、间隙全缩一号，
   否则 9 列在这个宽度下必然撑出横向滚动 */
@media (min-width: 900px) and (max-width: 1180px) {
  .tlist { font-size: 12.5px; }
  .trow { gap: 0 9px; padding: 11px 12px; }
  .trow.th { padding: 8px 12px; font-size: 12px; }
  .sub2 { font-size: 11.5px; }
  .tlist.v-mine .trow {
    grid-template-columns: 58px minmax(104px, 1.1fr) 78px minmax(78px, .9fr) minmax(84px, 1.25fr)
      minmax(78px, .9fr) minmax(70px, .8fr) minmax(64px, .72fr) 110px;
  }
  .tlist.v-all .trow {
    grid-template-columns: 58px minmax(92px, 1fr) 58px 78px minmax(72px, .88fr)
      minmax(78px, 1.2fr) minmax(72px, .88fr) minmax(64px, .76fr) minmax(60px, .7fr) 110px;
  }
  .tlist.v-change .trow {
    grid-template-columns: 58px minmax(120px, 1.3fr) 72px 74px 76px minmax(140px, 1.5fr)
      minmax(120px, 1.3fr) 88px;
  }
  .tlist.v-trash .trow {
    grid-template-columns: 58px minmax(140px, 1.5fr) 72px 72px 72px 118px 92px 124px;
  }
  /* 操作记录在笔记本宽度再收一档。合计 96+82+92+200=470px + 3 个 9px 间隙 + 左右 24px
     内边距 ≈ 521px，加上 232px 侧栏仍能塞进 900px 视口，不会顶出整页横向滚动 */
  .tlist.v-audit .trow {
    grid-template-columns: 96px 82px 92px minmax(200px, 3fr);
  }
  .tc-act .btn-sm, .tc-act .btn-link { font-size: 11.5px; padding: 3px 5px; }
}

/* 电脑端隐藏移动端专用块，反之亦然 */
[data-layout="desktop"] .only-mobile { display: none !important; }
[data-layout="mobile"] .only-desktop { display: none !important; }

/* ============================================================
   8. 每日进展
   ------------------------------------------------------------
   列表里每个单元格都很窄，进展只能给「最近两条 + 条数」；
   完整时间线放在弹窗里（写进展 / 审核时看）。 */
.tc-prog { font-size: 13px; }
/* 状态列可能有两个标签（状态 + 「每日」），要能自己折行 */
.tagrow { display: flex; flex-wrap: wrap; gap: 4px 5px; margin-bottom: 3px; }
.progline {
  display: flex; align-items: baseline; gap: 6px;
  line-height: 1.5; margin-bottom: 1px;
}
/* 文本自己截断，标签/署名不参与省略 —— 整行 nowrap 会把「卡点」吞掉 */
.progtxt {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.progline .tag { flex: none; }
/* 进展列里每条前面的日期小标 */
.progday {
  flex: none;
  display: inline-block; padding: 0 5px;
  border-radius: 5px; background: var(--blue-fill); color: var(--blue);
  font-size: 11.5px; line-height: 17px; font-weight: 500;
}
.progwho { flex: none; color: var(--muted); font-size: 11.5px; }
/* 「今日未更新」是催办信号，不是惩罚：用浅底胶囊 + 小字，不铺满底色 */
.stale {
  display: inline-block; margin-bottom: 4px;
  padding: 0 8px; border-radius: 999px;
  background: var(--red-fill); color: var(--red);
  border: 1px solid var(--red-line);
  font-size: 12px; font-weight: 500; line-height: 18px;
}

/* 进度落后于约定的按钮：给它一点紧迫感，但仍然点得到 */
.btn-urgent { border-color: var(--amber-line); color: var(--amber); background: var(--amber-fill); }
.btn-urgent:hover { border-color: var(--amber); background: var(--amber-fill); }

/* 关键任务未更新的提示条 */
.carrybox.stalebox { background: var(--red-fill); border-color: var(--red-line); }
.carrybox.stalebox b { color: var(--red); }

/* 期初欠账提示条：用琥珀色。它要看得见，但必须和「今天没写进展」的红色分开 ——
   这笔债仍然算在原来的月份里、不进本月分母，是背景信息，不是扣分项 */
.carrybox.debtbox { background: var(--amber-fill); border-color: var(--amber-line); }
.carrybox.debtbox b { color: var(--amber); }
/* 被删除的任务：用中性灰。
   它既不是"催办"（红）也不是"欠账"（琥珀）—— 是一个已经消失、只留下痕迹的记录，
   用刺眼的颜色反而会让人以为它是待办 */
.carrybox.delbox { background: #F2F4F7; border-color: #E4E8ED; }
.carrybox.delbox b { color: var(--text); }
.carrybox.delbox .debtwho { border-top-color: #E4E8ED; }
.carrybox.delbox .debtwho b { color: var(--text); }
.debtwho {
  margin-top: 7px; padding-top: 7px; border-top: 1px dashed var(--amber-line);
  font-size: 12.5px; color: var(--text-2); line-height: 1.7; word-break: break-word;
}
.debtwho b { color: var(--amber); }

/* 看板指标里的警示项 */
.metric.warn { background: var(--red-fill); }
.metric.warn b { color: var(--red); }

/* 勾选项（派单选「关键任务」、写进展勾「有卡点」） */
.chk {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 12px; margin-bottom: 12px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-soft); font-size: 13.5px; line-height: 1.6;
  cursor: pointer; transition: border-color .14s, background .14s;
}
.chk:hover { border-color: var(--blue-line); background: var(--blue-fill); }
.chk input { width: 17px; height: 17px; margin-top: 2px; flex: none; accent-color: var(--blue); }
.chk span { min-width: 0; }

/* 设置页 · 消息推送：事件勾选排成自适应多列，窄屏自动退成一列 */
.chkgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(228px, 1fr));
  gap: 6px 10px;
}
[data-layout="mobile"] .chkgrid { grid-template-columns: 1fr; }

/* 推送结果小行：时间 / 事件 / 结果 三栏对齐 */
.plog { margin-top: 10px; display: flex; flex-direction: column; gap: 2px; }
.plogrow {
  display: grid;
  grid-template-columns: 142px 96px 1fr;
  gap: 10px;
  align-items: baseline;
  padding: 6px 10px;
  background: var(--bg-soft);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
}
.plogrow .lk { font-weight: 600; }
.plog-ok { color: var(--green); }
.plog-bad { color: var(--red); }
[data-layout="mobile"] .plogrow { grid-template-columns: 1fr; gap: 2px; }

/* ---------- 站内「消息」卡片（群消息的完整副本） ---------- */
.msgcard { padding: 13px 15px 11px; }
.msgcard + .msgcard,
.msgcard + .card,
.card + .msgcard { margin-top: 10px; }
.msghead { display: flex; align-items: center; gap: 9px; margin-bottom: 7px; }
/* .sub2 本身是 block，放进 flex 行里要把那条块级规则还原掉 */
.msghead .sub2 { display: inline; margin-top: 0; }
.msgtitle {
  font-size: 14.5px; font-weight: 600; line-height: 1.5;
  margin-bottom: 4px; word-break: break-word;
}
.msgtext-h { font-size: 12.5px; margin: 2px 0 4px; }
/* 进展原文：整段照抄、不截断 —— 这就是这个页面存在的理由。
   用正文字体 + 左描边，读起来像「引用了一段话」，而不是一段代码 */
.msgtext {
  margin: 4px 0 2px; padding: 8px 11px;
  background: var(--bg-soft);
  border-left: 3px solid var(--blue-line);
  border-radius: var(--radius-sm);
  font-size: 13.5px; line-height: 1.65;
  white-space: pre-wrap; word-break: break-word;
}
/* 群里那条原文（含 markdown 符号），默认折叠 */
.msgsrc { margin-top: 9px; }

/* ============ PWA 离线角标 ============ */
#netbadge {
  position: fixed; top: 0; left: 0; right: 0; z-index: 9999;
  padding: 8px 12px calc(6px + env(safe-area-inset-top));
  background: #B54708; color: #fff; font-size: 13px; text-align: center;
  box-shadow: 0 2px 8px rgba(0,0,0,.18);
}
.msgsrc > summary {
  cursor: pointer; user-select: none;
  font-size: 12.5px; color: var(--muted); padding: 2px 0;
}
.msgsrc > summary:hover { color: var(--blue); }
.msgsrc pre {
  margin: 6px 0 0; padding: 9px 11px;
  background: var(--bg-soft); border-radius: var(--radius-sm);
  font-size: 12px; line-height: 1.6; color: var(--muted);
  white-space: pre-wrap; word-break: break-word;
  max-height: 260px; overflow: auto;
}
[data-layout="mobile"] .msgcard { padding: 12px 13px 10px; }
[data-layout="mobile"] .msgsrc pre { max-height: 200px; }

/* 人员名单的一行：上行是姓名/账号/角色，下行是口令状态与操作 ——
   挤在一行里「重置换口令」「看初始口令」「删除」会跟输入框抢宽度 */
.prow {
  padding: 10px 12px; margin-bottom: 8px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-soft);
}
.prow .psub {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--line-soft);
  font-size: 12px;
}
.prow .psub .stale { margin-bottom: 0; }

/* 初始口令展示：要一眼看清、方便手抄或复制，所以给等宽字体和大字号 */
.pwdbox {
  font-family: var(--mono);
  font-size: 26px; letter-spacing: 5px; text-align: center;
  padding: 15px 12px; margin: 6px 0 2px;
  border: 1px dashed var(--blue-line); border-radius: var(--radius);
  background: var(--blue-fill); color: var(--blue-dark);
  user-select: all; word-break: break-all; font-weight: 600;
}

/* 进展时间线 */
.timeline { max-height: 46vh; overflow-y: auto; }
/* 时间线按「天」分组：每天一个小标题 */
.tlday { margin-bottom: 2px; }
.tldayhead {
  display: flex; align-items: baseline; gap: 8px;
  margin: 14px 0 2px; padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
}
.tlday:first-child .tldayhead { margin-top: 2px; }
.tldaylab { font-weight: 650; font-size: 13.5px; }
.tldayhead .sub2 { font-size: 12px; margin-top: 0; }
.tlitem { padding: 10px 0; border-bottom: 1px solid var(--line-soft); }
.tlitem:last-child { border-bottom: none; }
.tlhead {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  margin-bottom: 5px; font-size: 12.5px;
}
.tlhead b { font-weight: 600; font-family: var(--mono); font-size: 12px; color: var(--text-2); }
.tlhead .btn-link { padding: 0; font-size: 12px; color: var(--muted); }
.tlhead .btn-link:hover { color: var(--red); background: none; text-decoration: underline; }
.tltext { font-size: 14px; line-height: 1.6; word-break: break-word; }

/* 进展批注：挂在对应那条进展的下面，做成「引用 + 缩进」的样子。
   跟 .msgtext（进展原文）是同一套视觉语言，但换成琥珀色 ——
   蓝色是「执行人写的」，琥珀是「管理者回的」，一眼分得清谁在说话 */
.tlcmt {
  margin: 8px 0 2px 14px; padding: 7px 10px;
  background: var(--amber-fill);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius-sm);
}
.tlcmt-head {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-bottom: 3px; font-size: 12px;
}
.tlcmt-who { color: var(--amber); font-weight: 600; }
.tlcmt-head .btn-link { padding: 0; font-size: 12px; color: var(--muted); }
.tlcmt-head .btn-link:hover { color: var(--red); background: none; text-decoration: underline; }
.tlcmt-text {
  font-size: 13.5px; line-height: 1.6; color: var(--text-2);
  white-space: pre-wrap; word-break: break-word;
}

/* 批注弹窗里「被批注的那条进展」：整段照抄，限高可滚，别把弹窗顶爆 */
.tlquote {
  padding: 9px 11px; background: var(--bg-soft);
  border-left: 3px solid var(--blue-line);
  border-radius: var(--radius-sm);
  font-size: 13.5px; line-height: 1.6; color: var(--text-2);
  white-space: pre-wrap; word-break: break-word;
  max-height: 150px; overflow-y: auto;
}

/* 批注计数的统一配色（列表格子里、消息页说明里都用它） */
.cmtn { color: var(--amber); font-weight: 600; }

/* 手机上批注块别缩进太多，横向本来就不够；正文也略小一档 */
[data-layout="mobile"] .tlcmt { margin-left: 6px; }
[data-layout="mobile"] .tlcmt-text { font-size: 13px; }

/* 手机上时间线不用限高：整页本来就能滚，套一层内部滚动反而难滑 */
[data-layout="mobile"] .timeline { max-height: none; }

/* ============================================================
   9. 可访问性与动效
   ============================================================ */

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
button:focus-visible { outline-offset: 1px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* 细滚动条：默认的粗灰条在浅色面板上很扎眼 */
.scroll-x::-webkit-scrollbar, .chipbar::-webkit-scrollbar { height: 8px; }
.scroll-x::-webkit-scrollbar-thumb, .chipbar::-webkit-scrollbar-thumb {
  background: #D5DAE1; border-radius: 4px;
}
.scroll-x::-webkit-scrollbar-track, .chipbar::-webkit-scrollbar-track { background: transparent; }
.scroll-x::-webkit-scrollbar-thumb:hover, .chipbar::-webkit-scrollbar-thumb:hover { background: #C2C9D2; }

/* ============================================================
   10. 禅道数据源卡片（看板顶部）
   ============================================================ */
.zt-card { border: 1px solid #E7EBEF; }
.zt-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.zt-btns { display: flex; gap: 8px; flex-wrap: wrap; }
.btnh {
  background: #fff; border: 1px solid #E1E6EC; color: var(--text-2);
  padding: 6px 12px; border-radius: var(--radius-sm); font-size: 13px; cursor: pointer;
  transition: all .15s ease;
}
.btnh:hover { border-color: var(--blue); color: var(--blue); }
.btnh.on { background: var(--blue); border-color: var(--blue); color: #fff; }
.zt-team { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 10px; }
.zt-mod { background: #F8FAFB; border: 1px solid #EEF1F4; border-radius: var(--radius-sm); padding: 10px 12px; }
.zt-modt { font-weight: 600; font-size: 13px; color: var(--text); margin-bottom: 6px; }
.zt-mod .kv { font-size: 12.5px; line-height: 1.8; color: var(--text-2); }
.zt-mod .kv b { color: var(--text); }
[data-layout="mobile"] .zt-team { grid-template-columns: 1fr; }

.zt-personhead {
  display: grid; grid-template-columns: 110px 1fr 1fr; gap: 12px;
  font-size: 12px; font-weight: 600; color: var(--text-2);
  padding: 4px 0 8px; border-bottom: 1px solid #EEF1F4;
}
.zt-person {
  display: grid; grid-template-columns: 110px 1fr 1fr; gap: 12px;
  align-items: center; padding: 9px 0; border-bottom: 1px solid #F3F5F7; font-size: 12.5px;
}
.zt-person:last-child { border-bottom: none; }
.zt-name { font-weight: 600; color: var(--text); }
.zt-ab { color: var(--text-2); line-height: 1.9; }
.zt-ab b { color: var(--text); }
.zt-abt { display: inline-block; min-width: 64px; }
.zt-ab .tag, .zt-team .tag { margin-left: 8px; vertical-align: middle; }
[data-layout="mobile"] .zt-personhead { display: none; }
[data-layout="mobile"] .zt-person { grid-template-columns: 1fr; gap: 2px; }

.zt-um { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 6px 0; }
.zt-umacct { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; min-width: 110px; font-weight: 600; }
.zt-umpick { flex: 1; min-width: 140px; max-width: 260px; }
.zt-ign { font-size: 12.5px; color: var(--text-2); line-height: 2; }
