/* ==========================================================================
   Wanova marketing site — design system + page styles
   Brand primitives from the identity spec `Wanova Logo 终稿.html`(「写一半的 W」:Ink 主笔 +
   Assist 绿 AI 笔)—— 单一强调色,层级靠填充/文字区分,见下方 --green* 令牌注释。
   This is a STANDALONE site, so the
   charter's embed layout rules do not apply — only its colour/voice/logo do.
   Day/night: follows prefers-color-scheme, with a manual [data-theme] override.

   对比度契约(WCAG 2.1 AA,正文级 4.5:1)。所有作为「文字」的令牌都按 4.5 选值,
   下面每条都标了实测比值 —— 改色前用同样的算法复核,别凭观感调:
     日间 --green 必须承载白字(--on-green),故比品牌绿深一档;品牌绿 #00A884 白字
     只有 3.03:1,过不了。夜间反过来:亮绿配深字,#00A884 得以原样留在夜里。
   等宽小字(--font-mono)只用于「标注类」微排版(eyebrow / pill / 小写大写标签),
   正文永不进 mono —— 且 mono 与 sans 都不含阿拉伯文/CJK 字形,见文件末尾
   「RTL / CJK」段的豁免规则,那里是这套排版能在 8 语种下不崩的原因。
   ========================================================================== */

/* ---- 自托管字体 (self-hosted, zero external requests) ------------------
   为什么自托管而不是挂 fonts.googleapis.com:cookies.html 明写本站
   "no web fonts loaded from a CDN",热链会让那句已发布的承诺变成假话,并构成
   未经同意把访客 IP 交给第三方(德国 LG München 2022 已就此判赔)。文件随仓库走,
   浏览器只向本站发请求。
   两款均为 SIL Open Font License 1.1,许可文本随字体一起分发(见同目录 OFL-*.txt)。
   Plus Jakarta Sans 是可变字体(wght 200–800),故一个文件覆盖全部字重;
   IBM Plex Mono 取 400/500 两档静态实例(标注类小字只用到这两档)。
   只取 latin + latin-ext:阿拉伯文与 CJK 刻意回落系统字体(见文件末 RTL/CJK 段),
   unicode-range 让浏览器按页面实际用到的字符集按需下载。
   font-display: swap —— 先用系统字体把文字画出来,字体到位后再换,永不白屏。 */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/plus-jakarta-sans-var-latin.woff2') format('woff2');   /* latin */
  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: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/plus-jakarta-sans-var-latin-ext.woff2') format('woff2');   /* latin-ext */
  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;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-400-latin.woff2') format('woff2');   /* latin */
  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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');   /* latin-ext */
  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;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-500-latin.woff2') format('woff2');   /* latin */
  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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');   /* latin-ext */
  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 tokens: day (default) ------------------------------------- */
:root {
  --bg:            #ffffff;
  --bg-soft:       #faf9f7;         /* 暖白:纸感,与纯白 --panel 拉开卡片层次 */
  --panel:         #ffffff;
  --elevated:      #f4f3f0;
  --border:        #ecebe6;         /* 中性色整体偏暖:线不再是冷灰蓝 */
  --border-strong: #ddddd6;
  --text:          #131311;
  --muted:         #5d5d56;         /* 6.30:1 on --bg-soft */
  --faint:         #6f6f66;         /* 5.07:1 on #fff / 4.82:1 on --bg-soft —— 它承载页脚、
                                       表单 hint、tagline 等真实文字,不是装饰色 */

  /* ★2026-08-03:靛紫家族(--indigo*)已整体删除。新品牌标识「写一半的 W」只有 Ink + 一个绿,
     没有第二个强调色,再留一套紫就是和标识打架。原先「紫=品牌强调 / 绿=每屏唯一动作」的双色
     层级因此收成【单一绿】—— 层级改由【填充 vs 文字】承担:
       · 实心绿(--green 底 + --on-green 字)= 那一个动作,每屏仍只给一次;
       · 绿字(--green-ink)= 链接与强调,量可以多,但绝不做成实心块。
     ⚠️ 品牌盘的 Assist 绿 #22A981 只是【笔画色】,白底上仅 2.97:1,永远不要拿它当文字或按钮底;
        下面这两个值才是同色系里过了 AA 的版本。 */
  --green:         #0b7a58;         /* 5.33:1 with --on-green */
  --green-ink:     #0a6b4d;         /* 6.52:1 on #fff */
  --green-soft:    #3a9e7c;         /* 仅用于 hover 边框等非文字场景(与白底 3.02:1) */
  --green-bg:      color-mix(in srgb, var(--green) 10%, transparent);
  --green-bg-2:    color-mix(in srgb, var(--green) 16%, transparent);
  --on-green:      #ffffff;

  --amber:         #7d6e10;         /* 5.11:1 on #fff / 4.73:1 on --amber-bg */
  --amber-bg:      rgba(234,179,8,0.12);
  --amber-border:  rgba(234,179,8,0.28);
  --danger:        #d93025;
  --danger-bg:     rgba(217,48,37,0.08);

  /* 分隔线有两档:--border 是「结构边界」(卡片轮廓),--hair 更轻,用于
     「同一块内部的分节」(顶栏底边、卡内分区、FAQ 条目),避免细线抢注意力。 */
  --hair:          color-mix(in srgb, var(--text) 9%, transparent);

  --shadow-sm:     0 1px 2px rgba(11,20,26,0.05);
  --shadow:        0 10px 30px -14px rgba(11,20,26,0.16);
  --shadow-lg:     0 34px 70px -34px rgba(11,20,26,0.30);
  --shadow-green:  0 18px 44px -22px rgba(11,122,88,0.42);

  /* 顶栏动作托盘: 把语言/主题降成背景噪音,托盘里唯一"浮起"的白片才是 Install。
     亮暗两套必须保持「chip 比 tray 亮一档」,否则片会陷进托盘里。 */
  --tray-bg:       #f4f3f0;
  --tray-chip:     #ffffff;

  --radius:        16px;
  --radius-sm:     11px;
  --radius-lg:     20px;
  --maxw:          1200px;

  /* 字体自托管在 assets/fonts/(见文件顶部 @font-face),不向任何外部主机发请求 ——
     原因见那里的注释。文件缺失时整条栈静默回落系统字体,页面不会坏。
     字重只用真实档位(600/700/800):Plus Jakarta Sans 虽是可变字体(wght 200–800)、
     620 这类半档确实能渲染,但 swap 期间和字体加载失败时走的是系统栈,那里会被
     静默吸附到最近档 —— 两种状态都成立的值才是安全的值。 */
  --font-sans: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", "Segoe UI Mono", Menlo, Consolas, monospace;
}

/* ---- design tokens: night ----------------------------------------------
   夜间刻意不跟日间的暖中性走:深色下暖灰会发脏,这里维持 WhatsApp 自己的冷夜色。
   两处必须与日间反着来:
     --green    夜里回到品牌绿 #00A884(在 #0B141A 上 6.14:1,亮而不刺),
     --on-green 随之从白翻成近黑 —— 亮绿配白字只有 3.03:1,配深字是 5.49:1。
   两个 block 的内容必须逐字一致(@media 版给系统偏好,[data-theme] 版给手动切换);
   改一处就改另一处,下面 --hair/--faint 也同理。 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:            #0B141A;
    --bg-soft:       #111B21;
    --panel:         #111B21;
    --elevated:      #202C33;
    --border:        #222E35;
    --border-strong: #2A3942;
    --text:          #E9EDEF;
    --muted:         #8696A0;
    --faint:         #7d8d97;      /* 5.43:1 on --bg (原 #667781 只有 4.00:1) */
    --hair:          color-mix(in srgb, var(--text) 14%, transparent);

    --tray-bg:       #111B21;
    --tray-chip:     #202C33;

    --green:         #00A884;      /* 品牌绿活在夜里 */
    --on-green:      #06231b;      /* 5.49:1 —— 亮绿上必须用深字 */
    --green-ink:     #48d489;
    --green-soft:    #2fbf8f;      /* 非文字:hover 边框 */
    --green-bg:      color-mix(in srgb, var(--green) 16%, transparent);
    --green-bg-2:    color-mix(in srgb, var(--green) 24%, transparent);

    --amber:         #d6b84a;
    --amber-bg:      rgba(234,179,8,0.12);
    --danger:        #E86F6F;
    --danger-bg:     rgba(232,111,111,0.12);

    --shadow-sm:     0 1px 2px rgba(0,0,0,0.4);
    --shadow:        0 12px 34px -16px rgba(0,0,0,0.65);
    --shadow-lg:     0 34px 70px -30px rgba(0,0,0,0.75);
    --shadow-green:  0 18px 44px -20px rgba(0,0,0,0.70);
  }
}
:root[data-theme="dark"] {
  --bg:            #0B141A;
  --bg-soft:       #111B21;
  --panel:         #111B21;
  --elevated:      #202C33;
  --border:        #222E35;
  --border-strong: #2A3942;
  --text:          #E9EDEF;
  --muted:         #8696A0;
  --faint:         #7d8d97;
  --hair:          color-mix(in srgb, var(--text) 14%, transparent);
  --tray-bg:       #111B21;
  --tray-chip:     #202C33;
  --green:         #00A884;
  --on-green:      #06231b;
  --green-ink:     #48d489;
  --green-soft:    #2fbf8f;
  --green-bg:      color-mix(in srgb, var(--green) 16%, transparent);
  --green-bg-2:    color-mix(in srgb, var(--green) 24%, transparent);
  --amber:         #d6b84a;
  --amber-bg:      rgba(234,179,8,0.12);
  --danger:        #E86F6F;
  --danger-bg:     rgba(232,111,111,0.12);
  --shadow-sm:     0 1px 2px rgba(0,0,0,0.4);
  --shadow:        0 12px 34px -16px rgba(0,0,0,0.65);
  --shadow-lg:     0 34px 70px -30px rgba(0,0,0,0.75);
  --shadow-green:  0 18px 44px -20px rgba(0,0,0,0.70);
}

/* ---- reset / base ------------------------------------------------------ */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* 标题字重分两档,不是一刀切:大标题(h1/h2)在 2.5rem 以上要 800 才压得住,
   卡片标题(h3/h4)在 1rem 附近 800 会糊成一团,给 700。字距随字号收紧 ——
   越大的字需要越紧的字距,这是光学补偿,不是风格偏好。
   注意:这些负字距对阿拉伯文(连写体)有害,对 CJK 无意义,末尾 RTL/CJK 段已豁免。 */
h1, h2, h3, h4 { line-height: 1.15; margin: 0; }
h1, h2 { font-weight: 800; letter-spacing: -0.03em; }
h3, h4 { font-weight: 700; letter-spacing: -0.015em; }
p { margin: 0; }
a { color: var(--green-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
img, svg { max-width: 100%; }
strong, b { font-weight: 600; }
:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-radius: 4px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ---- layout primitives ------------------------------------------------- */
.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 20px; }
.section { padding: 96px 0; }
.section--soft { background: var(--bg-soft); }
/* 标题区比正文窄一档(620 < 760 的 prose 宽度):一行 ~70 字符是标题的可读上限,
   拉满容器宽会让人眼在行间失去落点。 */
.section-head { max-width: 620px; margin: 0 auto 52px; text-align: center; }
.section-head .eyebrow { justify-content: center; margin: 0 auto 14px; }
.section-head h2 { font-size: clamp(1.85rem, 3.4vw, 2.6rem); line-height: 1.06; }
.section-head p { margin-top: 14px; color: var(--muted); font-size: 1.09375rem; line-height: 1.6; text-wrap: pretty; }

/* eyebrow 是「标注」,不是第二个按钮:等宽 + 宽字距 + 全大写把它压成分类标签,
   否则它和下面的 h2 争夺同一个视觉入口。 */
.eyebrow {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--green-ink); background: var(--green-bg);
  padding: 6px 11px; border-radius: 999px;
}
.eyebrow .ico { width: 15px; height: 15px; }

