@charset "UTF-8";
/* ==================================================================
   NETGRID · 添饭网络中台   |   设计系统 v5.0（毛玻璃主题）
   Design Language: 企业蓝浅色 + Glassmorphism
   ------------------------------------------------------------------
   配色遵循 WCAG AA：正文对比度 ≥ 4.5:1，大字与图形元素 ≥ 3:1
   字体仅使用系统字体栈（NAS 可能无外网，不依赖任何 CDN）
   形状语言：8/12px 圆角，半透明表面 + backdrop-filter 雾化 + 高光边
   状态编码：色条 + 文字徽章 + 圆点三重冗余（色盲友好）

   ⚠ app.js 内联样式直接引用 --up/--down/--warn/--muted/--muted-2 等
     变量名，这些别名禁止删除。
   ⚠ 毛玻璃必须配合「有色彩的衬底」才可见：body 用多重 radial-gradient
     光斑 + 线性渐变打底，卡片用半透明白 + backdrop-filter:blur() 透出。
     若以后把 body 背景改回纯色/纯白，毛玻璃会变成「半透明块」失去质感。
   ================================================================== */

/* ============ 1. 设计令牌 ============ */
:root{
  /* --- 品牌 --- */
  --brand:       #0071E3;
  --brand-ink:   #0058C7;
  --brand-wash:  #EAF2FE;

  /* --- 语义状态（= app.js 内联引用名） --- */
  --up:          #0E9F6E;
  --up-wash:     #E7F7F0;
  --warn:        #B54708;
  --warn-wash:   #FEF3E6;
  --down:        #D92D20;
  --down-wash:   #FDECEA;

  /* --- 文字层级 --- */
  --text:        #12161C;   /* ink-1 */
  --ink-2:       #39424F;
  --muted:       #6B7683;   /* ink-3 */
  --muted-2:     #98A2AE;   /* ink-4 */

  /* --- 线与底 --- */
  --line:        #E4E8EE;
  --line-2:      #EFF2F6;
  --bg:          #F5F7FA;
  --panel:       #FFFFFF;
  --card:        #FFFFFF;

  /* --- 图表专用（drawTrend 用；SVG 内联样式读不到外部 class，必须走变量）--- */
  --chart-line:  #D9E0E9;   /* 网格线，比 --line 稍明显一点但仍克制 */
  --chart-ink:   #6B7683;   /* 坐标轴文字 = --muted */
  --chart-dot:   #FFFFFF;   /* 数据点描边 = 卡片底色，挖空效果 */
  --chart-area:  0.22;      /* 面积填充起始透明度 */

  /* --- 兼容别名 --- */
  --accent:      var(--brand);
  --accent-dim:  var(--brand-ink);

  /* --- 形状 --- */
  --r-s:         11px;
  --r-m:         16px;
  --r-pill:      999px;

  /* --- 投影（克制，玻璃卡已改用雾化阴影，见下） --- */
  --sh-1:        0 1px 2px rgba(18,22,28,.05);
  --sh-2:        0 2px 8px rgba(18,22,28,.07), 0 1px 2px rgba(18,22,28,.04);

  /* --- 玻璃材质（2026-10-06 毛玻璃主题）---
     glass-bg   : 卡片半透明白，blur 后有磨砂感
     glass-brd  : 1px 半透明白边，模拟玻璃边缘高光
     glass-sh   : 雾化投影（比实色卡更柔、更「飘」）
     glass-in   : inset 顶部高光，玻璃立体感关键
     注：blur 用硬编码数值（不同层模糊量不同），不依赖变量 */
  --glass-bg:     rgba(255,255,255,.50);
  --glass-strong: rgba(255,255,255,.66);
  --glass-brd:    rgba(255,255,255,.70);
  --glass-sh:     0 10px 36px rgba(31,38,135,.14);
  --glass-in:     inset 0 1px 0 rgba(255,255,255,.75);

  /* --- 侧栏 --- */
  --side-w:      240px;
  --side-bg:     rgba(255,255,255,.42);
  --side-ink:    #1d1d1f;
  --side-ink-2:  #6e6e73;
}

