/* ============================================================
   ALLCENTER 授权中心

   视觉语言取自企业自己的两件东西，不另起一套：

     文化墙「TEAMWORD · 破浪迎晨曦，聚将战沙场」
       海军蓝的字 + 翠绿的三角切角 + 晨曦天光
     已注册商标
       正红 #E00820 + 白色几何标记

   于是分工明确：结构用墨蓝，行动用翠绿，红只留给品牌标记本身。
   纸色是中性偏绿灰而不是米黄 —— 米黄配墨蓝会显脏，配翠绿会显旧。
   数据一律等宽，标题用宋体。
   ============================================================ */

:root {
  --paper: #f2f3ef;
  --paper-2: #e8eae3;
  --surface: #ffffff;
  --surface-2: #f7f8f4;
  --line: #dfe2d9;
  --line-strong: #c9cec2;

  /* 墨：文化墙 TEAMWORD 的字色 */
  --ink: #0e1a2b;
  --ink-2: #2d3b4e;
  --muted: #69737f;
  --muted-2: #98a0a9;

  /* 翠：文化墙那几块三角的绿，压暗到正文可读（白底 5.9:1） */
  --accent: #0c7a50;
  --accent-2: #075e3d;
  --accent-soft: #e4f2ea;
  --accent-line: rgba(12, 122, 80, 0.18);

  /* 红：商标色。只用于品牌标记，不做按钮、不做链接 */
  --brand: #e00820;

  /* 晨曦：首屏天光，冷蓝向纸色过渡 */
  --dawn: #d2e5f6;
  --dawn-soft: #e2edf7;

  --warn: #8a5b10;
  --warn-soft: #faf1df;
  --danger: #a02e22;
  --danger-soft: #fbeae7;

  --radius: 10px;
  --radius-lg: 14px;
  --shadow-sm: 0 1px 2px rgba(14, 26, 43, 0.05), 0 4px 12px -8px rgba(14, 26, 43, 0.18);
  --shadow-md: 0 2px 6px rgba(14, 26, 43, 0.06), 0 18px 40px -24px rgba(14, 26, 43, 0.3);
  --sans: "PingFang SC", "HarmonyOS Sans SC", "Hiragino Sans GB", "Microsoft YaHei",
    system-ui, -apple-system, "Segoe UI", sans-serif;
  --serif: "Source Han Serif SC", "Noto Serif SC", "Songti SC", "SimSun", Georgia, serif;
  --mono: "SF Mono", "JetBrains Mono", "Cascadia Mono", ui-monospace, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font: 16px/1.7 var(--sans);
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    linear-gradient(to right, rgba(14, 26, 43, 0.03) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(14, 26, 43, 0.03) 1px, transparent 1px);
  background-size: 32px 32px;
  mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 30%, transparent 75%);
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-2); }

h1, h2, h3, p { margin: 0; }

.wrap { width: 100%; max-width: 1180px; margin: 0 auto; padding: 0 28px; position: relative; z-index: 1; }

.mono { font-family: var(--mono); font-variant-ligatures: none; }
.muted { color: var(--muted); }

/* 页面主体撑满剩余高度，页脚才不会被顶到半空；具体规则见"首屏"一节 */

/* ---------------------------------------------------------------- 顶栏 */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(242, 243, 239, 0.84);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}

.topbar-in {
  height: 66px;
  display: flex;
  align-items: center;
  gap: 22px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  color: var(--ink);
  font-weight: 600;
  letter-spacing: 0.01em;
}
.brand:hover { color: var(--ink); }

/* 品牌标记就用已注册的那个：红底白 A，几何与微信图标同一份 */
.brand-mark {
  width: 27px;
  height: 27px;
  flex: 0 0 auto;
  display: block;
  border-radius: 7px;
  box-shadow: 0 3px 10px -4px rgba(224, 8, 32, 0.5);
}

.brand-name {
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
}

.brand-sub {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.16em;
  color: var(--muted);
  text-transform: uppercase;
  border-left: 1px solid var(--line-strong);
  padding-left: 12px;
  margin-left: 2px;
  white-space: nowrap;   /* 挤出空间时它会先被压成「授权中 / 心」 */
}

.topnav { margin-left: auto; display: flex; align-items: center; gap: 6px; }

.tlink {
  position: relative;
  color: var(--ink-2);
  font-size: 15px;
  padding: 8px 9px;
  border-radius: 7px;
  transition: color 0.15s ease, background 0.15s ease;
}
.tlink:hover { background: var(--paper-2); color: var(--ink); }

/* 当前页给一条翠色下划线 —— 原来只靠颜色深浅，粘顶滚动时几乎看不出在哪一页 */
.tlink.on { color: var(--ink); font-weight: 600; }
.tlink.on::after {
  content: "";
  position: absolute;
  left: 9px;
  right: 9px;
  bottom: 1px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}

/* ---------------------------------------------------------------- 按钮 */

/* 主按钮用翠绿而不是墨色。
   墨色按钮在白纸上是"灰块"，视觉上退到背景里；翠绿是文化墙的动作色，
   也是整站唯一的高饱和面，点下去之前就知道"这是下一步"。 */
.btn {
  --bg: var(--accent);
  --fg: #fff;
  --bd: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 42px;
  padding: 0 18px;
  border: 1px solid var(--bd);
  border-radius: 9px;
  background: var(--bg);
  color: var(--fg);
  font: inherit;
  font-size: 15.5px;
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.12s ease, background 0.15s ease, box-shadow 0.15s ease,
    border-color 0.15s ease;
  white-space: nowrap;
}
.btn:hover {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: var(--fg);
  box-shadow: 0 10px 20px -12px rgba(12, 122, 80, 0.75);
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; transform: none; }

.btn-ghost {
  --bg: transparent;
  --fg: var(--ink);
  --bd: var(--line-strong);
}
.btn-ghost:hover {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--ink-2);
  box-shadow: var(--shadow-sm);
}

.btn-accent {
  --bg: var(--accent);
  --fg: #fff;
  --bd: var(--accent);
}
.btn-accent:hover { background: var(--accent-2); }

.btn-sm { height: 34px; padding: 0 12px; font-size: 14.5px; border-radius: 7px; }
.btn-block { width: 100%; }

.btn-quiet {
  --bg: transparent;
  --fg: var(--ink-2);
  --bd: transparent;
  height: 34px;
  padding: 0 10px;
  font-size: 14.5px;
}
.btn-quiet:hover { background: var(--paper-2); color: var(--ink); }

/* ---------------------------------------------------------------- 首屏 */

main { flex: 1 0 auto; }

/* 晨曦带。
   文化墙上是这样一幅画：深蓝的字压在晨曦渐变上，底下两块翠绿切角。
   这里把它拆成三层 —— 天光、白雾、切角 —— 文字还是压在中间。 */
.hero-band {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background:
    radial-gradient(74% 58% at 76% -14%, #ffffff 0%, rgba(255, 255, 255, 0) 62%),
    linear-gradient(180deg, var(--dawn) 0%, var(--dawn-soft) 38%, var(--paper) 90%);
}

.hero-band::before,
.hero-band::after {
  content: "";
  position: absolute;
  bottom: 0;
  pointer-events: none;
}
/* 切角用硬边实色，不用渐变淡出 —— 渐隐的三角形看起来像污渍，
   硬边的才像"切"出来的形状，那正是商标图腾和文化墙共有的手法。 */
.hero-band::before {
  left: 0;
  width: 30%;
  height: 208px;
  background: rgba(12, 122, 80, 0.1);
  clip-path: polygon(0 100%, 0 0, 100% 100%);
}
.hero-band::after {
  right: 0;
  width: 25%;
  height: 296px;
  background: rgba(12, 122, 80, 0.075);
  clip-path: polygon(100% 100%, 100% 11%, 0 100%);
}

.hero {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 60px;
  align-items: center;
  padding: 74px 0 44px;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 22px;
}
.eyebrow::before {
  content: "";
  width: 7px;
  height: 7px;
  background: var(--accent);
  border-radius: 1px;
}

.hero h1 {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(35px, 4.3vw, 55px);
  line-height: 1.22;
  letter-spacing: -0.015em;
  margin-bottom: 22px;
  color: var(--ink);
}

/* 下划线比底色块更利落 —— 在浅蓝天光上，绿色块会糊成脏斑。
   首屏与登录页共用这一笔，是两页之间唯一的显式呼应。 */
.hero h1 em,
.auth-aside h1 em {
  font-style: normal;
  position: relative;
  white-space: nowrap;
}
.hero h1 em::after,
.auth-aside h1 em::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.04em;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
  opacity: 0.9;
}

.hero-lead {
  font-size: 17px;
  line-height: 1.82;
  color: var(--ink-2);
  max-width: 30em;
}

.hero-actions { display: flex; gap: 12px; margin-top: 32px; flex-wrap: wrap; }

.hero-note {
  margin-top: 20px;
  font-size: 14.5px;
  color: var(--muted);
  font-family: var(--mono);
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  gap: 9px;
}
.hero-note::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* 企业信条，压在晨曦带底部正中，像信笺上的印章。
   文化墙原句，一个字不改。放中间是因为两侧正好是绿三角，
   左边那块最实，字压上去会糊。 */
.hero-motto {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 15px;
  padding: 0 0 30px;
  font-family: var(--serif);
  font-size: 14.5px;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  color: #4d5866;
}
.hero-motto::before,
.hero-motto::after {
  content: "";
  width: 38px;
  height: 1px;
  flex: 0 0 auto;
  background: var(--accent);
  opacity: 0.5;
}

/* 授权卡 —— 页面右侧的实物 */
.lic-wrap { display: flex; flex-direction: column; }
.lic-stage { position: relative; }
.lic-caption {
  position: relative;
  margin-top: 30px;
  text-align: center;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.lic-stage::before {
  content: "";
  position: absolute;
  inset: 18px -14px -18px 22px;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(14, 26, 43, 0.06);
  border-radius: var(--radius-lg);
  transform: rotate(-1.4deg);
}

.lic-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: 24px 24px 20px;
  box-shadow: var(--shadow-md);
  overflow: hidden;
}

/* 卡片顶上一条翠色，和下面那排状态灯是同一个语义：这设备在跑 */
.lic-card::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent) 58%, rgba(12, 122, 80, 0.12) 100%);
}

.lic-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}

.lic-label {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.2em;
  color: var(--muted-2);
  text-transform: uppercase;
}

.lic-code {
  font-family: var(--mono);
  font-size: 25px;
  letter-spacing: 0.02em;
  font-weight: 500;
  color: var(--ink);
  padding: 14px 0 16px;
  border-bottom: 1px dashed var(--line-strong);
}

.lic-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  padding: 16px 0 18px;
}
.lic-meta span {
  display: block;
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 4px;
}
.lic-meta b {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 500;
}

.leds { display: grid; grid-template-columns: repeat(12, 1fr); gap: 4px; }
.leds i {
  height: 18px;
  border-radius: 2px;
  background: var(--accent);
  opacity: 0.82;
  animation: led 4.2s ease-in-out infinite;
}
.leds i:nth-child(3n) { animation-delay: 0.6s; opacity: 0.62; }
.leds i:nth-child(4n+1) { animation-delay: 1.4s; opacity: 0.92; }
.leds i:nth-child(5n+2) { animation-delay: 2.1s; opacity: 0.5; }
@keyframes led {
  0%, 100% { opacity: 0.78; }
  50% { opacity: 0.42; }
}

.lic-foot {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.14em;
  color: var(--muted-2);
  text-transform: uppercase;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 9px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 500;
  border: 1px solid transparent;
  white-space: nowrap;
}
.pill i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.pill-ok { background: var(--accent-soft); color: var(--accent-2); border-color: rgba(12, 122, 80, 0.16); }
.pill-warn { background: var(--warn-soft); color: var(--warn); border-color: rgba(143, 90, 18, 0.18); }
.pill-bad { background: var(--danger-soft); color: var(--danger); border-color: rgba(156, 51, 39, 0.16); }
.pill-idle { background: var(--paper-2); color: var(--muted); border-color: var(--line); }

/* ---------------------------------------------------------------- 区块 */

.section { padding: 66px 0; border-top: 1px solid var(--line); }
/* 紧跟晨曦带的第一段不再画线，否则和 hero 的底边叠成双线 */
.section-first { border-top: 0; padding-top: 54px; }

.sec-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 34px;
  flex-wrap: wrap;
}

.sec-head h2 {
  display: flex;
  align-items: center;
  gap: 11px;
  font-family: var(--serif);
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
/* 区块标题前一枚翠色竖标，与 eyebrow 的方点是同一套记号 —— 全站统一的"起手式" */
.sec-head h2::before {
  content: "";
  width: 3px;
  height: 18px;
  flex: 0 0 auto;
  border-radius: 2px;
  background: var(--accent);
}

.sec-head p { color: var(--muted); font-size: 15px; }

/* 说明页里的小节标题。原先这类 h2 一条样式都没有，靠浏览器默认字号撑着，
   和首页的 .sec-head h2 完全是两套观感 —— 补上同一枚翠色竖标。 */
.sec-title {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 40px 0 16px;
}
.sec-title::before {
  content: "";
  width: 3px;
  height: 15px;
  flex: 0 0 auto;
  border-radius: 2px;
  background: var(--accent);
}

/* 白底衬板：把引导性内容从纸面上抬起来，与后面的目录分开 */
.panel-soft {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 36px 32px 38px;
  box-shadow: var(--shadow-sm);
}

/* 墨蓝衬板：要人掏钱的区块需要一块压得住的底。
   底纹是文化墙的复刻 —— 深蓝渐变，加一角翠绿切角。 */
.panel-ink {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  padding: 40px 36px 42px;
  color: #e8ebe4;
  background:
    radial-gradient(72% 88% at 94% 2%, rgba(12, 122, 80, 0.34), transparent 64%),
    linear-gradient(158deg, #11223a 0%, var(--ink) 56%, #0a1424 100%);
}
.panel-ink::after {
  content: "";
  position: absolute;
  right: -30px;
  bottom: -50px;
  width: 240px;
  height: 240px;
  background: rgba(12, 122, 80, 0.18);
  clip-path: polygon(100% 100%, 100% 0, 0 100%);
  pointer-events: none;
}
.panel-ink .sec-head { margin-bottom: 28px; position: relative; z-index: 1; }
.panel-ink .sec-head h2 { color: #fff; }
.panel-ink .sec-head h2::before { background: #3ecf93; }
.panel-ink .sec-head p { color: rgba(232, 235, 228, 0.6); }
.panel-ink .plans { position: relative; z-index: 1; }

/* 步骤 */

.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }

.step { border-top: 2px solid var(--accent); padding-top: 20px; }
.step-n {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.16em;
  color: var(--accent);
  font-weight: 600;
  margin-bottom: 10px;
}
.step h3 { font-size: 17px; font-weight: 600; margin-bottom: 8px; }
.step p { color: var(--ink-2); font-size: 15px; line-height: 1.75; }
.step .mono { font-size: 14.5px; color: var(--accent); white-space: nowrap; }

/* 价格 */

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

.plan {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 26px 22px 22px;
  display: flex;
  flex-direction: column;
  position: relative;
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.plan:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }

/* 推荐档不再反白成墨块：它现在站在墨蓝面板上，再压一层深色就直接没了。
   改成一圈翠色描边 + 实心标签，在深底上比暗卡片更跳。 */
.plan.featured {
  border-color: var(--accent);
  background: linear-gradient(180deg, #f7fdfa 0%, #e9f6ef 100%);
  box-shadow: 0 0 0 1px var(--accent), 0 26px 52px -30px rgba(0, 0, 0, 0.7);
}
.plan.featured:hover { transform: translateY(-3px); }

.plan-tag {
  position: absolute;
  top: 20px;
  right: 20px;
  font-size: 13px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-2);
  border: 1px solid var(--accent-line);
}
.plan.featured .plan-tag { background: var(--accent); color: #fff; border-color: transparent; }

.plan-name { font-size: 15px; font-weight: 600; color: var(--ink-2); letter-spacing: 0.01em; }

.plan-price { display: flex; align-items: baseline; gap: 4px; margin: 14px 0 4px; }
.plan-price span { font-size: 17px; color: var(--muted); }
.plan-price b {
  font-family: var(--mono);
  font-size: 40px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
}
.plan-price em { font-style: normal; font-family: var(--mono); font-size: 14px; color: var(--muted); }

.plan-term { font-size: 14.5px; color: var(--muted); margin-bottom: 18px; }

.plan ul { list-style: none; margin: 0 0 24px; padding: 0; display: grid; gap: 9px; }
.plan li { position: relative; padding-left: 16px; font-size: 15px; color: var(--ink-2); }
.plan li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 1px;
  background: var(--accent);
}
.plan .btn { margin-top: auto; }

/* FAQ */

.faq { display: grid; grid-template-columns: repeat(2, 1fr); gap: 26px 46px; }
.faq-item h3 { font-size: 16px; font-weight: 600; margin-bottom: 7px; }
.faq-item p { font-size: 15px; color: var(--ink-2); line-height: 1.75; }

/* 页脚 */

.footer {
  border-top: 1px solid var(--line);
  padding: 38px 0 44px;
  margin-top: auto;
  background: var(--surface-2);
}
.footer-in { display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; font-size: 14.5px; color: var(--muted); }
.footer-in .mono { font-size: 13px; letter-spacing: 0.1em; }

/* 备案与主体信息。微信审核会看这一行，客户判断"这是不是正经公司"也看这一行 */
.footer-legal {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  font-size: 13.5px;
  color: var(--muted-2);
}
.footer-legal a { color: var(--muted-2); border-bottom: 1px solid var(--line-strong); }
.footer-legal a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.footer-legal .sep { color: var(--line-strong); }

/* ---------------------------------------------------------------- 登录页 */

/* 两栏原来是 align-items:center，左侧比右侧卡片矮两百多像素，
   居中之后标题浮在半空、跟卡片的顶边对不上，看着像没对齐。
   改成顶部对齐：文字从卡片上沿起笔，读者一眼知道从哪开始。 */
.auth-shell {
  min-height: calc(100vh - 66px);
  display: grid;
  grid-template-columns: 1fr 460px;
  gap: 72px;
  align-items: start;
  padding: 64px 0 80px;
}
/* 手机上 auth-shell 收成一列，grid 子项默认 min-width:auto，
   40px 的标题会把它顶出容器 18px —— 正好是 .wrap 的内距，很容易误判成 padding 写错。 */
.auth-aside { padding-top: 6px; min-width: 0; }
.auth-card { min-width: 0; }

.auth-aside h1 {
  font-family: var(--serif);
  font-size: 40px;
  line-height: 1.28;
  font-weight: 600;
  margin-bottom: 18px;
  letter-spacing: -0.012em;
  color: var(--ink);
}

.auth-aside p { color: var(--ink-2); font-size: 16px; max-width: 26em; line-height: 1.85; }

.auth-points { list-style: none; padding: 0; margin: 30px 0 0; display: grid; gap: 14px; }
.auth-points li {
  display: flex;
  gap: 12px;
  font-size: 15px;
  color: var(--ink-2);
  line-height: 1.6;
}
.auth-points b {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--accent);
  border: 1px solid rgba(12, 122, 80, 0.24);
  border-radius: 4px;
  height: 20px;
  min-width: 26px;
  display: grid;
  place-items: center;
  flex: none;
  margin-top: 1px;
}

/* 认证礼包卡（注册页左侧）：跟着「公司 / 个人」切换，一次只显示对应的那一档。
   两档差一倍，并排摆着反而要客户自己比；只给当前选的那张，张数和面额一眼看完。
   2026-11-09：企业 ¥2000 / 19 张，个人 ¥1000 / 11 张。 */
.auth-gift { margin-top: 32px; max-width: 30em; }
.ag-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.ag-title { font-size: 15px; font-weight: 600; color: var(--ink); }
.ag-sub { font-size: 13.5px; color: var(--muted); }
.ag-card {
  padding: 14px 16px 15px;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius);
  background: var(--surface);
}
/* 用属性选择器切，不在 JS 里逐个 hidden —— 没脚本时也有默认那一档在。 */
.auth-gift[data-entity="company"] .ag-card[data-for="person"],
.auth-gift[data-entity="person"] .ag-card[data-for="company"] { display: none; }
.ag-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.ag-ent { font-size: 14px; color: var(--ink-2); }
.ag-count { font-size: 13.5px; color: var(--muted); }
.ag-val {
  font-family: var(--serif);
  font-size: 30px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
  margin: 2px 0 9px;
  letter-spacing: -0.01em;
}
.ag-chips { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.ag-chips li {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  padding: 2px 9px;
  border: 1px dashed var(--line-strong);
  border-radius: 999px;
  font-size: 13.5px;
  color: var(--ink-2);
}
.ag-chips b { font-weight: 600; color: var(--ink); }
.ag-hint { margin: 10px 0 0; font-size: 13.5px; line-height: 1.7; color: var(--muted); }

.auth-card {
  background:
    linear-gradient(90deg, var(--accent) 0%, var(--accent) 44%, rgba(12, 122, 80, 0.08) 100%) top left / 100% 3px no-repeat,
    var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: 30px;
  box-shadow: var(--shadow-md);
}

.auth-tabs { display: flex; gap: 2px; background: var(--paper-2); padding: 3px; border-radius: 9px; margin-bottom: 24px; }
.auth-tab {
  flex: 1;
  height: 34px;
  border: 0;
  background: transparent;
  border-radius: 7px;
  font: inherit;
  font-size: 15px;
  color: var(--muted);
  cursor: pointer;
}
.auth-tab[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
  font-weight: 500;
  box-shadow: 0 1px 3px rgba(14, 26, 43, 0.1);
}

.field { margin-bottom: 15px; }
.field label { display: block; font-size: 14.5px; color: var(--ink-2); margin-bottom: 6px; font-weight: 500; }
.field input {
  width: 100%;
  height: 42px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.field input::placeholder { color: var(--muted-2); }
.field input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.12);
}
.field-hint { font-size: 13.5px; color: var(--muted); margin-top: 5px; }
/* 只读字段（编辑项目里的站点码）：要和可编辑的输入框一眼分开，
   否则客户会点进去打字，发现打不动再来问「为什么改不了站点码」。 */
.field input[readonly] {
  background: var(--paper-2); color: var(--muted); cursor: default;
}
.field input[readonly]:focus { border-color: var(--line-strong); box-shadow: none; }

/* 注册：账号类型公司 / 个人。两块并排，选中态靠 JS 加 .on，
   不用 :has() —— 老一点的 WebView 还没支持，注册页偏偏最常在微信里打开。
   选择器要压过 .field label / .field input：这两条是给文字输入框写的，
   radio 和 label 也在 .field 里，不覆盖会被拉成 42px 高的大方框。 */
.entity-pick { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.field .entity-pick .ep-item {
  display: flex; align-items: flex-start; gap: 8px;
  margin-bottom: 0; padding: 10px 11px;
  border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface); cursor: pointer;
}
.field .entity-pick .ep-item input[type="radio"] {
  width: 15px; height: 15px; padding: 0; margin: 2px 0 0;
  border: 0; border-radius: 0; background: none; box-shadow: none;
  flex: none; accent-color: var(--accent); cursor: pointer;
  transition: none;
}
.field .entity-pick .ep-item input[type="radio"]:focus { box-shadow: none; }
.field .entity-pick .ep-item.on { border-color: var(--accent); background: var(--accent-soft); }
.ep-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ep-name { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.ep-note { font-size: 13.5px; line-height: 1.4; color: var(--muted); }
/* 公司名查重：候选直接贴在输入框下面，不另起一个 select。
   输入框保持客户自己敲的字，最接近的一条排第一，点一下才替换成标准名。 */
.cbox { position: relative; }
.cbox-menu {
  position: absolute; z-index: 30;
  top: calc(100% + 6px); left: 0; right: 0;
  background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 10px;
  box-shadow: 0 14px 34px rgba(20, 24, 22, 0.13);
  overflow: hidden;
}
.cbox-list { list-style: none; margin: 0; padding: 4px; max-height: 232px; overflow-y: auto; }
.cbox-item {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 10px; border-radius: 7px; cursor: pointer;
}
.cbox-item:hover, .cbox-item.on { background: var(--accent-soft); }
.cbox-name {
  flex: 1 1 auto; min-width: 0;
  font-size: 14.5px; line-height: 1.45; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cbox-item.on .cbox-name { color: var(--accent); font-weight: 600; }
.cbox-tag {
  flex: none; font-size: 13.5px; letter-spacing: 0.02em;
  color: var(--muted); border: 1px solid var(--line-strong);
  border-radius: 999px; padding: 1px 7px;
}
.cbox-tag.near { color: var(--accent); border-color: var(--accent-line); background: var(--surface); }
.cbox-foot {
  padding: 7px 11px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--muted); background: var(--surface-2);
}
.cbox-undo {
  margin-left: 6px; padding: 0; border: 0; background: none;
  font: inherit; color: var(--accent); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.cbox-undo[hidden] { display: none; }
/* .field 本身没写 display，但显式补上更保险：隐藏的必填框会在提交时
   报「无法聚焦」，把整次注册悄悄拦下来。 */
#regCompanyField[hidden] { display: none; }

.form-error {
  background: var(--danger-soft);
  border: 1px solid rgba(156, 51, 39, 0.18);
  color: var(--danger);
  border-radius: 8px;
  padding: 9px 12px;
  font-size: 14.5px;
  margin-bottom: 14px;
  display: none;
}
.form-error.show { display: block; }

.divider {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--muted-2);
  font-size: 13px;
  letter-spacing: 0.1em;
  margin: 20px 0;
}
.divider::before, .divider::after { content: ""; height: 1px; background: var(--line); flex: 1; }

.wx-btn {
  width: 100%;
  height: 44px;
  border-radius: 8px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15.5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  cursor: pointer;
}
.wx-btn:hover { background: var(--surface-2); }
.wx-btn svg { width: 19px; height: 19px; }
.wx-btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* 未配置微信时的说明。只给一个灰按钮，客户会以为网站坏了。 */
.wx-hint {
  margin-top: 10px;
  font-size: 14px;
  line-height: 1.7;
  color: var(--muted);
}
.wx-hint .mono { font-size: 13px; color: var(--ink-2); }

/* 微信授权失败回来的提示。过期、取消授权、已被别的账号绑定都要分开说 ——
   统一写「登录失败」，用户唯一能做的就是再点一次，然后还是失败。 */
.wx-msg {
  margin: 0 0 12px;
  padding: 10px 13px;
  border-radius: 9px;
  border: 1px solid rgba(160, 90, 30, 0.24);
  background: #fdf3e3;
  color: #7a4a10;
  font-size: 14.5px;
  line-height: 1.75;
}
.wx-msg b { color: #5c3708; }

/* 资料没补全被限制登录：跟「微信授权失败」那种可重试的提示不是一类事，
   用警示色分开，免得客户看成「再点一次就好了」。 */
.wx-msg.lock {
  border-color: rgba(156, 51, 39, 0.28);
  background: var(--danger-soft);
  color: var(--danger);
}
.wx-msg.lock b { color: #5c1108; }

/* 演示通道：只在 dev 模式出现，用来看注册链路通不通 */
.wx-demo {
  margin-top: 14px;
  padding: 12px 13px;
  border: 1px dashed rgba(12, 122, 80, 0.28);
  border-radius: 9px;
  background: var(--accent-soft);
}
.wx-demo-h {
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
.wx-demo p {
  margin: 6px 0 9px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink-2);
}
.wx-demo form { display: flex; gap: 7px; }
.wx-demo input {
  flex: 1;
  min-width: 0;
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  font: inherit;
  font-size: 14.5px;
  color: var(--ink);
}
.wx-demo input:focus { outline: none; border-color: var(--accent); }

/* 补资料浮层的说明段 */
.pg-lead {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--ink-2);
  margin: 0 0 14px;
}

/* 补资料浮层里的规则条：「第几次 / 共几次 / 什么时候会被限速」。
   塞进正文小字里等于没写 —— 客户要能在决定跳过之前看到代价。 */
.pg-meter {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--paper-2);
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--muted);
}
.pg-meter b {
  display: block;
  margin-bottom: 2px;
  font-size: 14px;
  color: var(--ink-2);
}
.pg-meter.is-last {
  border-color: rgba(156, 51, 39, 0.22);
  background: var(--danger-soft);
  color: var(--danger);
}
.pg-meter.is-last b { color: var(--danger); }

/* 补资料第二步：字段一对一对排，否则 10 个框竖着堆要往下滚两屏。
   手机上退回单列 —— 窄屏并排会把「公司全称」这种长值挤成省略号。 */
.pg-modal-wide { max-width: 640px; }
.pg-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.pg-form .field.full { grid-column: 1 / -1; }
@media (max-width: 560px) {
  .pg-form { grid-template-columns: 1fr; }
  .pg-form .field.full { grid-column: auto; }
}
/* .overlay.single .modal 写死 display:flex，会盖掉 [hidden] 的 display:none ——
   两步靠 hidden 切换，不补这一条两张弹窗会同时亮着。 */
.overlay.single .modal[hidden] { display: none; }
/* 第二步的弹窗比第一步高，头部和底部固定、中间滚动，按钮才不会被推出屏幕 */
.pg-modal .modal-body { min-height: 0; }
/* .field-row 写死 display:grid，同样会盖掉 [hidden] —— 省市区有库时
   这一行必须真的消失，不然会和上面的三格下拉叠成两套控件（踩过一次）。 */
#pgRegionFallback[hidden] { display: none; }
/* 第二步字段多，提示行压到 13px（全站下限）并收紧行距 —— 长表格里
   每行省 6px，整体就能少滚一屏 */
.pg-form .field { margin-bottom: 12px; }
.pg-form .field-hint { font-size: 13px; margin-top: 4px; line-height: 1.5; }

.auth-foot { margin-top: 18px; font-size: 14.5px; color: var(--muted); text-align: center; }
.auth-foot a { border-bottom: 1px solid rgba(12, 122, 80, 0.3); }

.dev-note {
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px dashed rgba(143, 90, 18, 0.3);
  border-radius: 7px;
  padding: 8px 10px;
  line-height: 1.6;
}

/* ---------------------------------------------------------------- 控制台 */

.console-head { padding: 40px 0 26px; display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.console-head h1 { font-family: var(--serif); font-size: 30px; font-weight: 600; letter-spacing: -0.01em; }
.console-head p { color: var(--muted); font-size: 15px; margin-top: 5px; }

/* 左栏原来是 align-items:start，一个站点时它比右侧面板短一大截，
   底下那截空白看着像页面没加载完。改成拉齐，按钮用 margin-top:auto 吸底，
   两侧就成了一条线 —— 站点多的时候左栏自己长，右侧跟着走，也不会错位。 */
.console-grid { display: grid; grid-template-columns: 300px 1fr; gap: 24px; align-items: stretch; padding-bottom: 26px; }
.console-grid > aside.panel { display: flex; flex-direction: column; }
.console-grid > aside.panel .side-foot { margin-top: auto; }

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.panel-head {
  padding: 16px 18px;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.panel-head h2 { font-size: 14.5px; font-weight: 600; letter-spacing: 0.02em; color: var(--ink-2); }
.panel-body { padding: 18px; }

/* 找项目：搜索 + 状态筛选。站点少时整块收起（见 console.html 的 hidden），
   多了才占这两行 —— 一两个站点摆个搜索框，是在暗示客户「你该有很多」。 */
.site-tools { padding: 11px 12px 10px; border-bottom: 1px solid var(--line); display: grid; gap: 8px; background: var(--surface-2); }
.site-search { position: relative; display: flex; align-items: center; }
.site-search > svg { position: absolute; left: 9px; width: 13px; height: 13px; color: var(--muted-2); pointer-events: none; }
.site-search input {
  width: 100%;
  height: 32px;
  padding: 0 26px 0 27px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  font: inherit;
  font-size: 14px;
  color: var(--ink);
}
.site-search input::placeholder { color: var(--muted-2); }
.site-search input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.site-search input::-webkit-search-cancel-button { display: none; }
.site-search-clear {
  position: absolute; right: 3px;
  width: 22px; height: 22px;
  border: 0; border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font-size: 16px; line-height: 1;
  cursor: pointer;
}
.site-search-clear:hover { background: var(--paper-2); color: var(--ink); }

/* 省 / 市 / 县索引。省占一整行、市与县各半行：左栏 250px，三个并排
   连「内蒙古」都写不全。下拉里存的是全称、显示的是简称（见 shortArea）。 */
.site-region { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.site-region[hidden] { display: none; }
.site-region .rg-prov { grid-column: 1 / -1; }
.rg-sel {
  width: 100%;
  height: 28px;
  padding: 0 19px 0 7px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background-color: var(--surface);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6' fill='none' stroke='%23888' stroke-width='1.4'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 6px center;
  background-size: 8px 5px;
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  font-size: 13px;
  line-height: 1;
  color: var(--ink-2);
  cursor: pointer;
}
.rg-sel:hover { border-color: var(--line-strong); }
.rg-sel:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* 选中态和状态胶囊一致：填深底，一眼看出「现在按地区收了范围」。 */
.rg-sel.on { background-color: var(--ink); border-color: var(--ink); color: #fff; font-weight: 500; }

.site-chips { display: flex; gap: 4px; flex-wrap: wrap; }
.schip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.schip:hover { border-color: var(--line-strong); color: var(--ink-2); }
.schip b { font-weight: 500; font-variant-numeric: tabular-nums; opacity: 0.55; }
.schip[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: #fff; }
.schip[aria-pressed="true"] b { opacity: 0.75; }
.schip-plat[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); }

.sitelist { display: grid; gap: 2px; max-height: 540px; overflow-y: auto; overscroll-behavior: contain; }
.siteitem {
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  padding: 12px 16px;
  cursor: pointer;
  font: inherit;
  display: grid;
  gap: 3px;
  transition: background 0.12s ease;
}
.siteitem:hover { background: var(--surface-2); }
.siteitem[aria-current="true"] { background: var(--accent-soft); border-left-color: var(--accent); }
/* 徽标紧贴站点码，平台标签才靠右 —— 三个子元素用 space-between 时
   徽标会被顶到中间，和站点码之间空出一大块，看着像没对齐。 */
.siteitem .s-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.siteitem .s-code { font-family: var(--mono); font-size: 14.5px; letter-spacing: 0.01em; color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.siteitem .s-plats { display: inline-flex; gap: 3px; flex: none; margin-left: auto; }
/* 公司分配 / 临时分享：左栏一排站点码长得一样，得一眼看出哪个不是自己建的。
   用最小号的实心标签，别和「有效/过期」那个状态点抢注意力。
   徽标只报「关系」，人名交给下面那行「创建人」——两处都写名字会重复，也挤。 */
.siteitem .s-share {
  flex: none;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: 0.02em;
}
.siteitem .s-sub { font-size: 13.5px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.siteitem .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--muted-2); flex: none; }

/* 停用 / 吊销：左栏一列站点码，只有第二行末尾那句「已停用」是看不见的。
   和「共享」同一档的实心小标签，但用红底 —— 它要说的是「这台现在不能用」。 */
.siteitem .s-off {
  flex: none;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--danger-soft);
  color: var(--danger);
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: 0.02em;
}

/* 「创建人」单独一行，每一行都有 —— 公司里项目会转手、会被同事的同事再分享，
   只挂「共享 / 分享」根本不知道该找谁。标签灰、名字深一号，扫一列就能比。 */
.siteitem .s-who-row { display: flex; align-items: center; gap: 12px; min-width: 0; margin-top: 1px; }
.siteitem .s-who {
  display: inline-flex; align-items: baseline; gap: 4px;
  min-width: 0; max-width: 100%;
  font-size: 13.5px; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.siteitem .s-who .s-k { color: var(--muted-2); flex: none; }

/* 平台徽标：两三个字母，悬停给全名。和目录页 .pr-plat 同一套外观，
   不另起配色 —— 平台是事实标签，不是状态，用颜色会跟「有效/过期」抢注意力。
   只有一个平台时 JS 不渲染（见 portal.js 的 hasMultiPlatform）。 */
.plat-tag {
  display: inline-flex;
  align-items: center;
  height: 17px;
  padding: 0 5px;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  background: var(--paper-2);
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.06em;
  line-height: 1;
  white-space: nowrap;
}
.dot.ok { background: var(--accent); }
.dot.warn { background: var(--warn); }
.dot.bad { background: var(--danger); }

.site-empty { padding: 26px 18px; font-size: 14.5px; color: var(--muted); text-align: center; line-height: 1.7; }
.site-empty .link-btn { color: var(--accent); font-size: 14.5px; text-decoration-color: var(--accent-line); }

.side-foot { border-top: 1px solid var(--line); padding: 14px 16px; }

/* 详情 */

.detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.detail-code-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.detail-code { font-family: var(--mono); font-size: 24px; letter-spacing: 0.01em; }
/* 编辑项目：靠右、带边框，和「站点码 + 平台徽标」拉开距离。
   它必须像一颗按钮，不能像一行小字 —— 客户找不到入口就等于没有这个功能。
   2026-11-08 起这颗按钮移到标题下方的 .detail-tools 一整行：挤在站点码
   右边时它和徽标长得像同一类东西，客户连着两轮说「找不到入口」。 */
.detail-code-row .plat-tag { height: 18px; font-size: 13.5px; padding: 0 6px; }
.detail-alias { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 14.5px; color: var(--muted); margin-top: 6px; }
.detail-alias .da-name { font-size: 14.5px; color: var(--ink-2); }
.detail-alias .da-share {
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--accent-line, var(--line-strong));
  color: var(--accent);
  font-size: 13.5px;
  line-height: 1.6;
}
.detail-alias .da-meta { color: var(--muted); }
.link-btn {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 13.5px;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line-strong);
}
.link-btn:hover { color: var(--accent); text-decoration-color: var(--accent-line); }
/* 项目资料编辑块：名称 + 地区 + 按钮，占满整行（.detail-alias 是 flex，
   flex-basis:100% 让它自己换行，不跟「绑定于 …」挤在一起）。 */
.alias-edit { flex: 1 1 100%; display: block; }
.alias-edit .field { margin-bottom: 10px; }
.alias-edit .field label { font-size: 13.5px; margin-bottom: 4px; }
.alias-edit .ae-name input {
  width: 100%;
  max-width: 340px;
  height: 34px;
  padding: 0 9px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  font: inherit;
  font-size: 14.5px;
  color: var(--ink);
}
.alias-edit .ae-name input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* 地区选择器的控件比这里默认的输入框高一档，统一成 34px 才不会一高一矮 */
.alias-edit .region-picker { margin-bottom: 10px; }
.alias-edit .region-picker input,
.alias-edit .region-picker select { width: 100%; height: 34px; font-size: 14.5px; }
.alias-edit .ae-acts { display: flex; gap: 6px; }

/* 左栏站点条目右侧的地区短标签 */
.siteitem .s-region {
  margin-left: auto;
  flex: none;
  font-size: 13px;
  color: var(--muted-2);
  white-space: nowrap;
}
.detail-alias .da-region {
  font-size: 13.5px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--muted);
}
/* 创建人 / 分享人：公司项目要能直接看出是谁建的。
   不给底色 —— 「公司分配」已经是标签，再挂一个彩色徽标就成了两个互相打架的标签。
   也不配人形图标：12px 下那枚图标糊成一团，反而不如「创建人」三个字清楚。 */
.detail-alias .da-who { color: var(--ink-2); white-space: nowrap; }
.detail-alias .da-who .dw-k { color: var(--muted); margin-right: 4px; }

.statgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; margin: 22px 0; }
.stat { background: var(--surface); padding: 14px 16px; }
.stat span { display: block; font-size: 13.5px; color: var(--muted); margin-bottom: 5px; }
.stat b { font-family: var(--mono); font-size: 17px; font-weight: 500; }
.stat b.sm { font-size: 15px; }

.meter { height: 6px; background: var(--paper-2); border-radius: 999px; overflow: hidden; margin-top: 10px; }
.meter i { display: block; height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.4s ease; }
.meter i.warn { background: var(--warn); }
.meter i.bad { background: var(--danger); }

.code-box {
  margin-top: 8px;
  border: 1px dashed var(--line-strong);
  background: var(--surface-2);
  border-radius: 10px;
  padding: 14px;
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.75;
  word-break: break-all;
  color: var(--ink-2);
  max-height: 132px;
  overflow: auto;
}

.actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 18px; }

