/* ============== CSS Variables ============== */
/* 色值 / 字号 / 圆角均取自原站 www.yuxiaor.com/v2 实测计算样式 */
:root {
  --c-primary: #1B3FA8;
  --c-primary-hover: #163590;
  --c-primary-light: #EDF1FC;
  --c-danger: #f53f3f;
  --c-danger-light: #ffece8;
  --c-warning: #ff7d00;
  --c-success: #00b42a;

  --c-text: #040a24;
  --c-text-regular: #555555;
  --c-text-secondary: #86909c;
  --c-text-placeholder: #AEB6C4;

  --c-bg: #f7f9fa;
  --c-bg-card: #ffffff;
  --c-border: #e5e6eb;
  --c-border-light: #f2f3f5;
  --c-input-border: #d8dce6;
  --c-header-border: #dddee3;

  --c-sidebar: #f7f8fa;
  --c-sidebar-hover: #ebeef3;
  --c-sidebar-active-bg: #ebeef3;
  --c-sidebar-text: #040a24;
  --c-sidebar-text-active: #040a24;

  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;

  --w-sidebar: 168px;
  --w-sidebar-collapsed: 60px;
  --h-topbar: 52px;

  --shadow-sm: 0 1px 8px rgba(0,0,0,.05);
  --shadow-md: 0 4px 16px rgba(0,0,0,.1);

  /* ---- 线性图标（与原站 yxe-icon 风格一致：24 视窗 / 1.7 描边 / 单色 mask）---- */
  --i-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7.5' height='7.5' rx='1.5'/%3E%3Crect x='13.5' y='3' width='7.5' height='7.5' rx='1.5'/%3E%3Crect x='3' y='13.5' width='7.5' height='7.5' rx='1.5'/%3E%3Crect x='13.5' y='13.5' width='7.5' height='7.5' rx='1.5'/%3E%3C/svg%3E");
  --i-target: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Ccircle cx='12' cy='12' r='3.5'/%3E%3Cpath d='M12 1.5v3M12 19.5v3M1.5 12h3M19.5 12h3'/%3E%3C/svg%3E");
  --i-approval: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6.5L9.5 17 4 11.5'/%3E%3Cpath d='M20 13v5.5a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 18.5v-13A1.5 1.5 0 0 1 5.5 4H15'/%3E%3C/svg%3E");
  --i-house: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 21h18'/%3E%3Cpath d='M5 21V8l7-4.5L19 8v13'/%3E%3Cpath d='M9.5 21v-6h5v6'/%3E%3C/svg%3E");
  --i-contract: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2.5H6.5A1.5 1.5 0 0 0 5 4v16a1.5 1.5 0 0 0 1.5 1.5h11A1.5 1.5 0 0 0 19 20V7.5z'/%3E%3Cpath d='M14 2.5V7.5h5'/%3E%3Cpath d='M8.5 13h7M8.5 16.5h4.5'/%3E%3C/svg%3E");
  --i-finance: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 4.5L12 12l5.5-7.5'/%3E%3Cpath d='M12 12v8.5'/%3E%3Cpath d='M8.5 14.5h7M8.5 17.5h7'/%3E%3C/svg%3E");
  --i-report: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='3.5' width='17' height='17' rx='2'/%3E%3Cpath d='M8 16.5V11M12 16.5V8M16 16.5v-4'/%3E%3C/svg%3E");
  --i-device: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='5' width='14' height='14' rx='2'/%3E%3Crect x='9.5' y='9.5' width='5' height='5' rx='1'/%3E%3Cpath d='M9.5 2.5v2.5M14.5 2.5v2.5M9.5 19v2.5M14.5 19v2.5M2.5 9.5H5M2.5 14.5H5M19 9.5h2.5M19 14.5h2.5'/%3E%3C/svg%3E");
  --i-meter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 12l4.5-3.5'/%3E%3Cpath d='M12 3.5v2M20.5 12h-2M12 20.5v-2M3.5 12h2'/%3E%3C/svg%3E");
  --i-workorder: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='4.5' width='14' height='16.5' rx='2'/%3E%3Cpath d='M9.5 4.5V3h5v1.5'/%3E%3Cpath d='M9 10.5h6M9 14.5h6'/%3E%3C/svg%3E");
  --i-promote: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 10v4h3l5 3.5v-11L6.5 10z'/%3E%3Cpath d='M15 9a4 4 0 0 1 0 6'/%3E%3Cpath d='M6.5 14v4.5'/%3E%3C/svg%3E");
  --i-member: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.8'/%3E%3Cpath d='M4.5 20.5c0-3.8 3.4-6 7.5-6s7.5 2.2 7.5 6'/%3E%3C/svg%3E");
  --i-esign: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.5 20.5h8.5'/%3E%3Cpath d='M16.8 3.7a2.1 2.1 0 0 1 3 3L8 18.5l-4 1 1-4z'/%3E%3C/svg%3E");
  --i-community: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 12a8.5 8.5 0 0 1-8.5 8.5H8l-4.5 2.5 1.2-4.4A8.5 8.5 0 1 1 20.5 12z'/%3E%3C/svg%3E");
  --i-setting: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3.2'/%3E%3Cpath d='M19.4 14.6a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-2.9 1.2 2 2 0 1 1-4 0 1.7 1.7 0 0 0-2.9-1.2l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0-1.2-2.9 2 2 0 1 1 0-4 1.7 1.7 0 0 0 1.2-2.9l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 2.9-1.2 2 2 0 1 1 4 0 1.7 1.7 0 0 0 2.9 1.2l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0 1.2 2.9 2 2 0 1 1 0 4 1.7 1.7 0 0 0-1.5 1z'/%3E%3C/svg%3E");
  --i-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7.5'/%3E%3Cpath d='M20.5 20.5L16.6 16.6'/%3E%3C/svg%3E");
  --i-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2'/%3E%3Cpath d='M3.5 7l8.5 6 8.5-6'/%3E%3C/svg%3E");
  --i-wallet: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 7.5A2 2 0 0 1 5.5 5.5h11a2 2 0 0 1 2 2v1'/%3E%3Crect x='3.5' y='8.5' width='17' height='10.5' rx='2'/%3E%3Ccircle cx='16.5' cy='13.8' r='1.1'/%3E%3C/svg%3E");
  --i-bell: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 8.5a6 6 0 1 0-12 0c0 6-2.5 7.5-2.5 7.5h17S18 14.5 18 8.5'/%3E%3Cpath d='M13.7 19.5a2 2 0 0 1-3.4 0'/%3E%3C/svg%3E");
  --i-help: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M9.6 9.2a2.5 2.5 0 1 1 3.2 2.6c-.7.3-1 .9-1 1.7v.3'/%3E%3Ccircle cx='12' cy='17' r='.9' fill='%23000' stroke='none'/%3E%3C/svg%3E");
  --i-support: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 14v-2a7.5 7.5 0 0 1 15 0v2'/%3E%3Crect x='2.5' y='13.5' width='4' height='6' rx='1.4'/%3E%3Crect x='17.5' y='13.5' width='4' height='6' rx='1.4'/%3E%3C/svg%3E");
  --i-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
  --i-arrow-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E");
  --i-arrow-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 6l6 6-6 6'/%3E%3C/svg%3E");
  --i-collapse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 6h17M3.5 12h10M3.5 18h17'/%3E%3Cpath d='M17.5 9.5l3 2.5-3 2.5'/%3E%3C/svg%3E");
  --i-logout: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 20.5H6a1.5 1.5 0 0 1-1.5-1.5V5A1.5 1.5 0 0 1 6 3.5h3.5'/%3E%3Cpath d='M15.5 16.5l4.5-4.5-4.5-4.5'/%3E%3Cpath d='M20 12H9'/%3E%3C/svg%3E");
  --i-more: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='5' cy='12' r='1.7'/%3E%3Ccircle cx='12' cy='12' r='1.7'/%3E%3Ccircle cx='19' cy='12' r='1.7'/%3E%3C/svg%3E");
  --i-download: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5v11'/%3E%3Cpath d='M7.5 10.5l4.5 4.5 4.5-4.5'/%3E%3Cpath d='M4.5 20.5h15'/%3E%3C/svg%3E");
  --i-sort: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 4.5v15M7 4.5L4 7.5M7 4.5l3 3'/%3E%3Cpath d='M17 19.5v-15M17 19.5l-3-3M17 19.5l3-3'/%3E%3C/svg%3E");
  --i-eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 12S6 6.5 12 6.5 21.5 12 21.5 12 18 17.5 12 17.5 2.5 12 2.5 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
  --i-phone: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 16.9v2.3a1.6 1.6 0 0 1-1.7 1.6 16 16 0 0 1-7-2.5 15.7 15.7 0 0 1-4.8-4.8 16 16 0 0 1-2.5-7.1A1.6 1.6 0 0 1 6.1 4.7h2.3a1.6 1.6 0 0 1 1.6 1.4c.1.9.3 1.7.6 2.5a1.6 1.6 0 0 1-.4 1.7l-1 1a12.8 12.8 0 0 0 4.8 4.8l1-1a1.6 1.6 0 0 1 1.7-.4c.8.3 1.6.5 2.5.6a1.6 1.6 0 0 1 1.4 1.6z'/%3E%3C/svg%3E");
  --i-doc: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.5 3H7a1.5 1.5 0 0 0-1.5 1.5v15A1.5 1.5 0 0 0 7 21h10a1.5 1.5 0 0 0 1.5-1.5V8z'/%3E%3Cpath d='M13.5 3V8H18'/%3E%3C/svg%3E");
}

/* ============== Reset ============== */
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { min-height: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB",
    Arial, sans-serif;
  font-size: 13px;
  line-height: 20px;
  color: var(--c-text-regular);
  background: var(--c-bg);
  overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
button { border: none; background: none; cursor: pointer; font: inherit; color: inherit; }
ul { list-style: none; }
h1, h2, h3, h4 { font-weight: 500; }

/* ============== Layout（顶栏通栏 + 侧栏在其下方，对齐原站）============== */
.sidebar {
  position: fixed; top: var(--h-topbar); left: 0; bottom: 0;
  width: var(--w-sidebar);
  background: var(--c-sidebar);
  border-right: 1px solid var(--c-border);
  color: var(--c-sidebar-text);
  display: flex; flex-direction: column;
  transition: width .2s;
  z-index: 90;
}
.sidebar.collapsed { width: var(--w-sidebar-collapsed); }
.sidebar.collapsed .nav-item span,
.sidebar.collapsed .nav-sub,
.sidebar.collapsed .arrow,
.sidebar.collapsed .nav-collapse span { display: none; }
.sidebar.collapsed .nav-item { justify-content: center; padding: 0; margin: 0 8px; }
.sidebar.collapsed .nav-item .ico:first-child { margin-right: 0; }

.main {
  margin-left: var(--w-sidebar);
  padding-top: var(--h-topbar);
  min-height: 100vh;
  display: flex; flex-direction: column;
  transition: margin-left .2s;
  min-width: 0;
}
.sidebar.collapsed ~ .main { margin-left: var(--w-sidebar-collapsed); }

/* ============== Sidebar ============== */
.sidebar-nav { flex: 1; overflow-y: auto; padding: 12px 0; }
.sidebar-nav::-webkit-scrollbar { width: 4px; }
.sidebar-nav::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 2px; }

.nav-item {
  display: flex; align-items: center;
  height: 40px; margin: 0 12px; padding: 0 8px 0 12px;
  border-radius: var(--r-sm);
  font-size: 13px;
  color: var(--c-sidebar-text);
  cursor: pointer;
  position: relative;
  transition: background .15s, color .15s;
}
.nav-item:hover { background: var(--c-sidebar-hover); }
.nav-item.active { background: var(--c-sidebar-active-bg); font-weight: 500; }
.nav-item .ico:first-child { margin-right: 10px; color: var(--c-text-regular); }
.nav-item.active .ico:first-child,
.nav-item:hover .ico:first-child { color: var(--c-primary); }
.nav-item .arrow { margin-left: auto; width: 12px; height: 12px; color: var(--c-text-secondary); transition: transform .2s; }
.nav-item .arrow.up { transform: rotate(180deg); }

.nav-sub {
  max-height: 0; overflow: hidden;
  transition: max-height .25s ease;
}
.nav-group.open .nav-sub { max-height: 500px; }
.nav-sub a {
  display: flex; align-items: center;
  height: 40px; margin: 0 12px; padding: 0 8px 0 36px;
  border-radius: var(--r-sm);
  font-size: 13px;
  color: var(--c-sidebar-text);
  transition: background .15s;
}
.nav-sub a:hover { background: var(--c-sidebar-hover); }
.nav-sub a.active { background: var(--c-sidebar-active-bg); font-weight: 500; }

.sidebar-footer {
  border-top: 1px solid var(--c-border);
  padding: 8px 0;
  flex-shrink: 0;
}
.nav-collapse { color: var(--c-text-regular); font-size: 13px; }

/* ============== Icons (CSS ico) ============== */
.ico {
  display: inline-block;
  width: 16px; height: 16px;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}
/* 线性图标（mask 取色，跟随文字颜色） */
.ico-overview  { -webkit-mask-image: var(--i-grid);      mask-image: var(--i-grid); }
.ico-lead      { -webkit-mask-image: var(--i-target);    mask-image: var(--i-target); }
.ico-approval  { -webkit-mask-image: var(--i-approval);  mask-image: var(--i-approval); }
.ico-house     { -webkit-mask-image: var(--i-house);     mask-image: var(--i-house); }
.ico-contract  { -webkit-mask-image: var(--i-contract);  mask-image: var(--i-contract); }
.ico-finance   { -webkit-mask-image: var(--i-finance);   mask-image: var(--i-finance); }
.ico-report    { -webkit-mask-image: var(--i-report);    mask-image: var(--i-report); }
.ico-device    { -webkit-mask-image: var(--i-device);    mask-image: var(--i-device); }
.ico-meter     { -webkit-mask-image: var(--i-meter);     mask-image: var(--i-meter); }
.ico-workorder { -webkit-mask-image: var(--i-workorder); mask-image: var(--i-workorder); }
.ico-promote   { -webkit-mask-image: var(--i-promote);   mask-image: var(--i-promote); }
.ico-member    { -webkit-mask-image: var(--i-member);    mask-image: var(--i-member); }
.ico-esign     { -webkit-mask-image: var(--i-esign);     mask-image: var(--i-esign); }
.ico-community { -webkit-mask-image: var(--i-community); mask-image: var(--i-community); }
.ico-setting   { -webkit-mask-image: var(--i-setting);   mask-image: var(--i-setting); }
.ico-collapse  { -webkit-mask-image: var(--i-collapse);  mask-image: var(--i-collapse); }
.ico-arrow-down  { -webkit-mask-image: var(--i-arrow-down);  mask-image: var(--i-arrow-down); width: 12px; height: 12px; color: var(--c-text-secondary); }
.ico-arrow-right { -webkit-mask-image: var(--i-arrow-right); mask-image: var(--i-arrow-right); width: 12px; height: 12px; }
.ico-search    { -webkit-mask-image: var(--i-search);    mask-image: var(--i-search); width: 18px; height: 18px; }
.ico-message   { -webkit-mask-image: var(--i-mail);      mask-image: var(--i-mail); }
.ico-wallet    { -webkit-mask-image: var(--i-wallet);    mask-image: var(--i-wallet); }
.ico-bell      { -webkit-mask-image: var(--i-bell);      mask-image: var(--i-bell); width: 18px; height: 18px; }
.ico-help      { -webkit-mask-image: var(--i-help);      mask-image: var(--i-help); width: 18px; height: 18px; }
.ico-support   { -webkit-mask-image: var(--i-support);   mask-image: var(--i-support); width: 18px; height: 18px; }
.ico-plus      { -webkit-mask-image: var(--i-plus);      mask-image: var(--i-plus); width: 14px; height: 14px; }
.ico-logout    { -webkit-mask-image: var(--i-logout);    mask-image: var(--i-logout); }
.ico-more      { -webkit-mask-image: var(--i-more);      mask-image: var(--i-more); }
.ico-download  { -webkit-mask-image: var(--i-download);  mask-image: var(--i-download); }
.ico-sort      { -webkit-mask-image: var(--i-sort);      mask-image: var(--i-sort); }
.ico-eye       { -webkit-mask-image: var(--i-eye);       mask-image: var(--i-eye); }
.ico-phone     { -webkit-mask-image: var(--i-phone);     mask-image: var(--i-phone); width: 14px; height: 14px; }
.ico-doc       { -webkit-mask-image: var(--i-doc);       mask-image: var(--i-doc); width: 14px; height: 14px; }
.ico-edit      { -webkit-mask-image: var(--i-esign);     mask-image: var(--i-esign); }
.ico-panel     { -webkit-mask-image: var(--i-report);    mask-image: var(--i-report); }

/* ============== 顶部通栏 host-header（对齐原站）============== */
.host-header {
  position: fixed; top: 0; left: 0; right: 0;
  height: var(--h-topbar);
  background: #fff;
  border-bottom: 1px solid var(--c-header-border);
  box-shadow: 0 1px 8px rgba(0,0,0,.05);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 24px 0 0;
  gap: 12px; min-width: 0;
  z-index: 100;
}
.header-left { display: flex; align-items: center; min-width: 0; height: 100%; }
.logo-area {
  display: flex; align-items: center; gap: 8px;
  width: var(--w-sidebar); padding-left: 16px;
  flex-shrink: 0; height: 100%;
}
.logo-img { width: 30px; height: 30px; display: inline-flex; flex-shrink: 0; }
.logo-img svg { width: 100%; height: 100%; }
.logo-title {
  font-size: 14px; color: var(--c-text); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.header-page-title {
  font-size: 14px; font-weight: 500; color: var(--c-text);
  margin-left: 20px; white-space: nowrap;
}
/* 顶栏二级导航（原站 topbar-sub-nav：总览页的 仪表盘/数据大屏、设置页的 常用设置/…） */
.header-subnav { display: flex; align-items: center; height: 100%; margin-left: 4px; }
.subnav-tab {
  position: relative; display: inline-flex; align-items: center;
  height: var(--h-topbar); padding: 0 14px;
  font-size: 13px; color: var(--c-text-regular); white-space: nowrap;
}
.subnav-tab:hover { color: var(--c-primary); }
.subnav-tab.active { color: var(--c-text); font-weight: 500; }
.subnav-tab.active::after {
  content: ""; position: absolute; left: 14px; right: 14px; bottom: 0;
  height: 2px; background: var(--c-primary);
}

.header-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.icon-actions { display: flex; align-items: center; gap: 2px; }
.action-icon-btn {
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm);
  color: var(--c-text-regular);
  cursor: pointer; position: relative;
  transition: background .15s, color .15s;
}
.action-icon-btn:hover { background: var(--c-bg); color: var(--c-primary); }
.red-dot {
  position: absolute; top: 9px; right: 9px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--c-danger);
}

.create-btn {
  height: 28px; padding: 0 16px;
  background: var(--c-primary); color: #fff;
  border-radius: var(--r-sm);
  font-size: 12px;
  display: inline-flex; align-items: center; gap: 4px;
  transition: background .15s;
}
.create-btn:hover { background: var(--c-primary-hover); }

.header-user {
  position: relative;
  display: flex; align-items: center; gap: 6px;
  height: 100%; padding: 0 4px 0 12px;
  cursor: pointer;
}
.user-name { font-size: 13px; color: var(--c-text); white-space: nowrap; }
.header-user .ico-arrow-down { transition: transform .2s; }
.header-user.open .ico-arrow-down { transform: rotate(180deg); }
.user-menu {
  position: absolute; top: calc(100% - 6px); right: 0;
  min-width: 184px; background: #fff;
  border: 1px solid var(--c-border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: 8px 0; display: none; z-index: 1000;
}
.header-user.open .user-menu { display: block; }
.um-head {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 16px 12px; margin-bottom: 6px;
  border-bottom: 1px solid var(--c-border-light);
}
.um-name { font-size: 13px; color: var(--c-text); }
.um-role { font-size: 12px; color: var(--c-text-secondary); margin-top: 2px; }
.um-item {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 16px; font-size: 13px; color: var(--c-text-regular);
  transition: background .12s, color .12s;
}
.um-item:hover { background: var(--c-bg); color: var(--c-primary); }
.um-divider { height: 1px; background: var(--c-border-light); margin: 6px 0; }
.um-logout { color: var(--c-danger); }
.um-logout:hover { background: var(--c-danger-light); color: var(--c-danger); }

.btn-primary {
  background: var(--c-primary);
  color: #fff;
  border-radius: var(--r-sm);
  padding: 0 16px;
  height: 32px;
  font-size: 13px;
  display: inline-flex; align-items: center; gap: 4px;
  transition: background .15s;
}
.btn-primary:hover { background: var(--c-primary-hover); }

.avatar {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: #EAF1FE;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; flex-shrink: 0;
}
.avatar img { width: 100%; height: 100%; display: block; object-fit: cover; }

/* ============== Content area ============== */
.content {
  flex: 1; overflow-y: auto;
  padding: 16px;
  background: #fff;
}
.content::-webkit-scrollbar { width: 8px; }
.content::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 4px; }

.row { display: grid; gap: 16px; }
.row-banner { grid-template-columns: 1fr 280px; }

.grid { display: grid; gap: 16px; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

/* ============== Card ============== */
.card {
  background: var(--c-bg-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: 16px;
}
.card-head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 12px;
}
.card-head-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
  gap: 8px;
}
.card-title {
  font-size: 15px; font-weight: 600;
  color: var(--c-text);
}

/* ============== 公告 + 新手 ============== */
.card-announce {
  display: flex; align-items: center; justify-content: space-between;
  background: #fff;
  height: 48px;
  padding: 0 16px;
}
.announce-body {
  display: flex; align-items: center; gap: 8px;
  font-size: 14px;
  color: var(--c-text-regular);
}
.announce-text {
  color: var(--c-text);
  font-weight: 500;
}
/* 批次76：--c-danger #f53f3f 是**填充档**，压白底只有 3.9:1，12~13px 的字看不清。
   文字一律走文字档 #B42318（5.9:1）。 */
.link-red { color: var(--c-danger-text); cursor: pointer; }
.link-red:hover { text-decoration: underline; }
.link-blue { color: var(--c-primary); cursor: pointer; }
.link-blue:hover { text-decoration: underline; }
.announce-actions { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.announce-divider { color: var(--c-text-placeholder); }

.card-novice {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 16px;
  height: 48px;
  background: #fff;
}
.novice-body {
  font-size: 13px;
  color: var(--c-text-regular);
  display: flex; gap: 6px; align-items: center;
}
.novice-body strong { color: var(--c-text); }
.novice-more { font-size: 13px; white-space: nowrap; }

/* ============== 待办提醒 ============== */
.card-todo { padding: 0; }
.card-todo .card-head { padding: 12px 16px; margin: 0; border-bottom: 1px solid var(--c-border-light); }

.todo-filters {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.todo-total {
  margin-left: auto;
  color: var(--c-text-secondary);
  font-size: 13px;
}
.btn-link {
  color: var(--c-primary);
  font-size: 13px;
  cursor: pointer;
}
.btn-link:hover { text-decoration: underline; }

/* select 下拉 */
.select {
  position: relative;
  display: inline-flex; align-items: center;
  height: 32px;
  padding: 0 28px 0 12px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  background: #fff;
  font-size: 13px;
  color: var(--c-text-regular);
  cursor: pointer;
  min-width: 90px;
  user-select: none;
}
.select .ico { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); }
.select-menu {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-md);
  padding: 4px 0;
  max-height: 280px; overflow-y: auto;
  display: none;
  z-index: 10;
}
.select.open .select-menu { display: block; }
.select-menu li {
  padding: 6px 12px;
  font-size: 13px;
  color: var(--c-text-regular);
  cursor: pointer;
}
.select-menu li:hover { background: var(--c-primary-light); color: var(--c-primary); }

.todo-body {
  display: grid; grid-template-columns: 160px minmax(0,1fr);
  max-height: 540px;
  overflow-y: auto;
}
.todo-cats { padding: 12px; border-right: 1px solid var(--c-border-light); }
.cat-card {
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  margin-bottom: 12px;
  cursor: pointer;
  transition: all .15s;
  border-left: 3px solid transparent;
}
.cat-card:last-child { margin-bottom: 0; }
.cat-card:hover { background: var(--c-bg); }
.cat-card.cat-active {
  background: var(--c-primary-light);
  border-color: var(--c-primary);
  border-left: 3px solid var(--c-primary);
}
.cat-title { font-size: 14px; font-weight: 600; margin-bottom: 8px; color: var(--c-text); }
.cat-line { font-size: 12px; color: var(--c-text-secondary); line-height: 20px; }
.cat-line b { color: var(--c-danger); font-weight: 600; margin: 0 2px; }
.cat-card.cat-active .cat-line b { color: var(--c-danger); }

.todo-list { padding: 4px 0; min-width: 0; }
.todo-item {
  display: grid;
  grid-template-columns: 100px minmax(180px, 1fr) 120px;
  align-items: center;
  padding: 10px 16px;
  border-bottom: 1px solid var(--c-border-light);
  font-size: 13px;
  gap: 10px;
  cursor: pointer;
  transition: background .15s ease;
  min-width: 0;
}
.todo-amount { min-width: 0; }
.todo-item:last-child { border-bottom: none; }
.todo-item:hover { background: var(--c-bg); }
.todo-overdue { color: var(--c-danger); }
.overdue-tag { display: block; font-weight: 600; }
.overdue-date { display: block; color: var(--c-text-secondary); font-size: 12px; margin-top: 2px; }
.house-name {
  color: var(--c-text); font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.house-sub { color: var(--c-text-secondary); font-size: 12px; margin: 2px 0; }
.house-contact {
  color: var(--c-text-secondary);
  font-size: 12px;
  margin-top: 4px;
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap;
}
.todo-amount { text-align: right; }
.amount { color: var(--c-text); font-weight: 600; }
.amount-type { color: var(--c-text-secondary); font-size: 12px; margin-top: 2px; }

.todo-footer {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px;
  border-top: 1px solid var(--c-border-light);
  font-size: 13px;
  color: var(--c-text-secondary);
}
.pager { display: flex; gap: 4px; align-items: center; }
.pg-btn, .pg-num {
  min-width: 32px; height: 28px;
  padding: 0 8px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  background: #fff;
  font-size: 12px;
  color: var(--c-text-regular);
}
.pg-btn:hover, .pg-num:hover { color: var(--c-primary); border-color: var(--c-primary); }
.pg-num.active {
  background: var(--c-primary);
  color: #fff;
  border-color: var(--c-primary);
}

/* ============== 房源出收 ============== */
.card-stat { display: flex; flex-direction: column; gap: 18px; }
.stat-block { }
.stat-label { font-size: 13px; color: var(--c-text-secondary); margin-bottom: 8px; }
.stat-cells { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.stat-cell {
  background: var(--c-bg);
  border-radius: var(--r-sm);
  padding: 10px 8px;
  text-align: center;
}
.stat-cell.highlight { background: var(--c-primary-light); }
.cell-num { font-size: 22px; font-weight: 700; color: var(--c-text); line-height: 28px; }
.stat-cell.highlight .cell-num { color: var(--c-primary); }
.cell-key { font-size: 12px; color: var(--c-text-secondary); line-height: 18px; }

/* ============== 库存管理 ============== */
.seg {
  display: inline-flex;
  background: var(--c-bg);
  border-radius: var(--r-sm);
  padding: 2px;
  gap: 2px;
}
.seg-item {
  height: 24px;
  padding: 0 10px;
  font-size: 12px;
  color: var(--c-text-regular);
  border-radius: 3px;
  transition: all .15s;
}
.seg-item.active {
  background: #fff;
  color: var(--c-primary);
  box-shadow: 0 1px 2px rgba(0,0,0,.08);
}
.seg-mini .seg-item { padding: 0 8px; font-size: 12px; height: 22px; }

.inv-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 16px; }
.inv-item { text-align: center; padding: 8px; background: var(--c-bg); border-radius: var(--r-sm); }
.inv-num { font-size: 22px; font-weight: 700; color: var(--c-text); }
.inv-num.muted { color: var(--c-text-placeholder); }
.inv-key { font-size: 12px; color: var(--c-text-secondary); }

.inv-progress { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.inv-progress-bar {
  flex: 1; height: 10px;
  background: var(--c-bg);
  border-radius: 5px; overflow: hidden;
}
.inv-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #ffd1a4, #ff9500);
  border-radius: 5px;
}
.inv-progress-text { display: flex; flex-direction: column; align-items: flex-end; }
.big-num { font-size: 22px; font-weight: 700; color: var(--c-warning); }
.big-num.primary { color: var(--c-primary); }
.muted { color: var(--c-text-secondary); font-size: 12px; }

.inv-days-title { font-size: 13px; color: var(--c-text-secondary); margin-bottom: 8px; }
.inv-days-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.inv-days-grid > div { text-align: center; padding: 6px; background: var(--c-bg); border-radius: var(--r-sm); }
.d-num { font-size: 18px; font-weight: 700; color: var(--c-text); }
.d-key { font-size: 11px; color: var(--c-text-secondary); }

/* ============== 收支情况 ============== */
.month-switch {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 12px;
  font-size: 13px;
}
.m-arrow {
  width: 24px; height: 24px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--c-text-regular);
}
.m-arrow:hover { color: var(--c-primary); border-color: var(--c-primary); }
.m-text { color: var(--c-text-secondary); }
.m-text.active { color: var(--c-primary); font-weight: 600; }

.balance-row {
  text-align: center; padding: 8px 0;
  background: var(--c-primary-light);
  border-radius: var(--r-sm);
  margin-bottom: 12px;
}
.balance-main { font-size: 22px; font-weight: 700; color: var(--c-primary); }
.balance-sub { font-size: 12px; color: var(--c-text-secondary); margin-top: 2px; }

.bal-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  margin-bottom: 8px;
}
.bal-cell {
  display: flex; flex-direction: column; align-items: center;
  padding: 8px;
  background: var(--c-bg);
  border-radius: var(--r-sm);
  font-size: 12px; color: var(--c-text-secondary);
}
.bal-cell b { font-size: 14px; color: var(--c-text); margin-top: 2px; }

.bal-line {
  display: flex; justify-content: space-between;
  font-size: 13px; padding: 4px 0;
  color: var(--c-text-regular);
}

.renew-line, .vacancy-line, .tenant-line {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 0;
  border-top: 1px solid var(--c-border-light);
}
.renew-pct, .vac-pct, .ten-pct {
  font-size: 20px; font-weight: 700;
  width: 70px;
}
.renew-pct, .vac-pct { color: var(--c-warning); }
.ten-pct { color: var(--c-text-placeholder); }
.renew-info, .vac-info, .ten-info { flex: 1; font-size: 13px; color: var(--c-text-regular); }
.renew-info div:first-child, .vac-info div:first-child, .ten-info div:first-child { font-weight: 500; }

/* ============== 审批 / 工单 / 抄表 mini 卡片 ============== */
.card-mini { padding: 16px; }
.mini-list { display: flex; flex-direction: column; gap: 10px; }
.mini-list li {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 13px;
  color: var(--c-text-regular);
  padding-bottom: 8px;
  border-bottom: 1px dashed var(--c-border);
}
.mini-list li:last-child { border-bottom: none; padding-bottom: 0; }
.mini-list li b {
  font-size: 16px;
  font-weight: 700;
  color: var(--c-text);
}
.mini-list li b.num-red { color: var(--c-danger); }
.mini-list-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; }
.mini-list-2col li { border-bottom: none; padding-bottom: 0; }

/* ============== 今日账务 ============== */
.ft-block { display: flex; flex-direction: column; gap: 6px; }
.ft-row {
  display: flex; align-items: center;
  font-size: 13px;
  color: var(--c-text-regular);
}
.ft-row span { color: var(--c-text-secondary); margin-right: 4px; }
.ft-row b { color: var(--c-text); font-weight: 600; margin-right: 16px; }
.ft-row .ml { margin-left: 8px; }
.ft-row.ft-accent b { color: var(--c-danger); }