/* ============ 2. 基础 ============ */
*{ box-sizing:border-box; }
html,body{ height:100%; }
body{
  margin:0;
  /* 毛玻璃衬底：四角彩色光斑 + 浅蓝→白→浅绿渐变打底。
     background-attachment:fixed 让光斑固定，卡片滑过时有「磨砂后景」层次。 */
  background:
    radial-gradient(820px 620px at 8% 2%,   rgba(255,122,180,.22), transparent 58%),
    radial-gradient(760px 580px at 95% 4%,  rgba(64,156,255,.24),   transparent 58%),
    radial-gradient(900px 700px at 90% 98%, rgba(154,108,255,.20),  transparent 60%),
    radial-gradient(820px 620px at 4% 96%,  rgba(52,199,89,.16),    transparent 60%),
    radial-gradient(680px 500px at 50% 52%, rgba(255,214,102,.10),  transparent 60%),
    linear-gradient(135deg,#eef3ff 0%,#f6f0ff 48%,#eafaf3 100%);
  background-attachment:fixed;
  color:var(--text);
  font:14px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans SC",sans-serif;
  -webkit-font-smoothing:antialiased;
}
a{ color:var(--brand); text-decoration:none; }
a:hover{ text-decoration:underline; }
button,input,select,textarea{ font:inherit; color:inherit; }
::selection{ background:var(--brand-wash); color:var(--brand-ink); }
:focus-visible{ outline:2px solid var(--brand); outline-offset:2px; border-radius:4px; }

::-webkit-scrollbar{ width:10px; height:10px; }
::-webkit-scrollbar-track{ background:transparent; }
::-webkit-scrollbar-thumb{ background:rgba(150,162,174,.55); border-radius:999px; border:3px solid transparent; background-clip:padding-box; }
::-webkit-scrollbar-thumb:hover{ background:rgba(120,134,150,.7); background-clip:padding-box; }

/* ============ 3. 骨架：侧栏 + 主区 ============ */
.shell{ display:flex; min-height:100vh; }

/* ---------- 3.1 左侧栏 ---------- */
.side{
  width:var(--side-w); flex:0 0 var(--side-w);
  background:var(--side-bg); color:var(--side-ink);
  -webkit-backdrop-filter:blur(30px) saturate(180%);
  backdrop-filter:blur(30px) saturate(180%);
  border-right:1px solid rgba(255,255,255,.55);
  box-shadow:2px 0 24px rgba(31,38,135,.08);
  display:flex; flex-direction:column;
  position:sticky; top:0; height:100vh; z-index:30;
}
.side-brand{
  display:flex; align-items:center; gap:10px;
  padding:16px 14px; border-bottom:1px solid rgba(0,0,0,.08);
}
.side-logo{
  width:32px; height:32px; flex:0 0 32px;
  border-radius:9px; background:var(--brand); color:#fff;
  display:grid; place-items:center;
}
.side-logo svg{ width:18px; height:18px; display:block; }
.side-txt{ display:flex; flex-direction:column; min-width:0; flex:1; }
/* 品牌名完整显示，不再截断。
   公司全名「中山市添饭餐饮管理有限公司-网络监控中心」共 20 字。

   ⚠️ 宽度是硬约束（2026-10-05 实测算出来的，别凭感觉调）：
      侧栏 216px − 左右内边距 28 − logo 32 − 两个 gap 10×2 − 状态点 8
      = 文字可用宽度仅 128px。
      13px 字号每行只放得下 9~10 个汉字 → 两行 18~20 字，
      实测第二行末尾仍出「…」，就是差这几个字。

   所以：字号降到 12px（每行 10~11 字），行数放宽到 3 行。
   3 行 = 30+ 字容量，对 20 字有富余；
   而且 site_title 是可以在「设置」里改的，以后填更长也能兜住。 */
.side-brand .bname{
  font-size:12px; font-weight:650; color:var(--text); line-height:1.38;
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
  overflow:hidden; word-break:break-all;
}
.side-brand .btag{
  font-size:10px; font-weight:500; color:var(--side-ink-2);
  letter-spacing:.4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  margin-top:1px;
}
.side-brand .dot{
  width:8px; height:8px; flex:0 0 8px; border-radius:50%;
  background:#22C55E; box-shadow:0 0 0 3px rgba(34,197,94,.16);
}
.side-brand .dot.off{ background:#EF4444; box-shadow:0 0 0 3px rgba(239,68,68,.16); animation:pulseDot 1.6s ease-in-out infinite; }
@keyframes pulseDot{ 0%,100%{opacity:1} 50%{opacity:.35} }

.side-nav{ flex:1; overflow-y:auto; padding:10px 10px 16px; }
.side-nav .grp{
  font-size:10.5px; font-weight:600; letter-spacing:1.2px;
  color:#5B6A80; padding:14px 10px 6px;
}
.side-nav button{
  display:flex; align-items:center; gap:11px; width:100%;
  padding:8px 10px; margin-bottom:2px;
  background:transparent; border:0; border-radius:var(--r-s);
  color:var(--side-ink); font-size:13.5px; font-weight:500;
  cursor:pointer; text-align:left;
  transition:background .14s, color .14s;
}
.side-nav button .lb{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.side-nav button:hover{ background:rgba(0,0,0,.05); color:var(--text); }
.side-nav button.active{ background:var(--brand); color:#fff; font-weight:600; box-shadow:0 4px 12px rgba(0,113,227,.30); }
.side-nav button.active .app-ico{ box-shadow:inset 0 1px 0 rgba(255,255,255,.4),0 3px 8px rgba(0,0,0,.18); }

.side-foot{ padding:10px; border-top:1px solid rgba(255,255,255,.07); }
.side-foot button{
  display:flex; align-items:center; gap:11px; width:100%;
  padding:8px 10px; margin-bottom:6px;
  background:transparent; border:0; border-radius:var(--r-s);
  color:var(--side-ink-2); font-size:13px; cursor:pointer; text-align:left;
  transition:background .14s, color .14s;
}
.side-foot button:hover{ background:rgba(0,0,0,.05); color:var(--text); }
.side-foot button.active{ background:rgba(0,113,227,.14); color:var(--brand-ink); }
.side-foot .clock{
  padding:8px 10px 2px; font-size:11.5px; color:#5B6A80;
  font-variant-numeric:tabular-nums;
}
.side-foot .clock .muted{ color:#55637A; }

/* ---------- 苹果风 app-icon（侧栏圆角方块图标） ---------- */
.app-ico{
  width:30px; height:30px; flex:0 0 30px; border-radius:8px;
  display:flex; align-items:center; justify-content:center;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),0 3px 8px rgba(0,0,0,.12);
}
.app-ico svg{ width:17px; height:17px; display:block; }

/* ---------- 3.2 主区 ---------- */
.main{ flex:1; min-width:0; display:flex; flex-direction:column; }
.wrap{ flex:1; width:100%; max-width:1640px; padding:22px 24px 44px; }

/* 页头 */
.page-head{
  display:flex; align-items:flex-end; gap:12px;
  margin-bottom:16px; padding-bottom:14px; border-bottom:1px solid rgba(255,255,255,.5);
  flex-wrap:wrap;
}
.page-head h1{
  margin:0; font-size:19px; font-weight:680; letter-spacing:-.2px; color:var(--text);
}
.page-head .sub{ font-size:12.5px; color:var(--muted); }
.page-head .spacer{ flex:1; }

/* ============ 4. 卡片 / 网格 / 标题（毛玻璃） ============ */
.card{
  background:var(--glass-bg);
  border:1px solid var(--glass-brd);
  border-radius:var(--r-m); padding:16px 18px;
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(16px) saturate(160%);
  backdrop-filter:blur(16px) saturate(160%);
}
.card h3{
  margin:0 0 14px; font-size:14.5px; font-weight:650; color:var(--text);
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
}
.card h3 .sub{ font-size:12px; font-weight:400; color:var(--muted); }
.grid{ display:grid; gap:14px; }

.section-title{
  display:flex; align-items:center; gap:10px;
  margin:24px 0 12px; font-size:14px; font-weight:650; color:var(--text);
}
.section-title::before{
  content:""; width:3px; height:14px; border-radius:2px; background:var(--brand); flex:0 0 3px;
}
.section-title::after{ content:""; flex:1; height:1px; background:rgba(255,255,255,.5); }

.empty{
  padding:44px 20px; text-align:center; color:var(--muted-2); font-size:13px;
  background:var(--glass-bg); border:1px dashed var(--glass-brd); border-radius:var(--r-m);
  -webkit-backdrop-filter:blur(14px) saturate(150%);
  backdrop-filter:blur(14px) saturate(150%);
}
.spinner{
  display:inline-block; width:14px; height:14px; vertical-align:-2px;
  border:2px solid var(--line); border-top-color:var(--brand);
  border-radius:50%; animation:spin .7s linear infinite;
}
@keyframes spin{ to{ transform:rotate(360deg); } }

/* ============ 5. KPI（毛玻璃） ============ */
.kpis{ display:grid; grid-template-columns:repeat(auto-fit,minmax(172px,1fr)); gap:14px; }
.kpi{
  position:relative; overflow:hidden;
  background:var(--glass-bg); border:1px solid var(--glass-brd);
  border-radius:var(--r-m); padding:14px 16px 15px;
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(16px) saturate(160%);
  backdrop-filter:blur(16px) saturate(160%);
  transition:box-shadow .16s, border-color .16s, transform .16s;
}
.kpi:hover{ box-shadow:0 12px 38px rgba(13,38,76,.16), var(--glass-in); transform:translateY(-1px); border-color:rgba(255,255,255,.8); }
.kpi::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:var(--line); border-radius:3px 0 0 3px;
}
.kpi.up::before{ background:var(--up); }
.kpi.down::before{ background:var(--down); }
.kpi.warn::before{ background:var(--warn); }
.kpi .label{ font-size:12.5px; color:var(--muted); font-weight:500; }
.kpi .value{
  margin:6px 0 4px; font-size:27px; font-weight:700; line-height:1.15;
  color:var(--text); font-variant-numeric:tabular-nums; letter-spacing:-.5px;
}
.kpi .value small{ font-size:14px; font-weight:600; color:var(--muted-2); margin-left:2px; }
.kpi .hint{ font-size:11.5px; color:var(--muted-2); line-height:1.45; }

/* 英雄 KPI：唯一实心蓝（保留实心，作为视觉锚点，不改成玻璃） */
.kpi.k-hero{
  background:linear-gradient(135deg,var(--brand) 0%,var(--brand-ink) 100%);
  border-color:var(--brand-ink); color:#fff;
}
.kpi.k-hero::before{ display:none; }
.kpi.k-hero .label{ color:rgba(255,255,255,.85); }
.kpi.k-hero .value{ color:#fff; }
.kpi.k-hero .value small{ color:rgba(255,255,255,.75); }
.kpi.k-hero .hint{ color:rgba(255,255,255,.78); }

/* ============ 6. 状态徽章（三重编码：文字+圆点+色） ============ */
.state{
  display:inline-flex; align-items:center; gap:5px;
  padding:2px 9px 2px 7px; border-radius:var(--r-pill);
  font-size:11.5px; font-weight:600; white-space:nowrap;
  border:1px solid transparent;
  -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);
}
.state i{ width:6px; height:6px; border-radius:50%; flex:0 0 6px; }
.state.on{ background:rgba(231,247,240,.66); color:var(--up); border-color:rgba(14,159,110,.28); }
.state.on i{ background:var(--up); }
.state.off{ background:rgba(253,236,234,.66); color:var(--down); border-color:rgba(217,45,32,.28); }
.state.off i{ background:var(--down); }
.state.unk{ background:rgba(241,244,248,.6); color:var(--muted); border-color:rgba(228,232,238,.7); }
.state.unk i{ background:var(--muted-2); }

/* ============ 7. 表格（毛玻璃） ============ */
.table-wrap{
  overflow-x:auto;
  background:var(--glass-bg); border:1px solid var(--glass-brd); border-radius:var(--r-m);
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(12px) saturate(150%);
  backdrop-filter:blur(12px) saturate(150%);
}
table{ width:100%; border-collapse:collapse; font-size:13px; }
th{
  text-align:left; padding:10px 12px; white-space:nowrap;
  font-size:12px; font-weight:600; color:var(--muted);
  background:rgba(255,255,255,.42); border-bottom:1px solid rgba(255,255,255,.5);
}
td{ padding:10px 12px; border-bottom:1px solid rgba(228,232,238,.5); color:var(--ink-2); vertical-align:middle; }
tbody tr:last-child td{ border-bottom:0; }
tbody tr:hover{ background:rgba(255,255,255,.4); }
td.num{ text-align:right; font-variant-numeric:tabular-nums; font-weight:600; color:var(--text); }

.mono{ font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,"Courier New",monospace; font-size:12.5px; }
.muted{ color:var(--muted); }

/* ---------- 固定资产页：数字右对齐 / 状态徽章 / 行内操作 ---------- */
th.r, td.r{ text-align:right; font-variant-numeric:tabular-nums; }

.tag{
  display:inline-block; padding:2px 9px; border-radius:var(--r-pill);
  font-size:11.5px; font-weight:600; line-height:1.6; white-space:nowrap;
}
.tag-ok{   background:var(--up-wash);   color:var(--up);   border:1px solid color-mix(in srgb, var(--up) 25%, transparent); }
.tag-idle{ background:var(--brand-wash); color:var(--brand-ink); border:1px solid color-mix(in srgb, var(--brand) 22%, transparent); }
.tag-warn{ background:var(--warn-wash); color:var(--warn); border:1px solid color-mix(in srgb, var(--warn) 25%, transparent); }
.tag-bad{  background:var(--down-wash); color:var(--down); border:1px solid color-mix(in srgb, var(--down) 25%, transparent); }

.ops{ white-space:nowrap; }
.lnk{
  border:none; background:none; cursor:pointer; font-size:12.5px; font-weight:600;
  color:var(--brand); padding:2px 6px; border-radius:6px;
}
.lnk:hover{ background:var(--brand-wash); }
.lnk.danger{ color:var(--down); }
.lnk.danger:hover{ background:var(--down-wash); }

.pill{
  display:inline-block; padding:1px 8px; border-radius:var(--r-pill);
  font-size:11.5px; font-weight:500;
  border:1px solid rgba(255,255,255,.6); background:rgba(255,255,255,.45); color:var(--muted);
  -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);
}

/* 进度条 */
.bar{ height:6px; border-radius:999px; background:rgba(228,232,238,.55); overflow:hidden; }
.bar span{ display:block; height:100%; border-radius:999px; background:var(--up); transition:width .5s ease; }
.bar span.mid{ background:var(--warn); }
.bar span.low{ background:var(--down); }

/* ============ 8. 按钮 ============ */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:5px;
  padding:7px 13px; border-radius:var(--r-s);
  border:1px solid rgba(255,255,255,.65); background:var(--glass-bg); color:var(--ink-2);
  font-size:13px; font-weight:550; cursor:pointer; white-space:nowrap;
  -webkit-backdrop-filter:blur(8px) saturate(150%); backdrop-filter:blur(8px) saturate(150%);
  transition:background .14s, border-color .14s, color .14s, box-shadow .14s;
}
.btn:hover{ background:rgba(255,255,255,.78); border-color:rgba(255,255,255,.85); color:var(--text); }
.btn.primary{ background:var(--brand); border-color:var(--brand); color:#fff; box-shadow:var(--sh-1); -webkit-backdrop-filter:none; backdrop-filter:none; }
.btn.primary:hover{ background:var(--brand-ink); border-color:var(--brand-ink); }
.btn.danger{ background:var(--down); border-color:var(--down); color:#fff; -webkit-backdrop-filter:none; backdrop-filter:none; }
.btn.danger:hover{ background:#B42318; border-color:#B42318; }
.btn.sm{ padding:4px 9px; font-size:12px; }
.btn:disabled{ opacity:.45; cursor:not-allowed; }

/* 工具条 */
.toolbar{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin-bottom:14px; }
.toolbar .spacer{ flex:1; }

/* ============ 9. 表单 ============ */
.field{ display:flex; flex-direction:column; gap:5px; margin-bottom:14px; }
.field label{ font-size:12.5px; font-weight:600; color:var(--ink-2); }
.field label .req{ color:var(--down); margin-left:2px; }
.field input,.field select,.field textarea{
  width:100%; padding:8px 11px;
  border:1px solid var(--line); border-radius:var(--r-s);
  background:rgba(255,255,255,.8); font-size:13.5px; color:var(--text);
  transition:border-color .14s, box-shadow .14s;
}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none; border-color:var(--brand); box-shadow:0 0 0 3px rgba(11,95,255,.12);
}
.field input[type=checkbox]{ width:auto; }
.field textarea{ min-height:76px; resize:vertical; }
.field .tip{ font-size:11.5px; color:var(--muted-2); line-height:1.5; }
.form-row{ display:grid; grid-template-columns:1fr 1fr; gap:0 14px; }
@media(max-width:620px){ .form-row{ grid-template-columns:1fr; } }

.divider{ display:flex; align-items:center; gap:10px; margin:16px 0; font-size:11.5px; color:var(--muted-2); }
.divider::before,.divider::after{ content:""; flex:1; height:1px; background:rgba(255,255,255,.5); }

/* 角色标签 */
.role-pill{
  display:inline-block; padding:2px 9px; border-radius:var(--r-pill);
  font-size:11.5px; font-weight:600; border:1px solid transparent;
}
.role-pill.lv0{ background:rgba(241,244,248,.6); color:var(--muted); border-color:rgba(228,232,238,.7); }
.role-pill.lv1{ background:rgba(238,243,255,.7); color:var(--brand-ink); border-color:rgba(11,95,255,.28); }
.role-pill.lv2{ background:rgba(254,243,230,.7); color:var(--warn); border-color:rgba(181,71,8,.28); }

/* ============ 10. 项目健康卡（毛玻璃） ============ */
.proj-card{
  position:relative; overflow:hidden; cursor:pointer;
  background:var(--glass-bg); border:1px solid var(--glass-brd);
  border-radius:var(--r-m); padding:14px 16px 15px;
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(16px) saturate(160%);
  backdrop-filter:blur(16px) saturate(160%);
  transition:box-shadow .16s, border-color .16s, transform .16s;
}
.proj-card:hover{ box-shadow:0 12px 38px rgba(13,38,76,.16), var(--glass-in); transform:translateY(-1px); border-color:rgba(255,255,255,.8); }
.proj-card::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:3px; background:var(--up);
}
.proj-card.has-down{ border-color:rgba(217,45,32,.32); background:rgba(253,236,234,.5); }
.proj-card.has-down::before{ background:var(--down); }
.proj-head{ display:flex; align-items:flex-start; gap:10px; }
.proj-head > div:first-child{ flex:1; min-width:0; }
.proj-name{ font-size:14.5px; font-weight:650; color:var(--text); line-height:1.35; }
.proj-site{ font-size:12px; color:var(--muted); margin-top:2px; }
.proj-stats{
  display:grid; grid-template-columns:repeat(4,1fr); gap:8px;
  margin-top:12px; padding-top:12px; border-top:1px solid rgba(255,255,255,.5);
}
.proj-stats .item{ text-align:center; }
.proj-stats .item b{
  display:block; font-size:16px; font-weight:700; color:var(--text);
  font-variant-numeric:tabular-nums;
}
.proj-stats .item span{ display:block; font-size:11px; color:var(--muted-2); margin-top:1px; }

/* --- 营业额行（数据来自 NAS 采集容器写 revenue_daily 表）---
   布局用**定宽**三列 grid，不用 flex+margin-left:auto，也不用 auto 列宽。

   为什么必须定宽（2026-10-05 实测踩坑）：
   - flex + margin-left:auto：meta 被推到行最右端，起点 X 随金额字数变化。
     实测当日 8 个账套金额从 ¥60.02 到 ¥44,295.72，长度差 3 字符，
     扫过去 meta 七扭八歪。
   - grid-template-columns: auto auto 1fr：**也不行**。每个 .proj-rev
     是独立的 grid 容器，auto 列按本卡内容算宽度，¥60 的卡第二列窄、
     ¥44,295 的卡第二列宽，1fr 起点照样漂。

   为什么必须用 px 而不是 em（同日第二次踩坑）：
   grid-template-columns 里的 em 相对**本容器继承字号**（~14px）折算，
   5.9em 只有 ~83px，装不下「¥44,295.72」（16px tabular-nums 约 88px），
   金额向左溢出压住标签、向右把 meta 挤出卡片 —— 表现为"字体偏离严重"。
   px 定宽不随字号漂：56px 装标签「今日营业额」(5×11px)，
   74px 装金额列 —— fmtYuan 是整数格式（¥44,296 ≈ 62px，留缓冲到
   ¥123,456 级别 70px），之前 92px 是按小数「¥44,295.72」估的，白占 18px，
   窄卡上 meta 只剩 ~110px 会被截。1fr 给备注。所有卡片的
   标签/金额/备注起点同线，金额右对齐，个位数字成一条竖线（tabular-nums 已开）。 */
.proj-rev{
  display:grid;
  grid-template-columns:56px 74px 1fr;
  align-items:baseline; column-gap:6px;
  margin-top:9px; padding:8px 10px; border-radius:8px;
  background:rgba(238,243,255,.55); border:1px solid rgba(11,95,255,.18);
  -webkit-backdrop-filter:blur(8px) saturate(150%); backdrop-filter:blur(8px) saturate(150%);
}
.proj-rev .rv-tag{
  font-size:11px; color:var(--muted); font-weight:500;
  white-space:nowrap;
}
.proj-rev .rv-today{
  font-size:16px; font-weight:700; color:var(--brand-ink);
  font-variant-numeric:tabular-nums; letter-spacing:-.3px;
  white-space:nowrap; text-align:right;
}
.proj-rev .rv-meta{
  font-size:11px; color:var(--color-text-secondary); font-variant-numeric:tabular-nums;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  justify-self:start;
}
/* 未绑账套 / 待采集：整行退成中性灰玻璃，不抢注意力 */
.proj-rev.idle{ background:rgba(255,255,255,.35); border-color:rgba(255,255,255,.55); }
.proj-rev.idle .rv-tag{ color:var(--muted-2); }
.proj-rev.idle .rv-today{ font-size:12.5px; font-weight:500; color:var(--muted-2); letter-spacing:0; }
/* 窄屏放不下三列时，让备注独占第二行而不是被压成省略号。
   两列同样 px 定宽（不能退回 auto/em，否则又漂了）。 */
@media(max-width:420px){
  .proj-rev{ grid-template-columns:56px 74px; row-gap:2px; }
  .proj-rev .rv-meta{ grid-column:1 / -1; }
}

/* ============ 11. 图表 ============ */
.chart-box{ width:100%; overflow:hidden; }
svg.chart{ display:block; width:100%; height:auto; }
.bars{ display:flex; flex-direction:column; gap:9px; }
.bars .row{ display:grid; grid-template-columns:minmax(96px,170px) 1fr auto; gap:10px; align-items:center; }
.bars .row .nm{ font-size:12.5px; color:var(--ink-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bars .row .vl{ font-size:12.5px; font-weight:600; color:var(--text); font-variant-numeric:tabular-nums; text-align:right; }

/* ============ 12. 分页（毛玻璃） ============ */
.pager{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:14px; }
.pager .pg{ display:flex; gap:4px; flex-wrap:wrap; }
.pager .pg button{
  min-width:30px; height:30px; padding:0 9px;
  border:1px solid rgba(255,255,255,.65); border-radius:6px; background:rgba(255,255,255,.5);
  color:var(--ink-2); font-size:12.5px; cursor:pointer;
  font-variant-numeric:tabular-nums;
  -webkit-backdrop-filter:blur(6px) saturate(150%); backdrop-filter:blur(6px) saturate(150%);
  transition:border-color .14s, color .14s, background .14s;
}
.pager .pg button:hover:not(:disabled){ border-color:var(--brand); color:var(--brand); background:rgba(255,255,255,.75); }
.pager .pg button.on{ background:var(--brand); border-color:var(--brand); color:#fff; font-weight:600; -webkit-backdrop-filter:none; backdrop-filter:none; }
.pager .pg button:disabled{ opacity:.4; cursor:not-allowed; }

/* ============ 13. 代码块 / 提示条 ============ */
.code{
  background:#0E1520; color:#D8E2F0; border-radius:var(--r-s);
  padding:12px 14px; font-size:12.5px; line-height:1.7;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,"Courier New",monospace;
  overflow-x:auto; white-space:pre-wrap; word-break:break-all;
}
.code .cmt{ color:#6B7C93; }

.hint-box{
  padding:11px 14px; border-radius:var(--r-s); font-size:12.5px; line-height:1.6;
  background:rgba(238,243,255,.62); border:1px solid rgba(11,95,255,.22); color:var(--brand-ink);
  -webkit-backdrop-filter:blur(10px) saturate(150%); backdrop-filter:blur(10px) saturate(150%);
}
.hint-box b{ font-weight:700; }
.hint-box.warn{ background:rgba(254,243,230,.62); border-color:rgba(181,71,8,.26); color:var(--warn); }

/* ============ 14. 模态框（毛玻璃） ============ */
.mask{
  position:fixed; inset:0; z-index:100;
  background:rgba(18,22,28,.42); -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center; padding:24px;
  animation:fadeIn .16s ease;
}
@keyframes fadeIn{ from{opacity:0} to{opacity:1} }
.modal{
  width:100%; max-width:600px; max-height:88vh;
  display:flex; flex-direction:column;
  background:rgba(255,255,255,.72); border:1px solid var(--glass-brd); border-radius:var(--r-m);
  box-shadow:0 18px 50px rgba(13,38,76,.22), var(--glass-in);
  -webkit-backdrop-filter:blur(24px) saturate(170%); backdrop-filter:blur(24px) saturate(170%);
  animation:modalIn .18s cubic-bezier(.2,.8,.3,1);
}
@keyframes modalIn{ from{opacity:0; transform:translateY(-10px)} to{opacity:1; transform:none} }
.modal-head{
  display:flex; align-items:center; gap:10px;
  padding:15px 18px; border-bottom:1px solid rgba(255,255,255,.5);
}
.modal-head h2{ margin:0; font-size:15.5px; font-weight:650; flex:1; }
.modal-body{ padding:18px; overflow-y:auto; flex:1; }
.modal-foot{
  display:flex; gap:9px; justify-content:flex-end;
  padding:13px 18px; border-top:1px solid rgba(255,255,255,.5); background:rgba(255,255,255,.4);
  border-radius:0 0 var(--r-m) var(--r-m);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
}
.close{
  width:28px; height:28px; border:0; border-radius:6px; background:transparent;
  color:var(--muted-2); font-size:20px; line-height:1; cursor:pointer;
  transition:background .14s, color .14s;
}
.close:hover{ background:rgba(255,255,255,.5); color:var(--text); }

/* ============ 15. Toast（毛玻璃） ============ */
#toasts{ position:fixed; top:16px; right:16px; z-index:200; display:flex; flex-direction:column; gap:8px; }
.toast{
  padding:10px 15px; border-radius:var(--r-s);
  background:rgba(255,255,255,.78); border:1px solid var(--glass-brd); border-left:3px solid var(--brand);
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(14px) saturate(160%); backdrop-filter:blur(14px) saturate(160%);
  color:var(--text); font-size:13px; max-width:360px;
  animation:slidein .2s ease;
}
.toast.ok{ border-left-color:var(--up); }
.toast.err{ border-left-color:var(--down); }
@keyframes slidein{ from{opacity:0; transform:translateX(14px)} to{opacity:1; transform:none} }

/* ============ 16. 响应式断点 ============ */
/* 16-1 中屏：KPI 降列 */
@media(max-width:1200px){
  .kpis{ grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
}
/* 16-2 侧栏收成图标条 */
@media(max-width:1100px){
  :root{ --side-w:64px; }
  .side-txt,.side-nav .grp,.side-nav button .lb,.side-foot button .lb,.side-foot .clock{ display:none; }
  .side-brand{ justify-content:center; padding:16px 0; }
  .side-nav button,.side-foot button{ justify-content:center; padding:11px 0; }
  .side-nav button .app-ico,.side-foot button .app-ico{ width:auto; }
}
/* 16-3 窄屏：侧栏转顶栏 */
@media(max-width:768px){
  .shell{ flex-direction:column; }
  .side{ width:100%; flex:0 0 auto; height:auto; position:relative; flex-direction:row; align-items:center; }
  .side-brand{ border-bottom:0; border-right:1px solid rgba(255,255,255,.07); padding:12px 14px; }
  .side-brand .bname{
    font-size:12px; line-height:1.38;
    display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
    white-space:normal; word-break:break-all;
  }
  .side-nav{ display:flex; gap:2px; padding:8px; overflow-x:auto; }
  .side-nav button{ padding:9px 12px; }
  .side-foot{ border-top:0; }
  .wrap{ padding:16px 14px 36px; }
  .kpi .value{ font-size:23px; }
  .proj-stats{ grid-template-columns:repeat(2,1fr); }
  #toasts{ left:12px; right:12px; }
  .toast{ max-width:none; }
}
/* 16-4 无障碍：尊重减弱动效 */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

/* ============ 17. 登录 / 用户区 / 用户管理 ============ */
.login-screen{
  position:fixed; inset:0; z-index:120;
  display:grid; place-items:center; padding:20px;
  background:
    radial-gradient(820px 620px at 8% 2%,   rgba(255,122,180,.22), transparent 58%),
    radial-gradient(760px 580px at 95% 4%,  rgba(64,156,255,.24),   transparent 58%),
    radial-gradient(900px 700px at 90% 98%, rgba(154,108,255,.20),  transparent 60%),
    radial-gradient(820px 620px at 4% 96%,  rgba(52,199,89,.16),    transparent 60%),
    radial-gradient(680px 500px at 50% 52%, rgba(255,214,102,.10),  transparent 60%),
    linear-gradient(135deg,#eef3ff 0%,#f6f0ff 48%,#eafaf3 100%);
}
.login-screen[hidden]{ display:none; }
.login-card{
  width:340px; max-width:100%;
  padding:26px 26px 22px;
  background:var(--glass-strong);
  border:1px solid var(--glass-brd);
  border-radius:var(--r-m);
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(18px) saturate(160%); backdrop-filter:blur(18px) saturate(160%);
}
.login-brand{ display:flex; align-items:center; gap:11px; margin-bottom:18px; }
.login-logo{ width:38px; height:38px; flex:0 0 38px; border-radius:10px; background:var(--brand); color:#fff; display:grid; place-items:center; }
.login-logo svg{ width:21px; height:21px; display:block; }
.login-brand .lb-name{ font-size:16px; font-weight:680; color:var(--text); line-height:1.3; }
.login-brand .lb-tag{ font-size:11px; color:var(--muted); letter-spacing:.4px; }
.login-card h2{ margin:0 0 16px; font-size:17px; font-weight:660; color:var(--text); }
.login-submit{ width:100%; justify-content:center; margin-top:6px; }
.login-err{ color:var(--down); font-size:12.5px; margin:2px 0 10px; }
.login-foot{ text-align:center; font-size:11.5px; margin:12px 0 0; }

/* 侧栏用户区 */
.side-user{ margin:0 0 8px; }
.user-chip{ display:flex; align-items:center; gap:9px; padding:8px 9px; border-radius:var(--r-s); background:rgba(255,255,255,.5); border:1px solid rgba(255,255,255,.6); }
.u-avatar{ width:30px; height:30px; flex:0 0 30px; border-radius:50%; background:var(--brand); color:#fff; display:grid; place-items:center; font-weight:650; font-size:13px; }
.u-meta{ flex:1; min-width:0; line-height:1.25; }
.u-name{ font-size:13px; color:var(--text); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.u-role{ font-size:10.5px; color:var(--side-ink-2); }
.u-btn{ width:28px; height:28px; flex:0 0 28px; border:0; border-radius:7px; background:rgba(0,0,0,.05); color:var(--side-ink-2); font-size:14px; cursor:pointer; transition:background .14s, color .14s; display:grid; place-items:center; }
.u-btn:hover{ background:rgba(0,0,0,.1); color:var(--text); }
.u-btn svg{ width:16px; height:16px; display:block; }

/* 模块勾选网格（用户管理弹窗） */
.mod-grid{ display:grid; grid-template-columns:1fr 1fr; gap:8px 14px; }
.mod-chk{ display:flex; align-items:center; gap:8px; font-size:13px; color:var(--ink-2); cursor:pointer; }
.mod-chk.is-disabled{ opacity:.5; cursor:not-allowed; }
.mod-chk input{ width:auto; }

/* 16-2 侧栏收成图标条时，用户区放不下，直接隐藏（桌面端不受影响） */
@media(max-width:1100px){
  .side-user{ display:none; }
}

/* 16-3 访问记录筛选条 */
.access-filter .f-in{
  min-width:118px; height:34px; padding:0 10px;
  border:1px solid var(--line); border-radius:9px;
  background:var(--glass-bg); color:inherit; font:inherit;
}
.access-filter .f-in:focus{ outline:none; border-color:var(--accent); }
.access-filter select.f-in{ cursor:pointer; }

/* 访问记录分页按钮（.pager 内直接子按钮） */
.pager button{
  height:32px; padding:0 12px; border:1px solid var(--line); border-radius:8px;
  background:var(--glass-bg); color:inherit; font:inherit; cursor:pointer;
  transition:border-color .14s, color .14s;
}
.pager button:hover:not(:disabled){ border-color:var(--brand); color:var(--brand); }
.pager button:disabled{ opacity:.4; cursor:not-allowed; }

/* ==================================================================
 * AI 菜谱分析（2026-10-08）
 *   标签切换 + 内嵌页容器。内嵌的是另一个独立服务，压满剩余高度。
 * ================================================================== */
.ai-tabs{
  display:inline-flex; gap:2px; padding:3px;
  background:var(--glass-bg); border:1px solid var(--glass-brd); border-radius:11px;
  -webkit-backdrop-filter:blur(14px) saturate(160%); backdrop-filter:blur(14px) saturate(160%);
}
.ai-tab{
  height:32px; padding:0 16px; border:0; border-radius:9px;
  background:transparent; color:var(--muted); font:inherit; font-size:13.5px; cursor:pointer;
  transition:background .14s, color .14s;
}
.ai-tab:hover{ color:var(--text); }
.ai-tab.active{ background:#fff; color:var(--brand); font-weight:600; box-shadow:0 1px 4px rgba(13,38,76,.10); }

.ai-embed{
  display:flex; flex-direction:column;
  margin-top:12px; border-radius:var(--r-m); overflow:hidden;
  background:var(--glass-bg); border:1px solid var(--glass-brd);
  box-shadow:var(--glass-sh), var(--glass-in);
  -webkit-backdrop-filter:blur(16px) saturate(160%); backdrop-filter:blur(16px) saturate(160%);
}
.ai-embed .toolbar{ margin:0; padding:10px 12px; border-bottom:1px solid rgba(255,255,255,.55); background:transparent; }
.ai-frame{
  width:100%; height:calc(100vh - 232px); min-height:460px;
  border:0; display:block; background:#fff;
}
.ai-dot{ display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px; vertical-align:middle; }
.ai-dot.ok{ background:#34C759; box-shadow:0 0 0 3px rgba(52,199,89,.18); }
.ai-dot.bad{ background:#FF3B30; box-shadow:0 0 0 3px rgba(255,59,48,.16); }
.ai-dot.warn{ background:#FF9500; box-shadow:0 0 0 3px rgba(255,149,0,.18); }
.ai-status{ font-size:13px; color:var(--muted); }
.ai-offline{ margin:14px; }
.ai-offline h3{ margin:0 0 8px; font-size:15px; }
.ai-offline ol{ margin:8px 0 8px 20px; padding:0; }
.ai-offline li{ margin:5px 0; }
