/* ── Reset & Base ── */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  --bg-primary: #0a0e14;
  --bg-secondary: #0f1821;
  --bg-card: #121c27;
  --bg-card-hover: #172230;
  --bg-input: #080e14;
  --border: #1e2d3a;
  --border-light: #2a3f50;
  --text-primary: #e8eef4;
  --text-secondary: #9ab0c4;
  --text-muted: #5a7085;
  --accent: #4fc3f7;
  --accent-glow: rgba(79, 195, 247, 0.15);
  --green: #66bb6a;
  --red: #ef5350;
  --yellow: #ffd54f;
  --orange: #ff9800;
  --sidebar-width: 170px;
  --header-height: 56px;
  --radius: 10px;
  --radius-sm: 6px;
}

body {
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  background: var(--bg-primary);
  color: var(--text-primary);
  min-height: 100vh;
  line-height: 1.6;
  overflow-x: hidden;
}

/* ── Screen switching ── */
.screen:not(#login-screen) {
  display: none;
}
.screen:not(#login-screen).active {
  display: block;
}

/* ── Login ── */
#login-screen {
  display: none;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: radial-gradient(ellipse at center, #0f1a25 0%, #080c12 70%);
}
#login-screen.active {
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-card {
  width: 420px;
  text-align: center;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 3rem 2.5rem;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.login-card .logo {
  font-size: 3rem;
  margin-bottom: 0.5rem;
}
.login-card h1 {
  font-size: 1.6rem;
  font-weight: 700;
  margin-bottom: 0.3rem;
}
.login-card .subtitle {
  color: var(--text-muted);
  font-size: 0.9rem;
  margin-bottom: 1.8rem;
}
.login-card .form-group {
  margin-bottom: 1rem;
  text-align: left;
}
.login-card .form-group label {
  display: block;
  font-size: 0.82rem;
  color: var(--text-secondary);
  margin-bottom: 0.3rem;
  font-weight: 500;
}
.login-card input[type='password'] {
  padding: 0.7rem 0.9rem;
  font-size: 0.95rem;
}
.login-card .btn {
  padding: 0.7rem;
  font-size: 0.95rem;
  margin-top: 0.5rem;
}
.checkbox-row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.82rem;
  color: var(--text-secondary);
  cursor: pointer;
  margin-bottom: 0.5rem;
  width: fit-content;
}
.checkbox-row input[type='checkbox'] {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--accent);
}
#login-error {
  margin-top: 0.8rem;
  font-size: 0.85rem;
  color: var(--red);
}

/* ── Admin Layout ── */
#admin-screen {
  display: none;
  min-height: 100vh;
}
#admin-screen.active {
  display: flex;
  min-height: 100vh;
  height: auto;
}

/* ── Sidebar ── */
.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  width: var(--sidebar-width);
  height: 100vh;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  z-index: 100;
  overflow-y: auto;
}
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 1rem 1.2rem;
  border-bottom: 1px solid var(--border);
  height: var(--header-height);
  flex-shrink: 0;
}
.sidebar-brand span {
  font-size: 1.4rem;
}
.sidebar-brand h1 {
  font-size: 1rem;
  font-weight: 700;
  white-space: nowrap;
}
.sidebar-nav {
  flex: 1;
  padding: 0.8rem 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.nav-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.8rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.12s;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
}
.nav-item:hover {
  background: rgba(79, 195, 247, 0.06);
  color: var(--text-secondary);
}
.nav-item.active {
  background: var(--accent-glow);
  color: var(--accent);
}
.nav-item.logout {
  margin-top: auto;
  color: var(--red);
}
.nav-item.logout:hover {
  background: rgba(239, 83, 80, 0.08);
}
.nav-item .nav-icon {
  font-size: 1.1rem;
  width: 1.6rem;
  text-align: center;
  flex-shrink: 0;
}
.nav-item .nav-label {
  white-space: nowrap;
}

/* ── Main Content ── */
.main-content {
  margin-left: var(--sidebar-width);
  flex: 1;
  padding: 1.2rem 1.8rem;
  max-width: calc(100vw - var(--sidebar-width));
  min-height: 100vh;
  overflow-y: auto;
}

/* ── Top Bar ── */
.top-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.2rem;
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--border);
}
.top-bar h2 {
  font-size: 1.15rem;
  font-weight: 600;
}
.top-actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

/* 退出登录按钮：桌面端隐藏（底部导航已有），手机端显示 */
.logout-top-btn {
  display: none;
}
@media (max-width: 768px) {
  .logout-top-btn {
    display: inline-flex;
  }
}

/* ── Card ── */
.card {
  background: var(--bg-card);
  border-radius: var(--radius);
  padding: 1.2rem 1.4rem;
  margin-bottom: 1rem;
  border: 1px solid var(--border);
  transition: border-color 0.15s;
}
.card:hover {
  border-color: var(--border-light);
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.8rem;
}
.card-header h2 {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.card-header-actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}

/* ── Stats Grid ── */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.85rem;
  margin-bottom: 1rem;
}
.stat-card {
  position: relative;
  background: var(--bg-card);
  border-radius: var(--radius);
  padding: 1.1rem 1rem 0.8rem;
  text-align: center;
  border: 1px solid var(--border);
  overflow: hidden;
  transition:
    border-color 0.15s,
    transform 0.12s,
    box-shadow 0.15s;
}
.stat-card:hover {
  border-color: var(--border-light);
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}
/* 每个卡片顶部一条主题色装饰条 */
.stat-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--accent), transparent);
}
.stat-card-upstream::before {
  background: linear-gradient(90deg, #66bb6a, transparent);
}
.stat-card-conc::before {
  background: linear-gradient(90deg, #ff9800, transparent);
}
.stat-card-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-bottom: 0.35rem;
}
.stat-ico {
  font-size: 0.95rem;
  line-height: 1;
}
.stat-num {
  display: block;
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--accent);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  background: linear-gradient(135deg, var(--accent), #2196f3);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.stat-card-upstream .stat-num {
  background: linear-gradient(135deg, #66bb6a, #43a047);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.stat-card-conc .stat-num {
  background: linear-gradient(135deg, #ffb74d, #fb8c00);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.stat-label {
  color: var(--text-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 600;
}
.stat-pct {
  display: inline-block;
  margin-top: 0.15rem;
  font-size: 0.68rem;
  color: var(--accent);
  background: rgba(79, 195, 247, 0.12);
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  letter-spacing: 0.02em;
}
/* 活跃率进度条 */
.stat-progress {
  height: 5px;
  border-radius: 999px;
  background: var(--bg-input);
  margin-top: 0.55rem;
  overflow: hidden;
}
.stat-progress-fill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), #2196f3);
  transition: width 0.6s ease;
}
.stat-sublist {
  margin-top: 0.6rem;
  border-top: 1px dashed var(--border);
  padding-top: 0.3rem;
  max-height: 96px;
  overflow-y: auto;
}
.stat-subrow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.7rem;
  padding: 0.24rem 0.15rem;
  gap: 0.4rem;
  border-radius: 6px;
  transition: background 0.12s;
}
.stat-subrow:hover {
  background: rgba(255, 255, 255, 0.03);
}
.stat-subrow + .stat-subrow {
  border-top: 1px solid var(--border);
}
.stat-sub-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-secondary);
  min-width: 0;
}
.stat-sub-val {
  white-space: nowrap;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  background: var(--bg-input);
  padding: 0.06rem 0.45rem;
  border-radius: 6px;
}
.stat-sub-live {
  color: #fff;
  background: rgba(255, 152, 0, 0.18);
  font-weight: 600;
}
.stat-sub-empty {
  justify-content: center;
  color: var(--text-muted);
  font-size: 0.68rem;
  padding: 0.3rem 0;
}

/* ── Forms ── */
.form-group {
  margin-bottom: 0.6rem;
}
.form-group label {
  display: block;
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-bottom: 0.25rem;
  font-weight: 500;
}
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 0.8rem;
  align-items: start;
}
.form-row .full-width {
  grid-column: 1 / -1;
}
.form-row .btn-wrap {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
}
.form-row .form-row-btn {
  grid-column: 1 / -1;
  padding-top: 0.3rem;
}

input,
select {
  width: 100%;
  padding: 0.55rem 0.7rem;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: 0.85rem;
  outline: none;
  transition:
    border-color 0.15s,
    box-shadow 0.15s;
}
input:focus,
select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
::placeholder {
  color: var(--text-muted);
  opacity: 0.6;
}

.input-sm {
  padding: 0.35rem 0.55rem;
  font-size: 0.78rem;
  width: auto;
  min-width: 140px;
}

/* ── Input + Unit Select ── */
.input-unit-group {
  display: flex;
  gap: 0;
  align-items: stretch;
}
.input-unit-group .unit-input {
  flex: 1;
  min-width: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  border-right: none;
}
.input-unit-group .unit-input:focus {
  box-shadow: none;
  border-color: var(--accent);
}
.input-unit-group .unit-select {
  width: auto;
  min-width: 76px;
  flex-shrink: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--bg-input);
  cursor: pointer;
  padding: 0.55rem 0.35rem;
  font-size: 0.8rem;
  border-left: none;
}
.input-unit-group .unit-select:focus {
  box-shadow: none;
  border-color: var(--accent);
}
.input-unit-group .unit-input:focus + .unit-select {
  border-color: var(--accent);
}
.input-unit-group .unit-select option {
  background: var(--bg-card);
  color: var(--text-primary);
}
.unit-input[disabled] {
  opacity: 0.3;
  cursor: not-allowed;
  background: #0a131c;
}

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.5rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
  line-height: 1.4;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.btn:active {
  transform: translateY(0) scale(0.98);
}
.btn-primary {
  background: linear-gradient(135deg, var(--accent), #2196f3);
  color: #080e14;
  font-weight: 600;
}
.btn-primary:hover {
  background: linear-gradient(135deg, #6ccdf9, #42a5f5);
  box-shadow: 0 4px 15px var(--accent-glow);
  transform: translateY(-1px);
}
.btn-primary:active {
  transform: translateY(0);
}
.btn-outline {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.btn-outline:hover {
  border-color: var(--border-light);
  color: var(--text-secondary);
  background: rgba(79, 195, 247, 0.04);
}
.btn-ghost {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  padding: 0.3rem 0.6rem;
  border-radius: var(--radius-sm);
  font-size: 0.82rem;
}
.btn-ghost:hover {
  background: var(--accent-glow);
  border-color: rgba(79, 195, 247, 0.25);
  color: var(--accent);
}
.text-danger {
  color: var(--red) !important;
}
.text-danger:hover {
  background: rgba(239, 83, 80, 0.1) !important;
  color: #ff6b6b !important;
}
.text-success {
  color: var(--green) !important;
}
.text-success:hover {
  background: rgba(102, 187, 106, 0.1) !important;
  color: #81c784 !important;
}
.btn-block {
  width: 100%;
}
.btn-sm {
  padding: 0.3rem 0.55rem;
  font-size: 0.8rem;
}
.btn-lg {
  padding: 0.6rem 1.2rem;
  font-size: 0.95rem;
}
.btn-danger {
  background: transparent;
  border: 1px solid rgba(239, 83, 80, 0.3);
  color: var(--red);
}
.btn-danger:hover {
  background: rgba(239, 83, 80, 0.12);
  border-color: rgba(239, 83, 80, 0.5);
  color: #ff6b6b;
}

/* ── Tables ── */
.table-wrap {
  overflow-x: hidden;
  border-radius: var(--radius-sm);
}
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8rem;
}
thead {
  position: sticky;
  top: 0;
  z-index: 1;
}
th {
  text-align: left;
  padding: 0.5rem 0.6rem;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--border);
  background: #0b131d;
  white-space: nowrap;
}
td {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid rgba(30, 45, 58, 0.5);
  vertical-align: middle;
}
tr:last-child td {
  border-bottom: none;
}
tr:hover td {
  background: rgba(79, 195, 247, 0.03);
}
.num-cell {
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.time-cell {
  white-space: nowrap;
  color: var(--text-muted);
  font-size: 0.76rem;
  text-align: center;
}
.mono-cell {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.76rem;
}
#recent-calls-table th,
#recent-calls-table td,
#detail-logs-table th,
#detail-logs-table td,
#err-logs-table th,
#err-logs-table td {
  text-align: center;
}
.action-cell {
  white-space: nowrap;
  text-align: right;
}
.rank-num {
  font-weight: 700;
  color: var(--accent);
  width: 1.8rem;
}
.empty-row {
  text-align: center;
  color: #3a4a5a;
  padding: 2rem !important;
  font-style: italic;
}

/* ── 口径 / 时间窗口切换按钮组 ──
   原先只有 stats/runtime.html 用页面内 <style> 私有定义，已提到此处共用
   （首页「模型响应时间」的窗口切换复用同一套外观）。 */
.scope-tabs {
  display: flex;
  gap: 0.35rem;
}
.scope-tab {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 0.82rem;
  transition: all 0.15s ease;
}
.scope-tab:hover {
  color: var(--text-primary);
  border-color: var(--border-light);
  background: rgba(79, 195, 247, 0.05);
}
.scope-tab.active {
  background: linear-gradient(135deg, var(--accent), #2196f3);
  color: #080e14;
  font-weight: 600;
  border-color: transparent;
}
.scope-tab.active .icon {
  filter: none;
}

/* 响应时间区块：口径说明行 */
.latency-meta {
  color: var(--text-muted);
  font-size: 0.74rem;
  padding: 0 0.25rem 0.7rem;
  line-height: 1.6;
}
/* 响应时间区块：头部右侧的「统计维度 / 时间范围」筛选控件
   —— 原先是 9 个窗口按钮（.scope-tabs），横向撑爆卡片头且在窄屏折行，
   改为原生 <select> 下拉：省空间、支持键盘、窄屏友好。
   ⚠️ 原生 <select> 在 width:auto 时固有宽度由**最宽的 option** 决定，
   故这里显式 min-width，别让「近 30 分钟」把控件拉得过长。 */
.latency-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem 0.85rem;
}
.latency-ctl {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}
.latency-ctl-label {
  color: var(--text-muted);
  font-size: 0.76rem;
}
.latency-select {
  background: #141b24;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--text);
  border-radius: 6px;
  padding: 0.3rem 0.5rem;
  font-size: 0.78rem;
  outline: none;
  cursor: pointer;
  /* 全局 select{width:100%} 会让控件在 flex 头部里被拉伸，必须显式收回 */
  width: auto;
  flex: none;
  min-width: 6.5rem;
  transition: border-color 0.15s;
}
.latency-select:hover {
  border-color: rgba(79, 195, 247, 0.45);
}
.latency-select:focus {
  border-color: var(--accent);
}
.latency-select option {
  background: #141b24;
  color: var(--text);
}
/* 分位数分档配色：越靠右越红，便于一眼看出谁在拖长尾 */
.latency-p50 {
  color: #7ddc7d;
}
.latency-p95 {
  color: #ffd166;
}
.latency-p99 {
  color: #ef6f6c;
}

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem 1.1rem;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
  background: linear-gradient(180deg, rgba(79, 195, 247, 0.02), transparent);
}
.filter-bar .filter-item {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.76rem;
  color: var(--text-muted);
  white-space: nowrap;
}
.filter-bar select {
  background: #141b24;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--text);
  border-radius: 6px;
  padding: 0.32rem 0.55rem;
  font-size: 0.78rem;
  outline: none;
  transition: border-color 0.15s;
  min-width: 7rem;
}
.filter-bar select:hover,
.filter-bar select:focus {
  border-color: var(--accent, #4fc3f7);
}
.filter-bar .btn {
  margin-left: auto;
}

/* ── Apikeys 记录页（#recent-section）：筛选栏排成一行 ──
   该页条件较多（状态 / Key / 上游 / 模型 / 关键字 + 刷新 / 重置），默认 flex-wrap 会折成
   两行，把表格往下推、条件顺序也变乱。此处强制单行：宽度不够时整条横向滚动，而非换行。
   作用域限定 #recent-section（只此页有该 id），不影响其它用 .filter-bar 的页面
   （日志记录页 / 上游记录页 / Apikeys 管理页）。 */
#recent-section .filter-bar {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  padding-bottom: 0.6rem; /* 给横向滚动条留位，避免压住控件 */
}
#recent-section .filter-bar .filter-item,
#recent-section .filter-bar .btn {
  flex: 0 0 auto;
}
#recent-section .filter-bar select {
  min-width: 6.5rem;
  max-width: 11rem;
}
/* 关键字输入框：原先是 JS 模板里的内联样式，搬到此处以便统一控制宽度 */
#recent-section .filter-bar .rc-filter-input {
  background: #141b24;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--text);
  border-radius: 6px;
  padding: 0.32rem 0.55rem;
  font-size: 0.78rem;
  outline: none;
  transition: border-color 0.15s;
  width: 11rem;
  min-width: 0;
}
#recent-section .filter-bar .rc-filter-input:hover,
#recent-section .filter-bar .rc-filter-input:focus {
  border-color: var(--accent, #4fc3f7);
}

/* 手机端：一行塞不下 7 个控件，横滑找条件并不好用，改回折行，
   并沿用「标签在上、控件在下」的排法（与 Apikeys 管理页手机端一致）。 */
@media (max-width: 900px) {
  #recent-section .filter-bar {
    flex-wrap: wrap;
    overflow-x: visible;
    gap: 0.5rem 0.6rem;
    padding-bottom: 0.85rem;
  }
  #recent-section .filter-bar .filter-item {
    flex: 1 1 8rem;
    flex-direction: column;
    align-items: stretch;
    gap: 0.22rem;
  }
  #recent-section .filter-bar select,
  #recent-section .filter-bar .rc-filter-input {
    width: 100%;
    max-width: none;
    min-width: 0;
  }
  #recent-section .filter-bar .btn {
    flex: 1 1 6rem;
    margin-left: 0;
    justify-content: center;
  }
}

/* ── 错误类型徽标（按类别配色）── */
.err-type {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  font-size: 0.74rem;
  white-space: nowrap;
  line-height: 1.35;
  border: 1px solid transparent;
}
.err-t--nt {
  background: rgba(244, 67, 54, 0.14);
  color: #ef5350;
  border-color: rgba(244, 67, 54, 0.25);
}
.err-t--server {
  background: rgba(224, 53, 44, 0.14);
  color: #ff6659;
  border-color: rgba(224, 53, 44, 0.25);
}
.err-t--busy {
  background: rgba(255, 152, 0, 0.14);
  color: #ffb300;
  border-color: rgba(255, 152, 0, 0.25);
}
.err-t--key {
  background: rgba(79, 195, 247, 0.14);
  color: #4fc3f7;
  border-color: rgba(79, 195, 247, 0.25);
}
.err-t--quota {
  background: rgba(255, 193, 7, 0.12);
  color: #ffd54f;
  border-color: rgba(255, 193, 7, 0.22);
}
.err-t--http {
  background: rgba(233, 30, 99, 0.12);
  color: #f06292;
  border-color: rgba(233, 30, 99, 0.22);
}
.err-t--gn {
  background: rgba(120, 144, 156, 0.14);
  color: #b0bec5;
  border-color: rgba(120, 144, 156, 0.22);
}
/* 客户端主动断开：中性色，与「上游/网关故障」的红色系区分开 */
.err-t--client {
  background: rgba(149, 117, 205, 0.14);
  color: #b39ddb;
  border-color: rgba(149, 117, 205, 0.25);
}

/* ── 状态码徽标（按范围配色）── */
.err-code {
  display: inline-block;
  padding: 0.08rem 0.45rem;
  border-radius: 5px;
  font-weight: 700;
  font-size: 0.74rem;
  font-variant-numeric: tabular-nums;
  border: 1px solid transparent;
  min-width: 2.3rem;
}
.err-c--c5xx {
  background: rgba(244, 67, 54, 0.16);
  color: #ff6659;
  border-color: rgba(244, 67, 54, 0.3);
}
.err-c--c429 {
  background: rgba(255, 152, 0, 0.16);
  color: #ffb300;
  border-color: rgba(255, 152, 0, 0.3);
}
.err-c--c4xx {
  background: rgba(255, 193, 7, 0.12);
  color: #ffd54f;
  border-color: rgba(255, 193, 7, 0.24);
}
.err-c--c0 {
  background: rgba(120, 144, 156, 0.14);
  color: #b0bec5;
  border-color: rgba(120, 144, 156, 0.24);
}

/* ── 错误信息、占位、空状态 ── */
.err-msg {
  display: block;
  max-width: 220px;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash {
  color: #546e7a;
}
.err-empty {
  padding: 2.6rem 1rem;
  text-align: center;
  color: #78909c;
  font-style: normal;
}
.err-empty-icon {
  font-size: 2.2rem;
  margin-bottom: 0.5rem;
  opacity: 0.6;
}
.err-card {
  border-left: 3px solid rgba(244, 67, 54, 0.5) !important;
}

.muted {
  color: var(--text-muted);
}
.muted-sm {
  color: var(--text-muted);
  font-size: 0.74rem;
}

/* ── Key display ── */
.key-display {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.76rem;
  color: #7ab8d4;
  background: var(--bg-input);
  padding: 0.15rem 0.4rem;
  border-radius: 3px;
  cursor: pointer;
  transition:
    background 0.12s,
    color 0.12s;
}
.key-display:hover {
  background: #0e1a24;
  color: var(--accent);
}
.key-name {
  font-weight: 500;
  color: var(--text-primary);
}
.copy-trigger {
  cursor: pointer;
}

/* ── Badge ── */
.badge {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 20px;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.6;
}
.badge-active {
  background: rgba(67, 160, 71, 0.12);
  color: var(--green);
}
.badge-revoked {
  background: rgba(229, 57, 53, 0.12);
  color: var(--red);
}
.badge-expired {
  background: rgba(255, 193, 7, 0.12);
  color: var(--yellow);
}
/* 最短响应时间标签（v3.4.7）：中性紫，刻意与「活跃/已过期/已吊销」的状态色区分，
   避免在「名称/状态」列里被读成第四种状态。 */
.badge-mindur {
  background: rgba(171, 71, 188, 0.14);
  color: #ce93d8;
}

/* ── Modal ── */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  z-index: 1000;
  align-items: flex-start;
  justify-content: center;
  padding: 2rem 1rem;
  overflow-y: auto;
  backdrop-filter: blur(2px);
}
.modal-overlay.active {
  display: flex;
}
#content-modal {
  z-index: 1500;
}
.modal-content {
  background: var(--bg-card);
  border-radius: 14px;
  padding: 1.4rem 1.6rem;
  max-width: 1100px;
  width: 100%;
  margin-top: 2vh;
  position: relative;
  border: 1px solid var(--border);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
  animation: modalIn 0.2s ease;
}
@keyframes modalIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.modal-close {
  position: absolute;
  top: 0.6rem;
  right: 0.9rem;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.3rem;
  cursor: pointer;
  line-height: 1;
  padding: 0.2rem;
  border-radius: 4px;
  transition: color 0.12s;
}
.modal-close:hover {
  color: var(--text-primary);
}

/* ── 排错详情弹窗（v3.3.42）────────────────────────────────────────
   诉求：① PC 上充分利用宽度；② 元信息与归因结论同屏；③ 请求/响应体点击才加载。
   宽度策略：用 `96vw + max-width:1440px` 而不是固定宽度 —— 1080p 上占满、
   2K 屏上也不会拉出横向滚动条。common.js 的 showContentHtml 通过给
   #content-modal 加 .modal-wide 切换，普通内容弹窗不受影响。
   ------------------------------------------------------------------ */