/* ============== 业绩排行 ============== */
.period-tag {
  font-size: 12px;
  color: var(--c-primary);
  background: var(--c-primary-light);
  padding: 2px 8px;
  border-radius: 10px;
  margin-right: auto;
}
.rank-list { display: flex; flex-direction: column; gap: 8px; }
.rank-item {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px;
  background: var(--c-bg);
  border-radius: var(--r-sm);
}
.rank-no {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--c-warning);
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700;
  flex-shrink: 0;
}
.rank-name { flex: 1; font-size: 13px; color: var(--c-text-regular); }
.rank-num { font-size: 14px; font-weight: 700; color: var(--c-text); }

/* ============== 日程 ============== */
.btn-add {
  width: 100%;
  margin-bottom: 12px;
  justify-content: center;
}
.schedule-empty {
  text-align: center;
  color: var(--c-text-placeholder);
  padding: 32px 0;
  font-size: 13px;
}

/* ============== 客户满意度 ============== */
.month-select {
  height: 26px;
  padding: 0 24px 0 8px;
  font-size: 12px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--c-text-regular);
  cursor: pointer;
  max-width: 140px;
}
.sat-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }
.sat-list li {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 13px;
  color: var(--c-text-regular);
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--c-border);
}
.sat-list li:last-child { border-bottom: none; }
.sat-list li b {
  font-size: 18px; font-weight: 700;
  color: var(--c-text);
}
.sat-score {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 10px 12px;
  background: var(--c-primary-light);
  border-radius: var(--r-sm);
}
.sat-score .big-num { font-size: 24px; color: var(--c-primary); }

/* ============== Responsive ============== */
@media (max-width: 1280px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 1024px) {
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
  .row-banner { grid-template-columns: 1fr; }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .kpi-grid { grid-template-columns: 1fr; }
}

/* ============== Tab Pane ============== */
.tab-pane { display: none; animation: fadeIn .25s ease; }
.tab-pane.active { display: block; }
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* ============== 仪表盘（panel） ============== */
.card-empty {
  display: flex; flex-direction: column; gap: 20px;
  background: linear-gradient(135deg, #f0f7ff 0%, #fff 100%);
}
.empty-head {
  display: flex; align-items: center; gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--c-border-light);
}
.empty-head .ico-panel::before { content: "📊"; font-size: 22px; }
.empty-head h2 { font-size: 18px; color: var(--c-text); }
.empty-tip {
  color: var(--c-text-secondary);
  font-size: 13px;
  line-height: 22px;
}
.kpi-grid { margin-top: 4px; }
.kpi-card {
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: 18px 20px;
  display: flex; flex-direction: column; gap: 6px;
  transition: box-shadow .2s, transform .2s;
}
.kpi-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.kpi-label { color: var(--c-text-secondary); font-size: 13px; }
.kpi-value { color: var(--c-text); font-size: 26px; font-weight: 700; }
.kpi-trend { color: var(--c-text-secondary); font-size: 12px; }
.kpi-trend.up span { color: var(--c-success); margin-left: 4px; }
.kpi-trend.down span { color: var(--c-danger); margin-left: 4px; }

.chart-placeholder {
  background: #fff;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: 18px 20px;
}
.chart-cap {
  font-size: 14px; color: var(--c-text);
  margin-bottom: 12px; font-weight: 600;
}
.chart-area {
  width: 100%; height: 220px;
  background: var(--c-bg);
  border-radius: var(--r-sm);
}
.chart-svg { width: 100%; height: 100%; display: block; }


/* ============== Modal（批次77 重写：四档宽度 + 三段固定结构） ============== */
.modal-mask {
  position: fixed; inset: 0;
  background: rgba(15,23,42,.45);
  display: none;
  align-items: center; justify-content: center;
  padding: 24px;
  z-index: 200;
  animation: fadeIn .15s ease;
}
.modal-mask.open { display: flex; }
.modal {
  background: #fff;
  border-radius: 12px;
  width: 560px;
  min-width: 0;
  max-width: 100%;
  max-height: calc(100vh - 48px);
  overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 48px -12px rgba(16,24,40,.22), 0 4px 12px -2px rgba(16,24,40,.08);
  animation: modalIn .2s ease;
}
/* 🔴 宽度只有四档，禁止再写内联 style="width:NNNpx"（批次77 前的 480/560/620/680/720/760/780 七种宽度已收口） */
.modal.modal-sm { width: 440px; }
.modal.modal-md { width: 560px; }
.modal.modal-lg { width: 720px; }
.modal.modal-xl { width: 900px; }
@keyframes modalIn {
  from { opacity: 0; transform: scale(.97) translateY(6px); }
  to { opacity: 1; transform: none; }
}
.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 0 20px;
  height: 56px;
  flex: 0 0 56px;
  border-bottom: 1px solid var(--c-border);
}
.modal-title {
  font-size: 15px; font-weight: 600; color: var(--c-text);
  display: flex; align-items: baseline; gap: 8px; min-width: 0;
}
/* 标题后的灰色副标题（可选）：<h3 class="modal-title">主标题<em>副标题</em></h3> */
.modal-title em { font-style: normal; font-size: 12.5px; font-weight: 400; color: var(--c-text-secondary); }
.modal-close {
  width: 32px; height: 32px;
  flex: 0 0 32px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1;
  color: var(--c-text-secondary);
  border-radius: 8px;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s, color .15s;
}
.modal-close:hover { background: #F2F4F7; color: var(--c-text); }
.modal-body {
  padding: 20px 24px;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
}
/* 底部操作条：所有弹窗统一走这里，右对齐 */
.modal-foot {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 8px;
  padding: 14px 24px;
  flex: 0 0 auto;
  border-top: 1px solid var(--c-border);
  background: #fff;
}
.modal-foot .foot-note {
  margin-right: auto;
  font-size: 12.5px; color: var(--c-text-secondary);
  display: flex; align-items: center; gap: 6px;
}
/* 🔴 弹窗里不再套卡片：.st-form / .st-card 进弹窗后去掉自己的边框和内距（原来双层边框） */
.modal-body > .st-form,
.modal-body > .set-card {
  border: 0; padding: 0; border-radius: 0; background: transparent;
}
/* 弹窗内的错误提示槽（表单校验失败 / 提交失败）—— 不占位，出错才显形 */
.form-msg {
  display: none;
  margin-top: 10px;
  font-size: 12.5px;
  line-height: 1.6;
  color: #B42318;
}
.form-msg.show { display: block; }

/* 新建弹窗（批次77）：6 个入口原来**全是同一个「+」圆圈**、颜色还是旧蓝 #3A8EE6 ——
   图标完全没承载信息，用户只能靠读文字区分。改成各用各的线性图标，
   底块统一 #F2F4F7 + #475467（设计铁律：宫格图标底块只能一种色，禁一条一个 pastel）。 */
.modal-create { width: 720px; }
.create-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
.create-item {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  border: 1px solid var(--c-border);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.create-item:hover {
  border-color: var(--c-primary);
  background: #FAFBFF;
}
.create-ico {
  width: 38px; height: 38px;
  border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  background: #F2F4F7;
  color: #475467;
  transition: background .15s, color .15s;
}
.create-ico .jxy-i, .create-ico svg { width: 20px; height: 20px; }
.create-item:hover .create-ico { background: var(--c-primary-light); color: var(--c-primary); }
.create-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.create-name { font-size: 13.5px; font-weight: 600; color: var(--c-text); }
.create-desc { font-size: 12px; color: var(--c-text-secondary); line-height: 1.5; }

@media (max-width: 768px) {
  .modal-create { width: 95vw; }
  .create-grid { grid-template-columns: 1fr 1fr; }
}

/* 搜索弹窗 */
.modal-search {
  width: 640px;
  padding: 0;
}
.search-box {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--c-border-light);
}
.search-box .ico-search::before { font-size: 18px; }
.search-box input {
  flex: 1;
  border: none; outline: none;
  font-size: 16px;
  background: transparent;
}
.search-box kbd {
  font-family: inherit;
  font-size: 11px;
  padding: 2px 8px;
  background: var(--c-bg);
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  color: var(--c-text-secondary);
}
.search-suggest { padding: 8px 0; max-height: 50vh; overflow-y: auto; }
.search-section {
  padding: 8px 20px;
  font-size: 12px;
  color: var(--c-text-secondary);
}
.search-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 20px;
  font-size: 14px;
  color: var(--c-text-regular);
  cursor: pointer;
  transition: background .15s;
}
.search-row:hover { background: var(--c-primary-light); color: var(--c-primary); }
.search-row .ico { color: var(--c-text-secondary); }

/* ============== Toast ============== */
.toast {
  position: fixed;
  top: 70px; left: 50%;
  transform: translateX(-50%) translateY(-12px);
  background: rgba(50,50,50,.92);
  color: #fff;
  padding: 10px 20px;
  border-radius: var(--r-md);
  font-size: 13px;
  pointer-events: none;
  opacity: 0;
  transition: all .25s ease;
  z-index: 300;
  box-shadow: var(--shadow-md);
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ============== 房源名称 tooltip ============== */
.house-name { cursor: help; }
.todo-row-actions { margin-top: 6px; }
.btn-mini {
  background: var(--c-success); color: #fff; border: 0; padding: 3px 10px;
  border-radius: var(--r-sm); font-size: 12px; cursor: pointer;
  transition: opacity .15s ease;
}
.btn-mini:hover { opacity: .85; }
.badge-paid { color: var(--c-success); font-size: 12px; font-weight: 600; }
.todo-empty { padding: 60px 0; text-align: center; color: var(--c-text-secondary); }

/* ============== 详情弹窗 / 表单弹窗 / 子页面 ============== */
/* 🔴 批次77：宽度收口到 .modal-sm/md/lg/xl 四档。
   这里原来按「弹窗用途」各写一套 max-width（560 / 1100 / 920 !important），
   和宽度档位打架 —— 用途和尺寸本来就是两件事，不该绑在一起。 */
.modal-bill, .modal-form, .modal-page { max-width: 100%; }
/* 批次62：详情弹层里要放 7~9 列的表格（供应商付款记录），560px 会把右边几列裁掉。
   .modal-wide 由调用方在 openInfoModal 之后临时加上，openInfoModal 每次打开都会先清掉，
   所以不会污染其它页面的详情弹层。 */
.modal-wide { width: 900px; max-width: 100%; }

/* ============== 整页视图（菜单点击 → 渲染到 .content 内的 #pageView） ============== */
.page-view {
  padding: 16px 20px 24px;
  min-height: 100%;
  animation: pv-fade .18s ease-out;
}
@keyframes pv-fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.page-view .pv-bread {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--c-text-secondary);
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--c-border);
}
.page-view .pv-bread .pv-ico { color: var(--c-text-secondary); }
.page-view .pv-bread .pv-crumb { color: var(--c-text-regular); }
.page-view .pv-bread .pv-cur { color: var(--c-primary); font-weight: 600; }
.page-view .pv-bread .pv-sep { color: var(--c-text-placeholder); }

/* pageView 内的子元素继承原页面宽度，不被 max-width 限制 */
.page-view .h-page, .page-view .modal-page, .page-view .modal-bill {
  max-width: none !important;
  width: 100%;
}
/* 🔴 批次77：这里原来又写了一份 .modal-foot（padding 12/20、gap 10），
   把上面 932 行那份盖掉了 —— 弹窗底部内距和间距因此有两套值。已删，只留 932 那份。
   ⚠ 原来这里还有一份 .btn-ghost / .btn-primary 的几何定义（height/padding/radius），
   实测被 2850 行那套「按钮令牌层」（--btn-h / --btn-px / --btn-r + !important）全部盖掉，
   写了也不生效 —— 已删。弹窗按钮的尺寸圆角统一由令牌层管，本批只把 --btn-r 从 6px 调到 8px
   （6px 的按钮配 8px 的输入框和 12px 的弹窗，圆角三档互不相干，是「不精致」的典型来源）。 */

