/* ============================================================
   zz-theme-terminal.css —— V1「终端」暗色科技主题（桌面端）
   2026-10-15 按用户裁定「按照第一版部署」落地。

   来源：由 zz-theme-light.css（2026-10-13 起在用的浅色主题）**逐项转换**得到，
   不是重写 —— 浅色那一版里的 antd v5 cssinjs 压制、弹层/表单覆盖、
   §12 对页面内联浅色样式的收口，全部保留；只换颜色与密度。

   为什么敢再回暗色：2026-10-13 退役的「深空操作台」是栽在**面层级没拉开**
   （三层背景 ΔL* 只有 3.9、弱化字 3.69:1）。本主题的令牌逐项算过闸，
   实测 ΔL* bg0↔bg1 = 7.0、bg1↔bg2 = 7.7、分隔线 19.2、弱化字 5.8:1。

   铁律：
   1. 红涨绿跌（.dfo-up 红 / .dfo-down 绿），A 股语义，禁止写反，红不当「错误」用。
   2. 页面代码一律 var(--dfo-*) 取色，不写死 hex。
   3. 不写 `* { background }` 一刀切，逐条列 .ant-*。
   4. 圆角 3px、面板无阴影：靠 1px 描边与面层级分层，不靠投影。
   5. 数字用等宽 tabular（.dfo-num / .dfo-mono / 表格数字列）。
   ============================================================ */


/* ------------------------------------------------------------
   §1 色彩令牌
   ------------------------------------------------------------ */
/* ------------------------------------------------------------
   §1 色彩令牌 —— V1「终端」，逐项算过闸（2026-10-15）
   验算脚本见 ~/.hermes/.../ui-redesign/gen_terminal_theme.py 顶部注释；
   实测值：ΔL* bg0↔bg1 = 7.0 · bg1↔bg2 = 7.7 · bg0↔bg3 = 10.4
           分隔线 ΔL*(bg1↔border) = 19.2（要求 ≥13）
           文字对比度：正文 15.5:1 · 次 8.9:1 · 弱 5.8:1 · 强调青 9.9:1
                       涨红 5.8:1 · 跌绿 9.1:1 · 警示 9.5:1（要求 ≥4.5:1）
   对比 2026-10-13 被退役的「深空操作台」：面 ΔL* 仅 3.9、弱化字 3.69:1 —— 那才是
   它糊成一坨的原因，本主题靠拉开面层级 + 提亮弱化字解决，不靠加辉光。
   ------------------------------------------------------------ */
:root {
    /* —— 面（四层，彼此必须拉开 ΔL* ≥ 6）—— */
    --dfo-bg0: #080B10;                       /* 页面底          L*  3.0 */
    --dfo-bg1: #141C27;                       /* 卡片/面板/侧栏  L* 10.0 */
    --dfo-bg2: #212C3C;                       /* 表头带/悬浮     L* 17.7 */
    --dfo-bg3: #1A2330;                       /* 斑马纹/内嵌块   L* 13.4 */

    /* —— 线 —— */
    --dfo-border: #35465C;                    /* 1px 分隔线 ΔL*(bg1) 19.2 */
    --dfo-border-strong: #4A648A;             /* 需要强调的描边 */

    /* —— 字 —— */
    --dfo-text: #EAF1F8;                      /* 正文   15.5:1 */
    --dfo-text-dim: #A9BACB;                  /* 次要    8.9:1 */
    --dfo-muted: #8698AB;                     /* 弱化    5.8:1 */

    /* —— 主色（单一强调色，只用于交互与选中）—— */
    --dfo-accent: #2FD8C5;
    --dfo-accent-hover: #4FE4D3;
    --dfo-accent-weak: rgba(47, 216, 197, 0.12);
    --dfo-accent2: #7FA8D8;

    /* —— 语义（A 股：红涨绿跌，含义单一不混用）—— */
    --dfo-up: #FF5C5C;
    --dfo-down: #2ED47A;
    --dfo-warn: #F0B429;

    /* —— 阴影：面板一律不加，弹层用深色投影拉开 —— */
    --dfo-shadow-card: none;
    --dfo-shadow-pop: 0 10px 30px rgba(0, 0, 0, 0.55);
    --dfo-shadow-modal: 0 24px 60px rgba(0, 0, 0, 0.65);
    --dfo-glow-accent: 0 0 0 3px rgba(47, 216, 197, 0.22);

    --dfo-radius: 3px;
}


/* ------------------------------------------------------------
   §2 基础 / 滚动条
   ------------------------------------------------------------ */
body {
    background: var(--dfo-bg0) !important;
    color: var(--dfo-text);
    -webkit-font-smoothing: antialiased;
}

a {
    color: var(--dfo-accent);
}
a:hover {
    color: var(--dfo-accent-hover);
}

::selection {
    background: rgba(37, 99, 235, 0.18);
    color: var(--dfo-text);
}

:focus-visible {
    outline: 2px solid rgba(37, 99, 235, 0.55);
    outline-offset: 1px;
}

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(100, 116, 139, 0.35) transparent;
}
*::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}
*::-webkit-scrollbar-track {
    background: transparent;
}
*::-webkit-scrollbar-thumb {
    background-color: rgba(100, 116, 139, 0.32);
    border-radius: 8px;
}
*::-webkit-scrollbar-thumb:hover {
    background-color: rgba(100, 116, 139, 0.55);
}

/* ------------------------------------------------------------
   §3 布局骨架：layout / sider / header / 侧边菜单
   （aside.py 与 layout/__init__.py 里仍有 theme='dark' 与 #0E141D
    内联底，这里用 !important 压制；如需彻底干净可把它们改成
    var(--dfo-bg1) 与 theme='light'）
   ------------------------------------------------------------ */
.ant-layout,
.ant-layout-content {
    background: var(--dfo-bg0);
    color: var(--dfo-text);
}
.ant-layout-sider {
    background: var(--dfo-bg1) !important;
}
.ant-layout-sider-children {
    background: transparent;
}
.ant-layout-header {
    background: var(--dfo-bg1);
    border-bottom: 1px solid var(--dfo-border);
}

/* 侧边菜单（#side-menu 带 inline 背景 #0E141D + theme='dark'） */
#side-menu {
    background: var(--dfo-bg1) !important;
    border-right: 1px solid var(--dfo-border);
}
#side-menu .ant-menu,
#side-menu .ant-menu-dark,
#side-menu .ant-menu-light {
    background: transparent !important;
    border-inline-end: 0 !important;
    color: var(--dfo-text-dim);
}
#side-menu .ant-menu-item,
#side-menu .ant-menu-submenu-title {
    color: var(--dfo-text-dim);
}
#side-menu .ant-menu-item .anticon,
#side-menu .ant-menu-submenu-title .anticon {
    color: inherit;
}
#side-menu .ant-menu-item:hover,
#side-menu .ant-menu-submenu-title:hover {
    color: var(--dfo-accent) !important;
    background: var(--dfo-bg2) !important;
}
/* 选中项：浅蓝底 + 左侧 3px 主色竖条 + 主色字 */
#side-menu .ant-menu-item-selected,
#side-menu .ant-menu-dark .ant-menu-item-selected {
    background: var(--dfo-accent-weak) !important;
    color: var(--dfo-accent) !important;
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--dfo-accent);
}
#side-menu .ant-menu-item-selected .anticon {
    color: var(--dfo-accent) !important;
}
#side-menu .ant-menu-sub.ant-menu-inline {
    background: transparent !important;
}
#side-menu .ant-menu-dark .ant-menu-sub,
#side-menu .ant-menu-dark .ant-menu-submenu-title {
    background: transparent !important;
}
/* 侧栏顶部 logo 条（aside.py 内联 #0E141D） */
#menu-collapse-sider-custom > .ant-space,
#menu-collapse-sider-custom .ant-row {
    background: transparent !important;
}

/* 侧边菜单浮层 */
.ant-menu-submenu-popup,
.ant-menu-submenu-popup .ant-menu {
    background: var(--dfo-bg1);
}
.ant-menu-submenu-popup .ant-menu-item {
    color: var(--dfo-text-dim);
}
.ant-menu-submenu-popup .ant-menu-item:hover {
    color: var(--dfo-accent);
    background: var(--dfo-bg2);
}

