/* ============================================================
   MatFlow N01 — 设计系统 v4（2026-09-05 莫兰迪 · 现代科技重构）
   ★ 仅重构「表现层」，HTML / JS / 业务逻辑零修改
   ★ JS 依赖的 class（nav-item / ni-text / xl / cell-edited /
     data-cell / data-book-tbody / toast / nav-mini…）全部保留
   ------------------------------------------------------------
   v4 设计语言：莫兰迪灰调 × 现代科技工具
   1) 暖灰画布 + 发丝线分层，取消大面积纯白，改用带灰度的"近白"
   2) 全站单一高饱和钴蓝（--c-primary 体系）作为唯一强调色，用于导航/按钮/表头等核心位置
   3) 语义色（绿/金/红/紫）仅表达状态，不做模块识别
   4) 渐变收敛到极少数锚点，数据表(.xl) 保留网格隐喻（功能需要）
   ============================================================ */

:root{
  /* ---------- 主色：品牌钴蓝（全站唯一高饱和强调色） ----------
     文字级强调用 --c-primary-dark（白底可读）；
     填充级（主按钮/Logo/头像/表头/导航高亮）用 --c-primary-strong */
  --c-primary:oklch(0.50 0.15 252);
  --c-primary-hover:oklch(0.455 0.16 252);
  --c-primary-strong:oklch(0.48 0.15 252);
  --c-primary-strong-hover:oklch(0.43 0.16 252);
  --c-primary-dark:oklch(0.395 0.11 252);
  --c-primary-soft:oklch(0.945 0.028 252);
  --c-primary-line:oklch(0.858 0.055 252);

  /* ---------- 点缀：并入主色（全站单一强调色，不再每页一色） ---------- */
  --c-accent:oklch(0.50 0.15 252);

  /* ---------- 辅助 / 语义色（莫兰迪灰调，AA 对比） ---------- */
  --c-ok:oklch(0.43 0.055 156);      --c-ok-soft:oklch(0.955 0.018 156);   --c-ok-line:oklch(0.87 0.04 156);
  --c-warn:oklch(0.45 0.07 80);      --c-warn-soft:oklch(0.965 0.025 85);  --c-warn-line:oklch(0.88 0.05 82);
  --c-danger:oklch(0.46 0.08 28);    --c-danger-soft:oklch(0.958 0.025 30);--c-danger-line:oklch(0.885 0.045 30);
  --c-info:oklch(0.43 0.045 285);    --c-info-soft:oklch(0.958 0.016 285); --c-info-line:oklch(0.885 0.03 285);

  /* ---------- 中性（暖灰 · 近白） ---------- */
  --bg:oklch(0.968 0.007 90);
  --bg-elevated:oklch(0.995 0.003 90);
  --surface:oklch(0.995 0.003 90);
  --surface-2:oklch(0.973 0.007 90);
  --surface-3:oklch(0.952 0.008 88);
  --border:oklch(0.926 0.008 85);        /* 发丝线 */
  --border-strong:oklch(0.876 0.009 85); /* 控件描边 */
  --text:oklch(0.30 0.014 70);
  --text-2:oklch(0.45 0.016 70);
  --text-3:oklch(0.50 0.015 70);

  /* ---------- 圆角 ---------- */
  --radius-xs:7px;
  --radius-sm:9px;
  --radius:14px;
  --radius-lg:18px;
  --radius-pill:999px;

  /* ---------- 阴影（无边界设计的主角） ---------- */
  --shadow-xs:0 1px 2px rgba(40,37,32,.05);
  --shadow:0 1px 2px rgba(40,37,32,.05),0 2px 6px rgba(40,37,32,.05);
  --shadow-md:0 2px 4px rgba(40,37,32,.05),0 8px 22px rgba(40,37,32,.08);
  --shadow-lg:0 6px 16px rgba(40,37,32,.08),0 20px 44px rgba(40,37,32,.13);
  --ring:0 0 0 3px oklch(0.5 0.15 252 / .18);

  /* ---------- 字号 ---------- */
  --fs-11:11px;
  --fs-12:12px;
  --fs-13:12.5px;
  --fs-14:13.5px;
  --fs-16:15.5px;
  --fs-18:18px;
  --fs-22:23px;
  --lh-tight:1.32;
  --lh-base:1.68;

  /* ---------- 间距 ---------- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:22px; --sp-6:30px;

  /* ---------- 动效 ---------- */
  --ease:cubic-bezier(.4,0,.2,1);
  --dur:.16s;
  --dur-slow:.26s;
  /* 侧栏折叠/展开专用：比通用动效更慢、更从容 */
  --dur-nav:.5s;
  --ease-nav:cubic-bezier(.33,.62,.22,1);

  /* ---------- 布局 ---------- */
  --sidebar-w:236px;
  --sidebar-mini-w:56px;
  --topbar-h:50px;
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei","Hiragino Sans GB",sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}

/* ============================================================
   基础
   ============================================================ */
*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--font);color:var(--text);
  font-size:var(--fs-14);line-height:var(--lh-base);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  /* 顶部一抹极淡的品牌蓝晕染，保持画布透气（全站同一种蓝） */
  background:
    radial-gradient(1100px 520px at 82% -8%, oklch(0.62 0.12 252 / .08) 0%, oklch(0.62 0.12 252 / 0) 62%),
    radial-gradient(900px 420px at -10% 108%, oklch(0.70 0.14 252 / .05) 0%, oklch(0.70 0.14 252 / 0) 58%),
    var(--bg);
  background-attachment:fixed;
}
a{text-decoration:none;color:inherit}
button{font-family:inherit;cursor:pointer;font-size:inherit}
input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
img,svg{vertical-align:middle}

:focus-visible{outline:2px solid var(--c-primary);outline-offset:2px;border-radius:var(--radius-xs)}
::selection{background:var(--c-primary-soft);color:var(--c-primary-dark)}

/* ============================================================
   布局
   ============================================================ */
.app{display:flex;min-height:100vh}

.sidebar{
  width:var(--sidebar-w);flex:0 0 var(--sidebar-w);
  background:var(--surface);border-right:1px solid var(--border);
  display:flex;flex-direction:column;position:fixed;top:0;bottom:0;left:0;z-index:20;
  transition:width var(--dur-nav) var(--ease-nav),box-shadow var(--dur-nav) var(--ease-nav);
}

/* 收起态：仅图标；悬停浮层展开 */
.app.nav-mini .sidebar{width:var(--sidebar-mini-w);flex-basis:var(--sidebar-mini-w)}
.app.nav-mini .main{margin-left:var(--sidebar-mini-w)}
.app.nav-mini .sidebar:hover{width:var(--sidebar-w);flex-basis:var(--sidebar-w);box-shadow:8px 0 32px rgba(40,37,32,.10)}
.app.nav-mini .brand{justify-content:center;padding:var(--sp-3) 0}
.app.nav-mini .brand-text,.app.nav-mini .sidebar-foot{display:none}
.app.nav-mini .nav-item{justify-content:center;gap:0;padding:9px 0;margin:0 8px 2px}
.app.nav-mini .ni-icon{width:auto;font-size:15px}
.app.nav-mini .ni-text{display:none;white-space:nowrap}
.app.nav-mini .sidebar:hover .brand{justify-content:flex-start;padding:var(--sp-4) var(--sp-3) var(--sp-3)}
.app.nav-mini .sidebar:hover .brand-text{display:block}
.app.nav-mini .sidebar:hover .sidebar-foot{display:block}
.app.nav-mini .sidebar:hover .nav-item{justify-content:flex-start;gap:10px;padding:8px 11px;margin:0 0 2px}
.app.nav-mini .sidebar:hover .ni-icon{width:18px;font-size:13px}
.app.nav-mini .sidebar:hover .ni-text{display:inline}

