/* ===== 智慧兔业养殖管理系统 · 界面主题 v2 ===== */

/* ── iPad 菜单间距（想调不用找具体规则，改这三个数即可）─────────────
   --pad-menu-gap    : 图标与文字的间距（默认 10px，想更紧凑改 6px）
   --pad-menu-indent : 子菜单相对父菜单的缩进（默认 24px，想贴近改 12px）
   --pad-sidebar-w   : iPad 侧栏宽度（默认 168px）
   改法：直接改下面的数值，或加到 .env 同级的自定义样式里覆盖。 */
:root{
  --pad-menu-gap:8px;
  --pad-menu-indent:18px;
  --pad-sidebar-w:168px;
  --autofill-bg:#0B1119;
  --code-bg:rgba(0,0,0,.32);
  --bg:#070A0F;
  --bg-soft:#0B1119;
  --panel:rgba(var(--ovl),.038);
  --panel-2:rgba(var(--ovl),.055);
  --card:rgba(var(--ovl),.045);
  --accent:rgb(var(--ar),var(--ag),var(--ab));
  /* 主题色 RGB 通道：换主题时只需改这 9 个值，所有半透明衍生色自动跟随 */
  --ar:0;   --ag:229; --ab:176;    /* accent   主高亮 */
  --a2r:90; --a2g:160;--a2b:255;   /* accent-2 辅色 */
  --a3r:165;--a3g:94; --a3b:247;   /* accent-3 点缀 */
  --accent-2:rgb(var(--a2r),var(--a2g),var(--a2b));
  --accent-3:rgb(var(--a3r),var(--a3g),var(--a3b));
  --accent-dim:rgba(var(--ar),var(--ag),var(--ab),.13);
  --text:#EAF2FA;
  --text2:#B9C6D6;
  --muted:#74839A;
  /* ★ 日志/终端正文色：必须跟随主题。原先硬编码 #9FB3C8，
     浅色模式底色变成浅灰后，浅灰字压浅底几乎看不见。 */
  --log-fg:#C8D6E5;
  /* ★ 次要弱化文字（分组标题 / 提示 / 空值 / 版本号 / 表尾）：
     原先硬编码 #4E5A6C，深色模式下偏暗到接近底色。 */
  --fg-dim:#8A97A8;
  --border:rgba(var(--ovl),.07);
  --border2:rgba(var(--ovl),.11);
  --green:rgb(var(--ar),var(--ag),var(--ab));
  --red:#FF6B8B;
  --orange:#F0A93F;
  --gray:#7B8798;
  --blue:rgb(var(--a2r),var(--a2g),var(--a2b));
  --purple:rgb(var(--a3r),var(--a3g),var(--a3b));
  /* 表面色：深浅模式各一套取值，浅色模式在文件末尾覆盖 */
  --sf-1:rgba(9,14,20,.62);      /* 顶栏 / 最外层 */
  --sf-2:rgba(11,17,25,.72);     /* 输入框 / 卡片 */
  --sf-3:rgba(13,19,27,.72);     /* 表格行 */
  --sf-4:rgba(17,24,33,.72);     /* 表格隔行 */
  --sf-5:rgba(18,26,36,.96);     /* 表头 / 冻结列（近实底） */
  --sf-solid:#121A24;            /* 完全不透明表面 */
  --sf-solid-2:#0F151E;
  --sf-pop:rgba(23,33,45,.98);   /* 弹窗 */
  --side-1:rgba(13,20,29,.92);   /* 侧栏渐变起 */
  --side-2:rgba(8,12,18,.95);    /* 侧栏渐变止 */
  --mask:rgba(3,6,10,.6);        /* 弹窗遮罩 */
  --sh-strong:rgba(0,0,0,.55);   /* 强投影 */
  --sh-soft:rgba(0,0,0,.42);     /* 常规投影 */
  --on-accent:#04231B;
  --ovl:255,255,255;             /* 叠加色通道：深模式=白，浅模式=深色 */
  --glow:.10;                    /* 背景光斑强度 */
  --radius:16px;
  --shadow:0 14px 36px rgba(0,0,0,.42);
  --ring:0 0 0 3px rgba(var(--ar),var(--ag),var(--ab),.18);
}


/* =========================================================
   主题配色：只改 9 个 RGB 通道，全站半透明衍生色自动跟随
   如需新增主题，复制一段并改 key 与三个 rgb 即可
   ========================================================= */
[data-theme="aqua"]{      /* 极光青（默认） */
  --ar:0;   --ag:229; --ab:176;
  --a2r:90; --a2g:160;--a2b:255;
  --a3r:165;--a3g:94; --a3b:247;
  --on-accent:#04231B;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:27;--kg:116;--kb:96;      --k2r:43;--k2g:102;--k2b:183;      --k3r:112;--k3g:45;--k3b:190;
  --dr:27;--dg:221;--db:176;      --d2r:90;--d2g:160;--d2b:255;      --d3r:175;--d3g:136;--d3b:221;
}
[data-theme="sky"]{       /* 天霁蓝 */
  --ar:56;  --ag:189; --ab:248;
  --a2r:129;--a2g:140;--a2b:248;
  --a3r:34; --a3g:211;--a3b:238;
  --on-accent:#06263A;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:34;--kg:109;--kb:143;      --k2r:45;--k2g:58;--k2b:190;      --k3r:30;--k3g:114;--k3b:126;
  --dr:56;--dg:189;--db:248;      --d2r:152;--d2g:159;--d2b:225;      --d3r:55;--d3g:207;--d3b:230;
}
[data-theme="violet"]{    /* 紫罗兰 */
  --ar:167; --ag:139; --ab:250;
  --a2r:244;--a2g:114;--a2b:182;
  --a3r:96; --a3g:165;--a3b:250;
  --on-accent:#1A0B33;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:81;--kg:45;--kb:190;      --k2r:184;--k2g:43;--k2b:117;      --k3r:42;--k3g:104;--k3b:179;
  --dr:178;--dg:161;--db:228;      --d2r:244;--d2g:114;--d2b:182;      --d3r:96;--d3g:165;--d3b:250;
}
[data-theme="amber"]{     /* 琥珀金 */
  --ar:251; --ag:191; --ab:36;
  --a2r:251;--a2g:146;--a2b:60;
  --a3r:250;--a3g:204;--a3b:21;
  --on-accent:#3A2600;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:128;--kg:101;--kb:30;      --k2r:151;--k2g:88;--k2b:35;      --k3r:123;--k3g:104;--k3b:29;
  --dr:233;--dg:190;--db:78;      --d2r:251;--d2g:146;--d2b:60;      --d3r:228;--d3g:188;--d3b:33;
}
[data-theme="rose"]{      /* 玫瑰粉 */
  --ar:251; --ag:113; --ab:133;
  --a2r:244;--a2g:114;--a2b:182;
  --a3r:251;--a3g:146;--a3b:60;
  --on-accent:#3A0713;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:188;--kg:44;--kb:65;      --k2r:184;--k2g:43;--k2b:117;      --k3r:151;--k3g:88;--k3b:35;
  --dr:222;--dg:142;--db:153;      --d2r:244;--d2g:114;--d2b:182;      --d3r:251;--d3g:146;--d3b:60;
}
[data-theme="emerald"]{   /* 翡翠绿 */
  --ar:52;  --ag:211; --ab:153;
  --a2r:45; --a2g:212;--a2b:191;
  --a3r:132;--a3g:204;--a3b:22;
  --on-accent:#04271C;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:27;--kg:116;--kb:84;      --k2r:27;--k2g:116;--k2b:105;      --k3r:79;--k3g:114;--k3b:27;
  --dr:52;--dg:211;--db:153;      --d2r:45;--d2g:212;--d2b:191;      --d3r:132;--d3g:204;--d3b:22;
}
[data-theme="mint"]{      /* 薄荷冰（更浅更亮） */
  --ar:110; --ag:231; --ab:214;
  --a2r:147;--a2g:197;--a2b:253;
  --a3r:196;--a3g:181;--a3b:253;
  --on-accent:#042A26;
  /* 可读墨色（自动算过 WCAG 对比度：浅色≥5.1，深色≈6~8.5 不刺眼） */
  --kr:28;--kg:118;--kb:105;      --k2r:42;--k2g:106;--k2b:178;      --k3r:75;--k3g:45;--k3b:190;
  --dr:48;--dg:221;--db:197;      --d2r:152;--d2g:194;--d2b:242;      --d3r:195;--d3g:181;--d3b:246;
}

/* ===== 可读墨色：同一套配色在深/浅底上用不同墨色，保证清晰不刺眼 =====
   浅底用「加深墨」--k*（对比度≥5.1），深底用「柔化墨」--d*（对比度6~8.5，不刺眼）。
   想调：改上面各主题块里的 --kr/--kg/--kb（浅色）或 --dr/--dg/--db（深色）即可，全站自动跟随。 */
:root{
  --accent-ink:rgb(var(--dr),var(--dg),var(--db));
  --ink2:rgb(var(--d2r),var(--d2g),var(--d2b));
  --ink3:rgb(var(--d3r),var(--d3g),var(--d3b));
}
[data-mode="light"]{
  --accent-ink:rgb(var(--kr),var(--kg),var(--kb));
  --ink2:rgb(var(--k2r),var(--k2g),var(--k2b));
  --ink3:rgb(var(--k3r),var(--k3g),var(--k3b));
}