.notice {
  display: flex;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 9px;
  font-size: 14.5px;
  line-height: 1.65;
  margin-top: 18px;
  border: 1px solid transparent;
}
.notice.warn { background: var(--warn-soft); border-color: rgba(143, 90, 18, 0.18); color: #6d450f; }
.notice.bad { background: var(--danger-soft); border-color: rgba(156, 51, 39, 0.16); color: var(--danger); }
.notice.info { background: var(--accent-soft); border-color: rgba(12, 122, 80, 0.14); color: var(--accent-2); }
/* display:flex 会盖掉浏览器默认的 [hidden]。不加这一行，所有「先留个位置、
   有内容再显示」的提示条都会渲染成一条空的黄框 —— 绑定站点那个弹窗里
   一直挂着这么一条，只是没人说过它是什么。 */
.notice[hidden] { display: none; }

/* ── 站点停用 / 吊销提示 ─────────────────────────────────────────
   比 .notice 重一档。它要一次答完三个问题：为什么停、现在能不能用、
   怎么才能恢复。三句话挤进一条单行 notice 里，客户只会看第一句就打电话。 */
.site-alert {
  margin-top: 18px;
  padding: 14px 16px 15px;
  border: 1px solid rgba(156, 51, 39, 0.18);
  border-left: 3px solid var(--danger);
  border-radius: 9px;
  background: var(--danger-soft);
}
.sa-top { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.sa-badge {
  flex: none;
  padding: 1px 7px;
  border-radius: 5px;
  background: var(--danger);
  color: #fff;
  font-size: 12.5px;
  letter-spacing: 0.02em;
}
.sa-title { font-size: 15px; color: var(--danger); }
.sa-line { margin: 9px 0 0; font-size: 14px; line-height: 1.72; color: var(--ink-2); }
.sa-line b { color: var(--ink); font-weight: 600; margin-right: 7px; }
.sa-steps { margin: 6px 0 0 18px; font-size: 14px; line-height: 1.72; color: var(--ink-2); }
.sa-steps li { margin-bottom: 3px; }
.sa-foot { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 13px; }
.sa-foot .field-hint { color: #8a5a52; margin: 0; }
.sa-foot .btn[disabled] { opacity: 0.62; }

.empty-state { padding: 54px 24px; text-align: center; }
.empty-state h3 { font-family: var(--serif); font-size: 21px; font-weight: 600; margin-bottom: 8px; }
.empty-state p { color: var(--muted); font-size: 15px; margin-bottom: 20px; }

/* 套餐选择 */

.plan-pick { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
/* 加购只有「不需要 + 若干项」，两列刚好；三列会空一格，看着像少了个套餐 */
.addon-pick { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.addon-pick .pick { padding: 11px 12px; }
.addon-pick .pick .p-price { font-size: 17px; margin: 4px 0 1px; }
.pick {
  border: 1px solid var(--line-strong);
  background: var(--surface);
  border-radius: 10px;
  padding: 14px;
  cursor: pointer;
  text-align: left;
  font: inherit;
  transition: border-color 0.14s ease, background 0.14s ease, box-shadow 0.14s ease;
  position: relative;
}
.pick:hover { border-color: var(--accent); }
.pick[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: 0 0 0 1px var(--accent) inset;
}
.pick .p-name { font-size: 14.5px; color: var(--ink-2); font-weight: 500; }
.pick .p-price { font-family: var(--mono); font-size: 21px; margin: 6px 0 2px; }
.pick .p-term { font-size: 13px; color: var(--muted); font-family: var(--mono); }

/* 试用档：不是商品，所以用虚线 + 弱化的价格，让它一眼区别于三档正式授权。
   放在第一格是因为客户最想先试一下，而不是先掏 599。 */
.pick-trial { border-style: dashed; }
.pick-trial .p-price { color: var(--accent); font-size: 18px; letter-spacing: 0.02em; }
.pick-trial[aria-pressed="true"] { border-style: solid; }

/* 试用期用完的灰卡：留在原位，但点不动。
   不直接删掉——删了客户会以为我们从来没提供过试用；摆在那儿他就知道
   「有这回事，是这台主机的 90 天用完了」。 */
.pick.is-off {
  cursor: not-allowed;
  background: var(--paper-2);
  border-color: var(--line);
  opacity: 0.72;
}
.pick.is-off:hover { border-color: var(--line); }
.pick.is-off .p-name,
.pick.is-off .p-term { color: var(--muted); }
.pick.is-off .p-price {
  color: var(--muted);
  font-size: 17px;
  letter-spacing: 0;
}

/* ---------------------------------------------------------------- 弹层 */

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(14, 26, 43, 0.42);
  backdrop-filter: blur(3px);
  z-index: 90;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.overlay.open { display: flex; }

.modal {
  width: 100%;
  max-width: 520px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  box-shadow: 0 40px 90px -40px rgba(14, 26, 43, 0.6);
  animation: rise 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  max-height: 88vh;
  display: flex;
  flex-direction: column;
}
@keyframes rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

.modal-head {
  padding: 20px 22px 16px;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.modal-head h3 { font-size: 17px; font-weight: 600; }
.modal-head p { font-size: 14.5px; color: var(--muted); margin-top: 3px; }
.modal-body { padding: 20px 22px; overflow: auto; }
.modal-foot { padding: 16px 22px 20px; border-top: 1px solid var(--line); display: flex; gap: 10px; justify-content: flex-end; }
/* .btn 写死 display:inline-flex，会盖掉 [hidden] 的 display:none —— 试用档下
   购买弹窗的「加入购物车」必须真的消失，不然客户点它只得到一句「不用进购物车」。 */
#buyCart[hidden] { display: none; }

.icon-btn {
  width: 30px; height: 30px; border-radius: 7px; border: 1px solid transparent;
  background: transparent; cursor: pointer; color: var(--muted); font-size: 18px; line-height: 1;
  display: grid; place-items: center; flex: none;
}
.icon-btn:hover { background: var(--paper-2); color: var(--ink); }

.xfer { display: grid; gap: 12px; }
.xfer-row { display: flex; justify-content: space-between; font-size: 15px; }
/* display:flex 会盖掉 [hidden] 的默认 display:none —— 加购行没选时会留一个空的「—」 */
.xfer-row[hidden] { display: none; }
.xfer-row span { color: var(--muted); }
.xfer-row b { font-family: var(--mono); font-weight: 500; }
.xfer-total { border-top: 1px solid var(--line); padding-top: 12px; }
.xfer-total b { font-size: 20px; }

.pay-zone { text-align: center; padding: 6px 0 2px; }
.qr-frame {
  width: 208px; height: 208px; margin: 0 auto 14px; padding: 10px;
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  display: grid; place-items: center;
}
.qr-frame svg { width: 100%; height: 100%; display: block; }
.pay-hint { font-size: 14.5px; color: var(--muted); }
.pay-amount { font-family: var(--mono); font-size: 30px; margin: 4px 0 10px; }

.success-mark {
  width: 52px; height: 52px; border-radius: 50%; margin: 4px auto 14px;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center;
}
.success-mark svg { width: 26px; height: 26px; }

.spinner {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid rgba(14, 26, 43, 0.15);
  border-top-color: var(--ink);
  animation: spin 0.7s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Toast */

.toast-wrap {
  position: fixed;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%);
  z-index: 120;
  display: grid;
  gap: 8px;
  pointer-events: none;
}
.toast {
  background: var(--ink);
  color: #f2f3ef;
  font-size: 14.5px;
  padding: 10px 16px;
  border-radius: 8px;
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.5);
  animation: rise 0.18s ease;
  max-width: 80vw;
}
.toast.bad { background: var(--danger); }

/* 加购成功条：加完购必须一步能到结算，不能只留导航上一颗小角标。
   桌面贴右下角，窄屏改成贴底通栏、两颗按钮各占一半宽。 */
.cart-notice {
  position: fixed;
  right: 26px;
  bottom: 26px;
  z-index: 130;
  display: flex;
  align-items: center;
  gap: 13px;
  max-width: calc(100vw - 52px);
  padding: 13px 14px 13px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 0 22px 56px -18px rgba(14, 26, 43, 0.42);
  animation: rise 0.26s cubic-bezier(0.22, 1, 0.36, 1);
}
/* display:flex 会盖掉浏览器默认的 [hidden]，不加这行关不掉 */
.cart-notice[hidden] { display: none; }
.cn-ico {
  display: grid; place-items: center;
  width: 28px; height: 28px; flex: none;
  border-radius: 50%; background: var(--accent); color: #fff;
  font-size: 16px; font-weight: 700;
}
.cn-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cn-main strong { font-size: 15px; color: var(--ink); }
.cn-main span { font-size: 13.5px; color: var(--muted); white-space: nowrap; }
.cn-acts { display: flex; align-items: center; gap: 8px; margin-left: 6px; }
.cn-x { flex: none; }

@media (max-width: 720px) {
  .cart-notice {
    left: 0; right: 0; bottom: 0;
    max-width: none;
    border-radius: 12px 12px 0 0;
    padding: 12px 12px calc(12px + env(safe-area-inset-bottom));
    flex-wrap: wrap;
    gap: 8px 10px;
  }
  .cn-main { flex: 1; }
  .cn-acts { width: 100%; margin-left: 0; }
  .cn-acts .btn { flex: 1; }
  .cn-x { position: absolute; top: 6px; right: 8px; }
}

/* ---------------------------------------------------------------- 响应式 */

@media (max-width: 980px) {
  .hero { grid-template-columns: 1fr; gap: 46px; padding: 56px 0 60px; }
  .lic-wrap { max-width: 460px; margin: 0 auto; }
  .auth-shell { grid-template-columns: 1fr; gap: 40px; padding: 40px 0 60px; }
  .auth-aside { order: 2; }
  .auth-card { order: 1; max-width: 460px; }
  .console-grid { grid-template-columns: 1fr; }
  /* 手机上整页滚，不要让左栏在页面里再套一个小滚动条 */
  .sitelist { max-height: none; overflow: visible; }
  .plans, .steps, .plan-pick, .addon-pick { grid-template-columns: 1fr; }
  .faq { grid-template-columns: 1fr; }
  .statgrid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 600px) {
  .wrap { padding: 0 18px; }
  .topbar-in { height: 58px; }
  .brand-sub { display: none; }
  .brand-name { font-size: 15px; letter-spacing: 0.08em; }
  .hero h1 { font-size: 30px; }
  /* 40px 在 375 宽下刚好顶满一行，挤得没有呼吸；收到 32 后两行更从容 */
  .auth-aside h1 { font-size: 32px; line-height: 1.3; margin-bottom: 14px; }
  .auth-aside p { font-size: 15px; }
  /* 竖屏里三角形要收，否则两块绿会盖掉半屏 */
  .hero-band::before { width: 46%; height: 128px; }
  .hero-band::after { width: 40%; height: 176px; }
  .hero-motto { font-size: 13.5px; letter-spacing: 0.26em; padding-bottom: 22px; }
  .sec-head h2 { font-size: 23px; }
  .sec-title { font-size: 19px; margin: 32px 0 14px; }
  .panel-ink { padding: 28px 20px 30px; }
  .lic-code { font-size: 19px; }
  .console-head h1 { font-size: 24px; }
  .detail-code { font-size: 19px; }
  .statgrid { grid-template-columns: 1fr 1fr; }
  .modal-foot { flex-direction: column-reverse; }
  .modal-foot .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------- 弹层切换 */

.overlay .modal { display: none; }
/* 新增弹窗必须在这里补一行，否则 overlay 会亮、弹窗自己不显示（踩过一次） */
.overlay[data-active="bind"] .modal[data-modal="bind"],
.overlay[data-active="edit"] .modal[data-modal="edit"],
.overlay[data-active="share"] .modal[data-modal="share"],
.overlay[data-active="buy"] .modal[data-modal="buy"],
.overlay[data-active="pay"] .modal[data-modal="pay"],
.overlay[data-active="done"] .modal[data-modal="done"] { display: flex; }

/* 一对一的遮罩：里面只有一个弹窗，不需要 data-active 选面板。
   运营后台的三个弹窗走这条 —— 不带 single 的话遮罩会亮、弹窗不显示。 */
.overlay.single .modal { display: flex; }

/* 下拉框跟输入框同一套视觉 */
.field select {
  width: 100%;
  height: 42px;
  padding: 0 34px 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23767b7b' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")
    no-repeat right 13px center;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  appearance: none;
  cursor: pointer;
}
.field select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.12);
}

/* 省 / 市 / 区县：等宽三列，窄到放不下自己掉成两列、一列。
   不用固定 3 列：弹窗在手机上是 320px，三个 select 会挤成三条缝。 */
.region-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 10px;
  margin-bottom: 15px;
}
.region-picker .field { margin-bottom: 0; }
/* .field 没写 display，但 [hidden] 在 grid 子项上会被 UA 之外的布局盖掉 ——
   和 .xfer-row 一个毛病，显式钉一遍才保险 */
.region-picker .field[hidden] { display: none; }
.region-picker label { white-space: nowrap; }

/* 详情里的授权码预览限高，避免把页面撑太长 */
#detail .code-box { max-height: 96px; }

/* 窄屏隐藏次要导航，避免中文链接被挤成竖排 */
@media (max-width: 600px) {
  .nav-sm-hide { display: none; }
}

/* ---------------------------------------------------------------- 产品授权卡 */

.prod-list { display: grid; gap: 12px; margin-top: 20px; }
.prod-card {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px 18px;
  background: var(--surface);
}
.pc-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
.pc-title { font-size: 16px; font-weight: 600; letter-spacing: 0.01em; }
.pc-meta { font-size: 13.5px; color: var(--muted); margin-top: 4px; }
.pc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 15px 0 9px; }
.pc-grid span { display: block; font-size: 13.5px; color: var(--muted); margin-bottom: 3px; }
.pc-grid b { font-family: var(--mono); font-size: 15px; font-weight: 500; }
.pc-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 13px; }

.code-details { margin-top: 11px; }
.code-details summary {
  cursor: pointer;
  font-size: 14px;
  color: var(--muted);
  list-style: none;
}
.code-details summary::-webkit-details-marker { display: none; }
.code-details summary::before { content: "＋ "; color: var(--muted-2); }
.code-details[open] summary::before { content: "－ "; }
.code-details .code-box { margin-top: 9px; max-height: 118px; }

/* ---------------------------------------------------------------- 驱动目录 */

.catalog { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px 28px; }
.cat { border-top: 1px solid var(--line-strong); padding-top: 14px; }
.cat-head { display: flex; align-items: baseline; gap: 10px; }
.cat-name { font-family: var(--serif); font-size: 18px; font-weight: 600; }
.cat-entity {
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--muted-2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.cat-desc { font-size: 14px; color: var(--muted); margin: 5px 0 11px; line-height: 1.6; }

.brand-row { display: flex; gap: 12px; padding: 7px 0; border-bottom: 1px dashed var(--line); }
.brand-row:last-child { border-bottom: 0; }
.brand-name { flex: none; width: 112px; font-size: 14.5px; color: var(--ink-2); padding-top: 2px; }
.brand-prods { display: flex; flex-wrap: wrap; gap: 5px; }

.pchip {
  font-size: 13.5px;
  padding: 2px 7px;
  border-radius: 5px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  white-space: nowrap;
}
.pchip em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--muted-2);
  margin-left: 5px;
}
.pchip.on_sale { border-color: rgba(12, 122, 80, 0.3); background: var(--accent-soft); color: var(--accent-2); }
.pchip.planned { color: var(--muted); border-style: dashed; }
.pchip.official { opacity: 0.65; }

.catalog-legend {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: 20px;
  font-size: 14px;
  color: var(--muted);
}
.catalog-legend i {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: 1px;
}

/* 软件服务那一条 */
.plan-strip {
  margin-top: 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  padding: 14px 18px;
  display: flex;
  gap: 16px;
  align-items: baseline;
  flex-wrap: wrap;
}
.strip-name { font-size: 14.5px; font-weight: 600; color: var(--ink-2); }
.strip-plans { font-size: 14.5px; color: var(--muted); }
.strip-plans b { font-family: var(--mono); color: var(--ink); font-weight: 500; }
.strip-plans b + span { color: var(--muted); }

@media (max-width: 980px) {
  .catalog { grid-template-columns: 1fr; }
  .brand-name { width: 96px; }
}

/* 产品卡里的进度条更像量尺，不像分割线 */
.prod-card .meter { height: 4px; background: rgba(14, 26, 43, 0.07); margin-top: 4px; }
.prod-card .meter i { opacity: 0.78; }

/* ---------------------------------------------------------------- 目录页 */

/* 子页页头：左边标题组、右边一列数字，底部一条实线收口。
   空白背景上直接落一段文字，看起来像文档的一节；有了数字栏和收口线，
   才像一页的刊头。 */
.page-head {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 260px;
  gap: 56px;
  align-items: end;
  padding: 48px 0 30px;
  border-bottom: 2px solid var(--ink);
  margin-bottom: 34px;
}
/* 斜纹只铺在右上角，用一个角向遮罩淡出。浓度压到 3%，
   扫一眼是纸的纹理，盯住看会以为是自己眼花 —— 不抢标题的注意力 */
