/* ============================================================================
 * ds.css —— 忆匣子的设计基底（薄层，覆盖 Bootstrap，不重写它）
 *
 * ## 加载顺序
 *
 *   /vendor/bootstrap.min.css   ← 库
 *   /assets/ds.css              ← 本文件（必须在 Bootstrap 之后）
 *
 * ## 两条纪律
 *
 * 1. **只覆盖，不重写**。这里放的是「品牌色 + 密度 + 三态」三类东西；
 *    布局、栅格、组件结构一律用 Bootstrap 的既有类。反过来说：若某个观感
 *    用 Bootstrap 的类就能表达（比如 `text-body-secondary`、`table-sm`），
 *    就不要在这里造一个 `.ds-*`。
 *
 * 2. **浅色为主**（2026-09-27 拍板，推翻了原先的「深蓝 + 金」）。
 *    图标本身不动（`#1B3A6B` 底 + `#F5C24B` 字形）—— 它与安卓启动器图标、
 *    favicon 三处同步，改要重生成矢量并重发安卓包。
 *    所以界面的主色取品牌蓝的**色相**、把明度提上来（深蓝在白底上做正文
 *    对比度不够）；金色降为点缀（深底上好看的金，在白底上大面积会显脏）。
 *
 * ## 对比度（WCAG AA，硬要求）
 *
 * 正文 ≥ 4.5:1、大字（≥18.66px 粗体 或 ≥24px）≥ 3:1。
 * 浅底最容易犯的错是「看着清爽但看不清」，所以每个前景色都在下面标了实测值。
 *
 * ⚠️ **这些数字是 `tools/contrast-check.mjs` 算出来的，改色后必须重跑并更新本段**。
 * 它这么规定不是洁癖：2026-09-27 复核发现原先声明的两组数字**与实际不符**
 * （`--ds-fg-3` 写 4.6 实际 4.35；`--ds-accent-ink` 写 7.1 实际 3.86），
 * 而声明的数字一旦错了，这段注释就从「保障」变成「误导」—— 所以现在把它
 * 变成一条命令，而不是一句叮嘱。
 *
 * 实测值（跑 `node tools/contrast-check.mjs` 可复现）：
 *   --ds-fg   #12233D  白底 15.75  页底 14.93
 *   --ds-fg-2 #4A5A75  白底  6.98  页底  6.61
 *   --ds-fg-3 #5F6D83  白底  5.25  页底  4.98  主色浅底 4.56
 *   --ds-brand #12508F 白底  8.17  页底  7.75
 *   #FFFFFF 在主色按钮上 → 8.17
 *   --ds-accent-ink #5C450E 在金底 #F5C24B 上 → 5.49
 *
 * ⚠️ **最浅的一档（`--ds-fg-3`）要在三种底上都达标**，因为它无处不在：
 * 白卡片（`.ds-kpi__label`）、页面底 `#F7F9FC`（`.ds-footer`）、主色浅底
 * `#E8F0F9`（`.ds-caveats`）。三者里主色浅底最不利，所以它决定上限。
 *
 * 金色**只做点缀**（下划线、强调数字的底纹），从不承载正文。
 * ========================================================================= */

