/* ============================================================================
   客小帮 AI 智慧拓客平台 · 基础组件库
   设计语言：科技蓝 · 浅色玻璃拟态（视觉标准 = 参考项目「创想工作台」theme.css / ui.css）
   ----------------------------------------------------------------------------
   1. 中性色一律偏蓝：边框用 --kx-border，文字用 --kx-text / --kx-text-2 / --kx-text-3，不用纯灰纯黑
   2. 大圆角：控件 10px、卡片 14px、弹层 20px、胶囊 999px
   3. 层次来自「玻璃半透明 + 蓝调投影 + 渐变强调」，主按钮＝渐变底 + 白字 + 蓝色投影
   4. 白底上的半透明叠加统一用 rgba(var(--kx-overlay-rgb), .02~.12)
   5. 样式只引用 tokens.css 的令牌（例外：白字与弹层的深色遮罩）
   6. 类名与旧版逐一保持兼容（39 个业务页面依赖），只重写视觉表现
   ========================================================================== */

/* ============================================================================
   1. 卡片
   ========================================================================== */
.kx-card {
  position: relative;
  background: var(--kx-surface);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-lg);
  /* 极淡蓝调投影：玻璃卡需要一点点高度层次，否则会和底纹糊在一起显「平」
     （参考项目的 .card 无投影是对的，但那是因为它叠在光晕底纹上；实测我方需要这一档） */
  box-shadow: var(--kx-shadow-xs);
  overflow: hidden;
}
/* 可交互卡片：悬停「边框转主题蓝 + 蓝调投影 + 上浮 2px」（对应参考项目 .card.hoverable） */
.kx-card--hover,
.kx-card--hoverable {
  transition: border-color var(--kx-dur) var(--kx-ease), box-shadow var(--kx-dur) var(--kx-ease),
              transform var(--kx-dur) var(--kx-ease);
}
.kx-card--hover:hover,
.kx-card--hoverable:hover {
  border-color: var(--kx-primary-border);
  box-shadow: var(--kx-card-glow);
  transform: translateY(-2px);
}
/* 强调卡片：顶部渐变描边（只在这类修饰类上点缀，不做全站装饰） */
.kx-card--accent::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  background: var(--kx-card-topline);
}
.kx-card--flush .kx-card__body,
.kx-card--flush-body .kx-card__body { padding: 0; }

/* 卡片头：56px 固定高度，标题 15px/600，底部 1px 蓝调分割线 */
.kx-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--kx-sp-3);
  flex-wrap: wrap;
  min-height: 56px;
  padding: 0 var(--kx-sp-6);
  border-bottom: 1px solid var(--kx-border);
}
.kx-card__title {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  margin: 0;
  font-size: var(--kx-fs-md);
  font-weight: var(--kx-fw-semibold);
  color: var(--kx-text);
  line-height: var(--kx-lh);
  min-width: 0;
}
/* 卡片标题图标：18×18 主色图标 + 主色浅底圆角块
   注意：icon() 组件会给 <svg> 写入内联 width/height（如 18px），内联样式优先级高于
   本规则，因此这里用 content-box + padding 把外框补到 24×24，避免用 !important。 */
.kx-card__title .kx-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: content-box;
  width: 18px;
  height: 18px;
  padding: 3px;
  border-radius: var(--kx-radius);
  font-size: 14px;
  flex: none;
  background: var(--kx-card-icon-soft, var(--kx-primary-soft));
  color: var(--kx-card-icon-deep, var(--kx-primary));
}
.kx-card__subtitle {
  margin-left: var(--kx-sp-2);
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-normal);
  color: var(--kx-text-3);
}
/* 允许右侧操作区收缩，避免在窄卡片里越界被裁切 */
.kx-card__extra {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}
.kx-card__extra::-webkit-scrollbar { display: none; }
.kx-card__body { padding: var(--kx-sp-6); }
/* 卡片底栏：极淡的深蓝内嵌底，与正文区分 */
.kx-card__foot {
  padding: var(--kx-sp-3) var(--kx-sp-6);
  border-top: 1px solid var(--kx-border);
  background: var(--kx-surface-3);
}

/* 色调变体：只影响标题图标的浅底色与图标色，不做顶部彩色描边 */
.kx-card--tone-blue   { --kx-card-icon-soft: var(--kx-c-blue-soft);   --kx-card-icon-deep: var(--kx-c-blue-deep); }
.kx-card--tone-cyan   { --kx-card-icon-soft: var(--kx-c-cyan-soft);   --kx-card-icon-deep: var(--kx-c-cyan-deep); }
.kx-card--tone-violet { --kx-card-icon-soft: var(--kx-c-violet-soft); --kx-card-icon-deep: var(--kx-c-violet-deep); }
.kx-card--tone-green  { --kx-card-icon-soft: var(--kx-c-green-soft);  --kx-card-icon-deep: var(--kx-c-green-deep); }
.kx-card--tone-orange { --kx-card-icon-soft: var(--kx-c-orange-soft); --kx-card-icon-deep: var(--kx-c-orange-deep); }
.kx-card--tone-pink   { --kx-card-icon-soft: var(--kx-c-pink-soft);   --kx-card-icon-deep: var(--kx-c-pink-deep); }

/* ============================================================================
   2. 页面头
   ========================================================================== */
.kx-page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--kx-sp-4);
  flex-wrap: wrap;
}
.kx-page-head__title {
  margin: 0;
  font-size: var(--kx-fs-3xl);
  font-weight: var(--kx-fw-bold);
  color: var(--kx-text);
  line-height: 1.4;
  letter-spacing: .5px;
}
.kx-page-head__desc {
  margin: var(--kx-sp-1) 0 0;
  font-size: var(--kx-fs);
  color: var(--kx-text-3);
  line-height: var(--kx-lh);
}
.kx-page-head__actions {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  flex-wrap: wrap;
  position: relative;   /* 供页头里的浮层（如营销中心的统计概览）定位 */
}

/* ============================================================================
   3. 网格
   ========================================================================== */
.kx-grid { display: grid; gap: var(--kx-sp-4); }
.kx-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.kx-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.kx-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.kx-grid--2-1 { grid-template-columns: 2fr 1fr; }
.kx-grid--1-2 { grid-template-columns: 1fr 2fr; }
.kx-row { display: flex; align-items: center; }
.kx-row--between { display: flex; align-items: center; justify-content: space-between; }
.kx-row--wrap { display: flex; align-items: center; flex-wrap: wrap; }
.kx-col { display: flex; flex-direction: column; }

/* ============================================================================
   4. 按钮
   ========================================================================== */
/* 次按钮：半透明叠加底 + 1px 蓝调边框 + 10px 圆角，hover 加深底色并上浮 1px */
.kx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--kx-sp-2);
  height: var(--kx-control-h);
  padding: 0 var(--kx-sp-5);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius);
  background: rgba(var(--kx-overlay-rgb), .05);
  color: var(--kx-text);
  font-size: var(--kx-fs);
  font-weight: var(--kx-fw-semibold);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: none;
  transition: background-color var(--kx-dur) var(--kx-ease), border-color var(--kx-dur) var(--kx-ease),
              color var(--kx-dur) var(--kx-ease), transform var(--kx-dur) var(--kx-ease);
}
.kx-btn:hover {
  background: rgba(var(--kx-overlay-rgb), .1);
  transform: translateY(-1px);
}
.kx-btn:active {
  background: rgba(var(--kx-overlay-rgb), .12);
  transform: translateY(0);
}
/* 焦点态：主色描边，不用系统默认样式 */
.kx-btn:focus-visible {
  outline: 2px solid var(--kx-primary);
  outline-offset: 1px;
}
.kx-btn .kx-icon { font-size: 14px; }

/* 主按钮：品牌渐变底 + 白字 + 蓝色投影（参考项目 .btn-primary） */
.kx-btn--primary {
  background: var(--kx-gradient-primary);
  border: none;
  color: #fff;
  box-shadow: var(--kx-shadow-btn);
}
.kx-btn--primary:hover {
  background: var(--kx-gradient-primary);
  filter: brightness(1.08);
  transform: translateY(-1px);
}
.kx-btn--primary:active {
  background: var(--kx-gradient-primary);
  filter: brightness(.98);
  transform: translateY(0);
}

/* 危险按钮：浅红半透明底 + 红字 + 红边框（不用实底，避免刺眼） */
.kx-btn--danger {
  background: var(--kx-danger-soft);
  border-color: var(--kx-danger-border);
  color: var(--kx-danger-text);
}
.kx-btn--danger:hover {
  background: color-mix(in srgb, var(--kx-danger) 20%, transparent);
  border-color: var(--kx-danger-border);
  color: var(--kx-danger-text);
}
.kx-btn--danger:active {
  background: color-mix(in srgb, var(--kx-danger) 26%, transparent);
  border-color: var(--kx-danger-border);
  color: var(--kx-danger-text);
}

/* 语义色按钮：软底 + 同色边框/文字（口径同 --danger，一排按钮并排时不互相抢眼）
   info 蓝=查看类 / success 绿=确认类 / warning 橙=修改类 / violet 紫=AI 类 */