/* ---- icons ------------------------------------------------------------- */
.ico { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
.ico-lg { width: 26px; height: 26px; }
.plan-feats li .yes, .ent .yes, .mock-tick { stroke: var(--green); }
.plan-feats li .no, .ent .no { stroke: var(--border-strong); }

/* ---- buttons ----------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: inherit; font-size: 0.9375rem; font-weight: 600; line-height: 1;
  padding: 12px 20px; border-radius: var(--radius-sm); border: 1px solid transparent;
  cursor: pointer; white-space: nowrap; transition: transform .06s ease, background .15s ease, border-color .15s ease, box-shadow .15s ease;
  text-decoration: none;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn .ico { width: 18px; height: 18px; }
/* 主 CTA 的绿有三处必须同时改,否则会互相打架(曾经的 bug:令牌调深了,而 :hover
   还是旧的浅绿 —— 悬停反而变亮,读起来像被禁用)。三处 = 底色 / 悬停底色 /
   扩散光晕,后两者从 --green 现算,不再写死字面量。 */
.btn-primary {
  background: var(--green); color: var(--on-green);
  box-shadow: 0 10px 22px -12px color-mix(in srgb, var(--green) 85%, transparent);
}
.btn-primary:hover {
  background: color-mix(in srgb, var(--green) 88%, #000);
  box-shadow: 0 12px 26px -12px color-mix(in srgb, var(--green) 95%, transparent);
}
.btn-ghost { background: var(--panel); color: var(--text); border-color: var(--border-strong); }
.btn-ghost:hover { background: var(--elevated); }
.btn-block { width: 100%; }
.btn-lg { padding: 15px 26px; font-size: 1rem; }
.btn-sm { padding: 8px 14px; font-size: 0.875rem; }
.btn[disabled] { opacity: .55; cursor: not-allowed; }
/* 忙碌态(billing.js setBusy):点击 → 建 Checkout Session → 跳支付页,中间那段看不见的
   往返要长在按钮上。旋钮做成伪元素,JS 只切一个类,按钮文案原样不动 —— 定价页有 8 个
   语种,一句 "Opening…" 就得多养 8 份译文,而旋钮不需要翻译。
   disabled 是为了真挡住连点,所以这里要把它那身「不可用」的灰压回去:用户该看到的是
   「在办了」,不是「坏了」。@keyframes spin / pulse 复用下面 status-card 与 .device 的。 */
.btn.is-busy::before {
  content: ""; flex: none; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent; opacity: .8;
  animation: spin .7s linear infinite;
}
.btn.is-busy[disabled] { opacity: 1; cursor: progress; }
/* 同一套样式也挂在 <a class="btn"> 上,而链接没有 disabled —— 忙的时候得另外挡住它,
   否则「已经在跳转了」的按钮还能再点一次。 */
a.btn.is-busy { pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .btn.is-busy::before { border-top-color: currentColor; animation: pulse 1.1s ease-in-out infinite; }
}
.btn-danger-ghost { background: transparent; color: var(--danger); border-color: var(--border-strong); }
.btn-danger-ghost:hover { background: var(--danger-bg); border-color: var(--danger); }

/* ---- header / nav ------------------------------------------------------ */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--hair);
}
/* Nav row spacing is deliberately tight: the row carries brand + 5 section links
   + 5 actions, and in the verbose locales (es/fr/pt-BR) it overflowed the
   container even before the install button existed. The budget is held by: link
   padding 9px, this 14px gap, the 4px tray gap, and the language switcher showing
   a code ("EN") rather than the full name. Measure all 8 locales before growing
   this row again — `documentElement.scrollWidth - clientWidth` per width/locale.
   ⚠ 字体算在这份预算里:Plus Jakarta Sans 比系统栈宽,换 --font-sans 必须重测。
   2026-07-28 实测(Jakarta 已生效,8 语种 × 1280/1200/1120/1000 共 32 组零溢出):
   最紧的是 **pt-BR @1120 仅剩 35px**,其次 es 37px、fr 77px —— 注意最坏情况已从
   French 变成 pt-BR(旧注释说 fr ~40px,那是系统字体年代的结论,勿再引用)。 */
.nav { display: flex; align-items: center; gap: 14px; height: 62px; }
/* 品牌标识 = 整合版「[W]anova」(标识规范 §06:图标顶替首字母)。规范给了三条硬对齐,
   这里逐条落地 —— 任何一条走样,标就会从字里"浮"出来:
     ① 图标高 = 大写字高(cap-height),不是行高也不是 x-height。Plus Jakarta Sans 实测
        sCapHeight 745 / upm 1000 = 0.745em;宽 = 高 × 裁切画布宽高比(50.5/33.5)= 1.1231em。
        用 em ⇒ 手机断点只要改 font-size,标自动跟着缩,不必再单独给尺寸。
     ② 底端压在字母基线上 → align-items:baseline(★不是 center;center 对的是行高中线,
        标会整体上浮、和 a 脱节),配合 inline-block 且内部 svg 为 block(无行盒时
        inline-block 的基线【就是】下外边缘)。
     ③ 与 a 之间按字母间距走,不留 logo 气口 → gap 必须为 0,靠 -0.04em 负边距收紧。 */
.brand { display: inline-flex; align-items: baseline; gap: 0; font-weight: 500; font-size: 1.0625rem; color: var(--text); }
.brand:hover { text-decoration: none; }
.brand .logo-lockup { display: inline-block; vertical-align: baseline; margin-inline-end: -0.04em; flex: none; }
.brand .logo-lockup svg { display: block; height: 0.745em; width: 1.1231em; }
/* 单独图标(auth 卡片):带四周留白的完整画布,故用 0 0 64 64 而非裁切版。 */
.logo { flex: none; }
.nav-links { display: flex; align-items: center; gap: 4px; margin-inline-start: 12px; }
.nav-links a { color: var(--muted); font-size: 0.9375rem; font-weight: 500; padding: 8px 9px; border-radius: 8px; }
.nav-links a:hover { color: var(--text); background: var(--elevated); text-decoration: none; }
/* Actions tray. Everything on the right sits in one soft container instead of a
   row of separately-outlined boxes: the language and theme controls drop their
   borders and become background, so the row reads as ONE cluster with two things
   sticking out of it — the white Install chip and the green CTA. That is what
   makes Install noticeable without a second saturated fill fighting the green
   (an all-ghost Install got ignored; a solid violet one out-shouted the money CTA).
   The tray also buys width back: -4px per gap, and the language switcher shows a
   code ("EN") instead of the full name. */
.nav-actions {
  display: flex; align-items: center; gap: 4px; margin-inline-start: auto;
  padding: 4px; border-radius: var(--radius); background: var(--tray-bg);
}
/* In the tray, everything is flat by default — only the chip and the CTA are raised. */
.nav-actions .icon-btn,
.nav-actions .lang-switch > summary { background: transparent; border-color: transparent; height: 34px; }
.nav-actions .icon-btn { width: 34px; }
.nav-actions .btn-ghost { background: transparent; border-color: transparent; }
.nav-actions .icon-btn:hover,
.nav-actions .btn-ghost:hover,
.nav-actions .lang-switch > summary:hover,
.nav-actions .lang-switch[open] > summary { background: var(--tray-chip); color: var(--text); }
/* Install (Chrome Web Store) — href injected by the generator from site.config.mjs.
   The one raised surface inside the tray: brand-violet label + icon on a chip that
   sits a shade above the tray in both themes (see --tray-chip). */
.nav-install {
  background: var(--tray-chip); color: var(--green-ink);
  border-color: var(--border); box-shadow: var(--shadow-sm); font-weight: 600;
}
.nav-install:hover { border-color: var(--green-soft); color: var(--green); }
.nav-install .ico { width: 17px; height: 17px; color: var(--green); }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--panel); color: var(--muted); cursor: pointer;
}
.icon-btn:hover { color: var(--text); background: var(--elevated); }
.theme-toggle .moon { display: none; }
:root[data-theme="dark"] .theme-toggle .sun,
.nav-toggle { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .moon { display: inline; }
}
:root[data-theme="dark"] .theme-toggle .moon { display: inline; }

/* ---- hero -------------------------------------------------------------- */
.hero { padding: 92px 0 60px; position: relative; overflow: hidden; }
.hero-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; }
.hero h1 { font-size: clamp(2.4rem, 5.6vw, 3.85rem); line-height: 1.0; letter-spacing: -0.038em; }
.hero h1 .grad {
  background: linear-gradient(100deg, var(--green-ink) 10%, var(--green) 120%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero .lede { margin-top: 22px; font-size: 1.1875rem; line-height: 1.6; color: var(--muted); max-width: 44ch; text-wrap: pretty; }
.hero-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }
.hero-note { margin-top: 20px; display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-size: 0.78125rem; letter-spacing: 0.01em; }
.hero-note .ico { width: 16px; height: 16px; color: var(--green); }
.trust-lock { color: var(--green); }

/* soft brand glow behind hero. 收敛过的:原来是一大团紫雾盖在标题上,压住了 h1;
   现在移出画布更远、只留边缘的一层晕。改 right/width 时必须同步末尾
   `[dir="rtl"] .hero::before` 的镜像值,否则阿拉伯语版的光斑位置不对称。 */
.hero::before {
  content: ""; position: absolute; top: -160px; right: -140px; width: 520px; height: 520px;
  background: radial-gradient(circle, var(--green-bg), transparent 68%);
  filter: blur(10px);
  pointer-events: none; z-index: 0;
}
.hero .container { position: relative; z-index: 1; }

/* hero product mock (inline SVG-ish card)
   卡中卡:外壳是一层浅托盘(--bg-soft),里面每一行是独立白卡。原来是「白卡 +
   紫色顶边」,那道 2px 紫边像贴在产品截图上的标签,把注意力吸到了边框上;
   现在靠整体抬升(--shadow-lg)和内圈发丝线做层次,顶边交回内容。 */
.mock {
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: 18px;
  box-shadow: var(--shadow-lg); overflow: hidden; padding: 6px;
}
.mock-bar { display: flex; align-items: center; gap: 7px; padding: 10px 12px 8px; background: transparent; }
.mock-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--border-strong); }
.mock-title { margin-inline-start: 8px; font-size: 0.78125rem; color: var(--faint); }
.mock-body { padding: 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 13px; }
.mock-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.mock-avatar { width: 34px; height: 34px; border-radius: 10px; background: var(--green-bg); color: var(--green-ink); display: inline-flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 700; flex: none; }
.mock-line { height: 8px; border-radius: 5px; background: var(--elevated); }
.mock-tick { margin-inline-start: auto; color: var(--green); }
.mock-progress { height: 8px; border-radius: 5px; background: var(--elevated); overflow: hidden; margin: 6px 0 14px; }
.mock-progress > i { display: block; height: 100%; width: 68%; background: var(--green); border-radius: 5px; }
.mock-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.mock-stat { background: var(--elevated); border-radius: var(--radius-sm); padding: 10px 12px; }
.mock-stat b { display: block; font-size: 1.25rem; font-weight: 700; }
.mock-stat span { font-size: 0.6875rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; }
.mock-stat.g b { color: var(--green); }
.mock-stat.i b { color: var(--green-ink); }

/* ---- logos / social proof strip ---------------------------------------
   一条静音带:发丝线 + 略宽的字距,让它像页面的注脚而不是第二个 feature 区。 */
.proof { padding: 22px 0; border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair); }
.proof-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px 34px; color: var(--faint); font-size: 0.84375rem; letter-spacing: 0.01em; }
.proof-row .item { display: inline-flex; align-items: center; gap: 8px; }
.proof-row .ico { width: 17px; height: 17px; color: var(--green); }

