/*
 * polish-layer.css — 全站视觉增强层。真源本文件，副本由 materialize_site_assets.js 分发，禁止改副本。
 * 只做三件事：补站点缺失的静息层次、收敛越界取值、修无障碍与触控地板。
 * 隐藏/显示必须挂在脚本亲手加上的类上（html.qf-pl-obs / .pl-pending）—— 脚本失效时内容仍可见。
 * 覆盖一律用 .x.x (0,2,0) 赢站点单类名，不依赖加载顺序（blog 站顺序相反）。
 * 颜色与圆角只走 tokens.css 的 --qf-*，引用前确认令牌存在或给字面兜底。
 */

/* ---------- 1. 滚动揭示：一次性 + 失效安全 ---------- */
/*
 * 【那 v1 的病怎么治】
 * v1 把隐藏规则无条件写在 CSS 里，显示依赖 JS → 脚本一挂（404 / CSP / 网络抖动）
 * 内容整片消失（实测 download 丢 11 块 6293 字、www 首页丢 8 块 3485 字）。
 * v2 把隐藏规则挂在 html.qf-pl-obs 与元素自己的 .pl-pending 上，
 * 这两个标记都由脚本亲手加：脚本没跑 → 标记不存在 → 没有任何东西被隐藏。
 * .pl-pending 只打给「首屏以下」的区块，所以也不会出现「先画出来又藏掉」的闪。
 */
html.qf-pl-obs [data-pl-reveal].pl-pending:not(.is-visible) {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity .62s var(--qf-ease-out, cubic-bezier(0, 0, .2, 1)),
    transform .62s var(--qf-ease-out, cubic-bezier(0, 0, .2, 1));
}
/*
 * 逐张错峰（原来这 5 条 [data-pl-delay="1..5"]）删掉了：全站 HTML 与 JS 里
 * data-pl-delay 一次都没写过（grep 全仓 0 处），polish-layer.js 也不读它，
 * 所以这 5 条恒不命中。而且 data-pl-reveal 是打在 <section> 上的，
 * 卡片属于 section 内部、跟着 section 一起显影，本来就没有「逐张」可言。
 * 要错峰得先让 JS 给同级区块写 transition-delay，那是另一件事，不留假规则在这。
 */
html.qf-pl-obs [data-pl-reveal].pl-pending.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  /*
   * 必须把 .pl-pending 也写进来，不能只写 [data-pl-reveal]。
   * 上一版这里是 html.qf-pl-obs [data-pl-reveal]:not(.is-visible)，特异性 (0,3,1)，
   * 而隐藏规则 …[data-pl-reveal].pl-pending:not(.is-visible) 是 (0,4,1) —— 后者更specific，
   * 于是「减弱动画下不隐藏任何东西」这条恒不生效：规则在、看着对，实际赢不过隐藏规则，
   * pending 块照样先藏后放（只是被第 17 节的 .01ms 压成了瞬间跳变，才没造成事故）。
   * 这条由 check_polish_layer.js 的 ⑧-b 钉住：reduce 里的选择器必须覆盖隐藏规则的全部复合形态。
   */
  html.qf-pl-obs [data-pl-reveal].pl-pending:not(.is-visible),
  html.qf-pl-obs [data-pl-reveal]:not(.is-visible) { opacity: 1; transform: none; transition: none; }
}

/* ---------- 2. Hero 光晕呼吸：只改 opacity ---------- */
@keyframes pl-glow-breathe {
  0%, 100% { opacity: .82; }
  50%      { opacity: 1; }
}
/*
 * 类名逐个查证（见文件末「选择器查证」注释）：.bl-hero / .ac-hero 是猜出来的假名 ——
 * blog 的 hero 叫 .v-hero，app 站根本没有 hero 板块，那两条规则一条都不会命中。
 * 补上真实存在的 .rl-hero（releases 站）。
 */
.hv-glow,
.pf-hero::before,
.dl-hero::before,
.qp-hero::before,
.st-hero::before,
.v-hero::before,
.sup-hero::before,
.rl-hero::before,
.docs-hero::before {
  animation: pl-glow-breathe 9s ease-in-out infinite;
}

/* ---------- 3. 区块节奏：统一呼吸间距 + 交替底色 ---------- */
/* 相邻 section 之间给一条极淡的分隔hairline，替代「大片空白」的观感 */
main > section + section { border-top: 1px solid var(--qf-border-soft, rgba(15, 23, 42, .06)); }
main > section { scroll-margin-top: 84px; }