.kx-btn--info,
.kx-btn--success,
.kx-btn--warning,
.kx-btn--violet { border-width: 1px; border-style: solid; }

.kx-btn--info    { background: var(--kx-c-blue-soft);   border-color: var(--kx-c-blue-border);   color: var(--kx-c-blue-deep); }
.kx-btn--success { background: var(--kx-c-green-soft);  border-color: var(--kx-c-green-border);  color: var(--kx-c-green-deep); }
.kx-btn--warning { background: var(--kx-c-orange-soft); border-color: var(--kx-c-orange-border); color: var(--kx-c-orange-deep); }
.kx-btn--violet  { background: var(--kx-c-violet-soft); border-color: var(--kx-c-violet-border); color: var(--kx-c-violet-deep); }

.kx-btn--info:hover,
.kx-btn--success:hover,
.kx-btn--warning:hover,
.kx-btn--violet:hover { filter: brightness(1.06); transform: translateY(-1px); }

.kx-btn--info:active,
.kx-btn--success:active,
.kx-btn--warning:active,
.kx-btn--violet:active { filter: brightness(.96); transform: translateY(0); }

.kx-btn--info:disabled, .kx-btn--info.is-disabled,
.kx-btn--success:disabled, .kx-btn--success.is-disabled,
.kx-btn--warning:disabled, .kx-btn--warning.is-disabled,
.kx-btn--violet:disabled, .kx-btn--violet.is-disabled { opacity: .55; filter: none; }

/* 文字按钮：透明底，hover 主色浅底（对应参考项目 .btn-ghost） */
.kx-btn--text {
  height: var(--kx-control-h);
  padding: 0 var(--kx-sp-5);
  border-color: transparent;
  background: transparent;
  color: var(--kx-primary);
}
.kx-btn--text:hover {
  background: var(--kx-primary-soft);
  border-color: transparent;
  color: var(--kx-primary-hover);
}
.kx-btn--text:active { background: var(--kx-primary-soft); }
.kx-btn--danger-text {
  height: var(--kx-control-h);
  padding: 0 var(--kx-sp-5);
  border-color: transparent;
  background: transparent;
  color: var(--kx-danger-text);
}
.kx-btn--danger-text:hover {
  background: var(--kx-danger-soft);
  border-color: transparent;
  color: var(--kx-danger-text);
}
.kx-btn--danger-text:active { background: var(--kx-danger-soft); }

/* 尺寸：小按钮 12px 字 / 8px 圆角，大按钮 44px 高 */
.kx-btn--sm {
  height: var(--kx-control-h-sm);
  padding: 0 var(--kx-sp-3);
  border-radius: var(--kx-radius-sm);
  font-size: var(--kx-fs-xs);
}
.kx-btn--lg { height: var(--kx-control-h-lg); padding: 0 var(--kx-sp-6); font-size: var(--kx-fs-lg); }
.kx-btn--block { width: 100%; }
/* 图标按钮：正方形 + 9px 圆角，hover 主色浅底（对应参考项目 .icon-btn） */
.kx-btn--icon {
  width: var(--kx-control-h);
  padding: 0;
  border-radius: 9px;
  border-color: transparent;
  background: transparent;
  color: var(--kx-text-2);
}
.kx-btn--icon:hover {
  background: var(--kx-primary-soft);
  border-color: transparent;
  color: var(--kx-primary);
}
.kx-btn--icon:active { background: var(--kx-primary-soft); }
.kx-btn--icon.kx-btn--sm { width: var(--kx-control-h-sm); }
.kx-btn--icon.kx-btn--lg { width: var(--kx-control-h-lg); }

/* 禁用：中性色底 + 不可点击；主按钮/危险按钮保留品牌色但整体降不透明度 */
.kx-btn:disabled,
.kx-btn.is-disabled {
  cursor: not-allowed;
  background: var(--kx-surface-3);
  border-color: var(--kx-border);
  color: var(--kx-text-4);
  transform: none;
}
.kx-btn--primary:disabled,
.kx-btn--primary.is-disabled {
  background: var(--kx-gradient-primary);
  border: none;
  color: #fff;
  box-shadow: none;
  opacity: .45;
  transform: none;
}
.kx-btn--danger:disabled,
.kx-btn--danger.is-disabled {
  background: var(--kx-danger-soft);
  border-color: var(--kx-danger-border);
  color: var(--kx-danger-text);
  transform: none;
  opacity: .45;
}

/* ============================================================================
   5. 标签 / 徽标
   ========================================================================== */
/* 标签：22px 高、胶囊形、同色浅底 + 同色描边 + 同色深字、12px（对齐参考项目 .badge/.chip 的胶囊语言） */
.kx-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--kx-sp-1);
  height: 22px;
  padding: 0 9px;
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-full);
  background: rgba(var(--kx-overlay-rgb), .04);
  color: var(--kx-text-2);
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-medium);
  line-height: 1;
  white-space: nowrap;
}
.kx-tag--default { background: rgba(var(--kx-overlay-rgb), .04); border-color: var(--kx-border); color: var(--kx-text-2); }
.kx-tag--primary { background: var(--kx-c-blue-soft);   border-color: var(--kx-c-blue-border);   color: var(--kx-c-blue-deep); }
.kx-tag--success { background: var(--kx-c-green-soft);  border-color: var(--kx-c-green-border);  color: var(--kx-c-green-deep); }
.kx-tag--warning { background: var(--kx-c-orange-soft); border-color: var(--kx-c-orange-border); color: var(--kx-c-orange-deep); }
.kx-tag--danger  { background: var(--kx-c-red-soft);    border-color: var(--kx-c-red-border);    color: var(--kx-c-red-deep); }
.kx-tag--info    { background: var(--kx-c-cyan-soft);   border-color: var(--kx-c-cyan-border);   color: var(--kx-c-cyan-deep); }
.kx-tag--violet  { background: var(--kx-c-violet-soft); border-color: var(--kx-c-violet-border); color: var(--kx-c-violet-deep); }
.kx-tag--cyan    { background: var(--kx-c-cyan-soft);   border-color: var(--kx-c-cyan-border);   color: var(--kx-c-cyan-deep); }
.kx-tag--accent  { background: var(--kx-accent-50);     border-color: var(--kx-c-violet-border); color: var(--kx-accent-deep); }

/* 胶囊标签：全圆角，同样是「浅底 + 同色描边 + 深色文字」 */
.kx-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--kx-sp-1);
  height: 22px;
  padding: 0 9px;
  border: 1px solid var(--kx-c-blue-border);
  border-radius: var(--kx-radius-full);
  background: var(--kx-c-blue-soft);
  color: var(--kx-c-blue-deep);
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-medium);
  line-height: 1;
  white-space: nowrap;
}
/* 色点：与文字同色，用于平台/分组等需要一眼区分的列 */
.kx-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.kx-pill--blue   { background: var(--kx-c-blue-soft);   border-color: var(--kx-c-blue-border);   color: var(--kx-c-blue-deep); }
.kx-pill--cyan   { background: var(--kx-c-cyan-soft);   border-color: var(--kx-c-cyan-border);   color: var(--kx-c-cyan-deep); }
.kx-pill--violet { background: var(--kx-c-violet-soft); border-color: var(--kx-c-violet-border); color: var(--kx-c-violet-deep); }
.kx-pill--green  { background: var(--kx-c-green-soft);  border-color: var(--kx-c-green-border);  color: var(--kx-c-green-deep); }
.kx-pill--orange { background: var(--kx-c-orange-soft); border-color: var(--kx-c-orange-border); color: var(--kx-c-orange-deep); }
.kx-pill--pink   { background: var(--kx-c-pink-soft);   border-color: var(--kx-c-pink-border);   color: var(--kx-c-pink-deep); }
.kx-pill--gray   { background: rgba(var(--kx-overlay-rgb), .04); border-color: var(--kx-border);  color: var(--kx-text-2); }
.kx-pill--plain::before { display: none; }

/* 徽标：计数点形态，胶囊圆角 + 白字 */
.kx-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--kx-radius-full);
  background: var(--kx-danger);
  color: #fff;
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-medium);
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   6. 统计卡
   ========================================================================== */