.page-head::before {
  content: "";
  position: absolute;
  inset: 0 0 2px 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(45deg, rgba(14, 26, 43, 0.05) 0 1px, transparent 1px 7px);
  -webkit-mask-image: linear-gradient(215deg, #000 0%, transparent 52%);
  mask-image: linear-gradient(215deg, #000 0%, transparent 52%);
}
.page-head.no-stats { display: block; }
.page-head h1 {
  position: relative;
  font-family: var(--serif);
  font-size: clamp(30px, 3.6vw, 42px);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.page-lead {
  position: relative;
  margin-top: 16px;
  max-width: 640px;
  color: var(--ink-2);
  font-size: 15.5px;
  line-height: 1.8;
}
/* 数字栏：值在左、说明在右，中间用一条引导虚线连起来。
   排成目录的样式，比四组数字各自为政好读，也不怕条数变化 */
.cat-stat-row {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.cat-stat {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px dashed var(--line);
}
.cat-stat:last-child { border-bottom: 0; }
.cat-stat b {
  font-family: var(--serif);
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.cat-stat .lead {
  flex: 1;
  border-bottom: 1px dotted var(--line-strong);
  transform: translateY(-4px);
}
.cat-stat span { font-size: 13.5px; color: var(--muted); letter-spacing: 0.02em; white-space: nowrap; }
/* 主指标给一点颜色，其余退成墨色，避免五行权重一样 */
.cat-stat:first-child b { color: var(--accent-2); }

.filterbar {
  position: sticky;
  top: 64px;
  z-index: 20;
  display: flex;
  gap: 9px 18px;
  flex-wrap: wrap;
  align-items: center;
  padding: 12px 0;
  background: rgba(244, 242, 236, 0.93);
  backdrop-filter: saturate(180%) blur(8px);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.fgroup { display: flex; gap: 6px; flex-wrap: wrap; }
.fgroup + .fgroup { padding-left: 18px; border-left: 1px solid var(--line); }
.fchip {
  font: inherit;
  font-size: 14.5px;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.fchip:hover { border-color: var(--line-strong); }
.fchip.on { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* 搜索框。目录到 400 条时，筛 chip 不够用 —— 客户带着问题来，
   要能直接搜「读电流」这种正文里的词。 */
.fsearch {
  position: relative;
  display: flex;
  align-items: center;
  flex: 0 1 330px;
  min-width: 200px;
}
.fs-input {
  font: inherit;
  font-size: 14.5px;
  width: 100%;
  padding: 7px 30px 7px 30px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 21 21'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 11px center;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
  -webkit-appearance: none;
  appearance: none;
}
.fs-input::-webkit-search-cancel-button { display: none; }
.fs-input::placeholder { color: var(--muted); font-size: 14.5px; }
.fs-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.08);
}
.fs-clear {
  position: absolute;
  right: 8px;
  font: inherit;
  font-size: 16px;
  line-height: 1;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
/* 同上：display:grid 会盖掉 [hidden]，清除按钮必须显式让位 */
.fs-clear[hidden] { display: none; }
.fs-clear:hover { background: var(--line); color: var(--ink); }

/* 平台标识。只有一个平台时整列不出现 —— 33 条全是 Crestron Home，
   每条挂个 CH 徽章纯属噪音；接入第二个平台那天，这一列会自己长出来。 */
.pr-plat {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.04em;
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid var(--line-strong);
  color: var(--muted);
  white-space: nowrap;
}
.pr-plat.multi { border-color: var(--accent); color: var(--accent); }

.cat-list { padding-bottom: 8px; counter-reset: catblk; }
/* 每个大类左边挂一个 01/02 序号：十一个大类一路排下来，
   没有编号时读者不知道自己走到第几块了 */
.cat-block {
  position: relative;
  padding: 32px 0 6px 44px;
  border-bottom: 1px solid var(--line);
  counter-increment: catblk;
}
.cat-block::before {
  content: counter(catblk, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 37px;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--muted-2);
}
.cat-block:last-child { border-bottom: 0; }
.cat-block-head {
  display: flex;
  align-items: baseline;
  gap: 8px 18px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.cbh-left { display: flex; align-items: baseline; gap: 10px; }
.cbh-left h2 { font-family: var(--serif); font-size: 21px; font-weight: 600; letter-spacing: -0.01em; }
.cat-block-desc { font-size: 14.5px; color: var(--muted); flex: 1; min-width: 220px; }

.prod-table { border-top: 1px solid var(--line); }
/* 筛选靠 hidden 属性，但 .prod-row 写死了 display:grid，会盖掉浏览器默认的 [hidden] */
.prod-row[hidden], .cat-block[hidden] { display: none !important; }
.prod-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 0.95fr) minmax(0, 1.05fr) 92px 78px;
  gap: 16px;
  align-items: center;
  padding: 10px 4px;
  border-bottom: 1px dashed var(--line);
  transition: background 0.12s;
}
.prod-row:last-child { border-bottom: 0; }
.prod-row:hover { background: var(--surface); }
/* 行首那道绿条：鼠标扫过十几行时，光靠底色变化找不到自己在哪一行 */
.prod-row:hover::before {
  content: "";
  position: absolute;
  left: -10px;
  top: 5px;
  bottom: 5px;
  width: 2px;
  background: var(--accent);
}
.pr-main { display: flex; align-items: baseline; gap: 9px; min-width: 0; }
.pr-name {
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  border-bottom: 1px solid transparent;
  transition: color 0.12s, border-color 0.12s;
}
.pr-name:hover { color: var(--accent); border-bottom-color: var(--accent); }
.pr-model {
  font-size: 13.5px;
  color: var(--muted-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pr-brand { font-size: 14.5px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pr-path { font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pr-get { text-align: right; }
.pr-act { text-align: right; }
.pr-dash { color: var(--muted-2); font-size: 14px; }

.get-tag {
  display: inline-block;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.02em;
  padding: 3px 7px;
  border-radius: 4px;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  white-space: nowrap;
}
.get-tag.soon { border-style: dashed; color: var(--muted-2); background: transparent; }
/* 免费是「好消息」，但墨绿留给付费，这里只把它从灰堆里提一档 */
.get-tag.free { color: var(--ink-2); background: var(--paper-2); }
.get-price {
  font-size: 14.5px;
  color: var(--accent);
  white-space: nowrap;
}
.get-price i { font-style: normal; font-size: 13px; color: var(--muted-2); margin-left: 2px; }

.pr-more {
  font-size: 13.5px;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.12s;
}
.pr-more:hover { color: var(--accent); }

.cat-legend {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 15px 17px;
  margin: 16px 0 2px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-2);
  font-size: 14px;
  color: var(--muted);
  line-height: 1.65;
}
.cat-legend span { display: flex; align-items: flex-start; gap: 9px; }
.cat-legend b { color: var(--ink-2); font-weight: 500; white-space: nowrap; }
.lg { flex: 0 0 9px; width: 9px; height: 9px; border-radius: 2px; margin-top: 6px; }
.lg.free { background: var(--line-strong); }
.lg.paid { background: var(--accent); }
.lg.soon { border: 1px dashed var(--line-strong); }

.cat-empty { padding: 64px 0; text-align: center; color: var(--muted); font-size: 15px; }
/* 分类还在、条目空了。空表头留着像没加载完，所以整块换成一句说明，
   但分类本身不能删 —— 客户按门类找过来，得看见「暂缺」而不是「不支持」 */
.cat-blank {
  margin: 0;
  padding: 22px 24px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.7;
  background: var(--panel-2, transparent);
}
.linklike {
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  padding: 0 4px;
}

.cat-cta {
  margin: 40px 0 64px;
  padding: 26px 28px;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
.cat-cta h3 { font-family: var(--serif); font-size: 19px; font-weight: 600; margin-bottom: 6px; }
.cat-cta p { font-size: 14.5px; color: var(--muted); max-width: 560px; line-height: 1.7; }
/* 「配合测试换授权」承诺条。跟正文同字号但单独成块：
   这不是又一段产品说明，是一个条件交换，混在段落里会被读成客套话。 */
.cat-cta .cta-offer {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-top: 13px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  color: var(--ink-2);
}
.cat-cta .cta-offer b { color: var(--accent-2); font-weight: 600; }
/* 中文「赠」笔画密，字块比正文小一档就糊；18px 方块配 11px 是这块的下限 */
.cta-offer-tag {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border-radius: 4px;
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  line-height: 21px;
  text-align: center;
  font-weight: 600;
}
/* 表单外的备用通道：一行，别做成第二个按钮抢主按钮的视线 */
.cat-mail { margin-top: 8px; font-size: 14px !important; }
.cat-mail a { color: var(--accent-2); text-decoration: none; border-bottom: 1px solid var(--accent-line); }

/* 厂商合作卡（品牌页）。跟 .cat-cta 的区别不只是配色：
   这里要讲清「免费」和「登记前准备什么」，是一条带清单的合作说明，
   不是一句提示。底色用翠的浅调，跟旁边的驱动卡片分开层次。 */
.vendor-cta {
  margin: 40px 0 64px;
  padding: 26px 28px 22px;
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  /* 用网格而不是「左文右按钮」的 flex：手机端按钮要能落到清单之后，
     flex 做不到跨过兄弟元素换位置，grid-template-areas 一行就能改。 */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "lead btn"
    "needs needs"
    "note note";
  align-items: start;
  gap: 18px 28px;
}
.vc-lead { grid-area: lead; min-width: 0; }
.vc-btn { grid-area: btn; }
.vc-lead h3 {
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.45;
  /* 手机上这行会折成两行；不均衡时第二行只剩一个「动」字。
     balance 让两行长度接近，正好在问号后断开。 */
  text-wrap: balance;
  margin-bottom: 8px;
}
/* 「免费」是这个卡唯一的卖点，用翠压一下，别让它混在句子里被读过去 */
.vc-lead h3 em { font-style: normal; color: var(--accent-2); }
.vc-lead p { font-size: 14.5px; color: var(--ink-2); max-width: 760px; line-height: 1.75; }

/* 四项登记材料。写死四列 —— 正好是客户发邮件时最容易漏的四个字段，
   顺序也按邮件从上到下排，照着念就能填。 */
.vc-needs {
  grid-area: needs;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px 20px;
  margin: 0;
  padding: 16px 0 0;
  border-top: 1px dashed rgba(12, 122, 80, 0.25);
}
.vc-needs li { display: flex; gap: 9px; align-items: flex-start; min-width: 0; }
.vc-needs b {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 21px;
  color: var(--accent-2);
  background: var(--surface);
  border: 1px solid var(--accent-line);
  border-radius: 5px;
  padding: 0 5px;
}
.vc-needs strong { display: block; font-size: 14.5px; font-weight: 600; color: var(--ink); margin-bottom: 3px; }
/* 四列每列才 250px，说明文字必然折成两行。不加 balance 会出现
   「…官网产品页更」+「好。」这种第二行只剩两个字的断法。 */
.vc-needs span { display: block; font-size: 14px; color: var(--muted); line-height: 1.65; text-wrap: balance; }
.vc-note { grid-area: note; margin: 0; font-size: 14px; color: var(--muted); line-height: 1.7; }
/* 详情页底部那张卡会把「发邮件」和「微信」写在同一行里，链接不带上色就会跳出个默认蓝 */
.vc-note a { color: var(--accent-2); text-decoration: none; border-bottom: 1px solid var(--accent-line); }
.vc-note a:hover { border-bottom-color: var(--accent-2); }

@media (max-width: 900px) {
  .vc-needs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* 窄屏整卡竖排，按钮压到最后 —— 先看要准备什么，再决定点。
   顺序要是倒过来，读完标题就点，邮件里还是只有一个品牌名。 */
@media (max-width: 700px) {
  .vendor-cta {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "lead" "needs" "note" "btn";
    gap: 14px;
  }
  .vc-btn { width: 100%; }
}
@media (max-width: 560px) {
  .vendor-cta { padding: 20px 18px 18px; }
  .vc-lead h3 { font-size: 18px; }
  .vc-needs { grid-template-columns: minmax(0, 1fr); gap: 12px; }
}

@media (max-width: 900px) {
  .prod-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "main state" "meta act";
    gap: 2px 12px;
    padding: 11px 2px;
  }
  .pr-main { grid-area: main; }
  .pr-brand { grid-area: meta; font-size: 13.5px; color: var(--muted); }
  .pr-path { display: none; }
  .pr-get { grid-area: state; }
  .pr-act { grid-area: act; }
  .cat-legend { font-size: 13.5px; gap: 8px; }
  .filterbar { top: 64px; gap: 8px; }
  .fgroup + .fgroup { padding-left: 0; border-left: 0; }
  .fsearch { flex: 1 1 100%; }

  /* 五个数字卡在 390 宽下会断成 3+2，第二行只剩两个还错位。
     改三列网格，5 个卡排成 3+2，右边空一格也不难看。 */
  .cat-stat-row {
    display: grid;
    /* 写死列数会在条目数变化时断成 3+1、3+2 —— 品牌页 4 个、目录页 5 个，
       同一个类要同时容得下，交给 auto-fit 自己算。 */
    grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
    gap: 14px 8px;
    margin: 22px 0 18px;
  }
  .cat-stat b { font-size: 21px; }
  .cat-stat span { font-size: 13.5px; }

  /* 九个大类 chip 竖着排会占三行，吸顶时几乎吃掉半屏。
     改成一行横滑：手指一划就到底，比折行省两行高度。 */
  .fgroup-cat {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
    /* 右侧留一点渐隐，暗示还能往右滑 */
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }
  .fgroup-cat::-webkit-scrollbar { display: none; }
  .fgroup-cat .fchip { flex: 0 0 auto; }
}

/* ---------------------------------------------------------------- 落地页货架 */

/* 免费入口条：官方自带的那些不卖，但要说清楚 —— 藏着反而显得心虚 */
.free-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  padding: 20px 22px;
  margin-bottom: 30px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--ink);
  transition: border-color 0.15s, background 0.15s;
}
.free-strip:hover { border-color: var(--line-strong); background: var(--surface); color: var(--ink); }
.fs-main { min-width: 0; flex: 1 1 460px; }
.fs-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
.fs-head b { font-family: var(--serif); font-size: 17px; font-weight: 600; }
.fs-main p { font-size: 14.5px; color: var(--muted); line-height: 1.75; max-width: 720px; }
.fs-main p b { color: var(--ink-2); font-weight: 600; }
.fs-go {
  font-size: 14.5px;
  color: var(--accent);
  font-weight: 500;
  white-space: nowrap;
  flex: 0 0 auto;
}

.shelf { margin-bottom: 32px; }
.shelf-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.dot { width: 6px; height: 6px; border-radius: 1px; display: inline-block; }
.dot-live { background: var(--accent); }
.dot-soon { background: var(--line-strong); }

.shelf-live { display: grid; gap: 12px; }
.live-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  transition: border-color 0.15s, transform 0.15s;
}
.live-card:hover { border-color: var(--accent); color: var(--ink); transform: translateY(-1px); }
.lc-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.lc-head { display: flex; align-items: center; gap: 12px; }
.lc-cat { font-size: 13.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted-2); }
.lc-name { font-family: var(--serif); font-size: 22px; font-weight: 600; margin-top: 8px; line-height: 1.3; }
.lc-model { font-size: 14px; color: var(--muted); }
.lc-spec { font-size: 14.5px; color: var(--muted); margin-top: 2px; }
.lc-go { flex: none; font-size: 14.5px; font-weight: 500; color: var(--accent); white-space: nowrap; }

.shelf-soon { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.soon-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 16px;
  border: 1px dashed var(--line-strong);
  border-radius: 10px;
  color: var(--ink);
  transition: border-color 0.15s, background 0.15s;
}
.soon-card:hover { border-color: var(--accent); background: var(--surface); color: var(--ink); }
.soon-card b { font-size: 15px; font-weight: 500; color: var(--ink-2); line-height: 1.4; }
.sc-cat { font-size: 13.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted-2); }
.sc-model { font-size: 13.5px; color: var(--muted-2); margin-top: 2px; }

.shelf-foot { display: flex; align-items: center; gap: 8px 18px; flex-wrap: wrap; margin-top: 26px; }
.shelf-note { font-size: 14.5px; color: var(--muted); }

@media (max-width: 760px) {
  .shelf-soon { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .shelf-soon { grid-template-columns: 1fr; }
  .live-card { padding: 18px 18px; flex-direction: column; align-items: flex-start; gap: 12px; }
}

/* ------------------------------------------------------------ 首页品牌墙

   69 个品牌不用卡片铺 —— 卡片墙要滚三屏，而且每个牌子只有一条驱动时，
   卡片里那张「1 条 · 1 个品类」是废话。这里只当能力清单看：
   文字流，扫一眼就知道「我家的牌子在不在里面」。 */

.bwall {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 0;
  padding: 4px 0 2px;
  font-size: 15px;
  line-height: 2;
}
.bwall a {
  color: var(--ink-2);
  padding: 2px 7px;
  border-radius: 5px;
  transition: background 0.12s, color 0.12s;
}
/* 分隔点挂在前一个名字的尾巴上（::after），不是后一个的开头。
   挂开头的话，一旦换行，行首就会孤零零留一个「·」。 */
.bwall a::after {
  content: "·";
  color: var(--line-strong);
  margin-left: 8px;
  pointer-events: none;
}
.bwall a:last-child::after { content: ""; }
.bwall a:hover { background: var(--accent-soft); color: var(--accent-2); }
/* 自有品牌：名字后面挂一个小字，别让客户把它当成「又一家合作品牌」 */
.bw-self i {
  font-style: normal;
  margin-left: 4px;
  padding: 0 4px;
  font-size: 13px;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 3px;
  vertical-align: 1px;
}

.bwall-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  font-size: 14.5px;
}
.bwall-go { font-weight: 600; }

@media (max-width: 520px) {
  .bwall { font-size: 14.5px; line-height: 1.95; }
  .bwall a { padding: 2px 5px; }
}

/* ------------------------------------------------------------ 驱动详情页 */

.dv-wrap { padding-bottom: 72px; }

.crumb {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 22px 0 0;
  font-size: 14px;
  color: var(--muted);
}
.crumb a { color: var(--muted); }
.crumb a:hover { color: var(--accent); }
.crumb i { font-style: normal; color: var(--muted-2); }
.crumb span { color: var(--ink-2); }

/* 页头现在只有一个子元素（标题块），主图、型号、价格全都搬进了右侧那一列。
   不再需要 flex 布局与 gap —— 留着那些规则只会让人以为页头还有第二个格子。 */
.dv-head {
  padding: 18px 0 16px;
  border-bottom: 1px solid var(--line);
}
.dv-head-main { min-width: 0; }
/* 产品主图：1200² 零售盒图，底色 #f2f2f2 与 --paper 只差 1 阶，直接贴着页面放，
   不加边框也不给白底 —— 加了框会变成「一张被框住的图」，像电商截图。
   留白由图片自己提供，容器只负责圆角兜住阴影。 */
.dv-cover {
  flex: 0 0 auto;
  width: 210px;
  height: 210px;
  margin: 0;
  border-radius: 12px;
  overflow: hidden;
}
/* 侧栏顶端的「铭牌」：图 + 一行品牌型号，居中成一列。
   gap 只给 6px —— 图注离图远了就会被读成另一段内容，而不是这张图的说明。
   300px 的列宽里图占 210，两边各留 45px 呼吸：再大把价格与按钮顶出首屏，
   再小盒子侧面的品名就糊了。 */
.dv-namplate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.dv-id {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--muted);
  text-align: center;
  /* 型号那段可能很长（"ALLCENTER_UM-PSC08（网转串版 ALLCENTER_UM-PSC08_IP）"），
     不留断行机会的话手机上会把整页撑出横向滚动条，右边那一截永远看不到 */
  overflow-wrap: anywhere;
}
.dv-id .mono { color: var(--ink-2); }
/* 源图是 1200² 的整张展台照，盒子本身只占中间七成，四周全是底色留白。
   原样缩到 176px 后盒子只有 120px 高，看着像缩略图。放大 1.1 倍把留白裁掉一圈，
   盒子回到约 150px；再多就切到落地阴影（阴影距边缘刚好 8%）。 */
.dv-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform: scale(1.1);
}
.dv-tags { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.dv-path { font-size: 13.5px; letter-spacing: 0.06em; color: var(--muted); text-transform: uppercase; }
.dv-head h1 {
  font-family: var(--serif);
  font-size: clamp(26px, 3.4vw, 40px);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}
/* 窄屏专用的价格/购买入口。桌面端右栏购买卡就在同一屏，页头再挂一次价就是
   客户说的「两区重复」，所以默认不渲染；1000px 以下右栏被推到正文之后才显形。 */
.dv-head-buy { display: none; }

.mode-tag {
  display: inline-block;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.05em;
  padding: 4px 8px;
  border-radius: 4px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.mode-tag.free { background: var(--surface-2); border-color: var(--line-strong); color: var(--muted); }
.mode-tag.paid { background: var(--accent); border-color: var(--accent); color: #fff; }
.mode-tag.soon { background: transparent; border: 1px dashed var(--line-strong); color: var(--muted); }
/* 0 元条目：既不是「官方内置」，也不是「付费授权」，给一枚实心但不抢品牌绿的章 */
.mode-tag.zero { background: var(--paper-2); border-color: var(--line-strong); color: var(--ink-2); }

/* 试用入口：页头撤掉那颗按钮后，它挪进购买卡、压在「加入购物车 / 立即购买」下面。
   主操作永远只有两颗，试用是补充而不是并列的第三个选项。 */
.dv-try {
  font-size: 14px;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--line-strong);
}
.dv-try:hover { color: var(--accent); text-decoration-color: var(--accent); }
/* 卡里的那一行：通栏居中，与上面的按钮组留一口气，别贴着 */
.sc-try { display: block; margin-top: 11px; text-align: center; }
/* 「先试用 90 天」这种短语被断成「先试用 90 / 天」比不写还难看 */
.nb { white-space: nowrap; }

/* ---- 定调提示条 ---- */

.dv-banner {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin: 20px 0 0;
  padding: 16px 18px;
  border-radius: var(--radius);
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink-2);
}
.dv-banner b { color: var(--ink); }
.dv-banner .mono {
  font-size: 14px;
  padding: 1px 5px;
  border-radius: 3px;
  background: rgba(14, 26, 43, 0.06);
}
.dvb-mark {
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 14px;
  margin-top: 2px;
}
.dv-banner.free { background: var(--surface-2); border: 1px solid var(--line); }
.dv-banner.free .dvb-mark { background: var(--line-strong); color: var(--paper); }
.dv-banner.paid { background: var(--accent-soft); border: 1px solid rgba(12, 122, 80, 0.18); }
.dv-banner.paid .dvb-mark { background: var(--accent); color: #fff; }
.dv-banner.zero { background: var(--accent-soft); border: 1px solid var(--accent-line); }
.dv-banner.zero .dvb-mark { background: var(--accent); color: #fff; font-size: 15px; }
.dv-banner.soon { background: transparent; border: 1px dashed var(--line-strong); }
.dv-banner.soon .dvb-mark { background: var(--line-strong); color: var(--paper); }
/* 已下架必须跟「还在做」一眼分开：虚线是"还没来"，这里是"过去了"。
   实线灰底、去饱和 —— 不抢眼，但也不像故障，更不会让人以为登记一下就能等到。 */
.dv-banner.off { background: var(--surface-2); border: 1px solid var(--line-strong); }
.dv-banner.off .dvb-mark { background: var(--ink-2); color: var(--paper); }
.dv-banner.off a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* ---- 双栏 ---- */

.dv-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 56px;
  align-items: start;
  margin-top: 34px;
}
.dv-main { min-width: 0; }

.dv-sec { margin-bottom: 44px; }

/* 收尾操作行。这个类一直在模板里用，却没有对应的样式 ——
   两个按钮是贴在一起的 inline-block，看着像漏了间距。 */
.dv-actions-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 34px 0 4px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.dv-sec h2 {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 12px;
}
.sec-no {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 400;
  color: var(--muted-2);
  letter-spacing: 0.08em;
}
.sec-lead { font-size: 14.5px; color: var(--muted); margin-bottom: 16px; max-width: 620px; line-height: 1.7; }

/* 步骤 */
.dv-steps { list-style: none; margin: 0; padding: 0; counter-reset: dvstep; }
.dv-steps li {
  position: relative;
  counter-increment: dvstep;
  padding: 0 0 16px 38px;
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink-2);
}
.dv-steps li::before {
  content: counter(dvstep, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 1px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 2px 5px;
  border-radius: 4px;
}
.dv-steps li:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 11px;
  top: 22px;
  bottom: 2px;
  width: 1px;
  background: var(--line);
}

/* 操作套路卡（guide.recipe）—— 目前是继电器模块的「场景藏起来但可被调用」。
   这类步骤顺序敏感：先关房间就再也建不了场景，先改回 Hidden 就把设备撤没了。
   所以不跟正文混排：底色 + 左竖线把它拎出来，提醒这是照着做的一整段。 */
.dv-recipe {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 20px 22px 8px;
}
.dv-recipe .dv-steps li { padding-bottom: 18px; }
.dv-recipe .rc-t {
  display: block;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 3px;
}
.dv-recipe .rc-b {
  display: block;
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--ink-2);
}
/* 注意事项：虚线切开，短横点 —— 不用红黄底色，这里没有危险操作，
   只是「顺序错了要返工」 */
.rc-warns {
  list-style: none;
  margin: 2px 0 0;
  padding: 14px 0 6px;
  border-top: 1px dashed var(--line-strong);
}
.rc-warns li {
  position: relative;
  padding: 0 0 8px 18px;
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--muted);
}
.rc-warns li:last-child { padding-bottom: 2px; }
.rc-warns li::before {
  content: "!";
  position: absolute;
  left: 2px;
  top: 0;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--warn);
}
@media (max-width: 560px) {
  .dv-recipe { padding: 16px 16px 6px; }
}

/* 前置条件 */
.dv-needs { list-style: none; margin: 0; padding: 0; }
.dv-needs li {
  position: relative;
  padding: 9px 0 9px 24px;
  font-size: 15px;
  color: var(--ink-2);
  border-bottom: 1px dashed var(--line);
}
.dv-needs li:last-child { border-bottom: 0; }
.dv-needs li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 17px;
  width: 6px;
  height: 6px;
  border-radius: 1px;
  border: 1px solid var(--line-strong);
}

/* 能与不能 */
/* 兼容性：左边一列标签，右边值（可带一行灰字补充）。
   手机上折成一列 —— 96px 的标签列在 390 下会把型号挤成竖排。 */
.dv-compat { margin: 0; border-top: 1px solid var(--line); }
.dv-compat > div {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
}
.dv-compat dt {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--muted);
  letter-spacing: 0.04em;
  padding-top: 2px;
}
.dv-compat dd { margin: 0; font-size: 14.5px; color: var(--ink-2); line-height: 1.6; }
.dv-compat dd .mono { color: var(--ink); }
.dc-note { display: block; font-size: 13.5px; color: var(--muted); margin-top: 3px; }
@media (max-width: 560px) {
  .dv-compat > div { grid-template-columns: 1fr; gap: 4px; }
}

/* 已知边界：装之前要确认的环境条件 */
.dv-env { list-style: none; margin: 0; padding: 0; }
.dv-env li {
  position: relative;
  padding-left: 12px;
  font-size: 14.5px;
  color: var(--ink-2);
  line-height: 1.7;
}
.dv-env li + li { margin-top: 2px; }
.dv-env li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 9px;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--muted-2);
}

.dv-two { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.cap-box {
  padding: 18px 20px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
}
.cap-box h3 {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 12px;
}
.cap-box.yes h3 { color: var(--accent); }
.cap-box.no h3 { color: var(--danger); }
.cap-box.no { background: var(--surface-2); border-style: dashed; }
.cap-box ul { list-style: none; margin: 0; padding: 0; }
.cap-box li {
  position: relative;
  padding: 0 0 9px 18px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ink-2);
}
.cap-box li:last-child { padding-bottom: 0; }
.cap-box li::before {
  position: absolute;
  left: 0;
  top: 0;
  font-size: 13px;
}
.cap-box.yes li::before { content: "+"; color: var(--accent); }
.cap-box.no li::before { content: "−"; color: var(--danger); }

/* 故障 */
.dv-fix { border-top: 1px solid var(--line); }
.fix-row {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 22px;
  padding: 13px 2px;
  border-bottom: 1px solid var(--line);
}
.fix-q { font-size: 15px; font-weight: 500; color: var(--ink); }
.fix-a { font-size: 14.5px; color: var(--muted); line-height: 1.7; }

/* 授权流程 */
.dv-flow { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.flow-step {
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.flow-step > span {
  display: inline-block;
  font-size: 13.5px;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 2px 6px;
  border-radius: 4px;
  margin-bottom: 10px;
}
.flow-step b { display: block; font-size: 15px; margin-bottom: 6px; }
.flow-step p { font-size: 14px; color: var(--muted); line-height: 1.7; }

/* 同类 */
.sib-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 10px; }
.sib-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
  transition: border-color 0.15s;
}
.sib-card:hover { border-color: var(--accent); color: var(--ink); }
.sib-card b { font-size: 14.5px; font-weight: 500; line-height: 1.45; }
.sib-meta { font-size: 13.5px; color: var(--muted-2); }
.sib-card .mode-tag { align-self: flex-start; font-size: 13px; padding: 3px 6px; }

/* ---- 侧栏 ---- */

.dv-side { position: sticky; top: 88px; display: flex; flex-direction: column; gap: 14px; }
.side-card {
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.side-card h3 {
  font-family: var(--serif);
  font-size: 16.5px;
  font-weight: 600;
  margin-bottom: 10px;
}
.side-card.buy { background: var(--surface); border-color: var(--line-strong); }
.sc-price { display: flex; align-items: baseline; gap: 5px; margin-bottom: 14px; }
.sc-price b {
  font-family: var(--mono);
  font-size: 27px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
}
/* 只命中直接子元素那颗说明文字：价格数字外层是 <b>¥<span id="scPrice">，
   写成后代选择器会把数字也缩成 11.5px 灰色。 */
.sc-price > span { font-size: 13.5px; color: var(--muted); }
/* 三档是可点选的：选中的那档同时决定顶上的价、下面两个按钮的档位。
   原来是每一档后面挂个「＋」，客户以为那是「再加一份」，实际是「按这一档加购」。 */
.sc-picks { display: flex; flex-direction: column; gap: 6px; margin: 0 0 13px; }
.sc-pick {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; width: 100%; padding: 9px 11px; text-align: left;
  border: 1px solid var(--line); border-radius: 8px;
  background: transparent; color: inherit; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.sc-pick:hover { border-color: var(--line-strong); }
.sc-pick.on {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.sc-pick.on .sp-price { color: var(--accent-2); }
.sp-l { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sp-name { font-size: 14.5px; color: var(--ink); }
.sp-dog { font-size: 13.5px; color: var(--muted); }
.sp-price { font-size: 14.5px; color: var(--ink-2); font-weight: 500; flex: none; }

/* 两个动作并排：加入购物车（次要）+ 立即购买（主要）。
   加购和直购必须一样显眼 —— 只给一个，客户会以为另一条路不存在。 */
.sc-acts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 0 0 4px; }
/* 0 元条目只有「下载」一个动作，别留半格空位把按钮挤成窄条 */
.sc-acts-one { grid-template-columns: 1fr; }
.sc-acts .btn { width: 100%; padding-left: 8px; padding-right: 8px; justify-content: center; }
#scCart.done { border-color: var(--accent); color: var(--accent-2); }
.sc-hint { margin-top: 12px; font-size: 13.5px; color: var(--muted); line-height: 1.7; }
.sc-lead { font-size: 14.5px; color: var(--muted); line-height: 1.75; }
.side-card.gap { border-color: var(--line-strong); }

/* 加购项：价格卡里单独一段，跟套餐列表用虚线分开 ——
   混在套餐里会被读成「还有第四档」，而它是一次性人工，不随年限叠加。 */
.sc-addons {
  margin-top: 16px;
  padding-top: 13px;
  border-top: 1px dashed var(--line-strong);
}
.sc-addons h4 {
  margin: 0 0 9px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.sc-addon {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  margin-bottom: 8px;
  border: 1px solid var(--line);
  border-radius: 7px;
  text-decoration: none;
  transition: border-color .15s, background .15s;
}
.sc-addon:hover { border-color: var(--accent); background: var(--accent-soft, #fdf6f4); }
.sa-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.sa-name { font-size: 14.5px; color: var(--ink); }
.sa-desc { font-size: 13px; color: var(--muted-2); line-height: 1.6; }
.sc-addon b { font-size: 14.5px; color: var(--accent); white-space: nowrap; font-weight: 500; }

.alt-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 12px;
  padding: 12px 13px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--ink);
  transition: border-color 0.15s, background 0.15s;
}
.alt-card:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--ink); }
.alt-card b { font-size: 14.5px; font-weight: 500; line-height: 1.4; }
.alt-card .mode-tag { align-self: flex-start; font-size: 13px; padding: 3px 6px; margin-bottom: 2px; }
.alt-meta { font-size: 13.5px; color: var(--muted-2); }
.alt-price { font-size: 13.5px; color: var(--accent); font-family: var(--mono); margin-top: 4px; }
.alt-price.muted { color: var(--muted-2); }

.sc-dl { display: grid; grid-template-columns: auto 1fr; gap: 7px 14px; margin: 0; font-size: 14px; }
.sc-dl dt { color: var(--muted-2); white-space: nowrap; }
.sc-dl dd { margin: 0; color: var(--ink-2); text-align: right; word-break: break-all; }
.side-card.small { padding: 16px 18px; }
.side-card.small h3 { font-size: 15px; margin-bottom: 6px; }

@media (max-width: 1000px) {
  .dv-grid { grid-template-columns: 1fr; gap: 34px; }
  .dv-side { position: static; flex-direction: row; flex-wrap: wrap; }
  .dv-side > .side-card { flex: 1 1 260px; }
  /* 单列之后购买卡排到了正文末尾，页头这一条要顶上来：价格 + 一个入口。
     锚点跳到 #buyCard 时留 80px 余量，别被吸顶导航压住卡片顶部。 */
  .dv-head-buy {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 14px;
  }
  .dhb-price { font-size: 14px; color: var(--muted); }
  .dhb-price b {
    font-family: var(--mono);
    font-size: 26px;
    font-weight: 500;
    letter-spacing: -0.03em;
    color: var(--ink);
    line-height: 1;
  }
  #buyCard { scroll-margin-top: 80px; }
}
@media (max-width: 720px) {
  /* 手机上侧栏回到单列，图缩到 150 —— 再大就把价格与两颗按钮推到首屏之外，
     而这屏最该看见的恰恰是价格 */
  .dv-cover { width: 150px; height: 150px; }
  .dv-two { grid-template-columns: 1fr; }
  .dv-flow { grid-template-columns: 1fr; }
  .fix-row { grid-template-columns: 1fr; gap: 4px; }
  .fix-q { font-size: 14.5px; }
  .dv-side { flex-direction: column; }
  .dv-side > .side-card { flex: 1 1 auto; }
}

/* ------------------------------------------------------ 控制台「下一步」 */

.console-next {
  margin-top: 26px;
  padding: 24px 26px 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
/* 首页那三步是横线起头，控制台放在卡片里，横线会跟卡片上沿打架，
   改成左侧竖标，紧凑一档 */
.console-next .step {
  border-top: 0;
  padding-top: 0;
  padding-left: 14px;
  border-left: 2px solid var(--accent-line);
}
.console-next .step h3 { font-size: 15.5px; margin-bottom: 6px; }
.console-next .step p { font-size: 14.5px; line-height: 1.72; color: var(--muted); }
.console-next .step .mono { font-size: 14px; white-space: normal; }

@media (max-width: 760px) {
  .console-next { padding: 20px 18px 6px; }
  .console-next .steps { gap: 18px; }
}

/* ------------------------------------------------------ 控制台排障折叠区 */

.console-help {
  margin-top: 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.console-help summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding: 15px 18px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.console-help summary::-webkit-details-marker { display: none; }
.console-help summary::after {
  content: "+";
  margin-left: auto;
  font-family: var(--mono);
  font-size: 15px;
  color: var(--muted);
}
.console-help[open] summary::after { content: "−"; }
.ch-q { font-size: 15px; font-weight: 500; color: var(--ink); }
.ch-hint { font-size: 13.5px; color: var(--muted); }

.ch-body { padding: 4px 18px 18px; border-top: 1px solid var(--line); }
.ch-cols {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 34px;
  padding-top: 18px;
}
.ch-body h4 {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 12px;
}
.ch-dl { margin: 0; }
.ch-dl dt { margin-top: 12px; }
.ch-dl dt:first-child { margin-top: 0; }
.ch-dl dd {
  margin: 5px 0 0;
  font-size: 14.5px;
  color: var(--muted);
  line-height: 1.7;
}
.ch-dl dd b { color: var(--ink-2); font-weight: 600; }
.ch-ol { margin: 0; padding-left: 18px; }
.ch-ol li {
  font-size: 14.5px;
  color: var(--muted);
  line-height: 1.7;
  padding-bottom: 5px;
}
.ch-note { margin-top: 10px; font-size: 13.5px; color: var(--warn); }
.ch-foot {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  font-size: 14px;
  color: var(--muted);
  line-height: 1.7;
}
.ch-foot a { color: var(--accent); }

.console-help code,
.ch-foot code {
  font-family: var(--mono);
  font-size: 13.5px;
  padding: 1px 5px;
  border-radius: 3px;
  background: rgba(14, 26, 43, 0.055);
  color: var(--ink-2);
}

@media (max-width: 760px) {
  .ch-cols { grid-template-columns: 1fr; gap: 24px; }
  .console-help summary { padding: 13px 15px; }
  .ch-body { padding: 2px 15px 16px; }
}

/* ============================================================
   导航改版（2026-11-06）
   品牌 / 平台两个新入口，加移动端下拉菜单。
   ============================================================ */

.nav-links { display: flex; align-items: center; gap: 2px; }

/* 导航项一律不折行。
   2026-11-08 加了「邀请有礼」和「消息」两个入口，1280 宽下这一排撑爆了——
   浏览器不是把最后一个挤下去，而是把每一项中文拆成两行（「驱动目 / 录」），
   整条导航变成锯齿。宁可整项换行，也不让字断在中间。 */
.tlink, .nav-links .tlink, .nav-act .tlink { white-space: nowrap; flex: none; }

/* 真挤不下时整排换行，别溢出到 logo 上 */
.nav-links { flex-wrap: wrap; row-gap: 4px; justify-content: flex-end; }
.nav-act { display: flex; align-items: center; gap: 8px; margin-left: 8px; }
.tlink.on { color: var(--ink); background: var(--paper-2); }
.nav-toggle { display: none; }
/* 折叠态菜单尾部的登录 / 进入控制台，桌面端不渲染 */
.nav-auth { display: none; }

/* ---------------------------------------------- 账号菜单（2026-11-09） */
/* 顶栏原来把「认证徽标 + 昵称 + 退出」平铺在导航右侧，昵称一带手机号就是 20 个字符，
   1280 宽下把主导航挤成两行。收成一枚头像按钮后，名字再长也只占 96px。
   菜单本身用 absolute 定位，不参与顶栏的弹性计算。 */
.nav-user { position: relative; flex: none; margin-left: 4px; }

.nu-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 34px; padding: 0 9px 0 4px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 14.5px; cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.nu-btn:hover { border-color: var(--line-strong); background: var(--paper-2); }
.nu-btn[aria-expanded="true"] { border-color: var(--accent); background: var(--surface); }

/* 头像用昵称首字，背景取会员等级色；未认证时用一个中性的墨色 */
.nu-ava {
  width: 26px; height: 26px; flex: none;
  display: grid; place-content: center;
  border-radius: 50%;
  background: var(--seal, #2d3b4e);
  color: #fff; font-size: 14px; font-weight: 700; line-height: 1;
  overflow: hidden;
}
.nu-name {
  max-width: 116px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 600;
}
.nu-seal { color: var(--seal, var(--accent)); font-size: 14px; line-height: 1; }
.nu-caret { flex: none; color: var(--muted); transition: transform 0.15s ease; }
.nu-btn[aria-expanded="true"] .nu-caret { transform: rotate(180deg); }

.nu-menu {
  position: absolute; right: 0; top: calc(100% + 9px); z-index: 60;
  width: 244px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow-md);
  animation: nuIn 0.14s ease both;
}
.nu-menu[hidden] { display: none; }
@keyframes nuIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

.nu-head { padding: 9px 10px 10px; border-bottom: 1px solid var(--line); }
.nu-head b {
  display: block; font-size: 14.5px; line-height: 1.35;
  word-break: break-all; color: var(--ink);
}
.nu-head span { display: block; margin-top: 3px; font-size: 13.5px; color: var(--muted); }
.nu-head span a { color: var(--accent-2); border-bottom: 1px solid var(--accent-line); }

.nu-links { padding: 5px 0; }
.nu-links a {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 10px; border-radius: 7px;
  font-size: 15px; color: var(--ink-2);
}
.nu-links a:hover { background: var(--paper-2); color: var(--ink); }
.nu-links a.nu-ops { color: var(--accent-2); }
.nu-dot {
  min-width: 17px; height: 17px; padding: 0 4px;
  display: inline-grid; place-content: center;
  border-radius: 9px; background: var(--brand); color: #fff;
  font-size: 13.5px; font-weight: 700;
}
.nu-out {
  display: block; width: 100%; margin-top: 2px; padding: 9px 10px 7px;
  border: 0; border-top: 1px solid var(--line); background: none;
  text-align: left; font: inherit; font-size: 14.5px; color: var(--muted);
  cursor: pointer; border-radius: 0 0 8px 8px;
}
.nu-out:hover { color: var(--danger); background: var(--danger-soft); }

.footer-links { display: flex; gap: 16px; flex-wrap: wrap; }
.footer-links a { color: var(--muted); }
.footer-links a:hover { color: var(--accent); }

.nav-toggle span {
  display: block;
  width: 15px;
  height: 1.6px;
  background: currentColor;
  border-radius: 2px;
}
.nav-toggle span + span { margin-top: 3.4px; }

@media (max-width: 860px) {
  .nav-links .nav-sm-hide { display: none; }
  .brand-sub { display: none; }
}

/* 导航从 720 → 1000 → 1080，每次都是同一个原因：这一排又多了一个入口。
   720→1000 是加了「邀请」和铃铛；1000→1080 是「问答」占回第 9 个位置，
   1024 实测「后台」被挤到第二行（右对齐，压在顶栏下边框外面，比汉堡难看）。
   1080 以上（1180 / 1280 实测）仍是一整排。 */
@media (max-width: 1080px) {
  .topbar-in { gap: 8px; position: relative; }
  .brand-name { font-size: 14.5px; letter-spacing: 0.08em; }
  .nav-toggle {
    display: grid;
    place-content: center;
    width: 34px;
    height: 34px;
    margin-left: 4px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    color: var(--ink);
    cursor: pointer;
  }
  .nav-act { margin-left: auto; gap: 6px; }
  .nav-act .btn-ghost { display: none; }
  .nav-act .tlink { max-width: 84px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* 购物车是唯一不能藏进汉堡菜单、也不能被截断的入口 */
  .nav-act .tlink.nav-cart { max-width: none; flex: none; overflow: visible; padding: 7px 8px; font-size: 14.5px; }
  .nav-cart b { margin-left: 3px; }

  /* 空间紧张时账号只留头像 + 箭头，全名和等级在展开的菜单头部 */
  .nu-name, .nu-seal { display: none; }
  .nu-btn { padding: 0 7px 0 3px; gap: 5px; }

  /* 收起的导航做成一整条下拉，贴着顶栏下沿，不遮内容也不挤按钮 */
  .nav-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* 左右要和 .wrap 的 28px 内边距对齐：以前写 16px，减去 -28 的偏移后
       文字从 -12px 开始，整列被切掉一截（只在手机上看得出来）。 */
    padding: 6px 28px 10px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 14px 28px rgba(14, 26, 43, 0.09);
  }
  body.nav-open .nav-links { display: flex; }
  .nav-links .tlink,
  .nav-links .tlink.nav-sm-hide {
    display: block;
    padding: 11px 8px;
    border-radius: 7px;
    font-size: 15px;
  }
  .nav-links .tlink + .tlink { border-top: 1px dashed var(--line); }
  /* 登录 / 进入控制台：桌面端在 nav-act 里，折叠后藏了，这里补回来。
     两个按钮等宽，别一个贴左一个贴右。 */
  .nav-auth {
    display: flex; gap: 8px;
    padding: 12px 8px 2px; margin-top: 6px;
    border-top: 1px solid var(--line);
  }
  .nav-auth .btn { flex: 1 1 0; justify-content: center; }
}

/* ------------------------------------------------ 目录：表头与第三方标记 */

/* 72 条之后，没有表头就不知道哪一列是品牌哪一列是接入方式 */
.prod-head {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 0.95fr) minmax(0, 1.05fr) 92px 78px;
  gap: 16px;
  padding: 8px 4px;
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-2);
  border-bottom: 1px solid var(--line);
}

/* 第三方作者的驱动：官方名单里有，但要单独买授权，不能和「官方免费」混着看 */
.pr-by {
  flex: none;
  font-size: 13px;
  letter-spacing: 0.02em;
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid rgba(143, 90, 18, 0.28);
  background: var(--warn-soft);
  color: var(--warn);
  white-space: nowrap;
}

.pr-brand a { color: var(--ink-2); border-bottom: 1px solid transparent; }
.pr-brand a:hover { color: var(--accent); border-bottom-color: rgba(12, 122, 80, 0.35); }

/* 认证标签：两档，只挂在「在售自研」驱动上。
   首发用冷蓝 —— 它描述的是时间（刚上），不该和「质量通过」共用一个绿；
   已认证用翠绿配勾，跟后台的通过态一脉相承。
   字号压到 9.5px：它是附注，抢了产品名的注意力就失去意义。 */
.cert-badge {
  flex: none;
  /* 宽度必须钉死。auto 在详情页页头那排 flex 里会被算成「只有内边距」的
     16px —— 文字的 scrollWidth 明明有 48，却不参与盒子宽度，溢出去压住右边
     的接入方式（「继电器与 I/O」只剩「器与 I/O」）。同一个类在目录页又算得对，
     这种「一处正常一处塌陷」最难查，钉死就再不会复发。 */
  width: max-content;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 13px;
  line-height: 1.45;
  letter-spacing: 0.04em;
  white-space: nowrap;
  border: 1px solid transparent;
  vertical-align: 1px;
}
.cert-badge.is-first {
  color: #14507f;
  background: #dcebf8;
  border-color: #a8cbe8;
}
.cert-badge.is-cert {
  color: #075e3d;
  background: #d5ebdf;
  border-color: rgba(12, 122, 80, 0.42);
}
/* 勾用伪元素而不是写进宏的文案：这样全站搜「已认证」只会命中真那三个字 */
.cert-badge.is-cert::before { content: "✓"; font-size: 10px; }

/* 详情页页头比列表大一号：那里是判断「这东西靠不靠得住」的地方 */
.cert-badge.lg { font-size: 13.5px; padding: 2px 7px; border-radius: 4px; }

/* 后台复用同一个类当按钮。没有 cursor 就会出现「看着能点、点了没反应」的错觉；
   边框改虚线，是因为虚线在界面语言里就等于「这里可以改」—— 不额外加图标，
   加了下标「首发 ⇄ 已认证」这种啰嗦的东西反而把 0.78fr 的列撑爆。 */
button.cert-badge { font-family: inherit; cursor: pointer; border-style: dashed; }
button.cert-badge:hover { border-color: currentColor; }
button.cert-badge:disabled { cursor: default; opacity: 0.55; }

.cbh-count {
  flex: none;
  font-size: 13.5px;
  color: var(--muted-2);
  letter-spacing: 0.04em;
}

@media (max-width: 900px) {
  .prod-head { display: none; }
  .cbh-count { order: 3; width: 100%; }
}

/* ------------------------------------------------ 详情页：字段表与验收集 */

.field-table { border-top: 1px solid var(--line); }
.ft-head,
.ft-row {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.05fr) minmax(0, 1.3fr);
  gap: 20px;
  padding: 11px 2px;
}
.ft-head {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-2);
  border-bottom: 1px solid var(--line);
}
.ft-row { border-bottom: 1px dashed var(--line); }
.ft-row:last-child { border-bottom: 0; }
.ft-name { font-size: 14px; color: var(--ink); padding-top: 1px; }
.ft-val { font-size: 14.5px; color: var(--ink-2); line-height: 1.65; }
.ft-note { font-size: 14.5px; color: var(--muted); line-height: 1.7; }

