/* ============================================
 * 自定义字体：HarmonyOS Sans SC 替换 Inter 作为中文主字体
 * 2026-08-12 部署，全站统一（admin/ + template/1 系列）
 * 修改字体只需改这里，无需动 codebase.min.css
 * ============================================ */

@font-face {
    font-family: "HarmonyOS Sans SC";
    src: url("../fonts/wenfont/HarmonyOS_Sans_SC_Medium.subset.woff2") format("woff2");
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

:root {
    /* body 实际读取的变量（5.11 中为字面量，必须显式覆盖） */
    --bs-body-font-family: "HarmonyOS Sans SC", "Inter", system-ui, -apple-system,
        "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans",
        Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
        "Segoe UI Symbol", "Noto Color Emoji";
    /* 其他组件读取的变量 */
    --bs-font-sans-serif: "HarmonyOS Sans SC", "Inter", system-ui, -apple-system,
        "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans",
        Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
        "Segoe UI Symbol", "Noto Color Emoji";
}

/* ============================================
 * 通用标签组件（公共标签，2026-08-12 全局定义），2026-08-12 全局化）
 * 用法：<span class="ai-tag ai-tag-green">正常</span>
 * 颜色不足时可用内联 style 覆盖背景/颜色
 * ============================================ */
.cb-tag {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.6;
    white-space: nowrap;
}
/* 标准色组合（浅底深字，对比度达标） */
.cb-tag-blue   { background: #dbeafe; color: #1d4ed8; }
.cb-tag-sky    { background: #e0f2fe; color: #0369a1; }
.cb-tag-green  { background: #dcfce7; color: #15803d; }
.cb-tag-yellow { background: #fef3c7; color: #d97706; }
.cb-tag-red    { background: #fee2e2; color: #dc2626; }
.cb-tag-purple { background: #f3e8ff; color: #7c3aed; }
.cb-tag-teal   { background: #ccfbf1; color: #0d9488; }
.cb-tag-pink   { background: #fce7f3; color: #be185d; }
.cb-tag-gray   { background: #f3f4f6; color: #6b7280; }
/* 主题色标签（跟随站点主色/颜色主题与深色模式，2026-09-14）
 * 用法：<span class="cb-tag cb-tag-primary">标签</span> */
.cb-tag-primary {
    background: rgba(2, 132, 199, .12);
    color: #0284c7;
}
html.dark .cb-tag-primary { background: rgba(2, 132, 199, .22); color: #7dd3fc; }

/* ============================================
 * 表格底部间距统一（2026-08-12）
 * Bootstrap .table 默认 margin-bottom:1rem 会叠加 block-content 的 padding，
 * 导致列表底部间距(42px)大于上/左/右(26px)。去掉表格自身 margin，由容器 padding 统一。
 * ============================================ */
#pjax-container table.table {
    margin-bottom: 0;
}

/* ============================================
 * 表格容器内 row 取消 margin-bottom（2026-08-12）
 * dataTables_wrapper 内的布局 row 被统一脚本误加 mb-3(16px)，
 * 导致列表底部间距(42px)大于其他三边(26px)。表格间距由 block-content padding 统一。
 * ============================================ */
#pjax-container .dataTables_wrapper .row {
    margin-bottom: 0 !important;
}
/* 例外：统计卡网格行（g-3 特征）显式 mb-3 时保留 16px（如用户列表页统计卡与表格之间）；表格行 mb-3 仍强制 0 */
#pjax-container .dataTables_wrapper .row.g-3.mb-3 {
    margin-bottom: 1rem !important;
}

/* ============================================
 * 手机端统计卡紧凑显示（2026-08-12）
 * 单列布局下隐藏大图标、高度自适应、数字居中，避免卡片过高过松
 * ============================================ */
@media (max-width: 575.98px) {
    #pjax-container .block-link-shadow .block-content {
        height: auto !important;
        justify-content: center;
        padding: 0.75rem 1rem !important;
    }
    /* 列表页顶部操作区：手机端搜索框缩至 2 字符宽（覆盖内联 width），功能按键只留图标 */
    .block-options .form-control[type='search'] {
        width: 2.5em !important;
        min-width: 2.5em;
        padding-left: 0.4rem;
        padding-right: 0.4rem;
    }
    .block-options .input-group {
        flex-wrap: nowrap;
    }
}

/* 列表页表格：内容自适应列宽时表头保持单行（防手机窄屏挤压导致表头换行，2026-08-31） */
.dataTables_wrapper .table th,
.table-vcenter th {
    white-space: nowrap;
}

/* 顶部操作区连体圆角（2026-09-10）：input-group 内 dropdown 包装的按钮（清空/下拉键）参与连体——
 * BS5 只处理直系子元素，.dropdown > .btn 保持自身圆角，导致与相邻控件衔接处出现圆角缺口。
 * 规则：中间一律直角，仅整个布局组首/尾保留外圆角 */
.input-group > .dropdown > .btn,
.input-group > .dropdown > .btn-group > .btn {
    border-radius: 0;
}
.input-group > .dropdown:first-child > .btn {
    border-top-left-radius: var(--bs-border-radius, .375rem);
    border-bottom-left-radius: var(--bs-border-radius, .375rem);
}
.input-group > .dropdown:last-child > .btn {
    border-top-right-radius: var(--bs-border-radius, .375rem);
    border-bottom-right-radius: var(--bs-border-radius, .375rem);
}

/* 多选计数徽标（2026-09-10）：与「选中项：删除」红色统一（解封类页面自行覆盖为绿） */
.bulk-count {
    color: #dc2626;
}


/* 黑夜模式：Codebase 暗色变量补齐（2026-09-04）——html.dark 下 --bs-body-color/-bg 保持浅底值，
 * 致弹窗/深色容器内 var() 文字（label/正文/表单文案）近黑不可见；补齐官方暗色变量后全站文字随主题变浅 */
html.dark {
    --bs-body-color: #d6d9e0;
    --bs-body-bg: #1b1f22;
    --bs-secondary-color: #9aa4b2;
    --bs-secondary-bg: #21262c;
    --bs-body-emphasis-color: #d6d9e0;
    --bs-border-color: #3a3f47;
    --bs-tertiary-bg: #191f27;
}
html.dark body {
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
}

/* 黑夜模式：官方 bg-*-op 为固定浅色块，暗色主题下改为暗色半透明 */
html.dark .bg-success-op { background-color: rgba(var(--bs-success-rgb), .12) !important; }
html.dark .bg-warning-op { background-color: rgba(var(--bs-warning-rgb), .12) !important; }
html.dark .bg-info-op    { background-color: rgba(var(--bs-info-rgb), .12) !important; }
html.dark .bg-danger-op  { background-color: rgba(var(--bs-danger-rgb), .12) !important; }
html.dark .bg-primary-op { background-color: rgba(var(--bs-primary-rgb), .12) !important; }
html.dark .bg-secondary-op { background-color: rgba(var(--bs-secondary-rgb), .12) !important; }
html.dark .bg-earth-op   { background-color: rgba(var(--bs-earth-rgb), .12) !important; }
html.dark .bg-teal-op    { background-color: rgba(var(--bs-teal-rgb), .12) !important; }
html.dark .bg-pink-op    { background-color: rgba(var(--bs-pink-rgb), .12) !important; }
html.dark .bg-purple-op  { background-color: rgba(var(--bs-purple-rgb), .12) !important; }


/* SweetAlert2 遮罩动画禁用（弹窗打开/切换时 backdrop 淡入淡出会造成闪烁） */
.swal2-container.swal2-backdrop-show,
.swal2-container.swal2-backdrop-hide {
    animation: none !important;
    -webkit-animation: none !important;
}
.swal2-container.swal2-backdrop-show {
    background: rgba(0, 0, 0, 0.4) !important;
}
/* 兜底：容器移除前的瞬间不得拦截点击/显示背景（popup 关闭动画由官方 swal2-hide 播放，不在此覆盖） */
.swal2-container.swal2-backdrop-hide {
    pointer-events: none !important;
    background: transparent !important;
}
/* SweetAlert 必须盖在 Bootstrap 弹窗之上（2026-10-01）：
   BS5 弹窗基础 z-index 1055，叠加第二个弹窗会再加 10+，而 SweetAlert 默认只有 1060 ——
   在「AI 审核弹窗」这类大弹窗里点通过/失败提示会被压在下面看不见（用户反馈「被遮挡」）。 */
.swal2-container { z-index: 20000 !important; }

/* ============================================
 * 列表底部选中项操作与分页垂直对齐（2026-08-14）
 * dataTables 官方 .dataTables_info 有 padding-top:0.85em 撑高导致
 * 选中项文字与分页不在一条水平线；此处归零由 flex align-items-center 对齐
 * ============================================ */
#pjax-container .dataTables_info {
    padding-top: 0;
}

/* ============================================
 * 顶部筛选控件统一主题（2026-09-03 更新：白底浅边框，与全局下拉新主题一致；
 * 原 2026-08-15 #f0f2f5 融入风作废——全站下拉统一视觉语言）
 * ============================================ */
#pjax-container .block-header select.form-select,
#pjax-container .block-options select.form-select,
#pjax-container .block-header input.form-control,
#pjax-container .block-options input.form-control {
    background-color: #fff;
    border-color: #e6e8ec;
    color: #3a3f4b;
}
/* 顶部筛选 select 最小宽度（2026-08-17）：form-select 箭头占 padding-right 约 38px，
 * 定宽不足（如 80-100px）时"全部状态/全部供应商"等文字被裁剪遮挡；
 * 统一 min-width 保证文字完整显示（inline width < 该值的自动加宽） */
#pjax-container .block-header select.form-select,
#pjax-container .block-options select.form-select {
    min-width: 125px !important;
}
/* 暗色模式：与全局暗色表单一致 */
html.dark #pjax-container .block-header select.form-select,
html.dark #pjax-container .block-options select.form-select,
html.dark #pjax-container .block-header input.form-control,
html.dark #pjax-container .block-options input.form-control {
    background-color: #24292f;
    border-color: #3a3f47;
    color: #d1d5db;
}

/* （2026-09-05 删除 2026-08-21 的"操作列一律纯文字"旧规则：td:last-child .btn span.d-none 强制显示 + .btn i 强制隐藏——
 * 它以 ID 特异性 + !important 压过 2026-09-04 的 ac-btn-icon 手机端显示规则（icon 永远藏、按钮空白）。
 * 现行规范见下方 ac-btn-icon/ac-btn-text 段：桌面文字、手机端仅 icon；旧式 icon(d-sm-none)+span(d-none d-sm-inline)
 * 自带响应式结构与新规范行为一致，无需额外规则） */

/* ============================================
 * 多选列固定宽度（2026-08-15，08-16 限定复选框列）
 * table-layout:fixed 表格按列宽比例摊分总宽，列宽总和 < 表格宽时多选列被拉伸（30px 变 49px）
 * 统一方案：多选列 width:2% + min/max-width:30px 锁死（百分比参与摊分但被 max-width 封顶），
 * 其余列保持原 px 宽度正常拉伸容纳内容（0 溢出）。页面多选列 th 已统一为 width:30px 系列，
 * 此规则覆盖为 2% + 锁 30px。
 * ⚠️ 用 :has(input[type="checkbox"]) 限定只作用于真正的多选列——无多选列的表格
 * （如邮件日志/奖励记录 ID 列）first-child 会被误锁 30px（2026-08-16 修复）
 * ============================================ */
#pjax-container table[style*="table-layout:fixed"] th:first-child:has(input[type="checkbox"]),
#pjax-container table[style*="table-layout: fixed"] th:first-child:has(input[type="checkbox"]) {
    width: 2% !important;
    min-width: 30px !important;
    max-width: 30px !important;
}

/* ============================================
 * 多选框列锁宽全站补全（2026-09-06）：上一条只覆盖 table-layout:fixed 的表格，
 * 弹窗内表格与 auto 布局表格的首列多选框在手机端被挤压（实测 100~139px）。
 * 按批量选择框的 name="ids[]" 精确定位（不误伤状态开关列），不限列位置——
 * 手机端操作列前置后多选列在第 2 列、未前置/桌面在首列均生效；弹窗内表格同步覆盖。
 * ============================================ */
#pjax-container table th:has(input[name="ids[]"]),
#pjax-container table td:has(input[name="ids[]"]),
.modal table th:has(input[name="ids[]"]),
.modal table td:has(input[name="ids[]"]) {
    width: 30px !important;
    min-width: 30px !important;
    max-width: 30px !important;
    padding-left: 3px !important;
    padding-right: 3px !important;
    text-align: center !important;
}

/* ============================================
 * 手机端操作列按钮紧凑化（2026-09-06）：icon 化后多按钮列仍占 110~140px
 * （btn-sm 左右 padding 8px×N 叠加），压缩到 5px 让出宽度给数据列
 * ============================================ */
@media (max-width: 767.98px) {
    #pjax-container table td:first-child .btn,
    #pjax-container table td:last-child .btn {
        padding-left: 5px !important;
        padding-right: 5px !important;
    }
}

/* ============================================
 * 操作列前置豁免多选列 30px 锁（2026-09-06）
 * 各列表页有「first-child 锁 30px」的多选列页面级规则（历史多选列规范），
 * 操作列移动端前置到 first-child 后被该规则误锁成 30px——按钮竖排/截断（公告/通知列表实测）。
 * 前置断点内对「含 .btn 的 first-child 列」豁免：恢复操作列自然宽度（min 80px）。
 * :has(.btn) 限定只有操作列豁免，多选列（checkbox）照常锁 30。
 * ============================================ */
@media (max-width: 991.98px) {
    #pjax-container table.col-ops-first-mobile th:first-child:has(.btn),
    #pjax-container table.col-ops-first-mobile td:first-child:has(.btn) {
        min-width: 80px !important;
        max-width: none !important;
        width: auto !important;
    }
}

