/* ============================================================
   梯诺士项目制经营管理系统 V2 · 设计系统（iOS 磨砂玻璃）
   零外部依赖：无 CDN、无构建链，可离线内网运行
   ============================================================ */
:root{
  /* 玻璃与光感 */
  --glass-bg: rgba(255,255,255,.62);
  --glass-bg-2: rgba(255,255,255,.42);
  --glass-border: rgba(255,255,255,.70);
  --glass-shadow: 0 8px 32px rgba(31,45,61,.10);
  --glass-shadow-hover: 0 12px 40px rgba(31,45,61,.16);
  --blur: saturate(180%) blur(20px);

  /* 底色：多层柔光渐变 */
  --bg:
    radial-gradient(1200px 600px at 8% -10%, #dbeafe 0%, transparent 60%),
    radial-gradient(900px 500px at 100% 0%, #ffe7e0 0%, transparent 55%),
    linear-gradient(180deg,#f7f9fc 0%,#eef2f7 100%);

  /* 文本与语义色 */
  --text-1:#1f2d3d; --text-2:#5b6b7f; --text-3:#8a94a6;
  --brand:#2f6fed; --brand-2:#1d5fd8;
  --ok:#237804; --ok-bg:rgba(35,120,4,.10);
  --warn:#d48806; --warn-bg:rgba(212,136,6,.12);
  --danger:#d4380d; --danger-bg:rgba(212,56,13,.10);
  /* 卡点标贴（黄）：--warn 是琥珀色 #d48806，低透明度下发米/咖色，读不出「黄」
     ⇒ 单独定义一对令牌供 .tag.blocker 使用（浅色：浅黄底 + 暗金字，对比度 ≈5:1） */
  --blocker-bg:rgba(255,214,20,.38); --blocker-fg:#7a5d00;
  /* 直接立项（提交）按钮专用紫：与默认蓝 / 幽灵灰 / 危险红明确区分 */
  --purple:#722ed1; --purple-2:#531dab;
  --line:rgba(31,45,61,.10);

  /* 形状与动效 */
  --r-sm:10px; --r-md:14px; --r-lg:18px; --r-xl:24px;
  --sp:4px;
  --ease: cubic-bezier(.4,0,.2,1);
  --dur:.22s;
  /* 品牌红（梯诺士官方：#CD0E0E/#C00000）——仅用于 Logo 与品牌字标；UI 主色仍用蓝 */
  --brand-red:#CD0E0E;
  /* 紧凑间距刻度（解决板块不对齐 / 密度差） */
  --s1:6px; --s2:10px; --s3:14px; --s4:18px; --s5:24px;
  --maxw:1200px;
}

@media (prefers-color-scheme: dark){
  :root{
    --glass-bg: rgba(28,32,40,.55);
    --glass-bg-2: rgba(28,32,40,.38);
    --glass-border: rgba(255,255,255,.12);
    --glass-shadow: 0 8px 32px rgba(0,0,0,.45);
    --glass-shadow-hover: 0 12px 40px rgba(0,0,0,.55);
    --bg:
      radial-gradient(1200px 600px at 8% -10%, #1b2a4a 0%, transparent 60%),
      radial-gradient(900px 500px at 100% 0%, #3a2430 0%, transparent 55%),
      linear-gradient(180deg,#12161c 0%,#0d1116 100%);
    --text-1:#eef2f7; --text-2:#a9b4c4; --text-3:#7d8899;
    --line:rgba(255,255,255,.10);
    --brand:#5b93f5; --brand-2:#7aa8f8;
    --ok:#73d13d; --warn:#ffc53d; --danger:#ff7875;
    --brand-red:#ff5a5a;
    --blocker-bg:rgba(255,197,61,.22); --blocker-fg:#ffc53d;
  }
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  font-family:-apple-system,"SF Pro Text","PingFang SC","Microsoft YaHei",sans-serif;
  background:var(--bg); background-attachment:fixed;
  color:var(--text-1); font-size:14px; line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}

/* —— 毛玻璃卡片 —— */
.glass{
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  border-radius:var(--r-lg);
  box-shadow:var(--glass-shadow);
  -webkit-backdrop-filter:var(--blur); backdrop-filter:var(--blur);
  transition:box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
/* 降级：不支持毛玻璃时用实色，保证可读性 */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){
  .glass{background:rgba(255,255,255,.94)}
  @media (prefers-color-scheme: dark){ .glass{background:rgba(24,28,34,.96)} }
}

/* —— 顶栏 —— */
.topbar{
  position:sticky; top:0; z-index:50;
  display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap;
  padding:12px 22px;
  background:var(--glass-bg-2);
  border-bottom:1px solid var(--glass-border);
  -webkit-backdrop-filter:var(--blur); backdrop-filter:var(--blur);
}
.brand{font-weight:700;font-size:16px;letter-spacing:.2px;display:flex;align-items:center;gap:10px;min-width:0}
.brand .ver{font-size:11px;font-weight:600;color:var(--text-3);border:1px solid var(--line);padding:1px 6px;border-radius:8px}
.brand .brand-name{font-size:15px;font-weight:700;letter-spacing:.2px;color:var(--text-1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.nav{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.nav a{padding:6px 11px;border-radius:var(--r-sm);color:var(--text-2);font-size:13px}
.nav a:hover{background:rgba(47,111,237,.10);color:var(--brand);text-decoration:none}
.nav a.hl{background:var(--brand);color:#fff}
.nav a.hl:hover{background:var(--brand-2);color:#fff}
/* 单一导航栏内的分组分隔线（SOP 业务主线 ｜ 管理组） */
.nav-sep{width:1px;height:18px;background:var(--line);margin:0 4px;flex:none}
.who{font-size:12px;color:var(--text-3);padding-left:8px;border-left:1px solid var(--line)}

/* —— 布局 —— */
.wrap{max-width:1180px;margin:22px auto 60px;padding:0 20px}
.page-title{display:flex;align-items:baseline;justify-content:space-between;margin:0 0 14px}
.page-title h1{margin:0;font-size:20px;font-weight:700}
.page-title .sub{color:var(--text-3);font-size:12px}
.grid{display:grid;gap:16px}
.cols-4{grid-template-columns:repeat(4,1fr)}
.cols-3{grid-template-columns:repeat(3,1fr)}
.cols-2{grid-template-columns:1fr 1fr}
@media (max-width:900px){ .cols-4{grid-template-columns:repeat(2,1fr)} .cols-3,.cols-2{grid-template-columns:1fr} }

.panel{padding:18px 20px;margin-bottom:16px}
.panel h2{margin:0 0 12px;font-size:15px;font-weight:650}
.panel h2 .hint{font-weight:400;color:var(--text-3);font-size:12px;margin-left:8px}

/* —— 指标卡 —— */
.stat{padding:16px 18px}
.stat .n{font-size:26px;font-weight:700;font-variant-numeric:tabular-nums}
.stat .l{font-size:12px;color:var(--text-3);margin-top:2px}
.stat.ok .n{color:var(--ok)} .stat.warn .n{color:var(--warn)} .stat.danger .n{color:var(--danger)}
.stat .n.accent{color:var(--brand)}

/* —— 按钮 —— */
.btn{
  display:inline-flex;align-items:center;gap:6px;
  padding:8px 16px;border:1px solid transparent;border-radius:var(--r-sm);
  background:var(--brand);color:#fff;font-size:13px;font-family:inherit;cursor:pointer;
  transition:background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn:hover{background:var(--brand-2)}
.btn:active{transform:scale(.985)}
.btn.ghost{background:transparent;border-color:var(--line);color:var(--text-2)}
.btn.ghost:hover{background:rgba(47,111,237,.08);color:var(--brand)}
.btn.danger{background:var(--danger)}
.btn.danger:hover{filter:brightness(.92)}
.btn.commit{background:var(--purple)}
.btn.commit:hover{background:var(--purple-2)}
.btn.sm{padding:5px 11px;font-size:12px;border-radius:8px}
.btn[disabled]{opacity:.5;cursor:not-allowed}

/* —— 表单 —— */
.form-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px 16px}
@media (max-width:900px){ .form-grid{grid-template-columns:1fr} }
.field{display:flex;flex-direction:column;gap:5px}
.field.full{grid-column:1/-1}
label{font-size:12px;color:var(--text-2);font-weight:600}
label .req{color:var(--danger);margin-left:2px}
input,select,textarea{
  width:100%;padding:8px 10px;font-size:13px;font-family:inherit;
  color:var(--text-1);background:rgba(255,255,255,.72);
  border:1px solid var(--line);border-radius:var(--r-sm);outline:none;
  transition:border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
input:focus,select:focus,textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px rgba(47,111,237,.16)}
@media (prefers-color-scheme: dark){ input,select,textarea{background:rgba(255,255,255,.06)} }
.form-foot{display:flex;align-items:center;gap:10px;margin-top:14px}

/* —— 弹窗（原生 dialog，玻璃拟态；零 JS 依赖）—— */
dialog.sheet{
  border:none;padding:0;background:transparent;
  width:min(1080px,94vw);max-height:88vh;overflow:auto;
}
dialog.sheet::backdrop{background:rgba(15,23,42,.44);backdrop-filter:blur(6px)}
dialog.sheet .frow{background:var(--glass-bg-2)}

/* —— 表格 —— */
.table-wrap{overflow:auto;border-radius:var(--r-md)}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{padding:9px 10px;text-align:left;border-bottom:1px solid var(--line);white-space:nowrap}
th{color:var(--text-3);font-weight:600;font-size:12px;background:var(--glass-bg-2);position:sticky;top:0}
tbody tr:hover{background:rgba(47,111,237,.05)}
td.num{text-align:right;font-variant-numeric:tabular-nums}

/* —— 进度评审表（执行过程页）：整表左对齐 + 整排宽的反馈填写行 ——
   2026-09-26（第 3 轮 UI 优化）
   ① 左对齐：`th,td` 默认已是 left，但 `td.num` 是 right（旧「轮次」列用的是 .num）⇒ 必须覆盖；
   ② `.fb-row` = 挂在评审行下方的整排表单行，让「项目跟进过程详细反馈」框与整排等宽。 */
.rev-table th,.rev-table td,.rev-table td.num{text-align:left}
.rev-table tr.fb-row > td{padding:2px 10px 12px;white-space:normal;background:rgba(47,111,237,.035)}
/* 版式（第 3 轮定稿）：文本框**独占一行**并与整排等宽；日期 + 提交按钮另起一行。
   ⚠ 不要把日期/按钮与文本框挤在同一 flex 行 —— 那样文本框只占剩余宽度（实测仅 836/1098px = 76%）。 */
.fb-form{display:flex;flex-direction:column;gap:8px}
.fb-form textarea{width:100%}
.fb-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}

/* —— 第 4 轮新增：引用 / 新建 / 修改 / 归档（需求②③④⑤）—— */
/* 被「引用」命中的评审行高亮（?quote=N 跳转落点） */
.rev-table tr.rev-hit > td{background:rgba(47,111,237,.07)}
.rev-table td.rev-act{white-space:normal}
.rev-act-in{display:flex;flex-direction:column;gap:4px;align-items:flex-start}
.rev-left{font-size:11px;color:var(--warn)}
.rev-left.frozen{color:var(--text-3)}

/* 只读引用块。D1 = 真引用：原文由服务端渲染、**不进 textarea**（物理上不可能被改写）；
   因此 `.fb-quote` 只需要断行保护 —— 过程记录正文同样可能是 763 字无空白长串。 */
.fb-quote{margin:0 0 8px;padding:6px 10px;border-left:2px solid var(--brand);
  background:rgba(47,111,237,.05);border-radius:0 var(--r-sm) var(--r-sm) 0;
  font-size:12px;line-height:1.7;color:var(--text-2);
  white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}
.fb-quote .q-h{display:block;font-size:11px;color:var(--brand);margin-bottom:2px}

/* 「修改反馈」折叠：summary 即按钮、展开后是**整排宽**表单（零 JS、无弹窗依赖） */
.fb-details > summary{cursor:pointer;display:inline-block;list-style:none;font-size:12px;
  padding:2px 10px;border:1px solid var(--glass-border);border-radius:var(--r-sm);color:var(--text-2)}
.fb-details > summary::-webkit-details-marker{display:none}
.fb-details[open] > summary{margin-bottom:8px}
/* 60 分钟窗口归零：前端冻结按钮（服务端 `is_history_review` 仍是唯一权威）
   ⚠ `pointer-events:none` 是必需的 —— 只改 cursor/opacity 拦不住点击。 */
.fb-details.fb-frozen > summary{cursor:not-allowed;opacity:.55;pointer-events:none}

/* 「＋ 新建评审」内联表单（零 JS、无障碍） */
.rev-new{margin:0 0 12px;font-size:12.5px}
.rev-new > summary{cursor:pointer;display:inline-block;list-style:none;font-size:12px;
  padding:3px 10px;border:1px solid var(--glass-border);border-radius:var(--r-sm);color:var(--text-2)}
.rev-new > summary::-webkit-details-marker{display:none}
.rev-new[open] > summary{margin-bottom:10px}

/* 超限提醒弹窗（原生 <dialog>，零依赖、零 CDN） */
.fb-overlay{border:none;border-radius:14px;padding:0;max-width:440px;width:calc(100% - 32px);
  background:var(--glass-bg-1,#fff);box-shadow:0 20px 55px rgba(16,24,40,.24)}
.fb-overlay::backdrop{background:rgba(16,24,40,.34)}
.fb-dialog{padding:18px 20px}
.fb-dialog h3{margin:0 0 8px;font-size:15px;font-weight:650;color:var(--text-1)}
.fb-dialog p{margin:0 0 14px;font-size:13px;line-height:1.75;color:var(--text-3)}
.fb-dialog-foot{display:flex;justify-content:flex-end}
/* ── 长文本单元格（8 个模板共 11 处使用）────────────────────────────────
   2026-09-26 修复「项目池 → 来源卡点/项目内容」内容超出单元格：
   原写法 `white-space:normal` 只在**空格 / 连字符**处断行，对
   `test003test003…`、URL、长编码、长英文单词这类**无断点长串完全无效**
   ⇒ 只能排成一行。真机实测（Chrome 1440px）：763 字符 = 4996.9px 宽，
     溢出单元格 4687px，压住右侧「状态」徽标；且把整表 min-content 撑到
     5563px（可视宽 1098px）⇒ **整张表也横向溢出**。
   修法：加 `overflow-wrap:anywhere` —— 它会引入断点**并参与 min-content
   计算**，表格算法才会按可用宽度分配列宽。（`word-break:break-word` 走的是
   旧语义、不参与 min-content 计算，仅作老引擎回退，不能单独承担此职责。）
   ⚠ `max-width:260px` 保留原值不动：它在本 auto 布局里**不表现为单元格硬上限**
     （实测列宽仍 319.7px），但**决定本列的"宽度贡献上限"**，从而影响整表列宽分配。
     实测把它改成 320/420 会让本列变宽、其余列被挤窄 ⇒ 非必要不要动。
   ✅ 回归判据：本页 99 个单元格溢出数 = 0；`.table-wrap` 无横向滚动；
      且 9 列宽度与修复前**逐个一致**（只治溢出、不动布局）。 */
td.wrap-cell{
  white-space:normal;
  overflow-wrap:anywhere;
  word-break:break-word;
  max-width:260px;
}

/* —— 徽标 —— */
.badge{display:inline-block;padding:1px 8px;border-radius:9px;font-size:11px;font-weight:600}
.badge.ok{background:var(--ok-bg);color:var(--ok)}
.badge.warn{background:var(--warn-bg);color:var(--warn)}
.badge.danger{background:var(--danger-bg);color:var(--danger)}
.badge.info{background:rgba(47,111,237,.12);color:var(--brand)}
.badge.mute{background:rgba(138,148,166,.14);color:var(--text-3)}

/* —— 消息 / Toast —— */
.msg{padding:10px 14px;border-radius:var(--r-md);margin-bottom:14px;font-size:13px;display:flex;gap:8px;align-items:flex-start}
.msg.ok{background:var(--ok-bg);border:1px solid rgba(35,120,4,.28);color:var(--ok)}
.msg.err{background:var(--danger-bg);border:1px solid rgba(212,56,13,.28);color:var(--danger)}
.msg code{background:rgba(0,0,0,.06);padding:1px 5px;border-radius:5px;font-family:ui-monospace,Consolas,monospace}

/* —— 登录页 —— */
.login-wrap{min-height:calc(100vh - 120px);display:flex;align-items:center;justify-content:center}
.login-card{width:370px;padding:30px 32px}
.login-logo{width:100%;max-width:230px;height:auto;display:block;margin:0 auto 16px}
.login-card h1{margin:0 0 18px;font-size:20px;text-align:center;line-height:1.4;letter-spacing:.3px}
.login-card .btn{width:100%;justify-content:center;margin-top:6px}
.login-card .foot{font-size:11px;color:var(--text-3);margin-top:16px;line-height:1.7}

/* —— 列表/键值 —— */
.kv{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px dashed var(--line);font-size:13px}
.kv:last-child{border-bottom:0}
.kv .k{color:var(--text-3)}
.kv .v{font-weight:600;font-variant-numeric:tabular-nums}
.muted{color:var(--text-3)}
.mono{font-family:ui-monospace,Consolas,"Courier New",monospace}
/* 长文本展示块（项目内容简述 / 排除理由 / 达成判定条件 / CLI 令牌）。
   2026-09-26：补 `overflow-wrap:anywhere`。原样只有 `overflow:auto`，
   对无空格长串（`test003test003…`、令牌、URL）**不能断行** ⇒ 只能撑宽并由
   横向滚动条兜底，视觉上等同"内容被截断"。加断行后长串在框内折行展示。 */
.code-block{background:rgba(31,45,61,.05);border:1px solid var(--line);border-radius:var(--r-sm);padding:10px 12px;font-size:12px;font-family:ui-monospace,Consolas,monospace;overflow:auto;overflow-wrap:anywhere}
@media (prefers-color-scheme: dark){ .code-block{background:rgba(255,255,255,.05)} }

.empty{padding:26px;text-align:center;color:var(--text-3);font-size:13px}

/* —— 分段控件（iOS 风格 Tab）—— */
.segmented{
  display:inline-flex;gap:2px;padding:3px;border-radius:12px;
  background:var(--glass-bg-2);border:1px solid var(--glass-border);
  -webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
}
.segmented a{
  padding:7px 16px;border-radius:9px;font-size:13px;color:var(--text-2);font-weight:600;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.segmented a:hover{color:var(--brand);text-decoration:none}
.segmented a.on{background:rgba(255,255,255,.92);color:var(--brand);box-shadow:0 2px 8px rgba(31,45,61,.10)}
@media (prefers-color-scheme: dark){
  .segmented a.on{background:rgba(255,255,255,.14);color:var(--brand-2)}
}

/* —— 分组标题（表单分区）—— */
.section-title{
  display:flex;align-items:center;gap:8px;margin:18px 0 10px;font-size:13px;font-weight:700;color:var(--text-2);
}
.section-title::before{content:"";width:3px;height:14px;border-radius:2px;background:var(--brand)}
.section-title:first-child{margin-top:0}

/* —— 动效偏好 —— */
@media (prefers-reduced-motion: reduce){ *{transition:none !important;animation:none !important} }

/* ============================================================
   经营驾驶舱 · 新增组件（SOP 节点布局 / 对齐 / 甘特 / 完成度）
   ============================================================ */

/* —— 对齐栅格（统一板块间距与基线，解决密度差） —— */
.deck{display:grid;gap:var(--s3);align-items:stretch}
.deck.c2{grid-template-columns:1.6fr 1fr}
.deck.c3{grid-template-columns:repeat(3,1fr)}
.deck.c4{grid-template-columns:repeat(4,1fr)}
.deck.c5{grid-template-columns:repeat(5,1fr)}
@media (max-width:1080px){ .deck.c3,.deck.c4,.deck.c5{grid-template-columns:repeat(2,1fr)} }
@media (max-width:720px){ .deck.c2,.deck.c3,.deck.c4,.deck.c5{grid-template-columns:1fr} }
.card{background:var(--glass-bg);border:1px solid var(--glass-border);border-radius:var(--r-md);
  box-shadow:var(--glass-shadow);-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  padding:var(--s4);display:flex;flex-direction:column;min-width:0}
.card.h{display:flex;align-items:center;justify-content:space-between;gap:var(--s2);padding:var(--s3) var(--s4)}
.card h3{margin:0;font-size:14px;font-weight:700;display:flex;align-items:center;gap:8px}
.card h3 .hint{font-weight:500;color:var(--text-3);font-size:12px;margin-left:auto}
.card .body{margin-top:var(--s3)}

/* —— 品牌字标 / Logo（红，官方色） —— */
.brand-logo{height:30px;width:auto;display:block;border-radius:7px}

/* —— SOP 节点步骤条（按项目管理 SOP 组织页面） —— */
.stepper{display:flex;align-items:stretch;gap:0;flex-wrap:nowrap;overflow-x:auto;padding:4px 0}
.step{flex:1 1 0;min-width:120px;display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:var(--s2) var(--s2);position:relative}
.step::after{content:"";position:absolute;top:19px;left:50%;width:100%;height:2px;background:var(--line);z-index:0}
.step:last-child::after{display:none}
.step .dot{width:38px;height:38px;border-radius:12px;display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:15px;background:var(--glass-bg-2);border:1px solid var(--glass-border);
  color:var(--text-2);z-index:1;box-shadow:var(--inset,inset 0 1px 0 rgba(255,255,255,.5))}
.step.done .dot{background:var(--ok-bg);color:var(--ok);border-color:transparent}
.step.active .dot{background:var(--brand);color:#fff;border-color:transparent;box-shadow:0 4px 14px rgba(47,111,237,.35)}
.step.warn .dot{background:var(--warn-bg);color:var(--warn);border-color:transparent}
.step.danger .dot{background:var(--danger-bg);color:var(--danger);border-color:transparent}
.step .lb{font-size:12px;font-weight:650;color:var(--text-1);text-align:center}
.step .sub{font-size:10.5px;color:var(--text-3);text-align:center}

/* —— 指标卡（对齐基线） —— */
.kpi-row{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--s3);margin-bottom:var(--s3)}
@media (max-width:1080px){ .kpi-row{grid-template-columns:repeat(3,1fr)} }
@media (max-width:560px){ .kpi-row{grid-template-columns:repeat(2,1fr)} }
.kpi{background:var(--glass-bg);border:1px solid var(--glass-border);border-radius:var(--r-md);
  box-shadow:var(--glass-shadow);-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  padding:var(--s3) var(--s4);display:flex;flex-direction:column;gap:2px}
.kpi .n{font-size:25px;font-weight:750;font-variant-numeric:tabular-nums;letter-spacing:-.5px}
.kpi .l{font-size:11.5px;color:var(--text-3)}
.kpi .n.accent{color:var(--brand)} .kpi .n.ok{color:var(--ok)} .kpi .n.warn{color:var(--warn)}
.kpi .n.danger{color:var(--danger)} .kpi .n.red{color:var(--brand-red)}

/* —— 完成度进度条 —— */
.progress{position:relative;height:9px;border-radius:99px;background:rgba(31,45,61,.10);overflow:hidden}
.progress > i{position:absolute;left:0;top:0;bottom:0;border-radius:99px;background:var(--brand);transition:width .4s var(--ease)}
.progress.ok > i{background:var(--ok)} .progress.warn > i{background:var(--warn)}
.progress.danger > i{background:var(--danger)} .progress.red > i{background:var(--brand-red)}
.progress.thin{height:6px}
.bar-row{display:flex;align-items:center;gap:10px;margin:7px 0;font-size:12.5px}
.bar-row .name{width:96px;flex:none;color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bar-row .track{flex:1;min-width:0}
.bar-row .val{width:46px;flex:none;text-align:right;font-variant-numeric:tabular-nums;font-weight:650;color:var(--text-1)}

/* —— 甘特图（纯 CSS，位置由模板算百分比） —— */
.gantt{position:relative;overflow-x:auto;padding-top:6px}
.gantt-scale{display:flex;border-bottom:1px solid var(--line);margin-bottom:6px;font-size:11px;color:var(--text-3)}
.gantt-scale > span{flex:1;text-align:center;padding:2px 0;white-space:nowrap}
.gantt-row{display:flex;align-items:center;gap:10px;padding:5px 0;border-bottom:1px dashed var(--line)}
.gantt-row .lab{width:200px;flex:none;font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gantt-row .lab .code{color:var(--text-3);font-size:11px;margin-right:6px}
.gantt-track{position:relative;flex:1;height:22px;background:rgba(31,45,61,.05);border-radius:7px;min-width:200px}
.gantt-bar{position:absolute;top:3px;height:16px;border-radius:6px;background:var(--brand);
  opacity:.85;overflow:hidden;display:flex;align-items:center}
.gantt-bar > i{position:absolute;left:0;top:0;bottom:0;background:rgba(255,255,255,.45)}
.gantt-bar.done{background:var(--ok)} .gantt-bar.late{background:var(--danger)}
.gantt-mark{position:absolute;top:-3px;width:9px;height:9px;border-radius:50%;background:var(--warn);
  box-shadow:0 0 0 3px var(--warn-bg);transform:translateX(-50%)}
.gantt-mark.bad{background:var(--danger);box-shadow:0 0 0 3px var(--danger-bg)}
.gantt-today{position:absolute;top:0;bottom:0;width:2px;background:var(--brand-red);opacity:.55;z-index:3}
.gantt-today::after{content:"今";position:absolute;top:-2px;left:3px;font-size:9px;color:var(--brand-red);font-weight:700}
/* 今日线贴近时间轴右界（today_pct 接近 100，例如"开放终点"把右界延到今天）时，
   默认向右展开的「今」标签会捅出轨道 ⇒ 容器出现横向滚动条。
   此时改为向左展开（2026-09-26 修复，真机实测溢出 12px）。 */
.gantt-today.edge::after{left:auto;right:3px}
/* 同理，2px 宽的线体在 left:100% 处也会越界 2px（实测容器 1104 vs 可视 1102）
   ⇒ 贴右界时整体左移一个线宽，使线体完整落在轨道内。 */
.gantt-today.edge{transform:translateX(-2px)}

/* —— 节点状态点 —— */
.nodedot{width:9px;height:9px;border-radius:50%;flex:none;display:inline-block}
.nodedot.ok{background:var(--ok);box-shadow:0 0 0 3px var(--ok-bg)}
.nodedot.wait{background:var(--warn);box-shadow:0 0 0 3px var(--warn-bg)}
.nodedot.bad{background:var(--danger);box-shadow:0 0 0 3px var(--danger-bg)}
.node-line{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:var(--r-sm);
  background:var(--glass-bg-2);border:1px solid var(--glass-border);margin-bottom:7px}
.node-line.esc{border-color:rgba(212,56,13,.45);background:var(--danger-bg)}
.node-line .nm{font-weight:650;font-size:12.5px}
.node-line .meta{font-size:11px;color:var(--text-3);margin-left:auto;text-align:right}

/* —— 失控 / 预警卡片 —— */
.alert-card{display:flex;gap:10px;padding:11px 12px;border-radius:var(--r-sm);
  background:var(--danger-bg);border:1px solid rgba(212,56,13,.32);margin-bottom:8px}
.alert-card.warn{background:var(--warn-bg);border-color:rgba(212,136,6,.32)}
.alert-card .tt{font-weight:700;font-size:12.5px;color:var(--danger)}
.alert-card.warn .tt{color:var(--warn)}
.alert-card .ds{font-size:11.5px;color:var(--text-2);margin-top:2px}
.alert-card .ic{color:var(--danger);flex:none}
.alert-card.warn .ic{color:var(--warn)}

/* —— 反馈日志时间线 —— */
.tl{position:relative;padding-left:20px}
.tl::before{content:"";position:absolute;left:6px;top:4px;bottom:4px;width:2px;background:var(--line)}
.tl .it{position:relative;padding:0 0 14px}
.tl .it::before{content:"";position:absolute;left:-17px;top:4px;width:10px;height:10px;border-radius:50%;
  background:var(--glass-bg-2);border:2px solid var(--brand)}
.tl .it .h{display:flex;gap:8px;align-items:baseline;font-size:12.5px}
.tl .it .h .who2{font-weight:700}
.tl .it .h .tm{font-size:11px;color:var(--text-3);margin-left:auto;white-space:nowrap}

/* 2026-09-26（第 4 轮 · 需求①）：`.item` / `.meta` / `.content` 此前**一条规则都没有**
   —— 尽管有 4 处模板在用（project_detail.html 1 处、project_exec.html 3 处）——
   于是 `.tl` 的竖线照常画、内容却是没有任何缩进/行高/断行保护的裸文本；
   叠加正文里 763 字**无空白长串**（真实库 project_logs#1 = `test003…` 连续 763 字）
   ⇒ 默认 overflow-wrap:normal 没有任何断点 ⇒ 横向冲出面板。
   修法：用**选择器组**让两套类名共用声明（零模板结构改动、只维护一处）。
   ⚠ 刻意不把 `.meta` 并入 `.h`：`.h` 是 display:flex，home.html 依赖其 gap 与
     `.tm{margin-left:auto}`；而 `.meta` 的模板是「文本 + ｜ + badge」混排，
     进 flex 会让 `｜` 分隔符间距不均（除非把文本包进单一子元素，见 `.meta-txt`）。 */
.tl .item{position:relative;padding:0 0 14px}
.tl .item::before{content:"";position:absolute;left:-17px;top:4px;width:10px;height:10px;
  border-radius:50%;background:var(--glass-bg-2);border:2px solid var(--brand)}
.tl .item.risk::before{border-color:var(--danger)}
.tl .item .meta{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:12.5px;
  line-height:1.7;color:var(--text-3)}
.tl .item .meta .meta-txt{min-width:0;overflow-wrap:anywhere;word-break:break-word}
.tl .item .meta .meta-act{margin-left:auto;flex:none}
.tl .it .b, .tl .item .content{font-size:12px;color:var(--text-2);margin-top:2px;
  white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;min-width:0}
.tl .pct{margin:4px 0;font-size:12.5px;color:var(--text-3)}
/* 2026-09-26（第 4 轮补充 · 用户复测仍溢出）：`.h` 此前**没有断行保护**。
   `.h` 是 display:flex，其子 `<span>{{ it.title }}</span>` 是 flex 项 ⇒ `min-width:auto`
   + `overflow-wrap:normal` ⇒ 一个 763 字**无空白长串**无法收缩也无法断行 ⇒ 撑宽 `.h`
   ⇒ 撑宽 `.tl` / `.body` / `.card` ⇒ **整页横向滚动（实测 3688px）**。
   （home.html「反馈日志 · 统一时间线」卡片；同页其余卡片被一起顶出去。）
   修法：① `.h` 允许换行 + `overflow-wrap:anywhere`（flex 项会**继承**，min-content 随之降为 1 字符）；
        ② 子项显式 `min-width:0` 兜底（不依赖 anywhere 对 min-content 的影响）。
   ⚠ `.tm{margin-left:auto}` 在 `flex-wrap:wrap` 下语义不变（仍尽量右靠）。 */
.tl .it .h{flex-wrap:wrap;overflow-wrap:anywhere;word-break:break-word}
.tl .it .h > span{min-width:0}
/* `.meta` 里允许出现**裸文本**（home/project_detail 的时间线就是裸文本 + `｜` + badge，
   没有 `.meta-txt` 包裹）⇒ flex 的匿名项同样需要断行保护，故加在容器上让子项继承。 */
.tl .item .meta{overflow-wrap:anywhere;word-break:break-word}
.tl .item .meta > *{min-width:0}

/* ══════════ 长串安全网（全局兜底，2026-09-26 第 4 轮补充） ══════════
   根因回顾：项目里存在 **763 字零空白长串**（真实库 `test003…`），而 CSS 默认
   `overflow-wrap:normal` 找不到断点 ⇒ 只要该长串落进**任何一个没有断行保护的容器**，
   就会横向冲出、并把祖先一路撑宽直到整页出现横向滚动条。
   ⚠ 上一轮的做法是「发现一处补一处」（只补了 `.tl .item .content`）⇒ 用户复测仍有溢出
     （`.h` / `.badge` / 裸文本 `.meta` 三处漏网）。⇒ 本节改为**按"容器类型"兜底**，
     覆盖全部会承载自由文本的组件；声明本身**不改变任何既有布局**，
     只在真的出现无断点长串时才产生效果（`anywhere` 仅在需要时才断）。 */
.card, .glass, .body, .msg, .empty, .hint, .sub, .kv .v, .kv .k,
.badge, .tag, .pill, h1, h2, h3, h4, li, p, .mono, .wrap-cell, td.wrap-cell,
.rev-table td, .fb-quote, .code-block, .fb-form textarea {
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* inline-block 的徽标/标签需给"宽度上限"才能让 anywhere 生效
   （否则 inline-block 按内容无限撑宽）。max-width:100% 只在超宽时才起作用。 */
.badge, .tag, .pill { max-width: 100%; }

/* —— 表格内超长自由文本折叠（2026-09-27 第 I 轮）——
   池列表「来源卡点 / 项目内容」列可能出现上千字符（含无空格长串）；
   断词已有 overflow-wrap:anywhere 兜底 ⇒ 此处只压**行高**：限 3 行、超出省略。
   ⚠ 用内层 div 而非直接作用于 td：td 无法改为 -webkit-box 布局。 */
.clamp-3{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}

/* —— 小标签（项目类型 / 状态） —— */
.tag{display:inline-flex;align-items:center;gap:4px;padding:2px 9px;border-radius:8px;font-size:11px;font-weight:650}
.tag.info{background:rgba(47,111,237,.13);color:var(--brand)}
.tag.mute{background:rgba(138,148,166,.16);color:var(--text-3)}
.tag.ok{background:var(--ok-bg);color:var(--ok)} .tag.warn{background:var(--warn-bg);color:var(--warn)}
.tag.danger{background:var(--danger-bg);color:var(--danger)} .tag.red{background:rgba(205,14,14,.12);color:var(--brand-red)}
.tag.tipo{background:rgba(205,14,14,.10);color:var(--brand-red)}
.tag.blocker{background:var(--blocker-bg);color:var(--blocker-fg)}

/* —— 页脚 —— */
.foot{text-align:center;color:var(--text-3);font-size:11px;margin-top:24px}

/* —— 数据表格 —— */
.tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.tbl th{text-align:left;color:var(--text-3);font-weight:650;padding:9px 10px;border-bottom:1px solid var(--glass-border);white-space:nowrap}
.tbl td{padding:9px 10px;border-bottom:1px dashed var(--line);vertical-align:middle}
.tbl tr:hover td{background:rgba(47,111,237,.04)}
.tbl .muted{color:var(--text-3);font-size:11.5px}

/* —— 表单控件 —— */
.inp{border:1px solid var(--glass-border);background:var(--glass-bg);color:var(--text-1);
  border-radius:8px;padding:6px 10px;font-size:12.5px;outline:none}
.inp:focus{border-color:var(--brand)}
.inp.sm{padding:4px 8px;font-size:12px;border-radius:7px}

/* ============================================================
   阶段⑤ · 经营驾驶舱首页强化（2026-09-21）
   现代高端商务 · iOS 亚克力磨砂半透视；仅新增类，不改既有组件
   ============================================================ */

/* —— Hero 横幅 —— */
.hero{position:relative;overflow:hidden;display:flex;align-items:center;gap:var(--s5);
  padding:22px 24px;margin-bottom:var(--s3);border-radius:var(--r-xl);
  background:var(--glass-bg);border:1px solid var(--glass-border);
  box-shadow:var(--glass-shadow);
  -webkit-backdrop-filter:saturate(200%) blur(28px);backdrop-filter:saturate(200%) blur(28px)}
.hero::before{content:"";position:absolute;top:-45%;right:-8%;width:430px;height:430px;border-radius:50%;
  background:radial-gradient(closest-side,rgba(47,111,237,.20),transparent 72%);pointer-events:none}
.hero::after{content:"";position:absolute;bottom:-55%;left:-6%;width:380px;height:380px;border-radius:50%;
  background:radial-gradient(closest-side,rgba(205,14,14,.12),transparent 72%);pointer-events:none}
.hero-main{flex:1;min-width:0;position:relative;z-index:1}
.hero-main h1{margin:0;font-size:24px;font-weight:800;letter-spacing:.4px}
.hero-main .sub{color:var(--text-3);font-size:12.5px;margin-top:4px}
.hero-chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.hero-chips .chip{padding:5px 12px;border-radius:99px;font-size:12px;color:var(--text-2);
  background:var(--glass-bg-2);border:1px solid var(--glass-border);white-space:nowrap}
.hero-chips .chip b{color:var(--text-1);font-variant-numeric:tabular-nums;margin-right:3px;font-weight:750}
.hero-chips .chip.alert{background:var(--danger-bg);border-color:rgba(212,56,13,.30)}
.hero-chips .chip.alert,.hero-chips .chip.alert b{color:var(--danger)}
.hero-ring{position:relative;z-index:1;flex:none;display:flex;align-items:center;gap:14px}
.hero-ring .rr{font-size:11.5px;color:var(--text-3);line-height:1.9}
.hero-ring .rr b{display:inline-block;min-width:26px;font-size:14px;color:var(--text-1);font-variant-numeric:tabular-nums}
@media (max-width:860px){ .hero{flex-direction:column;align-items:flex-start} .hero-ring{align-self:center} }

/* —— KPI 强化卡（左侧光色条 + 悬浮抬升 + 实时脚注） —— */
.kpi.boost{position:relative;overflow:hidden;transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease)}
.kpi.boost::before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:3px;border-radius:99px;background:var(--brand);opacity:.9}
.kpi.boost.k-warn::before{background:var(--warn)}
.kpi.boost.k-danger::before{background:var(--danger)}
.kpi.boost.k-red::before{background:var(--brand-red)}
.kpi.boost:hover{transform:translateY(-3px);box-shadow:var(--glass-shadow-hover)}
.kpi .foot{font-size:10.5px;color:var(--text-3);margin-top:5px;font-variant-numeric:tabular-nums}

/* —— 项目卡强化（风险灯 + 悬浮抬升） —— */
.deck.c3 > .card{transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease)}
.deck.c3 > .card:hover{transform:translateY(-3px);box-shadow:var(--glass-shadow-hover)}
.pcard-top{display:flex;align-items:center;gap:8px}
.pcard-top .pcard-name{font-size:13.5px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lamp{width:8px;height:8px;border-radius:50%;flex:none}
.lamp.g{background:var(--ok);box-shadow:0 0 0 3px var(--ok-bg)}
.lamp.y{background:var(--warn);box-shadow:0 0 0 3px var(--warn-bg)}
.lamp.r{background:var(--danger);box-shadow:0 0 0 3px var(--danger-bg)}
.lamp.n{background:rgba(138,148,166,.40)}

/* —— 板块标题图标芯片 —— */
.card h3 .ico-chip{width:26px;height:26px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;
  background:var(--glass-bg-2);border:1px solid var(--glass-border);font-size:14px;flex:none}

/* —— 渐变进度条 / 甘特条强化 / 里程碑菱形 —— */
.progress.grad > i{background:linear-gradient(90deg,var(--brand-2),var(--brand))}
.gantt-bar{background:linear-gradient(180deg,rgba(255,255,255,.22),rgba(255,255,255,0) 60%),var(--brand)}
.gantt-mark{border-radius:2px;transform:translateX(-50%) rotate(45deg)}

/* —— 甘特「开放终点」条（缺截止日期）—— 2026-09-26 缺陷① 新增 ——
   语义：只有开始日期、没有截止日期 ⇒ 计划未设终点，画斜纹条 + 右端虚化，
   与"已定终点的实心条"一眼区分；条长到时间轴右界（右界至少有"今天"）。
   注：必须放在 .gantt-bar 基础规则之后，并与 .done/.late 同级（都不带 .open）。 */
.gantt-bar.open{background:repeating-linear-gradient(135deg,rgba(31,45,61,.30) 0 6px,rgba(31,45,61,.13) 6px 12px);opacity:.85}
.gantt-bar.open > i{background:rgba(255,255,255,.62)}
.gantt-bar.open::after{content:"";position:absolute;right:0;top:0;bottom:0;width:8px;
  background:repeating-linear-gradient(90deg,var(--brand) 0 2px,transparent 2px 5px);opacity:.9}