/* 顶栏（layout/__init__.py 内联底 + 黑阴影） */
.dfo-header-row {
    background: var(--dfo-bg1) !important;
    box-shadow: var(--dfo-shadow-card) !important;
    border-bottom: 1px solid var(--dfo-border);
}
#fold-side-menu {
    background: transparent !important;
    color: var(--dfo-text-dim);
}
#fold-side-menu:hover {
    color: var(--dfo-accent) !important;
}
#index-reload {
    color: var(--dfo-text-dim);
}
#index-reload:hover {
    color: var(--dfo-accent) !important;
    background: var(--dfo-accent-weak) !important;
}
.header-search-hint kbd {
    background: var(--dfo-bg2);
    border: 1px solid var(--dfo-border);
    color: var(--dfo-text-dim);
    box-shadow: none;
}
/* 面包屑 */
.ant-breadcrumb,
.ant-breadcrumb a {
    color: var(--dfo-text-dim);
}
.ant-breadcrumb a:hover {
    color: var(--dfo-accent);
}
.ant-breadcrumb > ol > li:last-child {
    color: var(--dfo-text);
}
.ant-breadcrumb-separator {
    color: var(--dfo-muted);
}

/* ------------------------------------------------------------
   §4 antd 卡片
   ------------------------------------------------------------ */
.ant-card {
    background: var(--dfo-bg1);
    border-color: var(--dfo-border);
    border-radius: 10px;
    color: var(--dfo-text);
    box-shadow: var(--dfo-shadow-card);
}
.ant-card-bordered {
    border: 1px solid var(--dfo-border);
}
.ant-card:hover {
    box-shadow: 0 4px 14px rgba(16, 24, 40, 0.08);
}
.ant-card-head {
    color: var(--dfo-text);
    border-bottom: 1px solid var(--dfo-border);
}
.ant-card-head-title,
.ant-card-head-wrapper {
    color: var(--dfo-text);
}
.ant-card-extra {
    color: var(--dfo-text-dim);
}
.ant-card-body {
    color: var(--dfo-text);
}
.ant-card-actions {
    background: transparent;
    border-top: 1px solid var(--dfo-border);
}
.ant-card-actions > li {
    border-inline-end: 1px solid var(--dfo-border);
}
.ant-card-actions > li > span {
    color: var(--dfo-text-dim);
}
.ant-card-meta-title {
    color: var(--dfo-text);
}
.ant-card-meta-description {
    color: var(--dfo-text-dim);
}
.ant-card-grid {
    border: 1px solid var(--dfo-border);
    box-shadow: none;
}

/* ------------------------------------------------------------
   §5 antd 表格全套 + 分页 + 空态 + Spin
   ------------------------------------------------------------ */
.ant-table {
    background: var(--dfo-bg1);
    color: var(--dfo-text);
    font-variant-numeric: tabular-nums;
    border-radius: 8px;
}
.ant-table-container {
    border-color: var(--dfo-border);
}
/* 表头：浅灰带 + 强分隔线（对白面 ΔL* 7.2） */
.ant-table-thead > tr > th {
    background: var(--dfo-bg2);
    color: var(--dfo-text-dim);
    font-weight: 600;
    white-space: nowrap;
    border-bottom: 1px solid var(--dfo-border-strong);
}
.ant-table-thead > tr > td {
    background: var(--dfo-bg2);
    color: var(--dfo-text-dim);
    border-bottom: 1px solid var(--dfo-border-strong);
}
.ant-table-thead th.ant-table-column-has-sorters:hover {
    background: #232F3F;
}
/* 表体 */
.ant-table-tbody > tr > td {
    background: var(--dfo-bg1);
    color: var(--dfo-text);
    border-bottom: 1px solid var(--dfo-border);
    transition: background 0.15s ease;
}
.ant-table-tbody > tr:nth-child(even) > td {
    background: var(--dfo-bg3);
}
.ant-table-tbody > tr:hover > td {
    background: var(--dfo-accent-weak) !important;
}
.ant-table-tbody > tr.ant-table-row-selected > td {
    background: rgba(37, 99, 235, 0.14);
}
.ant-table-expanded-row > td {
    background: var(--dfo-bg2);
}
.ant-table-row-expand-icon {
    border-color: var(--dfo-border-strong);
}
.ant-table-row-expand-icon:hover {
    border-color: var(--dfo-accent);
}
.ant-table-column-sort {
    background: var(--dfo-bg2);
}
.ant-table-column-sorter-up.active,
.ant-table-column-sorter-down.active {
    color: var(--dfo-accent);
}
.ant-table-filter-trigger-container-open {
    background: var(--dfo-accent-weak);
}
.ant-table-filter-trigger-container-open .ant-table-filter-trigger {
    color: var(--dfo-accent);
}
.ant-table-filter-trigger {
    color: var(--dfo-text-dim);
}
/* 固定列：不透明底 + 浅分隔阴影 */
.ant-table-cell-fix-left,
.ant-table-cell-fix-right {
    background: var(--dfo-bg1);
}
.ant-table-thead .ant-table-cell-fix-left,
.ant-table-thead .ant-table-cell-fix-right {
    background: var(--dfo-bg2);
}
.ant-table-cell-fix-right-first::after {
    box-shadow: inset -8px 0 8px -8px rgba(16, 24, 40, 0.16) !important;
}
.ant-table-cell-fix-left-last::after {
    box-shadow: inset 8px 0 8px -8px rgba(16, 24, 40, 0.16) !important;
}
.ant-table-cell-scrollbar {
    background: var(--dfo-bg2);
    box-shadow: none;
}
/* 空态 */
.ant-table-placeholder {
    color: var(--dfo-text-dim);
    background: var(--dfo-bg1);
}
.ant-table-placeholder:hover > td {
    background: var(--dfo-bg1) !important;
}
.ant-empty-description {
    color: var(--dfo-text-dim);
}
/* Spin */
.ant-spin {
    color: var(--dfo-accent);
}
.ant-spin-dot-item {
    background-color: var(--dfo-accent);
}
.ant-spin-text {
    color: var(--dfo-accent);
}
/* 分页器 */
.ant-pagination {
    color: var(--dfo-text-dim);
}
.ant-pagination-total-text,
.ant-pagination-options {
    color: var(--dfo-text-dim);
}
.ant-pagination-item {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 6px;
}
.ant-pagination-item a {
    color: var(--dfo-text-dim);
}
.ant-pagination-item:hover {
    border-color: var(--dfo-accent);
}
.ant-pagination-item:hover a {
    color: var(--dfo-accent);
}
.ant-pagination-item-active {
    background: var(--dfo-accent);
    border-color: var(--dfo-accent);
}
.ant-pagination-item-active a {
    color: #04201D !important;
    font-weight: 600;
}
.ant-pagination-prev .ant-pagination-item-link,
.ant-pagination-next .ant-pagination-item-link,
.ant-pagination-jump-prev .ant-pagination-item-link,
.ant-pagination-jump-next .ant-pagination-item-link {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    color: var(--dfo-text-dim);
    border-radius: 6px;
}
.ant-pagination-prev:hover .ant-pagination-item-link,
.ant-pagination-next:hover .ant-pagination-item-link {
    border-color: var(--dfo-accent);
    color: var(--dfo-accent);
}
.ant-pagination-disabled .ant-pagination-item-link {
    color: var(--dfo-muted) !important;
    border-color: var(--dfo-border);
    background: var(--dfo-bg2);
}
.ant-pagination-ellipsis {
    color: var(--dfo-muted);
}

/* ------------------------------------------------------------
   §6 antd 弹层：modal / drawer / dropdown / select / popover /
       tooltip / message / notification
   ------------------------------------------------------------ */