.bill-detail-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.bill-house { font-size: 16px; font-weight: 600; color: var(--c-text); }
.bill-status { font-size: 12px; padding: 3px 10px; border-radius: 12px; }
.bill-status.paid { background: var(--c-success); color: #fff; }
.bill-status.unpaid { background: var(--c-danger-light); color: var(--c-danger); }
.bill-detail-amount { font-size: 28px; font-weight: 700; color: var(--c-danger); margin-bottom: 16px; }
.bill-detail-meta {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px 16px;
  background: var(--c-bg); padding: 14px; border-radius: var(--r-md); margin-bottom: 14px;
}
.bill-detail-meta > div { display: flex; justify-content: space-between; font-size: 13px; }
.bill-detail-meta span { color: var(--c-text-secondary); }
.bill-detail-meta b { color: var(--c-text); font-weight: 600; }
.bill-detail-meta .red { color: var(--c-danger); }
.bill-detail-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* 动态表单（#formModal 用）：标签在上，垂直堆叠。
   🔴 批次77：和 .st-form-row（标签在左）是两种合法布局，但控件规格必须完全一致 ——
   高度 36 / 圆角 8 / 字号 13 / 边框 #D0D5DD。原来这里是 7px 10px + 圆角 6，和左边那套对不上。 */
.dyn-form { display: grid; gap: 16px; align-content: start; }
/* 批次89：字段多的表单两列排（由 openFormModal 按字段数自动加类）。
   ⚠ 只写 grid-template-columns 不够 —— 两列里塞一个 textarea 会把同行另一格拉高，
   所以 .wide（textarea / 显式 wide:true）必须跨满整行。 */
.dyn-form.dyn-form--2col { grid-template-columns: 1fr 1fr; column-gap: 18px; }
.dyn-form--2col > .dyn-field.wide { grid-column: 1 / -1; }
/* 窄屏（手机 / 分屏）一律回到单列，两列在 340px 宽里每格只剩 160px，反而更难填 */
@media (max-width: 720px) {
  .dyn-form.dyn-form--2col { grid-template-columns: 1fr; }
}
.dyn-field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.dyn-field > label {
  font-size: 13px; font-weight: 500; color: #475467; line-height: 20px;
  display: flex; align-items: baseline; gap: 2px;
}
.dyn-field input, .dyn-field select, .dyn-field textarea {
  width: 100%; height: 36px; box-sizing: border-box;
}
.dyn-field textarea { height: auto; min-height: 88px; padding: 8px 11px; line-height: 1.65; resize: vertical; }
.dyn-field input[type=number] { text-align: right; font-variant-numeric: tabular-nums; }
.dyn-field .invalid { border-color: #F04438; box-shadow: 0 0 0 3px rgba(240,68,56,.1); }

/* ============== 多视频字段（批次114） ==============
   房源视频：一个「已上传列表」+ 一个上传按钮。
   刻意不做成拖拽区 —— 管理端主要在电脑上批量改房源，拖拽区占高度还容易误触。 */
.dyn-media { display: flex; flex-direction: column; gap: 10px; }
.dyn-media-list { display: flex; flex-direction: column; gap: 8px; }
.dyn-media-empty {
  font-size: 12.5px; color: #98A2B3; line-height: 1.7;
  background: #F8FAFC; border: 1px dashed #DCE3EC; border-radius: 8px; padding: 12px 14px;
}
.dyn-media-item {
  display: flex; align-items: center; gap: 12px;
  border: 1px solid var(--c-border); border-radius: 8px; padding: 8px 10px; background: #fff;
}
.dyn-media-item video {
  width: 108px; height: 62px; flex: 0 0 auto; border-radius: 6px;
  background: #0F172A; object-fit: cover;
}
.dyn-media-meta { flex: 1; min-width: 0; }
.dyn-media-name { font-size: 13px; color: var(--c-text); font-weight: 500; }
.dyn-media-url {
  font-size: 11.5px; color: #98A2B3; margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dyn-media-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dyn-media-hint { font-size: 12px; color: #98A2B3; line-height: 1.6; }
.pm-act-btn.danger { color: #B42318; border-color: #F3C9C4; }
.pm-act-btn.danger:hover { background: #FEF3F2; }

/* ============== 动态表格 ============== */
.dyn-table { width: 100%; border-collapse: collapse; font-size: 13px; table-layout: auto; }
.dyn-table th, .dyn-table td {
  padding: 9px 10px; border-bottom: 1px solid var(--c-border); text-align: left;
  white-space: nowrap;
}
.dyn-table th { background: var(--c-bg); color: var(--c-text-regular); font-weight: 600; }
.dyn-table tr:hover td { background: var(--c-bg); }

/* 表格外层（包装在审批/线索/巡房等页面的表格区域）：允许横向滚动 */
.rev-table, .be-table, .bp-table, .cp-table, .pt-table, .lead-table, .approval-table {
  overflow-x: auto;
  background: #fff;
  border-radius: var(--r-md);
  border: 1px solid var(--c-border-light);
}
.rev-table .dyn-table, .be-table .dyn-table, .bp-table .dyn-table,
.cp-table .dyn-table, .pt-table .dyn-table, .lead-table .dyn-table,
.approval-table .dyn-table { min-width: 900px; }

/* 收房管理表格（11 列，原网站真实结构） */
.rev-tbl th, .rev-tbl td { padding: 9px 8px; font-size: 13px; }
.rev-tbl td:nth-child(2) { min-width: 260px; color: var(--c-text-regular); }
.rev-house-status { padding: 4px 8px; font-size: 12px; border-radius: 4px; border: 1px solid var(--c-border); background: #fff; color: var(--c-text-regular); }

/* 批量编辑表格（12 列，原网站真实结构） */
.be-tbl th, .be-tbl td { padding: 7px 6px; font-size: 12px; }
.be-input { padding: 4px 6px; font-size: 12px; border: 1px solid var(--c-border); border-radius: 4px; }
.be-mini { padding: 3px 6px; font-size: 12px; border: 1px solid var(--c-border); border-radius: 4px; background: #fff; }
.be-edit-btn { padding: 4px 12px; font-size: 12px; background: var(--c-primary); color: #fff; border: 0; border-radius: 4px; cursor: pointer; }
.be-toggle { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; color: var(--c-text-regular); }

/* 行内编辑输入框（批量编辑 / 批量定价共用） */
.be-tbl .be-in, .bp-tbl .bp-in {
  width: 100%; min-width: 56px; max-width: 120px;
  padding: 4px 6px; font-size: 12px;
  border: 1px solid var(--c-border); border-radius: 4px;
  background: #fff; color: var(--c-text-regular);
}
.bp-tbl .bp-in { max-width: 90px; }
.be-tbl .be-in:focus, .bp-tbl .bp-in:focus { border-color: var(--c-primary); outline: none; }
/* 有未保存改动的行 */
tr.be-dirty { background: #fff8e6 !important; }
tr.be-dirty td:first-child { box-shadow: inset 3px 0 0 var(--c-primary); }
.be-tbl .be-save-one, .bp-tbl .bp-save { white-space: nowrap; }
.be-tbl td:first-child, .bp-tbl td:first-child { text-align: center; }

/* 批量定价表格（11 列，原网站真实结构） */
.bp-tbl th, .bp-tbl td { padding: 7px 6px; font-size: 12px; }
.bp-in { width: 70px; padding: 4px 6px; font-size: 12px; border: 1px solid var(--c-border); border-radius: 4px; background: #fff; }
.bp-save { padding: 4px 12px; font-size: 12px; background: var(--c-primary); color: #fff; border: 0; border-radius: 4px; cursor: pointer; }

/* 包房管理 + 巡房管理 */
.cp-stats-row { display: flex; gap: 14px; padding: 14px 20px 6px; flex-wrap: wrap; }
.cp-stat-card { background: #fff; border: 1px solid var(--c-border); border-radius: 8px; padding: 14px 18px; min-width: 140px; }
.cp-stat-num { font-size: 22px; font-weight: 700; color: var(--c-primary); }
.cp-stat-suf { font-size: 13px; color: var(--c-text-secondary); margin-left: 4px; font-weight: 400; }
.cp-stat-label { font-size: 12px; color: var(--c-text-secondary); margin-top: 4px; }
.cp-tbl th, .cp-tbl td { padding: 9px 8px; font-size: 13px; }
.cp-detail, .cp-renew, .pt-detail { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.cp-detail:hover, .cp-renew:hover, .pt-detail:hover { color: var(--c-primary); border-color: var(--c-primary); }

.pt-tbl th, .pt-tbl td { padding: 9px 8px; font-size: 13px; }
.pt-tbl td:nth-child(2) { min-width: 220px; }

/* 批次76：这里原来把 .badge.ok 定义成**品牌蓝**、.badge.warn 定义成**红**，
   和 2139 行那套（绿/琥珀/蓝）完全相反。两套定义谁生效取决于书写顺序，
   改一处另一处就反噬 —— 上一批「标记已收」变蓝底就是这个原因。
   现在只保留几何属性，颜色统一交给 2139 行那一套。 */
.badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 12px; }

/* ============== 审批中心（1:1 复刻原网站 approval）============== */
.ap-tbl th, .ap-tbl td { padding: 9px 8px; font-size: 13px; }
.ap-tbl td:nth-child(3) { min-width: 320px; color: var(--c-text-regular); }
.ap-tbl td:nth-child(5), .ap-tbl td:nth-child(6) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }

.ap-pass, .ap-reject, .ap-detail { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.ap-pass { color: var(--c-success); border-color: var(--c-success); }
.ap-pass:hover { background: var(--c-success); color: #fff; }
.ap-reject { color: var(--c-danger); border-color: var(--c-danger); }
.ap-reject:hover { background: var(--c-danger); color: #fff; }
.ap-detail:hover { color: var(--c-primary); border-color: var(--c-primary); }

.ap-feature { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 28px 32px; }
.ap-feature h3 { font-size: 18px; color: var(--c-text); margin-bottom: 14px; }
.ap-feature p { color: var(--c-text-regular); line-height: 1.8; margin-bottom: 10px; }
.ap-feature ul { list-style: none; padding: 0; }
.ap-feature li { padding: 10px 0; border-bottom: 1px dashed var(--c-border-light); color: var(--c-text-regular); line-height: 1.7; }
.ap-feature li b { color: var(--c-primary); margin-right: 6px; }

/* ============== 线索（租客/业主）1:1 复刻 ============== */
.lead-tbl th, .lead-tbl td { padding: 9px 8px; font-size: 13px; }
.lead-tbl td:nth-child(2) { font-family: 'SFMono-Regular', Consolas, monospace; }
.lead-tbl td:nth-child(10), .lead-tbl td:nth-child(11) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }

.lead-detail, .lead-follow { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.lead-detail:hover, .lead-follow:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* ============== 合同模块 4 页面（1:1 复刻原网站 contract/manage/*）============== */
.ct-table, .cr-table, .co-table, .cp-table { overflow-x: auto; background: #fff; border-radius: var(--r-md); border: 1px solid var(--c-border-light); }
.ct-table .dyn-table, .cr-table .dyn-table, .co-table .dyn-table, .cp-table .dyn-table { min-width: 960px; }

.ct-tbl th, .ct-tbl td, .cr-tbl th, .cr-tbl td, .co-tbl th, .co-tbl td, .cp-tbl th, .cp-tbl td { padding: 9px 8px; font-size: 13px; }
/* 注意：租客/业主合同表已加「勾选」列（第 1 列），因此下面 nth-child 均 +1 */
.ct-tbl td:nth-child(4), .co-tbl td:nth-child(4), .cp-tbl td:nth-child(1) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }
.cr-tbl td:nth-child(3), .cr-tbl td:nth-child(4), .cr-tbl td:nth-child(5), .cr-tbl td:nth-child(6) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }
.ct-tbl td:nth-child(6), .ct-tbl td:nth-child(7), .co-tbl td:nth-child(6), .co-tbl td:nth-child(7), .cp-tbl td:nth-child(5) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }

/* 合同勾选列 + 批量操作条 */
.ct-tbl th.ct-ck, .ct-tbl td.ct-ck, .co-tbl th.ct-ck, .co-tbl td.ct-ck { width: 34px; text-align: center; padding-left: 6px; padding-right: 4px; }
.ct-tbl td.ct-ck input, .co-tbl td.ct-ck input { cursor: pointer; }
.ct-batch {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 14px; margin-bottom: 10px;
  background: var(--c-primary-light); border: 1px solid #c9d8ff; border-radius: 8px;
}
.ct-batch-info { font-size: 13px; color: var(--c-text-regular); }
.ct-batch-info b { color: var(--c-primary); font-size: 15px; }
.ct-batch .btn-ghost, .ct-batch .btn-primary { height: 30px !important; padding: 0 14px !important; font-size: 13px; }

.ct-detail, .ct-edit, .cr-detail, .cr-sign, .co-detail, .co-renew, .cp-detail, .cp-renew {
  padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px;
}
.ct-detail:hover, .ct-edit:hover, .cr-detail:hover, .cr-sign:hover, .co-detail:hover, .co-renew:hover, .cp-detail:hover, .cp-renew:hover {
  color: var(--c-primary); border-color: var(--c-primary);
}

.h-dash { padding: 0 4px; color: var(--c-text-secondary); font-size: 12px; align-self: center; }

/* ============== 公告列表 ============== */
.ann-list { display: grid; gap: 12px; }
.ann-item { padding: 12px; border: 1px solid var(--c-border); border-radius: var(--r-md); }
.ann-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.ann-head b { color: var(--c-text); font-size: 14px; }
.ann-head span { color: var(--c-text-secondary); font-size: 12px; }
.ann-body { color: var(--c-text-regular); font-size: 13px; line-height: 1.7; }
.ann-foot { margin-top: 6px; color: var(--c-text-secondary); font-size: 12px; }

/* ============== 日程列表 ============== */
.schedule-list { display: grid; gap: 8px; }
.schedule-row {
  display: grid; grid-template-columns: 60px 1fr 60px; align-items: center; gap: 8px;
  padding: 8px; background: var(--c-bg); border-radius: var(--r-md);
}
.s-time { font-weight: 600; color: var(--c-primary); }
.s-title { color: var(--c-text); }
.s-tag {
  font-size: 12px; padding: 2px 8px; border-radius: 10px;
  background: var(--c-primary-light); color: var(--c-primary); text-align: center;
}

/* ============== 搜索结果 ============== */
.search-row-body { display: flex; flex-direction: column; }
.search-row-title { color: var(--c-text); font-size: 13px; }
.search-row-sub { color: var(--c-text-secondary); font-size: 12px; margin-top: 2px; }

/* ============== Toast 增强 ============== */
.toast-success { background: var(--c-success) !important; }
.toast-error { background: var(--c-danger) !important; }
/* 批次57：warn = 操作已完成但有折扣（如「催租只发了站内消息，短信未开通」） */
.toast-warn { background: #E8890C !important; }

/* ============== 出房管理 / 空房快查（1:1 复刻原网站）============== */
.h-page { padding: 0; }
.h-toolbar { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--c-border-light); margin-bottom: 12px; flex-wrap: wrap; }
.h-tabs { display: flex; gap: 4px; flex-shrink: 0; flex-wrap: nowrap; }
.h-tab { background: transparent; border: 1px solid var(--c-border); padding: 6px 14px; border-radius: var(--r-sm); cursor: pointer; font-size: 13px; color: var(--c-text-regular); transition: all .15s; white-space: nowrap; flex-shrink: 0; }
.h-tab:hover { border-color: var(--c-primary); color: var(--c-primary); }
.h-tab.active { background: var(--c-primary); color: #fff; border-color: var(--c-primary); }
.h-search { flex: 1; display: flex; gap: 8px; max-width: 460px; }
.h-select, .h-input { border: 1px solid var(--c-border); padding: 6px 10px; border-radius: var(--r-sm); font-size: 13px; outline: none; background: #fff; }
.h-input { flex: 1; }
.h-tools { display: flex; gap: 6px; margin-left: auto; flex-shrink: 0; flex-wrap: nowrap; }
.h-tool { background: transparent; border: 1px solid var(--c-border); width: 32px; height: 32px; border-radius: var(--r-sm); cursor: pointer; color: var(--c-text-regular); font-size: 14px; flex-shrink: 0; }
.h-tool:hover { border-color: var(--c-primary); color: var(--c-primary); }
.h-tool.h-tool-text { width: auto; padding: 0 14px; white-space: nowrap; flex-shrink: 0; }
.h-tools .h-select { height: 32px; padding: 0 10px; }

.h-main { display: grid; grid-template-columns: 1fr 256px; gap: 12px; align-items: start; }
.h-list { min-height: 480px; padding-right: 8px; }

/* ---- 房屋卡片（1:1 复刻原站 .panel.card：188x100 / 左 3px 状态色条 / 整块浅色底）---- */
.h-card-group { margin-bottom: 14px; }
.h-card-group-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px; height: 20px;
}
.h-card-group-title { font-size: 13px; color: var(--c-text); }
.h-card-group-actions { display: flex; align-items: center; gap: 6px; }
.h-more-btn {
  display: inline-flex; align-items: center; gap: 2px;
  height: 20px; padding: 0 4px;
  border: 1px solid #eeeeee; border-radius: 2px;
  background: #fff; color: var(--c-text-regular);
  font-size: 12px; line-height: 18px;
}
.h-more-btn:hover { border-color: var(--c-primary); color: var(--c-primary); }
.h-more-btn .ico { width: 10px; height: 10px; }
.h-eye-btn {
  width: 20px; height: 20px; display: inline-flex;
  align-items: center; justify-content: center;
  border: 0; background: none; color: #667085; cursor: pointer;
}
.h-eye-btn:hover { color: var(--c-primary); }
.h-eye-btn .ico { width: 15px; height: 15px; }

/* 批次106：列宽改成 minmax(210px, 1fr)。原来是固定 220px，容器 1070px 只铺到 660px，
   右侧 400px 空白看起来像「没排满」。改成 1fr 让每列把剩余宽度均分 ——
   同一屏仍是 4 列，但卡片铺到右边界，网格读起来是「一整片」，不是「左边一坨」。 */
.h-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
/* 批次106：卡片基样式重做。
   ⚠ 原来这里是「浅色 pastel 底 + 左侧 3px 彩色竖条」，靠一条通栏色带表达房态。
     那种写法有三个问题：
       ① 一屏 30 张卡 = 30 条彩色竖条，视觉噪音极大，像廉价模板；
       ② 竖条占掉 3px 内容宽，188px 的卡本来就窄；
       ③ 色带是「装饰性」的强色块，和卡片里真正要看的房号/租金抢注意力。
     现在改成：白底 + 1px 中性描边 + 状态用 7px 圆点表达（见 .h-card-state::before）。
     颜色语义保留，但收敛到一个点，卡片整体安静下来。 */
.h-card {
  position: relative; height: 118px;
  border-radius: 8px; border: 1px solid #E9EDF5;
  background: #fff; padding: 0;
  overflow: hidden; cursor: pointer;
  box-shadow: 0 1px 2px rgba(16,24,40,.03);
  transition: border-color .15s, box-shadow .15s;
}
.h-card:hover { border-color: #C7D2E4; box-shadow: 0 2px 4px rgba(16,24,40,.05), 0 8px 20px rgba(16,24,40,.07); }
/* 批次87：新建房源后高亮刚建的那一张卡，让用户一眼看到「建的东西在哪」。
   用 box-shadow 描边而不是改背景 —— 批次106 之前卡片背景带房态语义
   （在租青 / 空置橙 / 不可租红），覆盖背景等于用「看得见」换掉了「看得对」；
   现在背景虽然是白的，描边仍然是更轻的做法，不必为了高亮去改底色。 */
.h-card.jxy-flash {
  box-shadow: 0 0 0 2px var(--c-primary, #2F6BFF), 0 4px 14px rgba(47,107,255,.28);
  animation: jxy-flash-pulse 1.1s ease-in-out 4;
}
@keyframes jxy-flash-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--c-primary, #2F6BFF), 0 4px 14px rgba(47,107,255,.28); }
  50%      { box-shadow: 0 0 0 4px rgba(47,107,255,.45), 0 6px 18px rgba(47,107,255,.34); }
}
@media (prefers-reduced-motion: reduce) {
  .h-card.jxy-flash { animation: none; }
}
/* 批次88：同样的「刚建的就是这一条」提示，用在表格行上（客源 / 预定 / 账单）。
   ⚠ 批次87 只写了 `.h-card.jxy-flash`，探针断言的是 classList 里有这个类，
     所以断言是绿的、截图上却什么都看不见 —— 属于「有反应但反应是错的」的变种：
     class 挂上了，样式不生效。表格行没有卡片背景色语义，可以放心改背景。 */
tr.jxy-flash > td {
  background: #eaf1ff !important;
  box-shadow: inset 0 0 0 1px rgba(47,107,255,.55);
  animation: jxy-row-flash 1.1s ease-in-out 4;
}
tr.jxy-flash > td:first-child { box-shadow: inset 2px 0 0 0 var(--c-primary, #2F6BFF); }
@keyframes jxy-row-flash {
  0%, 100% { background: #eaf1ff; }
  50%      { background: #d8e6ff; }
}
@media (prefers-reduced-motion: reduce) {
  tr.jxy-flash > td { animation: none; }
}
/* 批次106：房态不再用底色表达。
   ⚠ 原来这四行是 pastel 底色（#d1f2f2 青 / #fff4ec 橙 / #feefef 粉 / #f2f3f5 灰）+ 左侧描边色。
     底色表达状态是「AI 味」最典型的指纹：一屏 30 张卡就是 30 块彩色便利贴，
     颜色之间没有规律，读者的眼睛先被色块抓走，反而找不到房号和租金。
     现在底色统一纯白（容器只负责「这是一张卡」），房态交给底部 7px 圆点 + 文字。 */
.h-card.living-house,
.h-card.reserve-house,
.h-card.empty-house,
.h-card.gray-house { background: #fff; }
.h-card-head { display: flex; align-items: center; height: 20px; padding: 0; }
.h-card-status-ico { width: 16px; height: 16px; color: #555; }
.h-card-name {
  margin-left: 0; font-size: 13px; font-weight: 600; color: var(--c-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 118px;
  font-variant-numeric: tabular-nums;
}
/* 租客名：原来塞在价格行右边（`.h-card-price em`），和「4,500/月」同一基线，
   读起来像价格的注释。挪到头部右侧，和房号构成「哪一间 · 谁住」一行。 */
.h-card-tenant {
  margin-left: auto; font-size: 12px; color: var(--c-text-secondary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 66px;
}
.h-card-avatar {
  margin-left: auto; width: 18px; height: 18px; border-radius: 50%;
  display: block; flex-shrink: 0; object-fit: cover; background: #EAF1FE;
}
.h-card-body { padding: 0; }
.h-card-price {
  font-size: 12px; color: var(--c-text); line-height: 18px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.h-card-meta { font-size: 12px; color: var(--c-text-secondary); line-height: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.h-card-foot { display: flex; align-items: center; justify-content: space-between; height: 20px; font-size: 12px; color: var(--c-text-secondary); }
.h-card-tags { display: flex; gap: 3px; }
.h-card-tag { width: 15px; height: 15px; border-radius: 3px; color: var(--c-text-secondary); background: #F2F4F7; font-size: 10px; line-height: 15px; text-align: center; }
.cell-sub { font-size: 12px; color: var(--c-text-secondary); }
.meter-off { color: var(--c-text-placeholder); font-size: 12px; }

.h-count-chip {
  position: sticky; bottom: 0; margin: 12px auto 0; width: fit-content;
  background: #000; color: #fff; font-size: 12px;
  border-radius: 4px; padding: 2px 8px;
}
/* 出房管理：加载更多 / 已到底 */
.h-list { max-height: calc(100vh - 190px); overflow-y: auto; }
.h-loadmore-wrap { text-align: center; padding: 14px 0 6px; }
.h-loadmore {
  border: 1px solid var(--c-border); background: #fff; color: var(--c-primary);
  font-size: 12.5px; padding: 6px 22px; border-radius: 16px; cursor: pointer;
}
.h-loadmore:hover { border-color: var(--c-primary); background: #f2f6ff; }
.h-nomore { font-size: 12px; color: var(--c-text-placeholder); }
.h-cards-flat { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 10px; margin-bottom: 10px; }
.f-check .f-cnt { color: var(--c-text-secondary); margin-left: auto; }

/* 右侧筛选面板 */
.h-filter { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 0; height: fit-content; }
.f-section { padding: 10px 12px; border-bottom: 1px solid var(--c-border-light); }
.f-section:last-child { border-bottom: none; }
.f-title { font-weight: 600; font-size: 13px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; }
.f-clear { color: var(--c-primary); font-size: 12px; cursor: pointer; font-weight: normal; }
.f-row { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 6px; }
.f-sel { border: 1px solid var(--c-border); padding: 5px 8px; border-radius: var(--r-sm); font-size: 12px; background: #fff; }
.f-radio, .f-check { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--c-text-regular); margin-bottom: 4px; cursor: pointer; line-height: 20px; }
.f-radio input, .f-check input { margin: 0; }
.f-radio .f-cnt { color: var(--c-text-secondary); margin-left: auto; }
.f-ico { display: inline-flex; align-items: center; gap: 4px; }
.f-tag { display: inline-block; width: 16px; height: 16px; line-height: 16px; text-align: center; border-radius: 3px; font-size: 11px; margin-right: 4px; }

/* 空房快查 */
.h-quick-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 12px; }
.h-quick-stat { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 12px; }
.h-quick-stat-label { font-size: 12px; color: var(--c-text-secondary); }
.h-quick-stat-num { font-size: 22px; font-weight: 700; color: var(--c-primary); margin-top: 4px; }
/* 批次111：空房总数与「可租」不一致时，在数字下面补一行小字说明差在哪 */
.h-quick-sub { font-size: 11.5px; color: var(--c-warning-text); margin-top: 2px; }
.h-quick-table { background: #fff; border-radius: var(--r-md); overflow: hidden; }

/* 响应式 */
@media (max-width: 1100px) {
  .h-main { grid-template-columns: 1fr; }
  .h-filter { max-height: 320px; }
}

/* ============== 推广模块 / 会员 / 网签 / 社群 / 设置 1:1 复刻 ============== */

/* KPI 卡片（推广-流量顶部） */
.kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 14px; }
.kpi-card { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 18px 20px; }
.kpi-card .kpi-label { font-size: 13px; color: var(--c-text-secondary); margin-bottom: 8px; }
.kpi-card .kpi-num { font-size: 26px; font-weight: 700; color: var(--c-text); line-height: 1.2; }
.kpi-card .kpi-unit { font-size: 13px; color: var(--c-text-secondary); margin-left: 4px; font-weight: 400; }
.kpi-card .kpi-extra { font-size: 12px; color: var(--c-text-secondary); margin-top: 6px; }
.kpi-card.kpi-blue .kpi-num { color: var(--c-primary); }
.kpi-card.kpi-green .kpi-num { color: var(--c-success); }
.kpi-card.kpi-orange .kpi-num { color: #ff9500; }
.kpi-card.kpi-red .kpi-num { color: var(--c-danger); }

/* 通用表格外层 */
.pf-table, .pm-table, .ps-table, .pd-table, .mt-table, .ns-table, .cf-table, .cu-table {
  overflow-x: auto;
  background: #fff;
  border-radius: var(--r-md);
  border: 1px solid var(--c-border-light);
}
.pf-table .dyn-table, .pm-table .dyn-table, .ps-table .dyn-table,
.pd-table .dyn-table, .mt-table .dyn-table, .ns-table .dyn-table,
.cf-table .dyn-table, .cu-table .dyn-table { min-width: 920px; }

/* 推广-流量 */
.pf-tbl th, .pf-tbl td { padding: 9px 8px; font-size: 13px; }
.pf-tbl td:nth-child(4), .pf-tbl td:nth-child(5),
.pf-tbl td:nth-child(6), .pf-tbl td:nth-child(7),
.pf-tbl td:nth-child(8) { font-family: 'SFMono-Regular', Consolas, monospace; text-align: right; }

/* 推广-营销 */
.pm-tbl th, .pm-tbl td { padding: 9px 8px; font-size: 13px; }
.pm-tbl td:nth-child(1) { min-width: 200px; color: var(--c-text); font-weight: 600; }
.pm-tbl td:nth-child(4), .pm-tbl td:nth-child(5) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }
.pm-act-btn { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.pm-act-btn:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* 推广-试住结算 */
.ps-tbl th, .ps-tbl td { padding: 9px 8px; font-size: 13px; }
.ps-tbl td:nth-child(1) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }
.ps-tbl td:nth-child(5), .ps-tbl td:nth-child(6), .ps-tbl td:nth-child(7) { font-family: 'SFMono-Regular', Consolas, monospace; text-align: right; }

/* 推广-分销 */
.pd-tbl th, .pd-tbl td { padding: 9px 8px; font-size: 13px; }
.pd-tbl td:nth-child(5), .pd-tbl td:nth-child(6), .pd-tbl td:nth-child(7) { font-family: 'SFMono-Regular', Consolas, monospace; text-align: right; }
.pd-act-btn { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.pd-act-btn:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* 会员-人才轮候 */
.mt-tbl th, .mt-tbl td { padding: 9px 8px; font-size: 13px; }
.mt-tbl td:nth-child(2) { font-family: 'SFMono-Regular', Consolas, monospace; }
.mt-tbl td:nth-child(7), .mt-tbl td:nth-child(8) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }
.mt-act-btn { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.mt-act-btn:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* 网签-合同管理 */
.ns-tbl th, .ns-tbl td { padding: 9px 8px; font-size: 13px; }
.ns-tbl td:nth-child(1), .ns-tbl td:nth-child(6) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; color: var(--c-text-secondary); }
.ns-act-btn { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.ns-act-btn:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* 社群-租客评价 */
.cf-tbl th, .cf-tbl td { padding: 9px 8px; font-size: 13px; }
.cf-rating { color: #ff9500; font-size: 14px; letter-spacing: 1px; }
.cf-content { color: var(--c-text-regular); max-width: 360px; overflow: hidden; text-overflow: ellipsis; }
.cf-act-btn { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.cf-act-btn:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* 社群-活动 */
.cu-tbl th, .cu-tbl td { padding: 9px 8px; font-size: 13px; }
.cu-tbl td:nth-child(1) { min-width: 180px; color: var(--c-text); font-weight: 600; }
.cu-act-btn { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.cu-act-btn:hover { color: var(--c-primary); border-color: var(--c-primary); }

/* 设置-账号设置 多 Tab 表单 */
/* 🔴 批次77 重写要点（改前 → 改后）：
 *   标签宽 140 → 96（140 太宽，控件右边空出 200px，整个表单「左重右轻」）
 *   align-items center → start（原来 textarea 时标签飘到框中间，topΔ=-32）
 *   控件无宽度 → width:100%（原来 input 171 / select 98 / 房源 338 三种宽度混排）
 *   控件高度随内容 → 统一 36px（原来 input 35 / select 37 / date 33 三套）
 *   帮助文字内联 → block 换行（内联时被挤到控件右侧撑爆）
 *   无必填标记 → 标签后 <em class="req">*</em>
 */
.st-form { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 24px 28px; }
.st-form h3 { font-size: 16px; color: var(--c-text); margin-bottom: 18px; padding-bottom: 12px; border-bottom: 1px solid var(--c-border-light); }
.st-form-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 12px;
  margin-bottom: 16px;
  align-items: start;
}
.st-form-row > label {
  font-size: 13px; font-weight: 500; color: #475467;
  line-height: 20px;
  padding-top: 8px;              /* 8 + 20 行高 → 标签文字与 36px 控件内的文字同一基线 */
  text-align: right;
  display: flex; align-items: baseline; justify-content: flex-end;
  min-width: 0;
}
/* 必填星号：跟在标签文字后面，不在前面（原来「*关联合同」星号贴着字，像标签的一部分） */
.st-form-row > label .req,
.dyn-field > label .req {
  color: #D92D20; font-style: normal; font-weight: 400;
  margin-left: 2px; flex: 0 0 auto;
}
.st-form-ctl { min-width: 0; }
/* 批次96：必须排除 checkbox / radio。
   原来这条命中 `.st-form-row` 里所有 input，把单选框、复选框也撑成 width:100% + height:36px
   → 圆点变成 49×36 的大方块盖在「租客/业主」文字上，勾选框变成一个大方框浮在条款文字旁边。
   单选/复选只该有原生尺寸。 */
.st-form-row input:not([type=checkbox]):not([type=radio]),
.st-form-row select,
.st-form-row textarea {
  width: 100%;
  height: 36px;
  max-width: none;
  box-sizing: border-box;
}
.st-form-row input[type=checkbox],
.st-form-row input[type=radio] {
  width: auto;
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  flex: 0 0 auto;
}
.st-form-row textarea { height: auto; min-height: 88px; padding: 8px 11px; line-height: 1.65; resize: vertical; }
/* 数字类字段右对齐（批次76 的对齐铁律：金额/数字列右对齐 + 等宽数字） */
.st-form-row input[type=number] { text-align: right; font-variant-numeric: tabular-nums; }
.st-form-row .st-tip { display: block; color: var(--c-text-secondary); font-size: 12px; line-height: 1.6; margin: 6px 0 0; }
.st-form-save { padding: 8px 22px; background: var(--c-primary); color: #fff; border: 0; border-radius: var(--r-sm); cursor: pointer; font-size: 13px; }
.st-form-save:hover { background: var(--c-primary-hover); }

/* ============== 顶部「+ 新建」下拉菜单（1:1 复刻原网站）============== */
.topbar-create { position: relative; display: inline-block; }
.btn-create-arrow { margin-left: 4px; font-size: 10px; transition: transform .15s; display: inline-block; }
.topbar-create.open .btn-create-arrow { transform: rotate(180deg); }

/* 一级面板（紧贴按钮下方） */
.create-dropdown {
  position: absolute; top: calc(100% + 6px); right: 0;
  min-width: 180px; background: #fff; border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.06);
  border: 1px solid var(--c-border-light);
  padding: 6px 0; z-index: 999; display: none;
}
.topbar-create.open .create-dropdown { display: block; }

/* 单个菜单项 */
.cd-item {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 18px; font-size: 14px; color: var(--c-text-regular);
  cursor: pointer; transition: background .12s; white-space: nowrap;
}
.cd-item:hover { background: var(--c-bg); color: var(--c-primary); }
.cd-item .cd-arrow { color: var(--c-text-secondary); font-size: 10px; margin-left: 12px; }
.cd-item:hover .cd-arrow { color: var(--c-primary); }

/* 二级子菜单（hover 向右展开） */
.cd-sub {
  position: absolute; top: -7px; left: 100%;
  min-width: 180px; background: #fff; border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.06);
  border: 1px solid var(--c-border-light);
  padding: 6px 0;
  display: none;
}
/* 🔴 触屏没有 hover：父项靠点击 toggle .sub-open（见 script.js bindTopbarCreateDropdown）。
   以前只有 :hover 一条路，触屏点「批量操作」「新建合同」完全没反应。 */
.cd-item:hover > .cd-sub,
.cd-item.sub-open > .cd-sub { display: block; }
.cd-item.sub-open { background: var(--c-bg); color: var(--c-primary); }
.cd-item.sub-open .cd-arrow { color: var(--c-primary); }
/* 装不下时翻到左边（script.js ensureSubInView 打这个类） */
.cd-item.sub-flip-left > .cd-sub { left: auto; right: 100%; }
.cd-sub .cd-item { padding: 8px 18px; font-size: 13px; }

/* 触屏设备：二级菜单改向左展开 —— 下拉本身 right:0，向右展会跑出屏幕 */
@media (hover: none) {
  .cd-sub { left: auto; right: 100%; }
}

/* 工具栏 / 区域下拉细节 */
.h-search { flex: 1; display: flex; gap: 8px; max-width: 560px; }

/* ============== 财务模块 5 页面（1:1 复刻）============== */
.bm-tbl th, .bm-tbl td { padding: 9px 8px; font-size: 13px; }
.bm-tbl td:nth-child(2) { min-width: 200px; color: var(--c-text-regular); }
.bm-tbl td:nth-child(5), .bm-tbl td:nth-child(6), .bm-tbl td:nth-child(7) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; }
/* 批次76：bm-mark / bm-detail 已改走 .dyn-table .op-btn，这里只剩打印 */
.bm-print { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.bm-print:hover { color: var(--c-primary); border-color: var(--c-primary); }

.bl-tbl th, .bl-tbl td { padding: 9px 8px; font-size: 13px; }
.bl-tbl td:nth-child(3) { min-width: 200px; color: var(--c-text-regular); }
.bl-tbl td:nth-child(5), .bl-tbl td:nth-child(7) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; }

.pa-tbl th, .pa-tbl td { padding: 9px 8px; font-size: 13px; }
.pa-tbl td:nth-child(2) { min-width: 200px; color: var(--c-text-regular); }
.pa-tbl td:nth-child(3), .pa-tbl td:nth-child(5) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; }
.pa-pass, .pa-reject, .pa-detail { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.pa-pass { color: var(--c-success); border-color: var(--c-success); }
.pa-pass:hover { background: var(--c-success); color: #fff; }
.pa-reject { color: var(--c-danger); border-color: var(--c-danger); }
.pa-reject:hover { background: var(--c-danger); color: #fff; }
.pa-detail:hover { color: var(--c-primary); border-color: var(--c-primary); }

.bi-tbl th, .bi-tbl td { padding: 9px 8px; font-size: 13px; }
.bi-tbl td:nth-child(4), .bi-tbl td:nth-child(6) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; }
.bi-issue, .bi-detail, .bi-download { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.bi-issue { color: var(--c-primary); border-color: var(--c-primary); }
.bi-issue:hover { background: var(--c-primary); color: #fff; }
.bi-detail:hover, .bi-download:hover { color: var(--c-primary); border-color: var(--c-primary); }

.bs-tbl th, .bs-tbl td { padding: 9px 8px; font-size: 13px; }
.bs-tbl td:nth-child(1) { min-width: 240px; }
.bs-tbl td:nth-child(4) { font-family: 'SFMono-Regular', Consolas, monospace; }
.bs-detail, .bs-pay { padding: 3px 10px; font-size: 12px; border: 1px solid var(--c-border); background: #fff; border-radius: 4px; cursor: pointer; color: var(--c-text-regular); margin-right: 4px; }
.bs-detail:hover, .bs-pay:hover { color: var(--c-primary); border-color: var(--c-primary); }


/* ============== 报表 / 设备 / 抄表 / 工单 9 页面样式（1:1 复刻）============== */
/* 报表通用：KPI 卡片 */
.rp-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 14px; }
.rp-kpis:has(.rp-kpi:nth-child(6)) { grid-template-columns: repeat(6, 1fr); }
.rp-kpi { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 14px 18px; }
.rp-kpi-label { font-size: 12px; color: var(--c-text-secondary); margin-bottom: 6px; }
.rp-kpi-num { font-size: 22px; font-weight: 700; line-height: 1.2; }
.rp-kpi-suf { font-size: 12px; color: var(--c-text-secondary); margin-top: 4px; }

/* 报表通用：图表占位 */
.rp-charts { display: grid; grid-template-columns: 1.4fr 1fr; gap: 12px; margin-bottom: 14px; }
.rp-chart { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 16px 18px; }
.rp-chart-title { font-weight: 600; font-size: 13px; color: var(--c-text); margin-bottom: 14px; }

/* 柱状图占位 */
.rp-bars { display: flex; align-items: flex-end; justify-content: space-between; height: 160px; gap: 8px; padding-top: 10px; border-bottom: 1px solid var(--c-border-light); }
.rp-bar { flex: 1; background: linear-gradient(180deg, #5fa8ed 0%, #3a8ee6 100%); border-radius: 4px 4px 0 0; position: relative; min-height: 8px; transition: opacity .15s; }
.rp-bar:hover { opacity: .8; }
.rp-bar span { position: absolute; bottom: -22px; left: 50%; transform: translateX(-50%); font-size: 11px; color: var(--c-text-secondary); white-space: nowrap; }
.rp-bar-active { background: linear-gradient(180deg, #ffb84d 0%, #ff9500 100%); }

/* 饼图占位（用 CSS conic-gradient 模拟） */
.rp-pie-wrap { display: flex; align-items: center; gap: 18px; }
.rp-pie {
  width: 140px; height: 140px; border-radius: 50%; flex-shrink: 0;
  background: conic-gradient(
    #3a8ee6 0% 72%,
    #67c23a 72% 84%,
    #e6a23c 84% 92%,
    #909399 92% 97%,
    #ee5252 97% 100%
  );
  position: relative;
}
.rp-pie::after {
  content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 70px; height: 70px; background: #fff; border-radius: 50%;
}
.rp-pie-legend { display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: var(--c-text-regular); }
.rp-pie-legend div { display: flex; align-items: center; gap: 6px; }
.rp-pie-legend i { display: inline-block; width: 12px; height: 12px; border-radius: 2px; }

/* 报表：自适应 KPI 栅格（数量不定时用） */
.rp-kpis-auto { grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)) !important; }

/* 报表：期间说明 */
.rp-period-note { font-size: 12px; color: var(--c-text-secondary); margin: 2px 0 10px; }

/* 报表：工具栏右侧按钮不被压缩 */
.h-page .h-tools { flex-shrink: 0; }
/* 报表：实时快照徽标 */
.rp-live-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: #67C23A; background: rgba(103, 194, 58, .1); border: 1px solid rgba(103, 194, 58, .3); border-radius: 999px; padding: 5px 12px; }
/* 报表：分页条 */
.rp-pager { display: flex; align-items: center; gap: 10px; justify-content: flex-end; padding: 12px 6px 4px; font-size: 12px; color: var(--c-text-secondary); }
.rp-pager .h-tool[disabled] { opacity: .45; cursor: not-allowed; }

/* 报表：图表单列（环形图页） */
.rp-charts-1 { grid-template-columns: 1fr; }

/* 报表：SVG 图表容器 */
.rp-svg-chart { width: 100%; }
.rp-svg-chart svg { width: 100%; height: 190px; display: block; }
.rp-bar-legend { display: flex; gap: 16px; justify-content: center; margin-top: 6px; font-size: 12px; color: var(--c-text-regular); }
.rp-bar-lg { display: inline-flex; align-items: center; gap: 6px; }
.rp-bar-lg i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

/* 报表：环形图 */
.rp-donut-wrap { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.rp-donut { position: relative; flex-shrink: 0; }
.rp-donut svg { display: block; }
.rp-donut-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; }
.rp-donut-total { font-size: 15px; font-weight: 700; color: var(--c-text); }
.rp-donut-cap { font-size: 11px; color: var(--c-text-secondary); margin-top: 2px; }
.rp-legend { display: flex; flex-direction: column; gap: 8px; font-size: 12px; flex: 1; min-width: 180px; }
.rp-lg-row { display: flex; align-items: center; gap: 8px; color: var(--c-text-regular); }
.rp-lg-row i { width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; }
.rp-lg-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rp-lg-val { font-family: 'SFMono-Regular', Consolas, monospace; color: var(--c-text); }
.rp-lg-share { width: 46px; text-align: right; color: var(--c-text-secondary); font-family: 'SFMono-Regular', Consolas, monospace; }
.rp-empty { color: var(--c-text-secondary); font-size: 12px; padding: 30px 0; text-align: center; }

/* 房态报表：矩阵与汇总 */
.rhc-matrix-wrap { background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md); padding: 14px 16px; margin-bottom: 14px; }
.rhc-matrix-title { font-weight: 600; font-size: 13px; color: var(--c-text); margin-bottom: 12px; }
.rhc-tbl { min-width: 640px; }
.rhc-b-tbl { min-width: 760px; }
.rhc-b-tbl td:nth-child(1) { min-width: 180px; }
.rhc-b-tbl td:nth-child(3), .rhc-b-tbl td:nth-child(4), .rhc-b-tbl td:nth-child(5), .rhc-b-tbl td:nth-child(6) { text-align: center; font-family: 'SFMono-Regular', Consolas, monospace; }
.rhc-b-tbl td:nth-child(8) { font-family: 'SFMono-Regular', Consolas, monospace; }

/* 报表通用：表格外层 */
.rp-table { overflow-x: auto; background: #fff; border-radius: var(--r-md); border: 1px solid var(--c-border-light); padding: 4px; }

/* 报表 4 表格 */
.rp-tbl th, .rp-tbl td, .rpf-tbl th, .rpf-tbl td, .rhc-tbl th, .rhc-tbl td, .rrc-tbl th, .rrc-tbl td { padding: 9px 10px; font-size: 13px; }
.rp-tbl .dyn-table, .rpf-tbl .dyn-table, .rhc-tbl .dyn-table, .rrc-tbl .dyn-table { min-width: 900px; }
.rp-tbl td:nth-child(2), .rpf-tbl td:nth-child(1), .rhc-tbl td:nth-child(1), .rrc-tbl td:nth-child(1) { min-width: 180px; color: var(--c-text-regular); }
.rp-tbl td:nth-child(4), .rp-tbl td:nth-child(5), .rp-tbl td:nth-child(6) { font-family: 'SFMono-Regular', Consolas, monospace; }
.rpf-tbl td { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; }
.rhc-tbl td:nth-child(2), .rhc-tbl td:nth-child(3), .rhc-tbl td:nth-child(4) { text-align: center; font-family: 'SFMono-Regular', Consolas, monospace; }

/* 设备 / 抄表 / 工单 通用：表格外层 */
.dv-table, .cl-table, .cs-table, .wk-table { overflow-x: auto; background: #fff; border-radius: var(--r-md); border: 1px solid var(--c-border-light); padding: 4px; }
.dv-table .dyn-table, .cl-table .dyn-table, .cs-table .dyn-table, .wk-table .dyn-table { min-width: 980px; }

/* 设备 / 抄表 / 工单 表格 */
.dv-tbl th, .dv-tbl td, .da-tbl th, .da-tbl td, .cl-tbl th, .cl-tbl td, .cs-tbl th, .cs-tbl td, .wk-tbl th, .wk-tbl td { padding: 9px 8px; font-size: 13px; }
.dv-tbl td:nth-child(4), .da-tbl td:nth-child(1), .cl-tbl td:nth-child(1), .cs-tbl td:nth-child(1), .wk-tbl td:nth-child(3) { min-width: 200px; color: var(--c-text-regular); }
.dv-tbl td:nth-child(9) { font-size: 12px; color: var(--c-text-secondary); }
.cl-tbl td:nth-child(3), .cl-tbl td:nth-child(4), .cl-tbl td:nth-child(5), .cl-tbl td:nth-child(6) { font-family: 'SFMono-Regular', Consolas, monospace; }
.cs-tbl td:nth-child(3), .cs-tbl td:nth-child(4), .cs-tbl td:nth-child(5) { font-family: 'SFMono-Regular', Consolas, monospace; }
.wk-tbl td:nth-child(5) { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wk-tbl td:nth-child(9), .wk-tbl td:nth-child(10) { font-size: 12px; color: var(--c-text-secondary); }

/* 报表 6 卡 KPI 自适应 */
@media (max-width: 1100px) {
  .rp-charts { grid-template-columns: 1fr; }
  .rp-kpis { grid-template-columns: repeat(2, 1fr) !important; }
}

/* ============== 新手上路（dashboard/tasks）============== */
.task-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md);
  padding: 18px 22px; margin-bottom: 14px;
}
.task-head-title { font-size: 18px; color: var(--c-text); margin-bottom: 6px; font-weight: 600; }
.task-head-sub { font-size: 13px; color: var(--c-text-secondary); }
.task-head-right { min-width: 240px; }
.task-progress-text { font-size: 13px; color: var(--c-text-regular); margin-bottom: 6px; text-align: right; }
.task-progress-text b { color: var(--c-primary); font-size: 15px; }
.task-progress { height: 8px; background: var(--c-border); border-radius: 99px; overflow: hidden; }
.task-progress span { display: block; height: 100%; background: var(--c-primary); border-radius: 99px; transition: width .3s; }
.task-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.task-card {
  display: flex; align-items: center; gap: 14px;
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md);
  padding: 16px 18px; transition: box-shadow .15s;
}
.task-card:hover { box-shadow: var(--shadow-md); }
.task-card.is-done { opacity: .72; }
.task-ico {
  width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 18px;
}
.task-ico.task-blue { background: #ecf5ff; }
.task-ico.task-red { background: #fef0f0; }
.task-ico.task-orange { background: #fff4e6; }
.task-ico.task-green { background: #f0f9eb; }
.task-ico.task-cyan { background: #e8f8f8; }
.task-body { flex: 1; min-width: 0; }
.task-title { font-size: 14px; color: var(--c-text); margin-bottom: 4px; }
.task-desc { font-size: 12px; color: var(--c-text-secondary); }
.task-action { flex-shrink: 0; }
.task-go-btn {
  padding: 5px 14px; border: 1px solid var(--c-primary); color: var(--c-primary);
  background: #fff; border-radius: 99px; font-size: 12px; cursor: pointer;
}
.task-go-btn:hover { background: var(--c-primary); color: #fff; }
.task-done-text { font-size: 12px; color: var(--c-text-secondary); }
.task-done-text.muted { color: var(--c-text-placeholder); }
@media (max-width: 1100px) { .task-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px) { .task-grid { grid-template-columns: 1fr; } }

/* ============== 短信（sms/manage）============== */
/* 批次57：短信通道未开通时的顶部提示（默认关闭，只发站内消息） */
.sms-chan-warn {
  margin: 0 0 14px; padding: 11px 14px; border-radius: var(--r-md);
  background: #FFF8E8; border: 1px solid #F5D08A; color: #7A5300;
  font-size: 13px; line-height: 1.75;
}
.sms-chan-warn b { color: #6B4700; }
.sms-wrap { display: flex; gap: 24px; align-items: flex-start; }
.sms-form {
  flex: 1; min-width: 0;
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--r-md);
  padding: 20px 24px;
}
.sms-row { display: grid; grid-template-columns: 96px minmax(0,1fr); gap: 12px; align-items: start; margin-bottom: 16px; }
.sms-row-top { align-items: flex-start; }
.sms-row > label {
  font-size: 13px; font-weight: 500; color: #475467; line-height: 20px;
  padding-top: 8px; text-align: right;
  display: flex; align-items: baseline; justify-content: flex-end;
}
/* 批次96：同样排除 checkbox / radio —— 否则「租客/业主」单选框被撑成 49×36 盖住文字 */
.sms-row input:not([type=checkbox]):not([type=radio]), .sms-row select, .sms-row textarea { width: 100%; box-sizing: border-box; }
.sms-row input:not([type=checkbox]):not([type=radio]), .sms-row select { height: 36px; }
.sms-row input[type=checkbox], .sms-row input[type=radio] { width: auto; height: auto; padding: 0; border: 0; background: none; }
.sms-req { color: #D92D20; font-style: normal; margin-left: 2px; font-weight: 400; }
.sms-radios { display: flex; gap: 18px; align-items: center; }
/* 批次96：原来是 inline-flex，label 里的文字节点会变成匿名 flex item 被压到最小内容宽度，
   「发送即代表同意《短信群发条款》」被挤成 5 行竖排（checkbox 右边明明有大片空白）。
   改成 inline-block + 行内垂直对齐，文字自然一行排开。 */
.sms-radio, .sms-check { display: inline-block; font-size: 13px; color: var(--c-text-regular); cursor: pointer; line-height: 22px; white-space: nowrap; }
.sms-radio > input, .sms-check > input { vertical-align: -2px; margin: 0 6px 0 0; }
.sms-picked { font-size: 13px; color: var(--c-text-secondary); margin-top: 8px; }
.sms-picked b { color: var(--c-primary); }
.sms-link-btn { color: var(--c-primary); font-size: 13px; background: none; border: 0; cursor: pointer; padding: 0; margin-top: 8px; }
.sms-editor { border: 1px solid var(--c-border); border-radius: var(--r-sm); padding: 10px 12px; background: #fff; }
.sms-sign { font-size: 13px; color: var(--c-text); margin-bottom: 6px; }
.sms-edit-sign { color: var(--c-primary); font-size: 12px; margin-left: 6px; }
.sms-editor textarea {
  width: 100%; min-height: 130px; border: 0; outline: none; resize: vertical;
  font-size: 13px; color: var(--c-text); font-family: inherit;
}
.sms-counter { display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: var(--c-text-secondary); }
.sms-submit { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.sms-send-btn { padding: 8px 32px; background: var(--c-primary); color: #fff; border: 0; border-radius: var(--r-sm); font-size: 13px; cursor: pointer; }
.sms-send-btn:hover { background: var(--c-primary-hover); }
.sms-preview { flex: 0 0 260px; }
.sms-phone {
  width: 260px; height: 460px; background: #fff; border: 1px solid var(--c-border);
  border-radius: 22px; box-shadow: var(--shadow-md); padding: 18px 14px; overflow: hidden;
}
.sms-phone-bar { text-align: center; font-size: 12px; color: var(--c-text-secondary); margin-bottom: 20px; }
.sms-phone-msg {
  background: var(--c-bg); border-radius: 8px; padding: 10px 12px;
  font-size: 13px; color: var(--c-text-regular); line-height: 1.6; word-break: break-all;
}
.sms-preview-tip { text-align: center; font-size: 12px; color: var(--c-text-secondary); margin-top: 10px; }

/* ============== 钱包（company-sua-wallets/manage）============== */
.wallet-notice {
  background: #fff4e6; border: 1px solid #ffe0b2; color: #b26a00;
  font-size: 13px; padding: 10px 16px; border-radius: var(--r-sm); margin-bottom: 14px;
}
.wallet-notice .link-blue { margin-left: 6px; }

/* ============== 消息中心（message/core）============== */
.msg-list { border: 1px solid var(--c-border); border-radius: var(--r-lg); overflow: hidden; }
.msg-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--c-border-light); cursor: pointer;
}
.msg-row:last-child { border-bottom: none; }
.msg-row:hover { background: var(--c-bg); }
.msg-icon {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  background: var(--c-primary-light); color: var(--c-primary);
  display: flex; align-items: center; justify-content: center;
}
.msg-body { flex: 1; min-width: 0; }
.msg-title { font-size: 13px; color: var(--c-text); margin-bottom: 4px; }
.msg-row.unread .msg-title::before {
  content: ''; display: inline-block; width: 6px; height: 6px;
  border-radius: 50%; background: var(--c-danger);
  margin-right: 6px; vertical-align: middle;
}
.msg-text { font-size: 12px; color: var(--c-text-secondary); }
.msg-time { font-size: 12px; color: var(--c-text-secondary); white-space: nowrap; }
.msg-empty {
  padding: 60px; text-align: center; color: var(--c-text-secondary);
  border: 1px solid var(--c-border); border-radius: var(--r-lg);
}
.msg-pager {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px;
  margin-top: 14px; font-size: 12px; color: var(--c-text-regular);
}
.msg-total { margin-right: auto; }
.msg-pager .pg-prev, .msg-pager .pg-next, .msg-pager .pg-num {
  min-width: 28px; height: 28px; border: 1px solid var(--c-border);
  background: #fff; border-radius: var(--r-sm);
  font-size: 12px; color: var(--c-text-regular);
}
.msg-pager .pg-num.active { background: var(--c-primary); border-color: var(--c-primary); color: #fff; }
.msg-pager button[disabled] { color: var(--c-text-placeholder); cursor: not-allowed; }

/* ============== 帮助中心（help）============== */
.help-faq { margin-top: 16px; border: 1px solid var(--c-border); border-radius: var(--r-lg); padding: 16px 20px; }
.help-faq-title { font-size: 14px; font-weight: 600; color: var(--c-text); margin-bottom: 12px; }
.help-q { padding: 10px 0; border-bottom: 1px dashed var(--c-border-light); }
.help-q:last-child { border-bottom: none; }
.help-q-title { font-size: 13px; color: var(--c-text); margin-bottom: 4px; }
.help-q-body { font-size: 12px; color: var(--c-text-secondary); line-height: 20px; }

/* ============== 设置页（常用/个性/签约/子账号/企业设置）============== */
.set-page { display: grid; grid-template-columns: 300px 1fr; gap: 0; padding: 8px 0 0 48px; }
.set-menu { padding-top: 6px; }
.set-menu-item { display: block; padding: 9px 0; font-size: 13px; color: var(--c-text-regular); }
.set-menu-item:hover { color: var(--c-primary); }
.set-menu-item.active { color: var(--c-text); font-weight: 600; }
.set-content { min-width: 0; }
.set-card-head {
  display: flex; align-items: center; justify-content: space-between;
  background: #f2f3f5; border-radius: 2px;
  padding: 0 16px; height: 56px; margin-bottom: 10px;
}
.set-card-title { font-size: 15px; font-weight: 500; color: var(--c-text); }
.set-card-btn { height: 32px; padding: 0 16px; background: var(--c-primary); color: #fff; border-radius: var(--r-sm); font-size: 13px; }
.set-card-btn:hover { background: var(--c-primary-hover); }
.set-tbl { background: #fff; }
.set-tbl th { height: 46px; font-size: 13px; font-weight: 700; background: #fff; border-bottom: 1px solid var(--c-border); }
.set-tbl td { height: 46px; font-size: 13px; }
.set-status-off { display: inline-block; background: var(--c-bg); color: var(--c-text-regular); padding: 2px 8px; border-radius: 2px; font-size: 12px; }
.set-ops a { margin-right: 12px; font-size: 13px; }
.set-form { padding: 6px 0; }
.set-row { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; font-size: 13px; color: var(--c-text-regular); }
.set-row > label:first-child { width: 140px; text-align: right; }
.set-row input[type=text] {
  height: 32px; width: 220px; padding: 0 10px;
  border: 1px solid var(--c-input-border); border-radius: var(--r-sm); font-size: 13px;
}
.set-tip { font-size: 12px; color: var(--c-text-secondary); }

/* ============== 数据大屏（浅色 · 页内正常页面）==============
 * 批次79：整块重写。批次73 那版是「深色全屏遮罩」（position:fixed; inset:0;
 * z-index:2000 + --bs-bg:#0B1220），用户提了三条：
 *   ① 不要深色页面；
 *   ② 为什么成了一个单独的页面（顶栏/侧边栏全被盖住，像另一个系统）；
 *   ③ 没有返回按钮（只有一个对比度 1.6:1 的「关闭」，等于看不见）。
 *
 * 现在它就是一个 **普通路由页**，渲染进 #pageView —— 顶栏、侧边栏、
 * 二级 tab 全在，左上角有「← 返回总览」，右上角保留「实时 / 时钟」。
 * 配色走设计规范的中性浅色阶，彩色只给数据条本身。
 *
 * 对比度（白底 #FFFFFF / 浅灰底 #F9FAFB）：
 *   #0F172A 18.0:1 / #475467 8.6:1 / #667085 4.97:1（4.76:1 on #F9FAFB）
 *   #067647 5.1:1 / #B54708 5.3:1 / #B42318 6.4:1 —— 全部 ≥ 4.5:1
 * ⚠ 品牌蓝 #2F6BFF 对白只有 4.498:1，**只用于填充条**，不做文字色。
 * ================================================ */
.bs-page {
  --bs-bg: #F9FAFB;
  --bs-surface: #FFFFFF;
  --bs-surface-2: #F9FAFB;
  --bs-border: #E4E7EC;
  --bs-border-2: #F2F4F7;
  --bs-text-1: #0F172A;
  --bs-text-2: #475467;
  --bs-text-3: #667085;
  --bs-accent: #2F6BFF;      /* 仅填充条 */
  --bs-ok: #12B886;          /* 填充条 */
  --bs-warn: #F59E0B;        /* 填充条 */
  --bs-danger: #EF4444;      /* 填充条 */
  --bs-muted: #98A2B3;       /* 填充条（中性档） */
  --bs-ok-ink: #067647;      /* 文字 */
  --bs-warn-ink: #B54708;    /* 文字 */
  --bs-danger-ink: #B42318;  /* 文字 */
  --bs-track: #F2F4F7;
  display: flex;
  flex-direction: column;
  gap: 14px;
  font-variant-numeric: tabular-nums;
}

/* ---- 页头：返回 + 标题 + 实时状态 ---- */
.bs-top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.bs-back {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px 0 10px;
  border: 1px solid var(--bs-border); border-radius: 8px;
  background: var(--bs-surface); color: var(--bs-text-2);
  font-size: 13px; cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.bs-back:hover { border-color: #D0D5DD; color: var(--bs-text-1); background: var(--bs-surface-2); }
.bs-back svg { width: 14px; height: 14px; flex: 0 0 14px; }
.bs-title { font-size: 19px; font-weight: 600; color: var(--bs-text-1); letter-spacing: -.1px; }
.bs-live {
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 10px; border-radius: 999px;
  background: #ECFDF5; color: var(--bs-ok-ink);
  font-size: 12px; font-weight: 500;
}
.bs-live i { width: 6px; height: 6px; border-radius: 999px; background: var(--bs-ok); }
.bs-clock { font-size: 13px; color: var(--bs-text-3); }
.bs-top-right { margin-left: auto; display: inline-flex; align-items: center; gap: 12px; }

/* ---- KPI 条 ---- */
.bs-kpi {
  display: grid; grid-template-columns: repeat(4, 1fr);
  background: var(--bs-surface); border: 1px solid var(--bs-border); border-radius: 12px;
}
.bs-kpi-item { padding: 18px 22px; border-left: 1px solid var(--bs-border); min-width: 0; }
.bs-kpi-item:first-child { border-left: none; }
.bs-kpi-label { font-size: 13px; color: var(--bs-text-3); }
.bs-kpi-value {
  margin-top: 7px; font-size: 32px; font-weight: 700; line-height: 1.08;
  color: var(--bs-text-1); letter-spacing: -.8px;
  display: flex; align-items: baseline; gap: 5px; min-width: 0;
}
.bs-kpi-value .u { font-size: 13px; font-weight: 500; color: var(--bs-text-3); letter-spacing: 0; }
.bs-kpi-item.is-warn .bs-kpi-value .num { color: var(--bs-warn-ink); }
.bs-kpi-sub { margin-top: 6px; font-size: 12px; color: var(--bs-text-3); }

/* ---- 主体两列 ---- */
.bs-body { display: grid; grid-template-columns: 1.1fr 1fr; gap: 14px; align-items: stretch; }
.bs-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.bs-card {
  background: var(--bs-surface); border: 1px solid var(--bs-border); border-radius: 12px;
  padding: 16px 18px; display: flex; flex-direction: column;
  min-height: 220px;
  /* 右列只有一张卡时也要撑到和左列同高，否则下面一大片空白 */
  flex: 1 1 auto;
}
.bs-card-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 12px; flex: 0 0 auto; }
.bs-card-title { font-size: 14px; font-weight: 600; color: var(--bs-text-1); }
.bs-card-extra { margin-left: auto; font-size: 12px; color: var(--bs-text-3); }

/* ---- 横向占比条 ----
 * space-around：卡片高度撑满，条数少时不挤在中间、上下各留一大块空白。 */
.bs-meters { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: space-around; gap: 6px; }
.bs-meter { display: flex; align-items: center; gap: 12px; font-size: 13px; padding: 3px 0; }
.bs-meter-label {
  width: 92px; flex: 0 0 auto; color: var(--bs-text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bs-meter-track { flex: 1 1 auto; height: 8px; border-radius: 999px; background: var(--bs-track); overflow: hidden; }
.bs-meter-track i { display: block; height: 100%; border-radius: 999px; transition: width .5s ease; }
.bs-meter-val { width: 62px; flex: 0 0 auto; text-align: right; font-weight: 600; color: var(--bs-text-1); }
.bs-meter-pct { width: 50px; flex: 0 0 auto; text-align: right; font-size: 12px; color: var(--bs-text-3); }

/* ---- 实时动态 ---- */
.bs-feed { list-style: none; margin: 0; padding: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.bs-feed li {
  display: flex; align-items: center; gap: 10px;
  min-height: 34px;
  font-size: 13px; color: var(--bs-text-2);
  border-bottom: 1px solid var(--bs-border-2);
}
.bs-feed li:last-child { border-bottom: none; }
.bs-feed b { flex: 0 0 auto; color: var(--bs-text-3); font-weight: 500; font-size: 12px; }
.bs-feed span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bs-feed em { flex: 0 0 auto; font-style: normal; font-weight: 600; color: var(--bs-ok-ink); }

/* 楼栋出租率：一栋都没有时的空态 */
.bs-empty { color: var(--bs-text-3); font-size: 13px; text-align: center; padding: 24px 0; }

/* 真·大屏（1920 / 2560）：整体提一档，否则投影到墙上字太小 */
@media (min-width: 1800px) {
  .bs-page { gap: 18px; }
  .bs-title { font-size: 22px; }
  .bs-kpi-item { padding: 22px 28px; }
  .bs-kpi-label { font-size: 14px; }
  .bs-kpi-value { font-size: 42px; }
  .bs-kpi-value .u { font-size: 15px; }
  .bs-kpi-sub { font-size: 13px; }
  .bs-card { padding: 20px 24px; min-height: 260px; }
  .bs-card-title { font-size: 16px; }
  .bs-card-extra { font-size: 13px; }
  .bs-meter { font-size: 15px; gap: 16px; }
  .bs-meter-label { width: 118px; }
  .bs-meter-track { height: 10px; }
  .bs-meter-val { width: 72px; }
  .bs-meter-pct { width: 60px; font-size: 13px; }
  .bs-feed li { font-size: 15px; min-height: 40px; }
  .bs-feed b { font-size: 13px; }
}

@media (max-width: 1180px) {
  .bs-body { grid-template-columns: 1fr; }
  .bs-kpi { grid-template-columns: repeat(2, 1fr); }
  .bs-kpi-item:nth-child(3) { border-left: none; border-top: 1px solid var(--bs-border); }
  .bs-kpi-item:nth-child(4) { border-top: 1px solid var(--bs-border); }
}

@media (max-width: 560px) {
  .bs-kpi { grid-template-columns: 1fr; }
  .bs-kpi-item { border-left: none; border-top: 1px solid var(--bs-border); }
  .bs-kpi-item:first-child { border-top: none; }
  .bs-kpi-value { font-size: 26px; }
  .bs-meter-label { width: 72px; }
  .bs-meter-val { width: 52px; }
  .bs-top-right { width: 100%; margin-left: 0; }
}

/* ==================================================================
 * 居小易 · 后台管理端 设计升级层 v2（2026-09-28）
 * ------------------------------------------------------------------
 * 说明：这一层只做「视觉重绘」，不改任何结构与业务逻辑。
 *      放在 style.css 末尾，用同名 token 覆盖旧值 + 组件级细化，
 *      所以 44 个页面一次性换脸；如需回滚，删掉这一段即可。
 * ================================================================== */
:root{
  --c-primary:#2F6BFF;
  --c-primary-hover:#1E57E8;
  --c-primary-light:#EEF3FF;
  --c-primary-soft:#F5F8FF;
  --c-danger:#EF4444;
  --c-danger-light:#FEF2F2;
  --c-warning:#F59E0B;
  --c-warning-light:#FFFBEB;
  --c-success:#12B886;
  --c-success-light:#ECFDF5;

  --c-text:#0F172A;
  --c-text-regular:#475467;
  /* 批次75：#8B95A7 压白底只有 3.02:1，低于 WCAG AA 正文 4.5:1 的下限，
     而它被当成「次要文字」用了 100+ 处（12~13px 正文级字号）。
     换成设计规范的 text-3 #667085 = 4.97:1。 */
  --c-text-secondary:#667085;
  --c-text-placeholder:#AEB6C4;

  --c-bg:#F4F6FB;
  --c-bg-card:#FFFFFF;
  --c-border:#E9EDF5;
  --c-border-light:#F1F4F9;
  --c-input-border:#DFE5EF;
  --c-header-border:#E9EDF5;

  --c-sidebar:#FFFFFF;
  --c-sidebar-hover:#F5F8FF;
  --c-sidebar-active-bg:#EEF3FF;
  --c-sidebar-text:#475467;
  --c-sidebar-text-active:#2F6BFF;

  --r-sm:6px;
  --r-md:8px;
  --r-lg:12px;
  --r-xl:16px;

  --shadow-sm:0 1px 2px rgba(16,24,40,.05), 0 1px 3px rgba(16,24,40,.06);
  --shadow-md:0 4px 12px rgba(16,24,40,.08), 0 2px 4px rgba(16,24,40,.04);
  --shadow-lg:0 12px 32px rgba(16,24,40,.12), 0 4px 10px rgba(16,24,40,.05);
  --shadow-focus:0 0 0 4px rgba(47,107,255,.12);
}
body{
  font-size:13.5px; line-height:21px; color:var(--c-text-regular);
  background:
    radial-gradient(1200px 600px at 100% -10%, #EEF3FF 0%, rgba(238,243,255,0) 60%),
    var(--c-bg);
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{font-weight:600;color:var(--c-text);letter-spacing:-.1px}

/* ---------- 顶部栏 ---------- */
.host-header,.topbar{
  background:rgba(255,255,255,.86); backdrop-filter:saturate(180%) blur(12px);
  border-bottom:1px solid var(--c-border);
}
.host-header{box-shadow:0 1px 0 rgba(16,24,40,.02)}

/* ---------- 侧边栏 ---------- */
.sidebar{
  background:var(--c-sidebar); border-right:1px solid var(--c-border);
  padding-top:6px;
}
/* 🔴 这里原来写的是 `.sidebar .nav-group, .sidebar .group-title` —— 把「分组小标题」
   的 11px / 大写 / 14px 上下留白套到了 **分组容器** 上。批次79 前 12 个分组里
   9 个被隐藏，看不出来；一旦全部显示，每个分组白吃 20px 竖向留白 × 16 组 = 320px，
   侧边栏直接被撑到滚动区外。容器不带排版，只有真正的小标题才带。 */
.sidebar .group-title{
  font-size:11px; font-weight:600; letter-spacing:.6px; text-transform:uppercase;
  color:var(--c-text-secondary); padding:14px 16px 6px;
}
.sidebar a,.sidebar .nav-item,.sidebar li>a{
  border-radius:10px; margin:2px 10px; padding:9px 12px;
  color:var(--c-sidebar-text); transition:background .16s,color .16s,transform .16s;
}
.sidebar a:hover,.sidebar .nav-item:hover{background:var(--c-sidebar-hover); color:var(--c-primary)}
.sidebar a.active,.sidebar .nav-item.active,.sidebar li>a.active{
  background:var(--c-sidebar-active-bg); color:var(--c-sidebar-text-active); font-weight:600;
  box-shadow:inset 3px 0 0 var(--c-primary);
}
.sidebar .ico,.sidebar i{opacity:.9}

/* ---------- 页面容器 / 标题 ---------- */
.page-view{padding:22px 24px 32px}
.h-page{background:transparent}
.h-title,.page-title{font-size:19px; font-weight:700; color:var(--c-text)}
.h-sub,.page-sub{color:var(--c-text-secondary); font-size:12.5px}
.h-toolbar{background:#fff; border:1px solid var(--c-border); border-radius:var(--r-lg);
  padding:12px 14px; box-shadow:var(--shadow-sm); margin-bottom:14px}
.h-tools{gap:8px}

/* ---------- 按钮 ---------- */
button,.btn,.h-tool,.h-btn{
  transition:background .16s,border-color .16s,box-shadow .16s,transform .16s,color .16s;
}
.h-tool,.h-btn,.btn-mini,.ap-detail,.ap-pass,.pd-act-btn,.st-form-save,.bi-issue,.bi-detail,.bi-download{
  border-radius:8px !important;
}
.h-tool{
  background:#fff; border:1px solid var(--c-input-border); padding:7px 13px; font-weight:500;
}
.h-tool:hover{border-color:var(--c-primary); color:var(--c-primary); background:var(--c-primary-soft)}
/* 主按钮：平色实心。规范禁渐变主按钮 + 禁彩色阴影 + 禁 hover 位移
   （.bi-issue 是表格行内小按钮，不属于主按钮族，改由文末统一层按「行内强调」处理） */
.btn-primary,.st-form-save{
  background:var(--c-primary); color:#fff;
  border:1px solid var(--c-primary); box-shadow:none;
}
.btn-primary:hover,.st-form-save:hover{
  background:var(--c-primary-hover); border-color:var(--c-primary-hover);
}
.ap-detail,.btn-mini,.ap-pass{
  background:transparent; color:var(--c-primary); border:none; padding:4px 8px; font-weight:500;
}
.ap-detail:hover,.btn-mini:hover{background:var(--c-primary-light); border-radius:8px}
.pg-num,.pg-prev,.pg-next{border-radius:8px !important; border:1px solid var(--c-border) !important; background:#fff}
.pg-num.active{background:var(--c-primary) !important; color:#fff !important; border-color:var(--c-primary) !important}

/* ---------- 表格 ---------- */
.dyn-table,table.dyn-table,.table-wrap table{
  border-collapse:separate; border-spacing:0; width:100%;
  background:#fff; border:1px solid var(--c-border); border-radius:var(--r-lg); overflow:hidden;
}
.dyn-table thead th{
  background:#F8FAFD; color:var(--c-text-secondary); font-weight:600; font-size:12px;
  letter-spacing:.3px; padding:11px 14px; border-bottom:1px solid var(--c-border); white-space:nowrap;
}
.dyn-table tbody td{padding:12px 14px; border-bottom:1px solid var(--c-border-light); color:var(--c-text-regular)}
.dyn-table tbody tr:last-child td{border-bottom:none}
.dyn-table tbody tr:hover td{background:#FAFCFF}
.cell-sub{color:var(--c-text-secondary); font-size:11.5px}
.empty,.no-data{padding:44px 16px; text-align:center; color:var(--c-text-secondary); font-size:13px}

/* ---------- 卡片 / KPI ---------- */
.card,.panel,.kpi-card,.st-card{
  background:var(--c-bg-card); border:1px solid var(--c-border); border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm); transition:box-shadow .2s,transform .2s
}
.card:hover,.kpi-card:hover{box-shadow:var(--shadow-md); transform:translateY(-2px)}
.kpi-card{border-radius:var(--r-xl); padding:18px 20px}
.kpi-label{color:var(--c-text-secondary); font-size:12.5px}
.kpi-num{font-size:24px; font-weight:700; color:var(--c-text); letter-spacing:-.4px}
.kpi-extra{color:var(--c-text-secondary); font-size:12px}
.kpi-red{border-left:3px solid var(--c-danger)}
.kpi-green{border-left:3px solid var(--c-success)}
.kpi-blue{border-left:3px solid var(--c-primary)}

/* ---------- 标签 / 状态 ----------
 * 批次76：徽标颜色分两层，别再混着用。
 *
 * ① 文字必须走「文字档」(--c-*-text)，不能走填充档。
 *    填充档 #00b42a / #f53f3f / #ff7d00 是为了做大色块调的，压在同色系浅底上
 *    只有 2.1~2.9:1；11.5px 的小字要到 4.5:1 才看得清。
 * ② 五档语义各管一段，不允许「兜底进蓝」：
 *    ok      活跃 / 已完成（在租中、已支付、已结清）
 *    warn    待办 / 需关注（待支付、待签约、即将到期、部分付款）
 *    danger  异常 / 失败（已逾期、不合格、停用）
 *    neutral 归档 / 已结束（已到期、已转租、正常退租、已作废、已退款）
 *    info    只是分类标签（账单类型、付款方式），不是状态
 *
 * 🔴 「已到期 / 已转租 / 正常退租」以前全落在 info 蓝上 —— 蓝色是品牌色，
 *    用户会读成「这是重点/这是活跃的」。合同结束是归档态，必须安静下去用灰。
 */
.badge,.tag,.pill,.st-badge{
  display:inline-flex; align-items:center; gap:4px; border-radius:999px;
  padding:2px 9px; font-size:11.5px; font-weight:600; line-height:18px
}
.badge.ok,.tag.ok{background:#ECFDF5; color:var(--c-success-text)}
.badge.warn,.tag.warn{background:#FFFAEB; color:var(--c-warning-text)}
.badge.danger,.tag.danger{background:#FEF3F2; color:var(--c-danger-text)}
.badge.neutral,.tag.neutral{background:#F2F4F7; color:#475467}
.badge.info,.tag.info{background:var(--c-primary-light); color:var(--c-primary)}
.badge.muted,.tag.muted{background:#F2F4F7; color:var(--c-text-secondary)}

/* ---------- 表单控件基础层（批次77 重写） ----------
 * 这一层只管「长得一样」，不管尺寸：颜色 / 圆角 / 占位符 / 聚焦环 / 禁用态 / 下拉箭头。
 * 尺寸（高 36）由 .modal 和 .st-form-row / .dyn-field 各自声明 —— 页面里的搜索框、
 * 筛选下拉高度不一样是正常的，但边框颜色和圆角必须一致。
 */
input[type=text],input[type=number],input[type=password],input[type=tel],
input[type=email],input[type=date],input[type=search],input[type=url],
select,textarea{
  border:1px solid #D0D5DD; border-radius:8px; padding:8px 11px; font-size:13px;
  color:var(--c-text); background:#fff; outline:none;
  transition:border-color .16s,box-shadow .16s; font-family:inherit;
  box-sizing:border-box;
}
input[type=text]:hover,input[type=number]:hover,input[type=password]:hover,input[type=tel]:hover,
input[type=email]:hover,input[type=date]:hover,select:hover,textarea:hover{
  border-color:#B8C0CE;
}
input:focus,select:focus,textarea:focus{
  border-color:var(--c-primary); box-shadow:0 0 0 3px rgba(47,107,255,.12);
}
input::placeholder,textarea::placeholder{ color:#98A2B3; }
input:disabled,select:disabled,textarea:disabled{
  background:#F9FAFB; color:#667085; cursor:not-allowed; border-color:#E4E7EC;
}
input:disabled::placeholder,textarea:disabled::placeholder{ color:#A9B1BF; }
input.invalid,select.invalid,textarea.invalid{
  border-color:#F04438; box-shadow:0 0 0 3px rgba(240,68,56,.1);
}
/* 日期框的日历图标各浏览器长得不一样 → 统一成灰、hover 变深 */
input[type=date]::-webkit-calendar-picker-indicator{
  opacity:.45; cursor:pointer; transition:opacity .15s;
}
input[type=date]:hover::-webkit-calendar-picker-indicator{ opacity:.8; }
/* 原生下拉箭头各系统不一致 → 换成统一 chevron（右侧留 30px 防压字） */
select{
  padding-right:30px;
  appearance:none; -webkit-appearance:none; -moz-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 10px center;
}
select:disabled{ background-image:none; }

/* 🔴 上面那条 `select{background-image:...}` 只有标签选择器（权重 0,0,1），
   而代码里 64 处 .h-select、10 处 .f-sel、以及 .month-select / .bp-in 都写了
   `background:#fff` 简写（权重 0,1,0）—— 简写会把 background-image 一起重置掉，
   结果箭头整个消失，下拉框长得和输入框一模一样，用户不知道能点。
   这里用「标签+类」双选择器（0,1,1）补回来，并给足右侧内距防文字压箭头。 */
select.h-select, select.f-sel, select.month-select, select.bp-in, select.h-input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
}
/* padding-right 必须 !important：`.h-tools .h-select`（0,2,0）会把内距压回 10px。
   16 处内联 style 只设 height/width，没有一处设 padding，所以不会打掉内联样式。 */
select.h-select, select.f-sel, select.month-select, select.bp-in, select.h-input {
  padding-right: 28px !important;
}
.h-search input,.h-search .inp{border-radius:8px}
/* ⚠ 这里原来还有一条 .st-form-row label{font-size:12.5px}，会把表单标签字号盖回 12.5 —— 已删，
   标签规格统一在 .st-form-row > label 里（13px / 500 / #475467）。 */
.st-tip{color:var(--c-text-secondary); font-size:12px; line-height:1.6}
.st-card{border-radius:var(--r-lg); padding:16px 18px; margin-bottom:14px}

/* ---------- 选项卡 ---------- */
.h-tab{border-radius:999px !important; padding:7px 15px !important; border:1px solid transparent !important;
  color:var(--c-text-regular); background:transparent; font-weight:500}
.h-tab:hover{background:#F1F4F9}
.h-tab.active{background:var(--c-primary-light) !important; color:var(--c-primary) !important; font-weight:600; border-color:transparent !important}
.h-tabs{gap:6px; flex-wrap:wrap}
/* ---------- 弹窗（批次77：几何全在上面的 Modal 段，这里只留遮罩模糊） ---------- */
.modal-mask{backdrop-filter:blur(2px)}
/* 🔴 这里原来还有 .modal / .modal-head / .modal-title / .modal-close / .modal-body 五条覆盖，
   把上面重写的圆角（12→16）、标题字重（600→700）、体内距（20/24→18/20）又盖了回去。
   弹窗看起来「圆角过大、标题发胖、内容贴边」就是这五条造成的。已全部删除。 */

/* 表单底部操作条：与 .modal-foot 视觉一致（上边框 + 右对齐 + 32px 按钮） */
.st-form-actions{
  display:flex; align-items:center; justify-content:flex-end; gap:8px;
  border-top:1px solid var(--c-border);
  padding-top:14px; margin-top:18px;
}
/* 说明文字放最左，按钮靠右（原来按钮在左、说明在右，主操作反而跑到角落里） */
.st-form-actions .st-tip{ order:-1; margin-right:auto; }
.st-form-save{
  height:32px; padding:0 16px !important;
  border-radius:8px !important;
  font-size:13px; font-weight:500 !important;
  display:inline-flex; align-items:center; justify-content:center;
}

/* ---------- 提示条 / 消息 ---------- */
.toast{border-radius:12px; box-shadow:var(--shadow-lg); font-size:13px; padding:11px 16px; border:none}
.msg-row{border-radius:12px; border:1px solid var(--c-border); background:#fff; margin-bottom:8px; padding:12px 14px; transition:.16s}
.msg-row:hover{border-color:#D5E0FB; box-shadow:var(--shadow-sm)}
.msg-row.unread{background:linear-gradient(90deg,#F7FAFF,#FFFFFF); border-color:#D9E5FF}
.msg-title{font-weight:600; color:var(--c-text)}

/* ---------- 滚动条 ---------- */
::-webkit-scrollbar{width:10px; height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#D7DEEA; border-radius:99px; border:2px solid transparent; background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:#C3CCDC; background-clip:padding-box}

/* ---------- 细节修饰 ---------- */
.h-quick-table,.dv-table,.bill-manage-table{border-radius:var(--r-lg); overflow:hidden}
.h-select{border-radius:9px !important}
.breadcrumb,.crumb{color:var(--c-text-secondary); font-size:12.5px}
.divider,.h-line{background:var(--c-border)}
[data-role="table-action"] button{font-weight:500}
.sidebar::-webkit-scrollbar{width:8px}

/* ============== 数据体检（设置 / 数据体检） ============== */
.dh-wrap { padding: 4px 2px 24px; }
.dh-loading { padding: 60px 0; text-align: center; color: var(--c-text-secondary); font-size: 13px; }
.dh-head {
  display: flex; align-items: center; gap: 24px; flex-wrap: wrap;
  background: var(--c-bg-card); border: 1px solid var(--c-border);
  border-radius: 12px; padding: 18px 22px; margin-bottom: 16px;
}
.dh-score {
  width: 92px; height: 92px; border: 3px solid var(--c-border); border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center; flex: 0 0 auto;
}
.dh-score b { font-size: 30px; line-height: 1; font-weight: 700; }
.dh-score span { font-size: 12px; color: var(--c-text-secondary); margin-top: 4px; }
.dh-kpis { display: flex; gap: 28px; flex: 1 1 auto; flex-wrap: wrap; }
.dh-kpi { display: flex; flex-direction: column; align-items: center; min-width: 56px; }
.dh-kpi b { font-size: 22px; line-height: 1.1; font-weight: 700; color: var(--c-text); }
.dh-kpi span { font-size: 12px; color: var(--c-text-secondary); margin-top: 4px; }
.dh-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 14px; }
.dh-card {
  background: var(--c-bg-card); border: 1px solid var(--c-border); border-left: 3px solid var(--c-border);
  border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column;
}
.dh-c-err { border-left-color: var(--c-danger); }
.dh-c-warn { border-left-color: var(--c-warning); }
.dh-c-info { border-left-color: var(--c-primary); }
.dh-c-ok { border-left-color: var(--c-success); }
.dh-c-unknown { border-left-color: var(--c-text-placeholder); }
.dh-card-head { display: flex; align-items: center; gap: 8px; }
.dh-badge { font-size: 11px; line-height: 18px; padding: 0 7px; border-radius: 4px; flex: 0 0 auto; }
.dh-b-err { background: var(--c-danger-light); color: var(--c-danger); }
.dh-b-warn { background: #fff7e8; color: var(--c-warning); }
.dh-b-info { background: var(--c-primary-light); color: var(--c-primary); }
.dh-b-ok { background: #e8ffea; color: var(--c-success); }
.dh-b-unknown { background: var(--c-border-light); color: var(--c-text-secondary); }
.dh-card-title { font-size: 14px; font-weight: 600; color: var(--c-text); flex: 1 1 auto; }
.dh-count { font-size: 18px; font-weight: 700; color: var(--c-text); }
.dh-desc { font-size: 12.5px; color: var(--c-text-secondary); line-height: 20px; margin-top: 8px; }
.dh-samples { list-style: none; margin: 10px 0 0; padding: 0; }
.dh-samples li {
  display: flex; justify-content: space-between; gap: 10px; padding: 5px 0;
  border-top: 1px dashed var(--c-border-light); font-size: 12.5px;
}
.dh-samples li b { color: var(--c-text-regular); font-weight: 500; }
.dh-samples li span { color: var(--c-text-secondary); flex: 0 0 auto; }
.dh-card-foot { margin-top: 12px; }
.dh-jump {
  border: 1px solid var(--c-primary); background: #fff; color: var(--c-primary);
  border-radius: 6px; padding: 5px 12px; font-size: 12.5px; cursor: pointer;
}
.dh-jump:hover { background: var(--c-primary-light); }
.dh-foot { margin-top: 16px; text-align: center; font-size: 12px; color: var(--c-text-placeholder); }

/* ============================================================
 * 批次14：工单中心（真实全流程）+ 催收管理
 * ============================================================ */
/* ---- 工单 ---- */
.wo-page .h-toolbar { align-items: center; }
/* ⚠ .h-tool 原本是 32×32 的图标按钮（style.css:1423），文字按钮会被挤成竖排单字。
   工单/催收页用的是带文字的工具按钮，必须放开宽度。 */
.wo-page .h-tool, .urge-page .h-tool {
  width: auto; min-width: 32px; padding: 0 12px; white-space: nowrap; font-size: 13px;
}
.wo-page .h-tools, .urge-page .h-tools { flex-shrink: 0; }
/* .h-search 默认 max-width 560px 且不换行；工单/催收的筛选条件多，必须放开并允许换行 */
.wo-page .h-search, .urge-page .h-search { max-width: none; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
.h-tab .wo-cnt {
  font-style: normal; font-size: 11px; color: var(--c-text-secondary);
  background: var(--c-border-light); border-radius: 8px; padding: 0 6px; margin-left: 4px;
}
.h-tab.active .wo-cnt { background: var(--c-primary-light); color: var(--c-primary); }
.wo-empty { padding: 40px 0; text-align: center; color: var(--c-text-secondary); font-size: 13px; }
.wo-acts { white-space: nowrap; }
.wo-acts .ap-pass, .wo-acts .ap-detail, .wo-acts .ap-reject { margin-right: 6px; }
.wk-desc { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wo-pager { display: flex; align-items: center; gap: 8px; justify-content: flex-end; padding: 12px 4px 0; }
.wo-pager-info { font-size: 13px; color: var(--c-text-secondary); margin-right: auto; }
.wo-pager .btn-ghost { height: 30px; padding: 0 12px; }
/* 批次76：.badge.muted 已提到 2164 行统一（同色系里 --c-border-light 压白底几乎看不见） */
.wo-detail-acts .btn-primary { height: 32px; padding: 0 14px; }

/* ---- 催收 ---- */
.urge-kpis { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-bottom: 14px; }
.urge-kpi { background: var(--c-bg-card); border: 1px solid var(--c-border); border-radius: 10px; padding: 14px 16px; }
.urge-kpi-v { font-size: 22px; font-weight: 600; color: var(--c-text); line-height: 1.3; }
.urge-kpi-l { font-size: 12px; color: var(--c-text-secondary); margin-top: 4px; }
.urge-kpi.warn .urge-kpi-v { color: var(--c-danger); }
.urge-kpi.info .urge-kpi-v { color: var(--c-warning); }
.urge-rule-card { background: var(--c-bg-card); border: 1px solid var(--c-border); border-radius: 10px; padding: 14px 16px; }
.urge-rule-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.urge-rule-head h3 { margin: 0; font-size: 15px; font-weight: 600; color: var(--c-text); }
.urge-switch { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--c-text-regular); cursor: pointer; }
.urge-rule-body { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.urge-field { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--c-text-regular); }
.urge-field label { color: var(--c-text-secondary); }
.urge-field input, .urge-field select {
  height: 32px; border: 1px solid var(--c-input-border); border-radius: 6px; padding: 0 8px; font-size: 13px;
}
.urge-field input[type="number"] { width: 92px; }
.urge-rule-body .btn-primary { height: 32px; padding: 0 16px; }
.urge-rule-tip { margin-top: 10px; font-size: 12px; color: var(--c-text-secondary); line-height: 1.6; }
.urge-tbl td { font-size: 13px; }

/* ---- 批次19：催收记录子页 ---- */
.urge-view-tabs { display: flex; gap: 4px; margin-top: 14px; border-bottom: 1px solid var(--c-border); }
.urge-vtab { background: transparent; border: none; padding: 10px 4px; margin-right: 20px; font-size: 14px; color: var(--c-text-secondary); cursor: pointer; position: relative; }
.urge-vtab.active { color: var(--c-primary); font-weight: 600; }
.urge-vtab.active::after { content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--c-primary); border-radius: 2px; }
.urge-rec-sums { display: grid; grid-template-columns: repeat(7, 1fr); gap: 10px; margin: 12px 0; }
.urge-rec-sum { background: var(--c-bg-card); border: 1px solid var(--c-border); border-radius: 8px; padding: 10px 12px; text-align: center; }
.urge-rec-sum b { display: block; font-size: 17px; font-weight: 600; color: var(--c-text); line-height: 1.3; }
.urge-rec-sum span { font-size: 11px; color: var(--c-text-secondary); }
.urge-rec-tbl td { font-size: 13px; }

/* ============================================================
 * 批次16：操作日志审计 + 站内消息发送/会话 + 智能设备（真实数据）
 * ============================================================ */

/* ---- 通用：口径卡（设备 / 操作日志共用） ---- */
.dv-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 14px; }
.dv-kpi { background: var(--c-bg-card); border: 1px solid var(--c-border); border-radius: 10px; padding: 14px 16px; }
.dv-kpi-n { font-size: 22px; font-weight: 600; color: var(--c-text); line-height: 1.3; }
.dv-kpi-l { font-size: 12px; color: var(--c-text-secondary); margin-top: 4px; }

/* ---- 操作日志 ---- */
.audit-page .h-tool { width: auto; min-width: 32px; padding: 0 12px; white-space: nowrap; font-size: 13px; }
.audit-page .h-tools { flex-shrink: 0; }
.audit-page .h-search { max-width: none; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
.audit-page .h-search .h-input[type="date"] { width: 148px; }
.audit-page .audit-toolbar { align-items: center; }
.au-tbl { width: 100%; }
.au-tbl td { font-size: 13px; vertical-align: top; }
.au-tbl .au-detail {
  max-width: 360px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--c-text-secondary); font-size: 12px;
}

/* ---- 智能设备 ---- */
.dv-page .h-tool { width: auto; min-width: 32px; padding: 0 12px; white-space: nowrap; font-size: 13px; }
.dv-page .h-tools { flex-shrink: 0; }
.dv-page .h-search { max-width: none; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
.dv-tbl td { font-size: 13px; vertical-align: middle; }
.dv-ops { white-space: nowrap; }
.dv-ops .ap-detail { margin-right: 6px; }
.dv-ops .link-red { color: var(--c-danger); }

/* ---- 消息中心：租客会话 ---- */
.msg-page .h-tool { width: auto; min-width: 32px; padding: 0 12px; white-space: nowrap; font-size: 13px; }
.msg-page .h-tools { flex-shrink: 0; }
.chat-list { max-height: 52vh; overflow-y: auto; padding: 12px 4px; background: var(--c-bg-page); border-radius: 10px; }
.chat-item { display: flex; flex-direction: column; align-items: flex-start; margin-bottom: 12px; }
.chat-item.mine { align-items: flex-end; }
.chat-bubble {
  max-width: 74%; padding: 9px 12px; border-radius: 10px; font-size: 13px; line-height: 1.6;
  background: var(--c-bg-card); border: 1px solid var(--c-border); color: var(--c-text); word-break: break-word;
}
.chat-item.mine .chat-bubble { background: var(--c-primary-light); border-color: var(--c-primary-light); }
.chat-time { font-size: 11px; color: var(--c-text-secondary); margin-top: 4px; }
.chat-reply { display: flex; gap: 10px; margin-top: 12px; align-items: flex-end; }
.chat-reply textarea {
  flex: 1; min-height: 64px; border: 1px solid var(--c-input-border); border-radius: 8px;
  padding: 8px 10px; font-size: 13px; resize: vertical; font-family: inherit; outline: none;
}
.chat-reply .st-form-save { height: 40px; padding: 0 22px; }

/* ================= 批次17：账单管理（真实分页 + 计数 + 汇总 + 批量） ================= */
.bm-page .bm-cnt { font-style: normal; font-size: 12px; color: var(--c-text-secondary); margin-left: 3px; }
.bm-page .h-tab.active .bm-cnt { color: var(--c-primary); }
/* ⚠ .h-tool 是原站的 32×32 图标按钮，放文字按钮必须覆盖宽度 */
.bm-page .h-tool { width: auto; padding: 0 12px; white-space: nowrap; }
.bm-sums { display: flex; flex-wrap: wrap; gap: 10px; padding: 10px 0 12px; align-items: center; }
.bm-sum { background: #fff; border: 1px solid var(--c-border); border-radius: 10px; padding: 8px 14px; font-size: 13px; color: var(--c-text-secondary); }
.bm-sum b { margin-left: 8px; font-size: 15px; color: var(--c-text-primary); }
.bm-sum-sel { display: flex; align-items: center; border-color: var(--c-primary); }
/* 表格新增勾选列 → 所有 nth-child 同步 +1（原 2/5/6/7 现为 3/6/7/8） */
.bm-tbl .bm-ck { width: 38px; text-align: center; }
.bm-tbl th:nth-child(2), .bm-tbl td:nth-child(2) { min-width: 150px; }
.bm-tbl td:nth-child(3) { min-width: 200px; color: var(--c-text-regular); }
.bm-tbl td:nth-child(6), .bm-tbl td:nth-child(7), .bm-tbl td:nth-child(8) { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px; }
.bm-pager { display: flex; align-items: center; justify-content: flex-end; gap: 6px; padding: 14px 0 4px; }
.bm-pg-info { margin-right: auto; font-size: 13px; color: var(--c-text-secondary); }
.bm-pager .pg-prev, .bm-pager .pg-next, .bm-pager .pg-num {
  height: 30px; min-width: 30px; padding: 0 10px; border: 1px solid var(--c-border);
  background: #fff; border-radius: 8px; cursor: pointer; font-size: 13px; color: var(--c-text-regular);
}
.bm-pager .pg-num.active { background: var(--c-primary); border-color: var(--c-primary); color: #fff; }
.bm-pager button[disabled] { opacity: .45; cursor: not-allowed; }
/* 批次17：账单管理工具栏换行（.h-search 默认 max-width:560px 且不换行，必须覆盖） */
.bm-page .h-toolbar { row-gap: 10px; }
.bm-page .h-search { flex: 1 1 620px; max-width: none; flex-wrap: wrap; }
.bm-page .h-tools { flex-shrink: 0; display: flex; align-items: center; gap: 6px; }
.bm-page .h-search .h-input[type="date"] { width: 148px; }
/* 批次76：bm-void 已改走 .dyn-table .op-btn.is-danger */

/* 批次18：收款记录 / 退款 / 流水页 */
/* 批次76：bm-rec / bm-refund 已改走 .dyn-table .op-btn */
.bl-tbl td, .bl-tbl th { white-space: nowrap; }
.bl-tbl td:nth-child(3) { white-space: normal; }
#blPager { display: flex; align-items: center; justify-content: flex-end; gap: 6px; padding: 14px 0 4px; }
#blPager .bm-pg-info { font-size: 13px; color: var(--c-text-secondary); margin-right: auto; }

/* ===== 批次21：第三方接入配置 - 支付接入向导 ===== */
.tp-guide { background: linear-gradient(135deg, #F0F6FF 0%, #F7FAFF 100%); border: 1px solid #D6E4FF; border-radius: 10px; padding: 16px 18px; margin-bottom: 6px; }
.tp-guide-head { font-size: 15px; font-weight: 600; color: #1A1A1A; margin-bottom: 10px; }
.tp-guide-status { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.tp-chip { font-size: 12px; padding: 3px 10px; border-radius: 12px; font-weight: 500; }
.tp-chip.ok { background: #E5F8F2; color: #16A37A; }
.tp-chip.off { background: #FFF1F0; color: #E5533D; }
.tp-guide-status .tp-tip { font-size: 12px; color: #8A94A6; }
/* 批次98：第三方配置卡片标题行。
   原来标题复用了 .st-form-row 的 96px 固定标签列，
   「微信支付 / 支付宝」「付呗 / 乐刷（聚合收单）」这类长标题会被挤成两三行，
   右侧状态徽标跟着往下掉。这里改成 flex 自适应，标题不换行。 */
.tp-card-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px dashed var(--c-border-light); }
.tp-card-head > b { font-size: 13px; font-weight: 600; color: #1D2129; }
.tp-card-head .badge { flex: 0 0 auto; }
.tp-card-head .st-tip { flex: 1 1 240px; min-width: 0; }
/* 批次98：卡片内的分组小标题（付呗 / 乐刷）。
   ⚠ 不能复用 .st-form-row —— 它的 label 列固定 96px，长标题会被截断，
     实测「付呗（聚合收单 · 文档 …）」只剩后半截，前半截被 overflow 吃掉了。 */
.tp-group-head { margin: 18px 0 10px; padding: 8px 12px; background: #F7F9FC; border-left: 3px solid #3974FF; border-radius: 4px; }
.tp-group-head > b { display: block; font-size: 13px; font-weight: 600; color: #1D2129; margin-bottom: 3px; }
.tp-group-head > span { display: block; font-size: 12px; line-height: 1.7; color: #8A94A6; }
.tp-steps { margin: 0; padding-left: 20px; }
.tp-steps li { font-size: 13px; line-height: 1.9; color: #334; }
.tp-steps li b { color: #1A1A1A; }
.tp-steps code { background: #EEF3FB; color: #2A5BD7; padding: 1px 6px; border-radius: 4px; font-size: 12px; font-family: SFMono-Regular, Consolas, monospace; word-break: break-all; }

/* ============================================================
 * 退租结算（批次31）
 * ============================================================ */
.ck-kpis { display: flex; gap: 12px; flex-wrap: wrap; padding: 0 0 12px; }
.ck-kpis .rp-kpi { flex: 1 1 150px; min-width: 140px; background: #fff; border: 1px solid #EDEFF3; border-radius: 8px; padding: 12px 14px; }
.ck-kpis .rp-kpi-label { font-size: 12px; color: #8A94A6; margin-bottom: 6px; }
.ck-kpis .rp-kpi-num { font-weight: 700; }
.ck-detail { font-size: 13px; }
.ck-sec { border: 1px solid #EDEFF3; border-radius: 8px; padding: 12px 14px; margin-bottom: 12px; background: #fff; }
.ck-sec-t { font-size: 14px; font-weight: 600; color: #1A1A1A; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px dashed #EDEFF3; }
.ck-kv { display: flex; justify-content: space-between; align-items: center; padding: 6px 0; font-size: 13px; color: #4E5969; }
.ck-kv b { color: #1A1A1A; font-weight: 600; }
.ck-kv.ck-total { border-top: 1px dashed #EDEFF3; margin-top: 6px; padding-top: 10px; }
.ck-sub { font-size: 12px; color: #8A94A6; margin-top: 6px; line-height: 1.7; }
.ck-warn { background: #FFF7E6; border: 1px solid #FFE0A3; color: #AD6800; border-radius: 6px; padding: 8px 10px; font-size: 12px; line-height: 1.7; margin-top: 8px; }
/* 退租结算弹窗的横排表单（批次77 对齐 .st-form-row：顶端对齐 + 同字号字重） */
.ck-form { display: flex; align-items: flex-start; gap: 12px; padding: 7px 0; }
.ck-form > label {
  width: 96px; flex: 0 0 96px;
  font-size: 13px; font-weight: 500; color: #475467; line-height: 20px;
  padding-top: 8px; text-align: right;
}
.ck-form > .h-input, .ck-form > .h-select { flex: 1 1 auto; min-width: 0; height: 36px; }
.cp-pager { display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 10px 4px; }
.cp-pager .muted { font-size: 12px; color: #8A94A6; }
.link-red { color: var(--c-danger-text); }
.link-red:hover { text-decoration: underline; }

/* ===== 批次32：出账中心（账期引擎） ===== */
.h-sec-title { font-size: 13px; color: var(--c-text-primary, #1f2329); }
.bl-periods { color: var(--c-primary, #3478F6); text-decoration: none; font-size: 12px; cursor: pointer; }
.bl-periods:hover { text-decoration: underline; }
#blBody .cp-table { max-height: none; }
#blBody .cp-table table { font-size: 12px; }
#blBody .empty-tip { padding: 18px 0; }
#blKpis .rp-kpi-num { white-space: nowrap; }

/* ==================================================================
   手机 / 平板适配（≤ 900px）
   ------------------------------------------------------------------
   原来侧边栏固定 168px + 主区 margin-left:168px：
   390px 的手机上侧栏吃掉 43% 宽度，主区被压到 222px，卡片里中文被竖排断字。
   这里把侧栏改成抽屉（顶栏汉堡开合），主区占满，表格允许横向滚动。
   ================================================================== */
/* 🔴 选择器必须带 button 限定（批次79）。
   这里原先是裸 `.nav-toggle`，本意只隐藏顶栏的手机汉堡按钮，但侧边栏
   12 个**分组标题**当时也用了 class="nav-item nav-toggle" → 被一起
   display:none → 9 个分组标题不可见，只剩默认展开的「房源」子项，
   用户以为「功能被精简了」。类名已改为 .nav-group-hd，这里再收窄到
   button 元素，双重保险，防止再次撞名。 */
button.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 32px;
  height: 32px;
  padding: 0 6px;
  margin-right: 6px;
  border-radius: 8px;
  cursor: pointer;
  flex: 0 0 32px;
}
button.nav-toggle span {
  display: block;
  height: 2px;
  width: 100%;
  border-radius: 2px;
  background: var(--c-text);
}
button.nav-toggle:active { background: var(--c-border-light, #f2f3f5); }

/* 侧边栏分组标题：显式声明可见，且与普通 nav-item 区分开 */
.sidebar .nav-group-hd { display: flex; }

/* ---- 侧边栏层级与密度（批次79）----
 * 分组标题恢复显示后暴露两个问题：
 *   ① 子项没有缩进 —— `.nav-sub a { padding-left:36px }` 被 v2 层
 *      `.sidebar a { padding:9px 12px }` 盖掉，子项和一级项左边缘完全对齐，
 *      看不出从属关系；
 *   ② 行高 40 + 上下 margin 2 = 44px/行，14 个一级项 + 7 个子项 = 924px，
 *      超出可视区 931−footer，底部「内容 / 设置」被挤到滚动区外。
 * 收到 36px 后 14×40 + 7×40 = 840px，一屏放得下。 */
.sidebar .nav-item { height: 36px; padding: 0 12px; }
.sidebar .nav-sub a {
  height: 34px;
  margin: 1px 10px;
  padding: 0 12px 0 38px;
  font-size: 13px;
  color: var(--c-text-regular);
}
.sidebar .nav-sub a.active { color: var(--c-sidebar-text-active); font-weight: 600; }

.nav-mask { display: none; }

@media (max-width: 900px) {
  html, body { -webkit-text-size-adjust: 100%; }

  button.nav-toggle { display: flex; }

  /* 侧栏：抽屉 */
  .sidebar {
    width: 232px;
    transform: translateX(-100%);
    transition: transform .26s ease;
    box-shadow: 2px 0 16px rgba(0, 0, 0, .22);
    z-index: 120;
  }
  body.nav-open .sidebar { transform: translateX(0); }
  .sidebar.collapsed { width: 232px; }
  .sidebar.collapsed .nav-item span,
  .sidebar.collapsed .nav-sub,
  .sidebar.collapsed .arrow,
  .sidebar.collapsed .nav-collapse span { display: revert; }
  .sidebar.collapsed .nav-item { justify-content: flex-start; padding: 0 14px; margin: 0; }

  .nav-mask {
    display: block;
    position: fixed;
    inset: var(--h-topbar) 0 0 0;
    background: rgba(0, 0, 0, .42);
    opacity: 0;
    pointer-events: none;
    transition: opacity .22s;
    z-index: 110;
  }
  body.nav-open .nav-mask { opacity: 1; pointer-events: auto; }

  /* 主区占满 */
  .main { margin-left: 0 !important; }

  /* 顶栏：收紧，只留必要元素 */
  .host-header { padding: 0 10px; gap: 6px; }

  /* 🔴 批次79：顶栏在 390 宽下会「左侧被压成 0 宽、右侧盖住汉堡」。
     根因是 `.header-left{min-width:0}` + `.header-right{flex-shrink:0}`：
     flex 把左侧压到 0 宽（量出来 w=0），而它的子元素仍按内容宽度绘制，
     于是汉堡（x=10）正好落在右侧第一个图标（x=16）下面 —— 点不到，
     手机上侧边栏抽屉根本打不开。这里让左侧不被压缩、右侧可收缩，
     再把 4 个次要图标（短信/钱包/帮助/客服）在窄屏收起。 */
  .header-left { flex: 0 0 auto; min-width: 0; }
  .header-right { flex: 0 1 auto; min-width: 0; }
  .logo-area { width: auto; padding-left: 8px; }
  /* ⚠ 必须 !important：3024 行的「按钮令牌层」给 .action-icon-btn 写了
     `display:inline-flex !important`，普通声明一律被吃掉（批次79 实测首版没生效）。 */
  .icon-actions > .action-icon-btn.is-aux { display: none !important; }
  .header-page-title { margin-left: 8px; font-size: 15px; }
  .header-subnav { display: none; }
  .logo-title { display: none; }
  .icon-actions { gap: 2px; }
  .action-icon-btn { width: 30px; height: 30px; }
  .create-btn { padding: 0 10px; }
  .create-btn span { display: none; }

  /* 内容区 */
  .content { padding: 10px !important; }
  .panel, .card { padding: 12px; }

  /* 栅格 */
  .grid-3, .grid-4, .kpi-grid { grid-template-columns: repeat(2, 1fr) !important; }

  /* 表格：横向滚动，不压缩列宽 */
  .table-wrap, .cp-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  table { min-width: 640px; }

  /* 弹窗 */
  .modal, .dialog { width: calc(100vw - 20px) !important; max-width: none !important; }

  /* 页头 */
  .page-head, .panel-head { flex-wrap: wrap; gap: 8px; }
}

@media (max-width: 480px) {
  .grid-3, .grid-4, .kpi-grid { grid-template-columns: 1fr !important; }
  .content { padding: 8px !important; }
  /* 🔴 这里原来写的是 `.action-icon-btn:nth-child(n+3){display:none}` —— 从来没生效过，
     被 3024 行按钮令牌层的 `display:inline-flex !important` 盖掉；而且它的取舍也不对
     （会留下「短信」、砍掉「消息」）。次要图标的收口统一由上面的 .is-aux 管。 */
}

/* 手机端补充：分页 / 按钮文字不要竖排断字 */
@media (max-width: 900px) {
  .pg-btn, .pg-num, .pg-prev, .pg-next,
  .h-tool, .btn, .create-btn, .tab-item, .filter-chip {
    white-space: nowrap;
    flex-shrink: 0;
  }
  .pager, .msg-pager, .bm-pager { flex-wrap: wrap; row-gap: 6px; }
  /* 待办提醒这类左右分栏在手机上要堆叠 */
  .todo-grid, .task-grid, .reminder-grid { grid-template-columns: 1fr !important; }
}

/* ============================================================================
   批次49：图标体系 + 按钮商业化升级
   —— 把 emoji 换成统一线性 SVG（jxy-icons.js），按钮向 SaaS 规范收敛。
   ============================================================================ */

/* ---------- 图标基座 ---------- */
.jxy-i {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  vertical-align: -0.15em;
  line-height: 1;
}
.jxy-i > svg { width: 100%; height: 100%; display: block; }
/* 图标 + 文字之间统一留白，避免每个模板各写一个空格 */
.jxy-i + *:not(.jxy-i) { margin-left: 0; }
.h-tool > .jxy-i, .btn-primary > .jxy-i, .btn-ghost > .jxy-i, .h-btn > .jxy-i { margin-right: 5px; }
.h-tool > .jxy-i:last-child, .btn-primary > .jxy-i:last-child, .btn-ghost > .jxy-i:last-child { margin-right: 0; }

/* 纯图标按钮：正方形，不带文字内边距 */
.h-tool.jxy-only {
  width: 32px; height: 32px; padding: 0 !important;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; color: var(--c-text-secondary, #5B6472);
}
.h-tool.jxy-only:hover { color: var(--c-primary); background: var(--c-primary-soft, #EEF3FF); }

/* 图标按钮内的图标随字号走，不要再被 h-tool 的 padding 挤歪 */
.h-tool .jxy-i { font-size: 15px; }

/* ---------- 按钮体系：统一圆角 / 高度 / 字重 / 焦点环 ---------- */
.btn-primary, .btn-ghost, .h-tool, .h-btn, .set-card-btn, .link-blue {
  -webkit-tap-highlight-color: transparent;
}
.btn-primary:focus-visible, .btn-ghost:focus-visible, .h-tool:focus-visible,
.h-btn:focus-visible, .set-card-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(47, 107, 255, .22);
}
.btn-primary:active, .set-card-btn:active { transform: translateY(0); box-shadow: 0 3px 10px rgba(47,107,255,.24); }
.btn-ghost:active, .h-tool:active { transform: translateY(0); }

/* 次要按钮：白底 + 细边，hover 才上色（原来颜色偏灰、边界不清） */
.btn-ghost {
  background: #fff !important;
  border: 1px solid var(--c-input-border, #DCDFE6) !important;
  color: var(--c-text-regular, #5B6472) !important;
  font-weight: 500;
}
.btn-ghost:hover {
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
  background: var(--c-primary-soft, #EEF3FF) !important;
}

/* 危险操作按钮：平色，去掉渐变与彩色阴影 */
.btn-danger, .btn-primary.danger {
  background: var(--c-danger) !important;
  border: 1px solid var(--c-danger) !important;
  box-shadow: none;
}
.btn-danger:hover, .btn-primary.danger:hover {
  background: #E0362F !important;
  border-color: #E0362F !important;
}

/* 卡片里的主操作按钮：与主按钮同尺寸（原 34px/8px 与主按钮 32px/6px 混排） */
.set-card-btn {
  height: 32px; padding: 0 14px; border-radius: 6px; border: 1px solid var(--c-primary);
  background: var(--c-primary);
  color: #fff; font-size: 13px; font-weight: 500; cursor: pointer;
  box-shadow: none;
}
.set-card-btn:hover { background: var(--c-primary-hover); border-color: var(--c-primary-hover); }

/* 文字链接：做成「带箭头的操作」而不是纯蓝字 */
.link-blue {
  color: var(--c-primary);
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border-radius: 6px;
  padding: 1px 2px;
}
.link-blue:hover { text-decoration: none; background: var(--c-primary-light, #EEF3FF); }
.link-blue .jxy-i { font-size: 13px; }

/* ============================================================================
   设计系统 · 按钮统一层 v1（阶段②「收敛」）
   ----------------------------------------------------------------------------
   唯一真源：D:/zu/design-system/components.css（.ds-btn--*）
   本层**不改任何类名** —— script.js 里 300+ 处字符串拼接，改类名风险过高。
   做法：把散落在 20+ 处的同类定义，收敛成同一套尺寸 / 圆角 / 字重 / 状态。

   收敛前的实测问题（这就是「不像商业产品」的具体来源）：
     · 品牌蓝 6 种取值        · .btn-primary 定义 10 次
     · 按钮高度 30/32/34 混排 · 圆角 2/4/6/8/99 混排
     · 主按钮用渐变 + 彩色投影 + hover 上浮（廉价感三件套）
     · 禁用态用 opacity 表达（看起来像「半透明可用」而不是「不可用」）

   ⚠ 本层用 !important 是刻意的：107 处按钮带内联 style="height:.."，
     类选择器无法覆盖内联样式，只有 !important 能收口。
     全部集中在这一段，不再散落 —— 后续新增按钮只需引用上面的类名即可。
   ============================================================================ */

:root {
  /* 尺寸档位：24 / 28 / 32 / 40（规范四档，本层只用到前三档） */
  --btn-h: 32px;
  --btn-h-sm: 28px;
  --btn-h-xs: 24px;
  --btn-px: 14px;
  --btn-px-sm: 10px;
  --btn-r: 8px;
  --btn-fs: 13px;
  --btn-fs-sm: 12px;
  --btn-fw: 500;

  /* 品牌蓝唯一值（原 --c-primary 是 #3974ff，与设计规范的 #2F6BFF 不同源） */
  --c-primary: #2F6BFF;
  --c-primary-hover: #1E5AF0;
  --c-primary-active: #164BD6;
  --c-primary-light: #EEF3FF;
  /* ⚠ --c-primary-soft 原来只被引用、从未定义 → .h-tool:hover 的背景一直是无效值 */
  --c-primary-soft: #EEF3FF;
  --c-primary-ring: rgba(47, 107, 255, .24);

  /* 禁用态：真灰，不用 opacity */
  --btn-off-bg: #F2F4F7;
  --btn-off-text: #A8B0BE;
  --btn-off-border: #E3E8F2;
}

/* ---------- ① 主按钮族：平色实心，32px ---------- */
.btn-primary,
.st-form-save,
.set-card-btn,
.sms-send-btn,
.create-btn,
.btn-add {
  height: var(--btn-h) !important;
  min-height: var(--btn-h) !important;
  padding: 0 var(--btn-px) !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs) !important;
  font-weight: var(--btn-fw) !important;
  line-height: 1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 6px;
  box-sizing: border-box !important;
  white-space: nowrap;
  background-image: none !important;   /* 兜底：清掉任何遗留渐变 */
  box-shadow: none !important;         /* 兜底：清掉任何彩色投影 */
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}

.btn-primary,
.st-form-save,
.set-card-btn,
.sms-send-btn,
.create-btn,
.btn-add {
  background-color: var(--c-primary) !important;
  border: 1px solid var(--c-primary) !important;
  color: #fff !important;
}

.btn-primary:hover,
.st-form-save:hover,
.set-card-btn:hover,
.sms-send-btn:hover,
.create-btn:hover,
.btn-add:hover {
  background-color: var(--c-primary-hover) !important;
  border-color: var(--c-primary-hover) !important;
  transform: none !important;          /* 规范：主按钮 hover 不位移 */
  box-shadow: none !important;
}

.btn-primary:active,
.st-form-save:active,
.set-card-btn:active,
.sms-send-btn:active,
.create-btn:active,
.btn-add:active {
  background-color: var(--c-primary-active) !important;
  border-color: var(--c-primary-active) !important;
}

/* ---------- ② 次按钮族：白底细边，32px ---------- */
.btn-ghost {
  height: var(--btn-h) !important;
  min-height: var(--btn-h) !important;
  padding: 0 var(--btn-px) !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs) !important;
  font-weight: var(--btn-fw) !important;
  line-height: 1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 6px;
  box-sizing: border-box !important;
  white-space: nowrap;
  background: #fff !important;
  border: 1px solid var(--btn-off-border) !important;
  color: var(--c-text-regular) !important;
  box-shadow: none !important;
}
.btn-ghost:hover {
  background: var(--c-primary-light) !important;
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
}

/* ---------- ③ 图标按钮：32×32 方形 ----------
   ⚠ 这里**不能给 height/width/padding 加 !important**：后台有 40+ 个 h-tool 靠内联
     style="width:auto;padding:0 12px" 撑开（"导出" / "批量生成正文" / "保存跟进"…），
     也有 style="height:24px" 的行内小按钮。一加 !important 就把内联样式打掉 → 文字被截断。
     所以：尺寸交给「原 .h-tool 的 32px + 内联覆盖」，本层只统一视觉（圆角/边框/色/状态）。 */
.h-tool,
.h-btn,
.h-more-btn,
.h-eye-btn,
.action-icon-btn {
  height: var(--btn-h);
  min-width: var(--btn-h);
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs);
  font-weight: var(--btn-fw);
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  background: #fff;
  border: 1px solid var(--btn-off-border);
  color: var(--c-text-regular);
  box-shadow: none !important;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.h-tool:hover,
.h-btn:hover,
.h-more-btn:hover,
.h-eye-btn:hover,
.action-icon-btn:hover {
  background: var(--c-primary-light) !important;
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
}
/* 带文字的工具栏按钮：宽度自适应，字号对齐（高度仍尊重内联） */
.h-tool.h-tool-text {
  width: auto !important;
  padding: 0 var(--btn-px) !important;
  font-size: var(--btn-fs) !important;
  font-weight: var(--btn-fw) !important;
  gap: 6px;
}

/* ---------- ④ 表格行内操作：28px ---------- */
.be-edit-btn,
.pm-act-btn,
.pd-act-btn,
.mt-act-btn,
.ns-act-btn,
.cf-act-btn,
.cu-act-btn,
.act-btn,
.bi-issue,
.bi-detail,
.bi-download,
.btn-mini,
.ap-detail,
.ap-pass,
.task-go-btn {
  height: var(--btn-h-sm) !important;
  min-height: var(--btn-h-sm) !important;
  padding: 0 var(--btn-px-sm) !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs-sm) !important;
  font-weight: var(--btn-fw) !important;
  line-height: 1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  white-space: nowrap;
  background-image: none !important;
  box-shadow: none !important;
  margin-right: 6px;
  vertical-align: middle;
}

/* 行内「中性」操作：白底灰边 */
.be-edit-btn,
.pm-act-btn,
.pd-act-btn,
.mt-act-btn,
.ns-act-btn,
.cf-act-btn,
.cu-act-btn,
.act-btn,
.bi-detail,
.bi-download,
.task-go-btn {
  background-color: #fff !important;
  border: 1px solid var(--btn-off-border) !important;
  color: var(--c-text-regular) !important;
}
.be-edit-btn:hover,
.pm-act-btn:hover,
.pd-act-btn:hover,
.mt-act-btn:hover,
.ns-act-btn:hover,
.cf-act-btn:hover,
.cu-act-btn:hover,
.act-btn:hover,
.bi-detail:hover,
.bi-download:hover,
.task-go-btn:hover {
  background-color: var(--c-primary-light) !important;
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
}

/* 行内「强调」操作：白底蓝边蓝字（开票 / 通过 / 详情链接式） */
.bi-issue,
.ap-detail,
.ap-pass,
.btn-mini {
  background-color: #fff !important;
  border: 1px solid var(--c-primary) !important;
  color: var(--c-primary) !important;
}
.bi-issue:hover,
.ap-detail:hover,
.ap-pass:hover,
.btn-mini:hover {
  background-color: var(--c-primary) !important;
  border-color: var(--c-primary) !important;
  color: #fff !important;
}

/* ---------- ⑤ 文字链 ---------- */
/* 破坏性文字链（终止 / 作废 / 删除）：必须在视觉上和普通链接区分开。
   ⚠ 两个坑（批次96 都踩过）：
   1) 不能靠内联 style —— `.link-blue` 用了 `color: ... !important`，内联压不过 !important；
   2) 光写 `.link-danger` 也不行 —— 同权重同 !important 时「后出现的赢」，
      而 `.link-blue` 在这条之后。必须用 `.link-blue.link-danger`（0,2,0）提高权重。 */
.link-blue.link-danger,
.link-blue.link-danger:hover {
  color: #D92D20 !important;
}
.link-blue,
.btn-link,
.sms-link-btn {
  font-size: var(--btn-fs) !important;
  font-weight: var(--btn-fw) !important;
  color: var(--c-primary) !important;
  background: none !important;
  border: 0 !important;
  padding: 1px 2px !important;
  border-radius: var(--btn-r) !important;
  cursor: pointer;
  text-decoration: none !important;
}
.link-blue:hover,
.btn-link:hover,
.sms-link-btn:hover {
  color: var(--c-primary-hover) !important;
  background: var(--c-primary-light) !important;
  text-decoration: none !important;
}

/* ---------- ⑥ 禁用态：真灰，不用 opacity ---------- */
.btn-primary:disabled,
.btn-primary.is-disabled,
.btn-ghost:disabled,
.btn-ghost.is-disabled,
.st-form-save:disabled,
.set-card-btn:disabled,
.sms-send-btn:disabled,
.create-btn:disabled,
.btn-add:disabled,
.h-tool:disabled,
.h-btn:disabled,
.act-btn:disabled,
.bi-issue:disabled,
.bi-detail:disabled,
.bi-download:disabled,
.btn-mini:disabled,
.pg-btn:disabled {
  background: var(--btn-off-bg) !important;
  background-image: none !important;
  border-color: var(--btn-off-border) !important;
  color: var(--btn-off-text) !important;
  box-shadow: none !important;
  opacity: 1 !important;             /* 禁用不靠透明度表达 */
  cursor: not-allowed !important;
  transform: none !important;
}
.btn-primary:disabled:hover,
.btn-ghost:disabled:hover,
.st-form-save:disabled:hover,
.set-card-btn:disabled:hover,
.h-tool:disabled:hover,
.act-btn:disabled:hover,
.btn-mini:disabled:hover {
  background: var(--btn-off-bg) !important;
  border-color: var(--btn-off-border) !important;
  color: var(--btn-off-text) !important;
}

/* ---------- ⑦ 焦点环：键盘可达性统一 ---------- */
.btn-primary:focus-visible,
.btn-ghost:focus-visible,
.st-form-save:focus-visible,
.set-card-btn:focus-visible,
.sms-send-btn:focus-visible,
.create-btn:focus-visible,
.btn-add:focus-visible,
.h-tool:focus-visible,
.h-btn:focus-visible,
.h-more-btn:focus-visible,
.h-eye-btn:focus-visible,
.action-icon-btn:focus-visible,
.be-edit-btn:focus-visible,
.act-btn:focus-visible,
.bi-issue:focus-visible,
.bi-detail:focus-visible,
.bi-download:focus-visible,
.btn-mini:focus-visible,
.link-blue:focus-visible,
.btn-link:focus-visible {
  outline: none !important;
  box-shadow: 0 0 0 3px var(--c-primary-ring) !important;
}

/* ============================================================================
   按钮统一层 · 补充段（阶段② 第二轮：把漏掉的类补齐）
   ----------------------------------------------------------------------------
   第一轮只覆盖了「按语义分组」的类名，实跑真实数据（307 行）后发现还漏了
   账单管理 / 发票管理 / 分页器 / 加载更多 这几组，它们的共同特征是：
   各自写了一份 padding:3px 10px + border-radius:4px，与其他行内按钮差 1px 高度、差 2px 圆角。
   1px 的差异单看无所谓，44 个页面放在一起就是「不专业」的来源。
   ============================================================================ */

/* ---------- ① 行内操作补充：发票 / 打印 ----------
 * 批次76：bm-mark / bm-void / bm-detail / bm-rec / bm-refund / bm-invoice
 * 已从这张表里移出 —— 它们现在统一走 `.dyn-table .op-btn`（见文件末尾）。
 * 留在这里会有严重后果：下面这些 `!important` 会把 `.op-btn.is-primary`
 * 的 `color:#fff` 覆盖成 `color:var(--c-success)`，于是「收款」变成
 * **蓝底绿字**（截图里就是一个空的蓝色色块，字看不见）。
 */
.bm-print,
.bi-email,
.bi-void {
  height: var(--btn-h-sm) !important;
  min-height: var(--btn-h-sm) !important;
  padding: 0 var(--btn-px-sm) !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs-sm) !important;
  font-weight: var(--btn-fw) !important;
  line-height: 1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  white-space: nowrap;
  background-image: none !important;
  box-shadow: none !important;
  margin-right: 6px;
  vertical-align: middle;
  cursor: pointer;
  background-color: #fff;
}

/* 中性：打印 */
.bm-print {
  border: 1px solid var(--btn-off-border) !important;
  color: var(--c-text-regular) !important;
}
.bm-print:hover {
  background-color: var(--c-primary-light) !important;
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
}

/* 文字链式（补录 / 作废发票）：无边框，但高度对齐行内档 */
.bi-email,
.bi-void {
  border: 0 !important;
  color: var(--c-primary) !important;
  background-color: transparent !important;
}
.bi-email:hover {
  background-color: var(--c-primary-light) !important;
  color: var(--c-primary-hover) !important;
}
.bi-void { color: var(--c-danger) !important; }
.bi-void:hover { background-color: var(--c-danger-light) !important; }

/* ---------- ② 分页器：30 / 23 两种高度并存，统一到 28 ---------- */
.pg-btn,
.pg-num,
.pg-prev,
.pg-next,
.pg-first,
.pg-last {
  height: var(--btn-h-sm) !important;
  min-width: var(--btn-h-sm) !important;
  padding: 0 var(--btn-px-sm) !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs-sm) !important;
  line-height: 1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  background: #fff !important;
  border: 1px solid var(--btn-off-border) !important;
  color: var(--c-text-regular) !important;
  cursor: pointer;
}
.pg-num { min-width: var(--btn-h-sm) !important; padding: 0 !important; }
.pg-btn:hover,
.pg-num:hover,
.pg-prev:hover,
.pg-next:hover {
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
}
.pg-num.active {
  background: var(--c-primary) !important;
  border-color: var(--c-primary) !important;
  color: #fff !important;
  font-weight: 600 !important;
}
.pg-btn:disabled,
.pg-prev:disabled,
.pg-next:disabled {
  background: var(--btn-off-bg) !important;
  border-color: var(--btn-off-border) !important;
  color: var(--btn-off-text) !important;
  opacity: 1 !important;
  cursor: not-allowed !important;
}

/* ---------- ③ 加载更多：胶囊 35px → 常规按钮 32px ---------- */
.h-loadmore {
  height: var(--btn-h) !important;
  padding: 0 var(--btn-px) !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs) !important;
  font-weight: var(--btn-fw) !important;
  line-height: 1 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  box-sizing: border-box !important;
  background: #fff !important;
  border: 1px solid var(--btn-off-border) !important;
  color: var(--c-text-regular) !important;
  cursor: pointer;
}
.h-loadmore:hover {
  border-color: var(--c-primary) !important;
  color: var(--c-primary) !important;
  background: var(--c-primary-light) !important;
}

/* ---------- ④ 危险文字链 ---------- */
.link-red {
  font-size: var(--btn-fs) !important;
  font-weight: var(--btn-fw) !important;
  color: var(--c-danger) !important;
  background: none !important;
  border: 0 !important;
  padding: 1px 2px !important;
  border-radius: var(--btn-r) !important;
  cursor: pointer;
  text-decoration: none !important;
}
.link-red:hover {
  background: var(--c-danger-light) !important;
  text-decoration: none !important;
}

/* ---------- ⑤ 行内「强调」变体：白底蓝边 → hover 实心 ---------- */
.act-btn--primary {
  background-color: #fff !important;
  border: 1px solid var(--c-primary) !important;
  color: var(--c-primary) !important;
}
.act-btn--primary:hover {
  background-color: var(--c-primary) !important;
  border-color: var(--c-primary) !important;
  color: #fff !important;
}

/* ============================================================================
   设计系统 · 列表页统一层 v1（阶段③）
   ----------------------------------------------------------------------------
   唯一真源：D:\zu\design-system\components.css
   与阶段② 同一策略：**不改类名、不动 DOM**，只在末尾收口样式。

   改前实测（18 个列表页，tools/_b65-probe.mjs）：
     · 页签高度 37 / 38 两种，胶囊 999px，选中态是「浅蓝底 + 蓝字」
       → 与旁边实心蓝的「查询」按钮形成两个蓝块，层次不清
     · 筛选区 3 页换行（账单管理 / 收款流水 / 合同列表），合同列表还横向溢出
       → 根因是 .h-search 写死 max-width:460px，控件挤在一起时只能压缩子元素
     · 表格行高 8 种（46/48/53/54/67/68/70），数字列不等宽 → 金额对不齐
     · 空态只有一行灰字，没有图标、没有视觉重量
     · 表头对齐不统一（4 页 center、其余 left）

   改后目标：
     · 页签统一「下划线」——它是「视图切换」不是按钮，不该和主操作抢色块
     · 筛选区：页签不压缩、筛选控件可换行但每个控件自身不压缩
     · 表格：行高收敛、数字等宽、表头统一左对齐（金额列右对齐由页面内联样式负责）
     · 空态：图标 + 主文案 + 提示语三层
   ============================================================================ */

/* ---------- ① 页签：胶囊 → 下划线 ----------
   下划线用 ::after 画在按钮自身底部，不依赖容器分隔线 ——
   这样它在 .h-toolbar 里、在卡片里、在裸容器里都长得一样。 */
.h-tabs {
  display: flex;
  gap: 20px;
  flex-wrap: nowrap;
  align-items: center;
}
.h-tab {
  position: relative;
  height: var(--btn-h) !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  color: var(--c-text-regular) !important;
  font-size: var(--btn-fs) !important;
  font-weight: 500 !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 5px;
  white-space: nowrap;
  cursor: pointer;
  transition: color .15s ease;
}
.h-tab:hover {
  background: transparent !important;
  color: var(--c-primary) !important;
}
.h-tab.active {
  background: transparent !important;
  color: var(--c-primary) !important;
  border-color: transparent !important;
  font-weight: 600 !important;
}
/* 选中下划线：2px 主色，压在文字正下方 */
.h-tab.active::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 1px;
  background: var(--c-primary);
}
/* 页签里的计数（「全部(211)」）：做成轻量徽标，不再和标题同字号 */
.h-tab .wo-cnt,
.h-tab .tab-cnt {
  font-size: 11.5px !important;
  font-weight: 500 !important;
  color: var(--c-text-secondary) !important;
  background: transparent !important;
  padding: 0 !important;
}
.h-tab.active .wo-cnt,
.h-tab.active .tab-cnt {
  color: var(--c-primary) !important;
  background: transparent !important;
}

/* ---------- ② 筛选区：页签不压缩，控件不被挤扁 ---------- */
.h-toolbar {
  display: flex;
  align-items: center;
  gap: 10px 14px;
  flex-wrap: wrap;
  padding: 10px 0;
  border-bottom: 1px solid var(--c-border-light);
  margin-bottom: 12px;
}
/* 布局：有页签时 —— 第 1 行「页签 + 操作按钮」，第 2 行「筛选控件独占一行」。
   这是商业后台的标准结构：视图切换与页面级操作同行，筛选条件单独一行。
   用 order 而不是改 DOM 顺序 —— script.js 里 15 个页面的筛选区是各自拼的字符串。 */
.h-toolbar:has(> .h-tabs) > .h-tabs { order: 1; flex: 1 1 auto; min-width: 0; }
.h-toolbar:has(> .h-tabs) > .h-tools { order: 2; flex: 0 0 auto; margin-left: auto; }
.h-toolbar:has(> .h-tabs) > .h-search { order: 3; flex: 1 0 100%; margin-top: 2px; }
/* 无页签的页面（供应商 / 应付账款 / 出账中心 / 业主结算）保持一行，不额外占高度 */
.h-toolbar:not(:has(> .h-tabs)) > .h-search { flex: 1 1 300px; min-width: 260px; }
/* ⚠ 原来 .h-search 写死 max-width:460px/560px，控件一多就只能压缩子元素
   → 日期框被压成 129px、合同列表直接横向溢出。这里放开宽度，改成「可换行」。 */
.h-toolbar > .h-search,
.h-search {
  flex: 1 1 300px;
  min-width: 260px;
  max-width: none;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  row-gap: 8px;
}
/* 筛选控件自身不许被压缩（压缩 = 日期框显示不全） */
.h-toolbar > .h-search > *,
.h-search > .h-select,
.h-search > input {
  flex: 0 0 auto;
}
.h-search > .h-input,
.h-search > input[type="text"] {
  flex: 1 1 auto;
  min-width: 180px;
}
.h-toolbar > .h-tools {
  flex: 0 0 auto;
  margin-left: auto;
}
/* 日期框：原生控件在不同浏览器下宽度差异大，给死最小宽度 */
.h-toolbar input[type="date"],
.h-toolbar input[type="month"],
.h-search input[type="date"],
.h-search input[type="month"] {
  min-width: 138px !important;
  flex: 0 0 auto !important;
}
/* 筛选区高度统一（原来 58 / 59 / 61 / 63 四种） */
.h-toolbar .h-select,
.h-toolbar .h-input {
  height: var(--btn-h) !important;
  box-sizing: border-box;
  padding: 0 10px !important;
  border-radius: var(--btn-r) !important;
  font-size: var(--btn-fs) !important;
}

/* ---------- ③ 表格：行高收敛 + 数字等宽 ---------- */
.dyn-table thead th {
  padding: 10px 14px !important;
  text-align: left;
  color: var(--c-text-secondary) !important;
  font-size: 12px !important;
  font-weight: 600 !important;
  letter-spacing: .2px;
  background: #F8FAFD !important;
  border-bottom: 1px solid var(--c-border) !important;
}
.dyn-table tbody td {
  padding: 10px 14px !important;
  border-bottom: 1px solid var(--c-border-light) !important;
  /* 等宽数字：金额列上下对齐，扫一眼就能比大小 */
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
/* 金额/数量列统一右对齐（页面若已内联 style 指定，内联优先） */
.dyn-table th.is-num,
.dyn-table td.is-num {
  text-align: right !important;
}
.dyn-table tbody tr:hover td {
  background: #FAFCFF !important;
}

/* ---------- ④ 空态：图标 + 主文案 + 提示 ----------
   .empty / .no-data 是现有唯一成体系的空态类（style.css 2166 行），
   这里给它加一个「空盒子」图标，并把排版做成三层。 */
.empty,
.no-data {
  padding: 52px 16px 56px !important;
  text-align: center;
  color: var(--c-text-secondary, #4E5969);
  font-size: 13px;
  line-height: 1.75;
}
.empty::before,
.no-data::before {
  content: '';
  display: block;
  width: 52px;
  height: 52px;
  margin: 0 auto 14px;
  opacity: .38;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7A99' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l9-5 9 5v9a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 17.5z'/%3E%3Cpath d='M3 8.5l9 5 9-5'/%3E%3Cpath d='M12 13.5v6'/%3E%3C/svg%3E") center/contain no-repeat;
}
/* 空态里的「下一步」链接：做成一个轻量按钮，不要裸蓝字 */
.empty a,
.no-data a,
.empty button,
.no-data button {
  display: inline-flex;
  align-items: center;
  height: var(--btn-h-sm);
  padding: 0 var(--btn-px);
  margin-top: 12px;
  border: 1px solid var(--c-primary);
  border-radius: var(--btn-r);
  color: var(--c-primary) !important;
  background: #fff;
  font-size: var(--btn-fs);
  font-weight: 500;
  text-decoration: none !important;
  cursor: pointer;
}
.empty a:hover,
.no-data a:hover,
.empty button:hover,
.no-data button:hover {
  background: var(--c-primary);
  color: #fff !important;
}

/* ---------- ⑤ 表格空态（表格里只有一行「暂无数据」时） ---------- */
.dyn-table tbody td[colspan] .empty,
.dyn-table tbody td[colspan] .no-data,
.dyn-table tbody tr.is-empty td {
  border-bottom: 0 !important;
}

/* ---------- ⑥ 表格外层：允许横向滚动，不再静默裁剪 ----------
   根因：本文件 2240 行 `.h-quick-table,.dv-table,.bill-manage-table{overflow:hidden}`
   覆盖了 1812 行的 `overflow-x:auto` → 账单管理表 1334px > 容器 1192px，
   右侧「作废」按钮直接被裁掉，且**没有任何视觉提示**（比报错更难发现）。
   这里统一兜住：任何直接包着 table 的 `*-table` 容器都可横向滚动。
   ⚠ 用 :has(> table) 而不是 :has(> .dyn-table) —— 出账中心 5 处是裸 table。 */
[class*="-table"]:has(> table),
[class*="-tbl"]:has(> table) {
  overflow-x: auto !important;
  overflow-y: visible;
  /* 让容器自己成为滚动容器后，圆角依旧裁切内容，不用额外包一层 */
  -webkit-overflow-scrolling: touch;
}

/* ---------- ⑦ 表格密度：14px → 12px 左右内距 ----------
   14 列的合同表 1429px，光靠滚动体验不好；每列省 4px 就能少滚 50 多像素。
   行高目标：单行 44（10+10+22+1border）、双行 64。 */
.dyn-table thead th,
.dyn-table tbody td {
  padding-left: 12px !important;
  padding-right: 12px !important;
}
.dyn-table tbody td {
  line-height: 22px !important;
}
/* 单元格里的次要信息（电话 / 楼栋号 / 月份）：统一 11.5px / 18px 行高，
   原来各页写 11px、12px、13px 三种，两行单元格总高度差出 8px。 */
.dyn-table tbody td .cell-sub,
.dyn-table tbody td small,
.dyn-table tbody td .sub-txt {
  font-size: 11.5px !important;
  line-height: 18px !important;
  color: var(--c-text-secondary) !important;
}

/* ---------- ⑧ 操作列：禁止折行 ----------
   ⚠ 试过 `width:1%`（业界常见的「按内容宽」写法）—— 在 auto 布局下**无效**：
     实测操作列仍占 254px（内容只有 150px），多出的 104px 被当成剩余空间分配掉了。
     `max-width:174px` 能压住，但按死像素，换一行按钮数量就溢出。
     结论：宽表靠 ⑫ 收内距 + ⑬ 操作列吸附解决，这里只保证按钮不折行。 */
.dyn-table tbody td:last-child:has(> button),
.dyn-table tbody td:last-child:has(> a) {
  white-space: nowrap;
}

/* ---------- ⑨ 空态：真实类名（v1 打错成 .empty/.no-data，这两个类全站不存在）----------
   实测真实空态类共 6 个：.empty-tip(21 处) / .wo-empty(15) / .msg-empty(8)
   / .todo-empty(6) / .schedule-empty(2) / .rp-empty(2)。
   原样式各写各的：padding 从 0 到 60px、字号 12/13、有的连居中都靠父元素。 */
.empty-tip,
.wo-empty,
.msg-empty,
.todo-empty,
.schedule-empty,
.rp-empty {
  display: block;
  padding: 48px 16px 52px !important;
  margin: 0 !important;
  text-align: center !important;
  color: var(--c-text-secondary, #4E5969) !important;
  font-size: 13px !important;
  line-height: 1.75 !important;
  background: transparent !important;
  border: 0 !important;
}
/* 空态图标：用 ::before 画，不改 DOM —— 6 个类分散在 21+ 处字符串拼接里 */
.empty-tip::before,
.wo-empty::before,
.msg-empty::before,
.todo-empty::before,
.schedule-empty::before,
.rp-empty::before {
  content: '';
  display: block;
  width: 52px;
  height: 52px;
  margin: 0 auto 14px;
  opacity: .34;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7A99' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l9-5 9 5v9a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 17.5z'/%3E%3Cpath d='M3 8.5l9 5 9-5'/%3E%3Cpath d='M12 13.5v6'/%3E%3C/svg%3E") center/contain no-repeat;
}
/* 出账中心嵌在卡片里，空态不需要 52px 的图标占位 */
#blBody .empty-tip {
  padding: 22px 16px 24px !important;
}
#blBody .empty-tip::before {
  width: 36px;
  height: 36px;
  margin-bottom: 8px;
}

/* ---------- ⑩ 表格内空态（colspan 行）去掉多余边框与内距 ---------- */
.dyn-table tbody tr.is-empty td,
.dyn-table tbody td[colspan] .empty-tip,
.dyn-table tbody td[colspan] .wo-empty {
  border-bottom: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* ---------- ⑪ 状态徽标：高度统一，不再把行高顶起来 ----------
   徽标各自 padding 2/3/4px、line-height 1.4/1.6 → 单行单元格 43~50 五种行高。 */
.dyn-table tbody td .badge,
.dyn-table tbody td .tag,
.dyn-table tbody td .pill {
  display: inline-flex !important;
  align-items: center;
  /* ⚠ 必须 middle：inline-flex 默认按基线对齐，18px 的徽标坐在基线上会把
     22px 的行盒撑到 24~30px —— 单行行高因此出现 43/45/49/51 四种。
     18px = 与 .cell-sub 的 18px 行高对齐，两行单元格稳定在 65。 */
  vertical-align: middle;
  height: 18px;
  padding: 0 7px !important;
  border-radius: 4px !important;
  font-size: 11.5px !important;
  line-height: 1 !important;
  white-space: nowrap;
}

/* ---------- ⑫ 宽表收内距：把表格拉回容器宽度 ----------
   账单管理 12 列原 1288px > 内容区 1192px（1440 屏），「操作」被顶出可视区。
   两处修正：
     a) 两列 min-width 给得太宽（账单号 150 实际只需 ~60、房源 200 实际只需 ~105）
     b) 水平内距 12 → 10，12 列共省 48px
   ⚠ 选择器必须写 `.dyn-table.bm-tbl` —— ⑦ 的 `.dyn-table tbody td` 特异性更高，
     只写 `.bm-tbl td` 压不住（同是 !important 时比特异性）。 */
.dyn-table.bm-tbl th,
.dyn-table.bm-tbl td {
  padding-left: 10px !important;
  padding-right: 10px !important;
}
.dyn-table.bm-tbl th:nth-child(2),
.dyn-table.bm-tbl td:nth-child(2) { min-width: 120px !important; }  /* 账单号 BD000768 */
.dyn-table.bm-tbl th:nth-child(3),
.dyn-table.bm-tbl td:nth-child(3) { min-width: 152px !important; }  /* 房源 杭州未来城 H0303 */

/* 合同列表 14 列：1313px，收内距后仍需横向滚动 —— 这是列数决定的，不强求塞进 1192。
   靠 ⑬ 的操作列吸附保证「查看/编辑/撤销」永远可点。 */
.dyn-table.ct-tbl th,
.dyn-table.ct-tbl td {
  padding-left: 10px !important;
  padding-right: 10px !important;
}

/* ---------- ⑬ 窄屏渐进披露：合同列表隐藏两列派生信息 ----------
   合同列表 14 列在 1440 屏合计 1313px > 内容区 1192px，「操作」列被裁掉。

   ⚠ 先试过「操作列 position:sticky 到右侧」——**实测无效**：滚动 80px 后
     单元格跟着内容一起左移（tdR 1521→1441），完全没有吸附效果。
     `<td>` 上的 sticky 在 border-collapse:separate 的 auto 布局表里不可靠。

   改用确定性方案：窄屏隐藏两列**可从其他列推导**的信息 ——
     · 租期（「1 年」）= 合同周期 的两个日期之差
     · 录入日期 = 只用于内部排序，详情页可查
   隐藏后 1313 - 61 - 94 = 1158px，1440 屏完整显示，不需要横向滚动。
   ⚠ 用 display:none 隐藏列是安全的：空态行是单个 colspan 单元格，浏览器会自动收窄。 */
@media (max-width: 1599px) {
  .ct-tbl th:nth-child(9),
  .ct-tbl td:nth-child(9),
  .ct-tbl th:nth-child(13),
  .ct-tbl td:nth-child(13) {
    display: none !important;
  }
}

/* ---------- ⑭ 阶段②漏网的按钮（_b65-btnhole.mjs 扫出来的） ----------
   阶段② 验收只扫了 14 个页面，支付授权页的 .pa-* 三个按钮漏了 ——
   它们还是 `padding:3px 10px; font-size:12px; border-radius:4px`，
   计算高度 30px，既不在 24/28/32/40 档位里，圆角也不合规。 */
.pa-pass,
.pa-reject,
.pa-detail {
  display: inline-flex;
  align-items: center;
  height: var(--btn-h-sm);
  padding: 0 10px;
  border-radius: var(--btn-r);
  font-size: var(--btn-fs-sm);
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
}
/* 语义色保留（同意=成功 / 拒绝=危险），只改尺寸与圆角 */

/* ---------- ⑮ 催收管理的竖排页签：与 .h-tab 统一 ----------
   .urge-vtab 本来就已经是「下划线式页签」（padding 10px 4px + ::after 2px），
   只是没跟 .h-tab 一起收口 → 计算高度 41px，和旁边 32px 的按钮不齐。 */
.urge-vtab {
  height: var(--btn-h) !important;
  padding: 0 !important;
  margin-right: 20px;
  font-size: var(--btn-fs) !important;
  display: inline-flex;
  align-items: center;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
}
.urge-vtab.active {
  color: var(--c-primary) !important;
  font-weight: 600 !important;
}

/* ==================================================================
 * 居小易 · 仪表盘 v3（批次75，2026-10-29）
 * ------------------------------------------------------------------
 * 范围：只作用于 #tabPanes（总览 / 仪表盘），不碰其余 44 个页面。
 * 起因：用户贴了 /admin/#!/be/dashboard/todo 的截图 ——「全部清色系、文字不清晰」。
 *
 * 这一版修 9 类问题，每一条都是「看着有、其实不对」：
 *   ① 文字对比度：--c-text-secondary #8B95A7 只有 3.02:1（已改 #667085 = 4.97:1）；
 *      另有 6 处把「填充档」琥珀 #F59E0B 当文字色（白底 2.15:1）、
 *      2 处把占位灰 #AEB6C4 当正文（2.04:1）。
 *   ② 数字颜色不承载语义：0 值、负数、正数长得一模一样 → .is-zero / .is-neg。
 *   ③ 渐变进度条 linear-gradient(#ffd1a4,#ff9500)：规范禁渐变，且橙色暗示「故障」。
 *   ④ 圆角 5 种混用（3/5/6/10/12/50%）→ 收敛到 4 / 6 / 8 / 12 / 999。
 *   ⑤ 数据卡片 hover 整体上浮 2px —— 只有「可点击入口」才该动。
 *   ⑥ 「今日」和「单」是两个 div，被强制换行 → 每格两行，格子被撑高。
 *   ⑦ 空态只有一行 2.04:1 的灰字 → 空态三件套（图标 + 主文案）。
 *   ⑧ 「新建 +」是整行蓝色实心按钮，视觉权重超过全页所有数据，但它是次要操作。
 *   ⑨ 客户满意度 5 行纯文字，看不出分布 → 加分布条。
 * ================================================================== */

/* ---------- 补充令牌：状态色的「文字档」 ----------
 * 规范：填充档 #FF4757 / #F59E0B / #12B886 只用于 background / border / 实心块；
 * 文字必须用文字档（#B42318 / #B54708 / #067647），否则对比度只有 2~3.8:1。 */
:root{
  --c-danger-text:#B42318;
  --c-warning-text:#B54708;
  --c-success-text:#067647;
  --c-num-zero:#667085;
  --c-fill-soft:#F7F8FA;
}

/* ---------- 页面标题与二级页签拉开层级 ----------
 * 原来「总览」14px/500 和页签「仪表盘」13px/500 几乎一样大，
 * 两个词意思又接近，读者分不清哪个是页面、哪个是视图。 */
.header-page-title{ font-size:15px; font-weight:600; letter-spacing:-.1px; }
#headerSubnav{ margin-left:10px; padding-left:12px; border-left:1px solid var(--c-border); }

/* ============ ① 卡片不再整体上浮 ============ */
#tabPanes .card:hover,
#tabPanes .panel:hover{ transform:none; box-shadow:var(--shadow-md); }

/* ============ ② 圆角收敛 ============ */
#tabPanes .seg-item{ border-radius:4px; }
#tabPanes .cat-card,
#tabPanes .stat-cell,
#tabPanes .inv-item,
#tabPanes .inv-days-grid > div,
#tabPanes .rank-item,
#tabPanes .bal-cell,
#tabPanes .sat-score,
#tabPanes .balance-row,
#tabPanes .m-arrow,
#tabPanes .sched-item{ border-radius:8px; }
#tabPanes .inv-progress-bar,
#tabPanes .inv-progress-fill,
#tabPanes .badge-paid,
#tabPanes .period-tag{ border-radius:999px; }

/* ============ ③ 数字：等宽 + 语义色 ============
 * 0 值 = 中性灰（没数据就是没数据，不该跟「有数据」长得一样）
 * 负数 = 文字档红（结余为负、租客净减，是必须被看见的）
 * ⚠ 用 !important：这些节点上挂着 .num-red / .muted / .highlight 等既有类，
 *   语义优先级高于它们。 */
#tabPanes .cell-num,
#tabPanes .inv-num,
#tabPanes .d-num,
#tabPanes .mini-list li b,
#tabPanes .sat-list li b,
#tabPanes .rank-num,
#tabPanes .bal-cell b,
#tabPanes .big-num,
#tabPanes .amount,
#tabPanes .ft-row b,
#tabPanes .renew-pct,
#tabPanes .vac-pct,
#tabPanes .ten-pct,
#tabPanes .cat-line b{ font-variant-numeric:tabular-nums; }

#tabPanes .is-zero{ color:var(--c-num-zero) !important; }
#tabPanes .is-neg{ color:var(--c-danger-text) !important; }

/* ============ ④ 文字对比度：填充档色不许当文字用 ============ */
#tabPanes .big-num{ color:var(--c-warning-text); }
#tabPanes .big-num.primary{ color:var(--c-primary); }
#tabPanes .renew-pct,
#tabPanes .vac-pct{ color:var(--c-warning-text); }
#tabPanes .ten-pct{ color:var(--c-text-secondary); }
#tabPanes .mini-list li b.num-red{ color:var(--c-danger-text); }
#tabPanes .ft-row.ft-accent b{ color:var(--c-danger-text); }
#tabPanes .todo-overdue{ color:var(--c-danger-text); }
#tabPanes .overdue-tag.fresh{ color:var(--c-warning-text); }
#tabPanes .inv-num.muted{ color:var(--c-num-zero); }
#tabPanes .schedule-empty{ color:var(--c-text-secondary); }

/* ============ ⑤ 待办提醒 ============ */
#tabPanes .cat-card{
  padding:10px 12px; margin-bottom:8px;
  border:1px solid var(--c-border);
  border-left:3px solid transparent;
  transition:background .16s,border-color .16s;
}
#tabPanes .cat-card:hover{ background:var(--c-fill-soft); }
#tabPanes .cat-card.cat-active{
  background:var(--c-primary-light);
  border-color:var(--c-border);
  border-left-color:var(--c-primary);
}
#tabPanes .cat-title{ font-size:13.5px; margin-bottom:6px; }
#tabPanes .cat-line{ font-size:12px; line-height:19px; }
#tabPanes .cat-line b{ color:var(--c-danger-text); }

#tabPanes .todo-item{
  grid-template-columns:104px minmax(180px,1fr) 136px;
  padding:9px 16px; gap:12px;
}
#tabPanes .house-name{ font-size:13.5px; }
#tabPanes .amount{ font-size:15px; letter-spacing:-.2px; }
#tabPanes .amount-type{ font-size:11.5px; margin-top:3px; }
#tabPanes .todo-row-actions{ margin-top:5px; }

/* 「标记已收」原来每行都是绿底白字实心按钮（白字压 #12B886 只有 2.6:1），
   一屏 15 行 = 15 个绿块 —— 行内操作不该是全页最重的颜色。
   改成 ghost：默认只有蓝字，hover 到这一行才出浅底。 */
#tabPanes .btn-mini{
  height:24px; padding:0 8px;
  /* ⚠ 必须 !important：第 2894 行的按钮组件层写着
     `.btn-mini{ background-color:#fff !important; border:1px solid var(--c-primary) !important }`，
     不带 !important 的局部样式一律被吃掉（改了没反应，很容易误判成选择器没命中）。 */
  background:transparent !important;
  border:1px solid transparent !important;
  color:var(--c-primary) !important;
  font-size:12px; font-weight:500;
  border-radius:6px; opacity:.8;
  transition:background .15s,opacity .15s,border-color .15s;
}
#tabPanes .todo-item:hover .btn-mini{
  opacity:1;
  background:var(--c-primary-light) !important;
  border-color:transparent !important;
  color:var(--c-primary) !important;
}
#tabPanes .badge-paid{
  display:inline-block; padding:1px 8px;
  color:var(--c-success-text); background:#ECFDF5;
  font-size:11.5px; font-weight:600;
}

/* ============ ⑥ 房源出收：「今日」和「单」被拆成两行 ============ */
#tabPanes .card-stat{ gap:16px; }
#tabPanes .stat-label{ font-size:12.5px; margin-bottom:6px; }
#tabPanes .stat-cell{ background:var(--c-fill-soft); padding:10px 8px; }
#tabPanes .stat-cell .cell-key{ display:inline; }
#tabPanes .stat-cell .cell-key + .cell-key{ margin-left:2px; }
#tabPanes .cell-num{ font-size:22px; line-height:26px; }
#tabPanes .cell-key{ font-size:11.5px; line-height:16px; }
#tabPanes .stat-cell.highlight{ background:var(--c-primary-light); }
#tabPanes .stat-cell.highlight .cell-num{ color:var(--c-primary); }

/* ============ ⑦ 库存管理：渐变橙 → 品牌蓝 ============ */
#tabPanes .inv-progress-fill{ background:var(--c-primary); }
#tabPanes .inv-progress-bar{ height:8px; background:#EEF1F6; }
#tabPanes .inv-item{ background:var(--c-fill-soft); padding:10px 6px; }
#tabPanes .inv-num{ font-size:24px; line-height:28px; }
#tabPanes .inv-key{ font-size:11.5px; }
#tabPanes .inv-days-grid > div{ background:var(--c-fill-soft); padding:8px 4px; }
#tabPanes .d-num{ font-size:16px; }
#tabPanes .d-key{ font-size:11px; }

/* ============ ⑧ 收支情况 ============ */
#tabPanes .balance-row{ background:var(--c-primary-light); padding:10px 0; }
#tabPanes .balance-main{ font-size:24px; letter-spacing:-.5px; }
#tabPanes .bal-cell{ background:var(--c-fill-soft); padding:10px 8px; }
#tabPanes .bal-cell b{ font-size:14px; }
#tabPanes .bal-line{ font-size:12.5px; color:var(--c-text-secondary); padding:6px 0; }
#tabPanes .renew-pct,
#tabPanes .vac-pct,
#tabPanes .ten-pct{ font-size:20px; letter-spacing:-.4px; }
#tabPanes .renew-info div:first-child,
#tabPanes .vac-info div:first-child,
#tabPanes .ten-info div:first-child{ font-size:12.5px; }
#tabPanes .renew-info .muted,
#tabPanes .vac-info .muted,
#tabPanes .ten-info .muted{ font-size:11.5px; line-height:16px; }

/* ============ ⑨ mini 卡片（审批 / 工单 / 抄表）============ */
#tabPanes .mini-list{ gap:0; }
#tabPanes .mini-list li{
  padding:9px 0; font-size:12.5px;
  border-bottom:1px solid var(--c-border-light);
}
#tabPanes .mini-list li b{ font-size:15px; }

/* ============ ⑩ 今日账务 ============ */
#tabPanes .ft-row{ font-size:12.5px; padding:3px 0; }
#tabPanes .ft-row b{ font-size:13px; }

/* ============ ⑪ 业绩排行 ============ */
#tabPanes .rank-no{ background:var(--c-primary); font-size:12px; }
#tabPanes .rank-item{ background:var(--c-fill-soft); padding:9px 12px; }
#tabPanes .rank-num{ font-size:14px; }

/* ============ ⑫ 日程：「新建 +」不该是全页最重的元素 ============ */
#tabPanes .card-schedule{ position:relative; }
#tabPanes .card-schedule .card-head-row{ padding-right:78px; }
#tabPanes .btn-add{
  position:absolute; top:14px; right:16px;
  width:auto; height:26px; padding:0 10px; margin:0;
  background:#fff; color:var(--c-primary);
  border:1px solid var(--c-border); border-radius:6px;
  font-size:12px; font-weight:500; box-shadow:none;
}
#tabPanes .btn-add:hover{
  background:var(--c-primary-light); border-color:var(--c-primary);
}
#tabPanes .sched-item{
  display:flex; align-items:center; gap:8px;
  font-size:12.5px; padding:8px 10px;
  background:var(--c-fill-soft); cursor:pointer;
  transition:background .15s;
}
#tabPanes .sched-item:hover{ background:#EEF1F6; }
#tabPanes .sched-date{ color:var(--c-text-secondary); font-variant-numeric:tabular-nums; }
#tabPanes .sched-title{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
#tabPanes .sched-del{ color:var(--c-danger-text); opacity:0; transition:opacity .15s; }
#tabPanes .sched-item:hover .sched-del{ opacity:1; }
#tabPanes .sched-item.is-done .sched-title{ text-decoration:line-through; color:var(--c-text-secondary); }

/* ============ ⑬ 空态三件套 ============ */
#tabPanes .schedule-empty{
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:8px; padding:26px 0; font-size:12.5px;
}
#tabPanes .schedule-empty::before{
  content:''; width:38px; height:38px;
  background:currentColor; opacity:.2;
  -webkit-mask:var(--i-doc) center/24px no-repeat;
  mask:var(--i-doc) center/24px no-repeat;
}
#tabPanes .todo-empty{ padding:44px 0; font-size:12.5px; color:var(--c-text-secondary); }
#tabPanes .todo-empty::before{
  content:''; display:block; width:40px; height:40px; margin:0 auto 10px;
  background:currentColor; opacity:.2;
  -webkit-mask:var(--i-doc) center/28px no-repeat;
  mask:var(--i-doc) center/28px no-repeat;
}

/* ============ ⑭ 客户满意度：加分布条 ============ */
#tabPanes .sat-list{ gap:2px; }
#tabPanes .sat-list li{
  display:grid; grid-template-columns:40px 1fr 34px;
  align-items:center; gap:10px;
  padding:5px 0; border-bottom:none;
}
#tabPanes .sat-list li > span{ font-size:12px; color:var(--c-text-secondary); }
#tabPanes .sat-list li > b{ font-size:13px; text-align:right; }
#tabPanes .sat-bar{ height:6px; border-radius:999px; background:#EEF1F6; overflow:hidden; }
#tabPanes .sat-bar i{
  display:block; height:100%; border-radius:999px;
  background:var(--c-primary); transition:width .4s ease;
}
#tabPanes .sat-score{ padding:12px; }
#tabPanes .sat-score .big-num{ font-size:26px; color:var(--c-primary); }

/* ==================================================================
 * 仪表盘 v3 · 补充（批次75，2026-10-29）
 * ------------------------------------------------------------------
 * ① 今日账务从「一行塞三组键值」改成 3 列 × 2 行格子 + 合计行
 * ② 语义色调 tone-warn / tone-bad（正常档不上色）
 * ③ 日程「新建 +」与右侧页签重叠 → 移到卡片底部，兼作空态引导
 * ④ 工单 2 列键值对太挤 → 加列间距
 * ================================================================== */

/* ---------- ① 今日账务 ---------- */
#tabPanes .ft-block{ display:flex; flex-direction:column; gap:10px; }
#tabPanes .ft-grid{
  display:grid; grid-template-columns:repeat(3, 1fr); gap:6px;
}
#tabPanes .ft-cell{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  padding:9px 4px; background:var(--c-fill-soft); border-radius:8px;
}
#tabPanes .ft-cell span{ font-size:11px; color:var(--c-text-secondary); white-space:nowrap; }
#tabPanes .ft-cell b{
  font-size:13px; font-weight:700; color:var(--c-text);
  font-variant-numeric:tabular-nums; letter-spacing:-.2px;
  white-space:nowrap;
}
#tabPanes .ft-total{
  display:flex; flex-direction:column; gap:0;
  border-top:1px solid var(--c-border-light);
}
#tabPanes .ft-total > div{
  display:flex; align-items:center; justify-content:space-between;
  padding:7px 2px;
  border-bottom:1px solid var(--c-border-light);
}
#tabPanes .ft-total > div:last-child{ border-bottom:none; }
#tabPanes .ft-total span{ font-size:12px; color:var(--c-text-secondary); }
#tabPanes .ft-total b{
  font-size:14px; font-weight:700; color:var(--c-text);
  font-variant-numeric:tabular-nums;
}
#tabPanes .ft-total b.num-red{ color:var(--c-danger-text); }

/* ---------- ② 语义色调：只有「要处理」才上色 ---------- */
#tabPanes .tone-warn{ color:var(--c-warning-text) !important; }
#tabPanes .tone-bad{ color:var(--c-danger-text) !important; }

/* ---------- ③ 日程「新建 +」移到卡片底部 ---------- */
/* 原来绝对定位在右上角，和「今天 / 本周 / 逾期」三个页签压在一起。
   挪到底部：空态时正好是空态三件套的「引导动作」，有日程时是列表后的操作。 */
#tabPanes .card-schedule{ display:flex; flex-direction:column; }
#tabPanes .card-schedule .card-head-row{ padding-right:0; }
#tabPanes .btn-add{
  position:static; order:99;
  width:100%; margin-top:auto;
  color:var(--c-primary) !important;
  border-style:dashed !important;
  border-color:var(--c-border) !important;
  background:#fff !important;
  box-shadow:none !important;
}
#tabPanes .btn-add:hover{
  background:var(--c-primary-light) !important;
  border-style:solid !important;
  border-color:var(--c-primary) !important;
}
#tabPanes .card-schedule .schedule-list{ margin-bottom:10px; }

/* ---------- ④ 工单 2 列键值 ---------- */
#tabPanes .mini-list-2col{ gap:0 22px; }
#tabPanes .mini-list-2col li{ font-size:12px; padding:7px 0; }
#tabPanes .mini-list-2col li span{
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
#tabPanes .mini-list-2col li b{ font-size:14px; }

/* ---------- ⑤ 房源出收：底部「本月净增」补齐等高留白 ---------- */
#tabPanes .stat-foot{
  display:flex; align-items:center; justify-content:space-between;
  margin-top:auto; padding-top:14px;
  border-top:1px solid var(--c-border-light);
  font-size:12.5px; color:var(--c-text-secondary);
}
#tabPanes .stat-foot b{
  font-size:18px; font-weight:700; color:var(--c-text);
  font-variant-numeric:tabular-nums; letter-spacing:-.3px;
}

/* ---------- ⑥ 业绩排行：比例底纹 + 底部合计 ---------- */
#tabPanes .card-rank{ display:flex; flex-direction:column; }
#tabPanes .rank-list{ flex:1 1 auto; }
#tabPanes .rank-item{
  position:relative; overflow:hidden;
  background:var(--c-fill-soft);
}
#tabPanes .rank-item::before{
  content:''; position:absolute; left:0; top:0; bottom:0;
  width:var(--pct,0%);
  background:rgba(47,107,255,.10);
  border-radius:8px;
}
#tabPanes .rank-item > *{ position:relative; z-index:1; }
#tabPanes .rank-foot{
  display:flex; align-items:center; justify-content:space-between;
  margin-top:auto; padding-top:12px;
  border-top:1px solid var(--c-border-light);
  font-size:12.5px; color:var(--c-text-secondary);
}
#tabPanes .rank-foot b{
  font-size:14px; font-weight:700; color:var(--c-text);
  font-variant-numeric:tabular-nums;
}

/* ---------- ⑦ 公告 / 新手上路：280px 装不下原文案 ---------- */
#tabPanes .row-banner{ grid-template-columns:1fr 320px; }
#tabPanes .novice-body{ white-space:nowrap; overflow:hidden; min-width:0; }
#tabPanes .novice-body strong{ white-space:nowrap; }
#tabPanes .novice-more{ flex:0 0 auto; }

/* ==================================================================
 * ⑧ 等高卡的「卡内死空白」（批次75）
 * ------------------------------------------------------------------
 * 现象：grid 把同一行的卡拉成等高后，内容少的卡底部留一大块白。
 *   实测：工单 149px / 库存 110px / 审批 97px / 房源出收 126px。
 *   白边在卡片**内部**看起来像渲染 bug；在页面背景上才是正常留白。
 *
 * 原则：撑满的必须是「数据块」，不是「缝隙」。
 *   把富余高度摊成几条大缝 → 看起来更散（试过，比原样更差）。
 *   让格子/行本身变高 → 读起来是「一块块数据面板」。
 * ================================================================== */

/* --- 审批 / 工单 / 抄表：清单行等分 --- */
#tabPanes .card-mini{ display:flex; flex-direction:column; }
#tabPanes .card-mini .card-title{ flex:0 0 auto; }
#tabPanes .card-mini .mini-list{ flex:1 1 auto; min-height:0; }
#tabPanes .card-mini .mini-list:not(.mini-list-2col) li{ flex:1 1 0; min-height:0; }
/* 等分之后最后一行贴着卡底，下边线看起来像「还有第 5 行」→ 表格惯例：末行不画线。
   ⚠ 基础样式的 .mini-list li:last-child{border-bottom:none} 被
   `#tabPanes .mini-list li` 的 id 优先级压掉了，必须在这里重写一次。 */
#tabPanes .card-mini .mini-list li:last-child{ border-bottom:none; }
/* 工单是两列 grid：第 5 项独占第 3 行，保留底线会只剩半条 → 整卡去线，靠行高分隔。 */
#tabPanes .card-mini .mini-list-2col{ grid-auto-rows:1fr; align-items:center; }
#tabPanes .card-mini .mini-list-2col li{ border-bottom:none; }

/* --- 库存管理：两组 4 格加高，缝隙自然收窄 --- */
#tabPanes .card-inventory{ display:flex; flex-direction:column; justify-content:space-between; }
#tabPanes .card-inventory .inv-item{
  min-height:96px; display:flex; flex-direction:column; justify-content:center;
}
#tabPanes .card-inventory .inv-num{ font-size:26px; line-height:32px; }
#tabPanes .card-inventory .inv-days-grid > div{
  min-height:74px; display:flex; flex-direction:column; justify-content:center;
}
#tabPanes .card-inventory .d-num{ font-size:19px; line-height:24px; }

/* --- 房源出收：两个数据组各占一半高度，组内「标签 + 格子」作为整体垂直居中 ---
   ⚠ 不要给 .stat-cell 加 flex-direction:column：那会把靠 display:inline 拼成一行的
     「今日」「单」拆成两个 flex item 竖着堆起来（踩过）。 */
#tabPanes .card-stat{ display:flex; flex-direction:column; }
#tabPanes .card-stat .stat-block{
  flex:1 1 auto; display:flex; flex-direction:column; justify-content:center;
}
#tabPanes .card-stat .stat-foot{ flex:0 0 auto; }

/* --- 业绩排行：只有 1~2 人上榜时整组垂直居中 ---
   行数少时贴顶 + 底部一大块白，像加载失败；居中后空白上下均分。 */
#tabPanes .card-rank .rank-list{
  display:flex; flex-direction:column; justify-content:center; gap:6px;
}

/* ==================================================================
 * ⑨ 收支卡：续租率的口径与语义（批次75）
 * ① 到期合同为 0 时「0.00%」是没有意义的假数 → 显示「—」+「本月无到期合同」；
 * ② 有分母时按健康度上色（<30% 红 / 30~60% 琥珀 / ≥60% 保持品牌蓝＝正常档不上色）；
 * ③ 大数字已经是「续租率」时，下面那行只留「到期/续租」明细，不再重复百分比。
 * ================================================================== */
#tabPanes .balance-main.tone-bad{ color:var(--c-danger-text); }
#tabPanes .balance-main.tone-warn{ color:var(--c-warning-text); }
#tabPanes .renew-line.is-compact{ display:block; padding:6px 0; }
#tabPanes .renew-line.is-compact .renew-info{ font-size:12px; }

/* 租客增减原本用 --c-text-placeholder（最浅一档，本来是给占位符的），
   有真实数值的指标不该长得像「未填写」。改正文深色，净减时才由 tpSetTone 变红。 */
#tabPanes .ten-pct{ color:var(--c-text-regular); }

/* 待办行高 62px（三行文本），分隔线却用 --c-border-light #f2f3f5（白底上几乎看不见），
   6 行连成一片很难扫读。行分隔用 --c-border #e5e6eb：能看见，但不会抢内容。 */
#tabPanes .todo-item{ border-bottom-color:var(--c-border); }

/* 待办卡左栏 4 个分类项、右栏 6 行明细 → 左栏下方空出 ~100px 白。
   让 4 个分类项等分左栏高度，左栏看起来就是「4 个分区标题」，和右侧行高呼应。 */
#tabPanes .todo-cats{ display:flex; flex-direction:column; }
#tabPanes .cat-card{ flex:1 1 0; display:flex; flex-direction:column; justify-content:center; }

/* ⚠ 撤回：上一步把 4 个分类项等分左栏高度，结果是 4 个 93px 的大空盒子
   （文字只占 3 行，剩下全是白），比原来的底部留白更难看。
   分类侧栏只有 4 项、下方留白是正常形态，不该硬撑。
   真正的问题是这个留白区看不出「左栏到此为止」——border-right 用的
   --c-border-light #f2f3f5 白底上几乎不可见，换成 --c-border 让分栏关系读得出来。 */
#tabPanes .todo-cats{ display:block; border-right-color:var(--c-border); }
#tabPanes .cat-card{ flex:0 0 auto; display:block; }

/* ==================================================================
 * 批次76：列表页（出房管理 / 租客合同 / 账单 及全站 20+ 张表）
 * ------------------------------------------------------------------
 * 这一批解决的不是「好不好看」，是「专不专业」。逐条对应实测证据：
 *
 *   ① 金额列全部左对齐 → 5,100.00 / 4,100.00 / 2,300.00 的小数点不在一条
 *      竖线上，扫一列要重新找小数点。会计表格的铁律是右对齐 + 等宽数字。
 *   ② 金额单位重复：「¥5,100.00元/月」—— ¥ 已经是元了，后面又写元。
 *   ③ 状态徽标语义坍缩：合同「已到期 / 已转租 / 提前退租 / 正常退租」
 *      四种完全不同的结局，全兜底成同一个品牌蓝（详见 script.js 的 ST_TONE）。
 *   ④ 行高 65px：租客姓名 + 电话两行，20 行表要滚 1300px，一屏只看得见 9 行。
 *   ⑤ 操作列 310px = 全表 21.6%，比「应收金额」列宽 3 倍多。
 *   ⑥ 行内操作高度不一：查看/编辑 24px、撤销 19px，基线错位。
 * ================================================================== */

/* ---------- ① 对齐：金额/数字右对齐，居中列单独标 ---------- */
.dyn-table th.ta-r, .dyn-table td.ta-r { text-align: right; }
.dyn-table th.ta-c, .dyn-table td.ta-c { text-align: center; }

/* 表头也跟着内容对齐：右对齐的列，表头也贴右，
   否则「应收金额」四个字在左、下面的数字在右，视觉上像两个列。 */
.dyn-table th.ta-r { padding-right: 10px; }
.dyn-table td.ta-r { padding-right: 10px; }

/* ---------- ② 金额 / 数字 ----------
 * tabular-nums 让每个数字占同样宽度（0 和 1 一样宽），小数点才能对齐。
 * 这一条是「专业表格」和「网页表格」最大的分野，肉眼一眼能看出来。 */
.dyn-table .money {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: -.1px;
  white-space: nowrap;
}
/* 单位（/月、天、间）跟在数字后面，字号降一档、颜色降一档，
   让它读起来是「单位」而不是「金额的一部分」。 */
.dyn-table .money-u {
  font-style: normal;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--c-text-secondary);
  margin-left: 1px;
  letter-spacing: 0;
}
/* 0 元不是异常，是「还没收到」。以前「实收金额」未支付时整片红，
   全列染色 = 全列没有染色。 */
.dyn-table .money.is-zero { color: var(--c-num-zero); }
.dyn-table .money.is-neg  { color: var(--c-danger-text); }
.dyn-table .money.tone-warn   { color: var(--c-warning-text); }
.dyn-table .money.tone-danger { color: var(--c-danger-text); }

/* ---------- ③ 单元格内的主 / 次 / 码 / 日期 / 区间 ---------- */
/* 主信息（房号、姓名）：深色、500，和次要信息拉开 */
.dyn-table tbody td .cell-main {
  display: block;
  font-weight: 500;
  color: var(--c-text);
  line-height: 20px;
}
/* 次要信息（楼栋、电话、账期月）：block 独占一行。
   原来 18 处写的是「<br><span class=cell-sub>」，靠 <br> 换行，
   行高由 <br> 撑出来、上下留白不可控；现在由 line-height 控制。 */
.dyn-table tbody td .cell-sub {
  display: block;
  line-height: 17px !important;
}
/* 编号 / 期次：等宽字体。12 位合同号用比例字体时，每行数字宽度都不一样，
   一列看下去像波浪。 */
.dyn-table tbody td .cell-code,
.dyn-table tbody td.cell-code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 12px;
  color: var(--c-text-secondary);
  letter-spacing: -.2px;
}
/* 日期：等宽 + 不换行。'2026-10-30' 在比例字体里 1 和 0 宽度不同，
   一列日期会左右跳动。 */
.dyn-table tbody td.cell-date {
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  color: var(--c-text-regular);
  white-space: nowrap;
}
/* 合同周期：起 → 止 两段 + 中间箭头。
   原来写 '2026-10-25 ~ 2027-10-25'，~ 在窄格里和数字粘成一坨，
   读者要数一遍才知道哪边是开始。 */
.dyn-table tbody td.cell-range {
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  color: var(--c-text-regular);
  white-space: nowrap;
}
.dyn-table tbody td.cell-range i {
  font-style: normal;
  color: var(--c-text-placeholder);
  margin: 0 4px;
}
/* 空值：一个短横，浅到不抢注意力，但位置保留（空着会让人以为渲染失败） */
.dyn-table tbody td .cell-none { color: var(--c-text-placeholder); }
/* 行内警示标记（逾期 N 天）：小号红字，不占一整行 */
.dyn-table tbody td .cell-flag {
  display: inline-block;
  margin-top: 1px;
  padding: 0 4px;
  border-radius: 3px;
  background: #FEF3F2;
  color: var(--c-danger-text);
  font-size: 11px;
  font-weight: 500;
  line-height: 16px;
}

/* ---------- ④ 行密度：65px → 56px ----------
 * 两行单元格 = 主信息 20 + 次要 17 + 上下内距 16 = 53，加边框 1px = 54。
 * 原来 65px 是因为 <br> 撑出额外行盒 + 徽标基线对齐把行盒顶高。
 * 现在统一 8px 内距，行高稳定在 54~56，一屏能多看见 2 行。 */
.dyn-table tbody td { padding-top: 8px !important; padding-bottom: 8px !important; }
/* 单行单元格不要跟着变矮 —— 否则同一张表里行高忽高忽低。
   min-height 撑住 40px 的舒适点击区。 */
.dyn-table tbody tr { height: 54px; }
.dyn-table tbody td { vertical-align: middle; }

/* 表头：12px / 600 / 深一档，底边 1px 实线。
   原来表头用 --c-text-regular #555 + 9px 内距，和正文 13px 只差 1px，
   读起来像「第一行数据」。 */
.dyn-table thead th {
  font-size: 12px !important;
  font-weight: 600 !important;
  color: var(--c-text-secondary) !important;
  background: #FAFBFC !important;
  border-bottom: 1px solid var(--c-border) !important;
  padding-top: 9px !important;
  padding-bottom: 9px !important;
  white-space: nowrap;
}

/* 行悬停：整行浅蓝，且不给左侧加色条（那是「选中」语义）。
   原来 hover 用 --c-bg，和白底几乎同色，鼠标划过看不出来。 */
.dyn-table tbody tr:hover td { background: #F7F9FE !important; }

/* ---------- ⑤ 行内操作：三级权重 ---------- */
/* 文字链（查看 / 编辑 / 撤销）：默认次要灰，悬停才变品牌蓝。
   原来三个都是蓝的（撤销还是填充红），一行里三个同权重链接，
   眼睛不知道该点哪个。 */
.dyn-table .op-link {
  display: inline-block;
  padding: 0 2px;
  font-size: 12.5px;
  line-height: 20px;
  color: var(--c-text-regular);
  text-decoration: none;
  cursor: pointer;
  transition: color .14s;
}
.dyn-table .op-link:hover { color: var(--c-primary); }
.dyn-table .op-link + .op-link { margin-left: 10px; }
/* 危险操作：用文字档红 #B42318，不用填充档 #f53f3f（后者压白底只有 3.9:1） */
.dyn-table .op-link.is-danger { color: var(--c-text-regular); }
.dyn-table .op-link.is-danger:hover { color: var(--c-danger-text); }

/* 按钮型操作（账单的 收款 / 作废 / 详情）：默认 ghost，
   只有主操作（收款）实心。原来 5 个按钮同权重平铺，扫不出主次。 */
.dyn-table .op-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 26px;
  padding: 0 9px;
  border: 1px solid var(--c-border);
  border-radius: 5px;
  background: #fff;
  color: var(--c-text-regular);
  font-size: 12px;
  font-family: inherit;
  line-height: 1;
  cursor: pointer;
  transition: background .14s, border-color .14s, color .14s;
  white-space: nowrap;
}
.dyn-table .op-btn:hover { border-color: var(--c-primary); color: var(--c-primary); background: var(--c-primary-light); }
.dyn-table .op-btn + .op-btn { margin-left: 4px; }
.dyn-table .op-btn.is-primary {
  border-color: var(--c-primary);
  background: var(--c-primary);
  color: #fff;
  font-weight: 500;
}
.dyn-table .op-btn.is-primary:hover { background: #2359d8; border-color: #2359d8; color: #fff; }
/* 危险操作默认和普通按钮一样灰，悬停才变红 —— 常驻红按钮会让人以为
   这一整行都出事了。 */
.dyn-table .op-btn.is-danger { color: var(--c-text-regular); }
.dyn-table .op-btn.is-danger:hover { border-color: #FDA29B; background: #FEF3F2; color: var(--c-danger-text); }

/* 操作列统一右对齐 + 不折行，并限宽。
   ⚠ 别写 `width:1%` —— auto 布局下无效（上一批踩过）。 */
.dyn-table th:last-child.ta-r, .dyn-table td:last-child.ta-r { white-space: nowrap; }

/* ---------- ⑥ 列宽重分配：合同 14 列 ----------
 * 原来 14 列平分 1430px ≈ 102px/列，结果「合同周期」185px 挤成两行、
 * 「租期」58px 装不下「7 个月」、「操作」160px 塞三个链接。
 * 原则：能短的固定短（状态、类型、租期），能长的给足（房源、周期、操作）。
 */
.ct-tbl { table-layout: fixed; }
.ct-tbl th:nth-child(1) { width: 36px; }   /* 勾选 */
.ct-tbl th:nth-child(2) { width: 78px; }   /* 状态 */
.ct-tbl th:nth-child(3) { width: 66px; }   /* 签约类型 */
.ct-tbl th:nth-child(4) { width: 118px; }  /* 房源 */
.ct-tbl th:nth-child(5) { width: 108px; }  /* 租客 / 电话 */
.ct-tbl th:nth-child(6) { width: 126px; }  /* 合同编号 */
.ct-tbl th:nth-child(7) { width: 72px; }   /* 签约方式 */
.ct-tbl th:nth-child(8) { width: 176px; }  /* 合同周期 */
.ct-tbl th:nth-child(9) { width: 62px; }   /* 租期 */
.ct-tbl th:nth-child(10) { width: 108px; } /* 租金 */
.ct-tbl th:nth-child(11) { width: 96px; }  /* 押金 */
.ct-tbl th:nth-child(12) { width: 74px; }  /* 付款方式 */
.ct-tbl th:nth-child(13) { width: 92px; }  /* 录入日期 */
.ct-tbl th:nth-child(14) { width: 158px; } /* 操作（三个文字链，实测需 145px） */
/* fixed 布局下内容会溢出，单元格统一裁切 + 省略号 */
.ct-tbl td { overflow: hidden; text-overflow: ellipsis; }

/* ---------- ⑦ 列宽重分配：账单 12 列 ----------
 * 原来「操作」310px（21.6%）> 「应收金额」98px × 3。
 * 一个列表页里操作比数据还宽，是本末倒置。 */
.bm-tbl { table-layout: fixed; }
.bm-tbl th:nth-child(1) { width: 38px; }   /* 勾选 */
.bm-tbl th:nth-child(2) { width: 104px; }  /* 账单号 */
.bm-tbl th:nth-child(3) { width: 176px; }  /* 房源 */
.bm-tbl th:nth-child(4) { width: 112px; }  /* 租客 */
.bm-tbl th:nth-child(5) { width: 96px; }   /* 类型 / 账期 */
.bm-tbl th:nth-child(6) { width: 76px; }   /* 期次 */
.bm-tbl th:nth-child(7) { width: 110px; }  /* 应收 */
.bm-tbl th:nth-child(8) { width: 110px; }  /* 实收 */
.bm-tbl th:nth-child(9) { width: 96px; }   /* 滞纳金 */
.bm-tbl th:nth-child(10) { width: 100px; } /* 应付日期 */
.bm-tbl th:nth-child(11) { width: 84px; }  /* 状态 */
.bm-tbl th:nth-child(12) { width: 236px; } /* 操作 */
.bm-tbl td { overflow: hidden; text-overflow: ellipsis; }
/* 账单表最后一列有 5 个按钮（已支付行），需要允许溢出到省略号之外——
   按钮不能裁切，所以操作列单独放开 */
.bm-tbl td:last-child { overflow: visible; }

/* ⚠ `.set-ops a { margin-right:12px }`（1833 行）是旧写法，三个链接的右外边距
   加起来 36px，加上内距把 135px 的操作列撑爆 —— 截图里「撤销」变成省略号，
   用户点不到撤销。现在间距交给 `.op-link + .op-link`（10px），这里清零。 */
.dyn-table .set-ops a { margin-right: 0; }

/* ==================================================================
 * 批次76：出房管理房源卡片
 * ------------------------------------------------------------------
 * 改造前的形态：一张卡一个 pastel 底色
 *   已出租 #d1f2f2（浅青） / 空房可租 #fff4ec（浅橙）
 *   空房不可租 #feefef（浅粉） / 锁房 #f2f3f5（浅灰）
 * 一屏 30 张卡 = 30 块彩色色块，颜色之间没有规律，看起来像便利贴墙。
 * 这是「AI 味」最典型的指纹：**用底色表达状态**。
 *
 * 改成：统一白底 + 左侧 3px 状态色条。
 *   底色回到「容器」的本职（区分区块），状态交给一条细色带 + 文字。
 *   好处：① 30 张卡读起来是一张网格，不是 30 个色块；
 *         ② 房号和价格回到纯白背景上，对比度最高；
 *         ③ 想加第 5 种状态，只需要再加一条色带，不用再挑一个 pastel。
 * ================================================================== */
/* ==================================================================
 * 批次106：出房管理房源卡片 · 第二版
 * ------------------------------------------------------------------
 * 演进过程（留着，避免下次又改回去）：
 *   v0  一张卡一个 pastel 底色（青/橙/粉/灰）→ 30 块彩色便利贴，最重的 AI 味
 *   v1  白底 + 左侧 3px 彩色竖条 → 底色干净了，但 30 条竖条依然吵，
 *       而且竖条把 188px 的卡又吃掉 3px
 *   v2（本版）白底 + 1px 中性描边 + 状态收敛为「7px 圆点 + 文字」
 *
 * v2 另外解决的三处「不像产品」的细节：
 *   ① 租客名原来挂在价格行右边（和「4,500/月」同基线），读起来像价格的注释
 *      → 挪到头部右侧，和房号组成「哪一间 · 谁住」一行
 *   ② 底部原来有一条 1px 通栏分割线硬切出一个「状态条」，22px 高的条里
 *      只有左边两个字，右边一大片空 → 去掉分割线，靠留白分段
 *   ③ 11px 的房型描述在 188px 宽里挤成一条黑线 → 卡放宽到 212px，正文回到 12px
 * ================================================================== */
#houseListArea .h-cards { gap: 12px; }
#houseListArea .h-card {
  height: 118px;
  padding: 12px 14px 11px;
  border-radius: 8px;
  border: 1px solid #E9EDF5;
  background: #fff;
  box-shadow: 0 1px 2px rgba(16,24,40,.03);
  display: flex; flex-direction: column;
  transition: border-color .15s, box-shadow .15s;
}
#houseListArea .h-card:hover {
  border-color: #C7D2E4;
  box-shadow: 0 2px 4px rgba(16,24,40,.05), 0 8px 20px rgba(16,24,40,.07);
}
/* 房态色条下线：底色和竖条都不再用颜色表达状态。
   状态改由底部圆点（.h-card-state::before）承担，一个点足够，不吵。 */

/* 头部：房号 + 租客名，一行读完「哪一间 · 谁住」 */
#houseListArea .h-card-head {
  flex: 0 0 20px; height: 20px; padding: 0; gap: 0;
  display: flex; align-items: center;
}
/* 房型图标下线：它表达的是房态（房子/工单/锁），和底部状态文字完全重复。
   两个地方说同一件事，是「信息没主次」的典型来源。script.js 已不再渲染该元素，
   这里保留规则作为防御（万一别处又渲染出来）。 */
#houseListArea .h-card-status-ico { display: none; }
#houseListArea .h-card-name {
  margin: 0; font-size: 13px; font-weight: 600; color: var(--c-text);
  font-variant-numeric: tabular-nums; letter-spacing: 0;
  max-width: 128px;
}
#houseListArea .h-card-tenant {
  margin-left: auto; font-size: 12px; color: var(--c-text-secondary);
  max-width: 70px; padding-left: 6px;
}
/* 通用人像图 30 张卡长得一模一样，零信息量；租客名已经说明是谁了。
   script.js 已不再渲染该元素，规则同样只作防御。 */
#houseListArea .h-card-avatar { display: none; }

#houseListArea .h-card-body { padding: 0; flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
/* 价格是这张卡上唯一的「金额」，给它最大的字号权重 */
#houseListArea .h-card-price {
  display: flex; align-items: baseline; gap: 2px;
  height: 28px; line-height: 28px; margin-top: 3px;
  font-size: 12px; color: var(--c-text);
}
#houseListArea .h-card-price b {
  font-size: 21px; font-weight: 700; color: var(--c-text);
  font-variant-numeric: tabular-nums; letter-spacing: -.2px;
}
#houseListArea .h-card-price i {
  font-style: normal; font-size: 11.5px; font-weight: 400; color: var(--c-text-secondary);
  margin-left: 1px;
}
/* 租客名已移到头部；em 保留兼容旧数据，不再占位 */
#houseListArea .h-card-price em { display: none; }
#houseListArea .h-card-meta {
  font-size: 12px; line-height: 17px; color: var(--c-text-secondary);
  letter-spacing: 0;
}
/* 底部状态行：去掉了原来的 1px 通栏分割线。
   有分割线时这张卡读起来是「内容区 + 被切掉的一条」，
   没有分割线、只用 8px 留白分段，才是正常的卡片。 */
#houseListArea .h-card-foot {
  margin-top: auto;
  flex: 0 0 18px; height: 18px;
  font-size: 12px; gap: 6px;
  justify-content: flex-start;
  border-top: 0;
}
/* 状态：6px 圆点 + 文字。圆点用 currentColor，颜色语义只写一次 */
#houseListArea .h-card-state {
  display: inline-flex; align-items: center;
  font-weight: 500; white-space: nowrap;
}
#houseListArea .h-card-state::before {
  content: ''; flex: 0 0 auto;
  width: 6px; height: 6px; border-radius: 50%;
  margin-right: 6px; background: currentColor;
}
#houseListArea .h-card-state.ok      { color: var(--c-success-text); }
#houseListArea .h-card-state.warn    { color: var(--c-warning-text); }
#houseListArea .h-card-state.danger  { color: var(--c-danger-text); }
#houseListArea .h-card-state.neutral { color: #98A2B3; }
#houseListArea .h-card-sub { color: var(--c-text-placeholder); white-space: nowrap; }
#houseListArea .h-card-tags { margin-left: auto; display: flex; gap: 3px; }

/* 角标：浅底 + 文字档色，1 个汉字装得下（原来实心亮色 + 白字只有 2.4:1） */
#houseListArea .h-card-tag {
  width: 15px; height: 15px; line-height: 15px;
  border-radius: 3px; font-size: 10px; font-weight: 600;
  text-align: center; flex: 0 0 auto;
  background: #F2F4F7; color: var(--c-text-secondary);
}
#houseListArea .h-card-tag.info   { background: #EEF3FF; color: var(--c-primary); }
#houseListArea .h-card-tag.ok     { background: #ECFDF5; color: var(--c-success-text); }
#houseListArea .h-card-tag.warn   { background: #FFFAEB; color: var(--c-warning-text); }
#houseListArea .h-card-tag.danger { background: #FEF3F2; color: var(--c-danger-text); }
#houseListArea .h-card-tag.more   { background: transparent; color: var(--c-text-placeholder); font-weight: 400; width: auto; }

/* 底部计数胶囊：原来是纯黑底白字（#000），在浅色后台里像一条错误提示。
   改成白底 + 边框 + 轻阴影，读起来是「浮在上面的提示条」。 */
#houseListArea .h-count-chip {
  background: rgba(255,255,255,.96);
  border: 1px solid var(--c-border);
  color: var(--c-text-regular);
  box-shadow: 0 2px 10px rgba(16,24,40,.10);
  backdrop-filter: blur(6px);
  font-size: 12px;
  padding: 4px 12px;
  border-radius: 999px;
}

/* 自动对齐扫出来的数字列（script.js 的 autoAlignNumericTables）：
   除了右对齐，还要等宽数字 —— 只右对齐不对齐小数点等于没做。 */
.dyn-table td.cell-num,
.dyn-table td.cell-num .cell-sub { font-variant-numeric: tabular-nums; }
.dyn-table td.cell-num { letter-spacing: -.1px; }

/* ---------- 批次76：右侧筛选面板 ---------- */
/* 计数为 0 的项收起来（hlMarkEmpty 打 .is-empty）。原来 19 行里 12 行是空的。 */
.h-filter .f-radio.is-empty,
.h-filter .f-check.is-empty { display: none; }

/* 业务状态的 1 字角标：原来是 4 种亮色实心 + 白字（10px 白字压在 #67c23a 上 2.4:1）。
   改成浅底 + 文字档色，和房源卡片上的角标同一套。 */
.h-filter .f-tag {
  width: 15px; height: 15px; line-height: 15px;
  border-radius: 3px; font-size: 10px; font-weight: 600;
  text-align: center; flex: 0 0 auto;
  background: #F2F4F7; color: var(--c-text-secondary);
}
.h-filter .f-tag.info   { background: #EEF3FF; color: var(--c-primary); }
.h-filter .f-tag.ok     { background: #ECFDF5; color: var(--c-success-text); }
.h-filter .f-tag.warn   { background: #FFFAEB; color: var(--c-warning-text); }
.h-filter .f-tag.danger { background: #FEF3F2; color: var(--c-danger-text); }

/* 筛选项行高 20px → 24px：19 个选项挤在 20px 行高里，勾选框和文字几乎贴在一起。
   收掉 0 项之后行数少了，可以把行距放松一点，读起来不紧绷。 */
.h-filter .f-radio,
.h-filter .f-check { line-height: 24px; margin-bottom: 2px; gap: 7px; }
.h-filter .f-cnt { font-variant-numeric: tabular-nums; }

/* 楼栋组标题：加房间数 + 拉开与卡片的层级。
   原来「八楼角」13px 常规字重，和卡片里的房号 12px/600 几乎同权重，
   6 个组连着排下来分不清「哪行是标题、哪行是数据」。 */
#houseListArea .h-card-group { margin-bottom: 20px; }
#houseListArea .h-card-group-head { margin-bottom: 12px; height: 22px; }
/* 批次106：卡片里的房号也是 13px/600，标题如果同样大小就分不出层级。
   标题提到 14px，间数降到 11.5px 淡灰 —— 三级层次：楼栋名 > 房号 > 间数。 */
#houseListArea .h-card-group-title {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 14px; font-weight: 600; color: #1D2939;
  letter-spacing: .1px;
}
#houseListArea .h-card-group-title em {
  font-style: normal; font-size: 11.5px; font-weight: 400;
  color: var(--c-text-secondary); font-variant-numeric: tabular-nums;
}
/* 「更多 / 眼睛」每组一份，6 组 = 12 个按钮常驻，占了标题行一半的视觉重量。
   默认淡出，鼠标进入该组才显形；键盘聚焦时也显形（不留无障碍死角）。 */
#houseListArea .h-card-group-actions { opacity: 0; transition: opacity .15s; }
#houseListArea .h-card-group:hover .h-card-group-actions,
#houseListArea .h-card-group:focus-within .h-card-group-actions { opacity: 1; }
#houseListArea .h-more-btn {
  height: 22px; padding: 0 7px; border-radius: 5px;
  border: 1px solid var(--c-border); color: var(--c-text-secondary);
  font-size: 11.5px;
}

/* ---------- 业主合同（co-tbl，13 列）：与租客合同同一套列宽逻辑 ----------
   少一列「签约类型」，把省下的宽度给房源和操作。 */
.co-tbl { table-layout: fixed; }
.co-tbl th:nth-child(1) { width: 36px; }
.co-tbl th:nth-child(2) { width: 78px; }   /* 状态 */
.co-tbl th:nth-child(3) { width: 118px; }  /* 房源 */
.co-tbl th:nth-child(4) { width: 108px; }  /* 业主 / 电话 */
.co-tbl th:nth-child(5) { width: 132px; }  /* 合同编号 */
.co-tbl th:nth-child(6) { width: 78px; }   /* 签约方式 */
.co-tbl th:nth-child(7) { width: 196px; }  /* 合同周期 */
.co-tbl th:nth-child(8) { width: 66px; }   /* 租期 */
.co-tbl th:nth-child(9) { width: 116px; }  /* 租金 */
.co-tbl th:nth-child(10) { width: 100px; } /* 押金 */
.co-tbl th:nth-child(11) { width: 80px; }  /* 付款方式 */
.co-tbl th:nth-child(12) { width: 96px; }  /* 录入日期 */
.co-tbl th:nth-child(13) { width: 116px; } /* 操作（两个文字链） */
.co-tbl td { overflow: hidden; text-overflow: ellipsis; }

/* ---------- 房源卡片：两处溢出（批次76 生产验收发现）----------
 * ① `.h-card-meta` 漏了 nowrap —— 「合租 · 主卧 · 75m² · 东南」在 171px 内容宽里
 *    折成两行，最后那个「南」掉到状态条那一行，看起来像多了一个角标。
 * ② 状态条里「在租」+「退租 09-23」+ 3 个角标加起来超宽，
 *    中间的退租日被 flex 压缩成「09-23」，读者看到的是一串没有主语的日期。
 *    文案已改成「至 09-23」；这里再给 sub 一个省略号兜底，角标永远不压缩。 */
#houseListArea .h-card-meta {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#houseListArea .h-card-foot > .h-card-state { flex: 0 0 auto; }
#houseListArea .h-card-foot > .h-card-sub {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#houseListArea .h-card-foot > .h-card-tags { flex: 0 0 auto; }

/* ==================================================================
 * 批次107：会员 · 人才轮候（独立申请闭环）
 * ------------------------------------------------------------------
 * 改造前这一页只有 8 列、其中 3 列是拿房源反查的假数据，没有搜索 / 分页 / 详情。
 * 现在列表 10 列 + 服务端分页，详情是完整档案 + 处理记录时间线，
 * 分配弹层带「按期望条件打分」的房源推荐。
 * 视觉延续批次106 的口径：不用底色表达状态，靠留白和 1px 中性描边分层。
 * ================================================================== */

/* ---------- 列表 ---------- */
.mt-table { background: #fff; border: 1px solid #E9EDF5; border-radius: 8px; overflow-x: auto; }
.mt-tbl { table-layout: fixed; min-width: 1092px; }
.mt-tbl th:nth-child(1)  { width: 96px; }   /* 轮候号 */
.mt-tbl th:nth-child(2)  { width: 100px; }  /* 申请人 */
.mt-tbl th:nth-child(3)  { width: 116px; }  /* 手机号 */
.mt-tbl th:nth-child(4)  { width: 84px; }   /* 期望区域 */
.mt-tbl th:nth-child(5)  { width: 108px; }  /* 期望户型 */
.mt-tbl th:nth-child(6)  { width: 116px; }  /* 期望租金 */
.mt-tbl th:nth-child(7)  { width: 92px; }   /* 月收入 */
.mt-tbl th:nth-child(8)  { width: 122px; }  /* 提交时间 */
.mt-tbl th:nth-child(9)  { width: 82px; }   /* 状态 */
.mt-tbl th:nth-child(10) { width: 176px; }  /* 操作 */
.mt-tbl td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-tbl td:last-child { overflow: visible; }

.mt-mono { font-variant-numeric: tabular-nums; }
.mt-dim { color: var(--c-text-secondary); }
.mt-na { color: var(--c-text-placeholder); font-style: normal; }
/* 「代录」标记：管理端补录的记录要和租客自己提交的区分开 */
.mt-src {
  margin-left: 6px; padding: 0 5px; border-radius: 3px;
  font-style: normal; font-size: 10px; line-height: 16px;
  color: var(--c-text-secondary); background: #F2F4F7;
}
.mt-acts { display: flex; gap: 10px; flex-wrap: nowrap; }
.mt-acts a { font-size: 13px; white-space: nowrap; }
/* ⚠ .link-blue 带 color:…!important，改色必须叠一个更高优先级的类 */
.link-blue.link-danger { color: var(--c-danger-text) !important; }

.mt-empty, .mt-loading {
  padding: 46px 0; text-align: center;
  font-size: 13px; color: var(--c-text-secondary);
}

.mt-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 12px 2px 0; flex-wrap: wrap;
}
.mt-total { font-size: 12.5px; color: var(--c-text-secondary); font-variant-numeric: tabular-nums; }
/* 这一页工具栏比默认的 .h-search（max-width 460px）宽：输入框 + 3 个下拉 + 2 个按钮。
   放开上限，输入框固定 200px，其余按内容宽 —— 否则输入框会被 flex:1 拉成一条 640px 的长条。 */
#memberTalentFilters { max-width: none; flex: 1 1 auto; align-items: center; }
#memberTalentFilters #mtKw { flex: 0 0 200px; }
#memberTalentFilters .h-select { flex: 0 0 auto; }
#mtCreate { height: 32px; padding: 0 14px; font-size: 13px; border-radius: 8px; }
.pg-dot { padding: 0 4px; color: var(--c-text-placeholder); font-size: 12px; }

/* 页签里的计数：淡一号、等宽，避免和页签名抢注意力 */
.mt-tab-n {
  margin-left: 5px; font-style: normal; font-size: 11.5px;
  color: var(--c-text-placeholder); font-variant-numeric: tabular-nums;
}
.h-tab.active .mt-tab-n { color: rgba(255, 255, 255, .78); }

/* ---------- 详情弹层 ---------- */
.mt-detail-hd {
  display: flex; align-items: center; gap: 10px;
  padding-bottom: 14px; margin-bottom: 4px;
  border-bottom: 1px solid #F0F2F6;
}
.mt-queue {
  font-size: 15px; font-weight: 600; color: var(--c-text);
  font-variant-numeric: tabular-nums; letter-spacing: .2px;
}
.mt-detail-meta { margin-left: auto; font-size: 12px; color: var(--c-text-placeholder); }

.mt-sec { margin-top: 18px; }
.mt-sec-h {
  font-size: 13px; font-weight: 600; color: var(--c-text);
  margin-bottom: 10px;
}
.mt-kvs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px; }
.mt-kv { display: flex; align-items: baseline; gap: 10px; font-size: 13px; min-width: 0; }
.mt-k { flex: 0 0 78px; color: var(--c-text-secondary); }
.mt-v { flex: 1 1 auto; color: var(--c-text); min-width: 0; word-break: break-all; }

/* 处理记录时间线：一条竖线 + 圆点，不用色块 */
.mt-timeline { position: relative; padding-left: 16px; }
.mt-timeline::before {
  content: ''; position: absolute; left: 3px; top: 6px; bottom: 6px;
  width: 1px; background: #EAEDF3;
}
.mt-tl-item { position: relative; padding: 0 0 14px 0; }
.mt-tl-item:last-child { padding-bottom: 0; }
.mt-tl-dot {
  position: absolute; left: -16px; top: 5px;
  width: 7px; height: 7px; border-radius: 50%;
  background: #C6CEDA; box-shadow: 0 0 0 2px #fff;
}
.mt-tl-top { display: flex; align-items: baseline; gap: 10px; }
.mt-tl-top b { font-size: 13px; font-weight: 600; color: var(--c-text); }
.mt-tl-time { font-size: 12px; color: var(--c-text-placeholder); font-variant-numeric: tabular-nums; }
.mt-tl-note { margin-top: 3px; font-size: 12.5px; color: var(--c-text-regular); line-height: 1.65; }
.mt-tl-op { margin-top: 2px; font-size: 11.5px; color: var(--c-text-placeholder); }

/* ---------- 弹层内表单件 ---------- */
.mt-tip {
  padding: 9px 12px; border-radius: 6px;
  background: #F7F9FC; border: 1px solid #EDF1F7;
  font-size: 12.5px; color: var(--c-text-regular); line-height: 1.7;
}
.mt-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 14px; }
.mt-chip {
  border: 1px solid var(--c-border); background: #fff; border-radius: 999px;
  padding: 4px 12px; font-size: 12.5px; color: var(--c-text-regular);
  cursor: pointer; transition: border-color .15s, color .15s;
}
.mt-chip:hover { border-color: var(--c-primary); color: var(--c-primary); }
.mt-field { margin-bottom: 12px; }
.mt-field > label { display: block; font-size: 12.5px; color: var(--c-text-secondary); margin-bottom: 6px; }
.mt-field textarea.h-input { width: 100%; height: auto; padding: 8px 10px; resize: vertical; line-height: 1.6; }
.mt-form2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; margin-top: 16px; }
.mt-check {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--c-text-regular);
  padding: 10px 0 12px;
}
.mt-check input { width: 15px; height: 15px; }

/* 房源推荐：一行一间，选中时描边换主色。
   ⚠ 不用整行填色表达「选中」—— 一屏 20 行里有颜色的只会有一行，
     但填色会让这行看起来像「警告」而不是「你选了这个」。 */
/* 高度按「整行数」给：一行约 56px + 8px 间距。300px 会切在第 5 行中间，
   看起来像布局坏了；248px 正好 4 行整。 */
.mt-houses {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 248px; overflow-y: auto;
  padding-right: 4px; scrollbar-width: thin;
}
.mt-house {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) 88px 52px;
  grid-template-rows: auto auto;
  align-items: center;
  gap: 2px 10px;
  padding: 9px 12px;
  border: 1px solid #E9EDF5; border-radius: 8px;
  background: #fff; cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
.mt-house:hover { border-color: #C7D2E4; }
.mt-house:has(input:checked) { border-color: var(--c-primary); box-shadow: 0 0 0 1px var(--c-primary); }
.mt-house.is-busy { opacity: .55; cursor: not-allowed; }
/* ⚠ 每一格都要显式写 grid-column + grid-row。
   只写 grid-row 不写 column 时，自动放置算法会把没定位的项（房源名）
   排到最后一个可用格子 —— 表现为「房源名被挤到最右、竖着换行」。 */
.mt-house input { grid-column: 1; grid-row: 1 / span 2; margin: 0; align-self: center; }
.mt-house-main { grid-column: 2; grid-row: 1; display: flex; flex-direction: column; min-width: 0; }
.mt-house-main b { font-size: 13px; font-weight: 600; color: var(--c-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-house-sub { font-size: 11.5px; color: var(--c-text-secondary); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mt-house-rent {
  grid-column: 3; grid-row: 1; text-align: right;
  font-size: 14px; font-weight: 600; color: var(--c-text);
  font-variant-numeric: tabular-nums;
}
.mt-house-score {
  grid-column: 4; grid-row: 1; text-align: right;
  font-size: 11.5px; color: var(--c-text-placeholder);
  font-variant-numeric: tabular-nums;
}
.mt-house-why {
  grid-column: 2 / span 3; grid-row: 2;
  font-size: 11px; color: var(--c-text-placeholder);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 900px) {
  .mt-kvs { grid-template-columns: 1fr; }
  .mt-form2 { grid-template-columns: 1fr; }
  .mt-house { grid-template-columns: 16px minmax(0, 1fr) 72px; }
  .mt-house-score { display: none; }
}

/* ==================================================================
 * 批次108：楼栋管理弹层
 * ------------------------------------------------------------------
 * 背景：楼栋在整站没有创建入口。新建房源时提示「去设置 → 房源相关设置建楼栋」，
 * 而那里只有 5 个开关。现在补一个能用的楼栋管理弹层（列表/搜索/新建/编辑/删除）。
 *
 * 视觉延续批次106/107 的口径：白底 + 1px 中性描边，不用底色表达状态；
 * 表头用字号和颜色区分层级，不画通栏粗线。
 * ================================================================== */

.bld-top {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 4px;
  border-bottom: 1px solid #E9EDF5;
}
.bld-sum { display: flex; align-items: baseline; gap: 16px; font-size: 12.5px; color: var(--c-text-secondary); }
.bld-sum b { font-size: 15px; font-weight: 600; color: var(--c-text); margin-right: 3px; font-variant-numeric: tabular-nums; }
.bld-warn { color: var(--c-warning-text, #B25E09); }
.bld-tools { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.bld-kw { width: 220px; height: 32px; }
.bld-new { height: 32px; padding: 0 14px; font-size: 13px; border-radius: 8px; }

.bld-scroll { overflow-x: auto; margin-top: 8px; }
.bld-tbl { width: 100%; table-layout: fixed; min-width: 820px; border-collapse: collapse; font-size: 13px; }
.bld-tbl th {
  text-align: left; font-weight: 500; font-size: 12.5px; color: var(--c-text-secondary);
  padding: 8px 10px; border-bottom: 1px solid #E9EDF5; white-space: nowrap;
}
.bld-tbl th:nth-child(1) { width: 240px; }
.bld-tbl th:nth-child(2) { width: 110px; }
.bld-tbl th:nth-child(3) { width: 70px; }
.bld-tbl th:nth-child(4) { width: 88px; }
.bld-tbl th:nth-child(5) { width: 70px; }
.bld-tbl th:nth-child(6) { width: 150px; }
.bld-tbl th:nth-child(7) { width: 92px; }
.bld-tbl td { padding: 10px; border-bottom: 1px solid #F2F4F7; vertical-align: middle; }
.bld-tbl tbody tr:last-child td { border-bottom: 0; }
.bld-tbl tbody tr:hover td { background: #FAFBFC; }
.bld-tbl td:last-child { overflow: visible; }

.bld-name { font-size: 13.5px; color: var(--c-text); }
.bld-sub {
  margin-top: 2px; font-size: 12px; color: var(--c-text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bld-mono { font-variant-numeric: tabular-nums; color: var(--c-text-secondary); }
.bld-dim { color: var(--c-text-placeholder); }
.bld-acts { display: flex; gap: 12px; white-space: nowrap; }
.bld-acts a { font-size: 13px; }

.bld-empty {
  padding: 44px 20px; text-align: center;
  font-size: 13px; color: var(--c-text-secondary); line-height: 2;
}
.bld-empty b { color: var(--c-text); font-weight: 500; }
.bld-loading { padding: 60px 0; text-align: center; font-size: 13px; color: var(--c-text-secondary); }

@media (max-width: 720px) {
  .bld-tools { margin-left: 0; width: 100%; }
  .bld-kw { flex: 1; width: auto; }
}

/* 批次108：楼栋管理弹层里还会再开「新建楼栋 / 删除确认」表单（#formModal）。
   两者 z-index 都是 200，谁在上取决于 DOM 顺序 —— 楼栋弹层是 appendChild 到 body 末尾的，
   不抬一层就会把表单盖住（表现：点了「+ 新建楼栋」什么都没出现）。 */
#formModal { z-index: 210; }

/* 批次108：设置 → 房源相关设置 里的楼栋卡片。
   .set-card-head 通用样式是「#f2f3f5 灰底 56px 通栏」—— 那套是给独立列表卡用的，
   塞在设置表单下面会读成「表单里的一条灰条」。这里改成白底 + 1px 下分隔线，
   和上面那块表单卡各自独立（批次106 的口径：不用底色表达分组）。 */
.set-bld-card {
  margin-top: 16px; padding: 0 20px 16px;
  background: #fff; border: 1px solid var(--c-border-light); border-radius: 8px;
}
.set-bld-card .set-card-head {
  background: transparent; height: auto; margin-bottom: 0;
  padding: 14px 0 12px; border-bottom: 1px solid #E9EDF5;
}
.set-bld-body { padding-top: 12px; font-size: 13px; color: var(--c-text-secondary); line-height: 1.9; }
.set-bld-body b { color: var(--c-text); font-weight: 600; }

/* 批次109：设置 → 房源相关设置 里的「户型预设」卡片。
   3 行 × 3 列的小表格（户型项 / 可选范围 / 默认值），比 9 个竖排输入框好读。
   ⚠ 表格只画横线不画竖线：竖线会把「1 — 9」这组范围切断，读成两个独立的格子。 */
.set-lay-tip { margin: 0 0 12px; font-size: 12.5px; color: var(--c-text-secondary); line-height: 1.7; }
.set-lay-tip b { color: var(--c-text); font-weight: 600; }
.set-lay-tbl { width: auto; max-width: 100%; border-collapse: collapse; }
.set-lay-tbl thead th {
  text-align: left; font-size: 12px; font-weight: 500; color: var(--c-text-secondary);
  padding: 0 0 8px; border-bottom: 1px solid #E9EDF5;
}
.set-lay-tbl tbody th {
  text-align: left; font-size: 13px; font-weight: 600; color: var(--c-text);
  padding: 10px 12px 10px 0; width: 64px;
}
.set-lay-tbl tbody td { padding: 10px 12px 10px 0; vertical-align: middle; }
.set-lay-tbl tbody tr + tr th, .set-lay-tbl tbody tr + tr td { border-top: 1px solid #F2F4F8; }
/* ⚠ 范围那一组必须用 inline-flex 的 <span> 包起来，不能直接给 <td> 设 display:flex ——
   那会把 td 的 table-cell 布局干掉，浏览器塞一个匿名单元格进去，
   结果「可选范围」列被撑到 300px、默认值列被挤到最右边，中间一大片空。 */
.set-lay-range { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.set-lay-tbl input[type=number] {
  width: 64px; height: 32px; padding: 0 8px; text-align: center;
  border: 1px solid var(--c-border); border-radius: 6px; font-size: 13px;
  font-variant-numeric: tabular-nums; color: var(--c-text); background: #fff;
}
.set-lay-tbl input[type=number]:focus { border-color: var(--c-primary); outline: none; }
.set-lay-dash { color: var(--c-text-secondary); font-size: 13px; }
.set-lay-tbl select {
  width: 88px; height: 32px; padding: 0 8px;
  border: 1px solid var(--c-border); border-radius: 6px; font-size: 13px;
  color: var(--c-text); background: #fff;
}
.set-lay-foot { margin-top: 14px; display: flex; align-items: center; }
.set-lay-foot .st-tip { font-size: 12px; color: var(--c-text-secondary); }
@media (max-width: 720px) {
  .set-lay-tbl { max-width: 100%; }
  .set-lay-tbl thead { display: none; }
  .set-lay-tbl tbody th { width: 44px; }
}

/* 批次110：设置 → 房源相关设置 里的「收房同步」卡片。
   四行「标签 + 值」，标签固定 68px 左对齐，值右接一行说明（来源地址 / 触发方式）。
   ⚠ 不用底色区分状态：上次失败时只把那一行的文字标红，不整块变红底 ——
     否则一屏里两块卡（户型预设 / 收房同步）只有一个刺眼，读起来像「这一页坏了」。 */
.set-acq-card .acq-row { display: flex; align-items: baseline; gap: 12px; padding: 5px 0; }
.set-acq-card .acq-k { flex: 0 0 68px; font-size: 12.5px; color: var(--c-text-secondary); }
.set-acq-card .acq-v { font-size: 13px; color: var(--c-text); line-height: 1.6; word-break: break-all; }
.set-acq-card .acq-v b { font-weight: 600; }
.set-acq-card .acq-src { margin-left: 8px; font-size: 12px; color: var(--c-text-secondary); font-variant-numeric: tabular-nums; }
.set-acq-card .acq-muted { color: var(--c-text-secondary); }
.set-acq-card .acq-bad { color: var(--c-danger); }
.set-acq-card .acq-warn { color: var(--c-danger); font-size: 13px; }
.set-acq-card .acq-note {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--c-border-light);
  font-size: 12.5px; color: var(--c-text-secondary); line-height: 1.8;
}
.set-acq-card .acq-note b { color: var(--c-text); font-weight: 600; }
.set-acq-card code { padding: 1px 5px; background: #f7f8fa; border-radius: 4px; font-size: 12px; }
@media (max-width: 720px) {
  .set-acq-card .acq-row { flex-direction: column; gap: 2px; }
  .set-acq-card .acq-k { flex: none; }
  .set-acq-card .acq-src { display: block; margin: 2px 0 0; }
}