.brand{
  display:flex;align-items:center;gap:11px;padding:var(--sp-4) var(--sp-3) var(--sp-3);
  border-bottom:1px solid var(--border);
}
.brand-logo{
  width:37px;height:37px;flex:0 0 37px;border-radius:11px;
  background:linear-gradient(135deg,var(--c-primary-strong),var(--c-primary-dark));
  color:#fff;font-weight:800;font-size:13px;display:flex;align-items:center;justify-content:center;
  letter-spacing:.5px;box-shadow:0 3px 10px color-mix(in oklch,var(--c-primary) 32%,transparent),inset 0 1px 0 oklch(1 0 0 / .14);
}
.brand-name{font-weight:700;font-size:var(--fs-16);letter-spacing:.2px;line-height:1.2}
.brand-sub{font-size:var(--fs-11);color:var(--text-3);line-height:1.4}

.nav{flex:1;overflow-y:auto;padding:var(--sp-3) 10px var(--sp-4)}
/* 2026-09-23：随侧栏改造删除 .nav-group / .nav-group-title（分组标题 + 子项列表的旧结构）。
   侧栏只剩主菜单，分组标题这个层级不复存在，规则已无元素可匹配。 */
.nav-item{
  position:relative;
  display:flex;align-items:center;gap:10px;padding:8px 11px;border-radius:var(--radius-sm);
  color:var(--text-2);font-size:var(--fs-14);margin-bottom:2px;line-height:1.4;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.nav-item:hover{background:var(--surface-3);color:var(--text)}
.nav-item.active{
  background:var(--c-primary-soft);
  color:var(--c-primary-dark);font-weight:600;
  box-shadow:inset 0 0 0 1px var(--c-primary-line);
}
.nav-item.active::before{
  content:"";position:absolute;left:-10px;top:50%;transform:translateY(-50%);
  width:3px;height:18px;border-radius:0 3px 3px 0;
  background:var(--c-primary);
}
.ni-icon{width:18px;text-align:center;font-size:13px;opacity:.72;flex:0 0 auto;transition:opacity var(--dur) var(--ease)}
.nav-item:hover .ni-icon,.nav-item.active .ni-icon{opacity:1}

/* 顶层菜单项：2026-09-23 起侧栏只保留主菜单、不再有分组标题，
   因此顶层项自身要有存在感——字重与字号略高于原子项，行距拉开一点。
   收起为图标条时的规则见上方 .app.nav-mini（选择器权重更高，会自动覆盖这里的内边距） */
.nav-item.nav-top{font-size:var(--fs-14);font-weight:600;color:var(--text);padding:10px 11px;margin-bottom:3px}
.nav-item.nav-top.active{color:var(--c-primary-dark)}
/* 注：这里刻意不覆盖 .ni-icon（图标字号/透明度）——那会盖掉 .app.nav-mini 与
   ≤860px 断点下「收起态图标放大到 15px / 悬停 13px」的既有规则，收起时图标会不居中 */

.sidebar-foot{padding:var(--sp-3) var(--sp-4);border-top:1px solid var(--border);background:var(--surface-2)}
.sf-badge{font-size:var(--fs-11);color:var(--text-2);font-weight:650}
.sf-note{font-size:10.5px;color:var(--text-3);margin-top:2px}

.main{flex:1;margin-left:var(--sidebar-w);display:flex;flex-direction:column;min-width:0;
  transition:margin-left var(--dur-nav) var(--ease-nav)}

.topbar{
  height:var(--topbar-h);background:oklch(0.995 0.003 90 / .82);backdrop-filter:saturate(1.5) blur(12px);
  border-bottom:1px solid var(--border);
  display:flex;align-items:center;justify-content:space-between;padding:0 var(--sp-4);gap:var(--sp-3);
  position:sticky;top:0;z-index:15;
}
.topbar-left,.topbar-right{display:flex;align-items:center;gap:10px;min-width:0}
.proj-select,.edition-select,.search-box input{
  border:1px solid transparent;border-radius:var(--radius-sm);
  padding:7px 12px;font-size:var(--fs-13);background:var(--surface-3);color:var(--text);
  font-family:inherit;min-height:34px;
  transition:all var(--dur) var(--ease);
}
.proj-select{min-width:210px;max-width:280px}
.edition-select{
  background:var(--c-primary-soft);
  color:var(--c-primary-dark);font-weight:650;min-width:118px;
  box-shadow:inset 0 0 0 1px var(--c-primary-line);
}
.search-box input{width:230px}
.search-box input::placeholder{color:var(--text-3)}
.proj-select:hover,.edition-select:hover,.search-box input:hover{background:var(--surface-2);box-shadow:var(--shadow-xs)}
.proj-select:focus,.edition-select:focus,.search-box input:focus{
  outline:none;background:var(--surface);box-shadow:var(--ring),inset 0 0 0 1px var(--c-primary)
}
.user-chip{
  display:flex;align-items:center;gap:8px;font-size:var(--fs-13);color:var(--text-2);
  padding:4px 12px 4px 4px;border-radius:var(--radius-pill);transition:all var(--dur) var(--ease);
}
.user-chip:hover{background:var(--surface-3);box-shadow:var(--shadow-xs)}
.avatar{
  width:30px;height:30px;border-radius:50%;
  background:linear-gradient(135deg,var(--c-primary-strong),var(--c-primary-dark));
  color:#fff;display:flex;align-items:center;justify-content:center;font-size:var(--fs-12);font-weight:700;
  box-shadow:0 2px 6px color-mix(in oklch,var(--c-primary) 28%,transparent);
}

.content{flex:1;padding:var(--sp-4) var(--sp-4) var(--sp-6);overflow-x:hidden}

/* ============================================================
   二级导航：主菜单 → 子页面横向标签
   2026-09-23：侧栏只留 7 个主菜单，子页面改为页面顶部的横排标签。
   放在 .main 里而不是各视图内部——它是导航而非页面内容，
   15 个视图模块一行都不用改；作为 .main 的直接子元素天然满宽，
   吸顶时左右不留空隙，也不必用负外边距去凑（那会在断点变化时错位）。
   ============================================================ */
.subnav{
  display:flex;align-items:stretch;gap:2px;flex-wrap:wrap;
  /* 左右内边距先扣掉 .sub-tab 的 12px 内边距，使首个标签的**文字**与页面内容左对齐。
     2026-09-23：原先是靠 .sub-tab:first-child 的 -12px 负外边距做到的，但选中态改成
     深蓝底之后，负外边距会让首个标签的底色向左越出内容区，故改为容器侧让位——
     文字位置不变，底色边界正确。 */
  padding:0 calc(var(--sp-4) - 12px);
  /* 用画布色而非 --surface：顶栏已是近白（深色下为 0.235），
     二级条同色会与之糊成一整块；取 --bg 与页面同底，只靠 1px 底线分层，
     吸顶滚动时又是不透明的，能干净地盖住下方内容 */
  background:var(--bg);border-bottom:1px solid var(--border);
  position:sticky;top:var(--topbar-h);z-index:14;
}
.subnav[hidden]{display:none}
.sub-tab{
  position:relative;font:inherit;font-size:var(--fs-13);line-height:1.2;
  color:var(--text-2);background:none;border:0;cursor:pointer;white-space:nowrap;
  padding:11px 12px;
  transition:color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.sub-tab:hover{color:var(--text);background:var(--surface)}
/* 选中态：深蓝底 + 加粗白字（2026-09-23 按要求）。
   原先只有「钴蓝字 + 2px 下划线」，多个标签并排时不够醒目，也难一眼看出当前位置。
   底色取 --c-primary-dark —— 浅色主题下是 oklch(0.395 0.11 252)，正是一支深蓝。
   下划线伪元素随之取消：底色已经承担了选中态，再压一条钴蓝线只会显得脏。
   顶部圆角让它读起来像「贴住内容区的一张标签」。 */
.sub-tab.active{
  color:#fff;font-weight:700;
  background:var(--c-primary-dark);
  border-radius:var(--radius-xs) var(--radius-xs) 0 0;
}
.sub-tab.active:hover{background:var(--c-primary-dark);color:#fff}
@media(max-width:1100px){
  /* 窄屏不换行、横向滚动：标签换行会把内容整体往下推一行，滚动更稳 */
  .subnav{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}
}
@media(max-width:640px){
  /* calc(sp-3 - 12px) 在当前令牌下等于 0，与改造前的视觉位置一致 */
  .subnav{padding:0 calc(var(--sp-3) - 12px);position:static}   /* 该断点下顶栏高度自适应，吸顶偏移会错位 */
}

/* ============================================================
   页头
   ============================================================ */
.page-head{
  display:flex;align-items:flex-end;justify-content:space-between;
  margin-bottom:var(--sp-4);gap:var(--sp-3);flex-wrap:wrap;
}
.page-title{
  font-size:var(--fs-18);font-weight:700;letter-spacing:.1px;line-height:var(--lh-tight);
  position:relative;padding-bottom:8px;margin-bottom:-1px;
}
/* 标题下的品牌色短条：全站统一的钴蓝强调 */
.page-title::after{
  content:"";position:absolute;left:0;bottom:0;
  width:26px;height:3px;border-radius:var(--radius-pill);
  background:linear-gradient(90deg,var(--c-primary-strong),var(--c-primary));
}
.page-desc{font-size:var(--fs-12);color:var(--text-3);margin-top:6px}
.page-actions{display:flex;gap:var(--sp-2);flex-wrap:wrap}

/* ============================================================
   按钮
   ============================================================ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  border:1px solid var(--border-strong);background:var(--surface);color:var(--text-2);
  padding:6px 14px;border-radius:var(--radius-sm);font-size:var(--fs-13);font-weight:550;
  line-height:1.5;min-height:33px;white-space:nowrap;
  box-shadow:var(--shadow-xs);
  transition:all var(--dur) var(--ease);
}
.btn:hover{
  border-color:var(--c-primary-line);color:var(--c-primary-dark);
  background:var(--c-primary-soft);transform:translateY(-1px);box-shadow:var(--shadow);
}
.btn:active{transform:translateY(0);box-shadow:var(--shadow-xs)}
.btn-primary{
  background:linear-gradient(180deg,var(--c-primary-strong),var(--c-primary-dark));
  border-color:transparent;color:#fff;font-weight:650;
  box-shadow:0 1px 2px color-mix(in oklch,var(--c-primary-dark) 34%,transparent),inset 0 1px 0 oklch(1 0 0 / .16);
}
.btn-primary:hover{
  background:linear-gradient(180deg,var(--c-primary-hover),var(--c-primary-strong-hover));
  border-color:transparent;color:#fff;
  box-shadow:0 4px 12px color-mix(in oklch,var(--c-primary-dark) 42%,transparent),inset 0 1px 0 oklch(1 0 0 / .12);
}
.btn-sm{padding:4px 11px;font-size:var(--fs-12);min-height:28px;border-radius:var(--radius-xs)}
.btn:disabled,.btn[disabled]{
  opacity:.5;cursor:not-allowed;transform:none!important;
  background:var(--surface-3);border-color:transparent;color:var(--text-3);box-shadow:none;
}
/* 危险微操作：行内「删」类动作。放在 .btn / .btn:hover 之后，
   hover 填成危险红（同 0,2,0 后写胜出）；disabled 仍由 .btn:disabled 兜住 */
.btn-danger{color:var(--c-danger);border-color:var(--c-danger-line);background:var(--c-danger-soft)}
.btn-danger:hover{background:var(--c-danger);border-color:var(--c-danger);color:#fff}
.btn-danger:active{background:var(--c-danger);border-color:var(--c-danger);color:#fff}
/* 图标微按钮：列序调整等极紧凑箭头（放在 .btn-sm 之后以覆盖 padding） */
.btn-icon{padding:2px 7px;min-height:24px;font-size:var(--fs-12);line-height:1.4;border-radius:var(--radius-xs);color:var(--text-2)}
.btn-icon:hover{color:var(--c-primary-dark);background:var(--c-primary-soft);border-color:var(--c-primary-line)}

/* ============================================================
   卡片（无边界：留白 + 阴影分层）
   ============================================================ */
.card{
  background:var(--surface);border:1px solid rgba(52,48,42,.05);
  border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden;
  transition:box-shadow var(--dur-slow) var(--ease),border-color var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease);
}
.card:hover{box-shadow:var(--shadow-md);border-color:rgba(52,48,42,.08)}
.card-head{
  padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--border);
  display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);
}
.card-title{font-size:var(--fs-14);font-weight:650;line-height:var(--lh-tight)}
.card-sub{font-size:var(--fs-11);color:var(--text-3);margin-top:2px}
.card-body{padding:var(--sp-4)}
.card-body.flush{padding:0}

/* ============================================================
   标签 Chip（去描边，纯色 tint）
   ============================================================ */
.chip{
  display:inline-flex;align-items:center;gap:5px;padding:2px 10px;border-radius:var(--radius-pill);
  font-size:var(--fs-11);font-weight:600;line-height:1.7;
  background:var(--surface-3);color:var(--text-2);border:1px solid transparent;white-space:nowrap;
}
.chip-primary{background:var(--c-primary-soft);color:var(--c-primary-dark);border-color:transparent}
.chip-ok{background:var(--c-ok-soft);color:var(--c-ok);border-color:transparent}
.chip-warn{background:var(--c-warn-soft);color:var(--c-warn);border-color:transparent}
.chip-danger{background:var(--c-danger-soft);color:var(--c-danger);border-color:transparent}
.chip-info{background:var(--c-info-soft);color:var(--c-info);border-color:transparent}
.chip-outline{background:transparent;border-color:var(--border-strong);color:var(--text-2)}

/* ============================================================
   栅格
   ============================================================ */
.grid{display:grid;gap:var(--sp-3)}
.g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.g4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:1280px){.g4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:1200px){.g3{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:820px){.g2,.g3,.g4{grid-template-columns:1fr}}

/* ============================================================
   统计卡
   ============================================================ */
.stat{padding:var(--sp-4);position:relative;overflow:hidden}
/* 左上角一抹单色渐变角，替代边框 */
.stat::before{
  content:"";position:absolute;top:0;left:0;width:64px;height:3px;
  background:linear-gradient(90deg,var(--c-primary),var(--c-primary-line));
  border-radius:0 0 3px 0;opacity:.9;
}
.stat-label{font-size:var(--fs-11);color:var(--text-3);font-weight:600;letter-spacing:.3px}
.stat-value{
  font-size:var(--fs-22);font-weight:700;margin-top:var(--sp-1);
  letter-spacing:-.5px;line-height:1.15;
  font-variant-numeric:tabular-nums;
  background:linear-gradient(160deg,var(--text) 30%,oklch(0.46 0.03 70) 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.stat-foot{font-size:var(--fs-11);color:var(--text-3);margin-top:var(--sp-1);display:flex;align-items:center;gap:6px}
.trend-up{color:var(--c-ok)}
.trend-down{color:var(--c-danger)}

/* ============================================================
   压缩统计条（单行低调概览：替代各页顶部大统计卡）
   ============================================================ */
.stat-strip{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  margin-bottom:14px;padding:6px 12px;
  border:1px solid var(--border);border-radius:var(--radius-sm);
  background:var(--surface);font-size:12px;color:var(--text-3);line-height:1.5;
}
.stat-strip .ss{display:inline-flex;align-items:baseline;gap:5px;flex-wrap:wrap;white-space:nowrap}
.stat-strip .sep{width:1px;height:13px;background:var(--border);flex:0 0 1px}
.stat-strip b{color:var(--text-2);font-weight:650;font-variant-numeric:tabular-nums}
.stat-strip b.ok{color:var(--c-ok)}
.stat-strip b.warn{color:var(--c-warn)}
.stat-strip b.danger{color:var(--c-danger)}
.stat-strip .alt{color:var(--text-3);opacity:.85}
@media(max-width:820px){.stat-strip .ss{white-space:normal}}

/* ============================================================
   UI 图表（ui.js 生成 SVG）：文字/网格/描点跟随主题，数据用色不动
   ============================================================ */
svg text{fill:var(--text-2)}
svg line{stroke:var(--border)}
svg circle{fill:var(--surface);stroke:var(--c-primary)}

/* ============================================================
   表格（常规表：表头用品牌蓝淡染，编辑/单元格区保持近白）
   ============================================================ */
.table-wrap{overflow-x:auto;border-radius:var(--radius-sm)}
table{width:100%;border-collapse:collapse;font-size:var(--fs-13)}
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--border);line-height:1.6;vertical-align:middle}
th{
  background:color-mix(in oklch,var(--c-primary) 13%,var(--surface));
  color:var(--c-primary-dark);font-weight:700;font-size:var(--fs-11);
  letter-spacing:.5px;white-space:nowrap;position:sticky;top:var(--topbar-h);z-index:2;
  border-bottom:1px solid var(--c-primary-line);
}
tbody tr{transition:background var(--dur) var(--ease)}
tbody tr:hover{background:var(--c-primary-soft)}
tbody tr:last-child td{border-bottom:none}
tbody tr:last-child tfoot td{border-top:1px solid var(--border-strong)}
td.num{text-align:right;font-variant-numeric:tabular-nums}
.mono{font-family:var(--font-mono);font-size:var(--fs-12);letter-spacing:-.1px}

/* 表格容器在 flush 卡片内贴合无边框 */
.card-body.flush > .table-wrap{border-radius:0}

/* ============================================================
   进度条
   ============================================================ */
.bar{height:6px;border-radius:var(--radius-pill);background:var(--surface-3);overflow:hidden;min-width:70px}
.bar-fill{
  height:100%;border-radius:var(--radius-pill);
  background:var(--c-primary);
  transition:width var(--dur-slow) var(--ease);
}
.bar-fill.ok{background:var(--c-ok)}
.bar-fill.warn{background:var(--c-warn)}
.bar-fill.danger{background:var(--c-danger)}

/* ============================================================
   筛选栏 / 表单控件
   ============================================================ */
.filters{display:flex;gap:var(--sp-2);flex-wrap:wrap;align-items:center;margin-bottom:var(--sp-4)}
.filters input,.filters select{
  border:1px solid transparent;border-radius:var(--radius-sm);
  padding:7px 12px;font-size:var(--fs-13);font-family:inherit;background:var(--surface-3);
  min-height:34px;transition:all var(--dur) var(--ease);
}
.filters input:hover,.filters select:hover{background:var(--surface-2);box-shadow:var(--shadow-xs)}
.filters input:focus,.filters select:focus{
  outline:none;background:var(--surface);box-shadow:var(--ring),inset 0 0 0 1px var(--c-primary)
}
/* 视图工具条：左＝筛选（看什么），右＝视图操作（表头/导入/导出）
   分区的意义是把「看什么」与「改什么」拆开——页头右侧只留页面级提交动作 */
.toolbar{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;margin-bottom:var(--sp-3)}
.toolbar .tb-right{margin-left:auto;display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap}
.tb-label{font-size:var(--fs-12);color:var(--text-3);font-weight:600;flex:0 0 auto}
.tb-sep{width:1px;height:20px;background:var(--border);flex:0 0 1px;margin:0 2px;align-self:center}
/* 工具条上的「开关型」按钮（表头配置 / 导入 Excel / 新增房间）：
   面板展开时按钮驻留主色软底，让「当前有面板打开」在按钮上也有反馈，
   而不是只靠上方凭空多出来的一张卡片提示。放在 .btn:hover 之后，同权重时后者胜出 */
.btn.is-on{background:var(--c-primary-soft);border-color:var(--c-primary-line);color:var(--c-primary-dark)}
.btn.is-on:hover{background:var(--c-primary-soft);border-color:var(--c-primary-line);color:var(--c-primary-dark)}
/* 批量修改条：带底纹的「次级模式条」，用底色与主工具条拉开层级，不与筛选争视线 */
.filters-batch{
  background:var(--surface-2);border:1px solid var(--border);
  border-radius:var(--radius-sm);padding:7px 11px;margin-bottom:var(--sp-3);
}
.filters-batch select,.filters-batch input{background:var(--surface);min-height:30px;padding:5px 10px;font-size:var(--fs-12)}
.filters-batch select:hover,.filters-batch input:hover,.filters-batch select:focus,.filters-batch input:focus{background:var(--surface)}
/* 表单字段标签：11px 弱化字，观感同 .stat-label 但语义独立（不再借用统计卡的类名） */
.flabel{display:block;font-size:var(--fs-11);color:var(--text-3);font-weight:600;letter-spacing:.3px;margin-bottom:5px}
/* 通用表单控件 .fld：与 topbar / 筛选栏同款外观，替代散落在视图里的行内样式
   （hover/focus 前景与背景成对定义，focus 用 ring 阴影，字体色在 hover 时不减淡） */
.fld{
  border:1px solid transparent;border-radius:var(--radius-sm);
  padding:7px 12px;font-size:var(--fs-13);font-family:inherit;
  background:var(--surface-3);color:var(--text);min-height:34px;
  transition:all var(--dur) var(--ease);
}
.fld:hover{background:var(--surface-2);box-shadow:var(--shadow-xs)}
.fld:focus{outline:none;background:var(--surface);box-shadow:var(--ring),inset 0 0 0 1px var(--c-primary)}
/* 单元格级编辑器 .ce：表格 / 面板内就地编辑的紧凑版 .fld（radius-xs + 驻留灰底）
   .ce-ghost 为「透明驻留」变体：平时融入表格，hover/聚焦才显形（OCR 校对等用） */
.ce{
  border:1px solid transparent;border-radius:var(--radius-xs);
  padding:4px 7px;font-size:var(--fs-12);font-family:inherit;
  background:var(--surface-3);color:var(--text);min-height:26px;
  transition:all var(--dur) var(--ease);
}
.ce:hover{background:var(--surface-2);box-shadow:var(--shadow-xs)}
.ce:focus{outline:none;background:var(--surface);box-shadow:var(--ring),inset 0 0 0 1px var(--c-primary)}
.ce-ghost{background:transparent;border-color:transparent}
.ce-ghost:hover{background:var(--surface-2);box-shadow:none}
.ce-ghost:focus{background:var(--surface);box-shadow:var(--ring),inset 0 0 0 1px var(--c-primary)}
/* 只读 / 禁用：去交互、弱化底、不发 ring（供技术参数只读块、自动回填项等） */
.fld[readonly],.fld[disabled],.ce[readonly],.ce[disabled]{
  background:var(--surface-2);color:var(--text-2);cursor:default;border-color:var(--border);
}
.fld[readonly]:hover,.fld[readonly]:focus,.fld[disabled]:hover,.fld[disabled]:focus,
.ce[readonly]:hover,.ce[readonly]:focus,.ce[disabled]:hover,.ce[disabled]:focus{
  background:var(--surface-2);color:var(--text-2);box-shadow:none;
}
input::placeholder,textarea::placeholder{color:var(--text-3)}
label{cursor:pointer}

/* ============================================================
   空间树
   ============================================================ */
.tree{font-size:var(--fs-13)}
.tree-node{border-radius:var(--radius-sm)}
.tree-row{
  display:flex;align-items:center;gap:var(--sp-2);padding:7px 11px;border-radius:var(--radius-sm);
  cursor:default;transition:background var(--dur) var(--ease),box-shadow var(--dur) var(--ease);line-height:1.5;
}
.tree-row:hover{background:var(--surface-3)}
.tree-row.selected{
  background:var(--c-primary-soft);color:var(--c-primary-dark);font-weight:600;
  box-shadow:inset 0 0 0 1px var(--c-primary-line);
}
.tree-toggle{
  width:18px;flex:0 0 18px;text-align:center;color:var(--text-3);cursor:pointer;
  user-select:none;font-size:10px;transition:color var(--dur) var(--ease);
}
.tree-toggle:hover{color:var(--c-primary)}
.tree-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tree-count{font-size:var(--fs-11);color:var(--text-3);font-variant-numeric:tabular-nums}
.tree-children{margin-left:19px;border-left:1px dashed var(--border-strong);padding-left:var(--sp-2)}

/* ============================================================
   物料板
   ============================================================ */
.board-canvas{
  background:
    linear-gradient(90deg,rgba(52,48,42,.018) 1px,transparent 1px) 0 0/20px 20px,
    linear-gradient(rgba(52,48,42,.018) 1px,transparent 1px) 0 0/20px 20px,
    var(--surface-2);
  border:1px dashed var(--border-strong);border-radius:var(--radius);
  min-height:420px;padding:var(--sp-4);display:grid;
  grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:var(--sp-3);align-content:start;
}
.board-tile{
  background:var(--surface);border:1px solid transparent;border-radius:var(--radius);
  overflow:hidden;box-shadow:var(--shadow);display:flex;flex-direction:column;cursor:grab;
  transition:box-shadow var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease);
}
.board-tile:hover{box-shadow:var(--shadow-md);transform:translateY(-3px)}
.tile-swatch{height:82px;position:relative}
.tile-body{padding:var(--sp-2) 11px}
.tile-code{font-family:var(--font-mono);font-size:10.5px;color:var(--text-3)}
.tile-name{font-size:var(--fs-13);font-weight:600;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile-meta{font-size:10.5px;color:var(--text-3);margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile-remove{
  position:absolute;top:6px;right:6px;width:22px;height:22px;border-radius:50%;
  background:rgba(52,48,42,.5);color:#fff;border:none;font-size:11px;line-height:1;
  display:none;align-items:center;justify-content:center;transition:background var(--dur) var(--ease);
}
.tile-remove:hover{background:var(--c-danger)}
.board-tile:hover .tile-remove{display:flex}
.board-empty{grid-column:1/-1;display:flex;align-items:center;justify-content:center;height:300px;color:var(--text-3);font-size:var(--fs-13)}

/* ============================================================
   配色格 / 图例
   ============================================================ */
.swatch-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));gap:var(--sp-2)}
.swatch-item{
  border:none;border-radius:var(--radius-sm);overflow:hidden;background:var(--surface);
  box-shadow:var(--shadow);
  transition:box-shadow var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.swatch-item:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}