.dv-verify { list-style: none; margin: 0; padding: 0; }
.dv-verify li {
  position: relative;
  padding: 9px 0 9px 26px;
  border-bottom: 1px dashed var(--line);
  font-size: 15px;
  color: var(--ink-2);
  line-height: 1.7;
}
.dv-verify li:last-child { border-bottom: 0; }
.dv-verify li::before {
  content: "✓";
  position: absolute;
  left: 2px;
  top: 9px;
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
}

@media (max-width: 720px) {
  .ft-head { display: none; }
  .ft-row { grid-template-columns: 1fr; gap: 3px; padding: 12px 0; }
  .ft-name { font-size: 14.5px; color: var(--muted); font-weight: 600; }
  .ft-val { font-size: 15px; }
}

/* ------------------------------------------------------------ 品牌索引页 */

.brand-filter {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  padding: 12px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.brand-filter-note { font-size: 14px; color: var(--muted); font-family: var(--mono); }

.brand-grid { padding: 4px 0 40px; }

/* 字母索引条：69 个品牌平铺时只能靠滚，有了这排才有「翻字典」的感觉 */
.bindex {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 13px 0 3px;
}
.bindex a {
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--ink-2);
  border: 1px solid transparent;
  border-radius: 5px;
  transition: background 0.12s, border-color 0.12s;
}
.bindex a:hover { background: var(--surface); border-color: var(--line-strong); color: var(--ink); }
.bindex a[hidden] { display: none; }

/* 分组：字母 + 条数，右边一条渐隐的横线把行收住 */
.bgrp { scroll-margin-top: 86px; }
.bgrp[hidden] { display: none; }
.bgrp-h {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 22px 0 12px;
}
.bgrp-h span {
  font-family: var(--serif);
  font-size: 23px;
  font-weight: 600;
  line-height: 1;
}
.bgrp-h i { font-style: normal; font-size: 13.5px; color: var(--muted-2); }
.bgrp-h::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, var(--line-strong), transparent);
}
.bgrp-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 12px;
}

.brand-card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 15px 16px 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  transition: border-color 0.15s, transform 0.15s;
}
.brand-card:hover { border-color: var(--accent); color: var(--ink); transform: translateY(-1px); }
.brand-card[hidden] { display: none; }

.bc-head { display: flex; align-items: center; gap: 7px; }
.bc-name { font-family: var(--serif); font-size: 17px; font-weight: 600; line-height: 1.3; }
/* 主名后面跟的另一种写法。同一个品牌在「中」组和字母组各有一张卡，
   别名压淡一档，读者才认得出是「一个牌子的两个名字」而不是重复数据 */
.bc-alt {
  font-weight: 500;
  font-size: 0.84em;
  color: var(--muted-2);
}
.bc-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--accent); flex: none; }
.bc-meta { font-size: 13.5px; color: var(--muted-2); letter-spacing: 0.03em; }
.bc-cats { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.bc-cat {
  font-size: 13.5px;
  color: var(--muted);
  background: var(--paper-2);
  border-radius: 4px;
  padding: 1px 6px;
  white-space: nowrap;
}
.bc-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
  font-size: 13.5px;
  color: var(--muted-2);
}
.bc-tags { display: inline-flex; align-items: center; gap: 3px; }
.bc-tags .lg { margin-left: 5px; }
.bc-go { color: var(--muted-2); }

/* ------------------------------------------------------------ 品牌详情页 */

.brand-head { padding-bottom: 6px; }
.brand-plat-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 10px; }
.brand-plat {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 14px;
  color: var(--ink-2);
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}
.brand-plat i { font-size: 13.5px; color: var(--muted-2); font-style: normal; }
.crumb-inline { font-size: 14px; color: var(--accent); }

/* ------------------------------------------------------------ 平台页 */

.plat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
  padding: 8px 0 20px;
}

/* 规划中的平台：一块浅底 + 一排小条目。原来五张等大的空卡把有货那张淹掉了 */
.plat-plan {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  padding: 20px 22px 6px;
  margin-bottom: 8px;
}
.plat-plan-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: 16px;
}
.plat-plan-head h2 {
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.plat-plan-head h2 .mono {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 400;
  color: var(--muted);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 1px 7px;
}
.plat-plan-head p {
  margin-top: 7px;
  max-width: 68ch;
  font-size: 14px;
  color: var(--muted);
  line-height: 1.75;
}
.plat-plan-list { border-top: 1px solid var(--line); }
.plat-plan-item {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px dashed var(--line);
  transition: background 0.12s, padding-left 0.12s;
}
.plat-plan-item:last-child { border-bottom: 0; }
.plat-plan-item b { font-size: 15px; font-weight: 600; }
.plat-plan-item .mono { font-size: 13.5px; color: var(--muted-2); letter-spacing: 0.04em; }
.plat-plan-item i {
  margin-left: auto;
  font-style: normal;
  font-size: 13.5px;
  color: var(--muted);
  opacity: 0.5;              /* 常显但压淡：藏起来就没人知道这行能点 */
  transition: opacity 0.12s, color 0.12s;
}
.plat-plan-item:hover { background: var(--accent-soft); padding-left: 8px; }
.plat-plan-item:hover i { opacity: 1; color: var(--accent-2); }

.plat-card {
  display: flex;
  flex-direction: column;
  padding: 20px 22px 18px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
}
.plat-card.live {
  border-style: solid;
  border-color: var(--line-strong);
  background: var(--surface);
  box-shadow: 0 1px 0 rgba(14, 26, 43, 0.03);
  /* 只有一两个平台时卡片会独占一行，纵向堆四块内容右半页全空。
     改成左信息 / 右数字两栏，卡片自己就撑满了 */
  display: grid;
  grid-template-columns: minmax(0, 1fr) 330px;
  gap: 40px;
  padding: 24px 26px 22px;
}
.plat-main { display: flex; flex-direction: column; }
.plat-card.live .plat-nums {
  grid-template-columns: repeat(2, 1fr);
  /* 数字块单独铺一层浅底：不然四个格子跟卡片同色，看上去只是一堆数字散在右边 */
  background: var(--paper);
  border-radius: var(--radius);
  padding: 5px;
}
@media (max-width: 900px) {
  .plat-card.live { grid-template-columns: minmax(0, 1fr); gap: 22px; }
}
.plat-head { display: flex; align-items: flex-start; gap: 12px; }
.plat-head h2 { font-family: var(--serif); font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
.plat-maker { font-size: 13.5px; color: var(--muted); margin-top: 3px; }
.plat-nums {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 9px;
  overflow: hidden;
  margin: 16px 0 14px;
}
.plat-nums > div { background: var(--surface); padding: 9px 10px; }
.plat-nums b { display: block; font-family: var(--mono); font-size: 17px; font-weight: 500; line-height: 1.2; }
.plat-nums span { font-size: 13.5px; color: var(--muted); }
.plat-cats { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 16px; }
.plat-desc { font-size: 14.5px; color: var(--muted); line-height: 1.75; }
.plat-points { margin: 10px 0 0; padding-left: 16px; }
.plat-points li { font-size: 14px; color: var(--muted-2); line-height: 1.8; }
.plat-foot { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 16px; }

.plat-why { padding: 34px 0 60px; border-top: 1px solid var(--line); margin-top: 26px; }
.plat-why h2 { font-family: var(--serif); font-size: 22px; font-weight: 600; margin-bottom: 20px; }
.plat-why-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; }
.plat-why-grid h3 { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
.plat-why-grid p { font-size: 14.5px; color: var(--muted); line-height: 1.8; }

@media (max-width: 900px) {
  .plat-why-grid { grid-template-columns: 1fr; gap: 18px; }
}
@media (max-width: 720px) {
  .brand-grid { grid-template-columns: 1fr 1fr; gap: 9px; padding: 18px 0 30px; }
  .bc-name { font-size: 16px; }
  .bc-cats { display: none; }
  .plat-card { padding: 17px 16px 15px; }
  .plat-nums b { font-size: 16px; }
}
@media (max-width: 420px) {
  /* 一列要滚 69 屏。两列仍能放下「AVPro Edge」这种长名，字号缩一档就行 */
  .brand-grid { gap: 8px; }
  .bc-name { font-size: 15px; }
  .bc-meta { font-size: 13px; }
  .bc-tag { font-size: 13px; }
}

/* ============================================================
   品牌页与平台页收尾（2026-11-06）
   卡片底部原来是「小方块 + 数字」，脱离图例读不懂；改成带字标签。
   平台页六张卡各写一遍同样三条 → 合并成一段，卡片只留一句状态。
   ============================================================ */

.bc-tag {
  font-size: 13.5px;
  color: var(--muted-2);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.bc-tag + .bc-tag::before {
  content: "·";
  margin: 0 5px 0 2px;
  color: var(--line-strong);
}
.bc-tag.paid { color: var(--accent); }
.bc-tag.soon { color: var(--muted-2); }

.bc-hint {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  font-size: 13px;
  color: var(--muted-2);
  white-space: nowrap;
}
.bc-hint .bc-dot { width: 5px; height: 5px; flex: none; }

/* 品牌详情页的平台胶囊：原来跟一个平台短码（CH），信息量为零；改成该平台的 SKU 数 */
.brand-plat b {
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-2);
}

.plat-note {
  margin: 22px 0 0;
  padding: 18px 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
}
.plat-note b { display: block; font-size: 15px; margin-bottom: 7px; }
.plat-note p { font-size: 14.5px; color: var(--muted); line-height: 1.8; max-width: 76ch; }

@media (max-width: 720px) {
  .bc-hint { display: none; }
  .plat-note { padding: 15px 16px; }
}

/* ------------------------------------------------------------ 驱动包下载 */
.dv-pkg {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
}
.dv-pkg .btn { margin-bottom: 0; }
.dv-pkg-note {
  display: block;
  margin-top: 7px;
  font-size: 13.5px;
  color: var(--muted-2);
  line-height: 1.7;
}
a.dv-pkg-note:hover { color: var(--accent); }

/* 「同一份授权，另有 N 种装法」的每个装法。
   右栏内宽 258px，而装法名字最长的是「网口版（UDP 6517，一口一个实例）」，
   连同版本号一共要 309px —— .btn 又带 white-space:nowrap，整行会从卡片左边缘
   溢出去压住正文（客户 2026-11-09 截图指出），390 下还把卡片撑到 430px、
   整页能横向拖动。这里改成两行：装法名在上、版本与体积在下。 */
.dv-var {
  height: auto;
  min-height: 40px;
  padding: 7px 10px;
  flex-direction: column;
  gap: 1px;
  white-space: normal;
  line-height: 1.45;
  text-align: center;
}
.dv-var + .dv-var { margin-top: 6px; }
.dv-var-l { display: block; font-size: 14.5px; }
.dv-var-m {
  display: block;
  font-size: 13px;
  font-weight: 400;
  color: var(--muted);
  letter-spacing: 0.01em;
}
/* 没买过时是一行灰字，不是按钮；同样两行，别让它跟上面的按钮长得一样 */
.dv-var-off { margin-top: 7px; }
.dv-var-off .dv-var-l { font-size: 14px; color: var(--ink-2); }
.dv-var-off .dv-var-m { color: var(--muted-2); }

/* 390 下五个统计格子挤成一行时，中文标签会在词中间折断（「官方内 / 置」）。
   改成横向滑一条：不折行、不留孤零零的一个格子，跟大类 chips 的交互一致。 */
@media (max-width: 420px) {
  .cat-stat-row {
    display: flex;
    gap: 20px;
    overflow-x: auto;
    padding-bottom: 2px;
    -webkit-overflow-scrolling: touch;
  }
  .cat-stat-row::-webkit-scrollbar { display: none; }
  .cat-stat { flex: none; }
  .cat-stat span { white-space: nowrap; }
}

/* ============================================================ 授权说明页 */

/* 授权页顶部的三张卡：先把「多少钱」摆在第一屏，再往下才是五行明细 */
/* 分节标题：买断价目那块单独起一段，避免和上方「三种授权」的三张卡黏在一起 */
.lic-sec-head { margin: 0 0 16px; }
.lic-sec-head h2 {
  font-size: 17px;
  font-weight: 500;
  color: var(--ink);
  margin: 0 0 6px;
}
.lic-sec-head p {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--muted);
  margin: 0;
  max-width: 64ch;
}

/* 一张卡里并排三档：同一份授权的三种期限，必须能一眼横向比较 */
.lic-tiers {
  list-style: none;
  margin: 10px 0 12px;
  padding: 0;
  border-top: 1px dashed var(--line);
}
.lic-tiers li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  padding: 6px 0;
  font-size: 14px;
  color: var(--muted);
  border-bottom: 1px dashed var(--line);
}
.lic-tiers li:last-child { border-bottom: 0; }
.lic-tiers b { color: var(--ink-2); font-weight: 500; }
.lic-fine {
  margin: -30px 0 46px;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--muted);
  max-width: 76ch;
}

.lic-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin: 4px 0 46px;
}
.lic-card {
  display: flex;
  flex-direction: column;
  padding: 20px 22px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.lic-card.hl { border-color: var(--accent); background: var(--accent-soft); }
.lic-card-k {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.lic-card-p {
  font-family: var(--serif);
  font-size: 34px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  margin-top: 12px;
}
.lic-card-p small { font-family: var(--sans); font-size: 14.5px; font-weight: 400; color: var(--muted); letter-spacing: 0; }
.lic-card-t { margin-top: 7px; font-size: 14px; color: var(--ink-2); }
.lic-card ul {
  list-style: none;
  margin: 15px 0 20px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.lic-card li {
  position: relative;
  padding-left: 13px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}
.lic-card li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--line-strong);
}
.lic-card.hl li::before { background: var(--accent); opacity: 0.55; }
.lic-card .btn { margin-top: auto; align-self: flex-start; }
/* 正式档的三个年限竖排，价格在前、年限在后，一眼能对上 */
.lic-tiers {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 14px 0 20px;
  border-top: 1px solid rgba(12, 122, 80, 0.16);
}
.lic-tier {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 7px 0;
  border-bottom: 1px solid rgba(12, 122, 80, 0.16);
}
.lic-tier b { font-family: var(--serif); font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums; }
.lic-tier span { font-size: 13.5px; color: var(--ink-2); }

.lic-table { border-top: 1px solid var(--line); margin-top: 4px; }
.lic-row {
  display: grid;
  grid-template-columns: 1fr 1.12fr 1.32fr 0.82fr 1.9fr;
  gap: 14px;
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
  font-size: 14.5px;
  color: var(--ink-2);
  line-height: 1.6;
  align-items: start;
}
.lic-head {
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--muted);
  letter-spacing: 0.05em;
  padding: 9px 0;
}
.lic-name {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
  color: var(--ink);
  font-weight: 600;
}
.lic-name em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 400;
  color: var(--muted-2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.lic-price { font-family: var(--mono); font-size: 13.5px; color: var(--ink); }
/* 正式授权三档原来挤在一行（¥399 / ¥999 / ¥1999），看不出哪档是几年。
   拆成竖排，年限跟着价格走。 */
.lp-stack { display: flex; flex-direction: column; gap: 2px; }
.lp-line { display: flex; align-items: baseline; gap: 7px; line-height: 1.5; }
.lp-line b { font-weight: 600; font-size: 14px; }
.lp-line i { font-style: normal; font-size: 13.5px; color: var(--muted); white-space: nowrap; }
.lic-foot { margin-top: 12px; font-size: 13.5px; color: var(--muted); line-height: 1.75; }

@media (max-width: 720px) {
  .lic-head { display: none; }
  .lic-row { grid-template-columns: 1fr; gap: 3px; padding: 14px 0; }
  /* 手机上五列横排必然挤成断字，改成竖排 + 前置字段名。
     标签用绝对定位而不是 inline-block：inline-block 在折行后会让第二行顶到最左，
     观感像另起一条；绝对定位 + padding-left 能让折行也对齐。 */
  .lic-row > span:not(.lic-name) {
    position: relative;
    padding-left: 62px;
  }
  .lic-row > span:not(.lic-name)::before {
    content: attr(data-l);
    position: absolute;
    left: 0;
    top: 0;
    width: 58px;
    font-family: var(--mono);
    font-size: 13.5px;
    color: var(--muted-2);
  }
}

/* 展厅申请表单 */
.sh-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-top: 16px;
  padding: 18px 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-width: 720px;
}
.sh-field { display: flex; flex-direction: column; gap: 6px; }
.sh-field.sh-wide { grid-column: 1 / -1; }
.sh-field label {
  font-family: var(--mono);
  font-size: 13.5px;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.sh-field input {
  padding: 9px 11px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 14.5px;
}
.sh-field input:focus { outline: none; border-color: var(--ink); }
.sh-field input::placeholder { color: var(--muted-2); }
.sh-act {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.sh-msg { font-size: 14px; color: var(--muted); line-height: 1.6; }
.sh-msg.is-ok { color: var(--accent); }
.sh-msg.is-bad { color: var(--danger); }
@media (max-width: 640px) {
  .sh-form { grid-template-columns: 1fr; padding: 14px 14px 16px; }
}

/* 区块末尾的「详见」行：一句话指路，不占新段落 */
.dv-more {
  margin-top: 14px;
  font-size: 13.5px;
  color: var(--muted);
  line-height: 1.7;
}
.dv-more a {
  color: var(--ink-2);
  border-bottom: 1px solid var(--line-strong);
  text-decoration: none;
}
.dv-more a:hover { color: var(--ink); border-bottom-color: var(--ink); }

/* 授权页的问答：字段名比详情页长，96px 会把「板」字挤到下一行 */
.lic-qa > div { grid-template-columns: 152px 1fr; }
@media (max-width: 560px) {
  .lic-qa > div { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------- 账号资料 */

.acct { padding-top: 38px; padding-bottom: 56px; }
.acct-head { max-width: 58ch; margin-bottom: 24px; }
.acct-head h1 {
  font-family: var(--serif);
  font-size: 29px;
  font-weight: 600;
  line-height: 1.35;
  margin: 8px 0 10px;
  letter-spacing: -0.01em;
}
.acct-head p { color: var(--muted); font-size: 15px; line-height: 1.75; }

.acct-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 296px;
  gap: 20px;
  align-items: start;
}

.acct-form { padding: 16px 18px 20px; }
.acct-acts { display: flex; gap: 10px; margin-top: 4px; }

/* 表单里的小分节：把「联系方式」和「收货地址」分开，
   否则八个输入框连成一片，客户不知道从哪开始填。 */
.acct-sec {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 18px 0 12px;
  padding-top: 16px;
  border-top: 1px dashed var(--line);
  font-size: 14px;
  letter-spacing: 0.06em;
  color: var(--ink-2);
}
.acct-sec em { font-style: normal; font-size: 13.5px; letter-spacing: 0; }
.acct-sec .acct-ok { color: var(--accent); }
.acct-sec .acct-miss { color: var(--muted-2); }

/* 已有邮箱 / 已有密码时不给输入框，给一段只读说明 ——
   灰掉的输入框反而让人以为「点一下就能改」 */
.acct-readonly {
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-2);
  font-size: 14.5px;
  color: var(--muted);
}

/* disabled 的输入框要一眼看出不能改：虚线边框比灰底更直白，
   灰底那一档太轻，和正常输入框差别不够 */
.acct-form input:disabled {
  background: var(--surface-2);
  border-style: dashed;
  border-color: var(--line);
  color: var(--muted);
  cursor: not-allowed;
}

.acct-side { padding: 16px 18px 18px; }
.acct-side h3 {
  margin: 0 0 12px;
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 600;
}
.acct-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--line);
  font-size: 14.5px;
}
.acct-row:first-of-type { border-top: 0; }
.acct-k { flex: 0 0 auto; color: var(--muted); }
.acct-v {
  min-width: 0;
  text-align: right;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.acct-v.is-miss { color: var(--warn); }

.acct-warn {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 14px;
  line-height: 1.65;
}

/* 绑定微信入口。放在账号状态卡里，和「已绑定 / 未绑定」挨着 ——
   放到主表单里会被当成又一个要填的字段。 */
.acct-bind {
  margin-top: 12px;
  width: 100%;
  justify-content: center;
  font-size: 14.5px;
}
.acct-tip { margin-top: 12px; font-size: 13.5px; line-height: 1.65; color: var(--muted); }

/* 窄屏先看到「还缺什么」，再往下才是表单 —— 用户来这页就是被提醒缺手机号 */
@media (max-width: 900px) {
  .acct-grid { grid-template-columns: minmax(0, 1fr); }
  .acct-side { order: -1; }
}
@media (max-width: 600px) {
  .acct { padding-top: 26px; padding-bottom: 40px; }
  .acct-head h1 { font-size: 24px; }
  .acct-form,
  .acct-side { padding: 14px 15px 16px; }
  .acct-acts .btn { flex: 1; }
}

/* ---------------------------------------------------------------- 运营后台 */
/* 内部工具，密度比客户页面高：一屏要看到今天该跟的线索、快用完的额度。
   这里不追求留白，追求「扫一眼就知道先干哪件事」。 */

.adm { padding-bottom: 70px; }

/* 微信配置页的几块面板直接排在 .adm 下，用的是 .panel 而不是 .adm-panel，
   于是块与块之间贴在一起，整页看起来像没排版。这里补上同一档间距。 */
.adm > section.panel { margin-bottom: 20px; }

/* 上面这几块的正文没有 .panel-body 包着，内容会直接贴到面板边框上。
   面板头的内距是 18px，这里统一对齐到同一根线。 */
.wxcard > .wxlead { margin: 0; padding: 14px 18px 10px; }
.wxcard > .wxkv { padding: 0 18px; }
.wxcard > .wxacts { margin: 0; padding: 14px 18px 18px; }
.adm > section.panel > .wxform { padding: 16px 18px 18px; }
.adm > section.panel > .wxcopy { margin: 0 18px; }
.adm > section.panel > .wxsteps { margin: 4px 18px 18px; padding-left: 34px; }
.adm > section.panel > .wxlead { margin: 0; padding: 14px 18px 18px; }
.adm > section.panel > .adm-table { border-top: 1px solid var(--line); }
.wxnote { padding: 18px 20px 16px; }
.wxnote h3 { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
.wxnote p { font-size: 14.5px; color: var(--muted); line-height: 1.75; }
.wxnote p + p { margin-top: 8px; }
.wxnote b { color: var(--ink-2); }

.adm-head {
  padding: 40px 0 24px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
.adm-head h1 { font-family: var(--serif); font-size: 30px; font-weight: 600; letter-spacing: -0.01em; }
.adm-head p { color: var(--muted); font-size: 15px; margin-top: 5px; max-width: 52ch; }

.adm-kpi { display: flex; gap: 10px; flex-wrap: wrap; }
.kpi {
  min-width: 118px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.kpi-n { display: block; font-size: 24px; line-height: 1.15; letter-spacing: -0.02em; }
.kpi-n em { font-style: normal; font-size: 14px; margin-left: 3px; color: var(--muted); letter-spacing: 0; }
.kpi-l { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); }
/* 副标：数字下面的那句解释。「其中 2 条超 24 小时」比单看 3 有用得多 */
.kpi-s { display: block; margin-top: 3px; font-size: 13.5px; line-height: 1.4; color: var(--muted-2); }
.kpi-s.warn { color: var(--warn); }

.adm-panel { margin-bottom: 20px; }
.adm-sub { font-size: 13px; margin-left: 8px; }

/* 分类 / 品牌两排索引。原来只有分类一排，且挤在标题右边，
   品牌筛选只能靠手拼 URL —— 客户报「Lutron 那个」时根本点不到。 */
.cat-index {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 18px;
}
.cat-index + .cat-index { border-top: 1px solid var(--line); }
.ci-l {
  flex: 0 0 auto;
  padding-top: 4px;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--muted-2);
  white-space: nowrap;
}
.cat-index .adm-tabs { flex: 1 1 auto; min-width: 0; }

/* 品牌可能有六七十个（多数只挂一个 SKU）。堆成六行会把 SKU 表推到首屏之外，
   改成一行横滑；分类只有几个，仍然换行。 */
.cat-index-brand .adm-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  padding: 1px 0 3px;
  scrollbar-width: thin;
}
.cat-index-brand .adm-tab { flex: 0 0 auto; }

.adm-tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.adm-tab em {
  margin-left: 5px;
  font-style: normal;
  font-size: 13.5px;
  color: var(--muted-2);
}
.adm-tab.on em { opacity: 0.72; }
.adm-tab {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 14px;
  color: var(--muted);
  text-decoration: none;
  border: 1px solid transparent;
  white-space: nowrap;
}
.adm-tab:hover { color: var(--ink); background: var(--paper-2); }
.adm-tab.on { color: var(--accent); background: var(--accent-soft); border-color: rgba(12, 122, 80, 0.18); }

/* 搜索栏单独一行：和筛选标签挤在一起时，输入框会被压到只剩几十像素 */
.adm-tools {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px 12px;
  border-top: 1px solid var(--line);
}
.adm-q {
  flex: 1;
  min-width: 0;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  font: inherit;
  font-size: 14.5px;
  color: var(--ink);
}
.adm-q::placeholder { color: var(--muted-2); }
.adm-q:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.1); }

.adm-reset { font-size: 14px; color: var(--muted); text-decoration: none; white-space: nowrap; }
.adm-reset:hover { color: var(--ink); }

/* 后台工具栏里的下拉（目前只有厂商登记的「类型」一个）。
   和 .adm-q 同高同边框，放在搜索框右边像一组工具，而不是另一个表单。 */
.adm-pick {
  flex: 0 0 auto;
  height: 34px;
  padding: 0 8px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  font: inherit;
  font-size: 14.5px;
  color: var(--ink-2);
}
.adm-pick:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.1); }

.adm-export {
  margin-left: auto;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 7px;
  font-size: 14px;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}
.adm-export:hover { color: var(--accent); border-color: rgba(12, 122, 80, 0.32); background: var(--accent-soft); }

/* 排序下拉。几千个客户时「最新注册」不是唯一有用的顺序：
   找续费看消费额，找失联看最近登录，找大户看项目数。 */
.adm-sort {
  height: 34px;
  padding: 0 8px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
  flex: none;
}
.adm-sort:focus { outline: 2px solid var(--accent-line); outline-offset: 1px; }

/* 分页器。这是「几千人时能不能管」的分水岭：
   没有它，第 51 个人往后就永远翻不到了（原实现是取 300 行后直接截断）。 */
