@property --visual-chat-cta-mix {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}
@property --visual-chat-cta-glow {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 18%;
}

/* The homepage background has one owner in style.css. Visual runtime only
   changes the variables consumed by that background, so enabling the lab
   cannot create a second paint layer or a seam between home sections. */
html[data-visual-home-enabled="1"] body[data-page-kind="home"] .hero {
  min-height: calc(var(--visual-heroMinHeight, 100) * 1vh) !important;
}
html[data-visual-home-enabled="1"] body[data-page-kind="home"] .hero-title {
  transform: scale(var(--visual-heroTitleScale, 1));
  transform-origin: center;
  letter-spacing: calc(var(--visual-heroTitleTracking,-.045) * 1em) !important;
}
html[data-visual-home-enabled="1"] body[data-page-kind="home"] .hero-desc {
  opacity: var(--visual-heroDescOpacity, .82);
  font-size: calc(var(--visual-heroDescSize,23.2) * 1px) !important;
}
/* .docs-catalog 属于纸面分区，间距由 _paper-theme.css 独占：
   两处都写会互相压，手机上就会出现 96px 的大段死白。 */
/* bot 页同样带 home-showcase-section（为了继承 hero/胶囊顶栏那套 home 规则），
   但它不是首页那条长滚动流：垂直节奏由 static/bot.css 的 .bot-sections gap
   独占。这里把 body[data-bot-page] 排除掉，否则这条强制声明会盖掉
   bot.css 的 padding-block:0，每屏上下各多挤 96px。 */