#content-modal.modal-wide .modal-content {
  /* 内联 style="max-width:800px" 会盖住这里，故同时用 !important */
  max-width: 1440px !important;
  width: 96vw;
  padding: 1.1rem 1.4rem 1.4rem;
}
/* HTML 模式下 #content-modal-body 的内联 style 已被 showContentHtml 备份并清空，
   因此下面的规则会真正生效：取消纯文本 pre 的行内换行，改由内部容器各自控制。 */
#content-modal.modal-wide #content-modal-body {
  white-space: normal;
  background: none;
  padding: 0;
  font-size: inherit;
  color: inherit;
  overflow: auto;
}
.errdbg {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

/* 顶部指标条：一眼看到耗时/token/方式/状态码/上游/关联ID */
.errdbg-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.5rem;
}
.errdbg-metric {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  min-width: 0;
}
.errdbg-metric-k {
  display: block;
  font-size: 0.7rem;
  color: var(--text-muted);
  margin-bottom: 0.15rem;
}
.errdbg-metric-v {
  display: block;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.errdbg-metric.is-strong .errdbg-metric-v {
  font-size: 1.05rem;
}

/* 主体两栏：PC 上左元信息、右结论；窄屏自动降为单栏 */
.errdbg-grid {
  display: grid;
  grid-template-columns: minmax(300px, 0.85fr) minmax(420px, 1.15fr);
  gap: 0.85rem;
  align-items: start;
}
.errdbg-card {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.75rem 0.9rem;
  min-width: 0;
}
.errdbg-h3 {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: none;
}
.errdbg-h3:not(:first-child) {
  margin-top: 0.9rem;
}

/* 元信息：标签列 + 值列，值列自适应吃掉剩余宽度 */
.errdbg-meta {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.errdbg-meta-item {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.15rem 0;
  border-bottom: 1px dashed var(--border);
}
.errdbg-meta-item:last-child {
  border-bottom: none;
}
.errdbg-meta-k {
  font-size: 0.78rem;
  color: var(--text-muted);
}
.errdbg-meta-v {
  font-size: 0.85rem;
  color: var(--text-primary);
  word-break: break-all;
}
.errdbg-meta-v.is-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
}

/* 错误信息：独立强调块 */
.errdbg-msg {
  font-size: 0.88rem;
  color: var(--text-primary);
  background: rgba(239, 68, 68, 0.08);
  border-left: 3px solid var(--danger, #ef4444);
  padding: 0.5rem 0.65rem;
  border-radius: 0 6px 6px 0;
  word-break: break-word;
}

/* 正文/归因等宽块 */
.errdbg-pre {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78rem;
  line-height: 1.55;
  color: var(--text-secondary);
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem 0.7rem;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 46vh;
  overflow: auto;
}
.errdbg-pre-detail {
  max-height: 40vh;
}

/* 折叠区（请求内容 / 响应内容） */
.errdbg-sec {
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-secondary);
}
.errdbg-sec-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 0.8rem;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-primary);
  font-size: 0.87rem;
  text-align: left;
  font-family: inherit;
}
.errdbg-sec-head:hover {
  background: rgba(127, 127, 127, 0.08);
}
.errdbg-sec-caret {
  color: var(--text-muted);
  font-size: 0.75rem;
  width: 0.8rem;
}
.errdbg-sec-name {
  font-weight: 600;
}
.errdbg-sec-size {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.errdbg-sec-act {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--text-muted);
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 999px;
}
.errdbg-sec-body {
  padding: 0 0.8rem 0.8rem;
}
.errdbg-sec-tip {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-bottom: 0.4rem;
}

/* ── 过程记录时间线（v3.3.43）────────────────────────────────────────
   诉求：按「重试 / 切换 / 降级重绑」分类呈现整个失败过程。
   设计取舍：**不按类型分块**，而是保持真实时间顺序、用颜色 + 图标区分类型 ——
   排查要看的恰恰是因果链（先切换、再重试、最后失败），按类型分块会把它打乱成
   三段，反而要自己拼时间。
   ------------------------------------------------------------------ */
.errdbg-card--wide {
  grid-column: 1 / -1;
}
/* ── 排错详情重排（v3.3.53）────────────────────────────────────────
   动机见 apierror-log.js 的 renderErrDebug：① error_message 原来独占一张
   wide 卡片却只有一句话；②「上游 / 关联 ID」在指标条与基本信息里各出现一次；
   ③ Token 只有 `3560 / 28276 / 31835` 三个裸数字，没有输入/输出标签；
   ④ 归因结论排在第 4 块且只占半幅宽度；⑤ 孤儿读现场埋在「过程记录」中间。
   下面这几条是为新结构补的：概要行 / 归因结论块 / 元信息三列网格 / 静默卡片。 */

/* 概要行：一句话结论 + 次要信息（时间 / Key / 错误类型） */
.errdbg-summary {
  padding: 0.7rem 0.85rem;
  background: var(--bg-subtle, rgba(127, 127, 127, 0.06));
  border-radius: 8px;
  border-left: 3px solid var(--accent, #4a9eff);
}
.errdbg-summary-msg {
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text-main);
}
.errdbg-summary-sub {
  margin-top: 0.35rem;
  font-size: 0.75rem;
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
}
.errdbg-dot {
  opacity: 0.55;
}

/* 归因结论：排错的第一落点，整宽、左侧色条按严重度着色 */
.errdbg-card--verdict {
  border-left: 3px solid var(--warn, #e0a800);
}
.errdbg-verdict {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.errdbg-verdict-row {
  display: grid;
  grid-template-columns: 5.2rem minmax(0, 1fr);
  gap: 0.6rem;
  align-items: start;
}
.errdbg-verdict-k {
  font-size: 0.75rem;
  color: var(--text-muted);
  padding-top: 0.1rem;
  white-space: nowrap;
}
.errdbg-verdict-v {
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--text-main);
  /* 说明文案较长（含多条判别指引），给足行高与整宽，避免半幅宽度下折行成面条 */
  word-break: break-word;
}

/* 基本信息：三列网格（原来是 9 行两列的竖排，且与指标条重复两项） */
.errdbg-meta--grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.3rem 1.1rem;
}
.errdbg-meta--grid .errdbg-meta-item:last-child {
  border-bottom: none;
}

/* 无记录时的「过程记录」：不铺卡片背景，只留一行灰字 */
.errdbg-card--quiet {
  background: transparent;
  border: none;
  padding: 0;
}
.errdbg-note--quiet {
  background: transparent;
  padding: 0.15rem 0;
  font-size: 0.75rem;
}
.errdbg-h3-sub {
  font-weight: 400;
  color: var(--text-muted);
  margin-left: 0.4rem;
  font-size: 0.72rem;
}
.errdbg-note {
  font-size: 0.78rem;
  color: var(--text-muted);
  padding: 0.5rem 0.6rem;
  background: rgba(127, 127, 127, 0.07);
  border-radius: 6px;
}
.errdbg-ev-sum {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-bottom: 0.45rem;
}
.errdbg-evs {
  list-style: none;
  margin: 0;
  padding: 0 0 0 0.15rem;
  max-height: 32vh;
  overflow: auto;
}
/* 竖线 + 节点，构成一条真正的时间轴 */
.errdbg-ev {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.3rem 0 0.3rem 0.15rem;
}
.errdbg-ev::before {
  content: '';
  position: absolute;
  left: 0.85rem;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
}
.errdbg-ev:first-child::before {
  top: 0.75rem;
}
.errdbg-ev:last-child::before {
  bottom: calc(100% - 0.75rem);
}
.errdbg-ev-icon {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 1.45rem;
  height: 1.45rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: 0.72rem;
  font-weight: 700;
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.errdbg-ev-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
}
.errdbg-ev-main {
  font-size: 0.83rem;
  color: var(--text-primary);
  font-weight: 500;
  word-break: break-word;
}
.errdbg-ev-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}
.errdbg-ev-tag {
  font-size: 0.7rem;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 0.4rem;
  white-space: nowrap;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.errdbg-ev-msg {
  flex: 1 0 100%;
  font-size: 0.75rem;
  color: var(--text-muted);
  line-height: 1.5;
  word-break: break-word;
}
.errdbg-ev-at {
  flex: 0 0 auto;
  font-size: 0.72rem;
  color: var(--text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: nowrap;
}
/* 三类事件分色（色阶只用于**身份区分**，不表示严重程度） */
.errdbg-ev.is-failover .errdbg-ev-icon {
  color: #38bdf8;
  border-color: rgba(56, 189, 248, 0.5);
}
.errdbg-ev.is-retry .errdbg-ev-icon {
  color: #fbbf24;
  border-color: rgba(251, 191, 36, 0.5);
}
.errdbg-ev.is-rebind .errdbg-ev-icon {
  color: #a78bfa;
  border-color: rgba(167, 139, 250, 0.5);
}
.errdbg-ev.is-failover::before {
  background: rgba(56, 189, 248, 0.35);
}
.errdbg-ev.is-retry::before {
  background: rgba(251, 191, 36, 0.35);
}
.errdbg-ev.is-rebind::before {
  background: rgba(167, 139, 250, 0.35);
}
.errdbg-ev.is-attempt .errdbg-ev-icon {
  color: var(--text-primary);
}

/* ── 孤儿读区块（v3.3.48）─────────────────────────────────────────
   回答「客户端断开后上游到底返回了什么、什么时候返回」。非流式断开时网关
   不 abort fetch，让这次生成跑完并把真实结果留在 usage_logs。两种结局分色：
   is-ok（真的返回了内容）/ is-dead（到超时一个字节都没给 = 上游挂死）。
   ------------------------------------------------------------------ */
.errdbg-orphan {
  margin-top: 0.5rem;
  padding: 0.55rem 0.7rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(127, 127, 127, 0.06);
}
.errdbg-orphan.is-ok {
  border-color: rgba(34, 197, 94, 0.45);
  background: rgba(34, 197, 94, 0.07);
}
.errdbg-orphan.is-dead {
  border-color: rgba(239, 68, 68, 0.45);
  background: rgba(239, 68, 68, 0.07);
}
.errdbg-orphan-head {
  font-size: 0.85rem;
  color: var(--text-primary);
  font-weight: 600;
}
.errdbg-orphan-head b {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
}
.errdbg-orphan-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin: 0.35rem 0 0.3rem;
}
.errdbg-orphan-note {
  font-size: 0.75rem;
  color: var(--text-muted);
  line-height: 1.5;
  margin-bottom: 0.4rem;
}
.errdbg-orphan-btn {
  font-size: 0.75rem;
  color: var(--text-primary);
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.2rem 0.6rem;
  cursor: pointer;
  font-family: inherit;
}
.errdbg-orphan-btn:hover {
  background: rgba(127, 127, 127, 0.12);
}
.errdbg-pre-orphan {
  margin-top: 0.45rem;
  max-height: 34vh;
}

/* 窄屏：两栏降为单栏，指标条自然换行 */
@media (max-width: 1100px) {
  .errdbg-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (max-width: 900px) {
  #content-modal.modal-wide .modal-content {
    width: 100%;
    max-width: 100% !important;
  }
  .errdbg-pre,
  .errdbg-pre-detail {
    max-height: 34vh;
  }
}
.modal-content h2 {
  font-size: 1.1rem;
  font-weight: 700;
  margin-bottom: 1.2rem;
  padding-right: 1.5rem;
}

/* ── Create API Key modal form ── */
.create-key-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.9rem 1rem;
  align-items: start;
}
.create-key-form .full-width {
  grid-column: 1 / -1;
}
.create-key-form .form-group {
  margin-bottom: 0;
}
.create-key-form .form-group label {
  font-size: 0.78rem;
  margin-bottom: 0.3rem;
}
.create-key-form .create-key-actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
  margin-top: 0.2rem;
}
.create-key-form .create-key-actions .btn {
  min-width: 96px;
  justify-content: center;
}

/* ── Edit API Key modal（v3.4.21）──────────────────────────────
   诉求：10 个字段纵向堆成一列太窄太长，改「分区卡片 + 两列」，
   让「基本信息 / 配额与并发 / 时间与限速」一眼分得开，少滚动。
   作用域全部限定在 #edit-modal，避免影响创建弹窗与其它 modal。 */
#edit-modal .modal-content {
  width: min(680px, 94vw);
  max-width: none;
  padding: 1.4rem 1.6rem 1.2rem;
}
#edit-modal h2 {
  margin-bottom: 0.9rem;
}
#edit-modal .edit-sec {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  padding: 0.8rem 0.95rem 0.5rem;
  margin-bottom: 0.8rem;
}
#edit-modal .edit-sec-title {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0 0 0.7rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: 0.04em;
}
#edit-modal .edit-sec-title::before {
  content: '';
  width: 3px;
  height: 12px;
  border-radius: 2px;
  background: var(--accent);
}
#edit-modal .edit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.7rem 1rem;
  align-items: start;
}
#edit-modal .edit-field {
  min-width: 0;
  margin-bottom: 0.35rem;
}
#edit-modal .edit-field.full,
#edit-modal .edit-grid > .full {
  grid-column: 1 / -1;
}
/* 空提示（如暂无特级上游提示）不占高度，避免分组内出现莫名空隙 */
#edit-modal .edit-grid > .edit-hint:empty {
  display: none;
}
#edit-modal .edit-hint {
  margin-top: 0.35rem;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--text-muted);
}
/* 开关行：标题与说明在左、开关贴右，比上下堆叠更像一条设置项 */
#edit-modal .edit-switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.18);
}
#edit-modal .edit-switch-row > div {
  min-width: 0;
}
#edit-modal .edit-switch-row label {
  margin-bottom: 0;
}
#edit-modal .edit-switch-row .switch {
  flex: none;
}
#edit-modal .edit-quick {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.45rem;
}
/* 让浏览器按深色主题绘制日期选择器的图标与弹层，否则 Windows Chrome 会用亮色画 */
#edit-modal input[type='datetime-local'] {
  color-scheme: dark;
}
#edit-modal .edit-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}
#edit-modal .edit-actions #edit-error {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 0.78rem;
  text-align: left;
  color: #ef5350;
}
#edit-modal .edit-actions .btn {
  flex: none;
  min-width: 96px;
  justify-content: center;
}
@media (max-width: 600px) {
  #edit-modal .modal-content {
    width: 100%;
    padding: 1.1rem 1rem 1rem;
  }
  #edit-modal .edit-grid {
    grid-template-columns: 1fr;
  }
  #edit-modal .edit-actions {
    flex-wrap: wrap;
  }
  #edit-modal .edit-actions #edit-error {
    flex: 1 0 100%;
    order: -1;
  }
  #edit-modal .edit-actions .btn {
    flex: 1 1 0;
  }
}

/* ── Refresh Upstream Modal ── */
.ru-divider {
  border: none;
  border-top: 1px solid var(--border);
  margin: 1rem 0;
}
.ru-result {
  margin-top: 0.8rem;
  padding: 0.75rem;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--border);
  font-size: 0.82rem;
  line-height: 1.55;
}
.ru-summary {
  font-weight: 600;
  margin-bottom: 0.4rem;
}
.ru-result-list {
  margin: 0;
  padding-left: 1rem;
}
.ru-result-list li {
  margin: 0.15rem 0;
}
.ru-result-list li.ok {
  color: #7ee2a8;
  list-style: none;
}
.ru-result-list li.warn {
  color: #f0c36d;
  list-style: none;
}
.ru-rebound {
  color: var(--text-secondary);
  font-size: 0.78rem;
  padding-left: 0.2rem;
}
.ru-interval-row input[type='number'] {
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: var(--text-primary);
  font-size: 0.85rem;
}

/* ── Detail Grid ── */
.detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: 0.8rem;
}
.detail-section {
  margin-bottom: 1rem;
}
.detail-section h3 {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
/* ── 详情弹窗 Tab（分段控件形态，替代旧的下折页） ── */
.detail-tabs {
  display: flex;
  gap: 0.25rem;
  padding: 0.22rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-input);
  margin-bottom: 1rem;
  width: fit-content;
  max-width: 100%;
  overflow-x: auto;
}
.detail-tab {
  padding: 0.36rem 0.85rem;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.8rem;
  font-weight: 600;
  border-radius: 7px;
  white-space: nowrap;
  transition:
    background 0.12s,
    color 0.12s,
    border-color 0.12s;
}
.detail-tab:hover {
  color: var(--text-primary);
  background: var(--bg-card-hover);
}
.detail-tab.active {
  color: var(--text-primary);
  background: var(--bg-card);
  border-color: var(--border-light);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
}
.detail-tab-panel {
  display: none;
}
.detail-tab-panel.active {
  display: block;
}
.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
}
.logs-filter-wrap {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.info-row {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid rgba(30, 45, 58, 0.5);
  font-size: 0.84rem;
}
.info-row:last-child {
  border-bottom: none;
}
.info-label {
  color: var(--text-muted);
  min-width: 5.5rem;
  flex-shrink: 0;
  font-size: 0.8rem;
}
.info-value {
  color: var(--text-primary);
  word-break: break-all;
}
.key-value {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--accent) !important;
  word-break: break-all;
}
.copy-hint {
  font-size: 0.68rem;
  color: var(--text-muted);
  flex-shrink: 0;
}