:root {
  /* ---- 品牌色阶（色相来自 #1B3A6B，明度按浅底需要提亮）---- */
  --ds-brand: #12508F;          /* 主色：链接、主按钮、选中态 */
  --ds-brand-hover: #0E4376;
  --ds-brand-soft: #E8F0F9;     /* 主色的极浅底（选中行、提示块）*/
  --ds-brand-border: #BBD2EA;
  --ds-accent: #F5C24B;         /* 品牌金：**只做点缀** */
  --ds-accent-ink: #5C450E;     /* 金底上的文字（#F5C24B 底 + 这个色 → 5.49:1）*/

  /* ---- 文字三档 ---- */
  --ds-fg: #12233D;
  --ds-fg-2: #4A5A75;
  /* 最浅的一档。**原来是 #6B7A93，2026-09-27 因未达 AA 改深**（4.35 → 5.25）。
     改深之后与 fg-2 的差别变小了，所以它现在只给「辅助信息」用
     （标签、脚注、`__note`），不要拿它当次要正文。*/
  --ds-fg-3: #5F6D83;

  /* ---- 面与线 ---- */
  --ds-bg: #F7F9FC;             /* 页面底：极浅灰蓝，比纯白柔和 */
  --ds-surface: #FFFFFF;        /* 卡片/表格底 */
  --ds-border: #E2E8F0;
  --ds-border-strong: #CBD5E1;

  /* ---- 语义色（三态）---- */
  --ds-danger: #B42318;
  --ds-danger-soft: #FEF3F2;
  --ds-warn: #B54708;
  --ds-warn-soft: #FFFAEB;
  --ds-ok: #067647;
  --ds-ok-soft: #ECFDF3;

  /* ---- 密度与圆角（比 Bootstrap 默认略紧凑：面板要在一屏里多放几行）---- */
  --ds-radius: 10px;
  --ds-radius-sm: 7px;
  --ds-gap: 16px;
  --ds-gap-sm: 10px;

  /* Bootstrap 的变量接管（覆盖它，而不是在每个组件上改） */
  --bs-primary: var(--ds-brand);
  --bs-primary-rgb: 18, 80, 143;
  --bs-body-color: var(--ds-fg);
  --bs-body-bg: var(--ds-bg);
  --bs-secondary-color: var(--ds-fg-2);
  --bs-tertiary-color: var(--ds-fg-3);
  --bs-border-color: var(--ds-border);
  --bs-link-color: var(--ds-brand);
  --bs-link-hover-color: var(--ds-brand-hover);
  --bs-border-radius: var(--ds-radius);
  --bs-border-radius-sm: var(--ds-radius-sm);
  /* 面板与官网都要的字体栈（与既有两个面板的内联字体保持同一套）*/
  --bs-body-font-family: -apple-system, "Segoe UI", "Microsoft YaHei", "PingFang SC",
                         "Noto Sans CJK SC", sans-serif;
}

/* ---------------------------------------------------------------- 基础 */

body {
  background: var(--ds-bg);
  color: var(--ds-fg);
  -webkit-text-size-adjust: 100%;
}

/* 正文基准 16px（Bootstrap 默认也是 1rem，这里**显式钉住**而不是靠默认值）。
 *
 * 原先官网的正文几乎一律是 `.small`(14px)，于是整页只剩 h1 与 14px 两级，
 * 中文在这种字号下的可读性明显偏低（中文没有词间空格，字形又密）。
 * 规矩：**正文用 16px，`.small` 只给真正的辅助信息**（脚注、单位、时间戳）。
 */
body { font-size: 1rem; }

/* 锚点跳转要给吸顶导航留位置。
 *
 * 导航是 `sticky-top`（高约 56px）。没有这行时点 help.html 的目录跳到小节，
 * 标题会被导航**盖住** —— 用户看到的是「跳过去了，但那一节的开头不见了」。
 * 用 `scroll-margin-top` 而不是 `padding-top` + 负 margin：后者会改变盒模型、
 * 影响布局，而前者只影响滚动定位。 */
:target { scroll-margin-top: 5rem; }
h1, h2, h3, h4, h5, h6 { scroll-margin-top: 5rem; }

a { color: var(--ds-brand); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--ds-brand-hover); }

/* 主按钮（Bootstrap 的 .btn-primary 现在自动用 --bs-primary，
   这里只补 hover 的深一档 —— 默认的 hover 是「变暗 15%」，在白底上偏灰）*/
.btn-primary {
  --bs-btn-bg: var(--ds-brand);
  --bs-btn-border-color: var(--ds-brand);
  --bs-btn-hover-bg: var(--ds-brand-hover);
  --bs-btn-hover-border-color: var(--ds-brand-hover);
  --bs-btn-active-bg: var(--ds-brand-hover);
  --bs-btn-disabled-bg: var(--ds-border-strong);
  --bs-btn-disabled-border-color: var(--ds-border-strong);
}

/* ---------------------------------------------------------------- 卡片 */

.ds-card {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius);
  padding: var(--ds-gap);
}

.ds-card + .ds-card { margin-top: var(--ds-gap); }

/* 卡片标题。原先卡片标题直接借 Bootstrap 的 `.h6`(16px/500)，与正文同大 ——
 * 「卡片级标题」和「正文」分不出来（`index.html` 的词库卡就是这种）。
 * 卡片标题要比正文明显，但**不能**压过区块标题 `.ds-title`(22px)。 */
.ds-card__title {
  font-size: 1.0625rem;        /* 17px */
  font-weight: 600;
  color: var(--ds-fg);
  margin-bottom: .25rem;
}

