﻿/* 客源 CRM · 样式（第 10 轮：字号整体放大 + 统计区 + 两行筛选 + 只读备注）
   设计基调：清爽、中文优先、键盘友好、标题明显大于内容。
   注意：类名是前端各页面在用的，改样式可以，别随便改名。 */

:root {
  --primary: #2f6bff;
  --primary-strong: #245ce0;
  --primary-weak: #eef3ff;
  --primary-line: #cddffd;

  --danger: #e5484d;
  --danger-weak: #fdecec;
  --success: #12a150;
  --success-weak: #e8f7ef;
  --warning: #f5a524;
  --warning-weak: #fff8e8;
  --warning-ink: #a06a00;

  --ink: #1b1f27;
  --ink-2: #454b55;
  --ink-3: #6a7280;
  --ink-4: #949ba6;
  --ink-5: #c3c9d2;

  --bg: #f4f6f9;
  --card: #ffffff;
  --line: #e5e8ee;
  --line-2: #eff1f5;
  --hover: #f7f9fc;

  --side-bg: #171b24;
  --side-bg-2: #1f2532;
  --side-ink: #98a1b0;
  --side-line: #262d3b;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .04);
  --shadow: 0 1px 3px rgba(16, 24, 40, .06), 0 10px 28px rgba(16, 24, 40, .07);
  --shadow-lg: 0 10px 40px rgba(16, 24, 40, .18);

  --sidebar-w: 232px;
  --topbar-h: 70px;
  --font-ui: "MiSans", "HarmonyOS Sans SC", "Microsoft YaHei UI", "PingFang SC", "Source Han Sans SC", system-ui, sans-serif;
  --font-display: "MiSans", "HarmonyOS Sans SC", "Microsoft YaHei UI", "PingFang SC", sans-serif;
  --detail-shell: color-mix(in srgb, var(--bg) 74%, var(--card));
  --detail-panel: color-mix(in srgb, var(--card) 74%, var(--primary-weak));
  --detail-panel-alt: color-mix(in srgb, var(--card) 84%, var(--primary-weak));

  /* ★★★ 第 121 轮（他 2026-10-16：「苹果手机最上面就点不到，你改成适应手机」）：
     iPhone 上"看得见、点不着"的那一条＝**状态栏／刘海底下那一溜** ——
     页面在 iPhone 上会铺到它下面去（大图 / VR 那层是 `position:fixed;inset:0`，更是铺满整屏），
     而那一溜的点击会被系统吃掉。所以顶部该让的地方按安全区往下让。
     ⚠️ 这四个值只有配合 `viewport-fit=cover`（见 index.html）才不是 0。 */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

/* ★★ 2026-10-17（他原话：「客户页 / 房源页右上角加字号 − +，只针对内容区，标题区不变」）。
   做法：**只用 CSS `zoom` 缩放 `#view` 这一个盒子**（100% = 原样，值由 `app.js` 那两颗按钮写）。
   为什么是 `zoom` 而不是去改 240 处 `font-size`：
     · 内容区里那批字号全是写死的 px（`font-size` 出现 242 次、一个 rem 都没有），
       逐个乘一遍就得改 240 行、还一定漏 —— 那才是不踏实的做法；
     · `zoom` 会让 `#view` **内部重新排版**（可用宽度按 1/zoom 折算），所以放大后
       文字换行更靠前、**不会出现横向滚动条**（这是它比 `transform: scale()` 强的地方：
       scale 不改变布局，放大会直接把内容顶出屏幕）；
     · 它只作用在 `#view` 上 ⇒ 顶栏 `.topbar`、左侧栏 `.side*` **一个像素都不跟着变**，
       这就是"只针对内容区、标题区不变"的实现方式（不用去记一串类名逐个排除）。
   ⚠️ **电脑端专属**：`max-width: 860px` 那段把它钉回 1 —— 手机上的字号跟着系统预览走。 */
#view { zoom: var(--内容字号, 1); }

/* 字号 − ／ ＋ 两颗按钮（只在客户页 / 房源页出现）。 */
.zoom-group { display: flex; align-items: center; gap: 6px; margin-right: 2px; }
.zoom-btn {
  width: 34px; height: 34px; padding: 0; justify-content: center;
  font-size: 20px; line-height: 1; font-weight: 600; color: var(--ink-2);
}
.zoom-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ★★★ 第 121 轮：**只给 iPhone/iPad** 的兜底（`data-ios` 是 index.html 里那段小脚本打的；
   安卓不打这个标记，所以安卓这条规则一辈子不生效、一个像素都不动）。
   万一某个环境里 `env(safe-area-inset-top)` 报 0（老机型 / 某些内核），
   顶部也至少留 12px —— 宁可多一条空隙，也不能"看得见点不着"。 */
[data-ios] { --safe-top: max(env(safe-area-inset-top, 0px), 12px); }

* { box-sizing: border-box; }

/* 关键：作者样式里的 display（比如 .gate{display:flex}）会盖掉浏览器默认的
   [hidden]{display:none}。这一条必须放最前面。 */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg); color: var(--ink);
  font-family: var(--font-ui);
  font-size: 15px; line-height: 1.6;
  letter-spacing: .006em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ★ 2026-10-28：网站备案信息。固定在中轴底部，登录前后都能看到；
   链接只去工信部备案官网，不影响现有页面布局和操作区域。 */
