/* ============================================================
   任务运行状态监控管理系统 · 自定义样式
   底座是 Tabler 1.6.1（已内置 Bootstrap 5 grid），本文件只补业务相关部分。
   ★ 能用 Tabler/Bootstrap 工具类解决的，不要在这里写 CSS ——
     工具类改一处生效全局，这里写死每个页面都要各自维护。
   ============================================================ */

:root {
    --tms-mono: "Cascadia Mono", "JetBrains Mono", Consolas, "Courier New", monospace;
    --tms-status-running: #206bc4;
    --tms-status-success: #2fb344;
    --tms-status-failed:  #d63939;
    --tms-status-stopped: #8a8f98;
    --tms-status-none:    #a8adb4;
}

/* ---------- Tabler 未提供、但视图里在用的三个类 ----------
 *
 * ★ 这三个都是「写了没报错、样式却完全没生效」的坑，所以集中在这里补齐：
 *
 * 1. .ti-2x —— 图标放大 2 倍（空态大图标用）
 *    Tabler Icons 的 webfont 包**只有 @font-face 与图标 content，没有尺寸修饰类**
 *    （`grep 'ti-2x' tabler-icons.min.css` 为 0）。Bootstrap 5.3 也没有。
 *    官方文档放大图标的方式是行内 font-size，但那会让模板里到处散落 style，
 *    这里统一用类承载。注意图标是字体，缩放靠 font-size，不是 width/height。
 *
 * 2. .min-w-0 —— flex 子项允许收缩到 0
 *    Bootstrap 有、Tabler 1.6.1 的工具类里被裁掉了。缺它的后果很隐蔽：
 *    flex 子项默认 min-width:auto，长 client_id / task_no 撑破容器，
 *    父级的 text-truncate 永远不触发（看起来「省略号坏了」）。
 *
 * 3. 提示条标题：Tabler 1.6.1 里叫 .alert-heading，**没有 .alert-title**
 *    （官方 CSS 只有 .alert-heading/.alert-description/.alert-icon/.alert-action）。
 *    视图里统一用 alert-heading，别改回 alert-title。
 */
.ti-2x {
    font-size: 2em;
    line-height: 1;
}

.min-w-0 {
    min-width: 0;
}

/* 提示条标题的降级字号：alert-heading 自带较大字号，
   flash 消息只需一行，2rem 会把布局撑开。 */
.alert.alert-info .alert-heading,
.alert.alert-success .alert-heading,
.alert.alert-warning .alert-heading,
.alert.alert-danger .alert-heading {
    font-size: 1rem;
    margin: 0;
}

/* ---------- 通用排版 ---------- */

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
                 "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
}

/* 数字类内容（耗时、进度、ID）用等宽，竖排时能对齐 */
.tms-num,
.mono {
    font-family: var(--tms-mono);
    font-variant-numeric: tabular-nums;
}

/* 页面标题区：所有页面统一用这个结构，避免各页面自己拼标题样式 */
.page-headers {
    margin-bottom: 1.5rem;
}

.page-headers .page-title {
    margin-bottom: .25rem;
}

