/* app.css 自定义组件层（Tailwind 之外的少量补充）。
 * 设计令牌在 theme.css；这里只放 Tailwind utility 覆盖不到的东西。 */

/* 全局兜底：库/组件样式可能覆盖 UA 的 hidden —— 勿删 */
[hidden] { display: none !important; }

/* 滚动条全局隐藏：滚动功能保留，滚动条一律不显示（设计稿无滚动条元素）。
 * Firefox 用 scrollbar-width，Chrome/Edge 用 ::-webkit-scrollbar。 */
* { scrollbar-width: none; }
*::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* 按钮基础（设计稿 btn btn-primary/secondary/text） */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 500; line-height: 1;
  border-radius: var(--apple-radius-md);
  cursor: pointer; user-select: none;
  transition: opacity .15s, background-color .15s, color .15s;
  white-space: nowrap;
}
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: var(--primary); color: var(--primary-foreground); }
.btn-primary:hover:not(:disabled) { opacity: .9; }
.btn-secondary {
  background: var(--secondary); color: var(--secondary-foreground);
  border: 1px solid var(--border);
}
.btn-secondary:hover:not(:disabled) { background: var(--accent); }
.btn-text { background: transparent; color: var(--muted-foreground); }
.btn-text:hover:not(:disabled) { background: var(--secondary); color: var(--foreground); }

/* 输入框（设计稿 field/control） */
.field {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--card); border: 1px solid var(--input);
  border-radius: var(--apple-radius-md);
  padding: 0 12px; height: 32px;
  transition: border-color .15s, box-shadow .15s;
}
.field:focus-within { border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 18%, transparent); }
.field .control {
  flex: 1; min-width: 0; height: 100%;
  background: transparent; border: none; outline: none;
  font-size: 13px; color: var(--foreground);
  font-family: inherit;
}
.field .control::placeholder { color: var(--muted-foreground); }
.field .icon { color: var(--muted-foreground); display: inline-flex; }

/* 表格内 textarea 型 field（聊天输入框，高度自适应） */
.field--area { height: auto; padding: 12px 16px; align-items: stretch; }
.field--area .control { height: auto; resize: none; font-size: 14px; line-height: 1.6; }

/* 输入框内嵌发送按钮：常态只留图标，聚焦才展开"发送"二字 */
.composer { position: relative; display: flex; width: 100%; }
.composer .control { padding-bottom: 36px; }
.composer-send {
  position: absolute; right: 10px; bottom: 10px;
  height: 32px; padding: 0 9px; gap: 0; justify-content: center;
  transition: opacity .15s, background-color .15s, color .15s, padding .18s ease, gap .18s ease;
}
.composer-send .lbl {
  max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap;
  transition: max-width .18s ease, opacity .18s ease;
}
.composer-send:focus { padding: 0 14px; gap: 6px; }
.composer-send:focus .lbl { max-width: 48px; opacity: 1; }

/* 开关（设计稿 peer toggle，手写避免依赖 peer 类细节）。
 * 选中态是品牌蓝不是绿色——绿色在本系统里专用于"额度充足/签到成功"，
 * 开关跟着变绿会让一列参数看起来像一排状态灯。 */
.tgl { position: relative; display: inline-flex; cursor: pointer; flex-shrink: 0; }
.tgl input { position: absolute; opacity: 0; pointer-events: none; }
.tgl .knob {
  width: 36px; height: 20px; border-radius: 999px;
  background: var(--background-400); transition: background-color .2s;
}
.tgl .knob::after {
  content: ""; position: absolute; left: 2px; top: 2px;
  width: 16px; height: 16px; border-radius: 999px;
  background: var(--background-50); box-shadow: var(--shadow-xs);
  transition: transform .2s;
}
.tgl input:checked + .knob { background: var(--primary); }
.tgl input:checked + .knob::after { transform: translateX(16px); }

/* 单选卡（调度模式选择） */
.modecard { border: 1px solid var(--border); border-radius: var(--apple-radius-md); cursor: pointer; transition: border-color .15s, background-color .15s; }
.modecard:hover { border-color: var(--icon-muted); }
.modecard.is-active { border-color: var(--primary); background: var(--brand-50); }
.dark .modecard.is-active { background: color-mix(in srgb, var(--brand-400) 12%, var(--card)); }