/* ---- feature grid ------------------------------------------------------ */
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.feature {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 24px; box-shadow: var(--shadow-sm); transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
.feature:hover { box-shadow: var(--shadow); transform: translateY(-2px); border-color: var(--border-strong); }
.feature .badge {
  width: 44px; height: 44px; border-radius: 13px; background: var(--green-bg);
  color: var(--green-ink); display: inline-flex; align-items: center; justify-content: center; margin-bottom: 14px;
}
.feature h3 { font-size: 1.0625rem; }
.feature p { margin-top: 8px; color: var(--muted); font-size: 0.9375rem; line-height: 1.6; }

.also { margin-top: 22px; display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.chip {
  display: inline-flex; align-items: center; gap: 8px; font-size: 0.875rem; font-weight: 500;
  color: var(--text); background: var(--panel); border: 1px solid var(--border);
  padding: 9px 15px; border-radius: 999px;
}
.chip .ico { width: 16px; height: 16px; color: var(--green-ink); }
/* chip 现在全部是链接（每个都有落地页）。给出可点的 affordance —— 之前一行 6 个里只有一个
   是 <a> 且样式与 <span> 完全相同，「哪个能点」只能靠试。 */
a.chip { text-decoration: none; transition: border-color .15s ease, background-color .15s ease, transform .15s ease; }
/* :hover 也要显式去下划线 —— 全局 `a:hover{text-decoration:underline}` 与 `a.chip` 同权重,
   靠源序取胜太脆;.nav-links a:hover 也是这么写的。 */
a.chip:hover { border-color: var(--green); background: var(--green-bg); transform: translateY(-1px); text-decoration: none; }
@media (prefers-reduced-motion: reduce) { a.chip:hover { transform: none; } }

/* ---- steps ------------------------------------------------------------- */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; counter-reset: step; }
.step { position: relative; padding: 24px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); }
.step .num {
  counter-increment: step; width: 34px; height: 34px; border-radius: 50%;
  background: var(--green); color: #fff; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 14px;
}
.step .num::before { content: counter(step); }
.step h3 { font-size: 1.0625rem; }
.step p { margin-top: 8px; color: var(--muted); font-size: 0.9375rem; line-height: 1.6; }

/* ---- off-device / trust band ------------------------------------------ */
.trust-band { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
/* 首页只有两张卡（功能页是三张）。塞进 3 列会空掉第三列，两张卡整体左偏 ~200px，
   在一个通篇居中的版块里格外扎眼。列数跟卡片数走 —— 同 .related.cols-N 的做法。 */
.trust-band.cols-2 { grid-template-columns: repeat(2, 1fr); }
.trust-card { padding: 24px; border-radius: var(--radius); border: 1px solid var(--border); background: var(--panel); }
.trust-card .badge { width: 40px; height: 40px; border-radius: 13px; background: var(--green-bg); color: var(--green-ink); display: inline-flex; align-items: center; justify-content: center; margin-bottom: 12px; }
.trust-card h3 { font-size: 1.0625rem; }
.trust-card p { margin-top: 7px; color: var(--muted); font-size: 0.9375rem; line-height: 1.6; }
.disclosure {
  margin-top: 22px; display: flex; align-items: center; gap: 12px; justify-content: center;
  background: var(--amber-bg); border: 1px solid var(--amber-border); border-radius: var(--radius-sm);
  padding: 12px 16px; color: var(--muted); font-size: 0.875rem;
}
.disclosure .ico { width: 18px; height: 18px; color: var(--amber); flex: none; }

/* ---- pricing ----------------------------------------------------------- */
.price-toggle { display: flex; justify-content: center; margin-bottom: 8px; }
.seg { display: inline-flex; background: var(--elevated); border-radius: 12px; padding: 4px; }
.seg button {
  font-family: inherit; font-size: 0.875rem; font-weight: 500; color: var(--muted);
  border: 0; background: transparent; padding: 8px 16px; border-radius: 9px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
}
.seg button.on { background: var(--panel); color: var(--text); box-shadow: var(--shadow-sm); }
.seg .save { font-size: 0.6875rem; color: var(--green-ink); background: var(--green-bg); padding: 2px 7px; border-radius: 999px; }
/* ★席位选择器(.seat-pick/.stepper)已随「按账号计价」删除(2026-08-08):没有数量可选了。 */

/* 三行信任承诺:与价格同屏,不放进法务附录。 */
.pledges {
  list-style: none; margin: 24px auto 0; padding: 0; max-width: 760px;
  display: grid; gap: 8px;
  /* 行内左对齐（勾号要竖着对齐），但框必须收缩到最长那行的宽度再 auto 居中。
     写死 760px 时最长一行只有 ~520px，右边空 240px —— 框居中了，看上去却整体偏左。 */
  width: fit-content;
}
.pledges li { display: flex; align-items: flex-start; gap: 9px; font-size: 0.875rem; color: var(--muted); }
.pledges .ico { width: 17px; height: 17px; flex: none; margin-top: 2px; color: var(--green); }
@media (max-width: 720px) { .seat-pick { gap: 8px; } }


/* ★三张卡等高(网格默认的 stretch,别再写回 align-items:start)。各档的行数【本来就不一样】
   —— 高档卡只列「本档才变的东西」,靠「Everything in <上一档>」把继承说掉,所以 Expert 的行
   永远比 Starter 少。按内容定高就会得到三个高低不一的盒子,而下面 .tier.pop 那 6px 抬升
   正是建立在等高之上的:三张卡本来就不齐时,把中间那张再抬高一点只会更乱。 */
.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.tier {
  position: relative; background: var(--panel); border: 1px solid var(--border-strong);
  border-radius: 18px; padding: 28px 24px;
  display: flex; flex-direction: column;
}
/* pop 卡实体抬起 6px:紫色光晕单独用不够,三张卡等高时「推荐」得在几何上也站出来。
   窄屏三卡竖排,抬升会变成一条突兀的缝,故只在多列布局下生效。 */
.tier.pop { border: 1.5px solid var(--green); box-shadow: var(--shadow-green); transform: translateY(-6px); }
@media (max-width: 720px) { .tier.pop { transform: none; } }
/* 身份态(billing.js applyIdentity):本页是唯一定价面,已订阅的人必须一眼认出自己那张卡。
   当前档用绿色(=「已拥有」,与 .ico.yes 同色系)区别于紫色的 pop(=「推荐买这张」)——
   两者会同时出现在 Professional 卡上,不能是同一个视觉信号。ribbon 刻意不改色也不改词:
   它说的是「最多人买这张」,那件事不因为你买了就不成立了。 */
.tier.tier-current { border: 1.5px solid var(--green); box-shadow: none; }
/* 「当前档 / 已包含」那两张卡的 CTA 变灰(禁用)。:not(.is-busy) 是必须的:忙碌态也靠
   disabled 挡连点,而它要看起来「在办了」而不是「不可用」—— 这条选择器与 .btn.is-busy
   [disabled] 同权重且排在后面,不排除就会把旋钮那颗按钮一起压灰。 */
.tier [data-checkout][disabled]:not(.is-busy) { opacity: .55; cursor: default; box-shadow: none; }
.price-id { text-align: center; font-size: 0.875rem; color: var(--muted); margin: -6px 0 18px; }
.price-id b { color: var(--text); font-weight: 600; }
.price-id a { color: var(--green-ink); }
/* 从扩展「订阅/升级」深链过来时(?plan=…)高亮对应档位 —— 让用户一眼看到该看哪张卡,
   但周期与席位仍由他自己在这一屏选(所以刻意不直接跳收银台)。 */
.tier.tier-focus { border: 1.5px solid var(--green); box-shadow: var(--shadow-green); }
.tier.tier-focus::after { content: ""; position: absolute; inset: -5px; border-radius: 18px;
  border: 2px solid var(--green); opacity: 0; animation: tier-ping 1.6s ease-out 2; pointer-events: none; }
@keyframes tier-ping { 0% { opacity: .55; transform: scale(.99); } 100% { opacity: 0; transform: scale(1.02); } }
@media (prefers-reduced-motion: reduce) { .tier.tier-focus::after { animation: none; } }
.ribbon {
  position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
  background: var(--green); color: #fff; font-size: 0.65rem; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 5px 13px; border-radius: 999px; white-space: nowrap;
}
.tier h3 { font-size: 1.125rem; letter-spacing: -0.01em; }
/* ★给 tagline 留两行的位置,而不是把文案写短。价格与 Subscribe 的纵向位置由它上面的
   内容高度决定,所以 tagline 一换行,那张卡的整个头部就往下掉一行 —— 而本站是 8 语生成的,
   同一句话在德语/阿拉伯语的行数与英语不同,「写短一点就不换行」在这里是靠不住的假设。 */
.tier .tagline { color: var(--faint); font-size: 0.875rem; margin-top: 4px; line-height: 1.45; min-height: 2.9em; }
.tier .price { display: flex; align-items: baseline; gap: 4px; margin: 16px 0 4px; }
/* 金额是这一屏的主角:2.75rem + 800 + 紧字距。单位/周期退成等宽小字,
   这样「$24.99」和「per number / mo」在视觉上是主句和脚注,而不是并列。 */
.tier .price .amt { font-size: 2.75rem; font-weight: 800; letter-spacing: -0.04em; }
.tier .price .per { color: var(--faint); font-size: 0.8125rem; }
.tier .annual-note { color: var(--green-ink); font-size: 0.75rem; min-height: 1.2em; }
.tier .btn { margin: 18px 0; }
/* flex:1 让功能列表吃掉等高之后多出来的空间,align-content:start 保证行本身不被拉开
   (grid 默认会把多余高度平分给每一行,读起来就是「行距忽然变大」)。 */
.plan-feats { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; flex: 1; align-content: start; }
.plan-feats li { display: flex; align-items: center; gap: 9px; font-size: 0.90625rem; color: var(--text); }
.plan-feats li .ico { width: 18px; height: 18px; }
.plan-feats li .yes { color: var(--green); }
.plan-feats li .no { color: var(--border-strong); }
.plan-feats li .ai { color: var(--green); }
.plan-feats li.off { color: var(--faint); }
.plan-feats li b { font-weight: 500; }
.plan-feats li.ai-head {
  margin-top: 7px; font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--green-ink); gap: 8px;
}
.plan-feats li.ai-head::after { content: ""; flex: 1; height: 1px; background: color-mix(in srgb, var(--green) 22%, transparent); }
.team-note { text-align: center; color: var(--muted); font-size: 0.875rem; margin: 6px 0 22px; }
.team-note b { color: var(--green-ink); font-weight: 600; }
.price-foot { text-align: center; color: var(--faint); font-size: 0.8125rem; margin-top: 26px; }
.price-foot .ico { color: var(--green); width: 14px; height: 14px; }

/* ---- FAQ --------------------------------------------------------------- */
.faq { max-width: 760px; margin: 0 auto; display: grid; gap: 10px; }
/* FAQ 条目刻意最安静:发丝线边框 + 12px 圆角。一屏 8 条卡片如果和 feature 卡
   同权重,整页的视觉重心会掉到页尾。 */
.faq details {
  background: var(--panel); border: 1px solid var(--hair); border-radius: 12px;
  padding: 2px 20px;
}
.faq details[open] { border-color: var(--border-strong); }
.faq summary {
  list-style: none; cursor: pointer; padding: 17px 0; font-weight: 600; font-size: 1.03125rem;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary .ico { color: var(--muted); transition: transform .2s ease; flex: none; }
.faq details[open] summary .ico { transform: rotate(180deg); }
.faq details > p { padding: 0 0 18px; color: var(--muted); font-size: 0.9375rem; line-height: 1.65; }

/* ---- CTA band ---------------------------------------------------------- */
.cta-band { text-align: center; }
/* 渐变收敛成近乎纯色:原来的 120deg 双色过渡自己就是一个视觉事件,和它上面的
   大标题抢戏。现在只留一点色温变化,主角交回文字。 */
.cta-inner {
  background: linear-gradient(150deg, var(--green) 0%, var(--green-ink) 92%);
  border-radius: 22px; padding: 62px 24px; color: #fff; box-shadow: var(--shadow-green);
}
.cta-inner h2 { font-size: clamp(1.6rem, 3vw, 2.2rem); letter-spacing: -0.03em; color: #fff; }
.cta-inner p { margin-top: 12px; color: rgba(255,255,255,0.85); font-size: 1.0625rem; }
.cta-inner .btn-primary { margin-top: 24px; }
.cta-inner .subnote { margin-top: 14px; font-size: 0.75rem; color: rgba(255,255,255,0.75); }

/* ---- footer ------------------------------------------------------------ */
.site-footer { border-top: 1px solid var(--hair); background: var(--bg-soft); padding: 48px 0 32px; }
.footer-grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 28px; }
.footer-brand .brand { margin-bottom: 12px; }
.footer-brand p { color: var(--muted); font-size: 0.9375rem; max-width: 30ch; }
.footer-col h4 { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--faint); margin-bottom: 12px; font-weight: 600; }
.footer-col a { display: block; color: var(--muted); font-size: 0.9375rem; padding: 5px 0; }
.footer-col a:hover { color: var(--text); }
.footer-bottom { margin-top: 36px; padding-top: 20px; border-top: 1px solid var(--hair); display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; align-items: center; color: var(--faint); font-size: 0.8125rem; }
.footer-disclaimer { max-width: 62ch; }