html[data-visual-home-enabled="1"] body[data-page-kind="home"]:not([data-bot-page]) :is(.home-ai-demo-section,.home-showcase-section) {
  padding-block: calc(var(--visual-homeSectionSpacing,96) * 1px) !important;
}
html[data-visual-home-enabled="1"] body[data-page-kind="home"] .hero-title .gradient {
  background-image: linear-gradient(90deg, var(--visual-title1), var(--visual-title2), var(--visual-title3), var(--visual-title2), var(--visual-title1)) !important;
  animation-duration: calc(var(--visual-titleSpeed, 6) * 1s) !important;
  animation-play-state: var(--visual-titleFlow, running) !important;
}
html body[data-page-kind="home"] :is(.gta-scroll-text, .home-section-title .gradient) {
  background-image: linear-gradient(180deg, var(--visual-title1, #ff9fc9) 0%, var(--visual-title2, #ffd27f) 48%, var(--visual-title3, #e7fbb0) 100%) !important;
  background-size: 100% 300% !important;
  -webkit-background-clip: text !important;
  background-clip: text !important;
  -webkit-text-fill-color: transparent !important;
  background-position: center var(--srbill-scroll-flow-y, 0%) !important;
  transition: background-position .12s linear !important;
}
html body[data-page-kind="home"] .home-section-point-icon {
  background: var(--section-icon-bg, rgba(231,251,176,.92)) !important;
  color: var(--section-icon-fg, #29331b) !important;
  box-shadow: 0 8px 20px var(--section-icon-shadow, rgba(231,251,176,.2)) !important;
}
html body[data-page-kind="home"] .home-section-point-icon :is(i, svg) {
  color: currentColor !important;
  stroke: currentColor !important;
}
html[data-visual-home-enabled="1"] body[data-page-kind="home"] .hero-desc {
  color: color-mix(in srgb, var(--text-primary) 92%, var(--visual-ctaBase, #e7fbb0)) !important;
  text-shadow: 0 1px 10px rgba(16, 12, 28, .52) !important;
  font-weight: 550 !important;
}
body[data-page-kind="home"] :is(.gta-scroll-p, .section-desc, .home-section-point-desc, .app-info p, .doc-info p) {
  color: color-mix(in srgb, var(--text-primary) 88%, #fff) !important;
  text-shadow: 0 1px 8px rgba(16, 12, 28, .42);
  font-weight: 500;
}
body[data-page-kind="home"] :is(.home-section-point-title, .app-info h3, .doc-info h3) {
  font-weight: 750;
}
body[data-page-kind="home"] #typewriter-text {
  font-size: .92em;
}
body[data-page-kind="home"] .hero-title .gradient {
  filter: contrast(var(--visual-titleContrast, 1)) drop-shadow(0 3px 12px var(--visual-titleShadow, rgba(23, 20, 38, .34))) !important;
}
body[data-page-kind="home"] .hero-actions .hero-btn-primary-glow {
  background: linear-gradient(135deg, color-mix(in srgb, var(--visual-ctaBase, #e7fbb0) 92%, #fff) 0%, var(--visual-ctaBase, #e7fbb0) 100%) !important;
  color: #26321b !important;
  border-color: color-mix(in srgb, var(--visual-ctaBase, #e7fbb0) 72%, #fff) !important;
  /* 中性投影，不用 --visual-ctaShadow 上色：那会变成一圈彩色光晕，
     正是设计规范里禁止的「四周发光」。 */
  box-shadow: 0 2px 8px rgba(18, 14, 32, .18) !important;
  animation: visual-hero-cta-breathe var(--visual-ctaCycle, 4.8s) ease-in-out infinite var(--visual-ctaPlayState, running) !important;
}
body[data-page-kind="home"] .hero-actions .hero-btn-primary-glow:hover {
  box-shadow: 0 4px 14px rgba(18, 14, 32, .24) !important;
  filter: brightness(1.04) saturate(1.04) !important;
}
/* Icons on the accent-green CTA must stay solid dark, otherwise they
   disappear into the button fill. The scroll cue and caret keep accent. */
body[data-page-kind="home"] .hero-actions .hero-btn-primary-glow :is(i, svg) {
  color: #26321b !important;
  stroke: currentColor !important;
  opacity: 1 !important;
}
body[data-page-kind="home"] .scroll-indicator :is(i, svg),
body[data-page-kind="home"] .typewriter-cursor {
  color: var(--visual-ctaBase, #e7fbb0) !important;
}
body[data-page-kind="home"] .typewriter-cursor {
  background-color: var(--visual-ctaBase, #e7fbb0) !important;
}
/* 呼吸只做 1px 位移，不再放大彩色阴影 —— 常驻彩色光晕是「AI 味」来源之一。 */
@keyframes visual-hero-cta-breathe {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-1px); }
}
body[data-page-kind="home"] .scroll-indicator :is(i, svg) {
  opacity: .86 !important;
  animation: visual-scroll-cue 2.8s cubic-bezier(.34, 1.56, .64, 1) infinite !important;
  filter: drop-shadow(0 2px 8px color-mix(in srgb, var(--visual-ctaBase, #e7fbb0) 28%, transparent));
}
@keyframes visual-scroll-cue {
  0%, 100% { transform: translateY(0) scale(1); opacity: .68; }
  48% { transform: translateY(5px) scale(1.04); opacity: 1; }
  68% { transform: translateY(2px) scale(1); opacity: .9; }
}
@media (prefers-reduced-motion: reduce) {
  body[data-page-kind="home"] .hero-actions .hero-btn-primary-glow,
  body[data-page-kind="home"] .scroll-indicator :is(i, svg) { animation: none !important; }
}
/* Home card surface has exactly one owner: style.css
   (body[data-page-kind="home"] .feature-card/.app-card/.doc-card/...).
   The lab only feeds --visual-card* variables; it must not repaint cards,
   otherwise enabling/disabling 首页视觉配置 flips between two surfaces. */
html[data-visual-home-enabled="1"][data-visual-cta-enabled="1"] body[data-page-kind="home"] .hero-actions .hero-btn-primary-glow {
  background: color-mix(in srgb,var(--visual-ctaBase,#e7fbb0) 82%,var(--visual-ctaHighlight,#f4ffd2)) !important;
  color: #28321c !important;
  border: 0 !important;
  /* 中性投影。原来这里用 --visual-ctaGlowPct 上色，就是首页 CTA 那圈
     彩色光晕的来源（用户反复指出的「四周发光」）。 */
  box-shadow: 0 2px 8px rgba(18, 14, 32, .18) !important;
}
body[data-page-kind="home"] .hero-title { cursor: pointer; }

html body .chat-sidebar {
  /* 侧栏玻璃底色的唯一拥有者。皮肤不再重复写 background，只换
     --aichat-sidebar-surface 令牌：书纸给纸面次级色，极简给画布色，
     Vice 保持默认薄玻璃。 */
  background: var(--aichat-sidebar-surface, rgba(255,255,255,var(--visual-chatSidebarAlpha,.045))) !important;
  /* 侧栏是唯一同时被"设计方"和"实验室"改 box-shadow 的阅读面：
     移动端抽屉 `--shadow-lg`（ai-chat-unified.css）与 legacy 主题的
     `0 12px 28px` 都会因为实验室的 readingShadeShadow 特异性更高而失效。
     侧栏的底色本来就是本规则独占的，所以把暗滤镜改成叠在 background 上，
     box-shadow 完整交还给设计方 —— 一个属性只有一个 owner。 */
  background-image: var(--visual-readingSidebarVeil, none) !important;
  border: 0 !important;
  backdrop-filter: blur(calc(var(--visual-chatSidebarBlur,30) * 1px)) saturate(calc(var(--visual-chatSidebarSaturation,145) * 1%)) !important;
  -webkit-backdrop-filter: blur(calc(var(--visual-chatSidebarBlur,30) * 1px)) saturate(calc(var(--visual-chatSidebarSaturation,145) * 1%)) !important;
}
/* Reader surfaces have one dark veil. Keep the navbar, composer, dialogs and
   action controls outside this selector so a bright preset stays readable
   without changing the surrounding shell. */
/* 首屏滤镜 / 非首屏压暗：与阅读区暗滤镜同一套机制（inset 覆盖，画在元素自己
   的盒子里），所以不会在首屏与第二屏之间产生接缝。默认 alpha = 0，运行时连
   data-* 标记都不加，因此不设置时这两条规则完全不参与渲染。 */
/* 首屏压暗与首屏柔光是同一条 box-shadow 的两个层：无阴影时用完全透明的
   inset 占位（不能写 none，列表里混 none 会让整条声明失效）。 */
:is(html, body)[data-hero-veil="true"] .hero {
  box-shadow: var(--visual-heroVeilShadow, inset 0 0 0 9999px transparent),
              var(--visual-heroGlowShadow, inset 0 0 0 9999px transparent) !important;
}
:is(html, body)[data-page-shade="true"] :is(.apps-section, .docs-catalog, .home-ai-demo-section, .home-showcase-section) {
  box-shadow: var(--visual-pageShadeShadow, none) !important;
}
/* 阅读暗滤镜只压"没有自己阴影的阅读面"。.chat-sidebar 已改走
   background-image（见上方 html body .chat-sidebar），不在这里抢 box-shadow。 */
body[data-reading-shade="true"] :is(.doc-content, .doc-toc, .sidebar) {
  box-shadow: var(--visual-readingShadeShadow, none) !important;
}
/* 提亮名单里不放 .title / .conv-item .title：AICHAT 会话标题的颜色由皮肤
   （_aichat-vice-skin.css / html body .conv-item 规则）独占，选中态是
   --aichat-active-title 的强调色。这条规则特异性 (0,4,1) 会把它顶掉，
   未选中标题也会从皮肤的 --text-primary 被压暗成"发灰"。 */
body[data-reading-shade="true"] :is(.doc-content, .doc-toc, .sidebar) :is(
  p, li, blockquote, h1, h2, h3, h4, h5, h6, th, td, a,
  .nav-title-text, .sidebar-title, .toc-link,
  .nav-file, .folder-header, .sidebar-header span,
  .new-chat-btn
),
html[data-aichat-skin="vice"] body[data-reading-shade="true"] .chat-sidebar :is(
  p, li, blockquote, h1, h2, h3, h4, h5, h6, th, td, a,
  .nav-title-text, .sidebar-title, .toc-link,
  .nav-file, .folder-header, .sidebar-header span,
  .new-chat-btn
) {
  color: color-mix(in srgb, currentColor 97%, #fff) !important;
  font-weight: 560;
  text-shadow: var(--visual-readingTextShadow, 0 0 .35px currentColor);
}
/* 暗滤镜只负责“把阅读正文提亮 3%”，不负责给自带文字色的组件定色。
   用户气泡的文字色是 shell-layout 按气泡底色算出来的 --user-bubble-text，
   一旦被这条 !important 覆盖就会变成“亮底白字”（截图事故）。
   注意 color: color-mix(... currentColor ...) 里的 currentColor 取的是
   继承值（父级 --text-primary），不是元素自身的 color，所以这里必须靠
   :not() 把用户气泡整棵子树排除掉，而不是指望它算对。 */
body[data-reading-shade="true"] .doc-content :is(
  .markdown-body, .msg-bubble, .gta-scroll-p, .section-desc,
  .home-section-point-title, .home-section-point-desc
):not(.message.user .msg-bubble):not(.message.user .markdown-body),
html[data-aichat-skin="vice"] body[data-reading-shade="true"] .chat-container :is(
  .markdown-body, .msg-bubble, .gta-scroll-p, .section-desc,
  .home-section-point-title, .home-section-point-desc
):not(.message.user .msg-bubble):not(.message.user .markdown-body) {
  color: color-mix(in srgb, currentColor 97%, #fff) !important;
  font-weight: 540;
}
/* Sidebar glass has exactly one owner: the row above (html body .chat-sidebar).
   .sidebar-header used to carry its own backdrop-filter from style.css, i.e. a
   second material sampled *through* the sidebar's glass, which rendered as an
   extra darker band above 本地对话历史. The conversation list scrolls inside its
   own box, so the header never has content to mask: one surface, one filter. */
html body :is(.sidebar-header,.conv-list) {
  background: transparent !important;
  border-color: transparent !important;
  /* 本选择器 (0,1,3) 已经高过 style.css 的 .sidebar-header (0,1,0)，
     所以这两条按权重生效，不再往上叠强调后缀。 */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
html body .conv-item {
  /* 未选中行保持全透明：设计规范明确「会话列表不留灰块，选中只靠标题变色」，
     所以「会话透明度」这个参数没有合法落点，已从实验室移除。 */
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
html body .conv-item:hover {
  /* 悬停反馈由 --visual-chatItemHoverAlpha 单一驱动（此前写死 7% 的
     color-mix，滑杆是死的）。fallback 取 .07 与历史观感一致。 */
  background: color-mix(in srgb,
    var(--text-primary) calc(var(--visual-chatItemHoverAlpha, .07) * 100%), transparent) !important;
  border: 0 !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
/* Unselected rows stay solid and legible; the active row is marked by the
   accent title colour only. No frame, no glow, no grey box. */
html body .conv-item .title {
  color: color-mix(in srgb, var(--text-primary) 92%, transparent) !important;
}
html body .conv-item :is(i,svg,.conv-more-btn) {
  color: color-mix(in srgb, var(--text-primary) 82%, transparent) !important;
  opacity: 1 !important;
}
html body .conv-item.active {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
html body .conv-item.active .title {
  color: var(--aichat-active-title, var(--theme-solid, var(--accent))) !important;
  font-weight: 800 !important;
}
html[data-aichat-skin="vice"] body .conv-item.active .title {
  color: var(--visual-chatActiveColor,#e7fbb0) !important;
}
/* Non-vice themes: one solid accent, automatic black/white foreground.
   用户气泡 = 这套主题的强调色本身（文字由 srbillTextOn 自动取黑白）。
   2026-10-19 d3f0784 曾把这里改成中性灰，等于把用户选的主题色从气泡上
   抹掉；皮肤文件（paper / minimal）只覆盖需要特例的那两档。 */
html[data-aichat-skin="solid"] {
  --user-bubble-bg: var(--theme-solid, var(--accent));
  --user-bubble-text: var(--on-accent, #fff);
}

/* 所有非 Vice 的纯色皮肤共用同一套壳：白纸/黑纸画布、中性气泡、
   透明侧栏与输入区。颜色只留给按钮、选中标题、图标等小控件。
   paper 有自己的纸面令牌（_aichat-paper-skin.css），这里明确排除。
   之前 colored 皮肤沿用 mode-light 的 #f2f2f7，和 minimal 的纯白并存，
   同一页出现两种“底色”，看起来像两套主题打架。 */
html[data-aichat-skin="solid"]:not([data-bubble-color="paper"]) {
  --aichat-canvas: #ffffff;
  --bg-primary: #ffffff;
  --bg-secondary: #ffffff;
  --bg-tertiary: #f5f5f7;
  --panel-bg: #ffffff;
  --panel-bg-soft: #ffffff;
  --aichat-sidebar-surface: transparent;
  --aichat-composer-surface: transparent;
  --aichat-composer-surface-light: transparent;
  --aichat-input-surface: var(--aichat-liquid-fill);
  --aichat-input-surface-light: var(--aichat-liquid-fill);
  --aichat-input-ring: rgba(0, 0, 0, .06);
  --aichat-input-ring-light: rgba(0, 0, 0, .06);
  color-scheme: light;
}
html[data-aichat-skin="solid"]:not([data-bubble-color="paper"])[data-theme="dark"] {
  --aichat-canvas: #000000;
  --bg-primary: #000000;
  --bg-secondary: #000000;
  --bg-tertiary: #1c1c1e;
  --panel-bg: #000000;
  --panel-bg-soft: #000000;
  --aichat-sidebar-surface: transparent;
  --aichat-composer-surface: transparent;
  --aichat-composer-surface-light: transparent;
  --aichat-input-surface: var(--aichat-liquid-fill);
  --aichat-input-surface-light: var(--aichat-liquid-fill);
  --aichat-input-ring: rgba(255, 255, 255, .08);
  --aichat-input-ring-light: rgba(255, 255, 255, .08);
  color-scheme: dark;
}

html:not([data-aichat-skin="vice"]) body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)) {
  background: var(--theme-solid, var(--accent)) !important;
  background-image: none !important;
  color: var(--on-accent, #fff) !important;
  border: 0 !important;
  box-shadow: 0 6px 22px color-mix(in srgb, var(--theme-solid, var(--accent)) 26%, transparent) !important;
  animation: none !important;
}
html:not([data-aichat-skin="vice"]) body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)) :is(i,svg) {
  color: var(--on-accent, #fff) !important;
  stroke: currentColor !important;
}
html:not([data-aichat-skin="vice"]) body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)):is(:hover,:focus-visible) {
  background: color-mix(in srgb, var(--theme-solid, var(--accent)) 88%, #fff) !important;
}

html[data-aichat-skin="vice"] body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)) {
  --visual-chat-cta-mix: 0%;
  --visual-chat-cta-glow: var(--visual-chatCtaGlowBase,18%);
  background: color-mix(in srgb,var(--visual-chatCtaBase,#e7fbb0),var(--visual-chatCtaHighlight,#f4ffd2) var(--visual-chat-cta-mix)) !important;
  color: var(--visual-chatCtaOn,#1c2115) !important;
  border: 0 !important;
  box-shadow: 0 6px 24px color-mix(in srgb,var(--visual-chatCtaShadow,#b6cf72) var(--visual-chat-cta-glow),transparent),inset 0 1px 0 rgba(255,255,255,.42) !important;
  animation: visual-chat-cta-breathe calc(var(--visual-chatCtaCycle,4.8) * 1s) ease-in-out infinite !important;
  animation-play-state: var(--visual-chatCtaPlayState,running) !important;
}
html[data-aichat-skin="vice"] body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)) :is(i,svg) {
  color: var(--visual-chatCtaOn,#1c2115) !important;
  stroke: currentColor !important;
}
html[data-aichat-skin="vice"] body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)):is(:hover,:focus-visible) {
  background: var(--visual-chatCtaHighlight,#f4ffd2) !important;
  color: var(--visual-chatCtaOn,#1c2115) !important;
  animation-play-state: paused !important;
}
html body .input-box {
  /* 底色由皮肤令牌决定；vice 在 _aichat-vice-skin.css 覆盖为薄玻璃。
     这里若写死白色，纯色主题的输入框会变成一块不透明白板。 */
  background: var(--aichat-input-surface, var(--aichat-liquid-fill)) !important;
  backdrop-filter: var(--aichat-liquid-filter, blur(40px) saturate(200%)) !important;
  -webkit-backdrop-filter: var(--aichat-liquid-filter, blur(40px) saturate(200%)) !important;
}
@keyframes visual-chat-cta-breathe {
  0%,100% { --visual-chat-cta-mix: 0%; --visual-chat-cta-glow: var(--visual-chatCtaGlowBase,18%); }
  50% { --visual-chat-cta-mix: 34%; --visual-chat-cta-glow: var(--visual-chatCtaGlowPeak,38%); }
}
@media (prefers-reduced-motion: reduce) {
  html body :is(.new-chat-btn,.chat-input-area .send-btn:not(.stop)) { animation: none !important; }
}

/* iOS PWA: the composer never paints its own panel, so no dark block or
   divider can appear between the input and the home indicator. */
html body .chat-input-area {
  /* 与侧栏同一条纪律：输入区底色只由这里拥有，皮肤换令牌不抢属性。
     书纸 / 极简都要能把自己那一档写进来，否则永远是透明（书纸实测就是
     一层白雾盖在纸面上）。 */
  background: var(--aichat-composer-surface, transparent) !important;
  background-image: none !important;
  border: 0 !important;
  border-top: 0 !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* AICHAT messages need the veil, but not the input area below them.
   阅读暗滤镜是 Vice 的阅读层，不是纯色主题的。纯色浅色被它压成
   rgb(163,164,169) 的灰膜，纯白画布和输入栏的玻璃一起发闷；
   纯色深色已有下面的豁免。这里直接把 AICHAT 的压暗限定在 Vice。 */
html[data-aichat-skin="vice"] body[data-reading-shade="true"] .chat-container {
  box-shadow: var(--visual-readingShadeShadow, none) !important;
}
/* 纯色皮肤 + 深色档：画布本身就是 #000000，这层带色压暗没有"可压暗"的东西，
   只会把纯黑染成 `rgba(13,17,30,.38)` 叠出来的 #05060b（偏蓝近黑），
   于是"纯色主题的黑色模式"看起来不纯黑。这一档不叠压暗，交还纯黑。
   vice（本身是暮色底）与浅色档（压暗才有意义）都保持原样。
   下文那条把阅读正文提亮 3% 的规则不受影响 —— 行距内的可读性照旧。 */
html[data-aichat-skin="solid"][data-theme="dark"] body[data-reading-shade="true"] :is(
  .chat-container,
  .doc-content,
  .doc-toc,
  .sidebar
) {
  box-shadow: none !important;
}
/* 侧栏的暗滤镜不在 box-shadow 上，所以这一档要关的是它自己的那一层。
   （移动端抽屉的 --shadow-lg 因此不会被误伤 —— 上一版把它一起杀了。） */
html[data-aichat-skin="solid"][data-theme="dark"] body[data-reading-shade="true"] .chat-sidebar {
  background-image: none !important;
}
body[data-reading-shade="true"] .chat-container :is(
  p, li, blockquote, h1, h2, h3, h4, h5, h6, th, td, a,
  .message-status
):not(.message.user *) {
  color: color-mix(in srgb, currentColor 97%, #fff) !important;
  font-weight: 540;
  text-shadow: var(--visual-readingTextShadow, 0 0 .35px currentColor);
}

/* ---- Hero avatar halo (visual lab: haloInner/haloOuter/haloAlpha/
   haloSpread/haloCycle/haloScale). Empty colour vars fall through to the
   pixel-sampled tint written by sampleAvatarHalo() in home.js. ---- */
/* Not gated on data-visual-home-enabled: visual-runtime.js writes the
   --visual-halo* vars unconditionally, so gating only these two rules
   made the live site (homeEnabled=false) show the halo colours but not
   its size or breathing period -- while the lab, which forces
   homeEnabled:true, showed both. That was the lab/live mismatch. */
body[data-page-kind="home"] .hero-avatar {
  --hero-halo-scale: var(--visual-haloScale, 1.28);
  /* 偏移的桌面默认值；手机档在下面的 media query 里覆盖。 */
  --hero-halo-x: 0vw;
  --hero-halo-y: 0vh;
}
body[data-page-kind="home"] .hero-avatar-halo {
  animation-duration: calc(var(--visual-haloCycle, 8.4) * 1s) !important;
}
@media (max-width: 900px) {
  body[data-page-kind="home"] .hero-avatar {
    --hero-halo-scale: var(--visual-haloMobileScale, 1.08);
    --hero-halo-spread: var(--visual-haloMobileSpread, 44px);
    --hero-halo-x: var(--visual-haloMobileX, 0vw);
    --hero-halo-y: var(--visual-haloMobileY, 0vh);
  }
}

body[data-page-kind="home"] .hero-avatar-particles {
  --avatar-particle-count: var(--visual-avatarParticleCount, 30);
  --avatar-particle-speed: var(--visual-avatarParticleSpeed, 6.2);
  --avatar-particle-size: var(--visual-avatarParticleSize, 3.5);
  --avatar-particle-color-1: var(--visual-avatarParticleColor1, #ffd166);
  --avatar-particle-color-2: var(--visual-avatarParticleColor2, #ff7eb6);
}