/* 筛选表单区：多个筛选项横向排布 */
.tms-filter-bar {
    background: var(--tms-surface, #fff);
    border: 1px solid var(--tms-border, #e6e7e9);
    border-radius: 8px;
    padding: 1rem 1.25rem;
    margin-bottom: 1.25rem;
}

/* 列表页的筛选卡片：不需要外边距（Tabler 的 card 已有 margin） */
.tms-filter-card .card-body {
    padding: .875rem 1.25rem;
}

.tms-filter-bar .form-label {
    font-size: .75rem;
    font-weight: 600;
    color: var(--tms-muted, #6c7a91);
    margin-bottom: .25rem;
    text-transform: none;
}

/* ---------- 状态标识 ---------- */

/*
 * 状态圆点。用于看板卡片与表格首列。
 * running 带呼吸动画：监控场景下「正在跑」是需要一眼看到的动态信号。
 */
.status-dot {
    display: inline-block;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    margin-right: .45rem;
    vertical-align: middle;
    flex-shrink: 0;
}

.status-running { background-color: var(--tms-status-running); animation: tms-pulse 1.6s ease-in-out infinite; }
.status-success { background-color: var(--tms-status-success); }
.status-failed  { background-color: var(--tms-status-failed); }
.status-stopped { background-color: var(--tms-status-stopped); }
.status-none    { background-color: var(--tms-status-none); }

@keyframes tms-pulse {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(32, 107, 196, .45); }
    50%      { opacity: .75; box-shadow: 0 0 0 .3rem rgba(32, 107, 196, 0); }
}

/* 尊重系统「减少动效」设置 —— 前庭障碍用户对闪烁敏感 */
@media (prefers-reduced-motion: reduce) {
    .status-running { animation: none; }
    .monitor-card { transition: none; }
}

/* ---------- 看板卡片 ---------- */

.monitor-card {
    transition: border-color .15s ease, box-shadow .15s ease;
    /* 顶部一条状态色带：不用点开就能区分状态，比只放个圆点更易扫读 */
    border-top: 2px solid transparent;
}

.monitor-card:hover {
    box-shadow: 0 .25rem .75rem rgba(24, 36, 51, .08);
    transform: translateY(-1px);
}

.monitor-card.is-running { border-top-color: var(--tms-status-running); }
.monitor-card.is-success { border-top-color: var(--tms-status-success); }
.monitor-card.is-failed  { border-top-color: var(--tms-status-failed); }
.monitor-card.is-stopped { border-top-color: var(--tms-status-stopped); }
.monitor-card.is-none    { border-top-color: var(--tms-status-none); }

/* 统计卡片 */
.tms-stat .card-body {
    padding: 1rem 1.25rem;
}

.tms-stat .tms-stat-value {
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.tms-stat .tms-stat-label {
    font-size: .75rem;
    color: var(--tms-muted, #6c7a91);
    font-weight: 500;
}

/* ---------- 表格 ---------- */

.table > :not(caption) > * > * {
    vertical-align: middle;
}

/* 时间列、ID 列不换行，窄屏横向滚动时保持可读 */
.tms-col-time,
.tms-col-id {
    white-space: nowrap;
    font-family: var(--tms-mono);
    font-size: .8125rem;
}

/* message 这类长文本列：限制在合理宽度内，超出省略，
   完整内容在详情页看 —— 否则一行能撑爆整张表 */
.tms-col-message {
    max-width: 22rem;
}

.tms-col-message .tms-ellipsis {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 排序表头里的上下箭头 */
.tms-sort-link {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: .15rem;
}

.tms-sort-link:hover { color: var(--tms-primary, #206bc4); }

.tms-sort-link.is-active { color: var(--tms-primary, #206bc4); font-weight: 600; }

/* ---------- 看板进度条：条内要显示百分比，轨道必须够高 ----------
 *
 * Tabler 的 .progress 轨道只有 4px（.progress-sm 是 8px），
 * 那是给「纯色条、不带文字」设计的。看板里的进度条要写百分比，
 * 而 .progress-bar 的文字实测是 font-size 10.5px —— 文字比轨道还高，
 * 上下各溢出约 1.25px，被轨道的圆角（overflow:hidden）裁掉，
 * 表现为「百分比只露出半截」。服务端毫无异常，纯视觉问题。
 *
 * 所以这里给带文字的进度条一个容得下文字的高度，并让文字垂直居中。
 * 只给 .tms-progress（显式加了类的），不影响其他纯装饰进度条。
 */
.tms-progress {
    height: 1.125rem;
    overflow: hidden;
}

.tms-progress .progress-bar {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .6875rem;
    line-height: 1;
    color: #fff;
    /* 0% 时条宽为 0，文字会被一起裁掉。
       用 min-width 兜一个能放下 3 位数字的宽度，条看起来仍是空的。 */
    min-width: 2.25rem;
}

/* ---------- 表格操作列按钮：统一为 Tabler Button Sizes → Small ----------
 *
 * ★ 为什么需要这段，而不是直接依赖 btn-group-sm：
 *
 *   Tabler 的 .btn-group-sm 只作用于**直接子元素**（选择器是 .btn-group-sm>.btn），
 *   而本项目的操作列按钮有一部分必须包在 form 里（提交需要 CSRF 字段，
 *   没有 JS 兜底的纯表单提交），于是 DOM 结构变成：
 *       div.btn-group-sm > form.d-inline > button.btn
 *   按钮是**孙级**，.btn-group-sm>.btn 匹配不到 → 尺寸退回默认 Medium。
 *   结果是同一行里「编辑」是小号、「归档」是大号，高低不齐。
 *
 *   两种修法都用了，双保险：
 *     1. 视图里给 form 内的 button 显式加 btn-sm（见 tasks/monitors/api_keys 列表页）
 *     2. 这里用 .tms-actions .btn 兜底，防止以后新增表单按钮又漏掉
 *
 * ★ 规格与 Tabler 的 .btn-sm 保持一致（直接抄它的自定义属性值，
 *   这样即使改用 btn-group-sm 的写法，视觉也不会跳）：
 *     --tblr-btn-padding-y: .3125rem
 *     --tblr-btn-padding-x: .5rem
 *     --tblr-btn-font-size: .75rem
 *     --tblr-btn-line-height: 1rem
 *     --tblr-btn-icon-size: 1rem
 *   ★ 必须用自定义属性而不是直接写 padding/font-size：
 *     Tabler 的按钮尺寸全部通过这组 --tblr-btn-* 变量驱动，
 *     直接写死 padding 会盖掉主题的其他细节（hover 态、禁用态的微调）。
 *
 * ★ 尺寸取值口径：.75rem ≈ 12px，是 Tabler Small 的标准值。
 *   别再往小了改 —— 再小一档 Tabler 官方没有对应类，中文字形会糊。
 */
.tms-actions .btn {
    --tblr-btn-padding-y: 0.3125rem;
    --tblr-btn-padding-x: 0.5rem;
    --tblr-btn-font-size: 0.75rem;
    --tblr-btn-line-height: 1rem;
    --tblr-btn-icon-size: 1rem;
    --tblr-btn-border-radius: var(--tblr-border-radius-sm);
}

/* 操作列里的按钮不允许换行：按钮一换行，整行高度就跳起来 */
.tms-actions .btn {
    white-space: nowrap;
}

/* 按钮之间的小间距。
 * 用 margin 而不是依赖 .btn 的相邻选择器 —— form.d-inline 是 inline 元素，
 * 视觉上会留下空隙，但 Bootstrap 的 .btn + .btn 规则匹配不到（中间隔着 form）。 */
.tms-actions .btn + .btn,
.tms-actions form + .btn,
.tms-actions .btn + form,
.tms-actions form + form {
    margin-left: .25rem;
}

/* 只有一列操作时（如登录日志只有「详情」），按钮组不该有多余内边距 */
.tms-actions .btn-group {
    gap: 0;
}

/* 窄屏下操作列按钮换行时，给一点行距避免上下贴在一起 */
@media (max-width: 575.98px) {
    .tms-actions .btn + form,
    .tms-actions form + form,
    .tms-actions .btn + form,
    .tms-actions form + .btn {
        margin-left: 0;
    }
    .tms-actions .btn-group {
        flex-wrap: wrap;
        gap: .25rem;
    }
}

/* ---------- 批量删除操作栏 ----------
 *
 * 用左侧色条 + 浅红底与普通卡片区分开：这是「有选中项、待执行破坏性操作」的信号，
 * 不该长得跟筛选卡片一样，否则用户会直接忽略。
 * 显隐由 JS 切换 hidden 属性，这里只管观感。
 */
.tms-batch-bar {
    border-left: 3px solid var(--tblr-danger, #d63939);
    background: rgba(214, 57, 57, .06);
}

/* 表头全选框与行内复选框垂直居中，别和表头文字基线错开 */
.tms-report-check {
    vertical-align: middle;
    cursor: pointer;
}

/*
    行复选框：光标可点+ 略微放大点击热区。
    行高本来就只有 40px 左右，浏览器默认的 13px 复选框在窄表里偏难点。
    ★ 不改尺寸上限：超过 16px 会让复选框比行高还高，破坏表格对齐。
    用 outline 做聚焦环，不依赖 Tabler 的 focus ring 变量 ——
    聚焦可见性是无障碍要求，缺了键盘用户就看不出焦点在哪。
*/
.tms-row-check {
    width: 1rem;
    height: 1rem;
    margin: 0;
    cursor: pointer;
}

.tms-row-check:focus-visible,
#tms-check-all:focus-visible {
    outline: 2px solid var(--tblr-primary, #206bc4);
    outline-offset: 2px;
}

/* 确认页表头吸顶：记录多时必须一直可见，否则往下翻不知道每列是什么 */
.tms-del-sticky {
    position: sticky;
    top: 0;
    z-index: 2;
}

/* ---------- 代码与密钥 ---------- */

.code-block {
    background: #1a1c1e;
    color: #d5d9dd;
    border-radius: 8px;
    padding: 1rem 1.25rem;
    font-family: var(--tms-mono);
    font-size: .8125rem;
    line-height: 1.6;
    overflow-x: auto;
    white-space: pre;
    margin: 0;
    border: 1px solid #2b2e31;
}

pre.json-view {
    background: #f8f9fb;
    color: #1a1c1e;
    border: 1px solid #e6e7e9;
    padding: 1rem;
    border-radius: 8px;
    font-family: var(--tms-mono);
    font-size: .8125rem;
    line-height: 1.6;
    max-height: 26rem;
    overflow: auto;
    margin: 0;
    /* JSON key 用等宽，保持缩进对齐 */
    tab-size: 2;
}

/*
 * 一次性密钥展示区。
 * 高亮 + 虚线边框 + 醒目底色：这是「只给看一次、必须立刻复制」的信息，
 * 视觉上要跟普通字段明显区分。
 */
.key-secret {
    font-family: var(--tms-mono);
    font-size: 1rem;
    background: #fffbea;
    color: #8a5a00;
    padding: .875rem 1rem;
    border-radius: 8px;
    word-break: break-all;
    border: 1px dashed #f0c419;
    user-select: all;
}

.key-secret.is-revealed {
    background: #e8f6e8;
    color: #14661f;
    border-color: #2fb344;
}

/* 60 秒倒计时条 */
.tms-countdown {
    height: 3px;
    background: #e6e7e9;
    border-radius: 2px;
    overflow: hidden;
    margin-top: .5rem;
}

.tms-countdown-bar {
    height: 100%;
    background: #f0c419;
    transition: width 1s linear;
}

/* ---------- 设置页：主题选择卡 ----------
 * label.card + btn-check radio：整张卡片可点，选中态用主色描边 + 淡投影。
 * 颜色走 Tabler 变量，深色主题下自动跟随（不要写死 #206bc4）。 */
.theme-option { cursor: pointer; }

/* 悬停提示「可点」：边框先变浅一档，比纯光标变化更明显 */
.theme-option:hover { border-color: var(--tblr-primary, #206bc4); opacity: .92; }

.theme-option.is-active {
    border-color: var(--tblr-primary, #206bc4);
    box-shadow: 0 0 0 .125rem rgba(32, 107, 196, .18);
}

/* ★ 点击即时反馈：is-active 是服务端按「已保存值」渲染的，点另一张卡后
 *   要等保存+刷新才更新；:has() 直接跟 radio 的 checked 状态走，边框立刻换。
 *   （不支持 :has() 的老浏览器由 app.js 里同步 is-active 类兜底。） */
.theme-option:has(input:checked) {
    border-color: var(--tblr-primary, #206bc4);
    box-shadow: 0 0 0 .125rem rgba(32, 107, 196, .18);
}

/* ---------- 其他 ---------- */

.cursor-pointer { cursor: pointer; }

/* 空状态：让「暂无数据」看起来是设计的一部分，而不是加载失败 */
.tms-empty {
    padding: 3rem 1rem;
    text-align: center;
    color: var(--tms-muted, #6c7a91);
}

.tms-empty .tms-empty-icon {
    font-size: 2.5rem;
    color: #adb5bd;
    margin-bottom: .75rem;
}

/* 描述列表：详情页的键值对布局 */
.tms-dl dt {
    font-weight: 500;
    color: var(--tms-muted, #6c7a91);
    font-size: .8125rem;
    margin-top: .75rem;
}

.tms-dl dd {
    margin-bottom: 0;
    margin-top: .125rem;
    word-break: break-word;
}

/* 窄屏：筛选栏由多列降为单列（Tabler 的 col-12 在 xs 下自动堆叠，这里只调间距） */
@media (max-width: 767.98px) {
    .tms-filter-bar { padding: .875rem 1rem; }
    .tms-col-message { max-width: none; }
}