.kx-stat {
  display: flex;
  flex-direction: column;
  gap: var(--kx-sp-3);
  padding: var(--kx-sp-5) var(--kx-sp-6);
  background: var(--kx-surface);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-lg);
  box-shadow: none;
  position: relative;
  overflow: hidden;
  transition: box-shadow var(--kx-dur) var(--kx-ease), border-color var(--kx-dur) var(--kx-ease);
}
/* 右上角装饰光斑（参考项目 .kpi-card::after） */
.kx-stat::after {
  content: '';
  position: absolute;
  right: -30px;
  top: -30px;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--kx-primary-100), transparent 70%);
  pointer-events: none;
}
/* 内容压在装饰光斑之上 */
.kx-stat__top,
.kx-stat__label,
.kx-stat__value,
.kx-stat__foot { position: relative; z-index: 1; }
/* 悬停只做「边框转主题蓝 + 蓝调投影」，不做位移 */
.kx-stat:hover {
  border-color: var(--kx-primary-border);
  box-shadow: var(--kx-shadow-xs);
}
.kx-stat__top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--kx-sp-3); }
.kx-stat__label {
  font-size: var(--kx-fs-xs);
  color: var(--kx-text-3);
  line-height: var(--kx-lh);
  margin-top: var(--kx-sp-1);
}
/* 图标：44×44 半透明同色底 + 同色图标（色调由 --kx-stat-soft / --kx-stat-deep 注入） */
.kx-stat__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--kx-stat-soft, var(--kx-c-blue-soft));
  color: var(--kx-stat-deep, var(--kx-c-blue));
  font-size: 18px;
  flex: none;
}
/* 兼容旧调用方式（只给图标指定色调，不带卡片级变体） */
.kx-stat__icon--accent  { --kx-stat-soft: var(--kx-c-violet-soft); --kx-stat-deep: var(--kx-c-violet); }
.kx-stat__icon--info    { --kx-stat-soft: var(--kx-c-cyan-soft);   --kx-stat-deep: var(--kx-c-cyan); }
.kx-stat__icon--success { --kx-stat-soft: var(--kx-c-green-soft);  --kx-stat-deep: var(--kx-c-green); }
.kx-stat__icon--violet  { --kx-stat-soft: var(--kx-c-violet-soft); --kx-stat-deep: var(--kx-c-violet); }
.kx-stat__icon--cyan    { --kx-stat-soft: var(--kx-c-cyan-soft);   --kx-stat-deep: var(--kx-c-cyan); }
.kx-stat__icon--warning { --kx-stat-soft: var(--kx-c-orange-soft); --kx-stat-deep: var(--kx-c-orange); }
.kx-stat__icon--danger  { --kx-stat-soft: var(--kx-c-red-soft);    --kx-stat-deep: var(--kx-c-red); }
.kx-stat__icon--pink    { --kx-stat-soft: var(--kx-c-pink-soft);   --kx-stat-deep: var(--kx-c-pink); }

/* 卡片色调变体：只提供图标底色与图标色两个变量 */
.kx-stat--blue   { --kx-stat-soft: var(--kx-c-blue-soft);   --kx-stat-deep: var(--kx-c-blue); }
.kx-stat--cyan   { --kx-stat-soft: var(--kx-c-cyan-soft);   --kx-stat-deep: var(--kx-c-cyan); }
.kx-stat--violet { --kx-stat-soft: var(--kx-c-violet-soft); --kx-stat-deep: var(--kx-c-violet); }
.kx-stat--green  { --kx-stat-soft: var(--kx-c-green-soft);  --kx-stat-deep: var(--kx-c-green); }
.kx-stat--orange { --kx-stat-soft: var(--kx-c-orange-soft); --kx-stat-deep: var(--kx-c-orange); }
.kx-stat--pink   { --kx-stat-soft: var(--kx-c-pink-soft);   --kx-stat-deep: var(--kx-c-pink); }

/* 数值：26px/700，统一中性色，不做彩色数值 */
.kx-stat__value {
  font-size: var(--kx-fs-4xl);
  font-weight: var(--kx-fw-bold);
  color: var(--kx-text);
  line-height: 1.2;
  letter-spacing: .5px;
  font-variant-numeric: tabular-nums;
}
.kx-stat__value small {
  margin-left: var(--kx-sp-1);
  font-size: var(--kx-fs);
  font-weight: var(--kx-fw-normal);
  color: var(--kx-text-3);
}
.kx-stat__foot { display: flex; align-items: center; gap: var(--kx-sp-1); font-size: var(--kx-fs-xs); color: var(--kx-text-3); }
.kx-stat__delta {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--kx-fs-2xs);
  font-weight: var(--kx-fw-medium);
  font-variant-numeric: tabular-nums;
}
.kx-stat__delta.is-up { color: var(--kx-success); }
.kx-stat__delta.is-down { color: var(--kx-danger); }
.kx-stat__delta.is-flat { color: var(--kx-text-3); }

/* ============================================================================
   7. 表单控件
   ========================================================================== */
.kx-input,
.kx-textarea,
.kx-select {
  width: 100%;
  height: var(--kx-control-h);
  padding: 0 var(--kx-sp-3);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius);
  background: rgba(var(--kx-overlay-rgb), .05);
  color: var(--kx-text);
  font-size: var(--kx-fs);
  font-family: inherit;
  line-height: var(--kx-lh);
  outline: none;
  transition: border-color var(--kx-dur) var(--kx-ease), box-shadow var(--kx-dur) var(--kx-ease);
}
/* 多行输入：高度自适应内容 */
.kx-textarea {
  height: auto;
  min-height: 76px;
  padding: var(--kx-sp-1) var(--kx-sp-3);
  resize: vertical;
  line-height: var(--kx-lh);
}
.kx-select { padding-right: 28px; cursor: pointer; appearance: none; background-image: none; }
.kx-input::placeholder,
.kx-textarea::placeholder { color: var(--kx-text-placeholder); }
.kx-input:hover,
.kx-textarea:hover,
.kx-select:hover { border-color: var(--kx-primary-hover); }
/* 聚焦：边框转主色 + 3px 主色柔光焦点环，不出现系统 outline */
.kx-input:focus,
.kx-textarea:focus,
.kx-select:focus {
  border-color: var(--kx-primary);
  box-shadow: 0 0 0 3px var(--kx-primary-100);
}
.kx-input:disabled,
.kx-textarea:disabled,
.kx-select:disabled {
  background: var(--kx-surface-3);
  color: var(--kx-text-4);
  cursor: not-allowed;
}

.kx-input-wrap { position: relative; display: flex; align-items: center; width: 100%; }
.kx-input-wrap .kx-input { padding-right: 34px; }
.kx-input__suffix {
  position: absolute;
  right: var(--kx-sp-2);
  display: inline-flex;
  align-items: center;
  color: var(--kx-text-3);
  cursor: pointer;
}
.kx-input__suffix:hover { color: var(--kx-primary); }

/* 多选下拉：关起来只显示已选内容，点开才浮出可勾选的选项面板。
   （原生 <select multiple> 没有「收起来」的形态，会把选项一行行全摊在页面上） */
.kx-multi { position: relative; width: 100%; }
.kx-multi__trigger {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  height: var(--kx-control-h);
  /* 右侧 52px：留给展开箭头（right 26）和清空按钮（right 8） */
  padding: 0 52px 0 var(--kx-sp-3);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius);
  background: rgba(var(--kx-overlay-rgb), .05);
  color: var(--kx-text);
  font-size: var(--kx-fs);
  font-family: inherit;
  line-height: var(--kx-lh);
  text-align: left;
  cursor: pointer;
  outline: none;
  transition: border-color var(--kx-dur) var(--kx-ease), box-shadow var(--kx-dur) var(--kx-ease);
}
.kx-multi__trigger:hover { border-color: var(--kx-primary-hover); }
.kx-multi.is-open .kx-multi__trigger {
  border-color: var(--kx-primary);
  box-shadow: 0 0 0 3px var(--kx-primary-100);
}
.kx-multi__trigger:disabled {
  background: var(--kx-surface-3);
  color: var(--kx-text-4);
  cursor: not-allowed;
}
/* 展开箭头：纯 CSS 三角，省一次图标请求 */
.kx-multi__trigger::after {
  content: '';
  position: absolute;
  right: 26px;
  top: 50%;
  margin-top: -2px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid var(--kx-text-3);
  transition: transform var(--kx-dur) var(--kx-ease);
}
.kx-multi.is-open .kx-multi__trigger::after,
.kx-multi__trigger:disabled::after { transform: none; }
.kx-multi.is-open .kx-multi__trigger::after {
  margin-top: -3px;
  transform: rotate(180deg);
}
.kx-multi__text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.kx-multi__text.is-placeholder { color: var(--kx-text-placeholder); }
/* 面板由 JS 挂到 document.body 上并用 fixed 定位（弹窗/滚动容器的 overflow 会裁掉 absolute 面板），
   所以这里只补布局，定位与宽高交给内联样式 */