/* 聊天气泡打字动画（设计稿三点 pulse）
   必须用 :empty 只命中三个空 span：写成 .typing span 会连"生成中"那个带文字的
   span 一起压成 6px 宽，中文被迫一字一行竖排。 */
.typing span:empty {
  width: 6px; height: 6px; border-radius: 999px;
  background: var(--muted-foreground);
  display: inline-block;
  animation: tw2a-pulse 1.2s ease-in-out infinite;
}
.typing span:empty:nth-child(2) { animation-delay: .15s; }
.typing span:empty:nth-child(3) { animation-delay: .3s; }
@keyframes tw2a-pulse {
  0%, 60%, 100% { transform: translateY(0); opacity: .4; }
  30% { transform: translateY(-3px); opacity: 1; }
}

/* 折叠思考块（聊天 reasoning）：气泡上方、默认展开、限高 + 可完全展开 */
.reasoning { border-left: 2px solid var(--border); padding-left: 10px; margin: 2px 0 8px; }
.reasoning summary {
  cursor: pointer; font-size: 11px; color: var(--muted-foreground);
  font-family: var(--font-mono); user-select: none;
}
.reasoning .rbody {
  font-size: 12.5px; color: var(--muted-foreground); white-space: pre-wrap; margin-top: 4px;
  max-height: 240px; overflow-y: auto; overscroll-behavior: contain;
}
.reasoning.is-full .rbody { max-height: none; overflow-y: visible; }
.rmore {
  margin-top: 4px; padding: 0; border: none; background: none; cursor: pointer;
  font: 11px/1.4 var(--font-mono); color: var(--muted-foreground);
}
.rmore:hover { color: var(--foreground); text-decoration: underline; }

/* toast 通知（右下角栈） */
#toasts { position: fixed; right: 16px; bottom: 16px; z-index: 90; display: flex; flex-direction: column; gap: 8px; }
.toast {
  min-width: 240px; max-width: 380px;
  background: var(--popover); color: var(--popover-foreground);
  border: 1px solid var(--border); border-radius: var(--apple-radius-md);
  box-shadow: var(--shadow-lg);
  padding: 10px 14px; font-size: 13px; line-height: 1.5;
  display: flex; gap: 8px; align-items: flex-start;
  animation: toast-in .2s ease-out;
}
.toast .t-title { font-weight: 600; }
.toast--ok .t-dot { color: var(--state-success); }
.toast--err .t-dot { color: var(--state-error); }
.toast--info .t-dot { color: var(--primary); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* 模态（登录门禁/确认框/登录流） */
.backdrop {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(0,0,0,.4);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
  animation: fade-in .15s ease-out;
}
.modal {
  width: 100%; max-width: 440px;
  background: var(--card); color: var(--card-foreground);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-2xl);
  animation: modal-in .18s ease-out;
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in { from { opacity: 0; transform: translateY(12px) scale(.98); } to { opacity: 1; transform: none; } }

/* 右侧抽屉 */
.drawer-bd { position: fixed; inset: 0; z-index: 70; background: rgba(0,0,0,.32); animation: fade-in .15s ease-out; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 71;
  width: min(460px, 92vw);
  background: var(--card); color: var(--card-foreground);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-xl);
  overflow-y: auto;
  animation: drawer-in .2s ease-out;
}
@keyframes drawer-in { from { transform: translateX(40px); opacity: 0; } to { transform: none; opacity: 1; } }

/* 行操作浮动菜单 */
#rowMenu {
  position: fixed; z-index: 60;
  background: var(--popover); color: var(--popover-foreground);
  border: 1px solid var(--border); border-radius: var(--apple-radius-md);
  box-shadow: var(--shadow-lg);
  min-width: 160px; padding: 4px;
  display: flex; flex-direction: column;
}
#rowMenu .mi {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: var(--apple-radius-sm);
  font-size: 13px; cursor: pointer; background: none; border: none;
  color: inherit; text-align: left; width: 100%;
}
#rowMenu .mi:hover { background: var(--accent); }
#rowMenu .mi--danger { color: var(--destructive); }
#rowMenu .mi--danger:hover { background: var(--state-error-surface); }

/* 汇总卡进度条（延迟/额度） */
.meter { height: 6px; border-radius: 999px; background: var(--secondary); overflow: hidden; }
.meter > i { display: block; height: 100%; border-radius: 999px; background: var(--primary); }

