/* ==========================================================================
   家装产研 · 项目与需求管理  样式
   ========================================================================== */

:root{
  --bg:#F2F4F7;
  --surface:#FFFFFF;
  --surface-2:#F8F9FB;
  --surface-3:#F1F3F7;
  --line:#E5E8EE;
  --line-2:#D8DDE6;
  --text:#14171F;
  --text-2:#5A6272;
  --text-3:#8A92A4;
  --primary:#2B5CE6;
  --primary-2:#1E47BC;
  --primary-weak:#EDF2FE;
  --danger:#C8362F;
  --danger-weak:#FDEDEC;
  --ok:#0F7B5A;
  --warn:#B45309;
  --radius:10px;
  --radius-lg:14px;
  --shadow-1:0 1px 2px rgba(16,24,40,.05),0 1px 3px rgba(16,24,40,.04);
  --shadow-2:0 8px 24px rgba(16,24,40,.10),0 2px 6px rgba(16,24,40,.06);
  --shadow-3:0 24px 60px rgba(16,24,40,.18);
  --sb-w:236px;
  --font:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;font-family:var(--font);background:var(--bg);color:var(--text);
  font-size:14px;line-height:1.55;-webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
body.phone-preview{background:radial-gradient(1200px 600px at 50% 0%,#E7EBF3 0%,#DDE3ED 60%,#D6DCE8 100%);padding:28px 0}
body.phone-preview .app{position:relative}
button,input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
button{cursor:pointer;border:none;background:none}
a{color:var(--primary);text-decoration:none}

/* SVG 图标兜底：带 viewBox 的 SVG 不写宽高时会被浏览器撑满容器。
   月报页提示条里的拖动手柄图标（24x24 的六点阵）曾因此被放大到近千像素，
   六个圆点渲染成六个大圆。这里全局缩到文字大小；下方按场景定的
   .brand-mark svg / .btn svg 等规则特异性更高，不受影响。 */
svg{width:1em;height:1em;flex:0 0 auto;vertical-align:-0.12em}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#C9CFDA;border-radius:8px;border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:#AEB6C4;background-clip:content-box}
::-webkit-scrollbar-track{background:transparent}

/* ---------- 骨架 ---------- */
/* position:relative 是为了给侧栏宽度把手当定位参照 —— 它绝对定位在侧栏右缘，
   不占 grid 的列，免得拖动时把内容区挤一下。 */
.app{position:relative;display:grid;grid-template-columns:var(--sb-w) 1fr;height:100vh;height:100dvh;overflow:hidden}
body.phone-preview .app{
  width:400px;height:820px;margin:0 auto;grid-template-columns:1fr;
  border-radius:30px;overflow:hidden;box-shadow:var(--shadow-3);border:1px solid #CBD2DE;background:var(--surface);
}
.main{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--bg)}
.view{flex:1;overflow:auto;padding:20px 24px 40px;min-height:0;scroll-behavior:smooth}
.app.is-compact{grid-template-columns:1fr}
.app.is-compact .view{padding:14px 14px 96px}
.app.is-compact .sidebar{display:none}

/* ---------- 侧栏 ---------- */
.sidebar{
  background:#101726;color:#C6CEE0;display:flex;flex-direction:column;
  padding:16px 12px 12px;gap:4px;overflow:auto;
}
.brand{display:flex;align-items:center;gap:10px;padding:6px 8px 16px}
.brand-mark{
  width:32px;height:32px;border-radius:9px;flex:0 0 auto;
  background:linear-gradient(150deg,#4C7BFF,#2B5CE6 55%,#7A4BFF);
  display:grid;place-items:center;box-shadow:0 4px 12px rgba(43,92,230,.45);
}
.brand-mark svg{width:18px;height:18px}
.brand-text{min-width:0}
.brand-title{font-size:14px;font-weight:600;color:#fff;letter-spacing:.2px}
.brand-sub{font-size:11px;color:#7C879E;margin-top:1px}
.nav-group{padding:12px 10px 6px;font-size:11px;color:#5E6A82;letter-spacing:.6px;font-weight:600}
.nav-item{
  display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:9px;
  color:#B9C2D4;font-size:13.5px;width:100%;text-align:left;transition:background .13s,color .13s;
}
.nav-item svg{width:17px;height:17px;flex:0 0 auto;opacity:.85}
.nav-item:hover{background:#1B2333;color:#F1F4FA}
.nav-item.on{background:#22304E;color:#fff;font-weight:600}
.nav-item.on svg{opacity:1;color:#7FA0FF}
.nav-count{margin-left:auto;font-size:11px;background:#26314A;color:#9FABC4;padding:1px 7px;border-radius:20px;font-variant-numeric:tabular-nums}
.nav-item.on .nav-count{background:#3A4E7E;color:#DCE5FA}
.sb-foot{margin-top:auto;padding:10px 6px 4px;border-top:1px solid #1E2637}
.usercard{display:flex;align-items:center;gap:10px;padding:8px;border-radius:9px;width:100%;text-align:left}
.usercard:hover{background:#1B2333}
.avatar{width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:600;color:#fff;background:linear-gradient(140deg,#5B7BFF,#2B5CE6);flex:0 0 auto}
.usercard .u-name{font-size:13px;color:#E7ECF6;font-weight:500;line-height:1.2}
.usercard .u-role{font-size:11px;color:#7C879E}

/* ---------- 侧栏：收起 / 调宽 ---------- */
/* 收起按钮：常驻在品牌区，图标跟着状态翻（收起态是「向右展开」）。
   收起后品牌区改成竖排，否则 56px 里塞不下 logo + 箭头。 */
.sb-toggle{
  margin-left:auto;width:24px;height:24px;flex:0 0 auto;display:grid;place-items:center;
  border-radius:7px;color:#7C879E;transition:background .13s,color .13s;
}
.sb-toggle:hover{background:#1B2333;color:#E7ECF6}
.sb-toggle svg{width:16px;height:16px}

/* 拖拽把手：贴在侧栏右缘的一条 7px 透明带，不占位、不影响布局。
   只有 hover / 拖动时才亮出那条线，平时完全看不见。 */
.sb-resize{position:absolute;top:0;bottom:0;left:var(--sb-w);width:7px;margin-left:-3px;cursor:col-resize;z-index:25}
.sb-resize::after{
  content:"";position:absolute;top:0;bottom:0;left:3px;width:1px;
  background:transparent;transition:background .15s;
}
.sb-resize:hover::after{background:#4C7BFF}
body.is-resizing-sb .sb-resize::after{background:var(--primary);left:2px;width:3px}
/* 拖动时全局改成 col-resize 并禁掉选中，否则会一路刷蓝一片文字 */
body.is-resizing-sb{cursor:col-resize;user-select:none;-webkit-user-select:none}

/* 收起态：只留图标。分组标题收成一条分隔线，数字变成图标右上角的小圆点
   （不这么做的话，收起后「意见箱还有几条没闭环」这个信息就没了）。 */
.app.is-sb-collapsed .sidebar{padding:16px 8px 12px;overflow-x:hidden}
.app.is-sb-collapsed .brand{flex-direction:column;gap:10px;padding:6px 0 14px}
.app.is-sb-collapsed .brand-text{display:none}
.app.is-sb-collapsed .sb-toggle{margin-left:0}
.app.is-sb-collapsed .nav-group{
  padding:0;height:1px;margin:12px 6px;background:#1E2637;
  font-size:0;line-height:0;text-indent:-9999px;overflow:hidden;
}
.app.is-sb-collapsed .nav-item{position:relative;justify-content:center;padding:9px 0;gap:0}
.app.is-sb-collapsed .nav-item svg{width:19px;height:19px}
.app.is-sb-collapsed .nav-label{display:none}
.app.is-sb-collapsed .nav-count{
  position:absolute;top:2px;right:5px;margin:0;padding:0 4px;
  min-width:16px;line-height:15px;font-size:10px;text-align:center;
}
.app.is-sb-collapsed .sb-foot{padding:10px 0 4px}
.app.is-sb-collapsed .usercard{justify-content:center;padding:6px 0}
.app.is-sb-collapsed .uc-text{display:none}
/* 收起态不给提示条：宽度不够，弹出来会顶破布局 */
.app.is-sb-collapsed .ro-banner{display:none}
/* 移动视图 / 手机预览下没有侧栏，把手一起藏掉 */
.app.is-compact .sb-resize{display:none}

/* ---------- 顶栏 ---------- */
.topbar{
  height:56px;flex:0 0 auto;background:var(--surface);border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:12px;padding:0 20px;position:relative;z-index:6;
}
.tb-title{font-size:15px;font-weight:600;letter-spacing:.1px;white-space:nowrap}
.tb-sub{font-size:12px;color:var(--text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tb-sep{width:1px;height:20px;background:var(--line)}
.tb-search{
  margin-left:auto;display:flex;align-items:center;gap:7px;background:var(--surface-3);
  border:1px solid transparent;border-radius:9px;padding:0 10px;height:34px;width:230px;transition:.15s;
}
.tb-search:focus-within{background:#fff;border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-weak)}
.tb-search input{border:none;background:none;outline:none;width:100%;font-size:13px}
.tb-search svg{width:15px;height:15px;color:var(--text-3);flex:0 0 auto}
.tb-actions{display:flex;align-items:center;gap:8px}
/* 列表工具栏里的搜索框（按名称模糊搜）：跟顶栏那个共用同一个关键词，不存第二份。
   外观对齐 .msel-btn（白底描边、同高同圆角）—— 它跟筛选按钮排在一行，长得不一样才违和。 */
.q-box{display:flex;align-items:center;gap:6px;background:var(--surface);flex:0 0 auto;
  border:1px solid var(--line-2);border-radius:8px;padding:0 10px;height:32px;width:212px;transition:.15s}
.q-box:hover{border-color:var(--primary)}
.q-box:focus-within{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-weak)}
.q-box input{border:none;background:none;outline:none;width:100%;font-size:13px;color:var(--text)}
.q-box input::placeholder{color:var(--text-3)}
.q-box svg{width:14px;height:14px;color:var(--text-3);flex:0 0 auto}
.app.is-compact .topbar{padding:0 12px;gap:8px;height:52px}
.app.is-compact .tb-search{display:none}
.app.is-compact .tb-sub{display:none}

/* ---------- 底部标签栏（移动） ---------- */
.tabbar{display:none}
.app.is-compact .tabbar{
  display:grid;grid-auto-flow:column;grid-auto-columns:1fr;align-items:center;
  position:fixed;left:0;right:0;bottom:0;height:60px;padding-bottom:env(safe-area-inset-bottom);
  background:rgba(255,255,255,.94);backdrop-filter:blur(14px);border-top:1px solid var(--line);z-index:30;
}
body.phone-preview .app.is-compact .tabbar{position:absolute}
.tab-item{display:flex;flex-direction:column;align-items:center;gap:2px;color:var(--text-3);font-size:10.5px;padding:6px 0}
.tab-item svg{width:20px;height:20px}
.tab-item.on{color:var(--primary);font-weight:600}

/* ---------- 通用 ---------- */
.btn{
  display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 13px;border-radius:9px;
  background:var(--surface);border:1px solid var(--line-2);color:var(--text);font-size:13px;
  font-weight:500;transition:.13s;white-space:nowrap;
}
.btn svg{width:15px;height:15px}
.btn:hover{background:var(--surface-2);border-color:#C4CBD7}
.btn:active{transform:translateY(.5px)}
.btn-primary{background:var(--primary);border-color:var(--primary);color:#fff;box-shadow:0 1px 2px rgba(43,92,230,.3)}
.btn-primary:hover{background:var(--primary-2);border-color:var(--primary-2)}
.btn-ghost{background:transparent;border-color:transparent;color:var(--text-2)}
.btn-ghost:hover{background:var(--surface-3);color:var(--text)}
.btn-danger{color:var(--danger);border-color:#EED2D0}
.btn-danger:hover{background:var(--danger-weak)}
.btn-sm{height:28px;padding:0 9px;font-size:12.5px;border-radius:7px}
.btn-xs{height:24px;padding:0 8px;font-size:12px;border-radius:6px}
.btn[disabled]{opacity:.5;pointer-events:none}
/* 展开态：工具条上「⋯」点了之后自己要有反馈，否则看不出是开关还是普通按钮 */
.btn.on{background:var(--primary-weak);border-color:#C9D8FA;color:var(--primary)}
.icon-btn{
  width:32px;height:32px;border-radius:8px;display:grid;place-items:center;color:var(--text-2);
  border:1px solid transparent;transition:.13s;flex:0 0 auto;
}
.icon-btn svg{width:17px;height:17px}
.icon-btn:hover{background:var(--surface-3);color:var(--text)}
.icon-btn.on{background:var(--primary-weak);color:var(--primary)}

.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:var(--shadow-1)}
.card+.card{margin-top:14px}
.card-head{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--line)}
.card-title{font-size:14px;font-weight:600}
.card-sub{font-size:12px;color:var(--text-3)}
.card-head .right{margin-left:auto;display:flex;gap:8px;align-items:center}
.card-body{padding:16px}
.card-body.tight{padding:0}
.hint{font-size:12px;color:var(--text-3);line-height:1.6}

/* ---------- 「说明」按钮：口径/提示收进弹窗，页面上只留一个入口 ----------
   外观跟 .btn.btn-sm 一致（同一个「说明」入口走到哪都长一样），只是字色更浅 */
.note-btn{display:inline-flex;align-items:center;justify-content:center;gap:3px;
  height:28px;padding:0 9px;border:1px solid var(--line-2);border-radius:7px;
  background:var(--surface);color:var(--text-3);font-size:12.5px;line-height:1;
  cursor:pointer;white-space:nowrap;transition:background .15s,color .15s,border-color .15s}
.note-btn svg{width:14px;height:14px;flex:none}
.note-btn:hover{background:var(--surface-2);color:var(--text);border-color:#C4CBD7}
/* 折叠标题栏里的「说明」要更矮一点，别把 32px 的行撑成 40px */
.rv-head .note-btn{height:22px;padding:0 7px;font-size:11.5px;border-radius:6px}
.rv-head .note-btn svg{width:12px;height:12px}
.note-lines p{margin:0 0 10px;font-size:13px;line-height:1.8;color:var(--text-2)}
.note-lines p:last-child{margin-bottom:0}
.note-lines p::before{content:"·";color:var(--text-3);margin-right:6px}
.note-lines b{color:var(--text);font-weight:600}
.sec-title{font-size:13px;font-weight:600;color:var(--text-2);margin:0 0 10px;display:flex;align-items:center;gap:8px}
.sec-title::before{content:"";width:3px;height:13px;border-radius:2px;background:var(--primary)}

/* ---------- KPI ---------- */
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.app.is-compact .kpis{grid-template-columns:repeat(2,1fr);gap:10px}
.kpi{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-lg);padding:14px 16px;box-shadow:var(--shadow-1);position:relative;overflow:hidden}
.kpi::after{content:"";position:absolute;right:-26px;top:-26px;width:76px;height:76px;border-radius:50%;background:var(--primary-weak);opacity:.7}
.kpi-num{font-size:26px;font-weight:650;letter-spacing:-.5px;font-variant-numeric:tabular-nums;position:relative;line-height:1.15}
.kpi-label{font-size:12.5px;color:var(--text-2);margin-top:3px;position:relative}
.kpi-delta{font-size:11.5px;color:var(--text-3);margin-top:6px;position:relative}
.kpi.k-project .kpi-num{color:#3B4DD8}.kpi.k-project::after{background:#EAECFD}
.kpi.k-need .kpi-num{color:#0E7490}.kpi.k-need::after{background:#E2F3F6}
.kpi.k-done .kpi-num{color:var(--ok)}.kpi.k-done::after{background:#E4F4EE}

/* ---------- 分布条 ---------- */
.bars{display:flex;flex-direction:column;gap:9px}
.bar-row{display:grid;grid-template-columns:104px 1fr 46px;align-items:center;gap:10px;font-size:12.5px}
.bar-name{color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bar-track{height:8px;border-radius:6px;background:var(--surface-3);overflow:hidden;flex:1}
.bar-fill{display:block;height:100%;border-radius:6px;background:var(--primary);transition:width .4s cubic-bezier(.2,.8,.3,1)}
.bar-val{text-align:right;color:var(--text-3);font-variant-numeric:tabular-nums}
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;align-items:start}
@media (max-width:1180px){.grid-2,.grid-3{grid-template-columns:1fr}}
.app.is-compact .grid-2,.app.is-compact .grid-3{grid-template-columns:1fr}

/* ---------- 工具栏 / 表单 ---------- */
.toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.toolbar .grow{flex:1}
.field{display:flex;flex-direction:column;gap:5px}
.field>label{font-size:12px;color:var(--text-2);font-weight:500}
.input,.select,.textarea{
  height:34px;padding:0 10px;border:1px solid var(--line-2);border-radius:9px;background:var(--surface);
  outline:none;transition:.13s;font-size:13px;width:100%;
}
.textarea{height:auto;padding:8px 10px;line-height:1.6;resize:vertical;min-height:74px}
.input:focus,.select:focus,.textarea:focus{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-weak)}
.select{appearance:none;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238A92A4' stroke-width='1.6'><path d='M4 6.5 8 10.5l4-4'/></svg>");background-repeat:no-repeat;background-position:right 8px center;background-size:14px;padding-right:26px}
.chips{display:flex;gap:6px;flex-wrap:wrap}
.chip{
  display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 10px;border-radius:8px;
  border:1px solid var(--line);background:var(--surface);font-size:12.5px;color:var(--text-2);transition:.13s;
}
.chip:hover{border-color:#C4CBD7;color:var(--text)}
.chip.on{background:var(--primary-weak);border-color:#C9D8FB;color:var(--primary-2);font-weight:600}
/* 延期类筛选选中后用红色，跟蓝色"普通筛选"区分开 —— 点下去是在看问题清单，不是在收窄范围 */
.chip-delay{color:#B42318}
.chip-delay:hover{color:#B42318}
.chip-delay.on{background:#FEF3F2;border-color:#FECDCA;color:#B42318}
.chip .x{opacity:.6}
/* chip 上的条数：加粗一点才是"统计"，跟标签文字分开 */
.chip b{font-weight:700;font-variant-numeric:tabular-nums}
/* 在当前其他筛选条件下为 0 的（没选中的）压暗：点下去也是空结果，先看清楚再点 */
.chip.zero{opacity:.45}
.chip.zero:hover{opacity:.75}
.seg{display:inline-flex;background:var(--surface-3);border-radius:9px;padding:3px;gap:2px}
.seg button{height:28px;padding:0 11px;border-radius:7px;font-size:12.5px;color:var(--text-2);font-weight:500}
.seg button.on{background:var(--surface);color:var(--text);font-weight:600;box-shadow:var(--shadow-1)}

/* ---------- 表格 ---------- */
.table-wrap{overflow:auto;border-radius:var(--radius-lg)}
table.data{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;min-width:0;table-layout:fixed}
table.data col.c-auto{width:auto}
table.data th{
  position:sticky;top:0;z-index:3;background:var(--surface-2);text-align:left;font-weight:600;font-size:12px;
  color:var(--text-2);padding:9px 10px;border-bottom:1px solid var(--line);white-space:nowrap;
}
table.data th.sortable{cursor:pointer;user-select:none}
table.data th.sortable:hover{color:var(--primary)}
table.data th .sortmark{font-size:10px;opacity:.55;margin-left:3px}
table.data td{padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:top}
table.data tbody tr{background:var(--surface);transition:background .1s}
table.data tbody tr:hover{background:#FAFBFD}
table.data tbody tr.sel{background:var(--primary-weak)}
table.data tbody tr.dragging{opacity:.35}
table.data tbody tr.dropbefore td{border-top:2px solid var(--primary)}
table.data tbody tr.dropafter td{border-bottom:2px solid var(--primary)}
.nw{white-space:nowrap}
td.c-name{font-weight:500;min-width:190px}
td.c-name .sub{font-size:11.5px;color:var(--text-3);font-weight:400;margin-top:2px;display:flex;gap:8px;flex-wrap:wrap}
td.num{text-align:right;font-variant-numeric:tabular-nums}
.row-handle{color:var(--text-3);cursor:grab;padding:0 2px;display:inline-flex;align-items:center;height:20px}
.row-handle svg{width:13px;height:13px}
.row-handle:active{cursor:grabbing}
/* 所属月报标签（列表格子里一排小月签 + 详情抽屉里的大号） */
.mchip{display:inline-block;font-size:11px;line-height:1.5;padding:1px 6px;margin:1px 3px 1px 0;
  border-radius:6px;background:var(--primary-weak);color:#22409B;border:1px solid #D3DEFB;white-space:nowrap}
.mchip.lg{font-size:12.5px;padding:3px 10px}
.mchip.cur{background:#EEF6FF;color:#155EEF;border-color:#BBD5FF}
.mchips{display:inline-flex;flex-wrap:wrap;gap:2px;padding:2px 4px;border-radius:8px;cursor:pointer;
  border:1px dashed transparent;background:none;min-height:22px;justify-content:flex-start;align-items:center}
.mchips:hover{border-color:#BBD5FF;background:var(--primary-weak)}
td.c-months{max-width:132px}
/* 月报选择弹窗里的月份清单 */
.mp-list{display:flex;flex-direction:column;gap:2px;max-height:320px;overflow:auto}
/* ---------- 意见箱 ---------- */
/* 一条意见 = 一张卡。左边色条 = 状态：灰（还没人认领）/ 蓝（处理中）/ 绿（已闭环）。
   和条目评论的配色刻意区分开：评论是"某条需求上的讨论"，意见箱是"独立的开放议题"。 */
.sg-item{border:1px solid var(--border);border-radius:10px;padding:12px 14px;margin-bottom:10px;
  background:#fff;border-left:3px solid #CBD5E1}
.sg-item.sg-open{border-left-color:#94A3B8}
.sg-item.sg-doing{border-left-color:var(--primary)}
.sg-item.sg-closed{border-left-color:var(--ok);background:#FCFDFD}
.sg-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.sg-title{font-size:14px;font-weight:600;color:var(--text-1)}
.sg-body{margin:6px 0 8px;font-size:13.5px;line-height:1.75;color:var(--text-1);white-space:normal}
.sg-meta{display:flex;gap:14px;flex-wrap:wrap;font-size:12px;color:var(--text-2)}
.sg-badge{display:inline-flex;align-items:center;font-size:11.5px;font-weight:600;
  padding:1px 8px;border-radius:6px;white-space:nowrap}
.sg-badge.sg-open{background:#F1F5F9;color:#475569}
.sg-badge.sg-doing{background:var(--primary-weak);color:#22409B}
.sg-badge.sg-closed{background:#E4F4EE;color:var(--ok)}
.sg-replies{margin:8px 0;border-top:1px dashed var(--border);padding-top:8px}
.sg-reply{position:relative;padding:6px 26px 6px 0;border-bottom:1px solid #F1F5F9}
.sg-reply:last-child{border-bottom:0}
.sg-reply-who{font-size:12.5px;font-weight:600;color:var(--text-1);margin-right:6px}
.sg-reply-when{font-size:11.5px;color:var(--text-3)}
.sg-reply-text{font-size:13px;line-height:1.7;color:var(--text-1);margin-top:2px}
.sg-reply .icon-btn{position:absolute;right:0;top:4px;opacity:.5}
.sg-reply:hover .icon-btn{opacity:1}
.sg-foot{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:8px}
.sg-foot .input{flex:1;min-width:200px}
/* 单元格下方的「实际」标签：预计值是承诺（会被改），实际值是既成事实（绿色 = 已经发生了） */
.cell-tag{display:block;margin-top:2px;font-size:11px;line-height:1.5;white-space:nowrap;
  color:var(--ok);font-weight:600}
.cell-tag.ok::before{content:'';display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--ok);margin-right:4px;vertical-align:1px}
/* 「缺上线时间」：红色 —— 这是数据里缺了个该有的数，不是状态提示，得有人去补 */
.cell-tag.warn{color:#B42318}
.cell-tag.warn::before{content:'';display:inline-block;width:5px;height:5px;border-radius:50%;
  background:#F04438;margin-right:4px;vertical-align:1px}
/* 可点的那份：点它就能把缺的时间补上，所以要长得像能点的东西 */
.cell-tag.warn.mk-online{cursor:pointer;border-bottom:1px dashed #F04438}
.cell-tag.warn.mk-online:hover{background:#FEF3F2;border-radius:4px}
/* 操作列常驻：行不再需要 hover 才能编辑。默认收起只显星标+详情，空间更友好 */
.ops.always{opacity:1}
.col-check{width:34px;padding-left:12px!important}
.col-idx{width:44px;color:var(--text-3);font-variant-numeric:tabular-nums;font-size:12px}
.col-ops{width:1%;white-space:nowrap;text-align:right}
.ops{display:flex;gap:2px;justify-content:flex-end;opacity:0;transition:.13s}
tr:hover .ops{opacity:1}

/* ---------- 评论 / 星标 ---------- */
/* 有未确认评论 = 这里有事等着人去点头，所以整行打底色 + 左侧一道竖线。
   确认完这条 class 就没了，高亮自己熄灭，评论记录仍留在面板里。 */
tr.cmt-open>td{background:#FFFBEB}
tr.cmt-open>td:first-child{box-shadow:inset 3px 0 0 #F59E0B}
/* 星标行 = 重点项目/需求。刻意用冷色底把两种状态分开：
   暖琥珀 = 有人等你点头（待办，会熄灭）；淡紫 = 这条是重点（标记，跟需求走）。
   两种可以同时出现 —— 那时以琥珀为主（待办更要紧），左侧留一道双色条表示两个状态都在。 */
tr.star-row>td{background:#F6F7FF}
tr.star-row>td:first-child{box-shadow:inset 3px 0 0 #7C6BF2}
tr.star-row.cmt-open>td{background:#FFFBEB}
tr.star-row.cmt-open>td:first-child{box-shadow:inset 3px 0 0 #F59E0B, inset 8px 0 0 #7C6BF2}
/* 勾选是临时操作状态，视觉优先级高于行底色（否则星标行会把"已选中"盖掉） */
table.data tbody tr.sel>td{background:var(--primary-weak)}
/* 名称前的常驻状态标记（不进 cellview，点它不会变成改名称）。
   星标与评论标记本身是 button：点一下就能取消星标 / 拉起评论面板，
   不用专门去操作列找按钮。 */
.mk-star,.mk-cmt{display:inline-flex;align-items:center;gap:1px;margin-right:4px;vertical-align:-3px;
  border:0;background:none;padding:0;font:inherit;cursor:pointer}
.mk-star{color:#F59E0B}
/* 评论：有待确认的用暖棕（待办信号），全确认了退回中性灰（只剩"这里有记录"） */
.mk-cmt{color:var(--text-3);position:relative}
.mk-cmt.on{color:#B45309}
.mk-cmt .mk-n{background:var(--text-3)}
.mk-cmt.on .mk-n{background:#B45309}
.mk-star:hover,.mk-cmt:hover{filter:brightness(.9)}
.mk-star svg,.mk-cmt svg{width:14px;height:14px}
/* 「研发直承」标签：青色，刻意跟星标（琥珀=重点）和评论（棕=待确认）分开，
   三个可以同时出现，一眼能分辨这条是"要人去做的"还是"研发能直接接的" */
.mk-dev{display:inline-flex;align-items:center;margin-right:4px;vertical-align:1px;
  font-size:10.5px;line-height:1.5;padding:0 5px;border-radius:5px;white-space:nowrap;
  color:#0E7490;background:#E0F2FE;border:1px solid #BAE6FD;font-weight:600}
.mk-n{
  min-width:14px;height:14px;padding:0 3px;border-radius:7px;background:#B45309;color:#fff;
  font-size:10px;font-weight:700;line-height:14px;text-align:center;
}
/* 「延期」标签：红色系，跟星标/评论/研发直承都不同色 ——
   它是唯一的"负面状态"，红色才不会被当成中性标签扫过去。
   .clickable 表示可以点开做人工确认解除（只有需求池有），
   .locked 是客观记录（月报里的「上月延期」），点了不会有任何反应。 */
.mk-delay{display:inline-flex;align-items:center;margin-right:4px;vertical-align:1px;
  font-size:10.5px;line-height:1.5;padding:0 5px;border-radius:5px;white-space:nowrap;
  color:#B42318;background:#FEF3F2;border:1px solid #FECDCA;font-weight:600}
.mk-delay.clickable{cursor:pointer}
.mk-delay.clickable:hover{background:#FEE4E2;border-color:#FDA29B}
.mk-delay.locked{cursor:default;opacity:.92}
/* 延期没填原因：比"延期"本身更该被看见，加重一档 */
.mk-delay.miss{background:#B42318;border-color:#B42318;color:#fff}
.mk-delay.miss.clickable:hover{background:#912018;border-color:#912018}
.chip-miss{color:#B42318}
.chip-miss.on{background:#B42318;border-color:#B42318;color:#fff}
/* 操作列的按钮：有未确认评论时气泡常亮，不然跟着 .ops 一起 hover 才出现 */
.cmt-btn.on,.star-btn.on{color:#B45309}
.star-btn svg{width:16px;height:16px}
.cmt-btn{position:relative}
.cmt-btn .cmt-n{
  position:absolute;top:-3px;right:-3px;min-width:14px;height:14px;padding:0 3px;
  border-radius:7px;background:#B45309;color:#fff;font-size:10px;font-weight:700;line-height:14px;
}
.card .star-btn,.kb-card .star-btn{cursor:pointer;margin-right:5px;color:var(--text-3);vertical-align:-2px}
.card .star-btn.on,.kb-card .star-btn.on{color:#F59E0B}
/* 移动端卡片视图：跟表格行同样的两种底色（卡片就是窄屏下的"行"） */
.kb-card.starred{background:#FAFAFF;border-color:#C7C3F5}
.kb-card.hasopen{background:#FFFDF5;border-color:#F0D6A8}
.kb-card.starred.hasopen{background:#FFFDF5;box-shadow:inset 3px 0 0 #F59E0B, inset 7px 0 0 #7C6BF2}
.btn-cmt{color:var(--text-2)}
.btn-cmt.on{background:#FEF3C7;color:#B45309;border-color:#FCD34D}

/* 评论面板 */
.cmt-panel{min-width:0}
.cmt-row{padding:9px 11px;border:1px solid var(--line);border-radius:9px;margin-bottom:8px;background:var(--surface-2)}
.cmt-row.acked{background:var(--surface);border-color:var(--line)}
.cmt-top{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-bottom:5px}
.cmt-who{font-size:12.5px}
.cmt-top .muted{font-size:11.5px}
.cmt-ack{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;color:#15803D;font-weight:600}
.cmt-ack svg{width:13px;height:13px}
.cmt-tx{font-size:13.5px;line-height:1.7;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}
.cmt-ops{display:flex;gap:6px;align-items:center;margin-top:7px;flex-wrap:wrap}
.cmt-new{margin-top:12px;padding-top:11px;border-top:1px dashed var(--line-2)}
.cmt-new .input{width:100%;resize:vertical;line-height:1.6}
.cmt-new-ops{display:flex;align-items:center;gap:8px;margin-top:8px}

/* ---------- 交叉总表（业务线 × 目标进度 × 项目/需求） ---------- */
.cross-sheet{overflow:auto;max-height:560px;border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--surface)}
table.cross{border-collapse:separate;border-spacing:0;table-layout:auto;font-size:12.5px;min-width:100%}
table.cross th,table.cross td{
  padding:7px 11px;border-bottom:1px solid var(--line);border-right:1px solid var(--line);
  white-space:nowrap;text-align:center;font-weight:400;
}
table.cross thead{position:sticky;top:0;z-index:3}
table.cross thead th{
  background:var(--surface-2);color:var(--text-2);font-weight:600;font-size:12px;
  border-bottom:1px solid var(--line-2);
}
table.cross thead th.grp{font-weight:600;color:var(--text);border-left:1px solid var(--line-2)}
table.cross thead th.grp .muted{display:block;font-weight:400;font-size:11px;margin-top:1px}
table.cross thead th.tot{background:#EEF2FD;border-left:1px solid var(--line-2)}
table.cross thead th.sub-h{font-weight:400;font-size:11.5px;color:var(--text-2);padding:5px 11px}
table.cross thead th.sub-h.tot{background:#E7ECFB;color:var(--text);font-weight:600}
table.cross th.lh,table.cross td.lh{
  position:sticky;left:0;z-index:1;background:var(--surface);text-align:left;font-weight:600;
  border-right:1px solid var(--line-2);min-width:104px;
}
table.cross thead th.lh{z-index:4;background:var(--surface-2)}
table.cross tbody tr:hover td,table.cross tbody tr:hover th.lh{background:#FAFBFD}
table.cross td.num{text-align:right;font-variant-numeric:tabular-nums}
table.cross td.num.strong{font-weight:600}
table.cross td.num.zero{color:#C4CAD6}
table.cross td.sep{border-right:2px solid var(--line-2)}
/* 合计行置于表体首行（合计在前），视觉上作为「一级」；各业务线为二级明细 */
table.cross tbody tr.total-row th,table.cross tbody tr.total-row td{
  background:#EEF2FD;font-weight:650;border-bottom:1px solid var(--line-2);
}
table.cross tr.line-row th.lh{
  background:var(--surface-2);font-size:12px;color:var(--text-2);text-align:left;
}
table.cross th.lh.sub{font-weight:400;padding-left:20px;color:var(--text-2)}
.phone .ops,.app.is-compact .ops{opacity:1}

/* 单元格内联编辑 */
.cellview{border-radius:6px;padding:1px 4px;margin:-1px -4px;min-height:20px;display:block;transition:.12s;cursor:text;word-break:break-word}
.cellview:hover{background:var(--surface-3);box-shadow:inset 0 0 0 1px var(--line-2)}
.cellview.empty::after{content:"—";color:#C4CAD6}
.cellview.ro{cursor:default}
.cellview.ro:hover{background:transparent;box-shadow:none}
/* 「最新目标进度」格：点它拉起的是月份选择器（目标是按月承诺的），不是就地输入。
   所以光标与对齐都按"可点的格子"来 —— button 默认居中且光标是手型，
   沿用 .cellview 那套 text 光标会让人以为点进去就能直接打字。 */
.c-goal .goal-edit{text-align:left;width:100%}
.c-goal .goal-edit:not(.ro){cursor:pointer}
.cellinput{
  width:100%;min-width:90px;height:28px;padding:0 6px;border:1px solid var(--primary);border-radius:6px;
  outline:none;font-size:13px;box-shadow:0 0 0 3px var(--primary-weak);background:#fff;
}

/* 柔性日期：日历为主 + 手输兜底的一体控件。
   两个输入同时存在，靠 .is-text 切换显隐 —— 不用 JS 增删节点，
   两种模式下的内容都留在 DOM 里，来回切不丢字。 */
.df-wrap{display:flex;align-items:center;gap:5px;min-width:0;flex-wrap:nowrap}
.df-wrap .df-date{flex:1 1 auto;min-width:0}
.df-wrap .df-text{display:none;flex:1 1 auto;min-width:0;resize:vertical;line-height:1.4;font-family:inherit}
.df-wrap.is-text .df-date{display:none}
.df-wrap.is-text .df-text{display:block}
.df-tog{
  flex:0 0 auto;width:30px;height:30px;display:grid;place-items:center;
  border:1px solid var(--line);border-radius:8px;background:var(--surface-3);
  color:var(--text-3);transition:background .13s,color .13s,border-color .13s;
}
.df-tog:hover{background:var(--primary-weak);color:var(--primary);border-color:var(--primary)}
/* 图标跟模式走：日历模式下显示铅笔（去手输），手输模式下显示日历（回选择） */
.df-wrap .df-i-cal{display:none}
.df-wrap.is-text .df-i-edit{display:none}
.df-wrap.is-text .df-i-cal{display:inline}
.df-tog svg{width:14px;height:14px}
/* 内联编辑场景：控件要塞进单元格，跟着 .cellinput 的高度走，别撑破行高 */
td .df-wrap .df-date,td .df-wrap .df-text{
  height:28px;padding:0 6px;font-size:13px;border-radius:6px;
}
td .df-wrap .df-date{border:1px solid var(--primary);box-shadow:0 0 0 3px var(--primary-weak)}
td .df-tog{width:26px;height:28px}
textarea.cellinput{height:auto;min-height:70px;padding:6px;line-height:1.5;resize:vertical}
select.cellinput{height:28px}
.pnum{font-variant-numeric:tabular-nums;color:var(--text-2)}

/* ---------- 长文本 / 富文本（进度说明） ---------- */
/* 完整展示：不截断、保留换行；**加粗** / !!标红!! / ==加底色== 由 ui.rich 转成标签 */
.rich{
  white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;
  font-size:12.5px;line-height:1.68;color:var(--text-2);
}
.rich b{font-weight:700;color:var(--text)}
.mk-red{color:var(--danger);font-weight:600}
.mk-hl{
  background:#FFF3C4;border-radius:3px;padding:0 2px;color:var(--text);
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
}
td.rich-td{vertical-align:top}
td.c-note{max-width:440px}
.hint.rich{color:var(--text-2);margin-top:5px}
.info-box code{
  font-family:var(--mono);font-size:11.5px;background:var(--surface-3);
  padding:1px 4px;border-radius:4px;color:var(--text-2);
}

/* ---------- 富文本编辑工具条 ---------- */
.rt-wrap{display:block;width:100%;min-width:180px}
.rt-bar{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:6px}
.rt-btn{
  height:24px;min-width:26px;padding:0 8px;border:1px solid var(--line-2);border-radius:6px;
  background:var(--surface);color:var(--text-2);font-size:12px;font-weight:600;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;transition:.12s;
}
.rt-btn:hover{border-color:var(--primary);color:var(--primary);background:var(--primary-weak)}
.rt-btn.rt-b{font-family:Georgia,"Times New Roman",serif;font-weight:800;font-size:13px}
.rt-btn.rt-r{color:var(--danger)}
.rt-btn.rt-r:hover{border-color:var(--danger);color:var(--danger);background:var(--danger-weak)}
.rt-btn.rt-h{background:#FFF3C4;color:#8A6100}
.rt-btn.rt-h:hover{background:#FFE9A0;border-color:#E0B93C;color:#7A5200}
.rt-tip{font-size:11px;color:var(--text-3);flex:1 1 100%}
.rt-prev{
  margin-top:7px;padding:7px 9px;border:1px dashed var(--line-2);border-radius:8px;
  background:var(--surface-2);
  white-space:pre-wrap;overflow-wrap:anywhere;
}
.rt-prev .muted{font-size:12px}
/* AI 总结的小节标题（「## 标题」渲染结果）。必须保持 inline：
   外层是 white-space:pre-wrap，换行由原文的 \n 提供，块级元素会再多空一行 */
.mk-h2{font-weight:800;font-size:1.06em;color:var(--text);letter-spacing:.2px}
@media (max-width:720px){
  td.c-note{max-width:none}
  .rt-tip{display:none}
}

/* ---------- 徽标 ---------- */
.badge{display:inline-flex;align-items:center;gap:4px;height:21px;padding:0 7px;border-radius:6px;font-size:11.5px;font-weight:600;white-space:nowrap;line-height:1}
.b-cat-project{background:#E9ECFD;color:#3B4DD8}
.b-cat-need{background:#E2F3F6;color:#0E7490}
.b-line{background:var(--surface-3);color:var(--text-2);font-weight:600;font-family:var(--mono);font-size:11px}
.b-width{background:#F1EAFE;color:#6D28D9}
.b-pri{background:#FFF3E0;color:#B45309;font-family:var(--mono)}
.b-soft{background:var(--surface-3);color:var(--text-2);font-weight:500}
.b-warn{background:#FEF3C7;color:#B45309}
.st{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:500;white-space:nowrap}
.st::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:0 0 auto}
.st-已上线{color:#0F7B5A}
.st-开发中{color:#2B5CE6}
.st-产品方案中{color:#7C3AED}
.st-已评审待排期{color:#B45309}
.st-待进产品方案{color:#0369A1}
.st-已受理待排产品{color:#0E7490}
.st-待业务需求评审{color:#C2410C}
.st-待受理{color:#6B7280}
.st-暂停{color:#B91C1C}
.g-9月已上线,.g-已上线{--gc:#0F7B5A}
.g-完成上线{--gc:#0E9F6E}
.g-进入开发{--gc:#2B5CE6}
.g-完成需求{--gc:#4F46E5}
.g-产品方案中{--gc:#7C3AED}
.g-暂无法介入{--gc:#8A92A4}
.g-待业务需求评审{--gc:#C2410C}

/* ---------- 月报分组 ---------- */
.group{border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--surface);overflow:hidden}
.group+.group{margin-top:12px}
.group-head{display:flex;align-items:center;gap:10px;padding:11px 14px 11px 12px;cursor:pointer;user-select:none;background:var(--surface)}
.group-head:hover{background:var(--surface-2)}
.group-bar{width:4px;height:18px;border-radius:3px;background:var(--gc,var(--primary));flex:0 0 auto}
.group-title{font-size:13.5px;font-weight:600}
.group-count{font-size:12px;color:var(--text-3);font-variant-numeric:tabular-nums}
.group-head .right{margin-left:auto;display:flex;align-items:center;gap:8px}
.group-body{border-top:1px solid var(--line)}
.caret{transition:transform .18s;color:var(--text-3)}
.group.closed .caret{transform:rotate(-90deg)}
.group.closed .group-body{display:none}

/* ---------- 看板 ---------- */
.kanban{display:grid;grid-auto-flow:column;grid-auto-columns:290px;gap:12px;overflow-x:auto;padding-bottom:8px}
.kb-col{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-lg);display:flex;flex-direction:column;max-height:calc(100vh - 250px)}
.kb-head{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--line);font-size:13px;font-weight:600}
.kb-head .group-count{margin-left:auto}
.kb-body{padding:10px;display:flex;flex-direction:column;gap:8px;overflow:auto}
.kb-card{background:var(--surface);border:1px solid var(--line);border-radius:10px;padding:10px 11px;box-shadow:var(--shadow-1);cursor:grab;position:relative}
/* 卡片右上角的操作：星标 + 详情。看板没有操作列，星标只能放这里；
   整卡仍可点开详情，但点这两个按钮不算（委托里已排除 button）。 */
.kb-ops{position:absolute;top:5px;right:5px;display:flex;gap:1px;padding:1px;
  border-radius:7px;background:var(--surface);box-shadow:0 0 0 1px var(--line);
  opacity:0;transition:.13s}
.kb-card:hover .kb-ops{opacity:1}
/* 卡片窄，右上角按纽组收窄到 24px，别糊掉半张卡 */
.kb-ops .icon-btn{width:24px;height:24px;border-radius:6px}
.kb-ops .icon-btn svg{width:14px;height:14px}
.kb-ops .star-btn{margin-right:0;vertical-align:0}
.kb-card.dragging{opacity:.4}
.kb-col.kb-drop{outline:2px dashed var(--primary);outline-offset:-3px;background:var(--primary-weak)}
.kb-card:hover{border-color:#C4CBD7;box-shadow:var(--shadow-2)}
.kb-card .t{font-size:13px;font-weight:500;line-height:1.45}
.kb-card .m{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:7px}
/* 卡片上的「最新目标进度」：看板按状态分列，卡片上缺的正是"它答应走到哪一步"。
   做法是"标签 + 可点的阶段徽标"，徽标配色沿用详情头部那颗，跟"这是个阶段值"对上。 */
.kb-goal-l{font-size:11.5px;color:var(--text-3)}
.kb-card .kb-goal{cursor:pointer}
.kb-card .kb-goal:hover{filter:brightness(.95);box-shadow:0 0 0 2px #E4D9FB}
.kb-empty{border:1px dashed var(--line-2);border-radius:10px;padding:16px;text-align:center;color:var(--text-3);font-size:12px}

/* ---------- 抽屉 ---------- */
.drawer-mask{position:fixed;inset:0;background:rgba(16,24,40,.34);z-index:80;opacity:0;pointer-events:none;transition:opacity .2s}
.drawer-mask.on{opacity:1;pointer-events:auto}
.drawer{
  position:fixed;top:0;right:0;height:100%;width:min(560px,94vw);background:var(--surface);z-index:81;
  transform:translateX(102%);transition:transform .26s cubic-bezier(.3,.8,.3,1);display:flex;flex-direction:column;
  box-shadow:var(--shadow-3);
}
.drawer.on{transform:none}
.drawer-head{display:flex;align-items:flex-start;gap:12px;padding:16px 18px;border-bottom:1px solid var(--line)}
.drawer-head .right{margin-left:auto;display:flex;gap:6px}
.drawer-body{flex:1;overflow:auto;padding:16px 18px 40px}
.drawer-foot{border-top:1px solid var(--line);padding:11px 18px;display:flex;gap:8px;justify-content:flex-end;background:var(--surface-2)}
body.phone-preview .drawer{position:absolute}
.app.is-compact .drawer{width:100vw}

.kv{display:grid;grid-template-columns:132px 1fr;gap:7px 12px;font-size:13px;align-items:start}
.kv dt{color:var(--text-3);font-size:12.5px;padding-top:1px}
.kv dd{margin:0;word-break:break-word;white-space:pre-wrap}

/* ---------- 弹窗 ---------- */
.modal{position:fixed;inset:0;z-index:90;display:none;place-items:center;padding:20px}
.modal.on{display:grid}
.modal-mask{position:absolute;inset:0;background:rgba(16,24,40,.38)}
.modal-box{
  position:relative;background:var(--surface);border-radius:16px;width:min(680px,96vw);max-height:88vh;
  display:flex;flex-direction:column;box-shadow:var(--shadow-3);animation:pop .18s cubic-bezier(.2,.9,.3,1);
}
@keyframes pop{from{opacity:0;transform:translateY(8px) scale(.985)}}
.modal-box.wide{width:min(1080px,96vw)}
.modal-head{display:flex;align-items:center;gap:10px;padding:15px 18px;border-bottom:1px solid var(--line)}
.modal-title{font-size:15px;font-weight:600}
.modal-head .right{margin-left:auto}
.modal-body{flex:1;overflow:auto;padding:18px}
.modal-foot{padding:12px 18px;border-top:1px solid var(--line);display:flex;gap:8px;justify-content:flex-end;background:var(--surface-2);border-radius:0 0 16px 16px}
body.phone-preview .modal{position:absolute}

/* ---------- 提示 ---------- */
.toast-root{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);z-index:120;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{background:#111827;color:#fff;padding:9px 15px;border-radius:10px;font-size:13px;box-shadow:var(--shadow-2);animation:up .2s;max-width:80vw}
.toast.ok{background:#0F7B5A}.toast.err{background:#C8362F}
@keyframes up{from{opacity:0;transform:translateY(8px)}}
.empty-state{text-align:center;padding:46px 20px;color:var(--text-3)}
.empty-state svg{width:40px;height:40px;opacity:.4;margin-bottom:10px}
.empty-state .t{font-size:14px;color:var(--text-2);font-weight:500;margin-bottom:4px}

/* ---------- AI 区块 ---------- */
.ai-card{border:1px solid #DCE4FB;background:linear-gradient(180deg,#F7F9FF,#fff);border-radius:var(--radius-lg);padding:14px 16px}
.ai-card+.ai-card{margin-top:12px}
.ai-head{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.ai-head .dot{width:20px;height:20px;border-radius:6px;background:linear-gradient(140deg,#6C8DFF,#2B5CE6);display:grid;place-items:center}
.ai-head .dot svg{width:12px;height:12px;color:#fff}
.ai-title{font-size:13px;font-weight:600}
.ai-head .right{margin-left:auto;display:flex;gap:6px}
/* 查看模式：总结全文完整铺开，不截断、不滚动 */
.ai-body{
  font-size:13.5px;line-height:1.85;color:#2B3242;
  white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;
}
.ai-body .muted{font-size:13px}
.ai-ph{color:var(--text-3);font-size:13px}
.typing::after{content:"▍";animation:blink 1s steps(2) infinite;color:var(--primary)}
@keyframes blink{50%{opacity:0}}

/* ---------- 数据看板 ---------- */
.stat-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:1px;background:var(--line);border-radius:var(--radius);overflow:hidden;border:1px solid var(--line)}
.stat-cell{background:var(--surface);padding:12px 14px}
.stat-cell .v{font-size:20px;font-weight:650;font-variant-numeric:tabular-nums;letter-spacing:-.3px}
.stat-cell .l{font-size:11.5px;color:var(--text-3);margin-top:2px}
.diff-add{color:var(--ok);font-weight:600}
.diff-del{color:var(--danger);font-weight:600}
.diff-chg{color:var(--warn);font-weight:600}

/* ---------- 导入 ---------- */
.drop{
  border:1.5px dashed var(--line-2);border-radius:var(--radius-lg);padding:34px 20px;text-align:center;
  background:var(--surface);transition:.16s;cursor:pointer;
}
.drop:hover,.drop.over{border-color:var(--primary);background:var(--primary-weak)}
.drop svg{width:32px;height:32px;color:var(--primary);margin-bottom:8px}
.drop .t{font-size:14px;font-weight:600;margin-bottom:4px}
.map-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px}
.map-item{display:grid;grid-template-columns:1fr auto;gap:6px;align-items:center;background:var(--surface-2);border:1px solid var(--line);border-radius:9px;padding:8px 10px}
.map-item .src{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.map-item .tgt{grid-column:1/-1}
.review-row{display:flex;align-items:center;gap:8px;padding:9px 2px;border-bottom:1px solid var(--line)}
.review-row:last-child{border-bottom:none}
.review-row .t{flex:1;min-width:0}
.review-row .t .n{font-size:13px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.review-row .t .d{font-size:11.5px;color:var(--text-3);margin-top:2px;display:flex;gap:8px;flex-wrap:wrap}

/* 归属：这条到底是在更新哪一条已有需求（认错了要能一眼看出来、一键换掉） */
.rev-match{font-size:11.5px;color:var(--text-3);margin-top:3px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.rev-match b{font-weight:500;color:var(--text-2)}
.rv-score{font-size:11px;font-variant-numeric:tabular-nums;color:var(--text-3);
  background:var(--surface-2);border-radius:4px;padding:0 5px}
.rv-score.weak{background:#FFF4E0;color:#8A6412}
.rv-score.on{background:var(--primary-weak);color:#22409B}
.rv-bind{border:1px solid var(--line);border-radius:9px;margin:2px 0 8px;padding:8px 10px;background:var(--surface-2)}
.rv-bind-top{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.rv-bind-list{max-height:220px;overflow:auto}
.rv-bind-item{display:flex;align-items:center;gap:10px;padding:5px 6px;border-radius:7px;cursor:pointer;font-size:12.5px}
.rv-bind-item:hover{background:var(--surface-3)}
.rv-bind-item.on{background:var(--primary-weak)}
.rv-bind-item .n{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rv-bind-item .muted{flex:0 0 auto;font-size:11.5px}

/* ---------- 变更记录 ---------- */
.chg{display:grid;grid-template-columns:120px 1fr;gap:6px 12px;font-size:13px;padding:10px 2px;border-bottom:1px solid var(--line)}
.chg .when{color:var(--text-3);font-size:12px;font-variant-numeric:tabular-nums}
.chg .what b{font-weight:600}
.chg .vals{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:3px;font-size:12.5px}
.oldv{color:var(--text-3);text-decoration:line-through;max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.newv{color:var(--text);background:#FFF7E0;border-radius:4px;padding:0 4px;max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.arrow{color:var(--text-3)}

/* ---------- 权限 ---------- */
.ro-banner{display:flex;align-items:center;gap:8px;background:#FFF8E8;border:1px solid #F3E0B5;color:#8A6412;border-radius:10px;padding:9px 13px;font-size:12.5px;margin-bottom:12px}
.ro-banner svg{width:15px;height:15px;flex:0 0 auto}
.lock{color:#C9A24A;display:inline-flex;vertical-align:-1px}
.lock svg{width:12px;height:12px}

/* ---------- 杂项 ---------- */
.row{display:flex;align-items:center;gap:8px}
.row.wrap{flex-wrap:wrap}
.spacer{flex:1}
.muted{color:var(--text-3)}
.small{font-size:12px}
.tnum{font-variant-numeric:tabular-nums}
.divider{height:1px;background:var(--line);margin:14px 0}
.checkbox{width:15px;height:15px;border-radius:4px;border:1.5px solid var(--line-2);background:#fff;display:grid;place-items:center;cursor:pointer;flex:0 0 auto}
.checkbox.on{background:var(--primary);border-color:var(--primary)}
.checkbox svg{width:11px;height:11px;color:#fff;display:none}
.checkbox.on svg{display:block}
.switch{width:38px;height:22px;border-radius:20px;background:#CFD5E0;position:relative;transition:.16s;flex:0 0 auto}
.switch::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;transition:.16s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.switch.on{background:var(--primary)}
.switch.on::after{left:18px}
.hidden{display:none!important}
.tag-dot{width:7px;height:7px;border-radius:50%;flex:0 0 auto}
.scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}
.nowrap{white-space:nowrap}
.warn-box{background:var(--danger-weak);border:1px solid #F0D6D4;color:#8E2A24;border-radius:10px;padding:10px 13px;font-size:12.5px;line-height:1.65}
.info-box{background:var(--primary-weak);border:1px solid #D3DEFB;color:#22409B;border-radius:10px;padding:10px 13px;font-size:12.5px;line-height:1.65}
.mono{font-family:var(--mono);font-size:12px}

/* ---------- 多选筛选（复选） ---------- */
.msel{position:relative;display:inline-flex}
.msel-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 10px;border:1px solid var(--line-2);
  background:var(--surface);color:var(--text);border-radius:8px;font-size:13px;cursor:pointer;white-space:nowrap}
.msel-btn:hover{border-color:var(--primary);color:var(--primary)}
.msel.on .msel-btn{border-color:var(--primary);background:var(--primary-weak);color:#22409B;font-weight:600}
.msel-caret{display:inline-flex;color:var(--text-3)}
.msel-caret svg{width:13px;height:13px}
.msel.open .msel-caret{transform:rotate(180deg)}
/* 筛选按钮常驻压在遮罩之上：面板打开时能直接点另一个筛选器切换过去，
   不必先关再开。总池现在有六个筛选器，来回开关很烦。
   z 62 刻意低于抽屉(80)/弹窗(90)/提示(120)，不会盖住它们。 */
.msel-btn{position:relative;z-index:62}
.msel-n{background:var(--primary);color:#fff;border-radius:9px;font-size:11px;line-height:15px;min-width:15px;
  height:15px;padding:0 4px;text-align:center;font-weight:600}
.msel-backdrop{position:fixed;inset:0;z-index:60}
.msel-pop{position:absolute;top:calc(100% + 6px);left:0;z-index:61;min-width:238px;max-width:320px;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-2);padding:8px;display:block}
.msel-tools{display:flex;align-items:center;gap:6px;padding:2px 4px 8px;border-bottom:1px solid var(--line);margin-bottom:6px}
.msel-tip{margin-left:auto;font-size:11.5px;color:var(--text-3)}
.msel-list{display:block;max-height:264px;overflow:auto}
.msel-item{display:flex;align-items:center;gap:8px;padding:6px 6px;border-radius:8px;cursor:pointer;font-size:13px}
.msel-item:hover{background:var(--surface-2)}
.msel-item.on{background:var(--primary-weak)}
.msel-opt{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msel-opt-n{font-size:11.5px;color:var(--text-3);font-variant-numeric:tabular-nums}
/* 该选项在当前其他筛选下为 0 条 */
.msel-opt-n.zero{opacity:.45}
.msel-item:hover .msel-opt-n.zero{opacity:.8}
@media (max-width:720px){
  .msel-btn{height:30px;font-size:12.5px}
  /* 底部抽屉模式下，按钮不再需要压在遮罩上，否则会浮在抽屉上面。
     这里要连 .msel.open 一起覆盖，否则上面那条特异性更高的规则会把按钮又提起来。 */
  .msel-btn,.msel.open .msel-btn{position:relative;z-index:auto}
  /* 手机上改成底部抽屉，避免面板超出屏幕右边 */
  .msel-pop{position:fixed;left:0;right:0;bottom:0;top:auto;min-width:0;max-width:none;
    border-radius:16px 16px 0 0;max-height:72vh;padding:12px 12px calc(12px + env(safe-area-inset-bottom));
    box-shadow:var(--shadow-3)}
  .msel-list{max-height:52vh}
  .msel-item{padding:11px 8px;font-size:14.5px}
  .msel-tools{padding-bottom:10px;margin-bottom:8px}
}

/* ---------- 月度目标进度（详情抽屉 / 所属月报选择器） ---------- */
/* 一排一期的写法是刻意的：目标与实际是同一个承诺的两半，拆成两行看不出"差多少"，
   放在一行并排才是一眼能读的对比。 */
.mp-edit{display:flex;flex-direction:column;gap:6px}
.mp-item{padding:7px 9px;border:1px solid var(--line);border-radius:10px;background:var(--surface-2)}
.mp-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
/* 从列表「最新目标进度」点进来时定位的那一期：勾出来告诉用户"改的就是这一期"。
   月份一长串，不给视觉锚点的话他要自己在里面找一遍。 */
.mp-row.focus{border-radius:9px;box-shadow:inset 0 0 0 2px #BBD5FF;background:var(--primary-weak)}
.mp-list{max-height:min(56vh,460px);overflow:auto}
/* 复选框与月份名是"勾/不勾"的点击区，给手型光标点明可点；
   下拉框不用 —— 它是改值的，跟勾选是两件事 */
.mp-row .checkbox,.mp-row .msel-opt,.mp-row .mchip{cursor:pointer}
/* 未勾选的那一期整体压暗：它现在不属于任何月报，值只是"暂存的草稿"，
   选了目标/实际会自动勾上（那时恢复全亮），不用先勾再选两步走 */
.mp-row:not(.on) .msel-opt,.mp-row:not(.on) .mp-goal{opacity:.55}
.mp-row:not(.on):hover .msel-opt,.mp-row:not(.on):hover .mp-goal{opacity:.85}
/* 月份标签要完整读出（2026年9月），不吃 msel-opt 那套省略号 —— 省略掉年份就没法对期 */
.mp-row .msel-opt{flex:0 0 auto;min-width:70px;overflow:visible;text-overflow:clip;
  font-weight:600;color:var(--text);white-space:nowrap}
.mp-goal{display:inline-flex;align-items:center;gap:5px;font-size:12.5px;
  color:var(--text-3);white-space:nowrap}
.mp-goal .select{height:28px;padding:0 24px 0 8px;font-size:12.5px}
.mp-badge:empty{display:none}
/* 已锁：实际进度被人工校准过，不再跟着目标走 —— 给个明确的静态标记，
   免得有人改了目标发现实际不动，以为是 bug。 */
.mp-lock{font-size:10.5px;line-height:1.5;padding:0 5px;border-radius:5px;border:1px solid var(--line-2);
  color:var(--text-3);background:var(--surface);white-space:nowrap}
.mp-delay{font-size:10.5px;font-weight:600;color:#B42318;background:#FEF3F2;border:1px solid #FECDCA;
  padding:0 5px;border-radius:5px;line-height:1.5;white-space:nowrap}
.mp-reason{display:flex;align-items:center;gap:8px;margin-top:6px;padding-left:4px}
.mp-reason-l{flex:0 0 auto;font-size:12px;color:#B42318;font-weight:600;white-space:nowrap}
.mp-reason .input{flex:1;height:28px;font-size:12.5px}
.mp-hint{font-size:12px;color:var(--text-3);margin-top:2px}

/* ---------- 复盘里的折叠清单（已上线 / 计划上线-开发中 / 延期） ---------- */
.rv-fold{border:1px solid var(--line);border-radius:10px;margin-top:8px;overflow:hidden}
.rv-head{display:flex;align-items:center;gap:8px;padding:8px 11px;cursor:pointer;
  background:var(--surface-2);font-size:13px}
.rv-head:hover{background:var(--surface-3)}
.rv-caret{display:inline-flex;color:var(--text-3)}
.rv-caret svg{width:14px;height:14px}
.rv-n{font-size:12px;color:var(--text-3);font-variant-numeric:tabular-nums}
/* 延期原因：填了正常显示，没填标红并做成补录入口 */
.rv-reason{font-size:12px;color:var(--text-2)}
.rv-reason.miss{color:#B42318;font-weight:600}
.rv-reason.miss.clickable{cursor:pointer;border-bottom:1px dashed #FDA29B}
.rv-reason.miss.clickable:hover{background:#FEF3F2}
.rv-search{margin-left:auto;width:200px;height:26px;font-size:12.5px}
.rv-body{padding:6px 8px;max-height:330px;overflow:auto}
.rv-row{display:flex;align-items:center;gap:10px;padding:5px 6px;border-radius:7px}
.rv-row:hover{background:var(--surface-2)}
.rv-row[hidden]{display:none}
.rv-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}
.rv-meta{flex:0 0 58px;font-size:12px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 右侧是"差在哪 / 为什么"：这列才是复盘的痛点，所以给它留最多宽度 */
.rv-ex{flex:0 1 auto;max-width:46%;font-size:12px;color:var(--text-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---------- 登录门禁 ---------- */
.app.is-locked{filter:blur(2px);pointer-events:none;user-select:none}
.login-root[hidden]{display:none}
.login-root{
  position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;
  padding:24px;background:radial-gradient(900px 520px at 22% 12%,#E9EFFB 0%,#E2E8F3 45%,#D9E0EC 100%);
}
.login-card{
  width:100%;max-width:392px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-3);padding:28px 26px 22px;
}
.login-brand{display:flex;align-items:center;gap:12px;margin-bottom:22px}
.login-mark{
  width:40px;height:40px;border-radius:11px;background:var(--primary);flex:none;
  display:flex;align-items:center;justify-content:center;box-shadow:0 6px 16px rgba(43,92,230,.28);
}
.login-mark svg{width:22px;height:22px}
.login-title{font-size:17px;font-weight:600;letter-spacing:.2px}
.login-sub{font-size:12.5px;color:var(--text-3)}
.login-label{display:block;font-size:12.5px;color:var(--text-2);margin:0 0 5px;font-weight:500}
.login-label:not(:first-child){margin-top:13px}
.login-btn{width:100%;margin-top:20px;height:40px;justify-content:center}
.login-err{
  margin-top:12px;padding:9px 11px;border-radius:9px;background:var(--danger-weak);
  color:var(--danger);font-size:12.5px;border:1px solid rgba(200,54,47,.18);
}
.login-foot{margin-top:18px;padding-top:14px;border-top:1px solid var(--line);font-size:12px;color:var(--text-3);line-height:1.6}
@media (max-width:520px){
  .login-card{padding:22px 18px 18px}
  .login-root{align-items:flex-start;padding-top:52px}
}

/* ---------------------------------------------------------------- AI 录入：附件列表 */
.att-list{margin-top:10px;display:flex;flex-direction:column;gap:6px}
.att-item{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:8px 10px;border:1px solid var(--line);border-radius:9px;background:var(--surface-2);
}
.att-kind{
  flex:none;font-size:10.5px;font-weight:600;line-height:1.5;padding:1px 6px;border-radius:5px;
  color:var(--text-2);background:var(--surface);border:1px solid var(--line);
}
.att-name{flex:1 1 auto;min-width:0;font-size:12.5px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.att-err{flex:1 1 100%;font-size:12px;color:var(--danger);line-height:1.5}


/* ---------------------------------------- 重排优先级面板（可拖动的独立界面） */
.rp-tip{margin-bottom:12px;padding:8px 11px;border:1px solid var(--line);border-radius:9px;background:var(--surface-2);line-height:1.7}
.rp-board{border:1px solid var(--line);border-radius:10px;overflow:hidden}
.rp-grp+.rp-grp{border-top:1px solid var(--line)}
.rp-grp-hd{
  padding:5px 12px;font-size:12px;font-weight:700;color:var(--text-2);
  background:var(--surface-2);border-bottom:1px solid var(--line);
}
.rp-row{
  display:flex;align-items:center;gap:10px;padding:5px 12px;border-bottom:1px solid var(--line);
  background:var(--surface);
}
.rp-row:last-child{border-bottom:0}
.rp-row:hover{background:var(--surface-2)}
.rp-row.dragging{opacity:.35}
.rp-row.dropbefore{border-top:2px solid var(--primary)}
.rp-row.dropafter{border-bottom:2px solid var(--primary)}
.rp-no{
  flex:none;width:38px;text-align:right;font-size:12.5px;font-variant-numeric:tabular-nums;color:var(--text);
}
.rp-no b{font-size:13.5px;color:var(--primary)}
.rp-keep{font-size:11.5px;color:var(--text-3)}
.rp-name{flex:1 1 auto;min-width:0;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-meta{flex:none;max-width:30%;font-size:11.5px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rp-old{flex:none;font-size:11.5px;color:var(--text-3)}
.rp-old.chg{color:var(--warn);font-weight:600}
