/**
 * 跨域代理助手 · 产品落地页样式
 *
 * 设计约束：
 * - 零外部依赖、零 CDN、零远程字体：GitHub Pages 直出。禁用 JavaScript 的访客与 AI 爬虫
 *   都能看到完整内容；`assets/landing.js` 只做渐进增强（轮播控件、滚动淡入、导航高亮、回顶导轨），
 *   其效果全部包裹在 `html.js` 选择器下，脚本缺失时页面不留空洞。
 * - 主色取自 `assets/theme/tokens.css` 的 sky 主题（#409eff），与扩展内 UI 保持同一品牌识别。
 * - 遵循 prefers-color-scheme / prefers-reduced-motion / :focus-visible，保证可读性与可访问性。
 * - 属性顺序遵循 Stylelint 的 recess-order 规则。
 */

:root {
  --lp-primary: #409eff;
  --lp-primary-strong: #1a5fb4;
  --lp-primary-soft: #ecf5ff;
  --lp-primary-faint: #f4f9ff;
  --lp-accent: #12b886;
  --lp-accent-soft: #e6f9f1;
  --lp-warn: #d9730d;
  --lp-warn-soft: #fff4e0;
  --lp-danger: #e0455e;
  --lp-ink: #1f2d3d;
  --lp-ink-soft: #5b6b7c;
  --lp-ink-faint: #8a97a5;
  --lp-bg: #fff;
  --lp-bg-alt: #f6f9fe;
  --lp-surface: #fff;
  --lp-line: #e3ecf7;
  --lp-line-strong: #cfe0f5;
  --lp-code-bg: #0f2b52;
  --lp-code-ink: #d7e8ff;
  --lp-footer-bg: #0e1f35;
  --lp-footer-ink: #c9d9ec;
  --lp-footer-faint: #8ba2bd;
  --lp-radius: 14px;
  --lp-radius-lg: 20px;
  --lp-radius-sm: 8px;
  --lp-shadow: 0 10px 30px rgb(16 63 128 / 8%);
  --lp-shadow-lg: 0 24px 60px rgb(16 63 128 / 14%);
  --lp-max: 1160px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --lp-primary-strong: #8ac4ff;
    --lp-primary-soft: #16283d;
    --lp-primary-faint: #12203259;
    --lp-accent-soft: #10312a;
    --lp-warn-soft: #33230f;
    --lp-ink: #e8eef5;
    --lp-ink-soft: #a9b7c6;
    --lp-ink-faint: #7f8b99;
    --lp-bg: #0e1621;
    --lp-bg-alt: #121c29;
    --lp-surface: #16212f;
    --lp-line: #24384f;
    --lp-line-strong: #2f4a68;
    --lp-code-bg: #0a121c;
    --lp-code-ink: #cfe3ff;
    --lp-footer-bg: #0a1220;
    --lp-shadow: 0 10px 30px rgb(0 0 0 / 40%);
    --lp-shadow-lg: 0 24px 60px rgb(0 0 0 / 55%);
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family:
    'PingFang SC',
    'Hiragino Sans GB',
    'Microsoft YaHei',
    system-ui,
    -apple-system,
    'Segoe UI',
    Roboto,
    sans-serif;
  font-size: 16px;
  line-height: 1.7;
  color: var(--lp-ink);
  background: var(--lp-bg);
}

a {
  color: var(--lp-primary-strong);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

:focus-visible {
  outline: 3px solid var(--lp-primary);
  outline-offset: 2px;
}

img {
  max-width: 100%;
  height: auto;
}

svg {
  flex-shrink: 0;
}

h2 {
  margin: 0 0 10px;
  font-size: clamp(23px, 3.4vw, 32px);
  line-height: 1.28;
  letter-spacing: -0.4px;
}

h3 {
  margin: 26px 0 8px;
  font-size: 19px;
}

p {
  margin: 0 0 14px;
}

code,
kbd,
pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* ---------- 基础工具类 ---------- */

.wrap {
  width: 100%;
  max-width: var(--lp-max);
  padding: 0 20px;
  margin: 0 auto;
}

.skip-link {
  position: absolute;
  top: 8px;
  left: 12px;
  z-index: 20;
  padding: 8px 14px;
  color: #fff;
  background: var(--lp-primary);
  border-radius: var(--lp-radius-sm);

  /* 用 transform 移出视口：之前用 top: -40px 时链接自身高约 43px，顶部会露出几px蓝条。 */
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

.muted {
  color: var(--lp-ink-soft);
}

.kbd {
  display: inline-block;
  padding: 1px 7px;
  font-size: 13px;
  background: var(--lp-bg-alt);
  border: 1px solid var(--lp-line);
  border-bottom-width: 2px;
  border-radius: 5px;
}

.chip {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  font-size: 12.5px;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-radius: 999px;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 14px;
}

.btn {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  padding: 11px 22px;
  font-weight: 600;
  line-height: 1.3;
  border: 1px solid transparent;
  border-radius: 11px;
  transition:
    background 0.18s ease,
    border-color 0.18s ease,
    color 0.18s ease,
    transform 0.18s ease,
    box-shadow 0.18s ease;
}

.btn-primary {
  position: relative;

  /* 裁剪的是「动效增强」一节那道扫过的高光：伪元素位移出边界时不该露出边角。 */
  overflow: hidden;
  color: #fff;
  background: var(--lp-primary);
  box-shadow: 0 8px 22px rgb(64 158 255 / 28%);
}

.btn-primary:hover {
  color: #fff;
  text-decoration: none;
  background: #2c86e8;
  transform: translateY(-1px);
}

.btn-ghost {
  color: var(--lp-ink);
  background: var(--lp-surface);
  border-color: var(--lp-line-strong);
}

.btn-ghost:hover {
  color: var(--lp-primary-strong);
  text-decoration: none;
  border-color: var(--lp-primary);
  transform: translateY(-1px);
}

/* 按下时回落到原位：悬停是「可以点」，这条是「点到了」。
   放在两条 :hover 之后，靠源码顺序压过悬停的抬升。 */
.btn:active {
  transform: translateY(1px) scale(0.985);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* ---------- 顶部导航 ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--lp-bg) 88%, transparent);
  border-bottom: 1px solid var(--lp-line);
  backdrop-filter: saturate(160%) blur(8px);
}

/* 页面滚动进度：贴在 sticky 页头的下沿，因此页头多高它就在哪，无需按断点调。
   默认不显示，只有 `html.js` 在（即 landing.js 真的跑起来了）才出现——禁用 JS 时
   进度条永远停在 0，与其留一条骗人的细线，不如什么都不画。 */
.scroll-progress {
  display: none;
}

html.js .scroll-progress {
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  display: block;
  height: 3px;
}