/* 骨架屏 */
.skel { position: fixed; inset: 0; z-index: 100; background: var(--background); display: flex; align-items: center; justify-content: center; }
.skel .sk {
  width: 42px; height: 42px; border-radius: 50%;
  border: 3px solid var(--secondary); border-top-color: var(--primary);
  animation: sk-rotate .8s linear infinite;
}
@keyframes sk-rotate { to { transform: rotate(360deg); } }

/* 登录门禁抖动 */
.shake { animation: shake .4s; }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-8px); }
  75% { transform: translateX(8px); }
}

/* usage JSON 原文 */
pre.usage {
  background: var(--secondary); border-radius: var(--apple-radius-sm);
  padding: 10px 12px; font-size: 11px; line-height: 1.6;
  font-family: var(--font-mono); overflow-x: auto;
  color: var(--foreground); white-space: pre-wrap; word-break: break-all;
}

/* 请求详情：上游错误原文。
   max-height 与 .rbody（240px）同档保持一致；可滚动，长错误体不撑爆抽屉。
   title 属性给浏览器原生悬停全文——短文本悬停看不出差别，正是长文本才需要它。 */
.log-detail {
  max-height: 240px; overflow-y: auto; overscroll-behavior: contain;
  background: var(--state-error-surface); color: var(--state-error);
  border-radius: var(--apple-radius-sm);
  padding: 10px 12px; font-size: 11.5px; line-height: 1.6;
  font-family: var(--font-mono); white-space: pre-wrap; word-break: break-all;
}
.log-detail-hd { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
/* 真被截断时的说明：只在 detail 以 "…" 结尾时出现，不静默切掉一截 */
.log-detail-trunc { font-size: 10.5px; color: var(--muted-foreground); }

/* 上游角标：颜色只允许写入 --bc（safeColor 白名单），由 color-mix 提亮 */
.badge {
  display: inline-flex; align-items: center; height: 18px; padding: 0 7px;
  border-radius: 999px; font-size: 10px; font-weight: 500; line-height: 1;
  background: color-mix(in srgb, var(--bc, var(--primary)) 14%, transparent);
  color: var(--bc, var(--primary));
}

/* 减少动效偏好 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* 视图容器是 flex-col + overflow-y-auto：直接子块禁止被 flex 压缩
 * （shrink 默认 1 会把超高的卡片压扁、内部 overflow:hidden 裁内容，整页却不滚——
 * 必须让内容保持自然高度，溢出交给视图层滚动）。min-height:auto 的默认值防不住这个。
 * 例外：带 flex-1 的子块（模型视图的卡片）本身要占满剩余空间、由内部滚动。 */
.view.flex > *:not(.flex-1) { flex-shrink: 0; }

/* 表内滚动：表头吸顶（sticky 挂在 th 上，thead/tr 上部分浏览器不生效） */
.tblsticky thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--secondary);
  box-shadow: inset 0 -1px 0 var(--border); /* 吸顶时与表体的分隔线 */
}

/* 数值强调（mono 数字 400 字重太细，尤其暗色下；数值类展示统一 500 + 前景亮色） */
.num {
  font-weight: 500;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
}

/* 自定义下拉（替代原生 select：字号/暗色/展开面板全走设计令牌） */
.dd { position: relative; display: inline-flex; }
.dd-btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 10px; min-width: 0;
  background: var(--card); color: var(--foreground);
  border: 1px solid var(--input);
  border-radius: var(--apple-radius-md);
  /* line-height 不能是 1：13px 字号下 .dd-val 的行盒只有 13px，而字形实际占 19px，
     叠加 .dd-val 的 overflow:hidden 会把文字底部裁掉 3px（实测）。 */
  font-size: 13px; font-weight: 500; line-height: 1.5;
  cursor: pointer; user-select: none; white-space: nowrap;
  transition: border-color .15s, box-shadow .15s;
}
/* 紧凑档：嵌在参数面板里，要和 28px 高 / 80px 宽的数字输入框对齐；
   width:100% 让按钮填满 .dd 声明的宽度，否则按钮按内容收缩会留右侧空隙、右边缘对不齐 */