.swatch-color{height:54px}
.swatch-info{padding:7px 9px}
.swatch-name{font-size:var(--fs-12);font-weight:600}
.swatch-code{font-size:10.5px;color:var(--text-3);font-family:var(--font-mono)}

/* ============================================================
   材料库瀑布流
   ============================================================ */
.mat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(196px,1fr));gap:var(--sp-3)}
.mat-card{
  border:none;border-radius:var(--radius);overflow:hidden;background:var(--surface);
  box-shadow:var(--shadow);
  transition:box-shadow var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease);
}
.mat-card:hover{box-shadow:var(--shadow-md);transform:translateY(-3px)}
.mat-thumb{height:116px;position:relative}
.mat-info{padding:11px var(--sp-3) var(--sp-3)}
.mat-name{font-size:var(--fs-14);font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mat-brand{font-size:var(--fs-12);color:var(--text-3);margin-top:2px}
.mat-tags{display:flex;gap:var(--sp-1);flex-wrap:wrap;margin-top:var(--sp-2)}
.mat-price{
  font-size:var(--fs-13);font-weight:700;margin-top:var(--sp-2);font-variant-numeric:tabular-nums;
  background:linear-gradient(90deg,var(--c-primary-dark),var(--c-primary));
  -webkit-background-clip:text;background-clip:text;color:transparent;
}

/* ============================================================
   流程步骤
   ============================================================ */
.steps{display:flex;gap:0;overflow-x:auto;padding:var(--sp-1) 0}
.step{flex:1;min-width:136px;position:relative;padding:0 8px}
.step-bar{height:5px;background:var(--surface-3);border-radius:var(--radius-pill);margin-bottom:10px;transition:background var(--dur-slow) var(--ease)}
.step-bar.done{background:var(--c-ok)}
.step-bar.active{background:var(--c-primary)}
.step-name{font-size:var(--fs-13);font-weight:600}
.step-meta{font-size:var(--fs-11);color:var(--text-3);margin-top:2px}

/* ============================================================
   空状态
   ============================================================ */
.empty{padding:var(--sp-6) var(--sp-5);text-align:center;color:var(--text-3);font-size:var(--fs-13);line-height:1.85}
.empty-icon{font-size:36px;opacity:.32;margin-bottom:var(--sp-2);filter:saturate(.6)}

/* ============================================================
   类 Excel 总表（保留网格隐喻，功能需要）
   ============================================================ */
.xl-wrap{
  overflow:auto;max-height:calc(100vh - 250px);
  border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);
  box-shadow:var(--shadow-xs);
}
.xl{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--fs-13)}
.xl th{
  position:sticky;top:0;z-index:3;
  background:color-mix(in oklch,var(--c-primary) 13%,var(--surface));
  color:var(--c-primary-dark);font-weight:700;font-size:var(--fs-12);white-space:nowrap;padding:9px 11px;
  border-bottom:1px solid var(--border-strong);border-right:1px solid var(--border);
}
.xl th.grp{
  background:color-mix(in oklch,var(--c-primary) 22%,var(--surface));
  color:var(--c-primary-dark);text-align:center;font-weight:700;
}
.xl td{
  padding:0;border-bottom:1px solid var(--border);border-right:1px solid var(--border);
  background:var(--surface);transition:background var(--dur) var(--ease);
}
.xl tbody tr:hover td{background:var(--c-primary-soft)}
.xl .cell{display:block;padding:8px 11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:190px}
.xl input[type=text]{
  width:100%;border:none;padding:8px 11px;font-size:var(--fs-13);font-family:inherit;
  background:transparent;color:var(--text);min-width:92px;
}
.xl input[type=text]:focus{outline:2px solid var(--c-primary);outline-offset:-2px;background:var(--surface)}
.xl select{
  width:100%;border:none;padding:8px 10px;font-size:var(--fs-13);font-family:inherit;
  background:transparent;color:var(--text);cursor:pointer;min-width:120px;
}
.xl select:focus{outline:2px solid var(--c-primary);outline-offset:-2px;background:var(--surface)}
/* 单元格编辑器可交互提示（2026-09-23）：总表里的下拉/输入原先完全透明，
   和纯文本长得一样，用户看不出这一格能点。hover 时把格子抬成近白面 + 主色发丝内描边，
   与「行 hover 的淡蓝底」形成反差，明确「这是控件、不是文字」。
   用 inset 阴影而非 border，避免 1px 边框引起落格跳动。 */