.scroll-progress i {
  display: block;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, var(--lp-primary), var(--lp-accent));
  transform: scaleX(0);
  transform-origin: 0 50%;
}

.site-header .wrap {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  min-height: 62px;
}

.brand {
  display: flex;
  gap: 10px;
  align-items: center;
  font-weight: 700;
  white-space: nowrap;
}

.brand img {
  width: 28px;
  height: 28px;
  border-radius: 6px;
}

.site-nav {
  display: flex;
  flex: 1;
  gap: 18px;
  align-items: center;
  min-width: 0;
  font-size: 15px;
}

/* `text-decoration: none` 是必需的：全局 `a:hover` 会加下划线，而下面那条自绘的
   `.site-nav > a::after` 下划条也在同一行底部，两者叠加就是「双线条」。 */
.site-nav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  color: var(--lp-ink-soft);
  white-space: nowrap;
  text-decoration: none;
  transition: color 0.18s ease;
}

.site-nav a:hover {
  color: var(--lp-ink);
}

/* 对比页与隐私页没有独立的 .nav-actions，跨页链接仍挤在 .site-nav 里，
   此时它是头部的最后一个子元素 —— 靠右排才和改版前一致。只在宽屏生效：
   横向滚动的条一旦右对齐，最左边那几项会被推到滚动范围之外，点不到。 */
@media (width > 900px) {
  .site-nav:last-child {
    justify-content: flex-end;
  }
}

html.js .site-nav > a[aria-current] {
  color: var(--lp-primary-strong);
}

/* 一条下划条承担两件事，但用两种强度区分：悬停时长出来的是半透明主色，只说
   「这一项可点」；当前区块（`landing.js` 打的 `aria-current`）才是实色主色并常驻。
   两者叠在同一行时读者看到的是一根线，而不是两根看起来等价的线。 */
.site-nav > a::after {
  position: absolute;
  bottom: -6px;
  left: 0;
  width: 100%;
  height: 2px;
  content: '';
  background: var(--lp-primary);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition:
    transform 0.24s ease,
    opacity 0.18s ease;
}

.site-nav > a:hover::after,
.site-nav > a:focus-visible::after {
  opacity: 0.45;
  transform: scaleX(1);
}

html.js .site-nav > a[aria-current]::after {
  opacity: 1;
  transform: scaleX(1);
}

.site-nav > a:focus-visible {
  outline-offset: 4px;
  border-radius: 6px;
}

/* 页内锚点之外的三个入口：另一个页面、站外仓库、语言切换。
   与区块导航分开，窄屏时它不跟着锚点一起横向滚走。 */
.nav-actions {
  display: flex;
  flex: none;
  gap: 8px;
  align-items: center;
  padding-left: 16px;
  font-size: 15px;
  border-left: 1px solid var(--lp-line);
}

/* 三个跨页入口做成一组等高胶囊：它们不是同一层内容（一个换页、一个出站、一个换语言），
   但都属于「页内锚点之外的出口」，用同一种形状归为一组，再靠描边把语言切换分出来。
   这里必须显式取消全局 `a:hover` 的下划线，否则浅底之上还压一条线。 */
.nav-actions a {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  min-height: 34px;
  padding: 0 12px;
  color: var(--lp-ink-soft);
  white-space: nowrap;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 999px;
  transition:
    color 0.18s ease,
    background-color 0.18s ease,
    border-color 0.18s ease;
}

.nav-actions a:hover {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-color: var(--lp-line-strong);
}

.nav-actions a:focus-visible {
  outline-offset: 3px;
}

.nav-actions svg {
  width: 16px;
  height: 16px;
}

.lang-switch {
  font-weight: 600;
  border-color: var(--lp-line-strong);
}

/* 小屏汉堡菜单：`<details>` 实现，禁用 JS 也能展开——窄屏下它接替
   .site-nav 的锚点条，「完整对比」一并收进下拉里。桌面宽度整体隐藏。
   下面几处 reset 是必需的：FAQ 的 `details` / `summary` 元素选择器会给每个
   `<details>` 套上卡片底色与自绘加减号，页头里因此会多出一块带「+」的白板。 */
.nav-menu {
  position: static;
  display: none;
  padding: 0;
  font-size: 15px;
  background: none;
  border: 0;
  border-radius: 0;
}

.nav-menu summary {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  color: var(--lp-ink);
  cursor: pointer;
  list-style: none;
  border-radius: 10px;
}

.nav-menu summary::before,
.nav-menu summary::after {
  display: none;
}

.nav-menu summary::-webkit-details-marker {
  display: none;
}

.nav-menu summary:hover {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
}

.nav-menu[open] summary {
  color: var(--lp-primary-strong);
}

.nav-menu-panel {
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  padding: 6px 0 10px;
  background: var(--lp-bg);
  border-bottom: 1px solid var(--lp-line);
  box-shadow: var(--lp-shadow-lg);
}

/* 收起时必须显式隐藏：面板是绝对定位、包含块在 `<details>` 之外（.site-header），
   因此逃过了浏览器对未展开内容的隐藏机制，会在页头上方留一块空白板。 */
.nav-menu:not([open]) .nav-menu-panel {
  display: none;
}

.nav-menu-panel a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 22px;
  color: var(--lp-ink-soft);
}

.nav-menu-panel a:hover {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-faint);
}

/* 当前区块。面板是纵向列表，桌面横条那根 `::after` 下划条在这里读不出来，
   于是换一组读得出的信号：左侧 3px 主色竖条 + 软底 + 主色文字 + 加粗。
   四个信号里只有底色是颜色依赖，灰度打印与色觉障碍下竖条和字重仍在。
   前缀 `html.js` 是必需的：选中态由 `landing.js` 打 `aria-current`，
   禁用 JavaScript 时没有任何链接会被标记，写在这里也就不会画出假的高亮。 */
html.js .nav-menu-panel a[aria-current] {
  font-weight: 600;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  box-shadow: inset 3px 0 0 var(--lp-primary);
}

/* 面板里的跨页出口：与页内锚点用一条分隔线分开，行高与其余条目一致。 */
.nav-menu-exits {
  margin-top: 6px;
  border-top: 1px solid var(--lp-line);
}

/* 触屏上没有 hover 反馈，把三个集群的链接都撑到 44px 见方的可点区域。 */
@media (pointer: coarse) {
  .site-nav a,
  .nav-actions a {
    min-height: 44px;
  }

  .lang-switch {
    min-height: 44px;
    padding: 0 16px;
  }

  .nav-menu summary {
    width: 44px;
    height: 44px;
  }

  .gallery-btn {
    width: 44px;
    height: 44px;
  }

  .gallery-dots button {
    width: 12px;
    height: 12px;
  }

  .gallery-dots button[aria-current='true'] {
    width: 28px;
  }
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  padding: 62px 0 54px;
  overflow: hidden;
  background:
    radial-gradient(circle at 12% 0%, rgb(64 158 255 / 18%), transparent 52%),
    radial-gradient(circle at 88% 22%, rgb(18 184 134 / 12%), transparent 48%),
    linear-gradient(180deg, var(--lp-primary-faint), var(--lp-bg));
}