/* ── Detail Info Grid（API Key 信息紧凑排版）── */
.detail-info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.15rem 1rem;
  font-size: 0.84rem;
}
.detail-info-grid .info-item {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.24rem 0;
  min-width: 0;
  border-bottom: 1px dashed rgba(30, 45, 58, 0.35);
}
.detail-info-grid .info-item:last-child {
  border-bottom: none;
}
.detail-info-grid .info-item.full {
  grid-column: 1 / -1;
}
.detail-info-grid .info-item .info-label {
  min-width: 4.2rem;
  font-size: 0.78rem;
}
.detail-info-grid .info-item .info-value {
  min-width: 0;
}
.detail-info-grid.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}
.detail-info-grid.cols-3 .info-item .info-label {
  min-width: auto;
  font-size: 0.76rem;
}
.detail-info-grid.cols-3 .info-item .info-value {
  font-size: 0.8rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.detail-section .quota-bar-wrap {
  padding: 0.1rem 0 0.45rem;
  margin-top: 0.1rem;
}

/* ══ Key 详情弹窗（重排版）═══════════════════════════════════════
   结构：概览主卡（名称 / 状态 / Key / 关键时间）→ 配额面板 → Token 用量
   面板 → 调用方式面板。全部面板等宽纵向排列，面板内再用等高网格，
   避免旧版左右两栏高度悬殊、标签与数值挤在一起。
   ⚠️ 老类（.detail-grid / .detail-info-grid / .token-summary-grid）保留：
   浏览器缓存里可能还有旧版 modals.js，样式先别删。
   ---------------------------------------------------------------- */
.kd-hero {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.95rem 1.05rem 0.85rem;
  margin-bottom: 0.9rem;
  background:
    radial-gradient(
      130% 150% at 0% 0%,
      rgba(79, 195, 247, 0.09),
      transparent 62%
    ),
    var(--bg-secondary);
}
.kd-hero-line {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
  min-width: 0;
}
.kd-name {
  font-size: 1.02rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.35;
  margin: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kd-status {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.08rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.7;
  flex-shrink: 0;
}
.kd-status i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 6px currentColor;
}
.kd-status.on {
  color: var(--green);
  background: rgba(102, 187, 106, 0.12);
}
.kd-status.warn {
  color: var(--yellow);
  background: rgba(255, 213, 79, 0.12);
}
.kd-status.off {
  color: var(--red);
  background: rgba(239, 83, 80, 0.12);
}
.kd-hero-id {
  margin-left: auto;
  font-size: 0.7rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.kd-keyline {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  margin: 0.7rem 0 0.7rem;
}
.kd-key {
  flex: 1;
  min-width: 0;
  display: block;
  padding: 0.44rem 0.7rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-input);
  color: #cfe9fb !important;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.79rem;
  line-height: 1.6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kd-copy {
  flex-shrink: 0;
}
.kd-facts {
  display: grid;
  /* 自适应列：宽度不够时自动折行，窄屏不再把日期挤成省略号 */
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 0.45rem 0.9rem;
}
.kd-fact {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.kd-fact > span {
  font-size: 0.68rem;
  color: var(--text-muted);
  letter-spacing: 0.02em;
}
.kd-fact > b {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kd-fact > b.kd-model {
  color: var(--accent);
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.78rem;
}
.kd-fact > b.kd-tone-on {
  color: var(--green);
}
.kd-fact > b.kd-tone-warn {
  color: var(--orange);
}
.kd-fact > b.kd-tone-off {
  color: var(--text-muted);
}
.kd-sub {
  font-style: normal;
  font-size: 0.68rem;
  color: var(--text-muted);
  margin-left: 0.3rem;
}
.kd-hint {
  margin-top: 0.62rem;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--border);
  font-size: 0.72rem;
  line-height: 1.55;
  color: var(--text-muted);
}
.kd-hint.warn {
  color: #ffb74d;
}

/* 面板：统一底色 + 细边框，内部所有网格等宽 */
.kd-panel {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.85rem 1rem 0.9rem;
  margin-bottom: 0.9rem;
}
.kd-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.7rem;
}
.kd-panel-head h3 {
  margin: 0;
  font-size: 0.83rem;
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: 0.01em;
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

/* 配额计量块（调用次数 / Token 配额） */
.kd-quotas {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
}
.kd-meter {
  border: 1px solid rgba(30, 45, 58, 0.75);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  padding: 0.6rem 0.75rem 0.55rem;
  min-width: 0;
}
.kd-meter-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}
.kd-meter-label {
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--text-muted);
}
.kd-meter-pct {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.kd-meter-main {
  display: flex;
  align-items: baseline;
  gap: 0.32rem;
  margin: 0.12rem 0 0.45rem;
  min-width: 0;
}
.kd-meter-main b {
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1.15;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.kd-meter-main i {
  font-style: normal;
  font-size: 0.74rem;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kd-meter .quota-bar {
  height: 5px;
}
.kd-meter-foot {
  margin-top: 0.32rem;
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: 0.7rem;
  color: var(--text-muted);
}
.kd-limits {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.4rem 0.9rem;
  margin-top: 0.72rem;
  padding-top: 0.68rem;
  border-top: 1px dashed var(--border);
}
.kd-limit {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  min-width: 0;
}
.kd-limit span {
  font-size: 0.72rem;
  color: var(--text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}
.kd-limit b {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Token 用量明细：一行四格 + 细分隔线（替代四张重卡片） */
.kd-figs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border: 1px solid rgba(30, 45, 58, 0.75);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  overflow: hidden;
}
.kd-fig {
  display: flex;
  flex-direction: column;
  gap: 0.16rem;
  padding: 0.6rem 0.75rem;
  border-left: 1px solid rgba(30, 45, 58, 0.75);
  min-width: 0;
}
.kd-fig:first-child {
  border-left: none;
}
.kd-fig span {
  font-size: 0.68rem;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kd-fig b {
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.kd-fig.in b {
  color: var(--accent);
}
.kd-fig.out b {
  color: var(--green);
}
.kd-fig.total b {
  color: var(--yellow);
}
.kd-note {
  margin-top: 0.55rem;
  font-size: 0.7rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* 调用方式：Endpoint / Key 并排，其余整行 */
.kd-code-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
}
/* 并排两块必须同时去掉外边距：只给 :last-child 去掉会让它比左块高出 0.6rem
   （grid stretch 用「外框高度」对齐，右侧少了 margin 就多占了 0.6rem 的边框盒） */
.kd-code-pair > .code-block {
  margin-bottom: 0;
}
/* 只清面板最后一个代码块的下外边距（原来的 .kd-panel .code-block:last-child
   会误命中并排区域里的 API Key 块） */
.kd-panel > .code-block:last-child {
  margin-bottom: 0;
}

/* ── Quota Bar ── */
.quota-bar-wrap {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0 0.3rem;
}
.quota-bar {
  flex: 1;
  height: 6px;
  background: var(--bg-input);
  border-radius: 3px;
  overflow: hidden;
}
.quota-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), #2196f3);
  border-radius: 3px;
  transition: width 0.4s ease;
}
.quota-fill.warning {
  background: linear-gradient(90deg, var(--orange), #fb8c00);
}
.quota-fill.danger {
  background: linear-gradient(90deg, var(--red), #e53935);
}
.quota-pct {
  font-size: 0.72rem;
  color: var(--accent);
  font-weight: 600;
  min-width: 2.8rem;
  text-align: right;
}

/* ── Detail Subsection ── */
.detail-subsection {
  margin-bottom: 0.7rem;
}
.sub-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 0.3rem;
}

/* ── Trend toggle buttons ── */
.trend-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.72rem;
  padding: 0.25rem 0.6rem;
  border-radius: 14px;
  cursor: pointer;
  transition: all 0.12s;
  white-space: nowrap;
}
.trend-btn-active {
  background: var(--accent);
  color: #080e14 !important;
  border-color: var(--accent);
  font-weight: 600;
}
.trend-btn-active:hover {
  background: #6ccdf9;
}

/* ── Code Blocks ── */
.code-block {
  background: var(--bg-input);
  border-radius: var(--radius-sm);
  margin-bottom: 0.6rem;
  overflow: hidden;
  border: 1px solid var(--border);
}
.code-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.35rem 0.8rem;
  background: #0b131d;
  font-size: 0.74rem;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
}
.code-content {
  display: block;
  padding: 0.6rem 0.8rem;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.76rem;
  line-height: 1.6;
  word-break: break-all;
  white-space: pre-wrap;
  color: var(--text-secondary);
}
.code-pre {
  margin: 0;
  overflow-x: auto;
}

.table-sm td {
  padding: 0.35rem 0.55rem;
  font-size: 0.76rem;
}
.table-sm th {
  padding: 0.35rem 0.55rem;
  font-size: 0.7rem;
}

/* ── Chart ── */
.chart-container {
  min-height: 100px;
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  padding: 0.5rem 0;
  overflow-x: auto;
  overflow-y: hidden;
}
.chart-empty {
  text-align: center;
  color: var(--text-muted);
  padding: 1.5rem;
  width: 100%;
  font-style: italic;
}
.chart-bar-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
}
.chart-bar {
  width: 60%;
  max-width: 36px;
  background: linear-gradient(to top, var(--accent), #72d0f8);
  border-radius: 4px 4px 0 0;
  min-height: 4px;
  transition: height 0.4s ease;
}
.chart-label {
  font-size: 0.68rem;
  color: var(--text-muted);
}
.chart-count {
  font-size: 0.7rem;
  color: var(--text-secondary);
  font-weight: 600;
}

/* ── Toast ── */
.toast {
  position: fixed;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-card);
  color: var(--text-primary);
  padding: 0.7rem 1.5rem;
  border-radius: var(--radius);
  font-size: 0.85rem;
  z-index: 2000;
  border: 1px solid var(--border);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
  animation: toastIn 0.25s ease;
  white-space: pre-line;
  text-align: center;
  max-width: 90vw;
  line-height: 1.5;
}
@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}
.toast-fade {
  opacity: 0;
  transform: translateX(-50%) translateY(12px);
  transition:
    opacity 0.25s,
    transform 0.25s;
}

/* ── Token Summary Grid ── */
.token-summary-grid {
  grid-template-columns: repeat(4, 1fr);
}
.token-summary-grid .stat-value {
  display: block;
  font-size: 1.4rem;
  font-weight: 700;
  line-height: 1.15;
}
.token-summary-grid .stat-card {
  padding: 0.8rem 0.6rem;
}
.stat-value.token-input {
  color: var(--accent);
}
.stat-value.token-output {
  color: var(--green);
}
.stat-value.token-total {
  color: var(--yellow);
}

/* ── Log content inline ── */
.log-content {
  display: inline-block;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: help;
  color: var(--text-muted);
  font-size: 0.76rem;
  line-height: 1.4;
}
.log-content.clickable {
  cursor: pointer;
  text-decoration: underline dotted #2a3a48;
  text-underline-offset: 2px;
  transition: color 0.12s;
}
.log-content.clickable:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}
.token-cell {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.76rem;
  color: var(--yellow);
}

/* ── Upstream Status ── */
.upstream-status-card {
  border-left: 3px solid var(--accent);
  background: linear-gradient(135deg, var(--bg-card) 0%, #0d1722 100%);
}
.upstream-status-card .card-header h2 {
  color: var(--text-secondary);
}
.upstream-loading {
  color: var(--text-muted);
  font-size: 0.82rem;
  padding: 0.4rem 0;
}
.upstream-unconfigured {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0;
  color: var(--text-muted);
  font-size: 0.82rem;
}
.upstream-unconfigured a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.upstream-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.45rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.upstream-row:last-child {
  border-bottom: none;
}
.upstream-sub {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding-left: 1.1rem;
}
.upstream-main {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
}
.upstream-status-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.dot-green {
  background: var(--green);
  box-shadow: 0 0 8px rgba(102, 187, 106, 0.5);
}
.dot-red {
  background: var(--red);
  box-shadow: 0 0 8px rgba(239, 83, 80, 0.5);
}
.upstream-status-text {
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--text-primary);
}
.upstream-latency {
  font-weight: 700;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
}
/* ── 上游/端点状态：一行多个的网格卡片 ── */
.up-status-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(235px, 1fr));
  gap: 6px 10px;
  padding: 8px 0 4px;
}
.up-status-cell {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 5px 10px;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid rgba(255, 255, 255, 0.08);
  white-space: nowrap;
  overflow: hidden;
  cursor: help;
  transition: border-color 0.15s, background 0.15s;
}
.up-status-cell:hover {
  border-color: rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
}
.up-status-cell .upstream-status-dot {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
}
.up-status-name,
.ep-status-name {
  font-weight: 600;
  font-size: 0.78rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
}
.ep-status-grid {
  margin-top: 6px;
}
.up-status-flag {
  font-size: 0.7rem;
  font-weight: 700;
  flex-shrink: 0;
  color: var(--text-muted);
}
/* 状态卡片更紧凑：减小内边距，卡片内顶部一行摘要 */
#upstream-status-card .card-header {
  padding-top: 0.55rem;
}
#upstream-status-card .card-header h2 {
  font-size: 0.95rem;
}
.up-status-summary {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  font-size: 0.75rem;
  color: var(--text-muted);
  padding: 0.05rem 0 0.15rem;
  margin-bottom: 0.1rem;
  border-bottom: 1px dashed rgba(255, 255, 255, 0.07);
}
.up-status-summary b {
  color: #cfd8dc;
  font-weight: 700;
}
.up-status-summary .s-online {
  color: #81c784;
}
.up-status-summary .s-offline {
  color: #e57373;
}
.up-status-summary .s-fast {
  color: #4fc3f7;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
}
.upcfg-badge.endpoint-badge {
  background: linear-gradient(180deg, rgba(33, 150, 243, 0.28), rgba(33, 150, 243, 0.16));
  color: #90caf9;
  border: 1px solid rgba(33, 150, 243, 0.45);
}
.ep-source-badge {
  color: #90caf9;
  font-weight: 600;
}
.upstream-badge {
  display: inline-block;
  padding: 0.08rem 0.45rem;
  border-radius: 16px;
  font-size: 0.7rem;
  font-weight: 600;
}
.upstream-detail {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.3rem 0 0;
}
.upstream-field {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-size: 0.8rem;
}
.upstream-field .info-label {
  min-width: 4.5rem;
  flex-shrink: 0;
}
.upstream-field code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.76rem;
  color: #7ab8d4;
  word-break: break-all;
}
.upstream-url {
  color: #6ab4c8 !important;
}

/* ── Scrollbar ── */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-track {
  background: var(--bg-primary);
}
::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--border-light);
}

/* ── Section Title ── */
.section-title {
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* ── Responsive adjustments ── */
@media (max-width: 1200px) {
  .form-row {
    grid-template-columns: 1fr 1fr;
  }
  .form-row .full-width {
    grid-column: 1 / -1;
  }
}

/* ── Mobile Bottom Nav & Mobile Card Lists (hidden on desktop) ── */
.mobile-bottom-nav {
  display: none;
}
.keys-mobile-list {
  display: none;
}
.ranking-mobile-list {
  display: none;
}
.recent-mobile-list {
  display: none;
}

@media (max-width: 900px) {
  /* 手机端：侧边栏 → 底部固定导航栏 */
  .sidebar {
    display: none !important;
  }
  #admin-screen.active .sidebar {
    display: flex !important;
    position: fixed !important;
    bottom: 0 !important;
    left: 0 !important;
    top: auto !important;
    width: 100% !important;
    height: auto !important;
    min-height: 0 !important;
    flex-direction: row !important;
    border-right: none !important;
    border-top: 1px solid var(--border);
    z-index: 100;
    padding: 0 !important;
    overflow: visible !important;
    background: rgba(15, 24, 33, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
  .sidebar-brand {
    display: none !important;
  }
  .sidebar-nav {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    padding: 0.2rem 0.3rem !important;
    gap: 0;
    width: 100% !important;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
    justify-content: flex-start !important;
  }
  .sidebar-nav::-webkit-scrollbar {
    display: none;
  }
  /* 移动端底部导航：隐藏分组标题，直接平铺展示所有子菜单项 */
  .nav-group-head {
    display: none !important;
  }
  .nav-group {
    display: contents;
  }
  .nav-sub {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    gap: 0;
    padding: 0;
  }
  .nav-sub-item {
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.18rem 0.35rem;
    font-size: 0.5rem;
    flex: 0 0 auto;
    justify-content: center;
    text-align: center;
    border-radius: 6px;
    min-height: 44px;
    white-space: nowrap;
  }
  .nav-sub-item .nav-icon {
    font-size: 0.85rem;
    width: auto;
  }
  .nav-sub-item .nav-label {
    display: block !important;
    font-size: 0.48rem;
    line-height: 1.1;
  }
  .nav-item.logout {
    margin-top: 0;
  }

  .main-content {
    margin-left: 0 !important;
    max-width: 100vw !important;
    padding: 0.6rem;
    padding-bottom: 5.5rem !important; /* 底部导航占高约 48px + 间距 */
  }

  .stats-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.45rem;
  }
  .stat-card {
    padding: 0.7rem 0.5rem;
  }
  .stat-num {
    font-size: 1.4rem;
  }

  .form-row {
    grid-template-columns: 1fr;
  }
  .form-row .full-width {
    grid-column: 1;
  }
  .form-row .form-row-btn {
    grid-column: 1;
  }
  .create-key-form {
    grid-template-columns: 1fr;
  }
  .create-key-form .full-width {
    grid-column: 1;
  }

  .card {
    padding: 0.7rem;
    margin-bottom: 0.7rem;
  }
  .card-header h2 {
    font-size: 0.72rem;
  }

  .top-bar {
    flex-direction: column;
    gap: 0.4rem;
    align-items: flex-start;
  }
  .top-bar h2 {
    font-size: 0.95rem;
  }

  .upstream-main {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .toast {
    bottom: 5rem;
    max-width: 85vw;
    font-size: 0.8rem;
    padding: 0.6rem 1.2rem;
  }

  /* ── Tables → Card lists (for 600-900px range too) ── */
  #keys-section .keys-table {
    display: none;
  }
  #keys-section .keys-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  #ranking-section table {
    display: none;
  }
  #ranking-section .ranking-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
  }
  #recent-section table {
    display: none;
  }
  #recent-section .recent-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
  }

  .chart-container {
    gap: 0.3rem;
  }
  .chart-bar {
    width: 75%;
    max-width: 28px;
  }
  .chart-count {
    font-size: 0.6rem;
  }
  .chart-label {
    font-size: 0.55rem;
  }

  .login-card {
    width: 92vw;
    padding: 2rem 1.5rem;
  }

  .modal-content {
    max-width: 96vw !important;
    padding: 1rem;
    margin-top: 1vh;
    border-radius: 10px;
  }
  .detail-grid {
    grid-template-columns: 1fr;
  }
  .token-summary-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .code-content {
    font-size: 0.68rem;
    padding: 0.4rem 0.6rem;
  }

  .form-group label {
    font-size: 0.72rem;
  }
  input,
  select {
    font-size: 0.8rem;
    padding: 0.45rem 0.6rem;
  }
  .input-unit-group .unit-select {
    padding: 0.45rem 0.25rem;
    font-size: 0.7rem;
    min-width: 62px;
  }

  .btn {
    font-size: 0.8rem;
    padding: 0.4rem 0.8rem;
  }

  #detail-logs-filter {
    width: 100%;
  }
  .section-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .card-header {
    flex-wrap: wrap;
    gap: 0.3rem;
  }
}

@media (max-width: 550px) {
  .sidebar-nav {
    display: grid !important;
    grid-template-columns: repeat(4, 1fr);
    padding: 0.25rem 0.15rem;
    gap: 0.1rem;
    overflow-x: visible !important;
  }
  .nav-sub-item {
    flex: none !important;
    padding: 0.18rem 0.08rem;
    font-size: 0.5rem;
    min-height: 34px;
    gap: 0.05rem;
    width: 100%;
  }
  .nav-sub-item .nav-icon {
    font-size: 0.9rem;
  }
  .nav-sub-item .nav-label {
    font-size: 0.48rem;
    line-height: 1.2;
  }
  /* 8 个项在 4 列 grid 中变为 2 行（4+4），导航约 70-80px */
  .main-content {
    margin-left: 0 !important;
    max-width: 100vw !important;
    padding-bottom: 6rem !important;
  }
}

/* ── Extra small: even tighter ── */
@media (max-width: 400px) {
  .sidebar-nav {
    display: grid !important;
    grid-template-columns: repeat(4, 1fr);
    padding: 0.15rem 0.1rem;
    gap: 0.06rem;
  }
  .nav-sub-item {
    flex: none !important;
    padding: 0.12rem 0.05rem;
    font-size: 0.42rem;
    min-height: 28px;
    gap: 0.03rem;
  }
  .nav-sub-item .nav-icon {
    font-size: 0.72rem;
  }
  .nav-sub-item .nav-label {
    font-size: 0.4rem;
    line-height: 1.1;
  }
  .main-content {
    padding-bottom: 5.5rem !important;
  }
}

@media (max-width: 480px) {
  .main-content {
    padding: 0.4rem;
    padding-bottom: 4.5rem !important;
  }
  .card {
    padding: 0.5rem;
    border-radius: 8px;
  }
  .stat-num {
    font-size: 1.1rem;
  }
  .stat-label {
    font-size: 0.6rem;
  }
  .stats-grid {
    grid-template-columns: 1fr 1fr;
    gap: 0.3rem;
  }
  .stat-card {
    padding: 0.5rem 0.3rem;
  }

  .nav-sub-item .nav-icon {
    font-size: 0.85rem;
  }

  .login-card {
    padding: 1.5rem 1rem;
  }
  .login-card .logo {
    font-size: 2.2rem;
  }
  .login-card h1 {
    font-size: 1.2rem;
  }

  .modal-content {
    padding: 0.8rem;
  }
  .modal-content h2 {
    font-size: 0.95rem;
  }

  .detail-grid {
    gap: 0.5rem;
  }
  .info-row {
    font-size: 0.75rem;
    flex-wrap: wrap;
  }
  .info-label {
    min-width: 4rem;
    font-size: 0.72rem;
  }

  .code-content {
    font-size: 0.62rem;
    padding: 0.3rem 0.5rem;
  }
  .code-block-header {
    font-size: 0.65rem;
    padding: 0.25rem 0.5rem;
  }

  .chart-bar {
    max-width: 20px;
  }
  .chart-bar-wrap {
    gap: 0.1rem;
  }

  .stat-value {
    font-size: 1.1rem !important;
  }
}

/* ── Updated Keys Table ── */

/* Status dot column */
.sts-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  vertical-align: middle;
}
.sts-active {
  background: var(--green);
  box-shadow: 0 0 6px rgba(102, 187, 106, 0.5);
}
.sts-revoked {
  background: var(--red);
  box-shadow: 0 0 6px rgba(239, 83, 80, 0.4);
}
.sts-expired {
  background: #5a5a5a;
  box-shadow: 0 0 4px rgba(90, 90, 90, 0.3);
}
.sts-expiring {
  background: var(--orange);
  box-shadow: 0 0 6px rgba(255, 152, 0, 0.4);
  animation: sts-pulse 1.8s ease-in-out infinite;
}
@keyframes sts-pulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.6;
    transform: scale(1.2);
  }
}

/* Model tag */
.model-tag {
  display: inline-block;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 0.74rem;
  color: var(--accent);
  background: rgba(79, 195, 247, 0.07);
  padding: 0.08rem 0.4rem;
  border-radius: 3px;
  white-space: nowrap;
}

/* 绑定的上游标签 */
.key-upstream-tag {
  display: inline-block;
  font-size: 0.72rem;
  color: #81c784;
  background: rgba(129, 199, 132, 0.1);
  padding: 0.08rem 0.4rem;
  border-radius: 3px;
  white-space: nowrap;
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

/* API Keys 列表：上游API 内联下拉列 */
.upstream-cell {
  vertical-align: middle;
}
.upstream-inline-select {
  width: 100%;
  max-width: 118px;
  font-size: 0.72rem;
  padding: 0.2rem 0.3rem;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 5px;
  background: var(--bg-2, #1e2530);
  color: #d8e1ec;
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.upstream-inline-select:hover:not(:disabled) {
  border-color: var(--accent, #4fc3f7);
}
.upstream-inline-select:disabled {
  opacity: 0.55;
  cursor: wait;
}
.upstream-inline-select option {
  color: #d8e1ec;
  background: #1e2530;
}

/* API Keys 列表（表格形态）：「优选上游 / 特级上游」两列的下拉按最长选项自适应宽度，
   完整显示上游名，不再被基类的 max-width 裁掉。
   原理：原生 <select> 在 `width: auto` 时，固有宽度由**最宽的 option** 决定，
   因此覆盖掉基类的 `width: 100%` + `max-width: 118px` 即可显示全部内容
   （<select> 的选中项超出是硬裁切，连省略号都没有，只能靠放开宽度解决）。
   ⚠️ 作用域必须限定到 #keys-table-wrap，不能直接改基类 `.upstream-inline-select`：
   同一个类也被手机端卡片（.km-card .km-row-ctl）复用，那里需要的是
   `width: 100%`（见下方 @media 段），二者不能混。
   ≤900px 时表格 `display: none`，本条自动失效，卡片规则照旧 —— 互不干扰。
   表格变宽的代价由 #keys-table-wrap 的横向滚动承接：
   `.keys-table` 的 min-width 只是**下限**，auto 布局会按内容继续撑宽。 */
#keys-table-wrap .upstream-inline-select {
  width: auto;
  max-width: none;
}

/* API Keys 列表：特级快路径开关（v3.3.54 起 Key 侧只有「开不开」一位，
   原来的 .premium-timeout-inline 内联数字输入已随之移除 —— 特级超时改在
   「上游管理 → 特级上游」按条目配置）。
   只需把系统配置页那套 .switch 在表格窄格里缩小一档并居中。 */
#keys-table-wrap .upstream-cell .switch {
  width: 40px;
  height: 22px;
  vertical-align: middle;
}
#keys-table-wrap .upstream-cell .switch .slider {
  border-radius: 22px;
}
#keys-table-wrap .upstream-cell .switch .slider::before {
  height: 15px;
  width: 15px;
}
#keys-table-wrap .upstream-cell .switch input:checked + .slider::before {
  transform: translateX(18px);
}