/* ============================================
 * 侧边栏隐藏滚动条（2026-08-16）
 * 保留滚动功能，仅隐藏滚动条视觉（浅色/暗夜模式通用）
 * ============================================ */
#sidebar .js-sidebar-scroll {
    scrollbar-width: none;
    -ms-overflow-style: none;
}
#sidebar .js-sidebar-scroll::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
}

/* ============================================
 * 侧边栏 SimpleBar 滚动条隐藏（2026-08-16）
 * .js-sidebar-scroll 被 SimpleBar 接管（class 含 simplebar-scrollable-y），
 * 滚动条是 .simplebar-scrollbar 伪元素，webkit/scrollbar-width 规则对它无效，
 * 单独隐藏它即可（滚动功能由 SimpleBar 正常处理）
 * ============================================ */
#sidebar .js-sidebar-scroll .simplebar-scrollbar {
    display: none;
}

/* ============================================
 * 登录页角色切换标签：选中态圆角（2026-10-03 用户要求）
 * 三端登录页（user|agent|developer/login.php）用官方 nav-tabs-block 当登录框标题栏，
 * 官方样式里 .nav-tabs-block .nav-link 是 border-radius:0（块状标签贴边铺满），
 * 选中态看着是「直角白块」；这里给它加圆角与一点内缩，选中态变成一个圆角白胶囊。
 * 作用域用登录页专属的 .js-validation-signin，不影响后台/代理端/开发者中心里的其它标签页。
 * ============================================ */
.js-validation-signin .nav-tabs-block .nav-link {
    border-radius: 6px;
    margin: 4px 2px;
}

.js-validation-signin .nav-tabs-block .nav-item:first-child .nav-link {
    margin-left: 6px;
}

.js-validation-signin .nav-tabs-block .nav-item:last-child .nav-link {
    margin-right: 6px;
}

.js-validation-signin .nav-tabs-block .nav-link.active,
.js-validation-signin .nav-tabs-block .nav-item.show .nav-link {
    border-radius: 6px;
}

/* ============================================
 * 主内容区 SimpleBar 滚动（2026-08-16）
 * body 原生滚动 → #main-container 内部滚动，滚动条由 SimpleBar 接管（隐藏原生滚动条），
 * 布局：header 固定 4.25rem，main 用 margin-top 下移 + height 撑满剩余视口，
 * 初始化与 pjax 后重算在 footer.php（_mainSimpleBar）
 * ============================================ */
/* 只作用于「带固定顶栏的主框架页」（后台 / 代理端 / 开发者中心）。
   注意别写成裸的 #main-container：登录页（admin|agent|developer/login.php）用的是
   同一套 #page-container > #main-container 结构，但它没有 page-header-fixed，
   被这条规则命中会在顶部多出 4.25rem（68px）空白（2026-09-17 修） */
#page-container.page-header-fixed #main-container {
    height: calc(100vh - 4.25rem);
    margin-top: 4.25rem;
    /* codebase 的 #page-container.page-header-fixed #main-container 特异性更高，
       必须 !important 才能盖掉其 padding-top:4.25rem（否则 margin+padding 双重 68px 间距） */
    padding-top: 0 !important;
    overflow-y: auto;
}

/* ============================================
 * SimpleBar mask 不创建 stacking context（2026-08-16）
 * .simplebar-mask 自带 position:absolute + z-index:0，会把 #pjax-container 内
 * 弹窗的 z-index(1055) 锁在 0 层级，打不过 body 上的 .modal-backdrop(1050)，
 * 导致所有弹窗被遮罩层挡住。改 z-index:auto 消除隔离（mask 无兄弟层叠需求，视觉不变）
 * ============================================ */
#main-container .simplebar-mask {
    z-index: auto;
}

/* ============================================
 * 全局滚动条统一（2026-08-17）
 * 原生滚动条统一为细条+圆角+半透明灰色（接近 SimpleBar 视觉），
 * 侧边栏/主内容区由 SimpleBar 接管不受影响；浅色/暗色模式适配
 * ============================================ */
* {
    scrollbar-width: thin;
    scrollbar-color: rgba(128, 128, 128, 0.4) transparent;
}
*::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}
*::-webkit-scrollbar-track {
    background: transparent;
}
/* 隐藏滚动条两端箭头（SimpleBar 官方风格无箭头，2026-08-17） */
*::-webkit-scrollbar-button {
    display: none !important;
    height: 0;
    width: 0;
}

/* ============================================
 * 全局滚动条统一（2026-08-17）
*::-webkit-scrollbar-thumb {
    background-color: rgba(128, 128, 128, 0.4);
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover {
    background-color: rgba(128, 128, 128, 0.6);
}
html.dark *::-webkit-scrollbar-thumb {
    background-color: rgba(255, 255, 255, 0.25);
}
html.dark *::-webkit-scrollbar-thumb:hover {
    background-color: rgba(255, 255, 255, 0.4);
}

/* ============================================
 * 后台手机端统一适配（2026-08-21，全站一次性修复三类问题）
 * 1) 列表多选列被挤压消失 → 锁 30px（不限 table-layout，覆盖 JS 渲染表格）
 * 2) 操作列按钮被挤压 → 不换行 + 自动宽
 * 3) 顶部筛选控件（select/搜索框/日期）手机端隐藏（按钮保留）
 * ============================================ */
@media (max-width: 991.98px) {
    /* ===== 手机端列表内容防压缩体系（三层保障）=====
     * 第一层：auto 布局——列宽由内容决定，永远不会被比例压缩到 0
     * 第二层：单元格单行省略——内容截断显示，不会撑爆列或换行成多行
     * 第三层：列宽上限——任何单列不超过 220px，防长文本/URL 独占表格 */
    #pjax-container table[id],
    #pjax-container .table.table-bordered {
        table-layout: auto !important;
    }
    /* 所有单元格：单行 + 省略号 + 列宽上限 */
    #pjax-container table th,
    #pjax-container table td {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 220px;
    }
    /* 多选列锁宽 */
    #pjax-container table th:first-child:has(input[type="checkbox"]),
    #pjax-container table td:first-child:has(input[type="checkbox"]) {
        width: 30px !important;
        min-width: 30px !important;
        max-width: 30px !important;
        padding-left: 2px !important;
        padding-right: 2px !important;
    }

    /* 2) 操作列：手机端保持一行不换行（2026-08-21 用户否决纵向堆叠方案）
     * auto 布局 + nowrap 下 min-content = 按钮整行宽，列不会被压窄；
     * 表格总宽超出时走外层 col-sm-12[overflow-x:auto] 横向滚动，按钮永不换行 */
    #pjax-container table th:last-child,
    #pjax-container table td:last-child {
        white-space: nowrap;
        max-width: none;  /* 豁免第三层 220px 列宽上限：多按钮操作列超上限会被 overflow:hidden 裁切 */
        overflow: visible;
    }
    /* 操作格内有包装 div 的页面：强制横向排列，防页面级/框架 flex-column 或换行 */
    #pjax-container table td:last-child > div,
    #pjax-container table td:last-child .d-flex {
        flex-direction: row !important;
        flex-wrap: nowrap !important;
        align-items: center !important;
        justify-content: center !important;
    }
    #pjax-container table td:last-child .btn {
        white-space: nowrap;
        flex-shrink: 0;
    }

    /* 3) 顶部筛选控件手机端隐藏：筛选 select/日期输入隐藏（按钮保留）；
     *    搜索框保留（2026-08-21 用户要求：搜索框要留、筛选框不留），另行缩窄到约两字宽。
     *    ⚠️ 日期输入用 flatpickr（type=text + readonly，占位符「开始日期/结束日期」），
     *    只按 placeholder*=「时间」匹配会漏掉它们（2026-09-16 实测手机端仍显示），所以补「日期」 */
    #pjax-container .block-options .form-select-sm,
    #pjax-container .block-options .form-control-sm[placeholder*="时间"],
    #pjax-container .block-options .form-control-sm[placeholder*="日期"],
    #pjax-container .block-options .input-group-text,
    #pjax-container .block-header .form-select-sm,
    #pjax-container .block-options .select2-container,
    #pjax-container .block-header .select2-container {
        display: none !important;
    }
    /* 搜索框手机端缩窄：约两字符完整可见（4em = 2字 + padding/边框 + 右侧按键余量；flex:0 0 auto 防拉伸压缩） */
    #pjax-container .block-options input[type="search"],
    #pjax-container .block-header input[type="search"] {
        flex: 0 0 auto !important;
        width: 4em !important;
        min-width: 0 !important;
    }

    /* 表单表格豁免（列表页内 td 是输入控件的表格）：压缩规则不适用——
     * 解除列宽上限/裁切，th/td 各保底 120px，由 table-responsive 横向滚动 */
    #pjax-container table:has(td .form-control) th,
    #pjax-container table:has(td .form-control) td,
    #pjax-container table:has(td .form-select) th,
    #pjax-container table:has(td .form-select) td {
        max-width: none;
        overflow: visible;
        min-width: 120px;
    }

    /* 空态单元格豁免：colspan 整行空态不受 220px 列宽上限截断（否则整行只剩左侧
       220px 内居中、视觉偏左），撑满表格宽度真正居中 */
    #pjax-container table td.dataTables_empty {
        max-width: none;
        overflow: visible;
    }

}