.hero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: 46px;
  align-items: center;
  justify-content: space-between;
}

.eyebrow {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  padding: 6px 14px;
  margin-bottom: 18px;
  font-size: 13px;
  font-weight: 600;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-radius: 999px;
}

.eyebrow .dot {
  width: 7px;
  height: 7px;
  background: var(--lp-primary);
  border-radius: 50%;
  animation: lp-pulse 1.8s ease-in-out infinite;
}

@keyframes lp-pulse {
  50% {
    opacity: 0.45;
    transform: scale(1.35);
  }
}

.hero h1 {
  margin: 0 0 16px;
  font-size: clamp(30px, 4.6vw, 46px);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: -0.9px;
}

.hero h1 .accent {
  color: var(--lp-primary);
}

.hero .lede {
  max-width: 620px;
  margin: 0 0 24px;
  font-size: clamp(16px, 1.5vw, 18.5px);
  color: var(--lp-ink-soft);
}

.hero .cta-row {
  margin-bottom: 20px;
}

.hero-note {
  font-size: 13.5px;
  color: var(--lp-ink-faint);
}

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 22px;
  font-size: 13px;
  color: var(--lp-ink-soft);
}

.badges span {
  padding: 3px 10px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: 999px;
}

/* Hero 右侧：双通道流程示意（内联 SVG，文字在 HTML 侧同步给出，便于抓取） */

.hero-visual {
  display: grid;
  gap: 12px;
  animation: lp-fade 0.7s ease 200ms both;
}

.hero-visual figure {
  margin: 0;
}

.hero-visual figure svg {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 18px 40px rgb(16 63 128 / 16%));
}

.hero-visual figcaption {
  margin-top: 10px;
  font-size: 13px;
  color: var(--lp-ink-faint);
  text-align: center;
}

.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
}

.stat {
  padding: 12px 14px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
}

.stat b {
  display: block;
  font-size: 20px;
  line-height: 1.3;
  color: var(--lp-primary-strong);
}

.stat span {
  font-size: 12.5px;
  color: var(--lp-ink-faint);
}

/* ---------- Hero 双通道流程示意 ----------
 * 用普通 HTML 文本而不是 SVG <text>：文字不会溢出裁切，
 * 可被搜索引擎与 AI 爬虫直接抽取，也自动跟随字号与主题。 */

.flow {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-lg);
  box-shadow: var(--lp-shadow-lg);
}

.flow-lanes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 8px;
}

.flow-node {
  padding: 11px 14px;
  font-size: 14px;
  font-weight: 700;
  color: var(--lp-ink);
  text-align: center;
  background: var(--lp-bg-alt);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
}

.flow-node small {
  display: block;
  margin-top: 2px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--lp-ink-soft);
}

.flow-node--fast {
  background: var(--lp-accent-soft);
  border-color: color-mix(in srgb, var(--lp-accent) 45%, var(--lp-line));
}

.flow-node--sw {
  background: var(--lp-warn-soft);
  border-color: color-mix(in srgb, var(--lp-warn) 45%, var(--lp-line));
}

.flow-node--target {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-color: color-mix(in srgb, var(--lp-primary) 45%, var(--lp-line));
}

.flow-arrow {
  font-size: 14px;
  line-height: 1;
  color: var(--lp-ink-faint);
  text-align: center;
}

.flow-node--page {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-faint);
  border-color: var(--lp-line-strong);
}

.flow-figure {
  margin: 0;
}

/* 详情页的双通道泳道：左网络层、右后台，窄屏自动叠成一列。 */

.flow-lane {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.flow-lane-tag {
  font-size: 12px;
  font-weight: 700;
  color: var(--lp-ink-faint);
  text-align: center;
  letter-spacing: 0.02em;
}

.flow-caption {
  margin-top: 4px;
  font-size: 13.5px;
  color: var(--lp-ink-soft);
}

/* ---------- 通用区块 ---------- */

section {
  padding: 56px 0;
  border-top: 1px solid var(--lp-line);
}

section[aria-labelledby] {
  scroll-margin-top: 72px;
}

.section-head {
  margin-bottom: 30px;
}

.section-head.center {
  text-align: center;
}

/* 区块标题里的语义图标：与 .feature-icon 同一套描边语言与配色，只是收小一号，
   让标题行有锚点又不抢正文重量。纯样式 + 内联 SVG，禁用 JS 时照常显示。 */
.section-head h2 {
  display: flex;
  gap: 12px;
  align-items: center;
}

.section-icon {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  color: var(--lp-primary);
  background: var(--lp-primary-soft);
  border-radius: 11px;
}

.section-icon svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentcolor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.section-head.center h2 {
  justify-content: center;
}

/* 文档标题栏：供没有 hero 的纯文档页（privacy.html）承载唯一的 <h1>。
   只覆写 padding-top，保留 .wrap 的左右留白。 */
.page-head {
  padding-top: 44px;
}

.page-head h1 {
  margin: 0;
  font-size: clamp(25px, 3.8vw, 36px);
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.6px;
}

.section-lede {
  max-width: 860px;
  margin: 0 0 26px;
  color: var(--lp-ink-soft);
}

.section-head.center .section-lede {
  margin-right: auto;
  margin-left: auto;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  gap: 18px;
}

.card {
  padding: 20px 22px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  box-shadow: var(--lp-shadow);
}

.card h3 {
  margin: 0 0 6px;
  font-size: 17px;
}

.card p {
  margin: 0;
  font-size: 15px;
  color: var(--lp-ink-soft);
}

/* ---------- 特性卡 ---------- */

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
}

.feature-card {
  padding: 24px 26px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-lg);
  box-shadow: var(--lp-shadow);
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease,
    transform 0.2s ease;
}

.feature-card:hover {
  border-color: var(--lp-line-strong);
  box-shadow: var(--lp-shadow-lg);
  transform: translateY(-3px);
}

/* 卡片抬起时图标跟着歪一点：让「这张卡被指向了」这件事在图标上也有回应，
   时长与缓动沿用卡片自身的 transform，两处不会走不同步。 */
.feature-card:hover .feature-icon {
  transform: rotate(-6deg) scale(1.06);
}

.feature-card-lg {
  grid-column: 1 / -1;
  padding: 28px 30px;
  background: linear-gradient(165deg, var(--lp-surface) 0%, var(--lp-primary-faint) 100%);
  border-color: color-mix(in srgb, var(--lp-primary) 26%, var(--lp-line));
}