.ant-modal-content {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border-strong);
    border-radius: 10px;
    box-shadow: var(--dfo-shadow-modal);
    color: var(--dfo-text);
}
.ant-modal-header {
    background: var(--dfo-bg1);
    border-bottom: 1px solid var(--dfo-border);
    border-radius: 10px 10px 0 0;
}
.ant-modal-title {
    color: var(--dfo-text);
}
.ant-modal-body {
    color: var(--dfo-text);
}
.ant-modal-footer {
    border-top: 1px solid var(--dfo-border);
}
.ant-modal-close {
    color: var(--dfo-muted);
    background: transparent;
}
.ant-modal-close:hover {
    color: var(--dfo-text);
    background: var(--dfo-bg2);
}
.ant-modal-confirm-body .ant-modal-confirm-title {
    color: var(--dfo-text);
}
.ant-modal-confirm-body .ant-modal-confirm-content {
    color: var(--dfo-text-dim);
}
.ant-modal-mask {
    background-color: rgba(17, 24, 39, 0.38);
}
/* Drawer */
.ant-drawer-content {
    background: var(--dfo-bg1);
    border-left: 1px solid var(--dfo-border);
    color: var(--dfo-text);
}
.ant-drawer-header {
    background: var(--dfo-bg1);
    border-bottom: 1px solid var(--dfo-border);
}
.ant-drawer-title {
    color: var(--dfo-text);
}
.ant-drawer-body {
    color: var(--dfo-text);
}
.ant-drawer-footer {
    border-top: 1px solid var(--dfo-border);
}
.ant-drawer-close {
    color: var(--dfo-muted);
}
.ant-drawer-mask {
    background-color: rgba(17, 24, 39, 0.38);
}
/* Dropdown */
.ant-dropdown-menu {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 8px;
    box-shadow: var(--dfo-shadow-pop);
}
.ant-dropdown-menu-item {
    color: var(--dfo-text-dim);
}
.ant-dropdown-menu-item:hover {
    background: var(--dfo-bg2);
    color: var(--dfo-text);
}
.ant-dropdown-menu-item .anticon {
    color: inherit;
}
.ant-dropdown-menu-item-divider {
    background-color: var(--dfo-border);
}
.ant-dropdown-menu-item-selected {
    background: var(--dfo-accent-weak);
    color: var(--dfo-accent);
}
/* Select 下拉面板 */
.ant-select-dropdown {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 8px;
    box-shadow: var(--dfo-shadow-pop);
}
.ant-select-item {
    color: var(--dfo-text-dim);
    border-radius: 6px;
}
.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
    background: var(--dfo-bg2);
    color: var(--dfo-text);
}
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
    background: var(--dfo-accent-weak);
    color: var(--dfo-accent);
    font-weight: 600;
}
.ant-select-item-empty {
    color: var(--dfo-muted);
}
/* Popover */
.ant-popover-inner {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 10px;
    box-shadow: var(--dfo-shadow-pop);
}
.ant-popover-inner-content {
    background: transparent;
    color: var(--dfo-text);
}
.ant-popover-title {
    color: var(--dfo-text);
    border-bottom: 1px solid var(--dfo-border);
}
.ant-popover-message > .anticon {
    color: var(--dfo-warn);
}
.ant-popover-buttons button {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    color: var(--dfo-text-dim);
}
.ant-popover-arrow-content,
.ant-popover-inner:before {
    background: var(--dfo-bg1);
}
/* Tooltip */
.ant-tooltip-inner {
    background: #212C3C;
    border: 1px solid #35465C;
    color: #EAF1F8;
    box-shadow: 0 6px 16px rgba(16, 24, 40, 0.24);
}
.ant-tooltip-arrow-content {
    background: #212C3C;
}
/* Message / Notification */
.ant-message-notice-content {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border-strong);
    border-radius: 8px;
    box-shadow: var(--dfo-shadow-pop);
    color: var(--dfo-text);
}
.ant-notification-notice {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border-strong);
    border-radius: 10px;
    box-shadow: var(--dfo-shadow-pop);
}
.ant-notification-notice-message {
    color: var(--dfo-text);
}
.ant-notification-notice-description {
    color: var(--dfo-text-dim);
}
.ant-notification-notice-close {
    color: var(--dfo-muted);
}

/* ------------------------------------------------------------
   §7 antd 表单控件：input / select / picker / checkbox / radio /
       switch / button
   ------------------------------------------------------------ */
.ant-input,
.ant-input-affix-wrapper,
.ant-input-number,
.ant-picker {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border-strong);
    color: var(--dfo-text);
    border-radius: 6px;
}
.ant-input:hover,
.ant-input-affix-wrapper:hover,
.ant-input-number:hover,
.ant-picker:hover {
    border-color: var(--dfo-accent);
}
.ant-input:focus,
.ant-input-focused,
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused,
.ant-input-number-focused,
.ant-picker-focused {
    border-color: var(--dfo-accent);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.ant-input::placeholder {
    color: var(--dfo-muted);
}
.ant-input-group-addon {
    background: var(--dfo-bg2);
    border: 1px solid var(--dfo-border);
    color: var(--dfo-text-dim);
}
.ant-input-number-handler-wrap {
    background: var(--dfo-bg2);
    border-left: 1px solid var(--dfo-border);
}
.ant-input-number-handler {
    color: var(--dfo-text-dim);
    border-bottom: 1px solid var(--dfo-border);
}
.ant-input-number-input,
.ant-input-number-handler-wrap input {
    background: transparent;
    color: var(--dfo-text);
}
.ant-input-textarea-show-count::after {
    color: var(--dfo-muted);
}
/* Select 选择器 */
.ant-select-selector {
    background: var(--dfo-bg1) !important;
    border: 1px solid var(--dfo-border-strong) !important;
    color: var(--dfo-text);
}
.ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
    background: var(--dfo-bg1);
}
.ant-select:hover:not(.ant-select-disabled) .ant-select-selector {
    border-color: var(--dfo-accent) !important;
}
.ant-select-selection-item {
    color: var(--dfo-text);
}
.ant-select-selection-placeholder {
    color: var(--dfo-muted);
}
.ant-select-arrow,
.ant-select-clear {
    color: var(--dfo-text-dim);
}
.ant-select-focused:not(.ant-select-disabled) .ant-select-selector {
    border-color: var(--dfo-accent) !important;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15) !important;
}
.ant-select-selection-item-remove {
    color: var(--dfo-text-dim);
}
.ant-select-selection-overflow-item .ant-select-selection-item {
    background: var(--dfo-bg2);
    border: 1px solid var(--dfo-border);
    color: var(--dfo-text);
}
/* 日期面板 */
.ant-picker-panel {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
}
.ant-picker-header,
.ant-picker-content th {
    color: var(--dfo-text-dim);
}
.ant-picker-cell {
    color: var(--dfo-muted);
}
.ant-picker-cell-in-view {
    color: var(--dfo-text);
}
.ant-picker-cell-selected .ant-picker-cell-inner {
    background: var(--dfo-accent);
    color: #04201D;
    font-weight: 600;
}
.ant-picker-cell-today .ant-picker-cell-inner::before {
    border-color: var(--dfo-accent);
}
/* Checkbox / Radio / Switch */
.ant-checkbox-inner {
    background: var(--dfo-bg1);
    border-color: var(--dfo-border-strong);
}
.ant-checkbox-checked .ant-checkbox-inner {
    background: var(--dfo-accent);
    border-color: var(--dfo-accent);
}
.ant-checkbox-wrapper {
    color: var(--dfo-text-dim);
}
.ant-radio-inner {
    background: var(--dfo-bg1);
    border-color: var(--dfo-border-strong);
}
.ant-radio-checked .ant-radio-inner {
    border-color: var(--dfo-accent);
}
.ant-radio-checked .ant-radio-inner::after {
    background: var(--dfo-accent);
}
.ant-radio-wrapper {
    color: var(--dfo-text-dim);
}
.ant-switch {
    background: #3E5070;
}
.ant-switch-checked {
    background: var(--dfo-accent);
}
/* Button */
.ant-btn {
    border-radius: 6px;
    transition: all 0.15s ease;
}
.ant-btn-default {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border-strong);
    color: var(--dfo-text);
}
.ant-btn-default:hover,
.ant-btn-default:focus {
    background: var(--dfo-bg2);
    border-color: var(--dfo-accent);
    color: var(--dfo-accent);
}
/* 主按钮：主色底 + 白字（4.6:1）*/
.ant-btn-primary:not(.ant-btn-dangerous) {
    background: var(--dfo-accent);
    border-color: var(--dfo-accent);
    color: #04201D;
    font-weight: 600;
    box-shadow: none;
}
.ant-btn-primary:not(.ant-btn-dangerous):hover,
.ant-btn-primary:not(.ant-btn-dangerous):focus {
    background: var(--dfo-accent-hover);
    border-color: var(--dfo-accent-hover);
    color: #04201D;
}
.ant-btn-dangerous {
    background: var(--dfo-up);
    border-color: var(--dfo-up);
    color: #ffffff;
}
.ant-btn-dangerous:hover {
    background: #C24A4A;
    border-color: #C24A4A;
    color: #ffffff;
}
.ant-btn-link {
    color: var(--dfo-accent);
}
.ant-btn-link:hover {
    color: var(--dfo-accent-hover);
}
.ant-btn-text {
    color: var(--dfo-text-dim);
}
.ant-btn-text:hover {
    color: var(--dfo-accent);
    background: var(--dfo-bg2);
}
.ant-btn-dashed {
    background: transparent;
    border: 1px dashed var(--dfo-border-strong);
    color: var(--dfo-text-dim);
}
.ant-btn-dashed:hover {
    border-color: var(--dfo-accent);
    color: var(--dfo-accent);
}
.ant-btn[disabled],
.ant-btn-loading {
    color: var(--dfo-muted);
    background: var(--dfo-bg2);
    border-color: var(--dfo-border);
}
.ant-btn-primary[disabled] {
    background: #2A3646;
    border-color: #2A3646;
    color: #6E7F91;
}
/* 表单标签 */
.ant-form-item-label > label {
    color: var(--dfo-text-dim);
}
.ant-form-item {
    color: var(--dfo-text);
}

/* ------------------------------------------------------------
   §8 其他组件：tabs / statistic / alert / tag / divider /
       typography / list / badge / descriptions / tree
   ------------------------------------------------------------ */