/* 应用页页脚（login/register/account/connect/billing-success）。
   刻意不是上面那个四列页脚：登录后的操作台不该再被塞一遍功能导航，这里只留
   「我们是谁 · 两条法务 · 怎么找到人」。那条 mailto 是 CREEM 账户审核的硬要求，
   来历见 site.config.mjs 的 SUPPORT_EMAIL。

   .app-page 把这几页改成 flex 列：内容不足一屏时页脚仍贴底，而不是浮在半空。
   auth-wrap 原本自带 min-height:100vh-64px（那时它下面什么都没有），现在交给 flex
   分配剩余高度 —— 否则「一屏高的卡片 + 页脚」必然溢出一小截、平白多出滚动条。 */
.app-page { display: flex; flex-direction: column; min-height: 100vh; }
.app-page > main { flex: 1 0 auto; }
.app-page .auth-wrap { min-height: 0; }
.app-footer { border-top: 1px solid var(--hair); background: var(--bg-soft); padding: 20px 0; margin-top: 48px; }
.app-footer .container { display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: center; justify-content: space-between; color: var(--faint); font-size: 0.8125rem; }
.app-footer-links { display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: center; }
.app-footer-links a { color: var(--muted); }
.app-footer-links a:hover { color: var(--text); }

/* ==========================================================================
   Legal pages (privacy / terms) — long-form prose
   ========================================================================== */
.legal { max-width: 760px; margin: 0 auto; }
.legal h1 { font-size: clamp(1.9rem, 4vw, 2.5rem); }
.legal .legal-meta { margin-top: 10px; color: var(--faint); font-size: 0.875rem; }
/* 分节线用发丝线:法务页有 20+ 个 h2,--border 那一档会把整页切成一堆横条。 */
.legal h2 {
  font-size: 1.3rem; margin: 44px 0 12px; padding-top: 26px;
  border-top: 1px solid var(--hair);
}
.legal h3 { font-size: 1rem; margin: 22px 0 8px; }
.legal p, .legal li { color: var(--muted); font-size: 0.9375rem; line-height: 1.7; text-wrap: pretty; }
.legal p + p { margin-top: 12px; }
.legal ul { margin: 12px 0; padding-inline-start: 22px; }
.legal li { margin-bottom: 7px; }
.legal li::marker { color: var(--green); }
.legal strong, .legal b { color: var(--text); font-weight: 600; }
.legal a { text-decoration: underline; }
.legal address { font-style: normal; }

.legal-tldr {
  margin-top: 26px; padding: 20px 22px; border-radius: var(--radius);
  background: var(--green-bg); border: 1px solid color-mix(in srgb, var(--green) 24%, transparent);
}
.legal-tldr h2 { margin: 0 0 10px; padding: 0; border: 0; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--green-ink); }
.legal-tldr ul { margin: 0; padding-inline-start: 20px; }
.legal-tldr li { color: var(--text); }

.legal-warn {
  margin: 20px 0; padding: 16px 18px; border-radius: var(--radius-sm);
  background: var(--amber-bg); border: 1px solid var(--amber-border);
}
.legal-warn p, .legal-warn li { color: var(--text); }
.legal-warn > :first-child { margin-top: 0; }

.legal-table-wrap { overflow-x: auto; margin: 16px 0; }
.legal table { width: 100%; border-collapse: collapse; font-size: 0.875rem; min-width: 480px; }
.legal th, .legal td { text-align: start; padding: 10px 12px; border-bottom: 1px solid var(--border); vertical-align: top; }
.legal th { color: var(--text); font-weight: 500; background: var(--bg-soft); white-space: nowrap; }
.legal td { color: var(--muted); }

/* Cross-index of the five legal documents (partials/legal-nav.html). */
.legal-nav { display: flex; flex-wrap: wrap; gap: 8px; margin: 22px 0 6px; }
.legal-nav a {
  padding: 6px 12px; border-radius: 999px; text-decoration: none;
  border: 1px solid var(--border-strong); background: var(--panel);
  color: var(--muted); font-size: 0.8125rem;
}
.legal-nav a:hover { border-color: var(--green); color: var(--green-ink); }
.legal-nav a[aria-current="page"] {
  background: var(--green-bg); border-color: color-mix(in srgb, var(--green) 34%, transparent);
  color: var(--green-ink); font-weight: 500;
}

/* Placeholders that only a registered company / lawyer can fill (entity name,
   jurisdiction, EU representative…). Deliberately loud: a legal page must never
   go live with one of these still in it, and amber-on-page is the cheapest
   possible guard.
   ⚠ 2026-08-06 起本类【在产物里为 0 处】,但那不等于「都填完了」—— 是那批事实被
   【整体拿掉】而非填上(法律主体未定,拍板先上线)。所以**别再把 grep legal-fill
   当作待办清单**,它现在恒为空;真实状态在 docs/gdpr-compliance.md §5。
   本样式保留:法律主体一旦定下来,那几处要加回来,届时还要靠它刺眼。
   ⚠ 这里的琥珀是安全机制,不是配色:2026-07 那版视觉打磨曾提议把 --amber 整组换成
   暖奶油色(对比度 4.31→3.67、虚线边框从黄变米白),等于把绊网调安静了 —— 已否。
   --amber 只允许朝「更清晰」的方向动(现为 5.11:1)。 */
.legal .legal-fill {
  background: var(--amber-bg); border: 1px dashed var(--amber-border);
  border-radius: 6px; padding: 0 6px; color: var(--amber);
  font-weight: 600; font-style: normal;
}

/* ==========================================================================
   Auth pages (login / register) + account dashboard
   ========================================================================== */
.auth-wrap { min-height: calc(100vh - 64px); display: grid; place-items: center; padding: 40px 20px; }
.auth-card {
  width: 100%; max-width: 420px; background: var(--panel); border: 1px solid var(--border);
  border-top: 2px solid var(--green); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 32px 30px;
}
/* 卡内品牌块 = 与顶栏同一套整合版(规范:两套组合别混用在同一个页面 —— 这两页的顶栏就是整合版)。
   1.5rem 略小于下方 h1 的 1.55rem:它是"这是谁家的表单",不该和标题抢主角。
   高度由 .brand .logo-lockup 的 em 规则自动跟随,这里只管字号与间距。 */
.auth-card .auth-brand { font-size: 1.5rem; margin-bottom: 16px; }
.auth-card h1 { font-size: 1.55rem; }
.auth-card .sub { margin-top: 6px; color: var(--muted); font-size: 0.9375rem; margin-bottom: 22px; }
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 0.8125rem; font-weight: 500; margin-bottom: 6px; color: var(--text); }
.field input {
  width: 100%; font-family: inherit; font-size: 0.9375rem; color: var(--text);
  background: var(--elevated); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 11px 13px;
}
.field input::placeholder { color: var(--faint); }
.field input:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px var(--green-bg); }
.field .hint { margin-top: 6px; font-size: 0.75rem; color: var(--faint); }
.form-note { margin-top: 18px; text-align: center; font-size: 0.875rem; color: var(--muted); }
/* Sits directly under the submit button: this link pair is what makes "creating
   an account = accepting the terms" (terms.html §1) actually true. */
.legal-consent { margin-top: 14px; font-size: 0.75rem; color: var(--faint); line-height: 1.5; }
.alert {
  display: none; align-items: center; gap: 9px; padding: 11px 14px; border-radius: var(--radius-sm);
  font-size: 0.875rem; margin-bottom: 18px;
}
.alert.show { display: flex; }
.alert-error { background: var(--danger-bg); border: 1px solid var(--danger); color: var(--danger); }
.alert-info { background: var(--green-bg); border: 1px solid var(--green); color: var(--green-ink); }
.alert .ico { width: 17px; height: 17px; flex: none; }
.trust-inline { margin-top: 20px; display: flex; align-items: center; justify-content: center; gap: 8px; color: var(--faint); font-size: 0.8125rem; }
.trust-inline .ico { color: var(--green); width: 14px; height: 14px; }

/* Google sign-in (progressive enhancement; hidden until GIS renders) */
.g-auth[hidden] { display: none; }
.g-signin { display: flex; justify-content: center; min-height: 44px; }
.auth-or { display: flex; align-items: center; gap: 12px; color: var(--faint); font-size: 0.8125rem; margin: 16px 0; }
.auth-or::before, .auth-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* Passwordless sign-in (auth.js). The alternate way in and the "…instead" link
   swap places with the password form, so both need the hidden attribute to win
   over their own display rule. */
.auth-alt[hidden], form[data-auth="code"][hidden], .form-note[hidden] { display: none; }
.auth-alt .btn { display: inline-flex; align-items: center; justify-content: center; gap: 9px; }
.auth-alt .btn .ico { width: 17px; height: 17px; }
/* The code itself: wide tracking so six digits read as six digits — this field
   is transcribed character by character from another screen. */
.code-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.375rem; letter-spacing: 0.42em; text-align: center; text-indent: 0.42em;
  padding-top: 13px; padding-bottom: 13px;
}
.code-field .hint { line-height: 1.7; }
/* "Forgot your password?" — sits under its field, aligned to the far edge where
   the eye lands after typing. */
.field-aside { text-align: right; }
/* A button that reads as a link: these are actions (resend / change address),
   not navigation, so they must not be anchors. */