.dd--sm .dd-btn { width: 100%; height: 28px; font-size: 12px; padding: 0 8px; }
.dd-btn:hover { border-color: var(--ring); }
.dd.open .dd-btn { border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 18%, transparent); }
.dd-btn .dd-caret { color: var(--muted-foreground); display: inline-flex; transition: transform .15s; }
.dd.open .dd-btn .dd-caret { transform: rotate(180deg); }
.dd-btn .dd-val { overflow: hidden; text-overflow: ellipsis; }
.dd-panel {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 65;
  min-width: 100%; max-width: min(360px, 86vw);
  max-height: 300px; overflow-y: auto;
  background: var(--popover); color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--apple-radius-md);
  box-shadow: var(--shadow-lg);
  padding: 4px;
  display: none;
}
.dd.open .dd-panel { display: block; animation: dd-in .12s ease-out; }
@keyframes dd-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.dd-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 10px; border-radius: var(--apple-radius-sm);
  font-size: 13px; cursor: pointer; white-space: nowrap;
}
.dd-opt:hover { background: var(--accent); }
.dd-opt.is-on { color: var(--primary); font-weight: 600; }
.dd-opt .dd-sub { font-size: 11px; color: var(--muted-foreground); font-family: var(--font-mono); }
/* 右缘对齐变体（菜单往左展开，防顶栏溢出） */
.dd--right .dd-panel { left: auto; right: 0; }

/* 行/按钮的 hover 反馈只能写在这里，不能用 tailwind 的 hover: 工具类：
 * vendor 的 tailwind-browser 只扫首屏静态 HTML、不观察 DOM 变化，而
 * hover:bg-[var(--accent)] / hover:bg-[var(--secondary)] 这类串只出现在 app*.js 的
 * 模板字符串里（实测 7 + 3 处），规则从未生成过 —— 这些 hover 一直静默失效。
 * .hov:hover 特异性 (0,2,0) 高于 tailwind 的 .bg-[...] (0,1,0)，
 * 所以"激活行被 hover"照样有反馈，与两张表的先后顺序无关。 */
.hov:hover { background: var(--accent); }
.hov-btn:hover { background: var(--secondary); color: var(--foreground); }

/* ---------------------------------------------------------------------------
 * 侧栏导航：分组小标题 + 浅灰药丸激活态
 * 激活态必须是 .is-on 而不是 tailwind 工具类：vendor 的 tailwind-browser 只在
 * 首屏扫一遍静态 HTML、不观察 DOM 变化，app.js setView 动态 add 的
 * bg-[var(--sidebar-accent)] 从来不会生成规则（实测整张注入表只有 31 条规则，
 * 且给活元素加 text-[17px] 计算值不变）——那个高亮在改样式之前就是坏的。
 * ------------------------------------------------------------------------- */
.nav-group {
  padding: 14px 10px 5px;
  font-size: 11px; font-weight: 600; letter-spacing: .02em;
  color: var(--icon-muted); user-select: none;
  flex-shrink: 0;
}
.nav-group:first-child { padding-top: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; height: 34px; padding: 0 10px;
  /* 侧栏 nav 是 flex-col + overflow-y-auto：不钉住 shrink 的话，窗口一矮
   * 六个导航项会被压成两行高的扁条（和 .view 那条同一个坑），而不是出滚动条。 */
  flex-shrink: 0;
  border: none; background: none; cursor: pointer; text-align: left;
  border-radius: var(--apple-radius-md);
  font-size: 13px; font-weight: 500; color: var(--sidebar-foreground);
  transition: background-color .12s, color .12s;
}
/* hover 比激活态浅一档，且导航项之间留 4px 间距：原先两者同色又零间距，
 * 鼠标扫到激活项上下相邻那一项时两块同色药丸会连成一整条色块（用户实拍反馈），
 * 分不清哪个才是当前视图。这里刻意用两个语义令牌而不是灰阶原语或 color-mix
 * ——原语在暗色下不翻转（--background-100 会变近白闪一下），color-mix 算出的
 * #fafafb 在纯白上又几乎看不见；--secondary/--accent 两套主题各自都成立。 */
.nav-item:hover { background: var(--secondary); }
.nav-item.is-on, .nav-item.is-on:hover { background: var(--accent); color: var(--sidebar-accent-foreground); font-weight: 600; }
.nav-item.is-on svg { color: var(--sidebar-foreground); }
.nav-item svg { width: 15px; height: 15px; stroke-width: 1.9; color: var(--icon-muted); flex-shrink: 0; }