.kx-multi__panel {
  top: auto;
  right: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
/* ⚠ 必须显式写：上面那条 display:flex 是作者样式，会盖掉浏览器默认的 [hidden]{display:none}，
   不补这条「面板收起来」就只是逻辑上关了、视觉上还留在页面上 */
.kx-multi__panel[hidden] { display: none; }
.kx-multi__search { flex: none; }
.kx-multi__list { flex: 1 1 auto; max-height: 240px; overflow-y: auto; }
.kx-multi__item { justify-content: space-between; outline: none; }
.kx-multi__item:focus-visible {
  background: rgba(var(--kx-overlay-rgb), .07);
  color: var(--kx-text);
}
.kx-multi__item.is-active { color: var(--kx-primary); font-weight: var(--kx-fw-medium); }
.kx-multi__item.is-disabled { color: var(--kx-text-4); cursor: not-allowed; }
.kx-multi__check { flex: none; color: var(--kx-primary); }
.kx-multi__check[hidden] { display: none; }
.kx-multi__empty { padding: 10px 12px; font-size: var(--kx-fs-xs); color: var(--kx-text-3); }

/* 表单字段 */
.kx-form { width: 100%; }
.kx-form-host { width: 100%; }
.kx-form__item { display: flex; flex-direction: column; gap: var(--kx-sp-2); }
.kx-form__label {
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-semibold);
  color: var(--kx-text-2);
  letter-spacing: .5px;
  line-height: 1.4;
}
.kx-form__required { margin-left: 2px; color: var(--kx-danger); }
.kx-form__tip { font-size: var(--kx-fs-xs); color: var(--kx-text-3); line-height: var(--kx-lh); }
/* 参数说明「?」（tipMode='popover'）：灰色圆形问号图标，默认就看得见，点一下弹说明。
   注意：sprite 里没有 ri-question-line，只有 ri-question-fill —— 填充圆带问号镂空，
   正好当「浅灰底 + 问号」用，不用再叠背景色。 */
.kx-form__tip-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 5px;
  padding: 0;
  vertical-align: -3px;
  border: 0;
  background: transparent;
  color: var(--kx-text-3);
  cursor: pointer;
  transition: color .15s;
}
.kx-form__tip-btn:hover,
.kx-form__tip-btn.is-open { color: var(--kx-primary); }
/* 说明气泡：fixed 挂到 body，位置由 JS 计算（避免被表单容器的 overflow 裁掉） */
.kx-form__tip-pop {
  position: fixed;
  z-index: var(--kx-z-modal);
  max-width: 280px;
  padding: var(--kx-sp-2) var(--kx-sp-3);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-sm);
  background: var(--kx-surface-solid);
  box-shadow: 0 8px 24px -8px rgba(0, 0, 0, .28);
  color: var(--kx-text-2);
  font-size: var(--kx-fs-xs);
  line-height: var(--kx-lh);
  white-space: normal;
  word-break: break-word;
}
.kx-form__error { font-size: var(--kx-fs-xs); color: var(--kx-danger-text); line-height: var(--kx-lh); }
.kx-form__control { width: 100%; }
/* 数值区间控件（如「年龄 [18] 岁 ~ [35] 岁」）：两个数字框 + 分隔符 + 两侧单位 */
.kx-range { display: flex; align-items: center; gap: var(--kx-sp-2); }
.kx-range__input { flex: 0 0 88px; width: 88px; }
.kx-range__sep { color: var(--kx-text-3); }
.kx-range__unit { font-size: var(--kx-fs-xs); color: var(--kx-text-3); }
/* 落单字段撑满整行时区间控件跟着铺开，别在右侧留半行空白 */
.kx-form__item--span-2 .kx-range { width: 100%; }
.kx-form__item--span-2 .kx-range__input { flex: 1 1 88px; width: auto; }
.kx-form__item.is-error .kx-input,
.kx-form__item.is-error .kx-textarea,
.kx-form__item.is-error .kx-select { border-color: var(--kx-danger-border); }
.kx-form__item.is-error .kx-input:focus,
.kx-form__item.is-error .kx-textarea:focus,
.kx-form__item.is-error .kx-select:focus { box-shadow: 0 0 0 3px var(--kx-danger-soft); }

/* 「跟随公共配置」：跟随态下控件只读（纯视觉禁用 —— 滑块 / 多选下拉 / 多行话术
   没有统一的 disabled 入口，逐个控件改实现既啰嗦又容易漏） */
.kx-form__item.is-following .kx-form__control { pointer-events: none; opacity: .55; }
/* 托管字段（带「跟随 / 单独指定」开关）的标题行排成一行：名称 + ? + 标签 + 开关（开关靠右） */
.kx-form__item.is-managed > .kx-form__label { display: flex; flex-wrap: wrap; align-items: center; }
/* 跟随态下把整个控件区收起来（opt-in，见 mountFollowToggles 的 collapseWhenFollowing）：
   值由公共参数决定，本地填的值不参与提交 —— 收起来整页只剩「参数名 + 开关」，更紧凑 */
.kx-form__item.is-collapsed .kx-form__control { display: none; }

/* ---------------------------------------------------------------------------
   公共参数页（功能工场 → 公共参数）的「一行一项」列表
   见 pages/script-param.js 的说明：这一页每项都带长摘要 + 开关 + 例外入口，
   通用表单的两列网格会把卡片撑成参差的阶梯，标题行也被挤成三行。
   --------------------------------------------------------------------------- */
/* 关掉通用表单的栅格与 16px 间距（那是给普通表单用的），由下面的行布局接管 */
.kx-param__group .kx-form > div { display: block !important; }
.kx-param__group .kx-form__tip:empty,
.kx-param__group .kx-form__error:empty { display: none; }

.kx-param__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(220px, 340px) auto;
  grid-template-areas: "meta control extra";
  align-items: center;
  gap: var(--kx-sp-2) var(--kx-sp-5);
  padding: var(--kx-sp-4) var(--kx-sp-6);
  border-top: 1px solid var(--kx-border-2);
}
.kx-param__row:first-child { border-top: 0; }
/* 宽控件（话术 / 多选 / 多行文本）另起一行铺满，否则 300px 里没法编辑 */
.kx-param__row--wide {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "meta extra" "control control";
  align-items: start;
}
.kx-param__row > .kx-form__label,
.kx-param__row > .kx-form__control,
.kx-param__row > .kx-param__extra { min-width: 0; }
.kx-param__row > .kx-form__label { grid-area: meta; }
.kx-param__row > .kx-form__control { grid-area: control; }
.kx-param__row > .kx-param__extra { grid-area: extra; justify-self: end; }
.kx-param__row--wide > .kx-form__control { margin-top: var(--kx-sp-1); }
/* 数字 / 下拉 / 开关不需要占满控件栏 */
.kx-param__row--narrow > .kx-form__control { max-width: 180px; }
/* 布尔行：取值开关前面挂一个「取值」前缀，跟右侧「是否托管」的开关区分开 */
.kx-param__control--inline { display: flex; align-items: center; gap: var(--kx-sp-2); }
.kx-param__vlabel { flex: none; font-size: var(--kx-fs-xs); color: var(--kx-text-3); }
/* 多选项（如 IP 归属地白名单，34 个省）在原生 multiple select 里会把整列选项铺开、
   把行撑到 120px+；这里固定高度、内部滚动，行高才可控 */
.kx-param__group select[multiple] { height: 96px; }
/* 未托管的行：控件本就 disabled，再压一档对比度，一眼能看出「这行没在起作用」 */
.kx-param__row.is-off > .kx-form__control { opacity: .6; }

.kx-param__desc {
  display: block;
  margin-top: 2px;
  font-weight: 400;
  letter-spacing: 0;
  font-size: var(--kx-fs-xs);
  color: var(--kx-text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.kx-param__extra {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-3);
  flex: none;
}
.kx-param__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--kx-sp-2);
  flex: none;
}
/* 定宽 + 右对齐：开关的位置不随「已托管 / 用功能默认」的字数左右漂移 */
.kx-param__state {
  min-width: 5.5em;
  text-align: right;
  font-size: var(--kx-fs-xs);
  color: var(--kx-text-3);
  white-space: nowrap;
}
/* 文案是定长的「按功能例外」，这里只兜底一个最小宽度，保证三栏对齐 */
.kx-param__exc { min-width: 104px; }
/* 有例外时把入口点亮，避免「设过例外」这件事只藏在数字里 */
.kx-param__exc.is-on { border-color: var(--kx-primary-border); color: var(--kx-primary); }

/* 页头按钮分组用的竖分隔线 */
.kx-param__actions {
  gap: var(--kx-sp-2);
  /* 这一排（作用域 + 7 个按钮 + 2 条分隔线）**永远一行**：一旦折行，分隔线会单独占一行，
     按钮也会分成上下两排、文字对不齐。空间不够时让上面的「标题 / 说明」整块先换行。 */
  flex-wrap: nowrap;
}
/* 要挤在一行，内边距比默认按钮收紧一档 */
.kx-param__actions .kx-btn { padding: 0 var(--kx-sp-4); }
.kx-param__sep {
  width: 1px;
  height: 20px;
  background: var(--kx-border);
  flex: none;
  margin: 0 var(--kx-sp-1);
}

/* ---------------------------------------------------------------------------
   「按功能例外」弹窗：批量设置块 + 每个功能一行
   （原来是每行套一个 .kx-card 叠在弹窗里，双层描边/投影显得很重，改成平铺列表）
   --------------------------------------------------------------------------- */
.kx-param__batch {
  margin-bottom: var(--kx-sp-4);
  padding: var(--kx-sp-3) var(--kx-sp-4);
  border: 1px dashed var(--kx-primary-border);
  border-radius: var(--kx-radius);
  background: var(--kx-primary-50);
}
.kx-param__batch-head {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  margin-bottom: var(--kx-sp-3);
  font-size: var(--kx-fs-sm);
  font-weight: var(--kx-fw-semibold);
  color: var(--kx-text);
}
.kx-param__batch-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(150px, 220px) auto;
  align-items: center;
  gap: var(--kx-sp-3);
}
.kx-param__batch-body > * { min-width: 0; }