.adm-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 18px;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
.pg-info { font-family: var(--mono); font-size: 13.5px; color: var(--muted); }
.pg-btns { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.pg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 14px;
  line-height: 1;
  text-decoration: none;
}
.pg-btn:hover { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.pg-btn.is-on { color: #fff; background: var(--accent); border-color: var(--accent); }
.pg-btn.is-off { color: var(--muted-2); background: transparent; border-color: transparent; }
.pg-gap { padding: 0 2px; font-size: 14px; color: var(--muted-2); }

/* ---------------- 目录管理 ---------------- */

/* 六列：SKU / 型号 / 归属 / 状态 / 键 / 操作。
   多一列「键」是因为客服装机时要核对产品键 —— 授权码里存的就是它。

   选择器要写成 .adm-row.adm-row-sku：`.adm-row` 定义在本段之后，
   同等特异性下后定义者赢，光写 .adm-row-sku 会被它整条盖掉。 */
.adm-row.adm-row-sku { grid-template-columns: 1.75fr 0.9fr 0.86fr 0.78fr 2fr 0.24fr 0.42fr; }
.adm-row-sku > * { min-width: 0; }
.adm-row-sku.is-off { opacity: 0.52; }

/* 状态和认证两个徽章竖排：状态列只有 0.78fr，横排会把「官方内置（免费）」
   这种长标签挤成两行。窄屏卡片布局里改回横排 —— 那里占的是整行宽度。 */
.adm-stack { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 3px; }
@media (max-width: 900px) {
  .adm-stack { flex-direction: row; align-items: center; gap: 6px; }
}

/* 价格列：三档并排在一格里，只有标准价是输入框。
   原来价格在单独一张表上，运营看到「在售」还得跳一页才知道多少钱。 */
.cat-price { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 15px; }
.cp-cell { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 0 0 auto; }
.cp-line { display: flex; align-items: center; gap: 4px; }
/* 三个数值要在同一条基线上：输入框 26px，两个只读数字也按 26px 行高排 */
.cp-cell b {
  display: block;
  line-height: 26px;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}
.cp-cell em {
  font-style: normal;
  font-size: 13px;
  line-height: 1.2;
  color: var(--muted-2);
  white-space: nowrap;
  letter-spacing: 0.01em;
}
.cp-cell.is-edit em { color: var(--accent-2); }
.cp-in { width: 54px; height: 26px; font-size: 14px; padding: 0 5px; }
/* 「存」贴着输入框，不放到行尾 —— 掉到下一行之后改价的人得多挪一次眼睛 */
.cp-save {
  width: 22px;
  height: 26px;
  padding: 0;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
}
.cp-save:hover { border-color: var(--accent); color: var(--accent-2); }
.cp-save:disabled { opacity: .6; cursor: default; }
/* 免费 = ¥0。这一格不写「—」：客户问「这个要不要钱」，答案是「不要」，不是「不知道」。 */
.cp-free { font-size: 14px; color: var(--muted); }
.cp-free b { color: var(--ink-2); font-weight: 500; }
.cp-none { font-size: 13.5px; color: var(--muted-2); }

/* 产品名比用户名长（「12 路 RS485 继电器」），单行截断会全变成「12 路 R…」。
   给两行，超过才截。 */
.adm-row-sku .adm-uname {
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* 编号必须整条露出来：客服装机时是照着它比对的，断行会被抄错 */
.cat-id { display: block; white-space: nowrap; font-size: 13px; color: var(--muted); }

/* 「说明不全」不是错误，是还不能上架。用浅黄标签而不是红点 ——
   后台红点满地都是，真出事时就看不出哪个是真错的。 */
.cat-warn {
  display: inline-block;
  padding: 0 5px;
  border-radius: 4px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 13.5px;
  line-height: 19px;
  cursor: help;
  white-space: nowrap;
}

.cat-actions { display: flex; gap: 6px; margin-left: auto; flex: none; }

.cat-hr { border: 0; border-top: 1px dashed var(--line-strong); margin: 18px 0 16px; }

.cat-save-hint { margin-right: auto; font-size: 14px; line-height: 1.45; color: var(--danger); }

/* 520px 一行只放得下一个字段，而 SKU 有十来个 —— 表单宽一点少滚两屏 */
.modal-wide { max-width: 760px; }
.field-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.field-row .field { margin-bottom: 12px; }
.field-row:last-of-type { margin-bottom: 4px; }

.adm-table { width: 100%; }

/* 六列：线索 / 公司+联系方式 / 客户备注 / 跟进 / 等待 / 状态。
   合并公司+联系方式、砍掉独立的「来源账号」列，换来多一列「跟进记录」。 */
.adm-row {
  display: grid;
  grid-template-columns: 60px 1.25fr 1.15fr 1.32fr 0.68fr 0.92fr;
  gap: 14px;
  align-items: center;
  padding: 11px 18px;
  border-top: 1px solid var(--line);
  font-size: 14.5px;
}
/* 有认领人的行比没认领人的高半行，表格会跳。给个下限让行高对齐 */
.adm-row:not(.adm-th) { min-height: 60px; }
.adm-th {
  border-top: 0;
  padding-top: 9px;
  padding-bottom: 9px;
  background: var(--surface-2);
  font-size: 13.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
/* 压了超过一天的，整行淡淡标一下：不刺眼，但滚动时能扫到 */
.adm-row.is-hot { background: rgba(143, 90, 18, 0.045); }

.adm-id { color: var(--muted); font-size: 14px; line-height: 1.35; }
.adm-who {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  color: var(--muted-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 没登录就提交的，值得多看一眼 —— 陌生访客比老客户更可能等着回复 */
.adm-who.guest { color: var(--warn); }
.adm-strong { font-weight: 500; color: var(--ink); }
.adm-contact { display: block; margin-top: 2px; font-size: 13px; font-weight: 400; color: var(--muted); }
.adm-date { font-size: 13.5px; color: var(--muted); }
.adm-note {
  font-size: 14px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 没写过跟进的显示成灰色斜体 —— 一眼能看出哪几条是「空白」 */
.adm-follow.empty { color: var(--muted-2); font-style: italic; }
.adm-left { color: var(--accent); font-weight: 500; }
.adm-done { font-size: 13.5px; color: var(--muted-2); }

/* 等待时长：24 小时黄、72 小时红。这不是 SLA，是让该打的电话自己冒出来 */
.adm-age { font-size: 14px; color: var(--muted); white-space: nowrap; }
.adm-age.warn { color: var(--warn); font-weight: 500; }
.adm-age.late { color: var(--danger); font-weight: 500; }
.adm-age.done { color: var(--muted-2); font-size: 13.5px; }

/* 公司归属：真正的公司名 + 角色徽章。下面那行小字是客户自己填的自由文本，
   两行必须能一眼分开 —— 运营看到「某某智能」以为绑好了，其实那只是个备注。 */
.adm-co { display: block; font-size: 14px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; }
.adm-role {
  display: inline-block;
  margin-top: 2px;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
  border: 1px solid var(--line);
}
.adm-role.is-owner { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.adm-co-free { display: block; font-size: 13.5px; color: var(--muted-2); overflow: hidden; text-overflow: ellipsis; }
.adm-ent { display: inline-block; margin-top: 4px; padding: 1px 6px; border-radius: 4px;
           font-size: 13.5px; background: var(--paper-2); color: var(--muted); }
.adm-ent.is-company { background: var(--accent-soft); color: var(--accent-2); }

.adm-side { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* 「改」这种行内小按钮，比整行一个编辑按钮更贴近它要改的那一格 */
.adm-go-sm { padding: 1px 8px; font-size: 13px; }

.adm-st { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.adm-badge {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 13.5px;
  line-height: 1.4;
  white-space: nowrap;
}
.adm-badge.st-open { background: var(--warn-soft); color: var(--warn); }
.adm-badge.st-contacted { background: var(--surface-2); color: var(--ink-2); border: 1px solid var(--line-strong); }
.adm-badge.st-granted { background: var(--accent-soft); color: var(--accent); }
.adm-badge.st-closed { background: transparent; color: var(--muted); border: 1px solid var(--line); }

.adm-go {
  padding: 3px 10px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink-2);
  font-family: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.adm-go:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }

.adm-owner {
  flex-basis: 100%;
  font-size: 13.5px;
  color: var(--muted-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 展厅三张现场照。审核的人不在现场，全靠这三格判断是不是真展厅，
   所以直接摊在列表里：点开是大图，缺的那格用虚线框标出来。 */
.adm-photos { display: flex; gap: 5px; margin-top: 6px; }
.adm-photo {
  width: 46px;
  height: 34px;
  border-radius: 5px;
  border: 1px solid var(--line);
  background-size: cover;
  background-position: center;
  background-color: var(--surface-2);
  flex: none;
}
a.adm-photo:hover { border-color: var(--accent); }
.adm-photo.is-miss {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 3px;
  border-style: dashed;
  border-color: var(--line-strong);
  color: var(--muted-2);
  font-size: 13px;
  line-height: 1.15;
  text-align: center;
  background: transparent;
}
/* 「发码」是这一行唯一的实体动作，给个实心底，别和「跟进」混成一个样子 */
.adm-go.is-grant {
  border-color: transparent;
  background: var(--accent);
  color: #fff;
  font-weight: 500;
}
.adm-go.is-grant:hover { color: #fff; opacity: 0.88; }
.adm-badge.st-rejected { background: var(--danger-soft); color: var(--danger); }

/* 发码弹窗：勾产品 + 站点码 + 签出来的码。码要能照着念/复制，
   所以用等宽字单独成行，不塞进提示条里。 */
.grant-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface-2);
}
.grant-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14.5px;
  color: var(--ink);
  cursor: pointer;
}
.grant-item input { width: 15px; height: 15px; flex: none; accent-color: var(--accent); }
.grant-item em { font-style: normal; font-size: 13px; color: var(--muted-2); }
.grant-warn {
  margin-bottom: 14px;
  padding: 9px 12px;
  border-radius: 8px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 14px;
  line-height: 1.6;
}
.grant-result {
  padding: 12px 14px;
  border-radius: 9px;
  border: 1px solid rgba(20, 110, 84, 0.2);
  background: rgba(20, 110, 84, 0.05);
}
.grant-ok { margin: 0 0 8px; font-size: 14.5px; font-weight: 500; color: var(--accent); }
.grant-codes { display: flex; flex-direction: column; gap: 4px; }
.grant-codes code {
  padding: 6px 9px;
  border-radius: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 13.5px;
  letter-spacing: 0.3px;
  word-break: break-all;
  user-select: all;
}

/* 额度：外层包一层，好让「明细」折叠在行下面而不破坏表格列 */
.adm-credit { border-top: 1px solid var(--line); }
.adm-credit .adm-row { border-top: 0; }
.adm-credit.is-done > .adm-row { opacity: 0.6; }
.adm-row-credit { grid-template-columns: 1.1fr 0.9fr 0.95fr 0.44fr 0.44fr 0.48fr 128px; }

.adm-acts { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.adm-mini {
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.adm-mini:hover { color: var(--ink); border-color: var(--line-strong); background: var(--surface-2); }

/* 流水明细：默认收起。要查某笔账时展开，平时不占高度 */
.adm-detail { border-top: 1px dashed var(--line); background: var(--surface-2); }
.adm-detail summary {
  padding: 7px 18px;
  font-size: 13.5px;
  color: var(--muted);
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 12px;
}
/* 左侧那句占满剩余宽度，工时/备注之类的补充信息推到右边 */
.adm-detail summary > span:first-of-type { flex: 1; }
.ad-x { color: var(--muted); white-space: nowrap; }
.ad-x + .ad-x { padding-left: 12px; border-left: 1px solid var(--line); }
.ad-x-miss { color: var(--danger); }
.adm-detail summary::-webkit-details-marker { display: none; }
.adm-detail summary::before { content: "▸ "; }
.adm-detail[open] summary::before { content: "▾ "; }
.adm-detail summary:hover { color: var(--ink-2); }

.adm-tl { padding: 2px 18px 10px; }
.adm-tl-row {
  display: grid;
  grid-template-columns: 76px 62px minmax(0, 1fr) 148px;
  gap: 12px;
  padding: 5px 0;
  border-top: 1px solid rgba(14, 26, 43, 0.05);
  font-size: 13.5px;
  color: var(--ink-2);
}
.adm-tl-row:first-child { border-top: 0; }
.adm-tl-t { color: var(--muted); }
.adm-tl-m { font-variant-numeric: tabular-nums; }
.adm-tl-m.plus { color: var(--accent); }
.adm-tl-m.minus { color: var(--ink-2); }
.adm-tl-n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-tl-w {
  font-size: 13.5px;
  color: var(--muted-2);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 跟进记录要能写一整句，不是单行输入框 */
.field textarea {
  width: 100%;
  min-height: 76px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  font: inherit;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink);
  resize: vertical;
}
.field textarea::placeholder { color: var(--muted-2); }
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.12);
}

.adm-empty { padding: 34px 18px 38px; text-align: center; }
.adm-empty p { font-size: 15px; color: var(--ink-2); }
.adm-empty a { color: var(--accent); }
.adm-hint { margin-top: 6px; font-size: 14px; color: var(--muted); }

/* ---------------------------------------------------------------- 用户管理 */

/* 后台分区切换：线索 / 用户。放页面顶部而不是主导航 ——
   导航栏那块已经被「驱动目录 / 品牌 / 平台」占满，再塞就挤成两行了。 */
.adm-switch {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  margin: 18px 0 16px;
  background: var(--paper-2);
  border-radius: 10px;
}
.adm-switch a {
  padding: 7px 16px;
  border-radius: 8px;
  font-size: 14.5px;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}
.adm-switch a:hover { color: var(--ink); }
.adm-switch a.on {
  background: var(--surface);
  color: var(--ink);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(14, 26, 43, 0.08);
}

/* 导航角标：只有「客户现在不能用」的才计数。数字小、颜色重 ——
   它的作用是让人路过时停一下，不是装饰。 */
.adm-badge {
  display: inline-block;
  min-width: 17px;
  margin-left: 4px;
  padding: 0 4px;
  border-radius: 9px;
  background: var(--danger);
  color: #fff;
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 400;
  line-height: 17px;
  text-align: center;
}

.adm-warn-txt { color: var(--warn); }

/* 七列：用户 / 联系方式 / 公司 / 时间 / 站点 / 订单 / 状态。
   联系方式和时间各占上下两行 —— 拆成四列会把每一列都压到换行，
   而且「邮箱」「手机」并排时反而看不出是同一个人。 */
.adm-row-user { grid-template-columns: 1.05fr 1.3fr 1fr 0.86fr 0.36fr 0.6fr 0.86fr; }
.adm-user { border-top: 1px solid var(--line); }
.adm-user .adm-row { border-top: 0; }
.adm-user.is-off > .adm-row { opacity: 0.52; }

.adm-uname {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.adm-src {
  display: inline-block;
  margin-top: 4px;
  padding: 1px 6px;
  border-radius: 5px;
  font-size: 13.5px;
  letter-spacing: 0.02em;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--line);
}
.adm-src.wechat { background: var(--accent-soft); color: var(--accent); border-color: rgba(12, 122, 80, 0.18); }
/* 两边都绑了要显眼一点：这类账号最容易被当成重号删掉 */
.adm-src.both { background: var(--warn-soft); color: var(--warn); border-color: rgba(143, 90, 18, 0.18); }

.adm-ways { display: grid; gap: 3px; min-width: 0; }
.adm-ways > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-ways .muted { font-size: 13px; }
.adm-spent { color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* 展开区：站点 / 订单 / 备注三块 */
.u-panel { padding: 12px 18px 14px; }
.u-block { margin-bottom: 14px; }
.u-block:last-child { margin-bottom: 0; }
.u-block h4 {
  margin: 0 0 6px;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.u-line {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) 78px 68px 64px;
  gap: 10px;
  align-items: center;
  padding: 4px 0;
  font-size: 13.5px;
  color: var(--ink-2);
  border-top: 1px solid rgba(14, 26, 43, 0.05);
}
.u-line:first-of-type { border-top: 0; }
/* 站点行的四段：码 / 名字+地区 / 改 / 日期 */
.u-line-site { grid-template-columns: 150px minmax(0, 1fr) auto 68px; }
.u-code { letter-spacing: 0.02em; }
.u-mid { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.u-region {
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 4px;
  font-size: 13.5px;
  font-style: normal;
  color: var(--muted);
  background: var(--surface-2);
}
/* 没设地区要显眼：这一格空着，按地区筛项目就永远筛不到它 */
.u-region.is-miss { color: var(--warn); background: var(--warn-soft); }
.u-more { margin-top: 8px; font-size: 13.5px; color: var(--muted); }
.u-note {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--ink-2);
  white-space: pre-wrap;
  padding: 8px 10px;
  background: var(--surface-2);
  border-left: 2px solid var(--line-strong);
  border-radius: 0 6px 6px 0;
}

/* 停用开关单独一行：和输入框挨着容易被顺手勾上 */
.u-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  font-size: 14.5px;
  color: var(--ink-2);
  cursor: pointer;
}
.u-check input { width: 16px; height: 16px; accent-color: var(--danger); cursor: pointer; }

.adm-foot {
  font-size: 13.5px;
  color: var(--muted-2);
  line-height: 1.75;
  max-width: 78ch;
}

@media (max-width: 900px) {
  /* 六列舍掉客户备注 → 五列。列数必须跟着减，否则多出的格子掉到下一行 */
  .adm-row { grid-template-columns: 54px 1.2fr 1.15fr 0.7fr 0.95fr; }
  .adm-row > :nth-child(3) { display: none; }
  .adm-row-credit { grid-template-columns: 1fr 0.9fr 0.48fr 0.48fr 0.52fr 120px; }
  .adm-row-credit > :nth-child(3) { display: none; }
  /* 用户表同样舍掉「公司」列。列数必须跟着改，否则第 7 个格子掉到下一行 */
  .adm-row-user { grid-template-columns: 1.1fr 1.25fr 0.86fr 0.36fr 0.6fr 0.86fr; }
  .adm-row-user > :nth-child(3) { display: none; }
}

@media (max-width: 700px) {
  .adm-head { padding-top: 28px; }
  .adm-head h1 { font-size: 25px; }
  .adm-kpi { width: 100%; }
  .kpi { flex: 1 1 46%; min-width: 0; padding: 10px 12px; }
  .kpi-n { font-size: 20px; }

  .adm-panel .panel-head { flex-wrap: wrap; align-items: flex-start; gap: 10px; }
  .adm-tabs { width: 100%; }

  .adm-tools { flex-wrap: wrap; padding: 10px 15px 12px; }
  .adm-q { flex: 1 1 100%; }
  .adm-export { margin-left: 0; }
  .adm-sort { flex: 1 1 auto; }
  /* 页码多时按钮会顶出屏幕：让信息行和按钮各占一行，按钮自己换行 */
  .adm-pager { flex-direction: column; align-items: flex-start; padding: 12px 15px; }
  .pg-btns { width: 100%; }
  /* SKU 表单三列挤在手机上只剩 100px，一格一行 */
  .field-row { grid-template-columns: 1fr; gap: 0; }
  .cat-actions { margin-left: 0; width: 100%; justify-content: flex-end; }

  .adm-table { padding: 2px 0; }
  .adm-th { display: none; }
  .adm-row,
  .adm-row-credit,
  .adm-row-user {
    grid-template-columns: 1fr;
    gap: 6px;
    padding: 13px 15px;
  }
  .adm-row > :nth-child(3),
  .adm-row-credit > :nth-child(3) { display: block; }

  /* 卡片式：字段名固定 64px，值跟在后面。
     用 flex 而不是 grid —— 值里还有徽标、按钮这些小元素，
     grid 的 grid-column 会把它们顶到意料之外的行。 */
  .adm-row > [data-l],
  .adm-row-credit > [data-l] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    min-width: 0;
  }
  .adm-row > [data-l]::before,
  .adm-row-credit > [data-l]::before {
    content: attr(data-l);
    flex: 0 0 64px;
    font-size: 13.5px;
    letter-spacing: 0.04em;
    color: var(--muted-2);
  }
  .adm-row > [data-l] > *,
  .adm-row-credit > [data-l] > * { min-width: 0; overflow-wrap: anywhere; }
  .adm-contact { flex-basis: 100%; margin-top: 1px; }
  /* 认领人别和「跟进」按钮挤一行，窄屏下会顶到卡片边缘；
     缩进 64px 对齐上面的值，否则会贴着卡片左边像另一个字段 */
  .adm-owner { flex-basis: 100%; padding-left: 64px; }
  .adm-note,
  .adm-tl-n { white-space: normal; }
  .adm-acts { flex: 1; }

  .adm-detail summary { padding: 8px 15px; }
  .adm-tl { padding: 2px 15px 10px; }
  /* 明细一行放不下四个字段，改成上下两行 */
  .adm-tl-row { grid-template-columns: 1fr; gap: 1px; padding: 8px 0; }
  .adm-tl-w { text-align: left; }

  /* 站点 / 订单明细同样竖排：五列在 390px 下会被压成一条缝 */
  .u-panel { padding: 10px 15px 12px; }
  .u-line,
  .u-line-site { grid-template-columns: 1fr; gap: 2px; }
  /* 12 个后台入口在 390px 下排成一行要 856px 宽，整页跟着横向滚动。
     允许换行，宁可叠成三行；每项按内容宽度分，不写 flex:1（那会把字挤断）。 */
  .adm-switch { display: flex; flex-wrap: wrap; margin: 14px 0; }
  .adm-switch a { flex: 1 1 auto; text-align: center; }
}

/* -------------------------------------------------- 新版页头/价格卡的窄屏收拢 */

/* 页头的两栏（标题 + 数字栏）在 900px 以下叠成一栏。
   数字栏改回横排、去掉引导虚线 —— 一行放不下四个带说明的数字，宁可换行 */
@media (max-width: 900px) {
  .page-head {
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    padding: 34px 0 22px;
  }
  .cat-stat-row {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0 26px;
    border-top: 1px solid var(--line);
  }
  .cat-stat {
    flex: 0 0 auto;
    padding: 9px 0 7px;
    border-bottom: 0;
    gap: 7px;
  }
  .cat-stat .lead { display: none; }
  .lic-cards { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .plat-plan-head { flex-wrap: wrap; gap: 10px; }
}

/* 分类序号在窄屏改成行内（标题上方一行），44px 缩进会白白吃掉表格宽度 */
@media (max-width: 700px) {
  .cat-block { padding-left: 0; }
  .cat-block::before {
    position: static;
    display: block;
    margin-bottom: 5px;
  }
  .prod-row:hover::before { display: none; }
}

/* 手机上品牌卡片改成两列：69 个品牌单列排下来要滚近十屏 */
@media (max-width: 480px) {
  .bgrp-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .brand-card { padding: 12px 12px 11px; gap: 6px; }
  .bc-name { font-size: 16px; }
  .bc-cat { font-size: 13.5px; padding: 1px 5px; }
}

/* ===== 平台开关台（/ops/platforms）=====

   这张表和前台没有关系，所以没有沿用卡片、大留白那一套：16 个平台要
   一屏看完，行高压到 40px 上下，输入框就是单元格本身，改完失焦即存。
   不用弹窗 —— 弹窗要点两下才看到内容，这里一次点击就能改。

   用真 <table> 而不是 .adm-row 那套 grid：这张表要支持「整组折叠、
   列宽按内容走」，table 的 table-layout:fixed + col 宽度最省事。 */
.pfa-tools { display: flex; align-items: center; gap: 10px; }
.pfa-tools .adm-q { width: 240px; flex: none; height: 32px; }

.pfa-flash { font-size: 14px; color: var(--muted); min-width: 0; white-space: nowrap; }
.pfa-flash.is-ok { color: var(--accent); }
.pfa-flash.is-bad { color: var(--danger); }

.pfa-wrap { overflow-x: auto; }
.pfa-table {
  width: 100%;
  min-width: 880px;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 14.5px;
}
.pfa-table th {
  text-align: left;
  font-weight: 500;
  font-size: 13.5px;
  letter-spacing: 0.02em;
  color: var(--muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--line-strong);
  background: var(--paper-2);
  white-space: nowrap;
}
.pfa-table td {
  padding: 5px 10px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.pfa-c-on { width: 54px; }
.pfa-c-id { width: 150px; }
.pfa-c-short { width: 78px; }
.pfa-c-maker { width: 140px; }
.pfa-c-group { width: 128px; }
.pfa-c-pre { width: 76px; }
.pfa-c-n { width: 56px; text-align: right; }
.pfa-c-ord { width: 108px; white-space: nowrap; }

.pfa-group-row td {
  padding: 12px 10px 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink-2);
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.pfa-gn { margin-left: 8px; font-weight: 400; color: var(--muted); }

/* 隐藏的行压暗，但不隐藏 —— 后台要能看见「关掉的都有哪些」 */
.pfa-row.is-off td:not(.pfa-c-on) { opacity: 0.45; }
.pfa-row.is-off td.pfa-c-on { opacity: 1; }
.pfa-row:hover td { background: var(--paper-2); }

/* 单元格即输入框：无边框，hover 才显形，避免 16 行 × 4 个框看着像表格炸了 */
.pf-in {
  width: 100%;
  height: 28px;
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: transparent;
  font: inherit;
  font-size: 14.5px;
  color: var(--ink);
}
.pf-in:hover { border-color: var(--line-strong); background: var(--surface); }
.pf-in:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface);
  box-shadow: 0 0 0 2px rgba(12, 122, 80, 0.12);
}
.pf-w6 { max-width: 78px; }
.pf-sel { height: 28px; padding: 0 4px; }

.pfa-pre { font-size: 13.5px; color: var(--muted); }

/* 开关：44×22 的滑块。原生 checkbox 保留（可键盘、可读屏），只是视觉换掉 */
.pfa-switch { position: relative; display: inline-block; width: 40px; height: 22px; cursor: pointer; }
.pfa-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.pfa-slider {
  position: absolute; inset: 0;
  background: var(--line-strong);
  border-radius: 999px;
  transition: background 0.15s;
}
.pfa-slider::before {
  content: "";
  position: absolute;
  width: 16px; height: 16px;
  left: 3px; top: 3px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(14, 26, 43, 0.3);
  transition: transform 0.15s;
}
.pfa-switch input:checked + .pfa-slider { background: var(--accent); }
.pfa-switch input:checked + .pfa-slider::before { transform: translateX(18px); }
.pfa-switch input:focus-visible + .pfa-slider { box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.25); }

.pfa-mini {
  width: 22px; height: 22px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 5px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.pfa-mini:hover { border-color: var(--accent); color: var(--accent); }

.pfa-saved {
  display: inline-block;
  width: 34px;
  font-size: 13.5px;
  color: transparent;
  transition: color 0.15s;
}
.pfa-saved.is-on { color: var(--accent); }
.pfa-saved.is-on.is-bad { color: var(--danger); }

.pfa-add { padding: 18px 20px 22px; border-top: 1px solid var(--line); background: var(--paper-2); }
.pfa-add h3 { margin: 0 0 4px; font-size: 15px; font-weight: 600; }
.pfa-add p { margin: 0 0 12px; font-size: 14px; line-height: 1.6; }
.pfa-add-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.pfa-add-row label { display: flex; flex-direction: column; gap: 4px; font-size: 13.5px; color: var(--muted); }
.pf-new {
  height: 32px;
  padding: 0 9px;
  min-width: 130px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  font: inherit;
  font-size: 14.5px;
  color: var(--ink);
}
.pf-new:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(12, 122, 80, 0.1); }
.pf-new.pf-w6 { min-width: 76px; }
.pfa-hint { margin: 10px 0 0; font-size: 14px; color: var(--danger); min-height: 16px; }

@media (max-width: 700px) {
  .pfa-tools { width: 100%; }
  .pfa-tools .adm-q { width: 100%; flex: 1; }
  .pfa-add-row label { min-width: calc(50% - 5px); }
  .pf-new { width: 100%; min-width: 0; }
}

/* 平台筛选条上的数量：没有它客户不知道点进去有几条，等于让他赌 */
.fchip-n {
  margin-left: 5px;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.fchip.on .fchip-n { color: var(--accent); }

/* ---------------------------------------------------------------- 购物车
   真 table 而不是卡片：一次要对比「原价 / 减免 / 实付」三列数字，
   卡片排下来眼睛要在每张卡里上下跳；表格能让数字纵向对齐，扫一眼就知道
   哪件贵、减了多少。行高压到 44px，八件驱动也不用来回滚。 */
/* 导航上的购物车件数。用 accent 底而不是灰色：它是「有东西等着结算」的提示，
   和旁边几个纯文字链接不是一类东西。 */
.nav-cart b {
  display: inline-block;
  min-width: 15px;
  margin-left: 5px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 21px;
  text-align: center;
  vertical-align: 1px;
}
/* display:inline-block 会盖掉 [hidden]：车空时角标必须真的消失 */
.nav-cart b[hidden] { display: none; }
/* 车里有东西时把入口点亮 —— 它不该混在旁边几个纯文字链接里 */
.nav-cart.has { color: var(--accent-2); font-weight: 600; background: var(--accent-soft); }

.cart-empty {
  padding: 48px 0;
  text-align: center;
  color: var(--muted);
}.cart-empty p { margin: 0 0 16px; font-size: 15px; }

.cart-tb {
  width: 100%;
  border-collapse: collapse;
  font-size: 14.5px;
  color: var(--ink);
}
.cart-tb th {
  text-align: left;
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--muted);
  padding: 0 10px 8px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.cart-tb td {
  padding: 12px 10px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.cart-tb tbody tr:hover { background: var(--surface-2); }
.cart-tb .num { text-align: right; white-space: nowrap; }
.cart-tb th.num { text-align: right; }
.cart-tb tfoot td {
  border-bottom: 0;
  border-top: 1px solid var(--line-strong);
  padding-top: 14px;
  font-size: 14.5px;
}
.cart-tb tfoot .num b { font-size: 16px; color: var(--ink); }

.ct-name {
  display: block;
  color: var(--ink);
  text-decoration: none;
  font-weight: 500;
}
.ct-name:hover { color: var(--accent); }
.ct-meta {
  display: block;
  margin-top: 3px;
  font-size: 13px;
  color: var(--muted);
}
.ct-plan { color: var(--muted); white-space: nowrap; }
.ct-sel {
  font: inherit;
  font-size: 14px;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  padding: 4px 6px;
  max-width: 190px;
}
.ct-sel:focus { outline: none; border-color: var(--accent); }
.ct-sel:disabled { opacity: .6; }

.ct-x {
  width: 24px;
  height: 24px;
  line-height: 1;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font-size: 16px;
}
.ct-x:hover { border-color: var(--line-strong); color: var(--danger, #a32d2d); }

.ct-note {
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--muted);
}

.ct-form { max-width: 520px; }

/* 积分抵扣。勾选框单独一块，和站点码表单分开 —— 客户在购物车里
   最先看的是「最后付多少」，这一块要显眼但不喧宾夺主。 */
.ct-points {
  max-width: 640px;
  padding: 14px 16px 4px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-2);
}
.ct-pts-pick {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 14.5px;
  color: var(--ink);
  cursor: pointer;
  line-height: 1.5;
}
.ct-pts-pick input {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  flex: none;
  accent-color: var(--accent);
}
.ct-pts-pick input:disabled { cursor: not-allowed; }
.ct-pts-pick b { color: var(--accent); font-weight: 600; }
.ct-points .ct-hint { margin: 8px 0 10px; color: var(--muted); }
.ct-points .ct-hint b { color: var(--ink); }
.ct-label {
  display: block;
  font-size: 14px;
  color: var(--muted);
  margin: 0 0 6px;
}
.ct-input {
  width: 100%;
  height: 38px;
  padding: 0 11px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink);
  font-size: 14.5px;
  font-family: inherit;
  margin-bottom: 8px;
}
.ct-input:focus { outline: 0; border-color: var(--accent); }
.ct-hint {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}
.ct-actions { display: flex; gap: 10px; align-items: center; }
.ct-msg {
  margin-top: 12px;
  font-size: 14.5px;
  color: var(--muted);
  min-height: 18px;
}
.ct-qr { margin-top: 14px; }
.ct-qr svg { width: 168px; height: 168px; display: block; }

/* ---------------------------------------------------------------- 后台价格台
   后台不追求和前台一致，追求「一眼看完全部价格、改错能马上发现」。
   所以是真表格 + 右对齐数字，价格输入框放在最后一列，扫下来就是一张价目表。 */
.pr-tb { width: 100%; border-collapse: collapse; font-size: 14.5px; }
.pr-tb th {
  text-align: left;
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--muted);
  padding: 0 10px 8px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.pr-tb td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.pr-tb tbody tr:hover { background: var(--surface-2); }
.pr-tb .num { text-align: right; white-space: nowrap; }
.pr-tb th.num { text-align: right; }

.pr-pname { display: block; color: var(--ink); text-decoration: none; }
.pr-pname:hover { color: var(--accent); }
.pr-pid {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  color: var(--muted-2);
}

/* 表头右下角的小字：直接写清这一列「能改」还是「自动算」。
   放到表格底部的说明里没人读，改价的人只盯表头。 */
.pr-th {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--muted-2);
}

/* 产品名下面那行「10950 天 / 21900 天」，以及买断格里的「含狗 ¥198」 */
.pr-term,
.pr-dog {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  color: var(--muted-2);
}

/* 三档并排后只剩一张五列表，产品列不压宽度会占掉一半屏 */
.pr-tb3 td:first-child { width: 42%; }

.pr-tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 13px;
}
.pr-tag.buy { background: var(--accent-soft); color: var(--accent-2); }
.pr-tag.term { background: var(--paper-2); color: var(--muted); }

/* 派生出来的两档：不是输入框。用虚线框 + 灰底，和左边那格能改的实线框分开，
   运营一眼就知道这两格不用填，也填不了。 */
.pr-ro {
  display: inline-block;
  min-width: 84px;
  height: 30px;
  line-height: 30px;
  padding: 0 8px;
  text-align: right;
  color: var(--ink-2);
  background: var(--paper-2);
  border: 1px dashed var(--line-strong);
  border-radius: 6px;
}
.pr-lock { font-size: 13px; color: var(--muted-2); padding: 0 6px; }
.pr-auto {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  font-style: normal;
  color: var(--muted-2);
}

.pr-in {
  width: 100px;
  height: 30px;
  padding: 0 8px;
  text-align: right;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 14.5px;
}
.pr-in:focus { outline: 0; border-color: var(--accent); }

.pr-save {
  height: 30px;
  padding: 0 12px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font-size: 14px;
  cursor: pointer;
}
.pr-save:hover { border-color: var(--accent); color: var(--accent); }
.pr-save.ok { border-color: var(--accent); color: var(--accent); }
.pr-save.bad { border-color: #a32d2d; color: #a32d2d; }
.pr-save:disabled { opacity: 0.6; cursor: default; }

.pr-hint {
  margin: 12px 0 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}

/* ---------------- 促销活动（/ops/pricing 下半张卡） ----------------
   促销开关与停止阈值放同一块：运营打开「价格」第一眼要能回答
   「现在到底打不打折、为什么没打」。拆成两页就会出现
   「促销开着但停止规则早就命中」，谁也不知道为什么客户没享受到 8 折。 */

.pm-badge {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 13px;
  white-space: nowrap;
}
.pm-badge.on { background: #e7f4ec; color: #1f6b3f; }
.pm-badge.off { background: var(--paper-2); color: var(--muted); }
.pm-badge.stop { background: #fdf1e3; color: #a05a00; }

.pm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.pm-sw {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
}
.pm-sw input {
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.pm-sw b { display: block; font-size: 14.5px; font-weight: 500; color: var(--ink); }
.pm-sw em {
  display: block;
  margin-top: 2px;
  font-style: normal;
  font-size: 13px;
  color: var(--muted-2);
}
.pm-used { font-size: 14px; color: var(--muted); white-space: nowrap; }

.pm-tb { margin: 14px 0 10px; }
.pm-in { width: 84px; }
.pm-del {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--muted-2);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.pm-del:hover { background: #fbeaea; color: #a32d2d; }

.pm-acts { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pm-msg { font-size: 14px; color: var(--muted); }

.pm-hr {
  margin: 20px 0 14px;
  border: 0;
  border-top: 1px solid var(--line);
}

.pm-stops { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 14px; }
.pm-field { display: flex; flex-direction: column; gap: 4px; font-size: 14px; color: var(--muted); }
.pm-field input {
  height: 32px;
  min-width: 150px;
  padding: 0 8px;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-size: 14.5px;
}
.pm-field input:focus { outline: 0; border-color: var(--accent); }
.pm-field em { font-style: normal; font-size: 13px; color: var(--muted-2); }

/* ---------------- 订单与发货（/ops/orders） ----------------
   一屏要同时看清「寄给谁、寄了没有、码是什么、能不能退」。
   所以每格都是「主行 + 小字副行」，不摊成更多列 —— 列一多就得左右滑。 */

.od-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.od-tb td { vertical-align: top; }
.od-tb td:first-child { white-space: nowrap; }

.od-no { display: block; font-size: 14px; }
.od-sub { display: block; font-size: 13.5px; color: var(--muted); line-height: 1.5; margin-top: 2px; }
.od-who, .od-prod { font-size: 14.5px; }
.od-back { color: var(--danger); }

.od-chip {
  display: inline-block;
  margin-top: 4px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 13px;
  white-space: nowrap;
}
.od-chip.paid, .od-chip.combo, .od-chip.dog-shipped {
  background: var(--accent-soft);
  color: var(--accent-2);
}
.od-chip.pending, .od-chip.closed, .od-chip.single, .od-chip.dog-done {
  background: var(--paper-2);
  color: var(--muted);
}
.od-chip.refunded { background: var(--danger-soft); color: var(--danger); }
.od-chip.dog-pending { background: var(--warn-soft); color: var(--warn); }

.od-dog-price { font-size: 14px; margin-right: 4px; }

/* 收件人 + 地址。发货的人照着这一格填快递单，所以字号不能再小、
   也不能被截断成一行 —— 门牌号截掉一半等于没写。 */
.od-ship {
  display: block;
  margin-top: 5px;
  max-width: 220px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-2);
  word-break: break-all;
}
.od-ship b { font-weight: 500; color: var(--ink); }
.od-ship-miss { color: var(--danger); }

.od-act { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
.od-btn {
  height: 28px;
  padding: 0 10px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font-size: 14px;
  cursor: pointer;
  white-space: nowrap;
}
.od-btn:hover { border-color: var(--accent); color: var(--accent); }
.od-btn:disabled { opacity: 0.6; cursor: default; }
.od-btn-bad:hover { border-color: var(--danger); color: var(--danger); }

/* 退款浮层里的风险提示。这一段不能做成灰色小字 ——
   离线码发出去就收不回来，是这一页唯一会造成实际损失的操作。 */
.od-warn {
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px solid rgba(156, 51, 39, 0.16);
  border-left: 3px solid var(--danger);
  border-radius: 8px;
  background: var(--danger-soft);
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink);
}
.od-warn b { display: block; margin-bottom: 6px; color: var(--danger); font-weight: 600; }
.od-warn p { margin: 0 0 6px; }
.od-warn p:last-child { margin-bottom: 0; }

@media (max-width: 720px) {
  .cart-tb { font-size: 14px; }
  .cart-tb th, .cart-tb td { padding: 10px 6px; }
  .ct-plan { display: none; }
  .cart-tb thead th:nth-child(2) { display: none; }
  .cart-tb tbody td:nth-child(2) { display: none; }
}

/* ============================================================
   展厅申请 · 三张现场照
   三个虚线格子并排，选中后直接把照片铺成格子背景 ——
   客户在展厅现场要一眼确认「我选的是不是这张」。
   ============================================================ */
.sh-photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }

.sh-photo {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; min-height: 116px; padding: 12px 8px;
  border: 1.5px dashed var(--line-strong); border-radius: 10px;
  background: var(--surface-2) center/cover no-repeat;
  cursor: pointer; text-align: center;
  transition: border-color .15s, background-color .15s;
}
.sh-photo:hover { border-color: var(--accent); background-color: var(--accent-soft); }
.sh-photo.has-img { border-style: solid; border-color: var(--accent); }
/* 选完之后把提示文字藏掉，否则字压在照片上看不清 */
.sh-photo.has-img .sh-photo-ico,
.sh-photo.has-img .sh-photo-t,
.sh-photo.has-img .sh-photo-h { visibility: hidden; }

.sh-photo-ico { font-size: 22px; line-height: 1; color: var(--accent); }
.sh-photo-t { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.sh-photo-h { font-size: 13.5px; color: var(--muted); }

.sh-tip { margin: 8px 0 0; font-size: 14.5px; color: var(--muted); line-height: 1.6; }

@media (max-width: 640px) {
  .sh-photos { grid-template-columns: 1fr; }
  .sh-photo { min-height: 96px; flex-direction: row; gap: 8px; justify-content: flex-start; }
}

/* ============================================================
   积分 · 账号页侧栏
   ============================================================ */
.acct-side-h {
  margin: 18px 0 10px; padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 14.5px; font-weight: 600; color: var(--muted); letter-spacing: .04em;
}

.pts-box { font-size: 14.5px; }
.pts-num {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 30px; font-weight: 700; line-height: 1.1; color: var(--accent-2);
}
.pts-num em { margin-left: 3px; font-size: 14.5px; font-style: normal; font-weight: 500; color: var(--muted); }
.pts-sub { margin-top: 4px; font-size: 14.5px; color: var(--muted); }
.pts-sub b { color: var(--ink); }

.pts-k { display: block; margin: 14px 0 5px; font-size: 14px; color: var(--muted); }
.pts-code {
  padding: 9px 11px; border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface-2); font-size: 17px; letter-spacing: .18em; color: var(--ink);
}
.pts-copy { margin-top: 8px; width: 100%; }
.pts-tip { margin: 10px 0 0; font-size: 14px; line-height: 1.65; color: var(--muted); }
.pts-tip b { color: var(--ink); }

.pts-log { margin: 12px 0 0; padding: 10px 0 0; border-top: 1px solid var(--line); list-style: none; }
.pts-log li { display: flex; justify-content: space-between; gap: 8px; padding: 4px 0; font-size: 14px; }
.pts-log .is-plus { color: var(--accent); font-weight: 600; }
.pts-log .is-minus { color: var(--muted); }
.pts-log-t { color: var(--muted); text-align: right; }

/* ============================================================
   公司管理
   ============================================================ */
.co-wrap { padding: 26px 0 64px; }

.co-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; margin-bottom: 18px;
}
.co-title { margin: 0; font-size: 24px; }
.co-sub { margin: 6px 0 0; max-width: 62ch; font-size: 14.5px; line-height: 1.7; color: var(--muted); }
.co-sub2 { font-size: 14.5px; }

.co-panel { margin-bottom: 16px; }
.co-panel .panel-head h2 { margin: 0; font-size: 17px; }

.co-badge {
  display: inline-block; margin-left: 8px; padding: 2px 8px; border-radius: 999px;
  font-size: 13.5px; font-weight: 600;
}
.co-badge.is-ok { background: var(--accent-soft); color: var(--accent-2); }

.co-role { font-size: 14px; }

.co-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px; margin-top: 12px;
}
.co-facts > div {
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 9px;
  background: var(--surface-2);
}
.co-facts span { display: block; font-size: 13.5px; color: var(--muted); }
.co-facts b { display: block; margin-top: 3px; font-size: 15px; color: var(--ink); }

.co-members { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.co-member {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 4px; border-bottom: 1px solid var(--line);
}
.co-member:last-child { border-bottom: 0; }

.co-avatar {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-2);
  font-size: 15px; font-weight: 700; text-transform: uppercase;
}
.co-mbody { flex: 1; min-width: 0; }
.co-mname { font-size: 15px; font-weight: 600; color: var(--ink); }
.co-mmeta { font-size: 13.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.co-tag {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-2);
  font-size: 13.5px; font-weight: 600; vertical-align: 1px;
}
.co-tag-me { background: var(--paper-2); color: var(--muted); }

.co-mact { flex: none; display: flex; gap: 6px; }
.co-mini {
  padding: 4px 9px; border: 1px solid var(--line-strong); border-radius: 6px;
  background: var(--surface); color: var(--ink-2); font-size: 13.5px; cursor: pointer;
}
.co-mini:hover { border-color: var(--accent); color: var(--accent-2); }
.co-mini.is-bad:hover { border-color: var(--danger); color: var(--danger); }

/* 待批准加入。和成员行同构，但整块铺一层浅绿底：
   这些人还没有任何项目权限，一眼要能看出「还没进公司」。 */
.co-joins {
  margin: 12px 0 6px; padding: 11px 13px;
  border: 1px solid var(--accent-line); border-radius: 10px;
  background: var(--accent-soft);
}
.co-joins-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 5px; }
.co-joins-head b { font-size: 14.5px; color: var(--accent-2); }
.co-joins-head .muted { font-size: 13.5px; }
/* 客户填的是简称时必须把他原话摊出来 —— 只显示标准名，主管理员会以为
   对方精确选中了本公司，点「同意」前少了一个判断依据。 */
.co-claim {
  margin-top: 4px;
  font-size: 13px;
  color: var(--warn);
  background: var(--warn-soft);
  border-radius: 5px;
  padding: 2px 7px;
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.co-join { display: flex; align-items: center; gap: 11px; padding: 9px 0 1px; }
.co-join + .co-join { margin-top: 8px; border-top: 1px solid rgba(12, 122, 80, 0.14); padding-top: 11px; }
.co-join .co-avatar { background: var(--surface); }
@media (max-width: 640px) {
  .co-join { flex-wrap: wrap; }
  .co-join .co-mact { width: 100%; padding-left: 43px; }
}

.co-add { display: flex; align-items: center; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.co-add input {
  flex: 1; min-width: 220px; padding: 8px 11px;
  border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface); color: var(--ink); font-size: 14.5px;
}
.co-add input:focus { outline: none; border-color: var(--accent); }
.co-msg { font-size: 14.5px; color: var(--muted); }
.co-msg.is-bad { color: var(--danger); }

.co-tip { margin: 10px 0 0; font-size: 14px; line-height: 1.7; color: var(--muted); }

/* 项目分配矩阵：项目名一列（弹性），成员每人一列（固定宽度）。
   不用 grid 是因为成员数量是变量，grid-template-columns 得在模板里拼。 */
.co-grant { margin-top: 10px; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.co-grow {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 12px; border-bottom: 1px solid var(--line);
  font-size: 14.5px;
}
.co-grow:last-child { border-bottom: 0; }
.co-ghead { background: var(--surface-2); font-size: 13.5px; color: var(--muted); }
.co-gsite { flex: 1; min-width: 0; }
.co-gsite b { display: block; font-size: 14.5px; color: var(--ink); }
.co-gsite .mono { font-size: 13px; color: var(--muted); }
.co-gby { margin-left: 8px; font-size: 13px; color: var(--muted-2); }
.co-gcol { flex: none; width: 52px; text-align: center; }

.co-check { display: inline-flex; cursor: pointer; }
.co-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.co-check span {
  display: block; width: 18px; height: 18px;
  border: 1.5px solid var(--line-strong); border-radius: 5px;
  background: var(--surface); transition: all .12s;
}
.co-check input:checked + span {
  border-color: var(--accent); background: var(--accent);
  /* 对勾用两个边框拼出来，不引图标字体 */
  position: relative;
}
.co-check input:checked + span::after {
  content: ""; position: absolute; left: 5px; top: 1.5px;
  width: 4px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.co-check input:focus-visible + span { outline: 2px solid var(--accent-line); outline-offset: 2px; }

.co-center { text-align: center; padding: 34px 20px; }
.co-big { font-size: 20px; font-weight: 700; color: var(--ink); }
.co-big.is-bad { color: var(--danger); }
.co-reason {
  display: inline-block; margin: 12px auto 0; padding: 9px 14px;
  border-radius: 9px; background: var(--warn-soft); color: var(--warn);
  font-size: 14.5px; text-align: left; max-width: 60ch;
}

.co-form { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 10px; }
.co-field { display: flex; flex-direction: column; gap: 5px; }
.co-field-wide { grid-column: 1 / -1; }
.co-field span { font-size: 14px; color: var(--muted); }
.co-field input {
  padding: 9px 11px; border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface); color: var(--ink); font-size: 15px;
}
.co-field input:focus { outline: none; border-color: var(--accent); }
.co-form-act { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px; }

/* 「加入已有公司」的候选行。不做浮层：这一页的输入框在页面中间，
   浮层一开就压住下面的按钮；平铺成一行，点哪个都直接填进去。 */
.co-sug {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: -2px;
  padding: 9px 11px;
  border: 1px dashed var(--line-strong);
  border-radius: 8px;
  background: var(--bg);
}
.co-sug-lead { font-size: 13.5px; color: var(--muted); }
.co-sug-item {
  padding: 4px 10px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
}
.co-sug-item:hover { border-color: var(--accent); color: var(--accent); }

@media (max-width: 720px) {
  .co-form { grid-template-columns: 1fr; }
  .co-gcol { width: 42px; }
  .co-head { flex-direction: column; }
}

/* ============================================================
   厂商登记（/vendor-signup、/account/vendor、/ops/vendors）

   这一支的目的只有一个：让品牌方把「什么设备、什么协议、找谁」
   一次说清。所以表单是两列（成对的字段并排，扫读快），
   右边常驻三张说明卡回答「之后会发生什么 / 没有文档行不行 / 要不要钱」。
   ============================================================ */

/* 页头：左侧标题 + 右侧动作。用 flex 而不是 .page-head 的两列网格 ——
   登记页右侧没有 KPI，套网格会空出 260px 的白。 */
.vs-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.vs-head .ph-main { flex: 1 1 520px; min-width: 0; }
.vs-head-act { flex: 0 0 auto; padding-bottom: 4px; display: flex; gap: 8px; flex-wrap: wrap; }

/* 页头右侧不是按钮，是一句「走错门了？换另一类」的文字链接。
   做成按钮会和下面「提交」抢注意力，而换类型是次要动作。 */
.vs-switch {
  font-size: 14.5px;
  color: var(--accent-2);
  text-decoration: none;
  border-bottom: 1px solid var(--accent-line);
  padding-bottom: 2px;
  white-space: nowrap;
}
.vs-switch:hover { border-bottom-color: var(--accent-2); }

/* 身份说明条。两种登记最容易走错的就是「我这种身份能不能填」：
   个人看到「公司全称 *」会以为走错门，品牌方看到「个人也能报」又会犯嘀咕。
   整宽一条写在表单上方，比塞进右侧小字有效。 */
.vs-notice {
  margin: -6px 0 22px;
  padding: 12px 16px;
  border: 1px solid var(--accent-line);
  border-left: 3px solid var(--accent-2);
  border-radius: 8px;
  background: var(--accent-soft);
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--ink-2);
  text-wrap: pretty;
}
.vs-notice b { color: var(--ink); font-weight: 600; }

.vs-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
  gap: 26px;
  align-items: start;
  margin-bottom: 60px;
}
.vs-body { padding: 20px 22px 22px; }

/* 成对字段并排。竖间距交给 .field 自己的 margin-bottom，
   这里只管横向 —— 用 gap 会在每组之间再叠一层，节奏就乱了。 */
.vs-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 18px; }
.vs-req { color: var(--danger); font-size: 14px; font-weight: 600; margin-left: 2px; }
/* 切到「个人」主体时公司不再是必填，星号要真的消失。
   .vs-req 没写 display，靠 [hidden] 本来也能盖住，这里写死是为了以后改样式不踩坑。 */
.vs-req[hidden] { display: none; }

/* 主体类型：两张并排的卡片，不是下拉。
   选「个人」和选「公司」看到的下文字段不一样，用 radio 卡片能当场看见差别；
   下拉要展开才知道有第二个选项，很多人根本不会点。 */
.vs-entity-field { margin-bottom: 18px; }
.vs-entity { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.vs-entity-opt {
  text-align: left;
  padding: 12px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--surface);
  cursor: pointer;
  font: inherit;
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
}
.vs-entity-opt b { display: block; font-size: 15px; font-weight: 600; color: var(--ink); margin-bottom: 3px; }
.vs-entity-opt span { display: block; font-size: 13.5px; color: var(--muted); line-height: 1.6; text-wrap: pretty; }
.vs-entity-opt:hover { border-color: var(--accent-line); }
.vs-entity-opt.is-on {
  border-color: var(--accent-2);
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-2);
}
.vs-entity-opt.is-on b { color: var(--accent-2); }
.vs-entity-opt:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

/* 从登录页绕回来时提示「内容还在」。没有这条，客户会以为表单被清空了，
   再把型号打一遍 —— 一半人打到一半就放弃了。 */
.vs-resume {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
  padding: 9px 12px;
  border-radius: 8px;
  background: var(--paper-2);
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.6;
}
.vs-resume[hidden] { display: none; }
.vs-resume button {
  flex: 0 0 auto;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 14px;
  color: var(--muted);
  text-decoration: underline;
  cursor: pointer;
}

/* 提交按钮上方那句「会弹登录选择」/「已登录，会挂你账号下」——
   提前说，弹窗才不突然。 */
.vs-who { margin: 4px 0 14px; font-size: 14px; color: var(--muted); line-height: 1.7; text-wrap: pretty; }
.vs-who b { color: var(--ink-2); font-weight: 600; }

/* 提交前的身份选择弹窗 */
.vs-auth-modal { max-width: 468px; }
.vs-auth-pick { display: grid; gap: 10px; }
.vs-auth-opt {
  display: block;
  padding: 14px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 11px;
  background: var(--surface);
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s;
}
.vs-auth-opt b { display: block; font-size: 15px; font-weight: 600; color: var(--ink); }
.vs-auth-opt span { display: block; margin-top: 4px; font-size: 14px; color: var(--muted); line-height: 1.65; text-wrap: pretty; }
.vs-auth-opt em { display: inline-block; margin-top: 8px; font-style: normal; font-size: 14px; font-weight: 600; color: var(--accent-2); }
.vs-auth-opt:hover { border-color: var(--accent-2); background: var(--accent-soft); }
/* 老用户最多，把「登录」这条常亮，不用眼睛再扫一遍 */
.vs-auth-opt:first-child { border-color: var(--accent-2); }

.vs-auth-skip {
  display: block;
  width: 100%;
  text-align: left;
  padding: 12px 16px;
  border: 1px dashed var(--line-strong);
  border-radius: 11px;
  background: none;
  font: inherit;
  cursor: pointer;
}
.vs-auth-skip b { display: block; font-size: 15px; font-weight: 600; color: var(--ink-2); }
.vs-auth-skip span { display: block; margin-top: 3px; font-size: 13.5px; color: var(--muted); line-height: 1.6; text-wrap: pretty; }
.vs-auth-skip:hover { border-color: var(--muted-2); background: var(--surface-2); }
.vs-auth-note { margin-top: 14px; font-size: 13.5px; color: var(--muted); line-height: 1.7; text-wrap: pretty; }

.vs-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding-top: 16px;
  border-top: 1px dashed var(--line);
}
.vs-legal { font-size: 13.5px; color: var(--muted); line-height: 1.65; max-width: 430px; }

/* 提交成功：把表单整块换掉，只留编号和下一步。
   客户此刻最想知道的是「我这事有人接了吗」，不是再看一遍表单。 */
.vs-done { padding: 6px 0 4px; }
.vs-done-mark {
  width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-2);
  font-size: 19px; margin-bottom: 14px;
}
.vs-done h2 { font-family: var(--serif); font-size: 21px; font-weight: 600; margin-bottom: 8px; }
.vs-done-msg { font-size: 15px; color: var(--ink-2); line-height: 1.75; margin-bottom: 16px; }
.vs-done-act { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }
.vs-done-note { margin-top: 12px; font-size: 14px; color: var(--muted); line-height: 1.7; max-width: 470px; text-wrap: pretty; }

/* 步骤条：左侧编号是圆形徽标，正文左对齐。用 ol 而不是 div，
   顺序对读者是有意义的，不是装饰。 */
.vs-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.vs-steps li { display: flex; gap: 10px; align-items: flex-start; }
.vs-steps b {
  flex: 0 0 auto;
  width: 20px; height: 20px; margin-top: 1px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--paper-2); color: var(--ink-2);
  font-family: var(--mono); font-size: 13px; font-weight: 500;
}
.vs-steps span { font-size: 14.5px; color: var(--muted); line-height: 1.7; text-wrap: pretty; }
.vs-steps strong { color: var(--ink); font-weight: 600; }
.vs-steps-done b { background: var(--accent-soft); color: var(--accent-2); }

.vs-side { display: grid; gap: 16px; }
/* 表单比右栏长一倍。滚到「还有什么要说明的」时，右边那三张说明卡
   如果早滚没了，等于白写 —— 贴住顶部让它跟着走。 */
@media (min-width: 1001px) {
  .vs-side { position: sticky; top: 18px; }
}
.vs-side-card a { color: var(--accent-2); text-decoration: none; border-bottom: 1px solid var(--accent-line); }
.vs-side-card b { color: var(--ink-2); font-weight: 600; }
.vs-side-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 18px 18px 16px;
}
.vs-side-card h2 { font-family: var(--serif); font-size: 16.5px; font-weight: 600; margin-bottom: 12px; }
.vs-side-quiet { background: var(--surface-2); }
.vs-side-quiet p { font-size: 14.5px; color: var(--muted); line-height: 1.75; }

/* ---- 我的登记（/account/vendor） */
.vreq-list { display: grid; gap: 14px; margin-bottom: 36px; }
.vreq-card {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
}
.vreq-main { min-width: 0; }
.vreq-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.vreq-brand { font-family: var(--serif); font-size: 17px; font-weight: 600; }
.vreq-no { font-size: 13.5px; color: var(--muted-2); }
.vreq-company { font-size: 14.5px; color: var(--ink-2); margin-top: 4px; }
.vreq-meta { font-size: 13.5px; color: var(--muted); margin-top: 6px; }
.vreq-dot { margin: 0 5px; color: var(--muted-2); }
/* 日期和「提交」不能被拆到两行 —— 手机上断成「2026-11-08 提」+「交」很难看 */
.vreq-when { white-space: nowrap; }
/* 进度提示用翠底 —— 这一行是客户来这页唯一要看的东西，别让它跟正文混在一起 */
.vreq-hint {
  display: inline-block;
  margin-top: 10px;
  padding: 5px 10px;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent-2);
  font-size: 14.5px;
  line-height: 1.6;
}
.vreq-go { flex: 0 0 auto; font-size: 14.5px; color: var(--accent-2); text-decoration: none; white-space: nowrap; }
.vreq-go:hover { text-decoration: underline; }