.ant-tabs-tab {
    color: var(--dfo-text-dim);
}
.ant-tabs-tab:hover {
    color: var(--dfo-text);
}
.ant-tabs-tab-active .ant-tabs-tab-btn,
.ant-tabs-tab-active .ant-tabs-tab-btn:hover {
    color: var(--dfo-accent);
}
.ant-tabs-ink-bar {
    background: var(--dfo-accent);
}
.ant-tabs-nav::before {
    border-bottom-color: var(--dfo-border);
}
.ant-statistic-title {
    color: var(--dfo-text-dim);
}
.ant-statistic-content {
    color: var(--dfo-text);
}
.ant-statistic-content-value {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}
/* Alert：浅色语义底（在白面上依旧是浅底 + 深字）*/
.ant-alert-success {
    background: rgba(46, 212, 122, 0.12);
    border-color: rgba(46, 212, 122, 0.38);
}
.ant-alert-success .ant-alert-icon {
    color: var(--dfo-down);
}
.ant-alert-info {
    background: rgba(47, 216, 197, 0.10);
    border-color: rgba(47, 216, 197, 0.35);
}
.ant-alert-info .ant-alert-icon {
    color: var(--dfo-accent);
}
.ant-alert-warning {
    background: rgba(240, 180, 41, 0.12);
    border-color: rgba(240, 180, 41, 0.40);
}
.ant-alert-warning .ant-alert-icon {
    color: var(--dfo-warn);
}
.ant-alert-error {
    background: rgba(255, 92, 92, 0.12);
    border-color: rgba(255, 92, 92, 0.42);
}
.ant-alert-error .ant-alert-icon {
    color: var(--dfo-up);
}
.ant-alert-message {
    color: var(--dfo-text);
}
.ant-alert-description {
    color: var(--dfo-text-dim);
}
/* Tag：未指定预设色时跟随主题 */
.ant-tag:not(.ant-tag-magenta):not(.ant-tag-red):not(.ant-tag-volcano):not(.ant-tag-orange):not(.ant-tag-gold):not(.ant-tag-yellow):not(.ant-tag-lime):not(.ant-tag-green):not(.ant-tag-cyan):not(.ant-tag-blue):not(.ant-tag-geekblue):not(.ant-tag-purple):not(.ant-tag-success):not(.ant-tag-processing):not(.ant-tag-error):not(.ant-tag-warning) {
    background: var(--dfo-bg2);
    border-color: var(--dfo-border);
    color: var(--dfo-text-dim);
}
.ant-divider {
    background: var(--dfo-border);
    border-color: var(--dfo-border);
}
.ant-typography {
    color: var(--dfo-text);
}
.ant-typography.ant-typography-secondary {
    color: var(--dfo-text-dim);
}
h1.ant-typography,
h2.ant-typography,
h3.ant-typography,
h4.ant-typography,
h5.ant-typography {
    color: var(--dfo-text);
}
.ant-typography code {
    background: var(--dfo-bg2);
    border: 1px solid var(--dfo-border);
    color: var(--dfo-text);
}
.ant-list-item {
    border-bottom: 1px solid var(--dfo-border);
}
.ant-list-item-meta-title {
    color: var(--dfo-text);
}
.ant-list-item-meta-description {
    color: var(--dfo-text-dim);
}
.ant-badge-count {
    background: var(--dfo-up);
    box-shadow: 0 0 0 1px var(--dfo-bg1);
}
.ant-avatar {
    border: 1px solid var(--dfo-border);
}
.ant-descriptions-item-label {
    color: var(--dfo-text-dim);
}
.ant-descriptions-item-content {
    color: var(--dfo-text);
}
/* 树 */
.ant-tree {
    background: transparent;
    color: var(--dfo-text);
}
.ant-tree .ant-tree-node-content-wrapper {
    color: var(--dfo-text);
}
.ant-tree .ant-tree-switcher,
.ant-tree .ant-tree-iconEle {
    color: var(--dfo-text-dim);
}
.ant-tree .ant-tree-node-content-wrapper:hover {
    background: var(--dfo-bg2) !important;
}
.ant-tree .ant-tree-node-selected {
    background: var(--dfo-accent-weak) !important;
}
.ant-tree-show-line .ant-tree-indent-unit {
    border-color: var(--dfo-border);
}
.ant-tree .ant-tree-title {
    color: var(--dfo-text);
}

/* ------------------------------------------------------------
   §9 登录页 #login-form-container
   ------------------------------------------------------------ */
#login-form-container .ant-card {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 14px;
    box-shadow: var(--dfo-shadow-modal);
}
#login-form-container .ant-card-head {
    border-bottom-color: var(--dfo-border);
}
#login-form-container .ant-card-head-title {
    color: var(--dfo-accent);
    text-shadow: none;
}
#login-form-container .ant-form-item-label > label {
    color: var(--dfo-text-dim);
}
#login-form-container a {
    color: var(--dfo-accent);
}

/* ------------------------------------------------------------
   §10 加载动画外圈
   ------------------------------------------------------------ */
._dash-loading {
    background-color: rgba(255, 255, 255, 0.88);
    border-radius: 16px;
    box-shadow:
        0 0 0 1px rgba(37, 99, 235, 0.18),
        0 8px 32px rgba(16, 24, 40, 0.12);
}

/* ------------------------------------------------------------
   §11 类名契约（页面代码直接引用，改名会坏页面）
   ------------------------------------------------------------ */
/* 卡片 */
.dfo-card {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 10px;
    transition: box-shadow 0.15s ease;
}
.dfo-card:hover {
    box-shadow: 0 4px 14px rgba(16, 24, 40, 0.08);
}

/* 页头/筛选主卡（压制页面内注入的浅色样式）*/
.dfo-hero {
    background: var(--dfo-bg1) !important;
    border: 1px solid var(--dfo-border) !important;
    border-radius: 10px;
}

/* 等宽数字 */
.dfo-mono {
    font-family: ui-monospace, 'JetBrains Mono', 'Cascadia Mono', Consolas, monospace;
    font-variant-numeric: tabular-nums;
}
.dfo-num {
    font-family: ui-monospace, 'JetBrains Mono', 'Cascadia Mono', Consolas, monospace;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* 红涨绿跌（A股语义，禁止写反）*/
.dfo-up {
    color: var(--dfo-up);
    font-weight: 600;
}
.dfo-down {
    color: var(--dfo-down);
    font-weight: 600;
}

/* 紧凑表格：行高 36px + sticky 表头 + 斑马纹 + 悬停 */
.dfo-table-compact .ant-table-tbody > tr > td {
    padding-top: 7px;
    padding-bottom: 7px;
}
.dfo-table-compact .ant-table-thead > tr > th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--dfo-bg2);
}
.dfo-table-compact .ant-table-tbody > tr:nth-child(even) > td {
    background: var(--dfo-bg3);
}
.dfo-table-compact .ant-table-tbody > tr:hover > td {
    background: var(--dfo-accent-weak) !important;
}

/* 状态签：胶囊 */
.dfo-chip {
    display: inline-block;
    padding: 1px 10px;
    border-radius: 999px;
    font-size: 12px;
    line-height: 20px;
    font-weight: 600;
    white-space: nowrap;
    color: var(--dfo-text-dim);
    background: var(--dfo-bg2);
    border: 1px solid var(--dfo-border);
}
.dfo-chip.dfo-status-running {
    color: var(--dfo-accent);
    background: var(--dfo-accent-weak);
    border-color: rgba(47, 216, 197, 0.35);
    animation: dfo-pulse 2s infinite;
}
.dfo-chip.dfo-status-success {
    color: #2ED47A;
    background: rgba(46, 212, 122, 0.12);
    border-color: rgba(46, 212, 122, 0.38);
}
.dfo-chip.dfo-status-failed {
    color: #FF8A82;
    background: rgba(255, 92, 92, 0.12);
    border-color: rgba(255, 92, 92, 0.42);
}
.dfo-chip.dfo-status-canceled {
    color: var(--dfo-muted);
    background: var(--dfo-bg2);
    border-color: var(--dfo-border);
}

@keyframes dfo-pulse {
    0%,
    100% {
        box-shadow: 0 0 0 0 rgba(37, 99, 235, 0.30);
    }
    50% {
        box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12);
    }
}

/* 主操作高亮（页面把它当 box-shadow 值用）*/
.dfo-glow-accent {
    box-shadow: var(--dfo-glow-accent);
    border-color: var(--dfo-accent);
}

/* 分区标题：左侧 3px 主色竖条 */
.dfo-section-title {
    position: relative;
    padding-left: 12px;
    letter-spacing: 0.02em;
    color: var(--dfo-text);
}
.dfo-section-title::before {
    content: '';
    position: absolute;
    left: 0;
    top: 18%;
    height: 64%;
    width: 3px;
    border-radius: 2px;
    background: var(--dfo-accent);
}

