/* ==========================================================================
   企业协同管理平台 — 样式表
   零外部依赖，全部自托管
   ========================================================================== */

:root{
  --brand:#4f46e5;
  --brand-dark:#4338ca;
  --brand-soft:#eef2ff;
  --ink:#1a1d29;
  --ink-2:#4b5268;
  --ink-3:#8a90a6;
  --line:#e7e9f2;
  --line-2:#eef0f7;
  --bg:#f5f6fb;
  --card:#ffffff;
  --ok:#059669;
  --warn:#d97706;
  --bad:#dc2626;
  --info:#2563eb;
  --sidebar-1:#191c2b;
  --sidebar-2:#232741;
  --radius:12px;
  --shadow:0 1px 2px rgba(20,24,45,.05), 0 4px 16px rgba(20,24,45,.04);
  --shadow-lg:0 8px 40px rgba(20,24,45,.10);

  /* 顶部安全区高度：浏览器 / iOS 主屏 PWA 用系统安全区；
     App 壳（uni-app web-view）里安卓的 env(safe-area-inset-top) 恒为 0，
     由 layout.php 头部的脚本按壳给的真实像素改写这个变量。
     ⚠ 所有「让出顶部」的地方只认这一个变量，不要再直接写 env()。 */
  --sb:env(safe-area-inset-top, 0px);
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Microsoft YaHei","PingFang SC",Roboto,"Helvetica Neue",Arial,sans-serif;
  font-size:14px;
  line-height:1.6;
  color:var(--ink);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
}
a{color:var(--brand);text-decoration:none}
a:hover{color:var(--brand-dark)}
h1,h2,h3,h4{margin:0;font-weight:600;letter-spacing:-.01em}
input,select,textarea,button{font-family:inherit;font-size:inherit}
.ico{flex:none;display:block}
.dim{color:var(--ink-3)}
.mono{font-family:ui-monospace,SFMono-Regular,Consolas,"Courier New",monospace}

/* ============================ 应用外壳 ============================ */
.shell{display:flex;min-height:100vh}