/* 左下角账号菜单：头像行常驻，主题/退出收进上弹浮层（参考稿的 UID 菜单） */
.um-row { position: relative; }
.um-btn {
  display: flex; align-items: center; gap: 9px;
  width: 100%; height: 40px; padding: 4px 8px;
  border: 1px solid var(--border); background: var(--card); cursor: pointer;
  border-radius: var(--apple-radius-md);
  transition: background-color .12s, border-color .12s;
}
.um-btn:hover, .um-btn.is-open { background: var(--secondary); }
.um-btn > svg { width: 14px; height: 14px; stroke-width: 1.9; color: var(--icon-muted); flex-shrink: 0; }
.um-avatar {
  width: 26px; height: 26px; border-radius: var(--apple-radius-sm); flex-shrink: 0;
  background: var(--primary); color: var(--primary-foreground);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600;
}
.um-pop {
  position: absolute; left: 0; right: 0; bottom: calc(100% + 6px); z-index: 62;
  background: var(--popover); color: var(--popover-foreground);
  border: 1px solid var(--border); border-radius: var(--apple-radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 5px; display: flex; flex-direction: column; gap: 1px;
  animation: dd-in .12s ease-out;
}
.um-item {
  display: flex; align-items: center; gap: 8px;
  width: 100%; height: 32px; padding: 0 8px;
  border: none; background: none; cursor: pointer; text-align: left;
  border-radius: var(--apple-radius-sm);
  font-size: 13px; color: inherit;
}
.um-item:hover { background: var(--accent); }
.um-item svg { width: 14px; height: 14px; stroke-width: 1.9; color: var(--icon-muted); flex-shrink: 0; }
.um-item--danger { color: var(--destructive); }
.um-item--danger svg { color: var(--destructive); }
.um-sep { height: 1px; margin: 5px 0; background: var(--border); }


/* ---- 通用小件：纯图标操作钮 / 浅灰药丸按钮 ----
 * 全部走 app.css 而不是 tailwind 任意值：vendor 的 tailwind-browser 只扫首屏
 * 静态 HTML、不观察 DOM 变化，只出现在 JS 模板里的类永远生成不出规则。 */
.icobtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; flex-shrink: 0;
  border: none; background: none; cursor: pointer;
  border-radius: var(--apple-radius-sm);
  color: var(--muted-foreground);
  transition: background-color .12s, color .12s, opacity .12s;
}
.icobtn:hover { background: var(--accent); color: var(--foreground); }
.icobtn svg { width: 14px; height: 14px; stroke-width: 1.9; }
.icobtn--danger:hover { color: var(--destructive); background: var(--state-error-surface); }
/* 删除的两段式确认：第一下把垃圾桶换成警示态（配色常驻，不靠 hover 才看得出） */
.icobtn--armed, .icobtn--armed:hover { color: var(--destructive); background: var(--state-error-surface); }
/* 状态型图标钮（如"可返回"）：亮 = 开，淡 = 关，不用文字也能读出两态 */
.icobtn.is-on { color: var(--primary); }
.icobtn.is-off { opacity: .38; }

.btn-ghost {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px; white-space: nowrap;
  background: var(--secondary); color: var(--secondary-foreground);
  border: none; border-radius: var(--apple-radius-md);
  font-size: 13px; font-weight: 500; line-height: 1; cursor: pointer;
  transition: background-color .12s, color .12s;
}
.btn-ghost:hover:not(:disabled) { background: var(--accent); }
.btn-ghost:disabled { opacity: .45; cursor: not-allowed; }
.btn-ghost svg { width: 13px; height: 13px; stroke-width: 1.9; }

/* ---- 自定义平台（app4.js）：平台组 ----
 * 参考稿的关键不是"卡片"，而是**没有卡片**：组头就是页面上的两行普通文字，
 * 成员列表是一块浅灰圆角矩形，除此之外不描边、不阴影、不包白卡。
 * 第一版给每个平台套了白卡 + 列头 + 每行三个控件，密度一上来就完全不像了，
 * 所以行上只留"名字 + 编辑 + 开关"，上下文/输出上限/是否下发/删除
 * 全部收进铅笔弹窗（渐进披露）——留白是省不出来的，只能搬走。 */