/* KPI 数值卡 */
.dfo-kpi {
    background: var(--dfo-bg1);
    border: 1px solid var(--dfo-border);
    border-radius: 10px;
    padding: 14px 18px;
}
.dfo-kpi .dfo-kpi-value {
    font-family: ui-monospace, 'JetBrains Mono', 'Cascadia Mono', Consolas, monospace;
    font-variant-numeric: tabular-nums;
    font-size: 22px;
    line-height: 30px;
    font-weight: 700;
    color: var(--dfo-text);
}
.dfo-kpi .dfo-kpi-label {
    font-size: 12px;
    color: var(--dfo-text-dim);
    margin-top: 2px;
}

/* 令牌别名类（页面若用 class 而非 inline style 取色时可直接用）*/
.dfo-text { color: var(--dfo-text); }
.dfo-text-dim { color: var(--dfo-text-dim); }
.dfo-muted { color: var(--dfo-muted); }
.dfo-accent { color: var(--dfo-accent); }
.dfo-warn { color: var(--dfo-warn); }
.dfo-bg0 { background: var(--dfo-bg0); }
.dfo-bg1 { background: var(--dfo-bg1); }
.dfo-bg2 { background: var(--dfo-bg2); }
.dfo-border { border-color: var(--dfo-border); }

/* ------------------------------------------------------------
   §12 dashboard：page_top / page_bottom 内联浅色样式的收口
   ------------------------------------------------------------ */
.page-header-content .content {
    color: var(--dfo-text-dim) !important;
}
.page-header-content .content .content-title {
    color: var(--dfo-text) !important;
}
.page-header-content .avatar > span {
    box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12) !important;
}
.extra-content .stat-item > p:first-child {
    color: var(--dfo-text-dim) !important;
}
.extra-content .stat-item > p {
    color: var(--dfo-text) !important;
}
.extra-content .stat-item::after {
    background-color: var(--dfo-border) !important;
}
.nav-card-title {
    color: var(--dfo-text) !important;
}
.nav-card-desc {
    color: var(--dfo-text-dim) !important;
}
a:hover .nav-card-title {
    color: var(--dfo-accent) !important;
}
.dashboard-guide-md p,
.dashboard-guide-md li {
    color: var(--dfo-text-dim) !important;
}
.dashboard-guide-md strong {
    color: var(--dfo-text);
}
/* 快捷入口图标：主色 / 辅色交替的浅底 */
.nav-card-icon {
    background: var(--dfo-accent-weak) !important;
    border: 1px solid rgba(47, 216, 197, 0.35) !important;
}
.nav-card-icon .anticon {
    color: var(--dfo-accent) !important;
}
.ant-col:nth-child(even) .nav-card-icon {
    background: rgba(124, 58, 237, 0.10) !important;
    border-color: rgba(124, 58, 237, 0.28) !important;
}
.ant-col:nth-child(even) .nav-card-icon .anticon {
    color: var(--dfo-accent2) !important;
}

/* ------------------------------------------------------------
   §13 压过 antd v5 cssinjs / 页面内联色（只改配色，不改布局）
   ------------------------------------------------------------ */
/* 页面/布局里写死的原始浅色底（#f7f9fc / #eef2f7 / #f5f6f8 …）
   统一归到页面底，保证卡片与页面拉得开；真正的白卡片不动。*/
div[style*="rgb(247, 249, 252)"], div[style*="#f7f9fc"],
div[style*="rgb(238, 242, 247)"], div[style*="#eef2f7"],
div[style*="rgb(245, 246, 248)"], div[style*="#f5f6f8"],
div[style*="rgb(245, 247, 250)"], div[style*="#f5f7fa"] {
    background-color: var(--dfo-bg0) !important;
}
/* 顶栏那条内联底 */
div[style*="rgb(240 241 242)"], div[style*="rgb(240, 241, 242)"] {
    background-color: var(--dfo-bg1) !important;
}

/* 表格：容器透明、单元格跟主题 */
.ant-table-wrapper .ant-table {
    background: transparent;
    color: var(--dfo-text);
}
.ant-table-wrapper .ant-table-container,
.ant-table-wrapper .ant-table-content {
    background: transparent;
}
.ant-table-wrapper .ant-table-thead > tr > th,
.ant-table-wrapper .ant-table-thead > tr > td {
    background: var(--dfo-bg2);
    color: var(--dfo-text-dim);
    border-bottom: 1px solid var(--dfo-border-strong);
}
.ant-table-wrapper .ant-table-tbody > tr > td {
    background: var(--dfo-bg1);
    color: var(--dfo-text);
    border-bottom: 1px solid var(--dfo-border) !important;
}
.ant-table-wrapper .ant-table-tbody > tr:nth-child(even) > td {
    background: var(--dfo-bg3);
}
.ant-table-wrapper .ant-table-tbody > tr:hover > td {
    background: var(--dfo-accent-weak) !important;
}
.ant-table-wrapper .ant-table-placeholder,
.ant-table-wrapper .ant-table-placeholder > td,
.ant-table-wrapper .ant-table-placeholder .ant-table-cell {
    background: var(--dfo-bg1);
    color: var(--dfo-text-dim);
}
.ant-table-wrapper .ant-table-cell-fix-left,
.ant-table-wrapper .ant-table-cell-fix-right {
    background: var(--dfo-bg1);
}
.ant-table-wrapper .ant-table-thead .ant-table-cell-fix-left,
.ant-table-wrapper .ant-table-thead .ant-table-cell-fix-right {
    background: var(--dfo-bg2);
}

/* 单元格内 AntdText：antd 默认近黑，跟随主题；带内联颜色的不动 */
.ant-typography:not([style*="color"]):not(.ant-typography-secondary) {
    color: var(--dfo-text) !important;
}
.ant-typography.ant-typography-secondary {
    color: var(--dfo-text-dim) !important;
}
.ant-form .ant-form-item .ant-form-item-label > label {
    color: var(--dfo-text-dim) !important;
}
.ant-statistic .ant-statistic-title {
    color: var(--dfo-text-dim) !important;
}
.ant-statistic .ant-statistic-content {
    color: var(--dfo-text) !important;
}
.ant-empty .ant-empty-description {
    color: var(--dfo-text-dim) !important;
}
.ant-checkbox-wrapper span {
    color: var(--dfo-text-dim);
}
.ant-radio-wrapper span {
    color: var(--dfo-text-dim);
}

/* 分页器 / Tabs / 弹层：同级特异性 + 关键属性 */
.ant-pagination .ant-pagination-total-text,
.ant-pagination .ant-pagination-options {
    color: var(--dfo-text-dim) !important;
}
.ant-pagination .ant-pagination-item {
    background: var(--dfo-bg1) !important;
    border-color: var(--dfo-border) !important;
}
.ant-pagination .ant-pagination-item a {
    color: var(--dfo-text-dim) !important;
}
.ant-pagination .ant-pagination-item-active {
    background: var(--dfo-accent) !important;
    border-color: var(--dfo-accent) !important;
}
.ant-pagination .ant-pagination-item-active a {
    color: #04201D !important;
}
.ant-pagination .ant-pagination-prev .ant-pagination-item-link,
.ant-pagination .ant-pagination-next .ant-pagination-item-link {
    background: var(--dfo-bg1) !important;
    border-color: var(--dfo-border) !important;
    color: var(--dfo-text-dim) !important;
}
.ant-pagination .ant-pagination-item-ellipsis,
.ant-pagination .ant-pagination-item-link,
.ant-pagination .ant-pagination-jump-prev .ant-pagination-item-link-icon,
.ant-pagination .ant-pagination-jump-next .ant-pagination-item-link-icon {
    color: var(--dfo-text-dim) !important;
}

.ant-tabs .ant-tabs-tab {
    color: var(--dfo-text-dim) !important;
}
.ant-tabs .ant-tabs-tab:hover {
    color: var(--dfo-text) !important;
}
.ant-tabs .ant-tabs-tab-active .ant-tabs-tab-btn {
    color: var(--dfo-accent) !important;
}
/* 卡片型标签页选中态（原来是白底青字，对比度不够）*/
.ant-tabs-tab.ant-tabs-tab-active {
    background: var(--dfo-accent-weak) !important;
    border-color: rgba(47, 216, 197, 0.35) !important;
}
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn,
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-remove {
    color: var(--dfo-accent) !important;
}