/* Mini quota bar */
.ql-mini-wrap {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  max-width: 160px;
  width: 100%;
}
.ql-mini-bar {
  flex: 1;
  height: 5px;
  background: var(--bg-input);
  border-radius: 3px;
  overflow: hidden;
  min-width: 40px;
}
.ql-mini-bar .quota-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.4s ease;
}
.ql-mini-bar .quota-fill.warning {
  background: linear-gradient(90deg, var(--orange), #fb8c00);
}
.ql-mini-bar .quota-fill.danger {
  background: linear-gradient(90deg, var(--red), #e53935);
}

.ql-mini-pct {
  font-size: 0.7rem;
  color: var(--text-secondary);
  font-weight: 600;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.ql-indicator.unlimited {
  color: var(--text-muted);
  font-size: 0.76rem;
}

.muted-xs {
  display: block;
  color: var(--text-muted);
  font-size: 0.68rem;
  margin-top: 0.15rem;
}

/* Action group */
.action-group {
  display: inline-flex;
  gap: 1px;
  align-items: center;
}
.action-group .btn-ghost {
  padding: 0.15rem 0.25rem;
  font-size: 0.85rem;
  line-height: 1;
}

/* Key row hover */
.key-row td {
  vertical-align: middle;
  padding-top: 0.55rem;
  padding-bottom: 0.55rem;
}

/* Expiry never */
.expiry-never {
  color: var(--text-muted);
  font-size: 0.76rem;
}

/* ── Name + Status merged (横排：状态点 + 名称 + badge) ── */
.ns-wrap {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}
.ns-wrap .key-name {
  font-size: 0.84rem;
  font-weight: 600;
}

/* ── Key + Model inline ── */
.key-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.key-wrap .key-display {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.key-wrap .key-model {
  display: inline-block;
}
.key-wrap .key-model .model-tag {
  font-size: 0.7rem;
  padding: 0.04rem 0.32rem;
}

/* ── Wrap cell for expiry+concurrency ── */
.wrap-cell {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.ee-row {
  font-size: 0.8rem;
  color: var(--text-secondary);
}

/* ── Last used inline ── */
.last-used {
  font-size: 0.8rem;
  color: var(--text-secondary);
}

/* ── Keys table tighter padding ── */
.keys-table th,
.keys-table td {
  padding: 0.45rem 0.5rem;
  text-align: center;
}
.keys-table td.num-cell {
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}
.keys-table th {
  font-size: 0.68rem;
  white-space: nowrap;
  text-align: center;
}
.keys-table th.sortable {
  cursor: pointer;
  user-select: none;
}
.keys-table th.sortable:hover {
  color: var(--accent, #4fc3f7);
}
.keys-table th .sort-arrow {
  font-size: 0.6rem;
  margin-left: 2px;
  opacity: 0.8;
}

/* ── Keys table: 列宽按内容动态分配（table-layout auto），长文本列保底截断 ── */
.keys-table {
  table-layout: auto;
  width: 100%;
}
.keys-table td:first-child,
.keys-table th:first-child {
  text-align: center;
}

/* Prevent content from pushing column widths */
.keys-table td {
  overflow: hidden;
  text-overflow: ellipsis;
}
.keys-table td.num-cell {
  overflow: visible;
}
.keys-table .key-display {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 长文本列（Key / 名称）保底 max-width，避免 auto 布局下撑破表格 */
.keys-table td:has(.key-wrap),
.keys-table td:has(.ns-wrap) {
  max-width: 220px;
  white-space: nowrap;
}

/* ── API Keys 表格：列多，窄屏改为横向滚动，而不是把各列挤扁 ── */
#keys-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#keys-table-wrap .keys-table {
  min-width: 1240px;
}

/* ══ API Keys 列表：逐列宽度合理化 ══
   三条准则：
     ① 不显示不全 —— 不留 max-width 上限、不出省略号；
     ② 不折叠     —— 单元格内容一律不换行（含 flex 容器内部换行）；
     ③ 不浪费     —— 不写死像素宽度，列宽全部交给 table-layout:auto 按内容自适应。
   表宽超出容器时由 #keys-table-wrap 的横向滚动承接
   （上面 .keys-table 的 min-width 只是**下限**，auto 布局会按内容继续撑宽）。
   ⚠️ 前缀统一用 #keys-table-wrap 而不用 .keys-table：后者还被套餐页的
   `.plan-table` 复用（见上文注释），且 ≤900px 时本表格 display:none，
   这些规则会自动失效、不会碰到手机端卡片。 */

/* ① 名称 / Key 两列：撤掉 220px 上限。
   原规则 `.keys-table td:has(.ns-wrap/.key-wrap){max-width:220px}` 会让超长
   名称/模型名直接被省略号吃掉（这两列还没有 title 兜底，等于看不到）。 */
#keys-table-wrap .keys-table td:has(.ns-wrap),
#keys-table-wrap .keys-table td:has(.key-wrap) {
  max-width: none;
}

/* ① 单元格不再裁剪。原先 `.keys-table td{overflow:hidden;text-overflow:ellipsis}`
   是无差别裁剪，长文本一律切掉；改由 auto 布局按内容撑开列宽。 */
#keys-table-wrap .keys-table td {
  overflow: visible;
  text-overflow: clip;
}

/* ② 名称 + 状态徽章保持一行。`.ns-wrap` 原为 flex-wrap:wrap，列宽紧时会把
   徽章挤到第二行，行高参差且像"两条数据"。 */
#keys-table-wrap .keys-table .ns-wrap {
  flex-wrap: nowrap;
}

/* ② 数值类内容不折行：「0 / 不限」「∞ 不限」「3,000/3,000」中间都带空格，
   窄列会被折成两行 —— 这正是要消除的"折叠显示"。 */
#keys-table-wrap .keys-table .ql-indicator,
#keys-table-wrap .keys-table .ql-mini-pct,
#keys-table-wrap .keys-table .conc-live {
  white-space: nowrap;
}

/* ③ 「调用次数 / Token 配额」列：撤掉 160px 上限，列宽改由下方那行数字决定。
   （该列的 .ql-mini-wrap 是 width:100%，百分比在列宽计算中等价于 auto、
   不参与撑宽，所以宽度完全由数字行决定 —— 既不截断也不空占。） */
#keys-table-wrap .keys-table .ql-mini-wrap {
  max-width: none;
}

/* ③ 特级快路径开关所在的「特级」列：只放一个 40px 的开关，不参与撑宽，
   也不需要额外的 max-width 覆盖（上一版的 .premium-timeout-inline 规则已随
   「Key 侧不再配特级超时」一并移除，见上方 2859 起的注释）。 */

/* ══ 各页表格横向滚动（方案B：逐表专属作用域，互不干扰）════
   机制与上面的 API Keys 完全一致，两个条件缺一不可：
     ① 容器 `overflow-x: auto` —— 用 id / 专属 class 覆盖全局
        `.table-wrap { overflow-x: hidden }`（id 优先级 100 > class 10，故能覆盖）；
     ② 表格自身 `min-width` 把宽度撑出去 —— 否则 `table { width: 100% }`
        会自适应收缩，根本不产生溢出，也就没有滚动条。
   ⚠️ 禁止直接改全局 `.table-wrap` / `.keys-table`：`.keys-table` 还被
      套餐管理页复用（.plan-table / .group-table 就是它），全局改会串页。
   ⚠️ 手机端已改用卡片列表的页面（keys / calls-recent / errorlog），
      其表格在对应断点 `display:none`，下面这些横滚规则只服务
      「>断点 但窗口仍不够宽」的桌面/平板区间；loginstats / plans 例外，
      见各自处的 card 断点规则。 */

/* ── Apikeys 调用记录（15 列，全站最宽）── */
#recent-calls-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#recent-calls-wrap #recent-calls-table {
  min-width: 1440px;
}

/* ── 报错日志页 4 个 Tab（最终报错 13 列 / 降级重绑 11 列 / 重试 13 列 / 切换 11 列）── */
#errlogs-table-wrap,
#rblogs-table-wrap,
#retrylogs-table-wrap,
#falogs-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#errlogs-table-wrap #err-logs-table {
  min-width: 1420px;
}
#rblogs-table-wrap #rb-logs-table {
  min-width: 1180px;
}
#retrylogs-table-wrap #retry-logs-table {
  min-width: 1340px;
}
#falogs-table-wrap #fa-logs-table {
  min-width: 1180px;
}

/* ── 统计页：模型响应时间（9~10 列，与下面两张表同样横向滚动）──
   ⚠️ 全局 `.table-wrap { overflow-x: hidden }`，所以每个"宽表"都必须用 id 覆盖成 auto，
   否则容器既不滚动、也不提示，列会被硬裁掉。这里给 #latency-table-wrap 补上，
   与 #upstream-stats-wrap / #server-stats-wrap 同一套机制。 */
#latency-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#latency-table-wrap #latency-table {
  min-width: 1120px;
}

/* ── 统计页：按上游 API / 按服务器 IP（各 10 列）── */
#upstream-stats-wrap,
#server-stats-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#upstream-stats-wrap #upstream-stats-table,
#server-stats-wrap #server-stats-table {
  min-width: 1120px;
}

/* ── 套餐管理页 · 套餐列表（9 列）──
   每个分组渲染一张表，会有多张同名表，故只能用 class 不能用 id。
   ⚠️ 这里必须写 `div.plan-table-wrap`（0,1,1）而不是裸 `.plan-table-wrap`（0,1,0）：
   后者与全局 `.table-wrap`（0,1,0）优先级**完全相同**，只能靠「本规则写在文件更后面」
   侥幸胜出 —— 一旦 `.table-wrap` 被挪到后面就会静默失效。加元素选择器前缀把特异性
   抬高一档，与规则顺序解耦。请勿「清理」掉这个 div 前缀。
   同理，该表沿用 `.keys-table` 只为复用单元格样式，下面用双类选择器（0,2,0）
   压过全局 `.keys-table`（0,1,0），与之解耦。 */
div.plan-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.plan-table-wrap .plan-table {
  min-width: 1080px;
}
/* ≤600px 时全局有 `.keys-table { display: none }`（那本是给 API Keys 页
   切卡片用的，会被套餐表误伤：表格消失且没有卡片替代 = 空白页）。
   这里显式恢复显示，避免套餐在手机上整块消失。 */
@media (max-width: 600px) {
  .plan-table-wrap .plan-table,
  .group-table-wrap .group-table {
    display: table;
  }
}

/* ── 分组管理弹窗（4 列；modal 仅 560px 宽，手机上为 100vw）──
   与上面同理，用 `div.` 前缀抬高特异性，不依赖规则书写顺序。 */
div.group-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.group-table-wrap .group-table {
  min-width: 460px;
}

/* ── Key 详情弹窗 · 调用记录（13 列）──
   ≤900px 时 modal 铺满屏幕，沿用既有的 `.pg-keys #detail-logs-table{min-width:720px}`
   （style.css 内 @media(max-width:900px) 段，优先级 110 > 100，自动覆盖下面的 1080px）。 */
#detail-logs-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#detail-logs-wrap #detail-logs-table {
  min-width: 1180px;
}

/* ── 登录记录页（4 列，但 User-Agent 极长）──
   该页原先只有 `#lst-mobile-list` 的 DOM 与填数据逻辑、却没有配套 CSS，
   导致 `.recent-mobile-list{display:none}` 让它永不显示、表格也没有
   `display:none`，手机端是「表格被裁切」的中间态。此处一并补齐：
   ≤900px 走卡片（与其它日志页同断点），>900px 走表格 + 横滚。 */
#lst-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#lst-table-wrap #lst-table {
  min-width: 760px;
}
@media (max-width: 900px) {
  #lst-table-wrap #lst-table {
    display: none;
  }
  #lst-table-wrap .recent-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
}

/* ── 系统配置页 · 限速/冷却 Key 列表（7 列）──
   容器 #keyrate-live-list 已有内联 `overflow: auto`（含横滚，只是缺 min-width
   撑不开），故只需补宽度。 */
#keyrate-live-list .rate-limits-table {
  min-width: 760px;
}

/* ── 系统配置页 · 进程内存键值表（2 列）──
   该表是「标签 + 值」两列，不存在多列被挤扁的问题，值本应换行自适应，
   故只做溢出兜底、刻意不设 min-width（设了反而制造无谓的横向滚动条）。 */
#mem-detail {
  overflow-x: auto;
}

/* ── 「调用次数 / Token 配额」两列：进度条在上、数字在下（两排）──
   原先「条 + 数字」并排，单列要吃掉 ~145px；改两排后宽度收到数字本身的宽度，
   省下的横向空间让给 Key / 名称等长文本列。
   仅作用于本页（body.pg-keys）的表格：>900px 才显示表格，
   手机端（≤900px）用的是卡片列表，卡片内的配额条仍是「条 + 数字」一行满宽。 */
.pg-keys .keys-table .ql-mini-wrap {
  flex-direction: column;
  align-items: stretch;
  gap: 0.2rem;
  /* 百分比宽度在列宽计算时等价于 auto（不参与撑宽），列宽仍由下面那行数字决定；
     定型后铺满单元格，于是同一列里每一行的进度条等宽。 */
  width: 100%;
}
.pg-keys .keys-table .ql-mini-wrap .ql-mini-bar {
  flex: none;
  width: 100%;
}
.pg-keys .keys-table .ql-mini-wrap .ql-mini-pct {
  text-align: center;
}

/* ── Action group positioning ── */
.keys-table .action-cell .action-group {
  display: inline-flex;
  gap: 0;
  align-items: center;
  flex-wrap: nowrap;
}
.keys-table .action-cell .action-group .btn-ghost {
  padding: 0.1rem 0.2rem;
  font-size: 0.82rem;
}

/* ── 清空并发按钮：醒目的橙色边框 + 轻背景 — 在表格 / 卡片上都更显眼 ── */
.btn-clear-conc {
  border: 1px solid rgba(255, 87, 34, 0.35) !important;
  border-radius: 4px !important;
  background: rgba(255, 87, 34, 0.05);
  transition:
    background 0.12s,
    border-color 0.12s;
}
.btn-clear-conc:hover {
  background: rgba(255, 87, 34, 0.18) !important;
  border-color: rgba(255, 87, 34, 0.7) !important;
}
.btn-clear-conc:active {
  background: rgba(255, 87, 34, 0.28) !important;
}
.btn-clear-conc:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── Smooth scroll ── */
html {
  scroll-behavior: smooth;
}

/* ── Mobile card list for keys (≤600px) ── */
@media (max-width: 600px) {
  .km-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    transition: border-color 0.12s;
    position: relative;
  }
  .km-card:active {
    border-color: var(--border-light);
  }
  .km-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
  }
  .km-card-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 600;
    font-size: 0.82rem;
    min-width: 0;
    flex: 1;
  }
  .km-card-title .key-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .km-card-body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
  }
  .km-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.74rem;
    color: var(--text-secondary);
    gap: 0.4rem;
  }
  .km-row .km-label {
    color: var(--text-muted);
    flex-shrink: 0;
  }
  .km-row .km-value {
    text-align: right;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }
  .km-key-code {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
    font-size: 0.68rem;
    color: #7ab8d4;
    background: var(--bg-input);
    padding: 0.08rem 0.35rem;
    border-radius: 3px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
  }
  .km-model-tag {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
    font-size: 0.62rem;
    color: var(--accent);
    background: rgba(79, 195, 247, 0.07);
    padding: 0.04rem 0.3rem;
    border-radius: 3px;
  }
  .km-card-actions {
    display: flex;
    gap: 0.15rem;
    align-items: center;
    flex-shrink: 0;
    overflow-x: auto;
    overflow-y: hidden;
    max-width: 60vw;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .km-card-actions::-webkit-scrollbar {
    display: none;
  }
  .km-card-actions .btn-ghost {
    padding: 0.1rem 0.18rem;
    font-size: 0.75rem;
    flex-shrink: 0;
  }
  .km-quota {
    display: flex;
    align-items: center;
    gap: 0.4rem;
  }
  .km-quota .ql-mini-wrap {
    max-width: 120px;
  }
  .km-quota .ql-mini-pct {
    font-size: 0.62rem;
  }

  /* Ranking mobile card */
  .rm-card {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.5rem 0.6rem;
  }
  .rm-rank {
    font-weight: 700;
    color: var(--accent);
    width: 1.2rem;
    text-align: center;
    flex-shrink: 0;
    font-size: 0.75rem;
  }
  .rm-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
  }
  .rm-body .km-row {
    font-size: 0.7rem;
  }
  .rm-name {
    font-weight: 500;
    font-size: 0.82rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Recent calls mobile card */
  .rc-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.5rem 0.6rem;
  }
  .rc-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.7rem;
    color: var(--text-muted);
    margin-bottom: 0.3rem;
  }
  .rc-header .rc-time {
    color: var(--text-muted);
  }
  .rc-body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
  }
  .rc-body .km-row {
    font-size: 0.7rem;
  }
  .rc-content {
    font-size: 0.67rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
    padding: 0.1rem 0;
  }
  .rc-content:hover {
    color: var(--accent);
  }
}

/* ── ===== MOBILE ENHANCEMENTS ===== ── */

/* Better login screen on mobile */
@media (max-width: 768px) {
  #login-screen {
    padding: 1rem;
  }
  .login-card {
    width: 100%;
    max-width: 400px;
    padding: 2rem 1.5rem;
  }
}

@media (max-width: 480px) {
  .login-card {
    padding: 1.5rem 1rem;
    border-radius: 16px;
  }
  .login-card .logo {
    font-size: 2.2rem;
  }
  .login-card h1 {
    font-size: 1.3rem;
  }
  .login-card .subtitle {
    font-size: 0.82rem;
    margin-bottom: 1.2rem;
  }
  .login-card input[type='password'] {
    padding: 0.65rem 0.8rem;
    font-size: 16px; /* prevent iOS zoom */
  }
}

/* Modal full-screen on small devices */
@media (max-width: 600px) {
  .modal-overlay {
    padding: 0;
    align-items: flex-end;
  }
  .modal-content {
    margin-top: auto;
    max-width: 100vw !important;
    border-radius: 16px 16px 0 0;
    max-height: 90vh;
    overflow-y: auto;
    padding: 1.2rem 1rem 1.5rem;
    animation: modalSlideUp 0.25s ease;
  }
  @keyframes modalSlideUp {
    from {
      transform: translateY(100%);
      opacity: 0;
    }
    to {
      transform: translateY(0);
      opacity: 1;
    }
  }
  #edit-modal .modal-content {
    max-width: 100vw !important;
    border-radius: 16px 16px 0 0;
  }
}

/* Better detail modal on mobile */
@media (max-width: 600px) {
  .detail-grid {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }
  .info-row {
    flex-wrap: wrap;
    gap: 0.3rem;
    padding: 0.35rem 0;
    font-size: 0.8rem;
  }
  .info-label {
    min-width: 4rem;
    font-size: 0.75rem;
  }
  .info-value {
    font-size: 0.8rem;
  }
  .token-summary-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.4rem;
  }
  .token-summary-grid .stat-value {
    font-size: 1.15rem !important;
  }
  .section-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.3rem;
  }
  /* Key 详情重排版：窄屏统一落成单列（或 2×2），避免数值被挤到换行 */
  .kd-hero {
    padding: 0.8rem 0.85rem 0.75rem;
  }
  .kd-facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .kd-hero-id {
    display: none;
  }
  .kd-quotas {
    grid-template-columns: 1fr;
  }
  .kd-limits {
    grid-template-columns: 1fr;
  }
  .kd-figs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .kd-fig:nth-child(3) {
    border-left: none;
  }
  .kd-fig:nth-child(n + 3) {
    border-top: 1px solid rgba(30, 45, 58, 0.75);
  }
  .kd-code-pair {
    grid-template-columns: 1fr;
  }
  .kd-key {
    font-size: 0.72rem;
  }
  /* 提高一级特异性：压过本文件后面 .detail-section 的移动端 padding/margin */
  .detail-section.kd-panel {
    padding: 0.7rem 0.78rem 0.75rem;
    margin-bottom: 0.6rem;
  }
  /* 代码块标题保持一行：标题左、复制右（旧的移动端规则会改成上下两行） */
  .kd-panel .code-block-header {
    flex-direction: row;
    align-items: center;
  }
  .logs-filter-wrap {
    width: 100%;
  }
  .logs-filter-wrap .input-sm {
    width: 100%;
  }
  .code-block-header {
    flex-direction: column;
    gap: 0.3rem;
    align-items: flex-start;
  }
  .table-sm {
    font-size: 0.68rem;
  }
  .table-sm td,
  .table-sm th {
    padding: 0.25rem 0.35rem;
    font-size: 0.65rem;
  }
  .table-sm td:first-child {
    white-space: nowrap;
  }
}

/* Content preview modal on mobile */
@media (max-width: 600px) {
  #content-modal .modal-content {
    max-height: 85vh;
  }
  #content-modal .modal-content > div:first-of-type {
    max-height: 55vh !important;
    font-size: 0.75rem !important;
  }
}

/* Upstream status better mobile wrapping */
@media (max-width: 600px) {
  .upstream-main {
    flex-wrap: wrap;
    gap: 0.4rem;
  }
  .upstream-status-text {
    font-size: 0.85rem;
  }
  .upstream-latency {
    font-size: 0.78rem;
  }
  .upstream-badge {
    font-size: 0.65rem;
  }
  .upstream-field {
    flex-wrap: wrap;
    font-size: 0.75rem;
  }
  .upstream-field .info-label {
    min-width: 3.5rem;
  }
}

/* Card hover/active feedback for touch devices */
@media (max-width: 768px) {
  .stat-card:active,
  .km-card:active,
  .rm-card:active,
  .rc-card:active {
    transform: scale(0.98);
    transition: transform 0.08s;
  }
  .card:active {
    border-color: var(--border-light);
  }
}

/* Prevent text size auto-adjust on orientation change */
html {
  -webkit-text-size-adjust: 100%;
}

/* Better input touch targets on mobile */
@media (max-width: 600px) {
  input,
  select,
  .btn {
    font-size: 16px; /* prevent iOS zoom on focus */
  }
  .btn {
    min-height: 38px;
  }
  .btn-sm {
    min-height: 32px;
  }
  .nav-sub-item {
    min-height: 44px; /* Apple HIG minimum */
  }
}

/* Extra small: iPhone SE / 5.8" and below */
@media (max-width: 375px) {
  .main-content {
    padding: 0.3rem;
    padding-bottom: 5rem !important;
  }
  .card {
    padding: 0.4rem;
    margin-bottom: 0.45rem;
  }
  .stat-num {
    font-size: 0.95rem;
  }
  .stat-label {
    font-size: 0.5rem;
  }
  .stats-grid {
    gap: 0.2rem;
  }
  .stat-card {
    padding: 0.35rem 0.2rem;
  }
  .nav-sub-item {
    padding: 0.15rem 0.08rem;
    font-size: 0.45rem;
    min-height: 40px;
  }
  .nav-sub-item .nav-icon {
    font-size: 0.75rem;
  }
  .nav-sub-item .nav-label {
    font-size: 0.42rem;
  }

  .km-card {
    padding: 0.35rem;
  }
  .km-card-title {
    font-size: 0.7rem;
  }
  .km-row {
    font-size: 0.62rem;
  }
  .km-key-code {
    font-size: 0.58rem;
  }
  .km-card-actions .btn-ghost {
    font-size: 0.72rem;
    padding: 0.1rem 0.15rem;
  }

  .rm-card {
    padding: 0.35rem;
  }
  .rm-name {
    font-size: 0.7rem;
  }

  .rc-card {
    padding: 0.35rem;
  }
  .rc-header {
    font-size: 0.6rem;
  }

  .chart-bar {
    max-width: 16px;
  }

  .modal-content {
    padding: 0.8rem 0.6rem;
  }
  .modal-content h2 {
    font-size: 0.85rem;
  }

  .login-card {
    padding: 1.2rem 0.8rem;
  }
  .login-card .logo {
    font-size: 1.8rem;
  }
  .login-card h1 {
    font-size: 1.1rem;
  }

  .form-group label {
    font-size: 0.65rem;
  }
  input,
  select {
    font-size: 14px;
    padding: 0.35rem 0.45rem;
  }
  .input-unit-group .unit-select {
    min-width: 50px;
    font-size: 0.6rem;
  }
  .btn {
    font-size: 0.72rem;
    min-height: 34px;
  }
  .card-header h2 {
    font-size: 0.65rem;
  }
  .top-bar h2 {
    font-size: 0.85rem;
  }

  .upstream-status-text {
    font-size: 0.78rem;
  }
  .upstream-latency {
    font-size: 0.7rem;
  }
  .upstream-badge {
    font-size: 0.6rem;
  }
  .upstream-main {
    gap: 0.3rem;
  }

  .code-content {
    font-size: 0.55rem;
    padding: 0.2rem 0.35rem;
  }
}

/* ── Pagination (inspired by Ant Design / Element UI) ── */
.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  padding: 12px 0 4px;
  flex-wrap: nowrap;
}
.pagination .page-size-select {
  background: var(--bg-card);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 3px 2px;
  font-size: 0.76rem;
  cursor: pointer;
  outline: none;
  width: 40px;
  text-align: center;
  text-align-last: center;
  flex-shrink: 0;
}
.pagination .page-size-select:hover {
  border-color: var(--border-light);
  color: var(--text-primary);
}
.page-btn-group {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}
.page-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  background: transparent;
  color: #b0bec5;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.8rem;
  cursor: pointer;
  transition: all 0.15s;
  text-align: center;
  line-height: 1;
}
.page-btn:hover:not(:disabled) {
  background: rgba(79, 195, 247, 0.08);
  border-color: var(--accent);
  color: var(--accent);
}
.page-btn:disabled {
  opacity: 0.25;
  cursor: not-allowed;
  border-color: var(--border);
}
.page-btn.active {
  background: var(--accent);
  color: #0a1628;
  border-color: var(--accent);
  font-weight: 700;
}
.page-btn.active:hover {
  background: #6ccdf9;
}
.page-ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  color: #607d8b;
  font-size: 0.8rem;
  letter-spacing: 1px;
  user-select: none;
}