@media (width >= 900px) {
  .feature-grid {
    grid-template-columns: repeat(6, 1fr);
  }

  .feature-card {
    grid-column: span 2;
  }

  .feature-card-lg {
    grid-column: span 3;
  }
}

.feature-card h3 {
  margin: 14px 0 8px;
  font-size: 18px;
}

.feature-card p {
  margin: 0;
  font-size: 14.8px;
  color: var(--lp-ink-soft);
}

.feature-icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  color: var(--lp-primary);
  background: var(--lp-primary-soft);
  border-radius: 13px;
  transition:
    transform 0.2s ease,
    background 0.2s ease;
}

.feature-icon--green {
  color: var(--lp-accent);
  background: var(--lp-accent-soft);
}

.feature-icon--orange {
  color: var(--lp-warn);
  background: var(--lp-warn-soft);
}

.feature-icon--purple {
  color: #8b5cf6;
  background: rgb(139 92 246 / 12%);
}

.feature-icon--cyan {
  color: #0aa2c0;
  background: rgb(10 162 192 / 12%);
}

.feature-icon--pink {
  color: var(--lp-danger);
  background: rgb(224 69 94 / 12%);
}

/* 能力标记（H/B/R/M/D/X/WS）与规则列一致，方便对照截图 */

.cap {
  display: inline-flex;
  justify-content: center;
  min-width: 22px;
  padding: 1px 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-radius: 5px;
}

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

.table-scroll {
  overflow-x: auto;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
}

table {
  width: 100%;
  font-size: 15px;
  border-collapse: collapse;
}

caption {
  padding: 12px 16px;
  font-size: 13px;
  color: var(--lp-ink-faint);
  text-align: left;
}

th,
td {
  padding: 12px 16px;
  vertical-align: top;
  text-align: left;
  border-bottom: 1px solid var(--lp-line);
}

th {
  font-weight: 600;
  background: var(--lp-bg-alt);
}

tbody tr:last-child td {
  border-bottom: 0;
}

.compare td:nth-child(n + 2),
.compare th:nth-child(n + 2) {
  text-align: center;
}

.compare th:first-child {
  min-width: 168px;
}

.compare .col-us {
  font-weight: 700;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
}

.compare tbody tr:hover td {
  background: var(--lp-bg-alt);
}

.compare tbody tr:hover td.col-us {
  background: color-mix(in srgb, var(--lp-primary) 14%, var(--lp-surface));
}

.mark-yes {
  font-weight: 700;
  color: var(--lp-accent);
}

.mark-no {
  color: var(--lp-ink-faint);
}

.mark-part {
  font-weight: 600;
  color: var(--lp-warn);
}

/* ---------- 截图轮播（CSS scroll-snap 为主，JS 只加控件） ---------- */

.gallery {
  position: relative;
}

/* 自动轮播进度条：landing.js 判定「可自动轮播」（非减弱动效、多张截图）时挂
 * .gallery-autoable 才会占位，翻页时挂 .gallery-auto 驱动填充动画；
 * 悬停/聚焦用 animation-play-state 暂停，与翻页共用同一条时间线。 */
.gallery-progress {
  display: none;
}

html.js .gallery-autoable .gallery-progress {
  display: block;
  height: 3px;
  margin-bottom: 14px;
  overflow: hidden;
  background: var(--lp-line);
  border-radius: 999px;
}

.gallery-progress i {
  display: block;
  width: 0;
  height: 100%;
  background: var(--lp-primary);
  border-radius: inherit;
}

.gallery.gallery-auto .gallery-progress i {
  animation: lp-gallery-auto 5.2s linear forwards;
}

.gallery.gallery-auto.is-paused .gallery-progress i {
  animation-play-state: paused;
}

@keyframes lp-gallery-auto {
  from {
    width: 0;
  }

  to {
    width: 100%;
  }
}

.gallery-track {
  display: flex;
  gap: 16px;
  padding-bottom: 8px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 4px;
  scrollbar-color: var(--lp-line-strong) transparent;
}

.gallery-track::-webkit-scrollbar {
  height: 8px;
}

.gallery-track::-webkit-scrollbar-thumb {
  background: var(--lp-line-strong);
  border-radius: 999px;
}

.slide {
  flex: 0 0 min(100%, 720px);
  scroll-snap-align: center;
}

html.js .slide {
  flex-basis: min(100%, 760px);
}

.slide figure {
  padding: 14px;
  margin: 0;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-lg);
  box-shadow: var(--lp-shadow-lg);
}

.slide img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: contain;
  border-radius: var(--lp-radius-sm);
}

.slide figcaption {
  padding: 12px 4px 2px;
}

.slide figcaption b {
  display: block;
  margin-bottom: 2px;
  font-size: 15.5px;
}

.slide figcaption span {
  font-size: 14px;
  color: var(--lp-ink-soft);
}

.gallery-bar {
  display: none;
  gap: 10px;
  align-items: center;
  justify-content: center;
  margin-top: 16px;
}

html.js .gallery-bar {
  display: flex;
}

.gallery-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  color: var(--lp-ink-soft);
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: 50%;
  transition:
    color 0.18s ease,
    border-color 0.18s ease,
    background 0.18s ease,
    transform 0.18s ease;
}

.gallery-btn:hover {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-faint);
  border-color: var(--lp-primary);
  transform: scale(1.08);
}

.gallery-btn:active {
  transform: scale(0.94);
}

.gallery-dots {
  display: flex;
  gap: 7px;
  align-items: center;
}

.gallery-dots button {
  width: 8px;
  height: 8px;
  padding: 0;
  cursor: pointer;
  background: var(--lp-line-strong);
  border: 0;
  border-radius: 999px;
  transition:
    width 0.2s ease,
    background 0.2s ease;
}

.gallery-dots button[aria-current='true'] {
  width: 24px;
  background: var(--lp-primary);
}

/* ---------- 步骤卡 ---------- */

.step-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: 18px;
}

.step-card {
  position: relative;
  padding: 24px 24px 22px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-lg);
  box-shadow: var(--lp-shadow);
}

.step-num {
  margin-bottom: 8px;
  font-size: 34px;
  font-weight: 800;
  line-height: 1;
  color: var(--lp-primary);
  letter-spacing: -1px;
}

.step-card h3 {
  margin: 0 0 8px;
  font-size: 17.5px;
}

.step-card p {
  margin: 0;
  font-size: 14.8px;
  color: var(--lp-ink-soft);
}

.step-card pre {
  margin-top: 12px;
}

/* ---------- 代码与流程 ---------- */