.link-btn {
  background: none; border: 0; padding: 0; font: inherit; color: var(--green);
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.link-btn:hover { color: var(--green-ink); }
.link-btn:disabled { color: var(--faint); text-decoration: none; cursor: default; }

/* account dashboard */
.account { padding: 40px 0 72px; }
/* Erasure form (account.js): only appears after an explicit click, and asks for a
   typed confirmation — a destructive, irreversible action shouldn't be one tap away. */
.delete-form { margin-top: 14px; }
.delete-form[hidden] { display: none; }
.delete-form .field { margin-bottom: 12px; }
.delete-form .alert { margin-bottom: 12px; }
.account-head { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; justify-content: space-between; margin-bottom: 26px; }
.account-head h1 { font-size: 1.8rem; }
.account-head .who { color: var(--muted); font-size: 0.9375rem; margin-top: 4px; }
.dash-grid { display: grid; grid-template-columns: 1.3fr 1fr; gap: 20px; align-items: start; }
.card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 24px; box-shadow: var(--shadow-sm);
}
.card + .card { margin-top: 20px; }
.card h2 { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--faint); font-weight: 600; margin-bottom: 14px; }
.plan-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.plan-name { font-size: 1.65rem; font-weight: 800; letter-spacing: -0.02em; text-transform: capitalize; }
.pill {
  display: inline-flex; align-items: center; gap: 6px; font-size: 0.75rem; font-weight: 500;
  padding: 4px 11px; border-radius: 999px;
}
.pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill-trial { color: var(--green-ink); background: var(--green-bg); }
.pill-active { color: var(--green-ink); background: var(--green-bg); }
.pill-warn { color: var(--amber); background: var(--amber-bg); }
.pill-none { color: var(--danger); background: var(--danger-bg); }
.plan-meta { margin-top: 14px; color: var(--muted); font-size: 0.9375rem; }
.plan-meta b { color: var(--text); font-weight: 500; }
.ent-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 8px; }
.ent {
  display: flex; align-items: center; gap: 9px; font-size: 0.9375rem;
  padding: 9px 12px; background: var(--elevated); border-radius: var(--radius-sm);
}
.ent .ico { width: 17px; height: 17px; flex: none; }
.ent .yes { color: var(--green); }
.ent .no { color: var(--border-strong); }
.ent.off { color: var(--faint); }
.ent b { font-weight: 500; }
.seat-bar { height: 8px; border-radius: 5px; background: var(--elevated); overflow: hidden; margin: 6px 0 4px; }
.seat-bar > i { display: block; height: 100%; background: var(--green); border-radius: 5px; }
.device { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--border); }
.device:first-of-type { border-top: 0; }
.device .dico { width: 36px; height: 36px; border-radius: 10px; background: var(--elevated); color: var(--muted); display: inline-flex; align-items: center; justify-content: center; flex: none; }
.device .dmeta { min-width: 0; }
.device .dmeta b { font-weight: 500; font-size: 0.9375rem; }
.device .dmeta span { display: block; color: var(--faint); font-size: 0.8125rem; font-family: var(--font-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.device .btn { margin-inline-start: auto; }
/* 释放席位控件(account.js releaseControl):常态一个按钮,点开变「问句 + 取消 + 释放」。
   问句和按钮在同一行会把窄屏挤爆,故 wrap:true 并允许问句独占一行。 */
.device .drelease { margin-inline-start: auto; display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }
.device .drelease .btn { margin-inline-start: 0; }
.device .drelease .dask { color: var(--muted); font-size: 0.8125rem; flex: 1 1 100%; text-align: end; }
.empty { color: var(--faint); font-size: 0.9375rem; padding: 10px 0; }
.skeleton { color: transparent; background: var(--elevated); border-radius: 6px; animation: pulse 1.3s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .5; } }
.plan-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }

/* account · upgrade panel (in-place plan change; see account.js upgradePanel) */
.upgrade-box { margin-top: 14px; padding: 14px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--elevated); }
.upgrade-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.upgrade-lbl { color: var(--muted); font-size: 0.875rem; }
.upgrade-sel { font-family: inherit; font-size: 0.875rem; color: var(--text);
  background: var(--panel); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 7px 9px; }
.upgrade-sel:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px var(--green-bg); }
.upgrade-box .meter-note { margin-top: 10px; }

/* account · entitlements card (dashboard IA: AI meters / included chips) */
.sec-head { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.12em; font-weight: 600;
  color: var(--faint); margin: 20px 0 10px; }
.sec-head:first-child { margin-top: 4px; }
.ai-meter { margin-bottom: 13px; }
.ai-meter:last-child { margin-bottom: 0; }
.ai-meter-off { opacity: 0.5; }
.ai-meter-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  font-size: 0.9375rem; margin-bottom: 6px; }
.ai-meter-val { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ai-meter-val-full { color: var(--amber); font-weight: 500; }
.ai-meter-track { height: 7px; border-radius: 5px; background: var(--elevated); overflow: hidden; }
.ai-meter-track.ai-meter-flat { opacity: 0.5; }
.ai-meter-track > i { display: block; height: 100%; border-radius: 5px; background: var(--green); }
.ai-meter-track > i.ai-meter-fill-full { background: var(--amber); }
.meter-note { margin-top: 8px; color: var(--faint); font-size: 0.8125rem; }
/* 消耗构成(credit 池化之后,「是什么花掉的」没有别的地方可以回答)。
   标签靠左、数字靠右,**没有条** —— 理由见 account.js 的 breakdownRow。 */
.bd-row { display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  font-size: 0.875rem; margin-bottom: 8px; }
.bd-label { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bd-val { flex: none; font-variant-numeric: tabular-nums; }
/* 加购 credits:挂在余额条底下。平常不抢戏 —— 它是出口,不是号召;真的快没了时
   按钮才由 .btn-ghost 换成 .btn-primary(分量由 account.js 的 runningLow 决定)。 */
.topup-box { margin-top: 14px; }
.topup-lead { color: var(--muted); font-size: 0.875rem; margin: 0 0 8px; }
.topup-row { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
/* 分段选择:三个数并排可比,而不是三个重量相同的按钮各写一遍「Buy N credits」。 */
.topup-seg { display: inline-flex; background: var(--elevated); border-radius: 10px; padding: 3px; gap: 2px; }
.topup-opt { font-family: inherit; font-size: 0.875rem; font-weight: 600; color: var(--muted);
  background: transparent; border: 0; border-radius: 8px; padding: 7px 16px; cursor: pointer;
  font-variant-numeric: tabular-nums; }
.topup-opt:hover { color: var(--text); }
.topup-opt.on { background: var(--panel); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.topup-fine { color: var(--faint); font-size: 0.75rem; line-height: 1.55; margin: 8px 0 0; max-width: 62ch; }
.feat-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.feat-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 0.8125rem;
  padding: 5px 11px; border-radius: 999px; border: 1px solid var(--green); color: var(--green-ink); }
.feat-chip .ico { width: 13px; height: 13px; }
.upg-hint { margin-top: 12px; color: var(--muted); font-size: 0.875rem; line-height: 1.5; }
.see-all { display: inline-block; margin-top: 14px; color: var(--green-ink); font-size: 0.875rem; font-weight: 500; }
.see-all:hover { text-decoration: underline; }

/* ---- toast ------------------------------------------------------------- */
.wn-toast {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 12px);
  background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: 12px 18px;
  font-size: 0.9375rem; z-index: 100; opacity: 0; max-width: 90vw;
  transition: opacity .25s ease, transform .25s ease;
}
.wn-toast.show { opacity: 1; transform: translate(-50%, 0); }
.wn-toast-error { border-color: var(--danger); color: var(--danger); }

/* ---- billing success --------------------------------------------------- */
.status-card { text-align: center; }
.status-card .spinner {
  width: 40px; height: 40px; margin: 0 auto 18px; border-radius: 50%;
  border: 3px solid var(--elevated); border-top-color: var(--green); animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.status-card .ok-badge {
  width: 56px; height: 56px; margin: 0 auto 18px; border-radius: 50%;
  background: var(--green-bg); color: var(--green); display: flex; align-items: center; justify-content: center;
}
.status-card .ok-badge .ico { width: 30px; height: 30px; }
.status-card h1 { font-size: 1.6rem; }
.status-card p { margin-top: 10px; color: var(--muted); }
.status-card .btn { margin-top: 22px; }

/* ==========================================================================
   Product demos
   Everything here is CSS-only and loops. The trick that keeps a multi-part
   scene in sync: every animated element in one scene shares the SAME duration
   and iteration-count, and `animation-delay` is used purely as a timeline
   cursor. Delays shift the phase once and then hold it forever, so the parts
   never drift apart. Keyframe percentages below are therefore "seconds ÷ the
   scene's duration" — e.g. in the 12s hero, 25% = 3s.
   The hero scene autoplays (it's above the fold). The co-pilot scenes start
   paused and the IntersectionObserver in index.html flips `.run` when they
   scroll into view, so five loops aren't burning CPU off-screen.
   ========================================================================== */

/* ---- hero scene: follow-up radar → AI draft → you press send (12s) ------ */
.demo-hero .mock-body { padding: 18px; }

.radar-head {
  display: flex; align-items: center; gap: 7px; margin-bottom: 12px;
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--faint);
}
.radar-count {
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0;
  color: var(--green-ink); background: var(--green-bg);
  padding: 1px 7px; border-radius: 999px;
}

/* 每一行是独立白卡(不是通栏列表):hero 里这块要在缩略尺寸下一眼看出「三个待跟进的
   人」,卡片边界比行距更能分割。注意 margin 归零 —— 旧版用 margin:0 -8px 让高亮
   出血到卡片边缘,现在行本身就是卡,出血会顶破 .mock-body 的内圈。 */
.rrow {
  display: flex; align-items: center; gap: 10px;
  padding: 12px; margin: 0 0 9px; border-radius: 11px;
  background: var(--panel); border: 1px solid var(--border);
  animation: rrowIn 12s ease-out infinite both;
}
.rrow:nth-child(2) { animation-delay: .2s; }
.rrow:nth-child(3) { animation-delay: .6s; }
.rrow:nth-child(4) { animation-delay: 1s; }
/* the row the co-pilot picks: fades in on its own delay, highlights on the
   scene's clock — hence two animations with two different delays. */
.rrow.sel {
  animation-name: rrowIn, rrowSel;
  animation-delay: .2s, 0s;
  border-color: color-mix(in srgb, var(--green) 26%, transparent);
}
.rmeta { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.rmeta b { font-weight: 600; font-size: 0.875rem; }
.rmeta span { font-size: 0.78125rem; color: var(--muted); }
.rpill {
  margin-inline-start: auto; flex: none; font-size: 0.65rem; font-weight: 500;
  padding: 3px 8px; border-radius: 6px; background: var(--elevated); color: var(--muted);
}
.rpill.warn { background: var(--amber-bg); color: var(--amber); }
.rpill.ind { background: var(--green-bg); color: var(--green-ink); }

@keyframes rrowIn {
  0%        { opacity: 0; transform: translateY(6px); }
  6%, 80%   { opacity: 1; transform: none; }
  88%, 100% { opacity: 0; transform: translateY(-4px); }
}
/* 起止帧必须是 --panel 而不是 transparent:.rrow 现在自带白卡底,
   动到 transparent 会让这一行在高亮前后「漏出」下面的托盘色。 */
@keyframes rrowSel {                    /* 2.0s → 9.6s */
  0%, 17%   { background: var(--panel); }
  21%, 80%  { background: var(--green-bg); }
  88%, 100% { background: var(--panel); }
}

/* 起草块走绿色一系,不再是紫色:紫 = 产品/AI 的颜色,绿 = 「这条可以发了」。
   这一格是整个 hero 演示的落点(下一步就是按 Send),它该和 CTA 同色系。 */
.draft {
  margin-top: 14px; padding: 13px; border-radius: 12px;
  background: var(--green-bg); border: 1px solid color-mix(in srgb, var(--green) 22%, transparent);
  animation: draftIn 12s ease-out infinite both;
}
.draft-head {
  display: flex; align-items: center; gap: 7px; margin-bottom: 8px;
  font-size: 0.6875rem; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--green-ink);
}
.draft-head .ico { width: 15px; height: 15px; }
.draft-body { font-size: 0.90625rem; line-height: 1.55; }
/* one word per span → a token-stream reveal, no JS typewriter */
.draft-body span {
  animation: wordIn 12s ease-out infinite both;
  animation-delay: calc(var(--i) * .085s);
}
.draft-foot { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.draft-note { display: inline-flex; align-items: center; gap: 5px; font-size: 0.6875rem; color: var(--green-ink); }
.draft-note .ico { width: 13px; height: 13px; }
.draft-send {
  margin-inline-start: auto; flex: none; background: var(--green); color: var(--on-green);
  font-size: 0.75rem; font-weight: 600; padding: 6px 15px; border-radius: 8px;
  animation: sendPulse 12s ease-out infinite both;
}

@keyframes draftIn {                    /* 2.5s → 3.2s in */
  0%, 21%   { opacity: 0; transform: translateY(6px) scale(.98); }
  27%, 80%  { opacity: 1; transform: none; }
  88%, 100% { opacity: 0; }
}
@keyframes wordIn {                     /* 3.4s onward, +85ms per word */
  0%, 28%   { opacity: 0; }
  31%, 80%  { opacity: 1; }
  88%, 100% { opacity: 0; }
}
/* 脉冲色从 --green 现算,不写死:曾经这里是 rgba(0,168,132,…) 的字面量,
   令牌一改绿色,光圈就和按钮不是同一个绿了(而且没人会发现)。 */
@keyframes sendPulse {                  /* 6.0s — "it's your turn" */
  0%, 50%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 50%, transparent); }
  58%       { box-shadow: 0 0 0 9px color-mix(in srgb, var(--green) 0%, transparent); }
  100%      { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}

/* ---- demo · a broadcast running, paced (10s) — feature landing pages ----
   The counters are real CSS: @property makes --n animatable as an integer, and
   counter() renders it. No JS ticking a number. */
@property --n { syntax: "<integer>"; initial-value: 0; inherits: false; }

.demo-bulk .mock-progress > i {
  width: 100%; transform-origin: left;
  animation: bProg 10s ease-out infinite both;
}
.demo-bulk .cnt { font-variant-numeric: tabular-nums; }
.demo-bulk .cnt::after { content: counter(n); }
.demo-bulk .cnt-pct::after { content: counter(n) "%"; }
.demo-bulk .cnt-sent  { counter-reset: n var(--n); animation: bSent  10s linear infinite both; }
.demo-bulk .cnt-queue { counter-reset: n var(--n); animation: bQueue 10s linear infinite both; }
.demo-bulk .cnt-pct   { counter-reset: n var(--n); animation: bPct   10s linear infinite both; }

.demo-bulk .brow { display: flex; align-items: center; gap: 10px; padding: 9px 0; animation: dFade 10s ease-out infinite both; }
.demo-bulk .brow:nth-child(3) { animation-delay: .4s; }
.demo-bulk .brow:nth-child(4) { animation-delay: 1.1s; }
.demo-bulk .brow:nth-child(5) { animation-delay: 1.8s; }
.demo-bulk .brow:nth-child(6) { animation-delay: 2.5s; }
.demo-bulk .brow .mock-tick { animation: dFade 10s ease-out infinite both; }
.demo-bulk .brow:nth-child(3) .mock-tick { animation-delay: 1.4s; }
.demo-bulk .brow:nth-child(4) .mock-tick { animation-delay: 2.1s; }
.demo-bulk .brow:nth-child(5) .mock-tick { animation-delay: 2.8s; }
.bwait {
  margin-inline-start: auto; flex: none; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--green);
  animation: spin .9s linear infinite;
}
.bnote { margin-top: 14px; font-size: 0.75rem; color: var(--faint); text-align: center; }

@keyframes bProg  { 0% { transform: scaleX(0); } 70%, 100% { transform: scaleX(.68); } }
@keyframes bSent  { 0% { --n: 0; }   70%, 100% { --n: 342; } }
@keyframes bQueue { 0% { --n: 500; } 70%, 100% { --n: 158; } }
@keyframes bPct   { 0% { --n: 0; }   70%, 100% { --n: 68; } }

/* ---- feature landing pages -------------------------------------------- */
.crumbs { display: flex; align-items: center; gap: 8px; font-size: 0.8125rem; color: var(--faint); margin-bottom: 22px; }
.crumbs a { color: var(--muted); }

.trust-card .badge.warn { background: var(--amber-bg); color: var(--amber); }

.plan-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; max-width: 760px; margin: 0 auto; }
.pstrip { text-align: center; padding: 18px; border-radius: var(--radius); background: var(--panel); border: 1px solid var(--border); }
.pstrip.pop { border-color: var(--green); box-shadow: var(--shadow-green); }
.pstrip b { display: block; font-weight: 500; }
.pstrip span { display: block; font-size: 1.4rem; font-weight: 500; margin: 6px 0 4px; }
.pstrip em { font-style: normal; font-size: 0.8125rem; color: var(--faint); }