/* 区块末尾的行动号召块。
 * 用主色浅底 + 左描边（与 `.ds-caveats`/`.ds-note` 同一家族），
 * 在一屏里明显但不喧哗 —— 它不是弹窗，也不用整块主色（那会盖过页面本身）。*/
.ds-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-gap);
  background: var(--ds-brand-soft);
  border: 1px solid var(--ds-brand-border);
  border-radius: var(--ds-radius);
  padding: var(--ds-gap);
}
.ds-cta__text { font-size: .9375rem; color: var(--ds-fg-2); }

/* KPI 卡（借鉴 Tabler 的排版：数字大、标签小、口径说明在下面一行）*/
.ds-kpi {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius);
  padding: 14px 16px;
  height: 100%;
}
.ds-kpi__label {
  font-size: .8125rem;         /* 13px */
  color: var(--ds-fg-3);
  margin-bottom: 2px;
}
.ds-kpi__value {
  font-size: 1.5rem;           /* 24px —— 大写数字够到 AA 的「大字」档 */
  font-weight: 700;
  color: var(--ds-fg);
  line-height: 1.25;
  font-variant-numeric: tabular-nums;   /* 数字等宽：跳数时不会左右抖 */
}
.ds-kpi__note { font-size: .75rem; color: var(--ds-fg-3); margin-top: 2px; }

/* 金色点缀：只给「今天/当前」这类标记，不做背景大色块 */
.ds-accent-mark {
  background: var(--ds-accent);
  color: var(--ds-accent-ink);
  border-radius: 4px;
  padding: 0 4px;
  font-weight: 600;
}

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

/* 面板里的表格一律包一层 .table-responsive（移动端横向滚动），
   粘性表头靠 .ds-table-sticky —— Bootstrap 没有现成的。*/
.ds-table-sticky thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--ds-surface);
  box-shadow: inset 0 -1px 0 var(--ds-border-strong);
}

.table > :not(caption) > * > * { padding: .5rem .65rem; }   /* 比默认紧凑一档 */
.table { --bs-table-border-color: var(--ds-border); }
.table > thead { color: var(--ds-fg-2); font-size: .8125rem; text-transform: none; }

/* 长文本截断 + 点击展开（`.ds-clamp` 由页面在点击后加 `.is-open`）*/
.ds-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  cursor: pointer;
}
.ds-clamp.is-open { -webkit-line-clamp: unset; }

/* 数字右对齐且等宽（表格里的金额/次数）*/
.ds-num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- 四态 */

/* 空态：**必须说明为什么空**（「窗口内没有数据」比「暂无数据」有用得多）*/
.ds-empty {
  text-align: center;
  padding: 40px 16px;
  color: var(--ds-fg-3);
}
.ds-empty__title { color: var(--ds-fg-2); font-weight: 600; margin-bottom: 4px; }

/* 错误态：可重试 */
.ds-error {
  border: 1px solid #FDA29B;
  background: var(--ds-danger-soft);
  color: var(--ds-danger);
  border-radius: var(--ds-radius-sm);
  padding: 12px 14px;
}

/* 无权限态：与错误态**视觉上要能区分**（错误是「坏了」，无权限是「你不该看」）*/
.ds-denied {
  border: 1px solid #FEDF89;
  background: var(--ds-warn-soft);
  color: var(--ds-warn);
  border-radius: var(--ds-radius-sm);
  padding: 12px 14px;
}

/* 骨架屏：用 Bootstrap 的 .placeholder-glow/.placeholder，这里只调色 */
.placeholder { background-color: var(--ds-border); }

/* ---------------------------------------------------------------- 口径说明 */

/* dataCaveats：**固定渲染、绝不放 tooltip**（口径错了，页面上所有数字都是误导）*/
.ds-caveats {
  margin: var(--ds-gap-sm) 0 0;
  padding: 10px 12px 10px 28px;
  background: var(--ds-brand-soft);
  border-left: 3px solid var(--ds-brand);
  border-radius: 0 var(--ds-radius-sm) var(--ds-radius-sm) 0;
  font-size: .8125rem;
  color: var(--ds-fg-2);
}
.ds-caveats li + li { margin-top: 4px; }

/* ---------------------------------------------------------------- 角色徽标 */

