/*
==========================================================================
   CMS 补缺层 —— 只补现有体系里确实没有的组件
   ------------------------------------------------------------------
   纪律：本文件不引入任何新的色值、圆角、字号语汇。所有取值必须能在
   00~90 里找到出处，注释标注来源。目的是让 CMS 的表格 / 表单 / 分页
   看上去就是 steam-app 与访达的延续，而不是另一套后台皮肤。

   复用关系速查（写新界面前先看这里，别造重复件）：
     应用外壳 双栏      .steam-app-container + .sa-sidebar + .sa-main   (50)
     应用内导航         .sa-topnav / .sa-nav-item / .sa-hero-tab        (50)
     侧栏分类           .sa-cat-list / .sa-cat-btn / .sa-cat-count      (50)
     搜索框             .sa-search-bar / .sa-search-input              (50)
     下拉选择           .sa-select / .sa-select-trigger / -menu/-option (50)
     开关               .sa-toggle（块）/ .sa-persist-switch（滑块）    (50)
     数字输入 步进      .sa-number-control / .sa-number-input           (50)
     面板 分组          .sa-cheat-section / .sa-cheat-group             (50)
     行列表             .sa-history-panel / .sa-history-row             (50)
     表格 表头/行       .fl-head / .fl-row / .fl-name / .fl-dim         (40)
     工具栏             .f-toolbar / .f-view / .f-path / .f-status      (40)
     按钮 主/次         .abtn / .abtn.gray                              (60)
     按钮 三档          .update-btn .primary/.ghost/.disabled           (80)
     按钮 小号          .sa-action-btn / .sa-mod-btn / .lco-mini-btn    (50/70)
     徽章               .sa-lib-badge / .update-badge / .lco-status     (50/80/70)
     标签               .gu-tag / .gu-genre                             (51)
     状态点             .sa-card-dot + .sa-dot-* / .gu-dot-ok/-blocked  (50/51)
     对话框 暗          .buy-confirm-overlay / .buy-confirm             (60)
     对话框 浅          .lco-notice / .lco-notice-dialog                (70)
     空/错/载入         .lco-empty / .lco-error / .lco-loading          (70)
     骨架屏             .sa-skel-* / .sa-shimmer                        (50)
     富文本正文         .note-rich                                      (30)
     通知               #notif                                          (60)
     聊天               .chat / .chat-bubble / .chat-bar                (60)
     图片查看器         .chat-image-viewer                              (60)
   ========================================================================== */

/* ============ 应用外壳 ============
   直接沿用 .steam-app-container 的双栏骨架，这里只给 CMS 场景加两个变体：
   无侧栏（单栏页面）与纯内容页（表单、详情）。 */
.cms-app { /* 与 .steam-app-container 并用，不覆盖其配色 */ }
/* 单栏应用：没有左侧分类时不留出空栏 */
.cms-app.cms-no-side .sa-sidebar { display: none; }

/* 内容区纵向布局：工具栏(固定) + 主体(滚动) + 分页(固定)。
   .sa-page 只管滚动，这层管三段式骨架。 */
.cms-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* 主体滚动区。滚动条规格照抄 .sa-page（50） */
.cms-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 16px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
.cms-scroll::-webkit-scrollbar { width: 8px; }
.cms-scroll::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); border-radius: 4px; }
/* 表单等需要更舒展留白的页面 */
.cms-scroll.cms-pad { padding: 16px 20px 28px; }
/* 填满型内容（客服工作台这类自己管滚动的整块布局）。
   默认的 .cms-scroll 是块级滚动容器，高度由内容决定，里面的 height:100%
   元素（.chat 就是）算不出高度会塌掉，底部的输入条会被 overflow 裁掉。
   这个变体把内容区改成 flex 容器并交出滚动权。
   留白与 .cms-scroll 一致（12/16），让填满型的内容和其它功能区对齐边线 ——
   通版铺满会让对话区顶到窗口边框，和别的页面看起来不是一套东西。 */
.cms-scroll.cms-fill { display: flex; overflow: hidden; padding: 12px 16px; }
.cms-scroll.cms-fill > * { flex: 1; min-width: 0; min-height: 0; }

/* 填满型的两栏。对齐 .sa-trainer-view（50）的两栏思路：左右各自是一张卡，
   中间靠 gap 分开 —— 不是「一张大卡里用竖线劈两半」。 */