/* ── Mobile pagination ── */
@media (max-width: 700px) {
  .pagination {
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    padding: 10px 0 4px;
  }
  .page-btn-group {
    flex-wrap: wrap;
    justify-content: center;
  }
  .page-btn {
    min-width: 28px;
    height: 28px;
    padding: 0 6px;
    font-size: 0.75rem;
    border-radius: 5px;
  }
  .page-ellipsis {
    min-width: 18px;
    font-size: 0.75rem;
  }
}

/* ── Quick Create Buttons ── */
.btn-quick {
  background: linear-gradient(135deg, #1a2332, #1e2a3d);
  border: 1px solid #2a3a55;
  color: #e0e6ed;
  padding: 0.6rem 1.2rem;
  font-size: 0.88rem;
  font-weight: 500;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s;
  flex: 1 1 auto;
  white-space: nowrap;
  text-align: center;
}
.btn-quick:hover {
  border-color: #4fc3f7;
  background: linear-gradient(135deg, #1e2d45, #243650);
  box-shadow: 0 2px 12px rgba(79, 195, 247, 0.15);
  transform: translateY(-1px);
  color: #fff;
}
.btn-quick:active {
  transform: translateY(0);
}
.btn-quick-green {
  border-color: #2a5540;
  background: linear-gradient(135deg, #14281e, #1a3328);
}
.btn-quick-green:hover {
  border-color: #66bb6a;
  background: linear-gradient(135deg, #1a3328, #204030);
  box-shadow: 0 2px 12px rgba(102, 187, 106, 0.15);
}
.quick-btn-group {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  grid-column: 1 / -1;
  width: 100%;
}

/* ── 快捷创建弹窗（Apikeys 管理，桌面优先） ──
   宽度随视口铺开到 1200px（覆盖基础 .modal-content 的 1100px 上限），
   套餐按钮按 ~200px 等宽平铺：宽屏 4-5 列，中屏 3 列，≤600px 单列；
   名称过长省略显示，全称由按钮 title 提供。 */
#quick-create-modal .modal-content {
  width: min(1200px, 94vw);
  max-width: none;
  padding: 1.4rem 1.7rem 1.5rem;
}
#quick-create-modal h2 {
  margin-bottom: 0.3rem;
}
#quick-create-modal .qc-sub {
  margin: 0 0 1.1rem;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--text-muted);
}
#quick-create-modal .quick-btn-group {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.7rem;
  max-height: 60vh;
  overflow-y: auto;
  padding-right: 0.15rem;
}
/* 分组（分类）标题：占满整行，名称 + 数量 + 分隔线 */
#quick-create-modal .qc-group-head {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.45rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
}
#quick-create-modal .qc-group-head:first-child {
  margin-top: 0;
}
#quick-create-modal .qc-group-head::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}
#quick-create-modal .qc-group-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
#quick-create-modal .qc-group-num {
  flex: none;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  font-size: 0.7rem;
  font-weight: 500;
  color: var(--text-muted);
}
#quick-create-modal .quick-btn-group .btn-quick {
  width: 100%;
  min-width: 0;
  flex: initial;
  padding: 0.8rem 1rem;
  font-size: 0.86rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
#quick-create-modal .qc-empty {
  grid-column: 1 / -1;
  padding: 1.4rem 0;
  text-align: center;
  font-size: 0.82rem;
}
@media (max-width: 600px) {
  #quick-create-modal .modal-content {
    width: 100%;
    padding: 1.1rem 1rem 1.3rem;
  }
  #quick-create-modal .quick-btn-group {
    grid-template-columns: 1fr;
    max-height: none;
  }
}

/* ── Key 行操作弹窗（Apikeys 管理）：每行只留一个入口按钮，具体操作收进这里 ── */
#key-actions-modal .modal-content {
  width: min(660px, 94vw);
  max-width: none;
  padding: 1.3rem 1.5rem 1.4rem;
}
#key-actions-modal h2 {
  margin-bottom: 0.3rem;
}
#key-actions-modal .ka-sub {
  margin: 0 0 1rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-muted);
  word-break: break-all;
}
#key-actions-modal .ka-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 0.5rem;
}
#key-actions-modal .ka-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-width: 0;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
  color: var(--text-primary);
  font-size: 0.82rem;
  text-align: left;
  cursor: pointer;
  transition:
    border-color 0.15s,
    background 0.15s;
}
#key-actions-modal .ka-item:hover {
  border-color: var(--accent);
  background: rgba(79, 195, 247, 0.1);
}
#key-actions-modal .ka-ico {
  flex: none;
  font-size: 1rem;
}
#key-actions-modal .ka-text {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  min-width: 0;
}
#key-actions-modal .ka-label {
  font-weight: 500;
}
#key-actions-modal .ka-hint {
  overflow: hidden;
  font-size: 0.7rem;
  color: var(--text-muted);
  white-space: nowrap;
  text-overflow: ellipsis;
}
#key-actions-modal .ka-item.ka-danger:hover {
  border-color: #ff6b6b;
  background: rgba(255, 107, 107, 0.12);
}
#key-actions-modal .ka-item.ka-danger .ka-label {
  color: #ff8a80;
}
@media (max-width: 600px) {
  #key-actions-modal .modal-content {
    width: 100%;
    padding: 1.1rem 1rem 1.3rem;
  }
  #key-actions-modal .ka-list {
    grid-template-columns: 1fr;
  }
}

/* ── Upstream Call Stats ── */
#upstream-stats-card {
  border-left: 3px solid var(--green);
  background: linear-gradient(135deg, var(--bg-card) 0%, #0d1a12 100%);
}
#upstream-stats-card .card-header h2 {
  color: var(--text-secondary);
}
.stats-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  flex-wrap: wrap;
}
.stats-start-label {
  font-size: 0.78rem;
  color: var(--text-muted);
}
.stats-start-value {
  font-size: 0.82rem;
  color: var(--text-secondary);
  font-weight: 500;
}
.upstream-stats-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem;
}
.ustat-item {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
  padding: 0.8rem 0.6rem;
  text-align: center;
}
.ustat-num {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  word-break: break-all;
}
.ustat-label {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-top: 0.2rem;
}
.upstream-stats-note {
  margin-top: 0.8rem;
  font-size: 0.74rem;
  color: var(--text-muted);
  padding: 0.4rem 0.6rem;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 6px;
  border-left: 2px solid var(--accent);
}

@media (max-width: 768px) {
  .upstream-stats-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.4rem;
  }
  .ustat-item {
    padding: 0.6rem 0.4rem;
  }
  .ustat-num {
    font-size: 1rem;
  }
  .stats-meta {
    flex-direction: column;
    align-items: flex-start;
  }
}

@media (max-width: 400px) {
  .page-btn {
    min-width: 26px;
    height: 26px;
    padding: 0 4px;
    font-size: 0.7rem;
  }
}

/* ─────────────────────────────────────────────
   方案 B · 多页面布局补充样式
   ───────────────────────────────────────────── */

/* 折叠菜单：统一分组标题 + 子菜单结构 */
.nav-group-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.8rem 0.3rem;
  color: var(--text-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  user-select: none;
}
.nav-group-head .nav-group-arrow {
  transition: transform 0.15s;
  font-size: 0.7rem;
  color: var(--text-muted);
  width: 1rem;
  text-align: center;
}
.nav-group:not(.expanded) .nav-group-head .nav-group-arrow {
  transform: rotate(-90deg);
}
.nav-group-head.group-active {
  color: var(--accent);
}

.nav-sub {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.15rem 0 0.4rem;
}
.nav-sub-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.7rem;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.82rem;
  font-weight: 500;
  border-radius: var(--radius-sm);
  transition:
    background 0.12s,
    color 0.12s;
}
.nav-sub-item:hover {
  background: rgba(79, 195, 247, 0.06);
  color: var(--text-secondary);
}
.nav-sub-item.active {
  background: var(--accent-glow);
  color: var(--accent);
}
.nav-sub-item .nav-icon {
  font-size: 1.1rem;
  width: 1.6rem;
  text-align: center;
  flex-shrink: 0;
}

/* 面包屑 */
.breadcrumb {
  color: var(--text-muted);
  font-size: 0.9rem;
}
.breadcrumb span + span::before {
  content: ' / ';
  margin: 0 0.35rem;
  opacity: 0.5;
}

/* 总览页快速入口卡片 */
.quick-entries {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
.quick-entry {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-decoration: none;
  color: var(--text-primary);
  transition:
    background 0.15s,
    border-color 0.15s,
    transform 0.15s;
}
.quick-entry:hover {
  background: var(--accent-glow);
  border-color: var(--accent);
  transform: translateY(-1px);
}
.quick-entry-icon {
  font-size: 1.6rem;
  flex-shrink: 0;
}
.quick-entry-title {
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 2px;
}
.quick-entry-desc {
  font-size: 0.78rem;
  color: var(--text-muted);
}

/* 移动端：侧边栏顶到顶部，按钮式折叠 */
@media (max-width: 768px) {
  .sidebar {
    position: fixed;
    left: -260px;
    transition: left 0.25s;
    z-index: 100;
    height: 100vh;
  }
  .sidebar.open {
    left: 0;
  }
  .main-content {
    margin-left: 0 !important;
  }
  .quick-entries {
    grid-template-columns: 1fr;
  }
}

/* modal-large: 大尺寸弹窗（详情页） */
.modal-content.modal-large {
  max-height: 90vh;
  overflow-y: auto;
}

/* 通用 toast 样式（如果还没） */
.toast {
  position: fixed;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(20, 20, 28, 0.95);
  color: #fff;
  padding: 10px 20px;
  border-radius: 8px;
  font-size: 0.9rem;
  z-index: 9999;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
  animation: toast-in 0.2s ease;
  white-space: pre-wrap;
  max-width: 80vw;
  text-align: center;
}
.toast.toast-fade {
  opacity: 0;
  transition: opacity 0.3s;
}
@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(10px);
  }
}

/* ════════════════════════════════════════════════════════
   手机端 UI 适配 (≤ 600px)
   在已有的 768px / 900px / 550px 适配之上，
   针对小屏手机做更精细的调整
   ════════════════════════════════════════════════════════ */

@media (max-width: 600px) {
  /* ── Top bar：标题 + 操作按钮 ── */
  .top-bar {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0;
  }
  .top-bar h2 {
    font-size: 0.9rem;
  }
  .breadcrumb {
    font-size: 0.7rem;
    flex: 1 1 100%;
    order: 2;
  }
  .top-actions {
    display: flex;
    gap: 0.3rem;
    margin-left: auto;
  }
  .top-actions .btn {
    font-size: 0.7rem;
    padding: 0.3rem 0.5rem;
  }
  .top-actions .btn-outline {
    padding: 0.3rem 0.5rem;
  }

  /* ── Stat cards ── */
  .stat-num {
    font-size: 1.2rem;
  }
  .stat-label {
    font-size: 0.65rem;
  }

  /* ── Forms：更紧凑 ── */
  .form-group label {
    font-size: 0.68rem;
    margin-bottom: 0.2rem;
  }
  input,
  select,
  textarea {
    font-size: 0.82rem;
    padding: 0.4rem 0.55rem;
  }
  .input-unit-group {
    flex-wrap: nowrap;
  }
  .input-unit-group .unit-input {
    min-width: 0;
    flex: 1;
  }
  .input-unit-group .unit-select {
    min-width: 56px;
    padding: 0.4rem 0.2rem;
    font-size: 0.66rem;
  }

  /* 快捷按钮组：竖排或更紧凑 */
  .quick-btn-group {
    flex-direction: column;
    gap: 0.4rem;
    width: 100%;
  }
  .quick-btn-group .btn {
    width: 100%;
    padding: 0.5rem;
  }

  /* ── Cards ── */
  .card {
    padding: 0.6rem 0.7rem;
    margin-bottom: 0.6rem;
  }
  .card-header h2 {
    font-size: 0.7rem;
  }
  .card-header {
    flex-wrap: wrap;
    gap: 0.4rem;
  }

  /* ── API Keys 列表行（key-row）：变小 ── */
  .keys-table {
    display: none;
  }
  .keys-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .km-card {
    padding: 0.6rem;
    font-size: 0.75rem;
  }
  .km-card .km-row {
    font-size: 0.72rem;
    padding: 2px 0;
  }
  .km-card .km-row .km-label {
    width: 65px;
    font-size: 0.66rem;
  }
  .km-card .km-actions {
    flex-wrap: wrap;
    gap: 0.25rem;
  }
  .km-card .km-actions .btn {
    padding: 0.25rem 0.4rem;
    font-size: 0.7rem;
  }

  /* 通用 action-group：换行 */
  .action-group {
    flex-wrap: wrap;
    gap: 0.2rem;
    max-width: 100%;
  }
  .action-group .btn {
    padding: 0.25rem 0.4rem;
    font-size: 0.75rem;
    flex: 0 0 auto;
  }
  .action-group .btn-ghost {
    min-width: 30px;
  }

  /* ── 表格转卡片列表 ── */
  #ranking-section table,
  #recent-section table {
    display: none;
  }
  #ranking-section .ranking-mobile-list,
  #recent-section .recent-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
  }
  .rm-card,
  .rc-card {
    padding: 0.5rem 0.6rem;
    font-size: 0.72rem;
    border-radius: 8px;
  }
  .rm-row,
  .rc-row {
    font-size: 0.7rem;
    padding: 2px 0;
  }

  /* ── Chart ── */
  .chart-container {
    gap: 0.2rem;
    padding: 0.4rem 0.2rem;
  }
  .chart-bar-wrap {
    min-width: 12px;
  }
  .chart-bar {
    width: 70%;
    max-width: 22px;
  }
  .chart-count {
    font-size: 0.55rem;
  }
  .chart-label {
    font-size: 0.5rem;
    writing-mode: horizontal-tb;
  }

  /* ── Modal：内容挤 ── */
  .modal-content {
    max-width: 100vw !important;
    width: 100vw !important;
    height: 100vh;
    max-height: 100vh !important;
    border-radius: 0 !important;
    margin: 0 !important;
    padding: 0.8rem !important;
  }
  .modal-overlay {
    padding: 0 !important;
    align-items: stretch !important;
  }
  .modal-close {
    font-size: 1.3rem;
    padding: 0.2rem 0.5rem;
  }
  .modal-content h2 {
    font-size: 0.95rem;
    margin-bottom: 0.5rem;
  }

  /* Detail modal：section padding 缩小 */
  .detail-section {
    padding: 0.5rem;
    margin-bottom: 0.5rem;
  }
  .detail-section h3 {
    font-size: 0.8rem;
    margin-bottom: 0.4rem;
  }
  .info-row {
    font-size: 0.72rem;
    padding: 0.25rem 0;
    flex-wrap: wrap;
    gap: 0.3rem;
  }
  .info-label {
    width: 80px;
    flex: 0 0 80px;
    font-size: 0.68rem;
  }
  .info-value {
    font-size: 0.72rem;
    word-break: break-all;
  }
  .code-block {
    font-size: 0.65rem;
  }
  .code-content {
    font-size: 0.62rem;
    padding: 0.4rem 0.5rem;
    word-break: break-all;
  }
  .code-pre {
    font-size: 0.6rem;
    white-space: pre-wrap;
    word-break: break-all;
  }

  /* stats-grid 内的 token 用量明细 */
  .token-summary-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.4rem;
  }
  .token-summary-grid .stat-card {
    padding: 0.5rem 0.3rem;
  }
  .token-summary-grid .stat-value {
    font-size: 0.95rem;
  }
  .token-summary-grid .stat-label {
    font-size: 0.6rem;
  }

  /* 调用记录表格 */
  .table-sm {
    font-size: 0.7rem;
  }
  .table-sm th,
  .table-sm td {
    padding: 0.25rem 0.3rem;
  }

  /* Pagination：紧凑 */
  .pagination {
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0.4rem 0;
  }
  .page-btn {
    padding: 0.25rem 0.5rem;
    font-size: 0.72rem;
  }

  /* 上游 API 状态行 */
  .upstream-main {
    flex-wrap: wrap;
    gap: 0.4rem;
  }
  .upstream-status-text {
    font-size: 0.85rem;
  }
  .upstream-latency {
    font-size: 0.78rem;
  }
  .upstream-badge {
    font-size: 0.7rem;
    padding: 0.15rem 0.4rem;
  }

  /* 上游统计 grid */
  .upstream-stats-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.4rem;
  }
  .ustat-item {
    padding: 0.5rem 0.4rem;
  }
  .ustat-num {
    font-size: 0.95rem;
  }
  .ustat-label {
    font-size: 0.6rem;
  }

  /* 输入框 placeholder 调整 */
  input::placeholder {
    font-size: 0.72rem;
  }

  /* toast：往上挪，避免被底部导航挡住 */
  .toast {
    bottom: 4.5rem;
    max-width: 92vw;
    font-size: 0.78rem;
    padding: 0.5rem 0.9rem;
  }

  /* Quick entries：单列 */
  .quick-entries {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }
  .quick-entry {
    padding: 0.7rem 0.8rem;
  }
  .quick-entry-icon {
    font-size: 1.3rem;
  }
  .quick-entry-title {
    font-size: 0.85rem;
  }
  .quick-entry-desc {
    font-size: 0.7rem;
  }

  /* Login card */
  .login-card {
    padding: 1.5rem 1.2rem;
  }
  .login-card h1 {
    font-size: 1.2rem;
  }
  .login-card .logo {
    font-size: 2.5rem;
  }

  /* 趋势范围按钮组 */
  .trend-range-btns {
    gap: 0.2rem;
    flex-wrap: wrap;
  }
  .trend-range-btns .btn {
    padding: 0.3rem 0.5rem;
    font-size: 0.72rem;
  }
}

/* ════════════════════════════════════════════════════════
   超窄屏 (≤ 380px)：进一步压缩
   ════════════════════════════════════════════════════════ */

@media (max-width: 380px) {
  .top-actions .btn {
    font-size: 0.62rem;
    padding: 0.22rem 0.4rem;
  }
  .top-actions .btn-outline .icon-keep {
    display: none;
  }
  .stat-num {
    font-size: 1rem;
  }
  .stat-label {
    font-size: 0.55rem;
  }
  .upstream-stats-grid {
    grid-template-columns: 1fr;
  }
  .token-summary-grid {
    grid-template-columns: 1fr;
  }
  .action-group .btn {
    padding: 0.2rem 0.35rem;
    font-size: 0.7rem;
  }
  .info-label {
    width: 70px;
    flex: 0 0 70px;
  }
}

/* ════════════════════════════════════════════════════════
   横向手机 / 平板小屏 (481px - 768px)
   介于手机和桌面之间
   ════════════════════════════════════════════════════════ */

@media (min-width: 481px) and (max-width: 768px) {
  /* 中等屏：3 列 stat */
  .stats-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  /* token 配额 grid 4 列 */
  .token-summary-grid {
    grid-template-columns: repeat(4, 1fr);
  }
  .upstream-stats-grid {
    grid-template-columns: repeat(3, 1fr);
  }
  /* modal 不要全屏 */
  .modal-content {
    max-width: 90vw !important;
    height: auto !important;
    max-height: 90vh !important;
    border-radius: 10px !important;
    margin: 2vh auto !important;
  }
  .modal-overlay {
    padding: 1rem !important;
  }
}

/* ═══════════ 上游配置管理面板（calls-upstream） ═══════════ */
.upcfg-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 14px;
}
.upcfg-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.upcfg-item {
  position: relative;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 14px;
  padding: 10px 14px 12px 18px;
  overflow: hidden;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.18);
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s, transform 0.2s;
}
.upcfg-item:hover {
  border-color: rgba(255, 255, 255, 0.16);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.24);
}
/* 左侧状态色条：激活为渐变绿，未激活为灰 */
.upcfg-item::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 5px;
  background: rgba(158, 158, 158, 0.35);
  border-radius: 14px 0 0 14px;
}
.upcfg-item.active {
  border-color: rgba(76, 175, 80, 0.5);
  background: linear-gradient(180deg, rgba(76, 175, 80, 0.08), rgba(76, 175, 80, 0.03));
  box-shadow: inset 0 0 0 1px rgba(76, 175, 80, 0.16), 0 4px 18px rgba(0, 0, 0, 0.18);
}
.upcfg-item.active::before {
  background: linear-gradient(180deg, #66bb6a, #43a047);
}
.upcfg-row1 {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.upcfg-name {
  font-weight: 700;
  color: #f0f0f0;
  font-size: 14px;
  letter-spacing: 0.3px;
}
/* 名称右侧的状态标签组（类型 / 激活 / 人设 / 思考强度）。
   整组作为一个 flex item：窄屏时整体换到下一行，而不是把标签拆散在两行。
   徽章之间 6px，比 .upcfg-row1 的 10px 更紧，视觉上才像一个"标签组"。 */
.upcfg-badges {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}
.upcfg-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.upcfg-meta-item {
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.3;
}
.upcfg-meta-label {
  color: #8f8f8f;
  flex-shrink: 0;
  min-width: 82px;
  font-weight: 500;
}
.upcfg-meta-item > span:last-child {
  color: #ddd;
  word-break: normal;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* 宽屏：卡片内 信息区 + 配置/操作区 横向两栏 */
.upcfg-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(430px, 620px);
  gap: 14px;
  margin-top: 8px;
  align-items: start;
}
.upcfg-info {
  min-width: 0;
}
.upcfg-aside {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  padding-left: 14px;
  border-left: 1px solid rgba(255, 255, 255, 0.08);
}
@media (max-width: 860px) {
  .upcfg-body {
    grid-template-columns: 1fr;
    gap: 16px;
  }
  .upcfg-aside {
    padding-left: 0;
    border-left: none;
    padding-top: 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
  }
  .upcfg-meta-item {
    flex-direction: column;
    gap: 2px;
  }
  .upcfg-meta-label {
    min-width: 0;
  }
}
/* 卡片头部状态徽章的统一规格：类型 / 激活 / 人设 / 思考强度
   —— 顺序由 renderUpstreamBadges() 统一产出，主备与特级共用，别各写一份。 */
.upcfg-badge {
  display: inline-block;
  font-size: 11px;
  padding: 2px 9px;
  border-radius: 12px;
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
  vertical-align: middle;
}
.upcfg-badge.active-badge {
  background: linear-gradient(180deg, rgba(76, 175, 80, 0.28), rgba(76, 175, 80, 0.18));
  color: #81c784;
  border: 1px solid rgba(76, 175, 80, 0.4);
}
.upcfg-badge.inactive-badge {
  background: rgba(158, 158, 158, 0.15);
  color: #9e9e9e;
  border: 1px solid rgba(158, 158, 158, 0.25);
}
.upcfg-badge.primary-badge {
  background: linear-gradient(180deg, rgba(66, 133, 244, 0.28), rgba(66, 133, 244, 0.18));
  color: #82b1ff;
  border: 1px solid rgba(66, 133, 244, 0.4);
}
.upcfg-badge.backup-badge {
  background: linear-gradient(180deg, rgba(255, 152, 0, 0.28), rgba(255, 152, 0, 0.18));
  color: #ffb74d;
  border: 1px solid rgba(255, 152, 0, 0.4);
}
.upcfg-badge.persona-badge {
  background: linear-gradient(180deg, rgba(186, 104, 200, 0.3), rgba(186, 104, 200, 0.18));
  color: #ce93d8;
  border: 1px solid rgba(186, 104, 200, 0.45);
}
/* 特级上游卡片徽章：与主/备、人设同一套徽章样式，只换配色（琥珀金=先试先行） */
.upcfg-badge.premium-badge {
  background: linear-gradient(180deg, rgba(255, 183, 77, 0.3), rgba(255, 183, 77, 0.16));
  color: #ffcc80;
  border: 1px solid rgba(255, 183, 77, 0.45);
}
/* 思考强度：已固定具体值时用青色（需要一眼看出这条线路被写死了），
   未配置（透传客户端值）用灰阶弱化，避免和「类型 / 激活」抢注意力。 */
.upcfg-badge.strength-badge {
  background: linear-gradient(180deg, rgba(0, 188, 212, 0.28), rgba(0, 188, 212, 0.16));
  color: #4dd0e1;
  border: 1px solid rgba(0, 188, 212, 0.45);
}
.upcfg-badge.muted-badge {
  background: rgba(158, 158, 158, 0.12);
  color: #9aa7b4;
  border: 1px solid rgba(158, 158, 158, 0.22);
}
/* 上游卡片编辑表单：人设开关行 */
.upcfg-form-checkbox {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.upcfg-form-checkbox input[type='checkbox'] {
  accent-color: var(--accent, #4caf50);
  width: 16px;
  height: 16px;
}
/* ── 页面上级 Tab（上游配置 / 特级上游 / 端点模板 / API 状态）──
   胶囊分段控件，独立于卡片之上；卡片里的「主 / 备」是下一级的 data-tab，别混用。 */
.upstream-tabs {
  display: flex;
  gap: 6px;
  padding: 6px;
  margin-bottom: 14px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.07);
  overflow-x: auto;
}
.upstream-tab {
  flex: 0 0 auto;
  padding: 8px 14px;
  border: 1px solid transparent;
  border-radius: 9px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.upstream-tab:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-primary);
}
.upstream-tab.active {
  background: rgba(79, 195, 247, 0.14);
  border-color: rgba(79, 195, 247, 0.4);
  color: #4fc3f7;
}
@media (max-width: 600px) {
  .upstream-tabs {
    gap: 4px;
    padding: 5px;
  }
  .upstream-tab {
    padding: 7px 10px;
    font-size: 12px;
  }
}

/* ── 上游配置管理 主/备 Tab ── */
.upcfg-tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--border);
  margin: 0 1rem 1rem;
  padding: 0;
}
.upcfg-tab {
  padding: 0.5rem 1rem;
  border: 1px solid transparent;
  border-bottom: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  border-radius: 8px 8px 0 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.upcfg-tab:hover {
  color: var(--text-primary);
  background: var(--bg-card-hover);
}
.upcfg-tab.active {
  color: var(--text-primary);
  background: var(--bg-card);
  border-color: var(--border);
  border-bottom-color: var(--bg-card);
  position: relative;
  top: 1px;
}
.upcfg-tab-cnt {
  font-size: 11px;
  padding: 1px 7px;
  border-radius: 10px;
  background: rgba(127, 127, 127, 0.18);
  color: var(--text-secondary);
  font-weight: 600;
}
.upcfg-tab.active .upcfg-tab-cnt {
  background: rgba(66, 133, 244, 0.25);
  color: #82b1ff;
}
.btn:disabled,
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: auto;
  box-shadow: none;
}

