:root {
  --blue: #2f6fed;
  --blue-d: #2456c4;
  --bg: #f4f6fb;
  --panel: #ffffff;
  --border: #e3e8f0;
  --text: #1f2733;
  /* D13 a11y：原 #6b7488 在 --bg(#f4f6fb) 上仅 4.34:1，未达 WCAG AA 4.5:1；
     #626b80 实测 4.94:1（白底 5.34:1），在保持"弱化文字"观感的前提下达标 */
  --muted: #626b80;
  --green: #1f9d55;
  --red: #d8453a;
  --amber: #d98a00;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
body { margin: 0; font-family: -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; background: var(--bg); color: var(--text); font-size: 14px; }
h1, h2, h3 { margin: 0 0 8px; }
.sub, .hint { color: var(--muted); font-size: 13px; }
.err { color: var(--red); min-height: 18px; margin: 6px 0; }

/* 登录 */
.login-mask { position: fixed; inset: 0; display: flex; z-index: 100; background: linear-gradient(135deg, #e9eefc 0%, #f4f6fb 60%, #e8eef8 100%); background-size: cover; background-position: center; background-repeat: no-repeat; }
.login-mask.has-bg { background-color: #f4f6fb; }

/* 启动遮罩：会话校验期间覆盖全屏，避免登录页闪现 */
.boot-mask {
  position: fixed; inset: 0; z-index: 99998;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; background: #f4f6f9; color: #495057;
}
.boot-spinner {
  width: 38px; height: 38px; border-radius: 50%;
  border: 4px solid #dee2e6; border-top-color: #4dabf7;
  animation: boot-spin .8s linear infinite;
}
.boot-text { font-size: 14px; letter-spacing: .04em; }
@keyframes boot-spin { to { transform: rotate(360deg); } }
.login-hero { flex: 1 1 0; min-width: 0; display: flex; align-items: center; justify-content: center; background: transparent; position: relative; overflow: hidden; }
.login-hero::before { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 70% 60%, rgba(47,111,237,.08) 0%, transparent 55%); pointer-events: none; }
.login-mask.has-bg .login-hero::before { background: rgba(255,255,255,.06); }
.login-hero-content { position: relative; text-align: center; padding: 40px; max-width: 620px; }
.login-hero-tag { display: inline-block; padding: 6px 16px; border-radius: 999px; background: rgba(47,111,237,.10); color: var(--blue-d); font-size: 14px; font-weight: 600; margin-bottom: 22px; }
.login-hero h1 { font-size: 56px; line-height: 1.18; color: var(--text); font-weight: 700; letter-spacing: -1px; margin-bottom: 18px; }
.login-hero-sub { font-size: 18px; color: var(--muted); margin: 0; }
.login-panel { flex: 0 0 520px; max-width: 45vw; display: flex; flex-direction: column; align-items: center; justify-content: center; background: rgba(255,255,255,0.30); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); padding: 40px; box-shadow: -10px 0 40px rgba(0,0,0,.12); border-left: 1px solid rgba(255,255,255,0.25); }
.login-title-panel { width: 100%; max-width: 400px; margin-bottom: 22px; text-align: center; font-size: clamp(30px, 5vw, 54px); font-weight: 800; color: var(--text); line-height: 1.15; letter-spacing: -1px; text-shadow: 0 1px 2px rgba(255,255,255,0.6); transform: translateY(-56px); }
.login-card { width: 100%; max-width: 400px; }
.login-card h2 { font-size: 28px; color: var(--text); font-weight: 700; margin-bottom: 6px; text-shadow: 0 1px 2px rgba(255,255,255,0.6); }
.login-card .sub { font-size: 14px; color: var(--text); margin-bottom: 28px; text-shadow: 0 1px 2px rgba(255,255,255,0.6); }
.login-card label { display: block; margin: 18px 0 6px; color: var(--text); font-size: 13px; font-weight: 500; text-shadow: 0 1px 2px rgba(255,255,255,0.6); }
.login-card input { position: relative; width: 100%; padding: 12px 14px; border: 1px solid rgba(255,255,255,0.35); border-radius: 10px; z-index: 102; background: rgba(255,255,255,0.55); font-size: 15px; }
.login-card input.pwd { -webkit-text-security: disc; text-security: disc; }
.login-card input:-webkit-autofill,
.login-card input:-webkit-autofill:focus { box-shadow: 0 0 0 1000px rgba(255,255,255,0.55) inset; -webkit-text-fill-color: var(--text); }
.login-card button[type="submit"] { width: 100%; margin-top: 28px; padding: 13px; border: 0; border-radius: 10px; background: var(--blue); color: #fff; font-size: 16px; font-weight: 600; cursor: pointer; }
.login-card button[type="submit"]:hover { background: var(--blue-d); }
.remember-row { display: flex; align-items: center; gap: 8px; margin-top: 14px; cursor: pointer; font-size: 13px; color: var(--text); }
.remember-row input { width: auto; margin: 0; }
.login-links { display: flex; justify-content: space-between; margin-top: 18px; }
.login-links .link { width: auto; margin: 0; padding: 0; background: none; color: var(--blue); font-size: 13px; text-decoration: underline; border: none; cursor: pointer; }
.login-links .link:hover { color: var(--blue-d); background: none; }
@media (max-width: 900px) {
  .login-hero { display: none; }
  .login-panel { flex: 1 1 0; max-width: none; }
}
.login-setting { max-width: 520px; }
.login-setting label { display: block; margin: 8px 0 6px; color: var(--muted); font-size: 13px; }
.login-setting input[type="file"] { padding: 8px 0; }
.login-bg-preview { width: 100%; height: 180px; margin: 12px 0; border: 1px dashed var(--border); border-radius: 10px; background: #f4f6fb; background-size: cover; background-position: center; background-repeat: no-repeat; display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 13px; }
.login-bg-preview:empty::before { content: '暂无背景预览'; }

/* 布局 */
.topbar { display: flex; align-items: center; justify-content: space-between; padding: 12px 22px; background: #fff; border-bottom: 1px solid var(--border); }
.brand { font-weight: 700; font-size: 16px; color: var(--blue-d); }
.brand-logo { width: 22px; height: 22px; object-fit: contain; vertical-align: -4px; margin-right: 6px; }
.login-logo { display: block; width: 64px; height: 64px; object-fit: contain; margin: 0 auto 10px; }
.logo-preview { width: 180px; height: 180px; margin: 12px 0; border: 1px dashed var(--border); border-radius: 10px; background: #f4f6fb center/contain no-repeat; display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 13px; }
.logo-preview:empty::before { content: '暂无 LOGO 预览'; }
.topbar-right { display: flex; align-items: center; gap: 14px; }
.proj-select { color: var(--muted); font-size: 13px; }
.proj-select select { margin-left: 6px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; }
.user { color: var(--text); font-weight: 600; }

.tabs { display: flex; gap: 4px; padding: 0 22px; background: #fff; border-bottom: 1px solid var(--border); }
.tab { padding: 12px 18px; border: 0; background: none; cursor: pointer; color: var(--muted); font-size: 14px; border-bottom: 2px solid transparent; }
.tab.active { color: var(--blue); border-bottom-color: var(--blue); font-weight: 600; }

/* 全局满屏布局：消除 body 纵向滚动条，解决滚轮在表格外空白区冒泡导致整页上下移动（需求管理页最明显） */
#app { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
.topbar, .tabs { flex: 0 0 auto; }
main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 20px 22px; overflow: auto; }
.view { animation: fade .2s; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.panel { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 16px 18px; margin-bottom: 18px; }
.panel-row { display: flex; flex-wrap: wrap; gap: 18px; align-items: stretch; }
.panel-row > .panel { flex: 1 1 360px; min-width: 0; margin-bottom: 18px; }
.panel-row .login-setting { max-width: none; }
.panel h3 { font-size: 15px; }

.toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.toolbar input, .toolbar select { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; }
.filter-label { font-size: 13px; color: var(--muted); white-space: nowrap; }

.subtabs { display: flex; gap: 6px; background: #eef1f6; padding: 4px; border-radius: 10px; flex-wrap: wrap; }
.subtab { padding: 7px 16px; border: 0; background: transparent; cursor: pointer; color: var(--muted); font-size: 13px; border-radius: 7px; }
.subtab.active { background: #fff; color: var(--blue); font-weight: 600; box-shadow: 0 1px 3px rgba(0,0,0,.08); }

.form-row { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 6px; }
.form-row label { display: flex; flex-direction: column; gap: 4px; color: var(--muted); font-size: 12px; }
.form-row input, .form-row select { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; min-width: 140px; }
/* 类型联动置灰字段 */
input:disabled, select:disabled, textarea:disabled { background: #f1f3f7; color: #9aa3b2; cursor: not-allowed; opacity: 1; }
.disabled { background: #f1f3f7 !important; color: #9aa3b2 !important; cursor: not-allowed; }

button { font-family: inherit; }
.btn-primary { background: var(--blue); color: #fff; border: 0; border-radius: 8px; padding: 8px 16px; cursor: pointer; }
.btn-primary:hover { background: var(--blue-d); }
.btn-ghost { background: #fff; color: var(--blue); border: 1px solid var(--blue); border-radius: 8px; padding: 8px 14px; cursor: pointer; }
.btn-ghost:hover { background: #eef3ff; }
.btn-danger { background: #fff; color: var(--red); border: 1px solid var(--red); border-radius: 8px; padding: 5px 10px; cursor: pointer; }
.btn-danger-ghost { background: #fff; color: var(--red); border: 1px solid var(--red); border-radius: 8px; padding: 8px 14px; cursor: pointer; }
.btn-danger-ghost:hover { background: #fdecea; }
/* 资源清理 */
.rm-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.rm-header h3 { margin: 0; font-size: 18px; }
.rm-header-tip { font-size: 12px; color: var(--muted); }
.rm-overview { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin: 4px 0 18px; }
.rm-card { background: #fff; border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; }
.rm-card-val { font-size: 22px; font-weight: 700; color: var(--text); }
.rm-card-label { font-size: 12px; color: var(--muted); margin-top: 6px; line-height: 1.5; }
.rm-card-label strong { color: var(--text); font-weight: 600; }
.rm-filterbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 14px; }
.rm-filterbar .filter-label { font-size: 12px; color: var(--muted); }
.rm-filterbar select, .rm-filterbar input { padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px; font-size: 13px; }
.rm-filterbar input[type="date"] { min-width: 130px; }
.rm-filterbar input[type="text"], .rm-filterbar input:not([type="date"]) { min-width: 160px; }
.rm-footer { display: flex; align-items: center; gap: 12px; margin-top: 14px; padding: 12px 14px; background: #f7f9fd; border: 1px solid var(--border); border-radius: 8px; }
.rm-footer .spacer { flex: 1; }
.rm-footer #rmSelectedCount { font-size: 13px; color: var(--text); }
.rm-footer #rmCleanBtn:disabled { background: #f1f3f7; color: #b0b8c5; border-color: #d4d8e0; cursor: not-allowed; }
.rm-locked { background: #fafafa; }
.lock-tag { display: inline-block; padding: 2px 8px; border-radius: 12px; background: #fff3e0; color: #e8932c; font-size: 12px; font-weight: 600; }
.free-tag { display: inline-block; padding: 2px 8px; border-radius: 12px; background: #e9f7ef; color: var(--green, #2e9e5b); font-size: 12px; font-weight: 600; }
.rm-file-cell { display: flex; align-items: center; gap: 10px; }
.rm-file-icon { width: 32px; height: 32px; border-radius: 6px; background: #eef3ff; color: var(--blue); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; flex-shrink: 0; }
.rm-file-icon.img { background: #f1f3f7; color: var(--muted); }
.rm-file-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rm-file-name { font-size: 13px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rm-file-meta { font-size: 11px; color: var(--muted); }
.rm-confirm-list { max-height: 40vh; overflow: auto; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; margin: 10px 0; font-size: 13px; }
.rm-confirm-list div { padding: 2px 0; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; }
.fm-preview { max-height: 46vh; overflow: auto; margin: 10px 0; border: 1px solid var(--border); border-radius: 8px; }
.fm-preview table { margin: 0; }
.btn-sm { padding: 4px 10px; font-size: 13px; border-radius: 6px; cursor: pointer; border: 1px solid var(--border); background: #fff; }
.btn-sm:hover { background: #f0f3fa; }
.btn-sm.active { background: var(--blue); color: #fff; border-color: var(--blue); cursor: default; }
.btn-sm.btn-pause { color: var(--amber); border-color: var(--amber); }
.btn-sm.btn-pause:hover { background: #fff8ec; }
.btn-sm.btn-start { color: var(--green); border-color: var(--green); }
.btn-sm.btn-start:hover { background: #e9f7ef; }
/* 账号管理：启用=绿色 / 禁用=红色 */
.btn-sm.btn-acc-enable { color: var(--green); border-color: var(--green); background: #f4fbf6; font-weight: 600; }
.btn-sm.btn-acc-enable:hover { background: #e8f7ee; }
.btn-sm.btn-acc-disable { color: var(--red); border-color: var(--red); background: #fff6f5; font-weight: 600; }
.btn-sm.btn-acc-disable:hover { background: #fdecea; }
/* 上线发版 — 完成上线：薄荷绿描边 + 浅绿文字 */
.btn-sm.btn-online { color: #5bb890; border-color: #5bb890; background: #f4fbf6; font-weight: 600; }
.btn-sm.btn-online:hover { background: #e8f7ee; color: #48a578; border-color: #48a578; }
/* 上线发版 — 撤销上线：暖米黄底 + 橙红描边/文字 */
.btn-sm.btn-unonline { color: #e8932c; border-color: #e8932c; background: #fff6e5; font-weight: 600; }
.btn-sm.btn-unonline:hover { background: #ffeccd; color: #d4821f; border-color: #d4821f; }
.search-with-multi { display: inline-flex; gap: 4px; align-items: center; }
.multi-kw-btn { padding: 4px 8px; font-size: 13px; border: 1px solid var(--border); background: #fff; border-radius: 8px; cursor: pointer; color: var(--blue); line-height: 1; }
.multi-kw-btn:hover { background: #eef3ff; }
.multi-kw-counter { text-align: right; font-size: 12px; color: var(--muted); margin-top: 4px; }

.grid { width: 100%; border-collapse: collapse; background: #fff; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.grid th, .grid td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 13px; }
.grid th { background: #f7f9fd; color: var(--muted); font-weight: 600; }
.grid tr:last-child td { border-bottom: 0; }
.grid tr:hover td { background: #fafbff; }

.table-wrap { overflow-x: auto; }
#projTable { width: auto; min-width: 100%; }
#projTable th, #projTable td { white-space: nowrap; vertical-align: middle; text-align: center; }
#releaseTable th, #releaseTable td { white-space: nowrap; vertical-align: middle; text-align: center; }
#releaseTable td:nth-child(3) { white-space: normal; word-break: break-word; min-width: 220px; max-width: 220px; text-align: left; }
#releaseTable th:nth-child(3) { min-width: 220px; max-width: 220px; text-align: left; }
#releaseTable td .btn-sm { margin: 0 2px; }
#issueTable th, #issueTable td { white-space: nowrap; vertical-align: middle; text-align: center; }
#issueTable td.cell-wrap { white-space: normal; word-break: break-word; }
#issueTable td .btn-sm { margin: 0 2px; }
#projTable td.col-reqname { white-space: normal; word-break: break-word; min-width: var(--name-col-width, 300px); max-width: var(--name-col-width, 300px); text-align: left; }
#projTable th.col-reqname { text-align: left; }
#projTable th.col-reqno, #projTable td.col-reqno { text-align: center; min-width: 120px; max-width: 120px; }
#projTable th { position: relative; }
#projTable .col-resizer { position: absolute; right: 0; top: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 2; }
#projTable .col-resizer:hover { background: rgba(47,111,237,.2); }

.badge { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; white-space: nowrap; }
.badge.green { background: #e6f6ec; color: var(--green); }
.badge.red { background: #fdecea; color: var(--red); }
.badge.amber { background: #fdf3e0; color: var(--amber); }
.badge.gray { background: #eef1f6; color: var(--muted); }
.badge.blue { background: #e8f0ff; color: var(--blue-d); }

.proj-context { background: #f0f5ff; border: 1px solid #d6e4ff; color: var(--blue-d); padding: 8px 14px; border-radius: 8px; font-size: 13px; font-weight: 600; margin-bottom: 14px; }
#topbarProject, #matProjContext { display: none !important; }

/* 弹窗 */
.modal-mask { position: fixed; inset: 0; background: rgba(20,28,45,.45); display: flex; align-items: center; justify-content: center; z-index: 200; }
.modal { background: #fff; border-radius: 14px; padding: 22px 24px; width: 760px; max-width: 92vw; max-height: 86vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(0,0,0,.3); position: relative; }
.modal h3 { font-size: 16px; margin-bottom: 14px; padding-right: 30px; }
.modal-close { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; border: none; background: transparent; color: var(--muted); font-size: 24px; line-height: 1; cursor: pointer; border-radius: 8px; z-index: 12; display: flex; align-items: center; justify-content: center; transition: background .15s, color .15s; }
.modal-close:hover { background: #f1f3f8; color: var(--text); }
.modal label { display: block; margin: 10px 0 4px; color: var(--muted); font-size: 13px; }
.modal input, .modal select, .modal textarea { width: 100%; padding: 9px 11px; border: 1px solid var(--border); border-radius: 8px; font-family: inherit; }
.modal input.readonly { background: #f4f6fa; color: var(--muted); }
.modal .actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.modal-resizer { position: absolute; right: 0; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 10; }
.modal-resizer:hover { background: rgba(47,111,237,.15); }

.empty { color: var(--muted); padding: 24px; text-align: center; }
.req-group { margin-bottom: 14px; }
.req-group h4 { margin: 0 0 6px; color: var(--blue-d); font-size: 14px; }
.req-group ul { margin: 0; padding-left: 18px; }
.req-group .form-row { display: flex; flex-wrap: wrap; gap: 14px; }
.req-group .form-row label { flex: 1 1 220px; min-width: 200px; margin: 0; }
.req-group .form-row label.full { flex: 1 1 100%; }
.req-group .form-row textarea { min-height: 72px; resize: vertical; }
.schedule-matrix-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.schedule-matrix-head label { margin: 0; }
.schedule-matrix { display: flex; flex-direction: column; gap: 16px; margin-bottom: 14px; }
.matrix-phase { border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.matrix-phase-head { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; background: #f5f7fb; border-bottom: 1px solid var(--border); }
.matrix-phase-title { font-weight: 600; font-size: 13px; color: var(--text); }
.phase-del { color: var(--red); border-color: var(--red); }
.matrix-group { border-top: 1px solid var(--border); border-radius: 0; overflow: hidden; }
.matrix-group:first-of-type { border-top: none; }
.matrix-header, .matrix-row { display: grid; grid-template-columns: 80px repeat(4, 1fr); align-items: center; }
.matrix-header { background: #f5f7fb; font-weight: 500; font-size: 13px; border-bottom: 1px solid var(--border); }
.matrix-row { border-top: 1px solid var(--border); }
.matrix-row:first-of-type { border-top: none; }
.matrix-corner, .matrix-label { padding: 10px 8px; color: var(--muted); font-size: 12px; background: #fafbfc; text-align: center; }
.matrix-stage { padding: 10px 4px; text-align: center; color: var(--text); border-left: 1px solid var(--border); }
.matrix-stage:first-of-type { border-left: none; }
.matrix-row input { width: 100%; height: 38px; border: none; border-left: 1px solid var(--border); padding: 0 4px; text-align: center; font-size: 13px; outline: none; background: transparent; }
.matrix-row input:first-of-type { border-left: none; }
.matrix-row input:focus { background: #f0f7ff; }
.multi-dropdown { position: relative; width: 100%; }
.multi-toggle { width: 100%; min-height: 36px; padding: 8px 28px 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: #fff; text-align: left; cursor: pointer; position: relative; color: var(--text); font-size: 13px; }
.multi-toggle .multi-text { display: inline-block; max-width: 100%; white-space: normal; word-break: break-all; line-height: 1.4; vertical-align: middle; }
#projStatusFilterWrap .multi-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; word-break: normal; display: block; max-width: 260px; }
.multi-toggle .multi-text.placeholder { color: var(--muted); }
.multi-toggle .multi-arrow { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); font-size: 10px; color: var(--muted); pointer-events: none; }
.multi-panel { display: none; position: absolute; left: 0; top: calc(100% + 4px); min-width: 100%; max-width: 320px; max-height: 240px; overflow-y: auto; background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.12); z-index: 100; padding: 8px 0; }
.multi-dropdown.open .multi-panel { display: block; }
.multi-dropdown.open .multi-arrow { transform: translateY(-50%) rotate(180deg); }
.multi-check { display: flex; align-items: center; gap: 8px; padding: 7px 12px; color: var(--text); font-size: 13px; cursor: pointer; white-space: nowrap; }
.multi-check:hover { background: #f5f7fb; }
.multi-check input { width: auto; margin: 0; flex-shrink: 0; }
.options-form { display: flex; flex-direction: column; gap: 18px; }
.opt-group h4 { margin: 0 0 8px; color: var(--blue-d); font-size: 14px; }
.opt-row { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; }
.opt-row input { flex: 1; }
.opt-row .btn-sm { flex-shrink: 0; }

/* 需求管理 */
#view-projects { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-projects .proj-filterbar { flex: 0 0 auto; margin-bottom: 0; padding-bottom: 14px; }
#view-projects .table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* 上线发版、问题跟进 */
#view-release, #view-issue { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-release > .toolbar, #view-issue > .toolbar { flex: 0 0 auto; margin-bottom: 0; padding-bottom: 14px; }
#view-release > .panel, #view-issue > .panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
#view-release > .panel > h3, #view-issue > .panel > h3 { flex: 0 0 auto; margin-bottom: 10px; }
#view-release > .panel > .table-wrap, #view-issue > .panel > .table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* ===== 列表表头冻结（竖向滚动时字段标题固定，不随上下滑动影响） =====
   根因：.grid 默认 overflow:hidden 会成为 sticky 的滚动参照导致冻结失效，
   故对需冻结的表改为 overflow:visible，使其 sticky 参照到外层滚动容器。 */
#projTable, #releaseTable, #issueTable, #incidentTable, #matProjectTable, #rosterTable, #perfTable table.grid {
  overflow: visible;
}
/* overflow:visible 后手动补齐四角圆角（避免方角溢出圆角边框） */
#projTable thead th:first-child, #releaseTable thead th:first-child, #issueTable thead th:first-child, #incidentTable thead th:first-child, #matProjectTable thead th:first-child, #rosterTable thead th:first-child, #perfTable table.grid thead th:first-child { border-top-left-radius: 10px; }
#projTable thead th:last-child, #releaseTable thead th:last-child, #issueTable thead th:last-child, #incidentTable thead th:last-child, #matProjectTable thead th:last-child, #rosterTable thead th:last-child, #perfTable table.grid thead th:last-child { border-top-right-radius: 10px; }
#projTable tbody tr:last-child td:first-child, #releaseTable tbody tr:last-child td:first-child, #issueTable tbody tr:last-child td:first-child, #incidentTable tbody tr:last-child td:first-child, #matProjectTable tbody tr:last-child td:first-child, #rosterTable tbody tr:last-child td:first-child, #perfTable table.grid tbody tr:last-child td:first-child { border-bottom-left-radius: 10px; }
#projTable tbody tr:last-child td:last-child, #releaseTable tbody tr:last-child td:last-child, #issueTable tbody tr:last-child td:last-child, #incidentTable tbody tr:last-child td:last-child, #matProjectTable tbody tr:last-child td:last-child, #rosterTable tbody tr:last-child td:last-child, #perfTable table.grid tbody tr:last-child td:last-child { border-bottom-right-radius: 10px; }
/* thead 冻结 */
#projTable thead th, #releaseTable thead th, #issueTable thead th, #incidentTable thead th, #matProjectTable thead th, #rosterTable thead th, #perfTable table.grid thead th {
  position: sticky; top: 0; z-index: 5;
}
/* 事故报告：补滚动容器与高度链（需求管理/上线发版/问题跟进/验收材料/绩效管理已具备） */
#view-incident { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-incident > .toolbar { flex: 0 0 auto; margin-bottom: 0; padding-bottom: 14px; }
#view-incident > .panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
#view-incident > .panel > h3 { flex: 0 0 auto; margin-bottom: 10px; }
#view-incident > .panel > .table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; }
/* 资源管理/花名册：补滚动容器与高度链 */
#view-schedule { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-schedule > .panel { flex: 0 0 auto; min-height: 0; }

/* ===== 上线发版：左侧固定列（横向滚动时 序号~操作 不随左右滑动） =====
   left 偏移由 JS 依据实际列宽写入下方 CSS 变量，避免长需求编号撑宽导致错位；此处为默认兜底值。 */
#releaseTable {
  --rel-fz-1: 0px; --rel-fz-2: 56px; --rel-fz-3: 176px; --rel-fz-4: 396px; --rel-fz-5: 516px;
}
#releaseTable thead th:nth-child(-n+5),
#releaseTable tbody td:nth-child(-n+5) {
  position: sticky; z-index: 3; background: #fff;
}
#releaseTable thead th:nth-child(-n+5) { z-index: 7; background: #f7f9fd; }
#releaseTable thead th:nth-child(1), #releaseTable tbody td:nth-child(1) { left: var(--rel-fz-1); }
#releaseTable thead th:nth-child(2), #releaseTable tbody td:nth-child(2) { left: var(--rel-fz-2); }
#releaseTable thead th:nth-child(3), #releaseTable tbody td:nth-child(3) { left: var(--rel-fz-3); }
#releaseTable thead th:nth-child(4), #releaseTable tbody td:nth-child(4) { left: var(--rel-fz-4); }
#releaseTable thead th:nth-child(5), #releaseTable tbody td:nth-child(5) { left: var(--rel-fz-5); }
#releaseTable tbody tr:hover td:nth-child(-n+5) { background: #fafbff; }
#releaseTable thead th:nth-child(5),
#releaseTable tbody td:nth-child(5) { box-shadow: 2px 0 6px -2px rgba(20,28,45,.16); }
#view-schedule > .panel:last-child { flex: 1 1 auto; display: flex; flex-direction: column; }
#view-schedule > .panel:last-child > h3 { flex: 0 0 auto; margin-bottom: 10px; }
#view-schedule > .panel:last-child > .table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* 需求排期甘特图 */
#view-gantt { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-gantt .panel { flex-shrink: 0; }
/* #ganttChart 与 .gantt-wrap 是同一元素：flex 撑满 + overflow:auto 自滚动，sticky 表头相对自身冻结 */
#ganttChart { flex: 1; min-height: 0; }
.gantt-wrap { overflow: auto; background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 0 16px 16px 0; --gantt-name-width: 180px; }
.gantt-header, .gantt-row { display: flex; align-items: stretch; min-width: max-content; }
.gantt-header { position: sticky; top: 0; z-index: 30; height: auto; background: #f7f9fd; }
.gantt-row { min-height: 48px; height: auto; }
/* 表头高度自适应时间轴（月份行+日期行），左侧冻结列 stretch 拉齐，保证列表与排期表顶部/底部分界线对齐 */
.gantt-header .gantt-no-col, .gantt-header .gantt-name-col, .gantt-header .gantt-team-col, .gantt-header .gantt-actions { height: auto; }
/* 需求编号/实施小组/操作标题文字居中（需求名称保持居左） */
.gantt-header .gantt-no-col, .gantt-header .gantt-team-col { justify-content: center; }
.gantt-header .gantt-actions { justify-content: center; padding: 4px 6px; font-weight: 600; }
/* 数据行：需求编号、操作列内容居中 */
.gantt-row .gantt-no-col { justify-content: center; }
.gantt-row .gantt-actions { justify-content: center; padding: 4px 6px; }
.gantt-no-col { width: 110px; flex-shrink: 0; padding: 0 12px; font-weight: 600; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); background: #f7f9fd; display: flex; align-items: center; position: sticky; left: 0; z-index: 15; }
.gantt-name-col { width: var(--gantt-name-width); flex-shrink: 0; padding: 0 12px; font-weight: 600; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); background: #f7f9fd; display: flex; align-items: center; position: sticky; left: 110px; z-index: 15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gantt-name-col .col-resizer { position: absolute; right: 0; top: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 20; }
.gantt-name-col .col-resizer:hover { background: rgba(47,111,237,.2); }
.gantt-row .gantt-name-col { font-weight: 400; }
.gantt-no-col .gantt-no { display: inline-block; flex-shrink: 0; background: var(--blue-d); color: #fff; font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: 500; }
.gantt-label .sub { font-weight: 400; font-size: 12px; color: var(--muted); margin-left: 6px; }
.gantt-team-col { width: 120px; flex-shrink: 0; padding: 0 6px; font-weight: 600; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); background: #f7f9fd; display: flex; align-items: center; justify-content: flex-start; color: var(--blue-d); position: sticky; left: calc(110px + var(--gantt-name-width)); z-index: 15; }
.gantt-row .gantt-team-col { font-weight: 400; cursor: pointer; }
.gantt-row .gantt-team-col:not(.empty):hover { text-decoration: none; }
.gantt-team-col .team-avatar { width: 20px; height: 20px; font-size: 11px; margin-left: -6px; border-width: 1.5px; }
.gantt-actions { width: 240px; flex-shrink: 0; padding: 4px 6px 4px 12px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); background: #f7f9fd; display: flex; align-items: center; justify-content: flex-start; flex-wrap: nowrap; gap: 4px; position: sticky; left: calc(110px + var(--gantt-name-width) + 120px); z-index: 15; }
.gantt-actions .gantt-add, .gantt-actions .gantt-online { margin-left: 0; }
.gantt-gap { width: 16px; flex-shrink: 0; background: #fff; position: sticky; left: calc(110px + var(--gantt-name-width) + 120px + 240px); z-index: 15; box-shadow: 6px 0 8px -4px rgba(0,0,0,.06); }
.gantt-header .gantt-gap { z-index: 25; }
.gantt-header .gantt-no-col,
.gantt-header .gantt-name-col,
.gantt-header .gantt-team-col,
.gantt-header .gantt-actions { z-index: 25; }
.gantt-timeline { position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
.gantt-months { display: flex; border-bottom: 1px solid var(--border); }
.gantt-month { text-align: center; font-size: 12px; color: var(--muted); padding: 6px 0; border-right: 1px solid var(--border); background: #f7f9fd; box-sizing: border-box; }
.gantt-days { display: flex; border-bottom: 1px solid var(--border); }
.gantt-day { width: 28px; flex-shrink: 0; text-align: center; font-size: 11px; color: var(--muted); padding: 4px 0; border-right: 1px solid #f0f2f7; box-sizing: border-box; }
.gantt-day.weekend { background: #f2f2f2; color: var(--red); font-weight: 700; }
.gantt-day.today { background: #e8f0ff; color: var(--blue-d); font-weight: 700; }
.gantt-day.holiday { background: #f2f2f2; color: var(--red); font-weight: 700; }
.gantt-track { position: relative; min-height: 48px; height: 100%; border-bottom: 1px solid var(--border); display: flex; align-items: center; flex-shrink: 0; overflow: hidden; }
.gantt-today-line { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--red); z-index: 4; pointer-events: none; }
/* sticky 表头为独立合成层，1px 今日线会被舍入丢失（只显示行区一半）；加宽至 3px 并回移 1px 保持对准当日格中心 */
.gantt-header .gantt-today-line { width: 3px; margin-left: -1px; }
.gantt-cell { width: 28px; height: 100%; flex-shrink: 0; border-right: 1px solid #f0f2f7; box-sizing: border-box; }
.gantt-cell.weekend { background: #f2f2f2; }
.gantt-cell.holiday { background: #f2f2f2; }
.gantt-bar { position: absolute; height: 18px; border-radius: 4px; font-size: 11px; color: #fff; line-height: 18px; padding: 0 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: grab; box-shadow: 0 1px 3px rgba(0,0,0,.15); user-select: none; z-index: 1; }
.gantt-bar:hover { filter: brightness(1.1); z-index: 5; }
.gantt-bar:active { cursor: grabbing; }
.gantt-row-paused .gantt-no-col, .gantt-row-paused .gantt-name-col, .gantt-row-paused .gantt-team-col, .gantt-row-paused .gantt-actions { background: #fff8ec; }
/* 方案 §9.2：排期重叠区段阴影叠加（纯视觉，不遮挡色条拖拽/单击） */
.gantt-overlap {
  position: absolute;
  top: 4px;
  bottom: 4px;
  z-index: 4;
  pointer-events: none;
  border-radius: 3px;
  background: repeating-linear-gradient(135deg, rgba(124,58,237,.26) 0 5px, rgba(124,58,237,.07) 5px 10px);
  box-shadow: inset 0 0 0 1px rgba(124,58,237,.45);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* 重叠阴影及其子元素必须完全放弃指针事件，防止遮挡色条拖拽/单击 */
.gantt-overlap *, .gantt-overlap span { pointer-events: none; }
.gantt-overlap span { font-size: 10px; font-weight: 700; color: #5b21b6; white-space: nowrap; text-shadow: 0 1px 0 rgba(255,255,255,.85); }
.gantt-paused-overlay { position: absolute; inset: 0; background: rgba(255,248,236,.72); display: flex; align-items: center; justify-content: center; z-index: 6; pointer-events: none; }
.gantt-paused-overlay span { background: var(--amber); color: #fff; font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px; box-shadow: 0 1px 4px rgba(0,0,0,.12); }
.gantt-add { margin-left: 8px; font-size: 11px; padding: 2px 8px; border: 1px dashed var(--border); border-radius: 6px; background: #fff; color: var(--blue-d); cursor: pointer; }
.gantt-add:hover { background: #eef3ff; }
/* 排期变更未读：按钮标红（仅改颜色类，不改 gantt-actions 布局，避免回归） */
.gantt-add.has-change { color: var(--red); border: 1px solid var(--red); background: #fdecea; font-weight: 600; }
.gantt-online { margin-left: 4px; font-size: 11px; padding: 2px 8px; border: 1px dashed var(--border); border-radius: 6px; background: #fff; color: var(--green); cursor: pointer; }
.gantt-online:hover { background: #e9f7ef; }
.gantt-undo { margin-left: 4px; font-size: 11px; padding: 2px 8px; border: 1px dashed var(--border); border-radius: 6px; background: #fff; color: var(--amber); cursor: pointer; }
.gantt-undo:hover { background: #fff8ec; }
.gantt-risk { font-size: 11px; padding: 2px 8px; border: 1px solid var(--orange, #e08e0b); border-radius: 6px; background: #fff7ec; color: #c47d00; cursor: pointer; }
/* 操作按钮字体与需求编号 chip 一致（11px / 500） */
.gantt-add, .gantt-online, .gantt-risk { font-weight: 500; }
.gantt-risk:hover { background: #fdeccd; }

/* ===== 排期变更记录板块（编辑排期弹窗「资源」下方） ===== */
.chg-block { border: 1px solid var(--border); border-radius: 8px; padding: 12px; margin-top: 4px; background: #fcfdff; }
.chg-tip { font-size: 12px; color: var(--muted); margin: 0 0 8px; line-height: 1.6; }
.chg-reason-input { width: 100%; min-height: 46px; resize: vertical; font-size: 13px; margin-bottom: 10px; }
.chg-list-head { font-size: 13px; font-weight: 600; color: var(--text); margin: 4px 0 8px; display: flex; justify-content: space-between; align-items: center; }
.chg-toggle-all { font-size: 12px; color: var(--blue-d); background: transparent; border: none; cursor: pointer; padding: 2px 0; }
.chg-list { display: flex; flex-direction: column; gap: 8px; max-height: 38vh; overflow-y: auto; }
.chg-list.collapsed { display: none; }
.chg-item { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: #fff; }
.chg-item-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.chg-type { font-size: 12px; font-weight: 600; padding: 1px 8px; border-radius: 999px; }
.chg-type.schedule { color: var(--blue-d); background: #eef3ff; }
.chg-type.resource { color: #b45a1a; background: #fff3e0; }
.chg-index { font-size: 12px; color: var(--muted); }
.chg-meta { font-size: 12px; color: var(--muted); }
.chg-meta strong { color: var(--text); font-weight: 600; }
.chg-body { font-size: 13px; color: var(--text); line-height: 1.7; }
.chg-body .old { color: var(--red); text-decoration: line-through; }
.chg-body .new { color: var(--green); }
.chg-reason { font-size: 12px; color: var(--muted); background: #f7f9fd; border-radius: 6px; padding: 5px 10px; margin-top: 6px; }
.chg-reason.empty { color: #aab; font-style: italic; }

/* 风险记录弹窗 */
.risk-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.risk-search { flex: 1; min-width: 160px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: #fff; }
.risk-filter { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: #fff; }
.risk-list { display: flex; flex-direction: column; gap: 10px; max-height: 56vh; overflow-y: auto; }
.risk-section-title { font-size: 13px; font-weight: 700; color: var(--muted); margin-top: 4px; margin-bottom: -2px; }
.risk-history-title { color: var(--muted); }
.risk-card { border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; background: #fff; }
.risk-card.completed { background: #f7f9fd; border-color: #e2e6ef; }
.risk-card.completed .risk-desc,
.risk-card.completed .risk-proposer,
.risk-card.completed .risk-seq,
.risk-card.completed .risk-stage { color: var(--muted); }
.risk-card.completed .badge { opacity: .75; }
.risk-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.risk-seq { font-weight: 700; color: var(--muted); font-size: 13px; }
.risk-stage { font-size: 12px; color: var(--blue-d); background: #eef3ff; padding: 2px 8px; border-radius: 12px; }
.risk-proposer { margin-left: auto; color: var(--muted); font-size: 12px; }
.risk-ops { display: inline-flex; gap: 10px; }
.risk-desc { font-size: 14px; line-height: 1.5; color: var(--text); white-space: pre-wrap; word-break: break-word; }
.risk-complete { color: var(--green) !important; font-weight: 600; }
.link-btn { background: none; border: none; color: var(--blue-d); cursor: pointer; padding: 0; font-size: 13px; }
.link-btn:hover { text-decoration: underline; }
.link-btn.danger { color: var(--red); }
.req { color: var(--red); margin-left: 2px; }

/* 概览 */
.overview-wrap { padding: 8px 4px; }
.overview-summary { display: flex; gap: 16px; margin-bottom: 24px; }
.overview-card { flex: 1; min-width: 160px; max-width: 260px; background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 20px 24px; box-shadow: 0 2px 8px rgba(0,0,0,0.04); }
.overview-card.total { background: linear-gradient(135deg, #f0f5ff 0%, #fff 100%); border-color: #d6e3ff; }
.overview-label { font-size: 14px; color: var(--muted); margin-bottom: 8px; }
.overview-value { font-size: 40px; font-weight: 700; color: var(--blue-d); line-height: 1; }
.overview-page-title { font-size: 24px; font-weight: 700; color: var(--text); margin: 0 0 6px; letter-spacing: -0.01em; }
.overview-section-title { font-size: 16px; font-weight: 600; color: var(--text); margin: 0 0 16px; }
/* 按阶段统计：一排 9 卡铺满（阶段顺序与 STAGES 一致）+ 阶段语义色 */
.overview-stage-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(178px, 1fr)); gap: 12px; }
.overview-stage-grid.ov-stage-one-row { grid-template-columns: repeat(9, minmax(0, 1fr)); grid-template-rows: 1fr; }
.overview-stage-card { background: var(--sc-bg, #fff); border: 1px solid var(--sc-bd, var(--border)); border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column; justify-content: center; }
.overview-stage-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.overview-stage-name { font-size: 13px; color: var(--sc, var(--text)); font-weight: 500; white-space: nowrap; }
.overview-stage-count { font-size: 22px; font-weight: 700; color: var(--sc, var(--blue-d)); }
.overview-stage-count small { font-size: 11px; font-weight: 400; color: var(--sc, var(--muted)); opacity: .7; margin-left: 2px; }
.overview-stage-bar { height: 6px; background: var(--sc-track, #eef3ff); border-radius: 3px; overflow: hidden; }
.overview-stage-fill { height: 100%; background: var(--sc, var(--blue-d)); border-radius: 3px; transition: width .3s ease; }
/* 阶段语义色：main / 卡片底色 / 边框 / 进度条底 */
.overview-stage-card[data-stage="待评估"]   { --sc: #98a2b3; --sc-bg: #f2f4f7; --sc-bd: #e2e6ec; --sc-track: #e7eaef; }
.overview-stage-card[data-stage="需求澄清"] { --sc: #2f6fed; --sc-bg: #eaf1fe; --sc-bd: #d3e2fd; --sc-track: #dbe7fd; }
.overview-stage-card[data-stage="方案设计"] { --sc: #14b8a6; --sc-bg: #e6f8f6; --sc-bd: #cbece7; --sc-track: #d5f0eb; }
.overview-stage-card[data-stage="需求评审"] { --sc: #8b5cf6; --sc-bg: #f1ecfe; --sc-bd: #ddd2fb; --sc-track: #e4dbfd; }
.overview-stage-card[data-stage="系统开发"] { --sc: #22c55e; --sc-bg: #e9f9ef; --sc-bd: #cceeda; --sc-track: #d7f4e3; }
.overview-stage-card[data-stage="接口联调"] { --sc: #f59e0b; --sc-bg: #fef4e2; --sc-bd: #fae3bb; --sc-track: #fceacd; }
.overview-stage-card[data-stage="SIT测试"]  { --sc: #274690; --sc-bg: #e9edf7; --sc-bd: #cfd8ec; --sc-track: #dae1f1; }
.overview-stage-card[data-stage="UAT测试"]  { --sc: #0d9488; --sc-bg: #e5f5f3; --sc-bd: #c9e9e5; --sc-track: #d3eeeb; }
.overview-stage-card[data-stage="产品验收"] { --sc: #7c3aed; --sc-bg: #f3e8ff; --sc-bd: #e9d5ff; --sc-track: #efddff; }
.overview-stage-card[data-stage="压力测试"] { --sc: #e11d48; --sc-bg: #ffe4ea; --sc-bd: #fbcfe0; --sc-track: #ffd9e3; }
.overview-stage-card[data-stage="上线发布"] { --sc: #d8453a; --sc-bg: #fdecea; --sc-bd: #f7d2cd; --sc-track: #fadbd6; }
/* 一排铺满模式：字号等比放大，卡内垂直居中填充 */
.ov-stage-one-row .overview-stage-card { padding: 16px 16px 14px; }
.ov-stage-one-row .overview-stage-name { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; }
.ov-stage-one-row .overview-stage-count { font-size: 28px; }
.ov-stage-one-row .overview-stage-count small { font-size: 12px; }
.ov-stage-one-row .overview-stage-bar { height: 8px; margin-top: 4px; }
.ov-stage-one-row .overview-stage-fill { border-radius: 4px; }

/* 概览-风险/阶段处理人/上线/统计 区块 */
.ov-risk-list, .ov-golive-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.ov-risk-item, .ov-golive-item { display: flex; align-items: center; gap: 12px; background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px; }
.ov-risk-no, .ov-gl-no { font-weight: 600; color: var(--blue-d); font-size: 13px; min-width: 112px; }
.ov-risk-name, .ov-gl-name { flex: 1; color: var(--text); font-size: 13px; }
.ov-risk-count { color: var(--orange, #c47d00); font-size: 13px; font-weight: 500; }
/* 风险与上线关注：今日关键节点统计卡（阶段首日 + 今日需要上线） */
.ov-today-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); gap: 12px; }
.ov-today-card { position: relative; background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 16px 12px; text-align: center; transition: transform .16s ease, box-shadow .16s ease; }
.ov-today-card:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(20,30,60,0.08); }
.ov-today-count { font-size: 30px; font-weight: 700; line-height: 1; color: var(--blue-d); letter-spacing: -0.02em; }
.ov-today-label { font-size: 12px; color: var(--muted); margin-top: 9px; }
.ov-today-card[data-golive="1"] .ov-today-count { color: var(--amber); }
.ov-today-card[data-tip]:hover::after {
  content: attr(data-tip); position: absolute; left: 50%; bottom: calc(100% + 9px); transform: translateX(-50%);
  background: #1f2733; color: #fff; font-size: 12px; line-height: 1.5; padding: 7px 11px; border-radius: 8px;
  white-space: pre-wrap; max-width: 248px; text-align: left; z-index: 30; pointer-events: none; box-shadow: 0 8px 20px rgba(0,0,0,0.22);
}
.ov-today-card[data-tip]:hover::before {
  content: ""; position: absolute; left: 50%; bottom: calc(100% + 3px); transform: translateX(-50%);
  border: 6px solid transparent; border-top-color: #1f2733; z-index: 30;
}
.ov-stage-handler-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; align-items: stretch; }
.ov-stage-handler-card { background: #fff; border: 1px solid var(--border); border-top: 3px solid var(--sc, var(--border)); border-radius: 10px; padding: 12px 14px; height: 360px; display: flex; flex-direction: column; box-sizing: border-box; }
.ov-stage-handler-card[data-stage="待评估及需求澄清"] { --sc: #98a2b3; }
.ov-stage-handler-card[data-stage="方案设计"] { --sc: #14b8a6; }
.ov-stage-handler-card[data-stage="需求评审"] { --sc: #8b5cf6; }
.ov-stage-handler-card[data-stage="系统开发"] { --sc: #22c55e; }
.ov-stage-handler-card[data-stage="接口联调"] { --sc: #f59e0b; }
.ov-stage-handler-card[data-stage="SIT测试"] { --sc: #274690; }
.ov-stage-handler-card[data-stage="UAT测试"] { --sc: #0d9488; }
.ov-stage-handler-card[data-stage="产品验收"] { --sc: #7c3aed; }
.ov-stage-handler-card[data-stage="压力测试"] { --sc: #e11d48; }
.ov-stage-handler-card[data-stage="上线发布"] { --sc: #d8453a; }
.ov-stage-handler-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px; flex: 0 0 auto; gap: 8px; }
.ov-sh-stage { font-size: 14px; font-weight: 600; color: var(--sc, var(--text)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-sh-count { font-size: 13px; color: var(--muted); flex: 0 0 auto; }
.ov-sh-items { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; padding-right: 4px; }
.ov-sh-row { display: grid; grid-template-columns: 84px minmax(0, 1fr) 56px 60px 80px; align-items: center; column-gap: 8px; font-size: 12px; }
.ov-sh-header { font-weight: 600; color: var(--muted); border-bottom: 1px solid var(--border); padding-bottom: 6px; margin-bottom: 2px; flex: 0 0 auto; }
.ov-sh-header > span { overflow: visible; text-overflow: unset; }
.ov-sh-row--hidden { display: none; }
.ov-stage-handler-card.ov-sh-expanded .ov-sh-row--hidden { display: grid; }
.ov-sh-more { margin-top: 10px; flex: 0 0 auto; align-self: flex-start; border: 1px dashed var(--border); background: #f7f9fd; color: var(--blue-d); border-radius: 8px; padding: 6px 12px; font-size: 12px; cursor: pointer; }
.ov-sh-more:hover { background: #eef3ff; }
.ov-sh-pno { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-sh-pname { min-width: 0; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-sh-pstage { color: var(--blue-d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-sh-exec { color: var(--blue-d); font-weight: 500; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-sh-starts { color: var(--text); font-weight: 500; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-sh-starts--yes { color: #d8453a; font-weight: 700; }
.ov-sh-empty { color: var(--muted); font-size: 12px; padding: 6px 0; }
@media (max-width: 1180px) { .ov-stage-handler-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.ov-stat-row { display: flex; gap: 16px; margin-top: 12px; flex-wrap: wrap; }
.ov-stat-card { flex: 1; min-width: 240px; background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 16px 20px; }
.ov-stat-title { font-size: 14px; color: var(--muted); margin-bottom: 10px; }
.ov-stat-body { display: flex; gap: 12px; flex-wrap: wrap; }
.ov-stat-pill { font-size: 13px; font-weight: 600; padding: 5px 12px; border-radius: 999px; }
.ov-stat-pill.green { background: #e9f8ee; color: #1f9d4d; }
.ov-stat-pill.amber { background: #fdf1dd; color: #b97700; }
.ov-stat-pill.gray { background: #f0f2f5; color: #6b7280; }
.ov-stat-body.pie-layout { display: block; }
.ov-pie-wrap { display: flex; align-items: center; gap: 20px; }
.ov-pie-wrap svg { flex-shrink: 0; }
.ov-pie-legend { display: flex; flex-direction: column; gap: 8px; flex: 1; }
.ov-pie-legend-item { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.ov-pie-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.ov-pie-label { color: var(--muted); }
.ov-pie-value { font-weight: 600; color: var(--text); margin-left: auto; }

/* 概览-趋势图 */
.ov-trend-block { margin-top: 28px; }
.ov-trend-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; flex-wrap: wrap; gap: 12px; }
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.seg button { border: none; background: #fff; color: var(--muted); font-size: 13px; padding: 6px 18px; cursor: pointer; transition: background .15s, color .15s; }
.seg button + button { border-left: 1px solid var(--border); }
.seg button.active { background: var(--blue-d); color: #fff; font-weight: 600; }
.ov-trend-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; }
.ov-chart-card { background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 20px 24px; min-height: 520px; display: flex; flex-direction: column; }
.ov-chart-title { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 14px; }
.ov-chart { flex: 1; min-height: 0; width: 100%; position: relative; }
.ov-chart svg { display: block; position: absolute; inset: 0; width: 100%; height: 100%; }
.ov-chart-tooltip { position: absolute; pointer-events: none; background: rgba(255, 255, 255, 0.96); border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; box-shadow: 0 6px 18px rgba(0,0,0,0.12); font-size: 12px; line-height: 1.5; color: var(--text); z-index: 10; display: none; white-space: nowrap; }
.ov-chart-tooltip .tt-label { color: var(--muted); margin-bottom: 2px; }
.ov-chart-tooltip .tt-val { font-weight: 700; font-size: 13px; }
.ov-chart-tooltip .tt-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }

.res-group { border: 1px solid var(--border); border-radius: 8px; padding: 12px; }
.res-row { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.res-row:last-child { margin-bottom: 0; }
.res-row label { min-width: 70px; width: auto; margin: 0; color: var(--muted); font-size: 13px; font-weight: 500; white-space: nowrap; flex-shrink: 0; }
.res-row select { flex: 1; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: #fff; }
.res-row select.has-busy { border-color: var(--red); color: var(--red); }
.multi-select { position: relative; flex: 1; }
.multi-trigger { min-height: 36px; padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px; background: #fff; cursor: pointer; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; color: var(--muted); }
.multi-trigger .tag { display: inline-flex; align-items: center; gap: 4px; background: #eef3ff; color: var(--blue-d); font-size: 12px; padding: 2px 8px; border-radius: 12px; }
.multi-trigger .placeholder { color: #aab; }
.multi-options { position: absolute; top: calc(100% + 4px); left: 0; right: 0; max-height: 220px; overflow-y: auto; background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.12); z-index: 100; display: none; }
.multi-options.open { display: block; }
.multi-options label { width: auto; display: flex; align-items: center; gap: 8px; padding: 8px 12px; margin: 0; cursor: pointer; font-size: 13px; color: var(--text); border-bottom: 1px solid #f2f2f2; }
.multi-options label:last-child { border-bottom: none; }
.multi-options label:hover { background: #f7f9fd; }
.multi-options label.busy { color: var(--red); }
.multi-options input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--blue-d); }
.role-filter-row { padding: 6px 10px; border-bottom: 1px solid #f2f2f2; position: sticky; top: 0; background: #fff; z-index: 1; }
.role-filter { width: 100%; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; background: #fff; font-size: 13px; }
.team-cell { max-width: 220px; cursor: pointer; padding: 6px 8px; vertical-align: middle; }
.team-cell:hover { text-decoration: none; }
.team-cell:hover .team-avatar { box-shadow: 0 0 0 2px rgba(47,111,237,.25); }
.team-avatars { display: inline-flex; flex-wrap: wrap; align-items: center; }
.team-avatar { width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: #fff; font-size: 13px; font-weight: 600; flex-shrink: 0; text-shadow: 0 1px 2px rgba(0,0,0,.12); border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0,0,0,.12); margin-left: -7px; }
.team-avatar:first-child { margin-left: 0; }
.team-cell:hover .team-avatar { box-shadow: 0 1px 5px rgba(0,0,0,.18); }
/* 列表内实施小组头像尺寸统一与需求排期（甘特）保持一致：20px */
#releaseTable .team-avatar,
#projTable .team-avatar { width: 20px; height: 20px; font-size: 11px; margin-left: -6px; border-width: 1.5px; }
.team-list { display: grid; grid-template-columns: 70px 1fr; gap: 8px 12px; }
.team-list .role { color: var(--muted); text-align: right; }
.team-list .names { color: var(--text); }
.team-row { display: flex; align-items: baseline; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border); }
.team-row:last-child { border-bottom: none; }
.team-role { width: 72px; flex-shrink: 0; color: var(--muted); text-align: right; font-size: 13px; }
.team-names { color: var(--text); }
#ganttLegend { width: 100%; max-width: 100%; box-sizing: border-box; padding: 12px 16px; background: #fff; border: 1px solid var(--border); border-top: none; border-radius: 0 0 12px 12px; flex-shrink: 0; }
.gantt-legend { display: flex; gap: 14px; flex-wrap: wrap; }
.gantt-legend span { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--muted); }
.gantt-legend i { width: 14px; height: 14px; border-radius: 3px; }

.conflict-list { margin: 10px 0; padding-left: 18px; color: var(--text); line-height: 1.8; }
.conflict-list li { margin-bottom: 4px; }
.busy-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px; background: #fafbff; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; }
.busy-item span { font-size: 13px; color: var(--text); }
.table-wrap { overflow-x: auto; }
#releaseTable { width: auto; min-width: 100%; }
#releaseTable th, #releaseTable td { white-space: nowrap; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.two-col .toolbar { margin-bottom: 10px; }
.two-col .toolbar h3 { margin: 0; }
code { background: #f0f3fa; padding: 2px 6px; border-radius: 4px; font-family: Consolas, monospace; font-size: 13px; color: var(--blue-d); }

/* 权限配置 */
/* 角色权限配置弹窗 */
.perm-role-row { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.perm-role-row label { margin: 0; color: var(--muted); font-size: 13px; white-space: nowrap; }
.perm-role-row select { width: 200px; }
.perm-role-panel { }
.perm-menu-section { margin-bottom: 22px; }
.perm-menu-section h4, .perm-func-section h4 { font-size: 14px; color: var(--text); margin: 0 0 12px; font-weight: 600; }
.perm-menu-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
.perm-menu-card { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: #fff; cursor: pointer; font-size: 13px; color: var(--text); transition: border-color .15s, background .15s; }
.perm-menu-card:hover { border-color: var(--blue); background: #f5f8ff; }
.perm-menu-card input { margin: 0; flex-shrink: 0; }
.perm-table-wrap { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.perm-func-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.perm-func-table th, .perm-func-table td { padding: 10px 8px; text-align: center; border-bottom: 1px solid var(--border); }
.perm-func-table th { background: #f4f6fb; color: var(--muted); font-weight: 600; }
.perm-func-table th:first-child, .perm-func-table td:first-child { text-align: left; padding-left: 14px; }
.perm-func-table tbody tr:last-child td { border-bottom: none; }
.perm-func-table tbody tr:hover { background: #fafbff; }
.perm-res { color: var(--text); font-weight: 500; }
.perm-td-check { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; cursor: pointer; margin: 0; }
.perm-na { color: #c5c9d2; }
.perm-hint-bar { margin-top: 18px; padding: 10px 14px; background: #eef4ff; color: var(--blue-d); border-radius: 8px; font-size: 13px; }
.perm-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
/* 旧版权限面板兼容（如仍被其他弹窗使用） */
.perm-panel { border: 1px solid var(--border); border-radius: 10px; padding: 14px; margin-top: 14px; background: #fafbff; }
.perm-panel h4 { margin: 0 0 10px; font-size: 14px; color: var(--text); }
.perm-section { margin-bottom: 12px; }
.perm-section b { display: block; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.perm-opts { display: flex; flex-wrap: wrap; gap: 10px; }
.perm-check { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; color: var(--text); cursor: pointer; background: #fff; padding: 5px 10px; border: 1px solid var(--border); border-radius: 6px; }
.perm-check input { margin: 0; }

/* 图片上传与预览 */
.image-upload { width: 100%; }
.image-placeholder { display: flex; align-items: center; justify-content: center; height: 120px; border: 2px dashed var(--border); border-radius: 10px; background: #f7f9fd; color: var(--muted); cursor: pointer; position: relative; overflow: hidden; transition: border-color .15s, background .15s; }
.image-placeholder:hover { border-color: var(--blue); background: #eef3ff; }
.image-placeholder span { pointer-events: none; font-size: 13px; }
.image-placeholder input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.image-preview { position: relative; display: inline-block; max-width: 260px; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; background: #fff; }
.image-preview img { display: block; max-width: 100%; max-height: 220px; cursor: zoom-in; }
.image-preview .btn-sm { position: absolute; top: 6px; right: 6px; background: rgba(255,255,255,.92); border-color: var(--red); color: var(--red); }
.image-preview .btn-sm:hover { background: var(--red); color: #fff; }

/* 图片大图预览灯箱 */
.img-lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.88); display: flex; align-items: center; justify-content: center; z-index: 300; cursor: zoom-out; }
.img-lightbox img { max-width: 92vw; max-height: 92vh; border-radius: 8px; box-shadow: 0 20px 60px rgba(0,0,0,.5); }
.img-lightbox-close { position: absolute; top: 14px; right: 22px; color: #fff; font-size: 36px; line-height: 1; cursor: pointer; text-shadow: 0 1px 4px rgba(0,0,0,.5); }

/* 概览：项目筛选与按项目维度统计 */
.overview-filterbar { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; flex-wrap: wrap; }
.overview-filterbar label { color: var(--muted); font-size: 13px; }
.overview-filterbar select { min-width: 220px; }
.ov-prog-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px; }
.ov-prog-card { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 15px 17px; box-shadow: 0 1px 2px rgba(16,24,40,.04); }
.ov-prog-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.ov-prog-no { font-weight: 700; color: var(--blue); font-size: 13px; }
.ov-prog-name { font-weight: 600; font-size: 15px; }
.ov-prog-meta { color: var(--muted); font-size: 13px; margin-bottom: 10px; }
.ov-prog-bars { display: flex; flex-direction: column; gap: 4px; min-height: 24px; }
.ov-prog-bar-row { display: flex; justify-content: space-between; font-size: 13px; padding: 2px 0; border-bottom: 1px dashed var(--border); }
.ov-prog-bar-label { color: var(--text); }
.ov-prog-bar-val { color: var(--muted); font-weight: 600; }
.ov-prog-foot { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; }

/* 需求管理筛选栏 */
.proj-filterbar { gap: 8px; }
.proj-filterbar input, .proj-filterbar select { padding: 7px 9px; font-size: 13px; }
.proj-filterbar input[type="month"], .proj-filterbar input[type="date"] { min-width: 120px; }
.proj-filterbar .date-span { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; color: var(--muted); white-space: nowrap; }
.proj-filterbar .date-span input { min-width: 110px; }

/* 材料清单弹窗表格 */
.mat-list-table th:nth-child(3),
.mat-list-table td:nth-child(3),
.mat-list-table th:nth-child(4),
.mat-list-table td:nth-child(4),
.mat-list-table th:nth-child(5),
.mat-list-table td:nth-child(5),
.mat-list-table th:nth-child(6),
.mat-list-table td:nth-child(6) { white-space: nowrap; }
.mat-list-table td:nth-child(2) { max-width: 320px; }
.mat-approval-no, .mat-approval-name { max-width: 130px; padding: 4px 6px; font-size: 13px; }

/* 验收材料清单文件名 */
.mat-filename { max-width: 280px; white-space: normal; word-break: break-all; }

/* 验收材料需求列表筛选栏 */
.mat-filterbar { gap: 8px; align-items: center; flex-wrap: nowrap; overflow: visible; padding-bottom: 8px; }
.mat-filterbar select { padding: 7px 9px; font-size: 13px; min-width: 96px; width: auto; }
.mat-filterbar .multi-dropdown { width: auto; min-width: 120px; }
.mat-filterbar .multi-toggle .multi-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; word-break: normal; display: block; }
.mat-filterbar button { white-space: nowrap; }
#matProjectTable th:first-child, #matProjectTable td:first-child { text-align: center; }
#matProjectTable th:nth-child(n+4):nth-child(-n+10),
#matProjectTable td:nth-child(n+4):nth-child(-n+10) { text-align: center; vertical-align: middle; }
.mat-row-check { width: 16px; height: 16px; cursor: pointer; }

/* 验收材料、绩效管理列表表头冻结 */
#view-materials { display: flex; flex-direction: column; height: 100%; overflow: auto; }
/* 需求列表面板：成为 flex 容器，让表格区域内部滚动、分页条固定在面板底部始终可见。
   原写法 .panel:first-of-type 因 #view-materials 下第一个 div 是 .proj-context 而从未匹配，
   导致表格无高度约束被整页撑开、分页条被顶到数千像素外（表现为"分页不显示"）。 */
#view-materials .mat-list-panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
#view-materials .mat-list-panel .pager { flex: 0 0 auto; }
#view-materials .mat-proj-table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; }
#matProjectTable thead th { position: sticky; top: 0; z-index: 5; }
#view-performance { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-performance #perfTable { flex: 1 1 auto; min-height: 0; overflow: auto; }
#view-performance .perf-table-wrap { min-height: 0; overflow: visible; }
#perfTable table.grid thead th { position: sticky; top: 0; z-index: 5; }

/* ===== 绩效管理 ===== */
#view-performance .toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
#view-performance .toolbar .spacer { flex: 1; }
#view-performance .toolbar .chk { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; color: var(--muted); }
#view-performance .toolbar input[type=text], #view-performance .toolbar input:not([type]), #view-performance .toolbar select { min-width: 160px; }
#perfTable table.grid { width: auto; min-width: 100%; }
#perfTable table.grid th,
#perfTable table.grid td { white-space: nowrap; vertical-align: middle; text-align: center; }
#perfTable table.grid th:nth-child(1),
#perfTable table.grid td:nth-child(1) { width: 50px; min-width: 50px; max-width: 50px; }
#perfTable table.grid th:nth-child(2),
#perfTable table.grid td:nth-child(2) { width: 180px; min-width: 180px; max-width: 180px; }
#perfTable table.grid td:nth-child(3) { white-space: normal; word-break: break-word; min-width: 220px; max-width: 220px; text-align: left; }
#perfTable table.grid th:nth-child(3) { min-width: 220px; max-width: 220px; text-align: left; }
#perfTable table.grid th:nth-child(4),
#perfTable table.grid td:nth-child(4) { width: 80px; min-width: 80px; max-width: 80px; }
#perfTable table.grid td:last-child { white-space: normal; min-width: 260px; max-width: 460px; text-align: left; }
#perfTable table.grid th:last-child { min-width: 260px; text-align: left; }
.perf-base { display: flex; gap: 24px; flex-wrap: wrap; margin-bottom: 12px; }
.perf-base > div { display: flex; flex-direction: column; gap: 4px; }
.perf-base label { font-size: 12px; color: var(--muted); }
.perf-total { font-size: 20px; font-weight: 700; color: var(--blue-d); }
.perf-team-source { font-size: 14px; color: var(--text); padding: 4px 0; }
.perf-stats-bar { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; background: #f6f8fc; border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; margin-bottom: 14px; }
.perf-stat { text-align: center; }
.perf-stat-label { font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.perf-stat-value { font-size: 20px; font-weight: 700; color: var(--text); }
.perf-stat-assigned { color: var(--blue); }
.perf-stat-done { color: var(--green); }
.perf-stat-pending { color: var(--amber); }
.perf-stat-released { color: var(--muted); }
.perf-summary { background: #f6f8fc; border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px; margin-bottom: 14px; font-size: 14px; }
.perf-summary .warn { color: var(--red); font-weight: 700; margin-left: 6px; }
.perf-pool { border-radius: 8px; padding: 10px 14px; margin-bottom: 14px; font-size: 14px; display: flex; flex-direction: column; align-items: stretch; gap: 8px; flex-wrap: wrap; }
.perf-pool-main { line-height: 1.5; }
.perf-pool-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.perf-pool-pending { background: #fff7e6; border: 1px solid #ffd591; color: #ad6800; }
.perf-pool-pending b { color: #d46b08; }
.perf-pool-confirmed { background: #f5f5f5; border: 1px solid var(--border); color: var(--muted); }
.perf-pool-confirmed b { color: var(--text); }
.perf-pool-resolved { background: #f0fbf3; border: 1px solid #b7eb8f; color: #389e0d; }
.perf-pool-resolved b { color: #237804; }
.pool-btn { font-size: 13px; padding: 4px 12px; border-radius: 6px; border: 1px solid var(--blue); background: var(--blue); color: #fff; cursor: pointer; }
.pool-btn:hover { filter: brightness(0.96); }
.pool-btn-ghost { background: #fff; color: var(--blue-d); border-color: var(--border); }
.pool-btn-ghost:hover { border-color: var(--blue-d); }
.perf-pool-extra { margin-top: 2px; }
.pool-inline { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.pool-input, .pool-select { padding: 4px 6px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; }
.pool-preview { color: #ad6800; font-variant-numeric: tabular-nums; }
.perf-pool-confirmed .pool-preview, .perf-pool-resolved .pool-preview { color: inherit; }
.m-remove { flex: 0 0 auto; width: 22px; height: 22px; line-height: 1; border: 1px solid var(--border); background: #fff; border-radius: 6px; cursor: pointer; color: var(--red); font-size: 15px; padding: 0; }
.m-remove:hover { border-color: var(--red); }
.hint { color: var(--red); font-size: 13px; margin: 0 0 10px; }
.perf-pool .btn-sm { margin-left: auto; }
.perf-pool .btn-primary { background: var(--blue); color: #fff; border-color: var(--blue); }
.perf-roles { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.perf-role { border: 1px solid var(--border); border-radius: 10px; padding: 12px; background: #fff; }
.perf-role-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.perf-role-label { font-weight: 600; min-width: 76px; }
.perf-role-ratio { display: inline-flex; align-items: center; gap: 2px; }
.perf-role-ratio input { width: 64px; }
.perf-role-pd { margin-left: auto; font-weight: 600; color: var(--blue-d); }
.perf-members { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.perf-member { display: flex; align-items: center; gap: 8px; }
.perf-member .m-name { flex: 1; min-width: 0; }
.perf-member .m-pd { width: 70px; }
.perf-member .m-res { min-width: 70px; text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
.perf-member .m-del { flex: 0 0 auto; width: 26px; height: 26px; line-height: 1; border: 1px solid var(--border); background: #fff; border-radius: 6px; cursor: pointer; color: var(--red); }
.perf-member .m-pct-wrap { display: inline-flex; align-items: center; gap: 4px; }
.perf-member .m-pct { width: 58px; text-align: right; padding: 2px 4px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; }
.perf-member .m-pct-unit { font-size: 12px; color: var(--muted); margin-left: -2px; }
.perf-member .m-pct-value { font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums; }
.perf-member .m-coeff-text { font-size: 12px; color: var(--muted); white-space: nowrap; min-width: 46px; text-align: right; }
.perf-member .pct-btn { width: 22px; height: 22px; line-height: 1; border: 1px solid var(--border); background: #fff; border-radius: 6px; cursor: pointer; font-size: 14px; padding: 0; color: var(--text); }
.perf-member .pct-btn:hover { border-color: var(--blue-d); color: var(--blue-d); }
.perf-add-member { font-size: 12px; color: var(--blue-d); background: none; border: none; cursor: pointer; padding: 2px 0; }

/* 绩效管理列表：成员人天明细 */
.perf-detail-row { display: flex; flex-wrap: wrap; gap: 6px 16px; justify-content: flex-start; }
.perf-detail-item { white-space: nowrap; font-size: 13px; }
.perf-done { color: #22c55e; font-weight: 700; }
.perf-pending { color: #f59e0b; font-weight: 700; }
.perf-neutral { color: var(--muted); font-weight: 600; }

/* 排期异常弱提示（需求阶段重叠状态展示方案 §6.4）：状态徽标下方的次级提示，视觉弱于主状态 */
.sched-hint { margin-top: 3px; font-size: 11px; line-height: 1.3; color: #b45309; white-space: nowrap; cursor: default; }
/* 方案 §9.3：并行进行中阶段（多个阶段排期重叠） */
.sched-hint.parallel { color: #7c3aed; }
.kanban-card .kc-parallel { margin-top: 5px; font-size: 11px; line-height: 1.3; color: #7c3aed; background: #f5f3ff; border: 1px solid #ddd6fe; border-radius: 4px; padding: 2px 6px; cursor: default; }

/* ===== 人员排行看板 ===== */
#view-ranking { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-ranking .rank-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
#view-ranking .ranking-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
#view-ranking .ranking-toolbar .spacer { flex: 1; }
.rank-tabs { display: inline-flex; gap: 4px; background: #f3f5fa; border-radius: 10px; padding: 3px; }
.rank-tab { border: none; background: transparent; padding: 6px 14px; border-radius: 8px; font-size: 13px; font-weight: 600; color: var(--muted); cursor: pointer; transition: color .15s ease, background .15s ease, box-shadow .15s ease; }
.rank-tab:hover { color: var(--text); }
.rank-tab.active { background: #fff; color: var(--blue-d); box-shadow: 0 1px 3px rgba(20,40,80,.10); }
.rank-summary { font-size: 13px; color: var(--muted); margin-left: auto; }
.rank-summary b { color: var(--blue-d); font-size: 15px; font-weight: 700; }
.rank-table-wrap { min-height: 0; overflow: visible; }

/* 人员排行 — 截图清爽表格 */
.rank-table { width: 100%; border-collapse: collapse; font-size: 13px; line-height: 1.4; color: var(--text); }
.rank-table thead th { position: sticky; top: 0; z-index: 5; padding: 10px 14px; font-weight: 600; font-size: 12px; color: var(--muted); background: #f7f9fd; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }
.rank-table thead th.th-rk { width: 56px; min-width: 56px; text-align: center; }
.rank-table thead th.th-pd { text-align: right; }
.rank-table thead th.th-bar { width: 42%; text-align: left; }
.rank-table tbody tr { border-bottom: 1px solid #f0f2f7; transition: background .12s ease; }
.rank-table tbody tr:hover { background: #f7f9fd; }
.rank-table tbody td { padding: 13px 14px; vertical-align: middle; white-space: nowrap; }
.rank-table td.rk { width: 56px; min-width: 56px; text-align: center; font-weight: 700; color: #98a2b3; font-size: 14px; }
.rank-table td.nm { font-weight: 600; color: var(--text); text-align: left; }
.rank-table td.role-cell { text-align: left; }
.rank-table td.pd { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text); }
.rank-table td.barcell { padding-right: 20px; text-align: left; }

.rank-bar { height: 10px; background: #f1f5f9; border-radius: 999px; overflow: hidden; }
.rank-bar-fill { height: 100%; background: var(--blue); border-radius: 999px; }
.rank-bar-fill.r-fill { background: var(--green); }
.rank-body .empty { padding: 40px; text-align: center; color: var(--muted); }
.role-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px; align-items: start; }
.role-panel { border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px; background: #fff; }
.role-panel-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.role-panel-head .count { margin-left: auto; font-size: 12px; color: var(--muted); }
.rank-role-wrap { min-height: 0; overflow: visible; }
.rank-role-wrap .rank-table thead th.th-bar { width: 30%; }

/* 角色徽标配色 — 截图色 */
.role-badge { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; white-space: nowrap; }
.role-badge.r-pm { background: #e8f0ff; color: #2f6fed; }
.role-badge.r-product { background: #fff1f0; color: #cf1322; }
.role-badge.r-frontend { background: #e6f6ec; color: #1f9d55; }
.role-badge.r-backend { background: #fff7e6; color: #d46b08; }
.role-badge.r-test { background: #fdecea; color: #e34d2c; }

/* ===== 需求看板（Kanban） ===== */
#view-kanban { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
#view-kanban .kanban-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
#view-kanban .kanban-toolbar .spacer { flex: 1; }
#view-kanban .kanban-toolbar input[type=text], #view-kanban .kanban-toolbar select { min-width: 160px; }
.kanban-board { flex: 1 1 auto; min-height: 0; display: flex; gap: 14px; overflow-x: auto; padding-bottom: 8px; }
.kanban-col { flex: 0 0 264px; min-width: 264px; display: flex; flex-direction: column; background: #f6f8fc; border: 1px solid var(--border); border-radius: 12px; max-height: 100%; }
.kanban-col.drag-over { border-color: var(--blue-d); box-shadow: 0 0 0 2px rgba(47,111,237,.15); }
.kanban-col-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid var(--border); font-weight: 600; }
.kanban-col-head .kc-count { background: #e6edff; color: var(--blue-d); border-radius: 999px; padding: 1px 9px; font-size: 12px; }
.kanban-col-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px; display: flex; flex-direction: column; gap: 10px; }
.kanban-card { background: #fff; border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; cursor: pointer; transition: box-shadow .15s, transform .15s; }
.kanban-card:hover { box-shadow: 0 4px 14px rgba(20,40,80,.12); transform: translateY(-1px); }
.kanban-card.dragging { opacity: .5; }
.kanban-card.paused { opacity: .72; border-style: dashed; }
.kanban-card .kc-no { font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.kanban-card .kc-name { font-weight: 600; line-height: 1.4; margin-bottom: 6px; }
.kanban-card .kc-meta { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--muted); }
.kanban-card .kc-prog { color: var(--blue-d); }
.kanban-empty { color: var(--muted); font-size: 12px; text-align: center; padding: 14px 0; }
.perf-detail-item b { color: var(--text); font-weight: 600; }

/* ---------- D06 分页条 ---------- */
.pager { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 10px 2px 2px; font-size: 13px; color: var(--muted); }
.pager-info { white-space: nowrap; }
.pager-info .pd-sum { margin-left: 16px; color: var(--blue-d); font-weight: 600; font-variant-numeric: tabular-nums; }
.pager-ctrl { display: flex; align-items: center; gap: 8px; }
.pager-ctrl label { display: flex; align-items: center; gap: 4px; margin: 0; font-size: 13px; color: var(--muted); }
.pager-ctrl select { padding: 3px 6px; font-size: 13px; }
.pager-ctrl button { min-width: 30px; }
.pager-ctrl button:disabled { opacity: .45; cursor: not-allowed; }
#projPageLabel, #fmPageLabel { min-width: 54px; text-align: center; color: var(--text); font-variant-numeric: tabular-nums; }

/* ---------- D09 勾选列 + 批量修改弹窗 ---------- */
.grid th.col-check, .grid td.col-check { width: 34px; min-width: 34px; text-align: center; padding-left: 6px; padding-right: 6px; }
.grid td.col-check input, .grid th.col-check input { cursor: pointer; width: 14px; height: 14px; }
.batch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px 14px; margin: 10px 0 4px; }
.batch-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); margin: 0; }
.batch-grid label.chk-inline { flex-direction: row; align-items: center; gap: 6px; }
.batch-preview { margin-top: 12px; }
.batch-summary { font-size: 13px; margin: 0 0 6px; color: var(--text); }
.batch-table-wrap { max-height: 320px; overflow: auto; border: 1px solid var(--border); border-radius: 6px; }
.batch-table-wrap table { font-size: 12px; }
.batch-preview .diff-old { color: var(--muted); text-decoration: line-through; }
.batch-preview .diff-new { color: var(--blue-d); font-weight: 600; }
.batch-preview .row-blocked td { background: #fdf2f2; }
.batch-preview .row-noop td { color: var(--muted); }
.batch-preview .err-cell { color: #b3261e; }
.text-warn { color: #a15c00; }

/* ---------- D04 脏日期告警标记 ---------- */
.cell-warn { color: #a15c00; background: #fff6e5; border-radius: 4px; padding: 1px 5px; white-space: nowrap; }

/* ============================================================
   项目概览 重设计 v2 — KPI 指标带 + 主题分区
   ============================================================ */
.ov-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 22px; }
.ov-header-main { min-width: 0; }
.ov-subtitle { margin: 0; font-size: 13px; color: var(--muted); }
.ov-header-filter { display: inline-flex; align-items: center; gap: 10px; }
.ov-header-filter label { font-size: 13px; color: var(--muted); white-space: nowrap; }
.ov-header-filter select { height: 36px; padding: 0 12px; border: 1px solid var(--border); border-radius: 8px; background: #fff; color: var(--text); font-size: 13px; min-width: 210px; }

.ov-zone { margin-bottom: 28px; }
.ov-zone--kpi { margin-bottom: 22px; }
.ov-zone-head { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; }
.ov-zone-bar { width: 4px; height: 16px; border-radius: 2px; background: linear-gradient(180deg, var(--blue) 0%, var(--blue-d) 100%); flex: 0 0 auto; }
.ov-zone-title { font-size: 16px; font-weight: 600; color: var(--text); margin: 0; letter-spacing: -0.01em; }

/* KPI 指标带 */
.ov-kpi-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.ov-kpi { position: relative; overflow: hidden; background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 18px 20px; box-shadow: 0 2px 8px rgba(20,30,60,0.04); transition: transform .18s ease, box-shadow .18s ease; }
.ov-kpi:hover { transform: translateY(-2px); box-shadow: 0 10px 24px rgba(20,30,60,0.09); }
.ov-kpi--primary { background: linear-gradient(135deg, #eef3ff 0%, #f8faff 100%); border-color: #d6e3ff; }
.ov-kpi--primary::after { content: ""; position: absolute; right: -22px; top: -22px; width: 92px; height: 92px; border-radius: 50%; background: radial-gradient(circle, rgba(47,111,237,0.14), transparent 70%); }
.ov-kpi--warn { background: linear-gradient(135deg, #fff7ec 0%, #fffdfa 100%); border-color: #f1ddbf; }
.ov-kpi-label { font-size: 20px; font-weight: 700; color: var(--muted); margin-bottom: 10px; letter-spacing: -0.01em; }
.ov-kpi-value { font-size: 40px; font-weight: 700; line-height: 1; color: var(--blue-d); letter-spacing: -0.02em; text-align: center; }
.ov-kpi--warn .ov-kpi-value { color: var(--amber); }
.ov-kpi-sub { font-size: 12px; color: var(--muted); margin-top: 7px; text-align: center; }

/* 通用卡片 + 两栏栅格 */
.ov-2col { display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 1fr); gap: 18px; align-items: stretch; }
.ov-2col > .ov-card { min-height: 0; }
/* 右侧阶段网格撑满卡片剩余高度，实现左右两卡等高 */
.ov-2col > .ov-card .ov-stage-one-row { flex: 1 1 auto; min-height: 0; }
.ov-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 16px 20px; box-shadow: 0 2px 8px rgba(20,30,60,0.04); display: flex; flex-direction: column; }
.ov-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.ov-card-title { font-size: 15px; font-weight: 600; color: var(--text); margin: 0; }
.ov-card-meta { font-size: 12px; color: var(--muted); background: #f3f5fa; padding: 3px 10px; border-radius: 999px; white-space: nowrap; }

/* 人员排行板块 — 白底内容框
   完整复用 .ov-card 规范（--panel 白底 / 14px 圆角 / 1px var(--border) 边框 /
   0 2px 8px rgba(20,30,60,.04) 阴影 / 16px 20px 内边距 / 继承全局字体），
   仅补充三条行为：高度随内容自适应、空态保持最小高度与留白、内容超出不出滚动条 */
.ov-card.ov-rank-card { min-height: 180px; min-width: 0; overflow: visible; }
.ov-card.ov-rank-card #rankingEmbed { display: block; min-width: 0; }
/* 排行区不设固定高度、不裁剪：行数多时整卡向下自然撑开，行数少/为空时保留最小留白 */
.ov-rank-card .rank-body { min-height: 96px; display: flex; flex-direction: column; justify-content: center; min-width: 0; }
.ov-rank-card .rank-table-wrap, .ov-rank-card .rank-role-wrap { overflow: visible; }
.ov-rank-card .rank-body .empty { margin: 0; }
.ov-rank-card .role-grid { width: 100%; }

@media (max-width: 1120px) {
  .ov-card.ov-rank-card { padding: 15px 16px; }
  .ov-rank-card .role-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
}
@media (max-width: 760px) {
  .ov-card.ov-rank-card { padding: 14px 12px; }
  .ov-rank-card .ranking-toolbar { gap: 8px; margin-bottom: 12px; }
  .ov-rank-card .rank-summary { margin-left: 0; }
  .ov-rank-card .rank-table thead th,
  .ov-rank-card .rank-table tbody td { padding-left: 8px; padding-right: 8px; }
  .ov-rank-card .rank-table td.barcell { padding-right: 8px; }
  .ov-rank-card .rank-table thead th.th-bar { width: 34%; }
}

/* 资源 chips */
.ov-res-chips { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 10px; }
.ov-res-chip { display: flex; flex-direction: column; gap: 5px; padding: 13px 8px; background: #f7f9fd; border: 1px solid var(--border); border-radius: 12px; text-align: center; transition: background .15s ease, border-color .15s ease; }
.ov-res-chip:hover { background: #eef3ff; border-color: #d6e3ff; }
.ov-res-num { font-size: 25px; font-weight: 700; color: var(--text); line-height: 1; }
.ov-res-role { font-size: 12px; color: var(--muted); }

/* 阶段卡在卡片内收敛间距（原 .overview-stage-grid 保留） */
.ov-card .overview-stage-grid { gap: 12px; }

/* 响应式 */
/* ≤1500px：资源卡与阶段卡上下堆叠，让阶段卡拿到整行宽度，仍保持一排 9 卡 */
@media (max-width: 1500px) {
  .ov-2col { grid-template-columns: minmax(0, 1fr); }
}
/* ≤1120px：阶段卡自动折行，避免单卡被压窄导致文字挤压 */
@media (max-width: 1120px) {
  .overview-stage-grid.ov-stage-one-row { grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); grid-template-rows: auto; }
}
@media (max-width: 980px) {
  .ov-kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ov-2col { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .ov-kpi-grid { grid-template-columns: minmax(0, 1fr); }
  .ov-header { align-items: flex-start; }
}

/* 未识别编号提示 Toast */
.unmatched-toast {
  position: fixed; top: 16px; left: 50%; transform: translateX(-50%);
  z-index: 10000; max-width: 520px; width: calc(100% - 32px);
  background: #fffbe6; border: 1px solid #ffe58f; border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,.12); padding: 12px 16px;
  font-size: 13px; color: #d48806; line-height: 1.6;
  animation: unmatchedSlideIn .25s ease-out;
}
.unmatched-toast .ut-title { font-weight: 600; margin-bottom: 4px; display: flex; align-items: center; gap: 6px; }
.unmatched-toast .ut-title::before { content: '!'; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; background: #faad14; color: #fff; border-radius: 50%; font-size: 12px; font-weight: 700; }
.unmatched-toast .ut-list { margin: 0; padding: 0 0 0 18px; }
.unmatched-toast .ut-list li { margin-bottom: 2px; word-break: break-all; }
.unmatched-toast .ut-close { float: right; cursor: pointer; background: none; border: none; font-size: 16px; color: #d48806; padding: 0 0 4px; line-height: 1; }
.unmatched-toast .ut-close:hover { color: #ad6803; }
@keyframes unmatchedSlideIn { from { opacity: 0; transform: translateX(-50%) translateY(-8px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }

/* 事故报告：故障影响卡片 + 长期方案附件 */
.inc-impact-card { background:#fafbff; border:1px solid #e6e8ef; border-radius:8px; padding:14px 16px; margin-bottom:12px; position:relative; }
.inc-impact-card .ic-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; }
.inc-impact-card .ic-head .ic-title { font-size:13px; font-weight:600; color:#1f3a8a; }
.inc-impact-card .ic-body .form-row { display:flex; flex-wrap:wrap; gap:14px; margin-bottom:8px; }
.inc-impact-card .ic-body .form-row label { flex:1 1 220px; min-width:200px; margin:0; display:flex; flex-direction:column; }
.inc-impact-card .ic-body .form-row label.full { flex:1 1 100%; }
.inc-impact-card .ic-body .form-row label > span { font-size:12px; color:#555; margin-bottom:4px; }
.inc-impact-card .ic-body .form-row input,
.inc-impact-card .ic-body .form-row textarea { width:100%; }
.inc-impact-card .ic-body .form-row textarea { min-height:72px; resize:vertical; }
.inc-impact-card .ic-del { position:absolute; top:10px; right:10px; }
.inc-attach-list { display:flex; flex-direction:column; gap:6px; margin:8px 0 10px; }
.inc-attach-item { display:flex; align-items:center; gap:8px; padding:6px 10px; background:#f4f6fb; border:1px solid #e6e8ef; border-radius:6px; font-size:13px; }
.inc-attach-item .ia-name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#1f3a8a; }
.inc-attach-item .ia-icon { color:#7b8aa6; font-size:12px; }
.inc-attach-item .ia-size { color:#999; font-size:12px; }
.inc-attach-item .ia-actions { display:flex; gap:4px; }
.inc-attach-item .ia-actions a, .inc-attach-item .ia-actions button { font-size:12px; padding:2px 8px; border-radius:4px; border:1px solid #d6dae4; background:#fff; color:#3a4256; cursor:pointer; text-decoration:none; }
.inc-attach-item .ia-actions a:hover, .inc-attach-item .ia-actions button:hover { background:#eef1f7; }
.inc-attach-item .ia-actions .ia-del { color:#c0392b; border-color:#f0c8c2; }
.inc-attach-item .ia-actions .ia-del:hover { background:#fceceb; }
.inc-attach-empty { font-size:12px; color:#999; padding:8px 0; }
.inc-attach-add { display:inline-block; }

/* 事故报告：关联需求检索下拉（高对比度、强可辨识、关键词高亮） */
.inc-req-dd { position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:9999; background:#fff; border:1.5px solid #1f3a8a; border-radius:6px; box-shadow:0 6px 18px rgba(31,58,138,.18); max-height:280px; overflow-y:auto; padding:4px 0; }
.inc-req-dd .inc-req-opt { display:flex; align-items:baseline; gap:8px; padding:9px 14px; font-size:13.5px; line-height:1.5; color:#1f3a8a; cursor:pointer; border-bottom:1px solid #f0f2f7; transition:background .12s ease; }
.inc-req-dd .inc-req-opt:last-child { border-bottom:none; }
.inc-req-dd .inc-req-opt:hover, .inc-req-dd .inc-req-opt.is-active { background:#eef2fb; color:#0c2161; }
.inc-req-dd .inc-req-opt .ir-no { font-weight:700; color:#0c2161; font-size:13.5px; flex-shrink:0; }
.inc-req-dd .inc-req-opt .ir-dot { color:#9aa3b8; flex-shrink:0; }
.inc-req-dd .inc-req-opt .ir-name { color:#3a4256; font-size:13px; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.inc-req-dd .inc-req-opt .ir-type { font-size:11.5px; color:#fff; background:#5b6db5; padding:1px 7px; border-radius:10px; flex-shrink:0; }
.inc-req-dd .inc-req-opt em.kw { background:#fff3a3; color:#c0392b; font-style:normal; font-weight:700; padding:0 2px; border-radius:2px; box-shadow:inset 0 -1px 0 #f1c40f; }
.inc-req-dd .inc-req-empty { padding:14px; font-size:13px; color:#888; text-align:center; }
.inc-req-wrap { position:relative; }

/* DMS 级联：一级菜单可搜索下拉 */
.dms-search-wrap { position:relative; }
.dms-search-wrap input[type="text"] { width:100%; box-sizing:border-box; }
.dms-search-dd { position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:9999; background:#fff; border:1.5px solid #1f3a8a; border-radius:6px; box-shadow:0 6px 18px rgba(31,58,138,.18); max-height:280px; overflow-y:auto; padding:4px 0; display:none; }
.dms-search-dd .dms-search-opt { padding:9px 14px; font-size:13.5px; line-height:1.5; color:#1f3a8a; cursor:pointer; border-bottom:1px solid #f0f2f7; transition:background .12s ease; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dms-search-dd .dms-search-opt:last-child { border-bottom:none; }
.dms-search-dd .dms-search-opt:hover, .dms-search-dd .dms-search-opt.is-active { background:#eef2fb; color:#0c2161; }
.dms-search-dd .dms-search-empty { padding:14px; font-size:13px; color:#888; text-align:center; }

/* ============================================================
   项目公告（Announcement）：左列表 + 右详情/整页编辑器
   视觉对齐原型（简约高级蓝），并复用平台 .panel/.btn-* 体系
   ============================================================ */
/* 公告视图整页满屏：公告激活时 #app 变 flex 列并占满视口（height:100vh），
   main 占满 tabs 以下区域（flex:1），#view-announcement 直接填充 main。
   上沿天然紧贴 tabs 底部、下沿贴视口底——零 JS 测量、零留白、零截断。非 Fullscreen API。 */
#view-announcement {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: #fff;
  padding: 0;
  margin: 0;
}
#app.ann-active { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
#app.ann-active main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 0; }
.ann-toolbar { gap:10px; align-items:center; }
.ann-layout { flex:1; min-height:0; display:flex; align-items:stretch; }

/* 响应式：平板竖屏/手机下左右栏上下堆叠，保持整页满屏、不横向挤压、不截断 */
@media (max-width: 820px) {
  .ann-layout { flex-direction: column; }
  .ann-left { width:auto; flex:0 0 auto; max-height:38vh; border-right:none; border-bottom:1px solid var(--border,#e5e6eb); }
  .ann-right { flex:1; min-height:0; }
  .ann-right-inner { padding:18px 16px; }
  .editor-wrap.page-mode .edit-head,
  .editor-wrap.page-mode .toolbar,
  .editor-wrap.page-mode .ann-cat-row,
  .ann-ql-toolbar.ql-toolbar.ql-snow { padding-left:16px; padding-right:16px; }
  .ann-quill-host .ql-editor { padding:18px 16px; }
}

/* 左侧公示栏 */
.ann-left { width:360px; flex-shrink:0; background:var(--panel,#fff); border-right:1px solid var(--border,#e5e6eb); display:flex; flex-direction:column; min-height:0; overflow:hidden; }
.ann-left-head { padding:16px 16px 12px; border-bottom:1px solid #eef0f3; flex-shrink:0; position:sticky; top:0; z-index:2; background:var(--panel,#fff); }
.ann-left-title { font-size:15px; font-weight:600; margin-bottom:12px; display:flex; align-items:center; gap:8px; color:#1f2329; }
.ann-left-title .ann-dot { width:7px; height:7px; border-radius:50%; background:#3056d3; }
.ann-search input { width:100%; height:36px; border:1px solid var(--border,#e5e6eb); border-radius:8px; padding:0 12px; font-size:13px; background:#fafbfc; outline:none; transition:.15s; box-sizing:border-box; }
.ann-search input:focus { border-color:#3056d3; background:#fff; box-shadow:0 0 0 3px #eaf0ff; }
.ann-add-btn { margin-top:12px; width:100%; height:38px; border:none; border-radius:8px; background:#3056d3; color:#fff; font-size:13.5px; font-weight:600; cursor:pointer; display:flex; align-items:center; justify-content:center; gap:6px; transition:.15s; }
.ann-add-btn:hover { background:#2748bd; }
.ann-list { flex:1; overflow-y:auto; padding:8px; list-style:none; margin:0; }
.ann-item { padding:12px 14px; border-radius:8px; cursor:pointer; margin-bottom:4px; position:relative; border:1px solid transparent; transition:.12s; }
.ann-item:hover { background:#f2f3f5; }
.ann-item.active { background:#eaf0ff; border-color:#cfe0ff; }
.ann-item.active::before { content:""; position:absolute; left:0; top:10px; bottom:10px; width:3px; border-radius:3px; background:#3056d3; }
.ann-it-title { font-size:14px; font-weight:600; color:#1f2329; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-bottom:6px; }
.ann-it-meta { font-size:12px; color:#8a919f; display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.ann-it-top { font-size:11px; color:#3056d3; background:#eaf0ff; padding:1px 6px; border-radius:4px; margin-left:auto; font-weight:600; }

/* 右侧内容区 */
.ann-right { flex:1; min-width:0; min-height:0; display:flex; flex-direction:column; background:#f5f6f8; overflow:hidden; }
/* 详情态与编辑页同宽：撑满右侧面板（原 max-width:920px + margin:0 auto 会把内容夹窄居中，导致左右大片留白）。
   左右内边距与编辑页 .edit-head/.edit-area/.edit-foot 的 36px 对齐，两页左右边缘完全一致。 */
.ann-right-inner { flex:1; overflow-y:auto; padding:28px 36px; width:100%; box-sizing:border-box; }
.ann-view-head { display:flex; align-items:flex-start; gap:16px; margin-bottom:8px; }
.ann-view-head h1 { font-size:24px; font-weight:700; line-height:1.35; flex:1; margin:0; color:#1f2329; }
.ann-view-meta { color:#8a919f; font-size:13px; margin-bottom:18px; display:flex; gap:18px; align-items:center; flex-wrap:wrap; }
.ann-view-meta .who { display:flex; align-items:center; gap:7px; }
.ann-view-meta .mini-avatar { width:22px; height:22px; border-radius:50%; background:#c9d2e3; color:#fff; display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:600; }
.ann-view-meta .ann-pinned { color:#3056d3; font-weight:600; }
.ann-divider { height:1px; background:#e5e6eb; margin:18px 0; }

/* 富文本正文渲染（与白名单一致） */
.ann-content { font-size:14.5px; color:#2b2f36; line-height:1.85; word-break:break-word; }
.ann-content h1, .ann-content h2, .ann-content h3 { margin:18px 0 10px; line-height:1.4; }
.ann-content h1 { font-size:21px; } .ann-content h2 { font-size:18px; } .ann-content h3 { font-size:16px; }
.ann-content p { margin:10px 0; }
.ann-content ul, .ann-content ol { margin:10px 0 10px 22px; padding-left:4px; }
.ann-content li { margin:4px 0; }
.ann-content blockquote { margin:12px 0; padding:10px 16px; border-left:3px solid #3056d3; background:#f7f9ff; color:#646a73; border-radius:0 6px 6px 0; }
.ann-content a { color:#3056d3; text-decoration:none; }
.ann-content a:hover { text-decoration:underline; }
.ann-content hr { border:none; border-top:1px solid #e5e6eb; margin:18px 0; }
.ann-content pre { background:#1f2329; color:#e6e6e6; padding:14px 16px; border-radius:8px; overflow:auto; font-size:13px; margin:12px 0; }
.ann-content pre code { font-family:"SFMono-Regular",Consolas,monospace; }
.ann-content code { background:#f0f1f3; padding:2px 6px; border-radius:4px; font-size:13px; font-family:"SFMono-Regular",Consolas,monospace; color:#c0341d; }

/* 空态 */
.ann-empty { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; color:#8a919f; gap:14px; min-height:300px; }
.ann-empty-ic { width:64px; height:64px; border-radius:16px; background:#eceef2; display:flex; align-items:center; justify-content:center; color:#8a919f; }
.ann-empty p { font-size:14px; }

/* 编辑态：整页编辑器（page-mode），标题/工具栏/编辑区/底栏同屏 */
.ann-right-inner.editing { padding:0; display:flex; flex-direction:column; overflow:hidden; max-width:none; }
.editor-wrap.page-mode { border:none; border-radius:0; box-shadow:none; flex:1; min-height:0; display:flex; flex-direction:column; background:#fff; overflow:hidden; }
.editor-wrap.page-mode .edit-head { padding:18px 36px; border-bottom:1px solid #eef0f3; flex-shrink:0; }
.editor-wrap.page-mode .edit-title-input { width:100%; border:none; outline:none; font-size:20px; font-weight:700; color:#1f2329; padding:4px 0; background:transparent; }
.editor-wrap.page-mode .edit-title-input::placeholder { color:#8a919f; font-weight:600; }
.editor-wrap.page-mode .toolbar { padding:8px 36px; border-bottom:1px solid #eef0f3; flex-wrap:wrap; background:#fbfcfd; flex-shrink:0; }
.editor-wrap.page-mode .edit-area { flex:1; min-height:0; overflow-y:auto; padding:22px 36px; font-size:14.5px; line-height:1.85; color:#2b2f36; outline:none; }
.editor-wrap.page-mode .edit-area:empty::before { content:attr(data-ph); color:#8a919f; }
.editor-wrap.page-mode .edit-foot { padding:14px 36px; border-top:1px solid #eef0f3; display:flex; align-items:center; gap:10px; flex-shrink:0; }
.ann-top-chk { font-size:13px; color:#646a73; display:flex; align-items:center; gap:6px; cursor:pointer; }
.editor-wrap.fullscreen { position:fixed; inset:16px; z-index:99; border-radius:14px; background:#fff; box-shadow:0 12px 48px rgba(0,0,0,.25); }

/* 工具栏（与平台风格一致） */
.editor-wrap .toolbar { display:flex; align-items:center; gap:2px; }
.editor-wrap .toolbar select { height:32px; border:1px solid #e5e6eb; border-radius:6px; background:#fff; font-size:13px; padding:0 8px; color:#646a73; cursor:pointer; outline:none; margin-right:6px; }
.editor-wrap .tbtn { width:32px; height:32px; border:none; background:transparent; border-radius:6px; cursor:pointer; display:flex; align-items:center; justify-content:center; color:#646a73; transition:.12s; position:relative; }
.editor-wrap .tbtn:hover { background:#f2f3f5; color:#1f2329; }
.editor-wrap .tbtn svg { width:18px; height:18px; }
.editor-wrap .tbtn b { font-size:14px; font-weight:800; }
.editor-wrap .tbtn i { font-style:italic; font-size:14px; }
.editor-wrap .tbtn s { font-size:14px; }
.editor-wrap .tbtn .color-a { font-size:14px; font-weight:700; text-decoration:underline; text-decoration-color:#3056d3; text-decoration-thickness:3px; color:#1f2329; }
.editor-wrap .tsep { width:1px; height:20px; background:#e5e6eb; margin:0 5px; }
.editor-wrap .color-picker { position:absolute; opacity:0; width:0; height:0; pointer-events:none; }

/* 编辑/详情按钮放行平台 .btn-* 体系（已有定义，这里仅补间距） */
.ann-view-head .ops .btn-ghost, .ann-view-head .ops .btn-danger { margin-left:0; }

/* ============ 项目公告 V1.1：分类标签 / Quill 编辑器 / 正文图片 ============ */
/* 分类下拉：列表筛选（左栏）与编辑区（右栏） */
.ann-cat-filter { margin-top:10px; width:100%; height:34px; border:1px solid var(--border,#e5e6eb); border-radius:8px; padding:0 10px; font-size:13px; background:#fafbfc; color:#646a73; outline:none; box-sizing:border-box; cursor:pointer; }
.ann-cat-filter:focus { border-color:#3056d3; background:#fff; }
.ann-cat-row { display:flex; align-items:center; gap:8px; padding:12px 36px; border-bottom:1px solid #eef0f3; background:#fbfcfd; }
.ann-cat-row select { height:32px; border:1px solid #e5e6eb; border-radius:6px; background:#fff; font-size:13px; padding:0 8px; color:#646a73; cursor:pointer; outline:none; }

/* 分类标签：五类配色，弱化饱和以贴合简约风格 */
.ann-tag { font-size:11px; font-weight:600; line-height:1.7; padding:1px 7px; border-radius:4px; white-space:nowrap; }
.ann-tag.cat-release { color:#1a56b8; background:#e8f0fe; }
.ann-tag.cat-outage { color:#a8321f; background:#fdeceb; }
.ann-tag.cat-policy { color:#7a5200; background:#fdf3e2; }
.ann-tag.cat-risk    { color:#a01f7a; background:#fdeaf6; }
.ann-tag.cat-other   { color:#5c6470; background:#f0f1f3; }

/* 正文图片自适应（含 Quill 编辑区内） */
.ann-content img, .ann-quill-host .ql-editor img { max-width:100%; height:auto; display:block; }
/* 文本对齐：只有编辑区在 .ql-editor 作用域内，详情只读视图需单独覆盖 */
.ann-content .ql-align-left    { text-align:left; }
.ann-content .ql-align-center  { text-align:center; }
.ann-content .ql-align-right   { text-align:right; }
.ann-content .ql-align-justify { text-align:justify; }
.ann-content img { border-radius:8px; margin:10px 0; }

/* Quill 工具栏：对齐平台 .toolbar 观感（覆盖 snow 主题默认边框与间距） */
.ann-ql-toolbar.ql-toolbar.ql-snow { display:flex; align-items:center; gap:2px; flex-wrap:wrap; padding:8px 36px; margin:0; border:0; border-bottom:1px solid #eef0f3; background:#fbfcfd; box-sizing:border-box; font-family:inherit; }
.ann-ql-toolbar.ql-snow .ql-formats { margin-right:6px; display:flex; align-items:center; gap:2px; }
.ann-ql-toolbar.ql-snow button { width:32px; height:32px; padding:5px; border:none; border-radius:6px; background:transparent; float:none; }
.ann-ql-toolbar.ql-snow button:hover { background:#f2f3f5; }
.ann-ql-toolbar.ql-snow button.ql-active { background:#eaf0ff; }
.ann-ql-toolbar.ql-snow button .ql-stroke { stroke:#646a73; }
.ann-ql-toolbar.ql-snow button:hover .ql-stroke,
.ann-ql-toolbar.ql-snow button.ql-active .ql-stroke { stroke:#1f2329; }
.ann-ql-toolbar.ql-snow button .ql-fill { fill:#646a73; }
.ann-ql-toolbar.ql-snow button:hover .ql-fill,
.ann-ql-toolbar.ql-snow button.ql-active .ql-fill { fill:#1f2329; }
.ann-ql-toolbar.ql-snow .ql-picker-label { border:1px solid #e5e6eb; border-radius:6px; height:32px; padding:0 8px; display:flex; align-items:center; color:#646a73; font-size:13px; }
.ann-ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label { border-color:#3056d3; }
.ann-ql-toolbar.ql-snow .ql-picker-options { border:1px solid #e5e6eb; border-radius:8px; box-shadow:0 6px 20px rgba(0,0,0,.08); padding:6px; background:#fff; }
.ann-ql-toolbar.ql-snow .tsep { width:1px; height:20px; background:#e5e6eb; margin:0 5px; flex:0 0 auto; }

/* Quill 编辑区：撑满整页编辑器剩余高度 */
.ann-quill-host { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
.ann-quill-host .ql-container.ql-snow { flex:1 1 auto; min-height:0; border:0; font-family:inherit; font-size:14.5px; }
.ann-quill-host .ql-editor { flex:1 1 auto; min-height:240px; overflow-y:auto; padding:22px 36px; line-height:1.85; color:#2b2f36; }
.ann-quill-host .ql-editor.ql-blank::before { content:attr(data-placeholder); color:#8a919f; font-style:normal; }
.ann-quill-host .ql-editor pre.ql-syntax { background:#1f2329; color:#e6e6e6; border-radius:8px; padding:12px 16px; }
.ann-quill-host .ql-editor blockquote { border-left:3px solid #3056d3; background:#f7f9ff; border-radius:0 6px 6px 0; }
.editor-wrap.fullscreen .ann-quill-host .ql-editor { min-height:0; }
#annUploadHint { margin-right:4px; }

/* 问题跟进：事项处理人多选（人员清单） */
.people-ms { position: relative; }
.pm-control { min-height: 38px; border: 1px solid #d9dee7; border-radius: 6px; padding: 5px 8px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; cursor: text; background: #fff; }
.pm-control:focus-within { border-color: #3056d3; box-shadow: 0 0 0 3px rgba(48,86,211,.12); }
.pm-ph { color: #aab2bf; font-size: 13px; }
.pm-chip { display: inline-flex; align-items: center; gap: 5px; background: #eaf1ff; color: #3056d3; border-radius: 20px; padding: 2px 6px 2px 10px; font-size: 12px; }
.pm-chip button { border: none; background: transparent; color: #3056d3; cursor: pointer; font-size: 12px; line-height: 1; }
.pm-panel { position: absolute; top: calc(100% + 5px); left: 0; right: 0; background: #fff; border: 1px solid #e8ecf3; border-radius: 6px; box-shadow: 0 6px 24px rgba(20,30,50,.12); padding: 8px; z-index: 30; }
.pm-search { width: 100%; border: 1px solid #d9dee7; border-radius: 5px; padding: 7px 9px; font-size: 12.5px; margin-bottom: 6px; outline: none; box-sizing: border-box; }
.pm-search:focus { border-color: #3056d3; }
.pm-list { max-height: 180px; overflow: auto; }
.pm-opt { display: flex; align-items: center; gap: 9px; padding: 7px 8px; border-radius: 5px; cursor: pointer; font-size: 13px; }
.pm-opt:hover { background: #f2f5fa; }
.pm-opt.sel { background: #eaf1ff; color: #3056d3; font-weight: 600; }
.pm-dot { width: 14px; height: 14px; border-radius: 4px; border: 1.5px solid #c9d2e0; flex: none; }
.pm-opt.sel .pm-dot { background: #3056d3; border-color: #3056d3; }

/* 问题跟进：多图上传（截图，支持粘贴/动态增删） */
.img-multi { width: 100%; }
.img-gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 10px; }
.img-slot { height: 120px; }
.img-slot-box { position: relative; width: 100%; height: 100%; border: 1px solid #e8ecf3; border-radius: 8px; overflow: hidden; cursor: pointer; background: #f7f8fd; }
.img-slot-box img { width: 100%; height: 100%; object-fit: cover; display: block; }
.img-del { position: absolute; top: 5px; right: 5px; width: 20px; height: 20px; border: none; border-radius: 50%; background: rgba(20,24,38,.55); color: #fff; cursor: pointer; font-size: 12px; line-height: 20px; }
.img-add-slot { height: 120px; border: 1.5px dashed #c9cfe0; border-radius: 8px; color: #5b6573; font-size: 14px; cursor: pointer; display: flex; align-items: center; justify-content: center; text-align: center; padding: 6px; background: #fff; }
.img-add-slot:hover { border-color: #3056d3; background: #eaf1ff; color: #3056d3; }