.gwcol { width: 100%; max-width: 760px; margin-inline: auto; }  /* 封顶 + 居中：不封顶会拉成整页宽，不居中则整块贴左 */
.gwgroup + .gwgroup { margin-top: 30px; }
.gwg-head { display: flex; align-items: flex-start; gap: 10px; padding: 0 2px 10px; }
.gwg-title { font-size: 14px; font-weight: 600; color: var(--card-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gwg-sub { margin-top: 3px; font-size: 11.5px; font-family: var(--font-mono); color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gwg-acts { margin-left: auto; display: flex; align-items: center; gap: 2px; flex-shrink: 0; }

.gwg-body { background: var(--secondary); border-radius: var(--apple-radius-lg); overflow: hidden; }
/* 一块灰底 + 挂在它下沿的那个入口，读起来是一组；拆成两个 body 子项就被 20px 行距冲散 */
.gwg-block { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.gwg-block > .gwl { align-self: flex-start; }
.gwm-row { display: flex; align-items: center; gap: 12px; padding: 11px 14px; }
.gwm-row + .gwm-row { border-top: 1px solid var(--border); }
.gwm-row--off { opacity: .5; }        /* 停用的模型整行压暗，不用读开关也看得出 */
.gwm-name { min-width: 0; flex: 1; display: flex; align-items: baseline; gap: 8px; }
.gwm-id { min-width: 0; font-size: 13px; font-family: var(--font-mono); color: var(--card-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gwm-dim { min-width: 0; font-size: 12px; color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gwm-acts { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.gwm-tgl { display: flex; align-items: center; }
.gwg-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding-top: 12px; }
.gwg-empty { padding: 16px 14px; font-size: 12.5px; color: var(--muted-foreground); text-align: center; }
.gwempty-card {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  text-align: center; padding: 40px 16px;
  background: var(--secondary); border-radius: var(--apple-radius-lg);
}

/* 组底的次级动作：参考稿只给了一个浅灰药丸（新增模型），其余降级成文字链，
 * 三个药丸并排会把视线从列表上抢走。 */
.gwl {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 2px; border: none; background: none; cursor: pointer;
  border-radius: var(--apple-radius-sm);
  font-size: 12.5px; color: var(--muted-foreground);
  transition: color .12s;
}
.gwl:hover:not(:disabled) { color: var(--foreground); }
.gwl:disabled { opacity: .4; cursor: not-allowed; }
.gwl svg { width: 13px; height: 13px; stroke-width: 1.9; }
.gwl--inline { display: inline-flex; margin-left: 8px; vertical-align: -2px; }
/* 占位但不显示：藏掉弹窗页脚左边的"删除"时，右边的 取消/保存 不该跟着跳到左边。
 * tailwind 的 .invisible 只在 JS 里出现就生成不出规则（同 .hov 那批），所以落这里。 */
.invisible { visibility: hidden; }

/* 输入格：现在只有密钥弹窗那张表在用，所以是带描边的常规表单控件 */
.gwcell {
  min-width: 0; width: 100%; padding: 6px 8px;
  background: var(--card); border: 1px solid var(--input);
  border-radius: var(--apple-radius-sm);
  font-size: 12.5px; color: var(--foreground); font-family: inherit;
  transition: border-color .12s, box-shadow .12s;
}
.gwcell:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 18%, transparent); }
.gwcell--mono { font-family: var(--font-mono); }
.gwcell--num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }


/* 密钥弹窗里仍是一张规规矩矩的表：带列头、带输入框描边 */
.gwtable { overflow-x: auto; }
.gwhead, .gwrow { display: grid; align-items: center; gap: 12px; padding: 8px 12px; }
.gwhead { font-size: 11px; color: var(--muted-foreground); white-space: nowrap; }
.gwrow { border-top: 1px solid var(--border); }
.gwrow:first-child { border-top: none; }
.gwhead--keys, .gwrow--keys { grid-template-columns: minmax(104px, 1fr) minmax(104px, 1fr) minmax(190px, 1.6fr) 32px; min-width: 560px; }
.gwtable .gwcell { border-color: var(--input); background: var(--card); }
.gwtable .gwcell:focus { border-color: var(--ring); }

/* ---- 弹窗外壳（参考稿的"添加模型"对话框）----
 * 参考稿的干净来自三件事：标题下不挂副标题、字段不带灰色说明行、输入框够高。
 * 上一版三条全违了（一行一句 mono 说明 + 32px 输入框 + 全单列），所以"不太一样"。
 * 说明文字改成挂在控件的 title 上，需要时悬停才出现，不占版面。 */
.modal--dlg { display: flex; flex-direction: column; max-height: 86vh; padding: 0; overflow: hidden; }
.modal--dlg .field { height: 38px; border-radius: var(--apple-radius-md); }
.dlg-head { display: flex; align-items: center; gap: 12px; padding: 20px 22px 6px; flex-shrink: 0; }
.dlg-title { font-size: 16px; font-weight: 600; letter-spacing: -.01em; }
.dlg-sub { margin-top: 2px; font-size: 11.5px; font-family: var(--font-mono); color: var(--muted-foreground); }
.dlg-body { flex: 1; min-height: 0; overflow-y: auto; padding: 0 22px 8px; display: flex; flex-direction: column; gap: 20px; }
.dlg-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 18px 22px 20px; flex-shrink: 0; }
.dlg-prev { font-size: 11.5px; line-height: 1.6; font-family: var(--font-mono); white-space: pre-line; }
/* 上面那条 38px 是"两个 class"的特异性，会把 rows=4 的粘贴框一起钉死，
 * 所以这两条同特异性的后置规则是必需的：粘贴框回到自适应，表内输入框保持紧凑。 */
.modal--dlg .field--area { height: auto; }
.modal--dlg .gwrow .field { height: 32px; padding: 0 10px; }

.fld { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.fld > span { font-size: 13px; font-weight: 500; color: var(--card-foreground); }
.fld-lblrow { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.fld-lblrow > label { font-size: 13px; font-weight: 500; color: var(--card-foreground); }
.fld > .field { width: 100%; }
.fld > .field--area { height: auto; }
/* 两列并排（参考稿的 提供商 | 提供商名称）：窄屏退回单列，避免输入框被挤扁 */
.fld-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 560px) { .fld-2 { grid-template-columns: 1fr; } }
.fld-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.fld-row .fld-t { font-size: 13px; font-weight: 500; }


/* ---------------------------------------------------------------------------
   任务记录视图（app5.js）：类型徽标 / chips / 积分列。全部走 theme.css 既有令牌。
--------------------------------------------------------------------------- */
.tk-b {
  display: inline-flex; align-items: center; height: 20px; padding: 0 8px;
  border-radius: var(--apple-radius-sm); font-size: 11px; font-weight: 500;
  white-space: nowrap;
}
.tk-b--checkin  { background: var(--secondary); color: var(--secondary-foreground); }
.tk-b--growth   { background: var(--secondary); color: var(--muted-foreground); }
.tk-b--claim    { background: var(--state-success-surface); color: var(--state-success); }
.tk-b--ok       { background: var(--state-success-surface); color: var(--state-success); }
.tk-b--fail     { background: var(--state-error-surface); color: var(--state-error); }
.tk-b--skip     { background: var(--state-warning-surface); color: var(--state-warning); }

/* 概览卡里的小渠道标签 */
.tk-ch {
  color: var(--muted-foreground); white-space: nowrap;
  padding: 0 6px; border-radius: var(--apple-radius-sm);
  background: var(--secondary); height: 18px; line-height: 18px; display: inline-flex; align-items: center;
}

/* 积分列（绿、右对齐由 markup 控制） */
.tk-credit { color: var(--state-success); font-weight: 600; }

/* 类型筛选 chips：高度对齐「立即采集」按钮（32px），水平线一致 */
.tk-chip {
  display: inline-flex; align-items: center; justify-content: center; height: 32px; padding: 0 14px;
  border-radius: 999px; border: 1px solid var(--border);
  background: var(--card); color: var(--muted-foreground);
  font-size: 12px; line-height: 1; cursor: pointer; transition: all .15s ease;
}
.tk-chip:hover { color: var(--foreground); border-color: var(--muted-foreground); }
.tk-chip.is-on {
  background: var(--primary); border-color: var(--primary);
  color: var(--primary-foreground); font-weight: 500;
}