.kx-param__excrow {
  padding: var(--kx-sp-3) 0;
  border-top: 1px solid var(--kx-border-2);
}
.kx-param__excrow:first-child { border-top: 0; }
.kx-param__exchead {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-3);
  margin-bottom: var(--kx-sp-2);
}
.kx-param__excname { font-size: var(--kx-fs); font-weight: var(--kx-fw-medium); min-width: 0; }
.kx-param__excdefault { flex: none; font-size: var(--kx-fs-xs); color: var(--kx-text-3); white-space: nowrap; }
.kx-param__exchead .kx-param__toggle { margin-left: auto; }
.kx-param__excact { margin-top: var(--kx-sp-2); }

/* 复选框：16×16 / 8px 圆角，选中为品牌渐变底 */
.kx-checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--kx-sp-2);
  font-size: var(--kx-fs);
  color: var(--kx-text);
  cursor: pointer;
}
.kx-checkbox__box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-sm);
  background: rgba(var(--kx-overlay-rgb), .05);
  color: #fff;
  font-size: 11px;
  flex: none;
  transition: background-color var(--kx-dur-fast) var(--kx-ease), border-color var(--kx-dur-fast) var(--kx-ease);
}
.kx-checkbox:hover .kx-checkbox__box { border-color: var(--kx-primary-border); }
.kx-checkbox.is-checked .kx-checkbox__box { background: var(--kx-gradient-primary); border-color: transparent; }
.kx-checkbox.is-indeterminate .kx-checkbox__box { background: var(--kx-gradient-primary); border-color: transparent; }
.kx-checkbox__label { user-select: none; }
.kx-checkbox-group,
.kx-radio-group { display: flex; flex-wrap: wrap; gap: var(--kx-sp-3) var(--kx-sp-5); align-items: center; }

/* 开关：40 宽 / 22 高 / 16 滑块，选中态用品牌渐变填充 */
.kx-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 40px;
  height: 22px;
  border-radius: var(--kx-radius-full);
  background: rgba(var(--kx-overlay-rgb), .12);
  cursor: pointer;
  flex: none;
  transition: background-color var(--kx-dur) var(--kx-ease);
}
.kx-switch::after {
  content: '';
  position: absolute;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--kx-shadow-xs);
  transition: transform var(--kx-dur) var(--kx-ease);
}
.kx-switch.is-checked { background: var(--kx-gradient-primary); }
.kx-switch.is-checked::after { transform: translateX(18px); }

/* 多值 + 逐行开关：一行一条 + 行首启用开关（业务参数 ui=line_switch，值仍是多行文本） */
.kx-lineswitch { display: flex; flex-direction: column; gap: var(--kx-sp-2); }
.kx-lineswitch__list { display: flex; flex-direction: column; gap: var(--kx-sp-2); }
.kx-lineswitch__row { display: flex; align-items: center; gap: var(--kx-sp-2); }
.kx-lineswitch__toggle { display: inline-flex; align-items: center; flex: none; cursor: pointer; }
.kx-lineswitch__row .kx-input { flex: 1; min-width: 0; }
.kx-lineswitch__del { flex: none; color: var(--kx-text-3); }
.kx-lineswitch__del:hover { color: var(--kx-danger); }
.kx-lineswitch__foot { display: flex; align-items: center; gap: var(--kx-sp-3); flex-wrap: wrap; }
.kx-lineswitch__hint { font-size: var(--kx-fs-xs); color: var(--kx-text-3); }

/* 标签输入：胶囊标签 + 行内输入框（业务字段 ui=tags，值仍是多行文本） */
.kx-taginput {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kx-sp-1) var(--kx-sp-2);
  min-height: var(--kx-control-h);
  padding: 4px var(--kx-sp-2);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius);
  background: rgba(var(--kx-overlay-rgb), .05);
  cursor: text;
  transition: border-color var(--kx-dur) var(--kx-ease), box-shadow var(--kx-dur) var(--kx-ease);
}
.kx-taginput:focus-within { border-color: var(--kx-primary); box-shadow: 0 0 0 3px var(--kx-primary-soft); }
.kx-taginput.is-disabled { cursor: default; opacity: .6; }
.kx-taginput__list { display: contents; }
.kx-taginput__tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding: 2px 7px;
  border: 1px solid var(--kx-c-blue-border);
  border-radius: var(--kx-radius-full);
  background: var(--kx-c-blue-soft);
  color: var(--kx-c-blue-deep);
  font-size: var(--kx-fs-xs);
  line-height: 1.6;
}
.kx-taginput__text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-taginput__del { display: inline-flex; align-items: center; cursor: pointer; opacity: .6; }
.kx-taginput__del:hover { opacity: 1; }
/* 行内输入框：去掉 .kx-input 自带的框与底色，视觉由外层 .kx-taginput 承担 */
.kx-taginput__input {
  flex: 1 1 120px;
  width: auto;
  min-width: 120px;
  height: 22px;
  padding: 0;
  border: none;
  background: transparent;
  box-shadow: none;
}
.kx-taginput__input:focus { border: none; box-shadow: none; }
.kx-form__item.is-error .kx-taginput { border-color: var(--kx-danger-border); }

/* ============================================================================
   8. 头像 / 进度 / 空状态
   ========================================================================== */
/* 头像：圆形 + 品牌渐变底 + 内阴影 + 文字阴影 */
.kx-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--kx-radius-full);
  background: var(--kx-gradient-primary);
  color: #fff;
  font-size: var(--kx-fs);
  font-weight: var(--kx-fw-semibold);
  flex: none;
  object-fit: cover;
  text-shadow: 0 1px 4px rgba(var(--kx-overlay-rgb), .4);
  box-shadow: inset 0 -6px 12px rgba(var(--kx-overlay-rgb), .25);
}
.kx-avatar--sm { width: 24px; height: 24px; font-size: var(--kx-fs-xs); }
.kx-avatar--lg { width: 40px; height: 40px; font-size: var(--kx-fs-lg); }

/* 进度条：6px 轨道 + 全圆角 + 渐变填充（色调变体走 --kx-c-*-grad） */
.kx-progress {
  position: relative;
  height: 6px;
  border-radius: var(--kx-radius-full);
  background: rgba(var(--kx-overlay-rgb), .08);
  overflow: hidden;
}
.kx-progress__bar {
  height: 100%;
  border-radius: var(--kx-radius-full);
  background: var(--kx-c-blue-grad);
  transition: width var(--kx-dur-slow) var(--kx-ease);
}
.kx-progress--success .kx-progress__bar { background: var(--kx-c-green-grad); }
.kx-progress--warning .kx-progress__bar { background: var(--kx-c-orange-grad); }
.kx-progress--danger .kx-progress__bar { background: var(--kx-c-red-grad); }
.kx-progress--cyan .kx-progress__bar { background: var(--kx-c-cyan-grad); }
.kx-progress--violet .kx-progress__bar { background: var(--kx-c-violet-grad); }
.kx-progress--pink .kx-progress__bar { background: var(--kx-c-pink-grad); }

.kx-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--kx-sp-2);
  padding: var(--kx-sp-10) var(--kx-sp-6);
  text-align: center;
}
/* 空状态图标圈：76px 圆形虚线框 */
.kx-empty__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  border: 1px dashed var(--kx-border-strong);
  border-radius: var(--kx-radius-full);
  background: rgba(var(--kx-overlay-rgb), .04);
  color: var(--kx-text-3);
  font-size: 26px;
  line-height: 1;
}
.kx-empty__text { font-size: var(--kx-fs); color: var(--kx-text-2); }
.kx-empty__desc { font-size: var(--kx-fs-xs); color: var(--kx-text-3); }

.kx-spin {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 2px solid rgba(var(--kx-overlay-rgb), .1);
  border-top-color: var(--kx-primary);
  border-radius: 50%;
  animation: kx-spin .7s linear infinite;
}

/* ============================================================================
   9. 表格
   ========================================================================== */