pre {
  padding: 18px 20px;
  margin: 0;
  overflow-x: auto;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--lp-code-ink);
  background: var(--lp-code-bg);
  border-radius: var(--lp-radius);
}

pre + pre,
pre + p,
p + pre {
  margin-top: 14px;
}

code {
  padding: 1px 6px;
  font-size: 0.92em;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-radius: 5px;
}

pre code {
  padding: 0;
  color: inherit;
  background: none;
}

ol.steps,
ul.ticks {
  padding-left: 0;
  margin: 0;
  list-style: none;
}

ol.steps {
  padding-left: 22px;
  list-style: decimal;
}

ol.steps li {
  margin-bottom: 10px;
}

ul.ticks li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 9px;
  font-size: 15px;
  color: var(--lp-ink-soft);
}

ul.ticks li::before {
  position: absolute;
  top: 0.55em;
  left: 2px;
  width: 8px;
  height: 8px;
  content: '';
  background: var(--lp-accent);
  border-radius: 50%;
}

/* ---------- 提示条 ---------- */

.callout {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 15px 18px;
  margin: 20px 0;
  font-size: 14.6px;
  color: var(--lp-ink-soft);
  background: var(--lp-primary-faint);
  border: 1px solid var(--lp-line);
  border-left: 3px solid var(--lp-primary);
  border-radius: var(--lp-radius-sm);
}

.callout p {
  margin: 0;
}

.callout--warn {
  background: var(--lp-warn-soft);
  border-left-color: var(--lp-warn);
}

.callout--key {
  background: var(--lp-accent-soft);
  border-left-color: var(--lp-accent);
}

/* ---------- FAQ ---------- */

/* 单列手风琴：三列网格时同一行卡片的高度由最长的那条答案决定，展开一条会把
   邻居一起撑高（`align-items: start` 只能止住拉伸，止不住视觉上的空洞），
   而 FAQ 的读法是「从上往下扫问题、按需展开一条」——一列才是它的自然形状。
   max-width 让答案保持可读行长，左边缘与 .section-head 对齐。 */
.faq-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  max-width: 880px;
}

.faq-category {
  display: flex;
  grid-column: 1 / -1;
  gap: 10px;
  align-items: center;
  margin-top: 10px;
  font-size: 15px;
  font-weight: 700;
}

.faq-category:first-child {
  margin-top: 0;
}

.faq-category .feature-icon {
  width: 32px;
  height: 32px;
  border-radius: 9px;
}

.faq-category .feature-icon svg {
  width: 17px;
  height: 17px;
}

details {
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius-sm);
  transition:
    border-color 0.18s ease,
    box-shadow 0.18s ease;
}

details[open] {
  border-color: var(--lp-line-strong);
  box-shadow: var(--lp-shadow);
}

/* 折叠图标：浏览器默认的三角 marker 在各引擎下尺寸与位置都不一致，展开后也
   没有任何状态反馈。这里改成一枚纯 CSS 自绘的加减号 —— ::before 画横杠、
   ::after 画竖杠，展开时竖杠旋转 90° 并淡出，图标读作「−」。summary 内部只有
   文本，中英两页的 FAQ 文本与条目一致性守卫不受影响；横向铺满的一行都是点击区。
   内边距由 summary 承担而不是 details：整行（含右侧加减号那一列）都要能点。 */
summary {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 46px;
  padding: 12px 46px 12px 18px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  border-radius: var(--lp-radius-sm);
  transition: background-color 0.18s ease;
}

summary::-webkit-details-marker {
  display: none;
}

summary::before,
summary::after {
  position: absolute;
  top: 50%;
  right: 9px;
  content: '';
  background: var(--lp-primary-strong);
  border-radius: 1px;
  transition:
    transform 180ms ease,
    opacity 180ms ease,
    background-color 180ms ease;
}

summary::before {
  width: 13px;
  height: 2px;
  margin-top: -1px;
}

summary::after {
  width: 2px;
  height: 13px;
  margin-top: -6.5px;
  margin-right: 5.5px;
}

summary:hover {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-faint);
}

summary:hover::before,
summary:hover::after,
details[open] > summary::before,
details[open] > summary::after {
  background: var(--lp-primary);
}

details[open] > summary::after {
  opacity: 0;
  transform: rotate(90deg);
}

summary:focus-visible {
  outline-offset: 4px;
  border-radius: var(--lp-radius-sm);
}

details p {
  padding: 0 18px;
  margin: 0 0 14px;
  color: var(--lp-ink-soft);
}

details p + p {
  margin-top: 8px;
}

/* ---------- 作者的其他插件 ---------- */

.tools-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

@media (width >= 720px) {
  .tools-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* 整卡可点：标题链接用 ::after 铺满卡片，卡内的「源码 / 商店」链接靠自己的
   position: relative + z-index 浮回可点层。这样读者点卡片的任何位置都成立，
   而不必命中那行 13.5px 的小字。 */
.tool-card {
  position: relative;
  padding: 22px;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: var(--lp-radius);
  transition:
    border-color 0.18s ease,
    box-shadow 0.18s ease,
    transform 0.18s ease;
}

.tool-card:hover {
  border-color: var(--lp-primary);
  box-shadow: var(--lp-shadow);
  transform: translateY(-2px);
}

.tool-card h3 {
  margin: 0;
  font-size: 17px;
}

.tool-card h3 a::after {
  position: absolute;
  inset: 0;
  content: '';
  border-radius: var(--lp-radius);
}

.tool-card h3 a:focus-visible {
  outline-offset: 5px;
}

.tool-mark {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-bottom: 12px;
  font-size: 14px;
  font-weight: 700;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-radius: 11px;
}

.tool-card--green .tool-mark {
  color: var(--lp-accent);
  background: var(--lp-accent-soft);
}

/* 这组里主推的那张：边框提到主色一档，右上角钉一枚角标。
   角标写成 <span> 而不是 ::after 的生成内容——「作者主推」是要被读者搜到、
   被爬虫读到的信息，塞进样式里就只剩视觉上一层皮。 */
.tool-card--featured {
  border-color: color-mix(in srgb, var(--lp-primary) 40%, var(--lp-line));
}

.tool-star {
  position: absolute;
  top: 16px;
  right: 16px;
  display: inline-flex;
  gap: 4px;
  align-items: center;
  padding: 3px 9px;
  font-size: 12px;
  font-weight: 700;
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
  border-radius: 999px;
}

.tool-star svg {
  width: 12px;
  height: 12px;
  fill: currentcolor;
}

.tool-product {
  margin: 2px 0 0;
  font-size: 13px;
  color: var(--lp-ink-faint);
}

.tool-desc {
  margin: 8px 0 0;
  font-size: 14.5px;
  color: var(--lp-ink-soft);
}

.tool-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-top: 12px;
  font-size: 13.5px;
}