.site-legal {
  position: fixed;
  left: 50%;
  bottom: max(7px, env(safe-area-inset-bottom));
  z-index: 80;
  transform: translateX(-50%);
  padding: 2px 9px;
  border: 1px solid rgba(30, 50, 43, .14);
  border-radius: 999px;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 3px 12px rgba(20, 35, 30, .08);
  color: #53635d;
  font-size: 11px;
  line-height: 1.55;
  letter-spacing: 0;
  white-space: nowrap;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.site-legal:hover,
.site-legal:focus-visible {
  color: var(--primary-strong);
  border-color: var(--primary-line);
  outline: none;
}
/* 备案信息只放在公开登录页；进入系统后隐藏，不占任何业务页面空间。 */
#app:not([hidden]) ~ .site-legal { display: none; }

button, input, textarea, select { font-family: inherit; font-size: inherit; color: inherit; }
h1, h2, h3, .page-head h1, .card-head h2, .topbar-title { font-family: var(--font-display); }
button { cursor: pointer; }
a { color: var(--primary); text-decoration: none; cursor: pointer; }
code { background: #f2f3f5; padding: 1px 6px; border-radius: 4px; font-size: 13.5px; }
.tnum { font-variant-numeric: tabular-nums; }
svg { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* ================================================================ 登录 / 初始化 */

.gate {
  min-height: 100vh; min-height: 100dvh; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(1200px 600px at 50% -10%, #e8effd 0%, transparent 60%), var(--bg);
}
.gate-card {
  width: 420px; background: var(--card); border: 1px solid var(--line);
  border-radius: 16px; box-shadow: var(--shadow); padding: 36px 34px 28px;
}
.gate-card h1 { margin: 0 0 6px; font-size: 28px; letter-spacing: -.02em; }
.gate-card .sub { color: var(--ink-4); font-size: 14px; margin-bottom: 26px; }
.gate-card .field { margin-bottom: 15px; }
.gate-card .field label { display: block; font-size: 14px; color: var(--ink-3); margin-bottom: 6px; }
.gate-card .btn { width: 100%; justify-content: center; margin-top: 10px; height: 42px; }
.gate-err { color: var(--danger); font-size: 14px; min-height: 22px; margin-top: 6px; }
.gate-tip { color: var(--ink-4); font-size: 13.5px; margin-top: 16px; line-height: 1.75; }

/* ================================================================ 登录页 V2（2026-10-21）
   电脑采用左右分屏，手机沿用城市窗景；登录页始终固定墨绿金，不受登录后的主题影响。
   注册 / 找回密码的弹窗故意放在 .gate-card 外面，避免登录页旧测试把弹窗字段算进主表单。 */
.gate.gate-login-v2 {
  width: 100%;
  max-width: 100%;
  min-height: calc(100vh - 30px - env(safe-area-inset-bottom, 0px));
  min-height: calc(100dvh - 30px - env(safe-area-inset-bottom, 0px));
  padding: 32px 32px 52px;
  align-items: stretch;
  background:
    radial-gradient(800px 560px at 18% 12%, rgba(62, 118, 98, .5), transparent 68%),
    radial-gradient(620px 480px at 92% 88%, rgba(166, 122, 58, .14), transparent 66%),
    #082f28;
}
.gate-login-shell {
  width: calc(100vw - 64px);
  max-width: none;
  height: calc(100vh - 64px);
  min-height: 620px;
  margin: auto;
  display: grid;
  grid-template-columns: 42% 58%;
  overflow: hidden;
  border-radius: 22px;
  background: #f4ede0;
  box-shadow: 0 28px 80px rgba(0, 13, 10, .36);
}
.gate-login-art {
  position: relative;
  min-height: 620px;
  padding: 42px 46px;
  overflow: hidden;
  color: #fff6e7;
  background:
    radial-gradient(460px 350px at 20% 12%, rgba(71, 132, 110, .58), transparent 72%),
    linear-gradient(145deg, #0c4438, #082d27);
}
.gate-login-art::before {
  content: "";
  position: absolute;
  right: -132px;
  bottom: 100px;
  width: 390px;
  height: 210px;
  border: 1px solid rgba(226, 193, 130, .22);
  border-radius: 50%;
  transform: rotate(-12deg);
}
.gate-login-art::after {
  content: "";
  position: absolute;
  left: -120px;
  top: -105px;
  width: 350px;
  height: 350px;
  border: 1px solid rgba(232, 204, 151, .12);
  border-radius: 50%;
  box-shadow: 0 0 0 42px rgba(232, 204, 151, .025), 0 0 0 90px rgba(232, 204, 151, .018);
}
.gate-brand-top {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: #fff8eb;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .06em;
  white-space: nowrap;
}
.gate-brand-logo {
  width: 62px;
  height: 62px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: 1px solid rgba(226, 196, 139, .48);
  border-radius: 13px;
  background: #103e34;
  box-shadow: 0 9px 24px rgba(0, 13, 10, .2);
}
.gate-brand-logo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.gate-art-copy {
  position: relative;
  z-index: 2;
  max-width: 390px;
  margin-top: 145px;
}
.gate-art-copy p {
  margin: 0 0 13px;
  color: #d7b36e;
  font-size: 12px;
  letter-spacing: .2em;
}
.gate-art-copy h2 {
  margin: 0;
  color: #fff5e4;
  font-family: "STSong", "Songti SC", "SimSun", serif;
  font-size: clamp(34px, 3.2vw, 48px);
  font-weight: 400;
  line-height: 1.38;
  letter-spacing: .08em;
}
.gate-art-copy > span {
  display: block;
  margin-top: 18px;
  color: rgba(247, 237, 218, .62);
  font-size: 14px;
  letter-spacing: .08em;
}
.gate-art-house {
  position: absolute;
  right: 26px;
  bottom: 18px;
  width: 210px;
  height: 118px;
  opacity: .62;
}
.gate-art-house .roof {
  position: absolute;
  left: 8%;
  right: 4%;
  top: 4%;
  height: 68px;
  border-top: 1px solid rgba(229, 195, 128, .82);
  border-left: 1px solid rgba(229, 195, 128, .28);
  transform: skewY(-18deg);
}
.gate-art-house .body {
  position: absolute;
  bottom: 0;
  width: 27%;
  border: 1px solid rgba(229, 195, 128, .27);
  border-bottom: 0;
  background: repeating-linear-gradient(0deg, transparent 0 22px, rgba(229, 195, 128, .13) 23px 24px);
}
.gate-art-house .body.a { left: 11%; height: 54px; }
.gate-art-house .body.b { left: 39%; height: 82px; }
.gate-art-house .body.c { left: 67%; height: 103px; }
.gate-card.gate-login-card {
  width: auto;
  padding: 52px clamp(44px, 7vw, 110px);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 0;
  background:
    radial-gradient(360px 230px at 100% 0%, rgba(198, 157, 84, .12), transparent 72%),
    #f4ede0;
  box-shadow: none;
}
.gate-login-card form {
  width: min(100%, 500px);
  margin: auto;
}
.gate-login-heading { margin-bottom: 28px; text-align: center; }
.gate-login-heading h1 {
  margin: 0;
  color: #173e35;
  font-family: "STSong", "Songti SC", "SimSun", serif;
  font-size: 38px;
  font-weight: 400;
  letter-spacing: .16em;
}
.gate-login-heading p {
  margin: 7px 0 0;
  color: #a47b3e;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 11px;
  letter-spacing: .28em;
}
.gate-login-card .field { margin-bottom: 16px; }
.gate-login-card .field label,
.gate-login-card .gate-label-row label {
  display: block;
  margin-bottom: 7px;
  color: #64716a;
  font-size: 14px;
}
.gate-label-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.gate-label-row label { margin-bottom: 7px; }
.gate-account-switch {
  padding: 0;
  border: 0;
  background: transparent;
  color: #9a743b;
  font-size: 12px;
  cursor: pointer;
}
.gate-login-card .input {
  height: 52px;
  border-radius: 8px;
  border-color: #d5cbbb;
  background: rgba(255, 253, 248, .78);
  color: #173e35;
}
.gate-login-card .input::placeholder { color: #9a9c93; }
.gate-login-card .btn.primary {
  width: 100%;
  height: 52px;
  margin-top: 4px;
  justify-content: center;
  border-radius: 7px;
  background: linear-gradient(105deg, #143d33, #225c4b 58%, #173f35);
  color: #f5dfb5;
  letter-spacing: .16em;
  box-shadow: 0 9px 22px rgba(21, 61, 51, .2);
}
.gate-login-card .gate-err { min-height: 18px; margin-top: 2px; }
.gate-card.gate-login-card.sg-card {
  width: auto;
  max-width: none;
}
.sg-login-inner {
  width: min(100%, 500px);
  margin: auto;
}
.gate-share-v2 .gate-login-heading { margin-bottom: 24px; }
.gate-share-v2 .sg-form { margin-top: 0; }
.gate-share-v2 .sg-input {
  text-align: left;
  letter-spacing: 0;
}
.gate-share-v2 .sg-go {
  margin-top: 2px;
  border: 0;
  border-radius: 7px;
  background: linear-gradient(105deg, #143d33, #225c4b 58%, #173f35);
  color: #f5dfb5;
  letter-spacing: .16em;
  box-shadow: 0 9px 22px rgba(21, 61, 51, .2);
}
.gate-share-v2 .sg-foot {
  margin-top: 14px;
  text-align: center;
  color: rgba(95, 105, 99, .72);
}
.gate-share-v2 .sg-apply {
  margin-top: 18px;
  border-top-color: rgba(154, 116, 59, .2);
}
.gate-share-v2 .sg-apply .small.muted { color: #768079; }
.gate-share-v2 .sg-apply .btn {
  justify-content: center;
  border-color: rgba(151, 112, 53, .28);
  background: rgba(255, 253, 248, .7);
  color: #315b4f;
}
.gate-share-v2 .sg-apply-ok {
  background: rgba(38, 112, 82, .1);
  color: #24634d;
}
.sg-invalid { text-align: center; }
.sg-invalid .gate-login-heading { margin-bottom: 8px; }
.sg-invalid .sub {
  max-width: 330px;
  margin: 0 auto;
  color: #718078;
  line-height: 1.75;
}
.gate-form-links {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 4px;
}
.gate-form-links button {
  min-height: 44px;
  padding: 4px 0;
  border: 0;
  background: transparent;
  color: #8d6a35;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.gate-form-links button:hover { color: #9a7134; }
.gate-access {
  position: fixed;
  z-index: 1000;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(3, 21, 17, .72);
  backdrop-filter: blur(8px);
}
.gate-access[hidden] { display: none; }
.gate-access-card {
  position: relative;
  width: min(100%, 398px);
  padding: 34px 32px 30px;
  border: 1px solid rgba(230, 199, 140, .3);
  border-radius: 19px;
  color: #f7efdf;
  background:
    radial-gradient(300px 190px at 100% 0%, rgba(76, 124, 103, .33), transparent 72%),
    #0c3a30;
  box-shadow: 0 28px 70px rgba(0, 10, 8, .46);
}
.gate-access-close {
  position: absolute;
  top: 13px;
  right: 13px;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: rgba(255,255,255,.045);
  color: rgba(248, 240, 224, .75);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.gate-access-head { padding-right: 42px; margin-bottom: 23px; }
.gate-access-head h3,
.gate-access-success h3 {
  margin: 0 0 8px;
  color: #fff7e8;
  font-family: "STSong", "Songti SC", "SimSun", serif;
  font-size: 26px;
  font-weight: 400;
  letter-spacing: .08em;
}
.gate-access-head p {
  margin: 0;
  color: rgba(244, 235, 218, .63);
  font-size: 12px;
  line-height: 1.75;
}
.gate-access-card .field { margin-bottom: 15px; }
.gate-access-card label {
  display: block;
  margin-bottom: 7px;
  color: rgba(245, 236, 218, .72);
  font-size: 13px;
}
.gate-access-card .input {
  width: 100%;
  height: 45px;
  border-color: rgba(236, 215, 177, .24);
  border-radius: 8px;
  background: rgba(255, 255, 255, .06);
  color: #fff9ed;
  font-size: 16px;
}
.gate-access-card .input::placeholder { color: rgba(244, 235, 219, .4); }
.gate-access-card .btn.primary {
  width: 100%;
  height: 46px;
  justify-content: center;
  border: 0;
  border-radius: 7px;
  background: linear-gradient(100deg, #c99b50, #e8ca8f 52%, #c1964a);
  color: #143b32;
}
.gate-access-err {
  min-height: 18px;
  margin: 2px 0 5px;
  color: #f0b4ac;
  font-size: 12px;
}
.gate-access-note {
  margin: 11px 0 0;
  color: rgba(243, 234, 216, .48);
  font-size: 11px;
  line-height: 1.65;
}
.gate-access-success { padding: 15px 0 2px; text-align: center; }
.gate-success-mark {
  width: 70px;
  height: 70px;
  margin: 0 auto 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(226, 189, 119, .48);
  border-radius: 50%;
  background: rgba(220, 180, 105, .09);
  color: #e8c783;
  font-size: 31px;
}
.gate-access-success p {
  max-width: 280px;
  margin: 0 auto 22px;
  color: rgba(243, 234, 216, .6);
  font-size: 12px;
  line-height: 1.75;
}

@media (max-width: 760px) {
  .gate.gate-login-v2 {
    width: 100vw;
    max-width: 100vw;
    margin: 0;
    padding: 0 0 46px;
    min-height: calc(100svh - 30px - env(safe-area-inset-bottom, 0px));
    min-height: calc(100dvh - 30px - env(safe-area-inset-bottom, 0px));
    background:
      radial-gradient(330px 280px at 20% 12%, rgba(57, 115, 95, .6), transparent 70%),
      linear-gradient(160deg, #082c25, #0b3b31 57%, #061f1b);
  }
  .gate-login-shell {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 100vw;
    margin: 0;
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  .gate-login-art {
    flex: 0 0 auto;
    min-height: 220px;
    padding: 26px 24px 20px;
  }
  .gate-brand-top { font-size: 16px; }
  .gate-brand-logo { width: 52px; height: 52px; }
  .gate-art-copy { margin-top: 28px; max-width: 300px; }
  .gate-art-copy p { margin-bottom: 9px; font-size: 10px; }
  .gate-art-copy h2 { font-size: 27px; line-height: 1.45; }
  .gate-art-copy > span { margin-top: 9px; font-size: 11px; }
  .gate-art-house { right: -12px; bottom: -30px; width: 170px; height: 104px; opacity: .42; }
  .gate-card.gate-login-card {
    flex: 1 1 auto;
    min-height: 0;
    padding: 32px 24px 38px;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: #fff6e7;
  }
  .gate-login-card form { width: min(100%, 360px); }
  .sg-login-inner { width: min(100%, 360px); }
  .gate-login-heading { margin-bottom: 22px; }
  .gate-login-heading h1 { color: #fff6e7; font-size: 29px; }
  .gate-login-heading p { color: #d8b36f; }
  .gate-login-card .field label,
  .gate-login-card .gate-label-row label { color: rgba(245, 235, 215, .72); }
  .gate-account-switch { color: #d8b36f; }
  .gate-login-card .input {
    border-color: rgba(235, 214, 175, .22);
    background: rgba(255, 255, 255, .06);
    color: #fff9ed;
    font-size: 16px;
  }
  .gate-login-card .input::placeholder { color: rgba(243, 235, 220, .39); }
  .gate-login-card .btn.primary {
    background: linear-gradient(100deg, #c99c50, #e8ca8e 53%, #c3984c);
    color: #163d34;
  }
  .gate-form-links button { color: #e5c681; }
  .gate-share-v2 .gate-login-card .gate-login-heading h1 { color: #fff6e7; }
  .gate-share-v2 .gate-login-art { padding: 22px 22px 16px; }
  .gate-share-v2 .gate-art-copy { margin-top: 18px; }
  .gate-share-v2 .gate-art-copy h2 { font-size: 25px; line-height: 1.35; }
  .gate-share-v2 .gate-art-copy > span { margin-top: 5px; font-size: 10.5px; }
  .gate-share-v2 .gate-login-card { padding-top: 24px; }
  .gate-share-v2 .sg-form { gap: 8px; }
  .gate-share-v2 .sg-input { height: 44px; }
  .gate-share-v2 .sg-foot { color: rgba(243, 232, 210, .58); }
  .gate-share-v2 .sg-apply { border-top-color: rgba(235, 214, 175, .18); }
  .gate-share-v2 .sg-apply .small.muted { color: rgba(243, 232, 210, .62); }
  .gate-share-v2 .sg-apply .btn {
    border-color: rgba(235, 214, 175, .24);
    background: rgba(255, 255, 255, .06);
    color: #fff6e7;
  }
  .sg-invalid .sub { color: rgba(243, 232, 210, .68); }
  .gate-access { padding: 14px; }
  .gate-access-card { padding: 30px 22px 24px; }
}

/* ================================================================ 外壳 */

.app-shell { display: flex; height: 100vh; overflow: hidden; }

.sidebar {
  width: var(--sidebar-w); flex: none;
  background:
    radial-gradient(circle at 18% 0%, color-mix(in srgb, var(--primary) 22%, transparent), transparent 32%),
    linear-gradient(180deg, var(--side-bg) 0%, color-mix(in srgb, var(--side-bg) 82%, var(--side-bg-2)) 100%);
  color: var(--side-ink);
  display: flex; flex-direction: column; padding: 16px 12px 14px;
  border-right: 1px solid color-mix(in srgb, var(--side-line) 78%, transparent);
  box-shadow: 18px 0 52px rgba(0, 0, 0, .13);
}
.brand {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 12px; margin: 0 2px 20px;
  border: 1px solid color-mix(in srgb, var(--side-ink) 18%, transparent);
  border-radius: 15px;
  background: color-mix(in srgb, var(--side-bg-2) 64%, transparent);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.055);
}
.brand-mark {
  width: 42px; height: 42px; flex: none; border-radius: 13px;
  background: linear-gradient(145deg, var(--primary), #5b8cff);
  color: #fff; font-weight: 700; font-size: 18px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 24px color-mix(in srgb, var(--primary) 32%, transparent);
}
.brand-mark.has-logo {
  width: 56px; height: 56px;
  padding: 3px;
  border: 1px solid color-mix(in srgb, var(--primary-line) 45%, transparent);
  overflow: hidden;
  background: linear-gradient(145deg, var(--primary), var(--primary-strong)) !important;
  box-shadow: 0 8px 22px color-mix(in srgb, var(--primary) 30%, transparent) !important;
}
html[data-ui-theme="blue"] .brand-mark.has-logo {
  background: linear-gradient(145deg, #173b5f, #0b2746) !important;
  border-color: rgba(123, 154, 184, .34);
  box-shadow: 0 8px 22px rgba(11, 39, 70, .34) !important;
}
.brand-mark.has-logo img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  filter: drop-shadow(0 4px 8px rgba(0,0,0,.22));
}
.brand-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.brand-text b { color: #fff; font-size: 18px; font-weight: 700; letter-spacing: .01em; }
.brand-text i { font-style: normal; font-size: 11.5px; color: color-mix(in srgb, var(--side-ink) 88%, #fff); letter-spacing: .08em; }

.nav { display: flex; flex-direction: column; gap: 5px; }
.nav a {
  display: flex; align-items: center; gap: 11px;
  min-height: 49px; padding: 6px 10px; border-radius: 12px;
  border: 1px solid transparent;
  color: var(--side-ink); font-size: 15px; font-weight: 600; letter-spacing: .01em; position: relative;
  transition: background .16s, border-color .16s, color .16s, transform .16s;
}
.nav a svg {
  width: 34px; height: 34px; flex: none; padding: 7px; border-radius: 9px;
  background: rgba(255,255,255,.045); stroke-width: 1.7;
  transition: background .16s, color .16s;
}
.nav a:hover {
  background: color-mix(in srgb, var(--side-bg-2) 76%, transparent);
  border-color: color-mix(in srgb, var(--side-ink) 16%, transparent);
  color: #fff; transform: translateX(2px);
}
.nav a.active {
  background: linear-gradient(90deg, color-mix(in srgb, var(--primary) 32%, transparent), color-mix(in srgb, var(--primary) 10%, transparent));
  border-color: color-mix(in srgb, var(--primary) 42%, transparent);
  color: #fff; font-weight: 700;
  box-shadow: inset 3px 0 0 var(--primary), 0 8px 20px rgba(0,0,0,.1);
}
.nav a.active svg { background: color-mix(in srgb, var(--primary) 34%, transparent); color: #fff; }
.nav a.active::before {
  content: ''; position: absolute; right: 10px; width: 5px; height: 5px;
  border-radius: 50%; background: currentColor; opacity: .72;
}
/* ★ 第 78 轮：菜单上的数字提醒（现在用在「后台」上 —— 有人提了底价等他审）
   放在文字右边；他要求"后台菜单挂红点"，所以给的是能点开看的数字，不只是一个圆点。 */
.nav a .nav-dot {
    margin-left: auto; min-width: 21px; height: 21px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--danger); color: #fff; font-size: 12px; font-weight: 700;
    border-radius: 11px; line-height: 1; box-shadow: 0 3px 10px rgba(229,72,77,.28);
}
.side-foot {
  margin-top: auto; padding: 10px; border: 1px solid color-mix(in srgb, var(--side-ink) 15%, transparent);
  border-radius: 13px; background: rgba(255,255,255,.028);
}
.side-note { font-size: 12px; color: color-mix(in srgb, var(--side-ink) 82%, transparent); margin: 0 2px 9px; line-height: 1.5; }
.side-foot .btn { color: var(--side-ink); background: transparent; border-color: transparent; justify-content: center; }
.side-foot .btn:hover { background: var(--side-bg-2); border-color: color-mix(in srgb, var(--side-ink) 16%, transparent); color: #fff; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }

.topbar {
  height: var(--topbar-h); flex: none;
  background: color-mix(in srgb, var(--card) 94%, transparent);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 12px; padding: 0 26px;
  box-shadow: 0 8px 26px rgba(16,24,40,.025);
  backdrop-filter: blur(14px);
}
.topbar-title { font-size: 17px; font-weight: 700; color: var(--ink-2); letter-spacing: .02em; }
.topbar-title b { color: var(--ink); }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.who { color: var(--ink-3); font-size: 15px; white-space: nowrap; }

.task-btn { position: relative; height: 38px; font-size: 15px; }
.task-btn svg { width: 19px; height: 19px; }
.task-btn.on { background: var(--primary); border-color: var(--primary); color: #fff; }
.tab-badge {
  display: inline-block; min-width: 21px; height: 21px; line-height: 21px;
  background: var(--danger); color: #fff; border-radius: 11px; font-size: 13px;
  font-style: normal; text-align: center; padding: 0 6px; margin-left: 6px;
}
.tab-badge.warn { background: var(--warning); }
.task-btn.on .tab-badge { background: rgba(255, 255, 255, .28); }

/* ================================================================ 通用控件 */

.input, textarea.input, select.input {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 9px 12px; background: #fff; outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.input:focus, textarea.input:focus { border-color: var(--primary-line); box-shadow: 0 0 0 3px rgba(47, 107, 255, .1); }
.search { width: 100%; }
textarea.input { width: 100%; resize: vertical; line-height: 1.8; }

.search-wrap { position: relative; display: flex; align-items: center; min-width: 0; }
.search-wrap > .si {
  position: absolute; left: 11px; width: 18px; height: 18px; flex: none;
  stroke: var(--ink-4); pointer-events: none;
}
.search-wrap > .input { padding-left: 36px; padding-right: 36px; }
.search-wrap > .input.no-icon { padding-left: 12px; }
.search-clear {
  position: absolute; right: 8px; width: 23px; height: 23px; padding: 0;
  border: 0; border-radius: 50%; background: #e8ebf1; color: var(--ink-3);
  font-size: 16px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.search-clear:hover { background: #dbe0e8; color: var(--ink); }

/* 第 64 轮修他报的：「我在筛选里面输入面积、底价、楼层、楼栋的内容，看不见 ——
   感觉像是输入进去了，但是我看不见。也显示 X 了，但是没有内容」。
   根因：上面那条 `.search-wrap > .input { padding-left:36px; padding-right:36px }` 是给
   **带放大镜的搜索框**留的位置；可这几个窄框只有 46~50px 宽（电脑端 media 里写死
   `#hAreaMin…{width:50px!important}`），左右 72px 的内边距**比框自己还宽** →
   文字区被挤成负数 → 字一个都画不出来，而右边那个 × 是绝对定位的，照样看得见（正是他描述的样子）。
   这几个框本来就没放大镜（icon:false），× 也不必 23px，所以单独压一版：
   6 + 17 = 23px，50px 的框里还剩 27px 给文字 ——「130」这种 3 位数放得下。
   ⚠️ 用 !important 是为了压过 media 里按 id 写死的那几条宽度规则旁的 padding（同级竞争太多）。 */
.search-wrap.narrow > .input { padding-left: 6px !important; padding-right: 17px !important; }
.search-wrap.narrow > .search-clear { right: 3px; width: 14px; height: 14px; font-size: 11px; }

.btn {
  display: inline-flex; align-items: center; gap: 7px; height: 38px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: #fff;
  color: var(--ink-2); font-size: 15px; transition: background .15s, border-color .15s, box-shadow .15s;
  white-space: nowrap;
}
.btn:hover { background: var(--hover); border-color: #d7dbe0; }
.btn.primary { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn.primary:hover { background: var(--primary-strong); border-color: var(--primary-strong); }
.btn.danger { color: var(--danger); border-color: #f3c9ca; }
.btn.danger:hover { background: var(--danger-weak); }
.btn.ghost { border-color: transparent; background: transparent; }
.btn.ghost:hover { background: var(--hover); }
.btn.small { height: 33px; padding: 0 13px; font-size: 14px; }
.btn.tiny { height: 28px; padding: 0 10px; font-size: 13px; border-radius: 6px; }
.btn.lg { height: 44px; padding: 0 22px; font-size: 16.5px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* 房源列表编号：独立可选，点击不打开详情；只给这一小块可复制反馈。 */
.house-code-copy {
  cursor: text;
  user-select: text;
  -webkit-user-select: text;
  border-radius: 4px;
  padding: 1px 3px;
  margin-left: -3px;
}
.house-code-copy:active,
.house-code-copy:focus-within {
  background: rgba(37, 99, 235, .10);
}
.house-code-copy .tnum {
  user-select: all;
  -webkit-user-select: all;
}
.btn kbd {
  font-size: 12px; color: var(--ink-4); border: 1px solid var(--line);
  border-bottom-width: 2px; border-radius: 3px; padding: 0 5px; margin-left: 3px;
}

.chipbar { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  height: 32px; padding: 0 14px; border: 1px solid var(--line); border-radius: 16px;
  background: #fff; color: var(--ink-2); font-size: 14px;
  display: inline-flex; align-items: center; gap: 5px;
}
.chip:hover { border-color: var(--primary-line); color: var(--primary); background: var(--primary-weak); }
.chip.on { background: var(--primary); border-color: var(--primary); color: #fff; }

.seg { display: inline-flex; background: #f1f3f7; border-radius: 10px; padding: 4px; gap: 3px; flex-wrap: wrap; }
.seg button {
  border: 0; background: transparent; padding: 8px 15px; border-radius: 8px;
  font-size: 15px; color: var(--ink-3); white-space: nowrap;
}
.seg button:hover { color: var(--ink); }
.seg button.active { background: #fff; color: var(--primary); font-weight: 600; box-shadow: var(--shadow-sm); }

.badge { display: inline-block; padding: 2px 10px; border-radius: 11px; font-size: 13px; line-height: 20px; }
.badge.level-A { background: var(--danger-weak); color: var(--danger); }
.badge.level-B { background: var(--warning-weak); color: var(--warning-ink); }
.badge.level-C { background: #f2f3f5; color: var(--ink-3); }
.badge.gray { background: #f2f3f5; color: var(--ink-3); }
.badge.blue { background: var(--primary-weak); color: var(--primary); }
.badge.green { background: var(--success-weak); color: var(--success); }
.badge.red { background: var(--danger-weak); color: var(--danger); }
.badge.orange { background: var(--warning-weak); color: var(--warning-ink); }

/* 视频对话：公开评论与私信分成两个通道，避免同一对话框里混成一条时间线。 */
.vd-channel-tabs {
  display: grid; grid-template-columns: 1fr 1fr; gap: 5px;
  padding: 4px; margin-bottom: 12px; border-radius: 11px; background: var(--bg);
}
.vd-channel-tab {
  min-height: 38px; border: 0; border-radius: 8px; cursor: pointer;
  background: transparent; color: var(--ink-3); font-size: 14px; font-weight: 600;
}
.vd-channel-tab.on {
  background: var(--card); color: var(--ink);
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--line-2);
}
.vd-channel-panel {
  padding: 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--card);
}
.vd-channel-panel.public { border-top: 3px solid var(--warning); }
.vd-channel-panel.private { border-top: 3px solid var(--success); }
.vd-channel-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 9px;
}
.vd-channel-head b { font-size: 14px; }
.vd-channel-note { margin-left: auto; color: var(--ink-3); font-size: 12px; }
.vd-channel-help { color: var(--ink-3); font-size: 12px; line-height: 1.55; }
.vd-channel-action { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.vd-channel-list {
  max-height: 46vh; overflow: auto; padding: 3px 2px;
  border-top: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
}
.vd-channel-list.empty {
  display: flex; align-items: center; justify-content: center;
  min-height: 76px; text-align: center;
}
.vd-reply-box { margin-top: 12px; border-top: 1px solid var(--line-2); padding-top: 10px; }
.vd-msg-channel {
  display: inline-flex; align-items: center; padding: 1px 7px;
  border-radius: 999px; font-size: 11px; font-weight: 600; line-height: 18px;
}
.vd-msg-channel.public { background: var(--warning-weak); color: var(--warning-ink); }
.vd-msg-channel.private { background: var(--success-weak); color: var(--success); }
.vd-private-dialog { border-top-width: 3px; }
@media (max-width: 860px) {
  .vd-channel-tab { min-height: 44px; }
  .vd-channel-note { width: 100%; margin-left: 0; }
  .vd-channel-list { max-height: 42vh; }
}

/* ================================================================ 内容区 */

.view {
  flex: 1;
  overflow: auto;
  padding: 24px 26px 48px;
  /* 房源三个页签的内容高度不同；固定滚动条槽位，避免切换时整页左右晃一下。 */
  scrollbar-gutter: stable;
}
/* 切页签时由代码逐帧还原位置，不让浏览器自己的滚动锚定再改一遍。 */
html.house-tab-switching-root,
html.house-tab-switching-root body,
.view.house-tab-switching { overflow-anchor: none; }
.view > * { max-width: 1600px; margin-left: auto; margin-right: auto; }

.page-head { display: flex; align-items: center; gap: 16px; margin: 0 auto 20px; flex-wrap: wrap; }
.page-head h1 { margin: 0; font-size: 32px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; }
.page-head .ph-sub { color: var(--ink-3); font-size: 15px; }
.page-head .ph-right { margin-left: auto; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
/* r214（草）：房源页内的「房源 / 成交」分段切换 —— 选中态整块填主题色，跟左侧菜单选中观感一致。 */
.view-switch {
  display: inline-flex; gap: 4px; padding: 4px;
  background: color-mix(in srgb, var(--primary) 10%, var(--bg, #f0f2f5));
  border-radius: 10px;
}
.view-switch .vs-tab {
  appearance: none; border: none; background: transparent;
  color: color-mix(in srgb, var(--ink, #1c2430) 72%, transparent);
  font-size: 14px; font-weight: 600; letter-spacing: .01em;
  min-width: 84px; padding: 7px 20px; border-radius: 7px; cursor: pointer;
  transition: background .16s, color .16s, box-shadow .16s;
}
.view-switch .vs-tab:hover { color: var(--ink, #1c2430); }
.view-switch .vs-tab.on {
  background: var(--primary, #2f6fed);
  color: #fff;
  box-shadow: 0 2px 6px color-mix(in srgb, var(--primary) 35%, transparent);
}
/* 成交页签下、搜索框那一行的四张卡 —— 完全复用工作台 .stat 卡样式（含 40px 数字、左侧色条）。 */
.deal-quick-cards { margin: 0 0 14px; }
.deal-quick-cards .stat.dq-active { border-color: var(--primary-line, #a7c0f2); box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 22%, transparent); }
.deal-quick-cards .stat .label { font-size: 15px; }
.deal-quick-cards .stat .value { font-size: 40px; }
.deal-quick-cards .stat.deal::after { background: var(--success, #2e9e6b); }
.deal-quick-cards .stat.deal .value { color: var(--success, #2e9e6b); }
.deal-quick-cards .stat::before {
  content: '';
  position: absolute; right: 16px; top: 14px; width: 34px; height: 34px;
  opacity: .18; pointer-events: none;
  background: currentColor;
  -webkit-mask: var(--dq-icon) center / contain no-repeat;
  mask: var(--dq-icon) center / contain no-repeat;
}
.deal-quick-cards .stat[data-dq="today"]::before { --dq-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'><rect x='3' y='4' width='18' height='18' rx='2'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>"); }
.deal-quick-cards .stat[data-dq="yesterday"]::before { --dq-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'><path d='M3 12a9 9 0 1 0 9-9 9 9 0 0 0-6.36 2.64L3 8'/><path d='M3 3v5h5'/></svg>"); }
.deal-quick-cards .stat[data-dq="week"]::before { --dq-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'><path d='M4 20V10M10 20V4M16 20v-7M22 20H2'/></svg>"); }
.deal-quick-cards .stat[data-dq="month"]::before { --dq-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'><path d='M3 3v18h18'/><path d='M18 17V9M13 17V5M8 17v-3'/></svg>"); }
/* 手机窄屏（≤860px）：页签和返回同一行；卡片收窄。 */
@media (max-width: 860px) {
  .page-head .view-switch { width: auto; }
  .page-head .view-switch .vs-tab { flex: 0 0 auto; min-width: 0; padding: 6px 14px; font-size: 13px; }
  .deal-quick-cards { grid-template-columns: repeat(2, minmax(0, 150px)); gap: 8px; margin-bottom: 10px; }
  .deal-quick-cards .stat { padding: 10px 12px; }
  .deal-quick-cards .stat .label { font-size: 12px; }
  .deal-quick-cards .stat .value { font-size: 24px; }
}

.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  margin: 0 auto 16px; overflow: hidden; box-shadow: var(--shadow-sm);
}
.card-head {
  padding: 15px 20px; border-bottom: 1px solid var(--line-2);
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.card-head h2 { margin: 0; font-size: 18px; font-weight: 650; }
.card-head .right { margin-left: auto; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.card-body { padding: 20px; }
.muted { color: var(--ink-4); }
.small { font-size: 13.5px; }
/* ★★ 第 79 轮（他 2026-10-08）：「共用一个链接，但手机号决定失效时间 / 能看什么」——
   权限页建链、改链弹窗里那一栏「每个号单独设置」，一行一个号。 */
.pp-list { display: flex; flex-direction: column; gap: 6px; }
.pp-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--line-2); border-radius: 8px; padding: 7px 10px;
}
.pp-row .pp-phone { font-variant-numeric: tabular-nums; min-width: 108px; }
.pp-row select.input { width: auto; flex: 0 1 168px; padding: 4px 8px; height: auto; }

/* ★★ 第 93 轮（他 2026-10-09）：访客行下面那块**明细** ——
   把这个号自己的「房源范围 / 能看的内容 / 能用的功能」直接列出来（原来只有个数，要点「修改」才知道）。
   `flex:1 0 100%` = 借 `.pp-row` 自己的 `flex-wrap:wrap` 落到下一行、占满整宽（手机上也是）。 */
.pp-own {
  flex: 1 0 100%;
  margin-top: 2px; padding-top: 7px;
  border-top: 1px dashed var(--line);
  font-size: 12.5px; line-height: 1.8; color: var(--ink-2);
  overflow-wrap: anywhere;
}
.pp-own b { color: var(--ink-3); font-weight: 650; margin-right: 2px; }

/* ★★ 第 79 轮：门槛页「申请看房」那一小块 */
.sg-apply { margin-top: 10px; border-top: 1px dashed var(--line-2); padding-top: 10px; }
.sg-apply-form { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.sg-apply-ok {
  margin-top: 10px; background: var(--success-weak); color: var(--success);
  padding: 9px 11px; border-radius: 8px; font-size: 13.5px;
}

/* ★★ 第 78 轮：没开放的字段**标签留着、内容打码**。
   以前是整列不画，他看着像"这页坏了"；现在是列头都在、值是 ****。
   给个淡淡的底色 + 等宽字母，一眼看出"这不是空，是没给我看"。 */
.mask {
  color: var(--ink-4);
  letter-spacing: 1.5px;
  font-weight: 600;
  background: var(--line-2);
  border-radius: 4px;
  padding: 0 5px;
  font-size: 12.5px;
  user-select: none;
}
.row { display: flex; align-items: center; gap: 12px; }
.row.wrap { flex-wrap: wrap; }
.spacer { flex: 1; }
hr.sep { border: 0; border-top: 1px solid var(--line-2); margin: 16px 0; }

/* 工作台卡片 */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; margin-bottom: 20px; }
.stat {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px; cursor: pointer; transition: transform .13s, box-shadow .13s, border-color .13s;
  box-shadow: var(--shadow-sm); position: relative; overflow: hidden;
}
.stat::after {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--primary);
}
.stat.hot::after { background: var(--danger); }
.stat.warm::after { background: var(--warning); }
.stat.calm::after { background: var(--primary); }
.stat:hover { border-color: var(--primary-line); box-shadow: var(--shadow); transform: translateY(-1px); }
.stat .label { font-size: 15px; color: var(--ink-3); }
.stat .value { font-size: 40px; font-weight: 700; letter-spacing: -.03em; margin: 4px 0 0; line-height: 1.15; }
.stat.hot .value { color: var(--danger); }
.stat.warm .value { color: var(--warning); }
.stat.calm .value { color: var(--primary); }

/* ★★★ 第 113 轮 · 第 4 条（他 2026-10-12）：「待办事项加上导航，比如 看房申请，视频消息，
   点一下，跳到对应的栏目上去」——
   `.todo-jump` = 待办上的**入口**（工作台待办卡小字里的每一类 ＋ 待办弹窗里那几颗徽标）。 */
.todo-jump { cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.todo-jump:hover { color: var(--primary); }
/* 徽标本身就是入口时，别被"虚线下划线"弄得像坏掉的徽标 —— 只留手型 + 悬停变色 */
.badge.todo-jump { text-decoration: none; }
.badge.todo-jump:hover { filter: brightness(.95); box-shadow: 0 0 0 2px var(--primary-line); }

/* 统计区：两张卡并排 */
.stats-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.stats-2col > .card { margin-bottom: 0; }

/* 统计小表（左标签右数值） */
.kv-table { width: 100%; border-collapse: collapse; }
.kv-table td { padding: 7px 0; border-bottom: 1px dashed var(--line-2); font-size: 15px; }
.kv-table tr:last-child td { border-bottom: 0; }
.kv-table td.k { color: var(--ink-3); }
.kv-table td.v { text-align: right; font-weight: 650; font-size: 17px; }
.kv-table td.v small { font-weight: 400; font-size: 13px; color: var(--ink-4); }

/* 横向条形（分布 / 排行） */
.bars { display: flex; flex-direction: column; gap: 8px; }
.bar-row { display: grid; grid-template-columns: 116px 1fr 62px; align-items: center; gap: 10px; font-size: 14px; }
.bar-label { color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-track { height: 12px; background: #eef1f6; border-radius: 6px; overflow: hidden; }
.bar-fill { height: 100%; background: linear-gradient(90deg, #6f9bff, var(--primary)); border-radius: 6px; }
.bar-fill.down { background: linear-gradient(90deg, #ff9aa0, var(--danger)); }
.bar-fill.up { background: linear-gradient(90deg, #7fd8a6, var(--success)); }
.bar-value { text-align: right; font-weight: 650; }

/* 折线图（变价趋势） */
.chart { width: 100%; position: relative; }
/* 工作台统计表的纯装饰分隔线：只画边框，不增加列，不影响布局 */
.tbl th.wb-divide, .tbl td.wb-divide { border-left: 1px solid var(--line); }
.tbl th.wb-divide { border-left-color: var(--line-2); }
/* 平均单价走势没有数据时也保留图表高度，搜索小区时页面不跳动 */
.trend-empty { min-height: 190px; display: flex; align-items: center; padding: 0 2px; box-sizing: border-box; }
.chart svg { width: 100%; height: auto; display: block; }
.chart .axis { stroke: var(--line); stroke-width: 1; }
.chart .grid { stroke: var(--line-2); stroke-width: 1; }
.chart .line { fill: none; stroke: var(--primary); stroke-width: 2.5; }
.chart .area { fill: rgba(47, 107, 255, .10); stroke: none; }
/* ★ 第 75 轮：他「**只要点不要圆圈**」，紧接着又说「**还是有圆圈**」——
   第一版我把点从"白心蓝边的空心圆"改成实心点（那一步是对的），
   但**鼠标移上去又把它放大 1.9 倍**成一坨更大的圆 —— 他看到的"圆圈"就是它。
   现在：**点是点，悬浮不改形状/大小**，只弹数据条（提示条贴在哪个点旁边，本身就说明了选中的是哪个）。 */
.chart .dot { fill: var(--primary); stroke: none; }
.chart .tick { fill: var(--ink-4); font-size: 11px; stroke: none; }
/* 真正接鼠标的是外面 r=12 的透明命中区（3px 的点根本瞄不准），它本身**完全看不见** */
.chart .hit { fill: transparent; stroke: none; cursor: pointer; }
.chart-tip {
  position: absolute; z-index: 6; pointer-events: none;
  transform: translate(-50%, -100%);
  background: rgba(17, 24, 39, .93); color: #fff;
  font-size: 12.5px; line-height: 1.5; white-space: nowrap;
  padding: 6px 10px; border-radius: 8px; box-shadow: 0 6px 18px rgba(16, 24, 40, .22);
  opacity: 0; transition: opacity .12s;
}
.chart-tip.on { opacity: 1; }
/* 点太靠上时翻到点的下面（见 views.js 的 __kyDot） */
.chart-tip.below { transform: translate(-50%, 0); }
@media (max-width: 860px) {
  /* 手机上点一下也能看（没有 hover）；字号大一点，别戳不着 */
  .chart-tip { font-size: 13.5px; padding: 7px 11px; }
}

/* 筛选条（可以有多行） */
.filter-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 20px;
}
.filter-row + .filter-row { border-top: 1px solid var(--line-2); }
.fgroup { display: flex; align-items: center; gap: 7px; }
.flabel { font-size: 14px; color: var(--ink-3); white-space: nowrap; font-weight: 600; }

/* 客户页头部：标题 + 共 N 个客户 + 状态 + 新增，尽量排在一行（第 35 轮他要的） */
.cust-title { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.cust-head #cStatus { width: 136px; }
.cust-head .ph-right { gap: 8px; }

/* 只读备注展示 */
.remark-view {
  white-space: pre-wrap; word-break: break-word;
  font-size: 15.5px; line-height: 1.85; color: var(--ink);
      background: var(--detail-panel); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 14px 16px; min-height: 120px;
}
/* 客户档案：不要边框，就是一块文字 */
.remark-view.plain { border: 0; background: transparent; padding: 0; min-height: 0; }
/* 跟进记录固定高度，后期跟进多了在框里滑（窗口本身高度不变） */
#colFollows { height: 556px; overflow: auto; }

/* ================================================================ 表格 */

table.tbl { width: 100%; border-collapse: collapse; }
table.tbl th, table.tbl td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--line-2); font-size: 15px; }
table.tbl th {
  font-weight: 650; font-size: 14px; color: var(--ink-3);
  background: #f8fafc; white-space: nowrap; position: sticky; top: 0; z-index: 2;
}
table.tbl tbody tr { cursor: pointer; transition: background .1s; }
table.tbl tbody tr:hover { background: var(--hover); }
table.tbl tbody tr.selected { background: var(--primary-weak); }
table.tbl tbody tr:last-child td { border-bottom: 0; }
table.tbl td.nowrap { white-space: nowrap; }
table.tbl td.remark {
  max-width: 360px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--ink-2);
}
table.tbl th.sortable { cursor: pointer; user-select: none; }
.empty { padding: 56px 20px; text-align: center; color: var(--ink-4); font-size: 15px; }
.empty .big { font-size: 36px; margin-bottom: 8px; }

.pager { display: flex; align-items: center; gap: 12px; padding: 15px 20px; color: var(--ink-3); font-size: 15px; }
.pager .spacer { flex: 1; }
.pager-jump { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.pager-page-input {
  width: 56px;
  height: 30px;
  box-sizing: border-box;
  text-align: center;
  padding: 3px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--card, #fff);
  color: inherit;
  font: inherit;
}
.pager-page-input:focus { outline: 2px solid rgba(37,99,235,.35); outline-offset: 1px; }

/* ================================================================ 提醒列表 */

.rem-list { }
.rem-row {
  display: flex; align-items: center; gap: 14px; padding: 13px 20px;
  border-bottom: 1px solid var(--line-2); cursor: pointer; transition: background .1s;
}
.rem-row:last-child { border-bottom: 0; }
.rem-row:hover { background: var(--hover); }
.rem-row.selected { background: var(--primary-weak); box-shadow: inset 4px 0 0 var(--primary); }
.rem-row.important {
  background: color-mix(in srgb, var(--danger, #c0392b) 7%, var(--bg, #fff));
  box-shadow: inset 4px 0 0 var(--danger, #c0392b);
}
.rem-date { width: 92px; flex: none; font-size: 15px; color: var(--ink-2); }
.rem-cust { width: 160px; flex: none; font-weight: 650; font-size: 15.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rem-text { flex: 1; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; font-size: 15px; }
.rem-over { width: 104px; flex: none; font-size: 14px; }
.rem-acts { flex: none; display: flex; gap: 7px; }
.rem-row.done .rem-text, .rem-row.done .rem-cust { text-decoration: line-through; color: var(--ink-4); }

/* ================================================================ 客户详情（整页） */

.detail-head { display: flex; align-items: center; gap: 15px; flex-wrap: wrap; }
.detail-head .name { font-size: 26px; font-weight: 700; letter-spacing: -.01em; }
.detail-head .meta { color: var(--ink-3); font-size: 15px; display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }

/* 图片位（预留：后期放房源图片 / 户型图） */
.img-slot {
  width: 104px; height: 72px; margin: 0 auto;
  border: 1px dashed var(--line); border-radius: 7px; background: #fafbfc;
  display: flex; align-items: center; justify-content: center; color: var(--ink-5);
}
.img-slot svg { width: 20px; height: 20px; }
.img-slot.big {
  width: 100%; height: 170px; flex-direction: column; gap: 8px;
  font-size: 13.5px; color: var(--ink-4); border-radius: var(--radius-sm);
}
.img-slot.big svg { width: 34px; height: 34px; }

/* 列表里有图之后：缩略图铺满那一格 */
a.img-slot.has-img { border: 0; background: none; position: relative; overflow: hidden; padding: 0; }
a.img-slot.has-img img { width: 100%; height: 100%; object-fit: cover; border-radius: 7px; display: block; }
.img-badge {
  position: absolute; right: 2px; bottom: 2px; background: rgba(0,0,0,.62); color: #fff;
  font-size: 10.5px; line-height: 1; padding: 2px 4px; border-radius: 6px;
}

/* 第 64 轮：房源 VR 角标。
   位置：图片缩略图的**左上角**（「共 N 张」在右下角，两个不打架）。
   点开是 realsee 的完整 VR 播放器（新窗口），不是我们截的图。 */
.img-cell { position: relative; display: inline-block; }
.vr-chip {
  position: absolute; left: 0; top: 0; z-index: 2;
  background: #1668dc; color: #fff; font-size: 10px; line-height: 1;
  padding: 2px 4px; border-radius: 6px; font-weight: 700; text-decoration: none;
  box-shadow: 0 1px 3px rgba(0,0,0,.22);
}
.vr-chip:hover { background: #0f56b8; color: #fff; }
/* 手机卡片头是 flex（标题 flex:1 会把后面的推开），所以卡片上的 VR 不能绝对定位 */
.vr-chip.in-card { position: static; flex: none; padding: 3px 7px; font-size: 11px; }

/* ---------------- 房源图片墙（第 37 轮） ---------------- */
.hd-imgs {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: #fbfcfd; padding: 10px 12px; margin-bottom: 12px;
}
.hd-imgs-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.hd-imgs-head b { font-size: 13.5px; }
.hd-imgs-body { display: flex; flex-wrap: wrap; gap: 8px; }
.hd-imgs-empty {
  width: 100%; height: 74px; border: 1px dashed var(--line); border-radius: 8px;
  display: flex; align-items: center; justify-content: center; color: var(--ink-5); font-size: 13px;
}
.hd-img { position: relative; width: 104px; height: 78px; border-radius: 8px; overflow: hidden; background: #eef1f4; }
.hd-img a { display: block; width: 100%; height: 100%; }
.hd-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hd-img-kind {
  position: absolute; left: 3px; bottom: 3px; border: 0; cursor: pointer;
  background: rgba(0,0,0,.6); color: #fff; font-size: 10.5px; line-height: 1;
  padding: 3px 5px; border-radius: 6px;
}
.hd-img-del {
  position: absolute; right: 3px; top: 3px; border: 0; cursor: pointer;
  width: 20px; height: 20px; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff;
  font-size: 12px; line-height: 1; padding: 0;
}
.hd-img-move { position: absolute; right: 3px; bottom: 3px; display: flex; gap: 2px; }
.hd-img-move button {
  border: 0; cursor: pointer; width: 20px; height: 20px; border-radius: 6px;
  background: rgba(0,0,0,.55); color: #fff; font-size: 13px; line-height: 1; padding: 0;
}
.hd-img-move button:disabled { opacity: .3; cursor: default; }

@media (max-width: 560px) {
  .hd-img { width: calc(33.33% - 6px); height: 84px; }
  .hd-imgs { padding: 9px 10px; }
}

/* ---------------- 全屏看图（可放大缩小、左右滑，第 37 轮他要求的） ---------------- */
.img-viewer {
  position: fixed; inset: 0; z-index: 9999;
  background: rgba(8, 10, 14, .94);
  display: flex; flex-direction: column;
  touch-action: none; user-select: none;
  /* ★★★ 第 124 轮（他 2026-10-16：「VR 最上面的『新窗口打开』和 ✕ 要做到固定，
     不要随着整屏滑动」）：这一层**自己也不许滚** —— 顶上那条（✕ 在里面）才钉得住。
     另一半在 JS 里：`views.js 锁滚动()` 把这层开着的时候**整页**也锁住
     （iOS 上 `fixed` 是贴布局视口的，页面一滚这一层就跟着走）。两条一起才稳。 */
  overflow: hidden;
}
.iv-top, .iv-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; color: #e8ecf2; flex: none;
}
/* ★★★ 第 121 轮：iPhone 上「点开 VR 关不了、点不到关闭按钮」就是这个 ——
   这一层铺满整屏（`inset:0`），顶上那条顶条正好落在**状态栏／刘海那一溜**里，
   手指点下去被系统吃掉。顶条按安全区往下让，✕ 就摸得到了。 */
.iv-top { padding-top: calc(10px + var(--safe-top)); }

/* ---- 第 68 轮：VR 全屏层（他：「看 VR 回去的时候没有 ✕」）----------------
   跟看大图共用 .img-viewer 那个壳（全屏 + 顶部一条 + 自己画 ✕），
   只是中间换成内嵌窗口；嵌不出来时上面那颗「新窗口打开」兜底。 */
.vr-viewer .vr-stage { flex: 1 1 auto; min-height: 0; padding: 0 8px; }
.vr-viewer .vr-stage iframe { width: 100%; height: 100%; border: 0; display: block; border-radius: 10px; background: #000; }
/* 第 69 轮：他「VR 点进去滑不动」——
   这层跟看大图共用 .img-viewer 那个壳，而那个壳是给"图片缩放/滑走关闭"写的
   （touch-action / 手势都在上面），嵌进去的 VR 就收不到手指了 ✗。
   所以 VR 这层把触摸手势**还回去**，页面的手势一律不拦。 */
.vr-viewer, .vr-viewer .vr-stage, .vr-viewer iframe { touch-action: auto !important; -webkit-overflow-scrolling: touch; }
.vr-viewer .vr-stage iframe { pointer-events: auto; }
.vr-viewer .vr-tip { flex: none; padding: 8px 12px 14px; text-align: center; color: #93a3b5; font-size: 12.5px; }
.vr-viewer .iv-btn { text-decoration: none; }
.iv-bar { justify-content: center; padding-bottom: calc(10px + var(--safe-bottom)); }
.iv-count { font-size: 13.5px; opacity: .9; }
.iv-zoom { font-size: 12.5px; width: 46px; text-align: center; opacity: .85; }
.iv-hint { font-size: 11.5px; opacity: .5; margin-left: 6px; }
.iv-btn {
  background: rgba(255,255,255,.14); color: #fff; border: 0; cursor: pointer;
  border-radius: 8px; padding: 6px 11px; font-size: 13px; line-height: 1.2;
}
.iv-btn:hover { background: rgba(255,255,255,.24); }
.iv-stage {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  overflow: hidden; position: relative;
}
.iv-stage img {
  max-width: 100%; max-height: 100%; object-fit: contain;
  transform-origin: center center; transition: transform .12s ease-out;
  -webkit-user-drag: none;
  /* ★★★ 第 121 轮（他 2026-10-16：「图片滑动有点延迟」，**所有端**）：
     原来这一张**没有独立合成层**（压测台量到 `will-change: auto`），
     于是手指拖动时每一帧都要把这张 2400x1800 的大图**重新画一遍**（缩放着画，最贵的一种）；
     提升成自己的层之后，拖动/翻页只让 GPU 做一次变换，不再重绘位图。
     ⚠️ `will-change` 只在"开着大图的这一会儿"存在（这一层是临时 DOM，关掉即销毁），
        所以不会像长期挂着 will-change 那样白占显存。 */
  will-change: transform;
  transform: translateZ(0);
  backface-visibility: hidden;
}
/* 手机长按图片：系统菜单不一定给“保存图片”（这一层有缩放/滑动手势），
   所以用我们自己的底部菜单收口，复制和保存都从同一张已加载的原图生成。 */
.iv-image-sheet {
  position: absolute; inset: 0; z-index: 6;
  display: flex; align-items: flex-end; justify-content: center;
  padding: 12px 12px calc(12px + var(--safe-bottom));
  background: rgba(0, 0, 0, .28);
  touch-action: manipulation;
}
.iv-image-sheet[hidden] { display: none !important; }
.iv-image-sheet-card {
  width: min(100%, 420px); padding: 10px;
  border-radius: 16px; background: #f8fafc;
  box-shadow: 0 16px 50px rgba(0,0,0,.36);
}
.iv-image-sheet-title {
  padding: 7px 10px 10px; color: #667085;
  font-size: 13px; text-align: center;
}
.iv-image-action {
  width: 100%; min-height: 48px; border: 0; border-radius: 11px;
  background: #fff; color: #1b1f27; font-size: 16px; cursor: pointer;
}
.iv-image-action + .iv-image-action { margin-top: 7px; }
.iv-image-action:active { background: #e9eef6; }
.iv-image-action.cancel { color: #667085; }
.iv-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 42px; height: 64px; border: 0; cursor: pointer;
  background: rgba(255,255,255,.12); color: #fff; font-size: 26px; line-height: 1; border-radius: 10px;
}
.iv-nav:hover { background: rgba(255,255,255,.24); }
.iv-nav.prev { left: 8px; }
.iv-nav.next { right: 8px; }
/* ★★★ 第 121 轮（他 2026-10-16）：「图片每次点开都有个提示 左右滑切换，也能点两边箭头，
   这个取消掉」⇒ 第 112 轮那句提示（`.iv-swipe-tip` ＋ `@keyframes ivtip`）**整段撤掉**，
   手机和电脑都不再画。手指左右滑、两边箭头、滚轮缩放一个字没动。 */
@media (max-width: 560px) {
  .iv-hint { display: none; }
  /* ★★★ 第 113 轮 · 第 1 条（他 2026-10-12）：「图片左右滑不动……**也要加上 下一页 上一页，
     跟之前一样，也可以点击**」——
     第 112 轮「侧滑」那一版把手机上的左右箭头**藏掉**了（`.iv-nav{display:none}`），
     他实测的结果就是"手机上既点不着、也以为滑不动"。所以现在**两条路并存**：
       · 手指左右滑照旧（`views.js` 的 `翻页()`，位移阈值 40px，不把"点一下"当滑动）；
       · 左右箭头**恢复**，而且比原来更大更好点（44×72，手机上手指够得着）。
     ⚠️ 电脑端（>560px）一个字没动。 */
  .iv-nav { display: block; width: 44px; height: 72px; font-size: 28px; }
  .iv-nav.prev { left: 6px; }
  .iv-nav.next { right: 6px; }
  /* ★★★ 第 121 轮（他 2026-10-16：「我在苹果手机点开 VR，都关不了，点不到关闭按钮」）：
     顶条那两颗按钮原来只有 ~28px 高，手机上本来就不好按；这一档放到 **44px**（苹果自己的建议值），
     ✕ 再单独加宽。⚠️ 只动手机上这一档的选择器，电脑端一个字没动。 */
  .iv-top .iv-btn { min-height: 44px; display: inline-flex; align-items: center; padding: 0 14px; font-size: 14px; }
  .iv-top .iv-btn[data-act=close] { min-width: 48px; justify-content: center; font-size: 17px; }
}

/* 表格：内容竖直居中 —— 他说的「标题和内容上下对齐、标题在内容中间」是这个意思（不是横向居中） */
/* 表格容器固定高度（约 6 行），内容在框里滑 —— 不然筛出一行时卡片会忽大忽小 */
.tbl-scroll { height: 306px; overflow: auto; }
/* 数字表固定 6 行高（报价区间 / 平均单价两张并排的卡要对齐） */
.kv-scroll { height: 224px; overflow: auto; padding: 6px 20px; }
@media (max-width: 860px) { .tbl-scroll { height: 260px; } .kv-scroll { height: 200px; } }

/* 可排序表头：点一下升序、再点降序 */
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { color: var(--primary); background: #f1f5fd; }
th.sortable .sort-ar { font-style: normal; font-size: 11px; color: var(--ink-5); margin-left: 2px; }
th.sortable.on { color: var(--primary); }
th.sortable.on .sort-ar { color: var(--primary); }

/* 表格：内容竖直居中 —— 他说的「标题和内容上下对齐、标题在内容中间」是这个意思（不是横向居中） */
table.tbl th, table.tbl td { vertical-align: middle; }

/* 房源列表：整行按百分比平铺（不再让小区一列吃光宽度，房号紧跟在小区后面）+ 备注留宽
   注意：只铺平列宽，文字仍是左对齐（他说过「居中」指竖直对齐，不是横向居中） */
table.tbl-house { table-layout: fixed; width: 100%; min-width: 1280px; }
table.tbl-house td.remark { max-width: none; }
table.tbl-house th { text-align: center; }table.tbl-house .house-code{display:block;margin-top:4px;color:var(--ink-3);font-size:12px;font-weight:400;text-align:center}
/* r161 续：小区名称按列宽换行并居中；图片列给了 112px，不再让 104px 的缩略图
   压到隔壁小区格上（他看到的“小区名称显示不全”就是这块重叠）。 */
table.tbl-house td.house-community-cell {
  text-align: center; white-space: normal; line-height: 1.35;
  overflow-wrap: anywhere; word-break: break-word;
}
table.tbl-house td.house-community-cell > b { display: block; font-weight: 650; }

/* 工作台：卡片按左右上下依次排；同一行的卡片**等高**、内容撑满，不留一块块空白 */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; align-items: stretch; }
.grid-2 > .card { margin-bottom: 0; display: flex; flex-direction: column; }
.grid-2 > .card > .card-body { flex: 1; }
.grid-2 > .card.span-2 { grid-column: 1 / -1; }

/* 图表卡的标题居中（标题在内容中间），右边的小字跟着居中 */
.card-head.center { justify-content: center; text-align: center; }
/* 2026-10-20 工作台统计卡统一头部：标题左、搜索框居中、说明单独一行居中。 */
.card-head.wb-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px minmax(0, 1fr);
  align-items: center;
  column-gap: 14px;
}
.card-head.wb-head > h2 { grid-column: 1; justify-self: start; text-align: left; min-width: 0; }
.card-head.wb-head > .right { grid-column: 2; margin: 0; width: 380px; display: flex; justify-content: center; }
.card-head.wb-head > .right .fgroup { width: 100%; display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "label input" "count count"; align-items: center; column-gap: 8px; row-gap: 4px; }
.card-head.wb-head > .right .flabel { grid-area: label; white-space: nowrap; }
.card-head.wb-head > .right .search-wrap { grid-area: input; width: 260px !important; max-width: 100%; justify-self: center; }
.card-head.wb-head > .right .search-wrap > .input { width: 100%; }
.card-head.wb-head > .right .small.muted { grid-area: count; justify-self: center; text-align: center; white-space: normal; overflow-wrap: anywhere; }
.card-head.wb-head > .right.small.muted { grid-column: 2; justify-self: center; text-align: center; }

@media (max-width: 860px) {
  .card-head.wb-head {
    display: flex; flex-direction: column; align-items: stretch;
    row-gap: 8px; padding: 12px 12px 10px;
  }
  .card-head.wb-head > h2 { text-align: center; align-self: center; font-size: 17px; line-height: 1.25; }
  .card-head.wb-head > .right { width: 100%; margin: 0; display: block; }
  .card-head.wb-head > .right .fgroup {
    display: flex; flex-direction: column; align-items: center;
    width: 100%; row-gap: 5px;
  }
  .card-head.wb-head > .right .flabel { display: block; text-align: center; }
  .card-head.wb-head > .right .search-wrap { width: 260px !important; max-width: 100%; flex: 0 0 auto; min-height: 34px; }
  .card-head.wb-head > .right .small.muted {
    display: block; width: 100%; max-width: 360px;
    font-size: 12px; line-height: 1.4; text-align: center;
    white-space: normal; overflow-wrap: anywhere;
  }
  #wbAreaTable table, #wbDealTable table { min-width: 560px; }
  #wbAreaTable th, #wbDealTable th, #wbAreaTable td, #wbDealTable td { white-space: nowrap; }
}
.card-head.center .right { margin-left: 12px; }

/* 数字列表格：列均匀铺满整行、数字居中（不留一边的空白） */
table.kv-table.wide { table-layout: fixed; width: 100%; }
table.kv-table.wide td { text-align: center; }
table.kv-table.wide td.k { text-align: left; }

/* 小区价格表：列按比例铺开 + 数字居中 */
table.tbl-fixed { table-layout: fixed; width: 100%; }
table.tbl-fixed td, table.tbl-fixed th { text-align: center; }
table.tbl-fixed td:first-child, table.tbl-fixed th:first-child { text-align: left; }

/* 可以点的统计行（点进对应的列表） */
.kv-table tr.clickable { cursor: pointer; }
.kv-table tr.clickable:hover td { background: var(--hover); }
.kv-table tr.clickable td.k::after { content: ' ›'; color: var(--ink-5); }

/* 客户详情窗口：两栏（左备注+需求 / 右跟进记录）。
   注意必须写 .modal.cd-modal —— 只写 .cd-modal 会被后面同权重的 .modal{width:620px} 盖掉（踩过） */
.modal.cd-modal { width: min(1058px, 96vw); }
.cd-head { align-items: center; }
.cd-identity { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.cd-identity h1 { margin: 0; }
.cd-contact { flex: 1 1 300px; min-width: 0; }
.cd-contact a {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.cd-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cd-modal .modal-body {
  max-height: 766px;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--primary-weak) 28%, transparent), transparent 42%),
    var(--detail-shell);
}
.cd2 { display: grid; grid-template-columns: minmax(320px, 44%) 1fr; gap: 0; }
.cd-modal .cd2-left {
  border-right: 1px solid var(--line);
  padding: 15px 18px;
  background: var(--detail-panel);
}
.cd-modal .cd2-right {
  padding: 15px 18px;
  min-width: 0;
  background: var(--detail-panel-alt);
}
.cd-modal .remark-view { background: color-mix(in srgb, var(--card) 88%, var(--primary-weak)); }
.cd-modal .fact-bar { background: var(--detail-panel-alt); border-color: var(--line); }
.cd-scroll { max-height: 560px; overflow: auto; }
/* 左栏现在整栏都是「客户档案」，让它撑满同样高度（右栏跟进记录也是固定高，两栏齐平） */
.cd2-left .cd-scroll { height: 556px; max-height: none; }

/* 2026-10-22：客户详情最小化为随行卡。
   电脑端固定在右上角；手机端改成底部卡，二者共用同一份数据与写跟进动作。 */
.overlay.is-float.cd-dock-overlay {
  z-index: 210;
  padding: calc(var(--topbar-h) + 12px) 16px 24px;
}
.modal.cd-dock {
  pointer-events: auto;
  width: 360px;
  max-width: calc(100vw - 32px);
  max-height: calc(100dvh - var(--topbar-h) - 40px);
  display: flex;
  flex-direction: column;
  border: 1px solid color-mix(in srgb, var(--line) 82%, var(--primary) 18%);
  border-radius: 15px;
  background:
    linear-gradient(155deg, color-mix(in srgb, var(--gold-soft) 52%, transparent), transparent 130px),
    var(--card);
  box-shadow: 0 16px 42px rgba(16, 24, 40, .22);
  overflow: hidden;
}
.modal.cd-dock.is-minimized { width: 320px; }
.modal.cd-dock.is-minimized .modal-body,
.modal.cd-dock.is-minimized .cd-dock-foot,
.modal.cd-dock.is-minimized .cd-dock-sub { display: none !important; }
.modal.cd-dock.is-minimized .modal-head { border-bottom: 0; }
.cd-dock .modal-head.cd-dock-head {
  flex: none;
  min-height: 58px;
  padding: 9px 9px 9px 12px;
  gap: 8px;
  flex-wrap: nowrap;
  background: color-mix(in srgb, var(--card) 92%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 72%, var(--gold) 28%);
}
.cd-dock-head-main {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1;
}
.cd-dock-avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  color: #fff9ee;
  font-family: Georgia, "Microsoft YaHei", serif;
  font-size: 15px;
  background: linear-gradient(145deg, var(--primary), var(--ink));
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .2);
}
.cd-dock-person {
  min-width: 0;
  flex: 1;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
}
.cd-dock-name-row {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
}
.cd-dock-name-row strong {
  overflow: hidden;
  font-size: 15px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cd-dock-name-row .badge { flex: none; }
.cd-dock-sub {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 2px;
  overflow: hidden;
  color: var(--ink-3);
  font-size: 11.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cd-dock-icon {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  padding: 0;
  color: var(--ink-3);
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-size: 20px;
  line-height: 1;
}
.cd-dock-icon:hover { color: var(--ink); background: var(--hover); }
.cd-dock .modal-head .close {
  width: 28px;
  height: 28px;
  margin-left: 0;
  padding: 0;
  font-size: 22px;
}
.cd-dock .modal-body {
  min-height: 0;
  max-height: none;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 12px 13px;
}
.cd-dock-section {
  padding: 11px 12px;
  background: color-mix(in srgb, var(--card) 82%, var(--surface-2, var(--hover)));
  border: 1px solid var(--line-2);
  border-radius: 10px;
}
.cd-dock-section + .cd-dock-section { margin-top: 9px; }
.cd-dock-section .section-title { margin-bottom: 7px; font-size: 12.5px; }
.cd-dock-profile {
  max-height: 144px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.65;
}
.cd-dock-follow-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 5px;
  color: var(--ink-4);
  font-size: 12px;
}
.cd-dock-follow {
  max-height: 108px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--ink);
  font-size: 13.5px;
  line-height: 1.62;
}
.cd-dock-reminder {
  margin-top: 8px;
  padding-top: 7px;
  border-top: 1px dashed var(--line-2);
  color: var(--warning-ink, var(--ink-3));
  font-size: 12px;
}
.cd-dock-foot { flex: none; padding: 0 13px 13px; }
.cd-dock-nav {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
  margin-bottom: 7px;
}
.cd-dock-nav .btn { justify-content: center; min-width: 0; }
.cd-dock-actions { display: flex; gap: 7px; margin: 0; }
.cd-dock-actions .btn { flex: 1; justify-content: center; }
@media (min-width: 861px) {
  body.has-cd-dock .overlay:not(.is-float):not(.cd-dock-overlay) { padding-right: 392px; }
}
@media (max-width: 860px) {
  .overlay.is-float.cd-dock-overlay {
    align-items: flex-end;
    justify-content: center;
    padding: calc(var(--topbar-h) + 10px + var(--safe-top)) 8px calc(10px + var(--safe-bottom));
  }
  .modal.cd-dock,
  .modal.cd-dock.is-minimized {
    width: 100%;
    max-width: 100%;
    border-radius: 16px;
  }
  .modal.cd-dock { max-height: min(68dvh, 560px); }
  .modal.cd-dock.is-minimized { max-height: 58px; }
  .cd-dock .modal-head.cd-dock-head {
    min-height: 58px;
    padding: 7px 7px 7px 11px;
  }
  .cd-dock-avatar { width: 34px; height: 34px; font-size: 15px; }
  .cd-dock-person { min-height: 42px; }
  .cd-dock-name-row strong { font-size: 15px; }
  .cd-dock-sub { font-size: 11px; }
  .cd-dock-icon, .cd-dock .modal-head .close {
    width: 40px;
    height: 40px;
  }
  .cd-dock .modal-body { padding: 10px 11px; }
  .cd-dock-foot { padding: 0 11px 11px; }
  .cd-dock-actions .btn { min-height: 40px; font-size: 12.5px; }
  /* 手机打开房源详情或其他业务弹窗时，业务层必须高于底部客户卡，避免挡住主要内容。 */
  body.has-cd-dock .overlay:not(.is-float):not(.cd-dock-overlay) { z-index: 230; }
}
/* ★ 2026-10-21：客户详情顶部的标题行和资料时间现在是弹窗正文里的固定块。
   正文仍写死 766px 时，右栏「操作记录」会被推到视口下方；改成弹窗定高 + 正文 flex，
   让左右两栏按实际剩余高度分配，跟进记录自己滚，操作记录条始终留在弹窗底边。
   只作用于电脑端；手机端已有自己的整屏定高布局，一个字不动。 */
@media (min-width: 861px) {
  .modal.cd-modal {
    height: min(820px, calc(100vh - 80px));
    display: flex;
    flex-direction: column;
  }
  .modal.cd-modal > .modal-body {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }
  .cd-modal .modal-body > .page-head,
  .cd-modal .modal-body > .fact-bar,
  .cd-modal .modal-body > .small {
    flex: none;
  }
  .cd-modal .cd2 {
    flex: 1 1 auto;
    min-height: 0;
  }
  .cd-modal .cd2-left,
  .cd-modal .cd2-right {
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .cd-modal .cd2-left .cd-scroll,
  .cd-modal #colFollows {
    flex: 1 1 auto;
    height: auto;
    max-height: none;
    min-height: 0;
  }
}
/* 需求下面就地展开的匹配房源（关掉就没了，不留东西） */
.match-inline { margin-top: 10px; border-top: 1px dashed var(--line-2); padding-top: 10px; }
.detail-page {
  display: flex; flex-direction: column;
  height: calc(100vh - var(--topbar-h) - 72px);
  min-height: 520px;
}
.fact-bar {
  display: flex; flex-wrap: wrap; gap: 10px 34px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 20px; margin-bottom: 14px; box-shadow: var(--shadow-sm);
}
/* ★★★ 第 125 轮（他 2026-10-16）：「录入时间、最后跟进、累计跟进、备注版本……**改成折叠的**，
   折叠的那块你自己找地方放，**不要影响其他的**」——
   这一条**还在原来的位置**（还是"固定头"的一部分，矮屏滚到底时不许动），
   只是那五项默认收起来、只剩一行「资料时间 ▸」；收起来之后它只占一行高，
   **客户档案**（紧挨着它下面那块）自然顶上来，落在他说的"录入时间那个位置"。 */
.fact-bar .fact-items { display: flex; flex-wrap: wrap; gap: 10px 34px; }
.fact-bar.folded .fact-items { display: none; }
.fact-fold {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; cursor: pointer; padding: 2px 0;
  color: var(--ink-3); font: inherit; font-size: 14px;
}
.fact-fold:hover { color: var(--ink-1); }
.fact-caret { font-size: 12px; opacity: .8; }
/* ★★★ 第 126 轮（他 2026-10-16 的更正）：
   「**电脑版改回去，不用动，只动手机就可以了**」—— 上面那套折叠**只在手机上生效**：
   电脑端照旧把五项**平铺**出来、连那颗折叠按钮都不画（原来的样子一个字不动）。
   收起时的紧一点的内边距也只在手机那条媒体查询里（见下面 `.cd-modal` 那一段）。 */
@media (min-width: 861px) {
  .fact-bar .fact-fold { display: none; }
  .fact-bar .fact-items { display: flex !important; }
  /* ★ 第 126 轮续：电脑端**不画**「客户档案」那一行的小箭头（那边不接折叠） */
  .cd-modal .cd2-left .section-title .fold-caret { display: none; }
}
.fact-bar span { display: flex; align-items: baseline; gap: 8px; }
.fact-bar i { font-style: normal; font-size: 13.5px; color: var(--ink-4); }
.fact-bar b { font-size: 16.5px; font-weight: 650; }
.detail-cols {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: minmax(280px, 32%) minmax(300px, 36%) 1fr;
  gap: 14px;
}
.detail-col {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px; box-shadow: var(--shadow-sm);
}
.detail-col .col-body { flex: 1; min-height: 0; overflow: auto; }
.detail-col .section-title:first-child { margin-top: 0; }

.split-2 { display: grid; grid-template-columns: minmax(340px, 40%) 1fr; gap: 0; align-items: stretch; }
.split-left { border-right: 1px solid var(--line-2); padding: 18px 20px; background: #fcfdff; }
.split-right { padding: 18px 20px; min-width: 0; }
.section-title {
  display: flex; align-items: center; gap: 9px;
  font-size: 15px; font-weight: 650; color: var(--ink-2); margin: 0 0 12px;
}

.timeline { }
.tl-item { padding: 13px 0; border-bottom: 1px dashed var(--line-2); }
.tl-item:last-child { border-bottom: 0; }
.tl-meta { display: flex; align-items: center; gap: 9px; color: var(--ink-4); font-size: 13.5px; margin-bottom: 5px; }
.tl-meta .who2 { color: var(--ink-2); font-weight: 650; }
.tl-text { color: var(--ink); white-space: pre-wrap; word-break: break-word; font-size: 15.5px; }

/* ================================================================ 弹窗 */

.overlay {
  position: fixed; inset: 0; background: rgba(20, 24, 32, .42);
  display: flex; align-items: flex-start; justify-content: center; z-index: 200;
  /* ★★★ 第 124 轮续（他 2026-10-16：「手机房源详情页，点开，整个详情页靠上，
     把小区名称、房源编号、还有 ✕ 那行整体挡住了，看不见」）：
     弹窗这一层也要按安全区往下让 —— iPhone 上页面铺到状态栏底下（`viewport-fit=cover`），
     而弹窗是**贴着这一层顶部**摆的（`align-items:flex-start`），它的第一条就是「小区名+编号+✕」，
     正好压在状态栏/刘海底下 ⇒ 看得见上半截、点不着、甚至整条看不见。
     安卓的系统栏在 WebView 外面 ⇒ `--safe-top` 是 0，一个像素都不动。 */
  padding: calc(56px + var(--safe-top)) 16px calc(24px + var(--safe-bottom)); overflow: auto;
  backdrop-filter: blur(1px);
}
.modal {
  background: var(--card); border-radius: 14px; box-shadow: var(--shadow-lg);
  width: 620px; max-width: 100%; overflow: hidden;
  animation: pop .14s ease-out;
}
@keyframes pop { from { opacity: 0; transform: translateY(-6px) scale(.995); } to { opacity: 1; transform: none; } }
/* 拖动期间把全屏虚化摘掉：backdrop-filter 覆盖整个视口，每帧都要重算 —— 就是他说的
   "鼠标在前，窗口在后"。只影响拖动的那一下，松手恢复。 */
.overlay.is-dragging { backdrop-filter: none; }
.modal.wide { width: 860px; }
/* 悬浮面板（float）：整块 overlay 不吃鼠标、透明，面板钉在右上角 · 顶栏下面 */
.overlay.is-float {
  justify-content: flex-end; align-items: flex-start;
  padding: calc(var(--topbar-h) + 12px) 16px 24px;
  background: transparent; backdrop-filter: none;
}
.modal-head {
  padding: 17px 20px; border-bottom: 1px solid var(--line-2);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.modal-head h3 { margin: 0; font-size: 19px; font-weight: 650; }
.modal-head .close {
  margin-left: auto; border: 0; background: transparent; color: var(--ink-4);
  font-size: 26px; line-height: 1; padding: 0 6px; border-radius: 6px;
}
.modal-head .close:hover { background: var(--hover); color: var(--ink); }
.modal-body { padding: 20px; max-height: 68vh; overflow: auto; }

/* 作品详情弹窗封面（第 116 轮·组C）：固定 4:3 卡片容器，图用 cover 填满，
   overflow:hidden 保证不溢出弹窗；点封面直接播（video.js 的 #vpCover 绑了播放）。 */
.vp-cover {
  width: 168px; flex: none; aspect-ratio: 4 / 3; align-self: flex-start;
  border-radius: 6px; overflow: hidden; background: #eef0f3; cursor: pointer;
}
.vp-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 今日任务悬浮面板（第 23 轮定稿）。他这一轮的要求，逐条落在这：
   · 浮在所有页面之上、**和当前页面同时显示**、互不影响 → `.overlay.is-float{pointer-events:none}`
     + 面板自己 pointer-events:auto（面板不吃鼠标，底下的列表照常点）
   · 尺寸：宽 273 = 顶栏统计卡单张宽；高 489 = 「客源统计」卡高
   · **只能上下拖**（左右锁定）→ 见 ui.js 的 makeDraggable(overlay,{axis:'y'})
   · 列表**两行一条、无边框、无蓝底、无选中态、没有快捷键提示**
   必须写 .modal.rd-modal，不然被上面 .modal{width:620px} 盖掉（和老 .cd-modal 同一个坑） */
.overlay.is-float { pointer-events: none; background: transparent; backdrop-filter: none; }
.modal.rd-modal {
  pointer-events: auto;
  /* ★ 第 75 轮，他连着两句：
     ① 「今日任务里面的字体还是有点小，整体放大」→ 我把面板和字号一起放大了（340×560）；
     ② 「**今日任务窗口大小不要动，只增加内容放大**」→ 窗口尺寸**退回原来的 273×489**，
        只把里面的字号/行高留着放大（内容 16px、客户名 17px、日期 14.5px、按钮和页签也大一号）。
     ⚠️ 以后改这个面板：**尺寸和字号是两件事**，他只同意后者变大。 */
  width: min(520px, calc(100vw - 24px)); max-width: calc(100vw - 24px);
  height: min(489px, calc(100dvh - 140px));        /* 定高：列表靠它算"剩下的全给它" */
  margin-left: auto; margin-right: 0;              /* 右边界钉住，只向左加宽 */
  display: flex; flex-direction: column;
  border: 0;                                       /* 他要去掉边框 */
  box-shadow: 0 10px 28px rgba(20, 24, 32, .16);   /* 只留一点投影：不投影就浮不起来 */
  animation: none;                                 /* 浮层别弹一下，省得跟拖动打架 */
}
/* 头部/内边距保持紧凑（273px 宽，字号已经放大，别在这两处再吃地方） */
.rd-modal .modal-head {
  flex: none; border-bottom: 0; padding: 12px 12px 8px;
  gap: 8px; flex-wrap: nowrap;
}
.rd-modal .modal-head h3 {
  flex: 0 1 auto; min-width: 0; font-size: 16px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rd-modal .modal-head .close { flex: none; margin-left: 0; font-size: 21px; }
/* 搜索框和客户页共用 searchBox；这里只负责把它放在标题与 × 之间并吃满剩余宽度。 */
.rd-head-search { flex: 1 1 150px; min-width: 76px; }
.rd-head-search .search-wrap { width: 100% !important; }
.rd-modal .modal-body {
  flex: 1; min-height: 0; max-height: none; overflow: hidden;
  padding: 0 10px 10px; display: flex; flex-direction: column;
}
/* 顶部 tab 行：不是卡片，没有边框 */
.rd-top { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; flex: none; }
.rd-top .seg { padding: 3px; border-radius: 8px; background: #f4f5f8; }
/* ⚠️ 页签/按钮是**控件**不是内容 —— 面板只有 273px 宽，控件放大就会把文字挤没，
   所以这几行保持原尺寸（他要求的是"只增加内容放大"）。 */
.rd-top .seg button { padding: 0 8px; font-size: 12.5px; height: 26px; }
.rd-top .seg button.active { color: var(--ink); background: #fff; box-shadow: 0 1px 2px rgba(16, 24, 40, .08); }
.rd-top #btnPostAll { height: 26px; padding: 0 8px; font-size: 12px; }
/* 「只看某个客户」那条（第 75 轮补：从客户详情点「去今日任务看」会筛到一个客户） */
.rd-onlycust {
  flex: none; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 8px; padding: 7px 10px; border-radius: 9px;
  background: var(--primary-weak, rgba(37, 99, 235, .08)); color: var(--ink-2); font-size: 14px;
}
.rd-onlycust b { font-weight: 700; }

/* 列表：自己滚、外面不动 */
.rd-list { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain; }

/* 两行一条：第一行 日期 · 客户 · 逾期标记；第二行 备注（小字）+ 三个按钮。
   没有边框、没有蓝底、没有选中态 —— 他明确要去掉。 */
.rd-modal .rem-row {
  display: block; padding: 10px 7px; border: 0; border-bottom: 1px solid var(--line-2);
  background: none; cursor: pointer;
}
.rd-modal .rem-row:last-child { border-bottom: 0; }
.rd-modal .rem-row:hover { background: var(--hover); }
.rd-modal .rem-row.selected { background: none; box-shadow: none; }   /* 不用蓝底选中态 */
.rd-modal .rem-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }
/* 必须显式写 width:auto —— 上面 .rem-date{width:92px}/.rem-cust{width:160px} 是老的"整页表格行"
   尺寸，不覆盖的话窄面板里它们照样占 92/160，整行就会被撑出横向滚动条（踩过） */
/* ★ 第 75 轮：**这儿才是"内容"，放大的是它们**（日期 / 客户名 / 内容 / 逾期标记） */
.rd-modal .rem-date { width: auto; flex: none; font-size: 13.5px; color: var(--ink-4); }
.rd-modal .rem-cust { width: auto; min-width: 0; flex: 0 1 auto; font-weight: 700; font-size: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rd-modal .rem-over { width: auto; margin-left: auto; flex: none; }
.rd-modal .rem-over .badge { font-size: 12.5px; padding: 1px 7px; white-space: nowrap; }
.rd-modal .rem-line2 { display: flex; align-items: flex-end; gap: 6px; margin-top: 4px; }
.rd-modal .rem-text {
  flex: 1; min-width: 0; width: auto; font-size: 16px; line-height: 1.55; color: var(--ink-2);
  white-space: normal; overflow-wrap: anywhere; overflow: visible; text-overflow: clip;
}   /* width:auto + 覆盖老的 nowrap/ellipsis —— 备注要整段换行，不截断 */
.rd-modal .rem-acts { flex: none; display: flex; gap: 5px; white-space: nowrap; }
/* 三个按钮也是控件 → 保持原尺寸，把宽度让给左边那段内容 */
.rd-modal .rem-acts .btn { height: 24px; padding: 0 7px; font-size: 11.5px; }
/* 他明确说"蓝色的"要去掉 —— 「跟进」不再用主色实心，三个按钮统一中性 */
.rd-modal .rem-acts .btn.primary { background: #fff; color: var(--ink-2); border: 1px solid var(--line); }
.rd-modal .rem-acts .btn.primary:hover { background: var(--hover); color: var(--ink); }
.rd-modal .empty { padding: 18px 8px; }

/* ---- 手机端房源列表：卡片（第 26 轮，照他 index_backup.html 的房源卡）----
   桌面端仍是表格（.tbl-house 一行一套）；手机上表格藏掉、卡片整宽铺开 —— 不用左右滑。
   两块都由 JS 渲染，靠这里的媒体查询切显示，不在 resize 时重画。 */
.hcards { display: none; }
@media (max-width: 860px) {
  /* 第 69 轮：他「搜索框，我下滑的时候不要动，方便我后续重新进行搜索」。
     ★★ 第 93 轮第一版（他 2026-10-09）：把「搜索行 + 筛选行」**整块**沾在顶上 —— 但那条一直没生效
        （实测滚 900px 时 top=-586）。两条原因都得治：
        ① 装它的那张卡在手机端是 `overflow-x:auto`（= 滚动容器）→ 里面的 sticky 认它当滚动祖先，
           而它自己不竖着滚 → 谁都钉不住 → 见下面 `.card.houses-card{overflow:visible}` 那一段；
        ② 钉住之后**贴到哪儿**：顶栏（.topbar）自己也是 sticky 且 z-index 60 比它高，`top:0` 会被顶栏盖住；
           而手机端顶栏是 `height:auto`（标题 + 按钮换行，每页高度都不一样），**不是**那个写死的 66px。
           所以高度由 JS **量**出来写进 `--hrow-stick`（`views.js` 的 `量吸顶偏移()`），
           ⚠️ **只能量、不能算**（坑 #141 同款教训）；量不到时退回 0px。

     ★★ 第 93 轮第二版（他看完手机之后）：「搜索框和筛选都在最上层，**只留搜索框就行**，
        筛选的这些不要留在最上层，**筛选的可以跟着滑动**」→ 改成**只钉搜索行**。
        ⚠️ 这里有第 69 轮栽过的那个坑：**sticky 只能待在"它爹"的高度范围内** ——
        搜索行的爹是 `.hrow-top`，而那一层只有两行高 → 只钉搜索行的话，往下滑 100px 它就跟着走了 ✗。
        解法：手机端把 `.hrow-top` 这一层**用 `display:contents` 拆掉**（它自己不再生成盒子），
        于是搜索行的"爹"变成**那张卡片**（卡片很高、装着整个列表）→ 能一路钉到底 ✓，
        而筛选行照旧在正常流里、**跟着页面一起滚走** ✓。桌面端（>860px）一个字没动。 */
  .hrow-top { display: contents; }
  .hrow-search {
    position: sticky; top: var(--hrow-stick, 0px); z-index: 30;
    background: var(--card); padding-bottom: 6px;
    border-bottom: 1px solid var(--line);
    border-radius: var(--radius) var(--radius) 0 0;
    box-shadow: 0 2px 8px rgba(16, 24, 40, .06);
  }
    /* 上滑时搜索框和查询/重置/清筛选/添加房源整行都保留，不隐藏操作按钮。 */
  html[data-page="houses"][data-mobile-scrolled="1"] .hrow-search {
    padding-top: 6px;
    padding-bottom: 6px;
  }
  html[data-page="houses"][data-mobile-scrolled="1"] .hrow-search > .search-wrap {
    flex: 1 1 100%;
    width: 100%;
  }
  table.tbl-house { display: none; }
  /* 手机上「上次同步 / 本次 N 条在库 / 文件路径 / 要处理的重复房源」这几块太占地方 —— 藏掉，
     要看回电脑。桌面端照旧显示（他在电脑上要盯着同步状态）。 */
  .sync-card { display: none; }
  .hcards { display: flex; flex-direction: column; gap: 10px; }
  .hcard { background: var(--card); border: 1px solid var(--line); border-radius: 12px;
    padding: 12px 13px; box-shadow: var(--shadow-sm); cursor: pointer; }
  .hcard:active { background: var(--hover); }
  .hcard-head { display: flex; align-items: flex-start; gap: 8px; }
  /* ---- 第 67 轮（他第一版说「不行，户型、编号都看不见了」，这是他给的准确排布）----
       左上：小区名，下面一行编号 ／ 右上：图片 ／ 下面：房号·楼层·面积·户型·装修照原来排。
       第一版错在哪：把「图 + 内容」左右并排 → 下面那块 kv 只剩一半宽，2 列网格塞不下，
       户型、编号被挤掉 ✗。现在**图只占顶行右侧**，kv/报价/备注都是整卡宽 ✓。 */
  .hcard-top { display: flex; gap: 10px; align-items: flex-start; }
  .hcard-titlewrap { flex: 1; min-width: 0; }
  .hcard-code { margin-top: 2px; font-size: 12.5px; color: var(--ink-3); letter-spacing: .01em; }
  .hcard-thumb {
    position: relative; flex: none; width: 132px; height: 104px; border-radius: 9px;
    overflow: hidden; background: #f2f4f7; border: 1px dashed var(--line);
    display: flex; align-items: center; justify-content: center;
    color: var(--ink-5); font-size: 11.5px; text-decoration: none;
  }
  .hcard-thumb.has-img { border: 0; border-style: none; background: #eef1f5; }
  .hcard-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .hcard-thumb-n {
    position: absolute; right: 3px; bottom: 3px; background: rgba(0,0,0,.62); color: #fff;
    font-size: 10.5px; line-height: 1; padding: 2px 4px; border-radius: 6px;
  }
  .hcard-title { flex: 1; min-width: 0; font-size: 20px; font-weight: 700; line-height: 1.3; }
  /* 第 68 轮：他「小区名称可以放大一点」—— 17px → 20px；编号那行跟着提到 13px，免得头重脚轻 */
  .hcard-code { font-size: 13px; }
  /* 第 69 轮：他「小区名和编号有点近，编号稍微往下调一下，中间留一点空」→ 拉开到 7px */
  .hcard-code { margin-top: 7px; }
  .hcard-head .badge { flex: none; }
  /* r162：VR 和「在售」竖着排，把横向空间让给小区名；
     小区名 6 个字（如「万科翠湾中城 / 绿地国际花都」）就能在一行里完整显示。 */
  .hcard-badges {
    flex: none; display: flex; flex-direction: column;
    align-items: center; gap: 6px;
  }
  .hcard-badges .vr-chip,
  .hcard-badges .badge { flex: none; }
  /* 小区名加粗（他第 27 轮要求）—— 别跟着下面那次重做一起删掉 */
  .hcard-title { font-weight: 800; }
  /* 第 52 轮：手机卡片改成**每一项都有小标题、两列排**。
     他原话：「手机端的楼层 18/总高 换个地方，看着都和房号、户型一起了，都分不清了，标题也没有，
     手机端卡片重新做吧」—— 原来是一行没名字的「🏠房号 📐面积 户型 楼层/总高」，全糊在一起。
     现在：房号 / 楼层 / 面积 / 户型 / 装修 / 编号 各自一格、前面有小标题；
     字号**仍然和报价一样大**（第 27 轮他要求过「房号/面积/户型要和报价数字一样大一样粗」），
     靠"有名字 + 分组"分清，不靠缩小字。 */
  .hcard-kv { margin-top: 9px; display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; }
  .hcard-kv > div { min-width: 0; display: flex; align-items: baseline; gap: 5px; }
  .hcard-kv i { font-style: normal; flex: none; font-size: 11.5px; color: var(--ink-4); }
  .hcard-kv b { min-width: 0; font-size: 18px; font-weight: 700; letter-spacing: -.02em; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
  .hcard-prices { display: grid; grid-template-columns: repeat(auto-fit, minmax(78px, 1fr)); gap: 1px;
    margin-top: 10px; background: var(--line-2); border: 1px solid var(--line-2);
    border-radius: 9px; overflow: hidden; }
  .hp { background: var(--card); padding: 8px 9px; }
  .hp i { display: block; font-style: normal; font-size: 11.5px; color: var(--ink-4); margin-bottom: 2px; }
  .hp b { font-size: 18px; font-weight: 700; letter-spacing: -.02em; }
  .hp s { text-decoration: none; font-size: 11.5px; color: var(--ink-4); margin-left: 2px; }
  .hp.deal { background: #f2f8f4; }
  .hcard-remark { margin-top: 9px; font-size: 13px; color: var(--ink-3); line-height: 1.5;
    overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; }
  .hcard-foot { display: flex; align-items: baseline; gap: 8px; margin-top: 9px;
    padding-top: 8px; border-top: 1px solid var(--line-2); font-size: 12.5px; color: var(--ink-4); }
  .hcard-unit { margin-left: auto; text-align: right; }
  .hcard-date { margin-top: 7px; font-size: 13px; color: var(--ink-2); }
}

/* 共多少套房源：并到「房源库」标题这一行（第 33 轮他要求，别再单占一行） */
.house-count { font-size: 15px; font-weight: 400; color: var(--ink-3); margin-left: 10px; }
.house-count b { font-size: 20px; font-weight: 700; color: var(--primary); }

/* 「更多筛选」折叠区（第 33 轮）：只留小区在最上面，其余折起来省高度 ——
   展开后按 auto-fit 排，一行尽量多放几个、不留空白 */
.filter-more {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 10px 16px; align-items: center; border-top: 1px solid var(--line-2);
}
.filter-more .fgroup { min-width: 0; }
.filter-more .fgroup .input { flex: 1; min-width: 0; }
#hMoreBtn .ar { display: inline-block; transition: transform .15s; font-size: 12px; }
#hMoreBtn.open .ar { transform: rotate(180deg); }

/* 2026-10-22：筛选扩展区默认收起。
   电脑端区域/装修由 JS 搬进主筛选行；手机端保留原布局，原「户型」位置改为“筛选”，
   点开后显示区域、装修、居室、卫浴。 */
.house-extra-filters {
  display: none;
  align-items: center;
  gap: 12px 20px;
  flex-wrap: wrap;
  padding: 10px 20px;
  border-top: 1px solid var(--line-2);
}
.house-extra-filters.open { display: flex; }
.house-extra-filters .fgroup { min-width: 0; }
.mobile-extra-groups { display: contents; }
.room-bath-groups { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.hchoice-group { gap: 5px; }
.hchoice {
  height: 28px;
  padding: 0 9px;
  color: var(--ink-2);
  background: #f7f8fa;
  border: 1px solid var(--line);
  border-radius: 7px;
  font-size: 13px;
}
.hchoice[aria-pressed="true"] {
  color: #fff;
  background: var(--primary);
  border-color: var(--primary);
}
#hDistrict { width: 88px; }
#hDecoration { width: 98px; }
.house-extra-toggle {
  min-width: 104px;
  max-width: 100%;
}
.house-extra-toggle .ar {
  display: inline-block;
  margin-left: 3px;
  font-size: 11px;
}
.house-extra-toggle.active {
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 36%, var(--line));
  background: var(--primary-weak, rgba(37, 99, 235, .08));
}

/* ---- 房源详情：手机端换成单列大卡片（第 25 轮，照他的 index_backup.html 那张房源卡）----
   桌面端保持原来的两栏 grid（.hd-desk），手机上藏起来换成 .hd-card。
   原因：390px 宽时两栏每列只剩 ~170px，"房号/面积/单价/钥匙"挤成一条条，很难读。 */
.hd-card { display: none; }
.hd-card-facts, .hd-card-prices, .hd-card-diff { display: none; }

@media (max-width: 860px) {
  .hd-desk { display: none; }
  .hd-card { display: block; }
  /* 手机上面包屑导航就能换页，详情底部那个「关闭」按着还占地方 —— 藏掉（第 32 轮他提的） */
  #hdClose { display: none; }
  /* 手机上筛选区：一行就够（小区 + 查询 + 更多筛选），折叠区一列排开 */
  .filter-row { padding: 10px 12px; gap: 8px; }
  /* 客户页头部：标题 + 共 N 个客户 + 状态 + 新增 挤进一行（实测 390px 刚好放得下），
     省下来的高度全给下面的搜索框和列表（他说"搜索框也没上移"）。
     ⚠️ 必须写 `.page-head.cust-head`（两个类）—— 只写 `.cust-head h1` 会被**后面**那条
     同权重的 `.page-head h1{font-size:25px}` 盖掉（和 `.modal.cd-modal` 那个坑一模一样，踩过） */
  .page-head { gap: 4px 8px; margin-bottom: 10px; }
  .page-head.cust-head h1 { font-size: 20px; }
  .page-head.cust-head .ph-sub { font-size: 12.5px; white-space: nowrap; }
  .page-head.cust-head .ph-right { margin-left: auto; gap: 6px; }
  /* 2026-10-22：手机客户页标题改成上下两层；整块高度保持原来约 30px。 */
  .page-head.cust-head .cust-title {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0;
    min-height: 30px;
  }
  .page-head.cust-head .cust-title h1 { line-height: 1.05; }
  .page-head.cust-head .cust-title .ph-sub { line-height: 1.15; }

  /* r163：视频管理页头控件必须在**同一行**：
     我自己 / 全部（以及可见员工）＋ 绑定 / 管理 ＋ 立即抓取。
     标题仍可单独占上一行，但右侧这一排不换行。 */
  .page-head:has(#vdHead) .ph-right { width: 100%; margin-left: 0; flex-wrap: nowrap; }
  #vdHead { display: flex; align-items: center; gap: 4px; flex-wrap: nowrap; min-width: 0; width: 100%; }
  #vdHead #vdWho { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: nowrap; gap: 4px; margin: 0; }
  #vdHead #vdWho .seg-tab { flex: 0 0 auto; height: 30px; padding: 0 7px; font-size: 12px; border-radius: 8px; }
  #vdHead > .btn { flex: 0 0 auto; height: 30px; padding: 0 8px; font-size: 12px; white-space: nowrap; }
  .cust-head #cStatus { width: 112px; height: 32px; padding: 0 6px; font-size: 13px; }
  .cust-head #cNew { height: 32px; padding: 0 10px; font-size: 13px; }
  .card-head { padding: 10px 12px; }
  .filter-more { grid-template-columns: 1fr; gap: 8px; }
  .filter-more .fgroup { justify-content: space-between; }
  /* ★★ 第 112 轮（他的第 2 条）：「共 N 套房源（在售，本页 20 套 · 17:50 更新）」这一串
     手机上会**折成两行**（「更新」那一截被挤到下一行），太占面积。
     两条改法：① 那一串里去掉没信息的「在售」（状态本来就有「只看：…」徽章说一遍，见 views.js）；
     ② 字号收到 12.5px + `nowrap` —— 标题「房源库」＋这一串就能待在**同一行**里。 */
  .house-count { margin-left: 6px; font-size: 12.5px; white-space: nowrap; }
  .house-count b { font-size: 16px; }
  .hd-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }

  /* 房号 / 面积 / 户型：一行三格 */
  .hd-card-facts { display: grid; grid-template-columns: 1.15fr 1fr 1.25fr; gap: 1px;
    background: var(--line-2); border: 1px solid var(--line-2); border-radius: 10px; overflow: hidden; }
  .hd-card-facts > div { background: var(--card); padding: 9px 10px; }
  .hd-card-facts i { display: block; font-style: normal; font-size: 12px; color: var(--ink-4); margin-bottom: 3px; }
  .hd-card-facts b { font-size: 15px; font-weight: 650; word-break: break-all; }

  /* 价格四宫格 */
  .hd-card-prices { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: 10px;
    background: var(--line-2); border: 1px solid var(--line-2); border-radius: 10px; overflow: hidden; }
  .hd-p { background: var(--card); padding: 10px 12px; }
  .hd-p i { display: block; font-style: normal; font-size: 12px; color: var(--ink-4); margin-bottom: 2px; }
  .hd-p b { font-size: 21px; font-weight: 700; letter-spacing: -.02em; }
  .hd-p s { text-decoration: none; font-size: 12.5px; color: var(--ink-4); margin-left: 3px; }
  .hd-card-diff { display: block; margin-top: 7px; }

  /* 其余字段整行，不再两栏挤压 */
  .hd-card-rows { display: block; margin-top: 12px; border-top: 1px solid var(--line-2); }
  .hd-row { display: flex; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line-2); }
  .hd-row:last-child { border-bottom: 0; }
  .hd-row i { flex: none; width: 62px; font-style: normal; font-size: 13px; color: var(--ink-4); }
  .hd-row span { flex: 1; min-width: 0; font-size: 14.5px; line-height: 1.5; word-break: break-word; }
}
.modal-foot {
  padding: 15px 20px; border-top: 1px solid var(--line-2);
  display: flex; align-items: center; gap: 12px; background: #fcfcfd;
  /* ★★★ 第 83 轮（他 2026-10-08：「**手机端没有保存按钮**」）：
     手机上弹窗只有 374px 宽，而脚里那段"flex:1 的长文本"（分享链接是**一长串不能断行的字符**，
     光自己就 397px）**不肯收缩**，于是把后面两个按钮一路挤到 x=513 —— 弹窗外，被
     `.modal{overflow:hidden}` 裁掉：按钮整颗看不见、也点不到（我实测过：按钮 rect left=513/right=577，
     手机屏只有 390 宽；脚 scrollWidth 569 > clientWidth 374）。
     两手一起上：① 下面 `.sl-url` 允许收缩 + 打省略号；② 这里允许换行兜底
     （万一以后哪个弹窗脚下又塞了长内容，最多换行，不会再被裁掉）。 */
  flex-wrap: wrap;
}
/* r161：房源详情右上角那组按钮。电脑端保持一行，顺序是「已发视频 · 复制卡片图片 · 复制文字」；
   手机端的换行位置在下面 700px 那条规则里单独写。 */
.hd-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }

/* 弹窗脚下那段"占满剩下宽度"的长文本（分享链接 URL）：必须能收缩，否则会把按钮挤出弹窗 */
.modal-foot > .sl-url { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.field { margin-bottom: 16px; }
.field > label { display: block; font-size: 14px; color: var(--ink-3); margin-bottom: 6px; }
.field .hint { font-size: 13.5px; color: var(--ink-4); margin-top: 6px; }
.err-text { color: var(--danger); font-size: 14px; min-height: 20px; }

/* 添加房源：固定分组行，所有列的输入框等宽。桌面和手机共用同一套网格。 */
.ah-form { display: flex; flex-direction: column; gap: 10px; }
.ah-row { display: grid; gap: 10px; align-items: start; min-width: 0; }
.ah-row-1 { grid-template-columns: minmax(0, 1fr); }
.ah-row-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ah-row-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ah-field { min-width: 0; margin-bottom: 0 !important; }
.ah-field > label { white-space: normal; line-height: 1.35; }
.ah-field > .input,
.ah-field textarea.input { width: 100%; box-sizing: border-box; min-width: 0; }
.ah-field textarea.input { min-height: 68px; resize: vertical; line-height: 1.55; }

/* 户型三个选择框在“面积”这一行的右半边里三等分，不再每只 86px 把整行撑大。 */
.ah-layout-picker {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 5px; width: 100%; max-width: 240px; min-width: 0;
}
.ah-layout-part { display: flex; align-items: center; gap: 2px; min-width: 0; }
.ah-layout-part .input {
  flex: 1 1 0; width: 100%; min-width: 0;
  padding-left: 6px; padding-right: 2px; font-size: 13px;
}
.ah-layout-part > span { flex: none; font-size: 12px; color: var(--ink-3); }

@media (max-width: 700px) {
  .ah-form { gap: 8px; }
  .ah-row { gap: 8px; }
}

/* 日历 */
.cal-wrap { display: flex; gap: 14px; }
.cal { width: 306px; }
.cal-head { display: flex; align-items: center; gap: 7px; margin-bottom: 9px; }
.cal-head .m { font-weight: 650; font-size: 15px; }
.cal-head button { border: 1px solid var(--line); background: #fff; border-radius: 6px; width: 30px; height: 30px; line-height: 1; font-size: 15px; }
.cal-head button:hover { background: var(--hover); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.cal-grid .wd { text-align: center; font-size: 12.5px; color: var(--ink-4); padding: 5px 0; }
.cal-day {
  position: relative; height: 38px; border-radius: 7px; border: 0; background: transparent;
  font-size: 14px; color: var(--ink-2); display: flex; align-items: center; justify-content: center;
}
.cal-day:hover { background: var(--hover); }
.cal-day.out { color: var(--ink-5); }
.cal-day.today { box-shadow: inset 0 0 0 1px var(--primary-line); color: var(--primary); font-weight: 600; }
.cal-day.sel { background: var(--primary); color: #fff; font-weight: 600; }
.cal-day .dot {
  position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%);
  width: 5px; height: 5px; border-radius: 50%; background: var(--warning);
}
.cal-day.sel .dot { background: #fff; }
.cal-side { flex: 1; font-size: 14px; color: var(--ink-3); }
.cal-side .picked { font-size: 17px; font-weight: 650; color: var(--primary); margin-bottom: 7px; }

/* ================================================================ 提示 */

.toast-root { position: fixed; right: 20px; bottom: 20px; z-index: 300; display: flex; flex-direction: column; gap: 9px; }
.toast {
  background: #23272e; color: #fff; padding: 13px 17px; border-radius: 9px; font-size: 15px;
  box-shadow: var(--shadow); max-width: 420px; animation: tin .18s ease-out;
}
.toast.ok { background: #12603a; }
.toast.err { background: #7a2226; }
@keyframes tin { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.fatal {
  position: fixed; left: 20px; bottom: 20px; z-index: 400; max-width: 680px;
  background: #7a2226; color: #fff; padding: 14px 18px; border-radius: 8px; font-size: 14px;
  white-space: pre-wrap; box-shadow: var(--shadow);
}

.boot { padding: 64px; text-align: center; color: var(--ink-4); font-size: 15px; }

/* ================================================================ 手机端②离线记 */

/* 顶栏「出门同步」 */
.off-btn { height: 38px; font-size: 15px; }
.off-btn svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.off-btn:disabled { opacity: .6; }

/* 顶栏「待上传 N 条」：没上传的时候要显眼（方案 5.11 唯一的风险点的第 2 条对策） */
.pending-btn {
  height: 38px; font-size: 15px; font-weight: 650;
  background: var(--danger-weak); border-color: #f3c9ca; color: var(--danger);
}
.pending-btn:hover { background: #fadedf; }

/* 离线中的状态条：让他在外面一眼看出「现在用的是手机上那一份」 */
.offline-pill {
  font-size: 13.5px; padding: 4px 11px; border-radius: 13px;
  background: var(--warning-weak); color: var(--warning-ink); white-space: nowrap;
}
.offline-pill.off { background: #fde8e8; color: var(--danger); font-weight: 600; }

/* 回到网里自动上传成功后的提示（不依赖 toast，offline.js 不引 ui.js） */
.offline-toast {
  position: fixed; right: 20px; bottom: 20px; z-index: 320;
  background: #12603a; color: #fff; padding: 13px 17px; border-radius: 9px;
  font-size: 15px; max-width: 460px; box-shadow: var(--shadow); animation: tin .18s ease-out;
}
.offline-toast.err { background: #7a2226; }

.kbd-help { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 22px; font-size: 15px; }
.kbd-help kbd {
  display: inline-block; min-width: 24px; text-align: center;
  border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 4px;
  padding: 1px 6px; margin-right: 6px; font-size: 13px; background: #fbfcfd;
}

/* ================================================================ 手机（窄屏） */
@media (max-width: 860px) {
  html, body { font-size: 16px; }

  /* ★ 第 121 轮：手机上 `100vh` 在 iPhone 上比"看得见的那块"高一点点（配合 viewport-fit=cover 更明显），
     会多出一条没用的滚动。补一条 `dvh`（认得它的内核就用它，不认得的照旧用 vh）。 */
  .app-shell { flex-direction: column; height: auto; min-height: 100vh; min-height: 100dvh; overflow: visible; }
  /* ★★ 第 90 轮（他 2026-10-08）：「手机端上面的工作台、客户、房源、设置、工具，我只能看到
     工作台、客户、房源，**要往右滑才出现设置、工具，有时候滑动还滑动不了**，解决下。」
     原因就是这一段：手机端把侧栏横过来变成一条**横着滚的长条**（`overflow-x:auto`），
     而每个页签 `padding:9px 13px; white-space:nowrap` —— 品牌 + 5 个页签 + 退出登录/改密码
     加起来约 700px，390px 的手机只能露前三个，剩下两个得横滑（在竖向页面里横滑还很难滑）。
     改成**两行**：第一行 = 品牌 + 退出登录/改密码，第二行 = 5 个页签**均分整宽**（`flex:1 1 0`）——
     全部看得见、点得到，不用滑。⚠️ 电脑端（>860px）一个字都没动。 */
  .sidebar {
    width: 100%; flex-direction: row; align-items: center; gap: 8px;
    flex-wrap: wrap; padding: 8px 10px; overflow-x: visible;
    /* ★★★ 第 121 轮（他 2026-10-16：「苹果手机最上面就点不到」）：
       ★ 这一条才是"最上面" —— 手机端这一列（品牌行 ＋ 菜单行）就在**整页最顶上**，
         而 iPhone 上最顶上那一溜（状态栏/刘海）的点击会被系统吃掉：
         品牌行那两颗（退出登录 / 改密码）和菜单行就"看得见、点不着"。
         所以它也要按安全区往下让。安卓上 `--safe-top` 是 0 ⇒ **一个像素都不动**。 */
      padding-top: calc(8px + var(--safe-top));
      border-right: 0;
      border-bottom: 1px solid color-mix(in srgb, var(--side-line) 76%, transparent);
      box-shadow: 0 10px 28px rgba(0,0,0,.14);
  }
    .brand { padding: 5px 8px 5px 5px; margin: 0; border-color: transparent; background: transparent; box-shadow: none; }
    .brand-mark { width: 34px; height: 34px; font-size: 15px; border-radius: 10px; }
    .brand-mark.has-logo { width: 42px; height: 42px; padding: 2px; }
    .brand-text b { font-size: 16px; }
  .brand-text i { display: none; }
  /* order：品牌(0) → 退出登录/改密码(1) 在第一行；页签(2) 整宽换到第二行。
     ★★★ 第 113 轮 · 第 6 条（他 2026-10-12）：「手机端的菜单栏有点近，我切换的时候容易误点，
     你可以把工具去掉，其他平铺，距离正好，工具栏在手机上没用」——
     实测（390 宽，探针 `第113轮-总管\组①-手机端与待办\_探针-图片查看器.mjs`）：
     改前 **6 项挤在一行、相邻间距只有 4px、每项高 37px**（比"手指能点准"的 44px 小）；
     改后 **5 项平铺**（工具项这一档不画）＋ 间距 10px ＋ 触控高度 45px。
     ⚠️ 只动**手机端的渲染**：菜单定义 `TAB_ROUTES` / 能力 `TAB_CAP` / 红点口径一个字都没碰，
        电脑端（>860px）照旧 6 项、间距与尺寸不变。 */
    .nav {
      flex-direction: row; gap: 10px; width: 100%; order: 2; justify-content: space-between;
      padding: 5px; border-radius: 13px; background: rgba(255,255,255,.045);
      border: 1px solid rgba(255,255,255,.06);
    }
  .nav a {
    flex: 1 1 0; min-width: 0; justify-content: center;
      padding: 7px 2px; min-height: 49px; white-space: nowrap; font-size: 12px; font-weight: 650; gap: 3px;
      flex-direction: column; border-radius: 10px;
  }
    .nav a svg { width: 22px; height: 22px; padding: 3px; background: transparent; }
    .nav a:hover { transform: none; }
  .nav a.active::before { display: none; }
    .nav a.active { box-shadow: none; border-color: color-mix(in srgb, var(--primary) 40%, transparent); }
  /* 手机端不画「工具」这一项（他："工具栏在手机上没用"）。用的是**属性选择器 + display**，
     不是 `a.hidden` —— 所以「工具」这条路/权限/红点都没变，只是窄屏不画它。 */
  .nav a[data-tab="tools"] { display: none; }
    .side-foot {
      margin-left: auto; order: 1; border: 0; padding: 0; background: transparent;
      display: flex; align-items: center; gap: 3px;
    }
  .side-note { display: none; }
    .side-foot .btn { width: auto; height: 30px; padding: 0 7px; font-size: 12px; }

  .main { overflow: visible; }
  /* ★★★ 第 121 轮（他 2026-10-16：「苹果手机最上面就点不到」）：
     这一条（顶部栏）是 `position:sticky; top:0`，它在 iPhone 上会贴在**最顶上**，
     而最顶上那一溜（状态栏/刘海）的点击是被系统吃掉的 ⇒ 里面那颗按钮"看得见点不着"。
     按安全区往下让；安卓上 `--safe-top` 是 0，**一个像素都不动**。 */
  .topbar { height: auto; flex-wrap: wrap; gap: 9px; padding: 11px; padding-top: calc(11px + var(--safe-top)); position: sticky; top: 0; z-index: 60; }
  .topbar-right { width: 100%; margin-left: 0; flex-wrap: wrap; gap: 9px; }
  .topbar-right .btn.task-btn { flex: 1; justify-content: center; }
  .topbar-right .btn.off-btn { flex: 1; justify-content: center; }
  .topbar-right .btn.pending-btn { flex: 1 0 100%; justify-content: center; }
  .offline-pill { font-size: 12.5px; }
  /* 手机客户 / 房源列表：顶栏只留「今日任务」一行。
     主题、同步、用户名、字号和离线 pill 都收起来，把高度让给列表。 */
  html[data-page="houses"] .topbar,
  html[data-page="customers"] .topbar,
  html[data-page="customer"] .topbar {
    gap: 0;
    padding: 7px 11px;
    padding-top: calc(7px + var(--safe-top));
  }
  html[data-page="houses"] .topbar-title,
  html[data-page="customers"] .topbar-title,
  html[data-page="customer"] .topbar-title,
  html[data-page="houses"] #themeSwitch,
  html[data-page="customers"] #themeSwitch,
  html[data-page="customer"] #themeSwitch,
  html[data-page="houses"] #btnPack,
  html[data-page="customers"] #btnPack,
  html[data-page="customer"] #btnPack,
  html[data-page="houses"] #btnHouseSync,
  html[data-page="customers"] #btnHouseSync,
  html[data-page="customer"] #btnHouseSync,
  html[data-page="houses"] #zoomGroup,
  html[data-page="customers"] #zoomGroup,
  html[data-page="customer"] #zoomGroup,
  html[data-page="houses"] #offlinePill,
  html[data-page="customers"] #offlinePill,
  html[data-page="customer"] #offlinePill,
  html[data-page="houses"] #btnPending,
  html[data-page="customers"] #btnPending,
  html[data-page="customer"] #btnPending,
  html[data-page="houses"] #userName,
  html[data-page="customers"] #userName,
  html[data-page="customer"] #userName {
    display: none !important;
  }
  html[data-page="houses"] .topbar-right,
  html[data-page="customers"] .topbar-right,
  html[data-page="customer"] .topbar-right {
    width: 100%;
    margin: 0;
    gap: 0;
  }
  html[data-page="houses"] #btnTasks,
  html[data-page="customers"] #btnTasks,
  html[data-page="customer"] #btnTasks {
    width: 100%;
    min-height: 36px;
  }

  .view { padding: 14px 11px 34px; }
  .page-head h1 { font-size: 25px; }
  .page-head .ph-sub { padding-bottom: 3px; font-size: 14px; }

  .card { overflow-x: auto; }
  /* ★★ 第 93 轮：**房源那一张卡不能是滚动容器**（其余卡一律照旧，一个字没动）。
     为什么：能滚的盒子里面的 `position:sticky` 会认这个盒子当"滚动祖先"，
     可它自己不竖着滚 → `.hrow-top` 谁都钉不住 —— 第 69 轮那条吸顶就是这么白做的（实测 top=-586）。
     为什么敢只在这一页放成 visible：手机上房源列表本来就是卡片（`table.tbl-house` 上面已 display:none）、
     筛选行是两列 grid 自己会换行 → **这一页根本不需要横滑**，所以放成 visible 没有副作用。 */
  .card.houses-card { overflow: visible; }
  .card-body { padding: 14px; }
  .card-head { padding: 12px 14px; }
  .card-head h2 { font-size: 17px; }
  .card-head .right { margin-left: 0; width: 100%; }
  .stat-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .stat { padding: 13px 14px; }
  .stat .value { font-size: 30px; }
  .stats-2col { grid-template-columns: 1fr; }
  .bar-row { grid-template-columns: 88px 1fr 54px; font-size: 13px; }

  .input, textarea.input, select.input { font-size: 16px; }

  .detail-head .name { font-size: 21px; }
  .detail-head .meta { font-size: 14px; gap: 10px; }
  /* 手机上：详情页不锁高度，三栏竖着堆（手机屏幕放不下三栏，允许滑动） */
  .detail-page { height: auto; min-height: 0; }
  .detail-cols { grid-template-columns: 1fr; }
  .detail-col .col-body { overflow: visible; }
  .split-2 { grid-template-columns: 1fr; }
  .split-right { order: 1; }
  .split-left { order: 2; border-right: 0; border-top: 1px solid var(--line-2); }

  .rem-row { flex-wrap: wrap; gap: 5px 9px; padding: 12px 14px; }
  .rem-date { width: auto; }
  .rem-cust { width: auto; }
  .rem-text { width: 100%; white-space: normal; order: 5; }
  .rem-acts { margin-left: auto; }

  /* ★ 第 124 轮续：手机上弹窗原本贴顶 10px —— 手机端要再加上安全区（见上面 `.overlay` 那段注释） */
  .overlay { padding: calc(10px + var(--safe-top)) 8px calc(10px + var(--safe-bottom)); align-items: flex-start; }
  .modal, .modal.wide { width: 100%; }
  /* ★ 第 124 轮续：手机弹窗的正文高度上限也要把**下安全区**扣掉 ——
     不然弹窗底边会伸进"小白条"那一溜（实测 390x844 + 下 34 时，详情弹窗底边落在 830，
     而看得见的底边是 810）⇒ 最后一行字会被"小白条"盖住、得再滚一下才看得见。 */
  .modal-body { max-height: calc(76vh - var(--safe-bottom)); }
  /* ★★★ 第 112 轮 · 第 15 条 ＋ 第 8 条（他 2026-10-11 的原话）：
     「手机端的详情页不要像电脑端一样，鼠标拖着整个页面哪里都能滑，**要固定**，
      **详情页里面可以上下滑**。」＋「视频管理里有要左右滑的页面（太长、超出手机宽度）→ 改成不用左右滑」。
     ★★ 他后来又定了一条（2026-10-11，总管转达）：「**跟原来弹窗一样大小**，你自己修改，你自己优化」
        ⇒ 我第一版做的"整屏高 ＋ 标题栏/底栏 flex 固定"**撤掉了**（弹窗尺寸 / 滚动方式**完全照原来**
          —— 就是上面那两行 `.modal{width:100%}` ＋ `.modal-body{max-height:76vh}`）；
          但第 15/8 条的**两条硬口径留着**（它们跟"弹窗多大"无关）：
       ① **不许横向溢出**：`.modal-body` 内容区 `overflow-x:hidden`
          —— 超宽的东西（表格 / 长标题 / 长串）改**卡片化 / 换行 / 按屏宽自适应**
          （视频管理那几屏走 `video.js` 的手机端卡片 `.vd-card`），**不许把页面撑出横向滚动条**；
       ② **滑到底别带动整页**：`overscroll-behavior:contain`（单指滑到底就停在框里，不"传给"外面那层）。
     ⚠️ **普通小弹窗（确认框 / 日期框）一个字没动**（它们走 `.modal` 不是 `.modal.wide`）；
        `.modal.cd-modal`（客户详情）自己有更靠后的规则，也不受影响。*/
  .modal.wide > .modal-body {
    overflow-x: hidden;
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  }
  .cal-wrap { flex-direction: column; }
  .cal { width: 100%; }
  .kbd-help { grid-template-columns: 1fr; }

  /* ---- 客户详情窗口：手机上「跟进记录」这一栏要能单指滑动（第 19 轮他提的） ----
     抓到的真 bug：.cd2 是 `minmax(320px,44%) 1fr` 的两栏网格，只在桌面写死了宽度。
     传到手机上（390px）：第一栏咬住 320px，第二栏被压成 **0 宽** ——
     跟进记录整栏既看不见也点不着（截图里只剩右边缘一个「跟进记录 (2」的竖条）。
     根因是第 11 轮详情从「整页」改成「独立窗口 .cd-modal」时，
     旧的手机端堆叠规则（.detail-cols）跟着作废了，新的 .cd2 一直没补手机端规则。
     手机上的做法：上下堆叠 —— 客户档案矮一点、自己滚；跟进记录占满剩下的高度、自己滚；
     **窗口本身不滚**（modal-body 不滚动），所以单指在跟进记录上滑，只动这一栏。 */
  .modal.cd-modal {
    width: 96vw;
    /* 手机上给「定高」而不是「最大高」：下面那堆 flex（55% 给跟进记录）要有确定的父高度才算得准，
       顺带好处是切换客户时窗口高度不跳。 */
    /* ★ 第 124 轮续：这两个值原来是"视口高 − 上下各 10px"（对齐上面那条 padding）——
       现在 padding 里加了安全区，高度也要跟着减，否则弹窗会比看得见的区域高、
       底部那一截（含里面的滚动条）会被推到屏幕外。 */
    height: calc(100vh - 20px - var(--safe-top) - var(--safe-bottom));
    height: calc(100dvh - 20px - var(--safe-top) - var(--safe-bottom));
    max-height: calc(100vh - 20px - var(--safe-top) - var(--safe-bottom));
    max-height: calc(100dvh - 20px - var(--safe-top) - var(--safe-bottom));
    display: flex; flex-direction: column;
  }
  .cd-modal .modal-head { flex: none; }
  .cd-modal .modal-body {
    flex: 1; min-height: 0; max-height: none; overflow: hidden;
    padding: 12px 12px 14px; display: flex; flex-direction: column;
  }
  /* 顶部这些是固定内容，别被 flex 压扁 */
  .cd-modal .modal-body > .page-head,
  .cd-modal .modal-body > .fact-bar,
  .cd-modal .modal-body > .cd2 + .small { flex: none; }
  /* 手机上这一头挤了 5 个按钮 + 姓名 + 状态 + 编号电话，不收紧的话能吃掉 250px —— 
     那些高度本来都该给「跟进记录」。收紧后按钮两行放得下，高度省下来给下面那一栏。 */
  .cd-modal .page-head { gap: 8px 10px; margin-bottom: 10px; }
  .cd-modal .page-head h1 { font-size: 21px; }
  .cd-modal .page-head .ph-sub { font-size: 13.5px; line-height: 1.7; }
  .cd-modal .page-head .ph-right { margin-left: 0; width: 100%; gap: 8px; }
  .cd-modal .page-head .ph-right .btn { height: 33px; padding: 0 11px; font-size: 13.5px; }
  .cd-modal .page-head .ph-right .btn kbd { display: none; }   /* 手机上按不到实体 Enter，留着只占地方 */
  /* 客户详情紧凑头：姓名 + 状态同行，编号 + 电话同行，四个主按钮同行。 */
  .cd-modal .page-head.cd-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 7px;
    padding: 12px;
    margin-bottom: 9px;
  }
  .cd-modal .cd-identity {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: nowrap;
    min-width: 0;
  }
  .cd-modal .cd-identity h1 {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 22px;
    line-height: 1.2;
  }
  .cd-modal .cd-contact {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    font-size: 14px;
    white-space: nowrap;
  }
  .cd-modal .cd-contact::-webkit-scrollbar { display: none; }
  .cd-modal .cd-actions {
    display: flex;
    align-items: center;
    gap: 5px;
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .cd-modal .cd-actions::-webkit-scrollbar { display: none; }
  .cd-modal .cd-actions .btn {
    flex: 1 1 0;
    min-width: 0;
    height: 34px;
    padding: 0 6px;
    font-size: 12.5px;
    white-space: nowrap;
  }
  /* 仅当跟进记录多到需要滚动时，打开详情就收起资料区，把高度让给跟进记录。
     类名只由 views.js 按内容量一次性设置，滑动过程中不切换，避免高度跳变造成闪屏。 */
  .cd-modal.cd-compact .fact-bar,
  .cd-modal.cd-compact .cd2-left,
  .cd-modal.cd-compact .cd-actions {
    display: none !important;
  }
  .cd-modal.cd-compact .page-head.cd-head {
    margin-bottom: 7px;
    padding-bottom: 10px;
  }
  .cd-modal .fact-bar {
    display: grid; grid-template-columns: 1fr 1fr; gap: 4px 12px;
    padding: 9px 12px; margin-bottom: 10px;
  }
  /* 收起时更省地方（只在手机这一档；电脑端那条媒体查询里把整块还原了） */
  .cd-modal .fact-bar.folded { display: block; padding: 6px 12px; }
  .cd-modal .fact-bar b { font-size: 14.5px; }

  /* ================================================================
     ★★★ 第 126 轮（他 2026-10-16 的原话，逐句落在这儿）：
       「手机的客户档案，我希望是**展开的**，不是关闭的，**可以挪到资料时间那个地方去**，
        资料时间，**放在客户档案的下面**，**只有跟进记录是滑动的**，
        **客户档案放上面不滑动**」
     ⇒ 手机上这三块的顺序改成：**客户档案 → 资料时间 → 跟进记录**；
        客户档案**整块展开、自己不滚**；只有跟进记录那一栏滚。
     ⚠️ 全是手机这一档的规则 —— **电脑端一个字不动**（那边还是：资料时间平铺在上面、
        客户档案在左栏、跟进记录在右栏，两栏各滚各的）。 */
  /* ① 拆掉两栏壳：让"客户档案 / 资料时间 / 跟进记录"三块能按 order 重排 */
  .cd-modal .cd2, .cd-modal .cd2-left, .cd-modal .cd2-right { display: contents; }
  /* ② 排序：档案(1) → 资料时间(2) → 跟进(3) → 操作记录(4) → 提醒任务(5) */
  .cd-modal .cd2-left .section-title,
  .cd-modal .cd2-left .cd-scroll { order: 1; }
  .cd-modal .fact-bar { order: 2; }
  .cd-modal .cd2-right .section-title,
  .cd-modal .cd2-right .cd-scroll { order: 3; }
  .cd-modal .cd-ops-bar { order: 4; }
  .cd-modal .modal-body > .small { order: 5; }
  /* ③ 客户档案：整块展开、**不滚**（他要的就是这个）。
        给它一个"卡片"的样子（原来那层灰底是 `.cd2-left` 的，拆壳之后没了）。
        ⚠️ 只兜一个很宽松的上限（55%）：正常长度的档案**完全展开、不出滚动条**；
           真遇到把屏幕占满的超长备注，才在它自己那块里滚一下 —— 不然跟进记录会被挤成 0 高。 */
  .cd-modal .cd2-left .cd-scroll {
    /* ⚠️ `flex: 0 0 auto` 必须有：拆壳之后它是 `.modal-body` 这个纵向 flex 的项，
       不写就会被"跟进记录那个 flex:1"挤扁（实测被压到 **55px 高、还得滚** —— 那正是他要改掉的毛病）。 */
    flex: 0 0 auto;
    height: auto; max-height: 55%; overflow-y: auto;
    background: #fcfdff; border: 1px solid var(--line-2); border-radius: var(--radius-sm);
    padding: 10px 12px; margin-bottom: 10px;
  }
  /* ④ **只有跟进记录滚**：占满剩下的高度、自己滚 */
  .cd-modal .cd2-right .cd-scroll { height: auto; max-height: none; flex: 1 1 auto; min-height: 140px; overflow-y: auto; }
  /* ⑤ 「客户档案」这一行也是同款折叠条（他："按照资料时间一样改，点开展示、再点开关闭，保持不滑动"）
        —— 收起时只留那一行；展开时是上面 ③ 那个"整块展开、不滚"的样子。 */
  .cd-modal .cd2-left .section-title { cursor: pointer; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
  .cd-modal .cd2-left .section-title .fold-caret { font-size: 12px; opacity: .8; }
  .cd-modal .cd2-left.folded .cd-scroll { display: none; }
  .cd-modal .cd2-left.folded .section-title { margin-bottom: 10px; }
  /* ⑥ （第 127 轮：他"把历史版本去掉，有点多余" ⇒ 那颗按钮和它整行的样式都撤了，
        `#btnVerHist` 在界面上已经不存在） */

  /* ================================================================
     ★★★ 第 112 轮 · 第 3 条：手机端「设置 / 权限与分享」页的导航重排
     （他的原话四条，逐条落在这儿；`.ac-head` 是 access.js 给权限页那行标题加的类）
       ① 「权限与分享」下面那段说明（给谁看、看哪些）**去掉**
          → 文案那半在 `access.js` 的 paintAccess（`pageHead` 不再传 sub），这里不用管；
       ② `＋ 新建分享链接` 和「返回」**往上提、跟「权限与分享」同行**
          → `.page-head.ac-head{flex-wrap:nowrap}` + 标题/按钮都不换行；
       ③ 「设置」「权限与分享」「后台」**字体大一点、均匀排在下一行**
          → `.seg-tabs.set-menu` 三个按钮 `flex:1 1 0` 均分整宽、字号 16px；
       ④ 再下面那几个导航按钮（分享链接 / 访客 / 看房申请 / 员工账号 / 底价审核 / 公客池 / 操作日志）
          **排列整齐一点** → 手机上也保持一行，横向滑动，不折成多行。
     ⚠️ 只是版式，路由名、按钮文字、点击行为一个都没动（测试按 `#setMenu .seg-tab` /
        `#acTabs .seg-tab` 的文字和数量取，不受影响）。 ================================================ */
  .page-head.ac-head { flex-wrap: nowrap; gap: 8px; align-items: center; margin-bottom: 10px; }
  .page-head.ac-head h1 { font-size: 21px; white-space: nowrap; }
  .page-head.ac-head .ph-right { margin-left: auto; flex-wrap: nowrap; gap: 6px; }
  .page-head.ac-head .ph-right .btn { height: 32px; padding: 0 10px; font-size: 13px; white-space: nowrap; }

  .seg-tabs.set-menu { gap: 8px; margin-bottom: 12px; }
  .seg-tabs.set-menu .seg-tab { flex: 1 1 0; min-width: 0; font-size: 16px; font-weight: 600; padding: 10px 4px; }

  #acTabs { display: flex; flex-wrap: nowrap; gap: 6px; margin-bottom: 12px; overflow-x: auto; scrollbar-width: none; }
  #acTabs::-webkit-scrollbar { display: none; }
  #acTabs .seg-tab { flex: 0 0 auto; width: auto; font-size: 13px; padding: 8px 10px; white-space: nowrap; }
  #acTabs .seg-tab i { font-size: 11.5px; padding: 0 5px; margin-left: 2px; }

  /* ---- 今日任务面板：手机上整屏宽、锚在右上角（遮罩一样不吃鼠标） ---- */
  /* ★ 第 124 轮续：悬浮面板（今日任务那种）钉在右上角 —— 顶栏下面，底部让它别压住小白条 */
  .overlay.is-float { padding: calc(var(--topbar-h) + 10px + var(--safe-top)) 10px calc(12px + var(--safe-bottom)); }
  .modal.rd-modal {
    width: 100%; max-width: 100%;
    height: auto; max-height: calc(100dvh - var(--topbar-h) - 22px);
    margin: 0; display: flex; flex-direction: column;
  }
  .rd-modal .modal-head { flex: none; }
  .rd-modal .modal-body {
    flex: 1; min-height: 0; max-height: none; overflow: hidden;
    padding: 0 12px 12px;
  }
  /* 手机上今日任务：窗口本来就是整屏宽，所以**内容**可以放得更大；
     控件（页签/按钮）仍保持原尺寸 —— 跟电脑端一个道理。 */
  .rd-top .seg button { font-size: 13.5px; height: 30px; }
  .rd-modal .rem-date { font-size: 14.5px; }
  .rd-modal .rem-cust { font-size: 17px; }
  .rd-modal .rem-text { font-size: 17px; line-height: 1.6; }
  .rd-modal .rem-acts .btn { height: 28px; padding: 0 10px; font-size: 12.5px; }
  .rd-modal .rem-line2 { display: flex; flex-direction: column; align-items: stretch; gap: 7px; }
  .rd-modal .rem-text { width: 100%; }
  .rd-modal .rem-acts { width: 100%; justify-content: flex-end; }

  .cd2 {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column;
  }
  /* 档案：内容多高就多高（封顶 20vh），剩下的全给跟进记录 —— 用 flex 而不是固定行高，
     这样屏幕矮的时候两块一起让位，不会把跟进记录挤成 0 或者被裁掉。
     右栏给 flex-basis 55% + 不许压缩：跟进记录是重点，谁也别想把它挤没；
     左栏可压缩（内容超出就在它自己的框里滚）。 */
  .cd2-left {
    flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column;
    border-right: 0; border-bottom: 1px solid var(--line-2); padding: 10px 12px 12px;
  }
  .cd2-left .cd-scroll { flex: 1 1 auto; height: auto; min-height: 0; max-height: 20vh; }
  .cd2-right { flex: 1 0 55%; padding: 10px 12px 0; min-height: 0; display: flex; flex-direction: column; }
  .cd2-right .cd-scroll { flex: 1 1 auto; min-height: 0; height: auto; max-height: none; }

  /* 滑到头之后不许把滚动"传给"外面那层 —— 单指滑动就只动这一块 */
  .cd-scroll { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

  .pager { flex-wrap: wrap; }

  table.tbl th, table.tbl td { padding: 9px 10px; font-size: 14px; }
  .col-remark { display: none; }
  .col-house-extra { display: none; }
  .col-cust-extra { display: none; }
}

/* 矮屏手机（老款 360×640 / 320×568 这种）：
   ⚠️ **第 75 轮改过**。原来这里是把「整窗」改成可滚（`height:auto` + `modal-body{overflow-y:auto}`），
   代价是顶部「客户名称…备注版本」也跟着滑走 —— 他这次明确要求那一段**固定住**。
   现在矮屏也只是把两栏的高度放宽、**让下面那两块自己滚**（规则在文件末尾「第 75 轮」那一段，
   晚出现的同权重规则会覆盖这里的旧值）。 */

/* ==================================================================
   第 38 / 39 轮：分享门槛页、权限管理页、勾选器
   全部自带样式，不依赖上面任何一块 —— 这样以后改房源/客户的样式碰不到这里。
   ================================================================== */

/* ---- 分享门槛页（/s/<token> 的第一屏：客户看到的就是它） ---- */
.sg-card { max-width: 420px; }
.sg-ico { font-size: 40px; line-height: 1; margin-bottom: 10px; }
.sg-hint { color: var(--ink-3); font-size: 13.5px; margin-top: 8px; }
/* ★ 第 78 轮（他报的）：「登录界面，输入手机号框太小，看不见，你可以分成两行，
   上面行是输入框，下面是登录框」—— 原来是 flex 横排，按钮文字一长就把输入框挤成一条缝。
   现在**竖着排**：输入框独占一行（整宽 46px 高），按钮在下面同样整宽。 */
.sg-form { display: flex; flex-direction: column; gap: 10px; margin-top: 18px; }
.sg-input { width: 100%; height: 46px; font-size: 17px; text-align: center; letter-spacing: .06em; }
.sg-go { width: 100%; height: 46px; font-size: 16px; white-space: nowrap; }
.sg-err { color: var(--danger); font-size: 13.5px; min-height: 20px; margin-top: 8px; }
.sg-foot { color: var(--ink-4); font-size: 12.5px; margin-top: 14px; }

/* ---- 分享视图顶部的横幅 ---- */
.share-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 18px; background: var(--primary-weak); color: var(--primary);
  border-bottom: 1px solid var(--primary-line); font-size: 14px;
}
.share-bar .sb-tag {
  background: var(--primary); color: #fff; border-radius: 6px;
  padding: 1px 8px; font-size: 12.5px; font-weight: 600;
}
.share-bar .sb-sub { color: var(--ink-3); font-size: 13px; }

/* ---- 权限页：分段页签 ---- */
.seg-tabs { display: flex; gap: 6px; margin-bottom: 16px; flex-wrap: wrap; }
.seg-tab {
  border: 1px solid var(--line-2); background: #fff; color: var(--ink-2);
  border-radius: 10px; padding: 8px 16px; font-size: 14.5px; cursor: pointer;
}
.seg-tab:hover { border-color: var(--primary-line); color: var(--primary); }
.seg-tab.on { background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 600; }
.seg-tab i {
  font-style: normal; background: rgba(0,0,0,.08); border-radius: 8px;
  padding: 0 6px; margin-left: 4px; font-size: 12.5px;
}
.seg-tab.on i { background: rgba(255,255,255,.25); }

/* ---- 权限页：一行一条 ---- */
.ac-list { display: flex; flex-direction: column; gap: 10px; }
.ac-row {
  display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap;
  background: #fff; border: 1px solid var(--line-2); border-radius: 12px; padding: 14px 16px;
}
.ac-row.off { opacity: .55; }
.ac-main { flex: 1; min-width: 240px; }
.ac-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.ac-meta {
  display: flex; gap: 14px; flex-wrap: wrap;
  color: var(--ink-3); font-size: 13px; margin-bottom: 6px;
}
.ac-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.ac-btns { display: flex; gap: 6px; flex-wrap: wrap; }
.ac-h2 { margin: 0 0 10px; font-size: 17px; }
.chip.ghost { background: transparent; color: var(--ink-4); border-style: dashed; }

/* ---- 勾选器（建链接 / 改员工权限都用它） ---- */
.sl-sec { border-top: 1px solid var(--line-2); margin-top: 16px; padding-top: 14px; }
.sl-sec-h { font-weight: 650; font-size: 15px; margin-bottom: 10px; }

/* 权限编辑 · 02 章节分屏：左侧只做导航，右侧一次只显示一个设置章节。 */
.pv-editor-intro {
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
  padding: 9px 11px; margin-bottom: 10px;
  border: 1px solid var(--primary-line); border-radius: 9px;
  background: var(--primary-weak); color: var(--primary); font-size: 13px;
}
.pv-editor-intro b { font-size: 13.5px; }
.pv-editor-intro span { color: var(--ink-2); }
.pv-template-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin: -2px 0 10px; padding: 2px 1px;
}
.pv-template-row > span { color: var(--ink-3); font-size: 12px; margin-right: 2px; }
.pv-template {
  min-height: 30px; padding: 0 10px; border: 1px solid var(--line);
  border-radius: 7px; background: var(--card); color: var(--ink-2);
  font-size: 12px; font-weight: 600;
}
.pv-template:hover { border-color: var(--primary-line); color: var(--primary); }
.pv-template.on { background: var(--primary-weak); border-color: var(--primary-line); color: var(--primary); }
.pv-editor-layout {
  display: grid; grid-template-columns: 205px minmax(0, 1fr);
  min-height: 430px; border: 1px solid var(--line); border-radius: 13px; overflow: hidden;
}
.pv-editor-nav {
  padding: 11px; background: color-mix(in srgb, var(--card) 68%, var(--primary-weak));
  border-right: 1px solid var(--line);
}
.pv-nav-cap {
  padding: 5px 8px 9px; color: var(--ink-4);
  font-size: 11px; font-weight: 700; letter-spacing: .12em;
}
.pv-step {
  width: 100%; min-height: 48px; display: grid; grid-template-columns: minmax(0, 1fr);
  align-items: center; gap: 3px; padding: 9px 11px; margin-bottom: 5px;
  border: 1px solid transparent; border-radius: 9px; background: transparent;
  color: var(--ink-2); text-align: left;
}
.pv-step > span {
  display: block; min-width: 0; font-size: 14px; font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pv-step:hover { background: var(--hover); border-color: var(--line); }
.pv-step.on {
  background: var(--primary); border-color: var(--primary); color: #fff;
  box-shadow: 0 6px 16px color-mix(in srgb, var(--primary) 20%, transparent);
}
.pv-editor-main { min-width: 0; padding: 17px 19px; background: var(--card); }
.pv-pane { max-height: 430px; overflow-y: auto; overscroll-behavior: contain; padding-right: 7px; }
.pv-pane-head { padding-bottom: 12px; margin-bottom: 13px; border-bottom: 1px solid var(--line-2); }
.pv-pane-head h3 { margin: 0; font-size: 18px; }
.pv-pane-head p { margin: 4px 0 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.65; }
.pv-status-row { display: flex; flex-wrap: wrap; gap: 8px 18px; padding: 2px 0 13px; }
.pv-region-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.pv-region-option {
  display: flex; align-items: center; gap: 10px; min-height: 66px; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--card); cursor: pointer;
}
.pv-region-option:has(input:checked) {
  border-color: var(--primary-line);
  background: color-mix(in srgb, var(--primary-weak) 76%, var(--card));
  box-shadow: inset 3px 0 0 var(--primary);
}
.pv-region-option input { margin: 0; accent-color: var(--primary); }
.pv-region-option span { display: flex; flex-direction: column; gap: 2px; }
.pv-region-option b { font-size: 14px; }
.pv-region-option small { color: var(--ink-3); font-size: 11.5px; }
.pv-field-label { display: block; color: var(--ink-3); font-size: 12.5px; margin: 10px 0 6px; }
.pv-subhead { margin: 15px 0 8px; color: var(--ink-3); font-size: 12.5px; font-weight: 650; }
.pv-comm-list { margin-top: 7px; }
.pv-settings-group { padding: 0 0 13px; margin-bottom: 13px; border-bottom: 1px solid var(--line-2); }
.pv-settings-group:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.pv-group-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.pv-group-head b { font-size: 13.5px; }
.pv-group-head span { color: var(--ink-4); font-size: 11.5px; }
.pv-tip {
  margin-top: 13px; padding: 9px 11px; border-radius: 8px;
  background: var(--warning-weak); border: 1px solid #f0d9a8;
  color: var(--warning-ink); font-size: 12.5px; line-height: 1.65;
}

.chk-group { margin-bottom: 14px; }
.chk-group-t { font-size: 13.5px; color: var(--ink-3); margin-bottom: 7px; }
.chk-grid { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.chk {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; cursor: pointer; user-select: none; white-space: nowrap;
}
.chk input { margin: 0; cursor: pointer; }
.chk-off { opacity: .45; cursor: not-allowed; }
.chk-off input { cursor: not-allowed; }
.chk-why { font-style: normal; font-size: 12px; color: var(--ink-4); }
.chk-n { font-style: normal; font-size: 12px; color: var(--ink-4); }
.chk-scroll {
  max-height: 190px; overflow: auto; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 4px 12px; border: 1px solid var(--line-2); border-radius: 10px; padding: 10px;
  overscroll-behavior: contain;
}
.chk-scroll .chk { display: flex; }

/* ---- 建完链接/加完员工之后的结果块 ---- */
.sl-done {
  margin-top: 16px; background: var(--success-weak, #eaf7ef);
  border: 1px solid #bfe3cd; border-radius: 12px; padding: 14px 16px;
}
.sl-done-h { font-weight: 650; margin-bottom: 10px; }
.sl-done-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.sl-code {
  font-family: ui-monospace, Consolas, monospace; font-size: 19px; letter-spacing: .12em;
  background: #fff; border: 1px dashed #bfe3cd; border-radius: 8px; padding: 3px 12px;
}

/* ---- 设置类的小表单（公客池那块用） ---- */
.field-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 8px;
}
.field-row > label:first-child { min-width: 190px; color: var(--ink-2); font-size: 14.5px; }
.switch-row { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 14.5px; }
.form2 { display: flex; flex-direction: column; gap: 6px; }
.form2 > label { font-size: 13.5px; color: var(--ink-3); margin-top: 6px; }

/* ---- 提示条 ---- */
.callout {
  border-radius: 10px; padding: 11px 14px; font-size: 14px; line-height: 1.6;
  background: #f4f6fa; border: 1px solid var(--line-2); color: var(--ink-2);
}
.callout.info { background: var(--primary-weak); border-color: var(--primary-line); color: var(--primary); }
.callout.warn { background: var(--warning-weak); border-color: #f0d9a8; color: var(--warning-ink); }

/* ---- 手机上：一行一条的卡片竖过来 ---- */
@media (max-width: 860px) {
  .ac-row { flex-direction: column; gap: 10px; }
  .ac-btns { width: 100%; }
  .field-row > label:first-child { min-width: 0; }
  .pv-editor-layout { grid-template-columns: 1fr; min-height: 0; }
  .pv-editor-nav {
    display: grid; grid-template-columns: 1fr 1fr; gap: 6px; overflow: visible;
    border-right: 0; border-bottom: 1px solid var(--line); padding: 7px;
  }
  .pv-nav-cap { display: none; }
  .pv-step { width: 100%; min-width: 0; min-height: 44px; margin: 0; padding: 8px 9px; }
  .pv-editor-main { padding: 13px; }
  .pv-pane { max-height: 55vh; padding-right: 3px; }
  .chk-scroll { max-height: 150px; grid-template-columns: 1fr 1fr; }
  .share-bar { padding: 8px 12px; font-size: 13px; }
}

/* 客户详情右栏底部的「操作记录」入口（第 39 轮）：
   刻意做得**不显眼** —— 他原话「尽量不让操作记录太明显，因为平常用不太到」。
   用一条虚线 + 留白跟上面的跟进记录隔开，按钮降到 75% 不透明度。 */
.cd-ops-bar {
  display: flex; align-items: center; gap: 8px;
  margin-top: 10px; padding-top: 10px;
  border-top: 1px dashed var(--line-2);
  flex: none;
}
.cd-ops-bar .btn { opacity: .7; font-weight: 400; }
.cd-ops-bar .btn:hover { opacity: 1; }

/* 设置页折叠（第 39 轮他要求「设置里面的功能都折叠，打开才能看完整的，节省空间」）。
   默认全折起来，点标题那一行展开；表头里本来就有按钮的地方不受影响（JS 里判过）。 */
.card.folded .card-body { display: none; }
.card-head.fold-head { cursor: pointer; user-select: none; }
.card-head.fold-head:hover h2 { color: var(--primary); }
.fold-arrow {
  font-style: normal; color: var(--ink-4); margin-right: 7px;
  font-size: 13px; display: inline-block; width: 12px;
}

/* 鼠标在能滑的表格上停了约 1 秒 → 它「接管」滚轮，给一圈浅描边提示
   （不然他不知道现在是滚页面还是滚表格）。只是一圈线，不动布局。 */
.tbl-scroll.wheel-armed, .kv-scroll.wheel-armed, .rd-list.wheel-armed {
  box-shadow: inset 0 0 0 2px var(--primary-line);
  border-radius: 8px;
  transition: box-shadow .15s;
}

/* 工作台「面积段分布」里两个能点的格子（在售 / 成交）——
   加个手型和悬停底色，不然他不知道这里能点。 */
.wb-cell-link { cursor: pointer; }
.wb-cell-link:hover { background: var(--primary-weak); }
.wb-cell-link:hover b { color: var(--primary); }

/* ==================================================================
   访客的「房源推荐页」（第 40 轮）
   ------------------------------------------------------------------
   客户点分享链接看到的就是这一页。跟管理端的房源表格是两种东西：
     · 管理端 = 一行一套、横着扫、能排序（他天天用，要快）
     · 这一页 = 大图卡片、竖着滑、点「感兴趣」（客户用，要看得懂）
   所以样式**自成一块**，不复用 .hcard（那个只在手机媒体查询里生效，
   桌面端打开分享链接就没有了）；这一页在电脑上也要是卡片。
   命名一律 g 前缀（guest），跟管理端那一套不会撞。
   ================================================================== */

.guest-page { max-width: 720px; margin: 0 auto; }

.guest-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 12px; }
.guest-head h1 { font-size: 22px; font-weight: 700; margin: 0; letter-spacing: -.02em; }
.guest-count { font-size: 14px; color: var(--ink-3); }
.guest-count b { color: var(--primary); font-size: 17px; }

/* 筛选：一行放不下就换行，手机上每个框都够大（手指点得中） */
.guest-filter {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 11px 13px; margin-bottom: 14px;
}
.guest-filter .input { width: 96px; height: 36px; }
.guest-filter #gq { width: 100%; flex: 1 1 180px; }
.guest-filter .fgroup { flex-wrap: wrap; }

.gcards { display: flex; flex-direction: column; gap: 14px; }

.gcard {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  overflow: hidden; box-shadow: var(--shadow-sm);
}

/* 大图区：横向 scroll-snap —— 左右滑是浏览器原生的惯性，
   不抢 touch 事件，就不会跟「整页上下滑」打架。 */
.gcard-imgs {
  position: relative; display: flex; overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  height: 260px; background: var(--line-2); scrollbar-width: none;
}
.gcard-imgs::-webkit-scrollbar { display: none; }
.gcard-imgs.empty { display: flex; align-items: center; justify-content: center;
  color: var(--ink-4); font-size: 14px; }
.gslide { flex: 0 0 100%; height: 100%; scroll-snap-align: center; }
.gslide img { width: 100%; height: 100%; object-fit: cover; display: block; cursor: zoom-in; }

/* 「1 / 5」角标：左右滑的时候他知道还有几张，也知道能滑 */
.gcount {
  position: absolute; right: 10px; bottom: 10px;
  background: rgba(0, 0, 0, .55); color: #fff; font-size: 12.5px;
  padding: 3px 10px; border-radius: 11px; pointer-events: none;
  font-variant-numeric: tabular-nums;
}

.gcard-body { padding: 13px 15px 15px; }
.gcard-top { display: flex; align-items: center; gap: 8px; }
.gcard-title { flex: 1; min-width: 0; font-size: 17px; font-weight: 700; line-height: 1.35; }
.gcard-title b { font-size: 18px; font-weight: 800; letter-spacing: -.02em; }
.gcard-top .badge { flex: none; }
.gcard-sub { margin-top: 5px; font-size: 14px; color: var(--ink-2); }

/* ★★★ 第 112 轮 · 第 7 / 8 条：视频管理 —— **手机端一行 = 一张卡片**（不再左右滑）。
   出处是 `video.js` 的 `卡片HTML()` / `画新的表()`（只在 `是手机()` 为真时画出来）。
   · 每张卡：第一列当卡头，其余列竖着一行一项（左边列名、右边值）—— 宽度天然跟屏宽；
   · 「是谁的号」「操作（回复）」这些列一个都没少，只是从"横向第 N 列"变成"竖着第 N 行"；
   · 桌面端根本不会用到这几个类（还是那张表），所以这几条不放进媒体查询里也不会互相影响。 */
.vd-cards { display: flex; flex-direction: column; gap: 10px; }
.vd-card {
  border: 1px solid var(--line-2); border-radius: 12px; background: #fff;
  padding: 10px 12px; overflow-wrap: anywhere;
}
.vd-card-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding-bottom: 8px; margin-bottom: 8px; border-bottom: 1px solid var(--line-2);
}
.vd-card-body { display: flex; flex-direction: column; gap: 6px; }
.vd-f { display: flex; gap: 8px; align-items: flex-start; }
.vd-f > i {
  flex: none; width: 74px; font-style: normal; color: var(--ink-4); font-size: 12.5px; line-height: 1.5;
}
.vd-f > span { flex: 1 1 auto; min-width: 0; font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.vd-f > span img { max-width: 100%; }

/* ★★★ 第 113 轮 · 第 3 条（他 2026-10-12）：「视频数据里面，发布时间，播放量，点赞，评论 分享，收藏，
   **竖列了**，你可以**横列放几个，并排**，这样会整齐。也节省空间」——
   落地：手机卡片里那几个**短指标**不再一行一个，改成**并排**（每行自动 2~3 个，
   宽度不够自己降列数），长文本（评论内容 / 最近一条内容）仍旧整行 —— 一眼看得全、卡片还矮一半。
   ⚠️ 只影响手机卡片（`.vd-fgrid` 只在 `video.js 卡片HTML()` 里画；电脑端还是那张表，一个字没动）。
   ⚠️ 用 `auto-fit + minmax` 而不是写死 3 列：390 宽下自动落 3 列，更窄的屏自动降 2 列，
      **永远不会把卡片撑出横向滚动条**。 */
.vd-fgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
  gap: 6px 10px;
}
.vd-fgrid .vd-f { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.vd-fgrid .vd-f > i { width: auto; font-size: 11.5px; color: var(--ink-4); }
.vd-fgrid .vd-f > span { font-size: 13.5px; font-weight: 600; overflow-wrap: anywhere; }

/* 报价：这一页的主角，字号明显大于其它所有文字 */
.gcard-price { margin-top: 8px; color: var(--danger); }
.gcard-price b { font-size: 30px; font-weight: 800; letter-spacing: -.03em; line-height: 1.1; }
.gcard-price s { text-decoration: none; font-size: 14px; font-weight: 600; margin-left: 3px; }

.gcard-interest {
  display: block; width: 100%; margin-top: 12px; height: 44px;
  font-size: 16px; font-weight: 600;
  background: var(--primary); color: #fff; border: 1px solid var(--primary);
  border-radius: 10px;
}
.gcard-interest:hover:not(:disabled) { background: var(--primary-strong); border-color: var(--primary-strong); }
.gcard-interest:disabled { cursor: default; }
/* 已经表过态：变安静，别再来抢眼睛（它已经没用了） */
.gcard-interest.done {
  background: var(--success-weak); color: var(--success);
  border-color: var(--success-weak); font-weight: 600;
}

/* ---- ★ 第 78 轮：底价 + 「提个底价」（只在分享链接里、且他勾了那个选项时才出现） ----
   位置就在报价下面一行：左边是这套房的当前底价，右边是提改的入口。
   ⚠️ 用手写的小块而不是现成的 .field —— 客户页是手机为主，这一行必须能挤在一行里。 */
.gcard-bottom {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px;
  margin-top: 6px; font-size: 15px; color: var(--text);
}
.gcard-bottom .gb-k { color: var(--muted); font-size: 13px; }
.gcard-bottom b { font-size: 19px; font-weight: 700; }
.gcard-bottom s { text-decoration: none; font-size: 13px; margin-left: 1px; }
.gcard-bottom .gcard-propose { margin-left: auto; }      /* 挤到右边，别跟数字黏在一起 */
.gcard-bottom .gb-state { font-size: 13px; font-weight: 600; }
.gcard-bottom .gb-state.pending { color: var(--warning, #b7791f); }
.gcard-bottom .gb-state.ok { color: var(--success); }
.gcard-bottom .gb-state.no { color: var(--danger); }
.gcard-propose-box {
  display: flex; align-items: center; gap: 6px; margin-top: 8px;
}
.gcard-propose-box .gb-in { flex: 1 1 auto; min-width: 0; height: 38px; font-size: 15px; }
/* hidden 是浏览器默认样式，这里被 display:flex 盖掉了 —— 必须显式写回来（老坑） */
.gcard-propose-box[hidden] { display: none; }

/* ★ 第 78 轮（他的要求）：「把权限挪到设置里面…权限只是设置里面的一个菜单，把后台也放到设置里面去」。
   这条就是那三个"菜单"（设置 / 权限与分享 / 后台），长在设置、权限、后台三个页面的顶上。 */
.seg-tabs.set-menu {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin-bottom: 18px;
  padding: 6px;
  border-radius: 15px;
  background: color-mix(in srgb, var(--card) 92%, var(--primary-weak));
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.seg-tabs.set-menu .seg-tab {
  position: relative;
  height: 46px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--ink-3);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .025em;
  transition: background .16s, color .16s, box-shadow .16s;
}
.seg-tabs.set-menu .seg-tab:hover { background: var(--primary-weak); color: var(--primary); }
.seg-tabs.set-menu .seg-tab.on {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  box-shadow: 0 8px 20px color-mix(in srgb, var(--primary) 24%, transparent);
}
.perm-layout {
  display: grid;
  grid-template-columns: 224px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.perm-subnav {
  position: sticky;
  top: calc(var(--topbar-h) + 14px);
  display: flex !important;
  flex-direction: column;
  gap: 6px;
  margin: 0 !important;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 15px;
  background: linear-gradient(180deg, var(--card) 0%, color-mix(in srgb, var(--card) 92%, var(--primary-weak)) 100%);
  box-shadow: 0 10px 28px rgba(16,24,40,.065);
  overflow: visible !important;
}
.perm-nav-cap {
  padding: 5px 10px 8px;
  color: var(--ink-4);
  font-size: 10.5px;
  font-weight: 750;
  letter-spacing: .15em;
}
.perm-subnav .seg-tab {
  width: 100%;
  min-height: 48px;
  justify-content: flex-start;
  text-align: left;
  gap: 10px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--ink-2);
  padding: 9px 12px;
  font-size: 15px;
  font-weight: 650;
  transition: background .16s, border-color .16s, color .16s, box-shadow .16s;
}
.perm-subnav .seg-tab::before {
  content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; opacity: .28;
}
.perm-subnav .seg-tab:hover { background: var(--hover); border-color: var(--line); color: var(--primary); }
.perm-subnav .seg-tab.on {
  background: var(--primary); border-color: var(--primary); color: #fff;
  box-shadow: 0 7px 18px color-mix(in srgb, var(--primary) 22%, transparent);
}
.perm-subnav .seg-tab.on::before { background: #fff; opacity: .9; }
.perm-subnav .seg-tab i {
  margin-left: auto; min-width: 27px; padding: 1px 7px; border-radius: 999px;
  background: var(--line-2); color: var(--ink-2); font-size: 12px; text-align: center;
}
.perm-subnav .seg-tab.on i { background: rgba(255,255,255,.18); color: #fff; }
.perm-main { min-width: 0; }
/* 权限与分享的名单导航：加大到正常侧边栏的视觉重量。
   这个 id 只落在权限页，不改后台/设置里的其它页签。 */
.perm-layout:has(#acTabs) { grid-template-columns: 232px minmax(0, 1fr); gap: 18px; }
#acTabs {
  gap: 7px;
  padding: 10px;
  border-radius: 14px;
  box-shadow: 0 6px 20px rgba(24, 39, 37, .07);
}
#acTabs .seg-tab {
  min-height: 52px;
  gap: 10px;
  padding: 11px 14px;
  border: 1px solid transparent;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 650;
}
#acTabs .seg-tab::before {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  opacity: .28;
}
#acTabs .seg-tab.on {
  box-shadow: inset 4px 0 0 rgba(255,255,255,.82), 0 7px 18px color-mix(in srgb, var(--primary) 22%, transparent);
}
#acTabs .seg-tab.on::before {
  background: #fff;
  opacity: 1;
}
#acTabs .seg-tab i {
  min-width: 30px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--line-2);
  color: var(--ink-2);
  font-size: 12.5px;
  font-style: normal;
  text-align: center;
}
#acTabs .seg-tab.on i { background: rgba(255,255,255,.16); color: #fff; }
.ac-v3-hero { background: linear-gradient(135deg, var(--primary), var(--primary-strong)); color: #fff; }
.ac-v3-hero .small.muted { color: rgba(255,255,255,.7); }
.ac-v3-url { margin-top: 5px; font-size: 20px; font-weight: 700; word-break: break-all; }
.ac-v3-section-title { font-size: 16px; font-weight: 700; margin-bottom: 6px; }
.ac-default-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  margin-top: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  cursor: pointer;
}
.ac-default-row:hover { border-color: var(--primary-line); background: var(--hover); }
.ac-default-row > div { flex: 1 1 auto; min-width: 0; }
.ac-default-row > span:last-child { flex: none; color: var(--primary); font-weight: 650; }
.name-tag {
  display: inline-flex;
  align-items: center;
  min-height: 23px;
  padding: 1px 7px;
  border-radius: 6px;
  background: var(--line-2);
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 400;
}
.ac-person-row { cursor: pointer; }
.ac-person-row:hover { background: var(--hover); }
@media (max-width: 860px) {
  .seg-tabs.set-menu { gap: 5px; padding: 5px; }
  .seg-tabs.set-menu .seg-tab { height: 44px; font-size: 13.5px; padding: 0 5px; border-radius: 9px; }
  .perm-layout { grid-template-columns: 1fr; gap: 9px; }
  .perm-subnav {
    position: static;
    flex-direction: row;
    gap: 6px;
    padding: 7px;
    overflow-x: auto !important;
    scrollbar-width: none;
  }
  .perm-subnav::-webkit-scrollbar { display: none; }
  .perm-subnav .seg-tab {
    width: auto;
    min-height: 44px;
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 8px 12px;
    font-size: 14px;
  }
    .perm-layout:has(#acTabs) { grid-template-columns: 1fr; }
    .perm-nav-cap { display: none; }
    #acTabs { padding: 6px; }
  #acTabs .seg-tab, #setTabs .seg-tab { flex: 1 0 auto; min-height: 44px; padding: 8px 12px; font-size: 14px; }
  .ac-default-row { align-items: flex-start; }
  .ac-v3-url { font-size: 16px; }
}

/* ★ 第 78 轮：权限里「能看哪些小区」改成**按区收着** ——
   平常只显示一行「新城区 · 86 个小区 · 已选 3 个」，点「选小区」才弹窗看详情去勾。 */
.pm-dist { display: flex; flex-direction: column; gap: 6px; }
.pm-dist-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: #fafbfc;
}
.pm-dist-main { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
.pm-dist-sel { color: var(--muted); }
.pm-dist-row .btn { flex: none; }

.guest-more { display: flex; justify-content: center; padding: 16px 0 30px; }
.guest-more .btn { min-width: 180px; height: 40px; }

/* 手机上：图片矮一点（一屏能看到「图 + 价 + 按钮」，不用滚来滚去） */
@media (max-width: 860px) {
  .guest-page { max-width: none; }
  .guest-head h1 { font-size: 19px; }
  .gcard-imgs { height: 58vw; max-height: 300px; }
  .gcard-price b { font-size: 27px; }
  .guest-filter { padding: 10px 11px; }
  .guest-filter .input { height: 38px; }   /* ≥38px 手指点得中 */
  .guest-filter .input { flex: 1 1 76px; width: auto; }
  .guest-filter #gq { flex: 1 1 100%; }
}

/* ==================================================================
   第 41 轮：批量转层次 + 手机号反查
   ================================================================== */

/* 公客页签的「批量转回私客」工具条。
   用主色浅底把它跟表格区分开 —— 它是个"操作模式"的入口，不是表格的一部分。 */
.cbatch {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 12px; margin-bottom: 8px;
  background: var(--primary-weak); border: 1px solid var(--primary-line);
  border-radius: 9px;
}
.cbatch .chk { margin: 0; font-size: 13.5px; }
.cbatch .btn:disabled { opacity: .5; cursor: default; }

/* 权限页顶部的「手机号反查」框（四个页签都在） */
#acPhoneCard { margin-bottom: 14px; }
#acPhoneCard .tbl { margin-top: 8px; }
#acPhoneCard .tbl th { font-size: 12.5px; }
/* 手机上表格横着放不下，让它自己滚，别把整页撑宽 */
@media (max-width: 860px) {
  #acPhoneCard .tbl { display: block; overflow-x: auto; white-space: nowrap; }
  .cbatch { gap: 8px; }
}

/* ==================================================================
   管理员后台（第 44 轮）
   ------------------------------------------------------------------
   这一页只有管理员能进，而且要先输密码解锁。视觉上刻意跟别处**不一样**：
   深色一点的锁屏 + 红调的危险按钮，让他一眼就知道"我现在在动真格的地方"。
   ================================================================== */

/* 右侧内容区锁着：后台外壳和左侧管理菜单仍显示 */
.admin-lock { display: flex; justify-content: center; padding: 48px 16px; }
.admin-lock-inline { display: block; padding: 8px 0 0; }
.admin-lock-inline .admin-lock-card {
  max-width: 520px; margin: 0 auto; padding: 28px 30px 24px;
  background:
    linear-gradient(145deg, color-mix(in srgb, var(--primary-weak) 34%, transparent), transparent 58%),
    var(--card);
}
.admin-lock-card {
  width: 100%; max-width: 420px; text-align: center;
  background: var(--card); border: 1px solid var(--line); border-radius: 16px;
  padding: 30px 28px 24px; box-shadow: var(--shadow);
}
.admin-lock-ico {
  width: 54px; height: 54px; margin: 0 auto 12px;
  display: flex; align-items: center; justify-content: center;
  background: var(--danger-weak); border-radius: 50%;
}
.admin-lock-ico svg { width: 27px; height: 27px; fill: none; stroke: var(--danger); stroke-width: 1.7; stroke-linecap: round; }
.admin-lock-card h1 { font-size: 21px; margin: 0 0 8px; }
.admin-lock-sub { font-size: 13.5px; color: var(--ink-3); line-height: 1.7; margin-bottom: 16px; }
.admin-lock-card .input { width: 100%; text-align: center; letter-spacing: .12em; height: 42px; }
.admin-lock-err { color: var(--danger); font-size: 13px; min-height: 20px; margin: 6px 0 4px; }
.admin-lock-card .btn.primary { width: 100%; height: 42px; }
.admin-lock-foot { font-size: 12.5px; color: var(--ink-4); line-height: 1.75; margin-top: 16px; }

/* 开着的那一屏：顶部工具条 */
.ad-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
}
.ad-bar .btn:disabled { opacity: .5; cursor: default; }
.ad-bar .search-wrap .input { height: 34px; }

/* 概览那几块数字 */
.ad-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.ad-stat {
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 13px 15px; box-shadow: var(--shadow-sm);
}
.ad-stat i { display: block; font-style: normal; font-size: 12.5px; color: var(--ink-4); margin-bottom: 3px; }
.ad-stat b { font-size: 25px; font-weight: 700; letter-spacing: -.02em; }
.ad-stat s { text-decoration: none; display: block; font-size: 12px; color: var(--ink-4); margin-top: 2px; }

/* 后台里的表格沿用 .tbl，但行高紧一点（一屏能多看几行） */
#adBody .tbl td { padding-top: 7px; padding-bottom: 7px; }
#adBody .tbl td .small { line-height: 1.55; }

@media (max-width: 860px) {
  .ad-bar { gap: 8px; }
  .ad-bar .search-wrap { width: 100% !important; }
  .ad-stats { grid-template-columns: 1fr 1fr; }
  .admin-lock { padding: 20px 10px; }
  .admin-lock-inline { padding: 4px 0 0; }
  #adBody .tbl { display: block; overflow-x: auto; white-space: nowrap; }
}

/* ==================================================================
   第 46 轮：骨架屏
   ------------------------------------------------------------------
   第一次进某一页（还没有快照）时先把版面撑住，别让人对着一行「加载中…」等。
   这是**知觉**上的优化，不是速度上的 —— 同一段等待，看着"内容正在来"比看着"卡住了"舒服得多。
   快照命中时根本不会走到这里（直接把上次画好的贴出来，见 app.js 的 go()）。
   ================================================================== */
.skel { padding: 2px 0; }
.skel-head { height: 28px; margin-bottom: 18px; }
.skel-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm); padding: 6px 16px;
}
.skel-row {
  display: flex; align-items: center; gap: 20px;
  height: 47px; border-bottom: 1px solid var(--line-2);
}
.skel-row:last-child { border-bottom: 0; }
.skel-bar {
  height: 11px; border-radius: 6px;
  background: linear-gradient(90deg, var(--line-2) 25%, var(--line) 37%, var(--line-2) 63%);
  background-size: 400% 100%;
  animation: skel 1.3s ease-in-out infinite;
}
@keyframes skel {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
/* 系统里关了动画（眩晕/省电）就让它静静地灰着，别硬闪 */
@media (prefers-reduced-motion: reduce) { .skel-bar { animation: none; } }

/* 手机端：工作台上「底价区间分布」和「平均单价分布」这一对框子。
   他 2026-10-01 提「两块要一样高」；2026-10-03 又提（原话）：
   「这两个框体，**最右边我都看不到信息**，我意思**太宽了**……比如 0-50万对应的 44 套，
   **中间隔的很远，紧凑点**，小区名字和单价也隔的很多，**你要适配屏幕**，
   **搜索框你可以放到标题下面也行啊**」。

   ★ 根因（2026-10-03 用探针在 360/390/414/768/1024/1440 六个屏宽下量出来的，先量再改）：
     `.grid-2` 是 `1fr 1fr`，**手机端从来没改成单列** → 两张卡在手机上仍**并排**；
     而「平均单价」那张的**卡片头最小宽度是 282px**（标题 96 + 搜索框 78 + 计数 60 + 间距），
     两张并排 = 443px > 390px；页面**又不横向滚动**（documentElement.scrollWidth 等于屏宽）→
     **卡片右边被直接裁掉**：390 屏下卡片右边缘 485px、末列数值右边缘 470px（超出屏幕 80px）。
     左边那张反而被挤到 176px（360 屏 161px）。这就是「最右边看不到信息」。
     另一头：`.kv-table.wide` 是 `table-layout:fixed; width:100%`（两列各占一半 + 数值右对齐），
     卡片只要够宽，标签和数值就被顶到两个角上 —— 这就是「0-50万……44套中间隔的很远」。

   ★ 修法：
     ① **标签和数值贴在一起**（这条**手机和电脑都改** —— 他这次没限定设备，而"隔的很远"电脑端更严重：
        1440 宽实测「0-50 万」和「2 套」之间空 **328px**、「美的广场公寓」和「24320 元/㎡」空 **261px**）。
        改法见下面不带媒体查询的三行；**高度一个字没动**（桌面 `.kv-scroll` 还是 224px、手机 200px）。
     ② 手机上那一行（`.wb-dist-row`）改成**单列** → 两张卡各占满屏宽，**不再被裁**；
     ③ 手机卡片头**允许换行**，用全局那条手机规则 `.card-head .right{width:100%}` →
        标题一行、搜索框/说明另起一行并占满宽 —— **正是他自己提的「搜索框放到标题下面」**；
        两张卡的头都是两行 → **两块还是一样高**。
     ⚠️ 上一版我用 `flex-wrap:nowrap` 硬把卡片头压成一行 —— 那**正是**把最小宽度顶到 282px、
        把右边裁掉的原因（他评价「跟没改一样」）。**别再压成一行、别再给 head 加 nowrap**。
     ⚠️ `.kv-scroll` 高度不要动：桌面 224px / 手机 200px，两块自然等高。
   ---- */

/* ① 标签和数值贴在一起（**所有屏宽**，只针对这两个框子）。
   原来是 `table-layout:fixed`（两列各占一半）+ 数值右对齐 → 只要卡片够宽，两者就被顶到两个角上。
   现在：标签列收缩到内容宽（`width:1px` + `nowrap` 是这个技巧的标准写法）、数值紧随其后左对齐；
   表格仍是 `width:100%`，所以那条横线还是通到卡片右边。 */
.card.wb-dist .kv-table { table-layout: auto; }
.card.wb-dist .kv-table td.k { width: 1px; white-space: nowrap; padding-right: 10px; }
.card.wb-dist .kv-table td.v { text-align: left; }

/* ② **卡片必须显式 width:100%**（所有屏宽）。这是量出来的一条硬规矩，别再删：
   这两张卡是**滚动容器**（`.card` 自己 `overflow:hidden`，手机端还有一条 `.card{overflow-x:auto}`），
   而 **Chrome 对滚动容器不做网格拉伸** —— 卡片的宽度退化成"内容宽"（fit-content），
   命令行的 `justify-items:stretch` / `justify-self:stretch` **都没用**（2026-10-03 一条条试过）。
   实测：1440 屏 —— 这一行两列各 570px，左边那张只算 **240px**（右边那张正好等于 570，是碰巧它的
   内容很宽）；768 屏 —— 该 365px 只算 204px。所以只要内容一变窄（比如把 `table-layout` 从 fixed
   改成 auto），卡片就会突然塌成一条。显式写 `width:100%` 之后：360/390/414/620/768/1024/1440 七档
   全部铺满该占的宽度。 */
.wb-dist-row > .card { width: 100%; }

@media (max-width: 860px) {
  /* 2026-10-20：工作台四张统计卡（小区价格变化 / 面积区间 / 小区成交 / 平均单价）
     手机端也按同一规则：标题居中，搜索区在下一行居中；输入框固定 260px，窄屏自动收。 */
  .card-head.center { justify-content: center; text-align: center; }
  .card.wb-dist .card-head #wbUnitCount { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
  .card.wb-dist .kv-scroll { padding: 4px 14px; }
  .card.wb-dist .kv-table td { padding: 4px 0; }
}

/* 窄屏（手机）才竖着排：两张卡各占满屏宽。
   700px 这个断点是量出来的：并排时每张卡分到 (屏宽-16)/2，
   768px 还能放得下卡片头（标题 + 搜索框 + 计数 ≈ 330px），
   再窄（620px → 每张 302px）头就放不下、右边又会被裁。 */
@media (max-width: 700px) {
  .wb-dist-row { grid-template-columns: 1fr; grid-auto-rows: 1fr; }  /* 两行等高 → 两块卡一样高 */

  /* r238：已发视频房源升为第五个主菜单，平台筛选只剩三个真实平台。
     手机端三个平台保持一行，其他页签条不跟着变。 */
  #vdPlat {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 4px;
  }
  #vdPlat .seg-tab {
    min-width: 0; padding: 8px 1px; font-size: 12px; white-space: nowrap;
  }

  /* r161 手机端房源详情按钮：
     · 「复制卡片图片」独占第一行；
     · 「已发视频」和「复制文字」同一行（左 / 右）。
     用显式网格位置，DOM 顺序仍是桌面端的「已发视频 → 复制卡片图片 → 复制文字」，两端只写一套按钮。 */
  .hd-actions.has-video-sent {
    width: 100%; margin-top: 8px;
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  }
  .hd-actions.has-video-sent #hdCopyCard { grid-row: 1; grid-column: 1 / -1; }
  .hd-actions.has-video-sent #hdVideoSent { grid-row: 2; grid-column: 1; }
  .hd-actions.has-video-sent #hdCopy { grid-row: 2; grid-column: 2; }
  /* r273：加入「准备带看」后改成 2×2：
     上排「已发视频 / 准备带看」，下排「复制卡片图片 / 复制文字」。
     复制卡片图片从独占整行缩成半行，和已发视频等宽；准备带看正在复制文字上方。 */
  .hd-actions.has-viewing-ready {
    width: 100%; margin-top: 8px;
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  }
  .hd-actions.has-viewing-ready.has-video-sent #hdVideoSent { grid-row: 1; grid-column: 1; }
  .hd-actions.has-viewing-ready.has-video-sent #hdViewingReady { grid-row: 1; grid-column: 2; }
  .hd-actions.has-viewing-ready.has-video-sent #hdCopyCard { grid-row: 2; grid-column: 1; }
  .hd-actions.has-viewing-ready.has-video-sent #hdCopy { grid-row: 2; grid-column: 2; }
  .hd-actions.has-viewing-ready:not(.has-video-sent) #hdViewingReady {
    grid-row: 1; grid-column: 1 / -1;
  }
  .hd-actions.has-viewing-ready:not(.has-video-sent) #hdCopyCard { grid-row: 2; grid-column: 1; }
  .hd-actions.has-viewing-ready:not(.has-video-sent) #hdCopy { grid-row: 2; grid-column: 2; }
}

/* 第 54 轮：手机上「房号 / 编号 / 工作表」这三组不显示（他要的），电脑端照旧显示 */
@media (max-width: 860px) {
  .only-desktop { display: none !important; }
  /* 手机上只留短句：卡片头里那种「… · 底价 ÷ 面积」「… · 另有 N 套没填底价」的尾巴会
     把右边顶出去、被省略号切掉（他：「最右边我都看不到信息」）。 */
  .only-wide { display: none !important; }
}

/* 第 54 轮：工作台这两块的两条**不能破**的底线（他原话）：
     ① **要滚动**（数据多了在框里滑）② **两块要一样高**；③ **电脑端不要动，保持原样**。
   桌面端**一个字都不改**（`.kv-scroll` 还是 224px、两块等高、都能滑）；
   手机端**也不改框高**（跟着全局那条 `.kv-scroll{height:200px}` 走，两块自然等高、都能滑）。
   ⚠️ 曾经把这两条写成**不带媒体查询**的全局规则 → 把电脑端也改了，
      当场被 ui-shot-ui2 那 4 条老断言抓住（"平均单价分布高度固定 224px" 等）—— 别再犯。
   ⚠️ 也曾按"底价不滚、平均单价加高"改过 —— 他立刻纠正：「**要滚动，要一样高**」。
      所以这里**不要**再动 height、不要改 overflow。
   （行距/内边距那两条已经并进上面那段手机规则里，这里不再重复。） */

/* 第 55 轮：手机端房源页筛选行 = **左边三个 / 右边三个**。   他原话：「房源页的筛选重新设计，把楼栋，状态，排序放**右边**，跟面积，价格，楼层**对齐**，
   也就是**左边三个，右边三个，紧凑下**」＋「**手机里的**」→ 所以电脑端一个字不动。

   改之前量到的（390 屏）：这一行是**四行 + 按钮一行、整行高 248px**，六个组东一个西一个 ——
   面积 y=336 / 价格 y=384 / 楼层+楼栋 y=432（楼栋被挤到楼层右边）/ 状态+排序 y=480 / 按钮 y=530。
   改之后：两列 grid，左列（.fg-left）面积·价格·楼层，右列（.fg-right）楼栋·状态·排序，
   两列各三行、行与行**对齐**，整行约 175px。

   · 桌面端（>860px）：`.fg-left` / `.fg-right` 都是 flex、`gap:inherit`（继承 `.filter-row` 的 12px），
     所以面积/价格/楼层之间的间距**和以前一模一样**；`.fg-right` 在电脑端是空的 → `:empty` 不显示，
     楼栋/状态/排序照旧留在「筛选」面板里 ⇒ **电脑端外观零变化**。
   · 手机上：两列 grid（左列略宽，因为面积/价格是「最小–最大」两个框）；
     组里的输入框/下拉框 `width:auto → 100%`（原来写死的 70/80/86/120/138px 在窄列里放不下），
     标签 `flex:0 0 auto`；「万·底价」那条提示在手机上省掉（标签同时由 JS 改成「底价」，
     免得只剩「价格」两个字分不清是报价还是底价）。 */
.fg-left, .fg-right { display: flex; align-items: center; gap: inherit; }
.fg-right:empty { display: none; }

/* 第 57 轮：他「电脑端和手机端一样，去掉那三个（房号/编号/工作表）」——
   这三个组**两端都隐藏**（手机上第 54 轮就藏了，现在电脑端也跟手机一样）。
   只藏不改结构：元素的 id 还在，URL 里带 room=/code=/sheet= 的旧链接照样能筛选，
   要恢复的话把这个类去掉就行。 */
.filter-drop { display: none !important; }

/* 第 58 轮：他「图片列户型图和底价钥匙还是放在外面吧，可以第二行，右边第二排最右边；户型也放出来」
   —— 这三样（户型 / 显示底价钥匙 / 图片列开关）搬到主行的第三块 .fg-extra。
   主行是 flex + wrap：放得下就并排，放不下就**整块落到第二行**，再用 margin-left:auto 顶到**最右边**
   （正是他要的「第二行、右边最右」）。手机上主行是两列 grid，这一块占满整行、内容靠右。 */
.fg-extra { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-left: auto; }

@media (max-width: 860px) {
  .house-extra-filters {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px 10px;
    padding: 10px 12px;
  }
  .house-extra-filters.open { display: grid; }
  .mobile-extra-groups,
  .room-bath-groups { display: contents; }
  .house-extra-filters .fgroup {
    min-width: 0;
    justify-content: space-between;
  }
  .house-extra-filters .hchoice-group {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
  .house-extra-filters .input {
    width: 100% !important;
    min-width: 0;
  }

  .hrow-main { display: grid; grid-template-columns: 1.15fr 1fr; gap: 6px 10px; align-items: start; }
  .fg-left, .fg-right { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; min-width: 0; }
  .fg-right:empty { display: none; }
  .hrow-main .fgroup { flex-wrap: nowrap; min-width: 0; gap: 4px; }
  .hrow-main .fgroup > .flabel { flex: 0 0 auto; }
  .hrow-main .fgroup .search-wrap { width: auto !important; flex: 1 1 0; min-width: 0; }
  .hrow-main .fgroup .input { width: 100% !important; min-width: 0; }
  .hrow-main .fgroup > .small.muted { display: none; }   /* 「万·底价」省掉（标签已改成「底价」） */
  .hrow-main #hMoreBtn { grid-column: 2; justify-self: start; }
  .hrow-main .unit { display: none; }                    /* 手机上标签已经够清楚，不加单位省地方 */
  /* 第 58 轮：户型 / 底价钥匙 / 图片列开关 这一块（.fg-extra）在手机上**占满整行、内容靠右**。
     第 60 轮：他要求这三样**排成一行**（原来会折成两行）→ 明确 nowrap，
     并把户型输入框和「显示」两字再省一省（手机上就是「底价/钥匙 ☐ 户型图」）。 */
  .hrow-main .fg-extra { grid-column: 1 / -1; width: 100%; justify-content: flex-end; flex-wrap: nowrap; gap: 8px; margin-left: 0; }
  .hrow-main .fg-extra .fgroup { flex-wrap: nowrap; min-width: 0; }
  .hrow-main .fg-extra .search-wrap { width: auto !important; flex: 1 1 70px; min-width: 56px; }
  .hrow-main .fg-extra .btn.toggle { flex: 0 0 auto; }
  .hrow-main #fgLayout { flex: 1 1 auto; }
  .hrow-main #fgLayout > .flabel { display: none; }
  .hrow-main #hExtraToggle { width: 100%; min-width: 0; height: 34px; }
}

/* 第 56 轮：他说「12345 全改」—— 就是电脑端筛选区那 5 条可优化项。
   **这一整段只作用于电脑端（≥861px），手机端一个字不变**（第 55 轮刚按他要求重排过）。 */
@media (min-width: 861px) {
  /* ② 搜索行和筛选行合成一行：两行包在 .hrow-top 里，电脑端 flex 排一行，放不下才换行。
     原来这两行各占一行、桌面明明有 1154px 宽（多出 ~65px 高）。 */
  .hrow-top { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 9px 14px; }
  .hrow-top > .filter-row { padding: 0; border-top: 0; flex-wrap: nowrap; gap: 10px; }
  /* ★★ 第 99 轮（他 2026-10-10）：「电脑端搜索框拉大，**现在太小了**，还是保持这一行」。
     原来是 `max-width: 340px` + 内层 `flex-basis: 140px` —— 实测 1440 屏下搜索框里能打字的
     只有 **120px** 宽（"万科昆吾"四个字就顶出去），确实太小。
     现在松到 `max-width: 520px` + 内层 `flex-basis: 200px; min-width: 160px`：
     搜索框本体实测 **125px → 208px**，而「搜索框 + 查询 + 重置 + 清筛选 + 添加房源」**仍然是同一行**
     （这一行自己 `flex-wrap: nowrap`，第 56 轮定的，别改成 wrap）。
     ⚠️ 只动这两个数，**不要把 `.hrow-top` 改成 nowrap**：搜索行与筛选行在 1440 本来就分两行
        （筛选行自己就要 1114px，容器只有 1154px，第 56 轮那条注释与 ui-shot-ui2 的
        「1440 放不下会优雅折行」都写着这件事）—— 强行挤成一行会把筛选行压成三四段。 */
  .hrow-top .hrow-search { flex: 0 1 auto; max-width: 520px; }
  .hrow-top .hrow-search .search-wrap { width: auto !important; flex: 1 1 200px; min-width: 160px; }
  /* 筛选行吃掉剩下的宽度（**不抢宽的搜索行 + 撑满的筛选行** 才排得成一整行：
     实测过——搜索行一旦按 flex-grow 抢宽，筛选行只剩 765px，自己就折成两行了）。 */
  .hrow-top .hrow-main { flex: 1 1 auto; flex-wrap: nowrap; row-gap: 0; min-width: 0; }
  .hrow-top > .filter-row.hrow-main { gap: 0; }
  /* 2026-10-22：电脑端恢复原来的横向筛选条。
     原户型输入换成紧凑按钮以后，面积/底价/楼层/楼栋/状态/排序/区域/装修/户型/图片列
     全部压在同一行；下面用更窄的控件宽度保证 1366 也不折行。 */
  .hrow-main {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    gap: 0;
  }
  .hrow-main > .fg-left,
  .hrow-main > .fg-right,
  .hrow-main > .fg-extra {
    display: contents;
  }
  .hrow-main .fg-left .search-wrap,
  .hrow-main .fg-right .search-wrap { width: 42px !important; flex: 0 0 42px !important; }
  .hrow-main .search-wrap.narrow > .input { padding-right: 13px !important; font-size: 11px !important; }
  .hrow-main .search-wrap.narrow > .search-clear { right: 1px; width: 12px; }
  #fgLayout > .flabel,
  #fgStatus > .flabel,
  #fgBuilding > .flabel,
  #fgSort > .flabel { font-size: 12px; }
  /* ★★★ 第 128 轮（他 2026-10-16）：「**房源**搜索框还是太短了，拉长到跟**户型**那列对齐……
     **只限电脑端**」—— 他说的"对齐"＝框的**右边缘**跟那一列的右边缘齐平。
     房源表那几列是**百分比**：图片 5% ＋ 小区 10% ＋ 房号 8% ＋ 面积 7% ＋ **户型 9%** ＝ **39%**
       ⇒ 框宽 = 容器宽的 39% 再扣掉"这一行比表格多的那点内边距"（实测差 ≈4px）。
     实测（1440）：改前框 208px、右边缘落在表格宽的 17.8%；改后 479.6px、右边缘 ≈ 758（＝户型那列右边缘）。
     ⚠️ 上面那条 `max-width: 520px` 必须松开（框被它卡住才只有 208px）；松开是安全的 ——
        实测这一行和筛选行**本来就分开站**（搜索行顶 262 / 筛选行顶 310），不会互相挤。
     ⚠️ `!important` 是因为框宽是**内联**写在 HTML 上的（手机档要用那两条内联值）。 */
  /* ⚠️ 必须先把这一行撑成**确定宽度**（`flex: 0 0 100%`）再把框写成百分比 ——
     百分比宽度在"宽度由内容决定"的 flex 行里**解析不了**（规范里退化成 auto），
     第 128 轮实测踩到：只写 `width: calc(39% - 4px)` 时框还是 214px、跟没写一样。 */
  .hrow-top .hrow-search { max-width: none; flex: 0 0 100%; }
  /* 实测对齐值：框宽 **428px**（= 户型列右边缘 707 − 框左边 279）。
     为什么是 px 不是百分比：① 表头那些百分比合计 >100%，浏览器实际分配跟声明不是一一对应
     （实测累计到「户型」= 表格宽的 35%，不是声明的 39%）；
     ② 这张表有**内容最小宽**（1280px），**不随视口缩** ⇒ 列的绝对位置在 1440 / 1200 下**一样**
     （实测两档「户型右」都是 707）⇒ 用 px 才在两档都对齐（用 38.4% 时 1200 那档差 92px）。
     ⚠️ 窄到 1000 以下的桌面档表格可能被压，那档对齐会漂 —— 他常用 1440，按这个定。 */
  .hrow-top .hrow-search .search-wrap { width: 428px !important; flex: 0 1 auto; }
  /* ① 状态 / 排序 在主行**右边**（原来它们在「筛选」面板里，主行右边却空着 325px）。
     `.fg-right` 是 JS 按屏宽搬家的目标：电脑端放状态+排序，手机端放楼栋+状态+排序。 */
  .hrow-main .fg-right { margin-left: auto; }
  /* ③ 单位（㎡ / 万 / 层）+ 把控件压紧 —— 压紧是"合成一行"的前提。
     **第 59 轮实测**（他「楼层和楼栋之间隔了好远，能不能第二排也挪到第一排」就是这一行没排下）：
     1366 屏下这一行的可用宽度只有 **1040px**，而「面积·底价·楼层」698 +「楼栋·状态·排序」392 + 间距 10
     = **1100px** → 楼栋那一组被挤到第二行，中间就空了一整行。
     所以再往下抠，一共抠出 ~44px：
     面积/底价框 56→50 · 楼层 52→46 · 楼栋 64→50 · 状态 84→70 · 排序 100→78 ·
     组内间距 6→4 · 排序那两条最长的选项名从「按表格顺序/按小区分组」缩成「表格顺序/小区分组」（值没变）。
     抠完 686-? + 373-? ≈ **1025 ≤ 1040** ✓ 所以 1366 上「左三右三」是**同一行**。
     （1280 屏只有 954px，物理上仍排不开 —— 不是没调。）
     ⚠️ 这几条**必须**留在 ≥861 的媒体查询里：带 #id 的选择器比手机那条
     `.hrow-main .fgroup .input{width:100%!important}` 优先级高，写在外面会把手机端也改小。 */
  /* 第 69 轮：他「电脑端楼层和楼栋之间空很大，户型/底价钥匙/户型图 怎么没和其他一列」——
     .fg-right 和 .fg-extra **各带一个 margin-left:auto**，两个「自动靠右」叠在一起，
     就把 楼层↔楼栋 撑出一个大空隙，后面那三样也被顶到旁边 ✗。
     电脑端两个 auto 都去掉：9 组条件**从左到右连续排**，多出来的空白留在最右边 ✓。 */
  .hrow-main .fg-right { margin-left: 0; }
  .hrow-main .fg-extra { margin-left: 0; }
  .hrow-main .fgroup {
    align-items: center;
    gap: 1px;
  }
  .hrow-main .flabel { font-size: 12px; }
  .hrow-main .fgroup > .flabel:first-child { margin-right: 8px; }
  .hrow-main .unit { font-size: 10px; color: var(--ink-3); }
  #hFloorMin, #hFloorMax { width: 42px !important; }
  #hBuilding { width: 46px !important; }
  #hStatus { width: 46px !important; }
  #hSort { width: 52px !important; }
  #hDistrict { width: 60px !important; }
  #hDecoration { width: 66px !important; }
  .hrow-main select.input {
    appearance: none;
    height: 32px;
    padding: 0 12px 0 4px;
    font-size: 11px;
    background-image:
      linear-gradient(45deg, transparent 50%, var(--ink-4) 50%),
      linear-gradient(135deg, var(--ink-4) 50%, transparent 50%);
    background-position: calc(100% - 7px) 50%, calc(100% - 3px) 50%;
    background-size: 4px 4px, 4px 4px;
    background-repeat: no-repeat;
  }
  #hExtraToggle {
    min-width: 54px !important;
    width: auto;
    height: 32px;
    padding: 0 6px;
    font-size: 13px;
  }
  .hrow-main #hImgMode { height: 32px; min-width: 0; padding: 0 4px; gap: 4px; font-size: 12px; }
  /* 第 64 轮：这么窄的框里，15.5px 的字 3 位数就顶出去了（实测「130」在 27px 文字区里刚好卡边），
     所以这些窄框在电脑端把字号降到 13px —— 手机端不动（那边框是拉开铺满的，字大点好点）。 */
  .search-wrap.narrow > .input { font-size: 13px !important; }
  .hrow-search .btn.tiny { padding: 0 8px; }
}

/* ⑤ 「图片列」是个**开关**（户型图 ↔ 实景图），不是查询条件 —— 给它开关的样子：
   一个小圆点 + 打开时有底色，鼠标放上去的 title 也说明了。 */
.btn.toggle { display: inline-flex; align-items: center; gap: 7px; }
.btn.toggle .tg-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ink-4); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.btn.toggle.on { border-color: var(--primary); color: var(--primary); background: var(--primary-weak, rgba(37, 99, 235, .08)); }
.btn.toggle.on .tg-dot { background: var(--primary); }

/* 第 60 轮：搜索框的「输入即联想」浮层（见 suggest.js）。
   他不要原生 datalist 那个黑色小三角，所以自己画一个列表：一边打字下面就直接列出来、点一下就填。
   浮层**挂在 body 上 + position:fixed** —— 筛选卡片自己有 overflow:hidden/auto，
   挂在输入框里面会被裁掉（这是排查过的一个坑）。 */
.suggest-box {
  position: fixed; z-index: 4000; min-width: 180px;
  background: var(--card, #fff); border: 1px solid var(--line, #e3e8ef); border-radius: 10px;
  box-shadow: 0 10px 28px rgba(16, 24, 40, .16); padding: 4px;
  max-height: 250px; overflow-y: auto; overscroll-behavior: contain;
}
.suggest-box .sg-item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 10px; border-radius: 7px; cursor: pointer; font-size: 14px; color: var(--ink, #1f2733);
}
.suggest-box .sg-item b { font-weight: 600; }
.suggest-box .sg-item i { font-style: normal; font-size: 12px; color: var(--ink-4, #8a93a3); flex: 0 0 auto; }
.suggest-box .sg-item:hover, .suggest-box .sg-item.on { background: var(--hover, #f2f5fa); }
.suggest-box .sg-more {
  padding: 7px 10px 5px; margin-top: 2px; border-top: 1px solid var(--line, #e3e8ef);
  font-size: 12px; color: var(--ink-4, #8a93a3); line-height: 1.35;
}

/* ==================================================================
   第 75 轮：客户页（卡片式 + 顶部固定 + 五个页签）+ 今日任务字体 + 详情页固定头
   他这轮的原话（5 条里的 1/3/4/5）：客户列表要卡片式；详情页「从客户名称一直到备注版本
   都固定住，只滑动客户档案和跟进记录」；今日任务「提醒字体有点小，我指的是里面的内容」；
   客户页「只看跟进中/新客户/返回 要和 客户/共N个客户 一行；私客 公客 公客池 加 无效 已成交
   一行；下面的提示不要；搜索框往上去；滑动的时候保持不动 只滑动内容」。
   ================================================================== */

/* ---- ① 顶部这一整块沾在顶上（搜索框搬进来了）：只滑下面的列表 ---- */
.cust-top {
  position: sticky; top: 0; z-index: 30;
  /* ⚠️ 必须是**不透明**的底色：透明的话列表会从底下透出来（sticky 的经典坑） */
  background: var(--bg, #f5f7fa);
  padding-bottom: 8px; margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
  box-shadow: 0 3px 10px rgba(16, 24, 40, .05);
}
.cust-search { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 8px 0 2px; }
.cust-search .search-wrap { flex: 0 1 340px; min-width: 150px; }
/* ★★★ 第 128 轮（他 2026-10-16）：「**客户**端搜索框拉长到跟**电话**对齐。**只限电脑端**」——
   客户表那几列是**固定 px**：姓名 130 ＋ 阶段/标记 210 ＋ **电话 136** ＝ **476px** ⇒ 框宽直接 476px
   （框的左边跟表格左边本来就齐，实测 258 / 259）。这里必须写 `flex-basis`：框宽是被上面那条
   `flex: 0 1 340px` 的 flex-basis 决定的，只写 width 不生效（第 128 轮踩过）。
   ⚠️ 手机端一个字不动（那边是 `.cust-search .search-wrap { flex: 1 1 auto }`，在下面那条手机档里）。 */
@media (min-width: 861px) {
  .cust-search .search-wrap { flex: 0 1 476px; width: 476px; }
}

/* ---- ② 客户卡片（手机端；桌面端仍是表格，两块都渲染、这里切显示） ---- */
.ccards { display: none; }
.ccard {
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 11px 12px; box-shadow: var(--shadow-sm); cursor: pointer;
}
.ccard:active { background: var(--hover); }
.ccard-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ccard-name { font-size: 16.5px; font-weight: 700; }
.ccard-kv { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 10px; margin-top: 8px; }
.ccard-kv > span { display: flex; gap: 6px; align-items: baseline; min-width: 0; }
.ccard-kv i { font-style: normal; color: var(--ink-4); font-size: 12px; flex: 0 0 auto; }
.ccard-kv b { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 备注**整段换行、不截断** —— 他报的就是「看不清楚后面的字」 */
.ccard-remark {
  margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--line-2);
  font-size: 13.5px; line-height: 1.55; color: var(--ink-2); overflow-wrap: anywhere;
}
.ccard-pick span { font-size: 12px; }

/* ---- ④ 跟进记录里那个「+ 添加客户跟进」**两端都藏掉** ----
   他第 75 轮先说"只保留上面的添加跟进"（当时我理解成只改手机），后来又明确指出：
   「电脑端的跟进记录的 +添加客户跟进 没删除掉，我的要求是**电脑端和手机端都只保留一个**，上面那个」。
   所以这条**不放在媒体查询里**（放进去就只管手机 —— 这正是我第一次做错的地方）。
   ⚠️ 只是 `display:none`：按钮还在 DOM 里，`body.querySelector('#btnAddFollow').onclick = …` 那行不用改。
   （每条记录后面的「删除」仍然只在**解锁后台**时才画、且只在手机端藏 —— 他没要求动电脑端那个。） */
.cd-modal #btnAddFollow { display: none; }

/* ---- ③ 今日任务：字体**整体放大** ----
   他先说「提醒字体有点小，我指的是里面的内容」，我放大了内容；他看后说「还是有点小，**整体放大**」——
   所以最终把面板尺寸、页签、日期、客户名、内容、按钮**一起**放大，
   值直接写在上面 `.rd-modal` 那一块里（**一处一值**，别再在这儿叠覆盖 —— 那正是我第一版的做法，
   结果两处尺寸打架、看代码的人不知道该信谁）。 */

@media (max-width: 860px) {
  /* ★★ 第 75 轮：手机上把 .view 的 overflow 放掉 —— 这是 sticky 能不能生效的关键。
     手机上真正滚动的是**窗口**（`.main` 在手机端已经是 `overflow: visible`），
     可 `.view` 还留着桌面那条 `overflow: auto`：它虽然**并不滚**（高度不被约束、scrollHeight == clientHeight），
     但浏览器会把"最近的滚动祖先"算成它 → 里面所有 `position: sticky`（我这轮的客户页顶块，
     以及第 69 轮房源页那块搜索/筛选）**全都钉不住**，一滑就跟着走（实测：滑 500px 后 top=-259）。
     放成 visible 之后，最近的滚动祖先回到窗口 → 它就正常钉住了。 */
  .view { overflow: visible; }

  /* 手机上顶栏自己也是 sticky（z-index 60），所以这块要**贴在顶栏下面**，
     不然会被顶栏盖住 —— 他要在滚到哪儿都能顺手搜索，盖住就白做了。 */
  /* 客户页上滑后只钉搜索行；客户标题、状态下拉、五个页签都随页面滚走。 */
  .cust-top { display: contents; }
  .cust-search {
    position: sticky;
    top: var(--m-topbar-h, var(--topbar-h, 48px));
    z-index: 29;
    padding: 7px 0;
    gap: 6px;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
    margin-bottom: 5px;
  }
  .cust-search .search-wrap { flex: 1 1 auto; min-width: 0; }
  .cust-search #cSearchBtn { display: none; }
  /* 他要的「一行」：客户 · 共 N 个客户 · 状态下拉 · 新客户 · 返回 */
  .page-head.cust-head { flex-wrap: nowrap; gap: 6px; margin-bottom: 8px; align-items: center; }
  .page-head.cust-head h1 { font-size: 19px; }
  .page-head.cust-head .ph-sub { font-size: 12px; white-space: nowrap; }
  .page-head.cust-head .ph-right { flex-wrap: nowrap; gap: 5px; margin-left: auto; }
  .page-head.cust-head .ph-right .input { height: 30px; padding: 0 6px; font-size: 12.5px; max-width: 104px; }
  .page-head.cust-head .ph-right .btn { height: 30px; padding: 0 9px; font-size: 12.5px; white-space: nowrap; }
  /* 五个页签一行放得下；万一放不下就自己横滑，不换行（他要"一行"） */
  .seg-tabs.cust-tabs { flex-wrap: nowrap; overflow-x: auto; gap: 4px; margin-bottom: 6px; }
  .seg-tabs.cust-tabs .seg-tab { padding: 0 10px; font-size: 13px; height: 30px; white-space: nowrap; flex: 0 0 auto; }

  /* 手机端：表格藏掉、卡片铺开 */
  table.tbl-cust { display: none; }
  .ccards { display: flex; flex-direction: column; gap: 10px; }

  /* 详情页：顶部（客户名称…备注版本）固定，只滑下面两块。
     上面第 1016~1092 行那套「窗口定高 + 两块各滚各的」本来就是对的，
     所以这里**只补**：① 整窗不许滚（矮屏那个兜底分支原来让它滚，头部就跟着走了）；
     ② 每条跟进后面的「删除」在手机上藏掉。
     ⚠️「+ 添加客户跟进」那个按钮的隐藏**不在这里** —— 他后来要求两端都藏，规则在文件末尾（非媒体查询里）。
     ⚠️ 别给 .cd2 加 overflow —— 那会让"单指在跟进记录上滑只动这一栏"的断言失效
     （.cd2 成了新的滚动容器）。矮屏需要它滚时，只在下面那个 max-height 分支里加。 */
  .cd-modal .modal-body { overflow: hidden; }
  .cd-modal .tl-del { display: none; }
  /* 手机上今日任务的字号：见上面 `.rd-modal ...` 那几行（第 75 轮整体放大那一段），
     这里不再叠一层覆盖 —— 一处一值。 */
}

/* 矮屏手机：窗口保持定高（顶部才固定得住），只把两栏高度放宽、让 .cd2 自己滚 */
@media (max-width: 860px) and (max-height: 780px) {
  .modal.cd-modal { height: calc(100dvh - 20px - var(--safe-top) - var(--safe-bottom)); }
  .cd-modal .modal-body { overflow: hidden; }
  .cd2 { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
  .cd2-right { flex: none; }
  .cd2-left .cd-scroll { max-height: 26vh; }
  .cd2-right .cd-scroll { height: 52vh !important; max-height: 52vh !important; flex: none !important; }
}

/* ================================================================
   ★★★ 第 113 轮 · 「绑定 / 管理」那个弹窗 ＋ 它里面那张二维码
   ------------------------------------------------------------------
   ⚠️ **这一段是纯新增**：上面 `.modal` / `.modal.wide` / `.modal-body` **一个字都没动** ——
     那几条是全站共用的，`.modal.wide` 还在第 112 轮被他明确**回退**过（手机端详情页在用）。
      这里只给「绑定」这一个弹窗新加一个类 `.qr-wide`，别的地方谁都不用。
   ------------------------------------------------------------------
   他 2026-10-12 的原话：「我解绑后重新绑，页面很小，我都扫不到，而且几秒钟就没有了。」
   他紧接着纠正的一句更关键：「**我就是电脑上的**……那个二维码，**还有窗口都特别小**，我根本扫不到」。
   追加一句：「**那个弹窗尽量大点**」—— 所以照"能多大就多大"来，不客气：
     · 弹窗放宽到 `min(96vw, 1100px)`、内容区 `max-height: 92vh`（原来 620px 的 `.modal`）；
     · 二维码放到 `min(70vh, 520px)` —— 电脑上隔半米也扫得动（原来写死 220×220）；
     · `.qr-bind-img` 给的只是**上限**：video.js 那边在图加载后量 `naturalWidth`，
       比展示尺寸小就把宽度收回去 —— **宁可小一点也不放大到糊**（他本来就嫌不清楚）；
       服务端那边同步把截图放大（`video-fetch.mjs` 的 `截二维码`：按长边 ~1040 像素反推 scale，3~4），
       让截图本身就够大，不靠前端拉伸。
   ================================================================ */
.modal.qr-wide { width: min(96vw, 1100px); }
.modal.qr-wide > .modal-body { max-height: 92vh; }
.qr-bind { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.qr-bind-img {
  width: min(70vh, 520px); height: auto; display: block;
  border: 1px solid var(--line-2); border-radius: 10px; background: #fff;
  cursor: zoom-in;
}
/* 「点图放大」那一层（video.js 的 `打开大图()` 自己插、自己删，没别的页面用它） */
.qr-lightbox {
  position: fixed; inset: 0; z-index: 400; background: rgba(12, 16, 22, .9);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 16px;
}
.qr-lightbox > img { width: min(92vw, 92vh); height: auto; background: #fff; border-radius: 10px; }
.qr-lightbox-bar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: center; }
/* 手机窄屏：退化成"接近整屏"，但**绝不撑出横向滚动条**（他第 112 轮定的硬口径）：
   overlay 有 8px 内边距，弹窗取 100% 也只是把那一圈留白吃掉，不会比视口宽。 */
@media (max-width: 860px) {
  .modal.qr-wide { width: 100%; }
  .modal.qr-wide > .modal-body { max-height: 88vh; padding: 14px; }
  .qr-bind-img { width: min(80vw, 520px); }
}

/* ================================================================
   ★★★ 第 114 轮 · 「绑定 / 管理」面板里那条**弹浏览器进度带**
   ------------------------------------------------------------------
   ⚠️ **这一段也是纯新增**：上面 `.modal` / `.modal.wide` / `.qr-wide` / `.qr-bind*`
      **一个字都没动**（第 113 轮那几条，手机端和别的弹窗还在用）。
      这里只给第 114 轮新加的三个类上样式：`.bd-actions` / `.bd-flow` / `.bd-flow-top` /
      `.bd-flow-btn`（都只出现在 `video.js` 的绑定面板里，别的地方谁都不用）。
   ------------------------------------------------------------------
   它要让他一眼看清两件事（他反复要的"别黑箱"）：
     · **已经等了多久**（真实秒数，从点按钮那一刻算）；
     · **这一次在等什么**（"正在起浏览器窗口…" / "窗口已经开好了，请在那个新窗口里登录…"）。
   所以：阶段徽标 ＋ 已等秒在第一行并排，说明文字在第二行（左对齐、能换行），
   网址和判据是小字第三/四行，三颗按钮排在最下面 —— **手机窄屏**只把按钮换行，绝不撑出横向滚动条。
   ================================================================ */
.bd-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bd-flow {
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg);
}
.bd-flow-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bd-flow-btn { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
@media (max-width: 860px) {
  .bd-flow-btn .btn { flex: 1 1 auto; }
}

/* ================================================================
   ★★ 2026-10-17 · 字号 − ／ ＋（他：客户页 / 房源页右上角，只针对内容区）
   ------------------------------------------------------------------
   上面第 67 行已经把 `#view` 的缩放因子接上了，这里补两件事：
     · **手机端不做**（这是他当面对我说的话：只做电脑端）⇒ 860px 以下钉回原样，
       顺带把那两颗按钮藏起来（`index.html` 里它们是默认 hidden，`app.js` 只在电脑端显）；
     · `#view` 是 `overflow:auto` 的滚动容器，`zoom` 之后它内部的可视宽度会按 1/zoom 折算
       ⇒ 高度同理，不会把页面的滚动搞坏，这里不需要额外补丁。
   ================================================================ */
@media (max-width: 860px) {
  #view { zoom: 1; }
  .zoom-group { display: none; }
}


/* ★★ 2026-10-17（他：「视频号点播放，看不了完整的，只显示一个小框」）：
   作品详情里的播放器**给一个稳定的宽高舞台**，视频按比例 contain 居中，不再按原始小尺寸缩在角落。
   · 桌面：占满弹窗宽度、上限 720 高；手机：9:16 竖屏，占满宽度。 */
.vp-stage {
  width: 100%; max-width: 100%; aspect-ratio: 16 / 9; max-height: 70vh;
  background: #000; border-radius: 8px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.vp-stage video { width: 100%; height: 100%; object-fit: contain; }
@media (max-width: 860px) {
  .vp-stage { aspect-ratio: 9 / 16; max-height: 70vh; border-radius: 6px; }
}


/* 来客直播评论（2026-10-18）：桌面左右分栏，手机上下堆叠 */
.lk-wrap { max-width: 1240px; margin: 0 auto; }
.lk-head { display: flex; gap: 16px; align-items: flex-start; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; }
.lk-head h1 { margin: 0; font-size: 30px; line-height: 1.2; }
.lk-sub { color: var(--ink-3); font-size: 14px; margin-top: 5px; }
.lk-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.lk-status { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; padding: 10px 12px; border: 1px solid var(--line-2); border-radius: 8px; background: #fff; margin-bottom: 14px; }
.lk-msg { color: var(--ink-3); font-size: 13px; }
.lk-grid { display: grid; grid-template-columns: minmax(260px, 34%) minmax(0, 1fr); gap: 14px; align-items: start; }
.lk-panel { border: 1px solid var(--line-2); border-radius: 8px; background: #fff; min-width: 0; overflow: hidden; }
.lk-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 13px 15px; border-bottom: 1px solid var(--line-2); }
.lk-room-list { max-height: 620px; overflow: auto; padding: 8px; }
.lk-room { display: flex; flex-direction: column; gap: 5px; width: 100%; text-align: left; border: 1px solid transparent; border-radius: 7px; padding: 11px 12px; background: transparent; cursor: pointer; color: inherit; }
.lk-room:hover { background: var(--hover); }
.lk-room.on { border-color: var(--primary-line); background: var(--primary-weak); }
.lk-room-title { font-weight: 600; line-height: 1.35; word-break: break-word; }
.lk-room-meta { color: var(--ink-3); font-size: 13px; }
.lk-comment-list { max-height: 620px; overflow: auto; padding: 8px; }
.lk-person { display: grid; grid-template-columns: 40px minmax(0, 1fr) 18px; gap: 11px; align-items: center; width: 100%; padding: 12px 10px; border: 1px solid transparent; border-radius: 9px; background: transparent; color: inherit; text-align: left; cursor: pointer; }
.lk-person:hover { background: var(--hover); border-color: var(--line-2); }
.lk-person:focus-visible { outline: 2px solid var(--primary-line); outline-offset: 1px; }
.lk-avatar { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: var(--primary-weak); color: var(--primary); font-weight: 700; }
.lk-person-main { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.lk-person-top { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.lk-person-latest { color: var(--ink); line-height: 1.45; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; word-break: break-word; }
.lk-person-meta { color: var(--ink-3); font-size: 12px; }
.lk-person-arrow { color: var(--ink-3); font-size: 24px; line-height: 1; }
.lk-comment { padding: 13px 0; border-bottom: 1px solid var(--line-2); }
.lk-comment:last-child { border-bottom: 0; }
.lk-comment-top { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 5px; }
.lk-comment-text { line-height: 1.65; word-break: break-word; white-space: pre-wrap; }
.lk-person-summary { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 4px 2px 14px; border-bottom: 1px solid var(--line-2); margin-bottom: 5px; }
.lk-person-summary span { color: var(--ink-3); font-size: 13px; }
.lk-person-comments { max-height: min(60vh, 560px); overflow: auto; }
.lk-person-comment { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 9px; padding: 13px 2px; border-bottom: 1px solid var(--line-2); }
.lk-person-comment:last-child { border-bottom: 0; }
.lk-comment-index { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--hover); color: var(--ink-3); font-size: 12px; }
.lk-comment-time { color: var(--ink-3); font-size: 12px; margin-top: 5px; }
.lk-clue { color: var(--orange, #d97706); font-weight: 600; }
.lk-empty { color: var(--ink-3); padding: 24px 12px; text-align: center; }
@media (max-width: 860px) {
  .lk-head h1 { font-size: 24px; }
  .lk-grid { grid-template-columns: 1fr; }
  .lk-room-list { max-height: 270px; }
  .lk-comment-list { max-height: none; }
  .lk-actions { width: 100%; }
  .lk-actions .btn { flex: 1; justify-content: center; }
}
.hq-multi{display:flex;gap:6px;flex-wrap:wrap;margin:0}.hq-chip{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--primary-line);background:var(--primary-weak);color:var(--primary);border-radius:7px;padding:3px 8px;font-size:13px;white-space:nowrap}.hq-chip button{border:0;background:transparent;color:inherit;font-size:16px;line-height:1;cursor:pointer;padding:0}

/* r161 续：选了多个小区后，标签必须在**搜索框自己的边框以内**。
   有标签时由外层 .search-wrap 画边框，输入框去掉自己的边框，和标签合成一个控件。 */
.search-wrap.has-multi {
  flex-wrap: wrap; gap: 4px 6px; align-items: center;
  min-height: 38px; padding: 4px 34px 4px 36px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: #fff;
  transition: border-color .15s, box-shadow .15s;
}
.search-wrap.has-multi:focus-within {
  border-color: var(--primary-line); box-shadow: 0 0 0 3px rgba(47, 107, 255, .1);
}
.search-wrap.has-multi > .input,
.search-wrap.has-multi > .input:focus {
  flex: 1 1 130px; min-width: 0; height: 28px;
  padding: 0 !important; border: 0 !important; box-shadow: none !important; background: transparent;
}
.search-wrap.has-multi > .hq-multi {
  flex: 1 0 100%; width: 100%; max-width: 100%; min-width: 0;
  flex-wrap: nowrap; overflow: hidden;
}
.search-wrap.has-multi .hq-chip {
  flex: 0 0 auto; white-space: nowrap; writing-mode: horizontal-tb;
}
.search-wrap.has-multi .hq-more { background: #eef2f8; color: var(--ink-2); border-color: var(--line); }
.search-wrap.has-multi > .si { top: 10px; left: 10px; }
.search-wrap.has-multi > .search-clear { top: 9px; right: 6px; }

/* 2026-10-19：视频管理顶部「采集节奏 / 保活状态」一行（桌面横排，手机自动折行） */
.vd-live {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 16px;
  margin: 0 4px 14px; padding: 9px 12px;
  border: 1px solid var(--line-2, #e3e8ef); border-radius: 10px;
  background: #f7f9fc; color: var(--ink-3, #5b6573); font-size: 12.5px;
}
.vd-live b { color: var(--ink, #1f2733); font-weight: 600; }
.vd-live:empty { display: none; }

/* ================================================================ 视频管理 · 方案 02
   电脑：顶部平台 + 左侧板块/页面；手机：2×2 平台 + 单行板块 + 单行页面。
   沿用原来的 #vdPlat / #vdBoard / #vdSub 事件与权限，只重排视觉层级。 */
.vd-page { padding-bottom: 24px; }
.vd-page-main { padding: 0 4px 24px; }
.vd-platform-card {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 14px;
  padding: 13px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--shadow);
}
.vd-nav-kicker {
  flex: none;
  color: var(--ink-4);
  font-size: 11px;
  letter-spacing: .06em;
}
.vd-platform-card #vdPlat {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}
.vd-platform-card #vdPlat .seg-tab {
  min-height: 36px;
  padding: 6px 16px;
  border-radius: 8px;
}
.vd-workspace {
  display: grid;
  grid-template-columns: 218px minmax(0, 1fr);
  align-items: start;
  gap: 14px;
}
.vd-workspace #vdBody { min-width: 0; min-height: 360px; }
.vd-workspace #vdLower[hidden] + #vdBody { grid-column: 1 / -1; }
.vd-nav-side {
  min-width: 0;
  min-height: 360px;
  padding: 13px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--shadow);
}
.vd-nav-title {
  display: flex;
  align-items: baseline;
  gap: 7px;
  padding: 1px 7px 10px;
  border-bottom: 1px solid var(--line-2);
}
.vd-nav-title span {
  color: var(--ink);
  font-size: 13px;
  font-weight: 700;
}
.vd-nav-title small {
  color: var(--ink-4);
  font-size: 9px;
}
.vd-nav-group { padding-top: 10px; }
.vd-nav-side .vd-nav-kicker { padding: 0 7px 5px; }
.vd-nav-side .seg-tabs {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}
.vd-nav-side .seg-tab {
  width: 100%;
  min-height: 36px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 7px 10px;
  border-color: transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-3);
  text-align: left;
}
.vd-nav-side .seg-tab:hover { background: var(--bg-2); }
.vd-nav-side .seg-tab.on {
  border-color: color-mix(in srgb, var(--primary) 22%, var(--line));
  background: color-mix(in srgb, var(--primary-weak) 78%, var(--card));
  color: var(--primary);
  font-weight: 700;
}
.vd-nav-side #vdBindBox { margin-top: 8px; }
.vd-nav-side #vdBindBox .seg-tabs { margin-top: 4px; }
.vd-nav-side #vdBindBox .seg-tab { font-size: 12px; }

@media (max-width: 860px) {
  .vd-page-main { padding: 0 2px 20px; }
  .vd-platform-card {
    display: block;
    padding: 11px;
    margin-bottom: 10px;
  }
  .vd-platform-card .vd-nav-kicker {
    display: block;
    margin: 0 2px 7px;
  }
  .vd-platform-card #vdPlat {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }
  .vd-platform-card #vdPlat .seg-tab {
    width: 100%;
    min-width: 0;
    min-height: 42px;
    padding: 7px 6px;
    white-space: nowrap;
  }
  .vd-workspace {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }
  .vd-workspace #vdBody { grid-column: 1 / -1; }
  .vd-workspace #vdBody { min-height: 320px; }
  .vd-nav-side { padding: 11px 9px; min-height: 224px; }
  .vd-nav-title { padding: 0 5px 8px; }
  .vd-nav-title small { display: none; }
  .vd-nav-group { padding-top: 8px; }
  .vd-nav-side .vd-nav-kicker { padding: 0 5px 5px; }
  .vd-nav-side #vdBoard,
  .vd-nav-side #vdSub,
  .vd-nav-side #vdBind {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 5px;
  }
  .vd-nav-side #vdBoard .seg-tab,
  .vd-nav-side #vdSub .seg-tab,
  .vd-nav-side #vdBind .seg-tab {
    min-width: 0;
    min-height: 42px;
    justify-content: center;
    padding: 6px 4px;
    text-align: center;
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .vd-nav-side #vdBindBox .small.muted { margin: 7px 4px 5px !important; }
  .vd-nav-side #vdSubBox { min-height: 89px; }
}

/* ================================================================ 视频管理 · 方案 02
   电脑：顶部平台 + 左侧板块/页面；手机：2×2 平台 + 单行板块 + 单行页面。
   仍沿用原来的 #vdPlat / #vdBoard / #vdSub 事件与权限，只改布局层级。 */
.vd-page { padding-bottom: 24px; }
.vd-page-main { padding: 0 4px 24px; }
.vd-platform-card {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 14px;
  padding: 13px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--shadow);
}
.vd-nav-kicker {
  flex: none;
  color: var(--ink-4);
  font-size: 11px;
  letter-spacing: .06em;
}
.vd-platform-card #vdPlat {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}
.vd-platform-card #vdPlat .seg-tab {
  min-height: 36px;
  padding: 6px 16px;
  border-radius: 8px;
}
.vd-workspace {
  display: grid;
  grid-template-columns: 218px minmax(0, 1fr);
  align-items: start;
  gap: 14px;
}
.vd-workspace #vdBody { min-width: 0; }
.vd-workspace #vdLower[hidden] + #vdBody { grid-column: 1 / -1; }
.vd-nav-side {
  min-width: 0;
  padding: 13px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--shadow);
}
.vd-nav-title {
  display: flex;
  align-items: baseline;
  gap: 7px;
  padding: 1px 7px 10px;
  border-bottom: 1px solid var(--line-2);
}
.vd-nav-title span {
  color: var(--ink);
  font-size: 13px;
  font-weight: 700;
}
.vd-nav-title small {
  color: var(--ink-4);
  font-size: 9px;
}
.vd-nav-group { padding-top: 10px; }
.vd-nav-side .vd-nav-kicker { padding: 0 7px 5px; }
.vd-nav-side .seg-tabs {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}
.vd-nav-side .seg-tab {
  width: 100%;
  min-height: 36px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 7px 10px;
  border-color: transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-3);
  text-align: left;
}
.vd-nav-side .seg-tab:hover { background: var(--bg-2); }
.vd-nav-side .seg-tab.on {
  border-color: color-mix(in srgb, var(--primary) 22%, var(--line));
  background: color-mix(in srgb, var(--primary-weak) 78%, var(--card));
  color: var(--primary);
  font-weight: 700;
}
.vd-nav-side #vdBindBox { margin-top: 8px; }
.vd-nav-side #vdBindBox .seg-tabs { margin-top: 4px; }
.vd-nav-side #vdBindBox .seg-tab { font-size: 12px; }

@media (max-width: 860px) {
  .vd-page-main { padding: 0 2px 20px; }
  .vd-platform-card {
    display: block;
    padding: 11px;
    margin-bottom: 10px;
  }
  .vd-platform-card .vd-nav-kicker {
    display: block;
    margin: 0 2px 7px;
  }
  .vd-platform-card #vdPlat {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }
  .vd-platform-card #vdPlat .seg-tab {
    width: 100%;
    min-width: 0;
    min-height: 42px;
    padding: 7px 6px;
    white-space: nowrap;
  }
  .vd-workspace {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }
  .vd-workspace #vdBody { grid-column: 1 / -1; }
  .vd-nav-side {
    padding: 11px 9px;
  }
  .vd-nav-title { padding: 0 5px 8px; }
  .vd-nav-title small { display: none; }
  .vd-nav-group { padding-top: 8px; }
  .vd-nav-side .vd-nav-kicker { padding: 0 5px 5px; }
  .vd-nav-side #vdBoard,
  .vd-nav-side #vdSub,
  .vd-nav-side #vdBind {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 5px;
  }
  .vd-nav-side #vdBoard .seg-tab,
  .vd-nav-side #vdSub .seg-tab,
  .vd-nav-side #vdBind .seg-tab {
    min-width: 0;
    min-height: 42px;
    justify-content: center;
    padding: 6px 4px;
    text-align: center;
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .vd-nav-side #vdBindBox .small.muted { margin: 7px 4px 5px !important; }
}

/* ================================================================
   r236 · 视频管理新框架
   字号/颜色沿用现有主题；主页面切换完全复用“设置”页的分段条：
   一条外层白底，内部四项等宽，选中项深色实底。
   ================================================================ */
.vd-page {
  --vd-panel-gap: 14px;
  padding-bottom: 24px;
}
.vd-hero {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 22px;
  padding: 20px 22px;
  border-radius: 16px;
  color: #f8fbf7;
  /* 旧版 Edge 若不认 color-mix，下面的复杂 background 会整条失效；
     先给纯色兜底，避免白底白字。 */
  background-color: #123f37;
  background-image:
    radial-gradient(circle at 86% 8%, color-mix(in srgb, var(--gold-soft) 38%, transparent), transparent 32%),
    linear-gradient(135deg, #123f37, #0b2e29 72%);
  box-shadow: var(--shadow-sm);
}
.vd-hero-copy { min-width: 0; }
.vd-hero h1 {
  margin: 2px 0 3px;
  color: #fffaf0;
  font-size: 28px;
  line-height: 1.2;
}
.vd-hero p {
  margin: 0;
  color: rgba(248, 251, 247, .68);
  font-size: 13px;
}
.vd-kicker {
  color: #e5c97f;
  font-size: 10px;
  letter-spacing: .16em;
}
.vd-hero-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 7px;
  flex-wrap: wrap;
  margin-left: auto;
}
.vd-hero-actions .btn {
  min-height: 36px;
  border-color: rgba(255, 255, 255, .18);
  color: #f8fbf7;
  background: rgba(255, 255, 255, .08);
}
.vd-hero-actions .btn.primary {
  border-color: #e5c97f;
  color: #1f2d26;
  background: #e5c97f;
}
.vd-page-main { padding: 14px 4px 24px; }
.vd-page .vd-live {
  min-height: 0;
  margin: 0 0 12px;
  padding: 0 2px;
}
.seg-tabs.set-menu.vd-main-switch {
  display: flex;
  grid-template-columns: none;
  gap: 0;
  margin: 0 0 12px;
  padding: 4px;
  border-radius: 12px;
  background: var(--card);
  box-shadow: var(--shadow-sm);
}
.seg-tabs.set-menu.vd-main-switch .seg-tab {
  flex: 1 1 0;
  min-width: 0;
  height: 43px;
  border: 0;
  border-radius: 8px;
  color: var(--ink-3);
  background: transparent;
  box-shadow: none;
  font-size: 14px;
  font-weight: 600;
}
.seg-tabs.set-menu.vd-main-switch .seg-tab.on {
  color: #fff;
  background: var(--primary);
  box-shadow: none;
}
.vd-platform-card {
  margin-bottom: 10px;
  padding: 9px 12px;
  border-radius: 11px;
  box-shadow: none;
}
.vd-platform-card #vdPlat .seg-tab {
  min-height: 32px;
  padding: 5px 13px;
  font-size: 13px;
}
.vd-bind-strip:empty { display: none; }
.vd-bind-strip {
  margin-bottom: 10px;
  padding: 0 2px;
}
.vd-bind-strip .small.muted { margin: 0 0 5px !important; }
.vd-bind-strip #vdBind .seg-tab { min-height: 30px; padding: 4px 10px; font-size: 12px; }
.vd-quick-tabs:empty { display: none; }
.vd-quick-tabs { margin-bottom: 12px; }
.vd-quick-tabs .vd-sub-switch {
  display: flex;
  grid-template-columns: none;
  gap: 0;
  margin: 0;
  padding: 4px;
  border-radius: 11px;
  background: var(--card);
  box-shadow: none;
}
.vd-quick-tabs .vd-sub-switch .seg-tab {
  flex: 1 1 0;
  height: 37px;
  border: 0;
  border-radius: 8px;
  color: var(--ink-3);
  background: transparent;
  box-shadow: none;
  font-size: 13px;
  font-weight: 600;
}
.vd-quick-tabs .vd-sub-switch .seg-tab.on {
  color: #fff;
  background: var(--primary);
  box-shadow: none;
}
.vd-workspace.vd-workspace-main {
  display: block;
  min-height: 0;
}
.vd-workspace-main #vdLower[hidden] { display: none !important; }
.vd-workspace-main #vdBody {
  min-height: 320px;
}
.vd-overview { display: grid; gap: var(--vd-panel-gap); }
.vd-overview > .card,
.vd-overview-cols > .card {
  width: 100%;
  min-width: 0;
  margin: 0;
}
.vd-overview-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.vd-overview-stat {
  min-width: 0;
  padding: 13px 15px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  box-shadow: var(--shadow-sm);
}
.vd-overview-stat > span { display: block; color: var(--ink-3); font-size: 12px; }
.vd-overview-stat > b { display: block; margin: 2px 0; font-size: 24px; line-height: 1.25; font-variant-numeric: tabular-nums; }
.vd-overview-stat > small { display: block; overflow: hidden; color: var(--ink-4); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.vd-overview-cols {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(240px, .8fr);
  gap: var(--vd-panel-gap);
}
.vd-overview-priority,
.vd-overview-side,
.vd-overview-videos {
  box-shadow: var(--shadow-sm);
}
.vd-section-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.vd-section-head > div { min-width: 0; }
.vd-section-head b { display: block; font-size: 15px; }
.vd-section-head span { display: block; color: var(--ink-4); font-size: 11px; }
.vd-section-head .btn { margin-left: auto; white-space: nowrap; }
.vd-priority-list { display: grid; }
.vd-priority-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 3px;
  border: 0;
  border-bottom: 1px solid var(--line-2);
  color: var(--ink);
  background: transparent;
  text-align: left;
}
.vd-priority-row:last-child { border-bottom: 0; }
.vd-priority-row:hover { background: var(--hover); }
.vd-priority-avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: var(--primary);
  background: var(--primary-weak);
  font-size: 12px;
  font-weight: 700;
}
.vd-priority-main { min-width: 0; }
.vd-priority-title { display: flex; align-items: center; gap: 6px; min-width: 0; }
.vd-priority-title b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vd-priority-text {
  display: block;
  overflow: hidden;
  color: var(--ink-3);
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vd-priority-time { color: var(--ink-4); font-size: 10px; white-space: nowrap; }
.vd-account-mini-list { display: grid; }
.vd-account-mini {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 0;
  border-bottom: 1px dashed var(--line-2);
}
.vd-account-mini:last-child { border-bottom: 0; }
.vd-account-mini > span:last-child { min-width: 0; }
.vd-account-mini b { display: block; overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
.vd-account-mini small { display: block; color: var(--ink-4); font-size: 10px; }
.vd-account-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; }
.vd-account-dot.ok { background: var(--success, #348565); box-shadow: 0 0 0 3px color-mix(in srgb, var(--success, #348565) 14%, transparent); }
.vd-account-dot.warn { background: var(--warning, #c1852b); }
.vd-laike-mini { margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid var(--line-2); }
.vd-mini-video-list { display: grid; }
.vd-mini-video {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 70px 70px;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 10px 2px;
  border: 0;
  border-bottom: 1px solid var(--line-2);
  color: var(--ink);
  background: transparent;
  text-align: left;
}
.vd-mini-video:last-child { border-bottom: 0; }
.vd-mini-video > span:nth-child(2) { min-width: 0; }
.vd-mini-video > span:nth-child(2) b { display: block; overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
.vd-mini-video > span:nth-child(2) small { display: block; color: var(--ink-4); font-size: 10px; }
.vd-mini-thumb {
  display: grid;
  place-items: center;
  width: 52px;
  height: 35px;
  border-radius: 7px;
  color: #f7e4b2;
  background: linear-gradient(135deg, #173e36, #315a4e);
  font-size: 10px;
}
.vd-mini-metric { text-align: right; }
.vd-mini-metric b { display: block; font-size: 12px; font-variant-numeric: tabular-nums; }
.vd-mini-metric small { display: block; color: var(--ink-4); font-size: 9px; }

@media (max-width: 860px) {
  .vd-hero {
    align-items: flex-start;
    flex-direction: column;
    padding: 17px;
  }
  .vd-hero h1 { font-size: 24px; }
  .vd-hero-actions { width: 100%; justify-content: flex-start; margin-left: 0; }
  .vd-hero-actions .btn { flex: 1 1 auto; }
  .vd-page-main { padding: 10px 2px 20px; }
  .seg-tabs.set-menu.vd-main-switch { padding: 3px; }
  .seg-tabs.set-menu.vd-main-switch .seg-tab {
    height: 39px;
    padding: 0 3px;
    font-size: 11px;
    white-space: nowrap;
  }
  .vd-platform-card #vdPlat {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .vd-overview-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
  .vd-overview-stat { padding: 10px 9px; }
  .vd-overview-stat > b { font-size: 19px; }
  .vd-overview-stat > small { font-size: 9px; }
  .vd-overview-cols { grid-template-columns: 1fr; }
  .vd-mini-video { grid-template-columns: 44px minmax(0, 1fr) 52px; }
  .vd-mini-thumb { width: 44px; height: 32px; }
  .vd-mini-video .vd-mini-metric:last-child { display: none; }
}

/* r215：随行卡（今日任务最小化后）里的电话做成可点的拨号链接 —— 跟普通链接同色系但不刺眼。 */
.cd-dock-tel {
  color: var(--ink, #1c2430); text-decoration: none;
  border-bottom: 1px dashed color-mix(in srgb, var(--primary) 55%, transparent);
  position: relative; z-index: 2; cursor: pointer; pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
}
.cd-dock-sub .cd-dock-tel { display: inline-block; padding: 1px 2px; }
.cd-dock-tel:hover { color: var(--primary, #2f6fed); border-bottom-color: var(--primary, #2f6fed); }
.cd-dock-wechat { display: inline-block; color: var(--ink-3); font-size: 12px; }
/* r219：号码放大方便看/复制；旁边「复制」小按钮；待办字样跟在后面 */
.cd-dock-tel { font-size: 19px; font-weight: 600; letter-spacing: .02em; }
.cd-dock-copy {
  margin-left: 6px; padding: 2px 8px; border-radius: 6px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--primary) 40%, transparent);
  background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--primary);
  font-size: 12px;
}
.cd-dock-copy:hover { background: color-mix(in srgb, var(--primary) 20%, transparent); }
.cd-dock-rem { font-size: 12px; color: var(--muted, #6b7684); margin-left: 6px; }

/* ================================================================ r217 · 侧边栏完全隐藏（照 Codex）
   箭头钉在左边缘；侧栏显示时贴侧栏右缘，隐藏时贴屏幕左缘；
   点一下整条滑出（width→0），再点滑回；状态记本机；手机端不启用。 */
.side-edge-toggle {
  position: fixed; left: var(--sidebar-w); top: 50%; transform: translate(-50%, -50%);
  z-index: 60; width: 22px; height: 44px; border: none; cursor: pointer;
  background: var(--side-bg, #1f2b3a); color: #fff;
  border-radius: 0 10px 10px 0;
  display: inline-flex; align-items: center; justify-content: center;
  transition: left .2s ease, background .16s;
  box-shadow: 2px 0 10px rgba(0,0,0,.18);
}
.side-edge-toggle svg { width: 15px; height: 15px; transition: transform .2s ease; }
.side-edge-toggle:hover { background: color-mix(in srgb, var(--side-bg) 84%, #fff); }
.app-shell.side-hidden .side-edge-toggle { left: 0; transform: translate(0, -50%); }
.app-shell.side-hidden .side-edge-toggle svg { transform: rotate(180deg); }
.app-shell.side-hidden .sidebar {
  width: 0; padding-left: 0; padding-right: 0; overflow: hidden;
  opacity: 0; pointer-events: none;
  transition: width .2s ease, opacity .16s ease;
}
@media (max-width: 860px) {
  .side-edge-toggle { display: none; }
}

/* ================================================================ 客户 -> 线索池（2026-10-25）
   不占左侧总菜单。切换条复用设置页的 .seg-tabs.set-menu；
   线索行按“来源 / 人 / 意向 / 核对与动作”排，手机自动改纵向卡片。 */
.seg-tabs.cust-area-tabs {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.lead-page-head { align-items: flex-start; }
.lead-summary {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 14px;
}
.lead-metric {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 64px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--shadow-sm);
}
.lead-metric span { color: var(--ink-3); font-size: 13px; }
.lead-metric b { color: var(--ink); font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.lead-pool-card { overflow: hidden; }
.lead-pool-card > .card-body { padding: 0; }
.lead-toolbar { padding: 12px 14px 0; }
.seg-tabs.set-menu.lead-status-tabs {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-bottom: 0 !important;
}
.lead-status-tabs .seg-tab {
  min-width: 0;
  padding-left: 6px;
  padding-right: 6px;
  white-space: nowrap;
}
.lead-search-row {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-2);
}
.lead-search-row .input { width: min(360px, 100%); }
.lead-list { display: block; }
.lead-row {
  display: grid;
  grid-template-columns: minmax(125px, .8fr) minmax(190px, 1.25fr) minmax(210px, 1.35fr) minmax(190px, 1fr);
  gap: 14px;
  align-items: center;
  padding: 14px;
  border-bottom: 1px solid var(--line-2);
}
.lead-row:last-child { border-bottom: 0; }
.lead-row:hover { background: var(--hover); }
.lead-person { min-width: 0; }
.lead-name {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
  font-size: 14px;
  font-weight: 700;
}
.lead-time { margin-top: 4px; color: var(--ink-3); font-size: 11px; }
.lead-source { min-width: 0; }
.lead-source-main { display: block; color: var(--primary); font-size: 12px; font-weight: 700; }
.lead-source-detail {
  display: -webkit-box; margin-top: 4px; overflow: hidden; color: var(--ink-3);
  font-size: 11px; line-height: 1.45; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.lead-intent { min-width: 0; color: var(--ink-2); font-size: 12px; line-height: 1.55; word-break: break-word; }
.lead-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.lead-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex-wrap: wrap;
  min-width: 0;
}
.lead-phone { color: var(--ink-2); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lead-form { display: grid; gap: 12px; }
.lead-form .field label { display: block; margin-bottom: 5px; color: var(--ink-3); font-size: 13px; }
.lead-form .field .input { width: 100%; }
@media (max-width: 860px) {
  .lead-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lead-metric { min-height: 56px; padding: 10px 11px; }
  .lead-metric b { font-size: 21px; }
  .lead-row {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 9px 10px;
    padding: 12px;
  }
  .lead-person { grid-column: 1; }
  .lead-source { grid-column: 1; }
  .lead-intent { grid-column: 1 / -1; }
  .lead-actions { grid-column: 1 / -1; justify-content: flex-start; padding-top: 3px; }
  .lead-page-head .ph-right { width: 100%; justify-content: flex-start; }
  .lead-status-tabs { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
  .lead-status-tabs .seg-tab {
    padding-left: 3px;
    padding-right: 3px;
    font-size: 12px;
    letter-spacing: 0;
  }
  .lead-search-row .input { width: 100%; }
}