.ds-role { font-size: .75rem; padding: .15em .5em; border-radius: 999px; font-weight: 600; }
.ds-role--admin { background: var(--ds-brand); color: #fff; }
.ds-role--operator { background: var(--ds-brand-soft); color: var(--ds-brand); border: 1px solid var(--ds-brand-border); }

/* ---------------------------------------------------------------- 官网 */

/* 区块节奏（**两档，全站统一**）
 *
 * 原先的问题是 Bootstrap 的 `mb-5`(3rem) 与 `mb-3`(1rem) 被混用在**同一层级**
 * 的区块之间（首页三个区块用 mb-5，help 的六张卡用 mb-3），于是「哪些是兄弟、
 * 哪些是子项」在视觉上讲不通 —— 标题的字号已经区分了层级，间距却没有。
 * 这里定两档，页面一律照用（`mb-0` 留给区块内最后一个元素）：
 *
 *   .ds-section        区块之间（兄弟关系）
 *   .ds-section__sub   区块内部的子块之间
 *
 * ⚠️ 用 `> * + *` 的相邻兄弟选择器而不是给每个子元素写 margin：这样**只有
 * 真正相邻**的两个子块之间才有间距，首尾自动不带（省掉一堆 `mb-0`）。
 * 它也不影响区块里已有的 Bootstrap 栅格（栅格自己的 gutter 照常生效）。
 */
.ds-section > * + * { margin-top: 3rem; }
.ds-section__sub > * + * { margin-top: 1.5rem; }

/* 区块标题。原先标题一律是裸 Bootstrap 的 `.h4`/`.h6`，问题有两个：
 *   1. `changelog.html` 的版本号用了 `span.h6`，与正文同大（16px/500），
 *      于是「版本号」看起来像正文而不是标题；
 *   2. 区块标题（h4=1.5rem）与卡片标题（.h6=1rem）之间只差一档，层级不分明。
 * 这里靠**字重 + 字号 + 一条金色短线**把三档拉开（金色终于有正经用途了：
 * 它只在标题下做点缀，不做色块）。 */
.ds-title {
  font-size: 1.375rem;          /* 22px */
  font-weight: 700;
  color: var(--ds-fg);
  margin-bottom: 0;
  padding-bottom: .5rem;
  border-bottom: 2px solid var(--ds-accent);
  display: inline-block;        /* 让那条线只跟到文字宽度 */
}
.ds-title__note {
  font-size: .9375rem;          /* 15px，比正文略小但仍高于 .small(14px) */
  color: var(--ds-fg-2);
  margin: .5rem 0 0;
}

.ds-hero { padding: 56px 0 40px; }
.ds-hero__icon { width: 88px; height: 88px; }
.ds-hero__title { font-size: clamp(1.9rem, 5vw, 2.6rem); font-weight: 800; letter-spacing: .5px; }
.ds-hero__lead { color: var(--ds-fg-2); font-size: 1.0625rem; max-width: 46ch; }

/* 关键数字（首屏那三个）。
 *
 * ⚠️ 原先首页给它们用的是 `.ds-stat__value` / `.ds-stat__label` 这两个**只存在于
 * 官网**的类，而 ds.css 里另有一套为面板写的 `.ds-kpi*`（含 `__label`/`__note`，
 * 也就是口径说明的位置）—— 结果是官网三个 KPI **没有任何口径说明**，
 * 而 `.ds-kpi*` 在官网上成了死代码。现在两处共用 `.ds-kpi*`。
 *
 * `.ds-stat` 只承担一件事：在窄屏并排时居中。**它不再有自己的字号与颜色**
 * （那两个值与 `.ds-kpi*` 重复，两份就会漂）。 */
.ds-stat { text-align: center; }

/* 特色卡 */
.ds-feature { height: 100%; }
.ds-feature__icon { width: 32px; height: 32px; color: var(--ds-brand); }
.ds-feature__title { font-size: 1rem; font-weight: 600; margin: 10px 0 4px; }
.ds-feature__text { font-size: .875rem; color: var(--ds-fg-2); margin: 0; }

/* 界面示意图（重绘的内联 SVG）
 *
 * ⚠️ **图里的颜色必须走类，不能写死在 `fill="#12508F"` 上**。
 * 踩过的坑：原先两张示意图把 7 个色值全部硬编码在内联属性里，改主色时
 * 示意图与页面就脱节了（而对比度那套纪律对它也失效 —— 硬编码的 #6B7A93
 * 既没被 `contrast-check.mjs` 覆盖，也没跟着 fg-3 的修正一起变）。
 *
 * ⚠️ **CSS 变量不能直接写进 SVG 的呈现属性**（`fill="var(--ds-brand)"` 无效 ——
 * 呈现属性按 SVG 的属性语法解析，不认 `var()`）。要生效必须通过 CSS，也就是
 * `style="fill:var(...)"` 或类选择器。这里用类选择器，好处是色值只有一处。
 */
.ds-mock {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius);
  padding: 12px;
}
.ds-mock svg { display: block; width: 100%; height: auto; }