.tool-links a {
  position: relative;
  z-index: 1;
}

/* ---------- 微信交流群（收在页脚里的紧凑卡片） ---------- */

/* 曾经是 FAQ 之后独占一屏的大区块：236px 二维码 + 三段落，把落地页的收尾拉得
   比正文还长。交流群是「读完之后的下一步」而不是一个内容区块，因此压成页脚里
   一张横向小卡——二维码缩到 108px（实测在 1x 屏幕上仍可扫），文案收成两行。 */
.footer-wechat {
  display: flex;
  flex: 0 1 auto;
  gap: 16px;
  align-items: center;
  padding: 16px 20px;
  background: rgb(255 255 255 / 4%);
  border: 1px solid rgb(255 255 255 / 9%);
  border-radius: var(--lp-radius);
}

/* 二维码留在白底上：反色后多数扫码器识别不到，深色模式下也刻意不跟随。 */
.footer-wechat-qr {
  width: 108px;
  height: 108px;
  padding: 5px;
  background: #fff;
  border-radius: var(--lp-radius-sm);
}

.footer-wechat-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
}

.footer-wechat-title {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: #fff;
}

.footer-wechat-desc {
  max-width: 320px;
  margin: 0;
  font-size: 13px;
  line-height: 1.65;
  color: var(--lp-footer-faint);
}

.footer-wechat-id {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 0;
  font-size: 13.5px;
  color: var(--lp-footer-ink);
}

/* 只放大字号，颜色交给全局 `code`：那套「主色文字 + 浅底」本来就自足，
   在深色页脚上是一块可读的 chip。覆成白字就成了白压浅蓝，等于看不见。 */
.footer-wechat-id code {
  font-size: 14px;
}

.footer-wechat-fallback {
  max-width: 360px;
  margin: 0;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--lp-footer-faint);
}

.footer-wechat-fallback a {
  text-decoration: underline;
  text-decoration-color: rgb(255 255 255 / 25%);
  text-underline-offset: 2px;
}

@media (width <= 560px) {
  .footer-wechat {
    flex-direction: column;
    align-items: center;
    width: 100%;
    text-align: center;
  }

  .footer-wechat-body {
    align-items: center;
  }

  .footer-wechat-id {
    justify-content: center;
  }
}

/* 只在 `html.js` 下出现：无 JS 时按钮不存在，号码本身是可选中的文本。
   它只存在于深色页脚里，因此自绘一枚暗色胶囊，不再借用浅色主题的 .btn/.btn-ghost。 */
.copy-btn {
  display: none;
  min-height: 30px;
  padding: 4px 14px;
  font-family: inherit;
  font-size: 13px;
  color: var(--lp-footer-ink);
  cursor: pointer;
  background: transparent;
  border: 1px solid rgb(255 255 255 / 18%);
  border-radius: 999px;
  transition:
    color 0.18s ease,
    border-color 0.18s ease;
}

html.js .copy-btn {
  display: inline-flex;
  align-items: center;
}

.copy-btn:hover {
  color: #fff;
  border-color: rgb(255 255 255 / 45%);
}

.copy-status {
  font-size: 13.5px;
  color: var(--lp-accent);
}

.copy-status:empty {
  display: none;
}

.copy-status.is-failed {
  color: var(--lp-danger);
}

/* ---------- 页脚 ---------- */

.site-footer {
  padding: 38px 0 44px;
  font-size: 14px;
  color: var(--lp-footer-ink);
  background: var(--lp-footer-bg);
}

.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 32px;
  align-items: flex-start;
  justify-content: space-between;
}

.site-footer a {
  color: var(--lp-footer-ink);
}

.site-footer a:hover {
  color: #fff;
}

.footer-main {
  flex: 1 1 420px;
  min-width: 0;
}

.footer-main .brand {
  margin-bottom: 10px;
  color: #fff;
}

.footer-disclaimer {
  max-width: 640px;
  color: var(--lp-footer-faint);
}

.footer-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin-top: 14px;
  font-size: 13px;
  color: var(--lp-footer-faint);
}

.site-footer nav {
  display: flex;
  flex: 1 1 100%;
  flex-wrap: wrap;
  gap: 10px 18px;
  align-items: center;
  padding-top: 18px;
  border-top: 1px solid rgb(255 255 255 / 8%);
}

/* ---------- 回顶 / 到底导轨（仅 JS 可用时出现） ---------- */

.scroll-rail {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 9;
  display: none;
  flex-direction: column;
  overflow: hidden;
  background: var(--lp-surface);
  border: 1px solid var(--lp-line);
  border-radius: 999px;
  box-shadow: var(--lp-shadow);
}

html.js .scroll-rail {
  display: flex;
}

.scroll-rail button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  color: var(--lp-ink-soft);
  cursor: pointer;
  background: transparent;
  border: 0;
  transition:
    background 0.18s ease,
    color 0.18s ease;
}

.scroll-rail button:hover {
  color: var(--lp-primary-strong);
  background: var(--lp-primary-soft);
}

.scroll-rail .rail-divider {
  height: 1px;
  margin: 0 10px;
  background: var(--lp-line);
}

html.js .scroll-rail.at-top .rail-top,
html.js .scroll-rail.at-bottom .rail-bottom {
  display: none;
}

/* ---------- 滚动淡入与动效（纯装饰，全部在文末的 prefers-reduced-motion 里关掉） ---------- */

/* 同组卡片依次进场：`--lp-rank` 由 landing.js 按「同一个父元素里的第几个 .reveal」写入，
   延迟只加在 .reveal 这一层，因此一组是一组，不是十几件各自触发的事。
   整段都在 `html.js` 下：禁用 JS 时内容直接可见，不做任何淡入。 */
html.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.55s cubic-bezier(0.16, 1, 0.3, 1) calc(var(--lp-rank, 0) * 70ms),
    transform 0.55s cubic-bezier(0.16, 1, 0.3, 1) calc(var(--lp-rank, 0) * 70ms);
}

html.js .reveal.in {
  opacity: 1;
  transform: none;
}

@keyframes lp-rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

@keyframes lp-fade {
  from {
    opacity: 0;
  }
}

/* 首屏不等滚动就登场：`both` 让第一帧就停在起始关键帧，避免「先闪一下再位移」。
   右侧流程图用淡入——它靠虚线与节点对齐自己讲通道，位移进场反而显得在躲。 */