.upcfg-detail {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.upcfg-detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 6px;
}
.upcfg-detail-item {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  white-space: nowrap;
  font-size: 12px;
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 8px;
  padding: 4px 9px;
  transition: border-color 0.15s, background 0.15s, transform 0.15s;
}
.upcfg-detail-item:hover {
  border-color: rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.06);
  transform: translateY(-1px);
}
.upcfg-detail-label {
  color: #a0a0a0;
  flex-shrink: 0;
  font-weight: 500;
  white-space: nowrap;
}
.upcfg-detail-value {
  color: #ececec;
  word-break: normal;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-right: auto;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  min-width: 0;
}
.upcfg-detail-value.upcfg-url {
  color: #4fc3f7;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  word-break: break-all;
}
.upcfg-detail-missing {
  color: #e57373;
  font-weight: 500;
}
.upcfg-mult-value {
  color: #ffd54f;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.upcfg-mult-btn {
  padding: 2px 9px;
  font-size: 11px;
  line-height: 1.45;
  flex-shrink: 0;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.04);
  color: #ccc;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.upcfg-mult-btn:hover {
  background: var(--accent-glow, rgba(102, 126, 234, 0.25));
  border-color: rgba(102, 126, 234, 0.5);
  color: #fff;
}
.upcfg-quick-input {
  width: 84px;
  padding: 4px 8px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(102, 126, 234, 0.4);
  color: #eee;
  font-size: 12px;
}
/* 行内编辑态（点 ✏️ 之后）：这一行要放「label + 输入框 + 💾 + ✖」，
   而 .upcfg-detail-item 的最小宽度只有 170px（多条件字段时更窄），
   .upcfg-detail-value 又带 overflow:hidden ⇒ 超出的按钮会被**直接裁掉**，
   现象就是「点 ✏️ 后只有输入框、没有保存按钮」。
   故编辑态：label 让位、输入框可伸缩、允许换行、不再裁切。 */
.upcfg-detail-item.is-editing {
  flex-wrap: wrap;
  white-space: normal;
  gap: 6px;
}
.upcfg-detail-item.is-editing .upcfg-detail-label {
  display: none;
}
.upcfg-detail-item.is-editing .upcfg-detail-value {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  overflow: visible;
  margin-right: 0;
}
.upcfg-detail-item.is-editing .upcfg-quick-input {
  flex: 1 1 64px;
  width: auto;
  min-width: 0;
}
.upcfg-quick-input:focus {
  outline: none;
  border-color: #667eea;
}
.upcfg-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  padding: 7px 10px;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 10px;
}
.upcfg-actions .btn-sm {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
  padding: 0.3rem 0.6rem;
  flex-shrink: 0;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s;
}
.upcfg-actions .btn-sm:hover {
  background: var(--accent-glow);
  transform: translateY(-1px);
}
.upcfg-form {
  margin-top: 14px;
  padding: 14px;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.upcfg-form label {
  font-size: 12px;
  color: #aaa;
  margin-bottom: 2px;
  display: block;
}
.upcfg-form-hint {
  font-size: 12px;
  line-height: 1.6;
  color: #9bb8d3;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(33, 150, 243, 0.08);
  border: 1px dashed rgba(33, 150, 243, 0.35);
}
.upcfg-form-hint .upcfg-url {
  color: #4fc3f7;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  word-break: break-all;
}
.upcfg-form input {
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: #eee;
  font-size: 13px;
}
.upcfg-form input:focus {
  outline: none;
  border-color: #667eea;
}
.upcfg-form-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.upcfg-form-row .grow {
  flex: 1;
  min-width: 180px;
}
.upcfg-empty {
  padding: 24px;
  text-align: center;
  color: #888;
}
.upcfg-test-result {
  font-size: 12px;
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  /* 结果文案里常带长 URL / 报错原文，端点卡片自适应后只有 340px 宽，
     没有这条会把卡片顶出容器（长串无空格无法换行） */
  overflow-wrap: anywhere;
}
.upcfg-test-result.ok {
  background: rgba(76, 175, 80, 0.12);
  color: #81c784;
}
.upcfg-test-result.err {
  background: rgba(244, 67, 54, 0.12);
  color: #e57373;
}
.upcfg-note {
  font-size: 11px;
  color: #8a8a8a;
  margin-top: 12px;
  line-height: 1.7;
  padding: 10px 12px;
  background: rgba(79, 195, 247, 0.06);
  border-left: 3px solid rgba(79, 195, 247, 0.5);
  border-radius: 6px;
}

/* 上游卡片内独立调用统计 */
.upcfg-stats {
  margin-top: 6px;
  padding: 7px 11px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.06);
  font-size: 12px;
  color: #888;
}
.upcfg-stats-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 0;
  color: #aaa;
  cursor: pointer;
  user-select: none;
  padding: 4px 8px;
  margin: -4px -8px;
  border-radius: 8px;
  transition: background 0.15s;
}
.upcfg-stats-head:hover {
  background: rgba(255, 255, 255, 0.04);
}
.upcfg-stats-arrow {
  transition: transform 0.15s;
  font-size: 13px;
  color: #999;
}
.upcfg-stats-title {
  font-weight: 600;
  font-size: 12px;
}
.upcfg-stats-hint {
  font-size: 11px;
  color: #666;
  margin-right: auto;
}
.upcfg-stats-head .btn {
  margin-left: 0;
}
.upcfg-stats-body {
  margin-top: 8px;
}
.upcfg-stats-grid {
  margin-bottom: 0;
}
.upcfg-stats-meta {
  font-size: 11px;
  color: #777;
  margin-top: 4px;
  padding-top: 5px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}
.upcfg-stats-err {
  color: #e57373;
  font-size: 12px;
}

/* 卡片内统计网格（列数与列宽随内容/容器宽度自动变化） */
.upcfg-stats .upstream-stats-grid {
  grid-template-columns: repeat(auto-fill, minmax(min-content, max-content));
  grid-auto-flow: dense;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}
.upcfg-stats .ustat-item {
  padding: 0.35rem 0.25rem;
  border-radius: 7px;
}
.upcfg-stats .ustat-num {
  font-size: 0.85rem;
}
.upcfg-stats .ustat-label {
  font-size: 0.55rem;
  margin-top: 0.1rem;
}

@media (max-width: 640px) {
  .upcfg-stats .upstream-stats-grid {
    grid-template-columns: repeat(auto-fill, minmax(min-content, max-content));
    grid-auto-flow: dense;
    justify-content: space-between;
    gap: 0.4rem 0.8rem;
  }
  .upcfg-stats-hint {
    display: none;
  }
}

/* ═══════════ 独立端点配置区（上游 API 管理页）    ═══════════ */
.ep-status-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.2rem 0 0.1rem;
}
.ep-status-title {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-weight: 600;
}
/* 「API 状态」页的四组（端点 / 特级 / 主 / 备）：每组一个小标题 + 计数 */
.up-status-section {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.up-status-section:first-of-type {
  border-top: none;
  padding-top: 0;
}
.up-status-section-head {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 2px;
}
.up-status-section-title {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text-secondary);
}
.up-status-section-cnt {
  font-size: 11px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 10px;
  background: rgba(127, 127, 127, 0.18);
  color: var(--text-secondary);
}
.ep-status-wrap {
  padding: 0.3rem 0;
}
.ep-status-empty {
  color: var(--text-muted);
  font-size: 0.78rem;
  padding: 0.3rem 0;
}
/* 端点卡片列表：等宽自适应网格。
   ⚠️ 这里刻意用 grid 而不是 flex-wrap —— flex 下每张卡片的 flex-grow 拿到的剩余空间
   取决于同一行有几张、加起来多宽，同一行的卡片宽度会不一致（最后一行只有一张时
   还会被拉宽）。grid 的 repeat(auto-fill, minmax(...)) 让每列严格等宽，视觉才整齐。
   min(340px, 100%) 是为了窄屏（<340px）时不撑破容器。 */
.ep-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
  align-items: start;
  gap: 12px;
  margin-top: 6px;
}
.ep-item {
  min-width: 0;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 12px;
  padding: 12px 14px;
  transition: border-color 0.2s, background 0.2s;
}
/* 展开编辑表单时横跨整行：表单里全是 width:100% 的输入框，
   挤在 340px 里三个字段叠成一条竖线，根本没法编辑。 */
.ep-item.editing {
  grid-column: 1 / -1;
}
.ep-item:hover {
  border-color: rgba(33, 150, 243, 0.35);
}
.ep-row1 {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.ep-name {
  font-weight: 700;
  color: #f0f0f0;
  font-size: 14px;
}
.ep-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
  font-size: 13px;
}
/* 端点选择弹层（上游卡片「切换端点」） */
.ep-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px);
  padding: 20px;
}
.ep-picker {
  width: 100%;
  max-width: 460px;
  max-height: 82vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 14px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}
.ep-picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.ep-picker-title {
  font-weight: 700;
  color: #f0f0f0;
  font-size: 14px;
}
.ep-picker-list {
  overflow-y: auto;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ep-picker-item {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  padding: 10px 12px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: inherit;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.ep-picker-item:hover {
  border-color: rgba(33, 150, 243, 0.5);
  background: rgba(33, 150, 243, 0.1);
}
.ep-picker-item .ep-name {
  font-weight: 600;
  font-size: 13px;
}
.ep-picker-item .ep-url {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-muted);
  font-size: 12px;
}
.ep-picker-item .ep-key {
  font-size: 11px;
  flex-shrink: 0;
  color: #90caf9;
}
.ep-picker-foot {
  padding: 10px 14px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 12px;
  color: var(--text-muted);
}
/* 表单中的下拉框统一样式（base/端点绑定等） */
.upcfg-form select {
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: #eee;
  font-size: 13px;
  /* 让浏览器按深色主题绘制下拉箭头 / 展开弹层的滚动条；
     缺了它 Windows Chrome 会用亮色系统主题画弹层，与下面的 option 配色打架 */
  color-scheme: dark;
}
.upcfg-form select:focus {
  outline: none;
  border-color: #667eea;
}
/* 展开的原生下拉面板（思考强度 / base / 端点绑定等）：
   ⚠️ <option> 只继承父级 color（#eee），背景却取系统默认的白色 ⇒ 白底浅字看不清。
   必须给 option 显式不透明深底（半透明在这里没用，弹层是独立绘制的）。
   配色与 .upstream-inline-select option 保持一致，避免两处下拉观感不一。 */
.upcfg-form select option,
.upcfg-form select optgroup {
  background-color: #1e2530;
  color: #d8e1ec;
}

/* ── 上游新增 / 编辑弹窗（普通与特级共用）────────────────────────────
   .modal-content 默认 1100px 是给详情页用的；这里改成「头 / 身 / 脚」三段式：
   头尾固定、中间滚动，长表单（特级十几个字段）也不会把标题和按钮顶出屏幕。 */
.upcfg-modal-content {
  max-width: 800px;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.upcfg-modal-head {
  padding: 1.1rem 1.6rem 0.7rem;
  border-bottom: 1px solid var(--border);
  flex: none;
}
.upcfg-modal-head h2 {
  margin: 0;
  padding-right: 1.8rem;
  font-size: 1.02rem;
}
.upcfg-modal-sub {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
}
.upcfg-modal-body {
  padding: 0.9rem 1.6rem 1rem;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
}
.upcfg-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 0.75rem 1.6rem;
  border-top: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.18);
  flex: none;
}

/* 弹窗内表单：分组 + 两列自适应网格。
   根元素保留 .upcfg-form 是为了继续吃到 input / select / option 的既有样式，
   这里只把它原本的「竖排 + 背景卡片」形态清掉。 */
.upcfg-modal-body .upcfg-form {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  gap: 0;
}
.upcf-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.upcf-section {
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 10px;
  padding: 12px 14px 14px;
  background: rgba(255, 255, 255, 0.02);
}
.upcf-section-title {
  font-size: 12px;
  font-weight: 600;
  color: #9bb8d3;
  margin-bottom: 10px;
  letter-spacing: 0.3px;
}
.upcf-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px 12px;
}
/* ⚠️ 必须带 .upcfg-form 前缀：.upcfg-form label 有 display:block + margin-bottom，
   特异性不够高会被它盖掉（表现为标签与输入框上下错位）。 */
.upcfg-form .upcf-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  font-size: 12px;
  color: #9aa7b4;
}
.upcf-field.span2 {
  grid-column: 1 / -1;
}
.upcf-label {
  font-size: 11.5px;
  color: #9aa7b4;
  letter-spacing: 0.2px;
}
.upcf-hint {
  font-size: 11px;
  line-height: 1.5;
  color: #78848f;
}
.upcfg-form .upcf-check {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 12.5px;
  color: #c9d4df;
  cursor: pointer;
}
.upcfg-form .upcf-check input[type='checkbox'] {
  width: 15px;
  height: 15px;
  flex: none;
  accent-color: var(--accent, #4caf50);
}

/* ═══════════ 系统配置页（sysconfig） ═══════════ */
#syscfg-body .card {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
#syscfg-body .card:hover {
  border-color: var(--border-light);
}

/* 顶部版本卡片 */
.syscfg-version {
  margin-bottom: 18px;
  background: linear-gradient(
    135deg,
    var(--bg-card-hover) 0%,
    var(--bg-card) 100%
  );
}
.syscfg-version .card-header h2 .syscfg-ver-badge {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 13px;
  color: var(--accent);
  letter-spacing: 0.04em;
}
.syscfg-versionspan {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  padding: 4px 14px;
  border-radius: 999px;
  background: var(--accent-glow);
  box-shadow: inset 0 0 0 1px rgba(79, 195, 247, 0.25);
}
.syscfg-versionspan .syscfg-ver-badge {
  font-size: 15px;
}
.syscfg-ip {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  padding: 6px 14px;
  border-radius: 8px;
  background: var(--bg-card-hover);
  box-shadow: inset 0 0 0 1px var(--border-light);
}

.syscfg-loading,
.syscfg-err {
  padding: 28px 24px;
  text-align: center;
  color: var(--text-secondary);
  font-size: 14px;
}
.syscfg-loading {
  letter-spacing: 0.02em;
}
.syscfg-err {
  color: var(--red);
}

/* 状态徽章 */
.syscfg-status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 999px;
  white-space: nowrap;
  line-height: 1;
}
.syscfg-status.on {
  background: var(--accent-glow);
  color: var(--accent);
  box-shadow: inset 0 0 0 1px rgba(79, 195, 247, 0.25);
}
.syscfg-status.off {
  background: rgba(158, 158, 158, 0.12);
  color: var(--text-muted);
  box-shadow: inset 0 0 0 1px rgba(158, 158, 158, 0.18);
}

/* 全局限流卡片 —— 头部状态组 */
.syscfg-rate-head {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
/* 配置来源徽章 */
.syscfg-rate-source {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 700;
  padding: 4px 12px;
  border-radius: 999px;
  white-space: nowrap;
  line-height: 1;
}
.syscfg-rate-source.db {
  background: rgba(102, 187, 106, 0.14);
  color: var(--green);
  box-shadow: inset 0 0 0 1px rgba(102, 187, 106, 0.3);
}
.syscfg-rate-source.env {
  background: rgba(255, 152, 0, 0.13);
  color: var(--orange);
  box-shadow: inset 0 0 0 1px rgba(255, 152, 0, 0.3);
}
.syscfg-rate-source.def {
  background: rgba(158, 158, 158, 0.1);
  color: var(--text-muted);
  box-shadow: inset 0 0 0 1px rgba(158, 158, 158, 0.18);
}
/* 来源说明行 */
.syscfg-rate-scope {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.7;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
/* 限流命中计数 */
.syscfg-rate-hit {
  font-size: 14px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.syscfg-rate-hit b {
  color: var(--orange);
  font-weight: 700;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
}

/* 卡片说明文字 */
.syscfg-desc {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.8;
  margin: 12px 0 18px;
  padding: 10px 14px;
  border-left: 3px solid var(--accent);
  background: rgba(255, 255, 255, 0.02);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.syscfg-desc code,
.syscfg-note-warn code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 12px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-primary);
  padding: 2px 6px;
  border-radius: 4px;
  border: 1px solid var(--border);
}

/* 表单字段行 */
.syscfg-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 15px 4px;
  border-top: 1px solid var(--border);
  transition: background 0.15s;
}
.syscfg-field:first-child {
  border-top: none;
}
.syscfg-field:hover {
  background: rgba(255, 255, 255, 0.015);
}
.syscfg-field-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.4;
}
.syscfg-field-hint {
  font-size: 12px;
  font-weight: 400;
  color: var(--text-muted);
  line-height: 1.6;
  margin-top: 1px;
}

/* 数字/文本输入 */
.syscfg-num {
  width: 150px;
  text-align: right;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  border: 1px solid var(--border);
  color: var(--text-primary);
  font-size: 14px;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.syscfg-num:hover {
  border-color: var(--border-light);
}
.syscfg-num:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}

/* 汇总信息条 */
.syscfg-summary {
  margin-top: 16px;
  padding: 13px 16px;
  border-radius: var(--radius-sm);
  background: var(--accent-glow);
  border: 1px solid rgba(79, 195, 247, 0.18);
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.8;
}
.syscfg-summary b {
  color: var(--accent);
  font-weight: 700;
}

/* 按钮操作区 */
.syscfg-actions {
  display: flex;
  gap: 10px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px dashed var(--border);
  flex-wrap: wrap;
}
.syscfg-actions .btn {
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* 上游 400 上下文修复卡片 —— 分组面板（①② 两类场景） */
#syscfg-repair-card .syscfg-group {
  margin-top: 18px;
  padding: 15px 18px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.015);
}
#syscfg-repair-card .group-tool {
  border-top: 2px solid rgba(102, 187, 106, 0.55);
}
#syscfg-repair-card .group-thinking {
  border-top: 2px solid rgba(79, 195, 247, 0.55);
}
#syscfg-repair-card .syscfg-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
#syscfg-repair-card .syscfg-group-title {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
}
#syscfg-repair-card .syscfg-group-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 800;
  color: var(--bg-primary);
  flex-shrink: 0;
}
#syscfg-repair-card .group-tool .syscfg-group-num {
  background: var(--green);
}
#syscfg-repair-card .group-thinking .syscfg-group-num {
  background: var(--accent);
}
#syscfg-repair-card .syscfg-group-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  padding: 4px 11px;
  border-radius: 999px;
  white-space: nowrap;
  line-height: 1;
}
#syscfg-repair-card .syscfg-group-badge.on {
  background: rgba(102, 187, 106, 0.14);
  color: var(--green);
  box-shadow: inset 0 0 0 1px rgba(102, 187, 106, 0.3);
}
#syscfg-repair-card .syscfg-group-badge.off {
  background: rgba(158, 158, 158, 0.1);
  color: var(--text-muted);
  box-shadow: inset 0 0 0 1px rgba(158, 158, 158, 0.18);
}
#syscfg-repair-card .syscfg-group-desc {
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin: 8px 0 14px;
  padding: 10px 12px;
  border-left: 3px solid var(--border-light);
  background: rgba(255, 255, 255, 0.015);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
#syscfg-repair-card .syscfg-group-desc code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 11.5px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-primary);
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid var(--border);
}
#syscfg-repair-card .syscfg-err-chip {
  display: inline-block;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 11.5px;
  background: rgba(239, 83, 80, 0.08);
  color: var(--red);
  border: 1px solid rgba(239, 83, 80, 0.22);
  padding: 1px 6px;
  border-radius: 4px;
}
/* 分组内表单行紧凑化 + 修复 global select width:100% 过宽问题 */
#syscfg-repair-card .syscfg-field {
  padding: 12px 4px;
}
#syscfg-repair-card select {
  width: min(460px, 62%);
  flex-shrink: 0;
  padding: 9px 12px;
  font-size: 13px;
  text-align: left;
}