.cms-fill-split { display: flex; gap: 12px; min-height: 0; }

/* 填满型的卡。视觉配方直接挂 .sa-cheat-section（50）复用，这里只改箱模型：
   那个类是 flex:none + overflow:clip（给说明气泡留溢出空间用的），
   而这里要的是撑满高度、内部自己滚、圆角把内容裁住。 */
.sa-cheat-section.cms-fill-card {
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  overflow-clip-margin: 0;
}

/* 卡内分组（panel 的 flat 变体）。
   自己不画边框 —— 靠 .sa-cheat-group 头条自带的上下分隔线断开相邻分组，
   这样一栏里叠四五个分组也只有单层细线，不会出现双边框糊在一起。 */
.cms-panel-flat { flex: none; min-width: 0; }
.cms-panel-flat + .cms-panel-flat > .sa-cheat-group { border-top: 1px solid rgba(255, 255, 255, 0.1); }

/* 侧栏里要常驻可及的分组。客服的退款 / 补余额 / 调会员属于这种：
   订单列表一长就把按钮顶出视野，每次操作都得先往上滚。
   sticky 配方与 .sa-detail-side（50）同源，区别是那边整栏 sticky，
   这里同一栏下面还有要滚的订单列表，所以只钉住上面这几组。
   背景必须不透明：滚动内容会从下面穿过，半透明会看到重影。 */
.cms-panel-flat.cms-panel-stick {
  position: sticky;
  top: 0;
  z-index: 2;
  background: #161c23;
}

/* ============ 工具栏 ============
   壳与分隔线取自 .f-toolbar（40），高度放到 44px 与其一致。
   CMS 工具栏项比访达多（搜索 + 若干筛选 + 操作按钮），允许换行增高。 */