.xl td select,.xl td input[type=text]{
  transition:background var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.xl td select:hover,.xl td input[type=text]:hover{
  background:var(--surface);box-shadow:inset 0 0 0 1px var(--c-primary-line);
}
.xl .sw{
  width:14px;height:14px;border-radius:4px;border:1px solid var(--border-strong);flex:0 0 14px;
  display:inline-block;vertical-align:-2px;margin-right:6px;
}
.xl tr.row-detached td{background:var(--c-warn-soft)}
.xl td.empty-cell{background:var(--c-warn-soft)}
/* 已脱离典型类型的行：hover 不被普通主色行悬浮盖过，保持并加深警示色调 */
.xl tbody tr.row-detached:hover td{background:color-mix(in oklch,var(--c-warn) 16%,var(--c-warn-soft))}

/* 物料书逐格自定义 */
.xl td[data-cell]{cursor:pointer;padding:7px 11px;line-height:1.55}
.xl td[data-cell]:hover{box-shadow:inset 0 0 0 1.5px var(--c-primary)}
.xl td.cell-edited{background:var(--c-warn-soft);box-shadow:inset 0 -2px 0 var(--c-warn)}
.xl td.cell-edited[data-cell]:hover{box-shadow:inset 0 0 0 1.5px var(--c-primary),inset 0 -2px 0 var(--c-warn)}

/* ============================================================
   吸附列（冻结列）· 2026-09-23
   需求：空间配置总表 / 三级流程配置总表 / 物料书 的左侧若干「定位列」
   （楼层·房间·科室·典型类型 / 楼层·房间·科室名称·典型类型 /
     标记色·材料编号·材料名称·使用区域·使用位置）
   在左右滚动时始终停在表格左边，不被推出视野。
   实现：由 UI.pinCols(wrap, n) 在挂载后量出前 n 列的实际宽度，
   逐列累加写入行内 left，并给每列（含表头）加 .pin。
   为什么按「前 n 列」而不是给每个 <td> 打 data-pin：
   三张表要固定的都恰好是各自最左的连续几列，按列位处理
   只需调列顺序 + 在 mount 里调一次，不必改到每一格的行体生成代码。
   ============================================================ */
.xl .pin{position:sticky;z-index:2}
/* ⚠️ 特异性：.xl .pin(0,2,0) 会盖掉 .xl th(0,1,1) 的 z-index:3，
   若不显式提回，横向滚动时表头会被吸附的 <td> 压住（表头消失）。
   这里用 .xl th.pin(0,2,1) 把它抬到 4，确保表头永远在最上层。 */
.xl th.pin{z-index:4}
/* 最后一条吸附列的右缘：投影 + 描边，让「冻结区 / 滚动区」有明确分界，
   否则两段同色单元格在滚动中会糊在一起，看不出是从哪里滑过去的。
   投影用 -6px 负扩散，只落在右侧，不影响左侧列。 */
.xl .pin-edge{
  box-shadow:6px 0 8px -6px oklch(0 0 0 / .28);
  border-right:1px solid var(--border-strong);
}

/* 物料书 v3.1：固定列宽（编辑时不挤动布局）+ 限高滚动（横向滚动条常驻可见） */
.xl.book-fixed{table-layout:fixed}
.xl.book-fixed th,.xl.book-fixed td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.xl.book-fixed th[data-sort="marker"]{width:88px}
.xl.book-fixed th[data-sort="mat_code"]{width:112px}
.xl.book-fixed th[data-sort="mat_name"]{width:130px}
.xl.book-fixed th[data-sort="use_area"]{width:150px}
.xl.book-fixed th[data-sort="use_location"]{width:170px}
.xl.book-fixed th[data-sort="mat_category"]{width:112px}
.xl.book-fixed th[data-sort="brand"]{width:120px}
.xl.book-fixed th[data-sort="approved"]{width:150px}
.xl.book-fixed th[data-sort="series"]{width:122px}
.xl.book-fixed th[data-sort="model"]{width:110px}
.xl.book-fixed th[data-sort="color"]{width:104px}
.xl.book-fixed th[data-sort="size"]{width:120px}
.xl.book-fixed th[data-sort="surface"]{width:104px}
.xl.book-fixed th[data-sort="fire_rating"]{width:92px}
.xl.book-fixed th[data-sort="tech_params"]{width:170px}
.xl.book-fixed th[data-sort="tech_spec"]{width:170px}
.xl.book-fixed th[data-sort="origin"]{width:92px}
.xl.book-fixed th[data-sort="supplier"]{width:126px}
.xl.book-fixed th[data-sort="contact"]{width:126px}
.xl.book-fixed th[data-sort="image"]{width:96px}
.xl.book-fixed th[data-sort="remark"]{width:132px}
.xl.book-fixed th[data-sort="history"]{width:150px}
.xl.book-fixed td[data-cell] input,
.xl.book-fixed td[data-cell] select,
.xl.book-fixed td[data-cell] textarea{min-width:0}
.book-scroll{max-height:calc(100vh - 225px)}

/* 空间配置总表：表格限高按本页「顶栏 + 页头 + 统计条 + 工具条 + 批量条 + 卡头」实占高度收紧。
   实测叠高 ≈ 338px（顶栏 50 + 内容区上内边距 16 + 页头 66 + 统计条 46 + 工具条 46 + 批量条 58 + 卡头 56），
   再为卡底提示行与页底内边距留 ≈54px。原 .xl-wrap 的 100vh-250px 对本页偏松，
   表格底部会掉到折叠线以下、滚一屏才能看到最后几行；max() 兜底，避免小视口把表格压没。 */
.st-wrap{max-height:max(320px, calc(100vh - 392px))}

/* 需求3：标记色整行填充（td 透出 tr 背景色；已自定义格保留琥珀标注）
   2026-09-23：悬停遮罩与已编辑格原为硬编码浅色 rgba(255,255,255,.38) /
   rgba(255,251,235,.92)——深色模式下会在标记色上盖出一层刺眼白斑。
   改为对 --surface / --c-warn-soft 做 color-mix，明暗两套主题各自成立：
   浅色=向近白抬升，深色=向深面抬升，语义一致。 */
/* ⚠️ 吸附列与标记行的冲突（2026-09-23 加吸附列时实测发现）：
   下面这一组规则让 td 透出 tr 的标记色，即 td 的 background 是 transparent；
   「已编辑格」那层还带 0.92 的 alpha。这两者一旦落在吸附格上，
   横向滚动时右边的列会从它底下直接穿过去 ——「冻结」变成了「透明玻璃」。
   所以吸附格必须自带**完全不透明**的底色，颜色取 --row-mark
   （book.js 把标记色同时写在 <tr> 的内联 style 上）。
   实现上用 :not(.pin) 把吸附格从「透明 / 半透明」那几条规则里**摘出去**，
   而不是靠提高特异性去压它们 —— 后者试过：同特异性的两条规则谁赢
   取决于书写顺序，实测 .pin 那条并未胜出，属于会被误改的隐式耦合。
   :not(.pin) 是明确的「不适用」，改序也不会翻车。 */
.xl tr.row-marked td:not(.pin){background:transparent}
.xl tbody tr.row-marked:hover td:not(.pin){background:color-mix(in oklch,var(--surface) 45%,transparent)}
.xl tr.row-marked td.cell-edited:not(.pin){background:color-mix(in oklch,var(--c-warn-soft) 92%,transparent)}

/* 吸附格：一律铺不透明的标记色；悬停/已编辑再叠一层同色底纹，alpha 仍为 1 */
.xl tr.row-marked td.pin{background-color:var(--row-mark)}
.xl tbody tr.row-marked:hover td.pin{
  background:linear-gradient(0deg,
    color-mix(in oklch,var(--surface) 45%,transparent),
    color-mix(in oklch,var(--surface) 45%,transparent)),var(--row-mark);
}
.xl tr.row-marked td.pin.cell-edited{
  background:linear-gradient(0deg,
    color-mix(in oklch,var(--c-warn-soft) 92%,transparent),
    color-mix(in oklch,var(--c-warn-soft) 92%,transparent)),var(--row-mark);
}

/* ============================================================
   典型类型管理
   ============================================================ */
.tt-item{
  border:none;border-radius:var(--radius-sm);padding:var(--sp-3) var(--sp-4);
  margin-bottom:var(--sp-2);background:var(--surface-2);
  transition:background var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.tt-item:hover{background:var(--surface);box-shadow:var(--shadow)}
.tt-item.active{background:var(--c-primary-soft);box-shadow:inset 0 0 0 1px var(--c-primary-line)}
.tt-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:var(--sp-2)}
.tt-name{font-size:var(--fs-14);font-weight:650}
.tt-cfg{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--sp-2)}
.tt-cfg-item{
  display:flex;align-items:center;gap:6px;font-size:var(--fs-12);
  background:var(--surface);border:none;border-radius:var(--radius-xs);padding:6px 10px;
  box-shadow:var(--shadow-xs);
}
.tt-cfg-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ============================================================
   Toast
   ============================================================ */