/* ---------- 4. 排版 ---------- */
h1, h2, h3, h4 {
  text-wrap: balance;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
p { text-wrap: pretty; }
/* 中文标题里夹英文时，避免英文单词被拆到两行 */
h1, h2, h3 { overflow-wrap: anywhere; }

/*
 * ---------- 5. 卡片体系：统一悬浮与描边 ----------
 * 类名清单来自测量而非命名规律：在 1440 视口滚一遍 10 站、让运行时渲染的卡也进 DOM，
 * 按「有边框/背景 + 圆角≥6 + 重复块」筛出真名，再用全仓 class="..." 交叉验证。
 * 恒不命中的规则等于没写，却因为个别站命中而看着像生效 —— 比缺样式更难发现。
 * 三段清单必须同步，由 _tools/check_polish_selector_names.js 兜底：仓库里零出现的类名报红。
 */
:is(.hv-card, .hv-step, .hv-syn, .hv-eco-item, .hv-plan, .hv-row,
    .pf-fcard, .pf-cell, .pf-mode, .pf-score, .pf-cross-card, .pf-mini, .pf-plan,
    .pf-index-item, .pf-nope-item, .pf-rel-card,
    .dl-req-card, .dl-ch-card, .dl-log-card, .dl-trust-item, .dl-faq-item,
    .support-card, .supcard, .supfaq, .sup-step, .sup-diag-card,
    .docs-idx-card, .docs-pager-item, .ds-item,
    .qp-fam-card, .qp-link-card,
    .srch-how-card, .st-card, .st-inc,
    .rl-card, .rl-mcard, .rl-chcard, .rl-mirror, .rl-faq-item,
    .v-row, .v-cross-item, .ac-card, .ac-list-item,
    .card, .faq-item, .principle, .step, .callout, .code-block) {
  --pl-card-shadow: var(--shadow-md, 0 2px 6px rgba(16,24,40,.06), 0 20px 46px -20px rgba(16,24,40,.30));
  transition:
    transform .24s var(--qf-ease-standard, cubic-bezier(.4, 0, .2, 1)),
    box-shadow .24s var(--qf-ease-standard, cubic-bezier(.4, 0, .2, 1)),
    border-color .24s ease;
}
[data-theme="dark"] :is(.hv-card, .hv-step, .hv-syn, .hv-eco-item, .hv-plan, .hv-row,
    .pf-fcard, .pf-cell, .pf-mode, .pf-score, .pf-cross-card, .pf-mini, .pf-plan,
    .pf-index-item, .pf-nope-item, .pf-rel-card,
    .dl-req-card, .dl-ch-card, .dl-log-card, .dl-trust-item, .dl-faq-item,
    .support-card, .supcard, .supfaq, .sup-step, .sup-diag-card,
    .docs-idx-card, .docs-pager-item, .ds-item,
    .qp-fam-card, .qp-link-card,
    .srch-how-card, .st-card, .st-inc,
    .rl-card, .rl-mcard, .rl-chcard, .rl-mirror, .rl-faq-item,
    .v-row, .v-cross-item, .ac-card, .ac-list-item,
    .card, .faq-item, .principle, .step, .callout, .code-block) {
  --pl-card-shadow: var(--shadow-md, 0 2px 6px rgba(16,24,40,.06), 0 20px 46px -20px rgba(16,24,40,.30));
}
:is(.hv-card, .hv-step, .hv-syn, .hv-eco-item, .hv-plan, .hv-row,
    .pf-fcard, .pf-cell, .pf-mode, .pf-score, .pf-cross-card, .pf-mini, .pf-plan,
    .pf-index-item, .pf-nope-item, .pf-rel-card,
    .dl-req-card, .dl-ch-card, .dl-log-card, .dl-trust-item, .dl-faq-item,
    .support-card, .supcard, .supfaq, .sup-step, .sup-diag-card,
    .docs-idx-card, .docs-pager-item, .ds-item,
    .qp-fam-card, .qp-link-card,
    .srch-how-card, .st-card, .st-inc,
    .rl-card, .rl-mcard, .rl-chcard, .rl-mirror, .rl-faq-item,
    .v-row, .v-cross-item, .ac-card, .ac-list-item,
    .card, .faq-item, .principle, .step, .callout, .code-block):hover {
  /*
   * 位移量走 --pl-lift：第 17 节（减弱动画）只要把这个变量设成 none，
   * 全站所有增强层位移一起消失，不必再把第 5/9 节的类名清单抄一遍 ——
   * 抄第二份清单就是下一处漂移源。
   */
  transform: var(--pl-lift, translateY(-3px));
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
  border-color: var(--qf-border, rgba(15, 23, 42, .12));
}

/*
 * ---------- 6. KPI / 统计卡：顶部品牌色条 + 等宽数字 ----------
 * 五个真名逐个查证：.hv-metrics > li（www）、.pf-stats > .pf-reveal（product）、
 * .qp-stat（api-portal.css:227）、.st-stat（status.js:546）、.rl-stat（releases.js:358）。
 * download / support 没有统计卡板块，因此不列入；新增卡请一并补进清单。
 */
.st-stat, .rl-stat, .qp-stat, .hv-metrics > li, .pf-stats > .pf-reveal {
  position: relative;
  overflow: hidden;
}
.st-stat::before, .rl-stat::before, .qp-stat::before,
.hv-metrics > li::before, .pf-stats > .pf-reveal::before {
  content: '';
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: 2px;
  background: var(--qf-brand-grad, linear-gradient(90deg, #2b5cff, #00c2ff));
  opacity: .55;
  transform: scaleX(.28);
  transform-origin: left;
  transition: transform .32s var(--qf-ease-out, cubic-bezier(0, 0, .2, 1)), opacity .32s ease;
}
.st-stat:hover::before, .rl-stat:hover::before, .qp-stat:hover::before,
.hv-metrics > li:hover::before, .pf-stats > .pf-reveal:hover::before {
  transform: scaleX(1);
  opacity: 1;
}
/* 统计数字用等宽字形，避免「1 4 7」跳动 */
.st-stat, .rl-stat, .qp-stat, .hv-metrics > li, .pf-stats > .pf-reveal {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
/* www 的 KPI 是 <ul>，浏览器默认给 li 项目符号；这里用色条当视觉锚点，圆点只会添乱 */
.hv-metrics > li { list-style: none; }

/* ---------- 7. 表格：不再挤成竖排 + 细行分隔 ---------- */
/*
 * 实测缺陷：www/privacy 的说明列被压到 87px 宽、191px 高（一行两字），
 * download 的「164.1 MB」同理。给内容列一个最小可读宽度地板。
 */
table { border-collapse: collapse; }
table th, table td {
  vertical-align: top;
  overflow-wrap: break-word;
}
table td:last-child, table th:last-child { min-width: 7.5em; }
table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--qf-surface, #fff);
}
table tbody tr { transition: background .16s ease; }
table tbody tr:hover { background: var(--qf-surface-hover, rgba(43, 92, 255, .045)); }
/*
 * 数字列右对齐不在这一层做：全站 <td class> 真实出现过的类名只有 mono / nb / num /
 * pf-* / qp-*，原后缀选择器一个都不命中；.num 的等宽+不换行各站 site.css 已给
 * （api site.css:1561）。support/sla.html:121 的 td.num 装的是「约 2 个工作日」，按数字对齐反而错。
 */
/*
 * ---------- 7b. 列宽地板：别让长 token 列把中文列压成两字一行 ----------
 * 实测两处（getComputedStyle 取证，不是看 CSS 猜的）：api/reference 端点表的路径列
 * nowrap 且长，把鉴权列挤到 70px，「会话 + 团队」被腰斩；download 构建表 174px 里文件名腰斩
 * （另见 download-site.css:507）。auto 布局把余量全给最长列，所以地板要打在被挤的列上，
 * 同时允许长 token 列在分隔符处让步。只在中大屏设地板，窄屏交给 .tbl-wrap / .qp-tbl-wrap 横向滚动。
 */
/*
 * 地板按单元格字号算，不能按 16px 的直觉拍 em：5.5em 在 api 表 13.5px 字号下只有 74px，
 * 「会话 + 团队」照样断成「会话 + 团 / 队」。中文可在任意两字间断行，差一点宽度断点就落在词中间，
 * word-break / keep-all 救不了，只能给够宽度：7.5em ≈ 101px @13.5px。
 */
@media (min-width: 768px) {
  table th:not(:first-child),
  table td:not(:first-child) { min-width: 7.5em; }
}
.qp-tbl .qp-path { white-space: normal; overflow-wrap: normal; word-break: normal; }
/*
 * 法务页（privacy / terms）：正文行长约束在 40em 对纯文字是对的，
 * 但表格被同一个约束压到实测 87px 列宽（「用户认证、云数据库…」一行两字）。
 * 宽屏时让表格从行长里破出去，独占容器宽度；窄屏不动，避免横向溢出。
 */
@media (min-width: 1280px) {
  .legal-doc .table-scroll,
  .legal-doc .tbl-wrap {
    width: 1080px;
    margin-inline: calc(50% - 540px);
  }
}

/* ---------- 8. 断词保护：代码型短语不被腰斩 ---------- */
/* api 站的「cursor-page/1」在卡里断成两截，读起来像两个 token */
code, kbd, samp, .qp-code, .hv-code, .rl-asset, .st-meta, .doc-pages a {
  overflow-wrap: break-word;
}
/*
 * .qp-contract-card 是猜的名；api 站真实的家族卡是 .qp-fam-card（api-portal.css 里 6 处），
 * 原来的 keep-all 因此从未生效。
 */
h1 code, h2 code, h3 code, .qp-fam-card code, .rl-chcard code {
  overflow-wrap: normal;
  word-break: keep-all;
}

/*
 * ---------- 9. 按钮微交互 ----------
 * 真实按钮是 .btn / .btn-ghost / .ac-btn / .v-btn / .rl-btn；
 * .qf-btn / .st-btn / .ds-btn / .qf-btn--primary 全站 0 次，只活在 _backup / _archive 里，勿再加回。
 */
.btn, .ac-btn, .rl-btn, .v-btn {
  position: relative;
  transition:
    transform .16s ease,
    box-shadow .2s ease,
    background .2s ease,
    color .2s ease,
    border-color .2s ease;
}
.btn:hover, .ac-btn:hover, .rl-btn:hover, .v-btn:hover {
  transform: var(--pl-lift, translateY(-1.5px));
}
.btn:active, .ac-btn:active, .rl-btn:active, .v-btn:active {
  transform: var(--pl-lift, translateY(.5px));
}
.btn-primary, .ac-btn--primary, .v-btn-primary {
  box-shadow: var(--shadow-brand, 0 6px 18px -6px var(--qf-brand-glow, rgba(43,92,255,.35)));
}
.btn-primary:hover, .ac-btn--primary:hover, .v-btn-primary:hover {
  box-shadow: var(--shadow-brand, 0 6px 18px -6px var(--qf-brand-glow, rgba(43,92,255,.35)));
}

/* ---------- 10. 标题区 kicker 与 hero 文案 ---------- */
.kicker {
  display: inline-flex;
  align-items: center;
  position: relative;
}
.kicker::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--qf-brand-grad, linear-gradient(90deg, #2b5cff, #00c2ff));
  opacity: .7;
}
.hv-hero h1, .pf-hero h1, .dl-hero h1, .qp-hero h1, .st-hero h1, .rl-hero h1,
.v-hero h1, .sup-hero h1, .docs-hero h1, .page-hero h1 {
  letter-spacing: -.035em;
}

/*
 * ---------- 11. 列表项悬浮 / 定价卡呼吸 ----------
 * 卡片类的悬浮位移已由第 5 节统一给，这里只补非卡片的列表项与定价卡呼吸 —— 两处都写就是漂移源。
 * .st-component 是猜的名（全站 0 次），status 站真实的事件条目叫 .st-inc。
 */
.st-inc, .ac-list li, .docs-side-list a, .rl-plat-item, .pf-list li {
  transition:
    transform .22s var(--qf-ease-standard, cubic-bezier(.4, 0, .2, 1)),
    background .22s ease,
    border-color .22s ease;
}
.st-inc:hover, .ac-list li:hover, .docs-side-list a:hover,
.rl-plat-item:hover, .pf-list li:hover {
  background: var(--qf-surface-hover, rgba(43, 92, 255, .045));
}


/*
 * ---------- 12. 状态指示脉冲（只动伪元素，不动布局） ----------
 * 只挂真是 8px 圆点的 api .qp-status-dot（api-portal.css:215）与 support .sup-status-dot
 * （support-site.css:75）。勿加 .st-overall / .rl-state：status 站写的是类名 'st-overall ok'，
 * 全站没有 data-level 属性，属性选择器恒不命中；.rl-state 是整块空态区不是圆点，
 * 套 50% 光圈会把整块糊一遍。
 * 颜色用 background: inherit 而非 currentColor：圆点自己的底色就是环该发的颜色，
 * currentColor 取继承的文字色，support 站会变成深灰一圈。
 */
.qp-status-dot, .sup-status-dot { position: relative; }
.qp-status-dot::after, .sup-status-dot::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  background: inherit;
  opacity: 0;
  animation: pl-status-pulse 2.6s ease-out infinite;
}
@keyframes pl-status-pulse {
  0%   { opacity: .5; transform: scale(.8); }
  100% { opacity: 0;  transform: scale(2); }
}

/* ---------- 13. 链接与锚点观感 ---------- */
main a:not([class]) { text-underline-offset: 3px; text-decoration-thickness: from-font; }
.hv-step-more, .qp-hero-cta a, .pf-hero-copy a { position: relative; }
/*
 * 标题的 # 锚点按钮挂在标题左侧（api-portal.css:1037 right:100%，宽 20 + 间距 8）。
 * 1024 档 qp-main 左内边距只有 24px → 实测按钮落在 [-4→16]，被视口裁掉 4px，
 * hover 时左半边点不到。窄屏把按钮收窄一档，让它落在 0 以内；≥1100px 不动原设计。
 */
@media (max-width: 1279px) {
  .qp-anchor { width: 16px; margin-right: 4px; }
}

/* ---------- 14. 代码块质感 ---------- */
pre, code, .hv-code, .qp-code, .docs-prose code {
  font-feature-settings: 'liga' 0, 'calt' 0;
  -webkit-font-smoothing: antialiased;
}
pre { scrollbar-width: thin; }

/* ---------- 15. 无障碍与浏览器细节 ---------- */
/*
 * 焦点环颜色必须取 --qf-primary：--qf-focus-ring 是 box-shadow 值（0 0 0 3px …），
 * 写进 outline 的颜色位会 invalid at computed-value time，outline 退回 initial = none，
 * 焦点环整个消失。--qf-focus-ring 只有一种正确用法：box-shadow。
 * 不要再把 --qf-focus-ring 用到任何「颜色位」上。
 */
:focus-visible {
  outline: 2px solid var(--qf-primary, #2b5cff);
  outline-offset: 2px;
  border-radius: var(--r-sm, 8px);
}
::selection {
  background: var(--qf-primary-soft, rgba(43, 92, 255, .18));
  color: var(--qf-text, inherit);
}
/*
 * 细滚动条。
 * 滑块色读 tokens.css 的 --qf-scrollbar-*，不能拿边框色顶：亮色 #e4e8f0 对白底 1.20:1、
 * 暗色 #232d43 对暗底 1.44:1，低于 WCAG 2.2 SC 1.4.11 的 3:1，视觉上等于没有滚动条。
 * scrollbar-color 与 ::-webkit-scrollbar 两条路径都要留：Chrome 121 / Safari 26.2 才支持标准属性，
 * 旧内核只认伪元素（现代内核下 ::-webkit-* 被忽略属规范行为）。
 * 两条路径必须指向同一组令牌，否则不同浏览器看到不同颜色；也不要再让 html 单独设一份，
 * html(0,0,1) 压过 *(0,0,0)，同一页面能测出两种颜色。
 */
* { scrollbar-width: thin; scrollbar-color: var(--qf-scrollbar-thumb, #7d8596) var(--qf-scrollbar-track, transparent); }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: var(--qf-scrollbar-track, transparent); }
*::-webkit-scrollbar-thumb {
  background: var(--qf-scrollbar-thumb, #7d8596);
  border: 3px solid transparent;
  background-clip: content-box;
  border-radius: 999px;
}
*::-webkit-scrollbar-thumb:hover { background-color: var(--qf-scrollbar-thumb-hover, #70788a); }

/* 图片与内联 SVG 不因增强层产生基线空隙 */
img, svg { max-width: 100%; }

/* ---------- 16. 页面入场 ---------- */
main { animation: pl-page-enter .45s var(--qf-ease-out, cubic-bezier(0, 0, .2, 1)) both; }
@keyframes pl-page-enter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/*
 * ---------- 17. 减弱动画 ----------
 * 用「全量归零」写法，不抄第 2/5/9/16 节的类名清单：抄第二份必然漂移，而漂移只在开了
 * reduced-motion 的机器上才看得见。
 * 用 .01ms 而不是 0s：0s 会让 transitionend / animationend 根本不触发，依赖它们收尾的脚本
 * （导航、揭示）会卡在中间态。
 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
  }
  html { scroll-behavior: auto; }
  :root { --pl-lift: none; }   /* 第 5/9 节的悬浮/按压位移一起失效 */
}

/* ---------- 18. 打印：增强层不得吃掉内容 ---------- */
@media print {
  [data-pl-reveal], main { opacity: 1 !important; transform: none !important; animation: none !important; }
  table thead th { position: static; }
}

/*
 * ---------- 19. 补齐缺失的无前缀令牌 ----------
 * --r-md/lg/xl、--mono、--beta 等名字此前有 35 处 var() 引用而全站无定义、无兜底：
 * 圆角落回 0、阴影落回 none、字族落回衬线。check_css_var_contract.js 只审 --qf-* / --brand-*，
 * 不看无前缀名字，所以一路跑绿。取值沿用 v4-skin.css 既有档位，只补中间缺的格。
 * --beta 是维护态色：--warn 已被 degraded、--brand 已被 in_progress 占用，故取紫，深色模式换浅紫保对比度。
 */
:root {
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  /*
   * --shadow-md 定义在 v4-skin.css（与 sm/lg/brand 同处），勿在此再写一份字面值 ——
   * 两处各写一份正是「同一档两个值」的来源。
   */
  --mono: var(--qf-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  --beta: #6d28d9;
  --beta-soft: rgba(109, 40, 217, .12);
}
[data-theme="dark"] {
  --beta: #c4b5fd;
  --beta-soft: rgba(196, 181, 253, .16);
}

/*
 * ---------- 20. 卡片静息层次 ----------
 * 6 站的卡片静息态没有阴影，而第 5 节只把阴影写在 :hover，不悬停就没有层次。
 * 用 :where 让整条特异度为 0：站点自己的 box-shadow 与第 5 节的 :is(…):hover 都赢，
 * 既不会叠出双层阴影，也不会覆盖某站刻意做的无阴影卡。有静息阴影的 4 站不动。
 */
:where(.hv-card, .hv-eco-item, .hv-plan, .hv-step,
       .docs-idx-card, .docs-pager-item,
       .qp-fam-card, .qp-link-card,
       .supcard, .supfaq, .support-card) {
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
}
/*
 * .srch-how-card 与 blog 的 .v-row 从中移出：两站都已在站内
 * 自己声明静息阴影。兜底层只留"站内确实没写"的卡片。
 */

/*
 * ---------- 21. 标题行高收口：展示型标题不用正文行距 ----------
 * 三处标题继承了正文行高：status.css:108 .st-sec-head h2（25px）、releases.css:226
 * .rl-sec-head h2（26px）、blog-site.css:794 .v-body h2（1.38em），都从 body 继承 1.75 ——
 * 26px 标题配 45px 行高，换行就散架。只收行高，不动字号与字重：字号由各站内容密度决定，
 * 硬统一会撑破布局。正文区留 1.34，比展示型松一档，读长标题不挤。
 */
.st-sec-head h2, .rl-sec-head h2, .rl-ver-head, .hv-head h2, .section-head h2 { line-height: 1.2; }
.v-body h2 { line-height: 1.34; }

/*
 * ---------- 22. api 站导航补外壳 ----------
 * api 站把 #siteHeader 直接挂在 body 上（其余站在 .header 内），site.css 与 nav-mega.css 的
 * .header 后代规则全部不命中，这里补外壳。
 * 全幅底带用 padding-inline 而不是 100vw：百分比按 body 内容宽（已扣滚动条）解析，不产生横向滚动条。
 * 1320px 对齐 .qp-shell，导航与正文落在同一条竖线；sticky 只在 ≥600px 打开，390px 时导航折成 104px 高，
 * 小屏只留背景与边线。
 */
body > #siteHeader {
  z-index: 100;
  max-width: none;
  background: color-mix(in srgb, var(--bg, #fff) 82%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-2, rgb(237, 240, 246));
  padding-inline: max(24px, calc((100% - 1320px) / 2 + 24px));
}
@media (min-width: 640px) {
  body > #siteHeader { position: sticky; top: 0; }
}
@media (max-width: 1023px) {
  body > #siteHeader { padding-inline: 16px; }
}

/*
 * ---------- 23. 尾部呼吸：单侧 padding 造成首尾不对称 ----------
 * .st-section / .rl-sec / .docs-idx-tight 只写了上 padding，相邻区块间只剩一档净空，末块直接贴 footer。
 * 站点用的是 padding 简写，展开成 longhand 后特异度 (0,1,0)，:where 的 (0,0,0) 恒输；
 * 重复同类名到 (0,2,0) 才能稳赢，且不依赖 polish-layer 的加载顺序（blog 站顺序相反）。
 */
.st-section.st-section { padding-bottom: 44px; }
.rl-sec.rl-sec { padding-bottom: 46px; }
.docs-idx-tight.docs-idx-tight { padding-bottom: 40px; }

/*
 * ---------- 24. 正文链接的 hover 线索 ----------
 * 正文句子里的裸链接在各站都是主色文字，静息态与正文只差颜色，指针移上去没有任何反馈。
 * 只命中无 class 的 a：带 class 的多是按钮或整卡链接，已有自己的 hover 语言，不该再叠下划线。
 */
main p a:not([class]):hover, main li a:not([class]):hover,
main p a:not([class]):focus-visible, main li a:not([class]):focus-visible {
  text-decoration: underline;
}

/*
 * ---------- 25. 圆角刻度：卡片 16 / 大卡 20 / 按钮 12 / 小控件 8 ----------
 * 即 tokens.css 的 --r-sm/md/lg = 8/12/16 与 --r-xl 20。散出去的 14 / 18 / 24 / 5 已逐条写回各站源规则，此处不留同值双写。
 * 有意不动的一批：pill 形（rad 999）是分段控件与标签的语言；.sup-search button 12px 配 52px 高，本身在阶上；
 * .dl-cta-jump 是文字式按钮（download-site.css:384）。
 */

/*
 * ---------- 26. 中性发丝线统一走 --qf-border ----------
 * 浅色 #e4e8f0 / 深色 #232d43，逐主题同一值；--pl-hairline 并入后已删除，别再单独定义。
 * 深色必须另给一档，只写浅色硬值会让深色站卡片镶一圈亮边。
 * 带品牌色的描边（releases rl-card.cur、product pf-bento-wide 的 rgba(43,92,255,.26)）
 * 是强调色，不属于中性发丝线，一律不碰。
 */

/*
 * v4 · 视觉重构：字阶、导航密度、按钮层级、卡片层次、首屏节奏 —— 目标是把 11 站读成
 * 同一套设计系统，而不是 11 个各自拼出来的页面。
 *
 * 为什么不重写各站 CSS：站点 CSS 合计 20 万行，逐站重写既无法一次验证，也会把已修好的
 * 无障碍 / 深色 / 响应式规则一起推倒。这一层是覆盖层：站点自己的规则仍赢，只在本层显式
 * 声明的属性上改观感。改写一律用 .x.x（0,2,0），严格高于站点单类名（0,1,0），
 * 因此不依赖加载顺序（blog 站顺序是反的）。
 *
 * 不改三件事：不隐藏任何内容（本层没有 opacity:0 / display:none）、不动品牌色本身
 * （主色、渐变、语义色仍来自 tokens.css）、不动信息架构（链接、层级、文案顺序不变）。
 */

/* ---------- 27. 设计令牌 v6 ---------- */
:root {
  /* 字阶：越大的字越紧，行高越小 —— 这是标题与正文分开读的基础 */
  --pl-fs-display: 36px;
  --pl-fs-h1: 36px;
  --pl-fs-h2: 28px;
  --pl-fs-h3: 18px;
  --pl-fs-lead: 16px;
  --pl-lh-tight: 1.12;
  --pl-lh-snug: 1.26;
  --pl-track-tight: -.021em;
  --pl-ease: cubic-bezier(.22, .61, .36, 1);
  --pl-dur: .18s;
  --pl-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  /*
   * 导航高度 --pl-nav-h 已移到 site.css:13。
   * 原因见那边的注释：移动端要把顶栏降到 56，覆盖块在 site.css 的 @media(max-width:479px)，
   * 而同为零特异性的 :root 由源序决胜 —— 令牌定义留在这里会把 site.css 的移动端覆盖压掉。
   * 这里只留导航底色，它没有响应式分档需求。
   */
  --pl-nav-bg: rgba(255, 255, 255, .78);

  /* 卡片层次：静息只有一圈很浅的投影，hover 才抬起 —— 这是密度感的来源 */
  --pl-card-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
  --pl-card-shadow-hover: var(--shadow-md, 0 2px 6px rgba(16,24,40,.06), 0 20px 46px -20px rgba(16,24,40,.30));
  --pl-brand-ring: rgba(43, 92, 255, .20);
}
[data-theme="dark"] {
  --pl-nav-bg: rgba(14, 17, 22, .74);
  --pl-brand-ring: rgba(108, 143, 255, .28);
}

/*
 * ---------- 28. 排版：标题收重，正文放松 ----------
 * 旧值大量 800 字重 + -0.02em，中文在 800 下会糊成一团（笔画粘连）；
 * 700 是系统字体里真正有字重区分的一档，中文也更清晰。
 */
h1, h2, h3, h4 { text-wrap: balance; }
p, .lead, .sub { text-wrap: pretty; }

.hero.hero h1,
.hv-hero.hv-hero h1,
.pf-hero.pf-hero h1,
.qp-hero.qp-hero h1,
.dl-hero.dl-hero h1,
.st-hero.st-hero h1,
.rl-hero.rl-hero h1,
.v-hero.v-hero h1,
.srch-hero.srch-hero h1,
.sup-hero.sup-hero h1 {
  font-weight: 700;
  letter-spacing: var(--pl-track-tight, -.02em);
  line-height: var(--pl-lh-tight, 1.14);
}
.hero.hero h1, .hv-hero.hv-hero h1 { font-size: var(--pl-fs-display); }
.page-hero.page-hero h1 { font-size: var(--pl-fs-h1); font-weight: 700; letter-spacing: var(--pl-track-tight, -.02em); line-height: 1.14; }

.section-head.section-head h2,
.hv-head.hv-head h2,
.st-sec-head.st-sec-head h2,
.rl-sec-head.rl-sec-head h2,
.docs-idx-hero.docs-idx-hero ~ * .section-head h2 {
  font-size: var(--pl-fs-h2);
  font-weight: 700;
  letter-spacing: -.018em;
  line-height: var(--pl-lh-snug);
}
.section-head.section-head .sub { font-size: var(--pl-fs-lead); }
.section-head.section-head h3 { font-size: var(--pl-fs-h3); font-weight: 700; letter-spacing: -.012em; }

.page-hero.page-hero .lead,
.hero.hero .lead,
.pf-hero.pf-hero .pf-lead,
.srch-hero.srch-hero .srch-lead,
.v-hero.v-hero .v-hero-lead {
  font-size: var(--pl-fs-lead);
  line-height: 1.72;
}

/*
 * ---------- 29. 导航：更密、更轻、状态更明确 ----------
 * 旧导航 66px + 14px 链接 + 38px 控件，在 1440 下占掉首屏 7%；
 * 新值 62px + 13.5px + 34px，同样的链接数下横向更舒展。
 */
.header.header {
  background: var(--pl-nav-bg, rgba(255, 255, 255, .78));
  border-bottom-color: var(--qf-border);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  backdrop-filter: blur(18px) saturate(1.6);
}
.header-inner.header-inner { height: var(--pl-nav-h, 62px); }
/*
 * min-height 44 = 触控地板。brand 是首页入口，也是移动端最常点的
 * 那个元素；它原本 28/34 高，实测在 1024 宽只有 108×28。
 */
.brand.brand { font-weight: 700; letter-spacing: -.025em; min-height: 44px; }
.logo.logo { border-radius: var(--r-md, 12px); box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22)); }

/*
 * 顶栏横向收口：左右 padding 随视口收缩。12px 是中文可读底线，字阶收敛后 1024 宽处
 * .nav-tools 右缘溢出 9px，四站共用这套顶栏、同时出现。
 * 这里 (0,2,1) 压得住 site.css 同档的 .nav-links a，也不能新增 @media（断点门禁是棘轮的）。
 * ≥1200 仍是 12px，1024 收到 10.24px，7 个链接共腾出约 24.6px。只动内边距不动字号。
 */
/*
 * 顶栏控件的触控地板：34px → 44px。这些是双类选择器 (0,2,0)/(0,2,1)，site.css / tokens.css
 * 里单类的 44px 规则全被压掉，实测 1024 宽 icon-btn 34×34、lang 26 高、nav 链接 39 高。
 * 写进基档而不挂在 max-width:1023：断点门禁是棘轮的，且 1024（iPad Pro 横屏）正好会落成全站
 * 控件最小的一档。代价是横向变紧，1024 由下面 .nav-links 的 clamp 吸收。
 */

.nav-links.nav-links a {
  font-size: 14px;
  /*
   * min(12px, 1vw) → clamp(6px, calc(3vw - 26px), 12px)。
   * 触控地板把三个控件抬到 44 后，1024 档被挤出 5px 真实横向溢出（scrollWidth 1029 / clientWidth 1024）。
   * 缺口 20px，7 个链接每侧各让 2px 正好补回 28px。
   * 用 clamp 而不是调小 1vw：≥1280 时上界锁 12px，桌面逐像素不变；下界 6px 顺带修了 390 宽时
   * 抽屉链接内边距只剩 3.9px、字贴边的问题。斜率与旧线在 1280 相交，1024 收到 6px 共让 31px。
   */
  /* 语言切换抬到 44 后这一档又紧 17px，斜率已并入下面这条声明。 */
  padding: 7px clamp(6px, calc(3vw - 26px), 12px);
  border-radius: var(--r-sm, 8px);
  /* 触控地板：只加高度，不改字号与横向内边距 —— 顶栏在 1024 已经很紧。 */
  min-height: 44px;
  display: flex;
  /*
   * 这条 align-items 试删过，被真浏览器判据打回（1440 档 normal）。
   * nav-mega.css:22 的 center 只覆盖带 .nav-link 的 <a>，.nav-links a 这条
   * (0,2,0) 覆盖的是全部导航链接，源层没有等价物。
   */
  align-items: center;
  transition: color var(--pl-dur, .18s) var(--pl-ease, ease), background var(--pl-dur, .18s) var(--pl-ease, ease);
}
.nav-links.nav-links a.active {
  box-shadow: inset 0 0 0 1px var(--pl-brand-ring, rgba(43, 92, 255, .2));
}
.nav-tools.nav-tools { gap: 6px; }

/*
 * 登录 / 注册：38 / 43 → 44 触控地板。
 * 这两枚按钮的样式由 nav-session.js 注入的 <style> 定义（.qf-login-link /
 * .qf-register-link，单类 0,1,0），注入块在文档里排在所有 <link> 之后 ——
 * 所以在 site.css 里加 min-height 会被它压回去（改了没反应那一类）。
 * 这里用 (0,3,0) 稳赢，既不必改 11 份 nav-session.js 副本，也不依赖注入顺序。
 */
.nav-tools.nav-tools .qf-login-link,
.nav-tools.nav-tools .qf-register-link {
  min-height: 44px;
  display: inline-flex;
  /*
   * 这条 align-items 试删过一次，被真浏览器判据打回：
   * 注入样式（nav-session.js:314）只给 .qf-login-link 设了字号/边框，
   * site.css:667 也没有 align-items，.nav-tools 的 center 是父元素的、
   * 不会继承给链接。删掉后 768 档实测 align-items 从 center 退回 normal。
   * 双类名规则里被加倍的那个类常常是祖先（这里是 .nav-tools），
   * 拿它去找"源层同值声明"会找到父元素的声明 —— 静态分诊会给出假等价。
   */
  align-items: center;
  justify-content: center;
}

/* 图标按钮：从「带边框的小方块」改成「静息无框、hover 才出底色」 */
.icon-btn.icon-btn {
  /*
   * 34 → 44。图标本身仍是 18px，
   * 变大的只是可点区域 —— 视觉上像"松了一圈"，不会显得按钮更重。
   */
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm, 8px);
  border-color: transparent;
  background: transparent;
  color: var(--qf-text-muted, #5A6478);
}
.icon-btn.icon-btn:hover {
  background: var(--qf-surface-hover, #F0F2F7);
  border-color: transparent;
  color: var(--qf-text, #101828);
  transform: none;
}
.icon-btn.icon-btn svg { width: 18px; height: 18px; }

/*
 * 语言切换：从「三个并排色块」收到「一枚分段胶囊」，
 * 选中态由整块品牌渐变改成白底品牌字 —— 导航里只需要一个高饱和按钮。
 */
.lang-switch.lang-switch {
  /*
   * 34 → 48，段内按钮 26 → 44。
   * 44 是触控地板，但分段控件的按钮嵌在外壳里，外壳必须吃掉 1px 边框 + 2px
   * 横向内边距，所以壳取 48（内高 46，按钮 stretch 到 46——不低于 44 即可）。
   * 视觉上从"迷你胶囊"变成"与图标按钮同高的分段条"，比原来更符合顶栏节奏。
   */
  height: 48px;
  padding: 0 2px;
  gap: 2px;
  border-radius: 999px;
  border-color: var(--qf-border-soft, #EEF1F6);
  background: var(--qf-surface-hover, #F0F2F7);
}
.lang-switch.lang-switch button {
  min-width: 44px;
  min-height: 44px;
  padding: 0 8px;
  font-size: 12px;
  /*
   * font-weight 删了 —— site.css:137 的 .lang-switch button
   * 与这里是同一组元素（本段没有祖先限定），取值同为 600，纯属重复。
   * padding / min-* 不能删：它们的竞争者在 nav-mega.css 的 @media 里，
   * 而 nav-mega 是全网死资产 —— 删了就没人给这两个值。
   */
  border-radius: 999px;
  color: var(--qf-text-muted, #5A6478);
}
.lang-switch.lang-switch button:hover { color: var(--qf-text, #101828); }
.lang-switch.lang-switch button.on {
  background: var(--qf-surface, #fff);
  color: var(--qf-primary, #2B5CFF);
  font-weight: 700;
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
}
[data-theme="dark"] .lang-switch.lang-switch button.on { background: var(--qf-surface-hover, #222A35); }

/* 登录 / 注册：导航里的按钮比正文按钮矮一档 */
/*
 * 登录 / 注册：导航里的按钮比正文按钮矮一档。
 * 34 → 44。这条是"矮一档"的设计意图，但 34 已经低于触控地板；
 * 相对高度差改由内边距与字号体现（13px vs 正文 14px），不再压可点高度。
 */
.nav-tools.nav-tools .btn { min-height: 44px; padding: 0 14px; font-size: 13px; border-radius: var(--r-sm, 8px); }
.nav-tools.nav-tools .btn-primary {
  background: linear-gradient(180deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0)), var(--qf-primary, #2B5CFF);
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
}
.nav-tools.nav-tools .btn-primary:hover {
  background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0)), var(--qf-primary-hover, #1E50E8);
  transform: none;
}
.nav-tools.nav-tools .btn-ghost { background: transparent; border-color: var(--qf-border); }
.nav-tools.nav-tools .btn-ghost:hover {
  background: var(--qf-surface-hover, #F0F2F7);
  color: var(--qf-text, #101828);
  border-color: var(--qf-border, #E3E7EF);
  transform: none;
}

/*
 * ---------- 30. 按钮：统一到 12px 圆角档与两级层次 ----------
 * 主按钮：品牌色实底 + 极轻高光，不再用 135° 双色渐变（渐变在深色下会发灰）；
 * 次按钮：白底发丝线，hover 只换描边与字色，不做位移。
 */
.btn.btn { border-radius: var(--r-md, 12px); font-weight: 600; letter-spacing: -.006em; }
/*
 * 字色必须由按钮变体自己决定。正文容器里的「.容器 a { color }」是 (0,1,1)，
 * 高于 .btn-primary 的 (0,1,0)，会把主按钮的白字改成品牌蓝 —— 蓝字落在蓝底上，
 * 按钮文字等于消失。这里用三重点类 (0,3,0)
 * 压住任何「容器 + a」规则，与下面背景色的写法一致。
 */
.btn.btn-primary.btn-primary {
  color: #fff;
  background: linear-gradient(180deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0)), var(--qf-primary, #2B5CFF);
  box-shadow: var(--shadow-brand, 0 6px 18px -6px var(--qf-brand-glow, rgba(43,92,255,.35)));
}
.btn.btn-primary.btn-primary:hover {
  background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0)), var(--qf-primary-hover, #1E50E8);
  box-shadow: var(--shadow-brand, 0 6px 18px -6px var(--qf-brand-glow, rgba(43,92,255,.35)));
}
.btn.btn-ghost.btn-ghost { color: var(--qf-text, var(--ink, #0F172A)); background: var(--qf-surface, #fff); border-color: var(--qf-border); }
.btn.btn-ghost.btn-ghost:hover { border-color: var(--qf-primary-ring, rgba(43, 92, 255, .35)); color: var(--qf-primary, #2B5CFF); }
/*
 * 原来这里还有一条 .btn.btn-danger.btn-danger { color:#fff }。
 * 删掉的理由是过时：site.css 里 .btn-danger 早已是 color:#fff，
 * 覆盖层的三重类名只剩加倍特异性，不再改变任何取值。
 */
.btn.btn:focus-visible { outline: 2px solid var(--qf-primary, #2B5CFF); outline-offset: 2px; }

/*
 * ---------- 31. 首屏：api 站从「整块高饱和蓝」改成「深色玻璃 + 品牌光」 ----------
 * 原来 qp-hero 直接铺 var(--qf-brand-grad)：整页唯一的大色块，和白底正文、
 * 白卡片的层级是断的。改用深墨底 + 右上角品牌光晕，白字对比度不变，
 * 但视觉重心从「彩色横幅」变成「产品面板」，与 api 站的 B 端气质一致。
 */
.qp-hero.qp-hero {
  /*
   * border-radius 删了 —— api-portal.css:145 的 .qp-hero
   * 本来就是 var(--r-lg,16px)，覆盖只是重复取值。
   */
  background:
    radial-gradient(120% 150% at 88% -12%, rgba(43, 92, 255, .42) 0%, transparent 58%),
    radial-gradient(90% 120% at 0% 110%, rgba(0, 194, 255, .18) 0%, transparent 55%),
    linear-gradient(155deg, #0C1426 0%, #111C33 52%, #0A1526 100%);
  box-shadow: var(--shadow-lg, 0 24px 56px -22px rgba(15,23,42,.38), 0 2px 8px -2px rgba(15,23,42,.10));
}
.qp-hero.qp-hero::after { opacity: .38; }
.qp-hero.qp-hero .qp-hero-cta .btn-primary {
  background: #fff;
  color: #12203A;
  box-shadow: var(--shadow-md, 0 2px 6px rgba(16,24,40,.06), 0 20px 46px -20px rgba(16,24,40,.30));
}
.qp-hero.qp-hero .qp-hero-cta .btn-primary:hover { background: #F2F5FF; color: #12203A; }
/*
 * 的 .btn-ghost 统一改成了白底深字；在深色 hero 里会变成「白底白字」的隐形按钮，
 * 这里按 500 特异度把 hero 内的 ghost 还原成半透明玻璃按钮。
 */
.qp-hero.qp-hero .qp-hero-cta .btn-ghost {
  background: rgba(255, 255, 255, .10);
  border-color: rgba(255, 255, 255, .30);
  color: #fff;
}
.qp-hero.qp-hero .qp-hero-cta .btn-ghost:hover {
  background: rgba(255, 255, 255, .17);
  border-color: rgba(255, 255, 255, .5);
  color: #fff;
}

/*
 * api 统计条：四个 24px 品牌蓝大字像四个标题，压过了正文。
 * 改成 16px 等宽强调值 + 描述，节奏回到「规格条」而不是「四个海报」。
 */
.qp-stat.qp-stat {
  border-color: var(--qf-border);
  /* border-radius 删了 —— api-portal.css:258 已是 var(--r-lg,16px)。 */
  padding: 14px 16px;
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
}
.qp-stat.qp-stat b {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.01em;
  /* font-variant-numeric 删了 —— api-portal.css:259 已声明 tabular-nums。 */
  color: var(--qf-text, #101828);
}
.qp-stat.qp-stat span { font-size: 13px; line-height: 1.6; }

/* ---------- 32. 卡片：静息一层浅影，hover 抬起一格 ---------- */
:where(.card, .hv-card, .pf-mini, .pf-cell, .dl-ch-card, .supcard, .docs-idx-card, .qp-fam-card, .rl-card, .st-card) {
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(15,23,41,.05), 0 10px 24px -18px rgba(15,23,41,.22));
}
.card.card:hover,
.hv-card.hv-card:hover,
.pf-mini.pf-mini:hover,
.docs-idx-card.docs-idx-card:hover,
.qp-fam-card.qp-fam-card:hover,
.supcard.supcard:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md, 0 2px 6px rgba(16,24,40,.06), 0 20px 46px -20px rgba(16,24,40,.30));
  border-color: var(--qf-primary-ring, rgba(43, 92, 255, .3));
}

/*
 * ---------- 33. docs 首页：收紧首屏、放大示意图、给正文一条可读宽度 ----------
 * 实测：原首屏右侧插图 320px，左侧文案只有两行，首屏底部留下约 90px 空带；
 * 插图放大到 380px 并把上下 padding 各收 8px，空带被内容吃掉。
 */
.page-hero.docs-idx-hero.page-hero.docs-idx-hero { padding-top: 44px; padding-bottom: 40px; }
.docs-idx-hero-grid.docs-idx-hero-grid { grid-template-columns: minmax(0, 1fr) 380px; gap: 48px; }
/*
 * 这一层的选择器是双类名（0,2,0），站点样式表里再窄断点的单类名规则盖不住它：
 * 380px 固定插图轨在 ≤414px 视口里把文案列压到 0 宽（正文一字一行，实测
 * 320/360/414 三档命中「每行 <3 字」）。窄屏必须在这里同特异性收回单列并隐藏插图。
 */
@media (max-width: 1023px) {
  .docs-idx-hero-grid.docs-idx-hero-grid { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .docs-idx-hero-art.docs-idx-hero-art { display: none; }
}
/*
 * 原来这里是一条流体 clamp(2.2rem, 1.72rem + 1.9vw, 3.05rem)，
 * 在 390 算出 42.6px、1440 算出 48.8px —— 而同一份令牌表里 --pl-fs-h1 就是 36px，
 * 其余 10 站与 docs 自己的内容页 h1 也都是 36。>40px 的 h1 只有这一处，
 * 于是一个「首页」比同站「内容页」的字大 36%，跨站看就是这套字阶里多出一档。
 * 上面的窄屏注释讲的是 grid 列宽（插图轨挤文案），与字号无关，字号跟着一起收口。
 */
.docs-idx-hero.docs-idx-hero h1 {
  font-size: var(--pl-fs-h1, 36px);
  font-weight: 700;
  letter-spacing: -.03em;
  /*
   * 不能删：docs-index.css:48 的 1.1 会被本层 .page-hero.page-hero h1（同为 0,2,1，但在文件后部）
   * 压掉，390 档会从 39.6px 变成 41.04px。覆盖层内部之间同样会互相压。
   */
  line-height: 1.1;
}
.docs-idx-hero-sub.docs-idx-hero-sub { font-size: var(--pl-fs-lead, 1.05rem); line-height: 1.78; max-width: 58ch; }

/* ---------- 34. 页脚与代码：收口到同一套字阶 ---------- */
.footer.footer { border-top-color: var(--qf-border); }
.footer-col.footer-col .footer-col-t {
  /*
   * font-size / font-weight / text-transform 删了 —— footer.css:101 的
   * .footer-col .footer-col-t（0,2,0）本来就是 12px + 700 + uppercase，
   * 这三条覆盖只是在加特异性重复同一个取值。剩下的两条是真覆盖：
   * letter-spacing .06em 压 .1em、color 压 --f-ink-2。
   */
  letter-spacing: .06em;
  color: var(--qf-text-muted, #5A6478);
}
pre, code, kbd, samp { font-family: var(--pl-mono, monospace); }
::selection { background: var(--qf-primary-soft, rgba(43, 92, 255, .14)); }

/* ---------- 35. 动效：统一缓动，尊重减弱偏好 ---------- */
a, button, .btn, .card, .hv-card, .docs-idx-card, .qp-fam-card {
  transition-timing-function: var(--pl-ease, cubic-bezier(.22, .61, .36, 1));
}
@media (prefers-reduced-motion: reduce) {
  .header.header { scroll-behavior: auto; }
  .card.card:hover,
  .hv-card.hv-card:hover,
  .pf-mini.pf-mini:hover,
  .docs-idx-card.docs-idx-card:hover,
  .qp-fam-card.qp-fam-card:hover,
  .supcard.supcard:hover { transform: none; }
  /* V7 §36.6 新增的三个卡片类同步进减弱动画名单 */
  .dl-ch-card.dl-ch-card:hover,
  .rl-card.rl-card:hover,
  .st-card.st-card:hover { transform: none; }
}

/*
 * ---------- 36. V7 设计语言 ----------
 * 一次改动同时落到 11 站 + admin：本文件是唯一被全部站点加载的增强层。
 * 约定沿用本层已有规则 —— 双类名 (0,2,0) 起，不依赖加载顺序（blog 是反的）；
 * 颜色一律取 tokens.css 的 --qf-v7-*（亮暗同批次定义），所以本节零字面色值，
 * 两套主题自动跟随。首屏规则再加一层 html[data-theme] 前缀 (0,3,x)，
 * 是为了压住 dl/srch/v 站各自写的 [data-theme="dark"] .xxx-hero 深色覆盖。
 */

/* 36.1 首屏：统一一层主题渐变托底。api 站 (.qp-hero) 不参与 —— 它已是深色玻璃面板；
 * www (.hv-hero) 也不参与 —— 它在 home-v5.css 里有自己的墨色首屏（V7 官网的版式主张） */
html[data-theme] .pf-hero.pf-hero,
html[data-theme] .v-hero.v-hero,
html[data-theme] .st-hero.st-hero,
html[data-theme] .srch-hero.srch-hero,
html[data-theme] .page-hero.page-hero,
html[data-theme] .sup-hero.sup-hero,
html[data-theme] .rl-hero.rl-hero,
html[data-theme] .dl-hero.dl-hero,
html[data-theme] .hero.hero {
  background: var(--qf-v7-hero-bg);
  border-bottom-color: var(--qf-v7-hairline);
}

/* 营销型首屏（product / blog）给足呼吸，工具型首屏（docs / search / status）保持紧凑 */
html[data-theme] .pf-hero.pf-hero,
html[data-theme] .v-hero.v-hero {
  padding-block: clamp(56px, 6.6vw, 96px);
}

/*
 * 36.2 标题：V7 把首屏字号抬到 clamp(34→56)，行高压到 1.06、字距收到 -.032em。
 * 原值全站 36px / 1.14 —— 在 1440 宽下 h1 只比 h2 大 8px，首屏没有主次。
 */
html[data-theme] .hv-hero.hv-hero h1,
html[data-theme] .pf-hero.pf-hero h1,
html[data-theme] .v-hero.v-hero h1,
html[data-theme] .hero.hero h1,
html[data-theme] .st-hero.st-hero h1,
html[data-theme] .rl-hero.rl-hero h1,
html[data-theme] .dl-hero.dl-hero h1,
html[data-theme] .srch-hero.srch-hero h1,
html[data-theme] .sup-hero.sup-hero h1,
html[data-theme] .page-hero.page-hero h1 {
  font-size: clamp(34px, 4.2vw, 56px);
  line-height: 1.06;
  letter-spacing: -.032em;
  font-weight: 700;
}

/* 首屏导语：16 → 17，行高放松；行宽锁在 34 字上下，中文长句不再横贯整屏 */
html[data-theme] .hv-hero.hv-hero .hv-lead,
html[data-theme] .pf-hero.pf-hero .pf-lead,
html[data-theme] .v-hero.v-hero .v-hero-lead,
html[data-theme] .hero.hero .lead,
html[data-theme] .page-hero.page-hero .lead,
html[data-theme] .st-hero.st-hero .st-lead,
html[data-theme] .rl-hero.rl-hero .rl-lead,
html[data-theme] .dl-hero.dl-hero .lead,
html[data-theme] .srch-hero.srch-hero .srch-lead,
html[data-theme] .sup-hero.sup-hero .lead {
  font-size: 17px;
  line-height: 1.72;
  max-width: 34em;
}

/* 36.3 区块标题：28 → clamp(26→40)，副标题放宽到 46 个汉字以内 */
html[data-theme] .section-head.section-head h2,
html[data-theme] .hv-head.hv-head h2,
html[data-theme] .st-sec-head.st-sec-head h2,
html[data-theme] .rl-sec-head.rl-sec-head h2 {
  font-size: clamp(26px, 2.4vw + 8px, 40px);
  line-height: 1.12;
  letter-spacing: -.024em;
}
html[data-theme] .section-head.section-head .sub {
  font-size: 16px;
  line-height: 1.72;
  max-width: 46em;
}
/*
 * releases / status 的区块标题前各挂了一个 9×9 渐变圆点。这两站之外没有任何
 * 区块标题带这个标记，而官网 V7 的区块索引是「顶部发丝线 + 右侧编号」——
 * 40px 标题旁边单摆一个圆点，读起来更像没删掉的项目符号。只摘标记，不动标题与间距。
 */
html[data-theme] .rl-sec-head.rl-sec-head h2::before,
html[data-theme] .st-sec-head.st-sec-head h2::before {
  content: none;
}

/*
 * 36.4 眉标（kicker）：从裸字改成胶囊标签。
 * 原先只是一个 uppercase 小字，和 h2 之间没有层次；胶囊把它变成"分区索引"。
 */
html[data-theme] .kicker.kicker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border: 1px solid var(--qf-v7-eyebrow-bd);
  border-radius: var(--qf-radius-full, 999px);
  background: var(--qf-v7-eyebrow-bg);
  color: var(--qf-v7-eyebrow-fg);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  line-height: 1.5;
  margin-bottom: 16px;
}
/*
 * 三站自己起的眉标类名：api 的 .qp-kicker 是裸字（无底色），releases / status 的
 * .rl-kicker / .st-kicker 虽已是胶囊，但底色用 --brand-soft、无描边 ——
 * 压在首屏的浅蓝渐变上两者几乎同色：像素实测胶囊内 238,243,253、胶囊外 242,246,255，
 * 只差 3–4 级，肉眼看就是「没有胶囊」。
 * 统一到 36.4 的同一套令牌：底色 10% 品牌 + 24% 品牌描边，胶囊边界在渐变上立得住。
 */
html[data-theme] .qp-kicker.qp-kicker,
html[data-theme] .rl-kicker.rl-kicker,
html[data-theme] .st-kicker.st-kicker {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border: 1px solid var(--qf-v7-eyebrow-bd);
  border-radius: var(--qf-radius-full, 999px);
  background: var(--qf-v7-eyebrow-bg);
  color: var(--qf-v7-eyebrow-fg);
  line-height: 1.5;
  margin: 0 0 16px;
}

/* 36.5 区块节奏：76 → clamp(64→104)。长页面在 1440 下不再一段紧贴一段 */
/*
 * 用 padding 简写而不是 padding-block：ui.css 里有一条 p[style*=...] 的 padding 简写，
 * 粗粒度特异度算到 903，任何 3 段的 longhand 写法都会被判为「永远不生效」。
 * `.section` 本身没有横向内边距（横向由 .container 负责），给简写不改变横向。
 */
html[data-theme] .section.section:not(.section-tight) {
  padding: clamp(64px, 6.2vw, 104px) 0;
}
html[data-theme] .section-alt.section-alt { background: var(--qf-v7-tint); }

/* 36.6 卡片：圆角 16 → 18，静息影更深一档，hover 只抬 4px 并换成品牌发丝线 */
.card.card,
.hv-card.hv-card,
.pf-mini.pf-mini,
.dl-ch-card.dl-ch-card,
.supcard.supcard,
.docs-idx-card.docs-idx-card,
.qp-fam-card.qp-fam-card,
.rl-card.rl-card,
.st-card.st-card {
  border-radius: 18px;
  border: 1px solid var(--qf-border);
  background: var(--qf-card);
  box-shadow: var(--qf-v7-card-shadow);
}
.card.card:hover,
.hv-card.hv-card:hover,
.pf-mini.pf-mini:hover,
.dl-ch-card.dl-ch-card:hover,
.docs-idx-card.docs-idx-card:hover,
.qp-fam-card.qp-fam-card:hover,
.rl-card.rl-card:hover,
.st-card.st-card:hover,
.supcard.supcard:hover {
  transform: translateY(-4px);
  border-color: var(--qf-v7-hairline);
  box-shadow: var(--qf-v7-card-shadow-hover);
}

/* 36.7 主按钮：品牌实底 + 一层品牌投影；暗色下字色转深（--qf-on-brand 在暗色是墨蓝） */
.btn.btn-primary.btn-primary {
  box-shadow: var(--qf-v7-btn-shadow);
}
.btn.btn-primary.btn-primary:hover {
  box-shadow: var(--qf-v7-btn-shadow-hover);
}
[data-theme="dark"] .btn.btn-primary.btn-primary { color: var(--qf-on-brand); }
[data-theme="dark"] .btn.btn-primary.btn-primary:hover { color: var(--qf-on-brand); }

/*
 * 36.8 页脚：整块换成墨色带（与官网首屏同一套深墨）。
 * 做法是把 footer.css 在 .footer 上定义的 --f-* 调色板整体改写成墨色系 ——
 * 页脚内部所有规则都读这组变量，所以一次改写即全站一致，不需要逐条覆盖子元素。
 * 亮暗两套取同一批值：深色块本身就是主题，深色站里再翻一次会变成「深底压深底」。
 */
.footer.footer {
  --f-brand: var(--qf-v7-on-ink-brand);
  --f-brand-deep: var(--qf-v7-on-ink);
  --f-brand-soft: var(--qf-v7-ink-glass);
  --f-bg: var(--qf-v7-ink);
  --f-card: var(--qf-v7-ink-glass);
  --f-line: var(--qf-v7-ink-hair);
  --f-ink: var(--qf-v7-on-ink);
  --f-ink-2: var(--qf-v7-on-ink-2);
  --f-muted: var(--qf-v7-on-ink-muted);
  background: var(--qf-v7-ink-grad);
  border-top-color: var(--qf-v7-ink-hair);
  color: var(--qf-v7-on-ink-muted);
}
.footer.footer::before {
  background: var(--qf-v7-divider);
  opacity: 1;
  height: 1px;
}
/* 页脚里的社交/二维码按钮原先是白底，墨底上会浮成一块贴纸 */
.footer.footer .social-btn,
.footer.footer .qf-qr-card {
  background: var(--qf-v7-ink-glass);
  border-color: var(--qf-v7-ink-glass-line);
}.footer.footer .social-btn:hover {
  background: var(--qf-v7-ink-glass-line);
  border-color: var(--qf-v7-on-ink-2);
}
/*
 * 栏目标题要单独覆盖：§34 的 .footer-col.footer-col .footer-col-t 直接把
 * color 写成了 --qf-text-muted（#5A6478），它不走 --f-* 调色板，
 * 所以 36.8 改写变量时它不会跟着翻——墨底上实测 3.14:1，12px 根本读不出来。
 * 这里用 (0,4,0) 压过 §34 的 (0,3,0) 与 footer.css 的 [data-theme="dark"] 覆盖。
 */
.footer.footer .footer-col .footer-col-t {
  color: var(--qf-v7-on-ink-muted);
}

/*
 * 36.9 收口 CTA：墨色面板（V7 的「墨色基座」）。
 * 全站每一页的最后一块内容区都是 .qf-cta，它的下面是墨色页脚（36.8）。
 * 旧版是白卡 + 浅影，与页脚之间是硬切；改成与首屏同一套墨色后，
 * 页尾变成「CTA → 页脚」一整块深色基座，滚动到底不会再有断层。
 * 只改容器与四类子元素（标题 / 正文 / 脚注 / 次按钮），不动按钮主色。
 */
html[data-theme] .qf-cta.qf-cta {
  background: var(--qf-v7-ink-grad);
  border-color: var(--qf-v7-ink-hair);
  box-shadow: var(--qf-v7-ink-window-shadow);
  color: var(--qf-v7-on-ink-2);
}
html[data-theme] .qf-cta.qf-cta h2 { color: var(--qf-v7-on-ink); }
html[data-theme] .qf-cta.qf-cta p { color: var(--qf-v7-on-ink-2); }
html[data-theme] .qf-cta.qf-cta .qf-cta-note {
  color: var(--qf-v7-on-ink-muted);
  border-top-color: var(--qf-v7-ink-hair);
}
html[data-theme] .qf-cta.qf-cta .qf-cta-note a {
  color: var(--qf-v7-on-ink-brand);
  border-bottom-color: var(--qf-v7-ink-glass-line);
}
html[data-theme] .qf-cta.qf-cta .btn.btn-ghost {
  background: var(--qf-v7-ink-glass);
  border-color: var(--qf-v7-ink-glass-line);
  color: var(--qf-v7-on-ink);
}
html[data-theme] .qf-cta.qf-cta .btn.btn-ghost:hover {
  background: var(--qf-v7-ink-glass-line);
  border-color: var(--qf-v7-on-ink-2);
  color: var(--qf-v7-on-ink);
}

/*
 * 36.10 语义兜底：[hidden] 必须真的不可见。
 * 各站有一批组件自己写了 display（.rl-notice 是 flex、.btn 是 inline-flex、
 * .docs-updated 是 flex），作者样式会压过浏览器对 [hidden] 的 UA 规则 ——
 * JS 已经设了 el.hidden = true，元素照样占位。逐页实测到 9 处：
 * 发布页顶部多一条 1152×26 空框、插件列表到底后仍露出「加载更多」、
 * docs 每页正文顶部多一行 13px 空白。开关语义只有一个，守卫也只能有一个，
 * 因此写成 !important（html-semantics 类，非「懒」）。
 */
[hidden] { display: none !important; }