.vs-empty {
  text-align: center;
  padding: 46px 20px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  margin-bottom: 32px;
}
.vs-empty h2 { font-family: var(--serif); font-size: 20px; font-weight: 600; margin-bottom: 8px; }
.vs-empty p { font-size: 14.5px; color: var(--muted); line-height: 1.75; max-width: 460px; margin: 0 auto 18px; }
.vs-empty-act { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.vs-foot-note { font-size: 14px; color: var(--muted); line-height: 1.7; margin-bottom: 40px; }

/* 登记类型标签。品牌登记给一点绿 —— 那是我们最想要的线索（一签一个品牌），
   驱动登记保持中性灰，别让每个卡片都在抢眼睛。 */
.vreq-kind, .vst-kind {
  font-size: 13.5px;
  letter-spacing: 0.03em;
  color: var(--muted);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 1px 7px;
  white-space: nowrap;
}
.vreq-kind.brand, .vst-kind.brand {
  color: var(--accent-2);
  border-color: var(--accent-line);
  background: var(--accent-soft);
}
.vreq-sub { font-size: 13px; color: var(--muted); margin-left: 6px; }
/* 后台「主体」列的个人标记。它不是一个状态，别用状态色。 */
.vst-person {
  font-size: 13.5px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--ink-2);
  white-space: nowrap;
}

/* ---- 状态标签：两个页面共用，颜色只按「离成交多远」分三档 */
.vreq-chip, .vst-chip {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 13px;
  line-height: 21px;
  white-space: nowrap;
}
.vreq-chip.open, .vst-chip.open { background: var(--warn-soft); color: var(--warn); }
.vreq-chip.contacted, .vst-chip.contacted { background: var(--dawn-soft); color: #1f4f7a; }
.vreq-chip.scheduled, .vst-chip.scheduled { background: var(--paper-2); color: var(--ink-2); }
.vreq-chip.developed, .vst-chip.developed { background: var(--accent-soft); color: var(--accent-2); }
.vreq-chip.rejected, .vst-chip.rejected { background: var(--danger-soft); color: var(--danger); }

/* ---- 后台表格里的几格 */
.vst-models { font-size: 14.5px; color: var(--ink); word-break: break-word; }
/* 协议链接必须自成一行 —— 和型号挤在一行时，「DT82TN / DT52 / DT82TV 协议文档 ↗」
   看起来像型号的一部分，运营会漏掉那张文档。 */
.vst-link { display: block; margin-top: 3px; color: var(--accent-2); text-decoration: none; border-bottom: 1px solid var(--accent-line); width: fit-content; }
.vst-follow { color: var(--muted); line-height: 1.6; }
.vst-act { margin-top: 8px; }
/* 「已送 XX 30 年」——用绿色，一眼区分于跟进记录（灰）。 */
.vst-gifted { color: var(--accent-2); line-height: 1.6; margin-top: 4px; }
.vst-gift { margin-top: 8px; margin-left: 6px; }
.field-hint.warn { color: var(--danger); }
/* 筛选标签上的条数：用徽标而不是裸数字，否则「待处理 1 已联系 1」读成一句话 */
.adm-tab b {
  display: inline-block;
  margin-left: 5px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 19px;
}
.adm-tab.on b { background: var(--accent-soft); color: var(--accent-2); }

@media (max-width: 1000px) {
  .vs-grid { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .vs-side { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  .vs-row { grid-template-columns: minmax(0, 1fr); }
  .vs-body { padding: 16px 15px 18px; }
  .vs-side { grid-template-columns: minmax(0, 1fr); }
  .vs-actions .btn { width: 100%; }
  .vreq-card { flex-direction: column; align-items: flex-start; gap: 12px; }
  .vs-head-act, .vs-head-act .btn { width: 100%; }
  /* 主体两张卡在窄屏并排会把说明挤成三行，改成上下两张 */
  .vs-entity { grid-template-columns: minmax(0, 1fr); }
  .vs-notice { margin-top: -12px; padding: 10px 13px; }
  .vs-auth-modal .modal-foot .btn { width: 100%; }
}
/* 390px 下标题会断成「…驱动我们 / 写」，一个字单独占一行。
   收字号 + balance 让它断在逗号处。 */
@media (max-width: 560px) {
  .vs-head h1 { font-size: 24px; text-wrap: balance; }
}

/* ---------------------------------------------------------------- 详情页动作条
   客户找了两轮「编辑项目」都没找到：原来那颗按钮挤在站点码右边，
   长得和大一号的「未授权」徽标是同一类东西。现在单独占一行，
   和顶上的「绑定站点」同一种描边按钮，右边一行小字说明这两颗按钮能干什么。

   分享也放在这里 —— 它和编辑是同一层的动作：都是对「这个项目」做什么，
   不是对某个驱动产品做什么。 */

.detail-tools {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 18px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
.detail-tool {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-2);
  font-weight: 500;
}
.detail-tool:hover { border-color: var(--accent); color: var(--accent); background: var(--surface); }
.detail-tool svg { width: 15px; height: 15px; flex: none; }
.detail-tools-tip { font-size: 13.5px; color: var(--muted); margin-left: 2px; }
.detail-ro {
  font-size: 14.5px;
  color: var(--accent-2);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  padding: 4px 12px;
}

/* 项目名后面那支笔：名字本身就是最可能被点的地方 */
.detail-pen {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 6px;
  background: none;
  color: var(--muted-2);
  cursor: pointer;
}
.detail-pen:hover { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.detail-pen svg { width: 13px; height: 13px; }

/* ---------------------------------------------------------------- 分享弹窗 */

.share-tabs {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--paper-2);
  border-radius: 10px;
  margin-bottom: 16px;
}
.share-tab {
  flex: 1;
  height: 34px;
  border: 0;
  border-radius: 7px;
  background: none;
  color: var(--muted);
  font-size: 14.5px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
}
.share-tab:hover { color: var(--ink-2); }
.share-tab.is-on {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}

.share-hint {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--muted);
  margin: 0 0 14px;
}
.share-hint b { color: var(--ink-2); font-weight: 600; }

.share-people { display: grid; gap: 6px; max-height: 216px; overflow: auto; margin-bottom: 4px; }
.share-person {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--surface);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.share-person:hover { border-color: var(--line-strong); background: var(--surface-2); }
.share-person.is-on { border-color: var(--accent); background: var(--accent-soft); }
.share-person .sp-avatar {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 50%;
  background: var(--paper-2);
  color: var(--ink-2);
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.share-person.is-on .sp-avatar { background: var(--accent); color: #fff; }
.share-person .sp-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.share-person .sp-body b { font-size: 14.5px; font-weight: 500; color: var(--ink); }
.share-person .sp-body i { font-style: normal; font-size: 13px; color: var(--muted); }
.share-person .sp-check {
  margin-left: auto;
  width: 15px;
  height: 15px;
  flex: none;
  border: 1.5px solid var(--line-strong);
  border-radius: 50%;
}
.share-person.is-on .sp-check { border-color: var(--accent); background: var(--accent); box-shadow: inset 0 0 0 3px var(--surface); }

.share-none {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--muted);
  padding: 12px 13px;
  border: 1px dashed var(--line-strong);
  border-radius: 9px;
  margin-bottom: 4px;
}

.share-hours { display: flex; gap: 6px; }
.share-hour {
  flex: 1;
  height: 38px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 14.5px;
  font-family: inherit;
  cursor: pointer;
}
.share-hour:hover { border-color: var(--accent); color: var(--accent); }
.share-hour.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-2);
  font-weight: 600;
}

/* 同事分享按天：三个常用天数 + 自己填一个数。
   预设不铺满整行 —— 铺满了右边那个「___ 天」输入框会被挤到下一行，
   客户以为只能在这三档里选。 */
.share-hours.is-days { align-items: center; flex-wrap: wrap; }
.share-hours.is-days .share-hour {
  flex: 0 0 auto;
  min-width: 62px;
  padding: 0 14px;
}
.share-days-custom {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
}
.share-days-custom input {
  width: 74px;
  height: 38px;
  padding: 0 9px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font-size: 14.5px;
  font-family: inherit;
  text-align: center;
  -moz-appearance: textfield;
}
.share-days-custom input::-webkit-outer-spin-button,
.share-days-custom input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.share-days-custom input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.share-days-custom > span { font-size: 14.5px; color: var(--muted); }

@media (max-width: 560px) {
  /* 手机上预设已经占满一行，输入框换到下一行。宽度给死、不要 flex:1 ——
     拉满后「天」会跑到屏幕最右边，看着像和输入框没关系。 */
  .share-days-custom { margin-left: 0; width: 100%; }
  .share-days-custom input { flex: none; width: 96px; }
}

.share-link {
  margin-top: 4px;
  padding: 12px 13px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  border-radius: 9px;
}
.share-link-head { font-size: 14.5px; font-weight: 600; color: var(--accent-2); margin-bottom: 8px; }
.share-link-row { display: flex; gap: 8px; }
.share-link-row input {
  flex: 1;
  min-width: 0;
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface);
  font-size: 14px;
  color: var(--ink);
}
.share-link-row .btn { flex: none; }

.share-list { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 12px; }
.share-list-head { font-size: 13.5px; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 8px; }
.share-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
}
.share-item:last-child { border-bottom: 0; }
.share-item.is-off { opacity: 0.55; }
.share-item .sh-kind {
  flex: none;
  font-size: 13.5px;
  color: var(--ink-2);
  background: var(--paper-2);
  border-radius: 4px;
  padding: 2px 6px;
}
.share-item .sh-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.share-item .sh-body b { font-size: 14.5px; font-weight: 500; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.share-item .sh-body i { font-style: normal; font-size: 13px; color: var(--muted); }
.share-item .co-mini { margin-left: auto; flex: none; }

/* ---------------------------------------------------------------- 分享页（对外）
   这一页没有导航、没有账号信息：拿到链接的人可能根本不是客户。
   一屏之内说清三件事 —— 这是哪个项目、还剩多久、授权码怎么用。 */

.sx-body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  min-height: 100vh;
}
.sx-top { border-bottom: 1px solid var(--line); background: var(--surface); }
.sx-top-in {
  max-width: 860px;
  margin: 0 auto;
  padding: 14px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.sx-brand { display: inline-flex; align-items: center; gap: 8px; }
.sx-brand svg { width: 24px; height: 24px; border-radius: 5px; }
.sx-brand b { font-size: 15px; letter-spacing: 0.06em; }
.sx-brand i { font-style: normal; font-size: 14px; color: var(--muted); margin-left: -2px; }
.sx-tag {
  font-size: 13px;
  color: var(--accent-2);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  padding: 3px 10px;
}

.sx-wrap { max-width: 860px; margin: 0 auto; padding: 26px 24px 48px; }
.sx-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 22px 24px;
  box-shadow: var(--shadow-sm);
}
.sx-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.sx-head h1 { font-family: var(--serif); font-size: 23px; font-weight: 600; margin: 0 0 5px; }
.sx-head p { margin: 0; font-size: 14.5px; color: var(--muted); }
.sx-left {
  flex: none;
  font-size: 14px;
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px solid rgba(143, 90, 18, 0.18);
  border-radius: 999px;
  padding: 4px 12px;
  font-variant-numeric: tabular-nums;
}
.sx-left.is-dead { color: var(--danger); background: var(--danger-soft); border-color: rgba(156, 51, 39, 0.16); }
.sx-note { margin: 16px 0 18px; }

.sx-products { display: grid; gap: 14px; }
.sx-prod { border: 1px solid var(--line); border-radius: var(--radius); padding: 15px 16px; background: var(--surface); }
.sx-prod.is-expired { background: var(--surface-2); }
.sx-prod-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.sx-prod-name { font-size: 15.5px; font-weight: 600; color: var(--ink); }
.sx-prod-meta { font-size: 13.5px; color: var(--muted); margin-top: 3px; }
.sx-prod-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 13px 0 0; }
.sx-prod-grid > div { background: var(--surface-2); border-radius: 7px; padding: 8px 10px; }
.sx-prod-grid span { display: block; font-size: 13px; color: var(--muted); }
.sx-prod-grid b { font-size: 14.5px; font-family: var(--mono); font-weight: 500; }

.sx-code { margin-top: 12px; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.sx-code-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 10px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
  color: var(--muted);
}
.sx-code-act { display: flex; gap: 6px; }
.sx-code-body {
  display: block;
  padding: 11px 12px;
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink-2);
  word-break: break-all;
  background: var(--surface);
  user-select: all;
}
.sx-how { margin: 10px 0 0; font-size: 14px; line-height: 1.7; color: var(--muted); }

/* 安装包一行：现场的人先下包、再贴码，别把它塞进授权码右边那排按钮里，
   手机上三个按钮并排会换行成两层，看着像两件事。 */
.sx-pkg {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px 10px; flex-wrap: wrap;
  margin-top: 10px; padding: 8px 10px;
  border: 1px dashed var(--line); border-radius: 8px;
  font-size: 14px; color: var(--muted);
}
.sx-pkg b { font-family: var(--mono); font-weight: 500; color: var(--ink-2); }
.sx-pkg-act { display: flex; gap: 6px; flex-wrap: wrap; }

.sx-empty { padding: 26px 4px 8px; text-align: center; }
.sx-empty b { font-size: 15px; color: var(--ink-2); }
.sx-empty p { margin: 6px 0 0; font-size: 14.5px; color: var(--muted); }

.sx-foot { margin: 18px 2px 0; font-size: 14px; line-height: 1.7; color: var(--muted); text-align: center; }

.sx-dead { text-align: center; padding: 44px 24px; }
.sx-dead-mark { color: var(--muted-2); margin-bottom: 12px; }
.sx-dead-mark svg { width: 34px; height: 34px; }
.sx-dead h1 { font-family: var(--serif); font-size: 21px; margin: 0 0 8px; }
.sx-dead p { margin: 0; font-size: 14.5px; line-height: 1.8; color: var(--muted); }