.ant-modal .ant-modal-content {
    background: var(--dfo-bg1) !important;
    color: var(--dfo-text) !important;
    border: 1px solid var(--dfo-border-strong);
}
.ant-modal .ant-modal-title,
.ant-modal .ant-modal-body,
.ant-modal .ant-modal-confirm-title {
    color: var(--dfo-text) !important;
}
.ant-modal .ant-modal-confirm-content {
    color: var(--dfo-text-dim) !important;
}
.ant-modal .ant-modal-close {
    color: var(--dfo-muted) !important;
}
.ant-drawer .ant-drawer-content {
    background: var(--dfo-bg1) !important;
    color: var(--dfo-text);
}
.ant-drawer .ant-drawer-title,
.ant-drawer .ant-drawer-body {
    color: var(--dfo-text) !important;
}
.ant-dropdown .ant-dropdown-menu {
    background: var(--dfo-bg1) !important;
}
.ant-dropdown .ant-dropdown-menu-item {
    color: var(--dfo-text-dim) !important;
}
.ant-select-dropdown {
    background: var(--dfo-bg1) !important;
}
.ant-select-dropdown .ant-select-item {
    color: var(--dfo-text-dim) !important;
}
.ant-select-dropdown .ant-select-item-option-active:not(.ant-select-item-option-disabled) {
    color: var(--dfo-text) !important;
}
.ant-message .ant-message-notice-content,
.ant-message-notice-content {
    background: var(--dfo-bg1) !important;
    color: var(--dfo-text) !important;
    border: 1px solid var(--dfo-border-strong);
}
.ant-notification .ant-notification-notice {
    background: var(--dfo-bg1) !important;
}
.ant-notification .ant-notification-notice-message {
    color: var(--dfo-text) !important;
}
.ant-notification .ant-notification-notice-description {
    color: var(--dfo-text-dim) !important;
}
.ant-popover .ant-popover-inner {
    background: var(--dfo-bg1) !important;
}
.ant-popover .ant-popover-inner-content,
.ant-popover .ant-popover-title {
    color: var(--dfo-text) !important;
}

/* 描述列表 / 面包屑 */
.ant-descriptions .ant-descriptions-item-label {
    color: var(--dfo-text-dim) !important;
}
.ant-descriptions .ant-descriptions-item-content {
    color: var(--dfo-text) !important;
}
.ant-breadcrumb a,
.ant-breadcrumb span {
    color: var(--dfo-text-dim) !important;
}
.ant-breadcrumb > ol > li:last-child span {
    color: var(--dfo-text) !important;
}

/* Tag 预设色：浅底 + 深字 */
.ant-tag.ant-tag-success {
    color: #2ED47A !important;
    background: rgba(46, 212, 122, 0.12) !important;
    border-color: rgba(46, 212, 122, 0.38) !important;
}
.ant-tag.ant-tag-processing,
.ant-tag.ant-tag-blue {
    color: #4FE4D3 !important;
    background: rgba(47, 216, 197, 0.10) !important;
    border-color: rgba(47, 216, 197, 0.35) !important;
}
.ant-tag.ant-tag-error,
.ant-tag.ant-tag-red,
.ant-tag.ant-tag-volcano {
    color: #FF8A82 !important;
    background: rgba(255, 92, 92, 0.12) !important;
    border-color: rgba(255, 92, 92, 0.42) !important;
}
.ant-tag.ant-tag-warning,
.ant-tag.ant-tag-gold,
.ant-tag.ant-tag-orange {
    color: #F0B429 !important;
    background: rgba(240, 180, 41, 0.12) !important;
    border-color: rgba(240, 180, 41, 0.40) !important;
}
.ant-tag.ant-tag-default {
    color: var(--dfo-text-dim) !important;
    background: var(--dfo-bg2) !important;
    border-color: var(--dfo-border) !important;
}

/* Alert 预设色 */
.ant-alert.ant-alert-success {
    background: rgba(46, 212, 122, 0.12) !important;
    border-color: rgba(46, 212, 122, 0.38) !important;
}
.ant-alert.ant-alert-info {
    background: rgba(47, 216, 197, 0.10) !important;
    border-color: rgba(47, 216, 197, 0.35) !important;
}
.ant-alert.ant-alert-warning {
    background: rgba(240, 180, 41, 0.12) !important;
    border-color: rgba(240, 180, 41, 0.40) !important;
}
.ant-alert.ant-alert-error {
    background: rgba(255, 92, 92, 0.12) !important;
    border-color: rgba(255, 92, 92, 0.42) !important;
}
.ant-alert .ant-alert-message {
    color: var(--dfo-text) !important;
}
.ant-alert .ant-alert-description {
    color: var(--dfo-text-dim) !important;
}

/* 输入类（portal 弹层内同样生效）*/
.ant-input,
.ant-input-affix-wrapper,
.ant-input-number,
.ant-picker {
    background: var(--dfo-bg1) !important;
    border-color: var(--dfo-border-strong) !important;
    color: var(--dfo-text) !important;
}
.ant-input::placeholder {
    color: var(--dfo-muted) !important;
}
.ant-input-number-input,
.ant-picker-input > input {
    color: var(--dfo-text) !important;
}
.ant-select:not(.ant-select-customize-input) .ant-select-selector {
    background: var(--dfo-bg1) !important;
    border-color: var(--dfo-border-strong) !important;
    color: var(--dfo-text) !important;
}
.ant-select-selection-placeholder {
    color: var(--dfo-muted) !important;
}
.ant-select-arrow {
    color: var(--dfo-text-dim) !important;
}
.ant-input-number-group-addon,
.ant-input-group-addon {
    color: var(--dfo-text-dim) !important;
    background: var(--dfo-bg2) !important;
    border-color: var(--dfo-border) !important;
}
.ant-checkbox-inner,
.ant-radio-inner {
    background: var(--dfo-bg1) !important;
    border-color: var(--dfo-border-strong) !important;
}
.ant-checkbox-checked .ant-checkbox-inner {
    background: var(--dfo-accent) !important;
    border-color: var(--dfo-accent) !important;
}

/* 按钮 */
.ant-btn-default,
.ant-btn-outline {
    background: var(--dfo-bg1) !important;
    border-color: var(--dfo-border-strong) !important;
    color: var(--dfo-text) !important;
}
.ant-btn-primary:not(.ant-btn-dangerous),
.ant-btn-primary:not(.ant-btn-dangerous) > span {
    background: var(--dfo-accent) !important;
    border-color: var(--dfo-accent) !important;
    color: #04201D !important;
}
.ant-btn-link {
    color: var(--dfo-accent) !important;
    background: transparent !important;
    border-color: transparent !important;
}
.ant-btn-text {
    color: var(--dfo-text-dim) !important;
}
.ant-btn[disabled],
.ant-btn[disabled]:hover {
    color: var(--dfo-muted) !important;
    background: var(--dfo-bg2) !important;
    border-color: var(--dfo-border) !important;
}
/* 危险按钮保持白字（补上：链接型危险按钮曾无底色）*/
.ant-btn-dangerous:not(.ant-btn-link),
.ant-btn-dangerous:not(.ant-btn-link) > span {
    color: #ffffff !important;
}
.ant-btn-link.ant-btn-dangerous,
.ant-btn-link.ant-btn-dangerous:hover {
    color: var(--dfo-up) !important;
}

/* 表格空数据/展开省略号提示同样跟着主题走 */
.ant-table .ant-table-cell-ellipsis .ant-table-cell-content,
.ant-typography.ant-typography-ellipsis {
    color: inherit !important;
}
.ant-checkbox .ant-checkbox + span {
    color: var(--dfo-text-dim);
}

/* 老页面里 antd 默认黑字跟随主题 */
#app-mount,
.ant-tabs-tabpane,
.ant-dropdown-trigger,
.ant-card-head-title {
    color: var(--dfo-text);
}
.ant-table-thead th,
.ant-table-tbody td {
    color: inherit;
}
.ant-table-thead th {
    color: var(--dfo-text-dim);
}
.ant-table-tbody td {
    color: var(--dfo-text);
}
.ant-select-selection-item,
.ant-select-selection-placeholder {
    color: var(--dfo-text);
}
.ant-select-selection-placeholder {
    color: var(--dfo-muted);
}

/* 页面里写死的涨跌色（#FF5C5C / #2ED47A 是为暗色挑的，白底上太浅）
   → 统一提到令牌色；只匹配“文字颜色”，不动底色 */
[style*="color: rgb(255, 77, 79)"], [style*="color: #ff4d4f"] {
    color: var(--dfo-up) !important;
}
[style*="color: rgb(34, 197, 94)"], [style*="color: #22c55e"] {
    color: var(--dfo-down) !important;
}
/* 老页面的 #2FD8C5/#2FD8C5 / #8698AB 一并归到令牌 */
[style*="color: rgb(24, 144, 255)"], [style*="color: #1890ff"],
[style*="color: rgb(22, 119, 255)"], [style*="color: #1677ff"] {
    color: var(--dfo-accent) !important;
}
[style*="color: rgb(140, 140, 140)"], [style*="color: #8c8c8c"] {
    color: var(--dfo-text-dim) !important;
}

/* ------------------------------------------------------------
   §14 布局修复（与原暗色主题一致，勿删）
   ------------------------------------------------------------ */