.kx-table-host { display: flex; flex-direction: column; min-width: 0; }
.kx-table-wrap {
  background: var(--kx-surface);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-lg);
  overflow: hidden;
}
/* 卡片内的表格：外层描边交给卡片本身，避免出现双层边框（参考项目表格无边框包裹） */
.kx-card__body .kx-table-wrap,
.kx-card--flush .kx-table-wrap,
.kx-card--flush-body .kx-table-wrap {
  border: 0;
  border-radius: 0;
  background: transparent;
}
.kx-table__scroll { position: relative; overflow: auto; }
.kx-table__scroll--fixed { overflow-y: auto; }
.kx-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 0;
  margin: 0;
  font-size: var(--kx-fs);
  color: var(--kx-text);
}
.kx-table__cell {
  padding: var(--kx-sp-3);
  text-align: left;
  border-bottom: 1px solid var(--kx-border-soft);
  background: transparent;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: var(--kx-lh);
}
/* 表头：透明底 + 12px/600 淡蓝字 + 1px 下边框（参考项目 th 无底色） */
.kx-table__thead .kx-table__cell {
  background: transparent;
  color: var(--kx-text-3);
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-semibold);
  letter-spacing: 1px;
  padding: 10px var(--kx-sp-3);
  border-bottom: 1px solid var(--kx-border);
  user-select: none;
}
.kx-table__tbody tr:last-child .kx-table__cell { border-bottom: 0; }
/* 吸顶表头必须有实底，否则滚动时内容会透出 */
.kx-table--fixed .kx-table__thead .kx-table__cell {
  position: sticky;
  top: 0;
  z-index: 4;
  background: var(--kx-surface-fixed);
}

.kx-table__cell--center { text-align: center; padding-left: var(--kx-sp-2); padding-right: var(--kx-sp-2); }
.kx-table__cell--right { text-align: right; }
/* 数据单元格内只有单个文本容器时，让省略号真正作用在该容器上：
   td 的 text-overflow 管不到子元素自身的溢出，子元素会「硬切」而没有省略号，
   长文本（如机型/系统版本串）看起来像串到了相邻列。
   只作用于 tbody；排除标签/胶囊/进度条/操作组/复选框等自带布局的元素。 */
.kx-table__tbody .kx-table__cell > span:only-child:not(.kx-tag):not(.kx-pill):not(.kx-progress):not(.kx-bp__op):not(.kx-checkbox),
.kx-table__tbody .kx-table__cell > div:only-child:not(.kx-tag):not(.kx-pill):not(.kx-progress):not(.kx-bp__op):not(.kx-checkbox) {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
.kx-table__cell.is-sortable { cursor: pointer; transition: color var(--kx-dur) var(--kx-ease); }
.kx-table__cell.is-sortable:hover,
.kx-table__cell.is-sorted { color: var(--kx-primary); }
.kx-table__th-inner { display: inline-flex; align-items: center; gap: var(--kx-sp-1); }
.kx-table__sorter { display: inline-flex; flex-direction: column; color: var(--kx-text-4); }
.kx-table__sorter .kx-icon { display: block; margin: -2px 0; }
.kx-table__sorter-up.is-on,
.kx-table__sorter-down.is-on { color: var(--kx-primary); }

/* 行状态：悬停淡蓝叠加、选中主色浅底、异常行浅红底 */
.kx-table__row { transition: background-color var(--kx-dur-fast) var(--kx-ease); }
.kx-table__row:hover .kx-table__cell { background: rgba(var(--kx-overlay-rgb), .035); }
.kx-table__row.is-selected .kx-table__cell { background: var(--kx-primary-soft); }
.kx-table__row.is-fail > .kx-table__cell { background: var(--kx-danger-soft); }

/* 斑马纹：极淡深蓝叠加交替，悬停加深一档以保持可辨识 */
.kx-table--zebra .kx-table__tbody tr:nth-child(even) .kx-table__cell { background: rgba(var(--kx-overlay-rgb), .02); }
.kx-table--zebra .kx-table__tbody tr:hover .kx-table__cell { background: rgba(var(--kx-overlay-rgb), .05); }
/* 斑马纹下选中态仍需可见（nth-child 权重更高，这里显式提权） */
.kx-table--zebra .kx-table__tbody tr.is-selected .kx-table__cell { background: var(--kx-primary-soft); }

/* 固定列是 sticky 的，必须给出**不透明**底色，否则横向滚动时下层文字会透出叠字
   （卡片本身是半透明玻璃，这里用与「玻璃卡叠在页面底纹上」等效的不透明色） */
.kx-table__cell--fixed-left,
.kx-table__cell--fixed-right { background: var(--kx-surface-fixed); }
.kx-table--fixed .kx-table__thead .kx-table__cell--fixed-left,
.kx-table--fixed .kx-table__thead .kx-table__cell--fixed-right { background: var(--kx-surface-fixed); }
.kx-table__row:hover .kx-table__cell--fixed-left,
.kx-table__row:hover .kx-table__cell--fixed-right { background: var(--kx-surface-fixed-hover); }
.kx-table__row.is-selected .kx-table__cell--fixed-left,
.kx-table__row.is-selected .kx-table__cell--fixed-right { background: var(--kx-surface-fixed-selected); }
.kx-table--zebra .kx-table__tbody tr:nth-child(even) .kx-table__cell--fixed-left,
.kx-table--zebra .kx-table__tbody tr:nth-child(even) .kx-table__cell--fixed-right { background: var(--kx-surface-fixed-zebra); }
.kx-table--zebra .kx-table__tbody tr:hover .kx-table__cell--fixed-left,
.kx-table--zebra .kx-table__tbody tr:hover .kx-table__cell--fixed-right { background: var(--kx-surface-fixed-hover); }
.kx-table--zebra .kx-table__tbody tr.is-selected .kx-table__cell--fixed-left,
.kx-table--zebra .kx-table__tbody tr.is-selected .kx-table__cell--fixed-right { background: var(--kx-surface-fixed-selected); }

.kx-table__actions { display: inline-flex; align-items: center; gap: 2px; justify-content: flex-end; }
.kx-table__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  /* 上下 8px：分页控件已降到 32px，这条不必再留 12px，否则整条偏高显空 */
  padding: var(--kx-sp-2) var(--kx-sp-4);
  border-top: 1px solid var(--kx-border);
}
.kx-table__empty { padding: var(--kx-sp-2) 0; }
/* 加载遮罩：按主题稀释卡片底色，暗色模式下不会出现白块 */
.kx-table__loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--kx-sp-2);
  background: var(--kx-surface);
  background: color-mix(in srgb, var(--kx-surface) 65%, transparent);
  z-index: 6;
  font-size: var(--kx-fs);
  color: var(--kx-text-2);
}
.kx-table__skeleton { display: flex; flex-direction: column; gap: var(--kx-sp-2); padding: var(--kx-sp-4); }
/* 骨架屏：基于叠加层的流光扫过（复用 base.css 的 kx-shimmer） */
.kx-skeleton {
  border-radius: var(--kx-radius-sm);
  background: linear-gradient(90deg, rgba(var(--kx-overlay-rgb), .05) 25%, rgba(var(--kx-overlay-rgb), .1) 50%, rgba(var(--kx-overlay-rgb), .05) 75%);
  background-size: 420px 100%;
  animation: kx-shimmer 1.4s var(--kx-ease) infinite;
}
.kx-skeleton--line { height: 12px; }
.kx-skeleton--row { height: 36px; }

/* ============================================================================
   10. 分页
   紧凑口径：分页专用控件高 32px（比表单控件 --kx-control-h=38px 小一档，
   分页是辅助操作，不该和主按钮一样大）；总数靠左、页码与每页条数靠右，
   避免整组挤在一侧、另一侧留出大片空白。
   ========================================================================== */
.kx-pagination {
  /* 分页专用控件高；子元素都带 fallback，脱离本容器（素材库自建分页）时也不会塌 */
  --kx-pagination-h: 32px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kx-sp-2);
  font-size: var(--kx-fs-sm);
  font-variant-numeric: tabular-nums;
}
/* auto 外边距把总数推到最左：即使容器是 justify-content: flex-end 也生效 */
/* 字号写在子元素上（不依赖容器）：素材库是页面自建分页，容器没有 .kx-pagination 类，
   字号若只写在容器上，那里会回落成 14px、与其它页不一致 */
.kx-pagination__total { margin-right: auto; color: var(--kx-text-3); font-size: var(--kx-fs-sm); white-space: nowrap; }
.kx-pagination__list { display: inline-flex; align-items: center; gap: 2px; }
.kx-pagination__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--kx-pagination-h, 32px);
  height: var(--kx-pagination-h, 32px);
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: var(--kx-radius-sm);
  background: transparent;
  color: var(--kx-text-2);
  font-size: var(--kx-fs-sm);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color var(--kx-dur-fast) var(--kx-ease), border-color var(--kx-dur-fast) var(--kx-ease),
              color var(--kx-dur-fast) var(--kx-ease);
}
.kx-pagination__item:hover:not(:disabled) { background: rgba(var(--kx-overlay-rgb), .06); color: var(--kx-primary); }
/* 当前页：主色浅底 + 主色描边 + 主色文字（与组件库选中态口径一致，不用实底/渐变） */
.kx-pagination__item.is-active {
  background: var(--kx-primary-soft);
  border-color: var(--kx-primary-border);
  color: var(--kx-primary);
  font-weight: var(--kx-fw-semibold);
}
.kx-pagination__item:disabled { color: var(--kx-text-4); cursor: not-allowed; }
.kx-pagination__ellipsis { padding: 0 2px; color: var(--kx-text-4); font-size: var(--kx-fs-sm); }
/* 简易模式（‹ 3 / 12 ›）：左右留 8px，避免页码紧贴两个箭头 */
.kx-pagination__simple { padding: 0 var(--kx-sp-2); color: var(--kx-text-2); font-size: var(--kx-fs-sm); white-space: nowrap; }
.kx-pagination__size {
  height: var(--kx-pagination-h, 32px);
  padding: 0 var(--kx-sp-2);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-sm);
  background: rgba(var(--kx-overlay-rgb), .05);
  color: var(--kx-text-2);
  font-size: var(--kx-fs-xs);
  cursor: pointer;
  transition: border-color var(--kx-dur) var(--kx-ease), color var(--kx-dur) var(--kx-ease);
}
.kx-pagination__size:hover { border-color: var(--kx-primary-hover); color: var(--kx-text); }