/* 示意图内的语义色（名字按用途而不是颜色，换色时不用改 HTML） */
.ds-mock__bg { fill: var(--ds-bg); }
.ds-mock__card { fill: var(--ds-surface); stroke: var(--ds-border); }
.ds-mock__text { fill: var(--ds-fg); }
.ds-mock__sub { fill: var(--ds-fg-2); }
.ds-mock__muted { fill: var(--ds-fg-3); }
.ds-mock__rule { stroke: var(--ds-border); }
.ds-mock__axis { stroke: var(--ds-border-strong); }
.ds-mock__brand { fill: var(--ds-brand); }
.ds-mock__brand-stroke { stroke: var(--ds-brand); }
.ds-mock__accent-stroke { stroke: var(--ds-accent); }
.ds-mock__pill { fill: var(--ds-brand-soft); stroke: var(--ds-brand-border); }
.ds-mock__pill-ink { fill: var(--ds-brand); }
.ds-mock__solid { fill: var(--ds-brand); }
.ds-mock__on-solid { fill: #FFFFFF; }

/* 页脚 */
.ds-footer {
  border-top: 1px solid var(--ds-border);
  margin-top: 48px;
  padding: 24px 0;
  color: var(--ds-fg-3);
  font-size: .875rem;
}

/* 顶部导航：入口在未登录时低调、登录过之后变显眼（由 site.js 切换 .is-armed）*/
.ds-nav__panel-entry {
  color: var(--ds-fg-3);
  text-decoration: none;
  font-size: .875rem;
}
.ds-nav__panel-entry.is-armed {
  color: var(--ds-brand);
  font-weight: 600;
}
.ds-nav__panel-entry.is-armed::after { content: "●"; font-size: .5em; vertical-align: middle; margin-left: 4px; color: var(--ds-accent-ink); }

/* 未登录时的「注册」是导航栏上的**主行动**（新访客该走的那条路）。
   它与 `.is-armed` 的区别：主色 + 稍重，**但不带那个金色圆点** —— 圆点的语义
   是「本地已有凭据」，放在未登录状态的链接上是误用。 */
.ds-nav__signup { color: var(--ds-brand); font-weight: 600; }

/* ---------------------------------------------------------------- 账号区（下拉）*/

/* ⚠️ 下拉不能靠 `overflow` 裁剪：它挂在 `sticky-top` 的导航栏里，
   任何祖先写了 `overflow: hidden/auto` 都会把它整个切掉（症状是「点了没反应」，
   而 DOM 里明明有）。所以这里只定位、不裁剪。 */
.ds-nav__account { position: relative; }

.ds-nav__account-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--ds-radius-sm);
  padding: 4px 8px;
  font-size: .875rem;
  font-weight: 600;
  color: var(--ds-brand);
  max-width: 16ch;
}
.ds-nav__account-btn:hover { background: var(--ds-brand-soft); }
.ds-nav__account-btn:focus-visible {
  outline: 2px solid var(--ds-brand);
  outline-offset: 2px;
}
/* 长名字截断：用户名可以到 20 个字符，不截会把导航挤变形 */
.ds-nav__account-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-nav__caret { font-size: .75em; color: var(--ds-fg-3); }

/* 身份还没取到时的占位块。刻意是**灰色无交互**的 —— 它的作用只是「别让已登录的人
   先看到『登录/注册』再跳变」，不是一个可点的东西。 */
.ds-nav__account-skel {
  display: inline-block;
  min-width: 4ch;
  padding: 4px 8px;
  color: var(--ds-fg-3);
  font-size: .875rem;
  letter-spacing: 1px;
}