/* feffery AntdCard 会给 .ant-card-body 注入 display:flex;flex-wrap:wrap，
   窄屏下内部 Row 换行后与分隔线/表格互相压盖 → 压回块级流式布局 */
.ant-card-body {
    display: block !important;
}

/* 窄屏表格：table-layout:fixed 且无 scroll.x 时列会被压到 25px，
   单元格文字压到隔壁列上 → 让表格按列宽铺开、容器横向滚动 */
.ant-table-wrapper .ant-table-content,
.ant-table-wrapper .ant-table-body {
    overflow-x: auto !important;
}
.ant-table-wrapper .ant-table-content > table,
.ant-table-wrapper .ant-table-body > table {
    width: max-content !important;
    min-width: 100% !important;
    table-layout: auto !important;
}

/* 空标题卡片渲染出的空头部（统一消除卡片顶部空白）*/
.ant-card-head:not(:has(.ant-card-head-title)) {
    display: none !important;
}

/* dcc.Graph 在 flex 卡片体内宽度塌陷 */
.dash-graph {
    width: 100%;
    min-width: 0;
}

/* ============================================================
   §15 V1「终端」细化层（2026-10-15 按用户裁定「按照第一版部署」）
   上面那 14 节已经把颜色换成暗色；这一节只做「终端化」的
   密度 / 排版 / 外壳细节 —— 改这里不会动到任何颜色语义。
   ============================================================ */

/* 15.1 排版：正文 12.5px，数字一律等宽 tabular */
body {
    font-size: 12.5px;
    line-height: 1.55;
}
.dfo-mono,
.dfo-num,
.dfo-kpi-value,
.ant-statistic-content,
kbd, code, samp {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}
.ant-table {
    font-variant-numeric: tabular-nums;
}

/* 15.2 表格：终端密度（行高压到 8px 内距，表头小字距） */
.ant-table-tbody > tr > td {
    padding: 8px 10px !important;
    font-size: 12.5px;
    line-height: 1.55;
}
.ant-table-thead > tr > th {
    padding: 7px 10px !important;
    font-size: 11px !important;
    font-weight: 500 !important;
    letter-spacing: 0.05em;
}
.ant-table-tbody > tr:hover > td {
    background: var(--dfo-bg2) !important;
}
.ant-table-cell .ant-tag,
.ant-table-cell .dfo-chip {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* 15.3 面：圆角 3px，面板不加投影（靠 1px 描边 + 面层级分层） */
.ant-card,
.ant-modal-content,
.ant-drawer-content,
.ant-dropdown-menu,
.ant-select-dropdown,
.ant-picker-dropdown .ant-picker-panel-container,
.ant-popover-inner,
.ant-btn,
.ant-btn-sm,
.ant-btn-lg,
.ant-input,
.ant-input-affix-wrapper,
.ant-select-selector,
.ant-picker,
.ant-tag,
.ant-alert,
.ant-notification-notice,
.ant-message-notice-content {
    border-radius: 3px !important;
}
.ant-card {
    box-shadow: none !important;
}

/* 15.4 卡片头：紧一档 */
.ant-card-head {
    min-height: 34px !important;
    padding: 0 12px !important;
}
.ant-card-head-title {
    padding: 9px 0 !important;
    font-size: 12.5px !important;
    font-weight: 600 !important;
    letter-spacing: 0.01em;
}
.ant-card-body {
    padding: 12px !important;
}

/* 15.5 侧栏：212px 窄栏；一级分组标题走小字距；选中项左侧 2px 青条 */
.ant-layout-sider {
    width: 212px !important;
    min-width: 212px !important;
    max-width: 212px !important;
    flex: 0 0 212px !important;
}
.ant-layout-sider-collapsed {
    width: 56px !important;
    min-width: 56px !important;
    max-width: 56px !important;
    flex: 0 0 56px !important;
}
#index-side-menu .ant-menu-submenu-title {
    height: 26px !important;
    line-height: 26px !important;
    font-size: 10.5px !important;
    letter-spacing: 0.14em;
    color: var(--dfo-muted) !important;
    margin: 0 !important;
    width: 100% !important;
    border-radius: 0 !important;
}
#index-side-menu .ant-menu-submenu-title .ant-menu-submenu-arrow {
    color: var(--dfo-muted) !important;
}
#index-side-menu .ant-menu-item {
    height: 28px !important;
    line-height: 28px !important;
    font-size: 12.5px !important;
    margin: 0 !important;
    width: 100% !important;
    border-radius: 0 !important;
}
/* 干掉 antd 默认的右侧选中竖条，改左侧 2px 青条（终端语义：当前所在） */
#index-side-menu .ant-menu-item::after,
#index-side-menu .ant-menu-submenu-title::after {
    display: none !important;
}
#index-side-menu .ant-menu-item-selected {
    box-shadow: inset 2px 0 0 var(--dfo-accent);
}
#index-side-menu .ant-menu-submenu-selected > .ant-menu-submenu-title {
    color: var(--dfo-text-dim) !important;
}

/* 15.6 顶栏：42px，去掉投影，靠 1px 下线分层 */
.dfo-header-row {
    height: 42px !important;
    box-shadow: none !important;
}
#menu-collapse-sider-custom .ant-row {
    height: 56px;
}

/* 15.7 底部状态栏：2026-10-15 全站撤除（DOM 已从 views/layout/__init__.py 删除）。
   相关 .dfo-status-bar / .dfo-status-dot 规则与「为状态栏让位」的 .ant-layout-content
   padding-bottom、#build-stamp 偏移一起清掉，否则页面底部会空出一条无用的留白。 */

/* 15.8 类名契约的终端化 */
.dfo-kpi {
    background: var(--dfo-bg1) !important;
    border: 1px solid var(--dfo-border);
    border-radius: 3px !important;
    box-shadow: none !important;
}
.dfo-kpi .dfo-kpi-value {
    font-weight: 600;
}
.dfo-chip {
    border-radius: 3px !important;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important;
    font-size: 10.5px !important;
    height: 18px !important;
    line-height: 17px !important;
    padding: 0 6px !important;
}
.dfo-section-title {
    font-size: 12px;
    letter-spacing: 0.04em;
}

/* ------------------------------------------------------------
   15.9 审计出来的三处「还是浅色」收口（2026-10-15，用
   audit.js 在真机上逐元素扫 computed background 找出来的，
   不是凭印象挑的）：
     · .ant-segmented（结果分析页「策略汇总 / 结果明细」）
     · .ant-pagination-options-quick-jumper input（跳页输入框）
     · .ant-table-placeholder（空表占位）
   ------------------------------------------------------------ */
.ant-segmented {
    background: var(--dfo-bg2) !important;
    color: var(--dfo-text-dim) !important;
}
.ant-segmented .ant-segmented-item {
    color: var(--dfo-text-dim) !important;
}
.ant-segmented .ant-segmented-item:hover:not(.ant-segmented-item-selected) {
    background: var(--dfo-bg3) !important;
    color: var(--dfo-text) !important;
}
.ant-segmented .ant-segmented-item-selected,
.ant-segmented .ant-segmented-thumb {
    background: var(--dfo-bg1) !important;
    color: var(--dfo-accent) !important;
    box-shadow: none !important;
}
.ant-pagination-options-quick-jumper input {
    background: var(--dfo-bg1) !important;
    color: var(--dfo-text) !important;
    border-color: var(--dfo-border-strong) !important;
}
.ant-table-placeholder,
.ant-table-placeholder:hover > td,
.ant-table-placeholder > td {
    background: var(--dfo-bg1) !important;
}
.ant-table-placeholder .ant-empty-description {
    color: var(--dfo-muted) !important;
}

/* ------------------------------------------------------------
   15.10 plotly 图表收口：页面里图表 layout 还按浅色主题配的
   （paper/plot 白底、轴标签深灰），在暗底上就是一块白板。
   这里只改「底板 + 刻度 + 图例」，**不动数据线与被标注的文字颜色**
   —— 涨跌注释类文字保持页面自己的红/绿语义。
   ------------------------------------------------------------ */
.js-plotly-plot .main-svg,
.js-plotly-plot .plot-container,
.js-plotly-plot .svg-container,
.js-plotly-plot .bg {
    background: transparent !important;
}
.js-plotly-plot .main-svg rect.bg {
    fill: transparent !important;
}
.js-plotly-plot .xtick text,
.js-plotly-plot .ytick text,
.js-plotly-plot .legend text,
.js-plotly-plot .g-xtitle text,
.js-plotly-plot .g-ytitle text {
    fill: var(--dfo-text-dim) !important;
}
.js-plotly-plot .gridlayer path,
.js-plotly-plot .gridlayer line,
.js-plotly-plot .axislayer-above path {
    stroke: var(--dfo-border) !important;
}
.js-plotly-plot .zerolinelayer path {
    stroke: var(--dfo-border-strong) !important;
}