.cms-toolbar {
  flex: none;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  flex-wrap: wrap;
  background: rgba(255, 255, 255, 0.05);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
/* 把后续项推到右侧 */
.cms-toolbar-gap { margin-left: auto; }
/* 工具栏里的搜索框比侧栏的宽一档，其余规格由 .sa-search-bar 提供 */
.cms-toolbar .sa-search-bar { width: clamp(160px, 22vw, 260px); }
/* 竖线分隔，取自 .dock-sep（60）的配方 */
.cms-toolbar-sep {
  width: 1px;
  align-self: stretch;
  margin: 2px 2px;
  background: rgba(255, 255, 255, 0.18);
}
/* 标题：规格取自 .f-tb-title（40） */
.cms-title {
  flex: none;
  font-size: 14px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.9);
  letter-spacing: -0.2px;
  white-space: nowrap;
}
/* 副标题 / 计数：取自 .sa-mod-counter（50） */
.cms-subtitle { flex: none; font-size: 12px; color: #8f98a0; }
.cms-subtitle b { color: #fff; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ============ 数据表格 ============
   视觉全部来自访达列表（40）：.fl-head 的粘性表头、.fl-row 的斑马纹与
   选中态、.fl-dim 的弱化文本。这里只做一件访达没有的事 —— 列数不固定，
   所以把 flex 换成 grid，列宽由 --cms-cols 声明。
   外面包一层 .sa-cheat-section（50）拿到面板的边框、圆角与毛玻璃。 */
.cms-table { --cms-cols: 1fr; display: block; }
.cms-table .fl-head,
.cms-table .fl-row {
  display: grid;
  grid-template-columns: var(--cms-cols);
  align-items: center;
  gap: 10px;
}
/* 表头在滚动容器内粘顶。背景与 .fl-head（40）一致，
   但这里位于 .sa-cheat-section 内，改用面板自身的底色避免透出下方行。 */
.cms-table .fl-head {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 30px;
  padding: 0 12px;
  background: rgba(37, 44, 53, 0.98);
  -webkit-backdrop-filter: blur(24px);
  backdrop-filter: blur(24px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
/* 行高比访达（28px）宽一档：CMS 单元格常有徽章和按钮 */
.cms-table .fl-row {
  min-height: 36px;
  height: auto;
  padding: 5px 12px;
}
/* 行悬停反馈，配方取自 .sa-cheat-row:hover（50） */
.cms-table .fl-row:hover { background: rgba(255, 255, 255, 0.08); }
/* 勾选态沿用 .fl-row.sel 的蓝底，但 CMS 是多选，做得比选中更轻，
   否则整屏蓝底会看不清内容。透明度取自 .sa-side-item.on（50） */
.cms-table .fl-row.cms-checked { background: rgba(26, 159, 255, 0.1); }
.cms-table .fl-row.cms-checked:hover { background: rgba(26, 159, 255, 0.16); }
/* 单元格：默认单行省略，与 .fl-name span（40）一致 */
.cms-cell {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cms-cell-num { text-align: right; font-variant-numeric: tabular-nums; }
.cms-cell-center { text-align: center; }
/* 允许折行的单元格（备注、地址等） */
.cms-cell-wrap { white-space: normal; overflow-wrap: anywhere; }
/* 两行式单元格：主文本 + 次要说明。取自 .sa-cheat-info（50） */
.cms-cell-stack { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cms-cell-stack > b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 次要说明字号与色值取自 .sa-cheat-desc（50） */
.cms-cell-stack > span { font-size: 11px; color: #6b747f; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 带缩略图的单元格，封面规格取自 .lco-cover（70） */
.cms-cell-media { min-width: 0; display: flex; align-items: center; gap: 9px; }
.cms-thumb {
  width: 52px;
  flex: none;
  aspect-ratio: 16 / 9;
  border-radius: 6px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.04);
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(255, 255, 255, 0.055);
}
.cms-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 方形头像变体 */
.cms-thumb.cms-thumb-sq { width: 30px; aspect-ratio: 1; border-radius: 5px; }
/* 无图时的首字母占位。用户没上传头像时比回落成一张品牌图更好认。
   底色与 .cms-readonly 同族，字色取 .sa-side-name 的弱化白。 */
.cms-thumb-text {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.55);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  user-select: none;
}

/* 排序表头。箭头借用 .sa-select-arrow（50）的两边框画法，
   保持与下拉箭头同一支笔。 */
.cms-sort {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  min-width: 0;
}
.cms-sort:hover { color: rgba(255, 255, 255, 0.85); }
.cms-sort span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cms-sort-arrow {
  flex: none;
  width: 6px;
  height: 6px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
  opacity: 0;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.2s, opacity 0.15s;
}
.cms-sort:hover .cms-sort-arrow { opacity: 0.45; }
.cms-sort[aria-sort="descending"] .cms-sort-arrow { opacity: 1; }
.cms-sort[aria-sort="ascending"] .cms-sort-arrow { opacity: 1; transform: translateY(1px) rotate(-135deg); }
/* 已参与排序的列，表头提亮（.fl-head 默认是 .4 透明度的弱化色） */
.cms-sort[aria-sort]:not([aria-sort="none"]) { color: #fff; }

/* 复选框。原生 input 配 accent-color，配方取自 .window-close-remember input（70），
   那里是浅底所以用 #147eff；这里是暗底，换成主题蓝 var(--blue)。 */
.cms-check {
  flex: none;
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--blue);
  cursor: pointer;
}
.cms-check:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
/* 表头/行的勾选列，宽度固定，居中 */
.cms-check-cell { display: flex; align-items: center; justify-content: center; }

/* 行内操作区。按钮本体用 .sa-action-btn / .lco-mini-btn，这里只管排布。 */
.cms-row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 5px; min-width: 0; }

/* .sa-action-btn 与 .sa-mod-btn 在 web-dist 里只装纯文字，所以原样式没给
   display。CMS 会往里放「图标 + 文字」，不补 inline-flex 的话两者会按块级
   上下堆叠，把 26px 高的按钮撑破（表现为图标在上、文字掉到下面）。
   .abtn / .sa-lib-badge / .sa-tool-icon 本身已有 flex，不需要处理。 */
.sa-action-btn,
.sa-mod-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  white-space: nowrap;
}
/* 图标不要被 flex 压缩 */
.sa-action-btn > svg,
.sa-mod-btn > svg { flex: none; }
/* 危险操作（删除/封禁）。色值取自 .sa-launch-btn.stop（50）的红渐变端 */
.sa-action-btn.cms-danger:hover,
.lco-mini-btn.cms-danger:hover,
.abtn.cms-danger:hover { border-color: rgba(255, 120, 110, 0.55); background: rgba(255, 90, 80, 0.2); color: #fff; }
/* 成功语义（通过/发放）。色值取自 .sa-launch-btn 的绿渐变端 */
.sa-action-btn.cms-ok:hover,
.lco-mini-btn.cms-ok:hover { border-color: rgba(124, 240, 27, 0.45); background: rgba(71, 176, 75, 0.22); color: #fff; }

/* ============ 按钮：尺寸 × 语义色 ============
   原来的变体把尺寸和颜色绑死了（primary=蓝+大、small=描边+小、gray=灰+大），
   于是做不出「小号蓝」或「大号红」，同一排按钮经常一个实底一个描边。
   这里把两件事拆成两维，底座一律是 .abtn（60-apps 的蓝色按钮原语）：

     尺寸  .cms-btn-sm  23px  行内、卡片内的操作
           .cms-btn-md  30px  工具栏、面板操作（与 .cms-input 等高，能对齐）
           （不加类）    36px  hero 主操作、对话框确认

     语义  （不加类）        蓝  主操作：保存、新增、提交、退款
           .gray            白透明  中性：刷新、取消、返回、导出
           .cms-tone-danger 红  破坏性：删除、封禁、下架、撤回
           .cms-tone-ok     绿  放行：通过、发放、上架

   颜色一个都不新造：红取 .sa-launch-btn.stop（50）的渐变，绿取 .sa-launch-btn
   的渐变，蓝是 .abtn 自己的 var(--blue)。
   只有 button() 会挂这些类 —— tab 胶囊、分页按钮、下拉都不走这套。 */
.abtn.cms-btn-sm { height: 23px; padding: 0 9px; border-radius: 7px; font-size: 10.5px; gap: 4px; }
.abtn.cms-btn-md { height: 30px; padding: 0 12px; border-radius: 8px; font-size: 12px; gap: 5px; }
/* .abtn 自带 padding:8px 16px，显式给高度让三档之间的落差是确定的 */
.abtn.cms-btn-lg { height: 36px; padding: 0 18px; font-size: 13px; gap: 6px; }

/* 纯图标按钮的破坏性语义。.sa-tool-icon（50）只有「压暗 → hover 提亮」两态，
   这里补一个红：静止仍然压暗（不抢注意力），hover 才变红提示这是危险操作。
   配方跟着 .sa-tool-icon.has-running 的做法 —— 只改 color，不加背景块。 */
.sa-tool-icon.cms-tone-danger:hover { background: rgba(255, 90, 80, 0.12); color: #ff8b84; }

/* 位置决定尺寸：表格行内、卡片内的一排操作自动收成小号。
   写成位置规则而不是逐个调用点传 size —— 行内操作有几十处，靠人一个个记
   「这里要用 sm」迟早漏，漏一个那一行就比同排的矮一截或高一截。
   选择器盯的是 md（button 的默认尺寸），所以只改「没特意指定尺寸」的按钮；
   个别地方显式传 size:'sm'/'lg' 时命中的是别的类，不受这条影响。 */
.cms-row-actions .abtn.cms-btn-md {
  height: 23px;
  padding: 0 9px;
  border-radius: 7px;
  font-size: 10.5px;
  gap: 4px;
}

.abtn.cms-tone-danger { background: linear-gradient(to right, #b04747, #732525); color: #efb0a9; }
.abtn.cms-tone-danger:hover:not(:disabled) { filter: none; background: linear-gradient(to right, #c34f4f, #802929); color: #fff; }
.abtn.cms-tone-ok { background: linear-gradient(to right, #47b04b, #257336); color: #d2efa9; }
.abtn.cms-tone-ok:hover:not(:disabled) { filter: none; background: linear-gradient(to right, #4fc354, #29803c); color: #fff; }

/* 禁用态：三种色都要能看出「点不了」，否则蓝底禁用和可用几乎没差别 */
.abtn:disabled { opacity: 0.45; cursor: not-allowed; filter: none; }
.abtn:disabled:hover { filter: none; }
/* 图标不被压缩，与 .sa-action-btn 一致 */
.abtn > svg { flex: none; }

/* 表格三态：载入 / 空 / 出错。
   .lco-loading / .lco-empty / .lco-error（70）是全窗口居中的版本，
   放进表格里需要收敛高度，其余样式继承。 */
.cms-table-state { padding: 44px 0; }
.cms-table-state.lco-loading,
.cms-table-state.lco-empty,
.cms-table-state.lco-error { min-height: 0; }

/* 表格骨架行。用 .sa-shimmer（50）提供扫光动画 */
.cms-skel-row { height: 36px; display: grid; grid-template-columns: var(--cms-cols); align-items: center; gap: 10px; padding: 5px 12px; }
.cms-skel-bar { height: 10px; border-radius: 2px; background: rgba(255, 255, 255, 0.02); }

/* ============ 分页 ============
   完全由现有件拼成：按钮 .sa-action-btn、页码 .sa-mod-counter、
   每页条数 .sa-select。这里只提供条形容器，规格对齐 .f-status（40）
   的底栏，但高度放宽以容纳按钮。 */
.cms-pager {
  flex: none;
  min-height: 38px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  flex-wrap: wrap;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.03);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.cms-pager-info { flex: none; font-variant-numeric: tabular-nums; }
.cms-pager-info b { color: rgba(255, 255, 255, 0.72); font-weight: 650; }
.cms-pager-nav { display: flex; align-items: center; gap: 4px; margin-left: auto; }
/* 页码按钮为正方形，其余（边框、底色、hover）继承 .sa-action-btn */
.sa-action-btn.cms-page-btn { min-width: 26px; padding: 0 7px; font-variant-numeric: tabular-nums; }
/* 当前页。选中色取自 .sa-history-badge（50）的蓝底 */
.sa-action-btn.cms-page-btn.on {
  border-color: rgba(108, 199, 255, 0.4);
  background: #1a9fff;
  color: #fff;
}
.sa-action-btn.cms-page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* 省略号占位，不可点 */
.cms-page-gap { min-width: 20px; text-align: center; color: rgba(255, 255, 255, 0.28); user-select: none; }
/* 每页条数的下拉宽度收窄，其余由 .sa-select 提供 */
.cms-pager .sa-select { width: 96px; }

/* ============ 批量操作条 ============
   勾选后从底部浮出。壳的配方取自 #dock（60）：深底 + 圆角 + 投影。 */
.cms-bulkbar {
  position: absolute;
  left: 50%;
  bottom: 14px;
  z-index: 25;
  transform: translateX(-50%) translateY(calc(100% + 22px));
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100% - 28px);
  padding: 8px 12px;
  border-radius: 14px;
  background: linear-gradient(rgba(47, 47, 47, .59), #212121 75%);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  box-shadow: 0 18px 45px rgba(0, 0, 0, .35);
  transition: transform 0.28s cubic-bezier(0.3, 1.2, 0.35, 1);
}
.cms-bulkbar.on { transform: translateX(-50%) translateY(0); }
.cms-bulkbar-count { flex: none; font-size: 12px; color: rgba(255, 255, 255, 0.72); font-variant-numeric: tabular-nums; }
.cms-bulkbar-count b { color: #fff; font-weight: 700; }
.cms-bulkbar-actions { display: flex; align-items: center; gap: 6px; }

/* ============ 表单 ============
   输入控件的配方来自 .sa-number-input（50）：暗底 + 细白边 + 聚焦蓝边。
   这里把它推广成整宽、左对齐、非等宽字体的通用输入。 */
.cms-form { display: flex; flex-direction: column; gap: 14px; }
/* 自适应多列，窄了自动落回单列。
   下限给 260px：220px 时宽屏会排到 5 列，每列输入框太窄，长一点的地址、
   密钥看不全。260px 在 1200px 宽的窗口里排 4 列，是可读性与密度的平衡点。 */
.cms-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px 14px; }
.cms-field { min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.cms-field-full { grid-column: 1 / -1; }
/* 标签规格取自 .sa-games-label（50）：11px / 600 / 大写 / 字距 */
.cms-label {
  display: flex;
  align-items: center;
  gap: 5px;
  color: #8c96a0;
  font: 600 11px/1.3 inherit;
  letter-spacing: 0.05em;
}
/* 必填星号。红取自 .circle.red（30）的 #ff5f57 */
.cms-label em { color: #ff5f57; font-style: normal; }
/* 字段说明，规格取自 .sa-cheat-desc（50） */
.cms-hint { font-size: 11px; line-height: 1.5; color: #6b747f; }
/* 字段级错误。色值取自 .chat-error（60）的 #ffaaa5 */
.cms-error { font-size: 11px; line-height: 1.5; color: #ffaaa5; }

.cms-input,
.cms-textarea {
  width: 100%;
  min-width: 0;
  padding: 0 10px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.3);
  color: #dbe2e6;
  font: 400 12px/1 inherit;
  outline: none;
  -webkit-user-select: text;
  user-select: text;
  transition: border-color 0.15s, background 0.15s;
}
.cms-input { height: 30px; }
.cms-textarea { min-height: 84px; padding: 8px 10px; line-height: 1.6; resize: vertical; }
.cms-input::placeholder,
.cms-textarea::placeholder { color: #7b8796; }
.cms-input:hover,
.cms-textarea:hover { border-color: rgba(255, 255, 255, 0.22); }
/* 聚焦态与 .sa-number-input:focus（50）一致 */
.cms-input:focus,
.cms-textarea:focus { border-color: rgba(108, 199, 255, 0.58); }
.cms-input:disabled,
.cms-textarea:disabled { opacity: 0.5; cursor: not-allowed; }
/* 校验失败的边框，色值同 .cms-error */
.cms-input.cms-invalid,
.cms-textarea.cms-invalid { border-color: rgba(255, 120, 110, 0.6); }
/* 等宽变体：ID、密钥、路径 */
.cms-input.cms-mono,
.cms-textarea.cms-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
/* 只读展示值（不可编辑但要能选中复制） */
.cms-readonly {
  min-height: 30px;
  padding: 7px 10px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.18);
  color: rgba(255, 255, 255, 0.66);
  font-size: 12px;
  line-height: 1.4;
  overflow-wrap: anywhere;
  -webkit-user-select: text;
  user-select: text;
}

/* 前后缀（¥、天、%）。色值与字号跟随 .cms-hint */
.cms-input-group { display: flex; align-items: center; gap: 6px; min-width: 0; }
.cms-input-group > .cms-input { flex: 1; }
.cms-affix { flex: none; font-size: 11px; color: #8c96a0; white-space: nowrap; }

/* 复选 / 单选行。整行可点，配方取自 .window-close-remember（70），
   但改为暗底：边框与底色对齐 .cms-readonly。 */
.cms-choice {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.18);
  color: rgba(255, 255, 255, 0.78);
  font-size: 12px;
  line-height: 1.4;
  cursor: pointer;
}
.cms-choice:hover { border-color: rgba(255, 255, 255, 0.18); background: rgba(255, 255, 255, 0.04); }
.cms-choice input { flex: none; width: 14px; height: 14px; margin: 0; accent-color: var(--blue); cursor: pointer; }
/* 无边框紧凑变体，用于筛选面板里的多选 */
.cms-choice.cms-choice-bare { padding: 3px 2px; border: none; background: transparent; }
.cms-choice.cms-choice-bare:hover { background: transparent; color: #fff; }

/* 开关字段：左标签右开关。开关本体用 .sa-toggle 或 .sa-persist-switch */
.cms-switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.cms-switch-row:last-child { border-bottom: none; }
.cms-switch-row > div { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* 主文本规格取自 .sa-cheat-name（50） */
.cms-switch-row > div > b { font-size: 13px; font-weight: 500; color: #dbe2e6; letter-spacing: 0.02em; }
.cms-switch-row > div > span { font-size: 11px; color: #6b747f; line-height: 1.5; }

/* 表单分区。面板皮由 .sa-cheat-section 提供，标题条由 .sa-cheat-group 提供，
   这里只给内容留白（对齐 .sa-cheat-group-rows 的 8px/12px）。 */
.cms-section-body { padding: 14px 14px 16px; }
/* 表单底部操作条。分隔线与内距对齐 .lco-notice-actions（70） */
.cms-form-actions {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 11px 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.03);
}
.cms-form-actions-gap { margin-right: auto; }

/* ============ 概览统计卡 ============
   卡面用 .sa-cheat-section 的皮，数字排版参考 .lco-ticket-days（70）
   的等宽大字，但那是浅色票据，这里换成暗底上的白字。 */
.cms-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 10px; }
.cms-stat { padding: 13px 14px 14px; }
/* 卡头规格取自 .section-title（60）：10.5px / 600 / 大写 / 字距 */
.cms-stat-label {
  display: flex;
  align-items: center;
  gap: 6px;
  color: rgba(255, 255, 255, 0.3);
  font: 600 10.5px/1 inherit;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.cms-stat-value {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-top: 8px;
  color: #fff;
  font-size: 25px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
/* 单位 / 货币符号，弱化一档，配方同 .card-price em（60） */
.cms-stat-value em { font-size: 13px; font-style: normal; font-weight: 500; color: rgba(255, 255, 255, 0.45); }
/* 同比说明。涨用 .sa-dot-super 的绿，跌用 .circle.red 的红 */
.cms-stat-delta { margin-top: 7px; font-size: 11px; color: #8f98a0; font-variant-numeric: tabular-nums; }
.cms-stat-delta.up { color: #7cf01b; }
.cms-stat-delta.down { color: #ff5f57; }

/* ============ 迷你图表 ============
   纯 SVG，取色一律用既有主题色：主线 #1a9fff（steam 蓝）、
   对比线 #7cf01b（超级绿）、网格用与分隔线同族的白透明。

   高度由 JS 以内联 style 写死。不能用 height:auto —— 那样高度会按 viewBox
   的宽高比跟着容器宽度一起涨，窗口最大化时一张 150 高的图会变成 300 多，
   把整页撑得很松。 */
.cms-chart { display: block; width: 100%; overflow: visible; }
.cms-chart-grid { stroke: rgba(255, 255, 255, 0.06); stroke-width: 1; }
.cms-chart-axis { fill: rgba(255, 255, 255, 0.32); font-size: 11px; font-variant-numeric: tabular-nums; }
.cms-chart-line { fill: none; stroke: #1a9fff; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.cms-chart-line.alt { stroke: #7cf01b; }
.cms-chart-area { fill: rgba(26, 159, 255, 0.12); stroke: none; }
.cms-chart-area.alt { fill: rgba(124, 240, 27, 0.1); }
.cms-chart-bar { fill: #1a9fff; }
.cms-chart-bar.alt { fill: #7cf01b; }
.cms-chart-dot { fill: #1a9fff; stroke: #171d25; stroke-width: 2; }
/* 图例：复用 .sa-lib-legend 的排布思路，尺寸更小 */
.cms-chart-legend { display: flex; align-items: center; gap: 12px; font-size: 11px; color: #8f98a0; }
.cms-chart-legend span { display: inline-flex; align-items: center; gap: 5px; }
.cms-chart-legend i { width: 8px; height: 2px; border-radius: 1px; background: #1a9fff; }
.cms-chart-legend i.alt { background: #7cf01b; }

/* ============ 徽章语义色 ============
   底座沿用 .lco-status（70）：17px 高、8px 字、4px 圆角。
   这里只补语义配色，色相全部取自既有用例，不新造颜色。 */
.lco-status.cms-st-ok { background: #2d744d; color: #fff; }            /* 同 .lco-compensation-redeemed */
.lco-status.cms-st-info { background: #2f66b5; color: #fff; }          /* 同 .lco-compensation-eligible */
.lco-status.cms-st-mute { background: #555a61; color: #e1e4e8; }       /* 同 .lco-status-pending */
.lco-status.cms-st-danger { background: #a84e4a; color: #fff; }        /* 同 .lco-status-refunded */
.lco-status.cms-st-warn { background: #8a6320; color: #ffe0a8; }       /* 由 .sa-settings-status.warn 的 #b86000 调暗至同族 */

/* ============ 详情键值表 ============
   用于订单/用户详情。左列标签、右列值，分隔线与 .sa-cheat-row 同族。 */
.cms-kv { display: grid; grid-template-columns: minmax(72px, auto) minmax(0, 1fr); gap: 0 14px; }
.cms-kv > dt,
.cms-kv > dd { padding: 7px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.04); min-width: 0; }
.cms-kv > dt { color: #8c96a0; font-size: 11px; }
.cms-kv > dd {
  margin: 0;
  color: #dbe2e6;
  font-size: 12px;
  overflow-wrap: anywhere;
  -webkit-user-select: text;
  user-select: text;
}
.cms-kv > dt:last-of-type,
.cms-kv > dd:last-of-type { border-bottom: none; }

/* ============ 窄窗口 ============
   窗口可被拖到很窄，表格必须能退化。用容器查询按应用自身宽度判断，
   与 steam-app 的 @container samain 同一策略。 */
.cms-app .sa-main { container-type: inline-size; container-name: cmsmain; }
@container cmsmain (max-width: 720px) {
  .cms-scroll { padding: 10px 12px; }
  .cms-toolbar { padding: 7px 12px; }
  .cms-pager { padding: 6px 10px; }
}
@container cmsmain (max-width: 520px) {
  .cms-form-grid { grid-template-columns: 1fr; }
  .cms-stat-grid { grid-template-columns: repeat(auto-fit, minmax(136px, 1fr)); }
  .cms-pager-nav { margin-left: 0; }
}
/* 表格的撤列不在这里做。grid-template-columns 的列数必须与实际可见的子元素
   数严格一致，用 display:none 藏掉一列却不改模板会让整行错位，所以由
   data-view.js 的 ResizeObserver 按 column.priority（md / lo）同时决定
   可见列集合与模板。 */

/* ============ hidden 属性修正 ============
   任何 display:flex / grid 的规则都会盖掉 hidden 属性，元素明明设了 hidden
   却还占着位置。web-dist 里 .mb-running[hidden]、.buy [hidden]、
   .ditem-badge[hidden] 都是为此单独补的规则 —— 每次新增一个 flex 组件就要
   记得补一条，很容易漏（详情页的 tab 内容用 .cms-form 包着，漏了就会所有
   tab 同时显示）。这里一次性兜住，不再逐个枚举。 */
[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .cms-bulkbar { transition: none; }
  .cms-sort-arrow { transition: none; }
}

/* ============ 客服工作台补件 ============
   聊天窗口本体（.chat / .chat-bubble / .chat-bar）全在 60-apps.css，
   这里只补后台独有的三样：图片键、上传进度、拖入投放态。 */

/* 图片键。.chat-bar button 是实心蓝胶囊（发送键的规格），次要动作不能也是
   蓝的，否则两个键抢注意力。尺寸和圆角完全继承，只把填色换成 .cms-readonly
   那套暗底 + 细边。 */
.chat-bar button.chat-bar-ghost {
  width: 34px;
  padding: 0;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.06);
  color: rgba(255, 255, 255, 0.72);
}
.chat-bar button.chat-bar-ghost:hover:not(:disabled) {
  filter: none;
  border-color: rgba(255, 255, 255, 0.24);
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
}

/* 上传进度。位置、外边距、圆角与 .chat-error（60）对齐，只是把警示色
   换成中性色 —— 这是进度不是错误。 */
.chat-upload {
  flex: none;
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 12px 7px;
  padding: 7px 10px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.05);
}
.chat-upload-text { flex: none; font-size: 11px; color: rgba(255, 255, 255, 0.66); }
.chat-upload-track {
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.1);
  overflow: hidden;
}
/* 进度色用 var(--blue)，与发送键、.chat-row.me 的气泡同色 */
.chat-upload-track > i { display: block; height: 100%; width: 0; border-radius: 2px; background: var(--blue); transition: width 0.18s ease-out; }

/* 拖入投放态。只描边不改布局 —— 改内边距会让整列消息在拖拽过程中位移。
   inset:-1px 让描边压住外层边框，不占额外空间。 */
.chat.chat-dropping { position: relative; }
.chat.chat-dropping::after {
  content: '松手发送图片';
  position: absolute;
  inset: -1px;
  z-index: 3;
  display: grid;
  place-items: center;
  border: 2px dashed rgba(108, 199, 255, 0.6);
  border-radius: 4px;
  background: rgba(26, 159, 255, 0.09);
  color: #cfe6ff;
  font-size: 12px;
  font-weight: 600;
  pointer-events: none;
}

/* ============ 实时日志 ============
   采集这类长任务要能一直盯着看。底色比 .cms-readonly 更沉（要有「控制台」
   的观感），字栈沿用 .lco-detail-item code（70）那一套等宽。
   高度写死 260px 并自己滚：日志会到几百行，让它撑开面板的话整页会一直往下长，
   下面的配置区就永远滚不到。 */
.cms-log {
  height: 260px;
  overflow-y: auto;
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.42);
  font: 500 11px/1.65 ui-monospace, SFMono-Regular, Consolas, monospace;
  -webkit-user-select: text;
  user-select: text;
  overscroll-behavior: contain;
}
/* 正常行用超级绿（同 .cms-chart-line.alt 的 #7cf01b，压暗一档避免刺眼），
   错误行用与 .cms-error 同族的浅红 */
.cms-log-line { color: #a9e77a; overflow-wrap: anywhere; white-space: pre-wrap; }
.cms-log-line.is-error { color: #ffaaa5; }
/* 警告（采集到但没匹配上激活码这类）。色值同 .cms-st-warn 的 #ffe0a8 */
.cms-log-line.is-warn { color: #ffe0a8; }
.cms-log-empty { color: #6b747f; font-size: 11px; }