/* ============================================================================
   11. 弹窗
   ========================================================================== */
.kx-modal-mask {
  position: fixed;
  inset: 0;
  z-index: var(--kx-z-modal);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 8vh var(--kx-sp-5) var(--kx-sp-8);
  overflow-y: auto;
  background: rgba(3, 6, 16, .7);
  backdrop-filter: blur(6px);
  animation: kx-fade-in var(--kx-dur) var(--kx-ease) both;
}
.kx-modal {
  width: 100%;
  max-width: 560px;
  background: var(--kx-surface-solid);
  border-radius: var(--kx-radius-xl);
  box-shadow: var(--kx-shadow-lg);
  animation: kx-rise-in var(--kx-dur-slow) var(--kx-ease) both;
  display: flex;
  flex-direction: column;
  max-height: 84vh;
  margin: auto 0;
  /* 弹窗自己裁掉溢出：正文（.kx-modal__body）是滚动容器，它的**滚动溢出**会被
     Chrome 并进祖先的 scrollable overflow，于是遮罩（.kx-modal-mask）的
     scrollHeight 变成正文的整份高度 —— 表现是遮罩出现滚动条、往下能滚出一大片空白
     （联调测试弹窗实测：视口 1000px，遮罩 scrollHeight 3219px、可滚 2219px 空白）。
     这里让弹窗把子元素的溢出裁掉，遮罩的 scrollHeight 就回到视口高度（实测 1000）。
     遮罩仍保留 overflow-y:auto 作兜底（真出现比视口还高的弹窗时还能滚）。

     用 `clip` 而不是 `hidden`：`overflow:hidden` 仍然是**滚动容器**，能被子元素的
     「聚焦滚入视口」带着滚 —— 勾选框那类 `position:absolute;opacity:0` 的隐藏 input
     一点就会被 focus，Chrome 为把它滚进视口，滚的正是这个面板而不是里面的
     `.kx-modal__body`（实测：面板 scrollTop 1759 = 2519-760 的极限值），正文被顶到
     y=-1604、整块看不见，而面板又滚不回来 —— 表现就是「点一下弹窗变白了、什么都不显示」
     （20-搜索视频触达·抖音 的 IP 勾选组实测）。`clip` 不产生滚动容器，焦点滚动
     自然落到真正该滚的 `.kx-modal__body` 上。 */
  overflow: hidden;   /* 老浏览器兜底（不认 clip 时保持原行为） */
  overflow: clip;     /* 现代浏览器：不是滚动容器，聚焦滚入视口带不走它 */
}
.kx-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--kx-sp-3);
  padding: var(--kx-sp-4) var(--kx-sp-6);
  flex: none;
}
.kx-modal__title {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  margin: 0;
  font-size: var(--kx-fs-lg);
  font-weight: var(--kx-fw-semibold);
  color: var(--kx-text);
  line-height: var(--kx-lh);
}
.kx-modal__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--kx-radius-sm);
  color: var(--kx-text-3);
  font-size: 16px;
  flex: none;
  transition: background-color var(--kx-dur-fast) var(--kx-ease), color var(--kx-dur-fast) var(--kx-ease);
}
.kx-modal__close:hover { background: rgba(var(--kx-overlay-rgb), .06); color: var(--kx-text); }
.kx-modal__body {
  padding: var(--kx-sp-2) var(--kx-sp-6) var(--kx-sp-5);
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}
.kx-modal__foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--kx-sp-2);
  padding: var(--kx-sp-3) var(--kx-sp-6);
  border-top: 1px solid var(--kx-border);
  flex: none;
}
.kx-modal__footer-inner { display: flex; align-items: center; justify-content: flex-end; gap: var(--kx-sp-2); }
.kx-confirm__text { font-size: var(--kx-fs); color: var(--kx-text-2); line-height: 1.7; }

/* ============================================================================
   12. 抽屉
   ========================================================================== */
.kx-drawer-mask {
  position: fixed;
  inset: 0;
  z-index: var(--kx-z-modal);
  background: rgba(3, 6, 16, .7);
  backdrop-filter: blur(6px);
  animation: kx-fade-in var(--kx-dur) var(--kx-ease) both;
}
.kx-drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: calc(var(--kx-z-modal) + 1);
  display: flex;
  flex-direction: column;
  width: 520px;
  max-width: 92vw;
  background: var(--kx-surface-solid);
  box-shadow: var(--kx-shadow-lg);
}
.kx-drawer--right { right: 0; animation: kx-slide-left var(--kx-dur-slow) var(--kx-ease) both; }
.kx-drawer--left { left: 0; animation: kx-slide-right var(--kx-dur-slow) var(--kx-ease) both; }
.kx-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--kx-sp-3);
  padding: var(--kx-sp-4) var(--kx-sp-6);
  border-bottom: 1px solid var(--kx-border);
  flex: none;
}
.kx-drawer__title {
  margin: 0;
  font-size: var(--kx-fs-lg);
  font-weight: var(--kx-fw-semibold);
  color: var(--kx-text);
  line-height: var(--kx-lh);
}
.kx-drawer__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--kx-radius-sm);
  color: var(--kx-text-3);
  font-size: 16px;
  transition: background-color var(--kx-dur-fast) var(--kx-ease), color var(--kx-dur-fast) var(--kx-ease);
}
.kx-drawer__close:hover { background: rgba(var(--kx-overlay-rgb), .06); color: var(--kx-text); }
.kx-drawer__body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--kx-sp-6); }
.kx-drawer__foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--kx-sp-2);
  padding: var(--kx-sp-3) var(--kx-sp-6);
  border-top: 1px solid var(--kx-border);
  flex: none;
}
.kx-drawer__footer-inner { display: flex; align-items: center; justify-content: flex-end; gap: var(--kx-sp-2); }

/* ============================================================================
   13. 轻提示
   ========================================================================== */
.kx-toast-root {
  position: fixed;
  top: var(--kx-sp-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--kx-z-toast);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--kx-sp-2);
  pointer-events: none;
}
/* 白底 + 12px 圆角 + 蓝调投影 + 1px 类型色边框 */
.kx-toast {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  min-width: 200px;
  max-width: 480px;
  padding: var(--kx-sp-2) var(--kx-sp-4);
  border: 1px solid var(--kx-border);
  border-radius: 12px;
  background: var(--kx-surface-solid);
  box-shadow: var(--kx-shadow-md);
  font-size: var(--kx-fs);
  color: var(--kx-text);
  pointer-events: auto;
  animation: kx-fade-down var(--kx-dur) var(--kx-ease) both;
}
.kx-toast__icon { display: inline-flex; font-size: 16px; flex: none; }
.kx-toast__text { flex: 1; line-height: var(--kx-lh); word-break: break-word; }
.kx-toast--success { border-color: var(--kx-success-border); }
.kx-toast--success .kx-toast__icon { color: var(--kx-success); }
.kx-toast--error { border-color: var(--kx-danger-border); }
.kx-toast--error .kx-toast__icon { color: var(--kx-danger); }
.kx-toast--warning { border-color: var(--kx-warning-border); }
.kx-toast--warning .kx-toast__icon { color: var(--kx-warning); }
.kx-toast--info { border-color: var(--kx-info-border); }
.kx-toast--info .kx-toast__icon { color: var(--kx-info); }
.kx-toast.is-leaving { animation: kx-fade-in var(--kx-dur) var(--kx-ease) reverse both; }

/* ============================================================================
   14. 树
   ========================================================================== */
.kx-tree { display: flex; flex-direction: column; gap: 1px; font-size: var(--kx-fs); }
.kx-tree__node { display: flex; flex-direction: column; }
.kx-tree__item {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  min-height: 32px;
  padding: 0 var(--kx-sp-2);
  border-radius: var(--kx-radius-sm);
  color: var(--kx-text);
  cursor: pointer;
  transition: background-color var(--kx-dur-fast) var(--kx-ease), color var(--kx-dur-fast) var(--kx-ease);
}
.kx-tree__item:hover { background: rgba(var(--kx-overlay-rgb), .05); }
.kx-tree__item.is-active {
  background: var(--kx-primary-soft);
  color: var(--kx-primary);
  font-weight: var(--kx-fw-medium);
}
.kx-tree__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  flex: none;
  color: var(--kx-text-3);
  transition: transform var(--kx-dur-fast) var(--kx-ease);
}
.kx-tree__arrow.is-open { transform: rotate(90deg); }
.kx-tree__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-tree__children { padding-left: var(--kx-sp-4); display: flex; flex-direction: column; gap: 1px; }
.kx-tree__empty { padding: var(--kx-sp-5); text-align: center; color: var(--kx-text-3); font-size: var(--kx-fs-xs); }
.kx-tree-select__panel {
  position: absolute;
  z-index: var(--kx-z-dropdown);
  min-width: 100%;
  max-height: 260px;
  overflow: auto;
  margin-top: var(--kx-sp-1);
  padding: var(--kx-sp-1);
  background: var(--kx-bg-float);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-lg);
  box-shadow: var(--kx-shadow-md);
}