/* ============================================
 * 弹窗高度固定 + 内容区限高内滚（2026-09-13 重构，取代此前的 80vh / 10.5rem 魔数方案）
 *
 * 结构：.modal > .modal-dialog(.modal-dialog-centered) > .modal-content > .block
 *       > 头部 + 内容区 + 按钮区(.border-top)
 *
 * 高度由 BS 原生 .modal-dialog-centered 的
 *   min-height: calc(100% - var(--bs-modal-margin) * 2)
 * 决定（= 视口高 - 上下边距）；再用同口径的 max-height 把 .block 钉住，
 * .block 变 flex 列：头部/按钮区保持自然高度，中间内容区吸收剩余高度并内滚。
 * 于是不论弹窗内容多少，dialog 高度都固定，且 dialog 不会因内容超高被 max-height 夹住。
 *
 * 为什么必须避免 dialog 被夹住：一旦被夹住，dialog 就成了「兜底滚动层」，
 * 弹窗右侧会多出一条外部滚动条、滚轮还会带着整个弹窗上移
 * （Chrome 会把内部滚动容器的滚动高度算进 dialog 的 scrollHeight）。
 *
 * 历史坑：旧方案在内容区写死 max-height:80vh / calc(100dvh - 10.5rem) 这类魔数来预留头尾高度，
 * 只要某个弹窗的头部+按钮区不是 121px（10.5rem 的隐含假设）就会溢出并触发上述外部滚动条。
 * 改为 flex 后不再依赖魔数，头部/按钮区多高都能自洽。
 * 内容少的弹窗保持收窄（flex 只缩不涨），靠 dialog 的 min-height 居中。
 * ============================================ */
.modal .modal-content > .block {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - var(--bs-modal-margin, 1.75rem) * 2); /* 回退：旧浏览器无 dvh */
    max-height: calc(100dvh - var(--bs-modal-margin, 1.75rem) * 2); /* 真机地址栏伸缩时不溢出 */
}
.modal .modal-content > .block > * {
    flex: 0 0 auto; /* 头部/按钮区等保持自然高度，不参与压缩 */
}
.modal .modal-content > .block > .block-content:not(.border-top) {
    flex: 0 1 auto; /* 只缩不涨：仅中间内容区让出高度 */
    min-height: 0; /* 允许收缩到内容高度以下，否则 flex 不会缩 */
    overflow-y: auto;
    overflow-x: hidden;
}

/* 弹窗内容区底部与按钮区分隔线的间距（2026-09-30 用户要求 + 统一规范）
 * Codebase 的 .block-content 默认 padding-bottom 只有 1px（底部间距本该由最后一段内容自己带），
 * 于是「内容区最后一个分组/表格」会紧贴按钮区上方那条分隔线，看着很挤（应用列表三个弹窗实测 1px）。
 * 这里给「带按钮区的弹窗内容区」统一补 18px；`.block-content-full`（没有按钮区、内容区当最后一块）保持
 * 它自己的 1.625rem 不变，别被这条覆盖。 */
.modal .modal-content > .block > .block-content:not(.border-top):not(.block-content-full) {
    padding-bottom: 18px;
}

/* 弹窗内用 .card 承载内容、不走上面 .block 结构的（历史上只有前台公告弹窗 #modal-onshou 是这样，
 * 它 2026-09-30 已改成首页自有的 .custom-modal-overlay 组件，不再走 Bootstrap 弹窗），
 * 这里补同样的限高内滚作为兜底：将来再出现 card 结构弹窗时无需单独处理。 */
.modal .modal-content > .card {
    max-height: calc(100vh - var(--bs-modal-margin, 1.75rem) * 2); /* 回退：旧浏览器无 dvh */
    max-height: calc(100dvh - var(--bs-modal-margin, 1.75rem) * 2);
    overflow-y: auto;
    overflow-x: hidden;
}

/* 弹窗标题单行截断（2026-08-31：手机端长标题换行会撑高标题栏，弹窗整体被顶出视口） */
.modal .block-header .block-title {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.modal .block-header .block-options {
    flex-shrink: 0;
    margin-left: auto;
}

/* ============================================
 * 弹窗内「标题 + 主体内容」分组模板（2026-09-30 用户要求）
 *
 * 长表单弹窗（应用列表的 添加/编辑、授权信息、更新信息）统一用它分组：
 *   每个分组 = 标题头（组名 + 可选说明/右侧操作） + 主体内容区
 * 结构：
 *   <div class="msec">
 *     <div class="msec-head"><span class="msec-title"><i class="si si-xxx"></i>组名</span>
 *                          <span class="msec-hint">可选说明</span></div>
 *     <div class="msec-body">字段（row + col-sm-*，字段用 mb-3）</div>
 *   </div>
 * 原先是「灰色大写 h5 小标题 + 平铺字段」，分组边界看不清；现在标题头带浅底与分隔线，
 * 主体区独立成块，扫一眼就知道哪几个字段是一组。
 * ============================================ */
.modal .msec {
    border: 1px solid #e6e8ec;
    border-radius: 10px;
    margin-bottom: 14px;
}

.modal .msec:last-child { margin-bottom: 0; }

.modal .msec-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    padding: 9px 14px;
    border-bottom: 1px solid #e6e8ec;
    border-radius: 9px 9px 0 0;
    background: rgba(148, 163, 184, .08);
}

.modal .msec-title {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #6c757d;
}

.modal .msec-title i { font-size: .95rem; opacity: .75; }

.modal .msec-hint {
    font-size: .75rem;
    color: #9ca3af;
}

/* 主体区：底部留 2px，由最后一个字段自己的 mb-3 提供下边距（避免出现双倍留白） */
.modal .msec-body { padding: 14px 14px 2px; }

html.dark .modal .msec { border-color: #2f3237; }
html.dark .modal .msec-head { border-bottom-color: #2f3237; background: rgba(148, 163, 184, .12); }
html.dark .modal .msec-title { color: #9aa3af; }
html.dark .modal .msec-hint { color: #6b7280; }

/* ============================================
 * 粘性表头补线（2026-09-14）
 * border-collapse: collapse 下，表头行的上下边框属于表格的折叠边框网格，
 * 不会跟着 position:sticky 的表头一起粘住 —— 滚动列表时表头上下横线消失
 * （更新包列表 78 行，滚动时最明显）。
 * 做法：把表头行的上下边框置为透明，改用 inset 阴影补线——阴影不参与折叠边框网格，
 * 会随表头一起移动；静止时线宽仍是 1px（不会与边框叠成 2px）。
 * 用法：给粘性表头加 class="thead-sticky"。颜色与项目表格边框一致：浅 #e4e7ed / 深 #181b1e
 * ============================================ */
.table > thead.thead-sticky > tr,
.table > thead.thead-sticky > tr > * {
    border-top-color: transparent;
    border-bottom-color: transparent;
}
.table > thead.thead-sticky > tr > * {
    box-shadow: inset 0 -1px 0 #e4e7ed, inset 0 1px 0 #e4e7ed;
}
html.dark .table > thead.thead-sticky > tr > * {
    box-shadow: inset 0 -1px 0 #181b1e, inset 0 1px 0 #181b1e;
}

/* ============================================
 * 输入框组内的「JS 追加操作位」（2026-09-14）
 * 场景：上传按钮后面要由 JS 追加按钮（如 #Releasestatehtml 的「删除安装包」）。
 * display:contents 让追加进来的按钮直接成为 input-group 的 flex 项、紧跟上传按钮，
 * 再补上 Bootstrap 只给直接子元素加的负外边距与左侧圆角归零，视觉上拼成一组。
 * ============================================ */
.input-group > [data-inline-actions] {
    display: contents;
}
.input-group > [data-inline-actions] > .btn {
    margin-left: calc(var(--bs-border-width, 1px) * -1);
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* 二级弹窗堆叠层级（2026-09-02：AI 助手等二级弹窗叠在主弹窗上时，遮罩与层级错乱导致上层弹窗被盖）
 * 遮罩同步提升：.modal-backdrop 默认 1050，二级/三级遮罩要插在主弹窗(1055/1070)与上层弹窗之间，
 * 否则二级遮罩会被主弹窗盖住、或主弹窗浮在遮罩之上（表现为遮罩"慢半拍/没盖住"） */
.modal-stack-2 {
    z-index: 1070;
}
.modal-stack-3 {
    z-index: 1085;
}
.modal-backdrop.modal-stack-2 {
    z-index: 1062;
}
.modal-backdrop.modal-stack-3 {
    z-index: 1077;
}

/* 原生下拉统一风格（2026-09-03：全站下拉与 Select2 定制主题对齐） */
.form-select {
    border-color: #e6e8ec;
    border-radius: 4px;
    background-color: #fff;
}
.form-select:focus {
    border-color: #e6e8ec;
    box-shadow: none;
}
html.dark .form-select {
    background-color: #24292f;
    border-color: #3a3f47;
    color: #f3f6f9;
}
html.dark .form-select:focus {
    border-color: #3a3f47;
    box-shadow: none;
}

/* Select2 贴合 Codebase 模板主题（2026-09-03：自模板设置页页面级迁移全局，所有 js-select2 生效） */
/* 容器双类前缀保证特异性压过 select2.min.css（该文件在 custom.css 之后加载，同特异性会被其覆盖） */
.select2-container.select2-container--default .select2-selection--single,
html.dark .select2-container.select2-container--default .select2-selection--single {
    height: 42px;
    border: 1px solid #e6e8ec;
    border-radius: 4px;
    background: #fff;
    box-shadow: none;
}
/* 弹窗内下拉：38px 对齐弹窗输入框（Bootstrap 默认 form-control）（2026-09-04） */
.modal .select2-container.select2-container--default .select2-selection--single,
html.dark .modal .select2-container.select2-container--default .select2-selection--single {
    height: 38px;
}
/* 弹窗内输入框补到 38px 与下拉等高（2026-09-15）：
 * 上面那条规则是按「弹窗输入框 38px」定的，但实际各弹窗字段写的是 .form-control.fs-sm（只有 35px），
 * 同一行里「输入框 35 / 下拉 38」会差 3px。这里按原意把弹窗输入框统一到 38px
 * （排除小号 .form-control-sm 与文本域；用 min-height 保证大字号不被裁切）。 */
.modal .block-content .form-control:not(textarea):not(.form-control-sm) {
    min-height: 38px;
}
/* 小号下拉（列表顶部筛选 form-select-sm 等）：31px 与 input-sm 对齐（2026-09-04） */
select.form-select-sm.select2-hidden-accessible + .select2-container.select2-container--default .select2-selection--single,
html.dark select.form-select-sm.select2-hidden-accessible + .select2-container.select2-container--default .select2-selection--single {
    height: 31px;
}
html.dark .select2-container.select2-container--default .select2-selection--single {
    background: #24292f;
    border-color: #3a3f47;
}
.select2-container.select2-container--default .select2-selection--single .select2-selection__rendered,
html.dark .select2-container.select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: 40px;
    padding-left: 10px;
    color: var(--bs-body-color);
}
.modal .select2-container.select2-container--default .select2-selection--single .select2-selection__rendered,
html.dark .modal .select2-container.select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: 36px;
}
select.form-select-sm.select2-hidden-accessible + .select2-container.select2-container--default .select2-selection--single .select2-selection__rendered,
html.dark select.form-select-sm.select2-hidden-accessible + .select2-container.select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: 29px;
    font-size: 12px; /* 小号筛选下拉文字与同排 input-sm 搜索框一致（2026-09-04） */
}
.select2-container.select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 40px;
}
.modal .select2-container.select2-container--default .select2-selection--single .select2-selection__arrow,
html.dark .modal .select2-container.select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 36px;
}
select.form-select-sm.select2-hidden-accessible + .select2-container.select2-container--default .select2-selection--single .select2-selection__arrow,
html.dark select.form-select-sm.select2-hidden-accessible + .select2-container.select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 29px;
}
/* 暗色模式：下拉容器深底下文字/箭头/面板选项显式浅色，避免 var(--bs-body-color) 解析仍为深色字看不清（2026-09-04） */
html.dark .select2-container.select2-container--default .select2-selection--single .select2-selection__rendered {
    color: #d6d9e0;
}
html.dark .select2-container.select2-container--default .select2-selection--single .select2-selection__arrow b {
    border-color: #9aa4b2 transparent transparent transparent;
}
html.dark .select2-container.select2-container--default .select2-results__option {
    color: #d6d9e0;
}
.select2-container.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container.select2-container--default.select2-container--open .select2-selection--single {
    border-color: #d7dce3;
    box-shadow: none;
}
.select2-dropdown,
html.dark .select2-dropdown {
    border: 1px solid #e6e8ec;
    border-radius: 6px;
    background: #fff;
    box-shadow: 0 4px 14px rgba(15, 23, 42, .08);
}
html.dark .select2-dropdown {
    background: #1f242b;
    border-color: #3a3f47;
}
/* 下拉面板挂载 body 顶层：z-index 高于弹窗/遮罩，任何容器内不可被裁切或遮挡（2026-09-04） */
.select2-container, html.dark .select2-container { z-index: 2000 !important; }
.select2-dropdown, html.dark .select2-dropdown { z-index: 2001 !important; }
.select2-container.select2-container--default .select2-results__options {
    padding: 6px;
}
.select2-container.select2-container--default .select2-results__option {
    padding: 6px 10px;
    margin: 1px 0;
    border-radius: 4px;
    font-size: .875rem;
    transition: background-color .12s ease, color .12s ease;
}
/* 官方库风格：hover/选中浅蓝底+品牌蓝字，选中项加粗（Bootstrap5-select2 官方配色，2026-09-04） */
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable,
.select2-container--default .select2-results__option--selected {
    background: #e7f1ff;
    color: #0a58ca;
}
.select2-container--default .select2-results__option--selected {
    font-weight: 600;
}
html.dark .select2-container--default .select2-results__option--highlighted.select2-results__option--selectable,
html.dark .select2-container--default .select2-results__option--selected {
    background: rgba(13, 110, 253, .16);
    color: #8ab4f8;
}