@media (max-width: 560px) {
  .sx-top-in { padding: 12px 16px; }
  .sx-wrap { padding: 18px 14px 36px; }
  .sx-card { padding: 17px 16px; }
  .sx-head h1 { font-size: 20px; }
  /* 授权码整行 202 字符，手机上只有一个字符宽的列会断成三行；
     等宽字号再压一点，仍然能整段选中复制 */
  .sx-code-body { font-size: 13.5px; }
  .detail-tools { padding: 9px 14px; }
  .detail-tools-tip { display: none; }
}

/* ============================================================
   认证会员 / 优惠券（2026-11-08）
   徽标用等级自己的颜色，但底色一律浅色 —— 深色块挂在导航里太抢眼。
   ============================================================ */

.nav-seal {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px; border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--surface); font-size: 13.5px; font-weight: 700;
  color: var(--ink-2); white-space: nowrap; text-decoration: none;
}
.nav-seal span { color: var(--seal, var(--accent)); font-size: 14.5px; letter-spacing: -1px; }
.nav-seal:hover { border-color: var(--accent); color: var(--accent-2); }
.nav-seal-off { border-style: dashed; color: var(--accent-2); }

.mem-seal-inline {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface-2); font-size: 13.5px; font-weight: 700;
  color: var(--ink-2); text-decoration: none; white-space: nowrap;
}
.mem-seal-inline span { color: var(--seal, var(--accent)); font-size: 14.5px; }
.acct-idline { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 8px 0 12px; }
.acct-idline > b { font-size: 15px; }
.acct-idline > span { font-size: 14px; color: var(--muted); }

.mem-wrap { padding-bottom: 56px; }
/* 认证礼包：两档并列的权益卡。券是客户最关心的，放在认证表单上面。
   2026-11-09：企业 ¥2000（19 张）/ 个人 ¥1000（11 张），长期有效。 */
.mem-gift {
  margin: 0 0 18px; padding: 18px 22px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface);
}
.mg-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.mg-head h2 { margin: 0; font-size: 17px; }
.mg-sub { margin-left: 8px; font-size: 13.5px; color: var(--muted); }
.mg-total { font-size: 14px; font-weight: 600; color: var(--accent-2); }
.mg-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.mg-card {
  padding: 12px 14px; border: 1px dashed var(--line-strong);
  border-radius: 10px; background: var(--surface-2);
}
.mg-card.is-on { border-style: solid; border-color: var(--accent-line); background: var(--accent-soft); }
.mg-ent { font-size: 14px; color: var(--muted); }
.mg-val { font-size: 26px; font-weight: 700; line-height: 1.25; color: var(--ink); }
.mg-val small { margin-left: 6px; font-size: 14px; font-weight: 500; color: var(--muted); }
.mg-parts { font-size: 13.5px; color: var(--ink-2); }
.mg-state { margin-top: 6px; font-size: 13.5px; color: var(--accent-2); }
.mg-card:not(.is-on) .mg-state { color: var(--muted); }
.mg-hint { margin: 12px 0 0; font-size: 13.5px; line-height: 1.75; color: var(--muted); }

.mem-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 18px; align-items: start; }
.mem-panel { padding: 20px 22px; }
.mem-state {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px; margin: 4px 0 18px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface-2);
}
.mem-state.is-ok { border-color: var(--accent-line); background: var(--accent-soft); }
.mem-state.is-wait { border-color: #e6d6ae; background: var(--warn-soft); }
.mem-seal {
  flex: 0 0 42px; height: 42px; display: grid; place-items: center;
  border-radius: 12px; background: var(--surface); border: 1px solid var(--line-strong);
  color: var(--seal, var(--muted)); font-size: 17px; letter-spacing: -2px;
}
.mem-state-txt h3 { margin: 0 0 4px; font-size: 17px; }
.mem-state-txt h3 small { font-size: 13px; font-weight: 500; color: var(--muted); margin-left: 6px; }
.mem-state-txt p { margin: 0; font-size: 14.5px; line-height: 1.7; color: var(--ink-2); }
.mem-form .field { margin-bottom: 13px; }
.mem-form textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--line-strong);
  border-radius: 8px; font: inherit; font-size: 14.5px; resize: vertical;
}
.mem-acts { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.mem-msg, .lv-msg, .cpn-msg { font-size: 14.5px; color: var(--accent-2); }
.mem-lv-group { margin: 8px 0 16px; }
.mem-lv-group h3 { margin: 0 0 8px; font-size: 14px; letter-spacing: .08em; color: var(--muted); }
.mem-lv-list { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.mem-lv {
  display: flex; align-items: center; gap: 7px; padding: 9px 10px;
  border: 1px solid var(--line); border-radius: 9px; background: var(--surface);
  font-size: 14.5px;
}
.mem-lv.on { border-color: var(--accent); background: var(--accent-soft); }
.mem-lv-badge { font-size: 15px; letter-spacing: -2px; }
.mem-lv-name { flex: 1; }
.mem-lv b { color: var(--accent-2); }
.mem-hint { margin: 4px 0 0; font-size: 14px; line-height: 1.75; color: var(--muted); }
.mem-cpn-head { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); }
.mem-cpn-list { display: grid; gap: 8px; }
.mem-cpn {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 10px 12px; border: 1px dashed var(--line-strong);
  border-radius: 9px; background: var(--surface-2);
}
.mem-cpn.dim { opacity: .55; }
.mem-cpn-main b { display: block; font-size: 14.5px; }
.mem-cpn-main span { font-size: 13px; color: var(--muted); }
.mem-cpn-side { text-align: right; }
.mem-cpn-side b { display: block; color: var(--accent-2); }
.mem-cpn-side span { font-size: 13px; color: var(--muted); }
.mem-empty { padding: 18px 4px; font-size: 14.5px; color: var(--muted); }

/* 购物车：把三层折扣摊开 */
.ct-break { padding: 16px 18px; }
.ct-break-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 10px; }
.ct-break-head b { font-size: 15px; }
.ct-break-head a { font-size: 14px; color: var(--accent-2); }
.ct-break-row { display: flex; justify-content: space-between; padding: 5px 0; font-size: 14.5px; }
.ct-break-row.off b { color: var(--accent-2); }
.ct-break-row.sum { margin-top: 6px; padding-top: 10px; border-top: 1px solid var(--line); font-weight: 700; }
.ct-break .ct-hint { margin: 10px 0 0; font-size: 13.5px; line-height: 1.7; color: var(--muted); }
.ct-coupon { padding: 16px 18px; }
.ct-coupon .notice { margin-top: 10px; }

/* 领券落地页 */
.cpn-wrap { max-width: 620px; padding: 48px 0 70px; }
.cpn-card { padding: 32px 34px; text-align: center; }
.cpn-stamp { margin: 16px 0 22px; }
.cpn-stamp-v { display: block; font-family: var(--serif); font-size: 40px; line-height: 1.2; color: var(--accent-2); }
.cpn-stamp-l { display: block; font-size: 14px; letter-spacing: .12em; color: var(--muted); }
.cpn-card h1 { margin: 0 0 10px; font-family: var(--serif); font-size: 22px; }
.cpn-lead { margin: 0 auto 20px; max-width: 440px; font-size: 14.5px; line-height: 1.8; color: var(--muted); }
.cpn-meta { display: grid; gap: 8px; text-align: left; padding: 14px 16px; border-radius: 10px; background: var(--surface-2); }
.cpn-meta > div { display: flex; justify-content: space-between; gap: 12px; font-size: 14.5px; }
.cpn-meta span { color: var(--muted); }
.cpn-btn { margin-top: 22px; min-width: 180px; }
.cpn-link { display: inline-block; margin-top: 12px; font-size: 14px; color: var(--accent-2); }
.cpn-msg { margin-top: 14px; font-size: 14.5px; color: var(--accent-2); }
.cpn-msg a { color: var(--accent-2); }