.toast-host{position:fixed;bottom:var(--sp-5);right:var(--sp-5);display:flex;flex-direction:column;gap:var(--sp-2);z-index:100}
.toast{
  background:oklch(0.24 0.01 80);color:#fff;padding:11px var(--sp-4);border-radius:var(--radius-sm);
  font-size:var(--fs-13);line-height:1.6;box-shadow:var(--shadow-lg);
  animation:slideIn var(--dur-slow) var(--ease);max-width:360px;
}
.toast.ok{background:linear-gradient(135deg,oklch(0.40 0.05 156),oklch(0.46 0.05 156))}
.toast.warn{background:linear-gradient(135deg,oklch(0.42 0.06 80),oklch(0.48 0.06 80))}
.toast.err{background:linear-gradient(135deg,oklch(0.43 0.075 28),oklch(0.49 0.075 28))}
@keyframes slideIn{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}

.toast-host > div[style*="position:fixed"]{animation:fadeIn var(--dur) var(--ease)}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}

/* ============================================================
   滚动条
   ============================================================ */
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:oklch(0.84 0.008 85);border-radius:var(--radius-pill);border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:oklch(0.77 0.01 85);background-clip:content-box}
::-webkit-scrollbar-track{background:transparent}

/* ============================================================
   响应式
   ============================================================ */