.ds-nav__menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 1030;               /* 高过 .sticky-top 的 1020 */
  min-width: 11rem;
  padding: 6px;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius);
  box-shadow: 0 8px 24px rgba(18, 35, 61, .12);
}
.ds-nav__menu.is-open { display: block; }

.ds-nav__menu-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border: 0;
  border-radius: var(--ds-radius-sm);
  background: none;
  color: var(--ds-fg);
  font-size: .875rem;
  text-decoration: none;
}
.ds-nav__menu-item:hover { background: var(--ds-brand-soft); color: var(--ds-brand); }
/* 按钮形态的菜单项（退出登录）要与链接外观一致 —— 但它是 button，
   浏览器默认会给它自己的字体与颜色，所以上面那套要显式覆盖一次宽度与字体。 */
.ds-nav__menu-item--btn { font-family: inherit; }

.ds-nav__menu-sep {
  height: 1px;
  margin: 6px 4px;
  background: var(--ds-border);
}

/* 移动端：导航折叠展开后空间窄，下拉贴着右侧但不要顶出视口 */
@media (max-width: 575.98px) {
  .ds-nav__menu { right: auto; left: 0; min-width: 9rem; }
  .ds-nav__account-btn { max-width: 12ch; }
}

/* -------------------------------------------------------- 评分堆叠条 / 时段柱 */

/* 一条横向堆叠条（四档评分各占一段）。
 * 用 flex 子项的 `flex-grow` 表达占比：比「手动算宽度百分比」少一处
 * 计算，也就少一处会算错的地方（段宽由浏览器按总量归一）。 */
.ds-stack {
  display: flex;
  height: 20px;
  border-radius: var(--ds-radius-sm);
  overflow: hidden;             /* 让第一段/最后一段跟着圆角走 */
  background: var(--ds-border); /* 全为 0 时露出的底 */
}
.ds-stack__seg { min-width: 2px; }   /* 极小占比也要看得见有一条 */

/* 24 小时柱状图。用 CSS 而不是图表库 —— 见 drawHours 的注释。 */
.ds-hours {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 96px;
  padding-bottom: 16px;         /* 给刻度文字留位置 */
  position: relative;
}
.ds-hours__col {
  flex: 1 1 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  position: relative;
}
.ds-hours__bar {
  background: var(--ds-brand-border);
  border-radius: 2px 2px 0 0;
  min-height: 0;
}
/* 峰值那根用主色（其余是浅蓝）—— 一眼看出集中在哪个时段 */
.ds-hours__bar.is-peak { background: var(--ds-brand); }
.ds-hours__tick {
  position: absolute;
  bottom: -16px;
  left: 0;
  font-size: .6875rem;          /* 11px：这是刻度，不是正文 */
  color: var(--ds-fg-3);
  font-variant-numeric: tabular-nums;
}

/* 反馈截图缩略图。**限定尺寸**：原图可达 4MB / 几千像素宽，
 * 直接摊在面板里会把行撑爆、也会让滚动变卡。 */
.ds-thumb {
  width: 140px;
  height: 140px;
  object-fit: cover;            /* 裁切而不是拉伸（截图的比例五花八门） */
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-bg);
  cursor: zoom-in;
}
.ds-thumb:hover { border-color: var(--ds-brand); }

/* 缩略图的加载中 / 失败占位。**必须占同样的尺寸** —— 否则图到达时整页
 * 会跳一下（面板上十几张图逐个到达，那种跳动很烦人）。 */
.ds-thumb--loading,
.ds-thumb--failed {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .75rem;
  color: var(--ds-fg-3);
  cursor: default;
}
.ds-thumb--loading { background: var(--ds-border); }
.ds-thumb--failed { background: var(--ds-danger-soft); color: var(--ds-danger); }

/* 放大态：脱离缩略图尺寸，按原图比例铺开（点一下放大、再点还原）。
 * `max-width: 100%` 保证不会溢出容器（面板最宽 1400px）。 */
.ds-thumb.is-zoom {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 80vh;
  object-fit: contain;
  cursor: zoom-out;
}

/* ------------------------------------------------------------ 标签页分组 */

/* 面板标签栏里两组之间的竖直分隔线（业务 / 基础设施）。
   用 `align-self: stretch` 让它跟着标签的高度，不写死像素值 ——
   标签高度会随字号与内边距变。 */
.ds-tab-sep {
  flex: 0 0 auto;
  align-self: stretch;
  width: 1px;
  margin: 4px 6px;
  background: var(--ds-border-strong);
}