/* ============================================================================
   15. 步骤条
   ========================================================================== */
.kx-steps { display: flex; width: 100%; }
.kx-steps__item { display: flex; flex: 1; min-width: 0; align-items: flex-start; }
.kx-steps__head { display: flex; align-items: center; gap: var(--kx-sp-2); flex: none; }
.kx-steps__indicator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: rgba(var(--kx-overlay-rgb), .06);
  color: var(--kx-text-3);
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-medium);
  flex: none;
  transition: background-color var(--kx-dur) var(--kx-ease), color var(--kx-dur) var(--kx-ease);
}
.kx-steps__number { line-height: 1; }
.kx-steps__item.is-active .kx-steps__indicator { background: var(--kx-gradient-primary); color: #fff; }
/* 已完成：主色浅底 + 同色描边 + 主色图标 */
.kx-steps__item.is-done .kx-steps__indicator {
  background: var(--kx-primary-soft);
  color: var(--kx-primary);
  border: 1px solid var(--kx-primary-border);
}
.kx-steps__body { display: flex; flex-direction: column; gap: 2px; padding-top: 2px; min-width: 0; }
.kx-steps__title { font-size: var(--kx-fs); font-weight: var(--kx-fw-normal); color: var(--kx-text-2); white-space: nowrap; }
.kx-steps__item.is-active .kx-steps__title { color: var(--kx-text); font-weight: var(--kx-fw-medium); }
.kx-steps__desc { font-size: var(--kx-fs-xs); color: var(--kx-text-3); }
.kx-steps__line {
  flex: 1;
  height: 1px;
  min-width: var(--kx-sp-5);
  margin: 12px var(--kx-sp-3) 0;
  background: var(--kx-border);
}
.kx-steps--vertical { flex-direction: column; gap: var(--kx-sp-4); }
.kx-steps--vertical .kx-steps__item { flex-direction: column; }
.kx-steps--vertical .kx-steps__line { width: 1px; height: 20px; margin: var(--kx-sp-2) 0 0 11px; flex: none; }

/* ============================================================================
   16. 标签页
   ========================================================================== */
.kx-tabs { display: flex; flex-direction: column; gap: var(--kx-sp-5); }
.kx-tabs__nav {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-1);
  border-bottom: 1px solid var(--kx-border);
  /* 1px 内边距给 .kx-tabs__item 的 -1px 负外边距留出空间，避免开启横向滚动后选中下划线被裁 */
  padding-bottom: 1px;
  /* 页签数量多（或容器窄）时允许横向滚动，避免后面的页签被裁掉后既看不见也点不到 */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.kx-tabs__nav::-webkit-scrollbar { display: none; }
.kx-tabs__item {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--kx-sp-1);
  padding: 9px var(--kx-sp-4);
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--kx-text-2);
  font-size: var(--kx-fs);
  font-weight: var(--kx-fw-normal);
  cursor: pointer;
  white-space: nowrap;
  flex: none;
  transition: color var(--kx-dur) var(--kx-ease), border-color var(--kx-dur) var(--kx-ease);
}
.kx-tabs__item:hover { color: var(--kx-primary-hover); }
/* 选中：2px 主色下划线 + 主色字 + 600 */
.kx-tabs__item.is-active {
  color: var(--kx-primary);
  border-bottom-color: var(--kx-primary);
  font-weight: var(--kx-fw-semibold);
}
.kx-tabs__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--kx-radius-full);
  background: rgba(var(--kx-overlay-rgb), .06);
  color: var(--kx-text-3);
  font-size: var(--kx-fs-xs);
  font-weight: var(--kx-fw-medium);
  font-variant-numeric: tabular-nums;
}
.kx-tabs__item.is-active .kx-tabs__badge { background: var(--kx-primary-soft); color: var(--kx-primary); }
.kx-tabs__panel { min-height: 0; }

/* ============================================================================
   17. 上传
   ========================================================================== */
.kx-upload__btn { display: inline-flex; cursor: pointer; }
.kx-upload__text { font-size: var(--kx-fs-xs); color: var(--kx-text-3); }
.kx-upload-field { display: flex; flex-direction: column; gap: var(--kx-sp-2); width: 100%; }
.kx-upload-field__btn { display: inline-flex; }
.kx-upload-list { display: flex; flex-direction: column; gap: var(--kx-sp-1); width: 100%; }
.kx-upload-list__item {
  display: flex;
  align-items: center;
  gap: var(--kx-sp-2);
  padding: var(--kx-sp-2) var(--kx-sp-3);
  border: 1px solid var(--kx-border);
  border-radius: var(--kx-radius-sm);
  background: rgba(var(--kx-overlay-rgb), .04);
  font-size: var(--kx-fs-xs);
  color: var(--kx-text-2);
  transition: border-color var(--kx-dur) var(--kx-ease);
}
.kx-upload-list__item:hover { border-color: var(--kx-primary-border); }
.kx-upload-list__item > span:nth-child(2) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-upload-list__remove { display: inline-flex; color: var(--kx-text-3); cursor: pointer; transition: color var(--kx-dur-fast) var(--kx-ease); }
.kx-upload-list__remove:hover { color: var(--kx-danger); }
.kx-upload__input { display: none; }

/* ============================================================================
   18. 时间线
   ========================================================================== */
.kx-timeline { display: flex; flex-direction: column; }
.kx-timeline__item {
  position: relative;
  display: flex;
  gap: var(--kx-sp-3);
  padding-bottom: var(--kx-sp-5);
}
.kx-timeline__item:last-child { padding-bottom: 0; }
/* 竖线：2px 主色→青蓝渐变（参考项目 .timeline::before） */
.kx-timeline__item::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 16px;
  bottom: 0;
  width: 2px;
  background: linear-gradient(180deg, var(--kx-primary-200), var(--kx-accent-50));
}
.kx-timeline__item:last-child::before { display: none; }
/* 节点：白底 + 2px 主色描边 + 3px 主色光晕 */
.kx-timeline__dot {
  position: relative;
  z-index: 1;
  width: 12px;
  height: 12px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--kx-surface-solid);
  border: 2px solid var(--kx-primary);
  box-shadow: 0 0 0 3px var(--kx-primary-100);
  flex: none;
}
.kx-timeline__dot--accent { border-color: var(--kx-primary); }
.kx-timeline__dot--info { border-color: var(--kx-info); }
.kx-timeline__dot--success { border-color: var(--kx-success); }
.kx-timeline__dot--danger { border-color: var(--kx-danger); }
.kx-timeline__content { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.kx-timeline__title { font-size: var(--kx-fs); font-weight: var(--kx-fw-medium); color: var(--kx-text); }
.kx-timeline__desc { font-size: var(--kx-fs-xs); color: var(--kx-text-3); line-height: var(--kx-lh); }
.kx-timeline__time { font-size: var(--kx-fs-xs); color: var(--kx-text-4); white-space: nowrap; }

/* ============================================================================
   19. 工具类
   ========================================================================== */
.kx-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.kx-strong { font-weight: var(--kx-fw-semibold); }
.kx-num { font-variant-numeric: tabular-nums; }
.kx-mono { font-family: var(--kx-font-mono); font-size: var(--kx-fs-xs); }
.kx-text-2 { color: var(--kx-text-2); }
.kx-text-3 { color: var(--kx-text-3); }
.kx-text-4 { color: var(--kx-text-4); }
.kx-text-primary { color: var(--kx-primary); }
.kx-text-success { color: var(--kx-success-text); }
.kx-text-danger { color: var(--kx-danger-text); }
.kx-text-warning { color: var(--kx-warning-text); }
.kx-up { color: var(--kx-success-text); }
.kx-down { color: var(--kx-danger-text); }
.kx-text-xs { font-size: var(--kx-fs-xs); }
.kx-text-sm { font-size: var(--kx-fs-sm); }
.kx-text-lg { font-size: var(--kx-fs-lg); }
.kx-hide { display: none !important; }
.kx-gap-1 { gap: var(--kx-sp-1); }
.kx-gap-2 { gap: var(--kx-sp-2); }
.kx-gap-3 { gap: var(--kx-sp-3); }
.kx-gap-4 { gap: var(--kx-sp-4); }
.kx-gap-5 { gap: var(--kx-sp-5); }
.kx-gap-6 { gap: var(--kx-sp-6); }
.kx-scroll-y { overflow-y: auto; }