.also-cta { text-align: center; margin-top: 26px; }

.related { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
/* Features hub（/features/）的分组大小不一 —— 按「使用时刻」分组，一组是 4 个功能，
   另一组只有 1 个。固定 3 列会让 4 个的那组掉一张到下一行、只占 1/3 宽，而 1 个的那组
   孤零零挂在左边、右侧空 2/3。所以列数跟着卡片数走。
   单卡片不铺满整行：1160px 宽只装两行文字会显得空，限宽居中反而像个重点条目。 */
.related.cols-4 { grid-template-columns: repeat(4, 1fr); }
.related.cols-2 { grid-template-columns: repeat(2, 1fr); }
.related.cols-1 { grid-template-columns: minmax(0, 720px); justify-content: center; }
.rel {
  display: block; padding: 20px; border-radius: var(--radius); color: var(--text);
  background: var(--panel); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
.rel:hover { text-decoration: none; box-shadow: var(--shadow); transform: translateY(-2px); border-color: var(--border-strong); }
.rel h3 { font-size: 1rem; color: var(--green-ink); }
.rel p { margin-top: 7px; color: var(--muted); font-size: 0.875rem; }

/* ---- pain section ------------------------------------------------------ */
.pains { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.pain {
  position: relative; padding: 28px 22px 22px;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
}
/* 引号压进背景:它是装饰,原来 .3 的紫色引号比它标注的那句抱怨还显眼。 */
.pain-q {
  position: absolute; top: 4px; left: 15px; font-family: Georgia, "Times New Roman", serif;
  font-size: 3.2rem; line-height: 1; color: var(--green); opacity: .16;
}
.pain p { position: relative; font-size: 0.96875rem; line-height: 1.55; text-wrap: pretty; }

/* ---- co-pilot grid ----------------------------------------------------- */
.cop-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 20px; }
.cop {
  grid-column: span 2; display: flex; flex-direction: column; overflow: hidden;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}
.cop:hover { box-shadow: var(--shadow); transform: translateY(-2px); border-color: var(--border-strong); }
@media (prefers-reduced-motion: reduce) { .cop:hover { transform: none; } }
.cop.wide { grid-column: span 3; }
.cop-text { padding: 20px 22px 22px; }
.cop-text h3 { display: flex; align-items: center; gap: 8px; font-size: 1.09375rem; }
.cop-text h3 .ico { width: 18px; height: 18px; color: var(--green-ink); }
.cop-text p { margin-top: 9px; color: var(--muted); font-size: 0.9375rem; line-height: 1.6; text-wrap: pretty; }
.cop-tag {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 15px;
  font-size: 0.65rem; letter-spacing: 0.09em; text-transform: uppercase; color: var(--faint);
  background: var(--elevated); border-radius: 999px; padding: 5px 11px;
}
.cop-tag .ico { width: 13px; height: 13px; }
.cop-tag.hi { color: var(--green-ink); background: var(--green-bg); }

/* ---- demo stage + shared parts ----------------------------------------- */
/* flex:1 → the stage soaks up whatever height the grid's equal-height rows hand
   the card, instead of leaving dead space under the text. Content stays centred,
   so a short demo next to a tall one still reads as a screen, not a gap. */
.cop-demo {
  flex: 1;
  display: flex; flex-direction: column; justify-content: center; gap: 8px;
  min-height: 186px; padding: 20px; overflow: hidden;
  background: var(--bg-soft); border-bottom: 1px solid var(--hair);
}
/* At night --bg-soft and --panel are the same ink, which would dissolve the
   stage into the card. --bg is a shade under the card there — and it happens to
   land on WhatsApp's own dark-mode look: deep floor, bubbles lifted off it. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cop-demo { background: var(--bg); }
}
:root[data-theme="dark"] .cop-demo { background: var(--bg); }
/* Hold every scene until demos.js adds .run (i.e. until it's on screen).
   !important is load-bearing, not laziness: each scene rule below uses the
   `animation` SHORTHAND, which resets animation-play-state to running, and
   `[data-demo="x"] .y` (0,2,0) outranks a plain `.cop-demo *` (0,1,0). Without
   !important the pause silently never happens and every loop burns CPU
   off-screen. Scoping to :not(.run) means running needs no rule at all. */
.cop-demo:not(.run) * { animation-play-state: paused !important; }

.d-head { display: flex; align-items: center; gap: 7px; font-size: 0.75rem; font-weight: 500; }
.d-head b {
  font-size: 0.625rem; font-weight: 600; color: var(--green-ink);
  background: var(--green-bg); padding: 1px 6px; border-radius: 999px;
}
.d-row { display: flex; align-items: center; gap: 8px; }
.d-av {
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  background: var(--green-bg); color: var(--green-ink);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.5625rem; font-weight: 600;
}
.d-nm { font-size: 0.8125rem; font-weight: 500; }
.d-pill {
  margin-inline-start: auto; flex: none; font-size: 0.625rem; font-weight: 500;
  padding: 2px 7px; border-radius: 999px; background: var(--elevated); color: var(--muted);
}
.d-pill.warn { background: var(--amber-bg); color: var(--amber); }
.d-pill.ind { background: var(--green-bg); color: var(--green-ink); }
.d-bub { max-width: 88%; padding: 8px 11px; border-radius: 11px; font-size: 0.8125rem; line-height: 1.45; }
.d-bub.in {
  align-self: flex-start; background: var(--panel); border: 1px solid var(--border);
  border-bottom-left-radius: 3px;
}
/* 出站气泡用 --on-green 而不是写死 #fff:夜间 --green 回到亮品牌绿,白字只有
   3.03:1,--on-green 会跟着翻成近黑。 */
.d-bub.out { align-self: flex-end; background: var(--green); color: var(--on-green); border-bottom-right-radius: 3px; }

@keyframes dFade {
  0%        { opacity: 0; }
  8%, 82%   { opacity: 1; }
  92%, 100% { opacity: 0; }
}
@keyframes dRise {
  0%        { opacity: 0; transform: translateY(6px); }
  10%, 82%  { opacity: 1; transform: none; }
  92%, 100% { opacity: 0; }
}

/* ---- demo 1 · follow-up radar (7s) ------------------------------------- */
[data-demo="radar"] .d-head { animation: dFade 7s ease-out infinite both; }
[data-demo="radar"] .d-row { animation: dRise 7s ease-out infinite both; }
[data-demo="radar"] .d-row:nth-child(2) { animation-delay: .3s; }
[data-demo="radar"] .d-row:nth-child(3) { animation-delay: .7s; }
[data-demo="radar"] .d-row:nth-child(4) { animation-delay: 1.1s; }

/* ---- demo 3 · AI draft you approve (8s) -------------------------------- */
.d-draft {
  position: relative; padding: 10px 11px 10px 32px; border-radius: 11px;
  background: var(--green-bg); border: 1px dashed color-mix(in srgb, var(--green) 42%, transparent);
  font-size: 0.8125rem; line-height: 1.45;
}
.d-sparkle { position: absolute; left: 10px; top: 10px; color: var(--green-ink); }
.d-sparkle .ico { width: 14px; height: 14px; }
.d-sendrow { display: flex; align-items: center; gap: 8px; }
.d-hint { font-size: 0.6875rem; color: var(--green-ink); }
.d-btn {
  margin-inline-start: auto; flex: none; background: var(--green); color: var(--on-green);
  font-size: 0.6875rem; font-weight: 600; padding: 4px 12px; border-radius: 6px;
}
[data-demo="draft"] .d-bub { animation: dRise 8s ease-out infinite both; }
[data-demo="draft"] .d-draft { animation: dRise 8s ease-out infinite both; animation-delay: .9s; }
[data-demo="draft"] .d-draft p span {
  animation: dFade 8s ease-out infinite both;
  animation-delay: calc(1.3s + var(--i) * .1s);
}
[data-demo="draft"] .d-sendrow { animation: dFade 8s ease-out infinite both; animation-delay: 2.4s; }
[data-demo="draft"] .d-btn { animation: dBtnPulse 8s ease-out infinite both; }
@keyframes dBtnPulse {                  /* 3.6s — the hand-off */
  0%, 45%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 50%, transparent); }
  55%       { box-shadow: 0 0 0 8px color-mix(in srgb, var(--green) 0%, transparent); }
  100%      { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}

/* ---- demo 4 · customer memory (7.5s) ----------------------------------- */
.d-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.d-chip {
  font-size: 0.6875rem; padding: 4px 9px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border); color: var(--muted);
}
.d-chip.prom { background: var(--amber-bg); border-color: var(--amber-border); color: var(--amber); }
[data-demo="memory"] .d-head { animation: dFade 7.5s ease-out infinite both; }
[data-demo="memory"] .d-chip {
  animation: dChipIn 7.5s cubic-bezier(.2,1.5,.4,1) infinite both;
  animation-delay: calc(.6s + var(--i) * .3s);
}
@keyframes dChipIn {
  0%        { opacity: 0; transform: translateY(5px) scale(.9); }
  7%, 82%   { opacity: 1; transform: none; }
  92%, 100% { opacity: 0; }
}