.hero-copy > * {
  animation: lp-rise 0.62s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.hero-copy > :nth-child(2) {
  animation-delay: 70ms;
}

.hero-copy > :nth-child(3) {
  animation-delay: 140ms;
}

.hero-copy > :nth-child(4) {
  animation-delay: 210ms;
}

.hero-copy > :nth-child(n + 5) {
  animation-delay: 280ms;
}

/* 汉堡面板从页头下沿滑出，和它「被页头打开」的空间关系一致。 */
.nav-menu[open] .nav-menu-panel {
  transform-origin: top;
  animation: lp-panel 0.2s ease both;
}

@keyframes lp-panel {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
}

/* 展开答案时内容淡入，配合卡片高度的变化说明「这段是新出现的」。
   写在 `details[open]` 上，因此收起再展开会重播一次。 */
details[open] > p {
  animation: lp-answer 0.32s ease both;
}

@keyframes lp-answer {
  from {
    opacity: 0;
    transform: translateY(-5px);
  }
}

/* 页头离顶后加投影：只有滚起来之后才需要「页头浮在内容之上」这层信息。
   阴影走 `html.js`——没有脚本就没有 `.is-scrolled`，不必为它留样式。 */
html.js .site-header {
  transition: box-shadow 0.25s ease;
}

html.js .site-header.is-scrolled {
  box-shadow: var(--lp-shadow);
}

/* ---------- 动效增强：数据巡航 / 光扫 / 追光 / 数字落定 ----------
 * 全站一套动效身份：入场与循环统一用签名曲线 cubic-bezier(0.16, 1, 0.3, 1)
 * （快进缓停、不回弹），反馈 ~180ms、屏内变化 ~280ms、进场 ~460ms；
 * 空间位移一律不走 linear。以下每条都只动 transform 与 opacity，
 * 并在文末 prefers-reduced-motion 里逐项关掉。 */

/* 首屏流程图：一个数据包沿「页面 → 通道 → 目标环境」循环巡航，被命中的节点同一刻亮一圈光。
   6.4s 一轮里只有前 4.5s 有动作，剩下的静默是留给读者读文案的——循环动效最怕催。
   两条泳道先后各亮一次，讲的是「按规则分流」，不是「二选一」。
   只作用于 .hero-visual：请求生命周期那张详图有八个箭头和若干无修饰节点，套同一批延迟会乱序。 */
.hero-visual .flow-node,
.hero-visual .flow-arrow {
  position: relative;
}

.hero-visual .flow-node::before {
  position: absolute;
  inset: -1px;
  pointer-events: none;
  content: '';
  border-radius: inherit;
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--lp-primary) 45%, transparent),
    0 0 16px color-mix(in srgb, var(--lp-primary) 26%, transparent);
  opacity: 0;
  animation: lp-hop 6.4s cubic-bezier(0.16, 1, 0.3, 1) infinite;
}

/* 小方块换成圆点：它代表的是「一次请求」，不该长得像另一个节点。 */
.hero-visual .flow-arrow::after {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  pointer-events: none;
  content: '';
  background: var(--lp-primary);
  border-radius: 50%;
  opacity: 0;
  animation: lp-travel 6.4s cubic-bezier(0.16, 1, 0.3, 1) 400ms infinite;
}

/* 错峰：延迟是上一拍走完的距离，不是随手挑的数。 */
.hero-visual .flow-node--fast::before {
  animation-delay: 1150ms;
}

.hero-visual .flow-node--sw::before {
  animation-delay: 1750ms;
}

/* 两个 .flow-arrow 同属一个 .flow，兄弟选择器只命中后一个（汇聚那一跳）。 */
.hero-visual .flow > .flow-arrow ~ .flow-arrow {
  animation-delay: 2600ms;
}

.hero-visual .flow-node--target::before {
  animation-delay: 3250ms;
}

@keyframes lp-hop {
  0%,
  20%,
  100% {
    opacity: 0;
  }

  3%,
  12% {
    opacity: 1;
  }
}

@keyframes lp-travel {
  0% {
    opacity: 0;
    transform: translateY(-11px);
  }

  2% {
    opacity: 1;
  }

  7% {
    opacity: 1;
    transform: translateY(11px);
  }

  9% {
    opacity: 0;
    transform: translateY(11px);
  }

  100% {
    opacity: 0;
    transform: translateY(-11px);
  }
}

/* 循环动效不该在没人看的地方耗电：脚本在场时先按住，滚进视口由 landing.js 放行。
   禁用 JS 时这条 paused 规则压根不匹配（在 `html.js` 下），巡航照常播。 */
html.js .hero-visual .flow-node::before,
html.js .hero-visual .flow-arrow::after {
  animation-play-state: paused;
}

html.js .hero-visual .flow.is-live .flow-node::before,
html.js .hero-visual .flow.is-live .flow-arrow::after {
  animation-play-state: running;
}

/* 主 CTA：悬停时一道高光从左扫到右，按下再荡开一圈内收的亮边。
   位移的是伪元素，背景色与阴影不动，所以和上面那条 translateY(-1px) 不抢。 */
.btn-primary::before,
.btn-primary::after {
  position: absolute;
  inset: 0;
  pointer-events: none;
  content: '';
}

.btn-primary::after {
  background: linear-gradient(105deg, transparent 40%, rgb(255 255 255 / 26%) 50%, transparent 60%);
  transform: translateX(-105%);
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}

.btn-primary:hover::after {
  transform: translateX(105%);
}

.btn-primary::before {
  border-radius: inherit;
  box-shadow: inset 0 0 0 2px rgb(255 255 255 / 70%);
  opacity: 0;
}