/* ------------------------------------------------------------
   15.11 空态 / 结果页（404、错误页）：标题与副标题在暗底上原本是
   默认深色 → 实测只有 1.03:1（等于看不见）。这是路由打不开时用户
   唯一能看到的字，必须能读。
   ------------------------------------------------------------ */
.ant-result-title {
    color: var(--dfo-text) !important;
}
.ant-result-subtitle {
    color: var(--dfo-text-dim) !important;
}
.ant-result-extra .ant-btn {
    color: var(--dfo-text-dim);
}
.ant-result-info .ant-result-icon > .anticon,
.ant-result-404 .ant-result-icon > .anticon,
.ant-result-error .ant-result-icon > .anticon {
    color: var(--dfo-accent) !important;
}
.ant-empty-normal .ant-empty-description,
.ant-empty .ant-empty-description {
    color: var(--dfo-muted) !important;
}

/* ------------------------------------------------------------
   15.12 选中行：antd 默认给 tableRowSelectedBg = #E6F4FF（浅蓝），
   在暗色下等于把整行字吃掉 —— 真机实测滚动验证页的数字只有 1.02:1。
   ------------------------------------------------------------ */
.ant-table-tbody > tr.ant-table-row-selected > td,
.ant-table-tbody > tr.ant-table-row-selected:hover > td,
.ant-table-wrapper .ant-table-tbody > tr.ant-table-row-selected > td {
    background: var(--dfo-accent-weak) !important;
    color: var(--dfo-text) !important;
}
.ant-table-tbody > tr.ant-table-row-selected .ant-table-cell-row-hover {
    background: var(--dfo-accent-weak) !important;
}

/* ------------------------------------------------------------
   15.13 antd 预设 tag 全套：原主题只覆盖了 blue / success / volcano /
   orange 三种，其余预设色还是浅底 + antd 自己的深色字（实测
   .ant-tag-green「正常」只有 3.37:1）。这里把预设色一次性收口成
   「半透明底 + 亮字 + 同色描边」，保留颜色语义，不再逐个漏。
   ------------------------------------------------------------ */
.ant-tag-green,
.ant-tag-success {
    color: #5BE49B !important;
    background: rgba(46, 212, 122, 0.14) !important;
    border-color: rgba(46, 212, 122, 0.42) !important;
}
.ant-tag-red,
.ant-tag-error {
    color: #FF8A82 !important;
    background: rgba(255, 92, 92, 0.14) !important;
    border-color: rgba(255, 92, 92, 0.42) !important;
}
.ant-tag-gold,
.ant-tag-warning {
    color: #F7CE63 !important;
    background: rgba(240, 180, 41, 0.14) !important;
    border-color: rgba(240, 180, 41, 0.42) !important;
}
.ant-tag-cyan,
.ant-tag-processing {
    color: #6FE4D6 !important;
    background: rgba(47, 216, 197, 0.14) !important;
    border-color: rgba(47, 216, 197, 0.42) !important;
}
.ant-tag-blue {
    color: #8FB8E8 !important;
    background: rgba(127, 168, 216, 0.16) !important;
    border-color: rgba(127, 168, 216, 0.42) !important;
}
.ant-tag-geekblue {
    color: #A8B6F0 !important;
    background: rgba(120, 140, 230, 0.16) !important;
    border-color: rgba(120, 140, 230, 0.42) !important;
}
.ant-tag-purple {
    color: #C4A8F0 !important;
    background: rgba(150, 110, 220, 0.16) !important;
    border-color: rgba(150, 110, 220, 0.42) !important;
}
.ant-tag-magenta {
    color: #F09AC8 !important;
    background: rgba(220, 90, 160, 0.16) !important;
    border-color: rgba(220, 90, 160, 0.42) !important;
}
.ant-tag-lime {
    color: #B8E060 !important;
    background: rgba(150, 200, 60, 0.16) !important;
    border-color: rgba(150, 200, 60, 0.42) !important;
}

/* 状态点 / 徽标颜色在暗底上的提亮 */
.ant-badge-status-success .ant-badge-status-dot { background: var(--dfo-down) !important; }
.ant-badge-status-error .ant-badge-status-dot { background: var(--dfo-up) !important; }
.ant-badge-status-warning .ant-badge-status-dot { background: var(--dfo-warn) !important; }
.ant-badge-status-processing .ant-badge-status-dot { background: var(--dfo-accent) !important; }
.ant-badge-status-text { color: var(--dfo-text-dim) !important; }

/* ------------------------------------------------------------
   15.14 开关（Switch）文字：真机实测「开启 / 关闭」两个词只有 4.10:1。
   选中态底是强调青 → 字必须压深；未选态底是暗灰 → 字必须提亮。
   ------------------------------------------------------------ */
.ant-switch .ant-switch-inner-checked {
    color: #04201D !important;
}
.ant-switch .ant-switch-inner-unchecked {
    color: var(--dfo-text) !important;
}

/* ------------------------------------------------------------
   15.15 antd v5 cssinjs 会把主色写成「双类名」规则（.ant-switch.ant-switch-checked），
   §8 里的单类规则压不住 → 实测开关选中态底仍是 antd 默认蓝 rgb(22,119,255)，
   导致「开启」只有 4.16:1。这里按主色补 !important（与 §13 同一思路，
   只补真正被压住的那几个，不一刀切）。
   ------------------------------------------------------------ */
.ant-switch {
    background: var(--dfo-border-strong) !important;
}
.ant-switch.ant-switch-checked,
.ant-switch-checked {
    background: var(--dfo-accent) !important;
}
.ant-checkbox-checked .ant-checkbox-inner,
.ant-checkbox-wrapper:hover .ant-checkbox-inner,
.ant-checkbox:hover .ant-checkbox-inner {
    background: var(--dfo-accent) !important;
    border-color: var(--dfo-accent) !important;
}
.ant-radio-checked .ant-radio-inner {
    border-color: var(--dfo-accent) !important;
}
.ant-radio-checked .ant-radio-inner::after {
    background: var(--dfo-accent) !important;
}
.ant-progress-bg {
    background: var(--dfo-accent) !important;
}
.ant-slider-track {
    background: var(--dfo-accent) !important;
}
.ant-slider-handle::after {
    box-shadow: 0 0 0 2px var(--dfo-accent) !important;
}

/* ------------------------------------------------------------
   15.16 禁用态：antd 给 `a[disabled]` / .ant-typography-disabled 的
   color 是 rgba(0,0,0,.25)（默认浅色主题的写法）。真机实测
   /system/user 表格里的「更多」下拉在被 disable 的行上只有 1.07:1 —— 看不见。
   禁用态要「明显变弱」但**仍然能读**，统一收到 --dfo-muted（对 bg1 5.8:1）。
   ------------------------------------------------------------ */
.ant-dropdown-link[disabled],
.ant-dropdown-trigger[disabled],
a[disabled],
.ant-typography-disabled,
.ant-typography.ant-typography-disabled {
    color: var(--dfo-muted) !important;
    cursor: not-allowed;
}
.ant-dropdown-link[disabled] .anticon,
.ant-dropdown-trigger[disabled] .anticon,
a[disabled] .anticon {
    color: inherit !important;
}

/* ------------------------------------------------------------
   15.17 登录页：主题 §9 只写了 `#login-form-container`，而实际登录页的
   类名是 `#login-page` + `.ant-pro-form-login-*` —— 选择器对不上，
   结果登录卡还是白底 + 浅色主题的深色字，真机实测「浮生 · 活着，靠搞钱
   养活自己」只有 1.04:1、忘记密码 1.79:1、记住我 1.99:1。登录页是
   老板打开系统的第一屏，这里必须能读。
   ------------------------------------------------------------ */
#login-page {
    background: var(--dfo-bg0) !important;
}
#login-page .ant-pro-form-login-container,
#login-page .ant-pro-form-login-main,
.ant-pro-form-login-main {
    background: var(--dfo-bg1) !important;
    border: 1px solid var(--dfo-border);
    border-radius: 3px;
    box-shadow: none;
}
.ant-pro-form-login-title {
    color: var(--dfo-text) !important;
}
.ant-pro-form-login-desc {
    color: var(--dfo-text-dim) !important;
}
#login-page .ant-form-item-label > label {
    color: var(--dfo-text-dim) !important;
}
#login-page a,
#forget-password-link,
#forget-password-link span {
    color: var(--dfo-accent) !important;
}
#login-page .ant-checkbox-wrapper,
#login-page .ant-checkbox-wrapper span {
    color: var(--dfo-text-dim) !important;
}
/* 验证码是图片，必须留白底，否则认不出来 —— 这条是**故意**的浅色 */
#login-captcha-image-container,
#login-captcha-image,
#login-captcha-image img {
    background: #FFFFFF !important;
    border-radius: 3px;
}
#login-page .ant-form-item-explain-error {
    color: var(--dfo-up) !important;
}