.sidebar{
  width:232px;flex:none;
  background:linear-gradient(170deg,var(--sidebar-1),var(--sidebar-2) 65%,#2a1f4d);
  color:#c9cde0;
  display:flex;flex-direction:column;
  position:sticky;top:0;height:100vh;
  border-right:1px solid rgba(255,255,255,.05);
}
.brand{
  display:flex;align-items:center;gap:10px;
  padding:18px 16px 16px;color:#fff;
  border-bottom:1px solid rgba(255,255,255,.07);
}
.brand:hover{color:#fff}
.brand-mark{
  width:34px;height:34px;border-radius:10px;flex:none;
  background:linear-gradient(135deg,#6366f1,#a855f7);
  display:flex;align-items:center;justify-content:center;color:#fff;
  box-shadow:0 4px 14px rgba(99,102,241,.45);
}
.brand-text{display:flex;flex-direction:column;line-height:1.25;overflow:hidden}
.brand-text b{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.brand-text small{font-size:11px;color:#8b91ad;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.nav{flex:1;overflow-y:auto;padding:10px 10px 16px}
.nav::-webkit-scrollbar{width:6px}
.nav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.12);border-radius:3px}
.nav-group{
  font-size:11px;color:#6d7391;
  padding:11px 10px 5px;letter-spacing:.06em;
}
.nav-item{
  display:flex;align-items:center;gap:9px;
  padding:7px 10px;border-radius:8px;color:#b9bfd6;
  font-size:13px;transition:.15s;margin-bottom:1px;
}
.nav-item:hover{background:rgba(255,255,255,.06);color:#fff}
.nav-item.active{
  background:linear-gradient(90deg,rgba(99,102,241,.28),rgba(99,102,241,.10));
  color:#fff;
  box-shadow:inset 0 0 0 1px rgba(129,140,248,.28);
}
.nav-item.active .ico{color:#a5b4fc}

/* 侧栏「讨论」的未读数：和底部 Tab 红点同一套数据（v1.21.1） */
.nav-dot{
  margin-left:auto;flex:none;min-width:18px;height:18px;padding:0 5px;
  border-radius:9px;background:var(--bad);color:#fff;
  font-size:10.5px;font-style:normal;line-height:18px;text-align:center;font-weight:600;
}

.sidebar-foot{
  border-top:1px solid rgba(255,255,255,.07);
  padding:12px 12px;display:flex;align-items:center;gap:10px;
}
.me{display:flex;align-items:center;gap:9px;flex:1;overflow:hidden}
.avatar{
  width:32px;height:32px;border-radius:9px;flex:none;
  background:linear-gradient(135deg,#4f46e5,#7c3aed);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;
}
.me-info{display:flex;flex-direction:column;line-height:1.25;overflow:hidden}
.me-info b{font-size:13px;color:#e8eaf5;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.me-info small{font-size:11px;color:#7d84a3}
.logout{color:#8b91ad;padding:6px;border-radius:6px}
.logout:hover{background:rgba(255,255,255,.08);color:#fff}

.main{flex:1;min-width:0;display:flex;flex-direction:column}
.topbar{
  height:60px;flex:none;display:flex;align-items:center;justify-content:space-between;
  padding:0 24px;background:rgba(255,255,255,.85);backdrop-filter:blur(8px);
  border-bottom:1px solid var(--line);position:sticky;top:0;z-index:20;
}
.page-title{font-size:17px;font-weight:600}
.topbar-actions{display:flex;gap:6px}
.icon-btn{
  width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;
  color:var(--ink-2);border:1px solid transparent;
}
.icon-btn:hover{background:var(--brand-soft);color:var(--brand);border-color:#e0e5ff}

.content{padding:22px 24px 8px;flex:1;max-width:1600px;width:100%}
.foot{padding:16px 24px 22px;color:var(--ink-3);font-size:12px}

/* ============================ 通用元素 ============================ */
.card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);
}
.card-head{
  padding:15px 18px;border-bottom:1px solid var(--line-2);
  display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
}
.card-head h3{font-size:15px}
.card-body{padding:18px}
.card-foot{padding:14px 18px;border-top:1px solid var(--line-2);background:#fbfcfe;border-radius:0 0 var(--radius) var(--radius)}

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  height:34px;padding:0 14px;border-radius:8px;border:1px solid var(--line);
  background:#fff;color:var(--ink-2);cursor:pointer;font-size:13.5px;
  transition:.15s;white-space:nowrap;text-decoration:none;
}
.btn:hover{border-color:#cfd4e6;background:#fafbff;color:var(--ink)}
.btn-primary{
  background:var(--brand);border-color:var(--brand);color:#fff;font-weight:500;
  box-shadow:0 2px 8px rgba(79,70,229,.28);
}
.btn-primary:hover{background:var(--brand-dark);border-color:var(--brand-dark);color:#fff}
.btn-danger{color:var(--bad);border-color:#f3c9c9;background:#fff8f8}
.btn-danger:hover{background:#fdecec;border-color:#e9a8a8;color:#b91c1c}
.btn-ghost{background:transparent;border-color:transparent;color:var(--ink-3)}
.btn-ghost:hover{background:var(--line-2);color:var(--ink)}
.btn-sm{height:28px;padding:0 10px;font-size:12.5px;border-radius:7px}
.btn-block{width:100%;height:40px}
.btn[disabled]{opacity:.5;cursor:not-allowed}

.alert{
  border-radius:10px;padding:11px 14px;margin-bottom:14px;font-size:13.5px;
  border:1px solid transparent;
}
.alert-success{background:#ecfdf5;border-color:#b7ebd2;color:#065f46}
.alert-error{background:#fef2f2;border-color:#f5c6c6;color:#991b1b}
.alert-info{background:#eff6ff;border-color:#c7dcfb;color:#1e40af}
.alert-warn{background:#fffbeb;border-color:#fae2ab;color:#92400e}

.badge{
  display:inline-block;padding:2px 9px;border-radius:999px;font-size:12px;line-height:1.6;
  background:#f1f3fa;color:var(--ink-2);border:1px solid transparent;white-space:nowrap;
}
.b-gray{background:#f1f3f9;color:#5b6279;border-color:#e6e9f2}
.b-green{background:#e9f9f1;color:#047857;border-color:#c3eeda}
.b-blue{background:#eaf2fe;color:#1d4ed8;border-color:#c9dcfb}
.b-amber{background:#fef6e7;color:#b45309;border-color:#f8e3b7}
.b-red{background:#fdeeee;color:#b91c1c;border-color:#f5cccc}
.b-purple{background:#f3efff;color:#6d28d9;border-color:#e0d5fd}

/* ============================ 表格 ============================ */
.table-wrap{overflow-x:auto;border-radius:0 0 var(--radius) var(--radius)}
table.grid{width:100%;border-collapse:collapse;font-size:13.5px}
table.grid thead th{
  text-align:left;padding:10px 14px;background:#fafbfe;color:var(--ink-3);
  font-weight:500;font-size:12.5px;border-bottom:1px solid var(--line);
  white-space:nowrap;position:sticky;top:0;
}
table.grid thead th a{color:inherit}
table.grid thead th a:hover{color:var(--brand)}
table.grid tbody td{
  padding:11px 14px;border-bottom:1px solid var(--line-2);vertical-align:middle;
}
table.grid tbody tr:last-child td{border-bottom:none}
table.grid tbody tr:hover{background:#fbfcff}
table.grid td.num{text-align:right;font-variant-numeric:tabular-nums}
table.grid td.act{text-align:right;white-space:nowrap}
/*
 * 操作列吸附右侧
 * 列多的模块（发票、合同、销售）在 1366/1440 宽屏下必然横向滚动，
 * 若不吸附，「详情/编辑/删除」会被滑出视野，用户以为没有操作入口。
 */
table.grid thead th:last-child{right:0;z-index:3}
table.grid tbody td.act{position:sticky;right:0;background:#fff;z-index:2;
  border-left:1px solid var(--line-2);box-shadow:-8px 0 10px -8px rgba(15,23,42,.22)}
table.grid thead th:last-child{border-left:1px solid var(--line);
  box-shadow:-8px 0 10px -8px rgba(15,23,42,.16)}
table.grid td.act .row-actions{gap:2px}
table.grid td.act .btn-sm{padding:4px 6px}
table.grid tbody tr:hover td.act{background:#fbfcff}
table.grid .empty{text-align:center;color:var(--ink-3);padding:46px 0}
.row-actions{display:inline-flex;gap:4px;justify-content:flex-end}
.link-danger{color:var(--bad)}
.link-danger:hover{color:#b91c1c}

.toolbar{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:13px 16px;border-bottom:1px solid var(--line-2);background:#fff;
  border-radius:var(--radius) var(--radius) 0 0;
}
.toolbar .spacer{flex:1}
.search-box{position:relative;display:flex;align-items:center}
.search-box .ico{position:absolute;left:10px;color:var(--ink-3)}
.search-box input{
  height:34px;padding:0 12px 0 33px;border:1px solid var(--line);border-radius:8px;
  width:250px;background:#fbfcfe;outline:none;transition:.15s;
}
.search-box input:focus{border-color:#c3caf5;background:#fff;box-shadow:0 0 0 3px rgba(79,70,229,.08)}

.pager{display:flex;align-items:center;gap:6px;justify-content:flex-end;padding:13px 16px;border-top:1px solid var(--line-2)}
.pager a,.pager span{
  min-width:32px;height:30px;padding:0 9px;border-radius:7px;display:inline-flex;
  align-items:center;justify-content:center;font-size:13px;border:1px solid var(--line);
  background:#fff;color:var(--ink-2);
}
.pager .cur{background:var(--brand);border-color:var(--brand);color:#fff}
.pager .info{border:none;background:transparent;color:var(--ink-3);margin-right:auto;padding-left:0}

/* ============================ 表单 ============================ */
.form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px}
.form-grid .span-2{grid-column:1 / -1}
.field{display:flex;flex-direction:column;gap:6px}
.field-label{font-size:13px;color:var(--ink-2);font-weight:500}
.field-label .req{color:var(--bad);margin-left:2px}
.field input[type=text],.field input[type=password],.field input[type=date],
.field input[type=number],.field input[type=email],.field input[type=tel],
.field select,.field textarea{
  width:100%;height:38px;padding:0 11px;border:1px solid var(--line);
  border-radius:8px;background:#fff;outline:none;transition:.15s;color:var(--ink);
}
.field textarea{height:auto;min-height:86px;padding:9px 11px;resize:vertical;line-height:1.6}
.field input:focus,.field select:focus,.field textarea:focus{
  border-color:#b9c1f2;box-shadow:0 0 0 3px rgba(79,70,229,.09);
}
.field input[readonly],.field select[disabled]{background:#f7f8fc;color:var(--ink-3)}
.field .hint{font-size:12px;color:var(--ink-3)}
.field .err{font-size:12px;color:var(--bad)}
.field.has-err input,.field.has-err select,.field.has-err textarea{border-color:#f0b4b4;background:#fffafa}
.check-line{display:flex;align-items:center;gap:8px;font-size:13.5px;color:var(--ink-2)}
.form-actions{display:flex;gap:10px;justify-content:flex-end;padding-top:6px}

/* ============================ 应用台 ============================ */
.hero{
  position:relative;overflow:hidden;
  background:linear-gradient(115deg,#1f1b3a 0%,#2c2359 42%,#3b2064 72%,#4a1f57 100%);
  border-radius:16px;padding:26px 28px;color:#fff;margin-bottom:20px;
}
.hero::after{
  content:'';position:absolute;right:-90px;top:-110px;width:320px;height:320px;border-radius:50%;
  background:radial-gradient(circle,rgba(139,92,246,.45),transparent 68%);
}
.hero h2{font-size:20px;margin-bottom:6px}
.hero p{margin:0;color:#b9b4e8;font-size:13.5px}
.hero .hero-meta{display:flex;gap:22px;margin-top:16px;flex-wrap:wrap;position:relative;z-index:1}
.hero .hm{display:flex;flex-direction:column}
.hero .hm b{font-size:19px;font-weight:600;letter-spacing:-.02em}
.hero .hm span{font-size:12px;color:#a9a4d8}

.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:12px;margin-bottom:20px}
.stat{
  background:#fff;border:1px solid var(--line);border-radius:12px;padding:14px 15px;
  display:flex;flex-direction:column;gap:3px;box-shadow:var(--shadow);transition:.15s;
}
.stat:hover{transform:translateY(-1px);box-shadow:var(--shadow-lg);border-color:#dcdff0}
.stat .st-label{font-size:12.5px;color:var(--ink-3)}
.stat .st-value{font-size:22px;font-weight:600;letter-spacing:-.02em;color:var(--ink)}
.stat .st-value small{font-size:12px;font-weight:400;color:var(--ink-3);margin-left:3px}
.stat.t-blue .st-value{color:#1d4ed8}
.stat.t-rose .st-value{color:#be123c}
.stat.t-indigo .st-value{color:#4338ca}
.stat.t-cyan .st-value{color:#0e7490}
.stat.t-teal .st-value{color:#0f766e}
.stat.t-green .st-value{color:#047857}
.stat.t-amber .st-value{color:#b45309}

.apps-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:9px;
}
.app-tile{
  display:flex;flex-direction:column;align-items:center;gap:9px;
  padding:15px 6px 12px;border-radius:11px;background:#fff;border:1px solid var(--line);
  color:var(--ink-2);text-align:center;transition:.16s;box-shadow:0 1px 2px rgba(20,24,45,.03);
}
.app-tile:hover{
  color:var(--ink);border-color:#d5d9ef;transform:translateY(-2px);
  box-shadow:0 8px 22px rgba(28,32,60,.09);
}
.app-tile .t-name{font-size:12.5px;font-weight:500;line-height:1.3}
.app-tile.off{opacity:.45;filter:grayscale(.5)}
.app-tile.off:hover{transform:none;box-shadow:none}

.app-icon{
  border-radius:14px;display:flex;align-items:center;justify-content:center;color:#fff;
  box-shadow:0 6px 16px rgba(20,24,45,.16);
}
.c-orange{background:linear-gradient(135deg,#ffb457,#f97316)}
.c-red{background:linear-gradient(135deg,#fb7185,#dc2626)}
.c-green{background:linear-gradient(135deg,#4ade80,#059669)}
.c-blue{background:linear-gradient(135deg,#60a5fa,#2563eb)}
.c-teal{background:linear-gradient(135deg,#2dd4bf,#0d9488)}
.c-rose{background:linear-gradient(135deg,#fb7185,#e11d48)}
.c-indigo{background:linear-gradient(135deg,#818cf8,#4f46e5)}
.c-cyan{background:linear-gradient(135deg,#22d3ee,#0891b2)}
.c-amber{background:linear-gradient(135deg,#fbbf24,#d97706)}
.c-violet{background:linear-gradient(135deg,#a78bfa,#7c3aed)}
.c-pink{background:linear-gradient(135deg,#f472b6,#db2777)}
.c-sky{background:linear-gradient(135deg,#38bdf8,#0284c7)}
.c-gray{background:linear-gradient(135deg,#94a3b8,#64748b)}

.grid-2{display:grid;grid-template-columns:1.55fr 1fr;gap:16px}
.grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}

.todo-list{display:flex;flex-direction:column;gap:8px}
/* 工作台「待办提醒」通栏卡片：宽屏自动分列，手机上自动回落单列 */
.dash-todo{margin-bottom:16px}
.dash-todo .todo-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:8px 12px}
.todo{
  display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:9px;
  background:#fbfcff;border:1px solid var(--line-2);font-size:13px;color:var(--ink-2);
}
.todo:hover{background:#f6f8ff;border-color:#e0e5fa;color:var(--ink)}
.dot{width:7px;height:7px;border-radius:50%;flex:none}
.dot.amber{background:#f59e0b}
.dot.red{background:#ef4444}
.dot.blue{background:#3b82f6}
.dot.green{background:#10b981}

.timeline{display:flex;flex-direction:column;gap:0}
.tl-item{display:flex;gap:11px;padding:9px 0;border-bottom:1px dashed var(--line-2);font-size:13px}
.tl-item:last-child{border-bottom:none}
.tl-time{color:var(--ink-3);font-size:12px;white-space:nowrap;min-width:88px}
.tl-text{color:var(--ink-2);flex:1}
.tl-text b{color:var(--ink);font-weight:500}

/* ============================ 登录页 ============================ */
.blank-body{background:#f5f6fb}
.login-page{min-height:100vh;display:grid;grid-template-columns:1.05fr 1fr}
.login-visual{
  background:linear-gradient(150deg,#17142c 0%,#241d47 40%,#3a1d5c 74%,#4b1b4f 100%);
  color:#fff;display:flex;align-items:center;padding:56px;position:relative;overflow:hidden;
}
.login-visual::before{
  content:'';position:absolute;width:520px;height:520px;border-radius:50%;
  background:radial-gradient(circle,rgba(124,58,237,.40),transparent 70%);
  left:-160px;bottom:-200px;
}
.login-visual::after{
  content:'';position:absolute;width:380px;height:380px;border-radius:50%;
  background:radial-gradient(circle,rgba(59,130,246,.28),transparent 70%);
  right:-120px;top:-120px;
}
.lv-inner{position:relative;z-index:1;max-width:430px}
.lv-logo{
  width:50px;height:50px;border-radius:14px;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,#6366f1,#a855f7);margin-bottom:22px;
  box-shadow:0 10px 30px rgba(124,58,237,.45);
}
.lv-inner h1{font-size:26px;margin-bottom:10px}
.lv-inner > p{color:#b7b2e0;font-size:14px;margin:0 0 28px}
.lv-points{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:14px}
.lv-points li{display:flex;align-items:flex-start;gap:10px;color:#cfcbe9;font-size:13.5px}
.lv-points .ico{color:#a78bfa;margin-top:2px}

.login-form-wrap{display:flex;align-items:center;justify-content:center;padding:40px 24px;background:#fbfbfe}
.login-card{width:100%;max-width:368px}
.login-card h2{font-size:21px;margin-bottom:6px}
.login-sub{color:var(--ink-3);font-size:13px;margin:0 0 24px}
.login-card .field{margin-bottom:15px}
.login-card .field input{height:42px}
.login-card .btn-block{margin-top:6px}
.login-foot{margin:16px 0 0;font-size:12.5px;color:var(--ink-3);text-align:center;display:flex;flex-direction:column;gap:4px}
.login-foot .dim{font-size:12px;opacity:.85}

/* ============================ 详情页 ============================ */
.detail-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:16px}
/* 标题区必须能收缩（min-width:0），否则长标题 + 一排按钮会把标题压成一列竖排字 */
.detail-head > div:first-child{min-width:0}
.detail-title{font-size:19px;font-weight:600;letter-spacing:-.01em;overflow-wrap:anywhere}
.detail-sub{color:var(--ink-3);font-size:13px;margin-top:3px}
/* 操作区：桌面单行不换行；按钮组自身不被压缩 */
.detail-acts{display:flex;gap:8px;flex:none}
.dl{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:0}
.dl-item{padding:11px 16px;border-bottom:1px solid var(--line-2);display:flex;gap:12px}
.dl-item dt{color:var(--ink-3);font-size:13px;min-width:88px;flex:none}
.dl-item dd{margin:0;color:var(--ink);font-size:13.5px;word-break:break-word;flex:1}
.dl-item.full{grid-column:1 / -1}

.mini-form{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;padding:14px 16px;background:#fbfcfe;border-top:1px solid var(--line-2)}
.mini-form .field{flex:1;min-width:120px;gap:4px}
.mini-form .field input,.mini-form .field select{height:34px}
.mini-form .field-label{font-size:12px;color:var(--ink-3)}
.mini-form [data-calc-out]{
  height:34px;display:flex;align-items:center;justify-content:flex-end;
  padding:0 10px;font-variant-numeric:tabular-nums;color:var(--ink-3);
  background:#f4f6fc;border:1px dashed var(--line);border-radius:8px;font-size:13px;
}

/* ============================ 错误页 ============================ */
.err-page{
  min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:40px;text-align:center;
}
.err-code{font-size:66px;font-weight:700;letter-spacing:-.04em;color:#d3d7ea;line-height:1}
.err-title{font-size:19px;margin:14px 0 8px}
.err-desc{color:var(--ink-3);font-size:13.5px;margin:0 0 22px;max-width:420px}

/* ============================ 安装向导 ============================ */
.install-wrap{max-width:680px;margin:0 auto;padding:48px 24px 60px}
.install-head{text-align:center;margin-bottom:28px}
.install-head .lv-logo{margin:0 auto 18px}
.install-head h1{font-size:22px;margin-bottom:8px}
.install-head p{color:var(--ink-3);font-size:13.5px;margin:0}
.install-card{background:#fff;border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);overflow:hidden}
.install-body{padding:24px}
.install-logs{background:#0f1424;color:#8ef0c1;font-family:ui-monospace,Consolas,monospace;font-size:12.5px;padding:14px 16px;border-radius:10px;margin-top:16px;white-space:pre-wrap;line-height:1.8}
.steps{display:flex;gap:8px;margin-bottom:20px}
.step{flex:1;height:4px;border-radius:2px;background:#e7e9f2}
.step.on{background:var(--brand)}

/* ============================ 响应式 ============================ */
@media (max-width:1100px){
  .grid-2{grid-template-columns:1fr}
  .grid-3{grid-template-columns:1fr}
  .login-page{grid-template-columns:1fr}
  .login-visual{display:none}
}
@media (max-width:820px){
  .sidebar{position:fixed;left:-240px;z-index:60;transition:left .2s}
  .sidebar.open{left:0}
  .content{padding:16px}
  .form-grid{grid-template-columns:1fr}
  .topbar{padding:0 16px}
}

/* 登录页左侧模块图标装饰 */
.lv-apps{display:flex;gap:8px;margin-top:30px;flex-wrap:wrap}
.lv-app{
  width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.07);color:#b9b3e6;
  border:1px solid rgba(255,255,255,.09);
  transition:.2s;
}
.lv-app:hover{background:rgba(139,92,246,.28);color:#fff;transform:translateY(-2px)}

/* 应用中心分组 */
.app-group{margin-bottom:20px}
.app-group:last-child{margin-bottom:2px}
.app-group-title{
  font-size:12px;color:var(--ink-3);font-weight:500;letter-spacing:.04em;
  margin:0 0 10px;padding-left:2px;
}

/* ==========================================================================
   讨论 —— 两级页面（微信式）
     一级：会话列表（.conv-page）—— 头像 / 名称 / 最后一条消息 / 时间 / 未读
     二级：会话内容（.chat-wrap）—— 完整聊天记录 + 输入框
   两级之间用普通链接跳转，浏览器前进后退与手机侧滑都能用。
   ========================================================================== */

/* ---------------- 一级：会话列表页 ---------------- */
.conv-page{
  max-width:880px;margin:0 auto;background:var(--card);
  border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);
  overflow:hidden;
}
.conv-head{
  display:flex;align-items:center;gap:12px;padding:16px 18px;
  background:#fff;border-bottom:1px solid var(--line-2);
}
.conv-head-main{flex:1;min-width:0}
.conv-head-title{margin:0;font-size:16px;font-weight:650;letter-spacing:.01em}
.conv-head-sub{margin:3px 0 0;font-size:12.5px;color:var(--ink-3)}
.conv-head-dot b{color:var(--bad,#e5484d);font-weight:600}

/* 新建会话：details 折叠，点按钮展开表单，提交后直接进新会话 */
.conv-new{position:relative;flex:none}
.conv-new-btn{list-style:none;display:inline-flex;align-items:center;gap:6px;cursor:pointer;user-select:none}
.conv-new-btn::-webkit-details-marker{display:none}
.conv-new-btn::marker{content:""}
.conv-new-form{
  position:absolute;right:0;top:calc(100% + 8px);width:min(340px,calc(100vw - 48px));z-index:20;
  background:#fff;border:1px solid var(--line);border-radius:12px;
  box-shadow:0 14px 34px rgba(20,24,45,.16);
  padding:12px;display:flex;flex-direction:column;gap:8px;
}
.conv-new-row{display:flex;gap:8px}
.conv-new-row input,.conv-new-row select{
  flex:1;min-width:0;height:34px;padding:0 10px;border:1px solid var(--line);
  border-radius:8px;background:#fff;outline:none;font-size:13px;
}
.conv-new-row input:focus,.conv-new-row select:focus{border-color:var(--brand)}
.conv-new-actions{display:flex;justify-content:flex-end}

.conv-list{display:flex;flex-direction:column}
.conv-item{
  display:flex;align-items:center;gap:12px;padding:12px 16px;
  color:inherit;text-decoration:none;position:relative;transition:background .15s;
}
.conv-item + .conv-item{border-top:1px solid var(--line-2)}
.conv-item:hover{background:#f6f7fc}
.conv-item.is-pinned{background:#f9f9fe}
.conv-item.is-pinned:hover{background:#f3f3fd}
/* 置顶区与普通区之间加一道稍深的分隔，一眼能看出哪一截是钉住的 */
.conv-item.is-pinned + .conv-item:not(.is-pinned){border-top-color:var(--line)}

.conv-ava{
  flex:none;width:46px;height:46px;border-radius:13px;
  display:flex;align-items:center;justify-content:center;
  font-size:17px;font-weight:600;background:#eef0ff;color:#4f46e5;
}
/* 头像配色跟着会话走（PHP 按 id 取模给 c1~c6），重排时颜色不会变 */
.conv-ava.c2{background:#e9f7f1;color:#0f9d76}
.conv-ava.c3{background:#fdf1e7;color:#c2740c}
.conv-ava.c4{background:#fdeef1;color:#c53a5a}
.conv-ava.c5{background:#eaf4fe;color:#1c7ed6}
.conv-ava.c6{background:#f3effe;color:#7048e8}
.conv-item.is-pinned .conv-ava{box-shadow:0 0 0 2px rgba(99,102,241,.18)}

.conv-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.conv-line{display:flex;align-items:center;gap:8px;min-width:0}
.conv-name{
  flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.conv-time{flex:none;font-size:11.5px;color:var(--ink-3)}
.conv-msg{
  flex:1;min-width:0;font-size:12.5px;color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.conv-msg i{font-style:normal;color:var(--ink-2,#5b6079)}
.conv-badge{
  flex:none;min-width:19px;height:19px;padding:0 6px;border-radius:10px;
  background:var(--bad,#e5484d);color:#fff;font-size:11px;font-weight:600;
  line-height:19px;text-align:center;
}
.conv-badge[hidden]{display:none}

/* 置顶按钮：个人视角，只改自己的列表。平时淡出，悬停条目才明显；
   已置顶的常亮；触屏没有 hover，用 hover:none 常显一半，否则手机点不到。 */
.conv-pin{
  flex:none;width:22px;height:22px;display:flex;align-items:center;justify-content:center;
  border-radius:6px;color:var(--ink-3);cursor:pointer;opacity:0;
  transition:opacity .15s,background .15s,color .15s;
}
.conv-item:hover .conv-pin{opacity:.7}
.conv-pin:hover{opacity:1;background:#e8e9f5;color:var(--brand)}
.conv-pin.on{opacity:1;color:var(--brand)}
.conv-pin.on:hover{background:var(--brand-soft)}
.conv-pin:focus-visible{opacity:1;outline:2px solid var(--brand);outline-offset:1px}
.conv-pin.is-busy{opacity:.4;pointer-events:none}
@media (hover:none){.conv-pin{opacity:.5}}

.conv-empty{padding:56px 20px;text-align:center;color:var(--ink-2,#4a5068);font-size:14px}
.conv-empty p{margin:0 0 6px}
.conv-hint{margin:0;padding:12px 16px;font-size:12px;border-top:1px solid var(--line-2);background:#fbfbfe}

/* ---------------- 二级：会话内容页 ---------------- */
.chat-wrap{
  display:flex;flex-direction:column;
  height:calc(100vh - 200px);height:calc(100dvh - 200px);min-height:480px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);overflow:hidden;
}
.chat-main{flex:1;min-width:0;display:flex;flex-direction:column;background:#f6f7fc;min-height:0}
.chat-head{
  height:62px;flex:none;padding:0 16px;display:flex;align-items:center;gap:10px;
  background:#fff;border-bottom:1px solid var(--line-2);
}
.chat-back{
  flex:none;width:34px;height:34px;display:flex;align-items:center;justify-content:center;
  border-radius:9px;color:#3d4360;background:#eef0f8;border:1px solid var(--line-2);
  text-decoration:none;transition:background .15s,color .15s,border-color .15s;
}
.chat-back:hover{background:var(--brand-soft);color:var(--brand);border-color:transparent}
.chat-back:active{transform:scale(.96)}
.chat-title{font-size:15px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-sub{display:flex;align-items:center;gap:8px;font-size:12px;margin-top:2px;white-space:nowrap;overflow:hidden}
.chat-msgs{
  flex:1;overflow-y:auto;padding:18px 20px;display:flex;flex-direction:column;gap:2px;
  scroll-behavior:smooth;
}
.chat-placeholder,.chat-empty-msg{
  flex:1;display:flex;flex-direction:column;gap:10px;align-items:center;justify-content:center;
  color:var(--ink-3);font-size:13px;
}
.msg{display:flex;gap:10px;margin:8px 0;align-items:flex-start}
.msg.mine{flex-direction:row-reverse}
/* 消息头像（v1.25.0 由 34px 放大到 40px：手机上一屏十几条消息时人脸太小认不出） */
.msg .avatar{width:40px;height:40px;border-radius:11px;font-size:14px}
.msg-body{position:relative;max-width:min(620px,72%);display:flex;flex-direction:column;gap:3px}
.msg.mine .msg-body{align-items:flex-end}
.msg-name{font-size:12px;color:var(--ink-3);padding:0 4px}
.bubble{
  padding:9px 13px;border-radius:12px;background:#fff;border:1px solid var(--line-2);
  font-size:13.5px;line-height:1.7;white-space:pre-wrap;word-break:break-word;
  box-shadow:0 1px 2px rgba(20,24,45,.04);border-bottom-left-radius:4px;
}
.msg.mine .bubble{
  background:linear-gradient(135deg,#4f46e5,#6366f1);color:#fff;border-color:transparent;
  border-bottom-left-radius:12px;border-bottom-right-radius:4px;
}
.msg-time{
  align-self:center;font-size:11.5px;color:var(--ink-3);background:rgba(255,255,255,.7);
  padding:2px 10px;border-radius:20px;margin:10px 0 4px;
}
.chat-composer{
  flex:none;display:block;padding:10px 16px 12px;
  background:#fff;border-top:1px solid var(--line-2);
}
/* 工具行：表情 / 附件按钮独立一行，位于输入框上方 */
.chat-composer-tools{display:flex;gap:8px;margin-bottom:8px}
.chat-composer-tools .chat-attach-btn{width:36px;height:36px;border-radius:9px}
/* 输入行：输入框 + 发送按钮 */
.chat-composer-main{display:flex;gap:10px;align-items:flex-end}
.chat-composer textarea{
  flex:1;min-height:42px;max-height:120px;resize:none;padding:10px 12px;
  border:1px solid var(--line);border-radius:10px;outline:none;line-height:1.5;font-size:13.5px;
}
.chat-composer textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px rgba(79,70,229,.08)}
.chat-composer .btn{height:42px;padding:0 22px}

@media (max-width:820px){
  /* 手机：列表页铺满，内容页占满可视高度（dvh 兼容地址栏伸缩） */
  .conv-page{border-radius:0;border-left:0;border-right:0;box-shadow:none}
  .conv-head{padding:14px 14px}
  .conv-item{padding:12px 14px;gap:10px}
  .conv-ava{width:44px;height:44px;border-radius:12px}
  .chat-wrap{
    height:calc(100vh - 130px);height:calc(100dvh - 130px);
    min-height:420px;border-radius:0;border-left:0;border-right:0;box-shadow:none;
  }
  .chat-head{height:56px;padding:0 10px}
  .chat-msgs{padding:14px 12px;min-height:280px}
  .chat-sub-hint{display:none}
}

/* ==========================================================================
   附件（合同 / 文档）
   ========================================================================== */
.attach-card{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.attach-name{font-weight:500}
.attach-actions{display:flex;gap:8px;flex-wrap:wrap}
.attach-preview{
  margin-top:14px;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#f8f9fc;
}
.attach-preview iframe{display:block;width:100%;height:620px;border:0;background:#fff}
.attach-preview img{display:block;max-width:100%;margin:0 auto}

/* ==========================================================================
   打印视图
   ========================================================================== */
.print-page{
  max-width:820px;margin:28px auto;background:#fff;padding:46px 52px;
  border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-lg);
  font-size:13.5px;color:var(--ink);
}
.print-head{text-align:center;margin-bottom:26px}
.print-head h1{font-size:22px;letter-spacing:.08em;margin-bottom:6px}
.print-head .print-sub{color:var(--ink-3);font-size:12.5px}
.print-table{width:100%;border-collapse:collapse}
.print-table th,.print-table td{border:1px solid #d9dbe8;padding:9px 12px;text-align:left;vertical-align:top}
.print-table th{background:#f6f7fb;font-weight:600;width:130px;color:var(--ink-2)}
.print-table td{white-space:pre-wrap}
.print-table tr.total td{font-weight:600}
.print-sign{display:flex;justify-content:space-between;margin-top:46px;gap:40px}
.print-sign div{flex:1}
.print-sign .line{border-bottom:1px solid #b9bccd;height:34px;margin-top:6px}
.print-toolbar{
  max-width:820px;margin:18px auto 0;display:flex;gap:10px;justify-content:flex-end;
}
@media print{
  body{background:#fff}
  /* 底部 Tab 栏是 fixed 定位：不显式隐藏会跟着打印到纸面上（手机端尤其明显） */
  .sidebar,.topbar,.foot,.tabbar,.print-toolbar,.alert{display:none !important}
  .shell{display:block}
  .content{padding:0;max-width:none}
  .print-page{margin:0;border:0;box-shadow:none;border-radius:0;padding:0;max-width:none}
  .print-table th{background:#f3f4f8 !important;-webkit-print-color-adjust:exact;print-color-adjust:exact}
}

/* ============================ 聊天附件 ============================ */
.chat-attach-btn{
  display:flex;align-items:center;justify-content:center;flex:none;
  width:42px;height:42px;border-radius:10px;border:1px solid var(--line);
  color:var(--ink-2);cursor:pointer;background:#fff;transition:background .15s;
}
.chat-attach-btn:hover{background:var(--brand-soft);color:var(--brand)}
.chat-attach-btn.active{background:var(--brand-soft);color:var(--brand);border-color:var(--brand)}

/* 输入区容器：预览条在上，输入行在下 */
.chat-composer-wrap{flex:none;position:relative;background:#fff;border-top:1px solid var(--line-2)}
.chat-composer-wrap .chat-composer{border-top:0;background:transparent}

/* ============ 待发附件预览（微信式：缩略图 + 删除角标） ============ */
.chat-preview{
  display:flex;gap:10px;flex-wrap:wrap;
  padding:12px 16px 2px;
}
/* 注意：display:flex 会盖掉 hidden 属性的 UA display:none，必须显式声明 */
.chat-preview[hidden]{display:none}
.chat-pv{
  position:relative;width:78px;height:78px;border-radius:9px;overflow:hidden;
  border:1px solid var(--line);background:#f1f2f7;flex:none;
}
.chat-pv-media{
  width:100%;height:100%;object-fit:cover;display:block;cursor:zoom-in;background:#000;
}
.chat-pv-kind{
  position:absolute;left:4px;top:4px;padding:0 5px;border-radius:5px;
  font-size:10px;line-height:15px;color:#fff;background:rgba(0,0,0,.55);
}
.chat-pv-size{
  position:absolute;left:0;right:0;bottom:0;padding:1px 0;text-align:center;
  font-size:10px;line-height:14px;color:#fff;background:rgba(0,0,0,.45);
}
.chat-pv-del{
  position:absolute;right:3px;top:3px;width:19px;height:19px;border:0;border-radius:50%;
  background:rgba(0,0,0,.58);color:#fff;font-size:10px;line-height:19px;text-align:center;
  cursor:pointer;padding:0;
}
.chat-pv-del:hover{background:var(--bad)}

/* ============ 表情面板（v1.21.0 重做：更大更清晰、带弹出动画） ============ */
.chat-emoji{
  position:absolute;left:14px;bottom:calc(100% + 8px);width:352px;max-height:260px;overflow-y:auto;
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  background:#fff;border:1px solid var(--line);border-radius:14px;padding:10px 12px 12px;
  box-shadow:0 16px 44px rgba(20,24,45,.18);z-index:40;
  transform-origin:16px bottom;
  animation:emoji-pop .16s ease-out;
  scrollbar-width:thin;scrollbar-color:#d4d6e0 transparent;
}
.chat-emoji::-webkit-scrollbar{width:7px}
.chat-emoji::-webkit-scrollbar-thumb{background:#d4d6e0;border-radius:4px}
.chat-emoji::-webkit-scrollbar-track{background:transparent}
@keyframes emoji-pop{
  from{opacity:0;transform:translateY(8px) scale(.96)}
  to{opacity:1;transform:translateY(0) scale(1)}
}
.chat-emoji-title{
  font-size:11px;color:var(--ink-3);padding:8px 4px 4px;letter-spacing:.06em;
  position:sticky;top:-10px;margin:-10px -4px 0;background:linear-gradient(#fff 78%,rgba(255,255,255,0));
  z-index:1;
}
.chat-emoji-grid{display:grid;grid-template-columns:repeat(9,1fr);gap:2px}
.chat-emoji-grid button{
  font-size:22px;line-height:1;height:38px;border:0;background:transparent;border-radius:9px;
  cursor:pointer;padding:0;
  font-family:"Segoe UI Emoji","Apple Color Emoji","Noto Color Emoji","Twemoji Mozilla",sans-serif;
  transition:background .12s,transform .12s;
}
.chat-emoji-grid button:hover{background:var(--brand-soft);transform:scale(1.18)}
.chat-emoji-grid button:active{transform:scale(.92);background:var(--brand-soft)}
.bubble-att{padding:5px;display:inline-block}
/* width/height:auto 不能省：标签上带 width/height 属性（用来占位防跳动），
   只写 max-* 的话两个维度会被各自压到上限，4:3 的照片会显示成正方形 */
.chat-img{max-width:220px;max-height:220px;width:auto;height:auto;border-radius:8px;display:block;background:#eef0f5}
.chat-video{max-width:280px;max-height:300px;border-radius:8px;display:block;background:#000}

/* ==========================================================================
   消息里的图片 / 视频：三种排列方式（对话 · 网格 · 列表）
   --------------------------------------------------------------------------
   由 .chat-msgs 上的 data-media 属性切换，只改 CSS，不重渲染消息：
     bubble → 原样大小（默认，和以前一样）
     grid   → 正方形缩略图（像手机相册的网格）
     list   → 横向条目：小缩略图 + 文件名 / 大小 / 时间
   文字气泡在三种方式下都完全不变。
   ========================================================================== */
.media{
  position:relative;display:inline-flex;max-width:100%;padding:5px;
  border:1px solid var(--line-2);border-radius:12px;border-bottom-left-radius:4px;
  background:#fff;box-shadow:0 1px 2px rgba(20,24,45,.04);
  color:inherit;text-decoration:none;
  transition:box-shadow .15s,border-color .15s;
}
.msg.mine .media{border-bottom-left-radius:12px;border-bottom-right-radius:4px}
.media:hover{border-color:#c9cde0;box-shadow:0 3px 12px rgba(20,24,45,.10)}
.media-image{cursor:zoom-in}
/* 底色 = 缩略图还没到位时的占位，避免一片白闪 */
.media .chat-img{max-width:220px;max-height:220px;width:auto;height:auto;border-radius:8px;display:block;background:#eef0f5}
.media .chat-video{max-width:280px;max-height:300px;border-radius:8px;display:block;background:#000}

/* 文件名 / 大小 / 时间：只有列表排列才显示 */
.media-meta{display:none}
.media-name{font-size:12.5px;font-weight:600;line-height:1.45;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.media-sub{font-size:11.5px;color:var(--ink-3);line-height:1.45;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ---------------- 网格：带图消息平铺成相册（多列自适应） ----------------
   做法：把消息容器切成网格，凡是「带图片/视频」的消息各占一格，
   纯文字消息仍横跨整行 —— 文字气泡的外观不变，只是带图消息的配文变成两行内的说明。
   最新的一张排在最前面（DOM 由 JS 倒序重排，见 chat.php 的 rebuildOrder），
   轮询追加的新消息插到最前面，自动落进第一格。 */
.chat-msgs[data-media="grid"]{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));
  grid-auto-rows:min-content;align-content:start;gap:8px;
}
.chat-msgs[data-media="grid"] > *{grid-column:1 / -1}
.chat-msgs[data-media="grid"] > .msg{margin:0}
.chat-msgs[data-media="grid"] > .msg-time{justify-self:center;margin:6px 0 2px}
.chat-msgs[data-media="grid"] > .msg.has-media{
  grid-column:auto;position:relative;display:block;margin:0;
}
.chat-msgs[data-media="grid"] > .msg.has-media .msg-body{max-width:none;width:100%;align-items:stretch}
.chat-msgs[data-media="grid"] > .msg.has-media .media{display:block;width:100%;padding:3px;border-radius:10px}
/* 注意 height:auto 不能省：图片标签带了 width/height 属性（用来占位防跳动），
   不写 height 的话属性值会盖掉 aspect-ratio，格子被撑成一条竖条 */
.chat-msgs[data-media="grid"] > .msg.has-media .chat-img,
.chat-msgs[data-media="grid"] > .msg.has-media .chat-video{
  width:100%;height:auto;max-width:none;max-height:none;aspect-ratio:1 / 1;object-fit:cover;border-radius:7px;
}
/* 配文：压成两行以内的小字说明，长文点开图片看完整对话 */
.chat-msgs[data-media="grid"] > .msg.has-media .bubble{
  margin-top:3px;padding:4px 8px;border-radius:8px;font-size:11.5px;line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  text-align:left;word-break:break-word;
}
/* 网格里不显示头像角标（v1.23.0 起用户明确要求：照片/视频右上角不要压东西，
   整格就是画面本身；谁发的靠点开灯箱/看配文即可）。
   姓名行也收起（网格里靠配文认人），保证每格等高。 */
.chat-msgs[data-media="grid"] > .msg.has-media .msg-name{display:none}
.chat-msgs[data-media="grid"] > .msg.has-media .avatar{display:none}

/* ---------------- 列表：缩略图 + 文件信息 ---------------- */
.chat-msgs[data-media="list"] .msg{margin:6px 0}
.chat-msgs[data-media="list"] .media{
  display:flex;align-items:center;gap:10px;
  width:326px;max-width:100%;padding:6px 12px 6px 6px;
}
.chat-msgs[data-media="list"] .media .chat-img,
.chat-msgs[data-media="list"] .media .chat-video{
  width:52px;height:52px;max-width:none;max-height:none;object-fit:cover;border-radius:7px;flex:none;
}
.chat-msgs[data-media="list"] .media-meta{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}

/* ---------------- 屏幕适配 ---------------- */
@media (max-width:1100px){
  /* 聊天区变窄时先收起“每 2 秒自动刷新”这句说明，避免标题区折行 */
  .chat-sub-hint{display:none}
}
@media (max-width:900px){
  /* 头部按钮只留图标，给标题让位 */
  .chat-vm span{display:none}
  .chat-vm{padding:0 8px}
}
@media (max-width:640px){
  .chat-head{padding:0 12px}
  .chat-msgs[data-media="grid"]{grid-template-columns:repeat(auto-fill,minmax(92px,1fr));gap:6px}
  .chat-msgs[data-media="list"] .media{width:100%}
  .chat-msgs[data-media="list"] .media .chat-img,
  .chat-msgs[data-media="list"] .media .chat-video{width:46px;height:46px}
}

/* ---------------- 头部：排列方式切换 ---------------- */
.chat-head-main{min-width:0;flex:1}
.chat-head-tools{display:flex;align-items:center;gap:8px;flex:none}
.chat-viewmode{
  display:inline-flex;align-items:center;gap:2px;padding:3px;
  border:1px solid var(--line-2);border-radius:10px;background:#f2f3f8;
}
.chat-vm{
  display:inline-flex;align-items:center;justify-content:center;gap:5px;
  height:26px;padding:0 9px;border:0;border-radius:8px;background:transparent;
  color:var(--ink-2);font-size:12.5px;line-height:1;cursor:pointer;
  transition:background .15s,color .15s,box-shadow .15s;
}
.chat-vm:hover:not(:disabled){color:var(--brand)}
.chat-vm.active{background:#fff;color:var(--brand);font-weight:600;box-shadow:0 1px 2px rgba(20,24,45,.12)}
.chat-vm:disabled{opacity:.38;cursor:not-allowed}
.chat-vm:disabled:hover{color:var(--ink-2)}

/* ---------------- 灯箱（点缩略图看大图） ---------------- */
.chat-lb{
  position:fixed;inset:0;z-index:120;display:flex;align-items:center;justify-content:center;
  padding:56px 66px;background:rgba(10,12,22,.9);
}
.chat-lb[hidden]{display:none}
.chat-lb-img{
  max-width:100%;max-height:100%;border-radius:8px;background:#0d0f18;
  box-shadow:0 20px 60px rgba(0,0,0,.55);object-fit:contain;
}
.chat-lb-close,.chat-lb-nav{
  position:absolute;display:flex;align-items:center;justify-content:center;padding:0;
  border:0;border-radius:50%;background:rgba(255,255,255,.14);color:#fff;cursor:pointer;
  transition:background .15s;
}
.chat-lb-close{top:16px;right:18px;width:38px;height:38px}
.chat-lb-nav{top:50%;width:44px;height:44px;transform:translateY(-50%)}
.chat-lb-nav.prev{left:16px}
.chat-lb-nav.next{right:16px}
.chat-lb-close:hover,.chat-lb-nav:hover{background:rgba(255,255,255,.3)}
.chat-lb-nav:disabled{opacity:.22;cursor:default}
.chat-lb-bar{
  position:absolute;left:0;right:0;bottom:18px;text-align:center;
  color:#e8eaf4;font-size:12.5px;pointer-events:none;
}
.chat-lb-bar b{font-weight:600}
.chat-lb-count{color:#aab0c8;margin-left:8px}
/* 灯箱里取的是原图（几 MB），加载期间给个提示，别让画面空着像卡死 */
.chat-lb.is-loading::before{
  content:"加载原图…";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  font-size:13px;color:#fff;opacity:.7;letter-spacing:.5px;pointer-events:none;
}
.chat-lb.is-loading .chat-lb-img{opacity:.12}
.chat-lb-img{transition:opacity .18s}
body.lb-open{overflow:hidden}
@media (max-width:640px){
  .chat-lb{padding:62px 10px 72px}
  .chat-lb-nav{width:36px;height:36px}
  .chat-lb-nav.prev{left:6px}
  .chat-lb-nav.next{right:6px}
}

/* ==========================================================================
   会话内搜索（只搜当前会话，点结果定位到那条消息）
   ========================================================================== */
.chat-search{position:relative;display:flex;align-items:center;gap:5px;flex:none}
.chat-search-btn{
  display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;
  border:0;border-radius:8px;background:transparent;color:var(--ink-2);cursor:pointer;
  transition:background .15s,color .15s;
}
.chat-search-btn:hover,.chat-search.is-open .chat-search-btn{background:var(--brand-soft);color:var(--brand)}
.chat-search-input{
  width:150px;height:28px;padding:0 24px 0 9px;font-size:12.5px;color:var(--ink);
  border:1px solid var(--line-2);border-radius:9px;background:#f7f8fc;outline:none;
  transition:border-color .15s,background .15s,box-shadow .15s;
  -webkit-appearance:none;appearance:none;
}
.chat-search-input::-webkit-search-cancel-button{display:none}
.chat-search-input:focus{border-color:var(--brand);background:#fff;box-shadow:0 0 0 3px rgba(79,70,229,.08)}
.chat-search-clear{
  position:absolute;right:4px;top:50%;transform:translateY(-50%);
  display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;
  border:0;border-radius:50%;background:transparent;color:var(--ink-3);cursor:pointer;
}
.chat-search-clear:hover{background:#eceef7;color:var(--ink)}
.chat-search-clear[hidden]{display:none}
.chat-search-panel{
  position:absolute;right:0;top:calc(100% + 8px);width:340px;max-width:min(92vw,360px);
  background:#fff;border:1px solid var(--line-2);border-radius:12px;overflow:hidden;
  box-shadow:0 14px 40px rgba(20,24,45,.16);z-index:45;
}
.chat-search-panel[hidden]{display:none}
.chat-search-info{
  padding:9px 12px;font-size:11.5px;color:var(--ink-3);
  background:#fafbff;border-bottom:1px solid var(--line-2);
}
.chat-search-list{max-height:322px;overflow-y:auto}
.chat-search-empty{padding:18px 14px;font-size:12.5px;color:var(--ink-3);text-align:center;line-height:1.7}
.chat-hit{
  display:flex;flex-direction:column;gap:3px;width:100%;padding:8px 12px;text-align:left;
  border:0;border-bottom:1px solid var(--line-2);background:transparent;cursor:pointer;
  font:inherit;color:inherit;
}
.chat-hit:last-child{border-bottom:0}
.chat-hit:hover{background:var(--brand-soft)}
.chat-hit-top{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.chat-hit-top b{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-hit-top small{font-size:11px;color:var(--ink-3);flex:none}
.chat-hit-text{
  font-size:12.5px;color:var(--ink-2);line-height:1.5;word-break:break-word;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.chat-hit mark{background:#fde68a;color:inherit;border-radius:3px;padding:0 1px}

/* 搜索命中定位：闪一下，让人一眼看到跳到了哪条 */
.msg.is-hit{border-radius:12px;background:rgba(99,102,241,.14);animation:chat-hit-flash 2.2s ease-out}
.msg.is-hit .bubble,.msg.is-hit .media{
  border-color:var(--brand);box-shadow:0 0 0 2px rgba(79,70,229,.32);
}
@keyframes chat-hit-flash{
  0%{background:rgba(99,102,241,.3)}
  100%{background:rgba(99,102,241,.14)}
}

/* ==========================================================================
   网格模式分页条（每页 18 张图片；对话 / 列表模式不显示）
   ========================================================================== */
.chat-pager{
  flex:none;display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
  padding:7px 18px;background:#fff;border-top:1px solid var(--line-2);
  box-shadow:0 -8px 18px -12px rgba(20,24,45,.28);   /* 轻微上投影：说明上面还能继续滚 */
}
.chat-pager[hidden]{display:none}
.chat-pager-info{font-size:12px;color:var(--ink-3)}
.chat-pager-ctl{display:flex;align-items:center;gap:4px;margin-left:auto}
.chat-pg{
  min-width:28px;height:28px;padding:0 7px;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--line-2);border-radius:8px;background:#fff;color:var(--ink-2);
  font-size:12.5px;line-height:1;cursor:pointer;
  transition:background .15s,color .15s,border-color .15s;
}
.chat-pg:hover:not(:disabled):not(.active){background:var(--brand-soft);color:var(--brand);border-color:transparent}
.chat-pg.active{background:var(--brand);border-color:var(--brand);color:#fff;font-weight:600}
.chat-pg:disabled{opacity:.4;cursor:not-allowed}
.chat-pg-nums{display:inline-flex;align-items:center;gap:4px;margin:0 2px}
.chat-pg-dots{color:var(--ink-3);font-size:12px;padding:0 2px}

/* 分页靠 JS 用 hidden 属性藏消息；网格里 .msg.has-media 显式设了 display:block，
   会盖掉 hidden 的 UA 样式，这里必须强制一下 */
.chat-msgs > [hidden]{display:none !important}

@media (max-width:1100px){
  .chat-search-input{width:118px}
}
@media (max-width:900px){
  /* 窄屏搜索：展开时整条标题栏让给搜索框（标题与显示方式按钮先藏起来），
     否则 340px 的结果面板挂在只有 28px 宽的小按钮上会顶到屏幕外面 */
  .chat-head{position:relative}
  .chat-head.search-open .chat-head-main{display:none}
  .chat-head.search-open .chat-head-tools{flex:1}
  .chat-head.search-open .chat-head-tools > :not(.chat-search){display:none}
  .chat-head.search-open .chat-search{flex:1}
  .chat-search-input{display:none;position:static;flex:1;width:auto;min-width:0}
  .chat-search.is-open .chat-search-input{display:block}
  .chat-search-panel{left:0;right:auto;width:100%;max-width:none;top:calc(100% + 6px)}
  .chat-pager{padding:7px 12px}
  .chat-pager-info{font-size:11.5px}
}
@media (max-width:820px){
  /* 手机上是整页滚动，分页条吸在屏幕底部，翻页不用一路划到底 */
  .chat-pager{position:sticky;bottom:0;z-index:12;box-shadow:0 -6px 16px rgba(20,24,45,.07)}
  /* 手机上顶栏太挤：刷新按钮去掉（回列表再进就是刷新），把宽度留给标题和返回 */
  .chat-head{gap:8px;padding:0 10px}
  .chat-head-tools{gap:6px}
  .chat-head-tools > .btn{display:none}
}
@media (max-width:640px){
  .chat-pager{gap:6px}
  .chat-pg{min-width:26px;height:26px;font-size:12px;padding:0 5px}
  .chat-pager-info{width:100%;order:2;text-align:center}
  .chat-pager-ctl{margin:0 auto;order:1}
  /* 小屏只留会话名，副标题（分类/条数）让位，否则标题只剩两三个字 */
  .chat-sub{display:none}
}
@media (max-width:480px){
  .chat-pg[data-pg="first"],.chat-pg[data-pg="last"]{display:none}
}

/* ============================ 工作台应用徽标 ============================ */
.t-icon{position:relative;display:inline-block;line-height:0}
.app-badge{
  position:absolute;top:-6px;right:-10px;z-index:2;
  min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:var(--bad,#e5484d);color:#fff;font-size:11px;line-height:18px;
  font-weight:600;text-align:center;font-style:normal;
  pointer-events:none;               /* 不挡图标点击 */
  box-shadow:0 0 0 2px #fff;
}

/* ============================ 右上角消息提醒 ============================ */
.notify-wrap{position:relative;display:inline-flex}
.notify-dot{
  position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 4px;
  border-radius:8px;background:var(--bad,#e5484d);color:#fff;font-size:10px;
  line-height:16px;font-weight:600;text-align:center;font-style:normal;
  pointer-events:none;box-shadow:0 0 0 2px #fff;
}
.notify-panel{
  position:absolute;right:0;top:calc(100% + 8px);width:340px;z-index:60;
  background:#fff;border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow-lg);overflow:hidden;
}
.notify-head{
  display:flex;justify-content:space-between;align-items:center;
  padding:12px 14px;border-bottom:1px solid var(--line-2);font-size:13.5px;
}
.notify-allread{
  border:0;background:none;color:var(--brand);font-size:12.5px;cursor:pointer;
}
.notify-allread:hover{text-decoration:underline}
.notify-list{max-height:380px;overflow-y:auto}
.notify-empty{padding:26px 0;text-align:center;color:var(--ink-3);font-size:12.5px}
.notify-item{display:flex;align-items:stretch;border-bottom:1px solid var(--line-2)}
.notify-item:last-child{border-bottom:0}
.notify-link{
  flex:1;min-width:0;padding:10px 12px;display:flex;flex-direction:column;gap:2px;
  color:inherit;text-decoration:none;
}
.notify-link:hover{background:#f6f7fc}
.notify-title{font-size:13px;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.notify-time{font-size:11.5px;color:var(--ink-3)}
.notify-close{
  flex:none;width:34px;border:0;background:none;color:var(--ink-3);
  font-size:16px;cursor:pointer;
}
.notify-close:hover{color:var(--bad);background:#fdf1f2}

/* ==================== 单据多行明细（库存单据） ==================== */
.bill-lines{
  margin-top:16px;border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;background:var(--card);
}
.bill-lines-head{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:10px 14px;background:#fbfcfe;border-bottom:1px solid var(--line-2);
}
.bill-lines-head b{font-size:13.5px}
.bill-lines-head .dim{font-size:12px;color:var(--ink-3)}
.bill-lines .table-wrap{border:none;border-radius:0}
/*
 * 明细表不参与「按比例压缩」：
 * table 是 width:100%，一有富余/不足浏览器就按比例重算列宽，th 上的 min-width
 * 基本撑不住，数量/单价会被压成「1.」。给它一个最小宽度，容器 overflow-x 兜住，
 * 窄屏就横向滚动，也不至于把内容截断。
 */
.bill-lines-table.is-wide{min-width:1060px}
.bill-lines-table td{padding:6px 7px}
.bill-lines-table th{padding:8px 7px;white-space:nowrap}
.bill-lines-table th,
.bill-lines-table td{vertical-align:middle}
.bill-lines-table select,
.bill-lines-table input[type=number],
.bill-lines-table input[type=text]{
  width:100%;min-width:0;height:32px;border:1px solid var(--line);border-radius:8px;
  padding:0 8px;font-size:13px;background:#fff;color:var(--ink);
  box-sizing:border-box;
}
.bill-lines-table select:focus,
.bill-lines-table input:focus{outline:2px solid var(--brand-soft);border-color:var(--brand)}
/* 分类列：选档案物料时自动带出档案分类并置灰（该行不会建档，改分类要到产品管理） */
.bill-lines-table select:disabled{
  background:#f4f5fa;color:var(--ink-3);cursor:not-allowed;border-style:dashed;
}
.bill-lines-table .line-amt{font-variant-numeric:tabular-nums;color:var(--ink-2)}
/* 明细「商品」列：可搜索档案 + 可直接手输品名的组合框 */
.bill-lines-table .line-prod-combo{position:relative;min-width:210px}
.bill-lines-table .line-prod-combo input[type=text]{padding-right:26px}
.bill-lines-table .line-prod-combo::after{
  content:"⌕";position:absolute;right:9px;top:50%;transform:translateY(-52%);
  font-size:14px;color:var(--ink-3);pointer-events:none;
}
.bill-lines-table .line-info{white-space:nowrap;font-size:12px}
/* 手填行（未建档物料）提示：一眼看出哪些行不参与库存联动 */
.bill-lines-table tr.is-manual .line-info{color:#b45309;font-weight:600}
.bill-lines-foot{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:10px 14px;border-top:1px solid var(--line-2);background:#fbfcfe;
}
.bill-lines-foot .dim{font-size:12.5px;color:var(--ink-3)}
.bill-lines-foot .dim b{color:var(--ink);font-variant-numeric:tabular-nums}

/* ===== 附件自动识别回填的字段：淡绿底 + 细边，提示"这是识别来的，请核对" ===== */
.is-autofilled{background:#f0fdf4;box-shadow:inset 0 0 0 1px #a7f3d0}
.is-autofilled:focus{background:#fff;box-shadow:inset 0 0 0 1px #34d399}

/* 工作台「待办提醒」：宽屏收成一条（标题 + 待办横排），避免通栏卡片里只有一行字显得空洞 */
@media (min-width:821px){
  .dash-todo{display:flex;align-items:center;gap:16px;padding:0 18px}
  .dash-todo .card-head{padding:14px 0;border-bottom:none;flex:none}
  .dash-todo .card-head h3{margin:0;white-space:nowrap}
  .dash-todo .card-body{padding:12px 0;flex:1;min-width:0}
  .dash-todo .card-body > p{margin:0}
}

/* ==========================================================================
   数据备份（设置 → 数据备份）
   列表用卡片行而不是表格：备份条目少、每行要放展开式说明，卡片行在手机上也更好挤
   ========================================================================== */
.bk-stats{margin-bottom:16px}
.bk-stats .st-value{font-variant-numeric:tabular-nums}

.bk-head-meta{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.bk-head-meta .dim{font-size:12.5px}

/* 启用开关那一行：整行可点，避免只有小方块能点中 */
.bk-switch{cursor:pointer}
.bk-switch-line{display:flex;align-items:flex-start;gap:10px}
.bk-switch-line input[type=checkbox]{
  width:17px;height:17px;margin:3px 0 0;accent-color:var(--brand);flex:none;cursor:pointer;
}
.bk-switch-line b{font-size:13.5px;color:var(--ink);font-weight:600}
.bk-switch-line .hint{display:block;margin-top:3px;line-height:1.55}

.bk-time{display:flex;align-items:center;gap:8px}
.bk-time select{width:auto;min-width:74px;height:38px;padding:0 10px;border:1px solid var(--line);
  border-radius:8px;background:#fff;color:var(--ink);outline:none}
.bk-time select:focus{border-color:#b9c1f2;box-shadow:0 0 0 3px rgba(79,70,229,.09)}
.bk-time .dim{font-size:12.5px;color:var(--ink-3)}

.bk-ok{color:#047857;font-weight:600}
.bk-inline-form{display:inline-flex;margin:0}

/* ---------- 备份列表 ---------- */
.bk-list{display:flex;flex-direction:column}
.bk-item{
  display:flex;align-items:flex-start;gap:12px;padding:13px 16px;
  border-top:1px solid var(--line-2);
}
.bk-item:first-child{border-top:none}
.bk-item:hover{background:#fbfcff}
/* 恢复前快照：左侧一条琥珀色标线，一眼区分"这不是普通备份，是退路" */
.bk-item.is-snap{background:#fffdf7;box-shadow:inset 3px 0 0 #f0b429}
.bk-item.is-snap:hover{background:#fffaf0}
.bk-ico{
  width:34px;height:34px;border-radius:9px;flex:none;display:flex;align-items:center;justify-content:center;
  background:var(--brand-soft);color:var(--brand);
}
.bk-item.is-snap .bk-ico{background:#fef3c7;color:#b45309}
.bk-main{flex:1;min-width:0}
.bk-title{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.bk-title b{font-size:13.5px;font-weight:600;color:var(--ink);word-break:break-all}
.bk-meta{display:flex;gap:12px;flex-wrap:wrap;margin-top:3px;font-size:12.5px;color:var(--ink-3)}
.bk-meta span{white-space:nowrap}
.bk-err{margin-top:5px;font-size:12.5px;color:#b91c1c;background:#fef2f2;border:1px solid #f5c6c6;
  border-radius:7px;padding:5px 9px;line-height:1.5;word-break:break-all}
.bk-acts{display:flex;align-items:center;gap:6px;flex:none;flex-wrap:wrap}
.bk-acts form{margin:0}
.bk-empty{padding:38px 18px;text-align:center;color:var(--ink-3);font-size:13.5px}
.bk-empty p{margin:0}
.bk-empty b{color:var(--ink-2)}

/* ---------- 恢复确认 ---------- */
.bk-danger{margin-bottom:16px;border-color:#f5c6c6;box-shadow:0 6px 24px rgba(220,38,38,.08)}
.bk-danger .card-head{background:#fff6f6;border-bottom-color:#f5c6c6;border-radius:var(--radius) var(--radius) 0 0}
.bk-danger .card-head h3{color:#991b1b;display:flex;align-items:center;gap:7px}
.bk-facts{list-style:none;margin:0 0 16px;padding:0;border:1px solid var(--line);border-radius:10px;overflow:hidden}
.bk-facts li{
  display:flex;gap:14px;padding:8px 13px;font-size:13px;border-top:1px solid var(--line-2);
}
.bk-facts li:first-child{border-top:none}
.bk-facts li span{width:74px;flex:none;color:var(--ink-3)}
.bk-facts li b{font-weight:600;color:var(--ink);word-break:break-all}
.bk-confirm-form{max-width:520px}
.bk-confirm-form .field{margin-bottom:8px}
.bk-confirm-form code{background:#f1f3fa;border-radius:4px;padding:1px 5px;font-size:12.5px;letter-spacing:.06em}

/* ---------- 机制说明 ---------- */
.bk-doc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px 24px}
.bk-doc-grid > div > b{display:flex;align-items:center;gap:6px;font-size:13.5px;color:var(--ink)}
.bk-doc-grid > div > b svg{color:var(--brand)}
.bk-doc-grid p{margin:5px 0 0;font-size:12.5px;line-height:1.72;color:var(--ink-3)}
.bk-doc-grid p b{color:var(--ink-2)}
.bk-doc-grid code{background:#f1f3fa;border-radius:4px;padding:1px 5px;font-size:12px;color:#4338ca}

@media (max-width:720px){
  .bk-item{flex-wrap:wrap;gap:10px 10px;padding:12px 14px}
  .bk-ico{order:0}
  .bk-main{order:1;flex:1 1 0;min-width:0}
  .bk-acts{order:2;flex:1 1 100%;justify-content:flex-end;padding-top:2px}
  .bk-doc-grid{grid-template-columns:1fr}
  .bk-facts li span{width:64px}
}

/* 卡片标题带图标时不折行（手机上加徽标会把标题挤成两行） */
.bk-h{display:flex;align-items:center;gap:7px;white-space:nowrap;min-width:0}

/* ==========================================================================
   移动端 App 化（≤820px）：底部 Tab 栏 / 抽屉开关 / 安全区 / 紧凑首页
   —— 目标：H5 套 WebView（HBuilderX H5+）时观感接近原生 App
   ========================================================================== */
:root{--tabbar-h:58px}

/* 桌面不出现：汉堡、Tab 栏、抽屉遮罩 */
.nav-toggle,.tabbar,.nav-mask{display:none}

/* 触摸端去掉点击蓝框（正文仍可长按复制，只针对可点元素） */
a,button,.tab-item,.icon-btn,.nav-item{-webkit-tap-highlight-color:transparent}

@media (max-width:820px){
  html{-webkit-text-size-adjust:100%;text-size-adjust:100%}

  /* ---------- 顶栏：手机端整条隐藏（v1.21.1） ----------
     桌面保留「☰ + 标题 + 消息提醒」；手机端已有底部 Tab 栏承担导航，
     这条常驻栏只剩占地方，故整条不显示。提醒改由底部「消息」Tab 的红点承载。
     内容区自己补上 iOS 刘海安全区，否则会被状态栏压住。 */
  .topbar{display:none}
  .nav-toggle{display:none}
  .page-title{font-size:16px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .hide-sm{display:none !important}
  .icon-btn{width:38px;height:38px}          /* 触摸目标 ≥38，比 34 好按 */

  /* ---------- 内容区：底部留出 Tab 栏 + 小黑条 ---------- */
  .content{
    padding:14px 14px 0;
    padding-top:calc(var(--sb) + 12px);
    padding-bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 16px);
  }
  .foot{display:none}

  /* ---------- 详情页头部：标题与操作按钮分两行 ----------
     原来 .detail-head 是单行 flex，右边 4~5 个按钮不肯换行，
     把左边标题挤到只剩几 px 宽 → 中文被迫一个字一行，成了竖排（v1.32.2 修）。
     现在：标题独占一行、按钮在下面两列铺满；「返回」按用户要求整条隐藏，
     回列表靠底部 Tab 或安卓返回键/侧滑。 */
  .detail-head{flex-direction:column;align-items:stretch;gap:12px;margin-bottom:14px}
  .detail-title{font-size:17px;line-height:1.4}
  .detail-sub{font-size:12.5px;line-height:1.6;margin-top:4px}
  .detail-acts{flex-wrap:wrap;gap:8px}
  .detail-acts > *{flex:1 1 calc(50% - 4px);min-width:0}
  .detail-acts .btn{height:38px;justify-content:center;padding:0 8px;font-size:13px}
  .detail-acts > form{display:flex;margin:0}
  .detail-acts > form .btn{flex:1;height:38px;justify-content:center;font-size:13px}

  /* ---------- 附件卡片：文件名与操作按钮分两行 ----------
     原来 avatar + 文件名 + 3 个按钮挤在一行，按钮宽度把文件名压到几十 px，
     文件名会被拆成"test-/doc./txt"竖着排（v1.32.2 修）。 */
  .attach-actions{flex:1 1 100%;gap:8px}
  .attach-actions .btn{flex:1 1 calc(50% - 4px);min-width:0;height:38px;justify-content:center;font-size:13px}
  .attach-name{overflow-wrap:anywhere}

  /* ---------- 侧栏抽屉 + 遮罩 ---------- */
  /* z-index 要高于底部 Tab 栏(80)，否则抽屉底部会被 Tab 栏压住一截 */
  .sidebar{z-index:90;padding-bottom:env(safe-area-inset-bottom);box-shadow:12px 0 40px rgba(15,23,42,.18)}
  .nav-mask{
    display:block;position:fixed;inset:0;z-index:65;background:rgba(15,23,42,.45);
    opacity:0;pointer-events:none;transition:opacity .18s;
  }
  body.nav-open .nav-mask{opacity:1;pointer-events:auto}
  body.nav-open{overflow:hidden}

  /* ---------- 底部 Tab 栏 ---------- */
  .tabbar{
    display:flex;position:fixed;left:0;right:0;bottom:0;z-index:80;
    background:rgba(255,255,255,.95);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
    border-top:1px solid var(--line);box-shadow:0 -1px 14px rgba(15,23,42,.06);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .tab-item{
    flex:1;height:var(--tabbar-h);display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:3px;color:var(--ink-3);font-size:11px;
  }
  .tab-item .tab-ico{display:flex;align-items:center;justify-content:center;width:24px;height:24px;position:relative}
  /* 未读红点：数字角标，0 条不显示（hidden 属性由 JS 控制） */
  .tab-dot{
    position:absolute;top:-5px;left:50%;margin-left:2px;
    min-width:16px;height:16px;padding:0 4px;border-radius:8px;
    background:var(--bad);color:#fff;font-size:10px;font-style:normal;
    line-height:16px;text-align:center;font-weight:600;
    box-shadow:0 0 0 2px rgba(255,255,255,.96);
  }
  .tab-item.active{color:var(--brand);font-weight:600}
  .tab-item:active{background:rgba(79,70,229,.06)}

  /* ---------- 首页紧凑化：hero 收一半，指标卡横滑一行 ---------- */
  .hero{padding:18px 18px 16px;margin-bottom:14px;border-radius:14px}
  .hero h2{font-size:18px}
  .hero p{font-size:12.5px}
  .hero .hero-meta{gap:20px;margin-top:13px}
  .hero .hm b{font-size:18px}
  .hero .hm span{font-size:12px}

  .stats{
    display:flex;gap:10px;overflow-x:auto;overscroll-behavior-x:contain;
    padding:2px 2px 6px;margin-bottom:14px;scroll-snap-type:x proximity;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;
  }
  .stats::-webkit-scrollbar{display:none}
  .stats > *{flex:0 0 44%;min-width:142px;scroll-snap-align:start}
  .stat{padding:12px 13px}
  .stat .st-value{font-size:19px}

  /* ---------- 应用宫格：4 列，图标缩到 40 ---------- */
  .apps-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:10px 4px}
  .app-tile{padding:11px 2px 10px;gap:7px;border-radius:12px;background:transparent;border:none;box-shadow:none}
  .app-tile:hover{transform:none;box-shadow:none}
  .app-tile .t-icon{transform:scale(.88)}
  .app-tile .t-name{font-size:11.5px;line-height:1.25}

  /* ---------- 待办空态收紧（原来空着也占 127px） ---------- */
  .dash-todo .card-body{padding:12px 16px}
  .dash-todo .card-head{padding:13px 16px}

  /* ---------- iOS 表单聚焦不放大（字号 <16px 会被强制 zoom） ---------- */
  input:not([type=checkbox]):not([type=radio]):not([type=hidden]),
  select,textarea{font-size:16px}
  /* 明细行表格例外：保持紧凑，否则一行被撑到 44px 高，录单没法用 */
  .bill-lines-table input,.bill-lines-table select,.bill-lines-table textarea{font-size:13px}
  .table input,.table select{font-size:13px}

  /* ---------- 弹层/浮层贴边不越界 ---------- */
  .notify-panel{max-width:calc(100vw - 24px)}
}

/* ==========================================================================
   讨论：会话授权 / 撤回 / 加入卡（v1.21.0）
   ========================================================================== */

/* 列表页：私有会话的锁标与「待加入」标签 */
.conv-lock{display:inline-flex;align-items:center;color:var(--ink-3);flex:none}
.conv-join-tag{
  flex:none;padding:1px 6px;border-radius:5px;font-size:10.5px;line-height:16px;
  color:#92400e;background:#fef3c7;border:1px solid #fde68a;
}
.conv-item.is-need-join .conv-name{color:var(--ink-2);font-weight:500}

/* 新建会话表单里的「仅授权成员可见」 */
.conv-new-priv{display:block}
.conv-new-priv label{display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-size:13px}
.conv-new-priv small{display:block;margin-top:3px;font-size:11.5px;line-height:1.5}

/* 内容页标题旁的锁 */
.chat-lock{display:inline-flex;align-items:center;color:var(--ink-3);margin-left:5px;vertical-align:1px}

/* 会话改名（v1.21.1）：标题旁铅笔 → 就地变输入框 */
.chat-title{display:flex;align-items:center;gap:5px}
.chat-title-txt{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-title .chat-lock{margin-left:0}
.chat-title-edit{
  flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;border-radius:6px;border:1px solid transparent;
  background:transparent;color:var(--ink-3);cursor:pointer;opacity:.6;transition:.15s;
}
.chat-title-edit:hover,.chat-title-edit:focus-visible{opacity:1;background:var(--brand-soft);color:var(--brand);border-color:#e0e5ff}
.chat-title.is-editing{gap:6px;overflow:visible}
.chat-title.is-editing .chat-title-input{
  flex:1;min-width:90px;height:28px;padding:0 8px;font-size:14px;border-radius:7px;
  border:1px solid var(--brand);background:#fff;color:var(--ink);
}
/* 改名时先把右侧工具组藏起来：手机顶栏本来就窄，不藏输入框会被挤成一条缝 */
.chat-wrap.is-renaming .chat-head-tools{display:none}

/* 成员与授权面板的关闭按钮（手机端点外面容易点错，给个明确出口） */
.chat-members-x{
  flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;border-radius:6px;border:none;background:transparent;
  color:var(--ink-3);cursor:pointer;
}
.chat-members-x:hover{background:#f1f2f8;color:var(--ink)}

/* 撤回提示：系统条样式，居中弱化（像微信的灰色撤回行） */
.msg-recalled{
  text-align:center;font-size:12px;color:var(--ink-3);
  padding:4px 12px;margin:2px 0;
}
.msg-recalled::before{content:'⌀';font-weight:600;margin-right:5px;color:#c3c6d4}

/* 撤回按钮：浮在自己消息正上方；触屏设备常显（没有 hover） */
.msg{position:relative}
.msg-recall{
  /* 相对 .msg-body 定位：mine 的消息体本身就靠右，按钮才贴得住气泡，
     挂在 .msg 上会跑到整行左端的空白处 */
  position:absolute;top:-15px;right:0;z-index:2;
  display:inline-flex;align-items:center;gap:3px;
  padding:2px 8px;border-radius:20px;border:1px solid var(--line);
  background:#fff;color:var(--ink-3);font-size:11px;line-height:16px;cursor:pointer;
  opacity:0;transform:translateY(2px);transition:opacity .15s,transform .15s;
  box-shadow:0 2px 8px rgba(20,24,45,.10);
}
.msg:hover > .msg-body > .msg-recall,
.msg-recall:focus-visible{opacity:1;transform:translateY(0)}
.msg-recall:hover{color:var(--bad);border-color:#fecaca;background:#fef2f2}
.chat-msgs > .msg:first-child > .msg-body > .msg-recall{top:2px}   /* 第一条再往上会被容器裁掉 */
@media (hover:none){
  .msg-recall{opacity:.72;transform:none}
}

/* 加入确认卡（已授权未加入时替代消息区） */
.chat-join{
  max-width:420px;margin:60px auto 0;text-align:center;
  background:#fff;border:1px solid var(--line);border-radius:16px;
  padding:34px 30px 30px;box-shadow:0 10px 34px rgba(20,24,45,.08);
}
.chat-join-ico{
  width:58px;height:58px;margin:0 auto 14px;border-radius:16px;
  display:flex;align-items:center;justify-content:center;
  background:var(--brand-soft);color:var(--brand);
}
.chat-join h3{margin:0 0 8px;font-size:16px}
.chat-join p{margin:0 0 18px;color:var(--ink-3);font-size:13px;line-height:1.7}

/* 成员与授权面板 */
.chat-members{position:relative}
.chat-members-panel{
  position:absolute;right:0;top:calc(100% + 8px);width:300px;max-height:340px;
  display:flex;flex-direction:column;
  background:#fff;border:1px solid var(--line);border-radius:12px;
  box-shadow:0 14px 40px rgba(20,24,45,.16);z-index:45;
}
.chat-members-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:11px 14px;border-bottom:1px solid var(--line-2);
}
.chat-members-head b{font-size:13.5px}
.chat-members-priv{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--ink-2);cursor:pointer;white-space:nowrap}
.chat-members-info{padding:8px 14px 6px;font-size:11.5px;color:var(--ink-3);line-height:1.6;border-bottom:1px solid var(--line-2)}
.chat-members-list{overflow-y:auto;padding:6px 8px;flex:1}
.chat-members-empty{padding:18px 10px;text-align:center;font-size:12px;color:var(--ink-3)}
.chat-mrow{
  display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:8px;
}
.chat-mrow:hover{background:#f6f7fb}
.chat-mname{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}
.chat-mrow.is-member .chat-mname{font-weight:600}
.chat-mstate{
  flex:none;padding:1px 6px;border-radius:5px;font-size:10.5px;line-height:16px;
  color:#92400e;background:#fef3c7;
}
.chat-mstate.ok{color:#166534;background:#dcfce7}
.chat-mrow input[type=checkbox]{flex:none;width:16px;height:16px;cursor:pointer;accent-color:var(--brand)}

@media (max-width:820px){
  /* 手机上面板太大：直接铺成浮层，挂在视口下部（top 沿用桌面值会掉到屏幕外） */
  .chat-members-panel{
    position:fixed;left:10px;right:10px;top:auto;bottom:calc(70px + env(safe-area-inset-bottom));
    width:auto;max-height:60vh;
  }
  /* 手机端整个「成员与授权」入口不放：浮层正好压住输入框，没地方落。
     授权/名单/可见性开关统一到电脑端做（v1.21.1，用户明确要求） */
  .chat-members{display:none !important}
  .chat-emoji{left:8px;right:8px;width:auto;bottom:calc(100% + 6px)}
}

/* hidden 属性会被 display:flex 盖掉（同 chat-preview 的坑），显式补一条 */
.chat-head-tools[hidden]{display:none !important}

/* v1.21.1：hidden 属性统一生效
   .chat-members-panel / .notify-panel 这类用了 display:flex，会盖掉 hidden 自带的
   display:none —— 表现就是「成员授权面板一直显示着，关不掉，很碍眼」。
   全局补这一条兜住所有同类问题，后续新面板不用再单独写。 */
[hidden]{display:none !important}

/* ==========================================================================
   平台管理：企业授权期限（v1.21.1）
   ========================================================================== */
.auth-period-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.auth-period-row input[type=date]{max-width:190px}
.auth-period-quick{display:flex;gap:6px;flex-wrap:wrap}
.auth-period .hint.is-warn{color:#b45309;font-weight:500}

/* 企业列表里的到期状态 */
.exp-tag{display:inline-flex;align-items:center;gap:4px;font-size:12px;white-space:nowrap}
.exp-tag b{font-weight:600}
.exp-tag.is-soon{color:#b45309}
.exp-tag.is-over{color:var(--bad);font-weight:600}

/* 我的 → 更多入口（v1.21.1：手机端顶栏隐藏后，抽屉菜单进不去，靠这里到各管理页） */
.me-links{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.me-link{
  display:flex;align-items:center;gap:9px;padding:12px 14px;
  border:1px solid var(--line);border-radius:10px;background:#fff;
  font-size:13.5px;color:var(--ink-2);transition:.15s;
}
.me-link .ico{color:var(--ink-3)}
.me-link:hover{border-color:#cfd4e6;background:#fafbff;color:var(--ink)}
.me-link:hover .ico{color:var(--brand)}
.me-link.is-danger{color:var(--bad)}
.me-link.is-danger .ico{color:var(--bad)}


/* ==================================================================
   讨论成员权限页（v1.22.0）：逐成员「能否撤回自己发的消息」
   ================================================================== */
/* 会话列表页右上角的「权限」按钮（仅企业管理员） */
.conv-perm-btn{gap:5px;flex:none}

.perm-page{display:block}
.perm-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}
.perm-head-main{min-width:0}
.perm-title{margin:0 0 4px;font-size:17px;color:var(--ink)}
.perm-sub{margin:0;font-size:12.5px;line-height:1.7;color:var(--ink-3);max-width:640px}
.perm-sub b{color:var(--ink-2);font-weight:600}

.perm-me{
  display:inline-block;margin-left:6px;padding:0 5px;border-radius:4px;
  background:var(--brand-soft);color:var(--brand);font-size:11px;line-height:16px;vertical-align:1px;
}
.perm-dis{
  display:inline-block;margin-left:6px;padding:0 5px;border-radius:4px;
  background:#fdecec;color:var(--bad);font-size:11px;line-height:16px;vertical-align:1px;
}
.perm-fixed{font-size:12.5px;color:var(--ink-3)}

/* 开关：隐掉原生 checkbox，用轨道 + 圆点画（不用图片，无加载抖动） */
.perm-sw{display:inline-flex;align-items:center;gap:9px;cursor:pointer;user-select:none}
.perm-sw input{position:absolute;opacity:0;width:0;height:0}
.perm-sw-track{
  position:relative;flex:none;width:38px;height:21px;border-radius:11px;
  background:#d5d9e6;transition:background .18s;
}
.perm-sw-knob{
  position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;
  background:#fff;box-shadow:0 1px 3px rgba(20,24,46,.25);transition:transform .18s;
}
.perm-sw input:checked + .perm-sw-track{background:var(--brand)}
.perm-sw input:checked + .perm-sw-track .perm-sw-knob{transform:translateX(17px)}
.perm-sw input:disabled + .perm-sw-track{opacity:.45}
.perm-sw input:focus-visible + .perm-sw-track{box-shadow:0 0 0 3px rgba(79,70,229,.18)}
.perm-sw-txt{font-size:12.5px;color:var(--ink-3);min-width:42px}

.perm-tip{font-size:12.5px;padding:3px 9px;border-radius:7px;white-space:nowrap}
.perm-tip.is-ok{background:#e9f7ef;color:#1a7f45}
.perm-tip.is-bad{background:#fdecec;color:var(--bad)}

.perm-note{
  margin:14px 0 0;font-size:12px;line-height:1.8;color:var(--ink-3);
}
.perm-note b{color:var(--ink-2)}

/* 桌面端顶栏已经有页面标题，页内不再重复；手机端顶栏隐藏，靠 perm-title 补回来 */
.perm-title{display:none}
@media (max-width:820px){
  .perm-title{display:block}
  .perm-head{gap:8px}
  .perm-sub{font-size:12px}
  /* 窄屏表格：只留「成员 / 开关」两列，账号与角色收进成员单元格下方 */
  .perm-note{font-size:11.5px}
}

.perm-col-sw{width:190px}
.perm-uid{display:none}
@media (max-width:820px){
  .perm-col-sw{width:auto}
  .perm-uid{display:block;margin-top:3px;font-size:11.5px;color:var(--ink-3)}
}

/* ==================================================================
   头像（v1.23.0）：有图就贴图，没图仍是姓名首字色块
   ================================================================== */
.avatar.has-img{padding:0;overflow:hidden;background:#eef0f5}
.avatar.has-img img{width:100%;height:100%;object-fit:cover;display:block;border-radius:inherit}

/* ---------------- 个人资料页的头像区 ---------------- */
.ava-edit{
  display:flex;align-items:flex-start;gap:16px;
  padding-bottom:18px;margin-bottom:18px;border-bottom:1px solid var(--line-2);
}
.ava-preview{
  width:76px;height:76px;border-radius:50%;flex:none;overflow:hidden;
  background:linear-gradient(135deg,#4f46e5,#7c3aed);color:#fff;
  display:flex;align-items:center;justify-content:center;
  font-size:26px;font-weight:600;line-height:1;
  box-shadow:0 2px 10px rgba(20,24,45,.14);
}
.ava-preview img{width:100%;height:100%;object-fit:cover;display:block}
.ava-ops{flex:1;min-width:0}
.ava-btns{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:7px}
.ava-pick{gap:6px;cursor:pointer}
.ava-remove{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink-3);cursor:pointer;user-select:none}
.ava-remove input{width:15px;height:15px;accent-color:var(--bad);cursor:pointer}
.ava-ops .hint{display:block;line-height:1.7}
.ava-warn{color:var(--bad);font-weight:600}
@media (max-width:820px){
  .ava-edit{gap:12px}
  .ava-preview{width:64px;height:64px;font-size:22px}
}

/* ==================================================================
   手机端会话窗口「全屏化」（v1.24.0）
   ------------------------------------------------------------------
   之前：会话窗口高度是 calc(100dvh - 130px)，底部还压着 58px 的 Tab 栏，
        加上内容区上下 padding，一屏能看消息的地方很窄，键盘一弹更挤。
   现在：手机端点进某个会话 = 二级全屏页——
        ① 窗口铺满整屏（100dvh），去掉圆角/边框，刘海与底部小黑条各自让位；
        ② 底部 Tab 栏整条收起（关闭窗口回到列表后自动恢复，见 layout.php 的 chat-focus）；
        ③ 列表页 / 桌面端完全不受影响。
   body.chat-focus 由服务端在 ?r=discuss&id=N 时渲染，不靠 JS 记状态，
   浏览器后退、侧滑返回、bfcache 恢复都不会残留「Tab 栏不见了」。
   ================================================================== */
@media (max-width:820px){
  /* 底部导航栏：会话窗口里不显示 */
  body.chat-focus .tabbar{display:none}

  /* 内容区不再为 Tab 栏留 58px，也不再加顶部安全区（改由窗口标题栏承担） */
  body.chat-focus .content{padding:0;max-width:none}

  /* 外壳高度对齐「动态视口」：页面不会因为 100vh/100dvh 的差值多出可滚动余量，
     否则输入框自动聚焦时整页会被顶上去一截（标题栏被切） */
  body.chat-focus .shell{min-height:100vh;min-height:100dvh}

  /* 会话窗口铺满一屏 */
  body.chat-focus .chat-wrap{
    height:100vh;height:100dvh;min-height:0;
    border:0;border-radius:0;box-shadow:none;
  }

  /* 标题栏：让出刘海高度，高度仍保持 56px 的可点区域 */
  body.chat-focus .chat-head{
    height:calc(56px + var(--sb));
    padding-top:var(--sb);
  }

  /* 输入区：让出底部小黑条，白色底一直铺到屏幕边缘 */
  body.chat-focus .chat-composer-wrap{padding-bottom:env(safe-area-inset-bottom)}
}

/* 桌面端（>820px）保持原样：卡片式窗口 + 底部 Tab 栏本来就不显示 */

/* ==================================================================
   视频懒加载占位（v1.25.0）
   ------------------------------------------------------------------
   历史问题：消息里的 <video preload="metadata"> 会让浏览器在打开会话时
   就给每个视频发一次 Range 请求（几 MB 的视频光拿 moov 也要几十~几百 KB），
   一屏十个视频就是白烧的流量，手机端尤其明显。
   现在：地址挂在 data-src 上，元素本身没有 src、preload="none"，
   用户点「播放」按钮才赋 src → 此时才真正发请求。
   ================================================================== */
.media-fig{
  position:relative;display:block;flex:none;line-height:0;
  border-radius:8px;overflow:hidden;
}
/* 未加载时的占位尺寸：用 16:9 撑出可点的区域，点了播放后移除 data-src，
   占位规则失效，视频按自身真实比例显示（竖屏视频不会被压成横的） */
video[data-src]{
  width:280px;height:auto;aspect-ratio:16 / 9;
  /* 背景必须透明：无封面的视频靠 .media-fig 的渐变兜底，
     video 自己刷一层底色会把渐变整个盖住（看起来还是死黑一块） */
  background:transparent;cursor:pointer;
}
.media-play{
  position:absolute;inset:0;z-index:2;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;
  border:0;padding:0;cursor:pointer;
  background:linear-gradient(180deg,rgba(12,15,30,.10),rgba(12,15,30,.52));
  color:#fff;font-size:12px;
}
.media-play-ico{
  width:46px;height:46px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.94);color:#2b2f45;
  box-shadow:0 6px 18px rgba(8,10,22,.35);
  transition:transform .15s;
}
.media-play:hover .media-play-ico{transform:scale(1.07)}
.media-play:active .media-play-ico{transform:scale(.95)}
.media-play-txt{text-shadow:0 1px 4px rgba(0,0,0,.55);letter-spacing:.02em}
/* 网格 / 列表里的缩略图很小，只留圆底播放键 */
.chat-msgs[data-media="grid"] .media-play-txt,
.chat-msgs[data-media="list"] .media-play-txt{display:none}
.chat-msgs[data-media="grid"] .media-play-ico{width:36px;height:36px}
.chat-msgs[data-media="list"] .media-play-ico{width:26px;height:26px}
.chat-msgs[data-media="grid"] .media-play-ico svg,
.chat-msgs[data-media="list"] .media-play-ico svg{width:16px;height:16px}
/* 列表模式：占位视频要跟缩略图同宽同高，否则把整行撑高 */
.chat-msgs[data-media="list"] .media-fig video[data-src]{width:52px;height:52px;aspect-ratio:auto}
.chat-msgs[data-media="grid"] .media-fig video[data-src]{width:100%;height:auto;aspect-ratio:1 / 1}
@media (max-width:640px){
  .chat-msgs[data-media="list"] .media-fig video[data-src]{width:46px;height:46px}
  video[data-src]{width:min(280px,72vw)}
}

/* ==================================================================
   头像裁剪弹层（v1.25.0）
   ================================================================== */
body.crop-open{overflow:hidden}
.crop-modal{
  /* z-index 必须高于底部 Tab 栏（80）和图片灯箱（120）：手机端弹层是全屏的，
     层级不够时「确定裁剪」正好被 Tab 栏盖住，点不到 */
  position:fixed;inset:0;z-index:130;display:flex;align-items:center;justify-content:center;
  padding:16px;background:rgba(14,17,34,.56);backdrop-filter:blur(2px);
}
.crop-dlg{
  width:min(420px,100%);max-height:calc(100dvh - 32px);
  display:flex;flex-direction:column;overflow:hidden;
  background:#fff;border-radius:16px;box-shadow:0 24px 64px rgba(12,16,34,.3);
}
.crop-head{
  flex:none;display:flex;align-items:center;justify-content:space-between;
  padding:13px 16px;border-bottom:1px solid var(--line-2);
}
.crop-head h4{font-size:14.5px;font-weight:600}
.crop-x{
  width:28px;height:28px;border:0;border-radius:8px;background:transparent;
  color:var(--ink-3);cursor:pointer;display:flex;align-items:center;justify-content:center;
}
.crop-x:hover{background:#f1f2f8;color:var(--ink)}
.crop-stage{
  position:relative;flex:none;height:300px;overflow:hidden;
  display:flex;align-items:center;justify-content:center;
  background:#1b1f33;touch-action:none;
}
.crop-frame{
  position:relative;overflow:hidden;background:#0d1020;
  box-shadow:0 0 0 9999px rgba(8,10,22,.55);   /* 框外压暗，一框就看出取景区 */
  cursor:grab;touch-action:none;
}
.crop-frame.is-drag{cursor:grabbing}
.crop-frame img{
  position:absolute;left:0;top:0;max-width:none;max-height:none;
  user-select:none;-webkit-user-select:none;-webkit-user-drag:none;pointer-events:none;
}
/* 三分线：帮助把脸放到视觉中心 */
.crop-guide{
  position:absolute;inset:0;pointer-events:none;
  background-image:
    linear-gradient(to right,rgba(255,255,255,.28) 1px,transparent 1px),
    linear-gradient(to bottom,rgba(255,255,255,.28) 1px,transparent 1px);
  background-size:33.333% 100%,100% 33.333%;
  background-position:-1px -1px;
  opacity:.7;
}
.crop-ctl{flex:none;display:flex;flex-direction:column;gap:10px;padding:12px 16px 2px}
.crop-ratios{display:flex;gap:8px}
.crop-ratio{
  flex:1;height:34px;display:inline-flex;align-items:center;justify-content:center;gap:4px;
  border:1px solid var(--line-2);border-radius:9px;background:#fff;
  font-size:12.5px;color:var(--ink-2);cursor:pointer;transition:border-color .15s,background .15s,color .15s;
}
.crop-ratio small{font-size:10.5px;color:var(--brand);opacity:.85}
.crop-ratio:hover{border-color:#c9cde0}
.crop-ratio.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand);font-weight:600}
.crop-zoom{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--ink-3)}
.crop-zoom input[type=range]{flex:1;min-width:0;accent-color:var(--brand);cursor:pointer}
.crop-zoom b{font-size:12px;color:var(--ink-2);font-variant-numeric:tabular-nums;min-width:38px;text-align:right}
.crop-tip{margin:0;font-size:11.5px;color:var(--ink-3);line-height:1.6}
.crop-foot{flex:none;display:flex;justify-content:flex-end;gap:10px;padding:12px 16px 16px}
@media (max-width:640px){
  .crop-modal{padding:0;align-items:stretch}
  .crop-dlg{width:100%;max-height:100dvh;border-radius:0}
  .crop-stage{height:min(46vh,300px);flex:1 1 auto}
  .crop-foot{padding-bottom:calc(14px + env(safe-area-inset-bottom))}
}

/* 头像区：重新裁剪按钮与提示 */
.ava-recrop{padding:0 10px}

/* ==================================================================
   工作台「最近动态」—— v1.26.2 起整块移除
   ------------------------------------------------------------------
   v1.25.0 只是手机端隐藏；v1.26.2 按需求连桌面端一起去掉，
   工作台改为通栏单列（原来的 .grid-2 包裹层也一并删了）。
   操作记录仍可在 平台管理 → 操作日志 查。
   ================================================================== */

/* ==================================================================
   视频封面（v1.26.0）
   ------------------------------------------------------------------
   为什么加：v1.25.0 让视频"点了才加载"后，打开的会话里只剩一片深色空框，
   用户不知道每条视频拍的是什么，只能挨个点开试——省了流量却把成本转给了人。
   做法：发布时在浏览器本地抓一帧（几十 KB 的 JPEG）当封面，
   静默态显示封面，点了才拉正片；正片首帧就绪后封面淡出。

   层级：封面 z-index:1（pointer-events:none，点击穿透到按钮），
        播放按钮 z-index:2，视频 z-index 默认（在封面之下）。
   ================================================================== */
.media-poster{
  position:absolute;inset:0;z-index:1;
  width:100%;height:100%;object-fit:cover;
  display:block;background:#161a2e;
  pointer-events:none;                       /* 别挡住播放按钮的点击 */
  transition:opacity .28s ease;
}
.media-poster.is-out{opacity:0}

/* 有封面时，占位框按封面真实比例撑开：宽 = min(280, 380×比例)。
   横屏视频吃满 280 宽；竖屏视频吃满 380 高（否则一条竖屏视频能占满整屏）。
   这样打开会话时"看到的那块"就是视频画面的真实形状，点了也不会突然变形。 */
.media-fig.has-poster{
  width:min(280px, calc(380px * var(--ar, 1.7778)));
  max-width:100%;
  aspect-ratio:var(--ar, 16 / 9);
  background:#161a2e;
}
.media-fig.has-poster > video[data-src]{
  width:100%;height:100%;aspect-ratio:auto;
}
/* 播放后（data-src 已摘、src 已挂）：视频按自身比例显示，别被容器压扁 */
.media-fig.has-poster > .chat-video{
  max-width:100%;max-height:380px;
}
/* 网格里的格子是正方形：封面裁切铺满，跟图片缩略图排在一起才整齐 */
.chat-msgs[data-media="grid"] .media-fig.has-poster{
  width:100%;aspect-ratio:1 / 1;
}
.chat-msgs[data-media="grid"] .media-fig.has-poster > .chat-video{max-height:none}
/* 列表模式跟 52px 缩略图同尺寸 */
.chat-msgs[data-media="list"] .media-fig.has-poster{
  width:52px;height:52px;aspect-ratio:auto;
}
.chat-msgs[data-media="list"] .media-fig.has-poster > .chat-video{max-height:52px}

@media (max-width:640px){
  .chat-msgs[data-media="list"] .media-fig.has-poster{width:46px;height:46px}
  .chat-msgs[data-media="list"] .media-fig.has-poster > .chat-video{max-height:46px}
  .media-fig.has-poster{width:min(280px, calc(320px * var(--ar, 1.7778)))}
  .media-fig.has-poster > .chat-video{max-height:320px}
}

/* 没有封面的老视频：别给一块死黑，用一层微渐变，
   至少看着像"媒体占位"而不是加载失败 */
.media-fig:not(.has-poster){
  background:
    radial-gradient(120% 100% at 50% 0%, #394066 0%, #20263e 68%, #171b2e 100%);
}

/* 无封面占位：.chat-video 自身带 background:#000（播放时是对的，能掩盖解码边），
   但在"还没播放"的占位态会把父容器那层渐变整个盖掉，于是又变回一块死黑。
   未播放（仍挂 data-src）且没有封面时，让 video 透明，露出渐变底。 */
.media-fig:not(.has-poster) > video.chat-video[data-src]{background:transparent}

/* ==================================================================
   手机端视频全屏播放层（v1.26.2）
   ------------------------------------------------------------------
   问题：手机屏宽 390 时，对话流里的竖屏视频受 max-height:300px 限制，
   只能显示成 169×300 的小方块；打开原生 controls 后，右上角那个 ⋮
   只有"下载/画中画/循环"，没有放大 —— 点了以为坏了。
   做法：手机端点视频直接进这一层，整屏、自绘控件，没有原生菜单。
   层级 126：高于图片灯箱(120)、低于头像裁剪弹层(130)。
   ================================================================== */
.chat-fs{
  position:fixed;inset:0;z-index:126;background:#000;overflow:hidden;
}
.chat-fs[hidden]{display:none}
/* 绝对定位铺满 + contain：竖屏视频在横屏里左右留黑边，但不裁掉画面 */
.fs-video{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;background:#000;display:block;
}
/* 顶部条：渐变压住状态栏那一带，但本身不吃点击（只有关闭键吃） */
.fs-top{
  position:absolute;top:0;left:0;right:0;display:flex;align-items:center;gap:12px;
  padding:calc(10px + var(--sb)) 14px 30px;
  background:linear-gradient(180deg,rgba(0,0,0,.68),rgba(0,0,0,0));
  color:#fff;pointer-events:none;
}
.fs-name{
  flex:1;min-width:0;font-size:13px;line-height:1.4;opacity:.92;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.fs-close{
  flex:none;width:40px;height:40px;padding:0;border:0;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.18);color:#fff;cursor:pointer;
  pointer-events:auto;-webkit-tap-highlight-color:transparent;
}
.fs-close:active{background:rgba(255,255,255,.34)}
.fs-bar{
  position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;gap:12px;
  padding:28px 16px calc(14px + env(safe-area-inset-bottom));
  background:linear-gradient(0deg,rgba(0,0,0,.72),rgba(0,0,0,0));
  color:#fff;
}
.fs-toggle{
  flex:none;width:38px;height:38px;padding:0;border:0;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.18);color:#fff;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.fs-toggle:active{background:rgba(255,255,255,.34)}
/* 图标按播放状态切换：停着显示三角，播着显示双竖线 */
.chat-fs .fs-i-pause{display:none}
.chat-fs.is-playing .fs-i-play{display:none}
.chat-fs.is-playing .fs-i-pause{display:flex}
.fs-time{
  flex:none;font-size:12px;color:#e6e9f2;letter-spacing:.02em;
  font-variant-numeric:tabular-nums;
}
.fs-seek{
  flex:1;min-width:0;height:4px;margin:0;padding:0;border:0;border-radius:3px;
  -webkit-appearance:none;appearance:none;background:rgba(255,255,255,.28);
  outline:none;cursor:pointer;
}
.fs-seek::-webkit-slider-runnable-track{height:4px;border-radius:3px;background:rgba(255,255,255,.28)}
.fs-seek::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:15px;height:15px;margin-top:-5.5px;
  border-radius:50%;background:#fff;box-shadow:0 1px 4px rgba(0,0,0,.5);
}
.fs-seek::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.28)}
.fs-seek::-moz-range-thumb{width:15px;height:15px;border:0;border-radius:50%;background:#fff}
body.fs-open{overflow:hidden}

/* ==================================================================
   跨模块引用单据弹层（v1.27.0）
   ------------------------------------------------------------------
   销售单想抄采购单的物料、入库单想照搬采购明细 —— 都在这一层里完成。
   左栏「来源单据」，右栏「这张单的物料明细」，勾完一次性填进明细表。
   层级 125：高于手机底部 Tab(80)、低于头像裁剪弹层(130)。
   ================================================================== */
.refdlg{
  position:fixed;inset:0;z-index:125;display:flex;align-items:center;justify-content:center;
  padding:24px;background:rgba(15,20,35,.46);
}
.refdlg[hidden]{display:none !important}
body.refdlg-open{overflow:hidden}
.refdlg-box{
  width:min(1020px,100%);max-height:min(780px,calc(100vh - 48px));
  background:var(--card);border-radius:14px;box-shadow:0 24px 64px rgba(15,23,42,.30);
  display:flex;flex-direction:column;overflow:hidden;
}
.refdlg-head{
  display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:14px 16px;border-bottom:1px solid var(--line-2);
}
.refdlg-head b{font-size:15px}
.refdlg-sub{font-size:12.5px}
.refdlg-x{
  margin-left:auto;flex:none;width:30px;height:30px;padding:0;border:0;border-radius:8px;
  display:flex;align-items:center;justify-content:center;
  background:transparent;color:var(--ink-3);cursor:pointer;
}
.refdlg-x:hover{background:var(--line-2);color:var(--ink)}

.refdlg-tabs{display:flex;gap:6px;flex-wrap:wrap;padding:10px 14px 0;border-bottom:1px solid var(--line-2)}
.refdlg-tab{
  padding:6px 12px;border:1px solid var(--line);border-bottom:0;
  border-radius:8px 8px 0 0;background:#fbfcfe;color:var(--ink-2);
  font-size:13px;cursor:pointer;
}
.refdlg-tab:hover{background:var(--line-2)}
.refdlg-tab.is-on{background:var(--brand-soft);border-color:#c7d2fe;color:var(--brand-dark);font-weight:600}

.refdlg-body{flex:1;min-height:0;display:flex}
.refdlg-left{width:330px;flex:none;border-right:1px solid var(--line-2);display:flex;flex-direction:column;min-height:0}
.refdlg-search{padding:10px 12px;border-bottom:1px solid var(--line-2)}
.refdlg-search input{width:100%}
.refdlg-list{flex:1;min-height:0;overflow:auto}
.refdlg-doc{padding:9px 12px;border-bottom:1px solid var(--line-2);cursor:pointer}
.refdlg-doc:hover{background:#f7f9ff}
.refdlg-doc.is-on{background:var(--brand-soft);box-shadow:inset 3px 0 0 var(--brand)}
.refdlg-doc-h{display:flex;align-items:baseline;gap:8px}
.refdlg-doc-h b{font-size:13px;color:var(--ink)}
.refdlg-doc-n{margin-left:auto;font-size:11.5px;color:var(--ink-3)}
.refdlg-doc-m{font-size:12px;color:var(--ink-3);line-height:1.5;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.refdlg-right{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}
.refdlg-docinfo{
  padding:10px 14px;border-bottom:1px solid var(--line-2);background:#fbfcfe;
  font-size:13px;color:var(--ink);line-height:1.5;
}
.refdlg-lines{flex:1;min-height:0;overflow:auto}
.refdlg-table thead th{position:sticky;top:0;z-index:1}
.refdlg-table thead th,.refdlg-table tbody td{white-space:nowrap}
.refdlg-table tbody td{padding:7px 10px;border-bottom:1px solid var(--line-2);font-size:13px}
.refdlg-table tbody tr:hover{background:#fafbff}
.refdlg-table input[type=checkbox]{width:15px;height:15px;cursor:pointer}
.refdlg-raw{
  font-size:11px;color:var(--warn);border:1px solid #fde3c0;background:#fff8ef;
  border-radius:4px;padding:0 4px;margin-left:4px;
}
.refdlg-empty{padding:28px 16px;text-align:center;color:var(--ink-3);font-size:13px}

.refdlg-foot{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:10px 14px;border-top:1px solid var(--line-2);background:#fbfcfe;
}
.refdlg-chk{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink-2);cursor:pointer}
.refdlg-sep{width:1px;height:16px;background:var(--line)}
.refdlg-grow{flex:1}
.refdlg-foot .dim b{color:var(--brand-dark)}

/* 明细表下方：本次引用了哪张单据、几行 */
.bill-ref-sum{
  padding:8px 14px;border-top:1px dashed #c7d2fe;background:#f5f7ff;
  font-size:12.5px;color:var(--brand-dark);
}

@media (max-width:820px){
  .refdlg{padding:0}
  .refdlg-box{width:100%;max-height:100dvh;height:100dvh;border-radius:0}
  .refdlg-head{padding:12px 14px}
  .refdlg-sub{display:none}
  .refdlg-body{flex-direction:column}
  .refdlg-left{width:100%;max-height:40%;border-right:0;border-bottom:1px solid var(--line-2)}
  /* 明细列多，手机放不下就横向滚动 —— 不压缩，否则「物料」会被挤成一字一行 */
  .refdlg-lines{-webkit-overflow-scrolling:touch}
  .refdlg-table{min-width:600px}
  .refdlg-foot{gap:10px;padding-bottom:calc(10px + env(safe-area-inset-bottom))}
  .refdlg-sep{display:none}
  .refdlg-grow{display:none}
  .refdlg-foot #billRefTip{width:100%;order:9}
  /* 取消 / 引用选中行 单独占一行、各一半，不要一个缩在右、另一个掉到别的行 */
  .refdlg-foot .btn{flex:1 1 45%;order:10}
}

/* ==========================================================================
   PWA：添加到桌面（v1.30.0）
   只在「我的」页用一小块卡片承载安装入口，其余页面不打扰
   ========================================================================== */
.pwa-inst{display:flex;align-items:center;gap:12px}
.pwa-inst-ico{
  flex:0 0 46px;width:46px;height:46px;border-radius:13px;
  background:linear-gradient(135deg,#6366f1 0%,#3730a3 100%);
  display:flex;align-items:center;justify-content:center;
  color:#fff;font:600 18px/1 "Microsoft YaHei","PingFang SC",system-ui,sans-serif;
  box-shadow:0 4px 12px rgba(79,70,229,.28);
}
.pwa-inst b{flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--ink)}
.pwa-inst b.is-done{color:var(--ok)}
.pwa-inst .btn{flex:0 0 auto}
.pwa-inst-desc{margin:10px 0 0;font-size:12.5px;line-height:1.7;color:var(--ink-3)}

/* ==========================================================================
   消息提醒设置（v1.31.0）
   开关用 appearance:none 自绘，不引第三方样式；颜色全走变量，深浅色主题都适配
   ========================================================================== */
/* 分隔线用「后一条加上边框」，不用 last-of-type：
   三行里第一行是 div、后两行是 label，last-of-type 会误判到第一行，导致线长在错误的位置 */
.alert-row{display:flex;align-items:center;gap:14px;padding:12px 0}
.alert-row + .alert-row{border-top:1px solid var(--line-2)}
.alert-row:first-child{padding-top:2px}
.alert-row:last-of-type{padding-bottom:2px}
.alert-txt{flex:1;min-width:0}
.alert-txt b{display:block;font-size:14px;font-weight:600;color:var(--ink);line-height:1.5}
.alert-txt i{display:block;margin-top:3px;font-size:12.5px;line-height:1.65;color:var(--ink-3);font-style:normal}
.alert-state{flex:0 0 auto;font-size:12.5px;font-weight:600;color:var(--ok);white-space:nowrap}
.alert-state.is-off{color:var(--ink-3);font-weight:400}
.alert-note{margin:12px 0 0;padding:9px 12px;border-radius:8px;font-size:12.5px;line-height:1.7;
  color:var(--ink-2);background:var(--line-2)}
.alert-note.is-err{color:var(--bad);background:rgba(220,38,38,.07)}
/* 锁屏提醒指引（v1.32.8）：只在 App 壳里显示的卡片，步骤 + 两个系统页按钮 */
.keep-steps{margin:10px 0 12px;padding-left:19px;color:var(--ink-2);font-size:12.5px;line-height:1.75}
.keep-steps li{margin:3px 0}
.keep-steps b{color:var(--ink);font-weight:600}
.keep-btns{display:flex;gap:8px;flex-wrap:wrap}

/* 开关：44×26，滑块 20。安卓/桌面点按区域够大，不用再套 wrapper */
.sw{
  appearance:none;-webkit-appearance:none;
  flex:0 0 44px;width:44px;height:26px;margin:0;padding:0;border:0;
  border-radius:999px;background:var(--line);position:relative;cursor:pointer;
  transition:background .18s ease;
}
.sw::after{
  content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;
  background:#fff;box-shadow:0 1px 3px rgba(20,24,45,.28);
  transition:transform .18s ease;
}
.sw:checked{background:var(--brand)}
.sw:checked::after{transform:translateX(18px)}
.sw:disabled{opacity:.45;cursor:default}
.sw:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