@media(max-width:1440px){
  .proj-select{min-width:180px}
  .search-box input{width:200px}
}
@media(max-width:1180px){
  :root{--sidebar-w:212px}
  .search-box input{width:170px}
  .content{padding:var(--sp-3) var(--sp-3) var(--sp-5)}
}
@media(max-width:1024px){
  .topbar{padding:0 var(--sp-3)}
  .search-box{display:none}
  .proj-select{min-width:150px}
  .page-head{align-items:flex-start;flex-direction:column}
  .page-actions{width:100%}
}
@media(max-width:860px){
  .main{margin-left:var(--sidebar-mini-w)}
  .sidebar{width:var(--sidebar-mini-w);flex-basis:var(--sidebar-mini-w)}
  .brand-text,.sidebar-foot{display:none}
  /* 选择器带 .app 是为了与 .nav-item.nav-top 同为 (0,2,0)；本段在源码中更靠后，
     同权重时后者胜出，收起态的内边距才能盖住顶层项自己的 padding */
  .app .nav-item{justify-content:center;gap:0;padding:9px 0;margin:0 8px 2px}
  .ni-text{display:none}
  .sidebar:hover{width:var(--sidebar-w);flex-basis:var(--sidebar-w);box-shadow:8px 0 32px rgba(40,37,32,.10)}
  .sidebar:hover .brand-text,.sidebar:hover .sidebar-foot{display:block}
  .sidebar:hover .nav-item{justify-content:flex-start;gap:10px;padding:8px 11px;margin:0 0 2px}
  .sidebar:hover .ni-text{display:inline}
  .content{padding:var(--sp-3)}
}
@media(max-width:640px){
  .topbar{height:auto;padding:var(--sp-2) var(--sp-3);flex-wrap:wrap;gap:var(--sp-2)}
  .topbar-left,.topbar-right{flex-wrap:wrap}
  .proj-select,.edition-select{min-width:120px;flex:1}
  .page-title{font-size:var(--fs-16)}
}