/* input-group 内 Select2 连体圆角适配（2026-09-03：筛选/组合控件内的下拉 Select2 化后
 * 沿 input-group 剥离相邻圆角，保持与其他组成元素连体一致） */
.input-group .select2-container .select2-selection--single {
    border-radius: 0;
}
.input-group > .select2-container:first-of-type .select2-selection--single {
    border-radius: 4px 0 0 4px;
}
.input-group > .select2-container:last-child .select2-selection--single {
    border-radius: 0 4px 4px 0;
}
.input-group > .select2-container:first-child:last-child .select2-selection--single {
    border-radius: 4px;
}


/* ===== 暗色模式：弹窗内硬编码浅色元素全局适配（2026-09-03） ===== */
/* 接口配置弹窗参数卡（本地接口/中转接口/AI渠道 api-config-section：内联样式写死 #fafafa） */
html.dark .api-config-section {
    background: #21262c !important;
    border-color: #3a3f47 !important;
}
html.dark .api-config-section h6 {
    color: #b8c0cc !important;
    border-bottom-color: #3a3f47 !important;
}
/* 参数表隔行浅灰 */
html.dark .object-row {
    background-color: #262b31 !important;
}
/* 可用用户选择列表（接口可调用人/群发/奖励对象弹窗 user-name 写死 #333） */
html.dark .user-name {
    color: #e8ecf1 !important;
}
html.dark .user-email {
    color: #9aa4b2 !important;
}
/* AI 开发弹窗代码块 pre.bg-light 固定浅底 */
html.dark pre.bg-light {
    background-color: #1f242b !important;
    color: #d6d9e0 !important;
}
/* 接口图标预览框（内联 #f8f9fa） */
html.dark #new_api_icon_preview {
    background: #262b31 !important;
    border-color: #3a3f47 !important;
}
/* AI 开发上传拖拽区常态（悬停态由 JS 按主题分支 setProperty important 设置） */
html.dark #aiDropZone {
    background: #21262c !important;
    border-color: #3a3f47 !important;
}

/* ===== 暗色模式：中转接口/AI渠道弹窗同构浅色元素（2026-09-03 第二轮） ===== */
html.dark .proxy-config-section {
    background: #21262c !important;
    border-color: #3a3f47 !important;
}
html.dark .proxy-config-section h6 {
    color: #b8c0cc !important;
    border-bottom-color: #3a3f47 !important;
}
/* 标签输入容器（排除/提取/包装/状态码白底） */
html.dark .exclude-tags-container {
    background: #1b1f22 !important;
    border-color: #3a3f47 !important;
}
html.dark .exclude-tags-container:focus-within {
    border-color: #5b8ff9 !important;
    box-shadow: 0 0 0 0.15rem rgba(91, 143, 249, 0.15) !important;
}
/* 中转接口图标预览框（新增/编辑两处） */
html.dark #newp_api_icon_preview,
html.dark #api_icon_preview {
    background: #262b31 !important;
    border-color: #3a3f47 !important;
}
/* AI 思考过程折叠区 */
html.dark #proxyAiThinkBody {
    background: #1b1f22 !important;
    border-color: #3a3f47 !important;
}
/* 帮助/示例代码块（pre 内联浅底） */
html.dark pre[style*="background"] {
    background: #1f242b !important;
    color: #d6d9e0 !important;
}
/* AI 渠道弹窗：密钥列表/分组勾选容器 */
html.dark #keyListContainer,
html.dark #groupCheckboxes {
    background: #21262c !important;
}
/* 评论弹窗等 bg-light 内容块 */
html.dark .block-content.block-content-full.bg-light {
    background-color: #1f242b !important;
}

/* ===== 暗色模式：其余后台弹窗/面板浅色容器（2026-09-03 第三轮全局兜底） ===== */
/* AI模型容量配置折叠卡（header/body/勾选标签） */
html.dark .cap-config-header {
    background: #21262c !important;
    border-bottom-color: #3a3f47 !important;
}
html.dark .cap-config-header:hover {
    background: #262b31 !important;
}
html.dark .cap-config-header .cap-config-title {
    color: #d6d9e0 !important;
}
html.dark .cap-config-body {
    background: #1b1f22 !important;
}
html.dark .cap-tag {
    background: #262b31 !important;
    border-color: #3a3f47 !important;
    color: #b8c0cc !important;
}
html.dark .cap-tag:hover {
    border-color: #5b8ff9 !important;
    color: #93c5fd !important;
}
/* 本地接口弹窗可用用户选择卡片（user-card 白底） */
html.dark .user-card {
    background-color: #1b1f22 !important;
    border-color: #3a3f47 !important;
}
/* AI操练场检查面板卡片（insp-card 白底） */
html.dark .insp-card {
    background: #1b1f22 !important;
    border-color: #3a3f47 !important;
}
html.dark .insp-card .insp-thumb {
    background: #262b31 !important;
}
html.dark .insp-card .insp-prompt {
    color: #9aa4b2 !important;
}
/* 网站设置首页背景图列表（bgimg-list 容器/缩略图/占位） */
html.dark .bgimg-list {
    background: #1b1f22 !important;
    border-color: #3a3f47 !important;
}
html.dark .bgimg-thumb {
    background: #262b31 !important;
    border-color: #3a3f47 !important;
}
html.dark .bgimg-ph {
    background: #262b31 !important;
}
/* AI违规词自定义分类（cat-custom 灰底） */
html.dark .cat-custom {
    background: #262b31 !important;
    border-color: #3a3f47 !important;
    color: #d6d9e0 !important;
}
/* 文章页标签输入容器（artice-tags-container 同 exclude-tags 结构） */
html.dark .artice-tags-container {
    background: #1b1f22 !important;
    border-color: #3a3f47 !important;
}
/* 在线客服/工单聊天气泡：对方/用户白底改暗（己方深色气泡保留） */
html.dark #svcDetailMsgs .sd-msg.ai .sd-bubble {
    background: #21262c !important;
    color: #d6d9e0 !important;
    border-color: #3a3f47 !important;
}
html.dark #chat-messages .chat-msg.user .chat-msg-bubble {
    background: #21262c !important;
    color: #d6d9e0 !important;
}

/* ===== 弹窗外层锁滚：modal 容器禁止整体滚动（2026-09-04） =====
 * 现状：block-content 限高规则只保证内容区内滚；modal 容器自身仍可滚
 * （scrollHeight 包含滚动内容时 > 视口），滚轮会带动整个弹窗移出视口。
 * 锁死 .modal 后滚动只发生在内容区（正常情况）或 dialog 自身（极小视口兜底） */
.modal {
    overflow: hidden !important;
}
.modal-dialog {
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
}

/* 断掉滚动内容向弹窗层的几何传播：block 收住内部滚动容器，
 * 否则 Chrome 将 block-content 的滚动高度计入 dialog 的 scrollHeight，
 * dialog（兜底滚动层）会出现外部滚动条并可滚，导致弹窗整体上移 */
.modal .modal-content > .block {
    overflow: hidden;
}

/* Select2 隐藏原生 select 的几何修正（2026-09-04 弹窗滚动根因）：
 * select2 把原生 select 设为 absolute 1px 隐藏，未设 top/left 时按流内静态位置
 * 定位（表单深处 2000px+），而其定位祖先直接是 .modal-content(relative)，
 * 会把 modal-content/dialog 的 scrollHeight 撑出一条外部滚动层，
 * 滚轮滚动该层时整个弹窗上移。显式钉回原点后 1px 隐藏元素不再撑高几何。 */
.select2-hidden-accessible {
    top: 0 !important;
    left: 0 !important;
}