/* ---------------------------------------------------------------- 提示块 */

/* 「温和提醒」类提示（例如 download.html 的 Windows 安装说明）。
 *
 * 原先那处用的是 Bootstrap 的 `alert-warning`（亮黄 + 深黄字），与本文件的
 * 语义色 `--ds-warn` 不是同一套 —— 同一页上两个黄，看起来像两种严重程度。
 * 这里统一到 token 上，并排布成「左描边」形态（与 `.ds-caveats` 同一家族），
 * 比整块色底的 alert 轻，适合「注意一下」而不是「出事了」。 */
.ds-note {
  border: 1px solid var(--ds-brand-border);
  border-left: 3px solid var(--ds-brand);
  background: var(--ds-brand-soft);
  color: var(--ds-fg-2);
  border-radius: 0 var(--ds-radius-sm) var(--ds-radius-sm) 0;
  padding: 10px 12px;
  font-size: .875rem;
}
.ds-note--warn {
  border-color: #FEDF89;
  border-left-color: var(--ds-warn);
  background: var(--ds-warn-soft);
  color: var(--ds-warn);
}

/* 下载块（download.html）*/
.ds-dl-meta { font-size: .8125rem; color: var(--ds-fg-3); }
.ds-dl-meta code { color: var(--ds-fg-2); word-break: break-all; }

/* 校验和那一块：原先用裸 Bootstrap 的 `pre.bg-body-tertiary`，是官网上唯一
   的「裸 Bootstrap 孤岛」（灰底 + 默认字体，与卡片体系不搭）。这里纳入 token。*/
.ds-hash {
  background: var(--ds-bg);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm);
  padding: 8px 10px;
  margin: 0;
  font-size: .8125rem;
  color: var(--ds-fg-2);
  word-break: break-all;
  white-space: pre-wrap;
}

/* ---------------------------------------------------------------- 移动端
 *
 * ⚠️ 断点只有这一个（575.98px = Bootstrap 的 `sm` 下界减 0.02）。
 * 原先这里只覆盖三项，而 `help.html` 的六行目录在 `lg` 以下**仍然占满首屏
 * 约三分之一** —— 手机用户要先划过目录才看到正文。这里把目录改成横向滚动条
 * （一行高），与 `.ds-clamp` 那套「小屏变紧凑」的思路一致。 */
@media (max-width: 991.98px) {
  .ds-toc {
    position: static !important;      /* 取消 position-lg-sticky 的粘性 */
    padding: 10px 12px;               /* 横排时不需要卡片的 16px 内边距 */
    margin-bottom: 1rem;
  }
  /* ⚠️ **flex 要打在 `ul` 上，不是 `.ds-toc` 上**。
     踩过一次：`.ds-toc` 的直接子元素只有一个 `<ul>`，把 flex 加在父级
     等于「让那个 ul 成为一个 flex 子项」—— 六行链接照样竖着排，
     症状是「媒体查询明明生效了、目录却没变矮」。
     同理 `flex: 0 0 auto` 要给 `li`（原来写的是 `.nav-item`，而这里
     用的是裸 `<ul><li>`，没有那个类，所以也没命中）。 */
  .ds-toc > ul {
    display: flex;
    flex-wrap: nowrap;
    gap: .75rem;
    overflow-x: auto;
    /* 横向滚动条在小屏容易误触，留一点上下空间让它好按 */
    padding-bottom: .25rem;
  }
  .ds-toc > ul > li { flex: 0 0 auto; }
  .ds-toc a { white-space: nowrap; }
  .ds-toc__title { display: none; }   /* 横排时它占一格且没信息量 */
}

@media (max-width: 575.98px) {
  .ds-hero { padding: 32px 0 24px; }
  .ds-caveats { font-size: .75rem; padding: 8px 10px 8px 24px; }
  .ds-kpi__value { font-size: 1.25rem; }
  /* 区块间距在小屏收一档：3rem 在 390px 宽下会让滚动变得很长 */
  .ds-section > * + * { margin-top: 2rem; }
  .ds-section__sub > * + * { margin-top: 1rem; }
  .ds-title { font-size: 1.25rem; }
}

/* 打印/截图时不要骨架屏（面板的截图会被人贴进群里）*/
@media print {
  .ds-card, .ds-kpi { break-inside: avoid; }
}