/* 流式大卡片 —— 分组面板（①②③ 收尾 / 输出 / 重试） */
#syscfg-stream-card .syscfg-group {
  margin-top: 16px;
  padding: 15px 18px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.015);
}
#syscfg-stream-card .syscfg-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
  flex-wrap: wrap;
}
#syscfg-stream-card .syscfg-group-title {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
}
#syscfg-stream-card .syscfg-group-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 800;
  color: var(--bg-primary);
  flex-shrink: 0;
  background: var(--accent);
}
#syscfg-stream-card .syscfg-group-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  padding: 4px 11px;
  border-radius: 999px;
  white-space: nowrap;
  line-height: 1;
}
#syscfg-stream-card .syscfg-group-badge.on {
  background: rgba(102, 187, 106, 0.14);
  color: var(--green);
  box-shadow: inset 0 0 0 1px rgba(102, 187, 106, 0.3);
}
#syscfg-stream-card .syscfg-group-badge.off {
  background: rgba(158, 158, 158, 0.1);
  color: var(--text-muted);
  box-shadow: inset 0 0 0 1px rgba(158, 158, 158, 0.18);
}
#syscfg-stream-card .syscfg-group-desc {
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.7;
  margin: 8px 0 14px;
  padding: 10px 12px;
  border-left: 3px solid var(--border-light);
  background: rgba(255, 255, 255, 0.015);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
#syscfg-stream-card .syscfg-group-desc code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-size: 11.5px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-primary);
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid var(--border);
}
#syscfg-stream-card .syscfg-field {
  padding: 12px 4px;
}

/* 分区小标题 */
.syscfg-section-title {
  margin: 22px 0 10px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  display: flex;
  align-items: center;
  gap: 6px;
}
.syscfg-section-title::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
  margin-left: 6px;
}

/* 环境变量警告条 */
.syscfg-note-warn {
  margin-top: 16px;
  padding: 13px 16px;
  border-radius: var(--radius-sm);
  background: rgba(255, 152, 0, 0.08);
  border: 1px solid rgba(255, 152, 0, 0.22);
  font-size: 13px;
  color: var(--orange);
  line-height: 1.7;
}
.syscfg-note-warn code {
  color: var(--orange);
}

/* 记录区图表标题行 */
#syscfg-retry-card h3 {
  letter-spacing: 0.05em;
}
#syscfg-retry-card .btn-sm {
  font-weight: 500;
}
#syscfg-retry-card h3.syscfg-section-title[style*="margin:0"]::after {
  display: none;
}

/* 记录区表格精致化 */
#syscfg-retry-card .table-wrap {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--bg-input);
}
#syscfg-retry-card .table-sm {
  width: 100%;
  border-collapse: collapse;
}
#syscfg-retry-card .table-sm thead th {
  background: var(--bg-card-hover);
  color: var(--text-secondary);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-align: center;
  padding: 0.55rem 0.6rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
#syscfg-retry-card .table-sm tbody td {
  padding: 0.5rem 0.6rem;
  font-size: 0.76rem;
  color: var(--text-primary);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  text-align: center;
}
#syscfg-retry-card .table-sm tbody tr:last-child td {
  border-bottom: none;
}
#syscfg-retry-card .table-sm tbody tr:hover td {
  background: rgba(255, 255, 255, 0.025);
}
#syscfg-retry-card .time-cell {
  color: var(--text-muted);
  white-space: nowrap;
  font-size: 0.72rem;
}
#syscfg-retry-card .num-cell {
  color: var(--text-secondary);
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
}

/* 开关 switch */
.switch {
  position: relative;
  display: inline-block;
  width: 48px;
  height: 26px;
  flex-shrink: 0;
}
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.switch .slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  border-radius: 26px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid var(--border-light);
  transition: background 0.2s, border-color 0.2s, box-shadow 0.2s;
}
.switch .slider::before {
  content: '';
  position: absolute;
  height: 18px;
  width: 18px;
  left: 3px;
  top: 3px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition: transform 0.2s;
}
.switch input:checked + .slider {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.switch input:checked + .slider::before {
  transform: translateX(22px);
}
.switch input:disabled + .slider {
  opacity: 0.4;
  cursor: not-allowed;
}

@media (max-width: 640px) {
  .syscfg-field {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .syscfg-num {
    width: 100%;
    text-align: left;
  }
  .syscfg-actions {
    flex-direction: column;
  }
  .syscfg-actions .btn {
    width: 100%;
  }
}

/* ── 日志记录页：手机端表格转卡片 ──
   该页有 4 个 tab（最终报错 / 降级重绑 / 重试 / 切换），面板统一包在 #errlog-panels 里，
   故这里用后代选择器一次覆盖，新增 tab 只要沿用 .recent-mobile-list + .err-card 即自动生效。 */
@media (max-width: 900px) {
  #err-logs-table,
  #rb-logs-table,
  #retry-logs-table,
  #fa-logs-table {
    display: none;
  }
  #errlog-panels .recent-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding-top: 0.3rem;
  }
  #errlog-panels .recent-mobile-list .rc-card {
    display: flex;
    flex-direction: column;
  }
  #errlog-panels .recent-mobile-list .err-card .rc-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
  }
  #errlog-panels .recent-mobile-list .err-card .rc-row > span:first-child {
    color: var(--text-muted);
    flex-shrink: 0;
    min-width: 2.2rem;
  }
  #errlog-panels .recent-mobile-list .err-card .rc-row > span:last-child {
    text-align: right;
    word-break: break-all;
    color: var(--text);
    flex: 1;
  }
}

/* ── 系统配置：顶部 Tab 页切换 ── */
.syscfg-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  border-bottom: 1px solid var(--border);
  margin: 0 1rem 1rem;
  padding-bottom: 0;
}
.syscfg-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0.5rem 1rem;
  border: 1px solid transparent;
  border-bottom: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  border-radius: 8px 8px 0 0;
  white-space: nowrap;
}
.syscfg-tab:hover {
  color: var(--text-primary);
  background: var(--bg-card-hover);
}
.syscfg-tab.active {
  color: var(--text-primary);
  background: var(--bg-card);
  border-color: var(--border);
  border-bottom-color: var(--bg-card);
  position: relative;
  top: 1px;
}

/* ═══════════ 数据库监控卡片（sysconfig 系统信息） ═══════════ */
#syscfg-dbmon-card .dbmon-badge {
  font-size: 0.8rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--border-light);
}
#syscfg-dbmon-card .dbmon-badge--ok {
  color: var(--green);
  background: rgba(102, 187, 106, 0.12);
  box-shadow: inset 0 0 0 1px rgba(102, 187, 106, 0.3);
}
#syscfg-dbmon-card .dbmon-badge--warn {
  color: var(--orange);
  background: rgba(255, 152, 0, 0.12);
  box-shadow: inset 0 0 0 1px rgba(255, 152, 0, 0.35);
}
.dbmon-val--warn {
  color: var(--orange) !important;
}

/* 概览横幅 */
.dbmon-hero {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: linear-gradient(135deg, var(--bg-card-hover), var(--bg-card));
  margin-bottom: 10px;
}
#syscfg-dbmon-card .dbmon-hero--ok {
  border-color: rgba(102, 187, 106, 0.35);
}
#syscfg-dbmon-card .dbmon-hero--warn {
  border-color: rgba(255, 152, 0, 0.45);
}
.dbmon-hero__title {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--text-primary);
}
.dbmon-hero__title b {
  color: var(--accent);
  font-family: 'SFMono-Regular', Consolas, monospace;
}
.dbmon-hero__sub {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-top: 2px;
}
.dbmon-hero__right {
  text-align: right;
  flex-shrink: 0;
}
.dbmon-hero__ping {
  font-size: 0.72rem;
  color: var(--text-muted);
}
.dbmon-hero__ping b {
  display: block;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text-primary);
  font-family: 'SFMono-Regular', Consolas, monospace;
}

/* 占用进度条 */
.dbmon-bar {
  height: 6px;
  border-radius: 999px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  overflow: hidden;
  margin-bottom: 14px;
}
.dbmon-bar__fill {
  height: 100%;
  border-radius: 999px;
  transition: width 0.4s ease;
}

/* 分组标题 */
.dbmon-group {
  margin-top: 14px;
}
.dbmon-group__title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-secondary);
  padding-bottom: 7px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
}
.dbmon-group__hint {
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}

/* 连接池建议提示条 */
.dbmon-tip {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  margin-top: 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-card-hover);
  line-height: 1.5;
}
.dbmon-tip--solid {
  border-color: rgba(102, 187, 106, 0.35);
  background: rgba(102, 187, 106, 0.06);
}
.dbmon-tip--tight {
  border-color: rgba(255, 152, 0, 0.5);
  background: rgba(255, 152, 0, 0.08);
}
.dbmon-tip__icon {
  font-size: 1.05rem;
  line-height: 1.3;
  flex-shrink: 0;
}
.dbmon-tip__body {
  font-size: 0.82rem;
  color: var(--text-primary);
}
.dbmon-tip__body code {
  color: var(--accent);
  background: var(--bg-input);
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid var(--border);
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: 0.75rem;
}
.dbmon-tip__body b {
  color: var(--accent);
  font-family: 'SFMono-Regular', Consolas, monospace;
}
.dbmon-tip--tight .dbmon-tip__body b {
  color: var(--orange);
}
.dbmon-tip__hint {
  display: block;
  margin-top: 4px;
  font-size: 0.74rem;
  color: var(--text-muted);
}

/* 指标小方块 */
.dbmon-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
}
.dbmon-tile {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 9px 11px;
  transition: border-color 0.15s, transform 0.15s;
}
.dbmon-tile:hover {
  border-color: var(--border-light);
  transform: translateY(-1px);
}
.dbmon-tile__label {
  font-size: 0.7rem;
  color: var(--text-muted);
  margin-bottom: 3px;
  white-space: nowrap;
}
.dbmon-tile__value {
  font-size: 1.02rem;
  font-weight: 700;
  color: var(--text-primary);
  font-family: 'SFMono-Regular', Consolas, monospace;
  line-height: 1.3;
  word-break: break-all;
}
.dbmon-tile__sub {
  font-size: 0.7rem;
  color: var(--text-muted);
  margin-top: 3px;
  white-space: nowrap;
}

@media (max-width: 640px) {
  .dbmon-tiles {
    grid-template-columns: repeat(2, 1fr);
  }
  .dbmon-hero {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
  .dbmon-hero__right {
    text-align: left;
  }
}

/* ════════════════════════════════════════════════════════════════
   Apikeys 管理（/keys/overview.html）手机端适配
   ────────────────────────────────────────────────────────────────
   作用域：body.pg-keys —— 仅该页 HTML 上的类，且下列全部规则都写在
   max-width 媒体查询里，因此桌面端（>900px）不产生任何影响，
   表现与改造前逐字一致。
   断点 900px 与「侧边栏 → 底部导航」的断点保持一致。
   ════════════════════════════════════════════════════════════════ */

/* ── 筛选栏的两个包装层 ──
   桌面端 display:contents：不为自己生成盒子，子元素直接参与
   .filter-bar 的 flex 布局，等价于改造前的平铺结构（视觉零差异）。 */
.pg-keys .kf-bar-row,
.pg-keys .kf-bar-more {
  display: contents;
}
.pg-keys .kf-toggle {
  display: none;
}
/* 搜索框样式：由 JS 内联样式原样搬到此处，便于小屏覆盖 */
.pg-keys .kf-search-input {
  background: #141b24;
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--text);
  border-radius: 6px;
  padding: 0.32rem 0.55rem;
  font-size: 0.78rem;
  outline: none;
  min-width: 12rem;
}
/* 手机端卡片列表的空态 / 加载失败提示 */
.pg-keys .km-empty {
  padding: 1.6rem 0.8rem;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  text-align: center;
  font-size: 0.8rem;
  color: var(--text-muted);
}

@media (max-width: 900px) {
  /* ── 列表：表格 → 卡片（与底部导航同一断点，避免横向滚动）── */
  .pg-keys #keys-table-wrap .keys-table {
    display: none;
  }
  .pg-keys .keys-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  /* ── 总览统计：固定 2 列，第 3 张（并发）占满整行 ── */
  .pg-keys .stats-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
  }
  .pg-keys .stats-grid .stat-card:nth-child(3) {
    grid-column: 1 / -1;
  }
  /* 整行卡片更高，上游/并发明细多露几行 */
  .pg-keys .stats-grid .stat-card:nth-child(3) .stat-sublist {
    max-height: 150px;
  }

  /* ── 卡片头：两个创建按钮等宽铺满，点按面积更大 ── */
  .pg-keys .card-header-actions {
    flex: 1 1 100%;
    gap: 0.4rem;
  }
  .pg-keys .card-header-actions .btn {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
  }

  /* ── 筛选栏：搜索 +「筛选」一行，其余条件收进折叠面板 ── */
  .pg-keys .filter-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
    padding: 0.6rem 0.7rem;
  }
  .pg-keys .kf-bar-row {
    display: flex;
    align-items: center;
    gap: 0.45rem;
  }
  .pg-keys .kf-bar-more {
    display: none;
  }
  .pg-keys .filter-bar.expanded .kf-bar-more {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .pg-keys .kf-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex: 0 0 auto;
    margin-left: 0;
    min-height: 38px;
  }
  .pg-keys .kf-caret {
    font-size: 0.7rem;
    line-height: 1;
    transition: transform 0.15s;
  }
  .pg-keys .filter-bar.expanded .kf-caret {
    transform: rotate(180deg);
  }
  /* 有筛选生效时给按钮加高亮小圆点：折叠状态下也能一眼看出列表被过滤过 */
  .pg-keys .filter-bar.has-filter .kf-toggle {
    border-color: var(--accent);
    color: var(--accent);
  }
  .pg-keys .filter-bar.has-filter .kf-toggle::after {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
  }
  .pg-keys .kf-search-item {
    flex: 1 1 auto;
    min-width: 0;
  }
  .pg-keys .kf-search-input {
    width: 100%;
    min-width: 0;
    flex: 1 1 auto;
  }
  /* 标签在上、控件在下：更符合手机单手操作，也避免控件被压窄 */
  .pg-keys .filter-bar .filter-item {
    flex-direction: column;
    align-items: stretch;
    gap: 0.22rem;
    font-size: 0.72rem;
    white-space: normal;
  }
  .pg-keys .filter-bar select {
    width: 100%;
    min-width: 0;
    min-height: 38px;
  }
  .pg-keys .filter-bar .btn {
    margin-left: 0;
  }
  .pg-keys .kf-bar-more .btn {
    width: 100%;
    justify-content: center;
    min-height: 38px;
  }

  /* ── 卡片（.km-card）基础布局 ──
     这些样式原本只在 ≤600px 的全局规则里定义，本页把卡片列表提前到
     ≤900px，故在 601-900px 区间需要补齐（取值与全局实现保持一致）。 */
  .pg-keys .km-card {
    display: flex;
    flex-direction: column;
    position: relative;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .pg-keys .km-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
  }
  .pg-keys .km-card-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    font-weight: 600;
    font-size: 0.82rem;
  }
  .pg-keys .km-card-body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
  }
  .pg-keys .km-card .km-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.74rem;
    color: var(--text-secondary);
  }
  .pg-keys .km-card .km-row .km-label {
    flex-shrink: 0;
    font-size: 0.7rem;
    color: var(--text-muted);
  }
  .pg-keys .km-card .km-row .km-value {
    min-width: 0;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }
  .pg-keys .km-card .km-key-code {
    display: inline-block;
    max-width: 100%;
    padding: 0.08rem 0.35rem;
    border-radius: 3px;
    background: var(--bg-input);
    color: #7ab8d4;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
    font-size: 0.68rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .pg-keys .km-card .km-model-tag {
    display: inline-block;
    padding: 0.04rem 0.3rem;
    border-radius: 3px;
    background: rgba(79, 195, 247, 0.07);
    color: var(--accent);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
    font-size: 0.62rem;
  }

  /* ── 卡片：手机端细化 ── */
  .pg-keys .km-card {
    padding: 0.65rem 0.7rem;
    gap: 0.45rem;
  }
  .pg-keys .km-card-header {
    align-items: flex-start;
  }
  .pg-keys .km-card-title {
    flex: 1 1 auto;
    flex-wrap: wrap;
    row-gap: 0.15rem;
    line-height: 1.35;
  }
  /* 名称不再截断成省略号（手机上认名字是最主要的识别方式） */
  .pg-keys .km-card-title .key-name {
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .pg-keys .km-card-title .badge,
  .pg-keys .km-card-title .sts-dot {
    flex: none;
  }
  .pg-keys .km-card-actions {
    max-width: none;
  }
  .pg-keys .km-card-actions .key-ops-btn {
    min-height: 34px;
  }
  .pg-keys .km-card-body {
    gap: 0.25rem;
  }
  .pg-keys .km-card .km-row .km-label {
    width: 4.9rem;
  }
  /* 含下拉 / 输入框的行：控件整行铺满，点按目标足够大 */
  .pg-keys .km-card .km-row-ctl {
    flex-direction: column;
    align-items: stretch;
    gap: 0.25rem;
    margin: 0.1rem 0;
  }
  .pg-keys .km-card .km-row-ctl > .km-label {
    width: auto;
  }
  .pg-keys .km-card .km-row-ctl > .km-value {
    display: block;
    text-align: left;
    white-space: normal;
    overflow: visible;
  }
  .pg-keys .km-card .km-row-ctl .upstream-inline-select {
    width: 100%;
    max-width: none;
    min-height: 38px;
    padding: 0.4rem 0.5rem;
  }
  /* 配额条：占满值区域，不再被 120px 卡住 */
  .pg-keys .km-card .km-quota {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    width: 100%;
    justify-content: flex-end;
  }
  .pg-keys .km-card .km-quota .ql-mini-wrap {
    flex: 1 1 auto;
    max-width: none;
    justify-content: flex-end;
  }
  .pg-keys .km-card .km-quota .ql-mini-bar {
    flex: 1 1 auto;
  }

  /* ── 分页：页码独占一行居中，条数 / 每页选择另起一行 ── */
  .pg-keys .pagination {
    flex-wrap: wrap;
    gap: 0.4rem 0.6rem;
    padding: 0.6rem 0 0.2rem;
  }
  .pg-keys #keys-pagination {
    flex: 1 1 100%;
    display: block;
    text-align: center;
  }
  .pg-keys #keys-pagination .page-btn-group {
    justify-content: center;
  }
  .pg-keys .pagination .page-size-select {
    width: 56px;
    min-height: 32px;
    font-size: 0.78rem;
  }

  /* ── 详情弹窗（从本页打开）：Tab 允许换行，调用记录表横向滚动而非挤扁 ── */
  .pg-keys .detail-tabs {
    flex-wrap: wrap;
    gap: 0.2rem;
  }
  .pg-keys .detail-tab {
    flex: 1 1 auto;
    padding: 0.45rem 0.6rem;
    font-size: 0.76rem;
    white-space: nowrap;
  }
  .pg-keys .modal-content .table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .pg-keys #detail-logs-table {
    min-width: 720px;
  }
}

@media (max-width: 600px) {
  /* 搜索框与卡片内控件：≥16px 才不会在 iOS Safari 聚焦时自动放大页面
     （.kf-search-input / .upstream-inline-select 的类选择器优先级高于全局的
       input,select{font-size:16px}，需单独声明） */
  .pg-keys .kf-search-input,
  .pg-keys .km-card .km-row-ctl .upstream-inline-select {
    font-size: 16px;
  }
  .pg-keys .km-card .km-row .km-label {
    width: 4.6rem;
  }
  .pg-keys .stats-grid {
    gap: 0.4rem;
  }
  /* 创建弹窗底部按钮：等宽铺满，点按更容易（该弹窗由本页打开） */
  .pg-keys .create-key-form .create-key-actions {
    gap: 0.5rem;
  }
  .pg-keys .create-key-form .create-key-actions .btn {
    flex: 1 1 0;
    min-width: 0;
    min-height: 42px;
  }
}

@media (max-width: 380px) {
  .pg-keys .kf-toggle {
    padding: 0.3rem 0.45rem;
    font-size: 0.72rem;
  }
  .pg-keys .stats-grid {
    gap: 0.3rem;
  }
  .pg-keys .km-card {
    padding: 0.5rem 0.55rem;
  }
  .pg-keys .km-card .km-row .km-label {
    width: 4.2rem;
  }
  .pg-keys .km-card .km-row-ctl .upstream-inline-select {
    font-size: 16px;
    padding: 0.35rem 0.4rem;
  }
}

/* ════════════════════════════════════════════════════════════════
   Key 详情弹窗「用量趋势」Tab（单张柱状趋势图 + 指标切换）
   ────────────────────────────────────────────────────────────────
   作用域：#detail-modal（该弹窗由 modals.js 统一渲染），
   类名统一 dtu-* 前缀，不与其他页面的 .chart-* 旧实现冲突。
   ════════════════════════════════════════════════════════════════ */

/* 控制区：指标切换（调用次数 / Token(M)）+ 窗口切换（7 / 30 / 90 天） */
#detail-modal .dtu-ctrls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
}
#detail-modal .dtu-metrics,
#detail-modal .dtu-ranges {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}
#detail-modal .dtu-metric.active,
#detail-modal .dtu-range.active {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(79, 195, 247, 0.1);
}

/* 柱状趋势图：每天一根柱 */
#detail-modal .dtu-chart {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  padding: 0.4rem 0.2rem 0.3rem;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
#detail-modal .dtu-col {
  flex: 1 0 auto;
  min-width: 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 2px;
}
/* 柱顶数值：调用次数=整数，Token=x.xM */
#detail-modal .dtu-val {
  font-size: 0.6rem;
  line-height: 1;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
#detail-modal .dtu-bar {
  display: block;
  width: 70%;
  max-width: 26px;
  border-radius: 3px 3px 0 0;
  background: linear-gradient(to top, var(--accent), #72d0f8);
}
/* 换个指标换个色：调用次数=主题蓝，Token=绿，一眼可辨 */
#detail-modal .dtu-chart.dtu-m-tokens .dtu-bar {
  background: linear-gradient(to top, var(--green), #8bd08e);
}
#detail-modal .dtu-bar-empty {
  height: 2px;
  background: var(--border);
}
#detail-modal .dtu-lb {
  font-size: 0.58rem;
  line-height: 1;
  color: var(--text-muted);
  white-space: nowrap;
}
#detail-modal .dtu-empty {
  padding: 1.6rem 0.8rem;
  text-align: center;
  font-size: 0.8rem;
  color: var(--text-muted);
}

@media (max-width: 600px) {
  #detail-modal .dtu-chart {
    gap: 2px;
  }
  #detail-modal .dtu-col {
    min-width: 15px;
  }
  #detail-modal .dtu-val {
    font-size: 0.54rem;
  }
  #detail-modal .dtu-lb {
    font-size: 0.54rem;
  }
  /* 手机上 3 个 Tab 会换行；控制区独占整行并改为竖排（指标一行、窗口一行），按钮等宽铺满
     （窄屏 .section-header 变成 column，故用 width + align-self 而不是 flex-basis 撑宽） */
  #detail-modal .dtu-ctrls {
    flex-direction: column;
    align-items: stretch;
    align-self: stretch;
    width: 100%;
    gap: 0.4rem;
  }
  #detail-modal .dtu-metrics,
  #detail-modal .dtu-ranges {
    width: 100%;
  }
  #detail-modal .dtu-metric,
  #detail-modal .dtu-range {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
  }
}