/* ===== 暗色模式：cb-tag 自定义标签（浅底深字→半透明底浅字，2026-09-04） ===== */
html.dark .cb-tag-blue   { background: rgba(59, 130, 246, .16); color: #93c5fd; }
html.dark .cb-tag-sky    { background: rgba(14, 165, 233, .16); color: #7dd3fc; }
html.dark .cb-tag-green  { background: rgba(34, 197, 94, .15);  color: #86efac; }
html.dark .cb-tag-yellow { background: rgba(245, 158, 11, .16); color: #fcd34d; }
html.dark .cb-tag-red    { background: rgba(239, 68, 68, .16);  color: #fca5a5; }
html.dark .cb-tag-purple { background: rgba(168, 85, 247, .16); color: #d8b4fe; }
html.dark .cb-tag-teal   { background: rgba(20, 184, 166, .16); color: #5eead4; }
html.dark .cb-tag-pink   { background: rgba(236, 72, 153, .16); color: #f9a8d4; }
html.dark .cb-tag-gray   { background: rgba(148, 163, 184, .16); color: #cbd5e1; }

/* ===== 暗色模式：AI操练场（pg-* 全套，2026-09-04） ===== */
/* 左侧会话列表 */
html.dark .pg-left { background: #1b1f22 !important; border-right-color: #3a3f47 !important; }
html.dark .pg-left .lh { border-bottom-color: #3a3f47 !important; }
html.dark .pg-left .li { border-bottom-color: #2a2f36 !important; }
html.dark .pg-left .li:hover { background: rgba(59, 130, 246, .08) !important; }
html.dark .pg-left .li.act { background: rgba(59, 130, 246, .16) !important; }
html.dark .pg-left .li .lt { color: #d6d9e0 !important; }
html.dark .pg-left .li .lm .model-tag { background: rgba(99, 102, 241, .16) !important; color: #a5b4fc !important; }
html.dark .pg-left .li .lm .mode-tag.sync { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; }
html.dark .pg-left .li .lm .mode-tag.async { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; }
html.dark .pg-left .li .lm .cost-tag { color: #fca5a5 !important; }
html.dark .pg-left .li .ld:hover { color: #fca5a5 !important; background: rgba(239, 68, 68, .12) !important; }
/* 中部工具栏 */
html.dark .pg-toolbar { background: #21262c !important; border-bottom-color: #3a3f47 !important; }
html.dark .pg-toolbar .tb-label { color: #9aa4b2 !important; }
html.dark .pg-toolbar .tb-sep { background: #3a3f47 !important; }
html.dark .pg-toolbar .tb-check .ck-box { border-color: #3a3f47 !important; }
html.dark .pg-toolbar .tb-check .ck-label { color: #9aa4b2 !important; }
html.dark .pg-toolbar .mode-switch { background: #262b31 !important; }
html.dark .pg-toolbar .mode-switch .mode-btn { color: #9aa4b2 !important; }
html.dark .pg-toolbar .mode-switch .mode-btn:hover { color: #d6d9e0 !important; }
html.dark .pg-toolbar .mode-switch .mode-btn.active { background: rgba(59, 130, 246, .22) !important; color: #93c5fd !important; box-shadow: none !important; }
/* 四种下拉（模型/渠道/端点/分组） */
html.dark .model-dropdown .dd-trigger,
html.dark .channel-dropdown .dd-trigger,
html.dark .endpoint-dropdown .dd-trigger,
html.dark .group-dropdown .dd-trigger { background: #1b1f22 !important; border-color: #3a3f47 !important; }
html.dark .model-dropdown.locked .dd-trigger,
html.dark .channel-dropdown.locked .dd-trigger,
html.dark .endpoint-dropdown.locked .dd-trigger,
html.dark .group-dropdown.locked .dd-trigger { background: #262b31 !important; }
html.dark .channel-dropdown .dd-trigger:hover,
html.dark .model-dropdown .dd-trigger:hover,
html.dark .group-dropdown .dd-trigger:hover { border-color: #5b8ff9 !important; }
html.dark .model-dropdown .dd-panel,
html.dark .channel-dropdown .dd-panel,
html.dark .endpoint-dropdown .dd-panel,
html.dark .group-dropdown .dd-panel { background: #1f242b !important; border-color: #3a3f47 !important; box-shadow: 0 8px 24px rgba(0, 0, 0, .45) !important; }
html.dark .model-dropdown .dd-search { background: #1f242b !important; border-bottom-color: #3a3f47 !important; }
html.dark .model-dropdown .dd-search input { background: #1b1f22 !important; border-color: #3a3f47 !important; color: #d6d9e0 !important; }
html.dark .channel-dropdown .dd-item,
html.dark .endpoint-dropdown .dd-item,
html.dark .group-dropdown .dd-item,
html.dark .model-dropdown .dd-item { color: #d6d9e0 !important; }
html.dark .channel-dropdown .dd-item:hover,
html.dark .endpoint-dropdown .dd-item:hover,
html.dark .group-dropdown .dd-item:hover,
html.dark .model-dropdown .dd-item:hover { background: rgba(59, 130, 246, .08) !important; }
html.dark .channel-dropdown .dd-item.active,
html.dark .endpoint-dropdown .dd-item.active,
html.dark .group-dropdown .dd-item.active,
html.dark .model-dropdown .dd-item.active { background: rgba(59, 130, 246, .16) !important; }
html.dark .channel-dropdown .dd-item .ch-tag,
html.dark .channel-dropdown .dd-trigger .dd-content .ch-tag { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; }
html.dark .group-dropdown .dd-item .gp-ratio,
html.dark .group-dropdown .dd-trigger .dd-content .gp-ratio { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; }
/* 类型标签九色（同 cb-tag 暗色方案） */
html.dark .type-tag-chat, html.dark .mi-tag.chat { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; }
html.dark .type-tag-completions { background: rgba(14, 165, 233, .16) !important; color: #7dd3fc !important; }
html.dark .type-tag-images { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; }
html.dark .type-tag-tts, html.dark .type-tag-audio { background: rgba(239, 68, 68, .16) !important; color: #fca5a5 !important; }
html.dark .type-tag-stt { background: rgba(148, 163, 184, .16) !important; color: #cbd5e1 !important; }
html.dark .type-tag-video, html.dark .type-tag-multimodal { background: rgba(168, 85, 247, .16) !important; color: #d8b4fe !important; }
html.dark .type-tag-rerank { background: rgba(236, 72, 153, .16) !important; color: #f9a8d4 !important; }
/* 中部消息区/输入区 */
html.dark .pg-msgs { background: #1b1f22 !important; }
html.dark .pg-input { background: #21262c !important; border-top-color: #3a3f47 !important; }
html.dark .pg-usage { background: rgba(34, 197, 94, .08) !important; }
html.dark .model-info-bar { background: #21262c !important; border-bottom-color: #3a3f47 !important; color: #9aa4b2 !important; }
/* 消息气泡与状态卡 */
html.dark .mr.assistant .bb { background: #21262c !important; color: #d6d9e0 !important; }
html.dark .mr.assistant .av { background: rgba(14, 165, 233, .16) !important; color: #7dd3fc !important; }
html.dark .mr.user .av { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; }
html.dark .mr .ma .btn-act:hover { background: #262b31 !important; }
html.dark .mr .ma .btn-act.btn-del:hover { background: rgba(239, 68, 68, .12) !important; }
html.dark .msg-async-status { background: rgba(14, 165, 233, .07) !important; border-color: rgba(14, 165, 233, .3) !important; }
html.dark .msg-async-status .mas-badge.pending { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; }
html.dark .msg-async-status .mas-badge.processing { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; }
html.dark .msg-async-status .mas-badge.failed { background: rgba(239, 68, 68, .16) !important; color: #fca5a5 !important; }
html.dark .msg-async-status .mas-progress { background: #3a3f47 !important; }
html.dark .msg-async-status .mas-footer code { background: #262b31 !important; }
html.dark .msg-async-result { background: rgba(34, 197, 94, .07) !important; border-color: rgba(34, 197, 94, .3) !important; }
html.dark .img-options-bar .io-tag .io-price { background: rgba(255, 255, 255, .1) !important; color: #fca5a5 !important; }
html.dark .img-options-bar .io-tag .io-price.free { color: #6ee7b7 !important; }
html.dark .msg-async-status .mas-title { color: #7dd3fc !important; }
html.dark .msg-async-status .mas-badge.completed { background: rgba(16, 185, 129, .16) !important; color: #6ee7b7 !important; }
html.dark .pg-usage .ul { color: #9aa4b2 !important; }
html.dark .model-info-bar .mi-tag.stt { background: rgba(148, 163, 184, .16) !important; color: #cbd5e1 !important; }

/* ===== 暗色模式：CKEditor 5 富文本（官方 --ck-color 变量覆盖，2026-09-04） ===== */
html.dark .ck {
    --ck-color-base-background: #1b1f22;
    --ck-color-base-foreground: #21262c;
    --ck-color-base-border: #3a3f47;
    --ck-color-base-action: #3b82f6;
    --ck-color-base-focus: #5b8ff9;
    --ck-color-base-active: rgba(59, 130, 246, .2);
    --ck-color-base-active-focus: rgba(59, 130, 246, .32);
    --ck-color-base-error: #f87171;
    --ck-color-base-text: #d6d9e0;
    --ck-color-toolbar-background: #21262c;
    --ck-color-toolbar-border: #3a3f47;
    --ck-color-button-default-background: transparent;
    --ck-color-button-default-hover-background: #262b31;
    --ck-color-button-default-active-background: #2d333b;
    --ck-color-button-default-disabled-background: transparent;
    --ck-color-button-on-background: rgba(59, 130, 246, .22);
    --ck-color-button-on-hover-background: rgba(59, 130, 246, .32);
    --ck-color-button-on-active-background: rgba(59, 130, 246, .4);
    --ck-color-button-on-text: #93c5fd;
    --ck-color-button-action-background: #3b82f6;
    --ck-color-button-action-hover-background: #2f74e0;
    --ck-color-button-action-text: #fff;
    --ck-color-button-cancel: #9aa4b2;
    --ck-color-dropdown-panel-background: #1f242b;
    --ck-color-dropdown-panel-border: #3a3f47;
    --ck-color-input-background: #1b1f22;
    --ck-color-input-border: #3a3f47;
    --ck-color-input-text: #d6d9e0;
    --ck-color-input-disabled-background: #262b31;
    --ck-color-list-background: #1f242b;
    --ck-color-list-button-hover-background: #262b31;
    --ck-color-list-button-on-background: rgba(59, 130, 246, .22);
    --ck-color-list-button-on-text: #93c5fd;
    --ck-color-panel-background: #1f242b;
    --ck-color-panel-border: #3a3f47;
    --ck-color-editor-base-text: #d6d9e0;
    --ck-color-editor-toolbar-background: #21262c;
    --ck-color-labeled-field-label-background: #21262c;
    --ck-color-image-placeholder-background: #262b31;
    --ck-color-image-placeholder-text: #9aa4b2;
    --ck-color-resizer: #5b8ff9;
    --ck-color-widget-blurred-border: #3a3f47;
    --ck-color-widget-hover-border: #5b8ff9;
    --ck-color-widget-editable-focus-background: #1b1f22;
    --ck-color-comment-background: #262b31;
    --ck-color-comment-remove-background: rgba(239, 68, 68, .1);
    --ck-color-placeholder-text: #6f7a89;
}

/* ===== 暗色模式：官方库功能按键 btn-alt-*（浅底深字→半透明底浅字，2026-09-04） ===== */
html.dark .btn-alt-primary { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; border-color: rgba(59, 130, 246, .16) !important; }
html.dark .btn-alt-primary:hover { background: rgba(59, 130, 246, .28) !important; }
html.dark .btn-alt-success { background: rgba(34, 197, 94, .15) !important; color: #86efac !important; border-color: rgba(34, 197, 94, .15) !important; }
html.dark .btn-alt-success:hover { background: rgba(34, 197, 94, .26) !important; }
html.dark .btn-alt-info { background: rgba(14, 165, 233, .16) !important; color: #7dd3fc !important; border-color: rgba(14, 165, 233, .16) !important; }
html.dark .btn-alt-info:hover { background: rgba(14, 165, 233, .28) !important; }
html.dark .btn-alt-warning { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; border-color: rgba(245, 158, 11, .16) !important; }
html.dark .btn-alt-warning:hover { background: rgba(245, 158, 11, .28) !important; }
html.dark .btn-alt-danger { background: rgba(239, 68, 68, .16) !important; color: #fca5a5 !important; border-color: rgba(239, 68, 68, .16) !important; }
html.dark .btn-alt-danger:hover { background: rgba(239, 68, 68, .28) !important; }

/* ===== 暗色模式：CKEditor 补充（Codebase 集成样式写死浅色部分，2026-09-04） ===== */
html.dark .ck.ck-toolbar { background: #21262c !important; border-color: #3a3f47 !important; color: #c9cfd8 !important; }
html.dark .ck.ck-sticky-panel__content { background: #21262c; border-color: #3a3f47; }
html.dark .ck.ck-toolbar .ck-toolbar__separator { background: #3a3f47; }
html.dark .ck.ck-editor__editable, html.dark .ck.ck-content { color: #d6d9e0 !important; }
html.dark .ck.ck-button, html.dark .ck.ck-dropdown__button { color: #c9cfd8; }
html.dark .ck.ck-button:not(.ck-disabled):hover, html.dark a.ck.ck-button:hover { background: #262b31; }
html.dark .ck.ck-button.ck-on { color: #93c5fd; }
html.dark .ck.ck-dropdown__panel { background: #1f242b; border-color: #3a3f47; box-shadow: 0 8px 24px rgba(0, 0, 0, .45); }
html.dark .ck.ck-list { background: #1f242b; color: #d6d9e0; }
html.dark .ck.ck-list__item .ck-button:hover:not(.ck-disabled) { background: #262b31; }
html.dark .ck.ck-list__item .ck-button.ck-on { background: rgba(59, 130, 246, .22); color: #93c5fd; }
html.dark .ck.ck-balloon-panel { background: #1f242b; border-color: #3a3f47; box-shadow: 0 8px 24px rgba(0, 0, 0, .45); }
html.dark .ck.ck-balloon-panel .ck.ck-toolbar { background: #21262c; border-color: #3a3f47; }
html.dark .ck.ck-input-text { background: #1b1f22; border-color: #3a3f47; color: #d6d9e0; }
html.dark .ck.ck-editor__editable > .ck-placeholder::before { color: #6f7a89; }

/* ===== 暗色模式：AI模型弹窗端点/渠道卡片（2026-09-04 补漏） ===== */
html.dark .ep-item, html.dark .ch-item { background: #1b1f22 !important; border-color: #3a3f47 !important; }
html.dark .ep-item:hover, html.dark .ch-item:hover { border-color: #5b8ff9 !important; background: rgba(91, 143, 249, .08) !important; }
html.dark .ep-item.ep-active, html.dark .ch-item.ch-active { border-color: #3b82f6 !important; background: rgba(59, 130, 246, .14) !important; }
html.dark .ep-item .ep-name, html.dark .ch-item .ch-name { color: #d6d9e0 !important; }
html.dark .ep-item.ep-active .ep-name { color: #93c5fd !important; }
html.dark .ep-item .ep-icon, html.dark .ch-item .ch-icon { color: #9aa4b2 !important; }
html.dark .ep-item.ep-active .ep-icon { color: #93c5fd !important; }
html.dark .ep-item .ep-url, html.dark .ch-item .ch-url { color: #9aa4b2 !important; }
html.dark .ep-item.ep-active .ep-url { color: #93c5fd !important; }

/* ===== 暗色模式：操练场请求配置弹窗只读输入框 ===== */
html.dark #modal-reqconfig input[readonly] { background: #262b31 !important; color: #cbd5e1 !important; }

/* ===== 暗色模式：全站列表内联彩色标签（JS 拼接 style 硬编码，属性选择器全色适配） ===== */
html.dark [style*="background:#dbeafe"], html.dark [style*="background: #dbeafe"] { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; }
html.dark [style*="background:#eff6ff"], html.dark [style*="background: #eff6ff"] { background: rgba(59, 130, 246, .13) !important; color: #93c5fd !important; }
html.dark [style*="background:#e3f2fd"], html.dark [style*="background: #e3f2fd"] { background: rgba(59, 130, 246, .16) !important; color: #93c5fd !important; }
html.dark [style*="background:#e0f2fe"], html.dark [style*="background: #e0f2fe"] { background: rgba(14, 165, 233, .16) !important; color: #7dd3fc !important; }
html.dark [style*="background:#dcfce7"], html.dark [style*="background: #dcfce7"] { background: rgba(34, 197, 94, .15) !important; color: #86efac !important; }
html.dark [style*="background:#f0fdf4"], html.dark [style*="background: #f0fdf4"] { background: rgba(34, 197, 94, .12) !important; color: #86efac !important; }
html.dark [style*="background:#d1fae5"], html.dark [style*="background: #d1fae5"] { background: rgba(16, 185, 129, .16) !important; color: #6ee7b7 !important; }
html.dark [style*="background:#fef3c7"], html.dark [style*="background: #fef3c7"] { background: rgba(245, 158, 11, .16) !important; color: #fcd34d !important; }
html.dark [style*="background:#fff7ed"], html.dark [style*="background: #fff7ed"] { background: rgba(249, 115, 22, .15) !important; color: #fdba74 !important; }
html.dark [style*="background:#fee2e2"], html.dark [style*="background: #fee2e2"] { background: rgba(239, 68, 68, .16) !important; color: #fca5a5 !important; }
html.dark [style*="background:#fff1f0"], html.dark [style*="background: #fff1f0"] { background: rgba(239, 68, 68, .14) !important; color: #fca5a5 !important; }
html.dark [style*="background:#f3e8ff"], html.dark [style*="background: #f3e8ff"] { background: rgba(168, 85, 247, .16) !important; color: #d8b4fe !important; }
html.dark [style*="background:#ccfbf1"], html.dark [style*="background: #ccfbf1"] { background: rgba(20, 184, 166, .16) !important; color: #5eead4 !important; }
html.dark [style*="background:#fce7f3"], html.dark [style*="background: #fce7f3"] { background: rgba(236, 72, 153, .16) !important; color: #f9a8d4 !important; }
html.dark [style*="background:#eef2ff"], html.dark [style*="background: #eef2ff"] { background: rgba(99, 102, 241, .16) !important; color: #a5b4fc !important; }
html.dark [style*="background:#f3f4f6"], html.dark [style*="background: #f3f4f6"] { background: rgba(148, 163, 184, .16) !important; color: #cbd5e1 !important; }
html.dark [style*="background:#f9fafb"], html.dark [style*="background: #f9fafb"] { background: #262b31 !important; color: #cbd5e1 !important; }
html.dark [style*="background:#f8f9fa"], html.dark [style*="background: #f8f9fa"] { background: #262b31 !important; color: #cbd5e1 !important; }
html.dark [style*="background:#fafbfc"], html.dark [style*="background: #fafbfc"] { background: #262b31 !important; color: #cbd5e1 !important; }
/* AI模型弹窗能力点选卡（cap-item） */
html.dark .cap-item { background: #1b1f22 !important; border-color: #3a3f47 !important; }
html.dark .cap-item:hover { border-color: #5b8ff9 !important; background: rgba(91, 143, 249, .08) !important; }
html.dark .cap-item.cap-active { border-color: #3b82f6 !important; background: rgba(59, 130, 246, .13) !important; }
html.dark .cap-item .cap-check { border-color: #3a3f47 !important; }
/* 弹窗底部按钮区兜底：防止页面级 ID 选择器写死浅色背景（ID 特异性需 !important 压制） */
html.dark .modal .block-content.border-top {
    background: transparent !important;
}

/* ===== cb-tag 组件补色：indigo / orange（2026-09-04 广告位置标签组件化） ===== */
.cb-tag-indigo { background: #e0e7ff; color: #4338ca; }
.cb-tag-orange { background: #ffedd5; color: #c2410c; }
html.dark .cb-tag-indigo { background: rgba(99, 102, 241, .16) !important; color: #a5b4fc !important; }
html.dark .cb-tag-orange { background: rgba(249, 115, 22, .16) !important; color: #fdba74 !important; }

/* ===== 列表价格单元格（插件列表统一口径：付费红、免费绿、免授权用标签）
 * 原先是后台插件管理页的内联样式，开发者端「我的插件」也要同一套观感，2026-09-22 提到这里共用。
 * 用法：<span class="price-pay">¥10.00 ~ ¥50.00</span> / <span class="price-free">免费</span> */
.price-pay  { color: #ff6b6b; font-weight: 600; }
.price-free { color: #28a745; font-weight: 600; }
html.dark .price-pay  { color: #fca5a5; }
html.dark .price-free { color: #6ee7b7; }
/* 同色值内联标签兜底（防其他页面写死） */
html.dark [style*="background:#e0e7ff"], html.dark [style*="background: #e0e7ff"] { background: rgba(99, 102, 241, .16) !important; color: #a5b4fc !important; }
html.dark [style*="background:#ffedd5"], html.dark [style*="background: #ffedd5"] { background: rgba(249, 115, 22, .16) !important; color: #fdba74 !important; }

/* ===== 自定义组合统一布局（2026-09-04）：下拉含“自定义”选项 + 联动输入框 =====
 * 全站弹窗/页面内“下拉（含自定义）+ 隐藏输入框”组合（QPS/额度/次数/时长等）：
 * 预设态下拉满框；选“自定义”后下拉:输入框 = 5:5 同行不换行，Select2 容器宽度受控 */
.input-group:has(> select option[value="custom"]) {
    flex-wrap: nowrap;
}
.input-group:has(> select option[value="custom"]) > .select2-container {
    flex: 1 1 50% !important;
    min-width: 0;
    width: auto;
}
.input-group:has(> select option[value="custom"]) > input {
    flex: 1 1 50% !important;
    min-width: 0;
}

/* ===== 自定义组合连体处单线分割（2026-09-04）：相接边框重叠 1px 避免双线粗边 ===== */
.input-group:has(> select option[value="custom"]) > input,
.sec-preset-wrap.joined > input { margin-left: -1px; }

/* ===== 后台列表操作列按钮：桌面显示文字、手机端仅显示图标（2026-09-04 统一，跟随顶部按键模式） =====
 * 行内按钮统一结构：<i class="fa fa-xxx ac-btn-icon"></i><span class="ac-btn-text">文字</span> */
.ac-btn-icon { display: none !important; }
@media (max-width: 767.98px) {
    .ac-btn-icon { display: inline-block !important; margin-right: 0 !important; }
    .ac-btn-text { display: none !important; }
}

/* ===== 列表末列（操作列）按钮不换行：防 auto 布局下长内容列把操作列挤成竖排叠字（2026-09-05） ===== */
.table td:last-child .btn { white-space: nowrap; }


/* ============================================
 * 插件授权卡片选择器（.ap-pick-box / .ap-card，2026-09-30 三端统一）
 *
 * 后台「插件授权」、代理端「插件授权」、开发者「发放授权」三个弹窗共用同一套卡片：
 *   分类标题（.ap-grp-head，粘性 + 计数角标）→ 网格（.ap-grp-grid，一行三张，窄屏退两列/一列）
 *   → 卡片（.ap-card：勾选框 + 插件名 + 小字说明 + 档位卡片；勾选态 .ap-card-on，不可选 .ap-card-off）。
 * 交互逻辑在 assets/js/plugin-picker.js（PluginPicker），这里只管样式。
 * 原来是代理端视图里的局部样式，为了让三端完全一致，2026-09-30 提到全局。
 * ============================================ */
/* 插件勾选面板：分类分组 + 卡片网格（一行三张，2026-09-30 用户要求） */
/* 插件卡片选择器的外框：**标签栏固定、只让卡片区滚动**
 * （2026-09-30 三次调整：原来是整框滚动 + 标签 sticky，但框自身有 6px 上内边距，
 *   sticky 只能贴到滚动口顶部，卡片会从标签栏上面那条 6px 的缝里"漏"出来；
 *   改成 flex 纵向：标签栏 flex:0，卡片区 .ap-cards 自己滚。外框 overflow:hidden 兜底不漏）。 */
.ap-pick-box {
    display: flex;
    flex-direction: column;
    max-height: 300px;
    overflow: hidden;
    border: 1px solid #e6e8ec;
    border-radius: 8px;
    padding: 0 10px 8px;
}

html.dark .ap-pick-box {
    border-color: #3a3f47;
}

/* 卡片滚动区（标签栏之下唯一会滚的地方） */
.ap-cards {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding-top: 8px;
}

.ap-grp-head {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 8px 2px 6px;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #8a93a0;
    background: #fff;
}

html.dark .ap-grp-head {
    background: #1f242b;
}

/* 卡片标题后面的小标签偶尔兼作按钮（如「续期」，2026-09-30）：补按钮基本样式，并禁掉收缩 */
button.cb-tag {
    border: none;
    cursor: pointer;
    font-family: inherit;
    flex: 0 0 auto;
}

/* 卡片的状态标签行（2026-09-30）：独立一行放标题下面 —— 挂在标题后面会把长标题挤没 */
.ap-card-tags {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    min-width: 0;
}

button.cb-tag:hover { filter: brightness(.95); }
button.cb-tag:disabled { cursor: not-allowed; opacity: .6; }

.ap-card-top .cb-tag { flex: 0 0 auto; }

/* 分类标签页（2026-09-30 二次调整：分类改成顶部标签切换，不再竖着堆一长条）
 * 「全部」= 所有分类一起显示；点某个分类只显示那一类。搜索时角标显示各分类命中数。
 * 固定在卡片滚动区之上（不再用 sticky，见上面 .ap-pick-box 的说明）。 */
.ap-tabs {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: nowrap;
    overflow-x: auto;
    padding: 8px 0;
    border-bottom: 1px solid #eef0f4;
    background: #fff;
}

html.dark .ap-tabs {
    border-bottom-color: #2f3237;
    background: #1f242b;
}

.ap-tab {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 11px;
    border: 1px solid #e6e8ec;
    border-radius: 999px;
    background: #fff;
    color: #4b5563;
    font-size: .8rem;
    line-height: 1.5;
    white-space: nowrap;
    cursor: pointer;
    transition: color .15s, border-color .15s, background-color .15s;
}

.ap-tab:hover {
    border-color: #93c5fd;
    color: #1d4ed8;
}

.ap-tab.is-active {
    border-color: #3b82f6;
    background: #eef6ff;
    color: #1d4ed8;
    font-weight: 600;
}

.ap-tab-cnt {
    display: inline-block;
    min-width: 16px;
    padding: 0 5px;
    border-radius: 8px;
    font-size: 11px;
    line-height: 16px;
    text-align: center;
    background: rgba(148, 163, 184, .18);
    color: #64748b;
}

.ap-tab.is-active .ap-tab-cnt {
    background: rgba(59, 130, 246, .18);
    color: #1d4ed8;
}

html.dark .ap-tab {
    border-color: #3a3f47;
    background: #20262d;
    color: #cbd5e1;
}

html.dark .ap-tab.is-active {
    border-color: #3b82f6;
    background: rgba(37, 99, 235, .22);
    color: #93c5fd;
}

html.dark .ap-tab-cnt {
    background: rgba(148, 163, 184, .22);
    color: #94a3b8;
}

.ap-grp-cnt {
    display: inline-block;
    min-width: 16px;
    padding: 0 5px;
    margin-left: 6px;
    border-radius: 8px;
    font-size: 11px;
    line-height: 16px;
    text-align: center;
    background: rgba(2, 132, 199, .12);
    color: #0284c7;
}

/* 一行三张（2026-09-30 用户要求）：modal-xl 内容区 ~1080px，三张各约 350px；
   窄屏自动退到两列 / 一列，别在手机上一行挤三张 */
.ap-grp-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-bottom: 6px;
}

@media (max-width: 1199.98px) {
    .ap-grp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767.98px) {
    .ap-grp-grid { grid-template-columns: 1fr; }
}

/* 搜索插件（2026-09-30）：标题右边的输入框，输入即过滤卡片（不重新请求） */
.ap-pick-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}

.ap-pick-search {
    width: 220px;
    max-width: 100%;
}

/* 单张插件卡：整卡可点（点名字/空白处都能勾选），高度压到最小 */
.ap-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 10px;
    border: 1px solid #e6e8ec;
    border-radius: 8px;
    cursor: pointer;
    transition: border-color .15s, background-color .15s;
}

.ap-card:hover {
    border-color: #93c5fd;
    background: #f8fafc;
}

html.dark .ap-card {
    border-color: #3a3f47;
}

html.dark .ap-card:hover {
    border-color: #3b82f6;
    background: rgba(148, 163, 184, .06);
}

.ap-card.ap-card-on {
    border-color: #3b82f6;
    background: #eef6ff;
}

html.dark .ap-card.ap-card-on {
    background: rgba(37, 99, 235, .16);
}

/* 不可选/已开通的卡片：只把「内容区」调暗，**标签行保持原样**
 * （2026-09-30 用户反馈：整卡 opacity 会让「已开通 · 到 X」「续期」也变暗，看着像点不了的死卡片；
 *   opacity 是父级乘算，子元素设 1 也救不回来，所以改成只压 top/sub/bottom 三块） */
.ap-card.ap-card-off {
    cursor: not-allowed;
    background: rgba(148, 163, 184, .06);
}

.ap-card.ap-card-off .ap-card-top,
.ap-card.ap-card-off .ap-card-sub,
.ap-card.ap-card-off .ap-card-bottom {
    opacity: .55;
}

.ap-card.ap-card-off .ap-card-tags { opacity: 1; }

.ap-card-top {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.ap-card-name {
    font-size: .86rem;
    font-weight: 600;
    line-height: 1.25;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 应用 · 版本 · 代理分成 / 已开通标签：同一行小字，空间不够就省略 */
.ap-card-sub {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: .72rem;
    color: #8a93a0;
    min-width: 0;
}

.ap-card-sub .ap-card-meta {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ap-card-bottom {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* 档位卡片（2026-09-26）：未勾选时整组置灰不可点（与原来的下拉 disabled 一致） */
.ap-card-bottom .ap-pick-tiers {
    width: 100%;
}

.ap-card-bottom .ap-pick-tiers.ap-tiers-off {
    opacity: .55;
}

/* ===== 隐藏 CKEditor 5 免费版在编辑器右下角挂的「Powered by CKEditor」外链角标（2026-09-30） =====
 * 自带的官方角标是固定定位、压在编辑区右下角，点它还会跳出编辑器官网（用户反馈「富文本输入框右下角
 * 出现了官方的跳转」，开发框架同样有）。这里是自建站点，不需要这个角标；
 * 只作用于 .ck-powered-by-balloon（该角标专属 class），不影响编辑器的任何功能按钮。 */
.ck-powered-by-balloon { display: none !important; }

/* ===== 接口/套餐点选列表（添加套餐标签/发放套餐共用，2026-09-10） ===== */
.pkg-api-pick { border: 1px solid var(--bs-border-color, #dee2e6); border-radius: 6px; max-height: 280px; overflow-y: auto; padding: 6px; display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 6px; }
.pkg-api-item { display: flex; align-items: center; gap: 6px; min-width: 0; padding: 7px 10px; border-radius: 6px; border: 1px solid transparent; cursor: pointer; font-size: .85rem; color: var(--bs-body-color); transition: background .15s, border-color .15s; }
.pkg-api-item:hover { background: rgba(16,185,129,.08); }
.pkg-api-item.active { background: rgba(16,185,129,.12); border-color: rgba(16,185,129,.45); color: #059669; font-weight: 600; }
html.dark .pkg-api-item.active { color: #6ee7b7; }
.pkg-api-item .pk-tag { flex-shrink: 0; font-size: 11px; padding: 0 6px; border-radius: 4px; background: rgba(148,163,184,.15); color: var(--bs-secondary-color, #6c757d); }
/* 卡片防变形：标题（pk-name）省略号不撑宽，meta（pk-sign）可收缩省略 */
.pkg-api-item .pk-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pkg-api-item .pk-sign { flex-shrink: 0; margin-left: auto; max-width: 45%; font-size: 11px; color: var(--bs-secondary-color, #6c757d); font-family: monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 发放套餐弹窗：接口标签页 + 对应套餐大卡片四列一排（2026-09-10） */
#grantPkgPick.pkg-api-pick { grid-template-columns: repeat(4, 1fr); }
#grantPkgPick .pkg-api-item { flex-direction: column; align-items: stretch; gap: 3px; padding: 8px 10px; }
#grantPkgPick .pkg-api-item .pk-tag { align-self: flex-start; }
#grantPkgPick .pkg-api-item .pk-name { white-space: normal; word-break: break-all; overflow: visible; text-overflow: clip; line-height: 1.35; }
#grantPkgPick .pkg-api-item .pk-sign { max-width: 100%; margin-left: 0; white-space: normal; overflow: visible; text-overflow: clip; word-break: break-all; }
@media (max-width: 767.98px) { #grantPkgPick.pkg-api-pick { grid-template-columns: repeat(2, 1fr); } }

/* 顶栏徽章下拉（工单/评论）手机端防溢出（2026-09-10）：
 * 固定宽 dropdown-md 在窄屏右对齐时会撑出屏幕左侧，限制不超过视口宽 */
@media (max-width: 767.98px) {
    .dropdown-menu-md {
        width: auto !important;
        min-width: 260px;
        max-width: calc(100vw - 2rem) !important;
    }
}

/* ============================================
 * 预设下拉组件（preset-input.js）的两种布局（2026-09-14 定稿）
 * 下拉走全站 Select2 美化 —— 实际可见的是 .select2-container，
 * 原生 select 被 Select2 隐藏成 1px，所以宽度必须作用于容器。
 * Select2 用 inline style 设宽度，这里用 !important 覆盖；
 * 布局状态由 JS 切换 .is-custom 类控制：
 *   预设态 → 只显示下拉，占满整行
 *   自定义态 → 下拉与输入框并排，各占一半（容器 gap 6px，各让出 3px）
 * ============================================ */
.preset-combo > .select2-container,
.preset-combo > .preset-combo-select {
    flex: 0 0 auto;
}
.preset-combo:not(.is-custom) > .select2-container,
.preset-combo:not(.is-custom) > .preset-combo-select {
    width: 100% !important;
}
.preset-combo.is-custom > .select2-container,
.preset-combo.is-custom > .preset-combo-select,
.preset-combo.is-custom > input[data-preset] {
    width: calc(50% - 3px) !important;
}

/* 自定义输入框与下拉等高（2026-09-15 统一）：
 * 下拉高度由上面 select2 规则按上下文决定（页面 42px / 弹窗 38px / 小号 31px），
 * 而输入框高度随自身类名变化（页面 .form-control 42px、弹窗里 .form-control.fs-sm 只有 35px），
 * 并排时就会一大一小。这里按同样的上下文把输入框补到与下拉同高。 */
.preset-combo.is-custom > input[data-preset] {
    height: 42px;
}
.modal .preset-combo.is-custom > input[data-preset] {
    height: 38px;
}
.preset-combo.is-custom > input[data-preset].form-control-sm {
    height: 31px;
}

/* 授权时长控件组（授权列表弹窗）——2026-09-26 已下线：
   时长下拉改成档位卡片点选（.tier-pick，见本文件底部），这段 .auth-duration-group 的两段式布局
   （下拉 + 天数/日期输入框各占一半）随之作废。 */

/* ============================================
 * 可勾选标签组（应用授权信息弹窗 → 代理售卖 → 允许售卖的等级）
 * 原用 badge bg-light 表现，勾选后外观无变化、间距仅 8px；
 * 改为「可勾选 chip」：默认描边、hover 描边微亮、选中填充主题色 + 加粗。
 * 底色/文字色在这里显式定义（不用 bg-body/text-body，那两个类带 !important
 * 会盖掉选中态的 background 与 color），深色模式单独覆盖。
 * ============================================ */
.agent-level-chips {
    display: flex;           /* 必须：否则 gap 不生效（标签是 inline-flex，靠 HTML 空白撑开，JS 生成的会贴在一起） */
    flex-wrap: wrap;
    gap: .625rem;            /* 标签间距 10px（行/列同一值） */
    margin-top: .75rem;      /* 与上方下拉留白：下拉自身的 mb-2 加在被 Select2 隐藏的原 select 上、不生效 */
    margin-bottom: .75rem;   /* 与下方说明文字留白 */
}

.agent-level-chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .375rem .75rem;
    font-size: .875rem;
    line-height: 1.2;
    color: #374151;
    background-color: #fff;
    border: 1px solid rgba(128, 128, 128, .35);
    border-radius: .375rem;
    cursor: pointer;
    user-select: none;
    transition: border-color .15s, background-color .15s, color .15s;
}

.agent-level-chip:hover {
    border-color: rgba(2, 132, 199, .55);
}

/* 选中态：用与 cb-tag-primary / 图表一致的主题色 #0284c7 */
.agent-level-chip:has(input:checked) {
    color: #0284c7;
    background-color: rgba(2, 132, 199, .12);
    border-color: #0284c7;
    font-weight: 600;
}

html.dark .agent-level-chip {
    color: rgb(214, 217, 224);
    background-color: rgb(38, 42, 47);
    border-color: rgba(255, 255, 255, .22);
}

html.dark .agent-level-chip:has(input:checked) {
    color: #7dd3fc;
    background-color: rgba(2, 132, 199, .22);
    border-color: #0284c7;
}

/* 兜底：极老浏览器不支持 :has() 时，至少让勾选框本身可辨 */
@supports not selector(:has(*)) {
    .agent-level-chip input:checked {
        outline: 2px solid rgba(2, 132, 199, .5);
        outline-offset: 2px;
    }
}

/* ========== 悬浮提示（Bootstrap 官方 .tooltip，由 app.min.js 的 scanTips 统一接管）==========
   官方默认 max-width 200px：包路径、拒绝原因这类长文案会被切成一堆窄行且居中，读起来费劲。
   放宽到 360px 并左对齐；长串（如 upload/download/.../package.zip）沿用官方 .tooltip 上的
   word-wrap: break-word，会在 / 处自然换行。配色/圆角/箭头沿用官方变量，暗色主题自动反色。 */
.tooltip {
    --bs-tooltip-max-width: 360px;
}

.tooltip-inner {
    text-align: left;
    /* 多行说明（卡密清单：应用一行、插件一行）在 title 里用的是真实换行符；
       官方默认 white-space: normal 会把 \n 折成空格 → 这里用 pre-line 保留换行，
       普通单行文案的观感不变（pre-line 只保留换行，多余空格照常合并）。2026-10-02 */
    white-space: pre-line;
}

/* 暗色主题：官方把气泡底色挂 --bs-tooltip-bg: var(--bs-emphasis-color)，本项目 5.11 的暗色包没重定义
   这个变量（仍是 #000），而文字色 --bs-tooltip-color 取 --bs-body-bg（暗色下是深色）→ 黑底深字看不见。
   这里按主题变量显式反色：浅底深字，箭头跟着 --bs-tooltip-bg 自动匹配。 */
html.dark .tooltip {
    --bs-tooltip-bg: #d6d9e0;
    --bs-tooltip-color: #1b1f22;
}

/* ========== 档位卡片点选器（.tier-pick，2026-09-26）==========
   把「授权时长下拉」换成该应用/插件在售档位的卡片点选（JS 见 common.js 的 tierPickRender）。
   三端共用：后台发放授权 / 插件授权 / 生成卡密、代理端开通授权 / 生成卡密 / 补发插件、开发者端免费授权。 */
.tier-pick {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.tier-pick-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 92px;
    padding: 8px 14px;
    background: #fff;
    border: 1px solid #dfe3e8;
    border-radius: 10px;
    line-height: 1.35;
    text-align: left;
    cursor: pointer;
    transition: border-color .15s, box-shadow .15s, background-color .15s;
}

.tier-pick-item:hover {
    border-color: #93b4d8;
}

.tier-pick-item:disabled {
    opacity: .55;
    cursor: not-allowed;
}

.tier-pick-item.is-active {
    border-color: #2f6fbf;
    background: #f2f7fd;
    box-shadow: 0 0 0 2px rgba(47, 111, 191, .14);
}

.tier-pick-item .tp-days {
    font-size: 13px;
    font-weight: 600;
    color: #262626;
}

.tier-pick-item .tp-price {
    font-size: 12px;
    color: #8c8c8c;
}

.tier-pick-item.is-active .tp-days,
.tier-pick-item.is-active .tp-price {
    color: #1d4e89;
}

/* 自定义天数：虚线边框区分「不是售卖档位」 */
.tier-pick-item.tier-pick-custom {
    border-style: dashed;
}

/* 自定义天数输入框（沿用 Bootstrap 的 .form-control，这里只管宽度与间距） */
.tier-pick-custom-input {
    max-width: 160px;
    margin-top: 8px;
}

/* 暗色主题：卡片底与文字跟着反色 */
html.dark .tier-pick-item {
    background: #2b2f33;
    border-color: #4a5057;
}

.tier-pick-item.is-active {
    border-color: #7fb0e8;
}

html.dark .tier-pick-item.is-active {
    background: #24303d;
    border-color: #7fb0e8;
}

html.dark .tier-pick-item .tp-days {
    color: #e8eaed;
}

html.dark .tier-pick-item .tp-price {
    color: #a8adb4;
}

/* 紧凑版档位卡片（表格单元格里用：后台「应用授权 → 插件」发放弹窗）
   表格列宽有限，缩小内边距与最小宽度，让 2~3 张卡片能并排 */
.tier-pick.is-compact {
    gap: 6px;
    justify-content: center;
}

.tier-pick.is-compact .tier-pick-item {
    min-width: 78px;
    padding: 5px 10px;
    gap: 0;
    border-radius: 8px;
}

.tier-pick.is-compact .tier-pick-item .tp-days {
    font-size: 12px;
}

.tier-pick.is-compact .tier-pick-item .tp-price {
    font-size: 11px;
}

/* ========== 分段标签页（.seg-tabs，2026-09-26）==========
   卡密生成弹窗的「应用卡密 / 插件卡密」切换用它（用户要求改成标签页模式）：
   两三个互斥选项的轻量切换，比卡片点选更像「标签」，也不占高度。 */
.seg-tabs {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    background: #f1f3f5;
    border-radius: 10px;
}

.seg-tabs button {
    border: 0;
    background: transparent;
    padding: 6px 18px;
    border-radius: 8px;
    font-size: 13px;
    color: #525252;
    line-height: 1.4;
    cursor: pointer;
    transition: background-color .15s, color .15s, box-shadow .15s;
}

.seg-tabs button:hover {
    color: #1d4e89;
}

.seg-tabs button.is-active {
    background: #fff;
    color: #1d4e89;
    font-weight: 600;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
}

html.dark .seg-tabs {
    background: #26292d;
}

html.dark .seg-tabs button {
    color: #a8adb4;
}

html.dark .seg-tabs button.is-active {
    background: #33373c;
    color: #9cc4f0;
}

/* 模型配置卡片（2026-10-01：对齐 api 项目的 .cfg-card 观感）
   - 主体上下留白收窄到 12px，但**底部固定 18px**：主体与分割线之间要看得见间隔（用户要求）
   - 标签行用 :empty 兜底：没有标签时高度归零，避免空行撑出死间距 */
.ai-cfg-card { transition: box-shadow .15s ease-in-out; }
.ai-cfg-card:hover { box-shadow: 0 .375rem 1.5rem rgba(0, 0, 0, .12); }
.ai-cfg-card .block-title { font-size: .875rem; }
.ai-cfg-card .ai-cfg-body { padding-top: .75rem; padding-bottom: 18px; }
.ai-cfg-label { font-size: 12px; color: #8a94a6; line-height: 1.2; margin-bottom: 3px; }
.ai-cfg-value { font-size: 14px; font-weight: 600; color: #1f2937; line-height: 1.3; }
.ai-cfg-tags { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 4px; }
.ai-cfg-tags:empty { margin-top: 0; }
html.dark .ai-cfg-label { color: #8a94a6; }
html.dark .ai-cfg-value { color: #e5e7eb; }

/* 「版本」按钮右上角角标（2026-10-01：后台与开发者端共用同一套样式）
   数字 = 待审核 + 已拒绝的版本数；颜色：有被拒绝的版本 = 红，只有待审核 = 黄 */
.pl-ver-btn { position: relative; }
.pl-ver-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: #f59e0b;
    color: #fff;
    font-size: 10px;
    font-weight: 600;
    line-height: 16px;
    text-align: center;
    box-shadow: 0 0 0 2px #fff;
}
.pl-ver-badge.pl-ver-badge-red { background: #dc2626; }
html.dark .pl-ver-badge { box-shadow: 0 0 0 2px #232a31; }

/* 模型配置：卡片区与面板底部留出间距（2026-10-01 用户反馈「底部间距缺失」）
   面板 .block-content 的 padding-bottom 只有 1px，最后一行卡片会贴着底边（实测间距 1px） */
#ai-cards { margin-bottom: 18px; }