/* ---- demo 5 · semantic auto-reply, held before it goes out (9s) --------- */
.d-bub.pend { animation: dSend 9s ease-out infinite both; animation-delay: .9s; }
.d-hold { display: inline-flex; align-items: center; gap: 6px; margin-inline-start: 8px; vertical-align: -1px; }
/* currentColor 而非 #fff:这条进度条画在出站气泡里,气泡文字色是 --on-green,
   夜间会翻成近黑 —— 写死白色会在亮绿底上消失。 */
.d-hold i {
  display: block; width: 30px; height: 3px; border-radius: 2px; background: currentColor;
  transform-origin: right; animation: dHold 9s linear infinite both; animation-delay: 1.1s;
}
.d-hold b { font-size: 0.625rem; font-weight: 500; opacity: .85; }
[data-demo="auto"] .d-bub.in { animation: dRise 9s ease-out infinite both; }
@keyframes dSend {                      /* drafted, held, then actually sent */
  0%        { opacity: 0; transform: translateY(6px); }
  8%        { opacity: .62; transform: none; }
  46%       { opacity: .62; }
  52%, 82%  { opacity: 1; }
  92%, 100% { opacity: 0; }
}
@keyframes dHold {                      /* the grace window draining */
  0%, 6%    { transform: scaleX(1); opacity: 1; }
  42%       { transform: scaleX(0); opacity: 1; }
  /* transform must be restated here: an unmentioned property falls back to the
     element's base value at the implicit 100%, which would grow the bar back. */
  46%, 100% { transform: scaleX(0); opacity: 0; }
}

/* ---- demo 6 · a deleted message, opened back up (9s) -------------------
   The whole feature in one shot: WhatsApp's tombstone, then what it said.
   The tombstone dims but never disappears — we don't hide what WhatsApp did. */
.d-tomb { display: inline-flex; align-items: center; gap: 6px; font-style: italic; color: var(--faint); }
.d-tomb .ico { width: 14px; height: 14px; }
.d-undel {
  display: block; margin-top: 8px; padding-top: 8px;
  border-top: 1px dashed color-mix(in srgb, var(--green) 40%, transparent);
}
.d-undel-tag {
  display: inline-flex; align-items: center; gap: 5px; margin-bottom: 5px;
  font-size: 0.625rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--green-ink);
}
.d-undel-tag .ico { width: 12px; height: 12px; }
.d-shot {
  display: block; margin-top: 7px; height: 44px; border-radius: 7px;
  background: linear-gradient(115deg, var(--green-bg-2), var(--green-bg));
  border: 1px solid var(--border);
}
[data-demo="undel"] .d-bub { animation: dRise 9s ease-out infinite both; }
[data-demo="undel"] .d-tomb { animation: dTomb 9s ease-out infinite both; }
[data-demo="undel"] .d-undel { animation: dUndel 9s ease-out infinite both; }
[data-demo="undel"] .d-shot { animation: dUndel 9s ease-out infinite both; animation-delay: .35s; }
@keyframes dTomb {
  0%, 33%   { opacity: 1; }
  40%, 82%  { opacity: .45; }
  92%, 100% { opacity: 1; }
}
@keyframes dUndel {
  0%, 33%   { opacity: 0; transform: translateY(-4px); }
  42%, 82%  { opacity: 1; transform: none; }
  92%, 100% { opacity: 0; }
}

/* ---- demo 7 · privacy blur, hover to reveal (8s) ----------------------
   The feature literally is a CSS blur filter, so the demo is the real thing:
   a chat list that's blurred, with one row clearing as if hovered. */
.d-blurrow { display: flex; align-items: center; gap: 9px; padding: 7px 4px; border-radius: 8px; }
.d-blurrow .d-av { width: 26px; height: 26px; font-size: 0.625rem; }
.d-bmeta { display: flex; flex-direction: column; min-width: 0; gap: 3px; }
.d-bname { height: 8px; width: 88px; border-radius: 4px; background: var(--text); opacity: .82; }
.d-bprev { height: 7px; width: 130px; border-radius: 4px; background: var(--muted); opacity: .5; }
.d-btime { margin-inline-start: auto; font-size: 0.625rem; color: var(--faint); }
/* everything sensitive blurs; the timestamp deliberately stays sharp */
[data-demo="blur"] .d-av,
[data-demo="blur"] .d-bname,
[data-demo="blur"] .d-bprev { filter: blur(4px); animation: dBlur 8s ease-in-out infinite both; }
[data-demo="blur"] .d-blurrow.reveal .d-av,
[data-demo="blur"] .d-blurrow.reveal .d-bname,
[data-demo="blur"] .d-blurrow.reveal .d-bprev { animation: dBlurReveal 8s ease-in-out infinite both; }
[data-demo="blur"] .d-blurrow.reveal { animation: dRevealBg 8s ease-in-out infinite both; }
.d-blurhint {
  margin-top: 10px; text-align: center; font-size: 0.6875rem; color: var(--faint);
  animation: dFade 8s ease-out infinite both; animation-delay: 1.5s;
}
.d-blurhint kbd {
  font-family: var(--font-mono); font-size: 0.625rem; background: var(--elevated);
  border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px;
}
@keyframes dBlur { 0%, 100% { filter: blur(4px); } }
@keyframes dBlurReveal {                /* the "hovered" row sharpens ~40%→75% of the loop */
  0%, 38%   { filter: blur(4px); }
  46%, 74%  { filter: blur(0); }
  82%, 100% { filter: blur(4px); }
}
@keyframes dRevealBg {
  0%, 38%   { background: transparent; }
  46%, 74%  { background: var(--elevated); }
  82%, 100% { background: transparent; }
}

/* ---- demo 2 · translation both ways (8s) ------------------------------- */
.d-tr {
  display: flex; align-items: flex-start; gap: 5px; margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed color-mix(in srgb, currentColor 32%, transparent);
  font-size: 0.75rem; opacity: .88;
}
.d-tr .ico { width: 12px; height: 12px; margin-top: 2px; flex: none; }
[data-demo="tr"] .d-bub:nth-child(1) { animation: dRise 8s ease-out infinite both; }
[data-demo="tr"] .d-bub:nth-child(1) .d-tr { animation: dFade 8s ease-out infinite both; animation-delay: .8s; }
[data-demo="tr"] .d-bub:nth-child(2) { animation: dRise 8s ease-out infinite both; animation-delay: 2s; }
[data-demo="tr"] .d-bub:nth-child(2) .d-tr { animation: dFade 8s ease-out infinite both; animation-delay: 2.8s; }

/* Reduced motion: kill every scene. Nothing here sets a resting opacity/
   transform, so dropping the animations leaves the finished frame on screen. */
@media (prefers-reduced-motion: reduce) {
  .demo-hero *, .cop-demo * { animation: none !important; }
}

/* ---- responsive -------------------------------------------------------- */
/* 4 列在笔记本宽度下每列只剩 ~250px，标题会断成三行 —— 先降到 2×2 再降到单列。 */
@media (max-width: 1100px) {
  .related.cols-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; gap: 32px; }
  .hero .lede { max-width: none; }
  .features-grid, .steps, .trust-band, .tiers { grid-template-columns: 1fr 1fr; }
  .pains { grid-template-columns: 1fr 1fr; }
  .cop-grid { grid-template-columns: 1fr 1fr; }
  .cop, .cop.wide { grid-column: span 1; }
  /* modifier 的优先级(0,2,0)高于裸 .related(0,1,0)，这里必须把它们一并列出，
     否则窄屏下 cols-4 仍是 4 列、挤成纸条。 */
  .related, .related.cols-4, .related.cols-2, .related.cols-1 { grid-template-columns: 1fr; }
  .related.cols-1 { justify-content: stretch; }
  .dash-grid { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
/* Laptop header: below the full container width (--maxw, now 1200) the row runs out
   of room in the verbose locales, so the install button drops its label and rides as
   an icon.
   The title attribute then supplies the accessible name — a display:none label is
   dropped from the accessibility tree, so the button must not depend on it.

   ★断点 1100 → 1200(2026-07-31,按钮文案从「Install」加长到「Install Extension」
     及各语言对应说法之后)。旧注释断言「1100 无需随 --maxw 调整」,那个结论是【按
     旧文案算的】,文案一变就失效 —— 实测 1101px 视口下:
       fr「Installer l'extension」 文档宽 1134(溢出 33)
       es「Instalar extensión」   1119(溢出 18)
       de「Erweiterung installieren」1113(溢出 12)
       en「Install Extension」     1086(仍安全)
     即最长的几个语言在 1100–1134 这一档会把导航栏挤出横向滚动条。取 1200 而不是
     刚好够的 1140:与 --maxw 对齐(视口窄于容器最大宽度就意味着空间开始紧张),
     且给未来更啰嗦的译文留余量。
     ⇒ 改按钮文案时必须回头重测这个断点,它是跟着文案走的。 */
@media (max-width: 1200px) {
  .nav-install .nav-install-label { display: none; }
  .nav-install { padding-inline: 10px; }
}

/* Phone header: brand + theme + Sign in + trial CTA + hamburger don't fit on a
   phone — the row overflowed the viewport (65px at 375, 120px at 320), which
   scrolls the whole page sideways. Shed the least valuable things first: the
   ghost "Sign in" (every page offers one in its body), then padding.
   The install button goes too — Chrome/Edge on a phone can't install extensions
   at all, so at this width it is the one control that can't do anything. */
@media (max-width: 560px) {
  .nav-actions { gap: 3px; padding: 3px; }
  /* Phone: the account chip keeps the avatar (still says "signed in, as someone"),
     drops the address — it is the widest thing in the row by far. */
  .acct-email { display: none; }
  .acct > summary { padding: 0 4px 0 3px; }
  .nav-actions .btn-sm { padding: 8px 11px; font-size: 0.8125rem; }
  .nav-actions .btn-ghost[data-auth-swap] { display: none; }
  .nav-install { display: none; }
}
/* Narrow phones (320–420). Shedding "Sign in" and install above is not enough. What
   is left — brand + globe + theme + trial CTA + hamburger — left the trial button only
   ~65px at 320px of content width, i.e. under 9 characters: no wording fits that,
   English included ("Start free trial" = 95px, so 30px of sideways scroll). The row
   needs structural width back rather than shorter copy, so the wordmark drops and the
   logo carries the brand alone (~64px). Copy still has to stay in budget on top of
   that: where the full CTA doesn't fit, nav.startTrial is a shortened noun phrase
   ("free trial"), separate from hero.ctaPrimary which keeps the verb.
   Hidden *visually only* (same declarations as .sr-only) — the wordmark is the brand
   link's accessible name and the logo <svg> is aria-hidden, so display:none would
   leave an unnamed link.
   Measured worst case after this: de fits down to 299px of content width, so a 320px
   phone clears it even with a 15px classic scrollbar. Re-measure if the row grows. */
@media (max-width: 420px) {
  .nav { gap: 10px; }
  /* 标是 em 尺寸,跟着这行 font-size 自动缩 —— 不需要再单独给它一个像素尺寸。 */
  .brand { font-size: 0.9375rem; }
  .site-header .brand-name {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
  }
  .nav-actions .btn-sm { padding: 7px 9px; font-size: 0.75rem; }
}

/* Section links → hamburger. The threshold is set by the row, not by "tablet":
   with the links inline the header needs ~1000px in the verbose locales (es/fr/pt-BR),
   so it used to overflow horizontally all the way from 721px up to ~1000px — the
   page scrolled sideways. Kept at 1040 deliberately: after the tray + "EN" the worst
   case (fr) actually survives down to 1000px, but with ~1px to spare — far too thin
   for a site whose translations are still drafts, so the extra 40px stays as margin.
   Re-measure if the row changes. */
@media (max-width: 1040px) {
  .nav-links { display: none; }
  .nav-toggle { display: inline-flex; }
  .nav.open .nav-links {
    display: flex; position: absolute; top: 64px; left: 0; right: 0; flex-direction: column;
    align-items: stretch; gap: 2px; padding: 12px 16px; background: var(--bg);
    border-bottom: 1px solid var(--border); box-shadow: var(--shadow);
  }
  .nav.open .nav-links a { padding: 12px; }
}

@media (max-width: 720px) {
  .section { padding: 56px 0; }
  /* modifier 优先级(0,2,0)高于裸类(0,1,0)，不一并列出的话手机上仍是 2 列。 */
  .features-grid, .steps, .trust-band, .trust-band.cols-2, .tiers, .footer-grid { grid-template-columns: 1fr; }
  .pains, .cop-grid, .plan-strip { grid-template-columns: 1fr; }
  .tier.pop { order: -1; }
  .hero h1 { font-size: clamp(2rem, 8vw, 2.6rem); }
}

/* ── Language switcher (native <details>, injected by build-i18n.mjs) ─────── */
.lang-switch { position: relative; }
.lang-switch > summary {
  display: inline-flex; align-items: center; gap: 6px;
  height: 40px; padding: 0 10px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--panel); color: var(--muted);
  cursor: pointer; list-style: none; white-space: nowrap;
  font-size: 0.8125rem; font-weight: 600;
}
.lang-switch > summary::-webkit-details-marker { display: none; }
.lang-switch > summary::marker { content: ""; }
.lang-switch > summary:hover,
.lang-switch[open] > summary { color: var(--text); background: var(--elevated); }
.lang-switch .ico { width: 18px; height: 18px; }
.lang-switch ul,
.acct ul {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
  min-width: 184px; margin: 0; padding: 6px; list-style: none;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow);
}
.lang-switch ul a,
.acct ul a {
  display: block; padding: 8px 10px; border-radius: 8px;
  color: var(--text); text-decoration: none; font-size: 0.875rem;
}
.lang-switch ul a:hover,
.acct ul a:hover { background: var(--elevated); }
.lang-switch ul a[aria-current="true"] { color: var(--green); font-weight: 700; }
[dir="rtl"] .lang-switch ul,
[dir="rtl"] .acct ul { right: auto; left: 0; }
@media (max-width: 720px) {
  .lang-switch .lang-cur { display: none; } /* 收起为地球图标 */
  .lang-switch > summary { padding: 0 9px; }
}