/* 打印 */
@media print{
  .sidebar,.topbar,.page-actions,.toast-host{display:none!important}
  .main{margin-left:0!important}
  .card,.table-wrap,.xl-wrap{box-shadow:none!important}
  .content{padding:0}
  body{background:var(--surface)!important}
}

/* 减少动效 */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}

/* ============================================================
   暗色模式（跟随系统，浅色优先；莫兰迪暖夜）
   ============================================================ */
@media(prefers-color-scheme:dark){
  :root{
    --bg:oklch(0.21 0.006 80);
    --bg-elevated:oklch(0.245 0.007 80);
    --surface:oklch(0.235 0.007 80);
    --surface-2:oklch(0.265 0.008 80);
    --surface-3:oklch(0.30 0.008 80);
    --border:oklch(0.345 0.009 80);
    --border-strong:oklch(0.42 0.01 80);
    --text:oklch(0.93 0.006 80);
    --text-2:oklch(0.76 0.012 80);
    --text-3:oklch(0.62 0.01 80);
    --c-primary:oklch(0.72 0.10 252);
    --c-primary-hover:oklch(0.80 0.10 252);
    --c-primary-strong:oklch(0.82 0.09 252);
    --c-primary-strong-hover:oklch(0.76 0.10 252);
    --c-primary-dark:oklch(0.88 0.07 252);
    --c-primary-soft:oklch(0.31 0.04 252);
    --c-primary-line:oklch(0.45 0.06 252);
    --c-accent:oklch(0.72 0.10 252);
    --c-ok:oklch(0.72 0.06 156);  --c-ok-soft:oklch(0.30 0.022 156);  --c-ok-line:oklch(0.42 0.035 156);
    --c-warn:oklch(0.75 0.07 82); --c-warn-soft:oklch(0.315 0.03 82); --c-warn-line:oklch(0.45 0.04 82);
    --c-danger:oklch(0.74 0.07 28);--c-danger-soft:oklch(0.315 0.03 30);--c-danger-line:oklch(0.46 0.045 30);
    --c-info:oklch(0.74 0.045 285);--c-info-soft:oklch(0.30 0.022 285);--c-info-line:oklch(0.44 0.03 285);
    --shadow:0 1px 2px rgba(0,0,0,.4),0 2px 6px rgba(0,0,0,.38);
    --shadow-md:0 2px 4px rgba(0,0,0,.4),0 8px 22px rgba(0,0,0,.46);
    --shadow-lg:0 6px 16px rgba(0,0,0,.5),0 20px 44px rgba(0,0,0,.55);
    --ring:0 0 0 3px oklch(0.72 0.10 252 / .24);
  }
  body{
    background:
      radial-gradient(1100px 520px at 82% -8%, oklch(0.62 0.10 252 / .07) 0%, oklch(0.62 0.10 252 / 0) 62%),
      radial-gradient(900px 420px at -10% 108%, oklch(0.70 0.12 252 / .05) 0%, oklch(0.70 0.12 252 / 0) 58%),
      var(--bg);
  }
  .topbar{background:oklch(0.235 0.007 80 / .82)}
  .card{border-color:rgba(255,255,255,.045)}
  .stat-value{background:linear-gradient(160deg,var(--text) 30%,oklch(0.7 0.02 80) 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
  .toast{background:oklch(0.30 0.01 80);color:var(--text)}
  /* 填充按钮在深色下反转为亮钴蓝 + 深字 */
  .btn-primary{
    background:linear-gradient(180deg,oklch(0.82 0.09 252),oklch(0.76 0.10 252));
    color:oklch(0.16 0.06 252);
    box-shadow:0 1px 2px rgba(0,0,0,.3),inset 0 1px 0 oklch(1 0 0 / .28);
  }
  .btn-primary:hover{
    background:linear-gradient(180deg,oklch(0.78 0.10 252),oklch(0.70 0.11 252));
    color:oklch(0.16 0.06 252);
  }
  /* 深色下选中标签：--c-primary-dark 已提亮（明度 0.88），白字对比度不足；
     与 .btn-primary 同规则，底用中亮蓝、字反转为深蓝 */
  .sub-tab.active{
    background:linear-gradient(180deg,oklch(0.82 0.09 252),oklch(0.76 0.10 252));
    color:oklch(0.16 0.06 252);
  }
  .sub-tab.active:hover{
    background:linear-gradient(180deg,oklch(0.78 0.10 252),oklch(0.70 0.11 252));
    color:oklch(0.16 0.06 252);
  }
  .brand-logo,.avatar{
    background:linear-gradient(135deg,oklch(0.82 0.09 252),oklch(0.70 0.10 252));
    color:oklch(0.16 0.06 252);
    box-shadow:0 2px 10px rgba(0,0,0,.35),inset 0 1px 0 oklch(1 0 0 / .18);
  }
  /* 表头在深色下提高蓝染浓度，仍与编辑区（深灰面）拉开 */
  th,.xl th{background:color-mix(in oklch,var(--c-primary) 20%,var(--surface))}
  .xl th.grp{background:color-mix(in oklch,var(--c-primary) 30%,var(--surface))}
  /* 兜底：残留的内联浅色背景统一收进主题 */
  [style*="background:#fff"],[style*="background: #fff"],
  [style*="background:#F9FAFB"],[style*="background: #F9FAFB"],
  [style*="background:#FAFBFC"],[style*="background: #FAFBFC"]{
    background:var(--surface-2)!important;color:var(--text)!important;
  }
  [style*="color:#111827"],[style*="color: #111827"],
  [style*="color:#374151"],[style*="color: #374151"]{color:var(--text)!important}
  [style*="color:#6B7280"],[style*="color: #6B7280"]{color:var(--text-3)!important}
}

/* 2026-09-05 统一品牌色：全站只用一个高饱和钴蓝（--c-primary 体系），
   应用于导航高亮 / 主按钮 / Logo / 页标题短条 / 表头淡染等核心位置。 */

/* ============================================================
   欢迎页（views/welcome.js）—— 2026-09-23
   index 原先首屏直接落到「空间配置总表」，现改为先落欢迎页。
   本节全部取主题变量，浅色 / 深色自动适配，无需额外的深色覆盖规则。
   ============================================================ */
.welcome-hero{
  display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);
  flex-wrap:wrap;padding:var(--sp-5);margin-bottom:var(--sp-4);
  border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--surface-2);
}
.welcome-hero h2{margin:0 0 6px;font-size:var(--fs-22);font-weight:700;color:var(--text)}
.welcome-hero .wh-sub{font-size:var(--fs-14);color:var(--text-2);line-height:var(--lh-base);max-width:760px}
.welcome-hero .wh-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--sp-3)}

