/* ---- Inter：自托管 ----------------------------------------------------
   原来这三档字重是 fonts.googleapis.com 上的一条 <link>。那是一条渲染阻塞
   的样式表，在国内取不到时浏览器要一直等到超时才继续排版——首屏卡多久
   取决于一个连不上的域名，而不是我们自己的服务器。

   两个文件都是 Inter 的可变字体，同一份文件覆盖 100–900：Google 给 400 /
   500 / 600 返回的本来就是同一个 URL，按字重拆成三份是白白多两次请求。

   latin-ext 那份 83KB 平时不会被下载——unicode-range 让浏览器只在页面真的
   出现该区段的字符时才去取它。中文交给下面 font-family 里的 PingFang /
   微软雅黑，本来也不该由 Inter 承担。 */
@font-face {
  font-family: Inter;
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: Inter;
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============================================================================
   色板取自 DESIGN-coinbase.md。那套系统只有一个品牌电压——#0052ff——其余
   全是白画布、墨黑、几档灰面。所以这里的规矩是：蓝色只出现在主 CTA、选中
   态、聚焦环和勾选标记上，层次一律靠"面 + 发丝线"做，不靠投影。

   文档本身是浅色优先的（白画布 + 深色通栏做节奏），站点有主题开关，所以
   两套主题分别落在文档的两块画布上：浅色 = canvas #ffffff，深色 =
   surface-dark #0a0b0d，卡片对应 surface-card / surface-dark-elevated。
   ========================================================================= */

/* 深色（默认）= 文档里的 surface-dark 画布。底 #0a0b0d，卡片 #16181c 抬一档。 */
:root,
html[data-theme='dark'] {
  --kx-bg: #0a0b0d;
  --kx-footer: #0a0b0d;
  --kx-band: #16181c;
  --kx-surface: #16181c;
  --kx-surface-hover: #1d2025;
  --kx-media: #16181c;
  --kx-soft: #16181c;
  --kx-soft-2: #1d2025;
  --kx-soft-hover: #23262c;
  --kx-line: #23262b;
  --kx-line-soft: #1a1d21;
  --kx-line-strong: #363b42;
  --kx-title: #ffffff;
  --kx-text: #ffffff;
  --kx-muted: #a8acb3;
  --kx-subtle: #7c828a;
  --kx-accent: #0052ff;
  --kx-accent-active: #003ecc;
  --kx-accent-weak: rgba(0, 82, 255, 0.22);
  /* 品牌蓝当"字"用的那一档。#0052ff 压在 #0a0b0d 上只有 3.4:1，正文级别的
     蓝字读不出来；填色（白字压蓝底 5.8:1）没这个问题，所以两者分开。 */
  --kx-accent-head: #5b8dff;
  --kx-header-bg: rgba(10, 11, 13, 0.82);
  --kx-scrollbar: rgba(168, 172, 179, 0.45);
  --kx-scrollbar-hover: rgba(168, 172, 179, 0.75);
  /* 表单状态色。文档给的是 #05b169 / #cf202f，但那对值只在一种底色上成立：
     红压在 #0a0b0d 上是 3.7:1，13.5px 的正文读不出来。深色这一档把红提亮到
     7.2:1，绿保持原值（7.0:1）。 */
  --kx-ok: #05b169;
  --kx-err: #ff6b78;
}

/* 浅色 = 文档的默认画布：纯白底，卡片同样是纯白，靠 1px #dee1e6 分离。 */
html[data-theme='light'] {
  --kx-bg: #ffffff;
  --kx-footer: #ffffff;
  --kx-band: #f7f7f7;
  --kx-surface: #ffffff;
  --kx-surface-hover: #f7f7f7;
  --kx-media: #ffffff;
  --kx-soft: #f7f7f7;
  --kx-soft-2: #eef0f3;
  --kx-soft-hover: #eef0f3;
  --kx-line: #dee1e6;
  --kx-line-soft: #eef0f3;
  --kx-line-strong: #c6ccd4;
  --kx-title: #0a0b0d;
  --kx-text: #0a0b0d;
  --kx-muted: #5b616e;
  /* 文档给的 muted 是 #7c828a，压在白底上只有 3.9:1——这一档专门放 13px 的
     小标签，达不到 AA。压深到 4.7:1，是整套色板里唯一一处没照抄的值。 */
  --kx-subtle: #6e747d;
  --kx-accent: #0052ff;
  --kx-accent-active: #003ecc;
  --kx-accent-weak: rgba(0, 82, 255, 0.08);
  --kx-accent-head: #0052ff;
  --kx-header-bg: rgba(255, 255, 255, 0.85);
  --kx-scrollbar: rgba(10, 11, 13, 0.24);
  --kx-scrollbar-hover: rgba(10, 11, 13, 0.4);
  /* 反过来：绿 #05b169 压在白底上只有 2.8:1，这一档压深到 5.0:1，
     红保持文档原值（5.4:1）。 */
  --kx-ok: #0a7f4e;
  --kx-err: #cf202f;
}

:root {
  --kx-ease-out: cubic-bezier(0.19, 1, 0.22, 1);
  --kx-ease-state: cubic-bezier(0.2, 0.8, 0.2, 1);
}

html {
  background: var(--kx-bg);
  color-scheme: dark;
  scroll-behavior: smooth;
  overflow-x: hidden;
  overflow-x: clip;
  /* 滚动条的位置一直留着。移动端菜单打开时脚本会把 overflow 设成 hidden，
     滚动条一撤，视口就凭空宽出 10px——顶栏右侧那排控件和居中容器会整体
     挪一下，而抽屉是半透明背景 + 从顶边卷下来的，这一挪正好看得见。
     预留出槽位，开合前后视口宽度不变，也就没有那一下位移。 */
  scrollbar-gutter: stable;
}

html[data-theme='light'] { color-scheme: light; }

body {
  margin: 0;
  background: var(--kx-bg);
  color: var(--kx-text);
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  overflow-x: clip;
}

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

/* ---- 兜底：site.js 缺席时不要把内容永久按在隐藏态 ----------------------
   下面三处隐藏态（整页遮罩、首屏入场、滚动揭示）都要等 site.js 才解开。
   脚本请求失败一次，用户看到的就是一张空白页——比闪一帧裸 HTML 严重得多。
   这条 1.6s 后强制淡回可见的动画不依赖 JS，正常情况下轮不到它生效：真正
   的规则写在后面且选择器更具体，会把它整条覆盖掉。 */
@keyframes kxFailsafe { to { opacity: 1; } }

/* 样式落地前先按住整页，之后再淡入，避免未套样式的裸 HTML 闪一帧。
   首屏入场动画也挂在同一个开关上，否则动画会在页面还看不见的时候演完。
   Tailwind 已经是静态 <link>，正常路径下 site.js 一执行就放行（见那边的
   同步探测），这道遮罩实际只在样式意外晚到时才看得见。

   限定在 html.kx-js 下：解开这道遮罩的 is-ready 由 site.js 加，而 .kx-js 由
   <head> 的内联脚本加。无条件写的话，site.js 请求失败（CDN 抽风、离线打开）
   就没有任何东西会摘掉 opacity: 0——页面永久白屏，比闪一帧裸 HTML 严重得多。
   这条和下面 .kx-reveal 的隐藏态是同一个道理，写法保持一致。 */
html.kx-js body { opacity: 0; transition: opacity 220ms ease; animation: kxFailsafe 200ms ease 1600ms forwards; }
html.kx-js body.is-ready { opacity: 1; }

/* ---- 首屏入场：从第一帧就是隐藏态的关键帧动画，不依赖 JS 观察器 ----
   阅读顺序即出场顺序（标题 → 副文 → 按钮 → 平台行），每个元素通过
   --kx-delay 各自延迟，因为它们并不都是兄弟节点。 */
@keyframes kxEnter {
  from { opacity: 0; transform: translate3d(0, 16px, 0) scale(0.99); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

.kx-enter { opacity: 0; animation: kxFailsafe 200ms ease 1600ms forwards; }

body.is-ready .kx-enter {
  animation: kxEnter 440ms cubic-bezier(0.23, 1, 0.32, 1) both;
  animation-delay: var(--kx-delay, 0ms);
}

/* ---- 入场 ----------------------------------------------------------------
   .kx-reveal 从第一帧就是隐藏态，由 site.js 同步决定它走哪条路：首屏内的
   换成 .kx-enter（关键帧），首屏以下的打上 [data-reveal]（滚动揭示）。两种
   接管方式都会让下面这条 :not() 失配，所以中间不存在已隐藏但没人管的状态。

   挂在 html.kx-js 上：这个类由 <head> 的内联脚本添加，禁用 JS 时它不存在，
   规则整条不生效，内容照常显示。 */
html.kx-js .kx-reveal:not([data-reveal]):not(.kx-enter) { opacity: 0; animation: kxFailsafe 200ms ease 1600ms forwards; }

/* ---- 滚动揭示：由页尾的 IntersectionObserver 打上 data-reveal ----
   带 html 前缀是为了压过 .kx-card 自己的 transition（同为 0,1,0，写在后面
   就赢）。被压过的后果不只是卡片不淡入：没有 opacity 过渡就没有
   transitionend，收尾逻辑一辈子跑不到，data-reveal 和 will-change 会永远
   挂在三张产品卡上。 */
html.kx-js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition: opacity 520ms var(--kx-ease-out), transform 520ms var(--kx-ease-out);
  will-change: opacity, transform;
}

html.kx-js [data-reveal].is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
  body.is-ready .kx-enter { animation: none; opacity: 1; }
  html.kx-js [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ---- 卡片 ----
   平铺纯色，不用渐变：过渡列表里只有 background-color，渐变层会在第 1 帧
   直接换掉，和 180ms 才走完的底色错开，hover 就会闪。

   圆角分两档（写在 HTML 的工具类里）：纯文字卡片走设计文档的 24px；裹着
   截图或视频的容器降到 8px——图里本来就有窗口边框、标题栏这些硬直角，
   外面一圈大圆弧和它对不上，越圆越像图被啃掉了一块。 */
.kx-card {
  background-color: var(--kx-surface);
  transition: background-color 180ms var(--kx-ease-state),
    border-color 180ms var(--kx-ease-state), color 180ms var(--kx-ease-state);
}

/* hover 只动底色和描边，不动投影：投影在指针下变大读起来像卡片朝你跳，
   一列卡片扫过去整页都在抖。

   描边压深一档，不染蓝：设计文档只给了一个品牌电压，要求它省着用——三张
   卡片并排，指针一路扫过去就是三次蓝色闪烁，蓝色该留给这一屏唯一的主 CTA。 */
.kx-card:hover {
  border-color: var(--kx-line-strong);
  background-color: var(--kx-surface-hover);
}

/* 图片容器自己建一个合成层，缩放就在层内部完成，不再和卡片的圆角裁剪
   互相干扰。backface-visibility 是同一件事的另一半：没有它，Blink 在
   缩放的图片边缘会留下一条抗锯齿缝，露出容器底色。 */
.kx-media {
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* 图片起手就放大一点点。overflow-hidden 的裁剪盒高度是 aspect-ratio 算
   出来的小数（比如 283.55px），scale(1) 的图正好卡在边界上，底边会漏出
   半像素的容器底色。多出来的 0.4% 顶掉这条缝，肉眼看不出来。 */
.kx-media img { transform: scale(1.004); }
.group:hover .kx-media img { transform: scale(1.045); }

@media (prefers-reduced-motion: reduce) {
  .kx-card { transition: none; }
  .group:hover .kx-media img { transform: scale(1.004); }
}

/* ---- 播放器容器 ----
   ArtPlayer 是往容器里塞 DOM 的，容器自己必须先有高度，否则它挂上去是
   0 高的一条。这几段视频和它们的封面都是 1153×720，所以直接按 8:5 占位：
   位置在脚本跑起来之前就留好了，播放器挂上去不会把下面的内容顶开。 */
.kx-player {
  width: 100%;
  aspect-ratio: 8 / 5;
  background-color: #000;
}

/* ---- 粘滞展示（产品页的功能详解）--------------------------------------
   左边条目随页滚，右边一张大图钉在视口里，滚到哪条换哪张。

   每条固定 56vh 且垂直居中：让每条的滚动距离与正文长短无关，切换的节拍
   才是均匀的——按内容高度排的话，一句话的"描述文件管理"会一闪而过，三段
   话的那条却要滚半天。

   压暗和高亮只在 lg 以上生效。窄屏没有粘滞列，每条自带一张图、本身就是
   完整的一段，再压暗只是让人读着费劲。 */
@media (min-width: 1024px) {
  .kx-step {
    display: flex;
    /* 上下夹住：矮屏上别把一条撑得比一屏还高，高屏上也别让五条一次全露出来
       ——两头都会让"滚一段换一张"读不出来。 */
    min-height: clamp(360px, 56vh, 560px);
    flex-direction: column;
    justify-content: center;
    border-left: 2px solid var(--kx-line);
    padding: 28px 0 28px 24px;
    transition: opacity 320ms var(--kx-ease-state), border-color 320ms var(--kx-ease-state);
  }

  .kx-step[data-active='false'] { opacity: 0.5; }
  .kx-step[data-active='true'] { border-left-color: var(--kx-accent); }
}

/* 右列被缺图降级撤掉之后（本地预览必然如此），剩下的条目列跨满整行，
   不然左边一条 360px 的窄栏旁边会空出三分之二的白。 */
[data-showcase] > :only-child { grid-column: 1 / -1; }

.kx-shots { position: relative; aspect-ratio: 8 / 5; }

.kx-shot {
  position: absolute;
  inset: 0;
  display: block;
  height: 100%;
  width: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 420ms var(--kx-ease-state);
}

/* 没有 JS 时第一张就是可见的那张，不会是一个空框。下面两条写在后面，
   接管之后由 data-active 说了算。 */
.kx-shot:first-child { opacity: 1; }
.kx-shot[data-active='true'] { opacity: 1; }
.kx-shot[data-active='false'] { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .kx-step, .kx-shot { transition: none; }
}

/* ---- 客户 logo 墙 ----
   底色写死白色，不跟 --kx-surface 走：这批 logo 是白底 JPEG（少数是透明
   PNG），深色主题下直接摆在黑底上，每个 logo 会自带一块方形白斑，而且
   黑字的那几个（凤凰网、马蜂窝、汽车之家）在黑底上根本读不出来。给瓷砖
   固定白底，logo 自己的白底就和瓷砖是同一个白，接缝消失。

   高度靠 min-height 而不是 aspect-ratio：十二张原图的比例并不统一（1.78
   到 2.0 都有），object-fit: contain 只保证不变形，统一的是瓷砖不是图。 */
.kx-logo-tile {
  display: grid;
  place-items: center;
  min-height: 84px;
  border: 1px solid var(--kx-line);
  border-radius: 8px;
  background-color: #ffffff;
  padding: 16px 20px;
}

.kx-logo-tile img {
  max-height: 48px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* ---- 跳过导航 ----
   移出视口用 transform 而不是 display: none / visibility: hidden：后两者
   把元素排除在焦点顺序之外，这个链接就永远等不到它该出场的那一次 Tab。 */
.kx-skip {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 200;
  transform: translateY(calc(-100% - 24px));
  border: 1px solid var(--kx-line);
  border-radius: 10px;
  background-color: var(--kx-surface);
  padding: 10px 16px;
  color: var(--kx-text);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: transform 180ms var(--kx-ease-state);
}

.kx-skip:focus { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .kx-skip { transition: none; }
}

/* ---- 按钮 ----
   设计文档的按钮只有一种几何：胶囊（100px）、44px 高、12/20 内边距、
   16px/600 的字。主色是唯一的品牌蓝，次级是一块灰面——次级不染蓝，
   一屏里蓝色只该有一两处。 */
.kx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 12px 20px;
  border: 1px solid transparent;
  border-radius: 100px;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.15;
  white-space: nowrap;
  text-decoration: none;
  transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease;
}

.kx-btn svg { width: 17px; height: 17px; }

/* 首屏那对 CTA 走文档的 button-pill-cta：56px 高、16/32 内边距。整站只有
   首屏用这一档，其余一律 44px——"更大的按钮"用两次就不再是重点了。 */
.kx-btn-lg { min-height: 56px; padding: 16px 32px; }

.kx-btn-primary {
  border-color: var(--kx-accent);
  background-color: var(--kx-accent);
  color: #fff;
}
/* 文档只记了 Default 和 Active 两态，没有 hover——hover 就顺着按下态往
   同一个方向走一半，不另起一个更亮的蓝，免得多出一档没有出处的颜色。 */
.kx-btn-primary:hover {
  border-color: #0047e6;
  background-color: #0047e6;
  color: #fff;
}
.kx-btn-primary:active {
  border-color: var(--kx-accent-active);
  background-color: var(--kx-accent-active);
  color: #fff;
}

/* 次级按钮：文档给的是一块 surface-strong 的灰面、无描边。这里补了一条
   发丝线——CTA 通栏本身就是 --kx-band 那块灰，无描边的灰按钮压在灰底上
   会整个化掉。 */
.kx-btn-ghost {
  border-color: var(--kx-line);
  background-color: var(--kx-soft-2);
  color: var(--kx-text);
}
.kx-btn-ghost:hover {
  border-color: var(--kx-line-strong);
  background-color: var(--kx-soft-hover);
  color: var(--kx-text);
}

.kx-nav-link { color: var(--kx-muted); transition: background-color 150ms ease, color 150ms ease; }
.kx-nav-link:hover, .kx-nav-link[aria-current="page"] {
  background-color: var(--kx-soft-hover);
  color: var(--kx-text);
}

/* ---- 头部下拉（主题 / 语言）------------------------------------------
   触发器长成一张小卡片，而不是一块无边框的灰底：它孤零零地悬在页面
   背景上，浅色主题下无边框的灰块读起来是一片污渍，不是控件。 */
.kx-menu-trigger {
  display: inline-flex;
  cursor: pointer;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--kx-line);
  border-radius: 10px;
  background-color: var(--kx-surface);
  padding: 8px 14px;
  color: var(--kx-text);
  font-size: 14px;
  font-weight: 500;
  transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease;
}

.kx-menu-trigger:hover,
.kx-menu-trigger[aria-expanded='true'] {
  border-color: var(--kx-line-strong);
  background-color: var(--kx-surface-hover);
}

/* 后代选择器，不是 `>`：主题触发器的图标包在一个 [data-theme-icon] 的
   <span> 里（脚本要整块换图标），直接子选择器够不到它，那个 <svg> 就会
   退回 300×150 的默认尺寸，把整个头部撑烂。 */
.kx-menu-trigger svg { width: 15px; height: 15px; }
.kx-menu-trigger [data-theme-icon] { display: inline-flex; }

/* 箭头：一个旋转 45° 的直角，展开时翻上去。比塞一个 chevron 图标省一个 <use>。 */
.kx-caret {
  height: 6px;
  width: 6px;
  rotate: 45deg;
  border-bottom: 1px solid currentColor;
  border-right: 1px solid currentColor;
  opacity: 0.7;
  transition: rotate 200ms var(--kx-ease-state);
}

.kx-menu-trigger[aria-expanded='true'] .kx-caret { rotate: -135deg; }

.kx-menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  z-index: 60;
  display: flex;
  min-width: 168px;
  flex-direction: column;
  gap: 4px;
  border: 1px solid var(--kx-line);
  border-radius: 16px;
  background-color: var(--kx-surface);
  padding: 6px;
  text-align: left;
  opacity: 0;
  /* 入场只动 opacity 和位移，不再动 scale。0.97→1 的缩放会让面板每一帧都在
     改自己的宽高（实测 162.96px 长到 168px），里面的文字和 1px 描边跟着一帧
     一个子像素地重新光栅化，200ms 里一直在微微晃——那就是"抖一下"。位移用
     translate3d 而不是 translate/scale 那对独立属性，配合下面的图层提升，整段
     动画交给合成器，面板内部一次都不用重画。 */
  transform: translate3d(0, 6px, 0);
  backface-visibility: hidden;
  /* 常驻提升，不等动画开始才提：临时提升会在动画首尾各触发一次图层的建立和
     销毁，文字的抗锯齿方式跟着切换，末帧会"啪"地重描一下。 */
  will-change: opacity, transform;
  /* 全站唯一保留投影的地方。设计文档只留一档很浅的投影（0 4px 12px /4%），
     但浮层不比卡片：它压在正文上，没有一点高度就分不出哪层在上面。这里按
     文档那一档的方向加深，不再是原来那两层重投影。 */
  box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.5);
  /* 淡入用普通 ease-out：--kx-ease-state 前段太陡，4ms 就冲到三分之一不透明度，
     面板像是先"啪"地出现再慢慢补齐，读起来同样是一下抖。位移保留原曲线。 */
  transition: opacity 140ms ease-out, transform 200ms var(--kx-ease-state);
}

html[data-theme='light'] .kx-menu-panel {
  box-shadow: 0 8px 24px -6px rgba(10, 11, 13, 0.12);
}

.kx-menu-panel[data-open='false'] { pointer-events: none; }
.kx-menu-panel[data-open='true'] { opacity: 1; transform: translate3d(0, 0, 0); }

.kx-menu-option {
  display: flex;
  min-height: 36px;
  width: 100%;
  cursor: pointer;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  padding: 8px 12px;
  color: var(--kx-muted);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  transition: background-color 170ms ease, color 170ms ease;
}

.kx-menu-option:hover,
.kx-menu-option:focus-visible { background-color: var(--kx-soft-hover); color: var(--kx-text); }
.kx-menu-option[data-current='true'] { background-color: var(--kx-accent-weak); color: var(--kx-text); }
.kx-menu-option > span:first-child { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.kx-menu-option svg { height: 14px; width: 14px; opacity: 0.75; }

/* 勾：位置始终占着，只切换透明度——否则选中项会比其它项宽一截，
   菜单在切换时横向抖一下。 */
.kx-menu-check {
  display: grid;
  height: 18px;
  width: 18px;
  flex: none;
  place-items: center;
  border-radius: 9999px;
  background-color: var(--kx-accent);
  color: #fff;
  opacity: 0;
  transition: opacity 200ms ease;
}

.kx-menu-check svg { height: 11px; width: 11px; opacity: 1; }
.kx-menu-option[data-current='true'] .kx-menu-check { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .kx-menu-panel, .kx-caret, .kx-menu-check { transition: none; }
}

/* 抽屉里的主题三连按钮 */
.kx-theme-chip {
  display: inline-flex;
  min-height: 42px;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid var(--kx-line);
  border-radius: 10px;
  background-color: var(--kx-surface);
  padding: 8px 12px;
  color: var(--kx-text);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  transition: background-color 180ms ease, border-color 180ms ease, color 180ms ease;
}

.kx-theme-chip svg { height: 16px; width: 16px; }
.kx-theme-chip:hover { background-color: var(--kx-surface-hover); }
.kx-theme-chip[data-current='true'] {
  border-color: var(--kx-accent);
  background-color: var(--kx-accent);
  color: #fff;
}

/* 滚过 10px 后给固定头部加毛玻璃和分隔线，静止时它是透明的。 */
[data-header][data-scrolled="true"] {
  border-bottom-color: var(--kx-line);
  background-color: var(--kx-header-bg);
  backdrop-filter: blur(18px) saturate(145%);
  -webkit-backdrop-filter: blur(18px) saturate(145%);
}

/* 标题里被强调的那半句。实色，不做渐变：渐变字在大字号上会让笔画左右
   深浅不一，中文的横竖密度又高，读起来是脏，不是亮点。一个颜色说清
   "这半句是重点"就够了。 */
.kx-accent-head { color: var(--kx-accent-head); }

/* 结尾 CTA 通栏。设计文档的页面节奏是"白 → 浅灰 → 深色"三段轮转，收尾这块
   原本取的是深色那一段（cta-band-dark：#0a0b0d 底 + 白字）。

   实际摆到这几个页面上不成立：满幅纯黑横穿白页面，上下都是硬边，而它上面
   是白底的客户墙、下面是白底的页脚，黑条夹在中间没有任何过渡，读起来是页面
   被切了一刀。所以走文档的另一档——surface-soft #f7f7f7 的浅灰通栏，深浅只
   差一档，节奏还在，但不再是一道横杠。

   深色主题下同理，走 --kx-band（#16181c）比页面底亮一档。两套主题都是"抬
   一层"，只是方向相反。 */
.kx-band { background-color: var(--kx-band); }

:where(a, button, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: 2px solid var(--kx-accent);
  outline-offset: 3px;
}

::selection { background: var(--kx-accent); color: #fff; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  border: 2px solid transparent;
  border-radius: 999px;
  background: var(--kx-scrollbar);
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--kx-scrollbar-hover); background-clip: padding-box; }

/* ---- 长文正文（隐私政策 / 使用协议）--------------------------------------
   这两页是法律文本，读者是"要查某一条"而不是"从头读到尾"，所以标题要能扫、
   段落要有呼吸，行长要短。max-width 交给外层容器控制。 */
.kx-prose { color: var(--kx-muted); font-size: 16px; line-height: 1.85; }

.kx-prose > h2 {
  margin: 2.6em 0 0.9em;
  color: var(--kx-text);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.4;
  scroll-margin-top: 88px;
}

.kx-prose > h2:first-child { margin-top: 0; }

.kx-prose p { margin: 0 0 1.1em; }
.kx-prose > :last-child { margin-bottom: 0; }

/* Tailwind 的 preflight 把 ul/ol 的 list-style 清成了 none，长文里必须要回来：
   没有项目符号的并列条目在中文里根本看不出是列表，只是几行短句。 */
.kx-prose ul { list-style: disc; }
.kx-prose ol { list-style: decimal; }
.kx-prose ul, .kx-prose ol { margin: 0 0 1.2em; padding-left: 1.35em; }
.kx-prose li { margin-bottom: 0.55em; }
.kx-prose li::marker { color: var(--kx-subtle); }
.kx-prose strong { color: var(--kx-text); font-weight: 600; }

.kx-prose a {
  color: var(--kx-accent-head);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* 条文里被单独框出来的一段（"我们承诺""如何联系"这类）。左侧一道品牌色的
   竖线，而不是整块底色：整块底色在长文里会变成一个个色斑，反而打断阅读。 */
.kx-prose .kx-note {
  margin: 1.6em 0;
  border-left: 3px solid var(--kx-accent-head);
  border-radius: 0 12px 12px 0;
  background-color: var(--kx-soft);
  padding: 1.1em 1.3em;
}

.kx-prose .kx-note p:last-child { margin-bottom: 0; }

/* ---- 表单控件 -------------------------------------------------------------
   只在联系页出现，但放在这里而不是内联：input 有 rest / hover / focus /
   invalid 四种状态，用工具类拼要写四遍前缀，读起来还不如直接写 CSS。 */
.kx-field {
  width: 100%;
  border: 1px solid var(--kx-line);
  border-radius: 12px;
  background-color: var(--kx-bg);
  padding: 10px 13px;
  color: var(--kx-text);
  font: inherit;
  font-size: 14.5px;
  line-height: 1.6;
  transition: border-color 170ms var(--kx-ease-state), background-color 170ms var(--kx-ease-state);
}

.kx-field::placeholder { color: var(--kx-subtle); }
.kx-field:hover { border-color: var(--kx-line-strong); }

/* 文档的输入框聚焦是"描边加粗到 2px 品牌蓝"。真把 border 从 1px 改成 2px
   会让框内文字整体挪 1px，所以用一层 inset 阴影补出第二个像素，几何不变。 */
.kx-field:focus {
  border-color: var(--kx-accent);
  background-color: var(--kx-bg);
  box-shadow: inset 0 0 0 1px var(--kx-accent);
  outline: none;
}

/* 只在用户提交过、字段确实错了之后才标红。:invalid 单独用会让空表单一打开
   就满屏红框——还没填就先挨骂。红取文档的 semantic-down。 */
.kx-field:user-invalid { border-color: var(--kx-err); }

/* 图文段：图挂掉时，文字块自动跨满整行。
   产品页的截图外链原站的 media_file，那批 URL 受服务端保护（跨域或直接访问
   都会被拒），本地预览时必然是破图。与其留一个空框加一行 alt，不如把图整块
   撤掉——见 site.js 里的 [data-figure] 处理。 */
.kx-figure-row > :only-child { grid-column: 1 / -1; }