/* ── Account chip (signed in) ──────────────────────────────────────────────
   Replaces the green "Your account" button: a green initials avatar + the
   signed-in address + a caret, on the same raised chip as Install. Two reasons
   it beats a button here — it answers "which account am I in?" (this site has a
   per-WhatsApp-number licence, so the wrong account is a real mistake to make),
   and it frees the green fill to mean one thing only: the trial CTA. The menu
   reuses the language switcher's popover, so there is one dropdown look on the
   site, and one <details> behaviour (no JS to open/close).
   nav.js fills the text from the session token's email claim. */
.acct { position: relative; }
.acct > summary {
  display: inline-flex; align-items: center; gap: 8px;
  height: 34px; padding: 0 8px 0 3px; border-radius: var(--radius-sm);
  background: var(--tray-chip); border: 1px solid var(--border);
  box-shadow: var(--shadow-sm); cursor: pointer; list-style: none;
  color: var(--text); font-size: 0.875rem; white-space: nowrap;
}
.acct > summary::-webkit-details-marker { display: none; }
.acct > summary::marker { content: ""; }
.acct > summary:hover, .acct[open] > summary { border-color: var(--border-strong); }
.acct-avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--green); color: var(--on-green);
  font-size: 0.6875rem; font-weight: 700; letter-spacing: .02em;
}
/* Addresses are unbounded; the nav is not. Truncate rather than let one long
   address push the row into a horizontal scroll. */
.acct-email { max-width: 190px; overflow: hidden; text-overflow: ellipsis; }
.acct-caret { width: 14px; height: 14px; color: var(--faint); }
.acct ul { min-width: 200px; }

/* ══════════════════════════════════════════════════════════════════════════
   微排版:标注类小字走等宽
   ──────────────────────────────────────────────────────────────────────────
   这一条清单就是「哪些东西是标注、不是内容」的唯一定义处。等宽字体让它们读起来
   像仪表盘上的刻度而不是另一句话:计量单位、周期、状态标签、小写大写分节标题。
   刻意只声明 font-family —— 字号/字距/颜色留在各自的组件规则里(它们随尺寸调过),
   放在全部组件之后是为了让这一条能覆盖前面的 font-family: inherit。
   ⚠ 正文永不进这份清单。加新条目前问一句:它是「数据」还是「话」?
   ⚠ mono 无阿拉伯文/CJK 字形,下面 RTL/CJK 段会把这些选择器整组换回 sans。 */
.eyebrow,
.cop-tag,
.ribbon,
.rpill,
.radar-head,
.draft-head,
.hero-note,
.mock-stat span,
.card h2,
.sec-head,
.footer-col h4,
.plan-feats li.ai-head,
.d-undel-tag,
.tier .price .per,
.tier .annual-note,
.cta-inner .subnote,
.device .dmeta span { font-family: var(--font-mono); }

/* ── RTL (Arabic) ──────────────────────────────────────────────────────────
   Layout mirrors automatically: <html dir="rtl"> flips text flow, grid/flex
   inline axis, and align-self flex-start/end; the physical spacing/alignment
   props above were converted to logical (margin-inline/padding-inline/
   text-align:start) so they flip too. Only a few decorative absolutely-
   positioned bits and physical corner radii need an explicit mirror here. */
[dir="rtl"] .hero::before { right: auto; left: -140px; }       /* brand glow → opposite corner（与 LTR 侧 -140px 对称，改一边就改另一边） */
[dir="rtl"] .pain-q { left: auto; right: 15px; }               /* quote mark → top-right */
[dir="rtl"] .d-sparkle { left: auto; right: 10px; }            /* demo sparkle → top-right */
/* chat-bubble tail corners: in-bubble sits right, out-bubble sits left in RTL */
[dir="rtl"] .d-bub.in { border-bottom-left-radius: 11px; border-bottom-right-radius: 3px; }
[dir="rtl"] .d-bub.out { border-bottom-right-radius: 11px; border-bottom-left-radius: 3px; }
/* breadcrumb chevron › → ‹ (the aria-hidden separator span) */
[dir="rtl"] .crumbs span[aria-hidden="true"] { display: inline-block; transform: scaleX(-1); }
/* forward-arrow CTAs (→) point with the RTL flow; :has targets only #i-arrow, not other icons */
[dir="rtl"] .ico:has(use[href="#i-arrow"]) { transform: scaleX(-1); }

/* ── 拉丁排版的豁免:阿拉伯文 ───────────────────────────────────────────────
   上面那套排版是为拉丁字母调的,有两样东西直接搬到阿拉伯文上是错的:
     1) 负字距 —— 阿拉伯文是连写体,字母靠基线连成词,收紧字距会破坏连接;
        正字距(eyebrow 那种 0.14em)更糟,它会把一个词拆成散字。
     2) 等宽字体 —— --font-mono(IBM Plex Mono)和 --font-sans(Plus Jakarta Sans)
        都不含阿拉伯文字形,浏览器会静默回退到系统字体,于是「为 Jakarta 调的字距」
        落在了一个完全不同的字面上。
   text-transform: uppercase 对阿拉伯文本就无效(无大小写),一并去掉以免语义混乱。
   注意选择器必须与上面「微排版」清单保持同步 —— 那里加一条,这里也要加。 */
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3, [dir="rtl"] h4,
[dir="rtl"] .hero h1, [dir="rtl"] .section-head h2,
[dir="rtl"] .tier h3, [dir="rtl"] .tier .price .amt,
[dir="rtl"] .cta-inner h2, [dir="rtl"] .plan-name { letter-spacing: normal; }
[dir="rtl"] .eyebrow,
[dir="rtl"] .cop-tag,
[dir="rtl"] .ribbon,
[dir="rtl"] .rpill,
[dir="rtl"] .radar-head,
[dir="rtl"] .draft-head,
[dir="rtl"] .hero-note,
[dir="rtl"] .mock-stat span,
[dir="rtl"] .card h2,
[dir="rtl"] .sec-head,
[dir="rtl"] .footer-col h4,
[dir="rtl"] .plan-feats li.ai-head,
[dir="rtl"] .d-undel-tag,
[dir="rtl"] .tier .price .per,
[dir="rtl"] .tier .annual-note,
[dir="rtl"] .cta-inner .subnote {
  font-family: var(--font-sans); letter-spacing: normal; text-transform: none;
}
/* 六位验证码是唯一的例外:它是逐字符从另一块屏幕抄过来的数字,宽字距正是可读性
   要求本身,且阿拉伯语环境下这个字段仍然填拉丁数字。故保留 .code-input 不豁免。 */

/* ── 拉丁排版的豁免:CJK ────────────────────────────────────────────────────
   lang 是 "zh-Hans"(site.config.mjs),:lang(zh) 按语言子标签前缀匹配,能命中。
     1) 负字距对方块字无意义,只会让字挤在一起;
     2) Plus Jakarta Sans / IBM Plex Mono 都无 CJK 字形 → 必须显式给 CJK 字体栈,
        否则回退结果随系统而异(而且会和拉丁数字混排出两种字重观感);
     3) 字重收到 700:中文系统字体一般只到 Bold,800 会触发合成加粗,笔画糊成一团。
     4) 中文没有词间空格 ⇒ 断行点无处不在。拉丁标题靠空格自然分行,中文标题却会被
        齐头断成锯齿,还常把「收件箱」这类词拦腰劈开、或甩出「里。」两字的孤行。
        text-wrap: balance 让浏览器把各行长度拉平(规范只对 ≤6 行的块生效,无性能顾虑)。
        它是 Chrome 114+ / Edge 特性 —— 而本站受众按定义只有这两个浏览器。 */
:lang(zh) {
  --font-sans: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
               "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas,
               "PingFang SC", "Microsoft YaHei", monospace;
}
:lang(zh) h1, :lang(zh) h2 { font-weight: 700; letter-spacing: normal; }
:lang(zh) h3, :lang(zh) h4 { letter-spacing: normal; }
:lang(zh) .hero h1,
:lang(zh) .section-head h2,
:lang(zh) .cta-inner h2,
:lang(zh) .tier h3,
:lang(zh) .plan-name { letter-spacing: normal; }
:lang(zh) .hero h1,
:lang(zh) .section-head h2,
:lang(zh) .cta-inner h2 { text-wrap: balance; }
/*  5) 标题字号是按拉丁文定的:英文一行放得下 5~6 个单词,同样宽度只放得下 8 个汉字,
       于是 feature 页 462px 的窄栏里,15 个 h1 有 8 个碎成 3~4 行、还把「自|动化」
       「聊天链|接与二维码」这类词拦腰劈开。降到 86% 可消灭全部 4 行、3 行减半,
       而 46~50px 依然是有分量的主标题。balance 负责匀行,这条负责让字先放得下。 */
:lang(zh) .hero h1 { font-size: clamp(2.05rem, 4.8vw, 3.3rem); }
/*  6) 降字号后仍有几条断在词中间(「自|动化」「不|用」)。balance 只管匀行、不认中文词界;
       `word-break: auto-phrase` 实测无效 —— CSS.supports 返回 true,但 Chrome 的分词
       线目前只对日文生效,zh-Hans 上是空操作(已实测比对,输出逐字符相同)。
       所以唯一可靠的办法是在文案里把不许拆的词圈出来。 */
.nb { white-space: nowrap; }
/* 金额是拉丁数字,紧字距对它依然成立,故 .amt 不在豁免之列。 */