/* ════════════════════════════════════════════════════════════════
   Apikeys 管理页 · 总览统计卡片（API Keys 列表上方的 .stats-grid 三张卡）
   ────────────────────────────────────────────────────────────────
   1) 全部规则以 .pg-keys（该页 body 类）限定作用域：.stat-card /
      .stats-grid 仍被 loginstats、token-summary-grid 等复用，
      不能直接改全局定义；
   2) 只改样式，DOM 结构（keys-overview.js 的 content 模板）保持不变；
   3) 每张卡用 --stat-c / --stat-c-2 / --stat-c-soft 表达主题色，
      顶部条、图标徽章、数字渐变、进度条、活跃徽标全部复用，
      新增卡片只需补一条变量覆盖；
   4) 排版按「内容形态」分配，而不是三等分：概览卡（活跃 / 总 Keys）
      只有数字 + 占比 + 进度条 → 窄列；上游选用 / 当前并发两张卡是
      「数字 + 上游明细列表」→ 宽列，且内部再分双栏（左数字 / 右明细），
      明细因此能多露几行而卡片不额外变高。见 @media (min-width: 901px)。
   ════════════════════════════════════════════════════════════════ */

/* ── 网格：只保留「等高 + 下边距」，列数与各断点字号见下方媒体查询
      （媒体查询不增加优先级，凡在基础块里写死的列数/gap 都会盖掉
        前面 max-width 媒体查询的同名声明，故此处一律不写）── */
.pg-keys .stats-grid {
  align-items: stretch;
  margin-bottom: 1.15rem;
}

/* ── 卡片：左对齐 + 右上角主题色氛围光 ── */
.pg-keys .stat-card {
  --stat-c: var(--accent);
  --stat-c-2: #2196f3;
  --stat-c-soft: rgba(79, 195, 247, 0.12);
  display: flex;
  flex-direction: column;
  min-width: 0;
  /* 统一下限：三张卡内容形态不同（概览卡是「数字+占比+进度条」，
     两张明细卡是「数字+上游列表」），只靠内容撑高会让卡片时高时低。
     min-height 让多出来的高度交给卡内 grid 的 1fr 行吸收，
     数字仍 align-self:center，不会顶格。 */
  min-height: 118px;
  text-align: left;
  padding: 0.58rem 0.8rem 0.5rem;
  border-radius: 12px;
  background:
    radial-gradient(120% 88% at 100% 0%, var(--stat-c-soft), transparent 60%),
    var(--bg-card);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
.pg-keys .stat-card-upstream {
  --stat-c: var(--green);
  --stat-c-2: #43a047;
  --stat-c-soft: rgba(102, 187, 106, 0.12);
}
.pg-keys .stat-card-conc {
  --stat-c: var(--orange);
  --stat-c-2: #fb8c00;
  --stat-c-soft: rgba(255, 152, 0, 0.13);
}
.pg-keys .stat-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-light);
  box-shadow:
    0 10px 26px rgba(0, 0, 0, 0.3),
    0 0 0 1px var(--stat-c-soft);
}

/* ── 顶部主题条：3px，末端淡出 ── */
.pg-keys .stat-card::before {
  height: 3px;
  background: linear-gradient(
    90deg,
    var(--stat-c) 0%,
    var(--stat-c-2) 32%,
    transparent 88%
  );
  opacity: 0.85;
}

/* ── 卡片头：图标徽章 + 标签，左对齐 ── */
.pg-keys .stat-card-head {
  justify-content: flex-start;
  gap: 0.4rem;
  margin-bottom: 0.28rem;
}
.pg-keys .stat-ico {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 6px;
  font-size: 0.7rem;
  background: var(--stat-c-soft);
  box-shadow: inset 0 0 0 1px var(--stat-c-soft);
}
.pg-keys .stat-label {
  text-transform: none;
  letter-spacing: 0.02em;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--text-secondary);
}

/* ── 主数字：主题色渐变文字（align-self 让渐变跟随文字宽度） ── */
.pg-keys .stat-card .stat-num {
  align-self: flex-start;
  font-size: 1.32rem;
  font-weight: 750;
  line-height: 1.05;
  letter-spacing: -0.01em;
  background: linear-gradient(135deg, var(--stat-c), var(--stat-c-2));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ── 活跃占比胶囊（仅第 1 张卡） ── */
.pg-keys .stat-pct {
  align-self: flex-start;
  margin-top: 0.12rem;
  padding: 0.08rem 0.42rem;
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--stat-c);
  background: var(--stat-c-soft);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* ── 活跃率进度条：贴卡片底部，与右侧两卡的明细列表起点对齐 ── */
.pg-keys .stat-progress {
  margin-top: auto;
  height: 4px;
  background: rgba(255, 255, 255, 0.06);
}
.pg-keys .stat-progress-fill {
  background: linear-gradient(90deg, var(--stat-c), var(--stat-c-2));
  box-shadow: 0 0 10px var(--stat-c-soft);
}

/* ── 上游选用 / 并发明细：同样贴底，行改为胶囊数值 + 无分割线 ── */
.pg-keys .stat-sublist {
  margin-top: auto;
  padding-top: 0.28rem;
  border-top: 1px solid var(--border);
  max-height: 35px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-light) transparent;
}
.pg-keys .stat-sublist::-webkit-scrollbar {
  width: 6px;
}
.pg-keys .stat-sublist::-webkit-scrollbar-track {
  background: transparent;
}
.pg-keys .stat-sublist::-webkit-scrollbar-thumb {
  background: var(--border-light);
  border-radius: 999px;
}
.pg-keys .stat-subrow {
  padding: 0.1rem 0.3rem;
  font-size: 0.66rem;
  line-height: 1.35;
  border-radius: 6px;
}
.pg-keys .stat-subrow + .stat-subrow {
  border-top: 0;
}
.pg-keys .stat-subrow:hover {
  background: var(--stat-c-soft);
}
.pg-keys .stat-sub-val {
  min-width: 1.9rem;
  padding: 0.02rem 0.34rem;
  text-align: center;
  font-size: 0.62rem;
  font-weight: 600;
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.05);
  border-radius: 999px;
}
.pg-keys .stat-sub-live {
  color: #fff;
  background: var(--stat-c);
  box-shadow: 0 0 0 3px var(--stat-c-soft);
}
.pg-keys .stat-sub-empty {
  padding: 0.25rem 0;
  font-size: 0.66rem;
}

/* ── 桌面（>900px）：按内容分配列宽 + 卡片内部按内容分栏 ──
   宽度：概览卡 0.78 : 明细卡 1.11 : 明细卡 1.11（三等分是浪费，概览卡
         装不满、明细卡的列表却被挤窄）。
   卡内：明细卡改为「左侧大数字 / 右侧上游列表」双栏（竖线分隔），
         列表因此能多露几行，卡片整体高度不增加；
         概览卡改为「数字 + 占比胶囊同行，进度条贴底」。 */
@media (min-width: 901px) {
  .pg-keys .stats-grid {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.05fr) minmax(0, 1.05fr);
    gap: 0.9rem;
  }

  /* 数字随视口温和缩放：概览卡较窄，四位数的「活跃 / 总 Keys」
     用固定字号会顶到占比胶囊或换行 */
  .pg-keys .stat-card .stat-num {
    font-size: clamp(1.08rem, 1vw + 0.3rem, 1.38rem);
    white-space: nowrap;
  }

  /* 概览卡：标题独占一行、数字独占一行、占比徽标再一行，进度条贴底。
     （实测过「标题 + 徽标同行」：窄桌面下卡片只有 ~190px，标题会被
       徽标挤成「活跃 /」「总」「Keys」三行，故一律各占一行。）
     行高分配 auto 1fr auto auto —— 多余高度给数字行，数字居中不顶格。 */
  .pg-keys .stat-card-key {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr auto auto;
    grid-template-areas:
      'head'
      'num'
      'pct'
      'bar';
  }
  .pg-keys .stat-card-key .stat-card-head {
    grid-area: head;
    margin-bottom: 0;
  }
  .pg-keys .stat-card-key .stat-num {
    grid-area: num;
    align-self: center;
  }
  .pg-keys .stat-card-key .stat-pct {
    grid-area: pct;
    justify-self: start;
    margin-top: 0.12rem;
  }
  .pg-keys .stat-card-key .stat-progress {
    grid-area: bar;
    margin-top: 0.28rem;
  }

  /* 明细卡：左数字 / 右列表，列表换成左侧竖线分隔并撑满整块高度 */
  .pg-keys .stat-card-upstream,
  .pg-keys .stat-card-conc {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      'head head'
      'num  list';
    align-items: center;
    column-gap: 0.6rem;
  }
  .pg-keys .stat-card-upstream .stat-card-head,
  .pg-keys .stat-card-conc .stat-card-head {
    grid-area: head;
  }
  .pg-keys .stat-card-upstream .stat-num,
  .pg-keys .stat-card-conc .stat-num {
    grid-area: num;
    align-self: center;
    min-width: 1.9rem;
    text-align: center;
  }
  .pg-keys .stat-card-upstream .stat-sublist,
  .pg-keys .stat-card-conc .stat-sublist {
    grid-area: list;
    align-self: stretch;
    margin-top: 0;
    padding-top: 0;
    padding-left: 0.7rem;
    border-top: 0;
    border-left: 1px solid var(--border);
    /* 上限要 ≥ 卡内实际可拉伸高度（min-height 118px 减去 head 与内边距，
       约 78px），否则 align-self:stretch 被这条封住，卡片变高而列表不填充。
       每行约 18px ⇒ 86px 稳定露 4 行，第 5 行起滚动。 */
    max-height: 86px;
  }
}

/* ── 平板 / 手机：沿用既有「2 列 + 第 3 张整行」布局，只收敛留白与字号。
      本区块基础规则写在文件末尾，会盖掉前面媒体查询里的同名声明
      （媒体查询不增加优先级），故 2 列、gap、字号必须在此重新声明。── */
@media (max-width: 900px) {
  .pg-keys .stats-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
  }
  .pg-keys .stats-grid .stat-card:nth-child(3) {
    grid-column: 1 / -1;
  }
  .pg-keys .stat-card {
    padding: 0.52rem 0.62rem 0.44rem;
    border-radius: 11px;
    /* 手机端跟随内容收敛，避免沿用桌面的 118px 把 2 列布局撑得过空 */
    min-height: 100px;
  }
  .pg-keys .stat-card .stat-num {
    font-size: 1.15rem;
  }
  .pg-keys .stat-ico {
    width: 18px;
    height: 18px;
    font-size: 0.62rem;
  }
  .pg-keys .stat-label {
    font-size: 0.66rem;
  }
  /* 明细只露 2 行（≤600px 同样值，故不再单独声明），靠滚动看更多 */
  .pg-keys .stat-sublist {
    max-height: 35px;
  }
  /* 覆盖本页旧规则 `.pg-keys .stats-grid .stat-card:nth-child(3) .stat-sublist
     { max-height: 150px }`（那条是上一版「第 3 张占满整行、多露几行」留下的，
     特异性 4 高于上面的 2，不覆盖会让第 3 张卡比另两张高出一截） */
  .pg-keys .stats-grid .stat-card:nth-child(3) .stat-sublist {
    max-height: 35px;
  }
  /* 触摸场景不要悬浮位移，改用按压缩放反馈 */
  .pg-keys .stat-card:hover {
    transform: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
  }
  .pg-keys .stat-card:active {
    transform: scale(0.985);
  }
}

@media (max-width: 600px) {
  .pg-keys .stats-grid {
    gap: 0.4rem;
  }
  .pg-keys .stat-card .stat-num {
    font-size: 1.05rem;
  }
  .pg-keys .stat-card-head {
    gap: 0.35rem;
    margin-bottom: 0.22rem;
  }
}

@media (max-width: 380px) {
  .pg-keys .stats-grid {
    gap: 0.3rem;
  }
  .pg-keys .stat-card {
    padding: 0.45rem 0.5rem 0.4rem;
  }
  .pg-keys .stat-card .stat-num {
    font-size: 0.95rem;
  }
}

/* ── 特级上游统计（v3.4.5）────────────────────────────────────────
   页面：上游管理 → ⭐ 特级上游 → 📊 调用统计。
   为什么不复用 .table-wrap：全局是 overflow-x:hidden（普通列表靠它防抖动），
   而统计表有 9 列、窄屏必须能左右滚 —— 只在本页用专用类覆盖，不动全局。 */
.prem-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(172px, 1fr));
  gap: 10px;
  margin: 2px 0 18px;
}
.prem-stat-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(127, 127, 127, 0.055);
  padding: 10px 12px;
  min-width: 0;
}
.prem-stat-label {
  display: block;
  font-size: 11.5px;
  color: #8f8f8f;
  margin-bottom: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prem-stat-value {
  display: block;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 700;
  color: #e8e8e8;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prem-stat-value small {
  font-size: 12px;
  font-weight: 600;
  color: #9aa0a6;
  margin-left: 5px;
}
.prem-stat-card.is-good .prem-stat-value {
  color: #66bb6a;
}
.prem-stat-card.is-warn .prem-stat-value {
  color: #ffb74d;
}
.prem-stats-title {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  margin: 18px 0 8px;
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--text-primary);
}
.prem-stats-title .muted {
  font-weight: 400;
  font-size: 11.5px;
  color: #8f8f8f;
}
/* 横向滚动容器：单元格一律不换行（数字被挤成两行比要滚动更难读） */
.prem-stats-scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  -webkit-overflow-scrolling: touch;
}
.prem-stats-scroll table {
  min-width: 880px;
}
.prem-stats-scroll th,
.prem-stats-scroll td {
  white-space: nowrap;
}
/* 占位表 / 原因表列少，不需要 880px 的最小宽度（否则平白多出滚动条） */
.prem-stats-scroll.is-narrow table {
  min-width: 0;
}
/* 占比：迷你条 + 百分比（只在同一分母内可比，见页脚口径） */
.prem-share {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.prem-share-bar {
  width: 52px;
  height: 5px;
  border-radius: 3px;
  background: rgba(127, 127, 127, 0.22);
  overflow: hidden;
  flex: 0 0 auto;
}
.prem-share-bar > i {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: #42a5f5;
}

/* ══ 一次调用一行 + 调用详情弹窗（v3.4.9）═════════════════════════════
   「Apikeys 记录」与「Key 详情 → 调用记录」都按 request_id 聚合成一行，
   点行打开详情弹窗。时间线**复用报错详情的 .errdbg-ev* 样式**（同一条视觉
   语言，不要再造一套），这里只补：可点击行、段数徽章、摘要/指标条、
   时间线里的正文就地展开块。
   ------------------------------------------------------------------ */
.call-row {
  cursor: pointer;
}
.call-row:hover td {
  background: rgba(79, 195, 247, 0.08);
}
/* 段数徽章：只在「本次调用被切成多段」时出现 —— 它同时是「扣了几次配额」的提示 */
.call-legs {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 183, 77, 0.5);
  background: rgba(255, 183, 77, 0.12);
  color: #ffb74d;
  font-size: 0.68rem;
  line-height: 1.4;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  vertical-align: middle;
}

.calldbg {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
/* ── 头部：一句话回答「什么时间 / 什么模型 / 花了多久 ──
   左侧状态徽章 + 完整时刻，右侧总耗时（唯一需要一眼看到的数字）。 */
.calldbg-head {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.6rem 0.8rem;
}
.calldbg-head-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text-primary);
}
.calldbg-when {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88rem;
  color: var(--text-primary);
}
.calldbg-total {
  margin-left: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.15rem;
  font-weight: 700;
  color: #4fc3f7;
  font-variant-numeric: tabular-nums;
}
.calldbg-head-sub {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.9rem;
  margin-top: 0.35rem;
  font-size: 0.78rem;
  color: var(--text-muted);
}
.calldbg-kv > i {
  font-style: normal;
  color: var(--text-muted);
  margin-right: 0.25rem;
}
.calldbg-kv > b {
  font-weight: 600;
  color: var(--text-primary);
}
.calldbg-kv > b > small {
  font-weight: 400;
  color: var(--text-muted);
  margin-left: 0.2rem;
}
.calldbg-mono,
.calldbg-hop-model {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.calldbg-badge {
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  border: 1px solid transparent;
}
.calldbg-badge.is-ok {
  color: #66bb6a;
  border-color: rgba(102, 187, 106, 0.45);
  background: rgba(102, 187, 106, 0.12);
}
.calldbg-badge.is-bad {
  color: #ef5350;
  border-color: rgba(239, 83, 80, 0.45);
  background: rgba(239, 83, 80, 0.12);
}
.calldbg-err-entry {
  border-left: 3px solid var(--danger, #ef4444);
  background: rgba(239, 68, 68, 0.08);
  border-radius: 6px;
  padding: 0.5rem 0.7rem;
  font-size: 0.82rem;
  color: var(--text-primary);
}
.calldbg-err-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-left: 0.35rem;
  vertical-align: middle;
}
/* 「失败但查不到归因」：中性提示，不要用红色 —— 它不是一次新的故障，只是说明记录缺失 */
.calldbg-err-entry.is-quiet {
  border-left-color: var(--border);
  background: rgba(255, 255, 255, 0.03);
  color: var(--text-muted);
}
.calldbg-bill-tip {
  margin-top: 0.5rem;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  background: rgba(255, 183, 77, 0.1);
  border: 1px dashed rgba(255, 183, 77, 0.45);
  font-size: 0.78rem;
  color: #ffb74d;
}
/* ── 调用路径：复用报错详情的 .errdbg-ev 竖轴（同一条视觉语言，不另造一套）──
   一跳 = .calldbg-leg（编号圆环 + 上游/模型 + 耗时标签），
   跳与跳之间 = .calldbg-jump（⇄/↪ + 为什么换上游）。 */
.calldbg-path {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.7rem 0.9rem 0.8rem;
}
.calldbg-path-title {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
}
/* 路径不该被裁：.errdbg-evs 默认 max-height:32vh + 内部滚动，那是给「过程事件」用的 */
.calldbg-evs {
  max-height: none;
  overflow: visible;
}
/* pre 展开块要独占一行 ⇒ 段行必须允许换行（.errdbg-ev 默认不 wrap） */
.calldbg-leg {
  flex-wrap: wrap;
}
.calldbg-leg .errdbg-ev-main {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem;
}
.calldbg-hop-model {
  font-size: 0.75rem;
  color: #4fc3f7;
  border: 1px solid rgba(79, 195, 247, 0.35);
  border-radius: 4px;
  padding: 0 0.25rem;
}
.calldbg-leg.is-ok .errdbg-ev-icon {
  border-color: rgba(102, 187, 106, 0.6);
  color: #66bb6a;
}
.calldbg-leg.is-bad .errdbg-ev-icon {
  border-color: rgba(239, 83, 80, 0.6);
  color: #ef5350;
}
/* 成功/失败标签：颜色之外还有文字，不靠颜色单独表达状态 */
.errdbg-ev-tag.is-ok {
  color: #66bb6a;
  border-color: rgba(102, 187, 106, 0.4);
}
.errdbg-ev-tag.is-bad {
  color: #ef5350;
  border-color: rgba(239, 83, 80, 0.4);
}
/* 路径上的「换跳原因」：弱化（它是注释，不是主角），但保留完整句 */
.calldbg-jump .calldbg-jump-text {
  flex: 1 0 100%;
  font-size: 0.75rem;
  color: var(--text-muted);
  line-height: 1.5;
  word-break: break-word;
}
.calldbg-jump .errdbg-ev-icon {
  font-size: 0.7rem;
}
.calldbg-body-link {
  font-size: 0.7rem;
  color: #4fc3f7;
  border: 1px solid rgba(79, 195, 247, 0.4);
  border-radius: 999px;
  padding: 0 0.4rem;
  cursor: pointer;
  white-space: nowrap;
}
.calldbg-body-link:hover {
  background: rgba(79, 195, 247, 0.12);
}
/* 正文就地展开：占满整行、限高可滚动（单段可达 MB 级） */
.calldbg-body-pre {
  flex: 1 0 100%;
  margin: 0.35rem 0 0.1rem;
  max-height: 40vh;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem 0.6rem;
  font-size: 0.75rem;
  color: var(--text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
/* 时间线里事件与段混排时，事件略弱化，避免抢段的注意力 */
.calldbg-event .errdbg-ev-main {
  color: var(--text-muted);
}

/* ── 技术细节（默认折叠）───────────────────────────────────────────
   请求 ID / IP / 链路快照 / 原始过程事件都放这里：排障时才展开，
   首屏只留「时间 / 模型 / 耗时 / 路径」，避免九宫格把重点挤下去。 */
.calldbg-more {
  border: 1px dashed var(--border);
  border-radius: 10px;
  padding: 0.45rem 0.8rem;
  background: transparent;
}
.calldbg-more > summary {
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--text-muted);
  list-style: none;
  user-select: none;
}
.calldbg-more > summary::-webkit-details-marker {
  display: none;
}
.calldbg-more > summary::before {
  content: '▸';
  display: inline-block;
  margin-right: 0.35rem;
  transition: transform 0.15s ease;
}
.calldbg-more[open] > summary::before {
  transform: rotate(90deg);
}
.calldbg-more > summary:hover {
  color: var(--text-primary);
}
.calldbg-more-title {
  margin: 0.7rem 0 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
}
@media (max-width: 600px) {
  /* 窄屏：耗时换到下一行，避免把「状态 + 时间」挤成两行碎字 */
  .calldbg-total {
    margin-left: 0;
    width: 100%;
  }
  .calldbg-head-line {
    font-size: 0.88rem;
  }
}

/* ══ ⚡ 并发查看弹窗（v3.4.19）════════════════════════════════════════
   只服务 keys/overview 页的 #conc-view-modal。
   ⚠️ 不复用 .keys-table：那张表带 min-width / 逐列宽度历史包袱，且 ≤600px 会被
   全局规则 display:none（那是给本页主列表切卡片的），弹窗里用会直接消失。
   故这里自成一套 .cv-* 类，作用域清晰、不与任何页面互相干扰。 */
.conc-view-modal {
  max-width: 900px;
}
.cv-sub {
  margin: 0 0 0.9rem;
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--text-secondary);
}
.cv-sub b {
  color: var(--orange, #ffa726);
}
.cv-summary {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.6rem;
  margin-bottom: 0.9rem;
}
.cv-sum-item {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
}
.cv-sum-label {
  font-size: 0.72rem;
  color: var(--text-muted);
}
.cv-sum-item b {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--accent, #4fc3f7);
  font-variant-numeric: tabular-nums;
}
.cv-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.7rem;
}
.cv-auto {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-right: auto;
  font-size: 0.78rem;
  color: var(--text-secondary);
  cursor: pointer;
}
.cv-table-wrap {
  max-height: 52vh;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
}
.cv-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
}
.cv-table th,
.cv-table td {
  padding: 0.45rem 0.6rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}
.cv-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg-card);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-muted);
}
.cv-table th.num,
.cv-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.cv-table tbody tr:last-child td {
  border-bottom: none;
}
.cv-idx {
  width: 2.5rem;
  color: var(--text-muted);
}
.cv-name {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cv-up {
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-secondary);
}
.cv-bar {
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.cv-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #26c6da, #4fc3f7);
  transition: width 0.3s ease;
}
.cv-bar-fill.cv-bar-full {
  background: linear-gradient(90deg, #ffa726, #ef5350);
}
.cv-empty {
  padding: 1.4rem 0.6rem !important;
  text-align: center !important;
  color: var(--text-muted);
}
.cv-foot {
  margin: 0.7rem 0 0;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--text-muted);
}
@media (max-width: 700px) {
  .cv-summary {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .conc-view-modal {
    padding: 1rem 0.8rem;
  }
}