.btn-primary:active::before {
  animation: lp-press 0.32s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes lp-press {
  from {
    opacity: 0.85;
  }

  to {
    opacity: 0;
  }
}

/* 卡片追光：一层跟随指针的柔光，画在卡片背景之上、正文之下——
   `z-index: -1` 配 `isolation: isolate` 把它关进卡片自己的层叠上下文，
   既盖不住文字，也钻不到页面底色后面去。坐标由 landing.js 以百分比写进
   `--lp-x` / `--lp-y`；粗指针和减弱动效下脚本压根不绑定，未加载 JS 时整条规则
   在 `html.js` 下也不匹配，因此不会留下没有光源的空洞。 */
html.js .feature-card,
html.js .tool-card {
  position: relative;
  isolation: isolate;
}

html.js .feature-card::before,
html.js .tool-card::before {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  content: '';
  background: radial-gradient(
    220px 220px at var(--lp-x, 50%) var(--lp-y, 50%),
    color-mix(in srgb, var(--lp-glow, var(--lp-primary)) 13%, transparent),
    transparent 70%
  );
  border-radius: inherit;
  opacity: 0;
  transition: opacity 0.28s ease;
}

html.js .feature-card:hover::before,
html.js .tool-card:hover::before {
  opacity: 1;
}

/* 绿色那张卡的追光跟着品牌走，别统一蓝。 */
.tool-card--green {
  --lp-glow: var(--lp-accent);
}

/* 统计条的四个数字落进格子：比首屏正文晚半拍，数字是「结论」，
   同时到就等于没说。过冲压到 4%，看得见落点、看不见弹。 */
.hero-visual .stat b {
  animation: lp-pop 0.46s cubic-bezier(0.16, 1, 0.3, 1) 260ms both;
}

.hero-visual .stat:nth-child(2) b {
  animation-delay: 330ms;
}

.hero-visual .stat:nth-child(3) b {
  animation-delay: 400ms;
}

.hero-visual .stat:nth-child(4) b {
  animation-delay: 470ms;
}

@keyframes lp-pop {
  0% {
    opacity: 0;
    transform: translateY(8px) scale(0.92);
  }

  62% {
    opacity: 1;
    transform: scale(1.04);
  }

  100% {
    transform: scale(1);
  }
}

/* 能力图标：卡片抬起时底色外呼出一圈同色光，和图标的旋转缩放是同一拍。
   用 currentcolor，所以六种图标各自的配色不用各写一条。 */
.feature-icon::after {
  position: absolute;
  inset: -1px;
  pointer-events: none;
  content: '';
  border: 1px solid currentcolor;
  border-radius: inherit;
  opacity: 0;
}

.feature-card:hover .feature-icon::after {
  animation: lp-halo 0.62s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes lp-halo {
  from {
    opacity: 0.5;
    transform: scale(1);
  }

  to {
    opacity: 0;
    transform: scale(1.28);
  }
}

/* ---------- 响应式 ---------- */

@media (width <= 1000px) {
  .hero .wrap {
    grid-template-columns: 1fr;
  }

  .hero-visual {
    max-width: 560px;
  }
}

/* 8 个锚点窄于此宽度就排不进一行。与其折成两行把 sticky 头部顶高，
   不如只让锚点条自身横向滚动 —— 完整对比 / GitHub / EN 三个入口留在原位，
   永远不需要滚动就能点。尾部留白 + 右侧渐隐遮罩让被截断的那一项看起来是
   「右边还有」，而不是被切掉。 */
@media (width <= 900px) {
  .site-nav {
    flex-wrap: nowrap;
    gap: 14px;
    max-width: 100%;
    padding-right: 28px;
    padding-bottom: 4px;
    overflow-x: auto;
    font-size: 14px;
    white-space: nowrap;
    scrollbar-width: none;
    mask-image: linear-gradient(90deg, #000 calc(100% - 26px), transparent);
  }

  .site-nav::-webkit-scrollbar {
    display: none;
  }
}

@media (width <= 760px) {
  section {
    padding: 44px 0;
  }

  .hero {
    padding: 44px 0 40px;
  }

  /* 窄屏下标题徽章收小一号：40px 的方块在 390px 宽度上会挤掉两行标题的宽度。 */
  .section-head h2 {
    gap: 10px;
  }

  .section-icon {
    width: 34px;
    height: 34px;
    border-radius: 10px;
  }

  .section-icon svg {
    width: 19px;
    height: 19px;
  }

  /* 锚点条整体收进汉堡菜单：第二行横向滚动条在 390px 宽度上仍要点准
     14px 的链接，下拉里是 44px 的行高。跨页链接（完整对比 / GitHub / 语言切换）
     由下拉里的 .nav-menu-exits 承接，因此 .nav-actions 在汉堡页直接隐藏。
     只作用于带汉堡菜单的页头（.site-header--menu）：隐私页的三条跨页链接没有
     汉堡可收，若一并隐藏就彻底点不到了，改走下面的换行兜底。 */
  .site-header .wrap {
    gap: 12px;
    padding-top: 10px;
    padding-bottom: 10px;
  }

  .site-header--menu .site-nav,
  .site-header--menu .nav-actions {
    display: none;
  }

  .site-header--menu .nav-menu {
    display: block;
    margin-left: auto;
  }

  .site-header:not(.site-header--menu) .site-nav {
    flex-wrap: wrap;
    gap: 12px 16px;
  }

  .feature-card-lg {
    padding: 24px 22px;
  }

  .slide {
    flex-basis: 100%;
  }

  .scroll-rail {
    right: max(14px, env(safe-area-inset-right));
    bottom: max(14px, env(safe-area-inset-bottom));
  }
}

/* 单手握持宽度：进一步压缩首屏留白与字号阶梯，保证 H1 不折成孤字行、
   统计条四项不换行、CTA 按钮可整行点按。 */
@media (width <= 480px) {
  section {
    padding: 36px 0;
  }

  .hero {
    padding: 30px 0 34px;
  }

  .hero h1 {
    margin-bottom: 12px;
    font-size: 29px;
    letter-spacing: -0.4px;
  }

  .hero .lede {
    margin-bottom: 18px;
    font-size: 15.5px;
  }

  .cta-row .btn {
    flex: 1 1 100%;
    justify-content: center;
    padding: 12px 18px;
  }

  .stat-strip {
    gap: 6px;
  }

  .stat {
    padding: 10px 6px;
  }

  .stat b {
    font-size: 22px;
  }

  .stat span {
    font-size: 12px;
  }

  .section-lede {
    font-size: 15px;
  }

  .slide figcaption b {
    font-size: 14.5px;
  }

  .slide figcaption span {
    font-size: 13px;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .eyebrow .dot {
    animation: none;
  }

  /* 上面「动效」一节逐项关闭：进场、面板滑出、答案淡入都不再播。 */
  .hero-copy > *,
  .hero-visual,
  .nav-menu[open] .nav-menu-panel,
  details[open] > p {
    animation: none;
  }

  /* 新增的四条同样逐项停：巡航的亮环与圆点、按下的亮边、数字落定、图标光晕。 */
  .hero-visual .flow-node::before,
  .hero-visual .flow-arrow::after,
  .btn-primary:active::before,
  .hero-visual .stat b,
  .feature-card:hover .feature-icon::after {
    animation: none;
  }

  /* 光扫与追光是纯装饰层，没有「慢一点」的意义，直接收掉比留着强。 */
  .btn-primary::after,
  html.js .feature-card::before,
  html.js .tool-card::before {
    display: none;
  }

  .btn,
  .feature-card,
  .feature-icon,
  .gallery-btn,
  .gallery-dots button,
  .scroll-rail button,
  .site-nav a,
  .nav-actions a,
  .tool-card,
  details,
  summary,
  .copy-btn,
  .btn-primary::after,
  html.js .feature-card::before,
  html.js .tool-card::before,
  .site-nav > a::after,
  summary::before,
  summary::after {
    transition: none;
  }

  html.js .reveal,
  html.js .site-header {
    transition: none;
  }

  html.js .reveal {
    opacity: 1;
    transform: none;
  }
}