/* 后台：等级表 / 认证审核 / 券管理 */
.lv-table { display: grid; gap: 0; }
.lv-row {
  display: grid; grid-template-columns: .7fr 1.5fr 1fr .7fr 1fr .7fr;
  gap: 10px; align-items: center; padding: 9px 12px;
  border-bottom: 1px solid var(--line); font-size: 14.5px;
}
.lv-th { background: var(--surface-2); font-weight: 700; color: var(--muted); }
.lv-in { width: 100%; padding: 6px 8px; border: 1px solid var(--line-strong); border-radius: 7px; font: inherit; font-size: 14.5px; }
.lv-short { max-width: 110px; }
/* 折扣按人话填（9.5 折 / 95 / 9500），居中好对行，等宽数字不抖 */
.lv-rate { text-align: center; font-variant-numeric: tabular-nums; }
/* 保存失败时整行标红：八行里得让人一眼看出是哪行填错了 */
.lv-row.lv-bad, .cert-row.lv-bad { background: var(--danger-soft); border-radius: 8px; }
.lv-row.lv-bad .lv-in { border-color: var(--danger); }
.cert-err { flex: 0 0 100%; font-size: 13.5px; line-height: 1.6; color: var(--danger); }
.lv-chk { display: inline-flex; align-items: center; gap: 5px; font-size: 14px; }
.lv-chk input { width: auto; }
.cert-table .adm-row { grid-template-columns: 1.1fr 1.3fr 1fr 1.2fr .7fr 1.5fr; }
.cert-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.cert-level { max-width: 150px; }
.cert-st { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 13px; font-weight: 700; }
.st-pending { background: var(--warn-soft); color: var(--warn); }
.st-approved { background: var(--accent-soft); color: var(--accent-2); }
.st-rejected { background: var(--danger-soft); color: var(--danger); }
.cpn-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
.cpn-form .field { margin-bottom: 12px; }
.cpn-wide { grid-column: 1 / -1; }
.cpn-acts { grid-column: 1 / -1; display: flex; align-items: center; gap: 14px; margin-top: 6px; }
.cpn-linkbox {
  display: flex; justify-content: space-between; align-items: center; gap: 14px;
  margin-top: 14px; padding: 12px 14px; border-radius: 9px;
  background: var(--accent-soft); border: 1px solid var(--accent-line);
}
.cpn-linkbox b { display: block; font-size: 14.5px; }
.cpn-linkbox span { font-size: 14px; color: var(--accent-2); word-break: break-all; }
.cpn-table .adm-row { grid-template-columns: 1.4fr .8fr 1.2fr .9fr .7fr 1.8fr; }
.cpn-ops { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.cpn-push { display: flex; gap: 5px; width: 100%; margin-top: 4px; }
.cpn-push .lv-in { flex: 1; min-width: 0; }
.od-discount {
  display: block; max-width: 150px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 13px; color: var(--accent-2);
}

/* 这些容器都有写死的 display，[hidden] 必须单独压回去 */
#cpAmountField[hidden], #cpRateField[hidden], #cpLinkBox[hidden],
#buyCouponField[hidden], #buyMemberRow[hidden], #buyCouponRow[hidden],
.ct-break-row[hidden] { display: none !important; }

@media (max-width: 860px) {
  .mem-grid { grid-template-columns: 1fr; }
  .lv-row { grid-template-columns: .7fr 1.4fr 1fr .7fr; }
  .lv-row > div:nth-child(5), .lv-row > div:nth-child(6) { grid-column: span 2; }
  .cert-table .adm-row, .cpn-table .adm-row { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .mem-panel { padding: 16px; }
  .mg-cards { grid-template-columns: 1fr; }
  .mem-lv-list { grid-template-columns: 1fr; }
  .cpn-form { grid-template-columns: 1fr; }
  .cpn-card { padding: 24px 18px; }
  .lv-row { grid-template-columns: .6fr 1.4fr 1fr; }
  .lv-row > div:nth-child(n+4) { grid-column: span 1; }
  .nav-seal { display: none; }
}

/* ============================================================
   站内信 / 邀请 / 测试反馈 / 账号合并
   2026-11-08 加的四个面。共用一组克制的东西：白面板、细边框、
   等宽数字。反馈卡和邀请页刻意做得比后台松一点 —— 这两页客户会看。
   ============================================================ */

/* ---- 顶栏：消息入口，和购物车角标同一套视觉 ---- */
/* 只放一个铃铛，不写「消息」两个字。
   1280 宽下这一排本来就被「邀请有礼」挤爆过一次（中文被拆成两行），
   铃铛省下来的 20px 是给「会员」「邀请」留的余量。 */
.nav-msg { display: inline-flex; align-items: center; line-height: 1; padding: 9px 8px; }
.nav-msg svg { display: block; }
.nav-msg b {
  position: absolute;
  top: 3px;
  right: 2px;
  display: inline-block;
  min-width: 14px;
  padding: 0 3px;
  border-radius: 8px;
  background: var(--brand);
  color: #fff;
  font-size: 13px;
  font-weight: 500;
  line-height: 17px;
  text-align: center;
}
/* display:inline-block 会盖掉 [hidden]，没读时角标必须真的消失 */
.nav-msg b[hidden] { display: none; }
.nav-msg.has { color: var(--brand); font-weight: 600; }

/* ---- 驱动页底部：测试反馈 ---- */
.fb-cta {
  max-width: 1180px;
  margin: 28px auto 0;
  padding: 26px 28px 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
}
.fb-cta-head { display: flex; gap: 24px; align-items: flex-start; justify-content: space-between; }
.fb-cta-head h3 { margin: 0 0 8px; font-size: 19px; color: var(--ink); }
.fb-cta-head h3 em {
  margin-left: 8px;
  font-style: normal;
  font-size: 14px;
  font-weight: 400;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 2px 8px;
  border-radius: 20px;
  vertical-align: 2px;
}
.fb-cta-head p { margin: 0; max-width: 640px; font-size: 15px; line-height: 1.75; color: var(--muted); }
.fb-cta-reward {
  flex: none;
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 16px;
  background: var(--accent-soft);
  border-radius: 10px;
}
.fb-cta-reward b { font-family: var(--mono, ui-monospace, monospace); font-size: 26px; color: var(--accent-2); }
.fb-cta-reward span { font-size: 13.5px; line-height: 1.5; color: var(--accent-2); }

.fb-form { margin-top: 20px; display: grid; gap: 12px; }
.fb-row { display: grid; gap: 6px; }
.fb-row-2 { grid-template-columns: 1fr 1fr; gap: 14px; }
.fb-row-2 > div { display: grid; gap: 6px; }
.fb-l { font-size: 14px; color: var(--muted); }
.fb-in {
  width: 100%;
  padding: 9px 11px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.fb-in:focus { outline: none; border-color: var(--accent-line); background: #fff; box-shadow: 0 0 0 3px var(--accent-soft); }
textarea.fb-in { resize: vertical; line-height: 1.7; }
.fb-file { padding: 6px 8px; font-size: 14.5px; }
.fb-acts { display: flex; align-items: center; gap: 12px; }
.fb-msg { font-size: 14.5px; color: var(--muted); }
.fb-note { margin: 0; font-size: 14px; color: var(--muted-2); }
.fb-login { margin-top: 18px; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.fb-login p { margin: 0; font-size: 14.5px; color: var(--muted); }

/* ---- 我的反馈 ---- */
.fb-wrap { max-width: 980px; }
.fb-list { display: grid; gap: 14px; }
.fb-item { padding: 18px 20px; }
.fb-head { display: flex; justify-content: space-between; gap: 14px; align-items: flex-start; }
.fb-head h3 { margin: 0 0 4px; font-size: 16.5px; }
.fb-body { margin: 10px 0 0; font-size: 15px; line-height: 1.8; color: var(--ink-2); white-space: pre-wrap; }
.fb-st {
  flex: none;
  padding: 3px 9px;
  border-radius: 20px;
  font-size: 13.5px;
  background: var(--paper-2);
  color: var(--muted);
}
.fb-st.st-open { background: #fdf1e3; color: #9a6212; }
.fb-st.st-accepted { background: var(--accent-soft); color: var(--accent-2); }
.fb-st.st-fixed { background: #e7eef7; color: #2f4a63; }
.fb-st.st-rejected { background: var(--paper-2); color: var(--muted-2); }

.fb-files { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.fb-file {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 14px;
  color: var(--ink-2);
  text-decoration: none;
}
.fb-file:hover { border-color: var(--accent-line); background: #fff; }
.fb-ext {
  font-size: 13.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--paper-2);
  color: var(--muted);
}
.fb-fname { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-foot { display: flex; align-items: center; gap: 16px; margin-top: 14px; font-size: 14px; }
.fb-reward { color: var(--accent-2); }
.fb-msg-link { margin-left: auto; color: var(--accent); text-decoration: none; }
.fb-empty { text-align: center; padding: 36px 20px; }
.fb-guide { margin-top: 22px; }
.fb-ul { margin: 0; padding-left: 20px; display: grid; gap: 8px; font-size: 15px; line-height: 1.7; color: var(--ink-2); }
.fb-ul b { color: var(--ink); }

/* ---- 邀请有礼 ---- */
.inv-wrap { max-width: 1060px; }
.inv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start; }
.inv-panel { padding: 20px 22px; }
.inv-k { display: block; margin: 14px 0 6px; font-size: 14px; color: var(--muted); }
.inv-code {
  font-size: 24px;
  letter-spacing: 4px;
  color: var(--ink);
  padding: 10px 14px;
  background: var(--surface-2);
  border: 1px dashed var(--line-strong);
  border-radius: 8px;
  text-align: center;
}
.inv-link { display: flex; gap: 8px; }
.inv-input {
  flex: 1;
  min-width: 0;
  padding: 9px 11px;
  font-size: 14.5px;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.inv-hint { min-height: 18px; margin: 8px 0 0; font-size: 14px; color: var(--accent); }
.inv-tip { margin: 14px 0 0; font-size: 14.5px; line-height: 1.75; color: var(--muted); }
.inv-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 6px 0 16px; }
.inv-stat { padding: 12px; background: var(--surface-2); border-radius: 10px; text-align: center; }
.inv-stat b { display: block; font-size: 22px; color: var(--ink); }
.inv-stat span { font-size: 13.5px; color: var(--muted); }
.inv-list { display: grid; gap: 2px; }
.inv-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  font-size: 14.5px;
}
.inv-who b { display: block; color: var(--ink); font-weight: 500; }
.inv-who .mono { font-size: 13.5px; color: var(--muted-2); }
.inv-meta { text-align: right; font-size: 13.5px; color: var(--muted); display: grid; gap: 2px; }
.inv-meta .is-ok { color: var(--accent); }
.inv-rules { margin-top: 18px; }
.inv-ol { margin: 0; padding-left: 20px; display: grid; gap: 8px; font-size: 15px; line-height: 1.7; color: var(--ink-2); }

/* ---- 站内信 ---- */
.msg-wrap { max-width: 880px; }
.msg-balance {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 12px 18px;
  background: var(--accent-soft);
  border-radius: 10px;
}
.msg-balance b { font-size: 26px; color: var(--accent-2); }
.msg-balance span { font-size: 13.5px; color: var(--accent-2); }
.msg-list { display: grid; gap: 10px; }
.msg-item {
  display: flex;
  gap: 14px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.msg-item.is-new { border-color: var(--accent-line); background: #fcfefd; }
.msg-dot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: 7px;
  border-radius: 50%;
  background: transparent;
}
.msg-item.is-new .msg-dot { background: var(--brand); }
.msg-main { flex: 1; min-width: 0; }
.msg-top { display: flex; justify-content: space-between; gap: 12px; }
.msg-top b { font-size: 15.5px; color: var(--ink); font-weight: 600; }
.msg-time { font-size: 13px; color: var(--muted-2); flex: none; }
.msg-body { margin: 8px 0 0; font-size: 14.5px; line-height: 1.8; color: var(--ink-2); white-space: pre-wrap; }
.msg-link { display: inline-block; margin-top: 8px; font-size: 14.5px; color: var(--accent); text-decoration: none; }
.msg-kind {
  flex: none;
  align-self: flex-start;
  padding: 3px 9px;
  border-radius: 20px;
  font-size: 13px;
  background: var(--paper-2);
  color: var(--muted);
}
.msg-kind.kind-reward { background: var(--accent-soft); color: var(--accent-2); }
.msg-kind.kind-feedback { background: #e7eef7; color: #2f4a63; }
/* 站点事务是「你的事在办」，不是「你在帮我们改驱动」—— 用中性灰绿区分开，
   免得跟反馈共用一色，客户在同一页看到两条就分不清哪条在讲他的站。 */
.msg-kind.kind-site { background: #e6efe9; color: #2f5340; }
.msg-kind.kind-gift { background: #fdf2dd; color: #7a5310; }

/* ---- 站内信：赠送授权的券卡 ----
   刻意做成「一张券」而不是一段通知正文：三个月后客户重装主机、回来找这串码，
   要能一眼认出哪一条是券，不用逐条读标题。

   类名前缀 gv- 是必须的：.lic-card 在驱动详情页已经有主（授权说明卡），
   借用这个名字会连它的 flex 布局和 .btn 定位一起继承过来 —— 页面上看着
   「大致对」，量出来才发现子元素全被排成一行。 */
.gv-card {
  display: block;
  margin-top: 12px;
  border: 1px solid var(--accent-line);
  border-radius: 12px;
  background: var(--surface);
  overflow: hidden;
}
.gv-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 14px;
  background: var(--accent-soft);
  border-bottom: 1px dashed rgba(12, 122, 80, 0.3);
}
.gv-tag { font-size: 13.5px; font-weight: 600; letter-spacing: 0.12em; color: var(--accent-2); }
.gv-term { font-size: 13.5px; color: var(--accent-2); white-space: nowrap; }
.gv-body { padding: 11px 14px 12px; }
.gv-name { font-size: 15.5px; font-weight: 600; color: var(--ink); line-height: 1.5; }
.gv-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-top: 5px;
  font-size: 13.5px;
  color: var(--muted);
}
.gv-meta b { font-weight: 500; color: var(--ink-2); }
.gv-code-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 9px 11px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
/* 授权码是 200 来个字符，一行放不下也不该被省略号吃掉：
   客户核对时看的是码的头和尾，中间截断等于没显示。 */
.gv-code {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--ink-2);
  word-break: break-all;
}
.gv-code-row .btn { flex: none; }
.gv-how { margin: 9px 0 0; font-size: 13.5px; line-height: 1.75; color: var(--muted); }
.gv-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 14px;
  border-top: 1px dashed var(--line);
  font-size: 13px;
  color: var(--muted-2);
}
.gv-go { color: var(--accent); text-decoration: none; white-space: nowrap; }
.gv-card.is-dead { border-color: var(--line); }
.gv-card.is-dead .gv-top { background: var(--paper-2); border-bottom-color: var(--line); }
.gv-card.is-dead .gv-tag, .gv-card.is-dead .gv-term { color: var(--muted); }
@media (max-width: 560px) {
  /* 手机上「授权 / 反馈」那枚徽标要吃掉 59px 正文宽度，把 200 个字符的码
     挤成十一二行。券卡自己写着「授权券」，徽标在这里是重复信息。 */
  .msg-kind { display: none; }
  /* 码是 200 多个字符，字号每大 1px 就多两三行；它是拿来复制的，
     在手机上不必跟正文同号 */
  .gv-code { font-size: 12.5px; line-height: 1.7; }
  .gv-code-row { flex-direction: column; align-items: stretch; }
  .gv-code-row .btn { width: 100%; }
  .gv-foot { flex-direction: column; align-items: flex-start; gap: 5px; }
}

/* ---- 后台：反馈队列 ---- */
.fbq-list { display: grid; gap: 12px; }
.fbq-card { padding: 16px 18px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
.fbq-head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.fbq-title { display: flex; align-items: center; gap: 8px; }
.fbq-title b { font-size: 15.5px; }
.fbq-kind { font-size: 13px; padding: 2px 8px; border-radius: 20px; background: var(--paper-2); color: var(--muted); }
.fbq-meta { font-size: 13.5px; margin-top: 4px; }
.fbq-body { margin: 12px 0 0; font-size: 14.5px; line-height: 1.8; color: var(--ink-2); white-space: pre-wrap; }
.fbq-reward { margin: 10px 0 0; font-size: 14px; color: var(--accent-2); }
.fbq-form { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line); display: grid; gap: 6px; }
.fbq-l { font-size: 13.5px; color: var(--muted); }
.fbq-in {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 14.5px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-2);
}
.fbq-acts { display: flex; align-items: center; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.fbq-msg { font-size: 14px; color: var(--muted); }

/* ---- 后台：疑似同一人 ---- */
.dup-panel { border-color: #f0dcc0; background: #fffdf9; }
.dup-card { padding: 14px 0; border-top: 1px solid var(--line); }
.dup-card:first-of-type { border-top: none; }
.dup-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.dup-key { font-size: 14.5px; color: var(--ink); background: var(--paper-2); padding: 2px 8px; border-radius: 6px; }
.dup-list { display: grid; gap: 6px; }
.dup-user {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  cursor: pointer;
}
.dup-user:hover { border-color: var(--accent-line); }
.dup-u-main { flex: 1; display: flex; align-items: center; gap: 8px; font-size: 14.5px; min-width: 0; }
.dup-u-main .mono { font-size: 13.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; }
.dup-tag { font-style: normal; font-size: 13.5px; padding: 1px 6px; border-radius: 20px; background: var(--accent-soft); color: var(--accent-2); }
/* 弱线索：只有昵称里的号码对得上。样式要跟硬线索拉开，别让人扫一眼就合并 */
.dup-tag-weak { background: #f6e6cf; color: #8a5a16; }
.dup-card.dup-weak { background: #fffaf0; border-radius: 8px; padding: 12px 12px 14px; }
.dup-card.dup-weak .dup-key { background: #fff0d8; }
.dup-u-meta { font-size: 13.5px; color: var(--muted); flex: none; }
.dup-acts { margin-top: 10px; display: flex; gap: 8px; }
/* 这一排是单选，不能继承 .field input 那套大输入框样式 */
.dup-user input[type="radio"] { width: 15px; height: 15px; flex: none; margin: 0; }

/* ---- 后台：公司定级 ---- */
.co-level { display: flex; gap: 6px; align-items: center; }
.co-level .lv-in { flex: 1; min-width: 0; }

/* ---- 账号页：撞号合并 ---- */
.link-box {
  margin-top: 16px;
  padding: 14px 16px;
  border: 1px solid #f0dcc0;
  background: #fffdf9;
  border-radius: 10px;
}
.link-box[hidden] { display: none; }
.link-box b { font-size: 15px; color: var(--ink); }
.link-box p { margin: 6px 0 0; font-size: 14.5px; line-height: 1.7; color: var(--muted); }
.link-hint { color: var(--muted-2) !important; }
.link-msg { margin-left: 10px; font-size: 14px; color: var(--accent); }
.pts-links { display: flex; gap: 14px; margin-top: 10px; font-size: 14px; }
.pts-links a { color: var(--accent); text-decoration: none; }

@media (max-width: 760px) {
  .fb-cta { padding: 18px 16px; }
  .fb-cta-head { flex-direction: column; gap: 14px; }
  .fb-row-2 { grid-template-columns: 1fr; }
  .inv-grid { grid-template-columns: 1fr; }
  .inv-code { font-size: 20px; letter-spacing: 2px; }
  .fb-fname { max-width: 140px; }
}

/* 平板（721–1000）跟着手机一起收进了汉堡菜单，但别把那套手机上的压缩参数
   一起带过来：字号、间距、控制台按钮在平板上一律照旧。 */
@media (min-width: 721px) and (max-width: 1000px) {
  .topbar-in { gap: 18px; }
  .brand-name { font-size: 16px; letter-spacing: 0.1em; }
  .nav-act .btn-ghost { display: inline-flex; }
}

/* 手机（≤600）的 .wrap 左右只有 18px，下拉得跟着收，否则右侧多出 20px 空白 */
@media (max-width: 600px) {
  .nav-links { padding-left: 18px; padding-right: 18px; }
}

/* ============================================================ 问答区
   一条原则：问题列表要能「扫」，详情页要能「读」。
   列表用卡片 + 右侧回答/浏览计数；详情页把正文和回答都给足行高，
   现场是拿着手机对着机柜看的，行距挤一点就读不下去。 */

.qa-wrap { padding-bottom: 64px; }
.qa-wrap .page-head { margin-bottom: 26px; }

.qa-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
.qa-search { display: flex; align-items: center; gap: 8px; flex: 1 1 420px; min-width: 0; }
.qa-search input {
  flex: 1 1 auto; min-width: 0; height: 38px; padding: 0 12px;
  border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface); font: inherit; font-size: 15px; color: var(--ink);
}
.qa-search input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.qa-reset { font-size: 14.5px; color: var(--muted); white-space: nowrap; }
.qa-ask-btn { flex: none; height: 38px; padding: 0 16px; }
.qa-scope { font-size: 14.5px; color: var(--muted); margin: -4px 0 14px; }

.qa-tabs { display: flex; align-items: center; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 18px; flex-wrap: wrap; }
.qa-tab {
  position: relative; padding: 9px 12px; font-size: 14.5px; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.qa-tab:hover { color: var(--ink); }
.qa-tab.on { color: var(--ink); border-bottom-color: var(--accent); font-weight: 600; }
.qa-tab em { font-style: normal; font-size: 13px; color: var(--muted-2); margin-left: 3px; }
.qa-tabs-hint { margin-left: auto; font-size: 14px; color: var(--muted-2); }

/* 状态：待解答（暖）/ 已解决（绿）/ 已隐藏（红）。三个都是小胶囊，
   不要做成按钮 —— 它们是事实，不是可点的动作。 */
.qa-st {
  display: inline-block; font-size: 13.5px; line-height: 1.6; padding: 0 7px;
  border-radius: 999px; border: 1px solid var(--line-strong); color: var(--muted);
  white-space: nowrap;
}
.qa-st.st-open { background: var(--warn-soft); border-color: transparent; color: var(--warn); }
.qa-st.st-solved { background: var(--accent-soft); border-color: transparent; color: var(--accent-2); }
.qa-st.st-hidden { background: var(--danger-soft); border-color: transparent; color: var(--danger); }

.qa-prod {
  display: inline-block; max-width: 240px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 13.5px; line-height: 1.7; padding: 0 7px;
  border-radius: 4px; background: var(--paper-2); color: var(--ink-2);
  vertical-align: 1px;
}

.qa-list { display: grid; gap: 10px; }
.qa-item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 18px;
  align-items: center; padding: 16px 18px; color: inherit;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.qa-item:hover { border-color: var(--accent-line); box-shadow: 0 8px 18px rgba(14, 26, 43, 0.06); }
.qa-item h2 { font-size: 16.5px; font-weight: 600; line-height: 1.45; margin-bottom: 5px; }
.qa-item p {
  font-size: 14.5px; color: var(--muted); line-height: 1.62; margin-bottom: 9px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.qa-item-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13.5px; color: var(--muted-2); }
/* 列表里的编号：淡淡放最后，客户截图或报号时能认出来 */
.qa-item-code { font-size: 13px; letter-spacing: .3px; color: var(--muted-2); }
.qa-asker { color: var(--muted); }
.qa-item-side { display: flex; gap: 16px; text-align: center; font-size: 13.5px; color: var(--muted-2); }
.qa-item-side b { display: block; font-size: 17px; font-weight: 600; color: var(--ink-2); line-height: 1.3; }

.qa-pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 22px; }
.qa-empty { padding: 26px 20px; font-size: 14.5px; color: var(--muted); }
.qa-empty p { line-height: 1.8; }

.qa-rules { margin-top: 34px; padding: 20px 22px; background: var(--surface-2); }
.qa-rules h2 { font-size: 15px; font-weight: 600; margin-bottom: 10px; }
.qa-rules ul { display: grid; gap: 7px; }
.qa-rules li { position: relative; padding-left: 14px; font-size: 14.5px; line-height: 1.75; color: var(--ink-2); }
.qa-rules li::before { content: ""; position: absolute; left: 0; top: 9px; width: 4px; height: 4px; border-radius: 50%; background: var(--accent); }

/* ---------------- 详情 */
.qa-crumb { display: flex; align-items: center; gap: 8px; padding-top: 18px; font-size: 14.5px; color: var(--muted); }
.qa-crumb-cur { color: var(--muted-2); }
.qa-q { padding: 20px 0 22px; border-bottom: 2px solid var(--ink); }
.qa-q-badges { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.qa-q h1 { font-family: var(--serif); font-size: clamp(23px, 2.6vw, 31px); font-weight: 600; line-height: 1.34; margin-bottom: 10px; }
.qa-q-meta { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; font-size: 14px; color: var(--muted); }
/* 问题编号：客户报号用，做成可点的胶囊，别让人以为是装饰文字 */
.qa-id { display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; font: inherit; font-size: 14px;
  color: var(--muted); background: var(--paper-2); border: 1px solid var(--line-strong); border-radius: 999px;
  cursor: pointer; white-space: nowrap; transition: .15s; }
.qa-id b { font-weight: 600; color: var(--ink); letter-spacing: .4px; }
.qa-id:hover { color: var(--ink-2); border-color: var(--accent-line); background: var(--surface); }
.qa-id:active { transform: translateY(1px); }
.qa-id.is-done { color: var(--accent-2); border-color: var(--accent-line); background: var(--accent-soft, var(--paper-2)); }
.qa-id.is-done b { color: var(--accent-2); }
.qa-q-body { margin-top: 16px; font-size: 15px; line-height: 1.88; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }
.qa-q-tags { display: flex; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.qa-tag { font-size: 13px; color: var(--muted); background: var(--paper-2); padding: 2px 8px; border-radius: 999px; }
.qa-ops-link { margin-left: auto; color: var(--accent-2); }

.qa-sec-title { display: flex; align-items: baseline; gap: 8px; margin: 30px 0 12px; font-size: 17px; font-weight: 600; }
.qa-sec-title .muted { font-size: 14px; font-weight: 400; }
.qa-sec-hint { margin-left: auto; font-style: normal; font-size: 14px; font-weight: 400; color: var(--accent-2); }

.qa-a { padding: 16px 18px; margin-bottom: 12px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; }
.qa-a.accepted { border-color: var(--accent-line); box-shadow: inset 3px 0 0 var(--accent); }
.qa-a-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.qa-a-who { display: flex; align-items: center; gap: 8px; font-size: 14.5px; flex-wrap: wrap; }
.qa-ava {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-2); font-size: 13px;
}
.qa-a-body { font-size: 15px; line-height: 1.82; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }
.qa-a-foot { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }

.qa-official, .qa-accepted, .qa-hidden, .qa-reward, .qa-guest {
  font-size: 13.5px; line-height: 1.7; padding: 0 7px; border-radius: 999px; white-space: nowrap;
}
.qa-official { background: var(--paper-2); color: var(--ink-2); }
.qa-accepted { background: var(--accent-soft); color: var(--accent-2); }
.qa-hidden { background: var(--danger-soft); color: var(--danger); }
.qa-reward { background: var(--warn-soft); color: var(--warn); }
.qa-guest { background: var(--paper-2); color: var(--muted); }

.qa-reply, .qa-login, .qa-official-box { margin-top: 18px; padding: 18px 20px; }
.qa-reply h2, .qa-official-box h2 { font-size: 15.5px; font-weight: 600; margin-bottom: 6px; }
.qa-reply-hint, .qa-login p { font-size: 14.5px; color: var(--muted); line-height: 1.7; margin-bottom: 10px; }
.qa-reply textarea, .qa-official-box textarea, .qa-form textarea, .qa-edit textarea {
  width: 100%; padding: 10px 12px; border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface); font: inherit; font-size: 15px; line-height: 1.7; color: var(--ink);
  resize: vertical;
}
.qa-reply textarea:focus, .qa-official-box textarea:focus,
.qa-form textarea:focus, .qa-edit textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.qa-login { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.qa-login p { margin: 0; flex: 1 1 260px; }

.qa-related { margin-top: 34px; }
.qa-related-list { display: grid; gap: 8px; }
.qa-related-item {
  display: flex; align-items: center; gap: 10px; padding: 11px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink-2); font-size: 14.5px;
}
.qa-related-item:hover { border-color: var(--accent-line); }
.qa-related-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------------- 提问表单 */
.qa-ask-wrap { max-width: 860px; }
.qa-who {
  margin: -8px 0 14px; padding: 10px 14px; font-size: 14.5px; color: var(--ink-2);
  background: var(--accent-soft); border-radius: 8px;
}
.qa-form { padding: 22px 24px; }
.qa-form .field { margin-bottom: 16px; }
.qa-form .field:last-of-type { margin-bottom: 0; }
.qa-form .field-hint { margin-top: 5px; font-size: 13.5px; color: var(--muted-2); }
.qa-guest-hint { margin: -6px 0 4px; font-size: 13.5px; color: var(--muted-2); }
.qa-row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.qa-form-foot { display: flex; align-items: center; gap: 12px; margin-top: 16px; flex-wrap: wrap; }
.qa-form-msg { font-size: 14.5px; color: var(--muted); }
.qa-form-msg.bad { color: var(--danger); }

/* ---------------- 后台 */
.qa-adm-head h1 { font-size: 20px; line-height: 1.4; }
.qa-adm-acts { display: flex; gap: 8px; align-items: center; }
.qa-adm-search { display: flex; align-items: center; gap: 8px; padding: 12px 18px; border-bottom: 1px solid var(--line); }
.qa-adm-search input {
  flex: 1 1 auto; min-width: 0; height: 34px; padding: 0 11px;
  border: 1px solid var(--line-strong); border-radius: 7px;
  background: var(--surface); font: inherit; font-size: 14.5px;
}
.qa-adm-search input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.qa-adm-list { display: grid; }
.qa-adm-item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px;
  align-items: center; padding: 13px 18px; color: inherit;
  border-bottom: 1px solid var(--line);
}
.qa-adm-item:last-child { border-bottom: 0; }
.qa-adm-item:hover { background: var(--surface-2); }
.qa-adm-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 15px; }
.qa-adm-title b { font-weight: 600; }
.qa-adm-meta { display: flex; align-items: center; gap: 10px; margin-top: 5px; font-size: 13.5px; color: var(--muted-2); flex-wrap: wrap; }
.qa-adm-side { display: flex; align-items: baseline; gap: 4px; font-size: 13px; color: var(--muted-2); }
.qa-adm-side b { font-size: 16px; color: var(--ink-2); }

.qa-edit { padding: 0 0 20px; margin-bottom: 18px; }
.qa-edit .field, .qa-edit .qa-row2 { margin: 14px 20px 0; }
.qa-edit .qa-form-foot { margin: 16px 20px 0; }
.qa-edit-acts { display: flex; gap: 8px; }
.qa-adm-answers { padding: 14px 18px; display: grid; gap: 12px; }
.qa-adm-answer { padding: 14px 16px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface-2); }
.qa-adm-answer.accepted { border-color: var(--accent-line); background: var(--surface); box-shadow: inset 3px 0 0 var(--accent); }

/* 删除按钮：只在后台出现，红字描边，不填红底 —— 满屏红会把「保存」的位置盖住 */
.btn-danger { --bg: transparent; --fg: var(--danger); --bd: var(--danger-soft); }
.btn-danger:hover { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }

/* 首页「常见问题」现在指向问答区，条目本身是链接 */
.faq-item { display: block; color: inherit; }
a.faq-item:hover h3 { color: var(--accent-2); }
.faq-more { display: flex; gap: 10px; margin-top: 24px; flex-wrap: wrap; }

/* ---------------- 分类（2026-11-09）
   大类 = 平台品牌（Crestron / Control4 / KNX），二级 = 产品线
   （Crestron HOME 驱动 / 硬件）。数据是任意深度，界面按两级排：
   第一行品牌、第二行选中品牌下的子类，再深就只在后台出现了。 */
.qa-cats { display: grid; gap: 5px; margin: -2px 0 14px; }
.qa-cat-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-height: 26px; }
.qa-cat-k { flex: none; width: 32px; font-size: 13.5px; color: var(--muted-2); }
.qa-cat-chip {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 3px 10px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface); font-size: 14.5px; color: var(--ink-2);
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.qa-cat-chip:hover { border-color: var(--accent-line); color: var(--accent-2); }
.qa-cat-chip.on { background: var(--accent-soft); border-color: transparent; color: var(--accent-2); font-weight: 600; }
.qa-cat-chip em { font-style: normal; font-size: 13.5px; color: var(--muted-2); }
.qa-cat-chip.on em { color: var(--accent-2); opacity: .75; }
.qa-cat-chip.sm {
  padding: 0 7px; font-size: 13.5px; line-height: 1.7; vertical-align: 1px;
  background: var(--paper-2); border-color: transparent; color: var(--ink-2);
}

/* 后台列表里的分类筛选条 */
.qa-adm-search select {
  flex: 0 1 190px; height: 34px; padding: 0 8px;
  border: 1px solid var(--line-strong); border-radius: 7px;
  background: var(--surface); font: inherit; font-size: 14.5px; color: var(--ink);
}
.qa-adm-search select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.qa-adm-catbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 18px; border-bottom: 1px solid var(--line); font-size: 14.5px;
}
.qa-adm-catbar .btn { margin-left: auto; }

/* ---------------- 分类管理（后台） */
.cat-manage {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 16px; align-items: start;
}
.cat-tree-panel, .cat-edit-panel { padding: 0 0 16px; }
.cat-tree { display: grid; padding: 8px 10px 10px; gap: 1px; }
.cat-node {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px 8px calc(10px + var(--d) * 20px);
  border: 0; border-radius: 7px; background: transparent;
  font: inherit; font-size: 14.5px; color: var(--ink); text-align: left; cursor: pointer;
}
.cat-node:hover { background: var(--surface-2); }
.cat-node.on { background: var(--accent-soft); color: var(--accent-2); font-weight: 600; }
.cat-node.is-off { opacity: .58; }
.cat-node-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-node-n { flex: none; font-size: 13px; color: var(--muted-2); }
.cat-node-n i { font-style: normal; opacity: .55; }
.cat-node.on .cat-node-n { color: var(--accent-2); }
.cat-off {
  flex: none; padding: 0 6px; border-radius: 999px; font-size: 13.5px; line-height: 1.7;
  background: var(--danger-soft); color: var(--danger);
}
.cat-new { padding: 12px 16px 0; margin-top: 4px; border-top: 1px solid var(--line); }
.cat-new-title { font-size: 14px; color: var(--muted-2); margin-bottom: 8px; }
.cat-new-row { display: flex; gap: 8px; }
.cat-new-row input, .cat-new-row select {
  height: 34px; padding: 0 10px; border: 1px solid var(--line-strong);
  border-radius: 7px; background: var(--surface); font: inherit; font-size: 14.5px; color: var(--ink);
}
.cat-new-row input { flex: 1 1 auto; min-width: 0; }
.cat-new-row select { flex: 0 1 190px; min-width: 0; }
.cat-new-row input:focus, .cat-new-row select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.cat-edit-panel .field { margin: 14px 20px 0; }
.cat-edit-panel .qa-form-foot { margin: 16px 20px 0; flex-wrap: wrap; }
.cat-edit-panel #catEditEmpty { margin: 6px 20px 0; }
.cat-note { margin: 14px 20px 0; font-size: 13.5px; line-height: 1.85; color: var(--muted-2); }

@media (max-width: 760px) {
  .cat-manage { grid-template-columns: 1fr; }
  .cat-new-row { flex-wrap: wrap; }
  .cat-new-row input { flex: 1 1 100%; }
  .cat-new-row select { flex: 1 1 100%; }
  .cat-edit-panel .field, .cat-edit-panel .qa-form-foot,
  .cat-note, .cat-edit-panel #catEditEmpty { margin-left: 14px; margin-right: 14px; }
  .qa-adm-search { flex-wrap: wrap; }
  .qa-adm-search select { flex: 1 1 100%; }
  .qa-adm-catbar .btn { margin-left: 0; }
}

@media (max-width: 760px) {
  .qa-item { grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 14px 15px; }
  .qa-item-side { justify-content: flex-start; gap: 20px; }
  /* 手机上把两个计数并排塞回标题下面，右侧那列整块收掉 */
  .qa-item-side b { display: inline; font-size: 14px; margin-right: 3px; }
  .qa-item-side div { display: inline-flex; align-items: baseline; gap: 2px; }
  .qa-row2 { grid-template-columns: 1fr; }
  /* 搜索框和「我要提问」在手机上并排不下一行，掉下来那个独占一行时要撑满，
     否则一个绿按钮孤零零贴在左边，看着像没做完 */
  .qa-ask-btn { flex: 1 1 100%; justify-content: center; }
  .qa-tabs-hint { display: none; }
  .qa-q h1 { font-size: 22px; }
  .qa-q-body, .qa-a-body { font-size: 15px; }
  .qa-form, .qa-reply, .qa-login, .qa-official-box, .qa-rules { padding: 16px 16px; }
  .qa-edit .field, .qa-edit .qa-row2, .qa-edit .qa-form-foot { margin-left: 14px; margin-right: 14px; }
  .qa-adm-item { padding: 12px 14px; }
  .qa-adm-search { padding: 10px 14px; }
  .qa-adm-answers { padding: 12px 14px; }
}

/* 问答正文配图：[[img:文件名|图注]] 由 app.py 的 qa_body 过滤器渲染成上面的结构 */
.qa-fig { margin: 14px 0 16px; white-space: normal; }
.qa-fig img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: 10px; background: #0c0e12;
}
.qa-fig figcaption { margin-top: 7px; font-size: 14px; line-height: 1.65; color: var(--muted); }

.qa-field-hint { margin: 6px 0 0; font-size: 13.5px; line-height: 1.6; color: var(--muted); }
.qa-field-hint code { font-family: var(--mono, ui-monospace, monospace); font-size: 13.5px; }

/* ---------------------------------------------------------------------------
   2026-11-09 网页工具入口（灯表生成器之类）
   有些驱动要现场手填一张表，光看步骤文字填不明白。入口放在两处：
   · 驱动详情页侧栏 —— 夹在价目卡和下载卡中间，买之前先看清要填什么；
   · 控制台站点卡 —— 已经买了的人在这里直接点，不用翻详情页。
   用浅绿底 + 图标和纯白卡片区分开，但不抢「立即购买」的主色块。
--------------------------------------------------------------------------- */
.btn-tool {
  --bg: var(--accent-soft);
  --fg: var(--accent-2);
  --bd: var(--accent-line);
}
.btn-tool:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 10px 20px -12px rgba(12, 122, 80, 0.7);
}

.dv-tool { background: var(--surface-2); border-color: var(--line-strong); }
.dv-tool-head { display: flex; gap: 11px; align-items: flex-start; margin-bottom: 12px; }
.dv-tool-ico {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 8px;
  font-size: 16px; line-height: 1;
  background: var(--accent-soft);
  color: var(--accent-2);
  border: 1px solid var(--accent-line);
}
.dv-tool-head h3 { margin-bottom: 4px; }
.dv-tool-desc { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
.dv-tool .dv-tool-btn { margin-bottom: 9px; }

/* ---------------------------------------------------------------- 404 */
/* 从搜索结果点进来的人不该撞上一句白底黑字的 Not Found。
   这一页只做三件事：说清没找到、给一个搜索框、给三条回退路径。 */
.nf-wrap { padding: 88px 28px 120px; }
.nf-box { max-width: 660px; margin: 0 auto; }

.nf-code {
  font-size: 14.5px; letter-spacing: 0.3em; color: var(--muted-2);
  padding-bottom: 10px;
}
.nf-box h1 {
  margin: 0 0 12px;
  font-size: 34px; line-height: 1.2; letter-spacing: -0.01em;
  color: var(--ink);
}
.nf-lead {
  margin: 0 0 26px;
  font-size: 15.5px; line-height: 1.75; color: var(--muted);
}

.nf-search {
  display: flex; gap: 8px;
  padding: 6px; margin-bottom: 30px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow-sm);
}
.nf-search input {
  flex: 1 1 auto; min-width: 0;
  padding: 10px 12px; border: 0; background: none;
  font: inherit; font-size: 15px; color: var(--ink);
}
.nf-search input:focus { outline: none; }
.nf-search .btn { flex: none; }

.nf-links { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.nf-link {
  display: block; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); color: var(--ink);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.nf-link:hover { border-color: var(--accent); transform: translateY(-1px); color: var(--ink); }
.nf-link b { display: block; font-size: 15px; margin-bottom: 4px; }
.nf-link span { font-size: 14.5px; color: var(--muted); }

.nf-foot {
  margin: 28px 0 0; padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: 14.5px; color: var(--muted);
}
.nf-foot b { color: var(--ink-2); }

@media (max-width: 620px) {
  .nf-wrap { padding: 56px 20px 80px; }
  .nf-box h1 { font-size: 26px; }
  .nf-links { grid-template-columns: 1fr; }
  .nf-search { flex-wrap: wrap; }
  .nf-search .btn { width: 100%; }
}

/* ============================================================
   品牌方推荐券包（/account/vendor · /invite）

   「100 张 ¥599 券只能送人、不能自己用」这件事，必须在页面上第一眼
   看出两个数：还剩多少张、已经送出去多少。所以条、数字、库存三件
   放在同一屏，不折进折叠区。
   ============================================================ */
.vcp-panel {
  margin-bottom: 22px;
  /* .panel 自身不带内边距（那是 .panel-body 的活），这张卡没包那层，
     所以内边距得自己给，否则标题和数字都贴着边框 */
  padding: 20px 22px 18px;
}

.vcp-panel.is-off {
  background: var(--surface-2);
  border-style: dashed;
  box-shadow: none;
}

.vcp-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
}

.vcp-head h2 { margin: 4px 0 6px; font-size: 21px; }

.vcp-sub {
  margin: 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.6;
}

.vcp-left {
  flex: none;
  text-align: right;
  padding-left: 14px;
}

.vcp-left b {
  display: block;
  font-size: 34px;
  /* line-height:1 在这颗 34px 的数字上会把字顶顶出容器，被卡片边切掉 */
  line-height: 1.16;
  color: var(--accent-2);
  letter-spacing: -0.02em;
}

.vcp-left span {
  display: block;
  margin-top: 6px;
  font-size: 14px;
  color: var(--muted);
}

.vcp-bar {
  height: 6px;
  margin: 18px 0 16px;
  border-radius: 999px;
  background: var(--paper-2);
  overflow: hidden;
}

.vcp-bar i {
  display: block;
  height: 100%;
  min-width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.vcp-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.vcp-stat {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}

.vcp-stat b {
  display: block;
  font-size: 20px;
  line-height: 1.1;
  color: var(--ink);
}

.vcp-stat span {
  display: block;
  margin-top: 5px;
  font-size: 14px;
  color: var(--muted);
}

.vcp-note {
  margin: 16px 0 0;
  padding: 12px 14px;
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 15px;
  line-height: 1.7;
  color: var(--ink-2);
}

.vcp-k {
  display: block;
  margin: 18px 0 6px;
  font-size: 14px;
  color: var(--muted);
  letter-spacing: 0.04em;
}

.vcp-link { display: flex; gap: 8px; }

.vcp-link input {
  flex: 1;
  min-width: 0;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 14.5px;
  color: var(--ink-2);
}

.vcp-hint {
  min-height: 18px;
  margin: 8px 0 0;
  font-size: 14.5px;
  color: var(--accent-2);
}

.vcp-empty {
  margin: 16px 0 0;
  font-size: 14.5px;
  color: var(--muted);
}

.vcp-list {
  margin-top: 20px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}

.vcp-list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
  font-size: 14.5px;
}

.vcp-row {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) 108px 92px;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px dashed var(--line);
}

.vcp-row:last-child { border-bottom: 0; }

.vcp-who { min-width: 0; }
.vcp-who b { display: block; font-size: 15px; }
.vcp-who span {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vcp-when { font-size: 13.5px; color: var(--muted); }

.vcp-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-2);
  font-size: 13.5px;
  white-space: nowrap;
}

.vcp-chip.used { background: var(--paper-2); color: var(--muted); }

/* 后台列表里那一行「推荐券包 100 张 · 已转出 3 · 剩 97」 */
.vst-pack { color: var(--accent-2); }
.vst-pack-ok { color: var(--accent-2); }

@media (max-width: 640px) {
  .vcp-head { flex-direction: column; gap: 10px; }
  /* 「99 张可送」压成一行，别让大数字独占一行把标题推下去 */
  .vcp-left {
    display: flex;
    align-items: baseline;
    gap: 6px;
    text-align: left;
    padding-left: 0;
  }
  .vcp-left b { font-size: 26px; }
  .vcp-left span { margin-top: 0; }
  .vcp-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 三列保持一行：日期和状态各自一列，掉到第二行会让人以为是另一个客户 */
  .vcp-row { grid-template-columns: minmax(0, 1fr) 78px 76px; row-gap: 4px; }
  .vcp-row .vcp-state { grid-column: auto; }
  .vcp-link { flex-direction: column; }
  /* 竖排时 input 不会自动撑满：UA 默认宽度按 size 算，只显示半截链接 */
  .vcp-link input { width: 100%; }
  .vcp-link .btn { width: 100%; }
}

/* ============================================================
   站点过户
   横幅用琥珀而不是正红：正红是商标色、也留给「出错了」。
   这条待办的语气是「有人想接你的项目，你确认一下」，
   不是「你的账号出事了」，颜色错了客户会先慌。
   ============================================================ */

.transfer-panel {
  margin: 0 0 18px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--warn);
  border-radius: 10px;
}
.tp-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 10px;
}
.tp-badge {
  font-size: 12px;
  line-height: 1.6;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--warn-soft);
  color: var(--warn);
  font-weight: 500;
  white-space: nowrap;
}
.tp-head strong { font-size: 15px; font-weight: 500; color: var(--ink); }
.tp-sub { font-size: 13px; color: var(--muted); line-height: 1.6; }
.tp-item {
  display: flex;
  gap: 16px;
  justify-content: space-between;
  align-items: flex-start;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
}
.tp-body { min-width: 0; flex: 1; }
.tp-title { font-size: 14px; color: var(--ink); }
.tp-title .mono { color: var(--ink-2); }
.tp-meta { font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: 1.6; }
.tp-note {
  margin-top: 7px;
  padding: 8px 10px;
  background: var(--surface-2);
  border-radius: 6px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.tp-act { display: flex; gap: 8px; flex-shrink: 0; }

/* 绑定弹窗里的「申请接管」：站点在别人名下时才出现 */
.transfer-ask {
  margin-top: 14px;
  padding: 14px 16px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  border-radius: 10px;
}
.transfer-ask[hidden] { display: none; }
.transfer-ask h4 { margin: 0 0 6px; font-size: 14px; font-weight: 500; color: var(--ink); }
.transfer-ask p { margin: 0 0 10px; font-size: 13px; line-height: 1.6; color: var(--ink-2); }
.transfer-ask label { display: block; margin-bottom: 5px; font-size: 13px; color: var(--muted); }
.transfer-ask textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 9px 10px;
  font: inherit;
  font-size: 13px;
  line-height: 1.6;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  resize: vertical;
}
.transfer-ask textarea:focus { outline: 2px solid var(--accent-line); outline-offset: 1px; }
.ta-foot { display: flex; align-items: center; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
.ta-foot .field-hint { margin: 0; }

@media (max-width: 640px) {
  .tp-item { flex-direction: column; gap: 10px; }
  .tp-act { width: 100%; }
  .tp-act .btn { flex: 1; }
}

/* 后台「站点过户待办」：一行一条，和用户列表的密度对齐 */
.tf-panel { margin-bottom: 16px; }
.tf-row {
  display: flex;
  gap: 16px;
  justify-content: space-between;
  align-items: flex-start;
  padding: 12px 0;
  border-top: 1px dashed var(--line);
}
.tf-row:first-of-type { border-top: 0; padding-top: 4px; }
.tf-main { min-width: 0; flex: 1; }
.tf-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.tf-code { font-size: 14px; color: var(--ink); }
.tf-arrow { font-size: 13px; color: var(--ink-2); }
.tf-meta { margin-top: 4px; font-size: 12.5px; color: var(--muted); line-height: 1.6; }
.tf-note {
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.tf-act { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
.tf-reason {
  width: 210px;
  padding: 7px 9px;
  font: inherit;
  font-size: 13px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
}
.tf-reason:focus { outline: 2px solid var(--accent-line); outline-offset: 1px; }

@media (max-width: 760px) {
  .tf-row { flex-direction: column; gap: 10px; }
  .tf-act { width: 100%; flex-wrap: wrap; }
  .tf-reason { width: 100%; }
  .tf-act .btn { flex: 1; }
}

/* ── 首发 / 已认证 ────────────────────────────────────────────────
   内容可信度标记，和「已解决」是两条正交的线：一个讲有没有答上，
   一个讲我们有没有按实机复核过。首发用虚线 —— 已经能看，但还不是
   可以照着报参数的权威答案；复核完转实线翠绿带勾。 */
.qa-cert {
  display: inline-block; font-size: 12.5px; line-height: 1.75; padding: 0 7px;
  border-radius: 999px; border: 1px dashed var(--line-strong);
  color: var(--muted); white-space: nowrap; letter-spacing: .02em;
  vertical-align: 1px;
}
.qa-cert.done {
  border: 1px solid transparent; background: var(--accent-soft); color: var(--accent-2);
}
.qa-cert.done::before { content: "\2713"; margin-right: 3px; font-size: 11px; }

/* ── 驱动健康度 ──────────────────────────────────────────────────
   列表上只在异常时出现：全绿的不画。一张卡片已经有授权状态点，
   再挂一个「正常」标签，几百个站点扫下来一片绿，反而看不出哪台真
   有问题。完整数据在右侧详情面板里，列表只负责把人叫过去。 */
.siteitem .s-health {
  flex: none;
  font-size: 12.5px;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid transparent;
}
.siteitem .s-health.lv-amber {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: rgba(143, 90, 18, 0.16);
}
.siteitem .s-health.lv-red {
  color: var(--danger);
  background: var(--danger-soft);
  border-color: rgba(160, 46, 34, 0.16);
}

.hpanel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 14px 16px;
  margin: 0 0 18px;
}
.hp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 13.5px;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.hp-lv {
  font-size: 12.5px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.hp-lv.lv-green { color: var(--accent); background: var(--accent-soft); border-color: var(--accent-line); }
.hp-lv.lv-amber { color: var(--warn); background: var(--warn-soft); border-color: rgba(143, 90, 18, 0.16); }
.hp-lv.lv-red { color: var(--danger); background: var(--danger-soft); border-color: rgba(160, 46, 34, 0.16); }

.hp-bits {
  margin-top: 9px;
  font-size: 13.5px;
  color: var(--ink-2);
  line-height: 1.7;
}
.hp-bits b { font-family: var(--mono); font-weight: 500; }

.hp-up {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  font-size: 13px;
}
.hp-up-i { color: var(--warn); font-weight: 500; }
.hp-drv { font-family: var(--mono); color: var(--ink); }
.hp-ver { font-family: var(--mono); color: var(--muted); }
.hp-ver-new { color: var(--warn); }
.hp-link { margin-left: auto; color: var(--accent); text-decoration: none; white-space: nowrap; }
.hp-link:hover { text-decoration: underline; }

/* 这句不是免责话术：心跳只证明主机在线、驱动在跑，不证明总线上的
   设备都正常。客户会把绿色当巡检报告，所以必须写在旁边。 */
.hp-note {
  margin-top: 10px;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--muted);
}

/* ── 报故障弹窗的上下文 ──────────────────────────────────────────
   做成灰底只读表，不是输入框。客户看见输入框就以为要自己填，
   看见表格就明白「这些已经知道了，我只用说现象」。 */
.report-ctx {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 12px 14px;
  margin-bottom: 16px;
}
.rc-title {
  font-size: 12.5px;
  color: var(--muted);
  margin-bottom: 9px;
}
.rc-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 14px;
  font-size: 13px;
  align-items: baseline;
}
.rc-k { color: var(--muted-2); white-space: nowrap; }
.rc-v { color: var(--ink-2); word-break: break-word; }
.rc-v.mono { font-family: var(--mono); }

/* ── 后台 /ops/health：待处理站点 ────────────────────────────────
   左边一条色杠代替整块红底：一屏十几行，整块染色会让人分不清
   哪几行是红的，色杠扫一眼就够。 */
.hp-list { display: grid; gap: 10px; }
.hrow {
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 12px 16px;
}
.hrow.lv-red { border-left-color: var(--danger); }
.hrow.lv-amber { border-left-color: var(--warn); }

.hr-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.hr-lv { font-size: 12.5px; color: var(--muted); }
.hrow.lv-red .hr-lv { color: var(--danger); }
.hrow.lv-amber .hr-lv { color: var(--warn); }
.hr-code { font-size: 14px; color: var(--ink); letter-spacing: 0.01em; }
.hr-alias { font-size: 13.5px; color: var(--ink-2); }
.hr-who { margin-left: auto; font-size: 13px; color: var(--muted-2); }

.hr-detail { margin-top: 6px; font-size: 13.5px; color: var(--ink-2); }

.hr-drivers { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 8px; }
.hr-drv { display: inline-flex; align-items: baseline; gap: 7px; font-size: 12.5px; color: var(--muted); }
.hr-drv b { font-weight: 500; color: var(--ink-2); }
.hr-rate { color: var(--muted-2); }
.hr-bad { color: var(--danger); }
.hr-new { color: var(--warn); }

.hr-err {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
  font-size: 12.5px;
  color: var(--muted);
  word-break: break-word;
}

.hr-note {
  margin-top: 22px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--muted-2);
}

/* ── 后台 /ops/alarms：站点报警 ──────────────────────────────────
   和健康度用同一套 .hrow / .hr-* 行样式，只补分组标题和操作区 ——
   两页都是「一屏待办」，长得不一样反而要重新学一遍怎么读。 */
.al-h2 {
  margin: 26px 0 6px;
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
}
.al-lead {
  margin: 0 0 12px;
  max-width: 74ch;
  font-size: 13px;
  line-height: 1.75;
  color: var(--muted);
}
.al-age { margin-left: 8px; color: var(--danger); }
.al-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.al-foot form { margin: 0; }
.al-hint { font-size: 12.5px; color: var(--muted-2); }

/* 延长试用：天数框和按钮同一行。框只有三四位数字，给 76px 就够 ——
   用默认宽度会把按钮挤到下一行，一列站点的按钮高度参差不齐。 */
.al-ext { display: inline-flex; align-items: center; gap: 6px; }
.al-ext input {
  width: 76px;
  padding: 5px 8px;
  font: inherit;
  font-size: 13.5px;
  line-height: 1.4;
  text-align: center;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 7px;
}
.al-ext input:focus { outline: 2px solid var(--accent-soft); outline-offset: 1px; }

/* 备注框跟天数框共用一套边框，但不能共用 76px 的宽度 —— 那句备注是给
   运营自己看的，写「客户承认有两台」要能看全。 */
.al-ext.wide input { width: 300px; text-align: left; }

/* ── 后台 /ops/sites/<code>/instances：实例清单 ──────────────────
   判定证据（clone_instances）和当前实例表是两个集合，页面合成一张表，
   用标签区分「计入判定」和「只有一次心跳」。标签不做颜色区分的话，
   运营会以为五个号就是五台机器。 */
.al-back { margin: 0 0 14px; font-size: 13px; }
.al-back a { color: var(--muted); text-decoration: none; }
.al-back a:hover { color: var(--accent); }

.ins-row { display: block; cursor: pointer; }
.ins-row .hr-top { align-items: center; }
.ins-row input[type="radio"] { margin: 0 2px 0 0; accent-color: var(--accent); }
.ins-row.ins-picked { border-color: var(--accent); }

/* 选不了的行（已无心跳 / 记录过期）在 radio 那一列留一个占位，
   否则实例号会跟上面的行错开，一眼看不出是对齐的列表。 */
.ins-nopick {
  display: inline-block;
  width: 13px;
  text-align: center;
  color: var(--muted-2);
}

.ins-tag {
  display: inline-block;
  padding: 1px 7px;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--muted);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  white-space: nowrap;
}
.ins-tag-on { color: var(--danger); border-color: var(--danger-soft); }
.ins-tag-live { color: var(--accent); border-color: var(--accent-soft); }
.ins-tag-keep { color: var(--ink); background: var(--accent-soft); border-color: var(--accent-line); }

/* 区间时长和「心跳 N 次」用同一种低对比的小字，避免把明细行读成标题。
   判定依据不在这一行，这一行只负责「谁、从几点到几点、跳了几次」。 */
.ins-span { color: var(--muted); }
.ins-span::before { content: "· "; color: var(--muted-2); }

/* ── 实例时间线 ────────────────────────────────────────────────
   判定依据是「两个号的在线区间重叠」，不是「有几个号」。这句话写成文字
   管理员还是得自己减时间，所以画成横轴：每条是一段区间，重叠的几分钟
   涂成红竖条。三列网格（号 / 轨道 / 时长），行间不留缝隙 —— 竖条跨行
   才会连成一条，留了 gap 就变成一串虚线，看不出是同一段时间。 */
.tl-wrap {
  margin: 14px 0 4px;
  padding: 14px 16px 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.tl { display: block; }

.tl-head,
.tl-row {
  display: grid;
  grid-template-columns: 82px 1fr 62px;
  align-items: center;
  gap: 12px;
}

.tl-head { padding-bottom: 4px; }
.tl-head .tl-id { font-size: 11.5px; color: var(--muted-2); }
.tl-len {
  font-size: 11.5px;
  color: var(--muted-2);
  text-align: right;
  white-space: nowrap;
}

.tl-row { padding: 0; }
.tl-id {
  font-size: 12.5px;
  color: var(--ink-2);
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.tl-id-on { color: var(--danger); }

.tl-track {
  position: relative;
  height: 24px;
  background: var(--paper);
  border-radius: 3px;
}
.tl-head .tl-track { background: none; height: 18px; }

/* 轨道两端的时刻。0% 向右推、100% 向左收，否则首尾两个字会被裁掉一半。
   用类不用 :first-child —— 竖带标签也插在这个容器里，顺序一变伪类就错位。 */
.tl-ax {
  position: absolute;
  top: 1px;
  font-size: 11px;
  color: var(--muted-2);
  white-space: nowrap;
}
.tl-ax-l { left: 0; }
.tl-ax-r { right: 0; }

.tl-bandlab {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  padding: 0 5px;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--danger);
  background: var(--danger-soft);
  border-radius: 3px;
  white-space: nowrap;
}

.tl-bar {
  position: absolute;
  top: 7px;
  height: 10px;
  border-radius: 999px;
  background: var(--line-strong);
}
.tl-bar-on { background: var(--danger); }

/* 只报过一次的号没有区间，画一根竖线 —— 硬给个宽度会显得它也活了一段时间。
   3px 而不是 1px：1px 在浅色轨道上几乎看不见，而这几根线恰恰是
   「见过 5 个号，其实只有 2 个算数」这个结论的视觉依据。 */
.tl-tick {
  position: absolute;
  top: 4px;
  width: 3px;
  height: 16px;
  margin-left: -1.5px;
  border-radius: 1.5px;
  background: var(--muted);
}
.tl-tick-on { background: var(--danger); }

.tl-band {
  position: absolute;
  top: 0;
  bottom: 0;
  background: rgba(160, 46, 34, 0.13);
  border-left: 1px dashed rgba(160, 46, 34, 0.5);
  border-right: 1px dashed rgba(160, 46, 34, 0.5);
}

.tl-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 10px 0 0;
  font-size: 11.5px;
  color: var(--muted-2);
}
.tl-legend span { display: inline-flex; align-items: center; gap: 6px; }
.tl-key { display: inline-block; }
.tl-key-bar { width: 22px; height: 8px; border-radius: 999px; background: var(--line-strong); }
.tl-key-tick { width: 2px; height: 12px; background: var(--muted-2); }
.tl-key-band { width: 14px; height: 12px; background: rgba(160, 46, 34, 0.13);
  border-left: 1px dashed rgba(160, 46, 34, 0.5); border-right: 1px dashed rgba(160, 46, 34, 0.5); }
.tl-blocknote { color: var(--muted-2); }

/* 「怎么读」那一段。放在图下面而不是上面：先看图，再解释，
   反过来读者还没看到图就先读了三行说明，等于没读。 */
.tl-read {
  margin: 10px 0 0;
  padding: 0 0 0 14px;
  border-left: 2px solid var(--line);
}
.tl-read p {
  margin: 0 0 8px;
  max-width: 82ch;
  font-size: 12.5px;
  line-height: 1.8;
  color: var(--muted);
}
.tl-read p:last-child { margin-bottom: 0; }
.tl-read b { color: var(--ink-2); font-weight: 500; }
.tl-em { color: var(--danger); }