.welcome-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));
  gap:var(--sp-3);padding:var(--sp-4);
}
.welcome-card{
  display:flex;flex-direction:column;gap:10px;
  padding:var(--sp-3) var(--sp-4);
  border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);
}
.welcome-card .wc-head{display:flex;align-items:center;gap:9px}
.welcome-card .wc-icon{
  width:26px;height:26px;flex:0 0 auto;border-radius:var(--radius-sm);
  display:flex;align-items:center;justify-content:center;
  background:var(--c-primary-soft);color:var(--c-primary-dark);font-size:var(--fs-14);
}
.welcome-card .wc-name{font-size:var(--fs-14);font-weight:600;color:var(--text)}
.welcome-card .wc-links{display:flex;flex-wrap:wrap;gap:6px}
.welcome-link{
  font:inherit;font-size:var(--fs-13);line-height:1.5;cursor:pointer;
  padding:4px 11px;border-radius:var(--radius-pill);
  border:1px solid var(--border);background:var(--surface-3);color:var(--text-2);
  transition:color var(--dur) var(--ease),background var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
.welcome-link:hover{color:var(--c-primary-dark);border-color:var(--c-primary-line);background:var(--c-primary-soft)}

.welcome-project{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
  gap:var(--sp-3);padding:var(--sp-4) var(--sp-4) var(--sp-3);
}
.welcome-project .wp-k{font-size:var(--fs-12);color:var(--text-3);margin-bottom:3px}
.welcome-project .wp-v{font-size:var(--fs-16);font-weight:600;color:var(--text)}
.wp-foot{padding:0 var(--sp-4) var(--sp-4)}
.wp-foot .wp-k{font-size:var(--fs-12);color:var(--text-3);margin-bottom:6px}