/* ===== 深浅模式切换控件 ===== */
.mode-row{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:6px}
.mode-title{font-size:13px;font-weight:600;color:var(--text)}
.mode-seg{
  display:inline-flex;padding:3px;gap:3px;border-radius:11px;
  background:rgba(var(--ovl),.05);border:1px solid var(--border2);
}
.mode-btn{
  padding:7px 18px;border-radius:9px;cursor:pointer;font-size:12.5px;font-weight:600;
  background:transparent;border:none;color:var(--muted);transition:.18s;
  font-family:inherit;
}
.mode-btn:hover{color:var(--text)}
.mode-btn.on{
  background:rgb(var(--ar),var(--ag),var(--ab));color:#fff;
  box-shadow:0 3px 10px rgba(var(--ar),var(--ag),var(--ab),.35);
}
[data-mode="light"] .mode-btn.on{color:#fff}
.mode-hint{font-size:11.5px;color:var(--muted);margin-bottom:14px}

/* ===== 主题选择器 ===== */
.theme-btn{
  width:34px;height:34px;border-radius:10px;display:flex;align-items:center;justify-content:center;
  cursor:pointer;color:var(--text2);
  background:rgba(var(--ovl),.05);border:1px solid var(--border2);
  transition:.18s;position:relative;
}
.theme-btn:hover{color:var(--accent);border-color:rgba(var(--ar),var(--ag),var(--ab),.45);
  background:rgba(var(--ar),var(--ag),var(--ab),.10)}
/* 登录页的「切换主题配色」：贴在登录卡右上角内侧。
   原来是 position:fixed 钉在浏览器视口右下角，登录框一缩小两边就分家（按钮孤零零飘在角落）。
   改成 absolute 跟随 .login-card 后，任何屏幕尺寸都紧贴登录框。
   想挪位置：改 right / top；想放回视口右下角：把 absolute 换回 fixed、right/bottom 设为 20px。 */
.theme-btn.login-theme{
  position:absolute;right:14px;top:14px;z-index:6;width:38px;height:38px;border-radius:12px;
  background:var(--sf-5);backdrop-filter:blur(10px);
}
.theme-btn svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.theme-card{
  cursor:pointer;border-radius:14px;padding:13px 12px 12px;text-align:center;
  background:rgba(var(--ovl),.04);border:1px solid var(--border2);
  transition:.18s;position:relative;
}
.theme-card:hover{transform:translateY(-2px);border-color:rgba(var(--ovl),.24);
  background:rgba(var(--ovl),.075)}
.theme-card.on{border-color:rgb(var(--ar),var(--ag),var(--ab));
  background:rgba(var(--ar),var(--ag),var(--ab),.12);
  box-shadow:0 0 0 3px rgba(var(--ar),var(--ag),var(--ab),.16)}
.theme-card.on::after{
  content:'✓';position:absolute;top:7px;right:9px;font-size:11px;font-weight:700;
  color:rgb(var(--ar),var(--ag),var(--ab));
}
.theme-swatch{
  height:38px;border-radius:10px;margin-bottom:9px;
  box-shadow:inset 0 1px 0 rgba(var(--ovl),.28);
}
.theme-name{font-size:12.5px;font-weight:600;color:var(--text)}
.theme-note{font-size:10.5px;color:var(--muted);margin-top:2px}
@media (max-width:620px){ .theme-grid{grid-template-columns:repeat(2,1fr)} }


/* =========================================================
   浅色模式：底色反相 + 叠加色反转（深色提亮 → 浅色压暗）
   与 7 套配色自由组合，共 14 种搭配
   ========================================================= */
[data-mode="light"]{
  --bg:#F2F5F9;
  --bg-soft:#FFFFFF;
  --text:#14202B;
  --text2:#3A4756;
  --muted:#6E7C8D;
  --log-fg:#33414F;      /* 浅底压深，对比度约 8:1 */
  --fg-dim:#5E6B7C;      /* 浅底次要文字 */
  --border:rgba(16,32,48,.11);
  --border2:rgba(16,32,48,.16);
  /* 叠加色反转：原本白色提亮改为深色压暗 */
  --ovl:18,32,48;
  --glow:.16;
  /* 表面色：改为白系 */
  --sf-1:rgba(255,255,255,.86);
  --sf-2:rgba(255,255,255,.92);
  --sf-3:#FFFFFF;
  --sf-4:rgba(246,249,252,.92);
  --sf-5:rgba(255,255,255,.98);
  --sf-solid:#FFFFFF;
  --sf-solid-2:#FBFCFE;
  --sf-pop:rgba(255,255,255,.99);
  /* 语义色在浅底上要加深，保证对比度 */
  --red:#C42044;   /* 原 #D92D51 对比度仅 4.25，加深到 5.17 */
  --orange:#8E5E17; /* 原 #B47400 对比度仅 3.59，加深到 5.17 */
  --gray:#5E6B7C;
  --ring:0 0 0 3px rgba(var(--ar),var(--ag),var(--ab),.30);
  --shadow:0 10px 28px rgba(16,32,48,.13);
  /* 侧栏 / 遮罩 / 投影在浅色下反转 */
  --side-1:rgba(255,255,255,.92);
  --side-2:rgba(246,249,252,.96);
  --mask:rgba(16,32,48,.34);
  --sh-strong:rgba(16,32,48,.18);
  --sh-soft:rgba(16,32,48,.10);
}
/* 浅色模式：背景光斑减弱，网格线改为深色 */
[data-mode="light"] body{
  background:
    radial-gradient(900px 520px at 10% -10%, rgba(var(--ar),var(--ag),var(--ab),.13), transparent 62%),
    radial-gradient(760px 460px at 95% 6%,   rgba(var(--a2r),var(--a2g),var(--a2b),.11), transparent 64%),
    radial-gradient(700px 520px at 55% 115%, rgba(var(--a3r),var(--a3g),var(--a3b),.08), transparent 62%),
    var(--bg);
}
[data-mode="light"] body::before{
  opacity:.32;
  background-image:
    linear-gradient(rgba(16,32,48,.055) 1px,transparent 1px),
    linear-gradient(90deg,rgba(16,32,48,.055) 1px,transparent 1px);
}
/* 浅色模式：主按钮白字（高亮色做底）保持不变，但边框型按钮需加深文字 */
[data-mode="light"] .btn-ghost{color:var(--text2)}
[data-mode="light"] .btn-ghost:hover{color:rgb(var(--ar),var(--ag),var(--ab))}
[data-mode="light"] .btn-primary{
  /* 浅色模式下加深高亮底色，保证按钮文字对比度 */
  background:linear-gradient(135deg,rgb(var(--ar),var(--ag),var(--ab)) 0%,rgba(var(--ar),var(--ag),var(--ab),.92) 100%);
  color:var(--on-accent);
}
/* 浅色模式：状态标签底色需更实，否则浅底上看不清 */
[data-mode="light"] .tag{font-weight:600}
/* [data-mode="light"] .tag.green{color:#067A5C} → 已由 --accent-ink/--ink2/--ink3 统一，按主题自动取色 */
/* [data-mode="light"] .tag.blue{color:#1F5FD0} → 已由 --accent-ink/--ink2/--ink3 统一，按主题自动取色 */
/* [data-mode="light"] .tag.purple{color:#7A34C9} → 已由 --accent-ink/--ink2/--ink3 统一，按主题自动取色 */
/* 自动填充底色：深色模式用深色，浅色模式用浅色（硬编码会导致浅色下登录框发黑） */
[data-mode="light"]{ --autofill-bg:#FFFFFF; --code-bg:rgba(16,32,48,.07); }
/* 浅色模式：侧栏品牌名原为「白→浅绿」渐变文字，白底上完全看不见，改为深绿渐变 */
[data-mode="light"] .brand-name{
  background:linear-gradient(120deg,#0B3B2E 20%,#0E7C5A 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
[data-mode="light"] .brand-logo{filter:drop-shadow(0 3px 10px rgba(16,32,48,.18))}
[data-mode="light"] .sidebar-foot .ver{color:var(--fg-dim)}
[data-mode="light"] .brand-name{font-weight:800}
/* 浅色模式：自动补齐状态条内的 code 标签原本是黑底，浅底上要反过来 */
[data-mode="light"] .af-box code{
  background:rgba(16,32,48,.08);
}
/* 浅色模式：登录页大标题也是白色渐变，白底上会看不见 */
[data-mode="light"] .brand-slogan{
  background:linear-gradient(120deg,#0B3B2E 10%,#0E7C5A 55%,#1F5FD0 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
/* 浅色模式：行号 / 空状态 / 次要文字加深，避免浅底上看不清 */
[data-mode="light"] .dbt-grid .tbl th.rowno,
[data-mode="light"] .dbt-grid .tbl td.rowno{color:var(--fg-dim)}
[data-mode="light"] .empty{color:var(--fg-dim)}
[data-mode="light"] .empty svg{stroke:#9AA6B6}
[data-mode="light"] .hint-inline{color:var(--fg-dim)}
[data-mode="light"] .null,
[data-mode="light"] .dbt-grid .tbl tbody td.null{color:var(--fg-dim)}
[data-mode="light"] .pk{background:rgba(var(--ar),var(--ag),var(--ab),.18);color:#0B6B52}
/* 滚动条 */
[data-mode="light"] ::-webkit-scrollbar-thumb{background:rgba(16,32,48,.20)}
[data-mode="light"] ::-webkit-scrollbar-thumb:hover{background:rgba(var(--ar),var(--ag),var(--ab),.55);background-clip:content-box}
/* 选中文字 */
[data-mode="light"] ::selection{background:rgba(var(--ar),var(--ag),var(--ab),.30)}
/* 加载遮罩 */
[data-mode="light"] .loading{color:var(--text2)}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  background:
    radial-gradient(900px 520px at 10% -10%, rgba(var(--ar),var(--ag),var(--ab),var(--glow)), transparent 62%),
    radial-gradient(760px 460px at 95% 6%,   rgba(var(--a2r),var(--a2g),var(--a2b),var(--glow)), transparent 64%),
    radial-gradient(700px 520px at 55% 115%, rgba(var(--a3r),var(--a3g),var(--a3b),.07), transparent 62%),
    var(--bg);
  background-attachment: fixed;
  color:var(--text);
  font:14px/1.5 "PingFang SC","Microsoft YaHei","Segoe UI",system-ui,sans-serif;
  -webkit-font-smoothing:antialiased;
  overflow:hidden;
}
/* 背景细网格 + 呼吸光斑 */
body::before{
  content:'';position:fixed;inset:0;pointer-events:none;z-index:0;opacity:.5;
  background-image:
    linear-gradient(rgba(var(--ovl),.028) 1px,transparent 1px),
    linear-gradient(90deg,rgba(var(--ovl),.028) 1px,transparent 1px);
  background-size:44px 44px;
  mask-image:radial-gradient(circle at 50% 30%,#000 0%,transparent 78%);
}
::selection{background:rgba(var(--ar),var(--ag),var(--ab),.28)}
svg{display:block}
.num{font-variant-numeric:tabular-nums}

/* 滚动条 */
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(var(--ovl),.11);border-radius:99px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:rgba(var(--ar),var(--ag),var(--ab),.4);background-clip:content-box}

/* 通用动画 */
@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes pop{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
@keyframes slideDown{from{opacity:0;transform:translateY(-14px)}to{opacity:1;transform:none}}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes floatY{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
@keyframes pulseGlow{0%,100%{opacity:.45}50%{opacity:.9}}

/* ================= 登录页 ================= */
.login-wrap{
  position:relative;height:100vh;display:flex;align-items:center;justify-content:center;
  /* 上下留白随屏幕变矮而收窄，避免矮屏（iPad 横屏约 584 高）把登录框挤出屏幕 */
  padding:min(28px,4vh);overflow:auto;
}
.login-wrap::after{
  content:'';position:absolute;width:520px;height:520px;right:-140px;bottom:-180px;
  background:radial-gradient(circle,rgba(var(--ar),var(--ag),var(--ab),.16),transparent 70%);
  filter:blur(20px);animation:floatY 8s ease-in-out infinite;pointer-events:none;
}
.login-box{
  position:relative;z-index:2;display:flex;width:min(1020px,100%);
  /* 原为写死 600px：iPad 横屏可用高仅约 528px，登录框会被裁掉上下两端。
     改成跟随视口，矮屏自动收窄、永不溢出；桌面 1080/768 高仍是 600px，观感不变。
     想改登录框最小高度：只动下面这个 600px。 */
  min-height:min(600px,calc(100vh - 2 * min(28px,4vh)));
  border-radius:26px;overflow:hidden;
  background:var(--panel);
  border:1px solid var(--border2);
  backdrop-filter:blur(18px);
  box-shadow:0 30px 80px var(--sh-strong), inset 0 1px 0 rgba(var(--ovl),.06);
  animation:pop .45s cubic-bezier(.2,.9,.3,1.05) both;
}
/* 品牌区 */
.login-brand{
  flex:0 0 46%;padding:46px 44px;display:flex;flex-direction:column;
  background:
    radial-gradient(520px 320px at 20% 0%,rgba(var(--ar),var(--ag),var(--ab),.14),transparent 62%),
    linear-gradient(160deg,var(--sf-5),var(--sf-1));
  border-right:1px solid var(--border);
}
.brand-mark{display:flex;align-items:center;gap:12px;margin-bottom:30px}
.mark-logo{
  width:46px;height:46px;display:flex;align-items:center;justify-content:center;
  background:transparent;border-radius:50%;
  filter:drop-shadow(0 6px 16px rgba(25,185,111,.35));
}
.mark-logo img{width:100%;height:100%;display:block;object-fit:contain}
.mark-title{font-size:20px;font-weight:800;letter-spacing:.5px}
.mark-sub{font-size:11.5px;color:var(--muted);letter-spacing:2px;text-transform:uppercase;margin-top:2px}
.brand-slogan{
  font-size:29px;font-weight:800;line-height:1.45;letter-spacing:.5px;margin-bottom:14px;
  background:linear-gradient(120deg,#FFFFFF 10%,#8FE9D5 55%,#5AA0FF 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.brand-desc{color:var(--text2);font-size:13.5px;line-height:1.9}
.brand-feats{margin-top:auto;display:flex;flex-direction:column;gap:20px;padding-top:26px}
/* 无背景、无边框，仅靠大图标 + 文字呈现 */
.feat{
  display:flex;align-items:center;gap:16px;padding:10px 0;
  background:none;border:none;
  transition:.22s;
}
.feat:hover{transform:translateX(4px)}
.feat:hover .feat-ico{color:#3DF5C4;filter:drop-shadow(0 0 12px rgba(var(--ar),var(--ag),var(--ab),.45))}
.feat:hover .feat-name{color:var(--accent)}
.feat-ico{
  width:52px;height:52px;flex:0 0 52px;display:flex;align-items:center;justify-content:center;
  background:none;color:var(--accent);
  transition:color .22s,filter .22s;
}
.feat-ico svg{width:32px;height:32px;stroke-width:1.6}
.feat-name{font-size:14.5px;font-weight:700;letter-spacing:.3px;transition:color .22s}
.feat-desc{font-size:12.5px;color:var(--muted);margin-top:4px;line-height:1.6}
/* 登录卡 */
/* position:relative 是为了让「切换主题配色」按钮贴在登录卡右上角内侧（见 .theme-btn.login-theme） */
.login-card{position:relative;flex:1;padding:46px 44px;display:flex;flex-direction:column;justify-content:center}
.login-head{display:flex;align-items:center;gap:12px;margin-bottom:8px}
.login-logo{
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  background:transparent;
  filter:drop-shadow(0 6px 16px rgba(25,185,111,.35));
}
.login-logo img{width:100%;height:100%;display:block;object-fit:contain}
.login-title{font-size:23px;font-weight:800;letter-spacing:.5px}
.login-tip{color:var(--muted);font-size:12.5px;margin-bottom:26px}
.field{margin-bottom:18px}
.field label{display:block;font-size:12.5px;color:var(--muted);margin-bottom:8px;letter-spacing:.4px}
.input-wrap{position:relative}
.input-wrap>svg{
  position:absolute;left:13px;top:50%;transform:translateY(-50%);
  width:16px;height:16px;color:var(--muted);pointer-events:none;transition:color .2s;
}
.input-wrap:focus-within>svg{color:var(--accent)}
/* 输入框底色与主题一致（深色），不再发白 */
.field input,.field select{
  width:100%;padding:12px 14px;border-radius:11px;
  background:var(--sf-2);border:1px solid var(--border2);
  color:var(--text);font-size:14px;font-family:inherit;outline:none;transition:.2s;
}
.field input::placeholder{color:var(--fg-dim)}
.input-wrap input{padding-left:40px}
.field input:focus,.field select:focus{
  border-color:rgba(var(--ar),var(--ag),var(--ab),.55);background:var(--sf-2);box-shadow:var(--ring);
}
/* 关键：屏蔽浏览器自动填充的白色/淡黄底色（Chrome 会强制刷白） */
.field input:-webkit-autofill,
.field input:-webkit-autofill:hover,
.field input:-webkit-autofill:focus,
.field input:-webkit-autofill:active,
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill{
  -webkit-text-fill-color:var(--text);
  caret-color:var(--text);
  /* 原来是硬编码 #0B1119 深色，切到浅色模式后登录框会变成黑底 —— 改用变量跟随主题 */
  -webkit-box-shadow:0 0 0 1000px var(--autofill-bg) inset !important;
  box-shadow:0 0 0 1000px var(--autofill-bg) inset !important;
  background-color:var(--autofill-bg) !important;
  background-image:none !important;
  transition:background-color 9999s ease-out 0s;
}
.login-err{
  min-height:20px;color:var(--red);font-size:12.5px;margin:2px 0 10px;
}
.login-extra{
  margin-top:14px;font-size:11.5px;color:var(--muted);text-align:center;line-height:1.8;
}
.login-extra b{color:var(--text2);font-weight:600}

/* ================= 按钮 ================= */
.btn-primary,.btn-ghost{
  border:none;border-radius:11px;padding:11px 20px;font-size:13.5px;font-family:inherit;
  cursor:pointer;transition:.18s;display:inline-flex;align-items:center;justify-content:center;gap:6px;
}
.btn-primary{
  background:linear-gradient(135deg,rgb(var(--ar),var(--ag),var(--ab)) 0%,rgba(var(--ar),var(--ag),var(--ab),.78) 100%);
  color:var(--on-accent);
  color:#04120E;font-weight:700;
  box-shadow:0 6px 18px rgba(var(--ar),var(--ag),var(--ab),.22),inset 0 1px 0 rgba(var(--ovl),.25);
}
.btn-primary:hover{transform:translateY(-1px);filter:brightness(1.06);box-shadow:0 12px 26px rgba(var(--ar),var(--ag),var(--ab),.34)}
.btn-primary:active{transform:translateY(0)}
.btn-primary svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}
.btn-ghost{
  background:rgba(var(--ovl),.05);color:var(--text2);border:1px solid var(--border2);
}
.btn-ghost:hover{background:rgba(var(--ovl),.1);color:var(--text);border-color:rgba(var(--ovl),.2);transform:translateY(-1px)}
.btn-ghost svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.btn-sm{padding:6px 14px;font-size:12.5px;border-radius:9px}
.login-btn{font-size:14.5px;letter-spacing:3px;margin-top:6px}
.ico{flex:0 0 auto;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.ico-img{width:20px;height:20px;display:block;object-fit:contain;filter:drop-shadow(0 2px 8px rgba(25,185,111,.35))}

/* ================= 布局 ================= */
.app{display:flex;height:100vh;position:relative;z-index:1}
.sidebar{
  width:240px;flex:0 0 240px;display:flex;flex-direction:column;
  background:linear-gradient(180deg,var(--side-1),var(--side-2));
  backdrop-filter:blur(14px);
  border-right:1px solid var(--border);
}
.brand{display:flex;align-items:center;gap:12px;padding:20px 18px 18px}
.brand-logo{
  width:36px;height:36px;flex:0 0 36px;display:flex;align-items:center;justify-content:center;
  background:transparent;
  filter:drop-shadow(0 4px 14px rgba(25,185,111,.30));
}
.brand-logo img{width:100%;height:100%;display:block;object-fit:contain}
.brand-text{min-width:0;flex:1}
.brand-name{
  font-size:14.5px;font-weight:800;letter-spacing:.2px;line-height:1.35;white-space:nowrap;
  background:linear-gradient(120deg,#FFFFFF 25%,#7FE7C6 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.menu{flex:1;overflow:auto;padding:6px 12px 12px}
.menu-group{margin:12px 0 6px;padding:0 10px;font-size:10.5px;color:var(--fg-dim);letter-spacing:1.4px}
.menu-item{
  position:relative;display:flex;align-items:center;gap:10px;
  padding:10px 12px;margin:2px 0;border-radius:11px;
  color:var(--muted);font-size:13.5px;cursor:pointer;
  border:1px solid transparent;transition:.18s;
}
.menu-item:hover{background:rgba(var(--ovl),.055);color:var(--text);transform:translateX(2px)}
.menu-item.on{
  background:linear-gradient(90deg,rgba(var(--ar),var(--ag),var(--ab),.17),rgba(var(--ar),var(--ag),var(--ab),.03));
  color:var(--accent-ink);font-weight:600;border-color:rgba(var(--ar),var(--ag),var(--ab),.2);
}
.menu-item.on::before{
  content:'';position:absolute;left:-12px;top:50%;transform:translateY(-50%);
  width:3px;height:20px;border-radius:0 3px 3px 0;background:var(--accent);
  box-shadow:0 0 12px rgba(var(--ar),var(--ag),var(--ab),.85);
}
.menu-item.on-parent{color:var(--accent-ink);background:rgba(var(--ar),var(--ag),var(--ab),.07)}
.menu-ico{width:18px;height:18px;flex:0 0 18px;color:inherit}
.menu-ico svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
.menu-name{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ↑ 三端防换行：min-width:0 允许压缩，超出显示省略号。
   电脑端原来只有 flex:1 没有这两条，文字一宽就折行（pad/phone 段本来就有）。 */
/* 父菜单展开箭头：未展开朝右 ›，展开后顺时针转 90° 朝下 ∨
   想换成别的方向：改下面 .open 的 rotate 角度即可（90=下，180=左，0=右） */
.menu-arrow{
  width:14px;height:14px;flex:0 0 14px;opacity:.6;transition:transform .2s, opacity .2s;
  display:flex;align-items:center;justify-content:center;font-size:15px;line-height:1;
}
.menu-arrow svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.menu-item.on .menu-arrow{opacity:1}
/* ★ 展开态必转向下。之前只写了 .menu-item.on 的旋转，导致「展开了但不是当前页」
   的父菜单箭头仍朝右，看起来像没展开 */
.menu-arrow.open{opacity:1;transform:rotate(90deg)}
.menu-child{padding:2px 0 4px 26px;animation:fade .2s both}
.menu-dot{
  width:5px;height:5px;border-radius:50%;background:var(--muted);margin-right:9px;
}
.menu-dot + .menu-name{font-size:12.8px}
.menu-item.on .menu-dot{background:var(--accent);box-shadow:0 0 10px rgba(var(--ar),var(--ag),var(--ab),.9)}
.menu-item.on-parent .menu-ico{color:var(--accent);opacity:1}
.sidebar-foot{
  padding:12px 18px;border-top:1px solid var(--border);
  display:flex;align-items:center;justify-content:space-between;
}
.sidebar-foot .role-tag{
  display:inline-flex;align-items:center;gap:6px;
  font-size:11.5px;color:var(--text2);background:rgba(var(--ovl),.05);
  border:1px solid var(--border2);border-radius:99px;padding:4px 11px;
}
.sidebar-foot .ver{font-size:10.5px;color:var(--fg-dim)}

/* min-height:0 很关键：flex 子项默认 min-height:auto，会被内容撑开而拒绝滚动，
   表现为「内容显示不全且下滑不动」 */
.main{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}
.topbar{
  flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;
  padding:15px 26px;
  background:var(--sf-1);
  backdrop-filter:blur(14px);
  border-bottom:1px solid var(--border);
}
.page-title{font-size:18px;font-weight:700;letter-spacing:.3px}
.page-sub{font-size:12px;color:var(--muted);margin-top:3px}

/* ===== 环境徽章：顶栏标题后面的小标签 =====
   作用：一眼分清现在是「测试环境」还是「正式环境」，
   避免在测试站改完代码后，误以为正式站也跟着变了（其实是两套独立部署）。
   显示内容由后端 /api/system/status 返回的 deploy_env 决定，
   改文案去 config.py 的 ENV_DISPLAY_NAME / ENV_LABEL。
   · 测试环境 = 橙色（提醒：这里改的东西还没上线）
   · 正式环境 = 绿色（提醒：这里改的东西直接影响用户）
   想换颜色：改下面 .env-badge.dev / .env-badge.prod 的配色即可。 */
.env-badge{
  display:inline-block;
  margin-left:8px;
  padding:2px 8px;
  border-radius:999px;
  font-size:11px;
  font-weight:700;
  letter-spacing:.2px;
  vertical-align:middle;
  line-height:1.6;
  white-space:nowrap;
  border:1px solid transparent;
}
.env-badge.dev{
  color:#ffd699;
  background:rgba(245,168,60,.16);
  border-color:#f5a83c;
}
.env-badge.prod{
  color:#7ff0c0;
  background:rgba(45,200,140,.16);
  border-color:#2dc88c;
}
/* 浅色模式：换成深字浅底，保证在白底上也看得清 */
[data-mode="light"] .env-badge.dev{color:#8a5300;background:#ffe9c2;border-color:#f0b95c}
[data-mode="light"] .env-badge.prod{color:#0b6b4a;background:#c9f2e0;border-color:#4cc79a}

/* ===== 一键发布卡片里的步骤输出 =====
   每一步执行完回显一行：✓ / ✗ + 说明。用等宽字体方便看命令和路径。 */
.sync-steps{
  margin-top:10px;
  padding:10px 12px;
  border-radius:8px;
  background:var(--bg-soft,#f6f8fa);
  border:1px solid var(--line,#e3e8ef);
  font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:12px;
  line-height:1.9;
  white-space:pre-wrap;
  word-break:break-all;
  max-height:340px;
  overflow:auto;
}
[data-mode="dark"] .sync-steps{background:rgba(255,255,255,.04);border-color:rgba(255,255,255,.12)}
.sync-steps .ok{color:var(--good,#1a7f52);font-weight:600}
.sync-steps .bad{color:var(--bad,#d33);font-weight:600}
.sync-steps .dim{color:var(--muted,#8a94a6)}
/* 失败步骤的命令输出：缩进成块单独显示。
   以前和输出挤在同一行，长文本会被容器截断，看不到真正的报错原因。
   white-space 保持 pre-wrap，让 Traceback 的换行原样保留，方便定位行号。 */
.sync-step-out{
  margin:2px 0 8px 18px;
  padding:8px 10px;
  border-radius:6px;
  border-left:3px solid var(--bad,#d33);
  background:rgba(211,51,51,.07);
  color:var(--bad,#d33);
  font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:11.5px;
  line-height:1.7;
  white-space:pre-wrap;
  word-break:break-all;
  max-height:220px;
  overflow:auto;
}
.userbox{display:flex;align-items:center;gap:11px}
.userbox .clock{
  text-align:right;font-size:11.5px;color:var(--muted);line-height:1.5;
  padding-right:12px;margin-right:2px;border-right:1px solid var(--border);
}
.userbox .clock b{display:block;color:var(--text2);font-weight:600;font-size:12.5px}
.u-avatar{
  width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:14px;font-weight:700;color:#04120E;
  background:linear-gradient(135deg,rgb(var(--ar),var(--ag),var(--ab)),rgb(var(--a2r),var(--a2g),var(--a2b)));
  box-shadow:0 4px 14px rgba(var(--ar),var(--ag),var(--ab),.25);
}
.u-name{font-size:13px;font-weight:600}
.u-role{font-size:11.5px;color:var(--muted);margin-top:1px}
.content{
  flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;
  padding:22px 26px 34px;
  display:flex;flex-direction:column;gap:18px;
  -webkit-overflow-scrolling:touch;   /* iOS 惯性滚动 */
  overscroll-behavior:contain;
}
.content>*{animation:rise .34s cubic-bezier(.2,.8,.3,1) both}
/* flex 子项默认可压缩，panel 被压扁后内部表格会被 overflow:hidden 裁掉，
   表现为「显示不全且下滑不动」。禁止压缩，交给 .content 滚动。 */
.content>*{flex:0 0 auto}

/* ================= 卡片 / 面板 ================= */
.panel{
  position:relative;overflow:hidden;
  background:linear-gradient(165deg,rgba(var(--ovl),.055),rgba(var(--ovl),.022));
  border:1px solid var(--border2);
  border-radius:var(--radius);
  padding:18px 20px 20px;
  box-shadow:0 8px 26px var(--sh-soft);
  transition:border-color .2s,box-shadow .2s;
}
.panel::before{
  content:'';position:absolute;left:14px;right:14px;top:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(var(--ar),var(--ag),var(--ab),.4),rgba(var(--a2r),var(--a2g),var(--a2b),.28),transparent);
}
.panel:hover{border-color:rgba(var(--ar),var(--ag),var(--ab),.18)}
.panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:15px;gap:12px;flex-wrap:wrap}
.panel-title{
  position:relative;padding-left:12px;font-size:14.5px;font-weight:700;letter-spacing:.3px;
}
.panel-title::before{
  content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:3px;height:14px;border-radius:3px;
  background:linear-gradient(180deg,var(--accent),rgba(var(--a2r),var(--a2g),var(--a2b),.6));
}
.panel-sub{font-size:12px;color:var(--muted)}

/* ================= 可折叠面板 ================= */
/* 用法：<div class="panel fold-panel" id="xxx"> + .fp-head（带 onclick="toggleFold('xxx')"） + .fp-body
   默认收起；展开状态由 JS 的 FOLD_STATE 记住，切走再回来还是原样。
   ★ 注意：折叠区里的「自动补齐异常告警」「生成结果」会被 JS 自动展开（openFold），
     所以不用担心关键信息被折起来看不见。 */
.fold-panel .fp-head{cursor:pointer;user-select:none;margin-bottom:0;transition:margin-bottom .18s}
.fold-panel .fp-head:hover .panel-title{color:var(--accent)}
.fold-panel .fp-arrow{
  display:inline-block;margin-left:8px;font-size:11px;color:var(--muted);
  transition:transform .18s,color .18s;
}
.fold-panel .fp-head:hover .fp-arrow{color:var(--accent)}
/* 默认收起：body 高度 0 + 溢出隐藏 */
.fold-panel .fp-body{
  max-height:0;overflow:hidden;opacity:0;
  transition:max-height .26s ease,opacity .2s ease,margin-top .2s ease;
}
/* 展开：给个足够大的高度让内容自然撑开（比 max-height:none 有过渡动画） */
.fold-panel.open .fp-body{max-height:4200px;opacity:1;margin-top:15px}
.fold-panel.open .fp-head{margin-bottom:0}

/* ================= KPI ================= */
/* KPI 卡片行
   ★ 想调每行几张卡：改下面 minmax(150px,1fr) 里的 150px ——
     数值越小，一行能塞的卡片越多（卡片越窄）；数值越大，卡片越宽、每行越少。
     例：想一行固定 4 张 → 把整行改成 grid-template-columns:repeat(4,1fr)
     现在的 auto-fit 会自动根据屏幕宽窄决定列数，不会在小屏上挤成一团。 */
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
.kpi{
  position:relative;overflow:hidden;
  background:linear-gradient(165deg,rgba(var(--ovl),.062),rgba(var(--ovl),.022));
  border:1px solid var(--border2);border-radius:var(--radius);
  padding:13px 15px 12px;transition:.22s;
}
.kpi::after{
  content:'';position:absolute;inset:0 0 auto 0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(var(--ar),var(--ag),var(--ab),.55),transparent);
}
.kpi:hover{transform:translateY(-3px);border-color:rgba(var(--ar),var(--ag),var(--ab),.28);box-shadow:0 16px 34px var(--sh-soft)}
.kpi-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.kpi-ico{
  width:30px;height:30px;border-radius:10px;display:flex;align-items:center;justify-content:center;
  background:var(--accent-dim);color:var(--accent);
}
.kpi-ico svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.kpi-ico.blue{background:rgba(var(--a2r),var(--a2g),var(--a2b),.14);color:var(--blue)}
.kpi-ico.purple{background:rgba(var(--a3r),var(--a3g),var(--a3b),.14);color:var(--purple)}
.kpi-ico.orange{background:rgba(240,169,63,.14);color:var(--orange)}
.kpi-ico.red{background:rgba(255,107,139,.14);color:var(--red)}
.kpi-badge{font-size:10.5px;color:var(--muted);border:1px solid var(--border2);border-radius:99px;padding:3px 9px}
.kpi-label{font-size:11.5px;color:var(--muted);letter-spacing:.3px}
.kpi-value{
  font-size:23px;font-weight:800;line-height:1.2;margin-top:4px;color:var(--accent);
  font-variant-numeric:tabular-nums;text-shadow:0 0 26px rgba(var(--ar),var(--ag),var(--ab),.22);
}
.kpi-value.blue{color:var(--blue);text-shadow:0 0 26px rgba(var(--a2r),var(--a2g),var(--a2b),.22)}
.kpi-value.purple{color:var(--purple);text-shadow:0 0 26px rgba(var(--a3r),var(--a3g),var(--a3b),.22)}
.kpi-value.orange{color:var(--orange);text-shadow:0 0 26px rgba(240,169,63,.22)}
.kpi-value.red{color:var(--red);text-shadow:0 0 26px rgba(255,107,139,.22)}
.kpi-foot{font-size:10.5px;color:var(--fg-dim);margin-top:4px}

/* ---- 两个小工具类（登录日志页在用）----
   .fs15 = 字号压到 15px：KPI 卡里放日期这类长文本时，23px 会撑破卡片
   .grow = 弹性占位（flex:1）：把后面的元素推到行尾，等效于一个透明的弹簧
   ★ 这两个 class 在 app.js 里有引用，删掉会导致界面错乱，check_all.py 会报错 */
.fs15{font-size:15px!important}
.grow{flex:1 1 auto;min-width:0}

/* ================= 表格 ================= */
.tbl-wrap{overflow-x:auto;margin:0 -4px;padding:0 4px}
.tbl{width:100%;border-collapse:separate;border-spacing:0;font-size:13px}
.tbl th{
  text-align:left;font-weight:600;color:var(--muted);font-size:12px;letter-spacing:.4px;
  padding:10px 12px;background:rgba(var(--ovl),.04);
  border-top:1px solid var(--border);border-bottom:1px solid var(--border);white-space:nowrap;
}
.tbl th:first-child{border-left:1px solid var(--border);border-top-left-radius:10px}
.tbl th:last-child{border-right:1px solid var(--border);border-top-right-radius:10px}
.tbl td{padding:11px 12px;border-bottom:1px solid rgba(var(--ovl),.05);color:var(--text2);vertical-align:middle}
.tbl tbody tr{transition:background .15s}
.tbl tbody tr:nth-child(even){background:rgba(var(--ovl),.018)}
.tbl tbody tr:hover{background:rgba(var(--ar),var(--ag),var(--ab),.055)}
.tbl tbody tr:hover td{color:var(--text)}
.tbl tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--accent);border-radius:0 0 0 8px}
.tbl tbody tr:last-child td{border-bottom:none}
.tbl td.num{font-variant-numeric:tabular-nums;color:var(--text);font-weight:600}
.tbl td.mid{color:var(--text2)}
.tbl td.mono{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12.2px;color:var(--muted)}
.tbl td button{margin-right:0}

/* ================= 状态标签 ================= */
.tag{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 11px;border-radius:99px;font-size:11.5px;font-weight:600;
  border:1px solid transparent;white-space:nowrap;
}
.tag .dot{width:6px;height:6px;border-radius:50%;background:currentColor;box-shadow:0 0 8px currentColor}
.tag.green{color:var(--accent-ink);background:rgba(var(--ar),var(--ag),var(--ab),.11);border-color:rgba(var(--ar),var(--ag),var(--ab),.24)}
/* 达成率异常提醒标签（B2/B5）：橙色，与「逾期」红色区分开 */
.tag.warn{color:var(--orange);background:rgba(240,169,63,.12);border-color:rgba(240,169,63,.28)}
[data-mode="light"] .tag.warn{color:#8A5A00;background:rgba(240,169,63,.16)}
.tag.red{color:var(--red);background:rgba(255,107,139,.11);border-color:rgba(255,107,139,.24)}
.tag.orange{color:var(--orange);background:rgba(240,169,63,.11);border-color:rgba(240,169,63,.24)}
.tag.blue{color:var(--ink2);background:rgba(var(--a2r),var(--a2g),var(--a2b),.11);border-color:rgba(var(--a2r),var(--a2g),var(--a2b),.24)}
.tag.purple{color:var(--ink3);background:rgba(var(--a3r),var(--a3g),var(--a3b),.11);border-color:rgba(var(--a3r),var(--a3g),var(--a3b),.24)}
.tag.gray{color:var(--gray);background:rgba(var(--ovl),.06);border-color:rgba(var(--ovl),.13)}
/* ── 看板「预估出栏」标签：与各环节「达成率」同一套淡底+彩字+圆点的样式 ──
   颜色走主题主色 --accent（换配色/切深浅自动跟着变）。
   想换成别的颜色：把 var(--accent) 与下面三处 rgba(var(--ar),…) 换成
   你想要的颜色即可，例如橙色 → color:var(--orange) / rgba(240,169,63,.13)。 */
.tag.yuji{
  color:var(--accent-ink);   /* 用「可读墨色」：浅底自动加深，不刺眼也看得清 */
  background:rgba(var(--ar),var(--ag),var(--ab),.13);
  border-color:rgba(var(--ar),var(--ag),var(--ab),.28);
  font-weight:700;
}
/* 还没有可推算的基数（配种都没录）→ 灰色「—」，避免被当成「预估 0 只」 */
.tag.yuji.yuji-empty{color:var(--gray);background:rgba(var(--ovl),.06);border-color:rgba(var(--ovl),.13);font-weight:600}

/* ── 成本盈亏页用的三种状态标签 ──────────────────────────
   .ok  = 达标 / 盈利（绿）  .err = 亏损 / 最差（红）
   .est = 「估」标记：这个数字是系统按经验值算的，不是你手填的
   这三个都走 CSS 变量，换配色、切深色浅色会自动跟着变，不用改两遍。 */
.tag.ok{color:var(--green);background:rgba(var(--ar),var(--ag),var(--ab),.11);border-color:rgba(var(--ar),var(--ag),var(--ab),.24)}
.tag.err{color:var(--red);background:rgba(255,107,139,.11);border-color:rgba(255,107,139,.24)}
/* 「估」字标记：用灰底弱化处理，只做提示，不抢主数据的视觉 */
.tag.est{
  color:var(--gray);background:rgba(var(--ovl),.06);border-color:rgba(var(--ovl),.13);
  font-weight:600;font-size:10px;padding:1px 5px;margin-left:3px;transform:translateY(-1px);
}

/* ================= 筛选行 ================= */
.filter{display:flex;align-items:center;gap:11px;flex-wrap:wrap}
.filter select,.filter input{
  padding:8px 12px;border-radius:10px;background:var(--sf-2);
  border:1px solid var(--border2);color:var(--text);font-size:13px;font-family:inherit;outline:none;transition:.2s;
}
.filter select:focus,.filter input:focus{border-color:rgba(var(--ar),var(--ag),var(--ab),.5);box-shadow:var(--ring)}


/* ===== 日期输入框 ===== */
.date-input{cursor:pointer;position:relative}
/* 日历图标：直接用浏览器原生的小图标，只做「上色 + 去背景」处理。
   旧做法是隐藏原生图标、用 background-image 画一个自定义 SVG，
   在弹窗(modal)里会和原生面板重叠，出现「一排图标」的错位。 */
::-webkit-calendar-picker-indicator{
  width:18px;height:18px;padding:0;margin:0;cursor:pointer;
  background:transparent;border-radius:4px;
  opacity:.85;
  /* 原生图标是黑色的：深色模式反色成浅色才看得清 */
  filter:invert(1) brightness(1.6);
  transition:opacity .15s;
}
::-webkit-calendar-picker-indicator:hover{opacity:1}
/* 浅色模式：白底上要用深色图标，不能再反色 */
[data-mode="light"] ::-webkit-calendar-picker-indicator{
  filter:none;opacity:.7;
}
[data-mode="light"] ::-webkit-calendar-picker-indicator:hover{opacity:1}
.field input.date-input,
.filter input.date-input,
.mfield input.date-input{
  padding-right:34px;
}
/* 未选择日期时给出视觉提示（配合必填校验） */
input.date-input:invalid,
input.date-input[value=""]{ }
input.date-input:hover{
  border-color:rgba(var(--ar),var(--ag),var(--ab),.45);
}
.date-input::-webkit-datetime-edit{color:var(--text)}
.date-input::-webkit-datetime-edit-fields-wrapper{color:var(--text)}
.date-input::-webkit-datetime-edit-text,
.date-input::-webkit-datetime-edit-year-field,
.date-input::-webkit-datetime-edit-month-field,
.date-input::-webkit-datetime-edit-day-field{color:var(--text)}
.date-input:focus::-webkit-datetime-edit-text{color:var(--accent)}

/* ===== 自定义复选框 ===== */
.cbx{display:inline-flex;align-items:center;gap:9px;cursor:pointer;user-select:none}
.cbx input{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
.cbx-box{
  width:19px;height:19px;flex:0 0 19px;border-radius:6px;
  background:var(--sf-2);border:1.5px solid rgba(var(--ovl),.22);
  display:flex;align-items:center;justify-content:center;
  transition:.18s;
}
.cbx-box svg{
  width:13px;height:13px;stroke:var(--accent);stroke-width:3.2;fill:none;
  stroke-linecap:round;stroke-linejoin:round;
  opacity:0;transform:scale(.5);transition:.18s;
}
.cbx:hover .cbx-box{border-color:rgba(var(--ar),var(--ag),var(--ab),.55)}
.cbx input:focus-visible + .cbx-box{box-shadow:var(--ring)}
/* 选中：深绿底 + 绿边 + 亮绿色对勾 */
.cbx input:checked + .cbx-box{
  background:rgba(var(--ar),var(--ag),var(--ab),.14);
  border-color:var(--accent);
  box-shadow:0 0 14px rgba(var(--ar),var(--ag),var(--ab),.30);
}
.cbx input:checked + .cbx-box svg{
  opacity:1;transform:scale(1);
  filter:drop-shadow(0 0 5px rgba(var(--ar),var(--ag),var(--ab),.7));
}
.cbx-txt{font-size:13px;color:var(--text2)}
.cbx input:checked ~ .cbx-txt{color:var(--accent);font-weight:600}

/* ================= 进度条 ================= */
.progress-wrap{margin-top:4px}
.progress-head{display:flex;justify-content:space-between;font-size:12px;margin-bottom:6px}
.progress-txt{color:var(--muted)}
/* ★ display:block 不能删！
   本文件的进度条在 JS 里用 <span> 渲染（见 app.js 的 pcaStructure），
   span 默认 display:inline，而 inline 元素的 width/height 一律无效 ——
   少了这行，填充条宽度为 0，再好看的渐变色也显示不出来，
   只剩外层 .bar 的灰底（表现就是"进度条永远是灰色"）。
   历史坑：改过好几次渐变色都没解决，最后发现根因在这里。 */
.bar{display:block;height:8px;border-radius:99px;background:rgba(var(--ovl),.10);overflow:hidden}
/* 进度条填充色：必须用「可读墨色」--accent-ink / --ink2 / --ink3，
   不要用 --ar/--ag/--ab（那是亮色主色）。
   原因：mint 这类浅配色主色是 RGB(110,231,214) 极浅薄荷绿，
   画在浅色底上几乎看不见（实测对比度不足 1.5，等于"没颜色"）。
   墨色在浅底自动加深、深底自动柔化，两端都清晰且不刺眼。
   想改配色：改各主题块里的 --kr/--kg/--kb（浅色）或 --dr/--dg/--db（深色）。 */
.bar-in{
  display:block;   /* ★ 同上：不写 block，width 不生效，填充条完全看不见 */
  height:100%;border-radius:99px;
  background:linear-gradient(90deg,var(--accent-ink),var(--ink2));
  transition:width .6s cubic-bezier(.2,.8,.3,1);
}
/* 多条并列时轮流取色，避免全是一个颜色看不出区别 */
.bar-in.k2{background:linear-gradient(90deg,var(--ink2),var(--ink3))}
.bar-in.k3{background:linear-gradient(90deg,var(--ink3),var(--accent-ink))}
.bar-in.k4{background:linear-gradient(90deg,var(--accent-ink),var(--ink3))}
/* 数值文字跟着条的颜色走，一眼能对上是哪一类 */
.pca-bar-vl.k1{color:var(--accent-ink);font-weight:700}
.pca-bar-vl.k2{color:var(--ink2);font-weight:700}
.pca-bar-vl.k3{color:var(--ink3);font-weight:700}
.pca-bar-vl.k4{color:var(--accent-ink);font-weight:700}
/* 类别名左侧加个小色点，条很短（占比 1%）时也能看出是哪一类 */
.pca-bar-nm{display:inline-flex;align-items:center;gap:6px;min-width:52px}
.pca-bar-nm::before{
  content:'';width:7px;height:7px;border-radius:99px;flex:0 0 7px;
  background:var(--accent-ink);
}
.pca-bar-row:nth-child(2) .pca-bar-nm::before{background:var(--ink2)}
.pca-bar-row:nth-child(3) .pca-bar-nm::before{background:var(--ink3)}
.pca-bar-row:nth-child(4) .pca-bar-nm::before{background:var(--ink3)}

/* ================= 盘存录入网格 ================= */
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.in-card{
  position:relative;overflow:hidden;
  background:linear-gradient(165deg,rgba(var(--ovl),.055),rgba(var(--ovl),.02));
  border:1px solid var(--border2);border-radius:var(--radius);
  padding:16px 18px;transition:.2s;
}
.in-card:hover{border-color:rgba(var(--ar),var(--ag),var(--ab),.25);transform:translateY(-2px);box-shadow:0 12px 28px rgba(0,0,0,.3)}
.in-label{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--muted);margin-bottom:10px}
.in-label .in-ico{
  width:26px;height:26px;flex:0 0 26px;border-radius:8px;display:flex;align-items:center;justify-content:center;
  background:var(--accent-dim);color:var(--accent);font-size:12px;font-weight:700;
}
.in-row{display:flex;align-items:center;gap:10px}
.in-row input{
  flex:1;padding:9px 12px;border-radius:10px;background:rgba(var(--ovl),.05);
  border:1px solid var(--border2);color:var(--text);font-size:14px;font-family:inherit;outline:none;transition:.2s;
  font-variant-numeric:tabular-nums;
}
.in-row input:focus{border-color:rgba(var(--ar),var(--ag),var(--ab),.5);background:rgba(var(--ar),var(--ag),var(--ab),.05);box-shadow:var(--ring)}
.in-unit{font-size:12px;color:var(--muted);flex:0 0 auto}
.in-status{display:flex;align-items:center;justify-content:space-between;font-size:12px;margin-top:10px;color:var(--muted)}

/* ================= 柱状图 ================= */
.chart{display:flex;align-items:flex-end;gap:14px;height:210px;padding:10px 4px 0}
.chart-col{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;gap:7px}
.chart-bar{
  width:100%;max-width:46px;border-radius:8px 8px 3px 3px;
  background:linear-gradient(180deg,rgb(var(--ar),var(--ag),var(--ab)),rgba(var(--ar),var(--ag),var(--ab),.18));
  box-shadow:0 0 18px rgba(var(--ar),var(--ag),var(--ab),.28);
  transition:.3s cubic-bezier(.2,.8,.3,1);min-height:3px;
}
.chart-col:hover .chart-bar{
  background:linear-gradient(180deg,#5AA0FF,rgba(var(--a2r),var(--a2g),var(--a2b),.2));
  box-shadow:0 0 22px rgba(var(--a2r),var(--a2g),var(--a2b),.4);transform:translateY(-3px);
}
.chart-val{font-size:11.5px;color:var(--text2);font-variant-numeric:tabular-nums}
.chart-lb{font-size:11px;color:var(--muted);white-space:nowrap}


/* ===== 录入配种：下一批日期提示条 ===== */
.next-tip{
  display:flex;align-items:center;flex-wrap:wrap;gap:8px;
  margin-top:12px;padding:10px 14px;border-radius:11px;
  background:rgba(var(--ovl),.035);border:1px solid var(--border);
  font-size:12.5px;color:var(--text2);line-height:1.7;
}
.next-tip b{color:var(--text);font-weight:700}
.nt-tag{
  display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
  padding:3px 10px;border-radius:99px;font-size:11.5px;font-weight:600;
  background:rgba(var(--a2r),var(--a2g),var(--a2b),.12);color:var(--blue);border:1px solid rgba(var(--a2r),var(--a2g),var(--a2b),.24);
}
.nt-tag svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.nt-tag.ok{background:rgba(var(--ar),var(--ag),var(--ab),.12);color:var(--accent);border-color:rgba(var(--ar),var(--ag),var(--ab),.24)}
.nt-tag.warn{background:rgba(240,169,63,.12);color:var(--orange);border-color:rgba(240,169,63,.24)}
.nt-sub{color:var(--muted);font-size:12px}



/* ===== 用户管理 · 权限列 ===== */
.perm-cell{min-width:150px}
.perm-tags{display:flex;flex-wrap:wrap;gap:4px}
.perm-tag{
  display:inline-block;padding:2px 8px;border-radius:6px;
  font-size:11.5px;color:var(--text2);
  background:rgba(var(--ovl),.055);border:1px solid var(--border2);
  white-space:nowrap;
}


/* ===== 系统维护 ===== */
.ops-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:12px}
.ops-item{
  display:flex;align-items:center;gap:10px;padding:11px 13px;border-radius:11px;
  background:rgba(var(--ovl),.035);border:1px solid var(--border);
}
.ops-ico{width:28px;height:28px;flex:0 0 28px;border-radius:9px;
  display:flex;align-items:center;justify-content:center;
  background:var(--accent-dim);color:var(--accent)}
.ops-ico svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.ops-lb{font-size:12px;color:var(--muted);flex:0 0 auto}
.ops-vl{font-size:12.5px;color:var(--text);margin-left:auto;text-align:right;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60%}
/* ops-vl 里的灰色补充说明（如「你填的是 X，已自动定位到代码目录」）
   ★ 上面 .ops-vl 是单行省略号，这里必须逐条放开，否则第二行会被裁掉看不见 */
.ops-vl .dim{display:block;white-space:normal;overflow:visible;text-overflow:clip;
  max-width:none;font-size:11.5px;color:var(--muted);margin-top:2px;line-height:1.45}
.ops-btns{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:12px}
.ops-btns .btn-ghost{display:inline-flex;align-items:center;gap:6px;padding:9px 16px}
.ops-btns .btn-ghost svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.ops-btns .btn-ghost[disabled]{opacity:.45;cursor:not-allowed}
.ops-btns .btn-ghost.danger{color:var(--orange);border-color:rgba(240,169,63,.28)}
.ops-btns .btn-ghost.danger:hover{background:rgba(240,169,63,.1);border-color:rgba(240,169,63,.45);color:var(--orange)}
.ops-log{
  margin:0;padding:14px 16px;border-radius:11px;max-height:340px;overflow:auto;
  background:var(--code-bg);border:1px solid var(--border2);
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;line-height:1.7;
  color:var(--log-fg);white-space:pre-wrap;word-break:break-all;
}
@media (max-width:1180px){ .ops-grid{grid-template-columns:repeat(2,1fr)} }
@media (max-width:700px){ .ops-grid{grid-template-columns:1fr} }


/* ===== 用户管理 · 权限编辑器 ===== */
.req{color:var(--red);font-style:normal;font-weight:700;margin-left:2px}
.bad{
  border-color:var(--red)!important;
  box-shadow:0 0 0 3px rgba(255,90,90,.18)!important;
  animation:shake .32s;
}
@keyframes shake{
  0%,100%{transform:translateX(0)}
  25%{transform:translateX(-4px)}
  75%{transform:translateX(4px)}
}
.perm-editor{margin-top:4px}
.pm-tag{
  display:inline-block;margin-left:8px;padding:1px 8px;border-radius:5px;
  font-size:11px;font-weight:600;
  background:rgba(var(--ar),var(--ag),var(--ab),.14);color:var(--accent);border:1px solid rgba(var(--ar),var(--ag),var(--ab),.26);
}
.pm-tag.inherit{background:rgba(var(--ovl),.06);color:var(--muted);border-color:var(--border2)}
/* ★ 「继承角色 / 已单独配置」标签是可点的（点击 = 清空勾选、恢复继承），
      所以必须给出可点击的视觉反馈，否则用户会以为它坏了（点了没反应）。 */
.pm-tag{cursor:pointer;user-select:none;transition:.15s}
.pm-tag:hover{filter:brightness(1.15);border-color:var(--accent)}
.pm-tag:active{transform:scale(.96)}
.pm-tag:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.perm-box{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px 10px;
  padding:12px;border-radius:11px;
  background:var(--sf-2);border:1px solid var(--border2);
}
.perm-cbx{padding:6px 8px;border-radius:8px;transition:.15s}
.pm-chk{position:absolute;opacity:0;width:0;height:0}
.perm-cbx:hover{background:rgba(var(--ovl),.05)}
.perm-cbx.sub{margin-left:14px}
.perm-cbx.sub .cbx-txt::before{
  content:'└ ';color:var(--fg-dim);
}
.perm-actions{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
.warn-hint{
  color:var(--orange);background:rgba(240,169,63,.09);
  border:1px solid rgba(240,169,63,.22);border-radius:9px;padding:8px 12px;
}


/* ===== 自动补齐状态条 ===== */
.af-box{
  margin-top:12px;padding:11px 14px;border-radius:11px;
  background:rgba(var(--ovl),.035);border:1px solid var(--border);
  font-size:12.5px;color:var(--text2);
}
.af-head{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.af-head svg{width:15px;height:15px;stroke:var(--accent);fill:none;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;flex:0 0 15px}
.af-title{font-weight:700;color:var(--text);font-size:13px}
.af-head .tag{padding:2px 9px;font-size:11.5px}
.af-sub{color:var(--muted);font-size:12px;margin-left:2px}
.af-head .btn-sm{margin-left:auto}
.af-box .af-sub b{color:var(--text2);font-weight:600}
.af-box code{
  padding:1px 5px;border-radius:5px;background:var(--code-bg);
  border:1px solid var(--border2);font-size:11px;color:var(--accent);
}


/* 生成批次按钮旁的提示文字 */
.gd-tip{font-size:12px;color:var(--muted);margin-left:2px;line-height:1.5}
.gd-tip b{color:var(--text);font-weight:700}
/* 禁用态按钮要一眼看出不可点 */
.btn-primary:disabled{opacity:.45;cursor:not-allowed;filter:grayscale(.4)}
.btn-ghost:disabled{opacity:.45;cursor:not-allowed}

/* ===== 数据表 CRUD ===== */
.tbl-tools{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.btn-ghost.danger{color:var(--red);border-color:rgba(255,90,90,.28)}
.btn-ghost.danger:hover{background:rgba(255,90,90,.12);border-color:rgba(255,90,90,.45)}
.btn-xs{padding:3px 9px;font-size:11.5px;border-radius:7px}
/* 操作列：必须给出高于普通单元格的 z-index 且背景完全不透明，
   否则横向滚动或 hover 时会被相邻单元格内容压住，导致按钮点不到 */
/* 冻结列层级必须整体高于普通单元格（后者 z-index 为 auto/0），
   且**表头要高于表体冻结列**，否则纵向滚动时操作列会盖住表头。
   层级从低到高：普通单元格 0 → 表体行号 5 → 表体操作列 6
                 → 表头普通列 7 → 表头行号 8 → 表头操作列 9 */
.dbt-grid .tbl th.opcol,.dbt-grid .tbl td.opcol{
  position:sticky;right:0;z-index:6;
  background:var(--sf-solid);
  border-left:1px solid rgba(var(--ovl),.07);
  white-space:nowrap;width:112px;min-width:112px;
  box-shadow:-6px 0 12px var(--sh-soft);
}
.dbt-grid .tbl th.opcol{z-index:9;background:var(--sf-5)}
.dbt-grid .tbl td.opcol{background:var(--sf-solid-2);text-align:center}
.dbt-grid .tbl td.opcol .btn-ghost{
  margin:0 2px;position:relative;z-index:1;
  /* 按钮自己也要不透明，否则相邻单元格的长文本会透过按钮的半透明底色 */
  background:var(--sf-solid);
}
.dbt-grid .tbl td.opcol .btn-ghost:hover{background:rgba(var(--ar),var(--ag),var(--ab),.14)}
/* 表头两个冻结角：行号列与操作列交叉处层级要最高 */
.dbt-grid .tbl th.rowno{z-index:8}
.dbt-grid .tbl td.rowno{z-index:5;background:var(--sf-solid-2)}
/* 兜底：任何非冻结单元格都不允许建立自己的层叠上下文压住冻结列 */
.dbt-grid .tbl td:not(.rowno):not(.opcol),
.dbt-grid .tbl th:not(.rowno):not(.opcol){z-index:auto}
/* 单元格内容过长时截断，避免撑破列宽后压到操作列上 */
.dbt-grid .tbl td:not(.opcol){max-width:220px;overflow:hidden;text-overflow:ellipsis}
.hint-inline{color:var(--fg-dim);font-size:11px}
/* 行编辑弹窗 */
.rf-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px}
.rf-grid .mfield{margin:0}
.rf{width:100%}
.f-tip{display:block;font-weight:400;font-size:11px;color:var(--muted);margin-top:1px}


/* ===== 权限勾选树（大类 + 子菜单） ===== */
.perm-tree{display:flex;flex-direction:column;gap:8px}
.pt-group{
  padding:9px 11px;border-radius:10px;
  background:var(--sf-2);border:1px solid var(--border2);
}
.pt-parent .pt-name{font-weight:700;color:var(--text);font-size:13px}
.pt-kids{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));
  gap:6px 10px;margin:8px 0 2px 26px;padding-left:12px;
  border-left:2px solid rgba(var(--ovl),.08);
}
.pt-kids .cbx-txt{font-size:12.5px;color:var(--text2)}


/* ===== 生产看板：耗时与缓存标识 ===== */
.kb-meta{
  margin-left:auto;font-size:12px;color:var(--muted);
  display:flex;align-items:center;gap:6px;
}
.kb-meta b{font-weight:700;color:var(--accent)}
.kb-meta b.kb-slow{color:var(--orange,#FFA94D)}
.kb-cache{
  padding:1px 7px;border-radius:6px;font-size:11px;
  background:rgba(var(--ovl),.07);border:1px solid var(--border2);color:var(--muted);
}

/* ===== 看板分页 ===== */
.pager{
  display:flex;align-items:center;gap:8px;padding:12px 4px 2px;flex-wrap:wrap;
}
.pager-info{font-size:12.5px;color:var(--muted);margin-right:4px}
.pager-cur{font-size:12.5px;color:var(--text);padding:0 6px;min-width:58px;text-align:center}
.pbtn{
  min-width:30px;height:28px;padding:0 8px;border-radius:7px;cursor:pointer;
  background:var(--bg-soft);border:1px solid var(--border2);color:var(--text);
  font-size:12.5px;transition:.15s;
}
.pbtn:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
.pbtn:disabled{opacity:.35;cursor:default}

/* ===== 登录页「记住我」 ===== */
.login-remember{margin:2px 0 4px}
.login-remember .cbx-txt{font-size:12.5px;color:var(--muted)}
.login-remember input:checked ~ .cbx-txt{color:var(--accent)}

/* ===== 数据表浏览 ===== */
/* 数据表格：限高区域内双向滚动，表头与首列冻结，避免「看不完也滚不动」 */
.dbt-grid{
  max-height:min(58vh, 620px);min-height:220px;overflow:auto;
  border:1px solid var(--border);border-radius:10px;
}
.dbt-grid .tbl{border-collapse:separate;border-spacing:0}
.dbt-grid .tbl thead th{
  position:sticky;top:0;z-index:7;background:var(--sf-5);
  border-bottom:1px solid rgba(var(--ovl),.10);
  box-shadow:0 1px 0 var(--sh-soft);
}
.dbt-grid .tbl thead th:first-child{left:0;z-index:8}
.dbt-grid .tbl th.rowno,.dbt-grid .tbl td.rowno{
  position:sticky;left:0;z-index:2;
  width:52px;min-width:52px;text-align:right;
  background:var(--sf-5);color:var(--fg-dim);
  font-size:11.5px;font-variant-numeric:tabular-nums;
  border-right:1px solid rgba(var(--ovl),.06);
}
.dbt-grid .tbl td.rowno{background:var(--sf-solid-2)}
.dbt-grid .tbl tbody tr:hover td.rowno{background:rgba(var(--ar),var(--ag),var(--ab),.10);color:var(--accent)}
.dbt-grid .tbl tbody td{
  background:var(--sf-3);border-bottom:1px solid var(--border);
  white-space:nowrap;max-width:280px;overflow:hidden;text-overflow:ellipsis;
}
.dbt-grid .tbl tbody tr:nth-child(even) td{background:var(--sf-4)}
.dbt-grid .tbl tbody tr:hover td{background:rgba(var(--ar),var(--ag),var(--ab),.07);color:var(--text)}

.dbt-wrap{
  display:grid;grid-template-columns:290px 1fr;gap:16px;
  align-items:stretch;height:calc(100vh - 168px);min-height:420px;
}
/* 左右两栏各自内部滚动，页面整体不再被撑长 */
.dbt-side{display:flex;flex-direction:column;min-height:0;overflow:hidden}
.dbt-search{
  display:flex;align-items:center;gap:8px;margin-bottom:10px;
  padding:8px 12px;border-radius:10px;
  background:var(--sf-2);border:1px solid var(--border2);
}
.dbt-search svg{width:15px;height:15px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 15px}
.dbt-search input{
  flex:1;min-width:0;border:none;outline:none;background:none;
  color:var(--text);font-size:13px;font-family:inherit;
}
.dbt-search input::placeholder{color:var(--fg-dim)}
.dbt-list{
  flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;
  margin:0 -4px;padding:0 4px;
}
.dbt-item{
  display:flex;align-items:center;gap:10px;padding:9px 11px;margin-bottom:4px;
  border-radius:10px;cursor:pointer;border:1px solid transparent;transition:.16s;
}
.dbt-item:hover{background:rgba(var(--ovl),.055)}
.dbt-item.on{
  background:linear-gradient(90deg,rgba(var(--ar),var(--ag),var(--ab),.15),rgba(var(--ar),var(--ag),var(--ab),.03));
  border-color:rgba(var(--ar),var(--ag),var(--ab),.24);
}
.dbt-ico{width:26px;height:26px;flex:0 0 26px;border-radius:8px;
  display:flex;align-items:center;justify-content:center;
  background:var(--accent-dim);color:var(--accent)}
.dbt-ico svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.dbt-meta{flex:1;min-width:0}
.dbt-name{display:block;font-size:13px;font-weight:600;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dbt-item.on .dbt-name{color:var(--accent)}
.dbt-cmt{display:block;font-size:11px;color:var(--muted);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dbt-num{flex:0 0 auto;font-size:11.5px;color:var(--muted);
  background:rgba(var(--ovl),.06);border-radius:99px;padding:2px 8px;
  font-variant-numeric:tabular-nums}
.dbt-main{
  display:flex;flex-direction:column;gap:14px;min-width:0;min-height:0;
  overflow-y:auto;overflow-x:hidden;
}
/* 右侧面板不拉伸，内容自然排布后随 dbt-main 滚动 */
.dbt-main>.panel{flex:0 0 auto}
.dct-toggle{
  display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none;
  padding:9px 12px;border-radius:10px;margin-bottom:12px;
  background:rgba(var(--ovl),.035);border:1px solid var(--border);
  font-size:13px;color:var(--text2);transition:.18s;
}
.dct-toggle:hover{background:rgba(var(--ar),var(--ag),var(--ab),.07);border-color:rgba(var(--ar),var(--ag),var(--ab),.22);color:var(--accent)}
.dct-toggle svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.dct-arrow{margin-left:auto;display:flex;transition:transform .2s}
.dct{max-height:340px;overflow:auto;border:1px solid var(--border);border-radius:10px;margin-bottom:4px}
.dct .tbl th{position:sticky;top:0;z-index:1;background:var(--sf-5)}
.pk{display:inline-block;font-size:9.5px;font-weight:700;color:#04120E;background:var(--accent);
  border-radius:4px;padding:1px 4px;vertical-align:1px;letter-spacing:.5px}
.tbl td.null{color:var(--fg-dim);font-style:normal}
.tbl td.null i{opacity:.55;font-style:normal}
.pager{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:14px;flex-wrap:wrap}
.pager select{
  padding:5px 9px;border-radius:8px;font-size:12.5px;
  background:var(--sf-2);border:1px solid var(--border2);
  color:var(--text2);font-family:inherit;outline:none;cursor:pointer;
}
.pager select:focus{border-color:rgba(var(--ar),var(--ag),var(--ab),.5)}
.pager .btn-ghost{display:inline-flex;align-items:center;gap:4px}
.pager .btn-ghost svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.pager .btn-ghost[disabled]{opacity:.4;cursor:not-allowed}
.pager-info{font-size:12.5px;color:var(--muted);padding:0 6px;font-variant-numeric:tabular-nums}

@media (max-width:1000px){
  .dbt-wrap{grid-template-columns:1fr;height:auto;min-height:0}
  .dbt-side{max-height:300px}
  .dbt-list{max-height:220px}
  .dbt-main{overflow:visible}
}


/* 生成批次：次要入口链接 */
.gd-more{
  display:inline-block;margin-left:6px;cursor:pointer;
  color:rgb(var(--ar),var(--ag),var(--ab));text-decoration:underline;
  font-size:11.5px;opacity:.9;
}
.gd-more:hover{opacity:1;font-weight:600}

/* ================= 空状态 / 加载 ================= */
.empty{
  padding:34px 10px;text-align:center;color:var(--fg-dim);font-size:12.5px;
  display:flex;flex-direction:column;align-items:center;gap:10px;
}
.empty svg{width:30px;height:30px;stroke:#46525F;fill:none;stroke-width:1.4}
.hint code{
  display:inline-block;padding:1px 6px;border-radius:5px;
  background:var(--code-bg);border:1px solid var(--border2);
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11.5px;color:var(--accent);
}
.cbx input[type=number]{
  width:62px;padding:5px 8px;border-radius:8px;text-align:center;
  background:var(--sf-2);border:1px solid var(--border2);
  color:var(--text);font-size:13px;font-family:inherit;outline:none;
}
.cbx input[type=number]:focus{border-color:rgba(var(--ar),var(--ag),var(--ab),.5);box-shadow:var(--ring)}
.empty code{
  display:inline-block;margin-top:4px;padding:3px 8px;border-radius:6px;
  background:var(--code-bg);border:1px solid var(--border2);
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:11.5px;color:var(--accent);
}
.loading{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;
  padding:64px 20px;color:var(--muted);font-size:13px;
}
/* 加载动画：使用品牌 Logo（透明背景），呼吸 + 旋转光环 */
.logo-loading{
  position:relative;width:64px;height:64px;display:flex;align-items:center;justify-content:center;
}
.logo-loading img{width:44px;height:44px;animation:logoBreath 1.5s ease-in-out infinite}
.logo-loading::after{
  content:'';position:absolute;inset:0;border-radius:50%;
  border:2px solid transparent;border-top-color:var(--accent);border-right-color:rgba(var(--ar),var(--ag),var(--ab),.35);
  animation:spin .9s linear infinite;
}
.logo-loading.sm{width:22px;height:22px}
.logo-loading.sm img{width:15px;height:15px}
.logo-loading.sm::after{border-width:1.5px}
@keyframes logoBreath{
  0%,100%{transform:scale(1);opacity:.92}
  50%{transform:scale(1.1);opacity:1}
}
@keyframes spin{to{transform:rotate(360deg)}}
.spinner{
  display:inline-block;vertical-align:-3px;width:18px;height:18px;border-radius:50%;
  border:2px solid rgba(var(--ar),var(--ag),var(--ab),.2);border-top-color:var(--accent);
  animation:spin .7s linear infinite;
}

/* ================= 弹窗 ================= */
.modal-mask{
  position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;
  background:var(--mask);backdrop-filter:blur(6px);animation:fade .18s both;padding:24px;
}
.modal-card{
  width:min(560px,100%);max-height:86vh;overflow:auto;
  background:linear-gradient(180deg,var(--sf-pop),var(--sf-1));
  border:1px solid var(--border2);border-radius:20px;
  box-shadow:0 30px 70px var(--sh-strong),inset 0 1px 0 rgba(var(--ovl),.07);
  animation:pop .24s cubic-bezier(.2,.9,.3,1.15) both;
}
.modal-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:18px 22px 14px;border-bottom:1px solid var(--border);
}
.modal-title{font-size:15px;font-weight:700;display:flex;align-items:center;gap:8px}
.modal-title svg{width:17px;height:17px;stroke:var(--accent);fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.modal-close{
  width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;
  cursor:pointer;color:var(--muted);transition:.18s;
}
.modal-close svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}
.modal-close:hover{background:rgba(var(--ovl),.09);color:var(--text);transform:rotate(90deg)}
/* 弹窗内部独立滚动：字段多时不至于顶出屏幕导致按钮点不到 */
.modal-body{
  padding:18px 22px;display:flex;flex-direction:column;gap:16px;
  max-height:min(62vh,520px);overflow:auto;-webkit-overflow-scrolling:touch;
}
.modal-foot{
  display:flex;justify-content:flex-end;gap:10px;
  padding:14px 22px 18px;border-top:1px solid var(--border);
}
.mfield label{display:block;font-size:12.5px;color:var(--muted);margin-bottom:7px}
.mfield input,.mfield select,.mfield textarea{
  width:100%;padding:10px 12px;border-radius:10px;background:var(--sf-2);
  border:1px solid var(--border2);color:var(--text);font-size:13.5px;font-family:inherit;outline:none;transition:.2s;
}
.mfield input:focus,.mfield select:focus,.mfield textarea:focus{
  border-color:rgba(var(--ar),var(--ag),var(--ab),.5);background:var(--sf-2);box-shadow:var(--ring);
}
.mfield input[readonly]{color:var(--muted);background:var(--sf-2)}

/* ===== form-grid：弹窗里的「标签 + 输入框」两列紧凑表单 =====
   写法： <div class="form-grid">
            <label>出栏只数</label><input id="cCnt" type="number">
            <label>备注</label><input id="cRemark">
          </div>
   —— label 和 input 交替出现即可，不用再套 .mfield 包裹层。
   —— 两列布局：左列标签（宽度自适应文字），右列输入框（撑满剩余）。
   —— 想改成上下排（标签在上、输入框在下）：删掉下面第一条的
      grid-template-columns，改成 grid-template-columns:1fr 即可。
   —— 手机端自动降为单列（见文件末尾 [data-dev="phone"] 段）。 */
.form-grid{
  display:grid;
  grid-template-columns:max-content 1fr;
  gap:12px 14px;
  align-items:center;
}
.form-grid label{
  display:block;font-size:12.5px;color:var(--muted);white-space:nowrap;
}
.form-grid input,.form-grid select,.form-grid textarea{
  width:100%;padding:10px 12px;border-radius:10px;background:var(--sf-2);
  border:1px solid var(--border2);color:var(--text);font-size:13.5px;
  font-family:inherit;outline:none;transition:.2s;
}
.form-grid input:focus,.form-grid select:focus,.form-grid textarea:focus{
  border-color:rgba(var(--ar),var(--ag),var(--ab),.5);background:var(--sf-2);box-shadow:var(--ring);
}
.form-grid input[readonly]{color:var(--muted);background:var(--sf-2)}
/* 备注这类需要跨满整行的：加 class="full" */
.form-grid .full{grid-column:1 / -1}

.mrow{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.hint{font-size:11.5px;color:var(--muted);line-height:1.8}
/* ===== 「仅管理员可见」的说明块 =====
   用法：给任何只想让管理员看到的说明文字加 class="adm-note"（可以和 .hint 一起用）。
   非管理员登录后 body 上会有 data-notes="0"，这里直接隐藏，不用改 JS。
   想改成所有人可见：删掉下面这两行即可。
   想额外给某个账号看：改 config.py 的 NOTES_EXTRA_USERS（不用碰这里）。        */
body[data-notes="0"] .adm-note{display:none !important}

/* ================= 开关 ================= */
.switch{
  position:relative;width:38px;height:21px;border-radius:99px;background:rgba(var(--ovl),.12);
  cursor:pointer;transition:.24s;flex:0 0 38px;border:1px solid transparent;
}
.switch::after{
  content:'';position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;
  background:#8A97A8;transition:.24s;
}
.switch.on{background:linear-gradient(135deg,#00E5B0,#0FC9A4);box-shadow:0 0 14px rgba(var(--ar),var(--ag),var(--ab),.35)}
.switch.on::after{left:19px;background:#04120E}

/* ================= Toast ================= */
.toast{
  position:fixed;top:22px;left:50%;transform:translateX(-50%);z-index:300;
  display:flex;align-items:center;gap:9px;
  padding:11px 20px;border-radius:12px;font-size:13px;
  background:linear-gradient(135deg,var(--sf-pop),var(--sf-solid));
  border:1px solid var(--border2);
  box-shadow:0 16px 40px var(--sh-strong),inset 0 1px 0 rgba(var(--ovl),.08);
  color:var(--text);animation:slideDown .26s cubic-bezier(.2,.9,.3,1.2) both;
}
.toast-dot{display:flex;align-items:center;flex:0 0 16px;color:var(--accent)}
.toast-dot svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.toast.err .toast-dot{color:var(--red)}
.toast.warn{border-color:rgba(240,169,63,.35)}
.toast.warn .toast-dot{color:var(--orange)}

.hidden{display:none !important}

/* ================= 响应式：多端适配 ================= */
/* 通用：任何表格在窄屏都可横向滑动，避免内容被裁掉 */
.tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
@media (max-width:1180px){
  .kpi-row{grid-template-columns:repeat(2,1fr)}
  .grid{grid-template-columns:repeat(2,1fr)}
  .ops-grid{grid-template-columns:repeat(2,1fr)}
}

/* —— 矮屏 / iPad 横屏（可用高约 528~640）：登录页收成单栏，内容不再被压扁 —— */
@media (max-height:640px){
  .login-brand{display:none}
  .login-box{max-width:520px;min-height:0}
  .login-card{padding:26px 30px}
  .login-tip{margin-bottom:16px}
  .field{margin-bottom:13px}
  .login-btn{margin-top:2px}
  .theme-btn.login-theme{top:10px;right:10px;width:34px;height:34px}
}

/* —— 平板 / 小笔电 —— */
@media (max-width:900px){
  .login-brand{display:none}
  .login-box{max-width:460px}
  .content{padding:18px 16px 30px}
  .topbar{padding:13px 16px}
  .grid{grid-template-columns:1fr}
  /* 面板内表格横向滚动 */
  .panel{overflow:visible}
}

/* —— 手机 / 竖屏 —— */
@media (max-width:760px){
  .sidebar{
    position:fixed;left:0;top:0;bottom:0;width:72px;flex:0 0 72px;
    transition:width .22s ease,transform .22s ease;overflow:visible;z-index:40;
    background:var(--sf-1);
  }
  .sidebar:hover,.sidebar:focus-within{width:212px;flex:0 0 212px}
  .brand,.menu-item{overflow:hidden;white-space:nowrap}
  .brand-text,.menu-name,.menu-child,.sidebar-foot .role-tag{display:none}
  .menu-item{justify-content:flex-start;padding:12px 12px}
  .sidebar:hover .brand-text,.sidebar:hover .menu-name,
  .sidebar:hover .menu-child,.sidebar:hover .sidebar-foot .role-tag{display:block}
  .sidebar:hover .sidebar-foot .role-tag{display:inline-flex}
  .menu-item.on::before{left:-12px}
  /* 侧栏占 72px，主区留出空间 */
  .main{margin-left:72px}
  .topbar{padding:11px 14px}
  .page-title{font-size:16px}
  .page-sub{font-size:11.5px}
  .userbox{gap:8px}
  .userbox .clock{display:none}
  .u-avatar{width:32px;height:32px;font-size:13px}
  .u-name{font-size:12px}
  .u-role{display:none}
  .content{padding:16px 14px 28px;gap:14px}
  .panel{padding:14px 14px 16px}
  /* 表格：允许横向滑动，表头不再强制吸顶以免遮挡 */
  .tbl{min-width:max-content}
  .panel{overflow-x:auto}
  /* 触控友好：按钮最小高度 */
  .btn-primary,.btn-ghost{min-height:32px}
  .btn-sm{min-height:30px}
  .filter{gap:8px}
  .filter input,.filter select{min-height:34px}
  .pager{gap:6px}
  .pbtn{min-width:34px;height:32px}
  /* 弹窗：窄屏铺满并内部滚动 */
  .modal-card{width:94vw;max-width:94vw}
  .modal-body{max-height:56vh;overflow:auto;-webkit-overflow-scrolling:touch}
  .rf-grid{grid-template-columns:1fr}
  .mfield input,.mfield select{min-height:36px}
}

@media (max-width:620px){
  .kpi-row{grid-template-columns:1fr}
  .mrow{grid-template-columns:1fr}
  .userbox .clock{display:none}
  .kpi{padding:14px 15px}
  .kpi-value{font-size:24px}
  /* 数据表两栏在小屏改为上下堆叠 */
  .dbt-wrap{grid-template-columns:1fr;height:auto;min-height:0}
  .dbt-side{max-height:260px}
  .dbt-list{max-height:190px}
  .dbt-main{overflow:visible}
  /* 操作列在窄屏收窄，避免挤压内容 */
  .dbt-grid .tbl th.opcol,.dbt-grid .tbl td.opcol{width:84px;min-width:84px}
}

/* 待办：是否含未来事项 的勾选与口径标签 */
.td-chk{
  display:inline-flex;align-items:center;gap:5px;cursor:pointer;
  font-size:11.5px;color:var(--muted);user-select:none;
}
.td-chk input{width:14px;height:14px;cursor:pointer;accent-color:rgb(var(--ar),var(--ag),var(--ab))}
.tag-mini{
  display:inline-block;margin-left:6px;padding:1px 7px;border-radius:8px;
  font-size:10.5px;line-height:1.6;color:var(--muted);
  background:rgba(var(--ovl),.07);border:1px solid var(--border);
}

/* 卡片头部里的分隔符（多列合并成标题时用） */
.mcard-sep{color:var(--muted);opacity:.55;margin:0 3px;font-weight:400}
/* iPhone 安全区：底部留白，避免被 home 横条挡住 */
[data-dev="phone"] .content{padding-bottom:calc(26px + env(safe-area-inset-bottom))}
[data-dev="phone"] .sidebar{padding-top:env(safe-area-inset-top)}
[data-dev="phone"] .topbar{padding-top:calc(10px + env(safe-area-inset-top))}

/* —— 横屏手机 / 矮屏 —— */
@media (max-height:520px){
  .content{padding:14px 16px 24px}
  .kpi{padding:12px 14px}
  .kpi-value{font-size:22px}
  .dbt-grid{max-height:46vh}
}

/* —— 触屏设备：加大可点区域 —— */
@media (hover:none){
  .btn-ghost,.btn-primary,.pbtn{min-height:34px}
  .menu-item{min-height:42px}
  .dbt-grid .tbl td.opcol .btn-ghost{padding:5px 11px}
}

/* 减少动画（部分用户系统设置） */
@media (prefers-reduced-motion:reduce){
  .content>*{animation:none}
  *{transition:none !important}
}

/* ===== 角色配色弹窗 ===== */
.rc-list{display:flex;flex-direction:column;gap:9px;margin-top:4px;max-height:340px;overflow-y:auto}
.rc-item{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:10px;
  background:rgba(var(--ovl),.04);border:1px solid var(--border2)}
.rc-dot{width:13px;height:13px;border-radius:50%;flex:0 0 13px;
  box-shadow:0 0 0 3px rgba(var(--ovl),.08)}
.rc-name{flex:1;font-size:13px;font-weight:600;color:var(--text)}
.rc-wrap{display:flex;align-items:center;gap:8px}
.rc-wrap input[type=color]{width:38px;height:30px;padding:2px;border-radius:7px;cursor:pointer;
  background:var(--sf-2);border:1px solid var(--border2)}
.rc-hex{font-family:var(--mono);font-size:11.5px;color:var(--muted);min-width:62px}

/* ===== 角色标签配色 =====
   颜色取自 sys_role.color，作为标签「主色」：
   文字 = 主色；底色 = 主色 14% 透明；边框 = 主色 38% 透明；圆点 = 主色。
   浅色模式下整体 brightness(.6) 加深，避免亮色在白底上看不清。 */
.role-tag{
  color:var(--rc);
  background:color-mix(in srgb, var(--rc) 14%, transparent);
  border:1px solid color-mix(in srgb, var(--rc) 38%, transparent);
}
.role-tag .dot{background:var(--rc)}
[data-mode="light"] .role-tag{filter:brightness(.6) saturate(1.05)}
/* 兼容不支持 color-mix 的旧浏览器：退回半透明叠加 */
@supports not (background: color-mix(in srgb, red 10%, transparent)){
  .role-tag{background:rgba(var(--ovl),.06);border:1px solid var(--border2)}
}

/* ===== 角色标签配色：预设色板 ===== */
.rc-palette{display:flex;flex-wrap:wrap;gap:7px;margin-top:9px}
.rc-sw{
  width:26px;height:26px;flex:0 0 26px;border-radius:7px;cursor:pointer;
  border:1.5px solid rgba(var(--ovl),.28);padding:0;
  transition:transform .12s, box-shadow .12s;
}
.rc-sw:hover{transform:scale(1.12);box-shadow:0 0 0 3px rgba(var(--ovl),.14)}
/* 当前选中的色块：描边+外圈，点下去要看得出来 */
.rc-sw.sel{
  border-color:#fff;transform:scale(1.08);
  box-shadow:0 0 0 3px rgba(var(--ovl),.30), 0 0 0 1px rgba(0,0,0,.35) inset;
}
.rc-list .rc-palette{margin:0 0 12px 0}

/* ===== 数据来源 / 计算方式 说明块 ===== */
.meta-box{
  background:var(--sf-1);border:1px solid var(--border);border-radius:12px;
  margin-bottom:14px;overflow:hidden;
}
.meta-box>summary{
  cursor:pointer;padding:11px 16px;list-style:none;
  display:flex;align-items:center;gap:8px;
  font-size:13px;color:var(--text);font-weight:500;
}
.meta-box>summary::-webkit-details-marker{display:none}
.meta-box>summary:hover{background:rgba(var(--ovl),.04)}
.meta-box>summary::before{
  content:'▸';color:var(--accent);font-size:11px;transition:transform .15s;
}
.meta-box[open]>summary::before{transform:rotate(90deg)}
.mt-toggle{margin-left:auto;font-size:11px;color:var(--muted)}
.mt-body{padding:0 16px 14px}
.mt-tbl{width:100%;border-collapse:collapse;font-size:12px}
.mt-tbl td{padding:7px 10px;border-top:1px solid var(--border);vertical-align:top}
.mt-k{width:150px;color:var(--text);font-weight:600;white-space:nowrap}
.mt-v{color:var(--muted);line-height:1.75}
.mt-v b{color:var(--accent);font-weight:600}
.mt-scope{margin-top:9px;padding:8px 11px;border-radius:8px;
  background:rgba(var(--ar),var(--ag),var(--ab),.08);
  color:var(--muted);font-size:11.5px;line-height:1.7}
@media (max-width:760px){
  .mt-k{width:auto;white-space:normal;display:block;padding-bottom:2px}
  .mt-tbl td{display:block;border-top:none;padding:4px 0}
  .mt-tbl tr{border-top:1px solid var(--border);padding:7px 0;display:block}
}

/* ===== 角色权限编辑 ===== */
.rp-tree{margin-top:4px}
.rp-tree .perm-tree{max-height:none;padding:12px 14px}
.rp-tree .perm-actions{margin-top:12px}

/* ===== 系统维护：每个按钮的详细说明 ===== */
.ops-detail{margin-top:10px}
/* 「全部展开 / 全部收起」那一小行 */
.ops-doc-bar{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap}
.ops-doc{
  margin:8px 0 0;padding:9px 12px;border-radius:8px;
  background:rgba(var(--ovl),.045);border:1px solid var(--border);
}
/* 默认收起：<details> 不带 open 即收起，点标题栏展开。
   用 list-style:none + 自定义箭头，避免浏览器默认三角和 flex 布局打架。 */
.ops-doc > summary.ops-doc-h{
  display:flex;align-items:center;gap:9px;margin-bottom:0;
  cursor:pointer;user-select:none;list-style:none;
}
.ops-doc > summary.ops-doc-h::-webkit-details-marker{display:none}
.ops-doc > summary.ops-doc-h::marker{content:''}
.ops-doc[open] > summary.ops-doc-h{margin-bottom:6px}
.ops-toggle{margin-left:auto;font-weight:400;font-size:11px;color:var(--muted);opacity:.8}
.ops-toggle::before{content:'▸ '}
.ops-doc[open] .ops-toggle{color:var(--accent-ink)}
.ops-doc[open] .ops-toggle::before{content:'▾ '}
.ops-doc-h b{color:var(--text);font-size:12.5px}
.ops-tag{
  padding:1px 7px;border-radius:5px;font-size:10.5px;font-weight:600;
}
.ops-tag.ok{background:rgba(16,185,129,.16);color:var(--green)}
.ops-tag.warn{background:rgba(245,158,11,.16);color:var(--orange)}
.ops-tag.danger{background:rgba(239,68,68,.16);color:var(--red)}
.ops-doc-p{margin:3px 0;line-height:1.8;font-size:11.8px;color:var(--muted)}
.ops-doc-p .mt-lb{min-width:52px;text-align:center}

/* ===== 看板：模板变化→结果 对照表 ===== */
.kb-rule{
  width:100%;margin:7px 0 9px;border-collapse:collapse;font-size:11.5px;
}
.kb-rule th,.kb-rule td{
  border:1px solid var(--border);padding:5px 8px;text-align:left;
  line-height:1.7;vertical-align:top;
}
.kb-rule th{background:rgba(var(--ovl),.07);color:var(--text);font-weight:600}
.kb-rule td:last-child{white-space:nowrap;text-align:center}
.ops-copy{
  cursor:pointer;display:inline-block;
  border-bottom:1px dashed var(--accent);
}
.ops-copy:hover{background:rgba(var(--ovl),.09);border-radius:3px}


/* ==================================================================
   移动端 / 平板自适应
   —— 同一个网址，按设备自动切换布局，不需要单独的手机站 ——
   设备类型由 JS 写在 <html data-dev="phone|pad|pc"> 上：
     phone 手机（含竖屏平板小尺寸）
     pad   平板（横竖屏 iPad / 安卓平板）
     pc    电脑
   核心思路：PC 用表格看"全"，手机用卡片看"准"——
   手机屏幕塞不下十几列的宽表，硬缩只会挤成一团，
   所以手机上把表格自动转成卡片，一列一行，看得完整。
   ================================================================== */

/* —— 汉堡按钮 / 返回按钮 / 关闭按钮：仅手机平板显示 —— */
.nav-burger,.nav-close,.nav-back{display:none}
/* 返回首页：手机/平板顶部左侧，点击回到首页（不是退出登录） */
.nav-back{
  flex:0 0 auto;display:none;align-items:center;gap:2px;
  height:38px;padding:0 10px 0 6px;border-radius:9px;
  background:transparent;border:1px solid var(--border);color:var(--text);
  cursor:pointer;font-size:13px;line-height:1;
}
.nav-back svg{
  width:18px;height:18px;stroke:currentColor;fill:none;
  stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;
}
.nav-back span{font-size:12.5px}
.nav-back:active{background:rgba(var(--ovl),.1)}
.nav-burger{
  flex:0 0 auto;width:38px;height:38px;padding:8px;border-radius:9px;
  background:transparent;border:1px solid var(--border);color:var(--text);
  cursor:pointer;align-items:center;justify-content:center;
}
.nav-burger svg,.nav-close svg{
  width:19px;height:19px;stroke:currentColor;fill:none;
  stroke-width:2;stroke-linecap:round;
}
.nav-burger:active{background:rgba(var(--ovl),.1)}
.nav-close{
  position:absolute;right:10px;top:12px;width:34px;height:34px;padding:7px;
  border-radius:8px;background:rgba(var(--ovl),.07);
  border:1px solid var(--border);color:var(--text);cursor:pointer;
}
.nav-mask{
  display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);
  z-index:45;animation:mfade .18s ease;
}
@keyframes mfade{from{opacity:0}to{opacity:1}}

/* —— 表格转卡片（手机/平板由 JS 生成 .mcards）—— */
.mcards{display:flex;flex-direction:column;gap:10px}
.mcard{
  border:1px solid var(--border);border-radius:11px;padding:11px 13px;
  background:var(--sf-1);
}
.mcard-t{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding-bottom:8px;margin-bottom:8px;border-bottom:1px dashed var(--border);
}
.mcard-t b{font-size:13.5px;color:var(--text);font-weight:600}
.mcard-r{
  display:flex;align-items:flex-start;justify-content:space-between;
  gap:12px;padding:4px 0;font-size:12.5px;line-height:1.6;
}
.mcard-k{color:var(--muted);flex:0 0 auto;min-width:74px;font-size:11.5px}
.mcard-v{
  text-align:right;color:var(--text);word-break:break-all;
  flex:1 1 auto;min-width:0;
}
.mcard-v.is-empty{color:var(--muted);opacity:.65}
/* 卡片里的操作按钮靠右排 */
.mcard-v .btn-ghost,.mcard-v .btn-primary{margin:2px 0 2px 5px}
/* 表格被转成卡片后隐藏原表 */
.tbl-mhidden{display:none !important}
/* 卡片在 PC 上永不出现 */
[data-dev="pc"] .mcards{display:none !important}

/* ================= 平板 pad =================
   说明：早期版本平板侧栏被压成 76px 的「纯图标条」，图标上下分散、
   和抽屉里的图标对不上，中间留一大片空白。现在改成 168px 的窄栏：
   图标 + 文字紧挨着排（和手机抽屉里的观感一致），不再有空档。
   想调宽度：只改文件顶部 --pad-sidebar-w 一处（sidebar / main 的 margin-left 都跟着变，
   下面三处已全部改用变量，不要再手改 168px 这种数字，否则会两边不一致）。
   想退回纯图标条：把 --pad-sidebar-w 改回 76px，并把 .menu-name 那段改回 display:none。 */
/* position:relative + transform:none 是为了压掉 @media(max-width:760px) 里
   「sidebar 变 position:fixed」的规则 —— 窄一点的平板（如 iPad mini 竖屏 744px）
   会命中那个断点，一旦侧栏 fixed 而 main 的 margin-left 又是 0，主内容就会被
   压到侧栏底下重叠。平板一律用 flex 常驻侧栏。 */
[data-dev="pad"] .sidebar{position:relative;transform:none;left:auto;width:var(--pad-sidebar-w);flex:0 0 var(--pad-sidebar-w)}
/* 同上：把 @media(max-width:760px) 里被隐藏的侧栏文字恢复出来，
   否则窄平板的品牌名和菜单文字会莫名消失。 */
[data-dev="pad"] .brand-text,[data-dev="pad"] .menu-name,[data-dev="pad"] .menu-child{display:block}
[data-dev="pad"] .sidebar:hover,[data-dev="pad"] .sidebar:focus-within{width:var(--pad-sidebar-w);flex:0 0 var(--pad-sidebar-w)}
[data-dev="pad"] .brand{justify-content:flex-start;gap:9px;padding:14px 12px 12px}
[data-dev="pad"] .brand-logo{width:30px;height:30px;flex:0 0 30px}
[data-dev="pad"] .brand-name{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
[data-dev="pad"] .brand-sub,[data-dev="pad"] .brand-text .sub{display:none}
[data-dev="pad"] .menu{padding:4px 8px 10px}
/* 图标 + 文字都显示且紧挨着（gap 10px，与手机端一致） */
/* 文字不撑满（flex:1 会把展开箭头顶到最右，中间留出一大片空白），
   箭头紧跟文字；想恢复「箭头靠最右」把下面这行改成 flex:1 */
[data-dev="pad"] .menu-name{display:block;flex:0 1 auto;min-width:0}
/* ★ 子菜单必须竖排（column）。
   之前只写了 display:flex 没写方向 → 默认 row（横排），子菜单项被挤成一排，
   而每个子项里的 .menu-name{flex:1} 在横向容器里会把文字撑开，
   于是「图标」和「文字」之间被拉开大片空白 —— 看着不像手机端那样紧挨着。
   竖排后每个子项各占一行，宽度撑满，图标和文字间距回到 10px（.menu-item 的 gap）。 */
[data-dev="pad"] .menu-child{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:1px;
}
/* 竖排后子项宽度撑满，长文字（如「成本盈亏」「栋舍对比」）不换行、超出省略，
   避免在窄侧栏里把行高顶开。 */
[data-dev="pad"] .menu-child .menu-item{min-width:0;overflow:hidden}
[data-dev="pad"] .menu-child .menu-name{
  flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
/* ★★ 关键修复（空白竖栏的真凶）★★
   .app 是 display:flex，.sidebar 本身就是「在流内」的 flex 子项，
   已经实打实占掉了 --pad-sidebar-w 的宽度；.main 又是 flex:1，
   本来就该紧跟在 sidebar 右边。
   但这里以前还写了 margin-left:var(--pad-sidebar-w) —— 那是「sidebar 为
   position:fixed 脱离文档流」时代的写法（见 @media(max-width:760px) 段）。
   后来改成 flex 布局，这行忘了删，于是 main 又被往右推了一整个侧栏宽度，
   在 sidebar 和 main 之间凭空多出一条等宽的空白（就是那条浅色竖栏）。
   → 修法：flex 布局下 main 的 margin-left 必须是 0，不要再加回来。
   判据：如果你看到侧栏右边有一条和侧栏一样宽的空白，就是这行没删。 */
[data-dev="pad"] .main{margin-left:0}
[data-dev="pad"] .menu-item{justify-content:flex-start;padding:9px 10px;gap:var(--pad-menu-gap);font-size:13px;margin:1px 0}
[data-dev="pad"] .menu-child{padding:2px 0 3px var(--pad-menu-indent)}
[data-dev="pad"] .menu-item.on::before{left:-8px}
/* 侧栏常驻可见 → 不需要汉堡和遮罩 */
[data-dev="pad"] .nav-burger{display:none}
[data-dev="pad"] .nav-back{display:flex}
[data-dev="pad"] .nav-close{display:none}
[data-dev="pad"] .nav-mask{display:none !important}
[data-dev="pad"] .kpi-row{grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px}
[data-dev="pad"] .content{padding:18px 18px 30px}
/* 平板：宽表允许横向滑动，但不转卡片（屏幕够宽） */
[data-dev="pad"] .panel{overflow-x:auto}
[data-dev="pad"] .tbl{min-width:max-content}
[data-dev="pad"] .modal-card{width:88vw;max-width:88vw}
[data-dev="pad"] .nav-mask.show{display:block}

/* ================= 平板：横屏 / 竖屏分开调 =================
   背景：iPad 横屏（1024×768）和竖屏（768×1024）宽度差 256px，
   之前两者共用一套布局，结果横屏太空、竖屏太挤。
   现在由 JS 在 <html> 上写 data-orient="land"（横屏）/ "port"（竖屏），
   下面两组规则分别生效。

   常见尺寸参考：
     iPad 10.9"  横屏 1180×820   竖屏  820×1180
     iPad Air    横屏 1180×820   竖屏  820×1180
     iPad 9.7"   横屏 1024×768   竖屏  768×1024
     iPad mini   横屏 1133×744   竖屏  744×1133

   想调 KPI 卡片列数：改 .kpi-row 的 repeat(N,1fr)，N 就是列数。
   想调侧栏宽度：只改 sidebar 的 width（横屏/竖屏三处都已用 --pad-sidebar-w 变量）。
   ⚠ main 的 margin-left 保持 0，不要跟着改 —— .app 是 flex 布局，
     sidebar 已经占好位了，再加 margin-left 会多空出一整条侧栏宽的空白（见 pad 段 ★★）。
   ============================================================ */

/* ---- 平板横屏：宽度够，KPI 排 4 列（和电脑一致），侧栏略放宽 ---- */
/* 横屏比竖屏宽 8px，用 calc 跟着 --pad-sidebar-w 走，改变量时横竖屏一起变 */
[data-dev="pad"][data-orient="land"] .sidebar{width:calc(var(--pad-sidebar-w) + 8px);flex:0 0 calc(var(--pad-sidebar-w) + 8px)}
/* 同上：flex 布局下 margin-left 必须为 0（见 pad 段 ★★ 说明） */
[data-dev="pad"][data-orient="land"] .main{margin-left:0}
[data-dev="pad"][data-orient="land"] .kpi-row{grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px}
[data-dev="pad"][data-orient="land"] .content{padding:20px 22px 34px}
[data-dev="pad"][data-orient="land"] .menu-item{padding:10px 11px;font-size:13.5px}
[data-dev="pad"][data-orient="land"] .modal-card{width:76vw;max-width:76vw}

/* ---- 平板竖屏：宽度紧，KPI 排 2 列，侧栏收窄给内容腾地方 ---- */
/* 竖屏用变量减 20px，改 --pad-sidebar-w 时横竖屏一起变（不要再写死 148px） */
[data-dev="pad"][data-orient="port"] .sidebar{width:calc(var(--pad-sidebar-w) - 20px);flex:0 0 calc(var(--pad-sidebar-w) - 20px)}
/* 同上：flex 布局下 margin-left 必须为 0（见 pad 段 ★★ 说明） */
[data-dev="pad"][data-orient="port"] .main{margin-left:0}
[data-dev="pad"][data-orient="port"] .kpi-row{grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:11px}
[data-dev="pad"][data-orient="port"] .content{padding:16px 14px 28px}
[data-dev="pad"][data-orient="port"] .menu-item{padding:8px 9px;font-size:12.5px;gap:8px}
[data-dev="pad"][data-orient="port"] .menu-child{padding:2px 0 3px 20px}
[data-dev="pad"][data-orient="port"] .brand{padding:12px 10px 10px}
[data-dev="pad"][data-orient="port"] .modal-card{width:92vw;max-width:92vw}
/* 竖屏宽度紧，表格允许压缩：单元格内边距收窄，一屏多看几行 */
[data-dev="pad"][data-orient="port"] .tbl th{padding:8px 9px;font-size:11.5px}
[data-dev="pad"][data-orient="port"] .tbl td{padding:8px 9px;font-size:12px}

/* ---- 系统设置 → 界面与设备 信息卡 ---- */
.dev-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-top:12px}
.dev-i{background:rgba(var(--ovl),.045);border:1px solid var(--border);border-radius:10px;padding:10px 12px}
.dev-i span{display:block;font-size:11.5px;color:var(--muted);margin-bottom:4px}
.dev-i b{font-size:14px;font-weight:700;color:var(--accent)}
.dev-row{display:flex;align-items:center;gap:10px;margin-top:12px;flex-wrap:wrap}
.dev-row label{font-size:12.5px;color:var(--muted)}
.dev-row .inp{min-width:150px;min-height:36px;font-size:13px}

/* ================= 手机 phone ================= */
[data-dev="phone"] .sidebar{
  position:fixed;left:0;top:0;bottom:0;width:232px;flex:0 0 232px;
  transform:translateX(-100%);z-index:50;
  box-shadow:6px 0 26px rgba(0,0,0,.3);
  transition:transform .22s ease;
}
[data-dev="phone"] .sidebar.open{transform:translateX(0)}
[data-dev="phone"] .main{margin-left:0}
[data-dev="phone"] .nav-burger{display:flex}
[data-dev="phone"] .nav-back{display:flex}
[data-dev="phone"] .nav-close{display:flex}
[data-dev="phone"] .nav-mask.show{display:block}
[data-dev="phone"] .brand-text,[data-dev="phone"] .menu-name,
[data-dev="phone"] .menu-child{display:block}
[data-dev="phone"] .menu-item{justify-content:flex-start;padding:11px 14px}
/* 顶栏精简：时钟和角色在手机上藏起来，给标题腾地方 */
[data-dev="phone"] .userbox .clock{display:none}
[data-dev="phone"] .u-role{display:none}
[data-dev="phone"] .topbar{padding:10px 12px;gap:7px}
/* 手机上「返回」只留箭头，省出横向空间给标题 */
[data-dev="phone"] .nav-back{padding:0 8px;height:36px}
[data-dev="phone"] .nav-back span{display:none}
[data-dev="phone"] .page-title{font-size:15.5px}
[data-dev="phone"] .page-sub{font-size:11px}
[data-dev="phone"] .content{padding:13px 12px 26px;gap:13px}
[data-dev="phone"] .panel{padding:13px 12px 15px;overflow:visible}
/* KPI 两列：手机上单列太占屏，两列刚刚好 */
[data-dev="phone"] .kpi-row{grid-template-columns:repeat(2,1fr);gap:10px}
[data-dev="phone"] .kpi{padding:12px 13px}
[data-dev="phone"] .kpi-value{font-size:21px}
[data-dev="phone"] .kpi-label{font-size:11px}
/* 筛选栏：换行排布，避免挤在一行 */
[data-dev="phone"] .filter{flex-wrap:wrap;gap:8px}
[data-dev="phone"] .filter label{font-size:11.5px}
[data-dev="phone"] .filter input,[data-dev="phone"] .filter select{
  min-height:36px;font-size:13px;
}
/* 触控友好：所有可点区域不低于 38px */
[data-dev="phone"] .btn-primary,[data-dev="phone"] .btn-ghost{min-height:38px}
[data-dev="phone"] .btn-sm{min-height:34px}
[data-dev="phone"] .pbtn{min-width:38px;height:36px}
[data-dev="phone"] .menu-item{min-height:44px}
/* 弹窗铺满，内部滚动 */
[data-dev="phone"] .modal-card{width:96vw;max-width:96vw;max-height:88vh}
[data-dev="phone"] .modal-body{max-height:60vh;overflow:auto;-webkit-overflow-scrolling:touch}
[data-dev="phone"] .mfield input,[data-dev="phone"] .mfield select{
  min-height:40px;font-size:14px;
}
/* 说明块：手机上默认折叠得更紧凑 */
[data-dev="phone"] .mt-chain{font-size:11.5px;line-height:1.75}
[data-dev="phone"] .kb-rule{font-size:11px}
[data-dev="phone"] .ops-doc{padding:8px 10px}
[data-dev="phone"] .ops-doc-p{font-size:11.5px;line-height:1.7}
/* 日期选择器：手机上加大格子，手指好点 */
[data-dev="phone"] .dp-grid{gap:3px}
[data-dev="phone"] .dp-cell{min-height:36px;font-size:13px}
/* 手机端卡片的操作行：按钮横向铺开更好按 */
[data-dev="phone"] .mcard-v .btn-ghost,[data-dev="phone"] .mcard-v .btn-primary{
  min-height:34px;padding:6px 13px;
}

/* —— 横屏手机 / 矮屏 —— */
@media (max-height:520px) and (orientation:landscape){
  [data-dev="phone"] .content{padding:11px 12px 20px}
  [data-dev="phone"] .modal-body{max-height:46vh}
  [data-dev="phone"] .kpi{padding:10px 12px}
  [data-dev="phone"] .kpi-value{font-size:19px}
}

/* ==================================================================
   手机 / 平板：视图模式（紧凑表格 ⇄ 卡片）
   ------------------------------------------------------------------
   为什么改：之前手机端一律把表格转成卡片，一条数据一整张卡、
   十几个字段竖排，一屏只放得下 1~2 条，50 条要翻二十几屏。
   现在默认：手机 = 紧凑表格（行高压到最小 + 冻结前两列 + 左右滑看
   其余列），一屏能看 20 多行，扫一眼就找到要找的批次。
   想逐条细看 → 点顶栏视图按钮切「卡片」；卡片本身也压成两列网格，
   高度只剩原来的三分之一。
   偏好记在浏览器本地（localStorage），换页面、下次打开都保持。
   ================================================================== */

/* —— 视图切换按钮：手机 / 平板显示在顶栏左侧 —— */
.nav-view{
  flex:0 0 auto;display:none;align-items:center;justify-content:center;
  width:38px;height:38px;padding:8px;border-radius:9px;
  background:transparent;border:1px solid var(--border);color:var(--text);cursor:pointer;
}
.nav-view svg{
  width:18px;height:18px;stroke:currentColor;fill:none;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
}
.nav-view:active{background:rgba(var(--ovl),.1)}
[data-dev="phone"] .nav-view,[data-dev="pad"] .nav-view{display:flex}

/* —— 手机：紧凑表格（默认）—— */
[data-dev="phone"][data-view="table"] .panel{
  padding:10px 10px 12px;overflow-x:auto;-webkit-overflow-scrolling:touch;
}
[data-dev="phone"][data-view="table"] .tbl{min-width:max-content;font-size:11.5px}
[data-dev="phone"][data-view="table"] .tbl th{padding:5px 8px;font-size:10.5px;letter-spacing:0}
[data-dev="phone"][data-view="table"] .tbl td{
  padding:4px 8px;font-size:11.5px;line-height:1.4;white-space:nowrap;
}
/* 冻结前两列（批次 / 栋舍）：滑到最右边也知道在看哪一批。
   注意：冻结列背景必须完全不透明，否则底下滚动的行会透上来 ——
   所以用 --sf-solid（实底）而不是半透明的 --sf-1。 */
[data-dev="phone"][data-view="table"] .tbl th:nth-child(-n+2),
[data-dev="phone"][data-view="table"] .tbl td:nth-child(-n+2){
  position:sticky;z-index:3;background-color:var(--sf-solid);
}
[data-dev="phone"][data-view="table"] .tbl th:nth-child(1),
[data-dev="phone"][data-view="table"] .tbl td:nth-child(1){left:0;min-width:44px}
[data-dev="phone"][data-view="table"] .tbl th:nth-child(2),
[data-dev="phone"][data-view="table"] .tbl td:nth-child(2){
  left:44px;min-width:48px;box-shadow:2px 0 6px rgba(0,0,0,.16);
}
/* 隔行变色：冻结列也要跟着变，不然一列深一列浅很突兀 */
[data-dev="phone"][data-view="table"] .tbl tbody tr:nth-child(even) td:nth-child(-n+2){
  background-color:var(--sf-solid-2);
}
/* 悬停：叠加一层主色（用 background-image 叠，不会把实底盖掉）*/
[data-dev="phone"][data-view="table"] .tbl tbody tr:hover td:nth-child(-n+2){
  background-image:linear-gradient(
    rgba(var(--ar),var(--ag),var(--ab),.055),rgba(var(--ar),var(--ag),var(--ab),.055));
}
/* 状态标签 / 达成率：手机上缩小，行高才压得住 */
[data-dev="phone"] .tbl .tag{padding:2px 7px;font-size:10px;gap:4px}
[data-dev="phone"] .tbl .tag .dot{width:5px;height:5px}
[data-dev="phone"] .tbl .tag-mini{margin-left:4px;padding:0 5px;font-size:9.5px}

/* —— 手机：卡片视图（顶栏按钮切换）—— 压成两列网格 —— */
[data-dev="phone"][data-view="card"] .mcard{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px 12px;padding:9px 11px;
}
[data-dev="phone"][data-view="card"] .mcard-t{grid-column:1/-1;padding-bottom:6px;margin-bottom:5px}
[data-dev="phone"][data-view="card"] .mcard-t b{font-size:13px}
[data-dev="phone"][data-view="card"] .mcard-r{
  display:flex;flex-direction:column;align-items:stretch;gap:0;padding:2px 0;border:0;
}
[data-dev="phone"][data-view="card"] .mcard-k{min-width:0;font-size:10.5px;line-height:1.4}
[data-dev="phone"][data-view="card"] .mcard-v{text-align:left;font-size:12.5px;line-height:1.45}
/* 手机屏幕窄，弹窗表单降为单列：标签在上、输入框在下，
   输入框加大到 40px 方便手指点按。
   想让手机也保持左右两列：把 grid-template-columns 改成 max-content 1fr。 */
[data-dev="phone"] .form-grid{
  grid-template-columns:1fr;
  gap:5px;
}
[data-dev="phone"] .form-grid label{margin-top:6px}
[data-dev="phone"] .form-grid input,
[data-dev="phone"] .form-grid select,
[data-dev="phone"] .form-grid textarea{min-height:40px;font-size:16px}

/* —— 平板：表格行高也压一点，一屏多看几行 —— */
[data-dev="pad"] .tbl th{padding:6px 9px;font-size:11px;letter-spacing:.2px}
[data-dev="pad"] .tbl td{padding:6px 9px;font-size:12px;line-height:1.45}
[data-dev="pad"] .tbl .tag{padding:3px 8px;font-size:10.5px;gap:5px}
[data-dev="pad"] .tbl .tag .dot{width:5px;height:5px}
/* 平板切卡片视图时压成三列（屏幕比手机宽） */
[data-dev="pad"][data-view="card"] .mcard{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1px 14px;
}
[data-dev="pad"][data-view="card"] .mcard-t{grid-column:1/-1}
[data-dev="pad"][data-view="card"] .mcard-r{
  display:flex;flex-direction:column;align-items:stretch;gap:0;padding:2px 0;border:0;
}
[data-dev="pad"][data-view="card"] .mcard-k{min-width:0;font-size:11px}
[data-dev="pad"][data-view="card"] .mcard-v{text-align:left;font-size:12.5px}

/* ===== 登录页构建标识（确认浏览器加载的是哪一版） ===== */
.login-build{
  margin-top:12px;text-align:center;font-size:10.5px;color:var(--muted);
  opacity:.65;letter-spacing:.4px;font-variant-numeric:tabular-nums;
}
.login-build span{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}

/* ===== 说明块：一眼看懂（大白话 / 举例 / 折叠的修改指引）===== */
.mt-lb{
  display:inline-block;margin-right:6px;padding:1px 7px;border-radius:5px;
  font-size:11px;font-weight:600;white-space:nowrap;vertical-align:1px;
  background:rgba(var(--ar),var(--ag),var(--ab),.13);
  color:var(--accent);
}
.mt-row{margin:3px 0;line-height:1.85}
/* ① 大白话：最醒目，看不懂技术也能明白这格是啥 */
.mt-plain{
  display:flex;gap:7px;align-items:flex-start;
  margin:0 0 7px;padding:8px 11px;border-radius:8px;
  background:linear-gradient(90deg,rgba(var(--ar),var(--ag),var(--ab),.14),rgba(var(--ar),var(--ag),var(--ab),.03));
  border-left:3px solid rgba(var(--ar),var(--ag),var(--ab),.55);
  color:var(--text);font-size:12.5px;line-height:1.7;font-weight:500;
}
.mt-plain-ico{font-size:13px;line-height:1.5;flex:0 0 auto}
/* ③ 举例：等宽数字，演算过程一眼看清 */
.mt-eg{
  display:flex;gap:7px;align-items:flex-start;
  margin:7px 0 0;padding:7px 11px;border-radius:8px;
  background:rgba(var(--ovl),.06);border:1px dashed var(--border);
  font-size:11.5px;line-height:1.9;color:var(--muted);
}
.mt-eg b{color:var(--accent)}
/* ④ 修改指引：默认折叠，想改才展开，不干扰阅读 */
.mt-more{margin-top:8px}
.mt-more>summary{
  cursor:pointer;list-style:none;font-size:11.5px;color:var(--accent);
  padding:4px 0;user-select:none;
}
.mt-more>summary::-webkit-details-marker{display:none}
.mt-more>summary:hover{text-decoration:underline}
.mt-more[open]>summary{color:var(--text)}
.mt-more .mt-how{margin-top:5px}
/* 顶部数据链路图 */
.mt-chain{
  margin:0 0 10px;padding:8px 11px;border-radius:8px;
  background:rgba(var(--ovl),.05);border:1px solid var(--border);
  font-size:11.5px;color:var(--muted);line-height:1.9;
}
.mt-chain code{
  padding:1px 5px;border-radius:4px;font-size:11px;
  background:rgba(var(--ovl),.1);color:var(--text2);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
}

/* ===== 说明块「后期怎么改」===== */
.mt-how{
  margin-top:6px;padding:7px 10px;border-radius:7px;
  background:rgba(var(--ar),var(--ag),var(--ab),.07);
  border-left:2px solid rgba(var(--ar),var(--ag),var(--ab),.45);
  color:var(--muted);font-size:11.5px;line-height:1.85;
}
.mt-how b{color:var(--accent);font-weight:600}
.mt-v code,.mt-how code{
  padding:1px 5px;border-radius:4px;font-size:11px;
  background:rgba(var(--ovl),.08);color:var(--text2);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
}
/* 看板「预估」列的计划值角标 */
.yugu-plan{
  display:inline-block;margin-left:5px;padding:0 5px;
  border-radius:5px;font-size:10px;line-height:15px;vertical-align:1px;
  background:rgba(var(--ovl),.10);color:var(--muted);
  border:1px dashed rgba(var(--ovl),.28);cursor:help;
}

/* 次要数值（如计划出栏）：降低视觉权重，突出实际值 */
.mono.muted{color:var(--muted);opacity:.75}

/* 看板「XX达成」子表头：缩小字号、降低字重，与主列区分 */
th.th-sub{font-size:12px;font-weight:500;opacity:.72;white-space:nowrap}

/* ── 看板「预估出栏」列：数值本身做高亮（与各环节「达成率」同款的淡底标签）──
   表头不高亮、单元格不加背景 / 不加左边框；高亮只作用在数字上
   （数字被 <span class="tag yuji"> 包起来，样式见上面 .tag.yuji 那一段）。
   颜色走 --accent 变量，切配色 / 切深浅自动跟着变，不用改两遍。
   想换个颜色：改各主题块里的 --kr/--kg/--kb（浅色墨）或 --dr/--dg/--db（深色墨），
   不要直接写 var(--accent) —— 那样浅色底上会淡到看不清。 */
th.th-yuji{
  /* 表头保持普通样式，不做任何高亮 */
  white-space:nowrap;
}
/* ★ 必须带上 .tbl 和 .mono：上面 625 行有 .tbl td.mono{color:var(--muted)}，
   两个类的选择器优先级高于单写 td.yuji，会把高亮色盖成灰色（表现就是"加了没反应"）。
   写成 .tbl td.mono.yuji（三个类）才能压过它。 */
td.yuji,
.tbl td.yuji,
.tbl td.mono.yuji{
  color:var(--accent-ink);            /* 仅文字变色 */
  font-weight:800;                /* 仅文字加粗 */
  border-left:0;                  /* 明确不加竖线 / 色块 */
}
/* 手机卡片模式：同样仅高亮数值文字 */
.card-yuji .mcard-v,
.card-yuji .mcard-v.is-empty{
  color:var(--accent-ink);font-weight:800;
}

/* 产量预测：合计行 */
tr.sum-row td{background:var(--sf-1);font-weight:600;border-top:2px solid var(--bd)}
tr.sum-row td:first-child{position:sticky;left:0;z-index:5}

/* ============================================================
   通用小工具类（首页「异常批次」卡片详情区用到）
   为什么单独写：以前 JS 里直接写 class="pd10 fs12 muted"，
   但 CSS 里没有这两个类，字号和间距全靠浏览器默认，看着跟别处不统一。
   后期想改：改下面两行即可，不用动 JS。
   ============================================================ */
.pd10{padding:10px}                 /* 内边距 */
.fs12{font-size:12px;line-height:1.7} /* 小字号正文 */

/* ===== 产量预测：顶部 KPI 汇总条 =====
   想改每行几个卡：调整 grid-template-columns 的 repeat(4,...) 数字 */
.fc-kpi{ display:grid; grid-template-columns:repeat(4,1fr); gap:10px; margin-bottom:12px; }
.fc-kpi-item{ padding:10px 12px; border:1px solid var(--bd); border-radius:10px; background:var(--sf-2); }
.fc-kpi-lb{ font-size:12px; color:var(--muted); margin-bottom:4px; }
.fc-kpi-vl{ font-size:18px; font-weight:700; }
/* hl = 主色高亮，用于最核心的那几个结果数字 */
.fc-kpi-vl.hl{ color:var(--accent-ink); font-weight:800; }
/* 大数字后面的小单位（只/栋/批），弱化处理不抢视线 */
.fc-kpi-un{ font-size:12px; font-weight:400; color:var(--muted); margin-left:3px; }

/* ===== 经营决策倒推：结果卡片网格 =====
   复用于盘存分析，改这里两处一起变 */
.biz-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-top:4px; }
.biz-card{ padding:10px 12px; border:1px solid var(--bd); border-radius:10px; background:var(--sf-2); }
.biz-card-lb{ font-size:12px; color:var(--muted); margin-bottom:4px; }
.biz-card-vl{ font-size:18px; font-weight:700; }
.biz-card.hl{ border-color:color-mix(in srgb, var(--accent) 40%, transparent);
              background:color-mix(in srgb, var(--accent) 10%, transparent); }
.biz-card.hl .biz-card-vl{ color:var(--accent-ink); font-weight:800; }
.biz-card-un{ font-size:12px; font-weight:400; color:var(--muted); margin-left:3px; }

/* 窄屏自动降列，避免卡片被压扁 */
@media(max-width:900px){ .fc-kpi{ grid-template-columns:repeat(2,1fr); } .biz-grid{ grid-template-columns:repeat(2,1fr); } }
@media(max-width:520px){ .fc-kpi{ grid-template-columns:1fr; } .biz-grid{ grid-template-columns:1fr; } }

/* ===== 盘存分析面板 =====
   结构：卡片行 → 配比/饲料行 → 存栏结构条 → 环比 → 提醒 */
.pca-row{ display:flex; align-items:center; gap:6px; margin-top:8px; flex-wrap:wrap; }
.pca-lb{ font-size:13px; color:var(--muted); min-width:64px; }
.pca-block{ margin-top:12px; padding-top:10px; border-top:1px dashed var(--bd); }
.pca-block-lb{ font-size:13px; font-weight:700; margin-bottom:6px; }
.pca-bars{ display:flex; flex-direction:column; gap:6px; }
.pca-bar-row{ display:flex; align-items:center; gap:8px; }
.pca-bar-nm{ min-width:74px; font-size:13px; }
.pca-bar-vl{ min-width:110px; text-align:right; font-size:13px; }
/* 环比列表：名称 / 本月值 / 涨跌标签 */
/* ===== 盘存分析：顶部四张汇总卡（总存栏/公兔/母兔/商品兔）=====
   想改成 2 列或 3 列：把下面的 minmax(150px,1fr) 改大即可，例如
   minmax(220px,1fr) 就是每行最多 2 张卡。手机窄屏会自动降成 2 列、1 列。 */
.pca-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:8px; margin-top:8px; }
/* hl = 高亮卡（总存栏）：主色文字 + 淡背景，跟随主题配色自动变 */

/* 合计/汇总标签（比普通标签更重一点，用于「合计」「全场均值」那一行） */
.tag.sum{ font-weight:800; border-width:1px; }

.pca-mom{ display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); gap:8px; }
.pca-mom-item{ display:flex; align-items:center; gap:6px; font-size:13px; }
.pca-mom-nm{ min-width:74px; color:var(--muted); }
@media(max-width:520px){ .pca-mom{ grid-template-columns:1fr; } }

/* ===== 计算口径注释块 calcNote =====
   作用：放在「结果」区域正下方，用灰色小字写清每个数字是怎么算出来的。
   跟顶部 metaBlock 的区别：
     metaBlock = 讲业务含义 + 数据来源 + 举例（默认折叠，讲给不懂的人听）
     calcNote  = 只讲算式本身（默认展开，一眼能对账）
   想改样式：改下面 .cn-* 这几个类即可。
   想加内容：到 web/js/app.js 找到对应 render 函数，在结果后面调 calcNote(...) 。 */
.calc-note{
  margin-top:10px; padding:9px 12px;
  border:1px dashed var(--bd); border-radius:10px;
  background:var(--sf-2); font-size:12px; line-height:1.9;
}
/* 注释块默认收起：<details> 不带 open 即收起，点标题栏展开。
   想默认展开，改 web/js/app.js 里 calcNote() 的 <details class="calc-note"> 加 open。 */
.calc-note > summary.cn-title{
  cursor:pointer; user-select:none; list-style:none;
  font-weight:700; color:var(--muted); margin-bottom:0;
  display:flex; align-items:center; gap:5px;
}
.calc-note > summary.cn-title::-webkit-details-marker{ display:none; }
.calc-note > summary.cn-title::marker{ content:''; }
.calc-note[open] > summary.cn-title{ margin-bottom:6px; color:var(--accent-ink); }
.calc-note .cn-toggle{
  margin-left:auto; font-weight:400; font-size:11px;
  color:var(--muted); opacity:.8;
}
.calc-note .cn-toggle::before{ content:'▸ '; }
.calc-note[open] .cn-toggle{ color:var(--accent-ink); }
.calc-note[open] .cn-toggle::before{ content:'▾ '; }
.calc-note .cn-item{ display:flex; gap:8px; align-items:baseline; flex-wrap:wrap; }
.calc-note .cn-k{
  flex:0 0 auto; min-width:96px; font-weight:700; color:var(--fg);
}
.calc-note .cn-f{ flex:1 1 auto; color:var(--muted); }
.calc-note .cn-f code{
  padding:1px 5px; border-radius:4px; background:var(--sf-3);
  font-size:11.5px; color:var(--accent-ink);
}
.calc-note .cn-eq{ color:var(--accent-ink); font-weight:700; }
.calc-note .cn-foot{
  margin-top:6px; padding-top:6px; border-top:1px dashed var(--bd);
  color:var(--muted); font-size:11.5px;
}
/* 手机端：名称不再固定宽度，改成上下两行，避免算式被挤到看不见 */
@media(max-width:520px){
  .calc-note .cn-item{ flex-direction:column; gap:0; }
  .calc-note .cn-k{ min-width:0; }
}

/* 发布进度条：以前点「发布到正式环境」后界面几十秒一动不动，
   不知道跑到第几步、是不是卡死了。现在每一步完成都会推进这根条。 */
.sync-bar{height:10px;border-radius:6px;background:rgba(127,127,127,.18);
  overflow:hidden;margin:8px 0 4px}
.sync-bar-in{height:100%;border-radius:6px;
  background:linear-gradient(90deg,#00E5B0,#5AA0FF);
  transition:width .4s ease}

/* 计算口径注释：内容区（<details> 展开后显示的部分） */
.calc-note .cn-body{ padding-top:2px; }
/* 面板内容区（不参与折叠，保持常驻展开） */
.fp-flat{ display:block; }
